nand.c
上传用户:kylngs
上传日期:2022-05-06
资源大小:5k
文件大小:16k
源码类别:

VxWorks

开发平台:

C/C++

  1. /*
  2. Nand Flash基本底层驱动函数,完成基本的读、写和擦除功能,没有加入ECC校验和写后校验功能。
  3. 外部调用的函数有:
  4. 写一页:
  5.   int WriteOnePage(unsigned long Address, unsigned int Length, unsigned char *buffer);
  6. 读一页:
  7.   int ReadOnePage(unsigned long Address, unsigned int Length, unsigned char *buffer);
  8. 多页连续读:
  9.   int NandMTDRead(unsigned long Address,unsigned char *buffer,unsigned int Length,unsigned int modes);
  10. 多页连续写:
  11.   int NandMTDWrite(unsigned long Address,unsigned char *buffer,unsigned int Length,unsigned int modes);
  12. 擦除函数:
  13.   int NandMTDErase(unsigned int BlockNo,unsigned int BlocksToErase);
  14. GPIO初始化:
  15.   void BusyGPIOInit(void);
  16.   
  17. CPU为150MHz频率下,使用1ms定时中断测试读写速度:
  18. 1.调用1000次ReadOnePage     用时1419ms
  19. 2.调用1000次WriteOnePage    用时1576ms
  20. 3.调用NandMTDErase擦除100块 用时126ms
  21. 注:如果在ReadOnePage和WriteOnePage中分别加入DEBUG_PRINT(宏定义为NoDEBUG_PRINT,即空函数)时,用时大幅度增加,分别为6973和6730
  22. 孟军 2008-5-26 16:36
  23. */
  24. #include "nand.h"
  25. #include "mcf523x_gpio.h"
  26. #include "m523xevb.h"
  27. /***********************************************************/
  28. /**********************调试用的宏定义***********************/
  29. //读扩展区
  30. #define EXTRA 4
  31. /*错误值 
  32. *仅在纯C下测试用 VxWorks系统中注释掉 
  33. */
  34. #define flTimeOut      0
  35. #define flOK           1
  36. #define flWriteFault   2
  37. #define flReadFault    4
  38. #define flEarseFault   3
  39. #define flBadParameter 5
  40. #define ERROR          0
  41. #define NO_ERROR       1
  42. /**********************调试用的宏定义***********************/
  43. /***********************************************************/
  44. /* Flash IDs
  45. */
  46. #define K9F4G08U0A_FLASH    0xECDC
  47. /* Flash 命令集*/
  48. #define PAGE_PROGRAM_START         0x80
  49. #define PAGE_PROGRAM_END           0x10
  50. #define READ_START                 0x00
  51. #define READ_END                   0x30
  52. #define READ_FOR_COPY_BACK_START   0x00
  53. #define READ_FOR_COPY_BACK_END     0x35
  54. #define COPY_BACK_PROGRAM_START    0x85
  55. #define COPY_BACK_PROGRAM_END      0x10
  56. #define CACHE_PROGRAM_START        0x80
  57. #define CACHE_PROGRAM_END          0x15
  58. #define RANDOM_DATA_INPUT          0x85
  59. #define RANDOM_DATA_OUTPUT_START   0x05
  60. #define RANDOM_DATA_OUTPUT_END     0xe0
  61. #define RESET_FLASH                0xff
  62. #define BLOCK_ERASE_START          0x60
  63. #define BLOCK_ERASE_END            0xd0
  64. #define READ_STATUS                0x70
  65. #define READ_ID                    0x90
  66. /*子函数声明*/
  67. int WaitForReady(void);
  68. int ReadStatusForError(void);
  69. int AddressInput_3Cycle(unsigned int PageNo );
  70. int AddressInput_5Cycle(unsigned long Address );
  71. void NoDEBUG_PRINT(const char *fmt, ...);
  72. /*----------------------------------------------------------------------
  73. *                       ReadOnePage
  74. *功能:读函数
  75. *参数:Address 读取数据的起始地址(flash芯片),Length 长度(字节),buffer 写入数据的起始地址(SDRAM地址)  
  76. *没有ECC校验
  77. *返回FLStatus flTimeOut flOK
  78. *20070202
  79. ----------------------------------------------------------------------*/
  80. int ReadOnePage(unsigned long Address, unsigned int Length, unsigned char *buffer)
  81. {
  82. unsigned int  iLength;
  83. //DEBUG_PRINT("ReadOnePage: block = %d page = %d Address = 0x%x, Length = %dn", (Address>>(BLOCK_SIZE_BITS+1)),((Address&BLOCK_MASK)>>(PAGE_SIZE_BITS+1)),Address, Length);
  84. FLASH_COMMAND=READ_START;/*读命令开始*/
  85. AddressInput_5Cycle(Address);/*发送地址*/
  86. FLASH_COMMAND=READ_END;/*读命令结束*/
  87. /*等待芯片就绪*/
  88. if( WaitForReady() != flOK )
  89. {
  90. return flTimeOut;
  91. }
  92. /*读数据*/
  93. for(iLength=0; iLength<Length; iLength++)
  94. {
  95. *buffer = FLASH_DATA;
  96. //DEBUG_PRINT("ReadOnePage: %d  data = %d ASCII = %c Address = 0x%x n", iLength+1,*buffer,*buffer,Address+iLength);
  97. buffer++;
  98. }
  99. return flOK;/*读成功*/
  100. }
  101. /*----------------------------------------------------------------------
  102. *                     WriteOnePage
  103. *功能:写函数
  104. *参数:Address 写入数据的起始地址(flash芯片),Length 长度(字节),buffer 读出数据的起始地址(SDRAM地址)  
  105. *返回:FLStatus - flTimeOut flWriteFault flOK
  106. *20070202
  107. ----------------------------------------------------------------------*/
  108. int WriteOnePage(unsigned long Address, unsigned int Length, unsigned char *buffer)
  109. {
  110. unsigned int iLength;
  111. //DEBUG_PRINT("WriteOnePage: block = %d page = %d Address = 0x%x, Length = %dn",(Address>>(BLOCK_SIZE_BITS+1)),((Address&BLOCK_MASK)>>(PAGE_SIZE_BITS+1)),Address, Length);
  112. FLASH_COMMAND=PAGE_PROGRAM_START;/*写命令开始*/
  113. AddressInput_5Cycle(Address);/*写地址*/
  114. /*写数据*/
  115. for(iLength=0; iLength<Length; iLength++)
  116. {
  117. FLASH_DATA=*buffer;
  118. //DEBUG_PRINT("WriteOnePage: %d  data = %d ASCII = %c Address= 0x%x n",iLength+1,*buffer,*buffer,Address+iLength);
  119. buffer++;
  120. }
  121. FLASH_COMMAND=PAGE_PROGRAM_END;/*写命令结束*/
  122. /*等待芯片就绪*/
  123. if( WaitForReady() != flOK )
  124. {
  125. return flTimeOut;
  126. }
  127. /*检查写操作是否成功
  128. */
  129. if(ReadStatusForError()==ERROR)
  130. {
  131. return flWriteFault;/*写错误*/
  132. }
  133. return flOK;/*写成功*/
  134. }
  135. /*----------------------------------------------------------------------
  136. *                       AddressInput_5Cycle
  137. *功能:将地址分5个周期输入到flash中
  138. *参数:地址 Address
  139. *时序参考k9f4g08的芯片资料
  140. *20070130
  141. ----------------------------------------------------------------------*/
  142. int AddressInput_5Cycle(unsigned long Address )
  143. {
  144. unsigned long AddressNow;
  145. DATA_ADDRESS=(unsigned char)Address;/*1st cycle A0-A7*/
  146. AddressNow = Address >> 8;
  147. DATA_ADDRESS=(unsigned char)(AddressNow&0x0f);/*2nd cycle A8-A11*/
  148. AddressNow = AddressNow >> 4;
  149. DATA_ADDRESS=(unsigned char)AddressNow;/*3rd cycle A12-A19*/
  150. AddressNow = AddressNow >> 8;
  151. DATA_ADDRESS=(unsigned char)AddressNow;/*4th cycle A20-A27*/
  152. AddressNow = AddressNow >> 8;
  153. DATA_ADDRESS=(unsigned char)(AddressNow&0x03);/*5th cycle A28-A29*/
  154. }
  155. /*----------------------------------------------------------------------
  156. *                       AddressInput_3Cycle
  157. *功能:将18位页号分3个周期输入到flash中
  158. *参数:PageNo 页号
  159. *时序参考k9f4g08的芯片资料。
  160. *20070130
  161. ----------------------------------------------------------------------*/
  162. int AddressInput_3Cycle(unsigned int PageNo )
  163. {
  164. DATA_ADDRESS=(unsigned char)PageNo;             /*1st cycle A12-A19*/
  165. DATA_ADDRESS=(unsigned char)(PageNo>>8);        /*2nd cycle A20-A27*/
  166. DATA_ADDRESS=(unsigned char)((PageNo>>16)&0x03);/*3rd cycle A28-A29*/
  167. }
  168. /*----------------------------------------------------------------------
  169. *               ReadStatusForError
  170. *功能:读状态寄存器.
  171. *返回:TRUE-Error FAULT-NoError.
  172. *20070202
  173. ----------------------------------------------------------------------*/
  174. int ReadStatusForError(void)
  175. {
  176. unsigned char chipStatus;/*芯片状态*/
  177. FLASH_COMMAND = READ_STATUS;/*读芯片状态命令*/
  178. chipStatus=FLASH_DATA;/*读取状态*/
  179. if( chipStatus&1 )/*I/O0不等于0 Error*/
  180. {
  181. return ERROR;/*Error*/
  182. }
  183. return NO_ERROR;/*NoError*/
  184. }
  185. /*----------------------------------------------------------------------
  186. *               WaitForReady
  187. *功能:等待芯片就绪.
  188. *参数:无
  189. *返回:flOK flTimeOut
  190. *20080519
  191. ----------------------------------------------------------------------*/
  192. int WaitForReady(void)
  193. {
  194.   unsigned long i=0;
  195. for(i=0;i<0xff;i++)
  196. {
  197.   if(BUSY_IO == 1)
  198.   {
  199.     return flOK;
  200.   }
  201. }
  202. return flTimeOut;
  203. }
  204. /*----------------------------------------------------------------------
  205. *                NandMTDRead
  206. *功能:从flash中读取数据。该程序将作为MTD读函数。
  207. *参数:Address-读地址 buffer-写数据指针 Length-长度(字节) 
  208.       modes-EXTRA:读扩展区;其他:读数据区
  209. *返回:成功返回flOK 失败返回flReadFault
  210. *20070315
  211. ----------------------------------------------------------------------*/
  212. int NandMTDRead( unsigned long Address, unsigned char *buffer, unsigned int Length, unsigned int modes)
  213. {
  214. unsigned char *temp;
  215. unsigned char AddressAvailableFlag;/*地址有效标志*/
  216. unsigned int LeftToRead;/*一个页面中偏移地址之后的空间大小,能表示现在读的位置*/
  217. unsigned int ReadStatus;/*读状态*/
  218. unsigned int PageSize;
  219. /*根据modes参数 设定所读区域大小 是读数据区 还是空闲区 并判断地址是否有效*/
  220. if(modes&EXTRA)/*空闲区 页地址大于等于PAGE_SIZE且小于PAGE_SIZE+SPARE_SIZE有效*/
  221. {
  222. PageSize = SPARE_SIZE;
  223. if( ( ( (unsigned short)Address & PAGE_MASK ) >= PAGE_SIZE)
  224. &&  ( ( (unsigned short)Address & PAGE_MASK ) < PAGE_SIZE+SPARE_SIZE) 
  225. &&  ( Address+Length <= MAX_ADDRESS ) )
  226. {
  227. AddressAvailableFlag = 1;/*地址有效*/
  228. }
  229. else
  230. {
  231. AddressAvailableFlag = 0;/*地址无效*/
  232. }
  233. }
  234. else/*modes!=EXTRA 数据区 页地址大于等于0且小于PAGE_SIZE有效*/
  235. {
  236. PageSize = PAGE_SIZE;
  237. if( ( ( (unsigned short)Address & PAGE_MASK ) >= 0)
  238. &&  ( ( (unsigned short)Address & PAGE_MASK ) < PAGE_SIZE)
  239. &&  ( Address+Length <= (MAX_ADDRESS-SPARE_SIZE) ) )
  240. {
  241. AddressAvailableFlag = 1;/*地址有效*/
  242. }
  243. else
  244. {
  245. AddressAvailableFlag = 0;/*地址无效*/
  246. }
  247. }
  248. /*越界错误*/
  249. if(!AddressAvailableFlag)    /* 越界 */
  250. {
  251. ERROR_PRINT("NandMTDRead:OutOfBoundary Address = 0x%x, Length = %dn",Address, Length);
  252. return flBadParameter;
  253. }
  254. /*计算一个页面中偏移地址之后的空间大小*/
  255. LeftToRead = PageSize - ( (unsigned short)Address & (PageSize - 1) );
  256. /*将buffer指针赋给temp*/
  257. temp = buffer;
  258. DEBUG_PRINT("NandMTDRead: Address = 0x%x, Length = %dn", Address, Length);
  259. for ( ; Length > 0 ; )
  260. {
  261. if( Length < LeftToRead )   /* 如果要读的长度小于一个页面中偏移地址之后的空间大小 */
  262. {
  263. LeftToRead = Length;    /* 那要读的就是该长度*/
  264. }
  265. /* 如果要读的长度大于一个页面的大小,就先读一个页面 *//* turn off EDC on partial block read*/
  266. ReadStatus=ReadOnePage(Address,LeftToRead,temp);
  267. if(ReadStatus!=flOK)/*如果读取错误,返回flReadFault*/
  268. {
  269. ERROR_PRINT("NandMTDRead:ReadErrorn");
  270. return flReadFault;
  271. }
  272. Length = Length - LeftToRead;/*更新长度*/
  273. if(Length>0)
  274. {
  275. if(PageSize==PAGE_SIZE)/*如果是读数据区*/
  276. {
  277. Address = (Address&CHIP_MASK)+(PAGE_SIZE*2);/*页地址加1,地址变为下一页的数据区*/
  278. }
  279. else if( PageSize==SPARE_SIZE)/*如果是读空闲区*/
  280. {
  281. Address = (Address&CHIP_MASK)+(PAGE_SIZE*3);/*地址变为下一页的空闲区*/
  282. }
  283. temp = temp + LeftToRead;/*移动指针*/
  284. LeftToRead = PageSize;/*新的一页 更新LeftToRead*/
  285. }
  286. }
  287. return flOK;
  288. }
  289. /*----------------------------------------------------------------------
  290. *                NandMTDWrite
  291. *功能:对flash写入数据。该程序将作为MTD写函数。
  292. *参数:Address-写地址 buffer-读数据指针 Length-长度(字节) 
  293.       modes-EXTRA:写扩展区;其他:写数据区
  294. *返回:成功返回flOK 失败返回flWriteFault
  295. *20070315
  296. ----------------------------------------------------------------------*/
  297. int NandMTDWrite( unsigned long Address,unsigned char *buffer,unsigned int Length, unsigned int modes)
  298. {
  299. unsigned char *temp;
  300. unsigned char AddressAvailableFlag;/*地址有效标志*/
  301. unsigned int LeftToWrite;/*一个页面中偏移地址之后的空间大小,能表示现在写的位置*/
  302. unsigned int WriteStatus;/*写状态*/
  303. unsigned int PageSize = PAGE_SIZE;
  304. /*根据modes参数 设定所读区域大小 是读数据区 还是空闲区 并判断地址是否有效*/
  305. if(modes&EXTRA)/*空闲区 页地址大于等于PAGE_SIZE且小于PAGE_SIZE+SPARE_SIZE有效*/
  306. {
  307. PageSize = SPARE_SIZE;
  308. if( ( ( (unsigned short)Address & PAGE_MASK ) >= PAGE_SIZE)
  309. &&  ( ( (unsigned short)Address & PAGE_MASK ) < PAGE_SIZE+SPARE_SIZE) 
  310. &&  ( Address+Length <= MAX_ADDRESS ) )
  311. {
  312. AddressAvailableFlag = 1;/*地址有效*/
  313. }
  314. else
  315. {
  316. AddressAvailableFlag = 0;/*地址无效*/
  317. }
  318. }
  319. else/*modes!=EXTRA 数据区 页地址大于等于0且小于PAGE_SIZE有效*/
  320. {
  321. PageSize = PAGE_SIZE;
  322. if( ( ( (unsigned short)Address & PAGE_MASK ) >= 0)
  323. &&  ( ( (unsigned short)Address & PAGE_MASK ) < PAGE_SIZE)
  324. &&  ( Address+Length <= (MAX_ADDRESS-SPARE_SIZE) ) )
  325. {
  326. AddressAvailableFlag = 1;/*地址有效*/
  327. }
  328. else
  329. {
  330. AddressAvailableFlag = 0;/*地址无效*/
  331. }
  332. }
  333. /*越界错误*/
  334. if(!AddressAvailableFlag)    /* 越界 */
  335. {
  336. ERROR_PRINT("NandMTDWrite:OutOfBoundary Address = 0x%x, Length = %dn",Address, Length);
  337. return flBadParameter;
  338. }
  339. /*是否开启写后校验*/
  340. #undef VERIFY_AFTER_WRITE
  341. #ifdef VERIFY_AFTER_WRITE
  342.  unsigned long  saveAddress = Address;
  343.  unsigned char flReadback[BLOCKS_PER_CHIP * PAGE_SIZE / sizeof(unsigned short)];
  344. #endif/*是否开启写后校验*/
  345. /*计算一个页面中偏移地址之后的空间大小*/
  346. LeftToWrite = PageSize - ( (unsigned short)Address & (PageSize - 1) );
  347. /*将buffer指针赋给temp*/
  348. temp = buffer;
  349. DEBUG_PRINT("NandMTDWrite: Address = 0x%x, Length = %dn", Address, Length);
  350. for( ; Length > 0 ; )
  351. {
  352. if( Length < LeftToWrite ) /* 如果要写的长度小于一个页面中偏移地址之后的空间大小 */
  353. {
  354. LeftToWrite = Length;  /* 那要写的就是该长度*/
  355. }
  356. /* 如果要读的长度大于一个页面的大小,就先读一个页面 *//* turn off EDC on partial block write*/
  357. WriteStatus = WriteOnePage(Address,LeftToWrite,temp);
  358. if(WriteStatus != flOK)/*如果写错误,返回flWriteFault*/
  359. {
  360. ERROR_PRINT("NandMTDWrite:WriteErrorn");
  361. return flWriteFault;
  362. }
  363. /*写后校验*/
  364. #ifdef VERIFY_AFTER_WRITE
  365. WriteStatus = ReadOnePage (Address,flReadback,LeftToWrite));
  366. if( (WriteStatus != flOK) || ( tffscmp(temp, flReadback, LeftToWrite ) != 0) )/*校验数据*/
  367. {
  368. ERROR_PRINT("NandMTDWrite:VerifyErrorn");
  369. return flWriteFault;
  370. }
  371. #endif/*VERIFY_AFTER_WRITE*/
  372. /*写后校验*/
  373. Length = Length - LeftToWrite;/*更新长度*/
  374. if(Length > 0)
  375. {
  376. if(PageSize==PAGE_SIZE)/*如果是写数据区*/
  377. {
  378. Address = (Address&CHIP_MASK)+(PAGE_SIZE*2);/*页地址加1,地址变为下一页的数据区*/
  379. }
  380. else if( PageSize==SPARE_SIZE)/*如果是写空闲区*/
  381. {
  382. Address = (Address&CHIP_MASK)+(PAGE_SIZE*3);/*地址变为下一页的空闲区*/
  383. }
  384. temp = temp + LeftToWrite;/*移动指针*/
  385. LeftToWrite = PageSize;/*新的一页 更新LeftToWrite*/
  386. }
  387. }
  388. return flOK ;
  389. }
  390. /*----------------------------------------------------------------------
  391. *                NandMTDErase
  392. *功能:对flash进行擦除操作。该程序将作为MTD擦除函数。
  393. *参数:vol-设备指针 BlockNo-块号 BlocksToErase—需要擦除的块的总数
  394. *返回:成功返回flOK 失败返回其他
  395. *20070202
  396. ----------------------------------------------------------------------*/
  397. int NandMTDErase(unsigned int BlockNo,unsigned int BlocksToErase)
  398. {
  399. unsigned int iBlock;
  400. unsigned int PageNo;
  401. if( BlockNo + BlocksToErase > BLOCKS_PER_CHIP )    /* 越界 */
  402. {
  403. ERROR_PRINT("NandMTDErase:OutOfBoundary BlockNo = %d BlocksToErase = %dn",BlockNo, BlocksToErase);
  404. return flBadParameter;
  405. }
  406. DEBUG_PRINT("firstBlock = %d, numOfBlock = %dn", BlockNo, BlocksToErase);
  407. for ( iBlock=0; iBlock < BlocksToErase; iBlock++, BlockNo++ )
  408. {
  409. PageNo = BlockNo*PAGES_PER_BLOCK;/*计算页号*/
  410. FLASH_COMMAND=BLOCK_ERASE_START;/*输入擦除命令*/
  411. AddressInput_3Cycle(PageNo);/*将擦除地址输入*/
  412. FLASH_COMMAND=BLOCK_ERASE_END;/*执行擦除*/
  413. /*等待芯片就绪*/
  414. if( WaitForReady() != flOK )
  415. {
  416. ERROR_PRINT("NandMTDErase: TimeOutn");
  417. return flTimeOut;
  418. }
  419. /*检查写操作是否成功*/
  420. if(ReadStatusForError()==ERROR)
  421. {
  422. ERROR_PRINT("NandMTDErase:EraseErrorn");
  423. return flEarseFault;
  424. }
  425. DEBUG_PRINT("ERASE: BlockNo = %d Erased!n", BlockNo);
  426. }
  427. return flOK;
  428. }
  429. /*----------------------------------------------------------------------
  430. *                NoDEBUG_PRINT
  431. *功能:不需要打印信息时将printf指向这个空函数
  432. *参数:空
  433. *返回:无
  434. *20070305
  435. ----------------------------------------------------------------------*/
  436. void NoDEBUG_PRINT( const char *fmt, ... )
  437. {}
  438. /*----------------------------------------------------------------------
  439. *                BusyGPIOInit
  440. *功能:初始化busy管脚所连接的GPIO
  441. *参数:空
  442. *返回:无
  443. *20080519
  444. ----------------------------------------------------------------------*/
  445. void BusyGPIOInit(void)
  446. {
  447.   MCF_GPIO_PAR_ETPU  = MCF_GPIO_PAR_ETPU & 0xfe;//LTPUODIS为GPIO功能
  448.   MCF_GPIO_PDDR_ETPU = MCF_GPIO_PDDR_ETPU & 0xfe;//LTPUODIS为GPIO输入
  449. }
  450. /*----------------------------------------------------------------------
  451. *                NandFlashCSConfig
  452. *功能:配置片选,建议将函数内容复制到hwinit.c的mcf523x_cs_init()函数中
  453. *参数:空
  454. *返回:无
  455. *20080519
  456. ----------------------------------------------------------------------*/
  457. void NandFlashCSConfig(void)
  458. {
  459.   MCF_CS_CSAR1 = MCF_CS_CSAR_BA(0x30000000);
  460. MCF_CS_CSCR1 = (0
  461. | MCF_CS_CSCR_IWS(6)
  462. | MCF_CS_CSCR_AA
  463. | MCF_CS_CSCR_PS_8);
  464. MCF_CS_CSMR1 = MCF_CS_CSMR_BAM_1M | MCF_CS_CSMR_V;
  465. }