Homepage Wiki Forum Buy

AD-converter

From GNUBLIN

severity (level) requirement Gnublin family
Gnublin logo advanced.png Kernel compile, Toolchain All

Contents

Note

Some boards have an incorrect resistor mounted. This reduces the full range of the AD converter to 0 .. ~1.6V. R19 should have 10 Ohm, but actually is 10 kOhm. In the german magazin "Elektor" of 1/2013 is a hint to solder two capacitors with 10µF and 100nF on R19 to Ground.

Wiederstand gnublin.png


For Beginners (with Gnublin-Distribution)

You can use the program gnublin-adcint to read out the internal ADC channels.

To get the actual voltage value on pin GPA1 you can type the following into your terminal:

gnublin-adcint -c 1

You will get the following or slightly different output (depending on your voltage value):

3049 mV

The LPC3131 has 4 internal AD-Converters (Channel 0 - 3 )

If you want to read out the voltage value of GPA3 (AD-Converter channel 3) you can run the following command:

gnublin-adcint -c 3

With the command

gnublin-adcint -h

you get this overview of all parameters:

-h Show this help -b show raw output -j Convert output to json format -c <x> Select gpa<x> Pin (0 - 3 possible, default is 1) -d Choose Path to device file

Without the distribution

Load the driver

Hint: On the standard SD card of Gnublin, these steps have already been done by the system. You can skip this step, provided you have not build your own kernel.


The driver for the adc was implemented by Michael Schwarz and Nils Stek. You can follow the developmental history on microcontroller.net [1]. The driver will be loaded as a kernel module as follows:

root@gnublin:~# modprobe lpc313x_adc

After loading the driver, following message will appear:

[lpc313x adc] driver loaded with major 253
[lpc313x adc] >> $ mknod /dev/lpc313x_adc c 253 0


The second line remembers you to make a device node. First check if it is not existing with ls /dev.


It could also happen, that the driver was already loaded at boot time. If this is the fact it should be in the config file /etc/modules:

root@gnublin:~# cat /etc/modules
...
lpc313x_adc
...


Which drivers are already loaded into the kernel you can see with lsmod. On Gnublin the output looks like follows:

root@gnublin:~# lsmod
Module Size Used by
lpc313x_adc 3766 0
pegasus 16772 0
mii 3416 1 pegasus

The experiments can start...

First we connect the potentiometer with Gnublin:

Adc-poti.png


The potentiometer meets a variable voltage divider, which creates a voltage from 0 to 3,3V and is connected to GPA1.

Attention: The voltage on GPA1 must not overstep 3,3V!!!


The shell

It's the simpliest way to read analog values. First you have to choose the analog input GPA1:

root@gnublin:~# echo "1" > /dev/lpc313x_adc

After that it's possible to read the analog values

root@gnublin:~# cat /dev/lpc313x_adc

The output is simply a hexadecimal number like

0x3b2

The default resolution of the adc is 10 bit. Thereby the values which can be read are between 0 and 0x3ff (decimal 0-1023). The transformer can even work with 8 bit or 4 bit resolution.More information is written down in the LPC313 User Manual. The README file of this driver describes how to change settings of the adc.


Python

A simple Python application to controll the adc, looks like follows( you can finde this example in /root/examples/misc/adc/adc.py:

import os

DEVICE = '/dev/lpc313x_adc'

def select_gpa1():
   fd = os.open(DEVICE, os.O_RDWR)
   os.write(fd, "0x0001")
   os.close(fd)

def get_adc():
   fd = os.open(DEVICE, os.O_RDONLY)
   av = os.read(fd, 256)
   os.close(fd)
   return av[:-1]  # strip off trailing '\n'

if __name__ == "__main__":
   select_gpa1()
   ad_val = get_adc()
   print ad_val


The returned Hex-String (e.g. 0x37b) can simply transformed into a number. Therefore you use the function int(val,16).

Actually the driver reads the adc value, by opening the corresponding device file. So you have pass everytime the same cycle(open, read, close the device file). If you make a time measure within reading 1000 adc values, it would take around one second. It's logicall, that the powerful interpreter language is not as fast as a C written application.

A useful pattern in order to measure periods of time in Python is

import time
t1 = time.clock()
...
t2 = time.clock()
print t2 - t1

Latencies can be build with time.sleep(), e.g. the following line causes a 0,3 second latency:

time.sleep(0.3)


More information offers the Python standard library for time functions [2].

ADC in C

Sample function to select the ADC-chanel and return the ADC-value as integer:

#include <fcntl.h> /* O_RDONLY=0 O_RDWR=2 */
#include <stdio.h> /* sscanf() */
#include <stdlib.h> /* EXIT_FAILURE=1 EXIT_SUCCESS=0 */
#include <unistd.h> /* close() read() write() */

int selectADC( int chanel ) {
	if ( chanel < 0 || chanel > 3 ) { return EXIT_FAILURE; }

	int fd;
	int ret;
	char sChanel[2] = { '0' + chanel , '\0' };
	
	fd = open( "/dev/lpc313x_adc" , O_RDWR );
	if ( fd < 0 ) { return EXIT_FAILURE; }
	ret = write( fd , sChanel , sizeof(sChanel) );
	if ( ret != sizeof(sChanel) ) { close( fd ); return EXIT_FAILURE; }
	ret = close( fd );
	if ( ret != EXIT_SUCCESS ) { return EXIT_FAILURE; }
	
	return EXIT_SUCCESS;
}

int getADC( void ) {
	int fd;
	int ret;
	int val;
	char sVal[6]; /* { '0' , 'x' , '3 ' , 'F' , 'F' , '\0' } */
	

	fd = open( "/dev/lpc313x_adc" , O_RDONLY );
	if ( fd < 0 ) { return -1; }
	ret = read( fd , sVal , sizeof(sVal) );
	if ( ret != sizeof(sVal) ) { close( fd ); return -2; }
	ret = close( fd );
	if ( ret != EXIT_SUCCESS ) { return -3; }

	ret = sscanf( sVal , "0x%x" , &val );
	if ( ret != 1 ) { return -4; }
	
	return val;
} 

An other code of the examples:

You can finde these in the folder /root/examples/misc/adc under the name adc.c.

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>

unsigned char buffer[256];

void select_gpa1()
{
   /* select ADC 1 */
   fd = open("/dev/lpc313x_adc", O_RDWR);
   write(fd, "1", 2);  /* "1\0" */
   close(fd);
}

int get_adc()
{
   fd = open("/dev/lpc313x_adc", O_RDONLY);
   n = read(fd, buffer, 256);
   close(fd);
   return n;
}

The function get_adc() returns the number of characters read (inclusive '\n' at the end). The C application takes for 1000 Readcycles only 0,18 seconds, about 5 times faster than the Python application.

In other languages