|
|
View previous topic :: View next topic |
Author |
Message |
Wei Guest
|
i2c slave reading problem |
Posted: Sun Jul 27, 2008 2:55 am |
|
|
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
|
|
Posted: Sun Jul 27, 2008 3:36 am |
|
|
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 |
|
|
|
|
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
|