通道选择
由上图可知,A/D控制器一共有4个通道,通用寄存器地址为0x126c0000。
A/D控制器寄存器
对ADC控制器的操作主要是通过配置寄存器来实现的,查看datasheet,必须掌握寄存器的使用。以下是A/D控制器寄存器汇总。
1、A/D控制寄存器ADCCON
RES : 选择A/D转换精度,0:划分成1024份 1:划分成4096份
ECFLG :转换是否结束 0:转换中 1:转换完毕;对于轮询模式需要根据该位判断数据是否转换完毕。
PRSCEN:A/D转换预分频是否使能
PRSCVL:预分频的值,转换公式见下面
STANDBY:待机模式 0:正常工作模式 1:待机模式。处于待机模式时要将PRSCEN设置为0
READ_START: A/D转换由读操作触发,设置为1后,每次读取A/D值的操作都会触发一次A/D转换。
ENABLE_START: 单次开启A/D转换,转换完毕后该位自动清零,当READ_START设置为1的时候,该位无效。
通常设置值为(1 << 16 | 1 << 14 | 99 <<6 | 1 << 1)。
2、A/D转换数据寄存器ADCDAT0
注意该寄存器的值只有低12位有效。
3、A/D清中断寄存器CLRINTADC
黄色部分可知,中断例程负责清中断,中断结束后写入任意值就可以清中断。
4、A/D通道选择寄存器ADCMUX
每次操作都要先设置通道,因为 4个通道是共用同一套寄存器,如果有其他任务也在使用A/D,就会产生混乱。在此我们选择通道3,置3即可。
5、ADC中断ID
参见9.2.2GIC Interrupt Table
由此可知,ADC中断号对应的SPI值是10,inturrupt ID 为42。对于终端查询方式和编写终端的驱动需要知道SPI id和inturrupt ID,后面讲解基于Linux驱动还会再分析设备树节点如何填写。
6、Combiner中断控制器
combiner的配置寄存器:IMSRn、IECRn、ISERn、ISTRn,类似于GPIO 对中断源分组。只有中断模式才需要考虑combiner中断控制器的操作。
7、Combiner分组
参考章节:10.2.1Interrupt CombinerTable 10-1Interrupt Groups of Interrupt Combiner
可见ADC在INTG10,即第10组。
8、Combiner IESR2
参考章节:10.4.2.9IESR2
如果要用中断模式设置为1即可。
9、Combiner IECR2
参考章节:10.4.2.10IECR2
此处用于关闭中断,采用默认值即可,注意,如果设置了1,那么中断功能就关闭了。
10、A/D转换的转换时间计算
例如:PCLK为100MHz,PRESCALER = 65 ;所有10位转换时间为
100MHz/(99+1) = 1MHz
转化时间为1/(1MHz/5 cycles) = 5us。
完成一次A/D转换需要5个时钟周期。A/D转换器的最大工作时钟为5MHz,所以最大采样率可以达到1Mit/s.
电路连接图
由该电路图可知,外设是一个滑动变阻器,根据接触点的不同,会导致输入电压的模拟值不同。连接的A/D控制器通道为3。该电路利用一个电位计输出电压到4412的AIN3管脚。输入的电压范围为0~1.8V。
ADC裸机开发程序实例
ADC数据的读取通常由2种方法:中断模式、轮训模式。
轮训模式
轮询模式读取数据步骤如下:
1.要读取数据首先向ADC寄存器ADCCON的bit:1写1,发送转换命令,采用读-启动模式来开启转换。
2.当ADC控制器转换完毕会将ADCCON的bit:15设置为1,
3.轮询检测ADCCON的bit:15是否设置为1,如果设置为1,就读走数据,否则继续等待。
这种方式比较占用CPU资源。
//注:这里使用读-启动模式
**********************ADC *****************
#define ADC_CFG __REG(0x10010118)
#define ADCCON __REG(0x126C0000)
#define ADCDLY __REG(0x126C0008)
#define ADCDAT __REG(0x126C000C)
#define CLRINTADC __REG(0x126C0018)
#define ADCMUX __REG(0x126C001C)
#include "exynos_4412.h"
#include "pwm.h"
#include "uart.h"
unsigned char table[10] = {'0','1','2','3','4','5','6','7','8','9'};
void mydelay_ms(int time)
{
int i, j;
while(time--)
{
for (i = 0; i < 5; i++)
for (j = 0; j < 514; j++);
}
}
adc_init(int temp)
{
ADCCON = (1 << 16 | 1 << 14 | 99 <<6 | 1 << 1);
ADCMUX = 3;
temp = ADCDAT & 0xfff;
}
* 裸机代码,不同于LINUX 应用层, 一定加循环控制