Skip to content

i2c_sam0.c i2c_sam0_transfer operations do not execute a STOP #41016

@maxmclau

Description

@maxmclau

Describe the bug
The i2c implementation on my ATSAMD51N19A board does not release the i2c line after a i2c_reg_read_byte_dt() operation.

To Reproduce

  1. Use a boiler plate blinky project
  2. Add i2c peripheral (BQ40z80 in my case)
  3. Use i2c_reg_read_byte_dt() to read a simple 8-bit register value
  4. Observe SCL line held LOW after operation (see screenshot)

Expected behavior
Running down the call stack i2c_sam0_transfer() is called without the I2C_MSG_STOP flag set.

if (data->msgs->flags & I2C_MSG_STOP) {
    i2c->CTRLB.bit.CMD = 3;
} else if ((data->msgs->flags & I2C_MSG_RESTART) && data->num_msgs > 1) {
    /*
        * No action, since we do this automatically if we
        * don't send an explicit stop
        */
} else {
    /*
        * Neither present, so assume we want to release
        * the bus (by sending a stop)
        */
    i2c->CTRLB.bit.CMD = 3;
}

Impact
This is causing a timeout on my fuel gauge's SMBbus line every other call throwing an arbitration error.

Logs and console output

DS1Z_QuickPrint3

Additional context
Calling a stop using i2c_transfer() after every i2c_reg_read_byte_dt() operation fixes my issue and releases the line.

i2c_reg_read_byte_dt(&cfg->bus, reg, &data);

struct i2c_msg msgs[1];
uint8_t addr = (uint8_t)cfg->bus.addr;

// ping i2c address of gauge
msgs[0].buf = &addr;
msgs[0].len = 0;
msgs[0].flags = I2C_MSG_STOP;

ret = i2c_transfer(cfg->bus.bus, &msgs[0], 1, addr);

Sorry if this is all vague, I'm very new to Zephyr and could be missing something very simple here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugThe issue is a bug, or the PR is fixing a bug

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions