How to tell the mode that P9, Pins 32 - 40 are in

Does anyone know how to tell the mode that P9.32 to P9.40 are in. The Beaglebone ‘bonescript’ doesn’t return a valid value for those particular pins. I need to read in analog voltages and have a program ready to go.

Thanks, David.

If you refer to the AM335x data sheet, you will find that there is no
mode setting for the analog input pins, they are always analog inputs
and do not have a pin control register.

Although you do have to properly enable the touch screen controller
and it's sequencing engine (typically done via loading the proper
kernel driver).

- --
Charles Steinkuehler
charles@steinkuehler.net

Update: I should comment that according to the BeagleBone Black reference manual https://github.com/CircuitCo/BeagleBone-Black/blob/master/BBB_SRM.pdf?raw=true , page 72, it shows that there is only 1 mode for these pins, but yet a DC input voltage doesn’t seem to register. I checked pin 3 and is putting out 3.3 V so it seems to be in mode 3, but I can’t verify on pins 32 to 40.

Thank you Charles, can you please point me somewhere that would explain how to enable the touch screen controller and kernel driver?

David

Load the default ADC driver by:

sudo su -c "echo cape-bone-iio > /sys/devices/bone_capemgr.*/slots"

Read the ADC values by:

cat /sys/devices/ocp.*/helper.*/AIN0

If you don't have the AIN[0-7] files in the ocp.*/helper.* directory
under sysfs, you don't have a proper device tree overlay loaded.

Note you can change the behavior and gain of the ADC readings based on
the device tree overlay you load. The cape-bone-iio overlay provides
millivolt readings (ie: 0 to 1800 for the 0.0V to 1.8V ADC input
range), which is less precision than the 4096 possible steps for a
12-bit ADC, but oh well. If you don't like it, make a custom overlay
with different gain settings.

- --
Charles Steinkuehler
charles@steinkuehler.net

This is odd, because this is what I am doing and I get the following:
-r–r--r-- 1 root root 4096 Jan 1 19:33 AIN0
-r–r--r-- 1 root root 4096 Jan 1 19:35 AIN1
-r–r--r-- 1 root root 4096 Jan 1 19:35 AIN2
-r–r--r-- 1 root root 4096 Jan 1 19:35 AIN3
-r–r--r-- 1 root root 4096 Jan 1 19:35 AIN4
-r–r--r-- 1 root root 4096 Jan 1 19:35 AIN5
-r–r--r-- 1 root root 4096 Jan 1 19:35 AIN6
-r–r--r-- 1 root root 4096 Jan 1 19:35 AIN7

But when I apply a DC 1 Volt to Pin 39 of expansion slot 9 (AIN0), and issue the cat /sys/devices/ocp./helper./AIN0 I get a value around 906 which I calculate to be about 0.22 Volts.

The other thing is that my program is probably not working because I just get 0’s for most columns. Any thoughts?

/*
Program to read in analog voltages

Sections of code taken from:
https://bwgz57.wordpress.com/2012/04/01/beaglebone-how-hot-is-it/
*/

// How to enable and use the analog to digital converter

// Step 1: Enable the drivers to activate the expansion slots
// echo cape-bone-iio > /sys/devices/bone_capemgr.*/slots

// Step 2: Read an analog input from AIN1 (Expansion P9, Pin 40)
// cat /sys/devices/ocp./helper./AIN1
//Should return a value between 0 and 4096

#include <stdio.h>
#include <fcntl.h>
#include <sys/time.h>
#include <time.h>
#include <math.h>

int main(void)
{

struct timeval tv;
double time_in_mill, start_time, sttime_ms;

long int start_timeint;

FILE *data_file;

int ret0, ret1, ret2, ret3, ret4, ret5, ret6, ret7;
int fd0, fd1, fd2, fd3, fd4, fd5, fd6, fd7;
//double v0, v1, v2, v3, v4, v5, v6, v7;
int v0, v1, v2, v3, v4, v5, v6, v7;

char buffer0[1024];
char buffer1[1024];
char buffer2[1024];
char buffer3[1024];
char buffer4[1024];
char buffer5[1024];
char buffer6[1024];
char buffer7[1024];
char filename[1024];

/* Open the channels */
fd0 = open("/sys/devices/ocp.2/helper.14/AIN0", O_RDONLY);
fd1 = open("/sys/devices/ocp.2/helper.14/AIN1", O_RDONLY);
fd2 = open("/sys/devices/ocp.2/helper.14/AIN2", O_RDONLY);
fd3 = open("/sys/devices/ocp.2/helper.14/AIN3", O_RDONLY);
fd4 = open("/sys/devices/ocp.2/helper.14/AIN4", O_RDONLY);
fd5 = open("/sys/devices/ocp.2/helper.14/AIN5", O_RDONLY);
fd6 = open("/sys/devices/ocp.2/helper.14/AIN6", O_RDONLY);
fd7 = open("/sys/devices/ocp.2/helper.14/AIN7", O_RDONLY);

/* Start a clock */
gettimeofday(&tv, NULL);
start_time = (double)(tv.tv_sec);
start_timeint = (long int)floor(start_time);
sttime_ms = (double)(tv.tv_usec)/1000000;

/* Generate a filename based on the time stamp*/
sprintf(filename,“data_%ld.txt”,start_timeint);

/* Open a file for the results */
data_file = fopen(filename,“w”);

if(!data_file)
{
printf(“Error Opening File… Exiting”);
return(1);
}

fprintf(data_file,“time\tch1\tch2\tch3\tch4\tch5\tch6\tch7\tch8\n”);

printf("\n");
printf(“Start Time = %f\n”,start_time);
printf("\n");
puts(“Program is running… Hit Control+C to stop\n”);

while (1)
{

ret0 = read(fd0, buffer0, sizeof(buffer0));
ret1 = read(fd1, buffer1, sizeof(buffer1));
ret2 = read(fd2, buffer2, sizeof(buffer2));
ret3 = read(fd3, buffer3, sizeof(buffer3));
ret4 = read(fd4, buffer4, sizeof(buffer4));
ret5 = read(fd5, buffer5, sizeof(buffer5));
ret6 = read(fd6, buffer6, sizeof(buffer6));
ret7 = read(fd7, buffer7, sizeof(buffer7));

/* Get current time */
gettimeofday(&tv, NULL);
time_in_mill = ((double)(tv.tv_sec) - start_time) + ((double)(tv.tv_usec)/1000000) - sttime_ms;

if (ret0 == -1)
{
printf(“Error:\n”);
printf("\tNote: Analog Acquisition Devices Must Be Enabled With The Following Command:\n");
printf("\n");
printf("\techo cape-bone-iio > /sys/devices/bone_capemgr./slots\n");
printf("\n");
return(1);
}
else
{
/
Buffer is a value between 0 and 4095 for voltages between 0 and 1.8 Volts */
buffer0[ret0] = NULL;
buffer1[ret1] = NULL;
buffer2[ret2] = NULL;
buffer3[ret3] = NULL;
buffer4[ret4] = NULL;
buffer5[ret5] = NULL;
buffer6[ret6] = NULL;
buffer7[ret7] = NULL;

//v0 = atoi(buffer0)*1.8/4095;
//v1 = atoi(buffer1)*1.8/4095;
//v2 = atoi(buffer2)*1.8/4095;
//v3 = atoi(buffer3)*1.8/4095;
//v4 = atoi(buffer4)*1.8/4095;
//v5 = atoi(buffer5)*1.8/4095;
//v6 = atoi(buffer6)*1.8/4095;
//v7 = atoi(buffer7)*1.8/4095;
//fprintf(data_file,"%f %f %f %f %f %f %f %f %f\n", time_in_mill, v0, v1, v2, v3, v4, v5, v6, v7);
v0 = atoi(buffer0);
v1 = atoi(buffer1);
v2 = atoi(buffer2);
v3 = atoi(buffer3);
v4 = atoi(buffer4);
v5 = atoi(buffer5);
v6 = atoi(buffer6);
v7 = atoi(buffer7);
fprintf(data_file,"%f %d %d %d %d %d %d %d %d\n", time_in_mill, v0, v1, v2, v3, v4, v5, v6, v7);
lseek(fd1, 0, 0);
}

}

/* Close the channels */
close(fd0);
close(fd1);
close(fd2);
close(fd3);
close(fd4);
close(fd5);
close(fd6);
close(fd7);

/* Close the file */
fclose(data_file);

}

A sample of the output looks like this (Note the 743 jumps around to other random values for AIN1)

time ch1 ch2 ch3 ch4 ch5 ch6 ch7 ch8
0.006933 905 0 0 0 0 0 0 0
0.007270 0 743 0 0 0 0 0 0
0.007418 0 743 0 0 0 0 0 0
0.007556 0 743 0 0 0 0 0 0
0.007691 0 743 0 0 0 0 0 0
0.007826 0 743 0 0 0 0 0 0
0.007958 0 743 0 0 0 0 0 0
0.008094 0 743 0 0 0 0 0 0
0.008333 0 743 0 0 0 0 0 0
0.008482 0 743 0 0 0 0 0 0
0.008621 0 743 0 0 0 0 0 0
0.008758 0 743 0 0 0 0 0 0
0.008895 0 743 0 0 0 0 0 0
0.009028 0 743 0 0 0 0 0 0
0.009163 0 743 0 0 0 0 0 0
0.009297 0 743 0 0 0 0 0 0
0.009432 0 743 0 0 0 0 0 0
0.009567 0 743 0 0 0 0 0 0
0.009703 0 743 0 0 0 0 0 0
0.009836 0 743 0 0 0 0 0 0
0.009971 0 743 0 0 0 0 0 0
0.010105 0 743 0 0 0 0 0 0
0.010319 0 743 0 0 0 0 0 0
0.010466 0 743 0 0 0 0 0 0
0.010604 0 743 0 0 0 0 0 0
0.010738 0 743 0 0 0 0 0 0
0.010873 0 743 0 0 0 0 0 0
0.011007 0 743 0 0 0 0 0 0
0.011142 0 743 0 0 0 0 0 0
0.011275 0 743 0 0 0 0 0 0
0.011409 0 743 0 0 0 0 0 0
0.011543 0 743 0 0 0 0 0 0
0.011679 0 743 0 0 0 0 0 0
0.011813 0 743 0 0 0 0 0 0
0.011948 0 743 0 0 0 0 0 0
0.012081 0 743 0 0 0 0 0 0
0.012289 0 743 0 0 0 0 0 0
0.012435 0 743 0 0 0 0 0 0
0.012573 0 743 0 0 0 0 0 0
0.012709 0 743 0 0 0 0 0 0
0.012846 0 743 0 0 0 0 0 0
0.012982 0 743 0 0 0 0 0 0
0.013115 0 743 0 0 0 0 0 0
0.013250 0 743 0 0 0 0 0 0
0.013382 0 743 0 0 0 0 0 0
0.013518 0 743 0 0 0 0 0 0

If you're using the default cape-bone-iio-00A0.dtbo, the gain is set
to produce millivolt outputs (ie: 0-1800 and *NOT* 0-4095).

Also, I found it is necessary to close and re-open the AINx file, just
seeking back to zero doesn't get you a new value, which is why the one
value you're getting back never changes.

You're getting zeros on the other channels because you're only
lseek'ing back to the file start on fd1, so after the first read
everything but channel 1 is null and you're not properly handling the
fact that your call to read() didn't actually _read_ any data.

- --
Charles Steinkuehler
charles@steinkuehler.net

Thank you Charles. I will look into this. One question, is 1800 getting divided across 4096? I don’t see how that can be if the value returned is an integer, or is it a float?

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

This is odd, because this is what I am doing and I get the
following: -r--r--r-- 1 root root 4096 Jan 1 19:33 AIN0 -r--r--r--
1 root root 4096 Jan 1 19:35 AIN1 -r--r--r-- 1 root root 4096 Jan
1 19:35 AIN2 -r--r--r-- 1 root root 4096 Jan 1 19:35 AIN3
-r--r--r-- 1 root root 4096 Jan 1 19:35 AIN4 -r--r--r-- 1 root
root 4096 Jan 1 19:35 AIN5 -r--r--r-- 1 root root 4096 Jan 1
19:35 AIN6 -r--r--r-- 1 root root 4096 Jan 1 19:35 AIN7

But when I apply a DC 1 Volt to Pin 39 of expansion slot 9 (AIN0),
and issue the cat /sys/devices/ocp.*/helper.*/AIN0 I get a value
around 906 which I calculate to be about 0.22 Volts.

If you're using the default cape-bone-iio-00A0.dtbo, the gain is set
to produce millivolt outputs (ie: 0-1800 and *NOT* 0-4095).

Also, I found it is necessary to close and re-open the AINx file, just
seeking back to zero doesn't get you a new value, which is why the one
value you're getting back never changes.

That's not what I've found. One can keep the files open and use lseek!
But a read will fail every now and then. This seems to be a transient error
and the next will probably succeed!

You can also use the raw devices in "/sys/bus/iio/devices/iio:device0/", these are 0..4095 / unscaled.

-- Bas

Also, I found it is necessary to close and re-open the AINx file,
just seeking back to zero doesn't get you a new value, which is why
the one value you're getting back never changes.

That's not what I've found. One can keep the files open and use
lseek! But a read will fail every now and then. This seems to be
a transient error and the next will probably succeed!

Ah...perhaps that's a python only thing, trying to be too smart for
it's own good and optimizing away the actual file read. :-/

You can also use the raw devices in
"/sys/bus/iio/devices/iio:device0/", these are 0..4095 /
unscaled.

Thanks! I missed that somehow...that will help a lot!

- --
Charles Steinkuehler
charles@steinkuehler.net

The value returned is an ascii string.

The code that generates the ascii string can be found in the iio_helper
module in the kernel source tree. The relevant bit is:

static ssize_t iio_helper_show_mvolts(struct device *dev,
                struct device_attribute *attr, char *buf)
{
        struct iio_helper_chan *chan = iio_helper_attr_to_chan(attr);
        int ret, val;
        u32 mvolts;

        ret = iio_read_channel_raw(chan->vsense_channel, &val);
        if (ret < 0)
                return ret;

        /* volts = ((1800 / 4096) * val * scale) = (1.8 * val * scale /4096) */
        mvolts = div_u64(1800 * chan->vsense_scale * (u64)val, 4096 * 100);

        return sprintf(buf, "%d\n", mvolts);
}

- --
Charles Steinkuehler
charles@steinkuehler.net

That makes sense as to why we need the ‘atoi’ functions. I should have realized it. Thank you. I will keep working on it, but it does seem to be working now. It’s down to a matter of sampling rate.

Thank you, David.