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

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

鸣谢:感谢eric硬汉哥

商务合作:[email protected]

基于单片机系统的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文件中,需要根据自己的硬件环境,实现如下五个函数:

1
2
3
4
5
6
7
const NAND_DRV nand0_drv = {
  Init,
  UnInit,
  PageRead,
  PageWrite,
  BlockErase,
};

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
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[i] = 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[i];
    }

    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输入输出,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
/*
 * 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脚本,稍作修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
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进行操作了。。。。。。。。结束!