Files
arcs/arcs-sdk/drivers/lisa_flash/lisa_flash.h
2026-08-13 16:50:52 +08:00

297 lines
9.2 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright (c) 2025, LISTENAI
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file lisa_flash.h
* @brief LISA Flash 设备驱动接口
*/
#pragma once
#include "lisa_device.h"
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/* ========================================================================
* Flash 类型定义
* ======================================================================== */
/**
* @brief Flash 参数结构体
*
* 包含 Flash 设备的运行时参数信息
* 仅包含写操作相关的基本参数,布局信息通过 page_layout 接口获取
*/
typedef struct {
size_t write_block_size; /* 最小写对齐和大小(字节) */
/**
* @brief 设备能力标志
*
* 用户代码应该通过 lisa_flash_params_get_* 辅助函数访问能力标志,
* 而不是直接访问结构体内容
*/
struct {
/**
* @brief 设备无需显式擦除
*
* 当此标志为 true 时,设备满足以下条件之一:
* - 设备在写入时自动擦除
* - 设备根本不需要擦除
* - 设备支持擦除但不强制要求擦除
*
* 对于 SPI Flash通常为 false需要显式擦除
*/
bool no_explicit_erase: 1;
} caps;
uint8_t erase_value; /* 擦除后的值,通常为 0xFF */
} lisa_flash_parameters_t;
/**
* @brief Flash 页面布局结构体
*
* 描述一组连续的、大小相同的页面
*/
typedef struct {
size_t pages_count; /* 此布局中的页面数量 */
size_t pages_size; /* 每个页面的大小(字节) */
} lisa_flash_pages_layout_t;
/* ========================================================================
* Flash 设备 API 结构体
* ======================================================================== */
typedef struct {
int (*read)(lisa_device_t *dev, size_t offset, void *data, size_t len);
int (*write)(lisa_device_t *dev, size_t offset, const void *data, size_t len);
int (*erase)(lisa_device_t *dev, size_t offset, size_t size);
const lisa_flash_parameters_t *(*get_parameters)(lisa_device_t *dev);
const lisa_flash_pages_layout_t *(*page_layout)(lisa_device_t *dev, size_t *layout_size);
} lisa_flash_api_t;
/* ========================================================================
* Flash 对外接口函数
* ======================================================================== */
/**
* @brief 从 Flash 读取数据
*
* 从指定偏移地址读取数据到缓冲区。
*
* @param dev Flash 设备指针
* @param offset 读取起始偏移地址(字节对齐)
* @param data 数据缓冲区指针
* @param len 读取长度(字节)
*
* @return 0 成功
* @return LISA_DEVICE_ERR_INVALID 参数无效
* @return LISA_DEVICE_ERR_NOT_SUPPORT 不支持该操作
* @return LISA_DEVICE_ERR_IO IO错误
* @return <0 其他错误
*
* @note 设备必须已初始化
* @note offset 和 len 必须在有效范围内
*/
static inline int lisa_flash_read(lisa_device_t *dev, size_t offset, void *data, size_t len)
{
if (!dev || !dev->api || !data) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_flash_api_t *api = (lisa_flash_api_t *)dev->api;
return api->read ? api->read(dev, offset, data, len) : LISA_DEVICE_ERR_NOT_SUPPORT;
}
/**
* @brief 向 Flash 写入数据
*
* 向指定偏移地址写入数据。
*
* @param dev Flash 设备指针
* @param offset 写入起始偏移地址(字节对齐)
* @param data 数据缓冲区指针
* @param len 写入长度(字节)
*
* @return 0 成功
* @return LISA_DEVICE_ERR_INVALID 参数无效
* @return LISA_DEVICE_ERR_NOT_SUPPORT 不支持该操作
* @return LISA_DEVICE_ERR_IO IO错误
* @return <0 其他错误
*
* @note 写入前必须先擦除目标区域
* @note offset 和 len 必须在有效范围内
*/
static inline int lisa_flash_write(lisa_device_t *dev, size_t offset, const void *data, size_t len)
{
if (!dev || !dev->api || !data) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_flash_api_t *api = (lisa_flash_api_t *)dev->api;
return api->write ? api->write(dev, offset, data, len) : LISA_DEVICE_ERR_NOT_SUPPORT;
}
/**
* @brief 擦除 Flash 区域
*
* 擦除指定偏移地址和大小的 Flash 区域。
*
* @param dev Flash 设备指针
* @param offset 擦除起始偏移地址
* @param size 擦除大小(字节)
*
* @return 0 成功
* @return LISA_DEVICE_ERR_INVALID 参数无效
* @return LISA_DEVICE_ERR_NOT_SUPPORT 不支持该操作
* @return LISA_DEVICE_ERR_IO IO错误
* @return <0 其他错误
*
* @note offset 和 size 必须按照硬件要求对齐(通常为扇区或块大小)
*/
static inline int lisa_flash_erase(lisa_device_t *dev, size_t offset, size_t size)
{
if (!dev || !dev->api) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_flash_api_t *api = (lisa_flash_api_t *)dev->api;
return api->erase ? api->erase(dev, offset, size) : LISA_DEVICE_ERR_NOT_SUPPORT;
}
/**
* @brief 获取 Flash 参数
*
* 获取 Flash 设备的运行时参数信息。
* 返回的指针指向常量结构体,在运行时保持不变。
*
* @param dev Flash 设备指针
*
* @return 指向 lisa_flash_parameters_t 结构体的指针,成功
* @return NULL 参数无效或不支持该操作
*
* @note 返回的指针指向常量数据,可以缓存该指针或复制其内容
* @note 必须在设备初始化后调用
* @note 参数包括write_block_size最小写对齐、caps能力标志、erase_value擦除值
* @note 布局信息(页大小、扇区大小、总大小)通过 lisa_flash_page_layout() 获取
* @note 建议使用辅助函数访问参数lisa_flash_params_get_*()
*/
static inline const lisa_flash_parameters_t *lisa_flash_get_parameters(lisa_device_t *dev)
{
if (!dev || !dev->api) {
return NULL;
}
lisa_flash_api_t *api = (lisa_flash_api_t *)dev->api;
return api->get_parameters ? api->get_parameters(dev) : NULL;
}
/**
* @brief 获取 Flash 页面布局
*
* 获取 Flash 设备的页面布局数组。
* 返回的数组描述了 Flash 的完整布局,包含一个或多个布局段。
*
* @param dev Flash 设备指针
* @param layout_size 输出参数,返回布局数组的元素数量
*
* @return 指向 lisa_flash_pages_layout_t 数组的指针,成功
* @return NULL 参数无效或不支持该操作
*
* @note 返回的指针指向常量数据,在运行时保持不变
* @note 必须在设备初始化后调用
* @note 对于均匀扇区的 Flashlayout_size 通常为 1
* @note 对于非均匀扇区的 Flash可能返回多个布局段
* @note 每个布局段描述一组连续的、大小相同的页面
*
* @example
* // 获取并遍历页面布局
* size_t layout_count = 0;
* const lisa_flash_pages_layout_t *layout = lisa_flash_page_layout(flash, &layout_count);
* if (layout) {
* size_t total_offset = 0;
* for (size_t i = 0; i < layout_count; i++) {
* printf("Layout %zu: %zu pages × %zu bytes (offset: 0x%zx)\n",
* i, layout[i].pages_count, layout[i].pages_size, total_offset);
* total_offset += layout[i].pages_count * layout[i].pages_size;
* }
* }
*/
static inline const lisa_flash_pages_layout_t *lisa_flash_page_layout(lisa_device_t *dev, size_t *layout_size)
{
if (!dev || !dev->api || !layout_size) {
return NULL;
}
lisa_flash_api_t *api = (lisa_flash_api_t *)dev->api;
return api->page_layout ? api->page_layout(dev, layout_size) : NULL;
}
/**
* @brief 从页面布局计算 Flash 总大小
*
* 遍历布局数组,累加所有布局段的大小。
*
* @param layout 页面布局数组指针
* @param layout_size 布局数组元素数量
*
* @return Flash 总大小(字节)
*
* @note 对于均匀布局layout_size=1返回 pages_count × pages_size
*/
static inline size_t lisa_flash_get_size_from_layout(const lisa_flash_pages_layout_t *layout, size_t layout_size)
{
size_t total_size = 0;
if (layout) {
for (size_t i = 0; i < layout_size; i++) {
total_size += layout[i].pages_count * layout[i].pages_size;
}
}
return total_size;
}
/**
* @brief 获取 Flash 参数中的写块大小
*
* @param params Flash 参数指针
*
* @return 写块大小(字节)
*/
static inline size_t lisa_flash_params_get_write_block_size(const lisa_flash_parameters_t *params)
{
return params ? params->write_block_size : 0;
}
/**
* @brief 获取 Flash 参数中的擦除值
*
* @param params Flash 参数指针
*
* @return 擦除后的值,通常为 0xFF
*/
static inline uint8_t lisa_flash_params_get_erase_value(const lisa_flash_parameters_t *params)
{
return params ? params->erase_value : 0xFF;
}
/**
* @brief 检查 Flash 是否需要显式擦除
*
* @param params Flash 参数指针
*
* @return true 无需显式擦除(设备自动擦除或不需要擦除)
* @return false 需要显式擦除(如 SPI Flash
*
* @note 对于 SPI Flash返回 false
* @note 对于 NOR Flash 等可能返回 true
*/
static inline bool lisa_flash_params_get_no_explicit_erase(const lisa_flash_parameters_t *params)
{
return params ? params->caps.no_explicit_erase : false;
}
#ifdef __cplusplus
}
#endif