天天看點

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

基于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

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

配置序列槽

我這裡配置的是序列槽1,對應引腳為PA9和PA10,波特率為115200,序列槽采用輪詢的方式通訊,不采用中斷的方式,故不配置序列槽中斷,其他預設。

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

生成代碼

H和C檔案分開,配置完成後,生成代碼,為後續IAP移植修改作準備

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

2.APP

需要再配置一個APP工程,做一個簡單的APP,就是讓一個LED燈不斷閃爍。

這裡簡單的配置了PB12口為輸出,作為LED燈,其他配置過程這裡就省略了。

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

二、移植Ymodem官方代碼

1.檔案移植

打開之前生成好的IAP工程目錄,在該目錄下建立一個Ymodem的檔案夾

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

打開我們從官網下載下傳好en.stsw-stm32067官方固件庫,将en.stsw-stm32067->STM32F4xx_AN3965_V1.0.0->Project->STM32F4xx_IAP下的inc和src檔案夾中的部分檔案複制到建立的Ymodem的檔案夾中

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

複制完的Ymodem的檔案夾内容如下,一共8個檔案

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

2.MDK檔案、路徑添加

打開IAP的MDK工程,添加一個Ymodem組,将Ymodem檔案夾中的.c檔案添加進去

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

添加Ymodem檔案夾中的.H檔案的路徑

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

3.修改代碼

完成1和2步後編譯工程會報很多錯誤,需要修改代碼

(1)删除不必要的代碼

打開common.h檔案,删除#include "stm324xg_eval.h" ,這個頭檔案是官方用在一個官方的開發闆上的,我們用不到,故删之

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

(2)修改IAP代碼

  • common.c檔案

打開common.c檔案,在193行有報錯,這裡官方用的不是HAL庫,而且官方用的開發闆的接口有不同的定義,是以,我們根據自己的實際情況修改下面的代碼

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

我們将這個函數修改如下,并且要添加一個頭檔案,從這個函數的内容可知,主要實作接收一個位元組

/** @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;
  }
}
           

同樣,修改下面的代碼

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

修改成這樣

/**
  * @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)

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

修改如下

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)函數

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

修改成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)函數

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

修改成如下:

/**
  * @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)函數

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

修改如下

/**
  * @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)函數

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

修改如下

/**
  * @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)函數

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

修改如下:

/**
  * @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 */
}
           

編譯一下,已經沒有錯誤了

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

(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 

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試
基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

生成bin檔案,複制

fromelf.exe --bin -o "[email protected]" "#L
基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

修改FLASH燒錄位址

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

設定完成後編譯一下,生成bin檔案

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

三、燒錄、測試

打開secureCRT上位機軟體,選好端口,設定好波特率,去掉RTS/CTS的勾,點選連接配接,如下圖

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

點選選項,選擇會話選項,彈出如下視窗,按下圖設定好,點選确定

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

将IAP代燒錄到開發闆,代碼開始執行後,如下圖

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

在下方視窗輸入1,此時序列槽不斷接受到'C',如下圖所示

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

選擇傳輸,點選發送Ymodem

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

選擇添加好APP生成的bin檔案,點選确定

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

等待一段時間,等待擦除flash,就會完成傳輸,此時,在下方視窗輸入3,即可運作APP

基于Ymodem協定的stm32f405rgt6+CubeMx+IAP線上更新一、CubeMX的配置二、移植Ymodem官方代碼三、燒錄、測試

至此,全部工作已結束

其他待更新。。。。。。

繼續閱讀