reading several channels with multiplexed ADC
First, thank you for a very nice repo!
I am using some code on Arduino Due to:
- 1 set up a timer
- 2 set up the ADC to trigger at rising edge of the timer, and read on several multiplexed channels one after the other
- 3 raise the ADC ISR once all conversions are done.
The code looks like this:
constexpr int adc_sample_rate = 1000;
constexpr uint8_t adc_channels[] = {7, 6, 5, 4, 3};
constexpr int nbr_adc_channels = sizeof(adc_channels);
void adc_setup()
{
PMC->PMC_PCER1 |= PMC_PCER1_PID37; // ADC power on
ADC->ADC_CR = ADC_CR_SWRST; // Reset ADC
ADC->ADC_MR |= ADC_MR_TRGEN_EN | // Hardware trigger select
ADC_MR_PRESCAL(200) | // pre-scaler
ADC_MR_TRGSEL_ADC_TRIG3; // Trigger by TIOA2 Rising edge
ADC->ADC_IDR = ~(0ul);
ADC->ADC_CHDR = ~(0ul);
for (int i = 0; i < nbr_adc_channels; i++)
{
ADC->ADC_CHER |= ADC_CHER_CH0 << adc_channels[i];
}
ADC->ADC_IER |= ADC_IER_EOC0 << adc_channels[nbr_adc_channels - 1];
ADC->ADC_PTCR |= ADC_PTCR_RXTDIS | ADC_PTCR_TXTDIS; // Disable PDC DMA
NVIC_EnableIRQ(ADC_IRQn); // Enable ADC interrupt
}
void tc_setup()
{
PMC->PMC_PCER0 |= PMC_PCER0_PID29; // TC2 power ON : Timer Counter 0 channel 2 IS TC2
TC0->TC_CHANNEL[2].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK2 // clock 2 has frequency MCK/8, clk on rising edge
| TC_CMR_WAVE // Waveform mode
| TC_CMR_WAVSEL_UP_RC // UP mode with automatic trigger on RC Compare
| TC_CMR_ACPA_CLEAR // Clear TIOA2 on RA compare match
| TC_CMR_ACPC_SET; // Set TIOA2 on RC compare match
constexpr int ticks_per_sample = F_CPU / 8 / adc_sample_rate; // F_CPU / 8 is the timer clock frequency, see MCK/8 setup
constexpr int ticks_duty_cycle = ticks_per_sample / 2; // duty rate up vs down ticks over timer cycle; use 50%
TC0->TC_CHANNEL[2].TC_RC = ticks_per_sample;
TC0->TC_CHANNEL[2].TC_RA = ticks_duty_cycle;
TC0->TC_CHANNEL[2].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger TC2 counter and enable
}
void ADC_Handler(){
// putting inside buffer
}
Is there a way to set up a similar timer + triggering + multiplexed ADC conversion with your library, or does this require doing some register operations as done here?
I looked at the examples:
- this one was very interesting about timers etc, but it looks like there is a bit more complexity than needed / the previous example, and also, the ADC is not really triggered by the timer, rather, the timer raises an interrupt in which ISR the ADC conversion is started. Not sure if this is less accurate that the method above?
https://github.com/pedvide/ADC/blob/master/examples/analogReadIntervalTimer/analogReadIntervalTimer.ino
- in this example, not sure what effective sampling frequency is obtained in the end:
https://github.com/pedvide/ADC/blob/master/examples/analogContinuousRead/analogContinuousRead.ino
- I am also not sure if this library lets one set the multiplexing through register setup?
The library doesn't support this, but I think depending on the Teensy model it is possible to do something like this using DMA. Basically you have a buffer with the channels (formatted like the SC1A register) and set DMA to transfer each at a time to the SC1A register, wait for thr ADC to finish, transfer the result from RA to some buffer and do it again. I don't have examples for this, but I think you may find some in the forum