Use nivelación en la EEPROM de un microcontrolador

13

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

  

Resistencia EEPROM programable en el sistema de 128 bytes: 100,000 Escribir / Borrar   Ciclos

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 hacer que sea inútil. Todo el dispositivo se volvería poco confiable, porque en un momento determinado no puede hacer un seguimiento de qué bytes en EEPROM no son confiables.

¿Existe una forma inteligente de realizar nivelación de desgaste en la EEPROM de un microcontrolador cuando utiliza de manera efectiva solo uno o dos bytes de los 128 disponibles?

    
pregunta jippie

4 respuestas

19

La técnica que normalmente utilizo es prefijar los datos con un número de secuencia 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 formo 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 el siguiente número de secuencia que se usará y la cola actual de la cola. El siguiente pseudocódigo de C demuestra que esto asume que en 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.

    
respondido por el PeterJ
4

A continuación se incluye un método que utiliza depósitos y aproximadamente un byte superior por depósito. Los bytes de cubo y los bytes de sobrecarga obtienen aproximadamente la misma cantidad de desgaste. En el ejemplo que nos ocupa, dado 128 bytes EEPROM, este método asigna 42 depósitos de 2 bytes y 44 bytes de estado, lo que aumenta la capacidad de desgaste en aproximadamente 42 veces.

Método:

Divida el espacio de direcciones EEPROM en grupos k , donde k = ⌊ E / ( n +1 ) With, con n = setup-data-array size = tamaño de depósito, y E = tamaño de EEPROM (o, más generalmente, el número de celdas EEPROM que se dedicarán a esta estructura de datos).

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

Cuando la entrada del directorio actual contiene j , el cubo j contiene datos actuales. Cuando necesita escribir una nueva entrada de datos de configuración, almacena j +1 en la entrada del directorio actual; si eso lo hace igual a k , inicialice la siguiente entrada de directorio a 0 y continúe desde allí.

Tenga en cuenta que los bytes de directorio obtienen aproximadamente la misma cantidad de desgaste que los bytes de depósito porque 2 · k > m k .

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

    
respondido por el James Waldby - jwpat7
2

He usado un número de secuencia para esto (similar a la respuesta de Peter). El número de secuencia puede ser en realidad tan poco como 1 bit, siempre que la cantidad de elementos en la cue sea impar. La cabeza y la cola están marcadas con 2 1 o 0 consecutivos

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

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

    
respondido por el Mick Clift
1

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

  1. Si su EEPROM tiene páginas que se pueden borrar individualmente y usted 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 utiliza una fracción de una página que debe borrarse a la vez, divida esa página en entradas de datos. Use una entrada limpia cada vez que escriba, y borre una vez que se quede sin entradas limpias.

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

Si su biblioteca EEPROM no expone la función de borrado (como Arduino), aquí hay un truco para Algoritmo # 2: ya que siempre se usa su primera entrada EEPROM, puede determinar el valor del bit "sucio" al leerlo. Luego, una vez que te quedas sin entradas limpias, simplemente comienzas nuevamente desde la primera entrada, invirtiendo el bit "sucio", y el resto de tus entradas se marcarán automáticamente como "limpias".

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

    
respondido por el Dmitry Grigoryev

Lea otras preguntas en las etiquetas