taobaofarmer 发表于 2018-11-10 17:09:41

坛子里有用LittleFS的吗?

前段儿有个朋友给我推荐了一个嵌入式的小FS,还是ARM出品的,带掉电保护和擦写均衡,默认的BLOCK是4K大小,这明摆着是冲着SPI FLASH去的,应该是非常适合W25Q系列的FLASH的文件系统,只不过不兼容FAT格式,不知道论坛里有没有同学在使用这个小FS,另外安富莱在整个论坛里好像都没提到过这个小型文件系统,针对SPI FLASH,为何安富莱不主推这个小系统呢?

eric2013 发表于 2018-11-11 02:18:31

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
(出处: 安富莱电子论坛)


taobaofarmer 发表于 2018-11-15 17:36:50

硬汉能不能基于咱家的开发板写一个LittleFS的DEMO,推广下这个小FS

taobaofarmer 发表于 2018-11-15 17:41:10

本帖最后由 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);

taobaofarmer 发表于 2018-11-15 17:53:51

上面的代码分3不分,第1不分是我写的25Q128驱动;第2部分是针对LittleFS的移植,移植比较简单,填好cfg结构的各个参数和4个移植函数;第3部分是我的应用,挂载FS,读写文件,但出现了问题。
首先uTemp = W25Q_ReadManufacturer();这句代码执行是正确的,读出的是厂家的代码0xef
W25Q_ChipErase();执行这句的时候除了问题,这句是整片擦除,擦除指令后我进行了等待,应该是等待挺久之后才会退出这个函数,可是执行的时候,刷一下就执行完了,而且芯片确实没有擦除掉,因为我执行读函数之后,发现读出来的数据根本不是整片擦除之后的效果
Q128的驱动函数,以前在没用FS的时候,保存参数和字库都是没问题的
最后一个,在挂载FS的时候,返回的还是正确的,然后打开文件,写文件,读文件出来的数据根本不对
本来裸奔用的好好的,现在整的都胡思乱想怀疑人生了,哪位用过LittleFS的师兄帮忙看看,谢谢

eric2013 发表于 2018-11-17 01:22:22

taobaofarmer 发表于 2018-11-15 17:36
硬汉能不能基于咱家的开发板写一个LittleFS的DEMO,推广下这个小FS

好的,后面我也研究研究。

leiyitan 发表于 2018-11-17 07:37:59

楼主这个搞法估计不对,打开 写 关闭, 然后再打开 读 再关闭,写完立马读,读不到,fatfs也不行

taobaofarmer 发表于 2018-11-17 09:16:58

W25Q的驱动问题不大,读、写、扇区擦除用了很多年了,一直没问题

木兰花 发表于 2018-11-26 09:52:46

好东西,有机会比较下在spi lash下littlefs、spiffs和RL-Flashfs的区别与性能

taobaofarmer 发表于 2018-11-26 10:05:13

你准备什么时候干这事儿?

ghostspider 发表于 2020-4-28 15:50:17

挂载文件的时候,提示Invalid superblock at,是什么原因啊?

jiulinzeng 发表于 2020-7-14 13:35:55

表示最近也在研究这个文件系统,没搞成功,希望硬汉哥有空也给咱搞个demo参考一下。

eric2013 发表于 2020-7-14 15:32:53

jiulinzeng 发表于 2020-7-14 13:35
表示最近也在研究这个文件系统,没搞成功,希望硬汉哥有空也给咱搞个demo参考一下。

二楼的两个就行。

老鸟kkk 发表于 2020-10-31 22:50:10

有没有人在sd卡上用这个成功的,目前在nor flash上移植没问题,sd上移植各种问题,sd卡底层直接读写都没问题

eric2013 发表于 2020-11-1 10:05:32

老鸟kkk 发表于 2020-10-31 22:50
有没有人在sd卡上用这个成功的,目前在nor flash上移植没问题,sd上移植各种问题,sd卡底层直接读写都没问 ...

SD卡不太适合用嵌入式文件系统littlefs,还是用FAT的靠谱。

taobaofarmer 发表于 2020-11-1 12:58:14

看来这个小FS还真是有不少关注的

老鸟kkk 发表于 2020-11-13 13:58:24

请问sd卡用fat的,一般怎么保证断电数据异常的问题,特别是异常断电导致的文件系统损坏?加大电容?

----- 发表于 2023-8-20 17:50:56

有人用LittleFS推SPI NAND吗?

页: [1]
查看完整版本: 坛子里有用LittleFS的吗?