I am trying to write to flash memory on my PIC18F87J11 but I have a problem understanding assembly. The datasheet for my PIC has only assembly and I am using C compiler. I was wondering if someone can help me translate this portion of code to C language. This code can be found here, Section 7.5.
MOVLW CODE_ADDR_UPPER ; Load TBLPTR with the base address
MOVWF TBLPTRU
MOVLW CODE_ADDR_HIGH
MOVWF TBLPTRH
MOVLW CODE_ADDR_LOW
MOVWF TBLPTRL
MOVLW DATA0
MOVWF TABLAT
TBLWT*+
MOVLW DATA1
MOVWF TABLAT
TBLWT*
PROGRAM_MEMORY
BSF EECON1, WPROG ; enable single word write
BSF EECON1, WREN ; enable write to memory
BCF INTCON, GIE ; disable interrupts
MOVLW H'55'
MOVWF EECON2 ; write H'55'
MOVLW H'AA'
MOVWF EECON2 ; write H'AA'
BSF EECON1, WR ; start program (CPU stall)
BSF INTCON, GIE ; re-enable interrupts
BCF EECON1, WPROG ; disable single word write
BCF EECON1, WREN ; disable write to memory
I know this is not a typical question to ask, but if I can receive some help it would be awesome.
It may be easiest to break this into a couple of steps. The first thing that I would do is look at the general overview of what needs to be accomplished prior to looking at the assembly. That can be found in 7.5.2 of your reference.
It's important to note that the ability to perform a word write is enabled when the WPROG bit is set and that the memory location must already be erased. Here are the steps:
- Load Table Pointer register with address of the data to be written.
- Write the 2 bytes into the holding registers and perform a table write.
- Set the WREN bit (EECON1<2>) to enable byte writes.
- Disable interrupts.
- Write H'55' to EECON2.
- Write H'AA' to EECON2.
- Set the WR bit. This will begin the write cycle.
- The CPU will stall for the duration of the write for Tiw (see Parameter D133A).
- Re-enable interrupts.
We can then break the assembly into the given steps for clarity. I have also commented every line of code so that you can see what the assembly is doing (I would never do this in actual code as it is just distracting).
1. Load Table Pointer with address of data to be written.
MOVLW CODE_ADDR_UPPER ;Move the value CODE_ADDR_UPPER to the working register.
MOVWF TBLPTRU ;Move the working register to TBLPTRU.
MOVLW CODE_ADDR_HIGH ;Move the value CODE_ADDR_HIGH to the working register.
MOVWF TBLPTRH ;Move the working register to TBLPTRH
MOVLW CODE_ADDR_LOW ;Move the value CODE_ADDR_LOW to the working register.
MOVWF TBLPTRL ;Move the working register to TBLPTRL.
2. Write the 2 bytes into the holding registers and perform a table write.
MOVLW DATA0 ;Move DATA0 to the working register.
MOVWF TABLAT ;Move the working register to TABLAT.
TBLWT*+ ;Write the data stored in TABLAT to the position
;defined in TBLPTR and then, increment TBLPTR.
MOVLW DATA1 ;Move DATA1 to the working register.
MOVWF TABLAT ;Move the working register to TABLAT.
TBLWT* ;Write the data stored in TABLAT to the position defined in TBLPTR.
The rest of the steps are included in the PROGRAM_MEMORY section.
PROGRAM_MEMORY ; This is just a label.
;STEP 3
BSF EECON1, WPROG ;Set the WPROG bit in the EECON1 register.
BSF EECON1, WREN ;Set the WREN bit in the EECON1 register.
;STEP 4
BCF INTCON, GIE ;Clear the GIE bit in the INTCON register.
;STEP 5
MOVLW H'55' ;Move 0x55 to the working register
MOVWF EECON2 ;Write 0x55 to EECON2 register.
;STEP 6
MOVLW H'AA' ;Move 0xAA to the working register.
MOVWF EECON2 ;Write 0xAA to the EECON2 register.
;STEP 7 AND 8
BSF EECON1, WR ;Set the WR bit in the EECON1 register.
;STEP 9
BSF INTCON, GIE ;Set the GIE bit in the INTCON register.
BCF EECON1, WPROG ;Clear the WPROG bit in the EECON1 register.
BCF EECON1, WREN ;Clear the WREN bit in the EECON1 register.
Since I have neither the PIC compiler or IDE with me, I know the following C code will not be perfect (please feel free to edit). However, this should give you a good idea of how to construct the C code based on the assembly example.
static void FlashWriteWord(unsigned int store_addr, unsigned char * data)
{
/* 1. Load Table Pointer with the address of the data to be written. */
TBLPTR = store_addr;
/* 2. Write the 2 bytes into the holding registers and perform a table write. */
TABLAT = data;
_asm
TBLWTPOSTINC /* Table writes are performed as inline assembly functions. */
_endasm
data++;
_asm
TBLWT /* Table writes are performed as inline assembly functions. */
_endasm
/* 3. Set the write enable bit to enable byte writes. */
EECON1bits.WPROG = 1;
EECON1bits.WREN = 1;
/* 4. Disable interrupts. */
INTCONbits.GIE = 0;
/* 5. Write H'55' to EECON2. */
EECON2 = 0x55;
/* 6. Write H'AA' to EECON2. */
EECON2 = 0xAA;
/* 7. Set the WR bit. This will begin the write cycle. */
/* 8. The CPU will stall for the duration of the write for Tiw (see Parameter D133A). */
EECON1bits.WR = 1;
/* 9. Re-enable interrupts. */
INTCONbits.GIE = 1;
EECON1bits.WPROG = 0;
EECON1bits.WREN = 0;
}
Hope that helps!