|
之前的按键中断程序是直接下载到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
[cpp] view plaincopy
01..global _start /* 声明一个全局的标号 */
02..global key_isr
03._start:
04.
05. bl clock_init
06. bl uart_init
07.
08. /* 开总中断 */
09. mrs r0, cpsr
10. bic r0, r0, #0x00000080 /* 清楚第7位,IRQ中断禁止位,写0使能IRQ */
11. msr cpsr, r0
12.
13. bl main /* 跳转到C函数去执行 */
14.
15.halt:
16. b halt
17.
18.key_isr:
19. /* 计算返回地址:PC的值等于当前执行的地址+8,
20. ** 当CPU正要执行某条指令时(还未执行),被中断,
21. ** 这时这条刚要执行的指令的地址刚好=PC-4 */
22. sub lr, lr, #4
23. stmfd sp!, {r0-r12, lr} /* 保护现场 */
24. bl key_handle
25. /* 恢复现场 */
26. ldmfd sp!, {r0-r12, pc}^ /* ^表示把spsr恢复到cpsr */
注意:在start.S中没有设置栈,是因为S5PV210在出厂时,samsung为其固化在iROM中的代码已经为我们设置好了栈。
clock.c
[cpp] view plaincopy
01.#define APLLCON0 *((volatile unsigned int *)0xE0100100)
02.#define MPLLCON *((volatile unsigned int *)0xE0100108)
03.#define EPLLCON0 *((volatile unsigned int *)0xE0100110)
04.#define VPLLCON *((volatile unsigned int *)0xE0100120)
05.#define CLK_SRC0 *((volatile unsigned int *)0xE0100200)
06.#define CLK_DIV0 *((volatile unsigned int *)0xE0100300)
07.#define CLK_DIV1 *((volatile unsigned int *)0xE0100304)
08.#define CLK_DIV2 *((volatile unsigned int *)0xE0100308)
09.#define CLK_DIV3 *((volatile unsigned int *)0xE010030C)
10.
11.void clock_init()
12.{
13. /* 1、设置PLL_LOCK寄存器(这里使用默认值) */
14. /* 2、设置PLL_CON寄存器(使用芯片手册推荐的值) */
15. APLLCON0 = (1 << 0) | (3 << 8) | (125 << 16) | (1 << 31); /* FOUTAPLL = 1000MHz */
16. MPLLCON = (1 << 0) | (12 << 8) | (667 << 16) | (1 << 31); /* FOUTMPLL = 667MHz */
17. EPLLCON0 = (1 << 0) | (12 << 8) | (667 << 16) | (1 << 31); /* FOUTEPLL = 96MHz */
18. VPLLCON = (3 << 0) | (6 << 8) | (108 << 16) | (1 << 31); /* FOUTVPLL = 54MHz */
19.
20. /* 3、选择PLL为时钟输出 */
21. /* MOUT_MSYS = SCLKAPLL = 1000MHz
22. ** MOUT_DSYS = SCLKMPLL = 667MHz
23. ** MOUT_PSYS = SCLKMPLL = 667MHz
24. */
25. CLK_SRC0 = (1 << 0) | (1 << 4) | (1 << 8) | (1 << 12);
26.
27. /* 4、设置系统时钟分频值 */
28. /* freq(ARMCLK) = MOUT_MSYS / (APLL_RATIO + 1) = 1000MHz / (0 + 1) = 1000MHz
29. ** freq(HCLK_MSYS) = ARMCLK / (HCLK_MSYS_RATIO + 1) = 1000MHz / (4 + 1) = 200MHz
30. ** freq(PCLK_MSYS) = HCLK_MSYS / (PCLK_MSYS_RATIO + 1) = 200MHz / (1 + 1) = 100MHz
31. ** freq(HCLK_DSYS) = MOUT_DSYS / (HCLK_DSYS_RATIO + 1) = 667 / (3 + 1) = 166MHz
32. ** freq(PCLK_DSYS) = HCLK_DSYS / (PCLK_DSYS_RATIO + 1) = 166 / (1 + 1) = 83MHz
33. ** freq(HCLK_PSYS) = MOUT_PSYS / (HCLK_PSYS_RATIO + 1) = 667 / (4 + 1) = 133MHz
34. ** freq(PCLK_PSYS) = HCLK_PSYS / (PCLK_PSYS_RATIO + 1) = 133 / (1 + 1) = 66MHz
35. */
36. CLK_DIV0 = (0 << 0) | (4 << 8) | (1 << 12) | (3 << 16) | (1 << 20) | (4 << 24) | (1 << 28);
37.}
uart.c
[cpp] view plaincopy
01.#define GPA0CON *((volatile unsigned int *)0xE0200000)
02.#define ULCON0 *((volatile unsigned int *)0xE2900000)
03.#define UCON0 *((volatile unsigned int *)0xE2900004)
04.#define UFCON0 *((volatile unsigned int *)0xE2900008)
05.#define UTRSTAT0 *((volatile unsigned int *)0xE2900010)
06.#define UTXH0 *((volatile unsigned int *)0xE2900020)
07.#define URXH0 *((volatile unsigned int *)0xE2900024)
08.#define UBRDIV0 *((volatile unsigned int *)0xE2900028)
09.#define UDIVSLOT0 *((volatile unsigned int *)0xE290002C)
10.
11./*
12.** UART0初始化
13.*/
14.void uart_init()
15.{
16. /*
17. ** 配置GPA0_0为UART_0_RXD
18. ** 配置GPA0_1为UART_0_TXD
19. */
20. GPA0CON &= ~0xFF;
21. GPA0CON |= 0x22;
22.
23. /* 8-bits/One stop bit/No parity/Normal mode operation */
24. ULCON0 = 0x3 | (0 << 2) | (0 << 3) | (0 << 6);
25.
26. /* Interrupt request or polling mode/Normal transmit/Normal operation/PCLK/*/
27. UCON0 = 1 | (1 << 2) | (0 << 10);
28.
29. /* 静止FIFO */
30. UFCON0 = 0;
31.
32. /*
33. ** 波特率计算:115200bps
34. ** PCLK = 66MHz
35. ** DIV_VAL = (66000000/(115200 x 16))-1 = 35.8 - 1 = 34.8
36. ** UBRDIV0 = 34(DIV_VAL的整数部分)
37. ** (num of 1's in UDIVSLOTn)/16 = 0.8
38. ** (num of 1's in UDIVSLOTn) = 12
39. ** UDIVSLOT0 = 0xDDDD (查表)
40. */
41. UBRDIV0 = 34;
42. UDIVSLOT0 = 0xDDDD;
43.}
44.
45.void uart_send_byte(unsigned char byte)
46.{
47. while (!(UTRSTAT0 & (1 << 2))); /* 等待发送缓冲区为空 */
48. UTXH0 = byte; /* 发送一字节数据 */
49.}
50.
51.unsigned char uart_recv_byte()
52.{
53. while (!(UTRSTAT0 & 1)); /* 等待接收缓冲区有数据可读 */
54. return URXH0; /* 接收一字节数据 */
55.}
56.
57.void uart_send_string(char *str)
58.{
59. char *p = str;
60. while (*p)
61. uart_send_byte(*p++);
62.}
key.c
[cpp] view plaincopy
01.#define GPH0CON *((volatile unsigned int *)0xE0200C00)
02.#define GPH0DAT *((volatile unsigned int *)0xE0200C04)
03.
04.#define EXT_INT_0_CON *((volatile unsigned int *)0xE0200E00)
05.#define EXT_INT_0_MASK *((volatile unsigned int *)0xE0200F00)
06.
07.#define VIC0INTSELECT *((volatile unsigned int *)0xF200000C)
08.#define VIC0INTENABLE *((volatile unsigned int *)0xF2000010)
09.
10.#define VIC0VECTADDR0 *((volatile unsigned int *)0xF2000100)
11.#define VIC0VECTADDR1 *((volatile unsigned int *)0xF2000104)
12.#define VIC0VECTADDR2 *((volatile unsigned int *)0xF2000108)
13.#define VIC0VECTADDR3 *((volatile unsigned int *)0xF200010C)
14.
15.#define VIC0ADDRESS *((volatile unsigned int *)0xF2000F00)
16.
17.#define EXT_INT_0_PEND *((volatile unsigned int *)0xE0200F40)
18.
19.extern void key_isr(void);
20.
21.void key_handle()
22.{
23. volatile unsigned char key_code = EXT_INT_0_PEND & 0xF;
24. volatile unsigned char key = 0;
25.
26. VIC0ADDRESS = 0; /* 清中断向量寄存器 */
27. EXT_INT_0_PEND |= 0xF; /* 清中断挂起寄存器 */
28.
29. if (key_code == 1) /* key1 */
30. key = '1';
31. else if (key_code == 2) /* key2 */
32. key = '2';
33. else if (key_code == 4) /* key3 */
34. key = '3';
35. else if (key_code == 8) /* key4 */
36. key = '4';
37.
38. uart_send_string("You are pressed key:");
39. uart_send_byte(key);
40. uart_send_string("\r\n");
41.
42.}
43.
44.int main()
45.{
46. GPH0CON |= 0xFFFFFFFF << 0; /* 配置GPH0[0.1.2.3]为外部中断:key1.key2.key3.key4 */
47.
48. EXT_INT_0_CON &= ~(0xFF << 0);
49. EXT_INT_0_CON |= 2 | (2 << 4) | (2 << 8) | (2 << 12); /* 配置EXT_INT[0.1.2.3]为下降沿触发 */
50. EXT_INT_0_MASK &= ~0xF; /* 取消屏蔽外部中断EXT_INT[0.1.2.3] */
51.
52. VIC0INTSELECT &= ~0xF; /* 选择外部中断EXT_INT[0.1.2.3]为IRQ类型的中断 */
53.
54. VIC0INTENABLE |= 0xF; /* 使能外部中断EXT_INT[0.1.2.3] */
55.
56. /* 当EXT_INT[0]触发中断,即用户按下key1时,
57. ** CPU就会自动的将VIC0VECTADDR0的值赋给VIC0ADDRESS并跳转到这个地址去执 */
58. VIC0VECTADDR0 = (unsigned int)key_isr; /* key1 */
59. VIC0VECTADDR1 = (unsigned int)key_isr; /* key2 */
60. VIC0VECTADDR2 = (unsigned int)key_isr; /* key3 */
61. VIC0VECTADDR3 = (unsigned int)key_isr; /* key4 */
62.
63. uart_send_string("\r\nKey and Uart Test\r\n");
64. while (1);
65.
66. return 0;
67.}
Makefile
[cpp] view plaincopy
01.key.bin: start.o clock.o uart.o key.o
02. arm-linux-ld -Ttext 0xD0020010 -o key.elf $^
03. arm-linux-objcopy -O binary key.elf $@
04. arm-linux-objdump -D key.elf > key.dis
05.
06.%.o : %.c
07. arm-linux-gcc -c $< -o $@
08.%.o : %.S
09. arm-linux-gcc -c $< -o $@
10.
11.clean:
12. rm *.o *.elf *.bin *.dis
程序烧写过程见《TQ210裸机编程(5)——系统时钟配置》
转载请注明来源:http://blog.csdn.net/zjhsucceed_329/
|
|