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.

Testing the ECC Mechanism in TMS570 problem

Other Parts Discussed in Thread: HALCOGEN, TMS570LS3137

Hi, 

I have written a short code which attempts to check the ECC mechanism for the SRAM by creating an error in the data bits. 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 location 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)
{

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;

volatile uint64 ecc8 = 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 */

ecc7 = (*(volatile uint64 *)0x084000C0U);
_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?

_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

  • Hi Pritesh,

         Thanks for you post. We are looking into this and will get back to you later. 

    Best Regards,
    Shelford

  • I have attempted a few modifications according to the mechanism proposed in the ECC handling document spna126. I am using DMB and ISB to ensure completion of operation before further instructions are processed.  I have attached the relevant files to this message. The problem now is that, even after disabling ECC, the ECC bits are modified as observed in the memory window of the debugger. The ECC mechanism does not get disabled. Also an attempt to read the ECC memory in leads to calling of custom_dabort interrupt.

    void main(void)
    {
    volatile uint64 read1 ;
    volatile uint64 read2;

    _esmCcmErrorsClear_();

    _eccEnableBusExportAndCpuEcc_();

    memoryInit(0x1U);

    (*(volatile uint64 *)(0x080000C0U)) = 0x5U; // Writing Data
    read1 = (*(volatile uint64 *)(0x080000C0U)); // Reading data to check
    //ecc = (*(volatile uint64 *)(0x084000C0U)); // This operation leads to custom_dabort prefetched entry interrupt
    _eccDisableBusExportAndCpuEcc_(); // Disabling the CPU SRAM ECC and event reporting

    (*(volatile uint64 *)(0x080000C0U)) ^= 0x1U; // Modifying Data Bits: "This causes ECC memory bits to change"

    _eccEnableBusExportAndCpuEcc_(); //Enabling ECC and reporting

    read2 = (*(volatile uint64 *)(0x080000C0U)); //Reading Data : Must be 0x5U output but is 0x4U(after changing 1 bit)

    while(1);

    }

    ; ECC procedures file ecc_control.asm

    .text
    .arm

    ; Enable Event Bus Export and ECC

    .def _eccEnableBusExportAndCpuEcc_
    .asmfunc

    _eccEnableBusExportAndCpuEcc_

    stmfd sp!, {r0}
    mrc p15, #0x00, r0, c9, c12, #0x00 ; Reading secondary Aux secondary Reg
    orr r0, r0, #0x10
    DMB
    mcr p15, #0x00, r0, c9, c12, #0x00 ; Enable export of the events in PMNC
    ISB ; To ensure the write before proceeding


    mrc p15, #0x00, r0, c1, c0, #0x01
    orr r0, r0, #0x0C000000 ; B0TCM/BITCM ECC Check Enable bits 26 and 27
    DMB
    mcr p15, #0x00, r0, c1, c0, #0x01
    ISB
    ldmfd sp!, {r0}
    bx lr

    .endasmfunc

    .def _eccDisableBusExportAndCpuEcc_
    .asmfunc

    _eccDisableBusExportAndCpuEcc_

    stmfd sp!, {r0}
    mrc p15, #0x00, r0, c9, c12, #0x00 ; Reading secondary Aux secondary Reg
    bic r0, r0, #0x10
    DMB
    mcr p15, #0x00, r0, c9, c12, #0x00 ; Disable export of the events in PMNC
    ISB ; To ensure the write before proceeding


    mrc p15, #0x00, r0, c1, c0, #0x01
    bic r0, r0, #0x0C000000 ; B0TCM/BITCM ECC Check Disable bits 26 and 27
    DMB
    mcr p15, #0x00, r0, c1, c0, #0x01
    ISB
    ldmfd sp!, {r0}
    bx lr

    .endasmfunc

    Files: Main: 7888.main.c

    ecc routines header file: 5141.ecc_routines.h

    ecc_routines assembly file : 0488.ecc_asm_routines.asm

  • Hi Pretish,

            Sorry for the late reply.  We took some time to look into this issue, please see my comments as below:

            1. Yes, when you disable ECC function in HALCoGen, We may need to fix it in the future.  If you want to disable ECC function before the main routine, you need to remove the "_coreEnableRamEcc_()"  function from the sys_startup.c file.

            2. Here the "_coreEnableRamEcc_();" and "_coreDisableRamEcc_();" just enable and disable the ECC data check function not the ECC data generation. Because it's the ECC mechanism designed by ARM. So when you disable ECC, you still can see the generated  ECC bits in the in the memory window. 

            3. Why you see the "BAD" data in the memory window when the ECC fucntion is enabled?  It's because CPU will check related ECC RAM data for each reading from  RAM data.  Meanwhile, please notice each refresh in the memory window is one time of reading from memory. So when you enable the ECC function, you read from the RAM data, you will get the correct value because you have the corresponding ECC RAM.   But when you read the ECC RAM data or display in the memory window, there will be a abort because  the ECC RAM datas haven't ECC RAM for itself.   So when you want to read the value from ECC RAM or want to see the value in memory window, you need to disable the ECC function before the reading instruction. Just use the "_coreDisableRamEcc_();" function

    Hope that this may help you.

    Best Regards,
    Shelford


  • Hi,

    So the question remains is how do I test that the ECC mechanism, particularly single error correction is working? I followed the procedure in the section 3.4 of the ECC handing in TMSx70-Based Microcontrollers. (Application report SPNA126).  Please check my previous post where I have attached the relevant files and the explanation for the code. Section 3.4 of SPNA126 provides a procedure of inserting an error into the RAM/ECC. I must have a way to test the ECC mechanism and show that the relevant procedure is working as I am working on an application for which consistency and correctness is critical. Please suggest some other way through which I may insert the error into the Data/ECC bits(possibly externally) and check that the SECDED mechanism is working. 

    Regards,

    Pritesh

  • Hi,

    I am using the hardware initialization function memoryInit available in the sys_selftest.c file generated by Halcogen. I call the memoryInit function with ram = 0x1U. as per the datasheet SPNS162A datasheet for TMS570LS3137 Microcontroller. But by using this only the memory in the RAM range of 0x08000000 to 0x0800FFFF gets initialized to 0. All the SRAM memory from location 0x08010000 onwards holds the data 0xBAD0BAD0. 

    void memoryInit(uint32 ram)
    {/* Enable Memory Hardware Initialization */

    systemREG1->MINITGCR = 0xAU;

    /* Enable Memory Hardware Initialization for selected RAM's */
    systemREG1->MSINENA = ram;

    /* Wait until Memory Hardware Initialization complete */
    while((systemREG1->MSTCGSTAT & 0x00000100U) != 0x00000100U)
    {
    }/* Wait */

    /* Disable Memory Hardware Initialization */
    systemREG1->MINITGCR = 0x5U;
    }

    I wish to actually run a code of this below form where I read and write to the memory locations so that the ECC checking/correction is done on the read. And the corrected data is written on the write back to the SRAM. This checking will eliminate all the single bit errors in the SRAM memory. But this function causes an abort,specifically to _dabort in the dabort.asm file. No errors are detected as the program skips to the noRamError routine in this dabort.asm file. 

    This happens exactly when "i = 0x08010000" and at the instruction  "temp = (*((volatile uint64*)i));". The program does not proceed beyond this point. It keeps on jumping the _dabort routine and back to the "temp = (*((volatile uint64*)i));" routine. No change of actions take place. No increment in "i" value takes place.

    void SramMemoryRefresh()
    {
    uint64 i,temp;
    i = 0x8000000;
    while(i < 0x80400000)
    {
    temp = (*((volatile uint64*)i));
    (*((volatile uint64*)i)) = temp;
    i += 0x8;
    }
    }

    Please examine the above case.

    Regards,

    Pritesh

  • Hi  Pritesh,

          Sorry for the delay reply. Now you want to test if our ECC mechanism(especially single bit correction) works.  You have two ways: 1. Use some energetic particles(like Alpha, neutron ...) to generate one bit flip. 2. Change one bit in ECC RAM with MCU writing. Why can't you change one bit in data field RAM?  Because our ECC generation function is always on, and you just can turn off the ECC check function. So when you change one bit in data field RAM, the corresponding ECC bits will be changed too.  Talking about monitor the one bit error correction situation.  We have one register to display the single-bit error occurrences in TCRAM module. It's register RAMOCCUR(TCRAM Module Single-Bit Error Occurrences Control Register). You can find it in the Tightly-Coupled RAM (TCRAM) Module section of  TRM.   I have post an ECC test example for your reference.  Notice that: 1. You must turn off ECC check function before you read the ECC bits. 2. You need to enable the ECC check fucntion and read the data and then you can see the detection of the one bit error. 

         7485.RM46HDK_ECC_TEST.zip

     Hope that this may help you.

    Best Regards,
    Shelford

  • Hi,

    Thank you for the reply. I now have a complete routine which performs memory scrubbing for the SRAM on the TMS570LS31x HDK. The primary action that must be performed is the clearing of the Status register of the Error Signalling Module as this remains active even after Power-On Reset. Then the routine stops in the sys_startup.c files on reset. Once it gets stuck here.... one has no other option but to remove that for(){} infinite loop by using if 0 , endif. Now I have a problem that I am modifying 2 bits in one word. It still gets detected as 1 bit error. Please look at the test_ECC function below.

    Following are my error checking and test functions.

    void SramMemOptiRef_Subroutine(volatile uint64* start,volatile uint64* end)
    {
    volatile uint64 temp;
    while(start < end)
    {
    temp = *start;
    //(*((volatile uint64*)start)) = temp;


    /* Checking for errors in memory */
    if (((tcram1REG->RAMERRSTATUS & 1U) == 1U))
    {
    *start = temp;
    printf("Error found1 %p\n",start);
    }
    else if (((tcram2REG->RAMERRSTATUS & 1U) == 1U))
    {
    *start = temp;
    printf("Error found2\n");
    }

    else if (((tcram1REG->RAMERRSTATUS & 0x20U) == 0x20U))
    {
    /*Multibit Error. Handle as per application requirements*/
    /* Error Address in *(uint64 *start) */
    printf("Error found3\n");
    }
    else if(((tcram2REG->RAMERRSTATUS & 0x20U) == 0x20U))
    {
    /*Multibit Error. Handle as per application requirements*/
    /* Error Address in *(uint64 *start) */
    printf("Error found4\n");
    }
    else
    {
    /* printf("All conditions failed\n"); */
    }

    /* clear SERR/MERR flags */
    tcram1REG->RAMERRSTATUS = 0x33U; //Bits 0 and 5
    tcram2REG->RAMERRSTATUS = 0x33U;

    /* clear status flags for ESM group1 channels 26 and 28 */
    esmREG->ESTATUS1[0U] = 0x14000000U;
    /* clear status flags for ESM group2 channels 6,8,10 and 12 */
    esmREG->ESTATUS1[1U] = 0xAA0U;
    /* clear status flags for ESM group3 channels 3 and 5 */
    esmREG->ESTATUS1[2U] = 0x28U;

    start++;
    }

    void SramMemoryOptiRefresh(void)
    {

    EnableECCSRAM();

    tcram1REG->RAMCTRL = 0x0005000AU;
    tcram2REG->RAMCTRL = 0x0005000AU;
    /* Checking and correcting memory 64 KB in one call */
    SramMemOptiRef_Subroutine((volatile uint64*)(0x8000000U),(volatile uint64*)(0x8010000U));

    SramMemOptiRef_Subroutine((volatile uint64*)(0x8010000U),(volatile uint64*)(0x8020000U));

    SramMemOptiRef_Subroutine((volatile uint64*)(0x8020000U),(volatile uint64*)(0x8030000U));

    SramMemOptiRef_Subroutine((volatile uint64*)(0x8030000U),(volatile uint64*)(0x8040000U));

    return;
    }

    void test_ECC()
    {
    DisableECCSRAM();

    /* Enable Writes to ECC SRAM */
    tcram1REG->RAMCTRL = 0x0005010AU;
    tcram2REG->RAMCTRL = 0x0005010AU;

    /*Set Single Error Correction Threshold to 1 */
    tcram1REG->RAMTHRESHOLD = 0x1U;
    tcram2REG->RAMTHRESHOLD = 0x1U;
    /* cause a 1-bit ECC error */
    (*(volatile uint32 *)(0x080000C0U)) ^= 0x1U;   // all these errors are detected as 1 bit errors only. ????
    //(*(volatile uint32 *)(0x080011C0U)) ^= 0x16U;
    //(*(volatile uint32 *)(0x080021C0U)) ^= 0x1111U;

    /* disable writes to ECC RAM */
    tcram1REG->RAMCTRL = 0x0005000AU;
    tcram2REG->RAMCTRL = 0x0005000AU;

    /*Calling Function twice to check if error was corrected */
    printf("First Call to Error Correcting Function\n");
    SramMemoryOptiRefresh();
    printf("Second Call to Error Correcting Function\n");
    SramMemoryOptiRefresh();
    }

    What am I doing wrong here? as modifying more than 2 bits in ECC bits still causes the error to be detected as 1 bit error only.

    Please let me know if you need the full code and the execution output.

    Regards,

    Pritesh

  • Pritesh,

         Please post your whole project. Thanks.

    Best Regards,

    Shelford

  • Hi,

    I am attaching the whole project to this post. It is a CCSv4 project. Please uncomment the lines for double bit changes to the memory bits in the test_ECC function which can be found in the ecc_routines.c file.

    4300.sram_ecc_test.zip

    Regards,

    Pritesh