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;

執行效果如下所示: