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 и перезагружаю процессор.
Я надеюсь, что кто-то успешно сделал это раньше и может указать мне на нюансы этого процессора, которые мне не хватает.
Спасибо.