I am developing a project using the nRF54L15 DK to interface with an ST25DV64KC NFC tag (specifically the Class 3 or Class 6 daughterboard from the ST25DV64KC-DISCO kit). My goal is to initialize the ST25DV64KC tag via I2C, write a Capability Container (CC) file at address 0x0000, an NDEF text record at 0x0004, and a binary status report at 0x0100 to support commands.
The project is built using the nRF Connect SDK v3.0.1.
I have configured the device tree overlay to use I2C21 with pins P2.09 (SDA), P2.10 (SCL), and P2.06 (GPO interrupt), powered at 1.8V (matching the DK’s VDDIO). However, the ST25DV64KC is not being detected at the default I2C address 0x53, with UART logs showing "ST25DV not found at I2C address 0x53, error: -5" (EIO) despite multiple retries. I have attempted to use internal pull-ups on the I2C lines and extended delays for stabilization, but the issue persists.
I have verified the wiring (SDA to P2.09, SCL to P2.10, GPO to P2.06, GND and E0–E2 to ground) and power (1.8V on Vcc), but communication still fails. The scan_i2c_bus function in my code tests addresses 0x50–0x57 without success.
I would appreciate guidance on:
- Confirming the SDA/SCL pin assignments when used with the nRF54L15 DK.
- Do I need external pull-up resistors.
- Any additional hardware or software configuration steps specific to the nRF54L15 DK and ST25DV64KC integration.
- Debugging steps to isolate the I2C failure further.
Attached are my device tree overlay (nrf54l15dk_nrf54l15_cpuapp.overlay), main.c file. Please let me know if additional information or logs are needed. Below is the serial monitor log I'm seeing when scanning for an I2C device.
0218.nrf54l15dk_nrf54l15_cpuapp.overlay
#include <zephyr/kernel.h> #include <zephyr/logging/log.h> #include <zephyr/drivers/i2c.h> #include <zephyr/drivers/gpio.h> #include <stdio.h> #include "st25dv.h" #include "st25dv_nfctag.h" #include "encode_status.h" #include "commands.h" #include <lib_NDEF_Text.h> #include "lib_wrapper.h" LOG_MODULE_REGISTER(nfc_status, LOG_LEVEL_INF); #define NFC_MEMORY_STATUS_ADDR 0x0100 // Binary status report address #define NFC_NDEF_ADDR 0x0004 // NDEF text record address (after CC) #define ST25DV_I2C_ADDR 0x53 // Default ST25DV I2C address #define I2C_DEV DT_NODELABEL(i2c22) // I2C21 device #define INIT_RETRIES 3 // Retry initialization #define GPIO_PORT DT_NODELABEL(gpio2) // GPIO2 for P2.09, P2.10 static const struct device *i2c_dev = DEVICE_DT_GET(I2C_DEV); static const struct device *gpio_dev = DEVICE_DT_GET(GPIO_PORT); int configure_i2c_pins(void) { if (!device_is_ready(gpio_dev)) { LOG_ERR("GPIO device %s not ready", gpio_dev->name); return -ENODEV; } // Configure P2.09 (SDA) and P2.10 (SCL) with strong internal pull-ups int ret = gpio_pin_configure(gpio_dev, 9, GPIO_INPUT | GPIO_PULL_UP); if (ret != 0) { LOG_ERR("Failed to configure P2.09 (SDA) pull-up, error: %d", ret); return ret; } ret = gpio_pin_configure(gpio_dev, 10, GPIO_INPUT | GPIO_PULL_UP); if (ret != 0) { LOG_ERR("Failed to configure P2.10 (SCL) pull-up, error: %d", ret); return ret; } LOG_INF("Internal pull-ups enabled on P2.09 and P2.10"); k_sleep(K_MSEC(50)); // Stabilize pull-up state return 0; } int scan_i2c_bus(void) { if (!device_is_ready(i2c_dev)) { LOG_ERR("I2C device %s not ready", i2c_dev->name); return -ENODEV; } LOG_INF("Scanning I2C bus for ST25DV addresses (0x50–0x65)..."); uint8_t dummy[1] = {0}; bool found = false; for (uint8_t addr = 0x53; addr <= 0x65; addr++) { k_sleep(K_MSEC(20)); // Increased delay for stability int ret = i2c_write(i2c_dev, dummy, 1, addr); if (ret == 0) { LOG_INF("Device found at I2C address 0x%02x", addr); found = true; if (addr == ST25DV_I2C_ADDR) { LOG_INF("ST25DV confirmed at 0x64"); return 0; } } else { LOG_DBG("No response at address 0x%02x, error: %d (0x%x)", addr, ret, ret); } } if (!found) { LOG_ERR("No I2C devices found in range 0x50–0x64"); } return -EIO; } int reset_tag(void) { LOG_INF("Attempting to reset ST25DV tag with extended delay"); k_sleep(K_SECONDS(1)); // Extended delay to simulate power cycle return 0; } int write_cc_file(void) { uint8_t cc_file[] = {0xE8, 0x40, 0x80, 0x01}; NFCTAG_StatusTypeDef ret = BSP_NFCTAG_WriteData(cc_file, 0x0000, sizeof(cc_file)); if (ret != NFCTAG_OK) { LOG_ERR("Failed to write CC file at 0x0000, error: %d", ret); return -EIO; } LOG_INF("CC file written to 0x0000: %02x %02x %02x %02x", cc_file[0], cc_file[1], cc_file[2], cc_file[3]); uint8_t read_buf[4]; if (BSP_NFCTAG_ReadData(read_buf, 0x0000, sizeof(read_buf)) != NFCTAG_OK) { LOG_ERR("Failed to read back CC file"); return -EIO; } if (memcmp(read_buf, cc_file, sizeof(cc_file)) != 0) { LOG_ERR("CC file verification failed: %02x %02x %02x %02x", read_buf[0], read_buf[1], read_buf[2], read_buf[3]); return -EIO; } LOG_INF("CC file verified successfully"); return 0; } int write_status_report(void) { struct status_v1 status = { .sid = {0xb0, 0x11, 0xf8, 0xc9, 0x1e, 0x8e, 0x4e, 0x46, 0xa5, 0xf0, 0x85, 0xcc, 0x39, 0xd8, 0xb4, 0x25}, .state = STATE_ACTIVE, .firmware = {0x01, 0x02, 0x00}, .boot = 0x01, .batt = 3600, .report_counts = { .primary = 1, .secondary = 2, .tertiary = 3 } }; uint8_t buffer[MIN_STATUS_LEN]; size_t len = encode_status_v1(&status, buffer, sizeof(buffer)); if (len == 0) { LOG_ERR("Failed to encode binary status report"); return -EINVAL; } NFCTAG_StatusTypeDef ret = BSP_NFCTAG_WriteData(buffer, NFC_MEMORY_STATUS_ADDR, len); if (ret != NFCTAG_OK) { LOG_ERR("Failed to write binary status report at 0x%04x, error: %d", NFC_MEMORY_STATUS_ADDR, ret); return -EIO; } LOG_INF("Binary status report written at 0x%04x, %d bytes", NFC_MEMORY_STATUS_ADDR, len); char status_text[80]; snprintf(status_text, sizeof(status_text), "SID: %02x%02x, State: %d, FW: %d.%d.%d, Batt: %d mV, R: %d,%d,%d", status.sid[0], status.sid[1], status.state, status.firmware[0], status.firmware[1], status.firmware[2], status.batt, status.report_counts.primary, status.report_counts.secondary, status.report_counts.tertiary); uint16_t ndef_len = NDEF_WriteText(status_text); if (ndef_len == 0) { LOG_ERR("Failed to create NDEF text record"); return -EINVAL; } if (ndef_len > NDEF_MAX_SIZE) { LOG_ERR("NDEF record too large: %d bytes, max %d", ndef_len, NDEF_MAX_SIZE); return -EINVAL; } uint16_t write_ret = NfcTag_WriteNDEF(ndef_len, NDEF_Buffer); if (write_ret != NDEF_OK) { LOG_ERR("NfcTag_WriteNDEF failed, error: %d", write_ret); return -EIO; } LOG_INF("NDEF text record written: %s (%d bytes)", status_text, ndef_len); return 0; } static int build_full_payload(void) { LOG_INF("COMMAND_SEND_REPORT (0x08) received - Building full payload"); return 0; } void main(void) { if (configure_i2c_pins() != 0) { LOG_ERR("Failed to configure I2C pins, halting"); return; } for (int i = 0; i < INIT_RETRIES; i++) { if (scan_i2c_bus() == 0) { break; } LOG_WRN("I2C scan failed, retry %d/%d", i + 1, INIT_RETRIES); reset_tag(); } if (!device_is_ready(i2c_dev)) { LOG_ERR("I2C check failed after retries, halting"); return; } if (BSP_NFCTAG_IsDeviceReady(3) != NFCTAG_OK) { LOG_ERR("ST25DV tag not ready"); return; } LOG_INF("ST25DV tag is ready"); if (BSP_NFCTAG_Init() != NFCTAG_OK) { LOG_ERR("Failed to initialize ST25DV NFC tag"); return; } LOG_INF("ST25DV NFC tag initialized successfully"); k_sleep(K_MSEC(100)); if (write_cc_file() != 0) { LOG_ERR("Failed to write CC file"); return; } if (write_status_report() != 0) { LOG_ERR("Failed to write status report"); return; } while (1) { k_sleep(K_SECONDS(5)); LOG_INF("Simulating COMMAND_SEND_REPORT trigger"); if (build_full_payload() != 0) { LOG_ERR("Failed to build full payload"); } } }
[00:00:09.419,199] <dbg> os: z_tick_sleep: thread 0x20000a98 for 625 ticks
[00:00:09.939,358] <err> nfc_status: No I2C devices found in range 0x50–0x64
[00:00:09.939,374] <wrn> nfc_status: I2C scan failed, retry 1/3
[00:00:09.939,378] <inf> nfc_status: Attempting to reset ST25DV tag with extendy
[00:00:09.939,387] <dbg> os: z_tick_sleep: thread 0x20000a98 for 31250 ticks
[00:00:10.939,450] <inf> nfc_status: Scanning I2C bus for ST25DV addresses (0x5.
[00:00:10.939,459] <dbg> os: z_tick_sleep: thread 0x20000a98 for 625 ticks
[00:00:18.741,859] <dbg> os: z_tick_sleep: thread 0x20000a98 for 625 ticks
[00:00:19.262,015] <dbg> os: z_tick_sleep: thread 0x20000a98 for 625 ticks
[00:00:19.782,179] <dbg> os: z_tick_sleep: thread 0x20000a98 for 625 ticks
[00:00:20.302,335] <dbg> os: z_tick_sleep: thread 0x20000a98 for 625 ticks
[00:00:20.822,494] <err> nfc_status: No I2C devices found in range 0x50–0x64
[00:00:20.822,510] <wrn> nfc_status: I2C scan failed, retry 2/3
[00:00:20.822,514] <inf> nfc_status: Attempting to reset ST25DV tag with extendy
[00:00:20.822,523] <dbg> os: z_tick_sleep: thread 0x20000a98 for 31250 ticks
[00:00:21.822,586] <inf> nfc_status: Scanning I2C bus for ST25DV addresses (0x5.
[00:00:21.822,595] <dbg> os: z_tick_sleep: thread 0x20000a98 for 625 ticks
[00:00:22.342,756] <dbg> os: z_tick_sleep: thread 0x20000a98 for 625 ticks
[00:00:22.862,910] <dbg> os: z_tick_sleep: thread 0x20000a98 for 625 ticks
[00:00:23.383,075] <dbg> os: z_tick_sleep: thread 0x20000a98 for 625 ticks