20#define ZERO_PWM_THRESHOLD 0.01
22#define FULL_PWM_THRESHOLD 0.99
36 memset((
void*)&
safe, 0,
sizeof(
safe));
54 if (std::isnan(dutyCycle)) {
57 }
else if (dutyCycle < 0) {
60 }
else if (dutyCycle > 1) {
73 if (dutyCycle < ZERO_PWM_THRESHOLD) {
80 }
else if (dutyCycle > FULL_PWM_THRESHOLD) {
98 int iteration =
state->safe.iteration;
100 float switchTime =
state->mode ==
PM_NORMAL ?
state->multiChannelStateSequence->getSwitchTime(
state->safe.phaseIndex) : 1;
101 float periodNt =
state->safe.periodNt;
103 efiPrintf(
"iteration=%d switchTime=%.2f period=%.2f", iteration, switchTime,
period);
111 uint32_t timeToSwitchNt = (uint32_t)((iteration + switchTime) * periodNt);
114 efiPrintf(
"start=%d timeToSwitch=%d",
state->safe.start, timeToSwitch);
116 return state->safe.startNt + timeToSwitchNt;
148 uint32_t iterationLimitInt32 = (0xFFFFFFFF /
periodNt) - 2;
153 uint32_t iterationLimitFloat = 838;
155 uint32_t iterationLimit = minI(iterationLimitInt32, iterationLimitFloat);
169 efiPrintf(
"state reset start=%d iteration=%d",
state->safe.start,
state->safe.iteration);
193 return getTimeNowNt() + MS2NT(NAN_FREQUENCY_SLEEP_PERIOD_MS);
226 efiPrintf(
"%s: nextSwitchTime %d",
state->m_name, nextSwitchTime);
231 bool isVeryBehindSchedule = nextSwitchTimeNt <
getTimeNowNt() - MS2NT(10);
238 if (isVeryBehindSchedule) {
243 printf(
"PWM: nextSwitchTimeNt=%d phaseIndex=%d iteration=%d\r\n", nextSwitchTimeNt,
247 return nextSwitchTimeNt;
258 state->dbgNestingLevel++;
261 efitick_t switchTimeNt =
state->togglePwmState();
262 if (switchTimeNt == 0) {
266 if (
state->m_executor ==
nullptr) {
271 state->m_executor->schedule(
state->m_name, &
state->scheduling, switchTimeNt, action_s::make<timerCallback>(
state ));
272 state->dbgNestingLevel--;
280 state->multiChannelStateSequence = seq;
297 criticalAssertVoid(
periodNt != 0,
"period is not initialized");
298 criticalAssertVoid(seq->
phaseCount != 0,
"signal length cannot be zero");
299 criticalAssertVoid(seq->
phaseCount <= PWM_PHASE_MAX_COUNT,
"too many phases in PWM");
300 criticalAssertVoid(seq->
waveCount > 0,
"waveCount should be positive");
326#if (BOARD_EXT_GPIOCHIPS > 0)
338 if (
state->hardPwm) {
349 state->seq.setSwitchTime(0, dutyCycle);
350 state->seq.setSwitchTime(1, PWM_MAX_DUTY);
354 state->outputPins[0] = output;
357 state->setSimplePwmDutyCycle(dutyCycle);
358 state->weComplexInit(executor, &
state->seq,
nullptr, callback);
366 output->
initPin(msg, brainPin);
378#if EFI_PROD_CODE && HAL_USE_PWM
382 state->hardPwm = hardPwm;
386#if EFI_PROD_CODE && HAL_USE_PWM
406 for (
int channelIndex = 0; channelIndex <
state->multiChannelStateSequence->waveCount; channelIndex++) {
416 for (
int channelIndex = 0; channelIndex <
state->multiChannelStateSequence->waveCount; channelIndex++) {
418 state->applyPwmValue(output, stateIndex, channelIndex);
void checkSwitchTimes(float scale) const
virtual pin_state_t getChannelState(int channelIndex, int phaseIndex) const =0
void setSwitchTime(const int phaseIndex, const float value)
Single output pin reference and state.
void initPin(const char *msg, brain_pin_e brainPin, pin_output_mode_e outputMode, bool forceInitWithFatalError=false)
void setValue(const char *msg, int logicValue, bool isForce=false)
Multi-channel software PWM output configuration.
pwm_gen_callback * m_stateChangeCallback
OutputPin * outputPins[PWM_PHASE_MAX_WAVE_PER_PWM]
void weComplexInit(Scheduler *executor, MultiChannelStateSequence const *seq, pwm_cycle_callback *pwmCycleCallback, pwm_gen_callback *callback)
MultiChannelStateSequence const * multiChannelStateSequence
efitick_t togglePwmState()
void setFrequency(float frequency)
pwm_config_safe_state_s safe
pwm_cycle_callback * m_pwmCycleCallback
void applyPwmValue(OutputPin *output, int stateIndex, int channelIndex=0)
void setSimplePwmDutyCycle(float dutyCycle) override
MultiChannelStateSequenceWithData< 2 > seq
hardware_pwm * gpiochip_tryInitPwm(const char *msg, brain_pin_e pin, float frequency, float duty)
Try to init PWM on given pin.
static EngineAccessor engine
bool warning(ObdCode code, const char *fmt,...)
void firmwareError(ObdCode code, const char *fmt,...)
@ CUSTOM_ERR_PWM_DUTY_ASSERT
@ CUSTOM_OBD_LOW_FREQUENCY
@ CUSTOM_PWM_DUTY_TOO_HIGH
@ CUSTOM_ERR_PWM_STATE_ASSERT
@ PwmConfigStateChangeCallback
bool brain_pin_is_ext(brain_pin_e brainPin)
void startSimplePwmExt(SimplePwm *state, const char *msg, Scheduler *executor, brain_pin_e brainPin, OutputPin *output, float frequency, float dutyCycle, pwm_gen_callback *callback)
void applyPinState(int stateIndex, PwmConfig *state)
void startSimplePwmHard(SimplePwm *state, const char *msg, Scheduler *executor, brain_pin_e brainPin, OutputPin *output, float frequency, float dutyCycle)
static void timerCallback(PwmConfig *state)
void startSimplePwm(SimplePwm *state, const char *msg, Scheduler *executor, OutputPin *output, float frequency, float dutyCycle, pwm_gen_callback *callback)
void copyPwmParameters(PwmConfig *state, MultiChannelStateSequence const *seq)
static efitick_t getNextSwitchTimeNt(PwmConfig *state)
void() pwm_gen_callback(int stateIndex, PwmConfig *pwm)
void() pwm_cycle_callback(PwmConfig *state)
void copyPwmParameters(PwmConfig *state, MultiChannelStateSequence const *seq)
state("state", SensorCategory.SENSOR_INPUTS, FieldType.INT8, 1871, 1.0, -1.0, -1.0, "")
static hardware_pwm * tryInitPin(const char *msg, brain_pin_e pin, float frequencyHz, float duty)
virtual void setDuty(float duty)=0