5

First, I read Raspberry as an I2C SLAVE and followed everything in there. Great thread. However, this thread does not address anything about sending data back.

This is the scenario: rPI4 as master, rPI3 as a slave, and other I2C slaves.

Master sees all devices. Master communicates with other non-rPI I2C slaves. rPI-slave can receive data from the rPI master. rPI-slave seems to send offset data to the master.

The idea is to be able to query the rPI slave for some values (temperature and load for example), using I2C. So I declared 0x01 as temperature register and 0x02 as load register. Anything else generates a "bad call" response. All rPI-slave responses are words (16 bits).

When I print the data as I am sending it, and I look at the I2C logic analyzer (external hardware Saleae), the data received at the master is what I see in the logic analyzer, but does not match what the code is sending. The code is sending: 0x4010, 0x9001, 0xf000, however, the signal analyzer (and master) sees: 0xf000, 0x4010, 0x9001. Some times, the stream is shifted by 1 byte only.

The data reception (rPI master to rPI slave) always works and is similar to the code in the mentioned thread, here is my sending code:

cout << "Sending result: " << std::hex << res << endl;
memset(&xfer,0,sizeof(xfer));
xfer.control = controlBits;
int b1 = (res & 0x00ff);
int b2 = (res & 0xff00) >> 8;
xfer.txBuf[0] = b1;
xfer.txBuf[1] = b2;
xfer.txCnt = 2 ;
cout << "Sending: 0x" << std::hex << b1 << "  0x" << b2 << endl << endl;
status = bscXfer(&xfer);

(All the couts are for debugging. res is the word to be sent. Controlbits is the value calculated in the code link above)

It almost seems like something is getting stuck in the I2C FIFO and since bscXfer only adds to the end of the I2C FIFO, I think only data is getting sent. I have not been able to find a way to empty the FIFO.

I read the BCM relevant pages and cannot seem to find an answer.

I have done an rpi-update on both, using the latest buster, all updates.

First update: I have tried bitbanging the I2C using the pigpio library. I get the exact same result. The analyzer and the master see the same results. However, the slave is sending different data. It's always the same issue: it appears that the slave buffer is not managed properly and therefore there seems to be an offset of 1 or 2 bytes in the return values as a whole (not each value). For example, if the return values should be 0x00 01 0x00 0x02 0xff 0xff, the master can receive something like 0xff 0xff 0x00 0x01 0x00 0x02. The shifting is not always the same, but there is always shifting. At this point, I am almost suspecting a bug in the pigpio code. It seems the FIFO is not managed well. This is only a suspicion.

Update#2 It seems that the hardware has an issue. I brought the actual source of pigpio bscXfer inside my code and made 2 functions: send and receive. This simplifies my code greatly. Still, the problem occurs.

Solution: I finally opted to add a NOOP command that reads the 0x00 register on the slave but returns no data. From the master's side, I can issue the command and read a 16-bit word 3 times. This empties the buffer on the slave and then I can get some good readings reliably.

I would still like to hear if anyone has had any success using the PI as a true I2C slave device: mimicking registers, returning data, and receiving data.

3
  • Small update... Mar 1, 2020 at 18:16
  • Please don't answer your question within the question. Instead create an answer and accept it after two days with a click on the tick on its left side. Only this will finish the question and it will not pop up again year for year. For the additional question you would like to hear you should create a new question specific to this issue.
    – Ingo
    Mar 4, 2020 at 11:57
  • Thanks for pointing this out @Ingo. Mar 4, 2020 at 17:09

2 Answers 2

3

It appears that there is some hardware problem or undocumented stuff is the PI that would prevent it to work reliably as a full I2C slave. After taking apart the pigpio library and isolating the bscXfer code, the PI just will not send the right stuff back on I2C (as a slave).

The solution is a workaround.

What I have done os that prior to doing a reading from the master, I actually perform several reads (4 in my case), to a function I will not answer in the slave. I elected to pick register 0x00. When the slave gets a request for register 0x00, it will not do anything in code. However, the master will force reading a 16-bit word. This seems to empty the buffer on the slave. Eventually, the master does a read/write to non-zero registers and the code on the slave returns the right data, which the master consumes.

If Broadcom fixes the problem in the chip or firmware update, then this workaround should have no effect on future versions. It's important to note that this is only a problem when using a PI as the master and a PI as the slave. PI as the master with off-the-sheld I2C devices works flawlessly.

4
  • Just curious if you have tried some other master instead of an RPi? Seems that the problem is most likely a buffer handling issue in the slave and the master has nothing to do with it. Or do you have some evidence that the RPi being the master influences the slave behavior? Mar 4, 2020 at 21:40
  • Thanks for forcing me to do some more research. I just dug out another i2c microcontroller I have here. Same slave code on the pi. The new master is a Particle. Looks like the slave pi code is working just fine with this master. I am going to play some more with the pi Master code. I am suspecting timing here. Mar 5, 2020 at 18:43
  • Sorry Larry, I spoke too soon: the code still does not work. Once you restart the slave, the bytes get out of sequence once again. So this points to the pi being a bad slave in some way. From the slave perspective, there does not seem to be a way to empty the FIFO buffer. Mar 5, 2020 at 18:52
  • Please accept your own answer with a click on the tick on its left side. Only this will finish the question and it will not pop up again year for year.
    – Ingo
    Mar 6, 2020 at 23:27
1

I'm new on this forum so I can't write a comment on Stephane Bourque's answer and I must create a new answer. I'm writing I2C slave just like you and I've found a solution regarding an uncontrolled shift on xfer.txBuf register, and that solution is to read the entire "txBuf" that is BSC_FIFO_SIZE (512 bytes) long on the master side. I've just tested this and it works, I will update this answer as I make progress but for now, it seems that this will do the job. Also, I use ioctl Linux messages on master to communicate with a slave (both master and a slave are RPi 3). Your thread and the one you linked have helped a lot in the process of making an I2C slave. If I manage to make something usable (I intend to make interrupt on the slave side for communication and not busy-wait as it is written in the previous thread) I will post it here and link the code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.