AVR Assembly SPI Communication Problem

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
I am trying to establish serial communication in Assembly language via SPI using an atmega162 as a master and an atmega16a as a slave but I couldn't succeed. 
I have attached the code can you tell me where I am making mistake? The MOSI pin of the Master is connected to the MOSI pin of the Slave , the MISO pin 
of the master is connected to the MISO pin of the slave, the SCK pin of the Master is connected to the SCK pin of the Slave and the grounds of the two 
breadborads are connected to each other. The SS pin of the Master is configured as an output and is connected to the SS pin of the Slave.  

Master:

.include "m162def.inc"
.def counter1 = R17
.def temp1 = R16
.def counter2 = R18
.def temp2 = r20

.cseg
.org 0
ldi temp2, low(RAMEND)
out SPL, temp
ldi temp2, high(RAMEND)
out SPH, temp
LDI temp1,0b11111111
OUT DDRA,temp1

SPI_MasterInit:
; Set MOSI, SCK and SS pins output, MISO input
ldi temp2, (0<<UMSEL0)
out UCSR0C, temp2
ldi r17,(1<<DDB5)|(1<<DDB7)|(1<<DDB4)
out DDRB,r17
; Enable SPI, Master, set clock rate fck/4
ldi r17,(1<<SPE)|(1<<MSTR)|(0<<SPR0)|(0<<SPR1)|(1<<CPOL)|(1<<CPHA)
out SPCR,r17
ldi r18,0b11111010

SPI_MasterTransmit:
RCALL delay1
CBI PORTB,4
RCALL delay2
; Start transmission of data (r18)
out SPDR,r18

Wait_Transmit:
; Wait for transmission complete
sbis SPSR,SPIF
rjmp Wait_Transmit
in r23,SPDR
RCALL delay2
SBI PORTB,4
rjmp SPI_MasterTransmit

;delay for about 20 miliseconds
delay1:
	LDI counter2, 255
count2:

	LDI counter1, 255
count1:

	DEC counter1
	NOP
	NOP
	BRNE count1
	DEC counter2
	BRNE count2
	RET

;delay for about 10 microseconds
delay2:
	LDI counter2, 1
count4:

	LDI counter1, 53
count3:

	DEC counter1
	BRNE count3
	DEC counter2
	BRNE count4
	RET

Slave:

.include "m16adef.inc"
.def counter1 = R17
.def temp1 = R19
.def counter2 = R18
.def temp2 = r20
.def dummy = r22

.cseg
.org 0
ldi temp2, low(RAMEND)
out SPL, temp2
ldi temp2, high(RAMEND)
out SPH, temp2
ldi temp1,0b11111111
out DDRA,temp1
ldi r22,0b11111010

SPI_SlaveInit:
; Set MISO output, all others input
ldi temp2, (0<<UMSEL)
out UCSRC, temp2
ldi r17,(1<<DDB6)
out DDRB,r17
; Enable SPI
ldi r17,(1<<SPE)|(1<<CPOL)|(1<<CPHA)
out SPCR,r17
ret
SPI_SlaveReceive:
; Wait for reception complete
sbis SPSR,SPIF
rjmp SPI_SlaveReceive
; Read received data and return
in r16,SPDR
rcall blink
;CP r16,r22
;BRBS 1,YAK
rjmp SPI_SlaveReceive

blink:
LDI	temp1,0xFF
OUT PORTA, temp1
rcall delay
LDI	temp1,0x00
OUT PORTA, temp1
;rjmp SPI_SlaveReceive
RET

;delay for about 5 miliseconds
delay:
	LDI counter2, 127
count2:

	LDI counter1, 255
count1:

	DEC counter1
	BRNE count1
	DEC counter2
	BRNE count2
	RET

 

Last Edited: Wed. Oct 4, 2017 - 03:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Answer:  You did not state what the problem is!???

 

Jim

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

I have now.

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

You still have not said what the problem is, only that it does not work???

What were expecting to happen, what did happen, how is that different from expected.

What have YOU done to debug so far?

 

However I did find this in the slave code:

 

sitkitanseltunc wrote:
out SPCR,r17

ret      <---------  where are you returning to?  This init was not called as a subroutine!

SPI_SlaveReceive:

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

Some bits of your code have indentation and are easy to read. the majority does not and is almost impossible to follow. Whitespace costs nothing!....

Master:

    .include "m162def.inc"
    .def counter1 = R17
    .def temp1 = R16
    .def counter2 = R18
    .def temp2 = r20
    
    .cseg
    .org 0
    ldi temp2, low(RAMEND)
    out SPL, temp
    ldi temp2, high(RAMEND)
    out SPH, temp
    LDI temp1,0b11111111
    OUT DDRA,temp1

SPI_MasterInit:
    ; Set MOSI, SCK and SS pins output, MISO input
    ldi temp2, (0<<UMSEL0)
    out UCSR0C, temp2
    ldi r17,(1<<DDB5)|(1<<DDB7)|(1<<DDB4)
    out DDRB,r17
    ; Enable SPI, Master, set clock rate fck/4
    ldi r17,(1<<SPE)|(1<<MSTR)|(0<<SPR0)|(0<<SPR1)|(1<<CPOL)|(1<<CPHA)
    out SPCR,r17
    ldi r18,0b11111010

SPI_MasterTransmit:
    RCALL delay1
    CBI PORTB,4
    RCALL delay2
    ; Start transmission of data (r18)
    out SPDR,r18

Wait_Transmit:
    ; Wait for transmission complete
    sbis SPSR,SPIF
    rjmp Wait_Transmit
    in r23,SPDR
    RCALL delay2
    SBI PORTB,4
    rjmp SPI_MasterTransmit

;delay for about 20 miliseconds
delay1:
    LDI counter2, 255
count2:

    LDI counter1, 255
count1:

    DEC counter1
    NOP
    NOP
    BRNE count1
    DEC counter2
    BRNE count2
    RET

;delay for about 10 microseconds
delay2:
    LDI counter2, 1
count4:

    LDI counter1, 53
count3:

    DEC counter1
    BRNE count3
    DEC counter2
    BRNE count4
    RET

Slave:

    .include "m16adef.inc"
    .def counter1 = R17
    .def temp1 = R19
    .def counter2 = R18
    .def temp2 = r20
    .def dummy = r22
    
    .cseg
    .org 0
    ldi temp2, low(RAMEND)
    out SPL, temp2
    ldi temp2, high(RAMEND)
    out SPH, temp2
    ldi temp1,0b11111111
    out DDRA,temp1
    ldi r22,0b11111010

SPI_SlaveInit:
    ; Set MISO output, all others input
    ldi temp2, (0<<UMSEL)
    out UCSRC, temp2
    ldi r17,(1<<DDB6)
    out DDRB,r17
    ; Enable SPI
    ldi r17,(1<<SPE)|(1<<CPOL)|(1<<CPHA)
    out SPCR,r17
    ret

SPI_SlaveReceive:
    ; Wait for reception complete
    sbis SPSR,SPIF
    rjmp SPI_SlaveReceive
    ; Read received data and return
    in r16,SPDR
    rcall blink
    ;CP r16,r22
    ;BRBS 1,YAK
    rjmp SPI_SlaveReceive

blink:
    LDI	temp1,0xFF
    OUT PORTA, temp1
    rcall delay
    LDI	temp1,0x00
    OUT PORTA, temp1
    ;rjmp SPI_SlaveReceive
    RET

;delay for about 5 miliseconds
delay:
    LDI counter2, 127
count2:

    LDI counter1, 255
count1:

    DEC counter1
    BRNE count1
    DEC counter2
    BRNE count2
    RET

Is there some reason for not making things like SPI_MasterInit and Transmit functions? Is it really the case you cannot afford the RCALL/RET overhead? The code would be clearer with something like:

main:
    rcall SPI_MasterInit
    ldi r18,0b11111010
loop:
    rcall SPI_MasterTransmit ; send R18
    rjmp loop
    
SPI_MasterInit:
    ; Set MOSI, SCK and SS pins output, MISO input
    ldi temp2, (0<<UMSEL0)
    out UCSR0C, temp2
    ldi r17,(1<<DDB5)|(1<<DDB7)|(1<<DDB4)
    out DDRB,r17
    ; Enable SPI, Master, set clock rate fck/4
    ldi r17,(1<<SPE)|(1<<MSTR)|(0<<SPR0)|(0<<SPR1)|(1<<CPOL)|(1<<CPHA)
    out SPCR,r17
    ret

SPI_MasterTransmit:
    RCALL delay1
    CBI PORTB,4
    RCALL delay2
    ; Start transmission of data (r18)
    out SPDR,r18

Wait_Transmit:
    ; Wait for transmission complete
    sbis SPSR,SPIF
    rjmp Wait_Transmit
    in r23,SPDR
    RCALL delay2
    SBI PORTB,4
    ret

Oh and delay1 and delay2 could be the same routine if you passed in the counter1/2 values as initial parameters (and adjusted for the lack of NOP;NOP).

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

@ki0bk said:

However I did find this in the slave code:

 

 

sitkitanseltunc wrote:

out SPCR,r17

 

ret      <---------  where are you returning to?  This init was not called as a subroutine!

SPI_SlaveReceive:

 

 

Indeed! The Slave has crossed the event horizon and fallen into a black hole.

 

 

EDIT: made the post I was quoting a Quote

Greg Muth

Portland, OR, US

Xplained Boards mostly

Atmel Studio 7.0 on Windows 10

 

Last Edited: Wed. Oct 4, 2017 - 05:02 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have removed the 'ret' command from my slave avr's code, yes it was a mistake. But the codes still don't work the way they are supposed to. This is how I wrote the codes: LED connected to any pin of slave's PORTA is supposed to blink every 20 miliseconds when the SPI works right. But now when I give slave and master power, the LED light attached to the slave in PORTA only lights steadily.  And this shows me that SPI does not work right. 

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

You have two potential problems, either it aint sendin correctly, or it aint receiving correctly?

 

How can you test to find which (or both) are the problem? 

 

Do you have an Arduino Uno handly?  I'll bet there is an SPI sketch that could be used as a known tx or rx device.

 

How about a logic analyzer?

How about a scope?  Either of these could be used to verify correct operation.

 

Jim

edit: spelling

Last Edited: Wed. Oct 4, 2017 - 06:54 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, I fixed the problem. My atmega162 which I was using as the master was not working properly so I had to replace it with a new one. Also I figured that I had to reload the data to the SPDR of the master AVR before the start of every transmission. SPI communication is working just fine now.