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:

Parents
  • 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;
    }

  • 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;
    }
     

  • I'm fairly certain there is an issue with the code. As I commented above, the issue is with the semaphore take command. When I step across it with the debugger everything runs fine. If I let it run normally, I got problems.

  • Is there any code running on the network core?

    It might be that the network core is using the serial peripheral for e.g. logging, which would cause problems.

    You can try to "erase all" from the "Programmer" application in nRF Connect for Desktop to make sure that there is nothing running on the network core.

    While it seems that the i2c_scanner sample has been removed in NCS v1.2.0, the first transaction in the bme680 sample seems to work as expected (I do not have access to a bme680 at the moment, so testing the sample properly is a bit hard).

  • When I was running my application core code, my network core was running the HCI example. I don't think it had any use for the I2C busses, but I'm not sure.

  • It wouldn't have to use I2C for it to be a problem. The nRF uses the same peripheral for both UART, SPI, and I2C, so if you use the peripheral for UART, you will not be able to use it for I2C. In addition, on the nRF553, some peripherals can be used by both cores. Therefore, if the network core uses the same peripheral that you want to use for I2C for logging over UART, you will have a problem.

  • , have you gotten the I2C with the BME680 to work the nRF52840 in Zephyr? I keep getting NRFX_ERROR_INTERNAL error and think I have some problem with my Zephyr setup. I am using the nRF52840-DK and the BME680 Zephyr example. The following ticket has all my settings, devzone.nordicsemi.com/.../bme680-zephyr-example-not-working-with-the-nrf52840-dk

Reply Children
Related