Running FOC control loop inside to PWM timer overflow interrupt handler or ADC sample finish interrupt handler.

Requests for the realization of running FOC control loop inside to PWM timer overflow interrupt handler or ADC sample finish interrupt handler(for 32 bit MCUs like stm32 or esp32).
Because it can maintain strict timing synchronization between FOC control and PWM duty cycle update, and it can can get a known dt value without having to use the micros() function.

Hey @NekoGirlChocolate,

I don’t think that owl timer overflow is the best way to go. Or the adc timer overflow. They are happening too fast.

I’d suggest you to use a dedicated timer for the loopFOC() function on 10kHz for example.

Also if not use the motion control (move()) in a such timer callback. And the move is the onr that would benefit the constant sampling time, and avoid using dt.
Maybe we could set up two timers one for loopFOC and the other for move.

But that becomes very specific and I’d leave it as a suggestion for better performance.

What is your take on this?

Hi, and welcome @NekoGirlChocolate!

I saw some of your driver code for the sensors and driver chips on GitHub, that’s very cool!

Regarding interrupt-driven control loops, I was thinking about this myself. The problem is that the setup of the timers can be quite MCU dependent, and also depending on the MCU the functions could be a bit slow for interrupt routines.
One approach might be to use the interrupts to set flags, which you check in the main loop.

I agree with Antun that it is better to leave the core library and basic examples as they are - they are very clear and understandable, and run on simple MCUs like ATMega. Having two simple functions in the Arduino main loop keeps the code accessible to beginner level embedded developers, who don’t know about interrupts and fast timers.

At the same time, for someone who is on a fast MCU like ESP32 or STM32, and knows what they are doing, it is pretty trivial to put the move()/loopFOC() functions into interrupt handlers or async tasks…

But maybe we should include some example code for how to do this?

I think, for high-performance MCUs such as STM32 and ESP32, they running programs very fast. So, I think this type of MCU can run a complete FOC control loop on PWM timer overflow interrupt handler. And some hardware has two low-side shunt to sample phase current, so, for these hardware, sample current at vector-0’s center is necessary, and PWM timer overflow interrupt is exactly happened at vector-0’s center or vector-7’s center, therefore, running FOC control loop on PWM timer overflow interrupt handler can accurately sample the phase current on these hardware.

You are right, and it would definitely be worth testing out…

There is another approach though, which I am looking at: you can use the timer interrupts to trigger ADC conversions directly, or just do the ADC in the interrupt routine. I am pretty sure both ESP32 and STM32 support this kind of operation. SAMD, which I am looking at in depth at the moment certainly does. It also has an “Event System” which looks like it could also be used for the purpose.

So in this approach you would get an ADC conversion on each PWM cycle, and store this in memory, perhaps passing through a filter first. And the FOC code runs asynchronously to this.

On the other hand, for current limiting this approach might even be too slow. For that a comparator based approach seems to be what is commonly used…

I would not run FOC on each PWM cycle - you don’t want to set the voltage that often. But if the MCU is fast enough it could be advantageous to run it in a timer-routine, as Antun suggested. This could actually save resources by not running it too often on a fast MCU like ESP32. And it would leave your main loop free to deal with communication.

@Antun_Skuric , I have a question in this regard: do you know offhand if the move() code is thread-safe with respect to loopFOC()?

I.e. if you put loopFOC() in an interrupt handler, could you just leave move() in the main loop, or would you also have to mask interrupts/run it in its own interrupt handler?

It is an interesting suggestion to run the foc code in the PWM handles callback but I think honestly that that is not the place for it. The PWM handler is much too fast for the FOC algorithm.

I would agree that running the FOC algorithm in synchronous mode would be beneficial both because of the performance and the code simplicity (we could remove timestamping code).

But PWM hanlder would run in general above 15khz, which is far too fast for motion control. Basically all the variables will be static in between calls and it could even become unstable due to the really small sample time. Another issue is that the simple time equal to the PWM sample time would mean that the voltage we wish to set to the motor will barely be achieved (motor electrical time constant is usually around 1ms) which so we would usually be really overcompensating. We usually need at least 4-5 PWM periods for the current to see the difference (at 15-20khz).

Now in terms of current control. I would agree that 15kHz is not far too fast for the Current control and that might even work. At this moment we are running the current control at arround 10khz.
But the big issue here are the sensors. We would need to have sensors which are able to be sampled at this rate both adc and the position sensor. And this is not easy to do. We are mostly constrained by the sensors here, even though we might have the processing capacity to do so.

In any case, I would say that PWM or ADC callbacks will not be used to execute neither current or motion control. I would definitely advise you to use the interrupt handler to run simplefoc, especially loopFOC() function but we need to be careful there that for your mcu+sensor combination is capable of doing so. And for this moment it is really hard for us to propose a general solution for this problem.

Now in terms of ADC callbacks, just a quick note, we will be using ADC and PWM callbacks to sync the current sensing reading. But not for the FOC algorithm.

Basically the idea is that loopFOC() takes the priority and you can put it into the interrupt handler. Since move() will take some time to execute I’d not disable interrupts during it’s execution. Because then you’d limit the loopFOC execution time to the move() execution time.

But I do have to admit that I do not know if all the parts of the code are thread safe. A priori I’d say they are but there might be some easter eggs :smiley:

Very interesting thread, I’m right there myself, trying out things. I just completed a SAMD-specific integration of a DMA-based adc scanner. I have good readings of the low side currents, and i must now decide how to use them.

Sorry to bump yet another old thread but this topic has been in my mind for a long time.

I come from a firmware that was able to sample the phase current synchronously and run the complete FOC algorithm in half a PWM period at 16Khz without a FPU thanks to fixed point math.

I agree that this is not necessary, but I think different parts of FOC algorithm have different criticality, and SimpleFOC could benefit from splitting the algorithm.

I just came accross a nice diagram in a paper that highlights this:

So this could be part of the fast loop and running in the interrupt:

  • sampling of the phase currents (you don’t even need to convert adc to voltage here)
  • possibly non HW critical fault detection (e.g. cycle by cycle current limitation/chopping)
  • sensor update/angle prediction (as close to the current sampling as possible)
  • inverse Park (possibly with another angle prediction as the angle will have changed until the duty cycles are applied as discussed with @dekutree64)
  • inverse Clarke
  • SVPWM
  • apply duty cycles

This ensures the duty cycles are updated as fast as possible, and that the phase current and angle are as close as possible, not introducing lag in the d axis.
This part is the one that will benefit most from optimization (use less float, cordic, fixed point math,…).

In the slower loop, as you mentioned, this doesn’t have to run so fast:

  • Clarke transform
  • Park transform
  • d and q filters
  • d and q PI controllers
  • feedforward terms like lag compensation and BEMF compensation
  • possible current/voltage saturation/limitation

And the move function can already be downsampled to run even slower than the slow loop.
I think this could make the main loop less time critical also.

As always, please move this post if it’s too off topic :rofl: