STM32 IAP升級固件 + 上位機 例程

本例程實現功能:

1、IAP固件程序實現固件APP搬移,跳轉至APP

2、APP固件程序實現自定義功能,接收上位機下發的bin文件

3、上位機加載APPbin文件,分割下發至APP固件程序(本例程使用QT開發)

一、IAP升級簡單介紹

基本原理不做贅述,參見:https://blog.csdn.net/wzy15965343032/article/details/88545225

兩種方式:

方式1:  IAP固件直接接收上位機下發的程序,將程序寫入APP區域,完成後跳轉至APP部分。這種方法正點原子有相應的例程;

方式2:

FALSH區域分爲4部分:IAP區、APP運行區、APP下載區、參數區域

1、IAP部分檢測APP程序是否有更新,有更新需從APP下載區搬運程序至APP運行區,完成後跳轉至APP區域;如無更新,直接跳轉。

2、APP區域負責運行程序主流程,如是APP升級數據包,則將此包寫入APP下載區,同時更新參數區升級標誌

3、APP下載區主要存放更新程序

4、參數區域存放升級標誌以及其他參數

本例程採用方式二升級

二、固件程序

STM32F103CBT6芯片使用HAL庫開發

1、flash區域劃分

分區 大小 扇區 地址
IAP 10k 0-9 0x08000000-0x080027FF
APP運行區 58k 10-57 0x08002800-0x08010FFF
APP下載區 58k 58-126 0x08011000-0x0801F7FF
參數區 2k 127-128 0x0801F800-0x0801FFFF

2、IAP程序開發

根據需求,IAP程根據參數區標誌位判定是否要升級,只需要完成flash讀寫即可,爲方便調試附帶串口打印功能;

跳轉APP部分程序一爲固定代碼,如下程序流程圖如下:

程序例程:

//跳轉到應用程序段
//ulAddr_App:APP運行區地址.
void IAP_ExecuteApp ( uint32_t ulAddr_App )
{
    pIapFun_TypeDef pJump2App;
    //檢查棧頂地址是否合法.
    if ( ( ( * ( __IO uint32_t * ) ulAddr_App ) & 0x2FFE0000 ) == 0x20000000 )    
    {
         pJump2App = ( pIapFun_TypeDef ) * ( __IO uint32_t * ) ( ulAddr_App + 4 );    
         //用戶代碼區第二個字爲程序開始地址(復位地址)        
         MSR_MSP( * ( __IO uint32_t * ) ulAddr_App );
         //初始化APP堆棧指針(用戶代碼區的第一個字用於存放棧頂地址)
         pJump2App ();                                                                        
         //跳轉到APP.
    }
}       

void IAP_Copy_App(void)
{
    uint8_t i;
    uint8_t buf[2] = {0x96,0x69};
    //擦除App扇區
    Flash_EraseSector(10,67);
    
    for(i = 0;i < 58;i++)
    {
         FLASH_ReadPage(68 + i,FLASH_BUFF);
         HAL_Delay(10);
         FLASH_WritePage(10 + i,FLASH_BUFF);
    }
    
    FLASH_WriteNData(FLASH_APP_UPTADE,buf,2);
}

int main(void)
{

  /* USER CODE BEGIN 1 */
  /* 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_DMA_Init();
  MX_USART3_UART_Init();
  /* USER CODE BEGIN 2 */
  USER_UART_Init();
  /* USER CODE END 2 */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
        HAL_Delay(100);
      printf("IAP start\r\n");    
   while(1){
           uint16_t ret = FLASH_ReadHalfWord(FLASH_APP_UPTADE);
           printf("update = %04x \n",ret);    
       if(ret == UPTADE_FALG)
       {
           printf("Updata App...\r\n");
               IAP_Copy_App();
           printf("Updata App Succeed...\r\n");
       }
       IAP_ExecuteApp(FLASH_APP_START);
     }
  /* USER CODE END 3 */
}

 

3、APP程序開發

APP程序需要:1、flash讀寫;2、串口接收,發送;3、中斷向量表重定義;4、程序重啓

程序主流程:串口接收數據包(1024byte)直接寫入flash(58扇區開始,往後寫),爲方便方便理解移植,本demo接收16K文件然後重啓。(正式版本可以通過通信協議控制

void IAP_WriteBin(int ii,uint8_t *pBuff,uint32_t Len)
{
    uint8_t buf[2] = {0xAA,0x55};
    //擦除DOWNLOAD扇區
    Flash_EraseSector(68+ii,68+ii+1);
    //寫入程序
    FLASH_WritePage(68+ ii,pBuff);
    if (ii > 15){
          //更新標記
          FLASH_WriteNData(FLASH_APP_UPTADE,buf,2);
          //復位單片機
         NVIC_SystemReset();
     }
}


void cmdProcess()
{
    if(g_rx232_end_flag == 1)
    {        
        IAP_WriteBin(current,g_rx232_buffer,g_rx232_len);
              current ++;
                HAL_Delay(10);
              memset(g_rx232_buffer,0,g_rx232_len);/*清接收緩存 */
              g_rx232_len=0;                       /*清除計數 */
        g_rx232_end_flag=0;                  /*清除接收結束標誌位*/
        HAL_UART_Receive_DMA(&huart3,g_rx232_buffer,BUFFER_SIZE);/*重新打開DMA接收*/
    }
    
        if(g_rx485_len)
    {        
              IAP_WriteBin(current,g_rx232_buffer,g_rx232_len);
              current ++;
               HAL_Delay(10);
               memset(g_rx485_buffer,0,g_rx485_len);/*清接收緩存 */
              HAL_UART_Receive_DMA(&huart1,g_rx485_buffer,BUFFER_SIZE);
              g_rx485_len = 0;
    }
}

三、上位機程序

使用QT進行開發

1、加載BIN文件

2、串口操作

3、程序分割下載(1024字節bin文件數據包)

void MainWindow::on_pushButton_loadfile_clicked()
{            
       QString fileName=QFileDialog::getOpenFileName(this,QString::fromLocal8Bit("bin file"),qApp->applicationDirPath(),

    QString::fromLocal8Bit("bin File(*.bin)"));//新建文件打開窗口
     if (fileName.isEmpty())//如果未選擇文件便確認,即返回
    return;

     QFile file(fileName);
     if(!file.open(QIODevice::ReadOnly)
     ui->label_filepath->setText(file.errorString());//文件打開錯誤顯示錯誤信息
     arry=file.readAll();//讀取文件
     ui->label_filepath->setText(fileName);
     ui->textEdit_3->append(arry.toHex());
     qDebug()<<arry.length();
     file.close();
}

void MainWindow::on_pushButton_download_clicked()

 {

     if (arry.length() <= 0){

         qDebug()<<"part num = 0 ";

         return;

     }


     unsigned char temp[1200];

     unsigned char crc[2];

     QString string;

     int j = 0;

     QByteArray partbuff;

     partbuff.resize(1200);

     partbuff.clear();

     upgrade.sum_part = arry.length()/1024;

     for(int i = 1 ;i <= upgrade.sum_part; i++)

     {

         partbuff.clear();

         partbuff.append(arry.mid(j,1024));

         memcpy( temp,partbuff,1024);

         myCom->write(partbuff,1024);

         delay_MSec(3000);

         //升級判定返回

         ui->progressBar->setValue(0);

         j = j + 1024;

         string = "\n" + QString::number(i) + "\n" +partbuff.toHex() +ui->textEdit_4->toPlainText();

         ui->textEdit_4->clear();

         ui->textEdit_4->setText(string);

         delay_MSec(100);

     }

 }

本例程源碼:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章