Arm Mbed OS support forum

How many bytes did the I2CSlave receive?

I’m using Mbed on several STM32 platforms. The device is configured as an I2C slave, using Mbed OS 6.3. I can detect an incoming transmission, and I can happily receive data and place it into a buffer. However, I can’t find a way of knowing how many bytes I received. The master could send any value between 0 and 255, even for the last byte, so I can’t just look at the buffer. The read(void) function returns 0 to 255, but doesn’t tell me much. The other function, read(data, length) receives all the bytes, but doesn’t tell me how many bytes were received, only if I received less than the expected length. Is there an easy way to find out how many bytes were received from the master, without having to loop through every byte? And if I do have to loop through every byte, how can I detect the end of a transmission?

If it varies then I guess you’ll need to tell the slave device how many bytes it should expect to receive. As a suggestion, maybe use the 1st byte to do it or set up your own register command for that purpose. If you have to loop through every byte then it will probably be ‘\0’ terminated or you could use your termination character too. I’m sure there are other methods out there too.

Unfortunately, that isn’t really a possibility. Think something like an EEPROM simulator, not predefined data structures. It might send one byte, maybe a dozen, and I can’t ask the master to structure the data, I need to be able to know what I received based on the bytes, not the data format. This will, in time, replace an I2C sensor to be able to simulate it, for firmware testing and validation.

Then maybe look at using ACK / NAK which signals end of i2c transmit.

Hello James,

To implement the read(data, length) method, I2CSlave calls int i2c_slave_read(i2c_t *obj, char *data, int length). The number of received bytes is then compared with the requested one:

int I2CSlave::read(char *data, int length)
{
    return i2c_slave_read(&_i2c, data, length) != length;
}

In order to get the number of received bytes try to implement your own I2CSlave, for example as below:

#include "mbed.h"

char buff[64];  // receive buffer

// New class definition. 
// It inherits I2CSlave's public methods.
class MyI2CSlave : public I2CSlave
{
public:
    using I2CSlave::_i2c; // get access to protected member

    MyI2CSlave(PinName sda, PinName scl) : I2CSlave(sda, scl) {}

    // override the inherited method
    int read(char *data, int length) { return i2c_slave_read(&_i2c, data, length); }
};

MyI2CSlave myI2CSlave(PB_8, PB_9);  // create an instance of the new class

int main()
{
    myI2CSlave.frequency(200000);   // call inherited method

    int receivedBytesCount = myI2CSlave.read(buff, 64); // call new implementation

    while (true) { }
}

Best regards, Zoltan

Hi Zoltan,

This was an excellent idea, but unfortunately it doesn’t work. Tracing it back, the i2c_api.c file for STM32s makes sure that it won’t work. It receives length, and if there is no timeout, then count = length, and return count. I ask for 10 bytes, but I’m only sending one, I’m not timing out, and it responds that I’m receiving 10. Oh well, it was a great shot, but I’ll just continue like this for the time being.