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 ECC RAM for TMS320F28377D

Other Parts Discussed in Thread: TMS320F28377D, CONTROLSUITE

We’re trying to verify that ECC RAM is working correctly at runtime for a TMS320F28377D. Tentatively, we were planning to test the single bit correction as follows:

  1. Set a word of memory to a known value
  2. Change the memory mapping of ECC RAM from Functional Mode to Data or ECC Mode using the DxTEST register
  3. Flip a single bit
  4. Change the memory mapping back to Functional Mode
  5. Read the word of memory and verify its set to the correct value
  6. Check the CERRCNT register and verify it incremented
  7. Check the CERRFLG register and verify DMARDERR is set
  8. Check the CCPUREADDR register and verify it is set to the correct address

We’ve successfully completed steps 1 – 5, however we’re having trouble with steps 6 – 8. Looking at the memory mapping for those registers, all 3 values always remain 0.

We were also planning to test the 2 bit error detection (similar to steps 1 – 4). After injecting an error, we were planning to:

  1. Check the UCERRFLG register and verify DMARDERR is set
  2. Check the UCDMAREADDR register and verify it is set to the correct address
  3. Check the NMIFLG register and verify RAMUNCERR is set (Not sure if this will work since we’ve disabled Non-Maskable interrupts)

These 3 values also remain 0. In fact, we’ve never seen any of the MemoryErrorRegs (0x0005_F500 – 0x0005_F53F) set to anything other than 0. It’s also worth noting, the MemoryErrorRegs don’t appear in the Registers tab of the debugger (CCS 6.1.0.000104).

Appreciate any suggestions you may have for us

  • Hi Zach,

    Your understanding is correct and steps are also correct. It should work.

    Are you checking these values in CCS memory watch window or reading inside code?

    Could you send me your code snapshot for this part?

    Regards,

    Vivek Singh

  • Hi Vivek,

    I'm working with Zach, here is the code snapshot

    typedef enum
    {
    	eM0,
    	eM1,
    	eD0,
    	eD1
    } eECC_MEM_REGION;
    
    typedef struct
    {
    	uint16_t TEST_MO:2;
    	uint16_t TEST_M1:2;
    	uint16_t TEST_D0:2;
    	uint16_t TEST_D1:2;
    	uint16_t rsvd1:8;
    	uint16_t rsvd2;
    } DxTEST_BITS;
    
    	typedef struct
    	{
    		uint16_t INIT_MO:1;
    		uint16_t INIT_M1:1;
    		uint16_t INIT_D0:1;
    		uint16_t INIT_D1:1;
    		uint16_t rsvd1:12;
    		uint16_t rsvd2;
    	} DxINIT_BITS;
    
    /*
     * Static
     *
     * Common_RAM_ECC_TEST - This function tests the ECC capability of the DSP to detect single bit errors.
     * It will inject a parity fault at the given start address and verify the data was corrected.
     *
     * Parameters
     *     uint16_t uiStartAddress[], start address of the RAM area to be tested
     *     eECC_MEM_REGION region, region of memory to test
     *
     * Returns
     *     TRUE if the RAM ECC test passes
     *     FALSE if the RAM ECC test fails
     */
    STATIC uint16_t Common_RAM_ECC_Test(uint16_t uiStartAddress[], eECC_MEM_REGION region)
    {
    	uint16_t pattern = 0u;
    	uint16_t isPass = TRUE;
    
    	DxTEST_BITS *const test = (DxTEST_BITS *)(MEM_CFG_REG_BASE + 0x10u);
    	CERRFLG_BITS *const cerrFlg = (CERRFLG_BITS *)(MEM_ERR_REG_BASE + 0x20u);
    	uint32_t *const cerrCnt = (uint32_t *)(MEM_ERR_REG_BASE + 0x2Eu);
    	uint32_t temp;
    
    	/* Write a known value to the memory address */
    	uiStartAddress[0] = pattern;
    	temp = *cerrCnt;
    
    	/* 1) Change the memory mapping of ECC RAM from Functional Mode to Data or ECC Mode
    	 * 2) Flip a single bit
    	 * 3) Change the memory mapping back to Functional Mode
    	 */
    	switch (region){
    		case eM0 :
    			__asm(" EALLOW");
    			test->TEST_MO = 0x2;
    			__asm(" EDIS");
    			uiStartAddress[0] = uiStartAddress[0] ^ 0x1;
    			__asm(" EALLOW");
    			test->TEST_MO = 0x0;
    			__asm(" EDIS");
    			break;
    		case eM1 :
    			__asm(" EALLOW");
    			test->TEST_M1 = 0x2;
    			__asm(" EDIS");
    			uiStartAddress[0] = uiStartAddress[0] ^ 0x1;
    			__asm(" EALLOW");
    			test->TEST_M1 = 0x0;
    			__asm(" EDIS");
    			break;
    		case eD0 :
    			__asm(" EALLOW");
    			test->TEST_D0 = 0x2;
    			__asm(" EDIS");
    			uiStartAddress[0] = uiStartAddress[0] ^ 0x1;
    			__asm(" EALLOW");
    			test->TEST_D0 = 0x0;
    			__asm(" EDIS");
    			break;
    		case eD1 :
    			__asm(" EALLOW");
    			test->TEST_D1 = 0x2;
    			__asm(" EDIS");
    			uiStartAddress[0] = uiStartAddress[0] ^ 0x1;
    			__asm(" EALLOW");
    			test->TEST_D1 = 0x0;
    			__asm(" EDIS");
    			break;
    		default :
    			isPass = FALSE;
    			break;
    	}
    
    	/* Read the word of memory and verify its set to the correct value */
    	if (uiStartAddress[0] != pattern){
    		isPass = FALSE;
    	}
    
    	/* Ensure the ECC Error Count has incremented by 1 */
    	if(*cerrCnt != (temp + 1))
    	{
    //		isPass = FALSE;
    	}
    	/* TBD: Check the CERRFLG register and verify DMARDERR is set */
    
    	/* TBD: Check the CCPUREADDR register and verify it is set to the correct address */
    
    	return isPass;
    }
    

    Thanks for your help.

    Tim Peterson

  • Hi Tim,

    In all case you are updating the value of same variable "uiStartAddress[0]"? Where is this variable mapped? It should be in same memory for which the test feature is getting tested. Can you please confirm?

    Regards,

    Vivek Singh
  • Hi Vivek,

    Per section 6.3.1 of the datasheet, uiStartAddress points to the following locations in memory:

    M0 0x0000 0000
    M1 0x0000 0400
    D0 0x0000 B000
    D1 0x0000 B800

    Also, looking at the code again, we noticed the variables uiStartAddress, test, cerrFlg, and cerrCnt should all be marked volatile.  We've updated the code, however the problem still persists.

    Thanks for your help,

    Zach Wolbers

  • Hi Zach,

    You are using test mode 0x2 (test->TEST_MO = 0x2)which updates ECC value. Instead of 0x2, could you try value 0x1 which update data value and see if that makes any difference in the result you are seeing.

    Regards,

    Vivek Singh

  • Hi Vivek,

    We tried switching to data mode, however the MemoryErrorRegs still don't update as expected.

    Thanks,

    Zach

  • Hi Zach,

    My first suggestion was going to be to make uiStartAddress a pointer to volatile memory. But it looks like you may have done that.
    Just make sure that the pointer isn't volatile, but the pointer points to volatile memory. Also, you will need to declare it as a volatile parameter in the function prototype and definition.

    Also, you said, "uiStartAddress points to the following locations in memory:..."

    Is this what you mean?
    uiStartAddress[0] = 0x0000 0000;
    uiStartAddress[1] = 0x0000 0400;
    uiStartAddress[2] = 0x0000 B000;
    uiStartAddress[3] = 0x0000 B800;

    If this is what you mean, then this will not work. What is the value of &uiStartAddress? In other words, what is the reference address of uiStartAddress?

    What you will need to do is declare the address of uiStartAddress to be these values.
    For example:
    uint16_t * uiStartAddress = 0x0000 0000; OR uint16_t uiStartAddress = 0x0000 0400; etc.

    But make sure that the address of uiStartAddress is not being used for something else. You can reserve some words for testing using the linker command file.

    sal
  • Hi Sal,

    Since the code snippet provided earlier is a little out of date, and since it references code from elsewhere in our project, I thought it'd save us time if I created a small, standalone project we can both run and test.

    Unfortunately, I can't attach an export of the project to a forum post. However, if you import the following project from controlSUITE, and update blinky_cpu01.c with the following code, you should be able to run the test.

    \controlSUITE\device_support\F2837xD\v200\F2837xD_examples_Cpu1\blinky\

    #include "F28x_Project.h"
    
    typedef enum
    {
        PASS,
        ASSERT_CERRCNT_FAILURE,
        ASSERT_CERRFLG_FAILURE,
        VALUE_FAILURE,
        CERRCNT_FAILURE,
        CERRFLG_FAILURE,
    } Status;
    
    void main(void)
    {
        Status status = PASS;
        const Uint16 pattern = 0;
        volatile Uint16* const data = (volatile Uint16*)(0xB000);   // D0
    
        InitSysCtrl();
    
        InitGpio();
        GPIO_SetupPinMux(31, GPIO_MUX_CPU1, 0);
        GPIO_SetupPinOptions(31, GPIO_OUTPUT, GPIO_PUSHPULL);
    
        DINT;
    
        InitPieCtrl();
    
        IER = 0x0000;
        IFR = 0x0000;
    
        InitPieVectTable();
    
        EINT;
        ERTM;
    
    
        GPIO_WritePin(31, 1);   //  Turn off LED
    
        //  Set a word of memory to a known value
        if(status == PASS)
        {
            *data = pattern;
        }
    
        //  Verify CERRCNT is 0
        if((status == PASS) && (MemoryErrorRegs.CERRCNT != 0))
        {
            status = ASSERT_CERRCNT_FAILURE;
        }
    
        //  Verify CERRFLG is not set
        if((status == PASS) && (MemoryErrorRegs.CERRFLG.bit.DMARDERR != 0))
        {
            status = ASSERT_CERRFLG_FAILURE;
        }
    
        //  Change the memory mapping of ECC RAM from Functional Mode to Data or Parity Mode using the DxTEST register
        if(status == PASS)
        {
            EALLOW;
            MemCfgRegs.DxTEST.bit.TEST_D0 = 0x1;    //  Data Mode
            //MemCfgRegs.DxTEST.bit.TEST_D0 = 0x2;    //  Parity Mode
            EDIS;
        }
    
        //  Flip a single bit
        if(status == PASS)
        {
            *data = *data ^ 0x1;
        }
    
        //  Change the memory mapping back to Functional Mode
        if(status == PASS)
        {
            EALLOW;
            MemCfgRegs.DxTEST.bit.TEST_D0 = 0x0;
            EDIS;
        }
    
        //  Read the word of memory and verify its set to the correct value
        if((status == PASS) && (*data != pattern))
        {
            status = VALUE_FAILURE;
        }
    
        //  Check the CERRCNT register and verify it incremented
        if((status == PASS) && (MemoryErrorRegs.CERRCNT != 1))
        {
            status = CERRCNT_FAILURE;
        }
    
        //  Check the CERRFLG register and verify DMARDERR is set
        if((status == PASS) && (MemoryErrorRegs.CERRFLG.bit.DMARDERR != 1))
        {
            status = CERRFLG_FAILURE;
        }
    
        //  Report any error
        if(status != PASS)
        {
            GPIO_WritePin(31, 0);   //  Turn on LED
        }
    
        //  Idle loop
        for(;;)
        {
            DELAY_US(1000*500);
        }
    }
    

    The test runs on D0 (mapped to 0x0000 B000 in memory) - neither CERRCNT nor CERRFLG.DMARDERR are set.

    Zach

  • Hi Zach,

    Try this

    #include "F28x_Project.h"

    #define HWREG(x) \
    (*((volatile uint32_t *)(x)))
    #define HWREG_BP(x) \
    __byte_peripheral_32((uint32_t *)(x))
    #define HWREGH(x) \
    (*((volatile uint16_t *)(x)))
    #define HWREGB(x) \
    __byte((int16_t *)(x),0)

    typedef enum
    {
    PASS,
    ASSERT_CERRCNT_FAILURE,
    ASSERT_CERRFLG_FAILURE,
    VALUE_FAILURE,
    CERRCNT_FAILURE,
    CERRFLG_FAILURE,
    } Status;

    void main(void)
    {
    Status status = PASS;
    const Uint32 pattern = 0;
    volatile Uint32* addr = (volatile Uint32*)(0x0000); // D0

    InitSysCtrl();

    InitGpio();
    GPIO_SetupPinMux(31, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(31, GPIO_OUTPUT, GPIO_PUSHPULL);

    DINT;

    InitPieCtrl();

    IER = 0x0000;
    IFR = 0x0000;

    InitPieVectTable();

    EINT;
    ERTM;


    GPIO_WritePin(31, 1); // Turn off LED

    // Set a word of memory to a known value
    HWREG(addr) = pattern;

    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");

    // Change the memory mapping of ECC RAM from Functional Mode to Data or Parity Mode using the DxTEST register
    EALLOW;
    MemCfgRegs.DxTEST.bit.TEST_D0 = 0x1; // Data Mode
    //MemCfgRegs.DxTEST.bit.TEST_D0 = 0x2; // Parity Mode
    MemCfgRegs.DxTEST.bit.TEST_D1 = 0x1; // Data Mode
    //MemCfgRegs.DxTEST.bit.TEST_D1 = 0x2; // Parity Mode
    MemCfgRegs.DxTEST.bit.TEST_M0 = 0x1; // Data Mode
    //MemCfgRegs.DxTEST.bit.TEST_M0 = 0x2; // Parity Mode
    MemCfgRegs.DxTEST.bit.TEST_M1 = 0x1; // Data Mode
    //MemCfgRegs.DxTEST.bit.TEST_M1 = 0x2; // Parity Mode
    EDIS;

    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");

    HWREG(addr) = HWREG(addr) ^ 0x1;

    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");

    // Change the memory mapping back to Functional Mode
    EALLOW;
    MemCfgRegs.DxTEST.bit.TEST_D0 = 0x0;
    MemCfgRegs.DxTEST.bit.TEST_D1 = 0x0;
    MemCfgRegs.DxTEST.bit.TEST_M0 = 0x0;
    MemCfgRegs.DxTEST.bit.TEST_M1 = 0x0;
    EDIS;

    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");
    __asm(" NOP");

    uint32_t temp = HWREG(addr);

    // Read the word of memory and verify its set to the correct value
    if((status == PASS) && (HWREG(addr) != pattern))
    {
    status = VALUE_FAILURE;
    }

    // Check the CERRCNT register and verify it incremented
    if((status == PASS) && (MemoryErrorRegs.CERRCNT != 1))
    {
    status = CERRCNT_FAILURE;
    }

    // Check the CERRFLG register and verify DMARDERR is set
    if((status == PASS) && (MemoryErrorRegs.CERRFLG.bit.DMARDERR != 1))
    {
    status = CERRFLG_FAILURE;
    }

    // Report any error
    if(status != PASS)
    {
    GPIO_WritePin(31, 0); // Turn on LED
    }

    // Idle loop
    for(;;)
    {
    DELAY_US(1000*500);
    }
    }


    It looks to me like it may require a 32-bit write and a 32-bit read to create the error.

    sal
  • OK, I think I've solved a couple problems.

    • The registers/bit fields listed in my original post and in the code above are incorrect - ECC/Parity errors generate CPU Read Errors, not DMA Read Errors. This explains why my test program failed. After updating the code, the following registers work as expected:
      • CERRFLG.CPURDERR
      • CERRCLR.CPURDERR
      • CCPUREDDR
      • UCERRFLG.CPURDERR
      • UCERRCLR.CPURDERR
      • UCCPUREADDR
      • NMIFLG.RAMUNCERR
      • NMIFLGCLR.RAMUNCERR
    • My original project wasn't properly initializing the DSP. This explains why all of the MemoryErrorRegs were always 0.

    The only problem remaining is CERRCNT - it's still always set to 0. When I ran your test program, CERRCNT was the test that caused it to fail (on line 120). Any ideas why it's the odd man out?

    Thanks,
    Zach

  • Not sure what line 120 is, but I stated above It looks to me like it may require a 32-bit write and a 32-bit read to create the error.

    sal
  • Hi Sal,

    The program you posted earlier performs a 32 bit read/write to memory. On line 120, CERRCNT is read (a 32 bit register); but it isn't incremented.

    On a side note, I'd hope these read/writes don't need to be 32 bits. At the end of the day, we're planning to monitor these registers for memory errors - the main program almost certainly will perform 16 bit read/writes. The status flag registers respond to 16 bit read/writes; I would think CERRCNT would too...

    Zach

  • You are wright. A 32-bit read should not be required. Are you unable to see CERRCNT increase with the code I sent you?

  • Correct - CERRCNT did not update when I ran your code.
  • I just ran some tests. If you set the correctable error threshold greater than 0, then you will see the correctable error count register increment.

    sal
  • Zach,
    Have you been able to test this. If this fixes the issue, please verify the answer above to close the thread.

    sal
  • Hi Sal,

    Just tried it - the counter incremented as expected.

    Thanks again,
    Zach