How to use I2C Master non blocking functions

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
lock attach
Attachments are accessible only for community members.
AmCi_3754291
Level 2
Level 2

Hey guys

I'm trying to use the non-blocking I2C functions: I2C_MasterWriteBuf and I2C_MasterReadBuf so I can more efficiently use RTOS functions.

The functions that I have look like this:

void BNO080_IMU1_sendPacket(uint8_t channelNumber, uint8_t dataLength) {

   

    uint8 packetLength = dataLength+4; // adding the 4 header bytes

    //debugging tool

   

    //memset(rdHeader, 0, sizeof(rdHeader)); //making sure that read header is 0s

    uint8_t wrData[packetLength];

    wrData[0] = packetLength >> 8;

    wrData[1] = channelNumber;

    wrData[2] = sequenceNumber[channelNumber]++;

   

    for (uint8_t i=0; i < dataLength; i++){

        wrData[2+i] = shtpData;

    }

   

    //USBUART_PutString("I'm about to send data\n");

    //while(!USBUART_CDCIsReady()) {};

   

    I2C_IMU1_MasterClearWriteBuf();

    uint8_t mstrStatus = I2C_IMU1_MasterStatus();

    uint8_t errStatus = I2C_IMU1_MasterWriteBuf(IMU_Address,(uint8_t *) wrData, sizeof(wrData), I2C_IMU1_MODE_COMPLETE_XFER);

   

  

    //I2C_IMU1_MasterClearStatus();

    //debugging

    char buffer[100];

    sprintf(buffer, "write error = %d; master status = %d\n", errStatus, mstrStatus);

    USBUART_PutString(buffer);

    while(!USBUART_CDCIsReady()){};

   

    while (0u == (I2C_IMU1_MasterStatus() & I2C_IMU1_MSTAT_WR_CMPLT)) {

        uint8_t mstrStatus = I2C_IMU1_MasterStatus();

        sprintf(buffer, "write incomplete. Master Status = %d\n", mstrStatus);

        USBUART_PutString(buffer);

        while(!USBUART_CDCIsReady()){};

        //mstrStatus = I2C_IMU1_MasterClearStatus();

        //CyDelay(50);

    }

           

bool BNO080_IMU1_receivePacket() {

   

    USBUART_PutString("receive packet sequence started\n");

    while(!USBUART_CDCIsReady()) {};

   

    memset(rdHeader, 0, sizeof(rdHeader)); //making sure that read header is 0s

    I2C_IMU1_MasterClearReadBuf();

    uint8_t errStatus = I2C_IMU1_MasterReadBuf(IMU_Address, (uint8_t *) rdHeader, sizeof(rdHeader), I2C_IMU1_MODE_COMPLETE_XFER);

    //uint8_t mstrStatus = I2C_IMU1_MasterClearStatus();

    char buffer[100];

    sprintf(buffer, "read error = %d\n", errStatus);

    USBUART_PutString(buffer);

    while(!USBUART_CDCIsReady()){};

   

    while (0u == (I2C_IMU1_MasterStatus() & I2C_IMU1_MSTAT_RD_CMPLT)) {

        uint8_t mstrStatus = I2C_IMU1_MasterStatus();

        sprintf(buffer, "read incomplete. Read Master Status = %d\n", mstrStatus);

        USBUART_PutString(buffer);

        while(!USBUART_CDCIsReady()){};

        //mstrStatus = I2C_IMU1_MasterClearStatus();

        //CyDelay(50);

    }

void BNO080_IMU1_getData(uint16_t bytesRemaining) {

   

    memset(rdHeader, 0, sizeof(rdHeader)); //making sure that read header is 0s

    //reading the header

    I2C_IMU1_MasterClearReadBuf();

    uint8_t errStatus = I2C_IMU1_MasterReadBuf(IMU_Address, (uint8_t *)rdHeader, sizeof(rdHeader), I2C_IMU1_MODE_COMPLETE_XFER);

   

    char buffer[100];

    sprintf(buffer, "get data read error = %d\n", errStatus);

    USBUART_PutString(buffer);

    while(!USBUART_CDCIsReady()){};

    //reading the data

    uint8_t rdData[bytesRemaining];

    I2C_IMU1_MasterClearReadBuf();

    I2C_IMU1_MasterReadBuf(IMU_Address, (uint8_t *) rdData, sizeof(rdData), I2C_IMU1_MODE_COMPLETE_XFER);

   

   while (0u == (I2C_IMU1_MasterStatus() & I2C_IMU1_MSTAT_RD_CMPLT)) {

        uint8_t mstrStatus = I2C_IMU1_MasterStatus();

        sprintf(buffer, "read incomplete. Master Status = %d\n", mstrStatus);

        USBUART_PutString(buffer);

        while(!USBUART_CDCIsReady()){};

        //mstrStatus = I2C_IMU1_MasterClearStatus();

        //CyDelay(50);

    }

    USBUART_PutString("get data read complete");

    while(!USBUART_CDCIsReady()){};

}

So it seems like I manage to write initially, read twice and the third time I try to read it breaks and the status error is something I don't recognize: 6 (as it can be seen in the image I attached.

The bundle has a lot more information than necessary for what we're doing here. Here what I'm looking it are the functions in BNO080_IMU1.c and main.c.

Any ideas as to what I might be doing wrong?

Thanks in advance

Amilcar

0 Likes
1 Solution
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

I just skimmed Sensor-Hub-Protocol-v1.7.pdf

https://cdn.sparkfun.com/assets/7/6/9/3/c/Sensor-Hub-Transport-Protocol-v1.7.pdf

According to the document the header of the packet is

2.2.1 SHTP Header  Figure 2

===========

Byte 0: Length LSB

Byte 1: Length MSB

Byte 2: Channel

Byte 3: SeqNum,

===========

But in your BNO080_IMU1.c

===========

    uint8_t wrData[packetLength];

    wrData[0] = packetLength >> 8;

    wrData[1] = channelNumber;

    wrData[2] = sequenceNumber[channelNumber]++;

===========

I think that it should be

===========

    uint8_t wrData[packetLength];

    wrData[0] = packetLength & 0xFF ; // LSB

    wrData[1] = (packetLength >> 😎 & 0xFF ; // MSB

    wrData[2] = channelNumber;

    wrData[3] = sequenceNumber[channelNumber]++;

===========

Although I can not afford time to read all BNO080 documents,

I'd recommend you to re-check

===========

(1) Sensor Hub Transport Protocol

https://cdn.sparkfun.com/assets/7/6/9/3/c/Sensor-Hub-Transport-Protocol-v1.7.pdf

(2) BNO080 Datasheet

https://cdn.sparkfun.com/assets/1/3/4/5/9/BNO080_Datasheet_v1.3.pdf

===========

moto

View solution in original post

0 Likes
9 Replies
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

In I2C_IMU1.h Statused of Master are defined as

========================

    /* Master status */

    #define I2C_IMU1_MSTAT_CLEAR            (0x00u) /* Clear (initialize) status value */

    #define I2C_IMU1_MSTAT_RD_CMPLT         (0x01u) /* Read complete */

    #define I2C_IMU1_MSTAT_WR_CMPLT         (0x02u) /* Write complete */

    #define I2C_IMU1_MSTAT_XFER_INP         (0x04u) /* Master transfer in progress */

    #define I2C_IMU1_MSTAT_XFER_HALT        (0x08u) /* Transfer is halted */

    #define I2C_IMU1_MSTAT_ERR_MASK         (0xF0u) /* Mask for all errors */

    #define I2C_IMU1_MSTAT_ERR_SHORT_XFER   (0x10u) /* Master NAKed before end of packet */

    #define I2C_IMU1_MSTAT_ERR_ADDR_NAK     (0x20u) /* Slave did not ACK */

    #define I2C_IMU1_MSTAT_ERR_ARB_LOST     (0x40u) /* Master lost arbitration during communication */

    #define I2C_IMU1_MSTAT_ERR_XFER         (0x80u) /* Error during transfer */

========================

So status == 6 seems to be

I2C_IMU1_MSTAT_WR_CMPLT (0x02) | I2C_IMU1_MSTAT_XFER_INP (0x04)

I think that this happens when a byte transfer is completed during multi bytes transfer.

So you may need to wait till

     I2C_IMU1_MSTAT_XFER_INP == 0

and

     I2C_IMU1_MSTAT_WR_CMPLT == 1

moto

0 Likes
lock attach
Attachments are accessible only for community members.

Thanks Moto!

So I've been poking around the code based on the info you gave me and managed to narrow down the issue.

My void BNO080_IMU1_sendPacket(uint8_t channelNumber, uint8_t dataLength) works! I managed to send data...

*********If I convert my "bool BNO080_IMU1_receivePacket()" to "void BNO080_IMU1_getData(uint16_t bytesRemaining)" into the blocking I2C (MasterSendStart(), MasterWriteByte(), MasterReadByte()) functions everything works fine.

However, if I turn my "bool BNO080_IMU1_receivePacket()"  into non_blocking and let  "void BNO080_IMU1_getData(uint16_t bytesRemaining)" to remain blocking, I manage to send 1 data packet and the next time I go to read data using: "uint8_t errStatus = I2C_IMU1_MasterReadBuf(IMU_Address, (uint8_t *)rdHeader, sizeof(rdHeader), I2C_IMU1_MODE_COMPLETE_XFER);" I get the I2C_MSTR_BUS_BUSY error. However, when I check the status of my previous start and stop conditions these are 0.

Have you experienced anything like this? I.e. Complete transfers occur but Bus is still busy?

I added a picture of what it is I'm getting printed:

write error is the output of MasterWriteBuf,

read error is the output of MasterReadBuf and

master status is the output of of MasterStatus()

Amilcar

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

In my experience, I have been making a couple of mistakes which causes I2C bus hang.

(1) When reading multiple bytes, except the last byte, we need to answer with ACK,

but at the last byte we need to answer with NAK.

So please make sure if you are sending NAK at the last data read function.

(2) Some I2C devices require certain amount of bytes to be transferred.

For example some Vishay I2C sensor requires to have 2 bytes sent or received.

So if we stop transaction at odd bytes, although from the view point of I2C transaction

there should be no problem, the sensor will keep holding the line until it will receive or send one more byte.

For this please refer to the datasheet of your device.

moto

0 Likes

Hey Motoo

How do I send ACK or NAK signals when I'm using I2C_MasterReadBuf() function instead of I2C_MasterReadByte() function?

Thanks

Amilcar

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Dear Amilcar-san,

From your screen shot, your program successfully read 276 bytes,

so I think that I2C_MasterReadBuf() is taking care of ACK/NAK.

Then I would imagine that something after "FLUSHING DATA" is wrong.

But in your attached project, I could not find "FLUSHING DATA" string,

Please check your project after writing "FLUSHING DATA"

if there is/are protocol error(s) between PSoC and your I2C device.

Best Regards,

4-Jan-2020

Motoo Tanaka

0 Likes

I've managed to isolate the issue even further: What is happening is

     1. I send a reset command to the IMU (this happens successfully)

     2. The IMU attempts to flush random data (it attempts to clear 276 bytes), HOWEVER only 16 of those 276 bytes are sent;

     3. Every other iteration of read attempt, successfully reads the first 4 bytes - that tell the PSoC how many bytes are left to be read (this is a BNO thing) but never manages to read any of the remaining 260 bytes.

Is I2C_MasterReadBuf() limited to 16 bytes somehow? Could I be hitting some sort of memory limit? If so how do I check something like that?

Thanks

Amilcar

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

I just skimmed Sensor-Hub-Protocol-v1.7.pdf

https://cdn.sparkfun.com/assets/7/6/9/3/c/Sensor-Hub-Transport-Protocol-v1.7.pdf

According to the document the header of the packet is

2.2.1 SHTP Header  Figure 2

===========

Byte 0: Length LSB

Byte 1: Length MSB

Byte 2: Channel

Byte 3: SeqNum,

===========

But in your BNO080_IMU1.c

===========

    uint8_t wrData[packetLength];

    wrData[0] = packetLength >> 8;

    wrData[1] = channelNumber;

    wrData[2] = sequenceNumber[channelNumber]++;

===========

I think that it should be

===========

    uint8_t wrData[packetLength];

    wrData[0] = packetLength & 0xFF ; // LSB

    wrData[1] = (packetLength >> 😎 & 0xFF ; // MSB

    wrData[2] = channelNumber;

    wrData[3] = sequenceNumber[channelNumber]++;

===========

Although I can not afford time to read all BNO080 documents,

I'd recommend you to re-check

===========

(1) Sensor Hub Transport Protocol

https://cdn.sparkfun.com/assets/7/6/9/3/c/Sensor-Hub-Transport-Protocol-v1.7.pdf

(2) BNO080 Datasheet

https://cdn.sparkfun.com/assets/1/3/4/5/9/BNO080_Datasheet_v1.3.pdf

===========

moto

0 Likes

Thanks Moto

This worked for getting the data out of the IMU.

What I had to do was do blocking i2c for the begin sequence and then use the non blocking functions to get the data.

Are there limitations to how many bytes can be read using the non blocking functions? If so what is it? Is there a way to get around it?

Thanks

Amilcar

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Dear Amilcar-san,

I'm glad hearing that you could make it work.

> Are there limitations to how many bytes can be read using the non blocking functions?

> If so what is it? Is there a way to get around it?

I checked I2C_MASTER.c in the Generated_Source, I2C_MasterReadBuf() is defined as

uint8 I2C_MasterReadBuf(uint8 slaveAddress, uint8 * rdData, uint8 cnt, uint8 mode)

Since the cnt is uint8, with this definition, the maximum number is 0xFF = 255.

I think there was a similar question in the past, and at that time the person copied and modified the function with

uint16 cnt, so that it can handle up to 65535.

May be you can define it as uint32.

But meantime, in my experience, if we get interrupt during an I2C transaction, it could corrupt the data and/or bus hang.

As it was an application which is required to work months without stopping, I protected each transaction of I2C

by using, CyEnterCriticalSection()  and CyExitCriticalSection() .

As usual, your mileage may vary 😉

Best Regards,

8-Jan-2020

Motoo Tanaka

0 Likes