Files
aqhomecontrol/avr/modules/uart_hw/lowlevel_tty.asm
2025-01-25 12:52:24 +01:00

282 lines
6.6 KiB
NASM

; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
.dseg
; uartHw_TtyOn1Interface: .byte UART_HW_IFACE_SIZE
.cseg
; ---------------------------------------------------------------------------
; @routine UART_HW_TtyOn1_Init @global
;
; @param Y pointer to interface data in SRAM (see @ref UART_HW_IFACE_OFFS_STATE)
; @clobbers R16, R17, X
UART_HW_TtyOn1_Init:
rcall UART_HW_InitInterface
; set baudrate
.if clock == 8000000
ldi r16, 25 ; (19.2Kb/s at 8MHz)
ldi r17, 0
.endif
.if clock == 1000000
ldi r16, 3 ; (19.2Kb/s at 1MHz)
ldi r17, 0
.endif
out UBRR1H, r17
out UBRR1L, r16
; set character format
ldi r16, (1<<USBS1)|(3<<UCSZ10)
out UCSR1C, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine UART_HW_TtyOn1_StartRx @global
;
; @clobbers none
UART_HW_TtyOn1_StartRx:
; enable RX complete interrupt
sbi UCSR1B, RXCIE1
; enable receive
sbi UCSR1B, RXEN1
ret
; @end
; ---------------------------------------------------------------------------
; @routine UART_HW_TtyOn1_StopRx @global
;
; @clobbers none
UART_HW_TtyOn1_StopRx:
; disable RX complete interrupt
cbi UCSR1B, RXCIE1
; disable receive
cbi UCSR1B, RXEN1
ret
; @end
; ---------------------------------------------------------------------------
; @routine UART_HW_TtyOn1_StartTx @global
;
; @param Y pointer to interface data in SRAM (see @ref UART_HW_IFACE_OFFS_STATE)
; @clobbers none
UART_HW_TtyOn1_StartTx:
; enable TX data register empty interrupt
sbi UCSR1B, UDRIE1
; enable transmit
sbi UCSR1B, TXEN1
ret
; @end
; ---------------------------------------------------------------------------
; @routine UART_HW_TtyOn1_StopTx @global
;
; @param Y pointer to interface data in SRAM (see @ref UART_HW_IFACE_OFFS_STATE)
; @clobbers none
UART_HW_TtyOn1_StopTx:
; enable TX data register empty interrupt
cbi UCSR1B, UDRIE1
; enable transmit
cbi UCSR1B, TXEN1
ret
; @end
; ---------------------------------------------------------------------------
; @routine UART_HW_TtyOn1_RecvSkipMessage
;
; skip all receiption data until a data pause of about 10ms
;
; @clobbers r16
UART_HW_TtyOn1_RecvSkipMessage:
UART_HW_TtyOn1_RecvSkipMessage_loop:
rcall ttyOn1RecvFlush ; (r16)
; wait for a data pause of 10ms
rcall ttyOn1RecvByteWithin10ms ; (r20, r22)
brcs UART_HW_TtyOn1_RecvSkipMessage_loop
ret
; @end
; ---------------------------------------------------------------------------
; @routine UART_HW_TtyOn1_RxCharIsr @global
;
; @param Y pointer to interface data in SRAM (see @ref UART_HW_IFACE_OFFS_STATE)
; @clobbers R16 (R17, R18, X)
UART_HW_TtyOn1_RxCharIsr:
sbis UCSR1A, RXC1
rjmp UART_HW_TtyOn1_RxCharIsr_end ; no data
in r16, UDR1
rcall UART_HW_InterfaceAddReadByte ; (R17, R18, X)
UART_HW_TtyOn1_RxCharIsr_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine UART_HW_TtyOn1_TxCharIsr @global
;
; @param Y pointer to interface data in SRAM (see @ref UART_HW_IFACE_OFFS_STATE)
; @clobbers R16, X
UART_HW_TtyOn1_TxCharIsr:
sbis UCSR1A,UDRE1
rjmp UART_HW_TtyOn1_TxCharIsr_end ; not ready
ldd r16, Y+UART_HW_IFACE_OFFS_WRITEBUFFERNUM
cpi r16, 0xff
breq UART_HW_TtyOn1_TxCharIsr_end ; no current write buffer
ldd r16, Y+UART_HW_IFACE_OFFS_WRITEBUFFERLEFT
tst r16
breq UART_HW_TtyOn1_TxCharIsr_end ; nothing to send
dec r16
std Y+UART_HW_IFACE_OFFS_WRITEBUFFERLEFT, r16
ldd xl, Y+UART_HW_IFACE_OFFS_WRITEBUFFERPTR
ldd xh, Y+UART_HW_IFACE_OFFS_WRITEBUFFERPTR+1
ld r16, X+
std Y+UART_HW_IFACE_OFFS_WRITEBUFFERPTR, xl
std Y+UART_HW_IFACE_OFFS_WRITEBUFFERPTR+1, xh
out UDR1, r16
UART_HW_TtyOn1_TxCharIsr_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ttyOn1RecvFlush
;
; Flush receiption buffer.
;
; @clobbers r16
ttyOn1RecvFlush:
lds r16, UCSR1A ; read status
sbrs r16, RXC1
ret
lds r16, UDR1 ; read data byte
rjmp ttyOn1RecvFlush
; @end
; ---------------------------------------------------------------------------
; @routine ttyOn1RecvByteWithin10ms
;
; Wait up to 10ms for incoming byte and read it.
;
; @return CFLAG set if okay (data available), cleared on error
; @return r16 byte received (if CFLAG set)
; @clobbers: r20, r22
ttyOn1RecvByteWithin10ms:
rcall ttyOn1WaitForData10ms ; (R20, R22)
brcc ttyOn1RecvByteWithin10ms_end
lds r16, UCSR1A ; check for errors
andi r16, (1<<FE1) | (1<<DOR1) | (1<<UPE1)
brne ttyOn1RecvByteWithin10ms_error
lds r16, UDR1 ; read data byte
sec
ret
ttyOn1RecvByteWithin10ms_error:
clc
ttyOn1RecvByteWithin10ms_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ttyOn1WaitForData10ms
;
; Wait for incoming data for max 10 milliseconds.
;
; @return CFLAG set if okay (data available), cleared on error
; @clobbers: r20, r22
ttyOn1WaitForData10ms:
.if clock == 8000000
ldi r20, 80
.endif
.if clock == 1000000
ldi r20, 10
.endif
ttyOn1WaitForData10ms_loop:
push r20
rcall ttyOn1WaitForData1000Cycles ; (r20, r22)
pop r20
brcs ttyOn1WaitForData10ms_gotit
dec r20
brne ttyOn1WaitForData10ms_loop
clc
ttyOn1WaitForData10ms_gotit:
ret
; @end
; ---------------------------------------------------------------------------
; @routine ttyOn1WaitForData1000Cycles
;
; Wait for incoming data for max 1000 clock cycles
; (about 1ms at 1MHz, 0.125 at 8MHz)
;
; @return CFLAG set if okay (packet received), cleared on error
; @clobbers: r20, r22
ttyOn1WaitForData1000Cycles:
ldi r20, 140 ; 1
ttyOn1WaitForData_loop:
lds r22, UCSR1A ; 2
sbrc r22, RXC1 ; 2/3
rjmp ttyOn1WaitForData_gotit ; 2
dec r20 ; 1
brne ttyOn1WaitForData_loop ; 1/2 -> 7 per loop, max about 1000
clc ; 1
ret ; 4
ttyOn1WaitForData_gotit:
sec ; 1
ret ; 4
; @end