cancel
Showing results for 
Search instead for 
Did you mean: 

MCU running too slow?

chichkinei
Associate II
Posted on May 20, 2013 at 08:44

So I've been noticing recently that my stm32f4 discovery board is running under 168 MHz. Or at least I think. I'm trying to get this loop

uint32_t i = 0;
for
(;i<76799;i++)
{
GPIOD->ODR = 0x4100;
GPIOD->ODR = 0x5100;
}

to execute as fast as possible and I noticed that one iteration of the loop takes 143nS to complete, which is about 24 cycles @ 168 MHz. Surely comparing a 32-bit integer, writing to a register twice, and jumping back to the beginning shouldn't take 24 cycles? If I probe PD12 (the pin that's changing), it takes about 21 nS from the time it goes low to the time it goes high again. 48MHz? What's going on here? I've attached the system_stm32f4xx.c just in case. EDIT: I also should have mentioned that other clocks (SPI, SDIO, TIM4) work correctly so maybe this MCU is just slower than I expected.
19 REPLIES 19
Posted on May 20, 2013 at 13:19

Microcontrollers usually don't execute C code, so it's sort of foolish to have expectations towards execution speed based on a C program alone...

JW

Posted on May 20, 2013 at 14:01

Accesses to AHB and APB buses will take multiple core cycles.

Toggling GPIO is a poor test of speed.

If the edges are slow, slew rate, you need to look at the Speed setting for the port, and the external loading.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
chichkinei
Associate II
Posted on May 21, 2013 at 02:45

Ok, so apparently is takes 16 instructions to do that loop, which I guess makes 24 cycles seem reasonable. And, indeed, after stepping through 1 instruction at a time it looks like a GPIO write takes 4 cycles. Now the question is, what's the fastest way to toggle PD12 76800 times? And as  a side question, is there a way to get the main clock out on a pin? I know that on AVR's you can set a CLKOUT fuse which will do that.

Posted on May 21, 2013 at 03:43

Fractions of the internal clocks can be feed out the MCOx pins. The pin drivers are limited to 100 MHz.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on May 21, 2013 at 04:38

Something like this should be reasonably fast

ldr r0, =0x40020C14 ; &GPIOD->ODR (0x14)
ldr r1, =0x4100
ldr r2, =0x5100
ldr r3, =7680 ; 10 per iteration loop
lp
strh r1,[r0] ; 1
strh r2,[r0]
strh r1,[r0] ; 2
strh r2,[r0]
strh r1,[r0] ; 3
strh r2,[r0]
strh r1,[r0] ; 4
strh r2,[r0]
subs r3,#1
strh r1,[r0] ; 5
strh r2,[r0]
strh r1,[r0] ; 6
strh r2,[r0]
strh r1,[r0] ; 7
strh r2,[r0]
strh r1,[r0] ; 8
strh r2,[r0]
strh r1,[r0] ; 9
strh r2,[r0]
strh r1,[r0] ; 10
strh r2,[r0]
bne lp

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
chichkinei
Associate II
Posted on May 21, 2013 at 07:08

Ah, I should have thought of simply doing the toggle a few times in a row. Now I just have to figure out how to shove a chunk of asm into C, because nothing I've tried seems to work. Are there any general conventions as to which registers to use? When stepping through the instructions peviously, mainly registers 2 and 3 were being used, though 0 was also holding a value. Also the MCO isn't giving me any luck. This code should give me 1/4 of the main clock on PC9, correct? I get nothing.

RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
GPIOC->ODR = 0x80000;
RCC->CFGR |= 0x30000000;
GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_MCO);
while
(1){}

It's located at the beginning of main(). First three times I wrote this, my post got thrown in the bit bucket... I see the forum software hasn't changed much while I've been gone
chichkinei
Associate II
Posted on May 21, 2013 at 07:09

Ah, and when it finally decides to work, it double posts it... I won't bother trying to figure out how to delete a post.

zzdz2
Associate II
Posted on May 21, 2013 at 09:40

Now I just have to figure out how to shove a chunk of asm into C, because nothing I've tried seems to work. Are there any general conventions as to which registers to use?

It depends on compiler, in gcc you can use something like this, no need to specify register names/numbers:

int main (void)
{
int out = 0x234242;
asm volatile (''str %0, [%1]''::''r''(out), ''r''(&GPIOC->ODR));
return 0;
}

http://gcc.gnu.org/onlinedocs/gcc-4.6.4/gcc/Extended-Asm.html

Posted on May 21, 2013 at 10:20

> Ok, so apparently is takes 16 instructions to do that loop,

Maybe yes, but given you refuse to give us information on how do you arrive to these conclusions, we can't give qualified comment except that GIGO. > And, indeed, after stepping through 1 instruction at a time it looks like a GPIO write takes 4 cycles. Again, the result depends wildly on your definition of ''stepping through''. I suspect, you still insist on observing execution of C code, which is foolish when it comes to cycle counting. OTOH, depending on how the cycles are counted, single-stepping might yield confusing results, too, as stopping the processor core might hide cycles otherwise spent waiting for bus operations. > Also the MCO isn't giving me any luck. > This code should give me 1/4 of the main clock on PC9, correct? I get nothing.

RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
GPIOC->ODR = 0x80000;
RCC->CFGR |= 0x30000000;
GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_MCO);
while
(1){}

This is a mess. Either stick to writing to registers, or to using the ''library'' utilities. There's no point to write to ODR if you use AF, not to mention that only the lowermost 16 bits are defined in ODR ; OTOH, you will want to gear up the pin's output speed, the register to do that is called OSPEEDR (and you might want to switch on the compensation cell accordingly). I don't use the ''library'' so won't comment on correctness of this snippet as a whole, but messy software is usually correct only by coincidence. > First three times I wrote this, my post got thrown in the bit bucket... > I see the forum software hasn't changed much while I've been gone Yes, the forum software is a mess, too. JW