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