Reading analog inputs fast in beaglebone black

I need to read all 7 analog pins in the BBB every 5 milliseconds. I’m doing so with the following C code:

void main(){
    char value_str[7];
    long int value_int = 0;

    FILE* f0 = fopen("/sys/bus/iio/devices/iio:device0/in_voltage0_raw", "r");

    while(1){
            fread(&value_str, 6, 6, f0);
            value_int = strtol(value_str,NULL,0);
            printf("0 %li\n", value_int);
            fflush(stdout);

            usleep(5000);
            rewind(f0);
    }

Hoever, the cpu usage goes up really high (20%). Is there any way to read the analog inputs differently so that it doesn’t use as much CPU? Someone suggested “DMA” but I’m completely lost on that regard…

Any help will be appreciated.

I need to read all 7 analog pins in the BBB every 5 milliseconds. I'm
doing so with the following C code:

...

     while(1){
             fread(&value_str, 6, 6, f0);
             value_int = strtol(value_str,NULL,0);
             printf("0 %li\n", value_int);
             fflush(stdout);

             usleep(5000);
             rewind(f0);
     }

Hoever, the cpu usage goes up really high (20%). Is there any way to
read the analog inputs differently so that it doesn't use as much CPU?

I would replace "printf("0 %li\n", value_int); fflush(stdout);" by saving the converted values into an array, and print the values only when the measurement ist finished.

Someone suggested "DMA" but I'm completely lost on that regard...

That would be for specialists

Christian

I would replace “printf(“0 %li\n”, value_int); fflush(stdout);” by
saving the converted values into an array, and print the values only
when the measurement ist finished.

What do you mean when the measurement is finished? I need to read the inputs every 5 milliseconds forever. Is there a “ready” flag or a time to wait after reading the file?

Thanks.

Christian is correct. Don’t use printf. It introduces a significant overhead.
remove printf, copy into a variable. Then check and see if you can meet timing. fingers crossed

Your email mentioned you wanted to acquire all 7 analog inputs for real time audio every 5ms.
Depending on your level of processing of the audio, you might face difficulty with that. Who knows, might just work.

Is there any correlation regarding timing between the channels? Can you acquire a sample from channel 1, sleep 500ms, acquire from channel 2, sleep 500ms acquire from channel 3,
Or do all samples have to be acquired simultaneously?

ZubairLK

I need to read all 7 analog pins in the BBB every 5 milliseconds. I’m doing so with the following C code:

void main(){
    char value_str[7];
    long int value_int = 0;

    FILE* f0 = fopen("/sys/bus/iio/devices/iio:device0/in_voltage0_raw", "r");

    while(1){
            fread(&value_str, 6, 6, f0);
            value_int = strtol(value_str,NULL,0);
            printf("0 %li\n", value_int);
            fflush(stdout);

            usleep(5000);
            rewind(f0);
    }

Hoever, the cpu usage goes up really high (20%). Is there any way to read the analog inputs differently so that it doesn’t use as much CPU? Someone suggested “DMA” but I’m completely lost on that regard…

You should try the IIO driver which you will find under /driver/IIO/adc/ti_am335x_adc.c. Samples are stored in a buffer which you can read with a user space app.

Search github for IIO and you will find several user space examples on how to use IIO.

Regards,
John

I need to read all 7 analog pins in the BBB every 5 milliseconds. I’m doing so with the following C code:

void main(){
    char value_str[7];
    long int value_int = 0;

    FILE* f0 = fopen("/sys/bus/iio/devices/iio:device0/in_voltage0_raw", "r");

    while(1){
            fread(&value_str, 6, 6, f0);
            value_int = strtol(value_str,NULL,0);
            printf("0 %li\n", value_int);
            fflush(stdout);

            usleep(5000);
            rewind(f0);
    }

Hoever, the cpu usage goes up really high (20%). Is there any way to read the analog inputs differently so that it doesn’t use as much CPU? Someone suggested “DMA” but I’m completely lost on that regard…

Here is some additional info on IIO that might be helpful:

http://processors.wiki.ti.com/index.php/AM335x_ADC_Driver%27s_Guide

Regards,
John

Hi,

Please correct me if I’m wrong, but this is my understanding with a 3.14.x or newer kernel:

Since it looks like you want continuous sampling you might want to use the hardware buffer in iio.
Normally you would use something like the generic_buffer.c [1] as a sample application, but the events were removed from the ti iio driver, so you need to hack the generic test a bit. Here [2] you can find a patch [3] based on which you can create your own patch against 3.14.x

Like this you should be able to let the driver A/D sample and form user space you should be able to read things whenever your process runs.
I don’t know your exact problem, but a real-time solution might be needed if you want to get every A/D sample of 7 channels every 5 ms.

Please let me know how things go.

Regards,

Robert

[1] https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/drivers/staging/iio/Documentation/generic_buffer.c?id=refs/tags/v3.14.4

[2] http://processors.wiki.ti.com/index.php/AM335x_ADC_Driver's_Guide
[3] http://processors.wiki.ti.com/images/a/ab/Generic_buffer.patch

Check out libpruio. It makes a PRUSS fetching ADC data.

Using default ADC settings you get 10 ksamples per channel, so ~1.4 ksamples for 7 channels (0.7 ms). Additionally you can customize the ADC settings (open- and sample delay, as well as averaging) to optimize for your purposes.

Thanks everyone for your replies! I will spend friday and saturday experimenting and will report back here with my findings and probably more questions :slight_smile:

I ended up using libpruio, the installation instrucions are kind of scattered but it works really well. Thanks!

Thanks for feedback. Feel free to mail your suggested improvements for the installation instructions.

Rafael,

Can you please post detailed instructions on installing libruio.

Thanks
Srikant

I can take the time to do so tomorrow. Stay tuned :slight_smile:

Here’s what I did:

  1. Install FreeBasic compiler in BBB

1.1. Download package from http://www.freebasic-portal.de/downloads/fb-on-arm/bbb-fbc-fbc-fuer-beaglebone-black-283.html

wget http://www.freebasic-portal.de/dlfiles/452/bbb_fbc-0.0.2.tar.xz

1.2. Uncompress and copy files

cd bbb_fbc-0.0.2
cp usr/local/bin/fbc /usr/local/bin/
cp -R usr/local/lib/freebasic /usr/local/lib/

  1. Install pruss driver kit for freebasic and BBB.

2.1. Download and uncompress package from http://www.freebasic-portal.de/dlfiles/539/FB_prussdrv-0.0.tar.bz2

2.2. Copy files

cd FB_prussdrv-0.0
cp bin/libprussdrv.* /usr/local/lib
ldconfig
mkdir /usr/local/include/freebasic/BBB
cp include/* /usr/local/include/freebasic/BBB
cp bin/pasm/usr/local/bin
cp bin/PRUSSDRV-00A0.dtbo /lib/firmware

2.3. Install am335x-pru-package

apt-get install am335x-pru-package

2.4. Activate the PRUSS by enabling the tree overlay. This must be done everytime, after each boot or before running your programs.

echo PRUSSDRV> /sys/devices/bone_capemgr.9/slots

  1. Install libpruio

3.1. Download and uncompress package from http://www.freebasic-portal.de/dlfiles/554/libpruio-0.0.2.tar.bz2

3.2. Copy files

cd libpruio-0.0.2
cd src/c_wrapper/
cp libpruio.so /usr/local/lib
cp libpruio.a /usr/local/lib
ldconfig
cd …/pruio/
cp pruio.bi /usr/local/include/freebasic/BBB
cp pruio.hp /usr/local/include/freebasic/BBB
cp pruio_pins.bi /usr/local/include/freebasic/BBB

  1. Here’s a simple example C program that uses the library

#include <stdio.h>
#include <unistd.h>
#include “pruio_c_wrapper.h”
#include “pruio_pins.h”

int main(int argc, const char *argv[]) {
PruIo *io = pruio_new(0, 0x98, 0, 1);
if (io->Errr) {
printf(“Initialisation failed (%s)\n”, io->Errr);
return 1;
}

if(pruio_config(io, 0, 0x1FE, 0, 4, 0)){
printf(“Config failed (%s)\n”, io->Errr);
return 1;
}

int a = 0;
int i;
while(1){
printf("\r%12o %12o %12o %12o %4X %4X %4X %4X %4X %4X %4X %4X\n", io->Gpio[0].Stat, io->Gpio[1].Stat, io->Gpio[2].Stat, io->Gpio[3].Stat, io->Value[1], io->Value[2], io->Value[3], io->Value[4], io->Value[5], io->Value[6], io->Value[7], io->Value[8]);
fflush(STDIN_FILENO);
usleep(1000);
}

pruio_destroy(io);

return 0;
}

  1. To compile it, here’s a makefile:

all: bbb-io.c Makefile
gcc -Wall -o bbb-io bbb-io.c /usr/local/lib/freebasic/fbrt0.o -lpruio -L"/usr/local/lib/freebasic/" -lfb -lpthread -lprussdrv -ltermcap -lsupc++ -Wno-unused-variable

Hello Rafael,

thanks for your complete installation instructions. I plan to include them in the next version of the documentation, if you don’t mind (at least I like to add a link to your post here).

BTW: In your C code example the destructor pruio_destroy() wont be called in case of an error. This means that the devices wont be restored to their original states.

thanks for your complete installation instructions. I plan to include them in the next version of the documentation, if you don’t mind (at least I like to add a link to your post here).

Of course I don’t mind, go ahead and include it :slight_smile:

Hi, a maybee stupid question regarding this “howto”:

What kernel version is needed for this to work?
How to build kernel for pruss support?
Or is the dtbo file doing all the magic?

Reagrds,
Ben

I’m using a Debian Stable image downloaded from http://beagleboard.org/latest-images

Hi Ben!

Or is the dtbo file doing all the magic?

The dtbo file is pretty simple. It only powers on the PRUSS. Here’s the dts file to compile:

`
/* Minimal device tree overlay to activate PRUSS

Licence: GPLv3
(C) 2014 by Thomas{ DoT ]Freiherr[ aT ]gmx[ dOt }net

compile with
dtc -O dtb -o PRUSSDRV-00A0.dtbo -b 0 -@ PRUSSDRV.dts
*/
/dts-v1/;

/ {
compatible = “ti,beaglebone”, “ti,beaglebone-black”;
part-number = “PRUSSDRV”;
version = “00A0”;

fragment@0{
target = <&pruss>;

overlay {
status = “okay”;
};
};
};

`

All that ‘magic’ comes with the libpruio binary.

Cool, Thanks for the info.
When I have some more time i will try it out.
Regards, Ben