TWI Slave code???

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

Can someone help me debug this code? I've used libraries(for master only) for the TWI/I2C before, but this is the first time making(or using)the slave code myself. It compiles fine but it doesn't work on my bread board? I've checked the code and the datasheets but I can't find anything wrong?

#include 
#include 


#define SCL_CLOCK  100000L
unsigned char data = 0b00000000;//declaring and initiating data var

//initiate
TWSR = 0;//no prescale
TWBR = ((F_CPU/SCL_CLOCK)-16)/2;//clock

//addressing
TWAR = 0b11110011;//address
TWCR = 0b01000100;//init address
	
while(!(TWCR & (1<<TWINT)));//wait for TWINT to be set and then clear
	
if ( (TWSR != TW_SR_SLA_ACK) && (TWSR != TW_SR_ARB_LOST_SLA_ACK)) return 0;//check status
	
//receive byte
TWDR = data;//read data from TWDR
TWCR = (1 = TWEA) | (1<<TWEN);//ack



//sudeo

if data == something
{
 LED on;
}

Life Is Like A Bucket Of Chicken.

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

What doesn't work?
How far does your code get?
What address is the master sending to?

I assume this isn't in you orignal code since you say it compiles fine. It's always best to do a copy and paste of the exact orignal code instead of retyping it otherwise people might waste their time trying to find solutions to something that wasn't even in the orginal code.

//receive byte 
TWDR = data;//read data from TWDR 
TWCR = (1 = TWEA) | (1<<TWEN);//ack 

//sudeo 

if data == something 
{ 
 LED on; 
} 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That is the original(cut and paste) code, and everything on the master side works fine. For the master I am using the http://homepage.hispeed.ch/peterfleury/group__pfleury__ic2master.html library, which I've tested separate. The problem is when I check the TWSR, it always returns 0 and never runs the rest of the code. I think it might have to do something with masking the TW_SR_SLA_ACK TW_SR_ARB_LOST_SLA_ACK and masking TWSR and then storing it on a variable?

#include  
#include  


#define SCL_CLOCK  100000L 

int main(void)
{
	DDRB = 0b11111111
	unsigned char data = 0b00000001;//declaring and initiating data var 

	//initiate 
	TWSR = 0; //no prescale 
	TWBR = ((F_CPU/SCL_CLOCK)-16)/2; //clock 

	//addressing 
	TWAR = 0b11110010; //address 
	TWCR = 0b01000100; //init address 

	while(!(TWCR & (1<<TWINT))); //wait for TWINT to be set and then clear 

	if ( (TWSR != TW_SR_SLA_ACK) && (TWSR != TW_SR_ARB_LOST_SLA_ACK)) return 0; //check status 

	//receive byte 
	TWDR = data; //read data from TWDR 
	TWCR = (1<<TWEA) | (1<<TWEN); //ack

		if((data < 10) && (data != 0)  && (data != 1))//red
	{	
		for(i = 0; i < 10; i++)
		{
			PORTB = 0b00000100;
			_delay_ms(200);
			PORTB = 0b00000000;
			_delay_ms(200);
		}
	}
	
	
	if(data > 10)//yellow
	{
		for(i = 0; i < 10; i++)
		{
			PORTB = 0b00000010;
			_delay_ms(200);
			PORTB = 0b00000000;
			_delay_ms(200);
		}
	}
}

Life Is Like A Bucket Of Chicken.

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

This will make you return from main which you probably don't want.

if ( (TWSR != TW_SR_SLA_ACK) && (TWSR != TW_SR_ARB_LOST_SLA_ACK)) return 0; //check status 

What value is TWSR after the while loop? Knowing the value will tell you if there is a bus error or if the master is sending a different command (maybe your sending a master read instead of a write).

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

The while loop tells me that my address has been received, and then the TWSR tells me which software action to take. In this case restart if the TWSR equals something besides TW_SR_SLA_ACK, and TW_SR_ARB_LOST_SLA_ACK. The TWSR doesn't equal any of those values, but the TWINT was tripped, so the address was received. I don't know what is happening?

Life Is Like A Bucket Of Chicken.

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

Taco_Bell wrote:
The while loop tells me that my address has been received, and then the TWSR tells me which software action to take. In this case restart if the TWSR equals something besides TW_SR_SLA_ACK, and TW_SR_ARB_LOST_SLA_ACK. The TWSR doesn't equal any of those values, but the TWINT was tripped, so the address was received. I don't know what is happening?

If you find the value of TWSR you will find out what is happening. :roll:

Use an emulator or LCD or serial port or LED's to get the value of TWSR and that will answer your question.

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

The that is being displayed on my LEDs is 0xFF(all of them are on 8) :lol: ). I think that means bus error?

Life Is Like A Bucket Of Chicken.

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

If the LED's turn on when the port pins are low, than yes, TWSR equals 0x00 which is a bus error. Which might mean your master device isn't working right.
If you have an O-scope then you can see exactly what's happening.

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

If I had an O-scope I would of used it :) and I used bipolar LED and grounded them to 5+ so they were all acutely off(0x00).

The code form the master use a the library previously indicated.

//
#include 
#include 

int main(void)
{
	i2c_init();
	if (i2c_start(0b11110010) == 0)
	{ 
		i2c_write(30);
	}
}

I previously test this code communicating to a RTC deceive.

Life Is Like A Bucket Of Chicken.

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

Taco_Bell wrote:
... I used bipolar LED and grounded them to 5+ so they were all acutely off(0x00).

I don't understand what your trying to say.
Does this mean TWSR = 0x00?

Taco_Bell wrote:

The code form the master use a the library previously indicated.

//
#include 
#include 

int main(void)
{
	i2c_init();
	if (i2c_start(0b11110010) == 0)
	{ 
		i2c_write(30);
	}
}

I previously test this code communicating to a RTC deceive.

There are a few issues with this code. The RTC didn't really work 100% with this code but since you don't have an o-scope it may have seemed like it was working properly.

You need a loop in main so the code doesn't try to return. Sometimes compilers add this for you but then your code still isn't portable.

You need to stop the I2C transacation.

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

atomicdog wrote:
I don't understand what your trying to say.
Does this mean TWSR = 0x00?
Exactly

#include  
#include  

int main(void) 
{ 
   i2c_init();
   while(1)
   {
      if (i2c_start(0b11110010) == 0) 
      { 
         i2c_write(30); 
      } 
      I2C_stop();
   }
}

The code still make the TWSR register value 0x00?

Life Is Like A Bucket Of Chicken.

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

Which AVR is powered on first? You might need to add a delay to the master to give the slave some more time.

Have you double checked your hardware?
What size pull-up resistors are you using?

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

I'm also working on a TWI slave (Not using libraries though) I have the same problem, status code is always 0. I know it's not a problem with the master (For me at least) because my master is a Wiimote (That still works with a real nunchuk)

I've noticed that my interrupt executes no matter what address I seem to use, does the same thing happen with you? (I have the general call address disabled and the address mask bits are all 0)

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

I tried putting software pull-ups and it work. Now I'm get the 0x60 value every time I turn it on.

This part doesn't seem to be working? I can't send a value to the slave?

 //receive byte 
   TWDR = data; //read data from TWDR 
   TWCR = (1<<TWEA) | (1<<TWEN); //ack 

Life Is Like A Bucket Of Chicken.

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

Taco_Bell wrote:
I tried putting software pull-ups and it work. Now I'm get the 0x60 value every time I turn it on.

This part doesn't seem to be working? I can't send a value to the slave?

 //receive byte 
   TWDR = data; //read data from TWDR 
   TWCR = (1<<TWEA) | (1<<TWEN); //ack 


Your first statement looks like it is writing data TO the TWDR, rather than what its comment says it's doing. Of course, the comment will have no bearing on the actual functioning of the code, but it's a something of a confidence-killer to see a self-contradictory line like

GlobalVar = 3;  // Set local variable "foo" to 27

And how are we to know whether the part you've shown seems to be working or not, or whether you can send a value to the slave? Could you maybe tell us what results you see from executing the two lines you cited?

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

I tested again and they value stored in the TWDR id the address?

Life Is Like A Bucket Of Chicken.

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

Taco_Bell wrote:
I tested again and they value stored in the TWDR id the address?

Could you find the person who wrote your tagline, and get him to translate your statement?

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

I tested the code again and the value stored in the TWDR is the address from the AVR?

Life Is Like A Bucket Of Chicken.

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

Taco_Bell wrote:
I tested the code again and the value stored in the TWDR is the address from the AVR?

If I understand correctly, the first byte received will be the 7 bit address plus one read/write bit

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

Taco_Bell wrote:
I tested the code again and the value stored in the TWDR is the address from the AVR?

Yes, that is what it should be after case 0x60.

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

The "software action" that takes place after TWSR reads 0x60 is to receive a byte and ack. it. How exactly it that done?

Life Is Like A Bucket Of Chicken.

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

Which AVR are you using?
I think you are misunderstanding what the datasheet is trying to say.

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

Not sure what chip you're using, but it's probably the same for all of them. The ATmega168 datasheet Has a table of what to set some of the bits in the TWCR to on page 231.
For status code 0x60 it says
TWSTA: Don't care
TWSTO: 0
TWINT: 1
TWEA: 1 or 0
The last one is the ACK bit, setting it to 1 will send an ACK to the master, setting it to 0 will return a NACK (You probably want to set it to one)

The next status code you should get is 0x80 (Means that you've received another byte, this ones data though, not your address)

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

I'm using the ATMega48. After I check the TWSR with a value of 0x60 then I sent a ack and waited with a while loop til' it was(TWINT tripped) sent. Then I checked the TWDR register and the value was 0x00 not 0x80?Which means there was a bus error?

TWAR = 0b11110010; //address 
	TWCR = 0b01000100; //init address 

	while(!(TWCR & (1<<TWINT))); //wait for TWINT to be set and then clear 

	if ( (TWSR != TW_SR_SLA_ACK) && (TWSR != TW_SR_ARB_LOST_SLA_ACK)) return 0; //check status

	TWCR = (1<<TWEA) | (1<<TWEN); //ack

	while(!(TWCR & (1<<TWINT))); //wait for TWINT to be set and then clear
	if ( (TWSR != TW_SR_DATA_ACK) && (TWSR != TW_SR_DATA_NACK)) return 0; //check status

	PORTB = TWSR;

If the code looks like this than TWSR's value is 0x60

TWAR = 0b11110010; //address 
	TWCR = 0b01000100; //init address 

	while(!(TWCR & (1<<TWINT))); //wait for TWINT to be set and then clear 

	if ( (TWSR != TW_SR_SLA_ACK) && (TWSR != TW_SR_ARB_LOST_SLA_ACK)) return 0; //check status

	TWCR = (1<<TWEA) | (1<<TWEN); //ack

	while(!(TWCR & (1<<TWINT))); //wait for TWINT to be set and then clear

	PORTB = TWSR;

	if ( (TWSR != TW_SR_DATA_ACK) && (TWSR != TW_SR_DATA_NACK)) return 0; //check status

And the TWDR still has a value of the address with the R/W bit.

Life Is Like A Bucket Of Chicken.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
TWCR = (1<<TWEA) | (1<<TWEN); //ack

Your missing something important here.

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

Where?

Life Is Like A Bucket Of Chicken.

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

You're not resetting TWINT bit, you have to set it to 1

TWCR |= 1<<TWINT;
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That worked. Now I can send data, yes :lol: .

Thank You,
atomicdog
Jrblast
Levenkay

Life Is Like A Bucket Of Chicken.