Files
aqhomecontrol/avr/modules/uart_hw/uart.asm
Martin Preuss b730fd068c fixed apidoc.
2025-05-24 17:25:00 +02:00

302 lines
6.7 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. *
; ***************************************************************************
; ***************************************************************************
; defines
.equ UART_ERROR_NOTFORME = 1
.equ UART_ERROR_INVALID = 2
.equ UART_ERROR_IO = 3
.equ UART_ERROR_CONTENT = 4
; ***************************************************************************
; code
.cseg
UART_Init:
; set baudrate
.if clock == 8000000
ldi r16, 25 ; (19.2Kb/s at 8MHz)
ldi r17, 0
.endif
.if clock == 1000000
ldi r16, 2 ; (19.2Kb/s at 1MHz)
ldi r17, 0
.endif
M_IO_WRITE UBRRH, r17
M_IO_WRITE UBRRL, r16
; set character format
.ifdef URSEL
ldi r16, (1<<URSEL) | (1<<USBS) | (1<<UCSZ1) | (1<<UCSZ0)
.else
ldi r16, (1<<USBS) | (1<<UCSZ1) | (1<<UCSZ0)
.endif
M_IO_WRITE UCSRC, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine UART_SendBytes @global
;
; @param X pointer data to send (in RAM)
; @param r17 number of bytes to send
; @clobbers R16, R17, X
UART_SendBytes:
tst r17
breq UART_SendBytes_secRet
rcall UART_StartTx ; (R16)
; send bytes
UART_SendBytes_loop1:
M_IO_READ r16, UCSRA
sbrs r16, UDRE
rjmp UART_SendBytes_loop1
ld r16, X+
M_IO_WRITE UDR, r16
dec r17
brne UART_SendBytes_loop1
; wait until all data sent
UART_SendBytes_loop2:
M_IO_READ r16, UCSRA
sbrs r16, TXC
rjmp UART_SendBytes_loop2
rcall UART_StopTx
UART_SendBytes_secRet:
sec
ret
; @end
; ---------------------------------------------------------------------------
; @routine UART_RecvPacket @global
;
; @param X pointer buffer (in RAM)
; @param r17 maximum number of bytes to receive
; @param r18 network address to listen to
; @clobbers r16, r17, X
UART_RecvPacket:
cpi r17, 3
brcs UART_RecvPacket_invalid
rcall uartRecvByteWithin10ms ; recv destination address
brcc UART_RecvPacket_ioError
cp r16, r18
breq UART_RecvPacket_forMe
cpi r16, 0xff
breq UART_RecvPacket_forMe
ldi r16, UART_ERROR_NOTFORME
rjmp UART_RecvPacket_clcRet
UART_RecvPacket_forMe:
st X+, r16 ; dest addr
dec r17
rcall uartRecvByteWithin10ms ; msg len (R16)
brcc UART_RecvPacket_ioError
st X+, r16
dec r17
inc r16 ; account for CRC
cp r17, r16
brcs UART_RecvPacket_badMsg
mov r17, r16
UART_RecvPacket_loop:
rcall uartRecvByteWithin10ms ; (R16)
brcc UART_RecvPacket_ioError
st X+, r16
dec r17
brne UART_RecvPacket_loop
sec
ret
UART_RecvPacket_invalid:
ldi r16, UART_ERROR_INVALID
rjmp UART_RecvPacket_clcRet
UART_RecvPacket_badMsg:
ldi r16, UART_ERROR_CONTENT
rjmp UART_RecvPacket_clcRet
UART_RecvPacket_ioError:
ldi r16, UART_ERROR_IO
UART_RecvPacket_clcRet:
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine uartRecvByteWithin10ms
;
; 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: none
uartRecvByteWithin10ms:
push r20
push r22
rcall uartWaitForData10ms ; (R20, R22)
pop r22
pop r20
brcc uartRecvByteWithin10ms_end
M_IO_READ r16, UCSRA ; check for errors
andi r16, (1<<FE) | (1<<DOR)
brne uartRecvByteWithin10ms_error
M_IO_READ r16, UDR ; read data byte
sec
ret
uartRecvByteWithin10ms_error:
clc
uartRecvByteWithin10ms_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine uartWaitForData10ms
;
; Wait for incoming data for max 10 milliseconds.
;
; @return CFLAG set if okay (data available), cleared on error
; @clobbers: r20, r22
uartWaitForData10ms:
.if clock == 8000000
ldi r20, 80
.endif
.if clock == 1000000
ldi r20, 10
.endif
uartWaitForData10ms_loop:
push r20
rcall uartWaitForData1000Cycles ; (r20, r22)
pop r20
brcs uartWaitForData10ms_gotit
dec r20
brne uartWaitForData10ms_loop
clc
uartWaitForData10ms_gotit:
ret
; @end
; ---------------------------------------------------------------------------
; @routine uartWaitForData1000Cycles
;
; 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
uartWaitForData1000Cycles:
ldi r20, 140 ; 1
uartWaitForData_loop:
M_IO_READ r22, UCSRA ; 2
sbrc r22, RXC ; 2/3
rjmp uartWaitForData_gotit ; 2
dec r20 ; 1
brne uartWaitForData_loop ; 1/2 -> 7 per loop, max about 1000
clc ; 1
ret ; 4
uartWaitForData_gotit:
sec ; 1
ret ; 4
; @end
; ---------------------------------------------------------------------------
; @routine UART_StartRx @global
;
; @clobbers R16
UART_StartRx:
M_IO_READ r16, UCSRA ; clear errors
cbr r16, (1<<FE) | (1<<DOR) | (1<<UPE)
sbr r16, (1<<RXC)
M_IO_WRITE UCSRA, r16
M_IO_READ r16, UCSRB
sbr r16, (1<<RXEN) ; enable receive
M_IO_WRITE UCSRB, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine UART_StopRx @global
;
; @clobbers R16
UART_StopRx:
M_IO_READ r16, UCSRB
cbr r16, (1<<RXCIE | (1<<RXEN)) ; disable RX complete interrupt, disable receive
M_IO_WRITE UCSRB, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine UART_StartTx @global
;
; @param Y pointer to interface data in SRAM (see @ref UART_HW_IFACE_OFFS_STATE)
; @clobbers R16
UART_StartTx:
M_IO_READ r16, UCSRA
sbr r16, (1<<TXC) ; clear TXC interrupt
M_IO_WRITE UCSRA, r16
M_IO_READ r16, UCSRB
sbr r16, (1<<TXEN) ; enable transceive
M_IO_WRITE UCSRB, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine UART_StopTx @global
;
; @param Y pointer to interface data in SRAM (see @ref UART_HW_IFACE_OFFS_STATE)
; @clobbers R16
UART_StopTx:
M_IO_READ r16, UCSRB
cbr r16, (1<<UDRIE) | (1<<TXC) | (1<<TXEN) ; disable TX UDRE and TXC1 interrupt, enable transceive
M_IO_WRITE UCSRB, r16
ret
; @end