Errores de lectura/escritura de EEPROM en dsPIC

Estoy ejecutando un Microchip dsPIC30F6012a. Tengo este chip en varios PCB, todos con el mismo software y observo el mismo problema en todos ellos. Esto implica un problema sistémico, no un problema de producción puntual. El problema también es reproducible, lo que implica que debería poder eliminarlo si sé dónde buscar. Pero todavía tengo dificultades sorprendentes para depurar la aplicación.

La placa bajo prueba acepta 24 V, que se reduce a 5 V a través de un V7805. El chip funciona con su oscilador interno, con un PLL de 16x, lo que proporciona una velocidad de funcionamiento de ~29,5 MIPS. El código relevante en esta placa es esencialmente muy simple: despertar, leer datos de EEPROM y luego ingresar a un ciclo infinito. Interrumpa cada milisegundo, observe algunos datos ambientales y escriba un valor actualizado en la EEPROM. Están sucediendo otras cosas, pero el problema aún ocurre incluso si el código no relacionado está comentado, por lo que puedo estar razonablemente seguro de que no es relevante para el problema en cuestión.

En uso general, el 95% del tiempo la placa se activa con el valor correcto en la memoria y continúa con su trabajo. Sin embargo, el otro 5% del tiempo, se despierta con un valor incorrecto. Específicamente, se despierta con una versión invertida de bits de los datos que se supone que debe tener. Lo que estoy viendo es un largo sin firmar de cuatro bytes, y la palabra superior o inferior del largo puede cambiarse. Por ejemplo, 10 se convierte en 2^16-10, que luego se convierte en 2^32-10. Puedo reproducir la falla ciclando manualmente la energía varias docenas de veces, pero eso no es muy consistente, y mi dedo del interruptor se desgasta.

Para reproducir el problema de forma controlada, construí una segunda placa que conduce el suministro de 24 V a la placa bajo prueba. (Otro dsPIC que maneja un optoacoplador darlington). La placa de prueba apaga los 24 V durante 1,5 segundos (el tiempo suficiente para que el riel de 5 V caiga esencialmente a 0 y permanezca allí durante un segundo), luego enciende los 24 V durante un período de tiempo configurable . Con un tiempo de encendido de aproximadamente 520 mS, puedo reproducir esta falla de EEPROM dentro de cinco ciclos de encendido, cada vez.

El riel de 5V se está comportando razonablemente. Se establece en 5 V dentro de 1 mS desde el encendido, con quizás 0,4 V de sobreimpulso, suponiendo que pueda confiar en mi alcance. Al apagarse, decae a 0V exponencialmente, alcanzando 1V en 50 mS. No tengo advertencias de compilación que parezcan relevantes, solo variables no utilizadas y saltos de línea faltantes al final de los archivos.

He probado varias cosas:

  • Habilitar/deshabilitar el MCLR
  • Habilitar/deshabilitar el WDT
  • Habilitar/deshabilitar la protección de código
  • Habilitar/deshabilitar/cambiar el voltaje de detección de caída de tensión
  • Habilitar/deshabilitar/cambiar el temporizador de encendido
  • Diferentes configuraciones de PLL en el oscilador interno principal
  • Conectar/desconectar mi programador PICkit 3
  • Agregar 470 uF de capacitancia al riel de 5V
  • Agregar/eliminar .1 uF en el pullup de 4.7k en mi pin MCLR
  • Deshabilitar todas las interrupciones en el código y dejar nada más que actualizaciones de EEPROM en el ciclo principal
  • Agregar un retraso de 1,5 segundos a mi rutina de inicio antes de comenzar a leer EEPROM

También escribí un código de prueba separado que no hace nada más que escribir continuamente valores en EEPROM y luego volver a leerlos, asegurándome de que el valor no haya cambiado. Decenas de miles de iteraciones no dieron errores. Todo lo que puedo concluir es que algo sale mal con la lectura o escritura de EEPROM, específicamente en el encendido/apagado.

He estado usando las mismas bibliotecas EEPROM desde 2007. He visto fallas ocasionales, pero nada reproducible. El código correspondiente se puede encontrar aquí:
http://srange.net/code/eeprom.c
http://srange.net/code/readEEByte.s
http://srange.net/code/eraseEEWord.s
http:/ /srange.net/code/writeEEWord.s

He visto errores de EEPROM antes en otras aplicaciones, pero siempre como fallas puntuales, nada tan reproducible o consistente.

¿Alguien tiene alguna idea de lo que está pasando? Me estoy quedando sin cosas para probar.

Consulte aquí para obtener una actualización sobre cómo resolver este problema: electronics.stackexchange.com/questions/38083/…

Respuestas (3)

Se me ocurren dos cosas:

En primer lugar, según la hoja de datos, un ciclo de borrado y escritura tarda al menos 0,8 ms y hasta 2,6 ms. Dice que tiene una interrupción cada 1 ms, lo que puede conducir a una operación de escritura. He visto en el código que deshabilita las interrupciones para partes del borrado y para partes de la función de escritura. Pero aún puede obtener un intercalado divertido de las llamadas a funciones. ¿Tal vez ayuda cuando deshabilita las interrupciones para toda la secuencia de borrado y escritura?

En segundo lugar, es posible que desee escribir mientras se corta la energía, y la escritura de EEPROM ocurre exactamente en el momento en que el voltaje de suministro cae por debajo del voltaje de funcionamiento. Puede intentar monitorear el voltaje de suministro y rechazar una escritura cuando está por debajo de, digamos, 4.5V. Esto supone que permanece el tiempo suficiente por encima de 2,7 V como voltaje mínimo de funcionamiento, y la detección de caída de voltaje está configurada para activarse solo por debajo de ese punto.

¡Usted está cerca! El ciclo es borrar->escribir, por lo que si se produce un apagado entre borrar y escribir, perderá sus datos. Mi primera solución fue dividir la EEPROM en varias copias redundantes, que se verifican automáticamente en busca de inconsistencias. Pero como eso consumió 3/4 de mi EEPROM, lo estoy reemplazando con un simple búfer de escritura. El búfer será un bloque EEPROM especial que contiene los datos que se escribirán, la dirección en la que se escribirá y una bandera que indica que la escritura aún no se ha completado. Esto debería solucionar el problema mientras ocupa mucho menos espacio.
Ahora puedo confirmar que mi enfoque basado en búfer funciona y no sufre pérdida de datos debido a un apagado asíncrono entre el borrado y la escritura.

Has analizado muchos posibles problemas de hardware. Está bien, pero lo más probable es que se trate de un error de firmware.

Desafortunadamente, su código fuente está mal documentado y está formateado para que sea difícil de seguir visualmente. Su primer archivo contiene declaraciones de rutinas externas en la parte superior:

void readEEByte(int sin firmar, int sin firmar, void*);
void eraseEEWord(int sin firmar, int sin firmar);
void writeEEWord(int sin firmar, int sin firmar, void*);

No solo es una mala idea poner declaraciones como esta en privado en los módulos del cliente, ¡no hay ni un solo comentario a la vista! Solo podemos adivinar lo que pretende que hagan estas rutinas a partir de su nombre, y los argumentos de llamada están completamente sin documentar. Más adelante en ese archivo, tiene varias líneas que comienzan con "//" y una línea completa de signos iguales. Estos agregan desorden visual, lo que hace que sea demasiado difícil tratar de seguir el código.

Puedes decir que nada de esto importa para el funcionamiento del código. Sin embargo, las malas prácticas de programación como esta sí importan mucho. Hacen que el código se escriba mal y dificultan la detección de errores o incluso lo que se supone que debe hacer el código. Todo esto da como resultado que acechen problemas difíciles de encontrar, como vas descubriendo. Usted mismo incluso dijo que ocasionalmente ha visto fallas en este código desde 2007. Eso debería haber sido una fuerte pista de un error, posiblemente incluso de un mal diseño general.

Solucione el desorden, documente correctamente todas las interfaces y coloque declaraciones comunes en archivos de inclusión que escriba una vez y luego haga referencia cuando sea necesario. Además, su declaración de que no tengo advertencias de compilación que parecen relevantes es una gran señal de alerta. De nuevo, arregla el desorden. Al depurar, busque siempre primero los problemas fácilmente reproducibles y reparables. A veces, esos son en realidad la causa de los problemas difíciles, o, a veces, al solucionarlos, descubre la causa de otros problemas. El compilador le está advirtiendo sobre el descuido en bandeja de plata. ¿Qué más quieres? No debe tener variables sin usar porque causan confusión a cualquiera que intente dar sentido a su código, y no hay ninguna excusa para perder nuevas líneas. Una vez más, arréglelos, especialmente antes de pedirle a alguien más que mire su código.

La pulcritud y la atención al detalle importan . Un montón.

 

Tienes toda la razón sobre el código. Para que quede claro, comencé a usar este código hace cinco años, pero alguien más lo escribió. No escribo cosas que se parezcan a esto. Todavía debería arreglarlo, y no es bueno que no lo haya hecho. Solo para no parecer un tonto tan grande. :-)
Acceder a la EEPROM interna es fácil. Para cosas tan simples, es más fácil escribir su propio código que tratar de descubrir cómo funciona el software de errores de otra persona y luego parchearlo hasta que parezca funcionar. Lea la hoja de datos y escriba el código. Estarías listo en una hora.
Estoy de acuerdo con Olin en que lo más probable es que sea firmware. La fe de erratas menciona que nada es sospechoso con la EEPROM.
@Madmad - Es posible que las hojas de erratas no digan que hay algo sospechoso en la parte, pero nunca dirán que no hay nada sospechoso en ella :-)
@Remiel: El soporte técnico probablemente no quería meterse en un código mal documentado y desordenado más que yo. Cuando haces una presentación descuidada, la discusión (si es que la hay) se vuelve sobre el descuido y tu punto original es secuestrado. Es difícil recuperarse incluso si finalmente lo arregla porque la gente ya se habrá desconectado de usted para entonces. Además, discutir sobre la falla del chip no lo ayudará a encontrar su error ni hará nada para que la gente lo tome en serio.
@stevenvh Mis tratos con Microchip y sus FAE han sido en su mayoría positivos. Las erratas de las piezas que he estado usando han sido precisas y han intervenido para ayudarnos con los problemas, a menudo encontrando soluciones para nosotros.

Tuve un comportamiento idéntico con 4 unidades de dsPIC30F6014A (de aproximadamente 10 utilizadas en los últimos meses), la única forma de evitar la corrupción esporádica de datos durante el apagado es establecer en cero el MCLR justo antes del apagado.

Obviamente, esto no es factible en la práctica, así que opté por el reemplazo del dsPIC "malo", si alguien tiene otra solución en su lugar ...

¿Por qué no sería eso factible? La detección de cortes de energía se realiza mucho, incluso para guardar datos en EEPROM en el último ms.