Desgaste nivelado en EEPROM de un microcontrolador


15

Por ejemplo: la hoja de datos para ATtiny2313 (como la mayoría de las hojas de datos de Atmel AVR) establece:

128 bytes de resistencia EEPROM programable en el sistema: 100,000 ciclos de escritura / borrado

Imagine que un programa solo requiere dos bytes para almacenar alguna configuración, los otros 126 bytes se desperdician efectivamente. Lo que me preocupa es que las actualizaciones periódicas de los dos bytes de configuración pueden desgastar la EEPROM del dispositivo y volverlo inútil. Todo el dispositivo no sería confiable, porque en un momento determinado simplemente no puede realizar un seguimiento de qué bytes en EEPROM no son confiables.

¿Existe una manera inteligente de nivelar el desgaste en la EEPROM de un microcontrolador cuando usa efectivamente solo uno o dos bytes de los 128 disponibles?


1
Si 100k ciclos de escritura fueran una restricción, ¿tendría sentido usar alguna otra tecnología en su lugar? ¿O un mecanismo que incorpora nivelación internamente o algo con un orden de magnitud o mayor resistencia?
Anindo Ghosh

1
@AnindoGhosh Simplemente no quiero desperdiciar mi pequeño stock de microcontroladores solo por desgastar EEPROM debido a que probé una prueba de concepto. No quiero preocuparme por qué byte he estado usando en un proyecto anterior cuando reutilizo el controlador. Y se siente bien saber que hago un uso óptimo del hardware disponible.
jippie


1
Tal vez eche un vistazo a mi respuesta en stackoverflow .
JimmyB

¡Eche un vistazo a la serie MSP430 FRAM de TI ... 10 ^ 13 escribe!
geometrikal

Respuestas:


19

La técnica que uso normalmente es prefijar los datos con un número secuencial de 4 bytes, donde el número más grande representa el último / valor actual. En el caso de almacenar 2 bytes de datos reales que darían un total de 6 bytes y luego formar en una disposición de cola circular, por lo que para 128 bytes de EEPROM contendría 21 entradas y aumentaría la resistencia 21 veces.

Luego, al arrancar, se puede usar el número de secuencia más grande para determinar tanto el siguiente número de secuencia que se usará como la cola actual de la cola. El siguiente pseudocódigo C demuestra que esto supone que, después de la programación inicial, el área EEPROM se ha borrado a valores de 0xFF, por lo que ignoro un número de secuencia de 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;
}

Para una EEPROM más pequeña, una secuencia de 3 bytes sería más eficiente, aunque requeriría un poco de corte de bits en lugar de utilizar tipos de datos estándar.


+1, buen enfoque. ¿Se puede optimizar un poco el almacenamiento utilizando menos bytes de "etiqueta", y posiblemente dependiendo de algún tipo de mecanismo de depósito hash para proporcionar una distribución adicional? ¿Un híbrido entre no nivelación y su enfoque?
Anindo Ghosh

@AnindoGhosh, sí, creo que podría. Normalmente he usado este enfoque en micros pequeños para simplificar el código y personalmente lo he usado principalmente en dispositivos más grandes como DataFLASH. Otra idea simple que viene a la mente también es que los números de secuencia podrían reducirse periódicamente para mantenerlos en valores más pequeños.
PeterJ

La nota de aplicación Atmel mencionada por @ m.Alin tiene una simplificación inteligente: después de un RESET, es posible mirar a través del [...] buffer, encontrando el último elemento [...] del buffer cambiado al encontrar la ubicación donde el La diferencia entre un elemento buffer y el siguiente elemento buffer es mayor que 1 .
jippie

¿No debería write_value () poner la entrada en queue_tail * sizeof (QUEUE_ENTRY)? estaré en lo correcto la primera vez, pero ¿no debería continuar avanzando si hay varias escrituras? i no se incrementa fuera de load_queue ().
Marshall Eubanks

2
@ DWORD32: Sí, eso es técnicamente correcto, pero irrelevante en la práctica. Para cuando eso suceda, ¡el límite de desgaste en la EEPROM habrá sido excedido por un factor de 2000!
Dave Tweed

5

A continuación se muestra un método que usa cubos y aproximadamente un byte superior por cubo. Los bytes de la cubeta y los bytes de sobrecarga reciben aproximadamente la misma cantidad de desgaste. En el ejemplo en cuestión, dados 128 bytes EEPROM, este método asigna 42 cubos de 2 bytes y 44 bytes de estado, aumentando la capacidad de desgaste aproximadamente 42 veces.

Método:

Divida el espacio de direcciones EEPROM en k cubos, donde k = ⌊ E / ( n +1) ⌋, con n = tamaño de matriz de datos de configuración = tamaño de cubeta y E = tamaño EEPROM (o, más generalmente, el número de EEPROM celdas para dedicar a esta estructura de datos).

Inicialice un directorio, una matriz de m bytes, todos configurados en k , con m = En · k . Cuando su dispositivo se inicia, lee a través del directorio hasta que encuentra la entrada actual, que es un byte no igual a k . [Si todas las entradas del directorio son iguales a k , inicialice la primera entrada del directorio a 0 y continúe desde allí.]

Cuando la entrada del directorio actual contiene j , el depósito j contiene datos actuales. Cuando necesite escribir una nueva entrada de datos de configuración, almacene j +1 en la entrada actual del directorio; si eso es igual a k , inicialice la siguiente entrada del directorio a 0, y continúe desde allí.

Tenga en cuenta que los bytes del directorio obtienen aproximadamente la misma cantidad de desgaste que los bytes del cubo porque 2 · k > mk .

( Adapte lo anterior de mi respuesta a la pregunta 34189 de Arduino SE , ¿Cómo aumentar la vida de EEPROM? )


2

He usado un número de secuencia continua para esto (similar a la respuesta de Peter). El número de secuencia en realidad puede ser tan pequeño como 1 bit, siempre que el número de elementos en la cue sea impar. La cabeza y la cola se marcan con los 2 1 o 0 consecutivos.

Por ejemplo, si desea pasar por 5 elementos, los números de secuencia serían:

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


1

Hay un par de opciones según el tipo de EEPROM que tenga y el tamaño de sus datos.

  1. Si su EEPROM tiene páginas que se pueden borrar individualmente y usa 1 página (o más), simplemente mantenga todas las páginas borradas, excepto las que están en uso, y reutilice las páginas de manera circular.

  2. Si solo usa una fracción de una página que debe borrarse de una vez, divida esa página en entradas de datos. Use una entrada limpia cada vez que esté escribiendo y borre una vez que se quede sin entradas limpias.

Use un bit "sucio" para distinguir entre entradas limpias y sucias si es necesario (por lo general, tiene al menos un byte que se garantiza que es diferente de 0xFF, que puede usarse para rastrear entradas sucias).

Si su biblioteca EEPROM no expone la función de borrado (como Arduino), aquí hay una buena truco para el algoritmo # 2: dado que su primera entrada EEPROM siempre se usa, puede determinar el valor del bit "sucio" al leerlo. Luego, una vez que se quede sin entradas limpias, simplemente comienza de nuevo desde la primera entrada, invierte el bit "sucio", y el resto de sus entradas automáticamente se marcan como "limpias".

Los números de secuencia y los catálogos son un desperdicio de espacio a menos que desee realizar un seguimiento de páginas defectuosas o actualizar diferentes partes de sus datos EEPROM de forma independiente.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.