An article to get the virtual serial port IAP

    在上一篇博客中我提到了STM32F407+虚拟串口在线升级的基本原理,这一篇我讲一下关于一些,在虚拟串口在线升级的代码和注意的一些细节。
    在线升级原理不清楚的请移步参考上一篇[我用一张图了解虚拟串口IAP](https://blog.csdn.net/cs111211/article/details/105142049)

1. Upgrade code explanation

  1)拷贝app代码到flash。
void STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite) 
{ 
  FLASH_Status status = FLASH_COMPLETE;
 u32 addrx=0;
 u32 endaddr=0; 
  if(WriteAddr<STM32_FLASH_BASE||WriteAddr%4)return; //非法地址
 FLASH_Unlock();         //解锁
  FLASH_DataCacheCmd(DISABLE);//FLASH擦除期间禁止数据缓存。
   
 addrx=WriteAddr;    //写入起始地址
 endaddr=WriteAddr+NumToWrite*4; //写入结束地址
 if(addrx<0X1FFF0000)   //只有主存储区才执行擦除操作 !
  while(addrx<endaddr)  //对非0xFF的地方先擦除
   if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF)//擦除非0XFFFFFFFF地方
   {   
    status=FLASH_EraseSector(STMFLASH_GetFlashSector(addrx),VoltageRange_3);//VCC=2.7~3.6V之间
    if(status!=FLASH_COMPLETE)break; //发生错误了
   }else addrx+=4;
  } 
 }
 if(status==FLASH_COMPLETE)
 {
  while(WriteAddr<endaddr)//写数据
  {
   if(FLASH_ProgramWord(WriteAddr,*pBuffer)!=FLASH_COMPLETE)//写入数据
   { 
    break; //写数据异常
   }
   WriteAddr+=4;
   pBuffer++;
  } 
 }
  FLASH_DataCacheCmd(ENABLE); //FLASH擦除结束,开启数据缓存
   FLASH_Lock();//上锁
} 

u32 iapbuf[512];  //缓冲
void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 appsize)
{
 u32 t;
 u16 i=0;
 u32 temp;
 u32 fwaddr=appxaddr;//写入当前的地址
 u8 *dfu=appbuf;
 for(t=0;t<appsize;t+=4)
 {         
  temp=(u32)dfu[3]<<24;   
  temp|=(u32)dfu[2]<<16;    
  temp|=(u32)dfu[1]<<8;
  temp|=(u32)dfu[0];   
  dfu+=4;//偏移4个地址
  iapbuf[i++]=temp;     
  if(i==512)
  {
   i=0; 
   STMFLASH_Write(fwaddr,iapbuf,512);
   fwaddr+=2048;//偏移2048  512*4=2048
  }
 } 
 if(i)STMFLASH_Write(fwaddr,iapbuf,i);// 
}

2) How to use the code The
above part of the code is a method to write the app to the specified area of ​​FLASH. You need to add the flash library to the project in the project.
That is stm32f4xx_flash.c.
These functions are used to write apps, we need to call the interface is void iap_write_appbin (u32 appxaddr, u8 * appbuf, u32 appsize). There are three input parameters:

  1. appxaddr: is the specified address written to flash. For specific addresses that can be written, please refer to my initial writing address. I wrote the top address of the app stack. #define FLASH_APP1_ADDR 0x08010000 this address. Because the boot program is not too big, we reserve 64k of memory for the boot program, which is 0x10000. The starting address of the flash is 0x08000000, so the starting address of the first app is 0x080000000 + 0x10000 = 0x08010000. Of course, you can download multiple apps to flash. (As long as the FLASH memory is enough) You can check the address of the flash sector in the chip data sheet where you can store the app.
  2. appbuf: is the buffer of the app program, which is the code of the app ()
  3. appsize: the size of the app program (bytes)

2. Jump code and points of attention

First go to the code and go to the app program

void iap_load_app(u32 appxaddr)
{
if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000) //检查栈顶地址是否合法
{
 __disable_irq();//关闭所有中断
 RCC_AHB2PeriphResetCmd(RCC_AHB2Periph_OTG_FS, ENABLE); 
 RCC_AHB2PeriphResetCmd(RCC_AHB2Periph_OTG_FS, DISABLE); //复位USB OTG
 TIM_Cmd(TIM3,DISABLE);//定时器失能
 jump2app=(iapfun)*(vu32*)(appxaddr+4);  //代码区第二个字是程序开始地址(复位地址) 
 MSR_MSP(*(vu32*)appxaddr);     //初始化app堆栈指针(第一个字用于存放栈顶地址)
   jump2app();         //转跳到app
}
}   

The above code is the code that jumps to the application. Here is a point.
1) Turn off all interrupts
Before jumping to the app , turn off all interrupts that have been turned on. Because the upgrade is only powered on once, if the interrupt is not turned off, nothing will change in the interrupt register. After jumping to the app program, the interrupt is still there, but the interrupt function is gone. The program does not know where the interrupt came from, so it will cause the program to freeze. So use __disable_irq (); // Turn off all interrupts
2) Disabled peripherals
that have been turned on are similar to the previous point, because the timer and usb virtual serial port are used in my bootloader program, and the app program Timers and virtual serial ports are also used. So if you can use these peripherals in the app normally, you must disable these peripherals before jumping, and the way to disable the peripherals is to disable its clock.
RCC_AHB2PeriphResetCmd (RCC_AHB2Periph_OTG_FS, ENABLE);
RCC_AHB2PeriphResetCmd (RCC_AHB2Periph_OTG_FS, DISABLE); // These two sentences are reset USB OTG
TIM_Cmd (TIM3, DISABLE); // It is the timer disabled.
3) Implement
jump2app = (iapfun) (vu32 ) (appxaddr + 4); This sentence corresponds to the second item in the app interrupt vector table, and the reset address is forced to be converted into a function pointer
MSR_MSP ( (vu32 ) appxaddr); // Initializing the app stack pointer (the first word is used to store the top address of the stack)
is to set the main function stack pointer.
The last sentence jump2app (); // Jump to app call function, go to app reset address to perform reset operation

3. How to generate app

1) Set the top address of the stack. The
APP program adds this sentence
SCB-> VTOR = 0x8000000 | 0X10000 after the definition of the main function variable ;
this sentence means that the top address of the app stack is 0x08010000. Similarly, other addresses can be set.
2) Set add
in the target option in target for options to edit according to the following figure. The address after the first box after IROM1 is changed to 0x08010000. This address is the start address of the app, and the second box is changed to 0xf0000. It is the size of the app program. The flash I use here is 1m, so size = 1M-64k = 0xf0000. The content in these two boxes must be an integer multiple of 0x400.
Insert picture description here
4) After generating the bin file
After setting the address, we need something to convert the program into a bin file. This function can be implemented in keilv5. First find the path of fromelf.exe, and then find the file name in your output. My project here is USART, and then a file with a suffix of .axf will be generated after compilation.
Insert picture description here
Then
Insert picture description here
tick the Run # 1 in the user option, and fill in a path in the following format in the following box E: \ MDK5 \ ARM \ ARMCC \ bin \ fromelf.exe --bin -o… \ OBJ \ USART.bin… \ OBJ \ USART.AXF is in
front of the path fromelf.exe \ --bin -o… \ OBJ \ USART.bin… \ OBJ \ USART.AXF
Then click ok, click compile and the following prompt appears in the output area indicating that the bin file was successfully generated. You can find the file USART.bin in the OBJ folder.
Insert picture description here

4. Some points of attention of the app program

1. To turn on the interrupt in the app, you need to turn on the interrupt and initialize the peripherals used to enable the corresponding peripheral clock at the beginning of mian.
2. The path in the user must be entered correctly or an error will be reported. Mine is in the path of E: \ MDK5 \ ARM \ ARMCC \ bin \ fromelf.exe, this will be different according to the location of your MDK installation.
3. Be sure to add SCB-> VTOR = 0x8000000 | 0X10000; in the program. Otherwise, the code will not run after the upgrade.

Published 3 original articles · Likes2 · Visits 112

Guess you like

Origin blog.csdn.net/cs111211/article/details/105533524