STM32 Keil环境下Flash操作指南:从原理到实践
STM32 Keil环境下Flash操作指南:从原理到实践
在嵌入式系统开发中,STM32微控制器的Flash操作是一个核心技能。无论是存储用户程序代码还是关键配置信息,掌握Flash的读写操作都是必不可少的。本文将带你从原理到实践,全面了解如何在Keil环境下进行STM32的Flash操作。
Flash基本原理
Flash是一种非易失性存储器,即使在断电后也能保持数据不丢失。在STM32微控制器中,Flash主要用于存储用户程序代码和必要的配置信息。与传统的EPROM不同,Flash支持带电擦除和编程,使得数据更新更加便捷。
Flash的最小擦除单元是扇区或区块,而不是单个字节。这意味着在写入数据前,必须先将目标区域擦除为全1状态。这一特性决定了Flash操作的基本流程:先擦除,再写入。
Keil环境下的Flash操作
在Keil环境下进行STM32的Flash操作,首先需要正确配置开发环境。以下是具体步骤:
安装Keil MDK软件:下载并安装Keil MDK 5.27或更高版本。在安装过程中,需要设置合适的安装路径,并填写个人信息(可以随意填写)。
注册和获取License:启动Keil软件后,依次选择File -> License Management,输入生成的License ID完成注册。
安装STM32支持包:在Keil软件主界面中,点击Pack Installer,依次选择File -> Import,安装STM32系列的支持包。
配置Flash参数:在Keil项目中,可以通过魔术棒(Options for Target)查看和修改当前芯片的Flash容量和起始地址。例如,将起始地址设置为0x8000000,大小设置为0x10000(64K),可以确保在烧录代码时不会擦除0x8000以后的空间。
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;
}
注意事项与调试技巧
防止数据被意外擦除:在Keil项目中,可以通过修改Flash起始地址和大小来保护数据。例如,将起始地址设置为0x80008000,可以确保在烧录代码时不会擦除0x8000之前的空间。
错误处理:在关键操作前后检查状态并清除可能的错误标志。例如,在擦除和写入操作后,检查返回状态是否为HAL_OK。
电压范围:确保电源电压符合要求,避免擦除失败或损坏Flash。
上电稳定性:长时间操作可能导致掉电,需确保供电稳定。
通过以上步骤和代码示例,你可以在Keil环境下安全地对Flash进行部分数据的保存、擦除和重写。掌握这些基本操作后,你可以进一步探索更复杂的Flash管理技术,如数据加密和磨损均衡等。
STM32的Flash操作虽然看似复杂,但掌握了基本原理和操作方法后,就能得心应手地进行各种数据存储和管理任务。动手实践是掌握这些技能的最佳途径,建议你尝试在实际项目中应用这些知识,不断积累经验。