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 multiple bytes by i2c

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



Joined: 24 Sep 2006
Posts: 271

View user's profile Send private message AIM Address

Sending multiple bytes by i2c
PostPosted: Tue Apr 22, 2025 12:23 pm     Reply with quote

How do I return multiple bytes from a Slave PIC?
The following software works.
This is how a Master PIC sends more than one byte in MAIN:
Code:
// *** send p_speed and s_speed to SIDE THRUSTERS ***
   I2C_START ();                        // start I2C
   I2C_WRITE (SIDE_WRT_ADDR);           // addr of side thrusters PIC
   I2C_WRITE (p_motor);                 // send port speed
   I2C_WRITE (s_motor);                 // send stbd speed
   I2C_WRITE (side_thr_reset);          // send any resets
   I2C_STOP ();                         // stop I2C


This is how they are received by a Slave PIC in the ISR (Interrupt Service Routine):
Code:
#INT_SSP
 void ssp_interrupt ()                      // have an interrupt
   {
    int incoming, state;                    // variables
    state = i2c_isr_state ();               // get state
     if (state <= 0x80)                     // master is sending data
      {
       if (state == 0x80)                   // throw away device address if state = 0x80
        incoming = i2c_read (2);            // but do not release i2c bus
       else
        incoming = i2c_read ();
       if (state == 1)                      // first data received is port speed
         p_speed = incoming;
       if (state == 2)                      // second data received is stbd speed
         s_speed = incoming;
       if (state == 3)                      // third data received is status reset
       status_reset = incoming;
       }
    if (state >= 0x80)                      // master is requesting data from slave
     {
      i2c_write (side_thr_status);          // send side thruster status
      CKP = TRUE;
     }
   }

I need to send an array of, say 200, int bytes back from a slave PIC.
To make it more complicated the Master in this case is a RaspberryPi 4b running Python. Not relevant to this forum but suggestions welcome.
I found this in https://www.ccsinfo.com/forum/viewtopic.php?t=59131&highlight=i2c+array
he seems to be incrementing the array for each request from the master, so there are 16 requests and 16 transactions? Cannot be sent as in the Main example?
I don't understand how count can be incremented if it is reset to 0 each interrupt. I probably don't fully understand Static.
Code:
#INT_SSP
void ssp_interrupt(){

   int8 incoming, state;
   static int8 count=0;

   state = i2c_isr_state();
   
   if(state < 0x80)
   {     // Master is sending data
      incoming = i2c_read();
   }

   if(state == 0x80)
   {
       count=0;
       incoming = i2c_read(2);  //perform the read on state==0x80
       //note special read that does not release the CKP
   }

   if (state>=0x80)
   {   // Master is requesting data from slave
      i2c_write(sensorArray[count++]);
  }
}
jeremiah



Joined: 20 Jul 2010
Posts: 1384

View user's profile Send private message

PostPosted: Tue Apr 22, 2025 2:28 pm     Reply with quote

One thing to understand is that i2c_isr_state() returns an 8 bit result, reserving the values 0x00 and 0x80 for special things. That means that if you use i2c_isr_state() on a message with more than 127 bytes, then you will get erroneous results (0x7F == 127, so incrementing that to 128 will be 0x80, one of the special states).

instead of using that, you may need to manually check the register status bits for the I2C to determine what i2c_isr_state() does. I haven't touched raw I2C in years, so I don't remember the status bits of note off the top of my head, but I am sure someone will come by and give better info.
rovtech



Joined: 24 Sep 2006
Posts: 271

View user's profile Send private message AIM Address

PostPosted: Tue Apr 22, 2025 2:53 pm     Reply with quote

Thanks Jeremiah.
That only applies to incoming in the ISR and I don't need to send the slave more than a few bytes. I have done that before as you can see from my example.
What I have never done is reply with many bytes from the slave and the array size could be anything. Ttelmah's code shown above uses a counter that is initialized as 0 and increments probably until the master stops asking. However it appears to me that only one byte can be returned at a time from the ISR, with the counter somehow being incremented each iteration. How then is the counter reset for the next batch?
Python has means of receiving an array according to AI but I have low trust in AI. AI says:

Code:
# Read an array
register = 0x00
length = 4
received_data = bus.read_i2c_block_data(address, register, length)
print(received_data) # Output: [1, 2, 3, 4]

# Using bytearray
data_to_send = bytearray([0x05, 0x06, 0x07, 0x08])
bus.write_i2c_block_data(address, register, list(data_to_send)) # bytearray needs to be converted to list
received_data = bus.read_i2c_block_data(address, register, len(data_to_send))
print(received_data) # Output: [5, 6, 7, 8]

But how do I send from my PIC ISR?
Ttelmah



Joined: 11 Mar 2010
Posts: 19785

View user's profile Send private message

PostPosted: Wed Apr 23, 2025 2:35 am     Reply with quote

There are 16 interrupts for each transaction, not 16 'requests'. In I2C, a
transaction begins with I2C starts, and ends with the stop. this is the complete
packet request. The PIC peripheral only handles one byte at a time, but
you can have dozens of bytes in the single transaction.

Yes, you do just have a counter, and load the next byte ahead of each
read by the master. You reset the counter, when you receive the address
byte. This is state 0x80, or 0x0. These mark 'address has been received
for either a read or a write' respectively. The I2C_isr_state actually maintains
the counter for you (but with the limitation of 127bytes max). So you
have state==0x80 says the master is starting a read transaction. 0x81, says
the master has read the first byte, and will want the next, 0x82 the third, etc.
etc...

Commonly in I2C, the master will often 'send' the byte address to be read or
written as the byte after the device address, so the sequence is:

START
DEVICE WRITE ADDRESS
REGISTER ADDRESS
RESTART
DEVICE READ ADDRESS - this reverses the bus
READ BYTE
READ BYTE.....
......
READ BYTE WITH NACK - this is vital.
STOP

The master should always NACK the last byte it is wanting to read,

Now two things here. 'RESTART', is sending another start, without a stop
before it. This tells the slave to again look for the address, and then when
this is received with the read bit set, the bus can reverse.
Then the master must ACK each byte, except the last one where it
sends a NACK
rovtech



Joined: 24 Sep 2006
Posts: 271

View user's profile Send private message AIM Address

PostPosted: Wed Apr 23, 2025 6:10 am     Reply with quote

Yes, I have been dong that as my example shows. But that is for a MASTER.
My question is what does the SLAVE software look like.
Can you explain your example of the SLAVE ISR code which I repeat here.
It looks to me like it is only replying with one byte. It also initializes count to 0 on each interrupt.

Code:
#INT_SSP
void ssp_interrupt(){

   int8 incoming, state;
   static int8 count=0;

   state = i2c_isr_state();
   
   if(state < 0x80)
   {     // Master is sending data
      incoming = i2c_read();
   }

   if(state == 0x80)
   {
       count=0;
       incoming = i2c_read(2);  //perform the read on state==0x80
       //note special read that does not release the CKP
   }

   if (state>=0x80)
   {   // Master is requesting data from slave
      i2c_write(sensorArray[count++]);
  }
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19785

View user's profile Send private message

PostPosted: Wed Apr 23, 2025 6:52 am     Reply with quote

Yes. It won't work if more than one byte is wanted.
It won't actually load a byte except for the first read.
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