新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應用 > stm32的flash如何寫數(shù)據(jù)和當做eerom使用

stm32的flash如何寫數(shù)據(jù)和當做eerom使用

作者: 時間:2016-11-27 來源:網(wǎng)絡(luò) 收藏
STM32本身沒有自帶EEPROM,但是STM32具有IAP(在應用編程)功能,所以我們可以把它的FLASH當成EEPROM來使用,同時,開發(fā)者為了維護后期的版本升級,應該考慮到升級的可能和可行性,總不能讓用戶拿著仿真器在線升級或現(xiàn)場調(diào)試吧很尷尬的,其次建議串口升級是目前較為被大眾接受的方式,stm32的串口升級時BOOT0在上啦的情況下升級只需要硬件設(shè)計時考慮到就ok。程序一般燒寫在flash里邊,地址0x8000000開始,升級的原理就是就是有一個寫好的bootloader引導程序,它占用一定的空間比如0x800000-0x80002000這是這段代碼的空間,那么用戶程序就是實現(xiàn)功能的程序就要從0x80002001k開始執(zhí)行了,在這里設(shè)置的時候還要注意嵌套中斷的NVIC是有區(qū)別的。
在bootloader里NVIC_configuration()
是這樣的
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;

#ifdefVECT_TAB_RAM
/* Set the Vector Table base location at 0x20000000 */
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else/* VECT_TAB_FLASH*/
/* Set the Vector Table base location at 0x08000000 */
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0);
#endif
/* Configure one bit for preemption priority */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
}

在功能程序里邊就要將0X8000000改成0x8000001l了。在keil編譯軟件里要設(shè)置一下。在general options里。那么FLASH可以存放程序,當然也可以當EEROM用了就是這個道理。
STM32FLASH簡介
不同型號的STM32,其FLASH容量也有所不同,最小的只有16K字節(jié),最大的則達到了1024K字節(jié)。戰(zhàn)艦STM32開發(fā)板選擇的STM32F103ZET6的FLASH容量為512K字節(jié),屬于大容量產(chǎn)品(另外還有中容量和小容量產(chǎn)品),
STM32的閃存模塊由:主存儲器、信息塊和閃存存儲器接口寄存器等3部分組成。
主存儲器,該部分用來存放代碼和數(shù)據(jù)常數(shù)(如const類型的數(shù)據(jù))。對于大容量產(chǎn)品,其被劃分為256頁,每頁2K字節(jié)。注意,小容量和中容量產(chǎn)品則每頁只有1K字節(jié)。從上圖可以看出主存儲器的起始地址就是0X08000000,B0、B1都接GND的時候,就是從0X08000000開始運行代碼的。
信息塊,該部分分為2個小部分,其中啟動程序代碼,是用來存儲ST自帶的啟動程序,用于串口下載代碼,當B0接V3.3,B1接GND的時候,運行的就是這部分代碼。另一部分用戶選擇字節(jié),則一般用于配置寫保護、讀保護等功能,
閃存存儲器接口寄存器,該部分用于控制閃存讀寫等,是整個閃存模塊的控制機構(gòu)。
閃存的讀取
內(nèi)置閃存模塊可以在通用地址空間直接尋址,任何32位數(shù)據(jù)的讀操作都能訪問閃存模塊的內(nèi)容并得到相應的數(shù)據(jù)。讀接口在閃存端包含一個讀控制器,還包含一個AHB接口與CPU銜接。這個接口的主要工作是產(chǎn)生讀閃存的控制信號并預取CPU要求的指令塊,預取指令塊僅用于在I-Code總線上的取指操作,數(shù)據(jù)常量是通過D-Code總線訪問的。這兩條總線的訪問目標是相同的閃存模塊,訪問D-Code將比預取指令優(yōu)先級高
這里要特別留意一個閃存等待時間,因為CPU運行速度比FLASH快得多,STM32F103的FLASH最快訪問速度≤24Mhz,如果CPU頻率超過這個速度,那么必須加入等待時間,比如我們一般使用72Mhz的主頻,那么FLASH等待周期就必須設(shè)置為2,該設(shè)置通過FLASH_ACR寄存器設(shè)置,具體代碼體現(xiàn)在RCC_Configuration()內(nèi)部這句話
/*設(shè)置FLASH延時周期數(shù)為2 */
FLASH_SetLatency(FLASH_Latency_2);。
使用STM32的官方固件庫操作FLASH的幾個常用函數(shù)。這些函數(shù)和定義分布在文件stm32f10x_flash.c以及stm32f10x_flash.h文件中。
1.鎖定解鎖函數(shù)
在對FLASH進行寫操作前必須先解鎖,解鎖操作也就是必須在FLASH_KEYR寄存器寫入特定的序列(KEY1和KEY2),固件庫函數(shù)實現(xiàn)很簡單:
voidFLASH_Unlock(void);
同樣的道理,在對FLASH寫操作完成之后,我們要鎖定FLASH,使用的庫函數(shù)是:
voidFLASH_Lock(void);
2.寫操作函數(shù)
固件庫提供了三個FLASH寫函數(shù):
FLASH_StatusFLASH_ProgramWord(uint32_tAddress,uint32_tData);
FLASH_StatusFLASH_ProgramHalfWord(uint32_tAddress,uint16_tData);
FLASH_StatusFLASH_ProgramOptionByteData(uint32_tAddress,uint8_tData);
顧名思義分別為:FLASH_ProgramWord為32位字寫入函數(shù),其他分別為16位半字寫入和用戶選擇字節(jié)寫入函數(shù)。這里需要說明,32位字節(jié)寫入實際上是寫入的兩次16位數(shù)據(jù),寫完第一次后地址+2,這與我們前面講解的STM32閃存的編程每次必須寫入16位并不矛盾。寫入8位實際也是占用的兩個地址了,跟寫入16位基本上沒啥區(qū)別。
3.擦除函數(shù)
固件庫提供三個FLASH擦除函數(shù):
FLASH_StatusFLASH_ErasePage(uint32_tPage_Address);
FLASH_StatusFLASH_EraseAllPages(void);
FLASH_StatusFLASH_EraseOptionBytes(void);
這三個函數(shù)可以顧名思義了,非常簡單。
4.獲取FLASH狀態(tài)
主要是用的函數(shù)是:
FLASH_StatusFLASH_GetStatus(void);
返回值是通過枚舉類型定義的:
typedefenum
{
  FLASH_BUSY=1,//忙
  FLASH_ERROR_PG,//編程錯誤
  FLASH_ERROR_WRP,//寫保護錯誤
  FLASH_COMPLETE,//操作完成
  FLASH_TIMEOUT//操作超時
}FLASH_Status;
從這里面我們可以看到FLASH操作的5個狀態(tài),每個代表的意思我們在后面注釋了。
5.等待操作完成函數(shù)
在執(zhí)行閃存寫操作時,任何對閃存的讀操作都會鎖住總線,在寫操作完成后讀操作才能正確地進行;既在進行寫或擦除操作時,不能進行代碼或數(shù)據(jù)的讀取操作。所以在每次操作之前,我們都要等待上一次操作完成這次操作才能開始。使用的函數(shù)是:
FLASH_StatusFLASH_WaitForLastOperation(uint32_tTimeout)
入口參數(shù)為等待時間,返回值是FLASH的狀態(tài),這個很容易理解,這個函數(shù)本身我們在固件庫中使用得不多,但是在固件庫函數(shù)體中間可以多次看到。
6.讀FLASH特定地址數(shù)據(jù)函數(shù)
有寫就必定有讀,而讀取FLASH指定地址的半字的函數(shù)固件庫并沒有給出來,這里我們自己寫的一個函數(shù):
u16STMFLASH_ReadHalfWord(u32faddr)
{
return*(vu16*)faddr;
}


而流程就是

觸發(fā)條件----àFlashunlockàserialdown--àflashlock
看了半天,原來只要幾句就可以解決,當然是不考慮其他功能,只是簡單的讀寫操作。
其中寫操作如下:
FLASH_Unlock();//解鎖FLASH編程擦除控制器
FLASH_ClearFlag(FLASH_FLAG_BSY|FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR);//清除標志位
/*********************************************************************************
// FLASH_FLAG_BSY FLASH忙標志位
// FLASH_FLAG_EOP FLASH操作結(jié)束標志位
// FLASH_FLAG_PGERR FLASH編寫錯誤標志位
// FLASH_FLAG_WRPRTERR FLASH頁面寫保護錯誤標凈
**********************************************************************************/
FLASH_ErasePage(FLASH_START_ADDR); //擦除指定地址頁
FLASH_ProgramHalfWord(FLASH_START_ADDR+(addr+i)*2,dat); //從指定頁的addr地址開始寫
FLASH_ClearFlag(FLASH_FLAG_BSY|FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR);//清除標志位
FLASH_Lock(); //鎖定FLASH編程擦除控制器

從上面可以看出基本順序是:解鎖-》清除標志位(可以不要)-》擦除-》寫半字16位-》清楚標志位(也可以不要)-》上鎖。其中FLASH_START_ADDR是宏定義的0x8000000+2048*255,0x8000000是Flash的起始地址,2048是因為我用的是大容量芯片,根據(jù)上一筆記Flash地址可以看出芯片每頁容量2K,即2048字節(jié),255表示芯片的最后一頁,這個根據(jù)不同芯片而定。之所以從后面頁寫起可以防止儲存數(shù)據(jù)破壞用戶程序。addr*2是因為每個數(shù)據(jù)占用2字節(jié)(半字),雖然寫入的是1字節(jié)數(shù)據(jù),但是編程是2字節(jié)為單位,也就是說一個字節(jié)的數(shù)據(jù)也會占用兩個字節(jié)地址。
用YMODEM協(xié)議(ymodem協(xié)議自己腦補)燒寫會用到flasheraser,剩下的就是要寫的數(shù)據(jù)地址,數(shù)據(jù)包大小處理,怎么寫到每一頁去,以后更新!


評論


技術(shù)專區(qū)

關(guān)閉