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

nRF5340 unable to write with I2C_1 in Zephyr

I am attempting to write a basic I2C program using Zephyr, but I am currently unable to sent a single byte over I2C. Am I doing something wrong? I'd prefer not to use the nrfxlib. 

Here is a list of the presently known TWIM errata:
(https://infocenter.nordicsemi.com/topic/errata_nRF5340_EngA/ERR/nRF5340/EngineeringA/latest/err_340_new.html)

[21] TWIM: 1000 kbps baud rate is not functional
[37] TWIM: First clock pulse after clock stretching may be too long or too short
[47] TWIM: I2C timing spec is violated at 400 kHz
[82] TWIM: TWIM2 and TWIM3 are not functional

Platform: nRF5340 PDK
SDA: P0.30
SCL: P0.31

Project Configuration: 

CONFIG_NEWLIB_LIBC=y
CONFIG_PRINTK=y
CONFIG_HAS_SEGGER_RTT=y
CONFIG_USE_SEGGER_RTT=y
CONFIG_RTT_CONSOLE=y
CONFIG_UART_CONSOLE=n

# nRF5340 board config
CONFIG_TRUSTED_EXECUTION_SECURE=y

CONFIG_BT=n
CONFIG_TIMESLICING=n
CONFIG_DEVICE_POWER_MANAGEMENT=y
CONFIG_SYS_POWER_MANAGEMENT=y
CONFIG_SYS_POWER_DEEP_SLEEP_STATES=y
CONFIG_DEVICE_POWER_MANAGEMENT=y

CONFIG_I2C=y
CONFIG_I2C_1=y

main.c

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

/* Application main Thread */
int main(void)
{
  struct device *p_i2c = device_get_binding("I2C_1");
  u32_t dev_config = I2C_SPEED_SET(I2C_SPEED_STANDARD) | I2C_MODE_MASTER;
  int res = i2c_configure(p_i2c, dev_config);
  if (res)
  {
    return res;
  }
  u8_t buf[2] = {0x0, 0xFF};
  i2c_burst_write(p_i2c, 0x77, 0x14, buf, 2);
  return 0;
}

Waveform:

  • First the HW related questions, do you have pull-ups turned on on the GPIOs? or do you have external pull up resistors? and what i2c device do you have connected to the bus? 

    Is i2c_burst_write() supported by the nrf5340? read https://docs.zephyrproject.org/apidoc/latest/group__i2c__interface_gae57ea5a1b4059e0d03d3bc068288de1f.html 

    I have been using this for simple transfers on the nrf52840 (previous generation nrf chip)

    int i;
    struct i2c_msg msgs[2];
    u8_t data[2][2];
    
    printf("pca9536_init().\n");
    i2c_dev = device_get_binding("I2C_1");
    if (!i2c_dev) {
    printf("pca9536_init(): I2C Device driver not found.\n");
    return;
    }
    // set the pins to outputs, and drive high
    data[0][0] = 3; // config register
    data[0][1] = 0xFF^((1<<PCA9536_RED_LED_PIN)|(1<<PCA9536_GREEN_LED_PIN)|(1<<PCA9536_BLUE_LED_PIN)); // 3 outputs
    msgs[0].buf = data[0];
    msgs[0].len = 2U;
    msgs[0].flags = I2C_MSG_WRITE | I2C_MSG_STOP;
    
    data[1][0] = 1; // output register
    data[1][1] = pca9536_state;
    msgs[1].buf = data[1];
    msgs[1].len = 2U;
    msgs[1].flags = I2C_MSG_WRITE | I2C_MSG_STOP;
    i = i2c_transfer(i2c_dev, &msgs[0], 2, (u8_t)PCA9536_I2C_ADDR);
    if (i!=0) {
    printf("pca9536_init(): transfer failed.\n");
    return;
    }

  • Thank you for the quick reply. 

    Hardware
    I have been using external pull-ups and a BME680. I removed the BME680 and kept the pull-ups and observed the same behavior on the bus.

    Software
    I switched over to using the `i2c_transfer()` function. The bus looks the same as with the previous implementation. The function only returns if I step through each call with the debugger. And only some times. Otherwise the program ends up hanging in nrf_regulators_system_off(...)


    Has there been much testing of the nRF5340 by way of i2c on zephyr?  

  • After more debugging, I found that the location in which the code is failing is when the i2c_nrfx_twim.c driver calls k_sem_take in the following code. In the snippet it is line 36. It seems to work everytime if I step across that line with the debugger. I think there is somehow a timing issue.

    i2c_nrfx_twim.c

    static int i2c_nrfx_twim_transfer(struct device *dev, struct i2c_msg *msgs,
    				  u8_t num_msgs, u16_t addr)
    {
    	int ret = 0;
    
    	k_sem_take(&(get_dev_data(dev)->transfer_sync), K_FOREVER);
    	nrfx_twim_enable(&get_dev_config(dev)->twim);
    
    	for (size_t i = 0; i < num_msgs; i++) {
    		if (I2C_MSG_ADDR_10_BITS & msgs[i].flags) {
    			ret = -ENOTSUP;
    			break;
    		}
    
    		nrfx_twim_xfer_desc_t cur_xfer = {
    			.p_primary_buf  = msgs[i].buf,
    			.primary_length = msgs[i].len,
    			.address	= addr,
    			.type		= (msgs[i].flags & I2C_MSG_READ) ?
    					  NRFX_TWIM_XFER_RX : NRFX_TWIM_XFER_TX
    		};
    		nrfx_err_t res = nrfx_twim_xfer(&get_dev_config(dev)->twim,
    					       &cur_xfer,
    					       (msgs[i].flags & I2C_MSG_STOP) ?
    					       0 : NRFX_TWIM_FLAG_TX_NO_STOP);
                    if (res != NRFX_SUCCESS) {
    			if (res == NRFX_ERROR_BUSY) {
    				ret = -EBUSY;
    				break;
    			} else {
    				ret = -EIO;
    				break;
    			}
    		}
                    
    		k_sem_take(&(get_dev_data(dev)->completion_sync), K_FOREVER);
    
    		res = get_dev_data(dev)->res;
    		if (res != NRFX_SUCCESS) {
    			LOG_ERR("Error %d occurred for message %d", res, i);
    			ret = -EIO;
    			break;
    		}
    	}
    
    	nrfx_twim_disable(&get_dev_config(dev)->twim);
    	k_sem_give(&(get_dev_data(dev)->transfer_sync));
    
    	return ret;
    }
     

  • Hi.

    Have you tried the bme680 or i2c_scanner samples in the zephyr repo?

    Both of them seem to work for me (I had to test without any I2C device connected).

    To get the bme680 sample to work on the nRF53DK, you have to add the following nrf5340_dk_nrf5340_cpuapp.overlay file in the project directory (next to the CMakeLists.txt file):

    &i2c1 {
      bme680@76 {
    		compatible = "bosch,bme680";
    		label = "BME680";
            reg = <0x76>;
      };
    };

    Replace the "76" after the "@" and in the reg field with the address of your sensor.

    To run the i2c_scanner sample, you have to change the "I2C_DEV" define to "I2C_1" on line 16 in main.c.

    Best regards,

    Didrik

  • Hi,

    i am having the same issue, but neither do i get the i2c_scanner sample or the bme680 sample working.

    I added the bme680 node to the dts and switched the I2C_DEV to I2C_1

    Did you manage to get those samples to work on the nrf5340_dk?

    Best regards,

    Chris

Related