bbb Internal ADC configuration settings?

Where can I find it (and set it)?

I’m right now trying to collect voltage readings using beaglebone’s internal adc using a bash script and a while loop. Right now the data collection is clocking at around 33 microseconds, but I know that the internal adc should be able to collect data as fast as 5 microseconds. What should I do to make that happen? Is the problem with making while loops move faster, or is it about setting the adc configurations?

This is my bash script:

#!/bin/bash

#echo cape-bone-iio > /sys/devices/bone_capemgr.*/slots

t0=$(date +%s%6N)

while true; do
t1=$(date +%s%6N)
rawVal=$(cat /sys/bus/iio/devices/iio:device0/in_voltage0_raw)
voltage=$(bc -l <<< $rawVal/4095*1.8)
time=$(expr $t1 - $t0)
echo $time $voltage
done

Scrolling and calling external functions like 'date' in Terminal are
extremely time consuming. In order to know how fast adc read is you
might want to start without timer and print in you loop....
E.G:

#!/bin/bash
#echo cape-bone-iio > /sys/devices/bone_capemgr.*/slots
t0=$(date +%s%6N)
for ((i=0;i<1000;i++)); do
     rawVal=$(cat /sys/bus/iio/devices/iio:device0/in_voltage0_raw)
     # voltage=$(bc -l <<< $rawVal/4095*1.8)
done
t1=$(date +%s%6N)
time=$(expr $t1 - $t0)
echo $time

That is because you are doing this wrong. Reading attributes via sysfs is slow and not meant for this purpose. With IIO, you enable a scan element (echo 1 > in_voltage0_en) and then you enable the buffer (echo 1 > buffer/enable)and then you read the values from /dev/iio:device0. In the BB-ADC overlay, you can modify the scan update time by modifying the Oversample (default is 16x), Open Delay time (default is 0x98) and sample time (default is 1). Now the IIO ADC driver captures samples using interrupts which isn’t ideal, but it will capture samples at a much higher rate than can be read from sysfs. If you want to capture at full speed, the driver needs to be updated to use DMA.

Regards,
John

Thanks for the reply John. Could you perhaps explain how to modify the oversample, open delay time, and sample time in greater detail in the BB-ADC overlay? I do not see these variables in the dto in github (https://github.com/beagleboard/devicetree-source/blob/master/arch/arm/boot/dts/BB-ADC-00A0.dts). Also, what value can/should I change them to?

So just to clarify, reading from /sys/bus/iio/devices/iio:device0/in_voltage0_raw reads attributes using sysfs, while reading from /dev/iio:device0 reads the values using IIO? Also another conceptual question, can you explain what exactly is in_voltage0_raw and iio:device0? I know it’s not a folder, and I interact with it by using cat. So is it just like a text file or something?

Thanks.

Also another conceptual question, can you explain what exactly is in_voltage0_raw and iio:device0? I know it’s not a folder, and I interact with it by using cat. So is it just like a text file or something?

in_voltage0_raw == one shot mode.

/dev/iio:device0 == continuous mode.

continuous mode is only really useful if you need more than 3-4 thousand samples a second. Otherwise one shot mode will possibly work just fine. It really how much you’re trying to do all at once.

/*

what the hell does what you’ve said there even mean John ? voltagex_raw is one shot mode, iio:deviceX is continuous mode.

What you said above only serves to confuse the situation.

Now if you want to convey more information that is actually useful to anyone reading this post. You can say that both voltageX_raw, and iio:deviceX are buffers.

With voltageX_raw being a single value buffer that gets updated only once every open() call on it’s file descriptor.

Where iio:deviceX is a buffer, defined in size by the value set in /sys/bus/iio/devices/iio:device0/buffer/length

More useful information can be found here: http://processors.wiki.ti.com/index.php/AM335x_ADC_Driver’s_Guide. Then if you want even more information still, googling “iio” will produce a lot of information. Much of it not so useful. At least for our use case, the Beaglebone.

John, also Audry asked what the values of that device tree fragment mean, not what the code was. As in Audry wants and explanation of the values:

ti,chan-step-avg = <0x16 0x16 0x16 0x16 0x16 0x16 0x16>;
ti,chan-step-opendelay = <0x98 0x98 0x98 0x98 0x98 0x98 0x98>;
ti,chan-step-sampledelay = <0x0 0x0 0x0 0x0 0x0 0x0 0x0>;

As far as I can tell. Quite honestly I could use that explanation myself. But step avg can be a value 0-16 if memory serves from reading the TRM, I’m just not clear exactly on what step avg actually does. . . . the explanation in the TRM is very jumbled / confusing.

Hi Audrey!

As mentioned above, a bash script is not feasible to handle ADC sampling at 200 kHz. Instead use a fast compiler language like C, C++ or FreeBASIC. The mentioned iio solutions require file access, which is also slow. In order to get direct access to the values, use libpruio. This library provides

  • full control over all ADC configuration registers
  • at run-time (no device tree changes / reboots)
  • sampling at full speed (200 kHz)
    and some further features … Check out the examples.

BR

William,

Rather you should not comment on my replies. If I say white, you say black even when you know you are wrong. If you look at the DT overlay the OP referenced, the additional entries don’t exist and that is why I posted an updated DT overlay. Reading in_voltagex_raw like your beaglebone-black-adc example was never meant for high speed capture. In fact you are just reading the same sample over and over again. Reading the buffer via /dev/iio:device0 is how you are supposed to read IIO ADC samples. If you want to understand oversampling, open delay, sample delay, then read the AM3358 TRM.

Regards,
John

http://events.linuxfoundation.org/sites/events/files/slides/lceu15_baluta.pdf

Regards,
John

Look at AM3358 TRM Figure 12-3 on Page 1497

Regards,
John

William,

Rather you should not comment on my replies. If I say white, you say black even when you know you are wrong.

That’s funny I was thinking the same, except your answer is wrong.

If you look at the DT overlay the OP referenced, the additional entries don’t exist and that is why I posted an updated DT overlay. Reading in_voltagex_raw like your beaglebone-black-adc example was never meant for high speed capture. In fact you are just reading the same sample over and over again.

http://processors.wiki.ti.com/index.php/AM335x_ADC_Driver’s_Guide#One-shot_Mode No one said anything about high speed capture. But have you actually ever used one shot mode ? It is NOT reading the same sample over and over again. But you do have to open / close the file every time you do want a new reading. That’s how it’s supposed to work.

Reading the buffer via /dev/iio:device0 is how you are supposed to read IIO ADC samples.

No one ask that question.

If you want to understand oversampling, open delay, sample delay, then read the AM3358 TRM.

So in other words, you do not know. But again, this is not a question i asked for myself. It’s the question I interpreted Audry asking to which you completely blew off.

William,

Rather you should not comment on my replies. If I say white, you say black even when you know you are wrong.

That’s funny I was thinking the same, except your answer is wrong.

If you look at the DT overlay the OP referenced, the additional entries don’t exist and that is why I posted an updated DT overlay. Reading in_voltagex_raw like your beaglebone-black-adc example was never meant for high speed capture. In fact you are just reading the same sample over and over again.

http://processors.wiki.ti.com/index.php/AM335x_ADC_Driver’s_Guide#One-shot_Mode No one said anything about high speed capture. But have you actually ever used one shot mode ? It is NOT reading the same sample over and over again. But you do have to open / close the file every time you do want a new reading. That’s how it’s supposed to work.

Reading the buffer via /dev/iio:device0 is how you are supposed to read IIO ADC samples.

No one ask that question.

If you want to understand oversampling, open delay, sample delay, then read the AM3358 TRM.

So in other words, you do not know. But again, this is not a question i asked for myself. It’s the question I interpreted Audry asking to which you completely blew off.

You have this amazing ability to read peoples minds; at least you think you do. You should reframe from guessing what people know or don’t know, but you do make me smile when I read what you say. If you read the section I referenced in the TRM, it is explained very clearly. Why would I cut and past that is already explained. The ADC uses a scan cycle and in that cycle, it has an open delay, a sample delay and then it oversamples a predefined number of time. The oversampling helps increase the bits of resolution:

[https://www.silabs.com/Support%20Documents/TechnicalDocs/an118.pdf](https://www.silabs.com/Support Documents/TechnicalDocs/an118.pdf)

The open delay and sample delay are used accommodate the sample&hold error that occurs when the source impedance is too high. What isn’t in the TRM, but is understood by EE who design ADC front ends, an analog buffer like an opamp or a instrumentation amplifier or a chopper amplifier is used to eliminate offset errors and present a low impedance to the ADC sample and hold. If you don’t do this, you will see bleedover from one channel to another. Now this probably doesn’t make any sense to you because this is all to EE specific, but you did ask.

Regards,
John

Question:

So just to clarify, reading from /sys/bus/iio/devices/iio:devic**e0/in_voltage0_raw reads attributes using sysfs, while reading from /dev/iio:device0 reads the values using IIO? Also another conceptual question, can you explain what exactly is in_voltage0_raw and iio:device0? I know it’s not a folder, and I interact with it by using cat. So is it just like a text file or something?

My answer:

in_voltage0_raw == one shot mode.

/dev/iio:device0 == continuous mode.

continuous mode is only really useful if you need more than 3-4 thousand samples a second. Otherwise one shot mode will possibly work just fine. It really how much you’re trying to do all at once.

John’s answer:

*Reading from /sys/bus/iio/devices/iio:*device0/in_voltage0_raw is reading and attribute of the IIO driver. Reading from /dev/iio:device0 is reading from the same IIO driver, but in this case you are reading from the buffer which stores samples defined in the DT overlay above.

Regards,
John

Total bullshit answer John. Which is getting to be common place from you. Sure iio:deviceX is a buffer, for continuous mode operation but in_voltageX_raw is not an fscking attribute. It’s a single value buffer. What’s more, your timing is impeccable. Bullshit answer right after I’ve already explained it. You tell me what I’m supposed to think about that.

Additionally, you go about spouting complete FUD saying that one shot mode only gives the same value over, and over again. It’s very obvious you have no personal hands on knowledge here. in_voltageX_raw is refreshed every time the pseudo file is opened. That means, if you open the file, you must close it , then reopen in order for the value to refresh. I’ll also give you another clue. In continuous mode, you have to read above 200Ksps from a single ADC channel before you start getting redundant data. So what makes you think that a very slow operation such as opening a file before reading a value is going to make the ADC’s maximum samples / second any slower ? Bonus hint: it wont.

Anyway, I’m starting to feel like a 5 year old fighting over something incredibly stupid. So I’m done with this conversation. However, again. Stop spreading FUD about stuff you obviously know nothing about, and I’ll stop putting it back into your face. It surely seems like you know what the iio buffer is and does, and you know what some obscure device tree values for the ADC are ( I never even knew of those ). But you definitely have no clue about one shot mode.

Question:

So just to clarify, reading from /sys/bus/iio/devices/iio:devic**e0/in_voltage0_raw reads attributes using sysfs, while reading from /dev/iio:device0 reads the values using IIO? Also another conceptual question, can you explain what exactly is in_voltage0_raw and iio:device0? I know it’s not a folder, and I interact with it by using cat. So is it just like a text file or something?

OK, so if you look at the /driver/iio/adc/ti_am335x_adc.c file, reading in_voltage0_raw is done by the tiadc_read_raw() function. The /dev/iio:device0 is a regular device driver interface, just like /dev/tty0. You can open, poll, read, etc. If you want to know how to interface to this driver, look at tools/iio/generic_buffer.c. So generally, you open /dev/iio:device0, then you poll this interface, which blocks, waiting for the buffer to exceed the watermark (prevents read from reading just a few values) and when poll returns, you read multiple values into a buffer in user space.

My answer:

in_voltage0_raw == one shot mode.

/dev/iio:device0 == continuous mode.

continuous mode is only really useful if you need more than 3-4 thousand samples a second. Otherwise one shot mode will possibly work just fine. It really how much you’re trying to do all at once.

John’s answer:

*Reading from /sys/bus/iio/devices/iio:*device0/in_voltage0_raw is reading and attribute of the IIO driver. Reading from /dev/iio:device0 is reading from the same IIO driver, but in this case you are reading from the buffer which stores samples defined in the DT overlay above.

Regards,
John

Total bullshit answer John. Which is getting to be common place from you. Sure iio:deviceX is a buffer, for continuous mode operation but in_voltageX_raw is not an fscking attribute. It’s a single value buffer. What’s more, your timing is impeccable. Bullshit answer right after I’ve already explained it. You tell me what I’m supposed to think about that.

There is no such thing as a single value buffer. Look up sysfs in the kernel docs, it is restricted to a single value (boolean, int, etc) per sysfs interface. Hence the reason why debugfs was developed, which can exchange complex data structures.

Additionally, you go about spouting complete FUD saying that one shot mode only gives the same value over, and over again. It’s very obvious you have no personal hands on knowledge here. in_voltageX_raw is refreshed every time the pseudo file is opened. That means, if you open the file, you must close it , then reopen in order for the value to refresh. I’ll also give you another clue. In continuous mode, you have to read above 200Ksps from a single ADC channel before you start getting redundant data. So what makes you think that a very slow operation such as opening a file before reading a value is going to make the ADC’s maximum samples / second any slower ? Bonus hint: it wont.

You don’t have to open the file for each read. You can open and then read and read again. That is what your example does. Looking at the code, it looks like you cannot read the same sample over and over again, because it waits for a new sample to complete before returning. This is probably why sysfs is slow because it has to wait for a complete scan cycle of all channels before returning a single value.

Anyway, I’m starting to feel like a 5 year old fighting over something incredibly stupid. So I’m done with this conversation. However, again. Stop spreading FUD about stuff you obviously know nothing about, and I’ll stop putting it back into your face. It surely seems like you know what the iio buffer is and does, and you know what some obscure device tree values for the ADC are ( I never even knew of those ). But you definitely have no clue about one shot mode.

You need to relax, take a breath. If you read the code in the driver, you will see that I am correct.

Regards,
John

Hi everyone,

First of all, thank you everyone for trying to help me. I appreciate everyone’s input.

I took everyone’s advice, and have moved away from bash to C++. It’s clocking at about 2 milliseconds, but I would really like it to go down into the microsecond range:

/** Simple LDR Reading Application

  • Written by Derek Molloy for the book "Exploring BeagleBone: Tools and

  • Techniques for Building with Embedded Linux" by John Wiley & Sons, 2014

  • ISBN 9781118935125. Please see the file README.md in the repository root

  • directory for copyright and GNU GPLv3 license information. */

#include

#include

#include

#include

using namespace std;

#define LDR_PATH “/sys/bus/iio/devices/iio:device0/in_voltage”

int readAnalog(int number)

{

stringstream ss;

ss << LDR_PATH << number << “_raw”;

fstream fs;

fs.open(ss.str().c_str(), fstream::in);

fs >> number;

fs.close();

return number;

}

int main(int argc, char* argv[])

{

cout << “Starting the readLDR program” << endl;

int value;

int i=1;

while (true)

{

float value = (float)readAnalog(0)/4095*1.8;

cout <<"V= " << value << endl;

cout << i << endl;

i++;

}

return 0;

}

Thank you TJF for pointing me to libpruio. I’ll use it later if I need it, but for now I rather not use the PRU if I don’t need to.

So I noticed this thing where I can’t see the buffer, or scan_elements, or mode in iio:device0, and I wonder if I’m not enabling the adc dto properly or something:

root@beaglebone:/sys/bus/iio/devices/iio:device0# ls -l
total 0
-r–r--r-- 1 root root 4096 Mar 1 20:51 dev
-rw-r–r-- 1 root root 4096 Mar 1 22:03 in_voltage0_raw
-rw-r–r-- 1 root root 4096 Mar 1 22:03 in_voltage1_raw
-rw-r–r-- 1 root root 4096 Mar 1 22:03 in_voltage2_raw
-rw-r–r-- 1 root root 4096 Mar 1 22:03 in_voltage3_raw
-rw-r–r-- 1 root root 4096 Mar 1 22:03 in_voltage4_raw
-rw-r–r-- 1 root root 4096 Mar 1 22:03 in_voltage5_raw
-rw-r–r-- 1 root root 4096 Mar 1 22:03 in_voltage6_raw
-rw-r–r-- 1 root root 4096 Mar 1 22:03 in_voltage7_raw
-r–r--r-- 1 root root 4096 Mar 1 20:51 name
drwxr-xr-x 2 root root 0 Mar 1 20:51 power
lrwxrwxrwx 1 root root 0 Mar 1 20:50 subsystem → …/…/…/…/…/bus/iio
-rw-r–r-- 1 root root 4096 Mar 1 20:50 uevent

This is what I’ve been doing to “enable” the adc (although I don’t really know what it is doing. I can’t find the file cape-bone-iio in bbb, and if I try echo cape-bone-iio > test.txt, it is just a regular string.):

echo cape-bone-iio > /sys/devices/bone_capemgr.*/slots

I tried searching for /driver/iio/adc/ti_am335x_adc.c, but I can’t find it (there’s nothing in root@beaglebone:/sys/bus/iio/drivers#). Could you perhaps specify the full filepath?

Thanks.

The buffer is available here:

/dev/iio:device0

Because the driver uses interrupts, you won’t get the speed you want. The driver has to be updated to use DMA if you want to use full speed. Reading from the buffer will reduce your CPU load compared to using LDR_PATH because this interface blocks until a sample is available, but not long enough for the thread to sleep. To use DMA, IIO have introduced a DMA framework and most of what you need is already available. However, IIO are going to be updating the IIO DMA framework to do zero copy between the kernel module and the socket interface, using MMU maps.

Regards,
John

It says:

root@beaglebone:/dev# cd iio:device0
-bash: cd: iio:device0: Not a directory

root@beaglebone:/dev# cat iio:device0
cat: iio:device0: Invalid argument