nandflash.c 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190
  1. /*
  2. *********************************************************************************************************
  3. *
  4. * 模块名称 : NAND Flash驱动模块
  5. * 文件名称 : bsp_nand.c
  6. * 版 本 : V1.3
  7. * 说 明 : 提供NAND Flash (HY27UF081G2A, 8bit 128K字节 大页)的底层接口函数。【安富莱原创】
  8. *
  9. * 修改记录 :
  10. * 版本号 日期 作者 说明
  11. * V1.0 2013-02-01 armfly 正式发布
  12. * V1.1 2014-05-02 armfly 增加512MB型号: H27U4G8F2DTR,
  13. * (1) 增加 NAND_ReadONFI() 函数;
  14. * (2) 增加 NAND_ReadParamPage() 函数;
  15. * (3) 解决 NAND_IsFreeBlock(uint32_t _ulBlockNo) 函数的BUG。
  16. * (4) 解决 FSMC_NAND_PageCopyBack() 和 FSMC_NAND_PageCopyBackEx(), A18必须相同的BUG
  17. * (5) 修改 NAND_FindFreeBlock(), 增加形参,查找奇数或偶数块号
  18. * (6) 修改 打印坏块的函数,增加标识 1 表示已用块 0 表示空闲块
  19. * (7) NAND_MarkUsedBlock() 调用的地方给的形参不对。 ulPhyPageNo / NAND_BLOCK_SIZE
  20. * V1.2 2015-07-23 armfly 增加函数 uint8_t NAND_GetBlockInfo(void); 方便LCD显示。
  21. * V1.3 2015-08-04 armfly 增加对 H27U1G8F2BTR 芯片的支持。
  22. *
  23. * Copyright (C), 2015-2016, 安富莱电子 www.armfly.com
  24. *
  25. *********************************************************************************************************
  26. */
  27. #include "nandflash.h"
  28. #include "string.h"
  29. #include "stdio.h"
  30. /* 定义调试打印语句,用于排错 */
  31. #define printf_err printf
  32. //#define printf_err(...)
  33. //#define printf_ok printf
  34. #define printf_ok(...)
  35. #define flag
  36. #define WRITE_PAGE_VERIFY_EN /* 写 page 数据时校验 */
  37. /*
  38. 如果在IAR或KEIL的编辑器中阅读,请将编辑器的字体设置为新宋体(9号/五号),缩进的TAB设置为4。
  39. 否则,方框处出现不对齐的问题。
  40. 【待完善的地方】
  41. (1)在操作NAND Flash时,如下语句是一个死循环。如果硬件出现异常,将导致软件死机
  42. while( GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_6) == 0 )
  43. (2)没有增加ECC校验功能。ECC可以检查1个或2个bit错误,如果只有1个bit错误,则可以修复这个bit。如果
  44. 多余2个bit错误,则可能检测不到。
  45. (3)正常写文件操作时,会导致重建LUT。目前,重建LUT的代码执行效率还不够高,有待完善。
  46. 【硬件说明】
  47. 安富莱开发板配置的NAND Flahs为海力士的HY27UF081G2A, 439板子配的为 H27U4G8F2DTR
  48. (1)NAND Flash的片选信号连接到CPU的FSMC_NCE2,这决定了NAND Flash的地址空间为 0x70000000(见CPU的数据
  49. 手册的FSMC章节)
  50. (2)有FSMC总线上有多个总线设备(如TFT、SRAM、CH374T、NOR),因此必须确保其他总线设备的片选处于禁止
  51. 状态,否则将出现总线冲突问题 (参见本文件初始化FSMC GPIO的函数)
  52. 【NAND Flash 结构定义】
  53. 备用区有16x4字节,每page 2048字节,每512字节一个扇区,每个扇区对应16自己的备用区:
  54. 每个PAGE的逻辑结构,前面512Bx4是主数据区,后面16Bx4是备用区
  55. ┌──────┐┌──────┐┌──────┐┌──────┐┌──────┐┌──────┐┌──────┐┌──────┐
  56. │ Main area ││ Main area ││ Main area ││Main area ││ Spare area ││ Spare area ││ Spare area ││Spare area │
  57. │ ││ ││ ││ ││ ││ ││ ││ │
  58. │ 512B ││ 512B ││ 512B ││ 512B ││ 16B ││ 16B ││ 16B ││ 16B │
  59. └──────┘└──────┘└──────┘└──────┘└──────┘└──────┘└──────┘└──────┘
  60. 每16B的备用区的逻辑结构如下:(三星推荐标准)
  61. ┌───┐┌───┐┌──┐┌──┐┌──┐┌───┐┌───┐┌───┐┌──┐┌──┐┌──┐┌──┐┌───┐┌───┐┌───┐┌───┐┌───┐
  62. │ BI ││RESER ││LSN0││LSN1││LSN2││RESER ││RESER ││RESER ││ECC0││ECC1││ECC2││ECC0││S-ECC1││S-ECC0││RESER ││RESER ││RESER │
  63. │ ││ VED ││ ││ ││ ││ VED ││ VED ││ VED ││ ││ ││ ││ ││ ││ ││ VED ││ VED ││ VED │
  64. └───┘└───┘└──┘└──┘└──┘└───┘└───┘└───┘└──┘└──┘└──┘└──┘└───┘└───┘└───┘└───┘└───┘
  65. K9F1G08U0A 和 HY27UF081G2A 是兼容的。芯片出厂时,厂商保证芯片的第1个块是好块。如果是坏块,则在该块的第1个PAGE的第1个字节
  66. 或者第2个PAGE(当第1个PAGE坏了无法标记为0xFF时)的第1个字节写入非0xFF值。坏块标记值是随机的,软件直接判断是否等于0xFF即可。
  67. 注意:网上有些资料说NAND Flash厂商的默认做法是将坏块标记定在第1个PAGE的第6个字节处。这个说法是错误。坏块标记在第6个字节仅针对部分小扇区(512字节)的NAND Flash
  68. 并不是所有的NAND Flash都是这个标准。大家在更换NAND Flash时,请仔细阅读芯片的数据手册。
  69. 为了便于在NAND Flash 上移植Fat文件系统,我们对16B的备用区采用以下分配方案:
  70. ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌───┐┌───┐┌──┐┌──┐┌──┐┌──┐
  71. │ BI ││USED││LBN0││LBN1││ECC0││ECC1││ECC2││ECC3││ECC4││ECC5││S-ECC1││S-ECC0││RSVD││RSVD││RSVD││RSVD│
  72. │ ││ ││ ││ ││ ││ ││ ││ ││ ││ ││ ││ ││ ││ ││ ││ │
  73. └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└───┘└───┘└──┘└──┘└──┘└──┘
  74. - BI : 坏块标志(Bad Block Identifier)。每个BLOCK的第1个PAGE或者第2个PAGE的第1个字节指示该块是否坏块。0xFF表示好块,不是0xFF表示坏块。
  75. - USED : 该块使用标志。0xFF表示空闲块;0xF0表示已用块。
  76. - LBN0 LBN1 : 逻辑块号(Logic Block No) 。从0开始编码。只在每个BLOCK的第1个PAGE有效,其它PAGE该字段固定为0xFF FF
  77. - ECC0 ~ ECC6 : 512B主数据区的ECC校验 (按照三星提供ECC算法,256字节对应3个字节的ECC)
  78. - S-ECC1 S-ECC0 : LSN0和LSN2的ECC校验
  79. - RSVD : 保留字节,Reserved
  80. 【坏块管理 & 磨损平衡】
  81. (1) 内部全局数组s_usLUT[]按次序保存物理块号。用于物理块和逻辑块的地址映射。
  82. (2) 格式化时,将98%的好块用于主数据存储。剩余的2%用于备用区(坏块替换)。
  83. (3) 写扇区(512B)时,如果扇区内容为空,则直接写入,减少不必要的块擦除操作。有效提高NAND Flash的寿命和读写性能。
  84. (4) 写扇区时,如果扇区内容不为空,则从末尾开始查找一个空闲块替换掉旧块,替换并改写数据完成后,将旧块擦除,并标注为空闲,之后重建LUT。
  85. (5) 块复制时,充分利用NAND Flash硬件的Copy-Back功能,无需读源页到内存再写入目标页。这样可显著提高读写效率。
  86. (6) 磨损平衡还存在缺陷,效果不好。ECC校验暂未实现。
  87. */
  88. /* 定义NAND Flash的物理地址。这个是由硬件决定的 */
  89. #define Bank2_NAND_ADDR ((uint32_t)0x70000000)
  90. #define Bank_NAND_ADDR Bank2_NAND_ADDR
  91. /* 定义操作NAND Flash用到3个宏 */
  92. #define NAND_CMD_AREA *(__IO uint8_t *)(Bank_NAND_ADDR | CMD_AREA)
  93. #define NAND_ADDR_AREA *(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA)
  94. #define NAND_DATA_AREA *(__IO uint8_t *)(Bank_NAND_ADDR | DATA_AREA)
  95. /* 逻辑块号映射表。好块总数的2%用于备份区,因此数组维数低于1024。 LUT = Look Up Table */
  96. static uint16_t s_usLUT[NAND_BLOCK_COUNT];
  97. static uint16_t s_usValidDataBlockCount; /* 有效的数据块个数 */
  98. static uint8_t s_ucTempBuf[NAND_PAGE_TOTAL_SIZE]; /* 大缓冲区,2112字节. 用于读出比较 */
  99. static uint8_t NAND_BuildLUT(void);
  100. static uint8_t FSMC_NAND_GetStatus(void);
  101. static uint16_t NAND_FindFreeBlock (uint32_t _ulSrcPageNo);
  102. static uint8_t NAND_MarkUsedBlock(uint32_t _ulBlockNo);
  103. static uint16_t NAND_AddrToPhyBlockNo(uint32_t _ulMemAddr);
  104. static uint8_t NAND_IsBufOk(uint8_t *_pBuf, uint32_t _ulLen, uint8_t _ucValue);
  105. uint8_t NAND_WriteToNewBlock(uint32_t _ulPhyPageNo, uint8_t *_pWriteBuf, uint16_t _usOffset, uint16_t _usSize);
  106. static uint8_t NAND_IsFreeBlock(uint32_t _ulBlockNo);
  107. static uint16_t NAND_LBNtoPBN(uint32_t _uiLBN);
  108. static uint8_t FSMC_NAND_ReadPage(uint8_t *_pBuffer, uint32_t _ulPageNo, uint16_t _usAddrInPage, uint16_t _usByteCount);
  109. static uint8_t FSMC_NAND_WritePage(uint8_t *_pBuffer, uint32_t _ulPageNo, uint16_t _usAddrInPage, uint16_t _usByteCount);
  110. static uint8_t FSMC_NAND_CompPage(uint8_t *_pBuffer, uint32_t _ulPageNo, uint16_t _usAddrInPage, uint16_t _usByteCount);
  111. static uint8_t FSMC_NAND_EraseBlock(uint32_t _ulBlockNo);
  112. /*
  113. *********************************************************************************************************
  114. * 函 数 名: FSMC_NAND_Init
  115. * 功能说明: 配置FSMC和GPIO用于NAND Flash接口。这个函数必须在读写nand flash前被调用一次。
  116. * 形 参: 无
  117. * 返 回 值: 无
  118. *********************************************************************************************************
  119. */
  120. /*
  121. FSMC_NWAIT PD6
  122. FSMC_NOE PD4
  123. FSMC_NCE2 PD7
  124. FSMC_A16 PD11
  125. FSMC_A17 PD12
  126. FSMC_NWE PD5
  127. FSMC_D0 PD14
  128. FSMC_D1 PD15
  129. FSMC_D2 PD0
  130. FSMC_D3 PD1
  131. FSMC_D4 PE7
  132. FSMC_D5 PE8
  133. FSMC_D6 PE9
  134. FSMC_D7 PE10
  135. */
  136. static void FSMC_NAND_Init(void)
  137. {
  138. GPIO_InitTypeDef GPIO_InitStructure;
  139. FSMC_NANDInitTypeDef FSMC_NANDInitStructure;
  140. FSMC_NAND_PCCARDTimingInitTypeDef FSMC_NANDTimingInitStructure;
  141. // 使能FSMC时钟
  142. RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC, ENABLE);
  143. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE, ENABLE);
  144. // 配置PD和PE的复用功能
  145. GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_FSMC);
  146. GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_FSMC);
  147. GPIO_PinAFConfig(GPIOD, GPIO_PinSource4, GPIO_AF_FSMC);
  148. GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_FSMC);
  149. GPIO_PinAFConfig(GPIOD, GPIO_PinSource6, GPIO_AF_FSMC);
  150. GPIO_PinAFConfig(GPIOD, GPIO_PinSource7, GPIO_AF_FSMC);
  151. GPIO_PinAFConfig(GPIOD, GPIO_PinSource11, GPIO_AF_FSMC);
  152. GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_FSMC);
  153. GPIO_PinAFConfig(GPIOE, GPIO_PinSource7, GPIO_AF_FSMC);
  154. GPIO_PinAFConfig(GPIOE, GPIO_PinSource8, GPIO_AF_FSMC);
  155. GPIO_PinAFConfig(GPIOE, GPIO_PinSource9, GPIO_AF_FSMC);
  156. GPIO_PinAFConfig(GPIOE, GPIO_PinSource10, GPIO_AF_FSMC);
  157. /* GPIO 配置 */
  158. /* 控制线CLE, ALE, D0-D3, NOE, NWE 和 NCE2 NAND 引脚配置为复用功能(即用于FSMC) */
  159. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_14 | GPIO_Pin_15 |
  160. GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 |
  161. GPIO_Pin_7;
  162. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  163. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  164. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  165. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  166. GPIO_Init(GPIOD, &GPIO_InitStructure);
  167. /* 数据线 D4-D7 引脚配置为复用功能 */
  168. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10;
  169. GPIO_Init(GPIOE, &GPIO_InitStructure);
  170. /* NWAIT 引脚配置*/
  171. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  172. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  173. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  174. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  175. GPIO_Init(GPIOD, &GPIO_InitStructure);
  176. // 配置FSMC NAND Flash的时序参数
  177. FSMC_NANDTimingInitStructure.FSMC_SetupTime = 0x1;
  178. FSMC_NANDTimingInitStructure.FSMC_WaitSetupTime = 0x2;
  179. FSMC_NANDTimingInitStructure.FSMC_HoldSetupTime = 0x2;
  180. FSMC_NANDTimingInitStructure.FSMC_HiZSetupTime = 0x2;
  181. // 配置FSMC NAND Flash的控制参数
  182. FSMC_NANDInitStructure.FSMC_Bank = FSMC_Bank2_NAND;
  183. FSMC_NANDInitStructure.FSMC_Waitfeature = FSMC_Waitfeature_Disable;
  184. FSMC_NANDInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_8b;
  185. FSMC_NANDInitStructure.FSMC_ECC = FSMC_ECC_Enable;
  186. FSMC_NANDInitStructure.FSMC_ECCPageSize = FSMC_ECCPageSize_1024Bytes;
  187. FSMC_NANDInitStructure.FSMC_TCLRSetupTime = 0x0;
  188. FSMC_NANDInitStructure.FSMC_TARSetupTime = 0x0;
  189. FSMC_NANDInitStructure.FSMC_CommonSpaceTimingStruct = &FSMC_NANDTimingInitStructure;
  190. FSMC_NANDInitStructure.FSMC_AttributeSpaceTimingStruct = &FSMC_NANDTimingInitStructure;
  191. // 初始化FSMC NAND Flash
  192. FSMC_NANDInit(&FSMC_NANDInitStructure);
  193. // 使能FSMC NAND Flash
  194. FSMC_NANDCmd(FSMC_Bank2_NAND, ENABLE);
  195. }
  196. /*
  197. *********************************************************************************************************
  198. * 函 数 名: NAND_ReadID
  199. * 功能说明: 读NAND Flash的ID。ID存储到形参指定的结构体变量中。
  200. * 形 参: 无
  201. * 返 回 值: 32bit的NAND Flash ID
  202. *********************************************************************************************************
  203. */
  204. uint32_t NAND_ReadID(void)
  205. {
  206. uint32_t data = 0;
  207. /* 发送命令 Command to the command area */
  208. NAND_CMD_AREA = 0x90;
  209. NAND_ADDR_AREA = 0x00;
  210. /* 顺序读取NAND Flash的ID */
  211. data = *(__IO uint32_t *)(Bank_NAND_ADDR | DATA_AREA);
  212. data = ((data << 24) & 0xFF000000) |
  213. ((data << 8 ) & 0x00FF0000) |
  214. ((data >> 8 ) & 0x0000FF00) |
  215. ((data >> 24) & 0x000000FF) ;
  216. return data;
  217. }
  218. /*
  219. *********************************************************************************************************
  220. * 函 数 名: FSMC_NAND_PageCopyBack
  221. * 功能说明: 将一页数据复制到另外一个页。源页和目标页所在的block必须同为偶数或同为奇数。即A18必须相同。
  222. * 形 参: - _ulSrcPageNo: 源页号
  223. * - _ulTarPageNo: 目标页号
  224. * 返 回 值: 执行结果:
  225. * - NAND_FAIL 表示失败
  226. * - NAND_OK 表示成功
  227. *
  228. * 说 明:数据手册推荐:在页复制之前,先校验源页的位校验,否则可能会积累位错误。本函数未实现。
  229. *
  230. *********************************************************************************************************
  231. */
  232. static uint8_t FSMC_NAND_PageCopyBack(uint32_t _ulSrcPageNo, uint32_t _ulTarPageNo)
  233. {
  234. uint8_t i;
  235. if ((_ulSrcPageNo & 0x40) != (_ulTarPageNo & 0x40))
  236. {
  237. printf_err("Error : FSMC_NAND_PageCopyBackEx(src=%d, tar=%d) \r\n", _ulSrcPageNo, _ulTarPageNo);
  238. return NAND_FAIL;
  239. }
  240. NAND_CMD_AREA = NAND_CMD_COPYBACK_A;
  241. /* 发送源页地址 , 对于 HY27UF081G2A
  242. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  243. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  244. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  245. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12
  246. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  247. H27U4G8F2DTR (512MB)
  248. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  249. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  250. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  251. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12
  252. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  253. 第5字节: A28 A29 A30 A31 0 0 0 0
  254. */
  255. NAND_ADDR_AREA = 0;
  256. NAND_ADDR_AREA = 0;
  257. NAND_ADDR_AREA = _ulSrcPageNo;
  258. NAND_ADDR_AREA = (_ulSrcPageNo & 0xFF00) >> 8;
  259. #if NAND_ADDR_5 == 1
  260. NAND_ADDR_AREA = (_ulSrcPageNo & 0xFF0000) >> 16;
  261. #endif
  262. NAND_CMD_AREA = NAND_CMD_COPYBACK_B;
  263. /* 必须等待,否则读出数据异常, 此处应该判断超时 */
  264. for (i = 0; i < 20; i++);
  265. while( GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_6) == 0 );
  266. NAND_CMD_AREA = NAND_CMD_COPYBACK_C;
  267. /* 发送目标页地址 , 对于 HY27UF081G2A
  268. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  269. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  270. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  271. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12
  272. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  273. H27U4G8F2DTR (512MB)
  274. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  275. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  276. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  277. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12 --- A18 是plane地址
  278. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  279. 第5字节: A28 A29 A30 A31 0 0 0 0
  280. Source and Destination page in the copy back program sequence must belong to the same device plane (A18)
  281. 源地址和目标地址的 A18必须相同
  282. */
  283. NAND_ADDR_AREA = 0;
  284. NAND_ADDR_AREA = 0;
  285. NAND_ADDR_AREA = _ulTarPageNo;
  286. NAND_ADDR_AREA = (_ulTarPageNo & 0xFF00) >> 8;
  287. #if NAND_ADDR_5 == 1
  288. NAND_ADDR_AREA = (_ulTarPageNo & 0xFF0000) >> 16;
  289. #endif
  290. NAND_CMD_AREA = NAND_CMD_COPYBACK_D;
  291. /* 检查操作状态 */
  292. if (FSMC_NAND_GetStatus() == NAND_READY)
  293. {
  294. return NAND_OK;
  295. }
  296. printf_err("Error: FSMC_NAND_PageCopyBack(%d, %d)\r\n", _ulSrcPageNo, _ulTarPageNo);
  297. return NAND_FAIL;
  298. }
  299. /*
  300. *********************************************************************************************************
  301. * 函 数 名: FSMC_NAND_PageCopyBackEx
  302. * 功能说明: 将一页数据复制到另外一个页,并更新目标页中的部分数据。源页和目标页所在的BLOCK必须同为偶数或同为奇数。
  303. * 形 参: - _ulSrcPageNo: 源页号
  304. * - _ulTarPageNo: 目标页号
  305. * - _usOffset: 页内偏移地址,pBuf的内容将写入这个地址开始单元
  306. * - _pBuf: 数据缓冲区
  307. * - _usSize: 数据大小
  308. * 返 回 值: 执行结果:
  309. * - NAND_FAIL 表示失败
  310. * - NAND_OK 表示成功
  311. *
  312. * 说 明:数据手册推荐:在页复制之前,先校验源页的位校验,否则可能会积累位错误。本函数未实现。
  313. *
  314. *********************************************************************************************************
  315. */
  316. static uint8_t FSMC_NAND_PageCopyBackEx(uint32_t _ulSrcPageNo, uint32_t _ulTarPageNo, uint8_t *_pBuf,
  317. uint16_t _usOffset, uint16_t _usSize)
  318. {
  319. uint16_t i;
  320. if ((_ulSrcPageNo & 0x40) != (_ulTarPageNo & 0x40))
  321. {
  322. printf_err("Error A18 not same: FSMC_NAND_PageCopyBackEx(src=%d, tar=%d) \r\n", _ulSrcPageNo, _ulTarPageNo);
  323. return NAND_FAIL;
  324. }
  325. NAND_CMD_AREA = NAND_CMD_COPYBACK_A;
  326. /* 发送源页地址 , 对于 HY27UF081G2A
  327. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  328. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  329. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  330. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12
  331. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  332. H27U4G8F2DTR (512MB)
  333. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  334. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  335. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  336. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12
  337. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  338. 第5字节: A28 A29 A30 A31 0 0 0 0
  339. */
  340. NAND_ADDR_AREA = 0;
  341. NAND_ADDR_AREA = 0;
  342. NAND_ADDR_AREA = _ulSrcPageNo;
  343. NAND_ADDR_AREA = (_ulSrcPageNo & 0xFF00) >> 8;
  344. #if NAND_ADDR_5 == 1
  345. NAND_ADDR_AREA = (_ulSrcPageNo & 0xFF0000) >> 16;
  346. #endif
  347. NAND_CMD_AREA = NAND_CMD_COPYBACK_B;
  348. /* 必须等待,否则读出数据异常, 此处应该判断超时 */
  349. for (i = 0; i < 20; i++);
  350. while( GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_6) == 0 );
  351. NAND_CMD_AREA = NAND_CMD_COPYBACK_C;
  352. /* 发送目标页地址 , 对于 HY27UF081G2A
  353. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  354. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  355. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  356. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12
  357. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  358. H27U4G8F2DTR (512MB)
  359. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  360. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  361. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  362. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12
  363. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  364. 第5字节: A28 A29 A30 A31 0 0 0 0
  365. */
  366. NAND_ADDR_AREA = 0;
  367. NAND_ADDR_AREA = 0;
  368. NAND_ADDR_AREA = _ulTarPageNo;
  369. NAND_ADDR_AREA = (_ulTarPageNo & 0xFF00) >> 8;
  370. #if NAND_ADDR_5 == 1
  371. NAND_ADDR_AREA = (_ulTarPageNo & 0xFF0000) >> 16;
  372. #endif
  373. /* 中间无需带数据, 也无需等待 */
  374. NAND_CMD_AREA = NAND_CMD_COPYBACK_C;
  375. NAND_ADDR_AREA = _usOffset;
  376. NAND_ADDR_AREA = _usOffset >> 8;
  377. /* 发送数据 */
  378. for(i = 0; i < _usSize; i++)
  379. {
  380. NAND_DATA_AREA = _pBuf[i];
  381. }
  382. NAND_CMD_AREA = NAND_CMD_COPYBACK_D;
  383. /* 检查操作状态 */
  384. if (FSMC_NAND_GetStatus() == NAND_READY)
  385. {
  386. return NAND_OK;
  387. }
  388. printf_err("Error: FSMC_NAND_PageCopyBackEx(src=%d, tar=%d, offset=%d, size=%d)\r\n",
  389. _ulSrcPageNo, _ulTarPageNo, _usOffset, _usSize);
  390. return NAND_FAIL;
  391. }
  392. /*
  393. *********************************************************************************************************
  394. * 函 数 名: FSMC_NAND_WritePage
  395. * 功能说明: 写一组数据至NandFlash指定页面的指定位置,写入的数据长度不大于一页的大小。
  396. * 形 参: - _pBuffer: 指向包含待写数据的缓冲区
  397. * - _ulPageNo: 页号,所有的页统一编码,范围为:0 - 65535
  398. * - _usAddrInPage : 页内地址,范围为:0-2111
  399. * - _usByteCount: 写入的字节个数
  400. * 返 回 值: 执行结果:
  401. * - NAND_FAIL 表示失败
  402. * - NAND_OK 表示成功
  403. *********************************************************************************************************
  404. */
  405. static uint8_t FSMC_NAND_WritePage(uint8_t *_pBuffer, uint32_t _ulPageNo, uint16_t _usAddrInPage, uint16_t _usByteCount)
  406. {
  407. uint16_t i;
  408. /* 发送页写命令 */
  409. NAND_CMD_AREA = NAND_CMD_WRITE0;
  410. /* 发送页内地址 , 对于 HY27UF081G2A
  411. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  412. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  413. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  414. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12
  415. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  416. H27U4G8F2DTR (512MB)
  417. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  418. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  419. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  420. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12
  421. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  422. 第5字节: A28 A29 A30 A31 0 0 0 0
  423. */
  424. NAND_ADDR_AREA = _usAddrInPage;
  425. NAND_ADDR_AREA = _usAddrInPage >> 8;
  426. NAND_ADDR_AREA = _ulPageNo;
  427. NAND_ADDR_AREA = (_ulPageNo & 0xFF00) >> 8;
  428. #if NAND_ADDR_5 == 1
  429. NAND_ADDR_AREA = (_ulPageNo & 0xFF0000) >> 16;
  430. #endif
  431. /* tADL = 100ns, Address to Data Loading */
  432. for (i = 0; i < 20; i++); /* 需要大于 100ns */
  433. /* 写数据 */
  434. for(i = 0; i < _usByteCount; i++)
  435. {
  436. NAND_DATA_AREA = _pBuffer[i];
  437. }
  438. NAND_CMD_AREA = NAND_CMD_WRITE_TRUE1;
  439. /* WE High to Busy , 100ns */
  440. for (i = 0; i < 20; i++); /* 需要大于 100ns */
  441. while( GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_6) == 0 );
  442. /* 检查操作状态 */
  443. if (FSMC_NAND_GetStatus() == NAND_READY)
  444. {
  445. /* 读出数据进行校验 */
  446. #ifdef WRITE_PAGE_VERIFY_EN
  447. FSMC_NAND_ReadPage (s_ucTempBuf, _ulPageNo, _usAddrInPage, _usByteCount);
  448. if (memcmp(s_ucTempBuf, _pBuffer, _usByteCount) != 0)
  449. {
  450. printf_err("Error1: FSMC_NAND_WritePage(page=%d, addr=%d, count=%d)\r\n",
  451. _ulPageNo, _usAddrInPage, _usByteCount);
  452. return NAND_FAIL;
  453. }
  454. #endif
  455. return NAND_OK;
  456. }
  457. printf_err("Error2: FSMC_NAND_WritePage(page=%d, addr=%d, count=%d)\r\n",
  458. _ulPageNo, _usAddrInPage, _usByteCount);
  459. return NAND_FAIL;
  460. }
  461. /*
  462. *********************************************************************************************************
  463. * 函 数 名: FSMC_NAND_ReadPage
  464. * 功能说明: 从NandFlash指定页面的指定位置读一组数据,读出的数据长度不大于一页的大小。
  465. * 形 参: - _pBuffer: 指向包含待写数据的缓冲区
  466. * - _ulPageNo: 页号,所有的页统一编码,范围为:0 - 65535
  467. * - _usAddrInPage : 页内地址,范围为:0-2111
  468. * - _usByteCount: 字节个数, (最大 2048 + 64)
  469. * 返 回 值: 执行结果:
  470. * - NAND_FAIL 表示失败
  471. * - NAND_OK 表示成功
  472. *********************************************************************************************************
  473. */
  474. static uint8_t FSMC_NAND_ReadPage(uint8_t *_pBuffer, uint32_t _ulPageNo, uint16_t _usAddrInPage, uint16_t _usByteCount)
  475. {
  476. uint16_t i;
  477. /* 发送页面读命令 */
  478. NAND_CMD_AREA = NAND_CMD_AREA_A;
  479. /* 发送页内地址 , 对于 HY27UF081G2A (128MB)
  480. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  481. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  482. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  483. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12
  484. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  485. H27U4G8F2DTR (512MB)
  486. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  487. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  488. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  489. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12
  490. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  491. 第5字节: A28 A29 A30 A31 0 0 0 0
  492. */
  493. NAND_ADDR_AREA = _usAddrInPage;
  494. NAND_ADDR_AREA = _usAddrInPage >> 8;
  495. NAND_ADDR_AREA = _ulPageNo;
  496. NAND_ADDR_AREA = (_ulPageNo & 0xFF00) >> 8;
  497. #if NAND_ADDR_5 == 1
  498. NAND_ADDR_AREA = (_ulPageNo & 0xFF0000) >> 16;
  499. #endif
  500. NAND_CMD_AREA = NAND_CMD_AREA_TRUE1;
  501. /* 必须等待,否则读出数据异常, 此处应该判断超时 */
  502. for (i = 0; i < 50; i++);
  503. while( GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_6) == 0);
  504. /* 读数据到缓冲区pBuffer */
  505. for(i = 0; i < _usByteCount; i++)
  506. {
  507. _pBuffer[i] = NAND_DATA_AREA;
  508. }
  509. return NAND_OK;
  510. }
  511. /*
  512. *********************************************************************************************************
  513. * 函 数 名: FSMC_NAND_CompPage
  514. * 功能说明: 比较数据
  515. * 形 参: - _pBuffer: 指向包含待比较的数据缓冲区
  516. * - _ulPageNo: 页号,所有的页统一编码,范围为:0 - 65535
  517. * - _usAddrInPage : 页内地址,范围为:0-2111
  518. * - _usByteCount: 字节个数, (最大 2048 + 64)
  519. * 返 回 值: 执行结果:
  520. * - NAND_FAIL 表示失败
  521. * - NAND_OK 表示成功, 相等
  522. *********************************************************************************************************
  523. */
  524. static uint8_t FSMC_NAND_CompPage(uint8_t *_pBuffer, uint32_t _ulPageNo, uint16_t _usAddrInPage, uint16_t _usByteCount)
  525. {
  526. uint16_t i;
  527. /* 发送页面读命令 */
  528. NAND_CMD_AREA = NAND_CMD_AREA_A;
  529. /* 发送页内地址 , 对于 HY27UF081G2A (128MB)
  530. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  531. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  532. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  533. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12
  534. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  535. H27U4G8F2DTR (512MB)
  536. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  537. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  538. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  539. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12
  540. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  541. 第5字节: A28 A29 A30 A31 0 0 0 0
  542. */
  543. NAND_ADDR_AREA = _usAddrInPage;
  544. NAND_ADDR_AREA = _usAddrInPage >> 8;
  545. NAND_ADDR_AREA = _ulPageNo;
  546. NAND_ADDR_AREA = (_ulPageNo & 0xFF00) >> 8;
  547. #if NAND_ADDR_5 == 1
  548. NAND_ADDR_AREA = (_ulPageNo & 0xFF0000) >> 16;
  549. #endif
  550. NAND_CMD_AREA = NAND_CMD_AREA_TRUE1;
  551. /* 必须等待,否则读出数据异常, 此处应该判断超时 */
  552. for (i = 0; i < 20; i++);
  553. while( GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_6) == 0);
  554. /* 读数据到缓冲区pBuffer */
  555. for(i = 0; i < _usByteCount; i++)
  556. {
  557. if (_pBuffer[i] != NAND_DATA_AREA)
  558. {
  559. return NAND_FAIL;
  560. }
  561. }
  562. return NAND_OK;
  563. }
  564. /*
  565. *********************************************************************************************************
  566. * 函 数 名: FSMC_NAND_WriteSpare
  567. * 功能说明: 向1个PAGE的Spare区写入数据
  568. * 形 参: - _pBuffer: 指向包含待写数据的缓冲区
  569. * - _ulPageNo: 页号,所有的页统一编码,范围为:0 - 65535
  570. * - _usAddrInSpare : 页内备用区的偏移地址,范围为:0-63
  571. * - _usByteCount: 写入的字节个数
  572. * 返 回 值: 执行结果:
  573. * - NAND_FAIL 表示失败
  574. * - NAND_OK 表示成功
  575. *********************************************************************************************************
  576. */
  577. static uint8_t FSMC_NAND_WriteSpare(uint8_t *_pBuffer, uint32_t _ulPageNo, uint16_t _usAddrInSpare, uint16_t _usByteCount)
  578. {
  579. if (_usByteCount > NAND_SPARE_AREA_SIZE)
  580. {
  581. printf_err("Error: FSMC_NAND_WriteSpare() %d\r\n",_usByteCount);
  582. return NAND_FAIL;
  583. }
  584. return FSMC_NAND_WritePage(_pBuffer, _ulPageNo, NAND_PAGE_SIZE + _usAddrInSpare, _usByteCount);
  585. }
  586. /*
  587. *********************************************************************************************************
  588. * 函 数 名: FSMC_NAND_ReadSpare
  589. * 功能说明: 读1个PAGE的Spare区的数据
  590. * 形 参: - _pBuffer: 指向包含待写数据的缓冲区
  591. * - _ulPageNo: 页号,所有的页统一编码,范围为:0 - 65535
  592. * - _usAddrInSpare : 页内备用区的偏移地址,范围为:0-63
  593. * - _usByteCount: 写入的字节个数
  594. * 返 回 值: 执行结果:
  595. * - NAND_FAIL 表示失败
  596. * - NAND_OK 表示成功
  597. *********************************************************************************************************
  598. */
  599. static uint8_t FSMC_NAND_ReadSpare(uint8_t *_pBuffer, uint32_t _ulPageNo, uint16_t _usAddrInSpare, uint16_t _usByteCount)
  600. {
  601. if (_usByteCount > NAND_SPARE_AREA_SIZE)
  602. {
  603. printf_err("Error: FSMC_NAND_ReadSpare() %d\r\n",_usByteCount);
  604. return NAND_FAIL;
  605. }
  606. return FSMC_NAND_ReadPage(_pBuffer, _ulPageNo, NAND_PAGE_SIZE + _usAddrInSpare, _usByteCount);
  607. }
  608. /*
  609. *********************************************************************************************************
  610. * 函 数 名: FSMC_NAND_WriteData
  611. * 功能说明: 向1个PAGE的主数据区写入数据
  612. * 形 参: - _pBuffer: 指向包含待写数据的缓冲区
  613. * - _ulPageNo: 页号,所有的页统一编码,范围为:0 - 65535
  614. * - _usAddrInPage : 页内数据区的偏移地址,范围为:0-2047
  615. * - _usByteCount: 写入的字节个数
  616. * 返 回 值: 执行结果:
  617. * - NAND_FAIL 表示失败
  618. * - NAND_OK 表示成功
  619. *********************************************************************************************************
  620. */
  621. static uint8_t FSMC_NAND_WriteData(uint8_t *_pBuffer, uint32_t _ulPageNo, uint16_t _usAddrInPage, uint16_t _usByteCount)
  622. {
  623. if (_usByteCount > NAND_PAGE_SIZE)
  624. {
  625. printf_err("Error: FSMC_NAND_WriteData() %d\r\n",_usByteCount);
  626. return NAND_FAIL;
  627. }
  628. return FSMC_NAND_WritePage(_pBuffer, _ulPageNo, _usAddrInPage, _usByteCount);
  629. }
  630. /*
  631. *********************************************************************************************************
  632. * 函 数 名: FSMC_NAND_ReadData
  633. * 功能说明: 读1个PAGE的主数据的数据
  634. * 形 参: - _pBuffer: 指向包含待写数据的缓冲区
  635. * - _ulPageNo: 页号,所有的页统一编码,范围为:0 - 65535
  636. * - _usAddrInPage : 页内数据区的偏移地址,范围为:0-2047
  637. * - _usByteCount: 写入的字节个数
  638. * 返 回 值: 执行结果:
  639. * - NAND_FAIL 表示失败
  640. * - NAND_OK 表示成功
  641. *********************************************************************************************************
  642. */
  643. static uint8_t FSMC_NAND_ReadData(uint8_t *_pBuffer, uint32_t _ulPageNo, uint16_t _usAddrInPage, uint16_t _usByteCount)
  644. {
  645. if (_usByteCount > NAND_PAGE_SIZE)
  646. {
  647. printf_err("Error: FSMC_NAND_ReadData() %d\r\n",_usByteCount);
  648. return NAND_FAIL;
  649. }
  650. return FSMC_NAND_ReadPage(_pBuffer, _ulPageNo, _usAddrInPage, _usByteCount);
  651. }
  652. /*
  653. *********************************************************************************************************
  654. * 函 数 名: FSMC_NAND_EraseBlock
  655. * 功能说明: 擦除NAND Flash一个块(block)
  656. * 形 参: - _ulBlockNo: 块号,范围为:0 - 1023, 0-4095
  657. * 返 回 值: NAND操作状态,有如下几种值:
  658. * - NAND_TIMEOUT_ERROR : 超时错误
  659. * - NAND_READY : 操作成功
  660. *********************************************************************************************************
  661. */
  662. static uint8_t FSMC_NAND_EraseBlock(uint32_t _ulBlockNo)
  663. {
  664. /* HY27UF081G2A (128MB)
  665. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  666. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  667. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  668. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12 A18以上是块号
  669. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  670. H27U4G8F2DTR (512MB)
  671. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  672. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  673. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  674. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12 A18以上是块号
  675. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  676. 第5字节: A28 A29 A30 A31 0 0 0 0
  677. */
  678. /* 发送擦除命令 */
  679. NAND_CMD_AREA = NAND_CMD_ERASE0;
  680. _ulBlockNo <<= 6; /* 块号转换为页编号 */
  681. #if NAND_ADDR_5 == 0 /* 128MB的 */
  682. NAND_ADDR_AREA = _ulBlockNo;
  683. NAND_ADDR_AREA = _ulBlockNo >> 8;
  684. #else /* 512MB的 */
  685. NAND_ADDR_AREA = _ulBlockNo;
  686. NAND_ADDR_AREA = _ulBlockNo >> 8;
  687. NAND_ADDR_AREA = _ulBlockNo >> 16;
  688. #endif
  689. NAND_CMD_AREA = NAND_CMD_ERASE1;
  690. return (FSMC_NAND_GetStatus());
  691. }
  692. /*
  693. *********************************************************************************************************
  694. * 函 数 名: FSMC_NAND_Reset
  695. * 功能说明: 复位NAND Flash
  696. * 形 参: 无
  697. * 返 回 值: 无
  698. *********************************************************************************************************
  699. */
  700. static uint8_t FSMC_NAND_Reset(void)
  701. {
  702. NAND_CMD_AREA = NAND_CMD_RESET;
  703. /* 检查操作状态 */
  704. if (FSMC_NAND_GetStatus() == NAND_READY)
  705. {
  706. return NAND_OK;
  707. }
  708. return NAND_FAIL;
  709. }
  710. /*
  711. *********************************************************************************************************
  712. * 函 数 名: FSMC_NAND_ReadStatus
  713. * 功能说明: 使用Read statuc 命令读NAND Flash内部状态
  714. * 形 参: - Address: 被擦除的快内任意地址
  715. * 返 回 值: NAND操作状态,有如下几种值:
  716. * - NAND_BUSY: 内部正忙
  717. * - NAND_READY: 内部空闲,可以进行下步操作
  718. * - NAND_ERROR: 先前的命令执行失败
  719. *********************************************************************************************************
  720. */
  721. static uint8_t FSMC_NAND_ReadStatus(void)
  722. {
  723. uint8_t ucData;
  724. uint8_t ucStatus = NAND_BUSY;
  725. /* 读状态操作 */
  726. NAND_CMD_AREA = NAND_CMD_STATUS;
  727. ucData = *(__IO uint8_t *)(Bank_NAND_ADDR);
  728. if((ucData & NAND_ERROR) == NAND_ERROR)
  729. {
  730. ucStatus = NAND_ERROR;
  731. }
  732. else if((ucData & NAND_READY) == NAND_READY)
  733. {
  734. ucStatus = NAND_READY;
  735. }
  736. else
  737. {
  738. ucStatus = NAND_BUSY;
  739. }
  740. return (ucStatus);
  741. }
  742. /*
  743. *********************************************************************************************************
  744. * 函 数 名: FSMC_NAND_GetStatus
  745. * 功能说明: 获取NAND Flash操作状态
  746. * 形 参: - Address: 被擦除的快内任意地址
  747. * 返 回 值: NAND操作状态,有如下几种值:
  748. * - NAND_TIMEOUT_ERROR : 超时错误
  749. * - NAND_READY : 操作成功
  750. *********************************************************************************************************
  751. */
  752. static uint8_t FSMC_NAND_GetStatus(void)
  753. {
  754. uint32_t ulTimeout = 0x10000;
  755. uint8_t ucStatus = NAND_READY;
  756. ucStatus = FSMC_NAND_ReadStatus();
  757. /* 等待NAND操作结束,超时后会退出 */
  758. while ((ucStatus != NAND_READY) &&( ulTimeout != 0x00))
  759. {
  760. ucStatus = FSMC_NAND_ReadStatus();
  761. ulTimeout--;
  762. }
  763. if(ulTimeout == 0x00)
  764. {
  765. ucStatus = NAND_TIMEOUT_ERROR;
  766. }
  767. /* 返回操作状态 */
  768. return (ucStatus);
  769. }
  770. /*
  771. *********************************************************************************************************
  772. * 函 数 名: NAND_Init
  773. * 功能说明: 初始化NAND Flash接口
  774. * 形 参: 无
  775. * 返 回 值: 执行结果:
  776. * - NAND_FAIL 表示失败
  777. * - NAND_OK 表示成功
  778. *********************************************************************************************************
  779. */
  780. uint8_t NAND_Init(void)
  781. {
  782. uint8_t Status;
  783. FSMC_NAND_Init(); /* 配置FSMC和GPIO用于NAND Flash接口 */
  784. FSMC_NAND_Reset(); /* 通过复位命令复位NAND Flash到读状态 */
  785. Status = NAND_BuildLUT(); /* 建立块管理表 LUT = Look up table */
  786. return Status;
  787. }
  788. /*
  789. *********************************************************************************************************
  790. * 函 数 名: NAND_WriteToNewBlock
  791. * 功能说明: 将旧块的数据复制到新块,并将新的数据段写入这个新块.
  792. * 形 参: _ulPhyPageNo : 源页号
  793. * _pWriteBuf : 数据缓冲区
  794. * _usOffset : 页内偏移地址
  795. * _usSize :数据长度,必须是4字节的整数倍
  796. * 返 回 值: 执行结果:
  797. * - NAND_FAIL 表示失败
  798. * - NAND_OK 表示成功
  799. *********************************************************************************************************
  800. */
  801. uint8_t NAND_WriteToNewBlock(uint32_t _ulPhyPageNo, uint8_t *_pWriteBuf, uint16_t _usOffset, uint16_t _usSize)
  802. {
  803. uint16_t n, i;
  804. uint16_t usNewBlock;
  805. uint16_t ulSrcBlock;
  806. uint16_t usOffsetPageNo;
  807. ulSrcBlock = _ulPhyPageNo / NAND_BLOCK_SIZE; /* 根据物理页号反推块号 */
  808. usOffsetPageNo = _ulPhyPageNo % NAND_BLOCK_SIZE; /* 根据物理页号计算物理页号在块内偏移页号 */
  809. /* 增加循环的目的是处理目标块为坏块的情况 */
  810. for (n = 0; n < 10; n++)
  811. {
  812. /* 如果不是全0xFF, 则需要寻找一个空闲可用块,并将页内的数据全部移到新块中,然后擦除这个块 */
  813. usNewBlock = NAND_FindFreeBlock(_ulPhyPageNo); /* 从最后一个Block开始,搜寻一个可用块. */
  814. if (usNewBlock >= NAND_BLOCK_COUNT)
  815. {
  816. printf_err("Error1: NAND_WriteToNewBlock() %d\r\n", usNewBlock);
  817. return NAND_FAIL; /* 查找空闲块失败 */
  818. }
  819. printf_ok("NAND_WriteToNewBlock(%d -> %d)\r\n", ulSrcBlock, usNewBlock);
  820. /* 使用page-copy功能,将当前块(usPBN)的数据全部搬移到新块(usNewBlock) */
  821. for (i = 0; i < NAND_BLOCK_SIZE; i++)
  822. {
  823. if (i == usOffsetPageNo)
  824. {
  825. /* 如果写入的数据在当前页,则需要使用带随机数据的Copy-Back命令 */
  826. if (FSMC_NAND_PageCopyBackEx(ulSrcBlock * NAND_BLOCK_SIZE + i, usNewBlock * NAND_BLOCK_SIZE + i,
  827. _pWriteBuf, _usOffset, _usSize) == NAND_FAIL)
  828. {
  829. printf_err("Error2: NAND_WriteToNewBlock() %d\r\n", ulSrcBlock);
  830. NAND_MarkBadBlock(usNewBlock); /* 将新块标记为坏块 */
  831. NAND_BuildLUT(); /* 重建LUT表 */
  832. break;
  833. }
  834. }
  835. else
  836. {
  837. /* 使用NAND Flash 提供的整页Copy-Back功能,可以显著提高操作效率 */
  838. if (FSMC_NAND_PageCopyBack(ulSrcBlock * NAND_BLOCK_SIZE + i,
  839. usNewBlock * NAND_BLOCK_SIZE + i) == NAND_FAIL)
  840. {
  841. printf_err("Error3: NAND_WriteToNewBlock() %d\r\n", ulSrcBlock);
  842. NAND_MarkBadBlock(usNewBlock); /* 将新块标记为坏块 */
  843. NAND_BuildLUT(); /* 重建LUT表 */
  844. break;
  845. }
  846. }
  847. }
  848. /* 目标块更新成功 */
  849. if (i == NAND_BLOCK_SIZE)
  850. {
  851. /* 标记新块为已用块 */
  852. if (NAND_MarkUsedBlock(usNewBlock) == NAND_FAIL)
  853. {
  854. NAND_MarkBadBlock(usNewBlock); /* 将新块标记为坏块 */
  855. NAND_BuildLUT(); /* 重建LUT表 */
  856. continue;
  857. }
  858. /* 擦除源BLOCK (如果源块写失败,则会擦除坏块标记) */
  859. if (FSMC_NAND_EraseBlock(ulSrcBlock) != NAND_READY)
  860. {
  861. printf_err("Error4: FSMC_NAND_EraseBlock(), %d\r\n", ulSrcBlock);
  862. NAND_MarkBadBlock(ulSrcBlock); /* 将源块标记为坏块 */
  863. NAND_BuildLUT(); /* 重建LUT表 */
  864. continue;
  865. }
  866. NAND_BuildLUT(); /* 重建LUT表 */
  867. break;
  868. }
  869. }
  870. if (n == 10)
  871. {
  872. printf_err("Error5: FSMC_NAND_EraseBlock() n=%d\r\n", n);
  873. return NAND_FAIL;
  874. }
  875. return NAND_OK; /* 写入成功 */
  876. }
  877. /*
  878. *********************************************************************************************************
  879. * 函 数 名: NAND_Write
  880. * 功能说明: 写一个扇区
  881. * 形 参: _MemAddr : 内存单元偏移地址
  882. * _pReadbuff :存放待写数据的缓冲区的指针
  883. * _usSize :数据长度,必须是4字节的整数倍
  884. * 返 回 值: 执行结果:
  885. * - NAND_FAIL 表示失败
  886. * - NAND_OK 表示成功
  887. ******************************************s***************************************************************
  888. */
  889. uint8_t NAND_Write(uint32_t _ulMemAddr, uint32_t *_pWriteBuf, uint16_t _usSize)
  890. {
  891. uint16_t usPBN; /* 物理块号 */
  892. uint32_t ulPhyPageNo; /* 物理页号 */
  893. uint16_t usAddrInPage; /* 页内偏移地址 */
  894. uint32_t ulTemp;
  895. /* 数据长度必须是4字节整数倍 */
  896. if ((_usSize % 4) != 0)
  897. {
  898. printf_err("Error:1 NAND_Write() %d\r\n",_usSize);
  899. return NAND_FAIL;
  900. }
  901. /* 数据长度不能超过512字节(遵循 Fat格式) */
  902. if (_usSize > 512)
  903. {
  904. printf_err("Error:2 NAND_Write() %d\r\n",_usSize);
  905. //return NAND_FAIL;
  906. }
  907. usPBN = NAND_AddrToPhyBlockNo(_ulMemAddr); /* 查询LUT表获得物理块号 */
  908. ulTemp = _ulMemAddr % (NAND_BLOCK_SIZE * NAND_PAGE_SIZE);
  909. ulPhyPageNo = usPBN * NAND_BLOCK_SIZE + ulTemp / NAND_PAGE_SIZE; /* 计算物理页号 */
  910. usAddrInPage = ulTemp % NAND_PAGE_SIZE; /* 计算页内偏移地址 */
  911. /* 读出扇区的内容,判断是否全FF */
  912. if (FSMC_NAND_ReadData(s_ucTempBuf, ulPhyPageNo, usAddrInPage, _usSize) == NAND_FAIL)
  913. {
  914. return NAND_FAIL; /* 读NAND Flash失败 */
  915. }
  916. /* 如果是全0xFF, 则可以直接写入,无需擦除 */
  917. if (NAND_IsBufOk(s_ucTempBuf, _usSize, 0xFF) == 1)
  918. {
  919. if (FSMC_NAND_WriteData((uint8_t *)_pWriteBuf, ulPhyPageNo, usAddrInPage, _usSize) == NAND_FAIL)
  920. {
  921. /* 将数据写入到另外一个块(空闲块) */
  922. return NAND_WriteToNewBlock(ulPhyPageNo, (uint8_t *)_pWriteBuf, usAddrInPage, _usSize);
  923. }
  924. /* 标记该块已用 */
  925. if (NAND_MarkUsedBlock(ulPhyPageNo / NAND_BLOCK_SIZE) == NAND_FAIL)
  926. {
  927. /* 标记失败,将数据写入到另外一个块(空闲块) */
  928. return NAND_WriteToNewBlock(ulPhyPageNo, (uint8_t *)_pWriteBuf, usAddrInPage, _usSize);
  929. }
  930. return NAND_OK; /* 写入成功 */
  931. }
  932. /* 将数据写入到另外一个块(空闲块) */
  933. return NAND_WriteToNewBlock(ulPhyPageNo, (uint8_t *)_pWriteBuf, usAddrInPage, _usSize);
  934. }
  935. /*
  936. *********************************************************************************************************
  937. * 函 数 名: NAND_Read
  938. * 功能说明: 读一个扇区
  939. * 形 参: _MemAddr : 内存单元偏移地址
  940. * _pReadbuff :存放读出数据的缓冲区的指针
  941. * _usSize :数据长度,必须是4字节的整数倍
  942. * 返 回 值: 执行结果:
  943. * - NAND_FAIL 表示失败
  944. * - NAND_OK 表示成功
  945. *********************************************************************************************************
  946. */
  947. uint8_t NAND_Read(uint32_t _ulMemAddr, uint32_t *_pReadBuf, uint16_t _usSize)
  948. {
  949. uint16_t usPBN; /* 物理块号 */
  950. uint32_t ulPhyPageNo; /* 物理页号 */
  951. uint16_t usAddrInPage; /* 页内偏移地址 */
  952. uint32_t ulTemp;
  953. /* 数据长度必须是4字节整数倍 */
  954. if ((_usSize % 4) != 0)
  955. {
  956. printf_err("Error:1 NAND_Read(_usSize) %d\r\n",_usSize);
  957. return NAND_FAIL;
  958. }
  959. usPBN = NAND_AddrToPhyBlockNo(_ulMemAddr); /* 查询LUT表获得物理块号 */
  960. if (usPBN >= NAND_BLOCK_COUNT)
  961. {
  962. /* 没有格式化,usPBN = 0xFFFF */
  963. printf_err("Error:1 NAND_Write() usPBN %d\r\n",usPBN);
  964. return NAND_FAIL;
  965. }
  966. ulTemp = _ulMemAddr % (NAND_BLOCK_SIZE * NAND_PAGE_SIZE);
  967. ulPhyPageNo = usPBN * NAND_BLOCK_SIZE + ulTemp / NAND_PAGE_SIZE; /* 计算物理页号 */
  968. usAddrInPage = ulTemp % NAND_PAGE_SIZE; /* 计算页内偏移地址 */
  969. if (FSMC_NAND_ReadData((uint8_t *)_pReadBuf, ulPhyPageNo, usAddrInPage, _usSize) == NAND_FAIL)
  970. {
  971. return NAND_FAIL; /* 读NAND Flash失败 */
  972. }
  973. /* 成功 */
  974. return NAND_OK;
  975. }
  976. /*
  977. *********************************************************************************************************
  978. * 函 数 名: NAND_WriteMultiSectors
  979. * 功能说明: 该函数用于文件系统,连续写多个扇区数据。扇区大小可以是512字节或2048字节
  980. * 形 参: _pBuf : 存放数据的缓冲区的指针
  981. * _SectorNo :扇区号
  982. * _SectorSize :每个扇区的大小 (一般是 512字节)
  983. * _SectorCount : 扇区个数
  984. * 返 回 值: 执行结果:
  985. * - NAND_FAIL 表示失败
  986. * - NAND_OK 表示成功
  987. *********************************************************************************************************
  988. */
  989. uint8_t NAND_WriteMultiSectors(uint8_t *_pBuf, uint32_t _SectorNo, uint16_t _SectorSize, uint32_t _SectorCount)
  990. {
  991. uint32_t i;
  992. uint32_t usLBN; /* 逻辑块号 */
  993. uint32_t usPBN; /* 物理块号 */
  994. uint32_t uiPhyPageNo; /* 物理页号 */
  995. uint16_t usAddrInPage; /* 页内偏移地址 */
  996. uint32_t ulTemp;
  997. uint8_t ucReturn;
  998. /*
  999. HY27UF081G2A = 128M Flash. 有 1024个BLOCK, 每个BLOCK包含64个PAGE, 每个PAGE包含2048+64字节,
  1000. 擦除最小单位是BLOCK, 编程最小单位是字节。
  1001. 每个PAGE在逻辑上可以分为4个512字节扇区。
  1002. */
  1003. for (i = 0; i < _SectorCount; i++)
  1004. {
  1005. /* 根据逻辑扇区号和扇区大小计算逻辑块号 */
  1006. //usLBN = (_SectorNo * _SectorSize) / (NAND_BLOCK_SIZE * NAND_PAGE_SIZE);
  1007. /* (_SectorNo * _SectorSize) 乘积可能大于32位,因此换下面这种写法 */
  1008. usLBN = (_SectorNo + i) / (NAND_BLOCK_SIZE * (NAND_PAGE_SIZE / _SectorSize));
  1009. usPBN = NAND_LBNtoPBN(usLBN); /* 查询LUT表获得物理块号 */
  1010. if (usPBN >= NAND_BLOCK_COUNT)
  1011. {
  1012. printf_err("Error1: NAND_WriteMultiSectors(), no format. usLBN=%d, usPBN=%d\r\n", usLBN, usPBN);
  1013. /* 没有格式化,usPBN = 0xFFFF */
  1014. return NAND_FAIL;
  1015. }
  1016. //ulTemp = ((uint64_t)(_SectorNo + i) * _SectorSize) % (NAND_BLOCK_SIZE * NAND_PAGE_SIZE);
  1017. ulTemp = ((_SectorNo + i) % (NAND_BLOCK_SIZE * (NAND_PAGE_SIZE / _SectorSize))) * _SectorSize;
  1018. uiPhyPageNo = usPBN * NAND_BLOCK_SIZE + ulTemp / NAND_PAGE_SIZE; /* 计算物理页号 */
  1019. usAddrInPage = ulTemp % NAND_PAGE_SIZE; /* 计算页内偏移地址 */
  1020. /* 如果 _SectorCount > 0, 并且是页面首地址,则可以进行优化 */
  1021. if (usAddrInPage == 0)
  1022. {
  1023. /* 暂未处理 */
  1024. }
  1025. memset(s_ucTempBuf, 0xFF, _SectorSize);
  1026. /* 如果是全0xFF, 则可以直接写入,无需擦除 */
  1027. //if (NAND_IsBufOk(s_ucTempBuf, _SectorSize, 0xFF) == 1)
  1028. if (FSMC_NAND_CompPage(s_ucTempBuf, uiPhyPageNo, usAddrInPage, _SectorSize) == NAND_OK)
  1029. {
  1030. if (FSMC_NAND_WriteData(&_pBuf[i * _SectorSize], uiPhyPageNo, usAddrInPage, _SectorSize) == NAND_FAIL)
  1031. {
  1032. printf_err("Error3: NAND_WriteMultiSectors(), Write Faile\r\n");
  1033. /* 将数据写入到另外一个块(空闲块) */
  1034. ucReturn = NAND_WriteToNewBlock(uiPhyPageNo, &_pBuf[i * _SectorSize], usAddrInPage, _SectorSize);
  1035. if (ucReturn != NAND_OK)
  1036. {
  1037. printf_err("Error4: NAND_WriteMultiSectors(), Write Faile\r\n");
  1038. return NAND_FAIL; /* 失败 */
  1039. }
  1040. /* 标记源块为坏块 */
  1041. NAND_MarkBadBlock(uiPhyPageNo / NAND_BLOCK_SIZE); /* 将源块标记为坏块 */
  1042. continue;
  1043. }
  1044. /* 标记该块已用 */
  1045. if (NAND_MarkUsedBlock(uiPhyPageNo / NAND_BLOCK_SIZE) == NAND_FAIL)
  1046. {
  1047. /* 标记失败,将数据写入到另外一个块(空闲块) */
  1048. ucReturn = NAND_WriteToNewBlock(uiPhyPageNo, &_pBuf[i * _SectorSize], usAddrInPage, _SectorSize);
  1049. if (ucReturn != NAND_OK)
  1050. {
  1051. return NAND_FAIL; /* 失败 */
  1052. }
  1053. continue;
  1054. }
  1055. }
  1056. else /* 目标区域已经有数据,不是全FF, 则直接将数据写入另外一个空闲块 */
  1057. {
  1058. /* 将数据写入到另外一个块(空闲块) */
  1059. ucReturn = NAND_WriteToNewBlock(uiPhyPageNo, &_pBuf[i * _SectorSize], usAddrInPage, _SectorSize);
  1060. if (ucReturn != NAND_OK)
  1061. {
  1062. printf_err("Error5: NAND_WriteMultiSectors(), Write Faile\r\n");
  1063. return NAND_FAIL; /* 失败 */
  1064. }
  1065. continue;
  1066. }
  1067. }
  1068. return NAND_OK; /* 成功 */
  1069. }
  1070. /*
  1071. *********************************************************************************************************
  1072. * 函 数 名: NAND_ReadMultiSectors
  1073. * 功能说明: 该函数用于文件系统,按扇区读数据。读1个或多个扇区,扇区大小可以是512字节或2048字节
  1074. * 形 参: _pBuf : 存放读出数据的缓冲区的指针
  1075. * _SectorNo :扇区号
  1076. * _SectorSize :每个扇区的大小
  1077. * _SectorCount : 扇区个数
  1078. * 返 回 值: 执行结果:
  1079. * - NAND_FAIL 表示失败
  1080. * - NAND_OK 表示成功
  1081. *********************************************************************************************************
  1082. */
  1083. uint8_t NAND_ReadMultiSectors(uint8_t *_pBuf, uint32_t _SectorNo, uint16_t _SectorSize, uint32_t _SectorCount)
  1084. {
  1085. uint32_t i;
  1086. uint32_t usLBN; /* 逻辑块号 */
  1087. uint32_t usPBN; /* 物理块号 */
  1088. uint32_t uiPhyPageNo; /* 物理页号 */
  1089. uint16_t usAddrInPage; /* 页内偏移地址 */
  1090. uint32_t ulTemp;
  1091. /*
  1092. HY27UF081G2A = 128M Flash. 有 1024个BLOCK, 每个BLOCK包含64个PAGE, 每个PAGE包含2048+64字节,
  1093. 擦除最小单位是BLOCK, 编程最小单位是字节。
  1094. 每个PAGE在逻辑上可以分为4个512字节扇区。
  1095. */
  1096. for (i = 0; i < _SectorCount; i++)
  1097. {
  1098. /* 根据逻辑扇区号和扇区大小计算逻辑块号 */
  1099. //usLBN = (_SectorNo * _SectorSize) / (NAND_BLOCK_SIZE * NAND_PAGE_SIZE);
  1100. /* (_SectorNo * _SectorSize) 乘积可能大于32位,因此换下面这种写法 */
  1101. usLBN = (_SectorNo + i) / (NAND_BLOCK_SIZE * (NAND_PAGE_SIZE / _SectorSize));
  1102. usPBN = NAND_LBNtoPBN(usLBN); /* 查询LUT表获得物理块号 */
  1103. if (usPBN >= NAND_BLOCK_COUNT)
  1104. {
  1105. printf_err("Error: NAND_ReadMultiSectors(), not format, usPBN = %d\r\n", usPBN);
  1106. /* 没有格式化,usPBN = 0xFFFF */
  1107. return NAND_FAIL;
  1108. }
  1109. ulTemp = ((uint64_t)(_SectorNo + i) * _SectorSize) % (NAND_BLOCK_SIZE * NAND_PAGE_SIZE);
  1110. uiPhyPageNo = usPBN * NAND_BLOCK_SIZE + ulTemp / NAND_PAGE_SIZE; /* 计算物理页号 */
  1111. usAddrInPage = ulTemp % NAND_PAGE_SIZE; /* 计算页内偏移地址 */
  1112. if (FSMC_NAND_ReadData((uint8_t *)&_pBuf[i * _SectorSize], uiPhyPageNo, usAddrInPage, _SectorSize) == NAND_FAIL)
  1113. {
  1114. printf_err("Error: NAND_ReadMultiSectors(), ReadData(page = %d, addr = %d)\r\n", uiPhyPageNo, usAddrInPage);
  1115. return NAND_FAIL; /* 读NAND Flash失败 */
  1116. }
  1117. }
  1118. /* 成功 */
  1119. return NAND_OK;
  1120. }
  1121. /*
  1122. *********************************************************************************************************
  1123. * 函 数 名: NAND_BuildLUT
  1124. * 功能说明: 在内存中创建坏块管理表
  1125. * 形 参: ZoneNbr :区号
  1126. * 返 回 值: NAND_OK: 成功; NAND_FAIL:失败
  1127. *********************************************************************************************************
  1128. */
  1129. static uint8_t NAND_BuildLUT(void)
  1130. {
  1131. uint16_t i;
  1132. uint8_t buf[VALID_SPARE_SIZE];
  1133. uint16_t usLBN; /* 逻辑块号 */
  1134. /* */
  1135. for (i = 0; i < NAND_BLOCK_COUNT; i++)
  1136. {
  1137. s_usLUT[i] = 0xFFFF; /* 填充无效值,用于重建LUT后,判断LUT是否合理 */
  1138. }
  1139. for (i = 0; i < NAND_BLOCK_COUNT; i++)
  1140. {
  1141. /* 读每个块的第1个PAGE,偏移地址为LBN0_OFFSET的数据 */
  1142. FSMC_NAND_ReadSpare(buf, i * NAND_BLOCK_SIZE, 0, VALID_SPARE_SIZE);
  1143. /* 如果是好块,则记录LBN0 LBN1 */
  1144. if (buf[BI_OFFSET] == 0xFF)
  1145. {
  1146. usLBN = buf[LBN0_OFFSET] + buf[LBN1_OFFSET] * 256; /* 计算读出的逻辑块号 */
  1147. if (usLBN < NAND_BLOCK_COUNT)
  1148. {
  1149. /* 如果已经登记过了,则判定为异常 */
  1150. if (s_usLUT[usLBN] != 0xFFFF)
  1151. {
  1152. return NAND_FAIL;
  1153. }
  1154. s_usLUT[usLBN] = i; /* 更新LUT表 */
  1155. }
  1156. }
  1157. }
  1158. /* LUT建立完毕,检查是否合理 */
  1159. for (i = 0; i < NAND_BLOCK_COUNT; i++)
  1160. {
  1161. if (s_usLUT[i] >= NAND_BLOCK_COUNT)
  1162. {
  1163. s_usValidDataBlockCount = i;
  1164. break;
  1165. }
  1166. }
  1167. if (s_usValidDataBlockCount < 100)
  1168. {
  1169. /* 错误: 最大的有效逻辑块号小于100。可能是没有格式化 */
  1170. return NAND_FAIL;
  1171. }
  1172. for (; i < s_usValidDataBlockCount; i++)
  1173. {
  1174. if (s_usLUT[i] != 0xFFFF)
  1175. {
  1176. return NAND_FAIL; /* 错误:LUT表逻辑块号存在跳跃现象,可能是没有格式化 */
  1177. }
  1178. }
  1179. /* 重建LUT正常 */
  1180. return NAND_OK;
  1181. }
  1182. /*
  1183. *********************************************************************************************************
  1184. * 函 数 名: NAND_AddrToPhyBlockNo
  1185. * 功能说明: 内存逻辑地址转换为物理块号
  1186. * 形 参: _ulMemAddr:逻辑内存地址
  1187. * 返 回 值: 物理页号, 如果是 0xFFFFFFFF 则表示错误
  1188. *********************************************************************************************************
  1189. */
  1190. static uint16_t NAND_AddrToPhyBlockNo(uint32_t _ulMemAddr)
  1191. {
  1192. uint16_t usLBN; /* 逻辑块号 */
  1193. uint16_t usPBN; /* 物理块号 */
  1194. usLBN = _ulMemAddr / (NAND_BLOCK_SIZE * NAND_PAGE_SIZE); /* 计算逻辑块号 */
  1195. /* 如果逻辑块号大于有效的数据块个数则固定返回0xFFFF, 调用该函数的代码应该检查出这种错误 */
  1196. if (usLBN >= s_usValidDataBlockCount)
  1197. {
  1198. return 0xFFFF;
  1199. }
  1200. /* 查询LUT表,获得物理块号 */
  1201. usPBN = s_usLUT[usLBN];
  1202. return usPBN;
  1203. }
  1204. /*
  1205. *********************************************************************************************************
  1206. * 函 数 名: NAND_LBNtoPBN
  1207. * 功能说明: 逻辑块号转换为物理块号
  1208. * 形 参: _uiLBN : 逻辑块号 Logic Block No
  1209. * 返 回 值: 物理块号, 如果是 0xFFFFFFFF 则表示错误
  1210. *********************************************************************************************************
  1211. */
  1212. static uint16_t NAND_LBNtoPBN(uint32_t _uiLBN)
  1213. {
  1214. uint16_t usPBN; /* 物理块号 */
  1215. /* 如果逻辑块号大于有效的数据块个数则固定返回0xFFFF, 调用该函数的代码应该检查出这种错误 */
  1216. if (_uiLBN >= s_usValidDataBlockCount)
  1217. {
  1218. return 0xFFFF;
  1219. }
  1220. /* 查询LUT表,获得物理块号 */
  1221. usPBN = s_usLUT[_uiLBN];
  1222. return usPBN;
  1223. }
  1224. /*
  1225. *********************************************************************************************************
  1226. * 函 数 名: NAND_FindFreeBlock
  1227. * 功能说明: 从最后一个块开始,查找一个可用的块。A18必须相同
  1228. * 形 参: _ulSrcPageNo : 源页号
  1229. * 返 回 值: 块号,如果是0xFFFF表示失败
  1230. *********************************************************************************************************
  1231. */
  1232. static uint16_t NAND_FindFreeBlock (uint32_t _ulSrcPageNo)
  1233. {
  1234. uint16_t n;
  1235. n = NAND_BLOCK_COUNT - 1;
  1236. if (_ulSrcPageNo & 0x40) /* 需要奇数块 */
  1237. {
  1238. if ((n & 0x01) == 0)
  1239. {
  1240. n--;
  1241. }
  1242. }
  1243. else /* 需要偶数块 */
  1244. {
  1245. if (n & 0x01)
  1246. {
  1247. n--;
  1248. }
  1249. }
  1250. while (1)
  1251. {
  1252. if (NAND_IsFreeBlock(n)) /* 是空闲块 */
  1253. {
  1254. return n;
  1255. }
  1256. if (n < 2)
  1257. {
  1258. return 0xFFFF; /* 没有找到空闲的块 */
  1259. }
  1260. n -= 2;
  1261. }
  1262. }
  1263. /*
  1264. *********************************************************************************************************
  1265. * 函 数 名: NAND_IsBufOk
  1266. * 功能说明: 判断内存缓冲区的数据是否全部为指定值
  1267. * 形 参: - _pBuf : 输入缓冲区
  1268. * - _ulLen : 缓冲区长度
  1269. * - __ucValue : 缓冲区每个单元的正确数值
  1270. * 返 回 值: 1 :全部正确; 0 :不正确
  1271. *********************************************************************************************************
  1272. */
  1273. static uint8_t NAND_IsBufOk(uint8_t *_pBuf, uint32_t _ulLen, uint8_t _ucValue)
  1274. {
  1275. uint32_t i;
  1276. for (i = 0; i < _ulLen; i++)
  1277. {
  1278. if (_pBuf[i] != _ucValue)
  1279. {
  1280. return 0;
  1281. }
  1282. }
  1283. return 1;
  1284. }
  1285. /*
  1286. *********************************************************************************************************
  1287. * 函 数 名: NAND_IsBadBlock
  1288. * 功能说明: 根据坏块标记检测NAND Flash指定的块是否坏块
  1289. * 形 参: _ulBlockNo :块号 0 - 1023 (对于128M字节,2K Page的NAND Flash,有1024个块)
  1290. * 返 回 值: 0 :该块可用; 1 :该块是坏块
  1291. *********************************************************************************************************
  1292. */
  1293. uint8_t NAND_IsBadBlock(uint32_t _ulBlockNo)
  1294. {
  1295. uint8_t ucFlag;
  1296. /* 如果NAND Flash出厂前已经标注为坏块了,则就认为是坏块 */
  1297. FSMC_NAND_ReadSpare(&ucFlag, _ulBlockNo * NAND_BLOCK_SIZE, BI_OFFSET, 1);
  1298. if (ucFlag != 0xFF)
  1299. {
  1300. return 1;
  1301. }
  1302. FSMC_NAND_ReadSpare(&ucFlag, _ulBlockNo * NAND_BLOCK_SIZE + 1, BI_OFFSET, 1);
  1303. if (ucFlag != 0xFF)
  1304. {
  1305. return 1;
  1306. }
  1307. return 0; /* 是好块 */
  1308. }
  1309. /*
  1310. *********************************************************************************************************
  1311. * 函 数 名: NAND_IsFreeBlock
  1312. * 功能说明: 根据坏块标记和USED标志检测是否可用块
  1313. * 形 参: _ulBlockNo :块号 0 - 1023 (对于128M字节,2K Page的NAND Flash,有1024个块)
  1314. * 返 回 值: 1 :该块可用; 0 :该块是坏块或者已占用
  1315. *********************************************************************************************************
  1316. */
  1317. static uint8_t NAND_IsFreeBlock(uint32_t _ulBlockNo)
  1318. {
  1319. uint8_t ucFlag;
  1320. /* 如果NAND Flash出厂前已经标注为坏块了,则就认为是坏块 */
  1321. if (NAND_IsBadBlock(_ulBlockNo))
  1322. {
  1323. return 0;
  1324. }
  1325. //FSMC_NAND_ReadPage(&ucFlag, _ulBlockNo * NAND_BLOCK_SIZE, USED_OFFSET, 1); 2014-05-03 bug
  1326. FSMC_NAND_ReadSpare(&ucFlag, _ulBlockNo * NAND_BLOCK_SIZE, USED_OFFSET, 1);
  1327. if (ucFlag == 0xFF)
  1328. {
  1329. return 1;
  1330. }
  1331. return 0;
  1332. }
  1333. /*
  1334. *********************************************************************************************************
  1335. * 函 数 名: NAND_ScanBlock
  1336. * 功能说明: 扫描测试NAND Flash指定的块
  1337. * 【扫描测试算法】
  1338. * 1) 第1个块(包括主数据区和备用数据区),擦除后检测是否全0xFF, 正确的话继续测试改块,否则该块
  1339. 是坏块,函数返回
  1340. * 2) 当前块写入全 0x00,然后读取检测,正确的话继续测试改块,否则退出
  1341. * 3) 重复第(2)步;如果循环次数达50次都没有发生错误,那么该块正常,函数返回,否则该块是坏块,
  1342. * 函数返回
  1343. * 【注意】
  1344. * 1) 该函数测试完毕后,会删除块内所有数据,即变为全0xFF;
  1345. * 2) 该函数除了测试主数据区外,也对备用数据区进行测试。
  1346. * 3) 擦写测试循环次数可以宏指定。#define BAD_BALOK_TEST_CYCLE 50
  1347. * 形 参: _ulPageNo :页号 0 - 65535 (对于128M字节,2K Page的NAND Flash,有1024个块)
  1348. * 返 回 值: NAND_OK :该块可用; NAND_FAIL :该块是坏块
  1349. *********************************************************************************************************
  1350. */
  1351. uint8_t NAND_ScanBlock(uint32_t _ulBlockNo)
  1352. {
  1353. uint32_t i, k;
  1354. uint32_t ulPageNo;
  1355. #if 0
  1356. /* 如果NAND Flash出厂前已经标注为坏块了,则就认为是坏块 */
  1357. if (NAND_IsBadBlock(_ulBlockNo))
  1358. {
  1359. return NAND_FAIL;
  1360. }
  1361. #endif
  1362. /* 下面的代码将通过反复擦除、编程的方式来测试NAND Flash每个块的可靠性 */
  1363. memset(s_ucTempBuf, 0x00, NAND_PAGE_TOTAL_SIZE);
  1364. for (i = 0; i < BAD_BALOK_TEST_CYCLE; i++)
  1365. {
  1366. /* 第1步:擦除这个块 */
  1367. if (FSMC_NAND_EraseBlock(_ulBlockNo) != NAND_READY)
  1368. {
  1369. return NAND_FAIL;
  1370. }
  1371. /* 第2步:读出块内每个page的数据,并判断是否全0xFF */
  1372. ulPageNo = _ulBlockNo * NAND_BLOCK_SIZE; /* 计算该块第1个页的页号 */
  1373. for (k = 0; k < NAND_BLOCK_SIZE; k++)
  1374. {
  1375. /* 读出整页数据 */
  1376. FSMC_NAND_ReadPage(s_ucTempBuf, ulPageNo, 0, NAND_PAGE_TOTAL_SIZE);
  1377. /* 判断存储单元是不是全0xFF */
  1378. if (NAND_IsBufOk(s_ucTempBuf, NAND_PAGE_TOTAL_SIZE, 0xFF) == 0)
  1379. {
  1380. return NAND_FAIL;
  1381. }
  1382. ulPageNo++; /* 继续写下一个页 */
  1383. }
  1384. /* 第2步:写全0,并读回判断是否全0 */
  1385. ulPageNo = _ulBlockNo * NAND_BLOCK_SIZE; /* 计算该块第1个页的页号 */
  1386. for (k = 0; k < NAND_BLOCK_SIZE; k++)
  1387. {
  1388. /* 填充buf[]缓冲区为全0,并写入NAND Flash */
  1389. memset(s_ucTempBuf, 0x00, NAND_PAGE_TOTAL_SIZE);
  1390. if (FSMC_NAND_WritePage(s_ucTempBuf, ulPageNo, 0, NAND_PAGE_TOTAL_SIZE) != NAND_OK)
  1391. {
  1392. return NAND_FAIL;
  1393. }
  1394. /* 读出整页数据, 判断存储单元是不是全0x00 */
  1395. FSMC_NAND_ReadPage(s_ucTempBuf, ulPageNo, 0, NAND_PAGE_TOTAL_SIZE);
  1396. if (NAND_IsBufOk(s_ucTempBuf, NAND_PAGE_TOTAL_SIZE, 0x00) == 0)
  1397. {
  1398. return NAND_FAIL;
  1399. }
  1400. ulPageNo++; /* 继续一个页 */
  1401. }
  1402. }
  1403. /* 最后一步:擦除整个块 */
  1404. if (FSMC_NAND_EraseBlock(_ulBlockNo) != NAND_READY)
  1405. {
  1406. return NAND_FAIL;
  1407. }
  1408. ulPageNo = _ulBlockNo * NAND_BLOCK_SIZE; /* 计算该块第1个页的页号 */
  1409. for (k = 0; k < NAND_BLOCK_SIZE; k++)
  1410. {
  1411. /* 读出整页数据 */
  1412. FSMC_NAND_ReadPage(s_ucTempBuf, ulPageNo, 0, NAND_PAGE_TOTAL_SIZE);
  1413. /* 判断存储单元是不是全0xFF */
  1414. if (NAND_IsBufOk(s_ucTempBuf, NAND_PAGE_TOTAL_SIZE, 0xFF) == 0)
  1415. {
  1416. return NAND_FAIL;
  1417. }
  1418. ulPageNo++; /* 继续写下一个页 */
  1419. }
  1420. return NAND_OK;
  1421. }
  1422. /*
  1423. *********************************************************************************************************
  1424. * 函 数 名: NAND_MarkUsedBlock
  1425. * 功能说明: 标记NAND Flash指定的块为已用块
  1426. * 形 参: _ulBlockNo :块号 0 - 1023 (对于128M字节,2K Page的NAND Flash,有1024个块)
  1427. * 返 回 值: NAND_OK:标记成功; NAND_FAIL:标记失败,上级软件应该进行坏块处理。
  1428. *********************************************************************************************************
  1429. */
  1430. static uint8_t NAND_MarkUsedBlock(uint32_t _ulBlockNo)
  1431. {
  1432. uint32_t ulPageNo;
  1433. uint8_t ucFlag;
  1434. /* 计算块的第1个页号 */
  1435. ulPageNo = _ulBlockNo * NAND_BLOCK_SIZE; /* 计算该块第1个页的页号 */
  1436. /* 块内第1个page备用区的第USED_OFFSET个字节写入非0xFF数据表示已用块 */
  1437. ucFlag = NAND_USED_BLOCK_FLAG;
  1438. if (FSMC_NAND_WriteSpare(&ucFlag, ulPageNo, USED_OFFSET, 1) == NAND_FAIL)
  1439. {
  1440. /* 如果标记失败,则需要标注这个块为坏块 */
  1441. return NAND_FAIL;
  1442. }
  1443. return NAND_OK;
  1444. }
  1445. /*
  1446. *********************************************************************************************************
  1447. * 函 数 名: NAND_MarkBadBlock
  1448. * 功能说明: 标记NAND Flash指定的块为坏块
  1449. * 形 参: _ulBlockNo :块号 0 - 1023 (对于128M字节,2K Page的NAND Flash,有1024个块)
  1450. * 返 回 值: 固定NAND_OK
  1451. *********************************************************************************************************
  1452. */
  1453. void NAND_MarkBadBlock(uint32_t _ulBlockNo)
  1454. {
  1455. uint32_t ulPageNo;
  1456. uint8_t ucFlag;
  1457. printf_err("NAND_MarkBadBlock(%d)\r\n", _ulBlockNo);
  1458. /* 计算块的第1个页号 */
  1459. ulPageNo = _ulBlockNo * NAND_BLOCK_SIZE; /* 计算该块第1个页的页号 */
  1460. /* 块内第1个page备用区的第BI_OFFSET个字节写入非0xFF数据表示坏块 */
  1461. ucFlag = NAND_BAD_BLOCK_FLAG;
  1462. if (FSMC_NAND_WriteSpare(&ucFlag, ulPageNo, BI_OFFSET, 1) == NAND_FAIL)
  1463. {
  1464. /* 如果第1个页标记失败,则在第2个页标记 */
  1465. FSMC_NAND_WriteSpare(&ucFlag, ulPageNo + 1, BI_OFFSET, 1);
  1466. }
  1467. }
  1468. /*
  1469. *********************************************************************************************************
  1470. * 函 数 名: NAND_ScanAllBadBlock
  1471. * 功能说明: 扫描测试所有的BLOCK, 如果是坏块,则做坏块标记
  1472. * 形 参: _ulBlockNo :块号 0 - 1023 (对于128M字节,2K Page的NAND Flash,有1024个块)
  1473. * 返 回 值: 固定NAND_OK
  1474. *********************************************************************************************************
  1475. */
  1476. void NAND_ScanAllBadBlock(void)
  1477. {
  1478. uint32_t i;
  1479. for (i = 0; i < NAND_BLOCK_COUNT; i++)
  1480. {
  1481. if (NAND_ScanBlock(i) == NAND_OK)
  1482. {
  1483. printf("Scan Block %d (%d%%), Ok\r\n", i, i * 100 / NAND_BLOCK_COUNT);
  1484. }
  1485. else
  1486. {
  1487. printf("Scan Block %d (%d%%), Err\r\n", i, i * 100 / NAND_BLOCK_COUNT);
  1488. NAND_MarkBadBlock(i);
  1489. }
  1490. }
  1491. }
  1492. /*
  1493. *********************************************************************************************************
  1494. * 函 数 名: NAND_Format
  1495. * 功能说明: NAND Flash格式化,擦除所有的数据,重建LUT
  1496. * 形 参: 无
  1497. * 返 回 值: NAND_OK : 成功; NAND_Fail :失败(一般是坏块数量过多导致)
  1498. *********************************************************************************************************
  1499. */
  1500. uint8_t NAND_Format(void)
  1501. {
  1502. uint16_t i, n;
  1503. uint16_t usGoodBlockCount;
  1504. /* 擦除每个块 */
  1505. usGoodBlockCount = 0;
  1506. for (i = 0; i < NAND_BLOCK_COUNT; i++)
  1507. {
  1508. FSMC_NAND_EraseBlock(i);
  1509. /* 如果是好块,则擦除 */
  1510. if (!NAND_IsBadBlock(i))
  1511. {
  1512. FSMC_NAND_EraseBlock(i);
  1513. usGoodBlockCount++;
  1514. }
  1515. }
  1516. /* 如果好块的数量少于100,则NAND Flash报废 */
  1517. if (usGoodBlockCount < 100)
  1518. {
  1519. return NAND_FAIL;
  1520. }
  1521. usGoodBlockCount = (usGoodBlockCount * 98) / 100; /* 98%的好块用于存储数据 */
  1522. /* 重新搜索一次 */
  1523. n = 0; /* 统计已标注的好块 */
  1524. for (i = 0; i < NAND_BLOCK_COUNT; i++)
  1525. {
  1526. if (!NAND_IsBadBlock(i))
  1527. {
  1528. /* 如果是好块,则在该块的第1个PAGE的LBN0 LBN1处写入n值 (前面已经执行了块擦除) */
  1529. if (FSMC_NAND_WriteSpare((uint8_t *)&n, i * NAND_BLOCK_SIZE, LBN0_OFFSET, 2) != NAND_OK)
  1530. {
  1531. return NAND_FAIL;
  1532. }
  1533. n++;
  1534. /* 计算并写入每个扇区的ECC值 (暂时未作)*/
  1535. if (n == usGoodBlockCount)
  1536. {
  1537. break;
  1538. }
  1539. }
  1540. }
  1541. NAND_BuildLUT(); /* 初始化LUT表 */
  1542. return NAND_OK;
  1543. }
  1544. /*
  1545. *********************************************************************************************************
  1546. * 函 数 名: NAND_FormatCapacity
  1547. * 功能说明: NAND Flash格式化后的有效容量. (最大支持4G)
  1548. * 形 参: 无
  1549. * 返 回 值: NAND_OK : 成功; NAND_Fail :失败(一般是坏块数量过多导致)
  1550. *********************************************************************************************************
  1551. */
  1552. uint32_t NAND_FormatCapacity(void)
  1553. {
  1554. uint16_t usCount;
  1555. /* 计算用于存储数据的数据块个数,按照总有效块数的98%来计算 */
  1556. usCount = (s_usValidDataBlockCount * DATA_BLOCK_PERCENT) / 100;
  1557. return (usCount * NAND_BLOCK_SIZE * NAND_PAGE_SIZE);
  1558. }
  1559. /*
  1560. *********************************************************************************************************
  1561. * 函 数 名: NAND_DispBadBlockInfo
  1562. * 功能说明: 通过串口打印出NAND Flash的坏块信息
  1563. * 形 参: 无
  1564. * 返 回 值: 无
  1565. *********************************************************************************************************
  1566. */
  1567. void NAND_DispBadBlockInfo(void)
  1568. {
  1569. uint32_t id;
  1570. uint32_t i;
  1571. uint32_t n;
  1572. uint32_t used = 0;
  1573. uint16_t bad_no[128];
  1574. FSMC_NAND_Init(); /* 初始化FSMC */
  1575. id = NAND_ReadID();
  1576. printf("NAND Flash ID = 0x%04X, Type = ", id);
  1577. if (id == HY27UF081G2A)
  1578. {
  1579. printf("HY27UF081G2A\r\n 1024 Blocks, 64 pages per block, 2048 + 64 bytes per page\r\n");
  1580. }
  1581. else if (id == K9F1G08U0A)
  1582. {
  1583. printf("K9F1G08U0A\r\n 1024 Blocks, 64 pages per block, 2048 + 64 bytes per page\r\n");
  1584. }
  1585. else if (id == K9F1G08U0B)
  1586. {
  1587. printf("K9F1G08U0B\r\n 1024 Blocks, 64 pages per block, 2048 + 64 bytes per page\r\n");
  1588. }
  1589. else if (id == H27U4G8F2DTR)
  1590. {
  1591. printf("H27U4G8F2DTR\r\n 4096 Blocks, 64 pages per block, 2048 + 64 bytes per page\r\n");
  1592. }
  1593. else if (id == H27U1G8F2BTR)
  1594. {
  1595. printf("H27U1G8F2BTR\r\n 1024 Blocks, 64 pages per block, 2048 + 64 bytes per page\r\n");
  1596. }
  1597. else
  1598. {
  1599. printf("unkonow\r\n");
  1600. return;
  1601. }
  1602. FSMC_NAND_Reset();
  1603. printf("Block Info : 0 is OK, * is Bad, - is Used\r\n");
  1604. n = 0; /* 坏块统计 */
  1605. used = 0; /* 已用块统计 */
  1606. for (i = 0; i < NAND_BLOCK_COUNT; i++)
  1607. {
  1608. if (NAND_IsBadBlock(i))
  1609. {
  1610. if (n < sizeof(bad_no) / 2)
  1611. {
  1612. bad_no[n] = i; /* 记录坏块号 */
  1613. }
  1614. printf("*");
  1615. n++;
  1616. }
  1617. else
  1618. {
  1619. if (NAND_IsFreeBlock(i))
  1620. {
  1621. printf("0");
  1622. }
  1623. else
  1624. {
  1625. printf("-"); /* 已用块 */
  1626. used++;
  1627. }
  1628. }
  1629. if (((i + 1) % 8) == 0)
  1630. {
  1631. printf(" ");
  1632. }
  1633. if (((i + 1) % 64) == 0)
  1634. {
  1635. printf("\r\n");
  1636. }
  1637. }
  1638. if (id == H27U4G8F2DTR)
  1639. {
  1640. printf("Bad Block Count = %d ( < 80 is OK), Used = %d \r\n", n, used);
  1641. }
  1642. else
  1643. {
  1644. printf("Bad Block Count = %d\r\n", n);
  1645. }
  1646. /* 打印坏块序号 */
  1647. if (n > 0)
  1648. {
  1649. for (i = 0; i < n; i++)
  1650. {
  1651. printf("%4d ", bad_no[i]);
  1652. }
  1653. printf("\r\n\r\n");
  1654. }
  1655. }
  1656. /*
  1657. *********************************************************************************************************
  1658. * 函 数 名: NAND_GetBlockInfo
  1659. * 功能说明: 获得NAND 坏块、已用块信息
  1660. * 形 参: 无
  1661. * 返 回 值: 1 表示成功识别, 0 表示识别失败
  1662. *********************************************************************************************************
  1663. */
  1664. uint8_t NAND_GetBlockInfo(NAND_BLOCK_INFO_T *_pInfo)
  1665. {
  1666. uint32_t id;
  1667. uint32_t i;
  1668. uint32_t n;
  1669. uint32_t used = 0;
  1670. uint32_t free = 0;
  1671. FSMC_NAND_Init(); /* 初始化FSMC */
  1672. id = NAND_ReadID();
  1673. _pInfo->ChipID = id;
  1674. if (id == HY27UF081G2A)
  1675. {
  1676. _pInfo->ChipID = HY27UF081G2A;
  1677. strcpy(_pInfo->ChipName, "HY27UF081G2A");
  1678. }
  1679. else if (id == K9F1G08U0A)
  1680. {
  1681. _pInfo->ChipID = K9F1G08U0A;
  1682. strcpy(_pInfo->ChipName, "K9F1G08U0A");
  1683. }
  1684. else if (id == K9F1G08U0B)
  1685. {
  1686. _pInfo->ChipID = K9F1G08U0B;
  1687. strcpy(_pInfo->ChipName, "K9F1G08U0B");
  1688. }
  1689. else if (id == H27U4G8F2DTR)
  1690. {
  1691. _pInfo->ChipID = H27U4G8F2DTR;
  1692. strcpy(_pInfo->ChipName, "H27U4G8F2DTR");
  1693. }
  1694. else if (id == H27U1G8F2BTR)
  1695. {
  1696. _pInfo->ChipID = H27U1G8F2BTR;
  1697. strcpy(_pInfo->ChipName, "H27U1G8F2BTR");
  1698. }
  1699. else
  1700. {
  1701. return 0;
  1702. }
  1703. FSMC_NAND_Reset();
  1704. n = 0; /* 坏块统计 */
  1705. used = 0; /* 已用块统计 */
  1706. free = 0; /* 未用的好块 */
  1707. for (i = 0; i < NAND_BLOCK_COUNT; i++)
  1708. {
  1709. if (NAND_IsBadBlock(i))
  1710. {
  1711. n++; /* 记录坏块 */
  1712. }
  1713. else
  1714. {
  1715. if (NAND_IsFreeBlock(i))
  1716. {
  1717. free++;
  1718. }
  1719. else
  1720. {
  1721. used++; /* 已用块 */
  1722. }
  1723. }
  1724. }
  1725. _pInfo->Bad = n;
  1726. _pInfo->Used = used;
  1727. _pInfo->Free = free;
  1728. return 1;
  1729. }
  1730. /*
  1731. *********************************************************************************************************
  1732. * 函 数 名: NAND_DispPhyPageData
  1733. * 功能说明: 通过串口打印出指定页的数据(2048+64)
  1734. * 形 参: _uiPhyPageNo : 物理页号
  1735. * 返 回 值: 无
  1736. *********************************************************************************************************
  1737. */
  1738. void NAND_DispPhyPageData(uint32_t _uiPhyPageNo)
  1739. {
  1740. uint32_t i, n;
  1741. uint32_t ulBlockNo;
  1742. uint16_t usOffsetPageNo;
  1743. ulBlockNo = _uiPhyPageNo / NAND_BLOCK_SIZE; /* 根据物理页号反推块号 */
  1744. usOffsetPageNo = _uiPhyPageNo % NAND_BLOCK_SIZE; /* 根据物理页号计算物理页号在块内偏移页号 */
  1745. if (NAND_OK != FSMC_NAND_ReadPage(s_ucTempBuf, _uiPhyPageNo, 0, NAND_PAGE_TOTAL_SIZE))
  1746. {
  1747. printf("FSMC_NAND_ReadPage Failed() \r\n");
  1748. return;
  1749. }
  1750. printf("Block = %d, Page = %d\r\n", ulBlockNo, usOffsetPageNo);
  1751. /* 打印前面 2048字节数据,每512字节空一行 */
  1752. for (n = 0; n < 4; n++)
  1753. {
  1754. for (i = 0; i < 512; i++)
  1755. {
  1756. printf(" %02X", s_ucTempBuf[i + n * 512]);
  1757. if ((i & 31) == 31)
  1758. {
  1759. printf("\r\n"); /* 每行显示32字节数据 */
  1760. }
  1761. else if ((i & 31) == 15)
  1762. {
  1763. printf(" - ");
  1764. }
  1765. }
  1766. printf("\r\n");
  1767. }
  1768. /* 打印前面 2048字节数据,每512字节空一行 */
  1769. for (i = 0; i < 64; i++)
  1770. {
  1771. printf(" %02X", s_ucTempBuf[i + 2048]);
  1772. if ((i & 15) == 15)
  1773. {
  1774. printf("\r\n"); /* 每行显示32字节数据 */
  1775. }
  1776. }
  1777. }
  1778. /*
  1779. *********************************************************************************************************
  1780. * 函 数 名: NAND_DispLogicPageData
  1781. * 功能说明: 通过串口打印出指定页的数据(2048+64)
  1782. * 形 参: _uiLogicPageNo : 逻辑页号
  1783. * 返 回 值: 无
  1784. *********************************************************************************************************
  1785. */
  1786. void NAND_DispLogicPageData(uint32_t _uiLogicPageNo)
  1787. {
  1788. uint32_t uiPhyPageNo;
  1789. uint16_t usLBN; /* 逻辑块号 */
  1790. uint16_t usPBN; /* 物理块号 */
  1791. usLBN = _uiLogicPageNo / NAND_BLOCK_SIZE;
  1792. usPBN = NAND_LBNtoPBN(usLBN); /* 查询LUT表获得物理块号 */
  1793. if (usPBN >= NAND_BLOCK_COUNT)
  1794. {
  1795. /* 没有格式化,usPBN = 0xFFFF */
  1796. return;
  1797. }
  1798. printf("LogicBlock = %d, PhyBlock = %d\r\n", _uiLogicPageNo, usPBN);
  1799. /* 计算物理页号 */
  1800. uiPhyPageNo = usPBN * NAND_BLOCK_SIZE + _uiLogicPageNo % NAND_BLOCK_SIZE;
  1801. NAND_DispPhyPageData(uiPhyPageNo); /* 显示指定页数据 */
  1802. }
  1803. /*
  1804. *********************************************************************************************************
  1805. * 函 数 名: NAND_ReadONFI
  1806. * 功能说明: 读NAND Flash的ONFI信息, 针对 H27U4G8F2DTR
  1807. * 形 参: _pBuf 存放结果的缓冲区, 大小4字节。应该固定返回 "ONFI" 字符串
  1808. * 返 回 值: 无
  1809. *********************************************************************************************************
  1810. */
  1811. void NAND_ReadONFI(uint8_t *_pBuf)
  1812. {
  1813. uint16_t i;
  1814. /* 发送命令 Command to the command area */
  1815. NAND_CMD_AREA = 0x90;
  1816. NAND_ADDR_AREA = 0x20;
  1817. /* 读数据到缓冲区pBuffer */
  1818. for(i = 0; i < 256; i++)
  1819. {
  1820. _pBuf[i] = NAND_DATA_AREA;
  1821. }
  1822. }
  1823. /*
  1824. *********************************************************************************************************
  1825. * 函 数 名: NAND_ReadParamPage
  1826. * 功能说明: Read Parameter Page, 针对 H27U4G8F2DTR
  1827. * 形 参: _pData 存放结果的缓冲区。
  1828. * 返 回 值: 无
  1829. *********************************************************************************************************
  1830. */
  1831. void NAND_ReadParamPage(PARAM_PAGE_T *_pData)
  1832. {
  1833. uint16_t i;
  1834. uint8_t *_pBuf = (uint8_t *)_pData;
  1835. /* 发送命令 Command to the command area */
  1836. NAND_CMD_AREA = 0xEC;
  1837. NAND_ADDR_AREA = 0x00;
  1838. /* 必须等待,否则读出数据异常, 此处应该判断超时 */
  1839. for (i = 0; i < 20; i++);
  1840. while( GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_6) == 0);
  1841. /* 读数据到缓冲区pBuffer */
  1842. for(i = 0; i < 256; i++)
  1843. {
  1844. _pBuf[i] = NAND_DATA_AREA;
  1845. }
  1846. }
  1847. /*
  1848. *********************************************************************************************************
  1849. * 函 数 名: NAND_DispParamPage
  1850. * 功能说明: 通过串口打印 Parameter Page Data Structure Definition (参数页数据结构) 针对 H27U4G8F2DTR
  1851. * 形 参: 无
  1852. * 返 回 值: 无
  1853. *********************************************************************************************************
  1854. */
  1855. void NAND_DispParamPage(void)
  1856. {
  1857. PARAM_PAGE_T tPage;
  1858. char buf[32];
  1859. FSMC_NAND_Reset();
  1860. NAND_ReadParamPage(&tPage);
  1861. #if 0
  1862. uint8_t Sign[4]; /* = "ONFI" */
  1863. uint16_t Revision; /* Bit1 = 1 表示支持 ONFI Ver 1.0 */
  1864. uint16_t Features; /* */
  1865. uint16_t OptionalCommands;
  1866. #endif
  1867. printf("\r\n");
  1868. printf("Read Parameter Page Data :\r\n");
  1869. printf("Sign = %c%c%c%c\r\n", tPage.Sign[0], tPage.Sign[1], tPage.Sign[2], tPage.Sign[3]);
  1870. printf("Revision = %04X\r\n", tPage.Revision);
  1871. printf("Features = %04X\r\n", tPage.Features);
  1872. printf("OptionalCommands = %04X\r\n", tPage.OptionalCommands);
  1873. /* Manufacturer information block */
  1874. memcpy(buf, tPage.Manufacturer, 12);
  1875. buf[12] = 0;
  1876. printf("Manufacturer = %s\r\n", buf); /* 制造商 */
  1877. memcpy(buf, tPage.Model, 20);
  1878. buf[20] = 0;
  1879. printf("Model = %s\r\n", buf); /* 型号 */
  1880. printf("JEDEC_ID = %02X\r\n", tPage.JEDEC_ID); /* AD */
  1881. printf("DateCode = %04X\r\n", tPage.DateCode);
  1882. #if 0
  1883. /* Memory organization block */
  1884. uint32_t PageDataSize;
  1885. uint16_t PageSpareSize;
  1886. uint32_t PartialPageDataSize;
  1887. uint16_t PartialPageSpareSize;
  1888. uint32_t BlockSize;
  1889. uint32_t LogicalUnitSize;
  1890. uint8_t LogicalUnitNumber;
  1891. uint8_t AddressCycles;
  1892. uint8_t CellBits;
  1893. uint16_t BadBlockMax;
  1894. uint16_t BlockEndurance;
  1895. uint8_t ValidBlocksBegin; /* 最前面保证有效的块个数 */
  1896. uint16_t BlockEndurance2; /* Block endurance for guaranteed valid blocks */
  1897. uint8_t ProgramsPerPage; /* Number of programs per page */
  1898. uint8_t PartialProgram;
  1899. uint8_t ECCcorrectBits;
  1900. uint8_t InterleavedAddrBits; /* 交错的地址位 */
  1901. uint8_t InterleavedOperaton;
  1902. uint8_t Rsv3[13];
  1903. #endif
  1904. printf("\r\n");
  1905. }
  1906. /***************************** 安富莱电子 www.armfly.com (END OF FILE) *********************************/