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?
// https://github.com/rusefi/rusefi/issues/630
#define EFI_INTERNAL_SLOW_ADC_PWM &PWMD1
// todo: switch to continues ADC conversion for fast ADC?
#define EFI_INTERNAL_FAST_ADC_PWM &PWMD2

View File

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

View File

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

View File

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

View File

@ -277,7 +277,7 @@
#define STM32_PWM_USE_TIM4 TRUE
#define STM32_PWM_USE_TIM5 FALSE
// 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_TIM1_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_TIM4 TRUE
#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_TIM1_IRQ_PRIORITY 7
#define STM32_PWM_TIM2_IRQ_PRIORITY 7

View File

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

View File

@ -37,7 +37,7 @@ public:
// 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 alignment");
static_assert(sizeof(samples) % 32 == 0, "ADC sample buffer size must be a multiple of 32 bytes");
int getAdcValueByHwChannel(int hwChannel) const;

View File

@ -30,6 +30,7 @@
#include "adc_subscription.h"
#include "AdcConfiguration.h"
#include "mpu_util.h"
#include "periodic_thread_controller.h"
#include "pin_repository.h"
#include "engine_math.h"
@ -71,14 +72,6 @@ AdcDevice::AdcDevice(ADCConversionGroup* hwConfig) {
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)
/**
* 8000 RPM is 133Hz
@ -109,15 +102,16 @@ static int adcDebugReporting = false;
EXTERN_ENGINE;
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++) {
result += samples[index];
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
#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.
*/
static ADCConversionGroup adcgrpcfgSlow = { FALSE, 0, adc_callback_slow, NULL,
static ADCConversionGroup adcgrpcfgSlow = { FALSE, 0, nullptr, NULL,
/* HW dependent part.*/
ADC_TwoSamplingDelay_20Cycles, // cr1
ADC_CR2_SWSTART, // cr2
@ -207,39 +201,7 @@ ADC_TwoSamplingDelay_5Cycles, // cr1
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
static void pwmpcb_slow(PWMDriver *pwmp) {
(void) pwmp;
doSlowAdc();
}
static void pwmpcb_fast(PWMDriver *pwmp) {
efiAssertVoid(CUSTOM_ERR_6659, getCurrentRemainingStack()> 32, "lwStAdcFast");
@ -311,12 +273,6 @@ int getInternalAdcValue(const char *msg, adc_channel_e hwChannel) {
}
#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, { {
PWM_OUTPUT_DISABLED, NULL }, { PWM_OUTPUT_DISABLED, NULL }, {
PWM_OUTPUT_DISABLED, NULL }, { PWM_OUTPUT_DISABLED, NULL } },
@ -457,33 +413,48 @@ int getSlowAdcCounter() {
return slowAdcCounter;
}
static void adc_callback_slow(ADCDriver *adcp, adcsample_t *buffer, size_t n) {
(void) buffer;
(void) n;
ScopePerf perf(PE::AdcCallbackSlow);
/* Note, only in the ADC_COMPLETE state because the ADC driver fires
* an intermediate callback when the buffer is half full. */
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();
class SlowAdcController : public PeriodicController<256> {
public:
SlowAdcController()
: PeriodicController("ADC", NORMALPRIO + 5, 200)
{
}
}
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];
@ -567,6 +538,8 @@ static void configureInputs(void) {
setAdcChannelOverrides();
}
static SlowAdcController slowAdcController;
void initAdcInputs() {
printMsg(&logger, "initAdcInputs()");
if (ADC_BUF_DEPTH_FAST > MAX_ADC_GRP_BUF_DEPTH)
@ -606,10 +579,9 @@ void initAdcInputs() {
#endif /* ADC_CHANNEL_SENSOR */
slowAdc.init();
#if HAL_USE_PWM
pwmStart(EFI_INTERNAL_SLOW_ADC_PWM, &pwmcfg_slow);
pwmEnablePeriodicNotification(EFI_INTERNAL_SLOW_ADC_PWM);
#endif /* HAL_USE_PWM */
// Start the slow ADC thread
slowAdcController.Start();
if (CONFIGB(isFastAdcEnabled)) {
fastAdc.init();