Working matrix scan
authorTero Marttila <terom@fixme.fi>
Thu, 17 Jun 2010 20:00:27 +0300
changeset 33 0d0309787be3
parent 32 7ceb76b5a104
child 34 4646abd073fb
child 40 3803c0b40a9c
Working matrix scan
Makefile
matrix.inc
matrix.s
spi.inc
--- 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