1

I have an issue in an app written for the ST Microelectronics STM32F103 (ARM Cortex-M3 r1p1). RTOS is uC/OS-III; dev environment is IAR EWARM v. 6.44; it also uses the ST Standard Peripheral Library v. 1.0.1.

The app is not new; it's been in development and in the field for at least a year. It makes use of two UARTs, I2C, and one or two timers. Recently I decided to review interrupt priority assignments, and I rearranged priorities as part of the review (things seemed to work just fine).

I discovered that there was no explicit allocation of group and sub-priority bits in the initialization code, including the RTOS, and so to make the app consistent with another app (same product, different processor) and with the new priority scheme, I added a call to NVIC_PriorityGroupConfig(), passing in NVIC_PriorityGroup_2. This sets the PRIGROUP value in the Application Interrupt and Reset Control Register (AIRCR) to 5, allocating 2 bits for group (preemption) priority and 2 bits for subpriority.

After doing this, I get an imprecise bus fault exception on execution, not immediately but very quickly thereafter. (More on where I suspect it occurs in a moment.) Since it's imprecise (BFSR.IMPRECISERR asserted), there's nothing of use in BFAR (BFSR.BFARVALID clear).

The STM32F family group implements 4 bits of priority. While I've not found this mentioned explicitly anywhere, it's apparently the most significant nybble of the priority. This assumption seems to be validated by the PRIGROUP table given in documentation (p. 134, STM32F10xxx/20xxx/21xxx/L1xxx Cortex-M3 Programming Manual (Doc 15491, Rev 5), sec. 4.4.5, Application interrupt and control register (SCB_AIRCR), Table 45, Priority grouping, p. 134).

In the ARM scheme, priority values comprise some number of group or preemption priority bits and some number of subpriority bits. Group priority bits are upper bits; subpriority are lower. The 3-bit AIRCR.PRIGROUP value controls how bit allocation for each are defined. PRIGROUP = 0 configures 7 bits of group priority and 1 bit of subpriority; PRIGROUP = 7 configures 0 bits of group priority and 8 bits of subpriority (thus priorities are all subpriority, and no preemption occurs for exceptions with settable priorities).

The reset value of AIRCR.PRIGROUP is defined to be 0.

For the STM32F10x, since only the upper 4 bits are implemented, it seems to follow that PRIGROUP = 0, 1, 2, 3 should all be equivalent, since they all correspond to >= 4 bits of group priority.

Given that assumption, I also tried calling NVIC_PriorityGroupConfig() with a value of NVIC_PriorityGroup_4, which corresponds to a PRIGROUP value of 3 (4 bits group priority, no subpriority).

This change also results in the bus fault exception.

Unfortunately, the STM32F103 is, I believe, r1p1, and so does not implement the Auxiliary Control Register (ACTLR; introduced in r2p0), so I can't try out the DISDEFWBUF bit (disables use of the write buffer during default memory map accesses, making all bus faults precise at the expense of some performance reduction).

I'm almost certain that the bus fault occurs in an ISR, and most likely in a UART ISR. I've set a breakpoint at a particular place in code, started the app, and had the bus fault before execution hit the breakpoint; however, if I step through code in the debugger, I can get to and past that breakpoint's location, and if I allow it to execute from there, I'll see the bus fault some small amount of time after I continue.

The next step will be to attempt to pin down what ISR is generating the bus fault, so that I can instrument it and/or attempt to catch its invocation and step through it.

So my questions are:

1) Anyone have any suggestions as to how to go about identifying the origin of imprecise bus fault exceptions more intelligently?

2) Why would setting PRIGROUP = 3 change the behavior of the system when PRIGROUP = 0 is the reset default? (PRIGROUP=0 means 7 bits group, 1 bit sub priority; PRIGROUP=3 means 4 bits group, 4 bits sub priority; STM32F10x only implements upper 4 bits of priority.)

Many, many thanks to everyone in advance for any insight or non-NULL pointers!

(And of course if I figure it out beforehand, I'll update this post with any information that might be useful to others encountering the same sort of scenario.)

artless noise
  • 21,212
  • 6
  • 68
  • 105
Cygnus
  • 11
  • 1
  • 2

1 Answers1

1

Even if BFAR is not valid, you can still read other related registers within your bus-fault 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);
}

If you can't use printf at the point in the execution when this specific Hard-Fault interrupt occurs, then save all the above data in a global buffer instead, so you can view it after reaching the while (1).

Here is the complete description of how to connect this ISR to the interrupt vector (although, as I understand from your question, you already have it implemented):

Jumping from one firmware to another in MCU internal FLASH

You might be able to find additional information on top of what you already know at:

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

Community
  • 1
  • 1
barak manos
  • 29,648
  • 10
  • 62
  • 114
  • I made a cursory examination of stacked data but what I saw didn't seem to make sense at the time. I shall re-investigate (I'd been hoping there was a more straightforward approach I'd overlooked). – Cygnus Feb 08 '14 at 22:19
  • Tried to edit my last comment, ran out of time: Incidentally, I have that Keil app note (209) already. For anyone else who might look at it: Note carefully that the magic value on p. 4 which goes into SCB->SHCSR to enable Usage, Memory, and Bus Faults is **incorrect** - it should be 0x00070000, _not_ 0x00007000. (Though depending on your compiler and/or OS, there are probably macros or functions that would be preferable to use for clarity.) – Cygnus Feb 08 '14 at 22:26
  • Out of personal experience, look for any operation on a structure that contains a 4-byte variable (`int` or `float`) or an 8-byte variable (`double`). These unaligned load/store operations can cause a lot of indirect damage (they might not generate a direct exception, but they surely generate the wrong value, which if later used as an index to an array, for example, would likely cause a memory-access violation). – barak manos Feb 09 '14 at 08:32
  • Indeed. Though I'd expect an issue like that to present itself regardless of the allocation of group and sub priority bits. The odd thing is that the fault does not appear when PRIGROUP is left at its default (all group priority), but fails if explicitly set to any other value except zero (which disables preemption entirely - no group bits, only subpriority). First thing this morning is to recover the stack and see if that sheds light on the issue. (Thanks, Barak!) – Cygnus Feb 10 '14 at 15:32
  • You're welcome. I'm pretty sure that you can recover the stack from within your Hard-fault ISR, using the first 8 lines in the code I provided... – barak manos Feb 10 '14 at 15:50
  • Just to reiterate for clarity, it's a Bus Fault (all 3 xFAULTENA bits enabled in SHCSR). I've examined the PC in the stack when the issue occurs: it's randomly one of two different locations in uC/OS-III code (OS_FlagPost() or OS_TickListUpdate()), but that doesn't clear things up since that code executes just fine with AIRCR.PRIGROUP set to 0 (POR default), 1, or 2. The fault only appears with PRIGROUP set to 3-6 (noting that 7 disables preemption, and things work fine there as well). – Cygnus Feb 10 '14 at 21:50
  • For diligent uC/OS-III-savvy readers, I should note that all ISRs are decorated with the canonical CS-protected increment of OSIntNestingCtr at the start and the OSIntExit() call at the end. – Cygnus Feb 10 '14 at 21:52
  • I've found an apparent bug in the ST Micro Standard Peripheral Library for the F10x, version 1.0.1. NVIC_Init() (misc.c) incorrectly calculates priority values given a group and sub priority value. That explains wny behavior was different for PRIGROUP=0 (the calculated priority value was **zero** for any combination of group and sub priority in that case, and differently wrong for other values of PRIGROUP). Still no solution, however. – Cygnus Feb 11 '14 at 01:35