Simple SPI program on ATmega168 :-(

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

Hi Freaks!

I have a simple test program for SPI.

On the device - It doesn't work at all - no port B outputs, when monitored with a scope

On the Studio simulator, when SPIF is set after the appropriate number of clocks (and you can see the data being clocked out of port B), SPSR is set to 0x80, but the lds r16, SPSR line does not change r16 from 0x00 - so it sits in the wait_spi_transmit loop for ever

What gives?

.include "" 			;ATmega168 definitions

.equ	MOSI	= 3				;port B3
.equ	SCK		= 5				;port B5
.equ	SS		= 2				;port B2

.org 0x0000


	;stack pointer initialisation
	ldi 	r16,high(RAMEND)
	out		SPH,r16
	ldi		r16,low(RAMEND)
	out		SPL,r16

	;Set up port B spi lines as outputs
	ldi		r16, (1 << SS) | (1 << SCK) | (1 << MOSI)
	out 	DDRB, r16

	;set SS high (as it is active low)
	sbi 	PortB, SS

	;Enable SPI, set clock rate fck/4
	ldi		r16, (1 << SPE ) | (1 << MSTR )
	out		SPCR, r16

	;send 0x09 to spi device
	ldi		r16, 0x09
	rcall	spi_transmit

	rjmp	loop

;spi transmit*******************
spi_transmit:						;
	cbi 	PortB, SS		;low SS

	out 	SPDR, r16		;output r16 to the SPI data register

	lds 	r16, SPSR		;wait on SPI status register SPIF flag
	sbrs 	r16, SPIF
	rjmp 	wait_spi_transmit

	sbi 	PortB, SS		;high SS

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

Very strange! I can't see anything wrong with this code - in fact it's identical to code I use, except that in my SPI setup I also set the bits for CPOL and CPHA.

If Port B.2 (SS) is not toggling, then you must not be executing the spi_transmit routine. Perhaps it's getting stuck at the wait_spi_transmit loop, as you say it does in the simulator. Does B.2 stick low or high? That would be a clue. High means you aren't in the wait loop; low means you probably are.

Regardless, the problem isn't in this source code, it's something else. Perhaps it's in the m168def file? Try explicitly testing for '7' instead of SPIF, and writing an explicit '0x50' to SPCR, and while you're at it, set the stack pointer to explicit 0x03FF. And - dumbass stupid question, I know - but are you actually using a Mega168, and not picked up a Mega48 by accident? The 48 only has half the RAM and so would not have a working stack.

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

Well, I've got it going on the simulator - the day job is stopping me trying it on the real hardware :(


lds    r16, SPSR

needs to be

in     r16, SPSR

...for reasons that I don't understand, since I thought:

    - the standard equivalent of the data sheet SBIS for AVRs with extended I/O maps (in this case, p.162 of the AtMega168 datasheet) was a LDS/SBRS pair - There's no difference between LDS and IN except the target location range and LDS is two cycles and IN is only one

Any views?

I think I've just been done AGAIN by this gotcha - I REALLY think Atmel should put the correct code examples in the datasheets. It's gotta be my #1 gripe about the whole AVR experience....but I need to try it on the hardware later just to confirm