2020-03-11 07:52 AM
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.
2020-03-11 09:25 AM
Agreed :) I'm a hardware guy not very much up on the software
Thanks for the pointers
2020-03-11 09:39 AM
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.
2020-03-11 09:55 AM
Thanks - that sounds interesting to try
2020-03-11 10:01 AM
> I'm not accessing any memory
Yes you do: you are running code which is stored in some memory.
JW
2020-03-11 10:07 AM
Ah, yes. I was thinking you meant accessing external memory
2020-03-11 10:10 AM
With 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.
2020-03-11 10:35 AM
> 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.
2020-03-11 10:55 AM
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
2020-03-11 11:08 AM
> 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.
2020-03-11 01:18 PM
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.