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.

RM48L952: WarmReset not bringing device into known state.

Part Number: RM48L952
Other Parts Discussed in Thread: HALCOGEN

Hi.

I have found that on a number of occasions I have been able to get a RM48L952 device into a state where it behaves differently on a nRST signal compared to a nPOReset signal.
After a software error causing a memory abort, I can not always get back into a running state using the warm reset pin.

The nRST signal always seems to be able to get me back to the bootloader running in Flash bank0, but not to the main program running in Flash bank1, while a power on reset signal everything runs as expected.

The boot loader can still be used to reflash flash bank 1.  Clearing main RAM, { memset((void*)0x08000000, 0, 0x40000) }, does not fix this.

I have no remote control of the Power On reset signal, so if the processor gets into this state I currently have no way of bringing it back out of the state.

Can any one suggest a way to fully reset the CPU into the same state as is achieved with a PowerOnReset?

  • Hello Chris,

    It looks like the software error causes an error of ESM group 3. If you use the HALCoGen generated _c_int00(), the code will stuck at
    if ((esmREG->SR1[2]) != 0U) {
    for(;;) {
    }
    }
    when any bit in ESMSR3 register is set.

    After PORRST, all registers in ESM module will be re-initialized to the default value. All the error status registers are cleared to zero. So your code can run through the startup and jump to your application code in bank1.

    After nRST (warm reset), ESMSR1/4/7, ESMSR3 and ESMEPSR register values remains un-changed. If any bit in ESMSR3 is set, this bit won't be cleared after nRST, so the code will stuck at the for loop.

    You can clear the ESMSR3 manually and pull the nERROR pin back to high.
    1. Write 1 to the corresponding bit in ESMSR3 to clear this bit
    2. Write 0x05 to ESMEKR register to release the ESM error pin back to normal

    if #2 can not bring the nERROR back to normal, please refer to DEVICE#60 in Errata (SPNZ232B)
    1. write 0x0A to ESMEKR register
    3. Write 0x0 to ESMEKR
  • Hi QJ

    Thank you for your detailed response, and I expect that you are correct in your assessment.
    I will get a chance to test this in the second half of next week, so will be able to give better feed back then.

    Best regards,
    Chris
  • Hi again QJ.

    Thank you again for your response.

    I have reviewed the system status of my processor in it's stuck state, and it would appear that the issue is not with the EMS.
    By uploading code to run out of RAM (a function of the bootloader that I'm using) I have read the values of a number of system registers:
    ESMSR1:00000000
    ESMSR2:00000000
    ESMSR3:00000000
    ESMSR4:00000000
    ESMEPSR:00000001
    ESMSSR2:00000000
    DIEIDL:0a013005
    DIEIDH:0800f742
    SYSTASR:00000000

    You will observe from this that there are not faults apparent from the ESM status registers, so in this case the nRST/nPORRST difference in behavior cannot be explained by the ESM. Do you have any other ideas about things that I should look at or try?

    Best regards,
    Chris

    Appendix A: - Code used to read the above registers:

    #include <stdint.h>
    /*-- Some registers. */
    #define ESMSR1 (*(volatile uint32_t *)0xfffff518)
    #define ESMSR2 (*(volatile uint32_t *)0xfffff51c)
    #define ESMSR3 (*(volatile uint32_t *)0xfffff520)
    #define ESMSR4 (*(volatile uint32_t *)0xfffff558)

    #define ESMEPSR (*(volatile uint32_t *)0xfffff524)
    #define ESMSSR2 (*(volatile uint32_t *)0xfffff53c)

    #define DIEIDL (*(volatile uint32_t *)(0xffffff00 + 0x7c))
    #define DIEIDH (*(volatile uint32_t *)(0xffffff00 + 0x80))
    #define SYSTASR (*(volatile uint32_t *)(0xffffff00 + 0xe8))

    static char rsp_buf[3000] = {};
    static inline void hx_uint4(char **d, uint8_t nib){
    nib &= 0xf;
    *(*d)++ = nib < 10 ? nib + '0' : nib - 10 + 'a';
    }

    static inline void hx_uint8(char **d, uint8_t b){
    hx_uint4(d, b>>4);
    hx_uint4(d, b);
    }

    static inline void hx_uint16(char **d, uint16_t v){
    hx_uint8(d, v >> 8);
    hx_uint8(d, v);
    }

    static inline void hx_uint32(char **d, uint32_t v){
    hx_uint16(d, v >> 16);
    hx_uint16(d, v);
    }

    static inline void st(char **d, const char *str){
    while(*str) *(*d)++ = *str++;
    }

    const char *blexe(void){
    char *d = rsp_buf;

    #define X(y) do{\
    st(&d, #y ":"); \
    hx_uint32(&d, y); \
    *d++ = '\n'; \
    }while(0)

    X(ESMSR1);
    X(ESMSR2);
    X(ESMSR3);
    X(ESMSR4);

    X(ESMEPSR);
    X(ESMSSR2);

    X(DIEIDL);
    X(DIEIDH);
    X(SYSTASR);

    return rsp_buf;
    }
  • Hello Chris,

    I understand that the problem is not caused by the ESM error.

    The startup code ("memoryInit(0x1)") generated through HalCoGen clears the whole memory to 0x00, so I think there is no chance to implement uninitialized variables which might affect the code execution after warm reset.

    Can you post your startup code and how the code jump to application image?

    In bootloader example code, I use this way:
    ((void (*)(void))g_ulTransferAddress)();
  • Hi QJ

    The initial startup code is standard HalCoGen code as generated with HalCoGen version 03.05.02  it predated the GCC code generation option, so uses a modified version of the TI compiler output.

    I've attached the normal flow for startup (bootloader) code below, with the parts that are likely to be of importance.  Please let me know if there is any function you wish to have a closer look at, that has not been listed here.  You will note that three variables have been copied into registers before the Memory Init call, then copied back, in order to preserve them across the memory clear.

    In brief:

    • Jump to code in flash2 if flagged in bootloader scratch area.
    • Do nomral start up in boot loader.
    • Perform CRC check on program in flash2.
    • If CRC OK
      • then set flag in bootloader scratch that on reset flash2 code should be called, then reset.
      • else Stay in bootloader

    The flash 2 has a set of exception vectors.  Boot loader code references these directly in all cases except for the reset vector where the above pseudo code is executed.

    The flash2 code then repeats much of the initialization code.

    Can you think of a situation where the CRC would fail for flash2 under a warm or software reset, but pass with a power on reset?

    Thank yo for all you help so far.  I hope the code provided below is the sort of detail you were looking for.

    Best regards,:
        Chris

    Notable program flow is:

    Boot loader:

    Reset IntVector  : ldr  pc,=_c_int00

    // sys_intvecs.S
            .extern _c_int00

    //------------------------------------------------------------------------------
    // exception vectors
            .arm
            .sect ".exceptionvector"
            .global exceptionvectors
            .type exceptionvectors, %function
            .func
    exceptionvectors:
            ldr pc,=_c_int00
            ldr pc,=fb2_exceptionvectors + 4        /* undefined instruction */
            ldr pc,=fb2_exceptionvectors + 8        /* supervisor call      */
            ldr pc,=fb2_exceptionvectors + 12       /* prefetch abort       */
            ldr pc,=fb2_exceptionvectors + 16       /* data abort           */
            ldr pc,=fb2_exceptionvectors + 20       /* not used             */
            ldr pc,[pc,#-0x1b0]     // IRQ - Jump to addr provided by VIM.
            ldr pc,[pc,#-0x1b0]     // FIQ - Jump to addr provided by VIM.
            .endfunc

    /*--- These are filled in by the FB2 application (not the bootloader) and are placed
     *    at 0x180000 by both bootloader linker and flash bank 2 app linker
     */
            .arm
            .sect ".fb2_exceptionvector"
            .global fb2_exceptionvectors, __rom_bank1_end__, ccp_c_int00
            .type fb2_c_int00, %function
            .func
    fb2_exceptionvectors:
    fb2_c_int00:
            ldr pc,=_c_int00
    fb2_expt_undefined_instruction:
            ldr pc,=0xffffffff      /* undefined instruction */
    fb2_expt_svc:
            ldr pc,=0xffffffff      /* supervisor call      */
    fb2_expt_pabort:
            ldr pc,=0xffffffff      /* prefetch abort       */
    fb2_expt_dabort:
            ldr pc,=0xffffffff      /* data abort           */
            ldr pc,=0xffffffff      /* not used             */
            ldr pc,[pc,#-0x1b0]     // IRQ - Jump to addr provided by VIM.
            ldr pc,[pc,#-0x1b0]     // FIQ - Jump to addr provided by VIM.
    __rom_bank1_end__: .word 0xffffffff // Again filled in by FB2 app. linker
            .endfunc

    ----

    extern void __attribute__((noreturn)) fb2_c_int00();

    __attribute__((naked)) void _c_int00(void)
    {
        _coreInitRegisters_();
        _coreInitStackPointer_();
        bootloader_scratch.reset_count++;
        if(bootloader_scratch.boot_state==0x5011dfad){
            fb2_c_int00();
        }
        if (DEVICE_ID_REV == 0x802AAD05U)
        {
            _esmCcmErrorsClear_();
        }
        _coreEnableEventBusExport_();
        if(bootloader_scratch.reset_reason == 0){
            bootloader_scratch.reset_reason = SYS_EXCEPTION;
        }
        if ((SYS_EXCEPTION & POWERON_RESET) != 0U)
        {
            bootloader_scratch.reset_reason = SYS_EXCEPTION;
            bootloader_scratch.reset_count = 0;
            SYS_EXCEPTION = 0xFFFFU;
            _errata_CORTEXR4_66_();
            _errata_CORTEXR4_57_();
            bootloader_scratch.boot_state = 0xBadFace;
        }
        else if ....
        else if ((SYS_EXCEPTION & CPU_RESET) !=0U)
        {
          if ((stcREG->STCSCSCR & 0xFU) == 0xAU)            
            {
                if ((stcREG->STCGSTAT & 0x3U) != 0x3U)
                {
                    stcSelfCheckFail();                        
                }
                /* STC self-check has passed */
                else                                        
                {
                    /* clear self-check mode */
                    stcREG->STCSCSCR = 0x05U;                
                    
                    /* clear STC global status flags */
                    stcREG->STCGSTAT = 0x3U;                
                    
                    /* clear ESM group1 channel 27 status flag */
                    esmREG->ESTATUS1[0U] = 0x08000000U;        
                    
                    /* Start CPU Self-Test */
                    cpuSelfTest(STC_INTERVAL, STC_MAX_TIMEOUT, TRUE);                            
                }
            }
            /* CPU reset caused by CPU self-test completion */
            else if ((stcREG->STCGSTAT & 0x1U) == 0x1U)        
            {
                /* Self-Test Fail flag is set */
                if ((stcREG->STCGSTAT & 0x2U) == 0x2U)        
                {
                    /* Call CPU self-test failure handler */
                    cpuSelfTestFail();                    
                }
                /* CPU self-test completed successfully */
                else                                        
                {
                    /* Continue start-up sequence after CPU STC completed */
                    afterSTC();                                
                }
            }
            /* CPU reset caused by software writing to CPU RESET bit */
            else                                            
            {
                /* Add custom routine here to handle the case where software causes CPU reset */
            }
        }
        else if ((SYS_EXCEPTION & SW_RESET) != 0U)
        {
            //bootloader_scratch.boot_state = 0x15adFace;
            SYS_EXCEPTION = SW_RESET;
        }
        else
        {
            /* Reset caused by nRST being driven low externally.
            Add user code to handle external reset. */
            bootloader_scratch.boot_state = 0x5adFace;
        }

    -------

    void afterSTC(void)
    {
        {
            register uint32_t t1 = bootloader_scratch.boot_state;
            register uint32_t t2 = bootloader_scratch.reset_count;
            register uint32_t t3 = bootloader_scratch.reset_reason;
            memoryInit(0x1U);
            bootloader_scratch.boot_state  = t1;
            bootloader_scratch.reset_count = t2;
            bootloader_scratch.reset_reason = t3;
        }
        _coreEnableRamEcc_();
        _coreEnableIrqVicOffset_();
        esmInit();
        _start();
        main();
        while(1);   /* If we get here there is a problem. */
    }

    ------

    void _start(void){
        extern uint8_t __bss_start__, __bss_end__;
        extern uint8_t __cinit_start__, __cinit_end__, __cinit_src__;
        memset(&__bss_start__, 0, &__bss_end__ - &__bss_start__);
        memcpy(&__cinit_start__, &__cinit_src__, &__cinit_end__ - &__cinit_start__);
    }

    ----

    int main(void){
    /* ---->8----
        ...
    ----8<------*/
       void run_fb2_app();
       while(1){
           do_bootloader_stuff();
       }
    }

    ----

    void run_fb2_app(void){
        extern const uint32_t fb2_exceptionvectors;
        uint32_t crc;
        uint32_t len;
        if(fb2_exceptionvectors == 0xffffffff) return; /* Flash blank. */
        if(__rom_bank1_end__ <  0x180000) return;      /* Silly end address? */
        if(__rom_bank1_end__ >= 0x300000) return;      /* Silly end address? */
        len = __rom_bank1_end__ - (uint32_t)fb2_c_int00;
        crc = crc32b4irEDB88320(CRC_SEED, fb2_c_int00, len);

        if(*(uint32_t *)__rom_bank1_end__ != crc) return; /* CRC missmatch. */

        /*-- Tell startup code not to come back here. */
        bootloader_scratch.boot_state = 0x5011dfad;

        /*-- Do a system reset, and rely on the different exec path in
         *   the boot up code.
         */
        systemREG1->SYSECR = 1<<15;
    }

  • Hello Chris,

    The CRC value calculated through CRC HW should be same after nPORRST and nRST. Where is the pre-determined CRC value stored? Might this value be affected by the reset?

    Can you get the calculated CRC value and pre-determined CRC value to check if they are match or mismatch?
  • Hi.
    I have verified that the CRC match. Thanks for the suggestion, but it would seem that this lead was a red herring, the CRC is correct, and the code in the second bank of flash is being executed, it just stops before I can get much debug information out of it, and my attempts to debug the problem as yet have not helped me identify where the code is stopping, or triggering another reset.
    In my case I have rediscovered that I do have a way of cycling the power to the RM48l952, so I can always remotely perform a power on reset, so I have a work around to my problem. This though does not answer my original question.
    For the sake of this thread I wondered if there is any code examples or suggestions of a way to bring the RM48l952 to a known state using a software / warm reset.
  • I am sorry for late reponse. Have you solved the problem?
  • Hi QJ.

    Thank you for following up.  I did mean to send through something to follow up on the state of this.

    I found a work around in my case, so have not actually got to the bottom of the problem.  I have not verified but it is likely that my problem was to do with the state variables that I was copying across the memory clear, triggering a different execution path in the code on the second flash.  I have re-discovered that while I have no remote control of the power on reset remotely signal, I have got remote control of the power to the RM48l952, so I can effect a power on reset using that.  I have also had some luck bringing the RM48l952 to a running state when jammed by clearing the persistent variables, then signalling a warm reset, but there were also cases where this did not appear to work.

    In short I cant say if the original problem is solved, but I can say that I require no further assistance for my case.

    To try and sum things up for anyone following this thread in the future I would pose the question "would the memory check call, followed by the memory check clearing that you first mentioned always be expected to bring the processor back to the same state?"  If not is there a complete  list of things needed to do recreate the same behaviour as a power on reset?

    Best regards,
        Chris

  • I'm still finding situations where I see different reset behavour on warm reset, software reset and power on reset.
    I no longer need this for my own use, but am still interested to know in if there is a software path to always bring a unit to a known state.
  • Thanks Chris, and glad to know you have workaround