PIC16F EEPROM escribe errores

3

Estoy desarrollando un PIC16F1936 utilizando el IDL MPLAB X con el compilador XC8. Me han asignado este proyecto en el que necesito "actualizar" el software de una PCB para que pueda interactuar con una herramienta externa a través de un enlace RS232.

Tengo el enlace en funcionamiento y también he comprobado que la fecha de transmisión es correcta. El problema que tengo es con una función específica que calibra los puntos de ajuste para la PCB. No puedo decir mucho sobre cuál es la función exacta de la PCB, así que lo siento por no publicar todo. Además, he heredado mucho de este código en este proyecto, como el código que estoy a punto de mostrarle.

Entonces, la función de calibración funciona así: se llama una vez que la herramienta envía el comando relevante a la PCB. Después de esto (según el comando enviado), la función leerá el valor del valor sumado de 40 valores del ADC y lo guardará en la EEPROM. ¡Aquí es donde realmente se desordena! La calibración funciona perfectamente bien cuando tengo que poner a cero el PCB, el problema surge cuando tengo que configurar MAX. Oh! Y el código es idéntico, aparte de la dirección EEPROM ...

Aquí está el código para la calibración:

if (zero == 1)
{
    WR = 1;                                         // Set EEPROM_WRITE flag
    EEPROM_WRITE(0x05,(AN1_sum >> 0x08));           // load MSbyte of AN1_sum into NV memory location 1
    EEPROM_WRITE(0x06,(AN1_sum & 0xff));            // load LSbyte of AN1_sum into NV memory location 2
    EEPROM_WRITE(0x07,(AN4_sum >> 0x08));           // load MSbyte of AN4_sum into NV memory location 3
    EEPROM_WRITE(0x08,(AN4_sum & 0xff));            // load LSbyte of AN4_sum into NV memory location 4

    zero1 = AN1_sum;                                // update volatile memory for zero1
    zero4 = AN4_sum;                                // update volatile memory for zero4
    WR = 1;                                         //Set EEPROM_WRITE flag
    EEPROM_WRITE(0x09, 2);                          //Write 2 to the EEPORM

    while(WR){                                      //Loop till WR flag is reset by EEPROM CONTROLLER
        MAL = 1;                                        //Light MAL until WR is reset
    }
    for(KILLTIME = 0; KILLTIME <= 200000; KILLTIME++);
    RESET();
    for(KILLTIME = 0; KILLTIME <= 200000; KILLTIME++);
}
else if (MAX == 1)
{
    WR = 1;                                         //Set EEPROM_WRITE flag
    EEPROM_WRITE(0x01,(AN1_sum >> 0x08));           // load MSbyte of AN1_sum into NV memory location 5
    EEPROM_WRITE(0x02,(AN1_sum & 0xff));            // load LSbyte of AN1_sum into NV memory location 6
    WR = 1;                                         //Set EEPROM_WRITE flag
    EEPROM_WRITE(0x03,(AN4_sum >> 0x08));           // load MSbyte of AN4_sum into NV memory location 7
    EEPROM_WRITE(0x04,(AN4_sum & 0xff));            // load LSbyte of AN4_sum into NV memory location 8

    MAX1 = AN1_sum;                                 // update volatile memory for MAX1
    MAX4 = AN4_sum;                                 // update volatile memory for MAX4

    WR = 1;                                         //Set EEPROM_WRITE flag
    EEPROM_WRITE(0x9, 3);                           //Write 3 to the EEPROM

    while(WR){                                      //Loop till WR flag is reset by EEPROM CONTROLLER
        MAL = 1;                                        //Light MAL until WR is reset
    }
    for(KILLTIME = 0; KILLTIME <= 200000; KILLTIME++);
    RESET();
    for(KILLTIME = 0; KILLTIME <= 200000; KILLTIME++);
}

Después del reinicio, la PCB se reinicia y pasa por este proceso de inicialización:

MAX1 = EEPROM_READ(0x01);                                               
MAX1 = (MAX1 << 8) + EEPROM_READ(0x02);
MAX4 = EEPROM_READ(0x03);                                 
MAX4 = (MAX4 << 8) + EEPROM_READ(0x04); 
zero1 = EEPROM_READ(0x05);                                           
zero1 = (zero1 << 8) + EEPROM_READ(0x06);                          
zero4 = EEPROM_READ(0x07);                                 
zero4 = (zero4 << 8) + EEPROM_READ(0x08); 

Suficientemente simple ¿verdad? Este es solo el tiempo en el código donde se configuran MAX y cero.

No tengo idea de por qué esto no funciona. MAX debería ser el valor que AN1 y AN4 tengan en el momento de la ejecución. He cambiado las direcciones de la EEPROM y he cambiado el nombre de las variables para asegurarme de que MAX y ZERO no se sobrescriban en ninguna otra parte del código. Sin resultado. MAX solo quiere ser el valor correcto cuando digo MAX1 = x y MAX 4 = y. No puede ser algo con los valores de AN1 y AN4, ya que funcionan bien para TARE sin importar cuál sea su valor.

¿Alguna idea?

Solo para agregar, he probado las siguientes soluciones:

  1. Cambié las direcciones EEPROM de manera que MAX las escriba en las direcciones. Quiero decir que MAX ahora se escribe en 0x05-0x08 y ZERO se escribe en 0x01-0x05. Todavía tengo el mismo problema. El valor del sensor se escribe correctamente en CERO pero no en MAX.

  2. He jugado un poco con la bandera WR colocando más y eliminándolos por completo. NO HAY CAMBIO.

  3. He intentado almacenar los valores de AN1_sum y AN4_sum en una variable temporal tan pronto como se inicia la función de calibración y, en su lugar, he utilizado esas variables.

  4. He intentado revertir los roles de ZERO y MAX. Con esto quiero decir que establezco CERO en el punto de ajuste máximo y MAX en el mínimo. Encontré que CERO establece con precisión y el valor que tiene puede afectar el valor de MAX. Por ejemplo, primero establecí la aplicación 45 en ambos canales y luego configuré el MAX. Después de la calibración, MAX tenía un valor de 26. Luego apliqué 198 a ambos canales y configuré CERO. ¡CERO mantuvo un valor final de 198, mientras que MAX cambió a 48!

Hace tiempo que sé que MAX es el culpable, pero no sé por qué o cómo está sucediendo esto. He revisado el resto del código y he comprobado si MAX está siendo afectado de alguna manera, pero no lo está.

    
pregunta user1651453

2 respuestas

1

Parece que no tienes el soporte adecuado de depuración adecuado, lo que dificulta innecesariamente tu trabajo.

Además, mencionas varias veces "El problema", pero nunca nos dices específicamente qué síntomas observas, lo que nos dificulta poder ayudarte. ¿Se apagó un LED cuando esperaba que parpadeara (o viceversa)? ¿Una pantalla de dígitos de 7 segmentos no muestra el número que esperaba?

Si yo fuera tú,

  1. Leería la hoja de datos para el procesador que estoy usando, en en particular la sección "Uso de la EEPROM de datos" página 116-117. Parece decir que se establece el bit WR después de configurar la dirección EEPROM y los registros de datos, por lo que la línea "WR = 1;" al principio de una sección de código parece fuera de lugar.

  2. Leería las preguntas frecuentes: "¿Cómo escribo y leo datos de EEPROM utilizando el compilador XC8?"

  3. Leería la Guía del usuario para el compilador - "Compilador MPLAB XC8 C Guía del usuario ", en particular la sección" Funciones de acceso a la EEPROM "en la página 108.

  4. Cuando tengo 2 trozos de código que hacen casi lo mismo, trato de refactorizarlos, así que tengo 1 función que hace todas las cosas comunes, y la llamo desde 2 lugares. En este caso, tiene (al menos) 4 ubicaciones que escriben un valor de 16 bits en la EEPROM, por lo que podría refactorizar las 4 para que llamen algo como:

    void EEPROM_WRITE_16( char address, int value ){
        char MSByte = (value >> 0x08) & 0xff;
        char LSByte = value & 0xff;
        if(eeprom_read(address) != MSByte){
            eeprom_write(address, MSByte); // load MSbyte into given EEPROM address
        };
        address++;
        if(eeprom_read(address) != LSByte){
            eeprom_write(address, LSByte); // load LSbyte into following EEPROM address
        };
    }
    
  5. Siempre que hago cosas con EEPROM, agrego algunas rutinas de "depuración" en el firmware para leer el contenido de la EEPROM y enviarlas a algún lugar donde un humano pueda leerlas, tal vez a un puerto de depuración UART o , si hay uno disponible, una pantalla LCD o LED; quizás incondicionalmente, brevemente en encendido.

  6. A veces, al depurar problemas difíciles, agrego comandos de "depuración" adicionales para escribir nuevos valores en EEPROM. Si esas funciones llaman a la misma (s) rutina (s) que uso en otros lugares para escribir en EEPROM, entonces puedo probar esas rutinas más o menos de forma aislada.

  7. A veces hago una copia de seguridad del programa principal y lo aparto, y creo un nuevo programa de prueba que comienza como una copia exacta del programa principal. Mientras el programa de prueba muestre los síntomas inesperados del problema, sigo eliminando las funciones que pienso no tienen relación con el problema, hasta que termine con un SSCCE - Short, Autocontenido, compilable, Ejemplo . Luego publico ese breve programa de prueba cuando pido ayuda. Un programa de este tipo generalmente recibe una respuesta mucho más rápido que (a) publicando el programa extremadamente largo o original, o (b) publicando solo fragmentos del programa completo que pienso están relacionados con el problema.

Los últimos 3 pasos (andamiaje de depuración adicional y SSCCE) facilitan la prueba rápida de varias soluciones propuestas y ver si realmente funcionarán para mi código. (Sugerencias como "bucle hasta que se complete la escritura anterior antes de comenzar una nueva lectura" (a) y la página 108 del "Compilador MPLAB XC8 C Guía del usuario "; 'asegúrese de que el enlazador esté configurado en "Vincular la biblioteca de periféricos"' (b) ; '[reemplazar] las llamadas de C con las instrucciones de ensamblaje en línea exactas descritas en ... la hoja de datos' (c) ; etc.).

¡Buena suerte!

    
respondido por el davidcary
0

Intente convertir el segundo argumento de EEPROM_WRITE () al tipo correcto. EEPROM se organiza en ubicaciones de memoria de 8 bits y, al parecer, al hacer (AN4_sum & 0xff) está intentando enmascarar los 8 bits más bajos de un entero (o un tipo más grande), pero el tipo de paso pasado permanece igual y el comportamiento De esta función puede ser impredecible. Siempre me ha resultado útil al aplicar máscaras para escribirlas en toda la longitud de la variable que estoy intentando enmascarar, es decir (AN4_sum & 0x00ff) para que siempre esté claro qué está pasando, especialmente si está revisando el código mucho después. fue escrito. Espero que esto ayude un poco ...

    
respondido por el Guih

Lea otras preguntas en las etiquetas