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 support@ccsinfo.com

I2C Slave - a question...

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



Joined: 07 May 2004
Posts: 16
Location: Shropshire, UK

View user's profile Send private message

I2C Slave - a question...
PostPosted: Mon May 24, 2004 6:40 am     Reply with quote

Having looked through this forum in search of answers, I'm surprised that his doesn't seem to have been asked before. Or my searching is wonky...

I have an I2C master (PIC16F877) talking to multiple slaves. This bit works without problems. The problem is with a PIC16F876 being used as a slave (it's designed as a plug-in interface to one of several types of modem, and to have its code changed depending on type without reprogramming the main controller).

I'm using the SSP interrupt to catch incoming characters. Again, this seems to be working - I'm getting the address byte, anyway. But I'm not getting anything else.

The master sends the slave address followed by a single data byte, but the data is not appearing at the slave, only the address. Do I have to read the entire transmission in the interrupt routine, all in one go - or is there an interrupt on every byte - as I assumed? This point is not very obvious in the documentation - can somebody clarify this?

Stu H
CCS PCM 3.185
Ttelmah
Guest







Re: I2C Slave - a question...
PostPosted: Mon May 24, 2004 8:41 am     Reply with quote

StuH_CC wrote:
Having looked through this forum in search of answers, I'm surprised that his doesn't seem to have been asked before. Or my searching is wonky...

I have an I2C master (PIC16F877) talking to multiple slaves. This bit works without problems. The problem is with a PIC16F876 being used as a slave (it's designed as a plug-in interface to one of several types of modem, and to have its code changed depending on type without reprogramming the main controller).

I'm using the SSP interrupt to catch incoming characters. Again, this seems to be working - I'm getting the address byte, anyway. But I'm not getting anything else.

The master sends the slave address followed by a single data byte, but the data is not appearing at the slave, only the address. Do I have to read the entire transmission in the interrupt routine, all in one go - or is there an interrupt on every byte - as I assumed? This point is not very obvious in the documentation - can somebody clarify this?

Stu H
CCS PCM 3.185

One very likely problem is time...
Using the faster data rates on I2C, or the SSP module, often runs into the problem of just how long the interrupt latency is. If you have no other interrupt source, it still takes a lot of machine cycles, to actually arrive in the interrupt handler (typically perhaps 80 clock cycles). The interrupt flag is reset when you exit the handler. If your handler itself, takes a reasonable amount of time to decide what is needed, then what can happen, is that you read the value, do your operations, and reach the end of the handler, at which point a second value has allready been received!. The code then clears the flag for this value, and the handler never gets called!...
At high rates on the SSP, the latency can be so long, that major steps have to be taken to handle this. However on the I2C, the route, is to use the 'NOCLEAR' option for the I2C handler, and then code an interrupt clear at the start of the handler. For the fastest response, you can even add a 'while' loop, that tests for the flag being set, and has the clear as it's first line. The code will then loop inside the handler, if a second character has been received.

Best Wishes
rnielsen



Joined: 23 Sep 2003
Posts: 852
Location: Utah

View user's profile Send private message

PostPosted: Mon May 24, 2004 8:46 am     Reply with quote

Your interrupt will occur every time there is new data to be read by the I2C routine. Here is a routine that I use for one of my Slave's:

Code:

#int_SSP   // I2C interrupt service routine
SSP_isr()
{
int8 data;
static int8 state = 0;

   if(SSPOV)// Make sure the buffer has not overflowed
   {
      data= SSPBUF;
      SSPOV=0;  // Clear the register
      return;
   }

   if(STOP)
   {
      return;
   }
   else
   {
      switch(SSPSTAT & 0x2D)
      {
         CASE 0x0C:// Master rx, slave address + 1
               CKP = 0;// hold SCL low, stretch it out
               index = 0;
               SSPBUF = stage[index];
               index++;
               CKP = 1;
            break;
         CASE 0x2C:// Master rx, data with /ack
            CKP = 0;
            SSPBUF = stage[index];
            index++;
            CKP = 1;
            break;
         CASE 0x28:// Master rx, data with not /ack
               sensor = 1;// enable the routine to read the sensor
               status = 1;
            break;
         default:
            break;
      }//end of switch()
   }// end of else
}// end of SSP interupt


This will handle the address byte, the ACK byte and the NOACK byte. CKP, SSBUFF, STOP and SSPOV are registers that I have declared globally.

Good luck
Ronald
StuH_CC



Joined: 07 May 2004
Posts: 16
Location: Shropshire, UK

View user's profile Send private message

PostPosted: Mon May 24, 2004 3:33 pm     Reply with quote

Quote:
use the 'NOCLEAR' option for the I2C handler, and then code an interrupt clear at the start of the handler


This worked like a charm... sort of, anyway. I've now hit the same problems that seem to afflict everyone else, i.e. it works once and gives up - most of the time. It doesn't catch the second "packet" of data that arrives 10ms later either.

On reflection, I've decided that I can't tolerate this level of sensitivity in my application, which has to operate reliably. It was a nice idea, but I think a straightforward 5V RS232 link with external interrupt signalling stands a better chance of working properly, given the short time that I have for development.

Thanks anyway for the help - I'm going to crack this when I have the time...

Stu H
Guest








PostPosted: Tue May 25, 2004 4:31 am     Reply with quote

Your master should use the ACK/NACK from the slave to tell is a byte has been received.

If the byte is ACK'ed, your slave holds the byte in it's incoming buffer. Read it with
Code:

Incoming = (unsigned char) I2C_Read(1);


There is no reason why I2C is less reliable than RS232. (IMHO) Smile
StuH_CC



Joined: 07 May 2004
Posts: 16
Location: Shropshire, UK

View user's profile Send private message

PostPosted: Tue May 25, 2004 10:04 am     Reply with quote

Well, never say never...

I found some slave code in this topic: http://www.ccsinfo.com/forum/viewtopic.php?t=14473 which looked worth a try.
It did, in fact, work - once, just like my own! The main difference was that this code actually received everything that was sent to it.
Combining it with the "manual" interrupt clearing method above, however, results in a routine that works, and keeps on working( the original was clocked at 16MHz, I'm running at 8 with 2 other ISRs to handle ). I feel a bit better about I2C for now.
Thanks again for the help.

Stu H.
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