Fast A/D with DMA, trying to get it to work.

Hello,

I need to do some fast analog reading, in order to detect an event, i.e. sample a waveform until the values start to rise, and then figure out what time after the start this occurs.

Not too difficult, except that the analog read needs to be no more than 4uS / conversion.

There is a thread on this here: A/D with DMA

The code there will compile (if not using arduino v1.66), but I am getting a reading of 2056uS / conversion, which is much slower than the standard library. The poster of the code claimed 2uS per conversion.

I have been trying on, and off for 2 weeks now to get it to work, but no amount of me fiddling with the a/d registers has improved things. In the original post people have commented how great this is, so I assume it has worked, for some.

I am using a M0 PRO board, but from what I gather it is almost exactly the same as the Zero.

Can anyone please help me to get this working?

Regards
Bob.

the fact is that the code you use is converting 1024 samples, not one.

Thank you so much for that.

I will look into that at work tomorrow.

Bob

Thanks again Aloyse,

changed the define hwords 1024 to 1, and now I am getting 10uS to do the conversion.
Guess it's more trawling through the data sheet for me.

Hope I can get down to 2uS, as the speed of the zero is its only advantage, apart from large memory.
If anyone has any experience with this please feel free to help.

Regards
BOb

adcdma.ino.ino (3.79 KB)

Hi Bob,

3.5 µs is in my opinion close to the limit because 360 ksamples/s spec corresponds to 2.86 µs conversion time. There will be latency from bus transfer delays etc.

I had made some investigations for programmatically controlled ADC. I managed to get the total conversion time down to 6 µs for 12-bits in single conversion mode with unity gain. See:
https://forum.arduino.cc/index.php?topic=341345.msg2390628#msg2390628
The code included in this has some comments with times from a timing function using systicks kindly supplied by Mantoui. The actual conversion took 4.58 µs for 12 bits in single conversion mode with a 2 MHz ADC clock. The maximum ADC clock rate is 2.1 MHz according to the manual. 2 MHz should according to Fig 32-6 in the manual correspond to 0.5*7 = 3.5 µs. I presume the difference is due to processor and bus latencies. Note that the gain and the ADC-mode (single conversion or free-running) effects the conversion time.

I believe the ADC is a so called pipeline ADC. I have not seen this explicitly stated in the manuals but some vague references to pipelines. A pipeline ADC is a hybrid between a flash ADC and a successive approximation ADC. As such the conversion time increases according to the number of bits. A useful explanation of how a pipeline ADC works is given at: Understanding Pipelined ADCs | Analog Devices

There is a manual for the SAMD21 ADCs. http://www.atmel.com/Images/Atmel-42109-SAM-Analog-to-Digital-Converter-ADC-Driver_ApplicationNote_AT03243.pdf It states "The ADC may be configured for 8-, 10-, or 12-bit result, reducing the conversion time." so this seems to be consistent with a pipeline ADC. It also states the ADC can convert up to 500 ksamples/s. It does not say what the number of bits the resolution was at this speed.

I also found it necessary to run the M0 Pro from an external 12 V power source to get the ADC to give stable conversion values. The 2 MHz ADC clock was generated from the 8 MHz oscillator. I was using single conversion mode which added 1 µs per conversion.

It seems to me that faster readout speed can be achieved using DMA combined with the event handling system. Then you don't need to invoke the processor at all. I have not seen any example code of how to use the event system and I admit to being no wizard at C/C++.

So to get the fastest ADC conversion speed. (i) Use an external power source, (ii) Work with 8- or 10-bit resolution, (iii) Set an appropriate ADC clock (iv) Consider using the event handling system with DMA. (v) if you can use free-running mode you should do so.

I hope this helps. I wish you every success.
Harry J. Whitlow

@whitlow I'm working with Mantoui's ADC DMA sketch and get stable conversion in some cases but not others. I wondered if you'd seen this specific case seeing as though you've posted some great info on ADC conversion stability.

My aim is to modify Mantoui's sketch to do 2 things:

  1. Put the ADC in input scan mode so I can sample from 2 pins instead of one.

  2. Get as close to 16 bit resolution while maintaining a 16kHz sample rate.

  3. Was easy enough and works great. This is the output of sketch a (A1 is connected to ground and A2 is connected to the DAC pin which is outputting 64).

Between sample time (2 channels): 4 us   
A1: 0
A2: 65
Between sample time (2 channels): 4 us   
A1: 0
A2: 65
Between sample time (2 channels): 4 us   
A1: 1
A2: 64
Between sample time (2 channels): 4 us   
A1: 1
A2: 66
  1. Is proving difficult. Just changing from ADC_CTRLB_RESSEL_10BIT to ADC_CTRLB_RESSEL_12BIT results in some strange behaviour where the samples appear to be converted in reverse order every now and then?? This is the output of sketch_b:
Between sample time (2 channels): 4 us   
A1: 4
A2: 263
Between sample time (2 channels): 4 us   
A1: 4
A2: 265
Between sample time (2 channels): 4 us   
A1: 265
A2: 4
Between sample time (2 channels): 4 us   
A1: 262
A2: 6

Have you seen this behaviour before? I’m running off usb power which I notice you advise against so I might try an alternate power source to see if that’s the cause. My aim is to run this off a LIPO battery eventually.

sketch_a.ino (3.98 KB)

sketch_b.ino (3.98 KB)

After going through Mantoui's code again I realised it must be an issue of synchronising the DMA transfer with the ADC which is important in my case because I'm using the ADC in input scan mode.

If anyone has any ideas on how to consistently get the ADC to start sampling the first pin in the inputscan sequence after the DMA transfer has been setup please share because I've tried a few things without success to date.