stm32内部flash在线读写操作
- 📍相关开源库文章介绍《STM32 利用FlashDB库实现在线扇区数据管理不丢失》
✨不同系列,内部flash编程有所区别。例如stm32f1是按照页擦除,半字(16bit)或全字(32bit)数据写入;stm32f4系列按照扇区擦除,可以字节(8bit)、半字(16bit)、字(32bit)和双字(64bit)数据写入.其他系列可以参考对应的参考手册内容说明。
📗stm32内部flash划分
- 📍STM32F10xxx闪存编程手册:
https://picture.iczhiku.com/resource/eetop/WhkWowqdUaYYwcnv.pdf
- 不同型号的MCU内部flash容量是不同的。STM32F1为例:按照页划分
- 🌿flash容量低于256KB的,页大小为:1KB=0x400;
- 🌿flash容量等于或大于256KB的,页大小为:2KB=0x800;
- 🧨stm32f4xx系列基于扇区操作,含 4 个 16 KB 扇区、1 个 64 KB 扇区 和 7 个 128 KB 扇区。(PM0081编程手册)
📘闪存编程
- 标准的闪存编程顺序:
- 检查FLASH_SR寄存器的BSY位,以确认没有其他正在进行的编程操作;
- 设置FLASH_CR寄存器的PG位为1;
- 写入要编程的半字到指定的地址;
- 等待BSY位变为0;
- 读出写入的地址并验证数据。
- 注意: 当FLASH_SR寄存器的BSY位为1时,不能对任何寄存器执行写操作。
- 编程过程流程图:
- stm32标准库,FLASH编程操作:
c
/**
* 函 数:FLASH编程字
* 参 数:Address 要写入数据的字地址
* 参 数:Data 要写入的32位数据
* 返 回 值:无
*/
void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data)
{
FLASH_Unlock(); //解锁
FLASH_ProgramWord(Address, Data); //编程字
FLASH_Lock(); //加锁
}
/**
* 函 数:FLASH编程半字
* 参 数:Address 要写入数据的半字地址
* 参 数:Data 要写入的16位数据
* 返 回 值:无
*/
void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
{
FLASH_Unlock(); //解锁
FLASH_ProgramHalfWord(Address, Data); //编程半字
FLASH_Lock(); //加锁
}
- HAL库,FLASH编程实现:
c
/**
* @brief 将16位数据写入FLASH
*
* @param data 指向要写入的数据的指针
* @param len 要写入的数据长度(以半字为单位)
* @param address 写入数据的起始地址
* @return HAL_StatusTypeDef 返回HAL状态,表示操作是否成功
*/
HAL_StatusTypeDef FLASH_HALFWORD_Write(uint16_t *data, uint16_t len, uint32_t address)
{
// 解锁FLASH,以便进行写操作
HAL_FLASH_Unlock();
// 初始化循环变量
uint16_t i = 0;
// 循环写入数据
for (i = 0; i < len; i++)
{
// 对FLASH进行编程,使用HAL_FLASH_Program函数以半字(16位)为单位写入数据
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, address, *data) == HAL_OK)
{
// 如果写入成功,更新地址和数据指针
address = address + i * 2; // 地址每次增加2字节(16位)
data = data + 1; // 数据指针指向下一个半字
}
else
{
// 如果写入失败,锁定FLASH并返回错误状态
HAL_FLASH_Lock();
return HAL_ERROR;
}
}
// 所有数据写入成功后,锁定FLASH并返回成功状态
HAL_FLASH_Lock();
return HAL_OK;
}
/**
* @brief 将32位数据写入FLASH
*
* @param data 指向要写入的数据的指针
* @param len 要写入的数据长度(以字为单位)
* @param address 写入数据的起始地址
* @return HAL_StatusTypeDef 返回HAL状态,表示操作是否成功
*/
HAL_StatusTypeDef FLASH_WORD_Write(uint32_t *data, uint16_t len, uint32_t address)
{
// 解锁FLASH,以便进行写操作
HAL_FLASH_Unlock();
// 初始化循环变量
uint16_t i = 0;
// 循环写入数据
for (i = 0; i < len; i++)
{
// 对FLASH进行编程,使用HAL_FLASH_Program函数以字(32位)为单位写入数据
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, *data) == HAL_OK)
{
// 如果写入成功,更新地址和数据指针
address = address + i * 4; // 地址每次增加4字节(32位)
data = data + 1; // 数据指针指向下一个字
}
else
{
// 如果写入失败,锁定FLASH并返回错误状态
HAL_FLASH_Lock();
return HAL_ERROR;
}
}
// 所有数据写入成功后,锁定FLASH并返回成功状态
HAL_FLASH_Lock();
return HAL_OK;
}
信息块的编程
- 选项字节编程流程::
- 检查FLASH_SR寄存器的BSY位,以确认没有其他正在进行的编程操作;
- 设置FLASH_CR寄存器的OPTWRE位为1;
- 设置FLASH_CR寄存器的OPTPG位为1;
- 写入要编程的半字到指定的地址;
- 等待BSY位变为0;
- 读出写入的地址并验证数据
📒闪存擦除
闪存可以按页擦除,也可以全部擦除。
页擦除
闪存的任何一页都可以通过FPEC的页擦除功能擦除;擦除一页应遵守下述过程:
- 检查FLASH_SR寄存器的BSY位,以确认没有其他正在进行的闪存操作;
- 用FLASH_AR寄存器选择要擦除的页;
- 设置FLASH_CR寄存器的PER位为1;
- 设置FLASH_CR寄存器的STRT位为1;
- 等待BSY位变为0;
- 读出被擦除的页并做验证。
- 闪存页擦除过程流程图:
- stm32标准库,FLASH页擦除操作:
c
/**
* 函 数:FLASH页擦除
* 参 数:PageAddress 要擦除页的页地址
* 返 回 值:无
*/
void MyFLASH_ErasePage(uint32_t PageAddress)
{
FLASH_Unlock(); //解锁
FLASH_ErasePage(PageAddress); //页擦除
FLASH_Lock(); //加锁
}
- HAL库 页擦除操作
c
HAL_StatusTypeDef FLASH_Erase_Page(uint32_t Page_Addr,uint32_t Page_Num)
{
FLASH_EraseInitTypeDef EraseInitStruct;
uint32_t PageError = 0;
HAL_FLASH_Unlock(); //解锁内部flash
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;//标明Flash执行页面只做擦除操作
EraseInitStruct.PageAddress = Page_Addr; //声明要擦除的地址
EraseInitStruct.NbPages = Page_Num; //要擦除的页数,此参数必须是Min_Data = 1和Max_Data =(最大页数-初始页的值)之间的值
if (HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK)
{
HAL_FLASH_Lock();
return HAL_ERROR;
}
HAL_FLASH_Lock();
return HAL_OK;
}
全部擦除
可以用全部擦除功能擦除所有用户区的闪存,信息块不受此操作影响。建议使用下述过程:
- 检查FLASH_SR寄存器的BSY位,以确认没有其他正在进行的闪存操作;
- 设置FLASH_CR寄存器的MER位为1;
- 设置FLASH_CR寄存器的STRT位为1;
- 等待BSY位变为0;
- 读出所有页并做验证。
- 闪存全擦除过程流程图:
- stm32标准库,FLASH全擦除操作:
c
/**
* 函 数:FLASH全擦除
* 参 数:无
* 返 回 值:无
* 说 明:调用此函数后,FLASH的所有页都会被擦除,包括程序文件本身,擦除后,程序将不复存在
*/
void MyFLASH_EraseAllPages(void)
{
FLASH_Unlock(); //解锁
FLASH_EraseAllPages(); //全擦除
FLASH_Lock(); //加锁
}
-
⚡需要注意,全擦除,会对内部整个flash进行擦除,擦除后,整个mcu成为空片,原来所烧录的程序将不复存在。如需再使用,需要重新烧录程序。
📙读取操作
内置闪存模块可以在通用地址空间直接寻址,任何32位数据的读操作都能访问闪存模块的内容并得到相应的数据。
- 代码实现:
c
/**
* 函 数:FLASH读取一个32位的字
* 参 数:Address 要读取数据的字地址
* 返 回 值:指定地址下的数据
*/
uint32_t MyFLASH_ReadWord(uint32_t Address)
{
return *((__IO uint32_t *)(Address)); //使用指针访问指定地址下的数据并返回
}
/**
* 函 数:FLASH读取一个16位的半字
* 参 数:Address 要读取数据的半字地址
* 返 回 值:指定地址下的数据
*/
uint16_t MyFLASH_ReadHalfWord(uint32_t Address)
{
return *((__IO uint16_t *)(Address)); //使用指针访问指定地址下的数据并返回
}
/**
* 函 数:FLASH读取一个8位的字节
* 参 数:Address 要读取数据的字节地址
* 返 回 值:指定地址下的数据
*/
uint8_t MyFLASH_ReadByte(uint32_t Address)
{
return *((__IO uint8_t *)(Address)); //使用指针访问指定地址下的数据并返回
}
📚相关测试代码
- 基于
STM32F103VC
,大容量芯片,页容量2K
- 🔖HAL库
c
通过网盘分享的文件:STM32F103VC_FLASH_Program.rar
链接: https://pan.baidu.com/s/1BrxBfByBddTfv4BUbFdZlA?pwd=3qry 提取码: 3qry
- 🔖std标准库,基于
STM32F103VC
,大容量芯片,页容量2K。(参考江协科技代码)
c
通过网盘分享的文件:15-1 读写内部FLASH.rar
链接: https://pan.baidu.com/s/115JvFfDWzdurpzlsaiWl6Q?pwd=vepn 提取码: vepn