zoukankan      html  css  js  c++  java
  • LCD实验学习笔记(七):NAND FLASH

    s3c2440 CPU内置NAND FLASH控制器。相关寄存大器起始地址为0x4e000000。

    通过设置NFCONF寄存器,设置NAND FLASH 时序。

    通过设置NFCONT寄存器,使能NAND FLASH、初始化ECC等。

    代码:


    #define GSTATUS1 (*(volatile unsigned int *)0x560000B0) //读此寄存器可以知道CPU芯片型号
    #define BUSY 1

    #define NAND_SECTOR_SIZE_LP 2048 //大页每页2048字节
    #define NAND_BLOCK_MASK_LP (NAND_SECTOR_SIZE_LP - 1) //大页掩码???

    typedef unsigned int S3C24X0_REG32;

    //s3c2440 NAND FLASH相关寄存器
    typedef struct {
      S3C24X0_REG32 NFCONF;
      S3C24X0_REG32 NFCONT;
      S3C24X0_REG32 NFCMD;
      S3C24X0_REG32 NFADDR;
      S3C24X0_REG32 NFDATA;
      S3C24X0_REG32 NFMECCD0;
      S3C24X0_REG32 NFMECCD1;
      S3C24X0_REG32 NFSECCD;
      S3C24X0_REG32 NFSTAT;
      S3C24X0_REG32 NFESTAT0;
      S3C24X0_REG32 NFESTAT1;
      S3C24X0_REG32 NFMECC0;
      S3C24X0_REG32 NFMECC1;
      S3C24X0_REG32 NFSECC;
      S3C24X0_REG32 NFSBLK;
      S3C24X0_REG32 NFEBLK;
    } S3C2440_NAND;

    static S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;//s3c2440 Nand flash 相关寄存器起始地址

    //供外部调用的函数声明
    void nand_init(void); //初始化
    void nand_read(unsigned char *buf, unsigned long start_addr, int size);//读取数据到缓冲区

    /* S3C2440的NAND Flash处理函数 */
    static void s3c2440_nand_reset(void);
    static void s3c2440_wait_idle(void);
    static void s3c2440_nand_select_chip(void);
    static void s3c2440_nand_deselect_chip(void);
    static void s3c2440_write_cmd(int cmd);
    static void s3c2440_write_addr_lp(unsigned int addr);
    static unsigned char s3c2440_read_data(void);

    //复位
    static void s3c2440_nand_reset(void)
    {
      s3c2440_nand_select_chip();//选片选
      s3c2440_write_cmd(0xff); //复位命令
      s3c2440_wait_idle(); //等待就绪
      s3c2440_nand_deselect_chip(); //取消片选
    }

    //等待就绪信号
    static void s3c2440_wait_idle(void)
    {
      int i;
      volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;
      //最后一位为1表示忙,忙就一直等
      while (!(*p & BUSY))
      for (i = 0; i < 10; i++);
    }

    //片选
    static void s3c2440_nand_select_chip()
    {
      s3c2440nand->NFCONT &= ~(1 << 1); //NFCONT寄存器[1]位Reg_nCE置0
      int i ;
      for (i = 0; i < 10; i++); //等待片选?
    }


    //取消片选
    static void s3c2440_nand_deselect_chip()
    {
      s3c2440nand->NFCONT |=(1<<1); //NFCONT寄存器[1]位Reg_nCE置1
    }

    //发送命令
    static void s3c2440_write_cmd(int cmd)
    {
      volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD; //p指向NFCMD寄存器
      *p = cmd; //命令写入命令寄存器
    }

    //发送地址
    static void s3c2440_write_addr_lp(unsigned int addr)
    {
      int i;
      volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;
      int col, page;
      col = addr & NAND_BLOCK_MASK_LP; //得到页内地址。 每页2K,页内地址为bit[0-10]
      page = addr / NAND_SECTOR_SIZE_LP; //得到页号。256M为2的28次方,地址总位数为27,即bit[11-27]为页号,共17位
      *p = col & 0xff; //地址后8位 ,A0-A7;
      for (i = 0; i < 10; i++);
      *p = (col >> 8) & 0x0f; //A8-A10
      for (i = 0; i < 10; i++);
      *p = page & 0xff; //页号后后位 A11-A18
      for (i = 0; i < 10; i++);
      *p = (page >> 8) & 0xff;//A19-A26
      for (i = 0; i < 10; i++);
      *p = (page >> 16) & 0x1; //A27
      for (i = 0; i < 10; i++);}

    //读数据
    static unsigned char s3c2440_read_data(void)
    {
      volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA;
      return *p;
    }


    //初始化Nand Flash
    void nand_init(void)
    {
      //设置时序
      //这里假设cpu频率100MHz,即一个时钟周期为10ns
      #define TACLS 0
      #define TWRPH0 3 //nand flash手册 twp最低要求12ns,即2个时钟周期以上,所以这里可以取1的,3可以保证400MHz时可用
      #define TWRPH1 0 //nand flash手册 tCLH最低要求5ns,取值0要求CPU频200Mhz以下
      s3c2440nand->NFCONF = (TACLS << 12) | (TWRPH0 << 8) | (TWRPH1 << 4);
      //使能Nand Flash,禁止片选,初始化ECC
      s3c2440nand->NFCONT = (1 << 4) | (1 << 1) | (1 << 0);
      s3c2440_nand_reset(); //复位
    }

    //读数据
    void nand_read(unsigned char *buf, unsigned long start_addr, int size)
    {
      //Nand Flash的读取单位最小是page,长度必须是page的整数倍。所以必须对齐
      if ((start_addr & NAND_BLOCK_MASK_LP)||(size & NAND_BLOCK_MASK_LP))
      {
        return;
      }
      s3c2440_nand_select_chip();//发出片选信号

      int i, j;
      for (i = start_addr; i < (start_addr+size);)
      {
        s3c2440_write_cmd(0); //发出READ0命令
        s3c2440_write_addr_lp(i);
        s3c2440_write_cmd(0x30);
        s3c2440_wait_idle();
        //读取页数据
        for ( j = 0; j <NAND_SECTOR_SIZE_LP;j++,i++)
        {
          *buf = s3c2440_read_data();
          buf++;
        }

      }

      s3c2440_nand_deselect_chip();//取消片选
    }


  • 相关阅读:
    基于注解的IOC配置
    字符串典型问题分析
    指针与数组
    数组的本质
    数组与指针分析
    指针的本质
    #与##操作符使用
    #pragma使用分析
    #error和#line使用分析
    条件编译使用
  • 原文地址:https://www.cnblogs.com/sekon/p/6443402.html
Copyright © 2011-2022 走看看