This article explores the TWI interface between two ATmega32 controllers. Readers are advised to consult the TWI Communication and TWI records for the ATmega32 before proceeding.
TWI works in four modes:
1. MASTER as transmitter.
two. MASTER as receiver.
3. SLAVE as receiver.
4. SLAVE as transmitter.
Generally modes 1 and 3 and modes 2 and 4 are used together. This article explains the use of these four modes in an experiment.
Objective: Establish communication between two ATmega32 using TWI interface. First the Master starts sending data and then the slave transmits the complement of data received to the master. When the Master receives the supplemented data, it shifts the original data to the left. This process of transmission and reception continues. As the data value reaches 0x80, the entire process is repeated. At the beginning, the original data value is 0x01. The received value is displayed in PORTB at both ends.
Circuit Description:
Make connections as shown in the circuit diagram.
Explanation of the code for the MASTER controller:
Step 1: Master initialization.
MASTER initialization means setting the TWI clock frequency (SCL). This is done by setting the bitrate in TWBR and the prescaler bits in TWSR.

Fig. 2: TWI clock frequency equation for initializing the master in the AVR
void TWI_init_master(void) // Function to initialize master
{
TWBR=0x01; // Bit rate
TWSR=(0<<TWPS1) (0<<TWPS0); // Setting prescalar bits
// SCL freq= F_CPU/(16+2(TWBR).4^TWPS)
}
Step 2: Send initial condition
The initial condition in TWI was explained previously. The AVR microcontroller has built-in registers that make this job much easier.
1. Clear the TWINT flag by writing a logical to it.
two. Set the TWSTA bit to send the start condition.
3. Set the TWEN bit to initialize TWI.
4. Monitor the status of the TWINT flag.
5. Check the ACK byte (using while condition as SCL frequency is very small compared to microcontroller clock frequency). The ACK byte can be compared by monitoring the TWSR status.
void TWI_start(void)
{
// Clear TWI interrupt flag, Put start condition on SDA, Enable TWI
TWCR= (1<<TWINT) (1<<TWSTA) (1<<TWEN);
while(!(TWCR & (1<<TWINT))); // Wait till start condition is transmitted
while((TWSR & 0xF8)!= 0x08); // Check for the acknowledgment
}
Step 3: Send slave address, data direction (write) bit and wait for ACK signal
Fig. 3: Initial condition bit in TWI
These three processes are controlled by the AVR's TWI registers .
1. Put the seven-bit slave address and direction control bit into the TWDR.
two. Clear the TWINT flag.
3. Enable TWI by writing logic one to the TWEN bit.
4. Monitor the status of the TWINT flag, the TWINT flag will be cleared when data in TWDR is transmitted.
5. Check correct recognition.
void TWI_read_address(unsigned char data)
{
TWDR=date; // Address and read instructions
TWCR=(1<<TWINT) (1<<TWEN); // Clear TWI interrupt flag,Enable TWI
while (!(TWCR & (1<<TWINT))); // Wait until complete TWDR byte received
while((TWSR & 0xF8)!= 0x40); // Check for the acknowledgment
}
Step 4: Send 8-bit data and wait for ACK
Fig. 4: Data transfer in TWI from the AVR
1. Put 8-bit data into TWDR.
8 bits = 7-bit slave address + data direction bit (write = 0).
two. Clear the TWINT flag.
3. Set the TWEN bit to enable TWI.
4. Monitor the status of the TWINT flag to complete data transmission.
5. Check recognition.
void TWI_write_data(unsigned char data)
{
TWDR=date; // put data in TWDR
TWCR=(1<<TWINT) (1<<TWEN); // Clear TWI interrupt flag,Enable TWI
while (!(TWCR & (1<<TWINT))); // Wait until complete TWDR byte transmitted
while((TWSR & 0xF8) != 0x28); // Check for the acknowledgment
}
Step 5: Send the STOP condition

Fig.5: TWI STOP condition bit
To send the stop condition use TWSTO
1. Clear the TWINT flag.
two. Set TWEN bit
3. Write logic one in the TWSTO bit to send the STOP condition on the SDA and SCL line.
4. Monitor the status of the TWSTO bit, as clearing the TWSO bit means the stop condition has been transmitted.
void TWI_stop(void)
{
// Clear TWI interrupt flag, Put stop condition on SDA, Enable TWI
TWCR= (1<<TWINT) (1<<TWEN) (1<<TWSTO);
while(!(TWCR & (1<<TWSTO))); // Wait till stop condition is transmitted
}
So far the slave side data transmission is complete, the MASTER is working in mode one. According to the objective, the data received by MASTER is displayed in PORTB. The flowchart of MASTER as transmitter (mode one) is given below.

Fig. 6: Flowchart of MASTER as a transmitter on the TWI interface using AVR
From here on, the MASTER would be working in mode two, that is, the MASTER would become a receiver. The AVR TWI operates in mode 2.
Step 6: Send the START condition on the bus lines
This step is so similar to the previous one.
Note : In Step 6, the START condition is sent after the STOP condition. If one more start condition is sent before the intermediate STOP condition, it is called a repeating start condition. The repeating start condition is the same as the START condition, but the only difference is between the commits. For more details on repetitive starting, see the data sheet. If data is sent continuously in the same direction, there is no need for a start condition, repetitive start, or intermediate stop condition. The second data can be transmitted right after receiving acknowledgment of the first byte of data (as shown in the flowchart above).
Step 7: Send slave address and data direction (read) bit and wait for ACK signal
1. Put 8-bit data into TWDR.
8 bits = 7-bit slave address + data direction bit (read = 1).
two. Clear the TWINT flag.
3. Set the TWEN bit to enable TWI.
4. Monitor the status of the TWINT flag to complete data transmission.
5. Check recognition.
void TWI_read_address(unsigned char data)
{
TWDR=date; // Address and read instructions
TWCR=(1<<TWINT) (1<<TWEN); // Clear TWI interrupt flag,Enable TWI
while (!(TWCR & (1<<TWINT))); // Wait until complete TWDR byte received
while((TWSR & 0xF8)!= 0x40); // Check for the acknowledgment
}
Step 8: Read data from the SDA bus
1. Clear TWINT flag
two. Set the TWEN bit, enable TWI
3. Monitor the status of the TWINT flag, as the TIWNT flag set indicates that the value in TWDR has been received.
4. Check recognition. If the master wants to receive the last byte from the slave, the status of the TWSR register will be 0x58. After receiving the last byte, a repetitive start condition is issued by the master to continue the communication or a stop condition must be given by the master to stop the communication process. Otherwise, if the master wants to continue receiving more bytes from the slave, the TWSR register status will be 0x50.
To confirm the saving of the last byte, the TWEA bit is used during data transmission. If the TWEA bit is set, reception will be continuous on the MASTER side. And if the TWEA bit is low, the MASTER orders the slave to send the last byte.
5. Get the received data. And send it to PORTB.
void TWI_read_data(void)
{
TWCR=(1<<TWINT) (1<<TWEN); // Clear TWI interrupt flag,Enable TWI
while (!(TWCR & (1<<TWINT))); // Wait until complete TWDR byte transmitted
while((TWSR & 0xF8) != 0x58); // Check for the acknowledgment
recv_data=TWDR;
PORTB=recv_data;
}
Step 9: Send STOP condition
The stop condition has already been explained.

Fig. 7: Flowchart of MASTER as a receiver on the TWI interface using AVR
Code explanation for the SLAVE controller:
Step 1: Initializing the Slave R control
Initialization of the slave controller is done by assigning an address to the slave. The seven-bit slave address is populated in the TWI slave Address Register (TWAR). The LSB of the TWAR, i.e. the TWGCE bit is used to allow the slave to recognize the general call address (0x00).
void TWI_init_slave(void) // Function to initialize slave
{
TWAR=0x20; // Fill slave address to TWAR
}
Step 2: Check TWSR registration status
If the value of TWSR is 0x60, it means that the data sent by the master in the next step should be read only by this specific slave and the slave sends back the acknowledgment to the master corresponding to the read operation. If the TWSR status is 0x70, SLAVE is requested to read the data in the general call (0x00). In this phase, the SLAVE acts as a receiver. AVR TWI is operating in mode 3.
1. Clear the TWIN flag.
two. Enable TWI.
3. Configure TEWA to receive recognition.
4. Monitor the status of the TWINT flag.
5. Match TWSR status. If status is 0x60 read data or skip to (1)
void TWI_match_read_slave(void) //Function to match the slave address and slave dirction bit(read)
{
while((TWSR & 0xF8)!= 0x60) // Loop until correct acknowledgment has been received
{
// Get acknowledgment, Enable TWI, Clear TWI interrupt flag
TWCR=(1<<TWEA) (1<<TWEN) (1<<TWINT);
while (!(TWCR & (1<<TWINT))); // Wait for TWINT flag
}
}
Step 3: Read the data
Read the data sent by MASTER.
1. Clear the TWINT flag.
two. Enable TWI.
3. Configure TWEA to receive ACK.
4. Get the TWDR data form, display it on PORTB.