Indossa un livellamento sull'EEPROM di un microcontrollore


15

Ad esempio: il foglio dati per ATtiny2313 (come la maggior parte dei fogli di dati Atmel AVR) indica:

128 byte Resistenza EEPROM programmabile nel sistema: 100.000 cicli di scrittura / cancellazione

Immagina che un programma richieda solo due byte per memorizzare una configurazione, mentre gli altri 126 byte vengono effettivamente sprecati. Ciò che mi preoccupa è che gli aggiornamenti regolari dei due byte di configurazione potrebbero logorare la EEPROM del dispositivo e renderla inutile. L'intero dispositivo diventerebbe inaffidabile, perché in un determinato momento non è possibile tenere traccia di quali byte in EEPROM non sono affidabili.

Esiste un modo intelligente per livellare l'usura della EEPROM di un microcontrollore quando si utilizzano effettivamente solo uno o due byte su 128 disponibili?


1
Se i cicli di scrittura a 100k fossero un vincolo, avrebbe senso usare qualche altra tecnologia? O un meccanismo che incorpora il livellamento interno o qualcosa con un ordine di grandezza o una resistenza maggiore?
Anindo Ghosh

1
@AnindoGhosh Non voglio sprecare la mia piccola scorta di microcontrollori solo a causa dell'usura della EEPROM a causa dei miei test come prova di concetto. Non voglio preoccuparmi di quale byte ho usato su un progetto precedente quando ho riutilizzato il controller. Ed è bello sapere che utilizzo in modo ottimale l'hardware disponibile.
jippie,


1
Forse dai un'occhiata alla mia risposta su StackOverflow .
JimmyB,

Dai un'occhiata alla serie FRAM MSP430 di TI ... 10 ^ 13 scritture !!!
geometrikal,

Risposte:


19

La tecnica che utilizzo normalmente è quella di aggiungere un prefisso ai dati con un numero progressivo a 4 byte in cui il numero più grande rappresenta il valore più recente / corrente. Nel caso della memorizzazione di 2 byte di dati effettivi che darebbero un totale di 6 byte e quindi mi trasformerò in una disposizione circolare della coda, quindi per 128 byte di EEPROM conterrebbe 21 voci e aumenterebbe la resistenza 21 volte.

Quindi, all'avvio, è possibile utilizzare il numero di sequenza più grande per determinare sia il numero di sequenza successivo da utilizzare sia la coda corrente della coda. Il seguente pseudo-codice C dimostra che ciò presuppone che durante la programmazione iniziale l'area EEPROM sia stata cancellata con valori di 0xFF, quindi ignoro un numero progressivo di 0xFFFF:

struct
{
  uint32_t sequence_no;
  uint16_t my_data;
} QUEUE_ENTRY;

#define EEPROM_SIZE 128
#define QUEUE_ENTRIES (EEPROM_SIZE / sizeof(QUEUE_ENTRY))

uint32_t last_sequence_no;
uint8_t queue_tail;
uint16_t current_value;

// Called at startup
void load_queue()
{
  int i;

  last_sequence_no = 0;
  queue_tail = 0;
  current_value = 0;
  for (i=0; i < QUEUE_ENTRIES; i++)
  {
    // Following assumes you've written a function where the parameters
    // are address, pointer to data, bytes to read
    read_EEPROM(i * sizeof(QUEUE_ENTRY), &QUEUE_ENTRY, sizeof(QUEUE_ENTRY));
    if ((QUEUE_ENTRY.sequence_no > last_sequence_no) && (QUEUE_ENTRY.sequence_no != 0xFFFF))
    {
      queue_tail = i;
      last_sequence_no = QUEUE_ENTRY.sequence_no;
      current_value = QUEUE_ENTRY.my_data;
    }
  }
}

void write_value(uint16_t v)
{
  queue_tail++;
  if (queue_tail >= QUEUE_ENTRIES)
    queue_tail = 0;
  last_sequence_no++;
  QUEUE_ENTRY.sequence_no = last_sequence_no;
  QUEUE_ENTRY.my_data = v;
  // Following assumes you've written a function where the parameters
  // are address, pointer to data, bytes to write
  write_EEPROM(queue_tail * sizeof(QUEUE_ENTRY), &QUEUE_ENTRY, sizeof(QUEUE_ENTRY));
  current_value = v;
}

Per una EEPROM più piccola una sequenza di 3 byte sarebbe più efficiente, sebbene richiederebbe un po 'di suddivisione dei bit invece di utilizzare tipi di dati standard.


+1, approccio piacevole. L'archiviazione può essere ottimizzata un po 'utilizzando meno byte "tag", e possibilmente a seconda di una qualche forma di meccanismo di hash bucket per fornire ulteriore distribuzione? Un ibrido tra nessun livellamento e il tuo approccio?
Anindo Ghosh

@AnindoGhosh, sì, credo che potrebbe. Normalmente ho usato questo approccio su piccoli micro per la semplicità del codice e personalmente l'ho usato principalmente su dispositivi più grandi come DataFLASH. Un'altra semplice idea che viene in mente è che i numeri di sequenza potrebbero essere periodicamente abbassati per mantenerli a valori più piccoli.
PeterJ

La nota applicativa Atmel menzionata da @ m.Alin ha una semplificazione intelligente: dopo un RESET è quindi possibile guardare attraverso il [...] buffer, trovando l'ultimo elemento [...] buffer modificato trovando la posizione in cui il la differenza tra un elemento buffer e l'elemento buffer successivo è maggiore di 1 .
jippie,

Write_value () non dovrebbe mettere la voce in queue_tail * sizeof (QUEUE_ENTRY)? sarò corretto la prima volta, ma non dovrebbe continuare ad avanzare se ci sono più scritture? non viene incrementato al di fuori di load_queue ().
Marshall Eubanks,

2
@ DWORD32: Sì, è tecnicamente corretto, ma nella pratica irrilevante. Quando si verificherà, il limite di usura sulla EEPROM sarà stato superato di un fattore 2000!
Dave Tweed

5

Di seguito è riportato un metodo che utilizza bucket e circa un byte overhead per bucket. I byte bucket e i byte overhead ottengono circa la stessa quantità di usura. Nell'esempio attuale, dati 128 byte EEPROM, questo metodo alloca 42 bucket da 2 byte e 44 byte di stato, aumentando la capacità di usura di circa 42 volte.

Metodo:

Dividi lo spazio degli indirizzi EEPROM in k bucket, dove k = ⌊ E / ( n +1) ⌋, con n = setup-data-array size = dimensione bucket, ed E = EEPROM size (o, più in generale, il numero di EEPROM celle da dedicare a questa struttura di dati).

Inizializza una directory, un array di m byte tutti impostati su k , con m = En · k . All'avvio, il dispositivo legge la directory fino a quando non trova la voce corrente, che è un byte non uguale a k . [Se tutte le voci della directory sono uguali a k , inizializza la prima voce della directory su 0 e continua da lì.]

Quando la voce della directory corrente contiene j , bucket j contiene i dati correnti. Quando è necessario scrivere una nuova voce dei dati di configurazione, si memorizza j +1 nella voce della directory corrente; se ciò lo rende uguale a k , inizializza la voce di directory successiva su 0 e continua da lì.

Si noti che i byte di directory ottengono circa la stessa quantità di usura dei byte di bucket poiché 2 · k > mk .

(Ho adattato quanto sopra dalla mia risposta alla domanda 34189 di Arduino SE , Come aumentare la durata della EEPROM? )


2

Per questo ho usato un numero progressivo (simile alla risposta di Peter). Il numero di sequenza può effettivamente essere di appena 1 bit, a condizione che il numero di elementi nell'indicazione sia dispari. La testa e la coda sono quindi contrassegnate dai 2 1 o 0 consecutivi

Ad esempio, se si desidera scorrere 5 elementi, i numeri di sequenza sarebbero:

{01010} (scrivi a 0) {11010} (scrivi a 1) {10010} (scrivi a 2) {10110} (scrivi a 3) {10100} (scrivi a 4) {10101} (scrivi a 5)


1

Ci sono un paio di opzioni a seconda del tipo di EEPROM che hai e della dimensione dei tuoi dati.

  1. Se la tua EEPROM ha pagine cancellabili individualmente e utilizzi 1 pagina (o più), mantieni semplicemente tutte le pagine cancellate tranne quelle in uso e riutilizzale in modo circolare.

  2. Se si utilizza solo una parte di una pagina che deve essere cancellata in una sola volta, suddividere tale pagina in voci di dati. Usa una voce pulita ogni volta che scrivi e cancella una volta esaurite le voci pulite.

Usa un bit "sporco" per distinguere tra voci pulite e sporche, se necessario (di solito, hai almeno un byte che è garantito essere diverso da 0xFF, che può essere usato per tracciare voci sporche).

Se la tua libreria EEPROM non espone la funzione di cancellazione (come Arduino), ecco un trucco per l'algoritmo n. 2: poiché la tua prima voce EEPROM viene sempre utilizzata, puoi determinare il valore del bit "sporco" leggendolo. Quindi, una volta esaurite le voci pulite, ricominciare dalla prima voce, invertendo il bit "sporco" e le altre voci vengono automaticamente contrassegnate come "pulite".

I numeri di sequenza e i cataloghi sono uno spreco di spazio a meno che non si desideri essere in grado di tracciare pagine errate o aggiornare parti diverse dei dati EEPROM in modo indipendente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.