--- a/Makefile Fri May 14 18:19:59 2010 +0300
+++ b/Makefile Thu Jun 17 20:00:27 2010 +0300
@@ -13,6 +13,7 @@
all: $(PROG).hex
+matrix.hex: spi.inc matrix.inc timer.inc delay.inc macros.inc
led7seg.hex: spi.inc led7seg.inc adc.inc timer.inc delay.inc macros.inc
timer.hex: timer.inc macros.inc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/matrix.inc Thu Jun 17 20:00:27 2010 +0300
@@ -0,0 +1,158 @@
+;; LED Matrix driver
+;;
+
+.set MATRIX_DDR = DDRB
+.set MATRIX_PORT = PORTB
+.set MATRIX_OE = PORTB1 ; Output Enable, active low, externally pulled high
+
+.dseg
+.set MATRIX_COLS = 8 ; number of columns
+
+matrix_colbit: .byte 1 ; column bit
+matrix_rowbuf: .byte MATRIX_COLS ; row bitmask by column
+
+.cseg
+
+;; Normalize the outputs, enable the matrix, an set up buffers
+Matrix_Init:
+ ; Setup ENable port
+ sbi MATRIX_PORT, MATRIX_OE ; high -> disabled
+ sbi MATRIX_DDR, MATRIX_OE ; out
+
+ ; blank hardware
+ ldi r16, 0
+
+ sts spi_outbuf + 0, r16 ; column sinks
+ sts spi_outbuf + 1, r16 ; row drivers
+
+ ; write out
+ rcall SPI_SendRecv
+
+ ; enable
+ cbi MATRIX_PORT, MATRIX_OE ; low -> enabled
+
+ ; init buffers
+ ldi r16, 0b1
+ sts matrix_colbit, r16
+
+ ldi r16, 0
+ ldi r17, MATRIX_COLS
+ ldi YL, low(matrix_rowbuf)
+ ldi YH, high(matrix_rowbuf)
+
+m_init_mzero:
+ st Y+, r16
+
+ ; loop until zero
+ dec r17
+ brne m_init_mzero
+
+ ; Use Timer0, 32k cycles -> 500Hz scan rate
+ ldi r16, 32
+ rcall Timer0_Start
+
+ ; done
+ ret
+
+;; Scan the next column
+;; Interrupt-driven
+Matrix_ScanCol:
+ ; Column bit
+ ; load
+ lds r16, matrix_colbit
+
+ ; start packet
+ cbi SPI_PORT, SPI_SS
+
+ ; output
+ out SPDR, r16
+
+ ; Compute col index
+ ldi r17, 0
+
+m_sc_colidx:
+ ; shift
+ lsr r16
+
+ ; done if we shifted the bit out
+ brcs m_sc_row
+
+ ; count shifts
+ inc r17
+ rjmp m_sc_colidx
+
+m_sc_row:
+ ; Row mask
+ ; base
+ ldi XL, low(matrix_rowbuf)
+ ldi XH, high(matrix_rowbuf)
+
+ ; offset
+ ldi r18, 0
+
+ add XL, r17
+ adc XH, r18
+
+ ; load
+ ld r16, X
+
+ ; output
+ rcall SPI_Wait
+ out SPDR, r16
+
+ ; Update col bit
+ lds r16, matrix_colbit
+
+ ; shift left
+ lsl r16
+ brcc m_sc_colout
+
+ ; overflow, take bit from C
+ rol r16
+
+m_sc_colout:
+ ; store
+ sts matrix_colbit, r16
+
+ ; End of packet
+ rcall SPI_Wait
+ sbi SPI_PORT, SPI_SS
+
+ ; Done
+ ret
+
+;; Scan the matrix once in one go
+Matrix_ScanFull:
+ ; Row index
+ ldi ZL, low(matrix_rowbuf)
+ ldi ZH, high(matrix_rowbuf)
+
+ ; Column bit
+ ldi r25, 0
+ sec ; set C
+
+m_pulse_col:
+ ; rotate bit left from C
+ rol r25
+
+ ; overflow
+ brcs m_pulse_end
+
+ ; store in output buffer
+ sts spi_outbuf + 1, r25
+
+ ; Row mask
+ ld r16, Z+
+
+ sts spi_outbuf + 0, r16
+
+ ; Display
+ rcall SPI_SendRecv
+
+ ; Next column
+ rjmp m_pulse_col
+
+m_pulse_end:
+ ; Done
+ ret
+
--- a/matrix.s Fri May 14 18:19:59 2010 +0300
+++ b/matrix.s Thu Jun 17 20:00:27 2010 +0300
@@ -7,38 +7,38 @@
.org 0x00
rjmp init
+.org OC1Aaddr
+ ; Timer/Counter1 Compare Output A
+ rjmp Timer_OC1A
+
+.org OC0Aaddr
+ ; Timer/Counter0 Compare Output A
+ rjmp Timer_OC0A
+
+.org SPIaddr
+ rjmp SPI_Interrupt
+
+.org 0x40
+
;; Syntax
.include "macros.inc"
;; SPI
.include "spi.inc"
+;; Matrix
+.include "matrix.inc"
+
+;; Timer
+.set TIMER0_CB_A = Matrix_ScanCol
+
+.include "timer.inc"
+
;; Utils
.include "delay.inc"
-;; Initialize output buffers
-Main_Init:
- ; Setup ENable port
- sbi PORTB, PORTB1 ; high -> disabled
- sbi DDRB, PORTB1 ; out
-
- ; all low
- ldi r16, 0
-
- sts spi_outbuf + 0, r16
- sts spi_outbuf + 1, r16
-
- ; write out
- rcall SPI_SendRecv
-
- ; enable
- cbi PORTB, PORTB1 ; low -> enabled
-
- ; done
- ret
-
;; Scan through each pixel
-Main_Scan:
+Main_ScanRaw:
; init
ldi r18, 1
ldi r19, 1
@@ -54,21 +54,48 @@
ldi r20, 5 ; ~4M cycles
rcall VarDelay
+ ; cols
+ lsl r19 ; next col
+ brcc scan_loop ; refresh if we didn't overflow
+
+ rol r19 ; shift back from C into r21.0
+
; rows
- rol r18 ; next row
+ lsl r18 ; next row
brcc scan_loop ; refresh if we didn't overflow
rol r18 ; shift back from C into r20.0
- ; cols
- rol r19 ; next col
- brcc scan_loop ; refresh if we didn't overflow
-
- rol r19 ; shift back from C into r21.0
-
; one scan completed
ret
+;; Scan with test pattern
+Main_ScanTest:
+ ; Generate pattern
+ ; end of buffer
+ ldi r17, MATRIX_COLS
+ ldi XL, low(matrix_rowbuf + MATRIX_COLS)
+ ldi XH, high(matrix_rowbuf + MATRIX_COLS)
+
+ ; bit pattern
+ ldi r16, 0b11
+
+st_loop:
+ ; put
+ st -X, r16
+
+ ; flip
+ rol r16
+
+ ; loop until zero
+ dec r17
+ brne st_loop
+
+st_scan:
+ ; Scan repeatedly
+ ;rcall Matrix_ScanCol
+ rjmp st_scan
+
Main:
init:
; Stack
@@ -80,16 +107,23 @@
; Enable interrupts
sei
+; DEBUG
+sbi DDRD, PORTD7
+cbi PORTD, PORTD7
+
+ ; Timer
+ rcall Timer_Init
+
; SPI
rcall SPI_Init
+
+ ; Matrix
+ rcall Matrix_Init
-
; Run
- rcall Main_Init
+ ; rcall Main_ScanRaw
-loop:
- rcall Main_Scan
- rjmp loop
+ rcall Main_ScanTest
end:
rjmp end
--- a/spi.inc Fri May 14 18:19:59 2010 +0300
+++ b/spi.inc Thu Jun 17 20:00:27 2010 +0300
@@ -3,6 +3,7 @@
;; SPI interface control and use
;;
+;; I/O Port
.equ SPI_DDR = DDRB
.equ SPI_PORT = PORTB
.equ SPI_SCK = PORTB5
@@ -10,14 +11,25 @@
.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
@@ -39,7 +51,7 @@
; 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)
+ ldi r16, (0 << SPIE) | (1 << SPE) | (SPI_DORD << DORD) | (1 << MSTR) | (SPI_CPOL << CPOL) | (SPI_CPHA << CPHA) | (SPI_CLOCK << SPR0)
out SPCR, r16
; Flags
@@ -110,6 +122,19 @@
; 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