Merge remote-tracking branch 'origin/master'

This commit is contained in:
rusefi 2020-05-07 00:56:22 -04:00
commit 46a56f3799
21 changed files with 276 additions and 39 deletions

View File

@ -24,7 +24,7 @@ jobs:
- build-target: frankenso-pal
efi-cpu: ARCH_STM32F4
efi-board: st_stm32f4
target-extra-params: -DHAL_TRIGGER_USE_PAL=TRUE -DHAL_USE_ICU=FALSE -DEFI_VEHICLE_SPEED=FALSE -DEFI_LOGIC_ANALYZER=FALSE
target-extra-params: -DHAL_TRIGGER_USE_PAL=TRUE -DEFI_ICU_INPUTS=FALSE -DEFI_VEHICLE_SPEED=FALSE -DEFI_LOGIC_ANALYZER=FALSE
- build-target: mre-f4
efi-cpu: ARCH_STM32F4

View File

@ -24,4 +24,4 @@ endif
# Override DEFAULT_ENGINE_TYPE
DDEFS += $(MCU_DEFS) -DEFI_USE_OSC=TRUE -DEFI_FATAL_ERROR_PIN=GPIOE_3 -DFIRMWARE_ID=\"proteus\" -DDEFAULT_ENGINE_TYPE=PROTEUS -DUSE_ADC3_VBATT_HACK -DSTM32_ADC_USE_ADC3=TRUE -DEFI_INCLUDE_ENGINE_PRESETS=FALSE
DDEFS += $(MCU_DEFS) -DEFI_USE_OSC=TRUE -DEFI_FATAL_ERROR_PIN=GPIOE_3 -DFIRMWARE_ID=\"proteus\" -DDEFAULT_ENGINE_TYPE=PROTEUS -DUSE_ADC3_VBATT_HACK -DSTM32_ADC_USE_ADC3=TRUE -DEFI_INCLUDE_ENGINE_PRESETS=FALSE -DEFI_ICU_INPUTS=FALSE -DHAL_TRIGGER_USE_PAL=TRUE -DEFI_VEHICLE_SPEED=FALSE -DEFI_LOGIC_ANALYZER=FALSE

View File

@ -126,12 +126,9 @@ void setDcMotorDuty(size_t index, float duty) {
}
#if EFI_PROD_CODE
void showDcMotorInfo(Logging* logger) {
for (int i = 0 ; i < engine->etbActualCount; i++) {
EtbHardware *etb = &etbHardware[i];
void showDcMotorInfo(Logging* logger, int i) {
EtbHardware *etb = &etbHardware[i];
scheduleMsg(logger, "ETB %d", i);
scheduleMsg(logger, "Motor: dir=%d DC=%f", etb->dcMotor.isOpenDirection(), etb->dcMotor.get());
}
scheduleMsg(logger, " motor: dir=%d DC=%f", etb->dcMotor.isOpenDirection(), etb->dcMotor.get());
}
#endif

View File

@ -20,5 +20,5 @@ void setDcMotorFrequency(size_t index, int hz);
void setDcMotorDuty(size_t index, float duty);
#if EFI_PROD_CODE
void showDcMotorInfo(Logging* logger);
void showDcMotorInfo(Logging* logger, int i);
#endif

View File

@ -502,10 +502,15 @@ static void showEthInfo(void) {
hwPortname(CONFIG(etbIo[0].controlPin1)),
currentEtbDuty,
engineConfiguration->etbFreq);
scheduleMsg(&logger, "dir1=%s", hwPortname(CONFIG(etbIo[0].directionPin1)));
scheduleMsg(&logger, "dir2=%s", hwPortname(CONFIG(etbIo[0].directionPin2)));
showDcMotorInfo(&logger);
int i;
for (i = 0; i < engine->etbActualCount; i++) {
scheduleMsg(&logger, "ETB%d", i);
scheduleMsg(&logger, " dir1=%s", hwPortname(CONFIG(etbIo[i].directionPin1)));
scheduleMsg(&logger, " dir2=%s", hwPortname(CONFIG(etbIo[i].directionPin2)));
scheduleMsg(&logger, " control=%s", hwPortname(CONFIG(etbIo[i].controlPin1)));
scheduleMsg(&logger, " disable=%s", hwPortname(CONFIG(etbIo[i].disablePin)));
showDcMotorInfo(&logger, i);
}
#endif /* EFI_PROD_CODE */
}

View File

@ -120,12 +120,16 @@ static void showIdleInfo(void) {
getIdlePosition(), boolToString(CONFIG(useStepperIdle)));
if (CONFIG(useStepperIdle)) {
scheduleMsg(logger, "directionPin=%s reactionTime=%.2f", hwPortname(CONFIG(idle).stepperDirectionPin),
engineConfiguration->idleStepperReactionTime);
scheduleMsg(logger, "stepPin=%s steps=%d", hwPortname(CONFIG(idle).stepperStepPin),
engineConfiguration->idleStepperTotalSteps);
scheduleMsg(logger, "enablePin=%s/%d", hwPortname(engineConfiguration->stepperEnablePin),
engineConfiguration->stepperEnablePinMode);
if (CONFIG(useHbridges)) {
/* TODO */
} else {
scheduleMsg(logger, "directionPin=%s reactionTime=%.2f", hwPortname(CONFIG(idle).stepperDirectionPin),
engineConfiguration->idleStepperReactionTime);
scheduleMsg(logger, "stepPin=%s steps=%d", hwPortname(CONFIG(idle).stepperStepPin),
engineConfiguration->idleStepperTotalSteps);
scheduleMsg(logger, "enablePin=%s/%d", hwPortname(engineConfiguration->stepperEnablePin),
engineConfiguration->stepperEnablePinMode);
}
} else {
if (!CONFIG(isDoubleSolenoidIdle)) {
scheduleMsg(logger, "idle valve freq=%d on %s", CONFIG(idle).solenoidFrequency,

View File

@ -627,6 +627,44 @@ void setDefaultMultisparkParameters(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
engineConfiguration->multisparkMaxSparkingAngle = 30;
}
void setDefaultStftSettings(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
auto& cfg = CONFIG(stft);
// Default to disabled
CONFIG(fuelClosedLoopCorrectionEnabled) = false;
// Default to proportional mode (for wideband sensors)
CONFIG(stftIgnoreErrorMagnitude) = false;
// 60 second startup delay - some O2 sensors are slow to warm up.
cfg.startupDelay = 60;
// Only correct in [12.0, 17.0]
cfg.minAfr = 120;
cfg.maxAfr = 170;
// Above 60 deg C
cfg.minClt = 60;
// 0.5% deadband
cfg.deadband = 5;
// Sensible region defaults
cfg.maxIdleRegionRpm = 1000 / RPM_1_BYTE_PACKING_MULT;
cfg.maxOverrunLoad = 35;
cfg.minPowerLoad = 85;
// Sensible cell defaults
for (size_t i = 0; i < efi::size(cfg.cellCfgs); i++) {
// 30 second time constant - nice and slow
cfg.cellCfgs[i].timeConstant = 30 * 10;
/// Allow +-5%
cfg.cellCfgs[i].maxAdd = 5;
cfg.cellCfgs[i].maxRemove = -5;
}
}
void setDefaultGppwmParameters(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
// Same config for all channels
for (size_t i = 0; i < efi::size(CONFIG(gppwm)); i++) {
@ -854,13 +892,7 @@ static void setDefaultEngineConfiguration(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
setDefaultCrankingSettings(PASS_ENGINE_PARAMETER_SIGNATURE);
engineConfiguration->fuelClosedLoopCorrectionEnabled = false;
engineConfiguration->fuelClosedLoopCltThreshold = 70;
engineConfiguration->fuelClosedLoopRpmThreshold = 900;
engineConfiguration->fuelClosedLoopTpsThreshold = 80;
engineConfiguration->fuelClosedLoopAfrLowThreshold = 10.3;
engineConfiguration->fuelClosedLoopAfrHighThreshold = 19.8;
engineConfiguration->fuelClosedLoopPid.pFactor = -0.1;
setDefaultStftSettings(PASS_ENGINE_PARAMETER_SIGNATURE);
/**
* Idle control defaults

View File

@ -0,0 +1,90 @@
#include "closed_loop_fuel_cell.h"
#include "engine.h"
#include "engine_configuration_generated_structures.h"
EXTERN_ENGINE;
constexpr float integrator_dt = FAST_CALLBACK_PERIOD_MS * 0.001f;
void ClosedLoopFuelCellBase::update(float lambdaDeadband, bool ignoreErrorMagnitude DECLARE_ENGINE_PARAMETER_SUFFIX)
{
// Compute how far off target we are
float lambdaError = getLambdaError(PASS_ENGINE_PARAMETER_SIGNATURE);
// If we're within the deadband, make no adjustment.
if (absF(lambdaError) < lambdaDeadband) {
return;
}
// Fixed magnitude - runs in constant adjustment rate mode
if (ignoreErrorMagnitude) {
if (lambdaError > 0) {
lambdaError = 0.1f;
} else {
lambdaError = -0.1f;
}
}
// Integrate
float adjust = getIntegratorGain() * lambdaError * integrator_dt
+ m_adjustment;
// Clamp to bounds
float minAdjust = getMinAdjustment();
float maxAdjust = getMaxAdjustment();
if (adjust > maxAdjust) {
adjust = maxAdjust;
} else if (adjust < minAdjust) {
adjust = minAdjust;
}
// Save state
m_adjustment = adjust;
}
float ClosedLoopFuelCellBase::getAdjustment() const {
return 1.0f + m_adjustment;
}
float ClosedLoopFuelCellImpl::getLambdaError(DECLARE_ENGINE_PARAMETER_SIGNATURE) const {
return (ENGINE(sensors.currentAfr) - ENGINE(engineState.targetAFR)) / 14.7f;
}
#define MAX_ADJ (0.25f)
float ClosedLoopFuelCellImpl::getMaxAdjustment() const {
if (!m_config) {
// If no config, disallow adjustment.
return 0;
}
float raw = m_config->maxAdd * 0.01f;
// Don't allow maximum less than 0, or more than maximum adjustment
return minF(MAX_ADJ, maxF(raw, 0));
}
float ClosedLoopFuelCellImpl::getMinAdjustment() const {
if (!m_config) {
// If no config, disallow adjustment.
return 0;
}
float raw = m_config->maxRemove * 0.01f;
// Don't allow minimum more than 0, or more than maximum adjustment
return maxF(-MAX_ADJ, minF(raw, 0));
}
float ClosedLoopFuelCellImpl::getIntegratorGain() const {
if (!m_config) {
// If no config, disallow adjustment.
return 0.0f;
}
float timeConstant = m_config->timeConstant * 0.1f;
// Clamp to reasonable limits - 100ms to 100s
timeConstant = maxF(0.1f, minF(timeConstant, 100));
return 1 / timeConstant;
}

View File

@ -0,0 +1,43 @@
#pragma once
#include "globalaccess.h"
class ClosedLoopFuelCellBase {
public:
// Update the cell's internal state - adjusting fuel up/down as appropriate
void update(float lambdaDeadband, bool ignoreErrorMagnitude DECLARE_ENGINE_PARAMETER_SUFFIX);
// Get the current adjustment amount, without altering internal state.
float getAdjustment() const;
protected:
// Helpers - virtual for mocking
virtual float getLambdaError(DECLARE_ENGINE_PARAMETER_SIGNATURE) const = 0;
virtual float getMaxAdjustment() const = 0;
virtual float getMinAdjustment() const = 0;
virtual float getIntegratorGain() const = 0;
private:
// Current fueling adjustment.
// 0 = no adjustment.
// 0.1 = add 10% fuel.
float m_adjustment = 0;
};
struct stft_cell_cfg_s;
class ClosedLoopFuelCellImpl final : public ClosedLoopFuelCellBase {
public:
void configure(const stft_cell_cfg_s* configuration) {
m_config = configuration;
}
private:
const stft_cell_cfg_s *m_config = nullptr;
protected:
float getLambdaError(DECLARE_ENGINE_PARAMETER_SIGNATURE) const override;
float getMaxAdjustment() const override;
float getMinAdjustment() const override;
float getIntegratorGain() const override;
};

View File

@ -3,4 +3,6 @@ CONTROLLERS_MATH_SRC =
CONTROLLERS_MATH_SRC_CPP = $(PROJECT_DIR)/controllers/math/engine_math.cpp \
$(PROJECT_DIR)/controllers/math/pid_auto_tune.cpp \
$(PROJECT_DIR)/controllers/math/speed_density.cpp
$(PROJECT_DIR)/controllers/math/speed_density.cpp \
$(PROJECT_DIR)/controllers/math/closed_loop_fuel_cell.cpp \

View File

@ -277,7 +277,7 @@ void initMapDecoder(Logging *sharedLogger DECLARE_ENGINE_PARAMETER_SUFFIX) {
//engine->configurationListeners.registerCallback(applyConfiguration);
if (engineConfiguration->hasFrequencyReportingMapSensor) {
#if HAL_USE_ICU
#if EFI_ICU_INPUTS
digital_input_s* digitalMapInput = startDigitalCapture("MAP freq", CONFIG(frequencyReportingMapInputPin));
digitalMapInput->setWidthCallback((VoidInt) digitalMapWidthCallback, NULL);

View File

@ -630,7 +630,7 @@ void requestTLE8888initialization(void) {
/* Driver exported functions. */
/*==========================================================================*/
int tle8888_writePad(void *data, unsigned int pin, int value) {
static int tle8888_writePad(void *data, unsigned int pin, int value) {
if ((pin >= TLE8888_OUTPUTS) || (data == NULL))
return -1;
@ -736,7 +736,7 @@ void tle8888_read_reg(uint16_t reg, uint16_t *val)
tle8888_spi_rw(chip, CMD_R(reg), val);
}
int tle8888_init(void * data)
static int tle8888_init(void * data)
{
int ret;
struct tle8888_priv *chip;
@ -763,7 +763,7 @@ int tle8888_init(void * data)
return 0;
}
int tle8888_deinit(void *data)
static int tle8888_deinit(void *data)
{
(void)data;

View File

@ -26,6 +26,7 @@
#define Window_watchdog_close_window_time_ms 100.8
#define getRegisterFromResponse(x) (((x) >> 1) & 0x7f)
#define getDataFromResponse(x) (((x) >> 8) & 0xff)
// unchangeable value for TLE8888QK
// unused for now

View File

@ -108,10 +108,10 @@ void tle8888_dump_regs(void)
for (int request = 0; request < 0x7e + 1; request++) {
uint16_t tmp;
tle8888_read_reg(request, &tmp);
uint8_t response = getRegisterFromResponse(tmp);
uint8_t data = (tmp >> 8) & 0xff;
uint8_t reg = getRegisterFromResponse(tmp);
uint8_t data = getDataFromResponse(tmp);
scheduleMsg(&logger, "%02x: %02x", response, data);
scheduleMsg(&logger, "%02x: %02x", reg, data);
}
}
#endif

View File

@ -76,6 +76,7 @@ static int turnOnTriggerInputPin(const char *msg, int index, bool isTriggerShaft
return 0;
/* try ICU first */
#if EFI_ICU_INPUTS
if (icuTriggerTurnOnInputPin(msg, index, isTriggerShaft) >= 0) {
if (isTriggerShaft)
shaftTriggerType[index] = TRIGGER_ICU;
@ -83,6 +84,7 @@ static int turnOnTriggerInputPin(const char *msg, int index, bool isTriggerShaft
camTriggerType[index] = TRIGGER_ICU;
return 0;
}
#endif
/* ... then EXTI */
if (extiTriggerTurnOnInputPin(msg, index, isTriggerShaft) >= 0) {
@ -103,15 +105,19 @@ static void turnOffTriggerInputPin(int index, bool isTriggerShaft) {
activeConfiguration.triggerInputPins[index] : activeConfiguration.camInputs[index];
if (isTriggerShaft) {
#if EFI_ICU_INPUTS
if (shaftTriggerType[index] == TRIGGER_ICU)
icuTriggerTurnOffInputPin(brainPin);
#endif
if (shaftTriggerType[index] == TRIGGER_EXTI)
extiTriggerTurnOffInputPin(brainPin);
shaftTriggerType[index] = TRIGGER_NONE;
} else {
#if EFI_ICU_INPUTS
if (camTriggerType[index] == TRIGGER_ICU)
icuTriggerTurnOffInputPin(brainPin);
#endif
if (camTriggerType[index] == TRIGGER_EXTI)
extiTriggerTurnOffInputPin(brainPin);

View File

@ -817,7 +817,7 @@ custom maf_sensor_type_e 4 bits, S32, @OFFSET@, [0:7], @@maf_sensor_type_e_enum@
bit enableCanVss
bit enableInnovateLC2
bit showHumanReadableWarning
bit unusedBit_251_10
bit stftIgnoreErrorMagnitude
bit unusedBit_251_11
bit unusedBit_251_12
bit unusedBit_251_13

View File

@ -19,6 +19,9 @@
#define BIT(n) (UINT32_C(1) << (n))
// we also have efi::size which probably does not work for C code
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
// human-readable IDs start from 1 while computer-readbale indexes start from 0
#define ID2INDEX(id) ((id) - 1)

View File

@ -1,6 +1,6 @@
package com.rusefi.config.generated;
// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.bat integration\rusefi_config.txt Wed May 06 12:32:31 EDT 2020
// this file was generated automatically by rusEfi tool ConfigDefinition.jar based on gen_config.bat integration\rusefi_config.txt Wed May 06 22:04:17 EDT 2020
// by class com.rusefi.output.FileJavaFieldsConsumer
import com.rusefi.config.*;
@ -1335,6 +1335,7 @@ public class Fields {
public static final int stft_offset = 1064;
public static final int stft_offset_hex = 428;
public static final int stft_startupDelay_offset = 1071;
public static final int stftIgnoreErrorMagnitude_offset = 976;
public static final int storageMode_offset = 2260;
public static final int tachOutputPin_offset = 704;
public static final int tachOutputPinMode_offset = 705;
@ -1548,7 +1549,6 @@ public class Fields {
public static final int unusedAtOldBoardConfigurationEnd_offset = 1160;
public static final int unusedAtOldBoardConfigurationEnd_offset_hex = 488;
public static final int unusedBit4_1476_offset = 1476;
public static final int unusedBit_251_10_offset = 976;
public static final int unusedBit_251_11_offset = 976;
public static final int unusedBit_251_12_offset = 976;
public static final int unusedBit_251_13_offset = 976;
@ -2105,7 +2105,7 @@ public class Fields {
public static final Field ENABLECANVSS = Field.create("ENABLECANVSS", 976, FieldType.BIT, 7);
public static final Field ENABLEINNOVATELC2 = Field.create("ENABLEINNOVATELC2", 976, FieldType.BIT, 8);
public static final Field SHOWHUMANREADABLEWARNING = Field.create("SHOWHUMANREADABLEWARNING", 976, FieldType.BIT, 9);
public static final Field UNUSEDBIT_251_10 = Field.create("UNUSEDBIT_251_10", 976, FieldType.BIT, 10);
public static final Field STFTIGNOREERRORMAGNITUDE = Field.create("STFTIGNOREERRORMAGNITUDE", 976, FieldType.BIT, 10);
public static final Field UNUSEDBIT_251_11 = Field.create("UNUSEDBIT_251_11", 976, FieldType.BIT, 11);
public static final Field UNUSEDBIT_251_12 = Field.create("UNUSEDBIT_251_12", 976, FieldType.BIT, 12);
public static final Field UNUSEDBIT_251_13 = Field.create("UNUSEDBIT_251_13", 976, FieldType.BIT, 13);
@ -3077,7 +3077,7 @@ public class Fields {
ENABLECANVSS,
ENABLEINNOVATELC2,
SHOWHUMANREADABLEWARNING,
UNUSEDBIT_251_10,
STFTIGNOREERRORMAGNITUDE,
UNUSEDBIT_251_11,
UNUSEDBIT_251_12,
UNUSEDBIT_251_13,

View File

@ -4,6 +4,7 @@ git remote add upstream https://github.com/rusefi/rusefi.git
rem The heros, in alpabetical order
git remote add andreika-git https://github.com/andreika-git/rusefi
git remote add DonaldBecker https://github.com/DonaldBecker/rusefi
git remote add dron0gus https://github.com/dron0gus/rusefi
git remote add mck1117 https://github.com/mck1117/rusefi
git remote add NOx-z https://github.com/NOx-z/rusefi

View File

@ -0,0 +1,52 @@
#include "closed_loop_fuel_cell.h"
#include "engine.h"
#include "gtest/gtest.h"
#include "gmock/gmock.h"
using ::testing::_;
using ::testing::Return;
using ::testing::StrictMock;
class MockClCell : public ClosedLoopFuelCellBase {
public:
MOCK_METHOD(float, getLambdaError, (DECLARE_ENGINE_PARAMETER_SIGNATURE), (const));
MOCK_METHOD(float, getMaxAdjustment, (), (const));
MOCK_METHOD(float, getMinAdjustment, (), (const));
MOCK_METHOD(float, getIntegratorGain, (), (const));
};
TEST(ClosedLoopCell, TestDeadband) {
StrictMock<MockClCell> cl;
// Error is more than deadtime, so nothing else should be called
EXPECT_CALL(cl, getLambdaError(_, _, _))
.WillOnce(Return(0.05f));
cl.update(0.1f, true, nullptr, nullptr, nullptr);
// Should be zero adjustment
EXPECT_FLOAT_EQ(cl.getAdjustment(), 1.0f);
}
TEST(ClosedLoopFuelCell, AdjustRate) {
StrictMock<MockClCell> cl;
// Error is more than deadtime, so nothing else should be called
EXPECT_CALL(cl, getLambdaError(_, _, _))
.WillOnce(Return(0.1f));
EXPECT_CALL(cl, getMinAdjustment())
.WillOnce(Return(-0.2f));
EXPECT_CALL(cl, getMaxAdjustment())
.WillOnce(Return(0.2f));
EXPECT_CALL(cl, getIntegratorGain())
.WillOnce(Return(2.0f));
cl.update(0.0f, false, nullptr, nullptr, nullptr);
// Should have integrated 0.2 * dt
// dt = 1000.0f / FAST_CALLBACK_PERIOD_MS
EXPECT_FLOAT_EQ(cl.getAdjustment(), 1 + (0.2f / (1000.0f / FAST_CALLBACK_PERIOD_MS)));
}

View File

@ -49,6 +49,7 @@ TESTS_SRC_CPP = \
tests/sensor/redundant.cpp \
tests/sensor/test_sensor_init.cpp \
tests/test_closed_loop_controller.cpp \
tests/test_stft.cpp \
tests/test_boost.cpp \
tests/test_gppwm.cpp \
tests/test_fuel_math.cpp \