RM48L952: FEE software

Part Number: RM48L952
Other Parts Discussed in Thread: HALCOGEN

Hello,

 

I am using a RM48L952 device for an application, for which we use HALCoGen 04.07.01.

We need to use the FEE lib, and we have some issues.

First the FEE documentation we have is v1.12 of the FEE TI Driver user guide, that is for the sofwtare version 1.19.01 as per revision history, but the software version of the files we have from halcogen is 1.19.04.

Where can I find the last document version of software release note of FEE TI driver so that I can have  accurate documentation for my usage?

 

Also, in the user guide, for me, the workflow is too generic and not clear in case of synchronous read or write. I cannot really understand the difference in the workflow for Sync / Async API.

For example after a syncrhnous write, do we need to pool the GetJobStatus? It seems that pending can be reported, while it is "syncrhonous". Could you please give detail on how synchronous API works please? (compared to Async ones)

 

Thanks for your help

Damien.

  • Hello,

    My first question was quite generic, but in fact I am facing an issue related to synchronised read, initialization and power fail safe management.
    Below my FEE configuration.
    I work on a RM48L952 chip using bank 7 for EEPROM.
    I have 2 Virtual sectors with 2 Flash sector each (of 16kB), so VS_1 is configured with Sector 0 and 1, and VS_2 is configured with Sector 2 and 3.
    Each VirtualSector size is the 32 KB.
    I have configured 52 data blocks in total, with several different data size, but with in particular one data which size is 0x4380 (17280 bytes).
    With this configuration, it means that each time I will write that big data (call it LOG_DATA), this will provoke a Virtual Sector change, since there is never enough free space to have the LOG_DATA twice in the same Virtual Sector (2 * 0x4380 is more than 32KB)


    When I make some power fail test, I can have the following situation on my 2 virtual sectors. (I provide the Flash content as en example enclosed in the zip file, those are bin data from memory of the device).
    The VS_1 is set a EmptyVirtualSector and the VS_2 is set as ActiveVirtualSector. So all seems OK from VS status blocks pont of view.
    But after the Fee_Init Call, we can see that the two last Fee_au16BlockOffset ([50] and [51]) of TI_Fee_GlobalVariables are still set with 0x0BAD.
    The Fee_Init finish without error notification at this stage.

    Then I try to initialize all my applicative data with the data read from the Fee(with TI_Fee_ReadSync calls), so I do basically a for loop to read over all the Fee data.
    This calls will end up with a data_abort exeption when I process the LOG_DATA.
    So this is my real blocking issue.

    After analysis, the data abort occurs because I try to read data from 0xF0210000 with if outside implemented FlashBank7 for my RM48L952 (from 0xF020_0000 to F020_FFFF).
    This seems to be an issue inside the librairy in the TI_Fee_ReadSync (and also in the TI_Fee_MainFunction), in the following part:

                                /* Read complete data of the block */
                                while((TI_Fee_GlobalVariables[u8EEPIndex].Fee_u16BlockSize>0U))                                   
                                {                            
                                    /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Reason -  Null pointer check is done in ti_fee_read."*/
                                    *TI_Fee_GlobalVariables[u8EEPIndex].Fee_pu8ReadDataBuffer=*TI_Fee_GlobalVariables[u8EEPIndex].Fee_pu8ReadAddress;
                                    
                                    if(TI_Fee_GlobalVariables[u8EEPIndex].Fee_pu8ReadDataBuffer != NULL_PTR)
                                    {
                                        /*SAFETYMCUSW 567 S MR:17.1,17.4 <APPROVED> "Reason -  Pointer Arithmatic is necessary here."*/
                                        TI_Fee_GlobalVariables[u8EEPIndex].Fee_pu8ReadDataBuffer++;                        
                                    }                                    
                                    #if(TI_FEE_CHECK_BANK7_ACCESS == STD_ON)
                                    if((TI_Fee_GlobalVariables[u8EEPIndex].Fee_pu8ReadAddress > (uint8 *)Device_FlashDevice.Device_BankInfo[0].Device_SectorInfo[0].Device_SectorStartAddress)
                                       && (TI_Fee_GlobalVariables[u8EEPIndex].Fee_pu8ReadAddress < (uint8 *) Device_FlashDevice.Device_BankInfo[0].Device_SectorInfo[DEVICE_BANK_MAX_NUMBER_OF_SECTORS-1U].Device_SectorStartAddress+
                                           Device_FlashDevice.Device_BankInfo[0].Device_SectorInfo[DEVICE_BANK_MAX_NUMBER_OF_SECTORS-1U].Device_SectorLength))
                                    {
                                        if(TI_Fee_GlobalVariables[u8EEPIndex].Fee_pu8ReadAddress != NULL_PTR)
                                        {
                                            /*SAFETYMCUSW 567 S MR:17.1,17.4 <APPROVED> "Reason -  Pointer Arithmatic is necessary here."*/
                                            TI_Fee_GlobalVariables[u8EEPIndex].Fee_pu8ReadAddress++;                        
                                        }
                                        TI_Fee_GlobalVariables[u8EEPIndex].Fee_u16BlockSize--;    
                                    }
                                    else
                                    {
                                        /* Address is out of bank7 range. Reset block size so that no furthur read's happen */
                                        TI_Fee_GlobalVariables[u8EEPIndex].Fee_u16BlockSize = 0U;
                                        TI_Fee_GlobalVariables[u8EEPIndex].Fee_u16JobResult = JOB_FAILED;
                                    }


    We can see that there is a test done on the TI_Fee_GlobalVariables[u8EEPIndex].Fee_pu8ReadAddress to check the proper range, if test is OK, then TI_Fee_GlobalVariables[u8EEPIndex].Fee_pu8ReadAddress
    is incrementted and then data is read on next loop start. if the address is set to 0xF020_FFFF, the test is OK, value is incremented to 0xF020_1000 an data is read from there, hence te data_abort.

    So the test here is not correct (should more like with -1).

    So, Ok, this is an issue for me, I don't know if this was reported before or not.
    Ater fixing that, the TI_Fee_ReadSync will report JOB_FAILED, which is better.

    But, this is not the end for me, since my real issue is how is it possible to be in such EEPROM case, where I have 2 last block with 0x0BAD offset? How to recover from that and, the most important how it is possible to avoid to be in this case.
    I guess the root cause is comming from a wrong data inside the VS_2 is is marked as valid.

    I have tried to be as detailed as possible for the moment, if you need more information and a debug session, please fee free to contact me.

    Thanks for your help.

    Damien

    0435.FEE.zip

  • Hi Damien,

    Seems like, you've correctly identified a boundary check issue in the TI_Fee_ReadSync function.

    Root Cause: 0x0BAD Block Offsets

    The 0x0BAD value in Fee_au16BlockOffset[50] and [51] indicates these blocks were not found during Fee_Init(). This is the core issue.

    Why this happens:

    • During a power failure while writing your large LOG_DATA (17280 bytes), the virtual sector switch was interrupted
    • VS_2 is marked as Active, but the last two data blocks are incomplete or corrupted
    • The FEE library couldn't locate valid headers for blocks 50 and 51 during initialization

    Recovery and Prevention Strategies:

    Immediate Recovery:

    1. Invalidate corrupted data: Before attempting to read, check if Fee_au16BlockOffset[blockIndex] == 0x0BAD
    2. Use default values: For blocks returning 0x0BAD, use application default values instead of reading from FEE
    3. Rewrite valid data: Once detected, immediately write valid data to these blocks

    --
    Thanks & regards,
    Jagadish.

  • Hello Jagadish,

    Thanks for your reply.

    The question, is why the switch interruption leads to an error?

    According the User Manual, this case should be managed (§4.12 Power Fail Behavior). According to me, the VS_2 should not be set as active if it is not totally ready/valid. And the previous active one VS_1 should still be active until, the VS_2 is ready and valid.

    Worst case scenario should only loose the write of the last data (LOG_DATA) that provokes the switch, and remain on the previous active VS if the switch cannot be completed properly.

    Regarding the management of BAD block offset, this check should not be managed by the FEE library? Because, what you say is that we should check internal variables of FEE Lib to detect the BAD block offset. For example a reading to an offset set a BAD should not be allowed by read APIs or return an error?

    In your answer, you didn't detail the prevention strategy, could be please give more detail on that please?

    For the immediate recovery:

    1) 0xBAD could not be a valid offset value if the previous data + header is taking 0xBAD data bytes for example? (in case of not lucky configuration)

    Thanks for helping us to understand better how this FEE lib works and should be handled.

    BR

    Damien