Saturday, 27 July 2013

Sampling analogue signals using the ADC on the Beaglebone Black


7 channels of the ADC are available on the expansion port of the Beaglebone Black. Accessing them can seem like a daunting task at first but it is quite simple once you get the hang of it.

The kernel that ships with the BBB as of 27 July doesn't support the stuff below. So compile one from the latest sources available at

If you don't know how to compile the latest kernel sources, check the following links for help on how to compile the kernel.

After booting the BBB, you have to configure the ADC pins and enable the Touchscreen/ADC (TSADC) module in the processor. This is done via the device tree(DT) files.

DT is a standard format since kernel 3.8 that tells the kernel what it needs to do to enable the TSADC module and configure the ADC pins.

Thanks to the great people at, you only need to do this
    echo BB-ADC > /sys/devices/bone_capemgr.*/slots

Check that it loaded correctly using dmesg
You can also list the current configured peripherals using

    cat /sys/devices/bone_capemgr.*/slots

Now checking the analogue value at one instant is simple
All you need to do is type the following

    cat /sys/bus/iio/iio:deviceX/in_voltageY_raw

where X is your adc device number and usually 0.
And Y is your analogue channel number.

Some people might be happy with one sample every once in a while in their applications.

However, the ADC is capable of much more. If you need to sample a signal continuously via a C/C++ application from the userspace, you are in luck.

The am335x driver is a standard IIO driver. And the IIO subsystem provides a sample test application to test the driver. Or in our case, to read from the driver.

The test application can be found in your kernel sources in the drivers/staging/iio/Documentation directory titled generic_buffer.c

Or if you want to take the easy route, check the following link for sources.

There are two parts to continuous sampling.
Configuring the ADC and the buffer.
Triggering the driver to tell it when to start filling in the buffer.

The IIO subsystem supports a trigger mechanism which is separate from the main ADC driver. The ADC driver supports any standard IIO trigger. And IIO provides trigger files which enable triggering via GPIOs or sysfs files.

Here I'll explain the sysfs way of doing things.

To add a sysfs trigger file type the following

    echo 1 > /sys/bus/iio/iio_sysfs_trigger/add_trigger

this creates a trigger directory in


Note: If you dont see this directory. You don't have a supported kernel. Compile the one using the latest sources.

Running the following pulses the trigger.

    echo 1 > /sys/bus/iio/trigger0/trigger_now
The trigger alone is useless. We need to connect this trigger to the adc driver.

Compile generic_buffer.c from the above github repo.

Then run the file using the following parameters

    ./generic_buffer -n TI-am335x-adc -t sysfstrig1 -l 128
The application searches for an IIO driver named 'TI-am335x-adc'.
Connects the trigger named "sysfstrig1" to the driver.
And configures the buffer size for 128 samples.

You might have noticed that you haven't exactly specified which channel you wish to sample. That is enabled separately via sysfs.

All this might seem confusing at first. But the IIO subsystem is designed to be highly configurable and adaptable to accommodate a variety of peripherals such as accelerometers, gyros, adcs etc.

Enabling which channel to sample using the triggered buffer mechanism is as simple as

    echo 1 > /sys/bus/iio/iio:deviceX/scan_elements/in_voltageX_en 

Where X is the channel number.

If you wish to enable another channel. Go ahead. The generic_buffer application will list both channels. Just note that the buffer is common for both channels.

e.g. 128 will result in 64 samples of 2 channels.

generic_buffer.c is just a starting point for your userspace application.
To sum up, you need to run the following to read continuously from the ADC.

    echo 1 > /sys/bus/iio/devices/iio_sysfs_trigger/add_trigger
    echo 1 > /sys/bus/iio/devices/iio\:device0/scan_elements/in_voltage7_en
    echo 1 > /sys/bus/iio/devices/iio\:device0/scan_elements/in_voltage5_en
    /home/root/main -n TI-am335x-adc -t sysfstrig1 -l 128 

And then run this in another terminal to trigger the driver to start sampling

    echo 1 > /sys/bus/iio/trigger0/trigger_now 

The generic_buffer application will display the length of samples.

Enjoy hacking with the BBB.
Leave a comment if you have a question or notice a bug somewhere.


  1. Nice. I got it all working with the 2013.07.31 angstrom demo files (which still uses the driver name tiadc rather than TI-am335x-adc).

    Trying to cross compiling the kernel on a mac is a bad idea...

    Any suggestions on how to set the sampling rate for continuous acquisition?

    1. An aspect I am not looking into at the moment.
      There is no interface at the moment. Max sampling I think.

      You'll have to check TRM and manually fix registers to your required rate..

    2. When I run generic_buffer, it reports that it can't find tiadc or TI-am335x-adc (I've tried both). I'm using the prebuilt systemd image, so I may be missing a required package. Any idea what it could be?

    3. Things have changed since this post. I have yet to update the blog..

      Sorry for the confusion.

      Also. You need the latest kernel uImage file for these.

    4. Hi, Fred. Do you bother to shed some light into cross compiling kernel on Mac? What was your setup and what would it be right now?

  2. Works with BBB-eMMC-flasher-2013.08.21.img.xz.
    "modprobe iio-trig-sysfs" is needed though.

    Several typos in the post, e.g.
    should be

    1. Thank-you for pointing it out.
      But the interface has changed significantly since this post.

      The linux kernel folk didn't like the trigger handling this way as it wasn't how iio usually handled triggers.

      Feel free to use this code if it works for you. But I'll be updating the blog soon with the new stuff.

  3. Is it possible to start ADC with the iio-trig-gpio (HW continuous mode) on BBB?
    Why "modprobe iio-trig-gpio" doesn't work on BBB?

    Thanks in advanve

    1. I haven't worked on gpio. I asked the iio mailing list and Lars Peter replied

      "You need to register a platform device for your IIO trigger, like this:

      static struct resource iio_gpio_trigger_resources[] = {
      [0] = {
      .start = IRQ_NR_FOR_YOUR_GPIO,

      static struct platform_device iio_gpio_trigger = {
      .name = "iio_interrupt_trigger",
      .num_resources = ARRAY_SIZE(iio_gpio_trigger_resources),
      .resource = iio_gpio_trigger_resources,


      Once you've done that the trigger will appear in the list of available
      triggers and you can assign it to your device."

    2. It's seems like you did that before: "....It took a while to restructure the driver".
      I'm wondering where to insert this struct ressource for register the iio-trig-gpio platform device: I have no information about that?
      Please I need some references for me to follow it step by step?
      Thank you in advance.

    3. I haven't done it before.
      if i remember correctly, you are looking for board-generic.c in arch/arm/mach-omap2/

    4. I can insert this modole (insmod iio-trig-gpio.ko) from the "/lib/modules/3.8.13/drivers/staging/iio/trigger/" directory and find it in the "/sys/module/iio_trig_gpio" like installed module; but it can't be activated like device in "/sys/bus/iio/devices/ directory". This is not the same with the iio-trig-sysfs module.
      Did you notice that before? Any help will be very welcome.
      Thank you again.

    5. Sorry I can't help out more. I have no experience. You could try emailing the IIO list.

  4. I'm using the tiadc driver with command " -n tiadc -t sysfstrig1 -l 128" and it is able to run the application with return some adc reading value, but the application only return 60++ value to me instead 128 sample adc value.Anything go wrong or i'm doing it wrongly?

  5. Lim Kean, You must have enabled two channels of the ADC.
    128 samples divided on 2 channels makes 64 samples each..

  6. Using this driver and your procedure I managed to get about 4000 samples per second. For sound capturing we need at least 16ksamples/s. Is there a way to do that ?

  7. The sampling frequency select side isn't set up in the driver. I am not sure what it has been set at in the code. Check the TRM. If I remember correctly, this is max sampling.

    also. Why do you wish to use the ADC for sound capturing?

    There is an Audio cape available. Needs a bit of a workaround to run with beaglebone black.
    And there are 10$ usb audio dongles that work..


  8. Hello-- Your code has a buffer overflow in iio_utils.h build_channel_array() which is always triggered. The problem occurs at the line
    fscanf(sysfsfp, "%u", &current->enabled);
    Even after the ci_array has been filled, the loop continues to check the remaining files, and while this happens "current" points *beyond* the end of the array. This fscanf() causes random memory to be stomped on and unpredictable behavior. I changed "current->enabled" to a local variable "current_enabled" and it worked fine then. Another way to solve the problem is end the loop after ci_array has been filled.

    1. Could you please post a patch on the IIO list and cc me as well?


  9. I'm not a member of iio mailing list, nor do I know where iio_utils.h came from other than your sample code. I posted a commit here which resolves the problem:

    Can you please forward as appropriate?

    1. Hi Craig,

      I forwarded your patch to the IIO mailing list and it has been accepted.

      The subsystem maintainer (Jonathan Cameron) was asking about your email address..

      Details here :


  10. sorry if this has already been covered... but ive spent a few literally sleepless nights so the brain is a little claged.. but shouldnt "echo BB-ADC > /sys/devices/bone_capemgr.*/slots" actually have a "9" rather than a "*" ? for me "*" did work till i tried adding it to my /etc/rc.local and it failed and after some more searching i found using the "9" got it working automatically (along with my w1 which is also in there)

    apologies if none of that is clear.... ill try my best to explain better in the morning

  11. Hi Zubair,

    I need to read all 7 analog inputs of the BBB every 5 milliseconds for a real-time
    audio app. However, reading using the usual file io interface to the analog pins consumes too much cpu. (See!category-topic/beagleboard/beaglebone-black/9NYdGWOT_Mg).

    Are the techniques discussed here still available in a current BBB build? I'm using Debian and here's the output of uname -a:

    Linux beaglebone 3.8.13-bone43 #1 SMP Wed Mar 26 14:21:39 UTC 2014 armv7l GNU/Linux

    Any pointers will be greatly appreciated since I'm in a bit of a dead end.


    1. Clarification: I wont use the ADCs to sample audio, but control signals

    2. Replied on the post!category-topic/beagleboard/beaglebone-black/9NYdGWOT_Mg

  12. This comment has been removed by the author.

  13. Hi Zubair,

    In response to

    ./generic_buffer -n tiadc -t sysfstrig1 -l 128

    this is what I get:

    iio device number being used is 0
    iio trigger number being used is 0
    Could not open /trigger/current_trigger
    Failed to write current_trigger file

    I verified that /trigger/current_trigger exists in the /iio/devices directory.

    I also tried:
    root@arm:/home/ubuntu# echo sysfstrig1 > /sys/bus/iio/devices/iio:device0/trigger/current_trigger

    root@arm:/home/ubuntu# cat /sys/bus/iio/devices/iio:device0/trigger/current_trigger

    Do you have any thoughts?

    Thanks in advance

    1. This is an old post. And trigger is not implemented by the driver anymore.

      to use the latest driver, you have to modify generic_buffer.c and remove the trigger checks

  14. When I run the generic buffer application, it says cannot find TI-am335x-adc.
    Is there any other other way I can read from the raw voltage files continuously at certain intervals of time?

    1. try

      ./generic_buffer -n tiadc -t sysfstrig1 -l 128

      instead of

      .generic_buffer -n TI-am335x-adc -t sysfstrig1 -l 128

    2. it depends on kernel versions. Naming conventions changed between 3.8 and 3.12..

      The name should be in sysfs somewhere