Help TWI interface problem

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello all,
I am using a Mega8 as TWI master and connected 4 EEPROM devices as slaves. The first slave address (in write mode) is 0xa0, the second 0xa2, the third 0xa4 and the fourth 0xa6. When I address the first chip I am able to read the data properly in the first go itself. But when I try to read the second device's data, for some peculiar reason, corrupted data comes. After many reads from the same device, correct data starts coming out!!!

Once the data comes out properly, any number reads there is no problem. If power is switched off and switched On after some time, the problem starts. I need to read the device at least 40-50 times before correct data starts coming out. I have tried all possible combinations including changing the pull-up resistors but to no avail. I am at my wits end to know what the problem is. Any help will be highly appreciated.

All manufacturers claim that multiple devices can be connected to a single TWI bus, so I wonder where I am going wrong.

Thank you.

Parthasaradhi Nayani

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is there any way you can temporarily remove all but the second device from the bus and concentrate on just that? It would be interesting to know if this is an issue with the second device or whether one of the other devices is jumping in when it shouldn't.

Dave

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Dave for the reply. There is no problem with one chip! We even tried on a totally new board assuming that there may be some PCB track problems. But the behaviour is identical. With one chip everything is fine. The behaviour is very peculiar. Initially junk comes from the addressed device and as you keep reading for many times correct data starts coming. We are writing once to each of the chips and the first device responds OK but the second one starts acting up! any clues? Thank you.

Parthasaradhi Nayani

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nayani P wrote:
any clues?

Not without knowing more about things. Any chance you can post the code and schematics?

Dave

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes I will be able to post the code and the schematic but it will be many hours before I can do that.

Parthasaradhi Nayani

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

Here is the code.


 void TWI_start(void);
 unsigned char TWI_read_ack(void);
 unsigned char TWI_read_nack(void);
 
 void TWI_write(unsigned char);
 
 void TWI_stop(void);

 void address_2_eeprom (unsigned char);

 void error_fun (unsigned char);
 
 void sendbyte (unsigned char);
 

// code portion

    DDRB= 0b00111111; 
	PORTB = 0x2d;
    DDRD = 0xff;
	PORTD = 0x00;
    DDRC = 0x3f;				// TWI SCL and SDA
	PORTC = 0x3f;				// chip in reset, and i2c bus bits as outputs with high outputs


	TWBR = 32;		// i2c clock pre-scale. This should give 97K frequency

	 while ( 1 )
	 {

	  address_2_eeprom (0xa2);		// send 1st chip address

	  TWI_write (0x00);
	  TWI_write (0x00);		// lower and higher order address

	  address_2_eeprom (0xa3);		// 1st chip in read mode
	  TWI_start ();
	  
	  for (i=0; i<9; i++)
	   sendbyte (TWI_read_ack ());	// read with ACK

	  sendbyte (TWI_read_nack ());	// last byte read with NACK
	  
	  TWI_stop ();

	  address_2_eeprom (0xa4);		// send 2nd chip address

	  TWI_write (0x00);
	  TWI_write (0x00);		// lower and higher order address

	  address_2_eeprom (0xa5);		// 2nd chip in read mode
	  TWI_start ();
	  
	  for (i=0; i<9; i++)
	   sendbyte (TWI_read_ack ());	// read with ACK
	   
	  sendbyte (TWI_read_nack ());	// last byte read with NACK
	  
	  TWI_stop ();


	  while (!(UCSRA & (1<<RXC)));	// wait for a character from serial port

	  data = UDR;	// dummy read

     }
	 
  return 1;
 }
 


void TWI_start(void)
 {
   TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);    // enable TWI,start conditions 
   while(!(TWCR & (1<<TWINT)))      // wait till TWINT is set. START condition sent
   {
     sendchar('S');
   }
 }


void TWI_stop(void)
 {
   TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN);      // enable stop condition
   _delay_loop_2 (10000);
   
 }

// just write the byte to TWI interface

void TWI_write (unsigned char data)
  {
    TWDR = data;		// write data
	TWCR = (1<<TWINT)|(1<<TWEN);	// start tran
    while(!(TWCR & (1<<TWINT)))   // wait till TWINT is set 
   }

   
// read byte with ACK. This will enable more bytes to be read
   
  unsigned char TWI_read_ack(void )
   { 

    TWCR = (1<<TWINT)|(1<<TWEA)|(1<<TWEN);  
    while(!(TWCR & (1<<TWINT)));    // wait till TWINT is set 
	return (TWDR);
  } 
  
// single byte read routine. NACK is sent after byte read, indicating to slave that no further 
// reads will be done

  unsigned char TWI_read_nack(void )
   { 

    TWCR = (1<<TWINT)|(1<<TWEN);  
    while(!(TWCR & (1<<TWINT)));    // wait till TWINT is set 
    return (TWDR);
   } 


// This routine just sends the chip address on the i2c bus and checks for ACK
// and or NACK

void address_2_eeprom (unsigned char addr)
 {
  unsigned char ch1;			//,ch2,ch3;
  
  TWI_start();
  TWI_write (addr);         // address the slave

  ch1 = TWSR;
  ch1 &= 0xf8;
  
  if (!(addr & 1))		// write mode ACK test
   {
   if (ch1 != 0x18)
     error_fun (addr);
	 }
  else
  if (ch1 != 0x40)		// read mode test for ACK
   error_fun (addr);
 
 }
 
 
void sendbyte(unsigned char dat) //function to send 0x38 as '3' and '8' onto hyperterminal
   {
    unsigned char ftmp;
	
    ftmp = (dat >> 4);
	if (ftmp > 9)
	  ftmp += 0x37;
	else
	  ftmp += 0x30;
	sendchar(ftmp);        // transmit the character to hyperterminal
	
	ftmp=dat & 0x0f;
	if (ftmp > 9)
	  ftmp += 0x37;
	else
	   ftmp += 0x30;
	sendchar(ftmp);
   }

void sendchar(unsigned char dat)
  {
   UDR=dat;
   while(!(UCSRA & 0x40));
    UCSRA|= 0x40;
  }
  
void USART_TRANS(unsigned char *ptr)  
   {       
   while(*ptr)
    {
	 UDR=*ptr++;
 	 while (!(UCSRA & 0x40));   //Wait for transmission complete 
	   UCSRA = 0x40;          
	}
   } 
   
void USART_Init(void)
 {
        UBRRH=0X00;
	    UBRRL=47;			// 7.x Mhz hence 47 for 9600 BPS
        UCSRB=0X98;	
	    UCSRC=0X86;  
 }  
   

void error_fun (unsigned char sldata)
{
 USART_TRANS ("Error from addressed device :");
 sendbyte (sldata);
 sendchar (0x0d);
 sendchar (0x0a);
 while (1);
}

Connections are pretty straight forward. The CLK and SDA pins are conected to all the devices and the device address A0,A1 and A2 are connected as follows

chip 1 A0=1, A2=0,A3=0
chip 2 A0=0,A2=1,A3=0

this is all.
Regards

Parthasaradhi Nayani

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What EEPROM devices are you using? I'd like to download a datasheet and refer to it as I look at the code.

Dave

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

One thing I did notice going through the code; when you send out the address to the device - address_2_eeprom() - you correctly check the status afterwards to make sure that the device responded with an ACK. However, when you do the actual write to the device - TW_write() - you do not check the status afterwards. It would be a good idea to put a status check here to verify that the device thinks the write completed successfully.

Dave