Periodic ADC readout

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderator: RoccoMarco

Post Reply
User avatar
jcw
Posts: 55
Joined: Thu May 23, 2013 12:59 am

Periodic ADC readout

Post by jcw »

I'm looking for a way to read out the ADC at 10 KHz on 4 channels with (eventually) minimal jitter, using a Nucleo F103RB board. The testhal code is a good start, and so are this page: https://sites.google.com/site/electroni ... c-sampling and this forum discussion: viewtopic.php?f=2&t=635

The GPT can be started as follows (as first test, it's toggling an LED at 10 Hz):

Code: Select all

void gpt_adc_trigger (GPTDriver*) { 
  palTogglePad(GPIOA, GPIOA_LED_GREEN);
}

static GPTConfig gpt_adc_config = {
  10000,           // timer clock: 10 KHz
  gpt_adc_trigger, // timer callback function
  0, 0
};

int main () {
  ...
  gptStart(&GPTD1, &gpt_adc_config);
  gptStartContinuous(&GPTD1, 1000);
  ...


The next step will be to start the ADC, but if done from in software gpt_adc_trigger(), then I would think that this can only be done as one-shot, and repeated again the next time gpt_adc_trigger() gets called. Each timeout then starts the ADC on 4 channels and then it stops again, right?

What I'm after though, ideally, is to have this all take place through DMA, i.e.use EXTSEL (external event select) to drive the ADC scans from the timer, at 10 KHz, and on each trigger have the ADC scan-and-save the next 4 readings to a circular buffer, using DMA. By then using the half-full and full interrupts, that would allow processing entire bursts of readings, as long as the reader thread can process half the buffer in time before the next interrupt.

While still working my way through the ChibiOS and STM32F1 docs, my question is: is the above approach feasible, and how far can it be integrated into what ChibiOS already does (which is quite a lot, including all the DMA setup).

-jcw
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Periodic ADC readout

Post by Giovanni »

You could just call adcStartConversionI() from the GPT callback, program the ADC in linear mode (non circular).

I haven't tested HW triggering on the F1 but I had to fix an issue on the F3 driver, I am not sure if the F1 driver is impacted too but it is very different.

Giovanni
User avatar
jcw
Posts: 55
Joined: Thu May 23, 2013 12:59 am

Re: Periodic ADC readout

Post by jcw »

FWIW, the reason for HW triggering (apart from reducing jitter), is to try pushing sampling rates up, later on.
But first things first - I'll try the gpt start w/ linear mode first, thanks.

-jcw
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Periodic ADC readout

Post by Giovanni »

HW triggering should be fine, I verified the code.

Giovanni
User avatar
jcw
Posts: 55
Joined: Thu May 23, 2013 12:59 am

Re: Periodic ADC readout

Post by jcw »

Great - it looks like the following code does indeed sample at 10 KHz and collect 64 values:

Code: Select all

#define ADC_GRP_NUM_CHANNELS   1
#define ADC_GRP_BUF_DEPTH      64

adcsample_t samples [ADC_GRP_NUM_CHANNELS * ADC_GRP_BUF_DEPTH];

void adcendcallback (ADCDriver*, adcsample_t*, size_t) {
  ; // breakpoint
}

void adcerrorcallback (ADCDriver*, adcerror_t) {
  ; // breakpoint
}

const ADCConversionGroup adcgrpcfg = {
  FALSE,
  ADC_GRP_NUM_CHANNELS,
  adcendcallback,
  adcerrorcallback,
  0,                                      // CR1
  ADC_CR2_EXTTRIG | ADC_CR2_EXTSEL_0,     // CR2
  0,                                      // SMPR1
  ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5),      // SMPR2
  ADC_SQR1_NUM_CH(ADC_GRP_NUM_CHANNELS),  // SQR1
  0,                                      // SQR2
  ADC_SQR3_SQ1_N(ADC_CHANNEL_IN0)         // SQR3
};

void gpt_adc_trigger (GPTDriver*) {
  adcStartConversionI(&ADCD1, &adcgrpcfg, samples, ADC_GRP_BUF_DEPTH);
}

const GPTConfig gpt_adc_config = {
  1000000,         // timer clock: 1 MHz
  gpt_adc_trigger, // timer callback function
  0, 0
};

int main () {
  halInit();
  chSysInit();

  palSetPadMode(GPIOA, 0, PAL_MODE_INPUT);

  gptStart(&GPTD1, &gpt_adc_config);
  gptStartContinuous(&GPTD1, 100); // 100 counts, i.e. 10 KHz

  adcStart(&ADCD1, NULL);


The GPT timer fires at 10 KHz, right? Is my understanding correct that each software interrupt appends a sample to the buffer, and after 64 interrupts, the adcendcallback() gets called?

I don't think the "ADC_CR2_EXTTRIG | ADC_CR2_EXTSEL_0" setting does anything yet, but hey, I'm seeing good readings, great!

-jcw
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Periodic ADC readout

Post by Giovanni »

Nope, the ADC samples 64 times the same channel each time adcStartConversionI() is called.

Giovanni
User avatar
jcw
Posts: 55
Joined: Thu May 23, 2013 12:59 am

Re: Periodic ADC readout

Post by jcw »

Ah, ok. So one adcStartConversionI() samples 64 times, 100 µs apart, and the EXT trigger is already working?
And I can simply restart the GPT every 64 x 100 µs to alternating buffers to keep things going?

-jcw
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Periodic ADC readout

Post by Giovanni »

There are several solutions:

- SW triggering with one sample at time.
- HW triggering with one sample at time.
- HW triggering with 64 samples and DISCEN enabled (the driver may not support this currently).

Giovanni
joewa
Posts: 22
Joined: Tue May 13, 2014 10:40 pm

Re: Periodic ADC readout

Post by joewa »

Did you already succeed to make hardware EXT trigger working?

If possible, I would like to trigger the conversion with more than one sample (500+) in scan mode to sample a few inputs.

I have been trying this for some time now: http://forum.chibios.org/phpbb/viewtopic.php?f=16&t=2173&start=10#p17753
Although I am not sure if this is possible.

Jörg
Post Reply