|
|
View previous topic :: View next topic |
Author |
Message |
joshkeys
Joined: 16 Aug 2005 Posts: 37 Location: Fredericton,NB
|
Sending(and receiving) multiple i2c bytes |
Posted: Fri Aug 19, 2005 10:46 am |
|
|
Hi there, i am still having problems with i2c communication and am going to go crazy soon!
I can easily send and receive i2c info from master to slave and vice versa, but only if i do it one byte at a time (i.e. start, address, byte, stop).. as soon as i try to do consecutive writes or reads it just freezes. It seems as if it just doesn't work right at all. should it not be as easy as creating a while(1) loop in the master and issuing a start command, address, two data bytes consecutively and then a stop? I tried this by sending a 4 followed by a 5 from the slave to the master. What i get is one of the three combinations
4 and 4
5 and 4
5 and 5
which is not right.. looking at the oscilloscope it seems as if there is almost a timing issue.. i see sometimes the first byte attempts to make a five, but the LSB goes high then low before the clock can pulse. therefore only a four is read. it is very strange.
From what i understand, if i want to read two or more bytes from the master i need to issue my first i2c_read(1) and the second i2c_read(0) to ACK the first and NACK the second (or last).. and with the slave i can just use the i2c_write(data) over and over because it will wait for the clock.
Also before i broke it down to the basics of just sending two, i was finding that the block was being held low after the first byte of four bytes was being sent from the slave to the master. Here was the code for that:
Code: |
#INT_SSP
void ssp_interrupt ()
{
int data;
int transmitting;
data = DA;
transmitting = RW_BUF;
if(data==1){ //If the buffer contains data
disable_interrupts(INT_SSP);
incoming=i2c_read();
incoming2 = i2c_read();
enable_interrupts(INT_SSP);
}
else{ //The buffer contains an address
if(transmitting==0){ //If Master is sending data
incoming2=i2c_read();
CKP=1;
}
else{ //The Master is requesting data
CKP=1; //Release clock
SSPIF=0; //Reset interrupt flag
output_bit(pin_a2,1); //Turn on pin for debugging
disable_interrupts(INT_SSP);
i2c_write(incoming);
output_bit(pin_a2,0); //Turn off pin for debugging
i2c_write(incoming2);
CKP=1;
output_bit(pin_a2,1); //Turn on pin for debugging
enable_interrupts(INT_SSP);
}
}
}
|
Please someone help. I have spent too many days on something i thought was going to take a few minutes!
Also note that when i was sending the data from the slave to the master i was using an interrupt routine, and in order to send consecutive bytes i would disable the interrupts after i started sending the first byte. When i looked on the scope i would see pin_a2 go high, low, then high all in the time the first byte was transmitted, and the clock held low the rest of the time. And when i used the debugger, i found that while it was in this low clock frozen state the debugger was sitting at this line
Code: |
if(data==1){ //If the buffer contains data
disable_interrupts(INT_SSP);
incoming=i2c_read(); <---------HERE
|
I hope someone can make sense of this. Thanks a ton
Josh
P.s. if i was to write consecutive bytes from the master to the slave, the scope showed that all bytes were sent perfectly. |
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Fri Aug 19, 2005 11:36 am |
|
|
This is what I do on a multiread to a fram.
This is for FM24C256. ((( Not able to handle chip crossing)))
I'll put all code in code library.
Code: |
//======================multi_read_fram===========================//
//does not handle chip to chip multi-read
//last read requires no ack
BOOLEAN multi_read_fram(int32 address,char *data,int16 size){
i2c_start();
i2c_write(0xA0);
i2c_write(hi(address));
i2c_write(lo(address));
i2c_start();
i2c_write(0xA1);//fram read
for(;size-1;data++,size--)
{
*data=i2c_read(1);//The ack will put next data on bus
}
*data=i2c_read(0);//last read requires no ack
i2c_stop();
return(TRUE);
}
|
|
|
|
joshkeys
Joined: 16 Aug 2005 Posts: 37 Location: Fredericton,NB
|
|
Posted: Fri Aug 19, 2005 12:22 pm |
|
|
Thanks for the code, but i am having problems on the slave side of things. My master seems to function properly, it is the slave PIC that causes me problems. THe code i posted earlier was from my slave PIC. If you have any info on that i would appreciate it.
Thanks
Josh |
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Fri Aug 19, 2005 12:28 pm |
|
|
Sorry, my slave is always the FRAM. No code for that. |
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Fri Aug 19, 2005 2:10 pm |
|
|
Here's a bit of code from an ISR that I use. It belongs to a PIC16F87. The registers are defined as the same names as the spec sheet calls them.
Code: |
#use i2c(Slave,fast,sda=PIN_B1,scl=PIN_B4,restart_wdt,address=0x90)
#int_SSP // I2C interrupt service routine
SSP_isr()
{
int8 data;
if(SSPOV)// Make sure the buffer has not overflowed
{
data= SSPBUF;
SSPOV=0; // Clear the register
return;
}
if(STOP)
{
return;
}
else
{
switch(SSPSTAT & 0x2D)// 0x2D filters only the bits that we’re interested in
{
CASE 0x0C:// Master rx mode, slave address + 1
CKP = 0;// hold SCL low, stretch it out
index = 0;
SSPBUF = stage[index];
index++;
CKP = 1;
break;
CASE 0x2C:// Master rx mode, data with /ack
CKP = 0;
SSPBUF = stage[index];
index++;
CKP = 1;
break;
CASE 0x28:// Master rx mode, data with not /ack
sensor = 1;// enable the routine to read the sensor
status = 1;// flag that the I2C routine was successful
break;
default:
break;
}//end of switch()
}// end of else
}// end of SSP interrupt
|
Ronald |
|
|
Ttelmah Guest
|
|
Posted: Fri Aug 19, 2005 2:15 pm |
|
|
The problem is that the slave, needs to wait for the first byte to send before writing the second. You can do this, by clearing the interrupt bit, and then looping testing this, or do the second write in the next interrupt. All the I2C_write command does in a slave, is transfer the byte into the buffer, it does not wait for the byte to complete transmission.
Best Wishes |
|
|
joshkeys
Joined: 16 Aug 2005 Posts: 37 Location: Fredericton,NB
|
|
Posted: Fri Aug 19, 2005 3:18 pm |
|
|
Ok, this is the ASM for the i2c_write() command
Code: |
.................... i2c_write(5);
1356: MOVF FC9,W
1358: MOVLW 05
135A: MOVWF FC9
135C: BSF FC6.4
135E: BCF F9E.3
1360: BTFSC FC7.0
1362: BRA 1360
|
why does line 1360 test the BF to ensure that it is a zero before proceeding? According to the data sheet, in transmit mode a 0 = Receieve not complete, SSPBUF is empty.. why wouldnt it wait utnil this went to a one, in whcih case i could just write my next byte as soon as it exited from this routine?
Thanks
Josh |
|
|
Ttelmah Guest
|
|
Posted: Sat Aug 20, 2005 3:01 am |
|
|
To my mind, if I2C_WRITE, waits for BF to clear, after transferring a byte, it is faulty for use in an interrupt, since the whole 'point' of using an interrupt driven approach, is to not waste time waiting for bytes to transfer. I must admit the last time I looked at it was probably about a hundred compiler versions ago, and at that time it was not checking the status properly. I therefore gave up on it...
This probably explains the slow performance on I2C, that some people have at times reported.
What it should do, is check that BF is clear, _before_ transferring the byte, since this way, in normal interrupt use, the routine can then return immediately. As it stands, it means that an interrupt driven slave receiver, will give appalling performance.
Personally, I have just copied the MicroChip application notes for I2C transfers, and my slave only ever sends one byte on an interrupt, and the transfers are done using the macros I posted some time ago for doing SSP. Slave works fine like this, transferring a 16byte packet.
Given that they do test the BF flag, it should work as posted. However I'd add a diagnostic, and see if the WCOL bit is set after the second transfer.
How is clock stretching configured on the slave?. Remember that you need to prevent the master from initiating the next transfer, till the byte is already loaded on the slave. Hence the sequence should be to hold the clock low, load the byte, and then release the clock.
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
|