2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* @file pwm_generator_logic.h
|
|
|
|
*
|
|
|
|
* @date Mar 2, 2014
|
2020-01-13 18:57:43 -08:00
|
|
|
* @author Andrey Belomutskiy, (c) 2012-2020
|
2015-07-10 06:01:56 -07:00
|
|
|
*/
|
|
|
|
|
2020-01-20 22:40:11 -08:00
|
|
|
#pragma once
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2019-12-03 22:15:52 -08:00
|
|
|
#include "state_sequence.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
#include "global.h"
|
|
|
|
#include "scheduler.h"
|
2019-03-29 06:11:13 -07:00
|
|
|
#include "efi_gpio.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2019-07-12 05:00:07 -07:00
|
|
|
#define PERCENT_TO_DUTY(x) (x) * 0.01
|
|
|
|
|
2018-12-08 19:57:00 -08:00
|
|
|
#define NAN_FREQUENCY_SLEEP_PERIOD_MS 100
|
|
|
|
|
2019-03-03 12:27:49 -08:00
|
|
|
// 99% duty cycle
|
|
|
|
#define FULL_PWM_THRESHOLD 0.99
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
typedef struct {
|
|
|
|
/**
|
|
|
|
* a copy so that all phases are executed on the same period, even if another thread
|
|
|
|
* would be adjusting PWM parameters
|
|
|
|
*/
|
|
|
|
float periodNt;
|
|
|
|
/**
|
|
|
|
* Iteration counter
|
|
|
|
*/
|
|
|
|
int iteration;
|
|
|
|
/**
|
|
|
|
* Start time of current iteration
|
|
|
|
*/
|
|
|
|
efitick_t startNt;
|
|
|
|
int phaseIndex;
|
|
|
|
} pwm_config_safe_state_s;
|
|
|
|
|
|
|
|
class PwmConfig;
|
|
|
|
|
|
|
|
typedef void (pwm_cycle_callback)(PwmConfig *state);
|
2019-04-12 17:15:18 -07:00
|
|
|
typedef void (pwm_gen_callback)(int stateIndex, void *arg);
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2018-12-08 19:57:00 -08:00
|
|
|
typedef enum {
|
|
|
|
PM_ZERO,
|
|
|
|
PM_NORMAL,
|
|
|
|
PM_FULL
|
|
|
|
} pwm_mode_e;
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* @brief Multi-channel software PWM output configuration
|
|
|
|
*/
|
|
|
|
class PwmConfig {
|
|
|
|
public:
|
|
|
|
PwmConfig();
|
2019-12-03 22:11:10 -08:00
|
|
|
PwmConfig(float *switchTimes, SingleChannelStateSequence *waves);
|
|
|
|
void init(float *switchTimes, SingleChannelStateSequence *waves);
|
2019-09-22 05:22:35 -07:00
|
|
|
void *arg = nullptr;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
void weComplexInit(const char *msg,
|
2019-01-09 05:50:51 -08:00
|
|
|
ExecutorInterface *executor,
|
2019-02-02 22:14:19 -08:00
|
|
|
const int phaseCount, float const *swithcTimes, const int waveCount, pin_state_t *const*pinStates,
|
2018-02-05 14:16:16 -08:00
|
|
|
pwm_cycle_callback *pwmCycleCallback,
|
2015-07-10 06:01:56 -07:00
|
|
|
pwm_gen_callback *callback);
|
|
|
|
|
2019-01-09 05:50:51 -08:00
|
|
|
ExecutorInterface *executor;
|
|
|
|
|
2018-12-08 19:57:00 -08:00
|
|
|
/**
|
|
|
|
* We need to handle zero duty cycle and 100% duty cycle in a special way
|
|
|
|
*/
|
|
|
|
pwm_mode_e mode;
|
2019-10-18 16:39:06 -07:00
|
|
|
bool isStopRequested = false;
|
2018-12-08 19:57:00 -08:00
|
|
|
|
2018-01-21 12:28:03 -08:00
|
|
|
/**
|
|
|
|
* @param use NAN frequency to pause PWM
|
|
|
|
*/
|
2017-07-10 19:08:55 -07:00
|
|
|
void setFrequency(float frequency);
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
void handleCycleStart();
|
2019-01-09 05:50:51 -08:00
|
|
|
const char *name;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2019-04-12 20:31:20 -07:00
|
|
|
// todo: 'outputPins' should be extracted away from here since technically one can want PWM scheduler without actual pin output
|
2015-07-10 06:01:56 -07:00
|
|
|
OutputPin *outputPins[PWM_PHASE_MAX_WAVE_PER_PWM];
|
2019-12-03 22:11:10 -08:00
|
|
|
MultiChannelStateSequence multiChannelStateSequence;
|
2020-01-19 04:02:49 -08:00
|
|
|
efitick_t togglePwmState();
|
2019-10-18 16:39:06 -07:00
|
|
|
void stop();
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
int dbgNestingLevel;
|
|
|
|
|
|
|
|
scheduling_s scheduling;
|
|
|
|
|
|
|
|
pwm_config_safe_state_s safe;
|
|
|
|
/**
|
|
|
|
* Number of events in the cycle
|
|
|
|
*/
|
|
|
|
int phaseCount;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* this callback is invoked before each wave generation cycle
|
|
|
|
*/
|
2018-02-05 14:16:16 -08:00
|
|
|
pwm_cycle_callback *pwmCycleCallback;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* this main callback is invoked when it's time to switch level on any of the output channels
|
|
|
|
*/
|
2019-09-22 05:22:35 -07:00
|
|
|
pwm_gen_callback *stateChangeCallback = nullptr;
|
2018-01-21 12:34:20 -08:00
|
|
|
private:
|
|
|
|
/**
|
|
|
|
* float value of PWM period
|
|
|
|
* PWM generation is not happening while this value is NAN
|
|
|
|
*/
|
|
|
|
float periodNt;
|
2020-12-18 05:21:18 -08:00
|
|
|
|
|
|
|
// Set if we are very far behind schedule and need to reset back to the beginning of a cycle to find our way
|
|
|
|
bool forceCycleStart = true;
|
2015-07-10 06:01:56 -07:00
|
|
|
};
|
|
|
|
|
2020-05-28 13:02:41 -07:00
|
|
|
struct hardware_pwm;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
class SimplePwm : public PwmConfig {
|
|
|
|
public:
|
|
|
|
SimplePwm();
|
2019-06-08 06:51:36 -07:00
|
|
|
explicit SimplePwm(const char *name);
|
2020-04-26 11:06:28 -07:00
|
|
|
virtual void setSimplePwmDutyCycle(float dutyCycle);
|
2015-07-10 06:01:56 -07:00
|
|
|
pin_state_t pinStates[2];
|
2019-12-03 22:11:10 -08:00
|
|
|
SingleChannelStateSequence sr[1];
|
2015-07-10 06:01:56 -07:00
|
|
|
float _switchTimes[2];
|
2020-05-28 13:02:41 -07:00
|
|
|
hardware_pwm* hardPwm = nullptr;
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
private:
|
2019-12-03 22:11:10 -08:00
|
|
|
SingleChannelStateSequence waveInstance;
|
2015-07-10 06:01:56 -07:00
|
|
|
};
|
|
|
|
|
2020-03-25 15:14:09 -07:00
|
|
|
/**
|
|
|
|
* default implementation of pwm_gen_callback which simply toggles the pins
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void applyPinState(int stateIndex, PwmConfig* state) /* pwm_gen_callback */;
|
|
|
|
|
2018-11-02 10:38:31 -07:00
|
|
|
/**
|
|
|
|
* Start a one-channel software PWM driver.
|
|
|
|
*
|
|
|
|
* This method should be called after scheduling layer is started by initSignalExecutor()
|
|
|
|
*/
|
2019-01-09 05:50:51 -08:00
|
|
|
void startSimplePwm(SimplePwm *state, const char *msg,
|
|
|
|
ExecutorInterface *executor,
|
|
|
|
OutputPin *output,
|
2020-03-25 15:14:09 -07:00
|
|
|
float frequency, float dutyCycle, pwm_gen_callback *stateChangeCallback = (pwm_gen_callback*)applyPinState);
|
2018-11-02 10:38:31 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* initialize GPIO pin and start a one-channel software PWM driver.
|
|
|
|
*
|
|
|
|
* This method should be called after scheduling layer is started by initSignalExecutor()
|
|
|
|
*/
|
2019-01-09 05:50:51 -08:00
|
|
|
void startSimplePwmExt(SimplePwm *state,
|
|
|
|
const char *msg,
|
|
|
|
ExecutorInterface *executor,
|
|
|
|
brain_pin_e brainPin, OutputPin *output,
|
2020-03-25 15:14:09 -07:00
|
|
|
float frequency, float dutyCycle, pwm_gen_callback *stateChangeCallback = (pwm_gen_callback*)applyPinState);
|
2018-11-02 10:38:31 -07:00
|
|
|
|
2020-05-28 13:02:41 -07:00
|
|
|
void startSimplePwmHard(SimplePwm *state, const char *msg,
|
|
|
|
ExecutorInterface *executor,
|
|
|
|
brain_pin_e brainPin, OutputPin *output, float frequency,
|
|
|
|
float dutyCycle);
|
|
|
|
|
2019-02-02 22:14:19 -08:00
|
|
|
void copyPwmParameters(PwmConfig *state, int phaseCount, float const *switchTimes,
|
2019-02-02 22:04:24 -08:00
|
|
|
int waveCount, pin_state_t *const *pinStates);
|
2015-07-10 06:01:56 -07:00
|
|
|
|