1.樹莓派SPI介紹
4B的引腳如下圖所示:
其中Pin19、21、23是SPI0,介面定義如下所示:
- 時鐘(SPI CLK, SCLK)
- 主機輸出、從機輸入(MOSI)
- 主機輸入、從機輸出(MISO)
在使用 SPI 介面前,你需要使用 gpio 命令來載入 SPI 驅勱到核心中:
gpio load spi
如果您需要的緩衝區大於 4KB,需要在命令列迕行指定緩衝區的大小,單位是 KB:
gpio load spi 100
上述命令將會分配 100KB 的緩衝區.(您可能很少需要改變返項謳置,預設值對於絕大多數應用程式來說已經足夠了). 為了使用 SPI 庫,你也需要在你的程式中新增如下語句:
#include <wiringPiSPI.h>
程式在編譯連線時,仍然需要新增-lwiringPi 選項
需要用到的函式如下所示:
int wiringPiSPISetup(int channel, int speed); //使用該函式可以初始化一個 SPI 通道,樹莓派有兩個 SPI 通道(0 和 1)。 //speed 引數是一個整數值,其範圍為 500000~32000000,代表 SPI 時鐘速度,單位是 Hz。 //返回值為-1,則失敗。則需要檢查一下電路連線和是否開啟了樹莓派的SPI。 int wiringPiSPIDataRW(int channel, unsigned char* data, int len); //該函式執行一個同時讀寫操作,通過選定的 SPI 匯流排。緩衝區中的資料,將會被 SPI匯流排的返回資料所覆蓋。 void delay (unsigned int howLong) //延時ms,最大傳入32位無符號型整數,大約49天。 void delayMicroseconds (unsigned int howLong) //延時微秒,最大傳入32位無符號型整數,大約71分鐘
2.FM25L16B晶片介紹
FM25L16是採用先進的鐵電工藝製造的1024*16位的非易失性儲存器(2048個位元組)。鐵電隨機儲存器(FRAM)具有非易失性,並且可以象RAM一樣快速讀寫。FM25L16中的資料在掉電後可以儲存45年。相對EEPROM或其他非易失性儲存器,FM25L16具有結構更簡單,系統可靠性更高等諸多優點。
與EEPROM系列不同的是,FM25L16以匯流排速度進行寫操作,無須延時。資料發到FM25L16後直接寫到具體的單元地址,下一個匯流排操作可以立即開始,無需資料輪詢。此外,FM25L16的讀/寫次數幾乎為無限次,比EEPROM高得多。同時,FM25L16的功耗也遠比EEPROM低。
引腳定義如下所示:
- /CS: 片選,低電平為啟用裝置
- SCK: SPI輸入時鐘,頻率最高支援20MHZ
- /HOLD: 輸入保持,比如當我們在進行讀寫的時候,假如產生了一箇中斷,由於時序已經在進行了,這時可以給個低電平讓晶片保持時序,等待中斷處理完成後,再來置高,繼續讀寫資料.
- /WP: 防寫,為低電平則不能寫操作
- SI、SO: SPI輸入輸出資料引腳
指令如下所示:
2.1 狀態暫存器(0x01)介紹
狀態暫存器的每個bit位意義如下所示:
其中BP1和BP0是設定防寫區域的.如下圖所示:
我們必須將BP1和BP0設定為0,才可以有寫所有地址的許可權.
2.2 寫暫存器(0x06)介紹
所有對記憶體陣列的寫入都以WREN(0X06)操作碼開頭,下一個操作碼是WRITE指令,這個操作碼後面跟著一個雙位元組地址。地址的前5位將被忽略(最多儲存2048位元組),然後就可以一直寫入資料.最後將CS置高則完成寫操作.
3.最終程式碼
#include<stdio.h> #include <cstring> #include<wiringPi.h> #include <wiringPiSPI.h> typedef unsigned char u8; typedef unsigned short u16; #define FM25CL16_WREN 0x06 // 寫使能 #define FM25CL16_WRITE 0x02 // 寫暫存器 #define FM25CL16_READ 0x03 // 讀暫存器 #define FM25CL64_WRSR 0x01 // 狀態暫存器 #define FM25L16_CSPIN 21 // 片選引腳 void initSPI() { //初始化所用到的IO引腳 pinMode(FM25L16_CSPIN, OUTPUT); digitalWrite(FM25L16_CSPIN, HIGH); //初始化SPI通道0,並設定為速度 if(wiringPiSPISetup(0,5000000)==-1) { printf("init spi failed!\n"); } } // 片選 void fm25l16Cs(u8 select) { if (select == 0) { digitalWrite(FM25L16_CSPIN, LOW); } else { digitalWrite(FM25L16_CSPIN, HIGH); } } // 向FLASH寫入一個位元組資料 static u8 fm25l16WriteByte(u8 Temp) { return wiringPiSPIDataRW(0,&Temp,1); } // FLASH寫使能 static void fm25l16WriteEnable() { fm25l16Cs(0); fm25l16WriteByte(FM25CL16_WREN); fm25l16Cs(1); } // 寫入一串資料 void fm25l16WriteBuff(u16 addr,u8* buff,u16 len) { u8 buffHead[3]; // 資料頭 fm25l16WriteEnable(); fm25l16Cs(0); buffHead[0] = FM25CL16_WRITE; buffHead[1] = (addr&0xFF00)>>8; buffHead[2] = (addr&0x00FF); wiringPiSPIDataRW(0,buffHead,3); wiringPiSPIDataRW(0,buff,len); fm25l16Cs(1); } // 讀出一串資料到buff中 void fm25l16ReadBuff(u16 addr,u8* buff,u16 len) { u8 buffHead[3]; // 資料頭 fm25l16Cs(0); buffHead[0] = FM25CL16_READ; buffHead[1] = (addr&0xFF00)>>8; buffHead[2] = (addr&0x00FF); wiringPiSPIDataRW(0,buffHead,3); wiringPiSPIDataRW(0,buff,len); fm25l16Cs(1); } // 寫狀態 void fm25l16Status() { u8 buff[2] = {FM25CL64_WRSR, 0X00}; fm25l16WriteEnable(); fm25l16Cs(0); wiringPiSPIDataRW(0,buff,2); // 取消防寫 fm25l16Cs(1); } int main() { u8 data[10]; u8 i=0; u8 beginData = 0; //初始化wiringPI的庫函式 if(wiringPiSetup()<0) { printf("init wiringPi error\n"); } initSPI(); //spi的初始化 fm25l16Status(); // 寫狀態暫存器 while(1) { for(i=0;i<10;i++) { data[i] = beginData++; } fm25l16WriteBuff(0,data,10); printf("write ok\n"); fm25l16ReadBuff(0,data,10); printf("read: "); for(i=0;i<10;i++) { printf("%d ",data[i]); } printf("\n"); delay(20); } return 0; }
執行效果如下所示: