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 did not end up getting it to work. I don't recall if I got the aforementioned examples to work. We dropped the nRF5340 and began developing with the nRF52840 again. Good luck!

  • Hi .

    crohloff said:
    but neither do i get the i2c_scanner sample or the bme680 sample working.

     How are they not working?

    Have you tried to connect a logic analyzer to see if you get any activity on the lines?

    Best regards,

    Didrik

  • It is the exact same behavior as Marciano-PL described. And then you mentioned that both examples work for you but maybe we have different chip versions? Thanks in advance.

  • 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).

Reply
  • 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).

Children
Related