Capture one Analog channel in continuous mode at near maximum speed?

I’m looking to write a simple app for BBB. When started from the command line, it would set up the ADC in continuous mode and read ~1 M samples from e.g. AN0 into memory. After the capture is complete, it would write the data to a file and exit.

Ideally, it would run at the hardware limit of 1.6 MSPS (15 cycles of 24 MHz adc_clk per sample). If that’s not practical, 800 KSPS or better would be acceptable.

What is an easy way to do this? Most Beaglebone ADC examples sample at kilohertz rates or slower.

This guide: http://processors.wiki.ti.com/index.php/Linux_Core_ADC_User's_Guide speaks of 200 KSPS. What is the limitation here?

I’ve seen various suggestions to use the PRU, but don’t understand why. I would think that since DMA would be required anyway, there should be no requirement to otherwise access the hardware with tight timing. If PRU is indeed necessary, is there a suitable example or tutorial? (None of the libpruio built-in examples deal with rapid sampling or large amounts of data.)

Any other ideas for a simple way to capture data fast will be gratefully appreciated.

Thanks.

I have been working on adding DMA to the ADC driver, but it currently it throws overflow errors before DMA starts. The DMA should trigger when the ADC fifo reaches a predefined threshold, but for some reason there is a delay before DMA triggers. The ADC driver uses the IIO framework and I’m using their experimental DMA buffer framework which has its share of issues. I’m trying to diagnose the error by replicating the setup in Starterware. Unfortunately the CCS debugger isn’t all that helpful so now I’m trying to get my Lauterbach working Starterware, but I have to translate the CCS GEL scripts to Lauterbach Practice scripts.

Regarding the sampling rate, the datasheet does specify 200ksps, but if you setup the sample delay, open delay, etc, it should be possible to achieve something like 1.5msps, but I haven’t been able to verify this yet.

Regards,
John

The ADC module is a 200ksps SAR module . . .You’re only going to be able to sample 200k samples per second . . .

Additionally you can use:

  1. PRUs ( Programmable Real-time Units )
  2. IIO ( industrial IO )
  3. /dev/mem/ + mmap()

To read 200ksps. Personally, I’ve proven that /dev/mem + mmap() can work for reading 200ksps for 7 channel simultaneously. But CPU usage is so high, that you’re not going ot be able to do a whole lot more in addition to reading the ADC in this fashion. Hence, the PRU are best used, as this offers hardware offload( very little CPU load needed - and only when reading values out ).

You should read the info Steward provided. There is a conflict in the AM3358 datasheet because it does say max 200ksps, but in the register settings, it does show you can configure the ADC for 1.6msps. There are discussions on E2E about this issue and no one from TI has said you cannot achieve 1.6msps.

Regards,
John

Wow, I think that /dev/mem + mmap() is the easy solution! Many thanks.

But can you please confirm that by “200ksps for 7 channel simultaneously” you mean that each of the 7 channels is being sampled 200k times per second. If so, that’s 1.4M captures per second, enough for my project.

But CPU usage is so high, that you’re not going to be able to do a whole lot more in addition to reading the ADC in this fashion.

This is essentially a lab experiment. The program only needs to run correctly once (though it will take many executions to get all the external factors right). On each run, the BBB has no other tasks to perform. It won’t start writing the results to a file until after the capture is complete. If CPU usage during the capture is 95%, that’s fine. If it’s 105%, I’ll slow the sample rate a bit to avoid losing samples. But if it’s 250%, then I’m in trouble.

If not missing samples requires running in single-user mode with no networking and only a serial console, that’s IMO a minor nuisance compared to learning about PRU, etc. and debugging a much more complex program.

um no the 7 channels go into a analog mux and you can only have one
selected input at a time.

You don’t read the IIO driver that way. You read the samples from /dev/iio:device0. You can modify the open delay, sample delay, in the devicetree, but because the current driver uses interrupts, the cpu utilization increases as you increase the sample rate. Also, the convertor is specified as 200ksps, but there is only one converter for all channel which use a multiplexor to select each ADC channel. So if you use 2 channels, then each channel is sampled at 100ksps.

Regards,
John

http://e2e.ti.com/support/arm/sitara_arm/f/791/p/382609/1349287#1349287

Regards,
John

I’m well aware of the analog mux and fully understand that if N channels are being sampled, the maximum sample rate for each channel is reduced by a factor of N.

However, Mr. Hermans, who clearly knows what he is talking about, stated “I’ve proven that /dev/mem + mmap() can work for reading 200ksps for 7 channel simultaneously.”
It’s reasonable to assume that he would not have included the “7 channel simultaneously” part unless it was somehow relevant to the performance he observed.

And, if the ADC is actually capable of doing conversions at a 1.6 MHz rate, then it could sample all 8 channels at 200KSPS each, and maybe that’s what Mr. Hermans was observing.

However, Mr. Hermans, who clearly knows what he is talking about, stated “I’ve proven that /dev/mem + mmap() can work for reading 200ksps for 7 channel simultaneously.”
It’s reasonable to assume that he would not have included the “7 channel simultaneously” part unless it was somehow relevant to the performance he observed.

You’re not understanding correctly . . . the ADC module is rated for 200ksps only. Not 1M, not 2M, 200ksps.

http://www.ti.com/lit/ds/sprs717j/sprs717j.pdf

Page 3:

– 12-Bit Successive Approximation Register
(SAR) ADC
• 200K Samples per Second
• Input can be Selected from any of the Eight Analog Inputs Multiplexed Through an 8:1 Analog Switch
• Can be Configured to Operate as a 4-Wire, 5-Wire, or 8-Wire Resistive Touch Screen Controller (TSC) Interface

The ADC uses a sequencer and you can only read the sample when the samples are complete. The sequencer provides an interrupt or triggers a DMA transfer when the EOC (End of Conversion) is achieved. Since you cannot service interrupts in userspace, you will have to poll repeatedly to wait for the conversion to complete. Given the non deterministic nature of Linux, you will miss some of the conversions when you processor utilization is high. Polling itself will cause high CPU utilization. Hence the /dev/mem + mmap() won’t work.

Regards,
John

You’re not understanding correctly . . . the ADC module is rated for 200ksps only. Not 1M, not 2M, 200ksps.

So your “7 channel simultaneously” comment had nothing to do with the total sample rate, but merely indicates that this 200 KSPS rate was achieved even though some additional overhead (e.g. distributing the captured data into 7 different buffers) was present. Is that correct?

But in that case, I’m confused by john3909’s link, wherein a TI spokesman stated that the 200 kSPS value is for 3 MHz ADC clock, though the maximum ADC clk frequency is 24 MHz. A further clarification was that the 24 MHz ADC clk could only be achieved when the master oscillator is 24 MHz, but I confirmed at https://github.com/CircuitCo/BeagleBone-Black/blob/master/BBB_SCH.pdf?raw=true that Y2 is indeed 24 MHz on production boards.

Stop second guessing what I mean by what I type, and just read that dammed datasheet. I even pasted a quote of the relevant information, and it’s quite clear.

Currently the ADC driver is configured for 16x oversample, Open Delay = 152 cycles and Sample Delay = 1 cycles.

time in us for processing a single channel, calculated as follows:

num cycles = open delay + (sample delay + conv time) * averaging

num cycles: 152 + (1 + 13) * 16 = 376

clock frequency: 24MHz / 8 = 3MHz
clock period: 1 / 3MHz = 333ns

processing time: 376 * 333ns = 125us

Regards,
John

Thanks for the link. Given the recent update to the data sheet, it seems pretty likely that the 200 kSPS total sample rate limit is correct, even though that conflicts with both the (older) TRM and the comments in 2014 by Biser Gatchev-XID . So, it appears to be a waste of time to attempt 800 kSPS+.

Sorry to have bothered you all,
Stewart

Well, I think that is still to be determined if the ADC can sample higher than 200ksps and that is why I’m adding DMA to this driver. But in any case, why not use a higher speed ADC connected via SPI or McASP? You can purchase boards that sample at a higher rate and connect those to the BBB.

Regards,
John

So going back to what I said earlier. When using /dev/mem + mmap() yes, I was (actually ) reading more than

200ksps from 7 channels simultaneously. For a total of somewhere around 1.5Msps

That is a totally different issue. You were reading the same sample over and over again as opposed to increasing the sample rate by changing the clock divider, open delay, sample delay, etc. In any case, at 200ksps, each sample occurs every 5uS. How is a user space app going to process samples at 5uS? Even when you poll for the EOC with 8 channels configured, you still have to service the samples every 40uS and that is still not possible from a userspace app.

My guess is the app you had was reading the same sample at a higher rate than 1.5msps and then the scheduler switched out your app to service background tasks and then return a while later and then your app would read the same sample again. The average sample rate would then result in 1.5msps. Not a good idea. You should enable the channel ID to see when you miss samples.

Regards,
John

The ADC is a SAR ADC. Overclocking it is likely to have side effects on the
analog end of things which will reduce accuracy.

Ignoring that it is a very bad idea to keep doing things in userland:

That is a totally different issue. You were reading the same sample over and
over again as opposed to increasing the sample rate by changing the clock
divider, open delay, sample delay, etc. In any case, at 200ksps, each
sample occurs every 5uS. How is a user space app going to process samples
at 5uS? Even when you poll for the EOC with 8 channels configured, you
still have to service the samples every 40uS and that is still not possible
from a userspace app.

You could use the FIFOs to reduce the read timing accuracy but you still risk
getting scheduled away for (comparatively) long period of time. This probally
means you will also need to check the status for FIFO overflows and....

My guess is the app you had was reading the same sample at a higher rate
than 1.5msps and then the scheduler switched out your app to service
background tasks and then return a while later and then your app would read
the same sample again. The average sample rate would then result in
1.5msps. Not a good idea. You should enable the channel ID to see when you
miss samples.

It is not just missing sames but what is the overall accuracy of the data when
the ADC module is overclocked? Does it appear anywhere near the 12bits of
accuracy?