No se pueden usar las funciones integradas del compilador para escribir en la EEPROM de dsPIC

Como mencioné aquí , he tenido problemas con la EEPROM en dsPIC30F6012A . Dado que mi antigua biblioteca EEPROM era difícil de analizar y admitir, volví al punto de partida y la reescribí usando las nuevas rutinas integradas de EEPROM del compilador C30 (¡más nuevas que mi biblioteca!). Tomé el código de demostración de Microchip e intenté ejecutarlo. Compilado, programado, sin problemas, pero no parecía funcionar correctamente. Hice una versión modificada de su demo, también sin éxito.

Ejecuto este programa, leo el contenido del chip en MPLAB X y observo el contenido de la EEPROM. Las operaciones de borrado funcionan correctamente, cualquier dirección que borre vuelve como 0xFFFF. Pero las operaciones de escritura no hacen nada. Probé varias combinaciones, escrituras repetidas, diferentes direcciones, nada parece estar escrito.

#include <p30fxxxx.h>
#include <libpic30.h>

 _FOSC(CSW_FSCM_OFF & FRC_PLL16); 
_FWDT(WDT_OFF);                 /* Turn off the Watch-Dog Timer.  */
_FBORPOR(MCLR_EN & PWRT_OFF);   /* Enable MCLR reset pin and turn off the power-up timers. */
_FGS(CODE_PROT_OFF);            /* Disable Code Protection */

 typedef struct _eestruct {
    unsigned char testdata[10];
} eestruct;
 eestruct eedata __attribute__((space(eedata)));
 eestruct backup_eedata __attribute__((space(eedata)));

 int main(){

    _prog_addressT EE_addr;
    //_init_prog_address(EE_addr, eedata);
    EE_addr = 0x7FF000;

    int temp_word = 0x0102;
    _erase_eedata(EE_addr, _EE_WORD);
    _wait_eedata();
    _write_eedata_word(EE_addr, temp_word);
    _wait_eedata();

    while(1){
    ClrWdt();
    };
    return 0;
}

Tengo cuatro teorías:

  1. Se están realizando escrituras y no estoy leyendo los datos correctamente.
  2. No se están realizando escrituras, porque algo anda mal con mi código.
  3. No se están realizando escrituras porque algo está mal con mis opciones de proyecto/compilación.
  4. No se están realizando escrituras porque algo anda mal con mi hardware.

He publicado en los foros de Microchip sin resultado. Abrí un ticket con Microchip, y lo único que hicieron fue decirme que usara/escribiera una convocatoria de asamblea. Parecen desinteresados ​​en si/por qué estas llamadas a funciones integradas no funcionan.

¿Alguien tiene alguna sugerencia?

¿Cuál es el dispositivo?
@LeonHeller De la pregunta mencionada anteriormente, es undsPIC30F6012a
Correcto, añadiendo a la pregunta.
¿MPLAB X lee la EEPROM como se esperaba? Tengo algunas teorías propias. (1) No compatible. (2) No vuelve a leer hasta que se lo indiques en el menú. (3) No se vuelve a leer correctamente. Esta es toda la experiencia MPLAB original. Es posible que MPLAB X haya solucionado todo esto. En caso de duda, hago que el PIC me informe sobre su contenido de EEPROM (algún tipo de rutina de volcado).
Los datos con los que inicializo la EEPROM se leen correctamente en MPLAB X, y los valores borrados se leen como 0xFFFF. Todo parece funcionar EXCEPTO la escritura.

Respuestas (2)

En caso de duda, refactorice.

No es probable que sea un problema de hardware, pero para descartarlo, intentaría reemplazar las llamadas C con las instrucciones de ensamblaje en línea exactas descritas en la sección 7 de la hoja de datos, siguiendo todas sus recomendaciones (deshabilitar interrupciones, sondear WR para probar si está listo, etc.)

Si lo hace funcionar, cree su propia función/biblioteca a partir del ensamblado en línea y continúe.

Desafortunadamente, ¡eso es lo que tenía que estoy tratando de refactorizar!
Debería publicar algo en los foros de Microchip o ponerse en contacto con un FAE si el código publicado en la hoja de datos no funciona.
Ya publicado en los foros, y abierto un ticket. No hay respuesta a ninguno de los dos.
¿Podría publicar su archivo de desmontaje/listado también?
Sorprendentemente, la respuesta del soporte técnico de Microchip también fue reemplazar las llamadas a funciones del compilador con código ensamblador. Cuando pregunté por qué las funciones no funcionaban, no respondieron y se negaron incluso a probar mi código. Aparentemente, a pesar de que las funciones que estoy usando están enumeradas en la documentación del compilador, y aunque Microchip publica un código de demostración usándolas en su sitio, las funciones en realidad no son compatibles con Microchip.

En primer lugar, una buena manera de comprobar si la EEPROM se ha escrito correctamente es volver a leerla a través de la ventana PSV (Program Space Visibility). En muchos casos no necesito la ventana PSV para nada más, así que la dejo permanentemente configurada para acceder a la EEPROM.

En segundo lugar, no miré su código C, pero aquí hay un fragmento de un proyecto 30F4013 que configura la ventana PSV para leer y escribe un byte en la EEPROM:

;**************************************************** ****************************
;
; Subrutina IEE_INIT
;
; Inicializa el estado del hardware y software gestionado por este módulo.
;
         glbsub iee_initregf0
;
; Configure la ventana de visibilidad del espacio del programa para mapear la EEPROM de datos internos
; al espacio de datos.
;
         mov #psvpage(ieestart), w0
         mov w0, Psvpag; qué región de la memoria de programación asignar a los datos adr 8000-FFFF
         bset Corcon, #Psv ;habilitar la ventana de visibilidad del espacio del programa

         descansar

;**************************************************** ****************************
;
; Macro ESPERAR_EEPROM
;
; Espere a que se complete cualquier operación anterior de EEPROM. TASK_YIELD se llama en
; un bucle durante la duración de la espera. TASK_YIELD no se llama si la EEPROM
; no está activo en la entrada.
;
.macro esperar_eeprom
1: ;Vuelva aquí para comprobar que la EEPROM está ocupada de nuevo
         btss Nvmcon, #Wr ;¿La EEPROM está ocupada?
         saltar 2f ;no, todo hecho
         gcall task_yield; dar a otras tareas la oportunidad de ejecutarse
         salta 1b; vuelve a comprobar que la EEPROM está ocupada de nuevo
2: ;la EEPROM ahora está inactiva
         .endm

;**************************************************** ****************************
;
; Subrutina IEE_WRITE
;
; Escriba el valor en W0 en la palabra EEPROM en el desplazamiento en W1. W1 debe
; contener los 16 bits bajos de la ubicación de la EEPROM como se mapea en el programa
; memoria. Esto se puede encontrar, por ejemplo, usando la función TBLOFFSET en
; cualquiera de los símbolos de dirección definidos en la sección .EEPROM anterior. Ya que hay
; son dos direcciones por palabra EEPROM y siempre se escribe una palabra completa, la
; bit bajo de W1 es irrelevante.
;
; W1 se devuelve incrementado en 2, que es la dirección de la siguiente EEPROM
; palabra. Llamadas sucesivas a esta rutina sin modificar W1 por lo tanto
; establecer palabras secuenciales de EEPROM.
;
; Esta rutina regresa después de que se haya completado la escritura. Esto puede tomar varios
; milisegundos. TASK_YIELD se llama en un bucle durante cualquier espera.
;
; Este procesador tiene 512 palabras de EEPROM.
;
         glbsub iee_write, regf2

         wait_eeprom; esperar a que se complete cualquier operación anterior
;
; Obtenga el valor actual de la palabra objetivo de la EEPROM en W2.
;
         mov #tblpage(ieestart), w2
         mov w2, Tblpag ;seleccione la página de memoria del programa para acceder
         tblrdl [w1], w2 ;leer la palabra EEPROM de destino
         cp w0, w2 ;comparar el nuevo valor con el existente
         bra z, iew_leave ;sin cambios, nada que hacer ?
;
; Borre la palabra EEPROM si algún bit 0 se cambia a 1 bit. El
; el valor existente de la palabra está en W2. TBLPAG ya está configurado adecuadamente para
; la dirección de la EEPROM.
;
         com w2, w2 ;hacer máscara de bits actualmente establecida en 0
         y w2, w0, w2 ;hacer máscara de 0 bits para cambiar a 1
         bra z, iew_derase; no hay 1 bits que cambien a 0, omita el borrado
         ;
         ; Realiza el borrado.
         ;
         ; De acuerdo con el manual de referencia familiar, para realizar un borrado
         ; necesita configurar la dirección y luego borrar una palabra. Sin embargo, tenemos
         ; encontré que esto no funciona para el primer intento de escritura desde el inicio.
         ; Después de un poco de experimentación, se descubrió que cargar un pestillo de escritura
         ; una vez parece ser lo que permite que los borrados funcionen. Por lo tanto, cargamos el
         ; escriba pestillo antes de hacer un borrado, aunque esto no es necesario
         ; según la documentación. Desde que se cargó el pestillo de escritura para
         ; la palabra para borrar también establece la dirección, no necesitamos configurar
         ; NVMADR explícitamente. Los datos escritos en el pestillo de escritura probablemente
         ; no importa, pero escribimos el valor de borrado ya que eso hace que el
         ; más sentido y tiene la mejor oportunidad de trabajar en torno a cualquier adicional
         ; comportamiento no documentado.
         ;
         movimiento #0xFFFF, w2
         tblwtl w2, [w1] ;cargar pestillo con el valor de borrado, establecer dirección

         movimiento #0b0100000001000100, w2
                 ; 0--------------- no iniciar la operación ahora
                 ; -1-------------- habilitar la operación de borrado
                 ; --0------------- borra cualquier condición de error anterior
                 ; ---XXXXX-------- sin usar
                 ; --------0100---- seleccionar borrar operación
                 ; ------------0100 una palabra de datos
         mov w2, Nvmcon ;configure para la operación de borrado

         disi #5; deshabilitar interrupciones alrededor de la secuencia de desbloqueo
         mov #0x55, w2 ;realizar secuencia de desbloqueo
         mov w2, tecla Nvm
         movimiento #0xAA, w2
         mov w2, tecla Nvm
         bset Nvmcon, #Wr ;iniciar el borrado

         wait_eeprom; esperar a que se complete el borrado
iew_derase: ;hecho de borrar la palabra
;
; Escribe la palabra.
;
         tblwtl w0, [w1] ;escriba la palabra, incremente la dirección

         movimiento #0b0100000000000100, w2
                 ; 0--------------- no iniciar la operación ahora
                 ; -1-------------- habilitar la operación de borrado
                 ; --0------------- borra cualquier condición de error anterior
                 ; ---XXXXX-------- sin usar
                 ; --------0000---- seleccionar operación de escritura
                 ; ------------0100 una palabra de datos
         mov w2, Nvmcon ;configure para la operación de borrado

         disi #5; deshabilitar interrupciones alrededor de la secuencia de desbloqueo
         mov #0x55, w2 ;realizar secuencia de desbloqueo
         mov w2, tecla Nvm
         movimiento #0xAA, w2
         mov w2, tecla Nvm
         bset Nvmcon, #Wr ;iniciar el borrado

         wait_eeprom; esperar a que se complete la escritura

iew_leave: ;punto de salida común
         agregue w1, #2, w1; incremente la dirección a la siguiente palabra EEPROM

         descansar

Tenga en cuenta que esta rutina hace algunas cosas buenas más allá de simplemente escribir a ciegas los nuevos datos en la EEPROM. No hace nada si la palabra EEPROM ya está configurada como se desea, y también omite el borrado si solo 1 bit se cambia a 0. Esto desgastará menos la EEPROM, especialmente si algún otro código entra accidentalmente en un bucle escribiendo en EEPROM. .