STM32的IAP设计(一)bootloader设计

    稍微复杂一点的电子产品,程序中都设计有bootloader,有bootloader的好处是:烧写程序以后,如果发现了新的BUG或者用户增加、修改需求,就可以在不拆壳子(产品出厂一般都是用环氧树脂密封固化)的情况下,通过预留的通信口给产品升级。再有产品到用户手里后,程序进行了升级,那我们可以将新程序的.bin文件发送给用户,让用户自己升级,从而避免了返厂的费用。

    IAP即在应用编程,需要为STM32程序设计一个bootloader,在此bootloader中,要设计进入bootloader下载的触发条件,并且设计通信端口协议,如串口、网口、SD卡等等,将接收到的bin文件烧写到内部的flash中。以前设计过的激光车检器的bootloader,为modbus协议,用在了山海路限高杆上;本程序是串口TTL通信协议,设计用于电喷ECU中的bootloader,已测试并量产。

    硬件平台是STM32F103RCT6,为STM32F10X_HD类型,FLash:256K,RAM:48K,Flash每2K一个扇区。本程序是在ST官方IAP程序AN2557的基础上修改优化而来的。ST官方程序是:刚上电检测外部按键是否按下,如果按下,则进入程序升级代码,使用Ymodem协议传输.bin文件。我们程序进入IAP升级的方法上电后长按键盘c,程序在200ms内检测字符c,如果200ms内按下c,则进入下一个500ms检测,如果没有按下,则判断是否有应用程序,如果有,则跳转到应用程序执行。这里为何前一个是200ms?因为在APP程序中设计有看门狗复位,如果看门狗复位后bootloader等待时间过长,则发动机在转速比较低的情况下容易因为看门狗复位而熄火,所以实测200ms看门狗不会熄火,而且在按键盘c触发IAP升级,人的手速也来得及,不受影响。

    若改为MD或者LD类型,则在option里面选择相应型号的芯片,启动文件更换相应的启动文件(有ld、md、hd),宏定义里使用STM32F10X_LD或者STM32F10X_MD。    

    RAM使用总48K, 即:0x20000000 ———— 0x2000C000
    Flash使用前64K,即:0x8000000 ———— 0x8010000

    配置如图1、图2,则bootloader使用flash的前64K,注意图2是要必须选择的,尤其在APP程序中,如果不选的话,APP生成的.bin文件是从flash起始地址开始的。

         

                                                                                                               图1
         

                                                                                                                 图2

主函数如下,上电后首先执行startup.s文件,初始化堆栈、PC指针然后进入上电复位程序,最终跳转到main()函数中。

#include "include.h"


volatile uint32_t cnt_ms;

/**
  * @brief  Main program.
  * @param  None
  * @retval None
  */
int main(void)
{  
    char recv_data;    
    volatile uint8_t state;
    
    RCC_Configuration();                       //init system clock,72MHz
                                                                                 
    FLASH_Unlock();                            //Flash unlock 
                                                                                 
    IAP_Init();                                //USART1 初始化
    
    delay_init();  
    SysTick->CTRL |=  SysTick_CTRL_ENABLE_Msk; //使能滴答定时器
    
   //开机0.2S内是否接收到字符c,如果没接收到,则执行应用程序
   //如果接收到字符c,则判断下个0.5S是否能接收到c,如果接收到
   //字符c,则进入bootloader升级程序,否则跳转到应用程序    
    cnt_ms = 200;                     
    while(cnt_ms)
      {
         if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET)
           {
             recv_data = USART_ReceiveData(USART1);
             USART_ClearFlag(USART1, USART_FLAG_RXNE);
                    
             if('c' == recv_data)
               {
                 break;
               }                        
           }                    
      }
    
    if(cnt_ms)  //前0.2内接收到字符c,则继续判断下一个0.5S内是否接收到字符c    
      {
        cnt_ms = 500;
        USART_ClearFlag(USART1, USART_FLAG_RXNE);
        while(cnt_ms)
          {
            if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET)
              {
                  recv_data = USART_ReceiveData(USART1);
                  USART_ClearFlag(USART1, USART_FLAG_RXNE);
                    
                  if('c' == recv_data)
                    {
                      break;
                    }
               }                    
          }     
        state = (cnt_ms > 0) ? 1:0;                
      }
    else      //前0.5内没有接收到字符c,则跳转到应用程序  
      {
        state = 0;
      }
        
    if(state) //Execute the IAP driver in order to re-program the Flash 
    { 
      SerialPutString("\r\n======================================================================");
      SerialPutString("\r\n=  (C) COPYRIGHT 2020 ShanDong ***** Aviation Engine Co., Ltd.       =");
      SerialPutString("\r\n=                                                                    =");
      SerialPutString("\r\n=  In-Application Programming Application  (Version 1.0.0)           =");
      SerialPutString("\r\n=                                                                    =");
      SerialPutString("\r\n=  By Yuan Anbin R & D Team                                          =");
      SerialPutString("\r\n======================================================================");            
      SerialPutString("\r\n\r\n");
      Main_Menu();
    }
  else      //Keep the user application running
    {
      //Test if user code is programmed starting from address "ApplicationAddress" 
      if(((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)//检查栈顶地址是否合法,即检查此段Flash中是否已有APP程序
        { 
          //Jump to user application
          __disable_irq();                                         //关闭总中断
                    
          JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);//取得APP代码区第二个字    
          Jump_To_Application = (pFunction) JumpAddress;           //将APP代码区第二个字强制转换,即取得复位中断函数地址
          
          __set_MSP(*(__IO uint32_t*) ApplicationAddress);         //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
                              
          Jump_To_Application();                                   //跳转到APP复位中断函数,从而进入APP的main()执行
        }
    }

  while(1)
    {
         
    }
}

 

定时中断服务函数在stm32f10x_it.c文件中,如下:

/**
  * @brief  This function handles SysTick Handler.
  * @param  None
  * @retval None
  */
extern volatile uint32_t cnt_ms;     

void SysTick_Handler(void)                 //1ms定时中断
{
    if(cnt_ms != 0x00)
      { 
          cnt_ms--;
      }    
}

 

 

  

 

posted @ 2020-11-11 15:54  星元的天空  阅读(974)  评论(0编辑  收藏  举报