Use Nordic's nrfx_twi driver in Zephyr

Hello, guys.

I am trying to port some existing piece of code that benefints from Nordic's SDK into Zephyr OS environment. The part of the code is using I2C bus to communicate with the sensor (CST816S touch controller).

To properly read the content of CST816S register, the following I2C-related lines are used:

ret = nrfx_twi_tx(&m_twi_0, 0x15, w2_data, 1, true);
...
ret = nrfx_twi_rx(&m_twi_0, 0x15, w2_data, 1);

The first line of code from above (nrfx_twi_tx(&m_twi_0, 0x15, w2_data, 1, true);) is I2C transfer without STOP stop condition generated at the end of the transfer (because the last argument is set to true).

I was initially trying to use native I2C drivers from Zephyr OS but was unable to find appropriate counterpart for nrfx_twi_tx(&m_twi_0, 0x15, w2_data, 1, true) type of I2C transfer. I used i2c_write_read() API that comes from Zephyr environment hoping that it will replace tx/rx requst from the above lines of code but to no avail.

I am now trying to figure out how to use Nordic's nrfx_twi drivers in Zephyr environment.

Putting the following lines in prj.conf file:

CONFIG_I2C=y
CONFIG_I2C_NRFX=y
CONFIG_NRFX_TWI=y
CONFIG_NRFX_TWI0=y
CONFIG_NRFX_TWI1=y

and trying to initialize I2C peripheral with:

    const nrfx_twi_config_t config_A = {
    .scl                = TWI_A_SCL_PIN,
    .sda                = TWI_A_SDA_PIN,
    .frequency          = NRF_TWI_FREQ_400K,
    .interrupt_priority = 1, //APP_IRQ_PRIORITY_HIGH,
    .hold_bus_uninit     = false
    };

    err_code = nrfx_twi_init(&m_twi_0, &config_A, NULL, NULL);
    LOG_INF("nrfx_twi_init(m_twi0): 0x%X", err_code);

    nrfx_twi_enable(&m_twi_0);

does not work properly. nrfx_twi_init() function returns  0xBAD0005 (NRFX_ERROR_INVALID_STATE).

I also tried to include the following part during the initialization process (before nrfx_twi_init() function):

    IRQ_CONNECT(DT_IRQN(DT_NODELABEL(i2c0)),
       DT_IRQ(DT_NODELABEL(i2c0), priority),
       nrfx_isr, nrfx_twi_0_irq_handler, 0);

but at that point, I got the following compilation error:

gen_isr_tables.py: error: multiple registrations at table_index 3 for irq 3 (0x3)
Existing handler 0x6773, new handler 0x6773
Has IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?

What I am missing here, what would be the proper way of using Nordic's nrfx_twi driver in Zephyr environment?

Is there any appropriate Zephyr I2C counter-part for this type of I2C transfers -> nrfx_twi_tx(&m_twi_0, 0x15, w2_data, 1, true)?

Thanks in advance for your time and efforts. It is really appreciated.

Looking forward to reading from you.

Sincerely,

Bojan.

Parents
  • Hello!

    What exactly were the issues you faced when you tried using i2c_write_read?

    I believe that API should suit your use case quite well.

    Best regards,

    Einar

  • Hello, .

    When I use Zephyr's I2C drivers here is what I include in prj.conf file:

    CONFIG_I2C=y
    CONFIG_I2C_0=y
    CONFIG_I2C_1=y

    after that, I initialize I2C bus with:

    i2c_dev0 = device_get_binding("I2C_0");    
    int ret = i2c_configure(i2c_dev0, I2C_SPEED_SET(I2C_SPEED_FAST) | I2C_MODE_MASTER);
    

    Everything goes smoothly up to this point.

    Now, when I want to replace the following piece of code:

    ret = nrfx_twi_tx(&m_twi_0, 0x15, w2_data, 1, true);
    ...
    ret = nrfx_twi_rx(&m_twi_0, 0x15, w2_data, 1);

    with

    ret = i2c_write_read(i2c_dev0, 0x15, w2_data, 1, &w2_data[1], 1);

    I get the following error:

    <err> i2c_nrfx_twi: Error on I2C line occurred for message 0
    <err> touch_ll: ***ERROR: i2c_write_read: -5

    -5 is the error code for EIO.

    I also noticed that, inside some other function that I am porting to Zephyr, there will be a need to just transfer the bytes over I2C with:

    uint32_t rev=nrfx_twi_tx(&m_twi_0, 0x6a, sendBuf, len+lenT, true);

    This is also an I2C transfer without the STOP stop condition generated at the end of the transfer. I imagine that an appropriate Zephyr counter-part function would be i2c_burst_write(). However, that function has one additional parameter which is the starting address (the address of the I2C register from where to start writing in burst mode). This parameter is missing in nrfx_twi_tx(..., true) function.

    For all the above reasons and errors, I just thought it might be useful to give it a try with using Nordic's NRFX_TWI APIs from Zephyr.

    Do you have any idea what I am doing wrong?

    Cheers,

    Bojan.

  • Hi!

    Where do you have the "CONFIG_I2C_0" and "CONFIG_I2C_1" options from? I can't seem to find them in the Kconfig documentation.

    Have you checked that the I2C device is actually enabled before you bind it to the device struct?

    You can do this by checking if the devicetree node has status "okay":

    #define I2C0_NODE DT_NODELABEL(i2c0)

    #if DT_NODE_HAS_STATUS(I2C0_NODE, okay)

    #define I2C0 DT_LABEL(I2C0_NODE)

    For transferring bytes, I believe the function you are looking for in the I2C API is i2c_write, not i2c_burst_write.

    Best regards,

    Einar

Reply
  • Hi!

    Where do you have the "CONFIG_I2C_0" and "CONFIG_I2C_1" options from? I can't seem to find them in the Kconfig documentation.

    Have you checked that the I2C device is actually enabled before you bind it to the device struct?

    You can do this by checking if the devicetree node has status "okay":

    #define I2C0_NODE DT_NODELABEL(i2c0)

    #if DT_NODE_HAS_STATUS(I2C0_NODE, okay)

    #define I2C0 DT_LABEL(I2C0_NODE)

    For transferring bytes, I believe the function you are looking for in the I2C API is i2c_write, not i2c_burst_write.

    Best regards,

    Einar

Children
No Data
Related