manual sync
This commit is contained in:
parent
ade040036f
commit
7050527756
|
@ -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=""${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/USARTv1}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/chibios/os/ports/common/ARMCMx/CMSIS/include}""/>
|
||||
</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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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_ */
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include <chprintf.h>
|
||||
#include "eficonsole.h"
|
||||
#include "console_io.h"
|
||||
#include "rusefi.h"
|
||||
#include "svnversion.h"
|
||||
|
||||
static Logging logger;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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_ */
|
|
@ -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
|
|
@ -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_ */
|
|
@ -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;
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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_ */
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
#include "global.h"
|
||||
#include "signal_executor.h"
|
||||
#include "trigger_structure.h"
|
||||
|
||||
#define MAX_EVENT_COUNT 40
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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()");
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -12,6 +12,15 @@
|
|||
|
||||
#include "main.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
|
||||
float getAfr(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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__)
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
svn up
|
||||
call generate_docs
|
||||
|
||||
rem http://www.ncftp.com/download/
|
||||
rem http://www.ncftp.com/download/
|
||||
cd ../doxygen
|
||||
ncftpput -u u71977750-docs -p docspass rusefi.com /html html/*
|
||||
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
}
|
|
@ -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_ */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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_ */
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#define RUSEFI_H_
|
||||
|
||||
void runRusEfi(void);
|
||||
int getRusEfiVersion(void);
|
||||
void scheduleReset(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file was generated by Version2Header
|
||||
#ifndef SVN_VERSION
|
||||
#define SVN_VERSION 2772
|
||||
#define SVN_VERSION 2936
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
rem Let's regemerate 'svnversion.h'
|
||||
java -jar ../java_tools/version2header.jar
|
|
@ -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_ */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ Overflow64Counter::Overflow64Counter() {
|
|||
}
|
||||
|
||||
void Overflow64Counter::offer(uint32_t value) {
|
||||
if(value < currentValue) {
|
||||
if (value < currentValue) {
|
||||
// new value less than previous value means there was an overflow in that 32 bit counter
|
||||
currentBase += 0x100000000LL;
|
||||
}
|
||||
|
|
|
@ -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_ */
|
||||
|
|
Loading…
Reference in New Issue