Non-Volatile Memory

From Nutwiki
Jump to: navigation, search

Test Environment

Hardware Comments Nut/OS
4.8.3
Nut/OS
4.8.7
Ethernut 1.3 H OK
Binaries
Compiler: AVR-GCC 4.3.2
OK
Binaries
Compiler: AVR-GCC 4.3.2
Ethernut 2.1 B OK
Binaries
Compiler: AVR-GCC 4.3.2
OK
Binaries
Compiler: AVR-GCC 4.3.2
Ethernut 3.0 E OK
Binaries
Compiler: ARM-GCC 4.3.3
OK
Binaries
Compiler: ARM-GCC 4.3.3

Overview

Within this example you'll learn how to load data from and save data to the non-volatile memory of your board.

Hardware dependencies

According to the hardware provided by your target board, Nut/OS supports different kind of non-volatile memory devices.

Target Board provides Configuration area uses
8-bit AVR 1 On-Chip EEPROM
X12x6 RTC 2 On-Chip EEPROM
AT45D DataFlash Last flash page
AT91SAM 3 Last on-chip flash page

Notes:

1 See Ethernut 1 and Ethernut 2 reference designs.
2 Intersil X1226 or X1286 real-time clocks with integrated EEPROM, used on Ethernut 3.0.
3 Used as a last resort if no other hardware is available.

System usage

Nut/OS itself makes use of non-volatile memory for two purposes:

  1. Persistent storage of the CONFOS structure, containing the host name
  2. Persistent storage of the CONFNET structure, containing the basic network configuration

By default, the CONFOS structure (19 bytes) is stored at the beginning of the configuration area, while the CONFNET structure (32 bytes) is located at byte offset 64.

Although not yet supported, Nut/OS is prepared to handle more than one network interface, each of which requires its own CONFNET structure at byte offset 96, 128 and so on. To avoid conflicts with later versions, most applications keep the first 256 bytes of the configuration area available for the OS.

In any case the Configurator allows to modify several default settings.

Configuring non-volatile memory

File:Configurator NVMEM.png
General configuration of non-volatile memory
File:Configurator CONFOS.png
Configuration of non-volatile system settings
File:Configurator CONFNET.png
Configuration of non-volatile network settings

Source

<source lang="c">

  1. include <dev/board.h>
  2. include <stdio.h>
  3. include <io.h>

struct _USER_CONFIG {

   unsigned char len;          /* Length of this structure. */
   unsigned int count;         /* Number of reboots. */

};

int main(void) {

   unsigned long baud = 115200;
   struct _USER_CONFIG uconf;
   NutRegisterDevice(&DEV_DEBUG, 0, 0);
   freopen(DEV_DEBUG_NAME, "w", stdout);
   _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
   puts("Non-volatile memory example\n");
   NutNvMemLoad(256, &uconf, sizeof(uconf));
   if (uconf.len != sizeof(uconf)) {
       puts("Size mismatch: There is no valid configuration present. A new configuration will be created.");
       uconf.count = 0;
   } else {
       printf("According to the user configuration this board was already rebooted %d times.\n", uconf.count);
   }
   uconf.len = sizeof(uconf);
   uconf.count++;
   NutNvMemSave(256, &uconf, sizeof(uconf));
   for (;;);
   return 0;

} </source>

Details

<source lang="c"> struct _USER_CONFIG {

   unsigned char len;          /* Length of this structure. */
   unsigned int count;         /* Number of reboots. */

}; </source>

This structure is a fictional user config that stores the number of reboots that the board has already done. Feel free to add your own fields if you like, just make sure you use it properly later on. The len is the length of our structure in bytes. We'll use this to compare the data read to the data we expected to read and then judge if it is valid or not.

<source lang="c">

   unsigned long baud = 115200;
   struct _USER_CONFIG uconf;

   NutRegisterDevice(&DEV_DEBUG, 0, 0);

   freopen(DEV_DEBUG_NAME, "w", stdout);
   _ioctl(_fileno(stdout), UART_SETSPEED, &baud);

   puts("Non-volatile memory example\n");

</source>

As always we register our debug device and tell the world the application name.

<source lang="c"> NutNvMemLoad(256, &uconf, sizeof(uconf)); </source>

Now we load our structure from non-volatile memory. But wait - isn't there no structure present we do this the first time? You're right. In that case we read junk data, data with unpredictable contents. We are prepared for this case, though. More on that in a moment. First, please note the 256. This is the memory address we read from. We can't use 0-255 because those are reserved for Nut/OS configurations. Technically we can read and write that data at will, we just don't want to mess with our configurations or accidentally overwrite them. So, 256+ it is. Also, please don't forget the & before the name of your structure/variable or you'll read data but not store it anywhere in RAM.

<source lang="c">

   if (uconf.len != sizeof(uconf)) {
       puts("Size mismatch: There is no valid configuration present. A new configuration will be created.");
       uconf.count = 0;

</source>

Now we compare the len variable we read to the real length of our structure in bytes. If they don't match, that is due to one of two reasons:

a) The structure we read was malformed. This can happen if we try to read a structure written by another program or another version of our own program. If you'd add a new variable to the userconfig for example you'd cause such a size mismatch on first reboot. b) There was no valid structure to read. This will happen if the structure was corrupted or simply never written (for example on first run of this program).

In this case we set the reboot count to 0 to give it a proper initial value.

<source lang="c"> } else {

   printf("According to the user configuration this board was already rebooted %d times.\n", uconf.count);

} </source>

If our sizes do match we output the number of reboots, uconf.count.

<source lang="c">

   uconf.len = sizeof(uconf);
   uconf.count++;

</source>

Now we increment the count by 1 since we rebooted once. We also set len to the size of uconf to make sure the length we save matches the length of what we save.

<source lang="c">

   NutNvMemSave(256, &uconf, sizeof(uconf));

</source>

Now we save our structure to NV memory. Again, we use the address 256 to avoid overwriting Nut/OS configurations. Also don't forget & in front of uconf or you won't save anything sensible.

Output

<source lang="text"> Non-volatile memory example

Size mismatch: There is no valid configuration present. A new configuration will

be created.

Non-volatile memory example

According to the user configuration this board was already rebooted 1 times.

Non-volatile memory example

According to the user configuration this board was already rebooted 2 times.

Non-volatile memory example

According to the user configuration this board was already rebooted 3 times. </source>

See also