Skip to main content
Explorer
September 5, 2024
Question

whole firmware run in ram

  • September 5, 2024
  • 2 replies
  • 1591 views

Hello:

    I use STM32CubeIDE 1.16.0 to develop an OTA feature in STM32H7A3ZIT6:

    The firmware should be programed at flash address 0x08000000,and run in ram, it will receive the whole update image in temporary memory and then program into the flash at the same start address 0x08000000,is it possible in this way? Any detailed examples or documents are appreciated, thanks.

Bill

    This topic has been closed for replies.

    2 replies

    ST Employee
    September 5, 2024

    Hello @lbapplem 

    Yes, it is possible to implement an OTA update feature for the STM32H7A3ZIT6 microcontroller using STM32CubeIDE. The general idea is to have a bootloader that can receive the new firmware image, store it temporarily in RAM or another memory area, and then program it into the flash memory at the start address 0x08000000.

    STM32CubeH7 Firmware Package: This package contains examples and libraries for STM32H7 series microcontrollers. You can find it on the STMicroelectronics website.

    AN4852 Application Note: This document provides guidelines for developing a bootloader for STM32 microcontrollers. It can be found on the STMicroelectronics website.

     

    lbapplemAuthor
    Explorer
    September 5, 2024

    Hi nouirakh:

        Thanks for the quick response, but in my case there may not be a bootloader to do so, only the application will start at the default flash address 0x08000000 where is the start address of the flash, and the application should receive the new firmware image to RAM, then erase the flash from 0x08000000 and program the new image into this address,is it possible? I've used STM32H7A3ZITX_RAM.ld to make the application run in RAM(if it does so), but the application will crash when running to erase the flash from 0x08000000, did I miss something?

    Bill

    ST Employee
    September 5, 2024

    hello @lbapplem 

    OK, so, it is possible to implement an OTA update feature without a separate bootloader, but it requires careful handling since the application will be running from RAM while it erases and reprograms the flash memory.By following these steps, you should be able to implement an OTA update feature:

    1. Modify the Linker Script

      Ensure that your linker script (STM32H7A3ZITX_RAM.ld) places the code and data in RAM. Here is an example of a linker script for running the application from RAM:

      /* Entry Point */
      ENTRY(Reset_Handler)
      
      /* Highest address of the user mode stack */
      _estack = 0x20040000; /* end of RAM */
      
      /* Generate a link error if heap and stack don't fit into RAM */
      _Min_Heap_Size = 0x200; /* required amount of heap */
      _Min_Stack_Size = 0x400; /* required amount of stack */
      
      /* Specify the memory areas */
      MEMORY
      {
       RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
      }
      
      /* Define output sections */
      SECTIONS
      {
       .isr_vector :
       {
       . = ALIGN(4);
       KEEP(*(.isr_vector)) /* Startup code */
       . = ALIGN(4);
       } >RAM
      
       .text :
       {
       . = ALIGN(4);
       *(.text) /* .text sections (code) */
       *(.text*) /* .text* sections (code) */
       *(.rodata) /* .rodata sections (constants, strings, etc.) */
       *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
       . = ALIGN(4);
       } >RAM
      
       .data : AT(__data_load_addr)
       {
       . = ALIGN(4);
       __data_start__ = .;
       *(.data) /* .data sections */
       *(.data*) /* .data* sections */
       . = ALIGN(4);
       __data_end__ = .;
       } >RAM
      
       .bss :
       {
       . = ALIGN(4);
       __bss_start__ = .;
       *(.bss)
       *(.bss*)
       . = ALIGN(4);
       __bss_end__ = .;
       } >RAM
      
       /* User_heap_stack section, used to check that there is enough RAM left */
       ._user_heap_stack :
       {
       . = ALIGN(8);
       PROVIDE ( end = . );
       PROVIDE ( _end = . );
       . = . + _Min_Heap_Size;
       . = . + _Min_Stack_Size;
       . = ALIGN(8);
       } >RAM
      }​

      2.Copy Application to RAM

      In your startup code, copy the application from flash to RAM and then jump to the RAM execution address. Here is an example of how to do this in your main.c:

      #include "stm32h7xx_hal.h"
      
      #define APPLICATION_ADDRESS 0x08000000
      #define RAM_EXECUTION_ADDRESS 0x20000000
      
      void SystemClock_Config(void);
      void Error_Handler(void);
      void JumpToRAM(void);
      
      int main(void) {
       HAL_Init();
       SystemClock_Config();
      
       // Copy application from flash to RAM
       uint32_t *flash_ptr = (uint32_t *)APPLICATION_ADDRESS;
       uint32_t *ram_ptr = (uint32_t *)RAM_EXECUTION_ADDRESS;
       for (uint32_t i = 0; i < (128 * 1024) / 4; i++) { // Assuming 128KB application size
       ram_ptr[i] = flash_ptr[i];
       }
      
       // Jump to RAM execution address
       JumpToRAM();
      
       while (1) {
       }
      }
      
      void JumpToRAM(void) {
       typedef void (*pFunction)(void);
       uint32_t jumpAddress = *(__IO uint32_t *)(RAM_EXECUTION_ADDRESS + 4);
       pFunction jumpToApplication = (pFunction)jumpAddress;
       __set_MSP(*(__IO uint32_t *)RAM_EXECUTION_ADDRESS);
       jumpToApplication();
      }
      
      void SystemClock_Config(void) {
       // Configure the system clock
       // ...
      }
      
      void Error_Handler(void) {
       // Implement error handling
       while (1) {
       }
      }​

      3. Flash Erase and Program

      Implement the flash erase and program routines in your application. Ensure that these routines are executed while the application is running from RAM.

      void EraseFlash(uint32_t address) {
       FLASH_EraseInitTypeDef eraseInitStruct;
       uint32_t sectorError;
       eraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
       eraseInitStruct.Sector = FLASH_SECTOR_0; // Adjust as needed
       eraseInitStruct.NbSectors = 1; // Adjust as needed
       eraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
       if (HAL_FLASHEx_Erase(&eraseInitStruct, &sectorError) != HAL_OK) {
       Error_Handler();
       }
      }
      
      void ProgramFlash(uint32_t address, uint8_t *data, uint32_t length) {
       HAL_FLASH_Unlock();
       for (uint32_t i = 0; i < length; i += 4) {
       if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address + i, *(uint32_t *)(data + i)) != HAL_OK) {
       Error_Handler();
       }
       }
       HAL_FLASH_Lock();
      }​

     

    Graduate II
    September 5, 2024

    "Build for 0x20000000 base address, with whatever split for data, rebase the Reset_Handler entry point, copy the entire FLASH image to RAM, set SCB->VTOR to 0x20000000 per SystemInit() and fork."

    https://community.st.com/t5/stm32-mcus-products/writing-a-program-that-updates-itself-at-runtime/m-p/714251