started reorganizing code into subfolders.

This commit is contained in:
Martin Preuss
2023-04-22 00:04:10 +02:00
parent 97016b21b9
commit 5e12b8ad4e
40 changed files with 38 additions and 60 deletions

View File

@@ -0,0 +1,180 @@
; ***************************************************************************
; copyright : (C) 2023 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
; ***************************************************************************
; data
.dseg
bmp280DataBegin:
bmp280Id: .byte 1
bmp280DataEnd:
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; BMP280_Init
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear on error
; USED:
BMP280_Init:
ldi xh, HIGH(bmp280DataBegin)
ldi xl, LOW(bmp280DataBegin)
clr r16
ldi r17, (bmp280DataEnd-bmp280DataBegin)
rcall Utils_FillSram
rcall bmp280ReadId
brcc BMP280_Init_error
sts bmp280Id, r16 ; store id
sec
ret
BMP280_Init_error:
clc
ret
; ---------------------------------------------------------------------------
; BMP280_Fini
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear on error
; USED:
BMP280_Fini:
sec
ret
; ---------------------------------------------------------------------------
; bmp280ReadId
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear on error
; - R16 : id (most probably 0x60)
; USED: R15, R16 (R17, R18, R22)
bmp280ReadId:
ldi r16, 0xd0
rjmp bmp280ReadSingleReg
; ---------------------------------------------------------------------------
; bmp280ReadSingleReg
;
; IN:
; - R16: register id
; OUT:
; - CFLAG: set if okay, clear on error
; - R16 : register content
; USED: R1, R15, R16 (R17, R18, R22)
bmp280ReadSingleReg:
in r15, SREG
cli
mov r1, r16
rcall twiStart ; (R22)
ldi r16, (BMP280_ADDR*2) ; start in write mode
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc bmp280ReadSingleReg_error
mov r16, r1 ; register num
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc bmp280ReadSingleReg_error
rcall twiRestart ; (R22)
ldi r16, (BMP280_ADDR*2)+1 ; restart in read mode
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc bmp280ReadSingleReg_error
rcall twiReceiveByteSendAck ; read ID
brcc bmp280ReadSingleReg_error
rcall twiStop ; (R22)
out SREG, r15
sec
ret
bmp280ReadSingleReg_error:
rcall twiStop ; (R22)
out SREG, r15
clc
ret
; ---------------------------------------------------------------------------
; bmp280ReadRegsToSram
;
; IN:
; - X: pointer to buffer to read data in
; - R18: first register to read from
; - R19: number of registers to read
; OUT:
; - CFLAG: set if okay, clear on error
; - R16 : id (most probably 0x60)
; USED: R15, R16 (R17, R18, R22)
bmp280ReadRegsToSram:
in r15, SREG
cli
mov r1, r18
mov r2, r19
rcall twiStart ; (R22)
ldi r16, (BMP280_ADDR*2) ; start in write mode
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc bmp280ReadRegsToSram_error
mov r16, r1 ; first register to read
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc bmp280ReadRegsToSram_error
rcall twiRestart ; (R22)
ldi r16, (BMP280_ADDR*2)+1 ; restart in read mode
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc bmp280ReadRegsToSram_error
bmp280ReadRegsToSram_loop:
rcall twiReceiveByteSendAck ; read register content
brcc bmp280ReadRegsToSram
st x+, r16 ; store register content
dec r2
brne bmp280ReadRegsToSram_loop
rcall twiStop ; (R22)
out SREG, r15
sec
ret
bmp280ReadRegsToSram_error:
rcall twiStop ; (R22)
out SREG, r15
clc
ret

432
avr/modules/com2/com2.asm Normal file
View File

@@ -0,0 +1,432 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ***************************************************************************
; data
.dseg
com2DataBegin:
com2Address: .byte 1
com2Interrupts: .byte 2
com2StatsPacketsIn: .byte 2
com2StatsIoError: .byte 2
com2StatsContentError: .byte 2
com2StatsNoBufferError: .byte 2
com2StatsIgnored: .byte 2
com2StatsHandled: .byte 2
com2StatsMissed: .byte 2 ; currently not used
com2StatsPacketsOut: .byte 2
com2StatsBusyError: .byte 2
com2StatsCollisions: .byte 2
com2RecvBuffersUsed: .byte 1
com2MaxBuffersUsed: .byte 1
com2RecvBuffersWritePos: .byte 1
com2RecvBuffersReadPos: .byte 1
com2RecvBuffers: .byte COM2_BUFFER_SIZE*COM2_BUFFER_NUM
com2SendBuffer: .byte COM2_BUFFER_SIZE
com2DataEnd:
; ***************************************************************************
; code
.cseg
COM2_BEGIN:
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Module interface
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; ---------------------------------------------------------------------------
; Com2_Init
;
; IN:
; OUT:
; - CFLAG: set if okay, clear on error
; USED: R16, R17, X, Y
Com2_Init:
; preset SRAM data area
ldi xh, HIGH(com2DataBegin)
ldi xl, LOW(com2DataBegin)
clr r16
ldi r17, (com2DataEnd-com2DataBegin)
rcall Utils_FillSram
; set address to 0 (will be updated later)
clr r16
sts com2Address, r16
; setup pins and interrupts
cbi COM_PORT_DATA, COM_PINNUM_DATA ; disable internal pullup for DATA
cbi COM_DDR_DATA, COM_PINNUM_DATA ; set DATA port as input
cbi COM_PORT_ATTN, COM_PINNUM_ATTN ; disable internal pullup for ATTN
cbi COM_DDR_ATTN, COM_PINNUM_ATTN ; set ATTN port as input
sbi COM_IRQ_ADDR_ATTN, COM_IRQ_BIT_ATTN ; enable pin change irq for ATTN line
in r16, GIMSK ; enable pin change irq PCIE0 or PCIE1
ori r16, (1<<COM_IRQ_GIMSK_ATTN)
out GIMSK, R16
ldi r16, (1<<COM_IRQ_GIFR_ATTN) ; clear pending irq by writing 1 to ATTN bit
out GIFR, r16
sec
ret
; ---------------------------------------------------------------------------
; Com_Run
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if something done, can be called again immediately (otherwise: wait for timer interrupt and retry)
; REGS: (R1, R3, R16, R17, R18, R19, R22, X)
COM2_Run:
rjmp com2HandleNextPacketInQueue
com2HandleNextPacketInQueue:
lds r16, com2RecvBuffersUsed
tst r16
breq com2HandleNextPacketInQueue_retNc ; no buffers in use
lds r16, com2RecvBuffersReadPos
rcall COM2_BufferPosToX ; get current read buffer to X (R16, R17)
rcall onPacketReceived
brcs com2HandleNextPacketInQueue_handled
ldi xl, LOW(com2StatsIgnored)
ldi xh, HIGH(com2StatsIgnored)
rjmp com2HandleNextPacketInQueue_incCounterDeallocBuffer
com2HandleNextPacketInQueue_handled:
ldi xl, LOW(com2StatsHandled)
ldi xh, HIGH(com2StatsHandled)
com2HandleNextPacketInQueue_incCounterDeallocBuffer:
rcall Utils_IncrementCounter16 ; (r18, r19, r22)
rcall COM2_BufferDeallocFront ; (r16, r17, r21)
sec ; always return with set CFLAG
ret
com2HandleNextPacketInQueue_retNc:
clc
ret
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Preparing messages
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; ---------------------------------------------------------------------------
; Write a simple packet into the given buffer with payload being only CMD and source address.
;
; IN:
; - R16: destination address
; - R18: command (e.g. CPRO_CMD_PING or CPRO_CMD_PONG)
; - X : pointer to buffer to write to
; OUT:
; - CFLAG: set if okay, clear otherwise
; REGS: R16, R17, X, Y (R3, R4, R15, R16, R17, R18, R19, R20, R21)
COM2_WriteMsgWithCmdAndSrcAddr:
ldi r17, COM2_PAYLOAD_FLAGS_SECONDS
push xh
push xl
rcall COM2_BeginMsgWithVariablePayload ; (R3, R4, R16, R17, R18, R19, R20, R21, X)
pop xl
pop xh
rcall com2CalcAndAddChecksumByte ; (R16, R17, R18, R19, X)
sec
ret
COM2_WriteMsgWithCmdAndSrcAddr_error:
clc
ret
; ---------------------------------------------------------------------------
; begin packet with variable payload.
;
; IN:
; - R16: destination address
; - R17: flags
; - R18: command (e.g. CPRO_CMD_PING)
; - X : pointer to packet buffer
; OUT:
; - X : points to end of packet as it was written so far
; MODIFIED REGS: R3, R16, R17, R18, R19, R20, R21, X (R4)
COM2_BeginMsgWithVariablePayload:
; write header (dest address, msg length)
st X+, r16 ; destination address
mov r16, r17 ; calculate payload size
mov r3, r17
rcall com2CalcPayloadSize ; (R4, R16, R17)
inc r16 ; add CMD byte
inc r16 ; add source address byte
st X+, r16
; write payload
st X+, r18 ; 0: CMD
lds r16, com2Address ; 1: source address
st X+, r16
lsr r3 ; shift out COM2_PAYLOAD_FLAGS_SECONDS
brcc COM2_BeginMsgWithVariablePayload_l1
; write seconds
lds r16, timerModuleCounterSecs ; adding of current seconds counter requested
st X+, r16
lds r16, timerModuleCounterSecs+1
st X+, r16
lds r16, timerModuleCounterSecs+2
st X+, r16
lds r16, timerModuleCounterSecs+3
st X+, r16
COM2_BeginMsgWithVariablePayload_l1:
lsr r3 ; shift out shift out COM2_PAYLOAD_FLAGS_UID
brcc COM2_BeginMsgWithVariablePayload_l2
; write uid
push xh
push xl
rcall Utils_ReadUid ; (R16, X)
pop xl
pop xh
st X+, r18
st X+, r19
st X+, r20
st X+, r21
COM2_BeginMsgWithVariablePayload_l2:
ret
; ---------------------------------------------------------------------------
; com2CalcPayloadSize
;
; Calculate payload size from given flags
;
; IN:
; - R16: flags
; OUT:
; - R16: payload size
; MODIFIED REGS: R4, R16, R17
com2CalcPayloadSize:
clr r4
ldi r17, 4
lsr r16 ; shift out COM2_PAYLOAD_FLAGS_SECONDS
brcc com2CalcPayloadSize_l1
add r4, r17 ; add 4 bytes
com2CalcPayloadSize_l1:
lsr r16 ; shift out COM2_PAYLOAD_FLAGS_UID
brcc com2CalcPayloadSize_l2
add r4, r17 ; add 4 bytes
com2CalcPayloadSize_l2:
lsr r16 ; shift out reserved1, after this R16 contains COM2_PAYLOAD_FLAGS_NUM0-4
add r16, r4 ; add previous bytes to R16
ret
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Sending and receiving messages
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; ---------------------------------------------------------------------------
; receive packet.
;
; OUT:
; - CFLAG: set if okay (packet received), cleared on error
; REGS: r16, r17, x (r18, r19, r20, r21, r22)
com2ReceivePacket:
rcall COM2_BufferAlloc ; (r16, r17, r21)
brcs com2ReceivePacket_bufferAvailable
ldi xl, LOW(com2StatsNoBufferError) ; buffer in use, don't release
ldi xh, HIGH(com2StatsNoBufferError) ; just increment error counter
rcall Utils_IncrementCounter16 ; (r18, r19, 22)
clc
ret
com2ReceivePacket_bufferAvailable:
push xl
push xh
lds r16, com2Address
ldi r17, (COM2_BUFFER_SIZE-3)
rcall com2ReceivePacketRaw
pop xh
pop xl
brcc com2ReceivePacket_error
rcall com2CheckMessageInBuffer ; (R16, R17, R18, R19, R20, X)
brcc com2ReceivePacket_dataError
; everything okay
ldi xl, LOW(com2StatsPacketsIn)
ldi xh, HIGH(com2StatsPacketsIn)
rcall Utils_IncrementCounter16 ; (r18, r19, 22)
sec
ret
com2ReceivePacket_error:
cpi r16, COM2_ERROR_IOERROR
breq com2ReceivePacket_ioError
cpi r16, COM2_ERROR_DATAERROR
breq com2ReceivePacket_dataError
rjmp com2ReceivePacket_retnc
com2ReceivePacket_ioError:
ldi xl, LOW(com2StatsIoError)
ldi xh, HIGH(com2StatsIoError)
rjmp com2ReceivePacket_incCounterDeallocNc
com2ReceivePacket_dataError:
ldi xl, LOW(com2StatsContentError)
ldi xh, HIGH(com2StatsContentError)
rjmp com2ReceivePacket_incCounterDeallocNc
com2ReceivePacket_incCounterDeallocNc:
rcall Utils_IncrementCounter16 ; (r18, r19, 22)
com2ReceivePacket_deallocRetnc:
rcall COM2_BufferDeallocBack
com2ReceivePacket_retnc:
clc
ret
; ---------------------------------------------------------------------------
; send packet from sendBuffer, if line free.
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay (packet sent), cleared on error
; REGS: r22, x (r18, r19, r22)
COM2_SendPacket:
ldi xl, LOW(com2SendBuffer)
ldi xh, HIGH(com2SendBuffer)
COM2_SendPacketAtX:
rcall COM2_SendPacketWithAttn
brcs COM2_SendPacket_okay
cpi r16, COM2_ERROR_BUSY
breq COM2_SendPacket_busyError
cpi r16, COM2_ERROR_COLLISION
breq COM2_SendPacket_collError
COM2_SendPacket_busyError:
ldi xl, LOW(com2StatsBusyError)
ldi xh, HIGH(com2StatsBusyError)
rjmp COM2_SendPacket_incCounterRetNc
COM2_SendPacket_collError:
ldi xl, LOW(com2StatsCollisions)
ldi xh, HIGH(com2StatsCollisions)
COM2_SendPacket_incCounterRetNc:
rcall Utils_IncrementCounter16 ; (r18, r19, r22)
clc
ret
COM2_SendPacket_okay:
ldi xl, LOW(com2StatsPacketsOut)
ldi xh, HIGH(com2StatsPacketsOut)
rcall Utils_IncrementCounter16 ; (r18, r19, r22)
sec
ret
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; ISR
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
com2IsrPcint0:
push r15
in r15, SREG
sbic COM_PIN_ATTN, COM_PINNUM_ATTN
rjmp com2IsrPcint0_end
; low, read packet
push r1
push r16
push r17
push r18
push r19
push r20
push r21
push r22
push xh
push xl
push r15
rcall com2ReceivePacket ; (r16, r17, r18, r19, r20, r21, r22, x)
pop r15
lds xl, com2Interrupts
lds xh, com2Interrupts+1
adiw xh:xl, 1
sts com2Interrupts, xl
sts com2Interrupts+1, xh
pop xl
pop xh
pop r22
pop r21
pop r20
pop r19
pop r18
pop r17
pop r16
pop r1
com2IsrPcint0_end:
out SREG, r15
pop r15
reti
.include "modules/com2/com2_packets.asm"
.include "modules/com2/com2_lowlevel.asm"
.include "modules/com2/com2_buffer.asm"
.include "modules/com2/com2_crc.asm"
COM2_END:
.equ MODULE_SIZE_COM2 = COM2_END-COM2_BEGIN

View File

@@ -0,0 +1,170 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ---------------------------------------------------------------------------
; COM_BufferAlloc
;
; Allocate a transfer buffer.
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear otherwise
; - X: pointer to allocated buffer in SRAM
; MODIFIED REGISTERS: r16, r17, r21
COM2_BufferAlloc:
in r21, SREG ; save global interrupt enable bit from SREG
cli
lds r17, com2RecvBuffersUsed
cpi r17, COM2_BUFFER_NUM
brcc COM2_AllocBuffer_error ; no buffer available
inc r17 ; increment number of buffers used
sts com2RecvBuffersUsed, r17 ; store new value
lds r16, com2MaxBuffersUsed ; calc max buffers used
cp r16, r17
brcc COM2_AllocBuffer_l0
sts com2MaxBuffersUsed, r17
COM2_AllocBuffer_l0:
lds r16, com2RecvBuffersWritePos ; get current write pos
mov r17, r16 ; increment for next call
inc r17
cpi r17, COM2_BUFFER_NUM ; CF set if COM_BUFFER_NUM > R17
brcs COM2_AllocBuffer_l1
clr r17 ; wraparound
COM2_AllocBuffer_l1:
sts com2RecvBuffersWritePos, r17 ; store new writepos for next caller
rcall COM2_BufferPosToX ; (R16, R17)
out SREG, r21 ; restore global interrupt enable bit in SREG
sec
ret
COM2_AllocBuffer_error:
out SREG, r21
clc
ret
; ---------------------------------------------------------------------------
; COM2_BufferDeallocBack
;
; Release a transfer buffer at the end of the list by decreasing the write pos.
; This releases the last allocated buffer!
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGISTERS: r16, r17, r21
COM2_BufferDeallocBack:
in r21, SREG ; save global interrupt enable bit from SREG
cli
lds r17, com2RecvBuffersUsed
tst r17
breq COM2_BufferDeallocBack_error ; no buffer allocated, nothing to release
dec r17
sts com2RecvBuffersUsed, r17 ; store new value
lds r17, com2RecvBuffersWritePos
tst r17 ; 0?
brne COM2_BufferDeallocBack_l1 ; nope go directly decrement r17
ldi r17, COM2_BUFFER_NUM ; wrap-around
COM2_BufferDeallocBack_l1:
dec r17
sts com2RecvBuffersWritePos, r17
out SREG, r21
sec
ret
COM2_BufferDeallocBack_error:
out SREG, r21
clc
ret
; ---------------------------------------------------------------------------
; COM2_BufferDeallocFront
;
; Release a transfer buffer by increasing the read pos.
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGISTERS: r16, r17, r21
COM2_BufferDeallocFront:
in r21, SREG ; save global interrupt enable bit from SREG
cli
lds r17, com2RecvBuffersUsed
tst r17
breq COM2_BufferDeallocFront_error ; no buffer allocated, nothing to release
dec r17
sts com2RecvBuffersUsed, r17 ; store new value
lds r17, com2RecvBuffersReadPos
inc r17
cpi r17, COM2_BUFFER_NUM
brcs COM2_BufferDeallocFront_l1
clr r17 ; wrap-around
COM2_BufferDeallocFront_l1:
sts com2RecvBuffersReadPos, r17
out SREG, r21
sec
ret
COM2_BufferDeallocFront_error:
out SREG, r21
clc
ret
; ---------------------------------------------------------------------------
; COM2_BufferPosToX
;
; Get a pointer to the SRAM position of the given buffer.
; CAVE: Code must correspond to COM2_BUFFER_SIZE!!
; IN:
; - R16: buffer number (starting with 0)
; OUT:
; - X: pointer to buffer in SRAM
; MODIFIED REGISTERS: R16, R17
COM2_BufferPosToX:
; calculate offset
clr r17
mov xl, r16
clr xh
lsl xl
rol xh ; *2
add xl, r16
adc xh, r17 ; *3
lsl xl
rol xh ; *6
lsl xl
rol xh ; *12
lsl xl
rol xh ; *24
; add base position of buffers
ldi r16, LOW(com2RecvBuffers)
ldi r17, HIGH(com2RecvBuffers)
add xl, r16
adc xh, r17
ret

View File

@@ -0,0 +1,60 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ---------------------------------------------------------------------------
; add checksum byte to buffer
;
; IN:
; - X : pointer to packet buffer
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGS: R16, R17, R18, R19, X
com2CalcAndAddChecksumByte:
adiw xh:xl, COM2_MSG_OFFS_MSGLEN
ld r18, X ; read msg len
sbiw xh:xl, COM2_MSG_OFFS_MSGLEN
inc r18 ; account for dest address
inc r18 ; account for msg len byte
rcall crc8Calc ; (R16, R17, R18, R20, X)
st X, r16 ; add checksum byte
sec
ret
; ---------------------------------------------------------------------------
; check message in buffer
;
; IN:
; - X : pointer to packet buffer
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGS: R16, R17, R18, R19, R20, X
com2CheckMessageInBuffer:
adiw xh:xl, COM2_MSG_OFFS_MSGLEN
ld r18, X ; read msg len
sbiw xh:xl, COM2_MSG_OFFS_MSGLEN
inc r18 ; account for dest address
inc r18 ; account for msg len byte
rcall crc8Calc ; (R16, R17, R18, R20, X)
ld r17, X
cp r16, r17 ; should be equal
brne com2CheckMessageInBuffer_error
sec
ret
com2CheckMessageInBuffer_error:
clc
ret

View File

@@ -0,0 +1,48 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
.equ COM2_BUFFER_SIZE = 24 ; CAVE: must change code in COM2_BufferPosToX when changing this!
.equ COM2_BUFFER_NUM = 4
.equ COM2_MAXWAIT_US = 100 ; maximum wait time in microseconds when waiting for rising/falling clock
.equ COM2_MAINTENANCE_ADDR = 0xc1
; flags for variable payload enqueue function
.equ COM2_PAYLOAD_FLAGS_SECONDS = 0x01
.equ COM2_PAYLOAD_FLAGS_UID = 0x02
.equ COM2_PAYLOAD_FLAGS_RESERVED1 = 0x04
.equ COM2_PAYLOAD_FLAGS_NUM0 = 0x08
.equ COM2_PAYLOAD_FLAGS_NUM1 = 0x10
.equ COM2_PAYLOAD_FLAGS_NUM2 = 0x20
.equ COM2_PAYLOAD_FLAGS_NUM3 = 0x40
.equ COM2_PAYLOAD_FLAGS_NUM4 = 0x80
.equ COM2_PAYLOAD_FLAGS_SHIFT_NUM = 3
.equ COM2_MSG_OFFS_DESTADDR = 0
.equ COM2_MSG_OFFS_MSGLEN = 1
.equ COM2_MSG_OFFS_MSGDATA = 2
.equ COM2_MSG_OFFS_CMD = 2 ; first at COM2_MSG_OFFS_MSGDATA
.equ COM2_MSG_OFFS_SRCADDR = 3
.equ COM2_MSG_OFFS_PAYLOAD = 4 ; payload for the cmd follows here
.equ COM2_ERROR_NOTFORME = 1 ; receiption errors
.equ COM2_ERROR_IOERROR = 2
.equ COM2_ERROR_DATAERROR = 3
.equ COM2_ERROR_BUSY = 4 ; send errors
.equ COM2_ERROR_COLLISION = 5

View File

@@ -0,0 +1,233 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ---------------------------------------------------------------------------
; com2SendByte
;
; Send a byte.
; We only set the data pin to low at the beginning for the startbit. After that
; we only change the pin direction (e.g. input vs output):
; - for 0 bit: set DDR to output, forcing the data line low
; - for 1 bit: set DDR to input, letting the external pullup R pull the data line to HIGH
; since the output pin is still set to 0 the internal pullup is disabled
; IN:
; - R16: byte to send
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGS: R16, R21, R22
com2SendByte:
ldi r21, 8 ; +1 bits left
; send startbit
cbi COM_PORT_DATA, COM_PINNUM_DATA ; +2 set DATA low
sbi COM_DDR_DATA, COM_PINNUM_DATA ; +2 set DATA as output
Utils_WaitNanoSecs COM_BIT_LENGTH, 5, r22 ; wait for one bit duration
; send data bits
com2SendByte_loop: ; 9 for low bit
lsr r16 ; 1+ bit to send -> CARRY
brcs com2SendByte_setHigh ; HI: +2, LO: +1
com2SendByte_setLow:
sbi COM_DDR_DATA, COM_PINNUM_DATA ; +2 set DATA as output
Utils_WaitNanoSecs COM_BIT_LENGTH, 9, r22
rjmp com2SendByte_loopEnd ; +2
com2SendByte_setHigh:
cbi COM_DDR_DATA, COM_PINNUM_DATA ; +2 set DATA as input, pullup R makes it ONE
nop ; +1 (to make pin change available)
Utils_WaitNanoSecs COM_BIT_LENGTH/2, 11, r22 ; wait for half a bit length for line to safely settle
sbis COM_PIN_DATA, COM_PINNUM_DATA ; +1 if no skip, +2 if skipped
rjmp com2SendByte_error ; +2 if error (collision: we wanted line to be high but it is low)
Utils_WaitNanoSecs COM_BIT_LENGTH/2, 0, r22
com2SendByte_loopEnd:
dec r21 ; +1
brne com2SendByte_loop ; +2, sum per loop: 10 cycles
; send stopbit
cbi COM_DDR_DATA, COM_PINNUM_DATA ; +2 set DATA as input, pullup R makes it ONE
Utils_WaitNanoSecs COM_BIT_LENGTH, 4, r22 ; wait for one bit length
sec
ret
com2SendByte_error:
clc
ret
; ---------------------------------------------------------------------------
; com2ReceiveByte
;
; Receive a byte.
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear otherwise
; - R16: byte read (if CFLAG set)
; MODIFIED REGS: R16, R20, R21, R22 (R17)
com2ReceiveByte:
cbi COM_DDR_DATA, COM_PINNUM_DATA ; set DATA port as input
cbi COM_PORT_DATA, COM_PINNUM_DATA ; disable internal pullup for DATA
ldi r21, 8 ; bits left
clr r20 ; byte currently receiving
; wait for startbit
rcall com2WaitForDataLow ; (R17)
brcc com2ReceiveByte_error
Utils_WaitNanoSecs COM_BIT_LENGTH/2, 5, r22 ; goto middle of startbit to maximize sync stability
com2ReceiveByte_loop:
Utils_WaitNanoSecs COM_BIT_LENGTH, 8, r22 ; 8 cycles used in the complete loop between waits
sec ; +1
sbic COM_PIN_DATA, COM_PINNUM_DATA ; LOW: +2, HIGH: +1
rjmp com2ReceiveByte_shiftIn ; HIGH: +2, rjmp, use set CFLAG
clc ; LOW: +1
com2ReceiveByte_shiftIn:
ror r20 ; +1
dec r21 ; +1
brne com2ReceiveByte_loop ; +2, sum per loop: 8 cycles
rcall com2WaitForDataHigh ; wait for start of stopbit
brcc com2ReceiveByte_error
mov r16, r20
sec
ret
com2ReceiveByte_error:
clc
ret
; ---------------------------------------------------------------------------
; com2WaitForDataLow
;
; Waits up to COM2_MAXWAIT_US loops for low data line
; IN:
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGISTERS: r17, r22
com2WaitForDataLow:
ldi r17, COM2_MAXWAIT_US
com2WaitForDataLow_loop:
sbis COM_PIN_DATA, COM_PINNUM_DATA
rjmp com2WaitForDataLow_done
rcall com2WaitFor1000ns
dec r17
brne com2WaitForDataLow_loop
clc ; timeout
ret
com2WaitForDataLow_done:
sec ; ok
ret
; ---------------------------------------------------------------------------
; com2WaitForDataHigh
;
; Waits up to COM2_MAXWAIT_US loops for high data line
; IN:
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGISTERS: r17, r22, X
com2WaitForDataHigh:
ldi r17, COM2_MAXWAIT_US
com2WaitForDataHigh_loop:
sbic COM_PIN_DATA, COM_PINNUM_DATA
rjmp com2WaitForDataHigh_done
rcall com2WaitFor1000ns
dec r17
brne com2WaitForDataHigh_loop
clc ; timeout
ret
com2WaitForDataHigh_done:
sec ; ok
ret
; ---------------------------------------------------------------------------
; com2WaitForAttnHigh
;
; Waits up to COM2_MAXWAIT_US loops for high ATTN line
; IN:
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGISTERS: r17, r22, X
com2WaitForAttnHigh:
ldi r17, COM2_MAXWAIT_US
com2WaitForAttnHigh_loop:
sbic COM_PIN_ATTN, COM_PINNUM_ATTN
rjmp com2WaitForAttnHigh_done
rcall com2WaitFor1000ns
dec r17
brne com2WaitForAttnHigh_loop
clc ; timeout
ret
com2WaitForAttnHigh_done:
sec ; ok
ret
; ---------------------------------------------------------------------------
; com2WaitForDataState1ms
;
; Waits up to COM2_MAXWAIT_US loops for high ATTN line
; IN:
; OUT:
; - CFLAG: set if state reached, cleared otherwise
; REGS: R24 (R22)
com2WaitForDataState1ms:
ldi r24, 100
com2WaitForDataState1ms_loop:
push r17
in r17, COM_PIN_DATA
eor r17, r16
andi r17, (1<<COM_PINNUM_DATA)
pop r17
breq com2WaitForDataState1ms_stateReached
Utils_WaitNanoSecs 10000, 0, r22 ; wait for 10us
dec r24
brne com2WaitForDataState1ms_loop
clc
ret
com2WaitForDataState1ms_stateReached:
sec
ret
; ---------------------------------------------------------------------------
; comWaitFor1000ns
;
; Waits for 1000 nanoseconds.
; IN:
; OUT:
; - CFLAG: set if okay, clear otherwise
; REGS: r22
com2WaitFor1000ns:
Utils_WaitNanoSecs 1000, 7, r22 ; wait for 1000 nanosecs (minus 3 cycles for rcall, 4 for ret)
ret

View File

@@ -0,0 +1,150 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ---------------------------------------------------------------------------
; receive packet into buffer pointed to by X.
;
; IN:
; - R16: COM address to listen to
; - R17: maximum value for accepted msg data (i.e. buffersize minus 3)
; - X : buffer to receive to
; OUT:
; - CFLAG: set if okay (packet received), cleared on error
; - R16: error code if CFLAG is cleared
; REGS: r16, r17, r18, X (r19, r20, r21, r22)
com2ReceivePacketRaw:
mov r18, r17
push r16
; read destination address
rcall com2ReceiveByte ; read byte (R16, R17, R20, R21, R22)
pop r17 ; pop from R16 to R17
brcc com2ReceivePacketRaw_ioError
; compare destination address (accept "FF" and own address)
cp r16, r17
breq com2ReceivePacketRaw_acceptAddr
cpi r16, 0xff
breq com2ReceivePacketRaw_acceptAddr
ldi r16, COM2_ERROR_NOTFORME
clc ; not for me
ret
com2ReceivePacketRaw_acceptAddr:
st X+, r16 ; store dest address, lock buffer
; read msg length
rcall com2ReceiveByte ; read packet length (R16, R17, R20, R21, R22)
brcc com2ReceivePacketRaw_ioError
st X+, r16
cp r16, r18 ; (COM2_BUFFER_SIZE-3)
brcc com2ReceivePacketRaw_contentError ; packet too long
inc r16 ; account for checksum byte
mov r17, r16
com2ReceivePacketRaw_loop:
push r17
rcall com2ReceiveByte ; read byte (R16, R17, R20, R21, R22)
pop r17
brcc com2ReceivePacketRaw_ioError
st X+, r16
dec r17
brne com2ReceivePacketRaw_loop
sec
ret
com2ReceivePacketRaw_ioError:
ldi r16, COM2_ERROR_IOERROR
rjmp com2ReceivePacketRaw_error
com2ReceivePacketRaw_contentError:
ldi r16, COM2_ERROR_DATAERROR
com2ReceivePacketRaw_error:
clc
ret
; ---------------------------------------------------------------------------
; send packet over wire, handle ATTN line.
;
; IN:
; - x : ptr to buffer to send
; OUT:
; - CFLAGS: set if okay, cleared otherwise (errorcode in R16)
; REGS: R15, R16, R22 (R17, R21, X)
COM2_SendPacketWithAttn:
in r15, SREG
push r15
cli
Utils_WaitNanoSecs COM_BIT_LENGTH, 0, r22 ; wait for one bit duration
; check for ATTN line: busy?
cbi COM_PORT_ATTN, COM_PINNUM_ATTN ; disable pullup on ATTN
cbi COM_DDR_ATTN, COM_PINNUM_ATTN ; set ATTN as input
nop ; needed to sample current input
sbis COM_PIN_ATTN, COM_PINNUM_ATTN ; ATTN low?
rjmp COM2_SendPacketWithAttn_lineBusyError ; jump if it is
cbi COM_PORT_ATTN, COM_PINNUM_ATTN ; set ATTN low
sbi COM_DDR_ATTN, COM_PINNUM_ATTN ; set ATTN as output
Utils_WaitNanoSecs COM_BIT_LENGTH, 0, r22 ; wait for one bit duration
adiw xh:xl, COM2_MSG_OFFS_MSGLEN
ld r16, X
sbiw xh:xl, COM2_MSG_OFFS_MSGLEN
inc r16 ; account for dest addr
inc r16 ; account for msglen byte
inc r16 ; account for crc byte
rcall com2SendPacketRaw ; (r16, r17, r21, r22, X)
cbi COM_DDR_ATTN, COM_PINNUM_ATTN ; release ATTN line (by setting direction to IN)
brcc COM2_SendPacketWithAttn_ioError
; packet successfully sent
pop r15
out SREG, r15
sec
ret
COM2_SendPacketWithAttn_ioError:
ldi r16,COM2_ERROR_COLLISION
rjmp COM2_SendPacketWithAttn_retNc
COM2_SendPacketWithAttn_lineBusyError:
ldi r16,COM2_ERROR_BUSY
COM2_SendPacketWithAttn_retNc:
pop r15
out SREG, r15
clc
ret
; ---------------------------------------------------------------------------
; send packet over wire, expects ATTN to be low.
;
; IN:
; - r16: number of bytes to send
; - x : ptr to buffer to send
; OUT:
; - nothing
; REGS: r16, r17, x (r21, r22)
com2SendPacketRaw:
mov r17, r16
com2SendPacket_loop:
ld r16, X+
rcall com2SendByte ; send byte (R16, R21, R22)
brcc com2SendPacket_ioError
dec r17
brne com2SendPacket_loop
sec
ret
com2SendPacket_ioError:
clc
ret

View File

@@ -0,0 +1,142 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ***************************************************************************
; data
.dseg
cproDataBegin:
cproMode: .byte 1
cproDataEnd:
; ***************************************************************************
; code
.cseg
CPRO_BEGIN:
CPRO_Init:
; preset SRAM data area
ldi xh, HIGH(cproDataBegin)
ldi xl, LOW(cproDataBegin)
clr r16
ldi r17, (cproDataEnd-cproDataBegin)
rcall Utils_FillSram
#ifdef MODULES_COM_WITH_ADDR_PROTO
rcall CPRO_Address_Init
#endif
sec
ret
; ---------------------------------------------------------------------------
; CPRO_OnPacketReceived:
;
; Try to handle the given packet.
;
; IN:
; - X : pointer to received buffer
; OUT:
; - CFLAG: set if handled, cleared otherwise
; USED: depending on called routines
CPRO_OnPacketReceived:
adiw xh:xl, COM2_MSG_OFFS_CMD
ld r16, x
sbiw xh:xl, COM2_MSG_OFFS_CMD
cpi r16, CPRO_CMD_PING
brne CPRO_OnPacketReceived_l1
rjmp cproHandlePing
CPRO_OnPacketReceived_l1:
#ifndef BASE_SYSTEM
cpi r16, CPRO_CMD_REBOOT_REQUEST
brne CPRO_OnPacketReceived_l2
rjmp cproHandleReboot
#endif
CPRO_OnPacketReceived_l2:
#ifdef MODULES_COM_WITH_ADDR_PROTO
rjmp CPRO_Address_OnPacketReceived
#else
clc
ret
#endif
cproHandlePing:
adiw xh:xl, COM2_MSG_OFFS_SRCADDR
ld r16, x
tst r16 ; dont handle src address 0
breq cproHandlePing_notHandled
inc r16
breq cproHandlePing_notHandled ; dont handle src address 255
dec r16
ldi xl, LOW(com2SendBuffer)
ldi xh, HIGH(com2SendBuffer)
rcall CPRO_WritePong
rjmp COM2_SendPacket ; use carry flag from this routine
cproHandlePing_notHandled:
clc
ret
; ---------------------------------------------------------------------------
; Compare the UID from a message against out own UID.
;
;IN:
; - X: pointer to UID in a message to compare against out own uid
; OUT:
; - CFLAG set if matches, cleared otherwise
; REGS: r16, r18, r19, r20, r21, X
cproCheckUidInMsg:
push xl
push xh
rcall Utils_ReadUid
pop xh
pop xl
ld r16, X+
cp r16, r18
brne cproCheckUidInMsg_notMe
ld r16, X+
cp r16, r19
brne cproCheckUidInMsg_notMe
ld r16, X+
cp r16, r20
brne cproCheckUidInMsg_notMe
ld r16, X+
cp r16, r21
brne cproCheckUidInMsg_notMe
sec
ret
cproCheckUidInMsg_notMe:
clc
ret
CPRO_END:
.equ MODULE_SIZE_CPRO = CPRO_END-CPRO_BEGIN

View File

@@ -0,0 +1,434 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ***************************************************************************
; This sub-module contains code for cooperative address management.
; Because the network of nodes doen't have a central control unit the nodes
; need to assign addresses to themselves with help from the community of existing
; nodes.
;
; Protocol A: Full Address Assignment Protocol
; --------------------------------------------
; This protocol is used when a node has no currently or previously assigned address.
; In this case we need to find a free address which no other node uses.
;
; 1) a node needs an address. It sends the packet "NEED_ADDRESS"
; 2) every node which already has an address sees this message and answers with
; a "HAVE_ADDRESS" packet. The nodes must not answer all at once to avoid
; congestions. Instead, the time it takes for a node to respond depends on
; its own address (e.g. a node with address 10 will wait for 10+3s before answering)
; 3) the initial node collects all "HAVE_ADDRESS" packets and puts the addresses
; received this way into a bitfield in which for every address received a bit is
; set
; 4) after about 130s all nodes in the address range 1-127 should have answered.
; So after this time the initial node looks at the bitfield of received addresses
; and selects the first unused address (corresponding bit cleared in bitfield).
; For this address the initial node sends a "CLAIM_ADDRESS" packet, three times
; with about 30s between the packets.
; 5) if the to-be-claimed address is already in use by another node, that node will
; send a "DENY_ADDRESS" packet. This is the second line of defense against address
; collisions and should very rarely occur.
; 6) after no node denied the to-be-claimed address the initial node finally takes the
; address and sends a "HAVE_ADDRESS" packet.
; 7) this concludes the address assignemt protocol
;
; Protocol B: Shortened Address Assignment Protocol
; -------------------------------------------------
; This protocol is used upon boot when a node previously got an address assigned to it.
; In this case the address is probably not used by an other node so we can shorten the
; procedure.
;
; 1) a node sends the packet CLAIM_ADDRESS with the previously assigned address
; 2) is any other node objects to this node using that address (e.g. because the other
; node now uses that address) that node will send a DENY_ADDRESS packet.
; 3) if no DENY_ADDRESS has been received within 10s the address can be used.
; 4) Otherwise the node changes into protocol A (see above).
#ifdef MODULES_COM_WITH_ADDR_PROTO
; ***************************************************************************
; defs
; ***************************************************************************
; data
.dseg
cproAddressDataBegin:
cproAddrRangeBegin: .byte 1
cproAddrRangeEnd: .byte 1
cproUsedAddresses: .byte 16 ; one bit per address known to b in use
cproAddressDataEnd:
cproAddresModeTimer: .byte 2 ; timer must not be zeroed, this is done by the timer module!!
; ***************************************************************************
; code
.cseg
CPRO_Address_Init:
ldi xh, HIGH(cproAddressDataBegin)
ldi xl, LOW(cproAddressDataBegin)
clr r16
ldi r17, (cproAddressDataEnd-cproAddressDataBegin)
rcall Utils_FillSram
; setup timer for address setup (after 10s)
ldi r16, CPRO_MODE_NOADDRESS
sts cproMode, r16
ldi r18, 10
ldi r19, 0
rcall cproAddressSetTimer
ret
CPRO_StartReclaimAddrProcedure:
ldi xl, LOW(EEPROM_OFFS_COMADDR)
ldi xh, HIGH(EEPROM_OFFS_COMADDR)
in r15, SREG
push r15
cli
rcall Utils_ReadEepromIncr ; (R16)
tst r16
breq CPRO_StartReclaimAddrProcedure_l1
cpi r16, 0xff
breq CPRO_StartReclaimAddrProcedure_l1
sts cproAddrRangeBegin, r16 ; currently claimed address
ldi r16, CPRO_MODE_SEND_RECLAIM_ADDR
sts cproMode, r16
rcall cproAddressSetTimer1s ; use singleshot timer, send after 1s
pop r15
out SREG, r15
sec
ret
CPRO_StartReclaimAddrProcedure_l1:
rcall CPRO_StartGetAddrProcedure
pop r15
out SREG, r15
ret
CPRO_StartGetAddrProcedure:
; reset bitfield of used addresses
ldi xh, HIGH(cproUsedAddresses)
ldi xl, LOW(cproUsedAddresses)
clr r16
ldi r17, 16
rcall Utils_FillSram
; preset range
ldi r16, 1
sts cproAddrRangeBegin, r16
ldi r16, 126
sts cproAddrRangeEnd, r16
; setup singleshot timer to later send "NEED_ADDRESS" packet
ldi r16, CPRO_MODE_SEND_NEED_ADDR
sts cproMode, r16
rcall cproAddressSetTimer1s
sec
ret
; REGS: r18, r19
;
cproAddressSetTimer1s:
ldi r18, 1
ldi r19, 0
rjmp cproAddressSetTimer
; IN:
; - r18: timer value (low)
; - r19: timer value (high)
; REGS: none
cproAddressSetTimer:
push r15
in r15, SREG
cli
sts cproAddresModeTimer, r18
sts cproAddresModeTimer+1, r19
out SREG, r15
pop r15
ret
cproGetFirstFreeAddr:
rjmp cproGetFreeAddr
cproGetNextFreeAddr:
lds r16, cproAddrRangeBegin
inc r16
sts cproAddrRangeBegin, r16
rjmp cproGetFreeAddr
cproGetFreeAddr:
lds r16, cproAddrRangeBegin
lds r17, cproAddrRangeEnd
cp r16, r17
brge cproGetFreeAddr_error
rcall cproFindFreeAddr
brcc cproGetFreeAddr_error
sec
ret
cproGetFreeAddr_error:
clc
ret
cproHandleAddrRange: ; not handled for now
; TODO
clc
ret
; ---------------------------------------------------------------------------
; cproFindFreeAddr
;
; find a free address in the bitfield cproUsedAddresses
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if handled, cleared otherwise
; - R16: free address (if CFLAG set)
; USED: R16, R17, R18, R19, R20, R21 X, (R1, R2, Z)
cproFindFreeAddr:
ldi xl, LOW(cproUsedAddresses)
ldi xh, HIGH(cproUsedAddresses)
lds r16, cproAddrRangeBegin
dec r16
rcall cproGetPosAndMaskInBitField ; r1=bit pos, r2=mask (r1, r2, r17, Z)
clr r17
add xl, r1
adc xh, r17 ; X: pointer to byte
mov r17, r2 ; mask
lds r18, cproAddrRangeBegin
dec r18
lds r19, cproAddrRangeEnd
inc r19 ; to make comparision easier
ldi r20, 8
cproFindFreeAddr_byteLoop:
ld r16, X+
cpi r16, 0xff
breq cproFindFreeAddr_nextByte ; byte full, skip
cproFindFreeAddr_bitLoop:
mov r21, r16
and r21, r17
brne cproFindFreeAddr_nextBit
; found a clear bit, return
inc r18
sts cproAddrRangeBegin, r18
mov r16, r18
sec
ret
cproFindFreeAddr_nextBit:
inc r18 ; next address
lsl r17 ; shift mask to the left
brcc cproFindFreeAddr_bitLoop
dec r18 ; take back inc
cproFindFreeAddr_nextByte:
add r18, r20
andi r18, 0xf8 ; clear lower 3 bits
cp r18, r19 ; compare to end address+1
brcc cproFindFreeAddr_allFull
ldi r17, 0x01 ; mask
rjmp cproFindFreeAddr_byteLoop
cproFindFreeAddr_allFull:
clc
ret
; ---------------------------------------------------------------------------
; cproSetBitInBitfield
;
; IN:
; - R16 : bit number to set (0-127)
; OUT:
; - nothing
; USED: R16, R17, X (r1, r2, Z)
cproSetBitInBitfield:
; set bit corresponding to given address in bitfield of used addresses
rcall cproGetPosAndMaskInBitField ; get offset into R1, mask into R2 (r1, r2, r17, Z)
ldi xl, LOW(cproUsedAddresses)
ldi xh, HIGH(cproUsedAddresses)
clr r17
add xl, r1
adc xh, r17
ld r16, X
or r16, r2
st X, r16
ret
; ---------------------------------------------------------------------------
; Get offset and mask for a given bit in a bitfield
; IN:
; - R16: bit to request position for
; OUT:
; - R1: offset into the bitfield to the byte containing the given bit
; - R2: mask for given id (apply to r1)
; USED REGISTERS: r1, r2, r17, Z
cproGetPosAndMaskInBitField:
mov r1, r16 ; divide by 8 to get the offset to the byte containing the given module id
lsr r1
lsr r1
lsr r1 ; r1=offset of the byte holding the given bit
mov r2, r16 ; get bit mask for bit position in table byte
ldi r17, 7 ; keep lower 3 bits
and r2, r17
ldi zh, HIGH(cproModuleBitNumToMaskMap*2)
ldi zl, LOW(cproModuleBitNumToMaskMap*2)
add zl, r2
brcc cproGetPosAndMaskInBitField_noOverflow
inc zh
cproGetPosAndMaskInBitField_noOverflow:
lpm r2, z ; r2=mask for bit in byte from bitfield
ret
cproModuleBitNumToMaskMap:
.db 1, 2, 4, 8, 16, 32, 64, 128
; ---------------------------------------------------------------------------
; Send a NEEDADDRESS packet.
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGS: R18 (R3, R4, R15, R16, R17, R20, R21, X, Y (R18, R19)
CPRO_SendNeedAddress:
ldi r18, CPRO_CMD_NEED_ADDRESS
rjmp cproSendAddressPacket
; ---------------------------------------------------------------------------
; Send a HAVE_ADDRESS packet.
;
; IN:
; - nothing
; - R19: address to send
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGS: R18 (R3, R4, R15, R16, R17, R18, R19, R20, R21, X, Y)
CPRO_SendHaveAddress:
ldi r18, CPRO_CMD_HAVE_ADDRESS
rjmp cproSendAddressPacket
; ---------------------------------------------------------------------------
; Send a CLAIM_ADDRESS packet.
;
; IN:
; - R19: claimed address
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGS: R18 (R3, R4, R15, R16, R17, R18, R19, R20, R21, X, Y)
CPRO_SendClaimAddress:
ldi r18, CPRO_CMD_CLAIM_ADDRESS
rjmp cproSendAddressPacket
; ---------------------------------------------------------------------------
; Send a DENY_ADDRESS packet.
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGS: R18, R19 (R3, R4, R15, R16, R17, R20, R21, X, Y)
CPRO_SendDenyAddress:
ldi r18, CPRO_CMD_DENY_ADDRESS
lds r19, com2Address
rjmp cproSendAddressPacket
; ---------------------------------------------------------------------------
; cproSendAddressPacket
; Send a NEED/HAVE/CLAIM ADDRESS packet.
;
; IN:
; - R18: command (either CPRO_CMD_NEED_ADDRESS, CPRO_CMD_HAVE_ADDRESS or CPRO_CMD_CLAIM_ADDRESS)
; - R19: address to send (claim, have)
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGS: R16, R17, R20, R21, X, Y (R3, R4, R15, R16, R17, R18, R19, R21, X)
cproSendAddressPacket:
ldi xl, LOW(com2SendBuffer)
ldi xh, HIGH(com2SendBuffer)
mov r6, r19
ldi r16, 0xff
ldi r17, COM2_PAYLOAD_FLAGS_UID | (1<<COM2_PAYLOAD_FLAGS_SHIFT_NUM)
rcall COM2_BeginMsgWithVariablePayload ; (R3, R4, R16, R17, R18, R19, R20, R21, X)
st X+, r6 ; address
ldi xl, LOW(com2SendBuffer)
ldi xh, HIGH(com2SendBuffer)
rcall com2CalcAndAddChecksumByte ; (R16, R17, R18, R19, X)
rjmp COM2_SendPacket
.include "modules/comproto/comproto_addr1.asm"
.include "modules/comproto/comproto_addr2.asm"
#endif ; MODULES_COM_WITH_ADDR_PROTO

View File

@@ -0,0 +1,166 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; This file contains timer handlers for the address protocol
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; ***************************************************************************
; code
.cseg
CPRO_Address_OnTimer:
lds r16, cproMode
ldi r17, CPRO_MODE_NEXT_FREE
ldi zl, LOW(cproAddressOnTimerTable)
ldi zh, HIGH(cproAddressOnTimerTable)
rjmp Utils_TableJump
cproAddressOnTimerTable:
.dw CPRO_StartReclaimAddrProcedure ; CPRO_MODE_NOADDRESS
.dw 0 ; CPRO_MODE_NORMAL
.dw cproHandle1sNeedAddr ; CPRO_MODE_SEND_NEED_ADDR
.dw cproHandle1sGetAddrStarted ; CPRO_MODE_GETADDRSTARTED
.dw cproHandle1sSendClaimAddr1 ; CPRO_MODE_SEND_CLAIM_ADDR1
.dw cproHandle1sClaimingAddr12 ; CPRO_MODE_CLAIMING_ADDR1
.dw cproHandle1sClaimingAddr12 ; CPRO_MODE_CLAIMING_ADDR2
.dw cproHandle1sClaimingAddr3 ; CPRO_MODE_CLAIMING_ADDR3
.dw cproHandle1sSendingHaveAddress ; CPRO_MODE_SENDING_HAVE_ADDR
.dw cproHandle1sSendReclaimAddr ; CPRO_MODE_SEND_RECLAIM_ADDR
.dw cproHandle1sReclaimingAddr ; CPRO_MODE_RECLAIMING_ADDR
.dw cproHandle1sSendDenyAddr ; CPRO_MODE_SEND_DENY_ADDR
cproHandle1sSendingHaveAddress:
lds r19, com2Address
rcall CPRO_SendHaveAddress
brcs cproHandle1sSendingHaveAddress_okay
rcall cproAddressSetTimer1s ; could not send, restart timer 1s and retry later
ret
cproHandle1sSendingHaveAddress_okay:
ldi r16, CPRO_MODE_NORMAL
sts cproMode, r16
ret
cproHandle1sNeedAddr:
rcall CPRO_SendNeedAddress
brcs cproHandle1sNeedAddr_okay
rjmp cproAddressSetTimer1s ; could not send, restart timer 1s and retry later
cproHandle1sNeedAddr_okay:
ldi r16, CPRO_MODE_GETADDRSTARTED ; wait for incoming messages
sts cproMode, r16
ldi r18, CPRO_WAITTIME_GETADDR ; set timeout
clr r19
rjmp cproAddressSetTimer
cproHandle1sSendDenyAddr:
rcall CPRO_SendDenyAddress
brcs cproHandle1sSendDenyAddr_okay
rjmp cproAddressSetTimer1s ; could not send, restart timer 1s and retry later
cproHandle1sSendDenyAddr_okay:
ldi r16, CPRO_MODE_NORMAL ; DENY_ADDR sent, back to normal
sts cproMode, r16
ret
cproHandle1sSendReclaimAddr:
lds r19, cproAddrRangeBegin
rcall CPRO_SendClaimAddress
brcs cproHandle1sSendReclaimAddr_okay
rjmp cproAddressSetTimer1s ; could not send, restart timer 1s and retry later
cproHandle1sSendReclaimAddr_okay:
ldi r16, CPRO_MODE_RECLAIMING_ADDR
sts cproMode, r16
ldi r18, CPRO_WAITTIME_RECLAIMADDR
clr r19
rjmp cproAddressSetTimer ; prepare time for next stage
cproHandle1sGetAddrStarted:
rcall cproGetFirstFreeAddr
brcs cproHandle1sGetAddrStarted_gotAddr
; no free address, abort TODO: send an error message to bus ("bus full")
ldi r16, CPRO_MODE_NOADDRESS
sts cproMode, r16
ret
cproHandle1sGetAddrStarted_gotAddr:
ldi r16, CPRO_MODE_SEND_CLAIM_ADDR1
sts cproMode, r16
rjmp cproAddressSetTimer1s ; start
cproHandle1sSendClaimAddr1:
lds r19, cproAddrRangeBegin
rcall CPRO_SendClaimAddress
brcs cproHandle1sClaimSend_okay
rjmp cproAddressSetTimer1s ; could not send, restart timer 1s and retry later
cproHandle1sClaimSend_okay: ; goto nex stage
ldi r16, CPRO_MODE_CLAIMING_ADDR1
sts cproMode, r16
ldi r18, CPRO_WAITTIME_CLAIMADDR
clr r19
rjmp cproAddressSetTimer ; prepare timer for next stage
cproHandle1sClaimingAddr12:
lds r19, cproAddrRangeBegin ; currently claimed address
rcall CPRO_SendClaimAddress
brcs cproHandle1sClaimingAddr12_okay
rjmp cproAddressSetTimer1s ; could not send, restart timer 1s and retry later
cproHandle1sClaimingAddr12_okay:
lds r16, cproMode
inc r16
sts cproMode, r16
ldi r18, CPRO_WAITTIME_CLAIMADDR
clr r19
rjmp cproAddressSetTimer ; prepare time for next stage
cproHandle1sClaimingAddr3:
cproHandle1sReclaimingAddr:
; claimed given address 3rd time or addr reclaimed, set address and enter "normal" mode
lds r19, cproAddrRangeBegin ; currently claimed address
sts com2Address, r19
rcall CPRO_SendHaveAddress
brcs cproHandle1sClaimingAddr3_okay
rjmp cproAddressSetTimer1s ; could not send, restart timer 1s and retry later
cproHandle1sClaimingAddr3_okay:
in r15, SREG
push r15
cli
lds r16, com2Address ; currently sent address is in cproAddrRangeBegin
ldi xl, LOW(EEPROM_OFFS_COMADDR) ; write address into eeprom
ldi xh, HIGH(EEPROM_OFFS_COMADDR)
rcall Utils_WriteEepromIncr ; write address to EEPROM
pop r15
out SREG, r15
ldi r16, CPRO_MODE_NORMAL ; set mode to "normal"
sts cproMode, r16
ret

View File

@@ -0,0 +1,168 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; This file contains packet receiption handlers for the address protocol
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; CPRO_Address_OnPacketReceived:
;
; Try to handle the given packet.
;
; IN:
; - X : pointer to received buffer
; OUT:
; - CFLAG: set if handled, cleared otherwise
; USED: depending on called routines
CPRO_Address_OnPacketReceived:
adiw xh:xl, COM2_MSG_OFFS_CMD
ld r16, x
sbiw xh:xl, COM2_MSG_OFFS_CMD
ldi r17, (cproPacketTypeTransTableEnd-cproPacketTypeTransTableBegin) & 0xff
ldi zl, LOW(cproPacketTypeTransTableBegin)
ldi zh, HIGH(cproPacketTypeTransTableBegin)
rcall Utils_FindBytePositionInTable
brcc CPRO_Address_OnPacketReceived_nc
ldi r17, (cproPacketTypeTransTableEnd-cproPacketTypeTransTableBegin) & 0xff
ldi zl, LOW(cproPacketTypeHandleTable)
ldi zh, HIGH(cproPacketTypeHandleTable)
rcall Utils_TableJump
sec
ret
CPRO_Address_OnPacketReceived_nc:
clc
ret
cproPacketTypeTransTableBegin:
.db CPRO_CMD_PING, CPRO_CMD_NEED_ADDRESS, CPRO_CMD_HAVE_ADDRESS, CPRO_CMD_ADDRESS_RANGE, CPRO_CMD_DENY_ADDRESS, CPRO_CMD_CLAIM_ADDRESS
cproPacketTypeTransTableEnd:
; position within table must be in same order as in table above!
cproPacketTypeHandleTable:
.dw cproHandlePing, cproHandleNeedAddr, cproHandleHaveAddr, cproHandleAddrRange, cproHandleDenyAddr, cproHandleClaimAddr
cproHandleNeedAddr:
lds r17, cproMode
cpi r17, CPRO_MODE_NORMAL
brne cproHandleNeedAddr_done
; enter CPRO_MODE_SENDING_HAVE_ADDR mode
lds r16, com2Address
tst r16
breq cproHandleNeedAddr_done ; we have no address, don't handle
ldi r24, CPRO_MODE_SENDING_HAVE_ADDR ; start singleshot timer for sending HAVE_ADDRESS
sts cproMode, r24
lds r24, com2Address
clr r25
adiw r25:r24, 3
rjmp cproAddressSetTimer
cproHandleNeedAddr_done:
sec
ret
cproHandleHaveAddr:
lds r17, cproMode
cpi r17, CPRO_MODE_GETADDRSTARTED
brne cproHandleHaveAddr_done
; validate address
adiw xh:xl, CPRO_PACKET_HAVEADDR_OFFS_ADDRESS
ld r16, x
sbiw xh:xl, CPRO_PACKET_HAVEADDR_OFFS_ADDRESS
tst r16
breq cproHandleHaveAddr_done ; invalid address, ignore
cpi r16, 127
brcc cproHandleHaveAddr_done ; invalid address, ignore
; set bit corresponding to given address in bitfield of used addresses
dec r16
rcall cproSetBitInBitfield
cproHandleHaveAddr_done:
sec
ret
cproHandleClaimAddr:
adiw xh:xl, CPRO_PACKET_CLAIMADDR_OFFS_ADDRESS
ld r16, x
tst r16
breq cproHandleClaimAddr_done
cpi r16, 0xff
breq cproHandleClaimAddr_done
lds r17, com2Address
tst r17
breq cproHandleClaimAddr_done
cp r16, r17
brne cproHandleClaimAddr_done
ldi r16, CPRO_MODE_SEND_DENY_ADDR
sts cproMode, r16
rcall cproAddressSetTimer1s
cproHandleClaimAddr_done:
sec
ret
cproHandleDenyAddr:
; check mode
lds r17, cproMode
cpi r17, CPRO_MODE_CLAIMING_ADDR1
brcs cproHandleDenyAddr_notInClaimAddr13Mode
cpi r17, CPRO_MODE_CLAIMING_ADDR3+1
brcc cproHandleDenyAddr_notInClaimAddr13Mode
; we are in one of the three CLAIM_ADDRESS modes and received a DENY_ADDR, check address
adiw xh:xl, CPRO_PACKET_DENYADDR_OFFS_ADDRESS
ld r16, x
sbiw xh:xl, CPRO_PACKET_DENYADDR_OFFS_ADDRESS
lds r17, cproAddrRangeBegin
cp r16, r17
brne cproHandleDenyAddr_done ; not our currently claimed address, ignore
; someone denied us our claimed address, try next
rcall cproGetNextFreeAddr
brcs cproHandleDenyAddr_gotFreeAddr
; no free address, abort TODO: send an error message to bus ("bus full")
ldi r16, CPRO_MODE_NOADDRESS
sts cproMode, r16
ret
cproHandleDenyAddr_gotFreeAddr: ; claim next address
ldi r16, CPRO_MODE_SEND_CLAIM_ADDR1
sts cproMode, r16
rcall cproAddressSetTimer1s ; start timer
rjmp cproHandleDenyAddr_done
cproHandleDenyAddr_notInClaimAddr13Mode: ; reclaim mode?
lds r17, cproMode
cpi r17, CPRO_MODE_RECLAIMING_ADDR
brne cproHandleDenyAddr_done
; reclaiming went wrong, go through full address assignment protocol
rcall CPRO_StartGetAddrProcedure
cproHandleDenyAddr_done:
sec
ret

View File

@@ -0,0 +1,67 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; Enqueue a DEBUG packet.
;
; IN:
; - R16: destination address
; - R1: debug value 1
; - R2: debug value 2
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGS: R16, R17, R20, X (R15, Y)
CPRO_EnqueueDebug:
push r16
rcall COM_AllocBufferAndGetXY ; (r16, r17, r21)
pop r16
brcc CPRO_EnqueueDebug_error
clr r17 ; r17: XOR byte
; write header (dest address, msg length)
st X+, r16 ; destination address
eor r17, r16
ldi r16, 4 ; 2 bytes payload
st X+, r16
eor r17, r16
; write payload
ldi r16, CPRO_CMD_DEBUG
st X+, r16
eor r17, r16
lds r16, comAddress
st X+, r16
eor r17, r16
mov r16, r1 ; debug 1
st X+, r16
eor r17, r16
mov r16, r2 ; debug 2
st X+, r16
eor r17, r16
; store XOR byte
st X+, r17
; mark buffer as enqueued with PRIO "info" (limited amount of retries)
ldi r20, COM_BUFFER_PRIO_INFO
rcall COM_EnqueuePacket ; (R15, R16)
brcc CPRO_EnqueueDebug_error
sec
ret
CPRO_EnqueueDebug_error:
clc
ret

View File

@@ -0,0 +1,74 @@
; ***************************************************************************
; copyright : (C) 2023 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 CPRO_CMD_PING = 10
.equ CPRO_CMD_PONG = 11
.equ CPRO_CMD_COMSENDSTATS = 20
.equ CPRO_CMD_COMRECVSTATS = 21
.equ CPRO_CMD_TWIBUSMEMBER = 30
.equ CPRO_CMD_DEBUG = 40
.equ CPRO_CMD_VALUE = 51 ; was 50 when sending timestamp instead of uid
.equ CPRO_CMD_NEED_ADDRESS = 60
.equ CPRO_CMD_HAVE_ADDRESS = 61
.equ CPRO_CMD_CLAIM_ADDRESS = 62
.equ CPRO_CMD_DENY_ADDRESS = 63
.equ CPRO_CMD_ADDRESS_RANGE = 64
.equ CPRO_CMD_FLASH_START = 70
.equ CPRO_CMD_FLASH_END = 71
.equ CPRO_CMD_FLASH_READY = 72
.equ CPRO_CMD_FLASH_DATA = 73
.equ CPRO_CMD_FLASH_RSP = 74
.equ CPRO_CMD_DEVICE = 80
.equ CPRO_CMD_MEMSTATS = 81
.equ CPRO_CMD_SYSSTATS = 82
.equ CPRO_CMD_REBOOT_REQUEST = 90
.equ CPRO_CMD_REBOOT_RESPONSE = 91
.equ CPRO_PACKET_HAVEADDR_OFFS_ADDRESS = COM2_MSG_OFFS_PAYLOAD+4
.equ CPRO_PACKET_CLAIMADDR_OFFS_ADDRESS = COM2_MSG_OFFS_PAYLOAD+4
.equ CPRO_PACKET_DENYADDR_OFFS_ADDRESS = COM2_MSG_OFFS_PAYLOAD+4
.equ CPRO_PACKET_REBOOTREQ_OFFS_UID = COM2_MSG_OFFS_PAYLOAD+0
.equ CPRO_WAITTIME_INITIAL = 10
.equ CPRO_WAITTIME_GETADDR = 130
.equ CPRO_WAITTIME_CLAIMADDR = 17
.equ CPRO_WAITTIME_RECLAIMADDR = 10
; current mode of operation
.equ CPRO_MODE_NOADDRESS = 0x00 ; no address, yet
.equ CPRO_MODE_NORMAL = 0x01 ; normal operation
.equ CPRO_MODE_SEND_NEED_ADDR = 0x02 ; wait to send need address
.equ CPRO_MODE_GETADDRSTARTED = 0x03 ; waiting for HAVE_ADDRESS and ADDRESS_RANGE packets to arrive
.equ CPRO_MODE_SEND_CLAIM_ADDR1 = 0x04 ; send CLAIM_ADDRESS as part of reclaiming procedure
.equ CPRO_MODE_CLAIMING_ADDR1 = 0x05 ; CLAIM_ADDRESS sent, waiting for HAVE_ADDRESS packet to reject the claim
.equ CPRO_MODE_CLAIMING_ADDR2 = 0x06 ; CLAIM_ADDRESS sent, 2nd try
.equ CPRO_MODE_CLAIMING_ADDR3 = 0x07 ; CLAIM_ADDRESS sent, 3rd try
.equ CPRO_MODE_SENDING_HAVE_ADDR = 0x08 ; waiting for our turn to send HAVE_ADDRESS packet
.equ CPRO_MODE_SEND_RECLAIM_ADDR = 0x09 ; send CLAIM_ADDRESS as part of reclaiming procedure
.equ CPRO_MODE_RECLAIMING_ADDR = 0x0a ; CLAIM_ADDRESS with the previously used address sent after bootup
.equ CPRO_MODE_SEND_DENY_ADDR = 0x0b ; someone claimed our address, send a DENY_ADDR message
.equ CPRO_MODE_NEXT_FREE = 0x0c ; next free mode

View File

@@ -0,0 +1,53 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; Enqueue a DEVICE packet.
;
; IN:
; - R16: destination address
; - X : buffer to write to
; OUT:
; - nothing
; REGS: R3, R4, R16, R17, R18, X (R19, R20, R21)
CPRO_WriteDevice:
ldi r17, COM2_PAYLOAD_FLAGS_UID | (6<<COM2_PAYLOAD_FLAGS_SHIFT_NUM)
ldi r18, CPRO_CMD_DEVICE
push xh
push xl
rcall COM2_BeginMsgWithVariablePayload ; (R3, R4, R16, R17, R18, R19, R20, R21, X)
lds r17, firmwareType
st X+, r17 ; 6: firmware type low
lds r17, firmwareType+1
st X+, r17 ; 7: firmware type high
lds r17, firmwareVersion
st X+, r17 ; 8: version low
lds r17, firmwareVersion+1
st X+, r17 ; 9: version high
lds r17, firmwareModules
st X+, r17 ; 10: modules mask low
lds r17, firmwareModules+1
st X+, r17 ; 11: modules mask low
pop xl
pop xh
rcall com2CalcAndAddChecksumByte ; (R16, R17, R18, R19, X)
ret

View File

@@ -0,0 +1,57 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; Enqueue a MEMSTATS packet.
;
; IN:
; - R16: destination address
; OUT:
; - nothing
; REGS: R3, R4, R16, R17, R18, X (R19, R20, R21)
CPRO_WriteMemStats:
ldi r17, COM2_PAYLOAD_FLAGS_UID | COM2_PAYLOAD_FLAGS_SECONDS | (6<<COM2_PAYLOAD_FLAGS_SHIFT_NUM)
ldi r18, CPRO_CMD_MEMSTATS
push xh
push xl
rcall COM2_BeginMsgWithVariablePayload ; (R3, R4, R16, R17, R18, R19, R20, R21, X)
; payload
ldi r20, LOW(RAMEND)
ldi r21, HIGH(RAMEND)
in r17, SPL
sub r20, r17
st X+, r20 ; stack used
in r17, SPH
sbc r21, r17
st X+, r21
lds r17, com2RecvBuffersUsed
st X+, r17 ; used buffers
lds r17, com2MaxBuffersUsed
st X+, r17 ; max used buffers
lds r17, com2StatsNoBufferError
st X+, r17 ; recvNoBuffer
lds r17, com2StatsNoBufferError+1
st X+, r17
pop xl
pop xh
rcall com2CalcAndAddChecksumByte ; (R16, R17, R18, R19, X)
ret

View File

@@ -0,0 +1,33 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; Write a PING packet.
;
; IN:
; - R16: destination address
; - X : buffer to write to
; OUT:
; - nothing
; REGS: R3, R4, R16, R17, R18, X (R19, R20, R21)
CPRO_WritePing:
ldi r18, CPRO_CMD_PING
rjmp COM2_WriteMsgWithCmdAndSrcAddr

View File

@@ -0,0 +1,33 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; Write a PONG packet.
;
; IN:
; - R16: destination address
; - X : buffer to write to
; OUT:
; - nothing
; REGS: R3, R4, R16, R17, R18, X (R19, R20, R21)
CPRO_WritePong:
ldi r18, CPRO_CMD_PONG
rjmp COM2_WriteMsgWithCmdAndSrcAddr

View File

@@ -0,0 +1,71 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; Handle reboot request
;
; IN:
; - X : buffer containing the received packet
; OUT:
; - nothing
; REGS:
cproHandleReboot:
adiw xh:xl, CPRO_PACKET_REBOOTREQ_OFFS_UID
rcall cproCheckUidInMsg
brcc cproHandleReboot_notHandled
sbiw xh:xl, CPRO_PACKET_REBOOTREQ_OFFS_UID+4
adiw xh:xl, COM2_MSG_OFFS_SRCADDR
ld r16, x
cpi r16, 0xff
breq cproHandleReboot_notHandled ; dont handle src address 255
cproHandleReboot_loop1:
push r16
ldi xl, LOW(com2SendBuffer)
ldi xh, HIGH(com2SendBuffer)
rcall CPRO_WriteRebootResponse
rcall COM2_SendPacket
pop r16
brcc cproHandleReboot_loop1
; directly call bootloader
cli
rjmp AQHOME_BOOTLOADER_ADDR
cproHandleReboot_notHandled:
clc
ret
; ---------------------------------------------------------------------------
; Write a Reboot Response packet.
;
; IN:
; - R16: destination address
; - X : buffer to write to
; OUT:
; - nothing
; REGS: R3, R4, R16, R17, R18, X (R19, R20, R21)
CPRO_WriteRebootResponse:
ldi r18, CPRO_CMD_REBOOT_RESPONSE
rjmp COM2_WriteMsgWithCmdAndSrcAddr ; R3, R4, R15, R16, R17, R18, R19, R20, R21, X

View File

@@ -0,0 +1,66 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; Write a COM reception stats packet.
;
; IN:
; - R16: destination address
; - X : buffer to write to
; OUT:
; - nothing
; REGS: R3, R4, R16, R17, R18, X (R19, R20, R21)
CPRO_WriteComRecvStats:
ldi r17, COM2_PAYLOAD_FLAGS_UID | (12<<COM2_PAYLOAD_FLAGS_SHIFT_NUM) ; seconds + 12 bytes payload
ldi r18, CPRO_CMD_COMRECVSTATS
push xh
push xl
rcall COM2_BeginMsgWithVariablePayload ; (R3, R4, R16, R17, R18, R19, R20, R21, X)
lds r16, com2StatsPacketsIn ; packets in
st X+, r16
lds r16, com2StatsPacketsIn+1
st X+, r16
lds r16, com2StatsContentError ; CRC errors
st X+, r16
lds r16, com2StatsContentError+1
st X+, r16
lds r16, com2StatsIoError ; IO errors
st X+, r16
lds r16, com2StatsIoError+1
st X+, r16
lds r16, com2StatsNoBufferError ; no buffer
st X+, r16
lds r16, com2StatsNoBufferError+1
st X+, r16
lds r16, com2StatsHandled
st X+, r16
lds r16, com2StatsHandled+1
st X+, r16
lds r16, com2StatsMissed
st X+, r16
lds r16, com2StatsMissed+1
st X+, r16
pop xl
pop xh
rcall com2CalcAndAddChecksumByte ; (R16, R17, R18, R19, X)
ret

View File

@@ -0,0 +1,53 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; Write a ComSendStats packet.
;
; IN:
; - R16: destination address
; - X : buffer to write to
; OUT:
; - nothing
; REGS: R3, R4, R16, R17, R18, X (R19, R20, R21)
CPRO_WriteComSendStats:
ldi r17, COM2_PAYLOAD_FLAGS_UID | (6<<COM2_PAYLOAD_FLAGS_SHIFT_NUM) ; UID + 6 bytes payload
ldi r18, CPRO_CMD_COMSENDSTATS
push xh
push xl
rcall COM2_BeginMsgWithVariablePayload ; (R3, R4, R16, R17, R18, R19, R20, R21, X)
lds r16, com2StatsPacketsOut ; packets out
st X+, r16
lds r16, com2StatsPacketsOut+1
st X+, r16
lds r16, com2StatsCollisions ; collisions
st X+, r16
lds r16, com2StatsCollisions+1
st X+, r16
lds r16, com2StatsBusyError ; busy
st X+, r16
lds r16, com2StatsBusyError+1
st X+, r16
pop xl
pop xh
rcall com2CalcAndAddChecksumByte ; (R16, R17, R18, R19, X)
ret

View File

@@ -0,0 +1,50 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; Write a SYSSTATS packet.
;
; IN:
; - R16: destination address
; - X : buffer to write to
; OUT:
; - nothing
; REGS: R3, R4, R16, R17, R18, X (R19, R20, R21)
CPRO_WriteSysStats:
ldi r17, COM2_PAYLOAD_FLAGS_UID | COM2_PAYLOAD_FLAGS_SECONDS | (4<<COM2_PAYLOAD_FLAGS_SHIFT_NUM)
ldi r18, CPRO_CMD_SYSSTATS
push xh
push xl
rcall COM2_BeginMsgWithVariablePayload ; (R3, R4, R16, R17, R18, R19, R20, R21, X)
; payload
lds r17, com2Interrupts
st X+, r17 ; com interrupts
lds r17, com2Interrupts+1
st X+, r17
lds r17, timerInterrupts
st X+, r17 ; timer interrupts
lds r17, timerInterrupts+1
st X+, r17
pop xl
pop xh
rcall com2CalcAndAddChecksumByte ; (R16, R17, R18, R19, X)
ret

View File

@@ -0,0 +1,67 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; Enqueue a TWI Bus Member packet.
;
; IN:
; - R16: destination address
; - R1 : Address of the bus member
; - R2 : availability (0=not available, 1=available)
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGS: R16, R17, R20, X (R15, Y)
CPRO_EnqueueTwiBusMember:
push r16
rcall COM_AllocBufferAndGetXY ; (r16, r17, r21)
pop r16
brcc CPRO_EnqueueTwiBusMember_error
clr r17 ; r17: XOR byte
; write header (dest address, msg length)
st X+, r16 ; destination address
eor r17, r16
ldi r16, 4 ; 4 bytes payload
st X+, r16
eor r17, r16
; write payload
ldi r16, CPRO_CMD_TWIBUSMEMBER ; send command
st X+, r16
eor r17, r16
lds r16, comAddress ; send source address
st X+, r16
eor r17, r16
mov r16, r1 ; send i2c bus member address
st X+, r16
eor r17, r16
mov r16, r2 ; send i2c bus member availability
st X+, r16
eor r17, r16
; store XOR byte
st X+, r17
; mark buffer as enqueued with PRIO "info" (limited amount of retries)
ldi r20, COM_BUFFER_PRIO_INFO
rcall COM_EnqueuePacket ; (R15, R16)
brcc CPRO_EnqueueTwiBusMember_error
sec
ret
CPRO_EnqueueTwiBusMember_error:
clc
ret

View File

@@ -0,0 +1,58 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; Write a VALUE packet.
;
; IN:
; - R16: destination address
; - R17: value id
; - R19:R18: value
; - R21:R20: denom (e.g. 100, meaning value must be divided by 100)
; - R22: value type
; - X : buffer to write to
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGS: R6, R7, R8, R9, R10, R11, R12, R16, R17, X, Y (R3, R4, R15, R16, R17, R18, R19, R20, R21)
CPRO_WriteValue:
mov r7, r17
mov r8, r18
mov r9, r19
mov r10, r20
mov r11, r21
mov r12, r22
ldi r17, COM2_PAYLOAD_FLAGS_UID | (6<<COM2_PAYLOAD_FLAGS_SHIFT_NUM)
ldi r18, CPRO_CMD_VALUE
push xh
push xl
rcall COM2_BeginMsgWithVariablePayload ; R3, R4, R16, R17, R18, R19, R20, R21, X
st X+, r7 ; 6: value id
st X+, r12 ; 7: value type
st X+, r8 ; 8: low value
st X+, r9 ; 9: high value
st X+, r10 ; 10: low denom
st X+, r11 ; 11: high denom
pop xl
pop xh
rcall com2CalcAndAddChecksumByte ; (R16, R17, R18, R19, X)
ret

236
avr/modules/flash/flash.asm Normal file
View File

@@ -0,0 +1,236 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ***************************************************************************
; code
.cseg
FLASH_BEGIN:
; ---------------------------------------------------------------------------
; start flashing a page
;
; Interrupts must be disabled!
;
; IN:
; - Z: Address to work on (byte address as for LPM!)
; OUT:
; - nothing
; REGS: R16 (R0, R1, R16, R20, R24, R25)
Flash_StartPage:
push zh
push zl
ldi r16, ~((PAGESIZE*2)-1)
and zl, r16
rcall Flash_ReadPageIntoPageBuffer ; (R0, R1, R16, R20, R24, R25, Z)
pop zl
pop zh
ret
; ---------------------------------------------------------------------------
; finish flashing a page
;
; Interrupts must be disabled!
;
; IN:
; - Z: Address to work on (byte address as for LPM!)
; OUT:
; - nothing
; REGS: R16 (R15, R20)
Flash_FinishPage:
ldi r16, ~((PAGESIZE*2)-1)
and zl, r16
rcall Flash_ErasePage ; (R15, R16, R20)
rcall Flash_WritePage ; (R15, R16, R20)
ret
; ---------------------------------------------------------------------------
; Flash_ReadPageIntoPageBuffer
;
; Interrupts must be disabled!
;
; IN:
; - Z: Address to read from (byte address as for LPM!)
; OUT:
; - nothing
; REGS: R0, R1, R16, R20, R24, R25, Z
Flash_ReadPageIntoPageBuffer:
ldi r24, LOW(PAGESIZE*2)
ldi r25, HIGH(PAGESIZE*2)
Flash_ReadPageIntoPageBuffer_loop:
lpm r0, Z+ ; read source data from FLASH (low)
lpm r1, Z ; read source data from FLASH (high)
sbiw ZH:ZL, 1 ; rewind Z address for following SPM
ldi r20, (1<<SPMEN) ; enable next SPM, write into temp page buffer
rcall flashDoSpm ; (R16)
adiw ZH:ZL, 2
sbiw r25:r24, 2 ; use subi for PAGESIZEB<=256
brne Flash_ReadPageIntoPageBuffer_loop
ret
; ---------------------------------------------------------------------------
; Flash_WriteIntoPage
;
; Interrupts must be disabled!
;
; IN:
; - Z: Address to write to (byte address as for LPM!)
; - R1:R0: Word to write into page
; OUT:
; - Z: address for next write
; REGS: R16
Flash_WriteIntoPage:
ldi r20, (1<<SPMEN) ; enable next SPM, write into temp page buffer
rcall flashDoSpm ; (R16)
adiw zh:zl, 2
ret
; ---------------------------------------------------------------------------
; Flash_ErasePage
;
; Interrupts must be disabled!
;
; IN:
; - Z: Address of the page to erase.
; OUT:
; - nothing
; REGS: R20 (R16)
Flash_ErasePage:
ldi r20, (1<<PGERS) + (1<<SPMEN) ; enable next SPM, erase page (R1/R0 ignored)
rcall flashDoSpm ; (R16)
ret
; ---------------------------------------------------------------------------
; Flash_WritePage
;
; Interrupts must be disabled!
;
; IN:
; - Z: Address of the page to erase.
; OUT:
; - nothing
; REGS: R15, R20 (R16)
Flash_WritePage:
ldi r20, (1<<PGWRT) + (1<<SPMEN) ; enable next SPM, write page (R1/R0 ignored)
rcall flashDoSpm ; (R16)
ret
; ---------------------------------------------------------------------------
; flashDoSpm
;
; wait until possible previous SPM finished and then issue another SPM.
;
; IN:
; - R20: value for register SPMCR
; - R0: low value for SPM
; - R1: high value for SPM
; - Z : address for SPM (byte address!)
; OUT:
; - nothing
; REGS: R16
flashDoSpm:
wait: ; wait for possibly previous SPM to complete
in r16, SPMCSR
sbrc r16, SPMEN
rjmp wait
; SPM timed sequence
out SPMCSR, r20
spm
ret
; ---------------------------------------------------------------------------
; flashReadEepromIncr
;
; Read a byte from EEPROM (see example in ATtiny24/44/84 manual p.19).
;
; IN:
; - X: EEPROM Address to read from
; OUT:
; - R16: byte read
; - X: EEPROM Address incremented
; REGS: R16
flashReadEepromIncr:
sbic EECR, EEPE ; wait for previous write to complete (if any)
rjmp flashReadEepromIncr
out EEARH, xh ; set EEPROM address
out EEARL, xl
sbi EECR, EERE ; start EEPROM read by writing EERE
in r16, EEDR ; read data from data register
adiw xh:xl, 1
ret
; ---------------------------------------------------------------------------
; flashReadUid
;
; Read UID from EEPROM.
;
; IN:
; OUT:
; - R18:R19:R20:R21: UID
; REGS: R16, X
flashReadUid:
push r15
in r15, SREG
cli
ldi xl, LOW(EEPROM_OFFS_UUID)
ldi xh, HIGH(EEPROM_OFFS_UUID)
rcall flashReadEepromIncr ; (R16)
mov r18, r16
rcall flashReadEepromIncr ; (R16)
mov r19, r16
rcall flashReadEepromIncr ; (R16)
mov r20, r16
rcall flashReadEepromIncr ; (R16)
mov r21, r16
out SREG, r15
pop r15
ret
FLASH_END:
.equ MODULE_SIZE_FLASH = FLASH_END-FLASH_BEGIN

View File

@@ -0,0 +1,600 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
.equ FLASH_ERROR_NONE = 0
.equ FLASH_ERROR_MSGERROR = 1
.equ FLASH_RECVBUFFER_MAXLEN = 128
.equ FLASH_CMD_FLASH_RSP = 74
.equ FLASH_MSG_OFFS_DESTADDR = 0
.equ FLASH_MSG_OFFS_MSGLEN = 1
.equ FLASH_MSG_OFFS_MSGDATA = 2
.equ FLASH_MSG_OFFS_CMD = 2 ; first at COM2_MSG_OFFS_MSGDATA
.equ FLASH_MSG_OFFS_SRCADDR = 3
.equ FLASH_MSG_OFFS_PAYLOAD = 4 ; payload for the cmd follows here
.equ FLASH_PACKET_DATA_OFFS_ADDR = FLASH_MSG_OFFS_PAYLOAD+0 ; 4 bytes
.equ FLASH_PACKET_DATA_OFFS_DATA = FLASH_MSG_OFFS_PAYLOAD+4 ; n bytes
.equ FLASH_PACKET_START_OFFS_UID = FLASH_MSG_OFFS_PAYLOAD+0 ; 4 bytes
; ***************************************************************************
; data
.dseg
flashDataBegin:
flashUid: .byte 4
flashSendBuffer: .byte 32
flashRecvBuffer: .byte FLASH_RECVBUFFER_MAXLEN
flashDataEnd:
; ***************************************************************************
; code
.cseg
FLASH_PROTO_BEGIN:
bootLoader:
cli ; disable interrupts throughout the whole process
; setup stack
.ifdef SPH ; if SPH is defined
ldi r16, High(RAMEND)
out SPH, r16 ; init MSB stack pointer
.endif
ldi r16, Low(RAMEND)
out SPL, r16 ; init LSB stack pointer
; rcall watchdogOff ; turn off watchdog timer (sometimes it stays on after reboot)
; setup pins and interrupts
cbi COM_PORT_DATA, COM_PINNUM_DATA ; disable internal pullup for DATA
cbi COM_DDR_DATA, COM_PINNUM_DATA ; set DATA port as input
cbi COM_PORT_ATTN, COM_PINNUM_ATTN ; disable internal pullup for ATTN
cbi COM_DDR_ATTN, COM_PINNUM_ATTN ; set ATTN port as input
sbi DDRA, PORTA3 ; out
cbi PORTA, PORTA3 ; on
sbi DDRA, PORTA2 ; out (debug)
sbi PORTA, PORTA2 ; off (debug)
rcall flashReadUid
sts flashUid, r18
sts flashUid+1, r19
sts flashUid+2, r20
sts flashUid+3, r21
; wait for 3 secs before sending message
ldi r16, 30
rcall flashWaitForMulti100ms
; send flash ready message
ldi xl, LOW(flashSendBuffer)
ldi xh, HIGH(flashSendBuffer)
rcall flashWriteFlashReady
rcall flashSendPacketUntilSuccess
sbi PORTA, PORTA3 ; LED off
bootLoader_loop1:
; wait up to 10s for incoming FLASH_START message
ldi r16, CPRO_CMD_FLASH_START
ldi r17, 100 ; 100*100ms=10s
rcall flashWaitForSpecificMessageWithLed
brcc bootLoader_startFirmware
; either FLASH_START or FLASH_END received
cpi r16, CPRO_CMD_FLASH_START ; not FLASH_START, no flashing requested
brne bootLoader_startFirmware
; receive and flash new firmware
rcall flashHandleFlashStart
brcc bootLoader_loop1
; received a FLASH START msg, handle flashing
rcall bootLoaderFlash
brcc bootLoader_waitAndRestartBootLoader
; try to start firmware
bootLoader_startFirmware:
sbi PORTA, PORTA3 ; LED off
ldi r16, 20
rcall flashWaitForMulti100ms
rjmp firmwareStart
bootLoader_waitAndRestartBootLoader:
sbi PORTA, PORTA3 ; LED off
ldi r16, 20
rcall flashWaitForMulti100ms
rjmp bootLoader
bootLoaderFlash:
bootLoaderFlash_loop1:
; wait up to 10s for incoming FLASH_DATA message
ldi r16, CPRO_CMD_FLASH_DATA
ldi r17, 100 ; 100*100ms=10s
rcall flashWaitForSpecificMessageWithLed
brcc bootLoaderFlash_error
; either FLASH_DATA or FLASH_END received
cpi r16, CPRO_CMD_FLASH_DATA ; not FLASH_DATA, flashing ended/aborted
brne bootLoaderFlash_end
; flash data
rcall flashHandleFlashData
rjmp bootLoaderFlash_loop1
bootLoaderFlash_end:
sec
ret
bootLoaderFlash_error:
clc
ret
; ---------------------------------------------------------------------------
; wait for a specific message to arrive within given time, flashing LED
;
; IN:
; - R16: message type to receive
; - R17: wait time in 100ms (1=100ms, 2=200ms etc.)
; OUT:
; - CFLAG: set if msg received (either expected msg or FLASH_END), cleared otherwise
; - R16: message type received (if CFLAG set)
; REGS: R2, R16, R17 (R1, R24, R25, X)
flashWaitForSpecificMessageWithLed:
mov r2, r16
sbi PORTA, PORTA3 ; LED off
flashWaitForSpecificMessageWithLed_loop:
sbi PINA, PORTA3 ; toggle LED
mov r16, r2
push r17
ldi r17, 100 ; wait up to 100ms
rcall flashWaitForSpecificMessage ; (R1, R16, R17, R24, R25, X)
pop r17
brcs flashWaitForSpecificMessageWithLed_received
dec r17
brne flashWaitForSpecificMessageWithLed_loop
sbi PORTA, PORTA3 ; off
clc
ret
flashWaitForSpecificMessageWithLed_received:
sbi PORTA, PORTA3 ; off
sec
ret
; ---------------------------------------------------------------------------
; wait for a specific message to arrive within given time.
;
; IN:
; - R16: msg command to wait for
; - R17: time to wait for packet (in milliseconds)
; OUT:
; - CFLAG: set if msg received, cleared on timeout
; - R16 : message type received
; REGS: R1, R16, R17, X (R24, R25)
flashWaitForSpecificMessage:
mov r1, r16 ; expected message type
flashWaitForSpecificMessage_loop0:
; wait for ATTN to go low
flashWaitForSpecificMessage_loop1:
ldi r16, 0 ; wait for low
rcall flashWaitForAttnState1ms ; (R22, R24)
brcs flashWaitForSpecificMessage_isLow
dec r17
brne flashWaitForSpecificMessage_loop1
rjmp flashWaitForSpecificMessage_timeout
; receive message
flashWaitForSpecificMessage_isLow: ; is low, receive message, check for msg type
push r17
ldi r16, COM2_MAINTENANCE_ADDR
ldi r17, FLASH_RECVBUFFER_MAXLEN-3
ldi xl, LOW(flashRecvBuffer)
ldi xh, HIGH(flashRecvBuffer)
rcall com2ReceivePacketRaw
pop r17
brcc flashWaitForSpecificMessage_waitAttnHigh
ldi xl, LOW(flashRecvBuffer)
ldi xh, HIGH(flashRecvBuffer)
adiw xh:xl, COM2_MSG_OFFS_CMD
ld r16, X
sbiw xh:xl, COM2_MSG_OFFS_CMD
cp r16, r1
breq flashWaitForSpecificMessage_received
cpi r16, CPRO_CMD_FLASH_END
breq flashWaitForSpecificMessage_received
flashWaitForSpecificMessage_waitAttnHigh:
dec r17
breq flashWaitForSpecificMessage_timeout
; wait for ATTN to go high
flashWaitForSpecificMessage_loop2:
ldi r16, 0xff ; wait for high
rcall flashWaitForAttnState1ms ; (R22, R24)
brcs flashWaitForSpecificMessage_isHigh
dec r17
brne flashWaitForSpecificMessage_loop2
rjmp flashWaitForSpecificMessage_timeout
flashWaitForSpecificMessage_isHigh:
rjmp flashWaitForSpecificMessage_loop0
flashWaitForSpecificMessage_received: ; R16 contains message type
sec
ret
flashWaitForSpecificMessage_timeout:
clc
ret
; ---------------------------------------------------------------------------
; Wait for up to 1ms for ATTN line to reach the given state
;
; IN:
; - R16: expected state (0xff for high, 0 for low)
; OUT:
; - CFLAG: set if state reached, cleared otherwise
; REGS: R24 (R22)
flashWaitForAttnState1ms:
ldi r24, 100
flashWaitForAttnState1ms_loop:
push r17
in r17, COM_PIN_ATTN
eor r17, r16
andi r17, (1<<COM_PINNUM_ATTN)
pop r17
breq flashWaitForAttnState1ms_stateReached
Utils_WaitNanoSecs 10000, 0, r22 ; wait for 10us
dec r24
brne flashWaitForAttnState1ms_loop
clc
ret
flashWaitForAttnState1ms_stateReached:
sec
ret
; ---------------------------------------------------------------------------
; wait indefinately until ATTN line is high, send packet over wire, retry until successfull
;
; IN:
; - x : ptr to buffer to send
; OUT:
; - nothing
; REGS: R15, R16, R22 (R17, R21, X)
flashSendPacketUntilSuccess:
push xl
push xh
rcall COM2_SendPacketWithAttn
pop xh
pop xl
brcc flashSendPacket_error
ret
flashSendPacket_error:
rcall flashWaitForAttnHigh
rjmp flashSendPacketUntilSuccess
; ---------------------------------------------------------------------------
; wait indefinately for free ATTN line
;
; IN:
; - nothing
; OUT:
; - nothing
; REGS: R15, R16, R22 (R17, R21, X)
flashWaitForAttnHigh:
rcall com2WaitForAttnHigh ; waits for up to 100us
brcc flashWaitForAttnHigh_stillLow
ret
flashWaitForAttnHigh_stillLow:
rcall flashWaitDependingOnUid ; (R16, R18, R22, R24, R25)
rjmp flashWaitForAttnHigh
; ---------------------------------------------------------------------------
; wait depending on lowest byte of uid.
;
; Wait interval is between 100ms and 25s (i.e. 255*100ms). This is used to avoid
; all nodes on the network trying to send messages at the exact same time (e.g. after
; power outage which would affect all nodes at the same time).
;
; IN:
; - nothing
; OUT:
; - nothing
; REGS: R16 (R18, R22, R24, R25)
flashWaitDependingOnUid:
lds r16, flashUid
tst r16
brne flashWaitDependingOnUid_l1
ldi r16, 17
flashWaitDependingOnUid_l1:
rjmp flashWaitForMulti100ms
; ---------------------------------------------------------------------------
; wait for multiples of 100ms.
;
; IN:
; - R16: number of 100ms loops
; OUT:
; - nothing
; REGS: R16 (R18, R22, R24, R25)
flashWaitForMulti100ms:
flashWaitForMulti100ms_loop:
rcall flashWaitFor100ms ; (R18, R22, R24, R25)
dec r16
brne flashWaitForMulti100ms_loop
ret
; ---------------------------------------------------------------------------
; wait for 100 milliseconds.
;
; IN:
; - nothing
; OUT:
; - nothing
; REGS: R18 (R22, R24, R25)
flashWaitFor100ms:
ldi r18, 100
flashWaitFor100ms_loop:
rcall flashWaitFor1ms ; (R22, R24, R25)
dec r18
brne flashWaitFor100ms_loop
ret
; ---------------------------------------------------------------------------
; wait for 1 millisecond.
;
; IN:
; - nothing
; OUT:
; - nothing
; REGS: R24 (R22)
flashWaitFor1ms:
ldi r24, 10
flashWaitFor1ms_loop:
Utils_WaitNanoSecs 100000, 0, r22 ; wait for 100us
dec r24
brne flashWaitFor1ms_loop
ret
; ---------------------------------------------------------------------------
; Write a FLASH_RESPONSE packet.
;
; IN:
; - R16: response code (0 if ok, error code otherwise)
; - X : buffer to write to
; OUT:
; - nothing
; MODIFIED REGS: R16, R17 (R18, R19, R20)
flashWriteFlashRsp:
clr r18
st X+, r18 ; dest address (unused)
ldi r18, 3 ; msg code+src address+one payload byte
st X+, r18 ; msg len
ldi r17, CPRO_CMD_FLASH_RSP
st X+, r17 ; msg code
clr r17
st X+, r17 ; src address (not used)
st X, r16 ; payload byte
sbiw xh:xl, 4
rcall com2CalcAndAddChecksumByte ; (R16, R17, R18, R19, R20, X)
sbiw xh:xl, 5
ret
; ---------------------------------------------------------------------------
; Write a FLASH_READY packet.
;
; IN:
; - X : buffer to write to
; OUT:
; - nothing
; MODIFIED REGS: R16, Z (R17, R18, R19, R20)
flashWriteFlashReady:
ldi r16, 0xff
st X+, r16 ; dest address (unused)
ldi r16, 12 ; msg code+src address+ten payload bytes
st X+, r16 ; msg len
ldi r16, CPRO_CMD_FLASH_READY
st X+, r16 ; msg code
ldi r16, COM2_MAINTENANCE_ADDR
st X+, r16 ; src address (not used)
; payload
lds r16, flashUid
st X+, r16
lds r16, flashUid+1
st X+, r16
lds r16, flashUid+2
st X+, r16
lds r16, flashUid+3
st X+, r16
ldi zl, low(firmwareType*2)
ldi zh, HIGH(firmwareType*2)
lpm r16, Z+
st X+, r16 ; firmwareType (low)
lpm r16, Z+
st X+, r16 ; firmwareType (high)
lpm r16, Z+
st X+, r16 ; firmwareVersion (low)
lpm r16, Z+
st X+, r16 ; firmwareVersion (high)
ldi r16, LOW(PAGESIZE*2)
st X+, r16
ldi r16, HIGH(PAGESIZE*2)
st X, r16
sbiw xh:xl, 13
rcall com2CalcAndAddChecksumByte ; (R16, R17, R18, R19, R20, X)
sbiw xh:xl, 14
ret
; ---------------------------------------------------------------------------
; Handle FLASH START packet.
;
; IN:
; - X : buffer containing the message
; OUT:
; - CFLAG: set if message is for us, cleared otherwise
; REGS: r16, r18. r19. r20, r21, X (R15, R17, R22)
flashHandleFlashStart:
lds r18, flashUid
lds r19, flashUid+1
lds r20, flashUid+2
lds r21, flashUid+3
adiw xh:xl, FLASH_PACKET_START_OFFS_UID
ld r16, X+
cp r16, r18
brne flashHandleFlashStart_notMe
ld r16, X+
cp r16, r19
brne flashHandleFlashStart_notMe
ld r16, X+
cp r16, r20
brne flashHandleFlashStart_notMe
ld r16, X
cp r16, r21
brne flashHandleFlashStart_notMe
; okay, flash start message is for us
rcall flashWaitFor100ms
rcall flashSendFlashResponse ; (R15, R16, R17, R18, R19, R20, R21, R22, X)
sec
ret
flashHandleFlashStart_notMe:
clc
ret
; ---------------------------------------------------------------------------
; Handle FLASH DATA packet.
;
; IN:
; - X : buffer containing the message
; OUT:
; - CFLAG: set if message is for us, cleared otherwise
; REGS: R0, R1, R15, R16, R17, R18, R19, R20, R21, R24, R25, X, Z
flashHandleFlashData:
adiw xh:xl, FLASH_MSG_OFFS_MSGLEN
ld r18, X ; length (subtract 6
cpi r18, 6 ; cmd(1), src(1), addr(4)
brcs flashHandleFlashData_badData
subi r18, 6 ; remaining length
adiw xh:xl, FLASH_PACKET_DATA_OFFS_ADDR-FLASH_MSG_OFFS_MSGLEN
ld zl, X+ ; address (low)
ld zh, X+ ; address (high)
adiw xh:xl, 2 ; ignore high bytes, points to first data byte now
; rcall Flash_StartPage ; (R0, R1, R16, R20, R24, R25)
push zl
push zh
flashHandleFlashData_loop:
ld r0, X+
ld r1, X+
rcall Flash_WriteIntoPage ; (R15, R16, Z+)
subi r18, 2
brne flashHandleFlashData_loop
pop zh
pop zl
rcall Flash_FinishPage ; (R15, R16, R20)
clr r16
rjmp flashHandleFlashData_sendResponse
flashHandleFlashData_badData:
ldi r16, FLASH_ERROR_MSGERROR
flashHandleFlashData_sendResponse:
rcall flashSendFlashResponse ; (R15, R16, R17, R18, R19, R20, R21, R22, X)
sec
ret
; ---------------------------------------------------------------------------
; Create and send a FLASH RESPONSE packet
;
; IN:
; - R16: response code to send
; OUT:
; - nothing
; REGS: r16, X (R15, R17, R18, R19, R20, R21, R22)
flashSendFlashResponse:
; send flash ready message
ldi xl, LOW(flashSendBuffer)
ldi xh, HIGH(flashSendBuffer)
clr r16
rcall flashWriteFlashRsp ; (R16, R17, R18, R19, R20)
rjmp flashSendPacketUntilSuccess ; (R15, R16, R17, R21, R22, X)
FLASH_PROTO_END:
.equ MODULE_SIZE_FLASH_PROTO = FLASH_PROTO_END-FLASH_PROTO_BEGIN

825
avr/modules/lcd/lcd.asm Normal file
View File

@@ -0,0 +1,825 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; Some code in this module is based on C-code in Tiny4kOLED (https://github.com/datacute/Tiny4kOLED/tree/master/src)
; by Stephen Denne (MIT license), rewritten in AVR assembler
;
; - page 0 is top line, page 7 ist bottom line
; - column 0 is the leftmost colum, column 127 is the rightmost column
; - a page has a height of 8 (->8 bits)
; - when writing a byte to a position (e.g. page 0, column 0)
; - writing to chip RAM is done in columns
;
; Page 0: col 0 col 1 ... col 127
; Row 0(LSB) 0/0 1/0 ... 127/0
; Row 1 0/1 1/1 ... 127/1
; Row 2 0/2 1/2 ... 127/2
; Row 3 0/3 1/3 ... 127/3
; ...
; Row 7(MSB) 0/7 1/7 ... 127/7
; and so one
; ***************************************************************************
; defines
.equ LCD_WIDTH = 128
.equ LCD_HEIGHT = 64
.equ LCD_PAGE_COUNT = 8
.equ LCD_CMD_MODE = 0x00
.equ LCD_DATA_MODE = 0x40
; ***************************************************************************
; data
.dseg
lcdDataBegin:
lcdDataEnd:
; ***************************************************************************
; code
.cseg
LCD_BEGIN:
; ---------------------------------------------------------------------------
; LCD_Init
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear on error
; USED:
LCD_Init:
ldi zl, LOW(lcdInitCommandsBegin)
ldi zh, HIGH(lcdInitCommandsBegin)
ldi r16, 8
rcall lcdWriteCommandsFromFlash
ldi r16, 0
rcall LCD_Fill
ldi r16, 255
rcall LCD_Fill
ldi r16, 0
rcall LCD_Fill
ldi r18, 20
ldi r19, 0
rcall LCD_SetCursor
ldi zl, LOW(lcdHelloMsg)
ldi zh, HIGH(lcdHelloMsg)
rcall LCD_PrintFromFlash
; set cursor to next line here, sometimes this doesn't work correctly
; when called later. TODO: find out what goes wrong here...
ldi r18, 0
ldi r19, 2
rcall LCD_SetCursor
sec
ret
; ---------------------------------------------------------------------------
; LCD_Fini
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear on error
; USED:
LCD_Fini:
sec
ret
; ---------------------------------------------------------------------------
; LCD_SetCursor
;
; Set cursor. X is specified in pixels, Y is specified in character rows (8 pixels).
; Left upper corner is 0/0 (x/y), right lower corner is 127/7
;
; IN:
; - R18: X
; - R19: Y
; OUT:
; - CFLAG: set if okay, cleared otherwise
; REGS: r1, r2, r15, r16 (R16, R17, R18, R22)
LCD_SetCursor:
in r15, SREG
push r15
cli
mov r1, r18
mov r2, r19
rcall twiStart ; (R22)
ldi r16, (LCD_TWI_ADDRESS*2)
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_SetCursor_error
ldi r16, LCD_CMD_MODE
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_SetCursor_error
mov r16, r2
andi r16, 0x07
ori r16, 0xb0 ; Set Page Start Address for Page Addressing Mode
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_SetCursor_error
mov r16, r1
andi r16, 0x0f ; Set Lower Column Start Address
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_SetCursor_error
mov r16, r1
swap r16
andi r16, 0x0f
ori r16, 0x10 ; Set Higher Column Start Address
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_SetCursor_error
rcall twiStop ; (R22)
pop r15
out SREG, r15
sec
ret
LCD_SetCursor_error:
rcall twiStop ; (R22)
pop r15
out SREG, r15
clc
ret
; ---------------------------------------------------------------------------
; LCD_Fill
;
; Fill display RAM with the given value.
;
; IN:
; - R16: data to write
; OUT:
; - CFLAG: set if okay, cleared otherwise
; REGS: r15, r16, r18, r19, r20, r21 (r17, r22)
LCD_Fill:
in r15, SREG
push r15
cli
mov r20, r16
ldi r21, 0 ; Y
LCD_Fill_loopY:
clr r18
mov r19, r21
rcall LCD_SetCursor
brcc LCD_Fill_error
rcall twiStart
ldi r16, (LCD_TWI_ADDRESS*2)
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_Fill_error
ldi r16, LCD_DATA_MODE
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_Fill_error
ldi r19, 0
LCD_Fill_loopX:
mov r16, r20
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
rcall twiSendByte
brcc LCD_Fill_error
inc r19
cpi r19, LCD_WIDTH
brcs LCD_Fill_loopX
rcall twiStop
inc r21
cpi r21, LCD_PAGE_COUNT
brcs LCD_Fill_loopY
pop r15
out SREG, r15
sec
ret
LCD_Fill_error:
rcall twiStop
pop r15
out SREG, r15
clc
ret
; ---------------------------------------------------------------------------
; LCD_PrintFromFlash
;
; Print a string from flash at the current position.
;
; IN:
; - Z: position of string to print
; OUT:
; - CFLAG: set if okay, cleared otherwise
; REGS: r15, r16, Z (R17, R18, R22)
LCD_PrintFromFlash:
in r15, SREG
push r15
cli
lsl zl
rol zh
rcall twiStart
ldi r16, (LCD_TWI_ADDRESS*2)
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_PrintFromFlash_error
ldi r16, LCD_DATA_MODE
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_PrintFromFlash_error
LCD_PrintFromFlash_loop:
lpm r16, z+
tst r16
breq LCD_PrintFromFlash_end
push zh
push zl
rcall lcdPrintOneChar
pop zl
pop zh
brcc LCD_PrintFromFlash_error
rjmp LCD_PrintFromFlash_loop
LCD_PrintFromFlash_end:
rcall twiStop
pop r15
out SREG, r15
sec
ret
LCD_PrintFromFlash_error:
rcall twiStop
pop r15
out SREG, r15
clc
ret
; ---------------------------------------------------------------------------
; LCD_PrintChar
;
; Print a character at the current position.
;
; IN:
; - R16: char
; OUT:
; REGS: r15, r16, r17, Z
LCD_PrintChar:
in r15, SREG
push r15
cli
rcall twiStart
ldi r16, (LCD_TWI_ADDRESS*2)
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_PrintChar_error
ldi r16, LCD_DATA_MODE
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_PrintChar_error
rcall lcdPrintOneChar
brcc LCD_PrintChar_error
rcall twiStop
pop r15
out SREG, r15
sec
ret
LCD_PrintChar_error:
rcall twiStop
pop r15
out SREG, r15
clc
ret
; ---------------------------------------------------------------------------
; LCD_PrintHexByte
;
; Convert a given byte into HEX and write it to the current position.
;
; IN:
; - R16: byte to convert to hex
; OUT:
; REGS: r15, r16, r17, Z
LCD_PrintHexByte:
in r15, SREG
push r15
cli
mov r20, r16
rcall twiStart
ldi r16, (LCD_TWI_ADDRESS*2)
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_PrintHexByte_error
ldi r16, LCD_DATA_MODE
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_PrintHexByte_error
mov r16, r20
rcall lcdPrintHexByte
brcc LCD_PrintHexByte_error
rcall twiStop
pop r15
out SREG, r15
sec
ret
LCD_PrintHexByte_error:
rcall twiStop
pop r15
out SREG, r15
clc
ret
; ---------------------------------------------------------------------------
; LCD_PrintHexWord
;
; Convert a give word into HEX and write it to the current position.
;
; IN:
; - r18: low byte of the word
; - r19: high byte of the word
; OUT:
; - CFLAG: set if okay, cleared otherwise
; REGS: r15, r16, r17, Z
LCD_PrintHexWord:
in r15, SREG
push r15
cli
push r18
push r19
rcall twiStart
ldi r16, (LCD_TWI_ADDRESS*2)
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_PrintHexWord_errorPop
ldi r16, LCD_DATA_MODE
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_PrintHexWord_errorPop
pop r19
pop r18
rcall lcdPrintHexWord
brcc LCD_PrintHexWord_errorNoPop
rcall twiStop
pop r15
out SREG, r15
sec
ret
LCD_PrintHexWord_errorPop:
rcall twiStop
pop r19
pop r18
LCD_PrintHexWord_errorNoPop:
pop r15
out SREG, r15
clc
ret
; ---------------------------------------------------------------------------
; lcdPrintHexWord
;
; Convert a given word into HEX and write it to the current position.
;
; IN:
; - r18: low byte of the word
; - r19: high byte of the word
; OUT:
; - CFLAG: set if okay, cleared otherwise
lcdPrintHexWord:
mov r16, r19
push r18
rcall lcdPrintHexByte
pop r18
brcc lcdPrintHexWord_error
mov r16, r18
rcall lcdPrintHexByte
brcc lcdPrintHexWord_error
sec
ret
lcdPrintHexWord_error:
clc
ret
; ---------------------------------------------------------------------------
; lcdPrintHexByte
;
; Convert a give byte into HEX and write it to the current position.
;
; IN:
; - R16: byte to convert to hex
; OUT:
; - CFLAG: set if okay, cleared otherwise
; REGS: r16, r20 (r16, r17)
lcdPrintHexByte:
mov r20, r16
swap r16
rcall lcdNibbleToAscii ; write high nibble (r16, r17)
rcall lcdPrintOneChar ; (r16, r17, Z)
brcc lcdPrintHexByte_error
mov r16, r20
rcall lcdNibbleToAscii ; write low nibble
rcall lcdPrintOneChar
brcc lcdPrintHexByte_error
sec
ret
lcdPrintHexByte_error:
clc
ret
; ---------------------------------------------------------------------------
; lcdNibbleToAscii
;
; Convert a nibble to an ASCII char.
; IN:
; - R16: byte (in bits 0-3)
; OUT:
; - R16: ASCII representation of that nibble (e.g. '0' for 0)
; REGS: r16, r17
lcdNibbleToAscii:
andi r16, 0xf
cpi r16, 10
brcs lcdNibbleToAscii_l1
ldi r17, 7
add r16, r17
lcdNibbleToAscii_l1:
ldi r17, '0'
add r16, r17
ret
; ---------------------------------------------------------------------------
; lcdWriteCommandsFromFlash
;
; IN:
; - R16: number of bytes to send
; - Z=pointer to data
; OUT:
; - CFLAG: set if okay, cleared otherwise
; REGS: r16, r20, Z (r17, r18, r22)
lcdWriteCommandsFromFlash:
rcall twiStart
lsl zl
rol zh
mov r20, r16 ; number of bytes
ldi r16, (LCD_TWI_ADDRESS*2)
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc lcdWriteCommandsFromFlash_error
lcdWriteCommandsFromFlash_loop:
lpm r16, z+
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc lcdWriteCommandsFromFlash_error
dec r20
brne lcdWriteCommandsFromFlash_loop
rcall twiStop ; (R22)
sec
ret
lcdWriteCommandsFromFlash_error:
rcall twiStop
clc
ret
; ---------------------------------------------------------------------------
; lcdPrintOneChar
;
; Print a character at the current position.
;
; IN:
; - R16: char
; OUT:
; REGS: r16, r19, Z (R17, R18, R22)
lcdPrintOneChar:
rcall lcdGetCharMatrix ; (r16, r17, Z)
ldi r16, 0 ; spacing between chars
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc lcdPrintOneChar_error
ldi r19, 6
lcdPrintOneChar_loop:
lpm r16, z+
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc lcdPrintOneChar_error
dec r19
brne lcdPrintOneChar_loop
sec
ret
lcdPrintOneChar_error:
clc
ret
; ---------------------------------------------------------------------------
; lcdGetCharMatrix
;
; Get pointer to matrix of given char.
;
; IN:
; - R16: char
; OUT:
; - Z: pos of character matrix (ready for LPM)
; REGS: r16, r17, Z
lcdGetCharMatrix:
#ifdef LCD_MINIMAL_FONT
rcall lcdUpcase
cpi r16, 65+32
brcc lcdGetCharMatrix_l1
cpi r16, 32
brcc lcdGetCharMatrix_l2
lcdGetCharMatrix_l1:
ldi r16, 32
lcdGetCharMatrix_l2:
ldi r17, 32
sub r16, r17
mov zl, r16
clr zh
clr r17
lsl zl ; *2
rol zh
add zl, r16 ; *3
adc zh, r17
lsl zl ; *6
rol zh
ldi r16, LOW(lcdFont6x8Minimal*2)
ldi r17, HIGH(lcdFont6x8Minimal*2)
add zl, r16
adc zh, r17
ret
#else
cpi r16, 95+32
brcc lcdGetCharMatrix_l1
cpi r16, 32
brcc lcdGetCharMatrix_l2
lcdGetCharMatrix_l1:
ldi r16, 32
lcdGetCharMatrix_l2:
ldi r17, 32
sub r16, r17
mov zl, r16
clr zh
clr r17
lsl zl ; *2
rol zh
add zl, r16 ; *3
adc zh, r17
lsl zl ; *6
rol zh
ldi r16, LOW(lcdFont6x8*2)
ldi r17, HIGH(lcdFont6x8*2)
add zl, r16
adc zh, r17
ret
#endif
#ifdef LCD_MINIMAL_FONT
; ---------------------------------------------------------------------------
; Uppercase the given character if it is lower case.
;
; IN:
; - R16: char
; OUT:
; - R16: char
; REGS: r16, r17
lcdUpcase:
cpi r16, 'a'
brcs lcdUpcase_done
cpi r16, 'z'+1
brcc lcdUpcase_done
ldi r17, 32
sub r16, r17
lcdUpcase_done:
ret
#endif
; TODO: set adressing mode??
lcdInitCommandsBegin: ; 28 bytes
.db LCD_CMD_MODE, 0xa8, ((LCD_PAGE_COUNT*8)-1), 0x8d, 0x14, 0xaf, 0xa1, 0xc8
lcdInitCommandsEnd:
lcdHelloMsg: .db "AqHOME 2023", 0
; font taken from Tiny4kOLED (https://github.com/datacute/Tiny4kOLED/tree/master/src) by Stephen Denne (MIT license),
; original by Neven Boyanov
#ifdef LCD_MINIMAL_FONT
lcdFont6x8Minimal:
.db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; 0
.db 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00 ; ! 1
.db 0x00, 0x00, 0x07, 0x00, 0x07, 0x00 ; " 2
.db 0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14 ; # 3
.db 0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12 ; $ 4
.db 0x00, 0x62, 0x64, 0x08, 0x13, 0x23 ; % 5
.db 0x00, 0x36, 0x49, 0x55, 0x22, 0x50 ; & 6
.db 0x00, 0x00, 0x05, 0x03, 0x00, 0x00 ; ' 7
.db 0x00, 0x00, 0x1c, 0x22, 0x41, 0x00 ; ( 8
.db 0x00, 0x00, 0x41, 0x22, 0x1c, 0x00 ; ) 9
.db 0x00, 0x14, 0x08, 0x3E, 0x08, 0x14 ; * 10
.db 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08 ; + 11
.db 0x00, 0x00, 0x00, 0xA0, 0x60, 0x00 ; , 12
.db 0x00, 0x08, 0x08, 0x08, 0x08, 0x08 ; - 13
.db 0x00, 0x00, 0x60, 0x60, 0x00, 0x00 ; . 14
.db 0x00, 0x20, 0x10, 0x08, 0x04, 0x02 ; / 15
.db 0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E ; 0 16
.db 0x00, 0x00, 0x42, 0x7F, 0x40, 0x00 ; 1 17
.db 0x00, 0x42, 0x61, 0x51, 0x49, 0x46 ; 2 18
.db 0x00, 0x21, 0x41, 0x45, 0x4B, 0x31 ; 3 19
.db 0x00, 0x18, 0x14, 0x12, 0x7F, 0x10 ; 4 20
.db 0x00, 0x27, 0x45, 0x45, 0x45, 0x39 ; 5 21
.db 0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30 ; 6 22
.db 0x00, 0x01, 0x71, 0x09, 0x05, 0x03 ; 7 23
.db 0x00, 0x36, 0x49, 0x49, 0x49, 0x36 ; 8 24
.db 0x00, 0x06, 0x49, 0x49, 0x29, 0x1E ; 9 25
.db 0x00, 0x00, 0x36, 0x36, 0x00, 0x00 ; : 26
.db 0x00, 0x00, 0x56, 0x36, 0x00, 0x00 ; ; 27
.db 0x00, 0x08, 0x14, 0x22, 0x41, 0x00 ; < 28
.db 0x00, 0x14, 0x14, 0x14, 0x14, 0x14 ; = 29
.db 0x00, 0x00, 0x41, 0x22, 0x14, 0x08 ; > 30
.db 0x00, 0x02, 0x01, 0x51, 0x09, 0x06 ; ? 31
.db 0x00, 0x32, 0x49, 0x59, 0x51, 0x3E ; @ 32
.db 0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C ; A 33
.db 0x00, 0x7F, 0x49, 0x49, 0x49, 0x36 ; B 34
.db 0x00, 0x3E, 0x41, 0x41, 0x41, 0x22 ; C 35
.db 0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C ; D 36
.db 0x00, 0x7F, 0x49, 0x49, 0x49, 0x41 ; E 37
.db 0x00, 0x7F, 0x09, 0x09, 0x09, 0x01 ; F 38
.db 0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A ; G 39
.db 0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F ; H 40
.db 0x00, 0x00, 0x41, 0x7F, 0x41, 0x00 ; I 41
.db 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01 ; J 42
.db 0x00, 0x7F, 0x08, 0x14, 0x22, 0x41 ; K 43
.db 0x00, 0x7F, 0x40, 0x40, 0x40, 0x40 ; L 44
.db 0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F ; M 45
.db 0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F ; N 46
.db 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E ; O 47
.db 0x00, 0x7F, 0x09, 0x09, 0x09, 0x06 ; P 48
.db 0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E ; Q 49
.db 0x00, 0x7F, 0x09, 0x19, 0x29, 0x46 ; R 50
.db 0x00, 0x46, 0x49, 0x49, 0x49, 0x31 ; S 51
.db 0x00, 0x01, 0x01, 0x7F, 0x01, 0x01 ; T 52
.db 0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F ; U 53
.db 0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F ; V 54
.db 0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F ; W 55
.db 0x00, 0x63, 0x14, 0x08, 0x14, 0x63 ; X 56
.db 0x00, 0x07, 0x08, 0x70, 0x08, 0x07 ; Y 57
.db 0x00, 0x61, 0x51, 0x49, 0x45, 0x43 ; Z 58
.db 0x00, 0x00, 0x7F, 0x41, 0x41, 0x00 ; [ 59
.db 0x00, 0x02, 0x04, 0x08, 0x10, 0x20 ; \ 60
.db 0x00, 0x00, 0x41, 0x41, 0x7F, 0x00 ; ] 61
.db 0x00, 0x04, 0x02, 0x01, 0x02, 0x04 ; ^ 62
.db 0x00, 0x40, 0x40, 0x40, 0x40, 0x40 ; _ 63
.db 0x00, 0x00, 0x01, 0x02, 0x04, 0x00 ; ' 64
#else
lcdFont6x8:
.db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; 0
.db 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00 ; ! 1
.db 0x00, 0x00, 0x07, 0x00, 0x07, 0x00 ; " 2
.db 0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14 ; # 3
.db 0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12 ; $ 4
.db 0x00, 0x62, 0x64, 0x08, 0x13, 0x23 ; % 5
.db 0x00, 0x36, 0x49, 0x55, 0x22, 0x50 ; & 6
.db 0x00, 0x00, 0x05, 0x03, 0x00, 0x00 ; ' 7
.db 0x00, 0x00, 0x1c, 0x22, 0x41, 0x00 ; ( 8
.db 0x00, 0x00, 0x41, 0x22, 0x1c, 0x00 ; ) 9
.db 0x00, 0x14, 0x08, 0x3E, 0x08, 0x14 ; * 10
.db 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08 ; + 11
.db 0x00, 0x00, 0x00, 0xA0, 0x60, 0x00 ; , 12
.db 0x00, 0x08, 0x08, 0x08, 0x08, 0x08 ; - 13
.db 0x00, 0x00, 0x60, 0x60, 0x00, 0x00 ; . 14
.db 0x00, 0x20, 0x10, 0x08, 0x04, 0x02 ; / 15
.db 0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E ; 0 16
.db 0x00, 0x00, 0x42, 0x7F, 0x40, 0x00 ; 1 17
.db 0x00, 0x42, 0x61, 0x51, 0x49, 0x46 ; 2 18
.db 0x00, 0x21, 0x41, 0x45, 0x4B, 0x31 ; 3 19
.db 0x00, 0x18, 0x14, 0x12, 0x7F, 0x10 ; 4 20
.db 0x00, 0x27, 0x45, 0x45, 0x45, 0x39 ; 5 21
.db 0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30 ; 6 22
.db 0x00, 0x01, 0x71, 0x09, 0x05, 0x03 ; 7 23
.db 0x00, 0x36, 0x49, 0x49, 0x49, 0x36 ; 8 24
.db 0x00, 0x06, 0x49, 0x49, 0x29, 0x1E ; 9 25
.db 0x00, 0x00, 0x36, 0x36, 0x00, 0x00 ; : 26
.db 0x00, 0x00, 0x56, 0x36, 0x00, 0x00 ; ; 27
.db 0x00, 0x08, 0x14, 0x22, 0x41, 0x00 ; < 28
.db 0x00, 0x14, 0x14, 0x14, 0x14, 0x14 ; = 29
.db 0x00, 0x00, 0x41, 0x22, 0x14, 0x08 ; > 30
.db 0x00, 0x02, 0x01, 0x51, 0x09, 0x06 ; ? 31
.db 0x00, 0x32, 0x49, 0x59, 0x51, 0x3E ; @ 32
.db 0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C ; A 33
.db 0x00, 0x7F, 0x49, 0x49, 0x49, 0x36 ; B 34
.db 0x00, 0x3E, 0x41, 0x41, 0x41, 0x22 ; C 35
.db 0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C ; D 36
.db 0x00, 0x7F, 0x49, 0x49, 0x49, 0x41 ; E 37
.db 0x00, 0x7F, 0x09, 0x09, 0x09, 0x01 ; F 38
.db 0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A ; G 39
.db 0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F ; H 40
.db 0x00, 0x00, 0x41, 0x7F, 0x41, 0x00 ; I 41
.db 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01 ; J 42
.db 0x00, 0x7F, 0x08, 0x14, 0x22, 0x41 ; K 43
.db 0x00, 0x7F, 0x40, 0x40, 0x40, 0x40 ; L 44
.db 0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F ; M 45
.db 0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F ; N 46
.db 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E ; O 47
.db 0x00, 0x7F, 0x09, 0x09, 0x09, 0x06 ; P 48
.db 0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E ; Q 49
.db 0x00, 0x7F, 0x09, 0x19, 0x29, 0x46 ; R 50
.db 0x00, 0x46, 0x49, 0x49, 0x49, 0x31 ; S 51
.db 0x00, 0x01, 0x01, 0x7F, 0x01, 0x01 ; T 52
.db 0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F ; U 53
.db 0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F ; V 54
.db 0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F ; W 55
.db 0x00, 0x63, 0x14, 0x08, 0x14, 0x63 ; X 56
.db 0x00, 0x07, 0x08, 0x70, 0x08, 0x07 ; Y 57
.db 0x00, 0x61, 0x51, 0x49, 0x45, 0x43 ; Z 58
.db 0x00, 0x00, 0x7F, 0x41, 0x41, 0x00 ; [ 59
.db 0x00, 0x02, 0x04, 0x08, 0x10, 0x20 ; \ 60
.db 0x00, 0x00, 0x41, 0x41, 0x7F, 0x00 ; ] 61
.db 0x00, 0x04, 0x02, 0x01, 0x02, 0x04 ; ^ 62
.db 0x00, 0x40, 0x40, 0x40, 0x40, 0x40 ; _ 63
.db 0x00, 0x00, 0x01, 0x02, 0x04, 0x00 ; ' 64
.db 0x00, 0x20, 0x54, 0x54, 0x54, 0x78 ; a 65
.db 0x00, 0x7F, 0x48, 0x44, 0x44, 0x38 ; b 66
.db 0x00, 0x38, 0x44, 0x44, 0x44, 0x20 ; c 67
.db 0x00, 0x38, 0x44, 0x44, 0x48, 0x7F ; d 68
.db 0x00, 0x38, 0x54, 0x54, 0x54, 0x18 ; e 69
.db 0x00, 0x08, 0x7E, 0x09, 0x01, 0x02 ; f 70
.db 0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C ; g 71
.db 0x00, 0x7F, 0x08, 0x04, 0x04, 0x78 ; h 72
.db 0x00, 0x00, 0x44, 0x7D, 0x40, 0x00 ; i 73
.db 0x00, 0x40, 0x80, 0x84, 0x7D, 0x00 ; j 74
.db 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00 ; k 75
.db 0x00, 0x00, 0x41, 0x7F, 0x40, 0x00 ; l 76
.db 0x00, 0x7C, 0x04, 0x18, 0x04, 0x78 ; m 77
.db 0x00, 0x7C, 0x08, 0x04, 0x04, 0x78 ; n 78
.db 0x00, 0x38, 0x44, 0x44, 0x44, 0x38 ; o 79
.db 0x00, 0xFC, 0x24, 0x24, 0x24, 0x18 ; p 80
.db 0x00, 0x18, 0x24, 0x24, 0x18, 0xFC ; q 81
.db 0x00, 0x7C, 0x08, 0x04, 0x04, 0x08 ; r 82
.db 0x00, 0x48, 0x54, 0x54, 0x54, 0x20 ; s 83
.db 0x00, 0x04, 0x3F, 0x44, 0x40, 0x20 ; t 84
.db 0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C ; u 85
.db 0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C ; v 86
.db 0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C ; w 87
.db 0x00, 0x44, 0x28, 0x10, 0x28, 0x44 ; x 88
.db 0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C ; y 89
.db 0x00, 0x44, 0x64, 0x54, 0x4C, 0x44 ; z 90
.db 0x00, 0x08, 0x36, 0x41, 0x41, 0x00 ; { 91
.db 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00 ; | 92
.db 0x00, 0x00, 0x41, 0x41, 0x36, 0x08 ; } 93
.db 0x00, 0x08, 0x04, 0x08, 0x10, 0x08 ; ~ 94
#endif
LCD_END:
.equ MODULE_SIZE_LCD = LCD_END-LCD_BEGIN

324
avr/modules/led/led.asm Normal file
View File

@@ -0,0 +1,324 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ***************************************************************************
; defs
.equ LED_DATA_OFFS_ADDRDDR = 0
.equ LED_DATA_OFFS_ADDRPORT = 1
.equ LED_DATA_OFFS_ADDRPIN = 2
.equ LED_DATA_OFFS_PINMASK = 3
.equ LED_SRAM_OFFS_PATTERNADDR = 0
.equ LED_SRAM_OFFS_COUNTER = 2
.equ LED_SRAM_OFFS_POS = 3
.equ LED_SRAM_SIZE = 4
; ***************************************************************************
; code
.cseg
LED_BEGIN:
; ---------------------------------------------------------------------------
; Led_Init
;
; IN:
; - Y: pointer to SRAM data
; - Z: pointer to FLASH data
; OUT:
; - CFLAG: set if okay, clear on error
; USED: R1, R2, R3, R4, R16, R17, X
Led_Init:
mov xh, yh
mov xl, yl
clr r16
ldi r17, LED_SRAM_SIZE
rcall Utils_FillSram
rcall ledGetFlashDataIntoRegs
brcc Led_Init_end
; set bit in DDR register (-> output)
mov xl, r1 ; DDR register address
clr xh
ld r16, x
or r16, r4 ; output
st x, r16
; turn off led
rcall ledOff
sec
Led_Init_end:
ret
; ---------------------------------------------------------------------------
; Led_SetPattern
;
; IN:
; - X: pointer to led pattern in flash
; - Y: pointer to SRAM data
; - Z: pointer to FLASH data
; OUT:
; - CFLAG: set if okay, clear on error
; USED: R1, R2, R3, R4, R16, R17, Z
Led_SetPattern:
rcall ledGetFlashDataIntoRegs
brcc Led_SetPattern_l2
std y+LED_SRAM_OFFS_PATTERNADDR, xl ; param 1
std y+LED_SRAM_OFFS_PATTERNADDR+1, xh ; param 2
; reset pos in pattern
clr r19
std y+LED_SRAM_OFFS_POS, r19
; store counter for current pattern element
mov zl, xl
mov zh, xh
lsl zl ; multiplay Z by 2
rol zh
lpm r19, z ; read current pattern counter
std y+LED_SRAM_OFFS_COUNTER, r19
; each pattern starts with LED on
rcall ledOn
Led_SetPattern_l2:
ret
; ---------------------------------------------------------------------------
; Led_Tick
;
; IN:
; - Y: pointer to SRAM data
; - Z: pointer to FLASH data
; OUT:
; - CFLAG: set if something done, reset otherwise
; USED:
Led_Tick:
rcall ledGetFlashDataIntoRegs
brcs Led_Tick_l1
ret
Led_Tick_l1:
ldd zl, y+LED_SRAM_OFFS_PATTERNADDR
ldd zh, y+LED_SRAM_OFFS_PATTERNADDR+1
ldd r18, y+LED_SRAM_OFFS_POS
ldd r19, y+LED_SRAM_OFFS_COUNTER
; test NULL ptr
mov r16, zl;
or r16, zh
breq Led_Tick_end ; no current pattern, end
cpi r19, 2 ; current counter less than 2?
brcs Led_Tick_nextPhase
dec r19
std y+LED_SRAM_OFFS_COUNTER, r19
ret
Led_Tick_nextPhase:
lsl zl ; multiplay Z by 2
rol zh
inc r18 ; next pos
rcall Led_Tick_getPattern
cpi r16, 0xff
breq Led_Tick_restart
cpi r16, 0
breq Led_Tick_stop
std y+LED_SRAM_OFFS_POS, r18
std y+LED_SRAM_OFFS_COUNTER, r16
mov r17, r18
andi r17, 1 ; even?
breq Led_Tick_switchOn
rjmp ledOff
Led_Tick_switchOn:
; turn on led
rjmp ledOn
Led_Tick_stop:
clr r16
std y+LED_SRAM_OFFS_PATTERNADDR, r16
std y+LED_SRAM_OFFS_PATTERNADDR+1, r16
std y+LED_SRAM_OFFS_COUNTER, r16
std y+LED_SRAM_OFFS_POS, r16
; LED off
rcall ledOff
Led_Tick_restart:
ldi r18, 0
rcall Led_Tick_getPattern
cpi r16, 0xff
breq Led_Tick_stop ; stop, because restart as first pattern is invalid
cpi r16, 0
breq Led_Tick_stop
std y+LED_SRAM_OFFS_POS, r18 ; incremented pos in pattern
std y+LED_SRAM_OFFS_COUNTER, r16 ; new counter value
rcall ledOn
ret
Led_Tick_getPattern: ; r18=pos
ldd zl, y+LED_SRAM_OFFS_PATTERNADDR
ldd zh, y+LED_SRAM_OFFS_PATTERNADDR+1
lsl zl ; multiplay Z by 2
rol zh
ldi r16, 0
add zl, r18
adc zh, r16
lpm r16, z
ret
Led_Tick_end:
ret
; ---------------------------------------------------------------------------
; ledGetFlashDataIntoRegs
;
; IN:
; - R28/ZL: pointer to data in flash (low)
; - R29/ZH: pointer to data in flash (hi)
; OUT:
; - CARRY flag set if okay, clear on error
; - R1: memory address of DDR register
; - R2: memory address of PORT register
; - R3: memory address of PIN register
; - R4: mask for used pin
; USED: R16
ledGetFlashDataIntoRegs:
push zh
push zl
mov r16, zl
or r16, zh
breq ledGetFlashDataIntoRegs_error
lsl zl
rol zh
lpm r1, z+ ; DDR
lpm r2, z+ ; PORTR
lpm r3, z+ ; PINR
lpm r4, z ; pin mask
pop zl
pop zh
sec
ret
ledGetFlashDataIntoRegs_error:
pop zl
pop zh
clc
ret
; ---------------------------------------------------------------------------
; ledOff
;
; IN:
; - R2: port register address (low part only)
; - R4: bit mask for pin to use
; OUT:
; - nothing
; MODIFIED REGS: none
; CYCLES: 26 (if R2 and R4 valid)
ledOff:
tst r2 ; 1
breq ledOff_end ; 1 if not taken
tst r4 ; 1
breq ledOff_end ; 1 if not taken
push xh ; 2
push xl ; 2
push r16 ; 2
mov xl, r2 ; 1 PORT register address
clr xh ; 1
ld r16, x ; 1
or r16, r4 ; 1
st x, r16 ; 2
pop r16 ; 2
pop xl ; 2
pop xh ; 2
ledOff_end:
ret ; 4
; ---------------------------------------------------------------------------
; ledOn
;
; IN:
; - R2: port register address (low part only)
; - R4: bit mask for pin to use
; OUT:
; - nothing
; MODIFIED REGS: none
; CYCLES: 28
ledOn: ; clock cycles
tst r2 ; 1
breq ledOn_end ; 1 if not taken
tst r4 ; 1
breq ledOn_end ; 1 if not taken
push xh ; 2
push xl ; 2
push r16 ; 2
mov xl, r2 ; 1 PORT register address
clr xh ; 1
ld r16, x ; 1
com r4 ; 1 invert bit mask for following AND
and r16, r4 ; 1
com r4 ; 1 undo inversion
st x, r16 ; 2
pop r16 ; 2
pop xl ; 2
pop xh ; 2
ledOn_end:
ret ; 4
LED_END:
.equ MODULE_SIZE_LED = LED_END-LED_BEGIN

View File

@@ -0,0 +1,495 @@
; ***************************************************************************
; copyright : (C) 2023 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 SI7021_FLAGS_PRESENT = 0x80
.equ SI7021_FLAGS_TEMP_VALID = 0x40
.equ SI7021_FLAGS_HUM_VALID = 0x20
.equ SI7021_FLAGS_LASTWASTEMP = 0x10
.equ SI7021_FLAGS_ERROR_MASK = 0x07
; ***************************************************************************
; data
.dseg
si7021DataBegin:
si7021Flags: .byte 1
si7021FirmwareRevision: .byte 1
si7021LastTemp: .byte 2
si7021LastHumidity: .byte 2
si7021DataEnd:
; ***************************************************************************
; code
.cseg
SI7021_BEGIN:
; ---------------------------------------------------------------------------
; SI7021_Init
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear on error
; USED:
SI7021_Init:
ldi xh, HIGH(si7021DataBegin)
ldi xl, LOW(si7021DataBegin)
clr r16
ldi r17, (si7021DataEnd-si7021DataBegin)
rcall Utils_FillSram
; check presence
rcall si7021CheckPresence
brcc SI7021_Init_error
lds r16, si7021Flags
ori r16, SI7021_FLAGS_PRESENT
sts si7021Flags, r16
; get firmware revision
; rcall si7021ReadFirmwareRevision
; brcc SI7021_Init_error
; sts si7021FirmwareRevision, r16
sec
ret
SI7021_Init_error:
clc
ret
; ---------------------------------------------------------------------------
; SI7021_Fini
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear on error
; USED:
SI7021_Fini:
sec
ret
; ---------------------------------------------------------------------------
; SI7021_PeriodicMeasurement
;
; Call this routine periodically to take measurements.
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear on error
; USED:
SI7021_PeriodicMeasurement:
in r15, SREG
push r15
cli
lds r17, si7021Flags
mov r16, r17
andi r16, SI7021_FLAGS_LASTWASTEMP
brne si7021PeriodicMeasurement_hum
ori r17, SI7021_FLAGS_LASTWASTEMP
sts si7021Flags, r17
push r17
rcall si7021MeasureTemp
pop r17
brcc si7021PeriodicMeasurement_error
ori r17, SI7021_FLAGS_TEMP_VALID
sts si7021Flags, r17
rcall si7021CalcTemp ; calculate temp*100 from sensor value
sts si7021LastTemp, r18
sts si7021LastTemp+1, r19
rjmp si7021PeriodicMeasurement_done
si7021PeriodicMeasurement_hum:
andi r17, ~SI7021_FLAGS_LASTWASTEMP
sts si7021Flags, r17
push r17
rcall si7021MeasureHumidity
pop r17
brcc si7021PeriodicMeasurement_error
ori r17, SI7021_FLAGS_HUM_VALID
sts si7021Flags, r17
rcall si7021CalcHumidity
sts si7021LastHumidity, r18
sts si7021LastHumidity+1, r19
si7021PeriodicMeasurement_done:
pop r15
out SREG, r15
sec
ret
si7021PeriodicMeasurement_error:
pop r15
out SREG, r15
clc
ret
; ---------------------------------------------------------------------------
; si7021CheckPresence
;
; Expects interrupts being disabled!
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear on error
; USED:
si7021CheckPresence:
rcall twiStart
ldi r16, (SI7021_ADDR*2)+1
rcall twiSendByte
brcc si7021CheckPresence_notfound
rcall twiStop
sec
ret
si7021CheckPresence_notfound:
rcall twiStop
clc
ret
#if 0
; ---------------------------------------------------------------------------
; si7021ReadFirmwareRevision
;
; Expects interrupts being disabled!
; Currently doesn't work (my SI7021 doesn't accept the command).
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear on error
; - R16: firmware revision (0xff: version 1.0, 0x20: version 2.0)
; USED:
si7021ReadFirmwareRevision:
rcall twiStart
ldi r16, (SI7021_ADDR*2) ; write access
rcall twiSendByteExpectAck
brcc si7021ReadFirmwareRevision_error1
ldi r16, 0x84
rcall twiSendByteExpectAck
brcc si7021ReadFirmwareRevision_error2
ldi r16, 0xb8
rcall twiSendByteExpectAck
brcc si7021ReadFirmwareRevision_error3
rcall twiRestart
ldi r16, (SI7021_ADDR*2)+1 ; read access
rcall twiSendByteExpectAck
brcc si7021ReadFirmwareRevision_error4
rcall twiReceiveByte ; don't send ACK
brcc si7021ReadFirmwareRevision_error5
rcall twiStop
sec
ret
si7021ReadFirmwareRevision_error1:
ldi r16, 1
rcall si7021SetError
rjmp si7021ReadFirmwareRevision_error
si7021ReadFirmwareRevision_error2:
ldi r16, 2
rcall si7021SetError
rjmp si7021ReadFirmwareRevision_error
si7021ReadFirmwareRevision_error3:
ldi r16, 3
rcall si7021SetError
rjmp si7021ReadFirmwareRevision_error
si7021ReadFirmwareRevision_error4:
ldi r16, 4
rcall si7021SetError
rjmp si7021ReadFirmwareRevision_error
si7021ReadFirmwareRevision_error5:
ldi r16, 5
rcall si7021SetError
rjmp si7021ReadFirmwareRevision_error
si7021ReadFirmwareRevision_error:
rcall twiStop
clc
ret
#endif
; ---------------------------------------------------------------------------
; si7021MeasureTemp
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear on error
; USED:
si7021MeasureTemp:
ldi r16, 0xf3
rjmp si7021MeasureAny
; ---------------------------------------------------------------------------
; si7021MeasureHumidity
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear on error
; USED:
si7021MeasureHumidity:
ldi r16, 0xf5
rjmp si7021MeasureAny
; ---------------------------------------------------------------------------
; si7021MeasureAny
;
; Sends the given command to the sensor and reads the result.
; Synchronization is done by sending re-start sequences until the sensor answers with
; the value.
; IN:
; - R16: command to send
; OUT:
; - CFLAG: set if okay, clear on error
; USED: R14, R16, R18, R19
si7021MeasureAny:
rcall twiStart ; (R22)
push r16
ldi r16, (SI7021_ADDR*2) ; write access
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
pop r16
brcc si7021MeasureAny_error
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
ldi r16, 200
mov r14, r16
si7021MeasureAny_loop: ; (R22)
rcall twiRestart
ldi r16, (SI7021_ADDR*2)+1 ; read access
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcs si7021MeasureAny_gotValue ; chip responds, receive values
dec r14
breq si7021MeasureAny_error ; timeout
Utils_WaitNanoSecs 100000, 0, r22
rjmp si7021MeasureAny_loop
si7021MeasureAny_gotValue:
rcall twiReceiveByteSendAck ; (R16, R17, R18, R22)
brcc si7021MeasureAny_error
mov r19, r16 ; MSByte
rcall twiReceiveByte ; no ACK (R16, R17, R18, R22)
brcc si7021MeasureAny_error
mov r18, r16
rcall twiStop ; (R22)
ldi r16, 0
rcall si7021SetError ; (none)
sec
ret
si7021MeasureAny_error:
rcall twiStop ; (R22)
clc
ret
; ---------------------------------------------------------------------------
; si7021SetError
;
; Set error code in flags.
; IN:
; - R16: error code to set (0-7)
; OUT:
; - CFLAG: set if okay, clear on error
; USED: none
si7021SetError:
push r17
lds r17, si7021Flags
andi r17, ~SI7021_FLAGS_ERROR_MASK
or r17, r16
sts si7021Flags, r17
pop r17
ret
; ---------------------------------------------------------------------------
; si7021CalcTemp
;
; Calculates temperatur * 100.
; Uses formula from specs: temp=(175.72*TEMP_CODE/65536)-46.85.
;
; IN:
; - R19:R18: Temperature value read from sensor
; OUT:
; - R19:R18: calculated temperature(Celsius) * 100
; USED: R16, R17, R18, R19, R20, R21, R22, R23, R24, R25, R26
si7021CalcTemp:
mov r20, r18
mov r21, r19
ldi r23, HIGH(17572)
ldi r22, LOW(17572)
rcall si7021Mulu16x16_32 ; result is in R19:R18:R17:R16, we only use R19-R18 -> /65536
ldi r16, LOW(4685)
ldi r17, HIGH(4685)
sub r18, r16
sbc r19, r17
ret
; ---------------------------------------------------------------------------
; si7021CalcHumidity
;
; Calculates humidity in percent.
; Uses formula from specs: rel humidity=(125*HUMIDITY_CODE/65536)-6.
;
; IN:
; - R19:R18: Humidity value read from sensor
; OUT:
; - R19:R18: calculated relative humidity
; USED: R16, R17, R18, R19, R20, R21, R22, R23, R24, R25, R26
si7021CalcHumidity:
mov r20, r18
mov r21, r19
clr r23
ldi r22, 125
rcall si7021Mulu16x16_32 ; result is in R19:R18:R17:R16, we only use R19-R18 -> /65536
ldi r16, 6
clr r17
sub r18, r16
sbc r19, r17
ret
; ---------------------------------------------------------------------------
; si7021Mulu16x16_32
;
; Multiplies two unsigned 16 bit values resulting in one 32 bit value.
; This is a rather simple but reasonable fast routine working just like you would
; when doing multiplications with pen and paper.
; TODO: adapt for signed values
;
; IN:
; - R21:R20: 16 bit value A
; - R23:R22: 16 bit value B
; OUT:
; - R19:R18:R17:R16: 32 bit result
; USED: R16, R17, R18, R19, R20, R21, R22, R23, R24, R25, R26
; R19:R18:R17:R16 = R21:R20 * R23:R22
; R19:R18:R17:R16 = R25:R24:R21:R20 * R23:R22
si7021Mulu16x16_32:
clr r19
clr r18
clr r17
clr r16
clr r25
clr r24
ldi r26, 16 ; 16 bit multiplicator
si7021Muls16x16_32_loop:
lsr r23
ror r22
brcc si7021Muls16x16_32_noadd ; current digit in B is 0, don't add shifted A to result
add r16, r22
adc r17, r23
adc r18, r24
adc r19, r25
; brcs si7021Muls16x16_32_overflow ; can't happen
si7021Muls16x16_32_noadd:
dec r26
breq si7021Muls16x16_32_done
lsl r20
rol r21
rol r24
rol r25
; brcs si7021Muls16x16_32_overflow ; can't happen
rjmp si7021Muls16x16_32_loop
si7021Muls16x16_32_done:
clc
ret
;si7021Muls16x16_32_overflow: ; never reached. Multiplying 2 16 bit values can't overflow 32 bit
; sec
; ret
SI7021_SendTemp:
lds r16, si7021Flags
andi r16, SI7021_FLAGS_TEMP_VALID
brne SI7021_SendTemp_haveValue
sec
ret
SI7021_SendTemp_haveValue:
ldi r16, 0xff ; destination address
ldi r17, VALUE_ID_TEMP1 ; value id
ldi r22, AQHOME_VALUETYPE_TEMP
lds r18, si7021LastTemp ; value
lds r19, si7021LastTemp+1
ldi r20, 100 ; denominator
clr r21
rjmp SI7021_SendValue
SI7021_SendHumidity:
lds r16, si7021Flags
andi r16, SI7021_FLAGS_HUM_VALID
brne SI7021_SendHumidity_haveValue
clc
ret
SI7021_SendHumidity_haveValue:
ldi r16, 0xff ; destination address
ldi r17, VALUE_ID_HUM1 ; value id
ldi r22, AQHOME_VALUETYPE_HUMIDITY
lds r18, si7021LastHumidity ; value
lds r19, si7021LastHumidity+1
ldi r20, 1 ; denominator
clr r21
rjmp SI7021_SendValue
SI7021_SendValue:
ldi xl, LOW(com2SendBuffer)
ldi xh, HIGH(com2SendBuffer)
rcall CPRO_WriteValue
rjmp COM2_SendPacket
SI7021_END:
.equ MODULE_SIZE_SI7021 = SI7021_END-SI7021_BEGIN

109
avr/modules/stats/stats.asm Normal file
View File

@@ -0,0 +1,109 @@
; ***************************************************************************
; copyright : (C) 2023 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 STATS_POS_MAX = 4
.equ STATS_POS_SEND = 4
.equ STATS_POS_RECV = 3
.equ STATS_POS_SYS = 2
.equ STATS_POS_MEM = 1
; ***************************************************************************
; data
.dseg
statsDataBegin:
statsRemaining: .byte 1
statsDataEnd:
statsSendTimer: .byte 2 ; intentionally outside zeroed out are
; ***************************************************************************
; code
.cseg
Stats_Init:
; preset SRAM data area
ldi xh, HIGH(statsDataBegin)
ldi xl, LOW(statsDataBegin)
clr r16
ldi r17, (statsDataEnd-statsDataBegin)
rcall Utils_FillSram
sec
ret
Stats_Run:
in r15, SREG
push r15
cli
ldi xl, LOW(com2SendBuffer)
ldi xh, HIGH(com2SendBuffer)
ldi r16, 0xff
lds r17, statsRemaining
tst r17
breq Stats_Run_done
cpi r17, STATS_POS_RECV
brne Stats_Run_l1
rcall CPRO_WriteComRecvStats
rjmp Stats_Run_SendPacket
Stats_Run_l1:
cpi r17, STATS_POS_SYS
brne Stats_Run_l2
rcall CPRO_WriteSysStats
rjmp Stats_Run_SendPacket
Stats_Run_l2:
cpi r17, STATS_POS_MEM
brne Stats_Run_l3
rcall CPRO_WriteMemStats
rjmp Stats_Run_SendPacket
Stats_Run_l3:
cpi r17, STATS_POS_SEND
brne Stats_Run_l4
rcall CPRO_WriteComSendStats
rjmp Stats_Run_SendPacket
Stats_Run_l4:
; add more stats here
rjmp Stats_Run_done
Stats_Run_SendPacket:
rcall COM2_SendPacket
brcc Stats_Run_done ; only decrement counter if message successfully sent
lds r16, statsRemaining
dec r16
sts statsRemaining, r16
Stats_Run_done:
pop r15
out SREG, r15
clc
ret
Stats_Timer:
ldi r16, STATS_POS_MAX ; RECV, SYS
sts statsRemaining, r16
ret

332
avr/modules/timer/timer.asm Normal file
View File

@@ -0,0 +1,332 @@
; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ***************************************************************************
; defs
.equ TIMER_FLAGS_IF_ADDR = 1
; ***************************************************************************
; data
.dseg
timerModuleData:
timerModuleTickCounter: .byte 1
timerTicksSinceLastRun: .byte 2
timerModuleCounterSecs: .byte 4
timerInterrupts: .byte 2
timerModuleData_end:
; ***************************************************************************
; code
.cseg
TIMER_BEGIN:
; ---------------------------------------------------------------------------
; Timer_Init
;
; IN:
; - nothing
; OUT:
; - nothing
; USED: r16, r17, x
Timer_Init: ; setup timer for IRQ every 100ms
; reset data in SDRAM
ldi xh, HIGH(timerModuleData)
ldi xl, LOW(timerModuleData)
ldi r16, 0
ldi r17, (timerModuleData_end-timerModuleData)
rcall Utils_FillSram
; CTC mode (WGM2:0=2, OCR0A=value, OCF0A Flag =1, -> IRQ_OC0A
; CMP-A interrupt about every 100ms
ldi r16, (1<<CS02) | (1<<CS00) ; Prescaler 1024
out TCCR0B, r16
ldi r16, (1<<WGM01) ; CTC mode
out TCCR0A, r16
ldi r16, 98-1 ; (1,000,000/1024)/10 = 97.65625
out OCR0A, r16
ldi r16, (1<<OCF0A) ; clear pending interrupts
out TIFR0, r16
ldi r16, (1<<OCIE0A)
out TIMSK0, r16
rcall timerInitTimers
ret
; ---------------------------------------------------------------------------
; Timer_Fini
;
; IN:
; - nothing
; OUT:
; - nothing
; USED:
Timer_Fini:
ret
; ---------------------------------------------------------------------------
; Timer_Run
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if something done, cleared otherwise
; USED: r15, r16, r24, r25 (more depending on called routines)
Timer_Run:
in r15, SREG
cli
lds r24, timerTicksSinceLastRun
lds r25, timerTicksSinceLastRun+1
clr r16 ; replace with 0 for next IRQ
sts timerTicksSinceLastRun, r16
sts timerTicksSinceLastRun+1, r16
out SREG, r15 ; restore global IRQ flag
sbiw r25:r24, 0
clc ; flag "nothing done"
breq Timer_Run_End
Timer_Run_loop: ; for every occurred 100ms irq
push r24
push r25
rcall onEvery100ms
pop r25
pop r24
lds r16, timerModuleTickCounter
inc r16
cpi r16, 10
brcc Timer_Run_SecondElapsed
sts timerModuleTickCounter, r16
rjmp Timer_Run_loop_end
Timer_Run_SecondElapsed:
clr r16
sts timerModuleTickCounter, r16
push r24
push r25
rcall timerRunTimers
pop r25
pop r24
Timer_Run_loop_end:
sbiw r25:r24, 1
brne Timer_Run_loop
sec
Timer_Run_End:
ret
; ---------------------------------------------------------------------------
; Set timer value.
;
; Setting a timer to 0 effectively stops the timer.
;
; IN:
; - r16: new timer value (low)
; - r17: new timer value (high)
; - X : pointer to timer value in SRAM
; OUT:
; - nothing
; REGS: X
Timer_SetValue:
push r15
in r15, SREG
cli
st X+, r16
st X+, r17
out SREG, r15
pop r15
ret
; ---------------------------------------------------------------------------
; Set timer value to 1s.
;
; IN:
; - X : pointer to timer value in SRAM
; OUT:
; - nothing
; REGS: X
Timer_SetValueTo1s:
push r16
push r17
ldi r16, 1
clr r17
rcall Timer_SetValue
pop r17
pop r16
ret
timerInitTimers:
ldi zl, LOW(timerList*2)
ldi zh, HIGH(timerList*2)
clr r16 ; run var for pos in time table
clr r17 ; 0 for adc
timerInitTimers_loop:
rcall timerReadTableEntry
mov r18, xl
or r18, xh
breq timerInitTimers_end
mov r18, r20
or r18, r21
breq timerInitTimers_writeInitial
add r20, r16 ; add counter pos in table so that not all timers elapse at the same time
adc r21, r17
timerInitTimers_writeInitial:
st X+, r20
st X, r21
inc r16
inc r16
rjmp timerInitTimers_loop
timerInitTimers_end:
ret
timerRunTimers:
ldi xl, LOW(timerModuleCounterSecs)
ldi xh, HIGH(timerModuleCounterSecs)
rcall Utils_IncrementCounter32
ldi zl, LOW(timerList*2)
ldi zh, HIGH(timerList*2)
timerRunTimers_loop:
rcall timerReadTableEntry
mov r16, xl
or r16, xh
breq timerRunTimers_end
mov r16, r22
andi r16, TIMER_FLAGS_IF_ADDR
breq timerRunTimers_l1 ; no need to check address
lds r16, com2Address ; check address
tst r16
breq timerRunTimers_loop ; no address, ignore counter
timerRunTimers_l1:
ld r24, X+
ld r25, X
sbiw r25:r24, 1
brcs timerRunTimers_loop ; overflow, so already was zero, ignore entry
breq timerRunTimers_reachedZero ; reached zero
st X, r25
st -X, r24
rjmp timerRunTimers_loop
timerRunTimers_reachedZero:
st X, r21 ; reset initial value
st -X, r20
push zl
push zh
rcall timerCallR19R18
pop zh
pop zl
rjmp timerRunTimers_loop
timerRunTimers_end:
ret
; ---------------------------------------------------------------------------
; read time table entry.
;
; IN:
; - Z : pointer to time list entry (suitable for LPM)
; OUT:
; - r19:r18: handler routine
; - X : SRAM address for counter
; - r21:r20: initial value
; - r22 : flags
; - r23 : reserved
timerReadTableEntry:
lpm xl, Z+ ; SRAM address of counter
lpm xh, Z+
lpm r18, Z+ ; routine (low)
lpm r19, Z+ ; routine (high)
lpm r22, Z+ ; flags
lpm r23, Z+ ; reserved
lpm r20, Z+ ; initial value
lpm r21, Z+
ret
timerCallR19R18:
push r18
push r19
ret
; ---------------------------------------------------------------------------
; OC0A interrupt handler
;
; Called every 100 milliseconds, increments timerTicksSinceLastRun. The rest is done outside ISR
; in Timer_Run.
timerIrqOC0A:
push r15
in r15, SREG
push r24
push r25
lds r24, timerTicksSinceLastRun
lds r25, timerTicksSinceLastRun+1
adiw r25:r24, 1
sts timerTicksSinceLastRun, r24
sts timerTicksSinceLastRun+1, r25
lds r24, timerInterrupts
lds r25, timerInterrupts+1
adiw r25:r24, 1
sts timerInterrupts, r24
sts timerInterrupts+1, r25
pop r25
pop r24
out SREG, r15
pop r15
reti
TIMER_END:
.equ MODULE_SIZE_TIMER = TIMER_END-TIMER_BEGIN

View File

@@ -0,0 +1,441 @@
; ***************************************************************************
; copyright : (C) 2023 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 TWI_BIT_LENGTH = 10000 ; 100000 and 200000 works for display: 10000, 100000, 200000
; ***************************************************************************
; data
.dseg
twiMasterDataBegin:
twiMasterScanEnabled: .byte 1
twiMasterLastScanned: .byte 1
twiMasterDataEnd:
; ***************************************************************************
; code
.cseg
TWIMASTER_BEGIN:
; ---------------------------------------------------------------------------
; macros
.macro twiClockHi
cbi TWI_DDR_SCL, TWI_PINNUM_SCL ; set to input
cbi TWI_PORT_SCL, TWI_PINNUM_SCL ; disable internal pullup
.endmacro
.macro twiClockLo
sbi TWI_DDR_SCL, TWI_PINNUM_SCL ; set to output
cbi TWI_PORT_SCL, TWI_PINNUM_SCL ; set to low
.endmacro
.macro twiDataHi
cbi TWI_DDR_SDA, TWI_PINNUM_SDA ; set to input
cbi TWI_PORT_SDA, TWI_PINNUM_SDA ; disable internal pullup
.endmacro
.macro twiDataLo
sbi TWI_DDR_SDA, TWI_PINNUM_SDA ; set to output
cbi TWI_PORT_SDA, TWI_PINNUM_SDA ; set to low
.endmacro
; ---------------------------------------------------------------------------
; TWI_Master_Init
;
; IN:
; OUT:
; - CFLAG: set if okay, clear on error
; USED:
TWI_Master_Init:
twiClockHi
twiDataHi
; preset SRAM data area
ldi xh, HIGH(twiMasterDataBegin)
ldi xl, LOW(twiMasterDataBegin)
clr r16
ldi r17, (twiMasterDataEnd-twiMasterDataBegin)
rcall Utils_FillSram
sec
ret
; ---------------------------------------------------------------------------
; TWI_Master_Fini
;
; IN:
; OUT:
; USED:
TWI_Master_Fini:
sec
ret
; ---------------------------------------------------------------------------
; TWI_Master_Run
;
; IN:
; OUT:
; USED:
TWI_Master_Run:
clc
ret
; ---------------------------------------------------------------------------
; twiStart
;
; Send START condition on the bus.
;
; IN:
; - nothing
; OUT:
; - nothing
; USED: R22
twiStart:
twiDataHi
Utils_WaitNanoSecs TWI_BIT_LENGTH, 0, r22
twiClockHi
Utils_WaitNanoSecs TWI_BIT_LENGTH, 0, r22
twiDataLo
Utils_WaitNanoSecs TWI_BIT_LENGTH, 0, r22
twiClockLo
Utils_WaitNanoSecs TWI_BIT_LENGTH, 0, r22
ret
; ---------------------------------------------------------------------------
; twiStop
;
; Send STOP condition on the bus.
;
; IN:
; - nothing
; OUT:
; - nothing
; USED: R22
twiStop:
twiDataLo
Utils_WaitNanoSecs TWI_BIT_LENGTH, 0, r22
twiClockHi
Utils_WaitNanoSecs TWI_BIT_LENGTH, 0, r22
twiDataHi
Utils_WaitNanoSecs TWI_BIT_LENGTH, 0, r22
ret
; ---------------------------------------------------------------------------
; twiRestart
;
; Send START condition again (needed for some chips to send address in write mode
; and receive data afterwards in read mode).
;
; IN:
; - nothing
; OUT:
; - nothing
; USED: R22
twiRestart:
twiDataHi
twiClockHi
rjmp twiStart
; ---------------------------------------------------------------------------
; twiReadBit
;
; Read a bit from the line (handling SCL line and possible clock stretching).
;
; IN:
; - nothing
; OUT:
; - CARRY flag set: okay, cleared on error
; - R16: bit read (if CARRY flag set), i.e. 0x00 or 0x01
; USED: R16, R22
twiReadBit:
twiDataHi
Utils_WaitNanoSecs TWI_BIT_LENGTH, 0, r22
twiClockHi
Utils_WaitNanoSecs TWI_BIT_LENGTH, 0, r22
ldi r16, 100
twiReadBit_loop:
sbic TWI_PIN_SCL, TWI_PINNUM_SCL
rjmp twiReadBit_clockReleased
Utils_WaitNanoSecs TWI_BIT_LENGTH/20, 0, r22
dec r16
brne twiReadBit_loop
; timeout
clc
ret
twiReadBit_clockReleased:
Utils_WaitNanoSecs TWI_BIT_LENGTH, 0, r22
ldi r16, 1
sbis TWI_PIN_SDA, TWI_PINNUM_SDA
clr r16
Utils_WaitNanoSecs TWI_BIT_LENGTH, 0, r22
twiClockLo
Utils_WaitNanoSecs TWI_BIT_LENGTH, 0, r22
sec
ret
; ---------------------------------------------------------------------------
; twiWriteBit
;
; Write a bit to the line (handling SCL and SDA line and possible clock stretching).
;
; IN:
; - R16: bit to send (either 0x00 or 0x01)
; OUT:
; - CARRY flag set: okay, cleared on error
; USED: R16, R22
twiWriteBit:
twiClockLo
Utils_WaitNanoSecs TWI_BIT_LENGTH, 0, r22
tst r16
breq twiWriteBit_write0
twiDataHi
rjmp twiWriteBit_written
twiWriteBit_write0:
twiDataLo
twiWriteBit_written:
Utils_WaitNanoSecs TWI_BIT_LENGTH, 0, r22
twiClockHi
Utils_WaitNanoSecs TWI_BIT_LENGTH, 0, r22
ldi r16, 100
twiWriteBit_loop:
sbic TWI_PIN_SCL, TWI_PINNUM_SCL
rjmp twiWriteBit_clockReleased
Utils_WaitNanoSecs TWI_BIT_LENGTH/20, 0, r22
dec r16
brne twiWriteBit_loop
; timeout
clc
ret
twiWriteBit_clockReleased:
Utils_WaitNanoSecs TWI_BIT_LENGTH, 0, r22
twiClockLo
Utils_WaitNanoSecs TWI_BIT_LENGTH, 0, r22
sec
ret
; ---------------------------------------------------------------------------
; twiSendByte
;
; Write a byte to the bus and reads the ACK bit back.
;
; IN:
; - R16: byte to send
; OUT:
; - CARRY flag set: okay, cleared on error
; - R16: ACK bit read (0x00 or 0x01)
; USED: R16, R17, R18, R22
twiSendByte:
mov r17, r16
ldi r18, 8
twiSendByte_loop:
clr r16
lsl r17 ; shift MSB out into carry flag
rol r16 ; shift carry flag into r16
rcall twiWriteBit ; (R16, R22)
brcc twiSendByte_error
dec r18
brne twiSendByte_loop
rcall twiReadBit ; r16: ACK bit received
brcc twiSendByte_error
sec
ret
twiSendByte_error:
clc
ret
; ---------------------------------------------------------------------------
; twiSendByteExpectAck
;
; Write a byte to the bus and expect ACK response.
;
; IN:
; - R16: byte to send
; OUT:
; - CARRY flag set: okay, cleared on error (including case of non-ACK response)
; USED: R16, R17, R18, R22
twiSendByteExpectAck:
rcall twiSendByte
brcc twiSendByteExpectAck_error
tst r16
brne twiSendByteExpectAck_error
sec
ret
twiSendByteExpectAck_error:
clc
ret
; ---------------------------------------------------------------------------
; twiReceiveByte
;
; Read a byte from the bus. Does not send an ACK bit, this must be done by the caller,
; if required.
;
; IN:
; OUT:
; - CARRY flag set: okay, cleared on error
; - R16: byte received
; USED: R16, R17, R18, R22
twiReceiveByte:
clr r17
ldi r18, 8
twiReceiveByte_loop:
rcall twiReadBit ; (R16, R22)
brcc twiReceiveByte_error
lsr r16
rol r17
dec r18
brne twiReceiveByte_loop
mov r16, r17
sec
ret
twiReceiveByte_error:
clc
ret
; ---------------------------------------------------------------------------
; twiReceiveByteSendAck
;
; Read a byte from the bus. Sends ACK bit.
;
; IN:
; OUT:
; - CARRY flag set: okay, cleared on error
; - R16: byte received
; USED: R16, R17, R18, R22
twiReceiveByteSendAck:
rcall twiReceiveByte
brcc twiReceiveByteSendAck_error
push r16
clr r16
rcall twiWriteBit ; send ACK (R16, R22)
pop r16
sec
ret
twiReceiveByteSendAck_error:
clc
ret
#ifdef WITH_DEBUG
TWI_Master_ScanNext:
in r15, SREG
cli
lds r16, twiMasterScanEnabled
tst r16
breq TWI_Master_ScanNext_end
lds r16, twiMasterLastScanned
tst r16
brne TWI_Master_ScanNext_inc
ldi r16, 7
TWI_Master_ScanNext_inc:
inc r16
cpi r16, 121
breq TWI_Master_ScanNext_finshed
; check current address
mov r21, r16
rcall twiStart
sec
rol r16 ; (ADDR<<1) + 1: read from address
rcall twiSendByte
brcc TWI_Master_ScanNext_abort ; clock stretching too long, bus error
sts twiMasterLastScanned, r21
rcall twiStop
tst r16
brne TWI_Master_ScanNext_noAnswer
; send message about available address
mov r1, r21
ldi r16, 1
mov r2, r16
ldi r16, 255 ; send to all
push r15
rcall CPRO_EnqueueTwiBusMember
pop r15
rjmp TWI_Master_ScanNext_end
TWI_Master_ScanNext_noAnswer:
; send message about available address
; mov r1, r21
; clr r2
; ldi r16, 255 ; send to all
; push r15
; rcall CPRO_EnqueueTwiBusMember
; pop r15
rjmp TWI_Master_ScanNext_end
TWI_Master_ScanNext_abort:
rcall twiStop
rjmp TWI_Master_ScanNext_end
TWI_Master_ScanNext_finshed:
clr r16
sts twiMasterScanEnabled, r16
TWI_Master_ScanNext_end:
out SREG, r15
ret
#endif
TWIMASTER_END:
.equ MODULE_SIZE_TWIMASTER = TWIMASTER_END-TWIMASTER_BEGIN