How to test SMU SRAM errors by injectiing ECC errors

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
User18541
Level 1
Level 1
First question asked Welcome!
Hello,

I am using TC23xx microcontroller and would like to test the SafeTLib SMU for the following SM1 SRAM errors.


  • SM1[HW].SRAM:ECC
  • SM1[HW].SRAM:EDC
  • SM1[HW].SRAM:ADDRMON


How can I enable and inject ECC errors to test the above SRAM errors ?

Thanks.
0 Likes
7 Replies
ScottW
Employee
Employee
10 sign-ins First solution authored First like received
See the ECC Bit Mapping Mode of the ECC Safety Register: ECCS.ECCMAP
0 Likes
User22439
Level 1
Level 1
First like received Welcome!
Scott Winder wrote:
See the ECC Bit Mapping Mode of the ECC Safety Register: ECCS.ECCMAP


Hello

I'm using TC275x, and am trying to inject RAM ECC error to CPU0 DSPR location.

Following are the steps performed:-

1. Write 32-bit dummy data to the RAM address (i.e. for CPU0 DSPR).
2. Disabled ECC functionality by writing “0x4000” to ECCD register ( Considered Safety end init protection & dummy write with “0x780F”).
3. Write Dummy Flipped data to a suspicious address.
4. Enabled ECC by writing “0x7800” to the ECCD register. ( Considered Safety end init protection & dummy write with “0x780F”).
5. Perform Read -write to the suspicious address again location to trigger ECC detection and checked the CERR bit status for that particular memory controller. (ie, MC14 for CPU0DSPR)

by performing the following steps I didn't observe the correctable error flag set in the ECCD register.

Following are my queries.
1. How to disable and enable ECC functionality? will Step 2 disable the functionality or just the error correction feature.
2. Tried writing ECCS.ECCMAP -> 01 but accessing the register is causing a trap,is there any preconditions other than to disable endinit protect?
3. For How many Data bits ECC is calculated for DSPR, PSPR, LMU?

Please share if any Hints.

Thank you

Regards
Gokul
0 Likes
NeMa_4793301
Level 6
Level 6
10 likes received 10 solutions authored 5 solutions authored
I use the MTU to inject errors. See this snippet:


#include "IfxMc_reg.h"
#include "IfxMc_bf.h"
#include "IfxMtu_reg.h"
#include "IfxScu_reg.h"
#include "IfxSmu_reg.h"
#include "IfxEmem_reg.h"
#include "IfxLmu_reg.h"
#include "IfxFlash_reg.h"

/* Defines */
#define SRAM_MC_ADDR_RANGE_SIZE ( (uint32) &MODULE_MC1 - (uint32) &MODULE_MC0 )
#define MC_NUMBER_DSPR0 (14)
#define MC_NUMBER_PSPR0 (16)
#define MC_NUMBER_DSPR1 (6)
#define MC_NUMBER_PSPR1 (9)
#define MC_NUMBER_EMEM_LOWER_0 (46) // see Table 8-21 Memory Controller in the User Manual
#define MC_NUMBER_LMU (79)

#define SRAM_MBIST_OPERATION_WAIT 50U

/* MCx_CONFIG0 values: */
#define SRAM_CONFIG0_NUMACCS_1 (1U)
#define SRAM_CONFIG0_ACCSTYPE_RD (1U)
#define SRAM_CONFIG0_ACCSTYPE_WR (0U)
#define MC_MCONTROL_USERED_MSK (1U)
#define MC_MCONTROL_USERED (14U)


/* Function Prototypes */
static void inject_dspr_error( void );
static void inject_pspr_error( void );
static void inject_lmu_error( void );
static void inject_emem_error( void );
static void inject_memory_error( const uint32 mc_number, const uint32 range );
static void smu_init( void );
static void read_raw_pflash_ecc( void );

volatile unsigned short etrr[88];
volatile unsigned short eccd[88];
volatile unsigned short mtu_value[128];
volatile unsigned long smu_ag[7];

int main(void)
{
volatile unsigned long *p;
volatile long i;

// test reading raw PFLASH ecc
read_raw_pflash_ecc();

// Enable MTU clock
_endinit_clear();
MTU_CLC.B.DISR = 0U;
while(MTU_CLC.B.DISS);
_endinit_set();

inject_emem_error(); // blows a hole @ 0xBF000200
// inject_lmu_error(); // blows a hole @ 0xB0000080

smu_init();


//inject_dspr_error();
//inject_pspr_error();

p = (unsigned long *) 0xBF000200; // read from initialized EMEM - no problem
//*(p + 1) = 4;
i = *p;
// p = (unsigned long *) 0xBF000200; // uncomment this line to cause EMEM alarm ALM4[13]
// i = *p;

// p = (unsigned long *) 0xB0000080; // uncomment this line to cause LMU alarms ALM2[18]
// i = *p;
// *(p+1) = 4;

for( ;; )
{
}
}



static void inject_dspr_error( void )
{
_safety_endinit_clear();

MTU_MEMTEST0.B.CPU1DSEN = 1U; // Enable MTU for DSPR1

do
{
__asm("nop");
} while ( (MTU_MEMSTAT0.U & (1 << (MC_NUMBER_DSPR1 & 0x1F))) != 0U );

inject_memory_error( MC_NUMBER_DSPR1, 0);

MTU_MEMTEST0.B.CPU1DSEN = 0U; // Disable MTU for DSPR0

do
{
__asm("nop");
} while ( (MTU_MEMSTAT0.U & (1 << (MC_NUMBER_DSPR1 & 0x1F))) != 0U );

_safety_endinit_set();
}



static void read_raw_pflash_ecc( void )
{
volatile unsigned char *p;
volatile unsigned char dummy;
volatile unsigned int eccrp2;

_endinit_clear();
FLASH0_MARP.B.TRAPDIS = 1;
FLASH0_ECCRP2.U = 0x80000000; // disable ECC handling viab ECCORDIS=1
p = (unsigned char *) 0xA05C0180;
dummy = *p;

eccrp2 = FLASH0_ECCRP2.U;
FLASH0_MARP.B.TRAPDIS = 0;
FLASH0_ECCRP2.U = 0x00000000; // disable ECC handling viab ECCORDIS=1
_endinit_set();
}



static void inject_pspr_error( void )
{
_safety_endinit_clear();

MTU_MEMTEST0.B.CPU1PSEN = 1U; // Enable MTU for PSPR0

do
{
__asm("nop");
} while ( (MTU_MEMSTAT0.U & (1 << (MC_NUMBER_PSPR1 & 0x1F))) != 0U );

inject_memory_error( MC_NUMBER_PSPR1, 0 );

MTU_MEMTEST0.B.CPU1PSEN = 0U; // Disable MTU for PSPR0

do
{
__asm("nop");
} while ( (MTU_MEMSTAT0.U & (1 << (MC_NUMBER_PSPR0 & 0x1F))) != 0U );

_safety_endinit_set();
}



static void inject_emem_error( void )
{
volatile unsigned long long *p;
volatile unsigned long o;
int i;

_endinit_clear();
EMEM_CLC.U = 0;
o = EMEM_CLC.U;

// see 36.2.6 EMEM initialization - 3 writes required to SBRCTR to unlock memory
EMEM_SBRCTR.U = 2;
EMEM_SBRCTR.U = 6;
EMEM_SBRCTR.U = 0xE;
EMEM_TILECONFIG.U = 0; // required after reset to allocate ADM (first 1 MB)
EMEM_TILECONFIGXM.U = 0; // required after reset to allocate XAM (second 1 MB)

_endinit_set();

p = (unsigned long long *) 0xBF000000;
for( i=0; i<0x2000; i++ )
{
*p++ = 0;
}

_safety_endinit_clear();
MTU_MEMTEST1.B.EMEML0EN = 1U; // Enable MTU for LMU operations

MC46_ECCD.U = 0x7810; // MUST BE A 16-BIT WRITE TO WORK... NOT A BITSET
//MC46_ECCD.B.TRC = 1; // clear all error tracking entries THIS BITSET DOESN'T WORK
//MC46_ECCD.B.SERR = 1; // clear error status THIS BITSET DOESN'T WORK

do
{
__asm("nop");
} while ( (MTU_MEMSTAT1.U & (1 << (MC_NUMBER_EMEM_LOWER_0 & 0x1F))) != 0U );

eccd[46] = MC46_ECCD.U;
etrr[46] = MC46_ETRR0.U;
inject_memory_error( MC_NUMBER_EMEM_LOWER_0, 0x10 );

MTU_MEMTEST1.B.EMEML0EN = 0U; // Disable MTU for LMU operations

do
{
__asm("nop");
} while ( (MTU_MEMSTAT1.U & (1 << (MC_NUMBER_EMEM_LOWER_0 & 0x1F))) != 0U );

_safety_endinit_set();
}



static void inject_lmu_error( void )
{
_safety_endinit_clear();

MTU_MEMTEST2.B.DAMEN = 1U; // Enable MTU for LMU operations

do
{
__asm("nop");
} while ( (MTU_MEMSTAT2.U & (1 << (MC_NUMBER_LMU & 0x1F))) != 0U );

inject_memory_error( MC_NUMBER_LMU, 0x10 );

MTU_MEMTEST2.B.DAMEN = 0U; // Disable MTU for LMU operations

do
{
__asm("nop");
} while ( (MTU_MEMSTAT2.U & (1 << (MC_NUMBER_LMU & 0x1F))) != 0U );

_safety_endinit_set();

}

static void inject_memory_error( const uint32 mc_number, const uint32 range )
{
uint32 ResultLoopCount;

Ifx_MC *Mc;

/* Get pointer to memory controller SFRs of RAM under test: */
Mc = (Ifx_MC *) ( (uint32) &MODULE_MC0 +
( (uint32) SRAM_MC_ADDR_RANGE_SIZE * (uint32) mc_number) );

// Enable error tracking
Mc->ECCS.U |= (uint16)((uint32)IFX_MC_ECCS_TRE_MSK <<
(uint32)IFX_MC_ECCS_TRE_OFF);


// Mc->RDBFL[0].U = 3; // Double bit error pattern
Mc->RDBFL[0].U = 1; // Double bit error pattern
Mc->RDBFL[1].U = 0; // Double bit error pattern
Mc->RDBFL[2].U = 0; // Double bit error pattern
Mc->RDBFL[3].U = 0; // Double bit error pattern
Mc->RDBFL[4].U = 0; // Double bit error pattern
Mc->RDBFL[5].U = 0; // Double bit error pattern
Mc->RDBFL[6].U = 0; // Double bit error pattern
Mc->RDBFL[7].U = 0; // Double bit error pattern
Mc->RDBFL[8].U = 0; // Double bit error pattern
Mc->RDBFL[9].U = 0; // Double bit error pattern
Mc->RDBFL[10].U = 0; // Double bit error pattern
Mc->RDBFL[11].U = 0; // Double bit error pattern
Mc->RDBFL[12].U = 0; // Double bit error pattern
Mc->RDBFL[13].U = 0; // Double bit error pattern
Mc->RDBFL[14].U = 0; // Double bit error pattern
Mc->RDBFL[15].U = 0; // Double bit error pattern
Mc->RDBFL[16].U = 0; // Double bit error pattern
Mc->RDBFL[17].U = 0; // Double bit error pattern

Mc->RANGE.U = (uint16)(range & ((uint16)IFX_MC_RANGE_ADDR_MSK) );

/* Configure writing of single memory address: */
Mc->CONFIG0.U = (uint16)(((uint32)SRAM_CONFIG0_NUMACCS_1 <<
(uint32)IFX_MC_CONFIG0_NUMACCS_OFF) |
((uint32)SRAM_CONFIG0_ACCSTYPE_WR <<
(uint32)IFX_MC_CONFIG0_ACCSTYPE_OFF));
Mc->CONFIG1.U = 0U;

/* Start write operation: */

Mc->MCONTROL.U = (uint16)(((uint32)IFX_MC_MCONTROL_DIR_MSK <<
(uint32)IFX_MC_MCONTROL_DIR_OFF) |
((uint32)IFX_MC_MCONTROL_START_MSK <<
(uint32)IFX_MC_MCONTROL_START_OFF)|
((uint32)MC_MCONTROL_USERED_MSK <<
(uint32)MC_MCONTROL_USERED));
Mc->MCONTROL.U = (uint16)(((uint32)IFX_MC_MCONTROL_DIR_MSK <<
(uint32)IFX_MC_MCONTROL_DIR_OFF)|
((uint32)MC_MCONTROL_USERED_MSK <<
(uint32)MC_MCONTROL_USERED));
/*wait for MBIST operation to complete*/
/*ResultLoopCount is used as count here*/
for (ResultLoopCount = 0U; ResultLoopCount < SRAM_MBIST_OPERATION_WAIT; ResultLoopCount++)
{
__asm("nop");
}
}

static void smu_init( void )
{
volatile int i;


_safety_endinit_clear(); // SMU registers are safety endinit protected
SMU_KEYS.B.CFGLCK = 0xBC; // unlock SMU configuration registers

// set LMU SRAM ECC uncorrectable errors to cause an NMI (see Table 9-19, ALM2[18]
SMU_AG2CF0.U = (1 << 18); // bit 18 of SMU Alarm configuration for alarm group 2 = 1
SMU_AG2CF1.U = (0 << 18); // bit 18 of SMU Alarm configuration for alarm group 2 = 0
SMU_AG2CF2.U = (1 << 18); // bit 18 of SMU Alarm configuration for alarm group 2 = 1

// set SRAM ECC uncorrectable errors to cause an NMI (see Table 9-21, ALM4[13]
SMU_AG4CF0.U = (1 << 13); // bit 18 of SMU Alarm configuration for alarm group 2 = 1
SMU_AG4CF1.U = (0 << 13); // bit 18 of SMU Alarm configuration for alarm group 2 = 0
SMU_AG4CF2.U = (1 << 13); // bit 18 of SMU Alarm configuration for alarm group 2 = 1
SMU_KEYS.B.CFGLCK = 0x00; // lock SMU configuration registers

_safety_endinit_set(); // end SMU configuration - safety endinit protected

_endinit_clear(); // SCU NMI trap configuration is endinit protected
SCU_TRAPDIS.B.SMUT = 0; // enable SMU NMI trap generation
_endinit_set();

// The SMU_Start command causes a transition from START to RUN
//
SMU_CMD.U = 0; // ARG=0, CMD=0: SMU_Start(0)
for( i=0; i<10000; i++ ) {} // kill some time

}
0 Likes
User22439
Level 1
Level 1
First like received Welcome!
Thank you very much for sharing the code snippet.

I had tried executing the MEM test without using the MTU and was searching for a way to disable and enable ECC functionality (similar to Flash ECC functionality ).

and also I had tried executing the Test using the MTU and found the following observation,

enabling MEMTEST affects the CPU's normal operation and the MEMSTAT (status register) doesn't give the required status. (not able to debug after enabling this bit).
Just wanted to check if the same issue was encountered before.

Also, could you please clarify my doubt, if the single memory read should also be performed before writing the error value in the RDBFL register?

Thank you.

Regards
Gokul
0 Likes
NeMa_4793301
Level 6
Level 6
10 likes received 10 solutions authored 5 solutions authored
Attempting to single-step through the MTU register manipulation is tricky business. It's possible if you can guarantee your debugger is not accessing the memory in question, but closing memory windows is not necessarily a surefire bet; sometimes the disassembly window tries to show hints by reading memory locations too.

No read is necessary before writing in the code snippet.
0 Likes
User22439
Level 1
Level 1
First like received Welcome!
oh!! What could be the alternate solution to debug and view the MEMTEST, ECCD registers?

Regards
Gokul
0 Likes
User22439
Level 1
Level 1
First like received Welcome!
Hello UC_Wrangler,

With reference to the Snippet shared for injecting the RAM ECC error via the MTU module, the RDBFL register is used for writing the Content to the memory. Could you pls clarify my below queries?

1. Single memory read is not performed instead predefined values are directly written to the CPU2 DSPR memory, then the ECC data will also be calculated and updated for the same.
Will this logic help in injecting single-bit ECC error.(Either we need to update the ECC bits or we need to disable the ECC functionality and flip a data bit and write to the memory location.)

2. How to calculate how many RDBFL registers are needed for writing a memory line for CPU DSPRs and LMU?

3. For CPU DSPR, I understand there are 16 bits data + 6 bit ECC, Does the data and ECC bits are arranged in a format in the RDBFL register? How to access the ECC bit part alone?

4. There is also RDBFL bit in the ECCS register which is used for flipping a bit. Will this help in Flipping the data and inject single-bit error in the CPU DSPRs?

Thanks in advance.

Regards
Gokul