ARM неправильно переходит от FLASH к RAM

У меня есть процессор STM32H750 ARM Cortex M7, и я компилирую код C с помощью STM32CubeIDE. Я хочу иметь код по умолчанию во FLASH, который может запускать приложение сам по себе, но который также может загружать обновленное приложение в ОЗУ и запускать обновление из ОЗУ. В конечном итоге обновление будет иметь другие инициализированные переменные и таблицы переходов, поэтому я думаю, что было бы целесообразно, чтобы ветвь от FLASH к RAM была в коде запуска до того, как произойдет эта инициализация. Однако на данный момент исходный код по умолчанию и исходный код обновления идентичны, за исключением адреса ветки обновления (подробнее об этом позже). В конечном итоге это должно работать с безопасностью RDP2, но на данный момент RDP2 не установлен.

Код запуска ищет набор волшебных файлов cookie, успешно загружая обновление, и переходит к адресу ContinueInit в обновлении. Я не включил векторы сброса и прерывания.

      Reset_Handler:  
  ldr   sp, =_estack      /* set stack pointer */

  ldr   r1, =0x580244dc
  ldr   r2, =0xe0000000
  str   r2, [r1]    /* turn on the RAM1-3 clocks - this is essential!   */

  ldr   r0, =0x580244d0
  ldr   r1, [r0]    /* get the value in the reset status register       */
  ldr   r2, =0x00460000
  cmp   r2, r1      /* compare reset status to external reset value     */
  ldr   r2, =0x00010000
  str   r2, [r0]    /* clear the reset status register                  */
  bne   ContinueInit    /* use default code if not from external reset      */

  ldr   r0, =magic_cookie
  ldr   r1, [r0]    /* get the value in the magic cookie                */
  ldr   r2, =0x12345678
  cmp   r2, r1      /* compare magic cookie to update value             */
  bne   ContinueInit    /* use default code if no cookie match              */

  ldr   r2, =0x00100010
  str   r2, [r0]    /* clear the magic cookie                   */
  b UpdateContinueInit

ContinueInit:
/* Copy the data segment initializers from code to SRAM */
  movs  r1, #0
  b  LoopCopyDataInit
CopyDataInit:
  ldr   r3, =_sidata
  ldr   r3, [r3, r1]
  str   r3, [r0, r1]
  adds  r1, r1, #4
LoopCopyDataInit:
  ldr   r0, =_sdata
  ldr   r3, =_edata
  adds  r2, r0, r1
  cmp   r2, r3
  bcc   CopyDataInit
  ldr   r2, =_sbss
  b     LoopFillZerobss

/* Zero fill the bss segment. */
FillZerobss:
  movs  r3, #0
  str   r3, [r2], #4
LoopFillZerobss:
  ldr   r3, = _ebss
  cmp   r2, r3
  bcc   FillZerobss

/* Call the clock system intitialization function.*/
  bl    SystemInit

/* Call static constructors */
  bl    __libc_init_array

/* branch to the default main program */
  bl    main
  bx    lr

Отдельные файлы .ld управляют связью по умолчанию и обновления. Адрес FLASH Continue_Init появляется в файле обновления .ld для сохранения сходства между значениями по умолчанию и обновлением.

      /\* Default Entry Point \*/
ENTRY(Reset_Handler)

/\* Highest address of the user mode stack */
\_estack = 0x20020000;    /* end of DTCMRAM */
/* Generate a link error if heap and stack don't fit into RAM */
\_Min_Heap_Size  = 0x400; /* required amount of heap  */
\_Min_Stack_Size = 0x800; /* required amount of stack \*/

/\* 1mS counter location used by ISR \*/
uwTick = 0x20000000;
magic_cookie  = 0x20000004;
UpdateContinueInit = 0x24014572;

/\* Specify the memory areas \*/
MEMORY
{
FLASH (rx)     : ORIGIN = 0x08000000, LENGTH = 128K
DTCMRAM (xrw)  : ORIGIN = 0x20000008, LENGTH = 0x1fff8
RAM123 (xrw)   : ORIGIN = 0x30000000, LENGTH = 288K
}

/\* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /\* Startup code \*/
. = ALIGN(4);
} \>FLASH

/\* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
(.text)           /* .text sections (code) */
(.text*)          / .text sections (code) \*/
*(.glue_7)         /* glue arm to thumb code \*/
*(.glue_7t)        /* glue thumb to arm code \*/
\*(.eh_frame)

    KEEP (*(.init))
    KEEP (*(.fini))
    
    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */

} \>FLASH

/\* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(4);
(.rodata)         /* .rodata sections (constants, strings, etc.) */
(.rodata*)        / .rodata sections (constants, strings, etc.) \*/
. = ALIGN(4);
} \>FLASH

.ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.\*) } \>FLASH
.ARM : {
\__exidx_start = .;
*(.ARM.exidx*)
\__exidx_end = .;
} \>FLASH

.preinit_array     :
{
PROVIDE_HIDDEN (\__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (\__preinit_array_end = .);
} \>FLASH
.init_array :
{
PROVIDE_HIDDEN (\__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (\__init_array_end = .);
} \>FLASH
.fini_array :
{
PROVIDE_HIDDEN (\__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (\__fini_array_end = .);
} \>FLASH

/\* used by the startup to initialize data \*/
\_sidata = LOADADDR(.data);

/\* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
\_sdata = .;        /* create a global symbol at data start */
(.data)           /* .data sections */
(.data*)          / .data sections \*/

    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */

} \>DTCMRAM AT\> FLASH

/\* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
\_sbss = .;         /* define a global symbol at bss start \*/
__bss_start__ = \_sbss;
\*(.bss)
*(.bss*)
\*(COMMON)

    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;

} \>RAM123

/\* 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);
} \>DTCMRAM

/\* Remove information from the standard libraries \*/
/DISCARD/ :
{
libc.a ( \* )
libm.a ( \* )
libgcc.a ( \* )
}

.ARM.attributes 0 : { \*(.ARM.attributes) }
}
      /* Update Entry Point */
ENTRY(Reset_Handler)

/* Highest address of the user mode stack */
_estack = 0x20020000;    /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size  = 0x400; /* required amount of heap  */
_Min_Stack_Size = 0x800; /* required amount of stack */

/* 1mS counter location used by ISR */
uwTick = 0x20000000;
magic_cookie 0= 0x20000004;
UpdateContinueInit = 0x08014572;

/* Specify the memory areas */
MEMORY
{
   DTCMRAM (xrw)  : ORIGIN = 0x2000008, LENGTH = 0x1fff8
   AXIRAM (xrw)   : ORIGIN = 0x24000000, LENGTH = 0x80000  
   RAM123 (xrw)   : ORIGIN = 0x30000000, LENGTH = 288K
}

/* Define output sections */
SECTIONS
{
  /* The startup code goes first into RSTRAM */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >AXIRAM

  /* The program code and other data goes into AXIRAM */
  .text :
  {
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
    *(.eh_frame)

    KEEP (*(.init))
    KEEP (*(.fini))

    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } >AXIRAM

  /* Constant data goes into AXIRAM */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >AXIRAM

  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >AXIRAM
  .ARM : {
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
  } >AXIRAM

  .preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } >AXIRAM
  .init_array :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } >AXIRAM
  .fini_array :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } >AXIRAM

  /* used by the startup to initialize data */
  _sidata = LOADADDR(.data);

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data : 
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */

    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */
  } >DTCMRAM AT> AXIRAM

  
  /* Uninitialized data section */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss secion */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)

    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >RAM123

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

  

  /* Remove information from the standard libraries */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }

  .ARM.attributes 0 : { *(.ARM.attributes) }
}

(Похоже, stackoverflow добавил несколько обратных косых черт.)

Мало того, что код обновления всегда зависает - он зависает в разных местах. Установив разные биты в волшебном файле cookie и изучив их после следующего сброса, я увидел, что он блокируется на ветке до UpdateContinueInit, до того, как он закончился с .bss обновления, на ветке к или внутри __libc_init_array обновления и через некоторое время после ветвления к главному обновлению.

При запуске основного по умолчанию я попробовал длинную ветвь к небольшой подпрограмме в обновлении, и это работает. Я проверил файлы списков, и установка регистра смещения векторной таблицы в SystemInit верна в обоих случаях. Попытка проверить регистры ошибок, начиная с 0xe000dc28, ничего не показала.

По умолчанию во FLASH работает нормально, если не пытаться перейти к обновлению. Я уверен, что по умолчанию обновление правильно загружается в оперативную память. Обновление выполняется правильно, если я устанавливаю регистр загрузочного адреса в isr_vector обновления, записываю обновление в ОЗУ через JTAG и перезагружаю процессор.

Я надеюсь, что кто-то успешно сделал это раньше и может указать мне на нюансы этого процессора, которые мне не хватает.

Спасибо.

0 ответов

Другие вопросы по тегам