完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
1. IAP介绍
在开发MCU应用时,很多时候都希望能够做到不断电就能升级Firmware,这样就能快速更新新功能或修复bug。这个时候就需要IAP功能,IAP是In Application Programming的首字母缩写,IAP是用户自己的程序在运行过程中对User Flash的部分区域进行烧写,IAP需要MCU能擦写内部Flash,并且具备软件复位功能。IAP的通信方式有很多选择,UART、SPI、IIC、USB、CAN等通信方式都可以选择,常用的可以选择UART、USB,如果需要远程升级,可以再搭配个2.4G、蓝牙等无线模块来实现OTA。这里将以ST的 NUCLEO-F103RB 开发板来实验下UART IAP的功能,开发自己的Bootloader程序。 STM32F103RB内置有官方的Bootloader程序,可以通过USART来升级,但这个Bootloader程序是无法修改的,而且进入的方式是上电时通过Boot Pin的电平来选择,不是特别方便。所以一般都会再自己实现一个Bootloader。 2. IAP说明 STM32F103RB内置有128K Flash Rom,可以划分为Bootloader和UserApp两个区域,Bootloader区域不会被更新,其功能是用来更新UserApp区域的,UserApp是真正的功能程序区域,用于写正常的用户程序。 Bootloader功能主要如下: 1)检查是否需要对UserApp区域进行更新 2)如果不需要更新则跳转到UserApp区域执行 3)执行更新操作,通过UART来接收数据 4)更新完成跳转到UserApp区域执行 Flash ROM空间划分 103RB 128K Rom空间被划分为Bootloader和UserApp两个区域,Bootloader使用0x08000000-0x08001FFF共8K的空间大小,UserApp使用0x08002000-0x0801FFFF 120K空间大小,并在最后的0x0801FFFC位置预留一个4byte空间,用来定义IAP Flag,具体值为 0x33CC55AA 。 Boot程序运行流程
由于IAP之架构会将MCU ROM分成两个区域运行,并相互不能干扰,但中断向量是有固定的入口,不做任何的话,中断向量都是在Bootloader区域中,此时UserApp的中断会无法正确执行,导致系统运行出错。所以需要对中断向量进行相应处理。
// system_stm32f1xx.c -- SystemInit() #ifdef VECT_TAB_SRAM SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */ #else SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */ #endif 对于像STM32F0 M0架构的MCU,没有中断向量重定向的寄存器的相关设置,但可以设置系统从SRAM来运行, 所以有一种巧妙的方法来到达向量重定义的目的,把UserApp前面中断向量相关的ROM复制到SRAM的开头来, 这样UserApp的中断也能得到正确响应。
2. 不正确时,运行Bootloader里的处理函数 __irq void SysTick_Handler(void) { if((*((uint32_t*)0x0801FFFC)) == 0x33CC55AA) { ((void(*)(void))*(uint32_t *)(APP_START_ADDRESS + SYSTICK_IRQ_OFFSET))(); //UserApp Interrupt handler } else { Boot_SysTick_Handler(); //Bootloader Interrupt handler } } Bootloader和UserAPP之间的相互跳转
// typedef void (*pFunction)(void); // pFunction JumpToApplication; // uint32_t JumpAddress; // #define IAP_FLAG_ADDRESS 0x0801FFFC // #define IAP_FLAG_VALUE 0x33CC55AA // #define APP_START_ADDRESS 0x08002000 // 8K if( *(volatile uint32_t*)(IAP_FLAG_ADDRESS) == IAP_FLAG_VALUE) { if (((*(__IO uint32_t*)APP_START_ADDRESS) & 0x2FFE0000 ) == 0x20000000) { /* Jump to user application */ JumpAddress = *(__IO uint32_t*)(APP_START_ADDRESS + 4); JumpToApplication = (pFunction) JumpAddress; /* Initialize user application's Stack Pointer */ __set_MSP( *(__IO uint32_t*)APP_START_ADDRESS ); JumpToApplication(); } }
__asm void Jmp_Boot(void) { LDR r0, = 0x08001001 //** bootloader MN_IAPHandler address = 0x8001000 } 3. Bootloader程序 ROM Setting 主函数 __attribute__((section(".ARM.__at_0x8001000"))) void MN_IAPHandler(void); int main(void) { // // #define IAP_FLAG_ADDRESS 0x0801FFFC // #define IAP_FLAG_VALUE 0x33CC55AA // #define APP_START_ADDRESS 0x08002000 // 8K if( *(volatile uint32_t*)(IAP_FLAG_ADDRESS) == IAP_FLAG_VALUE) { if (((*(__IO uint32_t*)APP_START_ADDRESS) & 0x2FFE0000 ) == 0x20000000) { /* Jump to user application */ JumpAddress = *(__IO uint32_t*)(APP_START_ADDRESS + 4); JumpToApplication = (pFunction) JumpAddress; /* Initialize user application's Stack Pointer */ __set_MSP( *(__IO uint32_t*)APP_START_ADDRESS ); JumpToApplication(); } } MN_IAPHandler(); } MN_IAPHandler(at 0x0800 1000) 当前Bootloader中不使用中断,所以需要关闭所有中断,如果是从UserApp跳转过来的,要重新设置下MSP以及时钟和Uart等功能,并且相关用上的RAM变量要清零下。 void MN_IAPHandler(void) { uint32_t i; __set_MSP(0x20001428); // Current Project MSP Value __disable_irq(); // disable interrupt //__set_PRIMASK(1); //SCB->VTOR = 0x08000000; LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_AFIO); LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR); /** NOJTAG: JTAG-DP Disabled and SW-DP Enabled */ LL_GPIO_AF_Remap_SWJ_NOJTAG(); /* Configure the system clock */ SystemClock_Config(); /* Initialize all configured peripherals */ LL_USART_DeInit(USART2); MX_USART2_UART_Init(); LL_InitTick(64000000, 100); //10ms wIAP_Recv_Cnts = 0; bIAP_Recv_TmOut = 0; bIAP_ProgramEnable = 0; for(i = 0; i < IAP_RECV_LEN; i++) { bIAP_Recv_Buf = 0x00; } while(1) { // Check if Usart2 data receive if( USART2->SR & (0x1<<5) ) { USART2->SR &=~(0x1<<5); bIAP_Recv_Buf[wIAP_Recv_Cnts++] = USART2->DR; if(wIAP_Recv_Cnts == IAP_RECV_LEN) { wIAP_Recv_Cnts = 0; IAP_Recv_Handle(); } } } } Flash擦除操作函数 /** * @brief LL_FLASH_Unlock * @retval ErrorStatus */ ErrorStatus LL_FLASH_Unlock(void) { // FLASH->SR = 0x0; // FLASH->CR = 0x80; if(READ_BIT(FLASH->CR, FLASH_CR_LOCK) != RESET) { /* Authorize the FLASH Registers access */ WRITE_REG(FLASH->KEYR, FLASH_KEY1); WRITE_REG(FLASH->KEYR, FLASH_KEY2); /* Verify Flash is unlocked */ if(READ_BIT(FLASH->CR, FLASH_CR_LOCK) != RESET) { return ERROR; } } return (SUCCESS); } /** * @brief LL_FLASH_Lock * @retval ErrorStatus */ ErrorStatus LL_FLASH_Lock(void) { SET_BIT(FLASH->CR, FLASH_CR_LOCK); return (SUCCESS); } /** * @brief LL_FLASH_PageErase * @retval None */ void LL_FLASH_PageErase(uint32_t PageAddress) { SET_BIT(FLASH->CR, FLASH_CR_PER); WRITE_REG(FLASH->AR, PageAddress & 0xFFFFFC00); // 1K SET_BIT(FLASH->CR, FLASH_CR_STRT); while(FLASH->SR & FLASH_SR_BSY); CLEAR_BIT(FLASH->CR, FLASH_CR_PER); // CLEAR_BIT(FLASH->CR, FLASH_CR_STRT); } /** * @brief LL_FLASH_Program_Word * @retval None */ void LL_FLASH_Program_Word(uint32_t Address, uint32_t Data) { SET_BIT(FLASH->CR, FLASH_CR_PG); *(__IO uint16_t*)Address = (uint16_t)(Data & 0xFFFF); while(FLASH->SR & FLASH_SR_BSY); *(__IO uint16_t*)(Address+2) = (uint16_t)(Data>>16); while(FLASH->SR & FLASH_SR_BSY); CLEAR_BIT(FLASH->CR, FLASH_CR_PG); // Verify // if(*(__IO uint32_t*)Address != Data) // { // return ERROR; // } } 4. UserApp程序 Rom Setting 在UserApp Rom最后位置定义IAP Flag常量,用于Bootloader中对UserApp Rom的判断 const uint32_t wIAP_FLAG __attribute__((at(0x801FFFC))) = 0x33CC55AA; 重定向中断向量 修改system_stm32f1xx.c中 VECT_TAB_OFFSET 为 0x2000 // system_stm32f1xx.c /* #define VECT_TAB_SRAM */ #define VECT_TAB_OFFSET 0x00002000U /*!< Vector Table base offset field. This value must be a multiple of 0x200. */ 升级动作 当收到需要升级的命令时,跳转到Bootloader中执行IAPHandler。跳转的方法前面都有介绍。 bin文件的生成 一般升级时需要bin文件,里面都是原始的ROM数据,可以自己写个hex转bin文件的小程序,或者使用STM32CubeProgrammer工具,先加载hex文件,然后另存为bin文件。 小结 最后写了个串口上位机,试了下升级,功能整体还是OK的,有没有bug还要再测试下,总体来说,UART IAP对于升级程序还是很方便的。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1780 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1621 浏览 1 评论
1081 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
728 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1679 浏览 2 评论
1938浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
731浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
570浏览 3评论
596浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
556浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 23:50 , Processed in 0.647833 second(s), Total 44, Slave 38 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号