'I2C slave, fSCL = 400kHz OK 'reads 1st byte after I2C START and stores to I2C_address 'if this is valid I2C write address of this slave, reads next 0/1/2 bytes, ' stores them to I2C_b1 and I2C_b2 and calls "Process_received_data" subroutine 'if this is valid I2C read address of this slave, calls "Prepare_data_for_master" subroutine, ' and sends prepared byte to the master 'else, waits for next START/STOP $crystal = 9600000 $regfile = "ATtiny13.dat" $hwstack = 16 $swstack = 0 $framesize = 24 Dim I2c_address As Byte , I2c_b1 As Byte , I2c_b2 As Byte , I2c_stop As Byte Dim Data_for_master As Byte , Address As Byte , Address_ee As Eram Byte Dim Learning_mode As Byte Const Scl = 4 Const Sda = 3 Const Ack = 3 Config Pinb.4 = Input 'SCL Config Pinb.3 = Input 'SDA,ACK Portb.scl = 0 'will generate delayed SCL when pinb.3=Output Portb.sda = 0 'will generate ACK when pinb.3=Output Clkpr = &B10000000 'set 9.6MHz clock Clkpr = &B00000000 Waitms 200 Learning_mode = 0 Gosub Learning_mode_hw_activation Address = Address_ee And &B11111110 'get write address from eeprom Do I2c_get: sbis pinb,scl 'wait for SCL&SDA=1 rjmp i2c_get sbis pinb,sda rjmp i2c_get I2c_wait_for_start: sbis pinb,scl 'wait for SCL=1,SDA=0 (START) rjmp i2c_get sbic pinb,sda rjmp i2c_wait_for_start I2c_get_0: 'clear receive area clr r22 sts {i2c_address},r22 sts {i2c_b1},r22 sts {i2c_b2},r22 sts {i2c_stop},r22 I2c_get_1: 'get 1st byte I2c_10: 'wait for SCL=0 sbic pinb,scl rjmp i2c_10 ldi r22,8 'bits to receive=8 lds r23,{address} 'I2C address->R23 I2c_11: sbis pinb,scl 'wait for SCL=1 rjmp i2c_11 sbic pinb,sda rjmp i2c_13 I2c_12: 'if SDA=0 sbic pinb,sda rjmp i2c_wait_for_start ' SDA 0->1? I2CSTOP! (unexpected: wait for next start) sbic pinb,scl rjmp i2c_12 ' loop while SCL=1 clc ' SDA=0->C rjmp i2c_15 I2c_13: 'if SDA=1 sbis pinb,sda rjmp i2c_get_1 ' SDA 1->0? I2CSTART! (repeated start) sbic pinb,scl rjmp i2c_13 ' loop while SCL=1 sec ' SDA=1->C I2c_15: rol r24 dec r22 brne i2c_11 'loop to next bit sts {i2c_address},r24 ! SUB r24,r23 'my address? cpi r24,2 brlo i2c_ack_1 rjmp i2c_exit ' no: exit and wait for next start I2c_ack_1: ' yes: generate ack sbi ddrb,ack 'pinb.ack = output (ACK) I2c_ack_10: sbis pinb,scl 'wait for SCL=1 rjmp i2c_ack_10 I2c_ack_11: sbic pinb,scl 'wait for SCL=0 rjmp i2c_ack_11 cbi ddrb,ack 'pinb.ack = input cpi r24,0 breq i2c_get_2 I2c_send_1: 'read address received sbi ddrb,scl 'pinb.scl = output (delayed SCL) rcall prepare_data_for_master ldi r22,8 lds r23,{address} 'I2C address->R23 lds r24,{data_for_master} sbi ddrb,sda 'pinb.sda = output (will send data) I2c_s1: sbrc r24,7 sbi portb,sda sbrs r24,7 cbi portb,sda cbi ddrb,scl 'pinb.scl = input (enable clock) I2c_s2: sbis pinb,scl 'wait for SCL=1 rjmp i2c_s2 I2c_s3: sbic pinb,scl 'wait for SCL=0 rjmp i2c_s3 rol r24 dec r22 brne i2c_s1 cbi portb,sda 'pinb.sda = 0 (will generate ACK) cbi ddrb,sda 'pinb.sda = input (will receive data) rjmp i2c_wait_for_start_stop 'wait for next start/stop I2c_get_2: 'write address received: get 2nd byte I2c_20: 'wait for SCL=0 sbic pinb,scl rjmp i2c_20 ldi r22,8 'bits to receive=8 I2c_21: sbis pinb,scl 'wait for SCL=1 rjmp i2c_21 sbic pinb,sda rjmp i2c_23 I2c_22: 'if SDA=0 sbic pinb,sda rjmp i2c_stop ' SDA 0->1? I2CSTOP! (finish this sequence) sbic pinb,scl rjmp i2c_22 ' loop while SCL=1 clc ' SDA=0->C rjmp i2c_25 I2c_23: 'if SDA=1 sbis pinb,sda rjmp i2c_get_1 ' SDA 1->0? I2CSTART! (repeated start) sbic pinb,scl rjmp i2c_23 ' loop while SCL=1 sec ' SDA=1->C I2c_25: rol r24 dec r22 brne i2c_21 'loop to next bit sts {i2c_b1},r24 'store received I2C address I2c_ack_2: 'generate ack sbi ddrb,ack 'pinb.ack = output (ACK) I2c_ack_20: sbis pinb,scl 'wait for SCL=1 rjmp i2c_ack_20 I2c_ack_21: sbic pinb,scl 'wait for SCL=0 rjmp i2c_ack_21 cbi ddrb,ack 'pinb.ack = input I2c_get_3: 'get 3rd byte I2c_30: 'wait for SCL=0 sbic pinb,scl rjmp i2c_30 ldi r22,8 'bits to receive=8 I2c_31: sbis pinb,scl 'wait for SCL=1 rjmp i2c_31 sbic pinb,sda rjmp i2c_33 I2c_32: 'if SDA=0 sbic pinb,sda rjmp i2c_stop ' SDA 0->1? I2CSTOP! (finish this sequence) sbic pinb,scl rjmp i2c_32 ' loop while SCL=1 clc ' SDA=0->C rjmp i2c_35 I2c_33: 'if SDA=1 sbis pinb,sda rjmp i2c_get_1 ' SDA 1->0? I2CSTART! (repeated start) sbic pinb,scl rjmp i2c_33 ' loop while SCL=1 sec ' SDA=1->C I2c_35: rol r24 dec r22 brne i2c_31 'loop to next bit sts {i2c_b2},r24 I2c_ack_3: 'generate ack sbi ddrb,ack 'pinb.ack = output (ACK) I2c_ack_30: sbis pinb,scl 'wait for SCL=1 rjmp i2c_ack_30 I2c_ack_31: sbic pinb,scl 'wait for SCL=0 rjmp i2c_ack_31 cbi ddrb,ack 'pinb.ack = input I2c_wait_for_start_stop: 'wait for start/stop I2c_ss_1: sbis pinb,scl 'wait for SCL=1 rjmp i2c_ss_1 sbic pinb,sda rjmp i2c_ss_3 I2c_ss_2: 'if SDA=0 sbic pinb,sda rjmp i2c_stop ' SDA 0->1? I2CSTOP! (finish this sequence) sbic pinb,scl rjmp i2c_ss_2 ' loop while SCL=1 rjmp i2c_ss_1 I2c_ss_3: 'if SDA=1 sbis pinb,sda rjmp i2c_get_1 ' SDA 1->0? I2CSTART! (repeated start) sbic pinb,scl rjmp i2c_ss_3 ' loop while SCL=1 rjmp i2c_ss_1 ' SDA=1->C I2c_stop: 'if stop, ldi r22,255 ' set flag and exit sts {i2c_stop},r22 I2c_exit: If Learning_mode > 0 Then 'if in learn mode, Address_ee = I2c_address ' remember the new address in eeprom Address = Address_ee And &B11111110 ' get write address from eeprom Learning_mode = 0 Elseif Address = I2c_address Then 'if valid I2C command received, Gosub Process_received_data ' call the subroutine for the evaluation End If Loop End ' *** here goes I2C address of this chip to be stored in the internal EEPROM ' *** BascomAVR compiler will produce .eep file for the programmer $eeprom Data &HAE 'address of this I2C slave $data ' *** PROCESS_RECEIVED_DATA *** ' *** this subroutine is called if valid write address of this I2C slave is received ' *** user should process received data (according to protocol 0-2B may be received): ' *** I2C_b1 (1B), usualy address, = 0 if not received ' *** I2C_b2 (1B), usualy data , = 0 if not received ' *** I2C_stop (1B) = 255 if STOP is received, = 0 if not Process_received_data: Writeeeprom I2c_b2 , I2c_b1 'in this example, I2C_b2 byte is written to internal eeprom at I2C_b1 Waitms 5 Return ' *** PREPARE_DATA_FOR_MASTER *** ' *** this subroutine is called if valid read address of this I2C slave is received ' *** user should prepare 1B of data in "Data_for_master" to be sent to the master: Prepare_data_for_master: Readeeprom Data_for_master , I2c_b1 'in this example, 1 byte is red from internal eeprom at I2C_b1 Return ' *** LEARNINIG_MODE_HW_ACTIVATION *** ' *** this subroutine is called at the beginning of the program to check if ' *** leaning mode is activated externaly (for example, connecting Pinx.y to gnd); ' *** to disable HW activation, should be empty: Learning_mode_hw_activation: ' Config Pinx.y = Input ' If Pinx.y = 0 Then ' Learning_mode = 1 ' Bitwait Pinx.y , Set ' End If Return