This commit is contained in:
Andrey B 2014-04-26 09:09:26 -05:00
parent 45732d88cb
commit de303ed994
40 changed files with 217 additions and 1594 deletions

View File

@ -263,9 +263,9 @@
#define LED_COMMUNICATION_PORT GPIOD
#define LED_COMMUNICATION_PIN GPIOD_LED6
#define EFI_SIGNAL_EXECUTOR_SLEEP TRUE
#define EFI_SIGNAL_EXECUTOR_SLEEP FALSE
#define EFI_SIGNAL_EXECUTOR_SINGLE_TIMER FALSE
#define EFI_SIGNAL_EXECUTOR_ONE_TIMER FALSE
#define EFI_SIGNAL_EXECUTOR_ONE_TIMER TRUE
#define EFI_SIGNAL_EXECUTOR_HW_TIMER FALSE
//#define EFI_SIGNAL_EXECUTOR_SLEEP FALSE

View File

@ -50,7 +50,7 @@ extern FlashState flashState;
extern SerialUSBDriver SDU1;
#define CONSOLE_DEVICE &SDU1
int previousWriteReport = 0;
static efitimems_t previousWriteReportMs = 0;
#if EFI_TUNER_STUDIO_OVER_USB
#define ts_serail_ready() is_usb_serial_ready()
@ -150,9 +150,9 @@ void handleValueWriteCommand(void) {
// unsigned char value = writeBuffer[1];
//
int now = chTimeNow();
if (overflowDiff(now, previousWriteReport) > 5 * TICKS_IN_MS) {
previousWriteReport = now;
efitimems_t nowMs = currentTimeMillis();
if (nowMs - previousWriteReportMs > 5) {
previousWriteReportMs = nowMs;
// scheduleMsg(&logger, "page %d offset %d: value=%d", pageId, writeRequest.offset, writeRequest.value);
}
@ -218,7 +218,7 @@ static msg_t tsThreadEntryPoint(void *arg) {
}
if (!wasReady) {
wasReady = TRUE;
// scheduleSimpleMsg(&logger, "ts channel is now ready ", chTimeNow());
// scheduleSimpleMsg(&logger, "ts channel is now ready ", hTimeNow());
}
short command = (short) chSequentialStreamGet(TS_SERIAL_DEVICE);

View File

@ -1,5 +1,11 @@
/**
* @file event_queue.cpp
* This is a data structure which keeps track of all pending events
* Implemented as a linked list, which is fine since the number of
* pending events is pretty low
* todo: MAYBE migrate to a better data structure, but that's low priority
*
* this data structure is NOT thread safe
*
* @date Apr 17, 2014
* @author Andrey Belomutskiy, (c) 2012-2014
@ -13,8 +19,7 @@ EventQueue::EventQueue() {
head = NULL;
}
void EventQueue::schedule(scheduling_s *scheduling, uint64_t nowUs, int delayUs,
schfunc_t callback, void *param) {
void EventQueue::insertTask(scheduling_s *scheduling, uint64_t nowUs, int delayUs, schfunc_t callback, void *param) {
if (callback == NULL)
firmwareError("NULL callback");
uint64_t time = nowUs + delayUs;
@ -37,34 +42,40 @@ void EventQueue::schedule(scheduling_s *scheduling, uint64_t nowUs, int delayUs,
LL_PREPEND(head, scheduling);
}
void EventQueue::schedule(scheduling_s *scheduling, int delayUs,
schfunc_t callback, void *param) {
schedule(scheduling, getTimeNowUs(), delayUs, callback, param);
void EventQueue::insertTask(scheduling_s *scheduling, int delayUs, schfunc_t callback, void *param) {
insertTask(scheduling, getTimeNowUs(), delayUs, callback, param);
}
uint64_t EventQueue::getNextEventTime(void) {
/**
* Get the timestamp of the soonest pending action
*/
uint64_t EventQueue::getNextEventTime(uint64_t nowUs) {
scheduling_s * elt;
// this is a large value which is expected to be larger than any real time
uint64_t result = EMPTY_QUEUE;
LL_FOREACH(head, elt)
{
if (elt->momentUs <= nowUs) {
// todo: I am not so sure about this branch
continue;
}
if (elt->momentUs < result)
result = elt->momentUs;
}
return result;
}
void EventQueue::execute(uint64_t now) {
/**
* Invoke all pending actions prior to specified timestamp
*/
void EventQueue::executeAll(uint64_t now) {
scheduling_s * elt, *tmp;
// DL_FOREACH_SAFE()
// here we need safe iteration because we are removing elements
LL_FOREACH_SAFE(head, elt, tmp)
{
if (elt->momentUs < now) {
if (elt->momentUs <= now) {
LL_DELETE(head, elt);
#if EFI_SIGNAL_EXECUTOR_ONE_TIMER
elt->callback(elt->param);
@ -72,3 +83,7 @@ void EventQueue::execute(uint64_t now) {
}
}
}
void EventQueue::clear(void) {
head = NULL;
}

View File

@ -16,12 +16,13 @@ class EventQueue {
public:
EventQueue();
void schedule(scheduling_s *scheduling, int delayUs, schfunc_t callback, void *param);
void schedule(scheduling_s *scheduling, uint64_t nowUs, int delayUs, schfunc_t callback, void *param);
void insertTask(scheduling_s *scheduling, int delayUs, schfunc_t callback, void *param);
void insertTask(scheduling_s *scheduling, uint64_t nowUs, int delayUs, schfunc_t callback, void *param);
void execute(uint64_t now);
void executeAll(uint64_t now);
uint64_t getNextEventTime(void);
uint64_t getNextEventTime(uint64_t nowUs);
void clear(void);
private:
scheduling_s *head;
};

View File

@ -51,13 +51,13 @@ void initSignalExecutor(void) {
void initOutputSignalBase(OutputSignal *signal) {
signal->status = IDLE;
signal->last_scheduling_time = 0;
// signal->last_scheduling_time = 0;
signal->initialized = TRUE;
}
static void turnHigh(OutputSignal *signal) {
#if EFI_DEFAILED_LOGGING
signal->hi_time = chTimeNow();
// signal->hi_time = hTimeNow();
#endif /* EFI_DEFAILED_LOGGING */
io_pin_e pin = signal->io_pin;
// turn the output level ACTIVE
@ -69,7 +69,7 @@ static void turnHigh(OutputSignal *signal) {
if(
pin == SPARKOUT_1_OUTPUT ||
pin == SPARKOUT_3_OUTPUT) {
// time_t now = chTimeNow();
// time_t now = hTimeNow();
// float an = getCrankshaftAngle(now);
// scheduleMsg(&logger, "spark up%d %d", pin, now);
// scheduleMsg(&logger, "spark angle %d %f", (int)an, an);
@ -87,7 +87,7 @@ static void turnLow(OutputSignal *signal) {
setOutputPinValue(signal->io_pin, FALSE);
#if EFI_DEFAILED_LOGGING
systime_t after = chTimeNow();
systime_t after = hTimeNow();
debugInt(&signal->logging, "a_time", after - signal->hi_time);
scheduleLogging(&signal->logging);
#endif /* EFI_DEFAILED_LOGGING */
@ -107,7 +107,7 @@ static void turnLow(OutputSignal *signal) {
int getRevolutionCounter(void);
void scheduleOutput(OutputSignal *signal, float delayMs, float durationMs, time_t now) {
void scheduleOutput(OutputSignal *signal, float delayMs, float durationMs) {
if (durationMs < 0) {
firmwareError("duration cannot be negative: %d", durationMs);
return;
@ -119,10 +119,10 @@ void scheduleOutput(OutputSignal *signal, float delayMs, float durationMs, time_
scheduling_s * sUp = &signal->signalTimerUp[index];
scheduling_s * sDown = &signal->signalTimerDown[index];
scheduleTask(sUp, TICKS_IN_MS * delayMs, (schfunc_t) &turnHigh, (void *) signal);
scheduleTask(sDown, TICKS_IN_MS * (delayMs + durationMs), (schfunc_t) &turnLow, (void*)signal);
scheduleTask(sUp, MS2US(delayMs), (schfunc_t) &turnHigh, (void *) signal);
scheduleTask(sDown, MS2US(delayMs + durationMs), (schfunc_t) &turnLow, (void*)signal);
signal->last_scheduling_time = now;
// signal->last_scheduling_time = now;
}
void scheduleOutputBase(OutputSignal *signal, float delayMs, float durationMs) {

View File

@ -69,8 +69,8 @@ struct OutputSignal_struct {
#endif
int initialized;
time_t last_scheduling_time;
time_t hi_time;
// time_t last_scheduling_time;
// time_t hi_time;
/**
* We are alternating instances so that events which extend into next revolution are not overriden while
@ -95,13 +95,13 @@ extern "C"
#endif /* __cplusplus */
void initOutputSignal(OutputSignal *signal, io_pin_e ioPin);
void scheduleOutput(OutputSignal *signal, float delayMs, float durationMs, time_t now);
void scheduleOutput(OutputSignal *signal, float delayMs, float durationMs);
void initOutputSignalBase(OutputSignal *signal);
void scheduleOutputBase(OutputSignal *signal, float delayMs, float durationMs);
void initSignalExecutor(void);
void initSignalExecutorImpl(void);
void scheduleTask(scheduling_s *scheduling, float delay, schfunc_t callback, void *param);
void scheduleTask(scheduling_s *scheduling, int delayUs, schfunc_t callback, void *param);
void scheduleByAngle(scheduling_s *timer, float angle, schfunc_t callback, void *param);
#ifdef __cplusplus

View File

@ -66,7 +66,7 @@ inline time_t toggleSignalIfNeeded(OutputSignal *out, time_t now) {
// addWaveChartEvent(out->name, out->status ? "up" : "down", "");
#endif /* EFI_WAVE_ANALYZER */
out->last_scheduling_time = now; /* store last update */
// out->last_scheduling_time = now; /* store last update */
estimated = now + GET_DURATION(out); /* update estimation */
}
return estimated - now;

View File

@ -1,203 +0,0 @@
/**
* @file trigger_decoder.c
*
* @date Dec 24, 2013
* @author Andrey Belomutskiy, (c) 2012-2014
*
* This file is part of rusEfi - see http://rusefi.com
*
* rusEfi is free software; you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "main.h"
#include "trigger_decoder.h"
#include "cyclic_buffer.h"
extern "C"
{
#include "trigger_mazda.h"
}
#if EFI_PROD_CODE || EFI_SIMULATOR
static Logging logger;
#endif
static cyclic_buffer errorDetection;
/**
* @return TRUE is something is wrong with trigger decoding
*/
int isTriggerDecoderError(void) {
return errorDetection.sum(6) > 4;
}
static inline int isSynchronizationGap(trigger_state_s *shaftPositionState, trigger_shape_s *triggerShape,
trigger_config_s *triggerConfig, int currentDuration) {
if (!triggerConfig->isSynchronizationNeeded)
return FALSE;
return currentDuration > shaftPositionState->toothed_previous_duration * triggerConfig->syncRatioFrom
&& currentDuration < shaftPositionState->toothed_previous_duration * triggerConfig->syncRatioTo;
}
static inline int noSynchronizationResetNeeded(trigger_state_s *shaftPositionState, trigger_shape_s *triggerShape,
trigger_config_s *triggerConfig) {
if (triggerConfig->isSynchronizationNeeded)
return FALSE;
if (!shaftPositionState->shaft_is_synchronized)
return TRUE;
/**
* in case of noise the counter could be above the expected number of events
*/
return shaftPositionState->current_index >= triggerShape->shaftPositionEventCount - 1;
}
/**
* @brief This method changes the state of trigger_state_s data structure according to the trigger event
*/
void processTriggerEvent(trigger_state_s *shaftPositionState, trigger_shape_s *triggerShape,
trigger_config_s *triggerConfig, ShaftEvents signal, time_t now) {
int isLessImportant = (triggerConfig->useRiseEdge && signal != SHAFT_PRIMARY_UP)
|| (!triggerConfig->useRiseEdge && signal != SHAFT_PRIMARY_DOWN);
if (isLessImportant) {
/**
* For less important events we simply increment the index.
*/
shaftPositionState->current_index++;
return;
}
int currentDuration = now - shaftPositionState->toothed_previous_time;
// todo: skip a number of signal from the beginning
#if EFI_PROD_CODE
// scheduleMsg(&logger, "from %f to %f %d %d", triggerConfig->syncRatioFrom, triggerConfig->syncRatioTo, currentDuration, shaftPositionState->toothed_previous_duration);
// scheduleMsg(&logger, "ratio %f", 1.0 * currentDuration/ shaftPositionState->toothed_previous_duration);
#else
if (shaftPositionState->toothed_previous_duration != 0) {
// printf("ratio %f: cur=%d pref=%d\r\n", 1.0 * currentDuration / shaftPositionState->toothed_previous_duration,
// currentDuration, shaftPositionState->toothed_previous_duration);
}
#endif
if (noSynchronizationResetNeeded(shaftPositionState, triggerShape, triggerConfig)
|| isSynchronizationGap(shaftPositionState, triggerShape, triggerConfig, currentDuration)) {
/**
* We can check if things are fine by comparing the number of events in a cycle with the expected number of event.
*/
int isDecodingError = shaftPositionState->current_index != triggerShape->shaftPositionEventCount - 1;
errorDetection.add(isDecodingError);
shaftPositionState->shaft_is_synchronized = TRUE;
shaftPositionState->current_index = 0;
} else {
shaftPositionState->current_index++;
}
shaftPositionState->toothed_previous_duration = currentDuration;
shaftPositionState->toothed_previous_time = now;
}
static void initializeSkippedToothTriggerShape(trigger_shape_s *s, int totalTeethCount, int skippedCount) {
triggerShapeInit(s);
float toothWidth = 0.5;
for (int i = 0; i < totalTeethCount - skippedCount - 1; i++) {
float angleDown = 720.0 / totalTeethCount * (i + toothWidth);
float angleUp = 720.0 / totalTeethCount * (i + 1);
triggerAddEvent(s, angleDown, T_PRIMARY, TV_HIGH);
triggerAddEvent(s, angleUp, T_PRIMARY, TV_LOW);
}
float angleDown = 720.0 / totalTeethCount * (totalTeethCount - skippedCount - 1 + toothWidth);
triggerAddEvent(s, angleDown, T_PRIMARY, TV_HIGH);
triggerAddEvent(s, 720, T_PRIMARY, TV_LOW);
}
void initializeSkippedToothTriggerShapeExt(engine_configuration2_s *engineConfiguration2, int totalTeethCount,
int skippedCount) {
trigger_shape_s *s = &engineConfiguration2->triggerShape;
initializeSkippedToothTriggerShape(s, totalTeethCount, skippedCount);
engineConfiguration2->triggerShape.shaftPositionEventCount = ((totalTeethCount - skippedCount) * 2);
checkSwitchTimes(s->size, s->wave.switchTimes);
}
static void configureNeonTriggerShape(trigger_shape_s *s) {
triggerShapeInit(s);
triggerAddEvent(s, 60, T_PRIMARY, TV_HIGH);
triggerAddEvent(s, 210, T_PRIMARY, TV_LOW);
triggerAddEvent(s, 420, T_PRIMARY, TV_HIGH);
triggerAddEvent(s, 630, T_PRIMARY, TV_LOW);
// voodoo magic - we always need 720 at the end
triggerAddEvent(s, 720, T_PRIMARY, TV_LOW);
s->shaftPositionEventCount = 4;
}
static void confgiureFordAspireTriggerShape(trigger_shape_s * s) {
triggerShapeInit(s);
s->shaftPositionEventCount = 10;
triggerAddEvent(s, 53.747, T_SECONDARY, TV_HIGH);
triggerAddEvent(s, 121.90, T_SECONDARY, TV_LOW);
triggerAddEvent(s, 232.76, T_SECONDARY, TV_HIGH);
triggerAddEvent(s, 300.54, T_SECONDARY, TV_LOW);
triggerAddEvent(s, 360, T_PRIMARY, TV_HIGH);
triggerAddEvent(s, 409.8412, T_SECONDARY, TV_HIGH);
triggerAddEvent(s, 478.6505, T_SECONDARY, TV_LOW);
triggerAddEvent(s, 588.045, T_SECONDARY, TV_HIGH);
triggerAddEvent(s, 657.03, T_SECONDARY, TV_LOW);
triggerAddEvent(s, 720, T_PRIMARY, TV_LOW);
}
void initializeTriggerShape(engine_configuration_s *engineConfiguration, engine_configuration2_s *engineConfiguration2) {
trigger_config_s *tt = &engineConfiguration->triggerConfig;
switch (tt->triggerType) {
case TT_TOOTHED_WHEEL:
initializeSkippedToothTriggerShapeExt(engineConfiguration2, tt->totalToothCount, tt->skippedToothCount);
return;
case TT_MAZDA_MIATA_NB:
initializeMazdaMiataNbShape(&engineConfiguration2->triggerShape);
return;
case TT_DODGE_NEON:
configureNeonTriggerShape(&engineConfiguration2->triggerShape);
return;
case TT_FORD_ASPIRE:
confgiureFordAspireTriggerShape(&engineConfiguration2->triggerShape);
return;
default:
fatal("not implemented")
;
}
}
void initTriggerDecoder(void) {
#if EFI_PROD_CODE || EFI_SIMULATOR
initLogging(&logger, "trigger decoder");
#endif
}

View File

@ -1,35 +0,0 @@
/**
* @file trigger_decoder.h
*
* @date Dec 24, 2013
* @author Andrey Belomutskiy, (c) 2012-2013
*/
#ifndef TRIGGER_DECODER_H_
#define TRIGGER_DECODER_H_
#include <time.h>
#ifdef __cplusplus
extern "C"
{
#include "trigger_structure.h"
#include "engine_configuration.h"
#else
#include "trigger_structure.h"
#include "engine_configuration.h"
#endif
int isTriggerDecoderError(void);
void processTriggerEvent(trigger_state_s *shaftPositionState, trigger_shape_s *triggerShape, trigger_config_s *triggerConfig, ShaftEvents signal, time_t now);
void initializeSkippedToothTriggerShapeExt(engine_configuration2_s *engineConfiguration2, int totalTeethCount, int skippedCount);
void initializeTriggerShape(engine_configuration_s *engineConfiguration, engine_configuration2_s *engineConfiguration2);
void initTriggerDecoder(void);
#ifdef __cplusplus
}
#endif
#endif /* TRIGGER_DECODER_H_ */

View File

@ -1,58 +0,0 @@
/**
* @file trigger_mazda.c
*
* @date Feb 18, 2014
* @author Andrey Belomutskiy, (c) 2012-2014
*
* This file is part of rusEfi - see http://rusefi.com
*
* rusEfi is free software; you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "trigger_mazda.h"
void initializeMazdaMiataNbShape(trigger_shape_s *s) {
triggerShapeInit(s);
/**
* cam sensor is primary, crank sensor is secondary
*/
triggerAddEvent(s, 20, T_PRIMARY, TV_LOW);
triggerAddEvent(s, 66, T_SECONDARY, TV_HIGH);
triggerAddEvent(s, 70, T_SECONDARY, TV_LOW);
triggerAddEvent(s, 136, T_SECONDARY, TV_HIGH);
triggerAddEvent(s, 140, T_SECONDARY, TV_LOW);
triggerAddEvent(s, 246, T_SECONDARY, TV_HIGH);
triggerAddEvent(s, 250, T_SECONDARY, TV_LOW);
triggerAddEvent(s, 316, T_SECONDARY, TV_HIGH);
triggerAddEvent(s, 320, T_SECONDARY, TV_LOW);
triggerAddEvent(s, 340, T_PRIMARY, TV_HIGH);
triggerAddEvent(s, 360, T_PRIMARY, TV_LOW);
triggerAddEvent(s, 380, T_PRIMARY, TV_HIGH);
triggerAddEvent(s, 400, T_PRIMARY, TV_LOW);
triggerAddEvent(s, 426, T_SECONDARY, TV_HIGH);
triggerAddEvent(s, 430, T_SECONDARY, TV_LOW);
triggerAddEvent(s, 496, T_SECONDARY, TV_HIGH);
triggerAddEvent(s, 500, T_SECONDARY, TV_LOW);
triggerAddEvent(s, 606, T_SECONDARY, TV_HIGH);
triggerAddEvent(s, 610, T_SECONDARY, TV_LOW);
triggerAddEvent(s, 676, T_SECONDARY, TV_HIGH);
triggerAddEvent(s, 680, T_SECONDARY, TV_LOW);
triggerAddEvent(s, 720, T_PRIMARY, TV_HIGH);
s->shaftPositionEventCount = 6 + 16;
}

View File

@ -1,24 +0,0 @@
/**
* @file trigger_mazda.h
*
* @date Feb 18, 2014
* @author Andrey Belomutskiy, (c) 2012-2013
*/
#ifndef TRIGGER_MAZDA_H_
#define TRIGGER_MAZDA_H_
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
#include "trigger_structure.h"
void initializeMazdaMiataNbShape(trigger_shape_s *s);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* TRIGGER_MAZDA_H_ */

View File

@ -1,60 +0,0 @@
/**
* @file trigger_structure.c
*
* @date Jan 20, 2014
* @author Andrey Belomutskiy, (c) 2012-2014
*
* This file is part of rusEfi - see http://rusefi.com
*
* rusEfi is free software; you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "main.h"
#include "trigger_structure.h"
void clearTriggerState(trigger_state_s *state) {
state->shaft_is_synchronized = FALSE;
state->toothed_previous_time = 0;
state->toothed_previous_duration = 0;
state->current_index = 0;
}
void triggerShapeInit(trigger_shape_s *trigger) {
memset(trigger, 0, sizeof(trigger_shape_s));
}
void triggerAddEvent(trigger_shape_s *trigger, float angle, trigger_wheel_e waveIndex, trigger_value_e state) {
angle /= 720;
if (trigger->size == 0) {
trigger->size = 1;
for (int i = 0; i < PWM_PHASE_MAX_WAVE_PER_PWM; i++)
trigger->wave.waves[i].pinStates[0] = 0;
trigger->wave.switchTimes[0] = angle;
trigger->wave.waves[waveIndex].pinStates[0] = state;
return;
}
// if(angle!=trigger->wave.switchTimes[trigger->currentIndex])
int index = trigger->size++;
for (int i = 0; i < PWM_PHASE_MAX_WAVE_PER_PWM; i++)
trigger->wave.waves[i].pinStates[index] = trigger->wave.waves[i].pinStates[index - 1];
trigger->wave.switchTimes[index] = angle;
trigger->wave.waves[waveIndex].pinStates[index] = state;
}
void checkSwitchTimes(int size, float *switchTimes) {
for (int i = 0; i < size - 1; i++)
chDbgCheck(switchTimes[i] < switchTimes[i + 1], "invalid switchTimes");
}

View File

@ -1,106 +0,0 @@
/**
* @file trigger_structure.h
*
* @date Dec 22, 2013
* @author Andrey Belomutskiy, (c) 2012-2013
*/
#ifndef TRIGGER_STRUCTURE_H_
#define TRIGGER_STRUCTURE_H_
#include "rusefi_enums.h"
#define PWM_PHASE_MAX_COUNT 150
#define PWM_PHASE_MAX_WAVE_PER_PWM 2
typedef enum {
SHAFT_PRIMARY_UP = 0,
SHAFT_PRIMARY_DOWN = 1,
SHAFT_SECONDARY_UP = 2,
SHAFT_SECONDARY_DOWN = 3,
} ShaftEvents;
typedef struct {
/**
* TRUE if we know where we are
*/
unsigned char shaft_is_synchronized;
int current_index;
int toothed_previous_duration;
int toothed_previous_time;
} trigger_state_s;
/**
* @brief PWM configuration for the specific output pin
*/
typedef struct {
int pinStates[PWM_PHASE_MAX_COUNT];
} single_wave_s;
typedef struct {
/**
* Number of events in the cycle
*/
int phaseCount;
/**
* Number of signal wires
*/
int waveCount;
single_wave_s waves[PWM_PHASE_MAX_WAVE_PER_PWM];
/**
* values in the (0..1] range which refer to points within the period at at which pin state should be changed
* So, in the simplest case we turn pin off at 0.3 and turn it on at 1 - that would give us a 70% duty cycle PWM
*/
float switchTimes[PWM_PHASE_MAX_COUNT];
} multi_wave_s;
typedef enum {
TV_LOW = 0,
TV_HIGH = 1
} trigger_value_e;
typedef enum {
T_PRIMARY = 0,
T_SECONDARY = 1
} trigger_wheel_e;
/**
* @brief Trigger wheel(s) configuration
*/
typedef struct {
trigger_type_e triggerType;
int isSynchronizationNeeded;
int totalToothCount;
int skippedToothCount;
float syncRatioFrom;
float syncRatioTo;
int useRiseEdge;
} trigger_config_s;
typedef struct {
multi_wave_s wave;
int size;
/**
* Total count of shaft events per CAM or CRANK shaft revolution.
* TODO this should be migrated to CRANKshaft revolution, this would go together
* TODO with eliminating RPM_MULT magic constant
*/
int shaftPositionEventCount;
} trigger_shape_s;
void clearTriggerState(trigger_state_s *state);
void triggerShapeInit(trigger_shape_s *trigger);
void triggerAddEvent(trigger_shape_s *trigger, float angle, trigger_wheel_e waveIndex, trigger_value_e state);
void checkSwitchTimes(int size, float *switchTimes);
#endif /* TRIGGER_STRUCTURE_H_ */

View File

@ -110,7 +110,7 @@ void publishChart(WaveChart *chart) {
* @brief Register a change in sniffed signal
*/
void addWaveChartEvent3(WaveChart *chart, char *name, char * msg, char * msg2) {
chDbgCheck(chart->isInitialized, "chart not initizlied");
chDbgCheck(chart->isInitialized, "chart not initialized");
#if DEBUG_WAVE
scheduleSimpleMsg(&debugLogging, "current", chart->counter);
#endif
@ -118,7 +118,8 @@ void addWaveChartEvent3(WaveChart *chart, char *name, char * msg, char * msg2) {
return;
lockOutputBuffer(); // we have multiple threads writing to the same output buffer
appendPrintf(&chart->logging, "%s%s%s%s", name, CHART_DELIMETER, msg, CHART_DELIMETER);
appendPrintf(&chart->logging, "%d%s%s", chTimeNow(), msg2, CHART_DELIMETER);
int time100 = getTimeNowUs() / 10;
appendPrintf(&chart->logging, "%d%s%s", time100, msg2, CHART_DELIMETER);
chart->counter++;
unlockOutputBuffer();
}

View File

@ -1,221 +0,0 @@
/**
* @file engine_controller.c
* @brief Controllers package entry point code
*
*
*
* @date Feb 7, 2013
* @author Andrey Belomutskiy, (c) 2012-2014
*
* This file is part of rusEfi - see http://rusefi.com
*
* rusEfi is free software; you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "main.h"
#include "trigger_central.h"
#include "engine_controller.h"
#include "idle_thread.h"
#include "rpm_calculator.h"
#include "signal_executor.h"
#include "main_trigger_callback.h"
#include "map_multiplier_thread.h"
#include "io_pins.h"
#include "tunerstudio.h"
#include "injector_central.h"
#include "ignition_central.h"
#include "rfiutil.h"
#include "engine_configuration.h"
#include "engine_math.h"
#include "wave_analyzer.h"
#include "allsensors.h"
#include "analog_chart.h"
#include "electronic_throttle.h"
#include "malfunction_indicator.h"
#include "map_averaging.h"
#include "malfunction_central.h"
#include "pin_repository.h"
#include "pwm_generator.h"
#include "adc_inputs.h"
#include "algo.h"
#define _10_MILLISECONDS (10 * TICKS_IN_MS)
extern engine_configuration_s *engineConfiguration;
/**
* CH_FREQUENCY is the number of system ticks in a second
*/
#define FUEL_PUMP_DELAY (4 * CH_FREQUENCY)
static VirtualTimer everyMsTimer;
static VirtualTimer fuelPumpTimer;
static Logging logger;
static engine_configuration2_s ec2;
engine_configuration2_s * engineConfiguration2 = &ec2;
static void updateStatusLeds(void) {
int is_cranking = isCranking();
setOutputPinValue(LED_RUNNING, getRpm() > 0 && !is_cranking);
setOutputPinValue(LED_CRANKING, is_cranking);
}
static void updateErrorCodes(void) {
/**
* technically we can set error codes right inside the getMethods, but I a bit on a fence about it
*/
setError(isValidIntakeAirTemperature(getIntakeAirTemperature()), OBD_Intake_Air_Temperature_Circuit_Malfunction);
setError(isValidCoolantTemperature(getCoolantTemperature()), OBD_Engine_Coolant_Temperature_Circuit_Malfunction);
}
static void fanRelayControl(void) {
int isCurrentlyOn = getOutputPinValue(FAN_RELAY);
int newValue;
if (isCurrentlyOn) {
// if the fan is already on, we keep it on till the 'fanOff' temperature
newValue = getCoolantTemperature() > engineConfiguration->fanOffTemperature;
} else {
newValue = getCoolantTemperature() > engineConfiguration->fanOnTemperature;
}
if (isCurrentlyOn != newValue) {
scheduleMsg(&logger, "FAN relay: %s", newValue ? "ON" : "OFF");
setOutputPinValue(FAN_RELAY, newValue);
}
}
static void onEveny10Milliseconds(void *arg) {
updateStatusLeds();
updateErrorCodes();
fanRelayControl();
// schedule next invocation
chVTSetAny(&everyMsTimer, _10_MILLISECONDS, &onEveny10Milliseconds, 0);
}
static void initPeriodicEvents(void) {
// schedule first invocation
chVTSetAny(&everyMsTimer, _10_MILLISECONDS, &onEveny10Milliseconds, 0);
}
static void fuelPumpOff(void *arg) {
if (getOutputPinValue(FUEL_PUMP_RELAY))
scheduleMsg(&logger, "fuelPump OFF at %s%d", portname(FUEL_PUMP_PORT ), FUEL_PUMP_PIN);
turnOutputPinOff(FUEL_PUMP_RELAY);
}
static void fuelPumpOn(ShaftEvents signal, int index) {
if (index != 0)
return; // let's not abuse the timer - one time per revolution would be enough
if (!getOutputPinValue(FUEL_PUMP_RELAY))
scheduleMsg(&logger, "fuelPump ON at %s%d", portname(FUEL_PUMP_PORT ), FUEL_PUMP_PIN);
turnOutputPinOn(FUEL_PUMP_RELAY);
/**
* the idea of this implementation is that we turn the pump when the ECU turns on or
* if the shafts are spinning and then we are constantly postponing the time when we
* will turn it off. Only if the shafts stop the turn off would actually happen.
*/
chVTSetAny(&fuelPumpTimer, FUEL_PUMP_DELAY, &fuelPumpOff, 0);
}
static void initFuelPump(void) {
registerShaftPositionListener(&fuelPumpOn, "fuel pump");
fuelPumpOn(SHAFT_PRIMARY_UP, 0);
}
char * getPinNameByAdcChannel(int hwChannel, uint8_t *buffer) {
strcpy(buffer, portname(getAdcChannelPort(hwChannel)));
itoa10(&buffer[2], getAdcChannelPin(hwChannel));
return buffer;
}
static uint8_t pinNameBuffer[16];
static void printAnalogChannelInfoExt(char *name, int hwChannel, float voltage) {
scheduleMsg(&logger, "%s ADC%d %s value=%fv", name, hwChannel, getPinNameByAdcChannel(hwChannel, pinNameBuffer),
voltage);
}
static void printAnalogChannelInfo(char *name, int hwChannel) {
printAnalogChannelInfoExt(name, hwChannel, getVoltageDivided(hwChannel));
}
static void printAnalogInfo(void) {
printAnalogChannelInfo("TPS", engineConfiguration->tpsAdcChannel);
printAnalogChannelInfo("CLT", engineConfiguration->cltAdcChannel);
printAnalogChannelInfo("IAT", engineConfiguration->iatAdcChannel);
printAnalogChannelInfo("MAF", engineConfiguration->mafAdcChannel);
printAnalogChannelInfo("AFR", engineConfiguration->afrSensor.afrAdcChannel);
printAnalogChannelInfoExt("Vbatt", engineConfiguration->vBattAdcChannel, getVBatt());
}
void initEngineContoller(void) {
initLogging(&logger, "Engine Controller");
initSensors();
initPwmGenerator();
initAnalogChart();
initAlgo();
#ifdef EFI_WAVE_ANALYZER
initWaveAnalyzer();
#endif
/**
* there is an implicit dependency on the fact that 'tachometer' listener is the 1st listener - this case
* other listeners can access current RPM value
*/
initRpmCalculator();
#if EFI_TUNER_STUDIO
startTunerStudioConnectivity();
#endif
// multiple issues with this initMapAdjusterThread();
initPeriodicEvents();
#if EFI_SIGNAL_EXECUTOR_SINGLE_TIMER
initOutputScheduler();
#endif
initInjectorCentral();
initIgnitionCentral();
initMalfunctionCentral();
#if EFI_ELECTRONIC_THROTTLE_BODY
initElectronicThrottle();
#endif /* EFI_ELECTRONIC_THROTTLE_BODY */
initMalfunctionIndicator();
initMapAveraging();
/**
* This method initialized the main listener which actually runs injectors & ignition
*/
initMainEventListener();
#if EFI_IDLE_CONTROL
startIdleThread();
#endif
initFuelPump();
addConsoleAction("analoginfo", printAnalogInfo);
}

View File

@ -13,12 +13,24 @@
#include <stdint.h>
#include "efifeatures.h"
/**
* integer time in milliseconds
* 32 bit 4B / 1000 = 4M seconds = 1111.11 hours = 46 days.
* Please restart your ECU every 46 days? :)
*/
typedef uint32_t efitimems_t;
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
#define US_PER_SECOND 1000000
#define MS2US(MS_TIME) ((MS_TIME) * 1000)
#define US_TO_TI_TEMP 10
// todo: implement a function to work with times considering counter overflow
#define overflowDiff(now, time) ((now) - (time))
@ -30,6 +42,18 @@ extern "C"
*/
uint64_t getTimeNowUs(void);
uint64_t getHalTimer(void);
/**
* @brief Returns the number of milliseconds since the board initialization.
*/
efitimems_t currentTimeMillis(void);
/**
* @brief Current system time in seconds.
*/
int getTimeNowSeconds(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@ -73,19 +73,10 @@ float getOneDegreeTimeMs(int rpm) {
}
/**
* @return time needed to rotate crankshaft by one degree, in systicks
* @deprecated use getOneDegreeTimeMs
* @return number of milliseconds in one crankshaft revolution
*/
float getOneDegreeTime(int rpm) {
return getOneDegreeTimeMs(rpm) * TICKS_IN_MS;
}
/**
* @return number of system it needed for one crankshaft revolution, in systicks
* @todo migrate getOneDegreeTimeMs
*/
float getCrankshaftRevolutionTime(int rpm) {
return 360 * getOneDegreeTime(rpm);
float getCrankshaftRevolutionTimeMs(int rpm) {
return 360 * getOneDegreeTimeMs(rpm);
}
/**

View File

@ -24,8 +24,7 @@ float getDefaultFuel(int rpm, float map);
//float getTCharge(int rpm, int tps, float coolantTemp, float airTemp);
float getOneDegreeTimeMs(int rpm);
float getOneDegreeTime(int rpm);
float getCrankshaftRevolutionTime(int rpm);
float getCrankshaftRevolutionTimeMs(int rpm);
int isCrankingRT(engine_configuration_s *engineConfiguration, int rpm);
#define isCrankingR(rpm) isCrankingRT(engineConfiguration, rpm)

View File

@ -1,359 +0,0 @@
/**
* @file settings.c
* @brief This file is about configuring engine via the human-readable protocol
*
* @date Dec 30, 2012
* @author Andrey Belomutskiy, (c) 2012-2014
*/
#include "main.h"
#include "settings.h"
#include "eficonsole.h"
#include "engine_configuration.h"
#include "flash_main.h"
#include "engine_controller.h"
#include "rusefi.h"
#include "thermistors.h"
#include "adc_inputs.h"
#include "interpolation.h"
#if EFI_PROD_CODE
#include "pin_repository.h"
#endif /* EFI_PROD_CODE */
static Logging logger;
static char LOGGING_BUFFER[1000];
extern engine_configuration_s *engineConfiguration;
extern engine_configuration2_s *engineConfiguration2;
static void doPrintConfiguration(void) {
printConfiguration(engineConfiguration, engineConfiguration2);
}
static void printIntArray(int array[], int size) {
for (int j = 0; j < size; j++)
print("%d ", array[j]);
print("\r\n");
}
void printFloatArray(char *prefix, float array[], int size) {
appendMsgPrefix(&logger);
appendPrintf(&logger, prefix);
for (int j = 0; j < size; j++)
appendPrintf(&logger, "%f ", array[j]);
appendMsgPostfix(&logger);
scheduleLogging(&logger);
}
char* getConfigurationName(engine_configuration_s *engineConfiguration) {
switch (engineConfiguration->engineType) {
#if EFI_SUPPORT_DODGE_NEON
case DODGE_NEON_1995:
return "Dodge Neon";
#endif /* EFI_SUPPORT_DODGE_NEON */
#if EFI_SUPPORT_FORD_ASPIRE
case FORD_ASPIRE_1996:
return "Ford Aspire";
#endif /* EFI_SUPPORT_FORD_ASPIRE */
#if EFI_SUPPORT_FORD_FIESTA
case FORD_FIESTA:
return "Ford Fiesta";
#endif /* EFI_SUPPORT_FORD_FIESTA */
#if EFI_SUPPORT_NISSAN_PRIMERA
case NISSAN_PRIMERA:
return "Nissan Primera";
#endif /* EFI_SUPPORT_NISSAN_PRIMERA */
case HONDA_ACCORD:
return "Honda Accord";
case FORD_INLINE_6_1995:
return "Ford 1995 inline 6";
case GY6_139QMB:
return "Gy6 139qmb";
case MAZDA_MIATA_NB:
return "Mazda Miata NB";
case MAZDA_323:
return "Mazda 323";
default:
return NULL;
}
}
/**
* @brief Prints current engine configuration to human-readable console.
*/
void printConfiguration(engine_configuration_s *engineConfiguration, engine_configuration2_s *engineConfiguration2) {
scheduleMsg(&logger, getConfigurationName(engineConfiguration));
scheduleMsg(&logger, "configurationVersion=%d", getGlobalConfigurationVersion());
for (int k = 0; k < FUEL_LOAD_COUNT; k++) {
// print("line %d (%f): ", k, engineConfiguration->fuelKeyBins[k]);
// for (int r = 0; r < FUEL_RPM_COUNT; r++) {
// print("%f ", engineConfiguration->fuelTable[k][r]);
// }
// print("\r\n");
}
printFloatArray("RPM bin: ", engineConfiguration->fuelRpmBins, FUEL_RPM_COUNT);
printFloatArray("Y bin: ", engineConfiguration->fuelLoadBins, FUEL_LOAD_COUNT);
printFloatArray("CLT: ", engineConfiguration->cltFuelCorr, CLT_CURVE_SIZE);
printFloatArray("CLT bins: ", engineConfiguration->cltFuelCorrBins, CLT_CURVE_SIZE);
printFloatArray("IAT: ", engineConfiguration->iatFuelCorr, IAT_CURVE_SIZE);
printFloatArray("IAT bins: ", engineConfiguration->iatFuelCorrBins, IAT_CURVE_SIZE);
printFloatArray("vBatt: ", engineConfiguration->battInjectorLagCorr, VBAT_INJECTOR_CURVE_SIZE);
printFloatArray("vBatt bins: ", engineConfiguration->battInjectorLagCorrBins, VBAT_INJECTOR_CURVE_SIZE);
// appendMsgPrefix(&logger);
scheduleMsg(&logger, "rpmHardLimit: %d", engineConfiguration->rpmHardLimit);
scheduleMsg(&logger, "rpmMultiplier=%f", engineConfiguration->rpmMultiplier);
scheduleMsg(&logger, "tpsMin: %d", engineConfiguration->tpsMin);
scheduleMsg(&logger, "tpsMax: %d", engineConfiguration->tpsMax);
scheduleMsg(&logger, "timingMode: %d", engineConfiguration->timingMode);
scheduleMsg(&logger, "fixedModeTiming: %d", (int) engineConfiguration->fixedModeTiming);
scheduleMsg(&logger, "crankingChargeAngle=%f", engineConfiguration->crankingChargeAngle);
scheduleMsg(&logger, "globalTriggerAngleOffset=%f", engineConfiguration->globalTriggerAngleOffset);
scheduleMsg(&logger, "analogChartMode: %d", engineConfiguration->analogChartMode);
scheduleMsg(&logger, "crankingRpm: %d", engineConfiguration->crankingSettings.crankingRpm);
scheduleMsg(&logger, "injectionPinMode: %d", engineConfiguration->injectionPinMode);
scheduleMsg(&logger, "ignitionPinMode: %d", engineConfiguration->ignitionPinMode);
scheduleMsg(&logger, "idlePinMode: %d", engineConfiguration->idlePinMode);
scheduleMsg(&logger, "fuelPumpPinMode: %d", engineConfiguration->fuelPumpPinMode);
scheduleMsg(&logger, "malfunctionIndicatorPinMode: %d", engineConfiguration->malfunctionIndicatorPinMode);
scheduleMsg(&logger, "analogInputDividerCoefficient: %f", engineConfiguration->analogInputDividerCoefficient);
#if EFI_PROD_CODE
// todo: calculate coils count based on ignition mode
for (int i = 0; i < 4; i++) {
brain_pin_e brainPin = engineConfiguration->ignitionPins[i];
GPIO_TypeDef *hwPort = getHwPort(brainPin);
int hwPin = getHwPin(brainPin);
scheduleMsg(&logger, "ignition %d @ %s%d", i, portname(hwPort), hwPin);
}
#endif /* EFI_PROD_CODE */
// appendPrintf(&logger, DELIMETER);
// scheduleLogging(&logger);
}
static void setFixedModeTiming(int value) {
engineConfiguration->fixedModeTiming = value;
doPrintConfiguration();
}
static void setTimingMode(int value) {
engineConfiguration->timingMode = (timing_mode_e) value;
doPrintConfiguration();
}
static void setEngineType(int value) {
engineConfiguration->engineType = (engine_type_e) value;
resetConfigurationExt((engine_type_e) value, engineConfiguration, engineConfiguration2);
#if EFI_PROD_CODE
writeToFlash();
scheduleReset();
#endif /* EFI_PROD_CODE */
incrementGlobalConfigurationVersion();
doPrintConfiguration();
}
static void setInjectionPinMode(int value) {
engineConfiguration->injectionPinMode = (pin_output_mode_e) value;
doPrintConfiguration();
}
static void setIgnitionPinMode(int value) {
engineConfiguration->ignitionPinMode = (pin_output_mode_e) value;
doPrintConfiguration();
}
static void setIdlePinMode(int value) {
engineConfiguration->idlePinMode = (pin_output_mode_e) value;
doPrintConfiguration();
}
static void setIgnitionOffset(int value) {
engineConfiguration->ignitionOffset = value;
doPrintConfiguration();
}
static void setFuelPumpPinMode(int value) {
engineConfiguration->fuelPumpPinMode = (pin_output_mode_e) value;
doPrintConfiguration();
}
static void setMalfunctionIndicatorPinMode(int value) {
engineConfiguration->malfunctionIndicatorPinMode = (pin_output_mode_e) value;
doPrintConfiguration();
}
static void setAnalogChartMode(int value) {
engineConfiguration->analogChartMode = value;
doPrintConfiguration();
}
static void setRpmMultiplier(int value) {
engineConfiguration->rpmMultiplier = value;
doPrintConfiguration();
}
static uint8_t pinNameBuffer[16];
static void printThermistor(char *msg, Thermistor *thermistor) {
int adcChannel = thermistor->channel;
float voltage = getVoltageDivided(adcChannel);
float r = getResistance(thermistor);
float t = getTemperatureC(thermistor);
scheduleMsg(&logger, "%s v=%f C=%f R=%f on channel %d", msg, voltage, t, r, adcChannel);
scheduleMsg(&logger, "bias=%f A=%f B=%f C=%f", thermistor->config->bias_resistor, thermistor->config->s_h_a,
thermistor->config->s_h_b, thermistor->config->s_h_c);
#if EFI_PROD_CODE
scheduleMsg(&logger, "@%s", getPinNameByAdcChannel(adcChannel, pinNameBuffer));
#endif
}
static void printTemperatureInfo(void) {
printThermistor("CLT", &engineConfiguration2->clt);
printThermistor("IAT", &engineConfiguration2->iat);
float rClt = getResistance(&engineConfiguration2->clt);
float rIat = getResistance(&engineConfiguration2->iat);
#if EFI_PROD_CODE
int cltChannel = engineConfiguration2->clt.channel;
scheduleMsg(&logger, "CLT R=%f on channel %d@%s", rClt, cltChannel,
getPinNameByAdcChannel(cltChannel, pinNameBuffer));
int iatChannel = engineConfiguration2->iat.channel;
scheduleMsg(&logger, "IAT R=%f on channel %d@%s", rIat, iatChannel,
getPinNameByAdcChannel(iatChannel, pinNameBuffer));
scheduleMsg(&logger, "cranking fuel %fms @ %fC", engineConfiguration->crankingSettings.fuelAtMinTempMs,
engineConfiguration->crankingSettings.coolantTempMinC);
scheduleMsg(&logger, "cranking fuel %fms @ %fC", engineConfiguration->crankingSettings.fuelAtMaxTempMs,
engineConfiguration->crankingSettings.coolantTempMaxC);
#endif
}
/**
* For example
* set_cranking_fuel_min 15 0
* would be 15ms @ 0C
*/
static void setCrankingFuleMin(int timeMs, int tempC) {
engineConfiguration->crankingSettings.coolantTempMinC = tempC;
engineConfiguration->crankingSettings.fuelAtMinTempMs = timeMs;
printTemperatureInfo();
}
static void setCrankingFuleMax(int timeMs, int tempC) {
engineConfiguration->crankingSettings.coolantTempMaxC = tempC;
engineConfiguration->crankingSettings.fuelAtMaxTempMs = timeMs;
printTemperatureInfo();
}
static void setGlobalTriggerAngleOffset(int value) {
engineConfiguration->globalTriggerAngleOffset = value;
doPrintConfiguration();
}
static void setGlobalFuelCorrection(float value) {
if (value < 0.01 || value > 50)
return;
scheduleMsg(&logger, "setting fuel mult=%f", value);
engineConfiguration->globalFuelCorrection = value;
}
static void setWholeTimingMap(float value) {
scheduleMsg(&logger, "Setting whole timing map to %f", value);
for (int l = 0; l < IGN_LOAD_COUNT; l++) {
for (int r = 0; r < IGN_RPM_COUNT; r++) {
engineConfiguration->ignitionTable[l][r] = value;
}
}
}
static void setWholeFuelMap(float value) {
scheduleMsg(&logger, "Setting whole fuel map to %f", value);
for (int l = 0; l < FUEL_LOAD_COUNT; l++) {
for (int r = 0; r < FUEL_RPM_COUNT; r++) {
engineConfiguration->fuelTable[l][r] = value;
}
}
}
static void setTimingMap(char * rpmStr, char *loadStr, char *valueStr) {
float rpm = atoff(rpmStr);
float engineLoad = atoff(loadStr);
float value = atoi(valueStr);
int rpmIndex = findIndex(engineConfiguration->ignitionRpmBins, IGN_RPM_COUNT, rpm);
rpmIndex = rpmIndex < 0 ? 0 : rpmIndex;
int loadIndex = findIndex(engineConfiguration->ignitionLoadBins, IGN_LOAD_COUNT, engineLoad);
loadIndex = loadIndex < 0 ? 0 : loadIndex;
engineConfiguration->ignitionTable[loadIndex][rpmIndex] = value;
scheduleMsg(&logger, "Setting timing map entry %d:%d to %f", rpmIndex, loadIndex, value);
}
static void setFuelMap(char * rpmStr, char *loadStr, char *valueStr) {
float rpm = atoff(rpmStr);
float engineLoad = atoff(loadStr);
float value = atoi(valueStr);
int rpmIndex = findIndex(engineConfiguration->fuelRpmBins, FUEL_RPM_COUNT, rpm);
rpmIndex = rpmIndex < 0 ? 0 : rpmIndex;
int loadIndex = findIndex(engineConfiguration->fuelLoadBins, FUEL_LOAD_COUNT, engineLoad);
loadIndex = loadIndex < 0 ? 0 : loadIndex;
engineConfiguration->fuelTable[loadIndex][rpmIndex] = value;
scheduleMsg(&logger, "Setting fuel map entry %d:%d to %f", rpmIndex, loadIndex, value);
}
void initSettings(void) {
initLoggingExt(&logger, "settings control", LOGGING_BUFFER, sizeof(LOGGING_BUFFER));
addConsoleAction("showconfig", doPrintConfiguration);
addConsoleAction("tempinfo", printTemperatureInfo);
addConsoleActionI("set_ignition_offset", setIgnitionOffset);
addConsoleActionI("set_global_trigger_offset_angle", setGlobalTriggerAngleOffset);
addConsoleActionI("set_analog_chart_mode", setAnalogChartMode);
addConsoleActionI("set_fixed_mode_timing", setFixedModeTiming);
addConsoleActionI("set_timing_mode", setTimingMode);
addConsoleActionI("set_engine_type", setEngineType);
addConsoleActionI("set_injection_pin_mode", setInjectionPinMode);
addConsoleActionI("set_ignition_pin_mode", setIgnitionPinMode);
addConsoleActionI("set_idle_pin_mode", setIdlePinMode);
addConsoleActionI("set_fuel_pump_pin_mode", setFuelPumpPinMode);
addConsoleActionI("set_malfunction_indicator_pin_mode", setMalfunctionIndicatorPinMode);
addConsoleActionI("set_rpm_multiplier", setRpmMultiplier);
// todo: start saving values into flash right away?
addConsoleActionF("set_global_fuel_correction", setGlobalFuelCorrection);
addConsoleActionII("set_cranking_fuel_min", setCrankingFuleMin);
addConsoleActionII("set_cranking_fuel_max", setCrankingFuleMax);
addConsoleActionF("set_whole_fuel_map", setWholeFuelMap);
addConsoleActionSSS("set_fuel_map", setFuelMap);
addConsoleActionF("set_whole_timing_map", setWholeTimingMap);
addConsoleActionSSS("set_timing_map", setTimingMap);
}

View File

@ -1,13 +1,20 @@
/*
* SingleTimerExecutor.cpp
/**
* @file SingleTimerExecutor.cpp
*
* Created on: Apr 18, 2014
* Author: Andrey
* This class combines the powers of a 1MHz hardware timer from microsecond_timer.c
* and pending events queue event_queue.cpp
*
* todo: add thread safety
*
* @date: Apr 18, 2014
* @author Andrey Belomutskiy, (c) 2012-2014
*/
#include "SingleTimerExecutor.h"
#include "efitime.h"
#include "signal_temp.h"
#if EFI_PROD_CODE
#include "microsecond_timer.h"
#endif
#if EFI_SIGNAL_EXECUTOR_ONE_TIMER || defined(__DOXYGEN__)
@ -16,33 +23,62 @@ static Executor instance;
extern schfunc_t globalTimerCallback;
static void executorCallback(void *arg) {
instance.eq.execute(getTimeNowUs());
instance.execute(getTimeNowUs());
}
void Executor::setTimer(uint64_t nowUs) {
uint64_t nextEventTime = queue.getNextEventTime(nowUs);
setHardwareUsTimer(nextEventTime - nowUs);
}
Executor::Executor() {
}
void Executor::schedule(scheduling_s *scheduling, uint64_t nowUs, int delayUs, schfunc_t callback, void *param) {
eq.schedule(scheduling, nowUs, delayUs, callback, param);
uint64_t nextEventTime = eq.getNextEventTime();
setTimer(nextEventTime - getTimeNowUs());
queue.insertTask(scheduling, nowUs, delayUs, callback, param);
setTimer(nowUs);
}
void scheduleTask(scheduling_s *scheduling, float delayMs, schfunc_t callback, void *param) {
void Executor::execute(uint64_t now) {
/**
* Let's execute actions we should execute at this point
*/
queue.executeAll(now);
/**
* Let's set up the timer for the next execution
*/
setTimer(now);
}
/**
* @brief Schedule an event
*
* Invokes event callback after the specified amount of time.
*
* @param [in, out] scheduling Data structure to keep this event in the collection.
* @param [in] delayUs the number of microseconds before the output signal immediate output if delay is zero.
* @param [in] dwell the number of ticks of output duration.
*/
void scheduleTask(scheduling_s *scheduling, int delayUs, schfunc_t callback, void *param) {
if (delayUs == 0) {
callback(param);
return;
}
// todo: eliminate this /100. Times still come as systick times here
instance.schedule(scheduling, getTimeNowUs(), delayMs * 1000000 / 100000, callback, param);
instance.schedule(scheduling, getTimeNowUs(), delayUs, callback, param);
}
void initOutputSignal(OutputSignal *signal, io_pin_e ioPin) {
signal->io_pin = ioPin;
signal->name = getPinName(ioPin);
// signal->duration = 0;
initOutputSignalBase(signal);
}
void initSignalExecutorImpl(void) {
globalTimerCallback = executorCallback;
TIM_Init();
#if EFI_PROD_CODE
initMicrosecondTimer();
#endif /* EFI_PROD_CODE */
}
#endif

View File

@ -1,8 +1,8 @@
/*
* SingleTimerExecutor.h
/**
* @file SingleTimerExecutor.h
*
* Created on: Apr 18, 2014
* Author: Andrey
* @date: Apr 18, 2014
* @author Andrey Belomutskiy, (c) 2012-2014
*/
#ifndef SINGLETIMEREXECUTOR_H_
@ -15,7 +15,10 @@ class Executor {
public:
Executor();
void schedule(scheduling_s *scheduling, uint64_t nowUs, int delayUs, schfunc_t callback, void *param);
EventQueue eq;
void execute(uint64_t now);
private:
EventQueue queue;
void setTimer(uint64_t now);
};
#endif /* SINGLETIMEREXECUTOR_H_ */

View File

@ -8,46 +8,46 @@
#include "pwm_generator_logic.h"
#include "engine_math.h"
static time_t getNextSwitchTime(PwmConfig *state) {
static uint64_t getNextSwitchTimeUs(PwmConfig *state) {
chDbgAssert(state->safe.phaseIndex < PWM_PHASE_MAX_COUNT, "phaseIndex range", NULL);
int iteration = state->safe.iteration;
float switchTime = state->multiWave.switchTimes[state->safe.phaseIndex];
float period = state->safe.period;
float periodMs = state->safe.periodMs;
#if DEBUG_PWM
scheduleMsg(&logger, "iteration=%d switchTime=%f period=%f", iteration, switchTime, period);
#endif
systime_t timeToSwitch = (systime_t) ((iteration + switchTime) * period);
uint64_t timeToSwitchUs = (iteration + switchTime) * periodMs * 1000;
#if DEBUG_PWM
scheduleMsg(&logger, "start=%d timeToSwitch=%d", state->safe.start, timeToSwitch);
#endif
return state->safe.start + timeToSwitch;
return state->safe.startUs + timeToSwitchUs;
}
static time_t togglePwmState(PwmConfig *state) {
static uint64_t togglePwmState(PwmConfig *state) {
#if DEBUG_PWM
scheduleMsg(&logger, "togglePwmState phaseIndex=%d iteration=%d", state->safe.phaseIndex, state->safe.iteration);
scheduleMsg(&logger, "state->period=%f state->safe.period=%f", state->period, state->safe.period);
#endif
if (state->safe.phaseIndex == 0) {
if (cisnan(state->period)) {
if (cisnan(state->periodMs)) {
/**
* zero period means PWM is paused
*/
return TICKS_IN_MS;
return 1;
}
if (state->cycleCallback != NULL)
state->cycleCallback(state);
chDbgAssert(state->period != 0, "period not initialized", NULL);
if (state->safe.period != state->period) {
chDbgAssert(state->periodMs != 0, "period not initialized", NULL);
if (state->safe.periodMs != state->periodMs) {
/**
* period length has changed - we need to reset internal state
*/
state->safe.start = chTimeNow();
state->safe.startUs = getTimeNowUs();
state->safe.iteration = 0;
state->safe.period = state->period;
state->safe.periodMs = state->periodMs;
#if DEBUG_PWM
scheduleMsg(&logger, "state reset start=%d iteration=%d", state->safe.start, state->safe.iteration);
#endif
@ -57,14 +57,14 @@ static time_t togglePwmState(PwmConfig *state) {
state->stateChangeCallback(state,
state->safe.phaseIndex == 0 ? state->multiWave.phaseCount - 1 : state->safe.phaseIndex - 1);
time_t nextSwitchTime = getNextSwitchTime(state);
uint64_t nextSwitchTimeUs = getNextSwitchTimeUs(state);
#if DEBUG_PWM
scheduleMsg(&logger, "%s: nextSwitchTime %d", state->name, nextSwitchTime);
#endif
time_t timeToSwitch = nextSwitchTime - chTimeNow();
uint64_t timeToSwitch = nextSwitchTimeUs - getTimeNowUs();
if (timeToSwitch < 1) {
//todo: introduce error and test this error handling warning(OBD_PCM_Processor_Fault, "PWM: negative switch time");
timeToSwitch = 1;
timeToSwitch = 10;
}
state->safe.phaseIndex++;
@ -76,34 +76,11 @@ static time_t togglePwmState(PwmConfig *state) {
}
static void timerCallback(PwmConfig *state) {
// todo: use this implementation! but something is wrong with it :(
time_t timeToSleep = togglePwmState(state);
scheduleTask(&state->scheduling, timeToSleep, (schfunc_t) timerCallback, state);
time_t timeToSleepUs = togglePwmState(state);
// parameter here is still in systicks
scheduleTask(&state->scheduling, timeToSleepUs, (schfunc_t) timerCallback, state);
}
//static msg_t deThread(PwmConfig *state) {
// chRegSetThreadName("Wave");
//
//#if DEBUG_PWM
// scheduleMsg(&logger, "Thread started for %s", state->name);
//#endif
//
//// setPadValue(state, state->idleState); todo: currently pin is always zero at first iteration.
//// we can live with that for now
// // todo: figure out overflow
//
// while (TRUE) {
// time_t timeToSwitch = togglePwmState(state);
//#if DEBUG_PWM
// scheduleMsg(&logger, "%s: sleep %d", state->name, timeToSwitch);
//#endif
// chThdSleep(timeToSwitch);
// }
//#if defined __GNUC__
// return -1;
//#endif
//}
/**
* Incoming parameters are potentially just values on current stack, so we have to copy
* into our own permanent storage, right?
@ -125,7 +102,7 @@ void copyPwmParameters(PwmConfig *state, int phaseCount, float *switchTimes, int
void weComplexInit(char *msg, PwmConfig *state, int phaseCount, float *switchTimes, int waveCount, int **pinStates,
pwm_cycle_callback *cycleCallback, pwm_gen_callback *stateChangeCallback) {
chDbgCheck(state->period != 0, "period is not initialized");
chDbgCheck(state->periodMs != 0, "period is not initialized");
chDbgCheck(phaseCount > 1, "count is too small");
if (phaseCount > PWM_PHASE_MAX_COUNT) {
firmwareError("too many phases in PWM");
@ -146,11 +123,9 @@ void weComplexInit(char *msg, PwmConfig *state, int phaseCount, float *switchTim
state->stateChangeCallback = stateChangeCallback;
state->safe.phaseIndex = 0;
state->safe.period = -1;
state->safe.periodMs = -1;
state->safe.iteration = -1;
state->name = msg;
// chThdCreateStatic(state->deThreadStack, sizeof(state->deThreadStack), NORMALPRIO, (tfunc_t) deThread, state);
timerCallback(state);
}

View File

@ -18,7 +18,7 @@ typedef struct {
* a copy so that all phases are executed on the same period, even if another thread
* would be adjusting PWM parameters
*/
float period;
float periodMs;
/**
* Iteration counter
*/
@ -26,7 +26,7 @@ typedef struct {
/**
* Start time of current iteration
*/
systime_t start;
uint64_t startUs;
int phaseIndex;
} pwm_config_safe_state_s;
@ -46,9 +46,8 @@ struct PwmConfig_struct {
* float value of PWM period
* PWM generation is not happening while this value is zero
*/
float period;
float periodMs;
WORKING_AREA(deThreadStack, UTILITY_THREAD_STACK_SIZE);
scheduling_s scheduling;
pwm_config_safe_state_s safe;

View File

@ -30,9 +30,9 @@
#if EFI_SIGNAL_EXECUTOR_SLEEP || defined(__DOXYGEN__)
void scheduleTask(scheduling_s *scheduling, float delayF, schfunc_t callback, void *param) {
int delay = delayF;
if (delay == 0) {
void scheduleTask(scheduling_s *scheduling, int delayUs, schfunc_t callback, void *param) {
int delaySt = delayUs * CH_FREQUENCY / 1000000;
if (delaySt == 0) {
/**
* in case of zero delay, we should invoke the callback
*/
@ -45,7 +45,7 @@ void scheduleTask(scheduling_s *scheduling, float delayF, schfunc_t callback, vo
if (isArmed)
chVTResetI(&scheduling->timer);
chVTSetI(&scheduling->timer, delay, (vtfunc_t)callback, param);
chVTSetI(&scheduling->timer, delaySt, (vtfunc_t)callback, param);
unlockAnyContext();
}

View File

@ -1,74 +0,0 @@
/**
* @file signal_temp.c
*
* Work in progress. https://sourceforge.net/p/rusefi/tickets/24/
*
* Here we have a 1MHz timer dedicated to event scheduling. We are using one of the 32-bit timers here,
* so this timer can schedule events up to 4B/100M = 4000 seconds from now.
*
* @date Apr 14, 2014
* @author Andrey Belomutskiy, (c) 2012-2013
*/
#include "main.h"
#include "signal_executor.h"
#include "signal_temp.h"
// https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https%3a%2f%2fmy.st.com%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fcortex_mx_stm32%2fInterrupt%20on%20CEN%20bit%20setting%20in%20TIM7&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&currentviews=474
#if EFI_PROD_CODE
int globalCounter = 0;
static TIM_TypeDef *TIM = TIM5;
schfunc_t globalTimerCallback;
void setTimer(int timeUs) {
TIM->ARR = timeUs - 1;
TIM->EGR |= TIM_EGR_UG; // generate an update event to reload timer's counter value
TIM->CR1 |= TIM_CR1_CEN; // restart timer
}
static void callback(void) {
GPIOD ->ODR ^= (1 << 13); // Toggle D13
globalCounter++;
if (globalTimerCallback == NULL) {
firmwareError("NULL globalTimerCallback");
return;
}
globalTimerCallback(NULL);
// if (globalCounter < 6) {
// setTimer(100000);
// }
}
// if you decide to move this to .cpp do not forget to make that a C method
CH_IRQ_HANDLER(STM32_TIM5_HANDLER) {
CH_IRQ_PROLOGUE();
if (((TIM->SR & 0x0001) != 0) && ((TIM->DIER & 0x0001) != 0)) {
callback();
}
TIM->SR = (int) ~STM32_TIM_SR_UIF; // Interrupt has been handled
CH_IRQ_EPILOGUE();
}
void TIM_Init(void) {
// if (1==1)
// return; // something is not right with this code :(
RCC ->APB1ENR |= RCC_APB1ENR_TIM5EN; // Enable TIM5 clock
// NVIC_EnableIRQ(TIM5_IRQn); // Enable TIM5 IRQ
nvicEnableVector(TIM5_IRQn, CORTEX_PRIORITY_MASK(12));
TIM->DIER |= TIM_DIER_UIE; // Enable interrupt on update event
TIM->CR1 |= TIM_CR1_OPM; // one pulse mode: count down ARR and stop
TIM->CR1 &= ~TIM_CR1_ARPE; /* ARR register is NOT buffered, allows to update timer's period on-fly. */
TIM->PSC = 84 - 1; // 168MHz / 2 / 84 = 1MHz, each tick is a microsecond
// setTimer(100000);
}
#endif /* EFI_PROD_CODE */

View File

@ -1,23 +0,0 @@
/**
* @file signal_temp.h
*
* @date Apr 14, 2014
* @author Andrey Belomutskiy, (c) 2012-2013
*/
#ifndef SIGNAL_TEMP_H_
#define SIGNAL_TEMP_H_
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
void TIM_Init(void);
void setTimer(int timeUs);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SIGNAL_TEMP_H_ */

View File

@ -3,7 +3,6 @@ SYSTEMSRC = \
$(PROJECT_DIR)/controllers/system/pwm_generator_logic.c \
$(PROJECT_DIR)/controllers/system/signal_executor_sleep.c \
$(PROJECT_DIR)/controllers/system/signal_executor_single_timer.c \
$(PROJECT_DIR)/controllers/system/signal_temp.c \
$(PROJECT_DIR)/controllers/system/signal_executor_hw_timer.c
SYSTEMSRC_CPP = $(PROJECT_DIR)/controllers/system/trigger_emulator_algo.cpp \

View File

@ -24,22 +24,22 @@ static LocalVersionHolder localVersion;
void setTriggerEmulatorRPM(int rpm) {
if (rpm == 0) {
configuration.period = NAN;
configuration.periodMs = NAN;
} else {
float gRpm = rpm * engineConfiguration->rpmMultiplier / 60.0; // per minute converted to per second
configuration.period = frequency2period(gRpm);
configuration.periodMs = frequency2period(gRpm);
}
scheduleMsg(&logger, "Emulating position sensor(s). RPM=%d", rpm);
}
static void updateTriggerShapeIfNeeded(PwmConfig *state) {
if(localVersion.isOld()) {
scheduleMsg(&logger, "Stimulator: updating trigger shape: %d/%d %d", localVersion.getVersion(), getGlobalConfigurationVersion(), chTimeNow());
scheduleMsg(&logger, "Stimulator: updating trigger shape: %d/%d %d", localVersion.getVersion(), getGlobalConfigurationVersion(), currentTimeMillis());
trigger_shape_s *s = &engineConfiguration2->triggerShape;
int *pinStates[2] = {s->wave.waves[0].pinStates, s->wave.waves[1].pinStates};
copyPwmParameters(state, s->size, s->wave.switchTimes, 2, pinStates);
state->safe.period = -1; // this would cause loop re-initialization
state->safe.periodMs = -1; // this would cause loop re-initialization
}
}

View File

@ -87,7 +87,7 @@ static void handleFuelInjectionEvent(ActuatorEvent *event, int rpm) {
// if (isCranking())
// scheduleMsg(&logger, "crankingFuel=%f for CLT=%fC", fuelMs, getCoolantTemperature());
scheduleOutput(event->actuator, delay, fuelMs, chTimeNow());
scheduleOutput(event->actuator, delay, fuelMs);
}
static void handleFuel(int eventIndex) {
@ -141,7 +141,7 @@ static void handleSparkEvent(ActuatorEvent *event, int rpm) {
//return;
}
scheduleOutput(event->actuator, sparkDelay, dwellMs, chTimeNow());
scheduleOutput(event->actuator, sparkDelay, dwellMs);
}
static void handleSpark(int eventIndex) {
@ -200,6 +200,11 @@ static void onShaftSignal(ShaftEvents ckpSignalType, int eventIndex) {
initializeIgnitionActions(advance - dwellAngle, engineConfiguration, engineConfiguration2);
}
if(rpm==0) {
// this happens while we just start cranking
// todo: check for 'trigger->is_synchnonized?'
return;
}
handleFuel(eventIndex);
handleSpark(eventIndex);
@ -225,7 +230,7 @@ void initMainEventListener() {
addConsoleAction("maininfo", showMainInfo);
initLogging(&logger, "main event handler");
printMsg(&logger, "initMainLoop: %d", chTimeNow());
printMsg(&logger, "initMainLoop: %d", currentTimeMillis());
initHistogram(&mainLoopHisto, "main callback");
if (!isInjectionEnabled())

View File

@ -38,12 +38,12 @@ static Logging logger;
* @return true if there was a full shaft revolution within the last second
*/
int isRunning() {
time_t now = chTimeNow();
return overflowDiff(now, rpmState.lastRpmEventTime) < CH_FREQUENCY;
uint64_t nowUs = getTimeNowUs();
return nowUs - rpmState.lastRpmEventTimeUs < US_PER_SECOND;
}
int getLastRpmEventTime(void) {
return rpmState.lastRpmEventTime;
uint64_t getLastRpmEventTime(void) {
return rpmState.lastRpmEventTimeUs;
}
int isCranking(void) {
@ -63,12 +63,12 @@ int getRpm() {
/**
* @return Current crankshaft angle, 0 to 720 for four-stroke
*/
float getCrankshaftAngle(time_t time) {
int timeSinceZeroAngle = overflowDiff(time, rpmState.lastRpmEventTime);
float getCrankshaftAngle(uint64_t timeUs) {
uint64_t timeSinceZeroAngle = timeUs - rpmState.lastRpmEventTimeUs;
float cRevolutionTime = getCrankshaftRevolutionTime(rpmState.rpm);
float cRevolutionTimeMs = getCrankshaftRevolutionTimeMs(rpmState.rpm);
return 360 * timeSinceZeroAngle / cRevolutionTime;
return 360.0 * timeSinceZeroAngle / cRevolutionTimeMs / 1000;
}
int getRevolutionCounter(void) {
@ -81,9 +81,9 @@ int getRevolutionCounter(void) {
*
* @return TRUE if noise is detected
*/
static int isNoisySignal(rpm_s * rpmState, int now) {
int diff = overflowDiff(now, rpmState->lastRpmEventTime);
return diff == 0;
static int isNoisySignal(rpm_s * rpmState, uint64_t nowUs) {
uint64_t diff = nowUs - rpmState->lastRpmEventTimeUs;
return diff < 1000; // that's 1ms
}
static char shaft_signal_msg_index[15];
@ -114,35 +114,35 @@ static void shaftPositionCallback(ShaftEvents ckpSignalType, int index) {
if (index != 0) {
#if EFI_PROD_CODE || EFI_SIMULATOR
if (engineConfiguration->analogChartMode == AC_TRIGGER)
acAddData(getCrankshaftAngle(chTimeNow()), 1000 * ckpSignalType + index);
acAddData(getCrankshaftAngle(getTimeNowUs()), 1000 * ckpSignalType + index);
#endif
return;
}
rpmState.revolutionCounter++;
time_t now = chTimeNow();
uint64_t nowUs = getTimeNowUs();
int hadRpmRecently = isRunning();
if (hadRpmRecently) {
if (isNoisySignal(&rpmState, now)) {
if (isNoisySignal(&rpmState, nowUs)) {
// unexpected state. Noise?
rpmState.rpm = NOISY_RPM;
} else {
int diff = now - rpmState.lastRpmEventTime;
uint64_t diff = nowUs - rpmState.lastRpmEventTimeUs;
// 60000 because per minute
// * 2 because each revolution of crankshaft consists of two camshaft revolutions
// / 4 because each cylinder sends a signal
// need to measure time from the previous non-skipped event
int rpm = (int)(60000 * TICKS_IN_MS / engineConfiguration->rpmMultiplier / diff);
int rpm = (int)(60 * US_PER_SECOND / engineConfiguration->rpmMultiplier / diff);
rpmState.rpm = rpm > UNREALISTIC_RPM ? NOISY_RPM : rpm;
}
}
rpmState.lastRpmEventTime = now;
rpmState.lastRpmEventTimeUs = nowUs;
#if EFI_PROD_CODE || EFI_SIMULATOR
if (engineConfiguration->analogChartMode == AC_TRIGGER)
acAddData(getCrankshaftAngle(now), index);
acAddData(getCrankshaftAngle(nowUs), index);
#endif
}
@ -169,13 +169,13 @@ void initRpmCalculator(void) {
rpmState.rpm = 0;
// we need this initial to have not_running at first invocation
rpmState.lastRpmEventTime = (time_t)-10 * CH_FREQUENCY;
rpmState.lastRpmEventTimeUs = (uint64_t)-10 * US_PER_SECOND;
registerShaftPositionListener(&shaftPositionCallback, "rpm reporter");
registerShaftPositionListener(&tdcMarkCallback, "chart TDC mark");
}
void scheduleByAngle(scheduling_s *timer, float angle, schfunc_t callback, void *param) {
int delay = (int)(getOneDegreeTime(getRpm()) * angle);
scheduleTask(timer, delay, callback, param);
float delayMs = getOneDegreeTimeMs(getRpm()) * angle;
scheduleTask(timer, MS2US(delayMs), callback, param);
}

View File

@ -15,7 +15,7 @@
typedef struct {
volatile int rpm;
volatile time_t lastRpmEventTime;
volatile uint64_t lastRpmEventTimeUs;
/**
* This counter is incremented with each revolution of one of the shafts. Could be
* crankshaft could be camshaft.
@ -37,10 +37,10 @@ void initRpmCalculator(void);
*/
int getRpm(void);
int isCranking(void);
int getLastRpmEventTime(void);
uint64_t getLastRpmEventTime(void);
int getRevolutionCounter(void);
float getCrankshaftAngle(time_t time);
float getCrankshaftAngle(uint64_t timeUs);
int isRunning(void);
void addWaveChartEvent(char *name, char *msg, char *msg2);

View File

@ -26,7 +26,7 @@ extern engine_configuration_s *engineConfiguration;
extern engine_configuration2_s *engineConfiguration2;
// we need this initial to have not_running at first invocation
static volatile time_t previousShaftEventTime = (time_t) -10 * CH_FREQUENCY;
static volatile uint64_t previousShaftEventTime = (efitimems_t) -10 * US_PER_SECOND;
static IntListenerArray triggerListeneres;
@ -58,16 +58,16 @@ void hwHandleShaftSignal(ShaftEvents signal) {
chDbgCheck(eventIndex >= 0 && eventIndex < HW_EVENT_TYPES, "signal type");
hwEventCounters[eventIndex]++;
time_t now = chTimeNow();
uint64_t nowUs = getTimeNowUs();
if (overflowDiff(now, previousShaftEventTime) > CH_FREQUENCY) {
if (nowUs - previousShaftEventTime > US_PER_SECOND) {
/**
* We are here if there is a time gap between now and previous shaft event - that means the engine is not runnig.
* That means we have lost synchronization since the engine is not running :)
*/
triggerState.shaft_is_synchronized = FALSE;
}
previousShaftEventTime = now;
previousShaftEventTime = nowUs;
// this is not atomic, but it's fine here
shaftEventCounter++;
@ -75,7 +75,7 @@ void hwHandleShaftSignal(ShaftEvents signal) {
* This invocation changes the state of
*/
processTriggerEvent(&triggerState, &engineConfiguration2->triggerShape, &engineConfiguration->triggerConfig, signal,
now);
nowUs);
if (!triggerState.shaft_is_synchronized)
return; // we should not propagate event if we do not know where we are

View File

@ -68,7 +68,7 @@ static inline int noSynchronizationResetNeeded(trigger_state_s const *shaftPosit
* @brief This method changes the state of trigger_state_s data structure according to the trigger event
*/
void processTriggerEvent(trigger_state_s *shaftPositionState, trigger_shape_s const *triggerShape,
trigger_config_s const *triggerConfig, ShaftEvents signal, time_t now) {
trigger_config_s const *triggerConfig, ShaftEvents signal, uint64_t nowUs) {
int isLessImportant = (triggerConfig->useRiseEdge && signal != SHAFT_PRIMARY_UP)
|| (!triggerConfig->useRiseEdge && signal != SHAFT_PRIMARY_DOWN);
@ -81,7 +81,7 @@ void processTriggerEvent(trigger_state_s *shaftPositionState, trigger_shape_s co
return;
}
int currentDuration = overflowDiff(now, shaftPositionState->toothed_previous_time);
int64_t currentDuration = nowUs - shaftPositionState->toothed_previous_time;
chDbgCheck(currentDuration >= 0, "negative duration?");
// todo: skip a number of signal from the beginning
@ -114,7 +114,7 @@ void processTriggerEvent(trigger_state_s *shaftPositionState, trigger_shape_s co
}
shaftPositionState->toothed_previous_duration = currentDuration;
shaftPositionState->toothed_previous_time = now;
shaftPositionState->toothed_previous_time = nowUs;
}

View File

@ -19,7 +19,7 @@ extern "C"
#include "engine_configuration.h"
int isTriggerDecoderError(void);
void processTriggerEvent(trigger_state_s *shaftPositionState, trigger_shape_s const*triggerShape, trigger_config_s const*triggerConfig, ShaftEvents signal, time_t now);
void processTriggerEvent(trigger_state_s *shaftPositionState, trigger_shape_s const*triggerShape, trigger_config_s const*triggerConfig, ShaftEvents signal, uint64_t nowUs);
void initializeSkippedToothTriggerShapeExt(engine_configuration2_s *engineConfiguration2, int totalTeethCount, int skippedCount);
void initializeTriggerShape(engine_configuration_s *engineConfiguration, engine_configuration2_s *engineConfiguration2);
int findTriggerZeroEventIndex(trigger_shape_s const * shape, trigger_config_s const*triggerConfig);

View File

@ -9,6 +9,7 @@
#define TRIGGER_STRUCTURE_H_
#include "rusefi_enums.h"
#include "stdint.h"
#define PWM_PHASE_MAX_COUNT 150
#define PWM_PHASE_MAX_WAVE_PER_PWM 2
@ -28,8 +29,8 @@ typedef struct {
int current_index;
int toothed_previous_duration;
int toothed_previous_time;
uint64_t toothed_previous_duration;
uint64_t toothed_previous_time;
} trigger_state_s;

View File

@ -1,181 +0,0 @@
/*
* rdi_perftest.c
*
* Created on: Nov 30, 2012
* Author: Andrey Belomutskiy, (c) 2012-2013
*/
#include "main.h"
#include "rfi_perftest.h"
#include "fuel_math.h"
//#include "rfirtc.h"
#include "eficonsole.h"
#include "time.h"
#include "engine_math.h"
#include "gpio_helper.h"
//#define TEST_PORT GPIOB
//#define TEST_PIN 6
static OutputPin testOutput;
static void testSystemCalls(int count) {
time_t start, time;
long result = 0;
start = currentTimeMillis();
for (int i = 0; i < count / 2; i++) {
// setPinValue(&testOutput, 0);
// setPinValue(&testOutput, 1);
}
time = currentTimeMillis() - start;
// Finished 100000 iterations of 'setPinValue()' in 120ms
// print("Finished %d iterations of 'setPinValue()' in %dms\r\n", count, time);
start = currentTimeMillis();
for (int i = 0; i < count; i++)
result += chTimeNow();
time = currentTimeMillis() - start;
if (result != 0) {
// Finished 100000 iterations of 'chTimeNow()' in 33ms
print("Finished %d iterations of 'chTimeNow()' in %dms\r\n", count, time);
}
start = currentTimeMillis();
for (int i = 0; i < count; i++) {
chSysLock()
;
result += chTimeNow();
chSysUnlock()
;
}
time = currentTimeMillis() - start;
if (result != 0) {
// Finished 100000 iterations of 'chTimeNow()' with chSysLock in 144ms
print("Finished %d iterations of 'chTimeNow()' with chSysLock in %dms\r\n", count, time);
}
count /= 10;
start = currentTimeMillis();
for (int i = 0; i < count; i++)
result += currentTimeMillis();
time = currentTimeMillis() - start;
if (result != 0)
print("Finished %d iterations of 'currentTimeMillis' in %dms\r\n", count, time);
}
static void testRusefiMethods(int count) {
time_t start, time;
int tempi = 1;
start = currentTimeMillis();
for (int i = 0; i < count; i++)
tempi += getBaseFuel(4020, 2.21111);
time = currentTimeMillis() - start;
if (tempi != 0)
print("Finished %d iterations of getBaseFuel in %dms\r\n", count, time);
start = currentTimeMillis();
// for (int i = 0; i < count; i++)
// tempi += getDefaultFuel(4020, 2.21111);
// time = currentTimeMillis() - start;
// if (tempi == 0)
// print("Finished %d iterations of getDefaultFuel in %dms\r\n", count, time);
}
static void testMath(int count) {
time_t start, time;
int tempi = 1;
start = currentTimeMillis();
for (int i = 0; i < count; i++)
;
time = currentTimeMillis() - start;
print("Finished %d iterations of empty loop in %dms\r\n", count, time);
start = currentTimeMillis();
for (int i = 0; i < count; i++)
tempi += tempi;
time = currentTimeMillis() - start;
if (tempi == 0)
print("Finished %d iterations of int summation in %dms\r\n", count, time);
start = currentTimeMillis();
tempi = 1;
for (int i = 0; i < count; i++)
tempi += (tempi + 100) / 130;
time = currentTimeMillis() - start;
if (tempi != 0)
print("Finished %d iterations of int division in %dms\r\n", count, time);
start = currentTimeMillis();
long templ = 1;
for (int i = 0; i < count; i++)
templ += templ;
time = currentTimeMillis() - start;
if (templ == 0)
print("Finished %d iterations of long summation in %dms\r\n", count, time);
start = currentTimeMillis();
templ = 1;
for (int i = 0; i < count; i++)
templ += (templ + 100) / 130;
time = currentTimeMillis() - start;
if (templ != 0) {
// Finished 100000 iterations of long division in 45ms
print("Finished %d iterations of long division in %dms\r\n", count, time);
}
start = currentTimeMillis();
float tempf = 1;
for (int i = 0; i < count; i++)
tempf += tempf;
time = currentTimeMillis() - start;
if (tempf != 0)
print("Finished %d iterations of float summation in %dms\r\n", count, time);
start = currentTimeMillis();
tempf = 1;
for (int i = 0; i < count; i++)
tempf += (tempf + 100) / 130.0;
time = currentTimeMillis() - start;
if (tempf != 0) {
// Finished 100000 iterations of float division in 65ms
print("Finished %d iterations of float division in %dms\r\n", count, time);
}
start = currentTimeMillis();
double tempd = 1;
for (int i = 0; i < count; i++)
tempd += tempd / 2;
time = currentTimeMillis() - start;
if (tempd != 0)
print("Finished %d iterations of double summation in %dms\r\n", count, time);
start = currentTimeMillis();
tempd = 1;
for (int i = 0; i < count; i++)
tempd += (tempd + 100) / 130.0;
time = currentTimeMillis() - start;
if (tempd != 0)
print("Finished %d iterations of double division in %dms\r\n", count, time);
}
static void runTests(int count) {
testRusefiMethods(count);
testSystemCalls(count);
testMath(count);
}
void initTimePerfActions() {
// initOutputPin("test pad", &testOutput, TEST_PORT, TEST_PIN);
addConsoleActionI("testmath", runTests);
}

View File

@ -24,6 +24,9 @@ int main(void) {
halInit();
chSysInit();
// looks like this holds a random value on start? Let's set a nice clean zero
DWT_CYCCNT = 0;
runRusEfi();
return 0;
}

View File

@ -43,16 +43,6 @@ extern "C"
*/
#define TICKS_IN_MS (CH_FREQUENCY / 1000)
/**
* @brief Current system time in seconds.
*/
#define chTimeNowSeconds() (chTimeNow() / CH_FREQUENCY)
/**
* @brief Returns the number of milliseconds since the board initialization.
*/
#define currentTimeMillis() (chTimeNow() / TICKS_IN_MS)
#define Delay(ms) chThdSleepMilliseconds(ms)
#ifdef __cplusplus
extern "C"

View File

@ -274,5 +274,5 @@ void firmwareError(const char *fmt, ...) {
}
int getRusEfiVersion(void) {
return 20140422;
return 20140424;
}

View File

@ -1,75 +0,0 @@
/**
* @file efilib.c
*
* We cannot use stdlib because we do not have malloc - so, we have to implement these functions
*
* @date Feb 21, 2014
* @author Andrey Belomutskiy, (c) 2012-2014
*/
#include <string.h>
#include <math.h>
#include "efilib.h"
int indexOf(const char *string, char ch) {
// todo: there should be a standard function for this
int len = strlen(string);
for (int i = 0; i < len; i++) {
if (string[i] == ch)
return i;
}
return -1;
}
// string to integer
int atoi(const char *string) {
// todo: use stdlib '#include <stdlib.h> '
int len = strlen(string);
if (len == 0)
return -ERROR_CODE;
if (string[0] == '-')
return -atoi(string + 1);
int result = 0;
for (int i = 0; i < len; i++) {
char ch = string[i];
if (ch < '0' || ch > '9') {
return ERROR_CODE;
}
int c = ch - '0';
result = result * 10 + c;
}
return result;
}
static char todofixthismesswithcopy[100];
// string to float
float atoff(const char *param) {
int totallen = strlen(param);
if (totallen > sizeof(todofixthismesswithcopy) - 1)
return (float)NAN;
strcpy(todofixthismesswithcopy, param);
char *string = todofixthismesswithcopy;
// todo: is there a standard function?
// todo: create a unit test
int dotIndex = indexOf(string, '.');
if (dotIndex == -1) {
// just an integer
int result = atoi(string);
return (float) result;
}
// todo: this needs to be fixed
string[dotIndex] = 0;
int integerPart = atoi(string);
string += (dotIndex + 1);
int decimalLen = strlen(string);
int decimal = atoi(string);
float divider = 1.0;
// todo: reuse 'pow10' function which we have anyway
for (int i = 0; i < decimalLen; i++)
divider = divider * 10.0;
return integerPart + decimal / divider;
}