一、內部flash簡介
- 在 STM32 芯片內部有一個 FLASH 存儲器,它主要用於存儲代碼 。
- 我們在電腦上編寫好應用程序后,使用下載器把編譯后的代碼文件燒錄到該內部 FLASH 中 。
- FLASH 存儲器的內容在掉電后不會丟失,芯片重新上電復位后,內核可從內部 FLASH 中加載代碼並運行。
- 訪問內部flash的速度比外部的SPI-Flash要快。
- flash擦除時是按扇區擦除,使用電擦除,設備電壓1.8V ~2.1V按字節(8bit)擦除,2.1V ~2.7V擦除半字(16bit),2.7V ~ 3.6V擦除一個字(32bit)
2.7V to 3.6V +外部電壓擦除兩個字(64bit),
二、內部flash的構成
STM32 的內部 FLASH 包含主存儲器、系統存儲器以及選項字節區域,它們的地址分布及大小見下表。
1、主存儲器
- 一般我們說STM32內部FLASH的時候,都是指這個主存儲器區域,它是存儲用戶應用程序的空間,芯片型號說明中的256K FLASH、512K FLASH都是指這個區域的大小。
- 主存儲器分為256頁,每須大小為2KB,共512KB。這個分頁的概念,實質就是FLASH存儲器的扇區,與其它FLASH - -樣,在寫入數據前,要先按頁(扇區)擦除。
2、系統存儲區
系統存儲區是用戶不能訪問的區域,它在芯片出廠時已經固化了啟動代碼,它負責實現串口、 USB 以及 CAN 等 ISP 燒錄功能。
3、選項字節
選項字節用於配置 FLASH 的讀寫保護、待機/停機復位、軟件/硬件看門狗等功能,這部分共 16 字節。可以通過修改 FLASH 的選項控制寄存器修改。
三、對內部flash的寫入過程
1.解鎖
由於內部FLASH空間主要存儲的是應用程序,是非常關鍵的數據,為了防止誤操作修改了這些內容,芯片復位后默認會給控制寄存器FLASH _CR上鎖,這個時候不允許設置FLASH的控制寄存器,從而不能修改FLASH中的內容。所以對FLASH寫入數據前,需要先給它解鎖。解鎖的操作步驟如下:
(1) 往FPEC鍵寄存器FLASH_ KEYR中寫入KEY1 = 0x45670123
(2)再往FPEC鍵寄存器FLASH_ KEYR中寫入KEY2 = 0xCDEF89AB
2.頁擦除.
在寫入新的數據前,需要先擦除存儲區域,STM32提供了頁(扇區)擦除指令和整個FLASH擦除(批量擦除)的指令,批量擦除指令僅針對主存儲區。頁擦除的過程如下:
(1) 檢查FLASH_ SR寄存器中的“忙碌寄存器位BSY”,以確認當前未執行任何Flash操作;
(2)在FLASH_ CR寄存器中,將“激活頁擦除寄存器位PER”置1。
(3)用FLASHAR寄存器選擇要擦除的頁;
(4) 將FLASH _CR寄存器中的“開始擦除寄存器位STRT"置1,開始擦除;
(5)等待BSY位被清零時,表示擦除完成。
3.寫入數據
擦除完畢后即可寫入數據,寫入數據的過程並不是僅僅使用指針向地址賦值,賦值前還還需要配置一-系列的寄存器,步驟如下:
(1) 檢查FLASH_ SR中的BSY位,以確認當前未執行任何其它的內部Flash操作;
(2) 將FLASH_ CR寄存器中的“激活編程寄存器位PG”置1;
(3)向指定的FLASH存儲器地址執行數據寫入操作,每次只能以16位的方式寫入;
(4)等待 BSY位被清零時,表示寫入完成。
/**
* @brief InternalFlash_Test,對內部FLASH進行讀寫測試
* @param None
* @retval None
*/
int InternalFlash_Test(void)
{
uint32_t EraseCounter = 0x00; //記錄要擦除多少頁
uint32_t Address = 0x00; //記錄寫入的地址
uint32_t Data = 0x3210ABCD; //記錄寫入的數據
uint32_t NbrOfPage = 0x00; //記錄寫入多少頁
FLASH_Status FLASHStatus = FLASH_COMPLETE; //記錄每次擦除的結果
TestStatus MemoryProgramStatus = PASSED;//記錄整個測試結果
/* 解鎖 */
FLASH_Unlock();
/* 計算要擦除多少頁 */
NbrOfPage = (WRITE_END_ADDR - WRITE_START_ADDR) / FLASH_PAGE_SIZE;
/* 清空所有標志位 */
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
/* 按頁擦除*/
for(EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++)
{
FLASHStatus = FLASH_ErasePage(WRITE_START_ADDR + (FLASH_PAGE_SIZE * EraseCounter));
}
/* 向內部FLASH寫入數據 */
Address = WRITE_START_ADDR;
while((Address < WRITE_END_ADDR) && (FLASHStatus == FLASH_COMPLETE))
{
FLASHStatus = FLASH_ProgramWord(Address, Data);
Address = Address + 4;
}
FLASH_Lock();
/* 檢查寫入的數據是否正確 */
Address = WRITE_START_ADDR;
while((Address < WRITE_END_ADDR) && (MemoryProgramStatus != FAILED))
{
if((*(__IO uint32_t*) Address) != Data)
{
MemoryProgramStatus = FAILED;
}
Address += 4;
}
return MemoryProgramStatus;
}
思考題1:flash擦除完之后,扇區里面所有的數據是什么?
思考題2:假如說現在已經擦除完扇區,先寫入了1個字,然后在下一個偏移地址再次寫入新的字是否在需要擦除扇區?
思考題3:假如說現在已經擦除完扇區,先寫了1個字,然后在同一個地址再次寫入新的字是否需要擦除扇區?
總結: