![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
StuH_CC
Joined: 07 May 2004 Posts: 16 Location: Shropshire, UK
|
I2C Slave - a question... |
Posted: Mon May 24, 2004 6:40 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
Re: I2C Slave - a question... |
Posted: Mon May 24, 2004 8:41 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Mon May 24, 2004 8:46 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
StuH_CC
Joined: 07 May 2004 Posts: 16 Location: Shropshire, UK
|
|
Posted: Mon May 24, 2004 3:33 pm |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
Guest
|
|
Posted: Tue May 25, 2004 4:31 am |
|
|
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](images/smiles/icon_smile.gif) |
|
![](templates/subSilver/images/spacer.gif) |
StuH_CC
Joined: 07 May 2004 Posts: 16 Location: Shropshire, UK
|
|
Posted: Tue May 25, 2004 10:04 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|