该笔记类别主要是在自己学习时做的一些记录,方便自己很久不用忘掉时进行快速回忆
1 使用
1.1 导入文件
文件名 | 位置 |
---|---|
fal.c | ./src/ |
fal_flash.c | ./src/ |
fal_partition.c | ./src/ |
fal_rtt.c | ./src/ |
fal_flash_stm32l1_port.c(移植文件) | ./samples/porting |
然后导入头文件地址
目录 |
---|
./samples/porting |
./inc |
1.2 添加宏定义
在rtconfig.h文件中添加宏定义
// fal
#define PKG_USING_FAL
#define FAL_PART_HAS_TABLE_CFG
1.3建立分区表
根据在移植文件中定义的存储空间名字来分区,例如在fal_flash_stm32l1_port.c中定义了
const struct fal_flash_dev stm32l_eeprom = { "stm32l_eeprom", 0, 2*1024, 2048, {NULL, read, write, erase} };
则在fla_cfg.h中可用如下划分区域
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WROD, "eeprom", "stm32l_eeprom", 0, 1024+512, 0}, \
{FAL_PART_MAGIC_WROD, "eeprom2", "stm32l_eeprom", 1024+512,512 , 0}, \
}
注意的是头文件中必须使用宏(FAL_PART_HAS_TABLE_CFG),才会使用这里定义的分区方式
1.3 例程
- 添加头文件
#include "fal.h"
- 初始化fla组件
fal_init();
- 打印分区表
fal_show_part_table();
输出结果:
- 选择一个操作分区
const struct fal_partition * bli = fal_partition_find("eeprom2") ;
if (bli ==RT_NULL)
{
rt_kprintf("flash not find\n");
}
- 读写测试
static uint8_t reg[3] ={0,0,0};
static uint8_t data[3] ={1,2,3};
fal_partition_read(bli,0,reg,3);
rt_kprintf("##%d %d %d",reg[0],reg[1],reg[2]);
rt_thread_mdelay(1000);
fal_partition_erase(bli,0,3);
fal_partition_write(bli,0,data,3);
fal_partition_read(bli,0,reg,3);
rt_kprintf("##%d %d %d",reg[0],reg[1],reg[2]);
先读取3个寄存器,然后写入新数据1,2,3,再次读取显示出来。串口打印结果在第一次读取时输出为零,在擦除写入后读取出来便是数据1,2,3. 复位模块后第一次读取出的数据也为1,2,3. 表示掉电保存成功了。
2 通用API
2.1查找 Flash 设备
失败返回NULL
const struct fal_flash_dev *fal_flash_device_find(const char *name)
2.2 查找 Flash 分区
const struct fal_partition *fal_partition_find(const char *name)
2.3 获取分区表
led:分区表长度
const struct fal_partition *fal_get_partition_table(size_t *len)
2.4 临时设置分区表
FAL 初始化时会自动装载默认分区表。使用该设置将临时修改分区表,重启后会 丢失 该设置
void fal_set_partition_table_temp(struct fal_partition *table, size_t len)
2.5 从分区读取数据
返回实际读取大小
int fal_partition_read(const struct fal_partition *part, uint32_t addr, uint8_t *buf, size_t size)
2.6 往分区写入数据
int fal_partition_write(const struct fal_partition *part, uint32_t addr, const uint8_t *buf, size_t size)
2.7 擦除分区数据
int fal_partition_erase(const struct fal_partition *part, uint32_t addr, size_t size)
2.8 擦除整个分区数据
int fal_partition_erase_all(const struct fal_partition *part)
2.9 打印分区表
void fal_show_part_table(void)
2.10 根据分区名称,创建对应的块设备
该函数可以根据指定的分区名称,创建对应的块设备,以便于在指定的分区上挂载文件系统
struct rt_device *fal_blk_device_create(const char *parition_name)
参数 | 描述 |
---|---|
parition_name | 分区名称 |
return | 创建成功,则返回对应的块设备,失败返回空 |
2.11 根据分区名称,创建对应的 MTD Nor Flash 设备
该函数可以根据指定的分区名称,创建对应的 MTD Nor Flash 设备,以便于在指定的分区上挂载文件系统
struct rt_device *fal_mtd_nor_device_create(const char *parition_name)
参数 | 描述 |
---|---|
parition_name | 分区名称 |
return | 创建成功,则返回对应的 MTD Nor Flash 设备,失败返回空 |
2.12 根据分区名称,创建对应的字符设备
该函数可以根据指定的分区名称,创建对应的字符设备,以便于通过 deivice 接口或 devfs 接口操作分区,开启了 POSIX 后,还可以通过 oepn/read/write 函数操作分区
struct rt_device *fal_char_device_create(const char *parition_name)
参数 | 描述 |
---|---|
parition_name | 分区名称 |
return | 创建成功,则返回对应的块设备,失败返回空 |
3 MSH命令
命令 | 说明 |
---|---|
fal | 显示fal的相关命令 |
fal probe | 显示并用于指定分区 |
fal read addr size | 例如 fal read 0 64 |
fal write addr data1 ... dataN | 例如fal write 8 1 2 3 4 5 |
fal erase addr size | 例如 fal erase 0 4096 |
fal bench <blk_size> | 例如 fal bench 4096 yes |
4 移植
使用一节中提到的samples\porting目下便是移植需要修改的文件,例如源码只提供了fal_flash_sfud_port.c和fal_flash_stm32f2_port.c两个文件,我想在芯片stm32L151上使用它的eeprom,则自己新建立一个文件,实现初始化、读、写、擦即可,最后在同目录下的fal_cfg.h中进行分区,就想下面这样
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WROD, "eeprom", "stm32l_eeprom", 0, 1024+512, 0}, \
{FAL_PART_MAGIC_WROD, "eeprom2", "stm32l_eeprom", 1024+512,512 , 0}, \
}
fal_flash_stm32l1_port.c
#include <fal.h>
#include "rtthread.h"
#define EEPROM_BASE_ADDR 0x08080000
static int read(long offset, uint8_t *buf, size_t size)
{
uint8_t *wAddr;
size_t i;
wAddr=(uint8_t *)(EEPROM_BASE_ADDR+offset);
for (i = 0; i < size; i++, wAddr++, buf++)
{
*buf = *(uint8_t *) wAddr;
}
// while(size--){
// *buf++=*wAddr++;
// }
return size;
}
static int write(long offset, const uint8_t *buf, size_t size)
{
size_t i;
uint32_t read_data;
uint32_t addr = EEPROM_BASE_ADDR + offset;
HAL_FLASHEx_DATAEEPROM_Unlock();
for (i = 0; i < size; i++, buf++, addr++)
{
// HAL_FLASHEx_DATAEEPROM_Erase(FLASH_TYPEERASEDATA_BYTE,addr);
HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_FASTBYTE , addr, *buf);
read_data = *(uint8_t *) addr;
/* check data */
if (read_data != *buf)
{
return -1;
}
}
HAL_FLASHEx_DATAEEPROM_Lock();
return size;
}
static int erase(long offset, size_t size)
{
size_t i;
uint32_t addr = EEPROM_BASE_ADDR + offset;
HAL_FLASHEx_DATAEEPROM_Unlock();
for(i=0;i<size;i++ , addr++)
{
HAL_FLASHEx_DATAEEPROM_Erase(FLASH_TYPEERASEDATA_BYTE,addr);
}
HAL_FLASHEx_DATAEEPROM_Lock();
return size;
}
const struct fal_flash_dev stm32l_eeprom = { "stm32l_eeprom", 0, 2*1024, 2048, {NULL, read, write, erase} };
同理无论任何存储,只需要实现对于接口后,上层使用便没有任何区别