建网站麻烦吗,大型网站seo课程,深圳高端网站建设电话,有什么好的网站可以接单子做STM32 BootLoader 刷新项目 (九) 跳转指定地址-命令0x55
前面我们讲述了几种BootLoader中的命令#xff0c;包括获取软件版本号、获取帮助、获取芯片ID、读取Flash保护Level。
下面我们来介绍一下BootLoader中最重要的功能之一—跳转#xff01;就像BootLoader词汇中的Boot…STM32 BootLoader 刷新项目 (九) 跳转指定地址-命令0x55
前面我们讲述了几种BootLoader中的命令包括获取软件版本号、获取帮助、获取芯片ID、读取Flash保护Level。
下面我们来介绍一下BootLoader中最重要的功能之一—跳转就像BootLoader词汇中的Boot一词一样就是启动跳转。
首先我们来介绍一下Boot跳转的应用。
1. BootLoader跳转指定地址的应用
STM32的BootLoader中跳转指定地址的应用场景主要包括以下几个方面 固件升级Firmware Upgrade BootLoader允许在不改变硬件连接的情况下进行固件的在线升级。当新的固件版本需要部署到设备上时BootLoader可以接收新的固件并将其烧录到指定的Flash地址然后跳转到新固件的执行地址从而实现固件的无缝更新。 多应用管理Multi-Application Management 在一些复杂的应用中可能需要在同一个设备上运行多个应用程序。BootLoader可以通过跳转到不同的地址来选择性地加载和执行不同的应用程序实现多应用的管理。 系统恢复System Recovery 如果设备在运行过程中出现软件故障BootLoader可以作为一个恢复点通过跳转到备份的固件地址来恢复系统的正常运行。 安全启动Secure Boot 在安全敏感的应用中BootLoader可以检查固件的合法性确保只有经过认证的固件才能被加载执行。这可以通过跳转到经过签名验证的固件地址来实现。 调试和测试Debugging and Testing 在开发和测试阶段BootLoader可以方便地进行程序的调试和测试。开发者可以通过BootLoader跳转到不同的测试固件地址快速验证新功能或修复bug。 节省资源Resource Saving 对于资源受限的嵌入式系统BootLoader可以减少对外部存储器的需求通过内部Flash存储固件节省成本和空间。 产品差异化Product Differentiation 通过BootLoader制造商可以为不同的市场或客户定制不同的固件版本通过跳转到不同的固件地址来实现产品的差异化。 远程维护Remote Maintenance BootLoader支持远程固件更新使得设备的维护和升级可以在不接触硬件的情况下完成这对于远程或难以接触的设备尤为重要。
这些应用场景展示了BootLoader在STM32微控制器中的灵活性和重要性它们使得设备能够更加智能、安全和易于维护。
2. 函数跳转的方法
在STM32的BootLoader中跳转到指定地址通常涉及到以下几个步骤
验证目标地址确保目标地址是有效的并且位于应用程序的合法执行区域内。设置堆栈指针将堆栈指针MSP设置为应用程序的初始堆栈值。跳转到应用程序使用函数指针或者直接修改程序计数器PC来跳转到应用程序的入口点。
下面是一个详细的代码示例包括注释解释每一步的作用
#include stm32f10x.h // 包含STM32F10x系列的头文件// 假设应用程序的入口地址存储在特定的Flash地址
#define APP_ENTRY_ADDR (0x08005000) // 应用程序的入口地址// 跳转到应用程序的函数
void Jump_To_Application(void) {volatile uint32_t *appEntryAddr; // 指向应用程序入口地址的指针void (*Reset_Handler)(void); // 应用程序的Reset_Handler函数指针// 将appEntryAddr指向存储应用程序入口地址的位置appEntryAddr (uint32_t *) APP_ENTRY_ADDR;// 检查应用程序入口地址是否有效// 这里简单地检查地址是否在Flash范围内实际应用中可能需要更复杂的检查if ((*appEntryAddr 0x2FFE0000) 0x08000000) {// 读取应用程序的入口地址uint32_t appStartAddr *appEntryAddr;// 将Reset_Handler函数指针指向应用程序的Reset_HandlerReset_Handler (void (*)(void)) appStartAddr;// 设置堆栈指针为应用程序的初始堆栈值// 这通常是应用程序入口地址的下一个地址__set_MSP(*((volatile uint32_t *) appStartAddr 1));// 关闭所有中断NVIC-ICER[0] 0xFFFFFFFF; // 禁用所有中断NVIC-ICPR[0] 0xFFFFFFFF; // 清除所有中断挂起位// 跳转到应用程序的Reset_HandlerReset_Handler();} else {// 应用程序入口地址无效可以在这里处理错误while(1) {// 错误处理代码}}
}代码解释
包含头文件包含STM32F10x系列的头文件以便使用STM32的寄存器定义和宏。定义应用程序入口地址APP_ENTRY_ADDR是存储应用程序入口地址的位置。跳转到应用程序的函数Jump_To_Application函数执行跳转到应用程序的操作。指向应用程序入口地址的指针appEntryAddr指向存储应用程序入口地址的位置。应用程序的Reset_Handler函数指针Reset_Handler是一个函数指针指向应用程序的Reset_Handler函数。检查应用程序入口地址是否有效通过检查地址是否在Flash范围内来验证地址的有效性。读取应用程序的入口地址从appEntryAddr读取应用程序的实际入口地址。设置堆栈指针将MSP设置为应用程序的初始堆栈值通常是应用程序入口地址的下一个地址。关闭所有中断禁用所有中断并清除所有中断挂起位以确保跳转过程中不会被中断干扰。跳转到应用程序的Reset_Handler通过Reset_Handler函数指针跳转到应用程序的Reset_Handler函数开始执行应用程序代码。
这个代码示例展示了如何在BootLoader中跳转到应用程序的入口地址包括地址验证、堆栈指针设置和实际的跳转操作。在实际应用中你可能需要根据具体的硬件和应用程序需求调整这些步骤。
3. 0x55命令介绍–地址跳转
在本篇文章我们的主要是介绍0x55的命令这个命令主要是在BootLoader中让程序跳转到指定地址。
通过上位机发送10 Byte的数据其中第1 Byte为整个数据的长度第2Byte为指令码第3-6 Byte为跳转的地址第7-10 Byte为前6个Byte的CRC校验值。上位机通过串口UART发送给下位机下位机回复地址是否跳转成功的标志。 下面是整个程序执行地址跳转的流程图 4. 程序设计
下面我们来进行程序设计下面是读取上位机指令并解析指令的过程通过switch case判断执行哪种命令。目前通过上位机执行BL_GO_TO_ADDR指令然后执行bootloader_handle_go_cmd(bl_rx_buffer)函数。
void bootloader_uart_read_data(void)
{uint8_t rcv_len0;printmsg_Host(BL_DEBUG_MSG: Receive CMD\n\r);while (1){HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);memset(bl_rx_buffer, 0, 200);//here we will read and decode the commands coming from host//first read only one byte from the host , which is the length field of the command packetHAL_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: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;default:printmsg(BL_DEBUG_MSG:Invalid command code received from host \n);break;}}
}下面是地址跳转函数通过过去输入的Buffer进行解析出跳转地址判断跳转地址是否在正确的跳转范围内如果在正确的跳转范围内则向上位机发送能够跳转的回复之后执行地址跳转。如果不在跳转范围内则向上位机回复地址不正确请重新输入。
/*Helper function to handle BL_GO_TO_ADDR command */
void bootloader_handle_go_cmd(uint8_t *pBuffer)
{uint32_t go_address0;uint8_t addr_valid ADDR_VALID;uint8_t addr_invalid ADDR_INVALID;printmsg(BL_DEBUG_MSG:bootloader_handle_go_cmd\n);//Total length of the command packetuint32_t command_packet_len bl_rx_buffer[0]1 ;//extract the CRC32 sent by the Hostuint32_t host_crc *((uint32_t * ) (bl_rx_buffercommand_packet_len - 4) ) ;if (! bootloader_verify_crc(bl_rx_buffer[0],command_packet_len-4,host_crc)){printmsg(BL_DEBUG_MSG:checksum success !!\n);bootloader_send_ack(pBuffer[0],1);//extract the go addressgo_address *((uint32_t *)pBuffer[2] );printmsg(BL_DEBUG_MSG:GO addr: %#x\n,go_address);if( verify_address(go_address) ADDR_VALID ){//tell host that address is finebootloader_uart_write_data(addr_valid,1);/*jump to go address.we dont care what is being done there.host must ensure that valid code is present over thereIts not the duty of bootloader. so just trust and jump *//* Not doing the below line will result in hardfault exception for ARM cortex M *///watch : https://www.youtube.com/watch?vVX_12SjnNhYgo_address1; //make T bit 1void (*lets_jump)(void) (void *)go_address;printmsg(BL_DEBUG_MSG: jumping to go address! \n);lets_jump();}else{printmsg(BL_DEBUG_MSG:GO addr invalid ! \n);//tell host that address is invalidbootloader_uart_write_data(addr_invalid,1);}}else{printmsg(BL_DEBUG_MSG:checksum fail !!\n);bootloader_send_nack();}
}5. 实战演练
下面是上位机的命令菜单通过在终端调用Python脚本然后在终端输入下位机连接的串口号即可进入命令界面目前可支持如下命令 在上位机中输入命令5即为在BootLoader中执行地址跳转命令0x55MCU根据读取跳转地址0xXXXXXXXX的值来进行跳转并告诉上位机能否跳转成功由下图可以看出当前地址跳转成功。 目前我在STM32中刷了两段程序其中BootLoader程序即为0x0800 0000-0x0800 7FFF处后面0x08000 8000-0x080F FFFF为APP应用程序则当我将跳转地址设为0x0800 8000时MCU则会从BootLoader跳转进入到APP应用程序中。 但为什么我们在输入跳转指令地址为0x08008000的时候并没有跳转到App程序呢下面我通过Hex和大家解释一下。
下面我们用STM32官方提供的工具STM32CubeProgrammer工具读取MCU中的Hex信息。
Note必须在连接ST-Link的时候才能显示Hex信息。 由上图我们可以看出在0x08008000地址开始处其中第一个地址0x0800 8000地址中的值时0x20020000这个值时Reset Handle即中断向量表的起始地址。第二个地址0x0800 8004中的值才是实际App程序所在的Flash地址。
所以在下图中我们执行地址跳转指令0x55跳转地址设为0x0800 8B16为什么比0x0800 8B15多1呢这是因为我们使用的Thumb指令执行的指令结尾必须1. 下面我们通过串口监控一下Mcu是否跳转成功由下图可以看出MCU成功跳转到App程序中。 6. 系列文章
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