打印
[学习笔记]

AUTOSAR —— S32K144 的 Fls 和 Fee 模块配置

[复制链接]
1739|15
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
呈兴|  楼主 | 2023-3-23 23:05 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本文来简要介绍一下如何在EB中配置AUTOSAR Fls和Fee模块。Fls模块是Flash的驱动,执行具体的Flash擦写读取等操作。Fee模块的全称是FlashEEPROMEmulation,即Flash模拟EEPROM,是为了解决Flash擦写寿命比较短的问题,通过算法实现各个Flash块的交替擦写,以延长寿命。

1. Fls
(1)FlashSector(扇区)
Fls模块中最重要的一点就是配置FlsSector,如下图所示,一共配置了8个Sector,每个Sector可以选择对应的Flash物理扇区,配置好后,这几个Sector就会被用来模拟EEPROM。S32K1XX系列芯片带有专门用来存储数据的Flash——FlexNVM,地址从0x10000000处开始。每个扇区的大小是2K。



使用特权

评论回复
评论
呈兴 2023-3-23 23:08 回复TA
———————————————— 版权声明:本文为CSDN博主「olddddd」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_42967006/article/details/122113864 

相关帖子

沙发
呈兴|  楼主 | 2023-3-23 23:07 | 只看该作者
回调函数

注意结合Fee模块一起使用的时候,要配置以下两个回调函数,否则数据存储会有问题:



使用特权

评论回复
板凳
呈兴|  楼主 | 2023-3-23 23:07 | 只看该作者
2. Fee

Fee模块是基于Fls模块的,不可单独使用。

配置Fee时首先要配置Fee Cluster,每个Cluster可以包含一个以上的FlashSector。

Cluster越多,Flash的平均擦写次数越少;每个Cluster包含的Sector越多,能够同时存储的数据量越大。
(上面是我初步分析的,大家有不同的看法可以交流一下,互相学习)

使用特权

评论回复
地板
呈兴|  楼主 | 2023-3-23 23:08 | 只看该作者
配置完Cluster之后就可以配置Block了,如下图所示,每个Block有一个唯一的序号——BlockNumber,作为该Block的索引,用于写入数据和读取数据。写入数据时要整个Block一起写入,读取的时候可以指定偏移量和数据长度,读取该Block中某个地址处的某几个字节数据。

每个Block可以分别配置大小,即可存储的数据长度。


使用特权

评论回复
5
呈兴|  楼主 | 2023-3-23 23:09 | 只看该作者
如果结合Nvm模块一起使用的话,要配置下面两个回调函数:



使用特权

评论回复
6
呈兴|  楼主 | 2023-3-23 23:10 | 只看该作者
再注意一下Fee Buffer Size这个概念,可以参考下面的注释,简单说就是Buffersize越大性能越好。


使用特权

评论回复
7
呈兴|  楼主 | 2023-3-23 23:10 | 只看该作者
3. 测试代码

下面的测试代码参考了NXP官方提供的Mcal Sample中的代码。

创建一个Task,每100ms调度一次,代码如下:

static CONST (uint8, AUTOMATIC) FeeTest_WriteBuff[32]={0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,
                                   0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
                                   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                                   0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA};
static VAR (uint8, AUTOMATIC)  FeeTest_ReadBuff[32]={0};

TASK( OsTask_FeeTest )
{
    volatile StatusType status;                 /* variable to check system status */
    Std_ReturnType stdRet = E_NOT_OK;
    MemIf_StatusType memif_status;

    memif_status = Fee_GetStatus();

    /* state-machine logic */
    switch(FeeState)
    {
        case FEE_ERASE_STATE:
        {
            if (MEMIF_IDLE == memif_status)
            {
                stdRet = Fee_EraseImmediateBlock(FeeBankIdx);
                if (stdRet != E_OK)
                {
//                    CONSOLE_MESSAGE("FEE Error %d returned by Fee_EraseImmediateBlock()", stdRet);
                    Can_PduInfo_0_0.sdu[0] = 0x01;
                    /*CONSOLE_MESSAGE("FEE state-machine state:%d", FeeState);*/
                    FeeState = FEE_ERROR_STATE;
                }
                else
                {
                    /* change the state */
                    FeeState = FEE_ERASE_BUSY_STATE;
                    Can_PduInfo_0_0.sdu[0] = 0x00;
                    stdRet = E_OK;
                }
            }
            else
            {
                stdRet = E_OK;
            }
        }
        break;
        case FEE_ERASE_BUSY_STATE:
            if (MEMIF_IDLE == memif_status)
            {
                FeeState = FEE_WRITE_STATE;
            }
            stdRet = E_OK;
        break;
        case FEE_WRITE_STATE:
        {
            if (MEMIF_IDLE == memif_status)
            {
                stdRet = Fee_Write(FeeBankIdx, (uint8 *)FeeTest_WriteBuff);
                if (stdRet != E_OK)
                {
//                    CONSOLE_MESSAGE("FEE Error returned by Fee_Write()", stdRet);
                    Can_PduInfo_0_0.sdu[0] = 0x02;
                    /*CONSOLE_MESSAGE("FEE state-machine state:", FeeState);*/
                    FeeState = FEE_ERROR_STATE;
                }
                else
                {
                    /* change the state */
                    FeeState = FEE_WRITE_BUSY_STATE;
                    stdRet = E_OK;
                }
            }
            else
            {
                stdRet = E_OK;
            }
        }
        break;
        case FEE_WRITE_BUSY_STATE:
            if (MEMIF_IDLE == memif_status)
            {
                FeeState = FEE_READ_STATE;
            }
            stdRet = E_OK;
        break;
        case FEE_READ_STATE:
        {
            if (MEMIF_IDLE == memif_status)
            {
                stdRet = Fee_Read(FeeBankIdx, 0, FeeTest_ReadBuff, 32u);
                if (stdRet != E_OK)
                {
//                    CONSOLE_MESSAGE("FEE Error %d returned by Fee_Read()", stdRet);
                    Can_PduInfo_0_0.sdu[0] = 0x03;
                    /*CONSOLE_MESSAGE("FEE state-machine state:", FeeState);*/
                    FeeState = FEE_ERROR_STATE;
                }
                else
                {
                    /* change the state */
                    FeeState = FEE_READ_BUSY_STATE;
                }
            }
            else
            {
                stdRet = E_OK;
            }
        }
        break;
        case FEE_READ_BUSY_STATE:
            if (MEMIF_IDLE == memif_status)
            {
                FeeState = FEE_VALIDATE_STATE;
            }
             stdRet = E_OK;
        break;
        case FEE_VALIDATE_STATE:
        {
            /* compare the read FeeTest_WriteBuffer with the written one */
            stdRet = SampleAppFee_memcmp((uint8 *)FeeTest_WriteBuff, FeeTest_ReadBuff, 32u);
            if (stdRet != E_OK)
            {
                Can_PduInfo_0_0.sdu[0] = 0x04;
//                CONSOLE_MESSAGE("FEE Error %d returned by SampleAppFee_memcmp()", stdRet);
                /*CONSOLE_MESSAGE("FEE state-machine state:%d", FeeState);*/
                FeeState = FEE_READ_ERROR_STATE;
//                CONSOLE_MESSAGE("Fee task READ ERROR!", 0);
            }
            else
            {
                /* change the state */
                FeeState = FEE_FINAL_STATE;
                Can_PduInfo_0_0.sdu[0] = 0xFF;
                if(FeeBankIdx < 4)
                {
                    FeeBankIdx++;
                    FeeState = FEE_ERASE_STATE;
                }
//                CONSOLE_MESSAGE("Fee task ended OK.", 0);
            }
        }
        break;

        case FEE_ERROR_STATE:
        {

        }
        /*break;*/

        default:
        {
            /* if we got here, something went terribly wrong*/
            stdRet = E_NOT_OK;
        }
        break;
    }



    status = TerminateTask();
}

使用特权

评论回复
8
呈兴|  楼主 | 2023-3-23 23:11 | 只看该作者
在main函数中初始化Fls和Fee模块:

        ……
    Fls_Init(&FlsConfigSet_0);
    Fee_Init();
    FeeState = FEE_ERASE_STATE;
    FeeBankIdx = 1;
    StartOS( Mode01 );                            /* jump to OS startup */

使用特权

评论回复
9
呈兴|  楼主 | 2023-3-23 23:11 | 只看该作者
在一个5ms为周期的函数中调用两个模块的主调度函数:
TASK( OsTask_5ms )
{
    volatile StatusType status;                 /* variable to check system status */
    ……
    Fls_MainFunction();
    Fee_MainFunction();
    status = TerminateTask( );
}


即可完成4个Fee Block的简单测试。

使用特权

评论回复
10
tpgf| | 2023-4-12 16:20 | 只看该作者
Fls驱动的设设计意图主要是给FEE模块使用以写入用户数据,而不是为了写程序代码到Flash里面

使用特权

评论回复
11
磨砂| | 2023-4-12 16:40 | 只看该作者
Fee模块本身是脱离硬件的,但是Fee模块可能会引用的Fls模块定制API

使用特权

评论回复
12
晓伍| | 2023-4-12 16:56 | 只看该作者
Fee模块作为ECU抽象层的模块,需要在Fls模块后初始化

使用特权

评论回复
13
八层楼| | 2023-4-12 17:17 | 只看该作者
在Fee模块层面上,首先将所管辖的Flash分为分区(Partition),每个Fls模块的FlsSector为一个Partition(通常只有1个)每个Partition分为2个逻辑扇区(FeeLogicalSector),也称为Virtual Sector,等价于Fls模块的FlsPhysicalSector
Fee模块以FeeLogicalSector为单位进行Erase操作

使用特权

评论回复
14
观海| | 2023-4-13 08:25 | 只看该作者
FLS驱动不但负责片上flash,同时也负责片外flash

使用特权

评论回复
15
guanjiaer| | 2023-4-13 09:27 | 只看该作者
Fee模块本身是脱离硬件的,但是Fee模块可能会引用的Fls模块定制API,所以只能算半抽象

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

21

主题

144

帖子

0

粉丝