manual sync

This commit is contained in:
Andrey B 2014-04-30 09:37:02 -05:00
parent ade040036f
commit 7050527756
94 changed files with 3163 additions and 262 deletions

View File

@ -21,7 +21,7 @@
<option id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.option.debugging.level.2128888061" name="Debug level" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.option.debugging.level" value="org.eclipse.cdt.cross.arm.gnu.base.option.debugging.level.max" valueType="enumerated"/>
<option id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.option.addtools.createlisting.1809317580" name="Create Extended Listing" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.option.addtools.createlisting" value="false" valueType="boolean"/>
<targetPlatform id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.platform.debug.568472866" isAbstract="false" name="Windows Platform" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.platform.debug"/>
<builder buildPath="${workspace_loc:/chibios_template/Debug}" id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.builder.debug.479710089" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="ARM Sourcery Windows GNU Make builder" parallelBuildOn="true" parallelizationNumber="optimal" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.builder.debug"/>
<builder buildPath="${workspace_loc:/chibios_template/Debug}" id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.builder.debug.479710089" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="ARM Windows GNU Make builder (Sourcery Lite Bare)" parallelBuildOn="true" parallelizationNumber="optimal" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.builder.debug"/>
<tool id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.assembler.debug.1465123421" name="ARM Sourcery Windows GCC Assembler" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.assembler.debug">
<inputType id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.assembler.base.input.1266531692" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.assembler.base.input"/>
</tool>
@ -135,6 +135,7 @@
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/USARTv1}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/ports/common/ARMCMx/CMSIS/include}&quot;"/>
</option>
<option id="org.eclipse.cdt.cross.arm.gnu.cpp.compiler.option.other.otherflags.1439013659" superClass="org.eclipse.cdt.cross.arm.gnu.cpp.compiler.option.other.otherflags" value="-c -fmessage-length=0 -std=c++11" valueType="string"/>
<inputType id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.cpp.compiler.base.input.1939416167" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.cpp.compiler.base.input"/>
</tool>
<tool id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.c.linker.debug.369587711" name="ARM Sourcery Windows GCC C Linker" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.c.linker.debug"/>
@ -180,7 +181,7 @@
<toolChain id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.toolchain.release.614122032" name="ARM Windows GCC (Sourcery G++ Lite)" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.toolchain.release">
<option id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.option.debugging.level.447783356" name="Debug level" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.option.debugging.level" value="org.eclipse.cdt.cross.arm.gnu.base.option.debugging.level.none" valueType="enumerated"/>
<targetPlatform id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.platform.release.1559197737" isAbstract="false" name="Windows Platform" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.platform.release"/>
<builder buildPath="${workspace_loc:/chibios_template/Release}" id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.builder.release.845491162" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="ARM Sourcery Windows GNU Make builder" parallelBuildOn="true" parallelizationNumber="optimal" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.builder.release"/>
<builder buildPath="${workspace_loc:/chibios_template/Release}" id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.builder.release.845491162" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="ARM Windows GNU Make builder (Sourcery Lite Bare)" parallelBuildOn="true" parallelizationNumber="optimal" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.builder.release"/>
<tool id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.assembler.release.1527944975" name="ARM Sourcery Windows GCC Assembler" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.assembler.release">
<inputType id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.assembler.base.input.1359572999" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.assembler.base.input"/>
</tool>

View File

@ -813,7 +813,7 @@ EXCLUDE_PATTERNS =
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories use the pattern */test/*
EXCLUDE_SYMBOLS =
EXCLUDE_SYMBOLS = cisnan, validateBuffer, append
# The EXAMPLE_PATH tag can be used to specify one or more files or directories
# that contain example code fragments that are included (see the \include

View File

@ -18,7 +18,7 @@ endif
# C++ specific options here (added to USE_OPT).
ifeq ($(USE_CPPOPT),)
USE_CPPOPT = -fno-rtti -fno-exceptions -fno-use-cxa-atexit
USE_CPPOPT = -std=c++11 -fno-rtti -fno-exceptions -fno-use-cxa-atexit
endif
# Enable this if you want the linker to remove unused code and data
@ -122,7 +122,7 @@ CSRC = $(PORTSRC) \
$(CONSOLEUTILSRC) \
$(HALSRC) \
$(EMULATIONSRC) \
$(HW_LAYERESRC) \
$(HW_LAYERSRC) \
$(CONTROLLERSSRC) \
$(CONTROLLERS_ALGO_SRC) \
$(CONTROLLERS_MATH_SRC) \
@ -141,6 +141,9 @@ CPPSRC = $(CHCPPSRC) \
$(CONTROLLERS_ALGO_SRC_CPP) \
$(SYSTEMSRC_CPP) \
$(ENGINES_SRC_CPP) \
$(HW_LAYER_SRC_CPP) \
$(CONSOLE_SRC_CPP) \
$(CONTROLLERS_SENSORS_SRC_CPP) \
$(CONTROLLERS_SRC_CPP) \
$(UTILSRC_CPP) \
$(CONTROLLERS_MATH_SRC_CPP) \

View File

@ -1,4 +1,7 @@
rem make, gcc, Windows and Cygwin combined have some issue with spaces or colons in paths, that's a workaround
rem that's more or less 'make clean'
rd /s /q .dep
rd /s /q build
# that's 'make' with some extra utilities
compile.bat

View File

@ -6,6 +6,7 @@ rm -rf build\rusefi.hex
call update_version.bat
echo Starting compilation
rem the important piece
make
rem cd build
@ -31,9 +32,11 @@ cd ../firmware
cd build
rem Generate human-readable version of the .map memory usage report
java -jar ../../java_tools/gcc_map_reader.jar > ../../firmware_binary/rusefi_ram_report.txt
cd ..
rem file, let's program the board right away
flash.bat
exit

View File

@ -1,4 +1,6 @@
CONSOLESRC = $(PROJECT_DIR)/console/eficonsole.c \
$(PROJECT_DIR)/console/console_io.c \
$(PROJECT_DIR)/console/status_loop.c
$(PROJECT_DIR)/console/console_io.c
CONSOLE_SRC_CPP = $(PROJECT_DIR)/console/status_loop.cpp

View File

@ -29,9 +29,18 @@
#define CONSOLE_CHANNEL EFI_CONSOLE_UART_DEVICE
#endif
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
void consolePutChar(int x);
void consoleOutputBuffer(const int8_t *buf, int size);
void startChibiosConsole(void (*console_line_callback_p)(char *));
int is_serial_ready(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* CONSOLE_IO_H_ */

View File

@ -27,7 +27,6 @@
#include <chprintf.h>
#include "eficonsole.h"
#include "console_io.h"
#include "rusefi.h"
#include "svnversion.h"
static Logging logger;

View File

@ -0,0 +1,409 @@
/**
* @file status_loop.c
* @brief Human-readable protocol status messages
*
* http://rusefi.com/forum/viewtopic.php?t=263 Dev console overview
* http://rusefi.com/forum/viewtopic.php?t=210 Commands overview
*
*
* @date Mar 15, 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 "status_loop.h"
#include "ec2.h"
#include "adc_inputs.h"
#if EFI_WAVE_ANALYZER
#include "wave_analyzer.h"
#endif
#include "trigger_central.h"
#include "engine_state.h"
#include "io_pins.h"
#include "mmc_card.h"
#include "console_io.h"
#include "advance_map.h"
#if EFI_TUNER_STUDIO
#include "tunerstudio.h"
#endif /* EFI_TUNER_STUDIO */
#include "wave_math.h"
#include "fuel_math.h"
#include "main_trigger_callback.h"
#include "engine_math.h"
#include "idle_thread.h"
#include "engine_configuration.h"
#include "rfiutil.h"
#include "svnversion.h"
#if EFI_PROD_CODE
// todo: move this logic to algo folder!
#include "rtc_helper.h"
#include "lcd_HD44780.h"
#include "rusefi.h"
#endif
// this 'true' value is needed for simulator
static volatile int fullLog = TRUE;
int warningEnabled = TRUE;
//int warningEnabled = FALSE;
extern engine_configuration_s * engineConfiguration;
extern engine_configuration2_s * engineConfiguration2;
#define FULL_LOGGING_KEY "fl"
#if EFI_PROD_CODE || EFI_SIMULATOR
static Logging logger;
static void setWarningEnabled(int value) {
warningEnabled = value;
}
#endif /* EFI_PROD_CODE || EFI_SIMULATOR */
#if EFI_FILE_LOGGING
static Logging fileLogger;
#endif /* EFI_FILE_LOGGING */
static void reportSensorF(char *caption, float value, int precision) {
#if EFI_PROD_CODE || EFI_SIMULATOR
debugFloat(&logger, caption, value, precision);
#endif /* EFI_PROD_CODE || EFI_SIMULATOR */
#if EFI_FILE_LOGGING
debugFloat(&fileLogger, caption, value, precision);
#endif /* EFI_FILE_LOGGING */
}
static void reportSensorI(char *caption, int value) {
#if EFI_PROD_CODE || EFI_SIMULATOR
debugInt(&logger, caption, value);
#endif /* EFI_PROD_CODE || EFI_SIMULATOR */
#if EFI_FILE_LOGGING
debugInt(&fileLogger, caption, value);
#endif /* EFI_FILE_LOGGING */
}
static const char* boolean2string(int value) {
return value ? "YES" : "NO";
}
void finishStatusLine(void) {
printLine(&logger);
}
void printSensors(void) {
#if EFI_FILE_LOGGING
resetLogging(&fileLogger);
#endif /* EFI_FILE_LOGGING */
// current time, in milliseconds
int nowMs = currentTimeMillis();
float sec = ((float) nowMs) / 1000;
reportSensorF("time", sec, 3);
reportSensorI("rpm", getRpm());
reportSensorF("maf", getMaf(), 2);
if (engineConfiguration2->hasMapSensor) {
reportSensorF(getCaption(LP_MAP), getMap(), 2);
}
reportSensorF("afr", getAfr(), 2);
reportSensorF("vref", getVRef(), 2);
reportSensorF("vbatt", getVBatt(), 2);
reportSensorF(getCaption(LP_THROTTLE), getTPS(), 2);
if (engineConfiguration2->hasCltSensor) {
reportSensorF(getCaption(LP_ECT), getCoolantTemperature(), 2);
}
reportSensorF(getCaption(LP_IAT), getIntakeAirTemperature(), 2);
// debugFloat(&logger, "tch", getTCharge1(tps), 2);
#if EFI_FILE_LOGGING
appendPrintf(&fileLogger, "\r\n");
appendToLog(fileLogger.buffer);
#endif /* EFI_FILE_LOGGING */
}
void printState(int currentCkpEventCounter) {
printSensors();
int rpm = getRpm();
debugInt(&logger, "ckp_c", currentCkpEventCounter);
debugInt(&logger, "fuel_lag", getRevolutionCounter());
// debugInt(&logger, "idl", getIdleSwitch());
// debugFloat(&logger, "table_spark", getAdvance(rpm, getMaf()), 2);
float engineLoad = getEngineLoad();
debugFloat(&logger, "fuel_base", getBaseFuel(rpm, engineLoad), 2);
// debugFloat(&logger, "fuel_iat", getIatCorrection(getIntakeAirTemperature()), 2);
// debugFloat(&logger, "fuel_clt", getCltCorrection(getCoolantTemperature()), 2);
// debugFloat(&logger, "fuel_lag", getInjectorLag(getVBatt()), 2);
debugFloat(&logger, "fuel", getRunningFuel(rpm, engineLoad), 2);
debugFloat(&logger, "timing", getAdvance(rpm, engineLoad), 2);
// float map = getMap();
// float fuel = getDefaultFuel(rpm, map);
// debugFloat(&logger, "d_fuel", fuel, 2);
}
#define INITIAL_FULL_LOG TRUE
//#define INITIAL_FULL_LOG FALSE
static char LOGGING_BUFFER[500];
#if EFI_PROD_CODE
volatile int needToReportStatus = FALSE;
static int prevCkpEventCounter = -1;
static Logging logger2;
static void printStatus(void) {
needToReportStatus = TRUE;
}
//float getTCharge1(float tps) {
// float cltK = tempCtoKelvin(getCoolantTemperature());
// float iatK = tempCtoKelvin(getIntakeAirTemperature());
// return getTCharge(getCurrentRpm(), tps, cltK, iatK);
//}
#if EFI_CUSTOM_PANIC_METHOD
extern char *dbg_panic_file;
extern int dbg_panic_line;
#endif
void onDbgPanic(void) {
setOutputPinValue(LED_ERROR, 1);
}
int hasFatalError(void) {
return dbg_panic_msg != NULL;
}
static void checkIfShouldHalt(void) {
#if CH_DBG_ENABLED
if (hasFatalError()) {
setOutputPinValue(LED_ERROR, 1);
#if EFI_CUSTOM_PANIC_METHOD
print("my FATAL [%s] at %s:%d\r\n", dbg_panic_msg, dbg_panic_file, dbg_panic_line);
#else
print("my FATAL [%s] at %s:%d\r\n", dbg_panic_msg);
#endif
chThdSleepSeconds(1);
// todo: figure out how we halt exactly
while (TRUE) {
}
chSysHalt();
}
#endif
}
/**
* Time when the firmware version was reported last time, in seconds
* TODO: implement a request/response instead of just constantly sending this out
*/
static systime_t timeOfPreviousPrintVersion = (systime_t) -1;
static void printVersion(systime_t nowSeconds) {
if (overflowDiff(nowSeconds, timeOfPreviousPrintVersion) < 4)
return;
timeOfPreviousPrintVersion = nowSeconds;
appendPrintf(&logger, "rusEfiVersion%s%d@%d %s%s", DELIMETER, getRusEfiVersion(), SVN_VERSION, getConfigurationName(engineConfiguration),
DELIMETER);
}
static systime_t timeOfPreviousReport = (systime_t) -1;
extern bool hasFirmwareError;
extern char errorMessageBuffer[200];
/**
* @brief Sends all pending data to dev console
*/
void updateDevConsoleState(void) {
if (!is_serial_ready())
return;
checkIfShouldHalt();
printPending();
pokeAdcInputs();
if (hasFirmwareError) {
printMsg(&logger, "firmware error: %s", errorMessageBuffer);
return;
}
if (!fullLog)
return;
systime_t nowSeconds = getTimeNowSeconds();
printVersion(nowSeconds);
int currentCkpEventCounter = getCrankEventCounter();
if (prevCkpEventCounter == currentCkpEventCounter && timeOfPreviousReport == nowSeconds)
return;
timeOfPreviousReport = nowSeconds;
prevCkpEventCounter = currentCkpEventCounter;
printState(currentCkpEventCounter);
#if EFI_WAVE_ANALYZER
// printWave(&logger);
#endif
finishStatusLine();
}
/*
* command example:
* sfm 3500 400
* that would be 'show fuel for rpm 3500 maf 4.0'
*/
static void showFuelMap(int rpm, int key100) {
float engineLoad = key100 / 100.0;
float baseFuel = getBaseFuel(rpm, engineLoad);
float iatCorrection = getIatCorrection(getIntakeAirTemperature());
float cltCorrection = getCltCorrection(getCoolantTemperature());
float injectorLag = getInjectorLag(getVBatt());
print("baseFuel=%f\r\n", baseFuel);
print("iatCorrection=%f cltCorrection=%f injectorLag=%d\r\n", iatCorrection, cltCorrection,
(int) (100 * injectorLag));
float value = getRunningFuel(rpm, engineLoad);
print("fuel map rpm=%d, key=%f: %d\r\n", rpm, engineLoad, (int) (100 * value));
scheduleMsg(&logger2, "fuel map value = %f", value);
}
static char buffer[10];
static char dateBuffer[30];
void updateHD44780lcd(void) {
lcd_HD44780_set_position(0, 9);
lcd_HD44780_print_char('R');
lcd_HD44780_set_position(0, 10);
char * ptr = itoa10((uint8_t*)buffer, getRpm());
ptr[0] = 0;
int len = ptr - buffer;
for (int i = 0; i < 6 - len; i++)
lcd_HD44780_print_char(' ');
lcd_HD44780_print_string(buffer);
lcd_HD44780_set_position(2, 0);
lcd_HD44780_print_char('C');
ftoa(buffer, getCoolantTemperature(), 100);
lcd_HD44780_print_string(buffer);
#if EFI_PROD_CODE
dateToString(dateBuffer);
lcd_HD44780_set_position(1, 0);
lcd_HD44780_print_string(dateBuffer);
#endif /* EFI_PROD_CODE */
}
#endif /* EFI_PROD_CODE */
static WORKING_AREA(lcdThreadStack, UTILITY_THREAD_STACK_SIZE);
static void lcdThread(void *arg) {
chRegSetThreadName("lcd");
while (true) {
#if EFI_HD44780_LCD
updateHD44780lcd();
#endif
chThdSleepMilliseconds(50);
}
}
static WORKING_AREA(tsThreadStack, UTILITY_THREAD_STACK_SIZE);
static void tsStatusThread(void *arg) {
chRegSetThreadName("tuner s");
while (true) {
#if EFI_TUNER_STUDIO
// sensor state for EFI Analytics Tuner Studio
updateTunerStudioState();
#endif /* EFI_TUNER_STUDIO */
chThdSleepMilliseconds(50);
}
}
void initStatusLoop(void) {
#if EFI_PROD_CODE || EFI_SIMULATOR
initLoggingExt(&logger, "status loop", LOGGING_BUFFER, sizeof(LOGGING_BUFFER));
#endif /* EFI_PROD_CODE || EFI_SIMULATOR */
setFullLog(INITIAL_FULL_LOG);
addConsoleActionI(FULL_LOGGING_KEY, setFullLog);
addConsoleActionI("warn", setWarningEnabled);
#if EFI_PROD_CODE
initLogging(&logger2, "main event handler");
addConsoleActionII("sfm", showFuelMap);
addConsoleAction("status", printStatus);
#endif /* EFI_PROD_CODE */
#if EFI_FILE_LOGGING
initLogging(&fileLogger, "file logger");
#endif /* EFI_FILE_LOGGING */
}
void startStatusThreads(void) {
// todo: refactoring needed, this file should probably be split into pieces
chThdCreateStatic(lcdThreadStack, sizeof(lcdThreadStack), NORMALPRIO, (tfunc_t) lcdThread, NULL);
chThdCreateStatic(tsThreadStack, sizeof(tsThreadStack), NORMALPRIO, (tfunc_t) tsStatusThread, NULL);
}
void setFullLog(int value) {
print("Setting full logging: %s\r\n", boolean2string(value));
printMsg(&logger, "%s%d", FULL_LOGGING_KEY, value);
fullLog = value;
}
int getFullLog(void) {
return fullLog;
}

View File

@ -180,7 +180,7 @@ static char* get2ndCaption(int loggingPoint) {
return NULL;
}
void initLoggingExt(Logging *logging, char *name, char *buffer, int bufferSize) {
void initLoggingExt(Logging *logging, const char *name, char *buffer, int bufferSize) {
print("Init logging\r\n");
logging->name = name;
logging->buffer = buffer;
@ -193,7 +193,7 @@ int isInitialized(Logging *logging) {
return logging->isInitialized == MAGIC_LOGGING_FLAG;
}
void initLogging(Logging *logging, char *name) {
void initLogging(Logging *logging, const char *name) {
initLoggingExt(logging, name, logging->DEFAULT_BUFFER, sizeof(logging->DEFAULT_BUFFER));
}
@ -237,22 +237,6 @@ void debugFloat(Logging *logging, char *caption, float value, int precision) {
appendFloat(logging, value, precision);
append(logging, DELIMETER);
}
/*
void logInt(Logging *logging, LoggingPoints loggingPoint, int value) {
char *caption = getCaption(loggingPoint);
debugInt(logging, caption, value);
}
void logFloat(Logging *logging, LoggingPoints loggingPoint, float value) {
debugFloat(logging, getCaption(loggingPoint), value, 2);
}
*/
static void commonSimpleMsg(Logging *logging, char *msg, int value) {
resetLogging(logging);
appendMsgPrefix(logging);
appendPrintf(logging, "%s%d", msg, value);
}
static char header[16];

View File

@ -28,7 +28,7 @@ typedef enum {
// todo: migrate to external buffer so that different instances have different
// size of buffers?
typedef struct {
char *name;
const char *name;
char SMALL_BUFFER[40];
// todo: explicitly default buffer externally so that we do not have default_buffer where we do not need it?
char DEFAULT_BUFFER[200];
@ -52,8 +52,8 @@ uint32_t loggingSize(Logging *logging);
int isInitialized(Logging *logging);
void initLogging(Logging *logging, char *name);
void initLoggingExt(Logging *logging, char *name, char *buffer, int bufferSize);
void initLogging(Logging *logging, const char *name);
void initLoggingExt(Logging *logging, const char *name, char *buffer, int bufferSize);
void debugInt(Logging *logging, char *caption, int value);
void logInt(Logging *logging, LoggingPoints loggingPoint, int value);

View File

@ -0,0 +1,47 @@
/**
* @file PwmTester.cpp
*
* @date Apr 29, 2014
* @author Andrey Belomutskiy, (c) 2012-2013
*/
#include "main.h"
#include "PwmTester.h"
#include "trigger_structure.h"
#include "pwm_generator_logic.h"
#include "engine_configuration.h"
#include "pwm_generator.h"
static Logging logger;
static float _switchTimes[2];
// todo: extract helper for simple PWM?
static int pinStates[2];
static single_wave_s wave(pinStates);
static single_wave_s sr[1] = { wave };
static PwmConfig pwmTest[4] = { PwmConfig(_switchTimes, sr),
PwmConfig(_switchTimes, sr),
PwmConfig(_switchTimes, sr),
PwmConfig(_switchTimes, sr)};
extern board_configuration_s *boardConfiguration;
static void startPwmTest(int freq) {
scheduleMsg(&logger, "running pwm test @%d", freq);
startSimplePwm(&pwmTest[0], "tester", boardConfiguration->injectionPins[0],
INJECTOR_1_OUTPUT, 0.5, freq / 1000, FALSE);
startSimplePwm(&pwmTest[1], "tester", boardConfiguration->injectionPins[1],
INJECTOR_2_OUTPUT, 0.5, freq / 100, FALSE);
startSimplePwm(&pwmTest[2], "tester", boardConfiguration->injectionPins[2],
INJECTOR_3_OUTPUT, 0.5, freq, FALSE);
startSimplePwm(&pwmTest[3], "tester", boardConfiguration->injectionPins[3],
INJECTOR_4_OUTPUT, 0.5, freq / 33.3, FALSE);
}
void initPwmTester(void) {
initLogging(&logger, "pwm test");
addConsoleActionI("pwmtest", startPwmTest);
}

View File

@ -0,0 +1,12 @@
/**
* @file PwmTester.h
*
* @date Apr 29, 2014
* @author Andrey Belomutskiy, (c) 2012-2013
*/
#ifndef PWMTESTER_H_
#define PWMTESTER_H_
void initPwmTester(void);
#endif /* PWMTESTER_H_ */

View File

@ -0,0 +1,56 @@
/**
* @file accel_enrichment.cpp
* @brief Acceleration enrichment calculator
*
* @date Apr 21, 2014
* @author Dmitry Sidin
* @author Andrey Belomutskiy (c) 2012-2014
*/
#include "main.h"
#include "trigger_central.h"
#include "accel_enrichment.h"
#include "engine_state.h"
#include "engine_math.h"
#include "signal_executor.h"
extern engine_configuration_s *engineConfiguration;
static AccelEnrichmemnt instance;
void AccelEnrichmemnt::updateDiffEnrichment(engine_configuration_s *engineConfiguration, float engineLoad) {
for (int i = 0; i == 4; i++) {
engineLoadD[i] = engineLoadD[i + 1];
}
engineLoadD[0] = engineLoad;
float Dcurr = engineLoadD[1] - engineLoadD[0];
float Dold = engineLoadD[3] - engineLoadD[2];
diffEnrichment = ((3 * Dcurr + Dold) / 4) * (engineConfiguration->diffLoadEnrichmentCoef);
}
float AccelEnrichmemnt::getDiffEnrichment() {
return diffEnrichment;
}
float getAccelEnrichment(void) {
return instance.getDiffEnrichment();
}
#if EFI_PROD_CODE
static WORKING_AREA(aeThreadStack, UTILITY_THREAD_STACK_SIZE);
static msg_t DiffEnrichmentThread(int param) {
chRegSetThreadName("Diff Enrichment");
while (TRUE) {
instance.updateDiffEnrichment(engineConfiguration, getEngineLoad());
chThdSleepMilliseconds(100);
}
#if defined __GNUC__
return -1;
#endif
}
void initDiffEnrichment(void) {
chThdCreateStatic(aeThreadStack, sizeof(aeThreadStack), LOWPRIO, (tfunc_t) DiffEnrichmentThread, NULL);
}
#endif

View File

@ -0,0 +1,27 @@
/**
* @file accel_enrichment.h
* @brief Acceleration enrichment calculator
*
* @date Apr 21, 2014
* @author Dmitry Sidin
* @author Andrey Belomutskiy (c) 2012-2014
*/
#ifndef ACC_ENRICHMENT_H_
#define ACC_ENRICHMENT_H_
#include "engine_configuration.h"
class AccelEnrichmemnt {
public:
void updateDiffEnrichment(engine_configuration_s *engineConfiguration, float engineLoad);
float getDiffEnrichment(void);
private:
float engineLoadD[5];
float diffEnrichment;
};
void initDiffEnrichment(void);
float getAccelEnrichment(void);
#endif /* ACC_ENRICHMENT_H_ */

View File

@ -27,7 +27,7 @@
#include "engine_math.h"
extern engine_configuration_s *engineConfiguration;
extern engine_configuration2_s *engineConfiguration2;
//extern engine_configuration2_s *engineConfiguration2;
static float *timing_ptrs[AD_LOAD_COUNT];
static int initialized = FALSE;

View File

@ -8,10 +8,19 @@
#ifndef ADVANCE_H_
#define ADVANCE_H_
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
#define AD_LOAD_COUNT 16
#define AD_RPM_COUNT 16
float getAdvance(int rpm, float engineLoad);
void prepareTimingMap(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* ADVANCE_H_ */

View File

@ -0,0 +1,48 @@
/*
* @file algo.cpp
*
* @date Mar 2, 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 "global.h"
#include "algo.h"
//#include "rpm_calculator.h"
#include "advance_map.h"
#include "fuel_math.h"
#include "wave_chart.h"
#include "settings.h"
#include "signal_executor.h"
WaveChart waveChart;
void initAlgo(void) {
#if EFI_PROD_CODE || EFI_SIMULATOR
initSettings();
initSignalExecutor();
#endif
#if EFI_WAVE_CHART
initWaveChart(&waveChart);
#endif
prepareFuelMap();
prepareTimingMap();
}

View File

@ -1,19 +1,18 @@
CONTROLLERS_ALGO_SRC = $(PROJECT_DIR)/controllers/algo/map_adjuster.c \
$(PROJECT_DIR)/controllers/algo/advance_map.c \
$(PROJECT_DIR)/controllers/algo/engine_configuration.c \
$(PROJECT_DIR)/controllers/algo/signal_executor.c \
$(PROJECT_DIR)/controllers/algo/interpolation.c \
$(PROJECT_DIR)/controllers/algo/malfunction_central.c \
$(PROJECT_DIR)/controllers/algo/event_registry.c \
$(PROJECT_DIR)/controllers/algo/idle_controller.c \
$(PROJECT_DIR)/controllers/algo/wave_chart.c \
$(PROJECT_DIR)/controllers/algo/nmea.c \
$(PROJECT_DIR)/controllers/algo/algo.c \
$(PROJECT_DIR)/controllers/algo/signal_executor_single_timer_algo.c
$(PROJECT_DIR)/controllers/algo/nmea.c
CONTROLLERS_ALGO_SRC_CPP = $(PROJECT_DIR)/controllers/algo/OutputSignalArray.cpp \
$(PROJECT_DIR)/controllers/algo/fuel_math.cpp \
$(PROJECT_DIR)/controllers/algo/accel_enrichmemnt.cpp \
$(PROJECT_DIR)/controllers/algo/accel_enrichment.cpp \
$(PROJECT_DIR)/controllers/algo/engine_configuration.cpp \
$(PROJECT_DIR)/controllers/algo/algo.cpp \
$(PROJECT_DIR)/controllers/algo/event_queue.cpp

View File

@ -0,0 +1,71 @@
/**
* ec2.h
*
* this is a mess because some code is still in C and some is
* already in C++. trigger structure is C++
*
* Created on: Apr 26, 2014
* Author: Andrey
*/
#ifndef EC2_H_
#define EC2_H_
#include "engine_configuration.h"
#include "trigger_structure.h"
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
/**
* this part of the structure is separate just because so far
* these fields are not integrated with Tuner Studio. Step by step :)
*/
class engine_configuration2_s {
public:
engine_configuration2_s();
int hasMapSensor;
int hasCltSensor;
Thermistor iat;
Thermistor clt;
int crankAngleRange;
trigger_shape_s triggerShape;
cranking_ignition_mode_e crankingIgnitionMode;
EventHandlerConfiguration engineEventConfiguration;
int isInjectionEnabledFlag;
};
void prepareOutputSignals(engine_configuration_s *engineConfiguration,
engine_configuration2_s *engineConfiguration2);
void initializeIgnitionActions(float baseAngle, engine_configuration_s *engineConfiguration, engine_configuration2_s *engineConfiguration2);
void addFuelEvents(engine_configuration_s const *e, engine_configuration2_s *engineConfiguration2, ActuatorEventList *list, injection_mode_e mode);
void registerActuatorEventExt(engine_configuration_s const *engineConfiguration, trigger_shape_s * s, ActuatorEventList *list, OutputSignal *actuator, float angleOffset);
void resetConfigurationExt(engine_type_e engineType,
engine_configuration_s *engineConfiguration,
engine_configuration2_s *engineConfiguration2,
board_configuration_s *boardConfiguration);
void applyNonPersistentConfiguration(engine_configuration_s *engineConfiguration,
engine_configuration2_s *engineConfiguration2, engine_type_e engineType);
void setDefaultNonPersistentConfiguration(engine_configuration2_s *engineConfiguration2);
void printConfiguration(engine_configuration_s *engineConfiguration, engine_configuration2_s *engineConfiguration2);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* EC2_H_ */

View File

@ -0,0 +1,383 @@
/**
* @file engine_controller.c
* @brief Utility method related to the engine configuration data structure.
*
* @date Nov 22, 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 "engine_configuration.h"
#include "allsensors.h"
#include "interpolation.h"
#include "trigger_decoder.h"
#include "engine_math.h"
#if EFI_PROD_CODE
#include "tunerstudio.h"
#endif
#include "audi_aan.h"
#include "dodge_neon.h"
#include "ford_aspire.h"
#include "ford_fiesta.h"
#include "ford_1995_inline_6.h"
#include "snow_blower.h"
#include "nissan_primera.h"
#include "honda_accord.h"
#include "GY6_139QMB.h"
#include "mazda_miata_nb.h"
#include "mazda_323.h"
#include "saturn_ion.h"
#include "MiniCooperR50.h"
#include "ford_escort_gt.h"
#include "citroenBerlingoTU3JP.h"
#define ADC_CHANNEL_FAST_ADC 256
static volatile int globalConfigurationVersion = 0;
int getGlobalConfigurationVersion(void) {
return globalConfigurationVersion;
}
void incrementGlobalConfigurationVersion(void) {
globalConfigurationVersion++;
}
/**
* @brief Sets the same dwell time across the whole getRpm() range
*/
void setConstantDwell(engine_configuration_s *engineConfiguration, float dwellMs) {
for (int i = 0; i < DWELL_CURVE_SIZE; i++) {
engineConfiguration->sparkDwellBins[i] = 1000 * i;
engineConfiguration->sparkDwell[i] = dwellMs;
}
}
void initBpsxD1Sensor(afr_sensor_s *sensor) {
/**
* This decodes BPSX D1 Wideband Controller analog signal
*/
sensor->v1 = 0;
sensor->value1 = 9;
sensor->v2 = 5;
sensor->value2 = 19;
}
void setWholeFuelMap(engine_configuration_s *engineConfiguration, float value) {
for (int l = 0; l < FUEL_LOAD_COUNT; l++) {
for (int r = 0; r < FUEL_RPM_COUNT; r++) {
engineConfiguration->fuelTable[l][r] = value;
}
}
}
/**
* @brief Global default engine configuration
* This method sets the default global engine configuration. These values are later overridden by engine-specific defaults
* and the settings saves in flash memory.
*/
void setDefaultConfiguration(engine_configuration_s *engineConfiguration,
board_configuration_s *boardConfiguration) {
memset(engineConfiguration, 0, sizeof(engine_configuration_s));
memset(boardConfiguration, 0, sizeof(board_configuration_s));
engineConfiguration->injectorLag = 0.0;
for (int i = 0; i < IAT_CURVE_SIZE; i++) {
engineConfiguration->iatFuelCorrBins[i] = -40 + i * 10;
engineConfiguration->iatFuelCorr[i] = 1; // this correction is a multiplier
}
for (int i = 0; i < CLT_CURVE_SIZE; i++) {
engineConfiguration->cltFuelCorrBins[i] = -40 + i * 10;
engineConfiguration->cltFuelCorr[i] = 1; // this correction is a multiplier
}
// setTableValue(engineConfiguration->cltFuelCorrBins, engineConfiguration->cltFuelCorr, CLT_CURVE_SIZE, -40, 1.5);
// setTableValue(engineConfiguration->cltFuelCorrBins, engineConfiguration->cltFuelCorr, CLT_CURVE_SIZE, -30, 1.5);
// setTableValue(engineConfiguration->cltFuelCorrBins, engineConfiguration->cltFuelCorr, CLT_CURVE_SIZE, -20, 1.42);
// setTableValue(engineConfiguration->cltFuelCorrBins, engineConfiguration->cltFuelCorr, CLT_CURVE_SIZE, -10, 1.36);
// setTableValue(engineConfiguration->cltFuelCorrBins, engineConfiguration->cltFuelCorr, CLT_CURVE_SIZE, 0, 1.28);
// setTableValue(engineConfiguration->cltFuelCorrBins, engineConfiguration->cltFuelCorr, CLT_CURVE_SIZE, 10, 1.19);
// setTableValue(engineConfiguration->cltFuelCorrBins, engineConfiguration->cltFuelCorr, CLT_CURVE_SIZE, 20, 1.12);
// setTableValue(engineConfiguration->cltFuelCorrBins, engineConfiguration->cltFuelCorr, CLT_CURVE_SIZE, 30, 1.10);
// setTableValue(engineConfiguration->cltFuelCorrBins, engineConfiguration->cltFuelCorr, CLT_CURVE_SIZE, 40, 1.06);
// setTableValue(engineConfiguration->cltFuelCorrBins, engineConfiguration->cltFuelCorr, CLT_CURVE_SIZE, 50, 1.06);
// setTableValue(engineConfiguration->cltFuelCorrBins, engineConfiguration->cltFuelCorr, CLT_CURVE_SIZE, 60, 1.03);
// setTableValue(engineConfiguration->cltFuelCorrBins, engineConfiguration->cltFuelCorr, CLT_CURVE_SIZE, 70, 1.01);
for (int i = 0; i < VBAT_INJECTOR_CURVE_SIZE; i++) {
engineConfiguration->battInjectorLagCorrBins[i] = 12 - VBAT_INJECTOR_CURVE_SIZE / 2 + i;
engineConfiguration->battInjectorLagCorr[i] = 0; // zero extra time by default
}
setConstantDwell(engineConfiguration, 4); // 4ms is global default dwell
setFuelLoadBin(engineConfiguration, 1.2, 4.4);
setFuelRpmBin(engineConfiguration, 800, 7000);
setTimingLoadBin(engineConfiguration, 1.2, 4.4);
setTimingRpmBin(engineConfiguration, 800, 7000);
setTableBin(engineConfiguration->map.config.samplingAngleBins, MAP_ANGLE_SIZE, 800, 7000);
setTableBin(engineConfiguration->map.config.samplingWindowBins, MAP_ANGLE_SIZE, 800, 7000);
// set_whole_timing_map 3
setWholeFuelMap(engineConfiguration, 3);
setThermistorConfiguration(&engineConfiguration->cltThermistorConf, 0, 9500, 23.8889, 2100, 48.8889, 1000);
engineConfiguration->cltThermistorConf.bias_resistor = 1500;
setThermistorConfiguration(&engineConfiguration->iatThermistorConf, 32, 9500, 75, 2100, 120, 1000);
// todo: this value is way off! I am pretty sure temp coeffs are off also
engineConfiguration->iatThermistorConf.bias_resistor = 2700;
engineConfiguration->rpmHardLimit = 7000;
engineConfiguration->crankingSettings.crankingRpm = 550;
// set_cranking_fuel_max 6 40
engineConfiguration->crankingSettings.coolantTempMaxC = 40; // 6ms at 40C
engineConfiguration->crankingSettings.fuelAtMaxTempMs = 6;
// set_cranking_fuel_min 6 -40
engineConfiguration->crankingSettings.coolantTempMinC = -40; // 6ms at -40C
engineConfiguration->crankingSettings.fuelAtMinTempMs = 6;
engineConfiguration->analogInputDividerCoefficient = 2;
engineConfiguration->crankingChargeAngle = 70;
engineConfiguration->timingMode = TM_DYNAMIC;
engineConfiguration->fixedModeTiming = 50;
engineConfiguration->analogChartMode = AC_TRIGGER;
engineConfiguration->map.channel = ADC_CHANNEL_FAST_ADC;
engineConfiguration->firingOrder = FO_1_THEN_3_THEN_4_THEN2;
engineConfiguration->crankingInjectionMode = IM_SIMULTANEOUS;
engineConfiguration->injectionMode = IM_SEQUENTIAL;
engineConfiguration->ignitionMode = IM_ONE_COIL;
engineConfiguration->globalTriggerAngleOffset = 0;
engineConfiguration->injectionOffset = 0;
engineConfiguration->ignitionOffset = 0;
engineConfiguration->overrideCrankingIgnition = TRUE;
engineConfiguration->analogChartFrequency = 20;
engineConfiguration->engineLoadMode = LM_MAF;
engineConfiguration->vbattDividerCoeff = ((float)(15 + 65)) / 15;
engineConfiguration->fanOnTemperature = 75;
engineConfiguration->fanOffTemperature = 70;
engineConfiguration->tpsMin = convertVoltageTo10bitADC(1.250);
engineConfiguration->tpsMax = convertVoltageTo10bitADC(4.538);
engineConfiguration->can_nbc_type = CAN_BUS_NBC_BMW;
engineConfiguration->can_sleep_period = 50;
engineConfiguration->canReadEnabled = TRUE;
engineConfiguration->canWriteEnabled = FALSE;
/**
* 0.5 means primary position sensor is on a camshaft
*/
engineConfiguration->rpmMultiplier = 0.5;
engineConfiguration->cylindersCount = 4;
engineConfiguration->displayMode = DM_HD44780;
engineConfiguration->logFormat = LF_NATIVE;
engineConfiguration->triggerConfig.triggerType = TT_TOOTHED_WHEEL;
engineConfiguration->triggerConfig.syncRatioFrom = 1.5;
engineConfiguration->triggerConfig.syncRatioTo = 3;
engineConfiguration->triggerConfig.isSynchronizationNeeded = TRUE;
engineConfiguration->triggerConfig.useRiseEdge = TRUE;
engineConfiguration->HD44780width = 16;
engineConfiguration->HD44780height = 2;
engineConfiguration->tpsAdcChannel = 3;
engineConfiguration->vBattAdcChannel = 5;
engineConfiguration->cltAdcChannel = 6;
engineConfiguration->iatAdcChannel = 7;
engineConfiguration->mafAdcChannel = 0;
engineConfiguration->afrSensor.afrAdcChannel = 14;
initBpsxD1Sensor(&engineConfiguration->afrSensor);
engineConfiguration->globalFuelCorrection = 1;
engineConfiguration->needSecondTriggerInput = TRUE;
engineConfiguration->map.config.mapType = MT_CUSTOM;
engineConfiguration->map.config.Min = 0;
engineConfiguration->map.config.Max = 500;
engineConfiguration->diffLoadEnrichmentCoef = 1;
boardConfiguration->idleValvePin = GPIOE_2;
boardConfiguration->idleValvePinMode = OM_DEFAULT;
boardConfiguration->fuelPumpPin = GPIOC_13;
boardConfiguration->fuelPumpPinMode = OM_DEFAULT;
boardConfiguration->electronicThrottlePin1 = GPIOC_9;
boardConfiguration->injectionPins[0] = GPIOB_9;
boardConfiguration->injectionPins[1] = GPIOB_8;
boardConfiguration->injectionPins[2] = GPIOE_3;
boardConfiguration->injectionPins[3] = GPIOE_5;
boardConfiguration->injectionPins[4] = GPIOE_6;
boardConfiguration->injectionPins[5] = GPIOC_12;
boardConfiguration->injectionPinMode = OM_DEFAULT;
boardConfiguration->ignitionPins[0] = GPIOC_7;
boardConfiguration->ignitionPins[1] = GPIOE_4; // todo: update this value
boardConfiguration->ignitionPins[2] = GPIOE_0; // todo: update this value
boardConfiguration->ignitionPins[3] = GPIOE_1; // todo: update this value
boardConfiguration->ignitionPinMode = OM_DEFAULT;
boardConfiguration->malfunctionIndicatorPin = GPIOC_9;
boardConfiguration->malfunctionIndicatorPinMode = OM_DEFAULT;
boardConfiguration->fanPin = GPIOC_15;
boardConfiguration->fanPinMode = OM_DEFAULT;
boardConfiguration->idleSwitchPin = GPIOC_8;
boardConfiguration->triggerSimulatorPins[0] = GPIOD_1;
boardConfiguration->triggerSimulatorPins[1] = GPIOD_2;
boardConfiguration->triggerSimulatorPinModes[0] = OM_DEFAULT;
boardConfiguration->triggerSimulatorPinModes[1] = OM_DEFAULT;
boardConfiguration->HD44780_rs = GPIOE_9;
boardConfiguration->HD44780_e = GPIOE_11;
boardConfiguration->HD44780_db4 = GPIOE_13;
boardConfiguration->HD44780_db5 = GPIOE_15;
boardConfiguration->HD44780_db6 = GPIOB_11;
boardConfiguration->HD44780_db7 = GPIOB_13;
}
void setDefaultNonPersistentConfiguration(engine_configuration2_s *engineConfiguration2) {
/**
* 720 is the range for four stroke
*/
engineConfiguration2->crankAngleRange = 720;
engineConfiguration2->hasMapSensor = TRUE;
engineConfiguration2->hasCltSensor = TRUE;
}
void resetConfigurationExt(engine_type_e engineType,
engine_configuration_s *engineConfiguration,
engine_configuration2_s *engineConfiguration2,
board_configuration_s *boardConfiguration) {
/**
* Let's apply global defaults first
*/
setDefaultConfiguration(engineConfiguration, boardConfiguration);
engineConfiguration->engineType = engineType;
/**
* And override them with engine-specific defaults
*/
switch (engineType) {
#if EFI_SUPPORT_DODGE_NEON || defined(__DOXYGEN__)
case DODGE_NEON_1995:
setDodgeNeonEngineConfiguration(engineConfiguration, boardConfiguration);
break;
#endif /* EFI_SUPPORT_DODGE_NEON */
#if EFI_SUPPORT_FORD_ASPIRE || defined(__DOXYGEN__)
case FORD_ASPIRE_1996:
setFordAspireEngineConfiguration(engineConfiguration, boardConfiguration);
break;
#endif /* EFI_SUPPORT_FORD_ASPIRE */
#if EFI_SUPPORT_FORD_FIESTA || defined(__DOXYGEN__)
case FORD_FIESTA:
setFordFiestaDefaultEngineConfiguration(engineConfiguration);
break;
#endif /* EFI_SUPPORT_FORD_FIESTA */
#if EFI_SUPPORT_NISSAN_PRIMERA || defined(__DOXYGEN__)
case NISSAN_PRIMERA:
setNissanPrimeraEngineConfiguration(engineConfiguration);
break;
#endif
case HONDA_ACCORD:
setHondaAccordConfiguration(engineConfiguration);
break;
#if EFI_SUPPORT_1995_FORD_INLINE_6 || defined(__DOXYGEN__)
case FORD_INLINE_6_1995:
setFordInline6(engineConfiguration, boardConfiguration);
break;
#endif /* EFI_SUPPORT_1995_FORD_INLINE_6 */
case GY6_139QMB:
setGy6139qmbDefaultEngineConfiguration(engineConfiguration);
break;
case MAZDA_MIATA_NB:
setMazdaMiataNbEngineConfiguration(engineConfiguration, boardConfiguration);
break;
case MAZDA_323:
setMazda323EngineConfiguration(engineConfiguration);
break;
case SATURN_ION_2004:
setSaturnIonEngineConfiguration(engineConfiguration);
break;
case MINI_COOPER_R50:
setMiniCooperR50(engineConfiguration, boardConfiguration);
break;
case FORD_ESCORT_GT:
setFordEscortGt(engineConfiguration, boardConfiguration);
break;
case CITROEN_TU3JP:
setCitroenBerlingoTU3JPConfiguration(engineConfiguration, boardConfiguration);
break;
default:
firmwareError("Unexpected engine type: %d", engineType);
}
applyNonPersistentConfiguration(engineConfiguration, engineConfiguration2, engineType);
#if EFI_TUNER_STUDIO
syncTunerStudioCopy();
#endif
}
engine_configuration2_s::engine_configuration2_s() {
}
void applyNonPersistentConfiguration(engine_configuration_s *engineConfiguration, engine_configuration2_s *engineConfiguration2, engine_type_e engineType) {
// todo: this would require 'initThermistors() to re-establish a reference, todo: fix
// memset(engineConfiguration2, 0, sizeof(engine_configuration2_s));
engineConfiguration2->isInjectionEnabledFlag = TRUE;
initializeTriggerShape(engineConfiguration, engineConfiguration2);
chDbgCheck(engineConfiguration2->triggerShape.size != 0, "size is zero");
chDbgCheck(engineConfiguration2->triggerShape.shaftPositionEventCount, "shaftPositionEventCount is zero");
prepareOutputSignals(engineConfiguration, engineConfiguration2);
initializeIgnitionActions(0, engineConfiguration, engineConfiguration2);
}

View File

@ -12,7 +12,6 @@
#include "efifeatures.h"
#include "sensor_types.h"
#include "can_header.h"
#include "trigger_structure.h"
#include "event_registry.h"
#include "rusefi_enums.h"
@ -83,6 +82,26 @@ typedef struct {
} afr_sensor_s;
#define DWELL_COUNT 8
/**
* @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;
/**
* @brief Engine configuration.
* Values in this data structure are adjustable and persisted in on-board flash RAM.
@ -303,46 +322,17 @@ typedef struct {
board_configuration_s boardConfiguration;
} persistent_config_s;
/**
* this part of the structure is separate just because so far
* these fields are not integrated with Tuner Studio. Step by step :)
*/
typedef struct {
int hasMapSensor;
int hasCltSensor;
Thermistor iat;
Thermistor clt;
int crankAngleRange;
trigger_shape_s triggerShape;
cranking_ignition_mode_e crankingIgnitionMode;
EventHandlerConfiguration engineEventConfiguration;
int isInjectionEnabledFlag;
} engine_configuration2_s;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
char* getConfigurationName(engine_configuration_s *engineConfiguration);
const char* getConfigurationName(engine_configuration_s *engineConfiguration);
void setDefaultConfiguration(engine_configuration_s *engineConfiguration, board_configuration_s *boardConfiguration);
void setWholeFuelMap(engine_configuration_s *engineConfiguration, float value);
void setConstantDwell(engine_configuration_s *engineConfiguration, float dwellMs);
void setDefaultNonPersistentConfiguration(engine_configuration2_s *engineConfiguration2);
void printConfiguration(engine_configuration_s *engineConfiguration, engine_configuration2_s *engineConfiguration2);
void printFloatArray(char *prefix, float array[], int size);
void resetConfigurationExt(engine_type_e engineType,
engine_configuration_s *engineConfiguration,
engine_configuration2_s *engineConfiguration2,
board_configuration_s *boardConfiguration);
void applyNonPersistentConfiguration(engine_configuration_s *engineConfiguration,
engine_configuration2_s *engineConfiguration2, engine_type_e engineType);
void incrementGlobalConfigurationVersion(void);
int getGlobalConfigurationVersion(void);

View File

@ -36,6 +36,11 @@ void chDbgPanic3(const char *msg, char * file, int line);
void initErrorHandling(void);
// todo: better place for this shared declaration?
int getRusEfiVersion(void);
#define efiAssert(x, y) chDbgAssert(x, y, NULL)
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@ -25,7 +25,7 @@
#include "engine_math.h"
extern engine_configuration_s *engineConfiguration;
extern engine_configuration2_s *engineConfiguration2;
//extern engine_configuration2_s *engineConfiguration2;
void resetEventList(ActuatorEventList *list) {
list->size = 0;

View File

@ -10,7 +10,6 @@
#include "global.h"
#include "signal_executor.h"
#include "trigger_structure.h"
#define MAX_EVENT_COUNT 40

View File

@ -36,6 +36,7 @@
#include "allsensors.h"
#include "engine_math.h"
#include "rpm_calculator.h"
#include "accel_enrichment.h"
static float *fuel_ptrs[FUEL_LOAD_COUNT];
static int initialized = FALSE;
@ -115,6 +116,9 @@ float getRunningFuel(int rpm, float engineLoad) {
float cltCorrection = getCltCorrection(getCoolantTemperature());
float injectorLag = getInjectorLag(getVBatt());
float accelEnrichment = getAccelEnrichment();
// todo: accelEnrichment
return baseFuel * cltCorrection * iatCorrection + injectorLag;
}

View File

@ -15,7 +15,7 @@
#include "idle_controller.h"
void idleDebug(char *msg, int value);
// todo: move this to "idle_controller.h"
int isCranking(void);
static int lastGoodValue = DEFAULT_IDLE_DUTY;

View File

@ -32,6 +32,11 @@ typedef struct {
int timeOfLastIdleChange;
} IdleValveState;
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
void idleInit(IdleValveState *idle);
int getIdle(IdleValveState *idle, int currentRpm, int time);
void setIdleRpm(IdleValveState *idle, int targetRpm);
@ -40,5 +45,10 @@ void setIdleRpm(IdleValveState *idle, int targetRpm);
int max(int i1, int i2);
int min(int i1, int i2);
float maxF(float i1, float i2);
void idleDebug(char *msg, int value);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* IDLE_CONTROLLER_H_ */

View File

@ -14,7 +14,7 @@
#include "main.h"
#include "interpolation.h"
#include "engine_math.h"
//#include "engine_math.h"
#define INTERPOLATION_A(x1, y1, x2, y2) ((y1 - y2) / (x1 - x2))

View File

@ -24,8 +24,8 @@ typedef enum {
LED_EMULATOR,
IDLE_VALVE,
TRIGGER_EMILATOR_PRIMARY,
TRIGGER_EMILATOR_SECONDARY,
TRIGGER_EMULATOR_PRIMARY,
TRIGGER_EMULATOR_SECONDARY,
SPARKOUT_1_OUTPUT,
SPARKOUT_2_OUTPUT,
@ -119,7 +119,7 @@ int getElectricalValue(int logicalValue, pin_output_mode_e mode);
int getOutputPinValue(io_pin_e pin);
void setDefaultPinState(io_pin_e pin, pin_output_mode_e *defaultState);
void outputPinRegisterExt2(char *msg, io_pin_e ioPin, brain_pin_e brainPin, pin_output_mode_e *outputMode);
void outputPinRegisterExt2(const char *msg, io_pin_e ioPin, brain_pin_e brainPin, pin_output_mode_e *outputMode);
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@ -84,6 +84,12 @@ typedef enum {
Internal_ForceMyEnumIntSize_trigger_type = ENUM_SIZE_HACK,
} trigger_type_e;
typedef enum {
SHAFT_PRIMARY_UP = 0,
SHAFT_PRIMARY_DOWN = 1,
SHAFT_SECONDARY_UP = 2,
SHAFT_SECONDARY_DOWN = 3,
} ShaftEvents;
/**
* This enum is used to select your desired Engine Load calculation algorithm

View File

@ -22,10 +22,6 @@
#include "signal_executor_sleep.h"
#endif /* EFI_SIGNAL_EXECUTOR_SLEEP */
#if EFI_SIGNAL_EXECUTOR_SINGLE_TIMER
#include "signal_executor_single_timer.h"
#endif /* EFI_SIGNAL_EXECUTOR_SINGLE_TIMER */
typedef void (*schfunc_t)(void *);
typedef struct scheduling_struct scheduling_s;
@ -34,9 +30,6 @@ struct scheduling_struct {
#if EFI_SIGNAL_EXECUTOR_SLEEP
VirtualTimer timer;
#endif /* EFI_SIGNAL_EXECUTOR_SLEEP */
#if EFI_SIGNAL_EXECUTOR_SINGLE_TIMER
volatile time_t moment;
#endif /* EFI_SIGNAL_EXECUTOR_SINGLE_TIMER */
volatile uint64_t momentUs;
#if EFI_SIGNAL_EXECUTOR_ONE_TIMER

View File

@ -66,7 +66,7 @@ void resetWaveChart(WaveChart *chart) {
appendPrintf(&chart->logging, "wave_chart%s", DELIMETER);
}
static char LOGGING_BUFFER[5000] __attribute__((section(".ccm")));
static char WAVE_LOGGING_BUFFER[5000] __attribute__((section(".ccm")));
static void printStatus(void) {
scheduleIntValue(&logger, "chart", isChartActive);
@ -109,7 +109,7 @@ void publishChart(WaveChart *chart) {
/**
* @brief Register a change in sniffed signal
*/
void addWaveChartEvent3(WaveChart *chart, char *name, char * msg, char * msg2) {
void addWaveChartEvent3(WaveChart *chart, const char *name, const char * msg, const char * msg2) {
chDbgCheck(chart->isInitialized, "chart not initialized");
#if DEBUG_WAVE
scheduleSimpleMsg(&debugLogging, "current", chart->counter);
@ -132,7 +132,7 @@ void initWaveChart(WaveChart *chart) {
printStatus();
initLoggingExt(&chart->logging, "wave chart", LOGGING_BUFFER, sizeof(LOGGING_BUFFER));
initLoggingExt(&chart->logging, "wave chart", WAVE_LOGGING_BUFFER, sizeof(WAVE_LOGGING_BUFFER));
chart->isInitialized = TRUE;
#if DEBUG_WAVE
initLoggingExt(&debugLogging, "wave chart debug", &debugLogging.DEFAULT_BUFFER, sizeof(debugLogging.DEFAULT_BUFFER));

View File

@ -31,7 +31,7 @@ extern "C"
{
#endif /* __cplusplus */
void addWaveChartEvent3(WaveChart *chart, char *name, char *msg, char *msg2);
void addWaveChartEvent3(WaveChart *chart, const char *name, const char *msg, const char *msg2);
void publishChart(WaveChart *chart);
void initWaveChart(WaveChart *chart);
void resetWaveChart(WaveChart *chart);

View File

@ -0,0 +1,62 @@
/**
* @file alternatorController.cpp
* @brief alternator controller - turn alternator off if you do not really need it
*
* @date Apr 6, 2014
* @author Dmitry Sidin
* @author Andrey Belomutskiy (c) 2012-2014
*/
#include "main.h"
#include "rpm_calculator.h"
#include "pwm_generator.h"
#include "wave_math.h"
#include "alternatorController.h"
#include "pin_repository.h"
#include "engine_configuration.h"
#include "voltage.h"
#if 0
extern board_configuration_s *boardConfiguration;
#define ALTERNATOR_VALVE_PWM_FREQUENCY 30000
static PwmConfig alternatorControl;
static WORKING_AREA(ivThreadStack, UTILITY_THREAD_STACK_SIZE);
static msg_t AltCtrlThread(int param) {
chRegSetThreadName("AlternatorController");
int alternatorDutyCycle = 500;
while (TRUE) {
chThdSleepMilliseconds(10);
if ( getVBatt() > 14.2 )
alternatorDutyCycle = alternatorDutyCycle + 1 ;
else
alternatorDutyCycle = alternatorDutyCycle - 1;
if (alternatorDutyCycle < 150 )
alternatorDutyCycle = 150;
if (alternatorDutyCycle > 950)
alternatorDutyCycle = 950;
setSimplePwmDutyCycle(&alternatorControl, 0.001 * alternatorDutyCycle);
}
#if defined __GNUC__
return -1;
#endif
}
void initAlternatorCtrl() {
startSimplePwm(&alternatorControl, "Alternator control",
boardConfiguration->alternatorControlPin,
0.5,
ALTERNATOR_VALVE_PWM_FREQUENCY,
ALTERNATOR_SWITCH
);
chThdCreateStatic(ivThreadStack, sizeof(ivThreadStack), LOWPRIO, (tfunc_t)AltCtrlThread, NULL);
}
#endif

View File

@ -1,15 +1,16 @@
CONTROLLERSSRC = \
controllers/electronic_throttle.c \
controllers/idle_thread.c \
controllers/injector_central.c \
controllers/ignition_central.c \
controllers/flash_main.c \
$(PROJECT_DIR)/controllers/malfunction_indicator.c \
$(PROJECT_DIR)/controllers/error_handling.c \
controllers/map_averaging.c \
controllers/map_multiplier_thread.c \
$(PROJECT_DIR)/controllers/alternatorController.c
controllers/map_multiplier_thread.c
CONTROLLERS_SRC_CPP = $(PROJECT_DIR)/controllers/settings.cpp \
controllers/electronic_throttle.cpp \
controllers/flash_main.cpp \
controllers/injector_central.cpp \
controllers/idle_thread.cpp \
controllers/PwmTester.cpp \
$(PROJECT_DIR)/controllers/alternatorController.cpp \
$(PROJECT_DIR)/controllers/engine_controller.cpp

View File

@ -0,0 +1,97 @@
/**
* @file electronic_throttle.cpp
* @brief Electronic Throttle Module driver L298N
*
* todo: make this more universal if/when we get other hardware options
*
* @date Dec 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 "electronic_throttle.h"
#include "boards.h"
#include "pin_repository.h"
#include "idle_controller.h"
#include "tps.h"
#include "io_pins.h"
#include "engine_configuration.h"
#include "pwm_generator.h"
#include "pwm_generator_logic.h"
#if EFI_ELECTRONIC_THROTTLE_BODY
static Logging logger;
/**
* @brief Control Thread stack
*/
static WORKING_AREA(etbTreadStack, UTILITY_THREAD_STACK_SIZE);
/**
* @brief Pulse-Width Modulation state
*/
static PwmConfig etbPwm;
static float prevTps;
extern engine_configuration_s *engineConfiguration;
extern board_configuration_s *boardConfiguration;
static msg_t etbThread(void *arg) {
while (TRUE) {
int tps = (int)getTPS();
if (tps != prevTps) {
prevTps = tps;
scheduleMsg(&logger, "tps=%d", (int) tps);
}
// this thread is activated 10 times per second
chThdSleepMilliseconds(100);
}
#if defined __GNUC__
return -1;
#endif
}
static void setThrottleConsole(int level) {
scheduleMsg(&logger, "setting throttle=%d", level);
etbPwm.multiWave.switchTimes[0] = 0.01 + (min(level, 98)) / 100.0;
print("st = %f\r\n", etbPwm.multiWave.switchTimes[0]);
}
void initElectronicThrottle(void) {
initLogging(&logger, "Electronic Throttle");
engineConfiguration->tpsMin = 140;
engineConfiguration->tpsMax = 898;
// these two lines are controlling direction
// outputPinRegister("etb1", ELECTRONIC_THROTTLE_CONTROL_1, ETB_CONTROL_LINE_1_PORT, ETB_CONTROL_LINE_1_PIN);
// outputPinRegister("etb2", ELECTRONIC_THROTTLE_CONTROL_2, ETB_CONTROL_LINE_2_PORT, ETB_CONTROL_LINE_2_PIN);
// this line used for PWM
startSimplePwm(&etbPwm, "etb",
boardConfiguration->electronicThrottlePin1,
ELECTRONIC_THROTTLE_CONTROL_1,
0.80,
500);
addConsoleActionI("e", setThrottleConsole);
chThdCreateStatic(etbTreadStack, sizeof(etbTreadStack), NORMALPRIO, (tfunc_t) etbThread, NULL);
}
#endif /* EFI_ELECTRONIC_THROTTLE_BODY */

View File

@ -48,6 +48,9 @@
#include "adc_inputs.h"
#include "algo.h"
#include "efilib2.h"
#include "ec2.h"
#include "PwmTester.h"
#define _10_MILLISECONDS (10 * TICKS_IN_MS)
@ -182,7 +185,7 @@ static void fuelPumpOn(ShaftEvents signal, int index) {
}
static void initFuelPump(void) {
registerShaftPositionListener(&fuelPumpOn, "fuel pump");
addTriggerEventListener(&fuelPumpOn, "fuel pump");
fuelPumpOn(SHAFT_PRIMARY_UP, 0);
}
@ -194,13 +197,13 @@ char * getPinNameByAdcChannel(int hwChannel, uint8_t *buffer) {
static uint8_t pinNameBuffer[16];
static void printAnalogChannelInfoExt(char *name, int hwChannel,
static void printAnalogChannelInfoExt(const 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) {
static void printAnalogChannelInfo(const char *name, int hwChannel) {
printAnalogChannelInfoExt(name, hwChannel, getVoltageDivided(hwChannel));
}
@ -247,10 +250,8 @@ void initEngineContoller(void) {
chThdCreateStatic(csThreadStack, sizeof(csThreadStack), LOWPRIO,
(tfunc_t) csThread, NULL);
#if EFI_SIGNAL_EXECUTOR_SINGLE_TIMER
initOutputScheduler();
#endif
initInjectorCentral();
initPwmTester();
initIgnitionCentral();
initMalfunctionCentral();

View File

@ -0,0 +1,115 @@
/**
* @file flash_main.c
* @brief Higher-level logic of saving data into internal flash memory
*
*
* @date Sep 19, 2013
* @author Andrey Belomutskiy, (c) 2012-2014
*/
#include <ch.h>
#include <hal.h>
#include <string.h>
#include "flash_main.h"
#include "eficonsole.h"
#include "flash.h"
#include "rusefi.h"
//#include "tunerstudio.h"
#include "engine_controller.h"
#include "datalogging.h"
#include "audi_aan.h"
#include "dodge_neon.h"
#include "ford_aspire.h"
#include "ford_fiesta.h"
#include "ford_1995_inline_6.h"
#include "snow_blower.h"
#include "nissan_primera.h"
#include "honda_accord.h"
#include "GY6_139QMB.h"
#include "ec2.h"
static engine_type_e defaultEngineType = FORD_ASPIRE_1996;
static Logging logger;
#if defined __GNUC__
FlashState flashState __attribute__((section(".ccm")));
#else
FlashState flashState;
#endif
engine_configuration_s *engineConfiguration = &flashState.persistentConfiguration.engineConfiguration;
board_configuration_s *boardConfiguration = &flashState.persistentConfiguration.boardConfiguration;
extern engine_configuration2_s * engineConfiguration2;
#define FLASH_ADDR 0x08060000
#define FLASH_USAGE sizeof(FlashState)
crc flashStateCrc(FlashState *state) {
return calc_crc((const crc*) &state->persistentConfiguration, sizeof(persistent_config_s));
}
void writeToFlash(void) {
flashState.version = FLASH_DATA_VERSION;
scheduleMsg(&logger, "FLASH_DATA_VERSION=%d", flashState.version);
crc result = flashStateCrc(&flashState);
flashState.value = result;
scheduleMsg(&logger, "Reseting flash=%d", FLASH_USAGE);
flashErase(FLASH_ADDR, FLASH_USAGE);
scheduleMsg(&logger, "Flashing with CRC=%d", result);
efitimems_t nowMs = currentTimeMillis();
result = flashWrite(FLASH_ADDR, (const char *) &flashState, FLASH_USAGE);
scheduleMsg(&logger, "Flash programmed in (ms): %d", currentTimeMillis() - nowMs);
scheduleMsg(&logger, "Flashed: %d", result);
}
static int isValidCrc(FlashState *state) {
if (state->version != FLASH_DATA_VERSION) {
scheduleMsg(&logger, "Unexpected flash version: %d", state->version);
return FALSE;
}
crc result = flashStateCrc(state);
int isValidCrc = result == state->value;
if (!isValidCrc)
scheduleMsg(&logger, "CRC got %d while %d expected", result, state->value);
return isValidCrc;
}
static void doResetConfiguration(void) {
resetConfigurationExt(engineConfiguration->engineType, engineConfiguration, engineConfiguration2, boardConfiguration);
}
static void readFromFlash(void) {
flashRead(FLASH_ADDR, (char *) &flashState, FLASH_USAGE);
setDefaultNonPersistentConfiguration(engineConfiguration2);
if (!isValidCrc(&flashState)) {
scheduleMsg(&logger, "Need to reset flash to default");
resetConfigurationExt(defaultEngineType, engineConfiguration, engineConfiguration2, boardConfiguration);
} else {
scheduleMsg(&logger, "Got valid configuration from flash!");
applyNonPersistentConfiguration(engineConfiguration, engineConfiguration2, engineConfiguration->engineType);
}
// we can only change the state after the CRC check
engineConfiguration->firmwareVersion = getRusEfiVersion();
}
void initFlash(void) {
initLogging(&logger, "Flash memory");
print("initFlash()\r\n");
addConsoleAction("readconfig", readFromFlash);
addConsoleAction("writeconfig", writeToFlash);
addConsoleAction("resetconfig", doResetConfiguration);
readFromFlash();
}

View File

@ -0,0 +1,144 @@
/**
* @file idle_thread.cpp
* @brief Idle Air Control valve thread.
*
* This thread looks at current RPM and decides if it should increase or decrease IAC duty cycle.
* This file is has the hardware & scheduling logic, desired idle level lives separately
*
*
* @date May 23, 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 "idle_controller.h"
#include "rpm_calculator.h"
#include "pwm_generator.h"
#include "wave_math.h"
#include "idle_thread.h"
#include "pin_repository.h"
#include "engine_configuration.h"
#define IDLE_AIR_CONTROL_VALVE_PWM_FREQUENCY 200
static WORKING_AREA(ivThreadStack, UTILITY_THREAD_STACK_SIZE);
static volatile int isIdleControlActive = EFI_IDLE_CONTROL;
extern board_configuration_s *boardConfiguration;
/**
* here we keep the value we got from IDLE SWITCH input
*/
static volatile int idleSwitchState;
static Logging logger;
static float _switchTimes[PWM_PHASE_MAX_COUNT];
// todo: extract helper for simple PWM?
static int pinStates[2];
static single_wave_s wave(pinStates);
static single_wave_s sr[1] = {wave};
static PwmConfig idleValve(_switchTimes, sr);
/**
* Idle level calculation algorithm lives in idle_controller.c
*/
static IdleValveState idle;
int getIdleSwitch() {
return idleSwitchState;
}
void idleDebug(char *msg, int value) {
printMsg(&logger, "%s%d", msg, value);
scheduleLogging(&logger);
}
static void setIdleControlEnabled(int value) {
isIdleControlActive = value;
scheduleMsg(&logger, "isIdleControlActive=%d", isIdleControlActive);
}
static void setIdleValvePwm(int value) {
// todo: change parameter type, maybe change parameter validation?
if (value < 1 || value > 999)
return;
scheduleMsg(&logger, "setting idle valve PWM %d", value);
/**
* currently IDEL level is an integer per mil (0-1000 range), and PWM takes a fioat in the 0..1 range
* todo: unify?
*/
setSimplePwmDutyCycle(&idleValve, 0.001 * value);
}
static msg_t ivThread(int param) {
chRegSetThreadName("IdleValve");
int currentIdleValve = -1;
while (TRUE) {
chThdSleepMilliseconds(100);
// this value is not used yet
idleSwitchState = palReadPad(getHwPort(boardConfiguration->idleSwitchPin), getHwPin(boardConfiguration->idleSwitchPin));
if (!isIdleControlActive)
continue;
int nowSec = getTimeNowSeconds();
int newValue = getIdle(&idle, getRpm(), nowSec);
if (currentIdleValve != newValue) {
currentIdleValve = newValue;
setIdleValvePwm(newValue);
}
}
#if defined __GNUC__
return -1;
#endif
}
static void setIdleRpmAction(int value) {
setIdleRpm(&idle, value);
scheduleMsg(&logger, "target idle RPM %d", value);
}
void startIdleThread() {
initLogging(&logger, "Idle Valve Control");
startSimplePwm(&idleValve, "Idle Valve",
boardConfiguration->idleValvePin,
IDLE_VALVE,
0.5,
IDLE_AIR_CONTROL_VALVE_PWM_FREQUENCY,
TRUE);
idleInit(&idle);
scheduleMsg(&logger, "initial idle %d", idle.value);
chThdCreateStatic(ivThreadStack, sizeof(ivThreadStack), NORMALPRIO, (tfunc_t)ivThread, NULL);
// this is idle switch INPUT - sometimes there is a switch on the throttle pedal
// this switch is not used yet
mySetPadMode("idle switch", getHwPort(boardConfiguration->idleSwitchPin), getHwPin(boardConfiguration->idleSwitchPin), PAL_MODE_INPUT);
addConsoleActionI("set_idle_rpm", setIdleRpmAction);
addConsoleActionI("set_idle_pwm", setIdleValvePwm);
addConsoleActionI("set_idle_enabled", setIdleControlEnabled);
}

View File

@ -0,0 +1,167 @@
/**
* @file injector_central.c
* @brief Utility methods related to fuel injection.
*
*
* @date Sep 8, 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 "injector_central.h"
#include "main.h"
#include "engines.h"
#include "io_pins.h"
#include "signal_executor.h"
#include "main_trigger_callback.h"
#include "engine_configuration.h"
#include "pin_repository.h"
#include "ec2.h"
static Logging logger;
extern engine_configuration_s *engineConfiguration;
extern engine_configuration2_s *engineConfiguration2;
extern board_configuration_s *boardConfiguration;
static int is_injector_enabled[MAX_INJECTOR_COUNT];
int isInjectionEnabled(void) {
return engineConfiguration2->isInjectionEnabledFlag;
}
void assertCylinderId(int cylinderId, char *msg) {
int isValid = cylinderId >= 1 && cylinderId <= engineConfiguration->cylindersCount;
if (!isValid) {
// we are here only in case of a fatal issue - at this point it is fine to make some blocking i-o
//scheduleSimpleMsg(&logger, "cid=", cylinderId);
print("ERROR [%s] cid=%d\r\n", msg, cylinderId);
chDbgAssert(TRUE, "Cylinder ID", null);
}
}
///**
// * This method schedules asynchronous fuel squirt
// */
/**
* @param cylinderId - from 1 to NUMBER_OF_CYLINDERS
*/
int isInjectorEnabled(int cylinderId) {
assertCylinderId(cylinderId, "isInjectorEnabled");
return is_injector_enabled[cylinderId - 1];
}
static void printStatus(void) {
for (int id = 1; id <= engineConfiguration->cylindersCount; id++) {
resetLogging(&logger);
appendPrintf(&logger, "injector%d%s", id, DELIMETER);
appendPrintf(&logger, "%d", isInjectorEnabled(id));
appendPrintf(&logger, DELIMETER);
scheduleLogging(&logger);
}
}
static void setInjectorEnabled(int id, int value) {
chDbgCheck(id >= 0 && id < engineConfiguration->cylindersCount, "injector id");
is_injector_enabled[id] = value;
printStatus();
}
void runBench(brain_pin_e brainPin, io_pin_e pin, float onTime, float offTime, int count) {
scheduleMsg(&logger, "Running bench: ON_TIME=%f ms OFF_TIME=%fms Counter=%d", onTime, offTime, count);
scheduleMsg(&logger, "output on %s", hwPortname(brainPin));
for (int i = 0; i < count; i++) {
setOutputPinValue(pin, TRUE);
chThdSleep((int) (onTime * CH_FREQUENCY / 1000));
setOutputPinValue(pin, FALSE);
chThdSleep((int) (offTime * CH_FREQUENCY / 1000));
}
scheduleMsg(&logger, "Done!");
}
static volatile int needToRunBench = FALSE;
float onTime;
float offTime;
int count;
brain_pin_e brainPin;
io_pin_e pin;
static void fuelbench(char * onStr, char *offStr, char *countStr) {
onTime = atoff(onStr);
offTime = atoff(offStr);
count = atoi(countStr);
brainPin = boardConfiguration->injectionPins[0];
pin = INJECTOR_1_OUTPUT;
needToRunBench = TRUE;
}
static void sparkbench(char * onStr, char *offStr, char *countStr) {
onTime = atoff(onStr);
offTime = atoff(offStr);
count = atoi(countStr);
brainPin = boardConfiguration->ignitionPins[0];
pin = SPARKOUT_1_OUTPUT;
needToRunBench = TRUE;
}
static WORKING_AREA(benchThreadStack, UTILITY_THREAD_STACK_SIZE);
static msg_t benchThread(int param) {
chRegSetThreadName("BenchThread");
while (TRUE) {
while (!needToRunBench) {
chThdSleepMilliseconds(50);
}
needToRunBench = FALSE;
runBench(brainPin, pin, onTime, offTime, count);
}
return 0;
}
void initInjectorCentral(void) {
initLogging(&logger, "InjectorCentral");
chThdCreateStatic(benchThreadStack, sizeof(benchThreadStack), NORMALPRIO, (tfunc_t) benchThread, NULL);
for (int i = 0; i < engineConfiguration->cylindersCount; i++)
is_injector_enabled[i] = true;
printStatus();
// todo: should we move this code closer to the injection logic?
// todo: dynamic initialization
// todo: consider actual cylinders count
outputPinRegisterExt2("injector1", INJECTOR_1_OUTPUT, boardConfiguration->injectionPins[0],
&boardConfiguration->injectionPinMode);
outputPinRegisterExt2("injector2", INJECTOR_2_OUTPUT, boardConfiguration->injectionPins[1],
&boardConfiguration->injectionPinMode);
outputPinRegisterExt2("injector3", INJECTOR_3_OUTPUT, boardConfiguration->injectionPins[2],
&boardConfiguration->injectionPinMode);
outputPinRegisterExt2("injector4", INJECTOR_4_OUTPUT, boardConfiguration->injectionPins[3],
&boardConfiguration->injectionPinMode);
outputPinRegisterExt2("injector5", INJECTOR_5_OUTPUT, boardConfiguration->injectionPins[4],
&boardConfiguration->injectionPinMode);
outputPinRegisterExt2("injector5", INJECTOR_6_OUTPUT, boardConfiguration->injectionPins[5],
&boardConfiguration->injectionPinMode);
addConsoleActionII("injector", setInjectorEnabled);
addConsoleActionSSS("fuelbench", &fuelbench);
addConsoleActionSSS("sparkbench", &sparkbench);
}

View File

@ -149,6 +149,6 @@ float getMap(void) {
void initMapAveraging(void) {
initLogging(&logger, "Map Averaging");
registerShaftPositionListener(&shaftPositionCallback, "rpm reporter");
addTriggerEventListener(&shaftPositionCallback, "rpm reporter");
addConsoleAction("faststat", showMapStats);
}

View File

@ -232,12 +232,6 @@ float getSparkDwellMsT(engine_configuration_s *engineConfiguration, int rpm) {
return getOneDegreeTimeMs(rpm) * angle;
}
if (rpm > engineConfiguration->rpmHardLimit) {
// technically this could be implemented via interpolate2d by setting everything above rpmHardLimit to zero
warning(OBD_PCM_Processor_Fault, "skipping spark due to rpm=%d", rpm);
return 0;
}
return interpolate2d(rpm, engineConfiguration->sparkDwellBins, engineConfiguration->sparkDwell, DWELL_CURVE_SIZE);
}
@ -250,19 +244,19 @@ void registerActuatorEventExt(engine_configuration_s const *engineConfiguration,
int triggerIndexOfZeroEvent = s->triggerShapeSynchPointIndex;
// todo: migrate to crankAngleRange?
float firstAngle = s->wave.switchTimes[triggerIndexOfZeroEvent] * 720;
float firstAngle = s->wave.getSwitchTime(triggerIndexOfZeroEvent) * 720;
// let's find the last trigger angle which is less or equal to the desired angle
int i;
for (i = 0; i < s->size - 1; i++) {
// todo: we need binary search here
float angle = fixAngle(s->wave.switchTimes[(triggerIndexOfZeroEvent + i + 1) % s->size] * 720 - firstAngle);
float angle = fixAngle(s->wave.getSwitchTime((triggerIndexOfZeroEvent + i + 1) % s->size) * 720 - firstAngle);
if (angle > angleOffset)
break;
}
// explicit check for zero to avoid issues where logical zero is not exactly zero due to float nature
float angle =
i == 0 ? 0 : fixAngle(s->wave.switchTimes[(triggerIndexOfZeroEvent + i) % s->size] * 720 - firstAngle);
i == 0 ? 0 : fixAngle(s->wave.getSwitchTime((triggerIndexOfZeroEvent + i) % s->size) * 720 - firstAngle);
chDbgCheck(angleOffset >= angle, "angle constraint violation in registerActuatorEventExt()");

View File

@ -15,9 +15,6 @@ extern "C"
{
#endif /* __cplusplus */
int cisnan(float f);
//float getDefaultVE(int rpm);
float getDefaultFuel(int rpm, float map);
@ -35,17 +32,10 @@ float getTriggerEventAngle(int triggerEventIndex);
float getEngineLoadT(engine_configuration_s *engineConfiguration);
#define getEngineLoad() getEngineLoadT(engineConfiguration)
void initializeIgnitionActions(float baseAngle, engine_configuration_s *engineConfiguration, engine_configuration2_s *engineConfiguration2);
void addFuelEvents(engine_configuration_s const *e, engine_configuration2_s *engineConfiguration2, ActuatorEventList *list, injection_mode_e mode);
float getSparkDwellMsT(engine_configuration_s *engineConfiguration, int rpm);
#define getSparkDwellMs(rpm) getSparkDwellMsT(engineConfiguration, rpm)
void registerActuatorEventExt(engine_configuration_s const *engineConfiguration, trigger_shape_s * s, ActuatorEventList *list, OutputSignal *actuator, float angleOffset);
int getCylinderId(firing_order_e firingOrder, int index);
void prepareOutputSignals(engine_configuration_s *engineConfiguration,
engine_configuration2_s *engineConfiguration2);
void setTableBin(float array[], int size, float l, float r);
void setFuelRpmBin(engine_configuration_s *engineConfiguration, float l, float r);

View File

@ -12,6 +12,15 @@
#include "main.h"
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
float getAfr(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

View File

@ -4,6 +4,6 @@ CONTROLLERS_SENSORS_SRC = $(PROJECT_DIR)/controllers/sensors/tps.c \
$(PROJECT_DIR)/controllers/sensors/maf.c \
$(PROJECT_DIR)/controllers/sensors/map.c \
$(PROJECT_DIR)/controllers/sensors/ego.c \
$(PROJECT_DIR)/controllers/sensors/voltage.c \
$(PROJECT_DIR)/controllers/sensors/thermistors.c
$(PROJECT_DIR)/controllers/sensors/voltage.c
CONTROLLERS_SENSORS_SRC_CPP = $(PROJECT_DIR)/controllers/sensors/thermistors.cpp

View File

@ -0,0 +1,169 @@
/**
* @file thermistors.c
*
* @date Feb 17, 2013
* @author Andrey Belomutskiy, (c) 2012-2014
*/
/**
* http://en.wikipedia.org/wiki/Thermistor
* http://en.wikipedia.org/wiki/Steinhart%E2%80%93Hart_equation
*/
#include "main.h"
#include "thermistors.h"
#include "adc_inputs.h"
#include "engine_configuration.h"
#include "engine_math.h"
#include "ec2.h"
extern engine_configuration_s *engineConfiguration;
extern engine_configuration2_s *engineConfiguration2;
static bool_t initialized = FALSE;
/**
* http://en.wikipedia.org/wiki/Voltage_divider
*/
float getR1InVoltageDividor(float Vout, float Vin, float r2) {
return r2 * Vin / Vout - r2;
}
float getR2InVoltageDividor(float Vout, float Vin, float r1) {
if (Vout == 0)
return NAN;
return r1 / (Vin / Vout - 1);
}
float getVoutInVoltageDividor(float Vin, float r1, float r2) {
return r2 * Vin / (r1 + r2);
}
float convertResistanceToKelvinTemperature(float resistance, ThermistorConf *thermistor) {
if (resistance <= 0) {
//warning("Invalid resistance in convertResistanceToKelvinTemperature=", resistance);
return 0;
}
float logR = log(resistance);
return 1 / (thermistor->s_h_a + thermistor->s_h_b * logR + thermistor->s_h_c * logR * logR * logR);
}
float convertKelvinToC(float tempK) {
return tempK - KELV;
}
float convertCelciustoKelvin(float tempC) {
return tempC + KELV;
}
float convertCelciustoF(float tempC) {
return tempC * 9 / 5 + 32;
}
float convertFtoCelcius(float tempF) {
return (tempF - 32) / 9 * 5;
}
float convertKelvinToFahrenheit(float kelvin) {
float tempC = convertKelvinToC(kelvin);
return convertCelciustoF(tempC);
}
float getKelvinTemperature(float resistance, ThermistorConf *thermistor) {
chDbgCheck(thermistor!=NULL, "thermistor pointer is NULL");
float kelvinTemperature = convertResistanceToKelvinTemperature(resistance, thermistor);
return kelvinTemperature;
}
float getResistance(Thermistor *thermistor) {
float voltage = getVoltageDivided(thermistor->channel);
chDbgCheck(thermistor->config != NULL, "config is null");
float resistance = getR2InVoltageDividor(voltage, _5_VOLTS, thermistor->config->bias_resistor);
return resistance;
}
float getTemperatureC(Thermistor *thermistor) {
chDbgCheck(initialized, "initialized");
float resistance = getResistance(thermistor);
float kelvinTemperature = getKelvinTemperature(resistance, thermistor->config);
return convertKelvinToC(kelvinTemperature);
}
int isValidCoolantTemperature(float temperature) {
// I hope magic constants are appropriate here
return !cisnan(temperature) && temperature > -50 && temperature < 250;
}
int isValidIntakeAirTemperature(float temperature) {
// I hope magic constants are appropriate here
return !cisnan(temperature) && temperature > -50 && temperature < 100;
}
/**
* @return coolant temperature, in Celcius
*/
float getCoolantTemperature(void) {
float temperature = getTemperatureC(&engineConfiguration2->clt);
if (!isValidCoolantTemperature(temperature))
return NAN;
return temperature;
}
void setThermistorConfiguration(ThermistorConf * tc, float tempC1, float r1, float tempC2, float r2, float tempC3,
float r3) {
tc->tempC_1 = tempC1;
tc->resistance_1 = r1;
tc->tempC_2 = tempC2;
tc->resistance_2 = r2;
tc->tempC_3 = tempC3;
tc->resistance_3 = r3;
}
void prepareThermistorCurve(ThermistorConf * config) {
float T1 = config->tempC_1 + KELV;
float T2 = config->tempC_2 + KELV;
float T3 = config->tempC_3 + KELV;
float L1 = log(config->resistance_1);
float L2 = log(config->resistance_2);
float L3 = log(config->resistance_3);
float Y1 = 1 / T1;
float Y2 = 1 / T2;
float Y3 = 1 / T3;
float U2 = (Y2 - Y1) / (L2 - L1);
float U3 = (Y3 - Y1) / (L3 - L1);
config->s_h_c = (U3 - U2) / (L3 - L2) * pow(L1 + L2 + L3, -1);
config->s_h_b = U2 - config->s_h_c * (L1 * L1 + L1 * L2 + L2 * L2);
config->s_h_a = Y1 - (config->s_h_b + L1 * L1 * config->s_h_c) * L1;
}
float getIntakeAirTemperature(void) {
float temperature = getTemperatureC(&engineConfiguration2->iat);
if (!isValidIntakeAirTemperature(temperature)) {
warning(OBD_PCM_Processor_Fault, "unrealistic intake temperature %f", temperature);
return NAN;
}
return temperature;
}
static void initThermistorCurve(Thermistor * t, ThermistorConf *config, int channel) {
prepareThermistorCurve(config);
t->config = config;
t->channel = channel;
}
void initThermistors(void) {
initThermistorCurve(&engineConfiguration2->clt, &engineConfiguration->cltThermistorConf,
engineConfiguration->cltAdcChannel);
initThermistorCurve(&engineConfiguration2->iat, &engineConfiguration->iatThermistorConf,
engineConfiguration->iatAdcChannel);
initialized = TRUE;
}

View File

@ -14,13 +14,14 @@
#include "flash_main.h"
#include "adc_inputs.h"
#include "engine_controller.h"
#include "rusefi.h"
#include "thermistors.h"
#include "adc_inputs.h"
#include "interpolation.h"
#include "tps.h"
#include "ec2.h"
#if EFI_PROD_CODE
#include "rusefi.h"
#include "pin_repository.h"
#endif /* EFI_PROD_CODE */
@ -51,7 +52,7 @@ void printFloatArray(char *prefix, float array[], int size) {
scheduleLogging(&logger);
}
char* getConfigurationName(engine_configuration_s *engineConfiguration) {
const char* getConfigurationName(engine_configuration_s *engineConfiguration) {
switch (engineConfiguration->engineType) {
#if EFI_SUPPORT_DODGE_NEON
case DODGE_NEON_1995:

View File

@ -0,0 +1,134 @@
/*
* @file pwm_generator_logic.c
*
* @date Mar 2, 2014
* @author Andrey Belomutskiy, (c) 2012-2014
*/
#include "pwm_generator_logic.h"
#include "engine_math.h"
PwmConfig::PwmConfig(float *st, single_wave_s *waves) : multiWave(st, waves) {
}
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 periodMs = state->safe.periodMs;
#if DEBUG_PWM
scheduleMsg(&logger, "iteration=%d switchTime=%f period=%f", iteration, switchTime, period);
#endif
uint64_t timeToSwitchUs = (iteration + switchTime) * periodMs * 1000;
#if DEBUG_PWM
scheduleMsg(&logger, "start=%d timeToSwitch=%d", state->safe.start, timeToSwitch);
#endif
return state->safe.startUs + timeToSwitchUs;
}
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->periodMs)) {
/**
* zero period means PWM is paused
*/
return 1;
}
if (state->cycleCallback != NULL)
state->cycleCallback(state);
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.startUs = getTimeNowUs();
state->safe.iteration = 0;
state->safe.periodMs = state->periodMs;
#if DEBUG_PWM
scheduleMsg(&logger, "state reset start=%d iteration=%d", state->safe.start, state->safe.iteration);
#endif
}
}
state->stateChangeCallback(state,
state->safe.phaseIndex == 0 ? state->multiWave.phaseCount - 1 : state->safe.phaseIndex - 1);
uint64_t nextSwitchTimeUs = getNextSwitchTimeUs(state);
#if DEBUG_PWM
scheduleMsg(&logger, "%s: nextSwitchTime %d", state->name, nextSwitchTime);
#endif
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 = 10;
}
state->safe.phaseIndex++;
if (state->safe.phaseIndex == state->multiWave.phaseCount) {
state->safe.phaseIndex = 0; // restart
state->safe.iteration++;
}
return timeToSwitch;
}
static void timerCallback(PwmConfig *state) {
time_t timeToSleepUs = togglePwmState(state);
// parameter here is still in systicks
scheduleTask(&state->scheduling, timeToSleepUs, (schfunc_t) timerCallback, state);
}
/**
* Incoming parameters are potentially just values on current stack, so we have to copy
* into our own permanent storage, right?
*/
void copyPwmParameters(PwmConfig *state, int phaseCount, float *switchTimes, int waveCount, int **pinStates) {
state->multiWave.phaseCount = phaseCount;
for (int phaseIndex = 0; phaseIndex < phaseCount; phaseIndex++) {
state->multiWave.switchTimes[phaseIndex] = switchTimes[phaseIndex];
for (int waveIndex = 0; waveIndex < waveCount; waveIndex++) {
// print("output switch time index (%d/%d) at %f to %d\r\n", phaseIndex,waveIndex,
// switchTimes[phaseIndex], pinStates[waveIndex][phaseIndex]);
state->multiWave.waves[waveIndex].pinStates[phaseIndex] = pinStates[waveIndex][phaseIndex];
}
}
}
void weComplexInit(const char *msg, PwmConfig *state, int phaseCount, float *switchTimes, int waveCount, int **pinStates,
pwm_cycle_callback *cycleCallback, pwm_gen_callback *stateChangeCallback) {
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");
return;
}
if (switchTimes[phaseCount - 1] != 1) {
firmwareError("last switch time has to be 1");
return;
}
chDbgCheck(waveCount > 0, "waveCount should be positive");
checkSwitchTimes2(phaseCount, switchTimes);
state->multiWave.waveCount = waveCount;
copyPwmParameters(state, phaseCount, switchTimes, waveCount, pinStates);
state->cycleCallback = cycleCallback;
state->stateChangeCallback = stateChangeCallback;
state->safe.phaseIndex = 0;
state->safe.periodMs = -1;
state->safe.iteration = -1;
state->name = msg;
timerCallback(state);
}

View File

@ -30,18 +30,21 @@ typedef struct {
int phaseIndex;
} pwm_config_safe_state_s;
typedef struct PwmConfig_struct PwmConfig;
class PwmConfig;
typedef void (pwm_cycle_callback)(PwmConfig *state);
typedef void (pwm_gen_callback)(PwmConfig *state, int stateIndex);
/**
* @brief Multi-channel software PWM output configuration
*/
struct PwmConfig_struct {
class PwmConfig {
public:
PwmConfig(float *switchTimes, single_wave_s *waves);
io_pin_e outputPins[PWM_PHASE_MAX_WAVE_PER_PWM];
multi_wave_s multiWave;
char *name;
const char *name;
/**
* float value of PWM period
* PWM generation is not happening while this value is zero
@ -71,7 +74,7 @@ extern "C"
void copyPwmParameters(PwmConfig *state, int phaseCount, float *switchTimes,
int waveCount, int **pinStates);
void weComplexInit(char *msg, PwmConfig *state,
void weComplexInit(const char *msg, PwmConfig *state,
int phaseCount, float *swithcTimes, int waveCount, int **pinStates,
pwm_cycle_callback *cycleCallback,
pwm_gen_callback *callback);

View File

@ -25,8 +25,8 @@
#include "main.h"
#include "signal_executor.h"
#include "datalogging.h"
#include "rpm_calculator.h"
#include "engine_math.h"
//#include "rpm_calculator.h"
//#include "engine_math.h"
#if EFI_SIGNAL_EXECUTOR_SLEEP || defined(__DOXYGEN__)

View File

@ -1,9 +1,8 @@
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_executor_hw_timer.c
SYSTEMSRC_CPP = $(PROJECT_DIR)/controllers/system/trigger_emulator_algo.cpp \
$(PROJECT_DIR)/controllers/system/pwm_generator_logic.cpp \
$(PROJECT_DIR)/controllers/system/SingleTimerExecutor.cpp

View File

@ -9,25 +9,37 @@
#include "engine_configuration.h"
#include "wave_math.h"
#include "LocalVersionHolder.h"
#include "ec2.h"
extern engine_configuration_s *engineConfiguration;
extern engine_configuration2_s *engineConfiguration2;
#if EFI_PROD_CODE && defined __GNUC__
PwmConfig configuration __attribute__((section(".ccm")));
#else
PwmConfig configuration;
#endif
/*
* todo: should we simply re-use instances used by trigger_decoder?
* todo: since we are emulating same shape we are decoding
*/
static int pinStates1[PWM_PHASE_MAX_COUNT];
static int pinStates2[PWM_PHASE_MAX_COUNT];
static single_wave_s waves[2] = {single_wave_s(pinStates1), single_wave_s(pinStates2)};
static single_wave_s sr[2] = {waves[0], waves[1]};
static float swtchTms[PWM_PHASE_MAX_COUNT];
PwmConfig triggerSignal(swtchTms, sr);
static Logging logger;
static LocalVersionHolder localVersion;
void setTriggerEmulatorRPM(int rpm) {
/**
* All we need to do here is to change the periodMs
* togglePwmState() would see that the periodMs has changed and act accordingly
*/
if (rpm == 0) {
configuration.periodMs = NAN;
triggerSignal.periodMs = NAN;
} else {
float gRpm = rpm * engineConfiguration->rpmMultiplier / 60.0; // per minute converted to per second
configuration.periodMs = frequency2period(gRpm);
triggerSignal.periodMs = frequency2period(gRpm);
}
scheduleMsg(&logger, "Emulating position sensor(s). RPM=%d", rpm);
}
@ -50,7 +62,7 @@ void initTriggerEmulatorLogic(pwm_gen_callback *stateChangeCallback) {
trigger_shape_s *s = &engineConfiguration2->triggerShape;
setTriggerEmulatorRPM(DEFAULT_EMULATION_RPM);
int *pinStates[2] = {s->wave.waves[0].pinStates, s->wave.waves[1].pinStates};
weComplexInit("position sensor", &configuration, s->size, s->wave.switchTimes, 2, pinStates,
weComplexInit("position sensor", &triggerSignal, s->size, s->wave.switchTimes, 2, pinStates,
updateTriggerShapeIfNeeded,
stateChangeCallback);

View File

@ -23,6 +23,7 @@
#include "main.h"
#include "main_trigger_callback.h"
#include "ec2.h"
extern "C" {
//#include "settings.h"
@ -66,16 +67,6 @@ static Logging logger;
static ActuatorEventList events;
static void handleFuelInjectionEvent(ActuatorEvent *event, int rpm) {
// int cylinderId = event->actuatorId;
// if (cylinderId == 0)
// return; // no cylinder should be fired at this event
// assertCylinderId(cylinderId, "onShaftSignal");
if (rpm > engineConfiguration->rpmHardLimit) {
scheduleMsg(&logger, "RPM above hard limit %d", rpm);
return;
}
float fuelMs = getFuelMs(rpm) * engineConfiguration->globalFuelCorrection;
if (fuelMs < 0) {
scheduleMsg(&logger, "ERROR: negative injectionPeriod %f", fuelMs);
@ -119,8 +110,8 @@ static void handleFuel(int eventIndex) {
}
static void handleSparkEvent(ActuatorEvent *event, int rpm) {
if (rpm == 0)
return;
efiAssert(rpm != 0, "non-zero RPM expected here");
// float advance = getAdvance(rpm, getEngineLoad());
// float sparkAdvanceMs = getOneDegreeTimeMs(rpm) * advance;
@ -129,9 +120,6 @@ static void handleSparkEvent(ActuatorEvent *event, int rpm) {
if (dwellMs < 0)
firmwareError("invalid dwell: %f at %d", dwellMs, rpm);
if (dwellMs <= 0)
return; // hard RPM limit was hit
float sparkDelay = getOneDegreeTimeMs(rpm) * event->angleOffset;
int isIgnitionError = sparkDelay < 0;
ignitionErrorDetection.add(isIgnitionError);
@ -176,10 +164,20 @@ static void onShaftSignal(ShaftEvents ckpSignalType, int eventIndex) {
chDbgCheck(eventIndex < engineConfiguration2->triggerShape.shaftPositionEventCount, "event index");
int rpm = getRpm();
if (rpm == 0) {
// this happens while we just start cranking
// todo: check for 'trigger->is_synchnonized?'
return;
}
if (rpm == NOISY_RPM) {
scheduleMsg(&logger, "noisy trigger");
return;
}
if (rpm > engineConfiguration->rpmHardLimit) {
warning(OBD_PCM_Processor_Fault, "skipping stroke due to rpm=%d", rpm);
return;
}
int beforeCallback = hal_lld_get_counter_value();
if (eventIndex == 0) {
if (localVersion.isOld())
@ -189,7 +187,7 @@ static void onShaftSignal(ShaftEvents ckpSignalType, int eventIndex) {
* TODO: warning. there is a bit of a hack here, todo: improve.
* currently output signals/times signalTimerUp from the previous revolutions could be
* still used because they have crossed the revolution boundary
* but we are already reporpousing the output signals, but everything works because we
* but we are already repurposing the output signals, but everything works because we
* are not affecting that space in memory. todo: use two instances of 'ignitionSignals'
*/
@ -200,11 +198,6 @@ 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);
@ -236,7 +229,7 @@ void initMainEventListener() {
if (!isInjectionEnabled())
printMsg(&logger, "!!!!!!!!!!!!!!!!!!! injection disabled");
registerShaftPositionListener(&onShaftSignal, "main loop");
addTriggerEventListener(&onShaftSignal, "main loop");
}
int isIgnitionTimingError(void) {

View File

@ -0,0 +1,187 @@
/**
* @file rpm_calculator.c
* @brief RPM calculator
*
* Here we listen to position sensor events in order to figure our if engine is currently running or not.
* Actual getRpm() is calculated once per crankshaft revolution, based on the amount of time passed
* since the start of previous shaft revolution.
*
* @date Jan 1, 2013
* @author Andrey Belomutskiy, (c) 2012-2014
*/
#include "main.h"
#include "rpm_calculator.h"
#include "trigger_central.h"
#include "engine_configuration.h"
#include "ec2.h"
#include "engine_math.h"
#if EFI_PROD_CODE || EFI_SIMULATOR
#include "analog_chart.h"
#endif /* EFI_PROD_CODE */
#include "wave_chart.h"
#include "rfiutil.h"
static rpm_s rpmState;
#define UNREALISTIC_RPM 30000
#define TOP_DEAD_CENTER_MESSAGE "r"
extern engine_configuration_s *engineConfiguration;
extern engine_configuration2_s *engineConfiguration2;
extern WaveChart waveChart;
static Logging logger;
/**
* @return true if there was a full shaft revolution within the last second
*/
int isRunning() {
uint64_t nowUs = getTimeNowUs();
return nowUs - rpmState.lastRpmEventTimeUs < US_PER_SECOND;
}
uint64_t getLastRpmEventTime(void) {
return rpmState.lastRpmEventTimeUs;
}
int isCranking(void) {
int rpm = getRpm();
return isCrankingR(rpm);
}
/**
* @return -1 in case of isNoisySignal(), current RPM otherwise
*/
int getRpm() {
if (!isRunning())
return 0;
return rpmState.rpm;
}
/**
* @return Current crankshaft angle, 0 to 720 for four-stroke
*/
float getCrankshaftAngle(uint64_t timeUs) {
uint64_t timeSinceZeroAngle = timeUs - rpmState.lastRpmEventTimeUs;
float cRevolutionTimeMs = getCrankshaftRevolutionTimeMs(rpmState.rpm);
return 360.0 * timeSinceZeroAngle / cRevolutionTimeMs / 1000;
}
int getRevolutionCounter(void) {
return rpmState.revolutionCounter;
}
/**
* Checks for noise on the trigger input line. Noise is detected by an unexpectedly small time gap between
* current and previous trigger input events.
*
* @return TRUE if noise is detected
*/
static int isNoisySignal(rpm_s * rpmState, uint64_t nowUs) {
uint64_t diff = nowUs - rpmState->lastRpmEventTimeUs;
return diff < 1000; // that's 1ms
}
static uint8_t shaft_signal_msg_index[15];
void addWaveChartEvent(char *name, char * msg, char *msg2) {
addWaveChartEvent3(&waveChart, name, msg, msg2);
}
/**
* @brief Shaft position callback used by RPM calculation logic.
*
* This callback is invoked on interrupt thread.
*/
static void shaftPositionCallback(ShaftEvents ckpSignalType, int index) {
itoa10(&shaft_signal_msg_index[1], index);
if (ckpSignalType == SHAFT_PRIMARY_UP) {
addWaveChartEvent("crank", "up", (char*)shaft_signal_msg_index);
} else if (ckpSignalType == SHAFT_PRIMARY_DOWN) {
addWaveChartEvent("crank", "down", (char*)shaft_signal_msg_index);
} else if (ckpSignalType == SHAFT_SECONDARY_UP) {
addWaveChartEvent("crank2", "up", (char*)shaft_signal_msg_index);
} else if (ckpSignalType == SHAFT_SECONDARY_DOWN) {
addWaveChartEvent("crank2", "down", (char*)shaft_signal_msg_index);
}
if (index != 0) {
#if EFI_PROD_CODE || EFI_SIMULATOR
if (engineConfiguration->analogChartMode == AC_TRIGGER)
acAddData(getCrankshaftAngle(getTimeNowUs()), 1000 * ckpSignalType + index);
#endif
return;
}
rpmState.revolutionCounter++;
uint64_t nowUs = getTimeNowUs();
int hadRpmRecently = isRunning();
if (hadRpmRecently) {
if (isNoisySignal(&rpmState, nowUs)) {
// unexpected state. Noise?
rpmState.rpm = NOISY_RPM;
} else {
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)(60 * US_PER_SECOND / engineConfiguration->rpmMultiplier / diff);
rpmState.rpm = rpm > UNREALISTIC_RPM ? NOISY_RPM : rpm;
}
}
rpmState.lastRpmEventTimeUs = nowUs;
#if EFI_PROD_CODE || EFI_SIMULATOR
if (engineConfiguration->analogChartMode == AC_TRIGGER)
acAddData(getCrankshaftAngle(nowUs), index);
#endif
}
static scheduling_s tdcScheduler;
static uint8_t rpmBuffer[10];
static void onTdcCallback(void) {
itoa10(rpmBuffer, getRpm());
addWaveChartEvent(TOP_DEAD_CENTER_MESSAGE, (char*)rpmBuffer, "");
}
static void tdcMarkCallback(ShaftEvents ckpSignalType, int index) {
if (index == 0) {
scheduleByAngle(&tdcScheduler, engineConfiguration->globalTriggerAngleOffset, (schfunc_t) onTdcCallback, NULL);
}
}
void initRpmCalculator(void) {
initLogging(&logger, "rpm calc");
strcpy((char*)shaft_signal_msg_index, "_");
rpmState.rpm = 0;
// we need this initial to have not_running at first invocation
rpmState.lastRpmEventTimeUs = (uint64_t)-10 * US_PER_SECOND;
addTriggerEventListener(&shaftPositionCallback, "rpm reporter");
addTriggerEventListener(&tdcMarkCallback, "chart TDC mark");
}
/**
* Schedules a callback 'angle' degree of crankshaft from now.
* The callback would be executed once after the duration of time which
* it takes the crankshaft to rotate to the specified angle.
*/
void scheduleByAngle(scheduling_s *timer, float angle, schfunc_t callback, void *param) {
float delayMs = getOneDegreeTimeMs(getRpm()) * angle;
scheduleTask(timer, MS2US(delayMs), callback, param);
}

View File

@ -1,11 +1,11 @@
TRIGGER_SRC = \
$(PROJECT_DIR)/controllers/trigger/trigger_central.c \
$(PROJECT_DIR)/controllers/trigger/trigger_mazda.c \
$(PROJECT_DIR)/controllers/trigger/trigger_structure.c \
$(PROJECT_DIR)/controllers/trigger/rpm_calculator.c
TRIGGER_SRC =
TRIGGER_SRC_CPP = \
$(PROJECT_DIR)/controllers/trigger/rpm_calculator.cpp \
$(PROJECT_DIR)/controllers/trigger/trigger_central.cpp \
$(PROJECT_DIR)/controllers/trigger/trigger_mazda.cpp \
$(PROJECT_DIR)/controllers/trigger/trigger_structure.cpp \
$(PROJECT_DIR)/controllers/trigger/trigger_decoder.cpp \
$(PROJECT_DIR)/controllers/trigger/trigger_chrysler.cpp \
$(PROJECT_DIR)/controllers/trigger/trigger_gm.cpp \

View File

@ -0,0 +1,121 @@
/*
* @file trigger_central.c
*
* @date Feb 23, 2014
* @author Andrey Belomutskiy, (c) 2012-2014
*/
#include "main.h"
#include "trigger_central.h"
#include "trigger_decoder.h"
#include "main_trigger_callback.h"
#include "engine_configuration.h"
#include "histogram.h"
#include "rfiutil.h"
#include "listener_array.h"
#include "wave_math.h"
#include "data_buffer.h"
#if defined __GNUC__
static histogram_s triggerCallback __attribute__((section(".ccm")));
#else
static histogram_s triggerCallback;
#endif
extern engine_configuration_s *engineConfiguration;
extern engine_configuration2_s *engineConfiguration2;
// we need this initial to have not_running at first invocation
static volatile uint64_t previousShaftEventTime = (efitimems_t) -10 * US_PER_SECOND;
static IntListenerArray triggerListeneres;
static Logging logging;
static trigger_state_s triggerState;
static volatile int shaftEventCounter;
int getCrankEventCounter() {
return shaftEventCounter;
}
/**
* @brief Adds a trigger event listener
*
* Trigger event listener would be invoked on each trigger event. For example, for a 60/2 wheel
* that would be 116 events: 58 SHAFT_PRIMARY_UP and 58 SHAFT_PRIMARY_DOWN events.
*/
void addTriggerEventListener(ShaftPositionListener handler, char *name) {
print("registerCkpListener: %s\r\n", name);
registerCallback(&triggerListeneres, (IntListener) handler, NULL);
}
#define HW_EVENT_TYPES 4
static int hwEventCounters[HW_EVENT_TYPES];
void hwHandleShaftSignal(ShaftEvents signal) {
chDbgCheck(engineConfiguration!=NULL, "engineConfiguration");
chDbgCheck(engineConfiguration2!=NULL, "engineConfiguration2");
int beforeCallback = hal_lld_get_counter_value();
int eventIndex = (int) signal;
chDbgCheck(eventIndex >= 0 && eventIndex < HW_EVENT_TYPES, "signal type");
hwEventCounters[eventIndex]++;
uint64_t nowUs = getTimeNowUs();
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 = nowUs;
// this is not atomic, but it's fine here
shaftEventCounter++;
/**
* This invocation changes the state of
*/
processTriggerEvent(&triggerState, &engineConfiguration2->triggerShape, &engineConfiguration->triggerConfig, signal,
nowUs);
if (!triggerState.shaft_is_synchronized)
return; // we should not propagate event if we do not know where we are
if (triggerState.current_index >= engineConfiguration2->triggerShape.shaftPositionEventCount) {
int f = warning(OBD_PCM_Processor_Fault, "unexpected eventIndex=%d", triggerState.current_index);
if(!f) {
for (int i = 0; i < HW_EVENT_TYPES; i++)
scheduleMsg(&logging, "event type: %d count=%d", i, hwEventCounters[i]);
}
} else {
/**
* Here we invoke all the listeners - the main engine control logic is inside these listeners
*/
invokeIntIntCallbacks(&triggerListeneres, signal, triggerState.current_index);
}
int afterCallback = hal_lld_get_counter_value();
int diff = afterCallback - beforeCallback;
// this counter is only 32 bits so it overflows every minute, let's ignore the value in case of the overflow for simplicity
if (diff > 0)
hsAdd(&triggerCallback, diff);
}
void printAllCallbacksHistogram(void) {
printHistogram(&logging, &triggerCallback);
}
void initTriggerCentral(void) {
initLogging(&logging, "ShaftPosition");
memset(hwEventCounters, 0, sizeof(hwEventCounters));
initHistogram(&triggerCallback, "all callbacks");
initTriggerDecoder();
clearTriggerState(&triggerState);
}

View File

@ -8,7 +8,7 @@
#ifndef TRIGGER_CENTRAL_H_
#define TRIGGER_CENTRAL_H_
#include "trigger_structure.h"
#include "rusefi_enums.h"
typedef void (*ShaftPositionListener)(ShaftEvents signal, int index);
@ -16,7 +16,7 @@ typedef void (*ShaftPositionListener)(ShaftEvents signal, int index);
extern "C"
{
#endif /* __cplusplus */
void registerShaftPositionListener(ShaftPositionListener handler, char *msg);
void addTriggerEventListener(ShaftPositionListener handler, char *name);
int getCrankEventCounter(void);
int isSignalDecoderError(void);
void hwHandleShaftSignal(ShaftEvents signal);

View File

@ -119,7 +119,8 @@ void processTriggerEvent(trigger_state_s *shaftPositionState, trigger_shape_s co
}
static void initializeSkippedToothTriggerShape(trigger_shape_s *s, int totalTeethCount, int skippedCount) {
triggerShapeInit(s);
efiAssert(s != NULL, "trigger_shape_s is NULL");
s->reset();
float toothWidth = 0.5;
@ -140,8 +141,8 @@ void initializeSkippedToothTriggerShapeExt(engine_configuration2_s *engineConfig
trigger_shape_s *s = &engineConfiguration2->triggerShape;
initializeSkippedToothTriggerShape(s, totalTeethCount, skippedCount);
engineConfiguration2->triggerShape.shaftPositionEventCount = ((totalTeethCount - skippedCount) * 2);
checkSwitchTimes(s->size, s->wave.switchTimes);
s->shaftPositionEventCount = ((totalTeethCount - skippedCount) * 2);
s->wave.checkSwitchTimes(s->size);
}
static void configureFordAspireTriggerShape(trigger_shape_s * s) {
@ -212,10 +213,10 @@ int findTriggerZeroEventIndex(trigger_shape_s const * shape, trigger_config_s co
int loopIndex = i / shape->size;
int time = 10000 * (loopIndex + shape->wave.switchTimes[stateIndex]);
int time = 10000 * (loopIndex + shape->wave.getSwitchTime(stateIndex));
int newPrimaryWheelState = shape->wave.waves[0].pinStates[stateIndex];
int newSecondaryWheelState = shape->wave.waves[1].pinStates[stateIndex];
int newPrimaryWheelState = shape->wave.getChannelState(0, stateIndex);
int newSecondaryWheelState = shape->wave.getChannelState(1, stateIndex);
if (primaryWheelState != newPrimaryWheelState) {
primaryWheelState = newPrimaryWheelState;

View File

@ -17,6 +17,8 @@ extern "C"
#include "trigger_structure.h"
#include "engine_configuration.h"
#include "ec2.h"
int isTriggerDecoderError(void);
void processTriggerEvent(trigger_state_s *shaftPositionState, trigger_shape_s const*triggerShape, trigger_config_s const*triggerConfig, ShaftEvents signal, uint64_t nowUs);

View File

@ -0,0 +1,104 @@
/**
* @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_HIGH);
triggerAddEvent(s, 66, T_SECONDARY, TV_LOW);
triggerAddEvent(s, 70, T_SECONDARY, TV_HIGH);
triggerAddEvent(s, 136, T_SECONDARY, TV_LOW);
triggerAddEvent(s, 140, T_SECONDARY, TV_HIGH);
triggerAddEvent(s, 246, T_SECONDARY, TV_LOW);
triggerAddEvent(s, 250, T_SECONDARY, TV_HIGH);
triggerAddEvent(s, 316, T_SECONDARY, TV_LOW);
triggerAddEvent(s, 320, T_SECONDARY, TV_HIGH);
triggerAddEvent(s, 340, T_PRIMARY, TV_LOW);
triggerAddEvent(s, 360, T_PRIMARY, TV_HIGH);
triggerAddEvent(s, 380, T_PRIMARY, TV_LOW);
triggerAddEvent(s, 400, T_PRIMARY, TV_HIGH);
triggerAddEvent(s, 426, T_SECONDARY, TV_LOW);
triggerAddEvent(s, 430, T_SECONDARY, TV_HIGH);
triggerAddEvent(s, 496, T_SECONDARY, TV_LOW);
triggerAddEvent(s, 500, T_SECONDARY, TV_HIGH);
triggerAddEvent(s, 606, T_SECONDARY, TV_LOW);
triggerAddEvent(s, 610, T_SECONDARY, TV_HIGH);
triggerAddEvent(s, 676, T_SECONDARY, TV_LOW);
triggerAddEvent(s, 680, T_SECONDARY, TV_HIGH);
triggerAddEvent(s, 720, T_PRIMARY, TV_LOW);
s->shaftPositionEventCount = 6 + 16;
}
void configureMazdaProtegeLx(engine_configuration_s *engineConfiguration,
engine_configuration2_s *engineConfiguration2) {
trigger_shape_s *s = &engineConfiguration2->triggerShape;
triggerShapeInit(s);
// s->initialState[0] = 1;
float w = 720 / 4 * 0.215;
float a = 5;
// triggerAddEvent(s, a, T_SECONDARY, TV_LOW);
// triggerAddEvent(s, a + w, T_SECONDARY, TV_HIGH);
// a += 180;
// triggerAddEvent(s, a, T_SECONDARY, TV_LOW);
// triggerAddEvent(s, a + w, T_SECONDARY, TV_HIGH);
// a += 180;
// triggerAddEvent(s, a, T_SECONDARY, TV_LOW);
// triggerAddEvent(s, a + w, T_SECONDARY, TV_HIGH);
// a += 180;
// triggerAddEvent(s, a, T_SECONDARY, TV_LOW);
// triggerAddEvent(s, a + w, T_SECONDARY, TV_HIGH);
float z = 0.093;
a = 180;
triggerAddEvent(s, a - z * 720, T_PRIMARY, TV_HIGH);
triggerAddEvent(s, a, T_PRIMARY, TV_LOW);
a += 180;
triggerAddEvent(s, a - z * 720, T_PRIMARY, TV_HIGH);
triggerAddEvent(s, a, T_PRIMARY, TV_LOW);
a += 180;
triggerAddEvent(s, a - z * 720, T_PRIMARY, TV_HIGH);
triggerAddEvent(s, a, T_PRIMARY, TV_LOW);
a += 180;
triggerAddEvent(s, a - z * 720, T_PRIMARY, TV_HIGH);
triggerAddEvent(s, a, T_PRIMARY, TV_LOW);
// s->shaftPositionEventCount = 2 + 8;
s->shaftPositionEventCount = 8;
engineConfiguration->triggerConfig.isSynchronizationNeeded = FALSE;
}

View File

@ -15,6 +15,8 @@ extern "C"
#include "trigger_structure.h"
#include "engine_configuration.h"
#include "ec2.h"
void initializeMazdaMiataNbShape(trigger_shape_s *s);
void configureMazdaProtegeLx(engine_configuration_s *engineConfiguration,

View File

@ -0,0 +1,111 @@
/**
* @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"
single_wave_s::single_wave_s(int *ps) {
this->pinStates = ps;
}
multi_wave_s::multi_wave_s(float *switchTimes, single_wave_s *waves) {
this->switchTimes = switchTimes;
this->waves = waves;
}
void multi_wave_s::reset(void) {
phaseCount = 0;
waveCount = 0;
}
float multi_wave_s::getSwitchTime(int index) const {
return switchTimes[index];
}
trigger_shape_s::trigger_shape_s() :
wave(switchTimes, h.waves) {
reset();
}
void trigger_shape_s::reset() {
size = 0;
shaftPositionEventCount = 0;
triggerShapeSynchPointIndex = 0;
memset(initialState, 0, sizeof(initialState));
memset(switchTimes, 0, sizeof(switchTimes));
wave.reset();
}
int multi_wave_s::getChannelState(int channelIndex, int phaseIndex) const {
return waves[channelIndex].pinStates[phaseIndex];
}
void multi_wave_s::setSwitchTime(int index, float value) {
switchTimes[index] = value;
}
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) {
// todo: inline & remove method
trigger->reset();
}
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++) {
single_wave_s *wave = &trigger->wave.waves[i];
efiAssert(wave!=NULL, "wave is NULL");
efiAssert(wave->pinStates!=NULL, "wave pinStates is NULL");
wave->pinStates[0] = trigger->initialState[i];
}
trigger->wave.setSwitchTime(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.getChannelState(i, index - 1);
trigger->wave.setSwitchTime(index, angle);
trigger->wave.waves[waveIndex].pinStates[index] = state;
}
void checkSwitchTimes2(int size, float *switchTimes) {
for (int i = 0; i < size - 1; i++)
chDbgCheck(switchTimes[i] < switchTimes[i + 1], "invalid switchTimes");
}
void multi_wave_s::checkSwitchTimes(int size) {
checkSwitchTimes2(size, switchTimes);
}

View File

@ -14,13 +14,6 @@
#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
@ -37,11 +30,20 @@ typedef struct {
/**
* @brief PWM configuration for the specific output pin
*/
typedef struct {
int pinStates[PWM_PHASE_MAX_COUNT];
} single_wave_s;
class single_wave_s {
public:
single_wave_s(int *pinStates);
int *pinStates;
};
typedef struct {
class multi_wave_s {
public:
multi_wave_s(float *st, single_wave_s *waves);
void reset(void);
float getSwitchTime(int phaseIndex) const;
void setSwitchTime(int phaseIndex, float value);
void checkSwitchTimes(int size);
int getChannelState(int channelIndex, int phaseIndex) const;
/**
* Number of events in the cycle
*/
@ -50,13 +52,14 @@ typedef struct {
* Number of signal wires
*/
int waveCount;
single_wave_s waves[PWM_PHASE_MAX_WAVE_PER_PWM];
single_wave_s *waves;
//private:
/**
* 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;
float *switchTimes;
};
typedef enum {
TV_LOW = 0,
@ -68,25 +71,19 @@ typedef enum {
T_SECONDARY = 1
} trigger_wheel_e;
/**
* @brief Trigger wheel(s) configuration
*/
typedef struct {
trigger_type_e triggerType;
class trigger_shape_helper {
int pinStates1[PWM_PHASE_MAX_COUNT];
int pinStates2[PWM_PHASE_MAX_COUNT];
public:
single_wave_s waves[2] = {single_wave_s(pinStates1), single_wave_s(pinStates2)};
};
int isSynchronizationNeeded;
int totalToothCount;
int skippedToothCount;
float syncRatioFrom;
float syncRatioTo;
int useRiseEdge;
} trigger_config_s;
typedef struct {
class trigger_shape_s {
private:
trigger_shape_helper h;
public:
trigger_shape_s();
void reset();
multi_wave_s wave;
int size;
@ -102,9 +99,13 @@ typedef struct {
int initialState[PWM_PHASE_MAX_WAVE_PER_PWM];
int triggerShapeSynchPointIndex;
} trigger_shape_s;
private:
float switchTimes[PWM_PHASE_MAX_COUNT];
};
void checkSwitchTimes2(int size, float *switchTimes);
#ifdef __cplusplus
extern "C"
{
@ -114,8 +115,6 @@ 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);
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@ -22,19 +22,19 @@
extern engine_configuration_s *engineConfiguration;
extern board_configuration_s *boardConfiguration;
extern PwmConfig configuration;
extern PwmConfig triggerSignal;
void initTriggerEmulator(void) {
#if EFI_EMULATE_POSITION_SENSORS
print("Emulating %s\r\n", getConfigurationName(engineConfiguration));
configuration.outputPins[0] = TRIGGER_EMILATOR_PRIMARY;
configuration.outputPins[1] = TRIGGER_EMILATOR_SECONDARY;
triggerSignal.outputPins[0] = TRIGGER_EMULATOR_PRIMARY;
triggerSignal.outputPins[1] = TRIGGER_EMULATOR_SECONDARY;
outputPinRegisterExt2("distributor ch1", configuration.outputPins[0], boardConfiguration->triggerSimulatorPins[0],
outputPinRegisterExt2("distributor ch1", triggerSignal.outputPins[0], boardConfiguration->triggerSimulatorPins[0],
&boardConfiguration->triggerSimulatorPinModes[0]);
outputPinRegisterExt2("distributor ch2", configuration.outputPins[1], boardConfiguration->triggerSimulatorPins[1],
outputPinRegisterExt2("distributor ch2", triggerSignal.outputPins[1], boardConfiguration->triggerSimulatorPins[1],
&boardConfiguration->triggerSimulatorPinModes[1]);
initTriggerEmulatorLogic(applyPinState);

View File

@ -241,7 +241,7 @@ void initWaveAnalyzer(void) {
initWave("input2 E5", 1, &LOGIC_ANALYZER_2_DRIVER, LOGIC_ANALYZER_2_PORT, LOGIC_ANALYZER_2_PIN, 1);
// initWave("input0 C6", 2, &WAVE_TIMER, WAVE_INPUT_PORT, WAVE_INPUT_PIN, 0);
registerShaftPositionListener(&onWaveShaftSignal, "wave analyzer");
addTriggerEventListener(&onWaveShaftSignal, "wave analyzer");
addConsoleActionII("wm", setWaveModeSilent);

View File

@ -2,3 +2,6 @@ svn up
call generate_docs
rem http://www.ncftp.com/download/
cd ../doxygen
ncftpput -u u71977750-docs -p docspass rusefi.com /html html/*

View File

@ -22,6 +22,15 @@
#ifndef BOARD_TEST_H_
#define BOARD_TEST_H_
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
void initBoardTest(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* BOARD_TEST_H_ */

View File

@ -30,7 +30,7 @@
/**
* @brief Initialize the hardware output pin while also assigning it a logical name
*/
void initOutputPinExt(char *msg, OutputPin *outputPin, GPIO_TypeDef *port, uint32_t pinNumber, iomode_t mode) {
void initOutputPinExt(const char *msg, OutputPin *outputPin, GPIO_TypeDef *port, uint32_t pinNumber, iomode_t mode) {
outputPin->currentLogicValue = -1;
outputPin->port = port;
outputPin->pin = pinNumber;
@ -38,7 +38,7 @@ void initOutputPinExt(char *msg, OutputPin *outputPin, GPIO_TypeDef *port, uint3
mySetPadMode(msg, port, pinNumber, mode);
}
void initOutputPin(char *msg, OutputPin *outputPin, GPIO_TypeDef *port, uint32_t pinNumber) {
void initOutputPin(const char *msg, OutputPin *outputPin, GPIO_TypeDef *port, uint32_t pinNumber) {
initOutputPinExt(msg, outputPin, port, pinNumber, PAL_MODE_OUTPUT_PUSHPULL);
}

View File

@ -22,8 +22,8 @@ typedef struct {
int currentLogicValue;
} OutputPin;
void initOutputPin(char *msg, OutputPin *outputPin, GPIO_TypeDef *port, uint32_t pinNumber);
void initOutputPinExt(char *msg, OutputPin *outputPin, GPIO_TypeDef *port, uint32_t pinNumber, iomode_t mode);
void initOutputPin(const char *msg, OutputPin *outputPin, GPIO_TypeDef *port, uint32_t pinNumber);
void initOutputPinExt(const char *msg, OutputPin *outputPin, GPIO_TypeDef *port, uint32_t pinNumber, iomode_t mode);
int getLogicPinValue(OutputPin * outputPin);
void setPinValue(OutputPin * outputPin, int electricalValue, int logicValue);

View File

@ -0,0 +1,171 @@
/**
* @file hardware.c
* @brief Hardware package entry point
*
* @date May 27, 2013
* @author Andrey Belomutskiy, (c) 2012-2014
*/
#include "hardware.h"
#include "pin_repository.h"
#include "io_pins.h"
#include "rtc_helper.h"
#include "rfiutil.h"
#include "adc_inputs.h"
#include "trigger_input.h"
#include "eficonsole.h"
#include "board_test.h"
#include "mcp3208.h"
#include "HIP9011.h"
#include "can_hw.h"
#include "histogram.h"
#include "mmc_card.h"
#include "neo6m.h"
#include "lcd_HD44780.h"
#include "eficonsole_logic.h"
#include "flash_main.h"
#include "trigger_central.h"
#include "svnversion.h"
McpAdcState adcState;
static void initSpiModule(SPIDriver *driver, ioportid_t sckPort, ioportmask_t sckPin, ioportid_t misoPort,
ioportmask_t misoPin, ioportid_t mosiPort, ioportmask_t mosiPin, int af) {
mySetPadMode("SPI clock", sckPort, sckPin, PAL_MODE_ALTERNATE(af));
mySetPadMode("SPI master out", mosiPort, mosiPin, PAL_MODE_ALTERNATE(af));
mySetPadMode("SPI master in ", misoPort, misoPin, PAL_MODE_ALTERNATE(af));
}
void initSpiModules(void) {
#if STM32_SPI_USE_SPI2
// scheduleMsg(&logging, "Turning on SPI2 pins");
initSpiModule(&SPID2,
EFI_SPI2_SCK_PORT, EFI_SPI2_SCK_PIN,
EFI_SPI2_MISO_PORT, EFI_SPI2_MISO_PIN,
EFI_SPI2_MOSI_PORT, EFI_SPI2_MOSI_PIN,
EFI_SPI2_AF);
#endif
#if STM32_SPI_USE_SPI3
// scheduleMsg(&logging, "Turning on SPI3 pins");
initSpiModule(&SPID3,
EFI_SPI3_SCK_PORT, EFI_SPI3_SCK_PIN,
EFI_SPI3_MISO_PORT, EFI_SPI3_MISO_PIN,
EFI_SPI3_MOSI_PORT, EFI_SPI3_MOSI_PIN,
EFI_SPI3_AF);
#endif
}
static I2CConfig i2cfg = { OPMODE_I2C, 100000, STD_DUTY_CYCLE, };
void initI2Cmodule(void) {
print("Starting I2C module\r\n");
i2cInit();
i2cStart(&I2CD1, &i2cfg);
mySetPadMode("I2C clock", EFI_I2C_SCL_PORT, EFI_I2C_SCL_PIN,
PAL_MODE_ALTERNATE(EFI_I2C_AF) | PAL_STM32_OTYPE_OPENDRAIN);
mySetPadMode("I2C data", EFI_I2C_SDA_PORT, EFI_I2C_SDA_PIN,
PAL_MODE_ALTERNATE(EFI_I2C_AF) | PAL_STM32_OTYPE_OPENDRAIN);
}
static char txbuf[1];
static void sendI2Cbyte(int addr, int data) {
// i2cAcquireBus(&I2CD1);
// txbuf[0] = data;
// i2cMasterTransmit(&I2CD1, addr, txbuf, 1, NULL, 0);
// i2cReleaseBus(&I2CD1);
}
void initHardware() {
// todo: enable protection. it's disabled because it takes
// 10 extra seconds to re-flash the chip
//flashProtect();
/**
* histograms is a data structure for CPU monitor, it does not depend on configuration
*/
initHistogramsModule();
/**
* We need the LED_ERROR pin even before we read configuration
*/
initPrimaryPins();
/**
* this call reads configuration from flash memory or sets default configuration
* if flash state does not look right.
*/
initFlash();
initRtc();
initOutputPins();
initAdcInputs();
#if EFI_HIP_9011
initHip9011();
#endif /* EFI_HIP_9011 */
#if EFI_CAN_SUPPORT
initCan();
#endif /* EFI_CAN_SUPPORT */
// init_adc_mcp3208(&adcState, &SPID2);
// requestAdcValue(&adcState, 0);
// todo: figure out better startup logic
initTriggerCentral();
initShaftPositionInputCapture();
initSpiModules();
#if EFI_FILE_LOGGING
initMmcCard();
#endif /* EFI_FILE_LOGGING */
// initFixedLeds();
// initBooleanInputs();
#if EFI_UART_GPS
initGps();
#endif
#if ADC_SNIFFER
initAdcDriver();
#endif
#if EFI_HD44780_LCD
// initI2Cmodule();
lcd_HD44780_init();
char buffer[16];
itoa10((uint8_t*)buffer, SVN_VERSION);
lcd_HD44780_print_string(buffer);
#endif
addConsoleActionII("i2c", sendI2Cbyte);
// while (true) {
// for (int addr = 0x20; addr < 0x28; addr++) {
// sendI2Cbyte(addr, 0);
// int err = i2cGetErrors(&I2CD1);
// print("I2C: err=%x from %d\r\n", err, addr);
// chThdSleepMilliseconds(5);
// sendI2Cbyte(addr, 255);
// chThdSleepMilliseconds(5);
// }
// }
initBoardTest();
}

View File

@ -8,6 +8,14 @@
#ifndef HARDWARE_H_
#define HARDWARE_H_
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
void initHardware(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* HARDWARE_H_ */

View File

@ -1,7 +1,5 @@
HW_LAYERESRC = $(PROJECT_DIR)/hw_layer/hardware.c \
$(PROJECT_DIR)/hw_layer/adc_inputs.c \
$(PROJECT_DIR)/hw_layer/trigger_input.c \
HW_LAYERSRC = $(PROJECT_DIR)/hw_layer/adc_inputs.c \
$(PROJECT_DIR)/hw_layer/pin_repository.c \
$(PROJECT_DIR)/hw_layer/io_pins.c \
$(PROJECT_DIR)/hw_layer/mcp3208.c \
@ -17,6 +15,8 @@ HW_LAYERESRC = $(PROJECT_DIR)/hw_layer/hardware.c \
$(PROJECT_DIR)/hw_layer/neo6m.c \
$(PROJECT_DIR)/hw_layer/gpio_helper.c \
$(PROJECT_DIR)/hw_layer/board_test.c \
$(PROJECT_DIR)/hw_layer/wave_analyzer_hw.c \
$(PROJECT_DIR)/hw_layer/pwm_generator.c
$(PROJECT_DIR)/hw_layer/wave_analyzer_hw.c
HW_LAYER_SRC_CPP = $(PROJECT_DIR)/hw_layer/hardware.cpp \
$(PROJECT_DIR)/hw_layer/pwm_generator.cpp \
$(PROJECT_DIR)/hw_layer/trigger_input.cpp

View File

@ -14,7 +14,7 @@
#include "gpio_helper.h"
#include "status_loop.h"
#include "main_trigger_callback.h"
#include "trigger_decoder.h"
#include "engine_configuration.h"
#include "console_io.h"
extern board_configuration_s *boardConfiguration;
@ -92,6 +92,9 @@ static void comBlinkingThread(void *arg) {
}
}
// todo: fix this, should be a proper declaration in a .h file
int isTriggerDecoderError(void);
static void errBlinkingThread(void *arg) {
chRegSetThreadName("err blinking");
while (TRUE) {
@ -105,7 +108,7 @@ static void errBlinkingThread(void *arg) {
}
}
static void outputPinRegisterExt(char *msg, io_pin_e ioPin, GPIO_TypeDef *port, uint32_t pin, pin_output_mode_e *outputMode) {
static void outputPinRegisterExt(const char *msg, io_pin_e ioPin, GPIO_TypeDef *port, uint32_t pin, pin_output_mode_e *outputMode) {
if (port == GPIO_NULL) {
// that's for GRIO_NONE
outputs[ioPin].port = port;
@ -134,14 +137,14 @@ int getHwPin(brain_pin_e brainPin) {
return brainPin % 16;
}
void outputPinRegisterExt2(char *msg, io_pin_e ioPin, brain_pin_e brainPin, pin_output_mode_e *outputMode) {
void outputPinRegisterExt2(const char *msg, io_pin_e ioPin, brain_pin_e brainPin, pin_output_mode_e *outputMode) {
GPIO_TypeDef *hwPort = getHwPort(brainPin);
int hwPin = getHwPin(brainPin);
outputPinRegisterExt(msg, ioPin, hwPort, hwPin, outputMode);
}
void outputPinRegister(char *msg, io_pin_e ioPin, GPIO_TypeDef *port, uint32_t pin) {
void outputPinRegister(const char *msg, io_pin_e ioPin, GPIO_TypeDef *port, uint32_t pin) {
outputPinRegisterExt(msg, ioPin, port, pin, &DEFAULT_OUTPUT);
}

View File

@ -5,14 +5,23 @@
* @author Andrey Belomutskiy, (c) 2012-2014
*/
#ifndef LCD_2X16_H_
#define LCD_2X16_H_
#ifndef LCD_HD44780_H_
#define LCD_HD44780_H_
extern void lcd_HD44780_init(void);
extern void lcd_HD44780_set_position(uint8_t row, uint8_t column);
extern void lcd_HD44780_print_char(char data);
extern void lcd_HD44780_print_string(char *string);
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
void lcd_HD44780_init(void);
void lcd_HD44780_set_position(uint8_t row, uint8_t column);
void lcd_HD44780_print_char(char data);
void lcd_HD44780_print_string(char *string);
void lcdShowFatalMessage(char *message);
#endif /* LCD_2X16_H_ */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* LCD_HD44780_H_ */

View File

@ -12,7 +12,16 @@
#include "ff.h"
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
void initMmcCard(void);
void appendToLog(char *line);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* MMC_CARD_H_ */

View File

@ -10,7 +10,16 @@
#ifndef NEO6M_H_
#define NEO6M_H_
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
void initGps(void);
float getCurrentSpeed(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* NEO6M_H_ */

View File

@ -18,7 +18,7 @@
#include "rusefi.h"
#define PIN_REPO_SIZE 7 * 16
char *PIN_USED[PIN_REPO_SIZE];
const char *PIN_USED[PIN_REPO_SIZE];
static int initialized = FALSE;
static Logging logger;
@ -63,7 +63,7 @@ static int getPortIndex(GPIO_TypeDef* port) {
static void reportPins(void) {
for (int i = 0; i < PIN_REPO_SIZE; i++) {
char *name = PIN_USED[i];
const char *name = PIN_USED[i];
if (name != NULL)
print("ping %d: %s\r\n", i, name);
}
@ -99,7 +99,7 @@ void initPinRepository(void) {
addConsoleAction("pins", reportPins);
}
static inline void markUsed(int index, char *msg) {
static inline void markUsed(int index, const char *msg) {
PIN_USED[index] = msg;
totalPinsUsed++;
}
@ -107,7 +107,7 @@ static inline void markUsed(int index, char *msg) {
/**
* This method would set an error condition if pin is already used
*/
void mySetPadMode(char *msg, ioportid_t port, ioportmask_t pin, iomode_t mode) {
void mySetPadMode(const char *msg, ioportid_t port, ioportmask_t pin, iomode_t mode) {
if (!initialized)
fatal("repo not initialized");
print("%s on %s:%d\r\n", msg, portname(port), pin);

View File

@ -24,10 +24,10 @@ extern "C"
void initPinRepository(void);
char *hwPortname(brain_pin_e brainPin);
void mySetPadMode(char *msg, ioportid_t port, ioportmask_t pin, iomode_t mode);
void mySetPadMode(const char *msg, ioportid_t port, ioportmask_t pin, iomode_t mode);
char *portname(GPIO_TypeDef* GPIOx);
// does not exactly belong here, but that works better for tests
void outputPinRegister(char *msg, io_pin_e ioPin, GPIO_TypeDef *port, uint32_t pin);
void outputPinRegister(const char *msg, io_pin_e ioPin, GPIO_TypeDef *port, uint32_t pin);
int getHwPin(brain_pin_e brainPin);
GPIO_TypeDef * getHwPort(brain_pin_e brainPin);

View File

@ -0,0 +1,66 @@
/**
* @file pwm_generator.cpp
* @brief software PWM generator
*
* Software PWM implementation. Considering how low all frequencies are, we can totally afford a couple of float multiplications.
* By generating PWM programmatically we are saving the timers for better purposes. This implementation also supports generating
* synchronized waves as needed for example to emulate dual Hall-effect crankshaft position sensors.
*
*
* @date May 28, 2013
* @author Andrey Belomutskiy, (c) 2012-2014
*
*/
#include "pwm_generator.h"
#include "pin_repository.h"
#include "wave_math.h"
#include "datalogging.h"
static Logging logger;
/**
* This method controls the actual hardware pins
*/
void applyPinState(PwmConfig *state, int stateIndex) {
chDbgAssert(state->multiWave.waveCount <= PWM_PHASE_MAX_WAVE_PER_PWM, "invalid waveCount", NULL);
for (int waveIndex = 0; waveIndex < state->multiWave.waveCount; waveIndex++) {
io_pin_e ioPin = state->outputPins[waveIndex];
chDbgAssert(stateIndex < PWM_PHASE_MAX_COUNT, "invalid stateIndex", NULL);
int value = state->multiWave.waves[waveIndex].pinStates[stateIndex];
setOutputPinValue(ioPin, value);
}
}
/**
* @param dutyCycle value between 0 and 1
*/
void setSimplePwmDutyCycle(PwmConfig *state, float dutyCycle) {
state->multiWave.setSwitchTime(0, dutyCycle);
}
void startSimplePwm(PwmConfig *state, const char *msg, brain_pin_e brainPin, io_pin_e ioPin, float dutyCycle,
float frequency, int initPin) {
GPIO_TypeDef * port = getHwPort(brainPin);
int pin = getHwPin(brainPin);
float switchTimes[] = { dutyCycle, 1 };
int pinStates0[] = { 0, 1 };
int *pinStates[1] = { pinStates0 };
state->outputPins[0] = ioPin;
if (initPin)
outputPinRegister(msg, state->outputPins[0], port, pin);
state->periodMs = frequency2period(frequency);
weComplexInit(msg, state, 2, switchTimes, 1, pinStates, NULL, applyPinState);
}
void initPwmGenerator(void) {
initLogging(&logger, "PWM gen");
}

View File

@ -23,8 +23,8 @@ extern "C"
void applyPinState(PwmConfig *state, int stateIndex);
void setSimplePwmDutyCycle(PwmConfig *state, float dutyCycle);
void startSimplePwm(PwmConfig *state, char *msg, brain_pin_e brainPin, io_pin_e ioPin,
float dutyCycle, float frequency);
void startSimplePwm(PwmConfig *state, const char *msg, brain_pin_e brainPin, io_pin_e ioPin,
float dutyCycle, float frequency, int initPin);
void initPwmGenerator(void);
#ifdef __cplusplus

View File

@ -0,0 +1,85 @@
/**
* @file trigger_input.c
* @brief Position sensor hardware layer
*
* @date Dec 30, 2012
* @author Andrey Belomutskiy, (c) 2012-2014
*/
#include "trigger_input.h"
#include "wave_analyzer_hw.h"
#include "pin_repository.h"
#include "trigger_structure.h"
#include "trigger_central.h"
#include "engine_configuration.h"
static WaveReaderHw primaryCrankInput;
static WaveReaderHw secondaryCrankInput;
extern engine_configuration_s *engineConfiguration;
#if EFI_SHAFT_POSITION_INPUT
/**
* that's hardware timer input capture IRQ entry point
* 'width' events happens before the 'period' event
*/
static void shaft_icu_width_callback(ICUDriver *icup) {
int isPrimary = icup == &PRIMARY_SHAFT_POSITION_INPUT_DRIVER;
if (!isPrimary && !engineConfiguration->needSecondTriggerInput)
return;
// icucnt_t last_width = icuGetWidth(icup); so far we are fine with system time
ShaftEvents signal = isPrimary ? SHAFT_PRIMARY_UP : SHAFT_SECONDARY_UP;
hwHandleShaftSignal(signal);
}
static void shaft_icu_period_callback(ICUDriver *icup) {
int isPrimary = icup == &PRIMARY_SHAFT_POSITION_INPUT_DRIVER;
if (!isPrimary && !engineConfiguration->needSecondTriggerInput)
return;
// icucnt_t last_period = icuGetPeriod(icup); so far we are fine with system time
ShaftEvents signal = isPrimary ? SHAFT_PRIMARY_DOWN : SHAFT_SECONDARY_DOWN;
hwHandleShaftSignal(signal);
}
/**
* the main purpose of this configuration structure is to specify the input interrupt callbacks
*/
static ICUConfig shaft_icucfg = { ICU_INPUT_ACTIVE_LOW, 100000, /* 100kHz ICU clock frequency. */
shaft_icu_width_callback, shaft_icu_period_callback };
#endif
void initShaftPositionInputCapture(void) {
#if EFI_SHAFT_POSITION_INPUT
// initialize primary Input Capture Unit pin
initWaveAnalyzerDriver(&primaryCrankInput, &PRIMARY_SHAFT_POSITION_INPUT_DRIVER, PRIMARY_SHAFT_POSITION_INPUT_PORT,
PRIMARY_SHAFT_POSITION_INPUT_PIN);
/**
* Start primary Input Capture Unit using given configuration
* @see shaft_icucfg for callback entry points
*/
shaft_icucfg.channel = PRIMARY_SHAFT_POSITION_INPUT_CHANNEL;
print("initShaftPositionInputCapture 1 %s:%d\r\n", portname(PRIMARY_SHAFT_POSITION_INPUT_PORT),
PRIMARY_SHAFT_POSITION_INPUT_PIN);
icuStart(&PRIMARY_SHAFT_POSITION_INPUT_DRIVER, &shaft_icucfg);
icuEnable(&PRIMARY_SHAFT_POSITION_INPUT_DRIVER);
// initialize secondary Input Capture Unit pin
initWaveAnalyzerDriver(&secondaryCrankInput, &SECONDARY_SHAFT_POSITION_INPUT_DRIVER,
SECONDARY_SHAFT_POSITION_INPUT_PORT,
SECONDARY_SHAFT_POSITION_INPUT_PIN);
shaft_icucfg.channel = SECONDARY_SHAFT_POSITION_INPUT_CHANNEL;
print("initShaftPositionInputCapture 2 %s:%d\r\n", portname(SECONDARY_SHAFT_POSITION_INPUT_PORT),
SECONDARY_SHAFT_POSITION_INPUT_PIN);
icuStart(&SECONDARY_SHAFT_POSITION_INPUT_DRIVER, &shaft_icucfg);
icuEnable(&SECONDARY_SHAFT_POSITION_INPUT_DRIVER);
#else
print("crank input disabled\r\n");
#endif
}

View File

@ -9,6 +9,15 @@
#ifndef CRANK_INPUT_H_
#define CRANK_INPUT_H_
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
void initShaftPositionInputCapture(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* CRANK_INPUT_H_ */

View File

@ -22,8 +22,17 @@ typedef struct {
IntListenerArray periodListeners;
} WaveReaderHw;
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
void initWaveAnalyzerDriver(WaveReaderHw *hw, ICUDriver *driver,
ioportid_t port, int pin);
void setWaveReaderMode(WaveReaderHw *hw, int mode);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* WAVE_ANALYZER_HW_H_ */

View File

@ -89,6 +89,8 @@ extern "C" {
#include "eficonsole.h"
#include "hardware.h"
#include "engine_controller.h"
#include "ec2.h"
#include "trigger_structure.h"
#include "lcd_HD44780.h"
#include "status_loop.h"
#include "pin_repository.h"
@ -274,5 +276,5 @@ void firmwareError(const char *fmt, ...) {
}
int getRusEfiVersion(void) {
return 20140424;
return 20140429;
}

View File

@ -9,7 +9,6 @@
#define RUSEFI_H_
void runRusEfi(void);
int getRusEfiVersion(void);
void scheduleReset(void);
#ifdef __cplusplus

View File

@ -1,4 +1,4 @@
// This file was generated by Version2Header
#ifndef SVN_VERSION
#define SVN_VERSION 2772
#define SVN_VERSION 2936
#endif

View File

@ -0,0 +1,2 @@
rem Let's regemerate 'svnversion.h'
java -jar ../java_tools/version2header.jar

View File

@ -10,6 +10,15 @@
typedef unsigned char crc;
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
crc calc_crc(const crc message[], int nBytes);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* CRC_H_ */

View File

@ -30,7 +30,7 @@ void resetConsoleActions(void) {
consoleActionCount = 0;
}
static void doAddAction(char *token, int type, Void callback) {
static void doAddAction(const char *token, int type, Void callback) {
if (consoleActionCount == CONSOLE_MAX_ACTIONS) {
fatal("Too many console actions\r\n");
return;
@ -44,33 +44,33 @@ static void doAddAction(char *token, int type, Void callback) {
/**
* @brief Register console action without parameters
*/
void addConsoleAction(char *token, Void callback) {
void addConsoleAction(const char *token, Void callback) {
doAddAction(token, NO_PARAMETER, callback);
}
/**
* @brief Register a console command with one Integer parameter
*/
void addConsoleActionI(char *token, VoidInt callback) {
void addConsoleActionI(const char *token, VoidInt callback) {
doAddAction(token, ONE_PARAMETER, (Void) callback);
}
/**
* @brief Register a console command with two Integer parameters
*/
void addConsoleActionII(char *token, VoidIntInt callback) {
void addConsoleActionII(const char *token, VoidIntInt callback) {
doAddAction(token, TWO_INTS_PARAMETER, (Void) callback);
}
void addConsoleActionS(char *token, VoidCharPtr callback) {
void addConsoleActionS(const char *token, VoidCharPtr callback) {
doAddAction(token, STRING_PARAMETER, (Void) callback);
}
void addConsoleActionSSS(char *token, VoidCharPtrCharPtrCharPtr callback) {
void addConsoleActionSSS(const char *token, VoidCharPtrCharPtrCharPtr callback) {
doAddAction(token, STRING3_PARAMETER, (Void) callback);
}
void addConsoleActionF(char *token, VoidFloat callback) {
void addConsoleActionF(const char *token, VoidFloat callback) {
doAddAction(token, FLOAT_PARAMETER, (Void) callback);
}
@ -172,7 +172,7 @@ int tokenLength(char *msgp) {
return result;
}
int strEqual(char *str1, char *str2) {
int strEqual(const char *str1, const char *str2) {
// todo: there must be a standard function?!
int len1 = strlen(str1);
int len2 = strlen(str2);

View File

@ -35,7 +35,7 @@ typedef enum {
} ACTION_PARAMETER_TYPE;
typedef struct {
char *token;
const char *token;
int parameterType;
void (*callback)(void);
} TokenCallback;
@ -52,17 +52,17 @@ typedef void (*VoidCharPtr)(char *);
typedef void (*VoidCharPtrCharPtrCharPtr)(char *, char *, char *);
char *validateSecureLine(char *line);
int strEqual(char *str1, char *str2);
int strEqual(const char *str1, const char *str2);
void resetConsoleActions(void);
void helpCommand(void);
void initConsoleLogic(void);
void handleConsoleLine(char *line);
void addConsoleAction(char *token, Void callback);
void addConsoleActionI(char *token, VoidInt callback);
void addConsoleActionII(char *token, VoidIntInt callback);
void addConsoleActionF(char *token, VoidFloat callback);
void addConsoleActionS(char *token, VoidCharPtr callback);
void addConsoleActionSSS(char *token, VoidCharPtrCharPtrCharPtr callback);
void addConsoleAction(const char *token, Void callback);
void addConsoleActionI(const char *token, VoidInt callback);
void addConsoleActionII(const char *token, VoidIntInt callback);
void addConsoleActionF(const char *token, VoidFloat callback);
void addConsoleActionS(const char *token, VoidCharPtr callback);
void addConsoleActionSSS(const char *token, VoidCharPtrCharPtrCharPtr callback);
#ifdef __cplusplus

View File

@ -20,6 +20,7 @@ extern "C"
int indexOf(const char *string, char ch);
float atoff(const char *string);
int atoi(const char *string);
int cisnan(float f);
#ifdef __cplusplus
}

View File

@ -8,6 +8,10 @@
#ifndef LISTENER_ARRAY_H_
#define LISTENER_ARRAY_H_
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
#define MAX_INT_LISTENER_COUNT 15
@ -30,4 +34,8 @@ void invokeJustArgCallbacks(IntListenerArray *array);
void invokeArgIntCallbacks(IntListenerArray *array, int value);
void invokeIntIntCallbacks(IntListenerArray *array, int value, int value2);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* LISTENER_ARRAY_H_ */