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