SPM troubles

Go To Last Post
6 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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

/* John Butera */

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John.

what about fuse settings?

Volkmar

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have JTAGEN, SPIEN, BODEN, and BODLEVEL0 programmed. Boot flash set for 256 words to correspond with SMALLBOOTSTART, and my crystal setting. No lock bits are set.

/* John Butera */

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi!
Read carefully what data sheet says about writing to flash -> RWW section must be reanabled before taking any access to It with LPM, JMP or CALL instructions or your uC may stay in indefinite state, so interrupts must be disabled also. I use ATMega128 and there is a good example for writing to FLASH, I use It with little modifications and I could share my code this evening after I finish work, It works really!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dmn wrote:
Read carefully what data sheet says about writing to flash -> RWW section must be reanabled before taking any access to It with LPM, JMP or CALL instructions

Yup, I read that part carefully, which is why I re-enabled the RWW section after each page write. But then I tried to be clever and make a DoSPM function to save a couple bytes of code space. I didn't read the Page Loading section very carefully though, which is what got me.

While loading the temporary buffer, if you try to re-enable the RWW section, the buffer gets erased.

Quote:
The temporary buffer will auto-erase after a page write operation or by writing the RWWSRE bit in SPMCR."

So I took..

   ldi      scratch, 0x11
   out      SPMCR, scratch
   spm 

..out of DoSPM and only call it before jumping back to the application section. This solved my problem entirely!

I think had a MOV instead of a MOVW in the code I pasted as well, but everything works great now. Just like I wanted it to. :D

/* John Butera */

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, It's good that It is working properly alredy, and you found the mistake by yourself. I'm glad to hear that!