CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

strange data receive from I2C

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
JaSoN



Joined: 05 Jul 2006
Posts: 15

View user's profile Send private message

strange data receive from I2C
PostPosted: Mon Jul 31, 2006 8:02 am     Reply with quote

Hi, I am programming I2C network on PIC16F877 microcontroller. The I2C network is built by 3 pics, 1 master with 2 slaves.
My program requires continuously receiving data from 2 slaves and each slave sends 4 bytes data to master.
It works fine if I do not ask for receiving data frequently. but, overflow data would be received from one of the slave, if I want the receive the data frequently.
Could anyone tell me why do this happen?
rnielsen



Joined: 23 Sep 2003
Posts: 852
Location: Utah

View user's profile Send private message

PostPosted: Mon Jul 31, 2006 9:03 am     Reply with quote

Code! Give us some code to look at.
JaSoN



Joined: 05 Jul 2006
Posts: 15

View user's profile Send private message

PostPosted: Mon Jul 31, 2006 9:10 am     Reply with quote

This is the code of the loop, it receives data from slave address 0x1E for the steering data and then read from slave address 0x0A for drive data. but the drive would return 255 after a numbers of data is read and the steering data still can return correctly!

I2Creceive(0X1E);
if(I2C_receive[4]==0)
{
slave_address=0x0A;
COMMAND[0]=0x56;
command_value=50;
I2Csend(slave_address,COMMAND[0],command_value);
}

if(I2C_receive[4]>0)
{
slave_address=0x0A;
COMMAND[0]=0x56;
command_value=130;
I2Csend(slave_address,COMMAND[0],command_value);
}
track_status[0]=I2C_receive[4];

STEERING=256*I2C_receive[0]+I2C_receive[1];
THRES=I2C_receive[2];
STEERINGlevel=I2C_receive[3];

//define cases to read data from drive module
if(track_status[0]==1 && track_status[1]==0)
{ speedread=1; }
else if (track_status[0]==0 && track_status[1]==1)
{ speedread=1; }
else speedread=0;


//if(speedread==1)
//{
slave_address=0x0A;
I2Creceive(slave_address);
DIS=256*I2C_receive[0]+I2C_receive[1];
SPEED=I2C_receive[2];
PWM=I2C_receive[3];

//distance data contains 4 characters
if (DIS<10>=0)
printf("\r\n0000%ld",DIS);
else if (DIS<100>9)
printf("\r\n000%ld",DIS);
else if (DIS<1000>99)
printf("\r\n00%ld",DIS);
else if (DIS<10000>999)
printf("\r\n0%ld",DIS);
else if (DIS>9999)
printf("\r\n%ld",DIS);

//speed data contains 3 characters
if (SPEED<10>9)
printf("\r\n00%ld",SPEED);
else if (SPEED<100>=0)
printf("\r\n0%ld",SPEED);
else printf("\r\n%Ld",SPEED);

printf("\r\n%Ld",PWM);
printf("\r\n%Ld", STEERING);
if (track_status[0]<100>=0)
{ printf("\r\n0%d",track_status[0]); }
else printf("\r\n%d", track_status[0]);
rnielsen



Joined: 23 Sep 2003
Posts: 852
Location: Utah

View user's profile Send private message

PostPosted: Mon Jul 31, 2006 3:46 pm     Reply with quote

Quote:
I2Creceive(0X1E);
I2Csend(slave_address,COMMAND[0],command_value);


I appears that you have created your own I2C routines so I have no idea of how you are trying to talk to the Slaves. You need to post your code for I2Creceive() and I2Csend().

Ronald
JaSoN



Joined: 05 Jul 2006
Posts: 15

View user's profile Send private message

PostPosted: Tue Aug 01, 2006 3:12 am     Reply with quote

thanks..here are the send and receive routines

void I2Csend(int slave_address, int I2C_command, int16 command_value)
{
char I2C_send;
char I2C_sendhi,I2C_sendlo;

I2C_sendhi=0;
I2C_sendlo=0;
I2C_send=command_value;
i2c_start(); i2c_write(slave_address);
i2c_write(I2C_command);
i2c_write(I2C_send);
i2c_stop();
}

void I2Creceive(int slave_address)
{
if (slave_address==0x0A)
{ M=2; }
else
{ M=4; }
for(I=0;I<=M;I++)
{
i2c_start(); i2c_write(slave_address+1); delay_us(20);
I2C_receive[I]=i2c_read(0);
i2c_stop(); }
}
rnielsen



Joined: 23 Sep 2003
Posts: 852
Location: Utah

View user's profile Send private message

PostPosted: Tue Aug 01, 2006 8:54 am     Reply with quote

One thing I see is that you are passing int variables to your I2CSend() routines and then stuffing them into char variables that are declared inside it. Not sure how the conversion will be handled here.

Next, you are sending the i2c_write() commands one right after another with no delays. The Slaves, which are PIC's themselves, will take time to realize that it has an I2C interrupt that needs to be serviced. Then, it will need to actually service that routine. This takes time and you're not allowing the Master to give the Slave this time. The bigger the Slave ISR the more time that it will need. In your Slave code you should have CKP, which controls the SCL line, set to zero(0) so it will hold the clock line low, which tells the Master that the Slave is busy, until it's done taking care of each i2c_write() then set CKP back to a high(1) so the Master knows that it can send the next i2c_write(). Your Master code should be written so that it will know how to handle this. I believe if you're using the I2C hardware the next i2c_write() will be sent once the SCL line has been released by the Slave.

An oscilloscope would be extremely handy in monitoring the signals so you can see if you are getting the ACK signal back properly. Your code isn't checking to see if the Slave is talking or not.

You should have something like:

Code:

i2c_start();
if(!i2c_write(address))// this checks to see if the Slave ACK'd back before
{                              // trying to write another command
  i2c_write(command);
}
i2c_stop();


The i2c_write() returns the ACK bit. If you get a NOACK (no response) then it will do no good to continue writing commands to the Slave because it's not listening. Clear a mud? Wink

Ronald
JaSoN



Joined: 05 Jul 2006
Posts: 15

View user's profile Send private message

PostPosted: Wed Aug 02, 2006 1:41 am     Reply with quote

Thanks very much..
I want to ask how can I determine whether the slave PIC is busy or not?
rnielsen



Joined: 23 Sep 2003
Posts: 852
Location: Utah

View user's profile Send private message

PostPosted: Wed Aug 02, 2006 3:10 pm     Reply with quote

In normal I2C parts, ie. temp sensors, eeproms....., the Slave will hold the SCL line LOW while it's doing whatever it is that needs to be done. Then the Slave releases the SCL line (allows it to float high) which the Master detects and then knows that it can send another command to the Slave. If you are using the I2C Hardware then the Master should know how to handle this. If you are bit-banging(let's see if we can get you confused now) then you'll have to put something in your code to test the SCL line if it's being held low by the Slave.

Simply try making a circuit and test things out. Send a Start, Write, Write and a Stop. Hold the SCL line Low and watch how it will 'hang' after the first Write command. The Master will think that the Slave is holding the SCL line low and it will wait until it is allowed to float High before sending the second Write command.

You have mountains of information in the forum on I2C available so search and study. Read the spec. sheet on the I2C protocol that can be found on www.philips.com web site. Don't expect much more help until you have beat your head against your monitor for a while trying to figure out how to make it work. That's the way you remember things the best.

Ronald
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group