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

i2c slave reading problem

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







i2c slave reading problem
PostPosted: Sun Jul 27, 2008 2:55 am     Reply with quote

Hi,

I originally had a working i2c communication between 2 PICs, but unfortunately the comm routine had to run every 10ms and timing the routine at the master showed around 1,000us per read. Basically, all the routine does is the master will read 4 bytes from the PIC slave every 10ms, like this:

Code:

   i2c_start();
   i2c_write(0xa0);
   i2c_write(STATUSREAD);
   i2c_stop();

   i2c_start();
   i2c_write(0xa1);

   highbyte = i2c_read();
   lowbyte = i2c_read();
   PulseHighTime[0] = make16(highbyte,lowbyte);

   highbyte = i2c_read();
   lowbyte = i2c_read(0); //send NACK
   PulseHighTime[1] = make16(highbyte,lowbyte);

   i2c_stop();


This works, but it is too slow for my liking, so I decided to remove the line that writes the status byte, such that the slave PIC is supposed to default to STATUSREAD when no status byte is received.

Master Code:
Code:

   i2c_start();
   i2c_write(0xa1);

   highbyte = i2c_read();
   lowbyte = i2c_read();
   PulseHighTime[0] = make16(highbyte,lowbyte);

   highbyte = i2c_read();
   lowbyte = i2c_read(0); //send NACK
   PulseHighTime[1] = make16(highbyte,lowbyte);

   i2c_stop();


Slave code:
Code:

#INT_SSP
void i2c_isr()
{
   unsigned int8 indata;

   if (i2c_poll())
   {
      indata = i2c_read();

      if (i2c_state == STATUSREAD) //default status
      {
         switch (indata)
         {
         case READCALDATA:
            i2c_state = READCALDATA;
            i2c_pointer = 0;
            break;
         case WRITECALDATA:
            i2c_state = WRITECALDATA;
            i2c_pointer = 0;
            break;
         }
      }
      else
      {
         switch (i2c_state)
         {
         case WRITECALDATA:
            Caldata[i2c_pointer] = indata;
            i2c_pointer++;
            if (i2c_pointer > 11) //end of buffer
            {
               write_Caldata = 1;
               i2c_state = STATUSREAD;
               i2c_pointer = 0;
            }
            break;
         }
      }
   }
   else
   {
      switch (i2c_state)
      {
      case STATUSREAD:
         i2c_write(SendServoData[i2c_pointer]);
         i2c_pointer++;
         if (i2c_pointer > 3) //end of buffer
         {
            i2c_state = STATUSREAD;
            i2c_pointer = 0;
         }
         break;
      case READCALDATA:
         i2c_write(Caldata[i2c_pointer]);
         i2c_pointer++;
         if (i2c_pointer > 11) //end of buffer
         {
            i2c_state = STATUSREAD;
            i2c_pointer = 0;
         }
         break;
      }
   }
}


But of course, here begins the problem with a STATUSREAD. It is more of a data problem, and when the SendServoData buffer is filled with known values for debugging, the data bytes seem to be shifting
Code:

   SendServoData[0] = 0; //highbyte
   SendServoData[1] = 0x0a; //lowbyte
   SendServoData[2] = 0; //highbyte
   SendServoData[3] = 0x14; //lowbyte

The first read from the master: 0x000a 0x0014 (correct)
second read: 0x0a00 0x1400
third read: 0x0014 0x000a
forth read: 0x1400 0x0a00

and the cycle repeats. I have spent days debugging but I can't find the error. Can anyone help me? I am using a 18F452 as master and 16F873A as slave, CCS 3.203 Thanks
Ttelmah
Guest







PostPosted: Sun Jul 27, 2008 3:36 am     Reply with quote

You don't make it easy for us, since you don't give your definitions for various things.
However there is no reason at all in I2C, to have to send the working address as the first byte after the device address. This is purely a convenience to allow for 'addressable' communications. What you want, should be do-able with:
Code:

#INT_SSP
void i2c_isr(void) {
   unsigned int8 indata;
   static state;
   static address=0;

   //There is no point in using poll. If the ISR is called, a byte _is_ waiting
   indata = i2c_read();
   state=i2c_isr_state();
   if (state <0x80) { //Here read from master is required
      switch (state) {
      case 0:
         address=0;
         break;
      case 1:
      case 2:  //extend states here, if more than two writes are needed
         Caldata[i2c_pointer++] = indata;
         break;
      default:
         //Here master has tried to write more than two bytes
         //Just ignore the data
         break;
      }
   else {
      switch (state) {
      case 0x80:
         address=0;
         //note drop through
      case 0x81:
      case 0x82:
      case 0x83:
      case 0x84:
         i2c_write(SendServoData[address++]);
         break;
      default:
         i2c_write(0); //dummy write if more than four bytes read by master
         break;
      }
   }
}

You say you only read four bytes, but you also include 'write' code as well in the slave. I have included write code as well, but only for two bytes. Extend if needed.
You seem to be making your job unnecessarily complex, by not using the supplied i2C_isr_state routine...

Best Wishes
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