I2C Issue(?): Ping: WaitSync Timeout, disconnecting now


#1

Hi,

I'm trying to connect my axoloti to an Arduino Uno. I'm using the chibios i2c library for it and I'm embedding the code into a script2 object (btw. is it possible to do this in a *.axo object without having to care about threading?).

Problem is, my axoloti stops as soon as I fire the first i2c commands to the Arduino (and when they are received, without a connection everything goes fine).
This is the error I get, afterwards I have to unplug the USB cable in order to be able to reconnect again:

Done uploading patch
Start starting patch
Done starting patch
Start locking
Done locking
Ping: WaitSync Timeout, disconnecting now
Disconnect request
Control transfer failed: -7

The script I'm using looks like this (I don't have anything else, except disp/i objects in my patcher).

#include <hal.h>

struct data_pkg_t {
    uint8_t channel;
    uint8_t value;
};

void setup() {
    palSetPadMode(GPIOB, 8, PAL_MODE_ALTERNATE(4)|PAL_STM32_PUDR_PULLUP|PAL_STM32_OTYPE_OPENDRAIN);// SCL
    palSetPadMode(GPIOB, 9, PAL_MODE_ALTERNATE(4)|PAL_STM32_PUDR_PULLUP|PAL_STM32_OTYPE_OPENDRAIN);// SDA
    static const I2CConfig i2cfg = {
        OPMODE_I2C,
        100000,
        STD_DUTY_CYCLE,
    };
    i2cStart(&I2CD1, &i2cfg);
    out2 = _INT(10);
}


void loop() {
    chThdSleepSeconds(1);
    
    struct data_pkg_t channelValue;
    msg_t msg = i2cMasterReceive(&I2CD1, 8,(uint8_t *) &channelValue, sizeof(channelValue));
    if (msg != RDY_OK) {
        out2 = _INT(i2cGetErrors(&I2CD1));
        return;
    }
    
    out1 = _INT(channelValue.channel);
    out2 = _INT(channelValue.value);
}

I already tried wrapping my call i2cAcquireBus() and i2cReleaseBus() with no luck. The problem even occurs when in the following cases:

  • Using i2cMasterReceiveTimeout
  • Not calling any i2cMasterReceive method, but just acquire and release
  • Using simple types instead of the struct

The arduino code is basically https://www.arduino.cc/en/Tutorial/MasterReader (Code for Slave Sender - Program for Arduino 2)

Any hints? I don't really know how to debug this further, the next step will be starting gdb... I could switch to UART, but I would really want to know, what the problem is here.


#2

The buffers you use for I2C send and receive must be declared in a different section of memory. That is required for DMA. Check archive/tests/io/spi_lkm1638.axh for an example.

static uint8_t _txbuf[8] __attribute__ ((section (".sram2")));
static uint8_t _rxbuf[8] __attribute__ ((section (".sram2")));

#3

Thanks for the quick reply, that totally makes sense... I'll give feedback when I got it running.


#4

Brilliant, this did the trick. One more thing occured: When I restarted the patch, the WaitSync Timeout occured again. I figured out that this is a conflict because of the i2c Driver not being freed correctly. Adding

if (chThdShouldTerminate()) {
       i2cStop(&I2CD1);
       return;
 }

Prevented this from happening. The basic code now looks like this.

#include <hal.h>

// helper for converting frac32 to int
__attribute__ ( ( always_inline ) ) __STATIC_INLINE int32_t _INT(float op1) {
    return op1 * (0xffffffff >> 1) / 1024;
}

struct data_pkg_t {
    uint8_t channel;
    uint8_t value;
}; 

struct data_pkg_t *rxBuffer; // Pointer to the rx Buffer

void setup() {
    static struct data_pkg_t _rxBuffer __attribute__ ((section (".sram2")));
    rxBuffer = &_rxBuffer;

    palSetPadMode(GPIOB, 8, PAL_MODE_ALTERNATE(4)|PAL_STM32_PUDR_PULLUP|PAL_STM32_OTYPE_OPENDRAIN);// SCL
    palSetPadMode(GPIOB, 9, PAL_MODE_ALTERNATE(4)|PAL_STM32_PUDR_PULLUP|PAL_STM32_OTYPE_OPENDRAIN);// SDA
    static const I2CConfig i2cfg = {
        OPMODE_I2C,
        100000,			// 100000 is the value of the Arduino Wire library
        FAST_DUTY_CYCLE_2,	
    };
    i2cStart(&I2CD1, &i2cfg);
}

void loop() {
    chThdSleepMilliseconds(20);
    
    if (chThdShouldTerminate()) {
        i2cStop(&I2CD1);
        return;
    }

    // receive the current value
    msg_t msg = i2cMasterReceive(&I2CD1, 8,(uint8_t *) rxBuffer, sizeof(data_pkg_t));

    if (msg != RDY_OK) {
	out1 = _INT(-1);
	out2 = _INT(i2cGetErrors(&I2CD1));
        return;
    }
    
    out1 = _INT(rxBuffer->channel);
    out2 = _INT(rxBuffer->value);
}

The Arduino code is:

#include <Wire.h>

struct data_pkg_t {
  uint8_t channel;
  uint8_t value;
};

void setup()
{
  
  Wire.begin(8);                // join i2c bus with address #8
  Wire.onRequest(requestEvent); // register event
  Serial.begin(57600);
  Serial.write("setup done \n");
}

void loop()
{
  delay(100);
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {
  struct data_pkg_t data = {4, 127};
  Serial.write("Sending \n");
  Wire.write((uint8_t*) &data, sizeof(data)); // respond with message
  Serial.write("Sent \n");  
}

The setup is rather simple, Axoloti PB9 is connected to the Arduino UNO A4, Axoloti PB8 to A3.