2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* @file pwm_generator_logic.cpp
|
|
|
|
*
|
|
|
|
* 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
|
2018-01-20 17:55:31 -08:00
|
|
|
* @author Andrey Belomutskiy, (c) 2012-2018
|
2015-07-10 06:01:56 -07:00
|
|
|
*/
|
|
|
|
|
2018-09-16 19:26:57 -07:00
|
|
|
#include "global.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
#include "pwm_generator_logic.h"
|
2019-03-29 07:29:01 -07:00
|
|
|
#include "pwm_generator.h"
|
2019-01-09 05:50:51 -08:00
|
|
|
#include "error_handling.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* We need to limit the number of iterations in order to avoid precision loss while calculating
|
|
|
|
* next toggle time
|
|
|
|
*/
|
|
|
|
#define ITERATION_LIMIT 1000
|
|
|
|
|
2018-12-09 06:23:31 -08:00
|
|
|
// 1% duty cycle
|
|
|
|
#define ZERO_PWM_THRESHOLD 0.01
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
SimplePwm::SimplePwm() {
|
|
|
|
waveInstance.init(pinStates);
|
|
|
|
sr[0] = waveInstance;
|
|
|
|
init(_switchTimes, sr);
|
|
|
|
}
|
2015-09-13 07:01:39 -07:00
|
|
|
|
2019-01-09 05:50:51 -08:00
|
|
|
SimplePwm::SimplePwm(const char *name) : SimplePwm() {
|
|
|
|
this->name = name;
|
|
|
|
}
|
|
|
|
|
2019-04-12 16:56:34 -07:00
|
|
|
PwmConfig::PwmConfig() {
|
2018-12-27 06:40:40 -08:00
|
|
|
memset((void*)&scheduling, 0, sizeof(scheduling));
|
|
|
|
memset((void*)&safe, 0, sizeof(safe));
|
2015-07-10 06:01:56 -07:00
|
|
|
dbgNestingLevel = 0;
|
|
|
|
periodNt = NAN;
|
2018-12-08 19:57:00 -08:00
|
|
|
mode = PM_NORMAL;
|
2015-07-10 06:01:56 -07:00
|
|
|
memset(&outputPins, 0, sizeof(outputPins));
|
|
|
|
phaseCount = 0;
|
2018-02-05 14:16:16 -08:00
|
|
|
pwmCycleCallback = NULL;
|
2015-07-10 06:01:56 -07:00
|
|
|
stateChangeCallback = NULL;
|
2019-01-09 05:50:51 -08:00
|
|
|
executor = NULL;
|
|
|
|
name = "[noname]";
|
2019-04-12 17:06:09 -07:00
|
|
|
arg = this;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2019-04-12 16:56:34 -07:00
|
|
|
PwmConfig::PwmConfig(float *st, SingleWave *waves) : PwmConfig() {
|
2015-07-10 06:01:56 -07:00
|
|
|
multiWave.init(st, waves);
|
|
|
|
}
|
|
|
|
|
2018-12-25 05:27:52 -08:00
|
|
|
void PwmConfig::init(float *st, SingleWave *waves) {
|
2015-07-10 06:01:56 -07:00
|
|
|
multiWave.init(st, waves);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-01-21 12:28:03 -08:00
|
|
|
* This method allows you to change duty cycle on the fly
|
2015-07-10 06:01:56 -07:00
|
|
|
* @param dutyCycle value between 0 and 1
|
2018-12-08 19:57:00 -08:00
|
|
|
* See also setFrequency
|
2015-07-10 06:01:56 -07:00
|
|
|
*/
|
|
|
|
void SimplePwm::setSimplePwmDutyCycle(float dutyCycle) {
|
2018-11-26 17:40:24 -08:00
|
|
|
if (cisnan(dutyCycle)) {
|
2019-04-15 17:47:06 -07:00
|
|
|
warning(CUSTOM_DUTY_INVALID, "spwd:dutyCycle %.2f", dutyCycle);
|
2018-10-21 14:45:14 -07:00
|
|
|
return;
|
2019-04-15 17:47:06 -07:00
|
|
|
} else if (dutyCycle < 0) {
|
|
|
|
warning(CUSTOM_DUTY_TOO_LOW, "spwd:dutyCycle %.2f", dutyCycle);
|
|
|
|
dutyCycle = 0;
|
|
|
|
} else if (dutyCycle > 1) {
|
|
|
|
warning(CUSTOM_DUTY_TOO_HIGH, "spwd:dutyCycle %.2f", dutyCycle);
|
|
|
|
dutyCycle = 1;
|
2018-01-21 13:06:03 -08:00
|
|
|
}
|
2019-02-01 19:37:21 -08:00
|
|
|
if (dutyCycle == 0.0f && stateChangeCallback != NULL) {
|
2019-02-01 19:20:15 -08:00
|
|
|
/**
|
|
|
|
* set the pin low just to be super sure
|
|
|
|
* this custom handling of zero value comes from CJ125 heater code
|
|
|
|
* TODO: is this really needed? cover by unit test?
|
|
|
|
*/
|
2019-04-12 17:15:18 -07:00
|
|
|
stateChangeCallback(0, arg);
|
2019-02-01 19:20:15 -08:00
|
|
|
}
|
|
|
|
|
2018-12-09 06:23:31 -08:00
|
|
|
if (dutyCycle < ZERO_PWM_THRESHOLD) {
|
2018-12-08 19:57:00 -08:00
|
|
|
mode = PM_ZERO;
|
2018-12-09 06:23:31 -08:00
|
|
|
} else if (dutyCycle > FULL_PWM_THRESHOLD) {
|
2018-12-08 19:57:00 -08:00
|
|
|
mode = PM_FULL;
|
|
|
|
} else {
|
|
|
|
mode = PM_NORMAL;
|
|
|
|
multiWave.setSwitchTime(0, dutyCycle);
|
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2018-12-08 18:23:49 -08:00
|
|
|
/**
|
|
|
|
* returns absolute timestamp of state change
|
|
|
|
*/
|
2015-07-10 06:01:56 -07:00
|
|
|
static efitimeus_t getNextSwitchTimeUs(PwmConfig *state) {
|
2018-07-25 20:30:00 -07:00
|
|
|
efiAssert(CUSTOM_ERR_ASSERT, state->safe.phaseIndex < PWM_PHASE_MAX_COUNT, "phaseIndex range", 0);
|
2015-07-10 06:01:56 -07:00
|
|
|
int iteration = state->safe.iteration;
|
2018-12-08 19:57:00 -08:00
|
|
|
// we handle PM_ZERO and PM_FULL separately
|
|
|
|
float switchTime = state->mode == PM_NORMAL ? state->multiWave.getSwitchTime(state->safe.phaseIndex) : 1;
|
2015-07-10 06:01:56 -07:00
|
|
|
float periodNt = state->safe.periodNt;
|
|
|
|
#if DEBUG_PWM
|
2018-01-23 09:05:14 -08:00
|
|
|
scheduleMsg(&logger, "iteration=%d switchTime=%.2f period=%.2f", iteration, switchTime, period);
|
2018-12-08 18:23:49 -08:00
|
|
|
#endif /* DEBUG_PWM */
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Once 'iteration' gets relatively high, we might lose calculation precision here.
|
|
|
|
* This is addressed by ITERATION_LIMIT
|
|
|
|
*/
|
|
|
|
efitime_t timeToSwitchNt = (efitime_t) ((iteration + switchTime) * periodNt);
|
|
|
|
|
|
|
|
#if DEBUG_PWM
|
|
|
|
scheduleMsg(&logger, "start=%d timeToSwitch=%d", state->safe.start, timeToSwitch);
|
2018-12-08 18:23:49 -08:00
|
|
|
#endif /* DEBUG_PWM */
|
2015-07-10 06:01:56 -07:00
|
|
|
return NT2US(state->safe.startNt + timeToSwitchNt);
|
|
|
|
}
|
|
|
|
|
2017-07-10 19:08:55 -07:00
|
|
|
void PwmConfig::setFrequency(float frequency) {
|
2018-01-21 12:28:03 -08:00
|
|
|
if (cisnan(frequency)) {
|
|
|
|
// explicit code just to be sure
|
|
|
|
periodNt = NAN;
|
|
|
|
return;
|
|
|
|
}
|
2017-07-10 19:08:55 -07:00
|
|
|
/**
|
|
|
|
* see #handleCycleStart()
|
|
|
|
*/
|
|
|
|
periodNt = US2NT(frequency2periodUs(frequency));
|
|
|
|
}
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
void PwmConfig::handleCycleStart() {
|
2018-12-08 18:23:49 -08:00
|
|
|
efiAssertVoid(CUSTOM_ERR_6697, safe.phaseIndex == 0, "handleCycleStart");
|
2018-02-05 14:16:16 -08:00
|
|
|
if (pwmCycleCallback != NULL) {
|
|
|
|
pwmCycleCallback(this);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2018-07-25 20:03:04 -07:00
|
|
|
efiAssertVoid(CUSTOM_ERR_6580, periodNt != 0, "period not initialized");
|
2015-07-10 06:01:56 -07:00
|
|
|
if (safe.periodNt != periodNt || safe.iteration == ITERATION_LIMIT) {
|
|
|
|
/**
|
|
|
|
* period length has changed - we need to reset internal state
|
|
|
|
*/
|
|
|
|
safe.startNt = getTimeNowNt();
|
|
|
|
safe.iteration = 0;
|
|
|
|
safe.periodNt = periodNt;
|
|
|
|
#if DEBUG_PWM
|
|
|
|
scheduleMsg(&logger, "state reset start=%d iteration=%d", state->safe.start, state->safe.iteration);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return Next time for signal toggle
|
|
|
|
*/
|
2018-01-21 12:31:46 -08:00
|
|
|
efitimeus_t PwmConfig::togglePwmState() {
|
2015-07-10 06:01:56 -07:00
|
|
|
#if DEBUG_PWM
|
2018-01-21 12:31:46 -08:00
|
|
|
scheduleMsg(&logger, "togglePwmState phaseIndex=%d iteration=%d", safe.phaseIndex, safe.iteration);
|
2019-02-10 19:47:49 -08:00
|
|
|
scheduleMsg(&logger, "period=%.2f safe.period=%.2f", period, safe.periodNt);
|
2015-07-10 06:01:56 -07:00
|
|
|
#endif
|
|
|
|
|
2018-01-21 12:31:46 -08:00
|
|
|
if (cisnan(periodNt)) {
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
2018-12-08 20:02:51 -08:00
|
|
|
* NaN period means PWM is paused, we also set the pin low
|
2015-07-10 06:01:56 -07:00
|
|
|
*/
|
2019-04-12 17:15:18 -07:00
|
|
|
stateChangeCallback(0, arg);
|
2018-12-08 19:57:00 -08:00
|
|
|
return getTimeNowUs() + MS2US(NAN_FREQUENCY_SLEEP_PERIOD_MS);
|
|
|
|
}
|
|
|
|
if (mode != PM_NORMAL) {
|
|
|
|
// in case of ZERO or FULL we are always at starting index
|
|
|
|
safe.phaseIndex = 0;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2018-12-08 18:23:49 -08:00
|
|
|
if (safe.phaseIndex == 0) {
|
|
|
|
handleCycleStart();
|
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Here is where the 'business logic' - the actual pin state change is happening
|
|
|
|
*/
|
2018-12-08 19:57:00 -08:00
|
|
|
int cbStateIndex;
|
|
|
|
if (mode == PM_NORMAL) {
|
|
|
|
// callback state index is offset by one. todo: why? can we simplify this?
|
|
|
|
cbStateIndex = safe.phaseIndex == 0 ? phaseCount - 1 : safe.phaseIndex - 1;
|
|
|
|
} else if (mode == PM_ZERO) {
|
|
|
|
cbStateIndex = 0;
|
|
|
|
} else {
|
|
|
|
cbStateIndex = 1;
|
|
|
|
}
|
|
|
|
|
2019-04-12 17:15:18 -07:00
|
|
|
stateChangeCallback(cbStateIndex, arg);
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2018-01-21 12:31:46 -08:00
|
|
|
efitimeus_t nextSwitchTimeUs = getNextSwitchTimeUs(this);
|
2015-07-10 06:01:56 -07:00
|
|
|
#if DEBUG_PWM
|
|
|
|
scheduleMsg(&logger, "%s: nextSwitchTime %d", state->name, nextSwitchTime);
|
2017-05-30 18:56:38 -07:00
|
|
|
#endif /* DEBUG_PWM */
|
2015-07-10 06:01:56 -07:00
|
|
|
// signed value is needed here
|
|
|
|
// int64_t timeToSwitch = nextSwitchTimeUs - getTimeNowUs();
|
|
|
|
// if (timeToSwitch < 1) {
|
|
|
|
// /**
|
|
|
|
// * We are here if we are late for a state transition.
|
|
|
|
// * At 12000RPM=200Hz with a 60 toothed wheel we need to change state every
|
|
|
|
// * 1000000 / 200 / 120 = ~41 uS. We are kind of OK.
|
|
|
|
// *
|
|
|
|
// * We are also here after a flash write. Flash write freezes the whole chip for a couple of seconds,
|
|
|
|
// * so PWM generation and trigger simulation generation would have to recover from this time lag.
|
|
|
|
// */
|
|
|
|
// //todo: introduce error and test this error handling warning(OBD_PCM_Processor_Fault, "PWM: negative switch time");
|
|
|
|
// timeToSwitch = 10;
|
|
|
|
// }
|
|
|
|
|
2018-01-21 12:31:46 -08:00
|
|
|
safe.phaseIndex++;
|
2018-12-08 19:57:00 -08:00
|
|
|
if (safe.phaseIndex == phaseCount || mode != PM_NORMAL) {
|
2018-01-21 12:31:46 -08:00
|
|
|
safe.phaseIndex = 0; // restart
|
|
|
|
safe.iteration++;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2018-12-08 19:57:00 -08:00
|
|
|
#if EFI_UNIT_TEST
|
|
|
|
printf("PWM: nextSwitchTimeUs=%d phaseIndex=%d iteration=%d\r\n", nextSwitchTimeUs,
|
|
|
|
safe.phaseIndex,
|
|
|
|
safe.iteration);
|
|
|
|
#endif /* EFI_UNIT_TEST */
|
2015-07-10 06:01:56 -07:00
|
|
|
return nextSwitchTimeUs;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Main PWM loop: toggle pin & schedule next invocation
|
2018-09-10 19:43:57 -07:00
|
|
|
*
|
|
|
|
* First invocation happens on application thread
|
2015-07-10 06:01:56 -07:00
|
|
|
*/
|
|
|
|
static void timerCallback(PwmConfig *state) {
|
|
|
|
state->dbgNestingLevel++;
|
2018-07-25 20:03:04 -07:00
|
|
|
efiAssertVoid(CUSTOM_ERR_6581, state->dbgNestingLevel < 25, "PWM nesting issue");
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2018-01-21 12:31:46 -08:00
|
|
|
efitimeus_t switchTimeUs = state->togglePwmState();
|
2019-01-09 07:17:35 -08:00
|
|
|
if (state->executor == NULL) {
|
|
|
|
firmwareError(CUSTOM_ERR_6695, "exec on %s", state->name);
|
|
|
|
return;
|
|
|
|
}
|
2019-01-09 05:50:51 -08:00
|
|
|
|
2019-01-09 06:37:16 -08:00
|
|
|
state->executor->scheduleByTimestamp(&state->scheduling, switchTimeUs, (schfunc_t) timerCallback, state);
|
2015-07-10 06:01:56 -07:00
|
|
|
state->dbgNestingLevel--;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Incoming parameters are potentially just values on current stack, so we have to copy
|
|
|
|
* into our own permanent storage, right?
|
|
|
|
*/
|
2019-02-02 22:14:19 -08:00
|
|
|
void copyPwmParameters(PwmConfig *state, int phaseCount, float const *switchTimes, int waveCount, pin_state_t *const *pinStates) {
|
2015-07-10 06:01:56 -07:00
|
|
|
state->phaseCount = phaseCount;
|
|
|
|
|
|
|
|
for (int phaseIndex = 0; phaseIndex < phaseCount; phaseIndex++) {
|
|
|
|
state->multiWave.setSwitchTime(phaseIndex, switchTimes[phaseIndex]);
|
|
|
|
|
2018-12-25 07:13:00 -08:00
|
|
|
for (int channelIndex = 0; channelIndex < waveCount; channelIndex++) {
|
|
|
|
// print("output switch time index (%d/%d) at %.2f to %d\r\n", phaseIndex, channelIndex,
|
2015-07-10 06:01:56 -07:00
|
|
|
// switchTimes[phaseIndex], pinStates[waveIndex][phaseIndex]);
|
2019-02-02 22:19:16 -08:00
|
|
|
pin_state_t value = pinStates[channelIndex][phaseIndex];
|
2018-12-25 07:13:00 -08:00
|
|
|
state->multiWave.channels[channelIndex].setState(phaseIndex, value);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
}
|
2018-12-08 19:57:00 -08:00
|
|
|
if (state->mode == PM_NORMAL) {
|
|
|
|
state->multiWave.checkSwitchTimes(phaseCount);
|
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2018-12-08 12:07:07 -08:00
|
|
|
/**
|
|
|
|
* this method also starts the timer cycle
|
|
|
|
* See also startSimplePwm
|
|
|
|
*/
|
2019-02-02 22:14:19 -08:00
|
|
|
void PwmConfig::weComplexInit(const char *msg, ExecutorInterface *executor,
|
|
|
|
const int phaseCount,
|
|
|
|
float const *switchTimes,
|
|
|
|
const int waveCount,
|
2019-02-02 22:11:50 -08:00
|
|
|
pin_state_t *const*pinStates, pwm_cycle_callback *pwmCycleCallback, pwm_gen_callback *stateChangeCallback) {
|
2019-03-08 04:01:15 -08:00
|
|
|
UNUSED(msg);
|
2019-01-09 05:50:51 -08:00
|
|
|
this->executor = executor;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2018-07-25 20:03:04 -07:00
|
|
|
efiAssertVoid(CUSTOM_ERR_6582, periodNt != 0, "period is not initialized");
|
2015-07-10 06:01:56 -07:00
|
|
|
if (phaseCount == 0) {
|
2016-10-10 13:02:39 -07:00
|
|
|
firmwareError(CUSTOM_ERR_PWM_1, "signal length cannot be zero");
|
2015-07-10 06:01:56 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (phaseCount > PWM_PHASE_MAX_COUNT) {
|
2016-10-10 13:02:39 -07:00
|
|
|
firmwareError(CUSTOM_ERR_PWM_2, "too many phases in PWM");
|
2015-07-10 06:01:56 -07:00
|
|
|
return;
|
|
|
|
}
|
2018-07-25 20:03:04 -07:00
|
|
|
efiAssertVoid(CUSTOM_ERR_6583, waveCount > 0, "waveCount should be positive");
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2018-02-05 14:16:16 -08:00
|
|
|
this->pwmCycleCallback = pwmCycleCallback;
|
2015-07-10 06:01:56 -07:00
|
|
|
this->stateChangeCallback = stateChangeCallback;
|
|
|
|
|
|
|
|
multiWave.waveCount = waveCount;
|
|
|
|
|
|
|
|
copyPwmParameters(this, phaseCount, switchTimes, waveCount, pinStates);
|
|
|
|
|
|
|
|
safe.phaseIndex = 0;
|
|
|
|
safe.periodNt = -1;
|
|
|
|
safe.iteration = -1;
|
|
|
|
|
|
|
|
// let's start the indefinite callback loop of PWM generation
|
|
|
|
timerCallback(this);
|
|
|
|
}
|
2018-11-02 10:38:31 -07:00
|
|
|
|
2019-01-09 05:50:51 -08:00
|
|
|
void startSimplePwm(SimplePwm *state, const char *msg, ExecutorInterface *executor,
|
|
|
|
OutputPin *output, float frequency, float dutyCycle, pwm_gen_callback *stateChangeCallback) {
|
2018-12-08 12:07:07 -08:00
|
|
|
efiAssertVoid(CUSTOM_ERR_6692, state != NULL, "state");
|
2018-11-02 10:38:31 -07:00
|
|
|
efiAssertVoid(CUSTOM_ERR_6665, dutyCycle >= 0 && dutyCycle <= 1, "dutyCycle");
|
2019-02-01 20:48:11 -08:00
|
|
|
efiAssertVoid(CUSTOM_ERR_6693, stateChangeCallback != NULL, "listener");
|
2018-11-02 10:38:31 -07:00
|
|
|
if (frequency < 1) {
|
|
|
|
warning(CUSTOM_OBD_LOW_FREQUENCY, "low frequency %.2f", frequency);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
float switchTimes[] = { dutyCycle, 1 };
|
2019-02-02 22:27:47 -08:00
|
|
|
pin_state_t pinStates0[] = { TV_FALL, TV_RISE };
|
2018-12-08 19:57:00 -08:00
|
|
|
state->setSimplePwmDutyCycle(dutyCycle);
|
2018-11-02 10:38:31 -07:00
|
|
|
|
|
|
|
pin_state_t *pinStates[1] = { pinStates0 };
|
|
|
|
|
|
|
|
state->outputPins[0] = output;
|
|
|
|
|
|
|
|
state->setFrequency(frequency);
|
2019-01-09 05:50:51 -08:00
|
|
|
state->weComplexInit(msg, executor, 2, switchTimes, 1, pinStates, NULL, stateChangeCallback);
|
2018-11-02 10:38:31 -07:00
|
|
|
}
|
|
|
|
|
2019-01-09 05:50:51 -08:00
|
|
|
void startSimplePwmExt(SimplePwm *state, const char *msg,
|
|
|
|
ExecutorInterface *executor,
|
|
|
|
brain_pin_e brainPin, OutputPin *output, float frequency,
|
2018-11-02 10:38:31 -07:00
|
|
|
float dutyCycle, pwm_gen_callback *stateChangeCallback) {
|
|
|
|
|
|
|
|
output->initPin(msg, brainPin);
|
|
|
|
|
2019-01-09 05:50:51 -08:00
|
|
|
startSimplePwm(state, msg, executor, output, frequency, dutyCycle, stateChangeCallback);
|
2018-11-02 10:38:31 -07:00
|
|
|
}
|
|
|
|
|
2018-11-03 10:45:36 -07:00
|
|
|
/**
|
|
|
|
* This method controls the actual hardware pins
|
|
|
|
*
|
|
|
|
* This method takes ~350 ticks.
|
|
|
|
*/
|
2019-04-12 17:15:18 -07:00
|
|
|
void applyPinState(int stateIndex, PwmConfig *state) /* pwm_gen_callback */ {
|
2018-11-03 10:45:36 -07:00
|
|
|
efiAssertVoid(CUSTOM_ERR_6663, stateIndex < PWM_PHASE_MAX_COUNT, "invalid stateIndex");
|
|
|
|
efiAssertVoid(CUSTOM_ERR_6664, state->multiWave.waveCount <= PWM_PHASE_MAX_WAVE_PER_PWM, "invalid waveCount");
|
2018-12-25 07:13:00 -08:00
|
|
|
for (int channelIndex = 0; channelIndex < state->multiWave.waveCount; channelIndex++) {
|
|
|
|
OutputPin *output = state->outputPins[channelIndex];
|
|
|
|
int value = state->multiWave.getChannelState(channelIndex, stateIndex);
|
2018-11-03 10:45:36 -07:00
|
|
|
output->setValue(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|