From b5bca8ac48882190892e2264a62b5f275a33e711 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Fri, 15 Jul 2022 22:53:49 +0300 Subject: [PATCH 01/91] heater: 5 sec stabilization time after switching to closed loop LSU4.2 falls to Underheated state right after switch to closed loop due to rise of sensorEsr (due to applied pump current?) --- firmware/heater_control.cpp | 28 ++++++++++++++++++---------- firmware/heater_control.h | 1 + firmware/wideband_config.h | 1 + test/tests/test_heater.cpp | 3 +++ 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/firmware/heater_control.cpp b/firmware/heater_control.cpp index 03329ecb..e80ecc4d 100644 --- a/firmware/heater_control.cpp +++ b/firmware/heater_control.cpp @@ -20,6 +20,7 @@ void HeaterControllerBase::Configure(float targetTempC, float targetEsr) m_preheatTimer.reset(); m_warmupTimer.reset(); m_batteryStableTimer.reset(); + m_closedLoopStableTimer.reset(); } bool HeaterControllerBase::IsRunningClosedLoop() const @@ -101,6 +102,7 @@ HeaterState HeaterControllerBase::GetNextState(HeaterState currentState, HeaterA case HeaterState::WarmupRamp: if (sensorTemp > closedLoopTemp) { + m_closedLoopStableTimer.reset(); return HeaterState::ClosedLoop; } else if (m_warmupTimer.hasElapsedSec(m_warmupTimeSec)) @@ -111,16 +113,22 @@ HeaterState HeaterControllerBase::GetNextState(HeaterState currentState, HeaterA break; case HeaterState::ClosedLoop: - // Check that the sensor's ESR is acceptable for normal operation - if (sensorTemp > overheatTemp) - { - SetFault(ch, Fault::SensorOverheat); - return HeaterState::Stopped; - } - else if (sensorTemp < underheatTemp) - { - SetFault(ch, Fault::SensorUnderheat); - return HeaterState::Stopped; + if (m_closedLoopStableTimer.hasElapsedSec(HEATER_CLOSED_LOOP_STAB_TIME)) { + // Check that the sensor's ESR is acceptable for normal operation + if (sensorTemp > overheatTemp) + { + SetFault(ch, Fault::SensorOverheat); + return HeaterState::Stopped; + } + else if (sensorTemp < underheatTemp) + { + SetFault(ch, Fault::SensorUnderheat); + return HeaterState::Stopped; + } + } else { + // give some time for stabilization... + // looks like heavy ramped Ipump affects sensorTemp measure + // and right after switch to closed loop sensorTemp drops below underhead threshold } break; diff --git a/firmware/heater_control.h b/firmware/heater_control.h index df0b2a2d..bb6aa7d7 100644 --- a/firmware/heater_control.h +++ b/firmware/heater_control.h @@ -73,6 +73,7 @@ class HeaterControllerBase : public IHeaterController Timer m_batteryStableTimer; Timer m_preheatTimer; Timer m_warmupTimer; + Timer m_closedLoopStableTimer; static const int batteryStabTimeCounter = HEATER_BATTERY_STAB_TIME / HEATER_CONTROL_PERIOD; }; diff --git a/firmware/wideband_config.h b/firmware/wideband_config.h index 242437ea..234f17d9 100644 --- a/firmware/wideband_config.h +++ b/firmware/wideband_config.h @@ -42,6 +42,7 @@ #define HEATER_PREHEAT_TIME 5 #define HEATER_WARMUP_TIMEOUT 60 +#define HEATER_CLOSED_LOOP_STAB_TIME 5 #define HEATER_BATTERY_STAB_TIME 0.5f // minimal battery voltage to start heating without CAN command diff --git a/test/tests/test_heater.cpp b/test/tests/test_heater.cpp index a3dc5e95..0f6549e5 100644 --- a/test/tests/test_heater.cpp +++ b/test/tests/test_heater.cpp @@ -128,6 +128,9 @@ TEST(HeaterStateMachine, ClosedLoop) // Temperature is reasonable, stay in closed loop EXPECT_EQ(HeaterState::ClosedLoop, dut.GetNextState(HeaterState::ClosedLoop, HeaterAllow::Allowed, 12, 780)); + // Skip 5 sec stabilizaiton time + Timer::setMockTime(5.1e6); + // Temperature is too hot, overheat EXPECT_EQ(HeaterState::Stopped, dut.GetNextState(HeaterState::ClosedLoop, HeaterAllow::Allowed, 12, 1000)); From 2b634a09dbe79989e8e6500438637367cb7ba185 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 5 Feb 2023 01:11:31 +0300 Subject: [PATCH 02/91] heater_control: retry heating attempt after timeout --- firmware/heater_control.cpp | 15 +++++++++++++++ firmware/heater_control.h | 3 +++ firmware/wideband_config.h | 5 +++++ 3 files changed, 23 insertions(+) diff --git a/firmware/heater_control.cpp b/firmware/heater_control.cpp index e80ecc4d..6826e4b8 100644 --- a/firmware/heater_control.cpp +++ b/firmware/heater_control.cpp @@ -108,6 +108,9 @@ HeaterState HeaterControllerBase::GetNextState(HeaterState currentState, HeaterA else if (m_warmupTimer.hasElapsedSec(m_warmupTimeSec)) { SetFault(ch, Fault::SensorDidntHeat); + // retry after timeout + m_retryTime = HEATER_DIDNOTHEAT_RETRY_TIMEOUT; + m_retryTimer.reset(); return HeaterState::Stopped; } @@ -118,11 +121,17 @@ HeaterState HeaterControllerBase::GetNextState(HeaterState currentState, HeaterA if (sensorTemp > overheatTemp) { SetFault(ch, Fault::SensorOverheat); + // retry after timeout + m_retryTime = HEATER_OVERHEAT_RETRY_TIMEOUT; + m_retryTimer.reset(); return HeaterState::Stopped; } else if (sensorTemp < underheatTemp) { SetFault(ch, Fault::SensorUnderheat); + // retry after timeout + m_retryTime = HEATER_UNDERHEAT_RETRY_TIMEOUT; + m_retryTimer.reset(); return HeaterState::Stopped; } } else { @@ -130,9 +139,15 @@ HeaterState HeaterControllerBase::GetNextState(HeaterState currentState, HeaterA // looks like heavy ramped Ipump affects sensorTemp measure // and right after switch to closed loop sensorTemp drops below underhead threshold } + // reset fault + SetFault(ch, Fault::None); break; case HeaterState::Stopped: + if ((m_retryTime) && (m_retryTimer.hasElapsedSec(m_retryTime))) { + return HeaterState::Preheat; + } + break; case HeaterState::NoHeaterSupply: /* nop */ break; diff --git a/firmware/heater_control.h b/firmware/heater_control.h index bb6aa7d7..fd344d64 100644 --- a/firmware/heater_control.h +++ b/firmware/heater_control.h @@ -70,10 +70,13 @@ class HeaterControllerBase : public IHeaterController const int m_preheatTimeSec; const int m_warmupTimeSec; + int m_retryTime = 0; + Timer m_batteryStableTimer; Timer m_preheatTimer; Timer m_warmupTimer; Timer m_closedLoopStableTimer; + Timer m_retryTimer; static const int batteryStabTimeCounter = HEATER_BATTERY_STAB_TIME / HEATER_CONTROL_PERIOD; }; diff --git a/firmware/wideband_config.h b/firmware/wideband_config.h index 234f17d9..34c06c7f 100644 --- a/firmware/wideband_config.h +++ b/firmware/wideband_config.h @@ -45,6 +45,11 @@ #define HEATER_CLOSED_LOOP_STAB_TIME 5 #define HEATER_BATTERY_STAB_TIME 0.5f + +#define HEATER_DIDNOTHEAT_RETRY_TIMEOUT 30 +#define HEATER_OVERHEAT_RETRY_TIMEOUT 60 +#define HEATER_UNDERHEAT_RETRY_TIMEOUT 30 + // minimal battery voltage to start heating without CAN command #define HEATER_BATTERY_ON_VOLTAGE 9.5 // mininal battery voltage to continue heating From 2539428e28e169718474d9a5fb1ea37936cb7d97 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 19 Feb 2023 12:31:53 +0300 Subject: [PATCH 03/91] heater_control: report SensorNoHeatSupply if no supply --- firmware/heater_control.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/firmware/heater_control.cpp b/firmware/heater_control.cpp index 6826e4b8..ea019ebb 100644 --- a/firmware/heater_control.cpp +++ b/firmware/heater_control.cpp @@ -49,6 +49,8 @@ HeaterState HeaterControllerBase::GetNextState(HeaterState currentState, HeaterA if (batteryVoltage < HEATER_BATTETY_OFF_VOLTAGE) { m_batteryStableTimer.reset(); + // set fault + SetFault(ch, Fault::SensorNoHeatSupply); return HeaterState::NoHeaterSupply; } else if (batteryVoltage > HEATER_BATTERY_ON_VOLTAGE) From 209918d4126813254fe51dd66720bfed2ba8a41b Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Thu, 2 Feb 2023 00:08:32 +0300 Subject: [PATCH 04/91] f1_dual: select bigger Vbat voltage from two heater voltages --- firmware/livedata.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/firmware/livedata.cpp b/firmware/livedata.cpp index 7a0c4e7c..33483402 100644 --- a/firmware/livedata.cpp +++ b/firmware/livedata.cpp @@ -16,6 +16,7 @@ static livedata_afr_s livedata_afr[AFR_CHANNELS]; void SamplingUpdateLiveData() { + float vbat = 0; for (int ch = 0; ch < AFR_CHANNELS; ch++) { volatile struct livedata_afr_s *data = &livedata_afr[ch]; @@ -34,9 +35,11 @@ void SamplingUpdateLiveData() data->esr = sampler.GetSensorInternalResistance(); data->fault = (uint8_t)GetCurrentFault(ch); data->heaterState = (uint8_t)GetHeaterState(ch); + if (GetInternalBatteryVoltage(ch) > vbat) + vbat = GetInternalBatteryVoltage(ch); } - livedata_common.vbatt = GetSampler(0).GetInternalBatteryVoltage(); + livedata_common.vbatt = vbat; } template<> From 6ac008ce128bdcb6e8b8d99d78baa898a02ead1e Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Thu, 2 Feb 2023 00:11:12 +0300 Subject: [PATCH 05/91] TODO --- firmware/livedata.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/livedata.cpp b/firmware/livedata.cpp index 33483402..7b72bc98 100644 --- a/firmware/livedata.cpp +++ b/firmware/livedata.cpp @@ -35,6 +35,7 @@ void SamplingUpdateLiveData() data->esr = sampler.GetSensorInternalResistance(); data->fault = (uint8_t)GetCurrentFault(ch); data->heaterState = (uint8_t)GetHeaterState(ch); + /* TODO: add GetPumpOutputDuty() */ if (GetInternalBatteryVoltage(ch) > vbat) vbat = GetInternalBatteryVoltage(ch); } From de8b629e5601fc9f5fcdeadccc2a7803291a5d79 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Thu, 2 Feb 2023 00:45:22 +0300 Subject: [PATCH 06/91] livedata: show per-channel heater supply voltage --- firmware/ini/wideband_dual.ini | 12 +++++++++--- firmware/ini/wideband_f1.ini | 5 ++++- firmware/livedata.cpp | 7 +++++-- firmware/livedata.h | 2 +- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/firmware/ini/wideband_dual.ini b/firmware/ini/wideband_dual.ini index dbb5377e..ac8a7734 100644 --- a/firmware/ini/wideband_dual.ini +++ b/firmware/ini/wideband_dual.ini @@ -97,6 +97,7 @@ VBatt = scalar, F32, 0, "V", 1, 0 AFR0_lambda = scalar, F32, 32, "", 1, 0 AFR0_afr = scalar, F32, 32, "", 14.7, 0 AFR0_temp = scalar, U16, 36, "C", 0.1, 0 +AFR0_HeaterSupply = scalar, U16, 38, "V", 0.01, 0 AFR0_NernstDc = scalar, U16, 40, "V", 0.001, 0 AFR0_NernstAc = scalar, U16, 42, "V", 0.001, 0 AFR0_PumpITarget = scalar, F32, 44, "mA", 1, 0 @@ -111,6 +112,7 @@ AFR0_heater = scalar, U08, 61, "", 1, 0 AFR1_lambda = scalar, F32, 64, "", 1, 0 AFR1_afr = scalar, F32, 64, "", 14.7, 0 AFR1_temp = scalar, U16, 68, "C", 0.1, 0 +AFR1_HeaterSupply = scalar, U16, 70, "V", 0.01, 0 AFR1_NernstDc = scalar, U16, 72, "V", 0.001, 0 AFR1_NernstAc = scalar, U16, 74, "V", 0.001, 0 AFR1_PumpITarget = scalar, F32, 76, "mA", 1, 0 @@ -177,6 +179,7 @@ gaugeCategory = AFR channel 0 AFR0_LambdaGauge = AFR0_lambda, "0: lambda", "", 0.5, 1.3, 0.5, 0.6, 1.05, 1.2, 3, 3 AFR0_AfrGauge = AFR0_afr, "0: AFR", "", 6.5, 20.0, 9.0, 10.0, 16.0, 17.0, 2, 2 AFR0_TempGauge = AFR0_temp, "0: AFR t", "C", 500, 1050, 500, 650, 800, 950, 0, 0 +AFR0_HeaterSupply = AFR0_HeaterSupply,"0: Heater Supply", "V", 3.0, 24.0, 9.0, 11.0, 15.0, 16.0, 1, 1 AFR0_NernstDcGauge = AFR0_NernstDc, "0: nernst DC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR0_NernstAcGauge = AFR0_NernstAc, "0: nernst AC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR0_HeaterDutyGauge = AFR0_HeaterDuty, "0: Heater Duty", "%", 0.0, 100.0, 1.0, 3.0, 90, 95, 1, 1 @@ -191,6 +194,7 @@ gaugeCategory = AFR channel 1 AFR1_LambdaGauge = AFR1_lambda, "1: lambda", "", 0.5, 1.3, 0.5, 0.6, 1.05, 1.2, 3, 3 AFR1_AfrGauge = AFR1_afr, "1: AFR", "", 6.5, 20.0, 9.0, 10.0, 16.0, 17.0, 2, 2 AFR1_TempGauge = AFR1_temp, "1: AFR t", "C", 500, 1050, 500, 650, 800, 950, 0, 0 +AFR1_HeaterSupply = AFR1_HeaterSupply,"1: Heater Supply", "V", 3.0, 24.0, 9.0, 11.0, 15.0, 16.0, 1, 1 AFR1_NernstDcGauge = AFR1_NernstDc, "1: nernst DC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR1_NernstAcGauge = AFR1_NernstAc, "1: nernst AC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR1_HeaterDutyGauge = AFR1_HeaterDuty, "1: Heater Duty", "%", 0.0, 100.0, 1.0, 3.0, 90, 95, 1, 1 @@ -227,9 +231,9 @@ Aux1InputGauge = { (Aux1InputSel == 0) ? AFR0_AfrGauge : ((Aux1InputSel == 1) ? gauge2 = AFR0_AfrGauge gauge3 = AFR1_AfrGauge gauge4 = AFR1_TempGauge - gauge5 = VBattGauge - gauge6 = VBattGauge - gauge7 = EGT0_Gauge + gauge5 = EGT0_Gauge + gauge6 = AFR0_HeaterSupply + gauge7 = AFR1_HeaterSupply gauge8 = EGT1_Gauge indicator = { EGT0_state }, "EGT0 ok", { EGT0: bitStringValue(EgtStatesList, EGT0_state)}, green, black, red, black @@ -252,6 +256,7 @@ entry = VBatt, "Battery", float, "%.2f" entry = AFR0_lambda, "0: Lambda", float, "%.3f" entry = AFR0_afr, "0: AFR", float, "%.2f" entry = AFR0_temp, "0: Temp C", int, "%d" +entry = AFR0_HeaterSupply, "0: Heater Supply", float, "%.2f" entry = AFR0_NernstDc, "0: Nernst DC", float, "%.3f" entry = AFR0_NernstAc, "0: Nernst AC", float, "%.3f" entry = AFR0_PumpITarget, "0: Ipump target", float, "%.2f" @@ -266,6 +271,7 @@ entry = AFR0_esr, "0: ESR", float, "%.1f" entry = AFR1_lambda, "1: Lambda", float, "%.3f" entry = AFR1_afr, "1: AFR", float, "%.2f" entry = AFR1_temp, "1: Temp C", int, "%d" +entry = AFR1_HeaterSupply, "1: Heater Supply", float, "%.2f" entry = AFR1_NernstDc, "1: Nernst DC", float, "%.3f" entry = AFR1_NernstAc, "1: Nernst AC", float, "%.3f" entry = AFR1_PumpITarget, "1: Ipump target", float, "%.2f" diff --git a/firmware/ini/wideband_f1.ini b/firmware/ini/wideband_f1.ini index facef154..24fdc03f 100644 --- a/firmware/ini/wideband_f1.ini +++ b/firmware/ini/wideband_f1.ini @@ -90,6 +90,7 @@ VBatt = scalar, F32, 0, "V", 1, 0 AFR0_lambda = scalar, F32, 32, "", 1, 0 AFR0_afr = scalar, F32, 32, "", 14.7, 0 AFR0_temp = scalar, U16, 36, "C", 0.1, 0 +AFR0_HeaterSupply = scalar, U16, 38, "V", 0.01, 0 AFR0_NernstDc = scalar, U16, 40, "V", 0.001, 0 AFR0_NernstAc = scalar, U16, 42, "V", 0.001, 0 AFR0_PumpITarget = scalar, F32, 44, "mA", 1, 0 @@ -122,6 +123,7 @@ gaugeCategory = AFR channel 0 AFR0_LambdaGauge = AFR0_lambda, "0: lambda", "", 0.5, 1.3, 0.5, 0.6, 1.05, 1.2, 3, 3 AFR0_AfrGauge = AFR0_afr, "0: AFR", "", 6.5, 20.0, 9.0, 10.0, 16.0, 17.0, 2, 2 AFR0_TempGauge = AFR0_temp, "0: AFR t", "C", 500, 1050, 500, 650, 800, 950, 0, 0 +AFR0_HeaterSupply = AFR0_HeaterSupply,"0: Heater Supply", "V", 3.0, 24.0, 9.0, 11.0, 15.0, 16.0, 1, 1 AFR0_NernstDcGauge = AFR0_NernstDc, "0: nernst DC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR0_NernstAcGauge = AFR0_NernstAc, "0: nernst AC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR0_HeaterDutyGauge = AFR0_HeaterDuty, "0: Heater Duty", "%", 0.0, 100.0, 1.0, 3.0, 90, 95, 1, 1 @@ -136,7 +138,7 @@ AFR0_EsrGauge = AFR0_esr, "0: ESR", "ohms", ; 1 2 3 4 ; 5 6 7 8 - gauge1 = VBattGauge + gauge1 = AFR0_HeaterSupply gauge2 = AFR0_AfrGauge gauge3 = AFR0_TempGauge gauge4 = AFR0_HeaterDutyGauge @@ -161,6 +163,7 @@ entry = VBatt, "Battery", float, "%.2f" entry = AFR0_lambda, "0: Lambda", float, "%.3f" entry = AFR0_afr, "0: AFR", float, "%.2f" entry = AFR0_temp, "0: Temp C", int, "%d" +entry = AFR0_HeaterSupply, "0: Heater Supply", float, "%.2f" entry = AFR0_NernstDc, "0: Nernst DC", float, "%.3f" entry = AFR0_NernstAc, "0: Nernst AC", float, "%.3f" entry = AFR0_PumpITarget, "0: Ipump target", float, "%.2f" diff --git a/firmware/livedata.cpp b/firmware/livedata.cpp index 7b72bc98..53aa84b2 100644 --- a/firmware/livedata.cpp +++ b/firmware/livedata.cpp @@ -24,8 +24,11 @@ void SamplingUpdateLiveData() const auto& sampler = GetSampler(ch); const auto& heater = GetHeaterController(ch); + float voltage = sampler.GetInternalBatteryVoltage(); + data->lambda = GetLambda(ch); data->temperature = sampler.GetSensorTemperature() * 10; + data->heaterSupplyVoltage = voltage * 100; data->nernstDc = sampler.GetNernstDc() * 1000; data->nernstAc = sampler.GetNernstAc() * 1000; data->pumpCurrentTarget = GetPumpCurrent(ch); @@ -36,8 +39,8 @@ void SamplingUpdateLiveData() data->fault = (uint8_t)GetCurrentFault(ch); data->heaterState = (uint8_t)GetHeaterState(ch); /* TODO: add GetPumpOutputDuty() */ - if (GetInternalBatteryVoltage(ch) > vbat) - vbat = GetInternalBatteryVoltage(ch); + if (voltage > vbat) + vbat = voltage; } livedata_common.vbatt = vbat; diff --git a/firmware/livedata.h b/firmware/livedata.h index 3a03b074..6d57a203 100644 --- a/firmware/livedata.h +++ b/firmware/livedata.h @@ -23,7 +23,7 @@ struct livedata_afr_s { // lambda also displayed by TS as AFR, same data with different scale factor float lambda; uint16_t temperature; - uint16_t padding; + uint16_t heaterSupplyVoltage; uint16_t nernstDc; uint16_t nernstAc; float pumpCurrentTarget; From f1bc57340d21a33a4cfca0ff8f60a4808fe3b996 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Wed, 26 Apr 2023 22:44:48 +0300 Subject: [PATCH 07/91] livedata: show Nernst voltage --- firmware/ini/wideband_dual.ini | 10 ++++++++-- firmware/ini/wideband_f1.ini | 5 ++++- firmware/livedata.cpp | 1 + firmware/livedata.h | 3 ++- firmware/sampling.cpp | 6 ++++++ firmware/sampling.h | 3 +++ 6 files changed, 24 insertions(+), 4 deletions(-) diff --git a/firmware/ini/wideband_dual.ini b/firmware/ini/wideband_dual.ini index ac8a7734..9f7ec0cf 100644 --- a/firmware/ini/wideband_dual.ini +++ b/firmware/ini/wideband_dual.ini @@ -104,7 +104,8 @@ AFR0_PumpITarget = scalar, F32, 44, "mA", 1, 0 AFR0_PumpIMeasure = scalar, F32, 48, "mA", 1, 0 AFR0_HeaterDuty = scalar, U16, 52, "%", 0.1, 0 AFR0_HeaterEffV = scalar, U16, 54, "V", 0.01, 0 -AFR0_esr = scalar, F32, 56, "ohms", 1, 0 +AFR0_esr = scalar, U16, 56, "ohms", 1, 0 +AFR0_Nernst = scalar, S16, 58, "V", 0.001, 0 AFR0_fault = scalar, U08, 60, "", 1, 0 AFR0_heater = scalar, U08, 61, "", 1, 0 @@ -119,7 +120,8 @@ AFR1_PumpITarget = scalar, F32, 76, "mA", 1, 0 AFR1_PumpIMeasure = scalar, F32, 80, "mA", 1, 0 AFR1_HeaterDuty = scalar, U16, 84, "%", 0.1, 0 AFR1_HeaterEffV = scalar, U16, 86, "V", 0.01, 0 -AFR1_esr = scalar, F32, 88, "ohms", 1, 0 +AFR1_esr = scalar, U16, 88, "ohms", 1, 0 +AFR1_Nernst = scalar, S16, 90, "V", 0.001, 0 AFR1_fault = scalar, U08, 92, "", 1, 0 AFR1_heater = scalar, U08, 93, "", 1, 0 @@ -180,6 +182,7 @@ AFR0_LambdaGauge = AFR0_lambda, "0: lambda", "", AFR0_AfrGauge = AFR0_afr, "0: AFR", "", 6.5, 20.0, 9.0, 10.0, 16.0, 17.0, 2, 2 AFR0_TempGauge = AFR0_temp, "0: AFR t", "C", 500, 1050, 500, 650, 800, 950, 0, 0 AFR0_HeaterSupply = AFR0_HeaterSupply,"0: Heater Supply", "V", 3.0, 24.0, 9.0, 11.0, 15.0, 16.0, 1, 1 +AFR0_NernstGauge = AFR0_Nernst, "0: nernst V", "V", -0.2, 1.8, -0.1, 0.0, 0.9, 0.95, 3, 3 AFR0_NernstDcGauge = AFR0_NernstDc, "0: nernst DC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR0_NernstAcGauge = AFR0_NernstAc, "0: nernst AC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR0_HeaterDutyGauge = AFR0_HeaterDuty, "0: Heater Duty", "%", 0.0, 100.0, 1.0, 3.0, 90, 95, 1, 1 @@ -195,6 +198,7 @@ AFR1_LambdaGauge = AFR1_lambda, "1: lambda", "", AFR1_AfrGauge = AFR1_afr, "1: AFR", "", 6.5, 20.0, 9.0, 10.0, 16.0, 17.0, 2, 2 AFR1_TempGauge = AFR1_temp, "1: AFR t", "C", 500, 1050, 500, 650, 800, 950, 0, 0 AFR1_HeaterSupply = AFR1_HeaterSupply,"1: Heater Supply", "V", 3.0, 24.0, 9.0, 11.0, 15.0, 16.0, 1, 1 +AFR1_NernstGauge = AFR1_Nernst, "1: nernst V", "V", -0.2, 1.8, -0.1, 0.0, 0.9, 0.95, 3, 3 AFR1_NernstDcGauge = AFR1_NernstDc, "1: nernst DC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR1_NernstAcGauge = AFR1_NernstAc, "1: nernst AC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR1_HeaterDutyGauge = AFR1_HeaterDuty, "1: Heater Duty", "%", 0.0, 100.0, 1.0, 3.0, 90, 95, 1, 1 @@ -257,6 +261,7 @@ entry = AFR0_lambda, "0: Lambda", float, "%.3f" entry = AFR0_afr, "0: AFR", float, "%.2f" entry = AFR0_temp, "0: Temp C", int, "%d" entry = AFR0_HeaterSupply, "0: Heater Supply", float, "%.2f" +entry = AFR0_Nernst, "0: Nernst V", float, "%.3f" entry = AFR0_NernstDc, "0: Nernst DC", float, "%.3f" entry = AFR0_NernstAc, "0: Nernst AC", float, "%.3f" entry = AFR0_PumpITarget, "0: Ipump target", float, "%.2f" @@ -272,6 +277,7 @@ entry = AFR1_lambda, "1: Lambda", float, "%.3f" entry = AFR1_afr, "1: AFR", float, "%.2f" entry = AFR1_temp, "1: Temp C", int, "%d" entry = AFR1_HeaterSupply, "1: Heater Supply", float, "%.2f" +entry = AFR1_Nernst, "1: Nernst V", float, "%.3f" entry = AFR1_NernstDc, "1: Nernst DC", float, "%.3f" entry = AFR1_NernstAc, "1: Nernst AC", float, "%.3f" entry = AFR1_PumpITarget, "1: Ipump target", float, "%.2f" diff --git a/firmware/ini/wideband_f1.ini b/firmware/ini/wideband_f1.ini index 24fdc03f..d9b80966 100644 --- a/firmware/ini/wideband_f1.ini +++ b/firmware/ini/wideband_f1.ini @@ -97,7 +97,8 @@ AFR0_PumpITarget = scalar, F32, 44, "mA", 1, 0 AFR0_PumpIMeasure = scalar, F32, 48, "mA", 1, 0 AFR0_HeaterDuty = scalar, U16, 52, "%", 0.1, 0 AFR0_HeaterEffV = scalar, U16, 54, "V", 0.01, 0 -AFR0_esr = scalar, F32, 56, "ohms", 1, 0 +AFR0_esr = scalar, U16, 56, "ohms", 1, 0 +AFR0_Nernst = scalar, S16, 58, "V", 0.001, 0 AFR0_fault = scalar, U08, 60, "", 1, 0 AFR0_heater = scalar, U08, 61, "", 1, 0 @@ -124,6 +125,7 @@ AFR0_LambdaGauge = AFR0_lambda, "0: lambda", "", AFR0_AfrGauge = AFR0_afr, "0: AFR", "", 6.5, 20.0, 9.0, 10.0, 16.0, 17.0, 2, 2 AFR0_TempGauge = AFR0_temp, "0: AFR t", "C", 500, 1050, 500, 650, 800, 950, 0, 0 AFR0_HeaterSupply = AFR0_HeaterSupply,"0: Heater Supply", "V", 3.0, 24.0, 9.0, 11.0, 15.0, 16.0, 1, 1 +AFR0_NernstGauge = AFR0_Nernst, "0: nernst V", "V", -0.2, 1.8, -0.1, 0.0, 0.9, 0.95, 3, 3 AFR0_NernstDcGauge = AFR0_NernstDc, "0: nernst DC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR0_NernstAcGauge = AFR0_NernstAc, "0: nernst AC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR0_HeaterDutyGauge = AFR0_HeaterDuty, "0: Heater Duty", "%", 0.0, 100.0, 1.0, 3.0, 90, 95, 1, 1 @@ -164,6 +166,7 @@ entry = AFR0_lambda, "0: Lambda", float, "%.3f" entry = AFR0_afr, "0: AFR", float, "%.2f" entry = AFR0_temp, "0: Temp C", int, "%d" entry = AFR0_HeaterSupply, "0: Heater Supply", float, "%.2f" +entry = AFR0_Nernst, "0: Nernst V", float, "%.3f" entry = AFR0_NernstDc, "0: Nernst DC", float, "%.3f" entry = AFR0_NernstAc, "0: Nernst AC", float, "%.3f" entry = AFR0_PumpITarget, "0: Ipump target", float, "%.2f" diff --git a/firmware/livedata.cpp b/firmware/livedata.cpp index 53aa84b2..75a0f2b2 100644 --- a/firmware/livedata.cpp +++ b/firmware/livedata.cpp @@ -30,6 +30,7 @@ void SamplingUpdateLiveData() data->temperature = sampler.GetSensorTemperature() * 10; data->heaterSupplyVoltage = voltage * 100; data->nernstDc = sampler.GetNernstDc() * 1000; + data->nernstV = (int16_t)(sampler.GetNernstV() * 1000.0); data->nernstAc = sampler.GetNernstAc() * 1000; data->pumpCurrentTarget = GetPumpCurrent(ch); data->pumpCurrentMeasured = sampler.GetPumpNominalCurrent(); diff --git a/firmware/livedata.h b/firmware/livedata.h index 6d57a203..e5712dc7 100644 --- a/firmware/livedata.h +++ b/firmware/livedata.h @@ -30,7 +30,8 @@ struct livedata_afr_s { float pumpCurrentMeasured; uint16_t heaterDuty; uint16_t heaterEffectiveVoltage; - float esr; + uint16_t esr; + int16_t nernstV; uint8_t fault; // See wbo::Fault uint8_t heaterState; } __attribute__((packed)); diff --git a/firmware/sampling.cpp b/firmware/sampling.cpp index 62f7b76e..57dee2cb 100644 --- a/firmware/sampling.cpp +++ b/firmware/sampling.cpp @@ -29,6 +29,11 @@ float Sampler::GetNernstAc() const return nernstAc; } +float Sampler::GetNernstV() const +{ + return nernstV; +} + float Sampler::GetPumpNominalCurrent() const { // Gain is 10x, then a 61.9 ohm resistor @@ -105,6 +110,7 @@ void Sampler::ApplySample(AnalogChannelResult& result, float virtualGroundVoltag // Compute AC (difference) and DC (average) components float nernstAcLocal = f_abs(r2_opposite_phase - r_2); nernstDc = (r2_opposite_phase + r_2) / 2; + nernstV = result.NernstVoltage; nernstAc = (1 - ESR_SENSE_ALPHA) * nernstAc + diff --git a/firmware/sampling.h b/firmware/sampling.h index 0c01f061..f9b583b3 100644 --- a/firmware/sampling.h +++ b/firmware/sampling.h @@ -8,6 +8,7 @@ struct ISampler { virtual float GetNernstDc() const = 0; virtual float GetNernstAc() const = 0; + virtual float GetNernstV() const = 0; virtual float GetPumpNominalCurrent() const = 0; virtual float GetInternalBatteryVoltage() const = 0; virtual float GetSensorTemperature() const = 0; @@ -24,6 +25,7 @@ class Sampler : public ISampler float GetNernstDc() const override; float GetNernstAc() const override; + float GetNernstV() const override; float GetPumpNominalCurrent() const override; float GetInternalBatteryVoltage() const override; float GetSensorTemperature() const override; @@ -35,6 +37,7 @@ class Sampler : public ISampler float nernstAc = 0; float nernstDc = 0; + float nernstV = 0; float pumpCurrentSenseVoltage = 0; #ifdef BATTERY_INPUT_DIVIDER From ae9bf40081de8a56a31c152c75eac4ba14f36645 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Fri, 21 Jul 2023 22:23:29 +0300 Subject: [PATCH 08/91] Rename GetInternalBatteryVoltage() to GetInternalHeaterVoltage() --- firmware/heater_control.cpp | 2 +- firmware/livedata.cpp | 2 +- firmware/sampling.cpp | 7 +++---- firmware/sampling.h | 6 +++--- firmware/uart.cpp | 2 +- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/firmware/heater_control.cpp b/firmware/heater_control.cpp index ea019ebb..15a1dd0f 100644 --- a/firmware/heater_control.cpp +++ b/firmware/heater_control.cpp @@ -202,7 +202,7 @@ void HeaterControllerBase::Update(const ISampler& sampler, HeaterAllow heaterAll // If we haven't heard from the ECU, use the internally sensed // battery voltage instead of voltage over CAN. float batteryVoltage = heaterAllowState == HeaterAllow::Unknown - ? sampler.GetInternalBatteryVoltage() + ? sampler.GetInternalHeaterVoltage() : GetRemoteBatteryVoltage(); // Run the state machine diff --git a/firmware/livedata.cpp b/firmware/livedata.cpp index 75a0f2b2..bd50fa44 100644 --- a/firmware/livedata.cpp +++ b/firmware/livedata.cpp @@ -24,7 +24,7 @@ void SamplingUpdateLiveData() const auto& sampler = GetSampler(ch); const auto& heater = GetHeaterController(ch); - float voltage = sampler.GetInternalBatteryVoltage(); + float voltage = sampler.GetInternalHeaterVoltage(); data->lambda = GetLambda(ch); data->temperature = sampler.GetSensorTemperature() * 10; diff --git a/firmware/sampling.cpp b/firmware/sampling.cpp index 57dee2cb..454b3406 100644 --- a/firmware/sampling.cpp +++ b/firmware/sampling.cpp @@ -43,13 +43,12 @@ float Sampler::GetPumpNominalCurrent() const return pumpCurrentSenseVoltage * ratio; } -float Sampler::GetInternalBatteryVoltage() const +float Sampler::GetInternalHeaterVoltage() const { #ifdef BATTERY_INPUT_DIVIDER // Dual HW can measure heater voltage for each channel // by measuring voltage on Heater- while FET is off - // TODO: rename function? - return internalBatteryVoltage; + return internalHeaterVoltage; #else // After 5 seconds, pretend that we get battery voltage. // This makes the controller usable without CAN control @@ -122,7 +121,7 @@ void Sampler::ApplySample(AnalogChannelResult& result, float virtualGroundVoltag PUMP_FILTER_ALPHA * (result.PumpCurrentVoltage - virtualGroundVoltageInt); #ifdef BATTERY_INPUT_DIVIDER - internalBatteryVoltage = result.BatteryVoltage; + internalHeaterVoltage = result.HeaterVoltage; #endif // Shift history over by one diff --git a/firmware/sampling.h b/firmware/sampling.h index f9b583b3..35631916 100644 --- a/firmware/sampling.h +++ b/firmware/sampling.h @@ -10,7 +10,7 @@ struct ISampler virtual float GetNernstAc() const = 0; virtual float GetNernstV() const = 0; virtual float GetPumpNominalCurrent() const = 0; - virtual float GetInternalBatteryVoltage() const = 0; + virtual float GetInternalHeaterVoltage() const = 0; virtual float GetSensorTemperature() const = 0; virtual float GetSensorInternalResistance() const = 0; }; @@ -27,7 +27,7 @@ class Sampler : public ISampler float GetNernstAc() const override; float GetNernstV() const override; float GetPumpNominalCurrent() const override; - float GetInternalBatteryVoltage() const override; + float GetInternalHeaterVoltage() const override; float GetSensorTemperature() const override; float GetSensorInternalResistance() const override; @@ -41,7 +41,7 @@ class Sampler : public ISampler float pumpCurrentSenseVoltage = 0; #ifdef BATTERY_INPUT_DIVIDER - float internalBatteryVoltage = 0; + float internalHeaterVoltage = 0; #endif Timer m_startupTimer; diff --git a/firmware/uart.cpp b/firmware/uart.cpp index 4e779cd4..127a488e 100644 --- a/firmware/uart.cpp +++ b/firmware/uart.cpp @@ -39,7 +39,7 @@ static void UartThread(void*) float lambda = GetLambda(ch); int lambdaIntPart = lambda; int lambdaThousandths = (lambda - lambdaIntPart) * 1000; - int batteryVoltageMv = GetSampler(ch).GetInternalBatteryVoltage() * 1000; + int batteryVoltageMv = GetSampler(ch).GetInternalHeaterVoltage() * 1000; int duty = GetHeaterDuty(ch) * 100; size_t writeCount = chsnprintf(printBuffer, 200, From 7918a0fcf72abb893c52f4d2bdf6ec3da63c1a1e Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Fri, 21 Jul 2023 22:50:29 +0300 Subject: [PATCH 09/91] sampling, heater: fix Battery vs Heater naming mess --- firmware/boards/f0_module/port.cpp | 2 +- firmware/boards/f1_dual/port.cpp | 4 ++-- firmware/boards/f1_dual_rev1/port.cpp | 4 ++-- firmware/boards/f1_rev2/port.cpp | 7 +++++-- firmware/boards/f1_rev3/port.cpp | 7 +++++-- firmware/boards/port.h | 3 ++- firmware/heater_control.cpp | 20 ++++++++++---------- firmware/heater_control.h | 2 +- firmware/sampling.cpp | 2 +- firmware/wideband_config.h | 8 ++++---- 10 files changed, 33 insertions(+), 26 deletions(-) diff --git a/firmware/boards/f0_module/port.cpp b/firmware/boards/f0_module/port.cpp index 4e965ea8..1b1c0565 100644 --- a/firmware/boards/f0_module/port.cpp +++ b/firmware/boards/f0_module/port.cpp @@ -47,7 +47,7 @@ AnalogResult AnalogSample() { .NernstVoltage = AverageSamples(adcBuffer, 0) * (1.0 / NERNST_INPUT_GAIN), .PumpCurrentVoltage = AverageSamples(adcBuffer, 1), - .BatteryVoltage = 0, + .HeaterSupplyVoltage = 0, }, }, .VirtualGroundVoltageInt = AverageSamples(adcBuffer, 2), diff --git a/firmware/boards/f1_dual/port.cpp b/firmware/boards/f1_dual/port.cpp index 9b4b45ce..40cff46e 100644 --- a/firmware/boards/f1_dual/port.cpp +++ b/firmware/boards/f1_dual/port.cpp @@ -111,13 +111,13 @@ AnalogResult AnalogSample() /* left */ .NernstVoltage = AverageSamples(adcBuffer, 3) * (1.0 / NERNST_INPUT_GAIN), .PumpCurrentVoltage = AverageSamples(adcBuffer, 2), - .BatteryVoltage = l_heater_voltage, + .HeaterSupplyVoltage = l_heater_voltage, }, { /* right */ .NernstVoltage = AverageSamples(adcBuffer, 1) * (1.0 / NERNST_INPUT_GAIN), .PumpCurrentVoltage = AverageSamples(adcBuffer, 0), - .BatteryVoltage = r_heater_voltage, + .HeaterSupplyVoltage = r_heater_voltage, }, }, /* Dual board has separate internal virtual ground = 3.3V / 2 diff --git a/firmware/boards/f1_dual_rev1/port.cpp b/firmware/boards/f1_dual_rev1/port.cpp index dd3c29bc..5e4c8538 100644 --- a/firmware/boards/f1_dual_rev1/port.cpp +++ b/firmware/boards/f1_dual_rev1/port.cpp @@ -135,10 +135,10 @@ AnalogResult AnalogSample() } /* left */ res.ch[0].PumpCurrentVoltage = AverageSamples(adcBuffer, 2); - res.ch[0].BatteryVoltage = l_heater_voltage; + res.ch[0].HeaterSupplyVoltage = l_heater_voltage; /* right */ res.ch[1].PumpCurrentVoltage = AverageSamples(adcBuffer, 0); - res.ch[1].BatteryVoltage = r_heater_voltage; + res.ch[1].HeaterSupplyVoltage = r_heater_voltage; return res; } diff --git a/firmware/boards/f1_rev2/port.cpp b/firmware/boards/f1_rev2/port.cpp index 294f582c..5836f713 100644 --- a/firmware/boards/f1_rev2/port.cpp +++ b/firmware/boards/f1_rev2/port.cpp @@ -66,8 +66,11 @@ AnalogResult AnalogSample() .PumpCurrentVoltage = AverageSamples(adcBuffer, 1), /* We also can measure output virtual ground voltage for diagnostic purposes */ //.VirtualGroundVoltageExt = AverageSamples(adcBuffer, 0) / VM_INPUT_DIVIDER, - .BatteryVoltage = AverageSamples(adcBuffer, 3) / BATTERY_INPUT_DIVIDER, - /* .HeaterVoltage = AverageSamples(adcBuffer, 4) / HEATER_INPUT_DIVIDER, */ + /* Heater measurement circuit has incorrect RC filter making inposible accurate + * measurement when heater pwm has high duty + * Assume WBO supply voltage == heater supply voltage */ + .HeaterSupplyVoltage = AverageSamples(adcBuffer, 3) / BATTERY_INPUT_DIVIDER, + /* .HeaterSupplyVoltage = AverageSamples(adcBuffer, 4) / HEATER_INPUT_DIVIDER, */ }, }, /* Rev 2 board has separate internal virtual ground = 3.3V / 2 diff --git a/firmware/boards/f1_rev3/port.cpp b/firmware/boards/f1_rev3/port.cpp index 39af3af2..11bdf974 100644 --- a/firmware/boards/f1_rev3/port.cpp +++ b/firmware/boards/f1_rev3/port.cpp @@ -63,8 +63,11 @@ AnalogResult AnalogSample() .PumpCurrentVoltage = AverageSamples(adcBuffer, 1), /* We also can measure output virtual ground voltage for diagnostic purposes */ //.VirtualGroundVoltageExt = AverageSamples(adcBuffer, 0) / VM_INPUT_DIVIDER, - .BatteryVoltage = AverageSamples(adcBuffer, 3) / BATTERY_INPUT_DIVIDER, - /* .HeaterVoltage = AverageSamples(adcBuffer, 4) / HEATER_INPUT_DIVIDER, */ + /* Heater measurement circuit has incorrect RC filter making inposible accurate + * measurement when heater pwm has high duty + * Assume WBO supply voltage == heater supply voltage */ + .HeaterSupplyVoltage = AverageSamples(adcBuffer, 3) / BATTERY_INPUT_DIVIDER, + /* .HeaterSupplyVoltage = AverageSamples(adcBuffer, 4) / HEATER_INPUT_DIVIDER, */ }, }, /* Rev 2 board has separate internal virtual ground = 3.3V / 2 diff --git a/firmware/boards/port.h b/firmware/boards/port.h index c7c063d3..d8a94e08 100644 --- a/firmware/boards/port.h +++ b/firmware/boards/port.h @@ -12,13 +12,14 @@ struct AnalogChannelResult float PumpCurrentVoltage; /* for dual version - this is voltage on Heater-, switches between zero and Vbatt with heater PWM, * used for both Vbatt measurement and Heater diagnostic */ - float BatteryVoltage; + float HeaterSupplyVoltage; }; struct AnalogResult { AnalogChannelResult ch[AFR_CHANNELS]; float VirtualGroundVoltageInt; + /* TODO: add SupplyVoltage - some boards can measure supply voltage */ }; AnalogResult AnalogSample(); diff --git a/firmware/heater_control.cpp b/firmware/heater_control.cpp index 15a1dd0f..579e2f29 100644 --- a/firmware/heater_control.cpp +++ b/firmware/heater_control.cpp @@ -19,7 +19,7 @@ void HeaterControllerBase::Configure(float targetTempC, float targetEsr) m_preheatTimer.reset(); m_warmupTimer.reset(); - m_batteryStableTimer.reset(); + m_heaterStableTimer.reset(); m_closedLoopStableTimer.reset(); } @@ -38,7 +38,7 @@ HeaterState HeaterControllerBase::GetHeaterState() const return heaterState; } -HeaterState HeaterControllerBase::GetNextState(HeaterState currentState, HeaterAllow heaterAllowState, float batteryVoltage, float sensorTemp) +HeaterState HeaterControllerBase::GetNextState(HeaterState currentState, HeaterAllow heaterAllowState, float heaterSupplyVoltage, float sensorTemp) { bool heaterAllowed = heaterAllowState == HeaterAllow::Allowed; @@ -46,17 +46,17 @@ HeaterState HeaterControllerBase::GetNextState(HeaterState currentState, HeaterA if (heaterAllowState == HeaterAllow::Unknown) { // measured voltage too low to auto-start heating - if (batteryVoltage < HEATER_BATTETY_OFF_VOLTAGE) + if (heaterSupplyVoltage < HEATER_SUPPLY_OFF_VOLTAGE) { - m_batteryStableTimer.reset(); + m_heaterStableTimer.reset(); // set fault SetFault(ch, Fault::SensorNoHeatSupply); return HeaterState::NoHeaterSupply; } - else if (batteryVoltage > HEATER_BATTERY_ON_VOLTAGE) + else if (heaterSupplyVoltage > HEATER_SUPPLY_ON_VOLTAGE) { // measured voltage is high enougth to auto-start heating, wait some time to stabilize - heaterAllowed = m_batteryStableTimer.hasElapsedSec(HEATER_BATTERY_STAB_TIME); + heaterAllowed = m_heaterStableTimer.hasElapsedSec(HEATER_BATTERY_STAB_TIME); } } @@ -201,12 +201,12 @@ void HeaterControllerBase::Update(const ISampler& sampler, HeaterAllow heaterAll // If we haven't heard from the ECU, use the internally sensed // battery voltage instead of voltage over CAN. - float batteryVoltage = heaterAllowState == HeaterAllow::Unknown + float heaterSupplyVoltage = heaterAllowState == HeaterAllow::Unknown ? sampler.GetInternalHeaterVoltage() : GetRemoteBatteryVoltage(); // Run the state machine - heaterState = GetNextState(heaterState, heaterAllowState, batteryVoltage, sensorTemperature); + heaterState = GetNextState(heaterState, heaterAllowState, heaterSupplyVoltage, sensorTemperature); float heaterVoltage = GetVoltageForState(heaterState, sensorEsr); // Limit to 12 volts @@ -215,7 +215,7 @@ void HeaterControllerBase::Update(const ISampler& sampler, HeaterAllow heaterAll } // duty = (V_eff / V_batt) ^ 2 - float voltageRatio = (batteryVoltage < 1.0f) ? 0 : heaterVoltage / batteryVoltage; + float voltageRatio = (heaterSupplyVoltage < 1.0f) ? 0 : heaterVoltage / heaterSupplyVoltage; float duty = voltageRatio * voltageRatio; #ifdef HEATER_MAX_DUTY @@ -228,7 +228,7 @@ void HeaterControllerBase::Update(const ISampler& sampler, HeaterAllow heaterAll } #endif - if (batteryVoltage >= 23) + if (heaterSupplyVoltage >= 23) { duty = 0; heaterVoltage = 0; diff --git a/firmware/heater_control.h b/firmware/heater_control.h index fd344d64..35854843 100644 --- a/firmware/heater_control.h +++ b/firmware/heater_control.h @@ -72,7 +72,7 @@ class HeaterControllerBase : public IHeaterController int m_retryTime = 0; - Timer m_batteryStableTimer; + Timer m_heaterStableTimer; Timer m_preheatTimer; Timer m_warmupTimer; Timer m_closedLoopStableTimer; diff --git a/firmware/sampling.cpp b/firmware/sampling.cpp index 454b3406..c3aba151 100644 --- a/firmware/sampling.cpp +++ b/firmware/sampling.cpp @@ -121,7 +121,7 @@ void Sampler::ApplySample(AnalogChannelResult& result, float virtualGroundVoltag PUMP_FILTER_ALPHA * (result.PumpCurrentVoltage - virtualGroundVoltageInt); #ifdef BATTERY_INPUT_DIVIDER - internalHeaterVoltage = result.HeaterVoltage; + internalHeaterVoltage = result.HeaterSupplyVoltage; #endif // Shift history over by one diff --git a/firmware/wideband_config.h b/firmware/wideband_config.h index 34c06c7f..e9e01f1f 100644 --- a/firmware/wideband_config.h +++ b/firmware/wideband_config.h @@ -50,7 +50,7 @@ #define HEATER_OVERHEAT_RETRY_TIMEOUT 60 #define HEATER_UNDERHEAT_RETRY_TIMEOUT 30 -// minimal battery voltage to start heating without CAN command -#define HEATER_BATTERY_ON_VOLTAGE 9.5 -// mininal battery voltage to continue heating -#define HEATER_BATTETY_OFF_VOLTAGE 8.5 +// minimal heater voltage to start heating without CAN command +#define HEATER_SUPPLY_ON_VOLTAGE 9.5 +// mininal heater voltage to continue heating +#define HEATER_SUPPLY_OFF_VOLTAGE 8.5 From a3b5321cde78cd09b1e45c5973a08d3ec2dcbcec Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Fri, 21 Jul 2023 23:06:06 +0300 Subject: [PATCH 10/91] heater: always rely on localy measured heater voltage if board able to measure it localy --- firmware/heater_control.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/firmware/heater_control.cpp b/firmware/heater_control.cpp index 579e2f29..2c072b3d 100644 --- a/firmware/heater_control.cpp +++ b/firmware/heater_control.cpp @@ -199,11 +199,13 @@ void HeaterControllerBase::Update(const ISampler& sampler, HeaterAllow heaterAll float sensorEsr = sampler.GetSensorInternalResistance(); float sensorTemperature = sampler.GetSensorTemperature(); - // If we haven't heard from the ECU, use the internally sensed - // battery voltage instead of voltage over CAN. - float heaterSupplyVoltage = heaterAllowState == HeaterAllow::Unknown - ? sampler.GetInternalHeaterVoltage() - : GetRemoteBatteryVoltage(); + #ifdef HEATER_INPUT_DIVIDER + // if board has ability to measure heater supply localy - use it + float heaterSupplyVoltage = sampler.GetInternalHeaterVoltage(); + #else + // this board rely on measured voltage from ECU + float heaterSupplyVoltage = GetRemoteBatteryVoltage(); + #endif // Run the state machine heaterState = GetNextState(heaterState, heaterAllowState, heaterSupplyVoltage, sensorTemperature); From 3bf989b374abf46d28f76d6950ddd5f936b52e73 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 24 Sep 2023 18:01:46 +0300 Subject: [PATCH 11/91] build: fix hex file generation Now hex file contains OpenBLT crc for main FW. So flashed hex should start main FW now. --- firmware/boards/build_f1_board.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/boards/build_f1_board.sh b/firmware/boards/build_f1_board.sh index 63fe6051..22551c56 100755 --- a/firmware/boards/build_f1_board.sh +++ b/firmware/boards/build_f1_board.sh @@ -65,8 +65,8 @@ if [ $USE_OPENBLT = "yes" ]; then echo "" echo "Invoking hex2dfu for composite OpenBLT+Wideband image (for DFU util)" $HEX2DFU -i ${OPENBLT_HEX} -i build/wideband.hex -C 0x1C -o ${DELIVER_DIR}/wideband.dfu -b ${DELIVER_DIR}/wideband.bin - echo "Combining two hex files into composite hex file" - $SREC_CAT ${OPENBLT_HEX} -Intel build/wideband.hex -Intel -o ${DELIVER_DIR}/wideband.hex -Intel + echo "Creating composite hex file" + $SREC_CAT ${DELIVER_DIR}/wideband.bin -binary -offset 0x08000000 -o ${DELIVER_DIR}/wideband.hex -Intel else echo "Bin for raw flashing" cp build/wideband.bin ${DELIVER_DIR} From daf4867d60b1baa71319a0bf7da579eba51f39e4 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 24 Sep 2023 18:03:16 +0300 Subject: [PATCH 12/91] Fix reset to DFU command --- firmware/Makefile | 10 ++--- firmware/boards/f1_common/f1_port.cpp | 41 +++++++++++++++++-- firmware/boards/f1_dual_rev1/board.c | 6 +++ .../boards/f1_dual_rev1/wideband_layout.ld | 9 ++-- firmware/boards/port.h | 3 ++ firmware/console/binary/tunerstudio.cpp | 6 +-- 6 files changed, 57 insertions(+), 18 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index a543e67c..06446207 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -136,7 +136,9 @@ LDSCRIPT=app.ld # C sources that can be compiled in ARM or THUMB mode depending on the global # setting. -CSRC = $(ALLCSRC) $(BOARDDIR)/board.c +CSRC = $(ALLCSRC) \ + $(BOARDDIR)/board.c \ + boards/f1_common/openblt/shared_params.c # C++ sources that can be compiled in ARM or THUMB mode depending on the global # setting. @@ -187,7 +189,8 @@ INCDIR = $(CONFDIR) \ console/binary/ \ boards/ \ shared/ \ - $(BOARDDIR)/io/ + $(BOARDDIR)/io/ \ + boards/f1_common/openblt # Define C warning options here. CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes @@ -236,9 +239,6 @@ ifeq ($(USE_OPENBLT),yes) # Reserve start of flash for OpenBLT USE_OPT += -Wl,--defsym=USE_BOOTLOADER=1 DDEFS += -DUSE_OPENBLT=TRUE - # Shared params - INCDIR += boards/f1_common/openblt - CSRC += boards/f1_common/openblt/shared_params.c endif # diff --git a/firmware/boards/f1_common/f1_port.cpp b/firmware/boards/f1_common/f1_port.cpp index 9de40483..c11821fa 100644 --- a/firmware/boards/f1_common/f1_port.cpp +++ b/firmware/boards/f1_common/f1_port.cpp @@ -5,12 +5,11 @@ #include "hal.h" #include "hal_mfs.h" -#if USE_OPENBLT -/* communication with OpenBLT that is plain C, not to modify external file */ +/* communication with OpenBLT that is plain C, not to modify external file + * Same code used to store "DFU-requested" flag */ extern "C" { #include "openblt/shared_params.h" }; -#endif // Storage // TODO: runtime detection? @@ -139,7 +138,7 @@ void rebootNow() void rebootToOpenblt() { -#if USE_OPENBLT +#ifdef USE_OPENBLT /* safe to call on already inited shares area */ SharedParamsInit(); /* Store flag to stay in OpenBLT */ @@ -149,6 +148,40 @@ void rebootToOpenblt() #endif } +void rebootToDfu() +{ + /* safe to call on already inited shares area */ + SharedParamsInit(); + /* Store flag to jump to DFU at main FW init */ + SharedParamsWriteByIndex(0, 0x02); + + rebootNow(); +} + +// stm32f10x XL-density devices +//#define BOOTLOADER_FW_ADDRESS 0x1FFFE000 +// stm32f10x devices +#define BOOTLOADER_FW_ADDRESS 0x1FFFF000 + +void checkDfuAndJump() +{ + uint8_t val; + if (SharedParamsReadByIndex(0, &val) == true) { + if (val == 0x02) { + // reset flag + SharedParamsWriteByIndex(0, 0x00); + + // AN2606 says: 2 Kbytes, starting from address 0x1FFFF000 contain the bootloader firmware. + // Point the PC to the System Memory reset vector (+4) + void (*SysMemBootJump)(void) = (void (*)(void)) (*((uint32_t *) (BOOTLOADER_FW_ADDRESS + 4))); + // Pick stack address from vector table + __set_MSP(*(__IO uint32_t*) BOOTLOADER_FW_ADDRESS); + SysMemBootJump(); + while (1); + } + } +} + void ToggleESRDriver(SensorType sensor) { switch (sensor) { diff --git a/firmware/boards/f1_dual_rev1/board.c b/firmware/boards/f1_dual_rev1/board.c index 1b451928..df80d0d5 100644 --- a/firmware/boards/f1_dual_rev1/board.c +++ b/firmware/boards/f1_dual_rev1/board.c @@ -17,6 +17,9 @@ #include "hal.h" #include "io_pins.h" +//#include "port.h" +extern void checkDfuAndJump(); + /** * @brief PAL setup. * @details Digital I/O ports static configuration as defined in @p board.h. @@ -41,6 +44,9 @@ const PALConfig pal_default_config = * any other initialization. */ void __early_init(void) { + /* Check if requested to jump to DFU */ + checkDfuAndJump(); + stm32_clock_init(); } diff --git a/firmware/boards/f1_dual_rev1/wideband_layout.ld b/firmware/boards/f1_dual_rev1/wideband_layout.ld index bd5d7ed7..00896070 100644 --- a/firmware/boards/f1_dual_rev1/wideband_layout.ld +++ b/firmware/boards/f1_dual_rev1/wideband_layout.ld @@ -5,8 +5,9 @@ /* OpenBLT code */ _OpenBLT_Flash_Size = DEFINED(USE_BOOTLOADER) ? 8k : 0; -/* OpenBLT <-> main FW shared area */ -_OpenBLT_Shared_Params_Size = DEFINED(USE_BOOTLOADER) ? 16 : 0; +/* OpenBLT <-> main FW shared area same area used to pass some data between restarts + * Now always enabled */ +Shared_Params_Size = 16; MEMORY { @@ -21,8 +22,8 @@ MEMORY flash5 (rx) : org = 0x00000000, len = 0 flash6 (rx) : org = 0x00000000, len = 0 flash7 (rx) : org = 0x00000000, len = 0 - shared (wx) : org = 0x20000000, len = _OpenBLT_Shared_Params_Size - ram0 (wx) : org = 0x20000000 + _OpenBLT_Shared_Params_Size, len = 48k - _OpenBLT_Shared_Params_Size + shared (wx) : org = 0x20000000, len = Shared_Params_Size + ram0 (wx) : org = 0x20000000 + Shared_Params_Size, len = 48k - Shared_Params_Size ram1 (wx) : org = 0x00000000, len = 0 ram2 (wx) : org = 0x00000000, len = 0 ram3 (wx) : org = 0x00000000, len = 0 diff --git a/firmware/boards/port.h b/firmware/boards/port.h index d8a94e08..02e9d59e 100644 --- a/firmware/boards/port.h +++ b/firmware/boards/port.h @@ -82,6 +82,9 @@ const char *getTsSignature(); void rebootNow(); void rebootToOpenblt(); +void rebootToDfu(); + +extern "C" void checkDfuAndJump(); // LSU4.2, LSU4.9 or LSU_ADV SensorType GetSensorType(); diff --git a/firmware/console/binary/tunerstudio.cpp b/firmware/console/binary/tunerstudio.cpp index dcfa1b4b..0448c7a8 100644 --- a/firmware/console/binary/tunerstudio.cpp +++ b/firmware/console/binary/tunerstudio.cpp @@ -208,15 +208,13 @@ static void handleIoTestCommand(TsChannelBase* tsChannel, ts_response_format_e m /* index is not used yet */ switch (subsystem) { -#if 0 /* DFU */ case 0xba: /* Send ok to make TS happy, wait until sent */ sendOkResponse(tsChannel, TS_CRC); chThdSleepMilliseconds(100); - jump_to_bootloader(); + rebootToDfu(); break; -#endif case 0xbb: /* Send ok to make TS happy, wait until sent */ @@ -225,7 +223,6 @@ static void handleIoTestCommand(TsChannelBase* tsChannel, ts_response_format_e m rebootNow(); break; -#if USE_OPENBLT case 0xbc: /* Send ok to make TS happy, wait until sent */ sendOkResponse(tsChannel, TS_CRC); @@ -233,7 +230,6 @@ static void handleIoTestCommand(TsChannelBase* tsChannel, ts_response_format_e m /* Jump to OpenBLT if present */ rebootToOpenblt(); break; -#endif default: tunerStudioError(tsChannel, "Unexpected IoTest command"); From 0b876f6f084056747d14896773d8e106fef874ec Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 25 Sep 2023 19:28:03 +0300 Subject: [PATCH 13/91] Add reset to DFU script Calling this command from TunerStudio seems to reset device to DFU mode, but TS attempts to continue communication breaks something and device does not reply to DFU tools. This script symply sends reset to dfu commant to tty device --- firmware/reset_to_dfu.sh | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100755 firmware/reset_to_dfu.sh diff --git a/firmware/reset_to_dfu.sh b/firmware/reset_to_dfu.sh new file mode 100755 index 00000000..49e5ecfd --- /dev/null +++ b/firmware/reset_to_dfu.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +DEV=/dev/ttyUSB0 + +#115200 +stty -F $DEV speed 115200 cs8 -cstopb -parenb > /dev/null +#Send cmd_dfu +printf '%b' '\x00\x05\x5A\x00\xBA\x00\x00\x7C\x48\x5B\xB1' > $DEV From 1c5a58d91400a7665eda3ce907222a2318d44376 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sat, 14 Oct 2023 21:10:42 +0300 Subject: [PATCH 14/91] sampling: do not try to calculate ESR if NerstAc is clamped --- firmware/boards/f0_module/port.cpp | 1 + firmware/boards/f1_dual/port.cpp | 4 ++++ firmware/boards/f1_dual_rev1/port.cpp | 9 +++++++-- firmware/boards/f1_rev2/port.cpp | 2 ++ firmware/boards/f1_rev3/port.cpp | 2 ++ firmware/boards/port.h | 2 ++ firmware/sampling.cpp | 14 ++++++++++++++ firmware/sampling.h | 1 + test/tests/test_sampler.cpp | 3 +++ 9 files changed, 36 insertions(+), 2 deletions(-) diff --git a/firmware/boards/f0_module/port.cpp b/firmware/boards/f0_module/port.cpp index 1b1c0565..d551e9d5 100644 --- a/firmware/boards/f0_module/port.cpp +++ b/firmware/boards/f0_module/port.cpp @@ -48,6 +48,7 @@ AnalogResult AnalogSample() .NernstVoltage = AverageSamples(adcBuffer, 0) * (1.0 / NERNST_INPUT_GAIN), .PumpCurrentVoltage = AverageSamples(adcBuffer, 1), .HeaterSupplyVoltage = 0, + .NernstClamped = false, }, }, .VirtualGroundVoltageInt = AverageSamples(adcBuffer, 2), diff --git a/firmware/boards/f1_dual/port.cpp b/firmware/boards/f1_dual/port.cpp index 40cff46e..44bc3b16 100644 --- a/firmware/boards/f1_dual/port.cpp +++ b/firmware/boards/f1_dual/port.cpp @@ -112,12 +112,16 @@ AnalogResult AnalogSample() .NernstVoltage = AverageSamples(adcBuffer, 3) * (1.0 / NERNST_INPUT_GAIN), .PumpCurrentVoltage = AverageSamples(adcBuffer, 2), .HeaterSupplyVoltage = l_heater_voltage, + /* TODO: */ + .NernstClamped = false, }, { /* right */ .NernstVoltage = AverageSamples(adcBuffer, 1) * (1.0 / NERNST_INPUT_GAIN), .PumpCurrentVoltage = AverageSamples(adcBuffer, 0), .HeaterSupplyVoltage = r_heater_voltage, + /* TODO: */ + .NernstClamped = false, }, }, /* Dual board has separate internal virtual ground = 3.3V / 2 diff --git a/firmware/boards/f1_dual_rev1/port.cpp b/firmware/boards/f1_dual_rev1/port.cpp index 5e4c8538..fd26c8b2 100644 --- a/firmware/boards/f1_dual_rev1/port.cpp +++ b/firmware/boards/f1_dual_rev1/port.cpp @@ -124,13 +124,18 @@ AnalogResult AnalogSample() res.VirtualGroundVoltageInt = HALF_VCC; for (int i = 0; i < AFR_CHANNELS; i++) { + res.ch[i].NernstClamped = false; float NernstRaw = AverageSamples(adcBuffer, (i == 0) ? 3 : 1); - if ((NernstRaw > 0.01) && (NernstRaw < (3.3 - 0.01))) { + if ((NernstRaw > 0.01) && (NernstRaw < (VCC_VOLTS - 0.01))) { /* not clamped */ res.ch[i].NernstVoltage = (NernstRaw - NERNST_INPUT_OFFSET) * (1.0 / NERNST_INPUT_GAIN); } else { /* Clamped, use ungained input */ - res.ch[i].NernstVoltage = AverageSamples(adcBuffer, (i == 0) ? 9 : 8) - HALF_VCC; + NernstRaw = AverageSamples(adcBuffer, (i == 0) ? 9 : 8) - HALF_VCC; + if ((NernstRaw > 0.01) && (NernstRaw < (VCC_VOLTS - 0.01))) { + res.ch[i].NernstClamped = true; + } + res.ch[i].NernstVoltage = NernstRaw; } } /* left */ diff --git a/firmware/boards/f1_rev2/port.cpp b/firmware/boards/f1_rev2/port.cpp index 5836f713..080234b7 100644 --- a/firmware/boards/f1_rev2/port.cpp +++ b/firmware/boards/f1_rev2/port.cpp @@ -71,6 +71,8 @@ AnalogResult AnalogSample() * Assume WBO supply voltage == heater supply voltage */ .HeaterSupplyVoltage = AverageSamples(adcBuffer, 3) / BATTERY_INPUT_DIVIDER, /* .HeaterSupplyVoltage = AverageSamples(adcBuffer, 4) / HEATER_INPUT_DIVIDER, */ + /* TODO: */ + .NernstClamped = false, }, }, /* Rev 2 board has separate internal virtual ground = 3.3V / 2 diff --git a/firmware/boards/f1_rev3/port.cpp b/firmware/boards/f1_rev3/port.cpp index 11bdf974..cc26fd10 100644 --- a/firmware/boards/f1_rev3/port.cpp +++ b/firmware/boards/f1_rev3/port.cpp @@ -68,6 +68,8 @@ AnalogResult AnalogSample() * Assume WBO supply voltage == heater supply voltage */ .HeaterSupplyVoltage = AverageSamples(adcBuffer, 3) / BATTERY_INPUT_DIVIDER, /* .HeaterSupplyVoltage = AverageSamples(adcBuffer, 4) / HEATER_INPUT_DIVIDER, */ + /* TODO: */ + .NernstClamped = false, }, }, /* Rev 2 board has separate internal virtual ground = 3.3V / 2 diff --git a/firmware/boards/port.h b/firmware/boards/port.h index 02e9d59e..406e3b9e 100644 --- a/firmware/boards/port.h +++ b/firmware/boards/port.h @@ -13,6 +13,8 @@ struct AnalogChannelResult /* for dual version - this is voltage on Heater-, switches between zero and Vbatt with heater PWM, * used for both Vbatt measurement and Heater diagnostic */ float HeaterSupplyVoltage; + /* If measured voltage is too close to ground or Vref assume value is clamped */ + bool NernstClamped; }; struct AnalogResult diff --git a/firmware/sampling.cpp b/firmware/sampling.cpp index c3aba151..43ffad8c 100644 --- a/firmware/sampling.cpp +++ b/firmware/sampling.cpp @@ -82,6 +82,13 @@ float Sampler::GetSensorTemperature() const float Sampler::GetSensorInternalResistance() const { + if (nernstClamped) + { + // TODO: report disconnected error? + // Return some non-realistic value + return 10000; + } + // Sensor is the lowside of a divider, top side is GetESRSupplyR(), and 3.3v AC pk-pk is injected float totalEsr = GetESRSupplyR() / (VCC_VOLTS / GetNernstAc() - 1); @@ -99,6 +106,13 @@ void Sampler::ApplySample(AnalogChannelResult& result, float virtualGroundVoltag { float r_1 = result.NernstVoltage; + // If value is close to ADC limit... + if (result.NernstClamped) { + nernstClamped = 100; + } else if (nernstClamped) { + nernstClamped--; + } + // r2_opposite_phase estimates where the previous sample would be had we not been toggling // AKA the absolute value of the difference between r2_opposite_phase and r2 is the amplitude // of the AC component on the nernst voltage. We have to pull this trick so as to use the past 3 diff --git a/firmware/sampling.h b/firmware/sampling.h index 35631916..a3e86332 100644 --- a/firmware/sampling.h +++ b/firmware/sampling.h @@ -39,6 +39,7 @@ class Sampler : public ISampler float nernstDc = 0; float nernstV = 0; float pumpCurrentSenseVoltage = 0; + int nernstClamped = 0; #ifdef BATTERY_INPUT_DIVIDER float internalHeaterVoltage = 0; diff --git a/test/tests/test_sampler.cpp b/test/tests/test_sampler.cpp index 42debf66..365f3fba 100644 --- a/test/tests/test_sampler.cpp +++ b/test/tests/test_sampler.cpp @@ -21,6 +21,7 @@ TEST(Sampler, TestDc) AnalogChannelResult data; data.NernstVoltage = 0.45f; data.PumpCurrentVoltage = 1.75f; + data.NernstClamped = false; constexpr float virtualGroundVoltage = 1.65f; for (size_t i = 0; i < 5000; i++) @@ -41,10 +42,12 @@ TEST(Sampler, TestAc) AnalogChannelResult dataLow; dataLow.NernstVoltage = 0.45f - 0.1f; dataLow.PumpCurrentVoltage = 1.75f; + dataLow.NernstClamped = false; AnalogChannelResult dataHigh; dataHigh.NernstVoltage = 0.45f + 0.1f; dataHigh.PumpCurrentVoltage = 1.75f; + dataHigh.NernstClamped = false; constexpr float virtualGroundVoltage = 1.65f; From 2b0505d09efbabb314cb60acf9b4a35d376f1996 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 16 Oct 2023 18:13:21 +0300 Subject: [PATCH 15/91] openbtl: f1_dual_rev1: enable OpenBLT on USART2 (Bluetooth) --- firmware/boards/f1_dual_rev1/io/io_pins.h | 5 ++++ .../boards/f1_dual_rev1/openblt/blt_conf.h | 11 +++++++-- firmware/boards/f1_dual_rev1/openblt/main.c | 23 +++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/firmware/boards/f1_dual_rev1/io/io_pins.h b/firmware/boards/f1_dual_rev1/io/io_pins.h index 88d98a54..5e6112e1 100644 --- a/firmware/boards/f1_dual_rev1/io/io_pins.h +++ b/firmware/boards/f1_dual_rev1/io/io_pins.h @@ -16,6 +16,11 @@ #define LL_UART_TX_PIN LL_GPIO_PIN_9 #define LL_UART_RX_PIN LL_GPIO_PIN_10 +// Communication - secondary (BT) UART +#define SEC_UART_GPIO_PORT GPIOC +#define SEC_LL_UART_TX_PIN LL_GPIO_PIN_10 +#define SEC_LL_UART_RX_PIN LL_GPIO_PIN_11 + // Communication - CAN1 #define CAN_GPIO_PORT GPIOA #define LL_CAN_TX_PIN LL_GPIO_PIN_12 diff --git a/firmware/boards/f1_dual_rev1/openblt/blt_conf.h b/firmware/boards/f1_dual_rev1/openblt/blt_conf.h index ec478dcc..650cef64 100644 --- a/firmware/boards/f1_dual_rev1/openblt/blt_conf.h +++ b/firmware/boards/f1_dual_rev1/openblt/blt_conf.h @@ -74,8 +74,15 @@ /** \brief Configure number of bytes in the host->target data packet. */ #define BOOT_COM_RS232_RX_MAX_DATA (64) /** \brief Select the desired UART peripheral as a zero based index. */ -#define BOOT_COM_RS232_CHANNEL_INDEX (0) - +//#define BOOT_COM_RS232_CHANNEL_INDEX (0) + +#define BOOT_COM_RS232_CHANNELS_N 2 +#define BOOT_COM_RS232_CHANNEL_INDEXES {0, 2} +#define BOOT_COM_RS232_CHANNEL_DEVS {(USART1), (USART3)} +// BOOT_COM_RS232_CHANNEL_INDEXES[0] +#define BOOT_COM_RS232_CHANNEL_DEFAULT_INDEX 0 +// BOOT_COM_RS232_CHANNEL_DEVS[0] +#define BOOT_COM_RS232_CHANNEL_DEFAULT_DEV USART1 /**************************************************************************************** * B A C K D O O R E N T R Y C O N F I G U R A T I O N diff --git a/firmware/boards/f1_dual_rev1/openblt/main.c b/firmware/boards/f1_dual_rev1/openblt/main.c index 0c8d0879..5e9c1920 100644 --- a/firmware/boards/f1_dual_rev1/openblt/main.c +++ b/firmware/boards/f1_dual_rev1/openblt/main.c @@ -128,6 +128,7 @@ void HAL_MspInit(void) /* GPIO ports clock enable. */ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA); LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOB); + LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOC); #if (BOOT_COM_RS232_ENABLE > 0) /* UART clock enable. */ @@ -142,6 +143,23 @@ void HAL_MspInit(void) GPIO_InitStruct.Mode = LL_GPIO_MODE_FLOATING; GPIO_InitStruct.Pull = LL_GPIO_PULL_UP; LL_GPIO_Init(UART_GPIO_PORT, &GPIO_InitStruct); +#if (BOOT_COM_RS232_CHANNELS_N > 1) + /* USART3 at PC10, PC11 */ + /* UART clock enable. */ + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART3); + /* UART TX and RX GPIO pin configuration. */ + GPIO_InitStruct.Pin = SEC_LL_UART_TX_PIN; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; + GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; + LL_GPIO_Init(SEC_UART_GPIO_PORT, &GPIO_InitStruct); + GPIO_InitStruct.Pin = SEC_LL_UART_RX_PIN; + GPIO_InitStruct.Mode = LL_GPIO_MODE_FLOATING; + GPIO_InitStruct.Pull = LL_GPIO_PULL_UP; + LL_GPIO_Init(SEC_UART_GPIO_PORT, &GPIO_InitStruct); + /* Enable remap: USART3 to PC10, PC11 */ + AFIO->MAPR |= AFIO_MAPR_USART3_REMAP_0; +#endif #endif #if (BOOT_COM_CAN_ENABLE > 0) @@ -181,6 +199,7 @@ void HAL_MspDeInit(void) LL_RCC_DeInit(); /* Deinit used GPIOs. */ + LL_GPIO_DeInit(GPIOC); LL_GPIO_DeInit(GPIOB); LL_GPIO_DeInit(GPIOA); @@ -191,10 +210,14 @@ void HAL_MspDeInit(void) #if (BOOT_COM_RS232_ENABLE > 0) /* UART clock disable. */ +#if (BOOT_COM_RS232_CHANNELS_N > 1) + LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_USART3); +#endif LL_APB2_GRP1_DisableClock(LL_APB2_GRP1_PERIPH_USART1); #endif /* GPIO ports clock disable. */ + LL_APB2_GRP1_DisableClock(LL_APB2_GRP1_PERIPH_GPIOC); LL_APB2_GRP1_DisableClock(LL_APB2_GRP1_PERIPH_GPIOB); LL_APB2_GRP1_DisableClock(LL_APB2_GRP1_PERIPH_GPIOA); From 4cb34e1b19b3ee9ab51995ceb47206ae882e2080 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 16 Oct 2023 18:17:50 +0300 Subject: [PATCH 16/91] OpneBLT: switch to my repo --- .gitmodules | 2 +- firmware/ext/openblt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 3dd267a6..1d4c3339 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,7 +10,7 @@ url = https://github.com/rusefi/kicad-libraries [submodule "firmware/ext/openblt"] path = firmware/ext/openblt - url = https://github.com/rusefi/openblt + url = https://github.com/dron0gus/openblt [submodule "firmware/libfirmware"] path = firmware/libfirmware url = https://github.com/rusefi/libfirmware.git diff --git a/firmware/ext/openblt b/firmware/ext/openblt index f24548b1..735fc8c5 160000 --- a/firmware/ext/openblt +++ b/firmware/ext/openblt @@ -1 +1 @@ -Subproject commit f24548b161e0e6f90651d8a2419d82f64dda9282 +Subproject commit 735fc8c5b0aec8717ae8fbc941745e2d34bf4bd1 From 32b141890a4b4cd80a1f6c366e319a7a1fece61e Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 10 Dec 2023 15:47:58 +0300 Subject: [PATCH 17/91] AEM X series protocol packet definition for UEGO and EGT --- for_rusefi/wideband_can.h | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/for_rusefi/wideband_can.h b/for_rusefi/wideband_can.h index 01f79371..b4844830 100644 --- a/for_rusefi/wideband_can.h +++ b/for_rusefi/wideband_can.h @@ -83,4 +83,40 @@ static inline const char* describeFault(Fault fault) { return "Unknown"; } +// AEMNet protocol + +#define AEMNET_UEGO_TX_PERIOD_MS 10 +#define AEMNET_UEGO_BASE_ID 0x00000180 + +// 29 bit ID, 500kbs, rate 100 hz, endian big, DLC 8 +// ID: 0x180 .. 0x18f +struct AemNetUEGOData +{ + // 0.0001 Lambda/bit, 0 to 6.5535 Lambda + uint16_t Lambda; + // 0.001 %/bit, -32.768% to 32.768% + uint16_t Oxygen; + // 0.1 V/bit, 0 to 25.5 Volts + uint8_t SystemVolts; + uint8_t reserved; + // [1] - Bosch LSU4.9 detected + // [5] - Free-Air cal in use + // [7] - Lambda data valid + uint8_t Flags; + // [6] - Sensor Fault + uint8_t Faults; +}; + +#define AEMNET_EGT_TX_PERIOD 50 +#define AEMNET_EGT_BASE_ID 0x000A0305 + +// 29 bit ID, 500kbs, rate 20 hz, endian big, DLC 8 +// ID: 0x000A0305 +struct AemNetEgtData +{ + // 1 degC/bit, 0 to 65535 degC + uint16_t TemperatureC; + uint8_t pad[6]; +}; + } // namespace wbo From 9922bd8281a6bb617ff234c0dc8cf22619521717 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 5 Feb 2024 11:26:54 +0300 Subject: [PATCH 18/91] can_helper: DLC can be less than 8, support extended ID --- firmware/can_helper.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/firmware/can_helper.h b/firmware/can_helper.h index 5ca38872..3607a62c 100644 --- a/firmware/can_helper.h +++ b/firmware/can_helper.h @@ -43,10 +43,11 @@ class CanTxMessage template class CanTxTyped final : public CanTxMessage { - static_assert(sizeof(TData) == sizeof(CANTxFrame::data8)); + static_assert(sizeof(TData) <= sizeof(CANTxFrame::data8)); public: - explicit CanTxTyped(uint32_t eid) : CanTxMessage(eid) { } + explicit CanTxTyped(uint32_t eid) : CanTxMessage(eid, sizeof(TData)) { } + explicit CanTxTyped(uint32_t eid, bool isExtended) : CanTxMessage(eid, sizeof(TData), isExtended) { } /** * Access members of the templated type. From eaa9a816e784ee133f24101aa96db5da82c564f1 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 5 Feb 2024 11:35:00 +0300 Subject: [PATCH 19/91] fix AEM protocol definitions --- for_rusefi/wideband_can.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/for_rusefi/wideband_can.h b/for_rusefi/wideband_can.h index b4844830..7b76bac3 100644 --- a/for_rusefi/wideband_can.h +++ b/for_rusefi/wideband_can.h @@ -105,7 +105,7 @@ struct AemNetUEGOData uint8_t Flags; // [6] - Sensor Fault uint8_t Faults; -}; +} __attribute__((packed)); #define AEMNET_EGT_TX_PERIOD 50 #define AEMNET_EGT_BASE_ID 0x000A0305 @@ -117,6 +117,6 @@ struct AemNetEgtData // 1 degC/bit, 0 to 65535 degC uint16_t TemperatureC; uint8_t pad[6]; -}; +} __attribute__((packed)); } // namespace wbo From 5dd0f83ce74a36377d7182c14df24c2ac6617405 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 5 Feb 2024 11:36:17 +0300 Subject: [PATCH 20/91] can protocol selection to settings --- firmware/boards/f1_common/f1_port.cpp | 26 +++++++++- firmware/boards/port.h | 24 ++++++++- firmware/can.cpp | 75 +++++++++++++++++++++++---- firmware/can.h | 1 + firmware/ini/wideband_dual.ini | 70 ++++++++++++++++++++++++- 5 files changed, 183 insertions(+), 13 deletions(-) diff --git a/firmware/boards/f1_common/f1_port.cpp b/firmware/boards/f1_common/f1_port.cpp index c11821fa..19311cac 100644 --- a/firmware/boards/f1_common/f1_port.cpp +++ b/firmware/boards/f1_common/f1_port.cpp @@ -53,7 +53,9 @@ void Configuration::LoadDefaults() { int i; - CanIndexOffset = 0; + *this = {}; + + NoLongerUsed0 = 0; sensorType = BOARD_DEFAULT_SENSOR_TYPE; /* default auxout curve is 0..5V for AFR 8.5 to 18.0 @@ -65,6 +67,28 @@ void Configuration::LoadDefaults() auxOutputSource[0] = AuxOutputMode::Afr0; auxOutputSource[1] = AuxOutputMode::Afr1; + for (i = 0; i < AFR_CHANNELS; i++) { + // enable RusEFI protocol + afr[i].RusEfiTx = true; + afr[i].RusEfiTxDiag = true; + afr[i].RusEfiIdOffset = i; + + // Disable AemNet + afr[i].AemNetTx = false; + afr[i].AemNetIdOffset = i; + } + + for (i = 0; i < EGT_CHANNELS; i++) { + // disable RusEFI protocol - not implemented + afr[i].RusEfiTx = false; + afr[i].RusEfiTxDiag = false; + afr[i].RusEfiIdOffset = i; + + // Enable AemNet + afr[i].AemNetTx = true; + afr[i].AemNetIdOffset = i; + } + /* Finaly */ Tag = ExpectedTag; } diff --git a/firmware/boards/port.h b/firmware/boards/port.h index 406e3b9e..7e363372 100644 --- a/firmware/boards/port.h +++ b/firmware/boards/port.h @@ -58,13 +58,35 @@ class Configuration { // Actual configuration data union { struct { - uint8_t CanIndexOffset = 0; + uint8_t NoLongerUsed0 = 0; // AUX0 and AUX1 curves float auxOutBins[2][8]; float auxOutValues[2][8]; AuxOutputMode auxOutputSource[2]; SensorType sensorType; + + // per AFR channel settings + struct { + bool RusEfiTx:1; + bool RusEfiTxDiag:1; + bool AemNetTx:1; + + uint8_t RusEfiIdOffset; + uint8_t AemNetIdOffset; + uint8_t pad[5]; + } afr[2]; + + // per EGT channel settings + struct { + bool RusEfiTx:1; + bool RusEfiTxDiag:1; + bool AemNetTx:1; + + uint8_t RusEfiIdOffset; + uint8_t AemNetIdOffset; + uint8_t pad[5]; + } egt[2]; } __attribute__((packed)); // pad to 256 bytes including tag diff --git a/firmware/can.cpp b/firmware/can.cpp index 470b9394..0a2acdee 100644 --- a/firmware/can.cpp +++ b/firmware/can.cpp @@ -8,6 +8,7 @@ #include "sampling.h" #include "pump_dac.h" #include "port.h" +#include "max3185x.h" // this same header is imported by rusEFI to get struct layouts and firmware version #include "../for_rusefi/wideband_can.h" @@ -25,6 +26,10 @@ void CanTxThread(void*) SendCanForChannel(ch); } + for (int ch = 0; ch < EGT_CHANNELS; ch++) { + SendCanEgtForChannel(ch); + } + chThdSleepMilliseconds(WBO_TX_PERIOD_MS); } } @@ -97,7 +102,7 @@ void CanRxThread(void*) else if ((frame.DLC == 0 || frame.DLC == 1) && frame.EID == WB_BL_ENTER) { // If 0xFF (force update all) or our ID, reset to bootloader, otherwise ignore - if (frame.DLC == 0 || frame.data8[0] == 0xFF || frame.data8[0] == GetConfiguration()->CanIndexOffset) + if (frame.DLC == 0 || frame.data8[0] == 0xFF || frame.data8[0] == GetConfiguration()->afr[0].RusEfiIdOffset) { SendAck(); @@ -110,8 +115,14 @@ void CanRxThread(void*) // Check if it's an "index set" message else if (frame.DLC == 1 && frame.EID == WB_MSG_SET_INDEX) { + int offset = frame.data8[0]; configuration = GetConfiguration(); - configuration->CanIndexOffset = frame.data8[0]; + for (int i = 0; i < AFR_CHANNELS; i++) { + configuration->afr[i].RusEfiIdOffset = offset + i * 2; + } + for (int i = 0; i < EGT_CHANNELS; i++) { + configuration->egt[i].RusEfiIdOffset = offset + i; + } SetConfiguration(); SendAck(); } @@ -137,16 +148,27 @@ void InitCan() chThdCreateStatic(waCanRxThread, sizeof(waCanRxThread), NORMALPRIO - 4, CanRxThread, nullptr); } +static int LambdaIsValid(int ch) +{ + const auto& sampler = GetSampler(ch); + const auto& heater = GetHeaterController(ch); + + float nernstDc = sampler.GetNernstDc(); + + return ((heater.IsRunningClosedLoop()) && + (nernstDc > (NERNST_TARGET - 0.1f)) && + (nernstDc < (NERNST_TARGET + 0.1f))); +} + void SendRusefiFormat(uint8_t ch) { - auto baseAddress = WB_DATA_BASE_ADDR + 2 * (ch + configuration->CanIndexOffset); + auto baseAddress = WB_DATA_BASE_ADDR + configuration->afr[ch].RusEfiIdOffset; const auto& sampler = GetSampler(ch); - const auto& heater = GetHeaterController(ch); float nernstDc = sampler.GetNernstDc(); - { + if (configuration->afr[ch].RusEfiTx) { CanTxTyped frame(baseAddress + 0); // The same header is imported by the ECU and checked against this data in the frame @@ -155,12 +177,10 @@ void SendRusefiFormat(uint8_t ch) uint16_t lambda = GetLambda(ch) * 10000; frame.get().Lambda = lambda; frame.get().TemperatureC = sampler.GetSensorTemperature(); - bool heaterClosedLoop = heater.IsRunningClosedLoop(); - bool nernstValid = nernstDc > (NERNST_TARGET - 0.1f) && nernstDc < (NERNST_TARGET + 0.1f); - frame.get().Valid = (heaterClosedLoop && nernstValid) ? 0x01 : 0x00; + frame.get().Valid = LambdaIsValid(ch) ? 0x01 : 0x00; } - { + if (configuration->afr[ch].RusEfiTxDiag) { auto esr = sampler.GetSensorInternalResistance(); CanTxTyped frame(baseAddress + 1); @@ -173,8 +193,45 @@ void SendRusefiFormat(uint8_t ch) } } +void SendAemNetUEGOForamt(uint8_t ch) +{ + auto id = AEMNET_UEGO_BASE_ID + configuration->afr[ch].AemNetIdOffset; + + const auto& sampler = GetSampler(ch); + + if (configuration->afr[ch].AemNetTx) { + CanTxTyped frame(id, true); + + frame.get().Lambda = GetLambda(ch) * 10000; + frame.get().Oxygen = 0; // TODO: + frame.get().SystemVolts = sampler.GetInternalHeaterVoltage(); + frame.get().Flags = + ((configuration->sensorType == SensorType::LSU49) ? 0x02 : 0x00) | + ((LambdaIsValid(ch)) ? 0x80 : 0x00); + frame.get().Faults = 0; //TODO: + } +} + +void SendAemNetEGTFormat(uint8_t ch) +{ + auto id = AEMNET_EGT_BASE_ID + configuration->egt[ch].AemNetIdOffset; + + if (configuration->egt[ch].AemNetTx) { + CanTxTyped frame(id, true); + + frame.get().TemperatureC = getEgtDrivers()[ch].temperature; + } +} + // Weak link so boards can override it __attribute__((weak)) void SendCanForChannel(uint8_t ch) { SendRusefiFormat(ch); + SendAemNetUEGOForamt(ch); } + +__attribute__((weak)) void SendCanEgtForChannel(uint8_t ch) +{ + // TODO: implement RusEFI protocol? + SendAemNetEGTFormat(ch); +} \ No newline at end of file diff --git a/firmware/can.h b/firmware/can.h index 38105f0b..a5904a96 100644 --- a/firmware/can.h +++ b/firmware/can.h @@ -24,3 +24,4 @@ float GetRemoteBatteryVoltage(); // implement this for your board if you want some non-standard behavior // default implementation simply calls SendRusefiFormat void SendCanForChannel(uint8_t ch); +void SendCanEgtForChannel(uint8_t ch); \ No newline at end of file diff --git a/firmware/ini/wideband_dual.ini b/firmware/ini/wideband_dual.ini index 9f7ec0cf..d36b07fb 100644 --- a/firmware/ini/wideband_dual.ini +++ b/firmware/ini/wideband_dual.ini @@ -69,11 +69,35 @@ Aux0InputSel = bits, U08, 133, [0:3], "AFR 0", "AFR 1", "Lambda 0", "L Aux1InputSel = bits, U08, 134, [0:3], "AFR 0", "AFR 1", "Lambda 0", "Lambda 1", "EGT 0", "EGT 1" LsuSensorType = bits, U08, 135, [0:2], "LSU 4.9", "LSU 4.2", "LSU ADV", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID" +RusEfiTx0 = bits, U08, 136, [0:0], "Disable", "Enable" +RusEfiTxDiag0 = bits, U08, 136, [1:1], "Disable", "Enable" +AemNetTx0 = bits, U08, 136, [2:2], "Disable", "Enable" +RusEfiIdOffset0= scalar, U08, 137, "", 1, 0, 0, 255, 0 +AemNetIdOffset0= scalar, U08, 138, "", 1, 0, 0, 255, 0 + +RusEfiTx1 = bits, U08, 144, [0:0], "Disable", "Enable" +RusEfiTxDiag1 = bits, U08, 144, [1:1], "Disable", "Enable" +AemNetTx1 = bits, U08, 144, [2:2], "Disable", "Enable" +RusEfiIdOffset1= scalar, U08, 145, "", 1, 0, 0, 255, 0 +AemNetIdOffset1= scalar, U08, 146, "", 1, 0, 0, 255, 0 + +AemNetEgtTx0 = bits, U08, 152, [2:2], "Disable", "Enable" +AemNetIdEgOff0 = scalar, U08, 154, "", 1, 0, 0, 255, 0 + +AemNetEgtTx1 = bits, U08, 160, [2:2], "Disable", "Enable" +AemNetIdEgOff1 = scalar, U08, 162, "", 1, 0, 0, 255, 0 + page = 2 ; this is a RAM only page with no burnable flash ; name = class, type, offset, [shape], units, scale, translate, min, max, digits highSpeedOffsets = array, U16, 0, [32], "", 1, 0, 0, 65535, 0, noMsqSave [SettingContextHelp] + RusEfiIdOffset0 = "Defines CAN ID offset for RusEFI AFR format packet channel 0 (left). Data packet ID = (0x190 + this offset), Diagnostic packed ID = (0x190 + 1 + this offset)." + RusEfiIdOffset1 = "Defines CAN ID offset for RusEFI AFR format packet channel 1 (right). Data packet ID = (0x190 + this offset), Diagnostic packed ID = (0x190 + 1 + this offset)." + AemNetIdOffset0 = "Defines CAN ID offset for AemNET USEGO format packet channel 0 (left). Packet ID = (0x180 + this offset)." + AemNetIdOffset1 = "Defines CAN ID offset for AemNET USEGO format packet channel 1 (right). Packet ID = (0x180 + this offset)." + AemNetIdEgOff0 = "Defines CAN ID offset for AemNET EGT format packet channel 0 (left). Packed ID = (0xA0305 + this offset)." + AemNetIdEgOff1 = "Defines CAN ID offset for AemNET EGT format packet channel 1 (right). Packed ID = (0xA0305 + this offset)." [Tuning] @@ -303,7 +327,8 @@ entry = EGT1_state, "EGT 1: State", int, "%d" menuDialog = main menu = "&Settings" subMenu = sensor_settings, "Sensor settings" - subMenu = can_settings, "CAN settings" + subMenu = can_settings, "CAN AFR settings" + subMenu = can_egt_settings, "CAN EGT settings" menu = "Outputs" subMenu = auxOut0, "AUX analog output 0" @@ -334,9 +359,50 @@ cmd_openblt = "Z\x00\xbc\x00\x00" dialog = sensor_settings, "Sensor Settings" field = "Sensor Type", LsuSensorType -dialog = can_settings, "CAN Settings" +dialog = afr0_can_settings, "AFR 0 (left) channel CAN Settings" + field = "RusEFI protocol:" + field = "Output AFR", RusEfiTx0 + field = "Output AFR diagnostic", RusEfiTxDiag0 + field = "CAN ID offset (base ID is 0x190) multiple of two", RusEfiIdOffset0, { (RusEfiTx0 == 1) || (RusEfiTxDiag0 == 1)} + field = "AemNet protocol:" + field = "Output AFR", AemNetTx0 + field = "CAN ID offset (base ID is 0x180)", AemNetIdOffset0, { (AemNetTx0 == 1) } + +dialog = afr1_can_settings, "AFR 1 (right) channel CAN Settings" + field = "RusEFI protocol:" + field = "Output AFR", RusEfiTx1 + field = "Output AFR diagnostic", RusEfiTxDiag1 + field = "CAN ID offset (base ID is 0x190) multiple of two", RusEfiIdOffset1, { (RusEfiTx1 == 1) || (RusEfiTxDiag1 == 1)} + field = "AemNet protocol:" + field = "Output AFR", AemNetTx1 + field = "CAN ID offset (base ID is 0x180)", AemNetIdOffset1, { (AemNetTx1 == 1) } + +dialog = egt0_can_settings, "EGT 0 (left) channel CAN Settings" + field = "RusEFI protocol:" + field = "not implemented yet" + field = "AemNet protocol:" + field = "Output EGT", AemNetEgtTx0 + field = "CAN ID offset (base ID is 0xA0305)", AemNetIdEgOff0, { (AemNetEgtTx0 == 1) }, { 1 }, displayInHex + +dialog = egt1_can_settings, "EGT 1 (right) channel CAN Settings" + field = "RusEFI protocol:" + field = "not implemented yet" + field = "AemNet protocol:" + field = "Output EGT", AemNetEgtTx1 + field = "CAN ID offset (base ID is 0xA0305)", AemNetIdEgOff1, { (AemNetEgtTx1 == 1) }, { 1 }, displayInHex + +dialog = common_can_settings, "CAN Settings" field = "CAN message ID offset", CanIndexOffset +dialog = can_settings, "CAN AFR Settings", border + panel = common_can_settings, North + panel = afr0_can_settings, West + panel = afr1_can_settings, East + +dialog = can_egt_settings, "CAN AFR Settings", border + panel = egt0_can_settings, West + panel = egt1_can_settings, East + dialog = auxOut0, "AUX analog out 0 Settings" field = "Signal", Aux0InputSel panel = auxOut0Curve From 3eaa3d2a80ab80370d8de4b6846f70d2e3c51cd2 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 5 Feb 2024 13:24:07 +0300 Subject: [PATCH 21/91] f0_module: fix --- firmware/boards/f0_module/port.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/firmware/boards/f0_module/port.cpp b/firmware/boards/f0_module/port.cpp index d551e9d5..ab7818c9 100644 --- a/firmware/boards/f0_module/port.cpp +++ b/firmware/boards/f0_module/port.cpp @@ -114,15 +114,15 @@ Configuration* GetConfiguration() // See https://github.com/mck1117/wideband/issues/11 to explain this madness switch (3 * sel1 + sel2) { - case 0: config.CanIndexOffset = 2; break; - case 1: config.CanIndexOffset = 0; break; - case 2: config.CanIndexOffset = 3; break; - case 3: config.CanIndexOffset = 4; break; + case 0: config.afr[0].RusEfiIdOffset = 2; break; + case 1: config.afr[0].RusEfiIdOffset = 0; break; + case 2: config.afr[0].RusEfiIdOffset = 3; break; + case 3: config.afr[0].RusEfiIdOffset = 4; break; case 4: /* both floating, do nothing */ break; - case 5: config.CanIndexOffset = 1; break; - case 6: config.CanIndexOffset = 5; break; - case 7: config.CanIndexOffset = 6; break; - case 8: config.CanIndexOffset = 7; break; + case 5: config.afr[0].RusEfiIdOffset = 1; break; + case 6: config.afr[0].RusEfiIdOffset = 5; break; + case 7: config.afr[0].RusEfiIdOffset = 6; break; + case 8: config.afr[0].RusEfiIdOffset = 7; break; default: break; } From cc267a1f9bb3eb419b85c2bc11bb59cf5301e6ef Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 5 Feb 2024 13:24:16 +0300 Subject: [PATCH 22/91] ini files: cleanup --- firmware/ini/wideband_dual.ini | 4 ---- 1 file changed, 4 deletions(-) diff --git a/firmware/ini/wideband_dual.ini b/firmware/ini/wideband_dual.ini index d36b07fb..8892209e 100644 --- a/firmware/ini/wideband_dual.ini +++ b/firmware/ini/wideband_dual.ini @@ -391,11 +391,7 @@ dialog = egt1_can_settings, "EGT 1 (right) channel CAN Settings" field = "Output EGT", AemNetEgtTx1 field = "CAN ID offset (base ID is 0xA0305)", AemNetIdEgOff1, { (AemNetEgtTx1 == 1) }, { 1 }, displayInHex -dialog = common_can_settings, "CAN Settings" - field = "CAN message ID offset", CanIndexOffset - dialog = can_settings, "CAN AFR Settings", border - panel = common_can_settings, North panel = afr0_can_settings, West panel = afr1_can_settings, East From ee43331431c4a106075f875071b08fa1fe3bc2e5 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 5 Feb 2024 13:25:53 +0300 Subject: [PATCH 23/91] Fix no-EGT boards --- firmware/can.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/firmware/can.cpp b/firmware/can.cpp index 0a2acdee..32d05a36 100644 --- a/firmware/can.cpp +++ b/firmware/can.cpp @@ -212,6 +212,7 @@ void SendAemNetUEGOForamt(uint8_t ch) } } +#if (EGT_CHANNELS > 0) void SendAemNetEGTFormat(uint8_t ch) { auto id = AEMNET_EGT_BASE_ID + configuration->egt[ch].AemNetIdOffset; @@ -222,6 +223,7 @@ void SendAemNetEGTFormat(uint8_t ch) frame.get().TemperatureC = getEgtDrivers()[ch].temperature; } } +#endif /* EGT_CHANNELS > 0 */ // Weak link so boards can override it __attribute__((weak)) void SendCanForChannel(uint8_t ch) @@ -232,6 +234,8 @@ __attribute__((weak)) void SendCanForChannel(uint8_t ch) __attribute__((weak)) void SendCanEgtForChannel(uint8_t ch) { +#if (EGT_CHANNELS > 0) // TODO: implement RusEFI protocol? SendAemNetEGTFormat(ch); +#endif /* EGT_CHANNELS > 0 */ } \ No newline at end of file From c61244feabebc4cea3726ef943933161564cfd6c Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 5 Feb 2024 13:50:15 +0300 Subject: [PATCH 24/91] ini file update --- firmware/ini/wideband_dual.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/ini/wideband_dual.ini b/firmware/ini/wideband_dual.ini index 8892209e..649b65b6 100644 --- a/firmware/ini/wideband_dual.ini +++ b/firmware/ini/wideband_dual.ini @@ -363,19 +363,19 @@ dialog = afr0_can_settings, "AFR 0 (left) channel CAN Settings" field = "RusEFI protocol:" field = "Output AFR", RusEfiTx0 field = "Output AFR diagnostic", RusEfiTxDiag0 - field = "CAN ID offset (base ID is 0x190) multiple of two", RusEfiIdOffset0, { (RusEfiTx0 == 1) || (RusEfiTxDiag0 == 1)} + field = "CAN ID offset (base ID is 0x190)", RusEfiIdOffset0, { (RusEfiTx0 == 1) || (RusEfiTxDiag0 == 1)}, { 1 }, displayInHex field = "AemNet protocol:" field = "Output AFR", AemNetTx0 - field = "CAN ID offset (base ID is 0x180)", AemNetIdOffset0, { (AemNetTx0 == 1) } + field = "CAN ID offset (base ID is 0x180)", AemNetIdOffset0, { (AemNetTx0 == 1) }, { 1 }, displayInHex dialog = afr1_can_settings, "AFR 1 (right) channel CAN Settings" field = "RusEFI protocol:" field = "Output AFR", RusEfiTx1 field = "Output AFR diagnostic", RusEfiTxDiag1 - field = "CAN ID offset (base ID is 0x190) multiple of two", RusEfiIdOffset1, { (RusEfiTx1 == 1) || (RusEfiTxDiag1 == 1)} + field = "CAN ID offset (base ID is 0x190)", RusEfiIdOffset1, { (RusEfiTx1 == 1) || (RusEfiTxDiag1 == 1)}, { 1 }, displayInHex field = "AemNet protocol:" field = "Output AFR", AemNetTx1 - field = "CAN ID offset (base ID is 0x180)", AemNetIdOffset1, { (AemNetTx1 == 1) } + field = "CAN ID offset (base ID is 0x180)", AemNetIdOffset1, { (AemNetTx1 == 1) }, { 1 }, displayInHex dialog = egt0_can_settings, "EGT 0 (left) channel CAN Settings" field = "RusEFI protocol:" From 55c42c23116aeab1b290298b8f9a967a21d59105 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sat, 10 Feb 2024 12:11:29 +0300 Subject: [PATCH 25/91] byteswap.h: add BE storage types --- firmware/util/byteswap.h | 86 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/firmware/util/byteswap.h b/firmware/util/byteswap.h index a053d0fa..d623a5b0 100644 --- a/firmware/util/byteswap.h +++ b/firmware/util/byteswap.h @@ -1,7 +1,17 @@ #pragma once +#include +#include + // http://en.wikipedia.org/wiki/Endianness +#if defined(__BYTE_ORDER__)&&(__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + #define bigEndianHost true +#endif +#if defined(__BYTE_ORDER__)&&(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + #define bigEndianHost false +#endif + static inline uint16_t SWAP_UINT16(uint16_t x) { return ((x << 8) | (x >> 8)); @@ -11,4 +21,78 @@ static inline uint32_t SWAP_UINT32(uint32_t x) { return (((x >> 24) & 0x000000ff) | ((x << 8) & 0x00ff0000) | ((x >> 8) & 0x0000ff00) | ((x << 24) & 0xff000000)); -} \ No newline at end of file +} + +// TODO: use SWAP_UINT16() and SWAP_UINT32() instead of following +template +T swap(const T& arg, bool bigInMem) +{ + if (bigEndianHost == bigInMem) { + // no byte-swapping needed + return arg; + } else { + // swap bytes + T ret; + + char* dst = reinterpret_cast(&ret); + const char* src = reinterpret_cast(&arg + 1); + + for (size_t i = 0; i < sizeof(T); i++) { + *dst++ = *--src; + } + + return ret; + } +} + +template +class BigEndian +{ + public: + struct IncompleteType; + BigEndian() { } + BigEndian(const T& t) : rep(swap(t, true)) { } + operator T() const { return swap(rep, true); } +#if 0 + // TODO: + constexpr operator typename std::conditional_t() const { + return SWAP_UINT32(rep); + } + + constexpr BigEndian(std::conditional_t val) { + rep = SWAP_UINT32(val); + } + + constexpr operator typename std::conditional_t() const { + return SWAP_UINT16(rep); + } + + constexpr BigEndian(std::conditional_t val) { + rep = SWAP_UINT32(val); + } +#endif + private: + T rep; +}; + +template +class LittleEndian +{ + public: + T rep; +// LittleEndian() { } + LittleEndian(const T& t) : rep(swap(t, false)) { } + operator T() const { return swap(rep, false); } +}; + +// Big endian storage types +using beint16_t = BigEndian; +using beint32_t = BigEndian; +using beuint16_t = BigEndian; +using beuint32_t = BigEndian; + +//static_assert(sizeof(buint8_t) == 1); +static_assert(sizeof(beint16_t) == 2); +static_assert(sizeof(beint32_t) == 4); +static_assert(sizeof(beuint16_t) == 2); +static_assert(sizeof(beuint32_t) == 4); From cb169fd2ae09bb104cbf9252bfce3b8d157909d5 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sat, 10 Feb 2024 12:24:43 +0300 Subject: [PATCH 26/91] AEMNET: move to separate files --- firmware/Makefile | 1 + firmware/can.cpp | 39 ++------------ firmware/can_aemnet.cpp | 107 ++++++++++++++++++++++++++++++++++++++ firmware/can_aemnet.h | 7 +++ for_rusefi/wideband_can.h | 36 ------------- 5 files changed, 120 insertions(+), 70 deletions(-) create mode 100644 firmware/can_aemnet.cpp create mode 100644 firmware/can_aemnet.h diff --git a/firmware/Makefile b/firmware/Makefile index 06446207..aa57a076 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -150,6 +150,7 @@ CPPSRC = $(ALLCPPSRC) \ shared/flash.cpp \ can.cpp \ can_helper.cpp \ + can_aemnet.cpp \ fault.cpp \ lambda_conversion.cpp \ pwm.cpp \ diff --git a/firmware/can.cpp b/firmware/can.cpp index 32d05a36..3265648a 100644 --- a/firmware/can.cpp +++ b/firmware/can.cpp @@ -1,13 +1,16 @@ #include "can.h" #include "hal.h" +#include "can_helper.h" +#include "can_aemnet.h" + +#include "port.h" #include "fault.h" #include "can_helper.h" #include "heater_control.h" #include "lambda_conversion.h" #include "sampling.h" #include "pump_dac.h" -#include "port.h" #include "max3185x.h" // this same header is imported by rusEFI to get struct layouts and firmware version @@ -193,43 +196,11 @@ void SendRusefiFormat(uint8_t ch) } } -void SendAemNetUEGOForamt(uint8_t ch) -{ - auto id = AEMNET_UEGO_BASE_ID + configuration->afr[ch].AemNetIdOffset; - - const auto& sampler = GetSampler(ch); - - if (configuration->afr[ch].AemNetTx) { - CanTxTyped frame(id, true); - - frame.get().Lambda = GetLambda(ch) * 10000; - frame.get().Oxygen = 0; // TODO: - frame.get().SystemVolts = sampler.GetInternalHeaterVoltage(); - frame.get().Flags = - ((configuration->sensorType == SensorType::LSU49) ? 0x02 : 0x00) | - ((LambdaIsValid(ch)) ? 0x80 : 0x00); - frame.get().Faults = 0; //TODO: - } -} - -#if (EGT_CHANNELS > 0) -void SendAemNetEGTFormat(uint8_t ch) -{ - auto id = AEMNET_EGT_BASE_ID + configuration->egt[ch].AemNetIdOffset; - - if (configuration->egt[ch].AemNetTx) { - CanTxTyped frame(id, true); - - frame.get().TemperatureC = getEgtDrivers()[ch].temperature; - } -} -#endif /* EGT_CHANNELS > 0 */ - // Weak link so boards can override it __attribute__((weak)) void SendCanForChannel(uint8_t ch) { SendRusefiFormat(ch); - SendAemNetUEGOForamt(ch); + SendAemNetUEGOFormat(ch); } __attribute__((weak)) void SendCanEgtForChannel(uint8_t ch) diff --git a/firmware/can_aemnet.cpp b/firmware/can_aemnet.cpp new file mode 100644 index 00000000..48a4fee9 --- /dev/null +++ b/firmware/can_aemnet.cpp @@ -0,0 +1,107 @@ +#include "can.h" +#include "hal.h" + +#include "can_helper.h" +#include "can_aemnet.h" + +#include "port.h" +#include "fault.h" +#include "heater_control.h" +#include "lambda_conversion.h" +#include "sampling.h" +#include "pump_dac.h" +#include "max3185x.h" + +// AEMNet protocol + +#define AEMNET_UEGO_TX_PERIOD_MS 10 +#define AEMNET_UEGO_BASE_ID 0x00000180 + +namespace aemnet +{ +// 29 bit ID, 500kbs, rate 100 hz, endian big, DLC 8 +// ID: 0x180 .. 0x18f +struct UEGOData +{ + // 0.0001 Lambda/bit, 0 to 6.5535 Lambda + beuint16_t Lambda; + // 0.001 %/bit, -32.768% to 32.768% + beuint16_t Oxygen; + // 0.1 V/bit, 0 to 25.5 Volts + uint8_t SystemVolts; + uint8_t reserved; + // [1] - Bosch LSU4.9 detected + // [5] - Free-Air cal in use + // [7] - Lambda data valid + uint8_t Flags; + // [6] - Sensor Fault + uint8_t Faults; +}; +// TODO!!! +// __attribute__((packed)); + +static_assert(sizeof(UEGOData) == 8); + +#define AEMNET_EGT_TX_PERIOD 50 +#define AEMNET_EGT_BASE_ID 0x000A0305 + +// 29 bit ID, 500kbs, rate 20 hz, endian big, DLC 8 +// ID: 0x000A0305 +struct EgtData +{ + // 1 degC/bit, 0 to 65535 degC + beuint16_t TemperatureC; + uint8_t pad[6]; +}; +//TODO!!!! +// __attribute__((packed)); + +static_assert(sizeof(EgtData) == 8); + +} //namespace aemnet + +static int LambdaIsValid(int ch) +{ + const auto& sampler = GetSampler(ch); + const auto& heater = GetHeaterController(ch); + + float nernstDc = sampler.GetNernstDc(); + + return ((heater.IsRunningClosedLoop()) && + (nernstDc > (NERNST_TARGET - 0.1f)) && + (nernstDc < (NERNST_TARGET + 0.1f))); +} + +void SendAemNetUEGOFormat(uint8_t ch) +{ + Configuration* configuration = GetConfiguration(); + auto id = AEMNET_UEGO_BASE_ID + configuration->afr[ch].AemNetIdOffset; + + const auto& sampler = GetSampler(ch); + + if (configuration->afr[ch].AemNetTx) { + CanTxTyped frame(id, true); + + frame.get().Lambda = GetLambda(ch) * 10000; + frame.get().Oxygen = 0; // TODO: + frame.get().SystemVolts = sampler.GetInternalHeaterVoltage() * 10; + frame.get().Flags = + ((configuration->sensorType == SensorType::LSU49) ? 0x02 : 0x00) | + ((LambdaIsValid(ch)) ? 0x80 : 0x00); + frame.get().Faults = 0; //TODO: + } +} + +#if (EGT_CHANNELS > 0) +void SendAemNetEGTFormat(uint8_t ch) +{ + Configuration* configuration = GetConfiguration(); + auto id = AEMNET_EGT_BASE_ID + configuration->egt[ch].AemNetIdOffset; + + if (configuration->egt[ch].AemNetTx) { + CanTxTyped frame(id, true); + + frame.get().TemperatureC = getEgtDrivers()[ch].temperature; + } +} +#endif /* EGT_CHANNELS > 0 */ diff --git a/firmware/can_aemnet.h b/firmware/can_aemnet.h new file mode 100644 index 00000000..23b2b438 --- /dev/null +++ b/firmware/can_aemnet.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include "byteswap.h" + +void SendAemNetUEGOFormat(uint8_t ch); +void SendAemNetEGTFormat(uint8_t ch); diff --git a/for_rusefi/wideband_can.h b/for_rusefi/wideband_can.h index 7b76bac3..01f79371 100644 --- a/for_rusefi/wideband_can.h +++ b/for_rusefi/wideband_can.h @@ -83,40 +83,4 @@ static inline const char* describeFault(Fault fault) { return "Unknown"; } -// AEMNet protocol - -#define AEMNET_UEGO_TX_PERIOD_MS 10 -#define AEMNET_UEGO_BASE_ID 0x00000180 - -// 29 bit ID, 500kbs, rate 100 hz, endian big, DLC 8 -// ID: 0x180 .. 0x18f -struct AemNetUEGOData -{ - // 0.0001 Lambda/bit, 0 to 6.5535 Lambda - uint16_t Lambda; - // 0.001 %/bit, -32.768% to 32.768% - uint16_t Oxygen; - // 0.1 V/bit, 0 to 25.5 Volts - uint8_t SystemVolts; - uint8_t reserved; - // [1] - Bosch LSU4.9 detected - // [5] - Free-Air cal in use - // [7] - Lambda data valid - uint8_t Flags; - // [6] - Sensor Fault - uint8_t Faults; -} __attribute__((packed)); - -#define AEMNET_EGT_TX_PERIOD 50 -#define AEMNET_EGT_BASE_ID 0x000A0305 - -// 29 bit ID, 500kbs, rate 20 hz, endian big, DLC 8 -// ID: 0x000A0305 -struct AemNetEgtData -{ - // 1 degC/bit, 0 to 65535 degC - uint16_t TemperatureC; - uint8_t pad[6]; -} __attribute__((packed)); - } // namespace wbo From cb2e38da7d43a9b11e1efd5f9fee6a6455385723 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sat, 10 Feb 2024 13:15:06 +0300 Subject: [PATCH 27/91] CAN: more accurate time intervals --- firmware/can.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/firmware/can.cpp b/firmware/can.cpp index 3265648a..69e43bd1 100644 --- a/firmware/can.cpp +++ b/firmware/can.cpp @@ -23,6 +23,8 @@ void CanTxThread(void*) { chRegSetThreadName("CAN Tx"); + systime_t prev = chVTGetSystemTime(); // Current system time. + while(1) { for (int ch = 0; ch < AFR_CHANNELS; ch++) { @@ -33,7 +35,7 @@ void CanTxThread(void*) SendCanEgtForChannel(ch); } - chThdSleepMilliseconds(WBO_TX_PERIOD_MS); + prev = chThdSleepUntilWindowed(prev, chTimeAddX(prev, TIME_MS2I(WBO_TX_PERIOD_MS))); } } From 6825eeff8646743620a23c84261bb743b38a2534 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sat, 10 Feb 2024 13:18:43 +0300 Subject: [PATCH 28/91] CAN: EGT message rate is 20Hz --- firmware/can.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/firmware/can.cpp b/firmware/can.cpp index 69e43bd1..580a8fbf 100644 --- a/firmware/can.cpp +++ b/firmware/can.cpp @@ -21,20 +21,26 @@ static Configuration* configuration; static THD_WORKING_AREA(waCanTxThread, 256); void CanTxThread(void*) { + int cycle; chRegSetThreadName("CAN Tx"); systime_t prev = chVTGetSystemTime(); // Current system time. while(1) { + // AFR - 100 Hz for (int ch = 0; ch < AFR_CHANNELS; ch++) { SendCanForChannel(ch); } - for (int ch = 0; ch < EGT_CHANNELS; ch++) { - SendCanEgtForChannel(ch); + // EGT - 20 Hz + if ((cycle % 5) == 0) { + for (int ch = 0; ch < EGT_CHANNELS; ch++) { + SendCanEgtForChannel(ch); + } } + cycle++; prev = chThdSleepUntilWindowed(prev, chTimeAddX(prev, TIME_MS2I(WBO_TX_PERIOD_MS))); } } From 81dc7342fdad625b61512215c21dc51497087da4 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 11 Feb 2024 23:01:15 +0300 Subject: [PATCH 29/91] byteswap.h: packed --- firmware/util/byteswap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/util/byteswap.h b/firmware/util/byteswap.h index d623a5b0..4ba6db1e 100644 --- a/firmware/util/byteswap.h +++ b/firmware/util/byteswap.h @@ -73,7 +73,7 @@ class BigEndian #endif private: T rep; -}; +} __attribute__((packed)); template class LittleEndian From 20c8e86acdd21c9e9ada4a0aed6d1223d312d461 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 11 Feb 2024 23:09:13 +0300 Subject: [PATCH 30/91] f1_dual_rev1: bump signature --- firmware/boards/f1_dual/wideband_board_config.h | 2 +- firmware/boards/f1_dual_rev1/wideband_board_config.h | 2 +- firmware/ini/wideband_dual.ini | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/boards/f1_dual/wideband_board_config.h b/firmware/boards/f1_dual/wideband_board_config.h index 107e854c..9b6bd059 100644 --- a/firmware/boards/f1_dual/wideband_board_config.h +++ b/firmware/boards/f1_dual/wideband_board_config.h @@ -1,7 +1,7 @@ #pragma once // TS settings -#define TS_SIGNATURE "rusEFI 2023.05.10.wideband_dual" +#define TS_SIGNATURE "rusEFI 2024.02.11.wideband_dual" // This board implements two channels #define AFR_CHANNELS 2 diff --git a/firmware/boards/f1_dual_rev1/wideband_board_config.h b/firmware/boards/f1_dual_rev1/wideband_board_config.h index b62b1aec..0203e16d 100644 --- a/firmware/boards/f1_dual_rev1/wideband_board_config.h +++ b/firmware/boards/f1_dual_rev1/wideband_board_config.h @@ -1,7 +1,7 @@ #pragma once // TS settings -#define TS_SIGNATURE "rusEFI 2023.05.10.wideband_dual" +#define TS_SIGNATURE "rusEFI 2024.02.11.wideband_dual" // This board implements two channels #define AFR_CHANNELS 2 diff --git a/firmware/ini/wideband_dual.ini b/firmware/ini/wideband_dual.ini index 649b65b6..621679d4 100644 --- a/firmware/ini/wideband_dual.ini +++ b/firmware/ini/wideband_dual.ini @@ -12,12 +12,12 @@ enable2ndByteCanID = false [MegaTune] ; https://rusefi.com/forum/viewtopic.php?p=36201#p36201 - signature = "rusEFI 2023.05.10.wideband_dual" + signature = "rusEFI 2024.02.11.wideband_dual" [TunerStudio] queryCommand = "S" versionInfo = "V" ; firmware version for title bar. - signature = "rusEFI 2023.05.10.wideband_dual" ; signature is expected to be 7 or more characters. + signature = "rusEFI 2024.02.11.wideband_dual" ; signature is expected to be 7 or more characters. ; TS will try to use legacy temp units in some cases, showing "deg F" on a CLT gauge that's actually deg C useLegacyFTempUnits = false From f54b7f165479c3c518c2dcf0d147d9fee9ffe3fb Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sat, 16 Mar 2024 23:06:08 +0300 Subject: [PATCH 31/91] Fix default config https://github.com/dron0gus/wideband/issues/16 --- firmware/boards/f1_common/f1_port.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/firmware/boards/f1_common/f1_port.cpp b/firmware/boards/f1_common/f1_port.cpp index 19311cac..c898972e 100644 --- a/firmware/boards/f1_common/f1_port.cpp +++ b/firmware/boards/f1_common/f1_port.cpp @@ -80,13 +80,13 @@ void Configuration::LoadDefaults() for (i = 0; i < EGT_CHANNELS; i++) { // disable RusEFI protocol - not implemented - afr[i].RusEfiTx = false; - afr[i].RusEfiTxDiag = false; - afr[i].RusEfiIdOffset = i; + egt[i].RusEfiTx = false; + egt[i].RusEfiTxDiag = false; + egt[i].RusEfiIdOffset = i; // Enable AemNet - afr[i].AemNetTx = true; - afr[i].AemNetIdOffset = i; + egt[i].AemNetTx = true; + egt[i].AemNetIdOffset = i; } /* Finaly */ From 5d96ce97b395ebb32fe3bd50f219b6a48d20cfd6 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 18 Mar 2024 12:30:35 +0300 Subject: [PATCH 32/91] max3185x: more const --- firmware/max3185x.cpp | 4 ++-- firmware/max3185x.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/max3185x.cpp b/firmware/max3185x.cpp index 0e13d48a..97f7acbb 100644 --- a/firmware/max3185x.cpp +++ b/firmware/max3185x.cpp @@ -9,7 +9,7 @@ #if (EGT_CHANNELS > 0) -static SPIConfig spi_config[2] = +static const SPIConfig spi_config[EGT_CHANNELS] = { { .circular = false, @@ -39,7 +39,7 @@ static SPIConfig spi_config[2] = } }; -static Max3185x instances[] = {&spi_config[0], &spi_config[1]}; +static Max3185x instances[EGT_CHANNELS] = {Max3185x(&spi_config[0]), Max3185x(&spi_config[1])}; static Max3185xThread EgtThread(instances); diff --git a/firmware/max3185x.h b/firmware/max3185x.h index 433eba53..26a3a08d 100644 --- a/firmware/max3185x.h +++ b/firmware/max3185x.h @@ -41,7 +41,7 @@ const struct livedata_egt_s * getEgtLiveDataStructAddr(const int ch); class Max3185x { public: - Max3185x(SPIConfig *spi) { + Max3185x(const SPIConfig *spi) { this->spi = spi; } livedata_egt_s livedata; @@ -51,7 +51,7 @@ class Max3185x { Max3185xType type; int readPacket(); private: - SPIConfig *spi; + const SPIConfig *spi; int detect(); int readPacket31855(); int readPacket31856(); From b27fe64854003cf5dcaaa6fd385d517746a55630 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 18 Mar 2024 12:31:06 +0300 Subject: [PATCH 33/91] max3185x: deinit SPI bus after use --- firmware/max3185x.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/firmware/max3185x.cpp b/firmware/max3185x.cpp index 97f7acbb..f7f99012 100644 --- a/firmware/max3185x.cpp +++ b/firmware/max3185x.cpp @@ -54,6 +54,8 @@ int Max3185x::spi_txrx(uint8_t tx[], uint8_t rx[], size_t n) spiExchange(EGT_SPI_DRIVER, n, tx, rx); /* Slave Select de-assertion. */ spiUnselect(EGT_SPI_DRIVER); + /* Bus deinit */ + spiStop(EGT_SPI_DRIVER); /* Ownership release. */ spiReleaseBus(EGT_SPI_DRIVER); From 65edf8d9fe55a30f234a61aa33a05ec27e037a78 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 18 Mar 2024 12:31:32 +0300 Subject: [PATCH 34/91] max3185x: improve chip type detection --- firmware/max3185x.cpp | 78 ++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 24 deletions(-) diff --git a/firmware/max3185x.cpp b/firmware/max3185x.cpp index f7f99012..012535de 100644 --- a/firmware/max3185x.cpp +++ b/firmware/max3185x.cpp @@ -83,38 +83,68 @@ int Max3185x::spi_rx32(uint32_t *data) return 0; } +// bits D17 and D3 are always expected to be zero +#define MAX31855_RESERVED_BITS 0x20008 + int Max3185x::detect() { + int ret; uint8_t rx[4]; - /* read MASK, CJHF, CJLF */ - uint8_t tx[4] = {0x02, 0x00, 0x00, 0x00}; - uint32_t data; + uint8_t tx[4]; + + /* try to apply settings to max31956 and then read back settings */ + // Wr, register 0x00 + tx[0] = 0x00 | BIT(7); + // CR0: 50Hz mode + // Change the notch frequency only while in the "Normally Off" mode - not in the Automatic + tx[1] = BIT(0); + // CR1: 4 samples average, K type + // The Thermocouple Voltage Conversion Averaging Mode settings should not be changed while + // conversions are taking place. + tx[2] = (2 << 4) | (3 << 0); + + // Stop any conversion + ret = spi_txrx(tx, rx, 2); + if (ret) { + return ret; + } + + // Apply notch frequency and averaging + ret = spi_txrx(tx, rx, 3); + if (ret) { + return ret; + } - int ret = spi_txrx(tx, rx, 4); - if (ret) + // Start Automatic Conversion mode + // CR0: Automatic Conversion mode, OCFAULT = 2, 50Hz mode + tx[1] = BIT(7) | BIT(0) | (2 << 4); + // CR1: 4 samples average, K type + tx[2] = (2 << 4) | (3 << 0); + ret = spi_txrx(tx, rx, 3); + if (ret) { return ret; - data = (rx[0] << 24) | - (rx[1] << 16) | - (rx[2] << 8) | - (rx[3] << 0); - /* MASK, CJHF, CJLF defaults: 0xff, 0x7f, 0xc0 */ - if ((data & 0x00ffffff) == 0x00ff7fc0) { - /* configure */ - /* CR0: 50 Hz mode - * Change the notch frequency only while in the "Normally Off" mode - not in the Automatic - * Conversion mode.*/ - tx[0] = 0x80; - tx[1] = 0x01; - spi_txrx(tx, rx, 2); - /* CR0: Automatic Conversion mode, OCFAULT = 2, 50Hz mode */ - tx[1] = BIT(7) | BIT(0) | 2 << 4; - /* CR1: 4 samples average, K type */ - tx[2] = (2 << 4) | (3 << 0); - spi_txrx(tx, rx, 3); + } + + /* Now readback settings */ + tx[0] = 0x00; + ret = spi_txrx(tx, rx, 4); + if ((rx[1] == tx[1]) && (rx[2] == tx[2])) { type = MAX31856_TYPE; return 0; } - if (data != 0xffffffff) { + + /* in case of max31855 we get standart reply with few reserved, always zero bits */ + uint32_t data = (rx[0] << 24) | + (rx[1] << 16) | + (rx[2] << 8) | + (rx[3] << 0); + + /* MISO is constantly low or high */ + if ((data == 0xffffffff) || (data == 0x0)) { + return -1; + } + + if ((data & MAX31855_RESERVED_BITS) == 0x0) { type = MAX31855_TYPE; return 0; } From 6b062c4f48f81e48975a4a72afb5ec958ba7f0c3 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 18 Mar 2024 12:32:14 +0300 Subject: [PATCH 35/91] max3185x: no magic numbers --- firmware/max3185x.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/firmware/max3185x.cpp b/firmware/max3185x.cpp index 012535de..421172f7 100644 --- a/firmware/max3185x.cpp +++ b/firmware/max3185x.cpp @@ -158,19 +158,25 @@ int Max3185x::readPacket31855() { uint32_t data; + #define MAX33855_FAULT_BIT BIT(16) + #define MAX33855_OPEN_BIT BIT(0) + #define MAX33855_GND_BIT BIT(1) + #define MAX33855_VCC_BIT BIT(2) + int ret = spi_rx32(&data); - /* TODO: also check for 0x00000000? */ - if ((ret) || (data == 0xffffffff)) { + if (((data & MAX31855_RESERVED_BITS) != 0) || + (data == 0x0) || + (data == 0xffffffff)) { livedata.state = MAX3185X_NO_REPLY; ret = -1; } else if (data & BIT(16)) { - if (data & BIT(0)) { + if (data & MAX33855_OPEN_BIT) { livedata.state = MAX3185X_OPEN_CIRCUIT; - } else if (data & BIT(1)) { + } else if (data & MAX33855_GND_BIT) { livedata.state = MAX3185X_SHORT_TO_GND; - } else if (data & BIT(2)) { + } else if (data & MAX33855_VCC_BIT) { livedata.state = MAX3185X_SHORT_TO_VCC; } From 03c2bfcbccaa7f151fe90e26335c71e79e8f6219 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 18 Mar 2024 12:37:45 +0300 Subject: [PATCH 36/91] max3185x: check spi_txrx return value --- firmware/max3185x.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/firmware/max3185x.cpp b/firmware/max3185x.cpp index 421172f7..23365a68 100644 --- a/firmware/max3185x.cpp +++ b/firmware/max3185x.cpp @@ -215,13 +215,16 @@ int Max3185x::readPacket31855() int Max3185x::readPacket31856() { - uint8_t rx[7]; - /* read Cold-Junction temperature MSB, LSB, Linearized TC temperature 3 bytes and Fault Status */ - uint8_t tx[7] = {0x0a}; + uint8_t rx[1 + 6]; + /* read one dummy byte, Cold-Junction temperature MSB, LSB, Linearized TC temperature 3 bytes and Fault Status */ + uint8_t tx[1 + 6] = {0x0a}; - int ret = spi_txrx(tx, rx, 7); + int ret = spi_txrx(tx, rx, sizeof(rx)); - if (rx[6] & BIT(0)) { + if (ret) { + livedata.state = MAX3185X_NO_REPLY; + /* Do not overwrite ret */ + } else if (rx[6] & BIT(0)) { livedata.state = MAX3185X_OPEN_CIRCUIT; ret = -1; } else if (rx[6] & BIT(1)) { From 6b7d2c2e7797f4efcf0471f57d083477670ec2d1 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 18 Mar 2024 12:58:04 +0300 Subject: [PATCH 37/91] max3185x: simplify, fix negative values for max31856 --- firmware/max3185x.cpp | 149 +++++++++++++++++++----------------------- firmware/max3185x.h | 8 +-- 2 files changed, 73 insertions(+), 84 deletions(-) diff --git a/firmware/max3185x.cpp b/firmware/max3185x.cpp index 23365a68..6a5f25e4 100644 --- a/firmware/max3185x.cpp +++ b/firmware/max3185x.cpp @@ -86,7 +86,7 @@ int Max3185x::spi_rx32(uint32_t *data) // bits D17 and D3 are always expected to be zero #define MAX31855_RESERVED_BITS 0x20008 -int Max3185x::detect() +Max3185xType Max3185x::detect() { int ret; uint8_t rx[4]; @@ -106,13 +106,13 @@ int Max3185x::detect() // Stop any conversion ret = spi_txrx(tx, rx, 2); if (ret) { - return ret; + return UNKNOWN_TYPE; } // Apply notch frequency and averaging ret = spi_txrx(tx, rx, 3); if (ret) { - return ret; + return UNKNOWN_TYPE; } // Start Automatic Conversion mode @@ -122,15 +122,14 @@ int Max3185x::detect() tx[2] = (2 << 4) | (3 << 0); ret = spi_txrx(tx, rx, 3); if (ret) { - return ret; + return UNKNOWN_TYPE; } /* Now readback settings */ tx[0] = 0x00; ret = spi_txrx(tx, rx, 4); if ((rx[1] == tx[1]) && (rx[2] == tx[2])) { - type = MAX31856_TYPE; - return 0; + return MAX31856_TYPE; } /* in case of max31855 we get standart reply with few reserved, always zero bits */ @@ -141,20 +140,19 @@ int Max3185x::detect() /* MISO is constantly low or high */ if ((data == 0xffffffff) || (data == 0x0)) { - return -1; + return UNKNOWN_TYPE; } if ((data & MAX31855_RESERVED_BITS) == 0x0) { - type = MAX31855_TYPE; - return 0; + return MAX31855_TYPE; } livedata.state = MAX3185X_NO_REPLY; - type = UNKNOWN_TYPE; - return -1; + + return UNKNOWN_TYPE; } -int Max3185x::readPacket31855() +Max3185xState Max3185x::readPacket31855() { uint32_t data; @@ -165,55 +163,39 @@ int Max3185x::readPacket31855() int ret = spi_rx32(&data); - if (((data & MAX31855_RESERVED_BITS) != 0) || + if ((ret) || + ((data & MAX31855_RESERVED_BITS) != 0) || (data == 0x0) || (data == 0xffffffff)) { - livedata.state = MAX3185X_NO_REPLY; - - ret = -1; - } else if (data & BIT(16)) { + return MAX3185X_NO_REPLY; + } else if (data & MAX33855_FAULT_BIT) { if (data & MAX33855_OPEN_BIT) { - livedata.state = MAX3185X_OPEN_CIRCUIT; + return MAX3185X_OPEN_CIRCUIT; } else if (data & MAX33855_GND_BIT) { - livedata.state = MAX3185X_SHORT_TO_GND; + return MAX3185X_SHORT_TO_GND; } else if (data & MAX33855_VCC_BIT) { - livedata.state = MAX3185X_SHORT_TO_VCC; + return MAX3185X_SHORT_TO_VCC; } - - ret = -1; } - if (ret) { - coldJunctionTemperature = NAN; - livedata.coldJunctionTemperature = 0; - temperature = NAN; - livedata.temperature = 0; - } else { - /* D[15:4] */ - int16_t tmp = (data >> 4) & 0xfff; - /* extend sign */ - tmp = tmp << 4; - tmp = tmp >> 4; /* shifting right signed is not a good idea */ - coldJunctionTemperature = (float)tmp * 0.0625; - - /* D[31:18] */ - tmp = (data >> 18) & 0x3fff; - /* extend sign */ - tmp = tmp << 2; - tmp = tmp >> 2; /* shifting right signed is not a good idea */ - temperature = (float) tmp * 0.25; - - /* update livedata: float to int */ - livedata.coldJunctionTemperature = coldJunctionTemperature; - livedata.temperature = temperature; - - livedata.state = MAX3185X_OK; - } - - return ret; + /* D[15:4] */ + int16_t tmp = (data >> 4) & 0xfff; + /* extend sign */ + tmp = tmp << 4; + tmp = tmp >> 4; /* shifting right signed is not a good idea */ + coldJunctionTemperature = (float)tmp * 0.0625; + + /* D[31:18] */ + tmp = (data >> 18) & 0x3fff; + /* extend sign */ + tmp = tmp << 2; + tmp = tmp >> 2; /* shifting right signed is not a good idea */ + temperature = (float) tmp * 0.25; + + return MAX3185X_OK; } -int Max3185x::readPacket31856() +Max3185xState Max3185x::readPacket31856() { uint8_t rx[1 + 6]; /* read one dummy byte, Cold-Junction temperature MSB, LSB, Linearized TC temperature 3 bytes and Fault Status */ @@ -222,52 +204,59 @@ int Max3185x::readPacket31856() int ret = spi_txrx(tx, rx, sizeof(rx)); if (ret) { - livedata.state = MAX3185X_NO_REPLY; - /* Do not overwrite ret */ + return MAX3185X_NO_REPLY; } else if (rx[6] & BIT(0)) { - livedata.state = MAX3185X_OPEN_CIRCUIT; - ret = -1; + return MAX3185X_OPEN_CIRCUIT; } else if (rx[6] & BIT(1)) { - livedata.state = MAX3185X_SHORT_TO_VCC; - ret = -1; + return MAX3185X_SHORT_TO_VCC; } - if (ret) { - coldJunctionTemperature = NAN; - livedata.coldJunctionTemperature = 0; - temperature = NAN; - livedata.temperature = 0; - } else { - /* update livedata: float to int */ - coldJunctionTemperature = (float)(rx[1] << 8 | rx[2]) / 256.0; - temperature = (float)((rx[3] << 11) | (rx[4] << 3) | (rx[5] >> 5)) / 128.0; - livedata.coldJunctionTemperature = coldJunctionTemperature; - livedata.temperature = temperature; - - livedata.state = MAX3185X_OK; + if (1) { + // 10 bit before point and 7 bits after + int32_t tmp = (rx[3] << 11) | (rx[4] << 3) | (rx[5] >> 5); + /* extend sign: move top bit 18 to 31 */ + tmp = tmp << 13; + tmp = tmp >> 13; /* shifting right signed is not a good idea */ + temperature = ((float)tmp) / 128.0; + } + if (1) { + int16_t tmp = (rx[1] << 6) | (rx[2] >> 2); + /* extend sign */ + tmp = tmp << 2; + tmp = tmp >> 2; /* shifting right signed is not a good idea */ + coldJunctionTemperature = ((float)tmp) / 64.0; } - return ret; + return MAX3185X_OK; } -int Max3185x::readPacket() +Max3185xState Max3185x::readPacket() { - int ret; - if (type == UNKNOWN_TYPE) { - ret = detect(); - if (ret < 0) { - return ret; + type = detect(); + if (type == UNKNOWN_TYPE) { + livedata.state = MAX3185X_NO_REPLY; } } if (type == MAX31855_TYPE) { - return readPacket31855(); + livedata.state = readPacket31855(); } else if (type == MAX31856_TYPE) { - return readPacket31856(); + livedata.state = readPacket31856(); + } + + if (livedata.state == MAX3185X_OK) { + /* update livedata: float to int */ + livedata.coldJunctionTemperature = coldJunctionTemperature; + livedata.temperature = temperature; + } else { + coldJunctionTemperature = NAN; + livedata.coldJunctionTemperature = 0; + temperature = NAN; + livedata.temperature = 0; } - return -1; + return MAX3185X_OK; } void Max3185xThread::ThreadTask() { diff --git a/firmware/max3185x.h b/firmware/max3185x.h index 26a3a08d..672ab29c 100644 --- a/firmware/max3185x.h +++ b/firmware/max3185x.h @@ -49,12 +49,12 @@ class Max3185x { float coldJunctionTemperature; float temperature; Max3185xType type; - int readPacket(); + Max3185xState readPacket(); private: const SPIConfig *spi; - int detect(); - int readPacket31855(); - int readPacket31856(); + Max3185xType detect(); + Max3185xState readPacket31855(); + Max3185xState readPacket31856(); int spi_rx32(uint32_t *data); int spi_txrx(uint8_t tx[], uint8_t rx[], size_t n); }; From fd95e674ef65eef8902d2ab71cd5ff49d9c363b4 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 18 Mar 2024 13:12:52 +0300 Subject: [PATCH 38/91] max3185x: SPI ts buffer is const --- firmware/max3185x.cpp | 4 ++-- firmware/max3185x.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/max3185x.cpp b/firmware/max3185x.cpp index 6a5f25e4..0468fb9d 100644 --- a/firmware/max3185x.cpp +++ b/firmware/max3185x.cpp @@ -43,7 +43,7 @@ static Max3185x instances[EGT_CHANNELS] = {Max3185x(&spi_config[0]), Max3185x(&s static Max3185xThread EgtThread(instances); -int Max3185x::spi_txrx(uint8_t tx[], uint8_t rx[], size_t n) +int Max3185x::spi_txrx(const uint8_t tx[], uint8_t rx[], size_t n) { /* Acquire ownership of the bus. */ spiAcquireBus(EGT_SPI_DRIVER); @@ -199,7 +199,7 @@ Max3185xState Max3185x::readPacket31856() { uint8_t rx[1 + 6]; /* read one dummy byte, Cold-Junction temperature MSB, LSB, Linearized TC temperature 3 bytes and Fault Status */ - uint8_t tx[1 + 6] = {0x0a}; + const uint8_t tx[1 + 6] = {0x0a}; int ret = spi_txrx(tx, rx, sizeof(rx)); diff --git a/firmware/max3185x.h b/firmware/max3185x.h index 672ab29c..07aaa97a 100644 --- a/firmware/max3185x.h +++ b/firmware/max3185x.h @@ -56,7 +56,7 @@ class Max3185x { Max3185xState readPacket31855(); Max3185xState readPacket31856(); int spi_rx32(uint32_t *data); - int spi_txrx(uint8_t tx[], uint8_t rx[], size_t n); + int spi_txrx(const uint8_t tx[], uint8_t rx[], size_t n); }; class Max3185xThread : public ThreadController { From 722475a85e28620d2af18766392b40835343adff Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 18 Mar 2024 15:51:11 +0300 Subject: [PATCH 39/91] max3185x: paranoid check for max31856 --- firmware/max3185x.cpp | 18 ++++++++++++++++++ firmware/max3185x.h | 2 ++ 2 files changed, 20 insertions(+) diff --git a/firmware/max3185x.cpp b/firmware/max3185x.cpp index 0468fb9d..06aac822 100644 --- a/firmware/max3185x.cpp +++ b/firmware/max3185x.cpp @@ -211,6 +211,18 @@ Max3185xState Max3185x::readPacket31856() return MAX3185X_SHORT_TO_VCC; } + // Paranoid check. + bool allZero = true; + for (int i = 1; i < 6; i++) { + if (rx[i] != 0x00) { + allZero = false; + break; + } + } + if (allZero) { + return MAX3185X_NO_REPLY; + } + if (1) { // 10 bit before point and 7 bits after int32_t tmp = (rx[3] << 11) | (rx[4] << 3) | (rx[5] >> 5); @@ -256,6 +268,12 @@ Max3185xState Max3185x::readPacket() livedata.temperature = 0; } + /* in case of communication problems - reinit */ + if (livedata.state == MAX3185X_NO_REPLY) { + livedata.commErrors++; + type = UNKNOWN_TYPE; + } + return MAX3185X_OK; } diff --git a/firmware/max3185x.h b/firmware/max3185x.h index 07aaa97a..e42c8d33 100644 --- a/firmware/max3185x.h +++ b/firmware/max3185x.h @@ -26,6 +26,8 @@ struct livedata_egt_s { float temperature; float coldJunctionTemperature; uint8_t state; + uint8_t pad0[3]; + uint32_t commErrors; } __attribute__((packed)); uint8_t pad[16]; }; From e4fc23fec4edfb81bc3d40f09ab5452fb9d0e46d Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 18 Mar 2024 15:56:18 +0300 Subject: [PATCH 40/91] max3185x: start in proper state --- firmware/max3185x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/max3185x.h b/firmware/max3185x.h index e42c8d33..c94012d1 100644 --- a/firmware/max3185x.h +++ b/firmware/max3185x.h @@ -50,7 +50,7 @@ class Max3185x { /* do we need float temperatures? */ float coldJunctionTemperature; float temperature; - Max3185xType type; + Max3185xType type = UNKNOWN_TYPE; Max3185xState readPacket(); private: const SPIConfig *spi; From 74176a60043c92538154a616f7290eaee3cedd76 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 18 Mar 2024 16:05:51 +0300 Subject: [PATCH 41/91] max3185x: communication error counter to TS --- firmware/ini/wideband_dual.ini | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/firmware/ini/wideband_dual.ini b/firmware/ini/wideband_dual.ini index 621679d4..56587b5b 100644 --- a/firmware/ini/wideband_dual.ini +++ b/firmware/ini/wideband_dual.ini @@ -153,11 +153,13 @@ AFR1_heater = scalar, U08, 93, "", 1, 0 EGT0_temp = scalar, F32, 96, "C", 1, 0 EGT0_coldJunction = scalar, F32, 100, "C", 1, 0 EGT0_state = scalar, U08, 104, "", 1, 0 +EGT0_commErrors = scalar, U32, 108, "n", 1, 0 ; EGT1 EGT1_temp = scalar, F32, 112, "C", 1, 0 EGT1_coldJunction = scalar, F32, 116, "C", 1, 0 EGT1_state = scalar, U08, 120, "", 1, 0 +EGT1_commErrors = scalar, U32, 124, "n", 1, 0 ; TODO: something is wrong with these Aux0InputSig = { (Aux0InputSel == 0) ? AFR0_lambda : ((Aux0InputSel == 1) ? AFR1_lambda : ((Aux0InputSel == 2) ? EGT0_temp : EGT1_temp)) } @@ -237,6 +239,7 @@ gaugeCategory = EGT channel 0 EGT0_Gauge = EGT0_temp, "0: EGT", "C", 0.0, 1600.0, 100.0, 250.0, 900.0, 1000.0, 0, 0 EGT0_ColdJunctionGauge = EGT0_coldJunction, "0: EGT CJ", "C", 0.0, 130.0, -55.0, -20.0, 95.0, 105.0, 1, 1 EGT0_StateGauge = EGT0_state, "0: EGT state", "", 0.0, 5.0, 0.0, 0.0, 0.5, 0.5, 0, 0 +EGT0_CommErrorsGauge = EGT0_commErrors,"0: EGT comm errors", "", 0.0, 10, 0.0, 0.0, 1, 1, 0, 0 ; EGT1 gaugeCategory = EGT channel 1 @@ -244,6 +247,7 @@ gaugeCategory = EGT channel 1 EGT1_Gauge = EGT1_temp, "1: EGT", "C", 0.0, 1600.0, 100.0, 250.0, 900.0, 1000.0, 0, 0 EGT1_ColdJunctionGauge = EGT1_coldJunction, "1: EGT CJ", "C", 0.0, 130.0, -55.0, -20.0, 95.0, 105.0, 1, 1 EGT1_StateGauge = EGT1_state, "1: EGT state", "", 0.0, 5.0, 0.0, 0.0, 0.5, 0.5, 0, 0 +EGT1_CommErrorsGauge = EGT1_commErrors,"1: EGT comm errors", "", 0.0, 10, 0.0, 0.0, 1, 1, 0, 0 ; AUX outputs Aux0InputGauge = { (Aux0InputSel == 0) ? AFR0_AfrGauge : ((Aux0InputSel == 1) ? AFR1_AfrGauge : ((Aux0InputSel == 2) ? EGT0_Gauge : EGT1_Gauge)) } @@ -316,11 +320,13 @@ entry = AFR1_esr, "1: ESR", float, "%.1f" entry = EGT0_temp, "EGT 0: EGT", int, "%d" entry = EGT0_coldJunction, "EGT 0: CJ", int, "%d" entry = EGT0_state, "EGT 0: State", int, "%d" +entry = EGT0_commErrors, "EGT 0: comm errors", int, "%d" ; EGT1 entry = EGT1_temp, "EGT 1: EGT", int, "%d" entry = EGT1_coldJunction, "EGT 1: CJ", int, "%d" entry = EGT1_state, "EGT 1: State", int, "%d" +entry = EGT1_commErrors, "EGT 1: comm errors", int, "%d" [Menu] From b55beffef8c1ae62764bd8d747141ccd8dee9a47 Mon Sep 17 00:00:00 2001 From: Alexey Esaulenko Date: Mon, 8 Apr 2024 17:22:34 +0400 Subject: [PATCH 42/91] Github action to auto-generate releases --- .github/workflows/build-firmware.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/build-firmware.yaml b/.github/workflows/build-firmware.yaml index 8e86fa63..3d1b0b20 100644 --- a/.github/workflows/build-firmware.yaml +++ b/.github/workflows/build-firmware.yaml @@ -48,3 +48,12 @@ jobs: with: name: Wideband ${{matrix.build-target}} path: ./firmware/deliver/${{matrix.build-target}}/wideband* + + - name: Zip artifacts + run: zip Wideband\ ${{matrix.build-target}}.zip ./firmware/deliver/${{matrix.build-target}}/wideband* + + - name: Make a new Release + uses: softprops/action-gh-release@v2 + if: startsWith(github.ref, 'refs/tags/') + with: + files: Wideband\ ${{matrix.build-target}}.zip From f37a034483feec5e921fe705705477d6c79c4b02 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Sun, 10 Mar 2024 20:19:01 -0700 Subject: [PATCH 43/91] allow manual fw runs --- .github/workflows/build-firmware.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-firmware.yaml b/.github/workflows/build-firmware.yaml index 3d1b0b20..493e2020 100644 --- a/.github/workflows/build-firmware.yaml +++ b/.github/workflows/build-firmware.yaml @@ -1,6 +1,6 @@ name: Build Firmware -on: [push, pull_request] +on: [push, pull_request, workflow_dispatch] jobs: build-firmware: From a9facf42334d201444682eab7dc7a65f17748732 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sat, 23 Mar 2024 21:39:53 +0300 Subject: [PATCH 44/91] f0_module needs hack to start pump before closed loop --- firmware/boards/f0_module/wideband_board_config.h | 6 ++++++ firmware/pump_control.cpp | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/firmware/boards/f0_module/wideband_board_config.h b/firmware/boards/f0_module/wideband_board_config.h index 529dcf9c..dbeb1c07 100644 --- a/firmware/boards/f0_module/wideband_board_config.h +++ b/firmware/boards/f0_module/wideband_board_config.h @@ -17,3 +17,9 @@ // Nernst voltage & ESR sense // ******************************* #define VM_RESISTOR_VALUE (10) + +// ******************************* +// Hack: allow pump driving above this temperature +// to avoid Vnerns voltage clamp near 0V +// ******************************* +#define START_PUMP_TEMP_THRESHOLD (650.0) diff --git a/firmware/pump_control.cpp b/firmware/pump_control.cpp index 601d7d98..0a4a0d6e 100644 --- a/firmware/pump_control.cpp +++ b/firmware/pump_control.cpp @@ -38,7 +38,11 @@ static void PumpThread(void*) const auto& heater = GetHeaterController(ch); // Only actuate pump when running closed loop! - if (heater.IsRunningClosedLoop()) + if (heater.IsRunningClosedLoop() || +#ifdef START_PUMP_TEMP_THRESHOLD + (sampler.GetSensorTemperature() >= START_PUMP_TEMP_THRESHOLD) || +#endif + (0)) { float nernstVoltage = sampler.GetNernstDc(); From 5c672e42021dfc71c6412592c260bb74b76f050f Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sat, 23 Mar 2024 21:42:57 +0300 Subject: [PATCH 45/91] Fix paranoid check --- firmware/pump_dac.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/firmware/pump_dac.cpp b/firmware/pump_dac.cpp index ed543a68..21de9825 100644 --- a/firmware/pump_dac.cpp +++ b/firmware/pump_dac.cpp @@ -90,11 +90,13 @@ void InitPumpDac() void SetPumpCurrentTarget(int ch, int32_t microampere) { +#ifndef START_PUMP_TEMP_THRESHOLD // Don't allow pump current when the sensor isn't hot if (!GetHeaterController(ch).IsRunningClosedLoop()) { microampere = 0; } +#endif state[ch].curIpump = microampere; From 4adc794ae576f4aaf74c77ccfa342824c86832c9 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 14 Apr 2024 15:00:36 +0300 Subject: [PATCH 46/91] Make START_PUMP_TEMP_THRESHOLD relative --- firmware/boards/f0_module/wideband_board_config.h | 6 +++--- firmware/heater_control.cpp | 5 +++++ firmware/heater_control.h | 2 ++ firmware/pump_control.cpp | 4 ++-- firmware/pump_dac.cpp | 2 +- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/firmware/boards/f0_module/wideband_board_config.h b/firmware/boards/f0_module/wideband_board_config.h index dbeb1c07..b71fc989 100644 --- a/firmware/boards/f0_module/wideband_board_config.h +++ b/firmware/boards/f0_module/wideband_board_config.h @@ -19,7 +19,7 @@ #define VM_RESISTOR_VALUE (10) // ******************************* -// Hack: allow pump driving above this temperature -// to avoid Vnerns voltage clamp near 0V +// Hack: allow pump driving above target temperature +// minus this offset to avoid Vnerns voltage clamp near 0V // ******************************* -#define START_PUMP_TEMP_THRESHOLD (650.0) +#define START_PUMP_TEMP_OFFSET (200.0) diff --git a/firmware/heater_control.cpp b/firmware/heater_control.cpp index 2c072b3d..84d390b8 100644 --- a/firmware/heater_control.cpp +++ b/firmware/heater_control.cpp @@ -28,6 +28,11 @@ bool HeaterControllerBase::IsRunningClosedLoop() const return heaterState == HeaterState::ClosedLoop; } +float HeaterControllerBase::GetTargetTemp() const +{ + return m_targetTempC; +} + float HeaterControllerBase::GetHeaterEffectiveVoltage() const { return heaterVoltage; diff --git a/firmware/heater_control.h b/firmware/heater_control.h index 35854843..c35a99fa 100644 --- a/firmware/heater_control.h +++ b/firmware/heater_control.h @@ -25,6 +25,7 @@ struct IHeaterController virtual bool IsRunningClosedLoop() const = 0; virtual float GetHeaterEffectiveVoltage() const = 0; virtual HeaterState GetHeaterState() const = 0; + virtual float GetTargetTemp() const = 0; }; class HeaterControllerBase : public IHeaterController @@ -37,6 +38,7 @@ class HeaterControllerBase : public IHeaterController bool IsRunningClosedLoop() const override; float GetHeaterEffectiveVoltage() const override; HeaterState GetHeaterState() const override; + float GetTargetTemp() const override; virtual void SetDuty(float duty) const = 0; diff --git a/firmware/pump_control.cpp b/firmware/pump_control.cpp index 0a4a0d6e..9bf6eb95 100644 --- a/firmware/pump_control.cpp +++ b/firmware/pump_control.cpp @@ -39,8 +39,8 @@ static void PumpThread(void*) // Only actuate pump when running closed loop! if (heater.IsRunningClosedLoop() || -#ifdef START_PUMP_TEMP_THRESHOLD - (sampler.GetSensorTemperature() >= START_PUMP_TEMP_THRESHOLD) || +#ifdef START_PUMP_TEMP_OFFSET + (sampler.GetSensorTemperature() >= heater.GetTargetTemp() - START_PUMP_TEMP_OFFSET) || #endif (0)) { diff --git a/firmware/pump_dac.cpp b/firmware/pump_dac.cpp index 21de9825..9d6576f7 100644 --- a/firmware/pump_dac.cpp +++ b/firmware/pump_dac.cpp @@ -90,7 +90,7 @@ void InitPumpDac() void SetPumpCurrentTarget(int ch, int32_t microampere) { -#ifndef START_PUMP_TEMP_THRESHOLD +#ifndef START_PUMP_TEMP_OFFSET // Don't allow pump current when the sensor isn't hot if (!GetHeaterController(ch).IsRunningClosedLoop()) { From d321f9826e609c7ac45f2a389e367f531213935f Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 7 Apr 2024 19:40:16 +0300 Subject: [PATCH 47/91] default settings: fix RusEFI CAN messages offset --- firmware/boards/f1_common/f1_port.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/boards/f1_common/f1_port.cpp b/firmware/boards/f1_common/f1_port.cpp index c898972e..96075af1 100644 --- a/firmware/boards/f1_common/f1_port.cpp +++ b/firmware/boards/f1_common/f1_port.cpp @@ -71,7 +71,7 @@ void Configuration::LoadDefaults() // enable RusEFI protocol afr[i].RusEfiTx = true; afr[i].RusEfiTxDiag = true; - afr[i].RusEfiIdOffset = i; + afr[i].RusEfiIdOffset = 2 * i; // Disable AemNet afr[i].AemNetTx = false; From 8a2e4f2e83a5bee72cd9735245eae306a08641fa Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 2 Jun 2024 19:21:05 +0300 Subject: [PATCH 48/91] README update --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 10126927..9cf5d866 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,13 @@ +# Wideband + +This fork is for development of FW for [RusEFI](https://github.com/rusefi) [dual channel wideband](https://github.com/rusefi/rusefi-hardware/tree/main/lambda-x2). Based on [initial desing](https://github.com/mck1117/wideband) from [mck1117](https://github.com/mck1117) + +For stm32f042 FW please refer to original repo. While I try to keep it buildable and unaffected by my modification I can not quaranty its functionality and provide any support. + +[OpenBLT](https://github.com/feaser/openblt) bootloader is used for FW update functionality. Please reffer to original [documentation](https://www.feaser.com/openblt/doku.php?id=faq) on how to compile host tools and use it. + +# Original readme + [![Build Firmware](https://github.com/mck1117/wideband/actions/workflows/build-firmware.yaml/badge.svg)](https://github.com/mck1117/wideband/actions/workflows/build-firmware.yaml) ![license](https://img.shields.io/github/license/mck1117/wideband) # rusEFI Wideband Controller From 698bebf88457bf5dd4b16000f6d64506d549b18b Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 2 Jun 2024 19:34:12 +0300 Subject: [PATCH 49/91] README: flashing --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 9cf5d866..268a112c 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,20 @@ This fork is for development of FW for [RusEFI](https://github.com/rusefi) [dual For stm32f042 FW please refer to original repo. While I try to keep it buildable and unaffected by my modification I can not quaranty its functionality and provide any support. +# Initial flashing + +For initial flashing of newly assembled device under Windows please refer to [this instruction](https://rusefi.com/forum/viewtopic.php?p=48379#p48379). + +I hope Linux users are experience enough to know how to use [stm32flash tool](https://github.com/ARMinARM/stm32flash). There are two sample scripts to [flash OpenBLT only](/firmware/dfu_flash_openblt.sh) and [flash combined image of OpenBLT + main FW](/firmware/dfu_flash.sh). + +# Update using OpenBLT + [OpenBLT](https://github.com/feaser/openblt) bootloader is used for FW update functionality. Please reffer to original [documentation](https://www.feaser.com/openblt/doku.php?id=faq) on how to compile host tools and use it. +There are few sample linux scripts for updating device over [CAN](/firmware/flash_can.sh) or [UART](/firmware/flash_uart.sh). + +Linux users can use almost any USB to CAN adapter supported by linux and providing SocketCAN interface ([for example](https://rusefi.com/forum/viewtopic.php?f=13&t=2209)). Windows users please check OpenBLT documentation. + # Original readme [![Build Firmware](https://github.com/mck1117/wideband/actions/workflows/build-firmware.yaml/badge.svg)](https://github.com/mck1117/wideband/actions/workflows/build-firmware.yaml) ![license](https://img.shields.io/github/license/mck1117/wideband) From 76abf589d6dac5199dfa47b8dca688d4869f26c9 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 2 Jun 2024 19:35:53 +0300 Subject: [PATCH 50/91] Missed flashing scripts --- firmware/dfu_flash.sh | 17 +++++++++++++++++ firmware/dfu_flash_openblt.sh | 16 ++++++++++++++++ firmware/flash_uart.sh | 26 ++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100755 firmware/dfu_flash.sh create mode 100755 firmware/dfu_flash_openblt.sh create mode 100755 firmware/flash_uart.sh diff --git a/firmware/dfu_flash.sh b/firmware/dfu_flash.sh new file mode 100755 index 00000000..41e1baf2 --- /dev/null +++ b/firmware/dfu_flash.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +usage() { + cat < Date: Sun, 2 Jun 2024 19:38:30 +0300 Subject: [PATCH 51/91] README: minor changes --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 268a112c..98662061 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Wideband -This fork is for development of FW for [RusEFI](https://github.com/rusefi) [dual channel wideband](https://github.com/rusefi/rusefi-hardware/tree/main/lambda-x2). Based on [initial desing](https://github.com/mck1117/wideband) from [mck1117](https://github.com/mck1117) +This fork is for development of FW for [RusEFI](https://github.com/rusefi) [dual channel wideband](https://github.com/rusefi/rusefi-hardware/tree/main/lambda-x2). Based on [original desing](https://github.com/mck1117/wideband) from [mck1117](https://github.com/mck1117) -For stm32f042 FW please refer to original repo. While I try to keep it buildable and unaffected by my modification I can not quaranty its functionality and provide any support. +For stm32f042 FW please refer to original repo. While I try to keep it buildable and unaffected by my modification I can not guaranty its functionality and provide any support. # Initial flashing From fd1c2f0057fbef3a2e34639ddd1934e50dec0196 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 6 Jan 2025 11:23:46 +0300 Subject: [PATCH 52/91] uart: directly chprintf() to SD device --- firmware/uart.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/firmware/uart.cpp b/firmware/uart.cpp index 127a488e..54f72815 100644 --- a/firmware/uart.cpp +++ b/firmware/uart.cpp @@ -22,7 +22,7 @@ SerialConfig cfg = { .cr3 = 0 }; -static char printBuffer[200]; +BaseSequentialStream *chp = (BaseSequentialStream *) &SD1; static THD_WORKING_AREA(waUartThread, 512); static void UartThread(void*) @@ -42,7 +42,7 @@ static void UartThread(void*) int batteryVoltageMv = GetSampler(ch).GetInternalHeaterVoltage() * 1000; int duty = GetHeaterDuty(ch) * 100; - size_t writeCount = chsnprintf(printBuffer, 200, + chprintf(chp, "[AFR%d]: %d.%03d DC: %4d mV AC: %4d mV ESR: %5d T: %4d C Ipump: %6d uA Vheater: %5d heater: %s (%d)\tfault: %s\r\n", ch, lambdaIntPart, lambdaThousandths, @@ -54,16 +54,14 @@ static void UartThread(void*) batteryVoltageMv, describeHeaterState(GetHeaterState(ch)), duty, describeFault(GetCurrentFault(ch))); - chnWrite(&SD1, (const uint8_t *)printBuffer, writeCount); } #if (EGT_CHANNELS > 0) for (ch = 0; ch < EGT_CHANNELS; ch++) { - size_t writeCount = chsnprintf(printBuffer, 200, + chprintf(chp, "EGT[%d]: %d C (int %d C)\r\n", (int)getEgtDrivers()[ch].temperature, (int)getEgtDrivers()[ch].coldJunctionTemperature); - chnWrite(&SD1, (const uint8_t *)printBuffer, writeCount); } #endif /* EGT_CHANNELS > 0 */ From 5690b5caeb82585c5762e7bbd27620971abd9b3b Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 6 Jan 2025 11:56:34 +0300 Subject: [PATCH 53/91] uart: fix debug code compilation --- firmware/uart.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/firmware/uart.cpp b/firmware/uart.cpp index 54f72815..8d87668a 100644 --- a/firmware/uart.cpp +++ b/firmware/uart.cpp @@ -37,20 +37,22 @@ static void UartThread(void*) for (ch = 0; ch < AFR_CHANNELS; ch++) { float lambda = GetLambda(ch); + const auto& sampler = GetSampler(ch); + int lambdaIntPart = lambda; int lambdaThousandths = (lambda - lambdaIntPart) * 1000; - int batteryVoltageMv = GetSampler(ch).GetInternalHeaterVoltage() * 1000; + int batteryVoltageMv = sampler.GetInternalHeaterVoltage() * 1000; int duty = GetHeaterDuty(ch) * 100; chprintf(chp, "[AFR%d]: %d.%03d DC: %4d mV AC: %4d mV ESR: %5d T: %4d C Ipump: %6d uA Vheater: %5d heater: %s (%d)\tfault: %s\r\n", ch, lambdaIntPart, lambdaThousandths, - (int)(GetSampler(ch).GetNernstDc(ch) * 1000.0), - (int)(GetSampler(ch).GetNernstAc(ch) * 1000.0), - (int)GetSampler(ch).GetSensorInternalResistance(ch), - (int)GetSampler(ch).GetSensorTemperature(ch), - (int)(GetSampler(ch).GetPumpNominalCurrent(ch) * 1000), + (int)(sampler.GetNernstDc() * 1000.0), + (int)(sampler.GetNernstAc() * 1000.0), + (int)sampler.GetSensorInternalResistance(), + (int)sampler.GetSensorTemperature(), + (int)(sampler.GetPumpNominalCurrent() * 1000), batteryVoltageMv, describeHeaterState(GetHeaterState(ch)), duty, describeFault(GetCurrentFault(ch))); @@ -59,7 +61,8 @@ static void UartThread(void*) #if (EGT_CHANNELS > 0) for (ch = 0; ch < EGT_CHANNELS; ch++) { chprintf(chp, - "EGT[%d]: %d C (int %d C)\r\n", + "[EGT%d]: %d C (int %d C)\r\n", + ch, (int)getEgtDrivers()[ch].temperature, (int)getEgtDrivers()[ch].coldJunctionTemperature); } From 692bd1db2eaf12d5a18d5637c2fde1f34ae1f95d Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Fri, 15 Jul 2022 22:53:49 +0300 Subject: [PATCH 54/91] heater: 5 sec stabilization time after switching to closed loop LSU4.2 falls to Underheated state right after switch to closed loop due to rise of sensorEsr (due to applied pump current?) --- firmware/heater_control.cpp | 26 +++++++++++++++++--------- firmware/heater_control.h | 1 + firmware/wideband_config.h | 1 + test/tests/test_heater.cpp | 7 +++++++ 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/firmware/heater_control.cpp b/firmware/heater_control.cpp index 9c2463e5..0c0ea813 100644 --- a/firmware/heater_control.cpp +++ b/firmware/heater_control.cpp @@ -30,6 +30,7 @@ void HeaterControllerBase::Configure(float targetTempC, float targetEsr) m_preheatTimer.reset(); m_warmupTimer.reset(); m_batteryStableTimer.reset(); + m_closedLoopStableTimer.reset(); } bool HeaterControllerBase::IsRunningClosedLoop() const @@ -116,6 +117,7 @@ HeaterState HeaterControllerBase::GetNextState(HeaterState currentState, HeaterA case HeaterState::WarmupRamp: if (sensorTemp > closedLoopTemp) { + m_closedLoopStableTimer.reset(); return HeaterState::ClosedLoop; } else if (m_warmupTimer.hasElapsedSec(m_warmupTimeSec)) @@ -137,15 +139,21 @@ HeaterState HeaterControllerBase::GetNextState(HeaterState currentState, HeaterA m_underheatTimer.reset(); } - if (m_overheatTimer.hasElapsedSec(0.5f)) - { - SetFault(ch, Fault::SensorOverheat); - return HeaterState::Stopped; - } - else if (m_underheatTimer.hasElapsedSec(0.5f)) - { - SetFault(ch, Fault::SensorUnderheat); - return HeaterState::Stopped; + if (m_closedLoopStableTimer.hasElapsedSec(HEATER_CLOSED_LOOP_STAB_TIME)) { + if (m_overheatTimer.hasElapsedSec(0.5f)) + { + SetFault(ch, Fault::SensorOverheat); + return HeaterState::Stopped; + } + else if (m_underheatTimer.hasElapsedSec(0.5f)) + { + SetFault(ch, Fault::SensorUnderheat); + return HeaterState::Stopped; + } + } else { + // give some time for stabilization... + // looks like heavy ramped Ipump affects sensorTemp measure + // and right after switch to closed loop sensorTemp drops below underhead threshold } break; diff --git a/firmware/heater_control.h b/firmware/heater_control.h index 3c9f09f7..60c4de12 100644 --- a/firmware/heater_control.h +++ b/firmware/heater_control.h @@ -68,6 +68,7 @@ class HeaterControllerBase : public IHeaterController Timer m_batteryStableTimer; Timer m_preheatTimer; Timer m_warmupTimer; + Timer m_closedLoopStableTimer; // Stores the time since a non-over/underheat condition // If the timer reaches a threshold, an over/underheat has diff --git a/firmware/wideband_config.h b/firmware/wideband_config.h index 5416233e..089b4393 100644 --- a/firmware/wideband_config.h +++ b/firmware/wideband_config.h @@ -42,6 +42,7 @@ #define HEATER_PREHEAT_TIME 5 #define HEATER_WARMUP_TIMEOUT 60 +#define HEATER_CLOSED_LOOP_STAB_TIME 5 #define HEATER_BATTERY_STAB_TIME 0.5f // minimal battery voltage to start heating without CAN command diff --git a/test/tests/test_heater.cpp b/test/tests/test_heater.cpp index d3de9272..54de18e4 100644 --- a/test/tests/test_heater.cpp +++ b/test/tests/test_heater.cpp @@ -126,6 +126,13 @@ TEST(HeaterStateMachine, ClosedLoop) Timer::setMockTime(0); dut.Configure(780, 300); + // Check 5 sec stabilization timeout + EXPECT_EQ(HeaterState::ClosedLoop, dut.GetNextState(HeaterState::ClosedLoop, HeaterAllow::Allowed, 12, 780)); + Timer::advanceMockTime(1e6); + EXPECT_EQ(HeaterState::ClosedLoop, dut.GetNextState(HeaterState::ClosedLoop, HeaterAllow::Allowed, 12, 1000)); + Timer::advanceMockTime(1e6); + EXPECT_EQ(HeaterState::ClosedLoop, dut.GetNextState(HeaterState::ClosedLoop, HeaterAllow::Allowed, 12, 200)); + // Temperature is reasonable, stay in closed loop EXPECT_EQ(HeaterState::ClosedLoop, dut.GetNextState(HeaterState::ClosedLoop, HeaterAllow::Allowed, 12, 780)); Timer::advanceMockTime(10e6); From 860d3e9aac9a141712919252c9c1814eb64bea12 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 5 Feb 2023 01:11:31 +0300 Subject: [PATCH 55/91] heater_control: retry heating attempt after timeout --- firmware/heater_control.cpp | 15 +++++++++++++++ firmware/heater_control.h | 3 +++ firmware/wideband_config.h | 5 +++++ 3 files changed, 23 insertions(+) diff --git a/firmware/heater_control.cpp b/firmware/heater_control.cpp index 0c0ea813..f0ea7f93 100644 --- a/firmware/heater_control.cpp +++ b/firmware/heater_control.cpp @@ -123,6 +123,9 @@ HeaterState HeaterControllerBase::GetNextState(HeaterState currentState, HeaterA else if (m_warmupTimer.hasElapsedSec(m_warmupTimeSec)) { SetFault(ch, Fault::SensorDidntHeat); + // retry after timeout + m_retryTime = HEATER_DIDNOTHEAT_RETRY_TIMEOUT; + m_retryTimer.reset(); return HeaterState::Stopped; } @@ -143,11 +146,17 @@ HeaterState HeaterControllerBase::GetNextState(HeaterState currentState, HeaterA if (m_overheatTimer.hasElapsedSec(0.5f)) { SetFault(ch, Fault::SensorOverheat); + // retry after timeout + m_retryTime = HEATER_OVERHEAT_RETRY_TIMEOUT; + m_retryTimer.reset(); return HeaterState::Stopped; } else if (m_underheatTimer.hasElapsedSec(0.5f)) { SetFault(ch, Fault::SensorUnderheat); + // retry after timeout + m_retryTime = HEATER_UNDERHEAT_RETRY_TIMEOUT; + m_retryTimer.reset(); return HeaterState::Stopped; } } else { @@ -155,9 +164,15 @@ HeaterState HeaterControllerBase::GetNextState(HeaterState currentState, HeaterA // looks like heavy ramped Ipump affects sensorTemp measure // and right after switch to closed loop sensorTemp drops below underhead threshold } + // reset fault + SetFault(ch, Fault::None); break; case HeaterState::Stopped: + if ((m_retryTime) && (m_retryTimer.hasElapsedSec(m_retryTime))) { + return HeaterState::Preheat; + } + break; case HeaterState::NoHeaterSupply: /* nop */ break; diff --git a/firmware/heater_control.h b/firmware/heater_control.h index 60c4de12..03234f8b 100644 --- a/firmware/heater_control.h +++ b/firmware/heater_control.h @@ -65,10 +65,13 @@ class HeaterControllerBase : public IHeaterController const int m_preheatTimeSec; const int m_warmupTimeSec; + int m_retryTime = 0; + Timer m_batteryStableTimer; Timer m_preheatTimer; Timer m_warmupTimer; Timer m_closedLoopStableTimer; + Timer m_retryTimer; // Stores the time since a non-over/underheat condition // If the timer reaches a threshold, an over/underheat has diff --git a/firmware/wideband_config.h b/firmware/wideband_config.h index 089b4393..1a8bbee9 100644 --- a/firmware/wideband_config.h +++ b/firmware/wideband_config.h @@ -45,6 +45,11 @@ #define HEATER_CLOSED_LOOP_STAB_TIME 5 #define HEATER_BATTERY_STAB_TIME 0.5f + +#define HEATER_DIDNOTHEAT_RETRY_TIMEOUT 30 +#define HEATER_OVERHEAT_RETRY_TIMEOUT 60 +#define HEATER_UNDERHEAT_RETRY_TIMEOUT 30 + // minimal battery voltage to start heating without CAN command #define HEATER_BATTERY_ON_VOLTAGE 9.5 // mininal battery voltage to continue heating From 3b8f61030ac172ed63f0c0023690e68df502174b Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 19 Feb 2023 12:31:53 +0300 Subject: [PATCH 56/91] heater_control: report SensorNoHeatSupply if no supply --- firmware/heater_control.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/firmware/heater_control.cpp b/firmware/heater_control.cpp index f0ea7f93..5637773c 100644 --- a/firmware/heater_control.cpp +++ b/firmware/heater_control.cpp @@ -64,6 +64,8 @@ HeaterState HeaterControllerBase::GetNextState(HeaterState currentState, HeaterA if (heaterSupplyVoltage < HEATER_BATTETY_OFF_VOLTAGE) { m_batteryStableTimer.reset(); + // set fault + SetFault(ch, Fault::SensorNoHeatSupply); return HeaterState::NoHeaterSupply; } else if (heaterSupplyVoltage > HEATER_BATTERY_ON_VOLTAGE) From 114189424489f07724edf653d110d3ede211599c Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Thu, 2 Feb 2023 00:08:32 +0300 Subject: [PATCH 57/91] f1_dual: select bigger Vbat voltage from two heater voltages --- firmware/livedata.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/firmware/livedata.cpp b/firmware/livedata.cpp index d69a37b7..45ee6878 100644 --- a/firmware/livedata.cpp +++ b/firmware/livedata.cpp @@ -16,6 +16,7 @@ static livedata_afr_s livedata_afr[AFR_CHANNELS]; void SamplingUpdateLiveData() { + float vbat = 0; for (int ch = 0; ch < AFR_CHANNELS; ch++) { volatile struct livedata_afr_s *data = &livedata_afr[ch]; @@ -34,9 +35,11 @@ void SamplingUpdateLiveData() data->esr = sampler.GetSensorInternalResistance(); data->fault = (uint8_t)GetCurrentFault(ch); data->heaterState = (uint8_t)GetHeaterState(ch); + if (sampler.GetInternalHeaterVoltage(ch) > vbat) + vbat = sampler.GetInternalHeaterVoltage(ch); } - livedata_common.vbatt = GetSampler(0).GetInternalHeaterVoltage(); + livedata_common.vbatt = vbat; } template<> From 1956861337bbd4e2146691d4fef967e1b4fbe70c Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Thu, 2 Feb 2023 00:11:12 +0300 Subject: [PATCH 58/91] TODO --- firmware/livedata.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/livedata.cpp b/firmware/livedata.cpp index 45ee6878..066b519a 100644 --- a/firmware/livedata.cpp +++ b/firmware/livedata.cpp @@ -35,6 +35,7 @@ void SamplingUpdateLiveData() data->esr = sampler.GetSensorInternalResistance(); data->fault = (uint8_t)GetCurrentFault(ch); data->heaterState = (uint8_t)GetHeaterState(ch); + /* TODO: add GetPumpOutputDuty() */ if (sampler.GetInternalHeaterVoltage(ch) > vbat) vbat = sampler.GetInternalHeaterVoltage(ch); } From d4ee6e97a090ab661bb6e93b9ac6d755d977ea4a Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Thu, 2 Feb 2023 00:45:22 +0300 Subject: [PATCH 59/91] livedata: show per-channel heater supply voltage --- firmware/ini/wideband_dual.ini | 12 +++++++++--- firmware/ini/wideband_f1.ini | 5 ++++- firmware/livedata.cpp | 7 +++++-- firmware/livedata.h | 2 +- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/firmware/ini/wideband_dual.ini b/firmware/ini/wideband_dual.ini index c4a0bc38..5fa68605 100644 --- a/firmware/ini/wideband_dual.ini +++ b/firmware/ini/wideband_dual.ini @@ -97,6 +97,7 @@ VBatt = scalar, F32, 0, "V", 1, 0 AFR0_lambda = scalar, F32, 32, "", 1, 0 AFR0_afr = scalar, F32, 32, "", 14.7, 0 AFR0_temp = scalar, U16, 36, "C", 0.1, 0 +AFR0_HeaterSupply = scalar, U16, 38, "V", 0.01, 0 AFR0_NernstDc = scalar, U16, 40, "V", 0.001, 0 AFR0_NernstAc = scalar, U16, 42, "V", 0.001, 0 AFR0_PumpITarget = scalar, F32, 44, "mA", 1, 0 @@ -111,6 +112,7 @@ AFR0_heater = scalar, U08, 61, "", 1, 0 AFR1_lambda = scalar, F32, 64, "", 1, 0 AFR1_afr = scalar, F32, 64, "", 14.7, 0 AFR1_temp = scalar, U16, 68, "C", 0.1, 0 +AFR1_HeaterSupply = scalar, U16, 70, "V", 0.01, 0 AFR1_NernstDc = scalar, U16, 72, "V", 0.001, 0 AFR1_NernstAc = scalar, U16, 74, "V", 0.001, 0 AFR1_PumpITarget = scalar, F32, 76, "mA", 1, 0 @@ -179,6 +181,7 @@ gaugeCategory = AFR channel 0 AFR0_LambdaGauge = AFR0_lambda, "0: lambda", "", 0.5, 1.3, 0.5, 0.6, 1.05, 1.2, 3, 3 AFR0_AfrGauge = AFR0_afr, "0: AFR", "", 6.5, 20.0, 9.0, 10.0, 16.0, 17.0, 2, 2 AFR0_TempGauge = AFR0_temp, "0: AFR t", "C", 500, 1050, 500, 650, 800, 950, 0, 0 +AFR0_HeaterSupply = AFR0_HeaterSupply,"0: Heater Supply", "V", 3.0, 24.0, 9.0, 11.0, 15.0, 16.0, 1, 1 AFR0_NernstDcGauge = AFR0_NernstDc, "0: nernst DC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR0_NernstAcGauge = AFR0_NernstAc, "0: nernst AC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR0_HeaterDutyGauge = AFR0_HeaterDuty, "0: Heater Duty", "%", 0.0, 100.0, 1.0, 3.0, 90, 95, 1, 1 @@ -193,6 +196,7 @@ gaugeCategory = AFR channel 1 AFR1_LambdaGauge = AFR1_lambda, "1: lambda", "", 0.5, 1.3, 0.5, 0.6, 1.05, 1.2, 3, 3 AFR1_AfrGauge = AFR1_afr, "1: AFR", "", 6.5, 20.0, 9.0, 10.0, 16.0, 17.0, 2, 2 AFR1_TempGauge = AFR1_temp, "1: AFR t", "C", 500, 1050, 500, 650, 800, 950, 0, 0 +AFR1_HeaterSupply = AFR1_HeaterSupply,"1: Heater Supply", "V", 3.0, 24.0, 9.0, 11.0, 15.0, 16.0, 1, 1 AFR1_NernstDcGauge = AFR1_NernstDc, "1: nernst DC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR1_NernstAcGauge = AFR1_NernstAc, "1: nernst AC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR1_HeaterDutyGauge = AFR1_HeaterDuty, "1: Heater Duty", "%", 0.0, 100.0, 1.0, 3.0, 90, 95, 1, 1 @@ -231,9 +235,9 @@ Aux1InputGauge = { (Aux1InputSel == 0) ? AFR0_AfrGauge : ((Aux1InputSel == 1) ? gauge2 = AFR0_AfrGauge gauge3 = AFR1_AfrGauge gauge4 = AFR1_TempGauge - gauge5 = VBattGauge - gauge6 = VBattGauge - gauge7 = EGT0_Gauge + gauge5 = EGT0_Gauge + gauge6 = AFR0_HeaterSupply + gauge7 = AFR1_HeaterSupply gauge8 = EGT1_Gauge indicator = { EGT0_state }, "EGT0 ok", { EGT0: bitStringValue(EgtStatesList, EGT0_state)}, green, black, red, black @@ -256,6 +260,7 @@ entry = VBatt, "Battery", float, "%.2f" entry = AFR0_lambda, "0: Lambda", float, "%.3f" entry = AFR0_afr, "0: AFR", float, "%.2f" entry = AFR0_temp, "0: Temp C", int, "%d" +entry = AFR0_HeaterSupply, "0: Heater Supply", float, "%.2f" entry = AFR0_NernstDc, "0: Nernst DC", float, "%.3f" entry = AFR0_NernstAc, "0: Nernst AC", float, "%.3f" entry = AFR0_PumpITarget, "0: Ipump target", float, "%.2f" @@ -270,6 +275,7 @@ entry = AFR0_esr, "0: ESR", float, "%.1f" entry = AFR1_lambda, "1: Lambda", float, "%.3f" entry = AFR1_afr, "1: AFR", float, "%.2f" entry = AFR1_temp, "1: Temp C", int, "%d" +entry = AFR1_HeaterSupply, "1: Heater Supply", float, "%.2f" entry = AFR1_NernstDc, "1: Nernst DC", float, "%.3f" entry = AFR1_NernstAc, "1: Nernst AC", float, "%.3f" entry = AFR1_PumpITarget, "1: Ipump target", float, "%.2f" diff --git a/firmware/ini/wideband_f1.ini b/firmware/ini/wideband_f1.ini index facef154..24fdc03f 100644 --- a/firmware/ini/wideband_f1.ini +++ b/firmware/ini/wideband_f1.ini @@ -90,6 +90,7 @@ VBatt = scalar, F32, 0, "V", 1, 0 AFR0_lambda = scalar, F32, 32, "", 1, 0 AFR0_afr = scalar, F32, 32, "", 14.7, 0 AFR0_temp = scalar, U16, 36, "C", 0.1, 0 +AFR0_HeaterSupply = scalar, U16, 38, "V", 0.01, 0 AFR0_NernstDc = scalar, U16, 40, "V", 0.001, 0 AFR0_NernstAc = scalar, U16, 42, "V", 0.001, 0 AFR0_PumpITarget = scalar, F32, 44, "mA", 1, 0 @@ -122,6 +123,7 @@ gaugeCategory = AFR channel 0 AFR0_LambdaGauge = AFR0_lambda, "0: lambda", "", 0.5, 1.3, 0.5, 0.6, 1.05, 1.2, 3, 3 AFR0_AfrGauge = AFR0_afr, "0: AFR", "", 6.5, 20.0, 9.0, 10.0, 16.0, 17.0, 2, 2 AFR0_TempGauge = AFR0_temp, "0: AFR t", "C", 500, 1050, 500, 650, 800, 950, 0, 0 +AFR0_HeaterSupply = AFR0_HeaterSupply,"0: Heater Supply", "V", 3.0, 24.0, 9.0, 11.0, 15.0, 16.0, 1, 1 AFR0_NernstDcGauge = AFR0_NernstDc, "0: nernst DC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR0_NernstAcGauge = AFR0_NernstAc, "0: nernst AC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR0_HeaterDutyGauge = AFR0_HeaterDuty, "0: Heater Duty", "%", 0.0, 100.0, 1.0, 3.0, 90, 95, 1, 1 @@ -136,7 +138,7 @@ AFR0_EsrGauge = AFR0_esr, "0: ESR", "ohms", ; 1 2 3 4 ; 5 6 7 8 - gauge1 = VBattGauge + gauge1 = AFR0_HeaterSupply gauge2 = AFR0_AfrGauge gauge3 = AFR0_TempGauge gauge4 = AFR0_HeaterDutyGauge @@ -161,6 +163,7 @@ entry = VBatt, "Battery", float, "%.2f" entry = AFR0_lambda, "0: Lambda", float, "%.3f" entry = AFR0_afr, "0: AFR", float, "%.2f" entry = AFR0_temp, "0: Temp C", int, "%d" +entry = AFR0_HeaterSupply, "0: Heater Supply", float, "%.2f" entry = AFR0_NernstDc, "0: Nernst DC", float, "%.3f" entry = AFR0_NernstAc, "0: Nernst AC", float, "%.3f" entry = AFR0_PumpITarget, "0: Ipump target", float, "%.2f" diff --git a/firmware/livedata.cpp b/firmware/livedata.cpp index 066b519a..94c0a6a5 100644 --- a/firmware/livedata.cpp +++ b/firmware/livedata.cpp @@ -24,8 +24,11 @@ void SamplingUpdateLiveData() const auto& sampler = GetSampler(ch); const auto& heater = GetHeaterController(ch); + float voltage = sampler.GetInternalHeaterVoltage(); + data->lambda = GetLambda(ch); data->temperature = sampler.GetSensorTemperature() * 10; + data->heaterSupplyVoltage = voltage * 100; data->nernstDc = sampler.GetNernstDc() * 1000; data->nernstAc = sampler.GetNernstAc() * 1000; data->pumpCurrentTarget = GetPumpCurrent(ch); @@ -36,8 +39,8 @@ void SamplingUpdateLiveData() data->fault = (uint8_t)GetCurrentFault(ch); data->heaterState = (uint8_t)GetHeaterState(ch); /* TODO: add GetPumpOutputDuty() */ - if (sampler.GetInternalHeaterVoltage(ch) > vbat) - vbat = sampler.GetInternalHeaterVoltage(ch); + if (voltage > vbat) + vbat = voltage; } livedata_common.vbatt = vbat; diff --git a/firmware/livedata.h b/firmware/livedata.h index 3a03b074..6d57a203 100644 --- a/firmware/livedata.h +++ b/firmware/livedata.h @@ -23,7 +23,7 @@ struct livedata_afr_s { // lambda also displayed by TS as AFR, same data with different scale factor float lambda; uint16_t temperature; - uint16_t padding; + uint16_t heaterSupplyVoltage; uint16_t nernstDc; uint16_t nernstAc; float pumpCurrentTarget; From 7253d0ed392b7d24e1916c3b7d986e3c8673c85e Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Wed, 26 Apr 2023 22:44:48 +0300 Subject: [PATCH 60/91] livedata: show Nernst voltage --- firmware/ini/wideband_dual.ini | 10 ++++++++-- firmware/ini/wideband_f1.ini | 5 ++++- firmware/livedata.cpp | 1 + firmware/livedata.h | 3 ++- firmware/sampling.cpp | 6 ++++++ firmware/sampling.h | 3 +++ 6 files changed, 24 insertions(+), 4 deletions(-) diff --git a/firmware/ini/wideband_dual.ini b/firmware/ini/wideband_dual.ini index 5fa68605..5f224ebd 100644 --- a/firmware/ini/wideband_dual.ini +++ b/firmware/ini/wideband_dual.ini @@ -104,7 +104,8 @@ AFR0_PumpITarget = scalar, F32, 44, "mA", 1, 0 AFR0_PumpIMeasure = scalar, F32, 48, "mA", 1, 0 AFR0_HeaterDuty = scalar, U16, 52, "%", 0.1, 0 AFR0_HeaterEffV = scalar, U16, 54, "V", 0.01, 0 -AFR0_esr = scalar, F32, 56, "ohms", 1, 0 +AFR0_esr = scalar, U16, 56, "ohms", 1, 0 +AFR0_Nernst = scalar, S16, 58, "V", 0.001, 0 AFR0_fault = scalar, U08, 60, "", 1, 0 AFR0_heater = scalar, U08, 61, "", 1, 0 @@ -119,7 +120,8 @@ AFR1_PumpITarget = scalar, F32, 76, "mA", 1, 0 AFR1_PumpIMeasure = scalar, F32, 80, "mA", 1, 0 AFR1_HeaterDuty = scalar, U16, 84, "%", 0.1, 0 AFR1_HeaterEffV = scalar, U16, 86, "V", 0.01, 0 -AFR1_esr = scalar, F32, 88, "ohms", 1, 0 +AFR1_esr = scalar, U16, 88, "ohms", 1, 0 +AFR1_Nernst = scalar, S16, 90, "V", 0.001, 0 AFR1_fault = scalar, U08, 92, "", 1, 0 AFR1_heater = scalar, U08, 93, "", 1, 0 @@ -182,6 +184,7 @@ AFR0_LambdaGauge = AFR0_lambda, "0: lambda", "", AFR0_AfrGauge = AFR0_afr, "0: AFR", "", 6.5, 20.0, 9.0, 10.0, 16.0, 17.0, 2, 2 AFR0_TempGauge = AFR0_temp, "0: AFR t", "C", 500, 1050, 500, 650, 800, 950, 0, 0 AFR0_HeaterSupply = AFR0_HeaterSupply,"0: Heater Supply", "V", 3.0, 24.0, 9.0, 11.0, 15.0, 16.0, 1, 1 +AFR0_NernstGauge = AFR0_Nernst, "0: nernst V", "V", -0.2, 1.8, -0.1, 0.0, 0.9, 0.95, 3, 3 AFR0_NernstDcGauge = AFR0_NernstDc, "0: nernst DC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR0_NernstAcGauge = AFR0_NernstAc, "0: nernst AC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR0_HeaterDutyGauge = AFR0_HeaterDuty, "0: Heater Duty", "%", 0.0, 100.0, 1.0, 3.0, 90, 95, 1, 1 @@ -197,6 +200,7 @@ AFR1_LambdaGauge = AFR1_lambda, "1: lambda", "", AFR1_AfrGauge = AFR1_afr, "1: AFR", "", 6.5, 20.0, 9.0, 10.0, 16.0, 17.0, 2, 2 AFR1_TempGauge = AFR1_temp, "1: AFR t", "C", 500, 1050, 500, 650, 800, 950, 0, 0 AFR1_HeaterSupply = AFR1_HeaterSupply,"1: Heater Supply", "V", 3.0, 24.0, 9.0, 11.0, 15.0, 16.0, 1, 1 +AFR1_NernstGauge = AFR1_Nernst, "1: nernst V", "V", -0.2, 1.8, -0.1, 0.0, 0.9, 0.95, 3, 3 AFR1_NernstDcGauge = AFR1_NernstDc, "1: nernst DC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR1_NernstAcGauge = AFR1_NernstAc, "1: nernst AC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR1_HeaterDutyGauge = AFR1_HeaterDuty, "1: Heater Duty", "%", 0.0, 100.0, 1.0, 3.0, 90, 95, 1, 1 @@ -261,6 +265,7 @@ entry = AFR0_lambda, "0: Lambda", float, "%.3f" entry = AFR0_afr, "0: AFR", float, "%.2f" entry = AFR0_temp, "0: Temp C", int, "%d" entry = AFR0_HeaterSupply, "0: Heater Supply", float, "%.2f" +entry = AFR0_Nernst, "0: Nernst V", float, "%.3f" entry = AFR0_NernstDc, "0: Nernst DC", float, "%.3f" entry = AFR0_NernstAc, "0: Nernst AC", float, "%.3f" entry = AFR0_PumpITarget, "0: Ipump target", float, "%.2f" @@ -276,6 +281,7 @@ entry = AFR1_lambda, "1: Lambda", float, "%.3f" entry = AFR1_afr, "1: AFR", float, "%.2f" entry = AFR1_temp, "1: Temp C", int, "%d" entry = AFR1_HeaterSupply, "1: Heater Supply", float, "%.2f" +entry = AFR1_Nernst, "1: Nernst V", float, "%.3f" entry = AFR1_NernstDc, "1: Nernst DC", float, "%.3f" entry = AFR1_NernstAc, "1: Nernst AC", float, "%.3f" entry = AFR1_PumpITarget, "1: Ipump target", float, "%.2f" diff --git a/firmware/ini/wideband_f1.ini b/firmware/ini/wideband_f1.ini index 24fdc03f..d9b80966 100644 --- a/firmware/ini/wideband_f1.ini +++ b/firmware/ini/wideband_f1.ini @@ -97,7 +97,8 @@ AFR0_PumpITarget = scalar, F32, 44, "mA", 1, 0 AFR0_PumpIMeasure = scalar, F32, 48, "mA", 1, 0 AFR0_HeaterDuty = scalar, U16, 52, "%", 0.1, 0 AFR0_HeaterEffV = scalar, U16, 54, "V", 0.01, 0 -AFR0_esr = scalar, F32, 56, "ohms", 1, 0 +AFR0_esr = scalar, U16, 56, "ohms", 1, 0 +AFR0_Nernst = scalar, S16, 58, "V", 0.001, 0 AFR0_fault = scalar, U08, 60, "", 1, 0 AFR0_heater = scalar, U08, 61, "", 1, 0 @@ -124,6 +125,7 @@ AFR0_LambdaGauge = AFR0_lambda, "0: lambda", "", AFR0_AfrGauge = AFR0_afr, "0: AFR", "", 6.5, 20.0, 9.0, 10.0, 16.0, 17.0, 2, 2 AFR0_TempGauge = AFR0_temp, "0: AFR t", "C", 500, 1050, 500, 650, 800, 950, 0, 0 AFR0_HeaterSupply = AFR0_HeaterSupply,"0: Heater Supply", "V", 3.0, 24.0, 9.0, 11.0, 15.0, 16.0, 1, 1 +AFR0_NernstGauge = AFR0_Nernst, "0: nernst V", "V", -0.2, 1.8, -0.1, 0.0, 0.9, 0.95, 3, 3 AFR0_NernstDcGauge = AFR0_NernstDc, "0: nernst DC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR0_NernstAcGauge = AFR0_NernstAc, "0: nernst AC", "V", 0.0, 1.0, 0.0, 0.0, 0.9, 0.95, 3, 3 AFR0_HeaterDutyGauge = AFR0_HeaterDuty, "0: Heater Duty", "%", 0.0, 100.0, 1.0, 3.0, 90, 95, 1, 1 @@ -164,6 +166,7 @@ entry = AFR0_lambda, "0: Lambda", float, "%.3f" entry = AFR0_afr, "0: AFR", float, "%.2f" entry = AFR0_temp, "0: Temp C", int, "%d" entry = AFR0_HeaterSupply, "0: Heater Supply", float, "%.2f" +entry = AFR0_Nernst, "0: Nernst V", float, "%.3f" entry = AFR0_NernstDc, "0: Nernst DC", float, "%.3f" entry = AFR0_NernstAc, "0: Nernst AC", float, "%.3f" entry = AFR0_PumpITarget, "0: Ipump target", float, "%.2f" diff --git a/firmware/livedata.cpp b/firmware/livedata.cpp index 94c0a6a5..bd50fa44 100644 --- a/firmware/livedata.cpp +++ b/firmware/livedata.cpp @@ -30,6 +30,7 @@ void SamplingUpdateLiveData() data->temperature = sampler.GetSensorTemperature() * 10; data->heaterSupplyVoltage = voltage * 100; data->nernstDc = sampler.GetNernstDc() * 1000; + data->nernstV = (int16_t)(sampler.GetNernstV() * 1000.0); data->nernstAc = sampler.GetNernstAc() * 1000; data->pumpCurrentTarget = GetPumpCurrent(ch); data->pumpCurrentMeasured = sampler.GetPumpNominalCurrent(); diff --git a/firmware/livedata.h b/firmware/livedata.h index 6d57a203..e5712dc7 100644 --- a/firmware/livedata.h +++ b/firmware/livedata.h @@ -30,7 +30,8 @@ struct livedata_afr_s { float pumpCurrentMeasured; uint16_t heaterDuty; uint16_t heaterEffectiveVoltage; - float esr; + uint16_t esr; + int16_t nernstV; uint8_t fault; // See wbo::Fault uint8_t heaterState; } __attribute__((packed)); diff --git a/firmware/sampling.cpp b/firmware/sampling.cpp index 415e5ca4..c3aba151 100644 --- a/firmware/sampling.cpp +++ b/firmware/sampling.cpp @@ -29,6 +29,11 @@ float Sampler::GetNernstAc() const return nernstAc; } +float Sampler::GetNernstV() const +{ + return nernstV; +} + float Sampler::GetPumpNominalCurrent() const { // Gain is 10x, then a 61.9 ohm resistor @@ -104,6 +109,7 @@ void Sampler::ApplySample(AnalogChannelResult& result, float virtualGroundVoltag // Compute AC (difference) and DC (average) components float nernstAcLocal = f_abs(r2_opposite_phase - r_2); nernstDc = (r2_opposite_phase + r_2) / 2; + nernstV = result.NernstVoltage; nernstAc = (1 - ESR_SENSE_ALPHA) * nernstAc + diff --git a/firmware/sampling.h b/firmware/sampling.h index fb352de3..1e4bed0b 100644 --- a/firmware/sampling.h +++ b/firmware/sampling.h @@ -8,6 +8,7 @@ struct ISampler { virtual float GetNernstDc() const = 0; virtual float GetNernstAc() const = 0; + virtual float GetNernstV() const = 0; virtual float GetPumpNominalCurrent() const = 0; virtual float GetInternalHeaterVoltage() const = 0; virtual float GetSensorTemperature() const = 0; @@ -24,6 +25,7 @@ class Sampler : public ISampler float GetNernstDc() const override; float GetNernstAc() const override; + float GetNernstV() const override; float GetPumpNominalCurrent() const override; float GetInternalHeaterVoltage() const override; float GetSensorTemperature() const override; @@ -35,6 +37,7 @@ class Sampler : public ISampler float nernstAc = 0; float nernstDc = 0; + float nernstV = 0; float pumpCurrentSenseVoltage = 0; #ifdef BATTERY_INPUT_DIVIDER From f782b485def8f21b28e090b624669841919726c2 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Fri, 21 Jul 2023 22:50:29 +0300 Subject: [PATCH 61/91] sampling, heater: fix Battery vs Heater naming mess --- firmware/heater_control.cpp | 12 ++++++------ firmware/heater_control.h | 2 +- firmware/wideband_config.h | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/firmware/heater_control.cpp b/firmware/heater_control.cpp index 5637773c..f27bdd2f 100644 --- a/firmware/heater_control.cpp +++ b/firmware/heater_control.cpp @@ -29,7 +29,7 @@ void HeaterControllerBase::Configure(float targetTempC, float targetEsr) m_preheatTimer.reset(); m_warmupTimer.reset(); - m_batteryStableTimer.reset(); + m_heaterStableTimer.reset(); m_closedLoopStableTimer.reset(); } @@ -61,17 +61,17 @@ HeaterState HeaterControllerBase::GetNextState(HeaterState currentState, HeaterA if (heaterAllowState == HeaterAllow::Unknown) { // measured voltage too low to auto-start heating - if (heaterSupplyVoltage < HEATER_BATTETY_OFF_VOLTAGE) + if (heaterSupplyVoltage < HEATER_SUPPLY_OFF_VOLTAGE) { - m_batteryStableTimer.reset(); + m_heaterStableTimer.reset(); // set fault SetFault(ch, Fault::SensorNoHeatSupply); return HeaterState::NoHeaterSupply; } - else if (heaterSupplyVoltage > HEATER_BATTERY_ON_VOLTAGE) + else if (heaterSupplyVoltage > HEATER_SUPPLY_ON_VOLTAGE) { - // measured voltage is high enough to auto-start heating, wait some time to stabilize - heaterAllowed = m_batteryStableTimer.hasElapsedSec(HEATER_BATTERY_STAB_TIME); + // measured voltage is high enougth to auto-start heating, wait some time to stabilize + heaterAllowed = m_heaterStableTimer.hasElapsedSec(HEATER_BATTERY_STAB_TIME); } } diff --git a/firmware/heater_control.h b/firmware/heater_control.h index 03234f8b..f42ea686 100644 --- a/firmware/heater_control.h +++ b/firmware/heater_control.h @@ -67,7 +67,7 @@ class HeaterControllerBase : public IHeaterController int m_retryTime = 0; - Timer m_batteryStableTimer; + Timer m_heaterStableTimer; Timer m_preheatTimer; Timer m_warmupTimer; Timer m_closedLoopStableTimer; diff --git a/firmware/wideband_config.h b/firmware/wideband_config.h index 1a8bbee9..e23dba39 100644 --- a/firmware/wideband_config.h +++ b/firmware/wideband_config.h @@ -50,10 +50,10 @@ #define HEATER_OVERHEAT_RETRY_TIMEOUT 60 #define HEATER_UNDERHEAT_RETRY_TIMEOUT 30 -// minimal battery voltage to start heating without CAN command -#define HEATER_BATTERY_ON_VOLTAGE 9.5 -// mininal battery voltage to continue heating -#define HEATER_BATTETY_OFF_VOLTAGE 8.5 +// minimal heater voltage to start heating without CAN command +#define HEATER_SUPPLY_ON_VOLTAGE 9.5 +// mininal heater voltage to continue heating +#define HEATER_SUPPLY_OFF_VOLTAGE 8.5 // ******************************* // Start driving the pump just before we're at target temperature From d4e024dbd606991c69321293ce8436466430dbea Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Fri, 21 Jul 2023 23:06:06 +0300 Subject: [PATCH 62/91] heater: always rely on localy measured heater voltage if board able to measure it localy --- firmware/heater_control.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/firmware/heater_control.cpp b/firmware/heater_control.cpp index f27bdd2f..0d70b839 100644 --- a/firmware/heater_control.cpp +++ b/firmware/heater_control.cpp @@ -224,14 +224,14 @@ void HeaterControllerBase::Update(const ISampler& sampler, HeaterAllow heaterAll float sensorEsr = sampler.GetSensorInternalResistance(); float sensorTemperature = sampler.GetSensorTemperature(); - #ifdef BOARD_HAS_VOLTAGE_SENSE + #if defined(HEATER_INPUT_DIVIDER) + // if board has ability to measure heater supply localy - use it + float heaterSupplyVoltage = sampler.GetInternalHeaterVoltage(); + #elif defined(BOARD_HAS_VOLTAGE_SENSE) float heaterSupplyVoltage = GetSupplyVoltage(); #else // not BOARD_HAS_VOLTAGE_SENSE - // If we haven't heard from the ECU, use the internally sensed - // battery voltage instead of voltage over CAN. - float heaterSupplyVoltage = heaterAllowState == HeaterAllow::Unknown - ? sampler.GetInternalHeaterVoltage() - : GetRemoteBatteryVoltage(); + // this board rely on measured voltage from ECU + float heaterSupplyVoltage = GetRemoteBatteryVoltage(); #endif // Run the state machine From c5db29006819475441eb0cf37f887639d21852fe Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 24 Sep 2023 18:03:16 +0300 Subject: [PATCH 63/91] Fix reset to DFU command --- firmware/Makefile | 10 ++--- firmware/boards/f1_common/f1_port.cpp | 41 +++++++++++++++++-- firmware/boards/f1_dual_rev1/board.c | 6 +++ .../boards/f1_dual_rev1/wideband_layout.ld | 9 ++-- firmware/boards/port.h | 3 ++ firmware/console/binary/tunerstudio.cpp | 6 +-- 6 files changed, 57 insertions(+), 18 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index a543e67c..06446207 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -136,7 +136,9 @@ LDSCRIPT=app.ld # C sources that can be compiled in ARM or THUMB mode depending on the global # setting. -CSRC = $(ALLCSRC) $(BOARDDIR)/board.c +CSRC = $(ALLCSRC) \ + $(BOARDDIR)/board.c \ + boards/f1_common/openblt/shared_params.c # C++ sources that can be compiled in ARM or THUMB mode depending on the global # setting. @@ -187,7 +189,8 @@ INCDIR = $(CONFDIR) \ console/binary/ \ boards/ \ shared/ \ - $(BOARDDIR)/io/ + $(BOARDDIR)/io/ \ + boards/f1_common/openblt # Define C warning options here. CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes @@ -236,9 +239,6 @@ ifeq ($(USE_OPENBLT),yes) # Reserve start of flash for OpenBLT USE_OPT += -Wl,--defsym=USE_BOOTLOADER=1 DDEFS += -DUSE_OPENBLT=TRUE - # Shared params - INCDIR += boards/f1_common/openblt - CSRC += boards/f1_common/openblt/shared_params.c endif # diff --git a/firmware/boards/f1_common/f1_port.cpp b/firmware/boards/f1_common/f1_port.cpp index b29f29dd..9098898b 100644 --- a/firmware/boards/f1_common/f1_port.cpp +++ b/firmware/boards/f1_common/f1_port.cpp @@ -5,12 +5,11 @@ #include "hal.h" #include "hal_mfs.h" -#if USE_OPENBLT -/* communication with OpenBLT that is plain C, not to modify external file */ +/* communication with OpenBLT that is plain C, not to modify external file + * Same code used to store "DFU-requested" flag */ extern "C" { #include "openblt/shared_params.h" }; -#endif // Storage // TODO: runtime detection? @@ -140,7 +139,7 @@ void rebootNow() void rebootToOpenblt() { -#if USE_OPENBLT +#ifdef USE_OPENBLT /* safe to call on already inited shares area */ SharedParamsInit(); /* Store flag to stay in OpenBLT */ @@ -150,6 +149,40 @@ void rebootToOpenblt() #endif } +void rebootToDfu() +{ + /* safe to call on already inited shares area */ + SharedParamsInit(); + /* Store flag to jump to DFU at main FW init */ + SharedParamsWriteByIndex(0, 0x02); + + rebootNow(); +} + +// stm32f10x XL-density devices +//#define BOOTLOADER_FW_ADDRESS 0x1FFFE000 +// stm32f10x devices +#define BOOTLOADER_FW_ADDRESS 0x1FFFF000 + +void checkDfuAndJump() +{ + uint8_t val; + if (SharedParamsReadByIndex(0, &val) == true) { + if (val == 0x02) { + // reset flag + SharedParamsWriteByIndex(0, 0x00); + + // AN2606 says: 2 Kbytes, starting from address 0x1FFFF000 contain the bootloader firmware. + // Point the PC to the System Memory reset vector (+4) + void (*SysMemBootJump)(void) = (void (*)(void)) (*((uint32_t *) (BOOTLOADER_FW_ADDRESS + 4))); + // Pick stack address from vector table + __set_MSP(*(__IO uint32_t*) BOOTLOADER_FW_ADDRESS); + SysMemBootJump(); + while (1); + } + } +} + void ToggleESRDriver(SensorType sensor) { switch (sensor) { diff --git a/firmware/boards/f1_dual_rev1/board.c b/firmware/boards/f1_dual_rev1/board.c index 1b451928..df80d0d5 100644 --- a/firmware/boards/f1_dual_rev1/board.c +++ b/firmware/boards/f1_dual_rev1/board.c @@ -17,6 +17,9 @@ #include "hal.h" #include "io_pins.h" +//#include "port.h" +extern void checkDfuAndJump(); + /** * @brief PAL setup. * @details Digital I/O ports static configuration as defined in @p board.h. @@ -41,6 +44,9 @@ const PALConfig pal_default_config = * any other initialization. */ void __early_init(void) { + /* Check if requested to jump to DFU */ + checkDfuAndJump(); + stm32_clock_init(); } diff --git a/firmware/boards/f1_dual_rev1/wideband_layout.ld b/firmware/boards/f1_dual_rev1/wideband_layout.ld index bd5d7ed7..00896070 100644 --- a/firmware/boards/f1_dual_rev1/wideband_layout.ld +++ b/firmware/boards/f1_dual_rev1/wideband_layout.ld @@ -5,8 +5,9 @@ /* OpenBLT code */ _OpenBLT_Flash_Size = DEFINED(USE_BOOTLOADER) ? 8k : 0; -/* OpenBLT <-> main FW shared area */ -_OpenBLT_Shared_Params_Size = DEFINED(USE_BOOTLOADER) ? 16 : 0; +/* OpenBLT <-> main FW shared area same area used to pass some data between restarts + * Now always enabled */ +Shared_Params_Size = 16; MEMORY { @@ -21,8 +22,8 @@ MEMORY flash5 (rx) : org = 0x00000000, len = 0 flash6 (rx) : org = 0x00000000, len = 0 flash7 (rx) : org = 0x00000000, len = 0 - shared (wx) : org = 0x20000000, len = _OpenBLT_Shared_Params_Size - ram0 (wx) : org = 0x20000000 + _OpenBLT_Shared_Params_Size, len = 48k - _OpenBLT_Shared_Params_Size + shared (wx) : org = 0x20000000, len = Shared_Params_Size + ram0 (wx) : org = 0x20000000 + Shared_Params_Size, len = 48k - Shared_Params_Size ram1 (wx) : org = 0x00000000, len = 0 ram2 (wx) : org = 0x00000000, len = 0 ram3 (wx) : org = 0x00000000, len = 0 diff --git a/firmware/boards/port.h b/firmware/boards/port.h index c622a33e..a917e960 100644 --- a/firmware/boards/port.h +++ b/firmware/boards/port.h @@ -87,6 +87,9 @@ const char *getTsSignature(); void rebootNow(); void rebootToOpenblt(); +void rebootToDfu(); + +extern "C" void checkDfuAndJump(); // LSU4.2, LSU4.9 or LSU_ADV SensorType GetSensorType(); diff --git a/firmware/console/binary/tunerstudio.cpp b/firmware/console/binary/tunerstudio.cpp index dcfa1b4b..0448c7a8 100644 --- a/firmware/console/binary/tunerstudio.cpp +++ b/firmware/console/binary/tunerstudio.cpp @@ -208,15 +208,13 @@ static void handleIoTestCommand(TsChannelBase* tsChannel, ts_response_format_e m /* index is not used yet */ switch (subsystem) { -#if 0 /* DFU */ case 0xba: /* Send ok to make TS happy, wait until sent */ sendOkResponse(tsChannel, TS_CRC); chThdSleepMilliseconds(100); - jump_to_bootloader(); + rebootToDfu(); break; -#endif case 0xbb: /* Send ok to make TS happy, wait until sent */ @@ -225,7 +223,6 @@ static void handleIoTestCommand(TsChannelBase* tsChannel, ts_response_format_e m rebootNow(); break; -#if USE_OPENBLT case 0xbc: /* Send ok to make TS happy, wait until sent */ sendOkResponse(tsChannel, TS_CRC); @@ -233,7 +230,6 @@ static void handleIoTestCommand(TsChannelBase* tsChannel, ts_response_format_e m /* Jump to OpenBLT if present */ rebootToOpenblt(); break; -#endif default: tunerStudioError(tsChannel, "Unexpected IoTest command"); From ee9e4b664560b51043785cf488d787d09e254a0e Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 25 Sep 2023 19:28:03 +0300 Subject: [PATCH 64/91] Add reset to DFU script Calling this command from TunerStudio seems to reset device to DFU mode, but TS attempts to continue communication breaks something and device does not reply to DFU tools. This script symply sends reset to dfu commant to tty device --- firmware/reset_to_dfu.sh | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100755 firmware/reset_to_dfu.sh diff --git a/firmware/reset_to_dfu.sh b/firmware/reset_to_dfu.sh new file mode 100755 index 00000000..49e5ecfd --- /dev/null +++ b/firmware/reset_to_dfu.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +DEV=/dev/ttyUSB0 + +#115200 +stty -F $DEV speed 115200 cs8 -cstopb -parenb > /dev/null +#Send cmd_dfu +printf '%b' '\x00\x05\x5A\x00\xBA\x00\x00\x7C\x48\x5B\xB1' > $DEV From b7c5f862a879f578d857b1d4b9ba698ecd755633 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sat, 14 Oct 2023 21:10:42 +0300 Subject: [PATCH 65/91] sampling: do not try to calculate ESR if NerstAc is clamped --- firmware/boards/f0_module/port.cpp | 1 + firmware/boards/f1_dual/port.cpp | 4 ++++ firmware/boards/f1_dual_rev1/port.cpp | 9 +++++++-- firmware/boards/f1_rev2/port.cpp | 2 ++ firmware/boards/f1_rev3/port.cpp | 2 ++ firmware/boards/port.h | 2 ++ firmware/sampling.cpp | 14 ++++++++++++++ firmware/sampling.h | 1 + test/tests/test_sampler.cpp | 3 +++ 9 files changed, 36 insertions(+), 2 deletions(-) diff --git a/firmware/boards/f0_module/port.cpp b/firmware/boards/f0_module/port.cpp index 4262350e..c2bf095d 100644 --- a/firmware/boards/f0_module/port.cpp +++ b/firmware/boards/f0_module/port.cpp @@ -53,6 +53,7 @@ AnalogResult AnalogSample() .NernstVoltage = AverageSamples(adcBuffer, 0) * (1.0 / NERNST_INPUT_GAIN), .PumpCurrentVoltage = AverageSamples(adcBuffer, 1), .HeaterSupplyVoltage = 0, + .NernstClamped = false, }, }, .VirtualGroundVoltageInt = AverageSamples(adcBuffer, 2), diff --git a/firmware/boards/f1_dual/port.cpp b/firmware/boards/f1_dual/port.cpp index 328e7b78..5edb9946 100644 --- a/firmware/boards/f1_dual/port.cpp +++ b/firmware/boards/f1_dual/port.cpp @@ -117,12 +117,16 @@ AnalogResult AnalogSample() .NernstVoltage = AverageSamples(adcBuffer, 3) * (1.0 / NERNST_INPUT_GAIN), .PumpCurrentVoltage = AverageSamples(adcBuffer, 2), .HeaterSupplyVoltage = l_heater_voltage, + /* TODO: */ + .NernstClamped = false, }, { /* right */ .NernstVoltage = AverageSamples(adcBuffer, 1) * (1.0 / NERNST_INPUT_GAIN), .PumpCurrentVoltage = AverageSamples(adcBuffer, 0), .HeaterSupplyVoltage = r_heater_voltage, + /* TODO: */ + .NernstClamped = false, }, }, /* Dual board has separate internal virtual ground = 3.3V / 2 diff --git a/firmware/boards/f1_dual_rev1/port.cpp b/firmware/boards/f1_dual_rev1/port.cpp index bd9dc1d8..0cc8d01c 100644 --- a/firmware/boards/f1_dual_rev1/port.cpp +++ b/firmware/boards/f1_dual_rev1/port.cpp @@ -129,13 +129,18 @@ AnalogResult AnalogSample() res.VirtualGroundVoltageInt = HALF_VCC; for (int i = 0; i < AFR_CHANNELS; i++) { + res.ch[i].NernstClamped = false; float NernstRaw = AverageSamples(adcBuffer, (i == 0) ? 3 : 1); - if ((NernstRaw > 0.01) && (NernstRaw < (3.3 - 0.01))) { + if ((NernstRaw > 0.01) && (NernstRaw < (VCC_VOLTS - 0.01))) { /* not clamped */ res.ch[i].NernstVoltage = (NernstRaw - NERNST_INPUT_OFFSET) * (1.0 / NERNST_INPUT_GAIN); } else { /* Clamped, use ungained input */ - res.ch[i].NernstVoltage = AverageSamples(adcBuffer, (i == 0) ? 9 : 8) - HALF_VCC; + NernstRaw = AverageSamples(adcBuffer, (i == 0) ? 9 : 8) - HALF_VCC; + if ((NernstRaw > 0.01) && (NernstRaw < (VCC_VOLTS - 0.01))) { + res.ch[i].NernstClamped = true; + } + res.ch[i].NernstVoltage = NernstRaw; } } /* left */ diff --git a/firmware/boards/f1_rev2/port.cpp b/firmware/boards/f1_rev2/port.cpp index b183d105..bcbaaf44 100644 --- a/firmware/boards/f1_rev2/port.cpp +++ b/firmware/boards/f1_rev2/port.cpp @@ -76,6 +76,8 @@ AnalogResult AnalogSample() * Assume WBO supply voltage == heater supply voltage */ .HeaterSupplyVoltage = AverageSamples(adcBuffer, 3) / BATTERY_INPUT_DIVIDER, /* .HeaterSupplyVoltage = AverageSamples(adcBuffer, 4) / HEATER_INPUT_DIVIDER, */ + /* TODO: */ + .NernstClamped = false, }, }, /* Rev 2 board has separate internal virtual ground = 3.3V / 2 diff --git a/firmware/boards/f1_rev3/port.cpp b/firmware/boards/f1_rev3/port.cpp index 361f7af9..5957e4f6 100644 --- a/firmware/boards/f1_rev3/port.cpp +++ b/firmware/boards/f1_rev3/port.cpp @@ -73,6 +73,8 @@ AnalogResult AnalogSample() * Assume WBO supply voltage == heater supply voltage */ .HeaterSupplyVoltage = AverageSamples(adcBuffer, 3) / BATTERY_INPUT_DIVIDER, /* .HeaterSupplyVoltage = AverageSamples(adcBuffer, 4) / HEATER_INPUT_DIVIDER, */ + /* TODO: */ + .NernstClamped = false, }, }, /* Rev 2 board has separate internal virtual ground = 3.3V / 2 diff --git a/firmware/boards/port.h b/firmware/boards/port.h index a917e960..3dd82f48 100644 --- a/firmware/boards/port.h +++ b/firmware/boards/port.h @@ -13,6 +13,8 @@ struct AnalogChannelResult /* for dual version - this is voltage on Heater-, switches between zero and Vbatt with heater PWM, * used for both Vbatt measurement and Heater diagnostic */ float HeaterSupplyVoltage; + /* If measured voltage is too close to ground or Vref assume value is clamped */ + bool NernstClamped; }; struct AnalogResult diff --git a/firmware/sampling.cpp b/firmware/sampling.cpp index c3aba151..43ffad8c 100644 --- a/firmware/sampling.cpp +++ b/firmware/sampling.cpp @@ -82,6 +82,13 @@ float Sampler::GetSensorTemperature() const float Sampler::GetSensorInternalResistance() const { + if (nernstClamped) + { + // TODO: report disconnected error? + // Return some non-realistic value + return 10000; + } + // Sensor is the lowside of a divider, top side is GetESRSupplyR(), and 3.3v AC pk-pk is injected float totalEsr = GetESRSupplyR() / (VCC_VOLTS / GetNernstAc() - 1); @@ -99,6 +106,13 @@ void Sampler::ApplySample(AnalogChannelResult& result, float virtualGroundVoltag { float r_1 = result.NernstVoltage; + // If value is close to ADC limit... + if (result.NernstClamped) { + nernstClamped = 100; + } else if (nernstClamped) { + nernstClamped--; + } + // r2_opposite_phase estimates where the previous sample would be had we not been toggling // AKA the absolute value of the difference between r2_opposite_phase and r2 is the amplitude // of the AC component on the nernst voltage. We have to pull this trick so as to use the past 3 diff --git a/firmware/sampling.h b/firmware/sampling.h index 1e4bed0b..e7562cf1 100644 --- a/firmware/sampling.h +++ b/firmware/sampling.h @@ -39,6 +39,7 @@ class Sampler : public ISampler float nernstDc = 0; float nernstV = 0; float pumpCurrentSenseVoltage = 0; + int nernstClamped = 0; #ifdef BATTERY_INPUT_DIVIDER float internalHeaterVoltage = 0; diff --git a/test/tests/test_sampler.cpp b/test/tests/test_sampler.cpp index 42debf66..365f3fba 100644 --- a/test/tests/test_sampler.cpp +++ b/test/tests/test_sampler.cpp @@ -21,6 +21,7 @@ TEST(Sampler, TestDc) AnalogChannelResult data; data.NernstVoltage = 0.45f; data.PumpCurrentVoltage = 1.75f; + data.NernstClamped = false; constexpr float virtualGroundVoltage = 1.65f; for (size_t i = 0; i < 5000; i++) @@ -41,10 +42,12 @@ TEST(Sampler, TestAc) AnalogChannelResult dataLow; dataLow.NernstVoltage = 0.45f - 0.1f; dataLow.PumpCurrentVoltage = 1.75f; + dataLow.NernstClamped = false; AnalogChannelResult dataHigh; dataHigh.NernstVoltage = 0.45f + 0.1f; dataHigh.PumpCurrentVoltage = 1.75f; + dataHigh.NernstClamped = false; constexpr float virtualGroundVoltage = 1.65f; From 2c32b59fb26aeb8edd8b9f976016f81eee19396f Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 16 Oct 2023 18:13:21 +0300 Subject: [PATCH 66/91] openbtl: f1_dual_rev1: enable OpenBLT on USART2 (Bluetooth) --- firmware/boards/f1_dual_rev1/io/io_pins.h | 5 ++++ .../boards/f1_dual_rev1/openblt/blt_conf.h | 11 +++++++-- firmware/boards/f1_dual_rev1/openblt/main.c | 23 +++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/firmware/boards/f1_dual_rev1/io/io_pins.h b/firmware/boards/f1_dual_rev1/io/io_pins.h index 88d98a54..5e6112e1 100644 --- a/firmware/boards/f1_dual_rev1/io/io_pins.h +++ b/firmware/boards/f1_dual_rev1/io/io_pins.h @@ -16,6 +16,11 @@ #define LL_UART_TX_PIN LL_GPIO_PIN_9 #define LL_UART_RX_PIN LL_GPIO_PIN_10 +// Communication - secondary (BT) UART +#define SEC_UART_GPIO_PORT GPIOC +#define SEC_LL_UART_TX_PIN LL_GPIO_PIN_10 +#define SEC_LL_UART_RX_PIN LL_GPIO_PIN_11 + // Communication - CAN1 #define CAN_GPIO_PORT GPIOA #define LL_CAN_TX_PIN LL_GPIO_PIN_12 diff --git a/firmware/boards/f1_dual_rev1/openblt/blt_conf.h b/firmware/boards/f1_dual_rev1/openblt/blt_conf.h index ec478dcc..650cef64 100644 --- a/firmware/boards/f1_dual_rev1/openblt/blt_conf.h +++ b/firmware/boards/f1_dual_rev1/openblt/blt_conf.h @@ -74,8 +74,15 @@ /** \brief Configure number of bytes in the host->target data packet. */ #define BOOT_COM_RS232_RX_MAX_DATA (64) /** \brief Select the desired UART peripheral as a zero based index. */ -#define BOOT_COM_RS232_CHANNEL_INDEX (0) - +//#define BOOT_COM_RS232_CHANNEL_INDEX (0) + +#define BOOT_COM_RS232_CHANNELS_N 2 +#define BOOT_COM_RS232_CHANNEL_INDEXES {0, 2} +#define BOOT_COM_RS232_CHANNEL_DEVS {(USART1), (USART3)} +// BOOT_COM_RS232_CHANNEL_INDEXES[0] +#define BOOT_COM_RS232_CHANNEL_DEFAULT_INDEX 0 +// BOOT_COM_RS232_CHANNEL_DEVS[0] +#define BOOT_COM_RS232_CHANNEL_DEFAULT_DEV USART1 /**************************************************************************************** * B A C K D O O R E N T R Y C O N F I G U R A T I O N diff --git a/firmware/boards/f1_dual_rev1/openblt/main.c b/firmware/boards/f1_dual_rev1/openblt/main.c index 0c8d0879..5e9c1920 100644 --- a/firmware/boards/f1_dual_rev1/openblt/main.c +++ b/firmware/boards/f1_dual_rev1/openblt/main.c @@ -128,6 +128,7 @@ void HAL_MspInit(void) /* GPIO ports clock enable. */ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA); LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOB); + LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOC); #if (BOOT_COM_RS232_ENABLE > 0) /* UART clock enable. */ @@ -142,6 +143,23 @@ void HAL_MspInit(void) GPIO_InitStruct.Mode = LL_GPIO_MODE_FLOATING; GPIO_InitStruct.Pull = LL_GPIO_PULL_UP; LL_GPIO_Init(UART_GPIO_PORT, &GPIO_InitStruct); +#if (BOOT_COM_RS232_CHANNELS_N > 1) + /* USART3 at PC10, PC11 */ + /* UART clock enable. */ + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART3); + /* UART TX and RX GPIO pin configuration. */ + GPIO_InitStruct.Pin = SEC_LL_UART_TX_PIN; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; + GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; + LL_GPIO_Init(SEC_UART_GPIO_PORT, &GPIO_InitStruct); + GPIO_InitStruct.Pin = SEC_LL_UART_RX_PIN; + GPIO_InitStruct.Mode = LL_GPIO_MODE_FLOATING; + GPIO_InitStruct.Pull = LL_GPIO_PULL_UP; + LL_GPIO_Init(SEC_UART_GPIO_PORT, &GPIO_InitStruct); + /* Enable remap: USART3 to PC10, PC11 */ + AFIO->MAPR |= AFIO_MAPR_USART3_REMAP_0; +#endif #endif #if (BOOT_COM_CAN_ENABLE > 0) @@ -181,6 +199,7 @@ void HAL_MspDeInit(void) LL_RCC_DeInit(); /* Deinit used GPIOs. */ + LL_GPIO_DeInit(GPIOC); LL_GPIO_DeInit(GPIOB); LL_GPIO_DeInit(GPIOA); @@ -191,10 +210,14 @@ void HAL_MspDeInit(void) #if (BOOT_COM_RS232_ENABLE > 0) /* UART clock disable. */ +#if (BOOT_COM_RS232_CHANNELS_N > 1) + LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_USART3); +#endif LL_APB2_GRP1_DisableClock(LL_APB2_GRP1_PERIPH_USART1); #endif /* GPIO ports clock disable. */ + LL_APB2_GRP1_DisableClock(LL_APB2_GRP1_PERIPH_GPIOC); LL_APB2_GRP1_DisableClock(LL_APB2_GRP1_PERIPH_GPIOB); LL_APB2_GRP1_DisableClock(LL_APB2_GRP1_PERIPH_GPIOA); From 82bc9f6b00f0180bf1f9c5219416058438f919de Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 16 Oct 2023 18:17:50 +0300 Subject: [PATCH 67/91] OpneBLT: switch to my repo --- .gitmodules | 2 +- firmware/ext/openblt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index cb879803..dc501e6d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,7 +10,7 @@ url = https://github.com/rusefi/kicad-libraries [submodule "firmware/ext/openblt"] path = firmware/ext/openblt - url = https://github.com/rusefi/openblt + url = https://github.com/dron0gus/openblt [submodule "firmware/libfirmware"] path = firmware/libfirmware url = https://github.com/rusefi/libfirmware.git diff --git a/firmware/ext/openblt b/firmware/ext/openblt index f24548b1..735fc8c5 160000 --- a/firmware/ext/openblt +++ b/firmware/ext/openblt @@ -1 +1 @@ -Subproject commit f24548b161e0e6f90651d8a2419d82f64dda9282 +Subproject commit 735fc8c5b0aec8717ae8fbc941745e2d34bf4bd1 From 386d2b84d982a59a2e56739758990efe121846d7 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 5 Feb 2024 11:26:54 +0300 Subject: [PATCH 68/91] can_helper: DLC can be less than 8, support extended ID --- firmware/can_helper.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/can_helper.h b/firmware/can_helper.h index b80c9177..3607a62c 100644 --- a/firmware/can_helper.h +++ b/firmware/can_helper.h @@ -46,7 +46,8 @@ class CanTxTyped final : public CanTxMessage static_assert(sizeof(TData) <= sizeof(CANTxFrame::data8)); public: - explicit CanTxTyped(uint32_t eid) : CanTxMessage(eid) { } + explicit CanTxTyped(uint32_t eid) : CanTxMessage(eid, sizeof(TData)) { } + explicit CanTxTyped(uint32_t eid, bool isExtended) : CanTxMessage(eid, sizeof(TData), isExtended) { } /** * Access members of the templated type. From 0fa06cfccdf45bab2941a16e22ad37ee0d5ddbfd Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 5 Feb 2024 11:36:17 +0300 Subject: [PATCH 69/91] CAN: protocol configuration to settings --- firmware/boards/f0_module/port.cpp | 16 +++--- firmware/boards/f1_common/f1_port.cpp | 26 +++++++++- firmware/boards/port.h | 24 ++++++++- firmware/can.cpp | 18 ++++--- firmware/can.h | 1 + firmware/ini/wideband_dual.ini | 70 ++++++++++++++++++++++++++- 6 files changed, 137 insertions(+), 18 deletions(-) diff --git a/firmware/boards/f0_module/port.cpp b/firmware/boards/f0_module/port.cpp index c2bf095d..da451160 100644 --- a/firmware/boards/f0_module/port.cpp +++ b/firmware/boards/f0_module/port.cpp @@ -119,15 +119,15 @@ Configuration* GetConfiguration() // See https://github.com/mck1117/wideband/issues/11 to explain this madness switch (3 * sel1 + sel2) { - case 0: config.CanIndexOffset = 2; break; - case 1: config.CanIndexOffset = 0; break; - case 2: config.CanIndexOffset = 3; break; - case 3: config.CanIndexOffset = 4; break; + case 0: config.afr[0].RusEfiIdOffset = 2; break; + case 1: config.afr[0].RusEfiIdOffset = 0; break; + case 2: config.afr[0].RusEfiIdOffset = 3; break; + case 3: config.afr[0].RusEfiIdOffset = 4; break; case 4: /* both floating, do nothing */ break; - case 5: config.CanIndexOffset = 1; break; - case 6: config.CanIndexOffset = 5; break; - case 7: config.CanIndexOffset = 6; break; - case 8: config.CanIndexOffset = 7; break; + case 5: config.afr[0].RusEfiIdOffset = 1; break; + case 6: config.afr[0].RusEfiIdOffset = 5; break; + case 7: config.afr[0].RusEfiIdOffset = 6; break; + case 8: config.afr[0].RusEfiIdOffset = 7; break; default: break; } diff --git a/firmware/boards/f1_common/f1_port.cpp b/firmware/boards/f1_common/f1_port.cpp index 9098898b..c19d17e4 100644 --- a/firmware/boards/f1_common/f1_port.cpp +++ b/firmware/boards/f1_common/f1_port.cpp @@ -54,7 +54,9 @@ void Configuration::LoadDefaults() { int i; - CanIndexOffset = 0; + *this = {}; + + NoLongerUsed0 = 0; sensorType = BOARD_DEFAULT_SENSOR_TYPE; /* default auxout curve is 0..5V for AFR 8.5 to 18.0 @@ -66,6 +68,28 @@ void Configuration::LoadDefaults() auxOutputSource[0] = AuxOutputMode::Afr0; auxOutputSource[1] = AuxOutputMode::Afr1; + for (i = 0; i < AFR_CHANNELS; i++) { + // enable RusEFI protocol + afr[i].RusEfiTx = true; + afr[i].RusEfiTxDiag = true; + afr[i].RusEfiIdOffset = 2 * i; + + // Disable AemNet + afr[i].AemNetTx = false; + afr[i].AemNetIdOffset = i; + } + + for (i = 0; i < EGT_CHANNELS; i++) { + // disable RusEFI protocol - not implemented + egt[i].RusEfiTx = false; + egt[i].RusEfiTxDiag = false; + egt[i].RusEfiIdOffset = i; + + // Enable AemNet + egt[i].AemNetTx = true; + egt[i].AemNetIdOffset = i; + } + /* Finaly */ Tag = ExpectedTag; } diff --git a/firmware/boards/port.h b/firmware/boards/port.h index 3dd82f48..1848a7a5 100644 --- a/firmware/boards/port.h +++ b/firmware/boards/port.h @@ -63,13 +63,35 @@ class Configuration { // Actual configuration data union { struct { - uint8_t CanIndexOffset = 0; + uint8_t NoLongerUsed0 = 0; // AUX0 and AUX1 curves float auxOutBins[2][8]; float auxOutValues[2][8]; AuxOutputMode auxOutputSource[2]; SensorType sensorType; + + // per AFR channel settings + struct { + bool RusEfiTx:1; + bool RusEfiTxDiag:1; + bool AemNetTx:1; + + uint8_t RusEfiIdOffset; + uint8_t AemNetIdOffset; + uint8_t pad[5]; + } afr[2]; + + // per EGT channel settings + struct { + bool RusEfiTx:1; + bool RusEfiTxDiag:1; + bool AemNetTx:1; + + uint8_t RusEfiIdOffset; + uint8_t AemNetIdOffset; + uint8_t pad[5]; + } egt[2]; } __attribute__((packed)); // pad to 256 bytes including tag diff --git a/firmware/can.cpp b/firmware/can.cpp index 69617834..390b4ae7 100644 --- a/firmware/can.cpp +++ b/firmware/can.cpp @@ -106,7 +106,7 @@ void CanRxThread(void*) else if ((frame.DLC == 0 || frame.DLC == 1) && CAN_ID(frame) == WB_BL_ENTER) { // If 0xFF (force update all) or our ID, reset to bootloader, otherwise ignore - if (frame.DLC == 0 || frame.data8[0] == 0xFF || frame.data8[0] == GetConfiguration()->CanIndexOffset) + if (frame.DLC == 0 || frame.data8[0] == 0xFF || frame.data8[0] == GetConfiguration()->afr[0].RusEfiIdOffset) { SendAck(); @@ -119,8 +119,14 @@ void CanRxThread(void*) // Check if it's an "index set" message else if (frame.DLC == 1 && CAN_ID(frame) == WB_MSG_SET_INDEX) { + int offset = frame.data8[0]; configuration = GetConfiguration(); - configuration->CanIndexOffset = frame.data8[0]; + for (int i = 0; i < AFR_CHANNELS; i++) { + configuration->afr[i].RusEfiIdOffset = offset + i * 2; + } + for (int i = 0; i < EGT_CHANNELS; i++) { + configuration->egt[i].RusEfiIdOffset = offset + i; + } SetConfiguration(); SendAck(); } @@ -148,7 +154,7 @@ void InitCan() void SendRusefiFormat(uint8_t ch) { - auto baseAddress = WB_DATA_BASE_ADDR + 2 * (ch + configuration->CanIndexOffset); + auto baseAddress = WB_DATA_BASE_ADDR + configuration->afr[ch].RusEfiIdOffset; const auto& sampler = GetSampler(ch); const auto& heater = GetHeaterController(ch); @@ -166,7 +172,7 @@ void SendRusefiFormat(uint8_t ch) pumpDuty > 0.1f && pumpDuty < 0.9f && lambda > 0.6f; - { + if (configuration->afr[ch].RusEfiTx) { CanTxTyped frame(baseAddress + 0); // The same header is imported by the ECU and checked against this data in the frame @@ -179,8 +185,8 @@ void SendRusefiFormat(uint8_t ch) frame.get().Valid = (heaterClosedLoop && lambdaValid) ? 0x01 : 0x00; } - { - CanTxTyped frame(baseAddress + 1); + if (configuration->afr[ch].RusEfiTxDiag) { + CanTxTyped frame(baseAddress + 1);; frame.get().Esr = sampler.GetSensorInternalResistance(); frame.get().NernstDc = nernstDc * 1000; diff --git a/firmware/can.h b/firmware/can.h index 9e966083..cf7d8069 100644 --- a/firmware/can.h +++ b/firmware/can.h @@ -24,6 +24,7 @@ float GetRemoteBatteryVoltage(); // implement this for your board if you want some non-standard behavior // default implementation simply calls SendRusefiFormat void SendCanForChannel(uint8_t ch); +void SendCanEgtForChannel(uint8_t ch); // Helpers to support both bxCAN and CANFD peripherals #ifdef STM32G4XX diff --git a/firmware/ini/wideband_dual.ini b/firmware/ini/wideband_dual.ini index 5f224ebd..8ef23c3e 100644 --- a/firmware/ini/wideband_dual.ini +++ b/firmware/ini/wideband_dual.ini @@ -69,11 +69,35 @@ Aux0InputSel = bits, U08, 133, [0:3], "AFR 0", "AFR 1", "Lambda 0", "L Aux1InputSel = bits, U08, 134, [0:3], "AFR 0", "AFR 1", "Lambda 0", "Lambda 1", "EGT 0", "EGT 1" LsuSensorType = bits, U08, 135, [0:2], "LSU 4.9", "LSU 4.2", "LSU ADV", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID" +RusEfiTx0 = bits, U08, 136, [0:0], "Disable", "Enable" +RusEfiTxDiag0 = bits, U08, 136, [1:1], "Disable", "Enable" +AemNetTx0 = bits, U08, 136, [2:2], "Disable", "Enable" +RusEfiIdOffset0= scalar, U08, 137, "", 1, 0, 0, 255, 0 +AemNetIdOffset0= scalar, U08, 138, "", 1, 0, 0, 255, 0 + +RusEfiTx1 = bits, U08, 144, [0:0], "Disable", "Enable" +RusEfiTxDiag1 = bits, U08, 144, [1:1], "Disable", "Enable" +AemNetTx1 = bits, U08, 144, [2:2], "Disable", "Enable" +RusEfiIdOffset1= scalar, U08, 145, "", 1, 0, 0, 255, 0 +AemNetIdOffset1= scalar, U08, 146, "", 1, 0, 0, 255, 0 + +AemNetEgtTx0 = bits, U08, 152, [2:2], "Disable", "Enable" +AemNetIdEgOff0 = scalar, U08, 154, "", 1, 0, 0, 255, 0 + +AemNetEgtTx1 = bits, U08, 160, [2:2], "Disable", "Enable" +AemNetIdEgOff1 = scalar, U08, 162, "", 1, 0, 0, 255, 0 + page = 2 ; this is a RAM only page with no burnable flash ; name = class, type, offset, [shape], units, scale, translate, min, max, digits highSpeedOffsets = array, U16, 0, [32], "", 1, 0, 0, 65535, 0, noMsqSave [SettingContextHelp] + RusEfiIdOffset0 = "Defines CAN ID offset for RusEFI AFR format packet channel 0 (left). Data packet ID = (0x190 + this offset), Diagnostic packed ID = (0x190 + 1 + this offset)." + RusEfiIdOffset1 = "Defines CAN ID offset for RusEFI AFR format packet channel 1 (right). Data packet ID = (0x190 + this offset), Diagnostic packed ID = (0x190 + 1 + this offset)." + AemNetIdOffset0 = "Defines CAN ID offset for AemNET USEGO format packet channel 0 (left). Packet ID = (0x180 + this offset)." + AemNetIdOffset1 = "Defines CAN ID offset for AemNET USEGO format packet channel 1 (right). Packet ID = (0x180 + this offset)." + AemNetIdEgOff0 = "Defines CAN ID offset for AemNET EGT format packet channel 0 (left). Packed ID = (0xA0305 + this offset)." + AemNetIdEgOff1 = "Defines CAN ID offset for AemNET EGT format packet channel 1 (right). Packed ID = (0xA0305 + this offset)." [Tuning] @@ -309,7 +333,8 @@ entry = EGT1_commErrors, "EGT 1: comm errors", int, "%d" menuDialog = main menu = "&Settings" subMenu = sensor_settings, "Sensor settings" - subMenu = can_settings, "CAN settings" + subMenu = can_settings, "CAN AFR settings" + subMenu = can_egt_settings, "CAN EGT settings" menu = "Outputs" subMenu = auxOut0, "AUX analog output 0" @@ -340,9 +365,50 @@ cmd_openblt = "Z\x00\xbc\x00\x00" dialog = sensor_settings, "Sensor Settings" field = "Sensor Type", LsuSensorType -dialog = can_settings, "CAN Settings" +dialog = afr0_can_settings, "AFR 0 (left) channel CAN Settings" + field = "RusEFI protocol:" + field = "Output AFR", RusEfiTx0 + field = "Output AFR diagnostic", RusEfiTxDiag0 + field = "CAN ID offset (base ID is 0x190) multiple of two", RusEfiIdOffset0, { (RusEfiTx0 == 1) || (RusEfiTxDiag0 == 1)} + field = "AemNet protocol:" + field = "Output AFR", AemNetTx0 + field = "CAN ID offset (base ID is 0x180)", AemNetIdOffset0, { (AemNetTx0 == 1) } + +dialog = afr1_can_settings, "AFR 1 (right) channel CAN Settings" + field = "RusEFI protocol:" + field = "Output AFR", RusEfiTx1 + field = "Output AFR diagnostic", RusEfiTxDiag1 + field = "CAN ID offset (base ID is 0x190) multiple of two", RusEfiIdOffset1, { (RusEfiTx1 == 1) || (RusEfiTxDiag1 == 1)} + field = "AemNet protocol:" + field = "Output AFR", AemNetTx1 + field = "CAN ID offset (base ID is 0x180)", AemNetIdOffset1, { (AemNetTx1 == 1) } + +dialog = egt0_can_settings, "EGT 0 (left) channel CAN Settings" + field = "RusEFI protocol:" + field = "not implemented yet" + field = "AemNet protocol:" + field = "Output EGT", AemNetEgtTx0 + field = "CAN ID offset (base ID is 0xA0305)", AemNetIdEgOff0, { (AemNetEgtTx0 == 1) }, { 1 }, displayInHex + +dialog = egt1_can_settings, "EGT 1 (right) channel CAN Settings" + field = "RusEFI protocol:" + field = "not implemented yet" + field = "AemNet protocol:" + field = "Output EGT", AemNetEgtTx1 + field = "CAN ID offset (base ID is 0xA0305)", AemNetIdEgOff1, { (AemNetEgtTx1 == 1) }, { 1 }, displayInHex + +dialog = common_can_settings, "CAN Settings" field = "CAN message ID offset", CanIndexOffset +dialog = can_settings, "CAN AFR Settings", border + panel = common_can_settings, North + panel = afr0_can_settings, West + panel = afr1_can_settings, East + +dialog = can_egt_settings, "CAN AFR Settings", border + panel = egt0_can_settings, West + panel = egt1_can_settings, East + dialog = auxOut0, "AUX analog out 0 Settings" field = "Signal", Aux0InputSel panel = auxOut0Curve From 2393224c4d31550be1e0bfcc5fef741e1b452013 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 5 Feb 2024 13:24:16 +0300 Subject: [PATCH 70/91] ini files: cleanup --- firmware/ini/wideband_dual.ini | 4 ---- 1 file changed, 4 deletions(-) diff --git a/firmware/ini/wideband_dual.ini b/firmware/ini/wideband_dual.ini index 8ef23c3e..df9295e9 100644 --- a/firmware/ini/wideband_dual.ini +++ b/firmware/ini/wideband_dual.ini @@ -397,11 +397,7 @@ dialog = egt1_can_settings, "EGT 1 (right) channel CAN Settings" field = "Output EGT", AemNetEgtTx1 field = "CAN ID offset (base ID is 0xA0305)", AemNetIdEgOff1, { (AemNetEgtTx1 == 1) }, { 1 }, displayInHex -dialog = common_can_settings, "CAN Settings" - field = "CAN message ID offset", CanIndexOffset - dialog = can_settings, "CAN AFR Settings", border - panel = common_can_settings, North panel = afr0_can_settings, West panel = afr1_can_settings, East From c20a505c24683bd41eb206364f66ce7cb9121817 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 5 Feb 2024 13:50:15 +0300 Subject: [PATCH 71/91] ini file update --- firmware/ini/wideband_dual.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/ini/wideband_dual.ini b/firmware/ini/wideband_dual.ini index df9295e9..65ef2911 100644 --- a/firmware/ini/wideband_dual.ini +++ b/firmware/ini/wideband_dual.ini @@ -369,19 +369,19 @@ dialog = afr0_can_settings, "AFR 0 (left) channel CAN Settings" field = "RusEFI protocol:" field = "Output AFR", RusEfiTx0 field = "Output AFR diagnostic", RusEfiTxDiag0 - field = "CAN ID offset (base ID is 0x190) multiple of two", RusEfiIdOffset0, { (RusEfiTx0 == 1) || (RusEfiTxDiag0 == 1)} + field = "CAN ID offset (base ID is 0x190)", RusEfiIdOffset0, { (RusEfiTx0 == 1) || (RusEfiTxDiag0 == 1)}, { 1 }, displayInHex field = "AemNet protocol:" field = "Output AFR", AemNetTx0 - field = "CAN ID offset (base ID is 0x180)", AemNetIdOffset0, { (AemNetTx0 == 1) } + field = "CAN ID offset (base ID is 0x180)", AemNetIdOffset0, { (AemNetTx0 == 1) }, { 1 }, displayInHex dialog = afr1_can_settings, "AFR 1 (right) channel CAN Settings" field = "RusEFI protocol:" field = "Output AFR", RusEfiTx1 field = "Output AFR diagnostic", RusEfiTxDiag1 - field = "CAN ID offset (base ID is 0x190) multiple of two", RusEfiIdOffset1, { (RusEfiTx1 == 1) || (RusEfiTxDiag1 == 1)} + field = "CAN ID offset (base ID is 0x190)", RusEfiIdOffset1, { (RusEfiTx1 == 1) || (RusEfiTxDiag1 == 1)}, { 1 }, displayInHex field = "AemNet protocol:" field = "Output AFR", AemNetTx1 - field = "CAN ID offset (base ID is 0x180)", AemNetIdOffset1, { (AemNetTx1 == 1) } + field = "CAN ID offset (base ID is 0x180)", AemNetIdOffset1, { (AemNetTx1 == 1) }, { 1 }, displayInHex dialog = egt0_can_settings, "EGT 0 (left) channel CAN Settings" field = "RusEFI protocol:" From 5cd9c5da9618e6f0aefc5d5ef529c76a89b72a8c Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sat, 10 Feb 2024 12:11:29 +0300 Subject: [PATCH 72/91] byteswap.h: add BE storage types --- firmware/util/byteswap.h | 86 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/firmware/util/byteswap.h b/firmware/util/byteswap.h index a053d0fa..4ba6db1e 100644 --- a/firmware/util/byteswap.h +++ b/firmware/util/byteswap.h @@ -1,7 +1,17 @@ #pragma once +#include +#include + // http://en.wikipedia.org/wiki/Endianness +#if defined(__BYTE_ORDER__)&&(__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + #define bigEndianHost true +#endif +#if defined(__BYTE_ORDER__)&&(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + #define bigEndianHost false +#endif + static inline uint16_t SWAP_UINT16(uint16_t x) { return ((x << 8) | (x >> 8)); @@ -11,4 +21,78 @@ static inline uint32_t SWAP_UINT32(uint32_t x) { return (((x >> 24) & 0x000000ff) | ((x << 8) & 0x00ff0000) | ((x >> 8) & 0x0000ff00) | ((x << 24) & 0xff000000)); -} \ No newline at end of file +} + +// TODO: use SWAP_UINT16() and SWAP_UINT32() instead of following +template +T swap(const T& arg, bool bigInMem) +{ + if (bigEndianHost == bigInMem) { + // no byte-swapping needed + return arg; + } else { + // swap bytes + T ret; + + char* dst = reinterpret_cast(&ret); + const char* src = reinterpret_cast(&arg + 1); + + for (size_t i = 0; i < sizeof(T); i++) { + *dst++ = *--src; + } + + return ret; + } +} + +template +class BigEndian +{ + public: + struct IncompleteType; + BigEndian() { } + BigEndian(const T& t) : rep(swap(t, true)) { } + operator T() const { return swap(rep, true); } +#if 0 + // TODO: + constexpr operator typename std::conditional_t() const { + return SWAP_UINT32(rep); + } + + constexpr BigEndian(std::conditional_t val) { + rep = SWAP_UINT32(val); + } + + constexpr operator typename std::conditional_t() const { + return SWAP_UINT16(rep); + } + + constexpr BigEndian(std::conditional_t val) { + rep = SWAP_UINT32(val); + } +#endif + private: + T rep; +} __attribute__((packed)); + +template +class LittleEndian +{ + public: + T rep; +// LittleEndian() { } + LittleEndian(const T& t) : rep(swap(t, false)) { } + operator T() const { return swap(rep, false); } +}; + +// Big endian storage types +using beint16_t = BigEndian; +using beint32_t = BigEndian; +using beuint16_t = BigEndian; +using beuint32_t = BigEndian; + +//static_assert(sizeof(buint8_t) == 1); +static_assert(sizeof(beint16_t) == 2); +static_assert(sizeof(beint32_t) == 4); +static_assert(sizeof(beuint16_t) == 2); +static_assert(sizeof(beuint32_t) == 4); From a1879c47bcc83ba8e76ac5d3c8807bf0a369fe59 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 10 Dec 2023 15:47:58 +0300 Subject: [PATCH 73/91] AEMNET: AFR and EGT --- firmware/Makefile | 1 + firmware/can.cpp | 14 ++++++ firmware/can_aemnet.cpp | 103 ++++++++++++++++++++++++++++++++++++++++ firmware/can_aemnet.h | 7 +++ 4 files changed, 125 insertions(+) create mode 100644 firmware/can_aemnet.cpp create mode 100644 firmware/can_aemnet.h diff --git a/firmware/Makefile b/firmware/Makefile index 06446207..aa57a076 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -150,6 +150,7 @@ CPPSRC = $(ALLCPPSRC) \ shared/flash.cpp \ can.cpp \ can_helper.cpp \ + can_aemnet.cpp \ fault.cpp \ lambda_conversion.cpp \ pwm.cpp \ diff --git a/firmware/can.cpp b/firmware/can.cpp index 390b4ae7..7c769f4e 100644 --- a/firmware/can.cpp +++ b/firmware/can.cpp @@ -4,6 +4,7 @@ #include "fault.h" #include "can_helper.h" +#include "can_aemnet.h" #include "heater_control.h" #include "lambda_conversion.h" #include "sampling.h" @@ -29,6 +30,10 @@ void CanTxThread(void*) SendCanForChannel(ch); } + for (int ch = 0; ch < EGT_CHANNELS; ch++) { + SendCanEgtForChannel(ch); + } + prev = chThdSleepUntilWindowed(prev, chTimeAddX(prev, TIME_MS2I(WBO_TX_PERIOD_MS))); } } @@ -200,4 +205,13 @@ void SendRusefiFormat(uint8_t ch) __attribute__((weak)) void SendCanForChannel(uint8_t ch) { SendRusefiFormat(ch); + SendAemNetUEGOFormat(ch); +} + +__attribute__((weak)) void SendCanEgtForChannel(uint8_t ch) +{ +#if (EGT_CHANNELS > 0) + // TODO: implement RusEFI protocol? + SendAemNetEGTFormat(ch); +#endif } diff --git a/firmware/can_aemnet.cpp b/firmware/can_aemnet.cpp new file mode 100644 index 00000000..9459cfe1 --- /dev/null +++ b/firmware/can_aemnet.cpp @@ -0,0 +1,103 @@ +#include "can.h" +#include "hal.h" + +#include "can_helper.h" +#include "can_aemnet.h" + +#include "port.h" +#include "fault.h" +#include "heater_control.h" +#include "lambda_conversion.h" +#include "sampling.h" +#include "pump_dac.h" +#include "max3185x.h" + +// AEMNet protocol + +#define AEMNET_UEGO_TX_PERIOD_MS 10 +#define AEMNET_UEGO_BASE_ID 0x00000180 + +namespace aemnet +{ +// 29 bit ID, 500kbs, rate 100 hz, endian big, DLC 8 +// ID: 0x180 .. 0x18f +struct UEGOData +{ + // 0.0001 Lambda/bit, 0 to 6.5535 Lambda + beuint16_t Lambda; + // 0.001 %/bit, -32.768% to 32.768% + beuint16_t Oxygen; + // 0.1 V/bit, 0 to 25.5 Volts + uint8_t SystemVolts; + uint8_t reserved; + // [1] - Bosch LSU4.9 detected + // [5] - Free-Air cal in use + // [7] - Lambda data valid + uint8_t Flags; + // [6] - Sensor Fault + uint8_t Faults; +} __attribute__((packed)); + +static_assert(sizeof(UEGOData) == 8); + +#define AEMNET_EGT_TX_PERIOD 50 +#define AEMNET_EGT_BASE_ID 0x000A0305 + +// 29 bit ID, 500kbs, rate 20 hz, endian big, DLC 8 +// ID: 0x000A0305 +struct EgtData +{ + // 1 degC/bit, 0 to 65535 degC + beuint16_t TemperatureC; + uint8_t pad[6]; +} __attribute__((packed)); + +static_assert(sizeof(EgtData) == 8); + +} //namespace aemnet + +static int LambdaIsValid(int ch) +{ + const auto& sampler = GetSampler(ch); + const auto& heater = GetHeaterController(ch); + + float nernstDc = sampler.GetNernstDc(); + + return ((heater.IsRunningClosedLoop()) && + (nernstDc > (NERNST_TARGET - 0.1f)) && + (nernstDc < (NERNST_TARGET + 0.1f))); +} + +void SendAemNetUEGOFormat(uint8_t ch) +{ + Configuration* configuration = GetConfiguration(); + auto id = AEMNET_UEGO_BASE_ID + configuration->afr[ch].AemNetIdOffset; + + const auto& sampler = GetSampler(ch); + + if (configuration->afr[ch].AemNetTx) { + CanTxTyped frame(id, true); + + frame.get().Lambda = GetLambda(ch) * 10000; + frame.get().Oxygen = 0; // TODO: + frame.get().SystemVolts = sampler.GetInternalHeaterVoltage() * 10; + frame.get().Flags = + ((configuration->sensorType == SensorType::LSU49) ? 0x02 : 0x00) | + ((LambdaIsValid(ch)) ? 0x80 : 0x00); + frame.get().Faults = 0; //TODO: + } +} + +#if (EGT_CHANNELS > 0) +void SendAemNetEGTFormat(uint8_t ch) +{ + Configuration* configuration = GetConfiguration(); + auto id = AEMNET_EGT_BASE_ID + configuration->egt[ch].AemNetIdOffset; + + if (configuration->egt[ch].AemNetTx) { + CanTxTyped frame(id, true); + + frame.get().TemperatureC = getEgtDrivers()[ch].temperature; + } +} +#endif /* EGT_CHANNELS > 0 */ diff --git a/firmware/can_aemnet.h b/firmware/can_aemnet.h new file mode 100644 index 00000000..23b2b438 --- /dev/null +++ b/firmware/can_aemnet.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include "byteswap.h" + +void SendAemNetUEGOFormat(uint8_t ch); +void SendAemNetEGTFormat(uint8_t ch); From 1d7166f826fa0c9fb73888c788076957e67b1f6c Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sat, 10 Feb 2024 13:18:43 +0300 Subject: [PATCH 74/91] CAN: EGT message rate is 20Hz --- firmware/can.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/firmware/can.cpp b/firmware/can.cpp index 7c769f4e..0116ba74 100644 --- a/firmware/can.cpp +++ b/firmware/can.cpp @@ -19,6 +19,7 @@ static Configuration* configuration; static THD_WORKING_AREA(waCanTxThread, 256); void CanTxThread(void*) { + int cycle; chRegSetThreadName("CAN Tx"); // Current system time. @@ -26,14 +27,19 @@ void CanTxThread(void*) while(1) { + // AFR - 100 Hz for (int ch = 0; ch < AFR_CHANNELS; ch++) { SendCanForChannel(ch); } - for (int ch = 0; ch < EGT_CHANNELS; ch++) { - SendCanEgtForChannel(ch); + // EGT - 20 Hz + if ((cycle % 5) == 0) { + for (int ch = 0; ch < EGT_CHANNELS; ch++) { + SendCanEgtForChannel(ch); + } } + cycle++; prev = chThdSleepUntilWindowed(prev, chTimeAddX(prev, TIME_MS2I(WBO_TX_PERIOD_MS))); } } From 47c377b3e14542b98ed9e0851adcaf259d902094 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 11 Feb 2024 23:09:13 +0300 Subject: [PATCH 75/91] f1_dual_rev1: bump signature --- firmware/boards/f1_dual/wideband_board_config.h | 2 +- firmware/boards/f1_dual_rev1/wideband_board_config.h | 2 +- firmware/ini/wideband_dual.ini | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/boards/f1_dual/wideband_board_config.h b/firmware/boards/f1_dual/wideband_board_config.h index 107e854c..9b6bd059 100644 --- a/firmware/boards/f1_dual/wideband_board_config.h +++ b/firmware/boards/f1_dual/wideband_board_config.h @@ -1,7 +1,7 @@ #pragma once // TS settings -#define TS_SIGNATURE "rusEFI 2023.05.10.wideband_dual" +#define TS_SIGNATURE "rusEFI 2024.02.11.wideband_dual" // This board implements two channels #define AFR_CHANNELS 2 diff --git a/firmware/boards/f1_dual_rev1/wideband_board_config.h b/firmware/boards/f1_dual_rev1/wideband_board_config.h index b62b1aec..0203e16d 100644 --- a/firmware/boards/f1_dual_rev1/wideband_board_config.h +++ b/firmware/boards/f1_dual_rev1/wideband_board_config.h @@ -1,7 +1,7 @@ #pragma once // TS settings -#define TS_SIGNATURE "rusEFI 2023.05.10.wideband_dual" +#define TS_SIGNATURE "rusEFI 2024.02.11.wideband_dual" // This board implements two channels #define AFR_CHANNELS 2 diff --git a/firmware/ini/wideband_dual.ini b/firmware/ini/wideband_dual.ini index 65ef2911..56587b5b 100644 --- a/firmware/ini/wideband_dual.ini +++ b/firmware/ini/wideband_dual.ini @@ -12,12 +12,12 @@ enable2ndByteCanID = false [MegaTune] ; https://rusefi.com/forum/viewtopic.php?p=36201#p36201 - signature = "rusEFI 2023.05.10.wideband_dual" + signature = "rusEFI 2024.02.11.wideband_dual" [TunerStudio] queryCommand = "S" versionInfo = "V" ; firmware version for title bar. - signature = "rusEFI 2023.05.10.wideband_dual" ; signature is expected to be 7 or more characters. + signature = "rusEFI 2024.02.11.wideband_dual" ; signature is expected to be 7 or more characters. ; TS will try to use legacy temp units in some cases, showing "deg F" on a CLT gauge that's actually deg C useLegacyFTempUnits = false From e07c03407b4e85159701aafb85f98eec1024b60c Mon Sep 17 00:00:00 2001 From: Alexey Esaulenko Date: Mon, 8 Apr 2024 17:22:34 +0400 Subject: [PATCH 76/91] Github action to auto-generate releases --- .github/workflows/build-firmware.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/build-firmware.yaml b/.github/workflows/build-firmware.yaml index 432dc5cd..9c210d96 100644 --- a/.github/workflows/build-firmware.yaml +++ b/.github/workflows/build-firmware.yaml @@ -48,3 +48,12 @@ jobs: with: name: Wideband ${{matrix.build-target}} path: ./firmware/deliver/${{matrix.build-target}}/wideband* + + - name: Zip artifacts + run: zip Wideband\ ${{matrix.build-target}}.zip ./firmware/deliver/${{matrix.build-target}}/wideband* + + - name: Make a new Release + uses: softprops/action-gh-release@v2 + if: startsWith(github.ref, 'refs/tags/') + with: + files: Wideband\ ${{matrix.build-target}}.zip From b280e9b9552ec5b450e3a9007d0600d1d34f6aea Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 2 Jun 2024 19:21:05 +0300 Subject: [PATCH 77/91] README update --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 10126927..9cf5d866 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,13 @@ +# Wideband + +This fork is for development of FW for [RusEFI](https://github.com/rusefi) [dual channel wideband](https://github.com/rusefi/rusefi-hardware/tree/main/lambda-x2). Based on [initial desing](https://github.com/mck1117/wideband) from [mck1117](https://github.com/mck1117) + +For stm32f042 FW please refer to original repo. While I try to keep it buildable and unaffected by my modification I can not quaranty its functionality and provide any support. + +[OpenBLT](https://github.com/feaser/openblt) bootloader is used for FW update functionality. Please reffer to original [documentation](https://www.feaser.com/openblt/doku.php?id=faq) on how to compile host tools and use it. + +# Original readme + [![Build Firmware](https://github.com/mck1117/wideband/actions/workflows/build-firmware.yaml/badge.svg)](https://github.com/mck1117/wideband/actions/workflows/build-firmware.yaml) ![license](https://img.shields.io/github/license/mck1117/wideband) # rusEFI Wideband Controller From bb15a595d4f79ea76e21cf566caeb3e15a22e7ac Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 2 Jun 2024 19:34:12 +0300 Subject: [PATCH 78/91] README: flashing --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 9cf5d866..268a112c 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,20 @@ This fork is for development of FW for [RusEFI](https://github.com/rusefi) [dual For stm32f042 FW please refer to original repo. While I try to keep it buildable and unaffected by my modification I can not quaranty its functionality and provide any support. +# Initial flashing + +For initial flashing of newly assembled device under Windows please refer to [this instruction](https://rusefi.com/forum/viewtopic.php?p=48379#p48379). + +I hope Linux users are experience enough to know how to use [stm32flash tool](https://github.com/ARMinARM/stm32flash). There are two sample scripts to [flash OpenBLT only](/firmware/dfu_flash_openblt.sh) and [flash combined image of OpenBLT + main FW](/firmware/dfu_flash.sh). + +# Update using OpenBLT + [OpenBLT](https://github.com/feaser/openblt) bootloader is used for FW update functionality. Please reffer to original [documentation](https://www.feaser.com/openblt/doku.php?id=faq) on how to compile host tools and use it. +There are few sample linux scripts for updating device over [CAN](/firmware/flash_can.sh) or [UART](/firmware/flash_uart.sh). + +Linux users can use almost any USB to CAN adapter supported by linux and providing SocketCAN interface ([for example](https://rusefi.com/forum/viewtopic.php?f=13&t=2209)). Windows users please check OpenBLT documentation. + # Original readme [![Build Firmware](https://github.com/mck1117/wideband/actions/workflows/build-firmware.yaml/badge.svg)](https://github.com/mck1117/wideband/actions/workflows/build-firmware.yaml) ![license](https://img.shields.io/github/license/mck1117/wideband) From 587b75538ec1b0773423b06338dcd7e10d66e1d7 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sun, 2 Jun 2024 19:35:53 +0300 Subject: [PATCH 79/91] Missed flashing scripts --- firmware/dfu_flash.sh | 17 +++++++++++++++++ firmware/dfu_flash_openblt.sh | 16 ++++++++++++++++ firmware/flash_uart.sh | 26 ++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100755 firmware/dfu_flash.sh create mode 100755 firmware/dfu_flash_openblt.sh create mode 100755 firmware/flash_uart.sh diff --git a/firmware/dfu_flash.sh b/firmware/dfu_flash.sh new file mode 100755 index 00000000..41e1baf2 --- /dev/null +++ b/firmware/dfu_flash.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +usage() { + cat < Date: Sun, 2 Jun 2024 19:38:30 +0300 Subject: [PATCH 80/91] README: minor changes --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 268a112c..98662061 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Wideband -This fork is for development of FW for [RusEFI](https://github.com/rusefi) [dual channel wideband](https://github.com/rusefi/rusefi-hardware/tree/main/lambda-x2). Based on [initial desing](https://github.com/mck1117/wideband) from [mck1117](https://github.com/mck1117) +This fork is for development of FW for [RusEFI](https://github.com/rusefi) [dual channel wideband](https://github.com/rusefi/rusefi-hardware/tree/main/lambda-x2). Based on [original desing](https://github.com/mck1117/wideband) from [mck1117](https://github.com/mck1117) -For stm32f042 FW please refer to original repo. While I try to keep it buildable and unaffected by my modification I can not quaranty its functionality and provide any support. +For stm32f042 FW please refer to original repo. While I try to keep it buildable and unaffected by my modification I can not guaranty its functionality and provide any support. # Initial flashing From 70914daf3063499daed32e55f361d35ee3e8b5c4 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 6 Jan 2025 11:23:46 +0300 Subject: [PATCH 81/91] uart: directly chprintf() to SD device --- firmware/uart.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/firmware/uart.cpp b/firmware/uart.cpp index 1bbc8bec..d549b465 100644 --- a/firmware/uart.cpp +++ b/firmware/uart.cpp @@ -27,7 +27,7 @@ SerialConfig cfg = { .cr3 = 0 }; -static char printBuffer[200]; +BaseSequentialStream *chp = (BaseSequentialStream *) &SD1; static THD_WORKING_AREA(waUartThread, 512); static void UartThread(void*) @@ -60,7 +60,7 @@ static void UartThread(void*) int heaterDuty = GetHeaterDuty(ch) * 100; int pumpDuty = GetPumpOutputDuty(ch) * 100; - size_t writeCount = chsnprintf(printBuffer, sizeof(printBuffer), + chprintf(chp, "[AFR%d]: %d.%03d DC: %4d mV AC: %4d mV ESR: %5d T: %4d C Ipump: %6d uA PumpDac: %3d Vheater: %5d heater: %s (%d)\tfault: %s\r\n", ch, lambdaIntPart, lambdaThousandths, @@ -73,16 +73,14 @@ static void UartThread(void*) heaterVoltageMv, describeHeaterState(GetHeaterState(ch)), heaterDuty, describeFault(GetCurrentFault(ch))); - chnWrite(&SD1, (const uint8_t *)printBuffer, writeCount); } #if (EGT_CHANNELS > 0) for (ch = 0; ch < EGT_CHANNELS; ch++) { - size_t writeCount = chsnprintf(printBuffer, sizeof(printBuffer), + chprintf(chp, "EGT[%d]: %d C (int %d C)\r\n", (int)getEgtDrivers()[ch].temperature, (int)getEgtDrivers()[ch].coldJunctionTemperature); - chnWrite(&SD1, (const uint8_t *)printBuffer, writeCount); } #endif /* EGT_CHANNELS > 0 */ From b557d035804012bfed9396b935406da8145c116e Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 27 Jan 2025 14:40:24 +0300 Subject: [PATCH 82/91] ChibiOS: fix STM32F1xx DAC driver compilation --- firmware/ChibiOS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/ChibiOS b/firmware/ChibiOS index dfdb730e..88cef96d 160000 --- a/firmware/ChibiOS +++ b/firmware/ChibiOS @@ -1 +1 @@ -Subproject commit dfdb730ecf5e536174e37dd9b5ff37e6bb5a59da +Subproject commit 88cef96dd5f86fc5a73e10fc5f3d13ab6030b9b2 From 27b8777b8a836732f8c00cd72c561021ee9a1823 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Sat, 10 Feb 2024 12:09:00 +0300 Subject: [PATCH 83/91] WIP: add CANio box protocol --- firmware/Makefile | 1 + firmware/boards/port.h | 1 + firmware/can.cpp | 6 ++ firmware/can_aemnet.cpp | 2 + firmware/can_aemnet.h | 1 - firmware/can_iobox.cpp | 210 ++++++++++++++++++++++++++++++++++++++++ firmware/can_iobox.h | 3 + 7 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 firmware/can_iobox.cpp create mode 100644 firmware/can_iobox.h diff --git a/firmware/Makefile b/firmware/Makefile index aa57a076..bb32ac90 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -151,6 +151,7 @@ CPPSRC = $(ALLCPPSRC) \ can.cpp \ can_helper.cpp \ can_aemnet.cpp \ + can_iobox.cpp \ fault.cpp \ lambda_conversion.cpp \ pwm.cpp \ diff --git a/firmware/boards/port.h b/firmware/boards/port.h index 1848a7a5..48dc6183 100644 --- a/firmware/boards/port.h +++ b/firmware/boards/port.h @@ -25,6 +25,7 @@ struct AnalogResult #ifdef BOARD_HAS_VOLTAGE_SENSE float SupplyVoltage; #endif + /* TODO: add AUX analog inputs */ }; // Enable ADCs, configure pins, etc diff --git a/firmware/can.cpp b/firmware/can.cpp index 0116ba74..c5caa305 100644 --- a/firmware/can.cpp +++ b/firmware/can.cpp @@ -5,6 +5,7 @@ #include "fault.h" #include "can_helper.h" #include "can_aemnet.h" +#include "can_iobox.h" #include "heater_control.h" #include "lambda_conversion.h" #include "sampling.h" @@ -82,6 +83,11 @@ void CanRxThread(void*) continue; } + if (frame.IDE == CAN_IDE_STD) + { + CanIoBoxRx(&frame); + } + // Ignore std frames, only listen to ext if (!CAN_EXT(frame)) { diff --git a/firmware/can_aemnet.cpp b/firmware/can_aemnet.cpp index 9459cfe1..63531f03 100644 --- a/firmware/can_aemnet.cpp +++ b/firmware/can_aemnet.cpp @@ -12,6 +12,8 @@ #include "pump_dac.h" #include "max3185x.h" +#include "byteswap.h" + // AEMNet protocol #define AEMNET_UEGO_TX_PERIOD_MS 10 diff --git a/firmware/can_aemnet.h b/firmware/can_aemnet.h index 23b2b438..6b42b1d1 100644 --- a/firmware/can_aemnet.h +++ b/firmware/can_aemnet.h @@ -1,7 +1,6 @@ #pragma once #include -#include "byteswap.h" void SendAemNetUEGOFormat(uint8_t ch); void SendAemNetEGTFormat(uint8_t ch); diff --git a/firmware/can_iobox.cpp b/firmware/can_iobox.cpp new file mode 100644 index 00000000..44bb1770 --- /dev/null +++ b/firmware/can_iobox.cpp @@ -0,0 +1,210 @@ +#include "can.h" +#include "hal.h" + +#include "can_helper.h" +#include "can_iobox.h" + +#include "sampling.h" +#include "byteswap.h" + +#define CAN_IOBOX_BASE0 0x200 +#define CAN_IOBOX_BASE1 0x220 +#define CAN_IOBOX_BASE2 0x240 + +/* Packets from MS3 to device */ +#define CAN_IOBOX_PING 0x00 +#define CAN_IOBOX_CONFIG 0x01 +#define CAN_IOBOX_SET_PWM(n) (0x02 + ((n) & 0x03)) +#define CAN_IOBOX_LAST_IN 0x05 + +/* Packets from device to MS3 */ +#define CAN_IOBOX_WHOAMI 0x08 +#define CAN_IOBOX_ADC14 0x09 +#define CAN_IOBOX_ADC57 0x0A + +struct pwm_settings { + beuint16_t on; + beuint16_t off; +} __attribute__ ((packed)); + +/* Base + 0x00 */ +/* "Are you there?" packet with zero payload */ + +/* Base + 0x01 */ +struct iobox_cfg { + uint8_t pwm_mask; // 0 - On/Off, 1 - PWM + uint8_t pad0; + uint8_t tachin_mask; + uint8_t pad1; + uint8_t adc_broadcast_interval; // mS + uint8_t tach_broadcast_interval; // mS + uint8_t pad2[2]; +} __attribute__((packed)); + +/* Base + 0x02, 0x03, 0x04 */ +struct iobox_pwm { + pwm_settings ch[2]; +} __attribute__ ((packed)); + +static_assert(sizeof(iobox_pwm) == 8); + +/* Base + 0x05 */ +struct iobox_pwm_last { + pwm_settings ch[1]; + uint8_t out_state; +} __attribute__ ((packed)); + +static_assert(sizeof(iobox_pwm_last) == 5); + +/* Base + 0x08 */ +struct iobox_whoami { + uint8_t version; + uint8_t pad[3]; + beuint16_t pwm_period; // PWM clock periods in 0.01 uS + beuint16_t tachin_period; // Tach-in clock periods in 0.01 uS +} __attribute__((packed)); + +static_assert(sizeof(iobox_whoami) == 8); + +/* Base + 0x09 */ +struct iobox_adc14 { + beuint16_t adc[4]; +} __attribute__((packed)); + +static_assert(sizeof(iobox_adc14) == 8); + +/* Base + 0x0A */ +struct iobox_adc57 { + uint8_t inputs; + uint8_t pad; + beuint16_t adc[3]; +} __attribute__((packed)); + +static_assert(sizeof(iobox_adc57) == 8); + +// TODO: move to configuration +static const uint32_t iobox_index = 0; + +static bool configured = false; + +static uint8_t pwm_mask = 0x00; +static uint8_t tachin_mask = 0x00; +static uint8_t adc_broadcast_interval = 20; +static uint8_t tach_broadcast_interval = 20; + +/* + * TODO: validate + * Scale value to 0 .. 1023 + * MegaSquirt IOBox has 0..5V ADC input range + */ +static uint16_t CanIoBoxGetAdc(size_t index) +{ + /* Total 7 ADC inputs, mapping: + * 1 - AUX left + * 2 - AUX right + * 3 - AUX out left voltage + * 4 - AUX out right voltage + * 5 - WBO supply voltage + * 6 - Left sensor heater supply + * 7 - Right sensor heater supply */ + switch (index) { + case 0 ... 4: + return 0; + break; + case 5: + /* TODO: */ + return 0; + case 6: + case 7: + { + const auto& sampler = GetSampler(index - 6); + + /* TODO: clamp */ + return sampler.GetInternalHeaterVoltage() / 25.5 * 1024; + } + break; + + default: + return 0.0; + } +} + +int CanIoBoxRx(const CANRxFrame *fr) +{ + const uint32_t base = CAN_IOBOX_BASE0 + iobox_index * 0x20; + + if (fr->IDE != CAN_IDE_STD) + return 0; + + if ((fr->EID < base) || + (fr->EID > base + CAN_IOBOX_LAST_IN)) + return 0; + + if ((fr->EID == base + CAN_IOBOX_PING) && (fr->DLC == 0)) + { + CanTxTyped frame(base + CAN_IOBOX_WHOAMI, false); + + frame.get().version = 1; + // PWM clock periods in 0.01 uS, equal to clock freq / 100 * 1000 + frame.get().pwm_period = 5000; + // Tach-in clock periods in 0.01 uS, equal to clock freq / 100 * 1000 + frame.get().tachin_period = 66; + + return 0; + } + else if (fr->EID == base + CAN_IOBOX_CONFIG) + { + const iobox_cfg *cfg = reinterpret_cast(fr->data8); + + //can0 201 [8] 00 00 00 00 14 14 00 00 + pwm_mask = cfg->pwm_mask; + tachin_mask = cfg->tachin_mask; + adc_broadcast_interval = cfg->adc_broadcast_interval; + tach_broadcast_interval = cfg->tach_broadcast_interval; + + configured = true; + + return 0; + } + else if ((fr->EID > base + CAN_IOBOX_SET_PWM(0)) && + (fr->EID < base + CAN_IOBOX_SET_PWM(2))) + { + const iobox_pwm *pwm = reinterpret_cast(fr->data8); + + /* TODO: PWM periods */ + return 0; + } + else if (fr->EID == base + CAN_IOBOX_SET_PWM(3)) + { + const iobox_pwm_last *pwm = reinterpret_cast(fr->data8); + + /* TODO: PWM periods and outputs */ + return 0; + } + + /* Should not happen */ + return -1; +} + +int CanIoBoxTx(void) +{ + if (!configured) + return 0; + + const uint32_t base = CAN_IOBOX_BASE0 + iobox_index * 0x20; + + if (1) { + CanTxTyped frame(base + CAN_IOBOX_ADC14, false); + + for (size_t i = 0; i < 4; i++) { + frame.get().adc[i] = CanIoBoxGetAdc(i); + } + } + if (1) { + CanTxTyped frame(base + CAN_IOBOX_ADC57, false); + + for (size_t i = 0; i < 3; i++) { + frame.get().adc[i] = CanIoBoxGetAdc(4 + i); + } + } +} \ No newline at end of file diff --git a/firmware/can_iobox.h b/firmware/can_iobox.h new file mode 100644 index 00000000..1f360a47 --- /dev/null +++ b/firmware/can_iobox.h @@ -0,0 +1,3 @@ +#pragma once + +int CanIoBoxRx(const CANRxFrame *fr); From 01b4fb12dcf4f6f2b0420ebcd1e4b6dc6b41c980 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 3 Feb 2025 19:40:51 +0300 Subject: [PATCH 84/91] AUXOUT: use unsigned as channel index --- firmware/auxout.cpp | 4 ++-- firmware/auxout.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/auxout.cpp b/firmware/auxout.cpp index 527f1459..b2c3e5a8 100644 --- a/firmware/auxout.cpp +++ b/firmware/auxout.cpp @@ -78,7 +78,7 @@ static const int8_t auxOutPwmChN[AFR_CHANNELS] = { #endif }; -void SetAuxDac(int channel, float voltage) +void SetAuxDac(size_t channel, float voltage) { voltage = voltage / AUXOUT_GAIN; auto duty = voltage / VCC_VOLTS; @@ -110,7 +110,7 @@ static const uint8_t auxOutDacCh[] = { #endif }; -void SetAuxDac(int channel, float voltage) +void SetAuxDac(size_t channel, float voltage) { voltage = voltage / AUXOUT_GAIN; diff --git a/firmware/auxout.h b/firmware/auxout.h index c78ea7d8..a1d4002d 100644 --- a/firmware/auxout.h +++ b/firmware/auxout.h @@ -3,4 +3,4 @@ #include void InitAuxDac(); -void SetAuxDac(int channel, float voltage); +void SetAuxDac(size_t channel, float voltage); From 5d60d8f46d46c6d8ebe827490cedcb48dd3e5c44 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 3 Feb 2025 19:41:16 +0300 Subject: [PATCH 85/91] AUXOUT: fix ripple canelation channel check --- firmware/auxout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/auxout.cpp b/firmware/auxout.cpp index b2c3e5a8..64b8bc20 100644 --- a/firmware/auxout.cpp +++ b/firmware/auxout.cpp @@ -86,7 +86,7 @@ void SetAuxDac(size_t channel, float voltage) auxDac.SetDuty(auxOutPwmCh[channel], duty); // Ripple cancelation channel - if (auxOutPwmChN[channel >= 0]) { + if (auxOutPwmChN[channel] >= 0) { auxDac.SetDuty(auxOutPwmChN[channel], duty); } } From f5956eccb4df1c9f90d70e8d27aa4d1f6a1c04ce Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 3 Feb 2025 19:57:35 +0300 Subject: [PATCH 86/91] AUXOUT: check arguments --- firmware/auxout.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/firmware/auxout.cpp b/firmware/auxout.cpp index 64b8bc20..efafddff 100644 --- a/firmware/auxout.cpp +++ b/firmware/auxout.cpp @@ -80,6 +80,10 @@ static const int8_t auxOutPwmChN[AFR_CHANNELS] = { void SetAuxDac(size_t channel, float voltage) { + if (channel >= AFR_CHANNELS) { + return; + } + voltage = voltage / AUXOUT_GAIN; auto duty = voltage / VCC_VOLTS; duty = clampF(0, duty, 1); @@ -112,6 +116,10 @@ static const uint8_t auxOutDacCh[] = { void SetAuxDac(size_t channel, float voltage) { + if (channel >= AFR_CHANNELS) { + return; + } + voltage = voltage / AUXOUT_GAIN; auxDac.SetVoltage(auxOutDacCh[channel], voltage); From a67fe47c28415680a63182d03b3bb09dbd5da576 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Mon, 3 Feb 2025 19:58:03 +0300 Subject: [PATCH 87/91] iobox: update --- firmware/boards/port.h | 1 + firmware/can_iobox.cpp | 27 ++++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/firmware/boards/port.h b/firmware/boards/port.h index 48dc6183..b6a6aca2 100644 --- a/firmware/boards/port.h +++ b/firmware/boards/port.h @@ -45,6 +45,7 @@ enum class AuxOutputMode : uint8_t { Lambda1 = 3, Egt0 = 4, Egt1 = 5, + MsIoBox = 6, }; class Configuration { diff --git a/firmware/can_iobox.cpp b/firmware/can_iobox.cpp index 44bb1770..3e522872 100644 --- a/firmware/can_iobox.cpp +++ b/firmware/can_iobox.cpp @@ -4,6 +4,8 @@ #include "can_helper.h" #include "can_iobox.h" +#include "port.h" +#include "auxout.h" #include "sampling.h" #include "byteswap.h" @@ -166,11 +168,28 @@ int CanIoBoxRx(const CANRxFrame *fr) return 0; } - else if ((fr->EID > base + CAN_IOBOX_SET_PWM(0)) && - (fr->EID < base + CAN_IOBOX_SET_PWM(2))) + else if ((fr->EID >= base + CAN_IOBOX_SET_PWM(0)) && + (fr->EID <= base + CAN_IOBOX_SET_PWM(2))) { const iobox_pwm *pwm = reinterpret_cast(fr->data8); + /* Two first channels are mapped to analog outputs */ + if (fr->EID == base + CAN_IOBOX_SET_PWM(0)) { + const auto cfg = GetConfiguration(); + + for (size_t n = 0; n < 2; n++) { + // if allowed to control DAC output over CAN + if (cfg->auxOutputSource[n] != AuxOutputMode::MsIoBox) { + continue; + } + // off time should be 0 + if (pwm->ch[n].off == 0) { + // 16 bit + SetAuxDac(n, 5.0 * pwm->ch[n].on / 0xffff); + } + } + } + /* TODO: PWM periods */ return 0; } @@ -207,4 +226,6 @@ int CanIoBoxTx(void) frame.get().adc[i] = CanIoBoxGetAdc(4 + i); } } -} \ No newline at end of file + + return 0; +} From 057ec1fe3cbf5e61899b6d6ccad67f537e93cb0f Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Tue, 4 Feb 2025 20:06:51 +0300 Subject: [PATCH 88/91] IoBox settings to config and export to TS --- firmware/boards/f0_module/port.cpp | 5 ++ firmware/boards/f1_common/f1_port.cpp | 11 ++++ firmware/boards/port.h | 24 +++++++++ firmware/can_iobox.cpp | 72 ++++++++++++++++++------- firmware/console/binary/tunerstudio.cpp | 8 +++ firmware/ini/wideband_dual.ini | 28 ++++++++-- 6 files changed, 125 insertions(+), 23 deletions(-) diff --git a/firmware/boards/f0_module/port.cpp b/firmware/boards/f0_module/port.cpp index da451160..49598c88 100644 --- a/firmware/boards/f0_module/port.cpp +++ b/firmware/boards/f0_module/port.cpp @@ -147,6 +147,11 @@ void SetConfiguration() ); } +void ResetConfiguration(); +{ + // NOP +} + SensorType GetSensorType() { return SensorType::LSU49; diff --git a/firmware/boards/f1_common/f1_port.cpp b/firmware/boards/f1_common/f1_port.cpp index c19d17e4..1b2b4ef7 100644 --- a/firmware/boards/f1_common/f1_port.cpp +++ b/firmware/boards/f1_common/f1_port.cpp @@ -90,6 +90,12 @@ void Configuration::LoadDefaults() egt[i].AemNetIdOffset = i; } + iobox.idx = 0; + iobox.enable_rx = 0; + iobox.enable_tx = 0; + iobox.IDE = CAN_IDE_STD; + iobox.SID = 0x200; + /* Finaly */ Tag = ExpectedTag; } @@ -127,6 +133,11 @@ void SetConfiguration() SaveConfiguration(); } +void ResetConfiguration() +{ + cfg.LoadDefaults(); +} + /* TS stuff */ int SaveConfiguration() { /* TODO: handle error */ diff --git a/firmware/boards/port.h b/firmware/boards/port.h index b6a6aca2..23f1d9bc 100644 --- a/firmware/boards/port.h +++ b/firmware/boards/port.h @@ -94,6 +94,27 @@ class Configuration { uint8_t AemNetIdOffset; uint8_t pad[5]; } egt[2]; + + // MS IO Box protocol settings + struct { + // MS IO Box index: 0, 1 or 2, else custom SID/EID is used. + uint8_t idx; + uint8_t enable_rx:1; + uint8_t enable_tx:1; + // Identifier type: CAN_IDE_STD or CAN_IDE_EXT + uint8_t IDE:1; + uint8_t pad[3]; + union { + struct { + // CAN_IDE_STD + uint32_t SID:11; + }; + struct { + // Extended identifier + uint32_t EID:29; + }; + }; + } iobox __attribute__((packed)); } __attribute__((packed)); // pad to 256 bytes including tag @@ -101,9 +122,12 @@ class Configuration { }; }; +static_assert(sizeof(Configuration) == 256); + int InitConfiguration(); Configuration* GetConfiguration(); void SetConfiguration(); +void ResetConfiguration(); /* TS stuff */ uint8_t *GetConfigurationPtr(); diff --git a/firmware/can_iobox.cpp b/firmware/can_iobox.cpp index 3e522872..7ef804ab 100644 --- a/firmware/can_iobox.cpp +++ b/firmware/can_iobox.cpp @@ -84,9 +84,6 @@ struct iobox_adc57 { static_assert(sizeof(iobox_adc57) == 8); -// TODO: move to configuration -static const uint32_t iobox_index = 0; - static bool configured = false; static uint8_t pwm_mask = 0x00; @@ -94,6 +91,25 @@ static uint8_t tachin_mask = 0x00; static uint8_t adc_broadcast_interval = 20; static uint8_t tach_broadcast_interval = 20; +static uint32_t CanIoBoxBaseId() +{ + const auto cfg = GetConfiguration(); + + // three standart IDs + if (cfg->iobox.idx <= 2) { + return (CAN_IOBOX_BASE0 + cfg->iobox.idx * 0x20); + } + + return ((cfg->iobox.IDE == CAN_IDE_STD) ? cfg->iobox.SID : cfg->iobox.EID); +} + +static uint8_t CanIoBoxIde() +{ + const auto cfg = GetConfiguration(); + + return cfg->iobox.IDE; +} + /* * TODO: validate * Scale value to 0 .. 1023 @@ -133,16 +149,27 @@ static uint16_t CanIoBoxGetAdc(size_t index) int CanIoBoxRx(const CANRxFrame *fr) { - const uint32_t base = CAN_IOBOX_BASE0 + iobox_index * 0x20; + const auto cfg = GetConfiguration(); + + if (!cfg->iobox.enable_rx) + return 0; - if (fr->IDE != CAN_IDE_STD) + if (CanIoBoxIde() != fr->IDE) return 0; - if ((fr->EID < base) || - (fr->EID > base + CAN_IOBOX_LAST_IN)) + const uint32_t base = CanIoBoxBaseId(); + uint32_t id; + if (fr->IDE == CAN_IDE_STD) { + id = fr->SID; + } else { + id = fr->EID; + } + + if ((id < base) || + (id > base + CAN_IOBOX_LAST_IN)) return 0; - if ((fr->EID == base + CAN_IOBOX_PING) && (fr->DLC == 0)) + if ((id == base + CAN_IOBOX_PING) && (fr->DLC == 0)) { CanTxTyped frame(base + CAN_IOBOX_WHOAMI, false); @@ -154,7 +181,7 @@ int CanIoBoxRx(const CANRxFrame *fr) return 0; } - else if (fr->EID == base + CAN_IOBOX_CONFIG) + else if ((id == base + CAN_IOBOX_CONFIG) && (fr->DLC == sizeof(iobox_cfg))) { const iobox_cfg *cfg = reinterpret_cast(fr->data8); @@ -168,24 +195,25 @@ int CanIoBoxRx(const CANRxFrame *fr) return 0; } - else if ((fr->EID >= base + CAN_IOBOX_SET_PWM(0)) && - (fr->EID <= base + CAN_IOBOX_SET_PWM(2))) + else if ((id >= base + CAN_IOBOX_SET_PWM(0)) && + (id <= base + CAN_IOBOX_SET_PWM(2)) && + (fr->DLC == sizeof(iobox_pwm))) { const iobox_pwm *pwm = reinterpret_cast(fr->data8); /* Two first channels are mapped to analog outputs */ if (fr->EID == base + CAN_IOBOX_SET_PWM(0)) { - const auto cfg = GetConfiguration(); - for (size_t n = 0; n < 2; n++) { // if allowed to control DAC output over CAN if (cfg->auxOutputSource[n] != AuxOutputMode::MsIoBox) { continue; } - // off time should be 0 - if (pwm->ch[n].off == 0) { - // 16 bit - SetAuxDac(n, 5.0 * pwm->ch[n].on / 0xffff); + + uint32_t period = pwm->ch[n].off + pwm->ch[n].on; + if (period == 0) { + SetAuxDac(n, 0); + } else { + SetAuxDac(n, 5.0 * pwm->ch[n].on / period); } } } @@ -193,7 +221,8 @@ int CanIoBoxRx(const CANRxFrame *fr) /* TODO: PWM periods */ return 0; } - else if (fr->EID == base + CAN_IOBOX_SET_PWM(3)) + else if ((id == base + CAN_IOBOX_SET_PWM(3)) && + (fr->DLC == sizeof(iobox_pwm_last))) { const iobox_pwm_last *pwm = reinterpret_cast(fr->data8); @@ -207,10 +236,15 @@ int CanIoBoxRx(const CANRxFrame *fr) int CanIoBoxTx(void) { + const auto cfg = GetConfiguration(); + + if (!cfg->iobox.enable_tx) + return 0; + if (!configured) return 0; - const uint32_t base = CAN_IOBOX_BASE0 + iobox_index * 0x20; + const uint32_t base = CanIoBoxBaseId(); if (1) { CanTxTyped frame(base + CAN_IOBOX_ADC14, false); diff --git a/firmware/console/binary/tunerstudio.cpp b/firmware/console/binary/tunerstudio.cpp index 0448c7a8..22a616ec 100644 --- a/firmware/console/binary/tunerstudio.cpp +++ b/firmware/console/binary/tunerstudio.cpp @@ -231,6 +231,14 @@ static void handleIoTestCommand(TsChannelBase* tsChannel, ts_response_format_e m rebootToOpenblt(); break; + case 0xbd: + ResetConfiguration(); + SetConfiguration(); + /* Send ok to make TS happy, wait until sent */ + sendOkResponse(tsChannel, TS_CRC); + chThdSleepMilliseconds(100); + rebootNow(); + default: tunerStudioError(tsChannel, "Unexpected IoTest command"); } diff --git a/firmware/ini/wideband_dual.ini b/firmware/ini/wideband_dual.ini index 56587b5b..c85322e8 100644 --- a/firmware/ini/wideband_dual.ini +++ b/firmware/ini/wideband_dual.ini @@ -65,8 +65,8 @@ Aux0OutBins = array, F32, 5, [8], "", 1, 0, 0, 1 Aux1OutBins = array, F32, 37, [8], "", 1, 0, 0, 1500, 2 Aux0Out = array, F32, 69, [8], "V", 1, 0, 0, 5.0, 2 Aux1Out = array, F32, 101, [8], "V", 1, 0, 0, 5.0, 2 -Aux0InputSel = bits, U08, 133, [0:3], "AFR 0", "AFR 1", "Lambda 0", "Lambda 1", "EGT 0", "EGT 1" -Aux1InputSel = bits, U08, 134, [0:3], "AFR 0", "AFR 1", "Lambda 0", "Lambda 1", "EGT 0", "EGT 1" +Aux0InputSel = bits, U08, 133, [0:2], "AFR 0", "AFR 1", "Lambda 0", "Lambda 1", "EGT 0", "EGT 1", "CAN input", "INVALID" +Aux1InputSel = bits, U08, 134, [0:2], "AFR 0", "AFR 1", "Lambda 0", "Lambda 1", "EGT 0", "EGT 1", "CAN input", "INVALID" LsuSensorType = bits, U08, 135, [0:2], "LSU 4.9", "LSU 4.2", "LSU ADV", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID" RusEfiTx0 = bits, U08, 136, [0:0], "Disable", "Enable" @@ -87,6 +87,12 @@ AemNetIdEgOff0 = scalar, U08, 154, "", 1, 0, 0, 2 AemNetEgtTx1 = bits, U08, 160, [2:2], "Disable", "Enable" AemNetIdEgOff1 = scalar, U08, 162, "", 1, 0, 0, 255, 0 +IoBoxIndex = bits, U08, 168, [0:1], "IoBox0 (0x200)", "IoBox1 (0x220)", "IoBox2 (0x240)", "Custom" +IoBoxRx = bits, U08, 169, [0:0], "Disable", "Enable" +IoBoxTx = bits, U08, 169, [1:1], "Disable", "Enable" +IoBoxCanIde = bits, U08, 169, [2:2], "Standart", "Extended" +IoBoxCanId = scalar, U32, 172, "", 1, 0, 0, 1073741823, 0 + page = 2 ; this is a RAM only page with no burnable flash ; name = class, type, offset, [shape], units, scale, translate, min, max, digits highSpeedOffsets = array, U16, 0, [32], "", 1, 0, 0, 65535, 0, noMsqSave @@ -335,6 +341,7 @@ menuDialog = main subMenu = sensor_settings, "Sensor settings" subMenu = can_settings, "CAN AFR settings" subMenu = can_egt_settings, "CAN EGT settings" + subMenu = can_iobox_settings, "CAN IO Box settings" menu = "Outputs" subMenu = auxOut0, "AUX analog output 0" @@ -359,6 +366,8 @@ cmd_reset_controller = "Z\x00\xbb\x00\x00" cmd_dfu = "Z\x00\xba\x00\x00" ; restart to OpenBlt cmd_openblt = "Z\x00\xbc\x00\x00" +; reset settings to default +cmd_defaults = "Z\x00\xbd\x00\x00" [UserDefined] @@ -405,20 +414,31 @@ dialog = can_egt_settings, "CAN AFR Settings", border panel = egt0_can_settings, West panel = egt1_can_settings, East +dialog = can_iobox_settings, "CAN IO Box Settings" + field = "IoBox index", IoBoxIndex + field = "Custom CAN ID", IoBoxCanId, { IoBoxIndex >= 3 } + field = "Custom CAN ID type", IoBoxCanIde, { IoBoxIndex >= 3 }, { 1 }, displayInHex + field = "Enable CAN Rx", IoBoxRx + field = "Enable CAN Tx", IoBoxTx + dialog = auxOut0, "AUX analog out 0 Settings" field = "Signal", Aux0InputSel - panel = auxOut0Curve + panel = auxOut0Curve, Center, { Aux0InputSel <= 5} dialog = auxOut1, "AUX analog out 1 Settings" field = "Signal", Aux1InputSel - panel = auxOut1Curve + panel = auxOut1Curve, Center, { Aux1InputSel <= 5} dialog = ecuReset, "Reset" commandButton = "Reset ECU", cmd_reset_controller commandButton = "Reset to DFU", cmd_dfu commandButton = "Reset to OpenBLT", cmd_openblt +dialog = ecuDefaults, "Default settings" + commandButton = "Load default & restart", cmd_defaults, { 1 }, showMessageOnClick, "Please restart TunerStudio to update settings" + dialog = ecuTools, "ECU tools and Commands", xAxis panel = ecuReset + panel = ecuDefaults [Tools] From b786240924caaa3d7ccebacf61a8282e0ca2dc7d Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Tue, 4 Feb 2025 22:41:34 +0300 Subject: [PATCH 89/91] DAC mode implemented --- firmware/auxout.cpp | 3 ++ firmware/boards/f0_module/port.cpp | 2 +- firmware/boards/f1_common/f1_port.cpp | 72 ++++++++++++++++++++++--- firmware/boards/port.h | 3 +- firmware/console/binary/tunerstudio.cpp | 4 +- firmware/ini/wideband_dual.ini | 22 ++++++-- firmware/test_can_dac.sh | 19 +++++++ 7 files changed, 110 insertions(+), 15 deletions(-) create mode 100755 firmware/test_can_dac.sh diff --git a/firmware/auxout.cpp b/firmware/auxout.cpp index efafddff..9201b3e0 100644 --- a/firmware/auxout.cpp +++ b/firmware/auxout.cpp @@ -166,6 +166,9 @@ void AuxOutThread(void*) { for (int ch = 0; ch < AFR_CHANNELS; ch++) { + if (cfg->auxOutputSource[ch] == AuxOutputMode::MsIoBox) + continue; + float input = AuxGetInputSignal(cfg->auxOutputSource[ch]); float voltage = interpolate2d(input, cfg->auxOutBins[ch], cfg->auxOutValues[ch]); diff --git a/firmware/boards/f0_module/port.cpp b/firmware/boards/f0_module/port.cpp index 49598c88..7e4ba06f 100644 --- a/firmware/boards/f0_module/port.cpp +++ b/firmware/boards/f0_module/port.cpp @@ -147,7 +147,7 @@ void SetConfiguration() ); } -void ResetConfiguration(); +void ResetConfiguration(uint16_t option) { // NOP } diff --git a/firmware/boards/f1_common/f1_port.cpp b/firmware/boards/f1_common/f1_port.cpp index 1b2b4ef7..a527952d 100644 --- a/firmware/boards/f1_common/f1_port.cpp +++ b/firmware/boards/f1_common/f1_port.cpp @@ -52,8 +52,6 @@ static Configuration cfg; // Configuration defaults void Configuration::LoadDefaults() { - int i; - *this = {}; NoLongerUsed0 = 0; @@ -61,14 +59,14 @@ void Configuration::LoadDefaults() /* default auxout curve is 0..5V for AFR 8.5 to 18.0 * default auxout[n] input is AFR[n] */ - for (i = 0; i < 8; i++) { + for (size_t i = 0; i < 8; i++) { auxOutBins[0][i] = auxOutBins[1][i] = 8.5 + (18.0 - 8.5) / 7 * i; auxOutValues[0][i] = auxOutValues[1][i] = 0.0 + (5.0 - 0.0) / 7 * i; } auxOutputSource[0] = AuxOutputMode::Afr0; auxOutputSource[1] = AuxOutputMode::Afr1; - for (i = 0; i < AFR_CHANNELS; i++) { + for (size_t i = 0; i < AFR_CHANNELS; i++) { // enable RusEFI protocol afr[i].RusEfiTx = true; afr[i].RusEfiTxDiag = true; @@ -79,7 +77,7 @@ void Configuration::LoadDefaults() afr[i].AemNetIdOffset = i; } - for (i = 0; i < EGT_CHANNELS; i++) { + for (size_t i = 0; i < EGT_CHANNELS; i++) { // disable RusEFI protocol - not implemented egt[i].RusEfiTx = false; egt[i].RusEfiTxDiag = false; @@ -100,6 +98,64 @@ void Configuration::LoadDefaults() Tag = ExpectedTag; } +void Configuration::LoadDefaults(uint16_t option) +{ + LoadDefaults(); + + // Override default with specific options + switch (option) { + case 0: + //nop + break; + case 1: + // AEM protocol AFR + EGT + for (size_t i = 0; i < EGT_CHANNELS; i++) { + egt[i].AemNetTx = true; + } + for (size_t i = 0; i < AFR_CHANNELS; i++) { + afr[i].RusEfiTx = false; + afr[i].RusEfiTxDiag = false; + afr[i].AemNetTx = true; + } + break; + case 2: + // AEM AFR only + for (size_t i = 0; i < EGT_CHANNELS; i++) { + egt[i].AemNetTx = false; + } + for (size_t i = 0; i < AFR_CHANNELS; i++) { + afr[i].RusEfiTx = false; + afr[i].RusEfiTxDiag = false; + afr[i].AemNetTx = true; + } + break; + case 16: + case 17: + case 18: + // DAC over can using MS IO Box protocol (rx only) + auxOutputSource[0] = auxOutputSource[1] = AuxOutputMode::MsIoBox; + for (size_t i = 0; i < EGT_CHANNELS; i++) { + egt[i].AemNetTx = false; + } + for (size_t i = 0; i < AFR_CHANNELS; i++) { + afr[i].RusEfiTx = false; + afr[i].RusEfiTxDiag = false; + afr[i].AemNetTx = false; + } + if (option - 16 < 3) { + iobox.idx = option - 16; + } else { + // custom CAN ID + iobox.idx = 3; + } + iobox.EID = 0x200 + 0x20 * (option - 16); + iobox.enable_rx = 1; + break; + default: + break; + } +} + int InitConfiguration() { size_t size = GetConfigurationSize(); @@ -117,7 +173,7 @@ int InitConfiguration() err = mfsReadRecord(&mfs1, MFS_CONFIGURATION_RECORD_ID, &size, GetConfigurationPtr()); if ((err != MFS_NO_ERROR) || (size != GetConfigurationSize() || !cfg.IsValid())) { /* load defaults */ - cfg.LoadDefaults(); + cfg.LoadDefaults(0); } return 0; @@ -133,9 +189,9 @@ void SetConfiguration() SaveConfiguration(); } -void ResetConfiguration() +void ResetConfiguration(uint16_t option) { - cfg.LoadDefaults(); + cfg.LoadDefaults(option); } /* TS stuff */ diff --git a/firmware/boards/port.h b/firmware/boards/port.h index 23f1d9bc..7ef747b4 100644 --- a/firmware/boards/port.h +++ b/firmware/boards/port.h @@ -61,6 +61,7 @@ class Configuration { return this->Tag == ExpectedTag; } void LoadDefaults(); + void LoadDefaults(uint16_t option); // Actual configuration data union { @@ -127,7 +128,7 @@ static_assert(sizeof(Configuration) == 256); int InitConfiguration(); Configuration* GetConfiguration(); void SetConfiguration(); -void ResetConfiguration(); +void ResetConfiguration(uint16_t option); /* TS stuff */ uint8_t *GetConfigurationPtr(); diff --git a/firmware/console/binary/tunerstudio.cpp b/firmware/console/binary/tunerstudio.cpp index 22a616ec..074f18be 100644 --- a/firmware/console/binary/tunerstudio.cpp +++ b/firmware/console/binary/tunerstudio.cpp @@ -204,7 +204,7 @@ static void handleBurnCommand(TsChannelBase* tsChannel, ts_response_format_e mod sendResponseCode(mode, tsChannel, TS_RESPONSE_BURN_OK); } -static void handleIoTestCommand(TsChannelBase* tsChannel, ts_response_format_e mode, uint16_t subsystem, uint16_t /* index */) { +static void handleIoTestCommand(TsChannelBase* tsChannel, ts_response_format_e mode, uint16_t subsystem, uint16_t index) { /* index is not used yet */ switch (subsystem) { @@ -232,7 +232,7 @@ static void handleIoTestCommand(TsChannelBase* tsChannel, ts_response_format_e m break; case 0xbd: - ResetConfiguration(); + ResetConfiguration(index); SetConfiguration(); /* Send ok to make TS happy, wait until sent */ sendOkResponse(tsChannel, TS_CRC); diff --git a/firmware/ini/wideband_dual.ini b/firmware/ini/wideband_dual.ini index c85322e8..11358ac4 100644 --- a/firmware/ini/wideband_dual.ini +++ b/firmware/ini/wideband_dual.ini @@ -349,6 +349,7 @@ menuDialog = main menu = "&Controller" subMenu = ecuTools, "ECU tools" + subMenu = ecuPresets, "Presets" [ControllerCommands] ; commandName = command1, command2, commandn... @@ -368,6 +369,12 @@ cmd_dfu = "Z\x00\xba\x00\x00" cmd_openblt = "Z\x00\xbc\x00\x00" ; reset settings to default cmd_defaults = "Z\x00\xbd\x00\x00" +; reset settings to presets +cmd_defaultsAemNet = "Z\x00\xbd\x00\x01" +cmd_defaultsAemNetAfrOnly = "Z\x00\xbd\x00\x02" +cmd_defaultsAemNetIoBox0 = "Z\x00\xbd\x00\x10" +cmd_defaultsAemNetIoBox1 = "Z\x00\xbd\x00\x11" +cmd_defaultsAemNetIoBox2 = "Z\x00\xbd\x00\x12" [UserDefined] @@ -434,11 +441,20 @@ dialog = ecuReset, "Reset" commandButton = "Reset to DFU", cmd_dfu commandButton = "Reset to OpenBLT", cmd_openblt -dialog = ecuDefaults, "Default settings" - commandButton = "Load default & restart", cmd_defaults, { 1 }, showMessageOnClick, "Please restart TunerStudio to update settings" - dialog = ecuTools, "ECU tools and Commands", xAxis panel = ecuReset + +dialog = ecuDefaults, "Pre-defined settings" + field = "ECU will restart after new settings appied" + commandButton = "Defaults", cmd_defaults, { 1 }, showMessageOnClick, "Please restart TunerStudio to update settings" + commandButton = "AEMNet AFR and EGT", cmd_defaultsAemNet, { 1 }, showMessageOnClick, "Please restart TunerStudio to update settings" + commandButton = "AEMNet AFR only", cmd_defaultsAemNetAfrOnly, { 1 }, showMessageOnClick, "Please restart TunerStudio to update settings" + field = "Special modes" + commandButton = "IO Box #0 (0x200) (DAC only)", cmd_defaultsAemNetIoBox0, { 1 }, showMessageOnClick, "Please restart TunerStudio to update settings" + commandButton = "IO Box #1 (0x220) (DAC only)", cmd_defaultsAemNetIoBox1, { 1 }, showMessageOnClick, "Please restart TunerStudio to update settings" + commandButton = "IO Box #2 (0x240) (DAC only)", cmd_defaultsAemNetIoBox2, { 1 }, showMessageOnClick, "Please restart TunerStudio to update settings" + +dialog = ecuPresets, "Presets", xAxis panel = ecuDefaults [Tools] diff --git a/firmware/test_can_dac.sh b/firmware/test_can_dac.sh new file mode 100755 index 00000000..bc74738f --- /dev/null +++ b/firmware/test_can_dac.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +INTERFACE=can0 +# base 0x200, base+2 = PWM1,2 periods packet +CANID=202 +#See http://www.msextra.com/doc/pdf/Microsquirt-IObox-1.pdf for protocol specification +# Note BIG-endian values + +while true; do + # zero + cansend $INTERFACE ${CANID}#0000.ffff.0000.ffff + sleep 1 + # half + cansend $INTERFACE ${CANID}#ff7f.ff7f.ff7f.ff7f + sleep 1 + #full + cansend $INTERFACE ${CANID}#ffff.0000.ffff.0000 + sleep 1 +done From 15f3462f9fec3576b827073a5c0ba505846b8fd8 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Tue, 4 Feb 2025 20:07:10 +0300 Subject: [PATCH 90/91] TS: bump signature --- firmware/boards/f1_dual/wideband_board_config.h | 2 +- firmware/boards/f1_dual_rev1/wideband_board_config.h | 2 +- firmware/boards/f1_rev2/wideband_board_config.h | 2 +- firmware/boards/f1_rev3/wideband_board_config.h | 2 +- firmware/ini/wideband_dual.ini | 4 ++-- firmware/ini/wideband_f1.ini | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/firmware/boards/f1_dual/wideband_board_config.h b/firmware/boards/f1_dual/wideband_board_config.h index 9b6bd059..25bdb644 100644 --- a/firmware/boards/f1_dual/wideband_board_config.h +++ b/firmware/boards/f1_dual/wideband_board_config.h @@ -1,7 +1,7 @@ #pragma once // TS settings -#define TS_SIGNATURE "rusEFI 2024.02.11.wideband_dual" +#define TS_SIGNATURE "rusEFI 2025.02.04.wideband_dual" // This board implements two channels #define AFR_CHANNELS 2 diff --git a/firmware/boards/f1_dual_rev1/wideband_board_config.h b/firmware/boards/f1_dual_rev1/wideband_board_config.h index 0203e16d..1516fc1b 100644 --- a/firmware/boards/f1_dual_rev1/wideband_board_config.h +++ b/firmware/boards/f1_dual_rev1/wideband_board_config.h @@ -1,7 +1,7 @@ #pragma once // TS settings -#define TS_SIGNATURE "rusEFI 2024.02.11.wideband_dual" +#define TS_SIGNATURE "rusEFI 2025.02.04.wideband_dual" // This board implements two channels #define AFR_CHANNELS 2 diff --git a/firmware/boards/f1_rev2/wideband_board_config.h b/firmware/boards/f1_rev2/wideband_board_config.h index a7650a6b..984beb89 100644 --- a/firmware/boards/f1_rev2/wideband_board_config.h +++ b/firmware/boards/f1_rev2/wideband_board_config.h @@ -1,7 +1,7 @@ #pragma once // TS settings -#define TS_SIGNATURE "rusEFI 2023.05.10.wideband_f1" +#define TS_SIGNATURE "rusEFI 2025.02.04.wideband_f1" // Fundamental board constants #define VCC_VOLTS (3.3f) diff --git a/firmware/boards/f1_rev3/wideband_board_config.h b/firmware/boards/f1_rev3/wideband_board_config.h index a7650a6b..984beb89 100644 --- a/firmware/boards/f1_rev3/wideband_board_config.h +++ b/firmware/boards/f1_rev3/wideband_board_config.h @@ -1,7 +1,7 @@ #pragma once // TS settings -#define TS_SIGNATURE "rusEFI 2023.05.10.wideband_f1" +#define TS_SIGNATURE "rusEFI 2025.02.04.wideband_f1" // Fundamental board constants #define VCC_VOLTS (3.3f) diff --git a/firmware/ini/wideband_dual.ini b/firmware/ini/wideband_dual.ini index 11358ac4..f95bc9ff 100644 --- a/firmware/ini/wideband_dual.ini +++ b/firmware/ini/wideband_dual.ini @@ -12,12 +12,12 @@ enable2ndByteCanID = false [MegaTune] ; https://rusefi.com/forum/viewtopic.php?p=36201#p36201 - signature = "rusEFI 2024.02.11.wideband_dual" + signature = "rusEFI 2025.02.04.wideband_dual" [TunerStudio] queryCommand = "S" versionInfo = "V" ; firmware version for title bar. - signature = "rusEFI 2024.02.11.wideband_dual" ; signature is expected to be 7 or more characters. + signature = "rusEFI 2025.02.04.wideband_dual" ; signature is expected to be 7 or more characters. ; TS will try to use legacy temp units in some cases, showing "deg F" on a CLT gauge that's actually deg C useLegacyFTempUnits = false diff --git a/firmware/ini/wideband_f1.ini b/firmware/ini/wideband_f1.ini index d9b80966..5be3cefe 100644 --- a/firmware/ini/wideband_f1.ini +++ b/firmware/ini/wideband_f1.ini @@ -12,12 +12,12 @@ enable2ndByteCanID = false [MegaTune] ; https://rusefi.com/forum/viewtopic.php?p=36201#p36201 - signature = "rusEFI 2023.05.10.wideband_f1" + signature = "rusEFI 2025.02.04.wideband_f1" [TunerStudio] queryCommand = "S" versionInfo = "V" ; firmware version for title bar. - signature = "rusEFI 2023.05.10.wideband_f1" ; signature is expected to be 7 or more characters. + signature = "rusEFI 2025.02.04.wideband_f1" ; signature is expected to be 7 or more characters. ; TS will try to use legacy temp units in some cases, showing "deg F" on a CLT gauge that's actually deg C useLegacyFTempUnits = false From 541d4137b8cc9efd62de43163413321635a47e54 Mon Sep 17 00:00:00 2001 From: Andrey Gusakov Date: Tue, 4 Feb 2025 22:47:34 +0300 Subject: [PATCH 91/91] fix f0 compilation --- firmware/auxout.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/firmware/auxout.cpp b/firmware/auxout.cpp index 9201b3e0..5bf78ca3 100644 --- a/firmware/auxout.cpp +++ b/firmware/auxout.cpp @@ -203,4 +203,9 @@ void InitAuxDac() { } + +void SetAuxDac(size_t, float) +{ +} + #endif