12.1.4.1 Program Flash Memory Write Sequence
The sequence of events for programming an internal program memory location must be:
- Read appropriate number of bytes into RAM. Refer to the memory organization table for Write latch size.
- Update data values in RAM as necessary.
- Load TBLPTR with address within the row to be erased.
- Execute the block erase procedure.
- Load TBLPTR with address of first byte being written.
- Write the n-byte block into the holding registers with auto-increment. Refer to the memory organization table for Write latch size.
- Set NVMREG bits to point to program memory.
- Clear FREE bit and set WREN bit register.
- Disable interrupts.
- Execute the unlock sequence (see NVM Unlock Sequence).
- WR bit is set as last step in the unlock sequence.
- The CPU will stall for the duration of the write (about 2 ms using internal timer).
- Re-enable interrupts.
- Verify the memory (table read).
This procedure will require about 6 ms to update each write block of memory. An example of the required code is given in below.
Important: Before setting the WR bit, the Table Pointer address needs to be within
the intended address range of the bytes in the holding registers.
Writing to Program Flash Memory
MOVLW D'64’ ; number of bytes in erase block
MOVWF COUNTER
MOVLW BUFFER_ADDR_HIGH ; point to buffer
MOVWF FSR0H
MOVLW BUFFER_ADDR_LOW
MOVWF FSR0L
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
READ_BLOCK:
TBLRD*+ ; read into TABLAT, and inc
MOVF TABLAT, W ; get data
MOVWF POSTINC0 ; store data
DECFSZ COUNTER ; done?
BRA READ_BLOCK ; repeat
MODIFY_WORD:
MOVLW BUFFER_ADDR_HIGH ; point to buffer
MOVWF FSR0H
MOVLW BUFFER_ADDR_LOW
MOVWF FSR0L
MOVLW NEW_DATA_LOW ; update buffer word
MOVWF POSTINC0
MOVLW NEW_DATA_HIGH
MOVWF INDF0
ERASE_BLOCK:
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
BCF NVMCON1, NVMREG0 ; point to Program Flash Memory
BSF NVMCON1, NVMREG1 ; point to Program Flash Memory
BSF NVMCON1, WREN ; enable write to memory
BSF NVMCON1, FREE ; enable Erase operation
BCF INTCON, GIE ; disable interrupts
; ----- Required Sequence -----
MOVLW 55h
MOVWF NVMCON2 ; write 55h
MOVLW AAh
MOVWF NVMCON2 ; write 0AAh
BSF NVMCON1, WR ; start erase (CPU stall)
; ------------------------------
BSF INTCON, GIE ; re-enable interrupts
TBLRD*- ; dummy read decrement
MOVLW BUFFER_ADDR_HIGH ; point to buffer
MOVWF FSR0H
MOVLW BUFFER_ADDR_LOW
MOVWF FSR0L
WRITE_ BUFFER_BACK
MOVLW BlockSize ; number of bytes in holding register
MOVWF COUNTER
MOVLW D’64’/BlockSize ; number of write blocks in 64 bytes
MOVWF COUNTER2
WRITE_BYTE_TO_HREGS:
MOVF POSTINC0, W ; get low byte of buffer data
MOVWF TABLAT ; present data to table latch
TBLWT+* ; write data, perform a short write
; to internal TBLWT holding register.
DECFSZ COUNTER ; loop until holding registers are full
BRA WRITE_WORD_TO_HREGS
PROGRAM_MEMORY:
BCF NVMCON1, NVMREG0 ; point to Program Flash Memory
BSF NVMCON1, NVMREG1 ; point to Program Flash Memory
BSF NVMCON1, WREN ; enable write to memory
BCF NVMCON1, FREE ; enable write to memory
BCF INTCON, GIE ; disable interrupts
; ----- Required Sequence -----
MOVLW 55h
MOVWF NVMCON2 ; write 55h
MOVLW 0AAh
MOVWF NVMCON2 ; write 0AAh
BSF NVMCON1, WR ; start program (CPU stall)
; ------------------------------
DCFSZ COUNTER2 ; repeat for remaining write blocks
BRA WRITE_BYTE_TO_HREGS
BSF INTCON, GIE ; re-enable interrupts
BCF NVMCON1, WREN ; disable write to memory