rusefi-1/firmware/controllers/system/timer/pwm_generator_logic.h

173 lines
4.1 KiB
C
Raw Normal View History

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
#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);
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();
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,
ExecutorInterface *executor,
const int phaseCount, float const *switchTimes, 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);
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
*/
void setFrequency(float frequency);
2015-07-10 06:01:56 -07:00
void handleCycleStart();
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];
MultiChannelStateSequence multiChannelStateSequence;
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;
// 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
};
struct hardware_pwm;
2015-07-10 06:01:56 -07:00
struct IPwm {
virtual void setSimplePwmDutyCycle(float dutyCycle) = 0;
};
class SimplePwm : public PwmConfig, public IPwm {
2015-07-10 06:01:56 -07:00
public:
SimplePwm();
explicit SimplePwm(const char *name);
void setSimplePwmDutyCycle(float dutyCycle) override;
2015-07-10 06:01:56 -07:00
pin_state_t pinStates[2];
SingleChannelStateSequence sr[1];
2015-07-10 06:01:56 -07:00
float _switchTimes[2];
hardware_pwm* hardPwm = nullptr;
private:
SingleChannelStateSequence waveInstance;
2015-07-10 06:01:56 -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()
*/
void startSimplePwm(SimplePwm *state, const char *msg,
ExecutorInterface *executor,
OutputPin *output,
float frequency, float dutyCycle);
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()
*/
void startSimplePwmExt(SimplePwm *state,
const char *msg,
ExecutorInterface *executor,
brain_pin_e brainPin, OutputPin *output,
float frequency, float dutyCycle);
2018-11-02 10:38:31 -07:00
void startSimplePwmHard(SimplePwm *state, const char *msg,
ExecutorInterface *executor,
brain_pin_e brainPin, OutputPin *output, float frequency,
float dutyCycle);
void copyPwmParameters(PwmConfig *state, int phaseCount, float const *switchTimes,
int waveCount, pin_state_t *const *pinStates);
2015-07-10 06:01:56 -07:00