This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

I2C reading from a register not working

Hello,

I am using zephyr on a nRF52840 to communicate with a vl53l5cx TOF sensor using I2C. When I use i2c_reg_read_byte() or i2c_burst_read(), the device address is sent, the internal register is sent, and then when read command is sent I receive no ACK and no error is returned from the function. Writing using the same functions work as expected. I am using sdk 1.9.1. Any help would be appreciated.

#include <zephyr.h>
#include <device.h>
#include <drivers/sensor.h>
#include <stdio.h>
#include <sys/printk.h>
#include <drivers/i2c.h>

#define TOF_I2C_ADDR (0x52 >> 1)

void main(void)
{
	const struct device *i2c_dev = device_get_binding("I2C_0");

	int ret;
	uint8_t buf[1];
	buf[0] = 0x1;
	//buf[1] = 0x2;
	//buf[2] = 0x3;
	//buf[3] = 0x4;

	if (i2c_dev == NULL)
	{
		printk("Could not get device\n");
		return;
	}

	i2c_configure(i2c_dev, I2C_SPEED_SET(I2C_SPEED_STANDARD));
	k_msleep(10);

	while (1)
	{
		ret = i2c_reg_read_byte(i2c_dev, TOF_I2C_ADDR, 0x00, buf);
		if (ret)
		{
			printk("Failed to read/write byte: %d\n", ret);
		}

		//printk("Buf: [%d, %d, %d, %d]\n\n", buf[0], buf[1], buf[2], buf[3]);
		printk("Buf: [%d]\n\n", buf[0]);
		k_msleep(1000);
	}
}

Thanks,

Jacob

Parents
  • Hi,

    I have my SDA and SCL lines connected to a scope, here is the output from the above code:

    The register address is written, then it should be a read command but the r/w bit is not set correctly. I believe this is an issue with i2c_reg_read_byte() and hence the i2c_write_read() since these do not work for me. However, if I perform a i2c_write() with my register address and a i2c_read afterwards it works as expected and this is the workaround I am currently using.

    -Jacob

Reply
  • Hi,

    I have my SDA and SCL lines connected to a scope, here is the output from the above code:

    The register address is written, then it should be a read command but the r/w bit is not set correctly. I believe this is an issue with i2c_reg_read_byte() and hence the i2c_write_read() since these do not work for me. However, if I perform a i2c_write() with my register address and a i2c_read afterwards it works as expected and this is the workaround I am currently using.

    -Jacob

Children
  • Hi

    This sounds very strange, I would expect i2c_write_read() to behave the same way as i2c_write(); i2c_read().

    There was no other difference when you tested this?

    Can you show me the exact function calls you used with parameters?

    -Einar

  • 	ret = i2c_write(i2c_dev, reg, 1U, TOF_I2C_ADDR);
    	ret = i2c_read(i2c_dev, buf, 1U, TOF_I2C_ADDR);

    This works and it reads the value expected the specified register.

    However, this

    ret = i2c_reg_read_byte(i2c_dev, TOF_I2C_ADDR, 0x0, buf);

    nor this work, and give the output on the scope shown above

    ret = i2c_write_read(i2c_dev, TOF_I2C_ADDR, reg, sizeof(*reg), buf, sizeof(buf));

    reg and buf are defined as such for testing purposes:

    	uint8_t buf[1];
    	buf[0] = 0x1;
    
    	uint8_t i = 0;
    	uint8_t *reg;
    	reg = &i;

  • Ok, so I've been looking deeper into this, and I think the problem is that according to the datasheet, your vl53l5cx TOF expects a stop bit after the write before beginning a read.

    Looking at the I2C source code in zephyr/include/drivers/i2c.h, write_read is exactly the same as write; read; _except_ that there is no stop bit at the end of the write in write_read. Also, the reg_read_byte function actually just calls the write_read function.

    So I think you have two options: either you can keep doing write; read; or you can write your own i2c function that uses i2c_transfer the same way write_read does, but with the stop bit added to the write part.

    Best regards,

    Einar

Related