FTDI Community

Please login or register.

Login with username, password and session length.
Advanced Search  

News:

Welcome to the FTDI Community!

Please read our Welcome Note

Technical Support enquires
please contact the team
@ FTDI Support


New Bridgetek Community is now open

Please note that we have created the Bridgetek Community to discuss all Bridgetek products e.g. EVE, MCU.

Please follow this link and create a new user account to get started.

Bridgetek Community

Author Topic: I2C Master Read in multiple read requests.  (Read 7693 times)

allenhuffman

  • Newbie
  • *
  • Posts: 49
  • Mostly harmless.
    • View Profile
    • Sub-Etha Software
I2C Master Read in multiple read requests.
« on: November 14, 2022, 05:27:55 PM »

UPDATE: Next post has confirmation this works, with a Saleae capture showing the start and stop bits are handled properly.

We use a custom protocol over I2C that embeds message length in our messages. In our PIC24 firmware, we have one board that will read the first two bytes (to get our protocol start code, and the number of data bytes in the message) and then it will read only the expected number of bytes. (Our actual protocol does more - having CRC and other things we validate, but I am simplyfing it here for example and removing most error checking.)

Code: [Select]
i2c_start (I2C_SUBNET_BUS);

i2c_write (I2C_SUBNET_BUS, I2CSlaveAddress + 1);

// Read the message on the I2C bus.
startCode = i2c_read (I2C_SUBNET_BUS, 1); // Start Code

numDataBytes = i2c_read (I2C_SUBNET_BUS, 1); // Num Data Bytes

for (int idx = 0; idx<(numDataBytes-1); idx++)
{
    RXBuffer[idx] = i2c_read (I2C_SUBNET_BUS, 1);
}

// Read the last byte, but don't ACK.
RXBuffer[idx] = i2c_read (I2C_SUBNET_BUS, ZERO);

i2c_stop (I2C_SUBNET_BUS);

Our system is fairly complex with as many as 27 different boards in communication over I2C.

On our FTDI Windows host program side, we hard code the expected response message size. We do something like:

Code: [Select]
FT4222_I2CMaster_Write(ftHandle, slaveAddress, buffer, bytesToWrite, &sizeTransferred);
...
FT4222_I2CMaster_Read(ftHandle, slaveAddress, responseBufferPtr, ExpectedResponseSizeForThatMessage, &sizeTransferred);

This is fine, but if we are writing something that has a large message expected, and there is a problem, the slave board will return a NACK message (7 bytes in our case) and the Master reads that and keeps reading up to the expected size.

No big deal, since our firmware zeros out the response buffer so if the Master reads 10 bytes at any time, it just gets back 10 0s.

BUT, I wanted to make our messages more flexible and maybe speeds things up. It looks like I could recreate what I want using ReadEx(), since I see:

Quote
The I2C condition will be sent with this I2C transaction
 START = 0x02
 Repeated_START = 0x03
 Repeated_START will not send master code in HS mode
 STOP = 0x04
 START_AND_STOP = 0x06

It looks like I would do a ReadEx of 2 bytes, with the flag set to START, then I can error check our start code (byte 0) and number of data bytes (byte 1) and then issue a ReadEx of that many bytes with flag set to Repeated_Start (for one less byte) then read the final byte using STOP.

I thought I'd ask if this was worth trying, or if there was a better way. Perhaps the driver handles doing a read with just STOP and I can save a step.

I plan to experiment on this before the end of the year, but thought I'd ask in case I couldn't even do this.

Thanks, much.


« Last Edit: November 14, 2022, 08:04:01 PM by allenhuffman »
Logged

allenhuffman

  • Newbie
  • *
  • Posts: 49
  • Mostly harmless.
    • View Profile
    • Sub-Etha Software
Re: I2C Master Read in multiple read requests.
« Reply #1 on: November 14, 2022, 08:03:16 PM »

Update: I have done tests, and verified under a Saleae logic analyzer, that this does work. There's just a huge gap between the reads on my Windows system.

Without full error checking (because this is bad code you shouldn't use for production):

Code: [Select]
uint8_t buffer[128];
memset (buffer, 0x0, sizeof(buffer));

ft4222Status = FT4222_I2CMaster_ReadEx (ftHandle, UNIVERSAL_BOARD_ADDRESS, START, &buffer[0], 2, &sizeTransferred);

if (ft4222Status == FT4222_OK)
{
    uint16_t numDataBytes = 0;

    printf ("Read %d bytes.\n", sizeTransferred);

    // buffer[0] is our Start Code, and we'd error check that here.

    // buffer[1] is the number of data bytes in our payload (if any)

    numDataBytes = buffer[1];

    printf ("Repsonse num data bytes %d.\n", numDataBytes);

    ft4222Status = FT4222_I2CMaster_ReadEx (ftHandle, UNIVERSAL_BOARD_ADDRESS, STOP, &buffer[2], 3+numDataBytes+2, &sizeTransferred);

In our case, our message format is a 5-byte header (starting with a Star Code, # of PayLoad Data Byters, and three other items), then payload bytes (if any), then a 2-byte CRC.

In testing, we took out all error checking and just did the two reads back to back.  This works, but will have a 150uS-300uS gap between reading the first two bytes and reading the rest, due to overhead of Windows and such. We haven't benchmarked it under Linux yet, but that's on the list.

Hope this helps others.
Logged