2022年10月12日 星期三

[STM32] M0 series IAP program jumps -1

In a previous project, the STM32 M0 was specified for use, and this project requires IAP functionality. Although the STM32 already has an embedded bootloader, unfortunately it does not meet the actual requirements. During implementation, it was found that the M0 does not have the VTOR register, which is not as convenient as the M3/M4. This is just a record of the issue.

First of all, I chose the STM32F0xx series chip, which has three boot sectors in hardware, which can be selected through the Boot0 pin. They are Main Flash memory, System memory, and Embedded SRAM. However, is it possible to bypass Boot0 through software?

Some of these will also be mentioned.

This is mentioned in the Reference Manual:

Simply put, the boot starts from 0x0000 0000, and Flash memory is the primary boot space. 0x0000 0000 and 0x0800 0000 can be considered as the same location.

The following description is the main point of today's topic.

The boot block can be selected in the software program by configuring the MEM_MODE setting in the SYSCFG configuration register. Unlike the M3/M4, the M0 does not support vector table relocation. Therefore, we can set a different boot location in the program segment. What needs to be done is to copy the vector table to the SRAM and remap the SRAM to the 0x0000 0000 address.

OK, now we need to create 2 projects: one for the IAP and one for the main application. First, we need to select the flash memory area. In this example, we will use 0x08000000-0x08003FFF for the IAP and 0x08004000 and above for the main application. This partitioning is not mandatory, but it is recommended to follow the sector boundary. It is important to check the Reference manual to ensure the sector sizes for each device model as they may vary.

The AP code segment will contain programs for downloading or receiving programs and flash-related write and erase programs. In this example, we will first focus on how to jump to the main code segment. The following is the process of modifying the code."

IAP Program Section - Project 1
Add the following code to the Define section of the program:


#define APP_FLASHADDR 0x08004000
typedef void (*JmpFunction)(void);

APP_FLASHADDR is the start address of the main program, and JmpFunction is a function pointer declaration.

Add the following code in the Private variables section:


uint32_t JumpAddress;
JmpFunction Jump_To_Application;

Add the following code in main() function.


uint32_t ApplicationAddress = APP_FLASHADDR;

if(((*(__IO uint32_t*)ApplicationAddress); 0x2FFE0000 ) == 0x20000000)
{
 /* Jump to user application */
 JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
 Jump_To_Application = (JmpFunction) JumpAddress;
 /* Initialize user application's Stack Pointer */
 __set_MSP(*(__IO uint32_t*) ApplicationAddress);
 Jump_To_Application();
}

The if statement checks if there is code in the program section, and if so, executes the jump procedure.

First, edit the Linker script. Find the STM32xxx.ld file. Look for the following text


/* Specify the memory areas */
MEMORY
{
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 8K
FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 64K
}

Modify it to


/* Specify the memory areas */
MEMORY
{
RAM (xrw)      : ORIGIN = 0x20000400, LENGTH = 7K
FLASH (rx)      : ORIGIN = 0x8004000, LENGTH = 48K
SRAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 1k
}

Add the following code after the last line '.ARM.attributes 0 : { *(.ARM.attributes) }':


.RAMVectorTable : {*(.RAMVectorTable)} >SRAM AT> FLASH

Memory organization needs to be modified in order to place the Vector table.
Insert at the beginning of main.c


#define APPLICATION_ADDRESS 0x08004000

#if   (defined ( __CC_ARM ))
  __IO uint32_t VectorTable[188] __attribute__((at(0x20000000)));
#elif (defined (__ICCARM__))
#pragma location = 0x20000000
  __no_init __IO uint32_t VectorTable[188];
#elif defined ( __GNUC__ )
  __IO uint32_t VectorTable[188] __attribute__((section(".RAMVectorTable")));
#endif

Add the following code to main() function:


  /* USER CODE BEGIN 1 */
 uint32_t i=0;
  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Copy the vector table from the Flash (mapped at the base of the application
load address 0x08004000) to the base address of the SRAM at 0x20000000. */
for(i = 0; i < 188; i++)
{
  VectorTable[i] = *(__IO uint32_t*)(APPLICATION_ADDRESS + (i<<2 code="">

Copy the contents of the vector table to SRAM. As for the vector table section, this is a break point. I found some content in the datasheet, but I truncated the last section because the table is too long. It may vary depending on the model, so adjustments may be made here when encountering differences.

Finally, add the following code before initializing configured peripherals.


  /* Enable the SYSCFG peripheral clock*/
  __HAL_RCC_SYSCFG_CLK_ENABLE();

  /* Remap SRAM at 0x00000000 */
  __HAL_SYSCFG_REMAPMEMORY_SRAM();

The above part of the jump has been completed. To verify if it is working properly, you can add the following code to the while loop to see if it jumps directly to this part.


HAL_Delay(250);
HAL_GPIO_TogglePin(GPIOC,LD4_Pin);
HAL_Delay(100);
HAL_GPIO_TogglePin(GPIOC,LD3_Pin);