We're no longer updating This wiki!!

This is an old revision of the document!


Using the ADC ports on 30pin header

There are two ADC inputs on the 30pin header provides 12-bit analog-to-digital converter.

CON10 - 2×15 pins

Pin Number Net Name GPIO & Export No
3 ADC_0.AIN0 XADC0AIN_0
23 ADC_0.AIN3 XADC0AIN_3

Using sysfs

Read raw data.(ADC Channel 0)

cat /sys/devices/12d10000.adc/iio:device0/in_voltage0_raw

Read raw data.(ADC Channel 3)

cat /sys/devices/12d10000.adc/iio:device0/in_voltage3_raw

Input voltage range is 0~1.8Volt. Otherwise your ODROID will be damaged permanently.

Using mmap

Example c source code

mmap_adc.c
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdint.h>
 
/* EXYNOS4412/5250 ADC_V1 registers definitions */
#define ADC_V1_DATAX		0x0C
 
/* Future ADC_V2 registers definitions */
#define ADC_V2_CON1		0x00
#define ADC_V2_CON2		0x04
#define ADC_V2_STAT		0x08
#define ADC_V2_INT_EN		0x10
#define ADC_V2_INT_ST		0x14
#define ADC_V2_VER		0x20
 
/* Bit definitions for ADC_V1 */
#define ADC_V1_CON_RES		(1u << 16)
#define ADC_V1_CON_PRSCEN	(1u << 14)
#define ADC_V1_CON_PRSCLV(x)    (((x) & 0xFF) << 6)
#define ADC_V1_CON_STANDBY	(1u << 2)
 
/* Bit definitions for ADC_V2 */
#define ADC_V2_CON1_SOFT_RESET	(1u << 2)
 
#define ADC_V2_CON2_OSEL	(1u << 10)
#define ADC_V2_CON2_ESEL	(1u << 9)
#define ADC_V2_CON2_HIGHF	(1u << 8)
#define ADC_V2_CON2_C_TIME(x)	(((x) & 7) << 4)
#define ADC_V2_CON2_ACH_SEL(x)	(((x) & 0xF) << 0)
#define ADC_V2_CON2_ACH_MASK	0xF
 
#define MAX_ADC_V2_CHANNELS	10
#define MAX_ADC_V1_CHANNELS	8
 
/* Bit definitions common for ADC_V1 and ADC_V2 */
#define ADC_CON_EN_START        (1u << 0)
#define ADC_DATX_MASK           0xFFF
 
#define EXYNOS_ADC_TIMEOUT      (msecs_to_jiffies(1000))
 
static volatile uint32_t *adc;
static uint32_t con1, con2;
void exynos_read_raw(unsigned char channel);
void exynos_adc_isr();
static int val;
 
int main(int argc, char **argv)
{
	int fd;
 
	if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
		printf("Unable to open /dev/mem\n");
		return -1;
	}
 
	adc = mmap(0, getpagesize(), PROT_READ | PROT_WRITE,
					MAP_SHARED, fd, 0x12D10000);
	if (adc < 0) {
		printf("mmap failed.\n");
		return -1;
	}
 
	// exynos_adc_hw_init
	con1 = ADC_V2_CON1_SOFT_RESET;
	*(adc + (ADC_V2_CON1 >> 2)) |= con1;
	con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL |
		ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(0);
	*(adc + (ADC_V2_CON2 >> 2)) |= con2;
 
	// Enable interrupts
	*(adc + (ADC_V2_INT_EN >> 2)) |= 1;
	while (1)
	{
		if (*(adc + (ADC_V2_INT_ST >> 2)) ^ 1) {
			exynos_read_raw(0);
			exynos_adc_isr();
		}
		sleep(1);
		printf("%d\n", val);
	}
 
	return 0;
}
void exynos_adc_isr()
{
	/* Read value */
	val = *(adc + (ADC_V1_DATAX >> 2)) & ADC_DATX_MASK;
	/* clear irq */
	*(adc + (ADC_V2_INT_ST >> 2)) |= 1;
}
 
void exynos_read_raw(unsigned char channel)
{
	con2 = *(adc + (ADC_V2_CON2 >> 2));
	con2 &= ~ADC_V2_CON2_ACH_MASK;
	con2 |= ADC_V2_CON2_ACH_SEL(channel);
	*(adc + (ADC_V2_CON2 >> 2)) |= con2;
 
	con1 = *(adc + (ADC_V2_CON1 >> 2));
	*(adc +(ADC_V2_CON1 >> 2)) = con1 | ADC_CON_EN_START;
}

Register Map Summary

NameOffsetDescriptionReset Value
ADC_CON10x0000ADC Control register0x0000_0002
ADC_CON20x0004ADC Configuration register0x0000_0720
ADC_STATUS0x0008ADC Status register0x0000_0000
ADC_DAT0x000CADC Data register0x0000_0000
ADC_INT_EN0x0010ADC Interrupt Enable register0x0000_0000
ADC_INT_STATUS0x0014ADC Interrupt Status register0x0000_0000
ADC_VERSION0x0020ADC Version information register0x8000_0008
en/xu3_hardware_adc.1453345278.txt.gz · Last modified: 2016/01/21 11:31 by john1117
CC Attribution-Share Alike 3.0 Unported
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0