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

1

Como mencioné aquí , he tenido problemas con EEPROM en dsPIC30F6012A . Como mi antigua biblioteca EEPROM era difícil de analizar y admitir, volví al punto uno y la reescribí utilizando las nuevas rutinas EEPROM incorporadas del compilador C30 (¡más nuevas que mi biblioteca!). Tomé el código de demostración de Microchip y traté de ejecutarlo. Compilado, programado, sin problemas, pero no parece 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 miro el contenido de EEPROM. Las operaciones de borrado funcionan correctamente, cualquier dirección que borre regresa como 0xFFFF. Pero las operaciones de escritura no hacen nada. He probado varias combinaciones, escrituras repetidas, direcciones diferentes, no parece que se haya escrito nada.

#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. Las escrituras no tienen lugar, porque algo está mal con mi código.
  3. Las escrituras no tienen lugar, porque algo está mal con Mis opciones de proyecto / compilación.
  4. Las escrituras no se llevan a cabo, porque hay algún problema con mi hardware.

He publicado en los foros de Microchip sin resultado. Abrí un boleto con Microchip, y todo lo que hicieron fue decirme que usara / escribiera una asamblea. No parecen interesados en si / por qué no funcionan estas llamadas a funciones integradas.

¿Alguien tiene alguna sugerencia?

    
pregunta Stephen Collings

2 respuestas

2

En caso de duda, refactor.

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 que se describen en la sección 7 de la hoja de datos, siguiendo todas sus recomendaciones (deshabilitar interrupciones, sondear WR para probar para cocer, etc.)

Si lo hace funcionar, cree su propia función / biblioteca desde el ensamblaje en línea y continúe.

    
respondido por el Adam Lawrence
0

En primer lugar, una buena manera de verificar si la EEPROM se ha escrito correctamente es volver a leerla a través de la ventana de Visibilidad del Espacio del Programa (PSV). En muchos casos no necesito la ventana de PSV para nada más, así que la dejo configurada permanentemente para el acceso a la EEPROM.

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

;*******************************************************************************
;
;   Subroutine IEE_INIT
;
;   Initialize the hardware and software state managed by this module.
;
         glbsub  iee_init, regf0
;
;   Set up the program space visibility window to map the internal data EEPROM
;   to data space.
;
         mov     #psvpage(ieestart), w0
         mov     w0, Psvpag  ;which region of prog memory to map to data adr 8000-FFFF
         bset    Corcon, #Psv ;enable program space visibility window

         leaverest

;*******************************************************************************
;
;   Macro WAIT_EEPROM
;
;   Wait for any previous EEPROM operation to complete.  TASK_YIELD is called in
;   a loop for the duration of the wait.  TASK_YIELD is not called if the EEPROM
;   is not active on entry.
;
.macro   wait_eeprom
1:                           ;back here to check EEPROM busy again
         btss    Nvmcon, #Wr ;EEPROM is busy ?
         jump    2f          ;no, all done
         gcall   task_yield  ;give other tasks a chance to run
         jump    1b          ;back to check EEPROM busy again
2:                           ;the EEPROM is now idle
         .endm

;*******************************************************************************
;
;   Subroutine IEE_WRITE
;
;   Write the value in W0 to the EEPROM word at the offset in W1.  W1 must
;   contain the low 16 bits of the EEPROM location as mapped into program
;   memory.  This can be found, for example, by using the TBLOFFSET function on
;   any of the address symbols defined in the .EEPROM section above.  Since there
;   are two addresses per EEPROM word and a whole word is always written, the
;   low bit of W1 is irrelevant.
;
;   W1 is returned incremented by 2, which is the address of the next EEPROM
;   word.  Successive calls to this routine without modifying W1 therefore
;   set sequential EEPROM words.
;
;   This routine returns after the write has completed.  This may take several
;   milliseconds.  TASK_YIELD is called in a loop during any waits.
;
;   This processor has 512 words of EEPROM.
;
         glbsub  iee_write, regf2

         wait_eeprom         ;wait for any previous operation to complete
;
;   Get the current EEPROM target word value into W2.
;
         mov     #tblpage(ieestart), w2
         mov     w2, Tblpag  ;select the program memory page to access
         tblrdl  [w1], w2    ;read the target EEPROM word
         cp      w0, w2      ;compare the new value to the existing
         bra     z, iew_leave ;no change, nothing to do ?
;
;   Erase the EEPROM word if any 0 bits are being changed to 1 bits.  The
;   existing value of the word is in W2.  TBLPAG is already set approriately for
;   the EEPROM address.
;
         com     w2, w2      ;make mask of bits currently set to 0
         and     w2, w0, w2  ;make mask of 0 bits to change to 1
         bra     z, iew_derase ;no 1 bits changing to 0, skip the erase
         ;
         ;   Perform the erase.
         ;
         ;   According to the family reference manual, to perform a erase you
         ;   need to set the address and then do a word erase.  However, we have
         ;   found this doesn't work for the first write attempt since startup.
         ;   After some experimentation it was found that loading a write latch
         ;   once seems to be what allows erases to work.  We therefore load the
         ;   write latch before doing a erase, even though this is not necessary
         ;   according to the documentation.  Since loading the write latch for
         ;   the word to erase also sets the address, we don't need to set
         ;   NVMADR explicitly.  The data written to the write latch probably
         ;   doesn't matter, but we write the erase value since that makes the
         ;   most sense and has the best chance of working around any additional
         ;   undocumented behavior.
         ;
         mov     #0xFFFF, w2
         tblwtl  w2, [w1]    ;load latch with the erase value, set address

         mov     #0b0100000001000100, w2
                 ;  0--------------- don't initiate operation now
                 ;  -1-------------- enable erase operation
                 ;  --0------------- clear any previous error condition
                 ;  ---XXXXX-------- unused
                 ;  --------0100---- select erase operation
                 ;  ------------0100 one data word
         mov     w2, Nvmcon  ;configure for the erase operation

         disi    #5          ;disable interrupts around unlock sequence
         mov     #0x55, w2   ;perform unlock sequence
         mov     w2, Nvmkey
         mov     #0xAA, w2
         mov     w2, Nvmkey
         bset    Nvmcon, #Wr ;start the erase

         wait_eeprom         ;wait for the erase to complete
iew_derase:                  ;done with erasing the word
;
;   Write the word.
;
         tblwtl  w0, [w1]    ;write the word, increment address

         mov     #0b0100000000000100, w2
                 ;  0--------------- don't initiate operation now
                 ;  -1-------------- enable erase operation
                 ;  --0------------- clear any previous error condition
                 ;  ---XXXXX-------- unused
                 ;  --------0000---- select write operation
                 ;  ------------0100 one data word
         mov     w2, Nvmcon  ;configure for the erase operation

         disi    #5          ;disable interrupts around unlock sequence
         mov     #0x55, w2   ;perform unlock sequence
         mov     w2, Nvmkey
         mov     #0xAA, w2
         mov     w2, Nvmkey
         bset    Nvmcon, #Wr ;start the erase

         wait_eeprom         ;wait for the write to complete

iew_leave:                   ;common exit point
         add     w1, #2, w1  ;increment address to the next EEPROM word

         leaverest

Tenga en cuenta que esta rutina hace algunas cosas agradables más allá de solo escribir ciegamente 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 invierte a 0. Esto desgastará menos la EEPROM, especialmente si algún otro código ingresa accidentalmente en un bucle al escribir en la EEPROM .

    
respondido por el Olin Lathrop

Lea otras preguntas en las etiquetas