概述
FAL (Flash Abstraction Layer) Flash 抽象层,是对 Flash 及基于 Flash 的分区进行管理、操作的抽象层,对上层统一了 Flash 及 分区操作的 API (框架图如下所示),并具有以下特性:
- 支持静态可配置的分区表,并可关联多个 Flash 设备;
- 分区表支持 自动装载 。避免在多固件项目,分区表被多次定义的问题;
- 代码精简,对操作系统 无依赖 ,可运行于裸机平台,比如对资源有一定要求的 Bootloader;
- 统一的操作接口。保证了文件系统、OTA、NVM等对 Flash 有一定依赖的组件,底层 Flash 驱动的可重用性;
- 自带基于 Finsh/MSH 的测试命令,可以通过 Shell 按字节寻址的方式操作(读写擦) Flash 或分区,方便开发者进行调试、测试;
正文
第一步:下载源文件
第二步:准备好一个工程
第三步:将源文件添加进工程,并包含好头文件路径
第四步:修改工程文件
修改fal_flash_sfud_port.c
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-01-26 armink the first version
*/
#include <fal.h>
#include <sfud.h>
#include "include.h"
#define FAL_USING_SFUD_PORT
#ifdef FAL_USING_SFUD_PORT
#ifdef RT_USING_SFUD
#include <spi_flash_sfud.h>
#endif
#ifndef FAL_USING_NOR_FLASH_DEV_NAME
#define FAL_USING_NOR_FLASH_DEV_NAME "norflash0"
#endif
static char log_buf[256];
static int init(void);
static int read(long offset, uint8_t *buf, size_t size);
static int write(long offset, const uint8_t *buf, size_t size);
static int erase(long offset, size_t size);
static sfud_flash_t sfud_dev = NULL;
struct fal_flash_dev nor_flash0 =
{
.name = FAL_USING_NOR_FLASH_DEV_NAME,
.addr = 0,
.len = 8 * 1024 * 1024,
.blk_size = 4096,
.ops = {init, read, write, erase},
.write_gran = 1
};
static int init(void)
{
#ifdef RT_USING_SFUD
/* RT-Thread RTOS platform */
sfud_dev = rt_sfud_flash_find_by_dev_name(FAL_USING_NOR_FLASH_DEV_NAME);
#else
/* bare metal platform */
// extern sfud_flash sfud_norflash0;
// sfud_dev = &sfud_norflash0;
sfud_flash *flash = NULL;
flash = sfud_get_device(0);
sfud_dev = flash;
#endif
if (NULL == sfud_dev)
{
return -1;
}
/* update the flash chip information */
nor_flash0.blk_size = sfud_dev->chip.erase_gran;
nor_flash0.len = sfud_dev->chip.capacity;
return 0;
}
static int read(long offset, uint8_t *buf, size_t size)
{
assert(sfud_dev);
assert(sfud_dev->init_ok);
sfud_read(sfud_dev, nor_flash0.addr + offset, size, buf);
return size;
}
static int write(long offset, const uint8_t *buf, size_t size)
{
assert(sfud_dev);
assert(sfud_dev->init_ok);
if (sfud_write(sfud_dev, nor_flash0.addr + offset, size, buf) != SFUD_SUCCESS)
{
return -1;
}
return size;
}
static int erase(long offset, size_t size)
{
assert(sfud_dev);
assert(sfud_dev->init_ok);
if (sfud_erase(sfud_dev, nor_flash0.addr + offset, size) != SFUD_SUCCESS)
{
return -1;
}
return size;
}
/**
* This function is print flash non-package info.
*
* @param format output format
* @param ... args
*/
void fal_print(const char *format, ...) {
va_list args;
/* args point to the first variable parameter */
va_start(args, format);
/* must use vprintf to print */
rt_vsprintf(log_buf, format, args);
uart_write(DEV_UART1,(uint8_t *)log_buf, strlen(log_buf));
va_end(args);
}
#endif /* FAL_USING_SFUD_PORT */
修改fal_cfg.h
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-05-17 armink the first version
*/
#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_
//#include <rtconfig.h>
//#include <board.h>
#define FAL_PART_HAS_TABLE_CFG
/* ===================== Flash device Configuration ========================= */
extern const struct fal_flash_dev stm32f1_onchip_flash;
extern struct fal_flash_dev nor_flash0;
/* flash device table */
#define FAL_FLASH_DEV_TABLE \
{ \
&nor_flash0, \
&stm32f1_onchip_flash, \
}
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG
/* partition table */
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WORD, "easyflash", "norflash0", 0, 1024*1024, 0}, \
{FAL_PART_MAGIC_WORD, "download", "norflash0", 1024*1024, 1024*1024, 0}, \
{FAL_PART_MAGIC_WORD, "bl", "onchipflash", 0, 10*1024, 0}, \
{FAL_PART_MAGIC_WORD, "app", "onchipflash", 10*1024, 50*1024, 0}, \
}
#endif /* FAL_PART_HAS_TABLE_CFG */
#endif /* _FAL_CFG_H_ */
修改fal_flash_stm32f1_port.c
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-01-26 armink the first version
*/
#include "include.h"
#define PAGE_SIZE_ONCHIP 2*1024
static int init(void)
{
/* do nothing now */
return 0;
}
static int read(long offset, uint8_t *buf, size_t size)
{
size_t i;
uint32_t addr = stm32f1_onchip_flash.addr + offset;
for (i = 0; i < size; i++, addr++, buf++)
{
*buf = *(uint8_t *) addr;
}
return size;
}
static int write(long offset, const uint8_t *buf, size_t size)
{
size_t i;
uint32_t addr = stm32f1_onchip_flash.addr + offset;
uint32_t read_data;
uint32_t *buf_32 = (uint32_t *)buf;
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
for (i = 0; i < size; i += 4, buf_32++, addr += 4) {
/* write data */
FLASH_ProgramWord(addr, *buf_32);
read_data = *(uint32_t *)addr;
/* check data */
if (read_data != *buf_32) {
return -1;
}
}
FLASH_Lock();
return size;
}
static int erase(long offset, size_t size)
{
size_t i;
FLASH_Status flash_status;
size_t erase_pages;
uint32_t addr = stm32f1_onchip_flash.addr + offset;
/* calculate pages */
erase_pages = size / PAGE_SIZE_ONCHIP;
if (size % PAGE_SIZE_ONCHIP != 0) {
erase_pages++;
}
/* start erase */
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
for (i = 0; i < erase_pages; i++) {
flash_status = FLASH_ErasePage(addr + (PAGE_SIZE_ONCHIP * i));
if (flash_status != FLASH_COMPLETE) {
return -1;
}
}
FLASH_Lock();
return size;
}
const struct fal_flash_dev stm32f1_onchip_flash =
{
.name = "onchipflash",
.addr = 0x0800C200,
.len = 256*1024,
.blk_size = 2*1024,
.ops = {init, read, write, erase},
.write_gran = 32
};
如果是使用rtthread-nano移植的话,还要修改fal_def.h
extern void fal_print(const char *format, ...);
#ifndef FAL_MALLOC
#define FAL_MALLOC malloc
#endif
#ifndef FAL_CALLOC
#define FAL_CALLOC calloc
#endif
#ifndef FAL_REALLOC
#define FAL_REALLOC realloc
#endif
#ifndef FAL_FREE
#define FAL_FREE free
#endif
#ifndef FAL_PRINTF
#define FAL_PRINTF fal_print //printf
#endif
#ifndef FAL_DEBUG
#define FAL_DEBUG 0
#endif
第五步:调试接
根据fal.h提供的接口使用即可,这里不作过多解释。效果展示如下:
总结
这样就完成了FAL的简单移植,实际项目中可以结合其他模块联合使用,效果还是很不错的。