1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-12-01 09:24:10 +01:00

OP-1227 Fix high CPU usage: Optimize Memory usage in ADC driver.

- performs undersampling in two steps operating with a half buffer at time;
- Skip costly undersampling for Temperature channel;
- some optimizations to the downsample loops;
- apply compiler speed optimization to PIOS_ADC_downsample_data()
This commit is contained in:
Alessio Morale 2014-06-08 22:01:05 +02:00
parent 843987484b
commit a9f1d55fea
2 changed files with 39 additions and 9 deletions

View File

@ -32,7 +32,7 @@
#define PIOS_ADC_H
// Maximum of 50 oversampled points
#define PIOS_ADC_MAX_SAMPLES ((((PIOS_ADC_NUM_CHANNELS + PIOS_ADC_USE_ADC2) >> PIOS_ADC_USE_ADC2) << PIOS_ADC_USE_ADC2) * PIOS_ADC_MAX_OVERSAMPLING * 2)
#define PIOS_ADC_MAX_SAMPLES ((((PIOS_ADC_NUM_CHANNELS + PIOS_ADC_USE_ADC2) >> PIOS_ADC_USE_ADC2) << PIOS_ADC_USE_ADC2) * PIOS_ADC_MAX_OVERSAMPLING * 2 / 2)
typedef void (*ADCCallback)(float *data);

View File

@ -32,7 +32,6 @@
#ifdef PIOS_INCLUDE_ADC
#include <pios_adc_priv.h>
// Private types
enum pios_adc_dev_magic {
@ -53,6 +52,7 @@ struct pios_adc_dev {
int16_t fir_coeffs[PIOS_ADC_MAX_SAMPLES + 1] __attribute__((aligned(4)));
volatile int16_t raw_data_buffer[PIOS_ADC_MAX_SAMPLES] __attribute__((aligned(4))); // Double buffer that DMA just used
float downsampled_buffer[PIOS_ADC_NUM_CHANNELS] __attribute__((aligned(4)));
uint8_t downsampleStep; // allows to reduce the downsampling buffer by operating in two steps
#endif
enum pios_adc_dev_magic magic;
};
@ -135,7 +135,6 @@ int32_t PIOS_ADC_Init(const struct pios_adc_cfg *cfg)
}
PIOS_ADC_Config(PIOS_ADC_MAX_OVERSAMPLING);
return 0;
}
@ -219,7 +218,7 @@ void PIOS_ADC_Config(uint32_t oversampling)
/* This makes sure we have an even number of transfers if using ADC2 */
pios_adc_dev->dma_block_size = ((PIOS_ADC_NUM_CHANNELS + PIOS_ADC_USE_ADC2) >> PIOS_ADC_USE_ADC2) << PIOS_ADC_USE_ADC2;
pios_adc_dev->dma_half_buffer_size = pios_adc_dev->dma_block_size * pios_adc_dev->adc_oversample;
pios_adc_dev->dma_half_buffer_size = pios_adc_dev->dma_block_size * pios_adc_dev->adc_oversample / 2;
/* Configure DMA channel */
DMA_InitTypeDef dma_init = pios_adc_dev->cfg->dma.rx.init;
@ -324,24 +323,55 @@ void PIOS_ADC_SetFIRCoefficients(float *new_filter)
}
}
/**
* @brief Downsample the data for each of the channels then call
* callback function if installed
*/
__attribute__((optimize("O3")))
void PIOS_ADC_downsample_data()
{
uint16_t chan;
uint16_t sample;
float *downsampled_buffer = &pios_adc_dev->downsampled_buffer[0];
static int32_t sum[PIOS_ADC_NUM_CHANNELS] = { 0 };
for (chan = 0; chan < PIOS_ADC_NUM_CHANNELS; chan++) {
int32_t sum = 0;
for (sample = 0; sample < pios_adc_dev->adc_oversample; sample++) {
sum += pios_adc_dev->valid_data_buffer[chan + sample * pios_adc_dev->dma_block_size] * pios_adc_dev->fir_coeffs[sample];
if (pios_adc_dev->downsampleStep == 0) {
for (uint8_t i = 0; i < PIOS_ADC_NUM_CHANNELS; i++) {
sum[i] = 0;
}
downsampled_buffer[chan] = (float)sum / pios_adc_dev->fir_coeffs[pios_adc_dev->adc_oversample];
}
for (sample = 0; sample < pios_adc_dev->adc_oversample / 2; sample++) {
const uint16_t *buffer = (const uint16_t *)&pios_adc_dev->valid_data_buffer[sample * pios_adc_dev->dma_block_size];
const uint16_t firCoeff = pios_adc_dev->fir_coeffs[sample + PIOS_ADC_NUM_CHANNELS * pios_adc_dev->downsampleStep];
#if (PIOS_ADC_USE_TEMP_SENSOR)
for (chan = 1; chan < PIOS_ADC_NUM_CHANNELS; chan++) {
#else
for (chan = 0; chan < PIOS_ADC_NUM_CHANNELS; chan++) {
#endif
sum[chan] += buffer[chan] * firCoeff;
}
}
// Full downsampling + fir filter is a little bit overwhelming for temp sensor.
if (pios_adc_dev->downsampleStep == 0) {
// first part of downsampling done. wait until the second block of samples is acquired
pios_adc_dev->downsampleStep = 1;
return;
}
pios_adc_dev->downsampleStep = 0;
#if (PIOS_ADC_USE_TEMP_SENSOR)
for (chan = 1; chan < PIOS_ADC_NUM_CHANNELS; chan++) {
#else
for (chan = 0; chan < PIOS_ADC_NUM_CHANNELS; chan++) {
#endif
downsampled_buffer[chan] = (float)sum[chan] / (pios_adc_dev->fir_coeffs[pios_adc_dev->adc_oversample]);
}
#if (PIOS_ADC_USE_TEMP_SENSOR)
downsampled_buffer[0] = pios_adc_dev->valid_data_buffer[0];
#endif
#if defined(PIOS_INCLUDE_FREERTOS)
if (pios_adc_dev->data_queue) {
static portBASE_TYPE xHigherPriorityTaskWoken;