spi.inc
author Tero Marttila <terom@paivola.fi>
Sun, 20 Apr 2014 23:51:57 +0300
changeset 80 5254ba612630
parent 36 06e1e554acbb
permissions -rw-r--r--
dmx-web: slightly better RGB colorpicker control..
;; vim: filetype=avr
;;
;; SPI interface control and use
;;

;; I/O Port
.equ SPI_DDR    = DDRB
.equ SPI_PORT   = PORTB
.equ SPI_SCK    = PORTB5
.equ SPI_MISO   = PORTB4
.equ SPI_MOSI   = PORTB3
.equ SPI_SS     = PORTB2

;; Internal status flags
.equ SPI_FLAGS  = GPIOR0
.equ SPI_BUSY   = 0

;; Settings
.set SPI_DORD = 0           ; word order
.set SPI_CPOL = 0           ; clock polarity
.set SPI_CPHA = 0           ; clock phase
.set SPI_CLOCK  = 0b01      ; clock speed

;; Internal state
; Number of in/out bytes
.set SPI_BUFLEN  = 2

.dseg
; Buffer for incoming frames
spi_inbuf:  .byte SPI_BUFLEN

; Buffer for outgoing frames
spi_outbuf: .byte SPI_BUFLEN

.cseg

;; 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) | (SPI_DORD << DORD) | (1 << MSTR) | (SPI_CPOL << CPOL) | (SPI_CPHA << CPHA) | (SPI_CLOCK << SPR0)
        out         SPCR, r16
    
    ; Flags
        clr         r0
        out         SPI_FLAGS, r0

    ; Start update timer
    ; XXX: also used for ADC
;        ldi         r16, 64         ; every 64k cycles
;        rcall       Timer0_Start
    
    ; Done
        ret

;; Triggered by Timer0, updates the spi_bufs
;;  Run from timer interrupt context
SPI_Update:
        ; skip if updating
        sbic        SPI_FLAGS, SPI_BUSY
        ret

    ;; Continue
    ; XXX: blocks too much?

;; Send/Recv from/to SPI buffers
SPI_SendRecv:
    ; Flag
        sbi         SPI_FLAGS, SPI_BUSY

    ; Start of packet
        cbi         SPI_PORT, SPI_SS
    
    ; Init buffers
        ldi         r16, SPI_BUFLEN
        
        ; send/recv in reverse order
        ldi         XL, low(spi_inbuf + SPI_BUFLEN)
        ldi         XH, high(spi_inbuf + SPI_BUFLEN)
        ldi         YL, low(spi_outbuf + SPI_BUFLEN)
        ldi         YH, high(spi_outbuf + SPI_BUFLEN)
    
    ; Write
spi_sr_next:
        ; load+send tail byte
        ld          r1, -Y
        out         SPDR, r1

    ; Wait
spi_sr_wait:        
        in          r1, SPSR
        sbrs        r1, SPIF
        rjmp        spi_sr_wait

    ; Read
        ; XXX: wrong, should be head byte?
        ; read+store tail byte
        in          r1, SPDR
        st          -X, r1
 
    ; Done?
        dec         r16
        brne        spi_sr_next         ; if nonzero
    
    ; End of packet
        sbi         SPI_PORT, SPI_SS
        
        cbi         SPI_FLAGS, SPI_BUSY

    ; Done
        ret

;; Wait for SPI to be ready for send
SPI_Wait:
    ; Test
        in          r1, SPSR
        sbrs        r1, SPIF
        rjmp        SPI_Wait
    
    ; Read SPDR to clear SPIF
        in          r10, SPDR

    ; Done
        ret

;; Service SPI interrupt
SPI_Interrupt:
    ; XXX: disabled
        reti