i2c not working at K-rate


#1

We want to communicate with a g sensor via i2c. The following code in the init tab returns signals successfully from the sensor:

// setup the pins
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
const int MPU_addr=0x68;
static const I2CConfig i2cfg = {
    OPMODE_I2C,
    400000,
    FAST_DUTY_CYCLE_2,
};
i2cStart(&I2CD1, &i2cfg);
uint8_t transmitBuffer = 0x6B;
uint8_t receiveBuffer[14];
i2cMasterTransmitTimeout(&I2CD1, MPU_addr, &transmitBuffer, 4, receiveBuffer, 0, 30);
transmitBuffer = 0x0;
i2cMasterTransmitTimeout(&I2CD1, MPU_addr, &transmitBuffer, 1, receiveBuffer, 0, 30);

transmitBuffer = 0x3B;
i2cMasterTransmitTimeout(&I2CD1, MPU_addr, &transmitBuffer, 1, receiveBuffer, 14, 30);
LogTextMessage("%d", receiveBuffer[1]);

We are using this code in the K-Rate tab:

  if(++i == 1000) {
	i = 0;
	const int MPU_addr=0x68;
	uint8_t transmitBuffer;
	uint8_t receiveBuffer[14];
	transmitBuffer = 0x3B;
	msg_t status = i2cMasterTransmitTimeout(&I2CD1, MPU_addr, &transmitBuffer, 1, receiveBuffer, 14, 30);
	LogTextMessage("status: %d", status);
	if(status == RDY_RESET) {
		i2cflags_t error = i2cGetErrors(&I2CD1);
		LogTextMessage("error: %d", error);
	} else if(status == RDY_TIMEOUT) {
		LogTextMessage("timeout");
	}
	LogTextMessage("%d", receiveBuffer[1]);
}

At K-rate an external i2c scope shows that continuously one wrong byte is transmitted from the axoloti board to the sensor and the receiveBuffer always contains the same values as in the init step.
The status message returned by i2cMasterTransmitTimeout() is RDY_OK.


#2

Best practice is keeping k-rate code free of functions that take considerable time to process.
This can be done by creating a thread at initialization and waking up that thread periodically, you could sleep the thread for a certain time, or wake up the thread from k-rate by sending it a signal.
The script/script2 object internals shows how create (and cleanup) a thread.

Another important thing is that the data for I2C transactions must be located in a DMA-capable memory area.
like

    // allocate buffers suitable for DMA transfert!
    static uint8_t _txbuf[8] __attribute__ ((section (".sram2")));
    static uint8_t _rxbuf[8] __attribute__ ((section (".sram2")));

I suggest to take a look at axoloti/archive/tests/io/spi_lkm1638.axh for an example that uses SPI and script2.