本文主要介紹STM32多種的內(nèi)部Flash讀寫(xiě)方式和讀寫(xiě)長(zhǎng)文件的功能函數(shù)怎樣編寫(xiě)。閱讀完本文可以使你能夠正常的完成Flash讀寫(xiě)操作。
介紹
STM32 FLASH

不同型號(hào)的 STM32,其 FLASH 容量也有所不同,最小的只有 16K 字節(jié),最大的則達(dá)到了1024K 字節(jié)。本次實(shí)驗(yàn)選用的STM32 開(kāi)發(fā)板是F103ZET6,其 FLASH 容量為 512K 字節(jié),屬于大容量產(chǎn)品(另外還有中容量和小容量產(chǎn)品),大容量產(chǎn)品的閃存模塊組織如圖 所示:
STM32 的閃存模塊由:主存儲(chǔ)器、信息塊和閃存存儲(chǔ)器接口寄存器等 3 部分組成。
主存儲(chǔ)器,該部分用來(lái)存放代碼和數(shù)據(jù)常數(shù)(如 const 類型的數(shù)據(jù))。對(duì)于大容量產(chǎn)品,其被劃分為 256 頁(yè),每頁(yè) 2K 字節(jié)。注意,小容量和中容量產(chǎn)品則每頁(yè)只有 1K 字節(jié)。從上圖可以看出主存儲(chǔ)器的起始地址就是0X08000000, B0、B1 都接 GND 的時(shí)候,就是從 0X08000000開(kāi)始運(yùn)行代碼的。
信息塊,該部分分為 2 個(gè)小部分,其中啟動(dòng)程序代碼,是用來(lái)存儲(chǔ) ST 自帶的啟動(dòng)程序,用于串口下載代碼,當(dāng) B0 接 V3.3,B1 接 GND 的時(shí)候,運(yùn)行的就是這部分代碼。用戶選擇字節(jié),則一般用于配置寫(xiě)保護(hù)、讀保護(hù)等功能。
閃存存儲(chǔ)器接口寄存器,該部分用于控制閃存讀寫(xiě)等,是整個(gè)閃存模塊的控制機(jī)構(gòu)。對(duì)主存儲(chǔ)器和信息塊的寫(xiě)入由內(nèi)嵌的閃存編程/擦除控制器(FPEC)管理;編程與擦除的高電壓由內(nèi)部產(chǎn)生。
在執(zhí)行閃存寫(xiě)操作時(shí),任何對(duì)閃存的讀操作都會(huì)鎖住總線,在寫(xiě)操作完成后讀操作才能正確地進(jìn)行;既在進(jìn)行寫(xiě)或擦除操作時(shí),不能進(jìn)行代碼或數(shù)據(jù)的讀取操作。
閃存的編程和擦除
STM32 的閃存編程是由 FPEC(閃存編程和擦除控制器)模塊處理的,這個(gè)模塊包含 7 個(gè)
32 位寄存器,他們分別是:
FPEC 鍵寄存器(FLASH_KEYR)
選擇字節(jié)鍵寄存器(FLASH_OPTKEYR)
閃存控制寄存器(FLASH_CR)
閃存狀態(tài)寄存器(FLASH_SR)
閃存地址寄存器(FLASH_AR)
選擇字節(jié)寄存器(FLASH_OBR)

寫(xiě)保護(hù)寄存器(FLASH_WRPR)
STM32 復(fù)位后,F(xiàn)PEC 模塊是被保護(hù)的,不能寫(xiě)入 FLASH_CR 寄存器;通過(guò)寫(xiě)入特定的序列到 FLASH_KEYR 寄存器可以打開(kāi) FPEC 模塊,只有在寫(xiě)保護(hù)被解除后,我們才能操作相關(guān)寄存器。
STM32 閃存的編程每次必須寫(xiě)入 16 位(不能單純的寫(xiě)入 8 位數(shù)據(jù)哦!),當(dāng) FLASH_CR 寄存器的 PG 位為’1’時(shí),在一個(gè)閃存地址寫(xiě)入一個(gè)半字將啟動(dòng)一次編程;寫(xiě)入任何非半字的數(shù)據(jù),F(xiàn)PEC 都會(huì)產(chǎn)生總線錯(cuò)誤。在編程過(guò)程中(BSY 位為’1’),任何讀寫(xiě)閃存的操作都會(huì)使 CPU暫停,直到此次閃存編程結(jié)束。
同樣,STM32 的 FLASH 在編程的時(shí)候,也必須要求其寫(xiě)入地址的 FLASH 是被擦除了的(也就是其值必須是 0XFFFF),否則無(wú)法寫(xiě)入,在FLASH_SR 寄存器的 PGERR 位將得到一個(gè)警告。
STM23 的 FLASH 寫(xiě)入過(guò)程如圖所示。
STM32的Flash寫(xiě)入順序如下:
檢查 FLASH_CR 的 LOCK 是否解鎖,如果沒(méi)有則先解鎖
檢查 FLASH_SR 寄存器的 BSY 位,以確認(rèn)沒(méi)有其他正在進(jìn)行的編程操作
設(shè)置 FLASH_CR 寄存器的 PG 位為’1’
在指定的地址寫(xiě)入要編程的半字
等待 BSY 位變?yōu)椤?’ - 讀出寫(xiě)入的地址并驗(yàn)證數(shù)據(jù)
Flash讀寫(xiě)的標(biāo)準(zhǔn)庫(kù)函數(shù)
解鎖函數(shù):void FLASH_Unlock(void);
對(duì) FLASH 進(jìn)行寫(xiě)操作前必須先解鎖,解鎖操作也就是必須在 FLASH_KEYR 寄存器寫(xiě)入特定的序列,固件庫(kù)函數(shù)實(shí)現(xiàn)很簡(jiǎn)單:只需要直接調(diào)用 FLASH_Unlock();即可。
鎖定函數(shù):void FLASH_Lock(void);
有解鎖當(dāng)然就有上鎖,為了保護(hù)Flash,讀寫(xiě)和擦除全部需要的Flash后需要上鎖,只需要調(diào)用:FLASH_Lock();
寫(xiě)操作函數(shù):
固件庫(kù)提供了三個(gè) FLASH 寫(xiě)函數(shù):
FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);
顧名思義分別為:FLASH_ProgramWord 為 32 位字寫(xiě)入函數(shù),其他分別為 16 位半字寫(xiě)入和用戶選擇字節(jié)寫(xiě)入函數(shù)。這里需要說(shuō)明,32 位字節(jié)寫(xiě)入實(shí)際上是寫(xiě)入的兩次 16 位數(shù)據(jù),寫(xiě)完第一次后地址+2,這與我們前面講解的 STM32 閃存的編程每次必須寫(xiě)入 16 位并不矛盾。寫(xiě)入 8位實(shí)際也是占用的兩個(gè)地址了,跟寫(xiě)入 16 位基本上沒(méi)啥區(qū)別。
4. 獲取 FLASH 狀態(tài)
主要是用的函數(shù)是:FLASH_Status FLASH_GetStatus(void);
返回值是通過(guò)枚舉類型定義的,分別為:
FLASH_BUSY = 1,//忙
FLASH_ERROR_PG,//編程錯(cuò)誤
FLASH_ERROR_WRP,//寫(xiě)保護(hù)錯(cuò)誤
FLASH_COMPLETE,//操作完成
FLASH_TIMEOUT//操作超時(shí)
5. 等待操作完成函數(shù)
在執(zhí)行閃存寫(xiě)操作時(shí),任何對(duì)閃存的讀操作都會(huì)鎖住總線,在寫(xiě)操作完成后讀操作才能正確地進(jìn)行;既在進(jìn)行寫(xiě)或擦除操作時(shí),不能進(jìn)行代碼或數(shù)據(jù)的讀取操作。
所以在每次操作之前,我們都要等待上一次操作完成這次操作才能開(kāi)始。使用的函數(shù)是:FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout)入口參數(shù)為等待時(shí)間,返回值是 FLASH 的狀態(tài),這個(gè)很容易理解,這個(gè)函數(shù)本身我們?cè)诠碳?kù)中使用得不多,但是在固件庫(kù)函數(shù)體中間可以多次看到。
6. 讀 FLASH 特定地址數(shù)據(jù)函數(shù)
有寫(xiě)就必定有讀,而讀取 FLASH 指定地址的半字的函數(shù)固件庫(kù)并沒(méi)有給出來(lái),這里我們自己寫(xiě)的一個(gè)函數(shù)。
u16 STMFLASH_ReadHalfWord(u32 faddr){return *(vu16*)faddr; }
軟件設(shè)計(jì)
FLASH的讀取
直接讀取某一地址的內(nèi)容
因?yàn)樽x取FLASH并不需要解鎖,我們可以直接用指針指向所讀的地址,之后讀取此地址的內(nèi)容即可。
p = (uint32_t *)(0x08008000);printf("\r\n讀取內(nèi)部FLASH該地址存儲(chǔ)的內(nèi)容為:0x%x",*p);
此程序就是先將0x08008000賦給指針變量P,之后將P指向地址的內(nèi)容以16進(jìn)制的格式輸出出來(lái)。
讀取選定位置的選定大小的內(nèi)容
首先我們編寫(xiě)一個(gè)函數(shù),用以讀取指定地址的半字(16位數(shù)據(jù))。
u16 STMFLASH_ReadHalfWord(u32 faddr){ return *(vu16*)faddr; }
從指定地址開(kāi)始讀出指定長(zhǎng)度的數(shù)據(jù)
LReadAddr:起始地址
pBuffer:數(shù)據(jù)指針
NumToWrite:半字(16位)數(shù)
void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead) { u16 i; for(i=0;i當(dāng)我們想讀取FLASH內(nèi)容時(shí),只需要直接調(diào)用上面的函數(shù)即可。
STMFLASH_Read(FLASH_ADDR,Temporary_storage,size);這里FLASH_ADDR是我們要讀取的起始地址,Temporary_storage是
16位的指針變量,存放我們讀取到的內(nèi)容, size是我們要讀取的大小,值得注意的是,size是半字大小,也就是有多少個(gè)兩個(gè)字節(jié)。比如我們要讀取100個(gè)字節(jié),size就可以填50。FLASH的寫(xiě)入
直接使用標(biāo)準(zhǔn)庫(kù)寫(xiě)入
首先需要先解鎖
FLASH_Unlock();寫(xiě)入前需要擦除當(dāng)前頁(yè),對(duì)擦除有不理解的可以看我的另一篇文章:基于STM32的Flash擦除方式
FLASH_ErasePage(0x08000000+2*1024*5);之后可以調(diào)用固件庫(kù)函數(shù),進(jìn)行寫(xiě)入。例如向地址 0x08000000+210245 至 0x08000000+210246 地址寫(xiě)入數(shù)據(jù)
FLASH_ProgramWord(0x08000000+2*1024*5,0x01234567);寫(xiě)入之后,不要忘了上鎖。
FLASH_Lock();寫(xiě)入選定位置的選定大小的內(nèi)容
我們首先編寫(xiě)一個(gè)不檢查的寫(xiě)入的函數(shù)。
WriteAddr:起始地址,pBuffer:數(shù)據(jù)指針,NumToWrite:半字(16位)數(shù) 。void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite) { u16 i; for(i=0;i之后編寫(xiě)函數(shù),實(shí)現(xiàn)從指定地址寫(xiě)入指定大小的指定內(nèi)容。
void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite) { u32 secpos; //扇區(qū)地址 u16 secoff; //扇區(qū)內(nèi)偏移地址(16位字計(jì)算) u16 secremain; //扇區(qū)內(nèi)剩余地址(16位字計(jì)算) u16 i; u32 offaddr; //去掉0X08000000后的地址 if(WriteAddr=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))return;//非法地址 FLASH_Unlock(); //解鎖 offaddr=WriteAddr-STM32_FLASH_BASE; //實(shí)際偏移地址. secpos=offaddr/STM_SECTOR_SIZE; //扇區(qū)地址 0~127 for STM32F103RBT6 secoff=(offaddr%STM_SECTOR_SIZE)/2; //在扇區(qū)內(nèi)的偏移(2個(gè)字節(jié)為基本單位.) secremain=STM_SECTOR_SIZE/2-secoff; //扇區(qū)剩余空間大小 if(NumToWrite<=secremain)secremain=NumToWrite;//不大于該扇區(qū)范圍 while(1) { STMFLASH_Read(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//讀出整個(gè)扇區(qū)的內(nèi)容 for(i=0;i (STM_SECTOR_SIZE/2))secremain=STM_SECTOR_SIZE/2;//下一個(gè)扇區(qū)還是寫(xiě)不完 else secremain=NumToWrite;//下一個(gè)扇區(qū)可以寫(xiě)完了 } }; FLASH_Lock();//上鎖} 使用時(shí),我們只需要當(dāng)我們功能需要寫(xiě)入Flash時(shí),調(diào)用此函數(shù)即可。
STMFLASH_Write(FLASH_ADDR,flg_false,size);//將標(biāo)志位置為更改為0x00此語(yǔ)句實(shí)現(xiàn)從FLASH_ADDR地址寫(xiě)入size大小的Temporary_storage數(shù)據(jù)。
-
寄存器
+關(guān)注
關(guān)注
31文章
5434瀏覽量
124528 -
FlaSh
+關(guān)注
關(guān)注
10文章
1679瀏覽量
151853 -
STM32
+關(guān)注
關(guān)注
2293文章
11032瀏覽量
365029
發(fā)布評(píng)論請(qǐng)先 登錄
通過(guò)對(duì)stm32內(nèi)部的flash的讀寫(xiě)可以實(shí)現(xiàn)對(duì)stm32的編程操作
對(duì)flash讀寫(xiě)可實(shí)現(xiàn)對(duì)stm32的編程操作
如何操作芯片內(nèi)部EEprom讀寫(xiě)數(shù)據(jù)
怎樣對(duì)STM32內(nèi)部的FLASH進(jìn)行讀寫(xiě)操作呢
STM32怎么讀寫(xiě)內(nèi)部flash的注意點(diǎn)呢
讀寫(xiě)STM32內(nèi)部的FLASH問(wèn)題解析
STM32內(nèi)部Flash讀寫(xiě)問(wèn)題

STM32F103:內(nèi)部Flash的讀寫(xiě)

HAL庫(kù)之讀寫(xiě)STM32F103內(nèi)部的FLASH空間

STM32讀寫(xiě)內(nèi)部flash注意點(diǎn)

STM32F4內(nèi)部Flash讀寫(xiě)

STM32 內(nèi)部Flash讀寫(xiě) 程序源碼 [已驗(yàn)證]
![<b class='flag-5'>STM32</b> <b class='flag-5'>內(nèi)部</b><b class='flag-5'>Flash</b><b class='flag-5'>讀寫(xiě)</b> 程序源碼 [已驗(yàn)證]](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
STM32CUBEIDE(16)----內(nèi)部Flash讀寫(xiě)

評(píng)論