I am writing some code to write a block of 16 bytes to the flash memory. I do this by reading the flash page into ram and copying the 16-byte block into the page buffer.
While copying the 16-byte block to the buffer, I check to see if I have to erase the page before writing it. I also check to see if I need to bother writing the page at all in case the block was already written to the flash.
According to the simulator (Studio4) this works. But when I load the program into a real chip, the flash stays unchanged.
After doing Pgm_PageWrite, address 0x3400 (0x6800 bytes) should contain the same patter as was written to Pgm_Buffer with all the ST -Y instructions in Reset. In the simulator this is true, in a real chip it is not.
Any ideas?
.include "m32def.inc" #define checksum r15 #define block r21 #define offset r22 #define pageL r24 #define pageH r25 #define scratch r23 #define pageByte r10 #define pageStatus r20 #define spmcrval r21 #define blockByte r11 #define rU_RTx r18 .equ USEG = 0x3400 .dseg .org 0x7F Pgm_Buffer: .byte 16 .org 0x100 .byte (256 - PAGESIZE*2) Pgm_PageBuffer: .byte PAGESIZE*2 .cseg .org 0 rjmp Reset Reset: ldi r16, low(RAMEND) out SPL, r16 ldi r16, high(RAMEND) out SPH, r16 /* Fill Pgm_Buffer with a pattern */ ldi YL, low(Pgm_Buffer+16) ldi YH, high(Pgm_Buffer+16) ldi r16, 0x00 st -Y, r16 ldi r16, 0x11 st -Y, r16 ldi r16, 0x22 st -Y, r16 ldi r16, 0x33 st -Y, r16 ldi r16, 0x44 st -Y, r16 ldi r16, 0x55 st -Y, r16 ldi r16, 0x66 st -Y, r16 ldi r16, 0x77 st -Y, r16 ldi r16, 0x88 st -Y, r16 ldi r16, 0x99 st -Y, r16 ldi r16, 0xAA st -Y, r16 ldi r16, 0xBB st -Y, r16 ldi r16, 0xCC st -Y, r16 ldi r16, 0xDD st -Y, r16 ldi r16, 0xEE st -Y, r16 ldi r16, 0xFF st -Y, r16 ldi block, 0x00 jmp Pgm_WriteBlock Pgm_WriteBlock_Return: nop nop rjmp PC .org SMALLBOOTSTART Pgm_WriteBlock: ; #define WAIT_SPM while(SPMCR & (1 << SPMEN)) mov offset, block ; blockOffset = address swap offset ; blockOffset *= 16 mov pageL, offset ; page = address * 16 andi pageL, ~(PAGESIZE*2 -1) mov pageH, offset andi pageH, 0x0F andi offset, (PAGESIZE*2 -1) & 0xF0 ; blockOffset &= (PAGESIZE-1) subi pageH, -high(USEG*2) ; page += 0x6800 movw ZH:ZL, pageH:pageL ; Z = page; /* load flash page into ram */ ser scratch ldi XL, low(Pgm_PageBuffer) ldi XH, high(Pgm_PageBuffer) Pgm_ReadPageBuffer: lpm scratch, Z+ st X+, scratch tst XL brne Pgm_ReadPageBuffer /* copy block to page */ clr pageStatus ldi XL, low(Pgm_PageBuffer) ldi XH, high(Pgm_PageBuffer) add XL, offset Pgm_CopyBlock: ld blockByte, Y+ ld pageByte, X cp pageByte, blockByte breq Pgm_CopyBlock2 sbr pageStatus, 0x01 ; bit 0 gets set if the flash page needs to be written and pageByte, blockByte cp pageByte, blockByte breq Pgm_CopyBlock2 sbr pageStatus, 0x02 ; bit 1 gets set if the flash page needs to be erased Pgm_CopyBlock2: st X+, blockByte cpi YL, Pgm_Buffer + 16 brne Pgm_CopyBlock /* copy page to spm temp buffer */ movw ZH:ZL, pageH:pageL ldi XL, low(Pgm_PageBuffer) ldi XH, high(Pgm_PageBuffer) Pgm_FillTempBuffer: ld r0, X+ ld r1, X+ ldi spmcrval, 1 rcall Pgm_DoSPM adiw ZH:ZL, 2 tst XL brne Pgm_FillTempBuffer sbrs pageStatus, 1 rjmp Pgm_WritePage /* erase page */ movw ZH:ZL, pageH:pageL ldi spmcrval, 3 rcall Pgm_DoSPM Pgm_WritePage: movw ZH:ZL, pageH:pageL ldi rU_RTx, 0 sbrs pageStatus, 0 jmp Pgm_WriteBlock_Return ldi spmcrval, 5 rcall Pgm_DoSPM jmp Pgm_WriteBlock_Return Pgm_DoSPM: in scratch, SPMCR sbrc scratch, SPMEN rjmp Pgm_DoSPM out SPMCR, spmcrval spm Pgm_WaitSPM: in scratch, SPMCR sbrc scratch, SPMEN rjmp Pgm_WaitSPM ldi scratch, 0x11 out SPMCR, scratch spm ret