nand_flash.c 63 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632
  1. /*
  2. *********************************************************************************************************
  3. *
  4. * 模块名称 : NAND Flash驱动模块
  5. * 文件名称 : bsp_nand.c
  6. * 版 本 : V1.0
  7. * 说 明 : 提供NAND Flash (HY27UF081G2A, 8bit 128K字节 大页)的底层接口函数。【安富莱原创】
  8. *
  9. * 修改记录 :
  10. * 版本号 日期 作者 说明
  11. * V1.0 2013-02-01 armfly 正式发布
  12. *
  13. * Copyright (C), 2013-2014, 安富莱电子 www.armfly.com
  14. *
  15. *********************************************************************************************************
  16. */
  17. #include "nand_flash.h"
  18. /*
  19. 如果在IAR或KEIL的编辑器中阅读,请将编辑器的字体设置为新宋体(9号/五号),缩进的TAB设置为4。
  20. 否则,方框处出现不对齐的问题。
  21. 【待完善的地方】
  22. (1)在操作NAND Flash时,如下语句是一个死循环。如果硬件出现异常,将导致软件死机
  23. while( GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_6) == 0 )
  24. (2)没有增加ECC校验功能。ECC可以检查1个或2个bit错误,如果只有1个bit错误,则可以修复这个bit。如果
  25. 多余2个bit错误,则可能检测不到。
  26. (3)正常写文件操作时,会导致重建LUT。目前,重建LUT的代码执行效率还不够高,有待完善。
  27. 【硬件说明】
  28. 安富莱STM32F103ZE-EK开发板配置的NAND Flahs为海力士的HY27UF081G2A
  29. (1)NAND Flash的片选信号连接到CPU的FSMC_NCE2,这决定了NAND Flash的地址空间为 0x70000000(见CPU的数据
  30. 手册的FSMC章节)
  31. (2)有FSMC总线上有多个总线设备(如TFT、SRAM、CH374T、NOR),因此必须确保其他总线设备的片选处于禁止
  32. 状态,否则将出现总线冲突问题 (参见本文件初始化FSMC GPIO的函数)
  33. 【NAND Flash 结构定义】
  34. 备用区有16x4字节,每page 1024字节,每512字节一个扇区,每个扇区对应16自己的备用区:
  35. 每个PAGE的逻辑结构,前面512Bx4是主数据区,后面16Bx4是备用区
  36. ┌──────┐┌──────┐┌──────┐┌──────┐┌──────┐┌──────┐┌──────┐┌──────┐
  37. │ Main area ││ Main area ││ Main area ││Main area ││ Spare area ││ Spare area ││ Spare area ││Spare area │
  38. │ ││ ││ ││ ││ ││ ││ ││ │
  39. │ 512B ││ 512B ││ 512B ││ 512B ││ 16B ││ 16B ││ 16B ││ 16B │
  40. └──────┘└──────┘└──────┘└──────┘└──────┘└──────┘└──────┘└──────┘
  41. 每16B的备用区的逻辑结构如下:(三星推荐标准)
  42. ┌───┐┌───┐┌──┐┌──┐┌──┐┌───┐┌───┐┌───┐┌──┐┌──┐┌──┐┌──┐┌───┐┌───┐┌───┐┌───┐┌───┐
  43. │ BI ││RESER ││LSN0││LSN1││LSN2││RESER ││RESER ││RESER ││ECC0││ECC1││ECC2││ECC0││S-ECC1││S-ECC0││RESER ││RESER ││RESER │
  44. │ ││ VED ││ ││ ││ ││ VED ││ VED ││ VED ││ ││ ││ ││ ││ ││ ││ VED ││ VED ││ VED │
  45. └───┘└───┘└──┘└──┘└──┘└───┘└───┘└───┘└──┘└──┘└──┘└──┘└───┘└───┘└───┘└───┘└───┘
  46. K9F1G08U0A 和 HY27UF081G2A 是兼容的。芯片出厂时,厂商保证芯片的第1个块是好块。如果是坏块,则在该块的第1个PAGE的第1个字节
  47. 或者第2个PAGE(当第1个PAGE坏了无法标记为0xFF时)的第1个字节写入非0xFF值。坏块标记值是随机的,软件直接判断是否等于0xFF即可。
  48. 注意:网上有些资料说NAND Flash厂商的默认做法是将坏块标记定在第1个PAGE的第6个字节处。这个说法是错误。坏块标记在第6个字节仅针对部分小扇区(512字节)的NAND Flash
  49. 并不是所有的NAND Flash都是这个标准。大家在更换NAND Flash时,请仔细阅读芯片的数据手册。
  50. 为了便于在NAND Flash 上移植Fat文件系统,我们对16B的备用区采用以下分配方案:
  51. ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌───┐┌───┐┌──┐┌──┐┌──┐┌──┐
  52. │ BI ││USED││LBN0││LBN1││ECC0││ECC1││ECC2││ECC3││ECC4││ECC5││S-ECC1││S-ECC0││RSVD││RSVD││RSVD││RSVD│
  53. │ ││ ││ ││ ││ ││ ││ ││ ││ ││ ││ ││ ││ ││ ││ ││ │
  54. └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└───┘└───┘└──┘└──┘└──┘└──┘
  55. - BI : 坏块标志(Bad Block Identifier)。每个BLOCK的第1个PAGE或者第2个PAGE的第1个字节指示该块是否坏块。0xFF表示好块,不是0xFF表示坏块。
  56. - USED : 该块使用标志。0xFF表示空闲块;0xF0表示已用块。
  57. - LBN0 LBN1 : 逻辑块号(Logic Block No) 。从0开始编码。只在每个BLOCK的第1个PAGE有效,其它PAGE该字段固定为0xFF FF
  58. - ECC0 ~ ECC6 : 512B主数据区的ECC校验 (按照三星提供ECC算法,256字节对应3个字节的ECC)
  59. - S-ECC1 S-ECC0 : LSN0和LSN2的ECC校验
  60. - RSVD : 保留字节,Reserved
  61. 【坏块管理 & 磨损平衡】
  62. (1) 内部全局数组s_usLUT[]按次序保存物理块号。用于物理块和逻辑块的地址映射。
  63. (2) 格式化时,将98%的好块用于主数据存储。剩余的2%用于备用区(坏块替换)。
  64. (3) 写扇区(512B)时,如果扇区内容为空,则直接写入,减少不必要的块擦除操作。有效提高NAND Flash的寿命和读写性能。
  65. (4) 写扇区时,如果扇区内容不为空,则从末尾开始查找一个空闲块替换掉旧块,替换并改写数据完成后,将旧块擦除,并标注为空闲,之后重建LUT。
  66. (5) 块复制时,充分利用NAND Flash硬件的Copy-Back功能,无需读源页到内存再写入目标页。这样可显著提高读写效率。
  67. (6) 磨损平衡还存在缺陷,效果不好。ECC校验暂未实现。
  68. */
  69. /* 定义NAND Flash的物理地址。这个是由硬件决定的 */
  70. #define Bank2_NAND_ADDR ((uint32_t)0x70000000)
  71. #define Bank_NAND_ADDR Bank2_NAND_ADDR
  72. /* 定义操作NAND Flash用到3个宏 */
  73. #define NAND_CMD_AREA *(__IO uint8_t *)(Bank_NAND_ADDR | CMD_AREA)
  74. #define NAND_ADDR_AREA *(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA)
  75. #define NAND_DATA_AREA *(__IO uint8_t *)(Bank_NAND_ADDR | DATA_AREA)
  76. /* 逻辑块号映射表。好块总数的2%用于备份区,因此数组维数低于1024。 LUT = Look Up Table */
  77. static uint16_t s_usLUT[NAND_BLOCK_COUNT];
  78. static uint16_t s_usValidDataBlockCount; /* 有效的数据块个数 */
  79. static uint8_t s_ucTempBuf[NAND_PAGE_TOTAL_SIZE]; /* 大缓冲区,2112字节. 用于读出比较 */
  80. static uint8_t NAND_BuildLUT(void);
  81. static uint8_t FSMC_NAND_GetStatus(void);
  82. static uint16_t NAND_FindFreeBlock(void);
  83. static uint8_t NAND_MarkUsedBlock(uint32_t _ulBlockNo);
  84. static void NAND_MarkBadBlock(uint32_t _ulBlockNo);
  85. static uint16_t NAND_AddrToPhyBlockNo(uint32_t _ulMemAddr);
  86. static uint8_t NAND_IsBufOk(uint8_t *_pBuf, uint32_t _ulLen, uint8_t _ucValue);
  87. uint8_t NAND_WriteToNewBlock(uint32_t _ulPhyPageNo, uint8_t *_pWriteBuf, uint16_t _usOffset, uint16_t _usSize);
  88. static uint8_t NAND_IsFreeBlock(uint32_t _ulBlockNo);
  89. static uint16_t NAND_LBNtoPBN(uint32_t _uiLBN);
  90. /*
  91. *********************************************************************************************************
  92. * 函 数 名: FSMC_NAND_Init
  93. * 功能说明: 配置FSMC和GPIO用于NAND Flash接口。这个函数必须在读写nand flash前被调用一次。
  94. * 形 参: 无
  95. * 返 回 值: 无
  96. *********************************************************************************************************
  97. */
  98. static void FSMC_NAND_Init(void)
  99. {
  100. FSMC_NANDInitTypeDef FSMC_NANDInitStructure;
  101. FSMC_NAND_PCCARDTimingInitTypeDef p;
  102. /*--NAND Flash GPIOs 配置 ------
  103. PD0/FSMC_D2
  104. PD1/FSMC_D3
  105. PD4/FSMC_NOE
  106. PD5/FSMC_NWE
  107. PD7/FSMC_NCE2
  108. PD11/FSMC_A16
  109. PD12/FSMC_A17
  110. PD14/FSMC_D0
  111. PD15/FSMC_D1
  112. PE7/FSMC_D4
  113. PE8/FSMC_D5
  114. PE9/FSMC_D6
  115. PE10/FSMC_D7
  116. PG6/FSMC_INT2 (本例程用查询方式判忙,此口线作为普通GPIO输入功能使用)
  117. */
  118. /* 配置GPIOG, PG6作为忙信息,配置为输入 */
  119. /* INT2 引脚配置为内部上来输入,用于忙信号 */
  120. /* 配置 FSMC 时序 */
  121. /*
  122. Defines the number of HCLK cycles to setup address before the command assertion for NAND-Flash
  123. read or write access to common/Attribute or I/O memory space (depending on the memory space
  124. timing to be configured).This parameter can be a value between 0 and 0xFF.
  125. */
  126. // p.FSMC_SetupTime = 0x01;
  127. p.FSMC_SetupTime = 0x1;
  128. /*
  129. Defines the minimum number of HCLK cycles to assert the command for NAND-Flash read or write
  130. access to common/Attribute or I/O memory space (depending on the memory space timing to be
  131. configured). This parameter can be a number between 0x00 and 0xFF
  132. */
  133. // p.FSMC_WaitSetupTime = 0x03;
  134. p.FSMC_WaitSetupTime = 0x3;
  135. /*
  136. Defines the number of HCLK clock cycles to hold address (and data for write access) after the
  137. command deassertion for NAND-Flash read or write access to common/Attribute or I/O memory space
  138. (depending on the memory space timing to be configured).
  139. This parameter can be a number between 0x00 and 0xFF
  140. */
  141. // p.FSMC_HoldSetupTime = 0x02;
  142. p.FSMC_HoldSetupTime = 0x2;
  143. /*
  144. Defines the number of HCLK clock cycles during which the databus is kept in HiZ after the start
  145. of a NAND-Flash write access to common/Attribute or I/O memory space (depending on the memory
  146. space timing to be configured). This parameter can be a number between 0x00 and 0xFF
  147. */
  148. // p.FSMC_HiZSetupTime = 0x01;
  149. p.FSMC_HiZSetupTime = 0x1;
  150. FSMC_NANDInitStructure.FSMC_Bank = FSMC_Bank2_NAND; /* 定义FSMC NAND BANK 号 */
  151. FSMC_NANDInitStructure.FSMC_Waitfeature = FSMC_Waitfeature_Disable; /* 插入等待时序使能 */
  152. FSMC_NANDInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_8b; /* 数据宽度 8bit */
  153. FSMC_NANDInitStructure.FSMC_ECC = FSMC_ECC_Enable; /* ECC错误检查和纠正功能使能 */
  154. FSMC_NANDInitStructure.FSMC_ECCPageSize = FSMC_ECCPageSize_2048Bytes; /* ECC 页面大小 */
  155. FSMC_NANDInitStructure.FSMC_TCLRSetupTime = 0x01; /* CLE低和RE低之间的延迟,HCLK周期数 */
  156. FSMC_NANDInitStructure.FSMC_TARSetupTime = 0x01; /* ALE低和RE低之间的延迟,HCLK周期数 */
  157. FSMC_NANDInitStructure.FSMC_CommonSpaceTimingStruct = &p; /* FSMC Common Space Timing */
  158. FSMC_NANDInitStructure.FSMC_AttributeSpaceTimingStruct = &p; /* FSMC Attribute Space Timing */
  159. FSMC_NANDInit(&FSMC_NANDInitStructure);
  160. /* FSMC NAND Bank 使能 */
  161. FSMC_NANDCmd(FSMC_Bank2_NAND, ENABLE);
  162. }
  163. /*
  164. *********************************************************************************************************
  165. * 函 数 名: NAND_ReadID
  166. * 功能说明: 读NAND Flash的ID。ID存储到形参指定的结构体变量中。
  167. * 形 参: 无
  168. * 返 回 值: 32bit的NAND Flash ID
  169. *********************************************************************************************************
  170. */
  171. uint32_t NAND_ReadID(void)
  172. {
  173. uint32_t data = 0;
  174. /* 发送命令 Command to the command area */
  175. NAND_CMD_AREA = 0x90;
  176. NAND_ADDR_AREA = 0x00;
  177. /* 顺序读取NAND Flash的ID */
  178. data = *(__IO uint32_t *)(Bank_NAND_ADDR | DATA_AREA);
  179. data = ((data << 24) & 0xFF000000) |
  180. ((data << 8) & 0x00FF0000) |
  181. ((data >> 8) & 0x0000FF00) |
  182. ((data >> 24) & 0x000000FF);
  183. return data;
  184. }
  185. /*
  186. *********************************************************************************************************
  187. * 函 数 名: FSMC_NAND_PageCopyBack
  188. * 功能说明: 将一页数据复制到另外一个页。源页和目标页必须同为偶数页或同为奇数页。
  189. * 形 参: - _ulSrcPageNo: 源页号
  190. * - _ulTarPageNo: 目标页号
  191. * 返 回 值: 执行结果:
  192. * - NAND_FAIL 表示失败
  193. * - NAND_OK 表示成功
  194. *
  195. * 说 明:数据手册推荐:在页复制之前,先校验源页的位校验,否则可能会积累位错误。本函数未实现。
  196. *
  197. *********************************************************************************************************
  198. */
  199. static uint8_t FSMC_NAND_PageCopyBack(uint32_t _ulSrcPageNo, uint32_t _ulTarPageNo)
  200. {
  201. uint8_t i;
  202. NAND_CMD_AREA = NAND_CMD_COPYBACK_A;
  203. /* 发送源页地址 , 对于 HY27UF081G2A
  204. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  205. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  206. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  207. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12
  208. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  209. */
  210. NAND_ADDR_AREA = 0;
  211. NAND_ADDR_AREA = 0;
  212. NAND_ADDR_AREA = _ulSrcPageNo;
  213. NAND_ADDR_AREA = (_ulSrcPageNo & 0xFF00) >> 8;
  214. NAND_CMD_AREA = NAND_CMD_COPYBACK_B;
  215. /* 必须等待,否则读出数据异常, 此处应该判断超时 */
  216. for (i = 0; i < 20; i++)
  217. ;
  218. while (GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_6) == 0)
  219. ;
  220. NAND_CMD_AREA = NAND_CMD_COPYBACK_C;
  221. /* 发送目标页地址 , 对于 HY27UF081G2A
  222. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  223. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  224. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  225. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12
  226. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  227. */
  228. NAND_ADDR_AREA = 0;
  229. NAND_ADDR_AREA = 0;
  230. NAND_ADDR_AREA = _ulTarPageNo;
  231. NAND_ADDR_AREA = (_ulTarPageNo & 0xFF00) >> 8;
  232. NAND_CMD_AREA = NAND_CMD_COPYBACK_D;
  233. /* 检查操作状态 */
  234. if (FSMC_NAND_GetStatus() == NAND_READY)
  235. {
  236. return NAND_OK;
  237. }
  238. return NAND_FAIL;
  239. }
  240. /*
  241. *********************************************************************************************************
  242. * 函 数 名: FSMC_NAND_PageCopyBackEx
  243. * 功能说明: 将一页数据复制到另外一个页,并更新目标页中的部分数据。源页和目标页必须同为偶数页或同为奇数页。
  244. * 形 参: - _ulSrcPageNo: 源页号
  245. * - _ulTarPageNo: 目标页号
  246. * - _usOffset: 页内偏移地址,pBuf的内容将写入这个地址开始单元
  247. * - _pBuf: 数据缓冲区
  248. * - _usSize: 数据大小
  249. * 返 回 值: 执行结果:
  250. * - NAND_FAIL 表示失败
  251. * - NAND_OK 表示成功
  252. *
  253. * 说 明:数据手册推荐:在页复制之前,先校验源页的位校验,否则可能会积累位错误。本函数未实现。
  254. *
  255. *********************************************************************************************************
  256. */
  257. static uint8_t FSMC_NAND_PageCopyBackEx(uint32_t _ulSrcPageNo, uint32_t _ulTarPageNo, uint8_t *_pBuf, uint16_t _usOffset, uint16_t _usSize)
  258. {
  259. uint16_t i;
  260. NAND_CMD_AREA = NAND_CMD_COPYBACK_A;
  261. /* 发送源页地址 , 对于 HY27UF081G2A
  262. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  263. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  264. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  265. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12
  266. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  267. */
  268. NAND_ADDR_AREA = 0;
  269. NAND_ADDR_AREA = 0;
  270. NAND_ADDR_AREA = _ulSrcPageNo;
  271. NAND_ADDR_AREA = (_ulSrcPageNo & 0xFF00) >> 8;
  272. NAND_CMD_AREA = NAND_CMD_COPYBACK_B;
  273. /* 必须等待,否则读出数据异常, 此处应该判断超时 */
  274. for (i = 0; i < 20; i++)
  275. ;
  276. while (GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_6) == 0)
  277. ;
  278. NAND_CMD_AREA = NAND_CMD_COPYBACK_C;
  279. /* 发送目标页地址 , 对于 HY27UF081G2A
  280. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  281. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  282. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  283. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12
  284. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  285. */
  286. NAND_ADDR_AREA = 0;
  287. NAND_ADDR_AREA = 0;
  288. NAND_ADDR_AREA = _ulTarPageNo;
  289. NAND_ADDR_AREA = (_ulTarPageNo & 0xFF00) >> 8;
  290. /* 中间无需带数据, 也无需等待 */
  291. NAND_CMD_AREA = NAND_CMD_COPYBACK_C;
  292. NAND_ADDR_AREA = _usOffset;
  293. NAND_ADDR_AREA = _usOffset >> 8;
  294. /* 发送数据 */
  295. for (i = 0; i < _usSize; i++)
  296. {
  297. NAND_DATA_AREA = _pBuf[i];
  298. }
  299. NAND_CMD_AREA = NAND_CMD_COPYBACK_D;
  300. /* 检查操作状态 */
  301. if (FSMC_NAND_GetStatus() == NAND_READY)
  302. {
  303. return NAND_OK;
  304. }
  305. return NAND_FAIL;
  306. }
  307. /*
  308. *********************************************************************************************************
  309. * 函 数 名: FSMC_NAND_WritePage
  310. * 功能说明: 写一组数据至NandFlash指定页面的指定位置,写入的数据长度不大于一页的大小。
  311. * 形 参: - _pBuffer: 指向包含待写数据的缓冲区
  312. * - _ulPageNo: 页号,所有的页统一编码,范围为:0 - 65535
  313. * - _usAddrInPage : 页内地址,范围为:0-2111
  314. * - _usByteCount: 写入的字节个数
  315. * 返 回 值: 执行结果:
  316. * - NAND_FAIL 表示失败
  317. * - NAND_OK 表示成功
  318. *********************************************************************************************************
  319. */
  320. static uint8_t FSMC_NAND_WritePage(uint8_t *_pBuffer, uint32_t _ulPageNo, uint16_t _usAddrInPage, uint16_t _usByteCount)
  321. {
  322. uint16_t i;
  323. /* 发送页写命令 */
  324. NAND_CMD_AREA = NAND_CMD_WRITE0;
  325. /* 发送页内地址 , 对于 HY27UF081G2A
  326. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  327. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  328. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  329. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12
  330. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  331. */
  332. NAND_ADDR_AREA = _usAddrInPage;
  333. NAND_ADDR_AREA = _usAddrInPage >> 8;
  334. NAND_ADDR_AREA = _ulPageNo;
  335. NAND_ADDR_AREA = (_ulPageNo & 0xFF00) >> 8;
  336. /* 写数据 */
  337. for (i = 0; i < _usByteCount; i++)
  338. {
  339. NAND_DATA_AREA = _pBuffer[i];
  340. }
  341. NAND_CMD_AREA = NAND_CMD_WRITE_TRUE1;
  342. /* 检查操作状态 */
  343. if (FSMC_NAND_GetStatus() == NAND_READY)
  344. {
  345. return NAND_OK;
  346. }
  347. return NAND_FAIL;
  348. }
  349. /*
  350. *********************************************************************************************************
  351. * 函 数 名: FSMC_NAND_ReadPage
  352. * 功能说明: 从NandFlash指定页面的指定位置读一组数据,读出的数据长度不大于一页的大小。
  353. * 形 参: - _pBuffer: 指向包含待写数据的缓冲区
  354. * - _ulPageNo: 页号,所有的页统一编码,范围为:0 - 65535
  355. * - _usAddrInPage : 页内地址,范围为:0-2111
  356. * - _usByteCount: 字节个数
  357. * 返 回 值: 执行结果:
  358. * - NAND_FAIL 表示失败
  359. * - NAND_OK 表示成功
  360. *********************************************************************************************************
  361. */
  362. static uint8_t FSMC_NAND_ReadPage(uint8_t *_pBuffer, uint32_t _ulPageNo, uint16_t _usAddrInPage, uint16_t _usByteCount)
  363. {
  364. uint16_t i;
  365. /* 发送页面读命令 */
  366. NAND_CMD_AREA = NAND_CMD_AREA_A;
  367. /* 发送页内地址 , 对于 HY27UF081G2A
  368. Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
  369. 第1字节: A7 A6 A5 A4 A3 A2 A1 A0 (_usPageAddr 的bit7 - bit0)
  370. 第2字节: 0 0 0 0 A11 A10 A9 A8 (_usPageAddr 的bit11 - bit8, 高4bit必须是0)
  371. 第3字节: A19 A18 A17 A16 A15 A14 A13 A12
  372. 第4字节: A27 A26 A25 A24 A23 A22 A21 A20
  373. */
  374. NAND_ADDR_AREA = _usAddrInPage;
  375. NAND_ADDR_AREA = _usAddrInPage >> 8;
  376. NAND_ADDR_AREA = _ulPageNo;
  377. NAND_ADDR_AREA = (_ulPageNo & 0xFF00) >> 8;
  378. NAND_CMD_AREA = NAND_CMD_AREA_TRUE1;
  379. /* 必须等待,否则读出数据异常, 此处应该判断超时 */
  380. for (i = 0; i < 20; i++)
  381. ;
  382. while (GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_6) == 0)
  383. ;
  384. /* 读数据到缓冲区pBuffer */
  385. for (i = 0; i < _usByteCount; i++)
  386. {
  387. _pBuffer[i] = NAND_DATA_AREA;
  388. }
  389. return NAND_OK;
  390. }
  391. /*
  392. *********************************************************************************************************
  393. * 函 数 名: FSMC_NAND_WriteSpare
  394. * 功能说明: 向1个PAGE的Spare区写入数据
  395. * 形 参: - _pBuffer: 指向包含待写数据的缓冲区
  396. * - _ulPageNo: 页号,所有的页统一编码,范围为:0 - 65535
  397. * - _usAddrInSpare : 页内备用区的偏移地址,范围为:0-63
  398. * - _usByteCount: 写入的字节个数
  399. * 返 回 值: 执行结果:
  400. * - NAND_FAIL 表示失败
  401. * - NAND_OK 表示成功
  402. *********************************************************************************************************
  403. */
  404. static uint8_t FSMC_NAND_WriteSpare(uint8_t *_pBuffer, uint32_t _ulPageNo, uint16_t _usAddrInSpare, uint16_t _usByteCount)
  405. {
  406. if (_usByteCount > NAND_SPARE_AREA_SIZE)
  407. {
  408. return NAND_FAIL;
  409. }
  410. return FSMC_NAND_WritePage(_pBuffer, _ulPageNo, NAND_PAGE_SIZE + _usAddrInSpare, _usByteCount);
  411. }
  412. /*
  413. *********************************************************************************************************
  414. * 函 数 名: FSMC_NAND_ReadSpare
  415. * 功能说明: 读1个PAGE的Spare区的数据
  416. * 形 参: - _pBuffer: 指向包含待写数据的缓冲区
  417. * - _ulPageNo: 页号,所有的页统一编码,范围为:0 - 65535
  418. * - _usAddrInSpare : 页内备用区的偏移地址,范围为:0-63
  419. * - _usByteCount: 写入的字节个数
  420. * 返 回 值: 执行结果:
  421. * - NAND_FAIL 表示失败
  422. * - NAND_OK 表示成功
  423. *********************************************************************************************************
  424. */
  425. static uint8_t FSMC_NAND_ReadSpare(uint8_t *_pBuffer, uint32_t _ulPageNo, uint16_t _usAddrInSpare, uint16_t _usByteCount)
  426. {
  427. if (_usByteCount > NAND_SPARE_AREA_SIZE)
  428. {
  429. return NAND_FAIL;
  430. }
  431. return FSMC_NAND_ReadPage(_pBuffer, _ulPageNo, NAND_PAGE_SIZE + _usAddrInSpare, _usByteCount);
  432. }
  433. /*
  434. *********************************************************************************************************
  435. * 函 数 名: FSMC_NAND_WriteData
  436. * 功能说明: 向1个PAGE的主数据区写入数据
  437. * 形 参: - _pBuffer: 指向包含待写数据的缓冲区
  438. * - _ulPageNo: 页号,所有的页统一编码,范围为:0 - 65535
  439. * - _usAddrInPage : 页内数据区的偏移地址,范围为:0-2047
  440. * - _usByteCount: 写入的字节个数
  441. * 返 回 值: 执行结果:
  442. * - NAND_FAIL 表示失败
  443. * - NAND_OK 表示成功
  444. *********************************************************************************************************
  445. */
  446. static uint8_t FSMC_NAND_WriteData(uint8_t *_pBuffer, uint32_t _ulPageNo, uint16_t _usAddrInPage, uint16_t _usByteCount)
  447. {
  448. if (_usByteCount > NAND_PAGE_SIZE)
  449. {
  450. return NAND_FAIL;
  451. }
  452. return FSMC_NAND_WritePage(_pBuffer, _ulPageNo, _usAddrInPage, _usByteCount);
  453. }
  454. /*
  455. *********************************************************************************************************
  456. * 函 数 名: FSMC_NAND_ReadData
  457. * 功能说明: 读1个PAGE的主数据的数据
  458. * 形 参: - _pBuffer: 指向包含待写数据的缓冲区
  459. * - _ulPageNo: 页号,所有的页统一编码,范围为:0 - 65535
  460. * - _usAddrInPage : 页内数据区的偏移地址,范围为:0-2047
  461. * - _usByteCount: 写入的字节个数
  462. * 返 回 值: 执行结果:
  463. * - NAND_FAIL 表示失败
  464. * - NAND_OK 表示成功
  465. *********************************************************************************************************
  466. */
  467. static uint8_t FSMC_NAND_ReadData(uint8_t *_pBuffer, uint32_t _ulPageNo, uint16_t _usAddrInPage, uint16_t _usByteCount)
  468. {
  469. if (_usByteCount > NAND_PAGE_SIZE)
  470. {
  471. return NAND_FAIL;
  472. }
  473. return FSMC_NAND_ReadPage(_pBuffer, _ulPageNo, _usAddrInPage, _usByteCount);
  474. }
  475. /*
  476. *********************************************************************************************************
  477. * 函 数 名: FSMC_NAND_EraseBlock
  478. * 功能说明: 擦除NAND Flash一个块(block)
  479. * 形 参: - _ulBlockNo: 块号,范围为:0 - 1023
  480. * 返 回 值: NAND操作状态,有如下几种值:
  481. * - NAND_TIMEOUT_ERROR : 超时错误
  482. * - NAND_READY : 操作成功
  483. *********************************************************************************************************
  484. */
  485. static uint8_t FSMC_NAND_EraseBlock(uint32_t _ulBlockNo)
  486. {
  487. /* 发送擦除命令 */
  488. NAND_CMD_AREA = NAND_CMD_ERASE0;
  489. _ulBlockNo <<= 6; /* 块号转换为页编号 */
  490. NAND_ADDR_AREA = _ulBlockNo;
  491. NAND_ADDR_AREA = _ulBlockNo >> 8;
  492. NAND_CMD_AREA = NAND_CMD_ERASE1;
  493. return (FSMC_NAND_GetStatus());
  494. }
  495. /*
  496. *********************************************************************************************************
  497. * 函 数 名: FSMC_NAND_Reset
  498. * 功能说明: 复位NAND Flash
  499. * 形 参: 无
  500. * 返 回 值: 无
  501. *********************************************************************************************************
  502. */
  503. static uint8_t FSMC_NAND_Reset(void)
  504. {
  505. NAND_CMD_AREA = NAND_CMD_RESET;
  506. /* 检查操作状态 */
  507. if (FSMC_NAND_GetStatus() == NAND_READY)
  508. {
  509. return NAND_OK;
  510. }
  511. return NAND_FAIL;
  512. }
  513. /*
  514. *********************************************************************************************************
  515. * 函 数 名: FSMC_NAND_ReadStatus
  516. * 功能说明: 使用Read statuc 命令读NAND Flash内部状态
  517. * 形 参: - Address: 被擦除的快内任意地址
  518. * 返 回 值: NAND操作状态,有如下几种值:
  519. * - NAND_BUSY: 内部正忙
  520. * - NAND_READY: 内部空闲,可以进行下步操作
  521. * - NAND_ERROR: 先前的命令执行失败
  522. *********************************************************************************************************
  523. */
  524. static uint8_t FSMC_NAND_ReadStatus(void)
  525. {
  526. uint8_t ucData;
  527. uint8_t ucStatus = NAND_BUSY;
  528. /* 读状态操作 */
  529. NAND_CMD_AREA = NAND_CMD_STATUS;
  530. ucData = *(__IO uint8_t *)(Bank_NAND_ADDR);
  531. if ((ucData & NAND_ERROR) == NAND_ERROR)
  532. {
  533. ucStatus = NAND_ERROR;
  534. }
  535. else if ((ucData & NAND_READY) == NAND_READY)
  536. {
  537. ucStatus = NAND_READY;
  538. }
  539. else
  540. {
  541. ucStatus = NAND_BUSY;
  542. }
  543. return (ucStatus);
  544. }
  545. /*
  546. *********************************************************************************************************
  547. * 函 数 名: FSMC_NAND_GetStatus
  548. * 功能说明: 获取NAND Flash操作状态
  549. * 形 参: - Address: 被擦除的快内任意地址
  550. * 返 回 值: NAND操作状态,有如下几种值:
  551. * - NAND_TIMEOUT_ERROR : 超时错误
  552. * - NAND_READY : 操作成功
  553. *********************************************************************************************************
  554. */
  555. static uint8_t FSMC_NAND_GetStatus(void)
  556. {
  557. uint32_t ulTimeout = 0x10000;
  558. uint8_t ucStatus = NAND_READY;
  559. ucStatus = FSMC_NAND_ReadStatus();
  560. /* 等待NAND操作结束,超时后会退出 */
  561. while ((ucStatus != NAND_READY) && (ulTimeout != 0x00))
  562. {
  563. ucStatus = FSMC_NAND_ReadStatus();
  564. ulTimeout--;
  565. }
  566. if (ulTimeout == 0x00)
  567. {
  568. ucStatus = NAND_TIMEOUT_ERROR;
  569. }
  570. /* 返回操作状态 */
  571. return (ucStatus);
  572. }
  573. /*
  574. *********************************************************************************************************
  575. * 函 数 名: nand_flash_init
  576. * 功能说明: 初始化NAND Flash接口
  577. * 形 参: 无
  578. * 返 回 值: 执行结果:
  579. * - NAND_FAIL 表示失败
  580. * - NAND_OK 表示成功
  581. *********************************************************************************************************
  582. */
  583. uint8_t nand_flash_init(void)
  584. {
  585. uint8_t Status;
  586. FSMC_NAND_Init(); /* 配置FSMC和GPIO用于NAND Flash接口 */
  587. FSMC_NAND_Reset(); /* 通过复位命令复位NAND Flash到读状态 */
  588. Status = NAND_BuildLUT(); /* 建立块管理表 LUT = Look up table */
  589. return Status;
  590. }
  591. /*
  592. *********************************************************************************************************
  593. * 函 数 名: NAND_WriteToNewBlock
  594. * 功能说明: 将旧块的数据复制到新块,并将新的数据段写入这个新块
  595. * 形 参: _ulPhyPageNo : 源页号
  596. * _pWriteBuf : 数据缓冲区
  597. * _usOffset : 页内偏移地址
  598. * _usSize :数据长度,必须是4字节的整数倍
  599. * 返 回 值: 执行结果:
  600. * - NAND_FAIL 表示失败
  601. * - NAND_OK 表示成功
  602. *********************************************************************************************************
  603. */
  604. uint8_t NAND_WriteToNewBlock(uint32_t _ulPhyPageNo, uint8_t *_pWriteBuf, uint16_t _usOffset, uint16_t _usSize)
  605. {
  606. uint16_t n, i;
  607. uint16_t usNewBlock;
  608. uint16_t ulSrcBlock;
  609. uint16_t usOffsetPageNo;
  610. ulSrcBlock = _ulPhyPageNo / NAND_BLOCK_SIZE; /* 根据物理页号反推块号 */
  611. usOffsetPageNo = _ulPhyPageNo % NAND_BLOCK_SIZE; /* 根据物理页号计算物理页号在块内偏移页号 */
  612. /* 增加循环的目的是处理目标块为坏块的情况 */
  613. for (n = 0; n < 10; n++)
  614. {
  615. /* 如果不是全0xFF, 则需要寻找一个空闲可用块,并将页内的数据全部移到新块中,然后擦除这个块 */
  616. usNewBlock = NAND_FindFreeBlock(); /* 从最后一个Block开始,搜寻一个可用块 */
  617. if (usNewBlock >= NAND_BLOCK_COUNT)
  618. {
  619. return NAND_FAIL; /* 查找空闲块失败 */
  620. }
  621. /* 使用page-copy功能,将当前块(usPBN)的数据全部搬移到新块(usNewBlock) */
  622. for (i = 0; i < NAND_BLOCK_SIZE; i++)
  623. {
  624. if (i == usOffsetPageNo)
  625. {
  626. /* 如果写入的数据在当前页,则需要使用带随机数据的Copy-Back命令 */
  627. if (FSMC_NAND_PageCopyBackEx(ulSrcBlock * NAND_BLOCK_SIZE + i, usNewBlock * NAND_BLOCK_SIZE + i,
  628. _pWriteBuf, _usOffset, _usSize) == NAND_FAIL)
  629. {
  630. NAND_MarkBadBlock(usNewBlock); /* 将新块标记为坏块 */
  631. NAND_BuildLUT(); /* 重建LUT表 */
  632. break;
  633. }
  634. }
  635. else
  636. {
  637. /* 使用NAND Flash 提供的整页Copy-Back功能,可以显著提高操作效率 */
  638. if (FSMC_NAND_PageCopyBack(ulSrcBlock * NAND_BLOCK_SIZE + i,
  639. usNewBlock * NAND_BLOCK_SIZE + i) == NAND_FAIL)
  640. {
  641. NAND_MarkBadBlock(usNewBlock); /* 将新块标记为坏块 */
  642. NAND_BuildLUT(); /* 重建LUT表 */
  643. break;
  644. }
  645. }
  646. }
  647. /* 目标块更新成功 */
  648. if (i == NAND_BLOCK_SIZE)
  649. {
  650. /* 标记新块为已用块 */
  651. if (NAND_MarkUsedBlock(usNewBlock) == NAND_FAIL)
  652. {
  653. NAND_MarkBadBlock(usNewBlock); /* 将新块标记为坏块 */
  654. NAND_BuildLUT(); /* 重建LUT表 */
  655. continue;
  656. }
  657. /* 擦除源BLOCK */
  658. if (FSMC_NAND_EraseBlock(ulSrcBlock) != NAND_READY)
  659. {
  660. NAND_MarkBadBlock(ulSrcBlock); /* 将源块标记为坏块 */
  661. NAND_BuildLUT(); /* 重建LUT表 */
  662. continue;
  663. }
  664. NAND_BuildLUT(); /* 重建LUT表 */
  665. break;
  666. }
  667. }
  668. return NAND_OK; /* 写入成功 */
  669. }
  670. /*
  671. *********************************************************************************************************
  672. * 函 数 名: NAND_Write
  673. * 功能说明: 写一个扇区
  674. * 形 参: _MemAddr : 内存单元偏移地址
  675. * _pReadbuff :存放待写数据的缓冲区的指针
  676. * _usSize :数据长度,必须是4字节的整数倍
  677. * 返 回 值: 执行结果:
  678. * - NAND_FAIL 表示失败
  679. * - NAND_OK 表示成功
  680. *********************************************************************************************************
  681. */
  682. uint8_t NAND_Write(uint32_t _ulMemAddr, uint32_t *_pWriteBuf, uint16_t _usSize)
  683. {
  684. uint16_t usPBN; /* 物理块号 */
  685. uint32_t ulPhyPageNo; /* 物理页号 */
  686. uint16_t usAddrInPage; /* 页内偏移地址 */
  687. uint32_t ulTemp;
  688. /* 数据长度必须是4字节整数倍 */
  689. if ((_usSize % 4) != 0)
  690. {
  691. return NAND_FAIL;
  692. }
  693. /* 数据长度不能超过512字节(遵循 Fat格式) */
  694. if (_usSize > 512)
  695. {
  696. // return NAND_FAIL;
  697. }
  698. usPBN = NAND_AddrToPhyBlockNo(_ulMemAddr); /* 查询LUT表获得物理块号 */
  699. ulTemp = _ulMemAddr % (NAND_BLOCK_SIZE * NAND_PAGE_SIZE);
  700. ulPhyPageNo = usPBN * NAND_BLOCK_SIZE + ulTemp / NAND_PAGE_SIZE; /* 计算物理页号 */
  701. usAddrInPage = ulTemp % NAND_PAGE_SIZE; /* 计算页内偏移地址 */
  702. /* 读出扇区的内容,判断是否全FF */
  703. if (FSMC_NAND_ReadData(s_ucTempBuf, ulPhyPageNo, usAddrInPage, _usSize) == NAND_FAIL)
  704. {
  705. return NAND_FAIL; /* 读NAND Flash失败 */
  706. }
  707. /* 如果是全0xFF, 则可以直接写入,无需擦除 */
  708. if (NAND_IsBufOk(s_ucTempBuf, _usSize, 0xFF))
  709. {
  710. if (FSMC_NAND_WriteData((uint8_t *)_pWriteBuf, ulPhyPageNo, usAddrInPage, _usSize) == NAND_FAIL)
  711. {
  712. /* 将数据写入到另外一个块(空闲块) */
  713. return NAND_WriteToNewBlock(ulPhyPageNo, (uint8_t *)_pWriteBuf, usAddrInPage, _usSize);
  714. }
  715. /* 标记该块已用 */
  716. if (NAND_MarkUsedBlock(ulPhyPageNo) == NAND_FAIL)
  717. {
  718. /* 标记失败,将数据写入到另外一个块(空闲块) */
  719. return NAND_WriteToNewBlock(ulPhyPageNo, (uint8_t *)_pWriteBuf, usAddrInPage, _usSize);
  720. }
  721. return NAND_OK; /* 写入成功 */
  722. }
  723. /* 将数据写入到另外一个块(空闲块) */
  724. return NAND_WriteToNewBlock(ulPhyPageNo, (uint8_t *)_pWriteBuf, usAddrInPage, _usSize);
  725. }
  726. /*
  727. *********************************************************************************************************
  728. * 函 数 名: NAND_Read
  729. * 功能说明: 读一个扇区
  730. * 形 参: _MemAddr : 内存单元偏移地址
  731. * _pReadbuff :存放读出数据的缓冲区的指针
  732. * _usSize :数据长度,必须是4字节的整数倍
  733. * 返 回 值: 执行结果:
  734. * - NAND_FAIL 表示失败
  735. * - NAND_OK 表示成功
  736. *********************************************************************************************************
  737. */
  738. uint8_t NAND_Read(uint32_t _ulMemAddr, uint32_t *_pReadBuf, uint16_t _usSize)
  739. {
  740. uint16_t usPBN; /* 物理块号 */
  741. uint32_t ulPhyPageNo; /* 物理页号 */
  742. uint16_t usAddrInPage; /* 页内偏移地址 */
  743. uint32_t ulTemp;
  744. /* 数据长度必须是4字节整数倍 */
  745. if ((_usSize % 4) != 0)
  746. {
  747. return NAND_FAIL;
  748. }
  749. usPBN = NAND_AddrToPhyBlockNo(_ulMemAddr); /* 查询LUT表获得物理块号 */
  750. if (usPBN >= NAND_BLOCK_COUNT)
  751. {
  752. /* 没有格式化,usPBN = 0xFFFF */
  753. return NAND_FAIL;
  754. }
  755. ulTemp = _ulMemAddr % (NAND_BLOCK_SIZE * NAND_PAGE_SIZE);
  756. ulPhyPageNo = usPBN * NAND_BLOCK_SIZE + ulTemp / NAND_PAGE_SIZE; /* 计算物理页号 */
  757. usAddrInPage = ulTemp % NAND_PAGE_SIZE; /* 计算页内偏移地址 */
  758. if (FSMC_NAND_ReadData((uint8_t *)_pReadBuf, ulPhyPageNo, usAddrInPage, _usSize) == NAND_FAIL)
  759. {
  760. return NAND_FAIL; /* 读NAND Flash失败 */
  761. }
  762. /* 成功 */
  763. return NAND_OK;
  764. }
  765. /*
  766. *********************************************************************************************************
  767. * 函 数 名: NAND_WriteMultiSectors
  768. * 功能说明: 该函数用于文件系统,连续写多个扇区数据。扇区大小可以是512字节或2048字节
  769. * 形 参: _pBuf : 存放数据的缓冲区的指针
  770. * _SectorNo :扇区号
  771. * _SectorSize :每个扇区的大小
  772. * _SectorCount : 扇区个数
  773. * 返 回 值: 执行结果:
  774. * - NAND_FAIL 表示失败
  775. * - NAND_OK 表示成功
  776. *********************************************************************************************************
  777. */
  778. uint8_t NAND_WriteMultiSectors(uint8_t *_pBuf, uint32_t _SectorNo, uint16_t _SectorSize, uint32_t _SectorCount)
  779. {
  780. uint32_t i;
  781. uint32_t usLBN; /* 逻辑块号 */
  782. uint32_t usPBN; /* 物理块号 */
  783. uint32_t uiPhyPageNo; /* 物理页号 */
  784. uint16_t usAddrInPage; /* 页内偏移地址 */
  785. uint32_t ulTemp;
  786. uint8_t ucReturn;
  787. /*
  788. HY27UF081G2A = 128M Flash. 有 1024个BLOCK, 每个BLOCK包含64个PAGE, 每个PAGE包含2048+64字节,
  789. 擦除最小单位是BLOCK, 编程最小单位是字节。
  790. 每个PAGE在逻辑上可以分为4个512字节扇区。
  791. */
  792. for (i = 0; i < _SectorCount; i++)
  793. {
  794. /* 根据逻辑扇区号和扇区大小计算逻辑块号 */
  795. // usLBN = (_SectorNo * _SectorSize) / (NAND_BLOCK_SIZE * NAND_PAGE_SIZE);
  796. /* (_SectorNo * _SectorSize) 乘积可能大于32位,因此换下面这种写法 */
  797. usLBN = (_SectorNo + i) / (NAND_BLOCK_SIZE * (NAND_PAGE_SIZE / _SectorSize));
  798. usPBN = NAND_LBNtoPBN(usLBN); /* 查询LUT表获得物理块号 */
  799. if (usPBN >= NAND_BLOCK_COUNT)
  800. {
  801. /* 没有格式化,usPBN = 0xFFFF */
  802. return NAND_FAIL;
  803. }
  804. // ulTemp = ((uint64_t)(_SectorNo + i) * _SectorSize) % (NAND_BLOCK_SIZE * NAND_PAGE_SIZE);
  805. ulTemp = ((_SectorNo + i) % (NAND_BLOCK_SIZE * (NAND_PAGE_SIZE / _SectorSize))) * _SectorSize;
  806. uiPhyPageNo = usPBN * NAND_BLOCK_SIZE + ulTemp / NAND_PAGE_SIZE; /* 计算物理页号 */
  807. usAddrInPage = ulTemp % NAND_PAGE_SIZE; /* 计算页内偏移地址 */
  808. /* 如果 _SectorCount > 0, 并且是页面首地址,则可以进行优化 */
  809. if (usAddrInPage == 0)
  810. {
  811. /* 暂未处理 */
  812. }
  813. /* 读出扇区的内容,判断是否全FF */
  814. if (FSMC_NAND_ReadData(s_ucTempBuf, uiPhyPageNo, usAddrInPage, _SectorSize) == NAND_FAIL)
  815. {
  816. return NAND_FAIL; /* 失败 */
  817. }
  818. /* 如果是全0xFF, 则可以直接写入,无需擦除 */
  819. if (NAND_IsBufOk(s_ucTempBuf, _SectorSize, 0xFF))
  820. {
  821. if (FSMC_NAND_WriteData(&_pBuf[i * _SectorSize], uiPhyPageNo, usAddrInPage, _SectorSize) == NAND_FAIL)
  822. {
  823. /* 将数据写入到另外一个块(空闲块) */
  824. ucReturn = NAND_WriteToNewBlock(uiPhyPageNo, &_pBuf[i * _SectorSize], usAddrInPage, _SectorSize);
  825. if (ucReturn != NAND_OK)
  826. {
  827. return NAND_FAIL; /* 失败 */
  828. }
  829. continue;
  830. }
  831. /* 标记该块已用 */
  832. if (NAND_MarkUsedBlock(uiPhyPageNo) == NAND_FAIL)
  833. {
  834. /* 标记失败,将数据写入到另外一个块(空闲块) */
  835. ucReturn = NAND_WriteToNewBlock(uiPhyPageNo, &_pBuf[i * _SectorSize], usAddrInPage, _SectorSize);
  836. if (ucReturn != NAND_OK)
  837. {
  838. return NAND_FAIL; /* 失败 */
  839. }
  840. continue;
  841. }
  842. }
  843. else /* 目标区域已经有数据,不是全FF, 则直接将数据写入另外一个空闲块 */
  844. {
  845. /* 将数据写入到另外一个块(空闲块) */
  846. ucReturn = NAND_WriteToNewBlock(uiPhyPageNo, &_pBuf[i * _SectorSize], usAddrInPage, _SectorSize);
  847. if (ucReturn != NAND_OK)
  848. {
  849. return NAND_FAIL; /* 失败 */
  850. }
  851. continue;
  852. }
  853. }
  854. return NAND_OK; /* 成功 */
  855. }
  856. /*
  857. *********************************************************************************************************
  858. * 函 数 名: NAND_ReadMultiSectors
  859. * 功能说明: 该函数用于文件系统,按扇区读数据。读1个或多个扇区,扇区大小可以是512字节或2048字节
  860. * 形 参: _pBuf : 存放读出数据的缓冲区的指针
  861. * _SectorNo :扇区号
  862. * _SectorSize :每个扇区的大小
  863. * _SectorCount : 扇区个数
  864. * 返 回 值: 执行结果:
  865. * - NAND_FAIL 表示失败
  866. * - NAND_OK 表示成功
  867. *********************************************************************************************************
  868. */
  869. uint8_t NAND_ReadMultiSectors(uint8_t *_pBuf, uint32_t _SectorNo, uint16_t _SectorSize, uint32_t _SectorCount)
  870. {
  871. uint32_t i;
  872. uint32_t usLBN; /* 逻辑块号 */
  873. uint32_t usPBN; /* 物理块号 */
  874. uint32_t uiPhyPageNo; /* 物理页号 */
  875. uint16_t usAddrInPage; /* 页内偏移地址 */
  876. uint32_t ulTemp;
  877. /*
  878. HY27UF081G2A = 128M Flash. 有 1024个BLOCK, 每个BLOCK包含64个PAGE, 每个PAGE包含2048+64字节,
  879. 擦除最小单位是BLOCK, 编程最小单位是字节。
  880. 每个PAGE在逻辑上可以分为4个512字节扇区。
  881. */
  882. for (i = 0; i < _SectorCount; i++)
  883. {
  884. /* 根据逻辑扇区号和扇区大小计算逻辑块号 */
  885. // usLBN = (_SectorNo * _SectorSize) / (NAND_BLOCK_SIZE * NAND_PAGE_SIZE);
  886. /* (_SectorNo * _SectorSize) 乘积可能大于32位,因此换下面这种写法 */
  887. usLBN = (_SectorNo + i) / (NAND_BLOCK_SIZE * (NAND_PAGE_SIZE / _SectorSize));
  888. usPBN = NAND_LBNtoPBN(usLBN); /* 查询LUT表获得物理块号 */
  889. if (usPBN >= NAND_BLOCK_COUNT)
  890. {
  891. /* 没有格式化,usPBN = 0xFFFF */
  892. return NAND_FAIL;
  893. }
  894. ulTemp = ((uint64_t)(_SectorNo + i) * _SectorSize) % (NAND_BLOCK_SIZE * NAND_PAGE_SIZE);
  895. uiPhyPageNo = usPBN * NAND_BLOCK_SIZE + ulTemp / NAND_PAGE_SIZE; /* 计算物理页号 */
  896. usAddrInPage = ulTemp % NAND_PAGE_SIZE; /* 计算页内偏移地址 */
  897. if (FSMC_NAND_ReadData((uint8_t *)&_pBuf[i * _SectorSize], uiPhyPageNo, usAddrInPage, _SectorSize) == NAND_FAIL)
  898. {
  899. return NAND_FAIL; /* 读NAND Flash失败 */
  900. }
  901. }
  902. /* 成功 */
  903. return NAND_OK;
  904. }
  905. /*
  906. *********************************************************************************************************
  907. * 函 数 名: NAND_BuildLUT
  908. * 功能说明: 在内存中创建坏块管理表
  909. * 形 参: ZoneNbr :区号
  910. * 返 回 值: NAND_OK: 成功; NAND_FAIL:失败
  911. *********************************************************************************************************
  912. */
  913. static uint8_t NAND_BuildLUT(void)
  914. {
  915. uint16_t i;
  916. uint8_t buf[VALID_SPARE_SIZE];
  917. uint16_t usLBN; /* 逻辑块号 */
  918. /* */
  919. for (i = 0; i < NAND_BLOCK_COUNT; i++)
  920. {
  921. s_usLUT[i] = 0xFFFF; /* 填充无效值,用于重建LUT后,判断LUT是否合理 */
  922. }
  923. for (i = 0; i < NAND_BLOCK_COUNT; i++)
  924. {
  925. /* 读每个块的第1个PAGE,偏移地址为LBN0_OFFSET的数据 */
  926. FSMC_NAND_ReadSpare(buf, i * NAND_BLOCK_SIZE, 0, VALID_SPARE_SIZE);
  927. /* 如果是好块,则记录LBN0 LBN1 */
  928. if (buf[BI_OFFSET] == 0xFF)
  929. {
  930. usLBN = buf[LBN0_OFFSET] + buf[LBN1_OFFSET] * 256; /* 计算读出的逻辑块号 */
  931. if (usLBN < NAND_BLOCK_COUNT)
  932. {
  933. /* 如果已经登记过了,则判定为异常 */
  934. if (s_usLUT[usLBN] != 0xFFFF)
  935. {
  936. return NAND_FAIL;
  937. }
  938. s_usLUT[usLBN] = i; /* 更新LUT表 */
  939. }
  940. }
  941. }
  942. /* LUT建立完毕,检查是否合理 */
  943. for (i = 0; i < NAND_BLOCK_COUNT; i++)
  944. {
  945. if (s_usLUT[i] >= NAND_BLOCK_COUNT)
  946. {
  947. s_usValidDataBlockCount = i;
  948. break;
  949. }
  950. }
  951. if (s_usValidDataBlockCount < 100)
  952. {
  953. /* 错误: 最大的有效逻辑块号小于100。可能是没有格式化 */
  954. return NAND_FAIL;
  955. }
  956. for (; i < s_usValidDataBlockCount; i++)
  957. {
  958. if (s_usLUT[i] != 0xFFFF)
  959. {
  960. return NAND_FAIL; /* 错误:LUT表逻辑块号存在跳跃现象,可能是没有格式化 */
  961. }
  962. }
  963. /* 重建LUT正常 */
  964. return NAND_OK;
  965. }
  966. /*
  967. *********************************************************************************************************
  968. * 函 数 名: NAND_AddrToPhyBlockNo
  969. * 功能说明: 内存逻辑地址转换为物理块号
  970. * 形 参: _ulMemAddr:逻辑内存地址
  971. * 返 回 值: 物理页号, 如果是 0xFFFFFFFF 则表示错误
  972. *********************************************************************************************************
  973. */
  974. static uint16_t NAND_AddrToPhyBlockNo(uint32_t _ulMemAddr)
  975. {
  976. uint16_t usLBN; /* 逻辑块号 */
  977. uint16_t usPBN; /* 物理块号 */
  978. usLBN = _ulMemAddr / (NAND_BLOCK_SIZE * NAND_PAGE_SIZE); /* 计算逻辑块号 */
  979. /* 如果逻辑块号大于有效的数据块个数则固定返回0xFFFF, 调用该函数的代码应该检查出这种错误 */
  980. if (usLBN >= s_usValidDataBlockCount)
  981. {
  982. return 0xFFFF;
  983. }
  984. /* 查询LUT表,获得物理块号 */
  985. usPBN = s_usLUT[usLBN];
  986. return usPBN;
  987. }
  988. /*
  989. *********************************************************************************************************
  990. * 函 数 名: NAND_LBNtoPBN
  991. * 功能说明: 逻辑块号转换为物理块号
  992. * 形 参: _uiLBN : 逻辑块号 Logic Block No
  993. * 返 回 值: 物理块号, 如果是 0xFFFFFFFF 则表示错误
  994. *********************************************************************************************************
  995. */
  996. static uint16_t NAND_LBNtoPBN(uint32_t _uiLBN)
  997. {
  998. uint16_t usPBN; /* 物理块号 */
  999. /* 如果逻辑块号大于有效的数据块个数则固定返回0xFFFF, 调用该函数的代码应该检查出这种错误 */
  1000. if (_uiLBN >= s_usValidDataBlockCount)
  1001. {
  1002. return 0xFFFF;
  1003. }
  1004. /* 查询LUT表,获得物理块号 */
  1005. usPBN = s_usLUT[_uiLBN];
  1006. return usPBN;
  1007. }
  1008. /*
  1009. *********************************************************************************************************
  1010. * 函 数 名: NAND_FindFreeBlock
  1011. * 功能说明: 从最后一个块开始,查找一个可用的块。
  1012. * 形 参: ZoneNbr :区号
  1013. * 返 回 值: 块号,如果是0xFFFF表示失败
  1014. *********************************************************************************************************
  1015. */
  1016. static uint16_t NAND_FindFreeBlock(void)
  1017. {
  1018. uint16_t i;
  1019. uint16_t n;
  1020. n = NAND_BLOCK_COUNT - 1;
  1021. for (i = 0; i < NAND_BLOCK_COUNT; i++)
  1022. {
  1023. if (NAND_IsFreeBlock(n))
  1024. {
  1025. return n;
  1026. }
  1027. n--;
  1028. }
  1029. return 0xFFFF;
  1030. }
  1031. /*
  1032. *********************************************************************************************************
  1033. * 函 数 名: NAND_IsBufOk
  1034. * 功能说明: 判断内存缓冲区的数据是否全部为指定值
  1035. * 形 参: - _pBuf : 输入缓冲区
  1036. * - _ulLen : 缓冲区长度
  1037. * - __ucValue : 缓冲区每个单元的正确数值
  1038. * 返 回 值: 1 :全部正确; 0 :不正确
  1039. *********************************************************************************************************
  1040. */
  1041. static uint8_t NAND_IsBufOk(uint8_t *_pBuf, uint32_t _ulLen, uint8_t _ucValue)
  1042. {
  1043. uint32_t i;
  1044. for (i = 0; i < _ulLen; i++)
  1045. {
  1046. if (_pBuf[i] != _ucValue)
  1047. {
  1048. return 0;
  1049. }
  1050. }
  1051. return 1;
  1052. }
  1053. /*
  1054. *********************************************************************************************************
  1055. * 函 数 名: NAND_IsBadBlock
  1056. * 功能说明: 根据坏块标记检测NAND Flash指定的块是否坏块
  1057. * 形 参: _ulBlockNo :块号 0 - 1023 (对于128M字节,2K Page的NAND Flash,有1024个块)
  1058. * 返 回 值: 0 :该块可用; 1 :该块是坏块
  1059. *********************************************************************************************************
  1060. */
  1061. uint8_t NAND_IsBadBlock(uint32_t _ulBlockNo)
  1062. {
  1063. uint8_t ucFlag;
  1064. /* 如果NAND Flash出厂前已经标注为坏块了,则就认为是坏块 */
  1065. FSMC_NAND_ReadSpare(&ucFlag, _ulBlockNo * NAND_BLOCK_SIZE, BI_OFFSET, 1);
  1066. if (ucFlag != 0xFF)
  1067. {
  1068. return 1;
  1069. }
  1070. FSMC_NAND_ReadSpare(&ucFlag, _ulBlockNo * NAND_BLOCK_SIZE + 1, BI_OFFSET, 1);
  1071. if (ucFlag != 0xFF)
  1072. {
  1073. return 1;
  1074. }
  1075. return 0; /* 是好块 */
  1076. }
  1077. /*
  1078. *********************************************************************************************************
  1079. * 函 数 名: NAND_IsFreeBlock
  1080. * 功能说明: 根据坏块标记和USED标志检测是否可用块
  1081. * 形 参: _ulBlockNo :块号 0 - 1023 (对于128M字节,2K Page的NAND Flash,有1024个块)
  1082. * 返 回 值: 1 :该块可用; 0 :该块是坏块或者已占用
  1083. *********************************************************************************************************
  1084. */
  1085. static uint8_t NAND_IsFreeBlock(uint32_t _ulBlockNo)
  1086. {
  1087. uint8_t ucFlag;
  1088. /* 如果NAND Flash出厂前已经标注为坏块了,则就认为是坏块 */
  1089. if (NAND_IsBadBlock(_ulBlockNo))
  1090. {
  1091. return 0;
  1092. }
  1093. FSMC_NAND_ReadPage(&ucFlag, _ulBlockNo * NAND_BLOCK_SIZE, USED_OFFSET, 1);
  1094. if (ucFlag == 0xFF)
  1095. {
  1096. return 1;
  1097. }
  1098. return 0;
  1099. }
  1100. /*
  1101. *********************************************************************************************************
  1102. * 函 数 名: NAND_ScanBlock
  1103. * 功能说明: 扫描测试NAND Flash指定的块
  1104. * 【扫描测试算法】
  1105. * 1) 第1个块(包括主数据区和备用数据区),擦除后检测是否全0xFF, 正确的话继续测试改块,否则该块
  1106. 是坏块,函数返回
  1107. * 2) 当前块写入全 0x00,然后读取检测,正确的话继续测试改块,否则退出
  1108. * 3) 重复第(2)步;如果循环次数达50次都没有发生错误,那么该块正常,函数返回,否则该块是坏块,
  1109. * 函数返回
  1110. * 【注意】
  1111. * 1) 该函数测试完毕后,会删除块内所有数据,即变为全0xFF;
  1112. * 2) 该函数除了测试主数据区外,也对备用数据区进行测试。
  1113. * 3) 擦写测试循环次数可以宏指定。#define BAD_BALOK_TEST_CYCLE 50
  1114. * 形 参: _ulPageNo :页号 0 - 65535 (对于128M字节,2K Page的NAND Flash,有1024个块)
  1115. * 返 回 值: NAND_OK :该块可用; NAND_FAIL :该块是坏块
  1116. *********************************************************************************************************
  1117. */
  1118. uint8_t NAND_ScanBlock(uint32_t _ulBlockNo)
  1119. {
  1120. uint32_t i, k;
  1121. uint32_t ulPageNo;
  1122. #if 1
  1123. /* 如果NAND Flash出厂前已经标注为坏块了,则就认为是坏块 */
  1124. if (NAND_IsBadBlock(_ulBlockNo))
  1125. {
  1126. return NAND_FAIL;
  1127. }
  1128. #endif
  1129. /* 下面的代码将通过反复擦除、编程的方式来测试NAND Flash每个块的可靠性 */
  1130. memset(s_ucTempBuf, 0x00, NAND_PAGE_TOTAL_SIZE);
  1131. for (i = 0; i < BAD_BALOK_TEST_CYCLE; i++)
  1132. {
  1133. /* 第1步:擦除这个块 */
  1134. if (FSMC_NAND_EraseBlock(_ulBlockNo) != NAND_READY)
  1135. {
  1136. return NAND_FAIL;
  1137. }
  1138. /* 第2步:读出块内每个page的数据,并判断是否全0xFF */
  1139. ulPageNo = _ulBlockNo * NAND_BLOCK_SIZE; /* 计算该块第1个页的页号 */
  1140. for (k = 0; k < NAND_BLOCK_SIZE; k++)
  1141. {
  1142. /* 读出整页数据 */
  1143. FSMC_NAND_ReadPage(s_ucTempBuf, ulPageNo, 0, NAND_PAGE_TOTAL_SIZE);
  1144. /* 判断存储单元是不是全0xFF */
  1145. if (NAND_IsBufOk(s_ucTempBuf, NAND_PAGE_TOTAL_SIZE, 0xFF) != NAND_OK)
  1146. {
  1147. return NAND_FAIL;
  1148. }
  1149. ulPageNo++; /* 继续写下一个页 */
  1150. }
  1151. /* 第2步:写全0,并读回判断是否全0 */
  1152. ulPageNo = _ulBlockNo * NAND_BLOCK_SIZE; /* 计算该块第1个页的页号 */
  1153. for (k = 0; k < NAND_BLOCK_SIZE; k++)
  1154. {
  1155. /* 填充buf[]缓冲区为全0,并写入NAND Flash */
  1156. memset(s_ucTempBuf, 0x00, NAND_PAGE_TOTAL_SIZE);
  1157. if (FSMC_NAND_WritePage(s_ucTempBuf, ulPageNo, 0, NAND_PAGE_TOTAL_SIZE) != NAND_OK)
  1158. {
  1159. return NAND_FAIL;
  1160. }
  1161. /* 读出整页数据, 判断存储单元是不是全0x00 */
  1162. FSMC_NAND_ReadPage(s_ucTempBuf, ulPageNo, 0, NAND_PAGE_TOTAL_SIZE);
  1163. if (NAND_IsBufOk(s_ucTempBuf, NAND_PAGE_TOTAL_SIZE, 0x00) != NAND_OK)
  1164. {
  1165. return NAND_FAIL;
  1166. }
  1167. ulPageNo++; /* 继续一个页 */
  1168. }
  1169. }
  1170. /* 最后一步:擦除整个块 */
  1171. if (FSMC_NAND_EraseBlock(_ulBlockNo) != NAND_READY)
  1172. {
  1173. return NAND_FAIL;
  1174. }
  1175. ulPageNo = _ulBlockNo * NAND_BLOCK_SIZE; /* 计算该块第1个页的页号 */
  1176. for (k = 0; k < NAND_BLOCK_SIZE; k++)
  1177. {
  1178. /* 读出整页数据 */
  1179. FSMC_NAND_ReadPage(s_ucTempBuf, ulPageNo, 0, NAND_PAGE_TOTAL_SIZE);
  1180. /* 判断存储单元是不是全0xFF */
  1181. if (NAND_IsBufOk(s_ucTempBuf, NAND_PAGE_TOTAL_SIZE, 0xFF) != NAND_OK)
  1182. {
  1183. return NAND_FAIL;
  1184. }
  1185. ulPageNo++; /* 继续写下一个页 */
  1186. }
  1187. return NAND_OK;
  1188. }
  1189. /*
  1190. *********************************************************************************************************
  1191. * 函 数 名: NAND_MarkUsedBlock
  1192. * 功能说明: 标记NAND Flash指定的块为已用块
  1193. * 形 参: _ulBlockNo :块号 0 - 1023 (对于128M字节,2K Page的NAND Flash,有1024个块)
  1194. * 返 回 值: NAND_OK:标记成功; NAND_FAIL:标记失败,上级软件应该进行坏块处理。
  1195. *********************************************************************************************************
  1196. */
  1197. static uint8_t NAND_MarkUsedBlock(uint32_t _ulBlockNo)
  1198. {
  1199. uint32_t ulPageNo;
  1200. uint8_t ucFlag;
  1201. /* 计算块的第1个页号 */
  1202. ulPageNo = _ulBlockNo * NAND_BLOCK_SIZE; /* 计算该块第1个页的页号 */
  1203. /* 块内第1个page备用区的第6个字节写入非0xFF数据表示坏块 */
  1204. ucFlag = NAND_USED_BLOCK_FLAG;
  1205. if (FSMC_NAND_WriteSpare(&ucFlag, ulPageNo, USED_OFFSET, 1) == NAND_FAIL)
  1206. {
  1207. /* 如果标记失败,则需要标注这个块为坏块 */
  1208. return NAND_FAIL;
  1209. }
  1210. return NAND_OK;
  1211. }
  1212. /*
  1213. *********************************************************************************************************
  1214. * 函 数 名: NAND_MarkBadBlock
  1215. * 功能说明: 标记NAND Flash指定的块为坏块
  1216. * 形 参: _ulBlockNo :块号 0 - 1023 (对于128M字节,2K Page的NAND Flash,有1024个块)
  1217. * 返 回 值: 固定NAND_OK
  1218. *********************************************************************************************************
  1219. */
  1220. static void NAND_MarkBadBlock(uint32_t _ulBlockNo)
  1221. {
  1222. uint32_t ulPageNo;
  1223. uint8_t ucFlag;
  1224. /* 计算块的第1个页号 */
  1225. ulPageNo = _ulBlockNo * NAND_BLOCK_SIZE; /* 计算该块第1个页的页号 */
  1226. /* 块内第1个page备用区的第6个字节写入非0xFF数据表示坏块 */
  1227. ucFlag = NAND_BAD_BLOCK_FLAG;
  1228. if (FSMC_NAND_WriteSpare(&ucFlag, ulPageNo, BI_OFFSET, 1) == NAND_FAIL)
  1229. {
  1230. /* 如果第1个页标记失败,则在第2个页标记 */
  1231. FSMC_NAND_WriteSpare(&ucFlag, ulPageNo + 1, BI_OFFSET, 1);
  1232. }
  1233. }
  1234. /*
  1235. *********************************************************************************************************
  1236. * 函 数 名: NAND_Format
  1237. * 功能说明: NAND Flash格式化,擦除所有的数据,重建LUT
  1238. * 形 参: 无
  1239. * 返 回 值: NAND_OK : 成功; NAND_Fail :失败(一般是坏块数量过多导致)
  1240. *********************************************************************************************************
  1241. */
  1242. uint8_t NAND_Format(void)
  1243. {
  1244. uint16_t i, n;
  1245. uint16_t usGoodBlockCount;
  1246. /* 擦除每个块 */
  1247. usGoodBlockCount = 0;
  1248. for (i = 0; i < NAND_BLOCK_COUNT; i++)
  1249. {
  1250. /* 如果是好块,则擦除 */
  1251. if (!NAND_IsBadBlock(i))
  1252. {
  1253. FSMC_NAND_EraseBlock(i);
  1254. usGoodBlockCount++;
  1255. }
  1256. }
  1257. /* 如果好块的数量少于100,则NAND Flash报废 */
  1258. if (usGoodBlockCount < 100)
  1259. {
  1260. return NAND_FAIL;
  1261. }
  1262. usGoodBlockCount = (usGoodBlockCount * 98) / 100; /* 98%的好块用于存储数据 */
  1263. /* 重新搜索一次 */
  1264. n = 0; /* 统计已标注的好块 */
  1265. for (i = 0; i < NAND_BLOCK_COUNT; i++)
  1266. {
  1267. if (!NAND_IsBadBlock(i))
  1268. {
  1269. /* 如果是好块,则在该块的第1个PAGE的LBN0 LBN1处写入n值 (前面已经执行了块擦除) */
  1270. FSMC_NAND_WriteSpare((uint8_t *)&n, i * NAND_BLOCK_SIZE, LBN0_OFFSET, 2);
  1271. n++;
  1272. /* 计算并写入每个扇区的ECC值 (暂时未作)*/
  1273. if (n == usGoodBlockCount)
  1274. {
  1275. break;
  1276. }
  1277. }
  1278. }
  1279. NAND_BuildLUT(); /* 初始化LUT表 */
  1280. return NAND_OK;
  1281. }
  1282. /*
  1283. *********************************************************************************************************
  1284. * 函 数 名: NAND_FormatCapacity
  1285. * 功能说明: NAND Flash格式化后的有效容量
  1286. * 形 参: 无
  1287. * 返 回 值: NAND_OK : 成功; NAND_Fail :失败(一般是坏块数量过多导致)
  1288. *********************************************************************************************************
  1289. */
  1290. uint32_t NAND_FormatCapacity(void)
  1291. {
  1292. uint16_t usCount;
  1293. /* 计算用于存储数据的数据块个数,按照总有效块数的98%来计算 */
  1294. usCount = (s_usValidDataBlockCount * DATA_BLOCK_PERCENT) / 100;
  1295. return (usCount * NAND_BLOCK_SIZE * NAND_PAGE_SIZE);
  1296. }
  1297. /*
  1298. *********************************************************************************************************
  1299. * 函 数 名: NAND_DispBadBlockInfo
  1300. * 功能说明: 通过串口打印出NAND Flash的坏块信息
  1301. * 形 参: 无
  1302. * 返 回 值: 无
  1303. *********************************************************************************************************
  1304. */
  1305. void NAND_DispBadBlockInfo(void)
  1306. {
  1307. uint32_t id;
  1308. uint32_t i;
  1309. uint32_t n;
  1310. FSMC_NAND_Init(); /* 初始化FSMC */
  1311. id = NAND_ReadID();
  1312. printf("NAND Flash ID = 0x%04X, Type = ", id);
  1313. if (id == HY27UF081G2A)
  1314. {
  1315. printf("HY27UF081G2A\r\n 1024 Blocks, 64 pages per block, 2048 + 64 bytes per page\r\n");
  1316. }
  1317. else if (id == K9F1G08U0A)
  1318. {
  1319. printf("K9F1G08U0A\r\n 1024 Blocks, 64 pages per block, 2048 + 64 bytes per page\r\n");
  1320. }
  1321. else if (id == K9F1G08U0B)
  1322. {
  1323. printf("K9F1G08U0B\r\n 1024 Blocks, 64 pages per block, 2048 + 64 bytes per page\r\n");
  1324. }
  1325. else
  1326. {
  1327. printf("unkonow\r\n");
  1328. return;
  1329. }
  1330. printf("Block Info : 0 is OK, * is Bad\r\n");
  1331. n = 0; /* 坏块统计 */
  1332. for (i = 0; i < NAND_BLOCK_COUNT; i++)
  1333. {
  1334. if (NAND_IsBadBlock(i))
  1335. {
  1336. printf("*");
  1337. n++;
  1338. }
  1339. else
  1340. {
  1341. printf("0");
  1342. }
  1343. if (((i + 1) % 8) == 0)
  1344. {
  1345. printf(" ");
  1346. }
  1347. if (((i + 1) % 64) == 0)
  1348. {
  1349. printf("\r\n");
  1350. }
  1351. }
  1352. printf("Bad Block Count = %d\r\n", n);
  1353. }
  1354. /*
  1355. *********************************************************************************************************
  1356. * 函 数 名: NAND_DispPhyPageData
  1357. * 功能说明: 通过串口打印出指定页的数据(2048+64)
  1358. * 形 参: _uiPhyPageNo : 物理页号
  1359. * 返 回 值: 无
  1360. *********************************************************************************************************
  1361. */
  1362. void NAND_DispPhyPageData(uint32_t _uiPhyPageNo)
  1363. {
  1364. uint32_t i, n;
  1365. uint32_t ulBlockNo;
  1366. uint16_t usOffsetPageNo;
  1367. ulBlockNo = _uiPhyPageNo / NAND_BLOCK_SIZE; /* 根据物理页号反推块号 */
  1368. usOffsetPageNo = _uiPhyPageNo % NAND_BLOCK_SIZE; /* 根据物理页号计算物理页号在块内偏移页号 */
  1369. if (NAND_OK != FSMC_NAND_ReadPage(s_ucTempBuf, _uiPhyPageNo, 0, NAND_PAGE_TOTAL_SIZE))
  1370. {
  1371. printf("FSMC_NAND_ReadPage Failed() \r\n");
  1372. return;
  1373. }
  1374. printf("Block = %d, Page = %d\r\n", ulBlockNo, usOffsetPageNo);
  1375. /* 打印前面 2048字节数据,每512字节空一行 */
  1376. for (n = 0; n < 4; n++)
  1377. {
  1378. for (i = 0; i < 512; i++)
  1379. {
  1380. printf(" %02X", s_ucTempBuf[i + n * 512]);
  1381. if ((i & 31) == 31)
  1382. {
  1383. printf("\r\n"); /* 每行显示32字节数据 */
  1384. }
  1385. else if ((i & 31) == 15)
  1386. {
  1387. printf(" - ");
  1388. }
  1389. }
  1390. printf("\r\n");
  1391. }
  1392. /* 打印前面 2048字节数据,每512字节空一行 */
  1393. for (i = 0; i < 64; i++)
  1394. {
  1395. printf(" %02X", s_ucTempBuf[i + 2048]);
  1396. if ((i & 15) == 15)
  1397. {
  1398. printf("\r\n"); /* 每行显示32字节数据 */
  1399. }
  1400. }
  1401. }
  1402. /*
  1403. *********************************************************************************************************
  1404. * 函 数 名: NAND_DispLogicPageData
  1405. * 功能说明: 通过串口打印出指定页的数据(2048+64)
  1406. * 形 参: _uiLogicPageNo : 逻辑页号
  1407. * 返 回 值: 无
  1408. *********************************************************************************************************
  1409. */
  1410. void NAND_DispLogicPageData(uint32_t _uiLogicPageNo)
  1411. {
  1412. uint32_t uiPhyPageNo;
  1413. uint16_t usLBN; /* 逻辑块号 */
  1414. uint16_t usPBN; /* 物理块号 */
  1415. usLBN = _uiLogicPageNo / NAND_BLOCK_SIZE;
  1416. usPBN = NAND_LBNtoPBN(usLBN); /* 查询LUT表获得物理块号 */
  1417. if (usPBN >= NAND_BLOCK_COUNT)
  1418. {
  1419. /* 没有格式化,usPBN = 0xFFFF */
  1420. return;
  1421. }
  1422. printf("LogicBlock = %d, PhyBlock = %d\r\n", _uiLogicPageNo, usPBN);
  1423. /* 计算物理页号 */
  1424. uiPhyPageNo = usPBN * NAND_BLOCK_SIZE + _uiLogicPageNo % NAND_BLOCK_SIZE;
  1425. NAND_DispPhyPageData(uiPhyPageNo); /* 显示指定页数据 */
  1426. }
  1427. /***************************** 安富莱电子 www.armfly.com (END OF FILE) *********************************/