色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

淺談STM32之SPI_FLASH之應用實例

ss ? 來源:未知 ? 作者:沈丹 ? 2018-10-07 11:29 ? 次閱讀
SPI Flash
首先它是個Flash,Flash是什么東西就不多說了(非易失性存儲介質),分為NOR和NAND兩種(NOR和NAND的區別本篇不做介紹)。SPI一種通信接口。那么嚴格的來說SPI Flash是一種使用SPI通信的Flash,即,可能指NOR也可能是NAND。但現在大部分情況默認下人們說的SPI Flash指的是SPI NorFlash。早期Norflash的接口是parallel的形式,即把數據線和地址線并排與IC的管腳連接。但是后來發現不同容量的Norflash不能硬件上兼容(數據線和地址線的數量不一樣),并且封裝比較大,占用了較大的PCB板位置,所以后來逐漸被SPI(串行接口)Norflash所取代。同時不同容量的SPI Norflash管腳也兼容封裝也更小。,至于現在很多人說起NOR flash直接都以SPI flash來代稱。
NorFlash根據數據傳輸的位數可以分為并行(Parallel,即地址線和數據線直接和處理器相連)NorFlash和串行(SPI,即通過SPI接口和處理器相連)NorFlash;區別主要就是:1、SPI NorFlash每次傳輸一bit位的數據,parallel連接的NorFlash每次傳輸多個bit位的數據(有x8和x16bit兩種); 2、SPI NorFlash比parallel便宜,接口簡單點,但速度慢。
NandFlash是地址數據線復用的方式,接口標準統一(x8bit和x16bit),所以不同容量再兼容性上基本沒什么問題。但是目前對產品的需求越來越小型化以及成本要求也越來越高,所以SPI NandFlash漸漸成為主流,并且采用SPI NANDFlash方案,主控也可以不需要傳統NAND控制器,只需要有SPI接口接口操作訪問,從而降低成本。另外SPI NandFlash封裝比傳統的封裝也小很多,故節省了PCB板的空間。
怎么用說白了對于Flash就是讀寫擦,也就是實現flash的驅動。先簡單了解下spi flash的物理連接。
之前介紹SPI的時候說過,SPI接口目前的使用是多種方式(具體指的是物理連線有幾種方式),Dual SPI、Qual SPI和標準的SPI接口(這種方式肯定不會出現在連接外設是SPI Flash上,這玩意沒必要全雙工),對于SPI Flash來說,主要就是Dual和Qual這兩種方式。具體項目具體看了,理論上在CLK一定的情況下, 線數越多訪問速度也越快。我們項目采用的Dual SPI方式,即兩線。

本實例用的是STM32F103VET6平臺,它有3個SPI接口(這里使用SPI1),各信號線連接到FLASH(型號:W25X16)的CS,CLK,DO,DIO線,以實現SPI通訊,對FLASH進行讀寫。

(這里采用主模式,全雙工通訊,通過查詢發送數據寄存器和接收數據寄存器狀態確保通訊正常)

mian函數:

1#define sFLASH_ID 0xEF3015(前面加個1,免得變大)

u32 DeviceID;

u32 FlashID;

int main(void)

{

/115200 8-N-1/

USART1_Config();

SPI_FLASH_Init();

DeviceID = SPI_FLASH_ReadDeviceID();

Delay(200);

FlashID = SPI_FLASH_ReadID();

printf(“\r\n FlashID is 0x%X, Manufacturer Device ID is 0x%X\r\n”,FlashID,DeviceID);

if(FlashID == sFLASH_ID)

{

printf(“\r\n 檢測到 flash W25X16 !\r\n”);

SPI_FLASH_SectorErase(FLASH_SectorToErase);

SPI_FLASH_BufferWrite(Tx_Buffer, FLASH_WriteAddress, BufferSize);

printf(“\r\n 寫入的數據為:%s \r\t”, Tx_Buffer);

SPI_FLASH_BufferRead(Rx_Buffer, FLASH_ReadAddress, BufferSize);

printf(“\r\n 讀出的數據為:%s \r\n”, Tx_Buffer);

TransferStatus1 = Buffercmp(Tx_Buffer, Rx_Buffer, BufferSize);

if( PASSED == TransferStatus1)

{

printf(“\r\n 2M 串行 flash(W25X16)測試成功!\n\r”);

}

else

{

printf(“\r\n 2M 串行 flash(W25X16)測試失敗!\n\r”);

}

}

else

{

printf(“\r\n 獲取不到 W25X16 ID!\n\r”);

}

SPI_Flash_PowerDown();

while(1);

1234567891011121314151617181920212223242526272829303132333435363738

}

mian函數的流程:

1,調用 USART1_Config() 初始化串口;

2,調用 SPI_FLASH_Init() 初始化SPI模塊;

3,調用 SPI_FLASH_ReadDeviceID 讀取FLASH器件生產廠商的ID信息;

4,調用 SPI_FLASH_ReadID 讀取FLASH器件的設備ID信息;

5,如果讀取ID正確,則調用 SPI_FLASH_SectorErase()把FLASH內容擦除,擦除后調用 SPI_FLASH_BufferWrite()向FLASH寫入數據,然后再調用 SPI_FLASH_BufferRead()從剛剛寫入的地址中讀出數據,最后調用 Buffercmp()對寫入和讀取的數據進行匹配,匹配成功則把標志變量 TransferStatus1賦值為 PASSED(自定義的枚舉變量);

6,根據標志量 TransferStatus1判斷FLASH數據的:擦除,寫入,讀取是否正常,分情況輸出到終端;

7,如果讀取FLASH的ID信息錯誤,則直接向終端輸出檢測不到FLASH信息;

8,最后調用 SPI_Flash_PowerDown()函數關閉 FLASH設備的電源(因為數據寫入到FLASH后并不會因斷電而丟失,所以需要使用的時候再開啟FLASH電源);

PS:

讀取器件ID信息可以知道設備與主機是否能夠正常工作,也便于區分不同的器件,可以在使用的FLASH用戶數據手冊找到ID表

SPI的初始化:

void SPI_FLASH_Init(void)

{

SPI_InitTypeDef SPI_InitStructure;

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

/這里是GPIO初始化部分,將4個引腳都設定好/

/!《 Configure SPI_FLASH_SPI pins: SCK /

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_Init(GPIOA, &GPIO_InitStructure);

/!《 Configure SPI_FLASH_SPI pins: MISO /

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;

GPIO_Init(GPIOA, &GPIO_InitStructure);

/!《 Configure SPI_FLASH_SPI pins: MOSI /

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;

GPIO_Init(GPIOA, &GPIO_InitStructure);

/!《 Configure SPI_FLASH_SPI_CS_PIN pin: SPI_FLASH Card CS pin /

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_Init(GPIOA, &GPIO_InitStructure);

/* Deselect the FLASH: Chip Select high */

SPI_FLASH_CS_HIGH(); //不用的時候就拉高

/這里是SPI設置部分/

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;

SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;

SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;

SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;

SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

SPI_InitStructure.SPI_CRCPolynomial = 3;

SPI_Init(SPI1, &SPI_InitStructure);

/* Enable SPI1 */

SPI_Cmd(SPI1, ENABLE);

}

GPIO初始化:

根據《STM32數據手冊》以及《STM32參考手冊》,把PA5(SCK),PA6(MISO),PA7(MOSI)設置成復用推挽輸出,因為PA4(NSS)是使用軟件模式,所以設置為通用退完輸出。

SPI模式初始化:

對于初始化,是需要根據通訊的設備FLASH的SPI特性來決定的,下面成員分析:

SPI_InitStructure.SPI_Direction= SPI_Direction_2Lines_FullDuplex;

這里設置通訊模式,這里設置成全雙工模式(可以在keil環境下查找其他模式)

SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

這里是設置工作模式,STM32的SPI設備可以gon工作在主機模式(SPI_Mode_Master)或從機模式(SPI_Mode_Slave),這兩個模式最大的區別就是SPI的SCK信號線時序,SCK的時序是由通訊中的主機產生的,如果配置成從機模式,STM32的SPI模塊將接收外來的SCK信號。(這里STM32作為SPI通訊主機,所以設置成 SPI_Mode_Master)。

SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;

這個是設置SPI每次通訊的數據大小(稱為數據幀)為8位還是16位(從FLASH的數據手冊可以查到,這里的FLASH的數據幀大小為8為,所以要把STM32的SPI模塊設置相同的)

SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;&SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;

這兩個成員是配置SPI的時鐘極性(CPOL)和時鐘相位(CPHA),這兩個配置影響到SPI的通訊模式,要設置成符合將要互相通訊的設備的要求。

CPOL:可以取 SPI_CPOL_High(SPI 通訊空閑時 SCK 為高電平)或者SPI_CPOL_Low(SPI 通訊空閑時 SCK 為低電平);

CPHA:可以取 SPI_CPHA_1Edge(在 SCK 的奇數邊沿采集數據)或者SPI_CPHA_2Edge (在 SCK 的偶數邊沿采集數據);

查詢這個FLASH的使用手冊,可以了解到這個FLASH支持以SPI的模式0和模式3通訊。

模式0:在SPI空閑時,SCK為低電平,奇數邊沿采樣;

模式3:在SPI空閑時,SCK為高電平,偶數變異采樣;

所以這里配置成模式3,把CPOL賦值為SPI_CPOL_High(SPI空閑時SCK為高電平),把CPHA賦值為SPI_CPHA_2Edge(在SCK的偶數邊沿超級數據)

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

這里是配置NSS引腳的使用模式,可以選擇為硬件模式(SPI_NSS_Hard)與軟件模式(SPI_NSS_Soft),在硬件模式中的SPI片選由硬件自動產生,而軟件模式則需要手動把相應的FPIO端口拉高或拉低產生非片選和片選信號(如果外界條件允許,硬件模式還會自動將STM32的SPI設置為主機)

這里是由軟件產生模式,所以賦值為SPI_NSS_Soft.

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;

這里是設置波特率分頻值,分頻后的時鐘為SPI的SCK信號線的時鐘頻率,這個成員可以設置為fpclk的2,4,6,8,32,64,128,256分頻。這里設置為4分頻

SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

所有串行的通訊協議都會有MSB先行(高位數據在前)還是LSB先行(地位數據在前)的問題,STM32的SPI模塊可以通過對這個結構體成員,對這個特性編程控制。

根據FLASH的通訊時序,這里設置為MSB先行(SPI_FirstBit_MSB)

SPI_InitStructure.SPI_CRCPolynomial = 3;

這里是設置SPI的CEC校驗的多項式,如果使用到CRC校驗時,就是用這個成員的參數(多項式),來計算CRC的值。(這里的FLASH不支持CRC校驗,所以賦值為3其實沒意義)

配置完這些結構體成員后,調用 SPI_Init()把這些參數寫入到寄存器中,然后調用SPI_Cmd()使能SPI1外設。

PS:

SPI_FLASH_CS_HIGH()這個實際是上一個自定義的宏:

#define SPI_FLASH_CS_HIGH() GPIO_SetBits(GPIOA, GPIO_Pin_4)

實際上這個宏就是用來把 PA4(NSS)引腳拉高,從而禁止SPI通訊

#define SPI_FLASH_CS_LOW() GPIO_ResetBits(GPIOA, GPIO_Pin_4)

如果要需要使用的時候,就直接拉低就行了這樣就可以開始通訊了

控制FLASH的命令:

因為不同的設備,都會相應的有不同的指令,如 EEPROM 中會把第一個數據解釋為存儲矩陣的地址(實質就是指令)。而 FLASH 則定義了更多的指令,有寫指令,讀指令,讀 ID 指令等等。

這些指令,對主機來說,只是它遵守最基本的通訊協議發送出的數據。但設備把這些數據解釋成不同的意義(指令編碼),所以才成為指令。在我們配置好 STM32 的協議模塊后,想要控制設備,就要遵守相應設備所定義的命令規則。

指 令 表 中 的 A0~A23 指 地 址 ; M0~M7 為 器 件 的 制 造 商 ID(MANUFACTURER ID);D0~D7 為數據。

讀取FLASH ID:

在命令列表可以了解到讀取設備 ID 的命令(Device ID)編碼為 ABh、dummy、dummy、dummy。表示此命令由這四個字節組成,其中dummy意為任意編碼,即這幾個字節必須發送數據,但這些數據是任意的,命令列表中帶括號的字節數據表示由FLASH返回給主機的響應,可以看到Device ID命令的第5個字節為從機返回的響應,(ID7~ID0),即返回設備的ID號。

使用DeviceID命令時的時序圖

可以看到主機首先通過MOSI線(即FLASH的DIO線)發送第一個字節為ABh編碼,緊接著三個字節的dummy編碼,然后FLASH就忽略DIO線上的信號,通過MISO線(即FLASH的DO線)把它的FLASH設備ID發送給主機。

u32 SPI_FLASH_ReadDeviceID(void)

{

u32 Temp = 0;

/使用的時候就拉低/

SPI_FLASH_CS_LOW();

/* Send “RDID ” instruction */

SPI_FLASH_SendByte(W25X_DeviceID);

SPI_FLASH_SendByte(Dummy_Byte);

SPI_FLASH_SendByte(Dummy_Byte);

SPI_FLASH_SendByte(Dummy_Byte);

/* Read a byte from the FLASH */

Temp = SPI_FLASH_SendByte(Dummy_Byte);

/* Deselect the FLASH: Chip Select high */

SPI_FLASH_CS_HIGH();

return Temp;

}

SPI_FLASH_CS_LOW();

把片選拉低,開始通訊

SPI_FLASH_SendByte(W25X_DeviceID);

向FLASH發送一個命令字節編碼:W25X_DeviceID (這里定義的宏為:0XAB)

SPI_FLASH_SendByte(Dummy_Byte);

根據指令表,發送完指令后,后面要接著發送三個字節的dummy_Byte(這里宏定義為:0xff,設置為其他也無所謂)

Temp = SPI_FLASH_SendByte(Dummy_Byte);

在前面發送完三個字節的 Dummy_Byte后,在第五個字節,FLASH通過DIO端口輸出它的器件ID,所以這里再調用一次SPI_FLASH_SendByte(Dummy_Byte)接收返回值,賦值給Temp.

SPI_FLASH_CS_HIGH();

把片選拉高,結束通訊

這樣就完成了讀取FLASH ID,這里有一個相對底層的函數SPI_FLASH_SendByte(),它實現了利用SPI發送和接收數據的功能

u8 SPI_FLASH_SendByte(u8 byte)

{

/等待發送數據寄存器清空/

while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);

/發送數據/

SPI_I2S_SendData(SPI1, byte);

/等待接收數據寄存器為非空/

while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);

/返回接收到的數值/

return SPI_I2S_ReceiveData(SPI1);

}

流程:

1,調用庫函數 SPI_I2S_GetFlagStatus()等待發送數據寄存器清空;

2,發送數據寄存器準備好后,調用庫函數SPI_I2S_SendData()向從機發送數據;

3,調用庫函數SPI_I2S_GetFlagStatus()等待接收數據寄存器非空;

4,接收寄存器非空時,調用SPI_I2S_ReceiveData()獲取接收寄存器中的數據并作為函數的返回值,這個數據即由從機發送給主機的數據;

這是最底層的發送數據和接收數據的函數,利用了庫函數的標志檢測確保通訊正常。

讀取廠商ID:

u8 SPI_FLASH_ReadID(void)

{

u32 Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;

SPI_FLASH_CS_LOW();//拉低開始通訊

SPI_FLASH_SendByte(W25x_JedecDeviceID);

Temp0 = SPI_FLASH_SendByte(Dummy_Byte);

Temp1 = SPI_FLASH_SendByte(Dummy_Byte);

Temp2 = SPI_FLASH_SendByte(Dummy_Byte);

Temp = (Temp0 《《 16) | (Temp1 《《 8) | (Temp2);

SPI_FLASH_CS_HIGH();

return Temp;

123456789101112131415

}

這個函數和之前的讀取設備ID流程也是類型的,差別在于發送一個字節的命令編碼JEDEC ID(9Fh)之后,從機就通過D0線返回廠商ID以及0~16位的設備ID。

讀廠商ID時序圖

擦除FLASH內容:

扇區擦除(根據FLASH的儲存原理,在寫入數據前,要先對存儲區域進行擦除,也叫預寫)

void SPI_FLASH_SectorErase(u32 SectorAddr)

{

/寫使能并且判斷FLASH狀態/

SPI_FLASH_WriteEnable();

SPI_FLASH_WaitForWriteEnd();

/*這里開始是FLASH擦除操作*/

SPI_FLASH_CS_LOW();

SPI_FLASH_SendByte(W25X_SectorErase);

/*這里是擦除一個扇區,也就是4KB*/

SPI_FLASH_SendByte((SectorAddr & 0xFF0000) 》》 16);

SPI_FLASH_SendByte((SectorAddr & 0xFF00) 》》 8);

SPI_FLASH_SendByte(SectorAddr & 0xFF);

SPI_FLASH_CS_HIGH();

/*再次判斷FLASH狀態確保可以執行下一次操作*/

SPI_FLASH_WaitForWriteEnd();

1234567891011121314

}

這是扇區擦除時序,其中的第一個字節為扇區擦除命令編碼(20h),緊跟其后的為要進行擦除的,根據FLASH的說明,整個存儲矩陣分為塊區和扇區,每塊(Block)的大小為64KB,每個扇區(Sector)的大小為4KB,對存儲矩陣進行擦除時,最小的單位為扇區。

寫使能:

void SPI_FLASH_WriteEnable(void)

{

SPI_FLASH_CS_LOW();

SPI_FLASH_SendByte(W25X_WriteEnable);

SPI_FLASH_CS_HIGH();

123

}

這里根據寫使能命令時序,只要發送命令WriteEnable(06h)就行了。

讀FLASH狀態:

在擦除操作之前,需要調用SPI_FLASH_WaitForWriteEnd()來確保FLASH不忙碌的時候,才發送命令或者數據,通過讀取FLASH的狀態寄存器來獲知他的工作狀態。

void SPI_FLASH_WaitForWriteEnd(void)

{

u8 FLASH_Status = 0;

SPI_FLASH_CS_LOW();

SPI_FLASH_SendByte(W25X_ReadStatusReg);

/*一直檢測FLASH狀態寄存器狀態,直到Bit0位(BUSY位)為0)*/

do

{

FLASH_Status = SPI_FLASH_SendByte(Dummy_Byte);

}while((FLASH_Status & WIP_Flag) == SET);

SPI_FLASH_CS_HIGH();

12345678910

}

整個函數實質是不斷的循環檢測FLASH狀態寄存器的Busy位,知道FLASH的內部寫時序完成,從而確保下一通訊操作正常。主機通過發送讀狀態寄存器命令Read Status Register(05h 編碼),返回的為他的8為狀態寄存的值。

檢測FLASH的狀態寄存器的Bit0(BUSY位),當FLASH在執行內部寫時序的時候,除了讀狀態寄存器命令,其他的一切命令他都會忽略,并且BUSY位保持為1,所以我們需要等待BUSY位為0的時候,再向FLASH發送其他命令。

向FLASH寫入數據:

對FLASH寫入數據,最小單位是256字節,廠商把這個單位曾為頁。寫入時,一般也只有頁寫入的方式,所以為了方便的把一個很長的數據寫入到FLASH時,一般需要進行轉換,把數據按頁分好,再寫入到FLASH中(類似于I2C對EEPROM的頁寫入,只是頁的大小不同而已)。

void SPI_FLASH_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)

{

u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp= 0;

/這里劃分好數據需要寫多少頁,寫地址,寫大小/

Addr = WriteAddr % SPI_FLASH_PageSize;

count = SPI_FLASH_PageSize - Addr;

NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;

NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;

if (Addr == 0)

{

if(NumOfPage == 0)

{

SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);

}

else

{

while(NumOfPage--)

{

SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);

WriteAddr += SPI_FLASH_PageSize;

pBuffer += SPI_FLASH_PageSize;

}

SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);

}

}

else

{

if(NumOfPage == 0)

{

if(NumOfSingle 》 count)

{

temp = NumOfSingle - count;

SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);

WriteAddr += count;

pBuffer += count;

SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);

}

else

{

SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite)

}

}

else

{

NumByteToWrite -= count;

NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;

NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;

SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);

WriteAddr += count;

pBuffer += count;

while (NumOfPage--)

{

SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageS

WriteAddr += SPI_FLASH_PageSize;

pBuffer += SPI_FLASH_PageSize;

}

if(NumOfSingle != 0)

{

SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);

}

}

}

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556

}

對數組進行分頁后,就調用SPI_FLASH_PageWrite()對數據進行按頁寫入(是不是和I2C寫入EEPROM的寫函數一樣(連行數都差不多-_-!),不了解的話可以去看之前的I2C部分)

底層寫操作:SPI_FLASH_PageWrite()

void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)

{

/寫使能/

SPI_FLASH_WriteEnable();

/拉低開始通訊/

SPI_FLASH_CS_LOW();

/發送PageProgram(02h))/

SPI_FLASH_SendByte(W25X_PageProgram);

/* Send WriteAddr high nibble address byte to write to */

SPI_FLASH_SendByte((WriteAddr & 0xFF0000) 》》 16);

/* Send WriteAddr medium nibble address byte to write to */

SPI_FLASH_SendByte((WriteAddr & 0xFF00) 》》 8);

/* Send WriteAddr low nibble address byte to write to */

SPI_FLASH_SendByte(WriteAddr & 0xFF);

/這里是判斷寫大小是否符合FLASH規定的256/

if(NumByteToWrite 》 SPI_FLASH_PerWritePageSize)

{

NumByteToWrite = SPI_FLASH_PerWritePageSize;

//printf(“\n\r Err: SPI_FLASH_PageWrite too large!”);

}

/這里才是寫真是數據/

while (NumByteToWrite–)

{

/* Send the current byte */

SPI_FLASH_SendByte(*pBuffer);

/* Point on the next byte to be written */

pBuffer++;

}

/* Deselect the FLASH: Chip Select high */

SPI_FLASH_CS_HIGH();

/* Wait the end of Flash writing */

SPI_FLASH_WaitForWriteEnd();

}

發送完寫入命令Page Program(編碼 02h)及地址之后,可以連續寫入最多256個字節的數據(SPI_FLASH_PerWritePageSize = 256),在發送完數據之后,記得調用SPI_FLASH_WaitForWriteEnd()等待FLASH內部寫時序完成再推出函數。

從FLASH讀取數據:

對于讀取數據,發送一個命令后,可以無限制的一直把整個FLASH的數據都讀取完,直到讀取的數據量足夠了,就拉高片選信號以表示讀取數據結束。

void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)

{

SPI_FLASH_CS_LOW();

SPI_FLASH_SendByte(W25X_ReadData);

/* Send ReadAddr high nibble address byte to read from */

SPI_FLASH_SendByte((ReadAddr & 0xFF0000) 》》 16);

/* Send ReadAddr medium nibble address byte to read from */

SPI_FLASH_SendByte((ReadAddr& 0xFF00) 》》 8);

/* Send ReadAddr low nibble address byte to read from */

SPI_FLASH_SendByte(ReadAddr & 0xFF);

while (NumByteToRead–)

{

/* Read a byte from the FLASH */

*pBuffer = SPI_FLASH_SendByte(Dummy_Byte);

/* Point to the next location where the byte read will be saved*/

pBuffer++;

}

/* Deselect the FLASH: Chip Select high */

SPI_FLASH_CS_HIGH();

}

首先發送一個讀取數據命令 Read Data(03h),接著發送24位讀數據起始地址,STM32再通過D0線接收數據,并使用指針的方式記錄起來


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • FlaSh
    +關注

    關注

    10

    文章

    1633

    瀏覽量

    147940
  • SPI
    SPI
    +關注

    關注

    17

    文章

    1706

    瀏覽量

    91506
收藏 人收藏

    評論

    相關推薦

    【S32K146 RT-Thread】 使用SFUD組件驅動spi flash

    【S32K146 RT-Thread】 使用SFUD組件驅動spi flash
    的頭像 發表于 11-21 01:05 ?261次閱讀
    【S32K146 RT-Thread】<b class='flag-5'>之</b> 使用SFUD組件驅動<b class='flag-5'>spi</b> <b class='flag-5'>flash</b>

    Air201模組教程:SPI通信與外部Flash的連接之道!

    今天我們要學習的是Air201定位模組LuatOS快速入門,本文將通過Air201+擴展板讀寫外部flash的演示,教你使用SPI示例,可根據實際需求靈活應用。
    的頭像 發表于 11-18 00:23 ?219次閱讀
    Air201模組教程:<b class='flag-5'>SPI</b>通信與外部<b class='flag-5'>Flash</b>的連接之道!

    LuatOS入門課|Air201模組與SPI Flash的交互藝術

    今天我會把我了解的關于如何使用SPI讀寫外部Flash教給大家,本文將通過Air201+擴展板讀寫外部flash的演示,教你使用SPI示例,可根據實際需求靈活應用。
    的頭像 發表于 11-17 09:51 ?254次閱讀
    LuatOS入門課|Air201模組與<b class='flag-5'>SPI</b> <b class='flag-5'>Flash</b>的交互藝術

    瀚海微SD NANDSD 協議(36)SPI模式

    簡介 SPI模式由基于flash的SD存儲卡提供的輔助通信協議組成。 這種模式是SD存儲卡協議的一個子集,設計用于與SPI通道通信,通常在摩托羅拉(以及最近一些其他供應商)的微控制器中發現。 接口
    的頭像 發表于 10-08 10:13 ?292次閱讀
    瀚海微SD NAND<b class='flag-5'>之</b>SD 協議(36)<b class='flag-5'>SPI</b>模式

    物聯網行業存儲方案詳解_SPI NOR Flash

    物聯網系統中為什么要使用SPI NOR FLASH 物聯網系統中使用SPI NOR FLASH的原因主要基于其獨特的性能特點和在嵌入式系統中的廣泛應用。以下是詳細的分析: 1、高可靠性
    的頭像 發表于 09-24 14:39 ?276次閱讀
    物聯網行業存儲方案詳解_<b class='flag-5'>SPI</b> NOR <b class='flag-5'>Flash</b>

    spi_flash期間的計時器中斷導致崩潰怎么解決?

    spi_flash_erase_sector(...); spi_flash_write(...); 如果在閃存訪問期間發生計時器中斷,ESP 似乎會崩潰并重新啟動。 當然,這可以通過在訪問 Flash 時禁用中斷來
    發表于 07-12 11:54

    【GD32F303紅楓派開發板使用手冊】第二十講 SPI-SPI NAND FLASH讀寫實驗

    通過本實驗主要學習以下內容: ?SPI通信協議,參考19.2.1東方紅開發板使用手冊 ?GD32F303 SPI操作方式,參考19.2.2東方紅開發板使用手冊 ?NAND FLASH基本原理 ?
    的頭像 發表于 06-20 09:50 ?886次閱讀
    【GD32F303紅楓派開發板使用手冊】第二十講 <b class='flag-5'>SPI-SPI</b> NAND <b class='flag-5'>FLASH</b>讀寫實驗

    【GD32F470紫藤派開發板使用手冊】第十一講 SPI-SPI NOR FLASH讀寫實驗

    通過本實驗主要學習以下內容: ?SPI簡介 ?GD32F470 SPI簡介 ?SPI NOR FLASH——GD25Q32ESIGR簡介 ?使用GD32F470
    的頭像 發表于 05-17 09:57 ?1771次閱讀
    【GD32F470紫藤派開發板使用手冊】第十一講 <b class='flag-5'>SPI-SPI</b> NOR <b class='flag-5'>FLASH</b>讀寫實驗

    STM32F207擦除片內FLASH,退出DEBUG無法執行下一步程序是怎么回事?

    由于項目需求,需要擦除片內指定空間,然后從SPI_FLASH中加載程序運行 問題如下:: 在DEBUG模式下,執行擦除程序后,則退出DEBUG,無法執行下一步程序 擦除代碼如下: 1
    發表于 04-23 07:46

    數位相框電源模組設計

    電子發燒友網站提供《數位相框電源模組設計.pdf》資料免費下載
    發表于 04-17 14:46 ?0次下載

    如何使用SPI的DMA模式讀寫FLASH

    先把讀的部分置換為DMA操作 HAL_SPI_Receive_DMA( hspi1,buffer,4096); 在回調函數中 再Flash_cs端設置為高電平 但程序不能正常運行,請問需要增加什么代碼
    發表于 04-16 07:59

    FATFS對SPI_FLASH新建文件、刪除文件或者修改文件后電腦無法識別,為什么?

    FATFS對SPI_FLASH新建文件、刪除文件或者修改文件后電腦無法識別,而且會斷開連接,需要重新插拔,這是什么問題呢
    發表于 04-09 07:06

    STM32F407ZGT6 spi flash片選引腳無法被拉低的原因?怎么解決?

    我用的芯片是STM32F407ZGT6,RTThread版本5.0.2,spi flash掛載在spi1總線,設備號是spi10 int
    發表于 02-20 07:13

    stm32 flash寫數據怎么存儲的

    stm32 flash寫數據怎么存儲的? STM32是一款廣泛應用于嵌入式系統開發的微控制器,它的Flash存儲器是其中一個重要的組成部分。在本文中,我將詳細介紹
    的頭像 發表于 01-31 15:46 ?2362次閱讀

    stm32f103 flash模擬eeprom

    STM32F103的Flash存儲器可以模擬EEPROM的功能,在本文中我們將詳細介紹如何使用STM32F103的Flash存儲器來實現EEPROM。 概述 EEPROM(Elect
    的頭像 發表于 01-09 11:21 ?2027次閱讀
    主站蜘蛛池模板: 欧美国产在线一区| 久久亚洲视频| 吉吉av电影| 精品伊人久久| 美女脱三角裤| 日本wwwhdsex69| 玩弄朋友娇妻呻吟交换电影| 亚洲AV久久无码精品九号| 亚洲乱码中文字幕久久| 中文字幕欧美一区| www.久久精品视频| 国产伦子沙发午休系列资源曝光| 国产亚洲精品V在线观看一| 九九久久国产精品大片| 嗯啊快拔出来我是你老师视频| 人人在线碰碰视频免费| 亚洲电影成人 成人影院| 在线电影一区二区| 朝鲜黄色录像| 狠狠鲁快播| 牛牛在线视频| 小SAO货叫大声点妓女| 中文字幕按摩| 高跟丝袜岳第一次| 久久精品国产亚洲AV忘忧草蜜臀| 欧美hdxxxx| 亚洲精品成人| A级韩国乱理伦片在线观看| 国产精品成人啪精品视频免费观看 | 5G在线观看免费年龄确认| 成人免费精品视频| 狠狠色狠色综合曰曰| 欧美黑人巨大videos免费| 香港成人社区| AV一区AV久久AV无码| 国内精品自线在拍2020不卡| 蜜芽tv在线www| 亚洲国产韩国欧美在线不卡| 99热这里只有的精品| 国产专区亚洲欧美另类在线| 欧美日韩黄色|