terom@17: ;; vim: filetype=avr terom@18: ;; terom@18: ;; SPI interface control and use terom@18: ;; terom@17: terom@33: ;; I/O Port terom@17: .equ SPI_DDR = DDRB terom@17: .equ SPI_PORT = PORTB terom@17: .equ SPI_SCK = PORTB5 terom@17: .equ SPI_MISO = PORTB4 terom@17: .equ SPI_MOSI = PORTB3 terom@17: .equ SPI_SS = PORTB2 terom@17: terom@33: ;; Internal status flags terom@17: .equ SPI_FLAGS = GPIOR0 terom@17: .equ SPI_BUSY = 0 terom@17: terom@33: ;; Settings terom@33: .set SPI_DORD = 0 ; word order terom@33: .set SPI_CPOL = 0 ; clock polarity terom@33: .set SPI_CPHA = 0 ; clock phase terom@33: .set SPI_CLOCK = 0b01 ; clock speed terom@33: terom@33: ;; Internal state terom@26: ; Number of in/out bytes terom@26: .set SPI_BUFLEN = 2 terom@26: terom@26: .dseg terom@33: ; Buffer for incoming frames terom@26: spi_inbuf: .byte SPI_BUFLEN terom@33: terom@33: ; Buffer for outgoing frames terom@26: spi_outbuf: .byte SPI_BUFLEN terom@26: terom@26: .cseg terom@26: terom@17: ;; Initialize SPI subsystem for master operation terom@17: SPI_Init: terom@17: ; Set modes terom@17: sbi SPI_DDR, SPI_SCK ; Out terom@17: sbi SPI_DDR, SPI_MOSI ; Out terom@17: sbi SPI_DDR, SPI_SS ; Out terom@17: terom@17: ; Drive SS high (off) terom@17: sbi SPI_PORT, SPI_SS terom@17: terom@17: ; Set control mode terom@23: ; XXX: Enable interrupt terom@17: ; Enable SPI terom@17: ; MSB first terom@17: ; Master mode terom@17: ; Polarity/phase: Mode 0 (sample on rising edge) terom@17: ; Clock rate 1/16 terom@33: ldi r16, (0 << SPIE) | (1 << SPE) | (SPI_DORD << DORD) | (1 << MSTR) | (SPI_CPOL << CPOL) | (SPI_CPHA << CPHA) | (SPI_CLOCK << SPR0) terom@17: out SPCR, r16 terom@17: terom@17: ; Flags terom@17: clr r0 terom@17: out SPI_FLAGS, r0 terom@30: terom@30: ; Start update timer terom@31: ; XXX: also used for ADC terom@31: ; ldi r16, 64 ; every 64k cycles terom@31: ; rcall Timer0_Start terom@17: terom@17: ; Done terom@17: ret terom@17: terom@30: ;; Triggered by Timer0, updates the spi_bufs terom@30: ;; Run from timer interrupt context terom@30: SPI_Update: terom@30: ; skip if updating terom@30: sbic SPI_FLAGS, SPI_BUSY terom@30: ret terom@30: terom@30: ;; Continue terom@30: ; XXX: blocks too much? terom@30: terom@26: ;; Send/Recv from/to SPI buffers terom@17: SPI_SendRecv: terom@17: ; Flag terom@17: sbi SPI_FLAGS, SPI_BUSY terom@17: terom@26: ; Start of packet terom@17: cbi SPI_PORT, SPI_SS terom@17: terom@26: ; Init buffers terom@26: ldi r16, SPI_BUFLEN terom@26: terom@26: ; send/recv in reverse order terom@26: ldi XL, low(spi_inbuf + SPI_BUFLEN) terom@26: ldi XH, high(spi_inbuf + SPI_BUFLEN) terom@26: ldi YL, low(spi_outbuf + SPI_BUFLEN) terom@26: ldi YH, high(spi_outbuf + SPI_BUFLEN) terom@17: terom@26: ; Write terom@26: spi_sr_next: terom@26: ; load+send tail byte terom@26: ld r1, -Y terom@26: out SPDR, r1 terom@26: terom@26: ; Wait terom@26: spi_sr_wait: terom@23: in r1, SPSR terom@23: sbrs r1, SPIF terom@23: rjmp spi_sr_wait terom@23: terom@23: ; Read terom@36: ; XXX: wrong, should be head byte? terom@26: ; read+store tail byte terom@26: in r1, SPDR terom@26: st -X, r1 terom@23: terom@23: ; Done? terom@23: dec r16 terom@26: brne spi_sr_next ; if nonzero terom@23: terom@26: ; End of packet terom@23: sbi SPI_PORT, SPI_SS terom@30: terom@30: cbi SPI_FLAGS, SPI_BUSY terom@23: terom@17: ; Done terom@17: ret terom@17: terom@33: ;; Wait for SPI to be ready for send terom@33: SPI_Wait: terom@33: ; Test terom@33: in r1, SPSR terom@33: sbrs r1, SPIF terom@33: rjmp SPI_Wait terom@33: terom@33: ; Read SPDR to clear SPIF terom@33: in r10, SPDR terom@33: terom@33: ; Done terom@33: ret terom@33: terom@17: ;; Service SPI interrupt terom@17: SPI_Interrupt: terom@23: ; XXX: disabled terom@17: reti terom@17: terom@17: