1.硬件型号\软件版本
MCU:STM32F405RGT6
RT-Thread:v4.1.0
2.CUBEMX配置SPI
既然要将我们的板子挂载成U盘,那么我们的板子必然要有一个片外内存,我的硬件板卡用的片外内存是W25Q64,对于这个芯片应该会有很多人比较熟悉,那相应的,需要用SPI去与W25Q64做交互(读、写),当然既然有了thread,这些交互操作thread会自动帮我们完成,而我们所要做的工作就是告诉thread用的是哪个SPI及其引脚,这就用到了CUBEMX。
由于我硬件使用SPI2去读取的W25Q64,所以我需要去配置SPI2,先配置引脚:
再配置SPI:
只需要配置红框处的即可,下面的具体参数可不配置
配置完cubeMX,相当于我们告诉了thread用的那个SPI及其引脚,可能会有人注意到W25Q64还有一个片选脚,这个我做在了meunuconfig里,下面会提到。
那接下来我们就要去配置thread:
RT-thread配置
先看Kconfig的配置,因为menuconfig的菜单都是来自各个路径下的Kconfig,我们用配置Kconfig的方式来给一个可视化的SPI的开关:
menuconfig BSP_USING_SPI
bool "Enable SPI"
default y
select RT_USING_SPI
if BSP_USING_SPI
config BSP_USING_SPI1
bool "Using SPI1"
default y
config BSP_USING_SPI2
bool "Using SPI2"
default n
config BSP_USING_SPI3
bool "Using SPI3"
default n
endif
然后进入到menuconfig的配置:
打开Env,关于Env这里就不做介绍了,可以去官网去看文档:
输入menuconfig进入可视化配置界面:
选择 Hardware Drivers Config
然后选择:On-chip Peripheral Drivers
然后使能SPI
然后在此选项下选择要打开的SPI:
我这里是因为项目需要把SPI1和SPI2都打开了。这些菜单都是在Kconfig内配置的,如果仅仅是刚从官网下载的一个新的工程的话是没有我上面这些菜单的,需要自己在Kconfig里去配置
打开SPI后,我们如果想直指目标的话直接去配置USB就行,但是我项目里需要配置文件系统,意思就是如果USB插在了电脑上,就会识别成U盘,但是如果拔掉U盘,我的内存就会挂载成文件系统。想看USB配置的可以直接略过下面的文件系统的配置和测试。
然后去配置Device Drivers:
先选择 RT-Thread Components目录:
进入Device Drivers的配置,配置如下:
文件系统的挂载
首先menunconfig指令进入可视化配置:
然后选择 RT-Thread Components:
MSH选项是调试打印口,映射的是我板子MCU的USART1,这个可以去看下官方文档,很基本的一个功能,后面可以通过MSH对文件系统进行操作
DFS就是我们要配置的关于文件系统一些选项:
进入这里去配置:
上述红框内的最大扇区的大小的配置一定要配,要不小于你所用内存的一个扇区大小,我用的是W25Q64,扇区大小是4K,所以我配置的是4096,只要不小于4096就可以。
然后保存配置,
输入
更新pack包
然后输入
重新生成MD5工程
到这里我们SPI-FLASH就配置好了,文件系统呢也配置好了,但是,我们需要吧SPI-FLASH和文件系统关联起来才可以操作文件系统访问flash,thread是不会自动帮我们做这些,需要我们自己去初始化挂载,我新建一个usb.c文件:
#include "dfs_file.h"
#include "drv_spi.h"
#include "spi_flash_sfud.h"
#include <board.h>
#include <rtdbg.h>
#include <rtdevice.h>
#include <rtthread.h>
/**
* 总线上挂载设备 spi20
* @return
*/
static int bsp_spi_attach_init(void)
{
__HAL_RCC_GPIOA_CLK_ENABLE();
// rt_err_t ret = rt_hw_spi_device_attach("spi3", WIZ_SPI_DEVICE, GPIOD, GPIO_PIN_2);;// spi10 表示挂载在 spi3
// 总线上的 0 号设备,PC0是片选,这一步就可以将从设备挂在到总线中。
rt_err_t ret = rt_hw_spi_device_attach(
"spi2", "spi20", GPIOC,
GPIO_PIN_1); // spi10 表示挂载在 spi3 总线上的 0 号设备,PC0是片选,这一步就可以将从设备挂在到总线中。
if (ret < 0) {
LOG_E("flash attach spi2 failed");
return -RT_ERROR;
}
return RT_EOK;
}
INIT_DEVICE_EXPORT(bsp_spi_attach_init);
/**
* 注册为块设备
* @return
*/
static int bsp_spi_block_device_init(void)
{
if (RT_NULL == rt_sfud_flash_probe("W25Q64", "spi20")) //注册块设备,这一步可以将外部flash抽象为系统的块设备
{
LOG_E("flash sfud failed\n");
return -RT_ERROR;
};
return RT_EOK;
}
/* 导出到自动初始化 */
INIT_DEVICE_EXPORT(bsp_spi_block_device_init);
/**
* 挂载文件系统
* @return
*/
static int bsp_spi_flash_mnt_init(void)
{
dfs_mkfs("elm", "W25Q64"); //格式化设备
if (dfs_mount("W25Q64", "/", "elm", 0, 0) == 0) //挂载文件
{
LOG_I("dfs mount success\r\n");
return RT_EOK;
} else {
LOG_E("dfs mount failed\r\n");
return -RT_ERROR;
}
}
/* 组件自动初始化 */
INIT_APP_EXPORT(bsp_spi_flash_mnt_init);
将此文件加入到你的keil工程,然后编译,thread会自动将flash挂载到文件系统。
将编译好的程序文件下载到你的板卡里,之后问题来了,怎么验证呢,还记得上面配置的MSH么,可以通过这个去用shell 指令去验证,关于MSH的东西真的可以去官网上去看,很简单。如果实在有人想看的话后面可以专门写个文章说一下。
我用的一个工具是MobaXterm:
这个工具比较好用,非常nice
打开软件:
电机红框内的Session工具按钮:
选择串口并配置端口号和波特率,然后点击OK:
在这里就可以输入指令进行一些操作,支持的指令可以输入help来查询:
我们输入“ls”指令来查看文件系统是否挂载成功:
这种呢就算是挂载成功了,如果没有挂载成功的话回复的就是下面这种:
那文件系统的挂载到此就结束了,有必要说的一点是,USB和文件系统是只能二选一的,就是要么使用USB,要么挂载成文件系统,当然可以去切换工作。
USB挂载
一样的方法,去menuconnfig配置USB:
进入TinyUSB的配置:
Using USB device这个选项的配置下我们也要有一下配置:
如上面红框,选择MSC大容量设备,CDC是通讯设备,如串口等,HID是人机交互设备,如游戏手柄什么的。
配置完之后我们需要去配置USB_Device,因为U盘一类是属于device类型的而不是host,所以我们还要去配设备驱动端的USB DEVICE,当然,更深入的不探讨,不然没完没了,就实用的配置:
应该有人注意到了这个W25Q64这个关键字,在上述我的usb.c文件里挂载的就是这个名称,这里就通过这个关键字把很多东西联通起来了,然后老样子更新设备包,重新生成MDK5工程
配置完menuconfig,总感觉少了点东西,是什么呢?
当然是硬件GPIO的配置啦,老样子,回到CUBEMX:
配置完GPIO之后很多人会忽略一个问题,就是USB的48M时钟,我们去到CUBEMX的时钟配置界面:
配置完时钟后,记得吧CUBE生成的
函数复制到board.c文件里,否则时钟配置没更新的话,USB永远跑不起来。
在上一个标题下我们做了挂载文件系统,写了一个usb.c文件,在里面写上了挂载文件系统的配置,但是上文说了USB和文件系统二选一,如果想挂载成U盘,那么需要去取消文件系统的挂载,所以我再usb.c的文件末尾新加了一个函数:
static int mount_to_usb(void)
{
char *fullpath = NULL;
fullpath = dfs_normalize_path(NULL, "/");
if (dfs_unmount(fullpath) == 0)
{
rt_kprintf("mount_to_usb ok!\n");
}
else
{
rt_kprintf("mount_to_usb fail!\n");
}
}
INIT_APP_EXPORT(mount_to_usb);
然后编译,下载:将板子上的USB查到电脑上:
这样就可以挂载成U盘了,我们可以在USB插上时挂载成U盘通过电脑往flash里放文件,然后拔掉U盘后自动挂载成文件系统,我们再从文件系统内取东西,通过这个操作我们可以无需升级固件来配置一些设备参数、也可以通过U盘升级固件。
好了,大概讲讲也就这么多,文章内若有不对的或不清晰的可在评论区或私信给予我更正意见。