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

Sending(and receiving) multiple i2c bytes

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



Joined: 16 Aug 2005
Posts: 37
Location: Fredericton,NB

View user's profile Send private message Send e-mail MSN Messenger

Sending(and receiving) multiple i2c bytes
PostPosted: Fri Aug 19, 2005 10:46 am     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Fri Aug 19, 2005 11:36 am     Reply with quote

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

View user's profile Send private message Send e-mail MSN Messenger

PostPosted: Fri Aug 19, 2005 12:22 pm     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Fri Aug 19, 2005 12:28 pm     Reply with quote

Sorry, my slave is always the FRAM. No code for that.
rnielsen



Joined: 23 Sep 2003
Posts: 852
Location: Utah

View user's profile Send private message

PostPosted: Fri Aug 19, 2005 2:10 pm     Reply with quote

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







PostPosted: Fri Aug 19, 2005 2:15 pm     Reply with quote

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

View user's profile Send private message Send e-mail MSN Messenger

PostPosted: Fri Aug 19, 2005 3:18 pm     Reply with quote

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







PostPosted: Sat Aug 20, 2005 3:01 am     Reply with quote

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