Thanks @Candas1 for adding that ADC_USE_INTERRUPT
code to Simple FOC\src\current_sense\hardware_specific\gd32\gd32f130/gd32f130_mcu.cpp
.
//#define ADC_USE_INTERRUPT // If defined, will use the End of conversion interrupt of inserted ADC
I think this was only for testing and you are going to remove it ?
But i think i can use that code to call motor.loopFOC()
( and motor.move()
) right when the two low-side mofet currents have been sampled (which need to be in sync with the bldc pwm.)
I had to set a priority lower then the HallSensor interrupts which use
nvic_irq_enable(gpio_exti_infor[pinNum].irqNum, EXTI_IRQ_PRIO, EXTI_IRQ_SUBPRIO);
=
nvic_irq_enable(gpio_exti_infor[pinNum].irqNum, 3, 0);
Then i think, the hall interrupts can interrupt the 300 microseconds long loopFOC()
(called nested interrupts = nvic = Nested vector interrupt control)
void* _configureADCLowSide(const void* driver_params, const int pinA, const int pinB, const int pinC)
{
...
adc_interrupt_flag_clear(ADC_INT_EOIC);
adc_interrupt_enable(ADC_INT_EOIC);
nvic_irq_enable(ADC_CMP_IRQn, 3, 3);
At the moment i simply add many extern to the gd32f130_mcu.cpp
to call motor.XY
and allow OUT2T
log output:
unsigned long iAdcMicros = 0;
unsigned long iAdcLast = 0;
unsigned long iAdcMicrosLoop = 0;
unsigned long iAdcMicrosLoopLast = 0;
#include <SimpleFOC.h>
extern BLDCMotor motor;
extern float target;
extern LowPassFilter LPF_target; // the higher the longer new values need to take effect
boolean bNoLoopFOC = false;
int iUsLoopFOC = 300;
Then this works nearly as nicely as having motor.loopFOC
and motor.move
in the main loop()
:
extern "C" {
void ADC_CMP_IRQHandler(void)
{
if ( adc_interrupt_flag_get(ADC_INT_EOIC) != RESET)
{
adc_interrupt_flag_clear(ADC_INT_EOIC);
unsigned long iNow = _micros();
iAdcMicros = iNow - iAdcLast;
iAdcLast = iNow;
if (motor.enabled)
{
if (bNoLoopFOC && (iNow - iAdcMicrosLoopLast > iUsLoopFOC) ) // 250 us = 4 kHz
{
bNoLoopFOC = false;
motor.loopFOC();
motor.move(LPF_target(target));
iAdcMicrosLoop = iNow - iAdcMicrosLoopLast;
iAdcMicrosLoopLast = iNow;
bNoLoopFOC = true;
}
}
}
}
}
The sound of the motor has an additional frequency which i think links to iUsLoopFOC
.
And now i can add delayMicroseconds(500);
to the main loop() with no effect on motor performance :-)
Current consumption (for 22V and T10) is flucktuating from 0.27 A to 0.3 A for both methods. But with my interrupt driven method , the 0.3 A flickers on my lcd power supply a bit more often than the loop::motor.loopFOC() method does. So the old method is slightly more efficient. Do not know why !
The motor.loopFOC + motor.move takes about 300 micro seconds :-(
So a frequency of more then 3 kHz is not possible :-/
That is a bit frustrating considering that the very simple Gen2 block commutation runs at 16 kHz ?
It is okay Candas if you do not help here. I think your focus is on using SimpleFOC with a Gen2 board for a very specific robot task, whereas i want a replacement of the Gen2.x firmware where users can add whatever they want to the main loop().
Maybe @robcazzaro will like to check my ADC_CMP_IRQHandler
for thread safty.
Is 3,3 the lowest possible interrupt priority ?