PIC24 DATOS EEPROM Emulación __builtin_tblpage error

2

Estoy usando el controlador PIC24fj256ga702 en mi proyecto. Quería almacenar algunos datos de bytes en una memoria no volátil en caso de que hubiera una pérdida de energía.

así que escribí algunas funciones siguiendo enlace

#define pagelength 1024             //page 42, one erase block 1024 instruction words
#define rowlength 128               //one write block = 128 instruction words.
/*
 * program memory upper boundary (instruction words) 0x02AFFE,
 * +2, i.e. 0x02B000, start of address
 * page length 1024 instruction words(erase block)
 * write block 128 instruction block; 255 bytes.
 */
#define address 0x2B002             // might have less than 255 blocks for writing data

uint8_t Rambuffer[pagelength * 2];
uint8_t Rowbuffer[rowlength * 2];       //one row of data, that can be written once. 255 bytes.

void readFlashPage(void)
{
    int offset, i;
    TBLPAG = __builtin_tblpage (address);    //returns the page number of the memory address received as a parameter. For table instructions the returned value is placed in TBLPAG
    offset = __builtin_tbloffset (address);  //returns the offset from the base address for a memory location whose address is passed as a parameter. The return value of this function is passed as a parameter to table read and table write instructions
    offset = offset & 0xF800; //set to the base of page
    for(i = 0; i<(pagelength * 2); i++){
        Rambuffer[i++] = __builtin_tblrdl(offset);  //returns the lower 16 bits of the memory address specified by TBLPAG and the offset parameter(calls TBLRDL instruction)
        Rambuffer[i] = __builtin_tblrdh(offset);    //returns the upper 8-bits of the memory adddress specified by TBLPAG and the offset parameter(calls TBLRDL instruction)
        offset = offset + 2;
    }
}

void eraseFlashPage(void){
    int offset;
    NVMADRU = __builtin_tblpage(address);
    offset = __builtin_tbloffset(address);
    NVMADR = (offset & 0xF800); // for page size of 1024 PM words

    //set WREN and page Erase in NVMCON
    NVMCON = 0x4003;

    __builtin_disi(6);      //disable interrupts for next six instructions
    __builtin_write_NVM();  //intiate write process
}

void rowFlashWrite(void){
    int offset, i;
    TBLPAG = 0xFA;   // base address of write latches 0xFA0000h till 0xFA00FEh

    //load row of data into write latches
    offset = 0;
    for (i = 0; i < rowlength * 2 ; i++){
        __builtin_tblwtl(offset, Rowbuffer[i++]);
        __builtin_tblwth(offset, Rowbuffer[i]);
        offset+=2;
    }

    //set the destination address into the NVM address registers

    NVMADRU = __builtin_tblpage(address);
    offset = __builtin_tbloffset(address);
    NVMADR = (offset & 0xF800);   // for page size of 1024 PM words

    //set WREN and enable row write in NVMCON

    NVMCON = 0x4002;

    __builtin_disi(6); // disable interrupts for 6 instruction cycles
    __builtin_write_NVM(); // initate write process
}

void rowFlashRead(void){
    int offset, i;
    TBLPAG = __builtin_tblpage (address);    //returns the page number of the memory address received as a parameter. For table instructions the returned value is placed in TBLPAG
    offset = __builtin_tbloffset (address);  //returns the offset from the base address for a memory location whose address is passed as a parameter. The return value of this function is passed as a parameter to table read and table write instructions
    for(i = 0; i<(rowlength * 2); i++){
        Rowbuffer[i++] = __builtin_tblrdl(offset);  //returns the lower 16 bits of the memory address specified by TBLPAG and the offset parameter(calls TBLRDL instruction)
        Rowbuffer[i] = __builtin_tblrdh(offset);    //returns the upper 8-bits of the memory adddress specified by TBLPAG and the offset parameter(calls TBLRDL instruction)
        offset = offset + 2;
    }
}

pero recibo este error cuando intento compilarlo

make -f nbproject/Makefile-default.mk SUBPROJECTS= .build-conf
make[1]: Entering directory 'C:/Users/HP/MPLABXProjects/Rollman/emulate.X'
make  -f nbproject/Makefile-default.mk dist/default/production/emulate.X.production.hex
make[2]: Entering directory 'C:/Users/HP/MPLABXProjects/Rollman/emulate.X'
"C:\Program Files (x86)\Microchip\xc16\v1.35\bin\xc16-gcc.exe"   main.c  -o build/default/production/main.o  -c -mcpu=24FJ256GA702  -MMD -MF "build/default/production/main.o.d"      -mno-eds-warn  -g -omf=elf -DXPRJ_default=default  -legacy-libc    -O0 -msmart-io=1 -Wall -msfr-warn=off  
nbproject/Makefile-default.mk:155: recipe for target 'build/default/production/main.o' failed
make[2]: Leaving directory 'C:/Users/HP/MPLABXProjects/Rollman/emulate.X'
nbproject/Makefile-default.mk:90: recipe for target '.build-conf' failed
make[1]: Leaving directory 'C:/Users/HP/MPLABXProjects/Rollman/emulate.X'
nbproject/Makefile-impl.mk:39: recipe for target '.build-impl' failed
main.c: In function 'readFlashPage':
main.c:83:32: error: Argument to __builtin_tblpage() is not the address
of an object in a code, psv, or eedata section;
the object must not be qualified with any form of index
main.c:84:34: error: Argument to __builtin_tbloffset() is not the address
of an object in a code, psv, or eedata section;
the object must not be qualified with any form of index
main.c: In function 'eraseFlashPage':
main.c:95:32: error: Argument to __builtin_tblpage() is not the address
of an object in a code, psv, or eedata section;
the object must not be qualified with any form of index
main.c:96:33: error: Argument to __builtin_tbloffset() is not the address
of an object in a code, psv, or eedata section;
the object must not be qualified with any form of index
main.c: In function 'rowFlashWrite':
main.c:120:32: error: Argument to __builtin_tblpage() is not the address
of an object in a code, psv, or eedata section;
the object must not be qualified with any form of index
main.c:121:33: error: Argument to __builtin_tbloffset() is not the address
of an object in a code, psv, or eedata section;
the object must not be qualified with any form of index
main.c: In function 'rowFlashRead':
main.c:134:32: error: Argument to __builtin_tblpage() is not the address
of an object in a code, psv, or eedata section;
the object must not be qualified with any form of index
main.c:135:34: error: Argument to __builtin_tbloffset() is not the address
of an object in a code, psv, or eedata section;
the object must not be qualified with any form of index
make[2]: *** [build/default/production/main.o] Error 255
make[1]: *** [.build-conf] Error 2
make: *** [.build-impl] Error 2

BUILD FAILED (exit value 2, total time: 573ms)

¿Esto lo arreglará?

uint16_t address __attribute__ ((space(prog))) = 0x2B002;

y pasar & dirección a __builtin_tblpage?

pero el atributo de espacio se usa para dirigir al compilador a asignar una variable en espacios de memoria específicos, ¿por lo que esto no puede ser correcto?

Realmente necesito ayuda aquí.

Gracias

p.s. también, ¿puede ver el código y decirme qué podría estar haciendo mal?

    
pregunta aamir

2 respuestas

1

Estás intentando usar una memoria que no existe.
Solo hay Flash en la dirección 0x2AFFE y está intentando acceder a 0x2B002.
Consulte la Hoja de datos página 42.
No hay memoria de ningún tipo implementado en las direcciones entre 0x2AFFE y 0x800000 en su dispositivo, por eso la hoja de datos especifica "Lectura no implementada" 0 para ese rango.
Si desea utilizar algo de Flash para emular EEPROM, debe usar Flash en el área de 'Memoria de programa flash de usuario' entre 0x00000 y 0x2AFFE.

const unsigned int attribute ((space(prog), address (0x6000))) table[10];
Es una forma perfectamente aceptable de hacerlo.
Ha hecho que el compilador asigne ese bloque de memoria a su matriz para que no coloque ningún código allí, lo que hace que sea seguro para su uso. Sin embargo, debe asegurarse de que la dirección y el tamaño que especifique para su matriz se alineen exactamente con uno o más de los "Bloques de borrado" en el Flash de su PIC.
La hoja de datos le dice que el rango 0x2B000 se divide en 172 bloques, por lo que es 0x400 por bloque. Su dirección de inicio de matriz & tamaño debe ser un múltiplo de este valor, por lo que para su caso, debe cambiar el tamaño de su matriz.
Si su matriz no llena exactamente uno o más bloques, entonces el compilador es libre de usar el resto de un bloque para el código, pero como el PIC borrará un bloque completo cuando necesite hacerlo para su emulación EEPROM, esto resultaría en algunos códigos siendo borrados también.

    
respondido por el brhans
0

Parece que la variable que pasa a las macros __builtin_tblpage son un byte (bit), mientras que necesita pasar un corto (16bits)

Yo uso esta función para que Microchip escriba / lea microchip PIC24EP, deberían ser bastante similares para ti.

/*********************************************************************
 * Function:        unsigned int NVMErasePage(void* address)
 *
 * Description:     Block Erases Program Memory
 * PreCondition:    None
 *
 * Inputs:          address:  Destination page address to Erase.
 *
 * Output:          '0' if operation completed successfully.
 *
 * Example:         NVMemErasePage(UINT32 0xBD000000)
 ********************************************************************/
UINT NVMemBlockErase(void)
{

    NVMCON = 0x400D;                //Bulk erase on next WR
    INTCON2bits.GIE = 0;                            //Disable interrupts for next few instructions for unlock sequence
    __builtin_write_NVM();
    while(NVMCONbits.WR == 1){}
    INTCON2bits.GIE = 1;                            // Re-enable the interrupts (if required).


    // Return WRERR state.
    return NVMCONbits.WRERR;    
}   



/*********************************************************************
 * Function:        unsigned int NVMErasePage(void* address)
 *
 * Description:     A page erase will erase a single page of program flash,
 *                  which equates to 1k instructions (3KBytes). The page to
 *                  be erased is selected using NVMADDR. The lower bytes of
 *                  the address given by NVMADDR are ignored in page selection.
 *
 * PreCondition:    None
 *
 * Inputs:          address:  Destination page address to Erase.
 *
 * Output:          '0' if operation completed successfully.
 *
 * Example:         NVMemErasePage(UINT32 0xBD000000)
 ********************************************************************/
UINT NVMemErasePage(UINT32 address)
{
    DWORD_VAL eraseAddress;
    eraseAddress.Val = address;


    TBLPAG = eraseAddress.byte.UB;
    NVMADRU = eraseAddress.word.HW;
    NVMADR = eraseAddress.word.LW;
    __builtin_tblwtl(eraseAddress.word.LW, 0xFFFF);
    NVMCON = 0x4003;                //Erase page on next WR

    INTCON2bits.GIE = 0;                            //Disable interrupts for next few instructions for unlock sequence
    __builtin_write_NVM();
    while(NVMCONbits.WR == 1){}
    INTCON2bits.GIE = 1;                            // Re-enable the interrupts (if required).


    // Return WRERR state.
    return NVMCONbits.WRERR;

}


/*********************************************************************
 * Function:        unsigned int NVMWriteWord(UINT32 address, UINT32 data)
 *
 * Description:     The word at the location pointed to by NVMADDR is programmed.
 *
 * PreCondition:    None
 *
 * Inputs:          address:   Destination address to write.
 *                  data:      Word to write.
 *
 * Output:          '0' if operation completed successfully.
 *
 * Example:         NVMWriteWord(0xBD000000, 0x12345678)
 ********************************************************************/
UINT NVMemWriteWord(UINT32 address, UINT32 data)
{
    DWORD_VAL writeAddress;
    DWORD_VAL writeData;

    writeAddress.Val = address;
    writeData.Val = data;

    NVMCON = 0x4001;        //Perform WORD write next time WR gets set = 1.
    NVMADRU = writeAddress.word.HW;
    NVMADR = writeAddress.word.LW;

    // Set the table address of "Latch". The data is programmed into the FLASH from a temporary latch. 
    TBLPAG = 0xFA;
    //The smallest block of data that can be programmed in
    //a single operation is 2 instruction words (6 Bytes + 2 Phantom Bytes).
    // Mask the high or low instruction words depending on the address and write either high or low instruction word.
    if(address % 4)
    {
        __builtin_tblwtl(0, 0xFFFF);                //Mask the low word of 1-st instruction into the latch.
        __builtin_tblwth(1, 0x00FF);                //Mask the high word of 1-st instruction into the latch. (8 bits of data + 8 bits of "phantom data" (phantom byte is always 0))

        __builtin_tblwtl(2, writeData.word.LW);     //Write the low word of 2-nd instruction into the latch
        __builtin_tblwth(3, writeData.word.HW);     //Write the high word of 2-nd instruction into the latch        

    }
    else
    {
        __builtin_tblwtl(0, writeData.word.LW);     //Write the low word of 1-st instruction into the latch
        __builtin_tblwth(1, writeData.word.HW);     //Write the high word of 1-st instruction into the latch 
        __builtin_tblwtl(2, 0xFFFF);                //Mask the low word of 2-nd instruction into the latch.
        __builtin_tblwth(3, 0x00FF);                //Mask the high word of 2-nd instruction into the latch. (8 bits of data + 8 bits of "phantom data" (phantom byte is always 0))

    }       

    INTCON2bits.GIE = 0;                            //Disable interrupts for next few instructions for unlock sequence
    __builtin_write_NVM();
    while(NVMCONbits.WR == 1){}
    INTCON2bits.GIE = 1;                            // Re-enable the interrupts (if required).

    // Return WRERR state.
    return NVMCONbits.WRERR;
}

Y los uso como:

typedef short          Word16;
typedef unsigned short UWord16;
typedef long           Word32;
typedef unsigned long  UWord32;
typedef union tuReg32
{
    UWord32 Val32;

    struct
    {
        UWord16 LW;
        UWord16 HW;
    } Word;

    char Val[4];
} uReg32;

void WritePM(char *Data, uReg32 SourceAddr, unsigned int Size)
{
    unsigned int    j, i = 0;
        uReg32 data1;
        char ptrData[6];

    while (i < Size)
    {
        for (j=0; j <6;j++)
            ptrData[j] = Data[j+i];

        data1.Val[0] = ptrData[0];
        data1.Val[1] = ptrData[1];
        data1.Val[2] = ptrData[2];

        NVMemWriteWord((UINT32) SourceAddr.Val32, (UINT32) data1.Val32);

        SourceAddr.Val32 += 2;
        i += 3;

        ClrWdt();
    }
}

Y

#define CONFIG_ADDR 0x7FF000

void WriteConf(char * ptr, unsigned int size)
{
    uReg32 Addr;

    Addr.Val32 = CONFIG_ADDR;

    _IPL = 7;
    Erase(Addr.Word.HW, Addr.Word.LW,PM_ROW_ERASE);
    _IPL = 0;

    WritePM( ptr, Addr, size);

}

void ReadConf(char * ptr, unsigned int size)
{
    uReg32 Addr;

    Addr.Val32 = CONFIG_ADDR;

    _IPL = 7;
    ReadPM(ptr, Addr, size);
    _IPL = 0;
}

Puede simplemente crear una estructura de sus datos y enviar un puntero a esas funciones.

Nota:

  • No puede escribir flash sin borrar primero una página completa. Fallaría o los datos se corromperían.
  • Necesitas escribir alineado en una página.
respondido por el Damien

Lea otras preguntas en las etiquetas