matrix.inc
changeset 89 1b3cea759eff
parent 88 c923295ee520
child 90 13c2deb919d1
equal deleted inserted replaced
88:c923295ee520 89:1b3cea759eff
     1 ;; LED Matrix driver
       
     2 ;; vim: set ft=avr:
       
     3 
       
     4 .dseg
       
     5 ;; I/O addresses
       
     6 ; Control port
       
     7 .set MATRIX_DDR = DDRB
       
     8 .set MATRIX_PORT = PORTB
       
     9 
       
    10 ; Pin for matrix driver Output Enable
       
    11 .set MATRIX_OE = PORTB1		; Output Enable, active low, externally pulled high
       
    12 
       
    13 ;; Matrix properties
       
    14 ; Matrix width in columns
       
    15 .set MATRIX_COLS = 8                        ; physical columns
       
    16 
       
    17 ; Framebuffer width in columns
       
    18 .set MATRIX_BUF_COLS = 16		            ; framebuffer columns
       
    19 
       
    20 ;; SPI addresses
       
    21 ; row drivers (8 bits)
       
    22 .set MATRIX_SPI_ROW = 0                     ; row mask source
       
    23 
       
    24 ; column sinks (8 bits)
       
    25 .set MATRIX_SPI_COL = 1                     ; column scan sink
       
    26 
       
    27 ;; Matrix state
       
    28 ; Matrix framebuffer
       
    29 ; this holds the columns data as a 1 byte bitmask of row data per column (8 bits -> 8 rows)
       
    30 matrix_colbuf:	    .byte MATRIX_BUF_COLS   ; framebuffer (row data by column)
       
    31 
       
    32 ; Column scan bit
       
    33 ; in the matrix refresh loop, we push out each column's row data in turn
       
    34 ; this bit tracks the currently refreshing column
       
    35 matrix_colbit:	    .byte 1                 ; column scan bit
       
    36 
       
    37 ; Matrix viewport offset
       
    38 ; the visible matrix data is taken directly from the framebuffer, but it can be taken at an arbitrary offset
       
    39 ; this determines the starting offset for the visible viewport's left edge from the start of the framebuffer in columns
       
    40 matrix_colshift:    .byte 1                 ; viewport left column offset
       
    41 
       
    42 ;; Text
       
    43 ; Maximum length of message
       
    44 .set TEXT_MAXLENGTH = 64
       
    45 
       
    46 ; Scrolling speed (kiloticks per frame)
       
    47 .set TEXT_SPEED = 1
       
    48 
       
    49 text_buffer:        .byte TEXT_MAXLENGTH    ; display message buffer
       
    50 text_offset:        .byte 1                 ; current offset in text
       
    51 
       
    52 .cseg
       
    53 
       
    54 ;; Normalize the outputs, enable the matrix, and set up buffers
       
    55 Matrix_Init:
       
    56     ; Setup ENable port
       
    57         sbi         MATRIX_PORT, MATRIX_OE	; high -> disabled
       
    58         sbi         MATRIX_DDR, MATRIX_OE	; out
       
    59  
       
    60 	; blank hardware
       
    61 		ldi			r16, 0
       
    62 
       
    63 		sts			spi_outbuf + 0, r16		; column sinks
       
    64 		sts			spi_outbuf + 1, r16		; row drivers
       
    65 
       
    66 	; write out
       
    67 		rcall		SPI_SendRecv
       
    68 
       
    69 	; enable
       
    70 		cbi			MATRIX_PORT, MATRIX_OE	; low -> enabled
       
    71 
       
    72 	; init buffers
       
    73 		ldi			r16, 0b1
       
    74 		sts			matrix_colbit, r16
       
    75 
       
    76         ldi         r16, 0
       
    77         sts         matrix_colshift, r16
       
    78 
       
    79 		ldi			r16, 0
       
    80 		ldi			r17, MATRIX_BUF_COLS
       
    81 		ldi			YL, low(matrix_colbuf)
       
    82 		ldi			YH, high(matrix_colbuf)
       
    83 
       
    84 m_init_mzero:
       
    85 		st			Y+, r16
       
    86 		
       
    87 		; loop until zero
       
    88 		dec			r17
       
    89 		brne		m_init_mzero
       
    90 
       
    91 	; Use Timer0, 32k cycles -> 500Hz scan rate
       
    92 		ldi			r16, 32
       
    93 		rcall		Timer0_Start
       
    94 
       
    95 	; done
       
    96 		ret
       
    97 
       
    98 ;; Scan the matrix's next column from the viewport
       
    99 ;;  Interrupt-driven
       
   100 Matrix_ScanCol:
       
   101     ; Save registers
       
   102         push        r16
       
   103         push        r17
       
   104 
       
   105 	; Column bit
       
   106 		; load
       
   107 		lds			r16, matrix_colbit
       
   108 	
       
   109 		; start packet
       
   110         cbi         SPI_PORT, SPI_SS
       
   111 
       
   112 		; output single column-enable bit
       
   113 		out			SPDR, r16
       
   114 
       
   115 	; Compute col index
       
   116 		ldi			r17, 0
       
   117 
       
   118 m_sc_colidx:
       
   119 		; shift
       
   120 		lsr			r16
       
   121 
       
   122 		; done if we shifted the bit out
       
   123 		brcs		m_sc_row
       
   124 
       
   125 		; count shifts
       
   126 		inc			r17
       
   127 		rjmp		m_sc_colidx
       
   128 
       
   129 m_sc_row:
       
   130     ; Column shift
       
   131         ; load
       
   132         lds         r16, matrix_colshift
       
   133 
       
   134         ; add to col index
       
   135         add         r17, r16
       
   136 
       
   137 	; Row mask
       
   138 		; base
       
   139 		ldi			XL, low(matrix_colbuf)
       
   140 		ldi			XH, high(matrix_colbuf)
       
   141 
       
   142 		; offset
       
   143 		ldi			r16, 0
       
   144 
       
   145 		add			XL, r17
       
   146 		adc			XH, r16
       
   147 
       
   148 		; load
       
   149 		ld			r16, X
       
   150 
       
   151 		; output full row-enable bitmask
       
   152 		rcall		SPI_Wait
       
   153 		out			SPDR, r16
       
   154 
       
   155 	; Update col bit
       
   156 		lds			r16, matrix_colbit
       
   157 	
       
   158 		; shift left
       
   159 		lsl			r16
       
   160 		brcc		m_sc_colout
       
   161 
       
   162 		; overflow, take bit from C
       
   163 		rol			r16
       
   164 
       
   165 m_sc_colout:
       
   166 		; store
       
   167 		sts			matrix_colbit, r16
       
   168 
       
   169 	; End of packet
       
   170 		rcall		SPI_Wait
       
   171         sbi         SPI_PORT, SPI_SS
       
   172 
       
   173 	; Done
       
   174         pop         r17
       
   175         pop         r16
       
   176 
       
   177 		ret
       
   178 
       
   179 ;; Scan the matrix once in one go
       
   180 ;; XXX: doesn't support colshift
       
   181 Matrix_ScanFull:
       
   182 	; Row index
       
   183 		ldi			ZL, low(matrix_colbuf)
       
   184 		ldi			ZH, high(matrix_colbuf)
       
   185 
       
   186 	; Column bit
       
   187 		ldi			r25, 0
       
   188 		sec								; set C
       
   189 		
       
   190 m_pulse_col:
       
   191 		; rotate bit left from C
       
   192 		rol			r25
       
   193 		
       
   194 		; overflow
       
   195 		brcs		m_pulse_end
       
   196 		
       
   197 		; store in output buffer
       
   198 		sts			spi_outbuf + 1, r25
       
   199 
       
   200 	; Row mask
       
   201 		ld			r16, Z+
       
   202 
       
   203 		sts			spi_outbuf + 0, r16
       
   204 
       
   205 	; Display
       
   206 		rcall		SPI_SendRecv
       
   207 
       
   208 	; Next column
       
   209 		rjmp		m_pulse_col
       
   210 
       
   211 m_pulse_end:
       
   212 	; Done
       
   213 		ret
       
   214 
       
   215 ;; Reset the viewport to the start (left edge) of the framebuffer
       
   216 Matrix_ShiftZero:
       
   217     ; Constant offset
       
   218         ldi         r16, 0
       
   219 
       
   220     ; Set
       
   221         rjmp        Matrix_ShiftSet
       
   222 
       
   223 ;; Shift the viewport one column to the left in the framebuffer, looping around to the end of the framebuffer
       
   224 ; This moves the visible output one column to the right
       
   225 Matrix_ShiftLeft:
       
   226     ; Decrement-loop current value
       
   227         ; current value
       
   228         lds         r16, matrix_colshift
       
   229 
       
   230         ; shift window left
       
   231         dec         r16
       
   232 
       
   233         ; test for underflow (MSB/N set) -> don't skip reset
       
   234         brpl        Matrix_ShiftSet
       
   235 
       
   236         ; reset window to right edge
       
   237         ldi         r16, MATRIX_BUF_COLS - MATRIX_COLS
       
   238 
       
   239     ; Set
       
   240         rjmp        Matrix_ShiftSet
       
   241 
       
   242 ;; Shift the viewport one column to the right in the framebuffer, looping around to the start of the FB
       
   243 ; This moves the visible output one column to the left
       
   244 Matrix_ShiftRight:
       
   245     ; Increment-loop current value
       
   246         ; current value
       
   247         lds         r16, matrix_colshift
       
   248 
       
   249         ; shift window right
       
   250         inc         r16
       
   251 
       
   252         ; test for overflow -> don't skip reset
       
   253         cpi         r16, MATRIX_BUF_COLS - MATRIX_COLS
       
   254         brlt        Matrix_ShiftSet
       
   255 
       
   256         ; reset window to left edge
       
   257         ldi         r16, 0
       
   258 
       
   259     ; Set
       
   260         rjmp        Matrix_ShiftSet
       
   261 
       
   262 ;; Set the matrix viewport offset
       
   263 ;; Input: r16
       
   264 Matrix_ShiftSet:
       
   265         ; store new value
       
   266         sts         matrix_colshift, r16
       
   267 
       
   268         ; done
       
   269         ret
       
   270 
       
   271 ;; Rewinds the currently visible viewport to the beginning of the framebuffer
       
   272 ; This copies the currently visible viewport data to the beginning of the framebuffer and resets the offset
       
   273 Matrix_ShiftRewind:
       
   274         ; current view offset
       
   275         ldi         XL, low(matrix_colbuf)
       
   276         ldi         XH, high(matrix_colbuf)
       
   277 
       
   278         ; offset
       
   279         lds         r16, matrix_colshift
       
   280 
       
   281         ; add
       
   282         ldi         r17, 0
       
   283         add         XL, r16
       
   284         adc         XH, r17
       
   285 
       
   286         ; start of framebuffer
       
   287         ldi         YL, low(matrix_colbuf + 0)
       
   288         ldi         YH, high(matrix_colbuf + 0)
       
   289 
       
   290         ; viewport width
       
   291         ldi         r17, MATRIX_COLS
       
   292 
       
   293 matrix_shiftrew_loop:
       
   294         ; copy
       
   295         ld          r16, X+
       
   296         st          Y+, r16
       
   297 
       
   298         ; count
       
   299         dec         r17
       
   300         brne        matrix_shiftrew_loop
       
   301 
       
   302         ; done, reset offset
       
   303         rjmp        MAtrix_ShiftZero
       
   304 
       
   305 
       
   306 ;; Load a NUL-terminated ASCII string from PGM into the text buffer
       
   307 ; Input:    Z       - Address of NUL-terminated ASCII string in PGM        
       
   308 Text_LoadString:
       
   309     ; Setup
       
   310         ; storage buffer
       
   311         ldi         YL, low(text_buffer)
       
   312         ldi         YH, high(text_buffer)
       
   313 
       
   314         ; max. length
       
   315         ldi         r18, TEXT_MAXLENGTH
       
   316 
       
   317 text_loads_loop:
       
   318     ; Test max length
       
   319         ; count and check for overflow
       
   320         dec         r18
       
   321         brne        text_loads_char
       
   322 
       
   323     ; Load char
       
   324         ; force NUL
       
   325         ldi         r16, 0x00
       
   326 
       
   327 text_loads_char:
       
   328         ; load next char
       
   329         lpm         r16, Z+
       
   330 
       
   331 text_loads_store:
       
   332     ; Store and test NUL
       
   333         ; store it
       
   334         st          Y+, r16
       
   335 
       
   336         ; test for NUL
       
   337         tst         r16
       
   338         brne        text_loads_loop
       
   339 
       
   340     ; Update scroll offset
       
   341         ; reset offset
       
   342         ldi         r17, 0
       
   343         sts         text_offset, r17
       
   344 
       
   345         ; done
       
   346         ret
       
   347 
       
   348 ;; Shows the loaded string of ASCII text on the display, scrolling it horizontally
       
   349 ; Uses font.inc for rendering
       
   350 ; XXX: uses blocking timer sleeps and doesn't return until done
       
   351 Text_ShowString:
       
   352     ; Load initial char
       
   353         ldi         XL, low(text_buffer + 0)
       
   354         ldi         XH, high(text_buffer + 0)
       
   355 
       
   356         ; load char
       
   357         ld          r16, X+
       
   358         push        XL
       
   359         push        XH
       
   360 
       
   361         ; one column spacing
       
   362         ldi         YL, low(matrix_colbuf + 1)
       
   363         ldi         YH, high(matrix_colbuf + 1)
       
   364 
       
   365         ; render to framebuffer
       
   366         rcall       Font_Render
       
   367 
       
   368         ; reset viewport
       
   369         rcall       Matrix_ShiftZero
       
   370        
       
   371    ; Load next char
       
   372 text_shows_next:        
       
   373         ; next char
       
   374         pop         XH
       
   375         pop         XL
       
   376         ld          r16, X+
       
   377         push        XL
       
   378         push        XH
       
   379 
       
   380         ; test NUL
       
   381         tst         r16
       
   382         breq        text_shows_end
       
   383 
       
   384         ; offscreen
       
   385         ldi         YL, low(matrix_colbuf + 1 + 6 + 1)
       
   386         ldi         YH, high(matrix_colbuf + 1 + 6 + 1)
       
   387 
       
   388         ; render
       
   389         rcall       Font_Render
       
   390 
       
   391     ; Animate to next char
       
   392         ldi         r20, 7
       
   393         
       
   394 text_shows_animloop:
       
   395         ; sleep
       
   396         ldi         XH, high(TEXT_SPEED * 1024)
       
   397         ldi         XL, low(TEXT_SPEED * 1024)
       
   398 
       
   399         rcall       Timer_Sleep
       
   400 
       
   401         ; shift
       
   402         rcall       Matrix_ShiftRight
       
   403 
       
   404         ; count
       
   405         dec         r20
       
   406         brne        text_shows_animloop
       
   407 
       
   408     ; Rewind to next char
       
   409         rcall       Matrix_ShiftRewind
       
   410 
       
   411         sbi         PIND, PIND7
       
   412 
       
   413         ; load next char and animate it in
       
   414         rjmp        text_shows_next
       
   415 
       
   416 text_shows_end:
       
   417     ; Done
       
   418         pop         XH
       
   419         pop         XL
       
   420 
       
   421 
       
   422     ; Clear second frame
       
   423         ldi         YL, low(matrix_colbuf + 16)
       
   424         ldi         YH, high(matrix_colbuf + 16)
       
   425         ldi         r16, MATRIX_COLS
       
   426         ldi         r17, 0
       
   427 
       
   428 text_shows_end2:        
       
   429         st          -Y, r17
       
   430 
       
   431         dec         r16
       
   432         brne        text_shows_end2
       
   433 
       
   434     ; Blink
       
   435 text_shows_end3:        
       
   436         ; on
       
   437         ldi         r16, 0
       
   438         rcall       Matrix_ShiftSet
       
   439 
       
   440         ; sleep
       
   441         ldi         XH, high(TEXT_SPEED * 6 * 1024)
       
   442         ldi         XL, low(TEXT_SPEED * 6 * 1024)
       
   443 
       
   444         rcall       Timer_Sleep
       
   445 
       
   446         ; off        
       
   447         ldi         r16, 8
       
   448         rcall       Matrix_ShiftSet
       
   449 
       
   450         ; sleep
       
   451         ldi         XH, high(TEXT_SPEED * 6 * 1024)
       
   452         ldi         XL, low(TEXT_SPEED * 6 * 1024)
       
   453 
       
   454         rcall       Timer_Sleep
       
   455 
       
   456         ; loop
       
   457         rjmp        text_shows_end3
       
   458 
       
   459     ; XXX: end
       
   460         ret
       
   461