Originally posted by me on May 21, 2017
So, this is a variation on using GPIO, via direct memory access. The benefit to using this code, or similar. Is that there is only two syscalls for each line / mux select. Versus 12 syscalls if using the standard “Linux way” using open(), write(), read(), and close(). That’s PER pin. yikes. Keep in mind, I haven’t put a ton of thought into this code, so it could very well be rough around the edges, but it does work.
So for our particular application. We have a Line select for AIN6 on the beaglebone. As we needed more ADC channels. Again, for our own application, we needed 5 additional channels, with valid cmd line tool only accepting values 0-3, and 7. strtol() is set to base 16, so as not to interpret ASCII characters as the numerical value zero. Or potentially causing a seg fault. Put more correctly, if using base “10” as the numerical base value, values like 0x7, or absurdly large strings of characters could be interpreted as 0, and potentially something else undesirable.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#define GPIO0 (0x44E07000)
#define GPIO2 (0x481AC000)
#define GPIO_SIZE (0x2000)
#define GPIO_DATAOUT (0x13C)
#define GPIO_DATAIN (0x138)
#define MA0 (1<<26) /*gpio_0*/
#define MA1 (1<<23) /*gpio_2*/
#define MA2 (1<<24) /*gpio_2*/
void line_select(uint8_t asp_value)
{
void *gpio_addr;
unsigned int *bank0_out, *bank2_out;
int fd = open("/dev/mem", O_RDWR);
gpio_addr = mmap(0, GPIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO0);
bank0_out = gpio_addr + GPIO_DATAOUT;
gpio_addr = mmap(0, GPIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO2);
bank2_out = gpio_addr + GPIO_DATAOUT;
close(fd);
(asp_value & (1 << 0)) ? (*bank0_out |= MA0) : (*bank0_out &= ~(MA0));
(asp_value & (1 << 1)) ? (*bank2_out |= MA1) : (*bank2_out &= ~(MA1));
(asp_value & (1 << 2)) ? (*bank2_out |= MA2) : (*bank2_out &= ~(MA2));
printf("Line select: %u%u%u\n",
!!(*bank2_out & MA2), !!(*bank2_out & MA1), !!(*bank0_out & MA0));
}
int main(int argc, char *argv[])
{
if(argc != 2) exit(1);
int argv2 = strtol(argv[1], NULL, 16);
if(argv2 != 7){
if(argv2 < 0 || argv2 > 3) exit(1);
}
line_select(argv2);
return 0;
}
Output:
root@wgd:~/dl-i2c-test# nano tst.c
root@wgd:~/dl-i2c-test# gcc -Wall -o tst tst.c
root@wgd:~/dl-i2c-test# ./tst 0
Line select: 000
root@wgd:~/dl-i2c-test# ./tst 1
Line select: 001
root@wgd:~/dl-i2c-test# ./tst 2
Line select: 010
root@wgd:~/dl-i2c-test# ./tst 3
Line select: 011
root@wgd:~/dl-i2c-test# ./tst 4
root@wgd:~/dl-i2c-test# ./tst 0x7
Line select: 111
root@wgd:~/dl-i2c-test# ./tst 0xFF
root@wgd:~/dl-i2c-test# ./tst -1
root@wgd:~/dl-i2c-test#