rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
Functions
pwm_generator_logic.cpp File Reference

Detailed Description

This PWM implementation keep track of when it would be the next time to toggle the signal. It constantly sets timer to that next toggle time, then sets the timer again from the callback, and so on.

Date
Mar 2, 2014
Author
Andrey Belomutskiy, (c) 2012-2020

Definition in file pwm_generator_logic.cpp.

Functions

static efitick_t getNextSwitchTimeNt (PwmConfig *state)
 
static void timerCallback (PwmConfig *state)
 
void copyPwmParameters (PwmConfig *state, MultiChannelStateSequence const *seq)
 
void startSimplePwm (SimplePwm *state, const char *msg, Scheduler *executor, OutputPin *output, float frequency, float dutyCycle, pwm_gen_callback *callback)
 
void startSimplePwmExt (SimplePwm *state, const char *msg, Scheduler *executor, brain_pin_e brainPin, OutputPin *output, float frequency, float dutyCycle, pwm_gen_callback *callback)
 
void startSimplePwmHard (SimplePwm *state, const char *msg, Scheduler *executor, brain_pin_e brainPin, OutputPin *output, float frequency, float dutyCycle)
 
void applyPinState (int stateIndex, PwmConfig *state)
 

Function Documentation

◆ applyPinState()

void applyPinState ( int  stateIndex,
PwmConfig state 
)

This method controls the actual hardware pins

Definition at line 403 of file pwm_generator_logic.cpp.

403 {
404#if EFI_PROD_CODE
405 if (!engine->isPwmEnabled) {
406 for (int channelIndex = 0; channelIndex < state->multiChannelStateSequence->waveCount; channelIndex++) {
407 OutputPin *output = state->outputPins[channelIndex];
408 output->setValue(0);
409 }
410 return;
411 }
412#endif // EFI_PROD_CODE
413
414 efiAssertVoid(ObdCode::CUSTOM_ERR_6663, stateIndex < PWM_PHASE_MAX_COUNT, "invalid stateIndex");
415 efiAssertVoid(ObdCode::CUSTOM_ERR_6664, state->multiChannelStateSequence->waveCount <= PWM_PHASE_MAX_WAVE_PER_PWM, "invalid waveCount");
416 for (int channelIndex = 0; channelIndex < state->multiChannelStateSequence->waveCount; channelIndex++) {
417 OutputPin *output = state->outputPins[channelIndex];
418 state->applyPwmValue(output, stateIndex, channelIndex);
419 }
420}
bool isPwmEnabled
Definition engine.h:117
Single output pin reference and state.
Definition efi_output.h:49
void setValue(const char *msg, int logicValue, bool isForce=false)
Definition efi_gpio.cpp:604
static EngineAccessor engine
Definition engine.h:413
@ CUSTOM_ERR_6664
@ CUSTOM_ERR_6663
state("state", SensorCategory.SENSOR_INPUTS, FieldType.INT8, 1871, 1.0, -1.0, -1.0, "")

Referenced by emulatorApplyPinState(), and startSimplePwm().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ copyPwmParameters()

void copyPwmParameters ( PwmConfig state,
MultiChannelStateSequence const *  seq 
)

Incoming parameters are potentially just values on current stack, so we have to copy into our own permanent storage, right?

Definition at line 279 of file pwm_generator_logic.cpp.

279 {
280 state->multiChannelStateSequence = seq;
281 if (state->mode == PM_NORMAL) {
282 state->multiChannelStateSequence->checkSwitchTimes(1);
283 }
284}
@ PM_NORMAL

Referenced by updateTriggerWaveformIfNeeded(), and PwmConfig::weComplexInit().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getNextSwitchTimeNt()

static efitick_t getNextSwitchTimeNt ( PwmConfig state)
static

returns absolute timestamp of state change

Once 'iteration' gets relatively high, we might lose calculation precision here. This is addressed by iterationLimit below, using any many cycles as possible without overflowing timeToSwitchNt Shall we reuse 'sumTickAndFloat' here?

Definition at line 96 of file pwm_generator_logic.cpp.

96 {
97 efiAssert(ObdCode::CUSTOM_ERR_ASSERT, state->safe.phaseIndex < PWM_PHASE_MAX_COUNT, "phaseIndex range", 0);
98 int iteration = state->safe.iteration;
99 // we handle PM_ZERO and PM_FULL separately
100 float switchTime = state->mode == PM_NORMAL ? state->multiChannelStateSequence->getSwitchTime(state->safe.phaseIndex) : 1;
101 float periodNt = state->safe.periodNt;
102#if DEBUG_PWM
103 efiPrintf("iteration=%d switchTime=%.2f period=%.2f", iteration, switchTime, period);
104#endif /* DEBUG_PWM */
105
106 /**
107 * Once 'iteration' gets relatively high, we might lose calculation precision here.
108 * This is addressed by iterationLimit below, using any many cycles as possible without overflowing timeToSwitchNt
109 * Shall we reuse 'sumTickAndFloat' here?
110 */
111 uint32_t timeToSwitchNt = (uint32_t)((iteration + switchTime) * periodNt);
112
113#if DEBUG_PWM
114 efiPrintf("start=%d timeToSwitch=%d", state->safe.start, timeToSwitch);
115#endif /* DEBUG_PWM */
116 return state->safe.startNt + timeToSwitchNt;
117}
beuint32_t period
@ CUSTOM_ERR_ASSERT

Referenced by PwmConfig::togglePwmState().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ startSimplePwm()

void startSimplePwm ( SimplePwm state,
const char msg,
Scheduler executor,
OutputPin output,
float  frequency,
float  dutyCycle,
pwm_gen_callback callback = NULL 
)

Start a one-channel software PWM driver.

This method should be called after scheduling layer is started by initSignalExecutor()

Definition at line 315 of file pwm_generator_logic.cpp.

317 {
318 efiAssertVoid(ObdCode::CUSTOM_ERR_PWM_STATE_ASSERT, state != NULL, "state");
319 efiAssertVoid(ObdCode::CUSTOM_ERR_PWM_DUTY_ASSERT, dutyCycle >= 0 && dutyCycle <= PWM_MAX_DUTY, "dutyCycle");
320 if (frequency < 1) {
321 warning(ObdCode::CUSTOM_OBD_LOW_FREQUENCY, "low frequency %.2f %s", frequency, msg);
322 return;
323 }
324
325#if EFI_PROD_CODE
326#if (BOARD_EXT_GPIOCHIPS > 0)
327 if (!callback) {
328 /* No specific scheduler, we can try enabling HW PWM */
329 if (brain_pin_is_ext(output->brainPin)) {
330 /* this pin is driven by external gpio chip, let's see if it can PWM */
331 state->hardPwm = gpiochip_tryInitPwm(msg, output->brainPin, frequency, dutyCycle);
332 }
333 /* TODO: sohuld we try to init MCU PWM on on-chip brainPin?
334 * Or this should be done only on startSimplePwmHard() call? */
335 }
336
337 /* We have succesufully started HW PWM on this output, no need to continue with SW */
338 if (state->hardPwm) {
339 return;
340 }
341#endif
342#endif
343
344 /* Set default executor for SW PWM */
345 if (!callback) {
346 callback = applyPinState;
347 }
348
349 state->seq.setSwitchTime(0, dutyCycle);
350 state->seq.setSwitchTime(1, PWM_MAX_DUTY);
351 state->seq.setChannelState(0, 0, TriggerValue::FALL);
352 state->seq.setChannelState(0, PWM_MAX_DUTY, TriggerValue::RISE);
353
354 state->outputPins[0] = output;
355
356 state->setFrequency(frequency);
357 state->setSimplePwmDutyCycle(dutyCycle);
358 state->weComplexInit(executor, &state->seq, nullptr, callback);
359}
brain_pin_e brainPin
Definition efi_output.h:86
hardware_pwm * gpiochip_tryInitPwm(const char *msg, brain_pin_e pin, float frequency, float duty)
Try to init PWM on given pin.
Definition core.cpp:439
bool warning(ObdCode code, const char *fmt,...)
static float frequency
Definition init_flex.cpp:21
@ CUSTOM_ERR_PWM_DUTY_ASSERT
@ CUSTOM_OBD_LOW_FREQUENCY
@ CUSTOM_ERR_PWM_STATE_ASSERT
bool brain_pin_is_ext(brain_pin_e brainPin)
void applyPinState(int stateIndex, PwmConfig *state)

Referenced by applyIACposition(), TachometerModule::init(), Generic4TransmissionController::init(), Gm4l6xTransmissionController::init(), initAlternatorCtrl(), initGpPwm(), initSpeedometer(), startBoostPin(), and startSimplePwmExt().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ startSimplePwmExt()

void startSimplePwmExt ( SimplePwm state,
const char msg,
Scheduler executor,
brain_pin_e  brainPin,
OutputPin output,
float  frequency,
float  dutyCycle,
pwm_gen_callback callback = NULL 
)

initialize GPIO pin and start a one-channel software PWM driver.

This method should be called after scheduling layer is started by initSignalExecutor()

Definition at line 361 of file pwm_generator_logic.cpp.

364 {
365
366 output->initPin(msg, brainPin);
367
368 startSimplePwm(state, msg, executor, output, frequency, dutyCycle, callback);
369}
void initPin(const char *msg, brain_pin_e brainPin, pin_output_mode_e outputMode, bool forceInitWithFatalError=false)
Definition efi_gpio.cpp:711
void startSimplePwm(SimplePwm *state, const char *msg, Scheduler *executor, OutputPin *output, float frequency, float dutyCycle, pwm_gen_callback *callback)

Referenced by startPwm(), startSimplePwmHard(), and turnVvtPidOn().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ startSimplePwmHard()

void startSimplePwmHard ( SimplePwm state,
const char msg,
Scheduler executor,
brain_pin_e  brainPin,
OutputPin output,
float  frequency,
float  dutyCycle 
)
Parameters
dutyCyclevalue between 0 and 1

Definition at line 374 of file pwm_generator_logic.cpp.

377 {
378#if EFI_PROD_CODE && HAL_USE_PWM
379 auto hardPwm = hardware_pwm::tryInitPin(msg, brainPin, frequency, dutyCycle);
380
381 if (hardPwm) {
382 state->hardPwm = hardPwm;
383 } else {
384#endif
385 startSimplePwmExt(state, msg, executor, brainPin, output, frequency, dutyCycle);
386#if EFI_PROD_CODE && HAL_USE_PWM
387 }
388#endif
389}
void startSimplePwmExt(SimplePwm *state, const char *msg, Scheduler *executor, brain_pin_e brainPin, OutputPin *output, float frequency, float dutyCycle, pwm_gen_callback *callback)
static hardware_pwm * tryInitPin(const char *msg, brain_pin_e pin, float frequencyHz, float duty)
Definition mpu_util.cpp:257

Referenced by initVrThresholdPwm(), and DcHardware::start().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ timerCallback()

static void timerCallback ( PwmConfig state)
static

Main PWM loop: toggle pin & schedule next invocation

First invocation happens on application thread

Definition at line 255 of file pwm_generator_logic.cpp.

255 {
257
258 state->dbgNestingLevel++;
259 efiAssertVoid(ObdCode::CUSTOM_ERR_6581, state->dbgNestingLevel < 25, "PWM nesting issue");
260
261 efitick_t switchTimeNt = state->togglePwmState();
262 if (switchTimeNt == 0) {
263 // we are here when PWM gets stopped
264 return;
265 }
266 if (state->m_executor == nullptr) {
267 firmwareError(ObdCode::CUSTOM_NULL_EXECUTOR, "exec on %s", state->m_name);
268 return;
269 }
270
271 state->m_executor->schedule(state->m_name, &state->scheduling, switchTimeNt, action_s::make<timerCallback>( state ));
272 state->dbgNestingLevel--;
273}
void firmwareError(ObdCode code, const char *fmt,...)
@ CUSTOM_NULL_EXECUTOR
@ CUSTOM_ERR_6581
@ PwmGeneratorCallback

Referenced by PwmConfig::weComplexInit().

Here is the call graph for this function:
Here is the caller graph for this function:

Go to the source code of this file.