How to preserve state between resets?

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

How to preserve state between resets?

Jump to solution
4,403 Views
laszlomonda
Contributor V

Hi guys,

My application firmware enumerates as a keyboard USB device, or as a BusPal protocol translator USB device. I must be able to switch between the two. I could reenumerate from the application software as the other USB device without resetting the MCU, but there is a lot of state involved in the firmware, and I'd rather not maintain the state upon switches.

Instead, I'd much rather reset the MCU to clean its state, and enumerate as the desired device. But for this to work, I have to store some state, so that the application firmware can branch to the USB keyboard routine vs the BusPal routine.

Is there any way to save state across resets? For example by using a register, SRAM or any other means? I used to use AVR microcontrollers and this was possible with AVRs. What about the K22? Also, what kind of reset should I use? Software reset, watchdog reset, or anything else?

Thank you for your help!

- Laci

1 Solution
3,107 Views
BlackNight
NXP Employee
NXP Employee

Hi Laci,

the trick is to avoid that the normal C/C++ startup code is erasing the memory with the information (by default, the startup code initializes all memory used).

One way is described in GNU Linker, can you NOT Initialize my Variable? | MCU on Eclipse .

Or simply hook your code into the part right after the reset (in the startup code), this depends on your environment/toolchain/etc.

I hope this helps,

Erich

View solution in original post

7 Replies
3,107 Views
bobpaddock
Senior Contributor III

With GCC the normal zeroing of a variable by the C start up code can be disabled:

#define NO_INIT_GCC __attribute__ ((section (".noinit")))

static uint16_t your_var_u16_n NO_INIT_GCC;

Such variables are collected in the .noinit section.
Checker that your linker script has such a section, how big it is and where it is located.

By default it is usually after the .data section.

I move it to be the first section in RAM to make sharing with a bootloader easier.

Check the 'Reset' state to make sure the variable does get initialized to a valid value for your application as its value will be random otherwise.


Also be aware that some of the lowest power states do not preserve the RAM.

0 Kudos
Reply
3,107 Views
laszlomonda
Contributor V

Thank you so much, Bob!

I think your solution is the most elegant one, although my case is more complicated than usually, because I want to transfer data between the bootloader and the application firmware which allocate memory differently.

There's an extremely relevant suggestion which worked perfectly on AVRs. I'm trying to implement the same on Kinetis, but I cannot access the stack pointer yet.

Thanks again!

0 Kudos
Reply
3,107 Views
bobpaddock
Senior Contributor III

This will return the  current stack pointer value:

static __inline__ void *sp_get(void)
{
void *sp;

__asm__ __volatile__ ("mrs %0, msp" : "=r"(sp));

return( sp );
}


However you probably actually want a constant from the linker script.  Probably not what you really want either.

I move the .noinit section to the start of RAM so it is in a known place so that I can communicate between bootloader and the app at startup.
Simpy moving .noinit to before everything else gets rid of all of the 'growth' and messing with stack discussed at AVRFreaks.

The GPIOx section also simulates some of the XMega address space so I can share code between the Kenitis M0+ and an XMega.

Make sure that the NOINIT space is more than you need but not by much.  Allocating to much wastes RAM and using more than allocated makes hair pulling bugs.  0x200/512 bytes is what I use in my project:

MEMORY
{
VECTORS (rx) : ORIGIN = 0x0, LENGTH = 0x000000C0
BOOTCFG (r) : ORIGIN = 0x000003C0, LENGTH = 64
FLASHCFG (r) : ORIGIN = 0x00000400, LENGTH = 16
FLASH (rx) : ORIGIN = 0x00000410, LENGTH = (256K - 1K - 0x410) /* Flash size - EEPROM Sim size - vectors and Flash Config bytes */
EEPROMSIM (rx) : ORIGIN = (256K - 1K), LENGTH = 1K

BOOTLOADER (rx) : ORIGIN = 0x1C000000, LENGTH = 16K

NOINIT (rwx) : ORIGIN = 0x1FFFE000, LENGTH = 0x200 /* Space for variables that do not get zeroed at C startup */
GPIOx (rwx) : ORIGIN = 0x1FFFE200, LENGTH = 0x10 /* Space to simulate AVR GPIOx */
RAM (rwx) : ORIGIN = 0x1FFFE210, LENGTH = (32K - 0x200 - 0x10) /* Internal SRAM. flash_kinetis_cmd executes out of RAM */

}

3,107 Views
BlackNight
NXP Employee
NXP Employee

Hi Laci,

If I remember correctly, there is a peripheral register bit/flag which can you tell the reset reason (say power-on reset or software reset, or watchdog). What I have used in some of my projects is to have a SRAM area with my status (protected with a CRC) which I read right after reset (before the startup code would initialize the SRAM). That way I can 'carry over' state information between resets.

Other than that, I'm usually programming the on-chip internal flash or EEPROM (see Configuration Data: Using the Internal FLASH instead of an external EEPROM | MCU on Eclipse ) or using an external SRAM or EEPROM for this. There can be other options too.

I hop the helps,

Erich

0 Kudos
Reply
3,107 Views
laszlomonda
Contributor V

Hi Erich,

Yes, know that it's possible to query the source of the reset via the Reset Control Module, but it isn't a whole lot of information to be transferred.

I'm much more interested about using the internal SRAM to transfer state across resets. How to do that?

Thank you!

Laci

0 Kudos
Reply
3,108 Views
BlackNight
NXP Employee
NXP Employee

Hi Laci,

the trick is to avoid that the normal C/C++ startup code is erasing the memory with the information (by default, the startup code initializes all memory used).

One way is described in GNU Linker, can you NOT Initialize my Variable? | MCU on Eclipse .

Or simply hook your code into the part right after the reset (in the startup code), this depends on your environment/toolchain/etc.

I hope this helps,

Erich

3,107 Views
laszlomonda
Contributor V

Hi Erich,

In your true style, of course there's an MCU on Eclipse article about this topic. :smileyhappy:

Thanks a ton! It's super useful, and makes perfect sense.

Have a nice day, and keep it up!

Laci

0 Kudos
Reply