SPI/LCD thingie
authorTero Marttila <terom@fixme.fi>
Wed, 05 May 2010 23:43:38 +0300
changeset 3 0584de343264
parent 2 f7bdcc9806e6
child 4 b45780fbd7e8
SPI/LCD thingie
hw.S
led7seg.s
--- a/hw.S	Wed May 05 17:33:30 2010 +0300
+++ b/hw.S	Wed May 05 23:43:38 2010 +0300
@@ -20,8 +20,8 @@
 
     ; Setup Timer 0
         ; Count to 64k
-        ldi         r18, HIGH(0xffff)
-        ldi         r19, LOW(0xffff)
+        ldi         r18, HIGH(0xffff/2)
+        ldi         r19, LOW(0xffff/2)
         sts         OCR1AH, r18
         sts         OCR1AL, r19
  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/led7seg.s	Wed May 05 23:43:38 2010 +0300
@@ -0,0 +1,199 @@
+.nolist
+.include "m168def.inc"      ; Same family as 328P
+.list
+
+;; Interrupt Vector
+.org 0x00
+        rjmp        init
+
+.org SPIaddr
+        rjmp        SPI_Interrupt
+
+;; SPI
+.equ SPI_DDR    = DDRB
+.equ SPI_PORT   = PORTB
+.equ SPI_SCK    = PORTB5
+.equ SPI_MISO   = PORTB4
+.equ SPI_MOSI   = PORTB3
+.equ SPI_SS     = PORTB2
+
+.equ SPI_FLAGS  = GPIOR0
+.equ SPI_BUSY   = 0
+
+;; Initialize SPI subsystem for master operation
+SPI_Init:
+    ; Set modes
+        sbi         SPI_DDR, SPI_SCK        ; Out
+        sbi         SPI_DDR, SPI_MOSI       ; Out
+        sbi         SPI_DDR, SPI_SS         ; Out
+
+    ; Drive SS high (off)
+        sbi         SPI_PORT, SPI_SS
+
+    ; Set control mode
+        ; Enable interrupt
+        ; Enable SPI
+        ; MSB first
+        ; Master mode
+        ; Polarity/phase: Mode 0 (sample on rising edge)
+        ; Clock rate 1/16
+        ldi         r16, (1 << SPIE) | (1 << SPE) | (0 << DORD) | (1 << MSTR) | (0 << CPOL) | (0 << CPHA) | (0b01 << SPR0)
+        out         SPCR, r16
+    
+    ; Flags
+        clr         r0
+        out         SPI_FLAGS, r0
+    
+    ; Done
+        ret
+
+;; Send byte
+;;  Input: r16
+;;  XXX: should not be busy...
+SPI_Send:
+    ; Flag
+        sbi         SPI_FLAGS, SPI_BUSY
+
+    ; Enable slave (low)
+        cbi         SPI_PORT, SPI_SS
+    
+    ; Write byte (starts SCK)
+        out         SPDR, r16
+    
+    ; Wait for interrupt
+    ; Done
+        ret
+
+;; Wait for byte to be sent
+SPI_Wait:
+wait_idle:
+        sbic        SPI_FLAGS, SPI_BUSY     ; Test for busy flag
+        rjmp        wait_idle               ; loop
+        
+    ; Done
+        ret
+
+;; Service SPI interrupt
+SPI_Interrupt:
+    ; Store SREG
+        in          r16, SREG
+
+    ; Drive SS high (off)
+        sbi         SPI_PORT, SPI_SS
+
+    ; Flag
+        cbi         SPI_FLAGS, SPI_BUSY
+
+    ; Done
+        out         SREG, r16
+        reti
+
+;; LCD
+.equ LCD_DDR    = DDRB
+.equ LCD_PORT   = PORTB
+.equ LCD_OE     = PORTB1                ; Output Enable (Low)
+
+; Output font for 7-segment display
+LCD_Font:
+.db     0b00111111, 0b00000110      ; 0, 1
+.db     0b01011011, 0b01001111      ; 2, 3
+.db     0b01100110, 0b01101101      ; 4, 5
+.db     0b01111101, 0b00000111      ; 6, 7
+.db     0b01111111, 0b01100111      ; 8, 9
+.db     0b10000000, 0b00000000      ; ., 
+
+;.db     0b00111111,     ; 0
+;        0b00000110,     ; 1
+;        0b01011011,     ; 2
+;        0b01001111,     ; 3
+;        0b01100110,     ; 4
+;        0b01101101,     ; 5
+;        0b01111101,     ; 6
+;        0b00000111,     ; 7
+;        0b01111111,     ; 8
+;        0b01100111,     ; 9
+;        0b10000000,     ; .
+;        0b01000000      ; 
+
+.equ LCD_0      = 0
+.equ LCD_1      = 1
+.equ LCD_2      = 2
+.equ LCD_3      = 3
+.equ LCD_4      = 4
+.equ LCD_5      = 5
+.equ LCD_6      = 6
+.equ LCD_7      = 7
+.equ LCD_8      = 8
+.equ LCD_9      = 9
+.equ LCD_DOT    = 10
+.equ LCD_EMPTY  = 11
+
+;; Initialize LCD to empty, and enable
+LCD_Init:
+    ; Setup ENable port
+        sbi         LCD_PORT, LCD_OE    ; Disabled (Low)
+        sbi         LCD_DDR, LCD_OE     ; Out
+
+        ; empty
+        ldi         r16, 0b11111111
+
+    ; Output
+        rcall       SPI_Send
+        rcall       SPI_Wait
+
+    ; Enable
+        cbi         LCD_PORT, LCD_OE
+
+    ; Done
+        ret
+
+;; Display a single digit on the display
+;;  Input: r16
+LCD_Show:
+        clr         r0, 0
+
+    ; Prep address
+        ; base addr for font table
+        ldi         ZH, high(2*LCD_Font)
+        ldi         ZL, low(2*LCD_Font)
+        
+        ; offset
+        add         ZL, r16
+        adc         ZH, r0
+
+    ; Load char
+        lpm         r16, Z
+
+    ; Invert
+        com         r16
+
+    ; Display
+        rcall        SPI_Send
+    
+    ; Done
+        ret
+
+init:
+    ; Stack
+        ldi         r16, high(RAMEND)
+        ldi         r17, low(RAMEND)
+        out         SPH, r16
+        out         SPL, r17
+
+    ; Enable interrupts
+        sei
+
+    ; SPI
+        rcall       SPI_Init
+    
+    ; LCD (requires interrupts)
+        rcall       LCD_Init    
+
+main:
+    ; Output something
+        ldi         r16, LCD_4
+        rcall       LCD_Show
+
+loop:
+        rjmp        loop
+