This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Trouble: TWI(I2C) stops at the function of i2c_reg_read_byte On nRF9160 DK. Why?

I'm trying to have nRF9160 DK communicate with an external accelerometer. 

nRF9160 stop working at the function of i2c_reg_read_byte in the code below.

Does anybody give any advice?

<main.c>

#include <nrf9160.h>
#include <zephyr.h>
#include <misc/printk.h>
#include <i2c.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

#define I2C_ACCEL_WRITE_ADDR 0x32
#define I2C_ACCEL_READ_ADDR 0x33

struct device *i2c_accel;
uint8_t WhoAmI = 0u;

uint8_t init_accelerometer(){
    i2c_accel = device_get_binding("I2C_2");
    if (!i2c_accel) {
		printk("error\r\n");
        return -1;
	} else  {
        i2c_configure(i2c_accel, I2C_SPEED_SET(I2C_SPEED_STANDARD));
        return 0;
    }
}

void main(void)
{
    printk("Hello, World!\r\n");
    init_accelerometer();

	while (1) {
        printk("loop head\r\n");

        if (i2c_reg_read_byte(i2c_accel, I2C_ACCEL_READ_ADDR, 0x0F, WhoAmI) != 0) { // stop wroking at this line
                printk("Error on i2c_read()\n");
        } else {
                printk("no error\r\n");
        }

        printk("WhoAmI = %u\r\n", WhoAmI);
        printk("enter sleep\r\n");
        k_sleep(1000);
	}
}

<prj.conf>

CONFIG_TRUSTED_EXECUTION_SECURE=y
# needed to get the NRF_UARTE2 define
CONFIG_UART_2_NRF_UARTE=y

CONFIG_TRUSTED_EXECUTION_NONSECURE=y
CONFIG_SERIAL=y
CONFIG_UART_INTERRUPT_DRIVEN=y

CONFIG_I2C=y
CONFIG_I2C_NRFX=y
CONFIG_I2C_2=y
CONFIG_I2C_INIT_PRIORITY=60

<overlay file>

/* needed to get the NRF_UARTE2 defined */
&uart2 {
	current-speed = <1000000>;
	status = "ok";
	tx-pin = <18>;
	rx-pin = <17>;
	rts-pin = <19>;
	cts-pin = <21>;
};

&i2c2 {
	status = "ok";
	sda-pin = <10>;
	scl-pin = <11>;
	clock-frequency = <100000>; 
};

UPDATE:

<printk>
***** Booting Zephyr OS v1.13.99-ncs2 *****
Hello, World!
loop head
// stack here

Parents
  • Do you have the source code for i2c_reg_read_byte() ?

    If yes, you should be able to see the line(s) of code where it is stuck inside of i2c_reg_read_byte()

    That would help us to help you further.   

    Thanks, Martin

  • Hi, mtsunstrum!. Thank you for your comment.

    I took i2c_reg_read_byte from zephyr driver.

    docs.zephyrproject.org/.../io_interfaces.html

    the definition is below. 

    /**
     * @brief Read internal register of an I2C device.
     *
     * This routine reads the value of an 8-bit internal register of an I2C
     * device synchronously.
     *
     * @param dev Pointer to the device structure for the driver instance.
     * @param dev_addr Address of the I2C device for reading.
     * @param reg_addr Address of the internal register being read.
     * @param value Memory pool that stores the retrieved register value.
     *
     * @retval 0 If successful.
     * @retval -EIO General input / output error.
     */
    static inline int i2c_reg_read_byte(struct device *dev, u16_t dev_addr,
    				    u8_t reg_addr, u8_t *value)
    {
    	return i2c_burst_read(dev, dev_addr, reg_addr, value, 1);
    }
  • Keep going .... 

    'res' tells you the result status. What is the value of 'res' ?

    And when you look in the nRF52 documentation what does that value of 'res' indicate as a possible reason for the failure ?

  • Also, before nrfx_twim_xfer() is executed, use your JTAG debugger to show all the values in nrfx_twim_xfer_desc_t data structure.

    Paste that data structure contents in this forum, so we can all help you with this issue.

    Info info info ...

  • I will inspect the code this weekend. By the way, can you reproduce the symptom on your nRF9160? Even If no I2C device is connected, "Error on i2c_read()" should be displayed if I2C works correctly.
    I'm using nRF91, not nRF52.
  • I created a new project and implemented almost same code. Then it works. I don't really figure out what was wrong. Anyway, this works.

    #include <nrf9160.h>
    #include <zephyr.h>
    #include <misc/printk.h>
    #include <i2c.h>
    #include <string.h>
    #include <stdlib.h>
    #include <math.h>
    
    #define I2C_ACCEL_WRITE_ADDR 0x32
    #define I2C_ACCEL_READ_ADDR 0x33
    
    struct device *i2c_accel;
    uint8_t WhoAmI = 0u;
    
    uint8_t init_accelerometer(){
        i2c_accel = device_get_binding("I2C_1");
        if (!i2c_accel) {
    		printk("error\r\n");
            return -1;
    	} else  {
                    i2c_configure(i2c_accel, I2C_SPEED_SET(I2C_SPEED_STANDARD));
            return 0;
        }
    }
    
    void main(void)
    {
            printk("Hello, World!\r\n");
            init_accelerometer();
    
    	while (1) {
                    printk("loop head\r\n");
    
                    if (i2c_reg_read_byte(i2c_accel, I2C_ACCEL_READ_ADDR >> 1, 0x0F, &WhoAmI) != 0) {
                            printk("Error on i2c_read()\n");
                    } else {
                            printk("no error\r\n");
                    }
    
                    printk("WhoAmI = %u\r\n", WhoAmI);
                    printk("enter sleep\r\n");
                    k_sleep(3000);
    	}
    }

    <prj.conf>
    CONFIG_TRUSTED_EXECUTION_SECURE=y
    CONFIG_SERIAL=y
    CONFIG_UART_INTERRUPT_DRIVEN=y
    CONFIG_I2C=y
    CONFIG_I2C_NRFX=y
    CONFIG_I2C_1=y
    CONFIG_I2C_INIT_PRIORITY=60
    

    <overlay file>
    /* needed to get the NRF_UARTE2 defined */
    &uart2 {
    	current-speed = <1000000>;
    	status = "ok";
    	tx-pin = <18>;
    	rx-pin = <17>;
    	rts-pin = <19>;
    	cts-pin = <21>;
    };
    
    &i2c1 {
    	status = "ok";
    	sda-pin = <10>;
    	scl-pin = <11>;
    	clock-frequency = <100000>; 
    };

Reply
  • I created a new project and implemented almost same code. Then it works. I don't really figure out what was wrong. Anyway, this works.

    #include <nrf9160.h>
    #include <zephyr.h>
    #include <misc/printk.h>
    #include <i2c.h>
    #include <string.h>
    #include <stdlib.h>
    #include <math.h>
    
    #define I2C_ACCEL_WRITE_ADDR 0x32
    #define I2C_ACCEL_READ_ADDR 0x33
    
    struct device *i2c_accel;
    uint8_t WhoAmI = 0u;
    
    uint8_t init_accelerometer(){
        i2c_accel = device_get_binding("I2C_1");
        if (!i2c_accel) {
    		printk("error\r\n");
            return -1;
    	} else  {
                    i2c_configure(i2c_accel, I2C_SPEED_SET(I2C_SPEED_STANDARD));
            return 0;
        }
    }
    
    void main(void)
    {
            printk("Hello, World!\r\n");
            init_accelerometer();
    
    	while (1) {
                    printk("loop head\r\n");
    
                    if (i2c_reg_read_byte(i2c_accel, I2C_ACCEL_READ_ADDR >> 1, 0x0F, &WhoAmI) != 0) {
                            printk("Error on i2c_read()\n");
                    } else {
                            printk("no error\r\n");
                    }
    
                    printk("WhoAmI = %u\r\n", WhoAmI);
                    printk("enter sleep\r\n");
                    k_sleep(3000);
    	}
    }

    <prj.conf>
    CONFIG_TRUSTED_EXECUTION_SECURE=y
    CONFIG_SERIAL=y
    CONFIG_UART_INTERRUPT_DRIVEN=y
    CONFIG_I2C=y
    CONFIG_I2C_NRFX=y
    CONFIG_I2C_1=y
    CONFIG_I2C_INIT_PRIORITY=60
    

    <overlay file>
    /* needed to get the NRF_UARTE2 defined */
    &uart2 {
    	current-speed = <1000000>;
    	status = "ok";
    	tx-pin = <18>;
    	rx-pin = <17>;
    	rts-pin = <19>;
    	cts-pin = <21>;
    };
    
    &i2c1 {
    	status = "ok";
    	sda-pin = <10>;
    	scl-pin = <11>;
    	clock-frequency = <100000>; 
    };

Children
  • Hello Yusuke,

    I'm also trying to communicate nRF9160 DK with an external accelerometer using I2C. I want to read the accelerometer and gyroscope values. I tried your code. When I don't connect the accelerometer, Error on i2c_read() is displayed which is correct. But when I connect the accelerometer nothing prints. The program stops there. After "loop head" nothing is printed on the terminal. Did you face the same problem? Do you know how to print the accelerometer values?

    Thanks

  • This works for me

    Windows10
    nrf v1.2.0

    main.c

    #include <zephyr.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <drivers/i2c.h>
    #include <device.h>
    
    #define I2C_ACCEL_ADDR (0x32 >> 1)
    #define ACCEL_REG_WHO_AM_I 0x0F
    
    struct device *i2c_2;
    
    u8_t configure_accelerometer() {
    
        if (i2c_reg_write_byte(i2c_2, I2C_ACCEL_ADDR, 0x20, 0x2F) != 0) { // CTRL_REG1 (20h), Enable x,y,z axis, 10Hz, normal mode
                return -1;
        }
        if (i2c_reg_write_byte(i2c_2, I2C_ACCEL_ADDR, 0x21, 0x01) != 0) { // CTRL_REG2 (21h), High-pass filter enabled for AOI function on Interrupt 1.
                return -1;
        }
        if (i2c_reg_write_byte(i2c_2, I2C_ACCEL_ADDR, 0x22, 0x40) != 0) { // CTRL_REG3 (23h), IA1 interrupt on INT1 pin enable
                return -1;
        }
        if (i2c_reg_write_byte(i2c_2, I2C_ACCEL_ADDR, 0x30, 0x2A) != 0) { // INT1_CFG (30h), Enable interrupt generation on X,Y,Z high event or on direction recognition
                return -1;
        }
        if (i2c_reg_write_byte(i2c_2, I2C_ACCEL_ADDR, 0x32, 0x08) != 0) { // INT1_THS (32h), 1 LSb = 16 mg, threshold = 128mg
                return -1;
        }
        if (i2c_reg_write_byte(i2c_2, I2C_ACCEL_ADDR, 0x33, 0x00) != 0) { // INT1_DURATION (33h), Set the minimum duration of the Interrupt 1 event to be recognized
                return -1;
        }
    
        return 0;
    }
    
    void main(void)
    {
        u8_t rx_buf[1];
        int8_t ret;
    
        i2c_2 = device_get_binding("I2C_2");
        if (!i2c_2) {
            sys_reboot(0);
        }
    
        if(configure_accelerometer() != 0) {
            sys_reboot(0);
        }
    
        u8_t reg = ACCEL_REG_WHO_AM_I;
    
        while (1) {
            printk("loop head\r\n");
            ret = i2c_burst_read(i2c_2, I2C_ACCEL_ADDR, reg, rx_buf, sizeof(rx_buf));
            if(ret == 0){ /* success */
                printk( "Read:  register = 0x%02X, value = 0x%02X\r\n", reg, rx_buf[0]);
            } else { /* ret = -EIO */
                printk( "i2c_burst_read fail!, register = 0x%02X, ret = %d\r\n", reg, ret);
            }
    
            k_sleep(3000);
        }            
    }
    

    prj.conf

    # General
    CONFIG_TRUSTED_EXECUTION_NONSECURE=y
    CONFIG_AT_HOST_LIBRARY=n
    CONFIG_SERIAL=y
    
    # I2C
    CONFIG_I2C=y
    CONFIG_I2C_NRFX=y
    CONFIG_I2C_2=y
    CONFIG_I2C_2_NRF_TWIM=y
    
    # Rebooot
    CONFIG_REBOOT=y
    
    # SEGGER RTT for Dev
    CONFIG_PRINTK=y
    CONFIG_CONSOLE=y
    CONFIG_STDOUT_CONSOLE=y
    CONFIG_UART_CONSOLE=n
    CONFIG_RTT_CONSOLE=y
    CONFIG_USE_SEGGER_RTT=y

    nrf9160_pca10090ns.overlay

    &i2c2 {
    	status = "okay";
    	sda-pin = <15>;
    	scl-pin = <16>;
    	clock-frequency = <100000>; 
    };

Related