I'm trying to take the BLDC FOC motor controller code found in one of my previous posts and wrapping it in a class. For timing purposes, I use a library called TeensyTimerTool.h and all of it's "timers" use callbacks. Within my FOC class, I have several of these timers. The desired callback functions for each timer is a member function of the FOC class, but this gives me an "invalid use of non-static member function" error.
I'm not sure how to fix this - does anyone have any ideas apart from ripping the callbacks into the global scope?
Sketch:
#include "foc.h"
foc_ctrl motorCtrlr;
void setup()
{
Serial.begin(115200);
motorCtrlr.begin(0, 1, 2);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
digitalWriteFast(3, HIGH);
digitalWriteFast(4, HIGH);
digitalWriteFast(5, HIGH);
}
void loop()
{
if (motorCtrlr.getAlpha() < 359.9)
motorCtrlr.setAlpha(motorCtrlr.getAlpha() + 0.1);
else
motorCtrlr.setAlpha(0);
delayMicroseconds(40);
}
foc.h:
#pragma once
#include "Arduino.h"
#include "TeensyTimerTool.h"
using namespace TeensyTimerTool;
class foc_ctrl
{
public:
void begin(const byte& a_pin,
const byte& b_pin,
const byte& c_pin,
const float& alpha = 0,
const unsigned int& fullPeriod = 50,
const float& maxDutyCycle = 1.0)
{
setPins(a_pin, b_pin, c_pin);
setAlpha(alpha);
setFullPeriod_us(fullPeriod);
setMaxDutyCycle(maxDutyCycle);
foc_timer.begin(foc_timer_callback, _full_period);
a_rise_timer.begin(a_rise_timer_callback);
b_rise_timer.begin(b_rise_timer_callback);
c_rise_timer.begin(c_rise_timer_callback);
a_fall_timer.begin(a_fall_timer_callback);
b_fall_timer.begin(b_fall_timer_callback);
c_fall_timer.begin(c_fall_timer_callback);
};
void setPins(const byte& a_pin,
const byte& b_pin,
const byte& c_pin)
{
_a_pin = a_pin;
_b_pin = b_pin;
_c_pin = c_pin;
pinMode(_a_pin, OUTPUT);
pinMode(_b_pin, OUTPUT);
pinMode(_c_pin, OUTPUT);
};
void setAlpha(const float& alpha) { _alpha = alpha; };
void setFullPeriod_us(const unsigned int& fullPeriod) { _full_period = fullPeriod;
foc_timer.begin(foc_timer_callback, _full_period); };
void setMaxDutyCycle(const float& maxDutyCycle) { _max_duty_cycle = maxDutyCycle; };
float getAlpha() { return _alpha; };
int getFullPeriod_us() { return _full_period; };
float getMaxDutyCycle() { return _max_duty_cycle; };
private:
PeriodicTimer foc_timer;
OneShotTimer a_rise_timer;
OneShotTimer b_rise_timer;
OneShotTimer c_rise_timer;
OneShotTimer a_fall_timer;
OneShotTimer b_fall_timer;
OneShotTimer c_fall_timer;
int _full_period = 50; // 50us -> 20kHz
float _max_duty_cycle = 1.0;
int _a_pin = 0;
int _b_pin = 1;
int _c_pin = 2;
float _alpha = 0;
FASTRUN void a_rise_timer_callback() { digitalWriteFast(_a_pin, HIGH); }
FASTRUN void b_rise_timer_callback() { digitalWriteFast(_b_pin, HIGH); }
FASTRUN void c_rise_timer_callback() { digitalWriteFast(_c_pin, HIGH); }
FASTRUN void a_fall_timer_callback() { digitalWriteFast(_a_pin, LOW); }
FASTRUN void b_fall_timer_callback() { digitalWriteFast(_b_pin, LOW); }
FASTRUN void c_fall_timer_callback() { digitalWriteFast(_c_pin, LOW); }
// https://www.youtube.com/watch?v=nh9TD2M2r-o
FASTRUN void foc_timer_callback()
{
// Find raw phase values using alpha input (global variable)
float V_a = sin(radians(_alpha));
float V_b = sin(radians(_alpha) - radians(120));
float V_c = sin(radians(_alpha) - radians(240));
float V_max;
float V_min;
// Determine third harmonic triangle wave using max/min phase values
if ((V_a >= V_b) && (V_a >= V_c))
V_max = V_a;
else if ((V_b >= V_a) && (V_b >= V_c))
V_max = V_b;
else
V_max = V_c;
if ((V_a <= V_b) && (V_a <= V_c))
V_min = V_a;
else if ((V_b <= V_a) && (V_b <= V_c))
V_min = V_b;
else
V_min = V_c;
float V_cm = -(V_max + V_min) / 2;
// Inject the third harmonic
V_a += V_cm;
V_b += V_cm;
V_c += V_cm;
// Scale to +-0.5
V_a *= (_max_duty_cycle / sqrt(3));
V_b *= (_max_duty_cycle / sqrt(3));
V_c *= (_max_duty_cycle / sqrt(3));
// Bias by 0.5 so that outputs go 0-1: results in duty cycle ratio for each phase
V_a += 0.5;
V_b += 0.5;
V_c += 0.5;
// Determine on/off period (in us) based on full switching period and phase duty cycle ratio
int T_a = round(_full_period * V_a);
int T_b = round(_full_period * V_b);
int T_c = round(_full_period * V_c);
// Set timers to turn phase high using center-aligned PWM waveform
a_rise_timer.trigger((_full_period - T_a) / 2);
b_rise_timer.trigger((_full_period - T_b) / 2);
c_rise_timer.trigger((_full_period - T_c) / 2);
// Set timers to turn phase low using center-aligned PWM waveform
a_fall_timer.trigger(((_full_period - T_a) / 2) + T_a);
b_fall_timer.trigger(((_full_period - T_b) / 2) + T_b);
c_fall_timer.trigger(((_full_period - T_c) / 2) + T_c);
}
};