IOT-OS之RT-Thread(十一)--- FAL分区管理与easyflash变量管理

一、FAL管理与示例

FAL (Flash Abstraction Layer) Flash 抽象层,是对 Flash 及基于 Flash 的分区进行管理、操作的抽象层,对上层统一了 Flash 及 分区操作的 API ,FAL 框架图如下:
FAL框架图
从上图可以看出FAL抽象层位于SFUD框架的上层,可以将多个Flash硬件(包括片内Flash和片外Flash)统一进行管理,并向上层比如DFS文件系统层提供对底层多个Flash硬件的统一访问接口,方便上层应用对底层硬件的访问操作。

1.1 FAL软件包源码获取

从Github下载的RT-Thread源码中并没有FAL软件包的源码,我们可以通过git工具获取,menuconfig中也配置了FAL软件包的配置项,在配置项内有FAL软件包的下载地址等信息,我们配置启用FAL软件包后即可通过git工具(前提是需要安装并配置后Git工具)自动下载FAL软件包源码到工程目录。

在前篇博客的工程目录stm32l475_dfs_sample中打开env环境,运行menuconfig命令,启用FAL配置界面如下:
启用FAL软件包的配置界面
启用FAL软件包后出现更多选项,我们想使用FAL管理STM32L475片内Flash和W25Q128 Flash,其中W25Q128使用SFUD框架驱动,在启用FAL软件包后,我们可以选择使用SFUD驱动,SFUD设备名默认为norflash0,可以更改设备名为W25Q128,使用SFUD驱动的配置界面如下:
FAL使用SFUD的配置界面
保存配置退出后,在env环境执行pkgs --update命令,会自动从FAL的github仓库获取FAL软件包源码到本地工程目录,如下图所示:
获取FAL软件包
获取到的FAL软件包目录结构如下:
FAL目录结构

1.2 FAL管理

FAL既然是对多个Flash设备进行分区管理的,自然会对Flash设备和分区有相应的数据结构描述。

  • FAL设备与分区控制块

FAL设备与FAL分区的描述结构体如下:

// projects\stm32l475_dfs_sample\packages\fal-latest\inc\fal_def.h

/* FAL flash and partition device name max length */
#ifndef FAL_DEV_NAME_MAX
#define FAL_DEV_NAME_MAX 24
#endif

struct fal_flash_dev
{
   
    char name[FAL_DEV_NAME_MAX];

    /* flash device start address and len  */
    uint32_t addr;
    size_t len;
    /* the block size in the flash for erase minimum granularity */
    size_t blk_size;

    struct
    {
   
        int (*init)(void);
        int (*read)(long offset, uint8_t *buf, size_t size);
        int (*write)(long offset, const uint8_t *buf, size_t size);
        int (*erase)(long offset, size_t size);
    } ops;
};
typedef struct fal_flash_dev *fal_flash_dev_t;

/**
 * FAL partition
 */
struct fal_partition
{
   
    uint32_t magic_word;

    /* partition name */
    char name[FAL_DEV_NAME_MAX];
    /* flash device name for partition */
    char flash_name[FAL_DEV_NAME_MAX];

    /* partition offset address on flash device */
    long offset;
    size_t len;

    uint32_t reserved;
};
typedef struct fal_partition *fal_partition_t;

fal_flash_dev结构体除了包含设备名、起始地址、长度、块大小等对flash设备的描述参数,还包括对flash设备的操作函数指针,这些操作函数需要在移植FAL时由下层的驱动实现。

fal_partition结构体则包含分区名、设备名、分区在设备上的偏移地址和长度等,从该结构体定义也可以看出,一个fal_partition分区不能跨flash设备分配。

  • FAL初始化过程

了解FAL原理,先从FAL组件初始化过程开始:

// projects\stm32l475_dfs_sample\packages\fal-latest\src\fal.c

/**
 * FAL (Flash Abstraction Layer) initialization.
 * It will initialize all flash device and all flash partition.
 *
 * @return >= 0: partitions total number
 */
int fal_init(void)
{
   
    extern int fal_flash_init(void);
    extern int fal_partition_init(void);

    int result;

    /* initialize all flash device on FAL flash table */
    result = fal_flash_init();

    if (result < 0) {
   
        goto __exit;
    }

    /* initialize all flash partition on FAL partition table */
    result = fal_partition_init();

__exit:

    if ((result > 0) && (!init_ok))
    {
   
        init_ok = 1;
        log_i("RT-Thread Flash Abstraction Layer (V%s) initialize success.", FAL_SW_VERSION);
    }
    else if(result <= 0)
    {
   
        init_ok = 0;
        log_e("RT-Thread Flash Abstraction Layer (V%s) initialize failed.", FAL_SW_VERSION);
    }

    return result;
}


// projects\stm32l475_dfs_sample\packages\fal-latest\src\fal_flash.c

static const struct fal_flash_dev * const device_table[] = FAL_FLASH_DEV_TABLE;
static const size_t device_table_len = sizeof(device_table) / sizeof(device_table[0]);
static uint8_t init_ok = 0;

/**
 * Initialize all flash device on FAL flash table
 *
 * @return result
 */
int fal_flash_init(void)
{
   
    size_t i;

    if (init_ok)
    {
   
        return 0;
    }

    for (i = 0; i < device_table_len; i++)
    {
   
        assert(device_table[i]->ops.read);
        assert(device_table[i]->ops.write);
        assert(device_table[i]->ops.erase);
        /* init flash device on flash table */
        if (device_table[i]->ops.init)
        {
   
            device_table[i]->ops.init();
        }
        ......
    }
    init_ok = 1;
    return 0;
}


// projects\stm32l475_dfs_sample\packages\fal-latest\src\fal_partition.c

USED static const struct fal_partition partition_table_def[] SECTION("FalPartTable") = FAL_PART_TABLE;
static const struct fal_partition *partition_table = NULL;

/**
 * Initialize all flash partition on FAL partition table
 *
 * @return partitions total number
 */
int fal_partition_init(void)
{
   
    size_t i;
    const struct fal_flash_dev *flash_dev = NULL;

    if (init_ok)
    {
   
        return partition_table_len;
    }

#ifdef FAL_PART_HAS_TABLE_CFG
    partition_table = &partition_table_def[0];
    partition_table_len = sizeof(partition_table_def) / sizeof(partition_table_def[0]);
#else
    /* load partition table from the end address FAL_PART_TABLE_END_OFFSET, error return 0 */
    long part_table_offset = FAL_PART_TABLE_END_OFFSET;
    size_t table_num = 0, table_item_size = 0;
    uint8_t part_table_find_ok = 0;
    uint32_t read_magic_word;
    fal_partition_t new_part = NULL;

    flash_dev = fal_flash_device_find(FAL_PART_TABLE_FLASH_DEV_NAME);
    if (flash_dev == NULL)
    {
   
        log_e("Initialize failed! Flash device (%s) NOT found.", FAL_PART_TABLE_FLASH_DEV_NAME);
        goto _exit;
    }

    /* check partition table offset address */
    if (part_table_offset < 0 || part_table_offset >= (long) flash_dev->len)
    {
   
        log_e("Setting partition table end offset address(%ld) out of flash bound(<%d).", part_table_offset, flash_dev->len);
        goto _exit;
    }

    table_item_size = sizeof(struct fal_partition);
    new_part = (fal_partition_t)FAL_MALLOC(table_item_size);
    if (new_part == NULL)
    {
   
        log_e("Initialize failed! No memory for table buffer.");
        goto _exit;
    }

    /* find partition table location */
    {
   
        uint8_t read_buf[64];

        part_table_offset -= sizeof(read_buf);
        while (part_table_offset >= 0)
        {
   
            if (flash_dev->ops.read(part_table_offset, read_buf, sizeof(read_buf)) > 0)
            {
   
                /* find magic word in read buf */
                for (i = 0; i < sizeof(read_buf) - sizeof(read_magic_word) + 1; i++)
                {
   
                    read_magic_word = read_buf[0 + i] + (read_buf[1 + i] << 8) + (read_buf[2 + i] << 16) + (read_buf[3 + i] << 24);
                    if (read_magic_word == ((FAL_PART_MAGIC_WORD_H << 16) + FAL_PART_MAGIC_WORD_L))
                    {
   
                        part_table_find_ok = 1;
                        part_table_offset += i;
                        log_d("Find the partition table on '%s' offset @0x%08lx.", FAL_PART_TABLE_FLASH_DEV_NAME,
                                part_table_offset);
                        break;
                    }
                }
            }
            else
            {
   
                /* read failed */
                break;
            }

            if (part_table_find_ok)
            {
   
                break;
            }
            else
            {
   
                /* calculate next read buf position */
                if (part_table_offset >= (long)sizeof(read_buf))
                {
   
                    part_table_offset -= sizeof(read_buf);
                    part_table_offset += (sizeof(read_magic_word) - 1);
                }
                else if (part_table_offset != 0)
                {
   
                    part_table_offset = 0;
                }
                else
                {
   
                    /* find failed */
                    break;
                }
            }
        }
    }

    /* load partition table */
    while (part_table_find_ok)
    {
   
        memset(new_part, 0x00, table_num);
        if (flash_dev->ops.read(part_table_offset - table_item_size * (table_num), (uint8_t *) new_part,
                table_item_size) < 0)
        {
   
            log_e("Initialize failed! Flash device (%s) read error!", flash_dev->name);
            table_num = 0;
            break;
        }

        if (new_part->magic_word != ((FAL_PART_MAGIC_WORD_H << 16) + FAL_PART_MAGIC_WORD_L))
        {
   
            break;
        }

        partition_table = (fal_partition_t) FAL_REALLOC(partition_table, table_item_size * (table_num + 1));
        if (partition_table == NULL)
        {
   
  • 28
    点赞
  • 94
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
### 回答1: RT-Thread是一个开源的嵌入式操作系统,它支持多种网络协议,如NB-IoT. 如果在使用RT-Thread上传数据到云平台时遇到没有数据流的问题,可能是由于网络连接问题或者云平台配置问题导致的。建议检查网络连接,确认云平台配置是否正确,并检查是否有防火墙或安全组限制了数据流量。 ### 回答2: RT-Thread是一个开源的实时操作系统,可以用于物联网设备的开发。NB-IoT(Narrowband Internet of Things)是一种低功耗广域网通信技术,适用于物联网设备的连接。而云平台是一个用于存储、管理和分析物联网设备数据的平台。 在RT-Thread中使用NB-IoT上传数据到云平台时,如果没有数据流,可能存在以下几种可能的原因: 1. 设备连接问题:首先要确保物联网设备已经成功连接到NB-IoT网络。检查设备的信号强度和联网状态,确认是否正常连接。 2. 云平台配置问题:确认设备的云平台配置是否正确。检查设备的云平台账号和密钥是否正确,确保设备可以正确地与云平台进行通信。 3. 数据传输问题:检查设备上传数据的程序是否正确。确认设备采集的数据是否正确,以及上传数据的协议和格式是否与云平台要求一致。 4. 云平台接收问题:云平台可能存在接收数据的问题。检查云平台的数据流配置是否正确,确保设备上传的数据可以被正确地接收和处理。 如果以上的检查都没有问题,仍然无法上传数据到云平台,可以尝试联系RT-Thread开发者社区或云平台的技术支持团队,寻求他们的帮助和建议。他们可能会提供更详细的解决方案,或者帮助排查可能存在的其他问题。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流云IoT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值