坛子里有用LittleFS的吗?
前段儿有个朋友给我推荐了一个嵌入式的小FS,还是ARM出品的,带掉电保护和擦写均衡,默认的BLOCK是4K大小,这明摆着是冲着SPI FLASH去的,应该是非常适合W25Q系列的FLASH的文件系统,只不过不兼容FAT格式,不知道论坛里有没有同学在使用这个小FS,另外安富莱在整个论坛里好像都没提到过这个小型文件系统,针对SPI FLASH,为何安富莱不主推这个小系统呢?LittleFS SPI FLASH 例程基于W25Q64 STM32F103
http://www.armbbs.cn/forum.ph ... id=89337&fromuid=58
(出处: 安富莱电子论坛)
littlefs移植使用
http://www.armbbs.cn/forum.php?mod=viewthread&tid=86250&fromuid=58
(出处: 安富莱电子论坛)
硬汉能不能基于咱家的开发板写一个LittleFS的DEMO,推广下这个小FS 本帖最后由 taobaofarmer 于 2018-11-15 17:44 编辑
/*
********************************************************************************
* .忙状态寄存器的BUSY位(D0位,只读)在写动作(页写、扇区擦除、块擦除、芯片擦除、写
* .状态寄存器)期间有效(指示忙),其余状态非忙,此函数执行后一直等到非忙状态才退出
********************************************************************************
*/
void W25Q_CheckBusy(void)
{
vu8i;
W25Q_Select();
{
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET);
SPI2->DR = 0x05;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
i = SPI2->DR;
do
{
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET);
SPI2->DR = 0xff;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
}
while(SPI2->DR & 0x01);
}
W25Q_DeSelect();
}
void W25Q_WriteEnable(void)
{
vu8i;
W25Q_Select();
{
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET);
SPI2->DR = 0x06;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
i = SPI2->DR;
}
W25Q_DeSelect();
}
void W25Q_WriteDisable(void)
{
vu8i;
W25Q_Select();
{
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET);
SPI2->DR = 0x04;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
i = SPI2->DR;
}
W25Q_DeSelect();
}
//address - 24位地址
//pHead - 存储读出数据的头指针
//len - 读出数据长度
void W25Q_ReadData(u32 address, u8 *pHead, u16 len)
{
u16i;
u8 add2, add1, add0;
add2 = (u8)(address>>16);
add1 = (u8)(address>>8);
add0 = (u8)(address);
W25Q_CheckBusy();
W25Q_Select();
{
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET); //1-送读命令03H
SPI2->DR = 0x03;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
i = SPI2->DR;
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET); //2-送高字节地址
SPI2->DR = add2;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
i = SPI2->DR;
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET); //3-送中字节地址
SPI2->DR = add1;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
i = SPI2->DR;
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET); //4-送低字节地址
SPI2->DR = add0;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
i = SPI2->DR;
for(i=0; i<len; i++)
{
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET);
SPI2->DR = 0xff;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
pHead = SPI2->DR;
}
}
W25Q_DeSelect();
}
//扇区(4K Bytes)擦除,该参数是扇区的绝对起始地址
void W25Q_SectorErase(u32 add)
{
vu8 i;
u8add2,add1,add0;
add2 = (u8)(add>>16);
add1 = (u8)(add>>8);
add0 = (u8)(add);
W25Q_CheckBusy();
W25Q_WriteEnable();
W25Q_Select();
{
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET);
SPI2->DR = 0x20;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
i = SPI2->DR;
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET);
SPI2->DR = add2;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
i = SPI2->DR;
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET);
SPI2->DR = add1;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
i = SPI2->DR;
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET);
SPI2->DR = add0;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
i = SPI2->DR;
}
W25Q_DeSelect();
W25Q_WriteDisable();
}
//整片擦除
void W25Q_ChipErase(void)
{
vu8 id;
W25Q_CheckBusy();
W25Q_WriteEnable();
W25Q_Select();
{
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET);
SPI2->DR = 0xc7;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
id = SPI2->DR;
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET);
SPI2->DR = 0xff;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
id = SPI2->DR;
}
W25Q_DeSelect();
W25Q_CheckBusy();
W25Q_WriteDisable();
}
//address - 24位地址
//pHead - 存储读出数据的头指针
//len - 读出数据长度
void W25Q_PageProgram(u32 address, u8 *pHead, u16 len)
{
u16i;
vu8j;
u8 add2, add1, add0;
add2 = (u8)(address>>16);
add1 = (u8)(address>>8);
add0 = (u8)(address);
W25Q_CheckBusy();
W25Q_WriteEnable();
W25Q_Select();
{
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET);
SPI2->DR = 0x02;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
i = SPI2->DR;
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET);
SPI2->DR = add2;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
i = SPI2->DR;
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET);
SPI2->DR = add1;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
i = SPI2->DR;
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET);
SPI2->DR = add0;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
i = SPI2->DR;
for(i=0; i<len; i++)
{
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET);
SPI2->DR = pHead;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
j = SPI2->DR;
}
}
W25Q_DeSelect();
W25Q_WriteDisable();
}
//Winbond Serial Flash Manufacturer ID:EFH
u8 W25Q_ReadManufacturer(void)
{
vu8 id;
W25Q_CheckBusy();
W25Q_Select();
{
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET);
SPI2->DR = 0x9f;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
id = SPI2->DR;
while((SPI2->SR & SPI_I2S_FLAG_TXE) == RESET);
SPI2->DR = 0xff;
while((SPI2->SR & SPI_I2S_FLAG_RXNE) == RESET);
id = SPI2->DR;
}
W25Q_DeSelect();
return id;
}
//下面是移植代码,只有4个函数,我用的是W25Q128
void lfs_MyConfig(u32 sectors)
{
//cfg.context = NULL;
//block device operations
cfg.read= lfs_block_device_read;
cfg.prog= lfs_block_device_prog;
cfg.erase = lfs_block_device_erase;
cfg.sync= lfs_block_device_sync;
//block device configuration
cfg.read_size = 256;
cfg.prog_size = 256;
cfg.block_size= 4096;
cfg.block_count = sectors;
cfg.lookahead = 256;
cfg.read_buffer = lfs_read_buf;
cfg.prog_buffer = lfs_prog_buf;
cfg.lookahead_buffer = lfs_lookahead_buf;
cfg.file_buffer = lfs_file_buf;
}
int lfs_block_device_read(const struct lfs_config *lfsc,
lfs_block_t block,
lfs_off_t off,
void *buffer,
lfs_size_t size)
{
W25Q_ReadData((block*lfsc->block_size)+off, (uint8_t *)buffer, size);
return LFS_ERR_OK;
}
int lfs_block_device_prog(const struct lfs_config *lfsc,
lfs_block_t block,
lfs_off_t off,
const void *buffer,
lfs_size_t size)
{
W25Q_PageProgram((block*lfsc->block_size)+off, (uint8_t*)buffer, size);
return LFS_ERR_OK;
}
int lfs_block_device_erase(const struct lfs_config *lfsc, lfs_block_t block)
{
W25Q_SectorErase(block*lfsc->block_size);
return LFS_ERR_OK;
}
int lfs_block_device_sync(const struct lfs_config *lfsc)
{
return LFS_ERR_OK;
}
uTemp = W25Q_ReadManufacturer();
W25Q_ChipErase();
lfs_MyConfig(4096);
err = lfs_mount(&lfs, &cfg);
// reformat if we can't mount the filesystem
// this should only happen on the first boot
if(err)
{
lfs_format(&lfs, &cfg);
lfs_mount(&lfs, &cfg);
}
lfs_file_open(&lfs, &file_SysParams, "/boot", LFS_O_RDWR | LFS_O_CREAT);
memset(uTemp, 0x77, 32);
lfs_file_write(&lfs, &file_SysParams, uTemp, 15);
memset(uTemp, 0x88, 32);
lfs_file_read(&lfs, &file_SysParams, uTemp, 16);
上面的代码分3不分,第1不分是我写的25Q128驱动;第2部分是针对LittleFS的移植,移植比较简单,填好cfg结构的各个参数和4个移植函数;第3部分是我的应用,挂载FS,读写文件,但出现了问题。
首先uTemp = W25Q_ReadManufacturer();这句代码执行是正确的,读出的是厂家的代码0xef
W25Q_ChipErase();执行这句的时候除了问题,这句是整片擦除,擦除指令后我进行了等待,应该是等待挺久之后才会退出这个函数,可是执行的时候,刷一下就执行完了,而且芯片确实没有擦除掉,因为我执行读函数之后,发现读出来的数据根本不是整片擦除之后的效果
Q128的驱动函数,以前在没用FS的时候,保存参数和字库都是没问题的
最后一个,在挂载FS的时候,返回的还是正确的,然后打开文件,写文件,读文件出来的数据根本不对
本来裸奔用的好好的,现在整的都胡思乱想怀疑人生了,哪位用过LittleFS的师兄帮忙看看,谢谢 taobaofarmer 发表于 2018-11-15 17:36
硬汉能不能基于咱家的开发板写一个LittleFS的DEMO,推广下这个小FS
好的,后面我也研究研究。 楼主这个搞法估计不对,打开 写 关闭, 然后再打开 读 再关闭,写完立马读,读不到,fatfs也不行 W25Q的驱动问题不大,读、写、扇区擦除用了很多年了,一直没问题 好东西,有机会比较下在spi lash下littlefs、spiffs和RL-Flashfs的区别与性能 你准备什么时候干这事儿? 挂载文件的时候,提示Invalid superblock at,是什么原因啊? 表示最近也在研究这个文件系统,没搞成功,希望硬汉哥有空也给咱搞个demo参考一下。 jiulinzeng 发表于 2020-7-14 13:35
表示最近也在研究这个文件系统,没搞成功,希望硬汉哥有空也给咱搞个demo参考一下。
二楼的两个就行。 有没有人在sd卡上用这个成功的,目前在nor flash上移植没问题,sd上移植各种问题,sd卡底层直接读写都没问题 老鸟kkk 发表于 2020-10-31 22:50
有没有人在sd卡上用这个成功的,目前在nor flash上移植没问题,sd上移植各种问题,sd卡底层直接读写都没问 ...
SD卡不太适合用嵌入式文件系统littlefs,还是用FAT的靠谱。 看来这个小FS还真是有不少关注的 请问sd卡用fat的,一般怎么保证断电数据异常的问题,特别是异常断电导致的文件系统损坏?加大电容? 有人用LittleFS推SPI NAND吗?
页:
[1]