STM32F030F4P6 仅在从闪存启动时运行中断处理程序。从引导加载程序引导时重置
STM32F030F4P6 runs interrupt handler only when booting from flash. Resets when booting from bootloader
代码 -
#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);
}
如问题中所述,当我直接从闪存(BOOT0 连接到 GND)启动时,此代码工作正常,但在使用引导加载程序时不起作用。一旦中断被引发,芯片就会重置并再次返回引导加载程序。我该如何解决这个问题?
我应该提到我使用自定义 linker script and a heavily modified boot.s.
您 运行 此微控制器中使用的 Cortex-M0 内核存在限制。
Cortex-M0 只能使用映射到地址 0x0 的中断向量 table。当微控制器配置为引导至引导加载程序时,系统内存映射到地址 0,因此引导加载程序的向量 table 用于所有中断。因此,您无法在通过引导加载程序启动的应用程序中安全地使用中断。
在 Cortex-M0+ 和更高版本上,您可以设置 SCB->VTOR
以使用位于内存其他位置的向量 table。但是,该寄存器在 Cortex-M0 部件(如 STM32F0)上不存在,因此这不适合您。
考虑使用 SWD 编程器(例如 ST-Link)来对您的微控制器进行编程,而不是使用引导加载程序。这也将允许您调试您的应用程序。
根据 duskwuffs 的评论,并且由于您指向 boot.s 和 linker.script 的链接起作用,我假设您的向量 table 仍然是来自引导加载程序的向量,并且您的应用程序中断只是跳到那里。如果您的引导加载程序没有映射到该向量 table 的 ISR,它可能只是发出重置(trap/exception 由于非法 address/instructions)。您可以使用通用向量 table 间接跳转到 RAM 提供的向量 table,并在启动代码中被您的应用程序覆盖。
代码 -
#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);
}
如问题中所述,当我直接从闪存(BOOT0 连接到 GND)启动时,此代码工作正常,但在使用引导加载程序时不起作用。一旦中断被引发,芯片就会重置并再次返回引导加载程序。我该如何解决这个问题?
我应该提到我使用自定义 linker script and a heavily modified boot.s.
您 运行 此微控制器中使用的 Cortex-M0 内核存在限制。
Cortex-M0 只能使用映射到地址 0x0 的中断向量 table。当微控制器配置为引导至引导加载程序时,系统内存映射到地址 0,因此引导加载程序的向量 table 用于所有中断。因此,您无法在通过引导加载程序启动的应用程序中安全地使用中断。
在 Cortex-M0+ 和更高版本上,您可以设置 SCB->VTOR
以使用位于内存其他位置的向量 table。但是,该寄存器在 Cortex-M0 部件(如 STM32F0)上不存在,因此这不适合您。
考虑使用 SWD 编程器(例如 ST-Link)来对您的微控制器进行编程,而不是使用引导加载程序。这也将允许您调试您的应用程序。
根据 duskwuffs 的评论,并且由于您指向 boot.s 和 linker.script 的链接起作用,我假设您的向量 table 仍然是来自引导加载程序的向量,并且您的应用程序中断只是跳到那里。如果您的引导加载程序没有映射到该向量 table 的 ISR,它可能只是发出重置(trap/exception 由于非法 address/instructions)。您可以使用通用向量 table 间接跳转到 RAM 提供的向量 table,并在启动代码中被您的应用程序覆盖。