2016年9月5日 星期一

2016年8月13日 星期六

7688 i2c & arduino slaver code



Ref : https://docs.labs.mediatek.com/resource/linkit-smart-7688/en/tutorials/peripheral-support-on-linkit-smart-7688-development-board/mraa






















P20  ->   I2C  SDA

P21   ->  I2C  SCK



使用MRAA為library..... 系統預設已經裝好...

MRAA

libmraa is a C/C++ library to interface with the peripherals on LinkIt Smart 7688 development board. libmraa is pre-installed in the system image of the board and supports C++, Python and Node.js bindings.

Basic concepts

The majority of hardware modules such as GPIO, UART, SPI and PWM are represented as objects. These modules are initialized on certain pins that are identified by pin numbers. The pin numbers in the libmraa on the board are identical to the GPIO numbers in the data sheet and in the Linux GPIO subsystem.
The following Python example creates GPIO object on GPIO pin 2: 
import mraa
pin = mraa.Gpio(2)    # Initialize GPIO2 (P10 on LinkIt Smart 7688 board)

I2C

Inter-Integrated Circuit (I2C) is a widely used protocol among peripherals. It consists of 2 signal pins — usually named SDA and SCL. LinkIt Smart 7688 development board has one set of I2C on GPIO4 (P21) and GPIO5 (P20) as SCL and SDA, respectively. The way I2Cs are initialized is slightly different from GPIO modules. Instead of using pins, I2Cs are initialized based on the device index. Since there is only one set of I2C master device on the board, you can simply pass 0, and it's always on pins GPIO4 and GPIO5.
import mraa 
i2c = mraa.I2c(0) 
I2C is capable of connecting multiple slave devices to a single I2C master. Each slave device is identified by a 7-bit address. The following example scans for a Seeed Studio 3-Axis Digital Accelerometer attached to the LinkIt Smart 7688 development board by reading the device ID from its registers.
import mraa
 
i2c = mraa.I2c(0)
# Grove - 3-Axis Digital Accelerometer(+-16g)
# is a ADXL345 configured to I2C address 0x53.
i2c.address(0x53)
# The device ID should be 
if 0xE5 == i2c.readReg(0x00):
 print "Grove - 3-Axis Digital Accelerometer found on I2C Bus"
else:
 print "Grove - 3-Axis Digital Accelerometer not found" 


mraa 在 i2c 下面用的 api 

address(I2c selfuint8_t address) → mraa::Result[source]
address: uint8_t
frequency(I2c selfmraa::I2cMode mode) → mraa::Result[source]
mode: enum mraa::I2cMode
read(I2c selfuint8_t * data) → int[source]
data: uint8_t *
readByte(I2c self) → uint8_t[source]
self: mraa::I2c *
readBytesReg(I2c selfuint8_t reguint8_t * data) → int[source]
reg: uint8_t data: uint8_t *
readReg(I2c selfuint8_t reg) → uint8_t[source]
reg: uint8_t
readWordReg(I2c selfuint8_t reg) → uint16_t[source]
reg: uint8_t
write(I2c selfuint8_t const * data) → mraa::Result[source]
data: uint8_t const *
writeByte(I2c selfuint8_t data) → mraa::Result[source]
data: uint8_t
writeReg(I2c selfuint8_t reguint8_t data) → mraa::Result[source]
reg: uint8_t data: uint8_t
writeWordReg(I2c selfuint8_t reguint16_t data) → mraa::Result[source]
reg: uint8_t data: uint16_t


======================================================
Ref  wire ->  slaver_reader sample

// Wire Slave Receiver
// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Receives data as an I2C/TWI slave device
// Refer to the "Wire Master Writer" example for use with this

// Created 29 March 2006

// This example code is in the public domain.


#include <Wire.h>

void setup() {
  Wire.begin(8);                // join i2c bus with address #8
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);           // start serial for output
}

void loop() {
  delay(100);
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany) {
  while (1 < Wire.available()) { // loop through all but the last
    char c = Wire.read(); // receive byte as a character
    Serial.print(c);         // print the character
  }
  int x = Wire.read();    // receive byte as an integer
  Serial.println(x);         // print the integer
}

=============================================
slaver_sender


#include <Wire.h>

void setup() {
  Wire.begin(8);                // join i2c bus with address #8
  Wire.onRequest(requestEvent); // register event
}

void loop() {
  delay(100);
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {
  Wire.write("hello "); // respond with message of 6 bytes
  // as expected by master
}













2016年8月9日 星期二

Jlink 研究

Ref :   https://applefreak111.wordpress.com/2013/03/07/howto-stm32%E6%96%B0%E6%89%8B%E4%B8%8A%E8%B7%AF-%E4%BD%BF%E7%94%A8keil%E5%92%8Cjlink/

Ref :  https://www.youtube.com/watch?v=Bm48FabZ3sE

大家好 今天我要跟各位初步介紹如何使用Keil來開發ST的STM32 ARM微處理器 那麼我們就廢話不多說 直接進入話題吧!
還是說一下廢話好了 ㄏㄏ STM32總共分有F0, F1, F2, F3, F4五個系列 每個系列的用途不同 所以功能也不同 我想各位應該也猜到越後面的能力就越強吧 至於選擇F1系列的原因是因為他的功能已經非常強了 舉個例,Sony的PlayStation Move裡面就使用了STM32F103VB這顆晶片 由此可知他的應用
當然很多控制的應用也可以取代8051 但這恐怕就有點殺雞焉用牛刀的感覺了 總之要看應用就是了 順道一提 用8051不如用AVR 封裝大小從PDIP8到PDIP28都有 我也還沒開始學 先玩STM32一陣子吧
首先呢 各位需要安裝Keil-MDK 這將會是我們的IDE(integrated development environment) 這套軟體把文字編輯器、編譯器、下載燒錄、及除錯全部包裝在一起 非常好用也省事
安裝的部分沒有什麼好解釋的 請各位自行先裝好 也請裝好JLink的驅動 如果有任何問題就留言發問吧
現在我們有了一切需要的工具 當然也少不了硬體啦 我用的是很簡易的開發板 對岸稱為最小系統板 這裡有個重要的事情要注意 就是你的STM32是哪個系列的哪個型號 例如我的是STM32F103RB 意味著他是F1係列的03RB 其功能我想各位自己讀讀datasheet就可以瞭解 我這就不多說了 唯一要注意的就是你的晶片是HD還是MD 這是什麼勒?就是裡面的flash記憶體大小 這個大小就是我們程式最大的容量 關於怎麼樣才是HD怎麼樣才是MD這個分別我有點點忘了 總之根記憶體大小有關就是了
對一位新手(我也是) 要學習STM32依據本人的經驗 他的學習曲線非常的陡 為什麼呢?因為相關的教學資料少之又少 書也沒幾本 我一開始學的時候停頓了超久才開竅 因為其實 他根本不用書就可以學了!一切的資料都在datasheet和reference manual(RM0008)內 只要能掌握這兩本(還有std_peripheral使用說明,但我不常用)就可以輕輕鬆鬆學會了STM32!

好啦~講了那麼多廢話…我們開始吧!首先我們需要建構好Keil的環境 各位可以來下載我事先做好的空白範本 因為其實ST也是希望大家這樣開發 不然每次都要重新設定路徑有的沒的 不省事
各位應該已經確認自己的晶片是HD還是MD 我的是MD 所以就複製一個範本 然後命個名好了之後就請開啓Project.uvproj吧 應該會長這樣


在main函數裡面就是我們寫主程式的地方 這和其他晶片是沒有兩樣的 現在裡面只有一個while的dummy回圈 沒啥用 等等我會講解STM32程式的開發的流程 因為這會和ARM的架構有點關係 所以我先稍稍講一下他的架構(這個時候你應該有RM0008和晶片的datasheet都打開 隨時都可以參考 這很重要) 我們來看看datasheet(以我的為例 也就是ST的CD00161566)的第11頁的block diagram 這大約就是我這顆晶片的運作方塊圖 看到下半邊 有一堆功能 ADC, GPIO, TIM, USART…etc. 等 這些都是我這顆晶片所擁有的功能 我們要啓用它 來使用他們,給他們clock 就可以使用了 當然我們還要進一步的填入這個功能的初始參數 例如你要啓用GPIOA 而裡面的參數有mode, pin,和speed 這些參數就和8051一樣 都有對應的register來作設定 STM32功能強大的地方來了 因為ARM的結構非常的複雜 所以ST已經寫好了一整套的Library 把所有低階的程式都抽象化掉了 這個Libray稱為Standart Peripheral Libray或Firmware Library中文我們就叫做硬體庫吧(因為我也不知道怎麼翻) 而這個library又建構於ARM公司所發行的CMSIS這個library 在這我只是簡介一番 因為實際我們在開發的時候 根本不用理會 只要知道怎麼寫C還有使用硬體庫就好了
整合一下剛剛所說的,如果我今天想要用GPIOA (General Purpose Input/Output,通用輸入/輸出 A的意思是A區塊 有A就有B 有B就有C 以此類推 已GPIO來講 一個區塊有16個輸入輸出單位) 我可以用下列的函數來進行設定
GPIO_InitTypeDef GPIO_InitStructure; //定義資料形態
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //啟用APB2 Peripheral的clock(這個是翻成”外設”?)
/*以下為GPIO參數設定*/
GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0; //設定Pin_0也就是GPIOA的P0
GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_out_PP; //設定為輸出push-pull
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度為50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始
由上可知,這個硬體庫都是使用自己的資料形態 然後使用者在來定義內部的欄位 就可以進行register的設定 簡單吧!現在GPIOA已經設定完了 我們現在要怎麼使用他勒?讓我們看下去
如果想要Set某支腳我們只要呼叫這個函數
GPIO_SetBits(GPIOA , GPIO_Pin_0);
如果想要Reset某支腳
GPIO_ResetBits(GPIOA , GPIO_Pin_0);
所謂sink 就是電流是由外部“流入”晶片 反之,source就是晶片“提供”電流給外部 這有什麼差勒?差可大囉!
如果我電路想接一顆LED 我可以把LED的正極直接接到晶片的輸出腳(當然要限流電阻) 然後晶片只要給high的訊號(3.3v or 3v3)LED就會亮了 對吧?但想想喔 如果他要提供電流 這隻腳 晶片就會有負載 有了負載溫度就高 若電流更大 就推不動了
但如果我們用sink,我們將腳設low (0v, GND)電流是從外部流入晶片到地 所以晶片沒有消耗到功率 大部份的驅動 都是採sink的方式 但如果一定要由晶片提供high訊號(七段顯示器掃描,LED陣列掃描) 我們會使用電子開關 例如在飽和區的BJT
剛剛介紹完怎麼啟用某個功能 我們現在就來看看怎麼作出一個LED流水燈吧!流水燈聽起來有點拔辣 這也是對岸的講法 其實就是某幾顆LED互相交替點亮熄滅 等同於控制晶片的Hello World
延續剛剛的main函數內 我們先創一個叫做GPIOA_Init(void)的函數吧 裡面我們會初始化GPIO這個功能
然後在main裡呼叫他 進行初始化 然後依序點亮和熄滅

我的板子LED剛好在PB0上 而且使用了source 所以我這樣寫
之後就按下”Build”來編譯 沒有問題後”Downoad”來下載到晶片內 因為我設定下載後自動reset所以功能在下載完成後馬上就可以動作了!這個功能 看每個人喜好 在一些比較複雜的應用我會想要自己按板子上的Reset扭來重設 這個設定可以在”Target Options”(有一個魔術棒的圖樣) 裡面的”Utilities”內的”Settings”內的”Download Options”找到 “Reset and Run”
圖四
我想初步介紹STM32及開發的方法到這邊就告一段落了 相信各位都覺得不難 因為真的不難!我自己卡關大部份都是在程式的流程設計還有資料的處理這方面卡關 但這些問題都是因為寫的程式不多所造成的 無聊的時候就想個功能 挑戰挑戰自己 經驗日積月累 就可以越來越厲害了!希望各位有學到東西 或者如果我有哪裡和你的認知不同請都提出來讓我們一起解決 畢竟我也是新手 只是比你們早玩罷了 請多指教囉~謝謝!

2016年8月2日 星期二

Ameba Arduino: MPU6050 – 使用 MPU6050 六軸慣性感測元件

Ref :  http://www.amebaiot.com/ameba-arduino-mpu6050/


材料準備
  • Ameba x 1
  • MPU6050 x 1
範例說明
MPU6050是款常見的6軸慣性感測元件,它包括了三軸加速度計及三軸陀螺儀。使用與讀取資料的介面為I2C,可以控制的 細節相當多,我們可以找不少開源的library可供使用。
I2CDev是其中知名的library,你可以找到原始的source code

Ameba使用MPU6050需要2個library,I2CDev與MPU6050, 請到底下的位址下載:
  • I2CDev
    Ameba沒有修改I2CDev裡面的程式碼,只是打包好讓使用者下載
  • MPU6050
    Ameba沒有修改API的內容,只有根據實際使用狀況修改example。
安裝library的方式請參考Arduino官方網站的教學文章將zip檔的library加入Ameba:
https://www.arduino.cc/en/Guide/Libraries#toc4
接著打開範例 “Files” -> “Example” -> “AmebaMPU6050” -> “MPU6050_raw”。(這個範例與I2CDev官方網站的一樣)
這個範例裡展示讀取三軸加速度計及三軸陀螺儀的值,我們先接線如下:

編譯並上傳程式碼,按下Reset之後可以在Serial Monitor看到一直印訊息:


這六個值分別是:
1. x軸的加速度
2. y軸的加速度
3. z軸的加速度
4. x軸的角速度
5. y軸的角速度
6. z軸的角速度
值的範圍是 -16383 ~ 16384,其中可以看到z軸因為重力加速度的關係,值會接近16384
這些值會因為干擾而一直變動,可以轉動一下MPU6050觀察一下值的變化。

程式碼說明

雖然程式碼很長,但重要的只有幾個。第一個是初始化: initialize()
初始化完就可以取值了: getMotion6(int16_t* ax, int16_t* ay, int16_t* az, int16_t* gx, int16_t* gy, int16_t* gz)

使用Digital Motion Processor

MPU6050搭載了一顆DMP(Digital Motion Processor),可以負責一些運動處理演算法,像是轉換成飛機三軸yaw/pitch/roll,轉換四元數(Quaternion),或是轉換成尤拉角(Euler angle)。
DMP會以高速計算,完成後發出GPIO Interrupt訊號在INT這根Pin上。計算結果會存在FIFO裡,Ameba如果一直都沒將結果取出,會造成FIFO overflow,並且下一次讀出的結果不正確。這種情況將FIFO reset即可。
另一個狀況要注意的是,當MPU6050發出GPIO Interrupt的時候,如果正好在處理I2C資料的送收,那麼MPU6050會停住,並且再也不會有任何動作。MPU6050沒有Reset或Enable Pin,這種情況下只能將MPU6050斷電再插電。因此寫程式的時候要注意,如果要處理要花時間的運算,最好等到下一次GPIO Interrupt發生再對MPU6050送收I2C資料。
我們打開範例 “File” -> “Examples” -> “AmebaMPU6050” -> “MPU6050_DMP6”。(與I2CDev官方網站的範例有些設定上的差異。)
因為打開DMP關係,在接線上需要多接一根線:




編譯並上傳至Ameba之後,按下Reset鍵。打開Serial Monitor,會提示鍵入字元之後啟動DMP
鍵入字元之後,會出現ypr的值


ypr即Yaw/Pitch/Roll,是飛機飛行常用的表示法

程式碼說明

除了MPU6050的Initialize()之外, DMP也需要初始化 mpu.dmpInitialize()
可以用底下這些API對初始值做校正:
mpu.setXGyroOffset(220);
mpu.setYGyroOffset(76);
mpu.setZGyroOffset(-85);
mpu.setZAccelOffset(1788);
啟動DMP: mpu.setDMPEnabled(true);
設定Ameba在要哪根GPIO傾聽Interrupt,我們設定為D3。當interrupt發生的時候,呼叫functiondmpDataReady()
attachInterrupt(3, dmpDataReady, RISING);
取得DMP每次計算結果的封包大小
packetSize = mpu.dmpGetFIFOPacketSize();
設定DMP的運算速度,這個值預設值是4,也就是 1k/(1+4) = 200Hz,但是會因為印Log很花時間的關係,造成Ameba來不及在下一次Interrupt發生的時候印完log,造成有機會在I2C送收的時候發生Interrupt,隨即MPU6050就停住不動了。所以需要適當選擇rate,如果rate的值太高(sample rate太低),會讓DMP的反應速度沒那麼快。
mpu.setRate(5); // 1khz / (1 + 5) = 166 Hz
接著在loop()裡面檢查是否有interrupt發生,如果有就將結果取出
fifoCount = mpu.getFIFOCount();
mpu.getFIFOBytes(fifoBuffer, packetSize);
範例裡預設使用OUTPUT_READABLE_YAWPITCHROLL,並各種轉換
mpu.dmpGetQuaternion(&q, fifoBuffer); // 四元數
mpu.dmpGetGravity(&gravity, &q); // 取得重力的值
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity); // 轉換成yaw/pitch/roll



Ameba Arduino: SPI – 使用LCD螢幕印出圖案與文字

Ref : http://www.amebaiot.com/ameba-arduino-spi-lcd/


材料準備
  • Ameba x 1
  • ILI9341 TFT LCD with SPI interface x 1
市面上有許多ILI9341 TFT LCD,基本上大同小異,唯一要注意的地方是可接受的SPI clock rate,這點需要看該項LCD的產品規格來確認。

範例說明
手邊已測試過兩款ILI9341 TFT LCD with SPI interface,分別是

常見的ILI9341 TFT LCD with SPI interface有底下這些Pin角
  • MOSI: 標準的SPI Pin 腳
  • MISO: 標準的SPI Pin 腳
  • SLK: 標準的SPI Pin 腳
  • CS: 標準的SPI Pin 腳
  • RESET: 拉Low再拉High可以重啟LCD, 詳細的重啟順序需要看LCD的規格
  • D/C: Data/Command, 這個Pin腳準位在Low的時候, 表示此時SPI傳送的都是命令, 而準位在High的時候表時傳送的都是資料
  • LED (or BL): 即背光, 需要有一定的亮度才可以看到螢幕內容,通常可用PWM控制,或直接接到VCC讓它100%發亮
  • VCC: 接到3V或5V, 要參考規格
  • GND: 接到GND
底下是QVGA TFT LCD的接法


CS -> D10
SCK -> D13
SDO -> D12
SDI ->  D11
底下是adafruit 2.8 tft lcd touch shield的接法,要注意的是,這款shield預設已打上背光,並且pin 8不是背光的pin,所以不需接上背光的pin。另外它接到5V,而不是3.3V。



開範例程式, “Files” -> “Examples” -> “AmebaSPI” -> “ILI9341_LCD_basic”

編譯後上傳到Ameba,完成後按下Reset按鈕。
螢幕上會執行一些基本測試,像是刷新螢幕為不同顏色,畫直線與橫線,畫斜線,畫圓圈,畫正方形,顯示不同大小的文字,最後不停地旋轉螢幕並印出文字








程式碼說明
  •  RGB 16-bitILI9341在繪圖時,使用的顏色代碼是RGB 16-bit, 與一般常見的RBG 24-bit差異是Red使用5 bit (原本的8 bits向右移3bits), Green使用6 bits(原本的8 bits向右移2bits), Blue使用5 bit(原本的8 bits向右移3bits)舉例來說,天空藍的RGB 24 bit為 0x87CEFF,表示成二進位為:
    • Red: 0x87 = B10000111
    • Green: 0xCE = B11001110
    • Blue: 0xFF = B11111111
    轉成RGB 16 bit為
    • Red: B10000
    • Green: B110011
    • Blue: B11111
    最後將這些二進位數值接起來 B1000011001111111 = 0x867F
  • ILI9341繪圖方式
    • 在繪圖前,需要下Command告訴它接下來要畫的矩形範圍, 接著再一個一個傳入2 byte的RGB 16 bits顏色代碼,ILI9341會一個一個pixel填入對應的顏色。
    • 畫1個pixel也需要設定範圍,只不過它的矩形長寬只有1個pixel
    • 因此畫垂直線或水平線要比畫斜線要快,因為垂直線或水平線只需要設定一次矩形範圍(長或寬為1個pixel),但畫斜線則比較慢,因為實際上它畫了許多點,而每個點都要設定矩形範圍。
  • ILI9341繪出文字
    • 在API裡,字型檔使用5×7的文字,但印出時是6×8的文字,其中右邊及下方都留白,這樣可以與下一個文字區分。底下是A的例子:
    • 如果是Font Size為2的情況,則裡面每個dot的大小為2×2的矩形。Font Size為3則每個dot的大小為3×3的矩形,以此類推。

  • 螢幕轉向ILI9341
    • ILI9341提供0度、90度、180度、270度的螢幕轉向
    • 原本0度的width為240,height為320,轉向90度之後,width為320,height為240

code study

重點是
1.  SPI.setDefaultFrequency(ILI9341_SPI_FREQUENCY);


=============================================================




#include "SPI.h"
#include "AmebaILI9341.h"


#define TFT_RESET  8
#define TFT_DC     9
#define TFT_CS    10

AmebaILI9341 tft = AmebaILI9341(TFT_CS, TFT_DC, TFT_RESET);




#define ILI9341_SPI_FREQUENCY 20000000

void setup() {
  Serial.begin(9600);
  Serial.println("ILI9341 Test!"); 

  SPI.setDefaultFrequency(ILI9341_SPI_FREQUENCY);

  tft.begin();

  Serial.println("test filling screen");
  testFillScreen();
  delay(500);

  Serial.println("test Lines");
  testLines(ILI9341_CYAN);
  delay(500);

  Serial.println("test Circles");
  testCircles(5, ILI9341_BLUE);
  delay(500);

  Serial.println("test Circles");
  testRectangle(ILI9341_LIGHTGREY);
  delay(500);

  Serial.println("test Text");
  testText();
  delay(500);
}


void loop() {
  for (int i=0; i<4; i++) {
    tft.setRotation(i);
    testText();
    delay(500);
  }
}


大部分的code 都包在   AmebaILI9341.h  .. path : C:\Users\jacky\AppData\Local\Arduino15\packages\realtek\hardware\ameba\1.1.1\libraries\SPI

然後裡面使用spi 的api大概有三個

 SPI.begin();

SPI.transfer(data);

這邊transfer 又做了三個版本..   
  1.  只傳一個byte    transfer(uint8_t _data, SPITransferMode _mode = SPI_LAST);

  2.  只傳兩個byte   uint16_t transfer16(uint16_t _data, SPITransferMode _mode = SPI_LAST);

 3.   傳送多個byte   ransfer(void *_buf, size_t _count, SPITransferMode _mode = SPI_LAST);