 |
 |
View previous topic :: View next topic |
Author |
Message |
rovtech
Joined: 24 Sep 2006 Posts: 270
|
Sending multiple bytes by i2c |
Posted: Tue Apr 22, 2025 12:23 pm |
|
|
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
|
|
Posted: Tue Apr 22, 2025 2:28 pm |
|
|
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: 270
|
|
Posted: Tue Apr 22, 2025 2:53 pm |
|
|
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: 19784
|
|
Posted: Wed Apr 23, 2025 2:35 am |
|
|
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 |
|
 |
|
|
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
|