|
发表于 2022-6-7 22:46:46
|
显示全部楼层
其实没你想象的那么复杂,每一种虚拟化大概几百行代码而已,一旦虚拟化完成后,应用部分真的是不需要修改了,提供一个对flash进行抽象化的fal组件,以供参考:
fal.h
[C] 纯文本查看 复制代码 /** ****************************************************************************
* @file fal.h
* @author mojinpan
* @copyright copyright (c) 2018-20xx mojinpan. All rights reserved.
* @brief FAL (Flash Abstraction Layer) Flash抽象层
* @version V1.3
* @date 2020-02-04
*
* @par 功能说明
* @details
* 1.统一flash相关操作,为应用层操作flash提供统一接口
* 2.支持静态可配置分区表,可关联多个flash设备
* 3.支持分区访问权限和分区写入权限多用户区分设置
* 4.每个分区和用户分别拥有一个权限控制字,高16位表示写权限,低16位表示访问权限,两者相与不为0即表示拥有对应权限
* 5.访问权限为读权限,无访问权限则看不到分区,拥有写权限就自动拥访问权限
*
* @par 移植说明
* @details
* 1.编写接口函数read(),write()和erase()
* 2.实例化FAL_Flash结构体,并配置好参数和接口函数
* 3.建议参考fal_port部分示例进行移植
*
* @par 调用说明
* @details
* 1.初始化flash
* 2.FAL_Flash结构体,并配置好参数和接口函数
* 3.定义好分区配置表FAL_PART_TABLE
* 4.根据权限需求,在分区配置表中配置好权限位,并对于确定用户配置字
* 5.调用FalInit()初始化fal
*******************************************************************************/
#ifndef _FAL_H_
#define _FAL_H_
#include <stdint.h>
#include <stdio.h>
#include <string.h>
/*******************************************************************************
Macro Definition 宏定义
*******************************************************************************/
#define FAL_SHELL_USED //开启FAL对shell的支持
#define FAL_SHELL_COLOR 1 //shell输出信息带颜色
#define FAL_DEV_NAME_MAX 24 //设备名称最大长度
#define FAL_OK 0
#define FAL_PART_ERR -1
#define FAL_PART_BUF_ERR -2
#define FAL_PART_SIZE_ERR -3
#define FAL_PART_NAME_ERR -4
#define FAL_FLASH_TYPE_ERR -5
#define FAL_FLASH_READ_ERR -6
#define FAL_FLASH_WRITE_ERR -7
#define FAL_FLASH_ERASE_ERR -8
#define FAL_FLASH_READ_ONLY -9
#define FAL_Assert(expr) UlogAssert(expr,while(1))
#define FAL_ERR(fmt,...) ULOG_E(fmt,##__VA_ARGS__)
#define FAL_WRNG(fmt,...) ULOG_W(fmt,##__VA_ARGS__)
#define FAL_INFO(fmt,...) ULOG_I(fmt,##__VA_ARGS__)
#define FAL_DBUG(fmt,...) ULOG_D(fmt,##__VA_ARGS__)
/*******************************************************************************
Data Type 数据类型
*******************************************************************************/
/// flash设备信息
typedef struct fal_flash
{
void* dev; //设备对象
uint32_t addr; //flash设备起始地址
size_t len; //fash设备长度
size_t blk_size; //用于擦除最小粒度的闪存块大小
size_t write_gran; //最小写入颗粒度 1(nor flash)/ 8(stm32f2/f4)/ 32(stm32f1)/ 64(stm32l4)
struct
{
int32_t (*read)(void* dev,uint32_t addr, uint8_t *buf, size_t size);
int32_t (*write)(void* dev,uint32_t addr, const uint8_t *buf, size_t size);
int32_t (*erase)(void* dev,uint32_t addr, size_t size);
} ops;
char name[FAL_DEV_NAME_MAX]; //设备名称
}FAL_Flash;
/// 分区信息
typedef struct
{
uint32_t magic_word;
char name[FAL_DEV_NAME_MAX]; //分区名称
FAL_Flash* flash; //flash设备对象
uint32_t offset; //分区偏移地址
size_t len; //分区大小
uint32_t cfg; //权限配置
} FAL_Part;
/*******************************************************************************
Function declaration 函数声明
*******************************************************************************/
int32_t FalInit(uint32_t cfg);
int32_t FalPartRead(const char *name,uint32_t addr, uint8_t *buf, size_t size);
int32_t FalPartWirte(const char *name,uint32_t addr,const uint8_t *buf, size_t size);
int32_t FalPartErase(const char *name,uint32_t addr, size_t size);
int32_t FalPartEraseAll(const char *name);
int32_t FalPartFindByName(FAL_Part** part,const char *name);
void FalHexDump(const char *name,uint32_t addr, uint32_t size);
void FalPartInfo(void);
//fal_port.c
int32_t FalFlashInit(FAL_Flash* fal,void *flash,uint8_t type,const char *name);
#endif /* _FAL_H_ */
/*********************************END OF FILE**********************************/
/*
//用户分区示例
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WORD, "bl", &stm32_onchip, 0, 64*1024, 0xFFFFFFFF}, \
{FAL_PART_MAGIC_WORD, "app", &stm32_onchip, 64*1024, 704*1024, 0xFFFFFFFF}, \
{FAL_PART_MAGIC_WORD, "easyflash", &norflash, 0, 1024*1024, 0xFFFFFFFF}, \
{FAL_PART_MAGIC_WORD, "download", &norflash, 1024*1024, 1024*1024, 0xFFFFFFFF}, \
}
*/
fal.c
[C] 纯文本查看 复制代码 /** ****************************************************************************
* @file fal.c
* @author mojinpan
* @copyright copyright (c) 2018-20xx mojinpan. All rights reserved.
* @brief FAL (Flash Abstraction Layer) Flash抽象层
*
* @version V1.0
* @date 2020-06-17
* @details
* 1.RT-Thread中移植出fal
* 2.将log信息改用使用ulog输出
* 3.对一些宏定义的条件判断进行简化
*
* @version V1.1
* @date 2020-07-22
* @details
* 1.完全重构整个组件,更进一步简化整个组件
* 2.取消flash设备表,合并到分区表中
* 3.暂时取消分区表储存在flash设备中
* 4.写操作增加最小写入颗粒和地址的对齐的判断
* 5.擦除操作增加最小擦除区域判断
* 6.增加权限配置,满足不同权限的用户对分区的可见程度的差异化配置
* 7.保留分区魔术字,后续如有需求可实现动态分区传递(主要可能是用boot和app之间交互用)
*
* @version V1.2
* @date 2020-08-08
* @details
* 1.增加分区格式化的命令行模式
* 2.增加FAL_SHELL_USED 用于配置是否提供shell的支持
*
* @version V1.3
* @date 2021-02-04
* @details
* 1.移除移植相关的接口函数,改为由下级驱动自行实现
* 2.将FAL_Flash中函数指针格式进行调整,改为传递void * flash,便于通用化调用
*
* @version V1.4
* @date 2021-04-20
* @details
* 1.调整shell的调用命令
* 2.增加flash内容jump显示的功能,便于查看flash读写情况
*******************************************************************************/
#include <string.h>
#include "bsp.h"
#include "fal.h"
#ifdef FAL_SHELL_USED
#include "shell.h"
#endif
/*******************************************************************************
Macro Definition 宏定义
*******************************************************************************/
//分区魔术字
#define FAL_PART_MAGIC_WORD 0x45503130
#define FAL_PART_MAGIC_WORD_H 0x4550L
#define FAL_PART_MAGIC_WORD_L 0x3130L
//flash jump格式
#if FAL_SHELL_COLOR == 1
#define flashPrintHead CSI(31) " Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F" CSI(39)
#define flashPrintAddr CSI(31)"0x%08x: "CSI(39)
#else
#define flashPrintHead " Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"
#define flashPrintAddr "0x%08x: "
#endif
/*******************************************************************************
Global Variables 全局变量
*******************************************************************************/
FAL_Part falPartLoadTab[] = FAL_PART_TABLE;
const uint32_t falPartLoadLen = sizeof(falPartLoadTab)/sizeof(FAL_Part);
FAL_Part *falPartTab[sizeof(falPartLoadTab)/sizeof(FAL_Part)];
uint32_t falPartLen = 0;
uint32_t userCfg = 0;
/** ****************************************************************************
* @brief FAL初始化
* @param cfg 用户权限配置,高16位表示写权限,低16位表示访问权限,和分区权限配置向与不为零即表示拥有改权限
* @note 每个分区在高位和低位各使用一个bit表示写权限和访问权限,这样可以比较方便推导出用户权限字
* @note 访问权限为读权限,无访问权限则看不到分区,拥有写权限就自动拥访问权限
*******************************************************************************/
int32_t FalInit(uint32_t cfg)
{
uint32_t i;
userCfg = cfg; //保存用户权限
falPartLen = 0;
//根据用户权限导出分区信息
for(i=0;i<falPartLoadLen;i++)
{
if((falPartLoadTab[i].cfg & userCfg) !=0)
{
falPartTab[falPartLen++] = &falPartLoadTab[i];
}
}
#ifdef FAL_INFO_MODE
if(falPartLen > 0)
{
FalPartInfo();
FAL_INFO("FAL (Flash Abstraction Layer) init success!");
return FAL_OK;
}
#endif
return FAL_PART_ERR;
}
/** ****************************************************************************
* @brief 通过分区名称查找分区信息
* @param part 分区信息结构体
* @name 分区名称
* @return 操作结果
*******************************************************************************/
int32_t FalPartFindByName(FAL_Part** part,const char *name)
{
uint32_t i;
if(name == NULL)
{
FAL_ERR("partition name is empty!");
return FAL_PART_NAME_ERR;
}
for (i = 0; i < falPartLen; i++)
{
if (!strncmp(name, falPartTab[i]->name, FAL_DEV_NAME_MAX))
{
*part = falPartTab[i];
return FAL_OK;
}
}
FAL_ERR("Cannot find partition by name %s!",name);
return FAL_PART_NAME_ERR;
}
/** ****************************************************************************
* @brief 擦除数据
* @param name 分区名称
* @param addr 地址
* @param size 大小
* @return 操作结果
*******************************************************************************/
int32_t FalPartErase(const char *name,uint32_t addr, size_t size)
{
int ret = 0;
FAL_Part* part;
if(FalPartFindByName(&part,name)!=FAL_OK)
{
return FAL_PART_NAME_ERR;
}
if((part->cfg & 0xFFFF0000 & userCfg) == 0)
{
FAL_ERR("Partition read only!");
return FAL_FLASH_READ_ONLY;
}
if ( (addr + size) > (part->len))
{
FAL_ERR("Partition erase error! Partition erase size (0x%x) out of bound.",(addr + size));
return FAL_PART_SIZE_ERR;
}
ret = part->flash->ops.erase(part->flash->dev,part->offset + addr, size);
if (ret < 0)
{
FAL_ERR("Partition erase error! Flash device(%s) erase error!", part->flash->name);
return ret;
}
return FAL_OK;
}
/** ****************************************************************************
* @brief 擦除整个分区
* @param name 分区名称
* @return 操作结果
*******************************************************************************/
int32_t FalPartEraseAll(const char *name)
{
FAL_Part* part;
if(FalPartFindByName(&part,name)!=FAL_OK)
{
return FAL_PART_NAME_ERR;
}
if((part->cfg & 0xFFFF0000 & userCfg) == 0)
{
FAL_ERR("%s Partition read only!",name);
return FAL_FLASH_READ_ONLY;
}
return FalPartErase(name, 0, part->len);
}
/** ****************************************************************************
* @brief 读取数据
* @param name 分区名称
* @param addr 地址
* @param buf 数据指针
* @param size 大小
* @return 操作结果
*******************************************************************************/
int32_t FalPartRead(const char *name,uint32_t addr, uint8_t *buf, size_t size)
{
int ret = 0;
FAL_Part* part;
if(FalPartFindByName(&part,name)!=FAL_OK)
{
return FAL_PART_NAME_ERR;
}
if(buf == NULL){
FAL_ERR("Partition read buf error!");
return FAL_PART_ERR;
}
if (addr + size > part->len)
{
FAL_ERR("Partition read error! Partition address 0x%x out of bound.",addr + size);
return FAL_PART_SIZE_ERR;
}
ret = part->flash->ops.read(part->flash->dev,part->offset + addr, buf, size);
if (ret < 0)
{
FAL_ERR("Partition read error! Flash device(%s) read error!", part->flash->name);
}
return ret;
}
/** ****************************************************************************
* @brief 写数据
* @param name 分区名称
* @param addr 地址
* @param buf 数据指针
* @param size 大小
* @return 操作结果
*******************************************************************************/
int32_t FalPartWirte(const char *name,uint32_t addr,const uint8_t *buf, size_t size)
{
int ret = 0;
FAL_Part* part;
if(FalPartFindByName(&part,name)!=FAL_OK)
{
return FAL_PART_NAME_ERR;
}
if((part->cfg & 0xFFFF0000 & userCfg) == 0)
{
FAL_ERR("Partition read only!");
return FAL_FLASH_READ_ONLY;
}
if(buf == NULL){
FAL_ERR("Partition Write buf error!");
return FAL_PART_ERR;
}
if (addr + size > part->len)
{
FAL_ERR("Partition write error! Partition address out of bound.");
return FAL_PART_SIZE_ERR;
}
if (size < part->flash->write_gran)
{
FAL_ERR("Partition write error! Write size must be greater than %d",part->flash->write_gran);
return FAL_PART_SIZE_ERR;
}
if (addr % part->flash->write_gran != 0)
{
FAL_ERR("Partition write error! The address must be %d-byte aligned",part->flash->write_gran);
return FAL_PART_SIZE_ERR;
}
ret = part->flash->ops.write(part->flash->dev,part->offset + addr, buf, size);
if (ret < 0)
{
FAL_ERR("Partition write error! Flash device(%s) write error!", part->flash->name);
}
return ret;
}
/** ****************************************************************************
* @brief 16进制输出
* @param name 分区名称
* @param addr 内存基址
* @param len 长度
*******************************************************************************/
void FalHexDump(const char *name,uint32_t addr, uint32_t size)
{
char data;
char buf[100];
uint8_t *address;
uint32_t len = size;
uint32_t printLen = 0;
if (size == 0)return;
printf("memory of 0x%08x, size: %d:\r\n", addr, size);
address = (uint8_t *)(addr & (~0x0000000F));
size += addr - (uint32_t)address;
size = (size + 15) & (~0x0000000F);
printf(flashPrintHead"\r\n");
while (size)
{
printLen += sprintf(buf + printLen, flashPrintAddr, (uint32_t)address);
for (int i = 0; i < 16; i++)
{
if ((uint32_t)(address + i) < addr
|| (uint32_t)(address + i) >= addr + len)
{
buf[printLen ++] = ' ';
buf[printLen ++] = ' ';
buf[printLen ++] = ' ';
}
else
{
FalPartRead(name,(uint32_t)(address + i),(uint8_t*)&data,1);
printLen += sprintf(buf + printLen, "%02x ", data);
}
}
buf[printLen ++] = '|';
buf[printLen ++] = ' ';
for (int i = 0; i < 16; i++)
{
if ((uint32_t)(address + i) < addr
|| (uint32_t)(address + i) >= addr + len)
{
buf[printLen ++] = ' ';
}
else
{
FalPartRead(name,(uint32_t)(address + i),(uint8_t*)&data,1);
if (data >= 32 && data<= 126)
{
printLen += sprintf(buf + printLen, "%c", data);
}
else
{
buf[printLen ++] = '.';
}
}
}
buf[printLen ++] = '|';
buf[printLen ++] = '\r';
buf[printLen ++] = '\n';
printf("%*s",printLen,buf);
address += 16;
size -= 16;
printLen = 0;
}
}
/** ****************************************************************************
* @brief 分区信息显示
*******************************************************************************/
void FalPartInfo(void)
{
char *item1 = "name", *item2 = "flash_dev";
size_t i, part_name_max = strlen(item1), flash_dev_name_max = strlen(item2);
FAL_Part *part;
bool write_en;
if (falPartLen)
{
for (i = 0; i < falPartLen; i++)
{
part = falPartTab[i];
if (strlen(part->name) > part_name_max)
{
part_name_max = strlen(part->name);
}
if (strlen(part->flash->name) > flash_dev_name_max)
{
flash_dev_name_max = strlen(part->flash->name);
}
}
}
printf("==================== FAL partition table ====================\r\n");
printf("| %-*.*s | %-*.*s | offset | len | R/W\r\n", part_name_max, FAL_DEV_NAME_MAX, item1, flash_dev_name_max,
FAL_DEV_NAME_MAX, item2);
printf("-------------------------------------------------------------\r\n");
for (i = 0; i < falPartLen; i++)
{
write_en = (falPartTab[i]->cfg & 0xFFFF0000 & userCfg) == 0 ? false : true;
printf("| %-*.*s | %-*.*s | 0x%08x | 0x%08x | %s\r\n",
part_name_max, FAL_DEV_NAME_MAX, falPartTab[i]->name,
flash_dev_name_max,FAL_DEV_NAME_MAX, falPartTab[i]->flash->name,
falPartTab[i]->offset,falPartTab[i]->len,write_en ? "R/W":"R");
}
printf("=============================================================\r\n");
}
#ifdef FAL_SHELL_USED
/*******************************************************************************
* @brief FAL对shell的支持
*******************************************************************************/
void FalShell(uint32_t argc, void* argv[])
{
uint8_t data;
uint32_t addr;
uint32_t len;
char* part;
Shell *shell;
if(argc == 1)
{//显示所有分区信息
FalPartInfo();
return;
}
else if(argc == 2 && !strcmp("-help",(char*)argv[1]))
{
//轮空,直接执行最后的显示信息
}
else if(argc == 3 && !strcmp("format",(char*)argv[1]))
{//格式化分区
printf("Format partition %s now? (Y/N) \r\n",(const char*)argv[2]);
data = getchar();
if(data == 'Y'|| data == 'y')
{
printf("Formatting ...... \r\n");
if(FalPartEraseAll((const char*)argv[2])==FAL_OK)
{
printf("Format successful!\r\n");
}
else
{
printf("Format failed!\r\n");
}
}
return;
}
else if(argc == 5 && !strcmp("jump",(char*)argv[1]))
{//格式化分区
part = ((char*)argv[2]);
addr = shellParsePara(argv[3]);
len = shellParsePara(argv[4]);
FalHexDump(part,addr,len);
return;
}
//无法识别指令时提示用户按要求输入指令
printf("Fal command format : fal [OPTION] [part] [addr] [len]\r\n");
printf("Fal print : fal\r\n");
printf("Fal format : fal format part \r\n");
printf("Fal jump : fal jump part addr len\r\n");
}
SHELL_EXPORT_CMD(fal, FalShell, use -help get more info);
#endif
/*********************************END OF FILE**********************************/
|
|