4
\$\begingroup\$

I am a mechanical engineer with the desire of learning electronics stuff.

I am working on these days at learning the TWI(I2C) communication in Atmega32. With a lot of internet search I have managed to get a tutorial explaining how I can make a mutual communication between a pair of Atmega32 chips.

Here is the code of the Master chip

#include<avr/io.h>
#include<util/delay.h>
#include<inttypes.h>

void TWI_start(void);
void TWI_repeated_start(void);
void TWI_init_master(void);
void TWI_write_address(unsigned char);
void TWI_read_address(unsigned char);
void TWI_write_data(unsigned char);
void TWI_read_data(void);
void TWI_stop(void);

unsigned char address=0x20, read=1, write=0;
unsigned char write_data=0x01, recv_data;

int main(void)
{
    _delay_ms(2000);
    DDRB=0xff;
    TWI_init_master();   // Function to initialize TWI
    while(1)
    {
        if(write_data==0x00)    
        write_data=1;

            // Function to send start condition
        TWI_start();
        // Function to write address and data direction bit(write) on SDA
        TWI_write_address(address+write);
        // Function to write data in slave
        TWI_write_data(write_data);
        // Function to send stop condition
        TWI_stop();


        _delay_ms(10);  // Delay of 10 mili second

        TWI_start();    
        // Function to write address and data direction bit(read) on SDA
        TWI_read_address(address+read); 
        TWI_read_data();
        // Function to read data from slave 
        TWI_stop();

        _delay_ms(1000);    

        write_data = write_data * 2;
    }


}

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)
}

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 acknowledgement
}

void TWI_repeated_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 restart condition is transmitted
    while((TWSR & 0xF8)!= 0x10); // Check for the acknowledgement
}

void TWI_write_address(unsigned char data)
{
    TWDR=data;  // Address and write instruction
    TWCR=(1<<TWINT)|(1<<TWEN);    // Clear TWI interrupt flag,Enable TWI
    while (!(TWCR & (1<<TWINT))); // Wait till complete TWDR byte transmitted
    while((TWSR & 0xF8)!= 0x18);  // Check for the acknowledgement
}

void TWI_read_address(unsigned char data)
{
    TWDR=data;  // Address and read instruction
    TWCR=(1<<TWINT)|(1<<TWEN);    // Clear TWI interrupt flag,Enable TWI
    while (!(TWCR & (1<<TWINT))); // Wait till complete TWDR byte received
    while((TWSR & 0xF8)!= 0x40);  // Check for the acknowledgement
}

void TWI_write_data(unsigned char data)
{
    TWDR=data;  // put data in TWDR
    TWCR=(1<<TWINT)|(1<<TWEN);    // Clear TWI interrupt flag,Enable TWI
    while (!(TWCR & (1<<TWINT))); // Wait till complete TWDR byte transmitted
    while((TWSR & 0xF8) != 0x28); // Check for the acknowledgement
}

void TWI_read_data(void)
{
    TWCR=(1<<TWINT)|(1<<TWEN);    // Clear TWI interrupt flag,Enable TWI
    while (!(TWCR & (1<<TWINT))); // Wait till complete TWDR byte transmitted
    while((TWSR & 0xF8) != 0x58); // Check for the acknowledgement
    recv_data=TWDR;
    PORTB=recv_data;
}

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
}

While the code of the Slave chip is:

#include<avr/io.h>
#include<util/delay.h>

void TWI_init_slave(void);
void TWI_match_read_slave(void);
void TWI_read_slave(void);
void TWI_match_write_slave(void);
void TWI_write_slave(void);

unsigned char write_data,recv_data;

int main(void)
{
    DDRB=0xff;
    TWI_init_slave(); // Function to initialize slave
    while(1)
    {
        //Function to match the slave address and slave direction bit(read) 
        TWI_match_read_slave(); 
        // Function to read data
        TWI_read_slave();

        // Togglem the receive data
        write_data=~recv_data;

        //Function to match the slave address and slave direction bit(write) 
        TWI_match_write_slave();
        // Function to write data
        TWI_write_slave();
    }
}

// Function to initialize slave
void TWI_init_slave(void)
{
    // Fill slave address to TWAR
    TWAR=0x20;
}

void TWI_write_slave(void) // Function to write data
{
    // Fill TWDR register with the data to be sent 
    TWDR= write_data;
    // Enable TWI, Clear TWI interrupt flag 
    TWCR= (1<<TWEN)|(1<<TWINT);
    // Wait for the acknowledgement
    while((TWSR & 0xF8) != 0xC0);
}

// Function to match the slave address and slave 
void TWI_match_write_slave(void)dirction bit(write) 
{
    // Loop till correct acknowledgement have been received
    while((TWSR & 0xF8)!= 0xA8)
    {
        // Get acknowledgment, Enable TWI, Clear TWI interrupt flag
        TWCR=(1<<TWEA)|(1<<TWEN)|(1<<TWINT);    
        while (!(TWCR & (1<<TWINT)));  // Wait for TWINT flag
    }
}

void TWI_read_slave(void)
{
    // Clear TWI interrupt flag,Get acknowledgement, Enable TWI
    TWCR= (1<<TWINT)|(1<<TWEA)|(1<<TWEN);   
    // Wait for TWINT flag
    while (!(TWCR & (1<<TWINT)));
    // Wait for acknowledgement
    while((TWSR & 0xF8)!=0x80);
    // Get value from TWDR
    recv_data=TWDR;
    // send the receive value on PORTB
    PORTB=recv_data;
}

//Function to match the slave address and slave direction bit(read)
void TWI_match_read_slave(void)
{
    // Loop till correct acknoledgement have been received
    while((TWSR & 0xF8)!= 0x60)
    {
        // Get acknowlegement, Enable TWI, Clear TWI interrupt flag
        TWCR=(1<<TWEA)|(1<<TWEN)|(1<<TWINT);    
        // Wait for TWINT flag
        while (!(TWCR & (1<<TWINT))); 
    }
}

The code works well in simulation for the very first phase of MasterTransmitter-SlaveReceiver.

However, for the second phase of MasterReceiver-SlaveTransmitter, the simulation seems to show no action and even doesn't step to the MasterTransmitter-SlaveReceiver mode.

\$\endgroup\$

5 Answers 5

2
\$\begingroup\$

The function TWI_match_read_slave() looks wrong to me. You have to enable TWAR and TWCR before checking if the slave has done self-addressing.

enter image description here

void TWI_slave_Rx_init()
{
    TWBR=1;         
    //Setting up the SCL frequency by writing a value in TWBR
    TWSR|=(0<<TWPS1)|(0<<TWPS0);    
    //Fscl=     Fcpu/(16+2*(TWBR)*(4^TWPS))
    TWAR=0b00000010;        
    //The first seven bits indicate the slave address 
    TWCR|=(1<<TWINT);
    TWCR|=(1<<TWEN)|(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO);    
    //Enabling Acknowledge function
    while (!(TWCR & (1<<TWINT)));   
    //Wait for the interrupt to be cleared as it will indicate the successful reception
    while(TWCR&(0xF8)!=(0x60)); 
    //Checking if the self-address+W has been received and ACK has been sent

}

This is how it should be as setting TWEA alone doesn't mean you've sent the acknowledge bit.

Setting TWEA will generate an acknowledge pulse ONLY IF the following conditions are met:

enter image description here

\$\endgroup\$
5
  • 1
    \$\begingroup\$ This answer would be even better if it had references. Could you add some? \$\endgroup\$
    – user17592
    Aug 31, 2014 at 12:05
  • \$\begingroup\$ It's all in the datasheet of ATmega16A. Page no. 196 & 180 respectively for the images. The code was written by me but is yet to be tested. Will update the comment as soon as I check it. I'm a newbie as far as I2C is concerned and I'm writing a library for the same. \$\endgroup\$
    – Adithya
    Aug 31, 2014 at 14:30
  • \$\begingroup\$ When you've checked, please edit your answer to include the result, and please also include a link to the datasheet you're referring to. After that, we can remove these comments. \$\endgroup\$
    – user17592
    Aug 31, 2014 at 14:32
  • \$\begingroup\$ electronicsdatasheets.com/pdf-datasheets/atmel/ATmega16A ATmega16A 's datasheet is up here for downloading. \$\endgroup\$
    – Adithya
    Aug 31, 2014 at 15:35
  • \$\begingroup\$ Sorry! The page nos. are 192 & 180 \$\endgroup\$
    – Adithya
    Aug 31, 2014 at 15:51
1
\$\begingroup\$

Use your DMM and check the voltage level on SDA and SCL. Usually if it gets stuck, it's because the slave got lost and is still holding SDA low.

\$\endgroup\$
0
\$\begingroup\$

In the Slave file: I'm not sure, but both variables write_data, mrecv_data are not initialized, may be that is your problem. In The Master file: recvdata also is not initilaized

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Thanks for help, however, as I think, the compiler sets the uninitialized declared variables to the value of 0x00. For making sure, I initialized all the declared variables to the value of 0x00, but I get the same unexpected output behavior. \$\endgroup\$
    – Diaa
    Feb 14, 2013 at 19:11
  • \$\begingroup\$ @DiaaAbidou - It's probably a good idea to never assume that uninitialized variables are any specific value, unless the compiler documentation explicitly specifies so. It seems it's not a problem here, though. \$\endgroup\$ May 3, 2013 at 5:03
0
\$\begingroup\$

I change the stop function in master and solve the problem:

void TWI_Stop(void)
{
   TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}

and I check this program in proteus work without problem.

\$\endgroup\$
0
\$\begingroup\$

am I only one to see this line ?

void TWI_match_write_slave(void)dirction bit(write)

should be

void TWI_match_write_slave(void)

Excuse my numbness, but I don't understand the rest of the code in that line, any help appreciated

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.