adc EOS IRQ speedup with a lookup array, achievable up to 100kHz with short capture window

remotes/github/master
Ondřej Hruška 7 years ago
parent c0846f0bb7
commit 02b0ceb139
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 65
      units/adc/_adc_core.c
  2. 1
      units/adc/_adc_init.c
  3. 2
      units/adc/_adc_internal.h
  4. 1
      units/adc/unit_adc.c

@ -327,30 +327,41 @@ void UADC_DMA_Handler(void *arg)
*/ */
void UADC_ADC_EOS_Handler(void *arg) void UADC_ADC_EOS_Handler(void *arg)
{ {
// GPIOC->BSRR = 0x01;
Unit *unit = arg; Unit *unit = arg;
struct priv *priv = unit->data; struct priv *priv = unit->data;
const bool can_average = priv->cfg.enable_averaging &&
priv->real_frequency_int < UADC_MAX_FREQ_FOR_AVERAGING;
// Normally // Normally
uint64_t timestamp = 0; uint64_t timestamp = 0;
if (priv->opmode == ADC_OPMODE_ARMED) timestamp = PTIM_GetMicrotime(); if (priv->opmode == ADC_OPMODE_ARMED) {
timestamp = PTIM_GetMicrotime();
}
LL_ADC_ClearFlag_EOS(priv->ADCx); LL_ADC_ClearFlag_EOS(priv->ADCx);
if (priv->opmode == ADC_OPMODE_UNINIT) { if (priv->opmode == ADC_OPMODE_UNINIT) {
goto exit; goto exit;
} }
// GPIOC->BSRR = 0x02;
// Wait for the DMA to complete copying the last sample
uint32_t dmapos = DMA_POS(priv); uint32_t dmapos = DMA_POS(priv);
// Wait for the DMA to complete copying the last sample
// XXX
// experiments revealed this was actually a bug somewhere else and DMA
// is quick enough so we don't have to worry about this
#if 0
uint32_t err = (dmapos % priv->nb_channels); uint32_t err = (dmapos % priv->nb_channels);
if (err != 0) { if (err != 0) {
GPIOC->BSRR = 0x02; GPIOC->BSRR = 0x02;
hw_wait_while(((dmapos = DMA_POS(priv)) % priv->nb_channels) != 0, 10); hw_wait_while(((dmapos = DMA_POS(priv)) % priv->nb_channels) != 0, 10);
GPIOC->BRR = 0x02; GPIOC->BRR = 0x02;
} }
// GPIOC->BRR = 0x02; #endif
// wrap dmapos to be past the last sample, even if outside the buffer
// - so we can subtract nb_channels
uint32_t sample_pos; uint32_t sample_pos;
if (dmapos == 0) { if (dmapos == 0) {
sample_pos = (uint32_t) (priv->buf_itemcount); sample_pos = (uint32_t) (priv->buf_itemcount);
@ -359,21 +370,26 @@ void UADC_ADC_EOS_Handler(void *arg)
} }
sample_pos -= priv->nb_channels; sample_pos -= priv->nb_channels;
uint8_t cnt = 0; // index of the sample within the group
const bool can_average = priv->cfg.enable_averaging && priv->real_frequency_int < UADC_MAX_FREQ_FOR_AVERAGING;
const uint32_t channels_mask = priv->channels_mask;
uint16_t val; uint16_t val;
// TODO change this to a pre-computed byte array traversal // TODO change this to a pre-computed byte array traversal
#if 1
for (uint32_t j = 0; j < priv->nb_channels; j++) {
const uint8_t i = priv->channel_nums[j];
val = priv->dma_buffer[sample_pos+j];
if (can_average) {
priv->averaging_bins[i] =
priv->averaging_bins[i] * (1.0f - priv->avg_factor_as_float) +
((float) val) * priv->avg_factor_as_float;
}
priv->last_samples[i] = val;
}
#else
for (uint8_t i = 0; i < 18; i++) { for (uint8_t i = 0; i < 18; i++) {
if (channels_mask & (1 << i)) { if (channels_mask & (1 << i)) {
// if (cnt == priv->nb_channels-1) {
// val = last_sample; // DMA may not have finished copying it yet
// } else {
val = priv->dma_buffer[sample_pos+cnt]; val = priv->dma_buffer[sample_pos+cnt];
// }
cnt++; cnt++;
@ -386,23 +402,30 @@ void UADC_ADC_EOS_Handler(void *arg)
priv->last_samples[i] = val; priv->last_samples[i] = val;
} }
} }
#endif
switch (priv->opmode) {
// Triggering condition test // Triggering condition test
if (priv->opmode == ADC_OPMODE_ARMED) { case ADC_OPMODE_ARMED:
val = priv->last_samples[priv->trigger_source]; val = priv->last_samples[priv->trigger_source];
if ((priv->trig_prev_level < priv->trig_level) && val >= priv->trig_level && (bool) (priv->trig_edge & 0b01)) { if ((priv->trig_prev_level < priv->trig_level) &&
val >= priv->trig_level &&
(bool) (priv->trig_edge & 0b01)) {
// Rising edge // Rising edge
UADC_HandleTrigger(unit, 0b01, timestamp); UADC_HandleTrigger(unit, 0b01, timestamp);
} }
else if ((priv->trig_prev_level > priv->trig_level) && val <= priv->trig_level && (bool) (priv->trig_edge & 0b10)) { else if ((priv->trig_prev_level > priv->trig_level) &&
val <= priv->trig_level &&
(bool) (priv->trig_edge & 0b10)) {
// Falling edge // Falling edge
UADC_HandleTrigger(unit, 0b10, timestamp); UADC_HandleTrigger(unit, 0b10, timestamp);
} }
priv->trig_prev_level = val; priv->trig_prev_level = val;
} break;
// auto-rearm was waiting for the next sample // auto-rearm was waiting for the next sample
else if (priv->opmode == ADC_OPMODE_REARM_PENDING) { case ADC_OPMODE_REARM_PENDING:
if (!priv->auto_rearm) { if (!priv->auto_rearm) {
// It looks like the flag was cleared by DISARM before we got a new sample. // It looks like the flag was cleared by DISARM before we got a new sample.
// Let's just switch to IDLE // Let's just switch to IDLE
@ -411,10 +434,12 @@ void UADC_ADC_EOS_Handler(void *arg)
// Re-arming for a new trigger // Re-arming for a new trigger
UADC_SwitchMode(unit, ADC_OPMODE_ARMED); UADC_SwitchMode(unit, ADC_OPMODE_ARMED);
} }
default:
break;
} }
exit: exit:
// GPIOC->BRR = 0x01;
return; return;
} }

@ -122,6 +122,7 @@ error_t UADC_init(Unit *unit)
priv->nb_channels = 0; priv->nb_channels = 0;
for (uint8_t i = 0; i <= UADC_MAX_CHANNEL; i++) { for (uint8_t i = 0; i <= UADC_MAX_CHANNEL; i++) {
if (priv->cfg.channels & (1UL << i)) { if (priv->cfg.channels & (1UL << i)) {
priv->channel_nums[priv->nb_channels] = (uint8_t) i;
priv->nb_channels++; priv->nb_channels++;
do { do {

@ -57,6 +57,8 @@ struct priv {
uint8_t dma_chnum; //!< DMA channel number uint8_t dma_chnum; //!< DMA channel number
DMA_Channel_TypeDef *DMA_CHx; //!< DMA channel instance DMA_Channel_TypeDef *DMA_CHx; //!< DMA channel instance
uint8_t channel_nums[18];
// Live config // Live config
float real_frequency; float real_frequency;
uint32_t real_frequency_int; uint32_t real_frequency_int;

@ -140,6 +140,7 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
// count the enabled channels // count the enabled channels
for(int i = 0; i < 32; i++) { for(int i = 0; i < 32; i++) {
if (new_channels & (1<<i)) { if (new_channels & (1<<i)) {
priv->channel_nums[nb_channels] = (uint8_t) i;
nb_channels++; nb_channels++;
} }
} }

Loading…
Cancel
Save