Author Topic: How to create ELF file which contains the normal prog, plus a relocatable block?  (Read 12621 times)

0 Members and 1 Guest are viewing this topic.

Offline gf

  • Super Contributor
  • ***
  • Posts: 1183
  • Country: de
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.
 

Offline gf

  • Super Contributor
  • ***
  • Posts: 1183
  • Country: de
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.
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3700
  • Country: gb
  • Doing electronics since the 1960s...
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.


« Last Edit: July 20, 2021, 10:08:57 pm by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3700
  • Country: gb
  • Doing electronics since the 1960s...
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!
« Last Edit: July 21, 2021, 08:41:45 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline gf

  • Super Contributor
  • ***
  • Posts: 1183
  • Country: de
Quote
Does anybody know what the "RAM AT > FLASH_BOOT" mean?

outsection : { .... } >RAM AT > FLASH_BOOT

means 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).

 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3700
  • Country: gb
  • Doing electronics since the 1960s...
OK thanks.

Could someone please take a look at my linkfile and tell me whether it makes sense, or is working by luck?

Code: [Select]
/*
*****************************************************************************
**
**  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.
« Last Edit: July 22, 2021, 09:59:44 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3700
  • Country: gb
  • Doing electronics since the 1960s...
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

Code: [Select]
    .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

Code: [Select]

  /* 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 */
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3700
  • Country: gb
  • Doing electronics since the 1960s...
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.

Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline abyrvalg

  • Frequent Contributor
  • **
  • Posts: 825
  • Country: es
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.
« Last Edit: August 23, 2021, 12:30:24 am by abyrvalg »
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3700
  • Country: gb
  • Doing electronics since the 1960s...
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.
« Last Edit: August 23, 2021, 06:40:54 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline abyrvalg

  • Frequent Contributor
  • **
  • Posts: 825
  • Country: es
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.
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3700
  • Country: gb
  • Doing electronics since the 1960s...
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

Code: [Select]
/******************************************************************************
*
* 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.
« Last Edit: August 23, 2021, 09:16:21 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline abyrvalg

  • Frequent Contributor
  • **
  • Posts: 825
  • Country: es
"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.
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3700
  • Country: gb
  • Doing electronics since the 1960s...
This is what I currently have

Code: [Select]
/* 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.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline abyrvalg

  • Frequent Contributor
  • **
  • Posts: 825
  • Country: es
"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).
« Last Edit: August 24, 2021, 11:14:29 pm by abyrvalg »
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3700
  • Country: gb
  • Doing electronics since the 1960s...
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:

Code: [Select]
   
  .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.

Code: [Select]
   
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

Code: [Select]
 
   .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?

« Last Edit: August 25, 2021, 09:51:28 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3700
  • Country: gb
  • Doing electronics since the 1960s...
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.

Code: [Select]
/*
 * 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:

Code: [Select]
/**
  ******************************************************************************
  * @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.

« Last Edit: August 26, 2021, 02:47:33 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline abyrvalg

  • Frequent Contributor
  • **
  • Posts: 825
  • Country: es
“ 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).
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3700
  • Country: gb
  • Doing electronics since the 1960s...
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.
« Last Edit: August 26, 2021, 07:32:27 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline abyrvalg

  • Frequent Contributor
  • **
  • Posts: 825
  • Country: es
Future technological singularity painted by SciFi: AIs inventing things beyond human understanding.
Singularity we are approaching in reality: AIs bloating code beyond human understanding :D
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3700
  • Country: gb
  • Doing electronics since the 1960s...
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.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline abyrvalg

  • Frequent Contributor
  • **
  • Posts: 825
  • Country: es
Nothing special. Set VTOR, enable interrupts, harvest. Check your vector table content (and actual placement/alignment) if it doesn't work.
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3700
  • Country: gb
  • Doing electronics since the 1960s...
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.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Online eutectique

  • Frequent Contributor
  • **
  • Posts: 392
  • Country: be
You can place the functions into RAM with the following line added to your .ld file:
Code: [Select]
  .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):
Code: [Select]
#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.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf