12.1.4.1 PFM Sector Write Sequence

The sequence of events for programming a block of internal program memory location should be:

  1. Set NVMADR with the target sector address.
  2. Read the PFM sector into RAM with the SECRD operation.
  3. Execute the sector erase procedure (see 12.1.3.1 PFM Erase Sequence).
  4. SECER is set as the last step in the erase sequence.
  5. The CPU will stall for the duration of the erase (about 10 ms using internal timer).
  6. Load TBLPTR with address of first byte being updated.
  7. Write the n-byte block into the holding registers with auto-increment. Refer to the Flash memory organization by device table for the number of holding registers.
  8. Disable interrupts.
  9. Execute the sector write unlock sequence (see 12.1.2 NVM Unlock Sequence).
  10. SECWR bit is set as last step in the unlock sequence.
  11. The CPU will stall for the duration of the write (about 10 ms using internal timer).
  12. Re-enable interrupts.
  13. Verify the memory (table read).

This procedure will require about 20 ms to update each block of memory. See the "Memory Programming Specifications" for more details. An example of the required code is given below.

Important: Before setting the SECWR bit, the NVMADR value needs to be within the intended address range of the target PFM sector.
Figure 12-9. Program Flash Memory (PFM) Write Flowchart

Writing a Sector of Program Flash Memory

; Code sequence to modify one word in a programmed sector of PFM
; Calling routine should check WREG for the following errors:
;
;    00h = Successful modification
;    01h = Read error
;    02h = Erase error
;    03h = Write error 
;
READ_BLOCK:
        MOVLW   CODE_ADDR_UPPER     ; load NVMADR with the base
        MOVWF   NVMADRU             ; address of the memory sector
        MOVLW   CODE_ADDR_HIGH
        MOVWF   NVMADRH
        MOVLW   CODE_ADDR_LOW
        MOVWF   NVMADRL
        BCF     INTCON, GIE         ; disable interrupts
        BSF     NVMCON0, NVMEN      ; enable NVM
; ----- Required Sequence -----       
        MOVLW   0BBh
        MOVWF   NVMCON2             ; first unlock byte = 0BBh
        MOVLW   44h
        MOVWF   NVMCON2             ; second unlock byte = 44h
        BSF     NVMCON1, SECRD      ; start sector read (CPU stall)
; ------------------------------        
        BTFSC   NVMCON0, NVMERR     ; Verify no error occurred during read
        BRA     NVM_RDERR           ; return read error code
ERASE_BLOCK:                        ; NVMADR is already pointing to target block
; ----- Required Sequence -----       
        MOVLW   0CCh
        MOVWF   NVMCON2             ; first unlock byte = 0CCh
        MOVLW   33h
        MOVWF   NVMCON2             ; second unlock byte = 33h
        BSF     NVMCON1, SECER      ; start sector erase (CPU stall)
; ------------------------------        
        BTFSC   NVMCON0, NVMERR     ; Verify no error occurred during erase
        BRA     NVM_ERERR           ; return erase error code
MODIFY_WORD:
        MOVLW   TARGET_ADDR_UPPER   ; load TBLPTR with the target address
        MOVWF   TBLPTRU             ; of the LSByte
        MOVLW   TARGET_ADDR_HIGH
        MOVWF   TBLPTRH
        MOVLW   TARGET_ADDR_LOW
        MOVWF   TBLPTRL
        MOVLW   NEW_DATA_LOW        ; update holding register
        MOVWF   TABLAT
        TBLWT*+
        MOVLW   NEW_DATA_HIGH
        MOVWF   TABLAT
        TBLWT*+
PROGRAM_MEMORY:                     ; NVMADR is already pointing to target block
; ----- Required Sequence -----       
        MOVLW   0DDh
        MOVWF   NVMCON2             ; first unlock byte = 0DDh
        MOVLW   22h
        MOVWF   NVMCON2             ; second unlock byte = 22h
        BSF     NVMCON1, SECWR      ; start sector programming (CPU stall)
; ------------------------------        
        BTFSC   NVMCON0, NVMERR     ; Verify no error occurred during write
        BRA     NVM_WRERR           ; return sector write error code
        CLRF    WREG,F              ; return with no error
        BRA     NVM_EXIT
NVM_RDERR:
        MOVLW   01h
        BRA     NVM_EXIT
NVM_ERERR:
        MOVLW   02h
        BRA     NVM_EXIT
NVM_WRERR:
        MOVLW   03h
NVM_EXIT:
        BCF    NVMCON0, NVMEN       ; disable NVM
        BSF    INTCON, GIE          ; re-enable interrupts
        RETURN