- STM32CubeMx開發之路—在線升級OTA(1/4)—基礎知識
- STM32CubeMx開發之路—在線升級OTA(2/4)—BootLoader
- STM32CubeMx開發之路—在線升級OTA(3/4)—App
- STM32CubeMx開發之路—在線升級OTA(4/4)—測試
- STM32CubeMx開發之路—在線升級OTA—(另一種思路)
運行環境
Windows10
STM32CubeMX
Version 5.4.0
Keil5(MDK5)
Version 5.28.0.0
硬件開發板
F103RB-NUCLEO
簡介
本例程主要講解在線升級(OTA)的App1
的編寫以及整個流程的說明.我將以我例程的App爲例, 採用Ymodem協議進行串口傳輸,講解App
的編寫(後面會提供免費的代碼下載鏈接), 其他的協議原理大體上都差不多, 都是通過某種協議拿到升級的代碼.
流程圖分析
以我歷程的App1爲例:
- 先修改向量表, 因爲本程序是由BootLoader跳轉過來的, 不修改向量表後面會出現問題.
- 打印版本信息, 方便查看不同的App版本
- 本例程的升級程序採用串口的Ymoderm協議進行傳輸bin文件. 具體的流程圖見下圖所示
程序編寫和分析
所需STM32的資源有:
- printf的使用, 詳情可參考 STM32CubeMx開發之路—3發送USART數據和printf重定向
- Flash的讀寫, 詳情可參考 STM32CubeMX開發之路—8Flash讀寫
- 串口的DMA收發, 詳情可參考 STM32CubeMx開發之路—4採用DMA方式收發數據
- YModem協議相關的, 詳情可參考 YModem介紹
Ymodem協議
- 百度百科Ymodem協議
- 具體流程可自行查找相關文檔, 這兒提供一個我找到的 XYmodem.pdf.
- Ymodem協議相關介紹可參考我的這篇教程 YModem介紹.
代碼分析
-
代碼大多數都是通過串口實現Ymodem協議的接收, 這兒就不詳細說明
-
後面放了我的源代碼, 詳情請參考我的源代碼.
-
主函數添加修改向量表的指令
- 打印版本信息以及跳轉指令
- YModem相關的文件接收部分
/**
* @bieaf YModem升級
*
* @param none
* @return none
*/
void ymodem_fun(void)
{
int i;
if(Get_state()==TO_START)
{
send_command(CCC);
HAL_Delay(1000);
}
if(Rx_Flag) // Receive flag
{
Rx_Flag=0; // clean flag
/* 拷貝 */
temp_len = Rx_Len;
for(i = 0; i < temp_len; i++)
{
temp_buf[i] = Rx_Buf[i];
}
switch(temp_buf[0])
{
case SOH:///<數據包開始
{
static unsigned char data_state = 0;
static unsigned int app2_size = 0;
if(Check_CRC(temp_buf, temp_len)==1)///< 通過CRC16校驗
{
if((Get_state()==TO_START)&&(temp_buf[1] == 0x00)&&(temp_buf[2] == (unsigned char)(~temp_buf[1])))///< 開始
{
printf("> Receive start...\r\n");
Set_state(TO_RECEIVE_DATA);
data_state = 0x01;
send_command(ACK);
send_command(CCC);
/* 擦除App2 */
Erase_page(Application_2_Addr, 40);
}
else if((Get_state()==TO_RECEIVE_END)&&(temp_buf[1] == 0x00)&&(temp_buf[2] == (unsigned char)(~temp_buf[1])))///< 結束
{
printf("> Receive end...\r\n");
Set_Update_Down();
Set_state(TO_START);
send_command(ACK);
HAL_NVIC_SystemReset();
}
else if((Get_state()==TO_RECEIVE_DATA)&&(temp_buf[1] == data_state)&&(temp_buf[2] == (unsigned char)(~temp_buf[1])))///< 接收數據
{
printf("> Receive data bag:%d byte\r\n",data_state * 128);
/* 燒錄程序 */
WriteFlash((Application_2_Addr + (data_state-1) * 128), (uint32_t *)(&temp_buf[3]), 32);
data_state++;
send_command(ACK);
}
}
else
{
printf("> Notpass crc\r\n");
}
}break;
case EOT://數據包開始
{
if(Get_state()==TO_RECEIVE_DATA)
{
printf("> Receive EOT1...\r\n");
Set_state(TO_RECEIVE_EOT2);
send_command(NACK);
}
else if(Get_state()==TO_RECEIVE_EOT2)
{
printf("> Receive EOT2...\r\n");
Set_state(TO_RECEIVE_END);
send_command(ACK);
send_command(CCC);
}
else
{
printf("> Receive EOT, But error...\r\n");
}
}break;
}
}
}
- 其中部分函數未在以上代碼中展現, 詳情請參看下面的源代碼(免費).
源碼
App1源代碼
STM32F103rb_App1.zip
備註:提供一下個人微信號 Hleafleafleaf,歡迎加好友,共同學習!共同進步!