Skip to content

MAX32660 I2C double read error #1395

Open
@marco-pontin

Description

@marco-pontin

I am developing an application using your MAX32660 MCU. I updated all the libraries in the SDK to the latest version. When performing a I2C read operation, it seems that the MCU is doubling the read (see screenshots attached). The behavior doesn't seem to be influenced by the number of bytes being read. I have also tested this with multiple sensors and I2C speeds.
Image
Here is the function I use to read registers from the slave on the network (almost completely taken from your I2C communication example). The behavior visible in the screenshots is obtained with a single call to the function below.

![Image](https://github.com/user-attachments/assets/0348dd21-d30f-458b-8563-b8efffe530fa)

int readRegister(uint8_t addr, uint8_t reg_num, uint8_t len){
    int error = 0;
    mxc_i2c_req_t reqMaster2;txdata[0]=reg_num;
    reqMaster2.i2c = I2C_MASTER;
    reqMaster2.addr = addr;
    reqMaster2.tx_buf = txdata;
    reqMaster2.tx_len = 1;
    reqMaster2.rx_buf = rxdata;
    reqMaster2.rx_len = len;
    reqMaster2.restart = 0;
    reqMaster2.callback = NULL;
    error = MXC_I2C_MasterTransaction(&reqMaster2);
    if (error != 0) {
        return error;
    }
    return 0;
}

I then started digging deeper into the libraries through debugging. When a reading occurs, the system runs line 973 without reading anything (read = 0 after axecution) and then sets up a new read at line 994 before restarting the while loop. This second time, the read is successful and after line 973 read >0. The problem is, as visible in the screenshot, the slave already responded to the first read request.

I seem to have solved the issue by adding the following instruction at line 966 in the file i2c_reva.c
i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_DONE;
I tried this as the same instruction is performed at line 992, before executing
i2c->fifo = (req->addr << 1) | 0x1; // Load slave address with read bit.
I was wondering if my fix is valid or if it can create unforseen behaviors in the future.
Please find attached the logic analyser screenshot with the double reads, and below the updated MXC_I2C_RevA_MasterTransaction function.
Thanks for the help.

int MXC_I2C_RevA_MasterTransaction(mxc_i2c_reva_req_t *req)
{
    mxc_i2c_reva_regs_t *i2c = req->i2c; // Save off pointer for faster access
    unsigned int written = 0;
    unsigned int read = 0;

    if (req->addr > MXC_I2C_REVA_MAX_ADDR_WIDTH) {
        return E_NOT_SUPPORTED;
    }

    if (MXC_I2C_GET_IDX((mxc_i2c_regs_t *)i2c) < 0) {
        return E_BAD_PARAM;
    }

    if (!(i2c->ctrl & MXC_F_I2C_REVA_CTRL_MST_MODE)) {
        return E_BAD_STATE;
    }

    // Check and return BUSY if the Bus is not ready
    if (i2c->status & MXC_F_I2C_REVA_STATUS_BUSY) {
        return E_BUSY;
    }

    // if(!read | write)
    //  Start
    //  send addr w/ write bit
    // if(Write)
    //  send tx_len data
    //  return if error (or NACK)
    // if(Read)
    //  if(Write)
    //   send restart
    //  else
    //   send start
    //  send addr w/ read bit
    //  read rx_len bytes acking all
    // stop or restart
    // return good or error

    MXC_I2C_ClearFlags((mxc_i2c_regs_t *)i2c, MXC_I2C_REVA_INTFL0_MASK,
                       MXC_I2C_REVA_INTFL1_MASK); // Clear all I2C Interrupts
    MXC_I2C_ClearTXFIFO((mxc_i2c_regs_t *)i2c);
    MXC_I2C_ClearRXFIFO((mxc_i2c_regs_t *)i2c);
    i2c->inten0 = 0;
    i2c->inten1 = 0;

    if ((req->rx_len == 0) || (req->tx_len != 0)) {
        // Load the slave address with write bit set
        i2c->fifo = (req->addr << 1) & ~0x1;
        i2c->mstctrl |= MXC_F_I2C_REVA_MSTCTRL_START;
    }

    while (req->tx_len > written) {
        if (i2c->intfl0 & MXC_F_I2C_REVA_INTFL0_TX_THD) {
            written += MXC_I2C_WriteTXFIFO((mxc_i2c_regs_t *)i2c, &req->tx_buf[written],
                                           req->tx_len - written);
            i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_TX_THD;
        }

        if (i2c->intfl0 & MXC_I2C_REVA_ERROR) {
            req->tx_len = written;
            MXC_I2C_Stop((mxc_i2c_regs_t *)i2c);
            return E_COMM_ERR;
        }
    }

    MXC_I2C_ClearFlags((mxc_i2c_regs_t *)i2c,
                       MXC_F_I2C_REVA_INTFL0_DONE | MXC_F_I2C_REVA_INTFL0_RX_THD, 0);

    if (req->rx_len != 0) {
        if (req->rx_len > MXC_I2C_REVA_MAX_FIFO_TRANSACTION) {
            i2c->rxctrl1 = 0;
        } else {
            i2c->rxctrl1 = req->rx_len; // 0 for 256, otherwise number of bytes to read
        }

        MXC_I2C_Start((mxc_i2c_regs_t *)i2c); // Start or Restart as needed

        while (i2c->mstctrl & MXC_F_I2C_REVA_MSTCTRL_RESTART) {}

        i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_DONE;
        i2c->fifo = (req->addr << 1) | 0x1; // Load slave address with read bit.
    }

    while (req->rx_len > read) {
        if (i2c->intfl0 & (MXC_F_I2C_REVA_INTFL0_RX_THD | MXC_F_I2C_REVA_INTFL0_DONE)) {
            read +=
                MXC_I2C_ReadRXFIFO((mxc_i2c_regs_t *)i2c, &req->rx_buf[read], req->rx_len - read);
            i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_RX_THD;
        }

        if (i2c->intfl0 & MXC_I2C_REVA_ERROR) {
            req->rx_len = read;
            MXC_I2C_Stop((mxc_i2c_regs_t *)i2c);
            return E_COMM_ERR;
        }

        if ((i2c->intfl0 & MXC_F_I2C_REVA_INTFL0_DONE) && (req->rx_len > read) &&
            (MXC_I2C_RevA_GetRXFIFOAvailable(i2c) == 0)) {
            if ((req->rx_len - read) > MXC_I2C_REVA_MAX_FIFO_TRANSACTION) {
                i2c->rxctrl1 = 0;
            } else {
                i2c->rxctrl1 = (req->rx_len - read); // 0 for 256, otherwise number of bytes to read
            }

            i2c->mstctrl |= MXC_F_I2C_REVA_MSTCTRL_RESTART;
            i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_DONE;
            i2c->fifo = (req->addr << 1) | 0x1; // Load slave address with read bit.
        }
    }

    if (req->restart) {
        i2c->mstctrl |= MXC_F_I2C_REVA_MSTCTRL_RESTART;
    } else {
        i2c->mstctrl |= MXC_F_I2C_REVA_MSTCTRL_STOP;

        while ((i2c->mstctrl & MXC_F_I2C_REVA_MSTCTRL_STOP)) {}
        // Wait for Transaction to finish
    }

    while (!(i2c->intfl0 & MXC_F_I2C_REVA_INTFL0_DONE)) {}
    // Wait for Transaction to finish

    i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_DONE | MXC_F_I2C_REVA_INTFL0_STOP;

    if (i2c->intfl0 & MXC_I2C_REVA_ERROR) {
        return E_COMM_ERR;
    }

    return E_NO_ERROR;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions