console.s
author Tero Marttila <terom@paivola.fi>
Mon, 21 Apr 2014 00:20:27 +0300
changeset 82 b5878197d017
parent 18 79b25e81721f
permissions -rw-r--r--
dmx-web: change dmx layout for more light types
.nolist
.include "m168def.inc"      ; Same family as 328P
.list

.include "macros.inc"

;; Load a 16-bit *word* address into the given register a a byte address
.macro loadp_16_i
		ldi			@0, high(2 * @2)
		ldi			@1, low(2 * @2)
.endm

.macro load_16_i
		ldi			@0, high(@2)
		ldi			@1, low(@2)
.endm

;; Data
.dseg
buffer:	.byte 0

;; Interrupt Vector
.cseg
.org 0x0000
        rjmp        Main

;; Libraries
.include "div.inc"			; Division routines

;; Serial
.set SERIAL_BAUD = 103		; 9.6k @ 16Mhz

;; Initialize the UART for 
Serial_Init:
	; Set up control registers
		; Single-speed
		poke		[UCSR0A, r16, (0 << U2X0)]

		; Async
		; n parity
		; 1 stop
		; 8 bits
		poke		[UCSR0C, r16, (0b00 << UMSEL00) | (0b00 << UPM00) | (0 << USBS0) | (0b11 << UCSZ00)]

		; Baud rate
		poke		[UBRR0L, r16:r17, SERIAL_BAUD]
		
		; Enable RX
		; Enable TX
		; 8 bits
		poke		[UCSR0B, r16, (1 << RXEN0) | (1 << TXEN0) | (0 << UCSZ02)]
		
	; Done
		ret

;; Send a single byte on serial port
; Input byte in r16
Serial_Send:
	; Wait for idle
		lds			r0, UCSR0A
		sbrs		r0, UDRE0
		rjmp		Serial_Send

	; Copy byte to buffer
		sts			UDR0, r16

	; Done
		ret

;; Read a single byte from serial port
; Output byte in r16
Serial_Recv:
	; Wait for recv
		lds			r0, UCSR0A
		sbrs		r0, RXC0
		rjmp		Serial_Recv

	; Copy byte from buffer
		lds			r16, UDR0

	; Done
		ret

;; Write nul-terminated string from program mem to serial port
; Input string in Z
Serial_pprint:
	; Load byte to r16
		lpm			r16, Z+

	; Quit if nul
		tst			r16
		breq		_serial_pprint_end

	; Write it
		rcall		Serial_Send

	; Continue
		rjmp		Serial_pprint

_serial_pprint_end:
		ret

;; Write nul-terminated string from sram and \r\n to serial port
; Input string in Z
Serial_sprintln:
	; Load byte to r16
		ld			r16, Z+

	; Quit if nul
		tst			r16
		breq		_serial_sprintln_end

	; Write it
		rcall		Serial_Send

	; Continue
		rjmp		Serial_sprintln

_serial_sprintln_end:
	; \r\n
		ldi			r16, 13
		rcall		Serial_Send
		ldi			r16, 10
		rcall		Serial_Send

	; Done
		ret

;; Write char to serial port
; Input byte in r16
Serial_bprint:
		; ASCII offset for '0'
		ldi			r17, 48
		mov			r4, r17	
	
	; Convert
		ldi			r17, 100
		call		div8u
		add			r16, r4
		rcall		Serial_Send
		mov			r16, r15

		ldi			r17, 10
		call		div8u
		add			r16, r4
		rcall		Serial_Send
		mov			r16, r15

		add			r16, r4
		rcall		Serial_Send
		
	ret

;; Program
message:	.db "Hello World", 13, 10, 0

Main:
; Initialization
	; Stack
		poke		[SPL, r16:r17, RAMEND]

    ; Enable interrupts
        sei

	; Init
		rcall		Serial_Init

; Main program
		ldi			ZH, high(message * 2)
		ldi			ZL, low(message * 2)
		
		rcall		Serial_pprint

; Echo out
		sbi			DDRB, PORTB5
		ldi			r20, 0
		ldi			r21, 0
		ldi			r22, 0
		
		; pointer to memory buffer
		ldi			XH, high(buffer)
		ldi			XL, low(buffer)

		st			X, r22		; '\0'

Main_Echo:
		; blink LED
		out			PORTB, r20
		
		; read
		rcall		Serial_Recv
		push		r16
		
		; display
		rcall		Serial_bprint
		ldi			r16, 32
		rcall		Serial_Send

		pop			r16

		; test for control chars
		cpi			r16, 127	; DEL
		breq		backspace

		cpi			r16, 13		; '\r'
		breq		cr

		cpi			r16, 10		; '\n'
		breq		Main_Echo	; ignore

		rjmp		char		; buffer char

; Erase last char
backspace:
		; ignore if already at zero
		cpi			XL, low(buffer)
		ldi			r23, high(buffer)
		cpc			XH, r23
		breq		echo

		; use pre-decrement to store nul
		st			-X, r22		; '\0'

		rjmp		echo

; Erase line
cr:
		; seek to start
		ldi			XH, high(buffer)
		ldi			XL, low(buffer)
		
		; store nul
		st			X, r22		; '\0'

		rjmp 		echo

char:
		; buffer char
		st			X+, r16
		st			X, r22		; '\0'

echo:		
		; running counter
		inc			r21
		mov			r16, r21
		rcall		Serial_bprint
		
		; ' '
		ldi			r16, 32
		rcall		Serial_Send

		; length
		mov			r16, XL
		rcall		Serial_bprint

		; ' '
		ldi			r16, 32
		rcall		Serial_Send
		
		; output buffer
		ldi			ZH, high(buffer)
		ldi			ZL, low(buffer)
		rcall		Serial_sprintln
		
		; toggle
		com			r20
		
		; continue
		rjmp		Main_Echo