Other Parts Discussed in Thread: HALCOGEN
I am trying to execute the CPU LBIST of a TI Hercules RM57L843 (integrated into the RM57L HDK Development Board). I am following the directions in SPNU562 (the RM57 Family Users Guide) 10.9.1 to set up the STC1 registers and put the CPU into idle mode with asm("WFI"). However, I am noticing that execution blows right past the asm("WFI") and gets stuck in an infinite loop that I implemented to catch this very possibility. The self-test does not execute and the CPU does not reset.
Symptoms are very similar to these two unresolved threads.
Here is the code I am using to execute the self-test. As I said, it is very similar to the algorithm in SPNU 10.9.1; however, when that didn't work I also added some undocumented tricks from TI's HALCOGEN generated self-test file {{HL_sys_selftest.c}}. That did not help. I present my code below for your perusal.
void cpuSelfTest()
{
// This code implements the steps from spnu462 10.9.1
// Block here to avoid boot loop!
volatile int i = 0;
while(i == 0);
// Step 1:
//
// Set the STC clock rate.
//
// "The maximum clock rate for the self-test is 110MHz" (spnu215a 5.5.5.2)
// STC1 is always driven by GCLK (spnu562 10.8.12)
// GCLK is configured to use PLL1. (BSP_CORE @r97029 HL_system.c : 282)
// Assuming PLL1 is 300 MHz, then /3 will yield 100 MHz.
// To divide by 3, use a STCCLKDIV of 2. (spnu562 10.8.12)
uint32 temp = stcREG1->STCCLKDIV;
temp &= ~((0x7 << 24) | (0x7 << 16)); // Clear [26:24] and [18:16]
temp |= ((0x2 << 24) | (0x02 << 16)); // STCCLKDIV[26:24] = STCCLK[18:16] = 0x02
stcREG1->STCCLKDIV = temp;
// Step 2:
//
// Clear the CPU RST status bit in the System Exception Status Register.
//
// Writing 1 to SYSESR[5] clears the bit. (spnu562 2.5.1.46)
systemREG1->SYSESR = (1 << 5); // Write 1 to SYSESR[5].
// Step 3:
//
// Choose the STC test interval count. Larger intervals have greater test
// coverage (and take longer to run). (spnu562 10.1.2)
// The largest interval supported on STC1 Segment 0 is 125, and yields
// 92.17% coverage. (spnu562 10.5)
//
temp = stcREG1->STCGCR0;
temp &= ~(0xFFFF << 16); // Clear [31:16]
temp |= (125U << 16); // STCGCR0[31:16] = 125
// TODO also setting RS_CNT to 1 to "Restart STC run from interval 0".
// Shouldn't make a difference because STCCICR is already 0 on boot.
temp |= 0x1;
stcREG1->STCGCR0 = temp;
// Step 4:
//
// Set the self-test timeout, measured in terms of VBUS clock cycles.
// (spnu562 10.8.3)
stcREG1->STCTPR = 0xFFFFFFFF;
// TODO HL_sys_selftest.c puts a "wait for 16 VBUS clock cycles" here. Why?
asm("NOP"); // 50 NOPs.
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
// Step 5:
//
// Choose which core to test (STCGCR1[11:8]).
// Other than 0x5 or 0xa == "Both cores in parallel". (spnu562 10.8.2)
// TODO this register may ignore writes: test its value via reading it back
//
// AND:
// Step 6:
//
// Enable self-test (STCGCR1[3:0]). (spnu562 10.8.2)
// 0xA = "Self-test run enabled"
// This does not kick off the self-test (yet!).
stcREG1->STCGCR1 = 0xA;
// Step 7:
//
// Context save - 10.4.2
// TODO
// Step 8:
//
// Kick off the LBIST CPU self-test by putting the CPU into idle mode.
// Does not return - instead resets the CPU.
// Make sure the memory writes actually posted. TODO might not be
// necessary.
asm("DSB");
while(true)
{
asm("WFI");
// TODO _gotoCPUIdle_ in HL_core_sys.asm puts 4 NOPs here.
// WHY???
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
}
// That while(true) better not return. :-)
while(1);
}
Please note:
- I am running this function immediately after setting up the C++ runtime and initializing my oscillators, PLL, flash, and so on via HL_system.c systemInit() version 4.04.00.
- You will notice the infinite while(1) loops in my code. I added those to prevent the dreaded STC boot loop problem. When execution gets stuck on those lines, I enter a debugger and manually advance past the loop.
So here are my questions:
- Do you see any problems with my code that would prevent the LBIST from running?
- Can you present some "known good" code for executing the LBIST on the RM57?
- Why is the algorithm used by HL_sys_selftest.c different from the algorithm recommended in the chip's Family User's Guide, and which should I use?
- Why does HALCOGEN "wait for 16 VBUS Clock Cycles" between programming most STC1 registers and writing STCGCR1 to enable the self-test?
- Why does HALCOGEN put NOPs after the WFI? I could not find any reason for this in the ARM Architecture Reference Manual.
- Do I have to put the WFI in a loop? (HALCoGen doesn't, but certain threads recommend that I should...)
I have got to say that all of this conflicting and sketchy information about the RM57L's safety features is not making me confident that it's the right processor for my application...






