1
votes

I'm trying to use SysTick_Handler in SW4STM32 for Linux, but whenever the SysTick interrupt is triggered, execution jumps to somewhere in system memory. By my understanding, it should jump into the void SysTick_Handler(void) that I declared, or failing that, into Default_Handler declared in startup_stm32.s where the interrupt vector table is defined. I set a break point in my SysTick_Handler, but it is never reached. In the code below, it gets through init_systick() and stays in the endless for loop if I don't include SysTick_CTRL_TICKINT_Msk, as expected, but when I do include it, the debugger tells me it ends up somewhere around address 0x1fffda7c.

main.c:

#include "stm32f0xx.h"

volatile uint32_t ticks = 0;

void SysTick_Handler(void) {
    ticks++;
}

void init_systick(void) {
    SysTick->LOAD = 43999;
    SCB->SHP[1] |= 0x40000000L;
    SysTick->VAL = 0;
    SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;
}

int main(void)
{
    init_systick();
    for(;;);
}

I verified from the .map file that the linker is using the declared SysTick_Handler instead of Default_Handler.

I also tried the following variation to use the standard peripheral library for setup, along with other interrupt priority values, with the same results:

#include "stm32f0xx.h"

volatile uint32_t ticks = 0;

void SysTick_Handler(void) {
    ticks++;
}

void init_systick(void) {
    SysTick_Config(44000);
    NVIC_EnableIRQ(SysTick_IRQn);
    NVIC_SetPriority(SysTick_IRQn, 0);
}

int main(void)
{
    init_systick();
    for(;;);
}

This shouldn't be relevant, but since the target doesn't have a timing crystal, I also modified void SetSysClock(void) in system_stm32f0xx.c to use the HSI clock and PLL, which appears to be working correctly:

static void SetSysClock(void)
{
    RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_HSI;
    while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) ;
    FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;
    RCC->CR &= ~RCC_CR_PLLON;
    while (RCC->CR & RCC_CR_PLLRDY) ;
    RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_PLLMUL & ~RCC_CFGR_PLLSRC) | RCC_CFGR_PLLMUL11;   // PLL takes 8 MHz HSI / 2 as input
    RCC->CR |= RCC_CR_PLLON;
    while (!(RCC->CR & RCC_CR_PLLRDY)) ;
    RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_PLL;
    while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) ;
}

-- EDIT: More info requested in the comments --

It's an M0 core, so it doesn't have vector table relocation. From the reference manual section 2.5 (page 44):

Unlike Cortex ® M3 and M4, the M0 CPU does not support the vector table relocation.

Address 0x00000000 should be mapped either to FLASH memory at 0x08000000, system memory at 0x1fffd800, or to SRAM at 0x20000000. The memory at address 0x00000000 matches system memory at 0x1fffd800, even though SYSCFG_CFGR1 MEM_MODE is set to 00, which should map FLASH memory there. Main FLASH memory at address 0x08000000 contains the correct vector table, but address 0x00000000 is populated with address 0x1fffd99d for the SysTick vector (and all other non-NULL vectors except the reset vector, which is 0x1fffdc41); the vectors shown by the debugger at address 0x00000000 are consistent with the observed behavior. All of this information was collected while paused at a breakpoint at address 0x08000298 (a correct position in FLASH memory where the correct code has been loaded), before executing the interrupt.

3
Check not the map file, but the actual position in the vtor table0___________
Where can I find the vector table? I'm used to it being in the disassembly listing, but if SW4STM32 generates it, I can't find it.Charles The Hat
I dumped the .bin file and the vector at 0x0000003c (which should be for SysTick) contains the address that the .map file assigned to my SysTick_Handler from main.oCharles The Hat
Use the debugger. Break and see the actual value of the vector (using VTOR value)0___________
please post the disassembly of the vector table and the handler(s) in question.old_timer

3 Answers

1
votes

The VTOR is referenced in the arm-v6 reference manual. It is a good idea to check this. https://static.docs.arm.com/ddi0419/d/DDI0419D_armv6m_arm.pdf

0xE000ED08 VTOR RW 0x00000000a Vector Table Offset Register, VTOR on page B3-231

That reference manual is for the arm-v6M architecture which is the architecture for cortex-m0 processors. This is the bible. Most of the generic cortex-m0 features of the stm line will not be mentioned in stm refrenece manuals, just in the arm arm.

I'll reiterate, check the VTOR.

And make sure you are building for the right line of STM32F030!

The STM32F030x4 and STM32F030x6 micros have a different memory map than the STM32F030x8.

0
votes

This sounds like there might be a problem with the linker file.

Can you verify that your linker file has something that looks like the following? (if it is a default file it will probably be far more complex).

. = 0;
.text 0 :
{
    *(.vector);
    crt0*(.text*);
main*(.text*);
    *(.text*);
} > flash

Basically what this is saying is that the 'text' (code) of the program starts at address 0x0, and the first thing to put there is the vector table, followed by startup code, main, and then other code.

You will also then want to check that you have some file specifying this vector table's contents that also agrees it should be at address 0x0. This example is from an ATSAMD21E18A.

.section .vector, "a", %progbits

.equ stack_base, 0x20004000

.word stack_base
.word reset_handler
.word nmi_handler
.word hardfault_handler
.word 0
// ...
.word 0
.word systick_handler
// ...

The important thing is that it is marked as the section vector which the linker file will try to put at 0x0. For a processor with VTOR (like the M0+), this table might be specified in C without any special markings, and its location won't matter, but since you don't have VTOR, you need to make sure the linker knows to put this section right at 0x0.

-1
votes

According the datasheet, that region is the system memory (for built-in bootloader). You may try two things:

  1. Double check BOOTx pins to make sure the MCU loads FLASH instead of the system memory.
  2. Make sure you assigned SCB->VTOR to the correct address of your own interrupt vector table.