rusefi/firmware/hw_layer/adc/adc_inputs.cpp

248 lines
6.5 KiB
C++
Raw Normal View History

/**
* @file adc_inputs.cpp
* @brief Low level ADC code
*
* @date Jan 14, 2013
2020-01-13 18:57:43 -08:00
* @author Andrey Belomutskiy, (c) 2012-2020
*/
#include "pch.h"
2024-07-27 09:36:35 -07:00
float PUBLIC_API_WEAK getAnalogInputDividerCoefficient(adc_channel_e) {
return engineConfiguration->analogInputDividerCoefficient;
}
2022-09-07 12:56:45 -07:00
#if HAL_USE_ADC
#include "adc_subscription.h"
#include "AdcDevice.h"
#include "mpu_util.h"
#include "periodic_thread_controller.h"
#include "protected_gpio.h"
extern AdcDevice fastAdc;
static volatile NO_CACHE adcsample_t slowAdcSamples[SLOW_ADC_CHANNEL_COUNT];
2024-05-09 13:12:49 -07:00
static uint32_t slowAdcConversionCount = 0;
static uint32_t slowAdcErrorsCount = 0;
static float mcuTemperature;
2024-07-22 16:47:57 -07:00
static AdcChannelMode adcHwChannelMode[EFI_ADC_TOTAL_CHANNELS];
// todo: move this flag to Engine god object
static int adcDebugReporting = false;
2024-07-22 16:47:57 -07:00
AdcChannelMode getAdcMode(adc_channel_e hwChannel) {
return adcHwChannelMode[hwChannel];
2024-05-09 09:05:31 -07:00
}
2024-06-25 01:51:37 -07:00
float getMCUInternalTemperature() {
return mcuTemperature;
}
int getInternalAdcValue(const char *msg, adc_channel_e hwChannel) {
if (!isAdcChannelValid(hwChannel)) {
warning(ObdCode::CUSTOM_OBD_ANALOG_INPUT_NOT_CONFIGURED, "ADC: %s input is not configured", msg);
return -1;
}
#if EFI_USE_FAST_ADC
2024-07-22 16:47:57 -07:00
if (adcHwChannelMode[hwChannel] == AdcChannelMode::Fast) {
2024-06-25 01:51:37 -07:00
return fastAdc.getAvgAdcValue(hwChannel);
}
#endif // EFI_USE_FAST_ADC
return slowAdcSamples[hwChannel - EFI_ADC_0];
}
2019-03-02 15:41:25 -08:00
static void printAdcValue(int channel) {
2024-05-09 13:00:59 -07:00
/* Do this check before conversion to adc_channel_e that is uint8_t based */
if ((channel < EFI_ADC_NONE) || (channel >= EFI_ADC_TOTAL_CHANNELS)) {
efiPrintf("Invalid ADC channel %d", channel);
return;
}
2019-03-02 15:41:25 -08:00
int value = getAdcValue("print", (adc_channel_e)channel);
float volts = adcToVoltsDivided(value, (adc_channel_e)channel);
2024-05-09 13:00:59 -07:00
efiPrintf("adc %d voltage : %.3f", channel, volts);
}
2024-05-09 04:59:52 -07:00
static void printAdcChannedReport(const char *prefix, int internalIndex, adc_channel_e hwChannel)
{
if (isAdcChannelValid(hwChannel)) {
ioportid_t port = getAdcChannelPort("print", hwChannel);
int pin = getAdcChannelPin(hwChannel);
int adcValue = getAdcValue("print", hwChannel);
float volts = getVoltage("print", hwChannel);
float voltsDivided = getVoltageDivided("print", hwChannel);
/* Human index starts from 1 */
efiPrintf(" %s ch[%2d] @ %s%d ADC%d 12bit=%4d %.3fV (input %.3fV)",
prefix, internalIndex, portname(port), pin,
/* TODO: */ hwChannel - EFI_ADC_0 + 1,
adcValue, volts, voltsDivided);
}
}
2021-07-17 10:42:10 -07:00
void printFullAdcReport(void) {
#if EFI_USE_FAST_ADC
efiPrintf("fast %lu samples", fastAdc.conversionCount);
for (int internalIndex = 0; internalIndex < fastAdc.size(); internalIndex++) {
2024-05-09 04:26:51 -07:00
adc_channel_e hwChannel = fastAdc.getAdcChannelByInternalIndex(internalIndex);
2024-05-09 04:59:52 -07:00
printAdcChannedReport("F", internalIndex, hwChannel);
}
#endif // EFI_USE_FAST_ADC
efiPrintf("slow %lu samples", slowAdcConversionCount);
/* we assume that all slow ADC channels are enabled */
for (int internalIndex = 0; internalIndex < ADC_MAX_CHANNELS_COUNT; internalIndex++) {
2024-05-05 08:51:47 -07:00
adc_channel_e hwChannel = static_cast<adc_channel_e>(internalIndex + EFI_ADC_0);
2024-05-09 04:59:52 -07:00
printAdcChannedReport("S", internalIndex, hwChannel);
}
}
static void setAdcDebugReporting(int value) {
adcDebugReporting = value;
efiPrintf("adcDebug=%d", adcDebugReporting);
}
class SlowAdcController : public PeriodicController<UTILITY_THREAD_STACK_SIZE> {
public:
2024-01-06 18:31:18 -08:00
SlowAdcController()
: PeriodicController("ADC", PRIO_ADC, SLOW_ADC_RATE)
{
}
2019-10-08 17:44:59 -07:00
void PeriodicTask(efitick_t nowNt) override {
{
ScopePerf perf(PE::AdcConversionSlow);
2019-10-08 17:44:59 -07:00
/* drop volatile type qualifier - this is safe */
if (!readSlowAnalogInputs((adcsample_t *)slowAdcSamples)) {
slowAdcErrorsCount++;
return;
}
// Ask the port to sample the MCU temperature
mcuTemperature = getMcuTemperature();
}
{
ScopePerf perf(PE::AdcProcessSlow);
AdcSubscription::UpdateSubscribers(nowNt);
slowAdcConversionCount++;
protectedGpio_check(nowNt);
}
2019-10-08 17:44:59 -07:00
}
};
void addFastAdcChannel(const char*, adc_channel_e hwChannel) {
2024-05-05 08:51:47 -07:00
if (!isAdcChannelValid(hwChannel)) {
return;
}
#if EFI_USE_FAST_ADC
fastAdc.enableChannel(hwChannel);
#endif
2024-07-22 16:47:57 -07:00
adcHwChannelMode[hwChannel] = AdcChannelMode::Fast;
// Nothing to do for slow channels, input is mapped to analog in init_sensors.cpp
}
void removeChannel(const char*, adc_channel_e hwChannel) {
2024-05-05 08:51:47 -07:00
if (!isAdcChannelValid(hwChannel)) {
return;
}
#if EFI_USE_FAST_ADC
2024-07-22 16:47:57 -07:00
if (adcHwChannelMode[hwChannel] == AdcChannelMode::Fast) {
/* TODO: */
//fastAdc.disableChannel(hwChannel);
}
#endif
2024-07-22 16:47:57 -07:00
adcHwChannelMode[hwChannel] = AdcChannelMode::Off;
}
// Weak link a stub so that every board doesn't have to implement this function
__attribute__((weak)) void setAdcChannelOverrides() { }
static void configureInputs() {
2024-07-22 16:47:57 -07:00
memset(adcHwChannelMode, (int)AdcChannelMode::Off, sizeof(adcHwChannelMode));
2019-12-03 20:55:18 -08:00
/**
* order of analog channels here is totally random and has no meaning
* we also have some weird implementation with internal indices - that all has no meaning, it's just a random implementation
* which does not mean anything.
*/
addFastAdcChannel("MAP", engineConfiguration->map.sensor.hwChannel);
addFastAdcChannel("HIP9011", engineConfiguration->hipOutputChannel);
// not currently used addFastAdcChannel("Vref", engineConfiguration->vRefAdcChannel, ADC_SLOW);
2020-09-21 03:10:25 -07:00
addFastAdcChannel("AUXF#1", engineConfiguration->auxFastSensor1_adcChannel);
2020-09-21 03:10:25 -07:00
setAdcChannelOverrides();
}
void waitForSlowAdc(uint32_t lastAdcCounter) {
// note that having ADC reading is one thing while having new sensor API is a totally different thing!
// todo: use sync.objects?
while (slowAdcConversionCount <= lastAdcCounter) {
chThdSleepMilliseconds(1);
}
}
static SlowAdcController slowAdcController;
void initAdcInputs() {
efiPrintf("initAdcInputs()");
configureInputs();
// migrate to 'enable adcdebug'
addConsoleActionI("adcdebug", &setAdcDebugReporting);
2019-04-12 17:52:51 -07:00
#if EFI_INTERNAL_ADC
portInitAdc();
// Start the slow ADC thread
2022-07-21 12:17:32 -07:00
slowAdcController.start();
2017-04-05 19:41:51 -07:00
#if EFI_USE_FAST_ADC
2024-06-25 05:04:11 -07:00
// After this point fastAdc is not allowed to add channels
fastAdc.init();
#endif // EFI_USE_FAST_ADC
addConsoleActionI("adc", (VoidInt) printAdcValue);
2024-06-25 05:04:11 -07:00
#else // ! EFI_INTERNAL_ADC
efiPrintf("ADC disabled");
2024-06-25 05:04:11 -07:00
#endif // EFI_INTERNAL_ADC
}
void printFullAdcReportIfNeeded(void) {
if (!adcDebugReporting)
return;
printFullAdcReport();
}
#else /* not HAL_USE_ADC */
__attribute__((weak)) float getVoltageDivided(const char*, adc_channel_e) {
return 0;
}
// voltage in MCU universe, from zero to VDD
__attribute__((weak)) float getVoltage(const char*, adc_channel_e) {
return 0;
}
#endif