问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

STM32 Keil环境下Flash操作指南:从原理到实践

创作时间:
2025-01-21 17:14:38
作者:
@小白创作中心

STM32 Keil环境下Flash操作指南:从原理到实践

在嵌入式系统开发中,STM32微控制器的Flash操作是一个核心技能。无论是存储用户程序代码还是关键配置信息,掌握Flash的读写操作都是必不可少的。本文将带你从原理到实践,全面了解如何在Keil环境下进行STM32的Flash操作。

01

Flash基本原理

Flash是一种非易失性存储器,即使在断电后也能保持数据不丢失。在STM32微控制器中,Flash主要用于存储用户程序代码和必要的配置信息。与传统的EPROM不同,Flash支持带电擦除和编程,使得数据更新更加便捷。

Flash的最小擦除单元是扇区或区块,而不是单个字节。这意味着在写入数据前,必须先将目标区域擦除为全1状态。这一特性决定了Flash操作的基本流程:先擦除,再写入。

02

Keil环境下的Flash操作

在Keil环境下进行STM32的Flash操作,首先需要正确配置开发环境。以下是具体步骤:

  1. 安装Keil MDK软件:下载并安装Keil MDK 5.27或更高版本。在安装过程中,需要设置合适的安装路径,并填写个人信息(可以随意填写)。

  2. 注册和获取License:启动Keil软件后,依次选择File -> License Management,输入生成的License ID完成注册。

  3. 安装STM32支持包:在Keil软件主界面中,点击Pack Installer,依次选择File -> Import,安装STM32系列的支持包。

  4. 配置Flash参数:在Keil项目中,可以通过魔术棒(Options for Target)查看和修改当前芯片的Flash容量和起始地址。例如,将起始地址设置为0x8000000,大小设置为0x10000(64K),可以确保在烧录代码时不会擦除0x8000以后的空间。

03

Flash读写代码示例

在STM32中进行Flash操作,需要使用HAL库提供的函数。以下是一个完整的Flash读写代码示例:

#include "stm32f4xx_hal.h"

// 获取地址所在页的函数
uint32_t getPage(uint32_t Address)
{
    uint32_t page = 0;
    if (Address < (FLASH_BASE + FLASH_BANK_SIZE))
        page = (Address - FLASH_BASE) / FLASH_PAGE_SIZE;
    else
        page = (Address - (FLASH_BASE + FLASH_BANK_SIZE)) / FLASH_PAGE_SIZE;
    return page;
}

// 获取Bank的代码
uint32_t GetBank(uint32_t Addr)
{
    uint32_t bank = 0;
    if (READ_BIT(SYSCFG->MEMRMP, SYSCFG_MEMRMP_FB_MODE) == 0)
    {
        if (Addr < (FLASH_BASE + FLASH_BANK_SIZE)) /* No Bank swap */
            bank = FLASH_BANK_1;
        else
            bank = FLASH_BANK_2;
    }
    else
    {
        if (Addr < (FLASH_BASE + FLASH_BANK_SIZE)) /* Bank swap */
            bank = FLASH_BANK_2;
        else
            bank = FLASH_BANK_1;
    }
    return bank;
}

// 擦除函数
FLASH_EraseInitTypeDef EraseInitStruct;
uint8_t eraseFlash(uint32_t start_addr, uint32_t end_addr)
{
    uint32_t BANK;
    uint32_t FirstPages = 0, LastPages = 0, NbPages = 0;
    uint32_t pageError = 0;
    HAL_FLASH_Unlock();                                         // 首先解锁flash
    FirstPages = getPage(start_addr);		            // 获取要擦除的第一个页
    LastPages = getPage(end_addr);
    NbPages = LastPages - FirstPages + 1;	                // 获取擦除的页数量
    BANK = GetBank(start_addr);																// 判断地址的Banks是1还是2
    /* Fill EraseInit structure*/
    EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;	// 页擦除
    EraseInitStruct.Banks = BANK;
    EraseInitStruct.Page = FirstPages;
    EraseInitStruct.NbPages = NbPages;
    if (HAL_FLASHEx_Erase(&EraseInitStruct, &pageError) != HAL_OK)
    {
        HAL_FLASH_Lock();                                       // 上锁
        return 2;												// 擦除有错误,返回2
    }
    // 清除标志位
    __HAL_FLASH_DATA_CACHE_DISABLE();
    __HAL_FLASH_INSTRUCTION_CACHE_DISABLE();

    __HAL_FLASH_DATA_CACHE_RESET();
    __HAL_FLASH_INSTRUCTION_CACHE_RESET();

    __HAL_FLASH_INSTRUCTION_CACHE_ENABLE();
    __HAL_FLASH_DATA_CACHE_ENABLE();

    HAL_FLASH_Lock();                                           // 上锁
    return 0;
}

// 写入函数
HAL_StatusTypeDef writeFlash(uint32_t addr, uint32_t data)
{
    HAL_StatusTypeDef status;
    status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr, data);
    return status;
}

// 读取函数
uint32_t readFlash(uint32_t addr)
{
    return *(__IO uint32_t*)addr;
}
04

注意事项与调试技巧

  1. 防止数据被意外擦除:在Keil项目中,可以通过修改Flash起始地址和大小来保护数据。例如,将起始地址设置为0x80008000,可以确保在烧录代码时不会擦除0x8000之前的空间。

  2. 错误处理:在关键操作前后检查状态并清除可能的错误标志。例如,在擦除和写入操作后,检查返回状态是否为HAL_OK。

  3. 电压范围:确保电源电压符合要求,避免擦除失败或损坏Flash。

  4. 上电稳定性:长时间操作可能导致掉电,需确保供电稳定。

通过以上步骤和代码示例,你可以在Keil环境下安全地对Flash进行部分数据的保存、擦除和重写。掌握这些基本操作后,你可以进一步探索更复杂的Flash管理技术,如数据加密和磨损均衡等。

STM32的Flash操作虽然看似复杂,但掌握了基本原理和操作方法后,就能得心应手地进行各种数据存储和管理任务。动手实践是掌握这些技能的最佳途径,建议你尝试在实际项目中应用这些知识,不断积累经验。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号