Using non initialised RAM to communicate with a boot loader

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Using non initialised RAM to communicate with a boot loader

1,820 Views
Gra67
Contributor III

Hi

I’m trying to set a specific address in RAM to a value so on a reset the boot loader can read it and action on it. The RAM is configured to not initialise.

I've simplified the test so that it doesn't involve the boot loader and checks itself. My app sets the address to a value, resets and when it re-starts it simply prints out that value before it is set again.

Unfortunately the value is not as expected. Oddly if I step through the code and monitor the variable and RAM it works.

I'm using Embedded Artist's iMX RT1062 OEM board with NXP's MCUXpresso IDE and SDK.

I've added the variable to OC RAM using Properties C/C++ Build - MCU settings:

Screenshot 2021-04-27 080409.jpg

I also did this, but not sure it is required:

Screenshot 2021-04-27 080644.jpg

Variable declared as:

__NOINIT(RAM4) volatile unsigned long mailBox;        // note must be global!

 

It's as if it has been cached and not properly written to the RAM. I've tried adding delays using lots of "__NOP();"

 

Has anyone seen this before?

Many thanks

Labels (1)
0 Kudos
8 Replies

1,774 Views
crist_xu
NXP Employee
NXP Employee

I think that the value does not write back from DCache to ram before re-reset, so maybe you can clean the DCache before you re-reset the system. Or just place the SCB_CleanDCache() before you exit the code. Or you can try to place the value in a non-cache area, such as DTCM

0 Kudos

1,756 Views
Gra67
Contributor III

Thanks for that suggestion, it helped!

I added SCB_CleanDCache() and it now consistently works if I repeatedly run it using MCUXpresso's Debug.

However, it doesn't work if I reset using the watchdog, which is the only way I can reset it in the field as I cannot get software resets to work.

I am restricted where I place this in RAM due to the bootloader I am using.

I'm wondering if it's the way I am resetting it now? Maybe a software reset would do it if I could get it working?

0 Kudos

1,736 Views
mjbcswitzerland
Specialist V

Hi Graeme

The uTasker loader ignores mailbox messages after a watchdog reset since such a reset is considered to be an error and so mailbox values could be corrupted.

// Only the bare-minimum loader calls this function to check the reset cause and maintain reset counters
//
static void fnSaveResetCause(void)
{
    if ((SRC_SRSR & SRC_SRSR_IPP_RESET_B_M7) != 0) {                     // power on reset
        *BOOT_RESET_COUNTER = 0;                                         // delete persistent memory
        *BOOT_WDOG_COUNTER = 0;
        *SECRET_KEY_0 = 0;                                               // delete trace of secret key (the key is written to persistant memory once when set so that the application can monitor it just once for test or tracking purposes)
        *SECRET_KEY_1 = 0;
        *SECRET_KEY_2 = 0;
        *SECRET_KEY_3 = 0;
        *BOOT_MAIL_BOX = DO_FULL_RESET;                                  // initiate full boot cycle
#if defined ERR050538                                                    // {1}
        _CONFIG_PERIPHERAL(GPIO_AD_B0_07, JTAG_TCK, PORT_PS_UP_ENABLE);  // enable pull-up on JTAG_TCK/SWD_CLK to avoid potential boot failure (this is retained across warm resets)
#endif
    }
    else {                                                               // not power on reset
#if defined iMX_RT105X || defined iMX_RT106X
        if ((SRC_SRSR & (SRC_SRSR_LOCKUP_SYSRESETREQ_M7 | SRC_SRSR_WDOG3_RST_B_M7 | SRC_SRSR_WDOG_RST_B_M7)) == SRC_SRSR_LOCKUP_SYSRESETREQ_M7) // commanded reset (which retains the boot mailbox content)
#else
        if ((SRC_SRSR & (SRC_SRSR_JTAG_SW_RST_M7 | SRC_SRSR_WDOG3_RST_B_M7 | SRC_SRSR_WDOG_RST_B_M7)) == SRC_SRSR_JTAG_SW_RST_M7) // commanded reset (which retains the boot mailbox content)
#endif
        {
            if ((*BOOT_MAIL_BOX & RESET_NO_COUNT_FLAG) != 0) {           // commanded reset that should not be counted, nor should the last reset cause be updated
                *BOOT_MAIL_BOX = (*BOOT_MAIL_BOX & ~RESET_NO_COUNT_FLAG);// remove the no count flag
                WRITE_ONE_TO_CLEAR(SRC_SRSR, (SRC_SRSR_IPP_RESET_B_M7 | SRC_SRSR_LOCKUP_SYSRESETREQ_M7 | SRC_SRSR_CSU_RESET_B_M7 | SRC_SRSR_IPP_USER_RESET_B_M7 | SRC_SRSR_WDOG_RST_B_M7 | SRC_SRSR_JTAG_RST_B_M7
                    | SRC_SRSR_JTAG_SW_RST_M7 | SRC_SRSR_WDOG3_RST_B_M7 | SRC_SRSR_TEMPSENSE_RST_B_M7)); // clear reset cause flags
                return;                                                  // return in order to avoid saving reset cause and incrementing reset counters
            }
            else {
                *BOOT_RESET_COUNTER = (*BOOT_RESET_COUNTER + 1);         // count the number of other resets
            }
        }
        else {                                                           // not a commanded reset
            if ((SRC_SRSR & (SRC_SRSR_WDOG3_RST_B_M7 | SRC_SRSR_WDOG_RST_B_M7)) != 0) { // watchdog reset detected
                unsigned short usWatchdogCount = *BOOT_WDOG_COUNTER;     // original watchdog reset count
                ++usWatchdogCount;                                       // count the number of watchdog resets
                if ((usWatchdogCount % 16) == 0) {                       // every 16th watchdog reset
                    *BOOT_MAIL_BOX = RESET_TO_FALLBACK_LOADER;           // offer the fall-back loader so that potentially bad code can be updated
                }
                else {
                    *BOOT_MAIL_BOX = DO_FULL_RESET;                      // initiate full boot cycle on watchdog reset
                }
                *BOOT_WDOG_COUNTER = usWatchdogCount;                    // save the incremented watchdog reset counter
            }
            else {
                *BOOT_RESET_COUNTER = (*BOOT_RESET_COUNTER + 1);         // count the number of other resets
                *BOOT_MAIL_BOX = DO_FULL_RESET;                          // initiate full boot cycle on non-commanded resets
            }
        }
    }
    *BOOT_RESET_CAUSE = (unsigned short)SRC_SRSR;                        // save the reset cause
    WRITE_ONE_TO_CLEAR(SRC_SRSR, (SRC_SRSR_IPP_RESET_B_M7 | SRC_SRSR_LOCKUP_SYSRESETREQ_M7 | SRC_SRSR_CSU_RESET_B_M7 | SRC_SRSR_IPP_USER_RESET_B_M7 | SRC_SRSR_WDOG_RST_B_M7 | SRC_SRSR_JTAG_RST_B_M7
        | SRC_SRSR_JTAG_SW_RST_M7 | SRC_SRSR_WDOG3_RST_B_M7 | SRC_SRSR_TEMPSENSE_RST_B_M7)); // clear reset cause flags
}

The relevant part is

if ((SRC_SRSR & (SRC_SRSR_WDOG3_RST_B_M7 | SRC_SRSR_WDOG_RST_B_M7)) != 0) { // watchdog reset detected
    unsigned short usWatchdogCount = *BOOT_WDOG_COUNTER; // original watchdog reset count
    ++usWatchdogCount; // count the number of watchdog resets
    if ((usWatchdogCount % 16) == 0) { // every 16th watchdog reset
        *BOOT_MAIL_BOX = RESET_TO_FALLBACK_LOADER; // offer the fall-back loader so that potentially bad code can be updated
    }
    else {
        *BOOT_MAIL_BOX = DO_FULL_RESET; // initiate full boot cycle on watchdog reset
    }
    *BOOT_WDOG_COUNTER = usWatchdogCount; // save the incremented watchdog reset counter
}

As you see, a watchdog reset will cause a full reset sequence to be executed and the mailbox cleared.

I haven't understood why there is an issue with performing a software reset on the EA boards since I never had such an issue but it would be possible to adjust the logic above to not clear the mailbox in case it does match one of the commands that you need.

In addition, the serial loader (fall-back loader) is in fact started every time 16x watchdog resets are detected. This puts the system in the fall-back loader mode fro 15s (allowing recovery in case the situation is due to loading a bad serial loader) and the 1 minute in the serial loader mode (in case it is due to a bad application). If you perform a watchdog reset 16x you should in fact enter the loader. Also you could change the counter value so that it does this after different counts or even every time.

Regards

Mark

 

 

 

0 Kudos

1,712 Views
Gra67
Contributor III

Hi Mark

I was vaguely aware watchdog resets were treated differently and they were counted from your flow diagram. The feature to roll back to fall-back loader after so many WD resets is a good idea. I did notice the FORCE_BOOT() checked for a SOFTWARE_RESET_DETECTED() so I removed this because I couldn't get a software reset to work.

To simplify testing I've removed your bootloader for now, so I just print out my mailbox variable when my app restarts, then I set it and force a watchdog reboot.

Adding SCB_CleanDCache(); helped, but only if I reset using the debugger. I've tried using L1CACHE_DisableICache(); too and it's no better. So it's looking like the WD reset corrupts the RAM some way the debugger reset doesn't. As you say, normally when a WD fires it's 'cos something bad has happened.

As a few people with Embedded Artists boards cannot perform a software reset I think I'll go back and ask them again.

Regards

Graeme

 

0 Kudos

1,742 Views
crist_xu
NXP Employee
NXP Employee

I think you should place the SCB_CleanDCache()  in the handler of the Watchdog, so that when a watchdog timeout occur, the cache will be cleaned. and the system will reset.
But i also recommend to place the varible in the DTCM or a non-cache area, so that the SCB_CleanDCache() function can omit.

0 Kudos

1,734 Views
mjbcswitzerland
Specialist V

Hi

Note that the RAM type used for the mailbox location depends on the FlexRAM configuration that the application uses. It is defined in the uTasker loader to be at the top of FlexRAM bank 15 (of 1062) so that it is sure that the ROM LOADER doesn't use the space (and also to enable on-the-fly FlexRAM changes without stack corruption). The exact layout and details are in chapter "RAM and Cache" of https://www.utasker.com/docs/iMX/i.MX_RT_1060_uTasker.pdf

The uTasker application is optimised for speed and so this is in fact always in DTMC when the application runs.

In environments that happen to have this in cached OCRAM disabling the data cache when writing is suitable solution since the next event is a reset anyway.

Regards

Mark

 

0 Kudos

1,803 Views
jeremyzhou
NXP Employee
NXP Employee

Hi,
Thank you for your interest in NXP Semiconductor products and for the opportunity to serve you.
I don't think the method can work, I think you should store the value to the Flash instead of RAM.
Have a great day,
TIC

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

 

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos

1,801 Views
Gra67
Contributor III

Hi Jeremyzhou

Using RAM this way can work I have done similar thing with other processors.

Also the bootloader I am using is the uTasker one and it looks at a specific RAM address.

Thanks

Graeme

0 Kudos