你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F407 FSMC驱动MT29F4G08A NAND FLASH源代码分享

[复制链接]
STMCU小助手 发布时间:2022-4-21 21:00
一、MT29F4G08A概述
   MT29F4G08是一颗 512MB 的 NAND FLASH 芯片相对于 SPI FLASH( W25Q256)和 SD 卡等存储设备,NAND FLASH 采用 8 位并口访问,具有访问速度快的优势。
1、NAND FLASH信号线

$KO2IP4KQQM{LB11{M{ZF90.png

2、NAND FLASH 存储阵列
S8C}8~@YXSWD_0WIHK62_NY.png

由图可知: MT29F4G08 由 2 个 plane 组成,每个 plane 有 2048 个 block,每个 block 由 64个 page 组成,每个 page 有 2K+64 字节( 2112 字节)的存储容量。所以, MT29F4G08 的总容量为: 2204864*( 2K+64) = 553648128 字节( 512MB)。其中, plane、 block、 page 等的个数根据 NAND FLASH 型号的不同,会有所区别,大家注意查看对应 NAND FLASH 芯片的数据
手册。
NAND FLASH 的最小擦除单位是 block,对 MT29F4G08 来说,是( 128+4) K 字节, NANDFLASH 的写操作具有只可以写 0,不能写 1 的特性,所以,在写数据的时候,必须先擦除 block(擦除后, block 数据全部为 1),才可以写入。NAND FLASH 的 page 由 2 部分组成:数据存储区( data area)和备用区域( spare area),对 MT29F4G08 来说,数据存储区大小为 2K 字节,备用区域大小为 64 字节。我们存储的有效数据,一般都是存储在数据存储区( data area)。备用区域( spare area),一般用来存放 ECC( ErrorChecking and Correcting)校验值,在工程中,我们将利用这个区域,来实现 NAND FLASH 坏块管理和磨损均衡。
NAND FLASH 的地址分为三类:块地址( Block Address)、页地址( Page Address)和列地址( Column Address)。以 MT29F4G08 为例,这三个地址,通过 5 个周期发送。

二、部分参考代码

  1. FSMC_NANDInitTypeDef NAND_Handler;    //NAND FLASH句柄
  2. nand_attriute nand_dev;             //nand重要参数结构体

  3. //初始化NAND FLASH
  4. u8 NAND_Init(void)
  5. {
  6.         GPIO_InitTypeDef GPIO_InitStructure;
  7.     FSMC_NAND_PCCARDTimingInitTypeDef ComSpaceTiming,AttSpaceTiming;

  8.         
  9.         
  10.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_GPIOE|RCC_AHB1Periph_GPIOG, ENABLE);//使能PD,PE,PF,PG时钟  
  11.         RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC,ENABLE);//使能FSMC时钟  
  12.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);


  13.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_14|GPIO_Pin_15;
  14.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用输出
  15.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
  16.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  17.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  18.         GPIO_Init(GPIOD, &GPIO_InitStructure);//初始化  


  19.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10;
  20.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用输出
  21.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
  22.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  23.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  24.         GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化


  25.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  26.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用输出
  27.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
  28.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  29.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  30.         GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化
  31.         
  32.         
  33.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  34.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  35.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  36.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  37.         GPIO_Init(GPIOD, &GPIO_InitStructure);
  38.         
  39.         
  40.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  41.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  42.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  43.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  44.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  45.         GPIO_Init(GPIOD, &GPIO_InitStructure);
  46.         GPIO_SetBits(GPIOD,GPIO_Pin_2);

  47.         GPIO_PinAFConfig(GPIOD,GPIO_PinSource0,GPIO_AF_FSMC);//PD0,AF12
  48.         GPIO_PinAFConfig(GPIOD,GPIO_PinSource1,GPIO_AF_FSMC);//PD1,AF12
  49.         GPIO_PinAFConfig(GPIOD,GPIO_PinSource4,GPIO_AF_FSMC);//PD0,AF12
  50.         GPIO_PinAFConfig(GPIOD,GPIO_PinSource5,GPIO_AF_FSMC);//PD1,AF12        
  51.         GPIO_PinAFConfig(GPIOD,GPIO_PinSource14,GPIO_AF_FSMC);
  52.         GPIO_PinAFConfig(GPIOD,GPIO_PinSource15,GPIO_AF_FSMC);//PD15,AF12
  53.         
  54.         GPIO_PinAFConfig(GPIOE,GPIO_PinSource3,GPIO_AF_FSMC);//PE7,AF12
  55.         GPIO_PinAFConfig(GPIOE,GPIO_PinSource4,GPIO_AF_FSMC);
  56.         GPIO_PinAFConfig(GPIOE,GPIO_PinSource7,GPIO_AF_FSMC);//PE7,AF12
  57.         GPIO_PinAFConfig(GPIOE,GPIO_PinSource8,GPIO_AF_FSMC);
  58.         GPIO_PinAFConfig(GPIOE,GPIO_PinSource9,GPIO_AF_FSMC);
  59.         GPIO_PinAFConfig(GPIOE,GPIO_PinSource10,GPIO_AF_FSMC);

  60.         GPIO_PinAFConfig(GPIOG,GPIO_PinSource9,GPIO_AF_FSMC);        
  61.         
  62.         
  63.         
  64.         
  65.         ComSpaceTiming.FSMC_SetupTime=2;         //建立时间
  66.     ComSpaceTiming.FSMC_WaitSetupTime=3;     //等待时间
  67.     ComSpaceTiming.FSMC_HoldSetupTime=2;     //保持时间
  68.     ComSpaceTiming.FSMC_HiZSetupTime=1;      //高阻态时间

  69.     AttSpaceTiming.FSMC_SetupTime=2;         //建立时间
  70.     AttSpaceTiming.FSMC_WaitSetupTime=3;     //等待时间
  71.     AttSpaceTiming.FSMC_HoldSetupTime=2;     //保持时间
  72.     AttSpaceTiming.FSMC_HiZSetupTime=1;      //高阻态时间        

  73.         
  74.     NAND_Handler.FSMC_Bank=FSMC_Bank3_NAND;                          //NAND挂在BANK3上
  75.     NAND_Handler.FSMC_Waitfeature=FSMC_Waitfeature_Disable;                    //关闭等待特性
  76.     NAND_Handler.FSMC_MemoryDataWidth=FSMC_MemoryDataWidth_8b;     //8位数据宽度
  77.     NAND_Handler.FSMC_ECC=FSMC_ECC_Disable;              //不使用ECC
  78.     NAND_Handler.FSMC_ECCPageSize=FSMC_ECCPageSize_2048Bytes;      //ECC页大小为2k
  79.     NAND_Handler.FSMC_TCLRSetupTime=0;                                  //设置TCLR(tCLR=CLE到RE的延时)=(TCLR+TSET+2)*THCLK,THCLK=1/180M=5.5ns
  80.     NAND_Handler.FSMC_TARSetupTime=1;                                   //设置TAR(tAR=ALE到RE的延时)=(TAR+TSET+2)*THCLK,THCLK=1/180M=5.5n。   
  81.         NAND_Handler.FSMC_CommonSpaceTimingStruct=&ComSpaceTiming;
  82.         NAND_Handler.FSMC_AttributeSpaceTimingStruct=&AttSpaceTiming;               
  83.         
  84.         
  85.         
  86.     FSMC_NANDInit(&NAND_Handler);
  87.     FSMC_NANDCmd(FSMC_Bank3_NAND,ENABLE);
  88.          
  89.     NAND_Reset();                               //复位NAND
  90.     delay_ms(100);
  91.     nand_dev.id=NAND_ReadID();                //读取ID
  92.         NAND_ModeSet(4);                                //设置为MODE4,高速模式
  93.         if(nand_dev.id==MT29F4G08ABADA)//NAND为MT29F4G08ABADA
  94.     {
  95.         nand_dev.page_totalsize=2112;        //nand一个page的总大小(包括spare区)
  96.         nand_dev.page_mainsize=2048;         //nand一个page的有效数据区大小
  97.         nand_dev.page_sparesize=64;                //nand一个page的spare区大小
  98.         nand_dev.block_pagenum=64;                //nand一个block所包含的page数目
  99.         nand_dev.plane_blocknum=2048;        //nand一个plane所包含的block数目
  100.         nand_dev.block_totalnum=4096;         //nand的总block数目
  101.     }else return 1;        //错误,返回
  102.     return 0;
  103. }


  104. //读取NAND FLASH的ID
  105. //返回值:0,成功;
  106. //    其他,失败
  107. u8 NAND_ModeSet(u8 mode)
  108. {   
  109.     *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_FEATURE;//发送设置特性命令
  110.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=0X01;                //地址为0X01,设置mode
  111.          *(vu8*)NAND_ADDRESS=mode;                                        //P1参数,设置mode
  112.         *(vu8*)NAND_ADDRESS=0;
  113.         *(vu8*)NAND_ADDRESS=0;
  114.         *(vu8*)NAND_ADDRESS=0;
  115.     if(NAND_WaitForReady()==NSTA_READY)return 0;//成功
  116.     else return 1;                                                                //失败
  117. }

  118. //读取NAND FLASH的ID
  119. //不同的NAND略有不同,请根据自己所使用的NAND FALSH数据手册来编写函数
  120. //返回值:NAND FLASH的ID值
  121. u32 NAND_ReadID(void)
  122. {
  123.     u8 deviceid[5];
  124.     u32 id;  
  125.     *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_READID; //发送读取ID命令
  126.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=0X00;
  127.         //ID一共有5个字节
  128.     deviceid[0]=*(vu8*)NAND_ADDRESS;      
  129.     deviceid[1]=*(vu8*)NAND_ADDRESS;  
  130.     deviceid[2]=*(vu8*)NAND_ADDRESS;
  131.     deviceid[3]=*(vu8*)NAND_ADDRESS;
  132.     deviceid[4]=*(vu8*)NAND_ADDRESS;  
  133.     //镁光的NAND FLASH的ID一共5个字节,但是为了方便我们只取4个字节组成一个32位的ID值
  134.     //根据NAND FLASH的数据手册,只要是镁光的NAND FLASH,那么一个字节ID的第一个字节都是0X2C
  135.     //所以我们就可以抛弃这个0X2C,只取后面四字节的ID值。
  136.     id=((u32)deviceid[1])<<24|((u32)deviceid[2])<<16|((u32)deviceid[3])<<8|deviceid[4];
  137.     return id;
  138. }  
  139. //读NAND状态
  140. //返回值:NAND状态值
  141. //bit0:0,成功;1,错误(编程/擦除/READ)
  142. //bit6:0,Busy;1,Ready
  143. u8 NAND_ReadStatus(void)
  144. {
  145.     vu8 data=0;
  146.     *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_READSTA;//发送读状态命令
  147.     NAND_Delay(NAND_TWHR_DELAY);        //等待tWHR,再读取状态寄存器
  148.          data=*(vu8*)NAND_ADDRESS;                        //读取状态值
  149.     return data;
  150. }
  151. //等待NAND准备好
  152. //返回值:NSTA_TIMEOUT 等待超时了
  153. //      NSTA_READY    已经准备好
  154. u8 NAND_WaitForReady(void)
  155. {
  156.     u8 status=0;
  157.     vu32 time=0;
  158.         while(1)                                                //等待ready
  159.         {
  160.                 status=NAND_ReadStatus();        //获取状态值
  161.                 if(status&NSTA_READY)break;
  162.                 time++;
  163.                 if(time>=0X1FFFFFFF)return NSTA_TIMEOUT;//超时
  164.         }  
  165.     return NSTA_READY;//准备好
  166. }  
  167. //复位NAND
  168. //返回值:0,成功;
  169. //    其他,失败
  170. u8 NAND_Reset(void)
  171. {
  172.     *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_RESET;        //复位NAND
  173.     if(NAND_WaitForReady()==NSTA_READY)return 0;//复位成功
  174.     else return 1;                                                                //复位失败
  175. }
  176. //等待RB信号为某个电平
  177. //rb:0,等待RB==0
  178. //   1,等待RB==1
  179. //返回值:0,成功
  180. //       1,超时
  181. u8 NAND_WaitRB(vu8 rb)
  182. {
  183.     vu32 time=0;  
  184.         while(time<0X1FFFFFF)
  185.         {
  186.                 time++;
  187.                 if(NAND_RB==rb)return 0;
  188.         }
  189.         return 1;
  190. }
  191. //NAND延时
  192. //一个i++至少需要4ns
  193. void NAND_Delay(vu32 i)
  194. {
  195.         while(i>0)i--;
  196. }
  197. //读取NAND Flash的指定页指定列的数据(main区和spare区都可以使用此函数)
  198. //PageNum:要读取的页地址,范围:0~(block_pagenum*block_totalnum-1)
  199. //ColNum:要读取的列开始地址(也就是页内地址),范围:0~(page_totalsize-1)
  200. //*pBuffer:指向数据存储区
  201. //NumByteToRead:读取字节数(不能跨页读)
  202. //返回值:0,成功
  203. //    其他,错误代码
  204. u8 NAND_ReadPage(u32 PageNum,u16 ColNum,u8 *pBuffer,u16 NumByteToRead)
  205. {
  206.     vu16 i=0;
  207.         u8 res=0;
  208.         u8 eccnum=0;                //需要计算的ECC个数,每NAND_ECC_SECTOR_SIZE字节计算一个ecc
  209.         u8 eccstart=0;                //第一个ECC值所属的地址范围
  210.         u8 errsta=0;
  211.         u8 *p;
  212.      *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_AREA_A;
  213.     //发送地址
  214.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)ColNum;
  215.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(ColNum>>8);
  216.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)PageNum;
  217.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(PageNum>>8);
  218.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(PageNum>>16);
  219.     *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_AREA_TRUE1;
  220.     //下面两行代码是等待R/B引脚变为低电平,其实主要起延时作用的,等待NAND操作R/B引脚。因为我们是通过
  221.     //将STM32的NWAIT引脚(NAND的R/B引脚)配置为普通IO,代码中通过读取NWAIT引脚的电平来判断NAND是否准备
  222.     //就绪的。这个也就是模拟的方法,所以在速度很快的时候有可能NAND还没来得及操作R/B引脚来表示NAND的忙
  223.     //闲状态,结果我们就读取了R/B引脚,这个时候肯定会出错的,事实上确实是会出错!大家也可以将下面两行
  224.     //代码换成延时函数,只不过这里我们为了效率所以没有用延时函数。
  225.         res=NAND_WaitRB(0);                        //等待RB=0
  226.     if(res)return NSTA_TIMEOUT;        //超时退出
  227.     //下面2行代码是真正判断NAND是否准备好的
  228.         res=NAND_WaitRB(1);                        //等待RB=1
  229.     if(res)return NSTA_TIMEOUT;        //超时退出
  230.         if(NumByteToRead%NAND_ECC_SECTOR_SIZE)//不是NAND_ECC_SECTOR_SIZE的整数倍,不进行ECC校验
  231.         {
  232.                 //读取NAND FLASH中的值
  233.                 for(i=0;i<NumByteToRead;i++)
  234.                 {
  235.                         *(vu8*)pBuffer++ = *(vu8*)NAND_ADDRESS;
  236.                 }
  237.         }else
  238.         {
  239.                 eccnum=NumByteToRead/NAND_ECC_SECTOR_SIZE;                        //得到ecc计算次数
  240.                 eccstart=ColNum/NAND_ECC_SECTOR_SIZE;
  241.                 p=pBuffer;
  242.                 for(res=0;res<eccnum;res++)
  243.                 {
  244.                         FSMC_Bank3->PCR3|=1<<6;                                                //使能ECC校验
  245.                         for(i=0;i<NAND_ECC_SECTOR_SIZE;i++)                                //读取NAND_ECC_SECTOR_SIZE个数据
  246.                         {
  247.                                 *(vu8*)pBuffer++ = *(vu8*)NAND_ADDRESS;
  248.                         }               
  249.                         while(!(FSMC_Bank3->SR3&(1<<6)));                                //等待FIFO空        
  250.                         nand_dev.ecc_hdbuf[res+eccstart]=FSMC_Bank3->ECCR3;//读取硬件计算后的ECC值
  251.                         FSMC_Bank3->PCR3&=~(1<<6);                                                //禁止ECC校验
  252.                 }
  253.                 i=nand_dev.page_mainsize+0X10+eccstart*4;                        //从spare区的0X10位置开始读取之前存储的ecc值
  254.                 NAND_Delay(NAND_TRHW_DELAY);//等待tRHW
  255.                 *(vu8*)(NAND_ADDRESS|NAND_CMD)=0X05;                                //随机读指令
  256.                 //发送地址
  257.                 *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)i;
  258.                 *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(i>>8);
  259.                 *(vu8*)(NAND_ADDRESS|NAND_CMD)=0XE0;                                //开始读数据
  260.                 NAND_Delay(NAND_TWHR_DELAY);//等待tWHR
  261.                 pBuffer=(u8*)&nand_dev.ecc_rdbuf[eccstart];
  262.                 for(i=0;i<4*eccnum;i++)                                                                //读取保存的ECC值
  263.                 {
  264.                         *(vu8*)pBuffer++= *(vu8*)NAND_ADDRESS;
  265.                 }                        
  266.                 for(i=0;i<eccnum;i++)                                                                //检验ECC
  267.                 {
  268.                         if(nand_dev.ecc_rdbuf[i+eccstart]!=nand_dev.ecc_hdbuf[i+eccstart])//不相等,需要校正
  269.                         {
  270.                                 printf("err hd,rd:0x%x,0x%x\r\n",nand_dev.ecc_hdbuf[i+eccstart],nand_dev.ecc_rdbuf[i+eccstart]);
  271.                                  printf("eccnum,eccstart:%d,%d\r\n",eccnum,eccstart);        
  272.                                 printf("PageNum,ColNum:%d,%d\r\n",PageNum,ColNum);        
  273.                                 res=NAND_ECC_Correction(p+NAND_ECC_SECTOR_SIZE*i,nand_dev.ecc_rdbuf[i+eccstart],nand_dev.ecc_hdbuf[i+eccstart]);//ECC校验
  274.                                 if(res)errsta=NSTA_ECC2BITERR;                                //标记2BIT及以上ECC错误
  275.                                 else errsta=NSTA_ECC1BITERR;                                //标记1BIT ECC错误
  276.                         }
  277.                 }                 
  278.         }
  279.     if(NAND_WaitForReady()!=NSTA_READY)errsta=NSTA_ERROR;        //失败
  280.     return errsta;        //成功   
  281. }
  282. //读取NAND Flash的指定页指定列的数据(main区和spare区都可以使用此函数),并对比(FTL管理时需要)
  283. //PageNum:要读取的页地址,范围:0~(block_pagenum*block_totalnum-1)
  284. //ColNum:要读取的列开始地址(也就是页内地址),范围:0~(page_totalsize-1)
  285. //CmpVal:要对比的值,以u32为单位
  286. //NumByteToRead:读取字数(以4字节为单位,不能跨页读)
  287. //NumByteEqual:从初始位置持续与CmpVal值相同的数据个数
  288. //返回值:0,成功
  289. //    其他,错误代码
  290. u8 NAND_ReadPageComp(u32 PageNum,u16 ColNum,u32 CmpVal,u16 NumByteToRead,u16 *NumByteEqual)
  291. {
  292.     u16 i=0;
  293.         u8 res=0;
  294.     *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_AREA_A;
  295.     //发送地址
  296.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)ColNum;
  297.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(ColNum>>8);
  298.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)PageNum;
  299.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(PageNum>>8);
  300.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(PageNum>>16);
  301.     *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_AREA_TRUE1;
  302.     //下面两行代码是等待R/B引脚变为低电平,其实主要起延时作用的,等待NAND操作R/B引脚。因为我们是通过
  303.     //将STM32的NWAIT引脚(NAND的R/B引脚)配置为普通IO,代码中通过读取NWAIT引脚的电平来判断NAND是否准备
  304.     //就绪的。这个也就是模拟的方法,所以在速度很快的时候有可能NAND还没来得及操作R/B引脚来表示NAND的忙
  305.     //闲状态,结果我们就读取了R/B引脚,这个时候肯定会出错的,事实上确实是会出错!大家也可以将下面两行
  306.     //代码换成延时函数,只不过这里我们为了效率所以没有用延时函数。
  307.         res=NAND_WaitRB(0);                        //等待RB=0
  308.         if(res)return NSTA_TIMEOUT;        //超时退出
  309.     //下面2行代码是真正判断NAND是否准备好的
  310.         res=NAND_WaitRB(1);                        //等待RB=1
  311.     if(res)return NSTA_TIMEOUT;        //超时退出  
  312.     for(i=0;i<NumByteToRead;i++)//读取数据,每次读4字节
  313.     {
  314.                 if(*(vu32*)NAND_ADDRESS!=CmpVal)break;        //如果有任何一个值,与CmpVal不相等,则退出.
  315.     }
  316.         *NumByteEqual=i;                                        //与CmpVal值相同的个数
  317.     if(NAND_WaitForReady()!=NSTA_READY)return NSTA_ERROR;//失败
  318.     return 0;        //成功   
  319. }
  320. //在NAND一页中写入指定个字节的数据(main区和spare区都可以使用此函数)
  321. //PageNum:要写入的页地址,范围:0~(block_pagenum*block_totalnum-1)
  322. //ColNum:要写入的列开始地址(也就是页内地址),范围:0~(page_totalsize-1)
  323. //pBbuffer:指向数据存储区
  324. //NumByteToWrite:要写入的字节数,该值不能超过该页剩余字节数!!!
  325. //返回值:0,成功
  326. //    其他,错误代码
  327. u8 NAND_WritePage(u32 PageNum,u16 ColNum,u8 *pBuffer,u16 NumByteToWrite)
  328. {
  329.     vu16 i=0;  
  330.         u8 res=0;
  331.         u8 eccnum=0;                //需要计算的ECC个数,每NAND_ECC_SECTOR_SIZE字节计算一个ecc
  332.         u8 eccstart=0;                //第一个ECC值所属的地址范围
  333.         
  334.         *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_WRITE0;
  335.     //发送地址
  336.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)ColNum;
  337.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(ColNum>>8);
  338.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)PageNum;
  339.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(PageNum>>8);
  340.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(PageNum>>16);
  341.         NAND_Delay(NAND_TADL_DELAY);//等待tADL
  342.         if(NumByteToWrite%NAND_ECC_SECTOR_SIZE)//不是NAND_ECC_SECTOR_SIZE的整数倍,不进行ECC校验
  343.         {  
  344.                 for(i=0;i<NumByteToWrite;i++)                //写入数据
  345.                 {
  346.                         *(vu8*)NAND_ADDRESS=*(vu8*)pBuffer++;
  347.                 }
  348.         }else
  349.         {
  350.                 eccnum=NumByteToWrite/NAND_ECC_SECTOR_SIZE;                        //得到ecc计算次数
  351.                 eccstart=ColNum/NAND_ECC_SECTOR_SIZE;
  352.                  for(res=0;res<eccnum;res++)
  353.                 {
  354.                         FSMC_Bank3->PCR3|=1<<6;                                                //使能ECC校验
  355.                         for(i=0;i<NAND_ECC_SECTOR_SIZE;i++)                                //写入NAND_ECC_SECTOR_SIZE个数据
  356.                         {
  357.                                 *(vu8*)NAND_ADDRESS=*(vu8*)pBuffer++;
  358.                         }               
  359.                         while(!(FSMC_Bank3->SR3&(1<<6)));                                //等待FIFO空        
  360.                         nand_dev.ecc_hdbuf[res+eccstart]=FSMC_Bank3->ECCR3;        //读取硬件计算后的ECC值
  361.                           FSMC_Bank3->PCR3&=~(1<<6);                                                //禁止ECC校验
  362.                 }  
  363.                 i=nand_dev.page_mainsize+0X10+eccstart*4;                        //计算写入ECC的spare区地址
  364.                 NAND_Delay(NAND_TADL_DELAY);//等待tADL
  365.                 *(vu8*)(NAND_ADDRESS|NAND_CMD)=0X85;                                //随机写指令
  366.                 //发送地址
  367.                 *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)i;
  368.                 *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(i>>8);
  369.                 NAND_Delay(NAND_TADL_DELAY);//等待tADL
  370.                 pBuffer=(u8*)&nand_dev.ecc_hdbuf[eccstart];
  371.                 for(i=0;i<eccnum;i++)                                        //写入ECC
  372.                 {
  373.                         for(res=0;res<4;res++)                                 
  374.                         {
  375.                                 *(vu8*)NAND_ADDRESS=*(vu8*)pBuffer++;
  376.                         }
  377.                 }                 
  378.         }
  379.     *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_WRITE_TURE1;
  380.          delay_us(NAND_TPROG_DELAY);        //等待tPROG
  381.         if(NAND_WaitForReady()!=NSTA_READY)return NSTA_ERROR;//失败
  382.     return 0;//成功   
  383. }
  384. //在NAND一页中的指定地址开始,写入指定长度的恒定数字
  385. //PageNum:要写入的页地址,范围:0~(block_pagenum*block_totalnum-1)
  386. //ColNum:要写入的列开始地址(也就是页内地址),范围:0~(page_totalsize-1)
  387. //cval:要写入的指定常数
  388. //NumByteToWrite:要写入的字数(以4字节为单位)
  389. //返回值:0,成功
  390. //    其他,错误代码
  391. u8 NAND_WritePageConst(u32 PageNum,u16 ColNum,u32 cval,u16 NumByteToWrite)
  392. {
  393.     u16 i=0;  
  394.         *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_WRITE0;
  395.     //发送地址
  396.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)ColNum;
  397.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(ColNum>>8);
  398.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)PageNum;
  399.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(PageNum>>8);
  400.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(PageNum>>16);
  401.                 NAND_Delay(NAND_TADL_DELAY);//等待tADL
  402.         for(i=0;i<NumByteToWrite;i++)                //写入数据,每次写4字节
  403.         {
  404.                 *(vu32*)NAND_ADDRESS=cval;
  405.         }
  406.     *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_WRITE_TURE1;
  407.          delay_us(NAND_TPROG_DELAY);        //等待tPROG
  408.     if(NAND_WaitForReady()!=NSTA_READY)return NSTA_ERROR;//失败
  409.     return 0;//成功   
  410. }
  411. //将一页数据拷贝到另一页,不写入新数据
  412. //注意:源页和目的页要在同一个Plane内!
  413. //Source_PageNo:源页地址,范围:0~(block_pagenum*block_totalnum-1)
  414. //Dest_PageNo:目的页地址,范围:0~(block_pagenum*block_totalnum-1)  
  415. //返回值:0,成功
  416. //    其他,错误代码
  417. u8 NAND_CopyPageWithoutWrite(u32 Source_PageNum,u32 Dest_PageNum)
  418. {
  419.         u8 res=0;
  420.     u16 source_block=0,dest_block=0;  
  421.     //判断源页和目的页是否在同一个plane中
  422.     source_block=Source_PageNum/nand_dev.block_pagenum;
  423.     dest_block=Dest_PageNum/nand_dev.block_pagenum;
  424.     if((source_block%2)!=(dest_block%2))return NSTA_ERROR;        //不在同一个plane内
  425.     *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_MOVEDATA_CMD0;        //发送命令0X00
  426.     //发送源页地址
  427.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)0;
  428.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)0;
  429.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)Source_PageNum;
  430.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(Source_PageNum>>8);
  431.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(Source_PageNum>>16);
  432.     *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_MOVEDATA_CMD1;//发送命令0X35
  433.     //下面两行代码是等待R/B引脚变为低电平,其实主要起延时作用的,等待NAND操作R/B引脚。因为我们是通过
  434.     //将STM32的NWAIT引脚(NAND的R/B引脚)配置为普通IO,代码中通过读取NWAIT引脚的电平来判断NAND是否准备
  435.     //就绪的。这个也就是模拟的方法,所以在速度很快的时候有可能NAND还没来得及操作R/B引脚来表示NAND的忙
  436.     //闲状态,结果我们就读取了R/B引脚,这个时候肯定会出错的,事实上确实是会出错!大家也可以将下面两行
  437.     //代码换成延时函数,只不过这里我们为了效率所以没有用延时函数。
  438.         res=NAND_WaitRB(0);                        //等待RB=0
  439.         if(res)return NSTA_TIMEOUT;        //超时退出
  440.     //下面2行代码是真正判断NAND是否准备好的
  441.         res=NAND_WaitRB(1);                        //等待RB=1
  442.     if(res)return NSTA_TIMEOUT;        //超时退出
  443.     *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_MOVEDATA_CMD2;  //发送命令0X85
  444.     //发送目的页地址
  445.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)0;
  446.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)0;
  447.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)Dest_PageNum;
  448.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(Dest_PageNum>>8);
  449.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(Dest_PageNum>>16);
  450.     *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_MOVEDATA_CMD3;        //发送命令0X10
  451.         delay_us(NAND_TPROG_DELAY);        //等待tPROG
  452.     if(NAND_WaitForReady()!=NSTA_READY)return NSTA_ERROR;        //NAND未准备好
  453.     return 0;//成功   
  454. }

  455. //将一页数据拷贝到另一页,并且可以写入数据
  456. //注意:源页和目的页要在同一个Plane内!
  457. //Source_PageNo:源页地址,范围:0~(block_pagenum*block_totalnum-1)
  458. //Dest_PageNo:目的页地址,范围:0~(block_pagenum*block_totalnum-1)  
  459. //ColNo:页内列地址,范围:0~(page_totalsize-1)
  460. //pBuffer:要写入的数据
  461. //NumByteToWrite:要写入的数据个数
  462. //返回值:0,成功
  463. //    其他,错误代码
  464. u8 NAND_CopyPageWithWrite(u32 Source_PageNum,u32 Dest_PageNum,u16 ColNum,u8 *pBuffer,u16 NumByteToWrite)
  465. {
  466.         u8 res=0;
  467.     vu16 i=0;
  468.         u16 source_block=0,dest_block=0;  
  469.         u8 eccnum=0;                //需要计算的ECC个数,每NAND_ECC_SECTOR_SIZE字节计算一个ecc
  470.         u8 eccstart=0;                //第一个ECC值所属的地址范围
  471.     //判断源页和目的页是否在同一个plane中
  472.     source_block=Source_PageNum/nand_dev.block_pagenum;
  473.     dest_block=Dest_PageNum/nand_dev.block_pagenum;
  474.     if((source_block%2)!=(dest_block%2))return NSTA_ERROR;//不在同一个plane内
  475.         *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_MOVEDATA_CMD0;  //发送命令0X00
  476.     //发送源页地址
  477.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)0;
  478.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)0;
  479.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)Source_PageNum;
  480.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(Source_PageNum>>8);
  481.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(Source_PageNum>>16);
  482.     *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_MOVEDATA_CMD1;  //发送命令0X35

  483.     //下面两行代码是等待R/B引脚变为低电平,其实主要起延时作用的,等待NAND操作R/B引脚。因为我们是通过
  484.     //将STM32的NWAIT引脚(NAND的R/B引脚)配置为普通IO,代码中通过读取NWAIT引脚的电平来判断NAND是否准备
  485.     //就绪的。这个也就是模拟的方法,所以在速度很快的时候有可能NAND还没来得及操作R/B引脚来表示NAND的忙
  486.     //闲状态,结果我们就读取了R/B引脚,这个时候肯定会出错的,事实上确实是会出错!大家也可以将下面两行
  487.     //代码换成延时函数,只不过这里我们为了效率所以没有用延时函数。
  488.         res=NAND_WaitRB(0);                        //等待RB=0
  489.         if(res)return NSTA_TIMEOUT;        //超时退出
  490.     //下面2行代码是真正判断NAND是否准备好的
  491.         res=NAND_WaitRB(1);                        //等待RB=1
  492.     if(res)return NSTA_TIMEOUT;        //超时退出
  493.     *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_MOVEDATA_CMD2;  //发送命令0X85
  494.     //发送目的页地址
  495.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)ColNum;
  496.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(ColNum>>8);
  497.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)Dest_PageNum;
  498.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(Dest_PageNum>>8);
  499.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(Dest_PageNum>>16);
  500.     //发送页内列地址
  501.         NAND_Delay(NAND_TADL_DELAY);//等待tADL
  502.         if(NumByteToWrite%NAND_ECC_SECTOR_SIZE)//不是NAND_ECC_SECTOR_SIZE的整数倍,不进行ECC校验
  503.         {  
  504.                 for(i=0;i<NumByteToWrite;i++)                //写入数据
  505.                 {
  506.                         *(vu8*)NAND_ADDRESS=*(vu8*)pBuffer++;
  507.                 }
  508.         }else
  509.         {
  510.                 eccnum=NumByteToWrite/NAND_ECC_SECTOR_SIZE;                        //得到ecc计算次数
  511.                 eccstart=ColNum/NAND_ECC_SECTOR_SIZE;
  512.                  for(res=0;res<eccnum;res++)
  513.                 {
  514.                         FSMC_Bank3->PCR3|=1<<6;                                                //使能ECC校验
  515.                         for(i=0;i<NAND_ECC_SECTOR_SIZE;i++)                                //写入NAND_ECC_SECTOR_SIZE个数据
  516.                         {
  517.                                 *(vu8*)NAND_ADDRESS=*(vu8*)pBuffer++;
  518.                         }               
  519.                         while(!(FSMC_Bank3->SR3&(1<<6)));                                //等待FIFO空        
  520.                         nand_dev.ecc_hdbuf[res+eccstart]=FSMC_Bank3->ECCR3;        //读取硬件计算后的ECC值
  521.                          FSMC_Bank3->PCR3&=~(1<<6);                                                //禁止ECC校验
  522.                 }  
  523.                 i=nand_dev.page_mainsize+0X10+eccstart*4;                        //计算写入ECC的spare区地址
  524.                 NAND_Delay(NAND_TADL_DELAY);//等待tADL
  525.                 *(vu8*)(NAND_ADDRESS|NAND_CMD)=0X85;                                //随机写指令
  526.                 //发送地址
  527.                 *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)i;
  528.                 *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(i>>8);
  529.                 NAND_Delay(NAND_TADL_DELAY);//等待tADL
  530.                 pBuffer=(u8*)&nand_dev.ecc_hdbuf[eccstart];
  531.                 for(i=0;i<eccnum;i++)                                        //写入ECC
  532.                 {
  533.                         for(res=0;res<4;res++)                                 
  534.                         {
  535.                                 *(vu8*)NAND_ADDRESS=*(vu8*)pBuffer++;
  536.                         }
  537.                 }                 
  538.         }
  539.     *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_MOVEDATA_CMD3;        //发送命令0X10
  540.          delay_us(NAND_TPROG_DELAY);                                                        //等待tPROG
  541.     if(NAND_WaitForReady()!=NSTA_READY)return NSTA_ERROR;        //失败
  542.     return 0;        //成功   
  543. }
  544. //读取spare区中的数据
  545. //PageNum:要写入的页地址,范围:0~(block_pagenum*block_totalnum-1)
  546. //ColNum:要写入的spare区地址(spare区中哪个地址),范围:0~(page_sparesize-1)
  547. //pBuffer:接收数据缓冲区
  548. //NumByteToRead:要读取的字节数(不大于page_sparesize)
  549. //返回值:0,成功
  550. //    其他,错误代码
  551. u8 NAND_ReadSpare(u32 PageNum,u16 ColNum,u8 *pBuffer,u16 NumByteToRead)
  552. {
  553.     u8 temp=0;
  554.     u8 remainbyte=0;
  555.     remainbyte=nand_dev.page_sparesize-ColNum;
  556.     if(NumByteToRead>remainbyte) NumByteToRead=remainbyte;  //确保要写入的字节数不大于spare剩余的大小
  557.     temp=NAND_ReadPage(PageNum,ColNum+nand_dev.page_mainsize,pBuffer,NumByteToRead);//读取数据
  558.     return temp;
  559. }
  560. //向spare区中写数据
  561. //PageNum:要写入的页地址,范围:0~(block_pagenum*block_totalnum-1)
  562. //ColNum:要写入的spare区地址(spare区中哪个地址),范围:0~(page_sparesize-1)  
  563. //pBuffer:要写入的数据首地址
  564. //NumByteToWrite:要写入的字节数(不大于page_sparesize)
  565. //返回值:0,成功
  566. //    其他,失败
  567. u8 NAND_WriteSpare(u32 PageNum,u16 ColNum,u8 *pBuffer,u16 NumByteToWrite)
  568. {
  569.     u8 temp=0;
  570.     u8 remainbyte=0;
  571.     remainbyte=nand_dev.page_sparesize-ColNum;
  572.     if(NumByteToWrite>remainbyte) NumByteToWrite=remainbyte;  //确保要读取的字节数不大于spare剩余的大小
  573.     temp=NAND_WritePage(PageNum,ColNum+nand_dev.page_mainsize,pBuffer,NumByteToWrite);//读取
  574.     return temp;
  575. }
  576. //擦除一个块
  577. //BlockNum:要擦除的BLOCK编号,范围:0-(block_totalnum-1)
  578. //返回值:0,擦除成功
  579. //    其他,擦除失败
  580. u8 NAND_EraseBlock(u32 BlockNum)
  581. {
  582.         if(nand_dev.id==MT29F16G08ABABA)BlockNum<<=7;          //将块地址转换为页地址
  583.     else if(nand_dev.id==MT29F4G08ABADA)BlockNum<<=6;
  584.     *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_ERASE0;
  585.     //发送块地址
  586.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)BlockNum;
  587.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(BlockNum>>8);
  588.     *(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(BlockNum>>16);
  589.     *(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_ERASE1;
  590.         delay_ms(NAND_TBERS_DELAY);                //等待擦除成功
  591.         if(NAND_WaitForReady()!=NSTA_READY)return NSTA_ERROR;//失败
  592.     return 0;        //成功   
  593. }
  594. //全片擦除NAND FLASH
  595. void NAND_EraseChip(void)
  596. {
  597.     u8 status;
  598.     u16 i=0;
  599.     for(i=0;i<nand_dev.block_totalnum;i++) //循环擦除所有的块
  600.     {
  601.         status=NAND_EraseBlock(i);
  602.         if(status)printf("Erase %d block fail!!,错误码为%d\r\n",i,status);//擦除失败
  603.     }
  604. }

  605. //获取ECC的奇数位/偶数位
  606. //oe:0,偶数位
  607. //   1,奇数位
  608. //eccval:输入的ecc值
  609. //返回值:计算后的ecc值(最多16位)
  610. u16 NAND_ECC_Get_OE(u8 oe,u32 eccval)
  611. {
  612.         u8 i;
  613.         u16 ecctemp=0;
  614.         for(i=0;i<24;i++)
  615.         {
  616.                 if((i%2)==oe)
  617.                 {
  618.                         if((eccval>>i)&0X01)ecctemp+=1<<(i>>1);
  619.                 }
  620.         }
  621.         return ecctemp;
  622. }
  623. //ECC校正函数
  624. //eccrd:读取出来,原来保存的ECC值
  625. //ecccl:读取数据时,硬件计算的ECC只
  626. //返回值:0,错误已修正
  627. //    其他,ECC错误(有大于2个bit的错误,无法恢复)
  628. u8 NAND_ECC_Correction(u8* data_buf,u32 eccrd,u32 ecccl)
  629. {
  630.         u16 eccrdo,eccrde,eccclo,ecccle;
  631.         u16 eccchk=0;
  632.         u16 errorpos=0;
  633.         u32 bytepos=0;  
  634.         eccrdo=NAND_ECC_Get_OE(1,eccrd);        //获取eccrd的奇数位
  635.         eccrde=NAND_ECC_Get_OE(0,eccrd);        //获取eccrd的偶数位
  636.         eccclo=NAND_ECC_Get_OE(1,ecccl);        //获取ecccl的奇数位
  637.         ecccle=NAND_ECC_Get_OE(0,ecccl);         //获取ecccl的偶数位
  638.         eccchk=eccrdo^eccrde^eccclo^ecccle;
  639.         if(eccchk==0XFFF)        //全1,说明只有1bit ECC错误
  640.         {
  641.                 errorpos=eccrdo^eccclo;
  642.                 printf("errorpos:%d\r\n",errorpos);
  643.                 bytepos=errorpos/8;
  644.                 data_buf[bytepos]^=1<<(errorpos%8);
  645.         }else                                //不是全1,说明至少有2bit ECC错误,无法修复
  646.         {
  647.                 printf("2bit ecc error or more\r\n");
  648.                 return 1;
  649.         }
  650.         return 0;
  651. }
复制代码
  1. int main(void)
  2. {        
  3.         u8 *buf;
  4.         u8 *backbuf;
  5.     u8 res;        
  6.         u16 i;

  7.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
  8.         delay_init(168);  //初始化延时函数
  9.         uart_init(115200);                //初始化串口波特率为115200
  10.         led_init();                                        //初始化LED
  11.          FSMC_SRAM_Init();                        //初始化外部SRAM  
  12.         
  13.         my_mem_init(SRAMIN);                //初始化内部内存池
  14.         my_mem_init(SRAMEX);                //初始化外部内存池
  15.         my_mem_init(SRAMCCM);                //初始化CCM内存池
  16.         
  17.          while(FTL_Init())                            //检测NAND FLASH,并初始化FTL
  18.         {
  19.                 printf("NAND Error!  Please Check\r\n");         
  20.                 delay_ms(500);        
  21.         }        
  22.         backbuf=mymalloc(SRAMIN,NAND_ECC_SECTOR_SIZE);        //申请一个扇区的缓存
  23.         buf=mymalloc(SRAMIN,NAND_ECC_SECTOR_SIZE);                //申请一个扇区的缓存
  24.         sprintf((char*)buf,"NAND Size:%dMB",(nand_dev.block_totalnum/1024)*(nand_dev.page_mainsize/1024)*nand_dev.block_pagenum);
  25.         printf("%s\r\n",buf);        //显示NAND容量  
  26.         
  27.         
  28.         for(i=0;i<NAND_ECC_SECTOR_SIZE;i++)
  29.         {
  30.                 buf<i>=i;
  31.         }
  32.         printf("Writing data to sector..\r\n");
  33.         res=FTL_WriteSectors(buf,2,NAND_ECC_SECTOR_SIZE,1);//写入扇区
  34.         
  35.         if(res==0)
  36.                 printf("Write data successed\r\n");//写入成功
  37.         else
  38.         {
  39.                 while(1)
  40.                 {
  41.                         printf("Write data failed\r\n");//写入失败
  42.                         delay_ms(500);        
  43.                 }
  44.         }
  45.         
  46.         
  47.         FTL_ReadSectors(backbuf,2,NAND_ECC_SECTOR_SIZE,1);//预先读取扇区0到备份区域,防止乱写导致文件系统损坏.
  48.         
  49.         res=FTL_ReadSectors(buf,2,NAND_ECC_SECTOR_SIZE,1);//读取扇区
  50.         
  51.         if(res==0)//读取成功
  52.         {
  53.                 printf("Sector 2 data is:\r\n");
  54.                 for(i=0;i<NAND_ECC_SECTOR_SIZE;i++)
  55.                 {
  56.                         printf("%x ",buf<i>);//输出数据
  57.                 }
  58.                 printf("\r\ndata end.\r\n");
  59.                 printf("USART1 Send Data Over!  \r\n");
  60.         }
  61.         
  62.         
  63.         
  64.          while(1)
  65.         {        
  66.                 turn_prog_led();
  67.                 delay_ms(10);   
  68.         }           
  69. }


  70. </i></i>
复制代码


收藏 评论0 发布时间:2022-4-21 21:00

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版