This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

How to write a routine to continuously refresh flash/ram memory by using ECC?

Other Parts Discussed in Thread: CCSTUDIO, HALCOGEN

I am using the TMS570 HDK development kit. I am currently focusing on inducing fault-tolerance to this MCU for use in radiation susceptible environments.I plan to use memory scrubbing technique(memory read- use ECC- Write back)...one memory bank at a time. One of the engineers had suggested that it may be possible to program the internal state machine to achieve this objective. The other option is using the flash api to read, run ECC and write the data and ECC bits back to memory. How do I make program run periodically?  It is imperative that this process be continuous to prevent accumulation of errors.Please let me know if you need any additional information.

  • You can use TI Flash API library functions to erase and program the Flash memory sector by sector. After programming, you can check the programmed data with your reference to see if there is any error. When Flash is erased, the flash content and ECC are not matching. With Flash ECC enabled, you will see uncorrectable error when reading erased flash space. If you need the check if Flash is erased correctly, you need to disable Flash ECC first. Following example shows how Flash API can be used. You can find more details in Flash API document.

    unsigned int Fapi_BlockProgram( unsigned int Bank, unsigned int Flash_Start_Address, unsigned int Data_Start_Address, unsigned int Size_In_Bytes, unsigned int Freq_In_MHz)
    {
        register unsigned int src = Data_Start_Address;
        register unsigned int dst = Flash_Start_Address;
        register unsigned int bytes_remain = Size_In_Bytes;

        Fapi_initializeAPI((Fapi_FmcRegistersType *)0xfff87000,Freq_In_MHz);

        Fapi_setActiveFlashBank(Bank);


        Fapi_issueAsyncCommandWithAddress(Fapi_EraseSector, (uint32 *)Flash_Start_Address);

        while( Fapi_checkFsmForReady() == Fapi_Status_FsmBusy );

        /* Disable the ECC Error Reporting logic inside R4 */
        if(Bank == 7)
        {
            *(int *) 0xfff87308 = 0x050A005;
        }
        else
        {
            A_TCM_Disable_ECC();
        }
        
        /* code to verify FLASH and EEPROM erase check */
        status = Flash_Erase_Check(Flash_Start_Address, Size_In_Bytes);

        if(status)
            return (status);

        if(Bank == 7)
        {
            *(int *) 0xfff87308 = 0x050A060A;
        }
        else
        {
            A_TCM_Enable_ECC();     /* Enable the ECC Error Reporting Logic inside R4 */
        }


         while( bytes_remain > 0)
        {
            Fapi_issueProgrammingCommand((unsigned int *)dst,
                                         (unsigned char *)src,
                                         (unsigned long) 16,
                                         0,
                                         0,
                                         Fapi_AutoEccGeneration);

             while( Fapi_checkFsmForReady() == Fapi_Status_FsmBusy );

            src += 0x10;
            dst += 0x10;
            bytes_remain -= 0x10;
        }

        status =  Flash_Program_Check(Flash_Start_Address, Data_Start_Address, Size_In_Bytes);

        return (status);
    }


    int Flash_Program_Check(unsigned int Program_Start_Address, unsigned int Source_Start_Address, unsigned int No_Of_Bytes)
    {
        register unsigned int *src1 = (unsigned int *) Source_Start_Address;
        register unsigned int *dst1 = (unsigned int *) Program_Start_Address;
        register unsigned int bytes = No_Of_Bytes;

        while(bytes > 0)
        {    
            if(*dst1++ != *src1++)
                error = 1;

            bytes -= 0x4;

        }

        return(error);

    }    


    int Flash_Erase_Check(unsigned int Start_Address, unsigned int Bytes)
    {
        register unsigned int *dst1 = (unsigned int *) Start_Address;
        register unsigned int bytes = Bytes;

        while(bytes > 0)
        {    
            if(*dst1++ != 0xFFFFFFFF)
                error = 2;

            bytes -= 0x4;

        }

        return(error);

    }

    Thanks and regards,

    Zhaohong

  • Hello Pritesh,

    I can understand the desire to run a periodic scrubbing of the SRAM for radiation induced errors, but I am interested that you believe this is necessary for flash as well.  Based on our reliability testing data and industry research, we have seen no indication that the flash memory designs incorporated in the TI products are susceptible to corruption by terrestrial sources of radiation.  I am a bit curious if you can share some details of your application, as we have not seen such concerns previously.

    Thanks and Regards,

    Karl 

  • I will check up the method you have suggested. But the functions you have suggested assume that the data is available in the memory. What I want is periodic scrubbing of the flash memory by reading the memory then applying the error detection/correction code and then write back the data. Does the ECC in the flash also correct the 1 bit errors continuously? If not is there a way to correct the one bit errors in a continuous manner? What must I do to extend this concept to RAM? As far as I have read in the attached document all I need to do for MCUs cortexR4 CPUs is to read and write to the RAM to correct this error. As the ECC is applied whenever  a data is read from the RAM and the ECC bits are generated when the data is written to the RAM. Please confirm this. 2465.ecchandlingin570imp.pdf

  • The application I wish to use the MCU is detection control systems in Physics experiments where MCU is exposed to high doses of radiation. I believe there are MCUs designed specifically to handle these type of applications but I want to use this MCU family and then wish to come up with a generic approach for this application. I believe that a simple read and write to the RAM with ECC enabled will suffice. This again has to be done continuously so that the single bit errors are corrected as and when they appear and do not accumulate. Also for the Flash Program/Data can this approach of reading and then writing along with generated ECC bits be used? What about the emulated EEPROM? I am referring tot the following TI document for ecc techniques.  0247.ecchandlingin570imp.pdf and flash 035 api.

  • Hello Pritesh,

    The flash memory (including flash emulated EEPROM) is non-volatile and cannot be directly re-written. It is not possible to automatically re-write the correction and re-fetch the corrected data as can be done with SRAM.  To reprogram the flash you must first manually erase a sector of the flash and then re-write the sector with correct data, as noted by Zhaohong.

    To migitate this concern the CPU uses an inline correction buffer to handle corrections in the flash  which ARM calls the hard error cache.  The R4F and R5F include a single 64b entry hard error cache.  There are a few corner cases in which the hard error cache may not have enough entries - such as errors in two 64b fetches which comprise a single unaligned memory access.  In this case the "LiveLock" functionality will trigger to detect the condition.

    Regards,

    Karl

  • Pritesh,

    Before starting this test, you have to initialize RAM so that the data content matches ECC. With ECC enabled, ECC will be checked on every data you read, single bit error will automatically corrected and double bit error will be reported. ECC will be updated for every data write. For non-64 bit write, CPU actually performed a read-modify-write operation.

    The difference between Flash and RAM is that you can not simply "write" back. You must first erase and then program. The Flash has to be erased in block. The minimum block size is a sector. You can check the device data sheet for sector sizes.

    Thanks and regards

    Zhaohong

  • Could you please let me know which datasheets to refer to, because when I searched I could not find the FLASH and the SRAM datasheets for the TMS570LS31x HDK Kit.

    Also in the 8780.spnu509ahdkusersgude.pdf the sram and the flash devices component numbers are not given. Where do I find out these? I have looked up the wiki pages for this HDK. Please let me know how to locate the required information about the FLASH and SRAM. Is it all a single component SDRAM 8Mb as mentioned in the User's guide? I also do not know whether the flash device is F035 or F021. Please let me know about this as I am new to microcontroller programming.

  • Hello,

    Our feedback to date has been with respect to the flash and the SRAM embedded inside the Hercules MCU.  Information on these memories can be found in the datasheet and TRM for the TMS570LS31x product mounted on your HDK.  Please refer to http://www.ti.com/mcu/docs/mcuprodtechdoc.tsp?sectionId=95&tabId=2837&familyId=1931&techDoc=6&docCategoryId=1&docCategoryId=6&docCategoryId=2&viewType=mostrecent

    The HDK does not have external flash.  The HDK does have a single 8MB SDRAM module as an external memory for the MCU.  The MCU does not support ECC for external memories.  The part number I read for the SDRAM on my TMS570LS12x HDK is IS42S16400F from ISSI, and datasheets should be available from their website here -- http://www.issi.com/pdf/42-45S16400F.pdf

    All TMS570LS31x products are built in the F021 process, an ITRS 65nm equivalent.   F035 is our previous process node, which is an ITRS 130nm equivalent. the TMS470M and TMS570LS20x/10x products are built in F035.

    Regards,

    Karl

  • Hello Karl,

    "LiveLock" as mentioned in your mail shown below, is valid only for FLASH Access or will it occur also for RAM Access?

    Thank you
    Regards
    Pashan

  • Hello Pashan,

    The livelock functionality is present in the CPU regardless of which memory the chip designer connects to the CPU TCM interfaces.  The possibility of a livelock condition on a flash access is very, very small.  With an SRAM access the possibility is even less due to the capability to write back correction results, and effectively zero if the SRAM is operating with zero wait states.

    We have requested ARM to improve public documentation of this feature but such documentation is not presently available.

    Regards,

    Karl

  • Hi,

    I have two questions:

    1) When I was reading the F021 API document I came across an obvious but  very important statement. "The F021 Flash API library cannot be executed from the same bank as the active bank selected for the API commands to operate on.....the F021 Flash API must be executed from RAM". Can you please tell me how to ensure that the error checking/flash modifying code is run from the RAM. What then must be done while refreshing the the RAM memory as a similar clash will be present here too?

    2) In one of the previous posts it was mentioned that I will have to initialize the RAM for ECC to match the data contents.... How do "I initialize" the RAM before I set the ECC on for the RAM?

  • Hi Pritesh,

    1) Flash memory has a few unique characteristics.  One of these is that you must erase the contents of the flash in order to program new contents.  Because of this, it is necessary to execute the flash erase/program code from a different memory - either a different physical bank of flash or from an SRAM.  The user controls the location at which all code runs on the device by the use of the linker.  In some cases you may wish to build re-locatable code to load the API in flash but copy and execute from SRAM.  

    2) Upon power-up SRAM will be in an unknown state - including the ECC bits.  It is necessary to write each location in the memory to initialize to a known state.  If the ECC is enabled while this operation is done, the correct ECC data will also be written for the initialized SRAM value.

    Regards,

    Karl 

  • Hi,

    So according to your previous reply, I will have to copy the program to the SRAM and then modify the PC and offset accordingly to start executing from the SRAM. My question is, how to find out how large my program is and what locations rather range of flash memory is it loaded into initially (to know what part of FLASH is to be copied: start & end address)? Please provide suggestions on where I should look for some tips on building relocatable code..

     Regarding my previous question about ram initialization... Does "Initialization" mean that I will have to initialize the entire contents of the RAM... in this case 256 KB after enabling ECC before I can begin using the scrubbing/refreshing operations on the entire memory?

  • Hi Pritesh,

    Assuming you are using the TI Code Composer Studio tool, you should reference the technical documents for CCS.  The linker tool will provide the capability to locate your code.  More details can be found here:  http://www.ti.com/tool/ccstudio  If you are using a different compilation tool suite you will need to reference the documentation for that tool suite.

    Regarding the SRAM query, you should initialize any SRAM that you will be using in your application.  Many developers will initialize all SRAM as a best practice - it may be difficult to predict how much SRAM will actually be used by your software.

    Regards,

    Karl

  • I have written a short code which attempsts to check the ECC mechanism for the SRAM. But it does not give the expected  output. Please refer below. All the functions used are from the Halcogen generated code for TMS570LS31x HDK development kit. The Corresponding ECC memory is : 0x084000C0. I am using code composer studio.

    //The comments are the output expected and observed when doing a line by line debug. 

    void main(void)
    {
    uint32 read1 = 0;
    uint32 read2 = 0;
    uint32 read3 = 0;
    uint32 read4 = 0;

    _esmCcmErrorsClear_();
    _coreEnableRamEcc_();


    _coreEnableEventBusExport_();
    memoryInit(0x1U);


    _coreEnableRamEcc_();
    (*(volatile uint32 *)(0x080000C0U)) = 0x2U; /* at this write the ECC bits change to 0xBAD0BAD0E9E9E9E9 */
    read1 = (*(volatile uint32 *)(0x080000C0U)); /*read1 should be 2 and is 2 and the ECC bits change to 0xE9E9E9EBE9E9E9E9*/

    _coreDisableRamEcc_();
    (*(volatile uint32 *)(0x080000C0U)) = 0x0U; /* No change in ECC bits */

    read2 = (*(volatile uint32 *)(0x080000C0U)); /*read2 should be 0 and is 0 and no change in ECC bits*/

    _coreEnableRamEcc_();
    read3 = (*(volatile uint32 *)(0x080000C0U)); /*should be 2 but is 0 and no change in ECC bits*/

    (*(volatile uint32 *)(0x080000C0U)) = 0x1U; /* This write does not modify ECC memory area i.e. no change in ECC bits*/
    read4 = (*(volatile uint32 *)(0x080000C0U)); /* should be 1 and is 1 an no change in ECC bits*/
    /* Finally the ECC bits are 0xE9E9E9EBE9E9E9E9 */


    while(1);
    }


    //When the program is "run" the final ECC value is 0xBAD0BAD0EFEFEFEF

    //The values in the read1 -4 variables remain same.

    _coreDisableRamEcc_

    stmfd sp!, {r0}
    mrc p15, #0x00, r0, c1, c0, #0x01
    bic r0, r0, #0x0C000000
    mcr p15, #0x00, r0, c1, c0, #0x01
    ldmfd sp!, {r0} 
    bx lr

    _coreEnableRamEcc_

    stmfd sp!, {r0}
    mrc p15, #0x00, r0, c1, c0, #0x01
    orr r0, r0, #0x0C000000
    mcr p15, #0x00, r0, c1, c0, #0x01
    ldmfd sp!, {r0} 
    bx lr

    What is the step I am doing wrong? What should I use to test the program if not the debugger as it is giving different outputs?  

    Regards,

    Pritesh

  • Now I modified the code to use variables to store the intermediate ECC memory values: 

    void main(void)
    {

    volatile uint32 read = 0;
    volatile uint32 read2 = 0;
    volatile uint32 read3 = 0;
    volatile uint32 read4 = 0;
    volatile uint64 ecc0 = 0;
    volatile uint64 ecc1 = 0;
    volatile uint64 ecc2 = 0;
    volatile uint64 ecc3 = 0;
    volatile uint64 ecc4 = 0;
    volatile uint64 ecc5 = 0;
    volatile uint64 ecc6 = 0;


    _esmCcmErrorsClear_();
    _coreEnableRamEcc_();


    _coreEnableEventBusExport_();
    memoryInit(0x1U);




    _coreEnableRamEcc_();

    (*(volatile uint32 *)(0x080000D8U)) = 0x1U;
    ecc8 = (*(volatile uint64 *)0x084000D8U); /* ecc8 = 0xEFEFEFEEEFEFEFEF but in the memory window finally this value is 0xBAD0BAD0EFEFEFEF */

    ecc0 = (*(volatile uint64 *)0x084000C0U); /* ecc0 = 0x0C0C0C0C0C0C0C0C */


    (*(volatile uint32 *)(0x080000C0U)) = 0x2U;
    ecc1 = (*(volatile uint64 *)0x084000C0U); /* ecc1 = 0x0C0C0C0C0C0C0C0C */


    read = (*(volatile uint32 *)(0x080000C0U)); /* should be 2 */
    ecc2 = (*(volatile uint64 *)0x084000C0U); /* ecc2 = 0xE9E9E9EBE9E9E9E9 */


    _coreDisableRamEcc_();

    (*(volatile uint32 *)(0x080000C0U)) = 0x0U;
    ecc3 = (*(volatile uint64 *)0x084000C0U); /* ecc3 = 0xE9E9E9EBE9E9E9E9 */

    read2 = (*(volatile uint32 *)(0x080000C0U)); /*should be 0 */
    _coreEnableRamEcc_();

    read3 = (*(volatile uint32 *)(0x080000C0U)); /*should be 2 */
    ecc4 = (*(volatile uint64 *)0x084000C0U); /* ecc4 = 0xE9E9E9EBE9E9E9E9 */

    (*(volatile uint32 *)(0x080000C0U)) = 0x1U;
    ecc5 = (*(volatile uint64 *)0x084000C0U); /* ecc5 = 0xE9E9E9EBE9E9E9E9 */

    read4 = (*(volatile uint32 *)(0x080000C0U)); /* should be 1 */
    ecc6 = (*(volatile uint64 *)0x084000C0U); /* ecc6 = 0xE9E9E9EBE9E9E9E9 when it should have been  0xEFEFEFEEEFEFEFEF according to ecc8 */

    while(1);
    /* USER CODE END */
    }

    In the memory window the ECC value for the variable in 0x08000C0 from the location 0x08004C0 is 0xBAD0BAD0EFEFEFEF */

    Once the ECC is disabled. It does not enable again. The actual ECC value for 0x1 i.e. ecc5 and ecc6 should have been 0xEFEFEFEEEFEFEFEF. What must be done to bypass this behaviour?

    Regards,

    Pritesh