cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 GPIO init delay?/sanity check

stmicro2399
Associate II
Posted on February 14, 2015 at 22:42

Hi all,

I'm playing around with an STM32F4 Discovery board, and I ran into an interesting issue. I'm using the GCC embedded ARM toolchain. This is the main code in question:

#include <stm32f407xx.h>
int
main (
void
)
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
GPIOD->MODER = (1 << 26) | (1 << 24) | (1<<30);
while
(1)
{
GPIOD->ODR ^= (1 << 13);
GPIOD->ODR ^= (1 << 12);
GPIOD->ODR ^= (1 << 15);
}
}

Now, the interesting part: when I compile without any optimization -O flag, or with -Os or -O1, everything works great: the orange, green and blue LEDs flash at some 100s of kHz.

However, when I compile with -O2, the code doesn't work at all -- the LEDs are all off. Inspecting with gdb, it seems that GPIOD->MODER is zero. The ODR register is correctly being changed but since MODER is zero it has no effect on the output. However, if I single step through the initialization using gdb it works fine! I also tried putting a __NOP(), or a write to a volatile int, before setting GPIOD->MODER and that also works fine. Writing to MODER twice in a row also works. I looked at the machine code GCC is outputting and it looks fine. The main difference is that for -O2, there is only 1 move instruction between the store instruction that enables the clock to the GPIO peripheral and the store instruction that writes to MODER. When I use -Os for example it outputs code with at least 1 extra instruction inbetween. This all makes me suspect that there's a timing issue between when I enable the clock to the GPIOD module and when I try to set its registers. So this is my question: is it reasonable to expect that a few clocks have to pass between enabling clock to the GPIO module and writing to its registers? Or does this indicate something else might be wrong? BTW, this is all running off the internet RC oscillator at 16 MHz. #worst-forum-software-ever
5 REPLIES 5
Posted on February 15, 2015 at 03:13

Yes, I think there is a potential hazard there, and the interaction of the write buffers. I can't find a specific cite for the issue right now, do I do recall mention of it. There are some bigger ones related to slower peripheral buses and tail-chain of interrupts before they clear.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
stmicro2399
Associate II
Posted on February 15, 2015 at 05:29

Thank you, that makes me feel more confident that I don't have a systemic issue going on.

Is there a conventional way of dealing with this properly or ''correctly''? I'm having difficulty finding any explicit mention of it in the documentation. I'm thinking a memory barrier might be a good way of making the ordering explicit. __DMB() between the two writes seems to work, although so does __NOP() so that doesn't say a lot I guess.
Posted on February 16, 2015 at 08:45

This sort of problem usually occurs when two interacting modules are on different clock domain - which is NOT the case here. Unfortunately, as this case shows too, there are other timing/synchronisation problems, which sadly are mostly undocumented by ST.

Ordering is not a problem here, as Cortex-M cores as of now don't reorder external accesses. There might be a perceived ordering problem in writing to different slaves in the system, ''thanks'' to the write buffers e.g. on the AHB/APB bridges (and the mentioned different clock domains on these slaves); but the processor's memory barrier mechanisms won't prevent these anyway, as they are completely external to the processor.

A foolproof solution here might be:

do { 

GPIOD->MODER = (1 << 26) | (1 << 24) | (1<<30);  } while (GPIOD->MODER != (1 << 26) | (1 << 24) | (1<<30));   JW 

Posted on February 16, 2015 at 09:05

Correcting myself - this one IS documented, although in a surprising manner - it's in the errata.

For example, in the STM32F40x/F41x errata rev.6 it's erratum 2.1.13, Delay after an RCC peripheral clock enabling

JW

stmicro2399
Associate II
Posted on February 16, 2015 at 20:05

Thanks for tracking that down, I couldn't find any documentation of this problem at all and did not think to check the errata. It is definitely more satisfying to have some real docs regarding this issue.

I can do the loop as you suggested, I think I actually had tried that at some point while debugging this issue and it does work nicely. I just wasn't sure until now what the most idiomatic/foolproof way of addressing this was.

Thanks everyone for your help!