AUTOSAR进阶图解==>AUTOSAR_SWS_FlashEEPROMEmulation
AUTOSAR Flash EEPROM Emulation (FEE) 模块架构详解
目录
- 1. 概述
- 1.1 FEE模块的作用
- 1.2 核心功能
- 2. 模块架构
- 2.1 整体架构图
- 2.2 架构层次分析
- 3. 虚拟地址方案
- 3.1 地址方案结构图
- 3.2 地址计算机制
- 4. 状态机管理
- 4.1 状态转换图
- 4.2 状态管理机制
- 5. 操作序列
- 5.1 写操作序列图
- 5.2 异步操作机制
- 6. 配置模型
- 6.1 配置结构图
- 6.2 配置参数详解
- 7. 错误处理
- 7.1 错误分类图
- 7.2 错误处理策略
- 8. 总结
1. 概述
1.1 FEE模块的作用
Flash EEPROM Emulation (FEE) 模块是AUTOSAR内存硬件抽象层的核心组件,主要功能是为上层应用提供类似EEPROM的存储服务,同时利用Flash存储器的特性实现高效的数据管理。
FEE模块的主要作用包括:
- 虚拟地址空间管理:提供32位虚拟线性地址空间,抽象底层Flash的物理地址
- 写入周期均衡:通过智能算法分散写入操作,延长Flash存储器寿命
- 即时数据支持:为高优先级数据提供快速写入通道,确保关键数据的及时存储
- 块完整性保护:提供数据一致性检查和错误恢复机制
1.2 核心功能
根据AUTOSAR 4.4.0规范,FEE模块实现以下核心功能:
-
地址转换服务:
- 16位块号 + 16位块内偏移的虚拟地址方案
- 虚拟页面到物理页面的映射机制
- 支持最大64KB的单个逻辑块大小
-
生命周期管理:
- 写入周期计数和分布管理
- 磨损均衡算法实现
- 内存区域的动态重分配
-
数据完整性保障:
- 写操作的原子性保证
- 电源故障时的数据保护
- 损坏块的检测和标记
2. 模块架构
2.1 整体架构图
该架构图展示了FEE模块在AUTOSAR软件栈中的位置及其与其他模块的交互关系。
2.2 架构层次分析
应用层 (Application Layer)
组件 NVRAM Manager (NvM):
- 职责:非易失性内存的统一管理接口
- 功能点:
- 为应用软件组件提供统一的NV数据访问接口
- 管理不同类型的NV存储设备(EEPROM、Flash等)
- 实现数据的冗余存储和错误恢复
- 提供块管理和数据集管理功能
/* NVRAM Manager接口示例 */
Std_ReturnType NvM_ReadBlock(NvM_BlockIdType BlockId, void* NvM_DstPtr);
Std_ReturnType NvM_WriteBlock(NvM_BlockIdType BlockId, const void* NvM_SrcPtr);
Std_ReturnType NvM_EraseNvBlock(NvM_BlockIdType BlockId);
Std_ReturnType NvM_InvalidateNvBlock(NvM_BlockIdType BlockId);
内存硬件抽象层 (Memory Hardware Abstraction Layer)
组件 Memory Abstraction Interface (MemIf):
- 职责:内存抽象接口,统一不同内存驱动的访问方式
- 功能点:
- 提供设备无关的内存访问接口
- 支持多个内存设备的并发访问
- 实现内存操作的统一状态管理
组件 Flash EEPROM Emulation (FEE):
- 职责:Flash存储器的EEPROM仿真
- 核心子组件:
- 虚拟地址管理:实现32位虚拟地址空间到物理地址的转换
- 块管理:逻辑块的创建、删除和维护
- 生命周期管理:写入周期统计和磨损均衡
- 即时数据处理:高优先级数据的快速写入通道
- 内部管理操作:垃圾回收、数据重组等后台任务
/* FEE模块核心数据结构 */
typedef struct {uint16 blockNumber; /* 逻辑块号 */uint16 blockSize; /* 块大小(字节) */uint32 writeCount; /* 写入次数统计 */boolean immediateData; /* 是否为即时数据 */Fee_BlockStatusType status; /* 块状态 */
} Fee_BlockInfoType;/* 虚拟地址管理 */
typedef struct {uint16 blockNumber; /* 16位块号 */uint16 blockOffset; /* 16位块内偏移 */
} Fee_VirtualAddressType;/* 物理地址计算函数 */
Fls_AddressType Fee_CalculatePhysicalAddress(Fee_VirtualAddressType virtualAddr)
{Fls_AddressType physicalAddr;uint16 virtualPageSize = Fee_ConfigPtr->virtualPageSize;/* 基础物理地址计算 */physicalAddr = (virtualAddr.blockNumber * virtualPageSize) + virtualAddr.blockOffset;/* 考虑磨损均衡的地址重映射 */physicalAddr = Fee_Internal_ApplyWearLeveling(physicalAddr, virtualAddr.blockNumber);return physicalAddr;
}
驱动层 (Driver Layer)
组件 Flash Driver (Fls):
- 职责:Flash存储器的底层驱动
- 功能点:
- 提供Flash存储器的读写擦除操作
- 实现硬件相关的地址管理
- 提供异步操作和状态查询接口
/* Flash驱动接口 */
Std_ReturnType Fls_Read(Fls_AddressType SourceAddress, uint8* TargetAddressPtr, Fls_LengthType Length);
Std_ReturnType Fls_Write(Fls_AddressType TargetAddress, const uint8* SourceAddressPtr, Fls_LengthType Length);
Std_ReturnType Fls_Erase(Fls_AddressType TargetAddress, Fls_LengthType Length);
Std_ReturnType Fls_Compare(Fls_AddressType SourceAddress, const uint8* TargetAddressPtr, Fls_LengthType Length);
3. 虚拟地址方案
3.1 地址方案结构图
该图展示了FEE模块的虚拟地址方案和内存分段结构。
3.2 地址计算机制
虚拟地址结构 (32位)
组件 虚拟地址结构:
- 功能:提供统一的32位虚拟地址空间抽象
- 关键属性:
- 高16位 (块号):
- 描述:标识逻辑块的唯一编号
- 类型:uint16
- 取值范围:0x0001-0xFFFE (0x0000和0xFFFF保留)
- 约束:必须在配置中预先定义,不能动态分配
- 来源:系统配置工具根据应用需求分配
- 低16位 (块内偏移):
- 描述:块内数据的字节偏移量
- 类型:uint16
- 取值范围:0x0000-0xFFFF
- 约束:不能超过配置的块大小
- 来源:运行时由上层应用指定
- 高16位 (块号):
/* 虚拟地址结构实现 */
typedef union {uint32 address;struct {uint16 offset; /* 低16位:块内偏移 */uint16 blockNumber; /* 高16位:块号 */} fields;
} Fee_VirtualAddress32Type;/* 地址分解函数 */
void Fee_ParseVirtualAddress(uint32 virtualAddress, uint16* blockNumber, uint16* offset)
{Fee_VirtualAddress32Type addr;addr.address = virtualAddress;*blockNumber = addr.fields.blockNumber;*offset = addr.fields.offset;
}
虚拟页面配置
组件 虚拟页面配置:
- 功能:定义虚拟页面大小和对齐要求,简化地址计算
- 关键属性:
- 虚拟页面大小 (FeeVirtualPageSize):
- 描述:逻辑块对齐的基本单位
- 类型:uint16
- 取值范围:必须是物理页面大小的整数倍
- 默认值:8字节(典型配置)
- 约束:必须满足底层Flash驱动的对齐要求
- 来源:根据Flash设备特性和性能要求配置
- 虚拟页面大小 (FeeVirtualPageSize):
/* 虚拟页面管理 */
#define FEE_VIRTUAL_PAGE_SIZE 8U /* 8字节虚拟页面 */
#define FEE_PHYSICAL_PAGE_SIZE 4U /* 4字节物理页面 *//* 页面对齐检查 */
boolean Fee_IsVirtualPageAligned(uint16 size)
{return ((size % FEE_VIRTUAL_PAGE_SIZE) == 0U);
}/* 计算所需虚拟页面数 */
uint16 Fee_CalculateVirtualPages(uint16 blockSize)
{return (blockSize + FEE_VIRTUAL_PAGE_SIZE - 1U) / FEE_VIRTUAL_PAGE_SIZE;
}
数据集支持
组件 数据集支持:
- 功能:支持同一逻辑块的多个版本,提高数据可靠性
- 关键属性:
- 数据集索引位数:
- 描述:用于编码数据集索引的位数
- 类型:uint8
- 取值范围:通常为2-4位
- 约束:由NVRAM管理器的NVM_DATASET_SELECTION_BITS参数决定
- 来源:NVRAM管理器配置
- 数据集索引位数:
/* 数据集索引处理 */
#define NVM_DATASET_SELECTION_BITS 4U /* 4位数据集索引 */
#define NVM_DATASET_MASK 0x0FU /* 数据集掩码 */
#define NVM_BLOCK_NUMBER_MASK 0xFFF0U /* 块号掩码 *//* 提取真实块号(去除数据集索引) */
uint16 Fee_ExtractBlockNumber(uint16 nvmBlockId)
{return (nvmBlockId & NVM_BLOCK_NUMBER_MASK) >> NVM_DATASET_SELECTION_BITS;
}/* 提取数据集索引 */
uint8 Fee_ExtractDatasetIndex(uint16 nvmBlockId)
{return (uint8)(nvmBlockId & NVM_DATASET_MASK);
}
4. 状态机管理
4.1 状态转换图
该状态图展示了FEE模块的完整状态转换逻辑和各状态的特征。
4.2 状态管理机制
状态 MEMIF_UNINIT
状态 MEMIF_UNINIT:
- 含义:模块未初始化状态,系统复位后的初始状态
- 特征:
- 所有API调用被拒绝(除Fee_Init外)
- 模块内部变量未初始化
- 不接受任何数据操作请求
- 进入条件:系统复位或模块重启
- 退出条件:调用Fee_Init函数成功
状态 MEMIF_BUSY_INTERNAL
状态 MEMIF_BUSY_INTERNAL:
- 含义:内部管理操作状态,模块正在执行内部维护任务
- 特征:
- 初始化过程进行中
- 垃圾回收操作执行中
- 磨损均衡算法运行中
- 可接受Fee_SetMode调用
- 进入条件:异步初始化开始或内部管理操作触发
- 退出条件:内部操作完成
状态 MEMIF_IDLE
状态 MEMIF_IDLE:
- 含义:空闲状态,模块准备接受新的操作请求
- 特征:
- 可接受所有API调用
- 没有正在进行的操作
- 可立即处理新请求
- 进入条件:初始化完成或操作执行完毕
- 退出条件:接收到新的操作请求
状态 MEMIF_BUSY
状态 MEMIF_BUSY:
- 含义:忙碌状态,正在处理上层模块的数据操作请求
- 特征:
- 正在执行读/写/擦除/无效化操作
- 拒绝新的数据操作请求
- 可接受Fee_Cancel调用
- 进入条件:开始执行数据操作
- 退出条件:操作完成、失败或被取消
/* 状态机实现 */
typedef enum {MEMIF_UNINIT, /* 未初始化 */MEMIF_IDLE, /* 空闲 */MEMIF_BUSY, /* 忙碌 */MEMIF_BUSY_INTERNAL /* 内部忙碌 */
} MemIf_StatusType;static MemIf_StatusType Fee_ModuleStatus = MEMIF_UNINIT;/* 状态查询函数 */
MemIf_StatusType Fee_GetStatus(void)
{return Fee_ModuleStatus;
}/* 状态转换函数 */
void Fee_SetStatus(MemIf_StatusType newStatus)
{Fee_ModuleStatus = newStatus;
}/* 状态转换验证 */
boolean Fee_IsValidStatusTransition(MemIf_StatusType fromStatus, MemIf_StatusType toStatus)
{boolean isValid = FALSE;switch (fromStatus) {case MEMIF_UNINIT:if ((toStatus == MEMIF_IDLE) || (toStatus == MEMIF_BUSY_INTERNAL)) {isValid = TRUE;}break;case MEMIF_IDLE:if ((toStatus == MEMIF_BUSY) || (toStatus == MEMIF_BUSY_INTERNAL)) {isValid = TRUE;}break;case MEMIF_BUSY:if (toStatus == MEMIF_IDLE) {isValid = TRUE;}break;case MEMIF_BUSY_INTERNAL:if (toStatus == MEMIF_IDLE) {isValid = TRUE;}break;default:break;}return isValid;
}
5. 操作序列
5.1 写操作序列图
该序列图详细展示了FEE模块写操作的完整流程,包括参数验证、异步处理和结果通知。
5.2 异步操作机制
参与者 NVRAM Manager (NvM)
参与者 NvM:
- 角色:非易失性内存管理器,提供统一的NV数据访问接口
- 职责:
- 管理应用层的NV数据访问请求
- 协调不同类型的NV存储设备
- 实现数据的冗余和一致性管理
- 处理存储操作的结果和错误
参与者 Memory Interface (MemIf)
参与者 MemIf:
- 角色:内存抽象接口,统一不同内存驱动的访问
- 职责:
- 提供设备无关的内存访问接口
- 路由内存操作到相应的驱动模块
- 管理多个内存设备的并发访问
- 维护内存操作的统一状态
操作组 FEE写操作流程
操作组 FEE写操作流程:
- 场景:上层应用请求写入数据到Flash存储器
- 触发条件:应用调用NvM写入接口
函数 Fee_Write
函数 Fee_Write:
- 描述:启动异步写操作的主要接口函数,负责参数验证和操作初始化
- 参数:
- BlockNumber [输入]:逻辑块号,标识要写入的目标块,类型:uint16,取值范围:1-65534
- DataBufferPtr [输入]:指向源数据缓冲区的指针,类型:const uint8*,约束:不能为NULL
- 返回值:
- E_OK:请求已被接受,将异步执行
- E_NOT_OK:请求被拒绝,可能因为模块状态不正确或参数无效
- 相关函数:
- 上层:MemIf_Write - 内存抽象接口的写入函数
- 下层:Fls_Write - Flash驱动的写入函数
- 并列:Fee_Read, Fee_Erase - 其他数据操作函数
/* Fee_Write函数实现 */
Std_ReturnType Fee_Write(uint16 BlockNumber, const uint8* DataBufferPtr)
{Std_ReturnType result = E_NOT_OK;/* 开发错误检测 */if (Fee_ModuleStatus == MEMIF_UNINIT) {#if (FEE_DEV_ERROR_DETECT == STD_ON)Det_ReportError(FEE_MODULE_ID, FEE_INSTANCE_ID, FEE_WRITE_ID, FEE_E_UNINIT);#endifreturn E_NOT_OK;}/* 运行时状态检查 */if (Fee_ModuleStatus == MEMIF_BUSY) {#if (FEE_DEV_ERROR_DETECT == STD_ON)Det_ReportRuntimeError(FEE_MODULE_ID, FEE_INSTANCE_ID, FEE_WRITE_ID, FEE_E_BUSY);#endifreturn E_NOT_OK;}/* 参数验证 */if (!Fee_IsValidBlockNumber(BlockNumber)) {#if (FEE_DEV_ERROR_DETECT == STD_ON)Det_ReportError(FEE_MODULE_ID, FEE_INSTANCE_ID, FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO);#endifreturn E_NOT_OK;}if (DataBufferPtr == NULL_PTR) {#if (FEE_DEV_ERROR_DETECT == STD_ON)Det_ReportError(FEE_MODULE_ID, FEE_INSTANCE_ID, FEE_WRITE_ID, FEE_E_PARAM_POINTER);#endifreturn E_NOT_OK;}/* 接受请求 */if ((Fee_ModuleStatus == MEMIF_IDLE) || (Fee_ModuleStatus == MEMIF_BUSY_INTERNAL)) {/* 保存请求参数 */Fee_CurrentJob.blockNumber = BlockNumber;Fee_CurrentJob.dataBufferPtr = DataBufferPtr;Fee_CurrentJob.jobType = FEE_JOB_WRITE;/* 标记块为损坏状态(写操作开始) */Fee_MarkBlockCorrupted(BlockNumber);/* 更新模块状态 */Fee_ModuleStatus = MEMIF_BUSY;Fee_JobResult = MEMIF_JOB_PENDING;result = E_OK;}return result;
}
函数 Fee_MainFunction
函数 Fee_MainFunction:
- 描述:主函数负责异步执行写操作的实际处理,包括地址计算、擦除和写入
- 参数:无参数,由调度器周期性调用
- 返回值:无返回值
- 相关函数:
- 下层:Fls_Erase, Fls_Write - Flash驱动操作函数
- 并列:Fee_JobEndNotification - 操作完成通知
/* Fee_MainFunction实现 */
void Fee_MainFunction(void)
{if (Fee_ModuleStatus == MEMIF_BUSY) {switch (Fee_CurrentJob.jobType) {case FEE_JOB_WRITE:Fee_ProcessWriteJob();break;case FEE_JOB_READ:Fee_ProcessReadJob();break;case FEE_JOB_ERASE:Fee_ProcessEraseJob();break;default:/* 错误处理 */break;}}else if (Fee_ModuleStatus == MEMIF_BUSY_INTERNAL) {/* 处理内部管理操作 */Fee_ProcessInternalOperations();}
}/* 写操作处理 */
static void Fee_ProcessWriteJob(void)
{Fls_AddressType physicalAddress;Fls_LengthType blockSize;Std_ReturnType result;switch (Fee_WriteJobState) {case FEE_WRITE_STATE_CALC_ADDRESS:/* 计算物理地址 */physicalAddress = Fee_CalculatePhysicalAddress(Fee_CurrentJob.blockNumber);Fee_CurrentJob.targetAddress = physicalAddress;Fee_WriteJobState = FEE_WRITE_STATE_CHECK_ERASE;break;case FEE_WRITE_STATE_CHECK_ERASE:/* 检查是否需要擦除 */if (Fee_IsEraseRequired(Fee_CurrentJob.targetAddress)) {Fee_WriteJobState = FEE_WRITE_STATE_ERASE;} else {Fee_WriteJobState = FEE_WRITE_STATE_WRITE;}break;case FEE_WRITE_STATE_ERASE:/* 执行擦除操作 */blockSize = Fee_GetBlockSize(Fee_CurrentJob.blockNumber);result = Fls_Erase(Fee_CurrentJob.targetAddress, blockSize);if (result == E_OK) {Fee_WriteJobState = FEE_WRITE_STATE_ERASE_WAIT;} else {Fee_ProcessJobError();}break;case FEE_WRITE_STATE_ERASE_WAIT:/* 等待擦除完成 */if (Fls_GetJobResult() == MEMIF_JOB_OK) {Fee_WriteJobState = FEE_WRITE_STATE_WRITE;} else if (Fls_GetJobResult() == MEMIF_JOB_FAILED) {Fee_ProcessJobError();}break;case FEE_WRITE_STATE_WRITE:/* 执行写入操作 */blockSize = Fee_GetBlockSize(Fee_CurrentJob.blockNumber);result = Fls_Write(Fee_CurrentJob.targetAddress, Fee_CurrentJob.dataBufferPtr, blockSize);if (result == E_OK) {Fee_WriteJobState = FEE_WRITE_STATE_WRITE_WAIT;} else {Fee_ProcessJobError();}break;case FEE_WRITE_STATE_WRITE_WAIT:/* 等待写入完成 */if (Fls_GetJobResult() == MEMIF_JOB_OK) {Fee_ProcessJobSuccess();} else if (Fls_GetJobResult() == MEMIF_JOB_FAILED) {Fee_ProcessJobError();}break;default:Fee_ProcessJobError();break;}
}
6. 配置模型
6.1 配置结构图
该配置模型图展示了FEE模块的完整配置结构,包括通用配置和块特定配置。
6.2 配置参数详解
类 FeeGeneral
类 FeeGeneral:
- 功能:通用配置参数容器,包含非块特定的全局配置
- 关键属性:
- FeeDevErrorDetect:
- 描述:开发错误检测和通知的开关
- 类型:EcucBooleanParamDef
- 取值范围:true/false
- 默认值:false
- 约束:仅在开发阶段启用,产品版本通常禁用
- 来源:开发配置需求
- FeeMainFunctionPeriod:
- 描述:主函数连续调用之间的时间间隔(秒)
- 类型:EcucFloatParamDef
- 取值范围:>0的浮点数
- 约束:必须与调度器配置匹配
- 来源:系统时序要求和性能需求
- FeeVirtualPageSize:
- 描述:逻辑块对齐的虚拟页面大小
- 类型:EcucIntegerParamDef
- 取值范围:0-65535字节
- 约束:必须是物理页面大小的整数倍
- 来源:Flash设备特性和对齐要求
- FeeDevErrorDetect:
/* FEE通用配置结构 */
typedef struct {boolean devErrorDetect; /* 开发错误检测 */float32 mainFunctionPeriod; /* 主函数周期(秒) */uint16 virtualPageSize; /* 虚拟页面大小 */boolean pollingMode; /* 轮询模式 */boolean versionInfoApi; /* 版本信息API */boolean setModeSupported; /* 模式设置支持 *//* 可选的通知函数指针 */void (*jobEndNotification)(void); /* 作业完成通知 */void (*jobErrorNotification)(void); /* 作业错误通知 */
} Fee_GeneralConfigType;/* 通用配置初始化示例 */
const Fee_GeneralConfigType Fee_GeneralConfig = {.devErrorDetect = FALSE, /* 产品版本禁用DET */.mainFunctionPeriod = 0.01f, /* 10ms周期 */.virtualPageSize = 8U, /* 8字节虚拟页面 */.pollingMode = FALSE, /* 使用中断模式 */.versionInfoApi = FALSE, /* 禁用版本API */.setModeSupported = TRUE, /* 支持模式切换 */.jobEndNotification = NvM_JobEndNotification,.jobErrorNotification = NvM_JobErrorNotification
};
类 FeeBlockConfiguration
类 FeeBlockConfiguration:
- 功能:块特定配置参数,定义每个逻辑块的属性
- 关键属性:
- FeeBlockNumber:
- 描述:逻辑块的唯一标识符(句柄)
- 类型:EcucIntegerParamDef (Symbolic Name)
- 取值范围:1-65534
- 约束:0x0000和0xFFFF保留不用,必须考虑数据集选择位
- 来源:应用需求和NVRAM管理器配置
- FeeBlockSize:
- 描述:逻辑块的大小(字节)
- 类型:EcucIntegerParamDef
- 取值范围:1-65535字节
- 约束:必须是虚拟页面大小的整数倍
- 来源:应用数据结构大小
- FeeNumberOfWriteCycles:
- 描述:该块要求的写入周期数
- 类型:EcucIntegerParamDef
- 取值范围:0-4294967295
- 约束:不能超过底层Flash设备的擦写次数规格
- 来源:应用的数据更新频率需求
- FeeBlockNumber:
/* 块配置结构 */
typedef struct {uint16 blockNumber; /* 块号 */uint16 blockSize; /* 块大小 */boolean immediateData; /* 即时数据标志 */uint32 numberOfWriteCycles; /* 写入周期数 */uint8 deviceIndex; /* 设备索引 */
} Fee_BlockConfigType;/* 块配置数组示例 */
const Fee_BlockConfigType Fee_BlockConfig[] = {/* 配置块:应用参数存储 */{.blockNumber = 1U,.blockSize = 32U, /* 32字节,4个虚拟页面 */.immediateData = FALSE,.numberOfWriteCycles = 10000U, /* 1万次写入周期 */.deviceIndex = 0U},/* 即时数据块:关键状态信息 */{.blockNumber = 100U,.blockSize = 16U, /* 16字节,2个虚拟页面 */.immediateData = TRUE, /* 即时数据,预擦除 */.numberOfWriteCycles = 100000U, /* 10万次写入周期 */.deviceIndex = 0U},/* 大容量数据块:标定数据 */{.blockNumber = 200U,.blockSize = 1024U, /* 1KB,128个虚拟页面 */.immediateData = FALSE,.numberOfWriteCycles = 1000U, /* 1千次写入周期 */.deviceIndex = 0U}
};#define FEE_NUMBER_OF_BLOCKS (sizeof(Fee_BlockConfig)/sizeof(Fee_BlockConfigType))
类 FeePublishedInformation
类 FeePublishedInformation:
- 功能:发布信息容器,提供模块开销计算的参数
- 关键属性:
- FeeBlockOverhead:
- 描述:每个逻辑块的管理开销(字节)
- 类型:EcucIntegerParamDef
- 取值范围:0-65535字节
- 来源:模块实现的内部管理数据结构大小
- FeePageOverhead:
- 描述:每个页面的管理开销(字节)
- 类型:EcucIntegerParamDef
- 取值范围:0-65535字节
- 来源:页面头部、尾部等管理信息占用的空间
- FeeBlockOverhead:
/* 发布信息结构 */
typedef struct {uint16 blockOverhead; /* 每块开销 */uint16 pageOverhead; /* 每页开销 */
} Fee_PublishedInfoType;/* 开销计算函数 */
uint32 Fee_CalculateTotalOverhead(uint16 numberOfBlocks, uint16 numberOfPages)
{uint32 totalOverhead;totalOverhead = (numberOfBlocks * Fee_PublishedInfo.blockOverhead) +(numberOfPages * Fee_PublishedInfo.pageOverhead);return totalOverhead;
}/* 内存需求计算 */
uint32 Fee_CalculateMemoryRequirement(const Fee_BlockConfigType* blockConfigs, uint16 numBlocks)
{uint32 totalDataSize = 0U;uint32 totalPages = 0U;uint16 i;/* 计算数据大小和页面数 */for (i = 0U; i < numBlocks; i++) {totalDataSize += blockConfigs[i].blockSize;totalPages += Fee_CalculateVirtualPages(blockConfigs[i].blockSize);}/* 加上管理开销 */totalDataSize += Fee_CalculateTotalOverhead(numBlocks, totalPages);return totalDataSize;
}
7. 错误处理
7.1 错误分类图
该错误处理图展示了FEE模块的完整错误分类体系和处理机制。
7.2 错误处理策略
类 开发错误 (Development Errors)
类 开发错误:
- 功能:开发阶段的参数和状态检查,帮助发现集成问题
- 关键属性:
- FEE_E_UNINIT (0x01):
- 描述:模块未初始化时调用API服务
- 检测条件:Fee_ModuleStatus == MEMIF_UNINIT
- 处理方式:调用Det_ReportError,返回E_NOT_OK
- 影响:API调用被拒绝,模块状态不变
- FEE_E_INVALID_BLOCK_NO (0x02):
- 描述:使用了无效或未配置的块号
- 检测条件:块号不在配置范围内或为保留值
- 处理方式:调用Det_ReportError,返回E_NOT_OK
- 影响:操作被拒绝,不进行任何处理
- FEE_E_PARAM_POINTER (0x04):
- 描述:API调用时传入了空指针
- 检测条件:关键指针参数为NULL_PTR
- 处理方式:调用Det_ReportError,返回E_NOT_OK
- 影响:操作被拒绝,避免内存访问错误
- FEE_E_UNINIT (0x01):
/* 开发错误检测宏 */
#if (FEE_DEV_ERROR_DETECT == STD_ON)
#define FEE_DET_REPORT_ERROR(ApiId, ErrorId) \Det_ReportError(FEE_MODULE_ID, FEE_INSTANCE_ID, (ApiId), (ErrorId))
#else
#define FEE_DET_REPORT_ERROR(ApiId, ErrorId)
#endif/* 参数验证函数 */
boolean Fee_ValidateBlockNumber(uint16 BlockNumber, uint8 ApiId)
{boolean isValid = TRUE;if ((BlockNumber == 0U) || (BlockNumber == 0xFFFFU)) {FEE_DET_REPORT_ERROR(ApiId, FEE_E_INVALID_BLOCK_NO);isValid = FALSE;}else if (!Fee_IsBlockConfigured(BlockNumber)) {FEE_DET_REPORT_ERROR(ApiId, FEE_E_INVALID_BLOCK_NO);isValid = FALSE;}return isValid;
}boolean Fee_ValidatePointer(const void* Pointer, uint8 ApiId)
{boolean isValid = TRUE;if (Pointer == NULL_PTR) {FEE_DET_REPORT_ERROR(ApiId, FEE_E_PARAM_POINTER);isValid = FALSE;}return isValid;
}
类 运行时错误 (Runtime Errors)
类 运行时错误:
- 功能:运行时状态相关的错误检测和报告
- 关键属性:
- FEE_E_BUSY (0x06):
- 描述:模块忙碌时尝试启动新的数据操作
- 检测条件:Fee_ModuleStatus == MEMIF_BUSY
- 处理方式:调用Det_ReportRuntimeError,返回E_NOT_OK
- 影响:新请求被拒绝,当前操作继续执行
- FEE_E_INVALID_CANCEL (0x08):
- 描述:没有正在进行的作业时调用取消操作
- 检测条件:Fee_ModuleStatus != MEMIF_BUSY
- 处理方式:调用Det_ReportRuntimeError
- 影响:取消操作被忽略
- FEE_E_BUSY (0x06):
/* 运行时错误处理 */
Std_ReturnType Fee_CheckModuleStatus(uint8 ApiId)
{Std_ReturnType result = E_OK;if (Fee_ModuleStatus == MEMIF_UNINIT) {FEE_DET_REPORT_ERROR(ApiId, FEE_E_UNINIT);result = E_NOT_OK;}else if (Fee_ModuleStatus == MEMIF_BUSY) {#if (FEE_DEV_ERROR_DETECT == STD_ON)Det_ReportRuntimeError(FEE_MODULE_ID, FEE_INSTANCE_ID, ApiId, FEE_E_BUSY);#endifresult = E_NOT_OK;}return result;
}
类 块完整性管理
类 块完整性管理:
- 功能:保护数据完整性,检测和处理数据损坏
- 关键特性:
- 写操作原子性:写操作开始时标记块为"损坏",成功完成后标记为"未损坏"
- 一致性检查:读取时验证块的完整性,检测中断的写操作
- 电源故障保护:通过状态标记和校验机制保护关键数据
- 损坏块隔离:将检测到的损坏块标记为不可用,防止数据污染
/* 块完整性管理 */
typedef enum {FEE_BLOCK_STATUS_OK, /* 块正常 */FEE_BLOCK_STATUS_CORRUPTED, /* 块损坏 */FEE_BLOCK_STATUS_INCONSISTENT, /* 块不一致 */FEE_BLOCK_STATUS_INVALID /* 块无效 */
} Fee_BlockStatusType;/* 块状态管理结构 */
typedef struct {uint16 blockNumber;Fee_BlockStatusType status;uint32 writeCount;uint32 checksum;
} Fee_BlockStatusInfoType;/* 标记块为损坏 */
void Fee_MarkBlockCorrupted(uint16 BlockNumber)
{Fee_BlockStatusInfoType* blockInfo;blockInfo = Fee_GetBlockStatusInfo(BlockNumber);if (blockInfo != NULL_PTR) {blockInfo->status = FEE_BLOCK_STATUS_CORRUPTED;/* 将状态信息写入NV存储 */Fee_WriteBlockStatusToNV(blockInfo);}
}/* 标记块为正常 */
void Fee_MarkBlockOK(uint16 BlockNumber)
{Fee_BlockStatusInfoType* blockInfo;blockInfo = Fee_GetBlockStatusInfo(BlockNumber);if (blockInfo != NULL_PTR) {blockInfo->status = FEE_BLOCK_STATUS_OK;blockInfo->writeCount++;/* 重新计算校验和 */blockInfo->checksum = Fee_CalculateBlockChecksum(BlockNumber);/* 将状态信息写入NV存储 */Fee_WriteBlockStatusToNV(blockInfo);}
}/* 检查块完整性 */
MemIf_JobResultType Fee_CheckBlockIntegrity(uint16 BlockNumber)
{Fee_BlockStatusInfoType* blockInfo;uint32 calculatedChecksum;MemIf_JobResultType result;blockInfo = Fee_GetBlockStatusInfo(BlockNumber);if (blockInfo == NULL_PTR) {return MEMIF_BLOCK_INVALID;}switch (blockInfo->status) {case FEE_BLOCK_STATUS_OK:/* 验证校验和 */calculatedChecksum = Fee_CalculateBlockChecksum(BlockNumber);if (calculatedChecksum == blockInfo->checksum) {result = MEMIF_JOB_OK;} else {result = MEMIF_BLOCK_INCONSISTENT;/* 自动标记为损坏 */Fee_MarkBlockCorrupted(BlockNumber);}break;case FEE_BLOCK_STATUS_CORRUPTED:result = MEMIF_BLOCK_INCONSISTENT;break;case FEE_BLOCK_STATUS_INVALID:result = MEMIF_BLOCK_INVALID;break;default:result = MEMIF_BLOCK_INCONSISTENT;break;}return result;
}
类 错误恢复机制
类 错误恢复机制:
- 功能:实现模块级和块级的错误恢复策略
- 关键特性:
- 优雅降级:在部分功能失效时仍能提供基本服务
- 自动重试:对临时性错误进行有限次数的重试
- 状态恢复:从错误状态安全返回到可操作状态
- 错误隔离:防止单个块的错误影响其他块的操作
/* 错误恢复机制 */
typedef struct {uint8 retryCount; /* 重试次数 */uint8 maxRetries; /* 最大重试次数 */boolean recoveryMode; /* 恢复模式标志 */Fee_JobType failedJobType; /* 失败的作业类型 */
} Fee_ErrorRecoveryType;static Fee_ErrorRecoveryType Fee_ErrorRecovery;/* 错误恢复处理 */
void Fee_ProcessJobError(void)
{/* 增加重试计数 */Fee_ErrorRecovery.retryCount++;if (Fee_ErrorRecovery.retryCount <= Fee_ErrorRecovery.maxRetries) {/* 重试操作 */Fee_RetryCurrentJob();} else {/* 重试次数用完,进入错误处理 */switch (Fee_CurrentJob.jobType) {case FEE_JOB_WRITE:/* 标记块为损坏 */Fee_MarkBlockCorrupted(Fee_CurrentJob.blockNumber);Fee_JobResult = MEMIF_JOB_FAILED;break;case FEE_JOB_READ:/* 返回块不一致状态 */Fee_JobResult = MEMIF_BLOCK_INCONSISTENT;break;case FEE_JOB_ERASE:/* 标记擦除失败 */Fee_JobResult = MEMIF_JOB_FAILED;break;default:Fee_JobResult = MEMIF_JOB_FAILED;break;}/* 恢复到空闲状态 */Fee_ModuleStatus = MEMIF_IDLE;/* 通知上层错误 */if (Fee_GeneralConfig.jobErrorNotification != NULL_PTR) {Fee_GeneralConfig.jobErrorNotification();}/* 重置错误恢复状态 */Fee_ErrorRecovery.retryCount = 0U;}
}/* 作业成功处理 */
void Fee_ProcessJobSuccess(void)
{switch (Fee_CurrentJob.jobType) {case FEE_JOB_WRITE:/* 标记块为正常 */Fee_MarkBlockOK(Fee_CurrentJob.blockNumber);break;case FEE_JOB_READ:/* 验证读取的数据完整性 */if (Fee_CheckBlockIntegrity(Fee_CurrentJob.blockNumber) != MEMIF_JOB_OK) {Fee_ProcessJobError();return;}break;default:break;}/* 设置作业结果 */Fee_JobResult = MEMIF_JOB_OK;/* 恢复到空闲状态 */Fee_ModuleStatus = MEMIF_IDLE;/* 通知上层成功 */if (Fee_GeneralConfig.jobEndNotification != NULL_PTR) {Fee_GeneralConfig.jobEndNotification();}/* 重置错误恢复状态 */Fee_ErrorRecovery.retryCount = 0U;
}
8. 总结
8.1 FEE模块优势
Flash EEPROM Emulation (FEE) 模块作为AUTOSAR内存硬件抽象层的核心组件,具有以下主要优势:
-
统一抽象接口:
- 为上层应用提供类似EEPROM的统一访问接口
- 屏蔽底层Flash存储器的硬件差异
- 支持多种Flash设备类型的透明切换
-
高效的存储管理:
- 32位虚拟地址空间提供灵活的内存布局
- 虚拟页面机制简化地址计算和管理
- 支持最大64KB的单个逻辑块,满足大容量数据存储需求
-
可靠性保障:
- 写入周期均衡延长Flash存储器使用寿命
- 完整的数据完整性检查和错误恢复机制
- 即时数据支持确保关键信息的快速存储
-
灵活的配置能力:
- 支持块级别的独立配置
- 可配置的写入周期数和存储策略
- 适应不同应用场景的存储需求
8.2 应用场景
FEE模块特别适用于以下应用场景:
- 汽车电子控制单元 (ECU):存储标定参数、故障代码、学习值等
- 工业控制系统:配置数据、运行参数、历史记录的持久化存储
- 嵌入式系统:需要频繁更新且要求高可靠性的数据存储
- 物联网设备:设备配置、状态信息、传感器数据的本地存储
通过本文的详细分析,我们可以看到FEE模块通过精心设计的架构、状态管理、地址方案和错误处理机制,为AUTOSAR系统提供了一个功能强大、可靠性高的Flash存储解决方案。其模块化设计和标准化接口使得它能够很好地集成到各种AUTOSAR应用中,为汽车电子和工业控制系统的数据持久化需求提供了坚实的基础。