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

全部博文(573)

文章存档

2018年(3)

2016年(48)

2015年(522)

分类: LINUX

2015-12-02 11:16:22

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
adc.c文件

点击(此处)折叠或打开

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

  3. /*
  4. *功能:AD转换初始化
  5. */
  6. void init_ADC()
  7. {
  8.         uart_sendString("init_ADC!\n");
  9.      //当PCLK为50M,ADC转换频率为2M时,算得预分频系数是24
  10.         unsigned int prscen = PCLK/ADC_FREQ -1;
  11.         
  12.         /*ADCCON寄存器
  13.         *[15]:只读,AD转换结束标志 0:正在转换 1:转换结束
  14.         *[14]=1 1:AD转换器的时钟使用预分频 0:AD转换器的时钟不使用预分频
  15.         *[13:6]=19,预分频系数,因为初始这8是全1
  16.         *[5:3]=0b010,AD转换的通道
  17.         *[2] 0: 正常模式 1: 静态模式 初始是1
  18.         *[1] 0:读转换数据时不启动下一次转换 1:读转换数据时启动下一次转换
  19.         *[0] 当READ_START位=1时,这个位无效。 0:无作用 1:启动AD转换(当转换真正开始时,此位被请0)
  20.         */
  21.         ADCCON &= (~(0xFF << 6)); //这里8位必须清0,
  22.         ADCCON &= (~(1 << 2));
  23.         //上面2句也可以合并成如下一句:
  24.         //ADCCON = 0x0; //全部清0,因为已经在前面保存了这个寄存器原来的值,所以这里可以全清0。
  25.         
  26.         ADCCON |= ((1 << 14) | ((prscen & 0xff) << 6));
  27.         ADCCON &= (~(1 << 1));
  28.         ADC_DISABLE(); //初始化时,并不启动AD转换
  29.         
  30.         //这里是普通的AD转换,ADCTSC寄存器的值,取默认值就行了。
  31.         ADCTSC &= (~(1<<2));
  32. }

  33. /*
  34. *功能:选择进行AD转换的通道
  35. */
  36. void get_ch(unsigned int chanal)
  37. {
  38.         int i;
  39.         unsigned int sel_mux;
  40.         sel_mux = (ADCCON>>3)&0x7; //新通道之前的通道
  41.         
  42.         uart_sendString("get_ch!\n");
  43.         if(sel_mux != chanal) //之前的通道,与现在选择的通道不同,则需要变换通道
  44.         {
  45.                 ADCCON &= (~(7<<3)); //先把已有的数据清0
  46.                 ADCCON |= (chanal<<3); //选择新的通道值。
  47.                 //注意:选择新的通道值之后,需要延时一段时间,等待AD转换器反应过来
  48.                 for(i=0; i<10000; i++);
  49.                 for(i=0; i<10000; i++);
  50.         }
  51. }


  52. /*
  53. *功能:读取AD转换后的值
  54. */
  55. unsigned int read_ADC()
  56. {
  57.         unsigned int data;
  58.         
  59.         //启动AD转换
  60.         ADC_START();
  61.         
  62.         uart_sendString("read_ADC!\n");
  63.         
  64.         while(ADCCON & 0x1); //转换真正开始时,此位会被清0,清0之后继续向下走
  65.         
  66.         while((ADCCON & 0x8000) == 0); //0:正在转换 1:转换结束,变成1之后继续向下走
  67.         
  68.         data = (ADCDAT0 & 0x3ff); //ADCDAT0[9:0]10位,是普通AD转换后的数据值
  69.         
  70.         return data;
  71. }
adc.h文件

点击(此处)折叠或打开

  1. #ifndef __ADC_H__
  2. #define __ADC_H__

  3. /*模数转换相关寄存器*/
  4. #define    ADCCON        (*(volatile unsigned long *)0x58000000)
  5. #define    ADCTSC        (*(volatile unsigned long *)0x58000004)
  6. #define    ADCDAT0        (*(volatile unsigned long *)0x5800000C)

  7. #define ADC_DISABLE() ((ADCCON) & (~(1<<0)))
  8. #define ADC_START() ((ADCCON) |= (0x1))

  9. //ADC转换频率最大为2M PCLK=50M
  10. #define ADC_FREQ (2000000)
  11. #define ADC_CHANAL_AIN2 2

  12. void init_ADC();
  13. void get_ch(unsigned int chanal);
  14. unsigned int read_ADC();

  15. #endif
adc.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. }
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. .text
  6. .global _start
  7. _start:
  8.                                       @函数disable_watch_dog, memsetup 在init.c中定义
  9.       ldr sp, =4096 @设置堆栈
  10.       bl disable_watch_dog @关WATCH DOG
  11.       bl clock_init @设置MPLL,改变FCLK、HCLK、PCLK
  12.       bl memsetup @初始化SDRAM
  13.       bl nand_init                 @ 初始化NAND Flash

  14.                      @ 复制nand中4k后的代码到SDRAM中
  15.      ldr r0, =0x30000000                 @ 1. 目标地址 = 0x30000000,这是SDRAM的起始地址
  16.      mov r1, #4096                 @ 2. 源地址 = 4096,运行地址在SDRAM中的代码保存在NAND Flash 4096地址开始处
  17.      mov r2, #6*1024                  @ 3. 复制长度 = 6K,对于本实验,这是足够了
  18.      bl CopyCode2SDRAM                 @ 调用C函数CopyCode2SDRAM
  19.     
  20.      bl clean_bss @ 清除bss段,未初始化或初值为0的全局/静态变量保存在bss段
  21.       
  22.       ldr sp, =0x34000000 @设置栈
  23.       
  24.      ldr lr, =ret_inituart @ 设置返回地址
  25.      ldr pc, =init_uart             @ 这里为什么不能用 bl init_uart ???,也可以在main函数里面初始化
  26. ret_inituart:

  27.       ldr lr, =halt_loop @设置返回地址
  28.       ldr pc, =main @b指令和bl指令只能前后跳转32M的范围,所以这里使用向pc赋值的方法进行跳转
  29. halt_loop:
  30.       b halt_loop
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中去,ADC实验中,这个函数没有使用
  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. }
main.c文件

点击(此处)折叠或打开

  1. #include "adc.h"
  2. #include "uart.h"
  3. #include "adc.h"

  4. int main(void)
  5. {
  6.         int i = 0;
  7.         unsigned int adc_data;
  8.     
  9.         //本实验仅完成模数转换,不涉及触摸屏,所以没有中断
  10.         uart_sendString("\n ADC test:\n");
  11.         uart_sendString("ADC frequency = 2MHZ\n");
  12.         uart_sendString("ADC chanal = AIN 2\n");
  13.         
  14.         uart_sendString("\n begin:\n");
  15.         
  16.         //这个目的是:保留之前的配置,本程序完之后,会恢复这个值。
  17.         //之所以保存它,是因为其他程序有可能使用了这个值,虽然本程序没有使用。
  18.         unsigned int ADCCON_save = ADCCON;
  19.         //AD转换初始化
  20.         init_ADC();
  21.         
  22.         /*1,本程序流程:每按一次键,就读取一下AD转换的值,按ESC键结束本次测试。
  23.         * 2,不转动电位器时,每次读取的值可能不一样,但是差距会很小,这是正常的,每次转化会有误差,电位器电压有波动。
  24.         * 3,转动电位器,可以看见不同的点位值。
  25.         * 4,有硬件原理图可以看出:电位器电压范围是0~3.3V,这里可以转化成10位。1024个电压等级,每个等级电压差值=3.3V/1024
  26.         * 即0V时,数字量是0 3.3V时,数字量是1023。所以可以根据数字量计算出电压值。
  27.         */
  28.         while(uart_getch() != 0x1b) //0x1b 是ESC键
  29.         {
  30.                 uart_sendString("\n*****************************************\n");
  31.                 //选择AD通道:本开发板硬件连线,只连接了AIN 2
  32.                 get_ch(ADC_CHANAL_AIN2);

  33.                 //读取AD转换后的值。
  34.                 adc_data = read_ADC();
  35.                 
  36.                 for(i=0; i<10000; i++);
  37.                 for(i=0; i<10000; i++);
  38.                 for(i=0; i<10000; i++);
  39.                 for(i=0; i<10000; i++);
  40.                         
  41.                 uart_sendString("ADC_data = : ");
  42.                 uart_sendByte_hex((unsigned long)(adc_data));
  43.                 uart_sendByte('\n');
  44.                 uart_sendString("*****************************************\n");
  45.         }
  46.         ADCCON = ADCCON_save; //恢复保存的值
  47.         
  48.         uart_sendString("end!\n");
  49.         
  50.         return 0;
  51. }
makefile文件

点击(此处)折叠或打开

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

  2. adc.bin: $(objs)
  3.     arm-linux-ld -Tadc.lds -o adc_elf $^
  4.     arm-linux-objcopy -O binary -S adc_elf $@
  5.     arm-linux-objdump -D -m arm adc_elf > adc.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 adc.bin adc_elf adc.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()
  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. UTRSTAT0: 串口收发TX/RX状态寄存器
  138. [0]:接收缓冲器数据就绪标志位。
  139. 0:接收缓冲器为空
  140. 1:接收缓冲器接收到有效数据(非FIFO模式,非请求中断,非DMA)
  141. 注意:如果UART使用FIFO,用户应该使用UFSTAT寄存器中的Rx FIFO计数位 和 Rx FIFO满位取代对此位的检查。

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

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










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

上一篇:移植mplay播放器

下一篇:uart裸机驱动程序

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