prep for multiple MAP sensors (#4705)

* prep for multiple MAP sensors

* move guard

* sensor info printing

* maybe kinetis memory
This commit is contained in:
Matthew Kennedy 2022-10-27 10:59:36 -07:00 committed by GitHub
parent 6c84b2b58c
commit 6a9b481c65
4 changed files with 98 additions and 78 deletions

View File

@ -41,20 +41,6 @@
*/
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
#define MAX_MAP_BUFFER_LENGTH (MAX_CYLINDER_COUNT)
// in MAP units, not voltage!
@ -68,24 +54,12 @@ static int averagedMapBufIdx = 0;
static scheduling_s startTimers[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 startAveraging(scheduling_s *endAveragingScheduling) {
efiAssertVoid(CUSTOM_ERR_6649, getCurrentRemainingStack() > 128, "lowstck#9");
{
// with locking we will have a consistent state
chibios_rt::CriticalSectionLocker csl;
mapAdcAccumulator = 0;
mapMeasurementsCounter = 0;
isAveraging = true;
}
getMapAvg().start();
mapAveragingPin.setHigh();
@ -93,6 +67,51 @@ static void startAveraging(scheduling_s *endAveragingScheduling) {
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
/**
@ -104,23 +123,18 @@ void mapAveragingAdcCallback(adcsample_t adcValue) {
efiAssertVoid(CUSTOM_ERR_6650, getCurrentRemainingStack() > 128, "lowstck#9a");
float instantVoltage = adcToVoltsDivided(adcValue);
SensorResult mapResult = convertMap(instantVoltage);
SensorResult mapResult = getMapAvg().submit(instantVoltage);
if (!mapResult) {
// hopefully this warning is not too much CPU consumption for fast ADC callback
warning(CUSTOM_INSTANT_MAP_DECODING, "Invalid MAP at %f", instantVoltage);
}
float instantMap = mapResult.value_or(0);
#if EFI_TUNER_STUDIO
engine->outputChannels.instantMAPValue = instantMap;
#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
@ -128,32 +142,9 @@ static void endAveraging(void*) {
#if ! EFI_UNIT_TEST
chibios_rt::CriticalSectionLocker csl;
#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();
}
@ -170,9 +161,7 @@ static void applyMapMinBufferLength() {
#if EFI_TUNER_STUDIO
void postMapState(TunerStudioOutputChannels *tsOutputChannels) {
tsOutputChannels->debugFloatField1 = v_averagedMapValue;
tsOutputChannels->debugFloatField2 = engine->engineState.mapAveragingDuration;
tsOutputChannels->debugIntField1 = mapMeasurementsCounter;
}
#endif /* EFI_TUNER_STUDIO */
@ -254,13 +243,13 @@ void mapAveragingTriggerCallback(
// only if value is already prepared
int structIndex = getRevolutionCounter() % 2;
scheduling_s *starTimer = &startTimers[i][structIndex];
scheduling_s *startTimer = &startTimers[i][structIndex];
scheduling_s *endTimer = &endTimers[i][structIndex];
// 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
// todo: schedule this based on closest trigger event, same as ignition works
scheduleByAngle(starTimer, edgeTimestamp, samplingStart,
scheduleByAngle(startTimer, edgeTimestamp, samplingStart,
{ startAveraging, endTimer });
}
#endif

View File

@ -7,6 +7,8 @@
#pragma once
#include "sensor_converter_func.h"
#if EFI_MAP_AVERAGING
#if HAL_USE_ADC
@ -19,11 +21,40 @@ void refreshMapAveragingPreCalc();
void mapAveragingTriggerCallback(
uint32_t index, efitick_t edgeTimestamp);
void onMapAveraged(float mapKpa, efitick_t nowNt);
SensorResult convertMap(float volts);
#if EFI_TUNER_STUDIO
void postMapState(TunerStudioOutputChannels *tsOutputChannels);
#endif
// allow smoothing up to number of cylinders
#define MAX_MAP_BUFFER_LENGTH (MAX_CYLINDER_COUNT)
#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();

View File

@ -10,6 +10,7 @@
#include "resistance_func.h"
#include "thermistor_func.h"
#include "identity_func.h"
#include "map_averaging.h"
void ProxySensor::showInfo(const char* sensorName) const {
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);
}
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 {
efiPrintf(" Linear function slope: %.2f offset: %.2f min: %.1f max: %.1f", m_a, m_b, m_minOutput, m_maxOutput);
const auto value = convert(testRawValue);

View File

@ -4,8 +4,7 @@
#include "linear_func.h"
#include "fallback_sensor.h"
#include "functional_sensor.h"
#include "function_pointer_sensor.h"
#include "identity_func.h"
#include "map_averaging.h"
static LinearFunc baroConverter;
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
// 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
static FunctionalSensor fastMapSensor(SensorType::MapFast, MS2NT(200));
MapAverager fastMapSensor(SensorType::MapFast, MS2NT(200));
// This is called from the fast ADC completion callback
void onMapAveraged(float mapKpa, efitick_t nowNt) {
// This sensor uses identity function, so it's kPa in, kPa out
fastMapSensor.postRawValue(mapKpa, nowNt);
MapAverager& getMapAvg() {
return fastMapSensor;
}
SensorResult convertMap(float volts) {
return mapConverter.convert(volts);
}
// Combine MAP sensors: prefer fast sensor, but use slow if fast is unavailable.
static FallbackSensor mapCombiner(SensorType::Map, SensorType::MapFast, SensorType::MapSlow);
@ -106,7 +100,7 @@ void initMap() {
configureMapFunction(mapConverter, engineConfiguration->map.sensor.type);
slowMapSensor.setFunction(mapConverter);
fastMapSensor.setFunction(identityFunction);
fastMapSensor.setFunction(mapConverter);
slowMapSensor.Register();
fastMapSensor.Register();