Two-Wire Serial Interface (TWI)

Two-Wire Serial Interface (TWI)
  1. Arduino UNO
/**************************************************************** ************ MASTER ****************************************************************/ #include <Wire.h> byte temp; void setup() { Wire.begin(); pinMode(2, OUTPUT); pinMode(3, OUTPUT); digitalWrite(2, HIGH); digitalWrite(3, HIGH); } void loop() { if (digitalRead(2) == LOW) { bitSet(temp, 2); } else { bitClear(temp, 2); } if (digitalRead(3) == LOW) { bitSet(temp, 3); } else { bitClear(temp, 3); } Wire.beginTransmission(8); Wire.write(temp); Wire.endTransmission(); } /**************************************************************** ************ SLAVE ****************************************************************/ #include <Wire.h> byte temp; void setup() { Wire.begin(8); Wire.onReceive(receiveEvent); } void loop() { } void receiveEvent(int howMany) { temp = Wire.read(); digitalWrite(2, bitRead(temp, 2)); digitalWrite(3, bitRead(temp, 3)); }
/**************************************************************** ************ MASTER ****************************************************************/ #include <avr/io.h> #ifndef F_CPU #warning "F_CPU not defined for " #define F_CPU 16000000L #endif void TWI_Init() { // TWI Bit Rate Register. // TWBR selects the division // factor for the bit rate generator. // The bit rate generator is a frequency divider // which generates the SCL clock // frequency in the Master modes. TWBR = ((F_CPU/400000)-16)/2; } void TWI_Start() { // Send START condition TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); // Wait for TWINT Flag set. This indicates // that the START condition has been // transmitted. while ((TWCR&(1<<TWINT))==0); // Check value of TWI Status Register. Mask // prescaler bits. If status different from // START go to ERROR. while ((TWSR & 0xF8) != 0x08); } void TWI_Write_Addr(unsigned char addr) { // Load SLA_W into TWDR Register. TWDR = addr; //TWINT bit in TWCR to start transmission of // address. TWCR = (1<<TWINT)|(1<<TWEN); // Wait for TWINT Flag set. This indicates // that the SLA+W has been transmitted, and // ACK/NACK has been received. while ((TWCR & (1<<TWINT)) == 0); // Check value of TWI Status Register. Mask // prescaler bits. If status different from // MT_SLA_ACK go to ERROR. // 0x18 = SLA+W has been transmitted; ACK has been received while ((TWSR&0xF8) != 0x18); } void TWI_Write_Data(unsigned char data) { // Load DATA into TWDR Register. TWDR = data; // Clear TWINT bit in TWCR to start transmission of data. TWCR = (1<<TWINT)|(1<<TWEN); // Wait for TWINT Flag set. This indicates // that the DATA has been transmitted, and // ACK/NACK has been received. while ((TWCR & (1<<TWINT)) == 0); // Check value of TWI Status Register. Mask // prescaler bits. If status different from // MT_DATA_ACK go to ERROR. while ((TWSR&0xF8) != 0x28); } void TWI_Stop() { // Transmit STOP condition. TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); } int main(void) { DDRD = 0x00; PORTD = 0xff; TWI_Init(); while (1) { TWI_Start(); TWI_Write_Addr(0x20); TWI_Write_Data(~PIND); TWI_Stop(); } } /**************************************************************** ************ SLAVE ****************************************************************/ #include <avr/io.h> #ifndef F_CPU #warning "F_CPU not defined for " #define F_CPU 16000000L #endif #include <util/delay.h> void TWI_Init(unsigned char slave_addr) { TWAR = slave_addr; } unsigned char TWI_Read_Data() { unsigned char x; TWCR = (1<<TWINT) // TWI Interrupt Flag |(1<<TWEA) // TWI Enable Acknowledge |(1<<TWEN) // TWI Enable ; while ((TWCR&(1<<TWINT))==0); // wait to be data has been received; // ACK has been returned while ((TWSR&(0xF8))!=0x80); x = TWDR; return x; } void TWI_Match_ACK() { while ((TWSR&0xF8)!=0x60) { TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA); // Wait for TWINT Flag set. This indicates // that the DATA has been transmitted, and // ACK/NACK has been received. while ((TWCR&(1<<TWINT))==0); } } int main(void) { DDRD = 0xFF; TWI_Init(0x20); while (1) { TWI_Match_ACK(); PORTD = TWI_Read_Data(); } }
/**************************************************************** ************ MASTER ****************************************************************/ .nolist .include "./m328Pdef.inc" .list .def temp = r16 .equ F_CPU = 16000000 .equ BIT_RATE = ((F_CPU/400000)-16)/2 .org 0x0000 rjmp start start: ldi temp, BIT_RATE ldi temp, high(RAMEND) out sph, temp ldi temp, low(RAMEND) out spl, temp clr temp out DDRD, temp ser temp out portd, temp rcall TWI_Init loop: rcall TWI_Start ldi temp, 0x20 ;SLA_W rcall TWI_Write_Addr in temp, PIND com temp rcall TWI_Write_Data rcall TWI_Stop rjmp loop TWI_Init: ldi temp, 0x0c sts TWBR, temp ret TWI_Start: // Send START condition ldi r16, (1<<TWINT)|(1<<TWSTA)|(1<<TWEN) sts TWCR, r16 /* Wait for TWINT Flag set. This indicates that the START condition has been transmitted. */ wait1: lds temp, TWCR sbrs temp,TWINT rjmp wait1 /* Check value of TWI Status Register. Mask prescaler bits. If status different from START go to ERROR. */ lds temp, TWSR andi temp, 0xF8 cpi temp, START brne ERROR TWI_Write_Addr: /* Load SLA_W into TWDR Register. */ sts TWDR, temp //Clear TWINT bit in TWCR to start transmission of address. ldi temp, (1<<TWINT) | (1<<TWEN) sts TWCR, temp /* Wait for TWINT Flag set. This indicates that the SLA+W has been transmitted, and ACK/NACK has been received. */ wait2: lds r16,TWCR sbrs r16,TWINT rjmp wait2 /* Check value of TWI Status Register. Mask prescaler bits. If status different from MT_SLA_ACK go to ERROR. */ lds r16,TWSR andi r16, 0xF8 cpi r16, 0x08 brne ERROR ret TWI_Write_Data: /* Load DATA into TWDR Register. */ sts TWDR, temp // Clear TWINT bit in TWCR to start transmission of data. ldi r16, (1<<TWINT) | (1<<TWEN) sts TWCR, r16 /* Wait for TWINT Flag set. This indicates that the DATA has been transmitted, and ACK/NACK has been received. */ wait3: lds r16,TWCR sbrs r16,TWINT rjmp wait3 /* Check value of TWI Status Register. Mask prescaler bits. If status different from MT_DATA_ACK go to ERROR. */ lds r16,TWSR andi r16, 0xF8 cpi r16, 0x28 brne ERROR ret TWI_Stop: // Transmit STOP condition. ldi temp, (1<<TWINT)|(1<<TWEN)| (1<<TWSTO) sts TWCR, temp ERROR: ret /**************************************************************** ************ SLAVE ****************************************************************/ .nolist .include "./m328Pdef.inc" .list .def temp = r16 .org 0x0000 rjmp start start: ser temp out DDRD, temp ldi temp, 0x20 ; My adress = 1, I don't respond to generic calls sts TWAR, temp ; Set address in TWAR loop: rcall twi rjmp loop twi: ldi temp, (1<<TWEA)|(1<<TWEN) sts TWCR, temp rcall twi_is_twint lds temp, TWSR ; Check TWI status andi temp, 0b11111000 cpi temp, 0x60 brne twi_is_twint ; Check if SLA+W is received ldi temp, (1<<TWINT)|(1<<TWEN)|(1<<TWEA) sts TWCR, temp ; Clear TWINT and enable again rcall twi_is_twint lds temp, TWDR out DDRD, temp out PORTD, temp ret twi_is_twint: lds temp, TWCR sbrs temp, TWINT rjmp twi_is_twint ret