Word Modify

Changing a word in PFM requires erasing the word before it is rewritten. However, the PFM cannot be erased by less than a page at a time. Changing a single word requires reading the page, erasing the page, and then rewriting the page with the modified word. The NVM command set includes page operations to simplify this task.

The steps necessary to change one or more words in PFM space are as follows:
  1. 1.Set the NVMADR registers to the target address.
  2. 2.Set the NVMCMD to ‘b010 (Page Read).
  3. 3.Set the GO bit to start the PFM read into the GPR buffer.
  4. 4.Monitor the GO bit or NVMIF interrupt flag to determine when the read has completed.
  5. 5.Make the desired changes to the GPR buffer data.
  6. 6.Set NVMCMD to ‘b110 (Page Erase).
  7. 7.Disable all interrupts.
  8. 8.Perform the unlock sequence as described in the Unlock Sequence section.
  9. 9.Set the GO bit to start the PFM page erase.
  10. 10.Monitor the GO bit or NVMIF interrupt flag to determine when the erase has completed.
  11. 11.Set NVMCMD to ‘b101 (Page Write).
  12. 12.Perform the unlock sequence.
  13. 13.Set the GO bit to start the PFM page write.
  14. 14.Monitor the GO bit or NVMIF interrupt flag to determine when the write has completed.
  15. 15.Interrupts can be enabled after the GO bit is clear.
  16. 16.Set the NVMCMD control bits to ‘b000.

Modifying a Word in Program Flash Memory in C

// Code sequence to modify one word in a programmed page of PFM
// The variable with desired value is specified by ModifiedWord
// PFM target address is specified by WORD_ADDR
// PFM page size is specified by PAGESIZE
// The Buffer RAM start address is specified by BufferRAMStartAddr. This value
// will be changed based on the device, refer to the "Memory Organization"
//chapter for more details.

// Save Interrupt Enable bit Value
uint8_t GIEBitValue = INTCON0bits.GIE;

uint16_t bufferRAM __at(BufferRAMStartAddr);

// Defining a pointer to the first location of the Buffer RAM
uint16_t *bufferRamPtr = (uint16_t*) & bufferRAM;

// Load NVMADR with the base address of the memory page
NVMADR = WORD_ADDR;              
NVMCON1bits.CMD = 0x02;            // Set the page read command
INTCON0bits.GIE = 0;               // Disable interrupts
NVMCON0bits.GO = 1;                // Start page read
while (NVMCON0bits.GO);            // Wait for the read operation to complete

// NVMADR is already pointing to target page           
NVMCON1bits.CMD = 0x06;           // Set the page erase command
//––––––––– Required Unlock Sequence ––––––––– 
NVMLOCK = 0x55;
NVMLOCK = 0xAA;
NVMCON0bits.GO = 1;               // Start page erase
//–––––––––––––––––––––––––––––––––––––––––––––
while (NVMCON0bits.GO);           // Wait for the erase operation to complete
// Verify erase operation success and call the recovery function if needed
if (NVMCON1bits.WRERR){             
   ERASE_FAULT_RECOVERY();
}

//Modify Buffer RAM for the given word to be written to PFM
uint8_t offset = (uint8_t) ((WORD_ADDR & ((PAGESIZE * 2) - 1)) / 2);
bufferRamPtr += offset;
*bufferRamPtr = ModifiedWord;

// NVMADR is already pointing to target page
NVMCON1bits.CMD = 0x05;           // Set the page write command
//––––––––– Required Unlock Sequence ––––––––– 
NVMLOCK = 0x55;
NVMLOCK = 0xAA;
NVMCON0bits.GO = 1;               // Start page write
//–––––––––––––––––––––––––––––––––––––––––––––
while (NVMCON0bits.GO);           // Wait for the write operation to complete
// Verify write operation success and call the recovery function if needed
if (NVMCON1bits.WRERR){             
   WRITE_FAULT_RECOVERY();
}

INTCON0bits.GIE = GIEBitValue;    // Restore interrupt enable bit value
NVMCON1bits.CMD = 0x00;           // Disable writes to memory