PIC24 DATA EEPROM Emulation __builtin_tblpage Fehler

Ich verwende den PIC24fj256ga702-Controller in meinem Projekt. Ich wollte einige Byte-Daten in einem nichtflüchtigen Speicher speichern, falls es zu einem Stromausfall kommt.

Also habe ich einige Funktionen nach http://microchipdeveloper.com/16bit:flash-write geschrieben

#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;
    }
}

aber ich erhalte diesen Fehler, wenn ich versuche, es zu erstellen

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)

Wird es dadurch behoben?

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

und Übergabe von &Adresse an __builtin_tblpage ?

aber das space-Attribut wird verwendet, um den Compiler anzuweisen, eine Variable in bestimmten Speicherbereichen zuzuweisen, also kann das nicht korrekt sein?

Ich brauche hier wirklich etwas Hilfe.

Danke

PS auch, kannst du bitte den Code sehen und mir sagen, was ich falsch mache

Sie versuchen, Speicher zu verwenden, der nicht vorhanden ist. Es gibt nur Flash unter der Adresse 0x2AFFE und Sie versuchen, auf 0x2B002 zuzugreifen. Datenblatt Seite 42.
Ich dachte, die oberste Grenze des Programmspeichers sei 0x2AFFE, und nach dieser Adresse bis 0x7FFFFF könnte EEPROM emuliert werden.
Nein. An Adressen zwischen 0x2AFFE und 0x800000 ist auf Ihrem Gerät kein Speicher jeglicher Art implementiert - deshalb gibt das Datenblatt für diesen Bereich "Unimplemented Read '0'" an. Wenn Sie Flash verwenden möchten, um EEPROM zu emulieren, müssen Sie Flash im Bereich „User Flash Program Memory“ zwischen 0x00000 und 0x2AFFE verwenden.
oh, was ist, wenn ich die seite überschreibe, auf der das programm steht? das sagt mir pickit, wenn ich meinen controller mit einer früheren version programmiere... Folgende speicherbereiche werden programmiert: programmspeicher: startadresse = 0x0, endadresse = 0x23ff programmierung/überprüfung abgeschlossen
Wenn ich dieses Array deklariere und die Adresse des ersten Speicherorts übergebe, wird das Projekt erstellt ... ist dies der richtige Weg? const unsigned int __ attribute __ ((space(prog), address (0x6000))) table[10];
Ich habe meine Kommentare unten in eine Antwort umgewandelt.

Antworten (2)

Sie versuchen, Speicher zu verwenden, der nicht vorhanden ist.
Es gibt nur Flash unter der Adresse 0x2AFFE und Sie versuchen, auf 0x2B002 zuzugreifen.
Siehe Datenblatt Seite 42.
An Adressen zwischen 0x2AFFE und 0x800000 ist auf Ihrem Gerät kein Speicher implementiert - deshalb gibt das Datenblatt für diesen Bereich "Unimplemented Read '0'" an.
Wenn Sie Flash verwenden möchten, um EEPROM zu emulieren, müssen Sie Flash im Bereich „User Flash Program Memory“ zwischen 0x00000 und 0x2AFFE verwenden.

const unsigned int attribute ((space(prog), address (0x6000))) table[10];
ist ein durchaus akzeptabler Weg, dies zu tun.
Sie lassen den Compiler diesen Speicherblock Ihrem Array zuweisen, damit dort kein Code abgelegt wird, sodass Sie ihn sicher verwenden können.
Sie müssen jedoch sicher sein, dass die Adresse und Größe, die Sie für Ihr Array angeben, mit genau einem oder mehreren der "Löschblöcke" im Flash Ihres PIC übereinstimmt.
Das Datenblatt sagt Ihnen, dass der 0x2B000-Bereich in 172 Blöcke aufgeteilt ist, also 0x400 pro Block. Ihre Array-Startadresse und -Größe müssen ein Vielfaches dieses Werts sein, daher sollten Sie für Ihren Fall die Größe Ihres Arrays ändern.
Wenn Ihr Array einen oder mehrere Blöcke nicht genau ausfüllt, kann der Compiler den Rest eines Blocks für Code verwenden. Da der PIC jedoch einen ganzen Block löscht, wenn dies für Ihre EEPROM-Emulation erforderlich ist, würde dies dazu führen in einigen Code wird auch gelöscht.

Danke, das hat das Problem behoben, aber jetzt, wenn ich versuche, den Speicher zu lesen, nachdem ich ihn geschrieben habe, bekomme ich nur Einsen. schreibe ich es vielleicht falsch, oder lese ich es falsch?

Es scheint, dass die Variable, die Sie an __builtin_tblpage-Makros übergeben, ein Byte (Bit) ist, während Sie ein kurzes (16 Bit) übergeben müssen.

Ich verwende diese Funktion für Microchip, um den PIC24EP-Mikrochip zu schreiben / zu lesen, sie sollten für Sie ziemlich ähnlich sein.

/*********************************************************************
 * 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;
}

Und ich benutze sie wie:

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();
    }
}

Und

#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;
}

Sie können einfach eine Struktur Ihrer Daten erstellen und einen Zeiger auf diese Funktionen senden.


Notiz:

  • Sie können kein Flash schreiben, ohne zuerst eine ganze Seite zu löschen. Es würde entweder fehlschlagen oder die Daten wären beschädigt.
  • Sie müssen ausgerichtet in eine Seite schreiben.