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:
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.
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.
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.
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 ...
Esteban Collings