From 2312b0ae5755e47b0963586f3ae717537c57da4d Mon Sep 17 00:00:00 2001 From: Andrey G Date: Wed, 9 Sep 2020 00:20:55 +0300 Subject: [PATCH] Adc improvements (#1765) * ADC: move DMA buffer outside of AdcDevice (save few bytes) * ADC: inlcude fast channels to debug output * ADC: save some CPU ticks (disabled until fully tested) * ADC: simplify --- firmware/controllers/engine_controller.cpp | 2 +- firmware/hw_layer/adc/AdcConfiguration.h | 10 +--- firmware/hw_layer/adc/adc_inputs.cpp | 69 ++++++++++++++++++---- firmware/hw_layer/adc/adc_inputs.h | 2 +- 4 files changed, 61 insertions(+), 22 deletions(-) diff --git a/firmware/controllers/engine_controller.cpp b/firmware/controllers/engine_controller.cpp index cd7dcac3cf..85ce87c3c8 100644 --- a/firmware/controllers/engine_controller.cpp +++ b/firmware/controllers/engine_controller.cpp @@ -308,7 +308,7 @@ static void printAnalogChannelInfoExt(const char *name, adc_channel_e hwChannel, } float voltage = adcVoltage * dividerCoeff; - scheduleMsg(&logger, "%s ADC%d %s %s adc=%.2f/input=%.2fv/divider=%.2f", name, hwChannel, getAdcMode(hwChannel), + scheduleMsg(&logger, "%s ADC%d %s %s adc=%.2f/input=%.2fv/divider=%.2f", name, hwChannel, getAdc_channel_mode_e(getAdcMode(hwChannel)), getPinNameByAdcChannel(name, hwChannel, pinNameBuffer), adcVoltage, voltage, dividerCoeff); #endif /* HAL_USE_ADC */ } diff --git a/firmware/hw_layer/adc/AdcConfiguration.h b/firmware/hw_layer/adc/AdcConfiguration.h index b0b4b32ad2..921d1c3bd2 100644 --- a/firmware/hw_layer/adc/AdcConfiguration.h +++ b/firmware/hw_layer/adc/AdcConfiguration.h @@ -20,7 +20,7 @@ typedef struct { class AdcDevice { public: - explicit AdcDevice(ADCConversionGroup* hwConfig); + explicit AdcDevice(ADCConversionGroup* hwConfig, adcsample_t *buf); void enableChannel(adc_channel_e hwChannelIndex); void enableChannelAndPin(const char *msg, adc_channel_e hwChannelIndex); adc_channel_e getAdcHardwareIndexByInternalIndex(int index) const; @@ -33,13 +33,7 @@ public: int getAdcValueByIndex(int internalIndex) const; void invalidateSamplesCache(); - // on F7 this must be aligned on a 32-byte boundary, and be a multiple of 32 bytes long. - // When we invalidate the cache line(s) for ADC samples, we don't want to nuke any - // adjacent data. - // F4 does not care - __ALIGNED(32) adcsample_t samples[ADC_MAX_CHANNELS_COUNT * MAX_ADC_GRP_BUF_DEPTH]; - // Assert multiple of 32 bytes long so we don't stomp on the data after the buffer - static_assert(sizeof(samples) % 32 == 0, "ADC sample buffer size must be a multiple of 32 bytes"); + adcsample_t *samples; int getAdcValueByHwChannel(int hwChannel) const; diff --git a/firmware/hw_layer/adc/adc_inputs.cpp b/firmware/hw_layer/adc/adc_inputs.cpp index ef0f73b94f..ca377b5611 100644 --- a/firmware/hw_layer/adc/adc_inputs.cpp +++ b/firmware/hw_layer/adc/adc_inputs.cpp @@ -42,6 +42,16 @@ #define ADC_BUF_DEPTH_SLOW 8 #define ADC_BUF_DEPTH_FAST 4 +// on F7 this must be aligned on a 32-byte boundary, and be a multiple of 32 bytes long. +// When we invalidate the cache line(s) for ADC samples, we don't want to nuke any +// adjacent data. +// F4 does not care +static __ALIGNED(32) adcsample_t slowAdcSampleBuf[ADC_BUF_DEPTH_SLOW * ADC_MAX_CHANNELS_COUNT]; +static __ALIGNED(32) adcsample_t fastAdcSampleBuf[ADC_BUF_DEPTH_FAST * ADC_MAX_CHANNELS_COUNT]; + +static_assert(sizeof(slowAdcSampleBuf) % 32 == 0, "Slow ADC sample buffer size must be a multiple of 32 bytes"); +static_assert(sizeof(fastAdcSampleBuf) % 32 == 0, "Fast ADC sample buffer size must be a multiple of 32 bytes"); + static adc_channel_mode_e adcHwChannelEnabled[HW_MAX_ADC_INDEX]; EXTERN_ENGINE; @@ -56,8 +66,9 @@ float getVoltage(const char *msg, adc_channel_e hwChannel DECLARE_ENGINE_PARAMET return adcToVolts(getAdcValue(msg, hwChannel)); } -AdcDevice::AdcDevice(ADCConversionGroup* hwConfig) { +AdcDevice::AdcDevice(ADCConversionGroup* hwConfig, adcsample_t *buf) { this->hwConfig = hwConfig; + this->samples = buf; channelCount = 0; conversionCount = 0; errorsCount = 0; @@ -65,7 +76,7 @@ AdcDevice::AdcDevice(ADCConversionGroup* hwConfig) { hwConfig->sqr1 = 0; hwConfig->sqr2 = 0; hwConfig->sqr3 = 0; - memset(hardwareIndexByIndernalAdcIndex, 0, sizeof(hardwareIndexByIndernalAdcIndex)); + memset(hardwareIndexByIndernalAdcIndex, EFI_ADC_NONE, sizeof(hardwareIndexByIndernalAdcIndex)); memset(internalAdcIndexByHardwareIndex, 0xFFFFFFFF, sizeof(internalAdcIndexByHardwareIndex)); } @@ -156,11 +167,11 @@ static ADCConversionGroup adcgrpcfgSlow = { .sqr3 = 0 // Conversion group sequence 1...6 }; -AdcDevice slowAdc(&adcgrpcfgSlow); +AdcDevice slowAdc(&adcgrpcfgSlow, slowAdcSampleBuf); void adc_callback_fast(ADCDriver *adcp, adcsample_t *buffer, size_t n); -static ADCConversionGroup adcgrpcfg_fast = { +static ADCConversionGroup adcgrpcfgFast = { .circular = FALSE, .num_channels = 0, .end_cb = adc_callback_fast, @@ -200,7 +211,7 @@ static ADCConversionGroup adcgrpcfg_fast = { .sqr3 = 0 // Conversion group sequence 1...6 }; -AdcDevice fastAdc(&adcgrpcfg_fast); +AdcDevice fastAdc(&adcgrpcfgFast, fastAdcSampleBuf); #if HAL_USE_GPT static void fast_adc_callback(GPTDriver*) { @@ -222,7 +233,7 @@ static void fast_adc_callback(GPTDriver*) { return; } - adcStartConversionI(&ADC_FAST_DEVICE, &adcgrpcfg_fast, fastAdc.samples, ADC_BUF_DEPTH_FAST); + adcStartConversionI(&ADC_FAST_DEVICE, &adcgrpcfgFast, fastAdc.samples, ADC_BUF_DEPTH_FAST); chSysUnlockFromISR() ; fastAdc.conversionCount++; @@ -278,14 +289,14 @@ static GPTConfig fast_adc_config = { }; #endif /* HAL_USE_GPT */ -const char * getAdcMode(adc_channel_e hwChannel) { +adc_channel_mode_e getAdcMode(adc_channel_e hwChannel) { if (slowAdc.isHwUsed(hwChannel)) { - return "slow"; + return ADC_SLOW; } if (fastAdc.isHwUsed(hwChannel)) { - return "fast"; + return ADC_FAST; } - return "INACTIVE - need restart"; + return ADC_OFF; } int AdcDevice::size() const { @@ -314,7 +325,8 @@ void AdcDevice::invalidateSamplesCache() { void AdcDevice::init(void) { hwConfig->num_channels = size(); - hwConfig->sqr1 += ADC_SQR1_NUM_CH(size()); + /* driver does this internally */ + //hwConfig->sqr1 += ADC_SQR1_NUM_CH(size()); } bool AdcDevice::isHwUsed(adc_channel_e hwChannelIndex) const { @@ -363,6 +375,26 @@ adc_channel_e AdcDevice::getAdcHardwareIndexByInternalIndex(int index) const { static void printFullAdcReport(Logging *logger) { scheduleMsg(logger, "fast %d slow %d", fastAdc.conversionCount, slowAdc.conversionCount); + for (int index = 0; index < fastAdc.size(); index++) { + appendMsgPrefix(logger); + + adc_channel_e hwIndex = fastAdc.getAdcHardwareIndexByInternalIndex(index); + + if (hwIndex != EFI_ADC_NONE && hwIndex != EFI_ADC_ERROR) { + ioportid_t port = getAdcChannelPort("print", hwIndex); + int pin = getAdcChannelPin(hwIndex); + + int adcValue = getAvgAdcValue(hwIndex, fastAdc.samples, ADC_BUF_DEPTH_FAST, fastAdc.size()); + appendPrintf(logger, " F ch%d %s%d", index, portname(port), pin); + appendPrintf(logger, " ADC%d 12bit=%d", hwIndex, adcValue); + float volts = adcToVolts(adcValue); + appendPrintf(logger, " v=%.2f", volts); + + appendMsgPostfix(logger); + scheduleLogging(logger); + } + } + for (int index = 0; index < slowAdc.size(); index++) { appendMsgPrefix(logger); @@ -373,7 +405,7 @@ static void printFullAdcReport(Logging *logger) { int pin = getAdcChannelPin(hwIndex); int adcValue = slowAdc.getAdcValueByIndex(index); - appendPrintf(logger, " ch%d %s%d", index, portname(port), pin); + appendPrintf(logger, " S ch%d %s%d", index, portname(port), pin); appendPrintf(logger, " ADC%d 12bit=%d", hwIndex, adcValue); float volts = adcToVolts(adcValue); appendPrintf(logger, " v=%.2f", volts); @@ -550,6 +582,19 @@ void initAdcInputs() { adcStart(&ADC_FAST_DEVICE, NULL); adcSTM32EnableTSVREFE(); // Internal temperature sensor + /* Enable this code only when you absolutly sure + * that there is no possible errors from ADC */ +#if 0 + /* All ADC use DMA and DMA calls end_cb from its IRQ + * If none of ADC users need error callback - we can disable + * shared ADC IRQ and save some CPU ticks */ + if ((adcgrpcfgSlow.error_cb == NULL) && + (adcgrpcfgFast.error_cb == NULL) + /* TODO: Add ADC3? */) { + nvicDisableVector(STM32_ADC_NUMBER); + } +#endif + #if defined(ADC_CHANNEL_SENSOR) // Internal temperature sensor, Available on ADC1 only slowAdc.enableChannel((adc_channel_e)ADC_CHANNEL_SENSOR); diff --git a/firmware/hw_layer/adc/adc_inputs.h b/firmware/hw_layer/adc/adc_inputs.h index 8c0394a703..c7d4b9d6ab 100644 --- a/firmware/hw_layer/adc/adc_inputs.h +++ b/firmware/hw_layer/adc/adc_inputs.h @@ -15,7 +15,7 @@ #if HAL_USE_ADC -const char * getAdcMode(adc_channel_e hwChannel); +adc_channel_mode_e getAdcMode(adc_channel_e hwChannel); void initAdcInputs(); // deprecated - migrate to 'getAdcChannelBrainPin'