STM32 BootLoader 刷新项目 (十) Flash擦除-命令0x56

STM32 BootLoader 刷新项目 (十) Flash擦除-命令0x56

1. STM32F407 BootLoader 中的 Flash 擦除功能详解

在嵌入式系统中,BootLoader 的设计是非常关键的部分,它负责引导主程序的启动、升级以及安全管理。而在 STM32F407 等 MCU 上实现 BootLoader,Flash 操作则是其中的核心功能之一。本文将重点介绍 STM32F407 上的 Flash 擦除功能,并给出实现过程和注意事项。

image-20241114070905643

一、STM32F407 Flash 结构概述

STM32F407 芯片采用 Cortex-M4 内核,内置 Flash 存储用于程序和数据存储。STM32F407 的 Flash 大小为 512KB,分为若干个扇区(Sector),每个扇区的大小并不相同:

  • 扇区 0 到 3:16KB 每扇区
  • 扇区 4:64KB
  • 扇区 5 到 11:128KB 每扇区

image-20241114070535836

这种不同大小的扇区设计适合不同的应用需求,比如小容量扇区用于存储配置数据,大容量扇区用于存储固件。

二、Flash 擦除的原理

Flash 擦除是将 Flash 中的某个扇区的数据重置为 0xFF。由于 Flash 的物理特性,写操作只能将位设置为 0,而擦除操作将位恢复为 1。因此,在更新 Flash 数据时,通常需要先擦除再写入。

在 STM32F407 中,Flash 擦除只能以扇区为单位进行,这意味着无法擦除扇区中的部分数据。每次擦除扇区时,整个扇区的数据都会被清空。

三、Flash 擦除的操作流程

在 STM32F407 的 BootLoader 中实现 Flash 擦除,一般需要遵循以下步骤:

  1. 解锁 Flash 控制寄存器:在进行任何 Flash 操作之前,需要解锁 Flash 的写保护功能。
  2. 等待 Flash 空闲:检查 Flash 状态寄存器,确保没有其他操作正在进行。
  3. 启动扇区擦除:设置目标扇区并启动擦除命令。
  4. 等待擦除完成:监控状态寄存器中的 BSY 位,等待擦除操作完成。
  5. 锁定 Flash 控制寄存器:完成操作后,将 Flash 锁定,以防止误操作。

四、Flash 擦除实现代码

以下是 STM32F407 上实现 Flash 擦除的代码示例。本文假设使用了 STM32 标准外设库,便于调用硬件寄存器。

#include "stm32f4xx.h"/*** @brief  擦除 Flash 指定扇区* @param  sector 要擦除的扇区编号* @retval 0 表示成功,-1 表示失败*/
int Flash_EraseSector(uint8_t sector)
{// 解锁 Flash 控制寄存器FLASH_Unlock();// 等待 Flash 空闲while (FLASH_GetStatus() == FLASH_BUSY);// 擦除操作FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);FLASH_Status status = FLASH_EraseSector(sector, VoltageRange_3);// 等待擦除完成if (status != FLASH_COMPLETE){FLASH_Lock();return -1; // 擦除失败}// 锁定 Flash 控制寄存器FLASH_Lock();return 0; // 擦除成功
}

五、代码详解

  • FLASH_Unlock():此函数用于解锁 Flash 控制寄存器,以允许擦除和写入操作。
  • FLASH_GetStatus():用于检查 Flash 是否处于忙碌状态。擦除操作会占用一定的时间,必须等待 Flash 空闲后才能继续。
  • FLASH_ClearFlag():清除可能出现的错误标志位,确保擦除操作不会受到之前错误的影响。
  • FLASH_EraseSector():这是 STM32 库中的擦除函数,输入参数为扇区编号和电压范围(STM32F4 系列通常使用 VoltageRange_3)。
  • FLASH_Lock():操作完成后锁定 Flash 控制寄存器,以防止意外操作。

六、Flash 擦除的注意事项

  1. 擦除单位:在 STM32F407 中,Flash 擦除只能以扇区为单位进行,无法进行字节或页的擦除。因此,设计 BootLoader 时要合理分配数据的存储位置,避免不必要的擦除操作。
  2. 电压范围:擦除 Flash 时,电源电压必须在一定范围内,低电压下可能导致擦除失败甚至损坏 Flash。STM32F407 提供了多种电压模式,通常选择 VoltageRange_3 即可。
  3. 错误处理:Flash 擦除失败可能会出现各种错误,例如写保护、编程错误等。建议在擦除操作前后清除并检查错误标志。
  4. 数据备份:在擦除前备份必要的数据。在 BootLoader 中进行固件更新时,最好将旧固件暂时保存至其他存储介质中,以应对擦除或写入失败的情况。
  5. 上电时间:Flash 擦除时间较长,尤其是 128KB 扇区,因此在设计 BootLoader 时需要考虑电源的持续供电能力,避免中途掉电。

2. BootLoader Flash划分

由下图可以看出本BootLoader的Flash的划分,其中划给BootLoader为32KB,从0x0800 0000-0x0800 7FFF,占用Sector 0-1两个段。App应用程序占用0x0800 8000-0x080F FFFF,总共10个Sector。

image-20241114070819942

下面是BootLoader的跳转过程,关于具体的跳转过程,可以参考上一篇文章: STM32 BootLoader 刷新项目 (九) 跳转指定地址-命令0x55

image-20241114230528904

image-20241114230647450

3. 0x56命令介绍–Flash擦除

在本篇文章,我们的主要是介绍0x56的命令,这个命令主要是在BootLoader中擦除指定Flash Sector的命令。

通过上位机发送8 Byte的数据,其中第1 Byte为整个数据的长度,第2Byte为指令码,第3 Byte为要擦除Flash的起始Sector序号,第4 Byte是擦除Sector的长度,第5-8 Byte为前6个Byte的CRC校验值。上位机通过串口UART发送给下位机,下位机回复地址是否擦除成功的标志。

image-20241114230143679

下面是发送命令过程中上位机与BootLoader之间的交互。

image-20241114230607647

4. Flash擦除命令程序设计

下面我们来进行程序设计,下面是读取上位机指令,并解析指令的过程,通过switch case判断执行哪种命令。目前通过上位机执行BL_FLASH_ERASE指令,然后执行bootloader_handle_flash_erase_cmd(bl_rx_buffer)函数。

下面是代码的详细注释和分析:

bootloader_uart_read_data 函数

该函数用于从主机接收命令数据并调用相应的处理函数来执行命令。它是 BootLoader 的核心输入接口,通过 UART 接收主机的命令,并根据命令类型分发到对应的处理函数。

void bootloader_uart_read_data(void)
{uint8_t rcv_len = 0;// 打印调试信息,提示接收到命令printmsg_Host("BL_DEBUG_MSG: Receive CMD\n\r");// 无限循环,持续接收命令并处理while (1){// 将 LED2 熄灭,表示进入命令接收状态HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);// 清空接收缓冲区,防止残留数据干扰memset(bl_rx_buffer, 0, 200);// 读取命令包的第一个字节,即命令的长度字段HAL_UART_Receive(C_UART, bl_rx_buffer, 1, HAL_MAX_DELAY);// 获取命令包长度,长度字节位于第一个字节rcv_len = bl_rx_buffer[0];// 根据命令包长度读取剩余的字节HAL_UART_Receive(C_UART, &bl_rx_buffer[1], rcv_len, HAL_MAX_DELAY);// 根据命令码执行相应的命令处理函数switch (bl_rx_buffer[1]){case BL_GET_VER:// 处理获取版本命令bootloader_handle_getver_cmd(bl_rx_buffer);break;case BL_GET_HELP:// 处理获取帮助命令bootloader_handle_gethelp_cmd(bl_rx_buffer);break;case BL_GET_CID:// 处理获取芯片 ID 命令bootloader_handle_getcid_cmd(bl_rx_buffer);break;case BL_GET_RDP_STATUS:// 处理获取读保护状态命令bootloader_handle_getrdp_cmd(bl_rx_buffer);break;case BL_GO_TO_ADDR:// 处理跳转到地址命令bootloader_handle_go_cmd(bl_rx_buffer);break;case BL_FLASH_ERASE:// 处理 Flash 擦除命令bootloader_handle_flash_erase_cmd(bl_rx_buffer);break;default:// 未知命令,打印调试信息printmsg("BL_DEBUG_MSG: Invalid command code received from host \n");break;}}
}
  • 初始化和循环:函数会无限循环等待主机发送的命令并进行解析。
  • 数据接收:首先读取一个字节的长度字段,然后根据这个长度读取完整的命令数据。
  • 命令解析:通过 switch 语句解析命令码,并调用相应的处理函数。
  • 错误处理:如果命令码不在预期范围内,打印调试信息。

bootloader_handle_flash_erase_cmd 函数

该函数处理 BL_FLASH_ERASE 命令,通过接收到的参数执行 Flash 擦除操作。

void bootloader_handle_flash_erase_cmd(uint8_t *pBuffer)
{uint8_t erase_status = 0x00;printmsg("BL_DEBUG_MSG: bootloader_handle_flash_erase_cmd\n");// 获取命令包的总长度uint32_t command_packet_len = bl_rx_buffer[0] + 1;// 从命令包中提取主机发送的 CRC32 值uint32_t host_crc = *((uint32_t *)(bl_rx_buffer + command_packet_len - 4));// 验证接收到的数据包的 CRC 校验if (!bootloader_verify_crc(&bl_rx_buffer[0], command_packet_len - 4, host_crc)){// 如果校验成功printmsg("BL_DEBUG_MSG: checksum success !!\n");// 发送 ACK 响应,确认命令长度为 1 字节bootloader_send_ack(pBuffer[0], 1);// 打印擦除信息:初始扇区和扇区数量printmsg("BL_DEBUG_MSG: initial_sector: %d, no_of_sectors: %d\n", pBuffer[2], pBuffer[3]);// 熄灭 LED 表示擦除操作开始HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);// 调用 `execute_flash_erase` 执行擦除操作,传入初始扇区和扇区数量erase_status = execute_flash_erase(pBuffer[2], pBuffer[3]);// 重新点亮 LED 表示擦除操作完成HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET);// 打印擦除操作的状态printmsg("BL_DEBUG_MSG: flash erase status: %#x\n", erase_status);// 发送擦除状态回主机bootloader_uart_write_data(&erase_status, 1);}else{// 如果 CRC 校验失败,发送 NACK 响应printmsg("BL_DEBUG_MSG: checksum fail !!\n");bootloader_send_nack();}
}
  • 参数解析和 CRC 校验:从命令包中提取 CRC 值并进行校验,确保数据完整性。
  • 发送 ACK 或 NACK:根据 CRC 校验结果发送确认或拒绝响应。
  • 擦除操作:如果校验通过,提取擦除操作的初始扇区和扇区数量,然后调用 execute_flash_erase 函数执行擦除操作。
  • 状态回传:擦除完成后,将操作状态通过 UART 返回给主机。

execute_flash_erase 函数

execute_flash_erase 函数负责执行 Flash 的具体擦除操作,支持部分扇区擦除和全片擦除。

uint8_t execute_flash_erase(uint8_t sector_number, uint8_t number_of_sector)
{// STM32F407 芯片共有 12 个扇区(0 到 11)// 如果 sector_number = 0xff,表示全片擦除FLASH_EraseInitTypeDef flashErase_handle;uint32_t sectorError;HAL_StatusTypeDef status;// 如果指定的扇区数量超过有效范围,返回无效扇区if (number_of_sector > 11)return INVALID_SECTOR;// 检查扇区号是否有效if ((sector_number == 0xFF) || (sector_number <= 11)){// 判断是否全片擦除if (sector_number == (uint8_t)0xFF){flashErase_handle.TypeErase = FLASH_TYPEERASE_MASSERASE;}else{// 部分扇区擦除// 计算剩余可擦除的扇区数uint8_t remaining_sector = 12 - sector_number;if (number_of_sector > remaining_sector){number_of_sector = remaining_sector;}flashErase_handle.TypeErase = FLASH_TYPEERASE_SECTORS;flashErase_handle.Sector = sector_number;flashErase_handle.NbSectors = number_of_sector;}// 设置擦除银行(STM32F4 系列有两个 Flash Bank,选取 Bank 1)flashErase_handle.Banks = FLASH_BANK_1;// 解锁 Flash 寄存器,允许擦除操作HAL_FLASH_Unlock();// 设置电压范围,适应 STM32F4 的工作电压范围flashErase_handle.VoltageRange = FLASH_VOLTAGE_RANGE_3;// 执行擦除操作,传入擦除配置和错误记录变量status = (uint8_t)HAL_FLASHEx_Erase(&flashErase_handle, &sectorError);// 锁定 Flash 控制寄存器,防止误操作HAL_FLASH_Lock();return status;  // 返回擦除操作的状态}return INVALID_SECTOR;  // 如果无效扇区,返回无效状态
}
  • 全片和部分擦除:函数支持全片擦除(sector_number == 0xFF)和从指定扇区开始的部分擦除。
  • 擦除范围检查:确保扇区数量不超过剩余的可擦除范围。
  • 解锁和锁定:在擦除操作前解锁 Flash 控制寄存器,擦除完成后重新锁定。
  • 电压范围设置:设置为 FLASH_VOLTAGE_RANGE_3,适配 STM32F4 的工作电压。
  • 状态返回:返回擦除状态,以便调用方确认擦除是否成功。

总结

  • bootloader_uart_read_data:从 UART 接收命令,解析命令码并调用对应的命令处理函数。
  • bootloader_handle_flash_erase_cmd:处理 Flash 擦除命令,进行 CRC 校验

5. 实战演练

下面是上位机的命令菜单,通过在终端调用Python脚本,然后在终端输入下位机连接的串口号,即可进入命令界面,目前可支持如下命令:

image-20240713104433991

下面我们执行命令–7,执行BL_FLASH_ERASE,即为在BootLoader中执行Flash擦除命令0x56,第一步输入要开始擦除的Sector起始段,第二步输入擦除Sector的长度,最后BootLoader向上位机返回是否擦除成功的Status。

image-20241115071431811

下面我们来看Flash擦除命令是否擦除成功,用STM32CubeProgrammer工具,用ST-LINK连接Debug口,上一步中我们擦除的Sector 3的Flash,这里面我们输入Sector 2的起始地址0x0800 C000,可以看出全部擦除为FF。至此Flash擦除命令已经讲完。

image-20241115072819345

6. 结论

Flash 擦除是 STM32F407 BootLoader 设计中的重要环节,它为固件更新和数据存储提供了基础。本文详细介绍了 Flash 擦除的原理和实现方法,并提供了相关代码和注意事项。在实际应用中,设计人员可以根据需要将擦除功能整合至 BootLoader 的主流程中,确保系统的可靠性和可升级性。

希望本篇文章能为读者在 STM32F407 的 BootLoader 开发中提供一些帮助,若有疑问,欢迎交流讨论。

7. 系列文章

STM32 BootLoader 刷新项目 (一) STM32CubeMX UART串口通信工程搭建

STM32 BootLoader 刷新项目 (二) 方案介绍

STM32 BootLoader 刷新项目 (三) 程序框架搭建及刷新演示

STM32 BootLoader 刷新项目 (四) 通信协议

STM32 BootLoader 刷新项目 (五) 获取软件版本号-命令0x51

STM32 BootLoader 刷新项目 (六) 获取帮助-命令0x52

STM32 BootLoader 刷新项目 (七) 获取芯片ID-0x53

STM32 BootLoader 刷新项目 (八) 读取Flash保护ROP-0x54

STM32 BootLoader 刷新项目 (九) 跳转指定地址-命令0x55

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/61331.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网页抓取API,让数据获取更简单

网页抓取的过程通常分为以下步骤&#xff0c;尤其是在面对静态网页时&#xff1a; 获取页面 HTML&#xff1a;使用 HTTP 客户端下载目标页面的 HTML 内容。解析 HTML&#xff1a;将下载的 HTML 输入解析器&#xff0c;准备提取内容。提取数据&#xff1a;利用解析器功能&#…

Golang语言整合jwt+gin框架实现token

1.下载jwt go get -u github.com/dgrijalva/jwt-go2.新建生成token和解析token文件 2.1 新建common文件夹和jwtConfig文件夹 新建jwtconfig.go文件 2.2 jwtconfig.go文件代码 /* Time : 2021/8/2 下午3:03 Author : mrxuexi File : main Software: GoLand */ package jwtC…

详细分析ipvsadm负载均衡的命令

目录 前言1. 基本知识2. 命令参数3. 拓展 前言 LVS四层负载均衡架构详解Lvs推荐阅读&#xff1a;添加链接描述 1. 基本知识 ipvsadm 是用于管理和配置 Linux 服务器上 IP Virtual Server (IPVS) 的工具&#xff0c;是 Linux 提供的一个负载均衡模块&#xff0c;支持多种负载…

量化选股日常操作日记-11-ai眼镜-润欣科技

用 微信小程序 梦想兔企业智能风险分析助手 &#xff0c;选择AI眼镜板块&#xff0c;挖掘了几个合适的股&#xff0c;分析下来感觉 润欣科技 比较安全些适合观察&#xff0c;几块到十几块波动&#xff0c;企业基本面也没有特别大问题。就是现在价位在周期波动高位&#xff0c;下…

动力学法测量金属弹性模量

&#x1f3eb;中南民族大学-⚛大学物理实验2-&#x1f4e0;通信工程2024 目录 Python代码 1. 绘制图像 2. 弹性模量数值计算 图像显示 Pycharm 豆包 MarsCode 非常强大&#xff01;有了它们&#xff0c;我在处理大学物理实验的数据及其可视化就非常方便&#xff0c;极大缩减…

NLP论文速读(EMNLP 2024)|动态奖励与提示优化来帮助语言模型的进行自我对齐

论文速读|Dynamic Rewarding with Prompt Optimization Enables Tuning-free Self-Alignment of Language Models 论文信息&#xff1a; 简介: 本文讨论的背景是大型语言模型&#xff08;LLMs&#xff09;的自我对齐问题。传统的LLMs对齐方法依赖于昂贵的训练和人类偏好注释&am…

SLM561A系列60V10-50mA单通道线性恒流LED驱动芯片,为汽车照明、景观照明助力

SLM561A系列选型参考&#xff1a; SLM561A10ae-7G SOD123 SLM561A15ae-7G SOD123 SLM561A20ae-7G SOD123 SLM561A25ae-7G SOD123 SLM561A30ae-7G SOD123 SLM561A35ae-7G SOD123 SLM561A40ae-7G SOD123 SLM561A45ae-7G SOD123 SLM561A50ae-7G SOD123 S…

RabbitMQ1:初识MQ

欢迎来到“雪碧聊技术”CSDN博客&#xff01; 在这里&#xff0c;您将踏入一个专注于Java开发技术的知识殿堂。无论您是Java编程的初学者&#xff0c;还是具有一定经验的开发者&#xff0c;相信我的博客都能为您提供宝贵的学习资源和实用技巧。作为您的技术向导&#xff0c;我将…

父组件提交时让各自的子组件验证表格是否填写完整

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 父组件中有三个表格&#xff0c;表格中时输入框&#xff0c;有些输入框是必填的&#xff0c;在父组件提交时需要验证这三个表格的必填输入框中是否有没填写的。 原因分析&#xff1a; 提示&#xff1a…

Siglus引擎 Unpack | 未完待续

前言 未完待续。 代码在这里&#xff1a;https://github.com/N0zoM1z0/SiglusEngine-Extract 以后随时会更新。&#xff08;&#xff09; 因为我是选择直接逆向游戏引擎&#xff0c;在无源码&#xff0c;不hook的情况下硬逆Siglus…… 路漫漫。。。 read.sav 可以直接逆Sigl…

黑马嵌入式开发入门模电基础学习笔记

学习视频: 黑马程序员嵌入式开发入门模电&#xff08;模拟电路&#xff09;基础 文章目录 背景介绍电流电压组件仿真三极管ne555PCBEDA案例&#xff1a;非接触式电笔案例&#xff1a;电子琴 背景介绍 电流 电压 组件 仿真 三极管 mos管 ne555 PCB EDA 案例&#xff1a;非接触…

linux 中mysql查看慢日志

1、到mysql容器&#xff0c;先登录到数据库&#xff0c;查看是否开启 mysql -h 127.0.0.1 -uroot -p SHOW VARIABLES LIKE slow_query_log; 2、如果没有开启&#xff0c;需要先开启 set global slow_query_log ON; 3、查看慢日志文件 SHOW VARIABLES LIKE slow_query_log…

从0开始机器学习--Day30--异常检测算法

异常检测算法(Anomaly detection algorithm) 我们定义异常检测算法的输出&#xff0c;也写作&#xff0c;这里的每一项括号内代表的是每个特征都符合各自的高斯分布&#xff08;也就是正态分布&#xff09;&#xff0c;代表均值&#xff0c;决定了模型的中心位置&#xff1b;代…

架构图解析:如何构建高效的微服务系统

在当今的数字化浪潮中&#xff0c;构建高效、灵活且可扩展的系统已成为企业的重要目标。微服务架构作为一种先进的软件设计模式&#xff0c;通过将复杂的应用程序分解为一系列小型、独立的服务&#xff0c;显著提升了系统的灵活性、可扩展性和维护性。本文将通过解析微服务系统…

排序排序的概念及其运用和选择排序

排序排序的概念及其运用和选择排序 7. 排序7.1 排序的概念及其运用7.2 选择排序算法——直接选择排序选择排序基本思想&#xff1a;直接选择排序选择排序原理参考程序 如何交换数据直接选择排序的特性总结&#xff1a; 7. 排序 7.1 排序的概念及其运用 排序&#xff1a;所谓排…

Websocket如何分块处理数据量超大的消息体

若我们服务端一次性最大处理的字节数是1M,而客户端发来了2M的数据&#xff0c;此时服务端的数据就要被切割成两次传输解码。Http协议中有分块传输&#xff0c;而在Websocket也可以分块处理超大的消息体。在jsr356标准中使用javax.websocket.MessageHandler.Partial可以分块处理…

【澜舟科技-注册/登录安全分析报告】

前言 由于网站注册入口容易被机器执行自动化程序攻击&#xff0c;存在如下风险&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露&#xff0c;不符合国家等级保护的要求。短信盗刷带来的拒绝服务风险 &#xff0c;造成用户无法登陆、注册&#xff0c;大量收到垃圾短信的…

uni-app快速入门(十)--常用内置组件(下)

本文介绍uni-app的textarea多行文本框组件、web-view组件、image图片组件、switch开关组件、audio音频组件、video视频组件。 一、textarea多行文本框组件 textarea组件在HTML 中相信大家非常熟悉&#xff0c;组件的官方介绍见&#xff1a; textarea | uni-app官网uni-app,un…

Tomcat 如何管理 Session

Tomcat 如何管理 Session 我们知道&#xff0c;Tomcat 中每一个 Context 容器对应一个 Web 应用&#xff0c;而 Web 应用之间的 Session 应该是独立的&#xff0c;因此 Session 的管理肯定是 Context 级的&#xff0c;也就是一个 Context 一定关联多个 Session。 Tomcat 中主…

鸿蒙NEXT开发-用户通知服务的封装和文件下载通知

注意&#xff1a;博主有个鸿蒙专栏&#xff0c;里面从上到下有关于鸿蒙next的教学文档&#xff0c;大家感兴趣可以学习下 如果大家觉得博主文章写的好的话&#xff0c;可以点下关注&#xff0c;博主会一直更新鸿蒙next相关知识 专栏地址: https://blog.csdn.net/qq_56760790/…