加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

nand flash

发布时间:2020-12-15 18:45:22 所属栏目:百科 来源:网络整理
导读:1.Nand??flash以page为单位进行读写,以block为单位进行擦除,没页分为main区和spare区,main区用于存放正常的数据,spare区用于存放一些附加信息 2.S3c2440?支持从Nand?启动是因为内部有一个叫做Steppingstone的SRAM buffer,当启动的时候,nand?的前4k的

1.Nand??flash以page为单位进行读写,以block为单位进行擦除,没页分为main区和spare区,main区用于存放正常的数据,spare区用于存放一些附加信息

2.S3c2440?支持从Nand?启动是因为内部有一个叫做Steppingstone的SRAM buffer,当启动的时候,nand?的前4k的将会代码将被拷贝到steppingstone中执行,注意前4k代码是不会经过ECC校验的,所以必须确保这些代码的准确

3.nand的操作都是通过使用命令来实现,有的操作只要一个命令就可以完成,而有的需要两个命令才能完成,下面是K9F1G08U0B的命令表:

??

?

4.关于TACLS,TWRPH0,TWRH1几个参数的数值问题:

从下面的时序图不难看出这几个参数的意思,在此就不赘述。

?

???????????????????????????????????????????????????????? ????图1 (s3c2440)

????????????????????????????????????????????????????????????????????????????????????????2(K9F1G08U0B)

比较上面两个时序图,我们发现,TWRPH0?即为K9F1G08U0B?中的twp,?TWRH1?为tCLH

TACLS为tcls – twp,K9F1G08U0B的手册给出了这些参数的最小时间,如图

?

?

都是以ns为单位的。Nand flash?控制器使用的是HCLK?,此时为100MHZ。一个周期为10ns。给本例中我们设置:TACLS为1,TWRPH0为2,TWRH1为0;只要注意设置大于上面的最小值就ok了。

?

6.ECC校验编程:由于使用软件的方法进行ECC校验比较复杂,S3C2440中自带了硬件产生ECC校验,可以通过NFCONT的[5]和[6]位来分别开启硬件ECC产生器,如果是8bit的nand flash接口将产生4个字节的main?区?ECC??校验码和2个字节的spare区?校验码,分别存在NFMECCD和NFSECCD中,当然前提是开启了对应区的ECC发生器。具体可以参考2440的手册P220.下面是编程ECC的过程:

(1)写NFCONT[4]为1初始化ECC?编解码器,写NFCONT[5]为0解锁main区ECC发生器

(2)当读写玩数据时写NFCONT[5]为1来锁定ECC防止被改变

(3)通常用户会将main区产生的ECC校验码写到spare区,这些数据和NFMECC0/1中的数据是相同的。本例中我们约定每一页的spare区的第0个地址到第3个地址存储main区ECC,第4个地址和第5个地址存储spare区ECC

(4)硬件自动产生的ECC会自动保存在NFMECC中,而NFMECCD0/1中的数据需要用户自己写入,当放入数据后,系统会自动比较NFMECC0/1和NFMECCD0/1的内容,这样就实现了ECC码的校验

(5)?最后我们就可以通过读取NFESTAT0/1(因为K9F1G08U0B是8位IO口,因此这里只用到了NFESTAT0)中的低4位来判断读取的数据是否正确,其中第0位和第1位为main区指示错误,第2位和第3位为spare区指示错误

下面是核心代码:

  1. #include?"def.h"??
  2. #include?"2440addr.h"??
  3. #include?"mynand.h"???
  4. ??
  5. //define?command??
  6. #define?CMD_READ1?0x00???//页读命令1??
  7. #define?CMD_READ2?0x30???//页读命令2??
  8. #define?CMD_READID?0x90???//读取ID??
  9. #define?CMD_RESET?0xff????//复位??
  10. #define?CMD_WRITE1?0x80???//页写命令1??
  11. #define?CMD_WRITE2?0x10???//页写命令2??
  12. #define?CMD_ERASE1?0x60???//块擦除命令1??
  13. #define?CMD_ERASE2?0xd0???//块擦除命令2??
  14. #define?CMD_STATUS?0x70???//读取状态命令??
  15. #define?CMD_RANDOMREAD1?0X05??//随机读取命令1??
  16. #define?CMD_RANDOMREAD2?0xe0???//随机读取命令2??
  17. #define?CMD_RANDOMWRITE??0x85???//随机写命令??
  18. ?
  19. #define?NF_CE_L()????{rNFCONT?&=~(1<<1);}???//使能片选??
  20. #define?NF_CE_H()?????{rNFCONT?|=(1<<1);}???//关闭片选??
  21. #define?NF_MECC_UnLock()????{rNFCONT&=~(1<<5);}???//解锁main去ECC??
  22. #define?NF_MECC_Lock()??????{rNFCONT|=(1<<5);}????//锁定main去ECC??
  23. #define?NF_SECC_UnLock()???{rNFCONT?&=?~(1<<6);?}???//解锁spare区ECC??
  24. #define?NF_SECC_Lock()?????{rNFCONT?|=?(1<<6);?}????//锁定spare区ECC??
  25. #define?NF_RSTECC()????????{rNFCONT?|=?(1<<4);?}????????//复位ECC??
  26. ?
  27. ?
  28. ?
  29. #define?NF_WAITRB()??{while(!(rNFSTAT?&(1<<0)))?;}???//等待nand?flash?空闲??
  30. #define?NF_CLEAR_RB()???????????{rNFSTAT?|=?(1<<2);?}???//清除RnB信号??
  31. #define?NF_DETECT_RB()??????{while(!(rNFSTAT&(1<<2)));}????
  32. ?
  33. #define?NF_RDDATA8()????????((*(volatile?unsigned?char*)0x4E000010)?)?????????????
  34. #define?NF_CMD(cmd)???{rNFCMD?=?(cmd);}??//命令??
  35. #define?NF_ADDR(?addr)??{rNFADDR?=?(addr);}??//地址??
  36. #define?NF_RDDATA()?????(rNFDATA)????//读取32位数据?????
  37. //#define?NF_RDDATA8()?????(rNFDATA)????//读取8位数据????
  38. #define?NF_WRDATA(data)??{?rNFDATA?=?(data);}??//写32位数据??
  39. #define?NF_WRDATA8(data)??{?rNFDATA8?=?(data);}??//写8位数据??
  40. ?
  41. #define?TACLS??1??
  42. #define?TWRPH0?2??
  43. #define?TWRPH1?0???
  44. ??
  45. extern?void?Delay(int?time); ??
  46. void?nand_init(void) ??
  47. { ??
  48. ????rGPACON?=?rGPACON?&?(~(0x3f<<17))?|(0x3f<<17)?; ??
  49. ????rNFCONF?=?(TACLS<<12)?|(TWRPH0<<8)?|(TWRPH1<<4)?|(0<<0)?; ??
  50. ????//非锁定,屏蔽nandflash中断,初始化ECC及锁定main区和spare区ECC,使能nandflash片选及控制器???
  51. ????rNFCONT?=?(0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0); ??
  52. ??
  53. ??
  54. } ??
  55. ??
  56. //复位nand???
  57. ?void?nand_reset() ??
  58. { ??
  59. ????int?i; ??
  60. ????NF_CE_L();??//cs???
  61. ????NF_CLEAR_RB();??????????????????????//清除RnB信号???
  62. ????for(i=0;i<10;i++)??; ??
  63. ????NF_CMD(CMD_RESET);???????????//写入复位命令???
  64. ????NF_DETECT_RB();????????????????????//等待RnB信号变高,即不忙???
  65. ????NF_CE_H();???????????????????????????????//关闭nandflash片选???
  66. ??
  67. } ??
  68. ??
  69. ??
  70. //读取nand的id号,首先需要写入读ID命令,然后再写入0x00地址,就可以读取到一共五个周期的芯片ID,第一个周期为厂商ID,第二个周期为设备ID,???
  71. //第三个周期至第五个周期包括了一些具体的该芯片信息???
  72. ?U8?read_id(void) ??
  73. { ??
  74. ????int?i; ??
  75. ????U8?first,?second,?third,?forth,?fifth;??//分别读取1---5个周期的数据???
  76. ????NF_CE_L();??//cs???
  77. ????//NF_CLEAR_RB();??????????????????????//清除RnB信号???
  78. ???//?for(i=0;i<10;i++)??;???
  79. ????NF_CMD(CMD_READID);?????????//读ID命令???
  80. ????NF_ADDR(0x0);????????????????????????//写0x00地址???
  81. ???? ??
  82. ????first?=?NF_RDDATA8()??;??//厂商ID:????0Xec???
  83. ????second?=?NF_RDDATA8()??;?//设备ID,一般从这个参数可以判断出nand的一些参数???
  84. ????third?=?NF_RDDATA8()??;?//0x00???
  85. ????forth?=?NF_RDDATA8()??;?//0x95???
  86. ????fifth?=?NF_RDDATA8()??;?//?0x40???
  87. ???? ??
  88. ????NF_CE_H();???????????????????????????????//关闭nandflash片选???
  89. ????return?second; ??
  90. } ??
  91. ??
  92. //带硬件ECC校验的读,page_numer为页号,每页2K???
  93. U8?nand_readpage_ecc(U32?page_number,?U8?*buffer) ??
  94. { ??
  95. ????int?i; ??
  96. ????U32?mainecc0,?spareecc;??//用于存放ecc的临时值???
  97. ????NF_RSTECC();???????????????????//复位ECC???
  98. ????NF_MECC_UnLock()??????????????//解锁主区ECC???
  99. ????NF_CE_L();??//清除RnB信号???
  100. ????NF_CMD(CMD_READ1);???????????//页读命令周期1???
  101. ????//写入地址,首先写入列地址(也即相对每一个页开始的地址),再写入行地址(也即页号)???
  102. ????NF_ADDR(0x00);???????//列地址A0~A7,这里直接从每页的开始读可以使用下面被注释的4行代码优化???
  103. ????NF_ADDR(0x00);????//列地址A8~A11???
  104. ????? ??
  105. ????//?page?=?page_number/4;???
  106. ????//?data_addr?=?512?*(page_number%4);???
  107. ????//?NF_ADDR(data_addr&0xff);???
  108. ????//?NF_ADDR((data_addr>>8)&0xff);???
  109. ???? ??
  110. ????NF_ADDR((page_number)?&?0xff);??????????????????//行地址A12~A19???
  111. ????NF_ADDR((page_number?>>?8)?&?0xff);???????????//行地址A20~A27???
  112. ???? ??
  113. ????NF_CMD(CMD_READ2);???????????//页读命令周期2???
  114. ????NF_DETECT_RB();????????????????????//等待RnB信号变高,即不忙???
  115. ??
  116. ????for(i=0;i<2048;i++) ??
  117. ???????buffer[i]?=?NF_RDDATA8()?; ??
  118. ????NF_MECC_Lock();?????????????????????//锁定main区ECC值???
  119. ????NF_SECC_UnLock();??????????????????//解锁spare区ECC???
  120. ???? ??
  121. ????mainecc0=NF_RDDATA();????????//读spare区的前4个地址内容,即第2048~2051地址,这4个字节为main区的ECC???
  122. ????//把读取到的main区的ECC校验码放入NFMECCD0/1的相应位置内???
  123. ????rNFMECCD0=((mainecc0&0xff00)<<8)|(mainecc0&0xff); ??
  124. ????rNFMECCD1=((mainecc0&0xff000000)>>8)|((mainecc0&0xff0000)>>16); ??
  125. ??
  126. ????NF_SECC_Lock();???????????????//锁定spare区的ECC值???
  127. ????spareecc=NF_RDDATA();???????????//继续读spare区的4个地址内容,即第2052~2055地址,其中前2个字节为spare区的ECC值???
  128. ????//把读取到的spare区的ECC校验码放入NFSECCD的相应位置内???
  129. ????rNFSECCD=((spareecc&0xff00)<<8)|(spareecc&0xff); ??
  130. ?????NF_CE_H();?????????????//关闭nandflash片选???
  131. ???? ??
  132. ????//判断所读取到的数据是否正确???
  133. ????if?((rNFESTAT0&0xf)?==?0x0) ??
  134. ??????????return?0x66;??????????????????//正确???
  135. ????else? ??
  136. ???????return?0x44;??? ??
  137. } ??
  138. ??
  139. U8?nand_writepage_ecc(U32?page_number,153)">int?i,stat; ??
  140. ????U32?mecc0,?secc;??//用于存放ecc的临时值???
  141. ????char?ECCBuf[10]; ??
  142. ????i?=?nand_is_badblock(page_number>>6)?; ??
  143. ????if(?i?==0x33) ??
  144. ????????return?0x42?;?//坏块???
  145. ???? ??
  146. ????NF_RSTECC();???????????????????//清除RnB信号???
  147. ????NF_CMD(CMD_WRITE1);???????????//行地址A20~A27???
  148. ???? ??
  149. ????for(i=0;i<2048;i++) ??
  150. ???????NF_WRDATA8(buffer[i]); ??
  151. ??
  152. ????NF_MECC_Lock();?????????????????????//锁定main区ECC值???
  153. ???? ??
  154. ????mecc0=rNFMECC0;????????????????????//读取main区的ECC校验码???
  155. ??????//把ECC校验码由字型转换为字节型,并保存到全局变量数组ECCBuf中???
  156. ????ECCBuf[0]=(U8)(mecc0&0xff); ??
  157. ????ECCBuf[1]=(U8)((mecc0>>8)?&?0xff); ??
  158. ????ECCBuf[2]=(U8)((mecc0>>16)?&?0xff); ??
  159. ????ECCBuf[3]=(U8)((mecc0>>24)?&?0xff); ??
  160. ???? ??
  161. ????NF_SECC_UnLock();??????????????????//解锁spare区ECC???
  162. ????for(i=0;i<4;i++) ??
  163. ???????{ ??
  164. ??????????????NF_WRDATA8(ECCBuf[i]); ??
  165. ???????}? ??
  166. ????? ??
  167. ????NF_SECC_Lock();???????????????//锁定spare区的ECC值???
  168. ????secc=rNFSECC;???????????????????//读取spare区的ECC校验码???
  169. ????//把ECC校验码保存到全局变量数组ECCBuf中???
  170. ????ECCBuf[4]=(U8)(secc&0xff); ??
  171. ????ECCBuf[5]=(U8)((secc>>8)?&?0xff); ??
  172. ????//把spare区的ECC值继续写入到spare区的第2052~2053地址内???
  173. ??
  174. ?????for(i=4;i<6;i++) ??
  175. ???????{ ??
  176. ??????????????NF_WRDATA8(ECCBuf[i]); ??
  177. ???????} ??
  178. ??
  179. ????NF_CMD(CMD_WRITE2);???????????//页读命令周期2???
  180. ????Delay(100); ??
  181. ??
  182. ????NF_CMD(CMD_STATUS);?????????????????//读状态命令???
  183. ????//判断状态值的第6位是否为1,即是否在忙,该语句的作用与NF_DETECT_RB();相同???
  184. ????do?{ ??
  185. ????????stat?=?NF_RDDATA8(); ??
  186. ??
  187. ????}while(!(stat&0x40)); ??
  188. ??
  189. ?????NF_CE_H();?????????????if?(stat?&?0x1) ??
  190. ????{ ??
  191. ????????i?=?rNF_MarkBadBlock(page_number>>6);?????????//标注该页所在的块为坏块???
  192. ????????if?(i?==?0x21) ??
  193. ??????????????return?0x43??;?????????//标注坏块失败???
  194. ????????else? ??
  195. ????????????return?0x44;?//写操作失败???
  196. ????} ??
  197. ????else? ??
  198. ????????return?0x66; ??
  199. ??
  200. ??
  201. } ??
  202. ??
  203. ??
  204. U8?nand_random_readpage(U32?page_number,?U32?add) ??
  205. { ??
  206. ???? ??
  207. ????NF_CE_L();??//等待RnB信号变高,即不忙???
  208. ???? ??
  209. ????NF_CMD(CMD_RANDOMREAD1);?????????????????//随意读命令周期1???
  210. ????//页内地址???
  211. ????NF_ADDR((char)(add&0xff));??????????????????????????//列地址A0~A7???
  212. ????NF_ADDR((char)((add>>8)&0x0f));?????????????????//列地址A8~A11???
  213. ?????NF_CMD(CMD_RANDOMREAD2);????????????????//随意读命令周期2???
  214. ?????return?NF_RDDATA8();???????????????//读取数据???
  215. ??
  216. ??
  217. } ??
  218. ??
  219. ??
  220. ??
  221. ??
  222. U8?nand_random_writepage(U32?page_number,?U32?add,?U8?data) ??
  223. { ??
  224. ????U8?stat; ??
  225. ????NF_CE_L();??//行地址A20~A27???
  226. ???? ??
  227. ????NF_CMD(CMD_RANDOMWRITE);???????????//页读命令周期2???
  228. ???? ??
  229. ????//列地址A8~A11???
  230. ????NF_WRDATA8(data);??????????????????????????//写入数据???
  231. ?????NF_CMD(CMD_WRITE2);????????????????//页写命令周期2???
  232. ????? ??
  233. ?????if?(stat?&?0x1) ??
  234. ????????return?0x44; ??
  235. ????return?0x66; ??
  236. ??
  237. } ??
  238. ??
  239. U8??nand_is_badblock(U32?block) ??
  240. { ??
  241. ????return?nand_random_readpage(block*64,?2054); ??
  242. ??
  243. } ??
  244. ??
  245. U8?rNF_MarkBadBlock(U32?block) ??
  246. { ??
  247. ????U8?result; ??
  248. ????result?=?nand_random_writepage(block*64,?2054,?0x33); ??
  249. ????if(result?==?0x44) ??
  250. ????????return?0x21;??????????????????//写坏块标注失败???
  251. ????else??
  252. ????????return?0x60?; ??
  253. ??
  254. }??

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读