JZ2440 ADC和触摸屏学习笔记

来源:互联网 发布:python分布式爬虫系统 编辑:程序博客网 时间:2024/05/21 05:43

裸机系列代码地址:链接:http://pan.baidu.com/s/1pLHOd0v 密码:4x5s

S3C2440的CMOS模数转换器可以接收8个通道的模拟信号输入,并将它们转换成10位的二进制数据

S3C2440的触摸屏接口向外提供4个控制引脚(XP,XM,YP,YM)与触摸屏的直接相连。S3C2440的ADC和触摸屏机构图如下所示

图中有两个中断信号:INT_ADC,INT_TC,前者表示A/D转换已经完成,后者表示触摸屏被按下了,或者弹起了。
在使用触摸屏是AIN[7:4]被用来和触摸屏相连,所以只有剩下的AIN[3:0]可以作为普通A/D转换通道用,不使用触摸屏时AIN[7:0]均可用作普通A/D转换通道
ADC的启动方式有两种:1、手工启动,第一次转换是使用
     2、读结果时就自动启动下一次转换,除第一次转换外使用
也有两种方法得知转换结束:1、查询状态位
    2、转换结束时发出中断INT_ADC_S
下面看一看ADC和触摸屏使用时主要使用的寄存器
ADCCON寄存器格式
[15]:只读,A/D转换结束标志。0=正在转换,1=转换结束
[14]:决定A/D转换器的时钟是否使用预分频。0=不使用,1=使用。通常情况需要使用预分频
[13:6]:预分频系数PRSCVL,取值0~255,A/D时钟=PCLK/(PRSCVL)。注意:A/D时钟必须小于PCLK的1/5
[5:3]:选择进行AD转换的通道
[2]:选择静态模式,0=正常模式,1=静态模式
[1]:读数据时是否启动下一次转换。0=不启动,1=启动
[0]:启动A/D转换。0=无作用,1=启动(真正转换开始时,此位被置0)

ADCDAT0寄存器格式
[15]:对于触摸屏,使用“等待中断模式”时,0=触摸屏被按下,1=触摸屏没有被按下
[14]:决定是否使用自动(连续)X/Y轴坐标转换模式
[13:12]:手动X/Y轴坐标转换模式
[11:10]:保留
[9:0]:x轴坐标转换数值

ADCDAT1数据格式和ADCDAT0相似

ADCTSC寄存器格式
[8]:表示检测的中断类型。0=触点按下中断,1=触点松开中断
[7]:0=YM驱动禁止(高阻),1=YM驱动使能(接地)
[6]:0=YP驱动禁止(接外部电压),1=YP驱动使能(接模拟输入)
[5]:0=XM驱动禁止(高阻),1=XM驱动使能(接地)
[4]:0=XP驱动禁止(接外部电压),1=XP驱动使能(接模拟输入)
[3]:PULL_UP,XP上拉使能,0=禁止上拉,1=使能上拉
[2]:AUTO_PST,是否使用自动(连续)X/Y轴坐标转换模式,0=普通模式,1=自动转换模式
[1:0]:手动量测X,Y轴坐标。00=无操作模式,01=量测x轴,10=量测y轴,11=等待中断模式

等待中断模式,如下为等待中断模式的触摸屏等效电路图,ADCTSC寄存器的设置参考此图

图中,S4,S5闭合,S1,S2,S3断开,即YM接地,XP上拉,XP作为模拟输入,YP作为模拟输入,XM高阻
从图中可知,设置ADCTSC寄存器为0xd3即可令触摸屏处于等待中断模式,这时,它在等待触摸屏被按下或是等待弹起。触摸屏
按下时产生INT_TC中断,弹起时亦产生此中断。

自动(连续)X/Y轴坐标转换模式
设置ADCTSC寄存器为0x0c进入此模式,触摸屏控制器就会自动转换触点的x,y坐标值,并分别写入ADCDAT0和ADCDAT1寄存器中
然后发出INT_ADC中断

对于普通转换模式,分离的x/y轴坐标转换模式,自动(连续)X/Y轴坐标转换模式,都可以通过ADCDLY寄存器来设置采样的延时时间

触摸屏的程序流程图和控制的状态转移图如下所示


下面是一个触摸屏的实例程序

Makefile 文件

objs:= head.o init.o main.o irq.oadcts.bin: $(objs) arm-linux-ld -Tadc_ts.lds -o adcts_elf $^arm-linux-objcopy -O binary -S adcts_elf $@arm-linux-objdump -D -m arm adcts_elf > adcts.dis%.o:%.c arm-linux-gcc -Wall -O2 -c -o $@ $<%.o:%.s arm-linux-gcc -Wall -O2 -c -o $@ $< clean:rm -f adcts_elf adcts.dis adcts.bin *.o 
链接文件
SECTIONS {    . = 0x30000000;    .text          :   { *(.text) }    .rodata ALIGN(4) : {*(.rodata)}     .data ALIGN(4) : { *(.data) }    .bss ALIGN(4)  : { *(.bss)  *(COMMON) }}
head.S

.text.global _start_start:b reset HandleUndef:b HandleUndefHandlerSWI:b HandlerSWI HandlePrefetchAbort:b HandlePrefetchAbortHandleDataAbort:b HandleDataAbortHandleNotUsed:b HandleNotUsed    b HandleIRQ           /*中断向量表的位置必须固定,即 b HandleIRQ运行位置必须在0x18处*/HandleFIQ:b HandleFIQreset:ldr sp,=4096                     /*设置C函数使用的栈*/bl disable_watch_dogmsr cpsr_c,#0xd2     /*进入中断模式*/ ldr sp,=3072         /*设置中断模式栈指针*/msr cpsr_c,#0xd3     /*进入系统模式*/ldr sp,=4096  /*设置系统模式栈指针*/msr cpsr_c,#0x5f     /*开IRQ中断,这之后程序可以响应中断*/bl init_clock                    /*设置系统时钟,使得uart使用PCLK为50MHZ*/bl memsetup                      /*初始化存储控制器使得SDRAM可用*/bl copy_steppingstone_to_sdram   /*将代码复制到SDRAM中*/ldr pc,=on_sdram                 /*地址相关代码,从这里开始程序在SDRAM中运行*/on_sdram:ldr sp,=0x34000000                /*设置代码在SDRAM中运行时的栈*/bl init_uart0                     /*初始化串口0*/bl main bl halt_loophalt_loop:b halt_loop HandleIRQ:sub lr,lr,#4stmdb sp!,{r0-r12,lr} ldr lr,=int_return ldr pc,=EINT_Handleint_return:ldmia sp!,{r0-r12,pc}^
init.c

#include "s3c2440.h"void disable_watch_dog(void){WTCON = 0x53000000;}/*注意这里必须用这种方式,用数组循环赋值的方式不可取*/void memsetup(void){volatile unsigned long *p = (volatile unsigned long *)0x48000000;/* 这个函数之所以这样赋值,而不是像前面的实验(比如mmu实验)那样将配置值     * 写在数组中,是因为要生成”位置无关的代码”,使得这个函数可以在被复制到     * SDRAM之前就可以在steppingstone中运行     */    /* 存储控制器13个寄存器的值 */    p[0] = 0x22011110;     //BWSCON    p[1] = 0x00000700;     //BANKCON0    p[2] = 0x00000700;     //BANKCON1    p[3] = 0x00000700;     //BANKCON2    p[4] = 0x00000700;     //BANKCON3      p[5] = 0x00000700;     //BANKCON4    p[6] = 0x00000700;     //BANKCON5    p[7] = 0x00018005;     //BANKCON6    p[8] = 0x00018005;     //BANKCON7        /* REFRESH,     * HCLK=12MHz:  0x008C07A3,     * HCLK=100MHz: 0x008C04F4     */     p[9]  = 0x008C04F4;    p[10] = 0x000000B1;     //BANKSIZE    p[11] = 0x00000030;     //MRSRB6    p[12] = 0x00000030;     //MRSRB7}void copy_steppingstone_to_sdram(void){unsigned int *pdest = (unsigned int *)0x30000000;unsigned int *psrc  = (unsigned int *)0x00000000;while(psrc<(unsigned int *)4096){*pdest = *psrc;pdest++;psrc++;}}void init_clock(void){#define MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))CLKDIVN = 0x03;__asm__(    "mrc    p15, 0, r1, c1, c0, 0\n"        /* 读出控制寄存器 */     "orr    r1, r1, #0xc0000000\n"          /* 设置为“asynchronous bus mode” */    "mcr    p15, 0, r1, c1, c0, 0\n"        /* 写入控制寄存器 */    );MPLLCON = MPLL_200MHZ;}void init_uart0(void){GPHCON = 0xa0;      /*GPH2,GPH3用作TXD0,RXD0*/GPHUP  = 0x0c;      /*GPH2,GPH3内部上拉*/#define UART_PCLK   50000000#define baurd       115200#define UART_BRD    ((UART_PCLK/(baurd*16)) -1 )ULCON0 = 0x03;      /*数据位数为8,一个停止位,无奇偶校验*/UCON0 = 0x05;       /*查询方式,UART时钟源为PCLK*/UFCON0 = 0x00;      /*不使用FIFO*/UMCON0 = 0x00;      /*不使用流控*/UBRDIV0 = UART_BRD; /*波特率为115200*/}
irq.c
#include "s3c2440.h"#define TXD0READY (1<<2)#define RXD0READY (1)#define ADC_START (1 << 0)#define PRESCALE_EN  (1 << 14)#define PRSCVL(x)    ((x) << 6)void putcc(char c){while( !(UTRSTAT0 & TXD0READY));UTXH0 = c;}unsigned char getcc(void){while(!(UTRSTAT0 & 1));return URXH0;}void putstring(char *p){while(*p != '\0'){putcc(*p);p++;}}static void isr_tc(void){if(ADCDAT0 & 0x8000){putstring("stylus up\n\r");ADCTSC = 0xd3;          /*进入等待中断模式,检测触电按下*/}else{putstring("stylus down\n\r");ADCTSC = 0x0c;          /*进入自动X/Y连续转换模式*/ADCCON |= ADC_START;    /*开启ADC转换*/}/*清除中断*/SUBSRCPND |= BIT_SUB_TC;SRCPND |= BIT_ADC;INTPND |= BIT_ADC;}static void isr_adc(void){int x,y;x = (int)(ADCDAT0 & 0x3ff);y = (int)(ADCDAT1 & 0x3ff);char ptx[4]={'\0','\0','\0','\0'};char pty[4]={'\0','\0','\0','\0'};ptx[0]=x/100+'0';ptx[1]=(x%100)/10+'0';ptx[2]=x%10+'0';pty[0]=y/100+'0';pty[1]=(y%100)/10+'0';pty[2]=y%10+'0';putstring(ptx);putstring("\n\r");putstring(pty);putstring("\n\r");ADCTSC = 0x1d3;;             /*进入等待中断模式,检测触电松开*//*清除中断*/SUBSRCPND |= BIT_SUB_ADC;SRCPND |= BIT_ADC;INTPND |= BIT_ADC;}void EINT_Handle(void){if(SUBSRCPND & BIT_SUB_TC)             /*如果是TC中断,则进入TC中断的处理函数*/isr_tc();if(SUBSRCPND & BIT_SUB_ADC)            /*如果是ADC中断,则进入ADC中断的处理函数*/isr_adc();}void Test_Ts(void){    INTMSK &= ~BIT_ADC;          // 开启ADC总中断    INTSUBMSK &= ~(BIT_SUB_TC);  // 开启INT_TC中断,即触摸屏被按下或松开时产生中断    INTSUBMSK &= ~(BIT_SUB_ADC); // 开启INT_ADC中断,即A/D转换结束时产生中断    INTMOD &= ~BIT_ADC;        // 使能预分频功能,设置A/D转换器的时钟 = PCLK/(49+1)    ADCCON = PRESCALE_EN | PRSCVL(49);    /* 采样延时时间 = (1/3.6864M)*50000 = 13.56ms     * 即按下触摸屏后,再过13.56ms才采样     */    ADCDLY = 50000;ADCTSC = 0xd3;                   /* 进入"等待中断模式",等待触摸屏被按下 */}
main.c

#include "s3c2440.h"extern void Test_Ts(void);extern void putstring(char *);int main(){Test_Ts();while(1);return 0;}