spi.inc
changeset 89 1b3cea759eff
parent 88 c923295ee520
child 90 13c2deb919d1
equal deleted inserted replaced
88:c923295ee520 89:1b3cea759eff
     1 ;; vim: filetype=avr
       
     2 ;;
       
     3 ;; SPI interface control and use
       
     4 ;;
       
     5 
       
     6 ;; I/O Port
       
     7 .equ SPI_DDR    = DDRB
       
     8 .equ SPI_PORT   = PORTB
       
     9 .equ SPI_SCK    = PORTB5
       
    10 .equ SPI_MISO   = PORTB4
       
    11 .equ SPI_MOSI   = PORTB3
       
    12 .equ SPI_SS     = PORTB2
       
    13 
       
    14 ;; Internal status flags
       
    15 .equ SPI_FLAGS  = GPIOR0
       
    16 .equ SPI_BUSY   = 0
       
    17 
       
    18 ;; Settings
       
    19 .set SPI_DORD = 0           ; word order
       
    20 .set SPI_CPOL = 0           ; clock polarity
       
    21 .set SPI_CPHA = 0           ; clock phase
       
    22 .set SPI_CLOCK  = 0b01      ; clock speed
       
    23 
       
    24 ;; Internal state
       
    25 ; Number of in/out bytes
       
    26 .set SPI_BUFLEN  = 2
       
    27 
       
    28 .dseg
       
    29 ; Buffer for incoming frames
       
    30 spi_inbuf:  .byte SPI_BUFLEN
       
    31 
       
    32 ; Buffer for outgoing frames
       
    33 spi_outbuf: .byte SPI_BUFLEN
       
    34 
       
    35 .cseg
       
    36 
       
    37 ;; Initialize SPI subsystem for master operation
       
    38 SPI_Init:
       
    39     ; Set modes
       
    40         sbi         SPI_DDR, SPI_SCK        ; Out
       
    41         sbi         SPI_DDR, SPI_MOSI       ; Out
       
    42         sbi         SPI_DDR, SPI_SS         ; Out
       
    43 
       
    44     ; Drive SS high (off)
       
    45         sbi         SPI_PORT, SPI_SS
       
    46 
       
    47     ; Set control mode
       
    48         ; XXX: Enable interrupt
       
    49         ; Enable SPI
       
    50         ; MSB first
       
    51         ; Master mode
       
    52         ; Polarity/phase: Mode 0 (sample on rising edge)
       
    53         ; Clock rate 1/16
       
    54         ldi         r16, (0 << SPIE) | (1 << SPE) | (SPI_DORD << DORD) | (1 << MSTR) | (SPI_CPOL << CPOL) | (SPI_CPHA << CPHA) | (SPI_CLOCK << SPR0)
       
    55         out         SPCR, r16
       
    56     
       
    57     ; Flags
       
    58         clr         r0
       
    59         out         SPI_FLAGS, r0
       
    60 
       
    61     ; Start update timer
       
    62     ; XXX: also used for ADC
       
    63 ;        ldi         r16, 64         ; every 64k cycles
       
    64 ;        rcall       Timer0_Start
       
    65     
       
    66     ; Done
       
    67         ret
       
    68 
       
    69 ;; Triggered by Timer0, updates the spi_bufs
       
    70 ;;  Run from timer interrupt context
       
    71 SPI_Update:
       
    72         ; skip if updating
       
    73         sbic        SPI_FLAGS, SPI_BUSY
       
    74         ret
       
    75 
       
    76     ;; Continue
       
    77     ; XXX: blocks too much?
       
    78 
       
    79 ;; Send/Recv from/to SPI buffers
       
    80 SPI_SendRecv:
       
    81     ; Flag
       
    82         sbi         SPI_FLAGS, SPI_BUSY
       
    83 
       
    84     ; Start of packet
       
    85         cbi         SPI_PORT, SPI_SS
       
    86     
       
    87     ; Init buffers
       
    88         ldi         r16, SPI_BUFLEN
       
    89         
       
    90         ; send/recv in reverse order
       
    91         ldi         XL, low(spi_inbuf + SPI_BUFLEN)
       
    92         ldi         XH, high(spi_inbuf + SPI_BUFLEN)
       
    93         ldi         YL, low(spi_outbuf + SPI_BUFLEN)
       
    94         ldi         YH, high(spi_outbuf + SPI_BUFLEN)
       
    95     
       
    96     ; Write
       
    97 spi_sr_next:
       
    98         ; load+send tail byte
       
    99         ld          r1, -Y
       
   100         out         SPDR, r1
       
   101 
       
   102     ; Wait
       
   103 spi_sr_wait:        
       
   104         in          r1, SPSR
       
   105         sbrs        r1, SPIF
       
   106         rjmp        spi_sr_wait
       
   107 
       
   108     ; Read
       
   109         ; XXX: wrong, should be head byte?
       
   110         ; read+store tail byte
       
   111         in          r1, SPDR
       
   112         st          -X, r1
       
   113  
       
   114     ; Done?
       
   115         dec         r16
       
   116         brne        spi_sr_next         ; if nonzero
       
   117     
       
   118     ; End of packet
       
   119         sbi         SPI_PORT, SPI_SS
       
   120         
       
   121         cbi         SPI_FLAGS, SPI_BUSY
       
   122 
       
   123     ; Done
       
   124         ret
       
   125 
       
   126 ;; Wait for SPI to be ready for send
       
   127 SPI_Wait:
       
   128     ; Test
       
   129         in          r1, SPSR
       
   130         sbrs        r1, SPIF
       
   131         rjmp        SPI_Wait
       
   132     
       
   133     ; Read SPDR to clear SPIF
       
   134         in          r10, SPDR
       
   135 
       
   136     ; Done
       
   137         ret
       
   138 
       
   139 ;; Service SPI interrupt
       
   140 SPI_Interrupt:
       
   141     ; XXX: disabled
       
   142         reti
       
   143 
       
   144