rt-thread 下,配置 stm32 的 虚拟串口

参考这里

步骤

cubeMX

1
2
3
4
5
打开 cubeMX,开启 USB_OTG, 使用 device 模式,启用 usb otg 的全局中断,配置时钟,生成代码,复制到项目

注意,cubeMX 里面配置的时候,rcc 需要启用 hse,外部晶震,usb 的时钟需要设置为 48MHZ,我是 F411CEU6 的板

复制 main.c 里面的时钟配置到 board.c

Kconfig

1
2
3
4
5
config BSP_USING_USBD_FS
bool "Enable OTGFS as USB device"
select RT_USING_USB_DEVICE
select _RT_USB_DEVICE_CDC
default n
1
2
3
4
5
6
7
8
9
Hardware Drivers Config >
On-chip Peripheral Drivers
[*] Enable OTGFS as USB device

RT-Thread Components >
Device Drivers >
Using USB >
[*] Enable composite device >
[*] Enable to use device as CDC device

测试代码

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
#include <rtthread.h>
#include <rtdevice.h>

int vcom_test(void)
{
rt_device_t dev = RT_NULL;
char buf[] = "hello vcom!\r\n";

dev = rt_device_find("vcom");

if (dev)
rt_device_open(dev, RT_DEVICE_FLAG_RDWR);
else
return -RT_ERROR;

while (1)
{
rt_device_write(dev, 0, buf, rt_strlen(buf));
rt_thread_mdelay(500);
}

rt_device_close(dev);
}

MSH_CMD_EXPORT(vcom_test, vcom_test)

rt-thread 下,配置 stm32 的 lfs

外挂 flash 上使用 lfs

参考的 这里

配置

准备

先按照外挂 flash 的配置配置好

1
2
3
4
5
6
7
8
9
10
11
RT-Thread Components ---> Device virtual file system
[*] Using device virtual file system

RT-Thread online packages > system packages > Littlefs: A high-integrity embedded file system
[*] Littlefs: A high-integrity embedded file system
(256) disk read size
(256) disk write size
(4096) disk block size
(256) lfs r/w cache size
(100) lfs enables wear leveling. 0 is disable.
(512) lfs lookahead size

代码

w25q128_lfs_demo.c

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
#include <fal.h>
#include <dfs_fs.h>
#include <rtdbg.h>

/*
[I/FAL] ==================== FAL partition table ====================
[I/FAL] | name | flash_dev | offset | length |
[I/FAL] -------------------------------------------------------------
[I/FAL] | filesystem | W25Q128 | 0x00000000 | 0x01000000 |
*/

#define FS_PARTITION_NAME "filesystem"
#define FS_DEVICE_NAME FS_PARTITION_NAME

int w25q128_lfs_demo(void)
{
fal_init();

struct rt_device* mtd_dev = RT_NULL;
mtd_dev = fal_mtd_nor_device_create(FS_PARTITION_NAME);
if ( !mtd_dev ){
LOG_E("Can't create a mtd device on '%s' partition.", FS_PARTITION_NAME);
}
else{
// 以防万一,先unmount
dfs_unmount("/");

if (dfs_mount(FS_DEVICE_NAME, "/", "lfs", 0, 0) == 0){
LOG_I("Filesystem initialized!");
}
else{
// mkfs -t lfs filesystem
dfs_mkfs("lfs", FS_DEVICE_NAME);

if (dfs_mount(FS_DEVICE_NAME, "/", "lfs", 0, 0) == 0){
LOG_I("Filesystem initialized!");
}
else{
LOG_E("Failed to initialize filesystem!");
}
}
}

return RT_EOK;
}

MSH_CMD_EXPORT(w25q128_lfs_demo, w25q128_lfs_demo);

注意

demo 代码里面的dfs_mountdfs_mkfs的参数,DEVICE_NAME, lfs 和 elm 是不一样的

rt-thread 下,配置 stm32 的 elmfs

elm 文件系统

说明

外挂 flash 上的 elm 文件系统

参考的 这里

配置

准备

先按照外挂 flash 的配置配置好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
RT-Thread Components > Device virtual file system  --->
-*- Using device virtual file system
[*] Using working directory
(2) The maximal number of mounted file system
(2) The maximal number of file system type
(16) The maximal number of opened files
[*] Enable elm-chan fatfs
elm-chan's FatFs, Generic FAT Filesystem Module --->
Support long file name (3: LFN with dynamic LFN working buffer on the heap) --->
(X) 3: LFN with dynamic LFN working buffer on the heap
(4096) Maximum sector size to be handled.
[*] Enable sector erase feature

RT-Thread Components > POSIX layer and C standard library
[*] Enable libc APIs from toolchain

代码

w25q128_elmfs_demo.c

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
#include <fal.h>
#include <dfs_fs.h>
#include <rtdbg.h>

/*
[I/FAL] ==================== FAL partition table ====================
[I/FAL] | name | flash_dev | offset | length |
[I/FAL] -------------------------------------------------------------
[I/FAL] | filesystem | W25Q128 | 0x00000000 | 0x01000000 |
*/

#define FS_PARTITION_NAME "filesystem"
#define FS_DEVICE_NAME "W25Q128"

int w25q128_elmfs_demo(void)
{
fal_init();

struct rt_device* mtd_dev = RT_NULL;
mtd_dev = fal_mtd_nor_device_create(FS_PARTITION_NAME);
if ( !mtd_dev ){
LOG_E("Can't create a mtd device on '%s' partition.", FS_PARTITION_NAME);
}
else{
// 以防万一,先unmount
dfs_unmount("/");

if (dfs_mount(FS_DEVICE_NAME, "/", "elm", 0, 0) == 0){
LOG_I("Filesystem initialized!");
}
else{
// mkfs -t elm W25Q128
dfs_mkfs("elm", FS_DEVICE_NAME);

if (dfs_mount(FS_DEVICE_NAME, "/", "elm", 0, 0) == 0){
LOG_I("Filesystem initialized!");
}
else{
LOG_E("Failed to initialize filesystem!");
}
}
}

return RT_EOK;
}

MSH_CMD_EXPORT(w25q128_elmfs_demo, w25q128_elmfs_demo);

注意

demo 代码里面的 dfs_mountdfs_mkfs 的参数,DEVICE_NAME, lfs 和 elm 是不一样的

建议

4096 扇区,挂载成 FAT,要格式化成功,至少要 800KB 以上。且还要修改格式化参数。

所以建议 4MB 以下的 FLASH 不要用 FAT,用 littlefs

rtt-stm32-at-socket

参考链接

配置

先启用 uart2

软件包

开启 at device 的支持

1
2
3
4
RT-Thread online packages >
IoT - internet of things >
AT DEVICE: RT-Thread AT component porting or samples for different device
[*] Espressif ESP8266 --->

配置参数

1
2
缓冲区大小可以设置大一点
配置使用 laster 版本软件包;

驱动部分

1
2
3
4
5
6
7
8
9
10
11
12
RT-Thread Components
Network
Socket abstraction layer
protocol stack implement
[*]Support AT Commands stack
[*]Enable BSD socket operated by the file system API
Enable AT commands
-*- Enable AT commands client
-*- Enable BSD Socket API support by AT commnads
# 这里是选择显示at命令日志
[ ] Enable print RAW format AT command communication data
(128) The maximum lenght of AT Commonds buffer

调试

使用 cutecom 连接,回车模式选择 CR/LF

1
2
3
4
5
AT+CWMODE=1
AT+CWJAP="ssid","password"
AT+CIFSR

AT+RST

注意

  • 模块串口和开发板的串口反接
  • 注意供电, wifi 芯片功耗很大,vcc 要接 5v,如果提示 wait AT client(uart2) connect timeout(5000 tick),可能是 vcc 供电不足,可以换一个 5v 的供电口解决
  • 模块如果使用杜邦线接线,用短的,长的可能会出现很多奇怪的问题
  • 如果提示缓冲区不够,可以使用串口调试器(cutecom)先调试 at 指令,很可能是不同的模块里面,在某些非正常时刻,发出太多的 response 导致的,可以看情况修改调用 at_create_resp 函数的地方针对性的修改缓冲区大小
1
2
比如 [E/at.clnt] Read response buffer failed. The Response buffer size is out of buffer size(xxx)
可以在 at.client.c 的 at_create_resp 函数上下断点观察流程,尝试把缓冲区都改大一点

如果还有解决不了的问题,看这里

rt-thread 下,配置 stm32 的 LAN8720A 网卡

配置 LAN8720A 接入网络

参考链接

cubeMX 配置

启用 Eth 模块

1
2
选择 RMII
对比实际板的原理图,修改引脚位置,注意rst引脚的位置

项目配置

修改 ports/phy_reset.c 内 rst 引脚位置, 复制 ports 目录到 board 下,修改 SConscript

1
2
3
4
path += [cwd + '/ports']

if GetDepend(['BSP_USING_ETH']):
src += Glob('ports/phy_reset.c')

board/Kconfig 配置

Kconfig 里面,menu “Onboard Peripheral Drivers”内添加

1
2
3
4
5
6
7
config PHY_USING_LAN8720A
bool
config BSP_USING_ETH
bool "Enable Ethernet"
default n
select RT_USING_LWIP
select PHY_USING_LAN8720A
1
2
3
4
5
6
7
8
RT-Thread Components >
Network >
Socket abstraction layer
[*] Enable socket abstraction layer
[*] Enable BSD socket operated by file system API
light weight TCP/IP stack
[] Enable alloc ip address through DHCP
[*] Enable lwIP stack

light weight TCP/IP stack里面, 选项 Enable alloc ip address through DHCP来控制 dhcp 或者固定 ip

打开调试开关

libraries/HAL_Drivers/drv_eth.c

1
2
3
#define ETH_RX_DUMP
#define ETH_TX_DUMP
#define DRV_DEBUG

相关代码

phy_reset.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <board.h>

#define RESET_IO GET_PIN(H, 2)

void phy_reset(void)
{
rt_pin_write(RESET_IO, PIN_LOW);
rt_thread_mdelay(50);
rt_pin_write(RESET_IO, PIN_HIGH);
}

int phy_init(void)
{
rt_pin_mode(RESET_IO, PIN_MODE_OUTPUT);
rt_pin_write(RESET_IO, PIN_HIGH);
return RT_EOK;
}
INIT_BOARD_EXPORT(phy_init);

rt-thread 下,配置 stm32 的 w5500 网卡

配置 w5500 网卡接入网络

物理接线

cubeMX 里面的 nss 脚貌似不需要接,cubeMX 里面的 sck 脚是对应模块的 sclk 脚

模块的 scs 脚接的位置就是, rt_hw_spi_device_attach 的最后两个参数的值

开发板和模块之间的 MISO 和 MOSI 不需要反接

cubeMX 配置

启用 spi1

设置 Mode 为 Full Duplex Master

设置 Hardware NSS Signal 为 output 模式

参考驱动配置,在 board/Kconfig 里面启用 spi1 的配置

配置 iot packages 里面的 wiznet 部分

1
2
3
4
5
6
7
RT-Thread online packages --->
IoT - internet of things --->
WIZnet: WIZnet TCP/IP chips SAL framework imlement --->
WIZnet device configure
(spi10) SPI device name
(10) Reset PIN number (NEW)
(11) IRQ PIN number (NEW)

参数说明

1
2
3
SPI device name 不是 spi 的总线名,需要手工创建,比如 spi10
设置 Reset PIN number
设置IRQ PIN number,也就是模块上的int引脚

编写 spi 初始化代码

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>

static int w5500_spi_init(void)
{
__HAL_RCC_GPIOA_CLK_ENABLE();

// 最后两个参数是spi模块scs引脚的位置
return rt_hw_spi_device_attach("spi1", "spi10", GPIOA, GPIO_PIN_4);
}
/* 导出到自动初始化 */
INIT_COMPONENT_EXPORT(w5500_spi_init);

重连测试

测试模拟:开机断网,中间断网,重连以后,看到 W5500 提示 link up 以后,可以 ping 通其他主机

无论 dhcp 模式打开还是关闭,均支持。

rt-thread 下,配置 stm32 的外挂 flash

外挂 flash 读写
参考这里

配置

cubeMX

根据原理图,找到相应的 spi 脚,配置引脚

Kconfig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
menuconfig BSP_USING_SPI
bool "Enable SPI BUS"
default n
select RT_USING_SPI
if BSP_USING_SPI
config BSP_USING_SPI2
bool "Enable SPI2 BUS"
default n

config BSP_SPI2_TX_USING_DMA
bool "Enable SPI2 TX DMA"
depends on BSP_USING_SPI2
default n

config BSP_SPI2_RX_USING_DMA
bool "Enable SPI1 RX DMA"
depends on BSP_USING_SPI2
select BSP_SPI2_TX_USING_DMA
default n
endif

Kconfig 的 "Onboard Peripheral Drivers" 添加

1
2
3
4
5
6
config BSP_USING_QSPI_FLASH
bool "Enable QSPI FLASH (W25Q128 spi10)"
select BSP_USING_QSPI
select RT_USING_SFUD
select RT_SFUD_USING_QSPI
default n
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
Hardware Drivers Config > Onboard Peripheral Drivers
[*] Enable QSPI FLASH (W25Q128 spi10)

RT-Thread Components > Device Drivers
[*] Using MTD Nor Flash device drivers

RT-Thread online packages >
system packages >
[*] fal: Flash Abstraction Layer implement. Manage flash device and partition. --->
(W25Q128) The name of the device used by FAL
这是 SFUD 初始化 flash 后创建的设备名

Hardware Drivers Config > On-chip Peripheral Drivers > Enable SPI BUS
[*] Enable SPI BUS --->
[*] Enable SPI2 BUS
-*- Enable SPI2 TX DMA
[*] Enable SPI1 RX DMA

RT-Thread Components > Device Drivers
[*] Using SPI Bus/Device device drivers
-*- Enable QSPI mode
-*- Using Serial Flash Universal Driver
[*] Using auto probe flash JEDEC SFDP parameter
[*] Using defined supported flash chip information table
-*- Using QSPI mode support
(50000000) Default spi maximum speed(HZ)

代码

fal_cfg.h

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
#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_

#include <rtthread.h>
#include <board.h>

#if defined(BSP_USING_ON_CHIP_FLASH)
extern const struct fal_flash_dev stm32_onchip_flash;
#endif /* BSP_USING_ON_CHIP_FLASH */

#if defined(BSP_USING_QSPI_FLASH)
extern struct fal_flash_dev nor_flash0;
#endif /* BSP_USING_QSPI_FLASH */

/* ========================= Device Configuration ========================== */
#ifdef BSP_USING_ON_CHIP_FLASH
#define ONCHIP_FLASH_DEV &stm32_onchip_flash,
#else
#define ONCHIP_FLASH_DEV
#endif /* BSP_USING_ON_CHIP_FLASH */

#ifdef BSP_USING_QSPI_FLASH
#define SPI_FLASH_DEV &nor_flash0,
#else
#define SPI_FLASH_DEV
#endif /* BSP_USING_QSPI_FLASH */

/* flash device table */
#define FAL_FLASH_DEV_TABLE \
{ \
ONCHIP_FLASH_DEV \
SPI_FLASH_DEV \
}

/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG

#ifdef BSP_USING_ON_CHIP_FLASH
#define ONCHIP_FLASH_PATITION {FAL_PART_MAGIC_WROD, "app", "onchip_flash", 0, 496 * 1024, 0}, \
{FAL_PART_MAGIC_WROD, "param", "onchip_flash", 496* 1024, 16 * 1024, 0},
#else
#define ONCHIP_FLASH_PATITION
#endif

#ifdef BSP_USING_QSPI_FLASH
#define SPI_FLASH_PARTITION {FAL_PART_MAGIC_WROD, "filesystem", "W25Q128", 9 * 1024 * 1024, 16 * 1024 * 1024, 0},
#else
#define SPI_FLASH_PARTITION
#endif

/* partition table */
#define FAL_PART_TABLE \
{ \
ONCHIP_FLASH_PATITION \
SPI_FLASH_PARTITION \
}
#endif /* FAL_PART_HAS_TABLE_CFG */

#endif /* _FAL_CFG_H_ */

w25q128_auto_init.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>

static int w25q128_auto_init(void)
{
__HAL_RCC_GPIOB_CLK_ENABLE();

// 最后俩参数是spi接口的cs脚
rt_hw_spi_device_attach("spi2", "spi10", GPIOI, GPIO_PIN_0);

if (RT_NULL == rt_sfud_flash_probe("W25Q128", "spi10"))
{
return -RT_ERROR;
};

return RT_EOK;
}
/* 导出到自动初始化 */
INIT_COMPONENT_EXPORT(w25q128_auto_init);

w25q128_flash_demo.c

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
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include <sfud.h>

#define SPI_FLASH_DEVICE_NAME "spi10"

void w25q128_flash_demo(void)
{
sfud_err result;
uint8_t* read_data;
uint8_t* write_data;
sfud_flash* sfud_dev = NULL;

sfud_dev = rt_sfud_flash_find(SPI_FLASH_DEVICE_NAME);
// 或者 sfud_dev = rt_sfud_flash_find_by_dev_name("W25Q128");

sfud_erase(sfud_dev, 0, 4096);

write_data = rt_malloc(32);
rt_memset(write_data, 3, 32);
sfud_write(sfud_dev, 0, 32, write_data);

read_data = rt_malloc(32);
sfud_read(sfud_dev, 0, 32, read_data);

rt_kprintf("please run cmd to check result\r\n");
rt_kprintf("sf probe %s\r\n", SPI_FLASH_DEVICE_NAME);
rt_kprintf("sf read 0 32\r\n");
}

MSH_CMD_EXPORT(w25q128_flash_demo, w25q128_flash_demo);

测试

1
2
3
4
5
6
7
8
9
msh />list_device
device type ref count
-------- -------------------- ----------
W25Q128 Block Device 0
spi10 SPI Device 0
e0 Network Interface 0
spi2 SPI Bus 0
uart1 Character Device 2
pin Miscellaneous Device 0
1
2
3
4
msh />sf probe spi10
msh />sf erase 0 10
msh />sf read 0 10
msh />sf bench yes

注意

Flash 先擦后写
写入之前请先擦除,这是 flash 特性决定的,因为 flash 的编程原理就是只能将 1 写为 0,而不能将 0 写为 1。擦除动作就是相应的页 / 块的所有位变为 1(所有字节均为 0xFF),所以不擦除直接写入会有问题。

rt-thread 下,配置 stm32 片上 flash 读写

片上 flash 读写,这里介绍 FAL 的用法

准备工作

FAL 准备

board/Kconfig 添加

1
2
3
config BSP_USING_ON_CHIP_FLASH
bool "Enable on-chip FLASH"
default n

启用 fal

1
2
3
4
RT-Thread online packages --->
system packages --->
[*]fal: Flash Abstraction Layer implement. Manage flash device and partition. --->
启用fal,如果只考虑片上flash的话,SFUD不要勾选

on_chip_flash 目录复制到你的 applications 目录

SConscript 添加如下

1
2
3
4
5
6
CPPPATH += [cwd + '/on_chip_flash']

on_chip_flash/romfs_init.c
on_chip_flash/fal_demo.c
on_chip_flash/lfs_demo.c
on_chip_flash/elm_demo.c

测试命令

1
2
3
fal probe xxx
fal read 0 10
fal write xxx

lfs 准备

scons --menuconfig 选中

1
2
3
4
5
6
7
RT-Thread Components --->
Device virtual file system
[*] Using device virtual file system
注意,以下参数,尽量设置大一些:
the maximal number of mounted file system
the maximal number of file system type
the maximal number of opened files
1
2
3
RT-Thread Components --->
Device Drivers --->
[*] Using MTD Nor Flash device drivers
1
2
3
RT-Thread Components --->
POSIX layer and C standard library --->
[*] Enable libc APIs from toolchain
1
2
3
4
5
6
RT-Thread online packages --->
system packages --->
[*] Littlefs: A high-integrity embedded file system ---->
注意:
disk block size 是扇区大小
lfs enable wear leveling. 0 is disable,这个设置为 100,为 0 有时候会崩

需要注意的地方

1
2
3
需要根据你需要的大小修改rtt自带驱动里面的`const struct fal_flash_dev stm32_onchip_flash_xxk`
驱动的相对路径为 `libraries/HAL_Drivers/drv_flash/drv_flash_f4.c`
这个结构体里面的blk_size为扇区大小,建议改成 `2048` 或者 `4096`

romfs 准备

使用场景:如果需要挂载多个 fs,可以使用 romfs 先创建几个文件夹,然后启动以后把几个 fs 分别挂载到不同的目录

1
2
3
4
RT-Thread Components --->
Device virtual file system
[*] Using device virtual file system
[*] Enable ReadOnly file system on flash

注意,需要使用下面的命令重新生成 romfs 的源码

1
python2 ./rt-thread/tools/mkromfs.py 你的文件目录 ./rt-thread/components/dfs/filesystems/romfs/romfs.c

代码

elm_demo.c

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
#include <dfs_fs.h>
#include <fal.h>
#include <rtdbg.h>

/*
[I/FAL] ==================== FAL partition table ====================
[I/FAL] | name | flash_dev | offset | length |
[I/FAL] -------------------------------------------------------------
[I/FAL] | elmfs | onchip_flash_64k | 0x00000000 | 0x00010000 |
[I/FAL] | lfs | onchip_flash_64k | 0x00010000 | 0x00010000 |
[I/FAL] | fal_onchip | onchip_flash_64k | 0x00020000 | 0x00010000 |
[I/FAL] | filesystem | W25Q128 | 0x00900000 | 0x01000000 |
[I/FAL] =============================================================
*/

#define ELM_FS_MOUNT_POINT "/"
#define ELM_FS_PARTITION_NAME "elmfs"

// fal_blk_device_create 会创建一个和分区名一样的device
#define FS_DEVICE_NAME ELM_FS_PARTITION_NAME

int elm_demo(void)
{
fal_init();

rt_device_t mtd_dev = RT_NULL;
if ( rt_device_find(ELM_FS_PARTITION_NAME) == RT_NULL){
mtd_dev = fal_blk_device_create(ELM_FS_PARTITION_NAME);
if (!mtd_dev){
LOG_E("Can't create a block device on '%s' partition.", ELM_FS_PARTITION_NAME);
}
}

dfs_unmount("/");

if (dfs_mount(FS_DEVICE_NAME, ELM_FS_MOUNT_POINT, "elm", 0, 0) == 0){
LOG_W("Filesystem initialized!");
}
else{
LOG_W("%s not formatted, now formatting", ELM_FS_PARTITION_NAME);
dfs_mkfs("elm", FS_DEVICE_NAME);

if ( dfs_mount(FS_DEVICE_NAME, ELM_FS_MOUNT_POINT, "elm", 0, 0) == 0 ){
LOG_W("Filesystem initialized!");
}
else{
LOG_E("Failed to initialize filesystem!");
}
}

return RT_EOK;
}
/*
mkfs -t elm elmfs
最后一个参数为通过 fal_blk_device_create 创建出来的 block device
*/
MSH_CMD_EXPORT(elm_demo, elm_demo);

fal_cfg.h

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
#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_

#include <rtthread.h>
#include <board.h>

// 片上flash的编译需要
// 定义分区大小,暂时只看64k
#define PARTITION_SIZE 64

//起始地址
#define STM32_FLASH_START_ADRESS_64K (STM32_FLASH_END_ADDRESS - PARTITION_SIZE*3*1024)

//分区长度
#define FLASH_SIZE_GRANULARITY_64K 64*3*1024

// 这些必须要定义,否则编译错误
#define STM32_FLASH_START_ADRESS_16K STM32_FLASH_START_ADRESS
#define STM32_FLASH_START_ADRESS_128K STM32_FLASH_START_ADRESS

#define FLASH_SIZE_GRANULARITY_16K 16*1024
#define FLASH_SIZE_GRANULARITY_128K 128*1024
// ---------------------

// F4系列得用这个64k的
#if defined(BSP_USING_ON_CHIP_FLASH)
extern const struct fal_flash_dev stm32_onchip_flash_64k;
#endif /* BSP_USING_ON_CHIP_FLASH */

#if defined(BSP_USING_QSPI_FLASH)
extern struct fal_flash_dev nor_flash0;
#endif /* BSP_USING_QSPI_FLASH */

/* ========================= Device Configuration ========================== */
#ifdef BSP_USING_ON_CHIP_FLASH
#define ONCHIP_FLASH_DEV &stm32_onchip_flash_64k,
#else
#define ONCHIP_FLASH_DEV
#endif /* BSP_USING_ON_CHIP_FLASH */

#ifdef BSP_USING_QSPI_FLASH
#define SPI_FLASH_DEV &nor_flash0,
#else
#define SPI_FLASH_DEV
#endif /* BSP_USING_QSPI_FLASH */

/* flash device table */
#define FAL_FLASH_DEV_TABLE \
{ \
ONCHIP_FLASH_DEV \
SPI_FLASH_DEV \
}

/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG

// 片上flash的设备名onchip_flash_64k是驱动里面定义好的,不能随便改
#ifdef BSP_USING_ON_CHIP_FLASH
#define ONCHIP_FLASH_PATITION {FAL_PART_MAGIC_WROD, "elmfs", "onchip_flash_64k", 0, 64 * 1024, 0}, \
{FAL_PART_MAGIC_WROD, "lfs", "onchip_flash_64k", 64* 1024, 64 * 1024, 0}, \
{FAL_PART_MAGIC_WROD, "fal_onchip", "onchip_flash_64k", 128* 1024, 64 * 1024, 0},
#else
#define ONCHIP_FLASH_PATITION
#endif

#ifdef BSP_USING_QSPI_FLASH
#define SPI_FLASH_PARTITION {FAL_PART_MAGIC_WROD, "filesystem", "W25Q128", 9 * 1024 * 1024, 16 * 1024 * 1024, 0},
#else
#define SPI_FLASH_PARTITION
#endif

/* partition table */
#define FAL_PART_TABLE \
{ \
ONCHIP_FLASH_PATITION \
SPI_FLASH_PARTITION \
}
#endif /* FAL_PART_HAS_TABLE_CFG */

#endif /* _FAL_CFG_H_ */

fal_demo.c

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
#include <fal.h>
#include <rtdbg.h>

/*
[I/FAL] ==================== FAL partition table ====================
[I/FAL] | name | flash_dev | offset | length |
[I/FAL] -------------------------------------------------------------
[I/FAL] | elmfs | onchip_flash_64k | 0x00000000 | 0x00010000 |
[I/FAL] | lfs | onchip_flash_64k | 0x00010000 | 0x00010000 |
[I/FAL] | fal_onchip | onchip_flash_64k | 0x00020000 | 0x00010000 |
[I/FAL] | filesystem | W25Q128 | 0x00900000 | 0x01000000 |
[I/FAL] =============================================================
*/

#define DEMO_FLASH_PARTITION_NAME "fal_onchip"

int fal_demo(void)
{
fal_init();

const struct fal_partition* partition = fal_partition_find(DEMO_FLASH_PARTITION_NAME);

fal_partition_erase(partition, 0x4, 2);

char data_to_save[] = {0xa, 0xb};
fal_partition_write(partition, 0x4, data_to_save, sizeof(data_to_save));

// char data_to_read[2] = {0};
// fal_partition_read(partition, 0x4, data_to_read, sizeof(data_to_read));

// char hex_str_data_array[2] = {0};
// hex_to_str(data_to_read, sizeof(data_to_read), hex_str_data_array);
// rt_kprintf("data :%s\n", hex_str_data_array);

rt_kprintf("please run cmd to check result\r\n");
rt_kprintf("fal probe %s\r\n", DEMO_FLASH_PARTITION_NAME);
rt_kprintf("fal read 4 2\r\n");

return RT_EOK;
}

MSH_CMD_EXPORT(fal_demo, fal_demo);

lfs_demo.c

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
#include <dfs_fs.h>
#include <fal.h>
#include <rtdbg.h>

/*
[I/FAL] ==================== FAL partition table ====================
[I/FAL] | name | flash_dev | offset | length |
[I/FAL] -------------------------------------------------------------
[I/FAL] | elmfs | onchip_flash_64k | 0x00000000 | 0x00010000 |
[I/FAL] | lfs | onchip_flash_64k | 0x00010000 | 0x00010000 |
[I/FAL] | fal_onchip | onchip_flash_64k | 0x00020000 | 0x00010000 |
[I/FAL] | filesystem | W25Q128 | 0x00900000 | 0x01000000 |
[I/FAL] =============================================================
*/

#define LFS_MOUNT_POINT "/"
#define LFS_PARTITION_NAME "lfs"
#define FS_DEVICE_NAME LFS_PARTITION_NAME

int lfs_demo(void)
{
fal_init();

// 创建mtd设备,list_device能看到
rt_device_t mtd_dev = RT_NULL;

if ( rt_device_find(LFS_PARTITION_NAME) == RT_NULL){
mtd_dev = fal_mtd_nor_device_create(LFS_PARTITION_NAME);
if (!mtd_dev){
LOG_E("Can't create a mtd device on '%s' partition.", LFS_PARTITION_NAME);
}
}

dfs_unmount("/");

if (dfs_mount(FS_DEVICE_NAME, LFS_MOUNT_POINT, "lfs", 0, 0) == 0){
LOG_W("Filesystem initialized!");
}
else{
LOG_W("%s not formatted, now formatting", LFS_PARTITION_NAME);
dfs_mkfs("lfs", FS_DEVICE_NAME);

if ( dfs_mount(FS_DEVICE_NAME, LFS_MOUNT_POINT, "lfs", 0, 0) == 0 ){
LOG_W("Filesystem initialized!");
}
else{
LOG_E("Failed to initialize filesystem!");
}
}

return RT_EOK;
}

/*
mkfs -t lfs lfs
最后一个参数为通过 fal_blk_device_create 创建出来的 block device
*/
MSH_CMD_EXPORT(lfs_demo, lfs_demo);

romfs_init.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <dfs_fs.h>
#include <rtdbg.h>

extern const struct romfs_dirent romfs_root;
#define DFS_ROMFS_ROOT (&romfs_root)

int romfs_init(void)
{
/* mount ROMFS as root directory */
if (dfs_mount( RT_NULL, "/", "rom", 0, (const void *)DFS_ROMFS_ROOT) == 0)
{
rt_kprintf("ROMFS File System initialized!\n");
}
else
{
rt_kprintf("ROMFS File System initialized Failed!\n");
}

return RT_EOK;
}

INIT_ENV_EXPORT(romfs_init);

注意

已知的问题:在某些板子上,fal 和 lfs 不兼容,同时启用以后,会导致 fal 的 erase 挂掉,当然 lfs 的格式化也会挂掉

elm 貌似格式化会报错,不管了

rt-thread 下,配置 stm32 的 u 盘

当成 u 盘

单片机作为 u 盘

打开 usb

1
2
3
4
5
打开 cubeMX,配置 USB_OTG, 使用 host_device 模式,nvic interrupt table 配置 usb on the go fs global interrupt, 生成代码,复制到项目

cubeMX 里面配置的时候,rcc 需要启用 hse,外部晶震,usb 的时钟需要设置为 48MHZ

复制 main.c 里面的时钟配置到 board.c

修改 board/Kconfig,添加

1
2
3
4
config BSP_USING_USBD
bool "Enable USB device"
select RT_USING_USB_DEVICE
default n
1
2
3
4
5
6
7
RT-Thread Components --->
Device Drivers --->
Using USB --->
[*] Using USB device
[*] Enable composite device
[*] Enable to use device as Mass Storage device
(自己改名字) msc class disk name

其他配置

参考 sdio 的配置,即可将 sd 卡插在 stm32 上,在电脑上显示出来

sd 卡的文件系统用 fat 和 ntfs 都可以

读写 u 盘

使用 usb host 读写 u 盘

参考 这里

usb host

1
2
3
4
打开 cubeMX,配置 USB_OTG, 使用 host_only 模式,nvic interrupt table 配置 usb on the go fs global interrupt, 生成代码,复制到项目

cubeMX 里面配置的时候,rcc 需要启用 hse,外部晶震,usb 的时钟需要设置为 48MHZ
复制 main.c 里面的时钟配置到 board.c

修改 board/Kconfig,添加

1
2
3
4
config BSP_USING_USBH
bool "Enable USB host"
select RT_USING_USB_HOST
default n
1
2
3
4
5
6
RT-Thread Components --->
Device Drivers --->
Using USB --->
[*] Using USB host
[*] Enable Udisk Drivers
(/) Udisk mount dir

文件系统

位置

1
2
3
4
5
6
RT-Thread Components --->
Device virtual file system --->
[*]Using device virtual file system
[*] Enable elm-chan fatfs
elm-chan's FatFs, Generic FAT Filesystem Module --->
(4096) Maximum sector size to be handled.

libc

1
2
3
RT-Thread Components --->
POSIX layer and C standard library --->
[*] Enable libc APIs from toolchain

复制驱动

去 gitee 的 rt thread 的 master 分支里面找到 drv_usbh.c 和 drv_usbh.h, 放到项目的 libraries/HAL_Drivers 里面

修改,添加 libraries/HAL_Drivers/SConscript

1
2
if GetDepend(['BSP_USING_USBH']):
src += ['drv_usbh.c']

备注

u 盘的供电需要 5v

可以修改 usb 调试宏查看日志 RT_DEBUG_USB