Skip to main content
SRobs.1
Associate
March 11, 2020
Question

STM32F7 How to get 50MHz on GPIO

  • March 11, 2020
  • 10 replies
  • 4056 views

I can only get the GPIO pin to toggle at 8MHz but datasheet indicates 108MHz is possible.

I tried changing OSPEEDRy[1:0] but this did not help, I only get the default 8MHz.

This topic has been closed for replies.

10 replies

TDK
March 11, 2020

Use a timer in PWM mode to toggle it at that high of a rate.

"If you feel a post has answered your question, please click ""Accept as Solution""."
SRobs.1
SRobs.1Author
Associate
March 11, 2020

Thanks for the swift response, but actually, I want to stream a pattern to several GPIO pins not just create a clock signal.

I'd be happy getting frequency up to 25MHz but also want to get variable lower frequencies.

TDK
March 11, 2020
You can try to use DMA, but 50MHz is probably beyond its capabilities. Or you could write your code in assembly, if that’s even possible to do in your case, to control exactly the number of cycles.
"If you feel a post has answered your question, please click ""Accept as Solution""."
SRobs.1
SRobs.1Author
Associate
March 11, 2020

I thought I could simply change the max speed with the OSPEEDR[1:0] setting. What is it's purpose if not to allow the higher frequncies ?

Uwe Bonnes
Chief
March 11, 2020

Put code in the ITCM and preload adresses to write to in registers. If some address must be loaded from flash, flash wait cycles come into account

SRobs.1
SRobs.1Author
Associate
March 11, 2020

I don't think I understand. I'm not accessing any memory so I don't know why the ITCM helps me. My application is to send data patterns via USB and output on GPIO.

RMcCa
Senior II
March 11, 2020

Use a dma channel triggered by a timer with the source a circular ram buffer and the destination the gpio odr. Should do 25MHz no sweat.​

SRobs.1
SRobs.1Author
Associate
March 11, 2020

Thanks - that sounds interesting to try​

waclawek.jan
Super User
March 11, 2020

> I'm not accessing any memory

Yes you do: you are running code which is stored in some memory.

JW

SRobs.1
SRobs.1Author
Associate
March 11, 2020

​Ah, yes. I was thinking you meant accessing external memory

Uwe Bonnes
Chief
March 11, 2020

0693W000000ThZgQAK.pngWith a long row of similar commands in the while loop like

void RAMFUNC FastToggle(void)
{
 GpioPinConfigSet(NUTGPIO_PORTB, 10, GPIO_CFG_OUTPUT |GPIO_CFG_SPEED_HIGH);
 volatile uint32_t *gpiob_bsrr = &GPIOB->BSRR;
 uint32_t on = (1 << 10);
 uint32_t off = (1 << ( 16 + 10));
 while(1) {
 *gpiob_bsrr = on;
 *gpiob_bsrr = off;
 *gpiob_bsrr = on;
 *gpiob_bsrr = off;
 

I get following scope picture. The one prolonges cycle is when the while loop jumps back:

Running at 216 MHz I get about 202 MHz change rate at the GPIO.

waclawek.jan
Super User
March 11, 2020

Sorry for highjacking - this is not pertinent to the topic, but:

volatile uint32_t *gpiob_bsrr = &GPIOB->BSRR;

Why? What's wrong (in context of your program/snippet) with

GPIOB->BSRR = on;

GPIOB->BSRR=off;

?

Thanks,

JW

berendi
Principal
March 11, 2020

> Datasheet simply indicates fast I/Os up to 108MHz is possible

It's possible up to 108MHz as in "Sale! Up to 50% off!". Setting OSPEED ensures that signal rise and fall times are tight enough for 108MHz.

> so I assumed one clock to set and one to clear the state of the pin.

Maybe, if the machine instructions are optimized for that. Data already present in registers, back-to-back str instructions to GPIOx->BSRR.

asm volatile(
 "str %[d1], [%[bsrr]]\n\t"
 "str %[d2], [%[bsrr]]\n\t"
 "str %[d3], [%[bsrr]]\n\t"
 "str %[d4], [%[bsrr]]\n\t"
 :
 :[bsrr]"r"(&GPIOA->BSRR),
 [d1]"r"(0x00000001), // PA0 high
 [d2]"r"(0x00000002), // PA1 high
 [d3]"r"(0x00010000), // PA0 low
 [d4]"r"(0x00020000) // PA1 low
);

This is as fast as it gets. Using more values than there are registers, counting, looping would slow it down a lot. Oh, and ensure that interrupts are disabled. Put one or more __NOP() calls before it to change alignment. It can work for a few cycles, but not really practical.

> I'm not accessing any memory so I don't know why the ITCM helps me.

Where is your program stored? How does the CPU core know what instruction to execute next? Yes, it has to fetch program instructions from memory.

berendi
Principal
March 11, 2020

> Use a dma channel triggered by a timer with the source a circular ram buffer and the destination the gpio odr. Should do 25MHz no sweat.​

As long as nothing is holding up the bus, e.g. accessing a slower APB peripheral from the MCU through the AHB-APB bridge.

To eliminate any jitter, it has to bypass the GPIO registers somehow. Maybe abusing the LTDC of FMC for the purpose.

LTDC would be ideal if you don't have an actual display, after all it is designed to put the contents of the framebuffer memory out to a parallel interface at an adjustable rate. The only problem is that it thinks in terms of scanlines and frames, and it might enforce some minimal horizontal and vertical blanking periods.

Using FMC might be possible if there is no memory or other peripheral connected to it, it should be possible to work out the FMC timings for 25 MHz, and copy data using DMA2 from SRAM2 to FMC.

SRobs.1
SRobs.1Author
Associate
March 11, 2020

Great support, thanks

I inherited the firmware and just use a python API to stream data to the GPIO.

This is a new MCU for us.

Seems I need some hep at the low level to modify the firmware.

I appreciate all the pointers and I'll pass on suggestions to my firmware team.

AVI-crak
Senior
March 12, 2020
void bistro(GPIO_TypeDef* GPIOx,int16_t* data, int d_size)
{
 asm volatile ("push {r3,r4,r5,r6,r7} \n\t"
 "add %[_gpio_x], %[_gpio_x], #0x14 \n\t"
 "sub %[_d_size], %[_d_size], #1 \n\t"
 "add %[_d_size], %[_a0], %[_d_size], lsl #1 \n\t"
 "sub %[_d_size], %[_d_size], #2 \n\t"
 "add r3, %[_a0], #2 \n\t"
 "add r4, %[_a0], #4 \n\t"
 "ldrh r5, [%[_a0]], #6 \n\t"
 "ldrh r6, [r3], #6 \n\t"
 "b step_n%=" "\n\t"
 "again_n%=: " "ldrh r5, [%[_a0]], #6 \n\t"
 "strh r7, [%[_gpio_x]] \n\t"
 "ldrh r6, [r3], #6 \n\t"
 "step_n%=: " "cmp %[_a0], %[_d_size] \n\t"
 "strh r5, [%[_gpio_x]] \n\t"
 "ldrh r7, [r4], #6 \n\t"
 "nop \n\t"
 "strh r6, [%[_gpio_x]] \n\t"
 "blo again_n%=" "\n\t"
 "strh r7, [%[_gpio_x]] \n\t"
 "pop {r3,r4,r5,r6,r7} \n\t"
 ::[_gpio_x] "r" (GPIOx), [_a0] "r" (data), [_d_size] "r" (d_size):"memory");
};

The speed of reading data, and the speed of code execution - very much depend on the location. Not all memory is fast.

The read / write command execution time is not equal to one clock cycle. In fact, these commands are executed in the pipeline, and take from three to six processor ticks. For the duration of the execution of the commands, the registers are locked, that is, they cannot read immediately or write something to them - you need to wait for the previous command to complete. But you can use other registers, and the pipeline will be fully loaded, and the read / write commands will alternate with each clock cycle. Just between reading and writing there will be a small and not very stable delay.