Registro de datos en la memoria flash en serie

1

Estoy trabajando en un registrador de datos que escribe las posiciones del GPS al flash serie W25Q64FV. Planeo escribir datos GPS cada segundo. Tengo un par de preguntas:

  1. Con esta memoria flash es posible escribir en cualquier posición de 1 a 256 bytes a la vez (página). La especificación dice que la memoria tiene 100,000 ciclos de escritura / borrado. ¿Se cuenta por página o por byte? Entonces, si escribo un byte en la dirección X y luego otro en la dirección X + 1 (pero en la misma página) ¿significa que solo me quedan 99.998 escrituras a esa página? Yo diría que no, pero seguro que lo estoy preguntando. ¿Qué sucede si la escritura de un byte reescribe internamente la página completa?
  2. ¿Cómo mantener persistentemente la dirección del último byte escrito? Podría escribirlo en la EEPROM de Arduino en cada actualización, pero también tiene "solo" 100,000 ciclos de escritura, por lo que esto se alcanzaría mucho antes. Otra posibilidad podría ser escanear toda la memoria escrita y buscar el (los) byte (s) vacío (s), pero esto puede llevar un tiempo. O tal vez solo para tener un mapa de bits en el encabezado flash que marca las páginas completas y solo escanearía el último. ¿Alguna otra sugerencia?
  3. ¿Hay algún propósito especial para borrar bloques o completar la memoria flash? ¿No puedo simplemente escribir en la memoria de forma rotunda? Si elimino un archivo en mi disco duro, no escribirá ceros en todos sus bytes, ¿no podría ser igual con flash?
pregunta Martin Ždila

4 respuestas

3

En primer lugar, la forma en que funciona flash, en general, es que un comando de escritura solo puede cambiar los bits de uno a cero. Para devolver los bits a uno, debe borrar un bloque de borrado completo. Por lo tanto, no puede simplemente "escribir en él como un disco duro". En la mayoría de los dispositivos flash, se pueden hacer múltiples escrituras en el mismo bloque o incluso en el mismo byte, de nuevo siempre y cuando solo esté cambiando los ceros a ceros. (Hay algunos dispositivos flash donde el fabricante recomienda que no se realicen varias escrituras en el mismo bloque, pero esto es raro.)

Para responder a sus preguntas específicas:

1) En general, la resistencia se basa en los ciclos borrar en cada bloque. Puede escribir bits individuales (a cero) todo lo que desee, pero hacer un borrado para devolver los bits a uno desgastará esos bits de destello.

2) Una forma es usar el primer byte de cada registro como indicador de estado. Se inicia, después del borrado, como 0xFF. Cuando comienza a escribir el registro, escribe 0x7F en ese byte (cero el bit alto). Una vez que complete la escritura del registro, escriba 0x3F en ese byte (cero el siguiente bit más alto). Para marcar un registro como eliminado, escriba 0x00 en ese byte. Todo esto aprovecha el hecho de que siempre puede pasar un bit de uno a cero.

Más tarde, cuando estás leyendo registros, solo miras los registros con 0x3F en ese byte. 0x7F significa que la escritura del registro se interrumpió (falla de alimentación / reinicio) y no es válida. Una vez que un bloque de borrado completo tiene solo 0x00, 0x7F y 0xFF, se puede borrar.

Por cierto, puedes mantener un mapa de bloques usados / libres en RAM para que solo tengas que escanear al iniciar.

3) Consulte la parte superior de esta publicación.

    
respondido por el DoxyLover
1

Habiendo trabajado con flash y habiendo sido mordido por varios problemas, sugeriría que podría ser una buena idea diseñar su formato de datos de tal manera que no sea confundido por nada que pueda Aparecen en un bloque que se borró cuando se perdió el poder. Mi esquema favorito actual es usar una secuencia de bloques rodantes, cada uno de los cuales tiene un byte que está programado en todos, excepto en el bloque más reciente; el bloque que sigue a ese bloque debe suponerse que contiene basura, y su contenido debe ignorarse. Cuando el bloque más reciente se llene, se debe borrar el siguiente bloque y se debe escribir la información de encabezado necesaria. Una vez hecho esto, el bloque "más reciente" anterior debe tener su byte de bandera programado para indicar que ya no es el bloque más reciente (el bloque recién borrado es).

Tenga en cuenta que con este esquema, no hay peligro de que aparezca un patrón de datos aparentemente válido en un bloque parcialmente borrado, o de que el software confunda un bloque parcialmente borrado con uno en blanco. No es posible evitar que el código lea el bit de "estado" de un bloque parcialmente borrado, pero ese bloque se reconocerá como basura basándose únicamente en el contenido de otros bloques que no sean de basura.

    
respondido por el supercat
0

1) Un ciclo p / e para un sector sería escribir varios valores en ese sector y borrar todo el sector en algún momento. Entonces, podría escribir todas las direcciones en un sector y eso solo contaría como un ciclo p / e si solo borra el sector una vez que esté lleno.

2) ¿Realmente tiene que almacenar persistentemente la última ubicación de memoria? Probablemente solo buscaría la última ubicación de Flash utilizada durante el encendido del dispositivo y luego mantendría el contador de direcciones en la RAM.

3) Dependiendo de su aplicación, simplemente podría llenar el dispositivo y borrar solo una vez que tenga que hacerlo. O puede implementar algún tipo de gestión que mueva la dirección de inicio, es decir, salte al siguiente bloque una vez que los datos se hayan transmitido a algún dispositivo externo. Eso también podría usarse como una forma simple de nivelación de desgaste.

    
respondido por el og1L
0

Esta es la forma en que hago el nivel de guerra en EERPOM / FLASH.

Divida su memoria en dos arreglos, una para datos y uno como nivel de guerra (asumo un número de 16 bits para el nivel de guerra aquí, que funciona bien siempre y cuando tenga < 65535 registros).

Para empezar, toda la memoria debe ser 0xFF bytes. Entonces, la primera escritura es un caso especial de warelevel [0] y warelevel [1] siendo 0xFFFF, usted escribe datos de registro en datos [0x0000] y escribe warelevel [0x0000] = 0x0001.

En todas las escrituras subsiguientes, recorre la matriz de nivel de guerra, buscando un número que no se incremente. Cuando encuentre uno, use ese índice para la matriz de datos y actualice la matriz de nivel de guerra para que sea secuencial.

Entonces, para la segunda escritura, verás que warelevel [0] = 0x0001, pero warelevel [1] = 0xFFFF, que no es incremental. Así que ya sabes que el siguiente índice para escribir es 1. Así que escribes warelevel [1] = warelevel [0] +1, y escribes tus datos en data [1].

Luego, para la siguiente escritura: warelevel [1] = 0x0001 y warelevel [2] = 0x0002, y warelevel [3] = 0xFFFF, así que ahora sabes escribir en la dirección 3, y ahora configuras warelevel [3] en 0x0003.

Esto continúa y uno para siempre. Básicamente, en cualquier momento puede encontrar la siguiente posición para escribir simplemente buscando un cambio numérico no incremental en la matriz de niveles de guerra.

Entonces todo lo que tienes que hacer es 'envolver'. Por ejemplo, siga contando más allá de 0xFFFF hasta 0. Con el desbordamiento de enteros estándar, todo funcionará. El contador puede ir de 0 a 0xFFFF, incluso si tiene menos de 0xFFFF registros (Sin embargo, necesita un contador de tamaño de bit más grande si tiene MÁS de 0xFFFF registros).

Esto le permitirá asegurarse de que cada byte se escriba el mismo número de veces. Así que el código es básicamente el "mejor uso" independientemente de si la vida útil de la memoria es 10k 100k o 1M.

La desventaja es, por supuesto, que se pierde espacio en la matriz de nivel de guerra. Cuanto más pequeños sean tus registros, más espacio perderás.

Las ventajas de este método es que no tiene que "almacenar" un índice en ningún lugar. Así que no hay una ubicación de memoria que se rompa con fuerza.

    
respondido por el Myforwik

Lea otras preguntas en las etiquetas