I'm doing a project where in I'm using Arduino Due to measure the time difference of arrival of signals to four piezoelectric sensors. The piezo sensors where glued on a board and we want to localize the source of taps on the boards based from the TDOA of the vibration to the piezos.

Originally, we are using interrupts to raise flags once we have detected the signals (basically, we've set a threshold on the piezo voltage to say that we've 'detected' a signal) but that seems susceptible to noises especially when the environment has loud noises (music, voices on microphones, etc.).

So what we think as a solution is to perform signal processing. However, to do this, we need to measure the voltage of the incoming signal using the ADC.

So far, my target is to make the performance of this approach comparable to that of the one where we are using interrupts. As of now, the new approach is super sensitive to the difference on the taps giving it a high POE.

As I understand it, the main difference between the two approach is that the interrupt approach has a microsecond difference between counts making the difference of the taps to about 10 to 30 microsecond. However, the Analog approach has a 20 microsecond difference between each sample for each channel, making the count difference 20 second also. Even a count difference would make it 20 us.

Is there anyway to make this time faster? I know the ADC needs time to convert and push the data to the appropriate registers but I'm just trying to find ways to make this faster. I've read on the datasheet of the Due MCU that it has 14 ADC channels plus a temp sensor at the 15th. Maybe a way of doing this could be to reduce the number of channels? I don't know how.

Are there any way to make the ADC conversion of the Arduino Due faster?


Yes, there is a possibility to configure ADC to run faster, as it can handle 1Msps. For four ADC channels it means 250ksps each (with 1us time difference between samples). It's not possible with Arduino wrappers as they are way too slow and also waits for conversion end. You have to configure it directly in MCUs registers, so start with SAM3X8 datasheet.

In short: free running mode, sequenced readings like: 0 1 2 3, with interrupt on 4th sample, interrupt handler and some processing.

| improve this answer | |
  • Thanks @KIIV! Another question, in the free running mode, would there be any problem on reading the output registers? I mean since the ADC is freely converting and I'm still reading channel 1 (I reckon reading through SPI or I2C is slower than the actual conversion), but the ADC has new set of data, will there be any data collision or anything? – noobiejp Jul 5 '17 at 8:54
  • @noobiejp That's why I mentioned sequenced readings. You can configure it to go over ADC inputs in any order. And readings are stored in corresponding data registers. – KIIV Jul 5 '17 at 9:05

difference between each sample for each channel,

That's way too slow for any mcu made since the 1980s.

Look into the datasheet and compare it via your code to see where you can pick up the speed. Typically there is a clock prescaler for the adc that you can change.

In general, the fastest would be continuous adc into dma. If you need to add multiple channels turn on scanning.

| improve this answer | |

//Configure ADC PMC->PMC_WPMR &= ~(PMC_WPMR_WPEN); //Disable the Write Protect Mode PMC->PMC_PCER1 |= PMC_PCER1_PID37; //Enable ADC Peripheral Clock

PIOA->PIO_PDR |= PIO_PDR_P16; //Disable PIO Controller

ADC->ADC_WPMR &= ~(ADC_WPMR_WPEN); //Disable the Write Protect Mode ADC->ADC_CHER |= ADC_CHER_CH7; //Enable A0 pin ADC->ADC_MR = 0; //ADC->ADC_MR = ADC_MR_PRESCAL(2); //ADC Clock set to 16MHz ADC->ADC_MR = ADC_MR_PRESCAL(4); //ADC Clock set to 8MHz ADC->ADC_MR |= ADC_MR_TRACKTIM(3); ADC->ADC_MR |= ADC_MR_STARTUP_SUT8; ADC->ADC_EMR = 0;

//read ADC output ADC->ADC_CR |= ADC_CR_START; //Software Trigger uint32_t adc_read = ADC->ADC_CDR[7];

you can change the parameters of prescaler to get the required speed

| improve this answer | |

You can set the ADC in freerun mode to get results as fast as they can be read.

Use adc_configure_trigger for this.

adc_configure_trigger(ADC, ADC_TRIG_SW, ADC_MR_FREERUN_ON);

To enable freerun on the ADC or to configure as needed. No need anymore to set registers.

There was a bug with this function before if called more than once, but it is now fixed. https://github.com/arduino/Arduino/issues/1819

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.