新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > ARM開(kāi)發(fā)步步深入之NandFlash 4KB突圍

ARM開(kāi)發(fā)步步深入之NandFlash 4KB突圍

作者: 時(shí)間:2016-12-07 來(lái)源:網(wǎng)絡(luò) 收藏

  實(shí)驗(yàn)?zāi)康模和黄?KB的Steppingstone存儲(chǔ)空間限制,讀取NandFlash中4KB后的代碼實(shí)現(xiàn)“點(diǎn)燈大法”,借此掌握NandFlash的操作。

本文引用地址:http://2s4d.com/article/201612/341245.htm

  實(shí)驗(yàn)環(huán)境及說(shuō)明:恒頤S3C2410開(kāi)發(fā)板H2410。H2410核心板的NandFlash選用的是三星片上(SOP)K9F1208U0M,該NandFlash容量為64MB。

  實(shí)驗(yàn)思路:開(kāi)發(fā)板上電啟動(dòng)后,自動(dòng)將NandFlash開(kāi)始的4K數(shù)據(jù)復(fù)制到SRAM中,然后跳轉(zhuǎn)到0地址開(kāi)始執(zhí)行。然后初始化存儲(chǔ)控制器SDRAM,調(diào)用NandFlash讀函數(shù)操作把4KB后的點(diǎn)燈代碼復(fù)制到SDRAM中,跳到點(diǎn)燈代碼的入口點(diǎn)實(shí)現(xiàn)點(diǎn)燈操作。

  知識(shí)掌握:NandFlash內(nèi)部結(jié)構(gòu)、命令字及存儲(chǔ)控制器

  一、NandFlash內(nèi)部結(jié)構(gòu)

  不同開(kāi)發(fā)板使用的NandFlash的型號(hào)可能不一樣,本文只是以K9F1208U0M為例做個(gè)簡(jiǎn)單介紹。引腳描述如下所示:

  '700')this.width='700';if(this.offsetHeight>'700')this.height='700';" src="http://www.arm79.com/attachment/Mon_1005/73_67_af4843899d603e0.jpg" onclick="if(this.width>=700) window.open('http://www.arm79.com/attachment/Mon_1005/73_67_af4843899d603e0.jpg');" border="0">

  NandFlash存儲(chǔ)單元結(jié)構(gòu)圖如下所示:

  '700')this.width='700';if(this.offsetHeight>'700')this.height='700';" src="http://www.arm79.com/attachment/Mon_1005/73_67_b53cf1b5e09813b.jpg" onclick="if(this.width>=700) window.open('http://www.arm79.com/attachment/Mon_1005/73_67_b53cf1b5e09813b.jpg');" border="0" width="700">

  Device、 Block和Page之間的關(guān)系---1 Device = 4,096 Blocks = 4096*32 Pages = 128K Pages;1 Block = 32 Page;1 Page = 528 Byte = 512 Byte + 16 Byte。其中1 Page中包含有數(shù)據(jù)寄存器512 Byte和16 Byte的備用位用于ECC校驗(yàn)存儲(chǔ)。所以有528 columns * 128K rows(Pages)。1 Page中的512 Byte的數(shù)據(jù)寄存器又分為兩個(gè)部分1st 256 Bytes和 2nd 256 Bytes。用于數(shù)據(jù)存儲(chǔ)的單元有 512 Bytes * 32 Pages * 4096 Blocks = 64 MB,用于ECC校驗(yàn)單元有16 Bytes * 32 Pages * 4096 Blocks = 2MB 。

  二、NandFlash命令字

  操作NandFlash時(shí),先傳輸命令,然后傳輸?shù)刂?,最后進(jìn)行數(shù)據(jù)的讀/寫(xiě)。K9F1208U0M的命令字如下所示:

  '700')this.width='700';if(this.offsetHeight>'700')this.height='700';" src="http://www.arm79.com/attachment/Mon_1005/73_67_9f90461920e6b01.jpg" onclick="if(this.width>=700) window.open('http://www.arm79.com/attachment/Mon_1005/73_67_9f90461920e6b01.jpg');" border="0" width="700">

  由于尋址需要26bit的地址,該26bit地址通過(guò)四個(gè)周期發(fā)送到NandFlash,如下圖所示:

  '700')this.width='700';if(this.offsetHeight>'700')this.height='700';" src="http://www.arm79.com/attachment/Mon_1005/73_67_e8c052eed36f8b9.jpg" onclick="if(this.width>=700) window.open('http://www.arm79.com/attachment/Mon_1005/73_67_e8c052eed36f8b9.jpg');" border="0">

  Read 1操作:該操作是對(duì)512 Bytes * 32 Pages * 4096 Blocks = 64 M的數(shù)據(jù)寄存器進(jìn)行尋址。第一個(gè)周期發(fā)送A7~A0的8bit Column地址,8bit的尋址范圍是0~255,只能對(duì)1st 256 Bytes部分進(jìn)行尋址。00h命令是1st 256 Bytes部分尋址。當(dāng)發(fā)送01h命令時(shí),A8將會(huì)被置1,此時(shí)尋址范圍變成了256~511了,所以01h命令是對(duì)2nd 256 Bytes部分進(jìn)行尋址。(*注意:A8在發(fā)送00h命令后被清0,在發(fā)送01h命令后被置1,并且在發(fā)送01h對(duì)2nd尋址完畢后,A8會(huì)自動(dòng)清0,指 針會(huì)自動(dòng)地指向1st);第二個(gè)周期的A9~A13的5bit是對(duì)Page進(jìn)行尋址(因?yàn)? Block = 32 Pages,5bit的尋址范圍是0~31,可以對(duì)1 Block里面的所有Page進(jìn)行尋址)。A14~A25的12bit則是對(duì)Block進(jìn)行尋址,12bit的尋址范圍是0~4095,對(duì)整個(gè) Device的4096個(gè)Blocks進(jìn)行尋址。Read 2操作:該操作是對(duì)16 Bytes * 32 Pages * 4096 Blocks =2MB的備用位(ECC)進(jìn)行尋址。50h命令為Read2操作,對(duì)1 Page里面的后16 Byte尋址。這樣,通過(guò)四個(gè)周期的發(fā)送即可對(duì)整個(gè)Device的所有存儲(chǔ)單元進(jìn)行尋址。

  三、NandFlash存儲(chǔ)控制器

  S3C2410 為簡(jiǎn)化對(duì)NandFlash的操作,提供了一組NandFlash控制器來(lái)實(shí)現(xiàn)對(duì)K9F1208U0M命令字的操作,主要有配置寄存器NFCONF、控制 寄存器NFCONT、命令寄存器NFCMD、地址寄存器NFADDR、數(shù)據(jù)寄存器NFDATA和狀態(tài)寄存器NFSTAT。

  ★NFCONF被用來(lái)使 能/禁止NandFlash控制器、使能/禁止控制引腳信號(hào)nFCE、初始化ECC、設(shè)置NandFlash的時(shí)序參數(shù)。TACLS、TWRPH0、 TWRPH1---這三個(gè)參數(shù)控制著NandFlash信號(hào)線CLE/ALE與寫(xiě)控制信號(hào)new的時(shí)序關(guān)系。根據(jù)NandFlash的Datasheet 中對(duì)其最小讀/寫(xiě)/控制時(shí)間的要求,聯(lián)系HCLK實(shí)際取值一般為100MHz,可以設(shè)這三個(gè)參數(shù)分別為1:3:1個(gè)HCLK即可(貌似ViVi中是 1:3:1),這樣可以滿(mǎn)足其時(shí)序要求。

  ★NandFlash狀態(tài)寄存器NFSTAT。只用到最低位[0],0:busy;1:ready。

  NandFlash 存儲(chǔ)控制器根據(jù)OM[1:0]位的取值可以工作在①自動(dòng)啟動(dòng)模式---OM[1:0]=00時(shí),復(fù)位之后,NandFlash的最先4KB的代碼被復(fù)制到 Steppingstone中即內(nèi)部4KB的SRAM。Steppingstone被映射為Bank0(nGS0),且CPU在此4KB內(nèi)部SRAM中開(kāi) 始執(zhí)行啟動(dòng)代碼;②NandFlash模式。

  示例代碼解析:

  ★head.S頭文件來(lái)設(shè)置SDRAM,設(shè)置SDRAM,將第二部分代碼復(fù)制到SDRAM,然后跳到SDRAM繼續(xù)執(zhí)行。

  .equ MEM_CTL_BASE, 0x48000000

  .text

  .global _start

  _start:

  bl disable_watch_dog @關(guān)門(mén)喂狗

  bl mem_control_setup @設(shè)置存儲(chǔ)控制器

  ldr sp, =4096 @設(shè)置棧指針,以下C函數(shù)調(diào)用前需要設(shè)好棧

  bl nand_init @初始化NandFlash

  @將NandFlash中地址4096開(kāi)始的1024字節(jié)代碼(led.c編譯得到)復(fù)制到SDRAM中

  ldr r0, =0x30000000 @目標(biāo)地址=0x30000000,SDRAM起始地址

  mov r1, #4096 @源地址=4096,連接的時(shí)候led代碼在4096開(kāi)始處

  mov r2, #1024 @復(fù)制長(zhǎng)度=1024,對(duì)于本實(shí)驗(yàn)的led足夠

  bl nand_read @調(diào)用C函數(shù)nand_read

  ldr lr, =halt_loop @設(shè)置返回地址

  ldr sp, =0x34000000 @重新設(shè)置棧

  ldr pc, =main @使用向pc賦值的方法進(jìn)行跳轉(zhuǎn)到點(diǎn)燈代碼

  halt_loop:

  b halt_loop

  ★nand.c文件實(shí)現(xiàn)NandFlash的初始化和數(shù)據(jù)讀取

  #define BUSY 1

  typedef unsigned long S3C2410_REG32; //貌似此處定義為unsigned int反匯編結(jié)果一樣的,也沒(méi)問(wèn)題。猜可能是指令直接按32位存儲(chǔ)了吧,知道的可以和我說(shuō)一下!

  /* NandFlash結(jié)構(gòu)體 */

  typedef struct {

  S3C2410_REG32 NFCONF;

  ......

  S3C2410_REG32 NFECC;

  }S3C2410_NAND;

  static S3C2410_NAND * s3c2410nand = (S3C2410_NAND *)0x4e000000;

  /* 供外部調(diào)用的函數(shù)聲明 */

  void nand_init(void);

  void nand_read(unsigned char *buf, unsigned long start_addr, int size);

  /* S3C2410的NandFlash處理函數(shù)聲明 */

  static void s3c2410_nand_reset(void);

  ......

  static unsigned char s3c2410_read_data();

  /* S3C2410的NandFlash操作函數(shù)實(shí)現(xiàn) */

  /* 復(fù)位 */

  static void s3c2410_nand_reset(void)

  {

  s3c2410_nand_select_chip();

  s3c2410_write_cmd(0xff); //發(fā)命令字0xFF實(shí)現(xiàn)復(fù)位操作復(fù)位

  s3c2410_wait_idle();

  s3c2410_nand_deselect_chip();

  }

  /* 等待NandFlash就緒 */

  static void s3c2410_wait_idle(void)

  {

  int i;

  volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFSTAT;

  while(!(*p & BUSY))

  for(i=0; i<10; i++);

  }

  /* 發(fā)出片選信號(hào) */

  static void s3c2410_nand_select_chip(void)

  {

  int i;

  s3c2410nand->NFCONF &= ~(1<<11); //對(duì)NFCONF的11位寫(xiě)0,激活NandFlash

  for(i=0; i<10; i++);

  }

  /* 取消片選信號(hào) */

  static void s3c2410_nand_deselect_chip(void)

  {

  s3c2410nand->NFCONF |= (1<<11); //對(duì)NFCONF的11位寫(xiě)1,使NandFlash不活動(dòng)

  }

  /* 發(fā)出命令 */

  static void s3c2410_write_cmd(int cmd)

  {

  volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFCMD;

  *p = cmd;

  }

  /* 發(fā)出地址 */

  static void s3c2410_write_addr(unsigned int addr)

  {

  int i;

  volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFADDR;

  *p = addr & 0xff;

  for(i=0; i<10; i++);

  *p = (addr >> 9) & 0xff;

  for(i=0; i<10; i++);

  *p = (addr >> 17) & 0xff;

  for(i=0; i<10; i++);

  *p = (addr >> 25) & 0xff;

  for(i=0; i<10; i++);

  }

  /* 讀取數(shù)據(jù) */

  static unsigned char s3c2410_read_data(void)

  {

  volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFDATA;

  return *p;

  }

  //設(shè)置TACLS、TWRPH0、TWRPH1三者的值,貌似ViVi等代碼中TWRPH0設(shè)為3,不知這樣的好處,知道的可以告訴我!

  #define TACLS 0

  #define TWRPH0 2

  #define TWRPH1 0

  /* 初始化NandFlash */

  void nand_init(void)

  {

  /* 使能NandFlash控制器, 初始化ECC, 禁止片選, 設(shè)置時(shí)序 */

  s3c2410nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);

  /* 復(fù)位s3c2410 NandFlash */

  s3c2410_nand_reset();

  }

  #define NAND_SECTOR_SIZE 512

  #define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)

  /* 讀函數(shù) */

  void nand_read(unsigned char *buf, unsigned long start_addr, int size)

  {

  int i, j;

  if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {

  return ; /* 地址或長(zhǎng)度不對(duì)齊 */

  }

  /* 選中芯片 */

  s3c2410_nand_select_chip();

  for(i=start_addr; i < (start_addr + size);) {

  /* 發(fā)出READ0命令 */

  s3c2410_write_cmd(0);

  /* 寫(xiě)地址*/

  s3c2410_write_addr(i);

  /*等待*/

  s3c2410_wait_idle();

  for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {

  *buf = s3c2410_read_data();

  buf++;

  }

  }

  /* 取消片選信號(hào) */

  s3c2410_nand_deselect_chip();

  return ;

  };



關(guān)鍵詞: ARM NandFlash

評(píng)論


相關(guān)推薦

技術(shù)專(zhuān)區(qū)

關(guān)閉