当前位置:网站首页>RT thread learning notes (VIII) -- start the elmfat file system based on SPI flash (Part 2)
RT thread learning notes (VIII) -- start the elmfat file system based on SPI flash (Part 2)
2022-07-26 10:42:00 【aping_ cs_ dn】
Software environment :Win7,Keil MDK 4.72a, IAR EWARM 7.2, GCC 4.2,Python 2.7 ,SCons 2.3.2
Hardware environment :Armfly STM32F103ZE-EK v3.0 Development board
Reference article :RT-Thread Programming Guide
[RTthread] The new version RTT Medium SPI Drive frame
Github managed Realtouch In the branch examples Directory spi flash Routine for
In the previous article, we introduced how to add SPI Flash drive , Can successfully identify SPI Flash Chip model , But you still can't mount the file system , Unable to operate on file system , Therefore, we should study this problem in this article .
【1】 be familiar with RT-Thread Built-in commands ( The system default is C-Express Style)
RT-Thread By default, it is enabled Shell Terminal functional , And it uses USART1 A serial port , All of these are what we need and do not need to be changed on the current development board , By default . The last compiled program has been burned into the development board , This time, just power on or reset the development board . In the serial port Shell terminal , Let's get familiar with RT-Thread Built-in commands , Then I can add our customized commands in the same way .
(1)list(): Display the commands and variables existing in the current system
stay Finsh Enter... At the prompt list(), The results are as follows :
finsh>>list()
--Function List:
led -- set led[0 - 1] on[1] or off[0].
list_mem -- list memory usage information
mkfs -- make a file system
df -- get disk free
ls -- list directory contents
rm -- remove files or directories
cat -- print file
copy -- copy file or dir
mkdir -- create a directory
hello -- say hello world
version -- show RT-Thread version information
list_thread -- list thread
list_sem -- list semaphone in system
list_event -- list event in system
list_mutex -- list mutex in system
list_mailbox -- list mail box in system
list_msgqueue -- list message queue in system
list_mempool -- list memory pool in system
list_timer -- list timer in system
list_device -- list device in system
list -- list all symbol in system
--Variable List:
dummy -- dummy variable for finsh
0, 0x00000000
finsh>>
These commands list At the beginning of the RT-Thread Programming Guide Of finsh shell Part of it says , No more details here .
Look at the below led.c In the relevant led Command code :
#ifdef RT_USING_FINSH
#include <finsh.h>
static rt_uint8_t led_inited = 0;
void led(rt_uint32_t led, rt_uint32_t value)
{
/* init led configuration if it's not inited. */
if (!led_inited)
{
rt_hw_led_init();
led_inited = 1;
}
if ( led == 0 )
{
/* set led status */
switch (value)
{
case 0:
rt_hw_led_off(0);
break;
case 1:
rt_hw_led_on(0);
break;
default:
break;
}
}
if ( led == 1 )
{
/* set led status */
switch (value)
{
case 0:
rt_hw_led_off(1);
break;
case 1:
rt_hw_led_on(1);
break;
default:
break;
}
}
}
FINSH_FUNCTION_EXPORT(led, set led[0 - 1] on[1] or off[0].)
#endif
Top switch led The code is very simple , Although the value written in the actual operation is exactly the opposite of the command description , That's because of the hardware driver logic problem , It's not the key to the problem I want to study , The key is the blue bold part above , Is a macro definition , stay finsh.h Of documents 324 Line is defined as follows :
#define FINSH_FUNCTION_EXPORT(name, desc) \
FINSH_FUNCTION_EXPORT_CMD(name, name, desc)
At first glance, there is another macro definition , Keep looking down , Locate the finsh.h Of documents 231 That's ok , The code is as follows :
#define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \
const char __fsym_##cmd##_name[] = #cmd; \
const char __fsym_##cmd##_desc[] = #desc; \
const struct finsh_syscall __fsym_##cmdSECTION("FSymTab")= \
{ \
__fsym_##cmd##_name, \
__fsym_##cmd##_desc, \
(syscall_func)&name \
};
stay finsh.h Of documents 116 That's ok , We can see above about finsh_syscall and syscall_func The definition of :
typedef long (*syscall_func)();
/* system call table */
struct finsh_syscall
{
const char* name;/* the name of system call */
#if defined(FINSH_USING_DESCRIPTION) && defined(FINSH_USING_SYMTAB)
const char* desc;/* description of system call */
#endif
syscall_func func;/* the function address of system call */
};
syscall_func Is a function pointer , The return value is long type , yes finsh_syscall A member of a class , This is about finsh The implementation of the command is very clear , When FINSH_FUNCTION_EXPOR When a macro is called ,led The entry address of the function is passed to finsh_syscall Class __fsym_##cmd, And initialized by the parameters passed in .
To be specific ,led() Was passed on to finsh_syscall A member of a class object syscall Type of func, And (syscall_func)&name To initialize , obviously name To be cast into syscall_func type , in other words led Pass to func, The return value type is long type .finsh_syscall Class object __fsym_##cmd adopt SECTION macro Specify in a specific code segment FSymTab, When a thread executes a code , The function of this command is also Called . as for cmd,desc Parameters through ## The reassembly and replacement of conjunctions are relatively simple .
【2】 use FINSH_FUNCTION_EXPOR Macro import commands (Finsh Command operation function of terminal ) stay finsh_thread Implementation of calls in threads
Reference article :RT-Thread Next finsh Principle analysis ( Source : amoBBS Amo e-forum )
Let's search globally finsh_thread, You can go to shell.c Of documents 291 That's ok void finsh_thread_entry(void* parameter), This thread shell Command interface thread , The response to the terminal command is sent from here , as follows
... ...
#ifdef RT_USING_CONSOLE
shell->device = rt_console_get_device();
RT_ASSERT(shell->device);
rt_device_open(shell->device, RT_DEVICE_OFLAG_RDWR);
rt_device_set_rx_indicate(shell->device,finsh_rx_ind);
#else
RT_ASSERT(shell->device);
#endif
}
while (1)
{
... ...
/* wait receive */
if (rt_sem_take(&shell->rx_sem, RT_WAITING_FOREVER) != RT_EOK) continue;
/* read one character from device */
while (rt_device_read(shell->device, 0, &ch, 1) == 1)
{
... ...
If no data is received on the serial port , And there is no data in the serial port buffer , namely shell->rx_sem The value of the semaphore is 0, that rt_sem_take This semaphore function will make finsh_thread Thread to sleep ,RTT The kernel will execute other threads . When the serial port receives data , The system scheduler will call finsh_thread The thread is in rt_device_set_rx_indicate Function Callback function finsh_rx_ind, The Function call rt_sem_release(&shell->rx_sem) To release the semaphore , This will wake up finsh_thread Threads , This thread Active call rt_device_read To receive data . Enter the user command and press enter to confirm , Will execute the following code finsh_run_line() Function for syntax parsing .
... ...
#ifndef FINSH_USING_MSH_ONLY
/* add ';' and run the command line */
shell->line[shell->line_position] = ';';
if (shell->line_position != 0) finsh_run_line(&shell->parser, shell->line);
else rt_kprintf("\n");
#endif
... ...
then finsh_run_line() call finsh_parser_run(), The code is as follows :
#ifndef FINSH_USING_MSH_ONLY
void finsh_run_line(struct finsh_parser* parser, const char *line)
{
const char* err_str;
rt_kprintf("\n");
finsh_parser_run(parser, (unsigned char*)line);
... ...
The above code parses the syntax of the input command , First, make a preliminary syntax judgment on the incoming string :
/*
expr_postfix -> expr_primary
| expr_postfix INC
| expr_postfix DEC
| expr_postfix '(' param_list ')'
*/
static struct finsh_node* proc_postfix_expr(struct finsh_parser* self)
{
enum finsh_token_type token;
struct finsh_node* postfix;
postfix =proc_primary_expr(self);
... ...
As shown in the above code , then proc_primary_expr(self) call finsh_node_new_id(id),finsh_node_new_id() The code is as follows :
... ...
/* then lookup system variable */
symbol = (void*)finsh_sysvar_lookup(id);
if (symbol == NULL)
{
/* then lookup system call */
symbol = (void*)finsh_syscall_lookup(id);
if (symbol != NULL) type = FINSH_IDTYPE_SYSCALL;
}
... ...
finsh_syscall_lookup() Used to find system calls , The code is as follows :
struct finsh_syscall* finsh_syscall_lookup(const char* name)
{
struct finsh_syscall* index;
struct finsh_syscall_item* item;
for (index =_syscall_table_begin; index <_syscall_table_end; FINSH_NEXT_SYSCALL(index))
{
if (strcmp(index->name, name) == 0)
return index;
}
... ...
Let's take another look _syscall_table_begin and _syscall_table_end The definition of , The code is as follows :
#ifdef FINSH_USING_SYMTAB
struct finsh_syscall *_syscall_table_begin = NULL;
struct finsh_syscall *_syscall_table_end = NULL;
struct finsh_sysvar *_sysvar_table_begin = NULL;
struct finsh_sysvar *_sysvar_table_end = NULL;
#else
struct finsh_syscall _syscall_table[] =
{
{"hello", hello},
{"version", version},
{"list", list},
{"list_thread", list_thread},
#ifdef RT_USING_SEMAPHORE
{"list_sem", list_sem},
#endif
#ifdef RT_USING_MUTEX
{"list_mutex", list_mutex},
#endif
#ifdef RT_USING_FEVENT
{"list_fevent", list_fevent},
#endif
#ifdef RT_USING_EVENT
{"list_event", list_event},
#endif
#ifdef RT_USING_MAILBOX
{"list_mb", list_mailbox},
#endif
#ifdef RT_USING_MESSAGEQUEUE
{"list_mq", list_msgqueue},
#endif
#ifdef RT_USING_MEMPOOL
{"list_memp", list_mempool},
#endif
{"list_timer", list_timer},
};
struct finsh_syscall *_syscall_table_begin = &_syscall_table[0];
struct finsh_syscall *_syscall_table_end = &_syscall_table[sizeof(_syscall_table) / sizeof(struct finsh_syscall)];
_syscall_table_begin and _syscall_table_end The type of finsh_syscall, This type has been introduced before , Namely FINSH_FUNCTION_EXPOR The type used in the macro . That is, user-defined function , As the system comes with led() Function call FINSH_FUNCTION_EXPOR Macro import . Be here finsh_thread After the thread is awakened, it passes through the front face setction(x) Assemble the code segment specified by the instruction to query , If a user-defined function is defined, it can be parsed through , such as finsh_node_new_id(id) Medium id Function function led. If the input command syntax is parsed again, there is no problem , Next, run the compilation function to compile all the nodes on the syntax tree , Then virtual machine finsh_vm_run() Call this command . /* compile node root */
if (finsh_errno() == 0)
{
finsh_compiler_run(parser->root);
}
else
{
err_str = finsh_error_string(finsh_errno());
rt_kprintf("%s\n", err_str);
}
/* run virtual machine */
if (finsh_errno() == 0)
{
char ch;
finsh_vm_run();
With the above right led Command awareness , Now we can see what we care about spi flash Commands for file system operation mkfs Waiting for the relevant orders .
【3】 File system operation command
(1) mkdfs command , Search globally in the system , You can go to dfs_fs.c Of documents 492 Line can be found led Command like macros :
#ifdef RT_USING_FINSH
#include <finsh.h>
void mkfs(const char *fs_name, const char *device_name)
{
dfs_mkfs(fs_name, device_name);
}
FINSH_FUNCTION_EXPORT(mkfs, make a file system);
similarly ,mkdir,copy,rm And other commands are imported in the same way finsh_thread In thread . Input in the terminal list_device() command , It is shown as follows :
finsh />list_device()
device type
-------- ----------
flash0 Block Device
spi12 SPI Device
spi11 SPI Device
spi1 SPI Bus
uart3 Character Device
uart2 Character Device
uart1 Character Device
0, 0x00000000
finsh />
finsh />mkfs("elm","flash0")
0, 0x00000000
finsh />
Obviously, the format succeeded , But why can't I mount successfully ? When debugging tracks ff.c Of documents 1986 Line time ,return 2 The conditions of , The system cannot be mounted , So refer to netizens About SPI flash Of elm file system It suddenly occurred to me after my post that the chip may not support , Therefore, the SST25VF016B Replace with 25Q64FV, Then change the underlying driver code to :
/* JEDEC Manufacturer¡¯s ID */
#define MF_ID (0xEF)... ...
/*else if(memory_type_capacity == MTC_SST25VF016B)
{
FLASH_TRACE("SST25VF016B detection\r\n");
spi_flash_device.geometry.sector_count = 512;
}*/
else
{
FLASH_TRACE("Memory Capacity error!\r\n");
return -RT_ENOSYS;
}
}Then recompile and download , The first boot still failed to mount , Execute at the terminal mkfs("elm","flash0") The display is formatted successfully , After reset, it shows that the mount is successful , It is shown as follows :
\ | /
- RT - Thread Operating System
/ | \ 1.2.2 build Mar 31 2015
2006 - 2013 Copyright by rt-thread team
W25Q64BV or W25Q64CV detection
finsh />flash0 mount to /.
Trace again ff.c Of documents 1986 Line time ,return 2 The condition of , It doesn't work .
Look at the flash Space
disk free: 8168 KB [ 2042 block, 4096 bytes per block ]
0, 0x00000000
finsh />
【4】 File system testing
stay rt-thread-1.2.2/examples/test Files can be found in the directory fs_test.c, Copy to the current branch drivers Under the table of contents , Then join in MDK engineering Drivers In the group , modify drivers In the catalog Sconscript Script , give the result as follows :
# add DFS drvers.
if GetDepend('RT_USING_DFS'):
src += ['rt_spi_device.c','rt_stm32f10x_spi.c','spi_flash_w25qxx.c','fs_test.c']
Save after modification .
open fs_test.c file , Separate 64 That's ok ,66 That's ok ,79 That's ok ,96 That's ok ,122 Yes 8000 Replace with 10, Too many times to read and write , Time consuming . And then in the thread while(1) At the end of close(fd) Add the following code below :
/* close file */
close(fd);
if(round >10) return;
} Separate 173 That's ok ,175 That's ok ,188 That's ok ,205 That's ok ,231 Yes 5000 Replace with 10, It's the same thing while(1) At the end of close(fd) Now add the above code . The purpose is to make these two threads run 10round After exit . Then save Compile and download , Use in the terminal after resetting list() Command to check : finsh />list()
--Function List:
led -- set led[0 - 1] on[1] or off[0].
fs_test -- file system R/W test. e.g: fs_test(3)
list_mem -- list memory usage information
mkfs -- make a file system
df -- get disk free
ls -- list directory contents
... ...
You can see fs_test The command appears in the list , Now you can call this command to test :
finsh />fs_test(3)
arg is : 0x03 0, 0x00000000
finsh />thread fsrw1 round 1 rd:40000byte/s,wr:5217byte/s
thread fsrw2 round 1 rd:60000byte/s,wr:180000byte/s
thread fsrw1 round 2 rd:40000byte/s,wr:3428byte/s
thread fsrw2 round 2 rd:60000byte/s,wr:5806byte/s
thread fsrw1 round 3 rd:5454byte/s,wr:3333byte/s
thread fsrw2 round 3 rd:7200byte/s,wr:6000byte/s
thread fsrw1 round 4 rd:4615byte/s,wr:60000byte/s
thread fsrw2 round 4 rd:45000byte/s,wr:45000byte/s
thread fsrw1 round 5 rd:5000byte/s,wr:30000byte/s
thread fsrw2 round 5 rd:6923byte/s,wr:45000byte/s
thread fsrw1 round 6 rd:40000byte/s,wr:40000byte/s
thread fsrw2 round 6 rd:7200byte/s,wr:60000byte/s
thread fsrw1 round 7 rd:40000byte/s,wr:40000byte/s
thread fsrw2 round 7 rd:7200byte/s,wr:60000byte/s
thread fsrw1 round 8 rd:40000byte/s,wr:40000byte/s
thread fsrw2 round 8 rd:7200byte/s,wr:60000byte/s
thread fsrw1 round 9 rd:4800byte/s,wr:30000byte/s
thread fsrw2 round 9 rd:7500byte/s,wr:45000byte/s
thread fsrw1 round 10 rd:4800byte/s,wr:30000byte/s
thread fsrw2 round 10 rd:90000byte/s,wr:60000byte/s
finsh />
You can see that the file is read and written successfully . Look at these two test files under the root directory :
finsh />ls("/")
Directory /:
TEST1.DAT 1200
TEST2.DAT 1800
0, 0x00000000
finsh />
Here we are , We have successfully opened the development board based on SPI Flash Of ELM FATFS file system .
边栏推荐
- 第4期:大学生提前职业技能准备之一
- el-table实现可编辑表格
- .net operation redis sorted set ordered set
- router.push(),router.repalce(),router.go()使用
- 反射机制简述
- kali 查看ip地址
- Flutter集成极光推送
- Flutter jni混淆 引入.so文件release包闪退
- Error[pe147]: declaration is incompatible with 'error problem
- Codepoint 58880 not found in font, aborting. flutter build apk时报错
猜你喜欢

在altium designer中禁用USBJATG

RT-Thread 学习笔记(七)---开启基于SPI Flash的elmfat文件系统(中)

Problems encountered in QRcode QR code (C language)

Flutter编译报错 version of NDK matched the requested version 21.0.6113669. Versions available locally: 2
![[leetcode每日一题2021/2/18]【详解】995. K 连续位的最小翻转次数](/img/de/62fca587cde95110c2a967ca93eea5.png)
[leetcode每日一题2021/2/18]【详解】995. K 连续位的最小翻转次数

RT-Thread 学习笔记(五)---编辑、下载、调试程序

Redis docker instance and data structure

The problem of large fluctuation of hx711 data
![[dectectron2] follow the official demo](/img/aa/03e46897234c309415b336ac39b7d9.png)
[dectectron2] follow the official demo

kali 查看ip地址
随机推荐
剑指Offer(五):用两个栈实现队列
kali 查看ip地址
在altium designer中禁用USBJATG
Flutter jni混淆 引入.so文件release包闪退
多目标优化系列1---NSGA2的非支配排序函数的讲解
The problem of formatting IAR sprintf floating point to 0.0 in UCOS assembly
The problem of large fluctuation of hx711 data
RT-Thread 学习笔记(八)---开启基于SPI Flash的elmfat文件系统(下)
使用flex实现左中右布局,中间自适应
使用Geoprocessor 工具
使用grid实现左中右布局,中间内容自适应
[leetcode每日一题2021/4/23]368. 最大整除子集
工厂模式详解
[leetcode daily question 2021/4/29]403. Frogs cross the river
Happens-Before原则深入解读
[leetcode daily question 2021/8/30]528. Choose randomly by weight [medium]
Flutter 防止科学计数并去除尾数无效0
Application of.Net open source framework in industrial production
Koin
Problems encountered in QRcode QR code (C language)