本實(shí)例用的是STM32F103VET6平臺(tái),它有3個(gè)SPI接口(這里使用SPI1),各信號(hào)線連接到FLASH(型號(hào):W25X16)的CS,CLK,DO,DIO線,以實(shí)現(xiàn)SPI通訊,對(duì)FLASH進(jìn)行讀寫。
(這里采用主模式,全雙工通訊,通過(guò)查詢發(fā)送數(shù)據(jù)寄存器和接收數(shù)據(jù)寄存器狀態(tài)確保通訊正常)
mian函數(shù):
1#define sFLASH_ID 0xEF3015(前面加個(gè)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”,F(xiàn)lashID,DeviceID);
if(FlashID == sFLASH_ID)
{
printf(“\r\n 檢測(cè)到 flash W25X16 !\r\n”);
SPI_FLASH_SectorErase(FLASH_SectorToErase);
SPI_FLASH_BufferWrite(Tx_Buffer, FLASH_WriteAddress, BufferSize);
printf(“\r\n 寫入的數(shù)據(jù)為:%s \r\t”, Tx_Buffer);
SPI_FLASH_BufferRead(Rx_Buffer, FLASH_ReadAddress, BufferSize);
printf(“\r\n 讀出的數(shù)據(jù)為:%s \r\n”, Tx_Buffer);
TransferStatus1 = Buffercmp(Tx_Buffer, Rx_Buffer, BufferSize);
if( PASSED == TransferStatus1)
{
printf(“\r\n 2M 串行 flash(W25X16)測(cè)試成功!\n\r”);
}
else
{
printf(“\r\n 2M 串行 flash(W25X16)測(cè)試失?。n\r”);
}
}
else
{
printf(“\r\n 獲取不到 W25X16 ID!\n\r”);
}
SPI_Flash_PowerDown();
while(1);
1234567891011121314151617181920212223242526272829303132333435363738
}
mian函數(shù)的流程:
1,調(diào)用 USART1_Config() 初始化串口;
2,調(diào)用 SPI_FLASH_Init() 初始化SPI模塊;
3,調(diào)用 SPI_FLASH_ReadDeviceID 讀取FLASH器件生產(chǎn)廠商的ID信息;
4,調(diào)用 SPI_FLASH_ReadID 讀取FLASH器件的設(shè)備ID信息;
5,如果讀取ID正確,則調(diào)用 SPI_FLASH_SectorErase()把FLASH內(nèi)容擦除,擦除后調(diào)用 SPI_FLASH_BufferWrite()向FLASH寫入數(shù)據(jù),然后再調(diào)用 SPI_FLASH_BufferRead()從剛剛寫入的地址中讀出數(shù)據(jù),最后調(diào)用 Buffercmp()對(duì)寫入和讀取的數(shù)據(jù)進(jìn)行匹配,匹配成功則把標(biāo)志變量 TransferStatus1賦值為 PASSED(自定義的枚舉變量);
6,根據(jù)標(biāo)志量 TransferStatus1判斷FLASH數(shù)據(jù)的:擦除,寫入,讀取是否正常,分情況輸出到終端;
7,如果讀取FLASH的ID信息錯(cuò)誤,則直接向終端輸出檢測(cè)不到FLASH信息;
8,最后調(diào)用 SPI_Flash_PowerDown()函數(shù)關(guān)閉 FLASH設(shè)備的電源(因?yàn)閿?shù)據(jù)寫入到FLASH后并不會(huì)因斷電而丟失,所以需要使用的時(shí)候再開(kāi)啟FLASH電源);
PS:
讀取器件ID信息可以知道設(shè)備與主機(jī)是否能夠正常工作,也便于區(qū)分不同的器件,可以在使用的FLASH用戶數(shù)據(jù)手冊(cè)找到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個(gè)引腳都設(shè)定好/
/!《 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(); //不用的時(shí)候就拉高
/這里是SPI設(shè)置部分/
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初始化:
根據(jù)《STM32數(shù)據(jù)手冊(cè)》以及《STM32參考手冊(cè)》,把PA5(SCK),PA6(MISO),PA7(MOSI)設(shè)置成復(fù)用推挽輸出,因?yàn)镻A4(NSS)是使用軟件模式,所以設(shè)置為通用退完輸出。
SPI模式初始化:
對(duì)于初始化,是需要根據(jù)通訊的設(shè)備FLASH的SPI特性來(lái)決定的,下面成員分析:
SPI_InitStructure.SPI_Direction= SPI_Direction_2Lines_FullDuplex;
這里設(shè)置通訊模式,這里設(shè)置成全雙工模式(可以在keil環(huán)境下查找其他模式)
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
這里是設(shè)置工作模式,STM32的SPI設(shè)備可以gon工作在主機(jī)模式(SPI_Mode_Master)或從機(jī)模式(SPI_Mode_Slave),這兩個(gè)模式最大的區(qū)別就是SPI的SCK信號(hào)線時(shí)序,SCK的時(shí)序是由通訊中的主機(jī)產(chǎn)生的,如果配置成從機(jī)模式,STM32的SPI模塊將接收外來(lái)的SCK信號(hào)。(這里STM32作為SPI通訊主機(jī),所以設(shè)置成 SPI_Mode_Master)。
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
這個(gè)是設(shè)置SPI每次通訊的數(shù)據(jù)大?。ǚQ為數(shù)據(jù)幀)為8位還是16位(從FLASH的數(shù)據(jù)手冊(cè)可以查到,這里的FLASH的數(shù)據(jù)幀大小為8為,所以要把STM32的SPI模塊設(shè)置相同的)
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;&SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
這兩個(gè)成員是配置SPI的時(shí)鐘極性(CPOL)和時(shí)鐘相位(CPHA),這兩個(gè)配置影響到SPI的通訊模式,要設(shè)置成符合將要互相通訊的設(shè)備的要求。
CPOL:可以取 SPI_CPOL_High(SPI 通訊空閑時(shí) SCK 為高電平)或者SPI_CPOL_Low(SPI 通訊空閑時(shí) SCK 為低電平);
CPHA:可以取 SPI_CPHA_1Edge(在 SCK 的奇數(shù)邊沿采集數(shù)據(jù))或者SPI_CPHA_2Edge (在 SCK 的偶數(shù)邊沿采集數(shù)據(jù));
查詢這個(gè)FLASH的使用手冊(cè),可以了解到這個(gè)FLASH支持以SPI的模式0和模式3通訊。
模式0:在SPI空閑時(shí),SCK為低電平,奇數(shù)邊沿采樣;
模式3:在SPI空閑時(shí),SCK為高電平,偶數(shù)變異采樣;
所以這里配置成模式3,把CPOL賦值為SPI_CPOL_High(SPI空閑時(shí)SCK為高電平),把CPHA賦值為SPI_CPHA_2Edge(在SCK的偶數(shù)邊沿超級(jí)數(shù)據(jù))
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
這里是配置NSS引腳的使用模式,可以選擇為硬件模式(SPI_NSS_Hard)與軟件模式(SPI_NSS_Soft),在硬件模式中的SPI片選由硬件自動(dòng)產(chǎn)生,而軟件模式則需要手動(dòng)把相應(yīng)的FPIO端口拉高或拉低產(chǎn)生非片選和片選信號(hào)(如果外界條件允許,硬件模式還會(huì)自動(dòng)將STM32的SPI設(shè)置為主機(jī))
這里是由軟件產(chǎn)生模式,所以賦值為SPI_NSS_Soft.
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
這里是設(shè)置波特率分頻值,分頻后的時(shí)鐘為SPI的SCK信號(hào)線的時(shí)鐘頻率,這個(gè)成員可以設(shè)置為fpclk的2,4,6,8,32,64,128,256分頻。這里設(shè)置為4分頻
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
所有串行的通訊協(xié)議都會(huì)有MSB先行(高位數(shù)據(jù)在前)還是LSB先行(地位數(shù)據(jù)在前)的問(wèn)題,STM32的SPI模塊可以通過(guò)對(duì)這個(gè)結(jié)構(gòu)體成員,對(duì)這個(gè)特性編程控制。
根據(jù)FLASH的通訊時(shí)序,這里設(shè)置為MSB先行(SPI_FirstBit_MSB)
SPI_InitStructure.SPI_CRCPolynomial = 3;
這里是設(shè)置SPI的CEC校驗(yàn)的多項(xiàng)式,如果使用到CRC校驗(yàn)時(shí),就是用這個(gè)成員的參數(shù)(多項(xiàng)式),來(lái)計(jì)算CRC的值。(這里的FLASH不支持CRC校驗(yàn),所以賦值為3其實(shí)沒(méi)意義)
配置完這些結(jié)構(gòu)體成員后,調(diào)用 SPI_Init()把這些參數(shù)寫入到寄存器中,然后調(diào)用SPI_Cmd()使能SPI1外設(shè)。
PS:
SPI_FLASH_CS_HIGH()這個(gè)實(shí)際是上一個(gè)自定義的宏:
#define SPI_FLASH_CS_HIGH() GPIO_SetBits(GPIOA, GPIO_Pin_4)
實(shí)際上這個(gè)宏就是用來(lái)把 PA4(NSS)引腳拉高,從而禁止SPI通訊
#define SPI_FLASH_CS_LOW() GPIO_ResetBits(GPIOA, GPIO_Pin_4)
如果要需要使用的時(shí)候,就直接拉低就行了這樣就可以開(kāi)始通訊了
控制FLASH的命令:
因?yàn)椴煌脑O(shè)備,都會(huì)相應(yīng)的有不同的指令,如 EEPROM 中會(huì)把第一個(gè)數(shù)據(jù)解釋為存儲(chǔ)矩陣的地址(實(shí)質(zhì)就是指令)。而 FLASH 則定義了更多的指令,有寫指令,讀指令,讀 ID 指令等等。
這些指令,對(duì)主機(jī)來(lái)說(shuō),只是它遵守最基本的通訊協(xié)議發(fā)送出的數(shù)據(jù)。但設(shè)備把這些數(shù)據(jù)解釋成不同的意義(指令編碼),所以才成為指令。在我們配置好 STM32 的協(xié)議模塊后,想要控制設(shè)備,就要遵守相應(yīng)設(shè)備所定義的命令規(guī)則。
指 令 表 中 的 A0~A23 指 地 址 ; M0~M7 為 器 件 的 制 造 商 ID(MANUFACTURER ID);D0~D7 為數(shù)據(jù)。
讀取FLASH ID:
在命令列表可以了解到讀取設(shè)備 ID 的命令(Device ID)編碼為 ABh、dummy、dummy、dummy。表示此命令由這四個(gè)字節(jié)組成,其中dummy意為任意編碼,即這幾個(gè)字節(jié)必須發(fā)送數(shù)據(jù),但這些數(shù)據(jù)是任意的,命令列表中帶括號(hào)的字節(jié)數(shù)據(jù)表示由FLASH返回給主機(jī)的響應(yīng),可以看到Device ID命令的第5個(gè)字節(jié)為從機(jī)返回的響應(yīng),(ID7~ID0),即返回設(shè)備的ID號(hào)。
使用DeviceID命令時(shí)的時(shí)序圖
可以看到主機(jī)首先通過(guò)MOSI線(即FLASH的DIO線)發(fā)送第一個(gè)字節(jié)為ABh編碼,緊接著三個(gè)字節(jié)的dummy編碼,然后FLASH就忽略DIO線上的信號(hào),通過(guò)MISO線(即FLASH的DO線)把它的FLASH設(shè)備ID發(fā)送給主機(jī)。
u32 SPI_FLASH_ReadDeviceID(void)
{
u32 Temp = 0;
/使用的時(shí)候就拉低/
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();
把片選拉低,開(kāi)始通訊
SPI_FLASH_SendByte(W25X_DeviceID);
向FLASH發(fā)送一個(gè)命令字節(jié)編碼:W25X_DeviceID (這里定義的宏為:0XAB)
SPI_FLASH_SendByte(Dummy_Byte);
根據(jù)指令表,發(fā)送完指令后,后面要接著發(fā)送三個(gè)字節(jié)的dummy_Byte(這里宏定義為:0xff,設(shè)置為其他也無(wú)所謂)
Temp = SPI_FLASH_SendByte(Dummy_Byte);
在前面發(fā)送完三個(gè)字節(jié)的 Dummy_Byte后,在第五個(gè)字節(jié),F(xiàn)LASH通過(guò)DIO端口輸出它的器件ID,所以這里再調(diào)用一次SPI_FLASH_SendByte(Dummy_Byte)接收返回值,賦值給Temp.
SPI_FLASH_CS_HIGH();
把片選拉高,結(jié)束通訊
這樣就完成了讀取FLASH ID,這里有一個(gè)相對(duì)底層的函數(shù)SPI_FLASH_SendByte(),它實(shí)現(xiàn)了利用SPI發(fā)送和接收數(shù)據(jù)的功能
u8 SPI_FLASH_SendByte(u8 byte)
{
/等待發(fā)送數(shù)據(jù)寄存器清空/
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
/發(fā)送數(shù)據(jù)/
SPI_I2S_SendData(SPI1, byte);
/等待接收數(shù)據(jù)寄存器為非空/
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
/返回接收到的數(shù)值/
return SPI_I2S_ReceiveData(SPI1);
}
流程:
1,調(diào)用庫(kù)函數(shù) SPI_I2S_GetFlagStatus()等待發(fā)送數(shù)據(jù)寄存器清空;
2,發(fā)送數(shù)據(jù)寄存器準(zhǔn)備好后,調(diào)用庫(kù)函數(shù)SPI_I2S_SendData()向從機(jī)發(fā)送數(shù)據(jù);
3,調(diào)用庫(kù)函數(shù)SPI_I2S_GetFlagStatus()等待接收數(shù)據(jù)寄存器非空;
4,接收寄存器非空時(shí),調(diào)用SPI_I2S_ReceiveData()獲取接收寄存器中的數(shù)據(jù)并作為函數(shù)的返回值,這個(gè)數(shù)據(jù)即由從機(jī)發(fā)送給主機(jī)的數(shù)據(jù);
這是最底層的發(fā)送數(shù)據(jù)和接收數(shù)據(jù)的函數(shù),利用了庫(kù)函數(shù)的標(biāo)志檢測(cè)確保通訊正常。
讀取廠商ID:
u8 SPI_FLASH_ReadID(void)
{
u32 Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;
SPI_FLASH_CS_LOW();//拉低開(kāi)始通訊
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
}
這個(gè)函數(shù)和之前的讀取設(shè)備ID流程也是類型的,差別在于發(fā)送一個(gè)字節(jié)的命令編碼JEDEC ID(9Fh)之后,從機(jī)就通過(guò)D0線返回廠商ID以及0~16位的設(shè)備ID。
讀廠商ID時(shí)序圖
擦除FLASH內(nèi)容:
扇區(qū)擦除(根據(jù)FLASH的儲(chǔ)存原理,在寫入數(shù)據(jù)前,要先對(duì)存儲(chǔ)區(qū)域進(jìn)行擦除,也叫預(yù)寫)
void SPI_FLASH_SectorErase(u32 SectorAddr)
{
/寫使能并且判斷FLASH狀態(tài)/
SPI_FLASH_WriteEnable();
/*這里開(kāi)始是FLASH擦除操作*/
SPI_FLASH_CS_LOW();
SPI_FLASH_SendByte(W25X_SectorErase);
/*這里是擦除一個(gè)扇區(qū),也就是4KB*/
SPI_FLASH_SendByte((SectorAddr & 0xFF0000) 》》 16);
SPI_FLASH_SendByte((SectorAddr & 0xFF00) 》》 8);
SPI_FLASH_SendByte(SectorAddr & 0xFF);
SPI_FLASH_CS_HIGH();
/*再次判斷FLASH狀態(tài)確??梢詧?zhí)行下一次操作*/
SPI_FLASH_WaitForWriteEnd();
1234567891011121314
}
這是扇區(qū)擦除時(shí)序,其中的第一個(gè)字節(jié)為扇區(qū)擦除命令編碼(20h),緊跟其后的為要進(jìn)行擦除的,根據(jù)FLASH的說(shuō)明,整個(gè)存儲(chǔ)矩陣分為塊區(qū)和扇區(qū),每塊(Block)的大小為64KB,每個(gè)扇區(qū)(Sector)的大小為4KB,對(duì)存儲(chǔ)矩陣進(jìn)行擦除時(shí),最小的單位為扇區(qū)。
寫使能:
void SPI_FLASH_WriteEnable(void)
{
SPI_FLASH_CS_LOW();
SPI_FLASH_SendByte(W25X_WriteEnable);
SPI_FLASH_CS_HIGH();
123
}
這里根據(jù)寫使能命令時(shí)序,只要發(fā)送命令WriteEnable(06h)就行了。
讀FLASH狀態(tài):
在擦除操作之前,需要調(diào)用SPI_FLASH_WaitForWriteEnd()來(lái)確保FLASH不忙碌的時(shí)候,才發(fā)送命令或者數(shù)據(jù),通過(guò)讀取FLASH的狀態(tài)寄存器來(lái)獲知他的工作狀態(tài)。
void SPI_FLASH_WaitForWriteEnd(void)
{
u8 FLASH_Status = 0;
SPI_FLASH_CS_LOW();
SPI_FLASH_SendByte(W25X_ReadStatusReg);
/*一直檢測(cè)FLASH狀態(tài)寄存器狀態(tài),直到Bit0位(BUSY位)為0)*/
do
{
FLASH_Status = SPI_FLASH_SendByte(Dummy_Byte);
}while((FLASH_Status & WIP_Flag) == SET);
SPI_FLASH_CS_HIGH();
12345678910
}
整個(gè)函數(shù)實(shí)質(zhì)是不斷的循環(huán)檢測(cè)FLASH狀態(tài)寄存器的Busy位,知道FLASH的內(nèi)部寫時(shí)序完成,從而確保下一通訊操作正常。主機(jī)通過(guò)發(fā)送讀狀態(tài)寄存器命令Read Status Register(05h 編碼),返回的為他的8為狀態(tài)寄存的值。
檢測(cè)FLASH的狀態(tài)寄存器的Bit0(BUSY位),當(dāng)FLASH在執(zhí)行內(nèi)部寫時(shí)序的時(shí)候,除了讀狀態(tài)寄存器命令,其他的一切命令他都會(huì)忽略,并且BUSY位保持為1,所以我們需要等待BUSY位為0的時(shí)候,再向FLASH發(fā)送其他命令。
向FLASH寫入數(shù)據(jù):
對(duì)FLASH寫入數(shù)據(jù),最小單位是256字節(jié),廠商把這個(gè)單位曾為頁(yè)。寫入時(shí),一般也只有頁(yè)寫入的方式,所以為了方便的把一個(gè)很長(zhǎng)的數(shù)據(jù)寫入到FLASH時(shí),一般需要進(jìn)行轉(zhuǎn)換,把數(shù)據(jù)按頁(yè)分好,再寫入到FLASH中(類似于I2C對(duì)EEPROM的頁(yè)寫入,只是頁(yè)的大小不同而已)。
void SPI_FLASH_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{
u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp= 0;
/這里劃分好數(shù)據(jù)需要寫多少頁(yè),寫地址,寫大小/
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
}
對(duì)數(shù)組進(jìn)行分頁(yè)后,就調(diào)用SPI_FLASH_PageWrite()對(duì)數(shù)據(jù)進(jìn)行按頁(yè)寫入(是不是和I2C寫入EEPROM的寫函數(shù)一樣(連行數(shù)都差不多-_-?。涣私獾脑捒梢匀タ粗暗腎2C部分)
底層寫操作:SPI_FLASH_PageWrite()
void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{
/寫使能/
SPI_FLASH_WriteEnable();
/拉低開(kāi)始通訊/
SPI_FLASH_CS_LOW();
/發(fā)送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規(guī)定的256/
if(NumByteToWrite 》 SPI_FLASH_PerWritePageSize)
{
NumByteToWrite = SPI_FLASH_PerWritePageSize;
//printf(“\n\r Err: SPI_FLASH_PageWrite too large!”);
}
/這里才是寫真是數(shù)據(jù)/
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();
}
發(fā)送完寫入命令Page Program(編碼 02h)及地址之后,可以連續(xù)寫入最多256個(gè)字節(jié)的數(shù)據(jù)(SPI_FLASH_PerWritePageSize = 256),在發(fā)送完數(shù)據(jù)之后,記得調(diào)用SPI_FLASH_WaitForWriteEnd()等待FLASH內(nèi)部寫時(shí)序完成再推出函數(shù)。
從FLASH讀取數(shù)據(jù):
對(duì)于讀取數(shù)據(jù),發(fā)送一個(gè)命令后,可以無(wú)限制的一直把整個(gè)FLASH的數(shù)據(jù)都讀取完,直到讀取的數(shù)據(jù)量足夠了,就拉高片選信號(hào)以表示讀取數(shù)據(jù)結(jié)束。
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();
}
首先發(fā)送一個(gè)讀取數(shù)據(jù)命令 Read Data(03h),接著發(fā)送24位讀數(shù)據(jù)起始地址,STM32再通過(guò)D0線接收數(shù)據(jù),并使用指針的方式記錄起來(lái)
-
FlaSh
+關(guān)注
關(guān)注
10文章
1633瀏覽量
147939 -
SPI
+關(guān)注
關(guān)注
17文章
1706瀏覽量
91502
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論