This works for me (using the am335x/sys_tscAdcSs.h header from the pru support package):
#include <stdint.h>
#include "sys_tscAdcSs.h"
static sysTscAdcSs volatile *adc;
// for complete compatibility with PRU
#undef ADC_TSC
#define ADC_TSC (*adc)
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
int main()
{
int fd = open( "/dev/mem", O_RDWR | O_CLOEXEC );
if( fd < 0 ) {
perror( "open /dev/mem" );
return 1;
}
adc = mmap( NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x44e0d000 );
if( adc == MAP_FAILED ) {
perror( "mmap" );
return 1;
}
close( fd ); // optional
printf( "ADC module identifier: 0x%08x\n", ADC_TSC.REVISION );
ADC_TSC.ADC_CLKDIV = 7; // configure clock divider to get 3 MHz adc clock
// etc, do remaining initialization here
return 0;
}
I would recommend using UIO instead of /dev/mem though, which is a mechanism that also allows userspace access to memory-mapped I/O, but limited to a single peripheral and without requiring root privileges. It also ensures the kernel will enable the module clock and if desired UIO can deliver interrupts to userspace.
I’ve added an example device tree overlay for this to my overlay-utils project: overlay-utils/adc.dtsi at master · mvduin/overlay-utils · GitHub
If you use this instead of whatever overlay you’re currently using to force-enable the ADC yet disable the ADC kernel driver (I’m assuming you do have one… right?) and, as mentioned in uio.h, install this uio.conf file into /etc/modprobe.d/, then after reboot there should be a uio device for the adc:
@beaglebone:~$ ls -l /dev/uio/adc
lrwxrwxrwx 1 root root 7 Sep 14 23:21 /dev/uio/adc -> ../uio0
(the actual uio device number may vary)
The only difference in usage is that you open the uio device instead of /dev/mem:
int fd = open( "/dev/uio/adc", O_RDWR | O_CLOEXEC );
and give offset 0 to mmap:
adc = mmap( NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );
Of course on the linux side you’re not restricted to using C, e.g. you could use my py-uio library, to which I’ve added a basic structure for the adc:
from uio.device import Uio
from uio.ti.subarctic.adc import Adc
adc_dev = Uio( "/dev/uio/adc" )
adc = adc_dev.map( Adc )
print( f'ADC module identifier: 0x{adc.ident:08x}' )
adc.clkdiv = 7 # configure clock divider to get 3 MHz adc clock