【CP AUTOSAR】Fls(FlashDriver)分析和使用
文章目录前言一、原理解析一、Flash page二、Flash sector三、Flash access code四、虚拟地址和物理地址二、代码架构一、多核访问二、擦写运行冲突三、数据同步四、FLASH加锁解锁五、FLASH擦写程序异步同步六、FLASH ECC三、主要变量和类型描述四、主要代码描述五、EBTresos配置六、使用范例七、参考资料总结前言本文介绍CP AUTOSAR 架构下的Fls组件基于S32K312芯片、NXP提供的MCAL包使用EB Tresos工具进行配置的经验不具体介绍芯片FLASH、存储外设等功能。Fls组件实现MCU内部FLASH、外部FLASH的读、写、擦除、比较、块检查等功能。Fls组件允许将FLASH驱动加载到RAM里执行操作。Fls组件位于Memory Drivers层里为上层Fee提供接口Fls组件本身不关注FLASH的校验、冗余设计等这些逻辑由Fee组件完成。上图为CP AUTOSAR存储架构。一、原理解析Fls组件有以下几个功能和概念一、Flash pageFLASH可编程的单位取决于硬件性能通常一页为8BYTEFLASH每次写数据的大小需要符合数据长度%一个Flash page0也就是说一页为8BYTE的话每次写入的数据长度需要能被8整除不足的补FF。FLASH每次写入的地址也需要能被一个Flash page整除。二、Flash sectorFLASH可擦除的单位取决于硬件性能假如一个扇区是8192个字节的话FLASH每次擦除数据的大小需要符合擦除长度81920也就是说FLASH每次擦除的大小只能是8192 * X。软件里配置sector的大小时尽量跟实际的sector大小一致。三、Flash access codeFLASH执行擦除、写数据时存储在RAM里的特殊代码。因为MCU的FLASH存在不同的partition在相同的partition内代码不能同时RWW即CPU在这分区不能取指令时又执行擦写操作否则会出现硬件异常有以下例子1、擦写代码存放在ram区可以对codeflash、dataflash区进行擦写。2、擦写代码存放在codeflash区则不能对codeflash区进行擦写动作但能对dataflash区进行擦写。3、擦写代码存放在dataflash区则不能对dataflash区进行擦写动作但能对codeflash区进行擦写。所以Fls组件允许在ram区运行Flash access code进行擦写动作比如在Bootloader的场合、需要对FLASH ECC校验错误块擦除的场合。四、虚拟地址和物理地址MCU存在不同的分区每个分区的物理地址都不同但软件里操作时是按虚拟地址来操作软件里配置虚拟地址映射到物理地址例如Fls组件配置了两个Sector第一个在codeflash区物理地址为0x00400000大小为8192个字节第二个在dataflash区物理地址为0x10000000大小为8192个字节但软件里操作的地址即虚拟地址基址为0虚拟地址0-8191为第一个Sector虚拟地址8192-16383为第二个Sector。二、代码架构NXP提供的本芯片Fls组件内部FLASH驱动使用芯片的C40外部FLASH驱动使用QSPI来操作本章不涉及外部FLASH驱动。一、多核访问Fls允许多核访问通过信号量来处理多核同步的问题在Fls_MainFunction()判断当前的核是否处理完毕然后是否释放信号量。二、擦写运行冲突当FLASH要擦写的扇区与执行代码在同一个扇区时会有冲突所以就需要把擦写代码放到RAM区里去执行。C40_Ip_AccessCode()为执行FLASH擦写的代码查看它的定义为acfls_code_romld文件里acfls_code_rom地址为0x20406F00在执行擦写任务时如果使能了AC CODE加载AC代码便会判断AC执行代码的扇区是否和要擦写的扇区一致一致的话将C40_Ip_AccessCode()加载到RAM区RAM区地址如果有定义的话在执行擦写寄存器时变运行RAM里的代码。AC代码只能在擦写同步模式下使用。三、数据同步在执行擦写读任务时那要注意D-CACHE的影响为预期FLASH里内容与实际内容一致在执行读操作前需要禁用CACHE执行擦写操作前打开CACHE执行擦写操作后禁用CACHE。在将擦写执行代码复制到RAM区运行时也要注意CACHE的影响不然执行完搬运代码后数据可能还在CACHE里然后CPU去执行目标RAM区里的代码就出错了所以在搬运前要禁用CACHE执行完要清理RAM区和CACHE。四、FLASH加锁解锁FLASH在每次擦写时需要先解锁执行完再加锁防止被异常篡改。五、FLASH擦写程序异步同步Fls组件的擦写任务都是异步的也就是说调用了接口后实际执行动作在Fls_MainFunction()里但擦写代码可以选择同步还是异步也就是说操作擦写寄存器后FLASH擦写没那么快运行完同步模式的话死等FLASH擦写完期间可以用回调函数如添加喂狗操作AC代码也只能用在同步模式异步模式为查询式判断FLASH有没有擦写完。/* On sync */if((STATUS_C40_IP_SUCCESSReturnCode)(FALSEAsynch)){Fls_IPW_CallAccessCodeWrite();/* Check status of write hardware */#if(STD_ONC40_MAIN_INTERFACE_ENABLED)ReturnCodeC40_Ip_MainInterfaceWriteStatus();#endif/* Assume that everything was ok */LldRetValFLASH_E_OK;/* The job has finished. Time to lock the sector */if((Fls_u32JobAddrIt(*(Fls_pConfigPtr-paSectorEndAddr))[Fls_u32JobSectorIt])||(Fls_u32JobAddrItFls_u32JobAddrEnd)){if(STATUS_C40_IP_SUCCESS!C40_Ip_SetLock(Fls_Ipw_xVirtualSectorInUse,(uint8)FLS_DOMAIN_ID)){/* Sector locking failed */Fls_eLLDJobResultMEMIF_JOB_FAILED;LldRetValFLASH_E_FAILED;}}if(STATUS_C40_IP_SUCCESS!ReturnCode){/* IP operation failed */Fls_eLLDJobResultMEMIF_JOB_FAILED;LldRetValFls_IPW_TranslateReturnCode(ReturnCode);}}/* If failed or Async */else{if(STATUS_C40_IP_SUCCESS!ReturnCode){/* IP operation failed */Fls_eLLDJobResultMEMIF_JOB_FAILED;LldRetValFls_IPW_TranslateReturnCode(ReturnCode);}else{LldRetValFLASH_E_PENDING;Fls_eLLDJobFLASH_JOB_WRITE;Fls_eLLDJobResultMEMIF_JOB_PENDING;}}六、FLASH ECCFLASH在擦写时如果遇到突然掉电情况也就是低压擦写或者向同一个地址没擦除多次写不同数据会容易造成ECC错误再下次读这块区域时便会触发硬件异常尤其是DATA FLASH区因为通常我们把数据存放在DATA FLASH区NXP提供的参考文档有以下处理办法1、通过使能Suppression开关让FLASH发生ECC错误时不产生HardFault让上层Fee识别到异常时触发擦除操作来消除ECC错误。如上图在使能ECC CHECK后底层会先判断ECC有没有抑制掉有抑制掉的话因为不会进入异常便检测对应地址ECC对不对不对的话当前操作返回错误上层就知道了当前读取操作失败。2、进入异常后让CPU跳过引起ECC异常的指令然后更新Fls状态机退出异常中断返回当前程序让程序继续运行上层Fee发现异常后执行擦除任务消除ECC或者直接在异常中断里执行擦除动作然后再返回让程序继续运行。EB里使能Fls ECC Handling HardfaultHandler后在进入异常中断里就可以调用Fls_DsiHandler()判断当前是否FLASH ECC故障Fls_DsiHandler()有返回FLS_HANDLED_SKIP就说明是FLASH ECC引起的异常这时可以在中断里来执行擦除动作并且更新Fls状态机或者退出让Fee来更新之后退出中断。Fls_DsiHandler()入参pExceptionDetailsPtr-data_pt是产生ECC的数据地址可由BFAR寄存器获得pExceptionDetailsPtr-syndrome_u32是异常类型固定写C40_DSI_EXC_SYNDROME。跳过异常地址方法可以参考AN12201.pdf里面有描述怎样改LR指针跳过异常地址。像S32K芯片ECC的错误状态还可以根据EER寄存器获得3、因为通过进入异常中断后通过跳过有ECC错误区域这种修改指针的方式不属于安全设计所以有一个思路是在读取FLASH时创建一个小任务在这个小任务里处理FLASH的操作这样就与其它任务做了隔离这个任务需要自己设计当这个任务里发现有ECC错误后删除本任务之后其它任务来处理有ECC坏的区域。通过使能Fls ECC Handling ProtectionHook来触发该策略。Callout用户自定义来创建任务。然后在任务里调用Fls_ReadEachBlock()读取FLASH区域如果触发了ECC错误那么删除任务并且调用Fls_DsiHandler()来更新状态机之后在其他主任务里处理坏的区域。在将有ECC问题的区擦除后弥补方法是将FLASH备份区填补到对应的擦除区或者将数据分为重要数据区和不重要数据区重要数据区跟代码一样是永远不动的擦写动作永远发生在不重要数据区那么即使发生ECC错误后不重要数据区就没顾虑的擦除掉。当然在遇到FLASH ECC异常时添加处理措施是一种安全模式的设计产品上设计上还是要有一些防护比如产品有网络管理功能在每次进入BUS SLEEP时要等FLASH操作执行完再进入休眠断电。如果产品电源接的是ACC电那么电路上MCU的电源可能要添加大电容防止MCU断电太快并且在MCU前级电路上增加低压监测电路也使能MCU自己本身的低压监测功能当低压时关掉一切外设然后运行Fls_MainFunction()。产品软件里每次触发复位时要等FLASH执行完再触发复位。三、主要变量和类型描述各种Callback、Callout用于的场合FlsAcCallback底层在同步模式下也就是执行擦写代码时等待擦写完成期间运行的回调函数用户可在里面添加喂狗等操作。FlsJobEndNotificationFls的任务执行结束并且成功后通知Fee模块和Fee集成时必须要添加。FlsJobErrorNotificationFls的任务执行结束并且错误后通知Fee模块和Fee集成时必须要添加。FlsStartFlashAccessNotif、FlsFinishedFlashAccessNotif用户可以让Fls在执行擦写代码前和结束后可以添加操作比如关闭打开全局中断操作中断不应在Fls里操作应该在OS或RTE里操作所以这两个回调供用户添加操作。FlsReadFunctionCallout此CALLOUT给用户添加任务在任务里处理FLASH ECC的问题。四、主要代码描述(一)、void Fls_Init(const Fls_ConfigType * ConfigPtr)Fls组件的初始化包括涉及到FLASH的硬件外设初始化在操作FLASH前必须先执行Fls_Init()。(二)、Std_ReturnType Fls_Write(Fls_AddressType TargetAddress,const uint8 * SourceAddressPtr,Fls_LengthType Length)Fls组件的写操作。TargetAddress为在配置范围内的虚拟地址并且能被页大小整除。SourceAddressPtr为写数据的地址注意这写数据的变量要定义为全局变量。Length为写数据大小即LengthFlash page * X。(三)、Std_ReturnType Fls_Erase(Fls_AddressType TargetAddress,Fls_LengthType Length)Fls组件的擦除操作。TargetAddress为配置范围内的虚拟地址因为MCU擦除单位是sector即最小擦除大小一个sector每次Fls_Erase()会检查TargetAddress映射在哪个物理扇区内擦除对应的物理扇区。Length为擦除数据大小如果Length不足sector大小则Length变成一个sector大小。(四)、Std_ReturnType Fls_Read(Fls_AddressType SourceAddress, uint8 * TargetAddressPtr,Fls_LengthType Length )Fls组件的读操作。SourceAddress为在配置范围内的虚拟地址和写操作不同该地址可以不需要被页大小整除。TargetAddressPtr为存放读出来的地址。Length为数据大小。(五)、Std_ReturnType Fls_Compare(Fls_AddressType SourceAddress,const uint8 * TargetAddressPtr,Fls_LengthType Length)Fls组件的比较操作比较操作能比较目标地址的数据和预期的数据是否一致基于芯片特性也能同时检查目标地址是否有ecc错误。SourceAddress为在配置范围内的虚拟地址和写操作不同该地址可以不需要被页大小整除。TargetAddressPtr为要比较数据的地址注意这比较数据的变量要定义为全局变量。Length为数据大小。(六)、Std_ReturnType Fls_BlankCheck(Fls_AddressType TargetAddress,Fls_LengthType Length)Fls组件的块检查操作即检查FLASH区域是不是等于FF。TargetAddress为任意配置范围内的虚拟地址。Length为要检查的数据大小。(七)、void Fls_SetMode(MemIf_ModeType Mode)设置Fls组件读写操作的快慢具体实现依据每个芯片功能来比如在MEMIF_MODE_SLOW模式下允许数据读写大小范围大MEMIF_MODE_FAST模式下允许数据读写大小范围小。(八)、void Fls_MainFunction(void)Fls组件执行读、写、擦除、比较、块检查操作的运行函数因为Fls组件的操作是异步的即调用Fls_Write()、Fls_Erase()、Fls_Read()、Fls_Compare()、Fls_BlankCheck()后FLASH不会马上动作需要在Fls_MainFunction()里执行完成。(九)、MemIf_StatusType Fls_GetStatus( void )获取Fls组件的运行状态为MEMIF_IDLE时表示Fls组件可以执行读写擦除比较块检查操作。(十)、MemIf_JobResultType Fls_GetJobResult( void )获取Fls组件的任务状态即每次执行完操作后是否成功为MEMIF_JOB_PENDING时表示Fls组件当前在执行读写擦除比较块检查操作。(十一)、void Fls_Cancel(void)中止当前的操作。从以上可知有写任务、读任务、擦除任务、比较任务、块校验任务。Fls_Write()、Fls_Erase()、Fls_Read()、Fls_Compare()、Fls_BlankCheck()都为异步操作每次执行时都将在Fls_MainFunction()里运行完成同时只能执行一个任务比如写任务要执行完后才能成功调用下一个任务。每个任务让用户只不需要关注物理地址任务在执行时会将虚拟地址映射到物理地址并且会检查地址的合法性例如以下软件配置了sector1物理地址为code flash的0x00400000软件设置大小为0x2000sector2物理地址为data flash的0x10000000软件设置大小为0x1FF8sector3物理地址为data flash的0x10002000软件设置大小为0x2000所以软件里虚拟地址为0x0-0x5FF8。已知该芯片FLASH的page大小为8个字节sector大小为0x2000个字节。1、假如调用Fls_Write()时TargetAddress设置为0x07那写任务将不会执行因为TargetAddress没有8个字节对齐。2、假如调用Fls_Write()时Length设置为0x07那写任务将不会执行因为Length没有8个字节对齐。3、假如调用Fls_Write()时TargetAddress设置为0x1FF8Length设置为16那实际上写入芯片FLASH的地址为code flash区的0x401FF8-0x401FFFdata flash区的0x10000000-0x1000000F而不是code flash区的0x401FF8-0x402007。4、假如调用Fls_Write()时TargetAddress设置为0x3FF8Length设置为8那实际上写入芯片FLASH的地址为data flash区的0x10001FF8-0x10001FFF而不是0x10002000-0x10002007。5、假如调用Fls_Erase()TargetAddress设置为0x2000Length设置为0x1FF8那实际上芯片FLASH擦除的地址是0x10000000-0x10001FFF因为FLASH实际sector大小为0x2000。五、EBTresos配置本次用的是NXP的S32K3的MCALEB配置主要配置如下Fls Access Code Erase、Fls Access Code Write代码里存放AC的RAM地址如果使能AC了情况下软件里会把存放AC的FLASH的地址里的数据搬到设置好的RAM区去执行AC代码。MEMIF_MODE_SLOW和MEMIF_MODE_FAST模式下最大和最小允许读写的长度。Fls ECC Handling HardfaultHandler开启ECC检测功能的APIFls ECC Handling ProtectionHook开启供AUTOSAROS ECC检测功能的APIFls Sector Index当前Fls Sector Index的索引Fls Physical Sector当前Sector选择的物理Sector区Fls Page Size 页的大小这里固定为8Fls Sector Size当前Sector的大小一般要跟选择的物理Sector大小一样Fls Sector Start Address当前Sector开始的地址起始地址为上一个Sector的结束地址Fls Data Error Suppression使能后抑制由于FLASH ECC错误引起的硬件异常。六、使用范例(一)、使用写任务后再使用比较任务/**忽略其他配置**/Std_ReturnType ret;uint8 data[8]{1,2,3,4,5,6,7,8};Fls_Init(Fls_Config_VS_0);retFls_Write(0x00,data,8);if(STD_ONret){while(MEMIF_IDLE!Fls_GetStatus()){Fls_MainFunction();}retFls_Compare(0x00,data,8);if(STD_ONret){while(MEMIF_IDLE!Fls_GetStatus()){Fls_MainFunction();}if(!(MEMIF_JOB_OKFls_GetJobResult())){/* 比较失败说明目标地址的数据与data数组里的数据不一致 */}}}(二)、使用擦除任务后再使用块检测任务/**忽略其他配置**/Std_ReturnType ret;Fls_Init(Fls_Config_VS_0);retFls_Erase(0x00,8092);if(STD_ONret){while(MEMIF_IDLE!Fls_GetStatus()){Fls_MainFunction();}retFls_BlankCheck(0x00,8092);if(STD_ONret){while(MEMIF_IDLE!Fls_GetStatus()){Fls_MainFunction();}if(!(MEMIF_JOB_OKFls_GetJobResult())){/* 块检测失败目标地址不是FF或者有ECC故障说明前面擦除失败 */}}}七、参考资料AUTOSAR_CP_SWS_FlashDriver.pdfAUTOSAR_CP_SRS_FlashDriver.pdfAUTOSAR_EXP_LayeredSoftwareArchitecture.pdfRTD_FLS_IM.pdfRTD_FLS_UM.pdfAN12201.pdf总结NXP的MCAL外部FLASH使用QSPI来驱动本文没讲述外部FLASH驱动怎么使用另外本文文字描述多点更像是本人的使用笔记仅供参考如有不对地方欢迎指教。