본문 바로가기

Firmware/stm32

STM32 IAP (Ymodem 프로토콜) Bootloader - 1

cubeMX : 5.6.1
cubeIDE : 1.3.1

Code Lib Version : STM32Cube_FW_F1_V1.8.0

MCU:STM32F103VBTx

 

 

stm32 bootloader를 만들어 보자.

 

bootloader에 사용할  Ymodem은 teraterm 프로그램에서 사용할 수 있으며

teraterm과 연결하기 위해 uart를 설정해준다.

 

 

다음으로 bootloader를 코딩하기 위해선

 

먼저 사용하는 Flash Memory가 크기가 몇인지, 어디에다 Bootloader 코드를 올리고

 

어떤 Flash Memory 주소에 Application을 올리지 확인해야한다.

 

우선 STM32F103VBTx의 메모리 주소를 확인.

 

 

STM32F103의 FLASH Memory는 0x0800 0000 ~ 0x0802 0000 으로 끝난다.

 

여기서 Bootloader의 시작 주소는  0x0800 0000으로 시작하고

Application Code의 시작 주소는 0x0800 4000로 잡는다.

 

 

이제 cube에서 다운 받은 \STM32Cube_FW_F1_V1.8.0\Projects\STM3210C_EVAL\Applications\IAP\IAP_Main의 예제를 참고해서 만들어 보자.

 

위 코드를 확인 후 첫번째로 수정해야 할 곳은 flash_if.h 이다.

 

flash_if.h 에는 위에서 언급한 Bootloader 시작주소와 Application Code의 시작 주소를 설정 할 수 있다.

 

flash_if.h



/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"

/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/

/* Error code */
enum 
{
  FLASHIF_OK = 0,
  FLASHIF_ERASEKO,
  FLASHIF_WRITINGCTRL_ERROR,
  FLASHIF_WRITING_ERROR,
  FLASHIF_PROTECTION_ERRROR
};

/* protection type */  
enum{
  FLASHIF_PROTECTION_NONE         = 0,
  FLASHIF_PROTECTION_PCROPENABLED = 0x1,
  FLASHIF_PROTECTION_WRPENABLED   = 0x2,
  FLASHIF_PROTECTION_RDPENABLED   = 0x4,
};

/* protection update */
enum {
	FLASHIF_WRP_ENABLE,
	FLASHIF_WRP_DISABLE
};

/* Define the address from where user application will be loaded.
   Note: this area is reserved for the IAP code                  */
#define FLASH_PAGE_STEP         FLASH_PAGE_SIZE           /* Size of page : 2 Kbytes */
#define APPLICATION_ADDRESS     (uint32_t)0x08004000      /* Start user code address: ADDR_FLASH_PAGE_8 */

/* Notable Flash addresses */
#define USER_FLASH_END_ADDRESS        0x08040000

/* Define the user application size */
#define USER_FLASH_SIZE               ((uint32_t)0x00003000) /* Small default template application */

/* Define bitmap representing user flash area that could be write protected (check restricted to pages 8-39). */
#define FLASH_PAGE_TO_BE_PROTECTED (OB_WRP_PAGES8TO9 | OB_WRP_PAGES10TO11 | OB_WRP_PAGES12TO13 | OB_WRP_PAGES14TO15 | \
                                    OB_WRP_PAGES16TO17 | OB_WRP_PAGES18TO19 | OB_WRP_PAGES20TO21 | OB_WRP_PAGES22TO23 | \
                                    OB_WRP_PAGES24TO25 | OB_WRP_PAGES26TO27 | OB_WRP_PAGES28TO29 | OB_WRP_PAGES30TO31 | \
                                    OB_WRP_PAGES32TO33 | OB_WRP_PAGES34TO35 | OB_WRP_PAGES36TO37 | OB_WRP_PAGES38TO39  )  


/* Exported macro ------------------------------------------------------------*/
/* ABSoulute value */
#define ABS_RETURN(x,y)               (((x) < (y)) ? (y) : (x))

/* Get the number of sectors from where the user program will be loaded */
#define FLASH_SECTOR_NUMBER           ((uint32_t)(ABS_RETURN(APPLICATION_ADDRESS,FLASH_START_BANK1))>>12)

/* Compute the mask to test if the Flash memory, where the user program will be
  loaded, is write protected */
#define FLASH_PROTECTED_SECTORS       (~(uint32_t)((1 << FLASH_SECTOR_NUMBER) - 1))
/* Exported functions ------------------------------------------------------- */
void FLASH_If_Init(void);
uint32_t FLASH_If_Erase(uint32_t StartSector);
uint32_t FLASH_If_GetWriteProtectionStatus(void);
uint32_t FLASH_If_Write(uint32_t destination, uint32_t *p_source, uint32_t length);
uint32_t FLASH_If_WriteProtectionConfig(uint32_t protectionstate);



/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

flash_if.h 코드를 살펴보면 FLASH_PAGE_STEP 이라는 Define이 나오는데 이건 Flash Memory를 Page단위로 나눈 것이다. Size of page는 2kbyte로 되어있다.

 

하지만 Datasheet를 봤을 땐

 

1Kbyte로 나눠져있다.

 

어차피 hal Lib에 stm32f103으로 Compile 하면 1Kbyte로 정의 해준다.

 

stm32f1xx_hal_flash_ex.h

#if (defined(STM32F101x6) || defined(STM32F102x6) || defined(STM32F103x6) || defined(STM32F100xB) || defined(STM32F101xB) || defined(STM32F102xB) || defined(STM32F103xB))
#define FLASH_PAGE_SIZE          0x400U
#endif /* STM32F101x6 || STM32F102x6 || STM32F103x6 */
       /* STM32F100xB || STM32F101xB || STM32F102xB || STM32F103xB */

#if (defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F103xE) || defined(STM32F101xG) || defined(STM32F103xG) || defined(STM32F105xC) || defined(STM32F107xC))
#define FLASH_PAGE_SIZE          0x800U
#endif /* STM32F100xB || STM32F101xB || STM32F102xB || STM32F103xB */
       /* STM32F101xG || STM32F103xG */ 
       /* STM32F105xC || STM32F107xC */

 

 

Application Address는 앞서 정의한데로 0x08004000 으로 정의해준다.

#define APPLICATION_ADDRESS     (uint32_t)0x08004000 

 

User Flash end address 는 넉넉히 잡아줘도 상관 없지만, 나중에 펌웨어를 업로드 할때 이 크기대로 업로드 되니

참고한다. (Upload image from the internal Flash ----------------- 2)

 

#define FLASH_PAGE_TO_BE_PROTECTED 값을 바꿔줘야한다.

 

위에 언급했던 TABLE 4를 연장해서 보면

 

Page Address
Page 0 0x0800 0000
Page 1 0x0800 07FF
... ...
Page 16 0x0800 4000
Page 17 0x0800 47FF
Page 18 0x0800 4BFF
Page 19 0x0800 4FFF

Page 16부터 Application Address가 된다.

 

따라서 보호해야할 Page는 16Page 이므로 16 Page ~ 23 Page 까지 FLASH_PAGE_TO_BE_PROTECTED로 정의해준다.

 

#define FLASH_PAGE_TO_BE_PROTECTED (OB_WRP_PAGES16TO19 | OB_WRP_PAGES20TO23 )

//#define OB_WRP_PAGES0TO3               0x00000001U /*!< Write protection of page 0 to 3 */
//#define OB_WRP_PAGES4TO7               0x00000002U /*!< Write protection of page 4 to 7 */
//#define OB_WRP_PAGES8TO11              0x00000004U /*!< Write protection of page 8 to 11 */
//#define OB_WRP_PAGES12TO15             0x00000008U /*!< Write protection of page 12 to 15 */
//#define OB_WRP_PAGES16TO19             0x00000010U /*!< Write protection of page 16 to 19 */
//#define OB_WRP_PAGES20TO23             0x00000020U /*!< Write protection of page 20 to 23 */
//#define OB_WRP_PAGES24TO27             0x00000040U /*!< Write protection of page 24 to 27 */
//#define OB_WRP_PAGES28TO31             0x00000080U /*!< Write protection of page 28 to 31 */
//#define OB_WRP_PAGES32TO35             0x00000100U /*!< Write protection of page 32 to 35 */
//#define OB_WRP_PAGES36TO39             0x00000200U /*!< Write protection of page 36 to 39 */

 

FLASH_PAGE_TO_BE_PROTECTED 는 0x30이 된다 ( 0x10 | 0x20)

 

bootloader에 bin 파일을 업데이트 할 시 필요한 ymodem 프로토콜은 그대로 가지고 온다. (ymodem.c)

 

main.c

/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file           : main.c
 * @brief          : Main program body
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
 * All rights reserved.</center></h2>
 *
 * This software component is licensed by ST under BSD 3-Clause license,
 * the "License"; You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at:
 *                        opensource.org/licenses/BSD-3-Clause
 *
 ******************************************************************************
 */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
 * @brief  The application entry point.
 * @retval int
 */
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 */

  /* Execute the IAP driver in order to reprogram the Flash */
  FLASH_If_Init();
  /* Display main menu */
  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 */
}

/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct =
  { 0 };
  RCC_ClkInitTypeDef RCC_ClkInitStruct =
  { 0 };

  /** Initializes the CPU, AHB and APB busses clocks 
   */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
   */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
 * @brief USART1 Initialization Function
 * @param None
 * @retval None
 */
static void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

/**
 * @brief GPIO Initialization Function
 * @param None
 * @retval None
 */
static void MX_GPIO_Init(void)
{

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
 * @brief  This function is executed in case of error occurrence.
 * @retval None
 */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

bootloader를 Test 하기 위해 Main.c 에서는 무조건 Main_Menu() 함수가 실행 되도록 코딩해준다.

 

컴파일 후 MCU에 정상적으로 Download가 되면 Bootloader 1단계는 완료가 되었다.

 

 

TeraTerm에 연결하여 정상적으로 메시지가 출력되는지 확인한다.