i2c_write_dt stop

Hello,
trying this and that with a qwiic relay, first a test on i2ccl then VS using a 9160DK.
(i2ccl -> pip install i2cdriver)

i2ccl /dev/ttyUSB0 w 0x18 5 r 0x18 1


returns a status of 0x00 that relay is not activated.

then in VS,

uint8_t wBuff[1] = {0x05};
uint8_t rBuff = 0x00;
uint8_t a = 0;

a = i2c_write_read_dt(&dev_i2c, wBuff, sizeof(wBuff), &rBuff, sizeof(rBuff));
if (a != 0) {
        printk("I2C error %d\n", a);
}
printk("Status: %X\n", rBuff);


Status: 0
same as i2ccl

Then when trying to activate the relay with a write,

i2ccl /dev/ttyUSB0 w 0x18 1 p


the relay clicks on ok

But in VS,

uint8_t wArray[1] = {0x01};
uint8_t a = 0;

a = i2c_write_dt(&dev_i2c, wArray, 1);
if (a != 0) {
    printk("I2C write failed with error %d\n", a);
}


There is no click response.
The difference seems to be that i2ccl is sending stop 'p' at the end of the write which Zephyr might not be doing the same.
When trying write and read 0x05 status separately in VS, the result is ok and same as i2ccl without stop.
If it is the missing stop, how best then to get a stop into i2c_write_dt?

thank-you,

Parents
  • Hello,

    Looking at\zephyr\include\zephyr\drivers\i2c.h I can find in the implementation of i2c_write_dt()/i2c_write() that the flags are fixed for this api:

    static inline int i2c_write(const struct device *dev, const uint8_t *buf,
    			    uint32_t num_bytes, uint16_t addr)
    {
    	struct i2c_msg msg;
    
    	msg.buf = (uint8_t *)buf;
    	msg.len = num_bytes;
    	msg.flags = I2C_MSG_WRITE | I2C_MSG_STOP;
    
    	return i2c_transfer(dev, &msg, 1, addr);
    }

    If you instead use the i2c_transfer_dt()/i2c_transfer() api directly you can set the flags yourself. I can see some drivers do this, and I just copy an example from \zephyr\drivers\sensor\maxim\max44009\max44009.c that might be useful as reference:

    static int max44009_reg_read(const struct device *dev, uint8_t reg,
    			     uint8_t *val, bool send_stop)
    {
    	const struct max44009_config *config = dev->config;
    	struct i2c_msg msgs[2] = {
    		{
    			.buf = &reg,
    			.len = 1,
    			.flags = I2C_MSG_WRITE,
    		},
    		{
    			.buf = val,
    			.len = 1,
    			.flags = I2C_MSG_READ,
    		},
    	};
    
    	if (send_stop) {
    		msgs[1].flags |= I2C_MSG_STOP;
    	}
    
    	if (i2c_transfer_dt(&config->i2c, msgs, 2) != 0) {
    		return -EIO;
    	}
    
    	return 0;
    }

    Kenneth

  • Tried using i2c_transfer_dt instead of i2c_write_dt (if that was the suggestion) but with no resulting click.

    uint8_t wArray[1] = {0x01};
    uint8_t a = 0;
    
    struct i2c_msg msgs[2] = {
        {
            .buf = wArray,
            .len = 1,
            .flags = I2C_MSG_WRITE,
        },
        {
            .flags = I2C_MSG_STOP,
        },
    };
    
    a = i2c_transfer_dt(&dev_i2c, msgs, 2);
    if (a != 0) {
        printk("I2C transfer failed with error %d\n", a);
    }else{
        printk("a %x \n", a);
    }

    Or was the suggestion to create my own custom relay driver using max44009.c as an example and add it to /ncs/v2.9.0/zephyr/drivers/i2c ?

    thank-you,

  • Working ok examples of the relay using i2ccl:

    i2ccl /dev/ttyUSB1 w 0x18 5 r 0x18 1

    >>>>>>>>>>>>>>>>>>>>>>>>

    i2ccl /dev/ttyUSB0 w 0x18 1 p



    Then in VS using a 9160DK:
    i2c_transfer_dt
    uint8_t wArray[1] = {0x01};
    uint8_t a = 0;
    
    struct i2c_msg msgs[2] = {
        {
            .buf = wArray,
            .len = 1,
            .flags = I2C_MSG_WRITE,
        },
        {
            .flags = I2C_MSG_STOP,
        },
    };
    
    a = i2c_transfer_dt(&dev_i2c, msgs, 2);
    if (a != 0) {
        printk("I2C transfer failed with error %d\n", a);
    }else{
        printk("a %x \n", a);
    }


    >>>>>>>>>>>>>>>>>>>>>>>>
    i2c_write_read_dt
    uint8_t wBuff[1] = {0x05};
    uint8_t rBuff = 0x00;
    uint8_t a = 0;
    
    a = i2c_write_read_dt(&dev_i2c, wBuff, sizeof(wBuff), &rBuff, sizeof(rBuff));
    if (a != 0) {
            printk("I2C error %d\n", a);
    }
    printk("Status: %X\n", rBuff);


    >>>>>>>>>>>>>>>>>>>>>>>>
    i2c_write_dt
    uint8_t wArray[1] = {0x01};
    uint8_t a = 0;
    
    a = i2c_write_dt(&dev_i2c, wArray, 1);
    if (a != 0) {
        printk("I2C write failed with error %d\n", a);
    }


    >>>>>>>>>>>>>>>>>>>>>>>>

    The PulseView output is showing different Addresses, like 18, 14, 10, where I think they should all be 18.
    For now, not sure why this is so.

    Reused DevAcademy code for this test.
    Changing the address of the i2c to 0x18.
    /boards/nrf9160dk_nrf9160_ns.overlay
    &i2c2 {
        status = "okay";
        pinctrl-0 = <&i2c2_default>;
        pinctrl-1 = <&i2c2_sleep>;
        pinctrl-names = "default", "sleep";
        mysensor: mysensor@18{
            compatible = "i2c-device";
            status = "okay";
            reg = < 0x18 >;
        };
    };
    
    &pinctrl {
        /omit-if-no-ref/ i2c2_default: i2c2_default {
            group1  {
                psels = <NRF_PSEL(TWIM_SCL, 0, 12)>,
                        <NRF_PSEL(TWIM_SDA, 0, 13)>;
            };
        };
    
        /omit-if-no-ref/ i2c2_sleep: i2c2_sleep {
            group1  {
                psels = <NRF_PSEL(TWIM_SCL, 0, 12)>,
                        <NRF_PSEL(TWIM_SDA, 0, 13)>;
                low-power-enable;
            };
        };
    };


    thank-you,


  • For comparison, here is the PulseView BME280 output for DevAcademy Fund L6-E1 v2.9.0,

    thank-you,

  • In an ideal world I would have time to try this, but unfortunately I don't. Looking at what is working I would expect something like this to work:

    // read
    msg[0].buf = value 5?;
    msg[0].len = 1;
    msg[0].flags = I2C_MSG_WRITE;

    msg[1].buf = buf;
    msg[1].len = 1;
    msg[1].flags = I2C_MSG_RESTART | I2C_MSG_READ | I2C_MSG_STOP;

    return i2c_transfer_dt(spec, msg, 2);

    // write

    msg[0].buf = value 1?;
    msg[0].len = 1;
    msg[0].flags = I2C_MSG_WRITE | I2C_MSG_STOP;

    return i2c_transfer_dt(spec, msg, 1);

    Kenneth

  • Made the slight change to the previous try of i2c_transfer_dt.

    uint8_t wArray[1] = {0x01}; // Register address to read from
    uint8_t a = 0;
    
    struct i2c_msg msgs[1] = {
        {
            .buf = wArray,
            .len = 1,
            .flags = I2C_MSG_WRITE | I2C_MSG_STOP,
        },
    };
    
    a = i2c_transfer_dt(&dev_i2c, msgs, 1);
    if (a != 0) {
        printk("I2C transfer failed with error %d\n", a);
    }else{
        printk("a %x \n", a);
    }

    Same result and no relay click.
    Will try i2c_write_dt() again.
    From the logic output, it seems to have the right structure.

    thank-you,

  • Better success using i2c_write_dt() on a thingy:53.

    thank-you,

Reply Children
No Data
Related