#include "fy_looplist.h" #include "fy_includes.h" #ifndef NULL #define NULL 0 #endif #ifndef min #define min(a, b) (a)<(b)?(a):(b) //< 获取最小值 #endif #define DEBUG_LOOP 1 static int Create(_loopList_s* p,unsigned char *buf,unsigned int len); static void Delete(_loopList_s* p); static int Get_Capacity(_loopList_s *p); static int Get_CanRead(_loopList_s *p); static int Get_CanWrite(_loopList_s *p); static int Read(_loopList_s *p, void *buf, unsigned int len); static int Write(_loopList_s *p, const void *buf, unsigned int len); struct _typdef_LoopList _list= { Create, Delete, Get_Capacity, Get_CanRead, Get_CanWrite, Read, Write }; //初始化环形缓冲区 static int Create(_loopList_s* p,unsigned char *buf,unsigned int len) { if(NULL == p) { #if DEBUG_LOOP printf("ERROR: input list is NULL "); #endif return 0; } p->capacity = len; p->buf = buf; p->head = p->buf;//头指向数组首地址 p->tail = p->buf;//尾指向数组首地址 return 1; } //删除一个环形缓冲区 static void Delete(_loopList_s* p) { if(NULL == p) { #if DEBUG_LOOP printf("ERROR: input list is NULL "); #endif return; } p->buf = NULL;//地址赋值为空 p->head = NULL;//头地址为空 p->tail = NULL;//尾地址尾空 p->capacity = 0;//长度为空 } //获取链表的长度 static int Get_Capacity(_loopList_s *p) { if(NULL == p) { #if DEBUG_LOOP printf("ERROR: input list is NULL "); #endif return -1; } return p->capacity; } //返回能读的空间 static int Get_CanRead(_loopList_s *p) { if(NULL == p) { #if DEBUG_LOOP printf("ERROR: input list is NULL "); #endif return -1; } if(p->head == p->tail)//头与尾相遇 { return 0; } if(p->head < p->tail)//尾大于头 { return p->tail - p->head; } return Get_Capacity(p) - (p->head - p->tail);//头大于尾 } //返回能写入的空间 static int Get_CanWrite(_loopList_s *p) { if(NULL == p) { #if DEBUG_LOOP printf("ERROR: input list is NULL "); #endif return -1; } return Get_Capacity(p) - Get_CanRead(p);//总的减去已经写入的空间 } // p--要读的环形链表 // buf--读出的数据 // count--读的个数 static int Read(_loopList_s *p, void *buf, unsigned int len) { int copySz = 0; if(NULL == p) { #if DEBUG_LOOP printf("ERROR: input list is NULL "); #endif return -1; } if(NULL == buf) { #if DEBUG_LOOP printf("ERROR: input buf is NULL "); #endif return -2; } if(p->head < p->tail)//尾大于头 { copySz = min(len, Get_CanRead(p)); //比较能读的个数 memcpy(buf, p->head, copySz); //读出数据 p->head += copySz; //头指针加上读取的个数 return copySz; //返回读取的个数 } else //头大于等于了尾 { if (len < Get_Capacity(p)-(p->head - p->buf))//读的个数小于头上面的数据量 { copySz = len;//读出的个数 memcpy(buf, p->head, copySz); p->head += copySz; return copySz; } else//读的个数大于头上面的数据量 { copySz = Get_Capacity(p) - (p->head - p->buf);//先读出来头上面的数据 memcpy(buf, p->head, copySz); p->head = p->buf;//头指针指向数组的首地址 //还要读的个数 copySz += Read(p,(char*)buf+copySz, len-copySz);//接着读剩余要读的个数 return copySz; } } } // p--要写的环形链表 // buf--写出的数据 // len--写的个数 static int Write(_loopList_s *p, const void *buf, unsigned int len) { int tailAvailSz = 0;//尾部剩余空间 if(NULL == p) { #if DEBUG_LOOP printf("ERROR: list is empty "); #endif return -1; } if(NULL == buf) { #if DEBUG_LOOP printf("ERROR: buf is empty "); #endif return -2; } if (len >= Get_CanWrite(p))//如果剩余的空间不够 { #if DEBUG_LOOP printf("ERROR: no memory "); #endif return -3; } if (p->head <= p->tail)//头小于等于尾 { tailAvailSz = Get_Capacity(p) - (p->tail - p->buf); //查看尾上面剩余的空间 if (len <= tailAvailSz)//个数小于等于尾上面剩余的空间 { memcpy(p->tail, buf, len);//拷贝数据到环形数组 p->tail += len;//尾指针加上数据个数 if (p->tail == p->buf+Get_Capacity(p))//正好写到最后 { p->tail = p->buf;//尾指向数组的首地址 } return len;//返回写入的数据个数 } else { memcpy(p->tail, buf, tailAvailSz); //填入尾上面剩余的空间 p->tail = p->buf; //尾指针指向数组首地址 //剩余空间 剩余数据的首地址 剩余数据的个数 return tailAvailSz + Write(p, (char*)buf+tailAvailSz, len-tailAvailSz);//接着写剩余的数据 } } else //头大于尾 { memcpy(p->tail, buf, len); p->tail += len; return len; } } /*********************************************END OF FILE********************************************/
#include "fy_includes.h" /* 晶振使用的是16M 其他频率在system_stm32f10x.c中修改 使用printf需要在fy_includes.h修改串口重定向为#define PRINTF_USART USART1 */ /* Bootloader程序 完成三个任务 步骤1.检查是否有程序更新,如果有就擦写flash进行更新,如果没有进入步骤2 步骤2.判断app1有没有可执行程序,如果有就执行,如果没有进入步骤3 步骤3.串口等待接收程序固件 */ #define FLAG_UPDATE_APP1 0xBBAA #define FLAG_UPDATE_APP2 0xAABB #define FLAG_APP1 0xAAAA #define FLAG_APP2 0xBBBB #define FLAG_NONE 0xFFFF _loopList_s list1; u8 rxbuf[1024]; u8 temp8[2]; u16 temp16; u32 rxlen=0; u32 applen=0; u32 write_addr; u8 overflow=0; u32 now_tick=0; u8 _cnt_10ms=0; static void App_Check(void) { //获取程序标号 STMFLASH_Read(FLASH_PARAM_ADDR,&temp16,1); if(temp16 == FLAG_APP1)//执行程序A { if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)//可执行? { printf(" 执行程序A... "); IAP_RunApp(FLASH_APP1_ADDR); } else { printf(" 程序A不可执行,擦除APP1程序所在空间... "); for(u8 i=10;i<35;i++) { STMFLASH_Erase(FLASH_BASE + i*STM_SECTOR_SIZE,512); } printf(" 程序A所在空间擦除完成... "); printf(" 将执行程序B... "); if(((*(vu32*)(FLASH_APP2_ADDR+4))&0xFF000000)==0x08000000)//可执行? { printf(" 执行程序B... "); IAP_RunApp(FLASH_APP2_ADDR); } else { printf(" 程序B不可执行,擦除APP2程序所在空间... "); for(u8 i=35;i<60;i++) { STMFLASH_Erase(FLASH_BASE + i*STM_SECTOR_SIZE,512); } printf(" 程序B所在空间擦除完成... "); } } } if(temp16 == FLAG_APP2)//执行程序B { if(((*(vu32*)(FLASH_APP2_ADDR+4))&0xFF000000)==0x08000000)//可执行? { printf(" 执行程序B... "); IAP_RunApp(FLASH_APP2_ADDR); } else { printf(" 程序B不可执行,擦除APP2程序所在空间... "); for(u8 i=35;i<60;i++) { STMFLASH_Erase(FLASH_BASE + i*STM_SECTOR_SIZE,512); } printf(" 程序B所在空间擦除完成... "); printf(" 将执行程序A... "); if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)//可执行? { printf(" 执行程序A... "); IAP_RunApp(FLASH_APP1_ADDR); } else { printf(" 程序A不可执行,擦除APP1程序所在空间... "); for(u8 i=10;i<35;i++) { STMFLASH_Erase(FLASH_BASE + i*STM_SECTOR_SIZE,512); } printf(" 程序A所在空间擦除完成... "); } } } if(temp16 == FLAG_NONE) { printf(" 擦除App1程序所在空间... "); for(u8 i=10;i<35;i++) { STMFLASH_Erase(FLASH_BASE + i*STM_SECTOR_SIZE,512); } printf(" 程序A所在空间擦除完成... "); } } static void Update_Check(void) { if(_list.Get_CanRead(&list1)>1) { _list.Read(&list1,&temp8,2);//读取两个数据 temp16 = (u16)(temp8[1]<<8) | temp8[0]; STMFLASH_Write(write_addr,&temp16,1); write_addr+=2; } if(GetSystick_ms() - now_tick >10)//10ms { now_tick = GetSystick_ms(); _cnt_10ms++; if(applen == rxlen && rxlen)//接收完成 { if(overflow) { printf("接收溢出,无法更新,请重试 "); SoftReset();//软件复位 } else { printf(" 接收BIN文件完成,长度为 %d ",applen); temp16 = FLAG_APP1; STMFLASH_Write(FLASH_PARAM_ADDR,&temp16,1);//写入标记 temp16 = (u16)(applen>>16); STMFLASH_Write(FLASH_PARAM_ADDR+2,&temp16,1); temp16 = (u16)(applen); STMFLASH_Write(FLASH_PARAM_ADDR+4,&temp16,1); SoftReset();//软件复位 } }else applen = rxlen;//更新长度 } if(_cnt_10ms>=50) { _cnt_10ms=0; Led_Tog(); if(!rxlen) { printf(" 等待接收App1的BIN文件 "); } } } int main(void) { NVIC_SetPriorityGrouping( NVIC_PriorityGroup_2); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO时钟 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); //禁止JTAG保留SWD Systick_Configuration(); Led_Configuration(); Key_Configuration(); Usart1_Configuration(9600); USART_ITConfig(USART1, USART_IT_IDLE, DISABLE);//关闭串口空闲中断 printf(" this is bootloader! "); if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == SET) { Delay_ms(100); if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == SET)//开机按下keyup进行更新 { printf(" 主动更新,"); temp16 = FLAG_NONE; STMFLASH_Write(FLASH_PARAM_ADDR,&temp16,1); } else { } } App_Check(); printf(" 执行BootLoader程序... "); _list.Create(&list1,rxbuf,sizeof(rxbuf)); write_addr = FLASH_APP1_ADDR; while(1) { Update_Check(); } } //USART1串口中断函数 void USART1_IRQHandler(void) { if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { u8 temp = USART1->DR; if(_list.Write(&list1,&temp,1)<=0) { overflow=1; } rxlen++; } }
其中的宏://FLASH起始地址 #define STM32_FLASH_BASE 0x08000000 //STM32 FLASH的起始地址 #define FLASH_APP1_ADDR STM32_FLASH_BASE+0x2800 //偏移10K #define FLASH_APP2_ADDR STM32_FLASH_BASE+0x8c00 //偏移35K #define FLASH_PARAM_ADDR STM32_FLASH_BASE+0xF000 //偏移60K
#include "fy_includes.h" /* 晶振使用的是16M 其他频率在system_stm32f10x.c中修改 使用printf需要在fy_includes.h修改串口重定向为#define PRINTF_USART USART1 */ /* APP1程序 完成两个任务 1.执行本身的app任务,同时监听程序更新,监听到停止本身的任务进入到状态2 2.等待接收完成,完成后复位重启 */ #define FLAG_UPDATE_APP1 0xBBAA #define FLAG_UPDATE_APP2 0xAABB #define FLAG_APP1 0xAAAA #define FLAG_APP2 0xBBBB #define FLAG_NONE 0xFFFF _loopList_s list1; u8 rxbuf[1024]; u8 temp8[2]; u16 temp16; u32 rxlen=0; u32 applen=0; u32 write_flsh_addr; u8 update=0; u8 overflow=0; u32 now_tick; u8 _cnt_10ms=0; static void Update_Check(void) { if(update)//监听到有更新程序 { write_flsh_addr = FLASH_APP2_ADDR;//App1更新App2的程序 overflow=0; rxlen=0; _list.Create(&list1,rxbuf,sizeof(rxbuf)); printf(" 擦除APP2程序所在空间... "); for(u8 i=35;i<60;i++)//擦除APP2所在空间程序 { STMFLASH_Erase(FLASH_BASE + i*STM_SECTOR_SIZE,512); } printf(" 程序B所在空间擦除完成... "); while(1) { if(_list.Get_CanRead(&list1)>1) { _list.Read(&list1,&temp8,2);//读取两个数据 temp16 = (u16)(temp8[1]<<8) | temp8[0]; STMFLASH_Write(write_flsh_addr,&temp16,1); write_flsh_addr+=2; } if(GetSystick_ms() - now_tick >10)//10ms { now_tick = GetSystick_ms(); _cnt_10ms++; if(applen == rxlen && rxlen)//接收完成 { if(overflow) { printf(" 接收溢出,请重新尝试 "); SoftReset();//软件复位 } printf(" 接收BIN文件完成,长度为 %d ",applen); temp16 = FLAG_APP2; STMFLASH_Write(FLASH_PARAM_ADDR,&temp16,1);//写入标记 temp16 = (u16)(applen>>16); STMFLASH_Write(FLASH_PARAM_ADDR+2,&temp16,1); temp16 = (u16)(applen); STMFLASH_Write(FLASH_PARAM_ADDR+4,&temp16,1); printf(" 系统将重启.... "); SoftReset();//软件复位 }else applen = rxlen;//更新长度 } if(_cnt_10ms>=50) { _cnt_10ms=0; Led_Tog(); if(!rxlen) { printf(" 等待接收App2的BIN文件 "); } } }//while(1) } } static void App_Task(void) { if(GetSystick_ms() - now_tick >500) { now_tick = GetSystick_ms(); printf(" 正在运行APP1 "); Led_Tog(); } } int main(void) { SCB->VTOR = FLASH_APP1_ADDR; RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO时钟 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); //禁止JTAG保留SWD Systick_Configuration(); Led_Configuration(); Usart1_Configuration(9600); printf(" this is APP1! "); Delay_ms(500); while(1) { Update_Check(); App_Task(); } } //USART1串口中断函数 void USART1_IRQHandler(void) { if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { u8 temp = USART1->DR; if(update) { if(_list.Write(&list1,&temp,1) <= 0 ) { overflow = 1; } } else { rxbuf[rxlen] = temp; } rxlen++; } if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) { u8 temp = USART1->DR; temp = USART1->SR; if(strstr((char *)rxbuf,"App Update") && rxlen) { update=1; USART_ITConfig(USART1, USART_IT_IDLE, DISABLE);//关闭串口空闲中断 } else { Usart1_SendBuf(rxbuf,rxlen); } rxlen=0; } }
这里如果要移植需要注意的就是向量表的偏移以及更新擦写的区域。全部0条评论
快来发表一下你的评论吧 !