TQ210裸机编程(七)——UART+key(中断)

TQ210裸机编程(7)——UART+key(中断)

之前的按键中断程序是直接下载到DDR内存运行的,这次结合时钟和串口的知识,改善按键中断实验的程序。

运行效果:

Key and Uart Test
You are pressed key:1
You are pressed key:1
You are pressed key:1
You are pressed key:3
You are pressed key:2
You are pressed key:3
You are pressed key:4
You are pressed key:4


直接上代码

start.S

.global _start					/* 声明一个全局的标号 */
.global key_isr
_start:

	bl clock_init
	bl uart_init

	/* 开总中断	*/
	mrs r0, cpsr
	bic r0, r0, #0x00000080		/* 清楚第7位,IRQ中断禁止位,写0使能IRQ */
	msr cpsr, r0

	bl main						/* 跳转到C函数去执行 */

halt:
	b halt

key_isr:
	/* 计算返回地址:PC的值等于当前执行的地址+8,
	** 当CPU正要执行某条指令时(还未执行),被中断,
	** 这时这条刚要执行的指令的地址刚好=PC-4 */
	sub lr, lr, #4
	stmfd sp!, {r0-r12, lr}  	/* 保护现场 */
	bl key_handle
	/* 恢复现场 */
	ldmfd sp!, {r0-r12, pc}^  	/* ^表示把spsr恢复到cpsr */
注意:在start.S中没有设置栈,是因为S5PV210在出厂时,samsung为其固化在iROM中的代码已经为我们设置好了栈。

clock.c

#define APLLCON0		*((volatile unsigned int *)0xE0100100)
#define MPLLCON			*((volatile unsigned int *)0xE0100108)
#define EPLLCON0		*((volatile unsigned int *)0xE0100110)
#define VPLLCON			*((volatile unsigned int *)0xE0100120)
#define CLK_SRC0 		*((volatile unsigned int *)0xE0100200)
#define CLK_DIV0		*((volatile unsigned int *)0xE0100300)
#define CLK_DIV1		*((volatile unsigned int *)0xE0100304)
#define CLK_DIV2		*((volatile unsigned int *)0xE0100308)
#define CLK_DIV3		*((volatile unsigned int *)0xE010030C)

void clock_init()
{
	/* 1、设置PLL_LOCK寄存器(这里使用默认值) */
	/* 2、设置PLL_CON寄存器(使用芯片手册推荐的值) */
	APLLCON0	= (1 << 0) | (3 << 8) | (125 << 16) | (1 << 31);	/* FOUTAPLL = 1000MHz */
	MPLLCON 	= (1 << 0) | (12 << 8) | (667 << 16) | (1 << 31);	/* FOUTMPLL = 667MHz */
	EPLLCON0 	= (1 << 0) | (12 << 8) | (667 << 16) | (1 << 31);	/* FOUTEPLL = 96MHz */
	VPLLCON 	= (3 << 0) | (6 << 8) | (108 << 16) | (1 << 31);	/* FOUTVPLL = 54MHz */
	
	/* 3、选择PLL为时钟输出 */
	/* MOUT_MSYS = SCLKAPLL = 1000MHz
	** MOUT_DSYS = SCLKMPLL = 667MHz
	** MOUT_PSYS = SCLKMPLL = 667MHz
	*/
	CLK_SRC0 = (1 << 0) | (1 << 4) | (1 << 8) | (1 << 12);
	
	/* 4、设置系统时钟分频值 */
	/* freq(ARMCLK) = MOUT_MSYS / (APLL_RATIO + 1) = 1000MHz / (0 + 1) = 1000MHz
	** freq(HCLK_MSYS) = ARMCLK / (HCLK_MSYS_RATIO + 1) = 1000MHz / (4 + 1) = 200MHz
	** freq(PCLK_MSYS) = HCLK_MSYS / (PCLK_MSYS_RATIO + 1) = 200MHz / (1 + 1) = 100MHz
	** freq(HCLK_DSYS) = MOUT_DSYS / (HCLK_DSYS_RATIO + 1) = 667 / (3 + 1) = 166MHz
	** freq(PCLK_DSYS) = HCLK_DSYS / (PCLK_DSYS_RATIO + 1) = 166 / (1 + 1) = 83MHz
	** freq(HCLK_PSYS) = MOUT_PSYS / (HCLK_PSYS_RATIO + 1) = 667 / (4 + 1) = 133MHz
	** freq(PCLK_PSYS) = HCLK_PSYS / (PCLK_PSYS_RATIO + 1) = 133 / (1 + 1) = 66MHz
	*/
	CLK_DIV0 = (0 << 0) | (4 << 8) | (1 << 12) | (3 << 16) | (1 << 20) | (4 << 24) | (1 << 28);
}

uart.c

#define GPA0CON		*((volatile unsigned int *)0xE0200000)
#define ULCON0 		*((volatile unsigned int *)0xE2900000)
#define UCON0 		*((volatile unsigned int *)0xE2900004)
#define UFCON0 		*((volatile unsigned int *)0xE2900008)
#define UTRSTAT0 	*((volatile unsigned int *)0xE2900010)
#define UTXH0  		*((volatile unsigned int *)0xE2900020)
#define URXH0 		*((volatile unsigned int *)0xE2900024)
#define UBRDIV0 	*((volatile unsigned int *)0xE2900028)
#define UDIVSLOT0	*((volatile unsigned int *)0xE290002C)

/*
** UART0初始化
*/
void uart_init()
{
	/*
	** 配置GPA0_0为UART_0_RXD
	** 配置GPA0_1为UART_0_TXD
	*/
	GPA0CON &= ~0xFF;
	GPA0CON |= 0x22;

	/* 8-bits/One stop bit/No parity/Normal mode operation */
	ULCON0 = 0x3 | (0 << 2) | (0 << 3) | (0 << 6);

	/* Interrupt request or polling mode/Normal transmit/Normal operation/PCLK/*/
	UCON0 = 1 | (1 << 2) | (0 << 10);

	/* 静止FIFO */
	UFCON0 = 0;

	/*
	** 波特率计算:115200bps
	** PCLK = 66MHz
	** DIV_VAL = (66000000/(115200 x 16))-1 = 35.8 - 1 = 34.8
	** UBRDIV0 = 34(DIV_VAL的整数部分)
	** (num of 1's in UDIVSLOTn)/16 = 0.8
	** (num of 1's in UDIVSLOTn) = 12
	** UDIVSLOT0 = 0xDDDD (查表)
	*/
	UBRDIV0 = 34;
	UDIVSLOT0 = 0xDDDD;
}

void uart_send_byte(unsigned char byte)
{
	while (!(UTRSTAT0 & (1 << 2)));	/* 等待发送缓冲区为空 */
	UTXH0 = byte;					/* 发送一字节数据 */		
}

unsigned char uart_recv_byte()
{
	while (!(UTRSTAT0 & 1));	/* 等待接收缓冲区有数据可读 */
	return URXH0;				/* 接收一字节数据 */		
}

void uart_send_string(char *str)
{
	char *p = str;
	while (*p)
		uart_send_byte(*p++);
}

key.c

#define GPH0CON				*((volatile unsigned int *)0xE0200C00)
#define GPH0DAT				*((volatile unsigned int *)0xE0200C04)

#define EXT_INT_0_CON 		*((volatile unsigned int *)0xE0200E00)
#define EXT_INT_0_MASK		*((volatile unsigned int *)0xE0200F00)

#define VIC0INTSELECT		*((volatile unsigned int *)0xF200000C)
#define VIC0INTENABLE 		*((volatile unsigned int *)0xF2000010)

#define VIC0VECTADDR0		*((volatile unsigned int *)0xF2000100)
#define VIC0VECTADDR1		*((volatile unsigned int *)0xF2000104)
#define VIC0VECTADDR2		*((volatile unsigned int *)0xF2000108)
#define VIC0VECTADDR3		*((volatile unsigned int *)0xF200010C)

#define VIC0ADDRESS  		*((volatile unsigned int *)0xF2000F00)

#define EXT_INT_0_PEND		*((volatile unsigned int *)0xE0200F40)

extern void key_isr(void);

void key_handle()
{	
	volatile unsigned char key_code = EXT_INT_0_PEND & 0xF;
	volatile unsigned char key = 0;
	
	VIC0ADDRESS = 0;		/* 清中断向量寄存器 */
	EXT_INT_0_PEND |= 0xF;	/* 清中断挂起寄存器 */
	
	if (key_code == 1)		/* key1 */
		key = '1';
	else if (key_code == 2)	/* key2 */
		key = '2';
	else if (key_code == 4)	/* key3 */
		key = '3';
	else if (key_code == 8)	/* key4 */
		key = '4';

	uart_send_string("You are pressed key:");
	uart_send_byte(key);
	uart_send_string("\r\n");

}

int main()
{
	GPH0CON |= 0xFFFFFFFF << 0;								/* 配置GPH0[0.1.2.3]为外部中断:key1.key2.key3.key4 */
	
	EXT_INT_0_CON &= ~(0xFF << 0);
	EXT_INT_0_CON |= 2 | (2 << 4) | (2 << 8) | (2 << 12);	/* 配置EXT_INT[0.1.2.3]为下降沿触发 */
	EXT_INT_0_MASK &= ~0xF;					/* 取消屏蔽外部中断EXT_INT[0.1.2.3] */
	
	VIC0INTSELECT &= ~0xF;					/* 选择外部中断EXT_INT[0.1.2.3]为IRQ类型的中断 */
	
	VIC0INTENABLE |= 0xF;						/* 使能外部中断EXT_INT[0.1.2.3] */
	
	/* 当EXT_INT[0]触发中断,即用户按下key1时,
	** CPU就会自动的将VIC0VECTADDR0的值赋给VIC0ADDRESS并跳转到这个地址去执 */
	VIC0VECTADDR0 = (unsigned int)key_isr;	/* key1 */
	VIC0VECTADDR1 = (unsigned int)key_isr;	/* key2 */
	VIC0VECTADDR2 = (unsigned int)key_isr;	/* key3 */
	VIC0VECTADDR3 = (unsigned int)key_isr;	/* key4 */
	
	uart_send_string("\r\nKey and Uart Test\r\n");
	while (1);
	
	return 0;
}

Makefile

key.bin: start.o clock.o uart.o key.o
	arm-linux-ld -Ttext 0xD0020010 -o key.elf $^
	arm-linux-objcopy -O binary key.elf $@
	arm-linux-objdump -D key.elf > key.dis
	
%.o : %.c
	arm-linux-gcc -c $< -o $@
%.o : %.S
	arm-linux-gcc -c $< -o $@
	
clean:
	rm *.o *.elf *.bin *.dis

程序烧写过程见《TQ210裸机编程(5)——系统时钟配置》


转载请注明来源:http://blog.****.net/zjhsucceed_329/