实验(10)、ADC_TS

实验目的:通过电压量的数字化采样,获取触摸屏位置

(1)head.S程序如下:

@******************************************************************************

@ File: head.S

@功能:设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行

@******************************************************************************

.extern main

.text

.global _start

_start:

@******************************************************************************

@中断向量,本程序中,除Reset和HandleIRQ外,其它异常都没有使用

@******************************************************************************

b Reset

@ 0x04:未定义指令中止模式的向量地址

HandleUndef:

b HandleUndef

@ 0x08:管理模式的向量地址,通过SWI指令进入此模式

HandleSWI:

b HandleSWI

@ 0x0c:指令预取终止导致的异常的向量地址

HandlePrefetchAbort:

b HandlePrefetchAbort

@ 0x10:数据访问终止导致的异常的向量地址

HandleDataAbort:

b HandleDataAbort

@ 0x14:保留

HandleNotUsed:

b HandleNotUsed

@ 0x18:中断模式的向量地址

b HandleIRQ

@ 0x1c:快中断模式的向量地址

HandleFIQ:

b HandleFIQ

Reset:

ldr sp, =4096 @设置栈指针,以下都是C函数,调用前需要设好栈

bl disable_watch_dog @关闭WATCHDOG,否则CPU会不断重启

bl clock_init @设置MPLL,改变FCLK、HCLK、PCLK

bl memsetup @设置存储控制器以使用SDRAM

bl nand_init @初始化NAND Flash

@复制代码到SDRAM中

ldr r0, =0x30000000 @ 1.目标地址= 0x30000000,这是SDRAM的起始地址

mov r1, #4096 @ 2.源地址= 4096,在SDRAM中运行的代码保存在NF该址开始处

mov r2, #16*1024 @ 3.复制长度= 16K,对于本实验,这是足够了

bl CopyCode2SDRAM @调用C函数CopyCode2SDRAM

@将NAND Flash中地址4096开始的2048字节代码(main.c编译得到)复制到SDRAM中

bl RdNF2SDRAM @调用C函数RdNF2SDRAM

bl clean_bss @清除bss段,未初始化或初值为0的全局/静态变量保存在bss段

msr cpsr_c, #0xd2 @进入中断模式

ldr sp, =0x31000000 @设置中断模式栈指针

msr cpsr_c, #0xdf @进入系统模式

ldr sp, =0x34000000 @设置系统模式栈指针

ldr lr, =ret_initirq @设置返回地址

ldr pc, =init_irq @调用中断初始化函数

ret_initirq:

msr cpsr_c, #0x5f @设置I-bit=0,开IRQ中断

ldr lr, =halt_loop @设置返回地址

ldr pc, =main @调用main函数

halt_loop:

b halt_loop

HandleIRQ:

sub lr, lr, #4 @计算返回地址

stmdb sp!,{ r0-r12,lr } @保存使用到的寄存器

@注意,此时的sp是中断模式的sp

@初始值是上面设置的4096

ldr lr, =int_return @设置调用IRQ_Handle函数后的返回地址

ldr pc, =IRQ_Handle @调用中断分发函数,在interrupt.c中

int_return:

ldmia sp!,{ r0-r12,pc }^ @中断返回, ^表示将spsr的值复制到cpsr

(2)init.c程序如下:

/*

* init.c:进行一些初始化

*/

#include "s3c24xx.h"

void disable_watch_dog(void);

void clock_init(void);

void memsetup(void);

void copy_steppingstone_to_sdram(void);

void clean_bss(void);

/*

*关闭WATCHDOG,否则CPU会不断重启

*/

void disable_watch_dog(void)

{

WTCON = 0; //关闭WATCHDOG很简单,往这个寄存器写0即可

}

#define FCLK 200000000

#define HCLK 100000000

#define PCLK 50000000

#define S3C2410_MPLL_200MHZ ((0x5c<<12)|(0x04<<4)|(0x00))

#define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))

/*

*对于MPLLCON寄存器,[19:12]为MDIV,[9:4]为PDIV,[1:0]为SDIV

*有如下计算公式:

* S3C2410: MPLL(FCLK) = (m * Fin)/(p * 2^s)

* S3C2410: MPLL(FCLK) = (2 * m * Fin)/(p * 2^s)

*其中: m = MDIV + 8, p = PDIV + 2, s = SDIV

*对于本开发板,Fin = 12MHz

*设置CLKDIVN,令分频比为:FCLK:HCLK:PCLK=1:2:4,

* FCLK=200MHz,HCLK=100MHz,PCLK=50MHz

*/

void clock_init(void)

{

// LOCKTIME = 0x00ffffff; //使用默认值即可

CLKDIVN = 0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1

/* HDIVN非0,CPU的总线模式应变为“asynchronous bus mode”*/

__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" /*写入控制寄存器*/

);

/*判断是S3C2410还是S3C2440 */

if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))

{

MPLLCON = S3C2410_MPLL_200MHZ; /*现在FCLK=200M,HCLK=100M,PCLK=50M*/

}

else

{

MPLLCON = S3C2440_MPLL_200MHZ; /*现在FCLK=200M,HCLK=100M,PCLK=50M*/

}

}

/*

*设置存储控制器以使用SDRAM

*/

void memsetup(void)

{

volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;

/*这个函数之所以这样赋值,而不是像前面的实验(比如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 *pdwSrc = (unsigned int *)0;

unsigned int *pdwDest = (unsigned int *)0x30000000;

while (pdwSrc < (unsigned int *)4096)

{

*pdwDest = *pdwSrc;

pdwDest++;

pdwSrc++;

}

}

void clean_bss(void)

{

extern int __bss_start, __bss_end;

int *p = &__bss_start;

for (; p <&__bss_end; p++)

*p = 0;

}

(3)interrupt.c程序如下:

#include "s3c24xx.h"

void (*isr_handle_array[50])(void);

void Dummy_isr(void)

{

while(1);

}

void init_irq(void)

{

int i = 0;

for (i = 0; i < sizeof(isr_handle_array) / sizeof(isr_handle_array[0]); i++)

{

isr_handle_array[i] = Dummy_isr;

}

INTMOD = 0x0; //所有中断都设为IRQ模式

INTMSK = BIT_ALLMSK; //先屏蔽所有中断

// isr_handle_array[ISR_IIC_OFT] = I2CIntHandle;

}

void IRQ_Handle(void)

{

unsigned long oft = INTOFFSET;

//清中断

if (oft == 4)

EINTPEND = 1<<7; //EINT4-7合用IRQ4,注意EINTPEND[3:0]保留未用,向这些位写入1可能导致未知结果

SRCPND = 1<<oft;

INTPND = INTPND;

/*调用中断服务程序*/

isr_handle_array[oft]();

}

(3_2)interrupt.h程序如下:

void EINT_Handle();

(4)main.c程序如下:

#include <stdio.h>

#include "serial.h"

#include "adc_ts.h"

int main()

{

char c;

uart0_init(); //波特率115200,8N1(8个数据位,无校验位,1个停止位)

while (1)

{

printf("\r\n##### Test ADC and Touch Screem #####\r\n");

printf("[A] Test ADC\n\r");

printf("[T] Test Touch Screem\n\r");

printf("Enter your selection: ");

c = getc();

printf("%c\n\r", c);

switch (c)

{

case 'a':

case 'A':

{

Test_Adc();

break;

}

case 't':

case 'T':

{

Test_Ts();

break;

}

default:

break;

}

}

return 0;

}

(5)adc_ts.c程序如下:

/*

* FILE: adc_ts.c

* ADC和触摸屏的测试函数

*/

#include <stdio.h>

#include "adc_ts.h"

#include "s3c24xx.h"

#include "serial.h"

// ADCCON寄存器

#define PRESCALE_DIS (0 << 14)

#define PRESCALE_EN (1 << 14)

#define PRSCVL(x) ((x) << 6)

#define ADC_INPUT(x) ((x) << 3)

#define ADC_START(1 << 0)

#define ADC_ENDCVT (1 << 15)

// ADCTSC寄存器

#define UD_SEN (1 << 8)

#define DOWN_INT (UD_SEN*0)

#define UP_INT (UD_SEN*1)

#define YM_SEN (1 << 7)

#define YM_HIZ (YM_SEN*0)

#define YM_GND(YM_SEN*1)

#define YP_SEN (1 << 6)

#define YP_EXTVLT (YP_SEN*0)

#define YP_AIN (YP_SEN*1)

#define XM_SEN (1 << 5)

#define XM_HIZ (XM_SEN*0)

#define XM_GND (XM_SEN*1)

#define XP_SEN (1 << 4)

#define XP_EXTVLT (XP_SEN*0)

#define XP_AIN (XP_SEN*1)

#define XP_PULL_UP (1 << 3)

#define XP_PULL_UP_EN (XP_PULL_UP*0)

#define XP_PULL_UP_DIS (XP_PULL_UP*1)

#define AUTO_PST (1 << 2)

#define CONVERT_MAN (AUTO_PST*0)

#define CONVERT_AUTO (AUTO_PST*1)

#define XP_PST(x) (x << 0)

#define NOP_MODE 0

#define X_AXIS_MODE 1

#define Y_AXIS_MODE 2

#define WAIT_INT_MODE 3

/*设置进入等待中断模式,XP_PU,XP_Dis,XM_Dis,YP_Dis,YM_En

* (1)对于S3C2410,位[8]只能为0,所以只能使用下面的wait_down_int,

*它既等待Pen Down中断,也等待Pen Up中断

* (2)对于S3C2440,位[8]为0、1时分别表示等待Pen Down中断或Pen Up中断

*/

/*进入"等待中断模式",等待触摸屏被按下*/

#define wait_down_int() { ADCTSC = DOWN_INT | XP_PULL_UP_EN | \

XP_AIN | XM_HIZ | YP_AIN | YM_GND | \

XP_PST(WAIT_INT_MODE); }

/*进入"等待中断模式",等待触摸屏被松开*/

#define wait_up_int() { ADCTSC = UP_INT | XP_PULL_UP_EN | XP_AIN | XM_HIZ | \

YP_AIN | YM_GND | XP_PST(WAIT_INT_MODE); }

/*进入自动(连续) X/Y轴坐标转换模式*/

#define mode_auto_xy() { ADCTSC = CONVERT_AUTO | XP_PULL_UP_DIS | \

XP_PST(NOP_MODE); }

extern void (*isr_handle_array[50])(void);

/*

*使用查询方式读取A/D转换值

*输入参数:

* ch:模拟信号通道,取值为0~7

*/

static int ReadAdc(int ch)

{

//选择模拟通道,使能预分频功能,设置A/D转换器的时钟= PCLK/(49+1)

ADCCON = PRESCALE_EN | PRSCVL(49) | ADC_INPUT(ch);

//清除位[2],设为普通转换模式

ADCTSC &= ~(1<<2);

//设置位[0]为1,启动A/D转换

ADCCON |= ADC_START;

//当A/D转换真正开始时,位[0]会自动清0

while (ADCCON & ADC_START);

//检测位[15],当它为1时表示转换结束

while (!(ADCCON & ADC_ENDCVT));

//读取数据

return (ADCDAT0 & 0x3ff);

}

void wait(unsigned int dly)

{ for(; dly > 0; dly--);

}

/*

*测试ADC

*通过A/D转换,测量可变电阻器的电压值

*/

void Test_Adc(void)

{

float vol2;

int t2;

printf("Measuring the voltage of AIN2, press any key to exit\n\r");

while (!awaitkey(0)) //串口无输入,则不断测试

{

vol2 = (float)ReadAdc(2);

wait(200000);

vol2 += (float)ReadAdc(2);

wait(200000);

vol2 += (float)ReadAdc(2);

wait(200000);

vol2 += (float)ReadAdc(2);

vol2 = ((vol2/4.0)*3.3)/1024.0; //计算电压值

t2 = (vol2 - (int)vol2) * 1000; //计算小数部分,本代码中的printf无法打印浮点数

printf("AIN2 = %d.%-3dV\r", (int)vol2, t2);

}

printf("\n");

}

/*

* INT_TC的中断服务程序

*当触摸屏被按下时,进入自动(连续) X/Y轴坐标转换模式;

*当触摸屏被松开时,进入等待中断模式,再次等待INT_TC中断

*/

static void Isr_Tc(void)

{

if (ADCDAT0 & 0x8000)

{

printf("Stylus Up!!\n\r");

wait_down_int(); /*进入"等待中断模式",等待触摸屏被按下*/

}

else

{

printf("Stylus Down: ");

mode_auto_xy(); /*进入自动(连续) X/Y轴坐标转换模式*/

/*设置位[0]为1,启动A/D转换

*注意:ADCDLY为50000,PCLK = 50MHz,

*要经过(1/50MHz)*50000=1ms之后才开始转换X坐标

*再经过1ms之后才开始转换Y坐标

*/

ADCCON |= ADC_START;

}

//清INT_TC中断

SUBSRCPND |= BIT_SUB_TC;

SRCPND |= BIT_ADC;

INTPND |= BIT_ADC;

}

/*

* INT_ADC的中断服务程序

* A/D转换结束时发生此中断

*先读取X、Y坐标值,再进入等待中断模式

*/

static void Isr_Adc(void)

{

//打印X、Y坐标值

printf("xdata = %4d, ydata = %4d\r\n", (int)(ADCDAT0 & 0x3ff), (int)(ADCDAT1 & 0x3ff));

/*判断是S3C2410还是S3C2440 */

if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))

{ // S3C2410

wait_down_int(); /*进入"等待中断模式",等待触摸屏被松开*/

}

else

{ // S3C2440

wait_up_int(); /*进入"等待中断模式",等待触摸屏被松开*/

}

//清INT_ADC中断

SUBSRCPND |= BIT_SUB_ADC;

SRCPND |= BIT_ADC;

INTPND |= BIT_ADC;

}

/*

* ADC、触摸屏的中断服务程序

*对于INT_TC、INT_ADC中断,分别调用它们的处理程序

*/

void AdcTsIntHandle(void)

{

if (SUBSRCPND & BIT_SUB_TC)

Isr_Tc();

if (SUBSRCPND & BIT_SUB_ADC)

Isr_Adc();

}

/*

*测试触摸屏,打印触点坐标

*/

void Test_Ts(void)

{

isr_handle_array[ISR_ADC_OFT] = AdcTsIntHandle; //设置ADC中断服务程序

INTMSK &= ~BIT_ADC; //开启ADC总中断

INTSUBMSK &= ~(BIT_SUB_TC); //开启INT_TC中断,即触摸屏被按下或松开时产生中断

INTSUBMSK &= ~(BIT_SUB_ADC); //开启INT_ADC中断,即A/D转换结束时产生中断

//使能预分频功能,设置A/D转换器的时钟= PCLK/(49+1)

ADCCON = PRESCALE_EN | PRSCVL(49);

/*采样延时时间= (1/3.6864M)*50000 = 13.56ms

*即按下触摸屏后,再过13.56ms才采样

*/

ADCDLY = 50000;

wait_down_int(); /*进入"等待中断模式",等待触摸屏被按下*/

printf("Touch the screem to test, press any key to exit\n\r");

getc();

//屏蔽ADC中断

INTSUBMSK |= BIT_SUB_TC;

INTSUBMSK |= BIT_SUB_ADC;

INTMSK |= BIT_ADC;

}

(6)framebuffer.c程序如下:

(7)s3c24xx.h程序如下:

/* WOTCH DOG register */

#define WTCON (*(volatile unsigned long *)0x53000000)

/* SDRAM regisers */

#define MEM_CTL_BASE 0x48000000

#define SDRAM_BASE 0x30000000

/* NAND Flash registers */

#define NFCONF (*(volatile unsigned int *)0x4e000000)

#define NFCMD (*(volatile unsigned char *)0x4e000004)

#define NFADDR (*(volatile unsigned char *)0x4e000008)

#define NFDATA (*(volatile unsigned char *)0x4e00000c)

#define NFSTAT (*(volatile unsigned char *)0x4e000010)

/*GPIO registers*/

#define GPBCON (*(volatile unsigned long *)0x56000010)

#define GPBDAT (*(volatile unsigned long *)0x56000014)

#define GPFCON (*(volatile unsigned long *)0x56000050)

#define GPFDAT (*(volatile unsigned long *)0x56000054)

#define GPFUP (*(volatile unsigned long *)0x56000058)

#define GPGCON (*(volatile unsigned long *)0x56000060)

#define GPGDAT (*(volatile unsigned long *)0x56000064)

#define GPGUP (*(volatile unsigned long *)0x56000068)

#define GPHCON (*(volatile unsigned long *)0x56000070)

#define GPHDAT (*(volatile unsigned long *)0x56000074)

#define GPHUP (*(volatile unsigned long *)0x56000078)

/*UART registers*/

#define ULCON0 (*(volatile unsigned long *)0x50000000)

#define UCON0 (*(volatile unsigned long *)0x50000004)

#define UFCON0 (*(volatile unsigned long *)0x50000008)

#define UMCON0 (*(volatile unsigned long *)0x5000000c)

#define UTRSTAT0 (*(volatile unsigned long *)0x50000010)

#define UTXH0 (*(volatile unsigned char *)0x50000020)

#define URXH0 (*(volatile unsigned char *)0x50000024)

#define UBRDIV0 (*(volatile unsigned long *)0x50000028)

/*interrupt registes*/

#define SRCPND (*(volatile unsigned long *)0x4A000000)

#define INTMOD (*(volatile unsigned long *)0x4A000004)

#define INTMSK (*(volatile unsigned long *)0x4A000008)

#define PRIORITY (*(volatile unsigned long *)0x4A00000c)

#define INTPND (*(volatile unsigned long *)0x4A000010)

#define INTOFFSET (*(volatile unsigned long *)0x4A000014)

#define SUBSRCPND (*(volatile unsigned long *)0x4A000018)

#define INTSUBMSK (*(volatile unsigned long *)0x4A00001c)

/*external interrupt registers*/

#define EINTMASK (*(volatile unsigned long *)0x560000a4)

#define EINTPEND (*(volatile unsigned long *)0x560000a8)

(8)Makefile程序如下:

CC = arm-linux-gcc

LD = arm-linux-ld

AR = arm-linux-ar

OBJCOPY = arm-linux-objcopy

OBJDUMP = arm-linux-objdump

INCLUDEDIR := $(shell pwd)/include

CFLAGS := -Wall -O2

CPPFLAGS :=-nostdlib-nostdinc -I$(INCLUDEDIR)

LDFLASG := -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc

export CC LD OBJCOPY OBJDUMP INCLUDEDIR CFLAGS CPPFLAGS

objs := head.o init.o nand.o interrupt.o adc_ts.o serial.o main.o lib/libc.a

adc_ts.bin: $(objs)

${LD} -Tadc_ts.lds -o adc_ts_elf $^ ${LDFLASG}

${OBJCOPY} -O binary -S adc_ts_elf $@

${OBJDUMP} -D -m arm adc_ts_elf > adc_ts.dis

.PHONY : lib/libc.a

lib/libc.a:

cd lib; make; cd ..

%.o:%.c

${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

%.o:%.S

${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

clean:

make clean -C lib

rm -f adc_ts.bin adc_ts_elf adc_ts.dis *.o

results matching ""

    No results matching ""

    results matching ""

      No results matching ""