STM32 IAP在线升级在项目中的应用
发布时间:2020-12-15 07:21:30 所属栏目:百科 来源:网络整理
导读:IAP即在线应用编程,平时我们写好的程序都是通过下载器去下载的,但是对于组装好的产品在想更新底层硬件代码是很麻烦的事情,如果在公司情况还没那么糟糕,要是发出去的产品出现bug,你不可能要用户给你下载程序的。IAP这种技术,我们就可以像软件一样,可以
一、FLASH读写接口的实现
//读1个字节 uint8_t FLASH_ReadByte(uint32_t Addr) { return *(vu8 *)Addr; } //读2个字节 uint16_t FLASH_ReadHalfWord(uint32_t Addr) { return *(vu16 *)Addr; } //读N个字节 void FLASH_ReadNByte(uint32_t Addr,uint8_t *pBuff,uint32_t Len) { uint32_t i; for(i = 0;i < Len;i++) { pBuff[i] = FLASH_ReadByte(Addr); Addr += 1; } }
#define STM32_SECTOR_SIZE 2048 //页大小 #define STM32_SECTOR_NUM 255 //页数 //STM32 FLASH的起始地址 #define STM32_FLASH_BASE 0x08000000 void FLASH_ReadPage(uint8_t Page_Num,uint8_t *pBuff) { uint16_t i; uint32_t Buff; uint32_t Addr; //是否超出范围 if(Page_Num > STM32_SECTOR_NUM) return; //先计算页首地址 Addr = Page_Num * STM32_SECTOR_SIZE + STM32_FLASH_BASE; for(i = 0;i < STM32_SECTOR_SIZE;i += 4) { Buff = FLASH_ReadWord(Addr); pBuff[i] = Buff; pBuff[i+1] = Buff >> 8; pBuff[i+2] = Buff >> 16; pBuff[i+3] = Buff >> 24; Addr += 4; } }
void FLASH_WritePage(uint8_t Page_Num,uint8_t *pBuff) { uint16_t i; uint16_t Buff; uint32_t Addr; //是否超出范围 if(Page_Num > STM32_SECTOR_NUM) return; //解锁 FLASH_Unlock(); //先计算页首地址 Addr = Page_Num * STM32_SECTOR_SIZE + STM32_FLASH_BASE; for(i = 0;i < STM32_SECTOR_SIZE ;i += 2) { Buff = ((uint16_t)pBuff[i+1] << 8) | pBuff[i]; FLASH_ProgramHalfWord(Addr,Buff); Addr += 2; } //上锁 FLASH_Lock(); }
void FLASH_WriteNData(uint32_t Addr,uint32_t Len) { uint32_t Offset; uint8_t Page_Num; uint16_t Page_Offset; uint16_t Free_Space; uint16_t i; if((Addr < STM32_FLASH_BASE) || (Addr > STM32_FLASH_END)) return; Offset = Addr - STM32_FLASH_BASE;//偏移地址 Page_Num = Offset / STM32_SECTOR_SIZE;//得到地址所在页 Page_Offset = Offset % STM32_SECTOR_SIZE;//在页内的偏移地址 Free_Space = STM32_SECTOR_SIZE - Page_Offset;//页区剩余空间 //要写入的数据是否大于剩余空间 if(Len <= Free_Space) Free_Space = Len; FLASH_Unlock();//解锁 while(1) { FLASH_ReadPage(Page_Num,STM32_FLASH_BUFF);//先把数据读到缓存中 FLASH_ErasePage(Page_Num * STM32_SECTOR_SIZE + STM32_FLASH_BASE);//页擦除 //修改缓存数据 for(i = 0;i < Free_Space;i++) { STM32_FLASH_BUFF[i+Page_Offset] = pBuff[i]; } FLASH_WritePage(Page_Num,STM32_FLASH_BUFF);//把缓存数据写入 //判断是否超出当前页,超出进入下一页 if(Len == Free_Space) break; else { Page_Num++;//下一页 Page_Offset = 0; pBuff += Free_Space; Len -= Free_Space; if(Len > STM32_SECTOR_SIZE) Free_Space = STM32_SECTOR_SIZE; else Free_Space = Len; } } FLASH_Lock(); } void FLASH_WriteNByte(uint32_t Addr,uint32_t Len) { uint16_t i; uint16_t temp = 0; if((Addr < STM32_FLASH_BASE) || (Addr > STM32_FLASH_END)) return; FLASH_Unlock();//解锁 for(i = 0;i < Len;i += 2) { temp = pBuff[i]; temp |= (uint16_t)pBuff[i+1] << 8; FLASH_ProgramHalfWord(Addr,temp); Addr += 2; if(Addr > STM32_FLASH_END) { FLASH_Lock(); return; } } FLASH_Lock(); }
void Flash_EraseSector(uint8_t Start_Page,uint8_t End_Page) { uint8_t i; uint8_t num = 0; if(Start_Page > End_Page) return; FLASH_Unlock();//解锁 num = End_Page - Start_Page;//擦除页数 for(i = 0;i <= num;i++) { FLASH_ErasePage((Start_Page + i) * STM32_SECTOR_SIZE + STM32_FLASH_BASE);//页擦除 } FLASH_Lock(); }
void Test_Flash_WR(uint8_t Page_Num) { uint16_t i = 0; uint8_t j = 0; //是否超出范围 if(Page_Num > STM32_SECTOR_NUM) return; for(i = 0;i < STM32_SECTOR_SIZE;i++) { buff[i] = j++; } //页擦除 // Flash_EraseSector(Page_Num,Page_Num); //写入 // FLASH_WritePage(Page_Num,buff); //写入 // FLASH_WriteNByte(Page_Num * STM32_SECTOR_SIZE + STM32_FLASH_BASE,buff,STM32_SECTOR_SIZE); //写入 FLASH_WriteNData(Page_Num * STM32_SECTOR_SIZE + STM32_FLASH_BASE + 4,10); //清零 memset(buff,STM32_SECTOR_SIZE); //读出 FLASH_ReadPage(Page_Num,buff); for(i = 0;i < STM32_SECTOR_SIZE;i++) { printf("%02X ",buff[i]); } printf("rn"); } 二、分区规划
三、Bootloader程序实现
#define FLASH_APP_ADDR STM32_SECTOR6_ADDR #define FLASH_DOWNLOAD_ADDR STM32_SECTOR56_ADDR #define FLASH_APP_FLAG STM32_SECTOR255_ADDR #define FLASH_UPDATA_FLAG FLASH_APP_FLAG + 2 int main(void) { SystemInit(); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); Delay_Init(); LED_Init(); KEY_Init(); USART1_Init(115200); //判断是否需要升级固件 if(FLASH_ReadHalfWord(FLASH_UPDATA_FLAG) == 0xAA55) { printf("Updata App...rn"); IAP_Copy_App();//拷贝到app分区 printf("Updata App Succeed...rn"); } //判断是否有APP程序 //中断向量表判断 if(((*(vu32*)(FLASH_APP_ADDR + 4))&0xFF000000) == 0x08000000) { printf("Run App...rnrn"); Delay_ms(10); IAP_Load_App(FLASH_APP_ADDR);//转到app } printf("No Apprn"); TIM3_Init(1000,72);//定时0.001s while(1) { Task_Process(); if(USART1_RX_CNT > 0) { IAP_WriteBin(FLASH_DOWNLOAD_ADDR,USART1_RxBuff,USART1_RX_CNT); USART1_RX_CNT = 0; } } }
typedef void (*IAP_Fun)(void); IAP_Fun JumpApp; uint8_t STM32_FLASH_BUFF[STM32_SECTOR_SIZE] = {0}; void IAP_Copy_App(void) { uint8_t i; uint8_t buf[2] = {0x00,0x00}; //擦除App扇区 Flash_EraseSector(6,55); for(i = 0;i < 50;i++) { FLASH_ReadPage(56 + i,STM32_FLASH_BUFF); FLASH_WritePage(6 + i,STM32_FLASH_BUFF); LED3 = !LED3; } FLASH_WriteNData(FLASH_UPDATA_FLAG,buf,2); } void IAP_Load_App(uint32_t Addr) { //检查栈顶地址是否合法 if(((*(vu32*)Addr) & 0x2FFE0000) == 0x20000000) { __disable_irq(); JumpApp = (IAP_Fun)*(vu32 *)(Addr + 4); MSR_MSP(*(vu32 *)Addr); JumpApp(); } }
void IAP_WriteBin(uint32_t Addr,uint32_t Len) { uint8_t buf[2] = {0xAA,0x55}; //擦除App扇区 Flash_EraseSector(6,55); //写入程序 FLASH_WriteNByte(Addr,pBuff,Len); //更新标记 FLASH_WriteNData(FLASH_UPDATA_FLAG,2); //复位单片机 NVIC_SystemReset(); } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |