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

全部博文(573)

文章存档

2018年(3)

2016年(48)

2015年(522)

分类: LINUX

2015-12-02 11:27:10

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. void disable_watch_dog();
  12. void clock_init(void);
  13. void memsetup();
  14. void copy_steppingstone_to_sdram(void);

  15. #endif
init.c文件

点击(此处)折叠或打开

  1. #include "2440init.h"
  2. #include "uart.h"

  3. /*
  4.  * 关闭WATCHDOG,否则CPU会不断重启
  5.  */
  6. void disable_watch_dog(void)
  7. {
  8.     WTCON = 0; // 关闭WATCHDOG很简单,往这个寄存器写0即可
  9. }

  10. /*
  11.  * 对于MPLLCON寄存器,[19:12]为MDIV,[9:4]为PDIV,[1:0]为SDIV
  12.  * 有如下计算公式:
  13.  * S3C2440: MPLL(FCLK) = (2 * m * Fin)/(p * 2^s)
  14.  * 其中: m = MDIV + 8 = 92+8, p = PDIV + 2 = 1+2, s = SDIV = 2
  15.  * 对于本开发板,Fin = 12MHz
  16.  * 设置CLKDIVN,令分频比为:FCLK:HCLK:PCLK=1:2:4,
  17.  * FCLK=200MHz,HCLK=100MHz,PCLK=50MHz
  18.  */
  19. void clock_init(void)
  20. {
  21.     // LOCKTIME = 0x00ffffff; // 使用默认值即可
  22.     CLKDIVN = 0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
  23.     /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
  24. __asm__(
  25.     "mrc p15, 0, r1, c1, c0, 0\n" /* 读出控制寄存器 */
  26.     "orr r1, r1, #0xc0000000\n" /* 设置为“asynchronous bus mode” */
  27.     "mcr p15, 0, r1, c1, c0, 0\n" /* 写入控制寄存器 */
  28.     );

  29.     MPLLCON = S3C2440_MPLL_200MHZ;
  30.     /* 现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz
  31.     并不保证你的任何设置都是合适的。所以,如果想要工作在200MHz,还是按照vivi的推荐值((0x5c<<12)|(0x01<<4)|(0x02))即可。
  32.     */
  33. }

  34. /*
  35. *功能:设置存储控制器以使用SDRAM
  36. *注意:REFRESH寄存器有特殊
  37. * 未开启PLL时:HCLK=12MHz: REFRESH寄存器值取: 0x008C07A3,
  38. * 开启PLL时:HCLK=100MHz: REFRESH寄存器值取: 0x008C04F4
  39. *在这个程序里面,为什么不能用下面这个函数,原因还没搞清楚。

  40.         链接地址指定为:0x30000000时,这个数组的反汇编代码:
  41.         300003c0 <.rodata>:
  42.         300003c0:    22011110     andcs    r1, r1, #4    ; 0x4
  43.         300003c4:    00000700     andeq    r0, r0, r0, lsl #14
  44.         300003c8:    00000700     andeq    r0, r0, r0, lsl #14
  45.         300003cc:    00000700     andeq    r0, r0, r0, lsl #14
  46.         300003d0:    00000700     andeq    r0, r0, r0, lsl #14
  47.         300003d4:    00000700     andeq    r0, r0, r0, lsl #14
  48.         300003d8:    00000700     andeq    r0, r0, r0, lsl #14
  49.         300003dc:    00018005     andeq    r8, r1, r5
  50.         300003e0:    00018005     andeq    r8, r1, r5
  51.         300003e4:    008c04f4     streqd    r0, [ip], r4
  52.         300003e8:    000000b1     streqh    r0, [r0], -r1
  53.         300003ec:    00000030     andeq    r0, r0, r0, lsr r0
  54.         300003f0:    00000030     andeq    r0, r0, r0, lsr r0
  55.         Disassembly of section .rodata.str1.4:
  56.         
  57.         链接地址指定为:0x0时,这个数组的反汇编代码:
  58.         000003c0 <.rodata>:
  59.         3c0:    22011110     andcs    r1, r1, #4    ; 0x4
  60.         3c4:    00000700     andeq    r0, r0, r0, lsl #14
  61.         3c8:    00000700     andeq    r0, r0, r0, lsl #14
  62.         3cc:    00000700     andeq    r0, r0, r0, lsl #14
  63.         3d0:    00000700     andeq    r0, r0, r0, lsl #14
  64.         3d4:    00000700     andeq    r0, r0, r0, lsl #14
  65.         3d8:    00000700     andeq    r0, r0, r0, lsl #14
  66.         3dc:    00018005     andeq    r8, r1, r5
  67.         3e0:    00018005     andeq    r8, r1, r5
  68.         3e4:    008c04f4     streqd    r0, [ip], r4
  69.         3e8:    000000b1     streqh    r0, [r0], -r1
  70.         3ec:    00000030     andeq    r0, r0, r0, lsr r0
  71.         3f0:    00000030     andeq    r0, r0, r0, lsr r0
  72.         Disassembly of section .rodata.str1.4:

  73. 可以看出来,这个数组中的数据放在ro段。

  74. 1,链接脚本只能决定你的各个段的地址,但是如果里面某个函数的代码没有访问任何与绝对地址相关的东西。是可以在任意地址运行的。

  75. 2,这段代码中数组里面的数据一般会放在RO段,是在链接的时候决定了他的位置,并且访问时以链接的绝对地址访问。
  76.         
  77.         链接起始地址指定为:0x30000000时,打印结果如下:
  78.         mem_cfg_val[0]的地址=0x00000FB4,=0xFFFFFFFF:
  79.         因为:mem_cfg_val[0]数组存放在4k内的物理地址0x00000FB4中,但是,程序会从连接地址0x300003c0中取值,所以是不对的值。
  80.         ......
  81.         mem_cfg_val[10]的地址=0x00000FE0,=0xFFFFFFFF
  82.         mem_cfg_val[10]的地址=0x00000FE4,=0xFFFFFFFF
  83.         
  84.         上面的值,明显是垃圾数据,那为什么地址不是0x300开头的地址?
  85.         
  86.         链接起始地址指定为:0x0时,打印结果如下:
  87.         mem_cfg_val[0]的地址=0x00000FB4,=0x22011110:
  88.         因为:mem_cfg_val[0]数组存放在4k内的物理地址0x00000FB4中,程序会从连接地址0x000003c0中取值,所以值是对的。
  89.         mem_cfg_val[1]的地址=0x00000FB8,=0x00000700
  90.         ......
  91.         mem_cfg_val[8]的地址=0x00000FD4,=0x00018005
  92.         mem_cfg_val[9]的地址=0x00000FD8,=0x008C04F4
  93.         ......
  94.         mem_cfg_val[12]的地址=0x00000FE4,=0x00000030
  95.         值是正常的
  96.         
  97. void memsetup(void)
  98. {
  99.         //init_uart();
  100.         uart_sendByte('\n');
  101.         uart_sendByte('w');
  102.         uart_sendByte('x');
  103.         uart_sendByte('c');
  104.         uart_sendByte('\n');
  105.         
  106.         // 连接地址是0x0时,这个函数是可以随便用的。
  107.     // 这个数组的地址是:连接地址0x30000000开始中的某个地址,不是映象文件的偏移物理地址0x0开始的。
  108.     // 即由于连接地址 和 映象文件的偏移物理地址 不是相同的地址值,
  109.     // 刚开始运行时是 映象文件的偏移物理地址,所以取连接地址中的值的时候,取不到想要的值
  110.     unsigned long const mem_cfg_val[]={ 0x22011110, //BWSCON
  111.                                             0x00000700, //BANKCON0
  112.                                             0x00000700, //BANKCON1
  113.                                             0x00000700, //BANKCON2
  114.                                             0x00000700, //BANKCON3
  115.                                             0x00000700, //BANKCON4
  116.                                             0x00000700, //BANKCON5
  117.                                             0x00018005, //BANKCON6
  118.                                             0x00018005, //BANKCON7
  119.                                             0x008C04F4, //REFRESH
  120.                                             0x000000B1, //BANKSIZE
  121.                                             0x00000030, //MRSRB6
  122.                                             0x00000030, //MRSRB7
  123.                                     };
  124.     int i = 0;
  125.     
  126.     volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;
  127.     for(; i < 13; i++)
  128.        {
  129.                uart_sendByte('\n');
  130.                 uart_sendByte('n');
  131.                 uart_sendByte('o');
  132.                 uart_sendByte('.');
  133.                 uart_sendByte_hex((unsigned long)i);
  134.                 uart_sendByte(':');
  135.                uart_sendByte_hex((unsigned long)(&(mem_cfg_val[i]))); //为什么打印出来的不是连接地址啊???
  136.                uart_sendByte('=');
  137.                uart_sendByte_hex((unsigned long)(mem_cfg_val[i]));
  138.                uart_sendByte('\n');
  139.                
  140.         p[i] = mem_cfg_val[i];
  141.     }
  142. }
  143. */

  144. void memsetup(void)
  145. {
  146.     volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;

  147.     // 这个函数之所以这样赋值,而不是像前面的实验(比如mmu实验)那样将配置值
  148.     // 写在数组中,是因为要生成”位置无关的代码”,使得这个函数可以在被复制到
  149.     // SDRAM之前就可以在steppingstone中运行
  150.     // 存储控制器13个寄存器的值
  151.     p[0] = 0x22011110; //BWSCON
  152.     p[1] = 0x00000700; //BANKCON0
  153.     p[2] = 0x00000700; //BANKCON1
  154.     p[3] = 0x00000700; //BANKCON2
  155.     p[4] = 0x00000700; //BANKCON3
  156.     p[5] = 0x00000700; //BANKCON4
  157.     p[6] = 0x00000700; //BANKCON5
  158.     p[7] = 0x00018005; //BANKCON6
  159.     p[8] = 0x00018005; //BANKCON7
  160.     
  161.                                             // REFRESH,
  162.                                             // HCLK=12MHz: 0x008C07A3,
  163.                                             // HCLK=100MHz: 0x008C04F4
  164.     p[9] = 0x008C04F4;
  165.     p[10] = 0x000000B1; //BANKSIZE
  166.     p[11] = 0x00000030; //MRSRB6
  167.     p[12] = 0x00000030; //MRSRB7
  168. }

  169. /*
  170. *功能:复制启动石中的4K代码,到SDRAM中去
  171. */
  172. void copy_steppingstone_to_sdram(void)
  173. {
  174.     unsigned int * src = (unsigned int *)0x0; /*片内4K内存*/
  175.     unsigned int * des = (unsigned int *)0x30000000; /*SDRAM起始地址,全部是物理地址*/
  176.     
  177.     while (src < (unsigned int *)4096) /*复制4K空间*/
  178.     {
  179.         *des = *src;
  180.         des++;
  181.         src++;
  182.     }
  183. }
head.S文件

点击(此处)折叠或打开

  1. @******************************************************************************
  2. @ File:head.S
  3. @ 功能:设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行
  4. @******************************************************************************
  5. .extern main
  6. .text
  7. .global _start
  8. _start:
  9.     ldr sp, =4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈
  10.     bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启
  11.     @ bl是位置无关码,相当于:PCnew = PC + 偏移
  12.     @ PCnew = (4+8) + 0x28 = 0x34
  13.     
  14.     @ ldr pc, =disable_watch_dog
  15.     @ ldr是位置相关码,相当于:PC=链接脚本中指定的链接地址0x30000034,走到这里时,程序会崩溃,所以不能使用LDR。
  16.     
  17.     bl clock_init @ 设置MPLL,改变FCLK、HCLK、PCLK
  18.     bl init_uart
  19.     bl memsetup @ 设置存储控制器以使用SDRAM
  20.     bl copy_steppingstone_to_sdram @ 复制代码到SDRAM中,在这之前,需要使用位置无关码。从这之后,使用的指令是不是位置无关码,没有关系了
  21.     
  22.     ldr pc, =on_sdram @ 跳到SDRAM中继续执行
  23. on_sdram:
  24.     ldr sp, =4096 @ 设置栈指针,0x30000000到 0x34000000 ,是SDRAM地址范围,共64M
  25.     ldr lr, =my_loop     @ 设置返回地址
  26.     @ bl main
  27.     ldr pc, =main @ 调用main函数
  28. my_loop:
  29.     b my_loop
leds.c

点击(此处)折叠或打开

  1. #include "2440init.h"
  2. #include "uart.h"

  3. /**************************************************************************/
  4. //LED相关的GPIO
  5. #define GPBDAT (*(volatile unsigned long *)0x56000014)
  6. #define GPBCON (*(volatile unsigned long *)0x56000010)
  7. #define GPBUP (*(volatile unsigned long *)0x56000018)
  8. /*注意:这个程序没有mmu,所以寄存器的地址是物理地址*/

  9. #define GPB5_OUT (1<<(5*2))
  10. #define GPB6_OUT (1<<(6*2))
  11. #define GPB7_OUT (1<<(7*2))
  12. #define GPB8_OUT (1<<(8*2))

  13. #define GPB5_ON (~(1<<5))
  14. #define GPB6_ON (~(1<<6))
  15. #define GPB7_ON (~(1<<7))
  16. #define GPB8_ON (~(1<<8))

  17. #define GPB5_OFF (1<<5)
  18. #define GPB6_OFF (1<<6)
  19. #define GPB7_OFF (1<<7)
  20. #define GPB8_OFF (1<<8)
  21. /**************************************************************************/

  22. /*
  23.  * 功能:初始化LED的GPIO引脚
  24.  * 注意:这个函数用不用inline都一样,不会影响运行,因为head.S中使用的是ldr pc, =main,不是ldr pc, =0x30004000一样绝对的值。
  25.  */
  26. static inline void init_led()
  27. {
  28.      GPBCON = (GPB5_OUT | GPB6_OUT | GPB7_OUT | GPB8_OUT);
  29.     GPBUP = 0x1e0;
  30.     GPBDAT = (GPB5_OFF | GPB6_OFF | GPB7_OFF | GPB8_OFF);
  31. }

  32. /*
  33. *功能:延时函数
  34. */
  35. static void wait(volatile unsigned int num)
  36. {
  37.     unsigned int i = 0;
  38.     unsigned int j = 0;
  39.     for(i=0; i<100; i++)
  40.         for(j=0; j<num; j++);
  41. }


  42. int main(void)
  43. {
  44.         // init_uart(); 在head.S中已经初始化了,这里可以省略
  45.         
  46.         uart_sendString("\n\n UART and LED begin:\n");
  47.         //uart_printf("%s%s:[%s][%s][%s]\n", __DTAE__, __TIME__, __FILE__, __FUNCTION__, __LINE__);
  48.         
  49.     init_led();
  50.     
  51.     int i = 8;
  52.     int j = 802;
  53.     char ch1 = 'a';
  54.     char ch2 = 'A';
  55.     unsigned long num = i*100;
  56.     unsigned long num2 = 0xFFFFFFFF;
  57.     char * name = "wangxiancai";
  58.     
  59.     int testnum = 12;
  60.     int x = testnum / 8;
  61.     int y = testnum % 8;
  62.     uart_printf("************x=[%d]***********\n", x);
  63.     uart_printf("************y=[%d]***********\n", y);
  64.     
  65.     uart_printf("************i=[%d]***********\n", i);
  66.     uart_printf("************j=[%d]***********\n", j);
  67.     uart_printf("************ch1=[%c]=[0x%x]***********\n", ch1, ch1);
  68.     uart_printf("************ch2=[%c]=[0x%x]***********\n", ch2, ch2);
  69.     uart_printf("************num=[0x%x]***********\n", num);
  70.     uart_printf("************num2=[0x%x]***********\n", num2);
  71.     uart_printf("************name=[%s]***********\n", name);
  72.     
  73.     while(1)
  74.     {
  75.             uart_sendString("\n***********************************\n");
  76.             uart_sendString("LED ON 3 second!\n");
  77.         GPBDAT = (GPB5_ON & GPB6_ON & GPB7_ON & GPB8_ON);
  78.         wait(30000);
  79.         uart_sendString("LED OFF 2 second!\n");
  80.         uart_sendString("***********************************\n");
  81.         GPBDAT = (GPB5_OFF | GPB6_OFF | GPB7_OFF | GPB8_OFF);
  82.         wait(20000);
  83.         
  84.     }

  85.     return 0;
  86. }
makefile文件

点击(此处)折叠或打开

  1. objs := head.o init.o uart.o leds.o

  2. uart.bin: $(objs)
  3.     arm-linux-ld -Tuart.lds -o uart_elf $^ $(shell arm-linux-gcc -msoft-float -print-libgcc-file-name)
  4. ##    arm-linux-ld -Tuart.lds -o uart_elf head.o init.o uart.o leds.o /home/wangxc/linux/toolchain/gcc-3.4.5-glibc-2.3.6/bin/../lib/gcc/arm-linux/3.4.5/libgcc.a 同上一句
  5.     arm-linux-objcopy -O binary -S uart_elf $@
  6.     arm-linux-objdump -D -m arm uart_elf > uart.dis
  7.     
  8. %.o:%.c
  9.     arm-linux-gcc -O2 -c -o $@ $<

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

  12. clean:
  13.     rm -f uart.bin uart_elf uart.dis *.o
uart.c文件

点击(此处)折叠或打开

  1. #include "uart.h"

  2. /***********************************************************************************/
  3. //串口相关函数
  4. /*功能:初始化串口UART0
  5. *轮询方式来使用串口
  6. */
  7. void init_uart(void)
  8. {
  9.      /*GPHCON寄存器
  10.     [7:6]=10,GPH2作为TXD0,串口发送数据引脚
  11.     [5:4]=10,GPH3作为RXD0,串口接受数据引脚
  12.     GPH2,GPH3控制串口通道0
  13.     GPH4,GPH5控制串口通道1
  14.     GPH6,GPH7控制串口通道2
  15.     */
  16.         rGPHCON = ((2<<6)|(2<<4)|(0<<2)|(0<<0));
  17.         rGPHUP = ((1<<3)|(1<<2)); /*禁止上拉*/
  18.         
  19.         /*ULCON0串口线路控制寄存器:设置传输格式
  20.         [6]=0,普通模式,非红外工作模式
  21.         [5:3]=000,无奇偶校验位,100=奇校验,101=偶校验,110=固定校验位为1,111=固定校验位为0
  22.         [2]=0,每帧1个停止位,1:每帧2个停止位
  23.         [1:0]=11,8位,每帧发送或接受的数据位的个数。00=5位,01=6位,10=7位
  24.         */
  25.         rULCON0 = 0x3;
  26.         
  27.         /*UCON0:串口控制寄存器:用于选择UART时钟源,设置UART中断方式
  28.         [15:12]:[11:10]选择PCLK时,这4位无效。选择FCLK/n时,表示n值。
  29.         [11:10]=00: 选择PCLK给UART比特率,10:PCLK, 01:UEXTCLK, 11:FCLK/n。
  30.         [9]=1: 中断请求类型
  31.         [8]=0: 中断请求类型
  32.         [7]=0: 禁止超时中断,1:使能超时中断
  33.         [6]=1: 产生接受错误状态中断,1:不产生接受错误状态中断
  34.         [5]=0: 正常操作,非回环模式。发送引脚发送的数据,直接到达接受引脚,一般是测试用。
  35.         [4]=0: 正常操作,不发送断电信号
  36.         [3:2]=01: 发送模式,中断或者轮询,如果中断寄存器不设置,就是轮询。
  37.         [1:0]=01: 接受模式,中断或者轮询
  38.         */
  39.         rUCON0 = 0x5;
  40.         
  41.         /*UFCON:串口FIFO控制寄存器:用于设置是否使用FIFO,设置各FIFO的触发阀值。
  42.         [7:6]=发送FIFO的触发深度,即在发送时,发送FIFO中还剩有多少个数据时,才触发中断,告诉CPU可以继续发送了。
  43.         [5:4]=接受FIFO的触发深度,即在接受时,接受FIFO中接受了多少个数据后,才触发中断,告诉CPU已经有接受到的数据了。
  44.         [3]=
  45.         [2]=TX的FIFO是否复位
  46.         [1]=RX的FIFO是否复位
  47.         [0]=0,不使用FIFO,非FIFO模式,相当于接受和发送时,不使用缓冲寄存器,上面的设置无效。如果这里是1,则上面的位肯定有对应的设置。
  48.         */
  49.         rUFCON0 = 0x0;
  50.         
  51.         /*UMCON:串口MODEM控制寄存器:用于流量控制
  52.         [7:5]=000,规定必须为0
  53.         [4]=0:禁止自动流控制(AFC),即不使用流控。一般不使用这种硬件自动流控制手段。
  54.         [3:1]=000:规定必须为0
  55.         [0]=0:高电平(撤销nRTS),1:低电平(激活nRTS),因为,AFC位禁止,nRTS必须由软件控制。如果AFC使能,则忽略这个位。
  56.         */
  57.         rUMCON0 = 0x0;
  58.         
  59.         /*UBRDIV:波特率分频寄存器:用于设置波特率
  60.         [15:0],波特率分频值。使用UEXTCLK作为输入时钟时,可以设置UBRDIV为0.
  61.         UBRDIV = (int)(UART时钟/(波特率*16))-1
  62.         */
  63.         rUBRDIV0 = UART_BRD;
  64. }

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

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

  80. UTXH0:串口发送缓冲寄存器
  81. [7:0]:串口要发送的数据
  82. */
  83. void uart_sendByte(int data)
  84. {
  85.     if(data == '\n')
  86.     {
  87.         while(!(rUTRSTAT0 &0x2));
  88.         WrUTXH0('\r'); /*回车不换行*/
  89.     }
  90.     /*等待,直到发送缓冲区中的数据已经全部发送出去
  91.     这里也可以检测UTRSTAT0[2]*/
  92.     while(!(rUTRSTAT0 &0x2));
  93.     /*向UTXH0寄存器中写入数据,UART即自动将它发送出去
  94.     #define rUTXH0 (*(volatile unsigned char *)0x50000020)    //UART 0 Transmission Hold
  95.     #define WrUTXH0(ch) (*(volatile unsigned char *)0x50000020)=(unsigned char)(ch)
  96.     所以:WrUTXH0(data); 相当于 rUTXH0 = data;
  97.     */
  98.     WrUTXH0(data);
  99. }

  100. /*功能:向串口打印一个字符串
  101. *参数:待打印的字符串
  102. */
  103. void uart_sendString(char *p)
  104. {
  105.     while(*p)
  106.         uart_sendByte(*p++);
  107. }

  108. /*功能:向串口打印一个字符的16进制格式
  109. *参数:待打印的字符
  110. * 数字0=0x30,数字9=0x39
  111. */
  112. void uart_sendByte_hex(unsigned long val)
  113. {
  114.     // val = 0x1234ABCD
  115.     unsigned long c;
  116.     int i = 0;
  117.     
  118.     uart_sendByte('0');
  119.     uart_sendByte('x');

  120.     for (i = 0; i < 8; i++)
  121.     {
  122.         c = (val >> ((7-i)*4)) & 0xf;
  123.         if((c >= 0) && (c <= 9))
  124.         {
  125.             c = '0' + c;
  126.         }
  127.         else if ((c >= 0xA) && (c <= 0xF))
  128.         {
  129.             c = 'A' + (c - 0xA);
  130.         }
  131.         uart_sendByte((int)c);
  132.     }
  133. }

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

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

  141. URXH0:串口接受缓冲寄存器
  142. [7:0]:串口接受到的数据
  143. */
  144. char uart_getch(void)
  145. {
  146.     /*等待,直到接受缓冲区中有数据*/
  147.     while(!(rUTRSTAT0 & 0x1));
  148.     /*直接读取URXH0寄存器,即可以获得接受到的数据
  149.     #define rURXH0 (*(volatile unsigned char *)0x50000024)    //UART 0 Receive buffer
  150.     #define RdURXH0() (*(volatile unsigned char *)0x50000024)
  151.     所以:return RdURXH0(); 相当于:return rURXH0;
  152.     */
  153.     return RdURXH0();
  154. }

  155. /*功能:从串口接受一个字符串
  156. *参数:输入的字符串
  157. */
  158. void uart_getString(char *string)
  159. {
  160.     char *string2 = string;
  161.     char c;
  162.     while((c=uart_getch()) != '\r')
  163.     {
  164.         if(c == '\b')
  165.         {
  166.             if((int)string2 < (int)string)
  167.             {
  168.                 //uart_printf("\b\b");
  169.                 string--;
  170.             }
  171.         }
  172.         else
  173.         {
  174.             *string++ = c;
  175.             uart_sendByte(c);
  176.         }
  177.     }
  178.     *string = '\0';
  179.     uart_sendByte('\n');
  180. }

  181. /***********************************************************************************/
  182. /*
  183. *功能:整型(int) 转化成 字符型(char)
  184. *注意:不用 % / 符号的话,只能正确打印:0...9的数字对应的字符'0'...'9'
  185. */
  186. void itoa(unsigned int n, char * buf)
  187. {
  188.     int i;

  189.     if(n < 10){
  190.         buf[0] = n + '0';
  191.         buf[1] = '\0';
  192.         return;
  193.     }
  194.     itoa(n / 10, buf);
  195.     
  196.     for(i=0; buf[i]!='\0'; i++);
  197.     
  198.     buf[i] = (n % 10) + '0';
  199.     
  200.     buf[i+1] = '\0';
  201. }

  202. /*
  203. *功能:16进制字(0x) 转化成 字符型(char)
  204. *注意:不用 % / 符号的话,只能正确打印,0...9..15的数字,对应的'0'...'9''A'...'F'
  205. *注意:由于编译问题,这个函数,暂时由uart_sendByte_hex()函数替代
  206. */
  207. void xtoa(unsigned int n, char * buf)
  208. {
  209.     int i;

  210.     if(n < 16)
  211.     {
  212.         if(n < 10)
  213.         {
  214.             buf[0] = n + '0';
  215.         }
  216.         else
  217.         {
  218.             buf[0] = n - 10 + 'a';
  219.         }
  220.         buf[1] = '\0';
  221.         return;
  222.     }
  223.     xtoa(n / 16, buf);
  224.     
  225.     for(i = 0; buf[i] != '\0'; i++);
  226.     
  227.     if((n % 16) < 10)
  228.     {
  229.         buf[i] = (n % 16) + '0';
  230.     }
  231.     else
  232.     {
  233.         buf[i] = (n % 16) - 10 + 'a';
  234.     }
  235.     buf[i + 1] = '\0';
  236. }

  237. /*******************************************************************************************
  238. 为了支持求余求模,需要:
  239. 1,修改makefile如下:增加libgcc的库
  240.     arm-linux-ld -Tuart.lds -o uart_elf $^ $(shell arm-linux-gcc -msoft-float -print-libgcc-file-name)
  241. 上面一句展开后,其实就是下面的一句:
  242. ##    arm-linux-ld -Tuart.lds -o uart_elf head.o init.o uart.o leds.o /home/wangxc/linux/toolchain/gcc-3.4.5-glibc-2.3.6/bin/../lib/gcc/arm-linux/3.4.5/libgcc.a
  243. 2,自己手写libgcc的库。
  244. 这个在uart3实现
  245. *******************************************************************************************/

  246. /*功能:向串口格式化打印一个字符串
  247. *参数:格式化的字符串
  248. *注意:由于求模求余的问题没有解决,所以这里%d输出时,只能输出0~9,10和10以上的不能输出
  249. */
  250. int uart_printf(const char *fmt, ...)
  251. {
  252.     int count = 0;
  253.     char c;
  254.     char *s;
  255.     int n;
  256.     char buf[65];
  257.     va_list ap;
  258.     
  259.     va_start(ap, fmt);
  260.     
  261.     while(*fmt != '\0')
  262.     {
  263.         if(*fmt == '%')
  264.         {
  265.             fmt++;
  266.             switch(*fmt)
  267.          {
  268.                 case 'd': /*整型*/
  269.                     n = va_arg(ap, int);
  270.                     if(n < 0)
  271.                     {
  272.                         //uputchar('-');
  273.                         uart_sendByte('-');
  274.                         n = -n;
  275.                     }    
  276.                     itoa(n, buf);
  277.                     //_uputs(buf);
  278.                     uart_sendString(buf);
  279.                     break;        
  280.                 case 'c': /*字符型*/
  281.                     c = va_arg(ap, int);
  282.                     uart_sendByte(c);
  283.                     break;
  284.                 case 'x': /*16进制*/
  285.                     n = va_arg(ap, int);
  286.                     //uart_sendByte_hex(n); /*由于求模求余编译有问题,所以用uart_sendByte_hex来替代下面的2行代码*/
  287.                     xtoa(n, buf);
  288.                     uart_sendString(buf);
  289.                     break;
  290.                 case 's': /*字符串*/
  291.                     s = va_arg(ap, char *);
  292.                     uart_sendString(s);
  293.                     break;
  294.                 case '%': /*输出%*/
  295.                     uart_sendByte('%');
  296.                     break;
  297.                 default:
  298.                     break;
  299.             }    
  300.         }
  301.         else
  302.         {
  303.             uart_sendByte(*fmt);
  304.             if(*fmt == '\n')
  305.             {
  306.                 //uart_sendByte('\r');
  307.             }
  308.         }
  309.         fmt++;
  310.     }

  311.     va_end(ap);

  312.     return count;
  313. }

  314. /*
  315. uart_printf("%s%s:[%s][%s][%s]\n", __DTAE__, __TIME__, __FILE__, __FUNCTION__, __LINE__);

  316. int WriteLog(const char *fmt, ...)
  317. {
  318.         return uart_printf(fmt);
  319. }

  320. */
uart.h文件

点击(此处)折叠或打开

  1. #ifndef _UART_H_
  2. #define _UART_H_

  3. /**************************************************************************/
  4. //串口相关寄存器
  5. #define rULCON0 (*(volatile unsigned *)0x50000000)
  6. #define rUCON0 (*(volatile unsigned *)0x50000004)
  7. #define rUFCON0 (*(volatile unsigned *)0x50000008)
  8. #define rUMCON0 (*(volatile unsigned *)0x5000000c)
  9. #define rUTRSTAT0 (*(volatile unsigned *)0x50000010)
  10. #define rUBRDIV0 (*(volatile unsigned *)0x50000028)

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

  13. #define rGPHCON (*(volatile unsigned *)0x56000070)
  14. #define rGPHUP (*(volatile unsigned *)0x56000078)

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

  19. typedef char * va_list;
  20. #define va_start(ap,p) (ap = (char *) (&(p)+1))
  21. #define va_arg(ap, type) ((type *) (ap += sizeof(type)))[-1]
  22. #define va_end(ap)

  23. void init_uart(void);
  24. void uart_sendByte(int data);
  25. void uart_sendString(char *p);
  26. void uart_sendByte_hex(unsigned long val);
  27. char uart_getch(void);
  28. void uart_getString(char *string);

  29. void itoa(unsigned int n, char * buf);
  30. void xtoa(unsigned int n, char * buf);
  31. int uart_printf(const char *fmt, ...);
  32. /**************************************************************************/

  33. #endif
uart.lds文件

点击(此处)折叠或打开

  1. SECTIONS {
  2.     . = 0x0;
  3.     .text : { *(.text) }
  4.     .rodata ALIGN(4) : {*(.rodata)}
  5.     .data ALIGN(4) : { *(.data) }
  6.     .bss ALIGN(4) : { *(.bss) *(COMMON) }
  7. }








阅读(788) | 评论(0) | 转发(0) |
0

上一篇:ADC裸机驱动代码

下一篇:MMU裸机驱动代码

给主人留下些什么吧!~~