nvcu_storage.c

nRF52840-MDK (id boards.json : nrf52840-mdk) · Fichier : nvcu_storage.c · Langage : C · Usage : Conserver des données en flash avec le NVCU

Le contrôleur NVMC permet d'écrire la flash applicative sans SoftDevice : ce programme persiste un compteur et une calibration dans la dernière page, effacée puis réécrite à chaque sauvegarde. Idéal pour mémoriser des réglages.

Matériel requis

Une carte nRF52840-MDK (Nordic nRF52840, Cortex-M4F @ 64 MHz, 1 Mo flash / 256 Ko RAM, BLE 5 + 802.15.4) avec son debugger intégré, programmée en C sous nRF5 SDK v17 et SoftDevice S140. nRF52840-MDK seule ; LED P0.06 pour le témoin de compteur.

Câblage

Aucun câblage. Vérifier la carte de mémoire du linker : la page 0xFF000 ne doit pas être utilisée par le programme.

Fonctionnement

La flash s'efface par page (4 Ko) puis s'écrit par mots alignés ; le magic word valide le contenu au démarrage. Écrire trop souvent use la flash (≈ 10 000 cycles).

Exécution

Ouvrir l'exemple correspondant du nRF5 SDK v17 (target custom_board), coller ce code dans main.c, compiler avec Segger Embedded Studio ou Makefile gcc, puis programmer via le debugger intégré (flash_nrf.py ou IDE).

Variantes

Passer au module FDS/NFDS (journaling multi-enregistrements) pour des écritures fréquentes, ou logger en SPI/QSPI externe.

nvcu_storage.c

// nRF52840-MDK : sauvegarde d'un compteur dans la page flash dédiée NVCU.
// La flash nRF52840 s'efface par page de 4 Ko : le NVCU gère tout ça.
#include "nrf_nvmc.h"
#include <string.h>

#define PAGE 0x000FF000UL      // dernière page applicative (avant boot code)
typedef struct { uint32_t magic; uint32_t compteur; float calibration; } store_t;

static void sauvegarder(const store_t *s) {
  nrf_nvmc_page_erase(PAGE);
  // Écriture par mots de 32 bits (contrainte de la flash nRF).
  const uint32_t *mots = (const uint32_t *)s;
  for (unsigned i = 0; i < sizeof(store_t) / 4; i++)
    nrf_nvmc_word_write(PAGE + 4 * i, mots[i]);
}

int main(void) {
  const store_t *stock = (const store_t *)PAGE;
  store_t s;
  if (stock->magic == 0xA5A5A5A5UL) {
    s = *stock;                       // reprise de la dernière valeur
  } else {
    s.magic = 0xA5A5A5A5UL; s.compteur = 0; s.calibration = 1.0f;
    sauvegarder(&s);
  }
  s.compteur++;                       // ex : compteur de cycles machine
  sauvegarder(&s);

  // Témoin : la LED clignote (compteur % 4) fois après chaque démarrage.
  nrf_gpio_cfg_output(6);
  for (uint32_t i = 0; i < (s.compteur % 4) + 1; i++) {
    nrf_gpio_pin_set(6);   for (volatile int d = 0; d < 2e5; d++);
    nrf_gpio_pin_clear(6); for (volatile int d = 0; d < 2e5; d++);
  }
  for (;;) { }
}

← Retour à la fiche