硬汉嵌入式论坛

 找回密码
 立即注册
查看: 4499|回复: 8
收起左侧

[客户分享] 基于rt-thread操作系统和stm32f407硬件平台,实现RL-FLASHFS文件系统移植(nandflash)

[复制链接]

4

主题

12

回帖

24

积分

新手上路

积分
24
发表于 2020-4-10 10:26:00 | 显示全部楼层 |阅读模式
本帖最后由 lz_kwok 于 2020-4-10 10:44 编辑

版权声明:本版面文章皆为原创、或参考其他技术网站、博客后自己动手做实验所得,转载请注明出处。

鸣谢:感谢eric硬汉哥

商务合作:lz_kwok@163.com

基于单片机系统的nandflash文件系统,一直是比较头疼的问题。由于nandflash存在硬件坏块,所以ecc动态均衡校验就显得十分重要。目前开源的ftl算法,都或多或少存在一些问题(没问题的也没开源,反正我没找到)。如此一来,keil的rl-flashfs就显得十足珍贵。

先来看看rl-flashfs的特点:

1. RL-FlashFS本身支持擦写均衡,坏块管理,ECC和掉电保护。

2. RL-FlashFS是FAT兼容的文件系统。

3. RL-FlashFS的文件名仅支持ASCII,不支持中文,这点要特别注意。

4. 首次格式化后使用,读速度2.3MB/S左右,写速度3.2MB/S左右,配置不同的文件系统缓冲大小,速度有区别。

5. RL-FlashFS的函数是标准的C库函数,跟电脑端的文件系统使用方法一样。

6. RL-FlashFS与FatFS的区别,FatFS仅是一个FAT类的文件件系统,擦写均衡,坏块管理,ECC和掉电保护都不支持。

    这些都需要用户自己去实现。

7. UFFS,YAFFS这两款文件系统是不兼容FAT的,也就是无法在Windows端模拟U盘。

但是比较讨厌的是,在MDK4.74之后,rl-flashfs与keil自家的操作系统做了比较深的耦合。虽然eric硬汉哥提供了freertos的教程,但是有没有可能把rl-flashfs与目前国内比较火的操作系统rt-thread做兼容呢?虽然rt-thread自带的uffs文件系统也能用,但是占用ram太高,且不兼容FAT。

说干就干,经过两天的移植和测试,初步完成rl-flashfs在rt-thread操作系统下的移植。

硬件平台:stm32f407zgtx

NANDFLASH:W29N02GVSIAA(FSMC)

(有需要开发板合作的可以私信邮箱)

从官网下载rl-arm的源码包,如下


rt-thread有非常棒的scons构建工具,根据该构建语法,编写对应的配置文件Kconfig和SConscript。编写完成后,利用rt-thread提供的Env工具,输入menuconfig,按照下图进行选择。注意,由于时间关系,并未和rtt原生的虚拟文件系统做兼容适配,故选择关闭Device virtual file system。


选择完毕后,在Env工具中 输入scons --target=mdk5,可自动将我配置好的源码目录加入到MDK中(本人使用的是mdk5.23)。工程如下:



工程中可以看到三个重要文件,寄File_Config.c、FS_NAND_FlashPrg.c和FSN_CM3.lib,注意FSN_CM3.lib只能用于keil下,对于使用IAR的同学,只能说声拜拜。


File_Config配置如下:



在FS_NAND_FlashPrg.c文件中,需要根据自己的硬件环境,实现如下五个函数:


const NAND_DRV nand0_drv = {

  Init,

  UnInit,

  PageRead,

  PageWrite,

  BlockErase,

};

为了实现这五个函数,首先新建drv_nand.c文件,实现W29N02GVSIAA驱动,代码如下:


static rt_uint8_t FSMC_NAND_ReadStatus(void)

{

        rt_uint8_t ucData;

        rt_uint8_t ucStatus = NAND_BUSY;

        NAND_CMD_AREA = NAND_CMD_STATUS;

        ucData = *(__IO rt_uint8_t *)(Bank_NAND_ADDR);

        if((ucData & NAND_ERROR) == NAND_ERROR)

        {

                ucStatus = NAND_ERROR;

        }

        else if((ucData & NAND_READY) == NAND_READY)

        {

                ucStatus = NAND_READY;

        }

        else

        {

                ucStatus = NAND_BUSY;

        }

        return (ucStatus);

}

static rt_uint8_t FSMC_NAND_GetStatus(void)

{

        rt_uint32_t ulTimeout = 0x10000;

        rt_uint8_t ucStatus = NAND_READY;

        ucStatus = FSMC_NAND_ReadStatus();

        while ((ucStatus != NAND_READY) &&( ulTimeout != 0x00))

        {

                ucStatus = FSMC_NAND_ReadStatus();

                if(ucStatus == NAND_ERROR)

                {

                        return (ucStatus);

                }

                ulTimeout--;

        }

        if(ulTimeout == 0x00)

        {

                ucStatus =  NAND_TIMEOUT_ERROR;

        }

        return (ucStatus);

}

//读取NAND FLASH的ID

//不同的NAND略有不同,请根据自己所使用的NAND FALSH数据手册来编写函数

//返回值:NAND FLASH的ID值

static rt_uint32_t NAND_ReadID(void)

{

    NAND_IDTypeDef nand_id;

    HAL_NAND_Read_ID(&NAND_Handler,&nand_id);

    NAND_DEBUG("ID[%X,%X,%X,%X]\n",nand_id.Maker_Id,nand_id.Device_Id,nand_id.Third_Id,nand_id.Fourth_Id);

    return 0;

}  

//复位NAND

//返回值:0,成功;

//    其他,失败

static rt_uint8_t NAND_Reset(void)

{

    NAND_CMD_AREA = NAND_RESET;        //复位NAND

    if(FSMC_NAND_GetStatus()==NAND_READY)

        return 0;           //复位成功

    else

        return 1;                        //复位失败

}

void rt_hw_mtd_nand_deinit(void)

{

    HAL_NAND_DeInit(&NAND_Handler);

}

//初始化NAND FLASH

rt_uint8_t rt_hw_mtd_nand_init(void)

{

    if(&NAND_Handler != NULL){

        rt_hw_mtd_nand_deinit();

    }

    FMC_NAND_PCC_TimingTypeDef ComSpaceTiming,AttSpaceTiming;

                                             

    NAND_Handler.Instance               = FMC_NAND_DEVICE;

    NAND_Handler.Init.NandBank          = FSMC_NAND_BANK2;                             //NAND挂在BANK2上

    NAND_Handler.Init.Waitfeature       = FSMC_NAND_PCC_WAIT_FEATURE_DISABLE;           //关闭等待特性

    NAND_Handler.Init.MemoryDataWidth   = FSMC_NAND_PCC_MEM_BUS_WIDTH_8;                //8位数据宽度

    NAND_Handler.Init.EccComputation    = FSMC_NAND_ECC_DISABLE;                        //不使用ECC

    NAND_Handler.Init.ECCPageSize       = FSMC_NAND_ECC_PAGE_SIZE_2048BYTE;             //ECC页大小为2k

    NAND_Handler.Init.TCLRSetupTime     = 1;                                            //设置TCLR(tCLR=CLE到RE的延时)=(TCLR+TSET+2)*THCLK,THCLK=1/180M=5.5ns

    NAND_Handler.Init.TARSetupTime      = 1;                                            //设置TAR(tAR=ALE到RE的延时)=(TAR+TSET+2)*THCLK,THCLK=1/180M=5.5n。   

    ComSpaceTiming.SetupTime        = 2;        //建立时间

    ComSpaceTiming.WaitSetupTime    = 5;        //等待时间

    ComSpaceTiming.HoldSetupTime    = 3;        //保持时间

    ComSpaceTiming.HiZSetupTime     = 1;        //高阻态时间

   

    AttSpaceTiming.SetupTime        = 2;        //建立时间

    AttSpaceTiming.WaitSetupTime    = 5;        //等待时间

    AttSpaceTiming.HoldSetupTime    = 3;        //保持时间

    AttSpaceTiming.HiZSetupTime     = 1;        //高阻态时间

   

    HAL_NAND_Init(&NAND_Handler,&ComSpaceTiming,&AttSpaceTiming);

    NAND_Reset();                               //复位NAND

    rt_thread_mdelay(100);

    return 0;

}

rt_uint8_t FSMC_NAND_ReadPage(rt_uint8_t *_pBuffer, rt_uint32_t _ulPageNo, rt_uint16_t _usAddrInPage, rt_uint16_t NumByteToRead)

{

        rt_uint32_t i;

    NAND_CMD_AREA = NAND_AREA_A;

    //发送地址

    NAND_ADDR_AREA = _usAddrInPage;

        NAND_ADDR_AREA = _usAddrInPage >> 8;

        NAND_ADDR_AREA = _ulPageNo;

        NAND_ADDR_AREA = (_ulPageNo & 0xFF00) >> 8;

    NAND_ADDR_AREA = (_ulPageNo & 0xFF0000) >> 16;

    NAND_CMD_AREA = NAND_AREA_TRUE1;

         /* 必须等待,否则读出数据异常, 此处应该判断超时 */

        for (i = 0; i < 20; i++);

    while(rt_pin_read(NAND_RB)==0);

        /* 读数据到缓冲区pBuffer */

        for(i = 0; i < NumByteToRead; i++)

        {

                _pBuffer = NAND_DATA_AREA;

        }

        return RT_EOK;

}

rt_uint8_t FSMC_NAND_WritePage(rt_uint8_t *_pBuffer, rt_uint32_t _ulPageNo, rt_uint16_t _usAddrInPage, rt_uint16_t NumByteToRead)

{

        rt_uint32_t i;

  rt_uint8_t ucStatus;

        NAND_CMD_AREA = NAND_WRITE0;

  //发送地址

         NAND_ADDR_AREA = _usAddrInPage;

        NAND_ADDR_AREA = _usAddrInPage >> 8;

        NAND_ADDR_AREA = _ulPageNo;

        NAND_ADDR_AREA = (_ulPageNo & 0xFF00) >> 8;

    NAND_ADDR_AREA = (_ulPageNo & 0xFF0000) >> 16;

        for (i = 0; i < 20; i++);

        for(i = 0; i < NumByteToRead; i++)

        {

        NAND_DATA_AREA = _pBuffer;

        }

        NAND_CMD_AREA = NAND_WRITE_TURE1;

        for (i = 0; i < 20; i++);

        

          ucStatus = FSMC_NAND_GetStatus();

        if(ucStatus == NAND_READY)   

        {

                ucStatus = RTV_NOERR;

        }

        else if(ucStatus == NAND_ERROR)

        {

                ucStatus = ERR_NAND_PROG;               

        }

        else if(ucStatus == NAND_TIMEOUT_ERROR)

        {

                ucStatus = ERR_NAND_HW_TOUT;               

        }

        

        return (ucStatus);

}

//擦除一个块

//BlockNum:要擦除的BLOCK编号,范围:0-(block_totalnum-1)

//返回值:0,擦除成功

//    其他,擦除失败

rt_uint8_t NAND_EraseBlock(rt_uint32_t _ulBlockNo)

{

    rt_uint8_t ucStatus;

        

        NAND_CMD_AREA = NAND_ERASE0;

        _ulBlockNo <<= 6;        

    NAND_ADDR_AREA = _ulBlockNo;

    NAND_ADDR_AREA = _ulBlockNo >> 8;

    NAND_ADDR_AREA = _ulBlockNo >> 16;

        NAND_CMD_AREA = NAND_ERASE1;

        ucStatus = FSMC_NAND_GetStatus();

        if(ucStatus == NAND_READY)   

        {

                ucStatus = RTV_NOERR;

        }

        else if(ucStatus == NAND_ERROR)

        {

                ucStatus = ERR_NAND_PROG;               

        }

        else if(ucStatus == NAND_TIMEOUT_ERROR)

        {

                ucStatus = ERR_NAND_HW_TOUT;               

        }

        

        return (ucStatus);

}

//全片擦除NAND FLASH

void NAND_EraseChip(void)

{

    rt_uint8_t status;

    rt_uint16_t i=0;

    for(i=0;i<2048;i++)     //循环擦除所有的块

    {

        status=NAND_EraseBlock(i);

        if(status)

            NAND_DEBUG("Erase %d block fail!!,ERRORCODE %d\r\n",i,status);//擦除失败

    }

}

实现FS_NAND_FlashPrg.c中五个函数后,还需要对rt-thread原生的stubs.c文件进行修改,根据rl-flashfs重新映射IO输入输出,代码如下:


/*

* Copyright (c) 2006-2018, RT-Thread Development Team

*

* SPDX-License-Identifier: Apache-2.0

*

* Change Logs:

* Date           Author       Notes

* 2012-11-23     Yihui        The first version

* 2013-11-24     aozima       fixed _sys_read()/_sys_write() issues.

* 2014-08-03     bernard      If using msh, use system() implementation

*                             in msh.

*/

#include <string.h>

#include <rt_sys.h>

#include "rtthread.h"

#include "libc.h"

#ifdef RT_USING_DFS

#include "dfs_posix.h"

#endif

#ifdef RT_USING_RL_FLASHFS

#include <File_Config.h>

struct __FILE { int handle; /* Add whatever you need here */ };

#endif

#ifdef __CLANG_ARM

__asm(".global __use_no_semihosting\n\t");

#else

#pragma import(__use_no_semihosting_swi)

#endif

/* Standard IO device handles. */

#define STDIN       0x8001

#define STDOUT      0x8002

#define STDERR      0x8003

/* Standard IO device name defines. */

const char __stdin_name[]  = "STDIN";

const char __stdout_name[] = "STDOUT";

const char __stderr_name[] = "STDERR";

/**

* required by fopen() and freopen().

*

* @param name - file name with path.

* @param openmode - a bitmap hose bits mostly correspond directly to

*                     the ISO mode specification.

* @return  -1 if an error occurs.

*/

FILEHANDLE _sys_open(const char *name, int openmode)

{

#ifdef RT_USING_DFS

    int fd;

    int mode = O_RDONLY;

#endif

    /* Register standard Input Output devices. */

    if (strcmp(name, __stdin_name) == 0)

        return (STDIN);

    if (strcmp(name, __stdout_name) == 0)

        return (STDOUT);

    if (strcmp(name, __stderr_name) == 0)

        return (STDERR);

#ifndef RT_USING_DFS

    #ifdef RT_USING_RL_FLASHFS

        return (__sys_open (name, openmode));

    #else

        return -1;

    #endif

#else

    /* Correct openmode from fopen to open */

    if (openmode & OPEN_PLUS)

    {

        if (openmode & OPEN_W)

        {

            mode |= (O_RDWR | O_TRUNC | O_CREAT);

        }

        else if (openmode & OPEN_A)

        {

            mode |= (O_RDWR | O_APPEND | O_CREAT);

        }

        else

            mode |= O_RDWR;

    }

    else

    {

        if (openmode & OPEN_W)

        {

            mode |= (O_WRONLY | O_TRUNC | O_CREAT);

        }

        else if (openmode & OPEN_A)

        {

            mode |= (O_WRONLY | O_APPEND | O_CREAT);

        }

    }

    fd = open(name, mode, 0);

    if (fd < 0)

        return -1;

    else

        return fd;

#endif

}

int _sys_close(FILEHANDLE fh)

{

#ifndef RT_USING_DFS

    #ifdef RT_USING_RL_FLASHFS

        if (fh > 0x8000) {

            return (0);

        }

        return (__sys_close (fh));

    #else

        return 0;

    #endif

#else

    if (fh <= STDERR) return 0;

    return close(fh);

#endif

}

/*

* Read from a file. Can return:

*  - zero if the read was completely successful

*  - the number of bytes _not_ read, if the read was partially successful

*  - the number of bytes not read, plus the top bit set (0x80000000), if

*    the read was partially successful due to end of file

*  - -1 if some error other than EOF occurred

*

* It is also legal to signal EOF by returning no data but

* signalling no error (i.e. the top-bit-set mechanism need never

* be used).

*

* So if (for example) the user is trying to read 8 bytes at a time

* from a file in which only 5 remain, this routine can do three

* equally valid things:

*

*  - it can return 0x80000003 (3 bytes not read due to EOF)

*  - OR it can return 3 (3 bytes not read), and then return

*    0x80000008 (8 bytes not read due to EOF) on the next attempt

*  - OR it can return 3 (3 bytes not read), and then return

*    8 (8 bytes not read, meaning 0 read, meaning EOF) on the next

*    attempt

*

* `mode' exists for historical reasons and must be ignored.

*/

int _sys_read(FILEHANDLE fh, unsigned char *buf, unsigned len, int mode)

{

#ifdef RT_USING_DFS

    int size;

#endif

    if (fh == STDIN)

    {

#ifdef RT_USING_POSIX

        size = libc_stdio_read(buf, len);

        return len - size;

#else

        /* no stdin */

        return -1;

#endif

    }

#ifndef RT_USING_RL_FLASHFS

    if ((fh == STDOUT) || (fh == STDERR))

        return -1;

#endif

#ifndef RT_USING_DFS

#ifdef RT_USING_RL_FLASHFS

    if (fh > 0x8000) {

        return (-1);

    }

    return (__sys_read (fh, buf, len));

#else

    return 0;

#endif

#else

    size = read(fh, buf, len);

    if (size >= 0)

        return len - size;

    else

        return -1;

#endif

}

/*

* Write to a file. Returns 0 on success, negative on error, and

* the number of characters _not_ written on partial success.

* `mode' exists for historical reasons and must be ignored.

*/

int _sys_write(FILEHANDLE fh, const unsigned char *buf, unsigned len, int mode)

{

#ifdef RT_USING_DFS

    int size;

#endif

    if ((fh == STDOUT) || (fh == STDERR))

    {

#if !defined(RT_USING_CONSOLE) || !defined(RT_USING_DEVICE)

        return 0;

#else

#ifdef RT_USING_POSIX

        size = libc_stdio_write(buf, len);

        return len - size;

#else

        if (rt_console_get_device())

        {

            rt_device_write(rt_console_get_device(), -1, buf, len);

            return 0;

        }

        return -1;

#endif

#endif

    }

#ifndef RT_USING_RL_FLASHFS

    if (fh == STDIN) return -1;

#endif

#ifndef RT_USING_DFS

#ifdef RT_USING_RL_FLASHFS

    if (fh > 0x8000) {

        return (-1);

    }

    return (__sys_write (fh, buf, len));

#else

    return 0;

#endif

#else

    size = write(fh, buf, len);

    if (size >= 0)

        return len - size;

    else

        return -1;

#endif

}

/*

* Move the file position to a given offset from the file start.

* Returns >=0 on success, <0 on failure.

*/

int _sys_seek(FILEHANDLE fh, long pos)

{

#ifndef RT_USING_RL_FLASHFS

    if (fh < STDERR)

        return -1;

#endif

#ifndef RT_USING_DFS

#ifdef RT_USING_RL_FLASHFS

    if (fh > 0x8000) {

        return (-1);

    }

    return (__sys_seek (fh, pos));

#else

    return -1;

#endif

#else

    /* position is relative to the start of file fh */

    return lseek(fh, pos, 0);

#endif

}

/**

* used by tmpnam() or tmpfile()

*/

int _sys_tmpnam(char *name, int fileno, unsigned maxlength)

{

#ifdef RT_USING_RL_FLASHFS

    return 1;

#else

    return -1;

#endif

}

char *_sys_command_string(char *cmd, int len)

{

#ifdef RT_USING_RL_FLASHFS

    return cmd;

#else

    /* no support */

    return RT_NULL;

#endif

}

/* This function writes a character to the console. */

void _ttywrch(int ch)

{

#ifdef RT_USING_CONSOLE

    char c;

    c = (char)ch;

    rt_kprintf(&c);

#endif

}

RT_WEAK void _sys_exit(int return_code)

{

    /* TODO: perhaps exit the thread which is invoking this function */

    while (1);

}

/**

* return current length of file.

*

* @param fh - file handle

* @return file length, or -1 on failed

*/

long _sys_flen(FILEHANDLE fh)

{

    struct stat stat;

#ifndef RT_USING_RL_FLASHFS   

    if (fh < STDERR)

        return -1;

#endif

#ifndef RT_USING_DFS

#ifdef RT_USING_RL_FLASHFS

    if (fh > 0x8000) {

        return (0);

    }

    return (__sys_flen (fh));

#else

    return -1;

#endif

#else

    fstat(fh, &stat);

    return stat.st_size;

#endif

}

int _sys_istty(FILEHANDLE fh)

{

#ifdef RT_USING_RL_FLASHFS

    if (fh > 0x8000) {

        return (1);

    }

    return (0);

#else

    if((STDIN <= fh) && (fh <= STDERR))

        return 1;

    else

        return 0;

#endif

}

int _sys_ensure (FILEHANDLE fh) {

  if (fh > 0x8000) {

    return (-1);

  }

  return (__sys_ensure (fh));

}

int remove(const char *filename)

{

#ifndef RT_USING_DFS

    return -1;

#else

    return unlink(filename);

#endif

}

#if defined(RT_USING_FINSH) && defined(FINSH_USING_MSH) && defined(RT_USING_MODULE) && defined(RT_USING_DFS)

/* use system(const char *string) implementation in the msh */

#else

int system(const char *string)

{

    RT_ASSERT(0);

    for (;;);

}

#endif

#ifdef __MICROLIB

#include <stdio.h>

int fputc(int c, FILE *f)

{

    char ch[2] = {0};

    ch[0] = c;

    rt_kprintf(&ch[0]);

    return 1;

}

int fgetc(FILE *f)

{

#ifdef RT_USING_POSIX

    char ch;

    if (libc_stdio_read(&ch, 1) == 1)

        return ch;

#endif

    return -1;

}

#endif

到这里,移植工作告一段落。


-------------------------------------------------------------------------------------------------------------------------------------------------------------------------


rt-thread吸引我的,除了强大配置功能之外,还有类似于linux的msh功能。既然是对文件系统移植,那就自定义几个shell命令来玩玩吧。参考linux的shell脚本,稍作修改:


static void glz_nand(int argc, char **argv)

{

    /* If the number of arguments less than 2 */

    if (argc < 2)

    {

help:

        rt_kprintf("\n");

        rt_kprintf("glz_nand [OPTION] [PARAM ...]\n");

        rt_kprintf("         ls                           显示指定工作目录下之内容\n");

        rt_kprintf("         cat        <filename>        显示文件内容\n");

        rt_kprintf("         mkdir      <docname>         创建文件夹\n");

        rt_kprintf("         rm         <filename>        删除文件\n");

        rt_kprintf("         formatall                    磁盘格式化\n");

                rt_kprintf("         df                           显示磁盘空间\n");

        return ;

    }

    else if (!strcmp(argv[1], "ls"))

    {

                if(argv[2]  != NULL){

                        ViewRootDir(argv[2]);

                }else{

                        ViewRootDir(NULL);

                }

    }

    else if (!strcmp(argv[1], "cat"))

    {

        if (argc < 3)

        {

            rt_kprintf("The input parameters are too few!\n");

            goto help;

        }

                ReadFileData(argv[2]);

    }

    else if (!strcmp(argv[1], "echo"))

    {

        if (argc < 4)

        {

            rt_kprintf("The input parameters are too few!\n");

            goto help;

        }

                if(!strcmp(argv[3], ">")){

                        EchotextFile(argv[2],argv[4]);

                }else{

                        rt_kprintf("bad parameters\n");

                }

    }

    else if (!strcmp(argv[1], "formatall"))

    {

                Formatflash();

    }

        else if (!strcmp(argv[1], "df"))

    {

                ViewNandCapacity();

    }

        else if (!strcmp(argv[1], "df"))

    {

                ViewNandCapacity();

    }

        else if (!strcmp(argv[1], "mkdir"))

    {

                if (argc < 2)

        {

            rt_kprintf("The input parameters are too few!\n");

            goto help;

        }

                CreateNewFile(argv[2]);

    }

        else if (!strcmp(argv[1], "rm"))

    {

                if (argc < 2)

        {

            rt_kprintf("The input parameters are too few!\n");

            goto help;

        }

                DeleteDirFile(argv[2]);

    }

    else

    {

        rt_kprintf("Input parameters are not supported!\n");

        goto help;

    }

}

MSH_CMD_EXPORT(glz_nand, GLZ nand RL-FLASHFS test function);

实现上述所有函数后,编译、下载,我们来看下效果撒。


首先,demo板上电,从串口输出log:



在msd中输入glz_nand,回车,可以看到命令提示:



先试下df,看下磁盘空间:




可以看到 磁盘空间大小为256MB。


下面分别实现其他指令操作:



好了,再也不用担心在单片机下对nandflash进行操作了。。。。。。。。结束!




回复

使用道具 举报

22

主题

250

回帖

321

积分

高级会员

积分
321
发表于 2020-4-10 21:07:36 | 显示全部楼层
非常厉害,不过看着像没有使用rtt的设备管理框架。
回复

使用道具 举报

3

主题

1234

回帖

1243

积分

至尊会员

积分
1243
发表于 2020-4-12 08:29:30 | 显示全部楼层
RL-FlashFS 文件系统模组,生产文件时,文件日期通过哪个函数获取的呢 ?
谢谢!!!
回复

使用道具 举报

4

主题

12

回帖

24

积分

新手上路

积分
24
 楼主| 发表于 2020-4-13 09:31:00 | 显示全部楼层
wujialing3000 发表于 2020-4-10 21:07
非常厉害,不过看着像没有使用rtt的设备管理框架。

是的,没用,考虑到直接用的系统库里的spi,直接用fopen、fwrite,与linux读写方式更贴近,就没再用rtt的框架再嵌套一层
回复

使用道具 举报

4

主题

12

回帖

24

积分

新手上路

积分
24
 楼主| 发表于 2020-4-24 14:55:30 | 显示全部楼层
硬汉哥有没有做过rl-flashfs应用spi接口的micro sd卡的方案?
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107244
QQ
发表于 2020-4-25 12:01:55 | 显示全部楼层
lz_kwok 发表于 2020-4-24 14:55
硬汉哥有没有做过rl-flashfs应用spi接口的micro sd卡的方案?

没有哦。
回复

使用道具 举报

0

主题

1

回帖

1

积分

新手上路

积分
1
发表于 2020-4-29 15:21:40 | 显示全部楼层
rl-arm的源码包哪里下载的,案例可以开源参考么
回复

使用道具 举报

4

主题

12

回帖

24

积分

新手上路

积分
24
 楼主| 发表于 2020-4-29 17:23:49 | 显示全部楼层

硬汉哥,spi的我搞定了。
但是有个问题咨询下 硬汉
/* Check Default drive settings */
#define __DEF  ((FL0_DEF   & FL0_EN)   +                          \
                (SF0_DEF   & SF0_EN)   +                          \
                (RAM0_DEF  & RAM0_EN)  +                          \
                (MC0_DEF   & MC0_EN)   + (MC1_DEF   & MC1_EN)  +  \
                (USB0_DEF  & USB0_EN)  + (USB1_DEF  & USB1_EN) +  \
                (NAND0_DEF & NAND0_EN) + (NAND1_DEF & NAND1_EN))
#if (__DEF == 0)
#error default drive not specified
#elif (__DEF > 1)
#error multiple default drives enabled
#endif

配置里有个默认driver的设置,如果挂载了设备后配合ftp功能,是不是只能挂载勾选默认的设备?测试发现,如果我勾选nand为默认设备,即便卸载nand,再挂载tf卡,ftp也无法传输文件。这个就什么办法解决吗
回复

使用道具 举报

4

主题

12

回帖

24

积分

新手上路

积分
24
 楼主| 发表于 2020-4-30 14:49:06 | 显示全部楼层
楼上的问题硬汉不用回复了,我已经定位到问题在哪了。
ftp_uif.c里写的不是很完善,修改下就可以了。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-23 06:45 , Processed in 0.246555 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表