ARM新一期第七天

  1. Nandflash 操作原理
    在这里插入图片描述
    ①原理图上nand 和 cpu之间只有数据线,怎么传输地址?
    在DATA0-DATA7上既传输数据,又传输地址,当ALE为高电平传输的是地址
    ②要操作NAND要发出命令,命令怎么传入?
    ALE为高电平传输的是地址
    CLE为高电平传输的是命令
    ALE和CLE都为低电平传输的数据
    ③数据线既接到NAND 也接到NOR,还会接到DM9000,那怎么避免干扰
    这些设备,要想访问必须要线选中,片选信号
    ④假设烧写NAND ,把命令,数据和地址都发给它,NAND 肯定不会一瞬间完 成,怎么判断烧写完成
    通过状态引脚RnB来判断,:高电平表示完成,低电平表示正忙
    ⑤怎么操作NAND 呢?
    一般就是发出命令,发出地址,发出数据/读出数据
    在这里插入图片描述
    读ID时序
    在这里插入图片描述
    cpu nand控制器寄存器
    在这里插入图片描述
    在这里插入图片描述
    uboot操作NAND
    在这里插入图片描述
    为什么是五个周期的地址呢,因为nand 是256M的,2的28次方,也就是需要28bit数据来表示,那就是4byte数据,为了兼容更大的nand,所以用了五个周期的地址。

2.cpu,nand时序图和代码实现
在这里插入图片描述

实现读ID代码:

void nand_init(void)
{
#define  TACLS   0
#define  TWRPH0  1
#define  TWRPH1  0

 /*设置NAND FLASH的时序*/
 NFCONF = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);
 
 /*使能NAND FLASH控制器,初始化ECC,禁止片选*/
 NFCONT = (1<<4) | (1<<1) | (1<<0);
}

void nand_select(void)
{
 /*使能片选*/
 NFCONT &=~(1<<1);
}

void nand_deselect(void)
{
 /*禁止片选*/
 NFCONT |= (1<<1);
}

void nand_cmd(unsigned char cmd)
{
 volatile int i;
 NFCCMD = cmd;
 for(i=0; i<10; i++);/*延时使得信号更加稳定*/
}

void nand_addr_byte(unsigned char addr)
{
 volatile int i;
 NFADDR = addr;
 for(i=0; i<10; i++);
}

unsigned char nand_data(void)
{
 return NFDATA;
}

void nand_chip_id(void)
{ 
 unsigned char buf[5]={0}; 
 
 nand_select(); 
 nand_cmd(0x90);
 nand_addr_byte(0x00);
 
 buf[0] = nand_data();
 buf[1] = nand_data(); 
 buf[2] = nand_data();
 buf[3] = nand_data();
 buf[4] = nand_data(); 
 
 nand_deselect();  
 
 printf("maker   id  = 0x%x\n\r",buf[0]);
 printf("device  id  = 0x%x\n\r",buf[1]); 
 printf("3rd byte    = 0x%x\n\r",buf[2]);  
 printf("4th byte    = 0x%x\n\r",buf[3]);   
 printf("page  size  = %d kb\n\r",1  <<  (buf[3] & 0x03)); 
 printf("block size  = %d kb\n\r",64 << ((buf[3] >> 4) & 0x03)); 
 printf("5th byte    = 0x%x\n\r",buf[4]); 
 
}

3.nand read operation
在这里插入图片描述

在这里插入图片描述

NAND READ 实现:

void nand_read(unsigned int addr, unsigned char *buf, unsigned int len)
{
 int i = 0;
 int page = addr / 2048;
 int col  = addr & (2048 - 1); 
 
 nand_select(); 
 
 while (i < len)
 {
  /* 发出00h命令 */
  nand_cmd(00);
  
  /* 发出地址 */
  /* col addr */
  nand_addr_byte(col & 0xff);
  nand_addr_byte((col>>8) & 0xff);
  
  /* row/page addr */
  nand_addr_byte(page & 0xff);
  nand_addr_byte((page>>8) & 0xff);
  nand_addr_byte((page>>16) & 0xff);
  
  /* 发出30h命令 */
  nand_cmd(0x30);
  
  /* 等待就绪 */
  wait_ready();
  
  /* 读数据 */
  for (; (col < 2048) && (i < len); col++)
  {
   buf[i++] = nand_data();   
  }
  if (i == len)
   break;
  col = 0;
  page++;
 } 
 nand_deselect();  
}

更改代码支持NAND启动:

void copy2sdram(void)
{
 /* 要从lds文件中获得 __code_start, __bss_start
  * 然后从0地址把数据复制到__code_start
  */
 extern int __code_start, __bss_start;
 
 volatile unsigned int *dest = (volatile unsigned int *)&__code_start;
 volatile unsigned int *end = (volatile unsigned int *)&__bss_start;
 volatile unsigned int *src = (volatile unsigned int *)0;
 
 int len;
 len = ((int)&__bss_start) - ((int)&__code_start);
 
 if (isBootFromNorFlash())
 {
  while (dest < end)
  {
   *dest++ = *src++;
  }
 }
 else
 {
  nand_init();
  nand_read(src, dest, len);?//如果len大于4k怎么办
 }
 
}
int isBootFromNorFlash(void)
{
 volatile unsigned int *p = (volatile unsigned int *)0;
 unsigned int val = *p;
 
 *p = 0x12345678;
 if (*p == 0x12345678)
 {
  /* 写成功, 对应nand启动 */
  *p = val;
  return 0;
 }
 else
 {
  return 1;
 }
}

NAND ERASE 和NAND WRITE
在这里插入图片描述code erase实现:

/*以块为单位进行擦除*/
int nand_erase(unsigned int addr, unsigned int len)
{
 int page = addr / 2048;
 
 if (addr & (0x1FFFF))
 {
  printf("nand_erase err, addr is not block align\n\r");
  return -1;
 } 
 if (len & (0x1FFFF))
 {
  printf("nand_erase err, len is not block align\n\r");
  return -1;
 } 
 nand_select(); 
 while (1)
 {
  page = addr / 2048;  
  nand_cmd(0x60);  
  
  /* row/page addr */
  nand_addr_byte(page & 0xff);
  nand_addr_byte((page>>8) & 0xff);
  nand_addr_byte((page>>16) & 0xff);
  nand_cmd(0xD0);
  wait_ready();
  
  len -= (128*1024);
  if (len == 0)
   break;
  addr += (128*1024);
 } 
 nand_deselect();  
 return 0;
}

code write 实现:

void nand_write(unsigned int addr, unsigned char *buf, unsigned int len)
{
 int page = addr / 2048;
 int col  = addr & (2048 - 1);
 int i = 0;
 
 nand_select(); 
 
 while (1)
 {
  nand_cmd(0x80);
  
  /* 发出地址 */
  /* col addr */
  nand_addr_byte(col & 0xff);
  nand_addr_byte((col>>8) & 0xff); 
   
  /* row/page addr */
  nand_addr_byte(page & 0xff);
  nand_addr_byte((page>>8) & 0xff);
  nand_addr_byte((page>>16) & 0xff);
  
  /* 发出数据 */
  for (; (col < 2048) && (i < len); )
  {
   nand_w_data(buf[i++]);
  }
  
  nand_cmd(0x10);
  wait_ready();
  
  if (i == len)
   break;
  else
  {
   /* 开始下一个循环page */
   col = 0;
   page++;
  }  
 } 
 
 nand_deselect();  
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值