STM32F103學(xué)習(xí)筆記(3)——讀寫(xiě)內(nèi)部Flash

一坯临、簡(jiǎn)介

在STM32芯片內(nèi)部有一個(gè) FLASH 存儲(chǔ)器,它主要用于存儲(chǔ)代碼,我們?cè)陔娔X上編寫(xiě)好應(yīng)用程序后单寂,使用下載器把編譯后的代碼文件燒錄到該內(nèi)部 FLASH 中,由于 FLASH 存儲(chǔ)器的內(nèi)容在掉電后不會(huì)丟失吐辙,芯片重新上電復(fù)位后宣决,內(nèi)核可從內(nèi)部 FLASH 中加載代碼并運(yùn)行。


STM32 的內(nèi)部 FLASH 包含主存儲(chǔ)器昏苏、系統(tǒng)存儲(chǔ)器以及選項(xiàng)字節(jié)區(qū)域尊沸,它們的地址分布及大小見(jiàn)下表


  • 主存儲(chǔ)器

一般我們說(shuō) STM32 內(nèi)部 FLASH 的時(shí)候,都是指這個(gè)主存儲(chǔ)器區(qū)域贤惯,它是存儲(chǔ)用戶應(yīng)用程序的空間洼专,芯片型號(hào)說(shuō)明中的 256K FLASH、512K FLASH 都是指這個(gè)區(qū)域的大小孵构。

主存儲(chǔ)器分為 256 頁(yè)屁商,每頁(yè)大小為 2KB,共 512KB浦译。這個(gè)分頁(yè)的概念棒假,實(shí)質(zhì)就是 FLASH 存儲(chǔ)器的扇區(qū),與其它 FLASH 一樣精盅,在寫(xiě)入數(shù)據(jù)前帽哑,要先按頁(yè)(扇區(qū))擦除。

注意上表中的主存儲(chǔ)器是本實(shí)驗(yàn)板使用的 STM32VET6 型號(hào)芯片的參數(shù)叹俏,即 STM32F1 大容量產(chǎn)品妻枕。若使用超大容量、中容量或小容量產(chǎn)品粘驰,它們主存儲(chǔ)器的頁(yè)數(shù)量屡谐、頁(yè)大小均有不同,使用的時(shí)候要注意區(qū)分蝌数。
主存儲(chǔ)器是以頁(yè)為單位劃分的愕掏。stm32根據(jù)FLASH主存儲(chǔ)塊容量、頁(yè)面的不同顶伞,系統(tǒng)存儲(chǔ)器的不同饵撑,分為小容量剑梳、中容量、大容量滑潘、互聯(lián)型垢乙,共四類產(chǎn)品。

  • 小容量產(chǎn)品:主存儲(chǔ)塊1-32KB语卤, 每頁(yè)1KB追逮。系統(tǒng)存儲(chǔ)器2KB
  • 中容量產(chǎn)品:主存儲(chǔ)塊64-128KB, 每頁(yè)1KB粹舵。系統(tǒng)存儲(chǔ)器2KB
  • 大容量產(chǎn)品:主存儲(chǔ)塊256KB以上钮孵, 每頁(yè)2KB。系統(tǒng)存儲(chǔ)器2KB
  • 互聯(lián)型產(chǎn)品:主存儲(chǔ)塊256KB以上齐婴, 每頁(yè)2KB油猫。系統(tǒng)存儲(chǔ)器18KB
  • 系統(tǒng)存儲(chǔ)區(qū)

系統(tǒng)存儲(chǔ)區(qū)是用戶不能訪問(wèn)的區(qū)域,它在芯片出廠時(shí)已經(jīng)固化了啟動(dòng)代碼柠偶,它負(fù)責(zé)實(shí)現(xiàn)串口、USB 以及 CAN 等 ISP 燒錄功能睬关。

  • 選項(xiàng)字節(jié)

選項(xiàng)字節(jié)用于配置 FLASH 的讀寫(xiě)保護(hù)诱担、待機(jī)/停機(jī)復(fù)位、軟件/硬件看門狗等功能电爹,這部分共 16 字節(jié)蔫仙。可以通過(guò)修改 FLASH 的選項(xiàng)控制寄存器修改丐箩。

二摇邦、查看工程的空間分布

由于內(nèi)部 FLASH 本身存儲(chǔ)有程序數(shù)據(jù),若不是有意刪除某段程序代碼屎勘,一般不應(yīng)修改程序空間的內(nèi)容施籍,所以在使用內(nèi)部 FLASH 存儲(chǔ)其它數(shù)據(jù)前需要了解哪一些空間已經(jīng)寫(xiě)入了程序代碼,存儲(chǔ)了程序代碼的扇區(qū)都不應(yīng)作任何修改概漱。通過(guò)查詢應(yīng)用程序編譯時(shí)產(chǎn)生
的“*.map”后綴文件丑慎,可以了解程序存儲(chǔ)到了哪些區(qū)域。


打開(kāi) map 文件后瓤摧,查看文件最后部分的區(qū)域竿裂,可以看到一段以 “Memory Map of the image” 開(kāi)頭的記錄(若找不到可用查找功能定位)

觀察表中的最后一項(xiàng),它的基地址是 0x0800175c照弥,大小為 0x00000020腻异,可知它占用的
最高的地址空間為 0x0800177c,跟執(zhí)行區(qū)域的最高地址 0x0000177c 一樣这揣,但它們比加載
區(qū)域說(shuō)明中的最高地址 0x80017a8 要小悔常,所以我們以加載區(qū)域的大小為準(zhǔn)影斑。對(duì)比表 45-1 的
內(nèi)部 FLASH 頁(yè)地址分布表,可知僅使用頁(yè) 0 至頁(yè) 2 就可以完全存儲(chǔ)本應(yīng)用程序这嚣,所以從頁(yè)
3(地址 0x08001800)后的存儲(chǔ)空間都可以作其它用途鸥昏,使用這些存儲(chǔ)空間時(shí)不會(huì)篡改應(yīng)用程
序空間的數(shù)據(jù)。

三姐帚、寫(xiě)入Flash

3.1 寫(xiě)入過(guò)程

3.1.1 解鎖

由于內(nèi)部 FLASH 空間主要存儲(chǔ)的是應(yīng)用程序吏垮,是非常關(guān)鍵的數(shù)據(jù),為了防止誤操作修改了這些內(nèi)容罐旗,芯片復(fù)位后默認(rèn)會(huì)給控制寄存器 FLASH_CR 上鎖膳汪,這個(gè)時(shí)候不允許設(shè)置 FLASH 的控制寄存器,從而不能修改 FLASH 中的內(nèi)容九秀。

所以對(duì) FLASH 寫(xiě)入數(shù)據(jù)前遗嗽,需要先給它解鎖。解鎖的操作步驟如下:

  1. 往 FPEC 鍵寄存器 FLASH_KEYR 中寫(xiě)入 KEY1 = 0x45670123
  2. 再往 FPEC 鍵寄存器 FLASH_KEYR 中寫(xiě)入 KEY2 = 0xCDEF89AB

3.1.2 頁(yè)擦除

在寫(xiě)入新的數(shù)據(jù)前鼓蜒,需要先擦除存儲(chǔ)區(qū)域痹换,STM32 提供了頁(yè)(扇區(qū))擦除指令和整個(gè) FLASH 擦除(批量擦除)的指令,批量擦除指令僅針對(duì)主存儲(chǔ)區(qū)都弹。
頁(yè)擦除的過(guò)程如下:

  1. 檢查 FLASH_SR 寄存器中的“忙碌寄存器位 BSY”娇豫,以確認(rèn)當(dāng)前未執(zhí)行任何 Flash 操作;
  2. 在 FLASH_CR 寄存器中畅厢,將“激活頁(yè)擦除寄存器位 PER ”置 1冯痢;
  3. 用 FLASH_AR 寄存器選擇要擦除的頁(yè);
  4. 將 FLASH_CR 寄存器中的“開(kāi)始擦除寄存器位 STRT ”置 1框杜,開(kāi)始擦除浦楣;
  5. 等待 BSY 位被清零時(shí),表示擦除完成咪辱。

3.1.3 寫(xiě)入數(shù)據(jù)

擦除完畢后即可寫(xiě)入數(shù)據(jù)振劳,寫(xiě)入數(shù)據(jù)的過(guò)程并不是僅僅使用指針向地址賦值,賦值前還需要配置一系列的寄存器梧乘,步驟如下:

  1. 檢查 FLASH_SR 中的 BSY 位澎迎,以確認(rèn)當(dāng)前未執(zhí)行任何其它的內(nèi)部 Flash 操作;
  2. 將 FLASH_CR 寄存器中的 “激活編程寄存器位 PG” 置 1选调;
  3. 向指定的 FLASH 存儲(chǔ)器地址執(zhí)行數(shù)據(jù)寫(xiě)入操作夹供,每次只能以 16 位的方式寫(xiě)入;
  4. 等待 BSY 位被清零時(shí)仁堪,表示寫(xiě)入完成哮洽。

3.2 寫(xiě)入函數(shù)

/* STM32大容量產(chǎn)品每頁(yè)大小2KByte,中弦聂、小容量產(chǎn)品每頁(yè)大小1KByte */
#if defined (STM32F10X_HD) || defined (STM32F10X_HD_VL) || defined (STM32F10X_CL) || defined (STM32F10X_XL)
  #define FLASH_PAGE_SIZE       ((uint16_t)0x800)   // 2048
#else
  #define FLASH_PAGE_SIZE       ((uint16_t)0x400)   // 1024
#endif

#define WRITE_START_ADDR        ((uint32_t)0x08008000)
#define WRITE_END_ADDR          ((uint32_t)0x0800C000)

/**
 @brief 內(nèi)部Flash寫(xiě)入
 @param address -[in] 寫(xiě)入的地址
 @param pData -[in&out] 指向需要操作的數(shù)據(jù)
 @param dataLen -[in] 數(shù)據(jù)長(zhǎng)度
 @return true - 成功鸟辅;false - 失敗
*/
bool Internal_WriteFlash(uint32_t addrStart, uint32_t *pData, uint32_t dataLen)
{   
    uint32_t i = 0;
    uint32_t eraseCounter = 0x00;                                                               // 記錄要擦除多少頁(yè)
    uint32_t address = 0x00;                                                                    // 記錄寫(xiě)入的地址
    uint32_t numberOfPage = 0x00;                                                               // 記錄寫(xiě)入多少頁(yè)
    FLASH_Status flashStatus = FLASH_COMPLETE;                                                  // 記錄每次擦除的結(jié)果
    
    address = addrStart;
    
    FLASH_Unlock();                                                                             // 解鎖
    numberOfPage = (WRITE_END_ADDR - address) / FLASH_PAGE_SIZE;                                // 計(jì)算要擦除多少頁(yè)
    FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);  // 清除所有標(biāo)志
    
    // 按頁(yè)擦除
    for(eraseCounter = 0; (eraseCounter < numberOfPage) && (flashStatus == FLASH_COMPLETE); eraseCounter++)
    {
        flashStatus = FLASH_ErasePage(address + (FLASH_PAGE_SIZE * eraseCounter));
    }
    
    for(i = 0; (i < dataLen)&&(flashStatus == FLASH_COMPLETE); i++)
    {
        flashStatus = FLASH_ProgramWord(address, pData[i]);                                     // 寫(xiě)入一個(gè)字(32位)的數(shù)據(jù)入指定地址
        address = address + 4;                                                                  // 地址偏移4個(gè)字節(jié) 
    }
    
    FLASH_Lock();                                                                               // 重新上鎖
    
    if(flashStatus == FLASH_COMPLETE)
    {
        return true;
    }
    return false;
}

四氛什、讀取Flash

4.1 讀取函數(shù)

/**
 @brief 內(nèi)部Flash讀取
 @param address -[in] 讀取的地址
 @param pData -[in&out] 指向需要操作的數(shù)據(jù)
 @param dataLen -[in] 數(shù)據(jù)長(zhǎng)度
 @return true - 成功;false - 失敗
*/
bool Internal_ReadFlash(uint32_t addrStart, uint32_t *pData, uint32_t dataLen)
{
    uint32_t i = 0;
    uint32_t address = 0x00;
    
    address = addrStart;
    
    for(i = 0; i < dataLen; i++)
    {
        pData[i] = (*(__IO uint32_t*) address);                                                 // 讀指定地址的一個(gè)字的數(shù)據(jù)
        address += 4;                                                                           // 地址偏移4個(gè)字節(jié)        
    }
    
    return true;
}

五匪凉、舉例

int main(void)
{    
    u32 in_data[5]={11,22,33,44,55};//要寫(xiě)入的數(shù)據(jù)
    u32 out_data[5];//讀存放
    int i;
    u8 STATUS=0;
    USART1_Config();//串口1配置
    GPIO_Configuration();//GPIO配置枪眉,用于點(diǎn)亮led
    STATUS=Internal_WriteFlash(0x08001800,in_data,5);
    Delay(0x02FFFF);
    if(STATUS)
    {
            GPIO_SetBits(GPIOD, GPIO_Pin_13);//點(diǎn)亮led1
            Internal_ReadFlash(0x08001800,out_data,5);
            printf("\r\n The Five Data Is : \r\n");
            for(i=0;i<5;i++)
            {
                    printf("\r %d \r",out_data[i]);
            }
    }
    while(1);
}

? 由 Leung 寫(xiě)于 2020 年 7 月 13 日

? 參考:[零死角玩轉(zhuǎn)STM32——基于野火F103【指南者】開(kāi)發(fā)板]
    stm32——Flash讀寫(xiě)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市再层,隨后出現(xiàn)的幾起案子贸铜,更是在濱河造成了極大的恐慌,老刑警劉巖聂受,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蒿秦,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蛋济,警方通過(guò)查閱死者的電腦和手機(jī)棍鳖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)碗旅,“玉大人渡处,你說(shuō)我怎么就攤上這事∷畋伲” “怎么了骂蓖?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)川尖。 經(jīng)常有香客問(wèn)我,道長(zhǎng)茫孔,這世上最難降的妖魔是什么叮喳? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮缰贝,結(jié)果婚禮上馍悟,老公的妹妹穿的比我還像新娘。我一直安慰自己剩晴,他們只是感情好锣咒,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著赞弥,像睡著了一般毅整。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上绽左,一...
    開(kāi)封第一講書(shū)人閱讀 51,737評(píng)論 1 305
  • 那天悼嫉,我揣著相機(jī)與錄音,去河邊找鬼拼窥。 笑死戏蔑,一個(gè)胖子當(dāng)著我的面吹牛蹋凝,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播总棵,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼鳍寂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了情龄?” 一聲冷哼從身側(cè)響起迄汛,我...
    開(kāi)封第一講書(shū)人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎刃唤,沒(méi)想到半個(gè)月后隔心,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡尚胞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年硬霍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笼裳。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡唯卖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出躬柬,到底是詐尸還是另有隱情拜轨,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布允青,位于F島的核電站橄碾,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏颠锉。R本人自食惡果不足惜法牲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望琼掠。 院中可真熱鬧拒垃,春花似錦、人聲如沸瓷蛙。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)艰猬。三九已至横堡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間姥宝,已是汗流浹背翅萤。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人套么。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓培己,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親胚泌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子省咨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355