2024-08-22 08:30 PM
I am testing the functions of STM32U575 and found the following issue.
I simply wrote this in main():
while(1){
for(i=0;i<160;i++);
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_11);
}
where i is defined as uint32_t.
HCLK is set to 160MHz by using PLLCLK with source=16MHz HSE, M=1, N=10, and R=1. Therefore the Cortex System timer is also 160MHz.
But I found the PC11 pin toggles at a cycle of about 17.2us with ICACHE on and about 45us with ICACHE off, instead of about 1us expected. DCACHE is always on.
I tried changing the Cortex System timer frequency but found it has completely no effect on the toggling frequency.
I have also enabled TIM2 and generated a PWM which performs correctly, showing that HSE is working correctly.
Why did this issue occur and how to solve it?
Thanks in advance.
2024-08-22 09:05 PM - edited 2024-08-23 12:05 AM
If you're going for high-frequency waveform generation, software control of GPIO is a bad way to do it.
With any optimizations turned on, the compiler would likely remove the for loop as having no side-effects. At the very least, you should look at the disassembly to see what code is being generated.
If compiler optimizations are off, don't expect your code to perform well.
GPIO drive strength can be controlled via registers. Their reset value puts them at the weakest value possible. Depending on what the pin's load looks like, that can mean slow rise/fall times. But I would expect 1Mhz to be doable for a reasonable load, even with the default setting.
As a general debugging approach, start at 1Hz, then gradually increase the toggle rate to find the range where code and reality begin to diverge. Investigate from there.
2024-08-22 10:39 PM - edited 2024-08-22 11:05 PM
I just toggled a GPIO on my U575 NUCLEO with GPIO Speed set to Very High
calling HAL_GPIO_TOGGLE = ~ 4 MHZ
calling GPIOF->ODR ^= GPIO_PIN_13 = ~ 16 MHZ
Things to consider:
- Trigger voltage : 3.3V in my case
- HAL overhead.
- For loop overheard of comparing and incrementing that variable. In both cases my pin toggled faster in a while(1) loop than in a for loop, obviously you need a for loop to break out but the point is that there is overhead, even if its fractional it will make a difference.
I would also suggest reading the electrical characteristics for the IO ports for your chip in the Datasheet (not the RM)
Eventually there will be a section on output frequency based on, like the previous answer said, load capacitance
2024-08-23 06:31 AM - edited 2024-08-23 06:32 AM
If you look at the disassembly of this code (i.e. the assembly instructions that the compiler generates) you'll see the loop takes more than 1 instruction. Also, each instruction in the loop can take multiple ticks.
The misunderstanding is that this should take 1us (i.e. 160 ticks) per toggle even in the best of scenarios.
Even then, these are not simple 8 bit microcontrollers. Instruction cycle counts are not fixed, lots of other variables at play here.
2024-08-23 06:41 AM
>>instead of about 1us expected
That's a pretty naive analysis. You should be looking at the machine code the MCU is running, and what the compiler did with the high-level code. Look at a disassembly.
Perhaps write GPIO->ODR or GPIO->BSRR directly for highest efficiency.
With optimization code like that can frequently be removed as it "does nothing"
The GPIO speed will be limited by the APB/AHB buses it lives on.
Whilst base through-put of the ARM MCU's can often be one-cycle, it's also pipe-lined. How deep that pipe is depends on the model.
If you want 1 MHz output, you'd use a TIM, not manually toggle, and count machine cycles.