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

  • Hello

    What sort of ACK are you expecting to see other than the functions returning 0?

    What sort  of register are you trying to read from the I2C device, and are you sure it's not read correctly?

    Can you explain what you have done to test writing, since you are unable to read?

    Best regards,

    Einar

  • 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

  • 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