399 lines
8.5 KiB
NASM
399 lines
8.5 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_RINGBUFFER_IN_SIZE = 24
|
|
.equ UART_RINGBUFFER_OUT_SIZE = 24
|
|
|
|
|
|
.equ UART_FLAGS_TXEN_BIT = 7
|
|
.equ UART_FLAGS_RXEN_BIT = 6
|
|
.equ UART_FLAGS_HWOVERRUN_BIT = 5
|
|
.equ UART_FLAGS_FRAMEERROR_BIT = 4
|
|
.equ UART_FLAGS_SWOVERRUN_BIT = 3
|
|
.equ UART_FLAGS_SWUNDERRUN_BIT = 2
|
|
.equ UART_FLAGS_LASTBYTESENT_BIT = 1
|
|
|
|
|
|
|
|
; ***************************************************************************
|
|
; data
|
|
|
|
.dseg
|
|
|
|
uartFlags: .byte 1
|
|
uartRingbufferIn: .byte RINGBUFFERY_SIZE+UART_RINGBUFFER_IN_SIZE
|
|
uartRingbufferOut: .byte RINGBUFFERY_SIZE+UART_RINGBUFFER_OUT_SIZE
|
|
|
|
|
|
; ***************************************************************************
|
|
; code
|
|
|
|
.cseg
|
|
|
|
|
|
|
|
UART_Init:
|
|
clr r16
|
|
sts uartFlags, r16
|
|
|
|
ldi r16, UART_RINGBUFFER_IN_SIZE
|
|
ldi yl, LOW(uartRingbufferIn)
|
|
ldi yh, HIGH(uartRingbufferIn)
|
|
rcall RingBufferY_Init
|
|
|
|
ldi r16, UART_RINGBUFFER_OUT_SIZE
|
|
ldi yl, LOW(uartRingbufferOut)
|
|
ldi yh, HIGH(uartRingbufferOut)
|
|
rcall RingBufferY_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_StartRx @global
|
|
;
|
|
; @clobbers R16
|
|
|
|
UART_StartRx:
|
|
; clear read error flags
|
|
lds r16, uartFlags
|
|
cbr r16, (1<<UART_FLAGS_HWOVERRUN_BIT) | (1<<UART_FLAGS_FRAMEERROR_BIT) | (1<<UART_FLAGS_SWOVERRUN_BIT)
|
|
sbr r16, (1<<UART_FLAGS_RXEN_BIT)
|
|
sts uartFlags, r16
|
|
|
|
M_IO_READ r16, UCSRA ; clear errors
|
|
cbr r16,(1<<RXC) | (1<<FE) | (1<<DOR) | (1<<UPE)
|
|
M_IO_WRITE UCSRA, r16
|
|
|
|
M_IO_READ r16, UCSRB
|
|
sbr r16, (1<<RXCIE) | (1<<RXEN) ; enable RX complete interrupt, enable receive
|
|
M_IO_WRITE UCSRB, r16
|
|
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine UART_StopRx @global
|
|
;
|
|
; @clobbers R16
|
|
|
|
UART_StopRx:
|
|
lds r16, uartFlags
|
|
cbr r16, (1<<UART_FLAGS_RXEN_BIT)
|
|
sts uartFlags, r16
|
|
|
|
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:
|
|
; clear write error flags
|
|
lds r16, uartFlags
|
|
cbr r16, (1<<UART_FLAGS_SWUNDERRUN_BIT) | (1<<UART_FLAGS_LASTBYTESENT_BIT)
|
|
sbr r16, (1<<UART_FLAGS_TXEN_BIT)
|
|
sts uartFlags, r16
|
|
|
|
M_IO_READ r16, UCSRA
|
|
cbr r16, (1<<TXC) ; clear TXC interrupt
|
|
M_IO_WRITE UCSRA, r16
|
|
|
|
M_IO_READ r16, UCSRB
|
|
sbr r16, (1<<UDRIE) | (1<<TXC) | (1<<TXEN) ; enable TX UDRE and TXC1 interrupt, 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:
|
|
lds r16, uartFlags
|
|
cbr r16, (1<<UART_FLAGS_TXEN_BIT)
|
|
sts uartFlags, r16
|
|
|
|
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
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine UART_ReadByte @global
|
|
;
|
|
; @return CFLAG on success, cleared on error
|
|
; @return r16 byte read
|
|
; @clobbers (R17, R18, X, Y)
|
|
|
|
UART_ReadByte:
|
|
ldi yl, LOW(uartRingbufferIn)
|
|
ldi yh, HIGH(uartRingbufferIn)
|
|
rjmp RingBufferY_ReadByteGuarded ; (R17, R18, X)
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine UART_WriteByte @global
|
|
;
|
|
; @clobbers (R17, R18, X, Y)
|
|
|
|
UART_WriteByte:
|
|
ldi yl, LOW(uartRingbufferOut)
|
|
ldi yh, HIGH(uartRingbufferOut)
|
|
rjmp RingBufferY_WriteByteGuarded ; (R17, R18, X)
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine UART_ResetWriteBuffer @global
|
|
;
|
|
; @clobbers (R17)
|
|
|
|
UART_ResetWriteBuffer:
|
|
ldi yl, LOW(uartRingbufferOut)
|
|
ldi yh, HIGH(uartRingbufferOut)
|
|
rjmp RingBufferY_Reset ; (R17)
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine UART_GetFlags @global
|
|
;
|
|
; @return r16 flags
|
|
; @clobbers none
|
|
|
|
UART_GetFlags:
|
|
lds r16, uartFlags
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine UART_RxCharIsr @isr
|
|
;
|
|
|
|
UART_RxCharIsr:
|
|
push r15
|
|
in r15, SREG
|
|
push r16
|
|
push r17
|
|
push r18
|
|
push xl
|
|
push xh
|
|
push yl
|
|
push yh
|
|
rcall uartHandleRxChar
|
|
pop yh
|
|
pop yl
|
|
pop xh
|
|
pop xl
|
|
pop r18
|
|
pop r17
|
|
pop r16
|
|
out SREG, r15
|
|
pop r15
|
|
reti
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine UART_TxCharIsr @isr
|
|
;
|
|
|
|
UART_TxCharIsr:
|
|
push r15
|
|
in r15, SREG
|
|
push r16
|
|
rcall uartHandleTxChar ; (R16)
|
|
pop r16
|
|
out SREG, r15
|
|
pop r15
|
|
reti
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine UART_UdreIsr @isr
|
|
;
|
|
|
|
UART_UdreIsr:
|
|
push r15
|
|
in r15, SREG
|
|
push r16
|
|
push r17
|
|
push r18
|
|
push xl
|
|
push xh
|
|
push yl
|
|
push yh
|
|
rcall uartHandleUdre
|
|
pop yh
|
|
pop yl
|
|
pop xh
|
|
pop xl
|
|
pop r18
|
|
pop r17
|
|
pop r16
|
|
out SREG, r15
|
|
pop r15
|
|
reti
|
|
; @end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine uartHandleRxChar
|
|
;
|
|
; @clobbers R16, R17, Y (R18, X)
|
|
|
|
uartHandleRxChar:
|
|
; check for errors
|
|
M_IO_READ r16, UCSRA
|
|
sbrc r16, FE
|
|
rjmp uartHandleRxChar_hwErrFe
|
|
sbrc r16, DOR
|
|
rjmp uartHandleRxChar_hwErrDor
|
|
; have char?
|
|
sbrs r16, RXC
|
|
rjmp uartHandleRxChar_end ; no data
|
|
|
|
; read char
|
|
M_IO_READ r16, UDR ; r16=received char
|
|
|
|
ldi yl, LOW(uartRingbufferIn)
|
|
ldi yh, HIGH(uartRingbufferIn)
|
|
rcall RingBufferY_WriteByte ; (R17, R18, X)
|
|
brcs uartHandleRxChar_end
|
|
lds r16, UART_FLAGS_SWOVERRUN_BIT
|
|
rjmp uartHandleRxChar_storeErrorFlags
|
|
uartHandleRxChar_hwErrFe:
|
|
lds r16, UART_FLAGS_FRAMEERROR_BIT
|
|
rjmp uartHandleRxChar_storeErrorFlags
|
|
uartHandleRxChar_hwErrDor:
|
|
lds r16, UART_FLAGS_HWOVERRUN_BIT
|
|
rjmp uartHandleRxChar_storeErrorFlags
|
|
uartHandleRxChar_storeErrorFlags:
|
|
lds r17, uartFlags
|
|
or r17, r16
|
|
sts uartFlags, r17
|
|
uartHandleRxChar_end:
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine uartHandleUdre
|
|
;
|
|
; @clobbers R16, Y (R17, R18, X)
|
|
|
|
uartHandleUdre:
|
|
M_IO_READ r16, UCSRA
|
|
sbrs r16, UDRE
|
|
; rjmp uartHandleUdre_disableUdre ; not ready, SNH!
|
|
rjmp uartHandleUdre_end ; not ready, SNH!
|
|
ldi yl, LOW(uartRingbufferOut)
|
|
ldi yh, HIGH(uartRingbufferOut)
|
|
rcall RingBufferY_ReadByte ; (R17, R18, X)
|
|
brcc uartHandleUdre_underrun
|
|
M_IO_WRITE UDR, r16
|
|
rjmp uartHandleUdre_end
|
|
uartHandleUdre_underrun:
|
|
lds r16, uartFlags
|
|
sbr r16, (1<<UART_FLAGS_SWUNDERRUN_BIT)
|
|
sts uartFlags, r16
|
|
uartHandleUdre_disableUdre:
|
|
M_IO_READ r16, UCSRB
|
|
cbr r16, (1<<UDRIE) ; disable TX UDRE interrupt
|
|
M_IO_WRITE UCSRB, r16
|
|
uartHandleUdre_end:
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine uartHandleTxChar
|
|
;
|
|
; @clobbers R16
|
|
|
|
uartHandleTxChar:
|
|
lds r16, uartFlags
|
|
sbr r16, (1<<UART_FLAGS_LASTBYTESENT_BIT)
|
|
sts uartFlags, r16
|
|
|
|
M_IO_READ r16, UCSRB
|
|
cbr r16, (1<<TXC) ; disable TXC interrupt
|
|
M_IO_WRITE UCSRB, r16
|
|
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
|