;; vim: filetype=avr
;;
;; SPI interface control and use
;;
.equ SPI_DDR = DDRB
.equ SPI_PORT = PORTB
.equ SPI_SCK = PORTB5
.equ SPI_MISO = PORTB4
.equ SPI_MOSI = PORTB3
.equ SPI_SS = PORTB2
.equ SPI_FLAGS = GPIOR0
.equ SPI_BUSY = 0
;; Initialize SPI subsystem for master operation
SPI_Init:
; Set modes
sbi SPI_DDR, SPI_SCK ; Out
sbi SPI_DDR, SPI_MOSI ; Out
sbi SPI_DDR, SPI_SS ; Out
; Drive SS high (off)
sbi SPI_PORT, SPI_SS
; Set control mode
; XXX: Enable interrupt
; Enable SPI
; MSB first
; Master mode
; Polarity/phase: Mode 0 (sample on rising edge)
; Clock rate 1/16
ldi r16, (0 << SPIE) | (1 << SPE) | (0 << DORD) | (1 << MSTR) | (0 << CPOL) | (0 << CPHA) | (0b01 << SPR0)
out SPCR, r16
; Flags
clr r0
out SPI_FLAGS, r0
; Done
ret
;; Send/recv one byte
;; Input: r16
;; Output: r10
;; Note: should not be busy...
SPI_SendRecv:
; Flag
sbi SPI_FLAGS, SPI_BUSY
; Enable slave (low)
cbi SPI_PORT, SPI_SS
; Write byte (starts SCK)
out SPDR, r16
; Wait for byte to be sent
spi_sr_wait:
in r1, SPSR
sbrs r1, SPIF
rjmp spi_sr_wait
; Read
mov r10, r11
in r11, SPDR
; Drive SS high (end of packet)
sbi SPI_PORT, SPI_SS
; Done
ret
;; Send buffer bytes
;; Input: post-buffer byte in X, buffer length in r16
;; Output: r10
;; Note: should not be busy...
SPI_SendBuf:
; Flag
sbi SPI_FLAGS, SPI_BUSY
; Enable slave (low)
cbi SPI_PORT, SPI_SS
; Write byte from X (starts SCK)
spi_srb_next:
ld r1, -X
out SPDR, r1
; Wait for byte to be sent
spi_srb_wait:
in r1, SPSR
sbrs r1, SPIF
rjmp spi_srb_wait
; Read
mov r10, r11
in r11, SPDR
; Done?
dec r16
brne spi_srb_next
; Drive SS high (end of packet)
sbi SPI_PORT, SPI_SS
; Done
ret
;; Service SPI interrupt
SPI_Interrupt:
; XXX: disabled
reti