Fix incorrect ADC channel counting with 16,17. Also make averaging toggleable.

This bug caused wrong measurements, DAC distortion and instability with 16+17
and at least 1 other channel.
remotes/github/master
Ondřej Hruška 6 years ago
parent 396501564a
commit c0846f0bb7
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 31
      units/adc/_adc_core.c
  2. 54
      units/adc/_adc_init.c
  3. 1
      units/adc/_adc_internal.h
  4. 13
      units/adc/_adc_settings.c
  5. 7
      units/adc/unit_adc.c

@ -327,8 +327,7 @@ void UADC_DMA_Handler(void *arg)
*/ */
void UADC_ADC_EOS_Handler(void *arg) void UADC_ADC_EOS_Handler(void *arg)
{ {
GPIOC->BSRR = 0x01;//TODO remove // GPIOC->BSRR = 0x01;
Unit *unit = arg; Unit *unit = arg;
struct priv *priv = unit->data; struct priv *priv = unit->data;
@ -341,11 +340,16 @@ void UADC_ADC_EOS_Handler(void *arg)
goto exit; goto exit;
} }
// GPIOC->BSRR = 0x02;
// Wait for the DMA to complete copying the last sample // Wait for the DMA to complete copying the last sample
uint32_t dmapos = DMA_POS(priv); uint32_t dmapos = DMA_POS(priv);
if ((DMA_POS(priv) % priv->nb_channels) != 0) { uint32_t err = (dmapos % priv->nb_channels);
hw_wait_while((dmapos = DMA_POS(priv)) % priv->nb_channels != 0, 100); // XXX this could be changed to reading it from the DR instead if (err != 0) {
GPIOC->BSRR = 0x02;
hw_wait_while(((dmapos = DMA_POS(priv)) % priv->nb_channels) != 0, 10);
GPIOC->BRR = 0x02;
} }
// GPIOC->BRR = 0x02;
uint32_t sample_pos; uint32_t sample_pos;
if (dmapos == 0) { if (dmapos == 0) {
@ -355,14 +359,22 @@ void UADC_ADC_EOS_Handler(void *arg)
} }
sample_pos -= priv->nb_channels; sample_pos -= priv->nb_channels;
int cnt = 0; // index of the sample within the group uint8_t cnt = 0; // index of the sample within the group
const bool can_average = priv->real_frequency_int < UADC_MAX_FREQ_FOR_AVERAGING; 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; const uint32_t channels_mask = priv->channels_mask;
uint16_t val;
// TODO change this to a pre-computed byte array traversal
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)) {
const uint16_t val = priv->dma_buffer[sample_pos+cnt]; // 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];
// }
cnt++; cnt++;
if (can_average) { if (can_average) {
@ -375,8 +387,9 @@ void UADC_ADC_EOS_Handler(void *arg)
} }
} }
// Triggering condition test
if (priv->opmode == ADC_OPMODE_ARMED) { if (priv->opmode == ADC_OPMODE_ARMED) {
const uint16_t 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
@ -401,7 +414,7 @@ void UADC_ADC_EOS_Handler(void *arg)
} }
exit: exit:
GPIOC->BRR = 0x01;//TODO remove // GPIOC->BRR = 0x01;
return; return;
} }

@ -21,6 +21,7 @@ error_t UADC_preInit(Unit *unit)
priv->cfg.frequency = 1000; priv->cfg.frequency = 1000;
priv->cfg.buffer_size = 256; // in half-words priv->cfg.buffer_size = 256; // in half-words
priv->cfg.averaging_factor = 500; // 0.5 priv->cfg.averaging_factor = 500; // 0.5
priv->cfg.enable_averaging = true;
priv->opmode = ADC_OPMODE_UNINIT; priv->opmode = ADC_OPMODE_UNINIT;
@ -120,33 +121,36 @@ error_t UADC_init(Unit *unit)
// Claim and configure all analog pins // Claim and configure all analog pins
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 & (1 << i)) { if (priv->cfg.channels & (1UL << i)) {
priv->nb_channels++; priv->nb_channels++;
char c; do {
uint8_t num; char c;
if (i <= 7) { uint8_t num;
c = 'A'; if (i <= 7) {
num = i; c = 'A';
} num = i;
else if (i <= 9) { }
c = 'B'; else if (i <= 9) {
num = (uint8_t) (i - 8); c = 'B';
} num = (uint8_t) (i - 8);
else if (i <= 15) { }
c = 'C'; else if (i <= 15) {
num = (uint8_t) (i - 10); c = 'C';
} else { num = (uint8_t) (i - 10);
break; }
} else {
break;
TRY(rsc_claim_pin(unit, c, num)); }
uint32_t ll_pin = hw_pin2ll(num, &suc);
GPIO_TypeDef *port = hw_port2periph(c, &suc); TRY(rsc_claim_pin(unit, c, num));
assert_param(suc); uint32_t ll_pin = hw_pin2ll(num, &suc);
GPIO_TypeDef *port = hw_port2periph(c, &suc);
LL_GPIO_SetPinPull(port, ll_pin, LL_GPIO_PULL_NO); assert_param(suc);
LL_GPIO_SetPinMode(port, ll_pin, LL_GPIO_MODE_ANALOG);
LL_GPIO_SetPinPull(port, ll_pin, LL_GPIO_PULL_NO);
LL_GPIO_SetPinMode(port, ll_pin, LL_GPIO_MODE_ANALOG);
} while (0);
} }
} }

@ -46,6 +46,7 @@ struct priv {
uint32_t frequency; //!< Timer frequency in Hz. Note: not all frequencies can be achieved accurately uint32_t frequency; //!< Timer frequency in Hz. Note: not all frequencies can be achieved accurately
uint32_t buffer_size; //!< Buffer size in bytes (count 2 bytes per channel per measurement) - faster sampling freq needs bigger buffer uint32_t buffer_size; //!< Buffer size in bytes (count 2 bytes per channel per measurement) - faster sampling freq needs bigger buffer
uint16_t averaging_factor; //!< Exponential averaging factor 0-1000 uint16_t averaging_factor; //!< Exponential averaging factor 0-1000
bool enable_averaging;
} cfg; } cfg;
// Peripherals // Peripherals

@ -23,6 +23,10 @@ void UADC_loadBinary(Unit *unit, PayloadParser *pp)
priv->cfg.frequency = pp_u32(pp); priv->cfg.frequency = pp_u32(pp);
priv->cfg.buffer_size = pp_u32(pp); priv->cfg.buffer_size = pp_u32(pp);
priv->cfg.averaging_factor = pp_u16(pp); priv->cfg.averaging_factor = pp_u16(pp);
if (version >= 1) {
priv->cfg.enable_averaging = pp_bool(pp);
}
} }
/** Write to a binary buffer for storing in Flash */ /** Write to a binary buffer for storing in Flash */
@ -30,13 +34,14 @@ void UADC_writeBinary(Unit *unit, PayloadBuilder *pb)
{ {
struct priv *priv = unit->data; struct priv *priv = unit->data;
pb_u8(pb, 0); // version pb_u8(pb, 1); // version
pb_u32(pb, priv->cfg.channels); pb_u32(pb, priv->cfg.channels);
pb_u8(pb, priv->cfg.sample_time); pb_u8(pb, priv->cfg.sample_time);
pb_u32(pb, priv->cfg.frequency); pb_u32(pb, priv->cfg.frequency);
pb_u32(pb, priv->cfg.buffer_size); pb_u32(pb, priv->cfg.buffer_size);
pb_u16(pb, priv->cfg.averaging_factor); pb_u16(pb, priv->cfg.averaging_factor);
pb_bool(pb, priv->cfg.enable_averaging);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -64,6 +69,9 @@ error_t UADC_loadIni(Unit *unit, const char *key, const char *value)
priv->cfg.averaging_factor = cfg_u16_parse(value, &suc); priv->cfg.averaging_factor = cfg_u16_parse(value, &suc);
if (priv->cfg.averaging_factor > 1000) return E_BAD_VALUE; if (priv->cfg.averaging_factor > 1000) return E_BAD_VALUE;
} }
else if (streq(key, "averaging")) {
priv->cfg.enable_averaging = cfg_bool_parse(value, &suc);
}
else { else {
return E_BAD_KEY; return E_BAD_KEY;
} }
@ -98,6 +106,9 @@ void UADC_writeIni(Unit *unit, IniWriter *iw)
iw_entry_d(iw, "buffer_size", priv->cfg.buffer_size); iw_entry_d(iw, "buffer_size", priv->cfg.buffer_size);
iw_cmt_newline(iw); iw_cmt_newline(iw);
iw_comment(iw, "Enable continuous sampling with averaging");
iw_comment(iw, "Caution: This can cause DAC output glitches");
iw_entry_s(iw, "averaging", str_yn(priv->cfg.enable_averaging));
iw_comment(iw, "Exponential averaging coefficient (permil, range 0-1000 ~ 0.000-1.000)"); iw_comment(iw, "Exponential averaging coefficient (permil, range 0-1000 ~ 0.000-1.000)");
iw_comment(iw, "- used formula: y[t]=(1-k)*y[t-1]+k*u[t]"); iw_comment(iw, "- used formula: y[t]=(1-k)*y[t-1]+k*u[t]");
iw_comment(iw, "- not available when a capture is running"); iw_comment(iw, "- not available when a capture is running");

@ -191,8 +191,13 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
return E_BUSY; return E_BUSY;
} }
if (! priv->cfg.enable_averaging) {
com_respond_str(MSG_ERROR, frame_id, "Averaging disabled");
return E_FAILURE;
}
if (priv->real_frequency_int > UADC_MAX_FREQ_FOR_AVERAGING) { if (priv->real_frequency_int > UADC_MAX_FREQ_FOR_AVERAGING) {
com_respond_str(MSG_ERROR, frame_id, "Too fast for smoothing"); com_respond_str(MSG_ERROR, frame_id, "Too fast for averaging");
return E_FAILURE; return E_FAILURE;
} }

Loading…
Cancel
Save