Files
aqhomecontrol/avr/twimaster.asm
2023-02-04 00:56:29 +01:00

423 lines
8.0 KiB
NASM

; ***************************************************************************
; 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
; ---------------------------------------------------------------------------
; 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 from 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
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_EnqueueI2cBusMember
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_EnqueueI2cBusMember
; 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