2

The code -

#include<stm32f030x6.h>

void _delay_ms(unsigned int del) {
  //Delay with systick
}

void sys_init() {
  //Set Clock to 6 * 8MHz crystal
}

void TIM14_IRQHandler(void) {
  //If UEV was generated, toggle PA4 (Connected to LED)
  if(TIM14->SR & TIM_SR_UIF) {
    GPIOA->BSRR = (GPIOA->ODR & GPIO_ODR_4)?(GPIO_BSRR_BR_4):(GPIO_BSRR_BS_4);
    TIM14->SR &= ~TIM_SR_UIF;
  }
}


int main(void) {
  sys_init();
  RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
  RCC->APB1ENR |= RCC_APB1ENR_TIM14EN;

  GPIOA->MODER = 0b1 << GPIO_MODER_MODER4_Pos;
  //GPIOA->AFR[0] = 4 << GPIO_AFRL_AFRL4_Pos;

  //Init timer
  TIM14->ARR = 731;
  TIM14->PSC = 0xffff;
  TIM14->DIER |= TIM_DIER_UIE;
  TIM14->CR1 |= TIM_CR1_CEN;

  NVIC_EnableIRQ(TIM14_IRQn);
  NVIC_SetPriority(TIM14_IRQn, 0);

  while(1);
}

As mentioned in the question, this code works just fine when I directly boot it off of the flash (BOOT0 connected to GND), but it does not work when using the bootloader. As soon as the interrupt is raised, the chip resets and lands back into the bootloader again. How can I fix this?
I should mention that I use a custom linker script and a heavily modified boot.s.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Shahe Ansar
  • 314
  • 2
  • 12

2 Answers2

3

You have run into a limitation of the Cortex-M0 core used in this microcontroller.

The Cortex-M0 can only use an interrupt vector table which is mapped at address 0x0. When the microcontroller is configured to boot to the bootloader, system memory is mapped at address 0, so the bootloader's vector table is used for all interrupts. As a result, you cannot safely use interrupts in an application launched through the bootloader.

On Cortex-M0+ and higher parts, you can set SCB->VTOR to use a vector table located elsewhere in memory. However, this register does not exist on Cortex-M0 parts, like the STM32F0, so this isn't an option for you.

Consider using a SWD programmer, like the ST-Link, to program your microcontroller instead of the bootloader. This will also allow you to debug your application.

  • Thanks for the answer. I knew you couldn't offset the vector table, but didn't know that you couldn't execute interrupts, since you can run the reset handler just fine in bootloader mode (With stm32flash -g 0) – Shahe Ansar Feb 25 '19 at 02:36
  • 1
    I haven't investigated specifically, but I suspect that's not actually happening as an interrupt. The STM32 bootloader protocol doesn't have a "reset into flash" command. It does have a "jump to address" command, but the address is provided with the command; `stm32flash` may be reading the reset vector out of the binary. –  Feb 25 '19 at 02:39
  • 3
    Although the vector table must start at address 0, the MCU can map internal RAM there, so an application can copy the vector table to the beginning of RAM, and change the mapping in `SYSCFG` to have the MCU use the new vector table. – followed Monica to Codidact Feb 25 '19 at 09:51
2

According to duskwuffs comments, and since your links to boot.s and linker.script to do work, I assume, your vector table is still the one from the bootloader, and your application interrupt just jumps there. If your bootloader has no ISR mapped at that vector table, it might just issue a reset then (trap/exception due to illegal address/instructions). You might be able to have a generic vector table to indirectly jump to a RAM provided vector table, overwritten by your application in the startup code.

kesselhaus
  • 1,241
  • 8
  • 9