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

全部博文(573)

文章存档

2018年(3)

2016年(48)

2015年(522)

分类: C/C++

2015-12-02 18:04:02

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. void clean_bss(void);

  16. #endif
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. /*
  58. *功能:复制启动石中的4K代码,到SDRAM中去,LCD实验中,这个函数没有使用
  59. */
  60. void copy_steppingstone_to_sdram(void)
  61. {
  62.     unsigned int * src = (unsigned int *)0x0; /*片内4K内存*/
  63.     unsigned int * des = (unsigned int *)0x30000000; /*SDRAM起始地址,全部是物理地址*/
  64.     
  65.     while (src < (unsigned int *)4096) /*复制4K空间*/
  66.     {
  67.         *des = *src;
  68.         des++;
  69.         src++;
  70.     }
  71. }

  72. void clean_bss(void)
  73. {
  74.     extern int __bss_start, __bss_end;
  75.     int *p = &__bss_start;
  76.     
  77.     for (; p < &__bss_end; p++)
  78.         *p = 0;
  79. }
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
  3. @ 功能: 设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行
  4. @******************************************************************************
  5.    
  6. .extern main
  7. .text
  8. .global _start
  9. _start:
  10. @******************************************************************************
  11. @ 中断向量,本程序中,除Reset和HandleIRQ外,其它异常都没有使用
  12. @******************************************************************************
  13.     b Reset

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

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

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

  27. @ 0x14: 保留
  28. HandleNotUsed:
  29.     b HandleNotUsed

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

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

  35. Reset:
  36.     ldr sp, =4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈
  37.     bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启
  38.     bl clock_init @ 设置MPLL,改变FCLK、HCLK、PCLK
  39.     bl memsetup @ 设置存储控制器以使用SDRAM
  40.     //@bl init_uart                     @ 先设置了时钟,才能再初始化串口,这里为什么报错,是bl只能在4k范围内跳转吗???
  41. /*uart为什么不能在这里初始化????
  42.     ldr lr, =ret_inituart @ 设置返回地址
  43.        ldr pc, =init_uart            @ 这里为什么不能用 bl init_uart ???
  44. ret_inituart:
  45. **/    
  46.     bl nand_init @ 初始化NAND Flash
  47.     
  48.                             @ 复制nand中4k后的代码到SDRAM中
  49.     ldr r0, =0x30000000 @ 1. 目标地址 = 0x30000000,这是SDRAM的起始地址
  50.     mov r1, #4096 @ 2. 源地址 = 4096,运行地址在SDRAM中的代码保存在NAND Flash 4096地址开始处
  51.     mov r2, #300*1024 @ 3. 复制长度 = 16K,对于本实验,这是足够了
  52.     bl CopyCode2SDRAM @ 调用C函数CopyCode2SDRAM
  53.     
  54.     bl clean_bss @ 清除bss段,未初始化或初值为0的全局/静态变量保存在bss段

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

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

  69.     ldr lr, =halt_loop @ 设置返回地址
  70.     ldr pc, =main @ 调用main函数
  71. halt_loop:
  72.     b halt_loop

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

点击(此处)折叠或打开

  1. #include "interrupt.h"
  2. #include "uart.h"

  3. void (*isr_handle_array[50])(void);

  4. void Dummy_isr(void)
  5. {
  6.     while(1);
  7. }

  8. void all_init_irq(void)
  9. {
  10.     int i = 0;
  11.     for (i = 0; i < sizeof(isr_handle_array) / sizeof(isr_handle_array[0]); i++)
  12.     {
  13.         isr_handle_array[i] = Dummy_isr;
  14.     }

  15.     INTMOD = 0x0;     // 所有中断都设为IRQ模式
  16.     INTMSK = BIT_ALLMSK; // 先屏蔽所有中断

  17. //    isr_handle_array[ISR_IIC_OFT] = I2CIntHandle;
  18. }

  19. void IRQ_Handle(void)
  20. {
  21.     unsigned long oft = INTOFFSET;
  22.     
  23.     //清中断
  24.     if (oft == 4)
  25.         EINTPEND = 1<<7; //EINT4-7合用IRQ4,注意EINTPEND[3:0]保留未用,向这些位写入1可能导致未知结果
  26.     SRCPND = 1<<oft;    
  27.     INTPND = INTPND;    

  28.     /* 调用中断服务程序 */
  29.     isr_handle_array[oft]();
  30. }

  31. //以上程序模板,只用函数指针,可以设置所有的中断函数,本程序先使用下面固定的函数:使用LED来测试4个外部中断

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

  70. /*
  71.  * 功能:初始化LED的GPIO引脚
  72.  */
  73. static void init_led()
  74. {
  75.      GPBCON = (GPB5_OUT | GPB6_OUT | GPB7_OUT | GPB8_OUT);
  76.     GPBUP = 0x1e0;
  77.     GPBDAT = (GPB5_OFF | GPB6_OFF | GPB7_OFF | GPB8_OFF);
  78. }

  79. /*
  80. *功能:中断服务子程序
  81. *注意:1,按键产生中断的优先级顺序:K4(EINT0) > K1(EINT1) > K3(EINT2) > K2(EINT4)
  82. * 所以,同时按下其中2个,3个或者4个,只有优先级最高的哪个LED会被点亮
  83. * 2,如果硬件接线有LED连接了EINT4,EINT5,由于他们的中断优先级相同,EINTPEND[4:5]都是1,但都只会让SRCPND[4]=1,
  84. * 如果他们同时按下,则INTPND[4]=1,且INTOFFSET=4,走到case 4,EINTPEND[4:5]=11b,2个if都成立,所以,最后这2个LED会被同时点亮。
  85. */
  86. void EINT_Handle()
  87. {
  88.             init_led();
  89.             
  90.             /*INTOFFSET:中断偏移寄存器,INTPND寄存器中的值被置1之后,中断偏移寄存器的值=32个一级中断的编号*/
  91.             unsigned long offset = INTOFFSET;
  92.             unsigned long eintval;
  93.             
  94.             uart_sendString("\n\nINTOFFSET=");
  95.             uart_sendByte_hex(offset);
  96.             uart_sendByte('\n');
  97.             
  98.             switch(offset)
  99.             {
  100.                     /*EINT0中断:K4被按下*/
  101.                     case 0:
  102.                     {
  103.                                 uart_sendString("K4 ON!->LED4 ON!\n");
  104.                                 GPBDAT = (GPB5_OFF | GPB6_OFF | GPB7_OFF | GPB8_OFF);
  105.                                 GPBDAT = GPB8_ON; /*LED4亮*/
  106.                                 break;
  107.                     }
  108.                     /*EINT1中断:K1被按下*/
  109.                     case 1:
  110.                     {
  111.                                 uart_sendString("K1 ON!->LED1 ON!\n");
  112.                                 GPBDAT = (GPB5_OFF | GPB6_OFF | GPB7_OFF | GPB8_OFF);
  113.                                 GPBDAT = GPB5_ON; /*LED1亮*/
  114.                                 break;
  115.                     }
  116.                     /*EINT2中断:K3被按下*/
  117.                     case 2:
  118.                     {
  119.                                 uart_sendString("K3 ON!->LED3 ON!\n");
  120.                                 GPBDAT = (GPB5_OFF | GPB6_OFF | GPB7_OFF | GPB8_OFF);
  121.                                 GPBDAT = GPB7_ON; /*LED3亮*/
  122.                                 break;
  123.                     }
  124.                     /*EINT4~EINT7中断:虽然这里可以肯定是,EINT4,K2被按下,但是还是做一下判断:具体是EINT4到EINT7中的哪一个?*/
  125.                     case 4:
  126.                     {
  127.                                 GPBDAT = (GPB5_OFF | GPB6_OFF | GPB7_OFF | GPB8_OFF);
  128.                                 
  129.                                 /*EINTPEND:外部中断挂起寄存器
  130.                                 *EINTPEND低4位保留
  131.                                 *EINTPEND[4]=1 : 表示EINT4发生
  132.                                 *EINTPEND[5]=1 : 表示EINT5发生
  133.                                 */
  134.                                 eintval = EINTPEND;
  135.                                 if(eintval & (1<<4))
  136.                                 {
  137.                                         uart_sendString("K2 ON!->LED2 ON!\n");
  138.                                         GPBDAT = GPB6_ON; /*LED2亮*/
  139.                                 }
  140.                                 if(eintval & (1<<5))
  141.                                 {
  142.                                         
  143.                                 }
  144.                                 break;
  145.                     }
  146.                     default:
  147.                     {
  148.                                 break;
  149.                     }
  150.             }
  151.             /*中断处理完成之后:必须清除所有的挂起寄存器
  152.             *注意:向挂起寄存器中写1,即可令此位为0;写入0是没有效果的,若写入0,挂起寄存器中的数据保持不变。
  153.             */
  154.             if(offset == 4) /*二级外部中断,还必须清除 EINTPEND*/
  155.             {
  156.                      EINTPEND = (1<<4);
  157.             }
  158.             SRCPND = (1<<offset);
  159.             uart_sendString("SRCPND=");
  160.             uart_sendByte_hex(SRCPND);
  161.             uart_sendByte('\n');
  162.             
  163.             INTPND = (1<<offset);
  164.             uart_sendString("INTPND=");
  165.             uart_sendByte_hex(SRCPND);
  166.             uart_sendString("\n*************************************");
  167.             /*在清除 SRCPND INTPND时,INTOFFSET会被自动清除*/
  168. }
interrupt.h文件

点击(此处)折叠或打开

  1. #ifndef _INTERRUPT_H_
  2. #define _INTERRUPT_H_

  3. /**************************************************************************/
  4. //中断相关寄存器
  5. #define EXTINT0 (*(volatile unsigned long *)0x56000088)
  6. #define EINTMASK (*(volatile unsigned long *)0x560000A4)

  7. #define INTMSK (*(volatile unsigned long *)0x4A000008)
  8. #define INTMOD (*(volatile unsigned long *)0x4A000004)
  9. #define PRIORITY (*(volatile unsigned long *)0x4A00000C)

  10. #define EINTPEND (*(volatile unsigned long *)0x560000A8)

  11. #define SRCPND (*(volatile unsigned long *)0x4A000000)
  12. #define INTPND (*(volatile unsigned long *)0x4A000010)
  13. #define INTOFFSET (*(volatile unsigned long *)0x4A000014)

  14. #define BIT_ALLMSK        (0xffffffff)
  15. /**************************************************************************/


  16. /**************************************************************************/
  17. //按键相关的GPIO
  18. #define GPFCON (*(volatile unsigned long *)0x56000050)
  19. #define GPFDAT (*(volatile unsigned long *)0x56000054)
  20. #define GPFUP (*(volatile unsigned long *)0x56000058)
  21. /*注意:这个程序没有mmu,所以寄存器的地址是物理地址*/

  22. #define GPF0_EINT (2<<(0*2))
  23. #define GPF1_EINT (2<<(1*2))
  24. #define GPF2_EINT (2<<(2*2))
  25. #define GPF4_EINT (2<<(4*2))
  26. /**************************************************************************/


  27. /**************************************************************************/
  28. //LED相关的GPIO
  29. #define GPBDAT (*(volatile unsigned long *)0x56000014)
  30. #define GPBCON (*(volatile unsigned long *)0x56000010)
  31. #define GPBUP (*(volatile unsigned long *)0x56000018)
  32. /*注意:这个程序没有mmu,所以寄存器的地址是物理地址*/

  33. #define GPB5_OUT (1<<(5*2))
  34. #define GPB6_OUT (1<<(6*2))
  35. #define GPB7_OUT (1<<(7*2))
  36. #define GPB8_OUT (1<<(8*2))

  37. #define GPB5_ON (~(1<<5))
  38. #define GPB6_ON (~(1<<6))
  39. #define GPB7_ON (~(1<<7))
  40. #define GPB8_ON (~(1<<8))

  41. #define GPB5_OFF (1<<5)
  42. #define GPB6_OFF (1<<6)
  43. #define GPB7_OFF (1<<7)
  44. #define GPB8_OFF (1<<8)
  45. /**************************************************************************/


  46. #endif
lcd.c文件

点击(此处)折叠或打开

  1. #include "uart.h"
  2. #include "lcd.h"
  3. #include "def.h"
  4. #include "picture24.h"

  5. volatile unsigned short LCD_BUFFER[LCD_YSIZE_TFT_480272][LCD_XSIZE_TFT_480272]; /*分配显存:LCD屏幕视频缓冲区*/

  6. /*功能:LCD初始化
  7. * 注意:本实验用的LCD是 TFT_LCD 分辨率=480*272
  8. */
  9. void lcd_init(void)
  10. {
  11.     /*设置GPIO引脚用于LCD*/
  12.     GPCUP = 0x00000000;
  13.     
  14.     /*GPCCON寄存器
  15.     [31:0]=1010,1010,1010,1010,高16位,设置为:VD[7]到VD[0]功能引脚
  16.      0000,0010,1010,1001,底16位,设置为:input,input,input,VM,VFRAME,VLINE,VCLK,output功能引脚
  17.     */
  18.     GPCCON = 0xaaaa02a9;
  19.     
  20.     GPDUP = 0x0;
  21.     
  22.     /*GPDCON寄存器
  23.     [31:0]=1010,1010,1010,1010,1010,1010,1010,1010, 设置为:VD[23]到VD[8]功能引脚
  24.     */
  25.     GPDCON = 0xaaaaaaaa;
  26.     
  27.     GPGUP = 0x0;
  28.     /*GPG4:为LCD_PWREN引脚
  29.     为什么这里不设置也行?
  30.     */
  31.     //rGPGCON |= (3<<8);
  32.     
  33.     /*LCD控制1寄存器:用于设置LCD类型,像素时钟,使能LCD信号的输出
  34.     [10:8]=CLKAVL_TFT=(100)b,像素时钟信号VCLK=高速时钟信号HCLK/((4+1)*2),本实验中HCLK=100MHZ,所以VCLK=10MHZ
  35.     [6:5]=PNRMODE_LCDTYPE_TFT=(11)b,4位双扫描显示模式(STN) 11:TFT面板 (为什么设置成00和11都行啊?)
  36.     [4:1]=BPPMODE_16BPP=(1100)b,TFT的16位每像素模式,即16bpp
  37.     [0]=ENVID_DISABLE=0,禁止LCD控制信号和视频输出
  38.     */
  39.     rLCDCON1 = ((CLKAVL_TFT<<8)|(PNRMODE_LCDTYPE_TFT<<5)|(BPPMODE_16BPP<<1)|ENVID_DISABLE);
  40.     
  41.     /*LCD控制2寄存器:用于设置垂直方向上信号的时间参数
  42.     [25:24]=VBPD_480272=(10)b,垂直后沿帧开始时,垂直同步周期后的无效行数为2
  43.     [23:14]=LINEVAL_480272=(272-1)十进制,决定LCD面板的垂直尺寸,272行
  44.     [13:6]=VFPD_480272=(100)b,垂直前沿帧结束时,垂直同步周期前的无效行数为4
  45.     [5:0]=VSPW_480272=(1000)b,VSYNC脉冲的高电平宽度8
  46.     */
  47.     rLCDCON2 = ((VBPD_480272<<24)|(LINEVAL_480272<<14)|(VFPD_480272<<6)|(VSPW_480272));
  48.     
  49.     /*LCD控制3寄存器:用于设置水平方向各信号的时间参数
  50.     [22:19]=HBPD_480272=(1010)b,无效的像素点数,一个VCLK周期对应一个像素点。
  51.     [18:8]=HOZVAL_480272=(480-1)十进制,决定LCD面板的水平尺寸,480行
  52.     [7:0]=HFPD_480272=(10011)b,无效的像素点数
  53.     */
  54.     rLCDCON3 = ((HBPD_480272<<19)|(HOZVAL_480272<<8|(HFPD_480272)));
  55.     
  56.     /*LCD控制4寄存器:LCDCON3位数不够用,补充用LCDCON4,来给出另外一个水平方向信号的时间参数
  57.     [7:0]=(30)十进制,无效的像素点数
  58.     */
  59.     rLCDCON4 = (HSPW_480272);
  60.     
  61.     /*LCD控制5寄存器
  62.     [11]=1,16bpp输出数据视频的格式,为5:6:5,[11]=0,格式为5:5:5:1
  63.     [9]=1,本程序是TFT屏,所以只决定HSYNC脉冲极性,反转,[9]=0,极性正常
  64.     [8]=1,本程序是TFT屏,所以只决定VSYNC脉冲极性,反转,[8]=0,极性正常
  65.     [1]=0,字节交换控制位使能
  66.     [0]=1,半字节交换控制位使能,0位和1位,共同决定了16BPP显示模式时,内存中像素的排列格式:p1在低16位,p2在高16位
  67.     */
  68.     rLCDCON5 = ((FORMAT_FRM565_565<<11)|(INVVLINE_HSYNC<<9)|(INVVFRAME_VSYNC<<8)|(BSWP<<1)|(HWSWP));
  69.     
  70.     //本实验设置:帧内存与视口(view point)完全吻合
  71.     /*LCD帧缓冲器开始地址1寄存器
  72.     [29:21]=A[30:22],设置帧内存的起始地址。最高位31可以肯定是1,因为SDRAM所在0x30000000,所以只取了高位22~30,低位全0,所以只是4M对齐
  73.     另外还有个问题:为什么只设置了起始地址,没有设置结束地址?
  74.     [20:0]
  75.     */
  76.     rLCDSADDR1 = ((((U32)LCD_BUFFER>>22)<<21)|(LOWER21BITS((U32)LCD_BUFFER>>1)));
  77.     
  78.     /*LCD帧缓冲器开始地址2寄存器
  79.     [20:0]:这里的*2实际上是在变换格式,等效于左移1位,为的是保证和LCD_ADDR合着写在一起,然后整体向右移动一位.
  80.     */
  81.     rLCDSADDR2 = LOWER21BITS(((U32)LCD_BUFFER + (SCR_XSIZE_TFT*SCR_YSIZE_TFT*2))>>1);
  82.     
  83.     /*LCD帧缓冲器开始地址3寄存器:虚拟屏地址的设置
  84.     [21:11]
  85.     [10:0]
  86.     */
  87.     rLCDSADDR3 = (((SCR_XSIZE_TFT - LCD_XSIZE_TFT_480272) << 11) | (LCD_XSIZE_TFT_480272));
  88.     
  89.     /*LCD中断屏蔽寄存器:决定屏蔽哪个中断源,被屏蔽的中断源将不会被服务
  90.     [1]=1,LCD帧同步中断,屏蔽
  91.     [0]=1,LCD FIFO中断,屏蔽
  92.     */
  93.     rLCDINTMSK |= (3);
  94.     
  95.     /*TCON控制寄存器:专用于SEC TFT_LCD:控制LPC3600/LCC3600模式,本实验不需要用这个寄存器
  96.     [2]=0,同步模式,1:DE模式
  97.     [1]=0,输出分辨率类型320*240,1:分辨率类型240*320
  98.     [0]=0,LPC3600禁止,1:LPC3600使能
  99.     */
  100.     //rTCONSEL &= (~7);
  101.     
  102.     /*TFT调色板:本实验不用调色板,所以不用这个寄存器
  103.     [0]=0,全部不能显示*/
  104.     //rTPAL = 0;    
  105. }

  106. /*功能:视频输出的开关
  107. *参数:1:开,0:关
  108. */
  109. void lcd_envidONOFF(int onoff)
  110. {
  111.     if(onoff == 1)
  112.     {
  113.         rLCDCON1 |= 1; /*LCDCON1最低位为1:LCD输出使能*/
  114.     }
  115.     else
  116.     {
  117.         rLCDCON1 &= (~1); /*LCDCON1最低位为0:LCD输出禁止*/
  118.     }
  119. }


  120. /*功能:清屏,在屏幕上显示一种颜色
  121. *参数:c:表示一个像素点的颜色值
  122. *c=0x0:显示全黑色 c=0xffffffff:显示全白色。
  123. *注意:往这个buf里面写数据,会自动显示屏幕,具体是传输到屏幕的,我们不用关心。
  124. */
  125. void lcd_ClearScr(unsigned int c)
  126. {
  127.     unsigned int x, y;
  128.     for(y=0; y < SCR_YSIZE_TFT; y++) /*虚拟屏幕的空间*/
  129.     {
  130.         for(x=0; x<SCR_XSIZE_TFT; x++)
  131.         {
  132.             LCD_BUFFER[y][x] = c; /*往缓冲区写东西,就是往屏幕上送东西*/
  133.         }
  134.     }
  135. }

  136. /*功能:显示一个像素点,描点
  137. *参数:x:x轴,y:y轴,c:表示一个像素点的颜色值
  138. */
  139. void putPixel(unsigned int x, unsigned int y, unsigned int c)
  140. {
  141.     if((x<SCR_XSIZE_TFT) && (y<SCR_YSIZE_TFT)) /*虚拟屏幕的空间*/
  142.         LCD_BUFFER[(y)][(x)] = c;
  143. }

  144. /*
  145.  * 功能:绘制同心圆
  146.  * 圆的方程:圆心(a,b),本LCD圆心固定为(240,136)
  147.  * (x-a)*(x-a) + (y-b)*(y-b) = R*R
  148.  * 数学原理:圆心固定,指定不同的(x,y)值时,可以得到不同的R值。
  149.  * 又因为R*R=16*color,所以,在同一个圆上时,color值相同。则可以实现同心圆上线条的颜色相同。
  150.  */
  151. void Mire(void)
  152. {
  153.     unsigned int x,y;
  154.     unsigned int color;
  155.     U8 red,green,blue,alpha;
  156.     
  157.     unsigned int ysize = 272;
  158.     unsigned int xsize = 480;

  159.     for (y = 0; y < ysize; y++)
  160.         for (x = 0; x < xsize; x++){
  161.             color = ((x-xsize/2)*(x-xsize/2) + (y-ysize/2)*(y-ysize/2))/4;
  162.             red = (color/8) % 256; //%256:表示保留8位,因为本程序约定用8位表示一个颜色
  163.             green = (color/4) % 256;
  164.             blue = (color/2) % 256;
  165.             alpha = (color*2) % 256;

  166.             color |= ((unsigned int)alpha << 24);
  167.             color |= ((unsigned int)red << 16);
  168.             color |= ((unsigned int)green << 8 );
  169.             color |= ((unsigned int)blue );

  170.             putPixel(x,y,color);
  171.         }
  172. }


  173. /*功能:画线
  174. *原理:2点确定一条直线
  175. *参数:点1(x1,y1), 点2(x2,y2),color:一个像素点的颜色
  176. *编程思路:
  177. */
  178. void glib_line(int x1, int y1, int x2, int y2, int color)
  179. {
  180.     int dx, dy, e;
  181.     dx = x2 - x1;
  182.     dy = y2 - y1;

  183.     if(dx>=0)
  184.     {
  185.         if(dy >= 0) // dy>=0
  186.         {
  187.             if(dx>=dy) // 1/8 octant
  188.             {
  189.                 e=dy-dx/2;
  190.                 while(x1<=x2)
  191.                 {
  192.                     putPixel(x1,y1,color);
  193.                     if(e>0){y1+=1;e-=dx;}    
  194.                     x1+=1;
  195.                     e+=dy;
  196.                 }
  197.             }
  198.             else        // 2/8 octant
  199.             {
  200.                 e=dx-dy/2;
  201.                 while(y1<=y2)
  202.                 {
  203.                     putPixel(x1,y1,color);
  204.                     if(e>0){x1+=1;e-=dy;}    
  205.                     y1+=1;
  206.                     e+=dx;
  207.                 }
  208.             }
  209.         }
  210.         else         // dy<0
  211.         {
  212.             dy=-dy; // dy=abs(dy)

  213.             if(dx>=dy) // 8/8 octant
  214.             {
  215.                 e=dy-dx/2;
  216.                 while(x1<=x2)
  217.                 {
  218.                     putPixel(x1,y1,color);
  219.                     if(e>0){y1-=1;e-=dx;}    
  220.                     x1+=1;
  221.                     e+=dy;
  222.                 }
  223.             }
  224.             else        // 7/8 octant
  225.             {
  226.                 e=dx-dy/2;
  227.                 while(y1>=y2)
  228.                 {
  229.                     putPixel(x1,y1,color);
  230.                     if(e>0){x1+=1;e-=dy;}    
  231.                     y1-=1;
  232.                     e+=dx;
  233.                 }
  234.             }
  235.         }    
  236.     }
  237.     else //dx<0
  238.     {
  239.         dx=-dx;        //dx=abs(dx)
  240.         if(dy >= 0) // dy>=0
  241.         {
  242.             if(dx>=dy) // 4/8 octant
  243.             {
  244.                 e=dy-dx/2;
  245.                 while(x1>=x2)
  246.                 {
  247.                     putPixel(x1,y1,color);
  248.                     if(e>0){y1+=1;e-=dx;}    
  249.                     x1-=1;
  250.                     e+=dy;
  251.                 }
  252.             }
  253.             else        // 3/8 octant
  254.             {
  255.                 e=dx-dy/2;
  256.                 while(y1<=y2)
  257.                 {
  258.                     putPixel(x1,y1,color);
  259.                     if(e>0){x1-=1;e-=dy;}    
  260.                     y1+=1;
  261.                     e+=dx;
  262.                 }
  263.             }
  264.         }
  265.         else         // dy<0
  266.         {
  267.             dy=-dy; // dy=abs(dy)

  268.             if(dx>=dy) // 5/8 octant
  269.             {
  270.                 e=dy-dx/2;
  271.                 while(x1>=x2)
  272.                 {
  273.                     putPixel(x1,y1,color);
  274.                     if(e>0){y1-=1;e-=dx;}    
  275.                     x1-=1;
  276.                     e+=dy;
  277.                 }
  278.             }
  279.             else        // 6/8 octant
  280.             {
  281.                 e=dx-dy/2;
  282.                 while(y1>=y2)
  283.                 {
  284.                     putPixel(x1,y1,color);
  285.                     if(e>0){x1-=1;e-=dy;}    
  286.                     y1-=1;
  287.                     e+=dx;
  288.                 }
  289.             }
  290.         }    
  291.     }
  292.     
  293. }

  294. /*功能:画矩形
  295. *参数:已知2个对角的顶点,就可以确定一个矩形 color:一个像素点的颜色
  296. */
  297. void glib_filledrectangle(int x1, int y1, int x2, int y2, int color)
  298. {
  299.     int i;
  300.     for (i= y1; i<=y2; i++)
  301.         glib_line(x1, i, x2, i, color);

  302. }

  303. /*
  304. *功能:显示bmp格式的图片
  305. */
  306. void paint_bmp(int x0, int y0, int h, int l, unsigned char bmp[])
  307. {
  308.     int x, y;
  309.     U32 c;
  310.     int p = 0;
  311.     
  312.     for(y = y0; y<l; y++)
  313.     {
  314.         for(x=x0; x<h; x++)
  315.         {
  316.             c = (bmp[p]<<8)|bmp[p+1];
  317.             if(((x0+x)<SCR_XSIZE_TFT) && ((y0+y) < SCR_YSIZE_TFT))
  318.             {
  319.                 LCD_BUFFER[y0+y][x0+x] = c;
  320.             }
  321.             p +=2;
  322.         }
  323.     }
  324. }
lcd.h文件

点击(此处)折叠或打开

  1. #ifndef _LCD_H_
  2. #define _LCD_H_

  3. /**************************************************************************/
  4. //lcd相关的GPIO
  5. #define GPCCON (*(volatile unsigned long *)0x56000020) //设置为:VD[7]到VD[0]功能引脚
  6. #define GPCDAT (*(volatile unsigned long *)0x56000024)
  7. #define GPCUP (*(volatile unsigned long *)0x56000028)

  8. #define GPDCON (*(volatile unsigned long *)0x56000030) //设置为:VD[23]到VD[8]功能引脚
  9. #define GPDDAT (*(volatile unsigned long *)0x56000034)
  10. #define GPDUP (*(volatile unsigned long *)0x56000038)

  11. #define GPGCON (*(volatile unsigned long *)0x56000060) //设置为:LCD_PWREN引脚
  12. #define GPGDAT (*(volatile unsigned long *)0x56000064)
  13. #define GPGUP (*(volatile unsigned long *)0x56000068)
  14. /**************************************************************************/

  15. /***************************************************************************/
  16. //LCD相关寄存器
  17. #define rLCDCON1 (*(volatile unsigned *)0x4d000000)    //LCD控制寄存器LCDCON1
  18. #define rLCDCON2 (*(volatile unsigned *)0x4d000004)    //LCD控制寄存器LCDCON2
  19. #define rLCDCON3 (*(volatile unsigned *)0x4d000008)    //LCD控制寄存器LCDCON3
  20. #define rLCDCON4 (*(volatile unsigned *)0x4d00000c)    //LCD控制寄存器LCDCON4
  21. #define rLCDCON5 (*(volatile unsigned *)0x4d000010)    //LCD控制寄存器LCDCON5
  22. #define rLCDSADDR1 (*(volatile unsigned *)0x4d000014)    //帧内存地址寄存器LCDSADDR1
  23. #define rLCDSADDR2 (*(volatile unsigned *)0x4d000018)    //帧内存地址寄存器LCDSADDR2
  24. #define rLCDSADDR3 (*(volatile unsigned *)0x4d00001c)    //帧内存地址寄存器LCDSADDR3
  25. #define rTPAL (*(volatile unsigned *)0x4d000050)    //临时调试板寄存器TPAL
  26. #define rLCDINTPND (*(volatile unsigned *)0x4d000054)    //LCD中断挂起寄存器
  27. #define rLCDSRCPND (*(volatile unsigned *)0x4d000058)    //LCD中断源寄存器
  28. #define rLCDINTMSK (*(volatile unsigned *)0x4d00005c)    //LCD中断屏蔽寄存器
  29. #define PALETTE 0x4d000400                         //调试板起始地址
  30. /*****************************************************************************/

  31. #define CLKAVL_TFT ((0x04)&(0x3ff)) //用于设置LCDCON1中,像素时钟:低10位有效
  32. #define PNRMODE_LCDTYPE_TFT ((0x03)&(0x3)) //用于设置LCDCON1中,LCD类型:TFT:低2位有效
  33. #define BPPMODE_8BPP ((0xB)&(0xf)) //用于设置LCDCON1中,BPP类型:8BPP:低4位有效
  34. #define BPPMODE_16BPP (0xC) //用于设置LCDCON1中,BPP类型:16BPP
  35. #define BPPMODE_24BPP (0xD) //用于设置LCDCON1中,BPP类型:24BPP
  36. #define ENVID_DISABLE (0) //用于设置LCDCON1中,LCD信号禁止
  37. #define ENVID_ENABLE (1) //用于设置LCDCON1中,LCD信号使能

  38. #define VBPD_480272 ((2)&(0xff)) //用于设置LCDCON2中,VBPD值:低8位有效
  39. #define LCD_YSIZE_TFT_480272 (272)
  40. //#define LINEVAL_480272 ((LCD_YSIZE_TFT_480272-1)&(0x3ff)) //用于设置LCDCON2中,LINEVAL值:低10位有效
  41. #define LINEVAL_480272 271 //LINEVAL_480272+1的值,必须是实际LCD的高度
  42. #define VFPD_480272 ((4)&(0xff)) //用于设置LCDCON2中,VFPD值:低8位有效
  43. #define VSPW_480272 ((8)&(0x3f)) //用于设置LCDCON2中,VSPW值:低8位有效

  44. #define HBPD_480272 ((10)&(0x7f)) //用于设置LCDCON3中,HBPD值:低7位有效
  45. #define LCD_XSIZE_TFT_480272 (480)
  46. //#define HOZVAL_480272 ((LCD_XSIZE_TFT_480272-1)&(0x7ff)) //用于设置LCDCON3中,HOZVAL值:低11位有效
  47. #define HOZVAL_480272 479 //HOZVAL_480272+1的值,必须是实际LCD的宽度
  48. #define HFPD_480272 ((19)&(0xff)) //用于设置LCDCON3中,HFPD值:低8位有效

  49. #define HSPW_480272 ((30)&(0xff)) //用于设置LCDCON4中,HSPW值:低8位有效

  50. #define FORMAT_FRM565_565 (1) //用于设置LCDCON5中,FRM565值:TFT_LCD的显示模式为16BPP时:所使用的数据格式:565格式
  51. #define FORMAT_FRM565_5551 (0) //用于设置LCDCON5中,FRM565值:TFT_LCD的显示模式为16BPP时:所使用的数据格式:5551格式
  52. #define INVVLINE_HSYNC (1) //用于设置LCDCON5中,INVVLINE值:1:极性反转
  53. #define INVVFRAME_VSYNC (1) //用于设置LCDCON5中,INVVFRAME值:1:极性反转
  54. #define BSWP (0) //用于设置LCDCON5中,BSWP值:0
  55. #define HWSWP (1) //用于设置LCDCON5中,HWSWP值:1:0位和1位,共同决定内存中像素的排列格式


  56. #define SCR_XSIZE_TFT (480)
  57. #define SCR_YSIZE_TFT (272)

  58. #define LOWER21BITS(n) ((n) & 0x1fffff)

  59. void lcd_init(void);
  60. void lcd_envidONOFF(int onoff);
  61. void putPixel(unsigned int x, unsigned int y, unsigned int c);
  62. void lcd_ClearScr(unsigned int c);
  63. void glib_line(int x1, int y1, int x2, int y2, int color);
  64. void glib_filledrectangle(int x1, int y1, int x2, int y2, int color);
  65. void Mire(void);
  66. void paint_bmp(int x0, int y0, int h, int l, unsigned char bmp[]);

  67. #endif
lcd.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 "uart.h"
  3. #include "nand.h"
  4. #include "lcd.h"
  5. #include "interrupt.h"
  6. #include "def.h"
  7. #include "picture24.h"

  8. int main()
  9. {
  10.     /*uart.o 和 main.o 的代码,同在0x30000000之后,可以相互调用,4k之内的代码就不能调用了*/
  11.     //init_uart();
  12.     
  13.     uart_sendString("\nLCD test!\n");
  14.     uart_sendByte('W');
  15.     uart_sendByte('\n');
  16.     uart_sendByte('X');
  17.     uart_sendByte('\n');
  18.     uart_sendByte('C');
  19.     uart_sendByte('\n');
  20.     lcd_init();
  21.     lcd_envidONOFF(1);
  22.     
  23.     uart_sendString("\npress any key display a white pixel in (240,136)\n");
  24.     uart_getch();
  25.     lcd_ClearScr(0x0);
  26.     putPixel(240,136,0xffffffff);
  27.     
  28.     
  29.     uart_sendString("\npress any key display four line\n");
  30.     uart_getch();
  31.     lcd_ClearScr(0xffffffff);
  32.     glib_line(0, 0, LCD_XSIZE_TFT_480272, LCD_YSIZE_TFT_480272, 0x0);
  33.     glib_line(0, LCD_YSIZE_TFT_480272, LCD_XSIZE_TFT_480272, 0, 0x0);
  34.     glib_line(0, LCD_YSIZE_TFT_480272/2, LCD_XSIZE_TFT_480272, LCD_YSIZE_TFT_480272/2, 0x0);
  35.     glib_line(LCD_XSIZE_TFT_480272/2, 0, LCD_XSIZE_TFT_480272/2, LCD_YSIZE_TFT_480272, 0x0);
  36.     
  37.     
  38.     uart_sendString("\npress any key display 7 rectangle\n");
  39.     uart_getch();
  40.     lcd_ClearScr(0xffffffff);
  41.     uart_sendString("\npress any key display NO.1 rectangle\n");
  42.     uart_getch();
  43.     glib_filledrectangle(0,0,480,38, 0x001f);
  44.     uart_sendString("\npress any key display NO.2 rectangle\n");
  45.     uart_getch();
  46.     glib_filledrectangle(0,40,480,78, 0x07e0);
  47.     uart_sendString("\npress any key display NO.3 rectangle\n");
  48.     uart_getch();
  49.     glib_filledrectangle(0,80,480,118, 0x0);
  50.     uart_sendString("\npress any key display NO.4 rectangle\n");
  51.     uart_getch();
  52.     glib_filledrectangle(0,120,480,158, 0xffe0);
  53.     uart_sendString("\npress any key display NO.5 rectangle\n");
  54.     uart_getch();
  55.     glib_filledrectangle(0,160,480,198, 0xf81f);
  56.     uart_sendString("\npress any key display NO.6 rectangle\n");
  57.     uart_getch();
  58.     glib_filledrectangle(0,200,480,238, 0x07ff);
  59.     uart_sendString("\npress any key display NO.7 rectangle\n");
  60.     uart_getch();
  61.     glib_filledrectangle(0,240,480,272, 0xf800);
  62.     uart_sendString("\npress any key display NO.8 circle\n");
  63.     uart_getch();
  64.     Mire();
  65.     uart_sendString("\npress any key display NO.9 bmp_picture\n");
  66.     uart_getch();
  67.     paint_bmp(0,0, 480,272, picture24);
  68.     while(1);

  69.     return 0;
  70. }
makefile文件

点击(此处)折叠或打开

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

  2. lcd.bin: $(objs)
  3.     arm-linux-ld -Tlcd.lds -o lcd_elf $^
  4.     arm-linux-objcopy -O binary -S lcd_elf $@
  5.     arm-linux-objdump -D -m arm lcd_elf > lcd.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 lcd.bin lcd_elf lcd.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.     /* 下面串口打印函数不能用了,因为连接脚本将nand.o放在4k内,uart.o在4k外,不能调用了
  55.     uart_sendByte('\n');
  56.     uart_sendByte('w');
  57.     uart_sendByte('x');
  58.     uart_sendByte('c');
  59.     uart_sendByte('\n');
  60.     
  61.     ret = nand_readId();
  62.     uart_sendByte('\n');
  63.     uart_sendString("nand_readId = ");
  64.     uart_sendByte_hex(ret);
  65.     uart_sendByte('\n');
  66.     
  67.     uart_sendString("please input:\n");
  68.     ch = uart_getch();
  69.     uart_sendString("your input is:");
  70.     uart_sendByte(ch);
  71.     uart_sendByte('\n');
  72.     */
  73.     
  74.     return ;
  75. }


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


  121. /*功能 : 发出地址
  122. *注意: 这个地址,不是页编号,是具体的读取NandFlash的起始地址,包括页内地址
  123. */
  124. void write_addr(unsigned int addr)
  125. {
  126.         //写地址(要读取数据的起始地址) :
  127.         //包括 : 列(页内)地址,是低位地址,共A0~A11,在具体的page页内寻址。一个page页=(2K+64)字节
  128.         // 行(页)地址,是高位地址,共A12~A28,可以寻址到page页。一个Nand器件=2K*64个page页 = 128K页
  129.         // 高位地址中,A12~A17,可以寻址到block块下面的page页。一个block块=64个page页
  130.         // 高位地址中,A18~A28,可以寻址到block块。一个Nand器件=2K个block块
  131.         //要写全部的5个周期的地址
  132.     
  133.         //32位的page_number : 低29位有效 :
  134.         //| 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 |
  135.      // 对应最后3个地址周期的页内地址的高11位 :
  136.         //|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|
  137.         //29位在5个地址周期中应是如下的分布 :
  138.         //| I7 | I6 | I5 | I4 | I3 | I2 | I1 | I0 |
  139.         //| L | L | L | L | L | L | L | A28 |
  140.         //| A27 | A26 | A25 | A24 | A23 | A22 | A21 | A20 |
  141.         //| A19 | A18 | A17 | A16 | A15 | A14 | A13 | A12 |
  142.         //| L | L | L | L | A11 | A10 | A9 | A8 |
  143.         //| A7 | A6 | A5 | A4 | A3 | A2 | A1 | A0 |
  144.     
  145.     int i;
  146.     int col, page;

  147.         col = addr & (2048 -1); //截取低位:取2048的原因:本程序使用的nand芯片的一个page页是2048字节
  148.         page = addr / 2048; //截取高位
  149.     
  150.     NF_ADDR(col & 0xFF); //列(页内)地址 A0~A7
  151.     for(i=0; i<100; i++);
  152.         NF_ADDR((col >> 8) & 0x0F);     //列(页内)地址 A8~A11
  153.         for(i=0; i<100; i++);
  154.         
  155.         NF_ADDR(page & 0xFF); //行(页)地址 A12~A19
  156.         for(i=0; i<100; i++);
  157.         NF_ADDR((page >> 8) & 0xFF); //行(页)地址 A20~A27
  158.         for(i=0; i<100; i++);
  159.         NF_ADDR((page >> 16) & 0x03); //行(页)地址 A28~A29
  160.         for(i=0; i<100; i++);
  161. }

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

  208. int CopyCode2SDRAM(unsigned char *buf, unsigned long start_addr, int size)
  209. {
  210.     nand_read(buf, start_addr, size);
  211.     return 0;
  212. }


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


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

点击(此处)折叠或打开

  1. #define WIN32

  2. unsigned char picture24[] = {

  3. #ifdef    WIN32
  4.    0xad,0x53,0xad,0x53,0xad,0x53,0xa5,0x33,0xa5,0x13,0xa5,0x13,0x9c,0xf2,0x9c,0xd2,
  5.    0x9c,0xd2,0x94,0xd2,0x94,0xb2,0x94,0xd2,0x9c,0xd3,0x9c,0xf3,0x9c,0xf3,0x9c,0xf3,
  6.    0xa4,0xf3,0xa5,0x13,0xa5,0x13,0xa5,0x13,0xa5,0x34,0xa5,0x34,0xad,0x54,0xad,0x54,
  7. ...............
  8. #else
  9.    0x24,0x19,0x24,0x21,0x24,0x21,0x24,0x21,0x04,0x19,0xe3,0x18,0x04,0x19,0x45,0x21,
  10. ........
  11.    0xa3,0x10,0xa2,0x10,0xa2,0x10,0xa2,0x10,0xa2,0x10,0xc3,0x18,0xe3,0x18,0xc3,0x18,
  12.    0xc3,0x18,0xc3,0x18,0xc3,0x18,0xc3,0x18,0xa3,0x10,0xa2,0x10,0x82,0x10,0x61,0x08,
  13.    
  14. #endif


  15. };
picture24.h文件

点击(此处)折叠或打开

  1. #ifndef _PICTURE_H_
  2. #define _PICTURE_H_

  3. extern unsigned char picture24[];

  4. #endif
uart.c文件

点击(此处)折叠或打开

  1. #include "uart.h"

  2. /***********************************************************************************/
  3. //串口相关函数
  4. /*功能:初始化串口UART0
  5. *轮询方式来使用串口
  6. */
  7. void init_uart()
  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. *参数:待发送的字符

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

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

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

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

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

  135. /*功能:向串口格式化打印一个字符串
  136. *参数:格式化的字符串
  137. 这个函数编译不过去,不知道什么原因?????????????
  138. void uart_printf(char* fmt,...)
  139. {
  140.     va_list args; //动态参数列表
  141.     char string[256];
  142.     
  143.     va_start(args,fmt);
  144.     vsprintf(string,fmt, args);
  145.     uart_sendString(string);
  146.     va_end(args);
  147. }
  148. */

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

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

  156. URXH0:串口接受缓冲寄存器
  157. [7:0]:串口接受到的数据
  158. */
  159. char uart_getch(void)
  160. {
  161.     /*等待,直到接受缓冲区中有数据*/
  162.     while(!(rUTRSTAT0 & 0x1));
  163.     /*直接读取URXH0寄存器,即可以获得接受到的数据
  164.     #define rURXH0 (*(volatile unsigned char *)0x50000024)    //UART 0 Receive buffer
  165.     #define RdURXH0() (*(volatile unsigned char *)0x50000024)
  166.     所以:return RdURXH0(); 相当于:return rURXH0;
  167.     */
  168.     return RdURXH0();
  169. }

  170. /*功能:从串口接受一个字符串
  171. *参数:输入的字符串
  172. */
  173. void uart_getString(char *string)
  174. {
  175.     char *string2 = string;
  176.     char c;
  177.     while((c=uart_getch()) != '\r')
  178.     {
  179.         if(c == '\b')
  180.         {
  181.             if((int)string2 < (int)string)
  182.             {
  183.                 //uart_printf("\b\b");
  184.                 string--;
  185.             }
  186.         }
  187.         else
  188.         {
  189.             *string++ = c;
  190.             uart_sendByte(c);
  191.         }
  192.     }
  193.     *string = '\0';
  194.     uart_sendByte('\n');
  195. }
  196. /***********************************************************************************/
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. void init_uart();
  20. void uart_sendByte(int data);
  21. void uart_sendString(char *p);
  22. void uart_sendByte_hex(unsigned long val);
  23. char uart_getch(void);
  24. void uart_getString(char *string);
  25. /**************************************************************************/

  26. #endif




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