-
#75 Reply
Posted by
gf
on 20 Jul, 2021 20:44
-
I think most here are bored with me posting files
Not bored, but sorry, had to hold back the last while due to lack of spare time - a couple of other things are waiting to be done, too.
-
#76 Reply
Posted by
gf
on 20 Jul, 2021 20:53
-
Likely you'll need to call the init from the loader. Another option is to do the initialisation from main itself and not depend on assembly. It only takes a memset and memcpy from main.
Indeed. Since the loader is not expected to know the size of the main program's .data and .bss, and the loadaddress of main's .data in flash, I'd rather tend to do it from main itself.
-
#77 Reply
Posted by
peter-h
on 20 Jul, 2021 21:41
-
I have both the loader mode, and the 'loader not needed' mode, running.
One thing I found is that the 'user application' (the bit which the loader will load from the SPI FLASH) will have to set up its RAM stuff i.e. zero bss and copy across 'data'.
Currently, the boot loader is doing that for the entire program loaded via SWD, which is fine, with the funny observation that loading the loader into RAM overwrites all that stuff, which doesn't matter because the loader does its own thing and then will always reboot the unit.
To my surprise, initialised data is being set up apparently correctly for both the FLASH code (loaded via SWD) and for the RAM based loader. The latter is done with memcpy but I had to drop in a local memcpy (and memset for the bss), from some sources I found, because the 16k bottom block has to be totally self sufficient. I've spent much of today stepping through the boot code and making sure the PC value never goes outside the 16k block
So I've put in local copies of a lot of the HAL bloatware, de-bloated somewhat.
Currently my real main (which has an entry point at 16k i.e. 0x08004000) doesn't run once one gets to more complex functions like osDelay; not sure why. Will have to poke about. The #1 candidate is 'data' but it seems to be there (I tested it with stuff like uint8_t fred[]={"abcd"} and checking it is in the right place and is actually in RAM. OTOH I am seeing initialised data from some modules appearing under 'common' and my linker script was loading these with bss, so I moved common to data, but it has not helped. Probably interrupts are buggered.
Anyway, amusingly, I am now back to what others suggested early on: putting the boot loader etc in the bottom 16k block rather than the uppermost block
Edit: interrupts were indeed messed up. It almost runs now, but RTOS doesn't start the processes.
-
#78 Reply
Posted by
peter-h
on 21 Jul, 2021 06:31
-
Well, I got some ideas from others and started digging around a particular area and found it!
I had FLASH_APP there before.
I don't know what was actually happening but _sidata (the location of initialised data
in flash from where the startup code copies it to RAM) was in RAM (0x20000000) which was obviously nonsense. It was not getting set up for main.c but was getting set up for subsequently loaded modules. No idea how...
Does anybody know what the RAM AT > FLASH_BOOT mean? I can see AT in the manual but how changing from FLASH_APP to FLASH_BOOT could change _sidata?
The fundamental learning point here - obvious in retrospect - is that any program loaded by the boot loader (into cpu flash, into ram, anywhere really)
needs to set up its own initialised data and clear its own bss. I thought I was doing that, but the linker script is impenetrable in these subtleties no matter how much I read the GCC manual.
The other thing was that a test statement like
uint8_t fred[]={"abcd"};
got optimised away and did not generate any 'data' section, unless one also puts in some crap like
uint32_t addr=&fred[0];
It still says it is not used but it doesn't remove it.
Now, according to a switch setting, I can run the loader (from RAM) or the existing FLASH based program which was loaded by SWD.
A cunning approach is to copy the entire loader into RAM (with a small assembler stub) and then it is all a lot simpler. Thank you abyrvalg for that!
-
#79 Reply
Posted by
gf
on 22 Jul, 2021 06:18
-
Does anybody know what the "RAM AT > FLASH_BOOT" mean?
outsection : { .... } >RAM AT > FLASH_BOOTmeans that
outsection's VMA is set to the next free address in the RAM region, and outsection's LMA is set to the next free address in the FLASH_BOOT region.
Then the current fill level of both regions, RAM and FLASH_BOOT is advanced by the SIZEOF(
outsection).
-
#80 Reply
Posted by
peter-h
on 22 Jul, 2021 07:41
-
OK thanks.
Could someone please take a look at my linkfile and tell me whether it makes sense, or is working by luck?
/*
*****************************************************************************
**
** File : LinkerScript.ld
**
** Author : Peter
**
** Abstract : Linker script for STM32F417VG Device with
** 1024KByte FLASH, 128KByte RAM + 64kbyte in CCM
**
**
** Target : 32F407/417
**
* 18/7/2021 PH mods to support a loader which executes at base of RAM i.e. 0x20000000.
* 21/7/21 PH loader RAM address changed to base+64k i.e. 0x20010000, and heap check removed (reason unclear but didn't
* do anything useful because the heap grows downwards at runtime anyway and the linker can't see that)
*
*
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Reference boot block stuff to ensure that it gets linked-in - not sure if these lines do anything */
EXTERN(b_main)
EXTERN(KDE_loader)
/* Highest address of the main stack. This stack is only for startup code, boot loader, and ISRs. The RTOS has its own. */
/* _estack = 0x20020000; */ /* stack in 128K RAM */
_estack = 0x10010000; /* stack in 64k CCM - note: configTOTAL_HEAP_SIZE + min_stack_size must not exceed 64k) */
/* top of RAM for _sbrk - top of heap check */
_top = 0x20020000;
/* Heap and stack sizes */
_Min_Heap_Size = 0x0000; /* 21/7/21 set to zero to prevent heap/stack conflict check from blowing up due to boot loader area */
_Min_Stack_Size = 0x4000; /* 16k stack - in CCM */
/* Specify the memory areas */
/* CCMRAM added PH 12/5/2021 - cannot use with DMA */
MEMORY
{
FLASH_BOOT (rx) : ORIGIN = 0x08000000, LENGTH = 16K
FLASH_APP (rx) : ORIGIN = 0x08004000, LENGTH = 1024K-16K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
}
/* Define output sections */
SECTIONS
{
/* loader_bss and loader sections must come first, in order to override the wildcards in subsequent sections */
loader_bss _loader_end : {
_loader_bss_start = .;
*KDE_loader.o(.bss*)
. = ALIGN(4);
_loader_bss_end = .;
}
/* RAM based loader is linked to execute here */
KDE_loader 0x20010000 : AT(_loader_loadaddr)
{
_loader_start = .;
*KDE_loader.o(.text*)
*KDE_loader.o(.rodata*)
*KDE_loader.o(.data*)
*KDE_loader.o(.common*)
*KDE_loader.o(.ARM.attributes)
. = ALIGN(4);
_loader_end = .;
}
_loader_size = SIZEOF(KDE_loader);
/* Place modules into FLASH, starting at the bottom (0x08000000)
The line "*b_main.o (.text .text* .rodata .rodata*)" is important, but for some reason
(probably the reset_handler reference) is not needed for isr_vector */
/* Startup code */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector))
. = ALIGN(4);
} >FLASH_BOOT
/* b_main.o */
.b_main.o :
{
. = ALIGN(4);
KEEP(*(.b_main.o))
*b_main.o (.text .text* .rodata .rodata*)
. = ALIGN(4);
} >FLASH_BOOT
/* === other bottom-16k stuff will go here === */
/* KDE_loader.o - goes last in the bottom block which makes it easier to check the block usage
by checking _loader_end_in_flash in the .map file */
.KDE_loader.o :
{
. = ALIGN(4);
KEEP(*(.KDE_loader.o))
*KDE_loader.o (.text .text* .rodata .rodata*)
. = ALIGN(4);
_loader_end_in_flash = .;
} >FLASH_BOOT
/* The rest of the KDE code goes here, at base+16k, starting with the real main() */
.main.o :
{
. = ALIGN(4);
KEEP(*(.main.o))
*main.o (.text .text* .rodata .rodata*)
. = ALIGN(4);
} >FLASH_APP
/* This collects all other stuff, which gets loaded into FLASH after main.o above */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.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 symbol at end of code */
} >FLASH_APP
/* .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH_APP
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH_APP */
/* 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 */
} >RAM AT >FLASH_BOOT
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* dummy placeholder in flash for loader section, to count flash usage */
.KDE_loader : {
. = . + SIZEOF(KDE_loader);
} AT >FLASH_BOOT
_loader_loadaddr = LOADADDR(.KDE_loader);
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss section */
_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;
} >RAM
/* The heap ends up after BSS in main RAM */
/* This also checks that the top of the heap doesn't hit the bottom of the stack i.e. how much RAM left */
/* User_heap_stack section, used to check that there is enough RAM left */
/* ._user_heap_stack : */
/* This check is basically disabled because _Min_Heap_Size=0 above */
.main_heap :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
/* . = . + _Min_Stack_Size; */ /* PH 14/5/2021 stack is in CCM, not here */
. = ALIGN(8);
} >RAM
/* } >CCMRAM */
/* MEMORY_bank1 section, code must be located here explicitly */
/* Example: extern int foo(void) __attribute__ ((section (".mb1text"))); */
/* Not used 14/5/2021 - was apparently used for LCD display on ST dev kit */
.memory_b1_text :
{
*(.mb1text) /* .mb1text sections (code) */
*(.mb1text*) /* .mb1text* sections (code) */
*(.mb1rodata) /* read-only data (constants) */
*(.mb1rodata*)
} >MEMORY_B1
/* CCM-RAM section
*
* IMPORTANT NOTE!
* If variables placed in this section must be zero initialized,
* the startup code needs to be modified to initialize this section.
* Done PH 12/5/2021
*/
.ccmram :
{
. = ALIGN(4);
_sccmram = .; /* create a global symbol at ccmram start */
*(.ccmram)
*(.ccmram*)
. = ALIGN(4);
_eccmram = .; /* create a global symbol at ccmram end */
} >CCMRAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
To recap, the bottom 16k is dedicated to the loader, and the RAM based portion of it (currently about 8k) gets copied to RAM at 0x20010000. The stack is at the top of CCM. The real main.c starts 16k up i.e. 0x08004000.
The data and bss stuff ends up at base of RAM i.e. 0x20000000, which is why the loader goes higher up. It is calling some functions in the bottom 16k so I don't want to screw up their data areas.
I had some problem with overlaps between the loader and the heap, which makes no practical sense since the two will never co-exist. I don't think there is any point in checking that in the linkfile, provided it is properly documented.
Some stuff in the original linkfile was related only to C++ so I removed it.
-
#81 Reply
Posted by
peter-h
on 14 Aug, 2021 20:33
-
Just an update for anyone trying to implement this.
I have been doing lots of testing on the boot loader, including corrupting the entire CPU FLASH (by writing a 1MB-32k jpeg into it
) to make sure the boot block is able to recover the working image from the serial FLASH.
Well it took a while to squash all the bugs, because the ST libs call all kinds of sh*t all over the place, and anything outside the boot block will obviously crash it. Some of the stuff was hidden in macros which actually generated code.
The funny one was in the startup... .s file which contains the standard asm init code
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
ldr sp, =_estack
/* Copy the data segment initializers from flash 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
/* Initialise CCM RAM - fills the whole CCM so don't use the stack until afterwards :) */
/* PH 15/5/2021 */
ldr r2, = 0x10000000 /* was _sccmram */
b LoopFillZeroCcm
FillZeroCcm:
movs r3, 0xaaaaaaaa /* this fill intentionally differs from the a5a5a5a5 fill used by FreeRTOS for its stacks */
str r3, [r2]
adds r2, r2, #4
LoopFillZeroCcm:
ldr r3, = 0x10010000 /* was _eccmram */
cmp r2, r3
bcc FillZeroCcm
/* Call the clock system initialization function. Moded to b_main.c*/
// bl B_SystemInit
/* Call static constructors */
/* bl B_libc_init_array */
/* Call the application's entry point - in this case the main() in the boot loader */
bl B_main
bx lr
.size Reset_Handler, .-Reset_Handler
Notice this code has its very own section .text.Reset_Handler. So with the standard linkfile this stuff will end up absolutely anywhere in the FLASH. I had to make sure it got loaded into the boot block, with this in the linkfile
/* Place modules into FLASH, starting at the bottom (0x08000000)
The line "*b_main.o (.text .text* .rodata .rodata*)" is important, but for some reason
is not needed for isr_vector */
/* Startup code */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector))
. = ALIGN(4);
} >FLASH_BOOT
.text.Reset_Handler :
{
. = ALIGN(4);
KEEP(*(.text.Reset_Handler))
*text.Reset_Handler (.text .text* .rodata .rodata*)
. = ALIGN(4);
} >FLASH_BOOT
.main.o :
{
. = ALIGN(4);
KEEP(*(.main.o))
*main.o (.text .text* .rodata .rodata*)
. = ALIGN(4);
} >FLASH_BOOT
.45dbxx.o :
{
. = ALIGN(4);
KEEP(*(.45dbxx.o))
*45dbxx.o (.text .text* .rodata .rodata*)
. = ALIGN(4);
} >FLASH_BOOT
/* === other boot block stuff will go here === */
/* loader.o - goes last in the bottom block which makes it easier to check the block usage
by checking _loader_end_in_flash in the .map file */
.loader.o :
{
. = ALIGN(4);
KEEP(*(.loader.o))
*loader.o (.text .text* .rodata .rodata*)
. = ALIGN(4);
_loader_end_in_flash = .;
} >FLASH_BOOT
/* The rest of the code goes here, loaded at base+32k */
-
#82 Reply
Posted by
peter-h
on 22 Aug, 2021 20:55
-
Just been watching this video
Around 16:30 he shows a curious way to implement a RAM resident boot loader and some inline assembler to jump to it. I can't say I understand it; perhaps he is using a compiler option to generate position-independent (relocatable) code.
-
#83 Reply
Posted by
abyrvalg
on 22 Aug, 2021 23:51
-
That thing at 16:30 is a jump from boot to the main part built as a separate binary (w/ base addr 08005000) with it's own vector table (extracting SP and PC values from it), not your case. You can find a month-old example of the same thing on the page 3 of this thread.
Edit: interesting, this construct coud fail (especially when compiled with lower optimization levels) if the compiler decides to place the app entry point var onto the stack. __set_MSP() drops the current stack frame completely, the only vars surviving are those in registers already.
-
#84 Reply
Posted by
peter-h
on 23 Aug, 2021 06:22
-
Yes; I have no idea why there is a need to change the stack pointer, just because you are jumping to another part of the same memory map.
Then, by all, means, set SP to some new value later.
But there is in any case no need to change the stack at all, from power-up. For example I set the SP to the top of the CCM at startup and just leave it there. The whole product has the stack (16k) at the top of CCM (which is 64k). Later the RTOS starts up and uses the lower 48k of CCM for its stuff. The original stack then is used only by main() and by ISRs. I fail to see any need to complicate matters.
The way I did it, I have a call (which never returns) to main() and main() is linked to be at 0x08008000 (base+32k), and it would be perfectly possible to pass parameters to main(). In fact I do pass some parms to main() but by writing them into a serial (SPI) FLASH, but that is done because they need to be nonvolatile as well.
-
#85 Reply
Posted by
abyrvalg
on 23 Aug, 2021 08:20
-
why there is a need to change the stack pointer
To have less dependencies between the bootloader and the app. App can have a completely different RAM map in his case, reusing areas previously occupied by boot. That construct essentially simulates a cold start with vector table moved to 08005000 (impossible with a true hw reset since VTOR gets reset), that’s what core does after reset - fetch SP and PC from +0 and +4 locations.
-
#86 Reply
Posted by
peter-h
on 23 Aug, 2021 09:14
-
Yes; true, although if the boot loader stack usage is insignificant, it doesn't really matter, especially if the boot loader doesn't use interrupts.
Actually I wonder how people solve the interrupt issue. The vectors reside in the bottom of the CPU FLASH
/******************************************************************************
*
* The minimal vector table for a Cortex M3. Note that the proper constructs
* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
*
*******************************************************************************/
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word MemManage_Handler
.word BusFault_Handler
.word UsageFault_Handler
.word 0
.word 0
.word 0
.word 0
.word SVC_Handler
.word DebugMon_Handler
.word 0
.word PendSV_Handler
.word SysTick_Handler
/* External Interrupts */
.word WWDG_IRQHandler /* Window WatchDog */
.word PVD_IRQHandler /* PVD through EXTI Line detection */
.word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */
.word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */
.word FLASH_IRQHandler /* FLASH */
.word RCC_IRQHandler /* RCC */
.word EXTI0_IRQHandler /* EXTI Line0 */
.word EXTI1_IRQHandler /* EXTI Line1 */
.word EXTI2_IRQHandler /* EXTI Line2 */
.word EXTI3_IRQHandler /* EXTI Line3 */
.word EXTI4_IRQHandler /* EXTI Line4 */
.word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */
.word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */
.word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */
.word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */
.word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */
.word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */
.word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */
.word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */
.word CAN1_TX_IRQHandler /* CAN1 TX */
.word CAN1_RX0_IRQHandler /* CAN1 RX0 */
.word CAN1_RX1_IRQHandler /* CAN1 RX1 */
.word CAN1_SCE_IRQHandler /* CAN1 SCE */
.word EXTI9_5_IRQHandler /* External Line[9:5]s */
.word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */
.word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */
.word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */
.word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
.word TIM2_IRQHandler /* TIM2 */
.word TIM3_IRQHandler /* TIM3 */
.word TIM4_IRQHandler /* TIM4 */
.word I2C1_EV_IRQHandler /* I2C1 Event */
.word I2C1_ER_IRQHandler /* I2C1 Error */
.word I2C2_EV_IRQHandler /* I2C2 Event */
.word I2C2_ER_IRQHandler /* I2C2 Error */
.word SPI1_IRQHandler /* SPI1 */
.word SPI2_IRQHandler /* SPI2 */
.word USART1_IRQHandler /* USART1 */
.word USART2_IRQHandler /* USART2 */
.word USART3_IRQHandler /* USART3 */
.word EXTI15_10_IRQHandler /* External Line[15:10]s */
.word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */
.word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */
.word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */
.word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */
.word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */
.word TIM8_CC_IRQHandler /* TIM8 Capture Compare */
.word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */
.word FSMC_IRQHandler /* FSMC */
.word SDIO_IRQHandler /* SDIO */
.word TIM5_IRQHandler /* TIM5 */
.word SPI3_IRQHandler /* SPI3 */
.word UART4_IRQHandler /* UART4 */
.word UART5_IRQHandler /* UART5 */
.word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */
.word TIM7_IRQHandler /* TIM7 */
.word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */
.word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */
.word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */
.word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */
.word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */
.word ETH_IRQHandler /* Ethernet */
.word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */
.word CAN2_TX_IRQHandler /* CAN2 TX */
.word CAN2_RX0_IRQHandler /* CAN2 RX0 */
.word CAN2_RX1_IRQHandler /* CAN2 RX1 */
.word CAN2_SCE_IRQHandler /* CAN2 SCE */
.word OTG_FS_IRQHandler /* USB OTG FS */
.word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */
.word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */
.word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */
.word USART6_IRQHandler /* USART6 */
.word I2C3_EV_IRQHandler /* I2C3 event */
.word I2C3_ER_IRQHandler /* I2C3 error */
.word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */
.word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */
.word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */
.word OTG_HS_IRQHandler /* USB OTG HS */
.word DCMI_IRQHandler /* DCMI */
.word 0 /* CRYP crypto */
.word HASH_RNG_IRQHandler /* Hash and Rng */
.word FPU_IRQHandler /* FPU */
/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
.weak HardFault_Handler
.thumb_set HardFault_Handler,Default_Handler
.weak MemManage_Handler
.thumb_set MemManage_Handler,Default_Handler
.weak BusFault_Handler
.thumb_set BusFault_Handler,Default_Handler
.weak UsageFault_Handler
.thumb_set UsageFault_Handler,Default_Handler
.weak SVC_Handler
.thumb_set SVC_Handler,Default_Handler
.weak DebugMon_Handler
.thumb_set DebugMon_Handler,Default_Handler
.weak PendSV_Handler
.thumb_set PendSV_Handler,Default_Handler
.weak SysTick_Handler
.thumb_set SysTick_Handler,Default_Handler
.weak WWDG_IRQHandler
.thumb_set WWDG_IRQHandler,Default_Handler
.weak PVD_IRQHandler
.thumb_set PVD_IRQHandler,Default_Handler
.weak TAMP_STAMP_IRQHandler
.thumb_set TAMP_STAMP_IRQHandler,Default_Handler
.weak RTC_WKUP_IRQHandler
.thumb_set RTC_WKUP_IRQHandler,Default_Handler
.weak FLASH_IRQHandler
.thumb_set FLASH_IRQHandler,Default_Handler
.weak RCC_IRQHandler
.thumb_set RCC_IRQHandler,Default_Handler
.weak EXTI0_IRQHandler
.thumb_set EXTI0_IRQHandler,Default_Handler
.weak EXTI1_IRQHandler
.thumb_set EXTI1_IRQHandler,Default_Handler
.weak EXTI2_IRQHandler
.thumb_set EXTI2_IRQHandler,Default_Handler
.weak EXTI3_IRQHandler
.thumb_set EXTI3_IRQHandler,Default_Handler
.weak EXTI4_IRQHandler
.thumb_set EXTI4_IRQHandler,Default_Handler
.weak DMA1_Stream0_IRQHandler
.thumb_set DMA1_Stream0_IRQHandler,Default_Handler
.weak DMA1_Stream1_IRQHandler
.thumb_set DMA1_Stream1_IRQHandler,Default_Handler
.weak DMA1_Stream2_IRQHandler
.thumb_set DMA1_Stream2_IRQHandler,Default_Handler
.weak DMA1_Stream3_IRQHandler
.thumb_set DMA1_Stream3_IRQHandler,Default_Handler
.weak DMA1_Stream4_IRQHandler
.thumb_set DMA1_Stream4_IRQHandler,Default_Handler
.weak DMA1_Stream5_IRQHandler
.thumb_set DMA1_Stream5_IRQHandler,Default_Handler
.weak DMA1_Stream6_IRQHandler
.thumb_set DMA1_Stream6_IRQHandler,Default_Handler
.weak ADC_IRQHandler
.thumb_set ADC_IRQHandler,Default_Handler
.weak CAN1_TX_IRQHandler
.thumb_set CAN1_TX_IRQHandler,Default_Handler
.weak CAN1_RX0_IRQHandler
.thumb_set CAN1_RX0_IRQHandler,Default_Handler
.weak CAN1_RX1_IRQHandler
.thumb_set CAN1_RX1_IRQHandler,Default_Handler
.weak CAN1_SCE_IRQHandler
.thumb_set CAN1_SCE_IRQHandler,Default_Handler
.weak EXTI9_5_IRQHandler
.thumb_set EXTI9_5_IRQHandler,Default_Handler
.weak TIM1_BRK_TIM9_IRQHandler
.thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler
.weak TIM1_UP_TIM10_IRQHandler
.thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler
.weak TIM1_TRG_COM_TIM11_IRQHandler
.thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler
.weak TIM1_CC_IRQHandler
.thumb_set TIM1_CC_IRQHandler,Default_Handler
.weak TIM2_IRQHandler
.thumb_set TIM2_IRQHandler,Default_Handler
.weak TIM3_IRQHandler
.thumb_set TIM3_IRQHandler,Default_Handler
.weak TIM4_IRQHandler
.thumb_set TIM4_IRQHandler,Default_Handler
.weak I2C1_EV_IRQHandler
.thumb_set I2C1_EV_IRQHandler,Default_Handler
.weak I2C1_ER_IRQHandler
.thumb_set I2C1_ER_IRQHandler,Default_Handler
.weak I2C2_EV_IRQHandler
.thumb_set I2C2_EV_IRQHandler,Default_Handler
.weak I2C2_ER_IRQHandler
.thumb_set I2C2_ER_IRQHandler,Default_Handler
.weak SPI1_IRQHandler
.thumb_set SPI1_IRQHandler,Default_Handler
.weak SPI2_IRQHandler
.thumb_set SPI2_IRQHandler,Default_Handler
.weak USART1_IRQHandler
.thumb_set USART1_IRQHandler,Default_Handler
.weak USART2_IRQHandler
.thumb_set USART2_IRQHandler,Default_Handler
.weak USART3_IRQHandler
.thumb_set USART3_IRQHandler,Default_Handler
.weak EXTI15_10_IRQHandler
.thumb_set EXTI15_10_IRQHandler,Default_Handler
.weak RTC_Alarm_IRQHandler
.thumb_set RTC_Alarm_IRQHandler,Default_Handler
.weak OTG_FS_WKUP_IRQHandler
.thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler
.weak TIM8_BRK_TIM12_IRQHandler
.thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler
.weak TIM8_UP_TIM13_IRQHandler
.thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler
.weak TIM8_TRG_COM_TIM14_IRQHandler
.thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler
.weak TIM8_CC_IRQHandler
.thumb_set TIM8_CC_IRQHandler,Default_Handler
.weak DMA1_Stream7_IRQHandler
.thumb_set DMA1_Stream7_IRQHandler,Default_Handler
.weak FSMC_IRQHandler
.thumb_set FSMC_IRQHandler,Default_Handler
.weak SDIO_IRQHandler
.thumb_set SDIO_IRQHandler,Default_Handler
.weak TIM5_IRQHandler
.thumb_set TIM5_IRQHandler,Default_Handler
.weak SPI3_IRQHandler
.thumb_set SPI3_IRQHandler,Default_Handler
.weak UART4_IRQHandler
.thumb_set UART4_IRQHandler,Default_Handler
.weak UART5_IRQHandler
.thumb_set UART5_IRQHandler,Default_Handler
.weak TIM6_DAC_IRQHandler
.thumb_set TIM6_DAC_IRQHandler,Default_Handler
.weak TIM7_IRQHandler
.thumb_set TIM7_IRQHandler,Default_Handler
.weak DMA2_Stream0_IRQHandler
.thumb_set DMA2_Stream0_IRQHandler,Default_Handler
.weak DMA2_Stream1_IRQHandler
.thumb_set DMA2_Stream1_IRQHandler,Default_Handler
.weak DMA2_Stream2_IRQHandler
.thumb_set DMA2_Stream2_IRQHandler,Default_Handler
.weak DMA2_Stream3_IRQHandler
.thumb_set DMA2_Stream3_IRQHandler,Default_Handler
.weak DMA2_Stream4_IRQHandler
.thumb_set DMA2_Stream4_IRQHandler,Default_Handler
.weak ETH_IRQHandler
.thumb_set ETH_IRQHandler,Default_Handler
.weak ETH_WKUP_IRQHandler
.thumb_set ETH_WKUP_IRQHandler,Default_Handler
.weak CAN2_TX_IRQHandler
.thumb_set CAN2_TX_IRQHandler,Default_Handler
.weak CAN2_RX0_IRQHandler
.thumb_set CAN2_RX0_IRQHandler,Default_Handler
.weak CAN2_RX1_IRQHandler
.thumb_set CAN2_RX1_IRQHandler,Default_Handler
.weak CAN2_SCE_IRQHandler
.thumb_set CAN2_SCE_IRQHandler,Default_Handler
.weak OTG_FS_IRQHandler
.thumb_set OTG_FS_IRQHandler,Default_Handler
.weak DMA2_Stream5_IRQHandler
.thumb_set DMA2_Stream5_IRQHandler,Default_Handler
.weak DMA2_Stream6_IRQHandler
.thumb_set DMA2_Stream6_IRQHandler,Default_Handler
.weak DMA2_Stream7_IRQHandler
.thumb_set DMA2_Stream7_IRQHandler,Default_Handler
.weak USART6_IRQHandler
.thumb_set USART6_IRQHandler,Default_Handler
.weak I2C3_EV_IRQHandler
.thumb_set I2C3_EV_IRQHandler,Default_Handler
.weak I2C3_ER_IRQHandler
.thumb_set I2C3_ER_IRQHandler,Default_Handler
.weak OTG_HS_EP1_OUT_IRQHandler
.thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler
.weak OTG_HS_EP1_IN_IRQHandler
.thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler
.weak OTG_HS_WKUP_IRQHandler
.thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler
.weak OTG_HS_IRQHandler
.thumb_set OTG_HS_IRQHandler,Default_Handler
.weak DCMI_IRQHandler
.thumb_set DCMI_IRQHandler,Default_Handler
.weak HASH_RNG_IRQHandler
.thumb_set HASH_RNG_IRQHandler,Default_Handler
.weak FPU_IRQHandler
.thumb_set FPU_IRQHandler,Default_Handler
I have "inherited" this project so haven't been digging into this part yet. AFAICT the ARM peripherals don't contain an ISR address register; they always go to these vectors, but since these vectors are in FLASH, the only ways to install your own handler are
- make most of the vector table point to one in RAM, which then points to where the FLASH one pointed to
- provide a means of rewriting the vector table - the whole bottom 16k block of necessity, but (I measured this) that takes only 300ms to erase and program.
But maybe the "weak" construct helps; I am not sure if it is useful when the original function is in FLASH.
-
#87 Reply
Posted by
abyrvalg
on 23 Aug, 2021 09:47
-
"although if the boot loader stack usage is insignificant, it doesn't really matter"
- you may want to change app's RAM layout radically, like placing a heap above the stack or whatever, that's about freedom to redefine those things later
- your current setup also makes all RAM regions allocated to boot vars and that part running from RAM unavailable to the main part (because everything is linked in one step and linker sees that area as occupied)
"Actually I wonder how people solve the interrupt issue"
They just don't create it. With the app part being a separate binary (like in that guy's project) it has it's own vector table (and many other things like own startup code initializing app's .data/.bss correctly) at a different flash address (08005000 in his case). All he needs to do is to change SCB->VTOR register to point to that second VT and all interrupts will land there.
-
#88 Reply
Posted by
peter-h
on 24 Aug, 2021 07:18
-
This is what I currently have
/* Configure the Vector Table location add offset address ------------------*/
#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field. This value must be a multiple of 0x200. */
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
and that seems an easy way to do it: put a copy of the existing table at the start of where the boot loader will jump to. Currently this is base+32k i.e. 0x08008000 and there is a tiny module called main_stub.c which calls (never to return) main.c and which contains no #includes etc (to make sure no code can sneak before the entry point) and which is linked to be at 0x0808000. The VT needs to be on a 0x200 boundary so I will probably put it after that call to main.c, with some suitable align directive.
Is the above SCB->VTOR assignment atomic and if not, would one do a "DI/EI" around it? Actually interrupts are not enabled at that stage anyway.
-
#89 Reply
Posted by
abyrvalg
on 24 Aug, 2021 23:02
-
"I will probably put it after that call to main.c, with some suitable align directive"
What have you decided at the end? - are you updating the main part w/o replacing the bootloader or reflashing everything?
In the 1st case you'll need to be careful with the main VT placement (to have it in the updateable part).
In the 2nd case you don't need a separate VT at all, just put all handlers into the default (boot) VT and enable interrupts when you reach main().
VTOR assignment is atomic, it is a single uint32 mem write.
BTW, even with interrupts disabled the VT still could be used by the CPU to invoke exception handlers (if something wrong happens). In some applications requiring "graceful" fault handling (i.e. motor control) it is important to think about VT life cycle (i.e. don’t leave VTOR pointing at a flash being rewritten, don’t reassign VTOR from boot to app before app’s .data/.bss init etc).
-
#90 Reply
Posted by
peter-h
on 25 Aug, 2021 06:06
-
Yes - very interesting things to consider.
I was going to have just one VT and have all the interrupt handlers in the boot block, but it may be necessary for the "user code" to hook up some interrupt and this isn't possible if the entire interrupt handling is in FLASH.
So the plan now is to create a copy of the VT at the base of the "user code" and set VTOR to point to that. And have interrupt handlers in the "user code".
I've been looking at some of the code around the VT, which ST provide, and I am not sure all of it makes sense. This is the relevant part:
.syntax unified
.cpu cortex-m4
.fpu softvfp
.thumb
.global g_pfnVectors
.global Default_Handler
/* start address for the initialization values of the .data section.
defined in linker script */
.word _sidata
/* start address for the .data section. defined in linker script */
.word _sdata
/* end address for the .data section. defined in linker script */
.word _edata
/* start address for the .bss section. defined in linker script */
.word _sbss
/* end address for the .bss section. defined in linker script */
.word _ebss
/* stack used for SystemInit_ExtMemCtl; always internal RAM used */
/**
* @brief This is the code that gets called when the processor first
* starts execution following a reset event. Only the absolutely
* necessary set is performed, after which the application
* supplied main() routine is called.
* @param None
* @retval : None
*/
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
ldr sp, =_estack
/* Copy the data segment initializers from flash to SRAM */
movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
.
.
.
.
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word MemManage_Handler
.word BusFault_Handler
.word UsageFault_Handler
.word 0
.word 0
.word 0
.word 0
.word SVC_Handler
.word DebugMon_Handler
.word 0
.word PendSV_Handler
.word SysTick_Handler
/* External Interrupts */
.word WWDG_IRQHandler /* Window WatchDog */
.word PVD_IRQHandler /* PVD through EXTI Line detection */
.word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */
.word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */
.word FLASH_IRQHandler /* FLASH */
.word RCC_IRQHandler /* RCC */
.word EXTI0_IRQHandler /* EXTI Line0 */
.word EXTI1_IRQHandler /* EXTI Line1 */
.word EXTI2_IRQHandler /* EXTI Line2 */
.word EXTI3_IRQHandler /* EXTI Line3 */
.word EXTI4_IRQHandler /* EXTI Line4 */
.word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */
.word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */
.word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */
.word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */
.word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */
.word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */
.word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */
.word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */
.word CAN1_TX_IRQHandler /* CAN1 TX */
.word CAN1_RX0_IRQHandler /* CAN1 RX0 */
.word CAN1_RX1_IRQHandler /* CAN1 RX1 */
.word CAN1_SCE_IRQHandler /* CAN1 SCE */
.word EXTI9_5_IRQHandler /* External Line[9:5]s */
.word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */
.word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */
.word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */
.word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
.word TIM2_IRQHandler /* TIM2 */
.word TIM3_IRQHandler /* TIM3 */
.word TIM4_IRQHandler /* TIM4 */
.word I2C1_EV_IRQHandler /* I2C1 Event */
.word I2C1_ER_IRQHandler /* I2C1 Error */
.word I2C2_EV_IRQHandler /* I2C2 Event */
.word I2C2_ER_IRQHandler /* I2C2 Error */
.word SPI1_IRQHandler /* SPI1 */
.word SPI2_IRQHandler /* SPI2 */
.word USART1_IRQHandler /* USART1 */
.word USART2_IRQHandler /* USART2 */
.word USART3_IRQHandler /* USART3 */
.word EXTI15_10_IRQHandler /* External Line[15:10]s */
.word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */
.word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */
.word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */
.word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */
.word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */
.word TIM8_CC_IRQHandler /* TIM8 Capture Compare */
.word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */
.word FSMC_IRQHandler /* FSMC */
.word SDIO_IRQHandler /* SDIO */
.word TIM5_IRQHandler /* TIM5 */
.word SPI3_IRQHandler /* SPI3 */
.word UART4_IRQHandler /* UART4 */
.word UART5_IRQHandler /* UART5 */
.word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */
.word TIM7_IRQHandler /* TIM7 */
.word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */
.word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */
.word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */
.word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */
.word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */
.word ETH_IRQHandler /* Ethernet */
.word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */
.word CAN2_TX_IRQHandler /* CAN2 TX */
.word CAN2_RX0_IRQHandler /* CAN2 RX0 */
.word CAN2_RX1_IRQHandler /* CAN2 RX1 */
.word CAN2_SCE_IRQHandler /* CAN2 SCE */
.word OTG_FS_IRQHandler /* USB OTG FS */
.word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */
.word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */
.word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */
.word USART6_IRQHandler /* USART6 */
.word I2C3_EV_IRQHandler /* I2C3 event */
.word I2C3_ER_IRQHandler /* I2C3 error */
.word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */
.word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */
.word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */
.word OTG_HS_IRQHandler /* USB OTG HS */
.word DCMI_IRQHandler /* DCMI */
.word 0 /* CRYP crypto */
.word HASH_RNG_IRQHandler /* Hash and Rng */
.word FPU_IRQHandler /* FPU */
/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
.weak HardFault_Handler
.thumb_set HardFault_Handler,Default_Handler
.weak MemManage_Handler
.thumb_set MemManage_Handler,Default_Handler
.weak BusFault_Handler
.thumb_set BusFault_Handler,Default_Handler
.weak UsageFault_Handler
.thumb_set UsageFault_Handler,Default_Handler
.weak SVC_Handler
.thumb_set SVC_Handler,Default_Handler
.weak DebugMon_Handler
.thumb_set DebugMon_Handler,Default_Handler
.weak PendSV_Handler
.thumb_set PendSV_Handler,Default_Handler
.weak SysTick_Handler
.thumb_set SysTick_Handler,Default_Handler
.weak WWDG_IRQHandler
.thumb_set WWDG_IRQHandler,Default_Handler
.weak PVD_IRQHandler
.thumb_set PVD_IRQHandler,Default_Handler
.weak TAMP_STAMP_IRQHandler
.thumb_set TAMP_STAMP_IRQHandler,Default_Handler
.weak RTC_WKUP_IRQHandler
.thumb_set RTC_WKUP_IRQHandler,Default_Handler
.weak FLASH_IRQHandler
.thumb_set FLASH_IRQHandler,Default_Handler
.weak RCC_IRQHandler
.thumb_set RCC_IRQHandler,Default_Handler
.weak EXTI0_IRQHandler
.thumb_set EXTI0_IRQHandler,Default_Handler
.weak EXTI1_IRQHandler
.thumb_set EXTI1_IRQHandler,Default_Handler
.weak EXTI2_IRQHandler
.thumb_set EXTI2_IRQHandler,Default_Handler
.weak EXTI3_IRQHandler
.thumb_set EXTI3_IRQHandler,Default_Handler
.weak EXTI4_IRQHandler
.thumb_set EXTI4_IRQHandler,Default_Handler
.weak DMA1_Stream0_IRQHandler
.thumb_set DMA1_Stream0_IRQHandler,Default_Handler
.weak DMA1_Stream1_IRQHandler
.thumb_set DMA1_Stream1_IRQHandler,Default_Handler
.weak DMA1_Stream2_IRQHandler
.thumb_set DMA1_Stream2_IRQHandler,Default_Handler
.weak DMA1_Stream3_IRQHandler
.thumb_set DMA1_Stream3_IRQHandler,Default_Handler
.weak DMA1_Stream4_IRQHandler
.thumb_set DMA1_Stream4_IRQHandler,Default_Handler
.weak DMA1_Stream5_IRQHandler
.thumb_set DMA1_Stream5_IRQHandler,Default_Handler
.weak DMA1_Stream6_IRQHandler
.thumb_set DMA1_Stream6_IRQHandler,Default_Handler
.weak ADC_IRQHandler
.thumb_set ADC_IRQHandler,Default_Handler
.weak CAN1_TX_IRQHandler
.thumb_set CAN1_TX_IRQHandler,Default_Handler
.weak CAN1_RX0_IRQHandler
.thumb_set CAN1_RX0_IRQHandler,Default_Handler
.weak CAN1_RX1_IRQHandler
.thumb_set CAN1_RX1_IRQHandler,Default_Handler
.weak CAN1_SCE_IRQHandler
.thumb_set CAN1_SCE_IRQHandler,Default_Handler
.weak EXTI9_5_IRQHandler
.thumb_set EXTI9_5_IRQHandler,Default_Handler
.weak TIM1_BRK_TIM9_IRQHandler
.thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler
.weak TIM1_UP_TIM10_IRQHandler
.thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler
.weak TIM1_TRG_COM_TIM11_IRQHandler
.thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler
.weak TIM1_CC_IRQHandler
.thumb_set TIM1_CC_IRQHandler,Default_Handler
.weak TIM2_IRQHandler
.thumb_set TIM2_IRQHandler,Default_Handler
.weak TIM3_IRQHandler
.thumb_set TIM3_IRQHandler,Default_Handler
.weak TIM4_IRQHandler
.thumb_set TIM4_IRQHandler,Default_Handler
.weak I2C1_EV_IRQHandler
.thumb_set I2C1_EV_IRQHandler,Default_Handler
.weak I2C1_ER_IRQHandler
.thumb_set I2C1_ER_IRQHandler,Default_Handler
.weak I2C2_EV_IRQHandler
.thumb_set I2C2_EV_IRQHandler,Default_Handler
.weak I2C2_ER_IRQHandler
.thumb_set I2C2_ER_IRQHandler,Default_Handler
.weak SPI1_IRQHandler
.thumb_set SPI1_IRQHandler,Default_Handler
.weak SPI2_IRQHandler
.thumb_set SPI2_IRQHandler,Default_Handler
.weak USART1_IRQHandler
.thumb_set USART1_IRQHandler,Default_Handler
.weak USART2_IRQHandler
.thumb_set USART2_IRQHandler,Default_Handler
.weak USART3_IRQHandler
.thumb_set USART3_IRQHandler,Default_Handler
.weak EXTI15_10_IRQHandler
.thumb_set EXTI15_10_IRQHandler,Default_Handler
.weak RTC_Alarm_IRQHandler
.thumb_set RTC_Alarm_IRQHandler,Default_Handler
.weak OTG_FS_WKUP_IRQHandler
.thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler
.weak TIM8_BRK_TIM12_IRQHandler
.thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler
.weak TIM8_UP_TIM13_IRQHandler
.thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler
.weak TIM8_TRG_COM_TIM14_IRQHandler
.thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler
.weak TIM8_CC_IRQHandler
.thumb_set TIM8_CC_IRQHandler,Default_Handler
.weak DMA1_Stream7_IRQHandler
.thumb_set DMA1_Stream7_IRQHandler,Default_Handler
.weak FSMC_IRQHandler
.thumb_set FSMC_IRQHandler,Default_Handler
.weak SDIO_IRQHandler
.thumb_set SDIO_IRQHandler,Default_Handler
.weak TIM5_IRQHandler
.thumb_set TIM5_IRQHandler,Default_Handler
.weak SPI3_IRQHandler
.thumb_set SPI3_IRQHandler,Default_Handler
.weak UART4_IRQHandler
.thumb_set UART4_IRQHandler,Default_Handler
.weak UART5_IRQHandler
.thumb_set UART5_IRQHandler,Default_Handler
.weak TIM6_DAC_IRQHandler
.thumb_set TIM6_DAC_IRQHandler,Default_Handler
.weak TIM7_IRQHandler
.thumb_set TIM7_IRQHandler,Default_Handler
.weak DMA2_Stream0_IRQHandler
.thumb_set DMA2_Stream0_IRQHandler,Default_Handler
.weak DMA2_Stream1_IRQHandler
.thumb_set DMA2_Stream1_IRQHandler,Default_Handler
.weak DMA2_Stream2_IRQHandler
.thumb_set DMA2_Stream2_IRQHandler,Default_Handler
.weak DMA2_Stream3_IRQHandler
.thumb_set DMA2_Stream3_IRQHandler,Default_Handler
.weak DMA2_Stream4_IRQHandler
.thumb_set DMA2_Stream4_IRQHandler,Default_Handler
.weak ETH_IRQHandler
.thumb_set ETH_IRQHandler,Default_Handler
.weak ETH_WKUP_IRQHandler
.thumb_set ETH_WKUP_IRQHandler,Default_Handler
.weak CAN2_TX_IRQHandler
.thumb_set CAN2_TX_IRQHandler,Default_Handler
.weak CAN2_RX0_IRQHandler
.thumb_set CAN2_RX0_IRQHandler,Default_Handler
.weak CAN2_RX1_IRQHandler
.thumb_set CAN2_RX1_IRQHandler,Default_Handler
.weak CAN2_SCE_IRQHandler
.thumb_set CAN2_SCE_IRQHandler,Default_Handler
.weak OTG_FS_IRQHandler
.thumb_set OTG_FS_IRQHandler,Default_Handler
.weak DMA2_Stream5_IRQHandler
.thumb_set DMA2_Stream5_IRQHandler,Default_Handler
.weak DMA2_Stream6_IRQHandler
.thumb_set DMA2_Stream6_IRQHandler,Default_Handler
.weak DMA2_Stream7_IRQHandler
.thumb_set DMA2_Stream7_IRQHandler,Default_Handler
.weak USART6_IRQHandler
.thumb_set USART6_IRQHandler,Default_Handler
.weak I2C3_EV_IRQHandler
.thumb_set I2C3_EV_IRQHandler,Default_Handler
.weak I2C3_ER_IRQHandler
.thumb_set I2C3_ER_IRQHandler,Default_Handler
.weak OTG_HS_EP1_OUT_IRQHandler
.thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler
.weak OTG_HS_EP1_IN_IRQHandler
.thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler
.weak OTG_HS_WKUP_IRQHandler
.thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler
.weak OTG_HS_IRQHandler
.thumb_set OTG_HS_IRQHandler,Default_Handler
.weak DCMI_IRQHandler
.thumb_set DCMI_IRQHandler,Default_Handler
.weak HASH_RNG_IRQHandler
.thumb_set HASH_RNG_IRQHandler,Default_Handler
.weak FPU_IRQHandler
.thumb_set FPU_IRQHandler,Default_Handler
Now, AIUI, on reset, the CPU loads SP from the base word in the VT and jumps to the address in base+4 of the VT (the second word). So why do they have
ldr sp, =_estack
at the start of the reset handler? Surely it doesn't do anything useful.
Also it seems to me that while interrupts are disabled (in the boot block) the only portion of the VT which is needed is the first part i.e.
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word MemManage_Handler
.word BusFault_Handler
.word UsageFault_Handler
because the other events cannot possibly occur. Is this correct?
And similarly, the VT in the "user code" doesn't really need the first two entries
.word _estack
.word Reset_Handler
because a) the SP is already set up and b) if the CPU is reset then VT base is reset to 0x08000000 so neither of these (in fact the entire 2nd VT) will get referenced. OTOH one has to have "something" in these locations because (after VTOR is set up to point at this VT) the CPU is expecting all the subsequent vectors to be appropriately offset, but they could just be two words of zero. IOW the first two VT entries are never referenced in any VT that has been relocated - AIUI.
Does this make sense?
-
#91 Reply
Posted by
peter-h
on 25 Aug, 2021 21:44
-
A related Q, to which any amount of googling on boot loaders doesn't stop interrupts from crashing as soon as they get enabled:
base of flash (boot loader): 0x08000000
base of user app: 0x08008000 (base+32k)
At base+32k I have the entry point which is just a reflection to main(). This is deffo right because code after it runs etc and has done for ages.
Then at 0x08008000 + 0x200 I have the user app vector table (which has to be 0x200-aligned) i.e.
SCB->VTOR = 0x08008200;
and the table is in the .map file in the right place too.
Is this correct?
Is there anything else which needs setting up to get the CPU to vector via the relocated table?
EDIT: SOLVED. But no idea why. What was needed was default_handler to be at the end of the relocated table. That sits in a separate asm file.
/*
* vectab2.s
*
* Created on: 25 Aug 2021
* Author: peter
*
* This table is at the start of customer code. Goes right after main_stub entry point.
* Must be 0x200 aligned.
*
*/
.section .isr_vector2,"a",%progbits
.type g_Vectors2, %object
.size g_Vectors2, .-g_Vectors2
/* 25/8/21 PH copied from startup_stm32f407.s */
/**
* @brief This is the code that gets called when the processor receives an
* unexpected interrupt. This simply enters an infinite loop, preserving
* the system state for examination by a debugger.
* @param None
* @retval None
*/
/* The first two will never get used. This vector table is activated by setting VTOR to point to it
and a reset will reset VTOR to 0. Also the _estack entry is redundant since SP is already set to
top of CCM.
*/
g_Vectors2:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word MemManage_Handler
.word BusFault_Handler
.word UsageFault_Handler
.word 0
.word 0
.word 0
.word 0
.word SVC_Handler
.word DebugMon_Handler
.word 0
.word PendSV_Handler
.word SysTick_Handler
/* External Interrupts */
.word WWDG_IRQHandler /* Window WatchDog */
.word PVD_IRQHandler /* PVD through EXTI Line detection */
.word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */
.word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */
.word FLASH_IRQHandler /* FLASH */
.word RCC_IRQHandler /* RCC */
.word EXTI0_IRQHandler /* EXTI Line0 */
.word EXTI1_IRQHandler /* EXTI Line1 */
.word EXTI2_IRQHandler /* EXTI Line2 */
.word EXTI3_IRQHandler /* EXTI Line3 */
.word EXTI4_IRQHandler /* EXTI Line4 */
.word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */
.word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */
.word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */
.word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */
.word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */
.word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */
.word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */
.word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */
.word CAN1_TX_IRQHandler /* CAN1 TX */
.word CAN1_RX0_IRQHandler /* CAN1 RX0 */
.word CAN1_RX1_IRQHandler /* CAN1 RX1 */
.word CAN1_SCE_IRQHandler /* CAN1 SCE */
.word EXTI9_5_IRQHandler /* External Line[9:5]s */
.word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */
.word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */
.word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */
.word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
.word TIM2_IRQHandler /* TIM2 */
.word TIM3_IRQHandler /* TIM3 */
.word TIM4_IRQHandler /* TIM4 */
.word I2C1_EV_IRQHandler /* I2C1 Event */
.word I2C1_ER_IRQHandler /* I2C1 Error */
.word I2C2_EV_IRQHandler /* I2C2 Event */
.word I2C2_ER_IRQHandler /* I2C2 Error */
.word SPI1_IRQHandler /* SPI1 */
.word SPI2_IRQHandler /* SPI2 */
.word USART1_IRQHandler /* USART1 */
.word USART2_IRQHandler /* USART2 */
.word USART3_IRQHandler /* USART3 */
.word EXTI15_10_IRQHandler /* External Line[15:10]s */
.word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */
.word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */
.word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */
.word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */
.word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */
.word TIM8_CC_IRQHandler /* TIM8 Capture Compare */
.word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */
.word FSMC_IRQHandler /* FSMC */
.word SDIO_IRQHandler /* SDIO */
.word TIM5_IRQHandler /* TIM5 */
.word SPI3_IRQHandler /* SPI3 */
.word UART4_IRQHandler /* UART4 */
.word UART5_IRQHandler /* UART5 */
.word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */
.word TIM7_IRQHandler /* TIM7 */
.word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */
.word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */
.word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */
.word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */
.word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */
.word ETH_IRQHandler /* Ethernet */
.word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */
.word CAN2_TX_IRQHandler /* CAN2 TX */
.word CAN2_RX0_IRQHandler /* CAN2 RX0 */
.word CAN2_RX1_IRQHandler /* CAN2 RX1 */
.word CAN2_SCE_IRQHandler /* CAN2 SCE */
.word OTG_FS_IRQHandler /* USB OTG FS */
.word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */
.word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */
.word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */
.word USART6_IRQHandler /* USART6 */
.word I2C3_EV_IRQHandler /* I2C3 event */
.word I2C3_ER_IRQHandler /* I2C3 error */
.word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */
.word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */
.word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */
.word OTG_HS_IRQHandler /* USB OTG HS */
.word DCMI_IRQHandler /* DCMI */
.word 0 /* CRYP crypto */
.word HASH_RNG_IRQHandler /* Hash and Rng */
.word FPU_IRQHandler /* FPU */
/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
.weak HardFault_Handler
.thumb_set HardFault_Handler,Default_Handler
.weak MemManage_Handler
.thumb_set MemManage_Handler,Default_Handler
.weak BusFault_Handler
.thumb_set BusFault_Handler,Default_Handler
.weak UsageFault_Handler
.thumb_set UsageFault_Handler,Default_Handler
.weak SVC_Handler
.thumb_set SVC_Handler,Default_Handler
.weak DebugMon_Handler
.thumb_set DebugMon_Handler,Default_Handler
.weak PendSV_Handler
.thumb_set PendSV_Handler,Default_Handler
.weak SysTick_Handler
.thumb_set SysTick_Handler,Default_Handler
.weak WWDG_IRQHandler
.thumb_set WWDG_IRQHandler,Default_Handler
.weak PVD_IRQHandler
.thumb_set PVD_IRQHandler,Default_Handler
.weak TAMP_STAMP_IRQHandler
.thumb_set TAMP_STAMP_IRQHandler,Default_Handler
.weak RTC_WKUP_IRQHandler
.thumb_set RTC_WKUP_IRQHandler,Default_Handler
.weak FLASH_IRQHandler
.thumb_set FLASH_IRQHandler,Default_Handler
.weak RCC_IRQHandler
.thumb_set RCC_IRQHandler,Default_Handler
.weak EXTI0_IRQHandler
.thumb_set EXTI0_IRQHandler,Default_Handler
.weak EXTI1_IRQHandler
.thumb_set EXTI1_IRQHandler,Default_Handler
.weak EXTI2_IRQHandler
.thumb_set EXTI2_IRQHandler,Default_Handler
.weak EXTI3_IRQHandler
.thumb_set EXTI3_IRQHandler,Default_Handler
.weak EXTI4_IRQHandler
.thumb_set EXTI4_IRQHandler,Default_Handler
.weak DMA1_Stream0_IRQHandler
.thumb_set DMA1_Stream0_IRQHandler,Default_Handler
.weak DMA1_Stream1_IRQHandler
.thumb_set DMA1_Stream1_IRQHandler,Default_Handler
.weak DMA1_Stream2_IRQHandler
.thumb_set DMA1_Stream2_IRQHandler,Default_Handler
.weak DMA1_Stream3_IRQHandler
.thumb_set DMA1_Stream3_IRQHandler,Default_Handler
.weak DMA1_Stream4_IRQHandler
.thumb_set DMA1_Stream4_IRQHandler,Default_Handler
.weak DMA1_Stream5_IRQHandler
.thumb_set DMA1_Stream5_IRQHandler,Default_Handler
.weak DMA1_Stream6_IRQHandler
.thumb_set DMA1_Stream6_IRQHandler,Default_Handler
.weak ADC_IRQHandler
.thumb_set ADC_IRQHandler,Default_Handler
.weak CAN1_TX_IRQHandler
.thumb_set CAN1_TX_IRQHandler,Default_Handler
.weak CAN1_RX0_IRQHandler
.thumb_set CAN1_RX0_IRQHandler,Default_Handler
.weak CAN1_RX1_IRQHandler
.thumb_set CAN1_RX1_IRQHandler,Default_Handler
.weak CAN1_SCE_IRQHandler
.thumb_set CAN1_SCE_IRQHandler,Default_Handler
.weak EXTI9_5_IRQHandler
.thumb_set EXTI9_5_IRQHandler,Default_Handler
.weak TIM1_BRK_TIM9_IRQHandler
.thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler
.weak TIM1_UP_TIM10_IRQHandler
.thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler
.weak TIM1_TRG_COM_TIM11_IRQHandler
.thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler
.weak TIM1_CC_IRQHandler
.thumb_set TIM1_CC_IRQHandler,Default_Handler
.weak TIM2_IRQHandler
.thumb_set TIM2_IRQHandler,Default_Handler
.weak TIM3_IRQHandler
.thumb_set TIM3_IRQHandler,Default_Handler
.weak TIM4_IRQHandler
.thumb_set TIM4_IRQHandler,Default_Handler
.weak I2C1_EV_IRQHandler
.thumb_set I2C1_EV_IRQHandler,Default_Handler
.weak I2C1_ER_IRQHandler
.thumb_set I2C1_ER_IRQHandler,Default_Handler
.weak I2C2_EV_IRQHandler
.thumb_set I2C2_EV_IRQHandler,Default_Handler
.weak I2C2_ER_IRQHandler
.thumb_set I2C2_ER_IRQHandler,Default_Handler
.weak SPI1_IRQHandler
.thumb_set SPI1_IRQHandler,Default_Handler
.weak SPI2_IRQHandler
.thumb_set SPI2_IRQHandler,Default_Handler
.weak USART1_IRQHandler
.thumb_set USART1_IRQHandler,Default_Handler
.weak USART2_IRQHandler
.thumb_set USART2_IRQHandler,Default_Handler
.weak USART3_IRQHandler
.thumb_set USART3_IRQHandler,Default_Handler
.weak EXTI15_10_IRQHandler
.thumb_set EXTI15_10_IRQHandler,Default_Handler
.weak RTC_Alarm_IRQHandler
.thumb_set RTC_Alarm_IRQHandler,Default_Handler
.weak OTG_FS_WKUP_IRQHandler
.thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler
.weak TIM8_BRK_TIM12_IRQHandler
.thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler
.weak TIM8_UP_TIM13_IRQHandler
.thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler
.weak TIM8_TRG_COM_TIM14_IRQHandler
.thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler
.weak TIM8_CC_IRQHandler
.thumb_set TIM8_CC_IRQHandler,Default_Handler
.weak DMA1_Stream7_IRQHandler
.thumb_set DMA1_Stream7_IRQHandler,Default_Handler
.weak FSMC_IRQHandler
.thumb_set FSMC_IRQHandler,Default_Handler
.weak SDIO_IRQHandler
.thumb_set SDIO_IRQHandler,Default_Handler
.weak TIM5_IRQHandler
.thumb_set TIM5_IRQHandler,Default_Handler
.weak SPI3_IRQHandler
.thumb_set SPI3_IRQHandler,Default_Handler
.weak UART4_IRQHandler
.thumb_set UART4_IRQHandler,Default_Handler
.weak UART5_IRQHandler
.thumb_set UART5_IRQHandler,Default_Handler
.weak TIM6_DAC_IRQHandler
.thumb_set TIM6_DAC_IRQHandler,Default_Handler
.weak TIM7_IRQHandler
.thumb_set TIM7_IRQHandler,Default_Handler
.weak DMA2_Stream0_IRQHandler
.thumb_set DMA2_Stream0_IRQHandler,Default_Handler
.weak DMA2_Stream1_IRQHandler
.thumb_set DMA2_Stream1_IRQHandler,Default_Handler
.weak DMA2_Stream2_IRQHandler
.thumb_set DMA2_Stream2_IRQHandler,Default_Handler
.weak DMA2_Stream3_IRQHandler
.thumb_set DMA2_Stream3_IRQHandler,Default_Handler
.weak DMA2_Stream4_IRQHandler
.thumb_set DMA2_Stream4_IRQHandler,Default_Handler
.weak ETH_IRQHandler
.thumb_set ETH_IRQHandler,Default_Handler
.weak ETH_WKUP_IRQHandler
.thumb_set ETH_WKUP_IRQHandler,Default_Handler
.weak CAN2_TX_IRQHandler
.thumb_set CAN2_TX_IRQHandler,Default_Handler
.weak CAN2_RX0_IRQHandler
.thumb_set CAN2_RX0_IRQHandler,Default_Handler
.weak CAN2_RX1_IRQHandler
.thumb_set CAN2_RX1_IRQHandler,Default_Handler
.weak CAN2_SCE_IRQHandler
.thumb_set CAN2_SCE_IRQHandler,Default_Handler
.weak OTG_FS_IRQHandler
.thumb_set OTG_FS_IRQHandler,Default_Handler
.weak DMA2_Stream5_IRQHandler
.thumb_set DMA2_Stream5_IRQHandler,Default_Handler
.weak DMA2_Stream6_IRQHandler
.thumb_set DMA2_Stream6_IRQHandler,Default_Handler
.weak DMA2_Stream7_IRQHandler
.thumb_set DMA2_Stream7_IRQHandler,Default_Handler
.weak USART6_IRQHandler
.thumb_set USART6_IRQHandler,Default_Handler
.weak I2C3_EV_IRQHandler
.thumb_set I2C3_EV_IRQHandler,Default_Handler
.weak I2C3_ER_IRQHandler
.thumb_set I2C3_ER_IRQHandler,Default_Handler
.weak OTG_HS_EP1_OUT_IRQHandler
.thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler
.weak OTG_HS_EP1_IN_IRQHandler
.thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler
.weak OTG_HS_WKUP_IRQHandler
.thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler
.weak OTG_HS_IRQHandler
.thumb_set OTG_HS_IRQHandler,Default_Handler
.weak DCMI_IRQHandler
.thumb_set DCMI_IRQHandler,Default_Handler
.weak HASH_RNG_IRQHandler
.thumb_set HASH_RNG_IRQHandler,Default_Handler
.weak FPU_IRQHandler
.thumb_set FPU_IRQHandler,Default_Handler
.section .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.size Default_Handler, .-Default_Handler
Previously, default_handler was in the boot block, which now contains a much abbreviated vector table since all interrupts are disabled in the boot block:
/**
******************************************************************************
* @file startup_stm32f407xx.s
* @author MCD Application Team
* @brief STM32F407xx Devices vector table for GCC based toolchains.
* This module performs:
* - Set the initial SP
* - Set the initial PC == Reset_Handler,
* - Set the vector table entries with the exceptions ISR address
* - Branches to main in the C library (which eventually
* calls main()).
* After Reset the Cortex-M4 processor is in Thread mode,
* priority is Privileged, and the Stack is set to Main.
*
* MODDED 17/5/2021 PH for CCM zeroing.
* 19/7/21 PH main() changed to B_main()
* 5/8/21 PH SystemInit() call moved to b_main.c
* 25/8/21 PH Vector table truncated and the whole one copied to vectab2.s
*
*
*/
.syntax unified
.cpu cortex-m4
.fpu softvfp
.thumb
.global g_pfnVectors
.global Default_Handler
/* start address for the initialization values of the .data section.
defined in linker script */
.word _sidata
/* start address for the .data section. defined in linker script */
.word _sdata
/* end address for the .data section. defined in linker script */
.word _edata
/* start address for the .bss section. defined in linker script */
.word _sbss
/* end address for the .bss section. defined in linker script */
.word _ebss
/* stack used for SystemInit_ExtMemCtl; always internal RAM used */
/**
* @brief This is the code that gets called when the processor first
* starts execution following a reset event. Only the absolutely
* necessary set is performed, after which the application
* supplied main() routine is called.
* @param None
* @retval : None
*/
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
ldr sp, =_estack
/* Copy the data segment initializers from flash 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
/* Initialise CCM RAM - fills the whole CCM so don't use the stack until afterwards :) */
/* PH 15/5/2021 */
ldr r2, = 0x10000000 /* was _sccmram */
b LoopFillZeroCcm
FillZeroCcm:
movs r3, 0xaaaaaaaa /* this fill intentionally differs from the a5a5a5a5 fill used by FreeRTOS for its stacks */
str r3, [r2]
adds r2, r2, #4
LoopFillZeroCcm:
ldr r3, = 0x10010000 /* was _eccmram */
cmp r2, r3
bcc FillZeroCcm
/* Call the clock system initialization function. Moded to b_main.c*/
// bl B_SystemInit
/* Call static constructors */
/* bl B_libc_init_array */
/* Call the application's entry point - in this case the main() in the boot loader */
bl B_main
bx lr
.size Reset_Handler, .-Reset_Handler
/******************************************************************************
*
* The minimal vector table for a Cortex M3. Note that the proper constructs
* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
*
*******************************************************************************/
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
/* 25/8/21 PH truncated to just those which could be activated from the boot block */
g_pfnVectors:
.word _estack
.word Reset_Handler
.word B_NMI_Handler
.word B_HardFault_Handler
.word B_MemManage_Handler
.word B_BusFault_Handler
.word B_UsageFault_Handler
/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/
/*
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
.weak HardFault_Handler
.thumb_set HardFault_Handler,Default_Handler
.weak MemManage_Handler
.thumb_set MemManage_Handler,Default_Handler
.weak BusFault_Handler
.thumb_set BusFault_Handler,Default_Handler
.weak UsageFault_Handler
.thumb_set UsageFault_Handler,Default_Handler
*/
TBH I don't understand the above default_handler stuff, especially why having that endless loop there makes it work, because if that trap was ever entered then obviously the thing would stay there, but I have the whole thing running perfectly, RTOS and all.
Maybe the boot block code needs its own default_handler also? I've spent hours reading about this stuff and this handler is supposed to trap any interrupts which are not defined in the table, or perhaps invalid opcodes so basically any attempt to execute a nonexistent ISR.
Also there isn't, and never was, a section in the linkfile for default_handler, so that loop isn't getting located anywhere. Could it be that without the default_handler being there, the compiler was optimising out much of the vector table, and that would obviously screw up int servicing
I thought asm (in a .s file especially) would never be optimised out, although I have read stuff to the contrary.
-
#92 Reply
Posted by
abyrvalg
on 26 Aug, 2021 06:54
-
“ What was needed was default_handler to be at the end of the relocated table”
And where it was before (when the code wasn’t working)? If you’ve placed it i.e. before the VT declaration in the same section - it would shift entire VT placement.
BTW, all those WEAKs in startup hinder some types of optimizations (-flto).
-
#93 Reply
Posted by
peter-h
on 26 Aug, 2021 07:19
-
The default_handler was in the boot block VT.
Moving it to the "user code" VT fixed the issue. I still don't know how but probably the VT weaks had to point somewhere.
It is in its own named section, which the linker would not have processed, so would not have affected the VT location - either VT - and I checked that the VT location was correct by looking at the .map file
and by doing memory examination.
Those "weak" thingies are from STM. I can sort of see how that system works but got rid of it in the boot block VT and made the handlers explicit functions (containing just while(1){} ) in the boot block, so exceptions enable the debugger to end up somewhere obvious. In the "user block", exceptions are handled by the same empty functions but residing in the ST HAL code.
So the only point of the "weaks" is a lazy way of setting up new ISRs
without having to edit that vector table file, which
is valid for user code but not for the boot block which has ints disabled. TBH I have not looked at int handling in the ST HAL yet; it looks like a lot of it goes to some huge function which picks its way through the int sources to find out who did it
I think 93.4% of stuff posted all over the internet, by desperate people trying to get STM stuff to work, is the result of shitty convoluted STM code which most "normal" embedded people don't understand. And there is no documentation! It was created to make life easy for those very people but it made it very hard to customise the code. For example google on STM 32F4 VTOR and see how many people struggle.
-
#94 Reply
Posted by
abyrvalg
on 26 Aug, 2021 07:50
-
Future technological singularity painted by SciFi: AIs inventing things beyond human understanding.
Singularity we are approaching in reality: AIs bloating code beyond human understanding
-
#95 Reply
Posted by
peter-h
on 26 Aug, 2021 20:06
-
Is there anything special that needs doing around the VTOR value loading?
The RM says nothing, but I've seen some stuff online where people used inline asm to flush the CPU cache, and such like.
-
#96 Reply
Posted by
abyrvalg
on 26 Aug, 2021 21:07
-
Nothing special. Set VTOR, enable interrupts, harvest. Check your vector table content (and actual placement/alignment) if it doesn't work.
-
#97 Reply
Posted by
peter-h
on 26 Aug, 2021 21:27
-
It does all work fine. I just had something "funny" around that VTOR loading line. It didn't come back and I suspect it was something funny with Cube which sometimes leaves breakpoints around, active, without displaying them. The only way to find them is Windows -> Show View -> Breakpoints. Didn't happen again.
-
#98 Reply
Posted by
eutectique
on 04 Mar, 2022 19:40
-
You can place the functions into RAM with the following line added to your .ld file:
.data : AT ( _sidata )
{
. = ALIGN(4);
_sdata = .;
*(.ramfunc .ramfunc.*) <----- ADD THIS
*(.data)
_edata = .;
} > RAM
...
and the following line in your code (or something similar to that effect depending on your compiler):
#define RAMFUNC __attribute__ ((section(".ramfunc")))
Then decorate whichever functions and data with RAMFUNC, and you are there. As I can see, this has already been suggested.
You would probably want to reclaim the RAM in case you don't use RAM functions. Then there is OVERLAY command in ld linker script. I've never needed one myself, but google brings quite a few examples.
Or you could probably want to have the piece of code and data in RAM to be completely independent from your main app, and yet linked into the app. Then you can add it as a subdirectory (subproject, whatever), add the rules to your overall Makefile so that the app depends on this sub-thing, and let the toolchain build both and combine them in one hex or srec file.