91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

淺談STM32之SPI_FLASH之應(yīng)用實(shí)例

ss ? 來源:未知 ? 作者:沈丹 ? 2018-10-07 11:29 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

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

本實(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)行讀寫。

(這里采用主模式,全雙工通訊,通過查詢發(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í)候再開啟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特性來決定的,下面成員分析:

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模塊將接收外來的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ù)在前)的問題,STM32的SPI模塊可以通過對(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)式),來計(jì)算CRC的值。(這里的FLASH不支持CRC校驗(yàn),所以賦值為3其實(shí)沒意義)

配置完這些結(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è)宏就是用來把 PA4(NSS)引腳拉高,從而禁止SPI通訊

#define SPI_FLASH_CS_LOW() GPIO_ResetBits(GPIOA, GPIO_Pin_4)

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

控制FLASH的命令:

因?yàn)椴煌脑O(shè)備,都會(huì)相應(yīng)的有不同的指令,如 EEPROM 中會(huì)把第一個(gè)數(shù)據(jù)解釋為存儲(chǔ)矩陣的地址(實(shí)質(zhì)就是指令)。而 FLASH 則定義了更多的指令,有寫指令,讀指令,讀 ID 指令等等。

這些指令,對(duì)主機(jī)來說,只是它遵守最基本的通訊協(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ī)首先通過MOSI線(即FLASH的DIO線)發(fā)送第一個(gè)字節(jié)為ABh編碼,緊接著三個(gè)字節(jié)的dummy編碼,然后FLASH就忽略DIO線上的信號(hào),通過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();

把片選拉低,開始通訊

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è)置為其他也無所謂)

Temp = SPI_FLASH_SendByte(Dummy_Byte);

在前面發(fā)送完三個(gè)字節(jié)的 Dummy_Byte后,在第五個(gè)字節(jié),F(xiàn)LASH通過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)用庫函數(shù) SPI_I2S_GetFlagStatus()等待發(fā)送數(shù)據(jù)寄存器清空;

2,發(fā)送數(shù)據(jù)寄存器準(zhǔn)備好后,調(diào)用庫函數(shù)SPI_I2S_SendData()向從機(jī)發(fā)送數(shù)據(jù);

3,調(diào)用庫函數(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ù),利用了庫函數(shù)的標(biāo)志檢測(cè)確保通訊正常。

讀取廠商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

}

這個(gè)函數(shù)和之前的讀取設(shè)備ID流程也是類型的,差別在于發(fā)送一個(gè)字節(jié)的命令編碼JEDEC ID(9Fh)之后,從機(jī)就通過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();

SPI_FLASH_WaitForWriteEnd();

/*這里開始是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的說明,整個(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()來確保FLASH不忙碌的時(shí)候,才發(fā)送命令或者數(shù)據(jù),通過讀取FLASH的狀態(tà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ī)通過發(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è)單位曾為頁。寫入時(shí),一般也只有頁寫入的方式,所以為了方便的把一個(gè)很長(zhǎng)的數(shù)據(jù)寫入到FLASH時(shí),一般需要進(jìn)行轉(zhuǎn)換,把數(shù)據(jù)按頁分好,再寫入到FLASH中(類似于I2C對(duì)EEPROM的頁寫入,只是頁的大小不同而已)。

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

{

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

/這里劃分好數(shù)據(jù)需要寫多少頁,寫地址,寫大小/

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)行分頁后,就調(diào)用SPI_FLASH_PageWrite()對(duì)數(shù)據(jù)進(jìn)行按頁寫入(是不是和I2C寫入EEPROM的寫函數(shù)一樣(連行數(shù)都差不多-_-?。?,不了解的話可以去看之前的I2C部分)

底層寫操作:SPI_FLASH_PageWrite()

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

{

/寫使能/

SPI_FLASH_WriteEnable();

/拉低開始通訊/

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è)命令后,可以無限制的一直把整個(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再通過D0線接收數(shù)據(jù),并使用指針的方式記錄起來


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • FlaSh
    +關(guān)注

    關(guān)注

    10

    文章

    1747

    瀏覽量

    155489
  • SPI
    SPI
    +關(guān)注

    關(guān)注

    17

    文章

    1885

    瀏覽量

    101187
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    STM32L062x8:超低功耗32位MCU的卓越

    STM32L062x8:超低功耗32位MCU的卓越選 在當(dāng)今的電子設(shè)計(jì)領(lǐng)域,低功耗、高性能的微控制器(MCU)是眾多應(yīng)用的核心需求。STMicroelectronics推出的STM32
    的頭像 發(fā)表于 03-02 15:20 ?93次閱讀

    STM32L072xx系列微控制器:低功耗設(shè)計(jì)的優(yōu)選

    STM32L072xx系列微控制器:低功耗設(shè)計(jì)的優(yōu)選選 在當(dāng)今的電子設(shè)備設(shè)計(jì)中,低功耗、高性能的微控制器是眾多工程師追求的目標(biāo)。STMicroelectronics推出的STM32L072xx系列
    的頭像 發(fā)表于 02-28 11:35 ?227次閱讀

    TLC69699:SPI兼容連接的理想

    TLC69699:SPI兼容連接的理想選 在電子設(shè)備的設(shè)計(jì)中,選擇合適的芯片來實(shí)現(xiàn)設(shè)備間的通信和控制至關(guān)重要。TLC69699作為一款具有SPI兼容連接功能的芯片,為TLC696xx設(shè)備家族的控制
    的頭像 發(fā)表于 02-26 17:30 ?488次閱讀

    STM32L052x6/8:超低功耗32位MCU的卓越

    STM32L052x6/8:超低功耗32位MCU的卓越選 在當(dāng)今的電子設(shè)備設(shè)計(jì)中,低功耗、高性能的微控制器(MCU)是眾多應(yīng)用的核心需求。STM32L052x6/8系列MCU憑借其出色的特性,成為
    的頭像 發(fā)表于 02-11 15:20 ?138次閱讀

    深入解析Rockchip SFC驅(qū)動(dòng):SPI Flash傳輸流程與問題排查指南

    在嵌入式系統(tǒng)中,SPI Flash憑借小巧、低功耗、高速的特性,廣泛用于存儲(chǔ)固件、配置參數(shù)等關(guān)鍵數(shù)據(jù)。Rockchip作為主流嵌入式SOC廠商,提供了專門的 SFC(Serial Flash
    的頭像 發(fā)表于 02-04 07:13 ?421次閱讀
    深入解析Rockchip SFC驅(qū)動(dòng):<b class='flag-5'>SPI</b> <b class='flag-5'>Flash</b>傳輸流程與問題排查指南

    SPI NOR FlashSPI NAND Flash存儲(chǔ)芯片的區(qū)別

    SPI NOR FlashSPI NAND Flash并非相互替代,而是互補(bǔ)關(guān)系。SPI NOR勝在讀取速度快、使用簡(jiǎn)單、可靠性高,是代碼
    的頭像 發(fā)表于 01-29 16:58 ?449次閱讀
    <b class='flag-5'>SPI</b> NOR <b class='flag-5'>Flash</b>和<b class='flag-5'>SPI</b> NAND <b class='flag-5'>Flash</b>存儲(chǔ)芯片的區(qū)別

    深度剖析MAX9939:SPI可編程增益放大器的卓越

    深度剖析MAX9939:SPI可編程增益放大器的卓越選 在電子工程師的設(shè)計(jì)工作中,選擇合適的放大器對(duì)于信號(hào)處理至關(guān)重要。今天,我們就來深入探討一款功能強(qiáng)大的放大器——MAX9939,它是一款SPI
    的頭像 發(fā)表于 01-15 11:05 ?241次閱讀

    國(guó)產(chǎn)SPI NOR Flash接口閃存介紹

    在當(dāng)今各類電子設(shè)備對(duì)存儲(chǔ)性能要求日益提升的背景下,SPI NOR Flash憑借其高速讀取、低功耗及靈活接口等優(yōu)勢(shì),成為嵌入式系統(tǒng)代碼存儲(chǔ)的關(guān)鍵元件。GT25Q系列SPI NOR Flash
    的頭像 發(fā)表于 12-26 11:51 ?436次閱讀

    FPGA實(shí)現(xiàn)基于SPI協(xié)議的Flash驅(qū)動(dòng)控制芯片擦除

    本篇博客具體包括SPI協(xié)議的基本原理、模式選擇以及時(shí)序邏輯要求,采用FPGA(EPCE4),通過SPI通信協(xié)議,對(duì)flash(W25Q16BV)存儲(chǔ)的固化程序進(jìn)行芯片擦除操作。
    的頭像 發(fā)表于 12-02 10:00 ?2571次閱讀
    FPGA實(shí)現(xiàn)基于<b class='flag-5'>SPI</b>協(xié)議的<b class='flag-5'>Flash</b>驅(qū)動(dòng)控制芯片擦除

    高性能SPI NOR FLASH芯片ZB25VQ系列推薦

    在嵌入式系統(tǒng)、物聯(lián)網(wǎng)設(shè)備及各類存儲(chǔ)應(yīng)用中,SPI NOR FLASH芯片因其接口簡(jiǎn)單、功耗低、讀寫速度快等特點(diǎn),成為代碼存儲(chǔ)與數(shù)據(jù)緩存的常見選擇。SPI NOR FLASH是一種基于
    的頭像 發(fā)表于 12-01 14:52 ?621次閱讀

    STM32C011開發(fā)(3)----Flash操作

    STM32C011 系列微控制器內(nèi)置 Flash 存儲(chǔ)器,支持程序存儲(chǔ)與數(shù)據(jù)保存,具備頁面擦除、雙字寫入、讀寫保護(hù)等功能。本文將簡(jiǎn)要介紹 STM32C011 的 Flash 結(jié)構(gòu)與特性
    的頭像 發(fā)表于 09-18 16:48 ?4851次閱讀
    <b class='flag-5'>STM32</b>C011開發(fā)(3)----<b class='flag-5'>Flash</b>操作

    SPI NOR FLASH是什么,與SPI NAND Flash的區(qū)別

    SPI NOR FLASH是什么? ? SPI NOR FLASH是一種非易失性存儲(chǔ)器,它通過串行接口進(jìn)行數(shù)據(jù)傳輸,具有讀寫速度快、可靠性高、體積小等優(yōu)點(diǎn)。它采用類似SRAM的存儲(chǔ)方式
    的頭像 發(fā)表于 08-21 09:26 ?1566次閱讀

    SFUD驅(qū)動(dòng)庫實(shí)戰(zhàn)手冊(cè):串行SPI Flash開發(fā)全流程解析

    針對(duì)嵌入式系統(tǒng)中SPI Flash的多樣化需求,SFUD庫提供了靈活且通用的解決方案。本文將從環(huán)境配置、庫初始化、基本操作到高級(jí)特性,完整展示SFUD庫的應(yīng)用流程,并通過具體示例幫助開發(fā)者深入理解其
    的頭像 發(fā)表于 07-29 13:19 ?722次閱讀
    SFUD驅(qū)動(dòng)庫實(shí)戰(zhàn)手冊(cè):串行<b class='flag-5'>SPI</b> <b class='flag-5'>Flash</b>開發(fā)全流程解析

    兆易創(chuàng)新推出GD5F1GM9系列高速Q(mào)SPI NAND Flash

    干擾的行業(yè)痛點(diǎn)。作為一種巧妙融合了NOR Flash高速讀取優(yōu)勢(shì)與NAND Flash大容量、低成本優(yōu)勢(shì)的新型解決方案,GD5F1GM9系列的面世將為SPI NAND Flash帶來新
    的頭像 發(fā)表于 04-16 13:50 ?1419次閱讀

    STM32定時(shí)器基本原理及常見問題培訓(xùn)資料

    STM32 定時(shí)器基本原理及常見問題培訓(xùn)資料v3.10 時(shí)基單元、捕捉比較功能、主從觸發(fā)與級(jí)聯(lián)、案例分享 培訓(xùn)內(nèi)容:
    發(fā)表于 04-08 16:26