配置优先级位分配后如何诊断不精确的总线故障,Cortex M3 STM32F10x w uC / OS-III

时间:2014-02-08 20:14:40

标签: exception embedded arm interrupt cortex-m3

我在为ST Microelectronics STM32F103(ARM Cortex-M3 r1p1)编写的应用程序中遇到了问题。 RTOS是uC / OS-III;开发环境是IAR EWARM v.6.44;它还使用ST标准外设库v.1.0.1。

该应用不是新的;它已经在开发和现场至少一年。它使用两个UART,I2C和一个或两个定时器。最近我决定审查中断优先级分配,并重新安排优先级作为审查的一部分(事情似乎工作得很好)。

我发现在初始化代码中没有显式分配组和子优先级位,包括RTOS,因此使应用程序与另一个应用程序(相同产品,不同处理器)和新优先级方案保持一致,我添加了对NVIC_PriorityGroupConfig()的调用,传入了NVIC_PriorityGroup_2。这将应用程序中断和复位控制寄存器(AIRCR)中的PRIGROUP值设置为5,为组(抢占)优先级分配2位,为子优先级分配2位。

执行此操作后,我在执行时得到一个不精确的总线故障异常,而不是立即,但此后很快。 (更多关于我怀疑它何时发生的地方。)由于它不精确(BFSR.IMPRECISERR断言),因此在BFAR中没有任何用处(BFSR.BFARVALID清除)。

STM32F系列组实现4位优先级。虽然我没有在任何地方发现这提到明确,但它显然是优先级最重要的nybble。这个假设似乎通过文档中给出的PRIGROUP表进行了验证(第134页,STM32F10xxx / 20xxx / 21xxx / L1xxx Cortex-M3编程手册(Doc 15491,Rev 5),第4.4.5节,应用程序中断和控制寄存器( SCB_AIRCR),表45,优先级分组,第134页。

在ARM方案中,优先级值包括一定数量的组或抢占优先级位和一些子优先级位。组优先级位是高位;次优先级较低。 3位AIRCR.PRIGROUP值控制如何定义每个位的分配。 PRIGROUP = 0配置7位组优先级和1位子优先级; PRIGROUP = 7配置0位组优先级和8位子优先级(因此优先级都是子优先级,并且对于具有可设置优先级的异常不会发生抢占)。

AIRCR.PRIGROUP的重置值定义为0。

对于STM32F10x,由于只实现了高4位,因此似乎PRIGROUP = 0,1,2,3应该都是等价的,因为它们都对应于> = 4位组优先级。 / p>

考虑到这一假设,我还尝试使用值NVIC_PriorityGroup_4调用NVIC_PriorityGroupConfig(),该值对应于PRIGROUP值3(4位组优先级,无子优先级)。

此更改会导致总线故障异常。

不幸的是,我相信STM32F103是r1p1,因此没有实现辅助控制寄存器(ACTLR;在r2p0中引入),因此我无法尝试DISDEFWBUF位(在默认情况下禁止使用写缓冲区)存储器映射访问,使所有总线故障精确,但会降低性能)。

我几乎可以肯定,ISR中发生了总线故障,很可能是在UART ISR中。我在代码中的某个特定位置设置了一个断点,启动了应用程序,并在执行到达断点之前发生了总线故障;但是,如果我在调试器中单步执行代码,我可以到达并超过该断点的位置,如果我允许它从那里执行,我会在继续之后看到总线故障一段时间。

下一步将尝试确定ISR产生总线故障的原因,以便我可以检测它和/或尝试捕获它的调用并逐步完成它。

所以我的问题是:

1)任何人都有任何关于如何更智能地识别不精确的总线故障异常来源的建议吗?

2)当PRIGROUP = 0是复位默认值时,为什么设置PRIGROUP = 3会改变系统的行为?(PRIGROUP = 0表示7位组,1位子优先级; PRIGROUP = 3表示4比特组,4比特子优先级; STM32F10x仅实现高4位优先级。)

很多,非常感谢所有人提前获得任何见解或非空指针!

(当然,如果我事先弄明白的话,我会用任何可能对遇到同类情景的人有用的信息更新这篇文章。)

1 个答案:

答案 0 :(得分:1)

即使BFAR无效,您仍然可以读取总线故障ISR中的其他相关寄存器:

void HardFault_Handler_C(unsigned int* hardfault_args)
{
    printf("R0    = 0x%.8X\r\n",hardfault_args[0]);         
    printf("R1    = 0x%.8X\r\n",hardfault_args[1]);         
    printf("R2    = 0x%.8X\r\n",hardfault_args[2]);         
    printf("R3    = 0x%.8X\r\n",hardfault_args[3]);         
    printf("R12   = 0x%.8X\r\n",hardfault_args[4]);         
    printf("LR    = 0x%.8X\r\n",hardfault_args[5]);         
    printf("PC    = 0x%.8X\r\n",hardfault_args[6]);         
    printf("PSR   = 0x%.8X\r\n",hardfault_args[7]);         
    printf("BFAR  = 0x%.8X\r\n",*(unsigned int*)0xE000ED38);
    printf("CFSR  = 0x%.8X\r\n",*(unsigned int*)0xE000ED28);
    printf("HFSR  = 0x%.8X\r\n",*(unsigned int*)0xE000ED2C);
    printf("DFSR  = 0x%.8X\r\n",*(unsigned int*)0xE000ED30);
    printf("AFSR  = 0x%.8X\r\n",*(unsigned int*)0xE000ED3C);
    printf("SHCSR = 0x%.8X\r\n",SCB->SHCSR);                
    while (1);
}

如果在执行此特定硬故障中断时无法在执行时使用printf,则将所有上述数据保存在全局缓冲区中,以便在到达{后可以查看它{1}}。

以下是如何将此ISR连接到中断向量的完整说明(尽管我从您的问题中了解到,您已经实现了它):

Jumping from one firmware to another in MCU internal FLASH

您可以在以下内容的基础上找到更多信息:

http://www.keil.com/appnotes/files/apnt209.pdf