基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新
目錄
一、CubeMX的配置
1.IAP
2.APP
二、移植Ymodem官方代碼
1.檔案移植
2.MDK檔案、路徑添加
3.修改代碼
(1)删除不必要的代碼
(2)修改IAP代碼
(3)修改APP代碼
三、燒錄、測試
準備工作:
1.STM32F4開發闆
2.USB轉序列槽工具
3.MDK Keil5
4.CubeMX
5.secureCRT上位機軟體
6.en.stsw-stm32067官方固件庫
工程下載下傳位址:
Ymodem_IAP_F405_CubeMx+secureCRT上位機軟體
一、CubeMX的配置
需要配置IAP和APP兩個工程,這兩個工程的配置都比較簡單
1.IAP
打開CubeMX軟體,選好晶片型号,這裡我的晶片型号是STM32F405RGT6
配置時鐘
配置主時鐘,我配置的是内部時鐘,主頻為168MHz
配置序列槽
我這裡配置的是序列槽1,對應引腳為PA9和PA10,波特率為115200,序列槽采用輪詢的方式通訊,不采用中斷的方式,故不配置序列槽中斷,其他預設。
生成代碼
H和C檔案分開,配置完成後,生成代碼,為後續IAP移植修改作準備
2.APP
需要再配置一個APP工程,做一個簡單的APP,就是讓一個LED燈不斷閃爍。
這裡簡單的配置了PB12口為輸出,作為LED燈,其他配置過程這裡就省略了。
二、移植Ymodem官方代碼
1.檔案移植
打開之前生成好的IAP工程目錄,在該目錄下建立一個Ymodem的檔案夾
打開我們從官網下載下傳好en.stsw-stm32067官方固件庫,将en.stsw-stm32067->STM32F4xx_AN3965_V1.0.0->Project->STM32F4xx_IAP下的inc和src檔案夾中的部分檔案複制到建立的Ymodem的檔案夾中
複制完的Ymodem的檔案夾内容如下,一共8個檔案
2.MDK檔案、路徑添加
打開IAP的MDK工程,添加一個Ymodem組,将Ymodem檔案夾中的.c檔案添加進去
添加Ymodem檔案夾中的.H檔案的路徑
3.修改代碼
完成1和2步後編譯工程會報很多錯誤,需要修改代碼
(1)删除不必要的代碼
打開common.h檔案,删除#include "stm324xg_eval.h" ,這個頭檔案是官方用在一個官方的開發闆上的,我們用不到,故删之
(2)修改IAP代碼
- common.c檔案
打開common.c檔案,在193行有報錯,這裡官方用的不是HAL庫,而且官方用的開發闆的接口有不同的定義,是以,我們根據自己的實際情況修改下面的代碼
我們将這個函數修改如下,并且要添加一個頭檔案,從這個函數的内容可知,主要實作接收一個位元組
/** @addtogroup STM32F4xx_IAP
* @{
*/
/* Includes ------------------------------------------------------------------*/
#include "common.h"
#include "usart.h" //添加的頭檔案
/* Private typedef -----------------------------------------------------------*/
/**
* @brief Test to see if a key has been pressed on the HyperTerminal
* @param key: The key pressed
* @retval 1: Correct
* 0: Error
*/
uint32_t SerialKeyPressed(uint8_t *key)
{
if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) != RESET)
{
*key = (uint16_t)((&huart1)->Instance->DR & (uint16_t)0x01FF);
return 1;
}
else
{
return 0;
}
}
同樣,修改下面的代碼
修改成這樣
/**
* @brief Print a character on the HyperTerminal
* @param c: The character to be printed
* @retval None
*/
void SerialPutChar(uint8_t c)
{
USART_SendData(USART1, c);
while (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE) == RESET)
{
}
}
在common.c末尾添加代碼,添加void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)函數
//添加代碼
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
{
/* Check the parameters */
assert_param(IS_USART_ALL_PERIPH(USARTx));
assert_param(IS_USART_DATA(Data));
/* Transmit Data */
USARTx->DR = (Data & (uint16_t)0x01FF);
}
在common.h添加聲明void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
/* Exported functions ------------------------------------------------------- */
void Int2Str(uint8_t* str,int32_t intnum);
uint32_t Str2Int(uint8_t *inputstr,int32_t *intnum);
uint32_t GetIntegerInput(int32_t * num);
uint32_t SerialKeyPressed(uint8_t *key);
uint8_t GetKey(void);
void SerialPutChar(uint8_t c);
void Serial_PutString(uint8_t *s);
void GetInputString(uint8_t * buffP);
//添加聲明
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
- flash_if.c檔案
修改FLASH_If_Init(void)
修改如下
void FLASH_If_Init(void)
{
HAL_FLASH_Unlock();
/* Clear pending flags (if any) */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
}
修改FLASH_If_Erase(uint32_t StartSector)函數
修改成HAL庫的方式,修改如下:
/**
* @brief This function does an erase of all user flash area
* @param StartSector: start of user flash area
* @retval 0: user flash area successfully erased
* 1: error occurred
*/
uint32_t FLASH_If_Erase(uint32_t StartSector)
{
uint32_t UserStartSector;
uint32_t SectorError;
FLASH_EraseInitTypeDef pEraseInit;
/* Unlock the Flash to enable the flash control register access *************/
/* Get the sector where start the user flash area */
UserStartSector = GetSector(APPLICATION_ADDRESS);
pEraseInit.TypeErase = TYPEERASE_SECTORS;
pEraseInit.Sector = UserStartSector;
pEraseInit.NbSectors = GetSector(USER_FLASH_END_ADDRESS)-UserStartSector+1 ;
pEraseInit.VoltageRange = VOLTAGE_RANGE_3;
if (HAL_FLASHEx_Erase(&pEraseInit, &SectorError) != HAL_OK)
{
/* Error occurred while page erase */
return (1);
}
return (0);
}
修改FLASH_If_Write(__IO uint32_t* FlashAddress, uint32_t* Data ,uint32_t DataLength)函數
修改成如下:
/**
* @brief This function writes a data buffer in flash (data are 32-bit aligned).
* @note After writing data buffer, the flash content is checked.
* @param FlashAddress: start address for writing data buffer
* @param Data: pointer on data buffer
* @param DataLength: length of data buffer (unit is 32-bit word)
* @retval 0: Data successfully written to Flash memory
* 1: Error occurred while writing data in Flash memory
* 2: Written Data in flash memory is different from expected one
*/
uint32_t FLASH_If_Write(__IO uint32_t* FlashAddress, uint32_t* Data ,uint32_t DataLength)
{
uint32_t i = 0;
for (i = 0; (i < DataLength) && (*FlashAddress <= (USER_FLASH_END_ADDRESS-4)); i++)
{
/* Device voltage range supposed to be [2.7V to 3.6V], the operation will
be done by word */
FLASH_ProgramWord(*FlashAddress, *(uint32_t*)(Data+i));
/* Check the written value */
if (*(uint32_t*)*FlashAddress != *(uint32_t*)(Data+i))
{
/* Flash content doesn't match SRAM content */
return(2);
}
/* Increment FLASH destination address */
*FlashAddress += 4;
}
return (0);
}
在flash_if.c末尾添加如下函數
void FLASH_ProgramWord(uint32_t Address, uint32_t Data)
{
/* Check the parameters */
assert_param(IS_FLASH_ADDRESS(Address));
/* If the previous operation is completed, proceed to program the new data */
CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE);
FLASH->CR |= FLASH_PSIZE_WORD;
FLASH->CR |= FLASH_CR_PG;
*(__IO uint32_t*)Address = Data;
}
在flash_if.h添加void FLASH_ProgramWord(uint32_t Address, uint32_t Data)聲明
/* Exported functions ------------------------------------------------------- */
void FLASH_If_Init(void);
uint32_t FLASH_If_Erase(uint32_t StartSector);
uint32_t FLASH_If_Write(__IO uint32_t* FlashAddress, uint32_t* Data, uint32_t DataLength);
uint16_t FLASH_If_GetWriteProtectionStatus(void);
uint32_t FLASH_If_DisableWriteProtection(void);
//添加聲明
void FLASH_ProgramWord(uint32_t Address, uint32_t Data);
#endif /* __FLASH_IF_H */
修改 FLASH_If_GetWriteProtectionStatus(void)函數
修改如下
/**
* @brief Returns the write protection status of user flash area.
* @param None
* @retval 0: No write protected sectors inside the user flash area
* 1: Some sectors inside the user flash area are write protected
*/
uint16_t FLASH_If_GetWriteProtectionStatus(void)
{
uint32_t UserStartSector = FLASH_SECTOR_1;
/* Get the sector where start the user flash area */
UserStartSector = GetSector(APPLICATION_ADDRESS);
/* Check if there are write protected sectors inside the user flash area */
if ((*(__IO uint16_t *)(OPTCR_BYTE2_ADDRESS) >> (UserStartSector/8)) == (0xFFF >> (UserStartSector/8)))
{ /* No write protected sectors inside the user flash area */
return 1;
}
else
{ /* Some sectors inside the user flash area are write protected */
return 0;
}
}
修改FLASH_If_DisableWriteProtection(void)函數
修改如下
/**
* @brief Disables the write protection of user flash area.
* @param None
* @retval 1: Write Protection successfully disabled
* 2: Error: Flash write unprotection failed
*/
uint32_t FLASH_If_DisableWriteProtection(void)
{
__IO uint32_t UserStartSector = FLASH_SECTOR_1, UserWrpSectors = OB_WRP_SECTOR_1;
/* Get the sector where start the user flash area */
UserStartSector = GetSector(APPLICATION_ADDRESS);
/* Mark all sectors inside the user flash area as non protected */
UserWrpSectors = 0xFFF-((1 << (UserStartSector/8))-1);
/* Unlock the Option Bytes */
HAL_FLASH_Unlock();
/* Disable the write protection for all sectors inside the user flash area */
FLASH_OB_DisableWRP(UserWrpSectors, FLASH_BANK_1);
/* Start the Option Bytes programming process. */
if (HAL_FLASH_OB_Launch( ) != HAL_OK)
{
/* Error: Flash write unprotection failed */
return (2);
}
/* Write Protection successfully disabled */
return (1);
}
需在末尾處添加 FLASH_OB_DisableWRP(uint32_t WRPSector, uint32_t Banks)函數
HAL_StatusTypeDef FLASH_OB_DisableWRP(uint32_t WRPSector, uint32_t Banks)
{
HAL_StatusTypeDef status = HAL_OK;
/* Check the parameters */
assert_param(IS_OB_WRP_SECTOR(WRPSector));
assert_param(IS_FLASH_BANK(Banks));
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(50000);
if(status == HAL_OK)
{
*(__IO uint16_t*)OPTCR_BYTE2_ADDRESS |= (uint16_t)WRPSector;
}
return status;
}
并在flash_if.h添加函數聲明HAL_StatusTypeDef FLASH_OB_DisableWRP(uint32_t WRPSector, uint32_t Banks);
/* Exported functions ------------------------------------------------------- */
void FLASH_If_Init(void);
uint32_t FLASH_If_Erase(uint32_t StartSector);
uint32_t FLASH_If_Write(__IO uint32_t* FlashAddress, uint32_t* Data, uint32_t DataLength);
uint16_t FLASH_If_GetWriteProtectionStatus(void);
uint32_t FLASH_If_DisableWriteProtection(void);
//添加聲明
void FLASH_ProgramWord(uint32_t Address, uint32_t Data);
HAL_StatusTypeDef FLASH_OB_DisableWRP(uint32_t WRPSector, uint32_t Banks);
#endif /* __FLASH_IF_H */
修改GetSector(uint32_t Address)函數
修改如下:
/**
* @brief Gets the sector of a given address
* @param Address: Flash address
* @retval The sector of a given address
*/
static uint32_t GetSector(uint32_t Address)
{
uint32_t sector = 0;
if((Address < ADDR_FLASH_SECTOR_1) && (Address >= ADDR_FLASH_SECTOR_0))
{
sector = FLASH_SECTOR_0;
}
else if((Address < ADDR_FLASH_SECTOR_2) && (Address >= ADDR_FLASH_SECTOR_1))
{
sector = FLASH_SECTOR_1;
}
else if((Address < ADDR_FLASH_SECTOR_3) && (Address >= ADDR_FLASH_SECTOR_2))
{
sector = FLASH_SECTOR_2;
}
else if((Address < ADDR_FLASH_SECTOR_4) && (Address >= ADDR_FLASH_SECTOR_3))
{
sector = FLASH_SECTOR_3;
}
else if((Address < ADDR_FLASH_SECTOR_5) && (Address >= ADDR_FLASH_SECTOR_4))
{
sector = FLASH_SECTOR_4;
}
else if((Address < ADDR_FLASH_SECTOR_6) && (Address >= ADDR_FLASH_SECTOR_5))
{
sector = FLASH_SECTOR_5;
}
else if((Address < ADDR_FLASH_SECTOR_7) && (Address >= ADDR_FLASH_SECTOR_6))
{
sector = FLASH_SECTOR_6;
}
else if((Address < ADDR_FLASH_SECTOR_8) && (Address >= ADDR_FLASH_SECTOR_7))
{
sector = FLASH_SECTOR_7;
}
else if((Address < ADDR_FLASH_SECTOR_9) && (Address >= ADDR_FLASH_SECTOR_8))
{
sector = FLASH_SECTOR_8;
}
else if((Address < ADDR_FLASH_SECTOR_10) && (Address >= ADDR_FLASH_SECTOR_9))
{
sector = FLASH_SECTOR_9;
}
else if((Address < ADDR_FLASH_SECTOR_11) && (Address >= ADDR_FLASH_SECTOR_10))
{
sector = FLASH_SECTOR_10;
}
else/*(Address < FLASH_END_ADDR) && (Address >= ADDR_FLASH_SECTOR_11))*/
{
sector = FLASH_SECTOR_11;
}
return sector;
}
- ymodem.h
在ymodem.h檔案添加頭檔案#include "stdint.h"
#include "stdint.h"
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __YMODEM_H_
#define __YMODEM_H_
- main.c檔案
在main.c檔案添加頭檔案#include "menu.h"
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "menu.h"
main()函數添加 FLASH_If_Init()和 Main_Menu ()函數
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_USART1_UART_Init();
/* USER CODE BEGIN 2 */
FLASH_If_Init();
Main_Menu ();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
編譯一下,已經沒有錯誤了
(3)修改APP代碼
打開APP工程,while(1)添加如下函數
int main(void)
{
/* USER CODE BEGIN 1 */
SCB->VTOR = FLASH_BASE | 0x4000; //中斷向量表偏移
/* 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();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_12);
HAL_Delay(1000);
}
/* USER CODE END 3 */
}
從IAP的flash_if.h的宏定義可以看出,這裡的APP起始位址為0x08004000
生成bin檔案,複制
fromelf.exe --bin -o "[email protected]" "#L
修改FLASH燒錄位址
設定完成後編譯一下,生成bin檔案
三、燒錄、測試
打開secureCRT上位機軟體,選好端口,設定好波特率,去掉RTS/CTS的勾,點選連接配接,如下圖
點選選項,選擇會話選項,彈出如下視窗,按下圖設定好,點選确定
将IAP代燒錄到開發闆,代碼開始執行後,如下圖
在下方視窗輸入1,此時序列槽不斷接受到'C',如下圖所示
選擇傳輸,點選發送Ymodem
選擇添加好APP生成的bin檔案,點選确定
等待一段時間,等待擦除flash,就會完成傳輸,此時,在下方視窗輸入3,即可運作APP
至此,全部工作已結束
其他待更新。。。。。。