一般学习中使用FatFS可能多一点,使用上差别不是太大,但是FatFs没有,磨损均衡,坏块,ECC等管理,作为学习移植文件系统,问题不大,但在用到实际项目上去的话,这是肯定不行的,FLASH在产生坏块后,文件系统会受到破坏导致数据的丢失和产品的不稳定,RL-FlashFs是专门针对Flash芯片的文件系统,类似的还有国外一个开源的SPI-ffs,是专门针对小型化SPI FLASH的一种文件系统。
平台配置
FLASH:W29N1GV 128MB SLC NAND
控制器:STM32F417ZGT6
接口:STM32的FSMC接口
软件平台:MDK4.74(选4.74的原因是5版本以后的RL-FlashFs变成了一个pack,依赖于RTX,因为现在使用了QPN框架,暂时不想用RTX就不去掉这个依赖了)
CubeMx配置:
image根据自己FLASH的数据手册来进行配置吧
其余的部分大可参照安富莱的教程,记录一下自己遇到的坑,其他朋友也可以参考一下
1.配置时不使用STM32的硬件ECC。
2.读取时的页大小 = Page Size + Spare area Size(我这边是2048 + 64 = 2112)
3.ST官方的库里面的读取函数都是整页读取的,移植时要自己写字节读取函数
以下是移植用到的API
uint8_t FSMC_NAND_Write_Page(uint8_t *_pBuffer, uint32_t _ulPageNo, uint16_t _usAddrInPage, uint16_t _usByteCount)
{
__IO uint32_t index = 0U;
uint32_t tickstart = 0U;
/* Process Locked */
__HAL_LOCK(&hnand1);
/* Check the NAND controller state */
if(hnand1.State == HAL_NAND_STATE_BUSY)
{
return HAL_BUSY;
}
hnand1.State = HAL_NAND_STATE_BUSY;
/* Send write page command sequence */
*(__IO uint8_t *)((uint32_t)(NAND_DEVICE1 | CMD_AREA)) = NAND_CMD_AREA_A;
*(__IO uint8_t *)((uint32_t)(NAND_DEVICE1 | CMD_AREA)) = NAND_CMD_WRITE0;
/* (hnand->Config.PageSize) > 512 */
{
//(((hnand1.Config.BlockSize)*(hnand1.Config.BlockNbr)) <= 65535U)
// 1024 Blocks = 1024 * 64 pages * 2K Bytes
{
*(__IO uint8_t *)((uint32_t)(NAND_DEVICE1 | ADDR_AREA)) = ADDR_1ST_CYCLE(_usAddrInPage);
*(__IO uint8_t *)((uint32_t)(NAND_DEVICE1 | ADDR_AREA)) = ADDR_2ND_CYCLE(_usAddrInPage);
*(__IO uint8_t *)((uint32_t)(NAND_DEVICE1 | ADDR_AREA)) = ADDR_1ST_CYCLE(_ulPageNo);
*(__IO uint8_t *)((uint32_t)(NAND_DEVICE1 | ADDR_AREA)) = ADDR_2ND_CYCLE(_ulPageNo);
}
}
for(uint16_t i = 0; i < 40; i++);
/* Write data to memory */
for(; index < _usByteCount; index++)
{
*(__IO uint8_t *)NAND_DEVICE1 = *(uint8_t *)_pBuffer++;
}
for(uint16_t i = 0; i < 40; i++);
*(__IO uint8_t *)((uint32_t)(NAND_DEVICE1 | CMD_AREA)) = NAND_CMD_WRITE_TRUE1;
/* Read status until NAND is ready */
while(HAL_NAND_Read_Status(&hnand1) != NAND_READY)
{
/* Get tick */
tickstart = HAL_GetTick();
if((HAL_GetTick() - tickstart ) > NAND_WRITE_TIMEOUT)
{
return ERR_NAND_HW_TOUT;
}
}
uint32_t status = HAL_NAND_Read_Status(&hnand1);
/* Update the NAND controller state */
hnand1.State = HAL_NAND_STATE_READY;
/* Process unlocked */
__HAL_UNLOCK(&hnand1);
if(status == NAND_READY)
{
return RTV_NOERR;
}
else if(status == NAND_ERROR)
{
return ERR_NAND_PROG;
}
return RTV_NOERR;
}
uint8_t FSMC_NAND_Read_Page(uint8_t *_pBuffer, uint32_t _ulPageNo, uint16_t _usAddrInPage, uint16_t _usByteCount)
{
__IO uint32_t index = 0U;
uint32_t tickstart = 0U;
/* Process Locked */
__HAL_LOCK(&hnand1);
/* Check the NAND controller state */
if(hnand1.State == HAL_NAND_STATE_BUSY)
{
return HAL_BUSY;
}
hnand1.State = HAL_NAND_STATE_BUSY;
/* Send write page command sequence */
*(__IO uint8_t *)((uint32_t)(NAND_DEVICE1 | CMD_AREA)) = NAND_CMD_AREA_A;
/* (hnand->Config.PageSize) > 512 */
{
//(((hnand1.Config.BlockSize)*(hnand1.Config.BlockNbr)) <= 65535U)
// 1024 Blocks = 1024 * 64 pages * 2K Bytes
{
*(__IO uint8_t *)((uint32_t)(NAND_DEVICE1 | ADDR_AREA)) = ADDR_1ST_CYCLE(_usAddrInPage); //Ò³ÄÚµØÖ·µÍ8
*(__IO uint8_t *)((uint32_t)(NAND_DEVICE1 | ADDR_AREA)) = ADDR_2ND_CYCLE(_usAddrInPage); //Ò³ÄÚµØÖ·¸ß8
*(__IO uint8_t *)((uint32_t)(NAND_DEVICE1 | ADDR_AREA)) = ADDR_1ST_CYCLE(_ulPageNo); //Ò³µØÖ·¸ß8
*(__IO uint8_t *)((uint32_t)(NAND_DEVICE1 | ADDR_AREA)) = ADDR_2ND_CYCLE(_ulPageNo); //Ò³µØÖ·µÍ8
}
}
*(__IO uint8_t *)((uint32_t)(NAND_DEVICE1 | CMD_AREA)) = NAND_CMD_AREA_TRUE1;
for(uint16_t i = 0; i < 40; i++);
/* Read status until NAND is ready */
while(HAL_NAND_Read_Status(&hnand1) != NAND_READY)
{
/* Get tick */
tickstart = HAL_GetTick();
if((HAL_GetTick() - tickstart ) > NAND_WRITE_TIMEOUT)
{
return ERR_NAND_HW_TOUT;
}
}
/* Go back to read mode */
*(__IO uint8_t *)((uint32_t)(NAND_DEVICE1 | CMD_AREA)) = ((uint8_t)0x00);
__DSB();
/* ¶ÁÊý¾Ýµ½»º³åÇøpBuffer */
for(index = 0; index < _usByteCount; index++)
{
*(uint8_t *)_pBuffer++ = *(uint8_t *)(NAND_DEVICE1);
}
hnand1.State = HAL_NAND_STATE_READY;
__HAL_UNLOCK(&hnand1);
return RTV_NOERR;
}
uint8_t NAND_IsBadBlock(uint32_t _ulBlockNo)
{
uint8_t ucFlag;
/* Èç¹ûNAND Flash³ö³§Ç°ÒѾ±êעΪ»µ¿éÁË£¬Ôò¾ÍÈÏΪÊÇ»µ¿é */
FSMC_NAND_Read_Page(&ucFlag, _ulBlockNo * NAND_BLOCK_SIZE, NAND_PAGE_SIZE + BBM_OFFSET, 1);
if (ucFlag != 0xFF)
{
return 1;
}
FSMC_NAND_Read_Page(&ucFlag, _ulBlockNo * NAND_BLOCK_SIZE + 1, NAND_PAGE_SIZE + BBM_OFFSET, 1);
if (ucFlag != 0xFF)
{
return 1;
}
return 0; /* ÊǺÿé */
}
uint8_t FSMC_NAND_EraseBlock(uint32_t _ulBlockNo)
{
uint32_t tickstart = 0U;
/* Process Locked */
__HAL_LOCK(&hnand1);
/* Check the NAND controller state */
if(hnand1.State == HAL_NAND_STATE_BUSY)
{
return HAL_BUSY;
}
/* Update the NAND controller state */
hnand1.State = HAL_NAND_STATE_BUSY;
/* Send Erase block command sequence */
*(__IO uint8_t *)((uint32_t)(NAND_DEVICE1 | CMD_AREA)) = NAND_CMD_ERASE0;
_ulBlockNo <<= 6;
*(__IO uint8_t *)((uint32_t)(NAND_DEVICE1 | ADDR_AREA)) = ADDR_1ST_CYCLE(_ulBlockNo);
*(__IO uint8_t *)((uint32_t)(NAND_DEVICE1 | ADDR_AREA)) = ADDR_2ND_CYCLE(_ulBlockNo >> 8);
*(__IO uint8_t *)((uint32_t)(NAND_DEVICE1 | CMD_AREA)) = NAND_CMD_ERASE1;
/* Update the NAND controller state */
hnand1.State = HAL_NAND_STATE_READY;
/* Get tick */
tickstart = HAL_GetTick();
/* Read status until NAND is ready */
while(HAL_NAND_Read_Status(&hnand1) != NAND_READY)
{
if((HAL_GetTick() - tickstart ) > NAND_WRITE_TIMEOUT)
{
/* Process unlocked */
__HAL_UNLOCK(&hnand1);
return ERR_NAND_HW_TOUT;
}
}
uint32_t status = HAL_NAND_Read_Status(&hnand1);
/* Process unlocked */
__HAL_UNLOCK(&hnand1);
if(status == NAND_READY)
{
return RTV_NOERR;
}
else if(status == NAND_ERROR)
{
return ERR_NAND_PROG;
}
return RTV_NOERR;
}
uint8_t NAND_Format(void)
{
for(uint16_t i = 0; i < 1024; i++)
{
FSMC_NAND_EraseBlock(i);
}
return NAND_OK;
}
void NAND_Init(void)
{
MX_FSMC_Init();
HAL_NAND_Reset(&hnand1);
}
void NAND_UnInit(void)
{
HAL_NAND_MspDeInit(&hnand1);
}
网友评论