0

Data passed between a Raspberry Pi, configured as an I2C slave device, is not reliably transmitting between an Arduino I2C bus master device. Data is consistently getting lost, and slave responses are received out of sequence. And the status flag bytes are getting reversed between PIGPIO and PIGPIOD.

Furthermore, I have not been able to determine from the documentation how the Raspberry Pi slave device is notified of a simple requestFrom() bus master request. There appears to be an unnecessary requirement to send a control message first from the master to slave.

The following code is used in a raspberry pi configured as an i2c slave device. As seen in the code, it can be compiled to be used either directly with PIGPIO or indirectly through the PIGPIOD using the macro switch PIGPIOD. This way, the code can be tested in both configurations.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <cstring>
#include <signal.h>

#ifdef PIGPIOD
#include <pigpiod_if2.h>
int pi_handle;
#else
#include <pigpio.h>
#endif

bool runloop = false;
bsc_xfer_t xfer;
uint8_t i2caddr = 0x15;

void reset_i2c()
  {
    xfer.control = (uint32_t)((uint32_t)i2caddr << 16) | (1<<7) /*BK*/;
    memset(xfer.txBuf, 0, BSC_FIFO_SIZE);
    xfer.txCnt = 0;

#ifdef PIGPIOD
    bsc_xfer(pi_handle, &xfer);
#else
    bscXfer(&xfer);
#endif

  }

void setup()
  {
    printf("I2C RPI Slave Test Program\n");

#ifdef PIGPIOD
    pi_handle = pigpio_start(0, 0);
    if (pi_handle < 0) {
      printf("WHOAAAAAA!\n");
    }
#else
    if (gpioInitialise()) {
      printf("WHOAAAAAA!\n");
    }
#endif

    usleep(25000);
    reset_i2c();

    //for (int i = 0; i < 32; i++) {
    //  event_callback_ex(pi_handle, i, (evtCBFuncEx_t)event_handler, (void *)i);
    //}
    usleep(25000);
  }
void loop()
{
  int status;
  uint8_t rx_ctl[10];
  bool rx_flag, tx_flag;

  runloop = true;
  while (runloop) {

    rx_flag = false;
    tx_flag = false;

    xfer.control = (uint32_t)((uint32_t)i2caddr << 16)
      | (1<<9) /*RE*/ | (1<<8) /*TE*/ | (1<<2) /*I2C*/ | (1<<0) /*EN*/;
#ifdef PIGPIOD
    status = bsc_xfer(pi_handle, &xfer);
#else
    status = bscXfer(&xfer);
#endif
    int rx = xfer.rxCnt;
    int tx = xfer.txCnt;

    //
    // Receive control bytes
    //
    if ((status >= 0) && (rx > 0))
      {
        for (int i = 0; (i < rx) && (i < 10); i++) {
          rx_ctl[i] = xfer.rxBuf[i];
        }
        rx_flag = true;
      }
    else if (status < 0)
      {
        //printf("Bad receive status.\n");
      }
    else if (rx <=0 )
      {
        //printf("No data received.\n");
      }

    //usleep (2500);
    //usleep (1);

    //
    // Transmit slave data
    //
    if (rx_flag) {
      // rx control determins response
      xfer.txBuf[0] = (rx_ctl[0]==5)?(15):(35);
      xfer.txBuf[1] = (rx_ctl[0]==5)?(16):(36);
      xfer.txBuf[2] = (rx_ctl[0]==5)?(17):(37);
      xfer.txBuf[3] = (rx_ctl[0]==5)?(18):(38);
      xfer.txCnt = 4;
#ifdef PIGPIOD
      status = bsc_xfer(pi_handle, &xfer);
#else
      status = bscXfer(&xfer);
#endif
      xfer.txCnt = 0;
      tx_flag = true;
    }
    //
    // Print results
    //
    if (rx_flag) {
      printf("Received control data, status=0x%x:", status);
      for (int i = 0; (i < rx) && (i < 10); i++) {
        printf("b[%d]=%d", i, rx_ctl[i]);
        if ((i < (rx-1)) && (i <= (10-1))) printf(", ");
      }
      printf("\n");
    }

    // SHORT PAUSE
    usleep (25000);
  }

  printf("Done looping.\n");
}

void quit_handler( int sig )
{
  runloop = false;
}

int
main(int argc, char **argv)
{
  printf("Main startup\n");

  // Responds to Ctrl-C
  signal(SIGINT,quit_handler);

  setup();
  loop();

  reset_i2c();
}

The following is the code on the Arduino MKR1010 CPU.

#include <Wire.h>

void setup(void)
{
  Wire.begin();
  //Wire.setClock(100000);
  
  Serial.begin(115200);
}

void loop(void)
{
  static bool resp = false;
 
  // Transmit
  Wire.beginTransmission(0x15);
  for (uint8_t i = (resp)?(5):(25); i < ((resp)?(5):(25))+5; i++) {
    Wire.write(i);
  }
  Wire.endTransmission();

  // Receive
  uint8_t rxbuf[10];
  int rxi = 0;
  Wire.requestFrom(0x15, 4);
  while (Wire.available()) {
    rxbuf[rxi++] = Wire.read();
  }

  // Report Transmission
  Serial.print("Sent following bytes: ");
  for (uint8_t i = (resp)?(5):(25); i < ((resp)?(5):(25))+5; i++) {
    Serial.print(i); Serial.print("...");
  }
  Serial.println("Done.");
  resp = !resp;

  // Report data Received
  Serial.print("Received data from slave...");
  if (rxi == 0) {
    Serial.print("No data waiting...");
  } else {
    for (int i = 0; (i < rxi) && (i < 10); i++) {
        Serial.print("B=");Serial.print(rxbuf[i]);
        if ((i < rxi) && (i < 10)) Serial.print(", ");    
    }
  }
  Serial.println("Done.");
  
  delay(100);
}

The OS version on the Raspberry Pi slave is:

$ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description:    Raspbian GNU/Linux 11 (bullseye)
Release:        11
Codename:       bullseye

The Arduino IDE version and Wire library on the MKR1010 is version 1.8.19 (Windows store 1.8.57.0).

The i2c bus is configured in /boot/config.txt with the following line:

dtparam=i2c_arm=on

And the loaded modles are:

$ cat /etc/modules
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.

i2c-dev

$ lsmod | grep i2c
i2c_bcm2835            16384  0
i2c_dev                20480  0

The two devices are connected as follows:

  1. The MKR1010 SDA Pin 11 is connected to Raspberry Pi GPIO 18
  2. The MKR1010 SCL Pin 12 is connected to Raspberry Pi GPIO 19.
  3. 2k pullup resistors are used on each of these lines to the Vcc of the MKR1010, 3.2volts.

Arduino i2C master output when the slave is not active appears like this:

21:46:28.699 -> Sent following bytes: 5...6...7...8...9...Done.
21:46:28.699 -> Received data from slave...No data waiting...Done.
21:46:28.772 -> Sent following bytes: 25...26...27...28...29...Done.
21:46:28.772 -> Received data from slave...No data waiting...Done.
21:46:28.910 -> Sent following bytes: 5...6...7...8...9...Done.
21:46:28.910 -> Received data from slave...No data waiting...Done.
21:46:29.013 -> Sent following bytes: 25...26...27...28...29...Done.
21:46:29.013 -> Received data from slave...No data waiting...Done.
21:46:29.100 -> Sent following bytes: 5...6...7...8...9...Done.
21:46:29.100 -> Received data from slave...No data waiting...Done.
21:46:29.169 -> Sent following bytes: 25...26...27...28...29...Done.
21:46:29.169 -> Received data from slave...No data waiting...Done.
21:46:29.293 -> Sent following bytes: 5...6...7...8...9...Done.
21:46:29.293 -> Received data from slave...No data waiting...Done.

Alternating byte sequences of [5,6,7,8,9] and [25,26,27,28,29] are sent to the non-existent slave. There is no response as indicated.

Raspberry Pi slave output using the PIGPIO direct method (no daemon) appears as so:

Received control data, status=0x400c2:b[0]=25, b[1]=26, b[2]=27, b[3]=28, b[4]=29
Received control data, status=0x400c2:b[0]=5, b[1]=6, b[2]=7, b[3]=8, b[4]=9
Received control data, status=0x400c2:b[0]=25, b[1]=26, b[2]=27, b[3]=28, b[4]=29
Received control data, status=0x400c2:b[0]=5, b[1]=6, b[2]=7, b[3]=8, b[4]=9
Received control data, status=0x400c2:b[0]=25, b[1]=26, b[2]=27, b[3]=28, b[4]=29
Received control data, status=0x400c2:b[0]=5, b[1]=6, b[2]=7, b[3]=8, b[4]=9
Received control data, status=0x400c2:b[0]=25, b[1]=26, b[2]=27, b[3]=28, b[4]=29
Received control data, status=0x400c2:b[0]=5, b[1]=6, b[2]=7, b[3]=8, b[4]=9
Received control data, status=0x400c2:b[0]=5, b[1]=6, b[2]=7, b[3]=8, b[4]=9
Received control data, status=0x400c2:b[0]=25, b[1]=26, b[2]=27, b[3]=28, b[4]=29
Received control data, status=0x401c2:b[0]=5, b[1]=6, b[2]=7, b[3]=8, b[4]=9
Received control data, status=0x401c2:b[0]=25, b[1]=26, b[2]=27, b[3]=28, b[4]=29
Received control data, status=0x401c2:b[0]=25, b[1]=26, b[2]=27, b[3]=28, b[4]=29
Received control data, status=0x402c2:b[0]=5, b[1]=6, b[2]=7, b[3]=8, b[4]=9
Received control data, status=0x402c2:b[0]=25, b[1]=26, b[2]=27, b[3]=28, b[4]=29
Received control data, status=0x402c2:b[0]=5, b[1]=6, b[2]=7, b[3]=8, b[4]=9
Received control data, status=0x402c2:b[0]=25, b[1]=26, b[2]=27, b[3]=28, b[4]=29
Received control data, status=0x403c2:b[0]=5, b[1]=6, b[2]=7, b[3]=8, b[4]=9
Received control data, status=0x403c2:b[0]=25, b[1]=26, b[2]=27, b[3]=28, b[4]=29
Received control data, status=0x10406:b[0]=5, b[1]=6, b[2]=7, b[3]=8, b[4]=9
Received control data, status=0x40302:b[0]=5, b[1]=6, b[2]=7, b[3]=8, b[4]=9
Received control data, status=0x40302:b[0]=25, b[1]=26, b[2]=27, b[3]=28, b[4]=29
Received control data, status=0x40406:b[0]=5, b[1]=6, b[2]=7, b[3]=8, b[4]=9
Received control data, status=0x406:b[0]=25, b[1]=26, b[2]=27, b[3]=28, b[4]=29

This shows the control data received by the slave. Sequences are received mostly in alternating order. However, there are a number of cases where some transmissions are dropped and we see the same sequence multiple times in a row.

Looking at the data from the bus master, we find:

22:35:27.652 -> Sent following bytes: 25...26...27...28...29...Done.
22:35:27.652 -> Received data from slave...B=15, B=16, B=17, B=18, Done.
22:35:27.744 -> Sent following bytes: 5...6...7...8...9...Done.
22:35:27.744 -> Received data from slave...B=15, B=16, B=17, B=18, Done.
22:35:27.866 -> Sent following bytes: 25...26...27...28...29...Done.
22:35:27.866 -> Received data from slave...B=35, B=36, B=37, B=38, Done.
22:35:27.981 -> Sent following bytes: 5...6...7...8...9...Done.
22:35:27.981 -> Received data from slave...B=15, B=16, B=17, B=18, Done.
22:35:28.062 -> Sent following bytes: 25...26...27...28...29...Done.
22:35:28.062 -> Received data from slave...B=35, B=36, B=37, B=38, Done.
22:35:28.177 -> Sent following bytes: 5...6...7...8...9...Done.
22:35:28.177 -> Received data from slave...No data waiting...Done.
22:35:28.273 -> Sent following bytes: 25...26...27...28...29...Done.
22:35:28.273 -> Received data from slave...B=15, B=16, B=17, B=18, Done.
22:35:28.390 -> Sent following bytes: 5...6...7...8...9...Done.
22:35:28.390 -> Received data from slave...No data waiting...Done.
22:35:28.462 -> Sent following bytes: 25...26...27...28...29...Done.
22:35:28.462 -> Received data from slave...No data waiting...Done.

The alternating control sequence data can be observed being sent. However responses should match control sequence [5,6,7,8,9] with response [15,16,17,18] and control sequence [25,26,27,28,29] with response [35,36,37,38,39]. These occasionally line up, but more often than not, they do not. And many cases of no response data when Wire.available() is called.

When using the daemon, pigpiod, we find that the missed control bytes increase in frequency, sometimes with as many as three in a row:

Received control data, status=0xc2000400:b[0]=5, b[1]=6, b[2]=7, b[3]=8, b[4]=9
Received control data, status=0xc2000400:b[0]=25, b[1]=26, b[2]=27, b[3]=28, b[4]=29
Received control data, status=0xc2000400:b[0]=25, b[1]=26, b[2]=27, b[3]=28, b[4]=29
Received control data, status=0xc2000400:b[0]=25, b[1]=26, b[2]=27, b[3]=28, b[4]=29
Received control data, status=0xc2000400:b[0]=5, b[1]=6, b[2]=7, b[3]=8, b[4]=9
Received control data, status=0xc2000400:b[0]=25, b[1]=26, b[2]=27, b[3]=28, b[4]=29
Received control data, status=0xc2000400:b[0]=5, b[1]=6, b[2]=7, b[3]=8, b[4]=9
Received control data, status=0xc2000400:b[0]=25, b[1]=26, b[2]=27, b[3]=28, b[4]=29
Received control data, status=0xc2000400:b[0]=5, b[1]=6, b[2]=7, b[3]=8, b[4]=9
Received control data, status=0xc2000400:b[0]=25, b[1]=26, b[2]=27, b[3]=28, b[4]=29
Received control data, status=0xc2000400:b[0]=5, b[1]=6, b[2]=7, b[3]=8, b[4]=9
Received control data, status=0xc2000400:b[0]=5, b[1]=6, b[2]=7, b[3]=8, b[4]=9
Received control data, status=0xc2000400:b[0]=25, b[1]=26, b[2]=27, b[3]=28, b[4]=29
Received control data, status=0xc2000400:b[0]=25, b[1]=26, b[2]=27, b[3]=28, b[4]=29
Received control data, status=0xc2000400:b[0]=25, b[1]=26, b[2]=27, b[3]=28, b[4]=29

Note that the status bytes are mixed up between pigpio direct and pigpiod versions. It doesn't appear to be a simple byteswap case either. byte 0 in the pigpio version is the first byte in pigpiod version. Regardless, any attempt to decode the status would not be portable. The documentation does not seem to mention any differences in status byte between the direct and daemon versions. In fact, I'm not even confident the pigpiod status is valid. Note the status from the direct calls seems much more precise. The data back from pigpiod is almost always the same status.

Output from the Arduino bus master shows similar characteristics with both pigpio and pigpiod versions of the slave. Therefore, I will not repeat the output.

For the Raspberry Pi to be useful as a slave:

  1. The master requestFrom() must get a matching response from the slave. If the responses don't match, the data is not useful.
  2. The control data cannot be lost, or responses again will not be useful.
  3. It would be useful to know how the Raspberry Pi slave is notified that a requestFrom() has been issued without any control data being sent.

Regarding 1 and 2 above, I tried various delays in various places. It would sometimes make the problem worse, but never better.

Regarding #3 above, I did try some experiments with the pigpiod event mechanism. Two problems, I only received events from 31. The bsc_xfer() had to be called to generate the event. However, once the call was made, it seemed better to just process it, rather than call it again in the event handler. Further, no event seemed generated for the requestFrom() command without control data. Also the event seemed to occur with no received data either.

Any pointers on how to resolve these issues is appreciated. Particularly how to detect a control dataless requestFrom() on the slave side. Thank you.

6
  • Your question and code is fairly long. I suggest to simplify the code. Use a logic analyzer to check the communication on the I²C wires.
    – Bodo
    Sep 26, 2022 at 17:17
  • Thank you for the comment. I can look at how it might be simplified. If I were to transmit a single control, response, then the drops and sequence errors might not be apparent. Also note in master response, sometimes it receives the same number 4 times. This is not possible since the slave never transmits a single value multiple times in a row. If I simplify, those details might get lost. The suggestion of the scope would confirm the presence of the signal on the wire.
    – tenchiro
    Sep 26, 2022 at 22:24
  • Reviewing the code, it seems to only be doing the required setup, transmission and output reporting. The only simplification would be to remove the alternating dataset transmissions, but then the sequencing errors cannot be observed. I can be simplified by integrating transmission and reporting, however I'm concerned this could introduce additional timing complexities.
    – tenchiro
    Sep 28, 2022 at 1:19
  • What exactly means "The suggestion of the scope would confirm the presence of the signal on the wire."? I suggest (again) to compare the data on the wire with the data reported by your programs. Do you see repeated or missing data or transfers without acknowledge on the wire?
    – Bodo
    Sep 28, 2022 at 11:22
  • Thank you for your response. I don't have a logic analyzer, but I do have an oscilloscope. I can use that. I only hope that I'm able to interpret the signals. I might need practice.
    – tenchiro
    Sep 29, 2022 at 1:44

2 Answers 2

0

I don't have any experience with the specific I²C software/driver for Raspberry Pi or Arduino, so the answer is based on general knowlege and some guessing.

I think the problems result from

  • the slave not being able to prepare the reply fast enough
  • the master ignoring a failed read request
  • missing re-syncronization in master on wrong reply

I²C has hard timing requirements. The slave has to follow the master's clock.
When the slave receives its address followed by a READ bit, it must set the ack bit and immediately send the data. With a clock of 100kHz, the slave's I²C interface has 5µs to decide whether to set the ack bit or not.

There is not enough time to prepare the data in software on request, it must already be stored in a tx buffer.

When the master has successfully sent some data, and the following read request fails, it should probably retry the read request and not send new data before it has received the response. (Up to a reasonable timeout or retry limit.)
If the master detects that a response does not match the previous request, it should probably try to read again until there is no more data, in order to clear any queues.

3
  • These are some very helpful suggestions and things to investigate. I will experiment with this. Thank you.
    – tenchiro
    Sep 29, 2022 at 1:47
  • I updated the question with the Arduino IDE version info, and the Raspberry PI os version. The pigpio libraries are the default libraries that came with the os install. I'm not sure if that answers your question. I'll update the question with more info if required. Thank you.
    – tenchiro
    Sep 29, 2022 at 1:59
  • @tenchiro Apparently my wording was not clear. I will update the answer. I don't have any experience with the I²C drivers you are using, but only general knowledge about communication protocols. It was not meant as a request for detailed version information.
    – Bodo
    Sep 29, 2022 at 11:00
0

I'm including the results achieved this far in my answer here. Some of the observations are as follows:

  1. Some comments elsewhere mentioned a poorly documented event mechanism that can be used with the BSC. There is in fact, no documentation. However through experiment and looking at the pigpio source code, the following is discovered:

Use the following code to register an event handler:

//
// Set event handler for BSC events (event number 31)
//
int eventno = PI_EVENT_BSC;
#ifdef PIGPIOD
    event_callback_ex(
      pi_handle,
      eventno,
      (evtCBFuncEx_t)event_handler, (void *)eventno /*user data*/
      );
#else
    eventSetFuncEx(
      eventno,
      (eventFuncEx_t)event_handler, (void *)eventno /*user data*/
      );
#endif

To understand how this is called, the pigpio source must be consulted as there is no description. According to the source code, this callback is called whenever the gpio monitoring thread detects the BSC FR (Flag Register) changes from the last time it was checked. There is no finer granularity than that.

Based on this, I implemented the event model. After setting this event function, at least one call to bscXfer() (or bsc_xfer()) must be made, or the callback won't get checked. After that, a separate thread will monitor the flags, so the main loop can go to sleep.

void loop()
  {
    int status = 0;
    runloop = true;

    xfer.txCnt = 0;
    xfer.control = (uint32_t)((uint32_t)i2caddr << 16)
      | (1<<9) /*RE*/ | (1<<8) /*TE*/ | (1<<2) /*I2C*/ | (1<<0) /*EN*/;
    status = BSCXFER(&xfer);

    while (runloop) {
      printf(".0x%x.", status); fflush(stdout);
      GPIOSLEEP(10, 0);
    }

    printf("Done looping.\n");
  }

However, this mechanism seems wanting to implement a generic i2c program. The biggest difficulty is handing the three basic scenarios:

  1. Master sends data to Slave and does not request a response.
  2. Master sends data to Slave and requests a
  3. Master sends no data to Slave and requests a response

The first is easy, check xfer.rxCnt and you know data was sent. Pull it out of rxBuf. #2 is tricky. If the master makes an immediate request for data, no separate event is always fired. Therefore, after the data is read, you don't know what to do. You can stuff data on the wire or not. If you do, and nothing is requested, then it creates problems. #3 can be handled if there is no receive data. Then assume a data request and send back the data.

Another difficulty is in synchronizing the request data with the sending of control data. It seems that sometimes the receive buffer is stuffed only after a PI_EVENT_BSC is fired. This results in a data request response before the control data is read. So there always seems to be one response past the control data transmission that is from the previous control. And since you don't know that, there is no way to tell which control the response matches up with. The only solution I was able to come up with was not generic, it implements a basic packet structure on the response so that you can tell what it is. Mine was as so:

HEAD-DATASIZE-DATA-CHECKSUM-TAIL

Bad data comes back. I found empirically that stuffing the transmission buffer all out once and sending with a single bsc call seemed to drop data. Not just the beginning or end, but sometimes the middle. Sending the data one byte at a time seemed best. Also, the Arduino code seemed to indicate data was available when less than the requested data is returned. To try to work around this, I set requests to single bytes. But this stopped all data. Nothing was received. Setting to 2 bytes worked, but when things got out of sync, it sometimes caused issues.

I started working with just setting the BSC control registers myself. However this experiment is not yet successful. Unfortunately the pigpio source code and the Broadcom BSC 2835 documentation differ and I was unable to reconcile. The pigpio source indicates that the 2835 base address is 0x7E000000. But the source indicates 0x20000000. Using the latter locks up the kernel. And the former doesn't seem to do anything. There is more control at the register level, so I hope this can be resolved.

Lastly, even with all the above, satisfaction is elusive. The BSC locks up frequently. Especially during testing when breaking out of the program. Catching the signals and attempting clean termination makes things better, but doesn't seem completely bullet proof. Here is the termination code:

void terminate()
  {
    reset_i2c();      // Send BK (break code) to BSC
    xfer.control = 0; // Causes pigpio to terminate the BSC device, and reset GP
IO modes etc.
                      // Not documented, only determined by looking at pigpio so
urce code
    BSCXFER(&xfer);
#ifdef PIGPIOD
    pigpio_stop(pi_handle);
#else
    gpioTerminate();
#endif
  }

Worse, sometimes the BSC hangs the bus. Here we can see the scope for the master when the BSC slave app is not running. The master sends control data and gets no response to data requests. In the photos below, the signal on top is SDA and the signal on the bottom is SCL.

enter image description here

Once the BSC starts transmitting, there is much more activity:

enter image description here

But when the BSC hangs, the lines go dead. This can be reset with the following code:

#ifdef PIGPIOD
    pi_handle = pigpio_start(0, 0);
    if (pi_handle < 0) {
      printf("WHOAAAAAA!\n");
    }
    set_pull_up_down(pi_handle, 18, PI_PUD_OFF);
    set_pull_up_down(pi_handle, 19, PI_PUD_OFF);
    set_mode(pi_handle, 18, PI_INPUT);
    set_mode(pi_handle, 19, PI_INPUT);
#else
    if (gpioInitialise()<=0) {
      printf("WHOAAAAAA!\n");
    }
    gpioSetPullUpDown(18, PI_PUD_OFF);
    gpioSetPullUpDown(19, PI_PUD_OFF);
    gpioSetMode(18, PI_INPUT);
    gpioSetMode(19, PI_INPUT);
#endif

  xfer.control = (uint32_t)((uint32_t)i2caddr << 16) | (1<<7) /*BK*/;
  xfer.txCnt = 0;
#ifdef PIGPIOD
  bsc_xfer(pi_handle, &xfer);
#else
  bscXfer(&xfer);
#endif


  xfer.control = 0;
#ifdef PIGPIOD
  bsc_xfer(pi_handle, &xfer);
#else
  bscXfer(&xfer);
#endif

#ifdef PIGPIOD
    pigpio_stop(pi_handle);
#else
    gpioTerminate();
#endif

This restores the bus, and the signal in the first scope picture above return, but the bsc doesn't seem quite the same after this, and usually just locks up the bus again when bscXfer() is used. What's more is that you cannot tell if the bus is locked up, unless you implement a heartbeat protocol. And the master cannot fix it because the bsc is holding the lines low.

Using a lightweight packet protocol and checking the data, about 20% of the responses come back corrupted. The packet protocol catches them. But this is still surprising. Also, less frequently, the control data isn't received. Therefore, it is probably necessary to include the control data in the request response. Especially since there can be a one message delay in sending control data, receiving it, and then transmitting the request response.

Based on all of this, I don't really feel 100% confident that I can use the bsc reliably in an I2C slave application. I hope that additional work reading and writing the BSC registers directly can yield more reliable results. Although this won't work with pigpiod, which is really convenient. I did get an inexpensive logic analyzer as suggested by Bogo above. Once I get that setup, it might also provide additional insights. Of course, any additional insight appreciated.

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.