本帖最后由 xld0932 于 2023-2-27 21:49 编辑
IAP应用程序升级是最常用的技术了,也有很多开源的IAP程序框架,比如OpenBLT、mOTA等等,本文我们来基于对MCU内部FLASH读、写、擦除这3个基础操作,结合XMODEM传输协议来完成一个简易的IAP应用程序升级功能……首先我们需要有2个工程,一个是BOOTLOADER工程,它的作用是XMODEM协议传输、FLASH数据写入、以及程序跳转运行;另一个就是我们的应用程序工程,它是具体的应用……对不同的工程,我们需要有不同的配置……
BOOTLOADER工程:
XMODEM传输协议的实现:
- /*!
- * [url=home.php?mod=space&uid=247401]@brief[/url] Xmodem_SendData
- *
- * @param None
- *
- * @retval None
- *
- */
- void Xmodem_SendData(uint8_t Data)
- {
- USART_TxData(USART1, Data);
- while (RESET == USART_ReadStatusFlag(USART1, USART_FLAG_TXBE))
- {
- }
- }
- /*!
- * [url=home.php?mod=space&uid=247401]@brief[/url] Xmodem_CalcCheckCRC
- *
- * @param Buffer & Length
- *
- * @retval Result
- *
- */
- uint16_t Xmodem_CalcCheckCRC(uint8_t *Buffer, uint16_t Length)
- {
- uint32_t Result = 0;
- Length += 2;
- while (Length--)
- {
- uint8_t Value = (Length < 2) ? 0 : *Buffer++;
- for (uint8_t j = 0; j < 8; j++)
- {
- Result <<= 1;
- if (Value & 0x00080)
- {
- Result += 0x0001;
- }
- Value <<= 1;
- if (Result & 0x10000)
- {
- Result ^= 0x1021;
- }
- }
- }
- Result &= 0xFFFF;
- return (Result);
- }
- /*!
- * [url=home.php?mod=space&uid=247401]@brief[/url] Xmodem_CalcCheckSum
- *
- * @param Buffer & Length
- *
- * @retval Result
- *
- */
- uint8_t Xmodem_CalcCheckSum(uint8_t *Buffer, uint16_t Length)
- {
- uint16_t Result = 0;
- while (Length--)
- {
- Result += *Buffer++;
- }
- Result &= 0xFF;
- return (Result);
- }
- /*!
- * [url=home.php?mod=space&uid=247401]@brief[/url] Xmodem_RxHandler
- *
- * @param None
- *
- * @retval None
- *
- */
- void Xmodem_RxHandler(void)
- {
- uint32_t Address = (0x08000000 + 0x10000);
- uint32_t StartTryTimtout = 0;
- QUEUE_INIT();
- Xmodem_State = XMODEM_RX_STATE_SOH;
- while (1)
- {
- if (QUEUE_EMPTY() == 0)
- {
- uint8_t data = QUEUE_READ();
- switch (Xmodem_State)
- {
- case XMODEM_RX_STATE_SOH:
- if ((data == XMODEM_SOH) || (data == XMODEM_STX))
- {
- Xmodem_Length = (data == XMODEM_STX) ? 1024 : 128;
- Xmodem_Index = 0;
- Xmodem_State = XMODEM_RX_STATE_NUM;
- }
- else if (data == XMODEM_EOT)
- {
- Xmodem_SendData(XMODEM_ACK);
- printf("\r\nXmodem Finish");
- return;
- }
- else if (data == XMODEM_CAN)
- {
- printf("\r\nXmodem Cancle");
- return;
- }
- else
- {
- }
- break;
- case XMODEM_RX_STATE_NUM:
- Xmodem_Number[Xmodem_Index++] = data;
- if (Xmodem_Index == 2)
- {
- Xmodem_Index = 0;
- Xmodem_State = XMODEM_RX_STATE_DAT;
- }
- break;
- case XMODEM_RX_STATE_DAT:
- Xmodem_Buffer[Xmodem_Index++] = data;
- if (Xmodem_Index == Xmodem_Length)
- {
- Xmodem_Index = 0;
- Xmodem_State = XMODEM_RX_STATE_CHK;
- }
- break;
- case XMODEM_RX_STATE_CHK:
- Xmodem_CheckData[Xmodem_Index++] = data;
- if ((Xmodem_CheckType == 1) && (Xmodem_Index == 1))
- {
- Xmodem_Index = 0;
- if (Xmodem_Number[0] == ((Xmodem_Number[1] ^ 0xFF) & 0xFF))
- {
- if (Xmodem_CheckData[0] == Xmodem_CalcCheckSum(Xmodem_Buffer, Xmodem_Length))
- {
- if ((Address % FLASH_PAGE_SIZE) == 0)
- {
- FLASH_ErasePage(Address / FLASH_PAGE_SIZE);
- }
- FLASH_PageProgram(Address, Xmodem_Buffer, Xmodem_Length);
- Address += Xmodem_Length;
- Xmodem_SendData(XMODEM_ACK);
- }
- else
- {
- Xmodem_SendData(XMODEM_NAK);
- }
- }
- else
- {
- Xmodem_SendData(XMODEM_NAK);
- }
- Xmodem_State = XMODEM_RX_STATE_SOH;
- }
- else if ((Xmodem_CheckType == 0) && (Xmodem_Index == 2))
- {
- Xmodem_Index = 0;
- if (Xmodem_Number[0] == ((Xmodem_Number[1] ^ 0xFF) & 0xFF))
- {
- uint16_t Result = 0;
- Result = Xmodem_CheckData[0];
- Result <<= 8;
- Result |= Xmodem_CheckData[1];
- if (Result == Xmodem_CalcCheckCRC(Xmodem_Buffer, Xmodem_Length))
- {
- if ((Address % FLASH_PAGE_SIZE) == 0)
- {
- FLASH_ErasePage(Address / FLASH_PAGE_SIZE);
- }
- FLASH_PageProgram(Address, Xmodem_Buffer, Xmodem_Length);
- Address += Xmodem_Length;
- Xmodem_SendData(XMODEM_ACK);
- }
- else
- {
- Xmodem_SendData(XMODEM_NAK);
- }
- }
- else
- {
- Xmodem_SendData(XMODEM_NAK);
- }
- Xmodem_State = XMODEM_RX_STATE_SOH;
- }
- else
- {
- /* do nothing */
- }
- break;
- default:
- break;
- }
- }
- else
- {
- if (StartTryTimtout == 0)
- {
- if (Xmodem_CheckType)
- {
- Xmodem_SendData(XMODEM_NAK);
- }
- else
- {
- Xmodem_SendData('C');
- }
- }
- StartTryTimtout = (StartTryTimtout + 1) % XMODEM_TRY_TIMEOUT;
- }
- }
- }
FLASH读、写、擦除操作:
- /*!
- * @brief Xmodem_FLASH_ErasePage
- *
- * @param Page
- *
- * @retval None
- *
- */
- void FLASH_ErasePage(uint32_t Page)
- {
- FMC_Unlock();
- FMC_ClearStatusFlag((FMC_FLAG_T)(FMC_FLAG_OC | FMC_FLAG_PE | FMC_FLAG_WPE));
- FMC_ErasePage(FLASH_PAGE_SIZE * Page);
- FMC_ClearStatusFlag(FMC_FLAG_OC);
- FMC_Lock();
- }
- /*!
- * @brief Xmodem_FLASH_PageProgram
- *
- * @param Address & Buffer & Length
- *
- * @retval None
- *
- */
- void FLASH_PageProgram(uint32_t Address, uint8_t *Buffer, uint32_t Length)
- {
- uint16_t *Data = (uint16_t *)Buffer;
- FMC_Unlock();
- FMC_ClearStatusFlag((FMC_FLAG_T)(FMC_FLAG_OC | FMC_FLAG_PE | FMC_FLAG_WPE));
- for (uint32_t i = 0; i < Length; i += 2)
- {
- FMC_ProgramHalfWord(Address + i, *Data);
- FMC_ClearStatusFlag(FMC_FLAG_OC);
- if (*(volatile uint16_t *)(Address + i) != *Data)
- {
- while (1)
- {
- GPIO_WriteBitValue(GPIOE, GPIO_PIN_5, BIT_RESET);
- GPIO_WriteBitValue(GPIOE, GPIO_PIN_6, BIT_RESET);
- }
- }
- Data++;
- }
- FMC_Lock();
- }
程序跳转运行:
- int main(void)
- {
- Xmodem_Init(115200);
- printf("\r\nAPM32F107VC MINIBOARD V1.0 %s %s--->Bootloader\r\n", __DATE__, __TIME__);
- KEY_Init();
- LED_Init();
- while (1)
- {
- if((BIT_RESET == GPIO_ReadInputBit(GPIOA, GPIO_PIN_0)) ||
- (BIT_RESET == GPIO_ReadInputBit(GPIOA, GPIO_PIN_1)) )
- {
- Xmodem_RxHandler();
- }
- else
- {
- if(*(volatile uint32_t *)(ApplicationAddress) != 0xFFFFFFFF)
- {
- USART_Disable(USART1);
- JumpAddress = *(volatile uint32_t *)(ApplicationAddress + 4);
- JumpToApplication = (pFunction)JumpAddress;
- /* Initialize user application's Stack Pointer */
- __set_MSP(*(volatile uint32_t *)ApplicationAddress);
- JumpToApplication();
- }
- }
- }
- }
KEIL工程配置:
APPLICATION工程:
中断向量表重定义:
KEIL工程配置之程序空间划分:
KEIL工程配置之生成BIN文件:
IAP运行测试:
下载BOOTLOADER程序到开发板,通过串口终端软件进行监控:
按下开发板上的任一按键(除RST按键),MCU进入XMODEM传输模式:
XMODEM接收数据,并将数据写入到指定的FLASH空间:
XMODEM传输结束后,跳转到应用程序起始地址,开始运行:
软件工程源代码:
BOOTLOADER:
Bootloader.zip
(474.31 KB, 下载次数: 14)
APPLICATION:
Application.zip
(489.23 KB, 下载次数: 12)
|