simplefoc / Arduino-FOC

Arduino FOC for BLDC and Stepper motors - Arduino Based Field Oriented Control Algorithm Library
https://docs.simplefoc.com
MIT License
1.94k stars 510 forks source link

Set STM32 timer prescaler based on timer clock frequency #388

Closed Copper280z closed 2 months ago

Copper280z commented 3 months ago

This commit adds a function which calculates the correct timer prescaler value based on the actual timer clock frequency and sets it. This is necessary because some stm32duino clock configs, specifically the nucleo-f746zg, set things up such that the timers have an input frequency that differs by 2x. Families other than F7 also allow for this, but don't seem to have the same problem with the default configs. image

HardwareTimer->setOverflow(num, HERTZ_FORMAT) attempts to deal with this, but it does so by setting TIMx->ARR to a value that differs by 2x, instead of setting the prescaler. For some PWM frequencies this leads to an off-by-one error in ARR between the different timers(with the 2x factor taken into account). The values I observed with the aforementioned f746 were

TIM1->ARR = 1349 (2698)
TIM4->ARR = 2699

This new function finds the lowest timer frequency for all timers, then calculates the prescaler value for each timer that's required to make the counter frequency match. It also calculates the correct overflow value for this frequency and sets it with HT->setOverflow(num, TICK_FORMAT), which does not reset the prescaler value. This method does require that no further calls to setOverflow are made with HERTZ_FORMAT, otherwise the prescaler value will be overwritten.

Additionally this change also adds the _getPwmState function, in anticipation of merging HFI support, as well as adding the STM32F7 family to the list of defines in _getInternalSourceTrigger. The F7 family timer interconnections appear to mirror the F4 family. pg713 of RM0385 rev8 (STM32F74xx and F75xx reference manual) image pg794 image

So far I've tested this on the F746 nucleo + SFOC shield and it works as expected. I haven't tested further on other targets.

runger1101001 commented 3 months ago

Hey, this may also explain this issue? https://github.com/simplefoc/Arduino-FOC/issues/166

May I ask, is this tested in combination with Antun's new timer-synchronisation based on triggers?

Copper280z commented 3 months ago

I think it might explain #166, at least based on a quick read. I'd need to check the various docs to confirm though. I'd expect this to resolve it, in any case, so long as HardwareTimer handles those timers correctly.

Yes, this is tested with Antun's timer sync code, which, to be clear, only syncs the start of the timers. It does not do any synchronization once they're running, that requires reset mode along with an update trigger, instead of an enable trigger. Using update/reset mode breaks current sensing in a difficult to fix way, at least without this change. I didn't test it with this change.

I ran into this whole trying to port current sensing and HFI to the F7, which strongly depend on having sync'd timers. I found that the effected timer was not sync'd even though it had nominally the same frequency on the scope.

askuric commented 2 months ago

Thanks for this. LGTM.

askuric commented 2 months ago

Hi @Copper280z, Did you maybe use f7 board with low-side current sensing or was it always inline? I was wondering if you know is some of the architectures f4/l4/g4 has the same low-side ADC configuration as f7.

Copper280z commented 2 months ago

I used it with lowside current sensing.

https://github.com/simplefoc/Arduino-FOC/pull/394#issue-2254582517