led7seg.s
author Tero Marttila <terom@fixme.fi>
Wed, 05 May 2010 23:54:50 +0300
changeset 4 b45780fbd7e8
parent 3 0584de343264
child 6 88c930373d62
permissions -rw-r--r--
count down a and blink \o/
.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

;; Delay for approx. 1s
Delay_1s:
        ; 20 * 255 * 255 = 1.3M cycles
        ldi         r20, 40
        ldi         r21, 255
        ldi         r22, 255

delay:
        dec         r22
        brne        delay
        dec         r21
        brne        delay
        dec         r20
        brne        delay

        ret


Main:
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    

;; Count down from 9
count:
        ; init from 9
        ldi         r24, LCD_9

loop:
        ; display
        mov         r16, r24
        rcall       LCD_Show

        ; exit if zero
        tst         r24
        breq        blink

        ; count down
        dec         r24

        ; wait...
        rcall        Delay_1s

        ; next
        rjmp        loop
   
;; Blink between dot and empty
blink:
        rcall       Delay_1s
        
        ; dot
        ldi         r16, LCD_DOT
        rcall       LCD_Show

        ; wait...
        rcall       Delay_1s
        
        ; empty
        ldi         r16, LCD_EMPTY
        rcall       LCD_Show
        
        ; loop
        rjmp        blink

end:
        rjmp        end