Reading Signature Row on AT90USB

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

I'm trying to read the signature row with `LPM` from my AT90USB647. Of particular interest is the 10-byte "Unique Serial Number" mentioned in section `29.7.10`. This is for a space conscious bootloader and thus all in assembly. Included is an excerpt from my software that matches the following pseudo-code.

The code acts as if the setting of SPMCSR doesn't happen and just reads the bytes from flash.

  1. Load desired address into Z
  2. Prepare rTemp2 register for later
  3. Reset CRC
  4. Set Signature Read Bit (etc)
  5. Load Signature Byte
  6. Wait for Serial Send buffer to be empty
  7. Send Byte and feed CRC
  8. Repeat from (4) until done
  9. Send CRC value
 // From datasheet section 29.7.10
 .equ	SigRowStart=0x0E
 .equ	SigRowEnd=0x18

 // Setup Z ptr signature bytes as per LPM
 ldi	ZL, SigRowStart
 ldi	ZH, 0x00

 // Register needed for LPM instruction
 ldi	rTemp2, ((1<<SIGRD) | (1<<SPMEN))

 rcall	ResetCRC

SignatureLPMLoop:
 // Specify type of LPM: Signature Read
 sts	SPMCSR, rTemp2
 
 // Load next signature byte
 lpm	rTemp0, Z+

 rcall	WaitSerialSend

 rcall	SendSerialDataCalcCRC

 cpi	ZL, SigRowEnd
 brne	SignatureLPMLoop

 rcall	SendCRC

The obvious first guess as to what may be wrong is rTemp2 getting mangled in one of the `rcall`s. Upon inspection, rTemp2 is not touched in the called functions. I also tried moving the line where I set rTemp2 to immediately before storing that to SPMSCR.

Any suggestions as to what I might doing wrong?

Pushing AVRs to their limits

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

Show us the MINIMAL set that shows the problem. Without calls to unknown functions.

No RSTDISBL, no fun!

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

That is what I did. The functions will be posted below, but I'm betting seeing them will not help.

I'm hoping someone else here has done something similar and might have a pointer relevant to the problem. Some caveat that the datasheet covers poorly for instance.

I cannot easily remove the functions of interest because that is how I'm testing this. Debugging would be difficult in my setup nor do I see how it would even help anyway.

ResetCRC:
 // Reset CRC to 0xffff seed
 ldi	CRCL, 0xff
 ldi	CRCH, 0xff
 ret

/**
 * Pre: Y == UCSRA
 */
WaitSerialSend:
 //	Load UCSRA into WaitSerialSendReg
 ld		WaitSerialSendReg, Y
 // Skip following loop if we're done
 sbrs	WaitSerialSendReg, UDRE1
 rjmp	WaitSerialSend
 ret

/**
 * Pre: Y == UCSRA
 * Input: rTemp0 == data
 * Assume Data Register is empty and ready for us
 */
SendSerialDataCalcCRC:
 sts	UDR1, rTemp0 // Start serial send
 eor	CRCL, rTemp0 // Add to CRC
 rjmp	CRC2 // jump so its ret returns for us

/**
 * CRC16/MODBUS. Copied from 
 *
 * SRP16 verifies this...
 * Poly  : 0x8005
 * init  : 0xffff
 * xorout: 0x0000
 * refin : true
 * refout: true
 * 
 * Input: CRC_data
 * Result: CRCL/CRCH
 * Mangles: CRCT1, CRCT2
 *
 * Usage 1:
 *   
 *   rcall	CRC
 *
 * Usage 2:
 *   eor	CRCL,rInputRegister
 *   rcall	CRC2
 */
CRC:
 eor	CRCL,CRC_data
CRC2:
 mov	CRCT1,CRCL
 swap	CRCT1
 eor	CRCT1,CRCL
 mov	CRCT2,CRCT1
 lsr	CRCT1
 lsr	CRCT1
 eor	CRCT1,CRCT2
 mov	CRCT2,CRCT1
 lsr	CRCT1
 eor	CRCT1,CRCT2
 andi	CRCT1,0x07
 mov	CRCT2,CRCL
 mov	CRCL,CRCH
 lsr	CRCT1
 ror	CRCT2
 ror	CRCT1
 mov	CRCH,CRCT2
 eor	CRCL,CRCT1
 lsr	CRCT2
 ror	CRCT1
 eor	CRCH,CRCT2
 eor	CRCL,CRCT1
 ret
 .def CRC_data=r1

 .def zero=r2
 
 .def WaitSerialSendReg=r3
 .def WaitSerialRecvReg=r4

 .def CRCT2=r15
 
 .def CRCH=r16
 .def CRCL=r17

 .def rTemp0=r18
 .def rTemp1=r19
 .def rTemp2=r20
 .def rTemp3=r21
 .def rTemp4=r22
 .def rTemp5=r23
 
 .def CRCT1=r24

 .def command=r25

Pushing AVRs to their limits

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

I just tried reading the same values with a C program and seem to have been successful using boot_signature_byte_get(x).

Looking at the .lst file, I see that the gcc generated assembly uses basically the same pair of instructions:

 144 0108 F092 5700 		sts 87, r15
 145 010c E491      		lpm r30, Z

The first difference is surely inconsequential that they use r15 instead of r20 with STS to set SIGRD and SPMEN bits in SPMCSR.

The second line is where the only significant differences that I see come in. They use r30 as the destination for the loaded information. (The weird part is this is part of the Z register). They also don't use the post increment instruction. (Likely because they are storing the result in Z).

I'm going to try to make mine similar to that to see if maybe the post-increment instruction is causing the problems. Edit: Nope.

Pushing AVRs to their limits