手上有个stm32开发板,想用内部flash挂载文件系统,查看网上资料,都是创建了一个fal或者littlefs的中间层,不想搞那么复杂了,想着直接挂载elf文件系统。第一步,先用内存模拟flash的读写,跳过flash读写失败的因素。
第一步,直接注册进IO一个设备,使用一下代码后,在shell中使用list_device可以看到 elf0的设备。
elf_device->parent.type = RT_Device_Class_Block;
rt_device_register(&(elf_device->parent), "elf0", RT_DEVICE_FLAG_RDWR);
第二步,添加设备驱动的opt函数。
#include <rtthread.h>
#include <rthw.h>
#define ELF_SECTOR_SIZE 64
#define SDCARD_SIM "sd.bin"
#define SDCARD_SIZE (24*2*512) //16k
#define SDCARD_DEVICE(device) (( struct rt_elf_device*)(device))
struct rt_elf_device
{
struct rt_device parent;
rt_uint32_t user_data;
unsigned char *ptr;
};
static struct rt_elf_device *elf_device = RT_NULL;
static rt_mutex_t lock;
static rt_err_t rt_sdcard_init(rt_device_t dev)
{
rt_kprintf("rt_sdcard_init\n");
return RT_EOK;
}
static rt_err_t rt_sdcard_open(rt_device_t dev, rt_uint16_t oflag)
{
rt_kprintf("rt_sdcard_open\n");
return RT_EOK;
}
static rt_err_t rt_sdcard_close(rt_device_t dev)
{
rt_kprintf("rt_sdcard_close\n");
return RT_EOK;
}
static rt_size_t rt_sdcard_read(rt_device_t device, rt_off_t position, void *buffer, rt_size_t size)
{
struct rt_elf_device *sd;
int result = 0;
rt_kprintf("sd read: pos %d, size %d\n", position, size);
rt_mutex_take(lock, RT_WAITING_FOREVER);
sd = SDCARD_DEVICE(device);
memcpy(buffer, sd->ptr+position*ELF_SECTOR_SIZE, size*ELF_SECTOR_SIZE);
rt_mutex_release(lock);
return size;
_err:
rt_kprintf("sd read errors!\n");
rt_mutex_release(lock);
return 0;
}
static rt_size_t rt_sdcard_write(rt_device_t device, rt_off_t position, const void *buffer, rt_size_t size)
{
struct rt_elf_device *sd;
int result = 0;
rt_kprintf("sd write: pos %d, size %d\n", position, size);
rt_mutex_take(lock, RT_WAITING_FOREVER);
sd = SDCARD_DEVICE(device);
memcpy(sd->ptr+position*ELF_SECTOR_SIZE, buffer,size*ELF_SECTOR_SIZE);
rt_mutex_release(lock);
return size;
_err:
rt_kprintf("sd write errors!\n");
rt_mutex_release(lock);
return 0;
}
static rt_err_t rt_sdcard_control(rt_device_t dev, int cmd, void *args)
{
struct rt_elf_device *sd;
unsigned int size;
RT_ASSERT(dev != RT_NULL);
sd = SDCARD_DEVICE(dev);
if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
{
struct rt_device_blk_geometry *geometry;
geometry = (struct rt_device_blk_geometry *)args;
if (geometry == RT_NULL) return -RT_ERROR;
geometry->bytes_per_sector = ELF_SECTOR_SIZE;
geometry->block_size = ELF_SECTOR_SIZE;
geometry->sector_count = SDCARD_SIZE / ELF_SECTOR_SIZE;
rt_kprintf("rt_sdcard_control bytes_per_sector = %d, bytes_per_sector = %d, \
sector_count = %d\n", geometry->bytes_per_sector, geometry->block_size, geometry->sector_count);
}
return RT_EOK;
}
rt_err_t rt_hw_sdcard_init(const char *spi_device_name)
{
//创建锁
lock = rt_mutex_create("lock", RT_IPC_FLAG_FIFO);
//申请控件
elf_device = (struct rt_elf_device*)rt_malloc (sizeof(struct rt_elf_device));
if (elf_device == RT_NULL)
{
rt_kprintf("rt_elf_device malloc error, no memory!\n");
return RT_ERROR;
}
elf_device->ptr = (unsigned char *) rt_malloc(SDCARD_SIZE);
if (elf_device->ptr == NULL)
{
rt_kprintf("malloc error, no memory!\n");
return RT_ERROR;
}
rt_memset((elf_device->ptr), 0, SDCARD_SIZE);
rt_memset(&(elf_device->parent), 0, sizeof(struct rt_device));
elf_device->parent.init = rt_sdcard_init;
elf_device->parent.open = rt_sdcard_open;
elf_device->parent.close = rt_sdcard_close;
elf_device->parent.read = rt_sdcard_read;
elf_device->parent.write = rt_sdcard_write;
elf_device->parent.control = rt_sdcard_control;
elf_device->parent.user_data = RT_NULL;
elf_device->parent.type = RT_Device_Class_Block;
rt_device_register(&(elf_device->parent), "elf0", RT_DEVICE_FLAG_RDWR);
return RT_EOK;
}
INIT_BOARD_EXPORT(rt_hw_sdcard_init);//添加自动调用
第三步,挂载设备。
#ifdef RT_USING_DFS_ELMFAT
int elffs_mount(void)
{
elm_init();
if(dfs_mount("elf0", "/", "elm", 0, 0) == 0)
{
rt_kprintf("elm File System initialized!\n");
}
else
{
if(dfs_mkfs("elm", "elf0") == 0)
{
if (dfs_mount("elf0", "/", "elm", 0, 0) == 0)
{
rt_kprintf("elm file system initialization done!\n");
}
else
{
rt_kprintf("elm file system initialization failed!\n");
}
}
}
}
#endif
INIT_APP_EXPORT(elffs_mount);
第四步,测试,通过msh />echo "hello" my.txt和msh />cat my.txt进行测试,测试结果如下:
\ | /
- RT - Thread Operating System
/ | \ 3.1.0 build Mar 2 2021
2006 - 2018 Copyright by rt-thread team
hwtimer0 register success
rt_sdcard_init
rt_sdcard_open
rt_sdcard_control bytes_per_sector = 128, bytes_per_sector = 128, sector_count = 192
sd read: pos 0, size 1
rt_sdcard_close
rt_sdcard_open
rt_sdcard_control bytes_per_sector = 128, bytes_per_sector = 128, sector_count = 192
rt_sdcard_control bytes_per_sector = 128, bytes_per_sector = 128, sector_count = 192
sst write: pos 0, size 1
sst write: pos 1, size 1
sst write: pos 2, size 1
sst write: pos 3, size 1
sst write: pos 4, size 1
sst write: pos 5, size 1
sst write: pos 6, size 1
sst write: pos 7, size 1
sst write: pos 8, size 1
sst write: pos 9, size 1
sst write: pos 10, size 1
sst write: pos 11, size 1
sst write: pos 12, size 1
sst write: pos 13, size 1
sst write: pos 14, size 1
sst write: pos 15, size 1
sst write: pos 16, size 1
sst write: pos 17, size 1
sst write: pos 18, size 1
sst write: pos 19, size 1
sst write: pos 20, size 1
sst write: pos 21, size 1
sst write: pos 22, size 1
sst write: pos 23, size 1
sst write: pos 24, size 1
sst write: pos 25, size 1
sst write: pos 26, size 1
sst write: pos 27, size 1
sst write: pos 28, size 1
sst write: pos 29, size 1
sst write: pos 30, size 1
sst write: pos 31, size 1
sst write: pos 32, size 1
sst write: pos 33, size 1
rt_sdcard_close
rt_sdcard_open
rt_sdcard_control bytes_per_sector = 128, bytes_per_sector = 128, sector_count = 192
sd read: pos 0, size 1
elm file system initialization done!
msh />ls
Directory /:
sd read: pos 2, size 1
msh />echo "hello" my.txt
sst write: pos 2, size 1
sd read: pos 1, size 1
sst write: pos 34, size 1
sst write: pos 1, size 1
sd read: pos 2, size 1
sst write: pos 2, size 1
msh />ls
Directory /:
MY.TXT 5
msh />cat my.txt
sd read: pos 34, size 1
hellomsh />
遇到的问题:
1、需要在menuconfig中打开RT_USING_DFS_ELMFAT
2、在dfs_mkfs提示fomat error, result=14的错误,看源码发现sector_count过小,必须大于128,修改后正常
3、系统如何知道flash的扇区大小,扇区数量,通过ioctl的cmd RT_DEVICE_CTRL_BLK_GETGEOME,编写程序给geometry结构体赋值
struct rt_device_blk_geometry
{
rt_uint32_t sector_count;
rt_uint32_t bytes_per_sector;
rt_uint32_t block_size;
};