后面还会讲到S3C2410用ADC结合触摸屏的驱动实验,此节简单介绍2410的ADC普通模式驱动方式。
S3C2410的ADC简介
S3C2410内置1个8通道的10位ADC,在2.5MHz的AD转换时钟下,最大转换速率可达500kHz。
先看ADC模块图:
此图来自S3C2410 datasheet. 简单说一下,外部晶体控制器部分控制外部的晶体管以控制触摸屏。AIN[0]-AIN[7]为七个模拟量输入通道,经8:1选择器后由内部逐次逼近式转换模块转换,后经ADC接口控制器送到中断源产生器再送到CPU。
S3C2410内置ADC的特性
- 分辩率: 10-位
- 微分线性度误差: ± 1.0 LSB
- 积分线性度误差: ± 2.0 LSB
- 最大转换速率: 500 KSPS
- 低功耗
- 供电电压: 3.3V
- 输入模拟电压范围: 0 ~ 3.3V
- 片上采样保持功能
- 普通转换模式
- 分离的X/Y轴坐标转换模式
- 自动(连续) X/Y轴坐标转换模式
- 等待中断模式
ADC普通转换模式(Normal Conversion Mode)
普通转换模式(AUTO_PST=0, XY_PST=0)用来进行一般的ADC转换。
这里简单看一下ADC的控制寄存器(ADCCON)、数据寄存器0(ADCDAT0)、数据寄存器1(ADCDAT1)、转换周期等待定时器(ADCDLY)的各位定义。
ADCCON 控制寄存器
ADCCON | BIT[15-0] | FUNCTION |
---|---|---|
ECFLG | [15] | 1 = End of Conversion |
PRESEN | [14] | 1 = Enable |
PRSCVL | [13:6] | 1-255 |
SEL_MUX | [5:3] | AIN0 - AIN7 |
STDBM | [2] | 1= Standby Mode |
READ_START | [1] | 1 = Enable start by Read operation |
ENABLE_START | [0] | 1 = A/D conversion start |
ADCTSC 触屏控制寄存器(ADC Touch Screen Control)
ADCTSC | BIT[8-0] | FUNCTION |
---|---|---|
Reserved | [8] | SBZ (should be zero) |
YM_SEN | [7] | select output value of YMON |
YP_SEN | [6] | select output value of YPON |
XM_SEN | [5] | … |
XP_SEN | [4] | … |
PULL_UP | [3] | 1 = XP pull-up is disable |
AUTO_PST | [2] | 1 = Auto X/Y Position conversion mode, 0 = Normal ADC mode |
XY_PST | [1:0] | Manual measurement of X-position or Y-position. |
其它几个寄存器的各位定义就不再列出了,学习时可以理解各位的定义,具体编程时可以再查看相应的datasheet.
S3C2410的ADC普通模式驱动代码
// 时钟定义
#define FCLK (200*1000000)
#define HCLK (FCLK/2)
#define PCLK (HCLK/2)
// ADC 转换时钟频率 (2MHz)
#define ADC_FREQ (2*1000000)
UINT32 adc0, adc1;
// 硬件访问方式
#define SNGS3C_REG_READ(x,result) ((result) = *(volatile unsigned int *)(x))
#define SNGS3C_REG_WRITE(x,data) (*((volatile unsigned int *)(x)) = (data))
#define SNGS3C_REG_AND(x, data) (*((volatile unsigned int *)(x)) &= (data))
#define SNGS3C_REG_OR(x, data) (*((volatile unsigned int *)(x)) |= (data))
#define SNGS3C_REG_XOR(x, data) (*((volatile unsigned int *)(x)) ^= (data))
// 函数功能:读取指定通道的ADC转换值
// 输入参数:通道值
// 返回值: 转换结果
int ReadAdc(int ch)
{
int i;
ch = ch & 0x07; // 通道值为3位二进制数 0-7
*(volatile UINT32 *)rADCCON = (1<<14)|((PCLK/ADC_FREQ - 1)<<6)
|(ch<<3)|(0<<2)|(0<<1)|(0<<0);
*(volatile UINT32 *)rADCTSC = (*(volatile UINT32 *)rADCTSC) & (~0x03);
// SNGS3C_REG_OR(rADCCON, (0|(1<<14)|((PCLK/ADC_FREQ -1)<<6)|(ch<<3)|(0<<2)|(0<<1)));
// SNGS3C_REG_AND(rADCTSC, (~0x03)); //普通ADC转换模式
taskDelay(sysClkRateGet()/500);
*(volatile UINT32 *)rADCCON |= 0x01; // 启动ADC
while((*(volatile UINT32 *)rADCCON )& 0x01); // 等待ADC启动
while(!((*(volatile UINT32 *)rADCCON) & 0x8000)); // 等待ADC完成
return ((*(volatile UINT32 *)rADCDAT0) & 0x3ff); // 返回转换结果 (0-1023)
}
// 函数名称: Adc_Main
// 函数功能: ADC主任务
void Adc_Main()
{
int vin0, vin1;
while(1)
{
adc0 = ReadAdc(0); // 读取通道的转换值
adc1 = ReadAdc(1);
vin0 = (adc0*3300) / 1024; // 计算实际的真实电压值
vin1 = (adc1*3300) / 1024;
printf("AIN0 is %d mV, AIN1 is %d mV \n", vin0, vin1);
// 重定位到串口打印输出
taskDelay(120); // 任务主循环里面必须延时让出CPU,提高CPU使用率
}
}
int AdcTask( void )
{
int iTaskID;
iTaskID = taskSpawn( "tAdc",120,0,0x9000, (FUNCPTR)Adc_Main, 0,0,0,0,0, 0,0,0,0,0 );
taskDelay( 10 );
return iTaskID;
}