# HG changeset patch # User Tero Marttila # Date 1273092218 -10800 # Node ID 0584de343264c6d2a819e37b582d4c716b7c4c92 # Parent f7bdcc9806e67612abc66e112c5b0bb82b82e939 SPI/LCD thingie diff -r f7bdcc9806e6 -r 0584de343264 hw.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 diff -r f7bdcc9806e6 -r 0584de343264 led7seg.s --- /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 +