SysTick中断导致执行跳转到STM32F030上的0x1fffxxxx

时间:2018-07-03 04:04:53

标签: arm stm32 interrupt-handling

我试图在Linux的SW4STM32中使用SysTick_Handler,但是无论何时触发SysTick中断,执行都会跳转到系统内存中的某个位置。根据我的理解,它应该跳到我声明的void SysTick_Handler(void)或失败的地方,进入定义中断向量表的startup_stm32.s中声明的Default_Handler。我在SysTick_Handler中设置了一个断点,但从未达到。在下面的代码中,如果我不按预期包含init_systick(),它将通过for并停留在无尽的SysTick_CTRL_TICKINT_Msk循环中,但是当我包含它时,调试器会告诉我它结束于地址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(;;);
}

我从.map文件中验证了链接器正在使用声明的SysTick_Handler而不是Default_Handler

我还尝试了以下变体,以使用标准外设库进行设置以及其他中断优先级值,结果相同:

#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(;;);
}

这应该无关紧要,但是由于目标没有定时晶体,因此我还修改了system_stm32f0xx.c中的void SetSysClock(void)以使用HSI时钟和PLL,它们似乎正常工作: / p>

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) ;
}

-编辑:在注释中请求更多信息-

这是M0内核,因此没有向量表重定位。从参考手册第2.5节(第44页)中:

  

与Cortex®M3和M4不同,M0 CPU不支持向量表重定位。

地址0x00000000应该映射到0x08000000的FLASH存储器,0x1fffd800的系统存储器或0x20000000的SRAM。即使SYSCFG_CFGR1 MEM_MODE设置为00,地址0x00000000的内存也将与系统内存0x1fffd800的内存匹配,这会将内存映射到那里。地址为0x08000000的主FLASH存储器包含正确的向量表,但是SysTick向量(以及除复位向量为0x1fffdc41以外的所有其他非空向量)的地址0x00000000填充了地址0x1fffd99d。调试器在地址0x00000000处显示的向量与观察到的行为一致。在执行中断之前,所有这些信息都是在地址0x08000298(在FLASH存储器中已加载正确代码的正确位置)的断点处暂停时收集的。

3 个答案:

答案 0 :(得分:1)

arm-v6参考手册中引用了VTOR。对此进行检查是个好主意。 https://static.docs.arm.com/ddi0419/d/DDI0419D_armv6m_arm.pdf

  

0xE000ED08 VTOR RW 0x00000000a向量表偏移量寄存器,VTOR第B3-231页

该参考手册适用于arm-v6M架构,该架构是cortex-m0处理器的架构。这是圣经。 stm系列的大多数通用cortex-m0功能不会在stm refrenece手册中提及,只是在手臂上。

我要重申一下,检查VTOR。

并确保您正在为STM32F030做正确的选择!

STM32F030x4和STM32F030x6微处理器具有与STM32F030x8不同的内存映射。

答案 1 :(得分:0)

听起来链接器文件可能有问题。

您可以验证链接器文件是否具有类似于以下内容的文件? (如果它是默认文件,则可能会复杂得多)。

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

基本上,这是指程序的“文本”(代码)从地址0x0开始,首先要放入向量表,然后是启动代码,主代码,然后是其他代码。 / p>

然后,您还需要检查是否有一些文件指定此向量表的内容,并同意该向量表应位于地址0x0处。此示例来自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
// ...

重要的是,它被标记为链接器文件将尝试放入0x0的vector部分。对于具有VTOR的处理器(例如M0 +),此表可能在C中指定,没有任何特殊标记,并且其位置无关紧要,但是由于您没有VTOR,因此需要确保链接器知道放置此部分位于0x0。

答案 2 :(得分:-1)

根据datasheet,该区域是系统内存(用于内置引导程序)。您可以尝试两件事:

  1. 仔细检查BOOTx引脚以确保MCU加载闪存而不是系统存储器。
  2. 确保已将SCB->VTOR分配给了自己的中断向量表的正确地址。