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

全部博文(573)

文章存档

2018年(3)

2016年(48)

2015年(522)

分类: LINUX

2015-12-02 12:04:23

2440init.h文件

点击(此处)折叠或打开

  1. #ifndef _2440INIT_H_
  2. #define _2440INIT_H_

  3. /**************************************************************************/
  4. //按键相关的GPIO
  5. #define GPFCON (*(volatile unsigned long *)0x56000050)
  6. #define GPFDAT (*(volatile unsigned long *)0x56000054)
  7. #define GPFUP (*(volatile unsigned long *)0x56000058)
  8. /*注意:这个程序没有mmu,所以寄存器的地址是物理地址*/

  9. /**************************************************************************/
  10. //LED相关的GPIO
  11. #define GPBDAT (*(volatile unsigned long *)0x56000014)
  12. #define GPBCON (*(volatile unsigned long *)0x56000010)
  13. #define GPBUP (*(volatile unsigned long *)0x56000018)
  14. /*注意:这个程序没有mmu,所以寄存器的地址是物理地址*/

  15. #define GPB5_OUT (1<<(5*2))
  16. #define GPB6_OUT (1<<(6*2))
  17. #define GPB7_OUT (1<<(7*2))
  18. #define GPB8_OUT (1<<(8*2))

  19. #define GPB5_ON (~(1<<5))
  20. #define GPB6_ON (~(1<<6))
  21. #define GPB7_ON (~(1<<7))
  22. #define GPB8_ON (~(1<<8))

  23. #define GPB5_OFF (1<<5)
  24. #define GPB6_OFF (1<<6)
  25. #define GPB7_OFF (1<<7)
  26. #define GPB8_OFF (1<<8)
  27. /**************************************************************************/

  28. /* WATCHDOG寄存器 */
  29. #define WTCON (*(volatile unsigned long *)0x53000000)
  30. /* SDRAM寄存器 */
  31. #define     MEM_CTL_BASE        0x48000000


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

  36. void disable_watch_dog();
  37. void clock_init(void);
  38. void memsetup();
  39. void copy_steppingstone_to_sdram(void);
  40. void clean_bss(void);

  41. #endif
def.h文件

点击(此处)折叠或打开

  1. #ifndef __DEF_H__
  2. #define __DEF_H__

  3. #define U32 unsigned int
  4. #define U16 unsigned short
  5. #define S32 int
  6. #define S16 short int
  7. #define U8 unsigned char
  8. #define    S8 char

  9. #endif
head.S文件

点击(此处)折叠或打开

  1. @******************************************************************************
  2. @ File: head.S head.o init.o nand.o interrupt.o uart.o touchscreen.o main.o
  3. @ 功能: 设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行
  4. @******************************************************************************
  5. .text
  6. .global _start
  7. _start:
  8. @******************************************************************************
  9. @ 中断向量,本程序中,除Reset和HandleIRQ外,其它异常都没有使用
  10. @******************************************************************************
  11.     b Reset

  12. @ 0x04: 未定义指令中止模式的向量地址
  13. HandleUndef:
  14.     b HandleUndef
  15.  
  16. @ 0x08: 管理模式的向量地址,通过SWI指令进入此模式
  17. HandleSWI:
  18.     b HandleSWI

  19. @ 0x0c: 指令预取终止导致的异常的向量地址
  20. HandlePrefetchAbort:
  21.     b HandlePrefetchAbort

  22. @ 0x10: 数据访问终止导致的异常的向量地址
  23. HandleDataAbort:
  24.     b HandleDataAbort

  25. @ 0x14: 保留
  26. HandleNotUsed:
  27.     b HandleNotUsed

  28. @ 0x18: 中断模式的向量地址
  29.     b HandleIRQ

  30. @ 0x1c: 快中断模式的向量地址
  31. HandleFIQ:
  32.     b HandleFIQ

  33. Reset:
  34.     ldr sp, =4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈
  35.     bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启
  36.     bl clock_init @ 设置MPLL,改变FCLK、HCLK、PCLK
  37.     bl memsetup @ 设置存储控制器以使用SDRAM
  38.     bl nand_init @ 初始化NAND Flash
  39.     
  40.                             @ 复制nand中4k后的代码到SDRAM中
  41.     ldr r0, =0x30000000 @ 1. 目标地址 = 0x30000000,这是SDRAM的起始地址
  42.     mov r1, #4096 @ 2. 源地址 = 4096,运行地址在SDRAM中的代码保存在NAND Flash 4096地址开始处
  43.     mov r2, #60*1024 @ 3. 复制长度 = 60K,对于本实验,这是足够了
  44.     bl CopyCode2SDRAM @ 调用C函数CopyCode2SDRAM
  45.     
  46.     bl clean_bss @ 清除bss段,未初始化或初值为0的全局/静态变量保存在bss段

  47.     msr cpsr_c, #0xd2 @ 进入中断模式
  48.     ldr sp, =0x31000000 @ 设置中断模式栈指针

  49.     msr cpsr_c, #0xdf @ 进入系统模式
  50.     ldr sp, =0x34000000 @ 设置系统模式栈指针,
  51. /*
  52.     ldr lr, =ret_inituart @ 设置返回地址
  53.     ldr pc, =init_uart            @ 这里为什么不能用 bl init_uart ???,也可以在main函数里面初始化
  54. ret_inituart:
  55.         
  56.         
  57.     ldr lr, =ret_initirq @ 设置返回地址
  58.     ldr pc, =init_irq @ 调用中断初始化函数
  59. ret_initirq:
  60. */
  61.     msr cpsr_c, #0x5f @ 设置I-bit=0,开IRQ中断

  62.     ldr lr, =halt_loop @ 设置返回地址
  63.     ldr pc, =main @ 调用main函数
  64. halt_loop:
  65.     b halt_loop

  66. HandleIRQ:
  67.     sub lr, lr, #4 @ 计算返回地址
  68.     stmdb { r0-r12,lr } @ 保存使用到的寄存器
  69.                                     @ 注意,此时的sp是中断模式的sp
  70.                                     @ 初始值是上面设置的4096
  71.     
  72.     ldr lr, =int_return @ 设置调用IRQ_Handle函数后的返回地址
  73.     ldr pc, =EINT_Handle @ 调用中断分发函数,在interrupt.c中
  74. int_return:
  75.     ldmia { r0-r12,pc }^ @ 中断返回, ^表示将spsr的值复制到cpsr
init.c文件

点击(此处)折叠或打开

  1. #include "2440init.h"

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

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

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

  33. void memsetup(void)
  34. {
  35.     volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;

  36.     // 可生成”位置无关的代码”,使得这个函数可以在被复制到
  37.     // SDRAM之前就可以在steppingstone中运行
  38.     // 存储控制器13个寄存器的值
  39.     p[0] = 0x22011110; //BWSCON
  40.     p[1] = 0x00000700; //BANKCON0
  41.     p[2] = 0x00000700; //BANKCON1
  42.     p[3] = 0x00000700; //BANKCON2
  43.     p[4] = 0x00000700; //BANKCON3
  44.     p[5] = 0x00000700; //BANKCON4
  45.     p[6] = 0x00000700; //BANKCON5
  46.     p[7] = 0x00018005; //BANKCON6
  47.     p[8] = 0x00018005; //BANKCON7
  48.     
  49.                                             // REFRESH,
  50.                                             // HCLK=12MHz: 0x008C07A3,
  51.                                             // HCLK=100MHz: 0x008C04F4
  52.     p[9] = 0x008C04F4;
  53.     p[10] = 0x000000B1; //BANKSIZE
  54.     p[11] = 0x00000030; //MRSRB6
  55.     p[12] = 0x00000030; //MRSRB7
  56. }

  57. void clean_bss(void)
  58. {
  59.     extern int __bss_start, __bss_end;
  60.     int *p = &__bss_start;
  61.     
  62.     for (; p < &__bss_end; p++)
  63.         *p = 0;
  64. }
interrupt.c文件

点击(此处)折叠或打开

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

  4. /*定义一个函数指针数组 : 数组的每一个元素是一个函数指针,用来保存用户定义的中断处理函数*/
  5. static void (*irq_interrupt_array[32])(void);

  6. void init_irq_interrupt(void) /*没有安装中断函数的时候,使用这个函数来初始化中断服务函数*/
  7. {
  8.     while(1);
  9. }

  10. /*函数功能:初始化函数指针数组
  11. */
  12. void all_init_irq(void)
  13. {
  14.     int i = 0;
  15.     for (i = 0; i < (sizeof(irq_interrupt_array) / sizeof(irq_interrupt_array[0])); i++)
  16.     {
  17.         irq_interrupt_array[i] = init_irq_interrupt;
  18.     }
  19. }

  20. /*
  21. *函数功能:安装中断处理函数
  22. *参数:
  23. * num : 32个一级中断的编号,即中断号
  24. * void (*irq_interrupt)(void) : 是个函数指针,是用户编写的中断处理函数。
  25. *注意:
  26. * 这个函数完整版是:用2个参数:1个表示1级中断,1个表示2级中断(没有2级中断时,用0)
  27. */
  28. int request_irq(int num, void (*irq_interrupt)(void))
  29. {
  30.         irq_interrupt_array[num] = irq_interrupt;

  31.         return 0;
  32. }

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

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

  84.             uart_printf("\n\nINTOFFSET(interrupt no.)=[%d]\n", offset);

  85.             irq_interrupt_array[offset](); //调用对应的irq中断服务函数

  86.             /*中断处理完成之后:必须清除所有的挂起寄存器
  87.             *注意:向挂起寄存器中写1,即可令此位为0;写入0是没有效果的,若写入0,挂起寄存器中的数据保持不变。
  88.             */
  89.             if(offset == 4) /*二级外部中断,还必须清除 EINTPEND*/
  90.             {
  91.                      EINTPEND = (1<<4);
  92.             }
  93.             SRCPND = (1<<offset);
  94.             INTPND = (1<<offset);

  95.             uart_printf("SRCPND=[0x%x]\n", SRCPND);
  96.             uart_printf("INTPND=[0x%x]\n", INTPND);
  97.             uart_sendString("*******************************************");
  98.             /*在清除 SRCPND INTPND时,INTOFFSET会被自动清除*/
  99. }
interrupt.h文件

点击(此处)折叠或打开

  1. #ifndef _INTERRUPT_H_
  2. #define _INTERRUPT_H_

  3. /**************************************************************************/
  4. #define GPF0_EINT (2<<(0*2))
  5. #define GPF1_EINT (2<<(1*2))
  6. #define GPF2_EINT (2<<(2*2))
  7. #define GPF3_EINT (2<<(3*2))
  8. #define GPF4_EINT (2<<(4*2))
  9. #define GPF5_EINT (2<<(5*2))
  10. #define GPF6_EINT (2<<(6*2))
  11. #define GPF7_EINT (2<<(7*2))
  12. /**************************************************************************/

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

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

  24. #define SUBSRCPND (*(volatile unsigned long *)0x4A000018)
  25. #define INTSUBMSK (*(volatile unsigned long *)0x4A00001C)

  26. #define BIT_ALLMSK        (0xffffffff)
  27. /**************************************************************************/

  28. #endif
interrupt.lds文件

点击(此处)折叠或打开

  1. SECTIONS {
  2.     . = 0x00000000;
  3.     .init : AT(0){ head.o init.o nand.o}
  4.     . = 0x30000000;
  5.     .text : AT(4096) { *(.text) }
  6.     .rodata ALIGN(4) : AT((LOADADDR(.text)+SIZEOF(.text)+3)&~(0x03)) {*(.rodata*)}
  7.     .data ALIGN(4) : AT((LOADADDR(.rodata)+SIZEOF(.rodata)+3)&~(0x03)) { *(.data) }
  8.     __bss_start = .;
  9.     .bss ALIGN(4) : { *(.bss) *(COMMON) }
  10.     __bss_end = .;
  11. }
main.c文件

点击(此处)折叠或打开

  1. #include "2440init.h"
  2. #include "interrupt.h"
  3. #include "uart.h"
  4. #include "def.h"

  5. extern void init_irq(void);
  6. extern int request_irq(int num, void (*irq_interrupt)(void));

  7. /*
  8.  * 功能:初始化LED的GPIO引脚
  9.  */
  10. void init_led(void)
  11. {
  12.      GPBCON = (GPB5_OUT | GPB6_OUT | GPB7_OUT | GPB8_OUT);
  13.     GPBUP = 0x1e0;
  14.     GPBDAT = (GPB5_OFF | GPB6_OFF | GPB7_OFF | GPB8_OFF);
  15. }

  16. void led_1_interrupt(void)
  17. {
  18.         uart_sendString("K1 ON!->LED1 ON!\n");
  19.         GPBDAT = (GPB5_OFF | GPB6_OFF | GPB7_OFF | GPB8_OFF);
  20.         GPBDAT = GPB5_ON; /*LED1亮*/
  21.         return;
  22. }

  23. void led_2_interrupt(void)
  24. {
  25.         uart_sendString("K2 ON!->LED2 ON!\n");
  26.         GPBDAT = (GPB5_OFF | GPB6_OFF | GPB7_OFF | GPB8_OFF);
  27.         GPBDAT = GPB6_ON; /*LED2亮*/
  28.         return;
  29. }

  30. void led_3_interrupt(void)
  31. {
  32.         uart_sendString("K3 ON!->LED3 ON!\n");
  33.         GPBDAT = (GPB5_OFF | GPB6_OFF | GPB7_OFF | GPB8_OFF);
  34.         GPBDAT = GPB7_ON; /*LED3亮*/
  35.         return;
  36. }

  37. void led_4_interrupt(void)
  38. {
  39.         uart_sendString("K4 ON!->LED4 ON!\n");
  40.         GPBDAT = (GPB5_OFF | GPB6_OFF | GPB7_OFF | GPB8_OFF);
  41.         GPBDAT = GPB8_ON; /*LED4亮*/
  42.         return;
  43. }

  44. int main()
  45. {
  46.         init_irq();
  47.      init_uart();
  48.         init_led();
  49.         
  50.         uart_printf("\n\ninterrupt test!\n");
  51.         
  52.         request_irq(1, led_1_interrupt); /*安装中断处理函数*/
  53.         request_irq(4, led_2_interrupt);
  54.         request_irq(2, led_3_interrupt);
  55.         request_irq(0, led_4_interrupt);
  56.     
  57.     while(1)
  58.     {
  59.     }
  60.         return 0;
  61. }
makefile文件

点击(此处)折叠或打开

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

  2. interrupt.bin: $(objs)
  3.     arm-linux-ld -Tinterrupt.lds -o interrupt_elf $^ $(shell arm-linux-gcc -msoft-float -print-libgcc-file-name)
  4.     arm-linux-objcopy -O binary -S interrupt_elf $@
  5.     arm-linux-objdump -D -m arm interrupt_elf > interrupt.dis

  6. %.o:%.c
  7.     arm-linux-gcc -Wall -O2 -c -o $@ $<

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

  10. clean:
  11.     rm -f interrupt.bin interrupt_elf interrupt.dis *.o
nand.c文件

点击(此处)折叠或打开

  1. #include "nand.h"
  2. #include "def.h"

  3. /*
  4. *功能:重启
  5. */
  6. void nand_reset()
  7. {
  8.     /*每操作NandFlash之前必须先片选*/
  9.     NF_CE_L();
  10.     /*发送命令之前要先清除RB*/
  11.     NF_CLEAR_RB();
  12.     /*向NandFlash写命令:即发送复位命令*/
  13.     NF_CMD(CMD_RESET);
  14.     /*注意:命令执行期间,NandFlash存储器忙,所以一直要等待为1:不忙*/
  15.     NF_WAIT_RB();
  16.     /*关闭片选*/
  17.     NF_CE_H();
  18. }

  19. /*
  20. *功能:NANDFLASH初始化
  21. *注意:1,本程序使用的是ARM9 2440处理器,需要设置 NFCONF,NFCONT这2个寄存器
  22. * 2,NandFlash的芯片是K9F2G08U0A。由芯片手册可知:
  23. * 容量:(256M+8M)字节,后面的8M叫OOB空间,坏块管理会用到它。
  24. * 8bit
  25. * 2K个块,每个块有64个page页
  26. * 一个page页 =(2K+64)字节
  27. * 所以,一个块 = 64页 = 64*(2K+64)字节 =(128K+2K)字节
  28. * 一个Nand器件 = 2K个块 = 2K*64个page页 = 128K页
  29. * 一个Nand器件 = 128K页 = 128K*(2K+64)字节 = (256M+8M)字节
  30. * 3,片内内存+SDRAM+网卡+寄存器:是由CPU统一编址的,由CPU发出地址。
  31. * 但是NandFlash不是由CPU统一编址的,所以NandFlash的0地址和片内内存的0地址,不是一回事。
  32. * 4,NandFlash中的OOB不参与编址,读取NandFlash上的2049这个地址,不是读取的0页上的地址,是1页上的。
  33. * 5,NandFlash控制器的各个控制引脚的时序,不需要程序员来驱动这些引脚,
  34. * 程序员只需要设置相关寄存器之后,控制器会自动发出控制信号。
  35. */
  36. void nand_init()
  37. {
  38.     //char ret;
  39.     //char ch;
  40.     /*NANDFLASH配置寄存器 : NFCONF
  41.     [13:12]=01:时序图中CLE,ALE持续值设置,1个HCLK时钟周期,如HCLK是100Mhz,则,1个HCLK时钟周期=10ns。
  42.     [10:8]=011:时序图中TWRPH0持续值设置,3个HCLK时钟周期
  43.     [6:4]=100:时序图中TWRPH1持续值设置,0个HCLK时钟周期
  44.     */
  45.     rNFCONF = ((TACLS << 12) | (TWRPH0 << 8) | (TWRPH1 << 4));
  46.     /*NANDFLASH控制寄存器 : NFCONT
  47.     其他位基本都是初始值或者不需要设置
  48.     [1]=1:禁止片选,CE引脚输出为1
  49.     [0]=1:MODE位,使能NandFlash控制器,命令使能CLE引脚设置为1
  50.     */
  51.     rNFCONT = (1<<4)|(1<<1)|(1<<0);
  52.     nand_reset();
  53.     
  54.     return ;
  55. }


  56. /*功能:读取芯片的ID号
  57. *注意:查看NandFlash的相关配置是否正确,可以去检查芯片的ID号。如果ID读取正确了,则说明配置正确了。
  58. *第1个周期:厂商编号 : 0xEC
  59. *第2个周期:设备编号:相同型号的芯片,有相同的ID号 : 0xDA,这个必须正确
  60. *第3个周期:内部芯片编号 : 0x10
  61. *第4个周期:页的大小 : 0x95
  62. *第5个周期:一个page另外带的融错空间的大小 : 0x44
  63. */
  64. char nand_readId()
  65. {
  66.     int i;
  67.     U8 cyc1;
  68.     U8 cyc2;
  69.     U8 cyc3;
  70.     U8 cyc4;
  71.     U8 cyc5;
  72.     //片选
  73.     NF_CE_L();
  74.     //清除RB
  75.     NF_CLEAR_RB();
  76.     //发送读ID命令
  77.     NF_CMD(CMD_READID);
  78.     //发送地址值:需要读取这个地址上的值,读ID号,规定就是这个地址,看的时序图,只需发送一个地址.
  79.     NF_ADDR(0x0);
  80.     for(i=0; i<1000; i++);
  81.     //从nandflash中读取数据:读5次,看时序图
  82.     //注意:每次只能读取8位数据,保存在数据寄存器中。
  83.     cyc1 = NF_RDDATA8();
  84.     for(i=0; i<100; i++);
  85.     cyc2 = NF_RDDATA8();
  86.     for(i=0; i<100; i++);
  87.     cyc3 = NF_RDDATA8();
  88.     for(i=0; i<100; i++);
  89.     cyc4 = NF_RDDATA8();
  90.     for(i=0; i<100; i++);
  91.     cyc5 = NF_RDDATA8();
  92.     for(i=0; i<100; i++);
  93.     
  94.     //等待命令执行完毕
  95.     NF_WAIT_RB();
  96.     //关闭片选
  97.     NF_CE_H();
  98.     
  99.     return cyc2;
  100. }


  101. /*功能 : 发出地址
  102. *注意: 这个地址,不是页编号,是具体的读取NandFlash的起始地址,包括页内地址
  103. */
  104. void write_addr(unsigned int addr)
  105. {
  106.         //写地址(要读取数据的起始地址) :
  107.         //包括 :(页内)地址,是低位地址,共A0~A11,在具体的page页内寻址。一个page页=(2K+64)字节
  108.         // 行()地址,是高位地址,共A12~A28,可以寻址到page页。一个Nand器件=2K*64个page页 = 128K页
  109.         // 高位地址中,A12~A17,可以寻址到block块下面的page页。一个block块=64个page页
  110.         // 高位地址中,A18~A28,可以寻址到block块。一个Nand器件=2K个block块
  111.         //要写全部的5个周期的地址
  112.     
  113.         //32位的page_number : 低29位有效 :
  114.         //| 28| 27| 26| 25| 24| 23| 22| 21| 20| 19| 18| 17| 16| 15| 14| 13| 12| 11| 10| 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
  115.      // 对应最后3个地址周期的页内地址的高11位 :
  116.         //|A28|A27|A26|A25|A24|A23|A22|A21|A20|A19|A18|A17|A16|A15|A14|A13|A12|A11|A10|A09|A08|A07|A06|A05|A04|A03|A02|A01|A00|
  117.         //29位在5个地址周期中应是如下的分布 :
  118.         //| I7 | I6 | I5 | I4 | I3 | I2 | I1 | I0 |
  119.         //| L | L | L | L | L | L | L | A28 |
  120.         //| A27 | A26 | A25 | A24 | A23 | A22 | A21 | A20 |
  121.         //| A19 | A18 | A17 | A16 | A15 | A14 | A13 | A12 |
  122.         //| L | L | L | L | A11 | A10 | A9 | A8 |
  123.         //| A7 | A6 | A5 | A4 | A3 | A2 | A1 | A0 |
  124.     
  125.     int i;
  126.     int col, page;

  127.         col = addr & (2048 -1); //截取低位:取2048的原因:本程序使用的nand芯片的一个page页是2048字节
  128.         page = addr / 2048; //截取高位
  129.     
  130.     NF_ADDR(col & 0xFF); //列(页内)地址 A0~A7
  131.     for(i=0; i<100; i++);
  132.         NF_ADDR((col >> 8) & 0x0F);     //列(页内)地址 A8~A11
  133.         for(i=0; i<100; i++);
  134.         
  135.         NF_ADDR(page & 0xFF); //行()地址 A12~A19
  136.         for(i=0; i<100; i++);
  137.         NF_ADDR((page >> 8) & 0xFF); //行()地址 A20~A27
  138.         for(i=0; i<100; i++);
  139.         NF_ADDR((page >> 16) & 0x03); //行()地址 A28~A29
  140.         for(i=0; i<100; i++);
  141. }

  142. /*
  143. *功能 : 从NandFlash位置start_addr开始读取数据,将数据复制到指定的SDRAM地址buf处,共复制size个字节。
  144. * 数据方向:(Nand的start_addr->SDRAM的buf)
  145. *参数 : buf : SDRAM的缓冲区起始地址:0x30001000
  146. * start_addr : 不是页编号,也就是说,不是每一个page页的开始地址处理,
  147. * 是具体的读取NandFlash的起始地址,包括页内地址:0x1003=4099
  148. * size : 复制的字节数,可以是页空间整数倍,也可以不是,也就是说,size可以小于2K,也可以大于2K。0x810,0x800=2048
  149. *注意 : read是相对于cpu说的,cpu读取nand中的程序代码,拷贝到SDRAM中去执行。
  150. */
  151. void nand_read(unsigned char *buf, unsigned long start_addr, int size)
  152. {
  153.         U32 i = 0, j = 0;
  154.         //片选
  155.         NF_CE_L();
  156.         
  157.         for(i=start_addr; i < (start_addr + size);)
  158.         {
  159.                 //清除RB
  160.                 NF_CLEAR_RB();
  161.                 //读NandFlash时的第1个命令
  162.               //0x00命令发出后,即相当于向NFCMD寄存器中写入了0,nandflash控制器会自动发出各种控制信号,
  163.                 //会自动满足时序图的要求,不再需要人工参与了。
  164.                 //这样,nandflash控制器提供的几个寄存器,就简化了对nandflash的操作。
  165.                 NF_CMD(CMD_READ1);
  166.                 //写地址
  167.                 write_addr(i);
  168.                 //读NandFlash时的第2个命令
  169.                 NF_CMD(CMD_READ2);
  170.                 //等待NandFlash不忙
  171.                 NF_WAIT_RB();
  172.                 
  173.                 //读数据 : 一般1次读1页的数据(1页=2K + 64字节),可能跨了2页才能读取一页的数据。
  174.                 //也可以只读一个page页的一部分数据,只是多了几次下面的循环。
  175.                 for(j=0; j<2048; j++, i++) //小于2048也行
  176.                 {
  177.                     //1次从nandflash的8位IO口上读取8位数据。
  178.                     //注意:每次读此寄存器,即执行一次下面语句,就会启动对nandflash的1次读操作。
  179.                     //前一次读操作未完成,是不会启动下一次读操作的。
  180.                     *buf = NF_RDDATA8();
  181.                     buf++;
  182.                 }
  183.         }
  184.         //关闭片选
  185.         NF_CE_H();
  186.         
  187. }

  188. int CopyCode2SDRAM(unsigned char *buf, unsigned long start_addr, int size)
  189. {
  190.     nand_read(buf, start_addr, size);
  191.     return 0;
  192. }


  193. /*
  194. *功能 : 擦除指定的块
  195. *参数 : block_number : 块号
  196. *注意 : 1,一个NandFlash块有2K个块。
  197. * 2,块被擦除后nand对应的块中的数据全部是1
  198. * 3,命令字分为2个阶段
  199. U8 nand_erase(U32 block_number)
  200. {
  201.         int i;
  202.         U8 stat;
  203.         //片选
  204.         NF_CE_L();
  205.         //清除RB
  206.         NF_CLEAR_RB();
  207.         //写入第1个擦除命令
  208.         NF_CMD(CMD_ERASE1);
  209.         //写块的地址 : 注意 : 只写块的地址就行,块地址都在行()地址的高位上,
  210.         //所以不需要写前面2个周期的列(页内)地址,写后面3个周期的页地址的高11位就行。
  211.         //列地址 : 就是页内地址, 共12位
  212.         //行地址 : 就是页地址, 共17位 : 高11位(A28-A18)是2K的块地址,低6位是64的页地址。
  213.         
  214.         //32位block_number:低11位有效 :
  215.      // | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
  216.      // 对应最后3个地址周期的页内地址的高11位 :
  217.         //| A28 | A27 | A26 | A25 | A24 | A23 | A22 | A21 | A20 | A19 | A18 |
  218.         //高11位在后面3个地址周期中应是如下的分布 :
  219.         //| I7 | I6 | I5 | I4 | I3 | I2 | I1 | I0 |
  220.         //| | | | | | | | A28 |
  221.         //| A27 | A26 | A25 | A24 | A23 | A22 | A21 | A20 |
  222.         //| A19 | A18 | | | | | | |
  223.         //
  224.         NF_ADDR((block_number << 6) & 0xFF);
  225.         NF_ADDR((block_number >> 2) & 0xFF);
  226.         NF_ADDR((block_number >> 10) & 0xFF);
  227.         //写入第2个擦除命令
  228.         NF_CMD(CMD_ERASE2);
  229.         
  230.         for(i=0; i<1000; i++);
  231.         //写入读状态寄存器的命令
  232.         NF_CMD(CMD_STATUS);
  233.         do
  234.         {
  235.          //读取8位状态数据
  236.                 stat = NF_RDDATA8();
  237.         }
  238.         while(!(stat & 0x40)); //等到第6位为1 : 表示读取数据完成。第0位为0,表示擦除成功
  239.         //关闭片选
  240.         NF_CE_H();
  241.         
  242.         //约定用0x66来表示擦除成功,或者写成功
  243.         return 0x66;
  244. }
  245. */


  246. /*功能 : 将buf处开始的数据,写入NandFlash的start_addr地址处,共写入size个字节。
  247. * 数据方向:(SDRAM的buf->Nand的start_addr)
  248. *参数 : buf : SDRAM的缓冲区起始地址
  249. * start_addr : 不是页编号,也就是说,不是每一个page页的开始地址处理,
  250. * 是具体的读取NandFlash的起始地址,包括页内地址:0x1003=4099
  251. * size : 复制的字节数,可以是页空间整数倍,也可以不是,也就是说,size可以小于2K,也可以大于2K。0x810,0x800=2048
  252. *注意 : write是相对于cpu说的,cpu写数据到nand中,SDRAM中的数据拷贝到Nand中。
  253. U8 nand_write(unsigned char *buf, unsigned long start_addr, int size)
  254. {
  255.         int i,j;
  256.         U8 stat;
  257.         //片选
  258.         NF_CE_L();
  259.         
  260.         for(i=start_addr; i < (start_addr + size);)
  261.         {
  262.                 //清除RB
  263.                 NF_CLEAR_RB();
  264.                 //写NandFlash时的第1个命令 : NandFlash写准备
  265.                 NF_CMD(CMD_WRITE1);
  266.                 //写地址
  267.                 write_addr(i);
  268.                 //写数据 : 一般1次写1页的数据 : 1页=2K字节+64字节,可能跨了2页才能写一页的数据。
  269.                 //也可以只写一个page页的一部分数据,只是多了几次下面的循环。
  270.                 for(j=0; j<2048; j++, i++)
  271.                 {
  272.                  //1次写8位的数据给NandFlash的8位IO口
  273.                  //注意:每次写这个寄存器,即执行一次下面的语句,都会启动一次nandflash的写数据操作,
  274.                  //前一次写数据操作不完成,是不会启动下一次写数据操作的
  275.                         NF_WRDATA8(*buf);
  276.                         buf++;
  277.                 }
  278.                 
  279.                 //写NandFlash时的第2个命令 : 启动写操作
  280.                 //此时,Flash内部会自动完成写,校验操作。
  281.                 NF_CMD(CMD_WRITE2);
  282.                 for(j=0; j<100; j++);
  283.                 //写入读状态寄存器的命令 : 用来判断当前写操作是否完成,是否成功
  284.                 NF_CMD(CMD_STATUS);
  285.                 do
  286.                 {
  287.                  //读取8位状态数据
  288.                         stat = NF_RDDATA8();
  289.                 }
  290.                 while(!(stat & 0x40)); //等到第6位为1 : 表示写数据完成。第0位为0,表示写数据成功
  291.         }
  292.         //关闭片选
  293.         NF_CE_H();
  294.         
  295.         return 0x66;
  296. }
  297. */
nand.h文件

点击(此处)折叠或打开

  1. #ifndef _NAND_H_
  2. #define _NAND_H_

  3. /*NANDFLASH配置寄存器 : NFCONF:用来设置时序参数宽度,数据位宽*/
  4. #define rNFCONF (*(volatile unsigned long *)0x4E000000)
  5. /*NANDFLASH控制寄存器 : NFCONT:用来禁止/使能nandflash控制器,使能/禁止片选信号*/
  6. #define rNFCONT (*(volatile unsigned long *)0x4E000004)
  7. /*NANDFLASH命令集寄存器 : NFCMMD:用来向nandflash发出命令信号*/
  8. #define rNFCMMD (*(volatile unsigned long *)0x4E000008)
  9. /*NANDFLASH地址集寄存器 : NFADDR:用来向nandflash发出地址信号*/
  10. #define rNFADDR (*(volatile unsigned long *)0x4E00000C)
  11. /*NANDFLASH数据寄存器 : NFDATA,32位=0x4E000010+0x4E000011+0x4E000012+0x4E000013*/
  12. #define rNFDATA (*(volatile unsigned long *)0x4E000010)
  13. /*截取NANDFLASH数据寄存器的8位 : 仅0x4E000010,实际上每次读写也只用到低8位,不可能用到32位。
  14. 每次读写此寄存器,就将启动一次对nandflash的读数据写数据的操作。*/
  15. #define rNFDATA8 (*(volatile unsigned char *)0x4E000010)
  16. /*NANDFLASH运行状态寄存器 : NFSTAT:只用了最低位,0:busy,1:ready*/
  17. #define rNFSTAT (*(volatile unsigned long *)0x4E000020)

  18. /*相关命令如下 : */
  19. /*读NandFlash页时的命令1*/
  20. #define CMD_READ1 0x00
  21. /*读NandFlash页时的命令2*/
  22. #define CMD_READ2 0x30

  23. /*页编程 : 写NandFlash页时的命令1*/
  24. #define CMD_WRITE1 0x80
  25. /*页编程 : 写NandFlash页时的命令2*/
  26. #define CMD_WRITE2 0x10

  27. /*擦除NandFlash块的命令1*/
  28. #define CMD_ERASE1 0x60
  29. /*擦除NandFlash块的命令2*/
  30. #define CMD_ERASE2 0xD0

  31. /*读状态寄存器的命令*/
  32. #define CMD_STATUS 0x70
  33. /*读取芯片ID的命令*/
  34. #define CMD_READID 0x90
  35. /*重启命令*/
  36. #define CMD_RESET 0xFF

  37. #define NF_CE_L() {(rNFCONT) &= (~(1<<1));}
  38. /*禁止nandfalsh : 控制寄存器NFCONT[1]=1*/
  39. #define NF_CE_H() {(rNFCONT) |= (1<<1);}

  40. /*向存储器发出命令 : 命令寄存器NFCMMD[7:0]*/
  41. #define NF_CMD(data) {(rNFCMMD) = (data);}
  42. /*向存储器发出地址值 : 地址寄存器NFADDR[7:0]*/
  43. #define NF_ADDR(data) {(rNFADDR) = (data);}

  44. /*等待NandFlash准备就绪(即不忙) : 一直等到状态寄存器NFSTAT[0]=1,循环才退出*/
  45. #define NF_WAIT_RB() {while(!((rNFSTAT) & (1<<0)));}
  46. /*清除RB:即检测RB传输*/
  47. #define NF_CLEAR_RB() {(rNFSTAT) |= (1<<2);}
  48. /*等待检测RnB : 一直等到状态寄存器NFSTAT[2]=1,循环才退出*/
  49. #define NF_DETECT_RB {while(!((rNDSTA) & (1<<2)));}

  50. /*从NANDFLASH的IO口中读数据(32位) : 数据寄存器NFDATA*/
  51. #define NF_RDDATA() (rNFDATA)
  52. /*从NANDFLASH的IO口中读数据(8位) : 数据寄存器NFDATA*/
  53. #define NF_RDDATA8() (rNFDATA8)
  54. /*向NANDFLASH的IO口中写数据(32位) : 数据寄存器NFDATA*/
  55. #define NF_WRDATA(data) {(rNFDATA) = (data);}
  56. /*向NANDFLASH的IO口中写数据(8位) : 数据寄存器NFDATA*/
  57. #define NF_WRDATA8(data) {(rNFDATA8) = (data);}

  58. /*时序信号参数的宽度*/
  59. #define TACLS 1
  60. #define TWRPH0 3
  61. #define TWRPH1 0

  62. void nand_reset();
  63. void nand_init();
  64. char nand_readId();
  65. void write_addr(unsigned int addr);
  66. void nand_read(unsigned char *buf, unsigned long start_addr, int size);
  67. int CopyCode2SDRAM(unsigned char *buf, unsigned long start_addr, int size);
  68. //U8 nand_erase(U32 block_number);
  69. //U8 nand_write(unsigned char *buf, unsigned long start_addr, int size);

  70. #endif
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. }
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_argp(ap, type) ((type *) (ap += sizeof(type)))-1
  23. #define va_end(ap)

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

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

  34. #endif









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