From 76ff30ddf10471d7f7fc23a746f0fe7568ff46af Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Sat, 28 Jan 2023 00:10:10 +0100 Subject: [PATCH] TWIMASTER: Added two-wire-master code (bitbang). --- avr/twimaster.asm | 372 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 372 insertions(+) create mode 100644 avr/twimaster.asm diff --git a/avr/twimaster.asm b/avr/twimaster.asm new file mode 100644 index 0000000..6f20562 --- /dev/null +++ b/avr/twimaster.asm @@ -0,0 +1,372 @@ + +; *************************************************************************** +; defines + +.equ TWI_BIT_LENGTH = 100000 ; 100000 and 200000 works for display + + + +; *************************************************************************** +; 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 + + + +; --------------------------------------------------------------------------- +; 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 + brcc twiReceiveByte_error + lsr r16 + rol r17 + dec r18 + brne twiReceiveByte_loop + mov r16, r17 + sec + ret +twiReceiveByte_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 COM_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 COM_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 + +