Move slow ADC to thread #630 (#1042)

* adc with thread

* enable

* check result

* stacktual embiggenment

* tracing

* let's be type safe

* improve assert

* format, comment

* remove EFI_INTERNAL_SLOW_ADC_PWM fully
This commit is contained in:
Matthew Kennedy 2019-12-11 06:28:11 -08:00 committed by rusefi
parent a44a0cad99
commit 37473bd26e
9 changed files with 56 additions and 87 deletions

View File

@ -264,7 +264,6 @@
// todo: switch to continues ADC conversion for slow ADC? // todo: switch to continues ADC conversion for slow ADC?
// https://github.com/rusefi/rusefi/issues/630 // https://github.com/rusefi/rusefi/issues/630
#define EFI_INTERNAL_SLOW_ADC_PWM &PWMD1
// todo: switch to continues ADC conversion for fast ADC? // todo: switch to continues ADC conversion for fast ADC?
#define EFI_INTERNAL_FAST_ADC_PWM &PWMD2 #define EFI_INTERNAL_FAST_ADC_PWM &PWMD2

View File

@ -267,7 +267,6 @@
// todo: switch to continuous ADC conversion for slow ADC? // todo: switch to continuous ADC conversion for slow ADC?
// https://github.com/rusefi/rusefi/issues/630 // https://github.com/rusefi/rusefi/issues/630
#define EFI_INTERNAL_SLOW_ADC_PWM &PWMD8
// todo: switch to continues ADC conversion for fast ADC? // todo: switch to continues ADC conversion for fast ADC?
#define EFI_INTERNAL_FAST_ADC_PWM &PWMD4 #define EFI_INTERNAL_FAST_ADC_PWM &PWMD4

View File

@ -293,7 +293,6 @@
// todo: switch to continues ADC conversion for slow ADC? // todo: switch to continues ADC conversion for slow ADC?
// https://github.com/rusefi/rusefi/issues/630 // https://github.com/rusefi/rusefi/issues/630
#define EFI_INTERNAL_SLOW_ADC_PWM &PWMD8
// todo: switch to continues ADC conversion for fast ADC? // todo: switch to continues ADC conversion for fast ADC?
#define EFI_INTERNAL_FAST_ADC_PWM &PWMD4 #define EFI_INTERNAL_FAST_ADC_PWM &PWMD4

View File

@ -201,7 +201,7 @@
* @note Disabling this option saves both code and data space. * @note Disabling this option saves both code and data space.
*/ */
#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) #if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define ADC_USE_MUTUAL_EXCLUSION TRUE #define ADC_USE_MUTUAL_EXCLUSION FALSE
#endif #endif
/*===========================================================================*/ /*===========================================================================*/

View File

@ -277,7 +277,7 @@
#define STM32_PWM_USE_TIM4 TRUE #define STM32_PWM_USE_TIM4 TRUE
#define STM32_PWM_USE_TIM5 FALSE #define STM32_PWM_USE_TIM5 FALSE
// todo: https://github.com/rusefi/rusefi/issues/630 ? // todo: https://github.com/rusefi/rusefi/issues/630 ?
#define STM32_PWM_USE_TIM8 TRUE #define STM32_PWM_USE_TIM8 FALSE
#define STM32_PWM_USE_TIM9 FALSE #define STM32_PWM_USE_TIM9 FALSE
#define STM32_PWM_TIM1_IRQ_PRIORITY 7 #define STM32_PWM_TIM1_IRQ_PRIORITY 7
#define STM32_PWM_TIM2_IRQ_PRIORITY 7 #define STM32_PWM_TIM2_IRQ_PRIORITY 7

View File

@ -285,7 +285,7 @@
#define STM32_PWM_USE_TIM3 FALSE #define STM32_PWM_USE_TIM3 FALSE
#define STM32_PWM_USE_TIM4 TRUE #define STM32_PWM_USE_TIM4 TRUE
#define STM32_PWM_USE_TIM5 FALSE #define STM32_PWM_USE_TIM5 FALSE
#define STM32_PWM_USE_TIM8 TRUE #define STM32_PWM_USE_TIM8 FALSE
#define STM32_PWM_USE_TIM9 FALSE #define STM32_PWM_USE_TIM9 FALSE
#define STM32_PWM_TIM1_IRQ_PRIORITY 7 #define STM32_PWM_TIM1_IRQ_PRIORITY 7
#define STM32_PWM_TIM2_IRQ_PRIORITY 7 #define STM32_PWM_TIM2_IRQ_PRIORITY 7

View File

@ -30,7 +30,7 @@ enum class PE : uint8_t {
PeriodicControllerPeriodicTask, PeriodicControllerPeriodicTask,
PeriodicTimerControllerPeriodicTask, PeriodicTimerControllerPeriodicTask,
AdcCallbackFast, AdcCallbackFast,
AdcCallbackSlow, AdcProcessSlow,
AdcConversionSlow, AdcConversionSlow,
AdcConversionFast, AdcConversionFast,
AdcSubscriptionUpdateSubscribers, AdcSubscriptionUpdateSubscribers,

View File

@ -37,7 +37,7 @@ public:
// F4 does not care // F4 does not care
__ALIGNED(32) adcsample_t samples[ADC_MAX_CHANNELS_COUNT * MAX_ADC_GRP_BUF_DEPTH]; __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 // 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 alignment"); static_assert(sizeof(samples) % 32 == 0, "ADC sample buffer size must be a multiple of 32 bytes");
int getAdcValueByHwChannel(int hwChannel) const; int getAdcValueByHwChannel(int hwChannel) const;

View File

@ -30,6 +30,7 @@
#include "adc_subscription.h" #include "adc_subscription.h"
#include "AdcConfiguration.h" #include "AdcConfiguration.h"
#include "mpu_util.h" #include "mpu_util.h"
#include "periodic_thread_controller.h"
#include "pin_repository.h" #include "pin_repository.h"
#include "engine_math.h" #include "engine_math.h"
@ -71,14 +72,6 @@ AdcDevice::AdcDevice(ADCConversionGroup* hwConfig) {
memset(internalAdcIndexByHardwareIndex, 0xFFFFFFFF, sizeof(internalAdcIndexByHardwareIndex)); memset(internalAdcIndexByHardwareIndex, 0xFFFFFFFF, sizeof(internalAdcIndexByHardwareIndex));
} }
#if !defined(PWM_FREQ_SLOW) || !defined(PWM_PERIOD_SLOW)
// todo: migrate from hardware timer to software ADC conversion triggering
// todo: I guess we would have to use ChibiOS timer and not our own timer because
// todo: adcStartConversionI requires OS lock. currently slow ADC is 20Hz
#define PWM_FREQ_SLOW 5000 /* PWM clock frequency. I wonder what does this setting mean? */
#define PWM_PERIOD_SLOW 25 /* PWM period (in PWM ticks). */
#endif /* PWM_FREQ_SLOW PWM_PERIOD_SLOW */
#if !defined(PWM_FREQ_FAST) || !defined(PWM_PERIOD_FAST) #if !defined(PWM_FREQ_FAST) || !defined(PWM_PERIOD_FAST)
/** /**
* 8000 RPM is 133Hz * 8000 RPM is 133Hz
@ -109,15 +102,16 @@ static int adcDebugReporting = false;
EXTERN_ENGINE; EXTERN_ENGINE;
static adcsample_t getAvgAdcValue(int index, adcsample_t *samples, int bufDepth, int numChannels) { static adcsample_t getAvgAdcValue(int index, adcsample_t *samples, int bufDepth, int numChannels) {
adcsample_t result = 0; uint32_t result = 0;
for (int i = 0; i < bufDepth; i++) { for (int i = 0; i < bufDepth; i++) {
result += samples[index]; result += samples[index];
index += numChannels; index += numChannels;
} }
return result / bufDepth;
// this truncation is guaranteed to not be lossy - the average can't be larger than adcsample_t
return static_cast<adcsample_t>(result / bufDepth);
} }
static void adc_callback_slow(ADCDriver *adcp, adcsample_t *buffer, size_t n);
// See https://github.com/rusefi/rusefi/issues/976 for discussion on these values // See https://github.com/rusefi/rusefi/issues/976 for discussion on these values
#define ADC_SAMPLING_SLOW ADC_SAMPLE_56 #define ADC_SAMPLING_SLOW ADC_SAMPLE_56
@ -125,7 +119,7 @@ static void adc_callback_slow(ADCDriver *adcp, adcsample_t *buffer, size_t n);
/* /*
* ADC conversion group. * ADC conversion group.
*/ */
static ADCConversionGroup adcgrpcfgSlow = { FALSE, 0, adc_callback_slow, NULL, static ADCConversionGroup adcgrpcfgSlow = { FALSE, 0, nullptr, NULL,
/* HW dependent part.*/ /* HW dependent part.*/
ADC_TwoSamplingDelay_20Cycles, // cr1 ADC_TwoSamplingDelay_20Cycles, // cr1
ADC_CR2_SWSTART, // cr2 ADC_CR2_SWSTART, // cr2
@ -207,39 +201,7 @@ ADC_TwoSamplingDelay_5Cycles, // cr1
AdcDevice fastAdc(&adcgrpcfg_fast); AdcDevice fastAdc(&adcgrpcfg_fast);
void doSlowAdc(void) {
efiAssertVoid(CUSTOM_ERR_6658, getCurrentRemainingStack()> 32, "lwStAdcSlow");
#if EFI_INTERNAL_ADC
/* Starts an asynchronous ADC conversion operation, the conversion
will be executed in parallel to the current PWM cycle and will
terminate before the next PWM cycle.*/
slowAdc.conversionCount++;
chSysLockFromISR()
;
if (ADC_SLOW_DEVICE.state != ADC_READY &&
ADC_SLOW_DEVICE.state != ADC_COMPLETE &&
ADC_SLOW_DEVICE.state != ADC_ERROR) {
// todo: why and when does this happen? firmwareError(OBD_PCM_Processor_Fault, "ADC slow not ready?");
slowAdc.errorsCount++;
chSysUnlockFromISR()
;
return;
}
adcStartConversionI(&ADC_SLOW_DEVICE, &adcgrpcfgSlow, slowAdc.samples, ADC_BUF_DEPTH_SLOW);
chSysUnlockFromISR()
;
#endif /* EFI_INTERNAL_ADC */
}
#if HAL_USE_PWM #if HAL_USE_PWM
static void pwmpcb_slow(PWMDriver *pwmp) {
(void) pwmp;
doSlowAdc();
}
static void pwmpcb_fast(PWMDriver *pwmp) { static void pwmpcb_fast(PWMDriver *pwmp) {
efiAssertVoid(CUSTOM_ERR_6659, getCurrentRemainingStack()> 32, "lwStAdcFast"); efiAssertVoid(CUSTOM_ERR_6659, getCurrentRemainingStack()> 32, "lwStAdcFast");
@ -311,12 +273,6 @@ int getInternalAdcValue(const char *msg, adc_channel_e hwChannel) {
} }
#if HAL_USE_PWM #if HAL_USE_PWM
static PWMConfig pwmcfg_slow = { PWM_FREQ_SLOW, PWM_PERIOD_SLOW, pwmpcb_slow, { {
PWM_OUTPUT_DISABLED, NULL }, { PWM_OUTPUT_DISABLED, NULL }, {
PWM_OUTPUT_DISABLED, NULL }, { PWM_OUTPUT_DISABLED, NULL } },
/* HW dependent part.*/
0, 0 };
static PWMConfig pwmcfg_fast = { PWM_FREQ_FAST, PWM_PERIOD_FAST, pwmpcb_fast, { { static PWMConfig pwmcfg_fast = { PWM_FREQ_FAST, PWM_PERIOD_FAST, pwmpcb_fast, { {
PWM_OUTPUT_DISABLED, NULL }, { PWM_OUTPUT_DISABLED, NULL }, { PWM_OUTPUT_DISABLED, NULL }, { PWM_OUTPUT_DISABLED, NULL }, {
PWM_OUTPUT_DISABLED, NULL }, { PWM_OUTPUT_DISABLED, NULL } }, PWM_OUTPUT_DISABLED, NULL }, { PWM_OUTPUT_DISABLED, NULL } },
@ -457,33 +413,48 @@ int getSlowAdcCounter() {
return slowAdcCounter; return slowAdcCounter;
} }
static void adc_callback_slow(ADCDriver *adcp, adcsample_t *buffer, size_t n) {
(void) buffer;
(void) n;
ScopePerf perf(PE::AdcCallbackSlow); class SlowAdcController : public PeriodicController<256> {
public:
/* Note, only in the ADC_COMPLETE state because the ADC driver fires SlowAdcController()
* an intermediate callback when the buffer is half full. */ : PeriodicController("ADC", NORMALPRIO + 5, 200)
if (adcp->state == ADC_COMPLETE) { {
slowAdc.invalidateSamplesCache();
efiAssertVoid(CUSTOM_STACK_ADC_6671, getCurrentRemainingStack() > 128, "lowstck#9c");
/* Calculates the average values from the ADC samples.*/
for (int i = 0; i < slowAdc.size(); i++) {
int value = getAvgAdcValue(i, slowAdc.samples, ADC_BUF_DEPTH_SLOW, slowAdc.size());
adcsample_t prev = slowAdc.values.adc_data[i];
float result = (slowAdcCounter == 0) ? value :
CONFIG(slowAdcAlpha) * value + (1 - CONFIG(slowAdcAlpha)) * prev;
slowAdc.values.adc_data[i] = (int)result;
}
slowAdcCounter++;
AdcSubscription::UpdateSubscribers();
} }
}
void PeriodicTask(efitime_t nowNt) override {
{
ScopePerf perf(PE::AdcConversionSlow);
slowAdc.conversionCount++;
msg_t result = adcConvert(&ADC_SLOW_DEVICE, &adcgrpcfgSlow, slowAdc.samples, ADC_BUF_DEPTH_SLOW);
// If something went wrong - try again later
if (result == MSG_RESET || result == MSG_TIMEOUT) {
slowAdc.errorsCount++;
return;
}
}
{
ScopePerf perf(PE::AdcProcessSlow);
slowAdc.invalidateSamplesCache();
/* Calculates the average values from the ADC samples.*/
for (int i = 0; i < slowAdc.size(); i++) {
adcsample_t value = getAvgAdcValue(i, slowAdc.samples, ADC_BUF_DEPTH_SLOW, slowAdc.size());
adcsample_t prev = slowAdc.values.adc_data[i];
float result = (slowAdcCounter == 0) ? value :
CONFIG(slowAdcAlpha) * value + (1 - CONFIG(slowAdcAlpha)) * prev;
slowAdc.values.adc_data[i] = (adcsample_t)result;
}
slowAdcCounter++;
AdcSubscription::UpdateSubscribers();
}
}
};
static char errorMsgBuff[_MAX_FILLER + 2]; static char errorMsgBuff[_MAX_FILLER + 2];
@ -567,6 +538,8 @@ static void configureInputs(void) {
setAdcChannelOverrides(); setAdcChannelOverrides();
} }
static SlowAdcController slowAdcController;
void initAdcInputs() { void initAdcInputs() {
printMsg(&logger, "initAdcInputs()"); printMsg(&logger, "initAdcInputs()");
if (ADC_BUF_DEPTH_FAST > MAX_ADC_GRP_BUF_DEPTH) if (ADC_BUF_DEPTH_FAST > MAX_ADC_GRP_BUF_DEPTH)
@ -606,10 +579,9 @@ void initAdcInputs() {
#endif /* ADC_CHANNEL_SENSOR */ #endif /* ADC_CHANNEL_SENSOR */
slowAdc.init(); slowAdc.init();
#if HAL_USE_PWM
pwmStart(EFI_INTERNAL_SLOW_ADC_PWM, &pwmcfg_slow); // Start the slow ADC thread
pwmEnablePeriodicNotification(EFI_INTERNAL_SLOW_ADC_PWM); slowAdcController.Start();
#endif /* HAL_USE_PWM */
if (CONFIGB(isFastAdcEnabled)) { if (CONFIGB(isFastAdcEnabled)) {
fastAdc.init(); fastAdc.init();