When I access a peripheral register (such as a GPIO port) just after enabling the clock gating of the peripheral, a hard fault happens. For example:
-
This code doesn't work (generates a hard fault):
/* enable clock to GPIOF at clock gating control register */ SYSCTL_RCGCGPIO_R |= SYSCTL_RCGCGPIO_R5; /* enable the GPIO pins for the LED (PF3, 2 1) as output */ GPIO_PORTF_DIR_R = 0x0E; while(1) {}
-
But with this little
nop
tweak, it works:/* enable clock to GPIOF at clock gating control register */ SYSCTL_RCGCGPIO_R |= SYSCTL_RCGCGPIO_R5; asm(" nop"); asm(" nop"); /* enable the GPIO pins for the LED (PF3, 2 1) as output */ GPIO_PORTF_DIR_R = 0x0E; while(1) {}
The code should work fine with no delay after enabling the clock, but I need to know what is happening here?
Long Story:
If I run the first code it gives me a bus error. I tried other ports in GPIO and also tried some UART channel and the problem persists. What I got is that: just adding sufficient asm(" nop");
instructions in the right place make the code works.
It appears that the problem is with the delay time between enabling the clock gating of a peripheral and accessing it's registers. Any solution that implements adding a sufficient delay works. I tried different things like using a delay function or using asm(" nop") instructions or just adding a debug breakpoint in the line just after enabling clock. Is this have something to do with clock gating latency or clock skew or such expressions?
I've debugged the code according to this document form TI. My fault register reads a value of 0x0000.0400
after fault which means that "A bus fault occurred, but that the exact faulting address is not known". I've checked the exception stack frame and analyzed the disassembly code that is executed before the fault happens and it seems that there's no problem. The document says that this fault occurs usually due to the STR
instruction, but I've checked the memory pointers and it's all fine.
Disassembly of the not-working code:
11 SYSCTL_RCGCGPIO_R |= SYSCTL_RCGCGPIO_R5;
main():
0000026c: 4913 ldr r1, [pc, #0x4c]
0000026e: 6808 ldr r0, [r1]
15 GPIO_PORTF_DIR_R = 0x0E;
00000270: 4A13 ldr r2, [pc, #0x4c]
11 SYSCTL_RCGCGPIO_R |= SYSCTL_RCGCGPIO_R5;
00000272: F0400020 orr r0, r0, #0x20
00000276: 6008 str r0, [r1]
15 GPIO_PORTF_DIR_R = 0x0E;
00000278: 200E movs r0, #0xe
0000027a: 6010 str r0, [r2]
Disassembly of the working code:
11 SYSCTL_RCGCGPIO_R |= SYSCTL_RCGCGPIO_R5;
main():
0000026c: 4914 ldr r1, [pc, #0x50]
0000026e: 6808 ldr r0, [r1]
00000270: F0400020 orr r0, r0, #0x20
00000274: 6008 str r0, [r1]
00000276: BF00 nop
00000278: BF00 nop
15 GPIO_PORTF_DIR_R = 0x0E;
0000027a: 4912 ldr r1, [pc, #0x48]
0000027c: 200E movs r0, #0xe
0000027e: 6008 str r0, [r1]
From my experiments, it seems like after enabling clock for GPIO requires more than 1 clock cycles before accessing the GPIO port registers. For UART it is higher, about 5 to 6 clock cycles (I've measured that with the debugger).
IDE: Code Composer Studio.
Compiler: TI v18.12.2.LTS (with optimization level of 2).
OS: Ubuntu Bionic 18.04.2 LTS.
So, is that delay required? or unfortunately, I have a hardware problem?
Best Answer
As I recall this is a known issue with the Tiva processors: you have to wait two or three clock cycles after enabling the clock before you can actually use the peripheral. Some people would, sadly, add a statement that just reads the value in some volatile register to kill time. Unfortunately, sometimes one statement wasn't enough. The situation lead to some very ugly hacks.
TI eventually added the General-Purpose Input/Output Peripheral Ready (PRGPIO) reister. This register has one bit for each port, and you can read the bit to see when the port is ready to use. Similar registers are available for other peripheral devices, such as the Universal Asynchronous Receiver/Transmitter Peripheral Ready register.