新聞中心

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

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

作者: 時(shí)間:2016-11-27 來源:網(wǎng)絡(luò) 收藏
STM32本身沒有自帶EEPROM,但是STM32具有IAP(在應(yīng)用編程)功能,所以我們可以把它的FLASH當(dāng)成EEPROM來使用,同時(shí),開發(fā)者為了維護(hù)后期的版本升級(jí),應(yīng)該考慮到升級(jí)的可能和可行性,總不能讓用戶拿著仿真器在線升級(jí)或現(xiàn)場(chǎng)調(diào)試吧很尷尬的,其次建議串口升級(jí)是目前較為被大眾接受的方式,stm32的串口升級(jí)時(shí)BOOT0在上啦的情況下升級(jí)只需要硬件設(shè)計(jì)時(shí)考慮到就ok。程序一般燒寫在flash里邊,地址0x8000000開始,升級(jí)的原理就是就是有一個(gè)寫好的bootloader引導(dǎo)程序,它占用一定的空間比如0x800000-0x80002000這是這段代碼的空間,那么用戶程序就是實(shí)現(xiàn)功能的程序就要從0x80002001k開始執(zhí)行了,在這里設(shè)置的時(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可以存放程序,當(dāng)然也可以當(dāng)EEROM用了就是這個(gè)道理。
STM32FLASH簡(jiǎn)介
不同型號(hào)的STM32,其FLASH容量也有所不同,最小的只有16K字節(jié),最大的則達(dá)到了1024K字節(jié)。戰(zhàn)艦STM32開發(fā)板選擇的STM32F103ZET6的FLASH容量為512K字節(jié),屬于大容量產(chǎn)品(另外還有中容量和小容量產(chǎn)品),
STM32的閃存模塊由:主存儲(chǔ)器、信息塊和閃存存儲(chǔ)器接口寄存器等3部分組成。
主存儲(chǔ)器,該部分用來存放代碼和數(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開始運(yùn)行代碼的。
信息塊,該部分分為2個(gè)小部分,其中啟動(dòng)程序代碼,是用來存儲(chǔ)ST自帶的啟動(dòng)程序,用于串口下載代碼,當(dāng)B0接V3.3,B1接GND的時(shí)候,運(yùn)行的就是這部分代碼。另一部分用戶選擇字節(jié),則一般用于配置寫保護(hù)、讀保護(hù)等功能,
閃存存儲(chǔ)器接口寄存器,該部分用于控制閃存讀寫等,是整個(gè)閃存模塊的控制機(jī)構(gòu)。
閃存的讀取
內(nèi)置閃存模塊可以在通用地址空間直接尋址,任何32位數(shù)據(jù)的讀操作都能訪問閃存模塊的內(nèi)容并得到相應(yīng)的數(shù)據(jù)。讀接口在閃存端包含一個(gè)讀控制器,還包含一個(gè)AHB接口與CPU銜接。這個(gè)接口的主要工作是產(chǎn)生讀閃存的控制信號(hào)并預(yù)取CPU要求的指令塊,預(yù)取指令塊僅用于在I-Code總線上的取指操作,數(shù)據(jù)常量是通過D-Code總線訪問的。這兩條總線的訪問目標(biāo)是相同的閃存模塊,訪問D-Code將比預(yù)取指令優(yōu)先級(jí)高
這里要特別留意一個(gè)閃存等待時(shí)間,因?yàn)镃PU運(yùn)行速度比FLASH快得多,STM32F103的FLASH最快訪問速度≤24Mhz,如果CPU頻率超過這個(gè)速度,那么必須加入等待時(shí)間,比如我們一般使用72Mhz的主頻,那么FLASH等待周期就必須設(shè)置為2,該設(shè)置通過FLASH_ACR寄存器設(shè)置,具體代碼體現(xiàn)在RCC_Configuration()內(nèi)部這句話
/*設(shè)置FLASH延時(shí)周期數(shù)為2 */
FLASH_SetLatency(FLASH_Latency_2);。
使用STM32的官方固件庫(kù)操作FLASH的幾個(gè)常用函數(shù)。這些函數(shù)和定義分布在文件stm32f10x_flash.c以及stm32f10x_flash.h文件中。
1.鎖定解鎖函數(shù)
在對(duì)FLASH進(jìn)行寫操作前必須先解鎖,解鎖操作也就是必須在FLASH_KEYR寄存器寫入特定的序列(KEY1和KEY2),固件庫(kù)函數(shù)實(shí)現(xiàn)很簡(jiǎn)單:
voidFLASH_Unlock(void);
同樣的道理,在對(duì)FLASH寫操作完成之后,我們要鎖定FLASH,使用的庫(kù)函數(shù)是:
voidFLASH_Lock(void);
2.寫操作函數(shù)
固件庫(kù)提供了三個(gè)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é)寫入實(shí)際上是寫入的兩次16位數(shù)據(jù),寫完第一次后地址+2,這與我們前面講解的STM32閃存的編程每次必須寫入16位并不矛盾。寫入8位實(shí)際也是占用的兩個(gè)地址了,跟寫入16位基本上沒啥區(qū)別。
3.擦除函數(shù)
固件庫(kù)提供三個(gè)FLASH擦除函數(shù):
FLASH_StatusFLASH_ErasePage(uint32_tPage_Address);
FLASH_StatusFLASH_EraseAllPages(void);
FLASH_StatusFLASH_EraseOptionBytes(void);
這三個(gè)函數(shù)可以顧名思義了,非常簡(jiǎn)單。
4.獲取FLASH狀態(tài)
主要是用的函數(shù)是:
FLASH_StatusFLASH_GetStatus(void);
返回值是通過枚舉類型定義的:
typedefenum
{
  FLASH_BUSY=1,//忙
  FLASH_ERROR_PG,//編程錯(cuò)誤
  FLASH_ERROR_WRP,//寫保護(hù)錯(cuò)誤
  FLASH_COMPLETE,//操作完成
  FLASH_TIMEOUT//操作超時(shí)
}FLASH_Status;
從這里面我們可以看到FLASH操作的5個(gè)狀態(tài),每個(gè)代表的意思我們?cè)诤竺孀⑨屃恕?br />5.等待操作完成函數(shù)
在執(zhí)行閃存寫操作時(shí),任何對(duì)閃存的讀操作都會(huì)鎖住總線,在寫操作完成后讀操作才能正確地進(jìn)行;既在進(jìn)行寫或擦除操作時(shí),不能進(jìn)行代碼或數(shù)據(jù)的讀取操作。所以在每次操作之前,我們都要等待上一次操作完成這次操作才能開始。使用的函數(shù)是:
FLASH_StatusFLASH_WaitForLastOperation(uint32_tTimeout)
入口參數(shù)為等待時(shí)間,返回值是FLASH的狀態(tài),這個(gè)很容易理解,這個(gè)函數(shù)本身我們?cè)诠碳?kù)中使用得不多,但是在固件庫(kù)函數(shù)體中間可以多次看到。
6.讀FLASH特定地址數(shù)據(jù)函數(shù)
有寫就必定有讀,而讀取FLASH指定地址的半字的函數(shù)固件庫(kù)并沒有給出來,這里我們自己寫的一個(gè)函數(shù):
u16STMFLASH_ReadHalfWord(u32faddr)
{
return*(vu16*)faddr;
}


而流程就是

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

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


評(píng)論


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

關(guān)閉