Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1058811
  • 博文数量: 573
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 66
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-28 16:21
文章分类

全部博文(573)

文章存档

2018年(3)

2016年(48)

2015年(522)

分类: C/C++

2015-12-02 17:28:47

2440init.h文件

点击(此处)折叠或打开

  1. #ifndef _2440INIT_H_
  2. #define _2440INIT_H_

  3. /* WATCHDOG寄存器 */
  4. #define WTCON (*(volatile unsigned long *)0x53000000)
  5. /* SDRAM寄存器 */
  6. #define     MEM_CTL_BASE        0x48000000


  7. /*系统时钟相关寄存器*/
  8. #define    MPLLCON        (*(volatile unsigned long *)0x4c000004)
  9. #define    CLKDIVN        (*(volatile unsigned long *)0x4c000014)
  10. #define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))


  11. /**************************************************************************/
  12. //中断相关寄存器
  13. #define EXTINT0 (*(volatile unsigned long *)0x56000088)
  14. #define EINTMASK (*(volatile unsigned long *)0x560000A4)
  15. #define EINTPEND (*(volatile unsigned long *)0x560000A8)

  16. #define SRCPND (*(volatile unsigned long *)0x4A000000)
  17. #define INTMOD (*(volatile unsigned long *)0x4A000004)
  18. #define INTMSK (*(volatile unsigned long *)0x4A000008)
  19. #define PRIORITY (*(volatile unsigned long *)0x4A00000C)
  20. #define INTPND (*(volatile unsigned long *)0x4A000010)
  21. #define INTOFFSET (*(volatile unsigned long *)0x4A000014)

  22. #define SUBSRCPND (*(volatile unsigned long *)0x4A000018)
  23. #define INTSUBMSK (*(volatile unsigned long *)0x4A00001C)
  24. /**************************************************************************/

  25. /**************************************************************************/
  26. //看门狗相关寄存器
  27. #define WTCON (*(volatile unsigned long *)0x53000000)
  28. #define WTDAT (*(volatile unsigned long *)0x53000004)
  29. #define WTCNT (*(volatile unsigned long *)0x53000008)

  30. #define SRCPND (*(volatile unsigned long *)0x4A000000)
  31. #define INTMOD (*(volatile unsigned long *)0x4A000004)
  32. #define INTMSK (*(volatile unsigned long *)0x4A000008)
  33. #define PRIORITY (*(volatile unsigned long *)0x4A00000C)
  34. #define INTPND (*(volatile unsigned long *)0x4A000010)
  35. #define INTOFFSET (*(volatile unsigned long *)0x4A000014)

  36. #define SUBSRCPND (*(volatile unsigned long *)0x4A000018)
  37. #define INTSUBMSK (*(volatile unsigned long *)0x4A00001C)
  38. /**************************************************************************/

  39. /**************************************************************************/
  40. //按键相关的GPIO
  41. #define GPFCON (*(volatile unsigned long *)0x56000050)
  42. #define GPFDAT (*(volatile unsigned long *)0x56000054)
  43. #define GPFUP (*(volatile unsigned long *)0x56000058)
  44. /*注意:这个程序没有mmu,所以寄存器的地址是物理地址*/

  45. #define GPF0_EINT (2<<(0*2))
  46. #define GPF1_EINT (2<<(1*2))
  47. #define GPF2_EINT (2<<(2*2))
  48. #define GPF4_EINT (2<<(4*2))
  49. /**************************************************************************/

  50. /**************************************************************************/
  51. //LED相关的GPIO
  52. #define GPBDAT (*(volatile unsigned long *)0x56000014)
  53. #define GPBCON (*(volatile unsigned long *)0x56000010)
  54. #define GPBUP (*(volatile unsigned long *)0x56000018)
  55. /*注意:这个程序没有mmu,所以寄存器的地址是物理地址*/

  56. #define GPB5_OUT (1<<(5*2))
  57. #define GPB6_OUT (1<<(6*2))
  58. #define GPB7_OUT (1<<(7*2))
  59. #define GPB8_OUT (1<<(8*2))

  60. #define GPB5_ON (~(1<<5))
  61. #define GPB6_ON (~(1<<6))
  62. #define GPB7_ON (~(1<<7))
  63. #define GPB8_ON (~(1<<8))

  64. #define GPB5_OFF (1<<5)
  65. #define GPB6_OFF (1<<6)
  66. #define GPB7_OFF (1<<7)
  67. #define GPB8_OFF (1<<8)
  68. /**************************************************************************/


  69. /**************************************************************************/
  70. //串口相关寄存器
  71. #define rULCON0 (*(volatile unsigned *)0x50000000)
  72. #define rUCON0 (*(volatile unsigned *)0x50000004)
  73. #define rUFCON0 (*(volatile unsigned *)0x50000008)
  74. #define rUMCON0 (*(volatile unsigned *)0x5000000c)
  75. #define rUTRSTAT0 (*(volatile unsigned *)0x50000010)
  76. #define rUBRDIV0 (*(volatile unsigned *)0x50000028)

  77. #define WrUTXH0(ch) (*(volatile unsigned char *)0x50000020)=(unsigned char)(ch)
  78. #define RdURXH0() (*(volatile unsigned char *)0x50000024)

  79. #define rGPHCON (*(volatile unsigned *)0x56000070)
  80. #define rGPHUP (*(volatile unsigned *)0x56000078)

  81. #define PCLK 50000000 // init.c中的clock_init函数设置PCLK为50MHz
  82. #define UART_CLK PCLK // UART0的时钟源设为PCLK
  83. #define UART_BAUD_RATE 115200 // 波特率
  84. #define UART_BRD ((UART_CLK / (UART_BAUD_RATE * 16)) - 1)

  85. void init_uart(void);
  86. void uart_sendByte(int data);
  87. void uart_sendString(char *p);
  88. void uart_sendByte_hex(unsigned long val);
  89. char uart_getch(void);
  90. void uart_getString(char *string);
  91. /**************************************************************************/

  92. void disable_watch_dog();
  93. void memsetup();
  94. void clock_init(void);
  95. void init_led();
  96. void init_irq();

  97. #endif
init.c文件

点击(此处)折叠或打开

  1. #include "2440init.h"

  2. /*
  3.  * 功能:初始化watchdog相关寄存器
  4.  * 注意:watchdog是内部2级中断
  5.  */
  6. void init_watchdog()
  7. {
  8.     //2级源挂起寄存器:第13位是表示看门狗中断发生的
  9.     SUBSRCPND |= (1<<13);
  10.     
  11.     //源挂起寄存器:第9位是表示看门狗中断发生的
  12.     SRCPND |= (1<<9);
  13.     INTPND |= (1<<9);
  14.     
  15.     //2级中断屏蔽寄存器:第13位是表示看门狗中断使能
  16.     INTSUBMSK &= ~(1<<13);
  17.     INTMSK &= ~(1<<9);
  18.     
  19.     /*看门狗控制寄存器 :WTCON
  20.     *[15:8]=0x60,预分频系数
  21.     *[5] 0:看门狗停止 1:看门狗启动
  22.     *[4:3]=(11)b 分频系数:0b00:16,0b01:32,0b10:64,0b11:128
  23.     *[2]=0:禁止中断,1:使能中断
  24.     *[0]=1:当定时器达到0时输出复位信号 0:当定时器达到0时不输出复位信号
  25.     *看门狗的工作频率 f_dog = PCLK/((预分频系数+1)*分频系数)
  26.     *WTCNT每减1所消耗的时间 t_dog = 1/f_dog
  27.     */
  28.     WTCON |= ((0x60 << 8) | (1<<3) | (1<<0));
  29.     WTCON &= (~(1<<2)); //禁止中断
  30.     
  31.     /*看门狗控制数据寄存器 :WTDAT 只有16位
  32.     *决定看门狗的超时周期 即定时周期,定时时间 T = t_dog * WTDAT
  33.     *在定时器启动后,当计数器达到0时,WTDAT的值会自动赋值给WTCNT。
  34.     *但是,第一次启动看门狗时,WTDAT的值不会自动赋值给WTCNT,需要程序员自己赋值。
  35.     */
  36.     WTDAT = 0x6000;
  37.     /*看门狗控制计数寄存器 :WTCNT
  38.     *第一次启动时,程序员必须手工向这个寄存器赋值。
  39.     *之后,每次计数达到0,WTDAT的值会自动赋值给WTCNT。
  40.     *看门狗启动之后,这个寄存器就开始自动减1.
  41.     */
  42.     WTCNT = 0x6000;
  43.     
  44.     WTCON &= ~(1<<0); //不输出复位信号
  45.     WTCON |= (1<<2); //使能中断
  46.     /*上面的配置:将看门狗定时器做普通定时器用。一般需要上面2行
  47.      做普通定时器用时,产生的是 普通中断 IRQ
  48.     */
  49.     
  50.     WTCON |= (1<<5); //一般把看门狗启动单独列出来,放在初始化程序的最后
  51. }

  52. /*
  53.  * 功能:初始化按键相关的GPIO引脚为外部中断
  54.  * 本程序:
  55.  * K1 : EINT1,引脚是GPF1
  56.  * K2 : EINT4,引脚是GPF4
  57.  * K3 : EINT2,引脚是GPF2
  58.  * K4 : EINT0,引脚是GPF0
  59.  */
  60. void init_irq()
  61. {
  62.      GPFCON = (GPF0_EINT | GPF1_EINT | GPF2_EINT | GPF4_EINT); /*设置这几个引脚为中断功能*/
  63.     GPFUP = 0x00;
  64.     
  65.     EXTINT0 = 0x00; /*设置外部中断控制寄存器,低电平触发,默认也是0x00,所以这句可以不要*/
  66.         
  67.         /*设置外部中断屏蔽寄存器,EINT4~EINT24,共20个需要在这个寄存器中使能他们,
  68.          *EINTMASK只能使能EINT4, EINT0,EINT1,EINT2,EINT3 不受EINTMASK控制
  69.          *EINTMASK[4]:禁止/使能EINT4
  70.          */
  71.         EINTMASK &= (~(1<<4));
  72.         
  73.         /*设置模式寄存器 :在IRQ模式中处理,默认也是0x00,所以这句可以不要*/
  74.         INTMOD = 0x00;
  75.         
  76.         /*设置中断优先级寄存器
  77.         *仲裁租0和6,优先级不轮换使能,每个仲裁组下优先级顺序:0-1-2-3-4-5-6,默认也是这个顺序
  78.         *最终按键产生中断的优先级顺序:K4(EINT0) > K1(EINT1) > K3(EINT2) > K2(EINT4)
  79.         */
  80.         PRIORITY &= (~(1<<0)) & (~(1<<6)) ;
  81.         
  82.         /*设置中断屏蔽寄存器,一级中断
  83.         *INTMSK[0]:禁止/使能EINT0
  84.         *INTMSK[1]:禁止/使能EINT1
  85.         *INTMSK[2]:禁止/使能EINT2
  86.         *INTMSK[4]:禁止/使能EINT4~EINT7
  87.         */
  88.         INTMSK &= (~(1<<0)) & (~(1<<1)) & (~(1<<2)) & (~(1<<4)); /*其实到这里,中断仍未完全开启,CPSR的I位还要清0*/
  89. }

  90. /*
  91.  * 功能:初始化LED的GPIO引脚
  92.  */
  93. void init_led()
  94. {
  95.      GPBCON = (GPB5_OUT | GPB6_OUT | GPB7_OUT | GPB8_OUT);
  96.     GPBUP = 0x1e0;
  97.     GPBDAT = (GPB5_OFF | GPB6_OFF | GPB7_OFF | GPB8_OFF);
  98. }

  99. /*
  100.  * 对于MPLLCON寄存器,[19:12]为MDIV,[9:4]为PDIV,[1:0]为SDIV
  101.  * 有如下计算公式:
  102.  * S3C2440: MPLL(FCLK) = (2 * m * Fin)/(p * 2^s)
  103.  * 其中: m = MDIV + 8 = 92+8, p = PDIV + 2 = 1+2, s = SDIV = 2
  104.  * 对于本开发板,Fin = 12MHz
  105.  * 设置CLKDIVN,令分频比为:FCLK:HCLK:PCLK=1:2:4,
  106.  * FCLK=200MHz,HCLK=100MHz,PCLK=50MHz
  107.  */
  108. void clock_init(void)
  109. {
  110.     // LOCKTIME = 0x00ffffff; // 使用默认值即可
  111.     CLKDIVN = 0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
  112.     /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
  113. __asm__(
  114.     "mrc p15, 0, r1, c1, c0, 0\n" /* 读出控制寄存器 */
  115.     "orr r1, r1, #0xc0000000\n" /* 设置为“asynchronous bus mode” */
  116.     "mcr p15, 0, r1, c1, c0, 0\n" /* 写入控制寄存器 */
  117.     );

  118.     MPLLCON = S3C2440_MPLL_200MHZ;
  119.     /* 现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz
  120.     并不保证你的任何设置都是合适的。所以,如果想要工作在200MHz,还是按照vivi的推荐值((0x5c<<12)|(0x01<<4)|(0x02))即可。
  121.     */
  122. }
  123. /*
  124.  * 关闭WATCHDOG,否则CPU会不断重启
  125.  */
  126. void disable_watch_dog(void)
  127. {
  128.     WTCON = 0; // 关闭WATCHDOG很简单,往这个寄存器写0即可
  129. }

  130. /*
  131. *功能:设置存储控制器以使用SDRAM
  132. *注意:REFRESH寄存器有特殊
  133. * 未开启PLL时:HCLK=12MHz: REFRESH寄存器值取: 0x008C07A3,
  134. * 开启PLL时:HCLK=100MHz: REFRESH寄存器值取: 0x008C04F4
  135. */
  136. void memsetup(void)
  137. {
  138.     /* SDRAM 13个寄存器的值 */
  139.     unsigned long const mem_cfg_val[]={ 0x22011110, //BWSCON
  140.                                             0x00000700, //BANKCON0
  141.                                             0x00000700, //BANKCON1
  142.                                             0x00000700, //BANKCON2
  143.                                             0x00000700, //BANKCON3
  144.                                             0x00000700, //BANKCON4
  145.                                             0x00000700, //BANKCON5
  146.                                             0x00018005, //BANKCON6
  147.                                             0x00018005, //BANKCON7
  148.                                             0x008C04F4, //REFRESH
  149.                                             0x000000B1, //BANKSIZE
  150.                                             0x00000030, //MRSRB6
  151.                                             0x00000030, //MRSRB7
  152.                                     };
  153.     int i = 0;
  154.     volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;
  155.     for(; i < 13; i++)
  156.         p[i] = mem_cfg_val[i];
  157. }









  158. /***********************************************************************************/
  159. //串口相关函数
  160. /*功能:初始化串口UART0
  161. *轮询方式来使用串口
  162. */
  163. void init_uart(void)
  164. {
  165.      /*GPHCON寄存器
  166.     [7:6]=10,GPH2作为TXD0,串口发送数据引脚
  167.     [5:4]=10,GPH3作为RXD0,串口接受数据引脚
  168.     GPH2,GPH3控制串口通道0
  169.     GPH4,GPH5控制串口通道1
  170.     GPH6,GPH7控制串口通道2
  171.     */
  172.         rGPHCON = ((2<<6)|(2<<4)|(0<<2)|(0<<0));
  173.         rGPHUP = ((1<<3)|(1<<2)); /*禁止上拉*/
  174.         
  175.         /*ULCON0串口线路控制寄存器:设置传输格式
  176.         [6]=0,普通模式,非红外工作模式
  177.         [5:3]=000,无奇偶校验位,100=奇校验,101=偶校验,110=固定校验位为1,111=固定校验位为0
  178.         [2]=0,每帧1个停止位,1:每帧2个停止位
  179.         [1:0]=11,8位,每帧发送或接受的数据位的个数。00=5位,01=6位,10=7位
  180.         */
  181.         rULCON0 = 0x3;
  182.         
  183.         /*UCON0:串口控制寄存器:用于选择UART时钟源,设置UART中断方式
  184.         [15:12]:[11:10]选择PCLK时,这4位无效。选择FCLK/n时,表示n值。
  185.         [11:10]=00: 选择PCLK给UART比特率,10:PCLK, 01:UEXTCLK, 11:FCLK/n。
  186.         [9]=1: 中断请求类型
  187.         [8]=0: 中断请求类型
  188.         [7]=0: 禁止超时中断,1:使能超时中断
  189.         [6]=1: 产生接受错误状态中断,1:不产生接受错误状态中断
  190.         [5]=0: 正常操作,非回环模式。发送引脚发送的数据,直接到达接受引脚,一般是测试用。
  191.         [4]=0: 正常操作,不发送断电信号
  192.         [3:2]=01: 发送模式,中断或者轮询,如果中断寄存器不设置,就是轮询。
  193.         [1:0]=01: 接受模式,中断或者轮询
  194.         */
  195.         rUCON0 = 0x5;
  196.         
  197.         /*UFCON:串口FIFO控制寄存器:用于设置是否使用FIFO,设置各FIFO的触发阀值。
  198.         [7:6]=发送FIFO的触发深度,即在发送时,发送FIFO中还剩有多少个数据时,才触发中断,告诉CPU可以继续发送了。
  199.         [5:4]=接受FIFO的触发深度,即在接受时,接受FIFO中接受了多少个数据后,才触发中断,告诉CPU已经有接受到的数据了。
  200.         [3]=
  201.         [2]=TX的FIFO是否复位
  202.         [1]=RX的FIFO是否复位
  203.         [0]=0,不使用FIFO,非FIFO模式,相当于接受和发送时,不使用缓冲寄存器,上面的设置无效。如果这里是1,则上面的位肯定有对应的设置。
  204.         */
  205.         rUFCON0 = 0x0;
  206.         
  207.         /*UMCON:串口MODEM控制寄存器:用于流量控制
  208.         [7:5]=000,规定必须为0
  209.         [4]=0:禁止自动流控制(AFC),即不使用流控。一般不使用这种硬件自动流控制手段。
  210.         [3:1]=000:规定必须为0
  211.         [0]=0:高电平(撤销nRTS),1:低电平(激活nRTS),因为,AFC位禁止,nRTS必须由软件控制。如果AFC使能,则忽略这个位。
  212.         */
  213.         rUMCON0 = 0x0;
  214.         
  215.         /*UBRDIV:波特率分频寄存器:用于设置波特率
  216.         [15:0],波特率分频值。使用UEXTCLK作为输入时钟时,可以设置UBRDIV为0.
  217.         UBRDIV = (int)(UART时钟/(波特率*16))-1
  218.         */
  219.         rUBRDIV0 = UART_BRD;
  220. }

  221. /*功能:向串口发送一个字符
  222. *参数:待发送的字符

  223. UTRSTAT0:用来表明数据是否已经发送完毕,是否已经接受到数据
  224. 串口收发TX/RX状态寄存器,是CPU自动更新的,程序员检测它的状态就行。
  225. [2]:发送移位寄存器空标志。
  226. 检测为0:表示发送移位寄存器非空,或发送缓冲寄存器非空。
  227. 检测为1:表示发送移位寄存器为空,且发送缓冲寄存器为空,程序员可以继续发送数据了。
  228. [1]:发送缓冲区空标志位。
  229. 检测为0:表示发送缓冲寄存器非空,即上次要发送的数据还没有发完。不能太快,否则会覆盖掉。
  230. 检测为1:表示发送缓冲寄存器为空,程序员可以继续发送数据了。(非FIFO模式,非请求中断,非DMA)
  231. 注意:如果UART使用FIFO,用户应该使用UFSTAT寄存器中的Rx FIFO计数位 和 Rx FIFO满位取代对此位的检查。
  232. [0]:接收缓冲器数据就绪标志位。
  233. 检测为0:表示接收缓冲器为空。
  234. 检测为1:表示接收缓冲器接收到有效数据,程序员可以取数据了。(非FIFO模式,非请求中断,非DMA)
  235. 注意:如果UART使用FIFO,用户应该使用UFSTAT寄存器中的Rx FIFO计数位 和 Rx FIFO满位取代对此位的检查。

  236. UTXH0:串口发送缓冲寄存器
  237. [7:0]:串口要发送的数据
  238. */
  239. void uart_sendByte(int data)
  240. {
  241.     if(data == '\n')
  242.     {
  243.         while(!(rUTRSTAT0 &0x2));
  244.         WrUTXH0('\r'); /*回车不换行*/
  245.     }
  246.     /*等待,直到发送缓冲区中的数据已经全部发送出去
  247.     这里也可以检测UTRSTAT0[2]*/
  248.     while(!(rUTRSTAT0 &0x2));
  249.     /*向UTXH0寄存器中写入数据,UART即自动将它发送出去
  250.     #define rUTXH0 (*(volatile unsigned char *)0x50000020)    //UART 0 Transmission Hold
  251.     #define WrUTXH0(ch) (*(volatile unsigned char *)0x50000020)=(unsigned char)(ch)
  252.     所以:WrUTXH0(data); 相当于 rUTXH0 = data;
  253.     */
  254.     WrUTXH0(data);
  255. }

  256. /*功能:向串口打印一个字符串
  257. *参数:待打印的字符串
  258. */
  259. void uart_sendString(char *p)
  260. {
  261.     while(*p)
  262.         uart_sendByte(*p++);
  263. }

  264. /*功能:向串口打印一个字符的16进制格式
  265. *参数:待打印的字符
  266. * 数字0=0x30,数字9=0x39
  267. */
  268. void uart_sendByte_hex(unsigned long val)
  269. {
  270.     /* val = 0x1234ABCD */
  271.     unsigned char c;
  272.     int i = 0;
  273.     
  274.     uart_sendByte('0');
  275.     uart_sendByte('x');

  276.     for (i = 0; i < 8; i++)
  277.     {
  278.         c = (val >> ((7-i)*4)) & 0xf;
  279.         if((c >= 0) && (c <= 9))
  280.         {
  281.             c = '0' + c;
  282.         }
  283.         else if ((c >= 0xA) && (c <= 0xF))
  284.         {
  285.             c = 'A' + (c - 0xA);
  286.         }
  287.         uart_sendByte(c);
  288.     }
  289. }

  290. /*功能:向串口格式化打印一个字符串
  291. *参数:格式化的字符串
  292. 这个函数编译不过去,不知道什么原因?????????????
  293. void uart_printf(char* fmt,...)
  294. {
  295.     va_list args; //动态参数列表
  296.     char string[256];
  297.     
  298.     va_start(args,fmt);
  299.     vsprintf(string,fmt, args);
  300.     uart_sendString(string);
  301.     va_end(args);
  302. }
  303. */

  304. /*功能:从串口接受一个字符
  305. *返回值:接受到的字符

  306. UTRSTAT0: 串口收发TX/RX状态寄存器
  307. [0]:接收缓冲器数据就绪标志位。
  308. 0:接收缓冲器为空
  309. 1:接收缓冲器接收到有效数据(非FIFO模式,非请求中断,非DMA)
  310. 注意:如果UART使用FIFO,用户应该使用UFSTAT寄存器中的Rx FIFO计数位 和 Rx FIFO满位取代对此位的检查。

  311. URXH0:串口接受缓冲寄存器
  312. [7:0]:串口接受到的数据
  313. */
  314. char uart_getch(void)
  315. {
  316.     /*等待,直到接受缓冲区中有数据*/
  317.     while(!(rUTRSTAT0 & 0x1));
  318.     /*直接读取URXH0寄存器,即可以获得接受到的数据
  319.     #define rURXH0 (*(volatile unsigned char *)0x50000024)    //UART 0 Receive buffer
  320.     #define RdURXH0() (*(volatile unsigned char *)0x50000024)
  321.     所以:return RdURXH0(); 相当于:return rURXH0;
  322.     */
  323.     return RdURXH0();
  324. }

  325. /*功能:从串口接受一个字符串
  326. *参数:输入的字符串
  327. */
  328. void uart_getString(char *string)
  329. {
  330.     char *string2 = string;
  331.     char c;
  332.     while((c=uart_getch()) != '\r')
  333.     {
  334.         if(c == '\b')
  335.         {
  336.             if((int)string2 < (int)string)
  337.             {
  338.                 //uart_printf("\b\b");
  339.                 string--;
  340.             }
  341.         }
  342.         else
  343.         {
  344.             *string++ = c;
  345.             uart_sendByte(c);
  346.         }
  347.     }
  348.     *string = '\0';
  349.     uart_sendByte('\n');
  350. }
  351. /***********************************************************************************/
head.S文件

点击(此处)折叠或打开

  1. @********************************************************************************
  2. @功能:初始化,设置中断模式,系统模式的栈,设置中断处理函数
  3. @********************************************************************************
  4. .text
  5. .global _start
  6. _start:

  7. @设置异常向量表,本程序只使用2个异常
  8. @复位 : Reset 地址:0x00
  9.         b Reset
  10.         
  11. @未定义指令终止 : HandleUndef 地址:0x04
  12. HandleUndef:
  13.         b HandleUndef
  14.         
  15. @软件中断 : HandleSWI 地址:0x08
  16. HandleSWI:
  17.         b HandleSWI
  18.         
  19. @指令欲取指终止 : HandlePrefetchAbort 地址:0x0C
  20. HandlePrefetchAbort:
  21.         b HandlePrefetchAbort
  22.         
  23. @数据访问终止 : HandleDataAbort 地址:0x10
  24. HandleDataAbort:
  25.         b HandleDataAbort

  26. @保留 : HandleNotUsed 地址:0x14
  27. HandleNotUsed:
  28.         b HandleNotUsed
  29.         
  30. @普通中断 : HandleIRQ 地址:0x18
  31.         b HandleIRQ

  32. @快速中断 : HandleFIQ 地址:0x1C
  33. HandleFIQ:
  34.         b HandleFIQ

  35. @产生复位异常时,跳转到这里来
  36. Reset:
  37.         LDR SP, =4096                    @设置栈指针,下面调用的是c函数,调用前需要设好栈。复位时,cpu进去系统模式,所以是系统模式栈指针
  38.         BL disable_watch_dog    @关看门狗
  39.         BL memsetup                        @初始化SDRAM寄存器,这个程序在4K内跑,没有用到SDRAM,所以这里可以没有
  40.         BL clock_init                    @设置系统时钟
  41.         BL init_uart                    @初始化串口
  42.         
  43.         MSR cpsr_c, #0xD2            @进入IRQ模式,I位,F位置1:不开中断
  44.         LDR SP, =3072                    @设置IRQ模式的栈指针,sp是sp_irq
  45.         
  46.         MSR cpsr_c, #0xDF            @进入sys模式,I位,F位置1:不开中断
  47.         LDR SP, =4096                    @设置sys模式的栈指针,sp是sp_sys
  48.         
  49.         BL init_led                        @初始化LED的GPIO引脚
  50.         BL init_irq                        @初始化外部中断相关的寄存器
  51.         BL init_watchdog @初始化看门狗相关的寄存器
  52.         MSR cpsr_c, #0x5F            @设置 I位=0,F位=1:开IRQ中断,不开FIQ
  53.         LDR LR, =my_loop            @设置Reset函数的返回地址
  54.         LDR PC, =main                    @调用main函数
  55.         
  56. my_loop:
  57.         B my_loop

  58. @产生普通中断时,跳转到这里来
  59. HandleIRQ:
  60.         SUB LR, LR, #4 @计算中断处理完毕之后的返回地址
  61.         STMDB { r0-r12, LR } @保存中断程序的运行环境,即保存使用到的寄存器,sp是中断模式的栈sp_irq
  62.         
  63.         LDR LR, =int_return @设置EINT_Handle函数执行完后的返回地址
  64.         LDR PC, =EINT_Handle @调用IRQ中断服务函数
  65. int_return:
  66.         LDMIA { r0-r12, PC }^ @中断返回,^表示将SPSR的值复制到CPSR
  67.                                                                 @上面这句:将恢复中断程序的运行环境。
  68.                                                                 @进入中断模式时,CPU自动将原来的CPSR值保存到SPSR中,这里会将SPSR的值复制到CPSR,这会导致CPU切换到原来的工作模式(即调用中断前的工作模式)
interrupt.c文件

点击(此处)折叠或打开

  1. #include "2440init.h"

  2. /*
  3. *功能:中断服务子程序
  4. *注意:1,按键产生中断的优先级顺序:K4(EINT0) > K1(EINT1) > K3(EINT2) > K2(EINT4)
  5. * 所以,同时按下其中2个,3个或者4个,只有优先级最高的哪个LED会被点亮
  6. * 2,如果硬件接线有LED连接了EINT4,EINT5,由于他们的中断优先级相同,EINTPEND[4:5]都是1,但都只会让SRCPND[4]=1,
  7. * 如果他们同时按下,则INTPND[4]=1,且INTOFFSET=4,走到case 4,EINTPEND[4:5]=11b,2个if都成立,所以,最后这2个LED会被同时点亮。
  8. */
  9. void EINT_Handle()
  10. {
  11.             /*INTOFFSET:中断偏移寄存器,INTPND寄存器中的值被置1之后,中断偏移寄存器的值=32个一级中断的编号*/
  12.             unsigned long offset = INTOFFSET;
  13.             unsigned long eintval;

  14.             uart_sendString("\n\nINTOFFSET=");
  15.             uart_sendByte_hex(offset);
  16.             uart_sendByte('\n');

  17.             switch(offset)
  18.             {
  19.                     /*EINT0中断:K4被按下*/
  20.                     case 0:
  21.                     {
  22.                                 uart_sendString("K4 ON!->LED4 ON!\n");
  23.                                 GPBDAT = (GPB5_OFF | GPB6_OFF | GPB7_OFF | GPB8_OFF);
  24.                                 GPBDAT = GPB8_ON; /*LED4亮*/
  25.                                 break;
  26.                     }
  27.                     /*EINT1中断:K1被按下*/
  28.                     case 1:
  29.                     {
  30.                                 uart_sendString("K1 ON!->LED1 ON!\n");
  31.                                 GPBDAT = (GPB5_OFF | GPB6_OFF | GPB7_OFF | GPB8_OFF);
  32.                                 GPBDAT = GPB5_ON; /*LED1亮*/
  33.                                 break;
  34.                     }
  35.                     /*EINT2中断:K3被按下*/
  36.                     case 2:
  37.                     {
  38.                                 uart_sendString("K3 ON!->LED3 ON!\n");
  39.                                 GPBDAT = (GPB5_OFF | GPB6_OFF | GPB7_OFF | GPB8_OFF);
  40.                                 GPBDAT = GPB7_ON; /*LED3亮*/
  41.                                 break;
  42.                     }
  43.                     /*EINT4~EINT7中断:虽然这里可以肯定是,EINT4,K2被按下,但是还是做一下判断:具体是EINT4到EINT7中的哪一个?*/
  44.                     case 4:
  45.                     {
  46.                                 GPBDAT = (GPB5_OFF | GPB6_OFF | GPB7_OFF | GPB8_OFF);
  47.                                 
  48.                                 /*EINTPEND:外部中断挂起寄存器
  49.                                 *EINTPEND低4位保留
  50.                                 *EINTPEND[4]=1 : 表示EINT4发生
  51.                                 *EINTPEND[5]=1 : 表示EINT5发生
  52.                                 */
  53.                                 eintval = EINTPEND;
  54.                                 if(eintval & (1<<4))
  55.                                 {
  56.                                         uart_sendString("K2 ON!->LED2 ON!\n");
  57.                                         GPBDAT = GPB6_ON; /*LED2亮*/
  58.                                 }
  59.                                 if(eintval & (1<<5))
  60.                                 {
  61.                                         
  62.                                 }
  63.                                 break;
  64.                     }
  65.                     /*看门狗INT_WDT_AC97中断: 将看门狗定时器做 普通定时器用,产生的中断*/
  66.                     case 9:
  67.                     {
  68.                          //看门狗中断时 内部中断 2级中断,所以必须清除 SUBSRCPND,当然 SRCPND INTPND也需要清除
  69.                                 SUBSRCPND |= (1<<13);
  70.                                 //SRCPND |= (1<<9); //程序后面有做,这里可以不在写了。
  71.                                 //INTPND |= (1<<9);
  72.                                 uart_sendString("\n watchdog interrupt!\n");
  73.                                 break;
  74.                     }
  75.                     default:
  76.                     {
  77.                                 break;
  78.                     }
  79.             }
  80.             /*中断处理完成之后:必须清除所有的挂起寄存器
  81.             *注意:向挂起寄存器中写1,即可令此位为0;写入0是没有效果的,若写入0,挂起寄存器中的数据保持不变。
  82.             */
  83.             if(offset == 4) /*二级外部中断,还必须清除 EINTPEND*/
  84.             {
  85.                      EINTPEND = (1<<4);
  86.             }
  87.             SRCPND = (1<<offset);
  88.             uart_sendString("SRCPND=");
  89.             uart_sendByte_hex(SRCPND);
  90.             uart_sendByte('\n');
  91.             
  92.             INTPND = (1<<offset);
  93.             uart_sendString("INTPND=");
  94.             uart_sendByte_hex(SRCPND);
  95.             uart_sendString("\n*************************************");
  96.             /*在清除 SRCPND INTPND时,INTOFFSET会被自动清除*/
  97. }
main.c文件

点击(此处)折叠或打开

  1. #include "2440init.h"

  2. int main()
  3. {
  4.      //本实验将看门狗定时器做 普通定时器用
  5.         uart_sendString("\n main begin: \n"); //如果这一句不停的打印出现,将表示系统一直在复位。
  6.         while(1)
  7.         {
  8.             //喂狗:在WTCNT减少到0之前,即在定时时间到来之前,给下面2个寄存器赋值,否则定时时间到,系统将复位。
  9.             //WTDAT = 0x6000;
  10.             //WTCNT = 0x6000;
  11.         }
  12.         return 0;
  13. }
makefile文件

点击(此处)折叠或打开

  1. objs := head.o init.o interrupt.o main.o

  2. watchdog.bin: $(objs)
  3.     arm-linux-ld -Ttext 0x00000000 -o watchdog_elf $^
  4.     arm-linux-objcopy -O binary -S watchdog_elf $@
  5.     arm-linux-objdump -D -m arm watchdog_elf > watchdog.dis
  6.     
  7. %.o:%.c
  8.     arm-linux-gcc -Wall -O2 -c -o $@ $<

  9. %.o:%.S
  10.     arm-linux-gcc -Wall -O2 -c -o $@ $<

  11. clean:
  12.     rm -f watchdog.bin watchdog_elf watchdog.dis *.o

阅读(1751) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~