;______________________________________ ; MODULE I2C ; Matériel : ATtiny 45/85 4MHz 5V ; ; (c) sammy76.free.fr ; V1.0 2016/06/01 Juin 2016 ;______________________________________ ; V1.0 ; ATtiny45 - 8MHz interne ; +-\/-+ ; PB5 1|- -|8 Vcc ; PB3 2|- -|7 PB2 ; PB4 3|- -|6 PB1 SDA ; GND 4|- -|5 PB0 SCL ; +----+ ;ATtiny85 - 16.5MHz Digispark ;P0 : ;P1 : SENSELED (Interne) ;P2 : ;P3 : SCL ;P4 : SDA ;P5 : ;Registres utilisés r16 (A),r19 (Adresse I²C), r20 (DATA) ; ;.CSEG ;.include "../includes/tn45def.inc" ;.equ I2CREAD = 0x01 ; read/write bit = read ;.equ I2CWRITE = 0x00 ; read/write bit = write ; IO Port Bits .equ bSDA = PB4 ;* SCL Port B, PB1 Pin 6 .equ bSCL = PB3 ;* SDA Port B, PB0 Pin 5 .equ mSDA = (1< 5us ; For I2C in fast mode (400kHz), use T/2 > 1.25us ;************************************************************************* I2CDelay: ldi XH,HIGH(C4PUS*5) ;5us ldi XL,LOW(C4PUS*5) rcall Wait4xCycles ret ; 4 cycle = total 60 cycles = 5.0 microsec with 8 Mhz crystal ;----------------------------------------------------------------- I2CInit: ; Set up port assignments ldi A,mSCL ; SCL only output by default out I2CDDR,A ;out DDRB,1 ldi A,mSCL out I2CPORT,A ; All outputs high, input pullups disabled cbi I2CPORT,bSDA ; Data line always drives low if driven cbi I2CDDR,bSDA ; SDA as input to start with - floats high cbi I2CPORT,bSCL ; Set SCL low to try and avoid... sbi I2CDDR,bSCL ; ...false start transitions rcall I2CDelay rjmp I2CStop ; Stop any erroneous transfer ;----------------------------------------------------------------- ; I2CStart ; Send I2C start condition ; Assumes SCL and SDA are high to start with. ; Leaves SCL and SDA low I2CStart: rcall I2CDelay sbi I2CDDR,bSDA ; Drive data line low (start bit) rcall I2CDelay cbi I2CPORT,bSCL ; Clock line low (ready to start) ret ;----------------------------------------------------------------- ; I2CStop ; Send I2C stop condition ; Assumes SCL is low to start with, SDA may be in either state ; Leaves SCL and SDA high I2CStop: sbi I2CDDR,bSDA ; SDA driven low rcall I2CDelay sbi I2CPORT,bSCL ; Clock line high (ready to stop) rcall I2CDelay cbi I2CDDR,bSDA ; Data line floats high (stop bit) rcall I2CDelay ret ;----------------------------------------------------------------- ;DATA_write_byte ; DATA byte ; ADR adresse byte DATA_write_byte: mov A,DATA ; save value rcall I2CStart mov DATA,ADR rcall I2CSendAddress brne WriteI2cNoAck ; No ack! mov DATA,A rcall I2CSendByte rcall I2CStop ret WriteI2cNoAck: rcall I2CStop clr DCounter WriteI2CErrorDelay: dec DCounter brne WriteI2CErrorDelay mov DATA,A ; restore data value rjmp DATA_write_byte ; and try again ;------------------------------------------------------------------ ; I2CSendByte ; Sends 8 bits of data from DATA and listens for an ACK at the end. ; Returns Z if ack received, else NZ. ; Assumes a start condition has already been sent, and SDA and SCL ; are low Leaves SCL low, SDA not driven. Uses DCounter and DATA. I2CSendAddress: I2CSendByte: push A ldi A,8 mov DCounter,A pop A I2CSendBits: add DATA,DATA ;*2 décalage à gauche brcc I2CSendBits0 ; si carry=0 I2CSendBits0 cbi I2CDDR,bSDA ; send 1 (floats high) rjmp I2CSendBits1 I2CSendBits0: sbi I2CDDR,bSDA ; send 0 (drives low) I2CSendBits1: rcall I2CDelay sbi I2CPORT,bSCL ; clock high rcall I2CDelay cbi I2CPORT,bSCL ; clock low dec DCounter brne I2CSendBits cbi I2CDDR,bSDA ; stop driving data bus rcall I2CDelay sbi I2CPORT,bSCL ; clock high rcall I2CDelay in DATA,I2CPIN ; sample data bus cbi I2CPORT,bSCL ; clock low rcall I2CDelay andi DATA,mSDA ; check ack bit (z set if OK) ret ;------------------------------------------------------------------ ; I2CReadByte Read a byte from the I2C bus and acknowledge ; Si DATA est nul, ACK est envoyé, sinon non. ; Byte is returned in A ; Leaves SCL low, I2C bus not driven. I2CReadByte: ldi A,8 mov DCounter,A clr A cbi I2CDDR,bSDA ; release bus (floats high) I2CReadBits: sbi I2CPORT,bSCL ; clock high rcall I2CDelay add A,A ;<<1 sbic I2CPIN,bSDA ; if SDA clear, skip increment inc A cbi I2CPORT,bSCL ; clock low rcall I2CDelay dec DCounter brne I2CReadBits tst DATA ; Send an ACK...? brne I2CReadBitsNack sbi I2CDDR,bSDA ; yes... drive data bus low I2CReadBitsNack: sbi I2CPORT,bSCL ; clock high rcall I2CDelay cbi I2CPORT,bSCL ; clock low rcall I2CDelay cbi I2CDDR,bSDA ; release bus (floats high) ret