Chinaunix首页 | 论坛 | 博客
  • 博客访问: 677484
  • 博文数量: 516
  • 博客积分: 4119
  • 博客等级: 上校
  • 技术积分: 4288
  • 用 户 组: 普通用户
  • 注册时间: 2012-10-30 17:29
文章分类

全部博文(516)

文章存档

2014年(4)

2013年(160)

2012年(352)

分类:

2012-11-01 11:03:48

原文地址:NAND Flash驱动 作者:graylocus

在MINI2440开发板上,NAND Flash型号K9F2G08,大小256MB。
1.首先是启动代码

点击(此处)折叠或打开

  1. ################################
  2. #head.S
  3. #作为启动代码,负责初始化工作,并将nand 4k 之后的代码copy到内存,跳到内存执行程序
  4. ##############################################

  5. .text
  6. .global _start
  7. _start:
  8. @函数disable_watch_dog, memsetup, init_nand, nand_read_ll在init.c中定义
  9. ldr sp, =4096 @调用C函数之前必须设置堆栈
  10. bl disable_watch_dog   @关WATCH DOG
  11. bl memsetup @初始化SDRAM
  12. bl nand_init @初始化NAND Flash
  13. @将NAND Flash中地址4096开始的2048字节代码(main.c编译得到)复制到SDRAM中
  14. @nand_read_ll函数需要3个参数:
  15. ldr r0, =0x30000000 @1目标地址=0x30000000,这是SDRAM的起始地址
  16. mov r1, #4096 @2.源地址 = 4096,连接的时候,main.c中的代码都存在NAND Flash地址4096开始处
  17. mov r2, #2048 @3. 复制长度= 2048(bytes)
  18. bl nand_read @调用C函数nand_read
  19. ldr sp, =0x34000000 @跳到内存中,重新设置栈
  20. ldr lr, =halt_loop @设置返回地址
  21. ldr pc, =main       @b指令和bl指令只能前后跳转32M的范围,所以这里使用向pc赋值的方法进行跳转

  22. halt_loop:
  23. b halt_loop


2.第二是init.c文件

点击(此处)折叠或打开

  1. /* WATCH DOG register */
  2. #define WTCON    (*(volatile unsigned long *)0x53000000)

  3. /* SDRAM regisers */
  4. #define MEM_CTL_BASE    0x48000000
  5.  
  6. void disable_watch_dog();
  7. void memsetup();

  8. /*上电后,WATCH DOG默认是开着的,要把它关掉 */
  9. void disable_watch_dog()
  10. {
  11.     WTCON = 0;
  12. }

  13. /* 设置控制SDRAM的13个寄存器 */
  14. void memsetup()
  15. {
  16.     int     i = 0;
  17.     unsigned long *p = (unsigned long *)MEM_CTL_BASE;

  18.     /* SDRAM 13个寄存器的值
  19.     .long 0x22011110     @BWSCON
  20.     .long 0x00000700    @BANK0
  21.     .long 0x00000700    @BANK1
  22.     .long 0x00000700    @BANK2
  23.     .long 0x00000700    @BANK3
  24.     .long 0x00000700    @BANK4
  25.     .long 0x00000700    @BANK5
  26.     .long 0x00018005    @BANK6
  27.     .long 0x00018005    @BANK7
  28.     .long 0x008c07a3    @REFRESH 刷新控制寄存器 在未使用PLL时,SDRAM是时钟频率等于晶振频率12Mhz
  29.                 @R_CNT=2^11+1-12(HCLK)*(64ms/8192)(刷新周期)=1955=0x07A3
  30.     .long 0x000000b1    @BANKSIZE寄存器
  31.     .long 0x00000030    @MRSRB6
  32.     .long 0x00000030    @MRSRB7
  33.      */
  34.     unsigned long const mem_cfg_val[]={ 0x22011110, //BWSCON
  35.                                             0x00000700, //BANKCON0
  36.                                             0x00000700, //BANKCON1
  37.                                             0x00000700, //BANKCON2
  38.                                             0x00000700, //BANKCON3
  39.                                             0x00000700, //BANKCON4
  40.                                             0x00000700, //BANKCON5
  41.                                             0x00018005, //BANKCON6
  42.                                             0x00018005, //BANKCON7
  43.                                             0x008C07A3, //REFRESH
  44.                                             0x000000B1, //BANKSIZE
  45.                                             0x00000030, //MRSRB6
  46.                                             0x00000030, //MRSRB7
  47.                                     };

  48.     for(; i < 13; i++)
  49.         p[i] = mem_cfg_val[i];
  50. }

3.最重要的nand.c

点击(此处)折叠或打开

  1. #define LARGER_NAND_PAGE
  2. #define GPACON (*(volatile unsigned long *)0x56000000)
  3. #define GPBDAT (*(volatile unsigned long *)0x56000014)

  4. #define NAND_SECTOR_SIZE     512
  5. #define NAND_BLOCK_MASK     (NAND_SECTOR_SIZE - 1)

  6. #define NAND_SECTOR_SIZE_LP     2048
  7. #define NAND_BLOCK_MASK_LP (NAND_SECTOR_SIZE_LP - 1)

  8. #define GSTATUS1     (*(volatile unsigned int *)0x560000B0)
  9. #define BUSY     (1<<2)

  10. static read_count = 0; //这个变量纯粹是用来测试用的,点亮led



  11. /* NAND FLASH (see S3C2440 manual chapter 6, www.100ask.net) */

  12. #define NFCONF    (*(volatile unsigned int *)0x4e000000) //0x48000000
  13. #define NFCONT    (*(volatile unsigned int *)0x4e000004) //0x48000004
  14. #define NFCMD        (0x4e000008) //0x48000008
  15. #define NFADDR    (0x4e00000C) //0x4800000C
  16. #define NFDATA    (0x4e000010) //0x48000010
  17. #define NFMECCD0    (*(volatile unsigned int *)0x4e000014) //0x48000014
  18. #define NFMECCD1    (*(volatile unsigned int *)0x4e000018) //0x48000018
  19. #define NFSECCD    (*(volatile unsigned int *)0x4e00001c) //0x4800001C
  20. #define NFSTAT    (0x4e000020) //0x48000020
  21. #define NFESTAT0    (*(volatile unsigned int *)0x4e000024) //0x48000024
  22. #define NFESTAT1    (*(volatile unsigned int *)0x4e000028) //0x48000028
  23. #define NFMECC0    (*(volatile unsigned int *)0x4e00002c) //0x4800002C
  24. #define NFMECC1    (*(volatile unsigned int *)0x4e000030) //0x48000030
  25. #define NFSECC    (*(volatile unsigned int *)0x4e000034) //0x48000034
  26. #define NFSBLK    (*(volatile unsigned int *)0x4e000038) //0x48000038
  27. #define NFEBLK    (*(volatile unsigned int *)0x4e00003c) //0x4800003C


  28. typedef struct {
  29.     void (*nand_reset)(void);
  30.     void (*wait_idle)(void);
  31.     void (*nand_select_chip)(void);
  32.     void (*nand_deselect_chip)(void);
  33.     void (*write_cmd)(int cmd);
  34.     void (*write_addr)(unsigned int addr);
  35.     unsigned char (*read_data)(void);
  36. }nand_chip_ops;


  37. static nand_chip_ops nand_chip;

  38. /* 供外部调用的函数 */
  39. void nand_init(void);
  40. void nand_read(unsigned char *buf, unsigned long start_addr, int size);

  41. /* NAND Flash操作的总入口, 它们将调用S3C2410或S3C2440的相应函数 */
  42. static void nand_reset(void);
  43. static void wait_idle(void);
  44. static void nand_select_chip(void);
  45. static void nand_deselect_chip(void);
  46. static void write_cmd(int cmd);
  47. static void write_addr(unsigned int addr);
  48. static unsigned char read_data(void);



  49. /* S3C2440的NAND Flash处理函数 */
  50. static void s3c2440_nand_reset(void);
  51. static void s3c2440_wait_idle(void);
  52. static void s3c2440_nand_select_chip(void);
  53. static void s3c2440_nand_deselect_chip(void);
  54. static void s3c2440_write_cmd(int cmd);
  55. static void s3c2440_write_addr(unsigned int addr);
  56. static unsigned char s3c2440_read_data(void);



  57. /* -------------------S3C2440的NAND Flash操作函数---------------------------- */



  58. /* 复位 */
  59. static void s3c2440_nand_reset(void)
  60. {
  61.     s3c2440_nand_select_chip();
  62.     s3c2440_write_cmd(0xff); // 复位命令
  63.     s3c2440_wait_idle();
  64.     s3c2440_nand_deselect_chip();
  65. }

  66. /* 发出片选信号 */
  67. static void s3c2440_nand_select_chip(void)
  68. {
  69.     int i;
  70.     NFCONT =NFCONT & (~(1<<1)); //NFCONT的1位清零,片选使能
  71.     for(i=0; i<10; i++);
  72. }

  73. /*等待就绪*/
  74. static void s3c2440_wait_idle(void)
  75. {
  76.     int i;
  77.     //对寄存器的操作,最好用volatile声明一下。有时候不明显的错误就是因为这个造成的
  78.     volatile unsigned char *p = (volatile unsigned char *)NFSTAT;
  79.     //{while(!(rNFSTAT&(1<<2)));}
  80.     while(!(*p & BUSY)) //NFSTAT的最低位为1,表明存储器就绪,为0表示忙
  81.         for(i=0; i<10; i++);
  82. }

  83. /* 取消片选信号 */
  84. static void s3c2440_nand_deselect_chip(void)
  85. {
  86.     NFCONT =NFCONT |(1<<1);
  87. }

  88. /* 发出命令 */
  89. static void s3c2440_write_cmd(int cmd)
  90. {
  91.     volatile unsigned char *p = (volatile unsigned char *)NFCMD;
  92.     *p = cmd; //强制类型转换,将int型数据转换为字符型数据,
  93. }

  94. /* 发出地址,在发地址时要弄清nandflash的页大小,手册上的写地址周期是按照4k/页的大小,这里板子上的nand页大小默认设置为2k */
  95. static void s3c2440_write_addr(unsigned int addr)
  96. {
  97.     int i;
  98.     volatile unsigned char *p = (volatile unsigned char *)NFADDR;
  99.     
  100.     //K9F2G08U0A芯片 的写地址过程分为5步,不同于1208的4步。
  101.     *p = addr & 0xFF;         //先发低八位,从0-7,
  102.     for(i=0; i<10; i++);      //延时
  103.     *p = (addr >> 8) & 0xFF;//再发从8位开始的8.9,10,11,共4位,这样把列地址发完,共12位,可寻址2^12=4096bytes
  104.     for(i=0; i<10; i++);
  105.     *p = (addr >> 11) & 0xFF;
  106.     for(i=0; i<10; i++);
  107.     *p = (addr >> 19) & 0xFF;
  108.     for(i=0; i<10; i++);
  109.     *p = (addr >> 27) & 0xff;//最后发送页地址的高2位。
  110.     for(i=0; i<10; i++);
  111. }


  112. /*2440读数据函数*/
  113. static unsigned char s3c2440_read_data(void)
  114. {
  115.     /*这里读到的是个16位数据,unsigned char 是8位的,由于读写数据时数据寄存器的
  116.         配置是按照IO口8位的宽度读写的,参照芯片手册6-5页,只有一个IO周期,且只有7:0位有效
  117.         这里进行强制转换,只取最低8位*/
  118.     unsigned char ch = *((volatile unsigned char *)NFDATA);
  119.     /*
  120.     if(read_count == 1)
  121.     GPBDAT &= ~(1<<6);
  122.     if(read_count ==2)
  123.     GPBDAT &= ~(1<<7);
  124.     */
  125.     if(read_count == 2048)
  126.     GPBDAT &= ~(1<<5); //read_data函数确实被调用了2048次。
  127.     return ch;    
  128. }



  129. /* ------------------------初始化NAND Flash------------------ */


  130. /* 在第一次使用NAND Flash前,复位一下NAND Flash */
  131. static void nand_reset(void)
  132. {
  133.     nand_chip.nand_reset();
  134. }

  135. static void wait_idle(void)
  136. {
  137.     nand_chip.wait_idle();
  138. }

  139. static void nand_select_chip(void)
  140. {
  141.     int i;
  142.     nand_chip.nand_select_chip();
  143.     for(i=0; i<10; i++);
  144. }

  145. static void nand_deselect_chip(void)
  146. {
  147.     nand_chip.nand_deselect_chip();
  148. }

  149. static void write_cmd(int cmd)
  150. {
  151.     nand_chip.write_cmd(cmd);
  152. }
  153. static void write_addr(unsigned int addr)
  154. {
  155.     nand_chip.write_addr(addr);
  156. }

  157. static unsigned char read_data(void)
  158. {
  159.     return nand_chip.read_data();
  160. }

  161. void nand_init()
  162. {

  163. //#define TACLS 0
  164. #define TACLS 1 //这里改为1,默认值也是1,WE信号延迟CLE/ALE一个时钟周期
  165. #define TWRPH0 5
  166. #define TWRPH1 0

  167.        GPACON = (GPACON &~(0x3f<<17)) | (0x3f<<17); //配置芯片引脚,为1用作NAND控制引脚
  168.         nand_chip.nand_reset = s3c2440_nand_reset;
  169.         nand_chip.wait_idle = s3c2440_wait_idle;
  170.         nand_chip.nand_select_chip = s3c2440_nand_select_chip;
  171.         nand_chip.nand_deselect_chip = s3c2440_nand_deselect_chip;
  172.         nand_chip.write_cmd = s3c2440_write_cmd;
  173.         nand_chip.write_addr = s3c2440_write_addr;
  174.         nand_chip.read_data = s3c2440_read_data;

  175.     /* 设置时序 */
  176.         NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);    //0xe=1110,设置AdvFlash2k字节,
  177.         /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
  178.         NFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)\
  179.                     |(1<<4)|(1<<1)|(1<<0);
  180.     
  181.      
  182.     /* 复位NAND Flash ,就是向nand_flash发送一个复位命令*/
  183.         nand_reset();
  184.     
  185. }
  186. /*
  187. //读函数,将nand_flash从4096地址处开始的数据拷贝到SDRAM起始地址,大小为1kb
  188. void nand_read(unsigned char *buf, unsigned long start_addr, int size)
  189. {
  190.     int i, j;
  191.    
  192. #ifdef LARGER_NAND_PAGE
  193.     if ((start_addr & NAND_BLOCK_MASK_LP) || (size & NAND_BLOCK_MASK_LP)) {
  194.         return ; //地址或长度不对齐
  195.     }
  196. #else
  197.     if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
  198.         return ; //地址或长度不对齐
  199.     }
  200. #endif    

  201.     
  202.     nand_select_chip();
  203.     for(i=start_addr; i < (start_addr + size);) {
  204.       
  205.       write_cmd(0);
  206.       
  207.       //Write Address
  208.       write_addr(i);
  209.       //在程序开头定义了LARGER_NAND_PAGE,表明该nand_flash是大页
  210. //#ifdef LARGER_NAND_PAGE
  211.       write_cmd(0x30);        
  212. //#endif
  213.       wait_idle();
  214.       //GPBDAT &= ~(1<<7); //test

  215. #ifdef LARGER_NAND_PAGE
  216.       for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++) {

  217. //#else
  218.      //for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
  219. //#endif
  220.           *buf = read_data(); //将读到的数据放到第一个参数buf指定的地址处,0x3000 0000
  221.           buf++;
  222.           //GPBDAT &= ~(1<<7);
  223.       }
  224.             //GPBDAT |= (1<<7);
  225.           //GPBDAT &= ~(1<<5);
  226.     }
  227.     //GPBDAT = 0xffff;
  228.     //GPBDAT = 0xfeff; //第八位清零,led4亮
  229.     GPBDAT &= (~1<<8);
  230.     //取消片选信号
  231.     nand_deselect_chip();
  232.    // GPBDAT |= (1<<5); //test
  233.     return ;
  234. }

  235. */
  236. /*自己的nand_read函数,相比韦大侠的,移植性差一点*/
  237. void nand_read(unsigned char *buf, unsigned long start_addr, int len)
  238. {
  239.     unsigned long i,j;
  240.     unsigned char *des_addr=buf;
  241.     nand_select_chip();
  242.     *(unsigned char *)NFSTAT = (*(unsigned char *)NFSTAT) | (1<<2);    //清除等待位
  243.     for(i=start_addr;i<(start_addr+len);)
  244.     {    //发出页读命令
  245.         write_cmd(0x00);
  246.         write_addr(i);
  247.         write_cmd(0x30);
  248.         wait_idle();
  249.         //GPBDAT &= ~(1<<8);
  250.         for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++)
  251.         {
  252.             read_count++;
  253.             *des_addr=read_data();
  254.             des_addr++;
  255.             //read_count++;
  256.         }
  257.     }
  258.     if(read_count==2048)
  259.     GPBDAT &=~(1<<6);
  260.     nand_deselect_chip();
  261.     //GPBDAT &= ~(1<<8);
  262. }

4.最后main.c

点击(此处)折叠或打开

  1. #include "s3c24xx.h"

  2. int main(void)
  3. {
  4.     unsigned long i=0;
  5.     //GPBCON = (1<<(2*5)) | (1<<(2*6)) | (1<<(2*7)) | (1<<(2*8)) ;
  6.     GPBDAT = 0xffffffff; //全部熄灭led
  7.     while(1){
  8.         for(i=1000000;i>0;i--); //delay
  9.         GPBDAT = ~(GPBDAT &(0xf<<5));    //GPBDAT的5,6,7,8进行位翻转,其余位不变
  10.     }
  11.     
  12.     return 0;
  13. }

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