Using Analog inputs in CPP

I am trying to get the ADC configured so I can use it in a CPP app.
I am monitoring the voltage of a battery so speed and precision are not major requirements.

I have found various articles but I suspect they are not up to date and so I get stuck trying to follow them.

The articles show testing the ADC from the CLI so I thought I would start with this and then progress to my CPP app.

Here is the contents of my BB-ADC-00A0.dts file

> // SPDX-License-Identifier: GPL-2.0-only
> /*
>  * Copyright (C) 2012 Texas Instruments Incorporated -
>  */
> /dts-v1/;
> /plugin/;
> /*
>  * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/
>  */
> &{/chosen} {
>     overlays {
> = __TIMESTAMP__;
>     };
> };
> &tscadc {
>     status = "okay";
>     adc {
>         ti,adc-channels = <0 1 2 3 4 5 6 7>;
>         ti,chan-step-avg = <16 16 16 16 16 16 16 16>;
>         ti,chan-step-opendelay = <0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98>;
>         ti,chan-step-sampledelay = <0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0>;
>     };
> };

Comparing to the source in Beaglebone Black ADC: Reading Analog Voltages | Microcontroller Tutorials there are some differences. Should I make these changes or are they redundant now as the AINx pins are not configurable with the modes?
I also note there is no AIN5, is this correct? (I only need two analog inputs).

Following another link I added into /boot/uEnv.txt:
and rebooted
In my case should this be set to BB-ADC-00A0?

I ran: sudo find / -type d -name scan_elements
and found : /sys/devices/platform/ocp/44e0d000.tscadc/
inside this directory I have the following files:
in_voltage0_en in_voltage1_type in_voltage3_index in_voltage5_en in_voltage6_type
in_voltage0_index in_voltage2_en in_voltage3_type in_voltage5_index in_voltage7_en
in_voltage0_type in_voltage2_index in_voltage4_en in_voltage5_type in_voltage7_index
in_voltage1_en in_voltage2_type in_voltage4_index in_voltage6_en in_voltage7_type
in_voltage1_index in_voltage3_en in_voltage4_type in_voltage6_index

I haven’t connected up a pot to an input yet but I am not sure which file type to read; _en, _index, _type
sudo cat in_voltage1_index
sudo cat in_voltage1_type
sudo cat in_voltage1_en

Can you please correct / confirm the above or point me to an up to date article on this.

Also an example of a CPP app reading the ADC without needing root access would be much appreciated.


1 Like


From what I understand, once these Pins are allocated, they are ready for use. I found an older model of the BB-ADC-00A0.dts file. It will be listed.

Then, I will show you what my /sys/devices/platform/ocp/ files show. It may be helpful.

// SPDX-License-Identifier: GPL-2.0-only
 * Copyright (C) 2012 Texas Instruments Incorporated -


 * Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/
&{/chosen} {
        overlays {
                BB-ADC-00A0.kernel = __TIMESTAMP__;

&tscadc {
        status = "okay";
        adc {
                ti,adc-channels = <0 1 2 3 4 5 6 7>;
                ti,chan-step-avg = <16 16 16 16 16 16 16 16>;
                ti,chan-step-opendelay = <0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98>;
                ti,chan-step-sampledelay = <0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0>;

From what I understand, the AIN (analog) pins are ready with that specific overlay from above. Now, calling it from a file is different. Let me show you my kernel and /boot/uEnv.txt file and image.

image: Debian Buster IoT Image 2020-04-06
kernel: 5.10.100-ti-r37




###U-Boot Overlays###
###Master Enable
###Overide capes with eeprom
###Additional custom capes
###Custom Cape
###Disable auto loading of virtual capes (emmc/video/wireless/adc)

So, I think cape_enable=bone_capemgr.enable_partno=BB-ADC is incorrect for now. They left the slots files alone while compiling images for whatever reason. It is done for now. That may be old news but, and I hate to say it, what I am discussing may be old news too. We shall see.


P.S. /proc/device-tree/chosen/overlays is where the entry in the /boot/uEnv.txt file should be allocated towards. So, once listed in /boot/uEnv.txt, your AIN pins are working and running.

I will get back to this post soon on file descriptors and how to call it in C/C++, hopefully. I am sure there are some other folks out there who already know. I have not been following the AIN-analog-iio, kernel changes well enough.

I forgot to show you the /sys/devices/platform/ocp/ files:

40300000.sram           ocp:P8_13_pinmux  ocp:P9_11_pinmux
44c00000.interconnect   ocp:P8_19_pinmux  ocp:P9_13_pinmux  ocp:P8_20_pinmux  ocp:P9_14_pinmux  ocp:P8_21_pinmux  ocp:P9_15_pinmux
47c00000.interconnect   ocp:P8_22_pinmux  ocp:P9_16_pinmux
48000000.interconnect   ocp:P8_23_pinmux  ocp:P9_17_pinmux  ocp:P8_24_pinmux  ocp:P9_18_pinmux  ocp:P8_25_pinmux  ocp:P9_19_pinmux  ocp:P8_27_pinmux  ocp:P9_20_pinmux  ocp:P8_28_pinmux  ocp:P9_21_pinmux
4a000000.interconnect   ocp:P8_29_pinmux  ocp:P9_22_pinmux
4a326004.pruss-soc-bus  ocp:P8_30_pinmux  ocp:P9_23_pinmux
4b144400.interconnect   ocp:P8_31_pinmux  ocp:P9_24_pinmux
4c000000.emif           ocp:P8_32_pinmux  ocp:P9_25_pinmux  ocp:P8_33_pinmux  ocp:P9_26_pinmux  ocp:P8_34_pinmux  ocp:P9_27_pinmux  ocp:P8_35_pinmux  ocp:P9_41_pinmux
driver_override         ocp:P8_36_pinmux  ocp:P9_42_pinmux
modalias                ocp:P8_37_pinmux  ocp:P9_91_pinmux
ocp:cape-universal      ocp:P8_38_pinmux  ocp:P9_92_pinmux
ocp:P8_03_pinmux        ocp:P8_39_pinmux  of_node
ocp:P8_04_pinmux        ocp:P8_40_pinmux  power
ocp:P8_05_pinmux        ocp:P8_41_pinmux  subsystem
ocp:P8_06_pinmux        ocp:P8_42_pinmux  supplier:platform:fixedregulator0
ocp:P8_07_pinmux        ocp:P8_43_pinmux  supplier:platform:fixedregulator@2
ocp:P8_08_pinmux        ocp:P8_44_pinmux  uevent
ocp:P8_09_pinmux        ocp:P8_45_pinmux
ocp:P8_10_pinmux        ocp:P8_46_pinmux

I went into some files, say ocp:P8_33_pinmux, and found little to nothing so far. Just this:

driver driver_override modalias of_node power state subsystem uevent

Hi Silver2row
I managed to get it going. Thanks for your help.

Hello Sir,

Seth here. Did anything I show you help out at all? I kind of put off handling the ADC on the BBB since the Adafruit_BBIO lib. has been having issues. This is really the only lib. I have used on the BBB and I am learning more slowly.

I am starting to handle Linux based fd and other ways to intervene in source too.

Anyway, I am glad you got things going. Tell me! How did you do it?

Was it in a self-made .dts file turned .dtbo or in another method?


P.S. I think bone-buses may provide an overlay too. I would have to check into this idea.

Hi Seth
Based on your email:
I added uboot_overlay_addr1=/lib/firmware/BB-ADC-00A0.dtbo to /boot/uEnv.txt
and I removed cape_enable=bone_capemgr.enable_partno=BB-ADC

I found a link which runs cat in_voltage0_raw from the /root@arm:/sys/bus/iio/devices/iio:device0 directory

But I don’t have this directory structure.

I had a reference which advised to run
sudo find / -type d -name scan_elements.
Using this I went to directory
cd /sys/devices/platform/ocp/44e0d000.tscadc/

Then I looked in the directory above stopping at …/iio:device0 and found the in_voltageX_raw files

SO from /sys/devices/platform/ocp/44e0d000.tscadc/ I ran cat in_voltage0_raw and got similar readings.

I added a pot and a series resistor between 3.3V and ground into AIN1 and found the values changed as expected.

I wrote some CPP test code as follows:

> float blockADCChannel(char channel) {
> 	float valueFloat = -1;
>     // debugPrintln("Read ADC Channel: %c", channel);
>     FILE* pFile;
> 	std::string fileName = "/sys/devices/platform/ocp/44e0d000.tscadc/";
> 	fileName.append(1, channel);
> 	fileName.append("_raw");
> 	// debugPrintln("ADC FileName: %s", fileName.c_str());
>     pFile = fopen(fileName.c_str(), "rb");
> 	if (pFile!=NULL) { // success
> 		char* ss(new char[11]);
> 		auto readLen = fread(ss, 1, 10, pFile);
> 		if (readLen > 1) { // more than EOL
> 			ss[readLen-1] = '\0';
> 			// debugPrintln("ADC Read: %d %s", readLen, ss);
> 			fclose(pFile);
> 			valueFloat = std::strtof(ss, NULL) / 4096 * 1.8; // 12 bit ADC with 1.8V reference
> 			// debugPrintln("ADC Read: %.2f", valueFloat);
> 			return valueFloat;
> 		}
> 	}
> 	return valueFloat;
> }

This returns the analog voltage reading on AN1 and matches my multi-meter perfectly.

Again thanks for your help.

1 Like


You rule. Thank you for clarifying and additional source. That source is a bit out of my level of knowledge but in time, I can look it up.


P.S. Neat. I never knew the base source for some .cpp file for analog to digital conversion could be so compact and relevant.

Another option… libiio has c bindings…

They have other examples, sorry we don’t have a direct example for our hardware ready to go…


1 Like

Another option… libpruio has c bindings…

There’re other examples, for BB hardware ready to go …