PIC18 - Flash memory - erase

Thread Starter

bug13

Joined Feb 13, 2012
1,692
Hi guys

I am using PIC18F44J10, I need to use a block of flash memory to store some settings. First time ever to use flash in a pic to store data.

Here are the instruction from the datasheet: (P78)
Code:
1. Load Table Pointer register with address of the
block being erased.
2. Set the WREN and FREE bits (EECON1<2,4>)
to enable the erase operation.
3. Disable interrupts.
4. Write 55h to EECON2.
5. Write 0AAh to EECON2.
6. Set the WR bit. This will begin the erase cycle.
7. The CPU will stall for duration of the erase for
TIE (see parameter D133B).
8. Re-enable interrupts.
How do I work out the address of my block? As in my case, I am using PIC18F44J10, it has 16KB of flash, I just want to erase the last block (1024 bytes), so I don't accditantly erase amy part of my firmware. Can't find anything in the datasheet.
 

Thread Starter

bug13

Joined Feb 13, 2012
1,692
So I looked at the XC8 compiler user guild, here are what I found, not helping!!
Capture.PNG

Capture2.PNG
 

JohnInTX

Joined Jun 26, 2012
3,772
What it is telling you is to download the MPLABX Code Configurator. That actually works pretty well except that if your chip isn't supported by it, you're out of luck. The Flash routines used to be in the old Peripheral Library but that may or may not be compatible with XC8. I've written flash on several projects but all were coded in assembler.
If you can't get it with MCC, you could allocate a 1024 char const array @ the page address you want. See sec 5.5.4.2 in the XC8 user's guide.
5.5.4.2 ABSOLUTE OBJECTS IN PROGRAM MEMORY
Non-auto objects qualified const can also be made absolute in the same way,
however, the address will indicate an address in program memory. For example:
const int settings[] @ 0x200 = { 1, 5, 10, 50, 100 };
will place the array settings at address 0x200 in the program memory.
Both initialized and uninitialized const objects can be made absolute. That latter is
useful when you only need to define a label in program memory without making a
contribution to the output file.
Since reading/writing flash requires some specific instruction sequences to unlock the write logic, you'll probably have to do that in assembler. Before all of that, I'd send a ticket to Microchip support and ask them. C is supposed to make things easy..

EDIT: FWIW, I attached the library routine descriptions from HiTechC. Maybe you can use them as a model to code yours.
EDIT2: I tried to build the sample code in that .pdf and it told me to use MCC Code Configurator. I have the latest version but it doesn't support your chip.

Good luck!
 

Attachments

Last edited:

takao21203

Joined Apr 28, 2012
3,682
Hi guys

I am using PIC18F44J10, I need to use a block of flash memory to store some settings. First time ever to use flash in a pic to store data.

Here are the instruction from the datasheet: (P78)
Code:
1. Load Table Pointer register with address of the
block being erased.
2. Set the WREN and FREE bits (EECON1<2,4>)
to enable the erase operation.
3. Disable interrupts.
4. Write 55h to EECON2.
5. Write 0AAh to EECON2.
6. Set the WR bit. This will begin the erase cycle.
7. The CPU will stall for duration of the erase for
TIE (see parameter D133B).
8. Re-enable interrupts.
How do I work out the address of my block? As in my case, I am using PIC18F44J10, it has 16KB of flash, I just want to erase the last block (1024 bytes), so I don't accditantly erase amy part of my firmware. Can't find anything in the datasheet.
theres memory map in the datasheet so set the table pointer registers accordingly + you need to repeat several times i think its 16 or 32 words at a time
 

spinnaker

Joined Oct 29, 2009
7,815
Are we talking flash memory as in storing data in program memory? Or is this EEPROM?
 

Thread Starter

bug13

Joined Feb 13, 2012
1,692
theres memory map in the datasheet so set the table pointer registers accordingly + you need to repeat several times i think its 16 or 32 words at a time
I am not sure if I understand you correctly, can you point me to which part of the datasheet I should be looking? I did looked at this:
6.0 MEMORY ORGANIZATION
But I didn't find anything useful, or I can say I don't know what to look for???
 

takao21203

Joined Apr 28, 2012
3,682
I am not sure if I understand you correctly, can you point me to which part of the datasheet I should be looking? I did looked at this:

But I didn't find anything useful, or I can say I don't know what to look for???
Well this is why they sell these training seminars bcz the datasheets are cryptic.
But all information is contained you can build your firmwares only from reading the datasheets all over again multiple times,
need no course, no books, nothing.

I have done that and particulary I used this IC some time.

It is chapter 7, called FLASH MEMORY. As I said, 64 bytes at a time, so you have a set of buffer registers which you load first (I think).
The address as such you need to set the upper bits to zero of course dont assume they are zero. Theres 3x 8bit registers.
Memory map is quite straightforward as it start at zero, firstly some fundamental vectors,

but also take care at the top you have configuration words. So you need to calculate accordingly. 16K is 0x4000 in hex this is where you consult a devices memory map to see all this.

So you need to study 6. and 7. you may need to read them a few times.

C is almost same as assembler, as mostly it is just moves, not much jumping or arithmetic, not too difficult.
And you can do the calculations as constants (defines). You need to treat the top configuration words.

Well youre right the process of writing to flash (just) actually is quite complicated, and even more if you wanted to modify / only update some of a 64 bytes block or lets say, store something spanning 100 bytes.

You need quite a flowchart to check all the possibilities that can occur but all the info is in the datasheet.
 

Thread Starter

bug13

Joined Feb 13, 2012
1,692
So here are my attempts to try to get it to work by try and error. No luck so far.

I try to understand how to work our the address of the block by trying out my function, and read the firmware back to see which block is erased, but I can't make sense how it may works.

I have attached my codes and the firmware read back files, and the datasheet info here.

As you can see, using my following function:
if I erase block 0, I erased address 0x0000 - 0x03FF, so far so good.
if I erase block 1, I erased address 0x0138 - 0x03FF, what??? I expect 0x0400 - 0x7FF
if I erase block 2, I erased address 0x0000 - 0x03FF, what??? I expect 0x0800 - 0xBFF

Any thought/s??

Code:
void flashEraseBlock(uint8_t block){
    /*
        The sequence of events for erasing a block of internal
        program memory location is:
        1. Load Table Pointer register with address of the
        block being erased.
        2. Set the WREN and FREE bits (EECON1<2,4>)
        to enable the erase operation.
        3. Disable interrupts.
        4. Write 55h to EECON2.
        5. Write 0AAh to EECON2.
        6. Set the WR bit. This will begin the erase cycle.
        7. The CPU will stall for duration of the erase for
        TIE (see parameter D133B).
        8. Re-enable interrupts.
   
        The Most Significant 7 bits of the
        TBLPTR<21:10> point to the block being erased.
        TBLPTR<9:0> are ignored.
    */

    /*
     *  Block 0 = 0000H - 03FFH
     *  Block 1 = 0400H - 07FFH
     *  etc...
     *
     */

    // load the address into pointer registers
    TBLPTRU = (block >> 2);
    TBLPTRH = (block << 6);
    TBLPTRL = 0;

//    TBLPTRU = 0;
//    TBLPTRH = (block << 2);
//    TBLPTRL = 0;


    // enable erase operation
    EECON1bits.WREN = 1;
    EECON1bits.FREE = 1;

    // disable interrupt
    di();

    // unlock erase
    EECON2 = 0x55;
    EECON2 = 0xAA;

    // start the process
    EECON1bits.WR = 1;

    // enable interrupt
    ei();
}
 

Attachments

Last edited:

Thread Starter

bug13

Joined Feb 13, 2012
1,692
Well this is why they sell these training seminars bcz the datasheets are cryptic.
But all information is contained you can build your firmwares only from reading the datasheets all over again multiple times,
need no course, no books, nothing.

I have done that and particulary I used this IC some time.

It is chapter 7, called FLASH MEMORY. As I said, 64 bytes at a time, so you have a set of buffer registers which you load first (I think).
The address as such you need to set the upper bits to zero of course dont assume they are zero. Theres 3x 8bit registers.
Memory map is quite straightforward as it start at zero, firstly some fundamental vectors,

but also take care at the top you have configuration words. So you need to calculate accordingly. 16K is 0x4000 in hex this is where you consult a devices memory map to see all this.

So you need to study 6. and 7. you may need to read them a few times.

C is almost same as assembler, as mostly it is just moves, not much jumping or arithmetic, not too difficult.
And you can do the calculations as constants (defines). You need to treat the top configuration words.

Well youre right the process of writing to flash (just) actually is quite complicated, and even more if you wanted to modify / only update some of a 64 bytes block or lets say, store something spanning 100 bytes.

You need quite a flowchart to check all the possibilities that can occur but all the info is in the datasheet.
I have read Chapter 6 and 7 multiple times, it's either I understand it incorrecly or I don't know where to look??

Specifically, I think the following are the words that I don't understand correctly, as I don't see the result as expected: (I use the code in my last post to try erase the a block, are my code do the same as the text suggested?)

Capture.PNG

Capture.PNG
 
Last edited:

JohnInTX

Joined Jun 26, 2012
3,772
I think the databook is poorly written. Look at the assembler code in the databook example:
Code:
MOVLW CODE_ADDR_UPPER ; load TBLPTR with the base
MOVWF TBLPTRU ; address of the memory block
MOVLW CODE_ADDR_HIGH
MOVWF TBLPTRH
MOVLW CODE_ADDR_LOW
MOVWF TBLPTRL
It loads the full memory address into TBLPTRU/H/L. The lower 10 bits (9-0) are ignored when you erase the 1024 byte block (2^10 = 1024). You have 16*1K blocks So the next 4 bits <13-10> of the table pointer indicate which of those 16K blocks will be erased. The unused bits above 13 should be 0 of course.
TBLPTR U/H/L for each block for the addresses shown should be
0000h: 00000000 00000000 00000000
0400h: 00000000 00000100 00000000
0800h: 00000000 00001000 00000000
0C00h: 00000000 00001100 00000000
1000h: 00000000 00010000 00000000
etc.
where the 1024 byte block number is in red. Bits 9-0 can be anything but the upper bits have to be 0. Your code specifies blocks > 15 so that is likely your problem.

Note that while this chip erases in 1K byte blocks it only writes in 64 byte blocks. That means that for each erase, you have to write 16 blocks to fully restore the erased memory if you care about all of the data in the 1K block. The PICs I've used have smaller erase blocks of 64 bytes. The procedure to modify part of the flash memory for those PICs was to :
  • Copy the 64byte flash block to RAM
  • Erase the 64 byte flash block
  • Modify RAM
  • Write the 64 bytes to flash in one or two steps.
Of the two implementations I'm looking at, neither of them on a 'J' part, one wrote the whole 64 byte block the other required 2 writes of 32 bytes each. The firmware knew the difference. Unfortunately, you can't do that because you don't have the SRAM to buffer a 1K block. That means that you'll have to waste a chunk of one block. Hopefully that's not a problem.

When you write, your addressing will be in 64byte blocks (2^6) so the TBLPTR addressing needs to use the next 4 bits. This addresses the first five 64byte write blocks, all in the first 1K erase block (0000):
0000h: 00000000 00000000 00000000
0040h: 00000000 00000000 01000000
0080h: 00000000 00000000 10000000
00c0h: 00000000 00000000 11000000
0100h: 00000000 00000001 00000000

These are in the second 1K erase block (0001)
0400h: 00000000 00000100 00000000
0440h: 00000000 00000100 01000000
0480h: 00000000 00000100 10000000
04c0h: 00000000 00000100 11000000
0500h: 00000000 00000101 00000000

Finally, note that the PIC stalls during the several msec write time and no processing is done. I don't recall offhand if the timers etc. continue to run or if they halt too. My applications wrote the flash during power on config then mostly it was read-only after that.

@takao21203 notes that you have to pay attention to where the config words are. In the 44J10 they are at 3FF8h-3FFFh. You probably don't want to erase those so the last 16K block is off limits. Here's the programming spec that has all of that stuff.
EDIT: According to the Programming Spec, the config registers are copied from the end of program flash upon reset so you conceivably could use the last 64byte page of the last 1K block by reading the 64bytes into RAM, modifying then writing that last page. You still erase the entire 1K block but at least it's at the end of the flash memory. One big potential problem would be if you lost power or reset the PIC in the middle of the process. That could corrupt the config bits and brick the system. I'm thinking that the flash-write capabilities of the 44J10 are more useful for field-upgradable firmware using a boot-loader than EEPROM emultion.

Give that a try.
Good luck!
 

Attachments

Last edited:

Thread Starter

bug13

Joined Feb 13, 2012
1,692
@JohnlnTX

Thanks for you details replay, I have tried a few things, I still have no luck.

Here are what I have done:

Code:
// reserve a 1024 bytes block for settings storage, this will be the block I want to erase too
const uint8_t settings[] @ 0x0800 = {
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ..... };
I have tried:
Code:
    // this is how I understand the datasheet origionally
    // it doesn't erase a block of memory
    // it earase 0x013A - 0x0FFF
    TBLPTRU = 0;
    TBLPTRH = 0b10000000;
    TBLPTRL = 0;
Code:
    // using the middle 4 bits of the TBLPTRH regierst as you suggested
    // it earase 0x013F - 0xFFFF
    TBLPTRU = 0;
    TBLPTRH = 0b00001000;
    TBLPTRL = 0;
To make sure the intended values are loaded into those register, I print them out after loading the values:
Code:
printf("TBLPTR: %02X %02X %02X\n", TBLPTRU, TBLPTRH, TBLPTRL);
Here are my erase function:
Code:
void flashEraseBlock(uint32_t addr){
    /*
        The sequence of events for erasing a block of internal
        program memory location is:
        1. Load Table Pointer register with address of the
        block being erased.
        2. Set the WREN and FREE bits (EECON1<2,4>)
        to enable the erase operation.
        3. Disable interrupts.
        4. Write 55h to EECON2.
        5. Write 0AAh to EECON2.
        6. Set the WR bit. This will begin the erase cycle.
        7. The CPU will stall for duration of the erase for
        TIE (see parameter D133B).
        8. Re-enable interrupts.
      
        The Most Significant 7 bits of the
        TBLPTR<21:10> point to the block being erased.
        TBLPTR<9:0> are ignored.
    */
   
    /*
     *  Block 0 = 0000H - 0399H
     *  Block 1 = 0400H - 0799H
     *  etc...
     *
     */
   
    // load the address into pointer registers
    TBLPTRU = 0;
    TBLPTRH = 0x08;
    TBLPTRL = 0;
//    TBLPTRU = 0;
//    TBLPTRH = (block << 2);
//    TBLPTRL = 0;
   
//    TBLPTRU = (block >> 2);
//    TBLPTRH = (block << 6);
//    TBLPTRL = 0;
   
    printf("TBLPTR: %02X %02X %02X\n", TBLPTRU, TBLPTRH, TBLPTRL);
    //return;
   
    // enable erase operation
    EECON1bits.WREN = 1;
    EECON1bits.FREE = 1;
   
    // disable interrupt
    di();
   
    // unlock erase
    EECON2 = 0x55;
    EECON2 = 0xAA;
   
    // start the process
    EECON1bits.WR = 1;
   
    ei();
   
    printf("DONE!\n");
    while(1);
}
 

Thread Starter

bug13

Joined Feb 13, 2012
1,692
I am running at 32MHz, if that have anything to do with it??? (8MHz crystal x4 PLL)
 

JohnInTX

Joined Jun 26, 2012
3,772
Just for grins, disable the PLL. Some early J parts had trouble with it. Check the errata?
At line 31 above, TBLPTRH should be 04h to erase block 1, no?
How are you checking the operation?
I can look in detail later..
 

Thread Starter

bug13

Joined Feb 13, 2012
1,692
Just for grins, disable the PLL. Some early J parts had trouble with it. Check the errata?
At line 31 above, TBLPTRH should be 04h to erase block 1, no?
How are you checking the operation?
I can look in detail later..
  • Have tried disable PLL, doesn't make any different.
  • Have looked errata, don't see anything about PLL.
  • Errata did mention something about the flash memory, but it's only related to the config bits, which I am not erasing.
Here is how I check the operation:
  • At my erase function, I print out "DONE!" to tell me it's done, which I have never seen. (Guessing the wrong location is erased??)
  • I check the operation by reading out firmware with IPE, export it to a HEX file, and inspect it with notepad++
  • I also print the data in the registers to make sure the correct values are loaded.
    Code:
    printf("TBLPTR: %02X %02X %02X\n", TBLPTRU, TBLPTRH, TBLPTRL);
 

JohnInTX

Joined Jun 26, 2012
3,772
@bug13 OK. Let me take a look at it in the sim. I think I have a few J parts on a board to look at as well. I'll let you know what I find..
 

Thread Starter

bug13

Joined Feb 13, 2012
1,692
@bug13 OK. Let me take a look at it in the sim. I think I have a few J parts on a board to look at as well. I'll let you know what I find..
Thanks John!!

Forgot to mention, I was trying to erase block 0x0800 - 0x0BFF, hence my TBLPTRH = 0x08; but I also try 0x0400-0x07FF, TBLPTRH = 0x04, still no luck.
 

JohnInTX

Joined Jun 26, 2012
3,772
Forgot to mention, I was trying to erase block 0x0800 - 0x0BFF, hence my TBLPTRH = 0x08; but I also try 0x0400-0x07FF, TBLPTRH = 0x04, still no luck.
With your scabbed code, MPSIM says that it does indeed erase block 1 at 0x800 so at least the logic and addressing is OK.. Test data around the block is unchanged confirming a 1K erase block.
 

JohnInTX

Joined Jun 26, 2012
3,772
You enable interrupts - do you actually have any? I realize that we're looking a just a piece of the code but if you don't and you enable IRQs *boom*
 
Top