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.

Hercules RM57 Initialization Code

Other Parts Discussed in Thread: HALCOGEN

I am running into an issue with by Initialization code and hope that you could assist.
When first bringing up the board it seems that If I do not immediately set up the SPregister with the stack location, run _memInit_ and _coreInitRegisters_ (with out cpu mode instructions) that my board will detect esmREG->SR1[2] making the board unusable. There seems to be a race with in the chip here, if I have a delay or any other instructions before this code (such as the power on / reset switch) it will detect errors and the chip will not be brought up correctly.
I have seen this problem with the GNU tool chain provided by TI but not by the TI compiler. The assembly between the two compilers is exactly the same yet one will detect esmREG->SR1[2] and the other will not. 
The error detected is real and effects code running on the processor later on if I ignore it. It is cleared if I keep the board powered and do a PORRST reset. We did not previously notice the severity of the issue because the USB Jtag connector keeps memory powered even when power is pulled and the error does not present it self.
It only appears when the board is fully powered off then powered on. Any insight on the issue would be appreciated. We have code to seemingly eliminate the issue but do not feel comfortable until we can explain why it is no longer detecting esmREG->SR1[2].
There also seems to be an issue setting the __vectors table in the first 0x20 bytes. When using LDR commands instead of branches, the esm detects errors. 
Thanks!
Dmitri 
  • Dmitri,
    I think I can help.
    On startup, the stackpointer is not initialized. If you start saving data onto the stack (i.e. RAM) but the stack pointer is not initialized, you will be writing to incorrect addresses. Similarly, with the dual CPU topology, the registers need to be initialized so that the CPUs start from a known identical condition.

    #pragma INTERRUPT(_c_int00, RESET)
    This pragma makes the function calls within _c_int00 feasible.

    The GCC interrupt attribute syntax, which has the same effects as the INTERRUPT pragma, is as follows. Note that the interrupt attribute can precede either the function's definition or its declaration.
    __attribute__((interrupt[( "interrupt_type" )] )) void func( void )

    Best Regards,
    Kevin Lavery
  • Kevin,

    I think we determined before that the gcc 'naked' attribute is the right one.

    EDIT:  this should be handled by HalCoGen if GCC is the selected toolchain.
    See the template file: <HalCoGen_InstallDir>\v04.05.01\drivers\TMS570LC4357ZWT\SYSTEM570v000\sys_startup.c

    The options for the supported toolchains are all there:

    /* Startup Routine */
    #if %%TOOLS:GCC%%
    void %%CORE_HANDLER_TABLE_RESET_ENTRY%%(void) __attribute__((noreturn));
    #else
    void %%CORE_HANDLER_TABLE_RESET_ENTRY%%(void);
    #endif
    @@USERCODE

    #if %%TOOLS:TI%%
    #pragma CODE_STATE(%%CORE_HANDLER_TABLE_RESET_ENTRY%%, 32)
    #pragma INTERRUPT(%%CORE_HANDLER_TABLE_RESET_ENTRY%%, RESET)
    #pragma WEAK(%%CORE_HANDLER_TABLE_RESET_ENTRY%%)
    #endif
    #if %%TOOLS:ARM%%
    __declspec(noreturn)
    __attribute__ ((section ("reset")))
    #endif
    #if %%TOOLS:GHS%%
    __attribute__((noreturn))
    #endif
    #if %%TOOLS:IAR%%
    /* Note: stackless keyword is supported since compiler version 6.20.1 */
    __stackless
    __arm
    #endif
    #if %%TOOLS:GCC%%
    __attribute__ ((naked))
    #endif

    void %%CORE_HANDLER_TABLE_RESET_ENTRY%%(void)
    {

  • I do not believe this to be the case.
    It may be helpful for me to paste the code, please take a look below.

    That is the only code that I have been able to have properly (no esm errors on FRESH power on) initialize the CPU.

    If I introduce delays in my _start, the ESM errors present them selves and the longer the delay the higher the probability of them happening.

    I am initializing the Stack pointer in my _memInit_ method by running the following:

    _memInit_:
    ldr sp,STACK # Setup stack pointer

    ldr r12, MINITGCR @Load MINITGCR register address
    mov r4, #0xA
    str r4, [r12] @Enable global memory hardware initialization

    ldr r11, MSIENA @Load MSIENA register address
    mov r4, #0x1 @Bit position 0 of MSIENA corresponds to SRAM
    str r4, [r11] @Enable auto hardware initalisation for SRAM
    mloop: @Loop till memory hardware initialization comletes
    ldr r5, MSTCGSTAT
    ldr r4, [r5]
    tst r4, #0x100
    beq mloop

    mov r4, #5
    str r4, [r12] @Disable global memory hardware initialization
    bx lr

    STACK is defined in my Linker to point to stack.

    _coreInitRegisters_:

    @ After reset, the CPU is in the Supervisor mode (M = 10011)
    mov r0, lr
    mov r1, #0x0000
    mov r2, #0x0000
    mov r3, #0x0000
    mov r4, #0x0000
    mov r5, #0x0000
    mov r6, #0x0000
    mov r7, #0x0000
    mov r8, #0x0000
    mov r9, #0x0000
    mov r10, #0x0000
    mov r11, #0x0000
    mov r12, #0x0000

    ; Enter Privileged + User mode
    mrc p15, 0, r2, c1, c0, 2
    orr r2, r2, 0x00F00000
    mcr p15, 0, r2, c1, c0, 2

    ; Enable VFP coprocessor
    fmrx r2, fpexc
    orr r2, r2, 0x40000000
    fmxr fpexc, r2

    mov fp, 0

    fmdrr d0, r1, r1
    fmdrr d1, r1, r1
    fmdrr d2, r1, r1
    fmdrr d3, r1, r1
    fmdrr d4, r1, r1
    fmdrr d5, r1, r1
    fmdrr d6, r1, r1
    fmdrr d7, r1, r1
    fmdrr d8, r1, r1
    fmdrr d9, r1, r1
    fmdrr d10, r1, r1
    fmdrr d11, r1, r1
    fmdrr d12, r1, r1
    fmdrr d13, r1, r1
    fmdrr d14, r1, r1
    fmdrr d15, r1, r1
    bl next1
    next1:
    bl next2
    next2:
    bl next3
    next3:
    bl next4
    next4:
    bx r0
    My reset looks like:
    __vectors:
    B _start
    B _undefined
    B _interrupt
    B _prefetch_handler
    B _abort_handler
    B _reserved_handler
    ldr pc,[pc,#-0x1b0]
    ldr pc,[pc,#-0x1b0]

    and _start looks like:

    void _start(void) __attribute__((noreturn));


     __attribute__ ((naked))


    void _start(void)
    {

    /* Initialize L2RAM to avoid ECC errors right after power on */
    _memInit_();


    /* Initialize Core Registers to avoid CCM Error */
    _coreInitRegisters_();

    // MORE code here omitted!
    }


    The other issue I spoke of is changing the __vectors table to look like:

    __vectors:
    B __entry # Reset goes to the entry function
    LDR pc,UNDEFINED # Undefined handler
    LDR pc,SWI # Software interrupt handler
    LDR pc,PREFETCH # Prefetch exception handler
    LDR pc,ABORT # Abort exception handler
    LDR pc,RESERVED # Reserved exception handler
    LDR pc,[pc,#-0x1b0] # IRQ interrupt handler
    LDR pc,[pc,#-0x1b0] # FIQ interrupt handler
    #
    #
    __entry:
    LDR sp,STACK # Setup stack pointer
    LDR pc,START # Jump to startup
    #
    #
    START:
    .data.w _start # Reset goes to startup function
    UNDEFINED:
    .data.w _undefined # Undefined handler
    SWI:
    .data.w _swi_interrupt # Software interrupt handler
    PREFETCH:
    .data.w _prefetch_handler # Prefetch exception handler
    ABORT:
    .data.w _abort_handler # Abort exception handler
    RESERVED:
    .data.w _reserved_handler # Reserved exception handler


    Never seems to get rid of the ESM light. It looks like it HAS to be branches which I believe put the VIM in hardware mode.

  • Dmitri,

    You should not add any code before the CPU's executed the _coreInitRegisters_, or else you will get a core compare error.
    That's just the way the part works -- the registers inside the CPU including some hidden ones are not initialized by the reset signal
    and require this careful sequence to get the registers of the two CPUs in sync.. before anything that would 'show' the difference in state propagates to the core compare.

    I think you should be able to use the HalCoGen code as-is for startup.. And generate it for the compiler that you are using.

    If this isn't working we should discuss more.

    Which bit in the ESMSR2 register is being set? I assume this is bit 2 for the CCM but I don't think we established this.
  • I am able to reproduce the issue with the TI toolchain by introducing a delay before calling mem and register init.

    void _c_int00(void)
    {

    /* USER CODE BEGIN (5) */
    /*if( 0x12345678 == myFaultInjected )
    {
    //_CoreRegisterSetRestore_(&myCoreRegisterSet[0]);
    }*/

    int i = 0;
    for (i = 0; i < 100000; i++){}
    /* USER CODE END */

    /* Reset handler: the following instructions read from the system exception status register
    * to identify the cause of the CPU reset.
    */
    switch(getResetSource())
    {

    // rest of the code
    }

    It seems like the difference between GNU and TI compilers are execution speed of the init code?

    Seeing this makes me thing that even in the TI compiler generated code the me and register init should happen as fast as possible. It also worries me that this code could fail the apparent race in rare cases (like the CPU being too hot?)
  • I am using Halcogen code. In the Halcogen code the first executed instructions are determining your reset source. With the TI toolchain, this seems to be fine as it will execute fast enough but with GNU it seems that it takes too long and the Error bit is set. I have tried having the initialize registers function set the stack pointer and have it execute before _memInit_ but that does not seem to do the trick.

    Value of esmREG-> SR1:

    ESMSR1 [0] 0x80000000

    ESMSR2 [1] 0x0

    ESMSR3 [2] 0x8

  • Hi Dmitri,

         The delay you added uses the uninitialized registers. Look at the assembly instructions to see what registers are modified. The assembly will tell the story.  (I do not believe that delay is the issue.)

          If you want to prove that the initialization is the problem, manually initialize the used registers (either in code or in the debugger). I'd want to pay special attention to the stack pointer...

         If you want to attach the .out file, I'll look at this...

    Best Regards,

    Kevin Lavery

  • 2541.BenchmarkBasic.zip

    I have attached the GNU .out file with no modifications to the Halogen HAL code to demonstrate the issue.

    To recreate the failure power down the board completely, with the USB debugger detached as it keeps memory powered, and power on the board. It has a failure rate of about 90% but if you repeat power on / power off eventually it will pass initialization and run the LED demo main.

    As mentioned before, initializing registers before the memory init does not work for me. Only the sequence I mentioned has worked for me with GNU tools to properly initialize the processor. (_vector, _memInit_, modified _registerInit_).

  • Dmitri,
    As I understand your code (I've parsed three lines so its not a lot):
    At address 0x00 you branch to 0x1BAE0
    At address 0x1BAE0 you branch and link to 0x1CE14
    At address 0x1CE14, the instruction is a push of R4 and R11.
    Is this correct when you step through it?

    If I've got the flow right, the question to ask is WHERE does the push go since the stack pointer is not setup?
    The issue here is that the function assumes it can save values. It cannot until the stack pointer points to RAM.

    I've made some inferences about the code, so if this does not follow your understanding, please respond saying so. I'm sorry in advance if I got the code wrong.

    Best Regards,
    Kevin Lavery
  • Hi Kevin,

    That is what I am seeing when I step through it.

    This is Halcogen generated code unmodified that I have submitted and should simple to reproduce on your end if you generate a GNU HAL for more in depth analysis with symbols.

    I can set up the stack pointer in the .out, but I wanted to submit what Halcogen generates as correct Initialization code with out modification.

    I have working initialization code written as I said, but I would like to clarify why my code is properly working and that it is doing what TI intended as it deviates from what Halcogen Generates for GNU tools. It also concerns me that the TI compiler Halcogen code looks almost identical to the GNU TI compiler generated code yet the two produce different initialization behaviours.

  • Dmitri,
    OK. I think you are doing two things --
    1.) submitting a bug regarding GNU generated initialization code. (I will get this to the right people.)
    2.) questioning the small differences between the GNU generated code and the TI tool-generated code. What you should see as the difference in the TI tools is that the push to the stack is not present. The reason that the push is missing is due to the pragma.

    Best regards,
    Kevin Lavery
  • Hi Kevin,

    Thanks for the the reply.

    Here is a list of what I am trying to find out.

    1.) Yes, there seems to be a bug in GNU code generation.

    2.) Setting the stack pointer with the GNU tool-chain does fix the issue of the ESMSR3 error preventing boot, but the behavior of the init code still seems to differ from the TI compiler. The ESM light will flash briefly between _memInit_ and _coreInitRegisters_ in the GNU code, but not on the TI compiler. 

    Is there any documentation around the timing of bring up? More specifically how quickly the registers must be initialized on boot as you mentioned?

    The other question I had was regarding LDR instructions instead of branches in the reset vector. I believe branches set the VIM into hardware mode and LDR sets the vim into Software mode?

  • Dmitri,
    To re-iterate, the issue you are seeing is almost certainly related to the code, not the timing. The calling function is responsible for saving some register values prior to entering the function, and the called function is responsible for saving other registers. Here, you have the case that neither calling or called functions is allowed to save register values onto the stack (because the stack and registers are not initialized).

    As an example, consider the function call that we have discussed. It includes a push of R4 and R11 onto the stack. There are two ways in which this instruction can go bad --
    -1- the stack pointer is not initialized and points somewhere other than RAM. (This case, I think, we have agreed is a problem and can be mitigated by initializing the stack pointer.)
    -2- the register values (SP, R4, R11) differ between CPU1 and CPU2 on power-up. Now, the write of R4 and R11 (assume you initialized SP to RAM ) can still cause a problem. This write causes a problem because the output of the CPUs is compared. If R4 and R11 are not the same, the write will not compare identical. You would expect this action to generate an ESM error.

    Again, the key idea is how to tell the GNU compiler that these initialization functions do not need a register context save (either from the calling or the called functions). Timing is a less likely reason for the behavior you describe.

    Best Regards,
    Kevin Lavery
  • Thanks Kevin,


    Initializing the stack pointer in GNU seems to fix the ESMSR[2] issues.