Issue Using NFC Pins (P0.02/P0.03) as I2C Slave on nRF5340

Hello Nordic Support Team,

I’m working with an nRF5340 using nRF Connect SDK 3.0.2.

I am trying to use the NFC pins (P0.02 and P0.03) as an I2C slave interface. However, when I use these pins, the I2C master never receives a valid NACK from my slave device. If I change to other pins, the communication works correctly.

My I2C TWIS driver source code, .conf file, and .overlay file are attached to this ticket.

How can I resolve this issue? My current hardware is routed to use the NFC pins.

Thanks in advance.

Best regards.

3324.app.conf

5481.appl.overlay

/**
 * @file i2cDrv.c
 * @author Luis Maciel ([email protected])
 * @brief
 * @version x.x.x
 * @date 2025-02-13
 *
 * @copyright Copyright LogPyx S/A (c) 2025
 *
 * 	 _
 *	| |    ___   __ _ _ __  _   ___  __
 *	| |   / _ \ / _` | '_ \| | | \ \/ /
 *	| |__| (_) | (_| | |_) | |_| |>  <
 *	|_____\___/ \__, | .__/ \__, /_/\_\
 *                |__|_|    |___/
 *
 *              Logpyx S/A
 */

#include <zephyr/kernel.h>
#include <zephyr/types.h>
#include <zephyr/device.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/logging/log.h>
#include <zephyr/devicetree/pinctrl.h>

#include <nrfx_twis.h>

#include "i2cDrv.h"

LOG_MODULE_REGISTER(i2cDrv, LOG_LEVEL_INF);

#define I2C_SLAVE 1

#if I2C_SLAVE
#define TWI_INSTANCE_ID 2
#define I2C2_NODE DT_NODELABEL(i2c2)
#define I2C2_ADDRESS 0x11

static const nrfx_twis_t s_twi = NRFX_TWIS_INSTANCE(TWI_INSTANCE_ID);

static i2cIrqHandler rxDone;

static void twis_event_handler(nrfx_twis_evt_t const *const p_event);
#else
static const struct i2c_dt_spec dev_i2c; // = I2C_DT_SPEC_GET(DT_ALIAS(myesp));
#endif

uint8_t rx_buf[TWI_RX_BUF_LEN];

void i2cDrvIn(uint8_t *txBuffer, uint16_t size)
{
#if I2C_SLAVE
    nrfx_twis_tx_prepare(&s_twi, txBuffer, size);
#else
    i2c_write_dt(&dev_i2c, txBuffer, size);
#endif
}

void i2cDrvInOut(uint8_t *txBuffer, uint16_t txSize, uint8_t *rxBuffer, uint16_t rxSize)
{
#if !I2C_SLAVE
    i2c_write_read_dt(&dev_i2c, txBuffer, txSize, rxBuffer, rxSize);
#endif
}

void i2cDrvOut(uint8_t *rxBuffer, uint16_t size)
{
    ARG_UNUSED(rxBuffer);
    ARG_UNUSED(size);
}

bool i2cDrvIsWaiting4Tx(void)
{
#if I2C_SLAVE
    return nrfx_twis_is_waiting_tx_buff(&s_twi);
#endif
    return false;
}

void i2cDrvInit(i2cIrqHandler cb)
{
#if I2C_SLAVE
    IRQ_CONNECT(DT_IRQN(I2C2_NODE),
                DT_IRQ(I2C2_NODE, priority),
                nrfx_isr,
                nrfx_twis_2_irq_handler,
                0);

    nrfx_twis_config_t twis_config = NRFX_TWIS_DEFAULT_CONFIG(30, 3, I2C2_ADDRESS);
    nrfx_twis_init(&s_twi, &twis_config, twis_event_handler);
    nrfx_twis_enable(&s_twi);
    rxDone = cb;
#else
    while (!i2c_is_ready_dt(&dev_i2c))
    {
        k_msleep(1);
    }
#endif
}

#if I2C_SLAVE

static void twis_event_handler(nrfx_twis_evt_t const *const p_event)
{
    switch (p_event->type)
    {
    case NRFX_TWIS_EVT_READ_REQ:
        if (p_event->data.buf_req)
        {
            // Sending default message
            static uint8_t default_msg[] = {0x01, 0x02, 0x03};
            nrfx_twis_tx_prepare(&s_twi, default_msg, sizeof(default_msg));
            // LOG_INF("Send default value to master");
        }
        break;

    case NRFX_TWIS_EVT_READ_DONE:
        // LOG_INF("Master terminou leitura.");
        break;

    case NRFX_TWIS_EVT_WRITE_REQ:
        if (p_event->data.buf_req)
        {
            // preparar buffer para receber
            // LOG_INF("Request to receive bytes from master", TWI_RX_BUF_LEN);
            nrfx_twis_rx_prepare(&s_twi, rx_buf, TWI_RX_BUF_LEN);
        }
        break;

    case NRFX_TWIS_EVT_WRITE_DONE:
    {
        // terminou de receber dados do master
        // LOG_INF("I2C Slave recebeu %d bytes:", p_event->data.rx_amount);
        // LOG_HEXDUMP_INF(rx_buf, p_event->data.rx_amount, "RX DATA");
        if (rxDone)
        {
            rxDone(rx_buf, p_event->data.rx_amount);
        }
        break;
    }

    case NRFX_TWIS_EVT_READ_ERROR:
    case NRFX_TWIS_EVT_WRITE_ERROR:
    case NRFX_TWIS_EVT_GENERAL_ERROR:
        break;

    default:
        break;
    }
}
#endif

  • Thank you for your response, Vidar.

    Yes, I can confirm that I'm able to successfully toggle the pins between high and low states using the debug code I developed.

    I can also verify that the signals are transmitting correctly. When using the same I2C bus with another slave device (my other custom board that uses P0.30 for SCL), the communication works properly.

  • During testing, I observed the following:

    1. Successful Configuration: The nRF5340 operates correctly as an I2C master when using P0.03 for SDA and P0.02 for SCL on my new board design.

    2. Failed Configuration: On an older board, a previously working configuration (SDA on P0.03, SCL on P0.30) fails when the pins are swapped in the device tree:

      • Working: psels = <NRF_PSEL(TWIS_SDA, 0, 3)>, <NRF_PSEL(TWIS_SCL, 0, 30)>

      • Failing: psels = <NRF_PSEL(TWIS_SDA, 0, 30)>, <NRF_PSEL(TWIS_SCL, 0, 3)>

    The issue suggests a problem on I2C slave driver.

  • So you were able to use the NFC pins now after you switched to new board, or is it still the same board? If you suspect the driver, you may consider reading out the TWIS PSEL registers and GPIO CFG registers to confirm the pins are configured correctly and according to the product specification. You can also add logging for the TWIS error events in the TWIS callback.

Related