STM32+S34ML08G201TFI000组合Nand Flash驱动程序设计

这篇博客介绍了如何针对STM32微控制器和S34ML08G201TFI000 Nand Flash芯片设计驱动程序,特别考虑了双Nand Flash配置。内容涵盖了驱动程序的结构、地址形成、ECC处理和读写操作,适用于嵌入式系统开发。
摘要由CSDN通过智能技术生成

       STM32固件抽象库中的Nand Flash函数的地址形成可能采用了某种型号的Nand Flash地址要求,与大多数的Nand Flash芯片的地址形成不一样。另外,设计的应用系统有两块S34ML08G201TFI000,一般开发板只有一块Nand Flash,为此对Nand Flash驱动程序进行了重新设计,下面的代码供感兴趣读者参考。

以下为驱动程序的说明文件

#ifndef __MYNAND__
#define __MYNAND__
#include "mySys.h"
#include "main.h"
/**********************************************************************************     
本程序只供学习使用,未经作者许可,不得用于其它任何用途
太原数据源板用ST32F429核心板的NAND驱动代码       
参考正点原子开发板修改而来
创建日期:2023/05/15
版本:V1.0
版权所有,盗版必究。
Copyright(C) 
All rights reserved                  
********************************************************************************/
/********************************************************************************
升级说明
V1.1 20160520
1,新增硬件ECC支持(仅在以NAND_ECC_SECTOR_SIZE大小为单位进行读写时处理)
2,新增NAND_Delay函数,用于等待tADL/tWHR
3,新增NAND_WritePageConst函数,用于搜寻坏块
4.新增了NAND_HandleTypeDef句柄指针
V1.2 20160525
1,去掉NAND_SEC_SIZE宏定义,由NAND_ECC_SECTOR_SIZE替代
2,去掉nand_dev结构体里面的secbuf指针,用不到
**********************************************************************************/     
 
#define NAND_MAX_PAGE_SIZE            4096        //定义NAND FLASH的最大的PAGE大小(不包括SPARE区),默认4096字节
#define NAND_ECC_SECTOR_SIZE        512            //执行ECC计算的单元大小,默认512字节

//NAND Flash读取延时时间
#define NAND_READ_TIMEOUT         0x01000000U
#define NAND_READ_ECC_TIMEOUT            0x01000000U
//NAND属性结构体
//typedef struct
//{
//  uint32_t        PageSize;              /*!< NAND memory page (without spare area) size measured in bytes 
//                                              for 8 bits adressing or words for 16 bits addressing             */

//  uint32_t        SpareAreaSize;         /*!< NAND memory spare area size measured in bytes 
//                                              for 8 bits adressing or words for 16 bits addressing             */
//  
//  uint32_t        BlockSize;             /*!< NAND memory block size measured in number of pages               */

//  uint32_t        BlockNbr;              /*!< NAND memory number of total blocks                               */
//     
//  uint32_t        PlaneNbr;              /*!< NAND memory number of planes                                     */

//  uint32_t        PlaneSize;             /*!< NAND memory plane size measured in number of blocks               */

//  FunctionalState ExtraCommandEnable;    /*!< NAND extra command needed for Page reading mode. This 
//                                              parameter is mandatory for some NAND parts after the read 
//                                              command (NAND_CMD_AREA_TRUE1) and before DATA reading sequence. 
//                                              Example: Toshiba THTH58BYG3S0HBAI6.
//                                              This parameter could be ENABLE or DISABLE
//                                              Please check the Read Mode sequnece in the NAND device datasheet */
//}NAND_DeviceConfigTypeDef; 
typedef struct __NAND_ATTRIBUTE__

    NAND_HandleTypeDef *ptrNandHandle;    //太原设备增加的成员
    //以下成员与HAL库函数定义的NAND_DeviceConfigTypeDef数据类型相似
    u16 page_totalsize;         //每页总大小,main区和spare区总和
    u16 page_mainsize;          //每页的main区大小,不包含备用区
    u16 page_sparesize;         //每页的spare区大小
    u8  block_pagenum;          //每个块包含的页数量
    u8     errCode;                //太原设备增加的成员变量
    u16 plane_blocknum;         //每个plane包含的块数量
    u16 block_totalnum;         //一个芯片所包含的块数量
    u16 good_blocknum;          //好块数量    
    u16 valid_blocknum;         //有效块数量(供文件系统使用的好块数量)
    u32 id;                         //NAND FLASH ID
    u16 *lut;                             //LUT表,用作逻辑块-物理块转换,
                                                        //数据类型由芯片的块的地址大小决定,存放物理块地址(物理块号包含位号),
                                                        //数组索引就是逻辑块号,逻辑块包含的字节数与物理块包含的字节数相同,即
                                                        //逻辑块大小与物理块大小相同
                                                        //参见芯片数据手册P12/76、P6/16和P16/132 
    u32 ecc_hard;                            //硬件计算出来的ECC值
    u32 ecc_hdbuf[NAND_MAX_PAGE_SIZE/NAND_ECC_SECTOR_SIZE];//ECC硬件计算值缓冲区      
    u32 ecc_rdbuf[NAND_MAX_PAGE_SIZE/NAND_ECC_SECTOR_SIZE];//ECC读取值的缓冲区
  u32 ecc_rdFlagBuf[NAND_MAX_PAGE_SIZE/NAND_ECC_SECTOR_SIZE];//读取ECC标识
  u32 ecc_hdFlagBuf[NAND_MAX_PAGE_SIZE/NAND_ECC_SECTOR_SIZE];//读取ECC标识  
    
    u32 DevicePageAddr;                //页地址,即由页码、面码和块地址构成
    u16 DeviceColAddr;        //列地址,
    u16 ByteNum;              //要读取的字节数
    u8 *ptrBuf;               //接受缓冲区
}Nand_AttributeTypeDef,*ptrNand_AttributeTypeDef;      

typedef struct __NAND_COPY__
{
    ptrNand_AttributeTypeDef ptrAttribute;    //指定芯片参数
    u32 Source_PageNum;                     //源页
    u32 Dest_PageNum;                       //目标页
    u16 ColNum;                             //页内偏移地址,用于修改
    u16 ByteNum;                            //字节数,用于修改
    u8 *ptrBuf;                               //源数据,用于修改
}NAND_CopyTypeDef,*ptrNAND_CopyTypeDef;
extern ptrNand_AttributeTypeDef ptrNand_Dev2;                //nand重要参数结构体
extern ptrNand_AttributeTypeDef ptrNand_Dev3;

#define NAND_RB                   PDin(6)    //NAND Flash的闲/忙引脚 

#define NAND1_ADDRESS            0X70000000    //bank2上的nand flash芯片的首地址,首地址为:0X7000 0000,片选信号为NCE2
#define NAND2_ADDRESS        ` 0X80000000  //bank3上的nand_flash芯片的首地址,首地址为:0x8000 0000,片选信号为NCE3

#define NAND_DATA                    0                        //芯片数据首地址
#define NAND_CMD                    1<<16                //芯片命令首地址
#define NAND_ADDR                    1<<17                //芯片地址首地址


//NAND FLASH命令
#define NAND_READID             0X90        //读ID指令
#define NAND_FEATURE                    0XEF        //设置特性指令
#define NAND_RESET              0XFF        //复位NAND
#define NAND_READSTA            0X70            //读状态
/*************************************************
读页起始命令和读页结束命令之间是发送芯片地址命令
**************************************************/
#define NAND_AREA_A             0X00      //读页起始命令
#define NAND_AREA_TRUE1         0X30      //读页结束命令

#define NAND_WRITE0                 0X80      //缓冲编程起始或继续开始命令
#define NAND_WRITE_TURE1        0X10      //缓冲编程结束命令

#define NAND_ERASE0                 0X60      //块擦除起始命令
#define NAND_ERASE1             0XD0      //块擦除结束命令

#define NAND_MOVEDATA_CMD0      0X00      //拷贝回读起始命令
#define NAND_MOVEDATA_CMD1      0X35      //拷贝回读结束命令
#define NAND_MOVEDATA_CMD2      0X85      //拷贝编程起始命令
#define NAND_MOVEDATA_CMD3      0X10      //拷贝编程结束命令


#define NAND_CMD_RANDOM_READ                    0X05
#define NAND_CMD_RANDOM_READ_TURE1        0XE0

#define NAND_CMD_MOVEDATA_0                        0X00
#define NAND_CMD_MOVEDATA_1                        0X35
#define NAND_CMD_MOVEDATA_2                      0X85
#define NAND_CMD_MOVEDATA_3                      0X10

#define NAND_CMD_RANDOM_WRITE                    0X85      //

#define NAND_CMD_FEATURE                            0XEF        //设置特性指令
/**********************************************************
本驱动程序函数使用的NAND FLASH状态宏定义
***********************************************************/
#define NSTA_READY                  0X40        //nand已经准备好
#define NSTA_SUCCESS                    0X00
#define NSTA_ERROR                        0X01        //nand错误
#define NSTA_TIMEOUT            0X02        //超时
#define NSTA_ECC1BITERR       0X03        //ECC 1bit错误
#define NSTA_ECC2BITERR       0X04        //ECC 2bit以上错误 
#define NSTA_BUSY                            0X05    //设备正在忙
#define NSTA_ERROR2                        0X06
#define NSTA_ERROR3                        0X03

/************************************************
NAND FLASH型号和对应的ID号
不同厂商同一型号芯片的ID号除生产厂商编号不同外,
其它都相同,因此不考虑生产厂家编号,只使用后面
4个字节,这4个字节的具体含义参见芯片数据手册,MT
厂家P36~P37,S厂家P26(1G~4G)和P7(8G)
*************************************************/
#define MT29F4G08ABADA                    0XDC909556    //MT29F4G08ABADA
#define S34ML08G2                                0XD3D1955A    //S34ML08G2
#define MT29F16G08ABABA                    0X48002689    //MT29F16G08ABABA

#define HAL_MT29F4G08ABADA            0X2CDC9095    //MT29F4G08ABADA
#define HAL_S34ML08G2                        0X01D3D195    //S34ML08G2
#define HAL_MT29F16G08ABABA            0X2C480026    //MT29F16G08ABABA

//使用HAL库函数得到的型号与ID的对应关系
//#define MT29F4G08ABADA            0X9590DC2C    //MT29F4G08ABADA
//#define MT29F16G08ABABA            0X2600482C    //MT29F16G08ABABA 
/************************************
NAND延时用函数
*************************************/
void NAND_Delay(vu32 i);
/************************************
ECC分离和修正函数,所谓分离就是把
FMC计算出的编码分成偶部和奇部等两
部分,然后由此可以判断是否发生错误
以及能否修改错误和恢复可修改的错误
数据
*************************************/
u16 NAND_ECC_Get_OE(u8 oe,u32 eccval);
u8 NAND_ECC_Correction(u8* data_buf,u32 eccrd,u32 ecccl);
/**********************************
初始化本模块全局变量函数
***********************************/
HAL_StatusTypeDef InitNandData(ptrNand_AttributeTypeDef ptr,NAND_HandleTypeDef *hnand);
HAL_StatusTypeDef InitAllNandData(void);
/*********************************************************
基于两个NAND芯片的专用函数定义
**********************************************************/
HAL_StatusTypeDef NAND_ReadID(ptrNand_AttributeTypeDef);
HAL_StatusTypeDef NAND_Init(ptrNand_AttributeTypeDef ptrNandAttribute,NAND_HandleTypeDef *hnand);
u8 NAND_WaitForReady(NAND_HandleTypeDef *hnand);
u16 NAND_EraseChip(NAND_HandleTypeDef *hnand);
u8 NAND_EraseBlock(NAND_HandleTypeDef *hnand,u32 BlockNum);
u8 NAND_ReadPage(ptrNand_AttributeTypeDef ptr);
HAL_StatusTypeDef NAND_ReadPageComp(ptrNand_AttributeTypeDef ptr,u32 CmpVal,u16 *NumByteEqual);
u8 NAND_ReadSpare(ptrNand_AttributeTypeDef ptr);
u8 NAND_WritePage(ptrNand_AttributeTypeDef ptr);
u8 NAND_WritePageConst(ptrNand_AttributeTypeDef ptr,u32 cval);
u8 NAND_WriteSpare(ptrNand_AttributeTypeDef ptr);
u8 NAND_CopyPageWithoutWrite(ptrNAND_CopyTypeDef ptr);
u8 NAND_CopyPageWithWrite(ptrNAND_CopyTypeDef ptr);
u8 NAND_CopyPageWithChangeByReadWrite(ptrNAND_CopyTypeDef ptr);
u8 NAND_CopyPageWithoutChangeByReadWrite(ptrNAND_CopyTypeDef ptr);
u8 NAND_ModeSet(ptrNand_AttributeTypeDef ptr,u8 mode);
u8 NAND_ReadPageWithOutECC(ptrNAND_CopyTypeDef ptr);
u8 NAND_WritePageWithOutECC(ptrNAND_CopyTypeDef ptr);
u8 NAND_WritePageTotalWithECC(ptrNAND_CopyTypeDef pt);
u8 NAND_GetECCByRead(ptrNAND_CopyTypeDef ptr);
u8 NAND_WriteECCOnly(ptrNAND_CopyTypeDef ptr);
#endif

//The following text is executting part

#include "myNand.h"
#include "main.h"
#include "fmc.h"
#include "malloc.h"
#include "part.h"
#include "myusart1.h"
//#define __no_init __attribute__((zero_init))
//__no_init 
ptrNand_AttributeTypeDef ptrNand_Dev2=NULL;                //nand重要参数结构体
ptrNand_AttributeTypeDef ptrNand_Dev3=NULL;

/************************************
NAND延时用函数
*************************************/
void NAND_Delay(vu32 i)
{
    while(i>0)i--;
}
/************************************************
初始化本模块应用的全局变量nand_dev2和nand_dev3
nand_dev2芯片联接在CPU的bank2,nand_dev3联接在
CPU的bank3上,参见CPU手册P1607。初始化后变量的
所有成员全部复位,即都设置为0x00。本函数已经校正!
*************************************************/
HAL_StatusTypeDef InitAllNandData(void)
{
  if(ptrNand_Dev2==NULL)
    ptrNand_Dev2=mymallocEx(sizeof(Nand_AttributeTypeDef));
  if(ptrNand_Dev2==NULL)
    return HAL_ERROR;
  mymemset(ptrNand_Dev2,0,sizeof(Nand_AttributeTypeDef));
    if(InitNandData(ptrNand_Dev2,&hnand1)!=HAL_OK)
    return HAL_ERROR;
  if(ptrNand_Dev3==NULL)
    ptrNand_Dev3=mymallocEx(sizeof(Nand_AttributeTypeDef));
  if(ptrNand_Dev3==NULL)
    return HAL_ERROR;
  mymemset(ptrNand_Dev3,0,sizeof(Nand_AttributeTypeDef));
    if(InitNandData(ptrNand_Dev3,&hnand2)!=HAL_OK)
    return HAL_ERROR;
  return HAL_OK;
}
/************************************************
入口参数:
ptr:Nand_attributeTypeDef类型指针;
hnand:NAND_HandleTypeDef类型指针
出口参数:
ptr:所指类型变量成员发生改变
返回参数:

*************************************************/
HAL_StatusTypeDef InitNandData(ptrNand_AttributeTypeDef ptr,NAND_HandleTypeDef *hnand)
{
    if((hnand==NULL)||(ptr==NULL))
    return HAL_ERROR;    
    ptr->DevicePageAddr=0x00000000;    
    ptr->DeviceColAddr=0x0000u;
    ptr->ByteNum=0x0000;
    ptr->ptrBuf=NULL;
    ptr->ptrNandHandle=hnand;
    while(NAND_ReadID(ptr)!=HAL_OK)
    {
        return HAL_ERROR;
    }        
    NAND_ModeSet(ptr,4);
  return HAL_OK;
}
/*********************************************
等待设备准备好,假如在延时一段时间期间设备还
没有准备好就认为设备超时,没有准备好。
入口参数:
    Nand Flash设备句柄指针hnand;
出口参数:无
返回参数:NSTA_READY=设备准备好,否则设备未准备
    好,即设备忙或错。
**********************************************/
u8 NAND_WaitForReady(NAND_HandleTypeDef *hnand)
{
    u8 ret;    
  uint32_t tickstart=HAL_GetTick();

    ret=HAL_NAND_Read_Status(hnand);
    while(ret!=NAND_READY)
    { 
        if(ret==NAND_ERROR)
            return NSTA_ERROR;
        else if((HAL_GetTick()-tickstart)>NAND_READ_TIMEOUT)
            return NSTA_TIMEOUT;
        else
            ret=HAL_NAND_Read_Status(hnand);
    }
    return NSTA_READY;
}
/***********************************************
从给定的校验码eccval中分离出奇数位或偶数位
上数字,以便判断是否发生存储或读取的错误。
入口参数:
oe:0=提取校验码的偶数位上的数字,1=提取校验码的奇数
      位上的数字
eccval:校验码,本CPU使用汉明码,为24位,用32位整
                型数变量存储,对应于512字节数据的汉明码。
出口参数:无
返回参数:给定校验码上偶数位或奇数位上数字构成的16
                 位码
************************************************/
u16 NAND_ECC_Get_OE(u8 oe,u32 eccval)
{
    u8 i;
    u16 ecctemp=0;
    for(i=0;i<24;i++)
    {
        if((i%2)==oe)
        {
            if((eccval>>i)&0X01)ecctemp+=1<<(i>>1); 
        }
    }
    return ecctemp;

/***********************************************************
根据FMC计算的前后ECC修正错误参数,注意只有前后ECC值不同时
才调用该函数!
入口参数:
eccrd:FMC第一次计算的ECC码,为保存的ECC值
ecccl:FMC最新计算的ECC码
data:FMC最新计算ECC码所用数据,为固定大小的数据,用宏
            定义变量标识
出口参数:data
返回参数:0=错误的data数据已修正,1=错误的data数据无法修正
已经检查过,但是有待调试通过
************************************************************/
u8 NAND_ECC_Correction(u8* data_buf,u32 eccrd,u32 ecccl)
{
    u16 eccrdo,eccrde,eccclo,ecccle;
    u16 eccchk=0;
    u16 errorpos=0; 
    u32 bytepos=0;  
    eccrdo=NAND_ECC_Get_OE(1,eccrd);    //获取eccrd的奇数位
    eccrde=NAND_ECC_Get_OE(0,eccrd);    //获取eccrd的偶数位
    eccclo=NAND_ECC_Get_OE(1,ecccl);    //获取ecccl的奇数位
    ecccle=NAND_ECC_Get_OE(0,ecccl);     //获取ecccl的偶数位
    eccchk=eccrdo^eccrde^eccclo^ecccle;
    if(eccchk==0XFFF)    //全1,说明只有1bit ECC错误
    {
        errorpos=eccrdo^eccclo; //获取错误位的位置
        bytepos=errorpos/8;     //获取错误位所在字节
        data_buf[bytepos]^=1<<(errorpos%8);  //修改错误位上的数字
    }
    else if(eccchk!=0)                 //不是全1,说明至少有2bit ECC错误,无法修复
    {
        return NSTA_ERROR;  //原来返回1       
    } 
    return NSTA_SUCCESS;  //原来返回0
}
/*******************************************************************
读取NAND Flash芯片的ID标识,共读取8个字节,只有前5个字节有意思。
并且根据读取的NAND FLASH芯片的ID初始化有关变量成员。
入口参数:
        ptr:芯片属性参数型Nand_AttributeTypeDef指针,参见myNand.h头文
                 件定义,使用到的变量成员有:ptr->ptrNandHandle
出口参数:
        ptr:根据读取的ID值初始化指针ptr所指Nand_AttributeTypeDef类型变量
                 的某些成员。主要有如下一些成员:
                 ptr->page_totalsize(一页存储器所含有的字节数,包含主字节数和
                 备用字节数);
                 ptr->page_mainsize(一页的主字节数)
                 ptr->page_sparesize(一页的备用字节数)
                 ptr->block_pagenum(一块存储单元所包含的页数)
                 ptr->plane_blocknum(一面存储单元所包含的块数)
                 ptr->block_toltalnum(存储单元总的块数)

                 ptr->ptrNandHandle->Config.PageSize(一页存储单元所包含的主字节数)
                 ptr->ptrNandHandle->Config.SpareAreaSize(一页存储单元包含的备用字节数)
                 ptr->ptrNandHandle->Config.BlockSize(一块存储单元所包含的页数)
                 ptr->ptrNandHandle->BlockNbr(存储单元包含的总块数)
                 ptr->ptrNandHandle->PlaneNbr(存储单元包含的面数)
                 ptr->ptrNandHandle->PlaneSize(一面存储单元所包含的块数)
返回参数:
        HAL_OK=函数执行成功,其它=函数执行失败。
******************

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值