Originally posted by me on May 10, 2017
So this bit may seem a little odd to some. Hell I know the hardware, and wrote this really quick snippet as a demonstration, and I think it’s odd. The short story here. Is that we have a pin multiplexer on AIN6, and this multiplexer selects an external channel based on a bit pattern sent to it through 3 GPIO pins. That code I won’t be showing in this post. but I wanted to point out why I have an odd “mvolts” value. Which indicates maximum input voltage before the voltage limiting resistor network. e.g. the on board ADC pins can only handle 1.8v absolute maximum voltage, and I’m pretty sure without all circuitry voltage drop, outside maximum voltage is supposed to be 0-10v, and wulf probably designed the voltage into the ADC it’s self to be less than 1.5v . . . So I started with 10v in mind, saw the reading was definitely too high, and then played a guessing game until the voltage I read from a volt meter, matched what I was reading through the ADC. So there is definite resolution loss here . . .
Anyway, the best and easiest way to load drivers for the ADC is to load the stock ADC overlay from /lib/firmware/.
root@wgd:~# ls /lib/firmware/ |grep ADC
BB-ADC-00A0.dtbo
That is the file to load. Which can be loaded through capemgr via the command line manually, or from /boot/uEnv.txt at boot.
ADC C code:
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
const char *ain6 = "/sys/bus/iio/devices/iio:device0/in_voltage6_raw";
int main()
{
int fd;
int len;
char adc[5] = {0};
float madc = 4095.0f;
float mvolts = 7.7f;
float bvolts = (mvolts / madc);
fd = open(ain6, O_RDONLY);
if(fd == -1){
perror("ain6");
exit(1);
}
len = read(fd, adc, sizeof(adc - 1));
int adc_val = strtol(adc, NULL, 10);
float voltage = adc_val * bvolts;
printf("%f \n", voltage);
close(fd);
return 0;
}
Output:
root@wgd:~# gcc -Wall -o adc adc.c
adc.c: In function 'main':
adc.c:14:6: warning: variable 'len' set but not used [-Wunused-but-set-variable]
int len;
^
root@wgd:~# ./adc
0.030085
A couple things to notice here. First is the warning I’m getting back from the compiler. This is because I’m using the -Wall option, which pretty much tells the compiler to use strict reporting of warnings. It is my belief that one should always at least use the -Wall compiler flag. Then we should treat these warning as if they’re errors, and correct them. Which( and yeah I hate explanations like this too ) I’m ignoring for this one situation. Basically “len” is a return value from read() which can let us know how many bytes were read out of the file, and we absolutely should test this value for a non negative number. Then act on negative numbers as an error, which could be done a few different ways. For this demo, I was not sure in a pinch what would be a better way to handle that potential error. Mostly because I know these values will always be 0-4095, unless there is a problem with the hardware. At which point we’re done anyhow( probably a blown processor ). One way to deal with this kind of error, would be to use perror() followed by exit(errno) in an if block. But at this point I’m fairly confident the system would not be running anyway . . .However, the values coming out of the ADC module should always be 1-4 characters, so how do we test for no characters ? NULL, but if we’re reading out a NULL, how did our code make it thus far anyhow ? Additionally, if we’re reading more than 4 character . . .Not only do I believe this to be impossible because of the way I wrote this code, but if it were somehow possible. We’d have a buffer overrun. Which may be a very good idea to test for. If for nothing else, good practice ? You decide.
Secondly, the really low, but not absolute zero value. Well, I’ve come to realize that when working with circuits of this nature, that can not be tied to ground, or pulled high. You’re basically “floating” but close to a low, or a high . . . again, I’m not exactly an EE, so maybe someone who cares to can elaborate further. But I always think of this sort of situation as induced parasitic voltages from the circuitry. I’m definitely all ears if someone has a better explanation, or insight into this. . .But I’ve tested these readings against a volt meter, and am reasonably happy that I’m “close enough” for my own purposes. Someday, perhaps I’ll buy a USB computer style Oscilloscope, in hopes to enlighten myself further..