prep for multiple MAP sensors (#4677)
* prep for multiple MAP sensors * move guard * sensor info printing
This commit is contained in:
parent
f5abf3059a
commit
b8c79b7881
|
@ -41,20 +41,6 @@
|
||||||
*/
|
*/
|
||||||
static NamedOutputPin mapAveragingPin("map");
|
static NamedOutputPin mapAveragingPin("map");
|
||||||
|
|
||||||
/**
|
|
||||||
* Running MAP accumulator - sum of all measurements within averaging window
|
|
||||||
*/
|
|
||||||
static volatile float mapAdcAccumulator = 0;
|
|
||||||
/**
|
|
||||||
* Running counter of measurements to consider for averaging
|
|
||||||
*/
|
|
||||||
static volatile int mapMeasurementsCounter = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* v_ for Voltage
|
|
||||||
*/
|
|
||||||
static float v_averagedMapValue;
|
|
||||||
|
|
||||||
// allow smoothing up to number of cylinders
|
// allow smoothing up to number of cylinders
|
||||||
#define MAX_MAP_BUFFER_LENGTH (MAX_CYLINDER_COUNT)
|
#define MAX_MAP_BUFFER_LENGTH (MAX_CYLINDER_COUNT)
|
||||||
// in MAP units, not voltage!
|
// in MAP units, not voltage!
|
||||||
|
@ -68,24 +54,12 @@ static int averagedMapBufIdx = 0;
|
||||||
static scheduling_s startTimers[MAX_CYLINDER_COUNT][2];
|
static scheduling_s startTimers[MAX_CYLINDER_COUNT][2];
|
||||||
static scheduling_s endTimers[MAX_CYLINDER_COUNT][2];
|
static scheduling_s endTimers[MAX_CYLINDER_COUNT][2];
|
||||||
|
|
||||||
/**
|
|
||||||
* that's a performance optimization: let's not bother averaging
|
|
||||||
* if we are outside of of the window
|
|
||||||
*/
|
|
||||||
static bool isAveraging = false;
|
|
||||||
|
|
||||||
static void endAveraging(void *arg);
|
static void endAveraging(void *arg);
|
||||||
|
|
||||||
static void startAveraging(scheduling_s *endAveragingScheduling) {
|
static void startAveraging(scheduling_s *endAveragingScheduling) {
|
||||||
efiAssertVoid(CUSTOM_ERR_6649, getCurrentRemainingStack() > 128, "lowstck#9");
|
efiAssertVoid(CUSTOM_ERR_6649, getCurrentRemainingStack() > 128, "lowstck#9");
|
||||||
|
|
||||||
{
|
getMapAvg().start();
|
||||||
// with locking we will have a consistent state
|
|
||||||
chibios_rt::CriticalSectionLocker csl;
|
|
||||||
mapAdcAccumulator = 0;
|
|
||||||
mapMeasurementsCounter = 0;
|
|
||||||
isAveraging = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
mapAveragingPin.setHigh();
|
mapAveragingPin.setHigh();
|
||||||
|
|
||||||
|
@ -93,6 +67,51 @@ static void startAveraging(scheduling_s *endAveragingScheduling) {
|
||||||
endAveraging);
|
endAveraging);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MapAverager::start() {
|
||||||
|
chibios_rt::CriticalSectionLocker csl;
|
||||||
|
|
||||||
|
m_counter = 0;
|
||||||
|
m_sum = 0;
|
||||||
|
m_isAveraging = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SensorResult MapAverager::submit(float volts) {
|
||||||
|
auto result = m_function ? m_function->convert(volts) : unexpected;
|
||||||
|
|
||||||
|
if (m_isAveraging && result) {
|
||||||
|
chibios_rt::CriticalSectionLocker csl;
|
||||||
|
|
||||||
|
m_counter++;
|
||||||
|
m_sum += result.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapAverager::stop() {
|
||||||
|
m_isAveraging = false;
|
||||||
|
|
||||||
|
if (m_counter > 0) {
|
||||||
|
float averageMap = m_sum / m_counter;
|
||||||
|
m_lastCounter = m_counter;
|
||||||
|
|
||||||
|
// TODO: this should be per-sensor, not one for all MAP sensors
|
||||||
|
averagedMapRunningBuffer[averagedMapBufIdx] = averageMap;
|
||||||
|
// increment circular running buffer index
|
||||||
|
averagedMapBufIdx = (averagedMapBufIdx + 1) % mapMinBufferLength;
|
||||||
|
// find min. value (only works for pressure values, not raw voltages!)
|
||||||
|
float minPressure = averagedMapRunningBuffer[0];
|
||||||
|
for (int i = 1; i < mapMinBufferLength; i++) {
|
||||||
|
if (averagedMapRunningBuffer[i] < minPressure)
|
||||||
|
minPressure = averagedMapRunningBuffer[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
setValidValue(minPressure, getTimeNowNt());
|
||||||
|
} else {
|
||||||
|
warning(CUSTOM_UNEXPECTED_MAP_VALUE, "No MAP values");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if HAL_USE_ADC
|
#if HAL_USE_ADC
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -104,23 +123,18 @@ void mapAveragingAdcCallback(adcsample_t adcValue) {
|
||||||
efiAssertVoid(CUSTOM_ERR_6650, getCurrentRemainingStack() > 128, "lowstck#9a");
|
efiAssertVoid(CUSTOM_ERR_6650, getCurrentRemainingStack() > 128, "lowstck#9a");
|
||||||
|
|
||||||
float instantVoltage = adcToVoltsDivided(adcValue);
|
float instantVoltage = adcToVoltsDivided(adcValue);
|
||||||
SensorResult mapResult = convertMap(instantVoltage);
|
|
||||||
|
SensorResult mapResult = getMapAvg().submit(instantVoltage);
|
||||||
|
|
||||||
if (!mapResult) {
|
if (!mapResult) {
|
||||||
// hopefully this warning is not too much CPU consumption for fast ADC callback
|
// hopefully this warning is not too much CPU consumption for fast ADC callback
|
||||||
warning(CUSTOM_INSTANT_MAP_DECODING, "Invalid MAP at %f", instantVoltage);
|
warning(CUSTOM_INSTANT_MAP_DECODING, "Invalid MAP at %f", instantVoltage);
|
||||||
}
|
}
|
||||||
|
|
||||||
float instantMap = mapResult.value_or(0);
|
float instantMap = mapResult.value_or(0);
|
||||||
#if EFI_TUNER_STUDIO
|
#if EFI_TUNER_STUDIO
|
||||||
engine->outputChannels.instantMAPValue = instantMap;
|
engine->outputChannels.instantMAPValue = instantMap;
|
||||||
#endif // EFI_TUNER_STUDIO
|
#endif // EFI_TUNER_STUDIO
|
||||||
|
|
||||||
/* Calculates the average values from the ADC samples.*/
|
|
||||||
if (isAveraging) {
|
|
||||||
// with locking we will have a consistent state
|
|
||||||
chibios_rt::CriticalSectionLocker csl;
|
|
||||||
mapAdcAccumulator += adcValue;
|
|
||||||
mapMeasurementsCounter++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -128,32 +142,9 @@ static void endAveraging(void*) {
|
||||||
#if ! EFI_UNIT_TEST
|
#if ! EFI_UNIT_TEST
|
||||||
chibios_rt::CriticalSectionLocker csl;
|
chibios_rt::CriticalSectionLocker csl;
|
||||||
#endif
|
#endif
|
||||||
isAveraging = false;
|
|
||||||
// with locking we would have a consistent state
|
|
||||||
#if HAL_USE_ADC
|
|
||||||
if (mapMeasurementsCounter > 0) {
|
|
||||||
v_averagedMapValue = adcToVoltsDivided(mapAdcAccumulator / mapMeasurementsCounter);
|
|
||||||
|
|
||||||
SensorResult mapValue = convertMap(v_averagedMapValue);
|
getMapAvg().stop();
|
||||||
|
|
||||||
// Skip update if conversion invalid
|
|
||||||
if (mapValue) {
|
|
||||||
averagedMapRunningBuffer[averagedMapBufIdx] = mapValue.Value;
|
|
||||||
// increment circular running buffer index
|
|
||||||
averagedMapBufIdx = (averagedMapBufIdx + 1) % mapMinBufferLength;
|
|
||||||
// find min. value (only works for pressure values, not raw voltages!)
|
|
||||||
float minPressure = averagedMapRunningBuffer[0];
|
|
||||||
for (int i = 1; i < mapMinBufferLength; i++) {
|
|
||||||
if (averagedMapRunningBuffer[i] < minPressure)
|
|
||||||
minPressure = averagedMapRunningBuffer[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
onMapAveraged(minPressure, getTimeNowNt());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
warning(CUSTOM_UNEXPECTED_MAP_VALUE, "No MAP values");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
mapAveragingPin.setLow();
|
mapAveragingPin.setLow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,9 +161,7 @@ static void applyMapMinBufferLength() {
|
||||||
|
|
||||||
#if EFI_TUNER_STUDIO
|
#if EFI_TUNER_STUDIO
|
||||||
void postMapState(TunerStudioOutputChannels *tsOutputChannels) {
|
void postMapState(TunerStudioOutputChannels *tsOutputChannels) {
|
||||||
tsOutputChannels->debugFloatField1 = v_averagedMapValue;
|
|
||||||
tsOutputChannels->debugFloatField2 = engine->engineState.mapAveragingDuration;
|
tsOutputChannels->debugFloatField2 = engine->engineState.mapAveragingDuration;
|
||||||
tsOutputChannels->debugIntField1 = mapMeasurementsCounter;
|
|
||||||
}
|
}
|
||||||
#endif /* EFI_TUNER_STUDIO */
|
#endif /* EFI_TUNER_STUDIO */
|
||||||
|
|
||||||
|
@ -254,13 +243,13 @@ void mapAveragingTriggerCallback(
|
||||||
// only if value is already prepared
|
// only if value is already prepared
|
||||||
int structIndex = getRevolutionCounter() % 2;
|
int structIndex = getRevolutionCounter() % 2;
|
||||||
|
|
||||||
scheduling_s *starTimer = &startTimers[i][structIndex];
|
scheduling_s *startTimer = &startTimers[i][structIndex];
|
||||||
scheduling_s *endTimer = &endTimers[i][structIndex];
|
scheduling_s *endTimer = &endTimers[i][structIndex];
|
||||||
|
|
||||||
// at the moment we schedule based on time prediction based on current RPM and angle
|
// at the moment we schedule based on time prediction based on current RPM and angle
|
||||||
// we are loosing precision in case of changing RPM - the further away is the event the worse is precision
|
// we are loosing precision in case of changing RPM - the further away is the event the worse is precision
|
||||||
// todo: schedule this based on closest trigger event, same as ignition works
|
// todo: schedule this based on closest trigger event, same as ignition works
|
||||||
scheduleByAngle(starTimer, edgeTimestamp, samplingStart,
|
scheduleByAngle(startTimer, edgeTimestamp, samplingStart,
|
||||||
{ startAveraging, endTimer });
|
{ startAveraging, endTimer });
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "sensor_converter_func.h"
|
||||||
|
|
||||||
#if EFI_MAP_AVERAGING
|
#if EFI_MAP_AVERAGING
|
||||||
|
|
||||||
#if HAL_USE_ADC
|
#if HAL_USE_ADC
|
||||||
|
@ -19,11 +21,40 @@ void refreshMapAveragingPreCalc();
|
||||||
void mapAveragingTriggerCallback(
|
void mapAveragingTriggerCallback(
|
||||||
uint32_t index, efitick_t edgeTimestamp);
|
uint32_t index, efitick_t edgeTimestamp);
|
||||||
|
|
||||||
void onMapAveraged(float mapKpa, efitick_t nowNt);
|
|
||||||
SensorResult convertMap(float volts);
|
|
||||||
|
|
||||||
#if EFI_TUNER_STUDIO
|
#if EFI_TUNER_STUDIO
|
||||||
void postMapState(TunerStudioOutputChannels *tsOutputChannels);
|
void postMapState(TunerStudioOutputChannels *tsOutputChannels);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// allow smoothing up to number of cylinders
|
||||||
|
#define MAX_MAP_BUFFER_LENGTH (MAX_CYLINDER_COUNT)
|
||||||
|
|
||||||
#endif /* EFI_MAP_AVERAGING */
|
#endif /* EFI_MAP_AVERAGING */
|
||||||
|
|
||||||
|
class MapAverager : public StoredValueSensor {
|
||||||
|
public:
|
||||||
|
MapAverager(SensorType type, efitick_t timeout)
|
||||||
|
: StoredValueSensor(type, timeout)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
SensorResult submit(float sensorVolts);
|
||||||
|
|
||||||
|
void setFunction(SensorConverter& func) {
|
||||||
|
m_function = &func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void showInfo(const char* sensorName) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
SensorConverter* m_function = nullptr;
|
||||||
|
|
||||||
|
bool m_isAveraging = false;
|
||||||
|
size_t m_counter = 0;
|
||||||
|
size_t m_lastCounter = 0;
|
||||||
|
float m_sum = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
MapAverager& getMapAvg();
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "resistance_func.h"
|
#include "resistance_func.h"
|
||||||
#include "thermistor_func.h"
|
#include "thermistor_func.h"
|
||||||
#include "identity_func.h"
|
#include "identity_func.h"
|
||||||
|
#include "map_averaging.h"
|
||||||
|
|
||||||
void ProxySensor::showInfo(const char* sensorName) const {
|
void ProxySensor::showInfo(const char* sensorName) const {
|
||||||
efiPrintf("Sensor \"%s\" proxied from sensor \"%s\"", sensorName, getSensorName(m_proxiedSensor));
|
efiPrintf("Sensor \"%s\" proxied from sensor \"%s\"", sensorName, getSensorName(m_proxiedSensor));
|
||||||
|
@ -66,6 +67,11 @@ void Lps25Sensor::showInfo(const char* sensorName) const {
|
||||||
efiPrintf("%s: LPS25 baro %.2f kPa", sensorName, get().Value);
|
efiPrintf("%s: LPS25 baro %.2f kPa", sensorName, get().Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MapAverager::showInfo(const char* sensorName) const {
|
||||||
|
const auto value = get();
|
||||||
|
efiPrintf("Sensor \"%s\" is MAP averager: valid: %s value: %.2f averaged sample count: %d", sensorName, boolToString(value.Valid), value.Value, m_lastCounter);
|
||||||
|
}
|
||||||
|
|
||||||
void LinearFunc::showInfo(float testRawValue) const {
|
void LinearFunc::showInfo(float testRawValue) const {
|
||||||
efiPrintf(" Linear function slope: %.2f offset: %.2f min: %.1f max: %.1f", m_a, m_b, m_minOutput, m_maxOutput);
|
efiPrintf(" Linear function slope: %.2f offset: %.2f min: %.1f max: %.1f", m_a, m_b, m_minOutput, m_maxOutput);
|
||||||
const auto value = convert(testRawValue);
|
const auto value = convert(testRawValue);
|
||||||
|
|
|
@ -4,8 +4,7 @@
|
||||||
#include "linear_func.h"
|
#include "linear_func.h"
|
||||||
#include "fallback_sensor.h"
|
#include "fallback_sensor.h"
|
||||||
#include "functional_sensor.h"
|
#include "functional_sensor.h"
|
||||||
#include "function_pointer_sensor.h"
|
#include "map_averaging.h"
|
||||||
#include "identity_func.h"
|
|
||||||
|
|
||||||
static LinearFunc baroConverter;
|
static LinearFunc baroConverter;
|
||||||
static FunctionalSensor baroSensor(SensorType::BarometricPressure, MS2NT(50));
|
static FunctionalSensor baroSensor(SensorType::BarometricPressure, MS2NT(50));
|
||||||
|
@ -18,17 +17,12 @@ static FunctionalSensor slowMapSensor(SensorType::MapSlow, MS2NT(50));
|
||||||
// lowest reasonable idle is maybe 600 rpm
|
// lowest reasonable idle is maybe 600 rpm
|
||||||
// one sample per cycle (1 cylinder, or "sample one cyl" mode) gives a period of 100ms
|
// one sample per cycle (1 cylinder, or "sample one cyl" mode) gives a period of 100ms
|
||||||
// add some margin -> 200ms timeout for fast MAP sampling
|
// add some margin -> 200ms timeout for fast MAP sampling
|
||||||
static FunctionalSensor fastMapSensor(SensorType::MapFast, MS2NT(200));
|
MapAverager fastMapSensor(SensorType::MapFast, MS2NT(200));
|
||||||
|
|
||||||
// This is called from the fast ADC completion callback
|
MapAverager& getMapAvg() {
|
||||||
void onMapAveraged(float mapKpa, efitick_t nowNt) {
|
return fastMapSensor;
|
||||||
// This sensor uses identity function, so it's kPa in, kPa out
|
|
||||||
fastMapSensor.postRawValue(mapKpa, nowNt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SensorResult convertMap(float volts) {
|
|
||||||
return mapConverter.convert(volts);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Combine MAP sensors: prefer fast sensor, but use slow if fast is unavailable.
|
// Combine MAP sensors: prefer fast sensor, but use slow if fast is unavailable.
|
||||||
static FallbackSensor mapCombiner(SensorType::Map, SensorType::MapFast, SensorType::MapSlow);
|
static FallbackSensor mapCombiner(SensorType::Map, SensorType::MapFast, SensorType::MapSlow);
|
||||||
|
@ -106,7 +100,7 @@ void initMap() {
|
||||||
configureMapFunction(mapConverter, engineConfiguration->map.sensor.type);
|
configureMapFunction(mapConverter, engineConfiguration->map.sensor.type);
|
||||||
|
|
||||||
slowMapSensor.setFunction(mapConverter);
|
slowMapSensor.setFunction(mapConverter);
|
||||||
fastMapSensor.setFunction(identityFunction);
|
fastMapSensor.setFunction(mapConverter);
|
||||||
|
|
||||||
slowMapSensor.Register();
|
slowMapSensor.Register();
|
||||||
fastMapSensor.Register();
|
fastMapSensor.Register();
|
||||||
|
|
Loading…
Reference in New Issue