新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 「STM32 Flash 操作全解析」擦除、寫入、讀取一網打盡!附完整源碼

        「STM32 Flash 操作全解析」擦除、寫入、讀取一網打盡!附完整源碼

        作者:嵌入式芯視野 時間:2025-07-15 來源:今日頭條 收藏

        在嵌入式開發中,MCU 內部的 常用于存儲配置信息、日志數據或用于 OTA 升級。F4 系列 MCU 提供了對 的靈活操作能力,包括按扇區擦除、字節或半字寫入等。本文將圍繞一段實際使用的 操作代碼進行講解,主要涉及 Flash 的擦除、寫入與讀取功能。

        一、Flash 結構及操作基本原理

        F4 MCU 的 Flash 存儲器按照扇區(Sector)劃分,每個扇區大小不一,例如在 F407 中,前四個扇區大小為 16KB,第五個為 64KB,之后為若干個 128KB 的大扇區。片上 Flash 支持:

        • 扇區級擦除(Sector Erase)

        • 多種對齊方式的編程(如 Byte、Halfword、Word、Double Word)

        • 擦寫需先解鎖并清除相關標志位

        操作前需解鎖 Flash 控制器,完成后應及時鎖定以防意外寫入。

        二、Flash 扇區映射及擦除操作

        代碼中的扇區映射表 sec_map[] 采用結構體 sec_info_t 維護每個扇區的起始地址、大小及編號:

        typedef struct {
            unsigned int start;    unsigned int size;    unsigned int secnum;
        } sec_info_t;

        這是一個結構體類型,表示每個扇區的起始地址、扇區大小和扇區編號。接著通過一個常量數組 sec_map[] 列出 Flash 不同扇區的信息:

        const sec_info_t sec_map[] = {
            {0x08000000, 16*1024, FLASH_Sector_0},
            {0x08004000, 16*1024, FLASH_Sector_1},
            {0x08008000, 16*1024, FLASH_Sector_2},
            {0x0800C000, 16*1024, FLASH_Sector_3},
            {0x08010000, 64*1024, FLASH_Sector_4},
            {0x08020000, 128*1024, FLASH_Sector_5},
            {0x08040000, 128*1024, FLASH_Sector_6},
            {0x08040000, 128*1024, FLASH_Sector_7}};

        該映射表根據 STM32F4 的 Flash 布局列出了常用的 8 個扇區。


        二、Flash 擦除函數講解

        函數 mcu_flash_erase() 實現對 Flash 指定地址范圍的擦除。

        int mcu_flash_erase(unsigned int addr, size_t size)
        • addr: 要擦除的起始地址

        • size: 要擦除的范圍(單位為字節)

        函數先計算扇區數量:

        int len = sizeof(sec_map) / sizeof(sec_info_t);

        然后依次遍歷扇區,找出與 addr 和 size 匹配的扇區范圍,并執行擦除:

        status = FLASH_EraseSector(sec->secnum, VoltageRange_2);

        在執行擦除之前必須解鎖 Flash:

        FLASH_Unlock();

        擦除完成后鎖定 Flash:

        FLASH_Lock();

        最后返回 1 表示成功,返回 0 表示擦除失敗。

        三、Flash 寫入函數講解

        寫入函數為:

        int mcu_flash_write(unsigned int addr ,const void *buf, size_t size)
        • addr: 寫入的起始地址

        • buf: 待寫入的數據緩沖區

        • size: 寫入數據的字節數

        寫入之前,同樣要進行 Flash 解鎖,并清除標志位:

        FLASH_Unlock();              
        FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_OPERR | 
                        FLASH_FLAG_PGAERR);

        然后進入一個循環,按字節或半字方式逐步寫入 Flash:

        if ((addr & 1) == 0 && size > 2) {    status = FLASH_ProgramHalfWord(addr, *((uint16_t *)p));    wrlen = 2;
        } else {    status = FLASH_ProgramByte(addr, *((uint8_t *)p));    wrlen = 1;
        }

        寫入完成后更新地址和緩沖區指針:

        size -= wrlen;addr += wrlen;p    += wrlen;

        如果寫入中某次操作返回錯誤,則提前跳出,最后執行鎖定操作并返回是否寫入成功:

        FLASH_Lock();return ret;

        四、Flash 讀取函數講解

        讀取函數的接口為:

        int mcu_flash_read(unsigned int addr ,void *buf, size_t size)

        該函數直接通過內存拷貝讀取 Flash 數據:

        memcpy(buf, (void *)addr, size);  
        return 0;

        其中 addr 是 Flash 的起始地址,buf 是目標緩存區,size 是讀取字節數。由于 STM32 的 Flash 可以直接映射為內存讀取,因此可以像訪問普通內存一樣操作。

        五、總結

        本篇文章介紹了 STM32F4 MCU 內部 Flash 的基礎操作實現,包括:

        • 使用結構體映射 Flash 扇區信息

        • 實現 Flash 擦除函數,通過匹配地址范圍擦除對應扇區

        • 實現 Flash 寫入函數,按字節或半字逐步寫入 Flash

        • 實現 Flash 讀取函數,通過 memcpy 方式直接讀取 Flash 內容

        以上代碼適用于裸機開發,也可作為 STM32 Flash 操作的基礎模板,配合上層協議或文件系統進行擴展應用,如參數存儲、數據記錄、Bootloader 固件升級等功能。

        開源源碼供參考:

        #include "mcu_flash.h"#include "stm32f4xx.h"#include <string.h>typedef struct {
            unsigned int start;    unsigned int size;    unsigned int secnum;
        }sec_info_t;/*扇區地址映射 ---------------------------------------------------------------*/const sec_info_t sec_map[] = 
        {
            {0x08000000, 16*1024, FLASH_Sector_0},
            {0x08004000, 16*1024, FLASH_Sector_1},
            {0x08008000, 16*1024, FLASH_Sector_2},
            {0x0800C000, 16*1024, FLASH_Sector_3},
            {0x08010000, 64*1024, FLASH_Sector_4},
            {0x08020000, 128*1024, FLASH_Sector_5},
            {0x08040000, 128*1024, FLASH_Sector_6},
            {0x08040000, 128*1024, FLASH_Sector_7}
        };/*
         * @brief       stm32 mcu 內部flash擦除操作
         * @param[in]   addr        - 地址
         * @param[in]   探險大小    - size
         * @return      0 - 失敗, 非0 - 成功
         */int mcu_flash_erase(unsigned int addr, size_t size){ 
            int i;    int len = sizeof(sec_map) / sizeof(sec_info_t);    const sec_info_t *sec = &sec_map[len - 1];
            
            FLASH_Status status;    
            /*越界處理*/
            if (addr > sec->start + sec->size)        return 0;
            
            FLASH_Unlock();    for (i = 0; i < len; i++)
            {
                sec = &sec_map[i];        if ( (sec->start >= addr && sec->start < addr + size) || 
                     (sec->start + sec->size > addr && sec->start + sec->size <= addr + size))
                {            //FLASH_OB_WRPConfig();
                    status = FLASH_EraseSector(sec->secnum, VoltageRange_2);            if (status != FLASH_COMPLETE)
                    {
                        FLASH_Lock(); 
                        return 0;  
                    }
                                  
                }
            }
            FLASH_Lock(); 
            return 1;
        }/*
         * @brief       stm32 mcu 內部flash寫操作
         * @param[in]   addr        - 地址
         * @param[in]   buf         - 數據緩沖區
         * @param[in]   寫入大小    - size
         * @return      0 - 失敗, 非0 - 成功
         */int mcu_flash_write(unsigned int addr ,const void *buf, size_t size){    unsigned char *p = (uint8_t *)buf;//    unsigned int base = addr;//    size_t tlen = size;
            int wrlen;
            FLASH_Status status = FLASH_COMPLETE;    int ret = 0;
            FLASH_Unlock();              
            FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_OPERR | 
                            FLASH_FLAG_PGAERR);     
            while (size) {#if 0
                /*根據對齊方式優化寫入長度*/
                if ((addr & 7) == 0 && size > 8)             /*8字節對齊,按雙字寫入*/  
                {
                    status = FLASH_ProgramDoubleWord(addr, *((uint64_t *)p));            if (status != FLASH_COMPLETE)                goto _quit;
                    wrlen = 8;
                }        else if ((addr & 3) == 0 && size > 4)        /*4字節對齊,按字寫入*/
                {
                    status = FLASH_ProgramWord(addr, *((uint32_t *)p));            if (status != FLASH_COMPLETE)                goto _quit;
                    wrlen = 4;
                }        else if ((addr & 1) == 0 && size > 2)        /*2字節對齊,按半字寫入*/
                {
                    status = FLASH_ProgramHalfWord(addr, *((uint16_t *)p));            if (status != FLASH_COMPLETE)                goto _quit;
                    wrlen = 2;
                }        else                                         /*按字節寫入 --------*/
                {
                    status = FLASH_ProgramByte(addr, *((uint8_t *)p));            if (status != FLASH_COMPLETE)                goto _quit;
                    wrlen = 1;
                }#endif
                if ((addr & 1) == 0 && size > 2)        /*2字節對齊,按半字寫入*/
                {
                    status = FLASH_ProgramHalfWord(addr, *((uint16_t *)p));            if (status != FLASH_COMPLETE)                goto _quit;
                    wrlen = 2;
                }        else                                         /*按字節寫入 --------*/
                {
                    status = FLASH_ProgramByte(addr, *((uint8_t *)p));            if (status != FLASH_COMPLETE)                goto _quit;
                    wrlen = 1;
                }        
                /*地址偏移 -------------------------------------------------------*/
                size -= wrlen;
                addr += wrlen;
                p    += wrlen;        
            }
        _quit:

             ret = status == FLASH_COMPLETE;// && memcmp(buf, (void *)base, tlen) ? 1 : 0;     
         FLASH_Lock();     return ret;
        }/*
         * @brief       stm32 mcu 內部flash讀操作
         * @param[in]   addr        - 地址
         * @param[in]   buf         - 數據緩沖區
         * @param[in]   讀出長度    - size
         * @return      0 - 失敗, 非0 - 成功
         */int mcu_flash_read(unsigned int addr ,void *buf, size_t size){    memcpy(buf, (void *)addr, size);  
            return 0;
        }



        關鍵詞: STM32 Flash

        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 峨山| 蓬安县| 兴义市| 和龙市| 绵竹市| 边坝县| 武宣县| 苏州市| 靖远县| 广安市| 收藏| 铁岭市| 马山县| 汉中市| 盈江县| 扎鲁特旗| 东至县| 凉城县| 全椒县| 扎赉特旗| 安庆市| 河间市| 汉沽区| 亚东县| 博兴县| 绥化市| 黎川县| 新乐市| 高唐县| 故城县| 柘城县| 黄大仙区| 桐城市| 米林县| 开化县| 定南县| 汝城县| 普兰县| 宜兰县| 阿图什市| 丰县|