赞
踩
芯片:stm32f407
开发平台:stm32cubeide
上位机开发平台:visual studio 2017
1. FLASH分配
将flash划分为四个部分:
bootloader: 0x8000000-0x800ffff
app1: 0x8010000-0x805ffff
app2: 0x8060000-0x80affff
parameters: 0x80e0000-0x80fffff
其中,bootloader程序为启动程序,app1是当前运行程序,app2为准备升级程序,parameters存储程序相关参数。
2. BOOTLOADER
在app2中用最后一段flash地址0x80dfff0来存储升级标志Upgrade_Flag,比如有新程序下载到app2中,则0x80dfff0中数据为0xaaaaaa,如果为其他则表示没有新程序,开机后bootloader首先运行,启动后检测Upgrade_Flag是否为0xaaaaaa:
如果是,则将app2中的程序拷贝到app1中,然后重置标志位Upgrade_Flag为0xffffffff且跳转到app1起始地址0x8010000开始执行新的程序;
如果否,则直接跳转到app1起始地址0x8010000开始运行程序;
bootloader主要代码如下:
- #define IAP_ADDRESS 0x8000000 //
- #define APP1_ADDRESS 0x8010000 //
- #define APP1_ADDRESS_END 0x805FFFF //
- #define APP2_ADDRESS 0x8060000 //
- #define APP2_ADDRESS_END 0x80AFFFF //
- #define PARA_ADDRESS 0x80E0000 //
- #define UPGRADE_ADDRESS 0x80DFFF0 //
-
-
- pFunction Jump_To_Application;
- uint32_t JumpAddress;
-
- pFunction Jump_To_Application;
- void Jump_To_APP()
- {
- uint32_t JumpAddress;
- printf("jump to app: %#x\r\n", APP1_ADDRESS);
- //HAL_DeInit();
- __disable_irq();
- if(((*(__IO uint32_t*)APP1_ADDRESS)&0x2ffe0000)==0x20020000)
- {
- /* Jump to user application */
- JumpAddress = *(__IO uint32_t*) (APP1_ADDRESS + 4);
- Jump_To_Application = (pFunction) JumpAddress;
- //printf("jump %#x success \r\n",APP1_ADDRESS);
-
- /* Initialize user application's Stack Pointer */
- __set_MSP(*(__IO uint32_t*) APP1_ADDRESS);
- Jump_To_Application();
- }
- else
- {
- printf("error [0x%08x]\r\n",(*(volatile uint32_t*)APP1_ADDRESS));
- }
- }
- uint8_t u8_Code_Buff[2048];//2k
- uint16_t Num=0;
- uint8_t NotUpgrade[4]={0xff,0xff,0xff,0xff};
- uint8_t Upgrade[4]={0xaa,0xaa,0xaa,0xaa};
- uint32_t Upgrade_Flag;
-
- void Copy_APP2_to_APP1(void)
- {
-
- if(((*(__IO uint32_t*)APP2_ADDRESS)&0x2ffe0000)!=0x20020000)
- {
- printf("invalid app in address [0x%08x]\r\n",APP2_ADDRESS);
- return;
- }
- MEM_IF_IniT();
- uint32_t APP1_Addr;
- uint32_t APP2_Addr;
- APP1_Addr=APP1_ADDRESS;
- APP2_Addr=APP2_ADDRESS;
- MEM_If_Erase(APP1_ADDRESS,APP1_ADDRESS_END);
- printf("Erase app1 flash\r\n");
- for(int i=0;i<150;i++)//copy 150*2k=300k, max size of app is 300k
- {
- printf("APP1_Addr = %x\r\n",APP1_Addr);
- printf("APP2_Addr = %x\r\n",APP2_Addr);
- MEM_If_Read(u8_Code_Buff,APP2_Addr,2048);
- HAL_Delay(10);
- MEM_If_Write_Byte(u8_Code_Buff,APP1_Addr,2048);
- HAL_Delay(10);
- APP1_Addr+=0x800;
- APP2_Addr+=0x800;
- memset(u8_Code_Buff,0,sizeof(u8_Code_Buff));
- Num=i;
- if(1)
- {
- printf("Successfully copied page %d\r\n",Num);
- }
- else
- {
- printf("Copy failed page %d\r\n",Num);
- }
-
- }
- MEM_If_Erase(UPGRADE_ADDRESS,UPGRADE_ADDRESS);
- MEM_If_Write_Byte(NotUpgrade,UPGRADE_ADDRESS,sizeof(NotUpgrade));
- MEM_IF_DeInit();
- }
-
- int main(void)
- {
- /* USER CODE BEGIN 1 */
-
- //SCB->VTOR = FLASH_BASE | 0x40000;
-
- /* USER CODE END 1 */
-
- /* MCU Configuration--------------------------------------------------------*/
-
- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
- HAL_Init();
-
- /* USER CODE BEGIN Init */
- /* USER CODE END Init */
-
- /* Configure the system clock */
- SystemClock_Config();
-
- /* USER CODE BEGIN SysInit */
-
- /* USER CODE END SysInit */
-
- /* Initialize all configured peripherals */
- MX_GPIO_Init();
- MX_USART1_UART_Init();
- /* USER CODE BEGIN 2 */
- printf("\r\n");
- printf("*****************************************\r\n");
- printf("* luckyzjian's ISP *\r\n");
- printf("* *\r\n");
- printf("* www.cdxcjc.com *\r\n");
- printf("* *\r\n");
- printf("* Version: v%d.%d.%d *\r\n",version_board,version_year,version_no);
- printf("* *\r\n");
- printf("* 026-82598116 *\r\n");
- printf("*****************************************\r\n");
- printf("************ flash table ***************\r\n");
- printf("*bootloader : %#x -------- %#x******\r\n",IAP_ADDRESS,APP1_ADDRESS-1);
- printf("*APP1 : %#x -------- %#x******\r\n",APP1_ADDRESS,APP1_ADDRESS_END);
- printf("*APP2 : %#x -------- %#x******\r\n",APP2_ADDRESS,APP2_ADDRESS_END);
- printf("*PRIVATE PARA: %#x -------- %#x******\r\n",PARA_ADDRESS,PARA_ADDRESS+0X1FFFF);
- printf("*****************************************\r\n");
-
-
- TM1629_init();
- Upgrade_Flag=*(__IO uint32_t*)(UPGRADE_ADDRESS);
- printf("Upgrade_Flag = 0x%x\r\n",Upgrade_Flag);
-
- if(0xaaaaaaaa==Upgrade_Flag)
- {
- printf("there is new app in address: %x\r\n",APP2_ADDRESS);
- printf("copy new app in address: %x to address: %x\r\n",APP2_ADDRESS,APP1_ADDRESS);
- TM1629_printRow1("-----",ShowType_Right);
- TM1629_printRow2("-ISP-",ShowType_Right);
- TM1629_DISPLAY();
- Copy_APP2_to_APP1();
- printf("copy finished\r\n",APP2_ADDRESS,APP1_ADDRESS);
- printf("------%#x\r\n",(APP1_ADDRESS+4)&0XFF000000);
- if(((APP1_ADDRESS+4)&0xff000000)==0x08000000)
- {
- printf("jump APP1 running");
- Jump_To_APP(APP1_ADDRESS);
- }
- }
- else
- {
- printf("there is no new app in address: %x\r\n",APP2_ADDRESS);
- printf("------%#x\r\n",(APP1_ADDRESS+4)&0xff000000);
- if(((APP1_ADDRESS+4)&0xff000000)==0x08000000)
- {
- printf("jump APP1 running\r\n");
- Jump_To_APP(APP1_ADDRESS);
- }
- }
-
-
- /* USER CODE END 2 */
-
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- /* USER CODE END WHILE */
-
- /* USER CODE BEGIN 3 */
- }
-
- /* USER CODE END 3 */
- }
3. APP
APP程序因为是从0x08010000开始运行的,要注意修改如下两个地方
- /Core/Src/system_stm32f4xx.c中:
-
- #define VECT_TAB_OFFSET 0x00010000U /*!< Vector Table base offset field.
- This value must be a multiple of 0x200. */
-
- STM32F407ZGTX_FLASH.ld:
-
- MEMORY
- {
- CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K
- RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
- FLASH (rx) : ORIGIN = 0x8010000, LENGTH = 320K
- }
程序通过TCP下载,因为我项目中已经有一套TCP的通讯接口,为了方便,便在原来的自定义接口协议中增加了下载程序的协议
通讯格式定义如下:
发送: | |||
0x02 | 起始码 | 1 | |
ADD | 地址 | 1 | 控制仪地址 0X80~0X8F 代表0~15号地址 |
CMD | 命令字节 | 1 | |
LB | 数据[DF]长度 | 1 | |
[DF] | 数据 | LB | |
CS | 校验码 | 1 | =NOT(0x02+ADD+CMD+LB+[DF])+1 |
0X03 | 结束码 | 1 | |
响应: | |||
0x06 | 起始码 | 1 | |
ADD | 地址 | 1 | 控制仪地址 0X80~0X8F 代表0~15号地址 |
CMD | 命令字节 | 1 | |
LB | 数据[DF]长度 | 1 | |
[DF] | 数据 | LB | |
CS | 校验码 | 1 | =NOT(0x06+ADD+CMD+LB+[DF])+1 |
0X03 | 结束码 | 1 |
涉及下载的命令定义如下:
命令 | 命令代码 | 命令格式 | 响应 | 说明 |
开始下载固件 | 0x51 | 0x02 ADD 0x51 0x02 [分包数量] CS 0x03 | 0x06 ADD 0x51 0x01 <STATUS> CS 0x03 | [分包数量],固件数据包按1000字节一个包进行分包,最后一包不足1000字节时,用0x00填充到1000字节,将总的分包数量在开始升级固件指令时写入 返回STATUS: 0X06 成功; 0x15 失败 |
写入固件 | 0x52 | 0x02 ADD 0x52 [分包顺序][数据长度]{数据} CS 0x03 | 0x02 ADD 0x52 0x03 [分包顺序] <STATUS> CS 0x03 | [分包顺序][数据长度]《数据》三部分固定长度为1004个字节,其中: [分包顺序]为两字节,代表该帧数据为整个固件包的第几包数据,从0开始计数; [数据长度]为两字节,代表该包数据字节长度,应固定为1000字节; 《数据》为固件内容,当最后一包不足1000字节时,用0x00填充到1000字节 返回STATUS: 0X06 成功; 0x15 失败; |
写入固件结束 | 0x53 | 0x02 ADD 0x53 0x02 <CRCH> <CRCL> CS 0x03 | 0x06 ADD 0x53 0x01 <STATUS> CS 0x03 | CRCH,CHRL组成固件全部数据的CRC16校验,下位机收到结束指令后,对整包数据进行CRC16校验,与该指令CRC校准字比对,如果比对成功,则标记为升级成功(向地址0x80DFFF0写入0xaaaaaa) 返回STATUS: 0X06 升级成功; 0x15 升级失败; |
放弃写入固件 | 0x5f | 0x02 ADD 0x5f 0x00 CS 0x03 | 0x06 ADD 0x5f 0x00 CS 0x03 |
-
- #define CLIENTMAX 5
- typedef struct
- {
- struct netconn *conn;
- uint8_t num;
- }tcp_client;
- typedef struct{
- struct netconn *client[CLIENTMAX+2];
- uint8_t state[CLIENTMAX+2];
- osThreadId client_taskid[CLIENTMAX+2];
- Controller_StatusDef realdatastatus[CLIENTMAX+2];
- }client_ad;
- client_ad clientad;
-
-
- uint8_t isIAPStart=0;
- uint16_t IAP_frameTotalCount=0;
- uint16_t IAP_frameCount=0;
- uint16_t IAP_frameSeq=0;
- uint16_t IAP_frameLength=0;
- uint16_t IAP_frameCRC=0x0000;
- uint8_t isIAPFinish=0;
- uint8_t isIAPSuccess=0;
-
- uint8_t NotUpgrade[4]={0xff,0xff,0xff,0xff};
- uint8_t Upgrade[4]={0xaa,0xaa,0xaa,0xaa};
-
- void svr_task(void const *arg);
- void processCmd(Controller_AckDataDef frame,Controller_AckDataDef* ackframe,uint8_t clientindex);
- osThreadDef(myTaskClient, tcp_server_thread, osPriorityNormal, CLIENTMAX, 1400);
-
- void MX_FREERTOS_Init(void) {
-
- osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 1024);
- defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
-
- osThreadDef(tcpmultiTask, svr_task, osPriorityNormal, 0, 1024);
- osThreadCreate(osThread(tcpmultiTask), NULL);
- clientad.state[CLIENTMAX]=1;
- clientad.realdatastatus[CLIENTMAX]=RealPass_Stop;
- comackframe.originaldata_data=comackdata;
- isCOMHasACK=0;
-
-
- }
- err_t client_init(void *arg,uint8_t* clientnumindex)
- {
- uint8_t clientnum; //?????? TCP client ????
- err_t err; //????(UCOSIII)
- uint8_t ifreceiveclient=0;
- for(clientnum=0;clientnum<CLIENTMAX;clientnum++) //???????????(????20????)
- {
- if(clientad.state[clientnum]==0) //???? clientnum ?????????0(???)
- {
-
- ifreceiveclient=1;
- break; //???? ???? ????????
- }
- }
- if(ifreceiveclient==0)
- {
- UsrLog("This no space to accept client");
- return 1;
- }
- *clientnumindex=clientnum;
- return ERR_OK; //??????
- }
-
- void svr_task(void const *arg)
- {
- err_t oserr;
- struct netconn *conn,*newconn;
- while(!isLWIPInitSuccess)
- osDelay(100);
-
-
- for(int i=0;i<CLIENTMAX;i++)
- {
- clientad.state[i]=0;
- clientad.realdatastatus[i]=RealPass_Stop;
- //clientad.iapstatus[i]=IAPStatus_app;
- }
- conn = netconn_new(NETCONN_TCP);
- netconn_bind(conn,IP_ADDR_ANY,sysParameterStruct._Para_ControlIP_PORT);
- netconn_listen(conn);
- sprintf((char*)iptxt, "%d", sysParameterStruct._Para_ControlIP_PORT);
- UsrLog("tcp start listen on port: %s",iptxt);
-
- while(1)
- {
- uint8_t clientnumindex=0;
- //if(get_clientindex(&clientnumindex) != ERR_OK)
- // osDelay(100);
- if(netconn_accept(conn,&newconn) == ERR_OK)
- {
- if(client_init((void *)newconn,&clientnumindex) != ERR_OK)
- {
- netconn_close(newconn);
- netconn_delete(newconn);
- }
- else
- {
-
- clientad.client[clientnumindex]=newconn;
- clientad.state[clientnumindex]=1;
- clientad.client_taskid[clientnumindex] = osThreadCreate(osThread(myTaskClient), (void *)clientnumindex);
- osDelay(100);
- if(clientad.client_taskid[clientnumindex]==NULL)
- {
- UsrLog("Failed to create the recv thread with id: %d",clientnumindex);
- }
- else
- {
- UsrLog("create the recv thread with id: %x",(int)(clientad.client_taskid[clientnumindex]));
- }
-
- }
- }
- osDelay(100);
- }
- }
- void tcp_server_thread(void const *arg)
- {
- err_t err;
- struct netbuf *clientrecvbuf;
- Controller_AckDataDef recvframe;
- Controller_AckDataDef ackframe;
- uint8_t recvdata[40];
- uint8_t ackdata[80];
- /*recv tcp data buf*/
- ackframe.originaldata_head=0x06;
- ackframe.originaldata_address=sysParameterStruct._Para_ControlEquiAddress;
- ackframe.originaldata_end=0x03;
- ackframe.originaldata_data=ackdata;
- ip_addr_t addr; u16_t port;
- uint8_t *app_flash_buf;
- /* get remote IP address and port*/
- uint8_t clientindex=(uint8_t)arg;
- if((err=netconn_getaddr(clientad.client[clientindex],&addr, &port, 0))==ERR_OK)
- {
- sprintf((char*)iptxt, "%d.%d.%d.%d:%d", (uint8_t)(addr.addr),(uint8_t)(addr.addr>>8),(uint8_t)(addr.addr>>16),(uint8_t)(addr.addr>>24),port);
- UsrLog("one client is connected:%s",iptxt);
- }
- uint8_t *data;
- u16_t len;
- while(1)
- {
- if((err=netconn_recv(clientad.client[clientindex],&clientrecvbuf))==ERR_OK)
- {
- do{
- netbuf_data(clientrecvbuf,&data,&len);
- //printf("recevie one frame: length=%d, data=0x%x--0x%x\r\n",len,data[0],data[len-1]);
- if(len>=6)
- {
- if(data[0]==0x02&&data[len-1]==0x03)
- {
- recvframe.originaldata_head=data[0];
- recvframe.originaldata_address=data[1];
- recvframe.originaldata_cmd=data[2];
- if(recvframe.originaldata_cmd==0x52)//app upload data frame:0x02 add 0x52 [frame seq] [frame len] {app data} cs 0x03
- {
- IAP_frameSeq=(uint16_t)((data[3]<<8)|data[4]);
- IAP_frameLength=(uint16_t)((data[5]<<8)|data[6]);
- app_flash_buf=data+7;
- printf("recevie one frame data: frame seq=%d, frame data length=%d\r\n",IAP_frameSeq,IAP_frameLength);
- uint8_t frameRight=1;
- if(isIAPStart)
- {
- if(IAP_frameSeq==IAP_frameCount&&IAP_frameSeq<IAP_frameTotalCount)
- {
- if(IAP_frameLength!=500)
- {
- printf("wrong frame length(%d), length should be 1000\r\n",IAP_frameLength);
- frameRight=0;
- }
- if(frameRight)
- {
- printf("valid frame data\r\n");
- uint32_t flashdestination=APP2_ADDRESS+500*IAP_frameSeq;
- MEM_IF_IniT();
- if (MEM_If_Write_Word(app_flash_buf,flashdestination,IAP_frameLength) == HAL_OK)
- {
- printf("write frame data seq(%d)(data:0x%x..) to flash(addr:0x%08x) success\r\n",IAP_frameSeq,*app_flash_buf,flashdestination);
- IAP_frameCount++;
- }
- else /* An error occurred while writing to Flash memory */
- {
- printf("write frame data seq(%d) to flash fail\r\n",IAP_frameSeq);
- frameRight=0;
- }
- MEM_IF_DeInit();
- }
- }
- else
- {
- frameRight=0;
- }
-
- }
- else
- {
- frameRight=0;
- }
- if(!frameRight)
- {
- printf("invalid frame data or process data fail\r\n");
- }
- uint8_t realdatalength=0;
- ackframe.originaldata_head=0x06;
- ackframe.originaldata_address=sysParameterStruct._Para_ControlEquiAddress;
- ackframe.originaldata_end=0x03;
- ackframe.originaldata_cmd=recvframe.originaldata_cmd;
- *(ackframe.originaldata_data+realdatalength)=IAP_frameSeq>>8;
- realdatalength++;
- *(ackframe.originaldata_data+realdatalength)=IAP_frameSeq;
- realdatalength++;
- *(ackframe.originaldata_data+realdatalength)=frameRight?0x06:0x15;
- realdatalength++;
- ackframe.originaldata_length=realdatalength;
- netconn_ack(&ackframe,clientad.client[clientindex]);
-
- }
- else
- {
- recvframe.originaldata_length=data[3];
- recvframe.originaldata_cs=data[len-2];
- recvframe.originaldata_end=data[len-1];
- if(recvframe.originaldata_length+6==len)
- {
- for(int i=0;i<recvframe.originaldata_length;i++)
- {
- recvdata[i]=data[4+i];
- }
- recvframe.originaldata_data=recvdata;
- processCmd(recvframe,&ackframe,clientindex);
- netconn_ack(&ackframe,clientad.client[clientindex]);
- continue;
- }
- }
- }
- }
- ackframe.originaldata_cmd=0xf3;
- ackframe.originaldata_length=0;
- netconn_ack(&ackframe,clientad.client[clientindex]);
- }
- while(netbuf_next(clientrecvbuf)>=0);
- netbuf_delete(clientrecvbuf);
- }
- else if(err==ERR_CLSD||err==ERR_RST)
- break;
- }
- if(clientad.state[clientindex]==1)
- {
- if((err=netconn_getaddr(clientad.client[clientindex],&addr, &port, 0))==ERR_OK)
- {
- sprintf((char*)iptxt, "%d.%d.%d.%d:%d", (uint8_t)(addr.addr),(uint8_t)(addr.addr>>8),(uint8_t)(addr.addr>>16),(uint8_t)(addr.addr>>24),port);
- UsrLog("one ramote is closed:%s",iptxt);
- }
- clientad.state[clientindex]=0;
- netconn_close(clientad.client[clientindex]);
- netconn_delete(clientad.client[clientindex]);
- vTaskDelete(clientad.client_taskid[clientindex]);
- }
- }
-
- void processCmd(Controller_AckDataDef frame,Controller_AckDataDef* ackframe,uint8_t clientindex)
- {
- //Controller_AckDataDef ackframe;
- ackframe->originaldata_head=0x06;
- ackframe->originaldata_address=sysParameterStruct._Para_ControlEquiAddress;
- ackframe->originaldata_end=0x03;
- ackframe->originaldata_cmd=frame.originaldata_cmd;
- ackframe->originaldata_length=0;
- uint8_t *databuf=ackframe->originaldata_data;
- uint8_t realdatalength=0;
- switch(frame.originaldata_cmd)
- {
- case 0x51://start download app
- printf("start download app\r\n");
- IAP_frameTotalCount=(uint16_t)(frame.originaldata_data[0] << 8 | frame.originaldata_data[1]);
- printf("app frames total count is %d\r\n",IAP_frameTotalCount);
- MEM_IF_IniT();
- if(MEM_If_Erase(APP2_ADDRESS,APP2_ADDRESS_END)!=HAL_OK)
- {
- printf("erase flash fail, abort app downloading\r\n");
- isIAPStart=false;
- *(databuf+realdatalength)=0x15;
- realdatalength++;
- ackframe->originaldata_length=realdatalength;
- }
- else
- {
- printf("erase flash from %#x to %#x, wait for frame transmitting\r\n",APP2_ADDRESS,APP2_ADDRESS_END);
- IAP_frameCount=0;
- isIAPStart=true;
- *(databuf+realdatalength)=0x06;
- realdatalength++;
- ackframe->originaldata_length=realdatalength;
- }
- MEM_IF_DeInit();
- break;
- case 0x53://finish download app
- printf("finish download app\r\n");
- uint16_t IAP_crc16=(uint16_t)(frame.originaldata_data[0] << 8 | frame.originaldata_data[1]);
- printf("receive app crc16 is %x\r\n",IAP_crc16);
-
- if(1)//(IAP_crc16==IAP_frameCRC)
- {
- printf("pass crc check, finish download app\r\n");
- MEM_IF_IniT();
- MEM_If_Erase(UPGRADE_ADDRESS,UPGRADE_ADDRESS);
- MEM_If_Write_Byte(Upgrade,UPGRADE_ADDRESS,sizeof(Upgrade));
- MEM_IF_DeInit();
-
- *(databuf+realdatalength)=0x06;
- realdatalength++;
- ackframe->originaldata_length=realdatalength;
- isIAPStart=false;
- }
- else
- {
- printf("crc check fail, finish download app\r\n");
- *(databuf+realdatalength)=0x15;
- realdatalength++;
- ackframe->originaldata_length=realdatalength;
- isIAPStart=false;
- }
- break;
- case 0x5f:
- printf("receive abort download app command\r\n");
- isIAPStart=false;
- IAP_frameCount=0;
- break;
- /*
- other cmd process...
- */
- default:break;
- }
- }
3. 上位机实现升级工具(C# winform)
4. 实现效果
升级工具通过TCP与板卡进行通讯,之前版本是V20.2024.3
打开升级程序包bin文件
点击下载
开始下载,显示整片程序被分成399个包
下载完成,提示重启板卡完成升级
重启后,开始将程序从APP2拷贝到APP1
拷贝完成,跳转到APP1运行,程序已经更新成V20.2024.4
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。