1.STM32CUBEMX配置
NAND FLASH配置(这里的RB脚我是使用的模拟信号)
参数配置
时钟配置
2.驱动模块
/*
* dNAND.c
*
* Created on: 2023/12/5
* Author: WZX
*/
#include "dNAND.h"
#include <stddef.h>
static NAND_TypeDef_t *nand;
static uint8_t dNAND_WaitForReady(void);
static uint8_t dNAND_WaitRB(volatile uint8_t rb);
static uint8_t dNAND_ECC_Correction(uint8_t *data_buf, uint32_t eccrd, uint32_t ecccl);
/*********************************************************************
* @fn dNAND_Init
*
* @brief nand初始化.
*
* @param nand_t:nand参数
*
* @return none
*/
void dNAND_Init(NAND_TypeDef_t *nand_t)
{
if(nand_t == NULL)
{
return;
}
nand = nand_t;
nand->MPU_Init();
nand->Reset();
nand->Delay(100);
nand->Nand_Dev.id = nand->Read_ID();
dNAND_ModeSet(4);
switch(nand->Nand_Dev.id)
{
case MT29F4G08ABADA:
break;
case MT29F16G08ABABA:
nand->Nand_Dev.page_totalsize=2112;
nand->Nand_Dev.page_mainsize=2048;
nand->Nand_Dev.page_sparesize=64;
nand->Nand_Dev.block_pagenum=64;
nand->Nand_Dev.plane_blocknum=1024;
nand->Nand_Dev.block_totalnum=2048;
break;
case W29N01GVSIAA:
nand->Nand_Dev.page_totalsize=2112;
nand->Nand_Dev.page_mainsize=2048;
nand->Nand_Dev.page_sparesize=64;
nand->Nand_Dev.block_pagenum=64;
nand->Nand_Dev.plane_blocknum=1024;
nand->Nand_Dev.block_totalnum=2048;
break;
case W29N01HVSINA:
nand->Nand_Dev.page_totalsize=2112;
nand->Nand_Dev.page_mainsize=2048;
nand->Nand_Dev.page_sparesize=64;
nand->Nand_Dev.block_pagenum=64;
nand->Nand_Dev.plane_blocknum=1024;
nand->Nand_Dev.block_totalnum=1024;
break;
default:
break;
}
}
/*********************************************************************
* @fn dNAND_ModeSet
*
* @brief nand模式选择.
*
* @param mode:模式
*
* @return none
*/
void dNAND_ModeSet(uint8_t mode)
{
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = NAND_FEATURE;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = 0X01;
*(volatile uint8_t *)NAND_ADDRESS = mode;
*(volatile uint8_t *)NAND_ADDRESS = 0;
*(volatile uint8_t *)NAND_ADDRESS = 0;
*(volatile uint8_t *)NAND_ADDRESS = 0;
dNAND_WaitForReady();
}
/*********************************************************************
* @fn dNAND_ReadSpare
*
* @brief nand读取备用区.
*
* @param PageNum:页地址,范围0-block_pagenum*block_totalnum-1
*
* @param ColNum:区域地址,范围0-page_sparesize-1
*
* @param pBuffer:数据缓冲区
*
* @param NumByteToRead:读取的字节数
*
* @return none
*/
void dNAND_ReadSpare(uint32_t PageNum, uint16_t ColNum, uint8_t *pBuffer, uint16_t NumByteToRead)
{
uint8_t remainbyte = nand->Nand_Dev.page_sparesize - ColNum;
if(NumByteToRead > remainbyte)
{
NumByteToRead = remainbyte;
}
dNAND_ReadPage(PageNum, ColNum + nand->Nand_Dev.page_mainsize, pBuffer, NumByteToRead);
}
/*********************************************************************
* @fn dNAND_WriteSpare
*
* @brief nand写入备用区.
*
* @param PageNum:页地址,范围0-block_pagenum*block_totalnum-1
*
* @param ColNum:区域地址,范围0-page_sparesize-1
*
* @param pBuffer:数据缓冲区
*
* @param NumByteToRead:写入的字节数
*
* @return none
*/
void dNAND_WriteSpare(uint32_t PageNum, uint16_t ColNum, uint8_t *pBuffer, uint16_t NumByteToWrite)
{
uint8_t remainbyte = nand->Nand_Dev.page_sparesize - ColNum;;
if(NumByteToWrite > remainbyte)
{
NumByteToWrite = remainbyte;
}
dNAND_WritePage(PageNum, ColNum + nand->Nand_Dev.page_mainsize, pBuffer, NumByteToWrite);
}
/*********************************************************************
* @fn dNAND_EraseBlock
*
* @brief nand块擦除.
*
* @param BlockNum:块编号,范围0-block_totalnum-1
*
* @return none
*/
void dNAND_EraseBlock(uint32_t BlockNum)
{
if(nand->Nand_Dev.id == MT29F16G08ABABA) {
BlockNum <<= 7;
} else if(nand->Nand_Dev.id == MT29F4G08ABADA) {
BlockNum <<= 6;
} else if(nand->Nand_Dev.id == W29N01HVSINA) {
BlockNum <<= 6;
}
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = NAND_ERASE0;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)BlockNum;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(BlockNum>>8);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(BlockNum>>16);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = NAND_ERASE1;
dNAND_WaitForReady();
}
/*********************************************************************
* @fn dNAND_EraseChip
*
* @brief nand芯片擦除.
*
* @param none
*
* @return none
*/
void dNAND_EraseChip(void)
{
for(uint16_t i = 0; i<nand->Nand_Dev.block_totalnum; i++)
{
dNAND_EraseBlock(i);
}
}
/*********************************************************************
* @fn dNAND_ReadPage
*
* @brief nand读取页数据.
*
* @param PageNum:页地址,范围0-block_pagenum*block_totalnum-1
*
* @param ColNum:区域地址,范围0-page_sparesize-1
*
* @param pBuffer:数据缓冲区
*
* @param NumByteToRead:读取的字节数
*
* @return none
*/
void dNAND_ReadPage(uint32_t PageNum, uint16_t ColNum, uint8_t *pBuffer, uint16_t NumByteToRead)
{
volatile uint16_t i = 0;
uint8_t res = 0;
uint8_t eccnum = 0;
uint8_t eccstart = 0;
uint8_t *p;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = NAND_AREA_A;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)ColNum;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(ColNum>>8);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)PageNum;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(PageNum>>8);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(PageNum>>16);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = NAND_AREA_TRUE1;
res = dNAND_WaitRB(0);
if(res) {
return;
}
res = dNAND_WaitRB(1);
if(res) {
return;
}
if(NumByteToRead % NAND_ECC_SECTOR_SIZE) {
for(i = 0; i < NumByteToRead; i++) {
*(volatile uint8_t *)pBuffer++ = *(volatile uint8_t *)NAND_ADDRESS;
}
} else {
eccnum = NumByteToRead / NAND_ECC_SECTOR_SIZE;
eccstart = ColNum / NAND_ECC_SECTOR_SIZE;
p = pBuffer;
for(res = 0; res < eccnum; res++) {
nand->ECC_Enable();
for(i = 0; i < NAND_ECC_SECTOR_SIZE; i++) {
*(volatile uint8_t *)pBuffer++ = *(volatile uint8_t *)NAND_ADDRESS;
}
nand->ECC_Fifo_Empty();
nand->Nand_Dev.ecc_hdbuf[res + eccstart] = nand->ECC_Get();
nand->ECC_Disable();
}
i = nand->Nand_Dev.page_mainsize + 0X10 + eccstart*4;
nand->Delay(30);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = 0X05;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)i;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(i>>8);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = 0XE0;
nand->Delay(30);
pBuffer = (uint8_t*)&nand->Nand_Dev.ecc_rdbuf[eccstart];
for(i = 0; i < 4*eccnum; i++) {
*(volatile uint8_t *)pBuffer++ = *(volatile uint8_t *)NAND_ADDRESS;
}
for(i = 0; i < eccnum; i++) {
if(nand->Nand_Dev.ecc_rdbuf[i + eccstart] != nand->Nand_Dev.ecc_hdbuf[i + eccstart]) {
dNAND_ECC_Correction(p + NAND_ECC_SECTOR_SIZE*i, \
nand->Nand_Dev.ecc_rdbuf[i + eccstart], \
nand->Nand_Dev.ecc_hdbuf[i + eccstart]);
}
}
}
dNAND_WaitForReady();
}
/*********************************************************************
* @fn dNAND_ReadPageComp
*
* @brief nand读取对比页数据,main区和spare区都可以用.
*
* @param PageNum:页地址,范围0-block_pagenum*block_totalnum-1
*
* @param ColNum:区域地址,范围0-page_sparesize-1
*
* @param CmpVal:对比的值,32bit位单位对比
*
* @param NumByteToRead:读取的字节数
*
* @param NumByteEqual:从初始位置和CmpVal相同的值个数
*
* @return none
*/
void dNAND_ReadPageComp(uint32_t PageNum, uint16_t ColNum, uint32_t CmpVal, uint16_t NumByteToRead, uint16_t *NumByteEqual)
{
uint16_t i = 0;
uint8_t res = 0;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = NAND_AREA_A;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)ColNum;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(ColNum>>8);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)PageNum;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(PageNum>>8);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(PageNum>>16);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = NAND_AREA_TRUE1;
res = dNAND_WaitRB(0);
if(res) {
return;
}
res = dNAND_WaitRB(1);
if(res) {
return;
}
for(i = 0; i < NumByteToRead; i++) {
if(*(volatile uint32_t *)NAND_ADDRESS != CmpVal) {
break;
}
}
*NumByteEqual = i;
dNAND_WaitForReady();
}
/*********************************************************************
* @fn dNAND_WritePage
*
* @brief nand写入页数据.
*
* @param PageNum:页地址,范围0-block_pagenum*block_totalnum-1
*
* @param ColNum:区域地址,范围0-page_sparesize-1
*
* @param pBuffer:数据缓冲区
*
* @param NumByteToWrite:写入的字节数
*
* @return none
*/
void dNAND_WritePage(uint32_t PageNum, uint16_t ColNum, uint8_t *pBuffer, uint16_t NumByteToWrite)
{
volatile uint16_t i = 0;
uint8_t res = 0;
uint8_t eccnum = 0;
uint8_t eccstart = 0;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = NAND_WRITE0;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)ColNum;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(ColNum>>8);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)PageNum;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(PageNum>>8);
nand->Delay(30);
if(NumByteToWrite % NAND_ECC_SECTOR_SIZE) {
for(i = 0; i < NumByteToWrite; i++) {
*(volatile uint8_t *)NAND_ADDRESS = *(volatile uint8_t *)pBuffer++;
}
} else {
eccnum = NumByteToWrite / NAND_ECC_SECTOR_SIZE;
eccstart = ColNum / NAND_ECC_SECTOR_SIZE;
for(res = 0; res < eccnum; res++) {
nand->ECC_Enable();
for(i = 0; i < NAND_ECC_SECTOR_SIZE; i++) {
*(volatile uint8_t *)NAND_ADDRESS = *(volatile uint8_t *)pBuffer++;
}
nand->ECC_Fifo_Empty();
nand->Nand_Dev.ecc_hdbuf[res + eccstart] = nand->ECC_Get();
nand->ECC_Disable();
}
i = nand->Nand_Dev.page_mainsize + 0X10 + eccstart*4;
nand->Delay(30);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = 0X85;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)i;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(i>>8);
nand->Delay(30);
pBuffer = (uint8_t *)&nand->Nand_Dev.ecc_hdbuf[eccstart];
for(i = 0; i < eccnum; i++) {
for(res = 0; res < 4; res++) {
*(volatile uint8_t *)NAND_ADDRESS = *(volatile uint8_t *)pBuffer++;
}
}
}
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = NAND_WRITE_TURE1;
dNAND_WaitForReady();
}
/*********************************************************************
* @fn dNAND_WritePageConst
*
* @brief nand写入页指定长指定数据.
*
* @param PageNum:页地址,范围0-block_pagenum*block_totalnum-1
*
* @param ColNum:区域地址,范围0-page_sparesize-1
*
* @param cval:写入数据
*
* @param NumByteToWrite:写入的字节数
*
* @return none
*/
void dNAND_WritePageConst(uint32_t PageNum, uint16_t ColNum, uint32_t cval, uint16_t NumByteToWrite)
{
uint16_t i = 0;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = NAND_WRITE0;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)ColNum;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(ColNum>>8);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)PageNum;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(PageNum>>8);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(PageNum>>16);
nand->Delay(30);
for(i = 0; i < NumByteToWrite; i++) {
*(volatile uint32_t*)NAND_ADDRESS = cval;
}
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = NAND_WRITE_TURE1;
dNAND_WaitForReady();
}
/*********************************************************************
* @fn dNAND_CopyPageWithoutWrite
*
* @brief nand拷贝数据不写新的数据.
*
* @param Source_PageNum:源地址,范围0-block_pagenum*block_totalnum-1
*
* @param Dest_PageNum:目标地址,范围0-block_pagenum*block_totalnum-1
*
* @return none
*/
void dNAND_CopyPageWithoutWrite(uint32_t Source_PageNum, uint32_t Dest_PageNum)
{
uint8_t res = 0;
uint16_t source_block = 0, dest_block = 0;
source_block = Source_PageNum / nand->Nand_Dev.block_pagenum;
dest_block = Dest_PageNum / nand->Nand_Dev.block_pagenum;
if((source_block % 2) != (dest_block % 2)) {
return;
}
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = NAND_MOVEDATA_CMD0;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)0;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)0;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)Source_PageNum;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(Source_PageNum>>8);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(Source_PageNum>>16);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = NAND_MOVEDATA_CMD1;
res = dNAND_WaitRB(0);
if(res) {
return;
}
res = dNAND_WaitRB(1);
if(res) {
return;
}
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = NAND_MOVEDATA_CMD2;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)0;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)0;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)Dest_PageNum;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(Dest_PageNum>>8);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(Dest_PageNum>>16);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = NAND_MOVEDATA_CMD3;
dNAND_WaitForReady();
}
/*********************************************************************
* @fn dNAND_CopyPageWithWrite
*
* @brief nand拷贝数据写入新的数据.
*
* @param Source_PageNum:源地址,范围0-block_pagenum*block_totalnum-1
*
* @param Dest_PageNum:目标地址,范围0-block_pagenum*block_totalnum-1
*
* @param ColNum:区域地址,范围0-page_sparesize-1
*
* @param pBuffer:数据缓存区
*
* @param NumByteToWrite:写入数据字节数
*
* @return none
*/
void dNAND_CopyPageWithWrite(uint32_t Source_PageNum, uint32_t Dest_PageNum, uint16_t ColNum, uint8_t *pBuffer, uint16_t NumByteToWrite)
{
uint8_t res = 0;
volatile uint16_t i = 0;
uint16_t source_block = 0, dest_block = 0;
uint8_t eccnum = 0;
uint8_t eccstart = 0;
source_block = Source_PageNum / nand->Nand_Dev.block_pagenum;
dest_block = Dest_PageNum / nand->Nand_Dev.block_pagenum;
if((source_block % 2) != (dest_block % 2)) {
return;
}
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = NAND_MOVEDATA_CMD0;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)0;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)0;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)Source_PageNum;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(Source_PageNum>>8);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(Source_PageNum>>16);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = NAND_MOVEDATA_CMD1;
res = dNAND_WaitRB(0);
if(res) {
return;
}
res = dNAND_WaitRB(1);
if(res) {
return;
}
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = NAND_MOVEDATA_CMD2;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)ColNum;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(ColNum>>8);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)Dest_PageNum;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(Dest_PageNum>>8);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(Dest_PageNum>>16);
nand->Delay(30);
if(NumByteToWrite % NAND_ECC_SECTOR_SIZE) {
for(i = 0; i < NumByteToWrite; i++) {
*(volatile uint8_t *)NAND_ADDRESS = *(volatile uint8_t *)pBuffer++;
}
} else {
eccnum = NumByteToWrite / NAND_ECC_SECTOR_SIZE;
eccstart = ColNum / NAND_ECC_SECTOR_SIZE;
for(res = 0; res < eccnum; res++) {
nand->ECC_Enable();
for(i = 0; i < NAND_ECC_SECTOR_SIZE; i++) {
*(volatile uint8_t *)NAND_ADDRESS = *(volatile uint8_t *)pBuffer++;
}
nand->ECC_Fifo_Empty();
nand->Nand_Dev.ecc_hdbuf[res + eccstart] = nand->ECC_Get();
nand->ECC_Disable();
}
i = nand->Nand_Dev.page_mainsize + 0X10 + eccstart*4;
nand->Delay(30);
*(volatile uint8_t *)(NAND_ADDRESS | NAND_CMD) = 0X85;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)i;
*(volatile uint8_t *)(NAND_ADDRESS | NAND_ADDR) = (uint8_t)(i>>8);
nand->Delay(30);
pBuffer = (uint8_t *)&nand->Nand_Dev.ecc_hdbuf[eccstart];
for(i = 0; i < eccnum; i++) {
for(res = 0; res < 4; res++) {
*(volatile uint8_t *)NAND_ADDRESS = *(volatile uint8_t *)pBuffer++;
}
}
}
*(volatile uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_MOVEDATA_CMD3;
dNAND_WaitForReady();
}
/*********************************************************************
* @fn dNAND_WaitForReady
*
* @brief nand等待信号.
*
* @param none
*
* @return 0--正确,1--超时
*/
static uint8_t dNAND_WaitForReady(void)
{
uint8_t status = 0;
volatile uint32_t time = 0;
while(1)
{
status = nand->Read_Status();
if(status & 0x01)
{
break;
}
if(time++ >= 0x1FFFF)
{
return NSTA_TIMEOUT;
}
}
return NSTA_READY;
}
/*********************************************************************
* @fn dNAND_WaitRB
*
* @brief nand等待rb信号.
*
* @param rb:rb信号线
*
* @return 0--正确,1--超时
*/
static uint8_t dNAND_WaitRB(volatile uint8_t rb)
{
volatile uint16_t time = 0;
while(time < 10000)
{
time++;
if(nand->Get_RB() == rb)
{
return 0;
}
}
return 1;
}
/*********************************************************************
* @fn dNAND_ECC_Get_OE
*
* @brief nand获取ecc奇偶数.
*
* @param oe:0--偶数位,1--奇数位
*
* @param eccval:输入ecc值
*
* @return 返回计算的ecc值
*/
static uint16_t dNAND_ECC_Get_OE(uint8_t oe, uint32_t eccval)
{
uint8_t i;
uint16_t ecctemp = 0;
for(i = 0; i < 24; i++)
{
if((i%2) == oe)
{
if((eccval>>i) & 0X01)
{
ecctemp += 1<<(i>>1);
}
}
}
return ecctemp;
}
/*********************************************************************
* @fn dNAND_ECC_Correction
*
* @brief nand ecc校正.
*
* @param eccrd:保存的ecc值
*
* @param ecccl:硬件ecc值
*
* @return 0--错误已修正,1--大于2个bit错误无法修正
*/
static uint8_t dNAND_ECC_Correction(uint8_t *data_buf, uint32_t eccrd, uint32_t ecccl)
{
uint16_t eccrdo, eccrde, eccclo, ecccle;
uint16_t eccchk = 0;
uint16_t errorpos = 0;
uint32_t bytepos = 0;
eccrdo = dNAND_ECC_Get_OE(1, eccrd);
eccrde = dNAND_ECC_Get_OE(0, eccrd);
eccclo = dNAND_ECC_Get_OE(1, ecccl);
ecccle = dNAND_ECC_Get_OE(0, 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
{
return 1;
}
return 0;
}
/*
* dNAND.h
*
* Created on: 2023/12/5
* Author: WZX
*/
#ifndef _DNAND_H_
#define _DNAND_H_
#include <stdint.h>
#define NAND_MAX_PAGE_SIZE 2048 //定义NAND FLASH的最大的PAGE大小(不包括SPARE区),默认4096字节
#define NAND_ECC_SECTOR_SIZE 512 //执行ECC计算的单元大小,默认512字节
//NAND FLASH型号和对应的ID号
#define MT29F4G08ABADA 0XDC909556 //MT29F4G08ABADA
#define MT29F16G08ABABA 0X48002689 //MT29F16G08ABABA
#define W29N01GVSIAA 0XEFF18095 //W29N01GVSIAA
#define W29N01HVSINA 0XEFF10095 //W29N01HVSINA
#define NAND_ADDRESS 0X80000000 //nand flash的访问地址,接NCE3,地址为:0X8000 0000
#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
//NAND FLASH状态
#define NSTA_READY 0X40 //nand已经准备好
#define NSTA_ERROR 0X01 //nand错误
#define NSTA_TIMEOUT 0X02 //超时
#define NSTA_ECC1BITERR 0X03 //ECC 1bit错误
#define NSTA_ECC2BITERR 0X04 //ECC 2bit以上错误
#define NAND_REGION_NUMBER MPU_REGION_NUMBER3 //NAND FLASH使用region0
#define NAND_ADDRESS_START 0X80000000 //NAND FLASH区的首地址
#define NAND_REGION_SIZE MPU_REGION_SIZE_256MB //NAND FLASH区大小
typedef struct
{
uint16_t page_totalsize; //每页总大小,main区和spare区总和
uint16_t page_mainsize; //每页的main区大小
uint16_t page_sparesize; //每页的spare区大小
uint8_t block_pagenum; //每个块包含的页数量
uint16_t plane_blocknum; //每个plane包含的块数量
uint16_t block_totalnum; //总的块数量
uint16_t good_blocknum; //好块数量
uint16_t valid_blocknum; //有效块数量(供文件系统使用的好块数量)
uint32_t id; //NAND FLASH ID
uint16_t *lut; //LUT表,用作逻辑块-物理块转换
uint32_t ecc_hard; //硬件计算出来的ECC值
uint32_t ecc_hdbuf[NAND_MAX_PAGE_SIZE/NAND_ECC_SECTOR_SIZE];//ECC硬件计算值缓冲区
uint32_t ecc_rdbuf[NAND_MAX_PAGE_SIZE/NAND_ECC_SECTOR_SIZE];//ECC读取的值缓冲区
} Nand_Attriute;
typedef struct
{
Nand_Attriute Nand_Dev;
uint8_t (*MPU_Init)(void);
uint8_t (*Reset)(void);
uint8_t (*Delay)(volatile uint16_t ms);
uint32_t (*Read_ID)(void);
uint8_t (*Get_RB)(void);
uint8_t (*ECC_Enable)(void);
uint8_t (*ECC_Disable)(void);
uint32_t (*ECC_Get)(void);
uint32_t (*Read_Status)(void);
uint8_t (*ECC_Fifo_Empty)(void);
} NAND_TypeDef_t;
void dNAND_Init(NAND_TypeDef_t *nand_t);
void dNAND_ModeSet(uint8_t mode);
void dNAND_ReadSpare(uint32_t PageNum, uint16_t ColNum, uint8_t *pBuffer, uint16_t NumByteToRead);
void dNAND_WriteSpare(uint32_t PageNum, uint16_t ColNum, uint8_t *pBuffer, uint16_t NumByteToWrite);
void dNAND_EraseBlock(uint32_t BlockNum);
void dNAND_EraseChip(void);
void dNAND_ReadPage(uint32_t PageNum, uint16_t ColNum, uint8_t *pBuffer, uint16_t NumByteToRead);
void dNAND_ReadPageComp(uint32_t PageNum, uint16_t ColNum, uint32_t CmpVal, uint16_t NumByteToRead, uint16_t *NumByteEqual);
void dNAND_WritePage(uint32_t PageNum, uint16_t ColNum, uint8_t *pBuffer, uint16_t NumByteToWrite);
void dNAND_WritePageConst(uint32_t PageNum, uint16_t ColNum, uint32_t cval, uint16_t NumByteToWrite);
void dNAND_CopyPageWithoutWrite(uint32_t Source_PageNum, uint32_t Dest_PageNum);
void dNAND_CopyPageWithWrite(uint32_t Source_PageNum, uint32_t Dest_PageNum, uint16_t ColNum,uint8_t *pBuffer, uint16_t NumByteToWrite);
#endif
3.初始化
/*
* Cmd_NAND.c
*
* Created on: 2023/12/5
* Author: WZX
*/
#include "Cmd_NAND.h"
#include "dNAND.h"
#include "stm32h7xx.h"
extern NAND_HandleTypeDef hnand1;
static uint8_t nand_reset(void);
static uint8_t nand_mpu_init(void);
static uint8_t nand_delay(volatile uint16_t ms);
static uint32_t nand_read_id(void);
static uint8_t nand_get_rb(void);
static uint8_t nand_ecc_enable(void);
static uint8_t nand_ecc_disable(void);
static uint32_t nand_ecc_get(void);
static uint32_t nand_read_status(void);
static uint8_t nand_wait_fifo_empty(void);
/*********************************************************************
* @fn Cmd_NAND_Init
*
* @brief nand初始化.
*
* @param none
*
* @return none
*/
void Cmd_NAND_Init(void)
{
static NAND_TypeDef_t nand_temp;
nand_temp.Reset = nand_reset;
nand_temp.MPU_Init = nand_mpu_init;
nand_temp.Delay = nand_delay;
nand_temp.Read_ID = nand_read_id;
nand_temp.Get_RB = nand_get_rb;
nand_temp.ECC_Enable = nand_ecc_enable;
nand_temp.ECC_Disable = nand_ecc_disable;
nand_temp.ECC_Get = nand_ecc_get;
nand_temp.Read_Status = nand_read_status;
nand_temp.ECC_Fifo_Empty = nand_wait_fifo_empty;
dNAND_Init(&nand_temp);
}
//复位
static uint8_t nand_reset(void)
{
if(HAL_NAND_Reset(&hnand1) == HAL_OK)
{
return 0;
}
return 1;
}
static uint8_t nand_mpu_init(void)
{
MPU_Region_InitTypeDef MPU_Initure;
HAL_MPU_Disable();
MPU_Initure.Enable = MPU_REGION_ENABLE;
MPU_Initure.Number = NAND_REGION_NUMBER;
MPU_Initure.BaseAddress = NAND_ADDRESS_START;
MPU_Initure.Size = NAND_REGION_SIZE;
MPU_Initure.SubRegionDisable = 0X00;
MPU_Initure.TypeExtField = MPU_TEX_LEVEL0;
MPU_Initure.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_Initure.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
MPU_Initure.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_Initure.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_Initure.IsBufferable = MPU_ACCESS_BUFFERABLE;
HAL_MPU_ConfigRegion(&MPU_Initure);
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
return 0;
}
static uint8_t nand_delay(volatile uint16_t ms)
{
//HAL_Delay(ms);
volatile uint32_t index = 0;
for(index = ms; index != 0; index--)
{
}
return 0;
}
static uint32_t nand_read_id(void)
{
NAND_IDTypeDef nand_id;
uint32_t nandid;
if(HAL_NAND_Read_ID(&hnand1, &nand_id) == HAL_OK)
{
nandid = (nand_id.Maker_Id << 24) | (nand_id.Device_Id << 16) | \
(nand_id.Third_Id << 8) | (nand_id.Fourth_Id);
return nandid;
}
return 0xFFFFFFFF;
}
static uint8_t nand_get_rb(void)
{
return HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_6);
}
static uint8_t nand_ecc_enable(void)
{
if(HAL_NAND_ECC_Enable(&hnand1) == HAL_OK)
{
return 0;
}
return 1;
}
static uint8_t nand_ecc_disable(void)
{
if(HAL_NAND_ECC_Disable(&hnand1) == HAL_OK)
{
return 0;
}
return 1;
}
static uint32_t nand_ecc_get(void)
{
uint32_t ECCval;
if(HAL_NAND_GetECC(&hnand1, &ECCval, 1) == HAL_OK)
{
return ECCval;
}
return 1;
}
static uint32_t nand_read_status(void)
{
return HAL_NAND_Read_Status(&hnand1);
}
static uint8_t nand_wait_fifo_empty(void)
{
while(!(FMC_Bank3_R->SR&(1<<6)));
return 0;
}