NRF52832 appears to lock up on weak NFC signal

This one is throwing me for a loop. We have a very basic NFC component in our firmware that serves up a static NDEF file and wakes the MCU from a system_off state.55045.prj.conf

We have been occasionally encountering an issue where NFC doesn't seem to work and won't work again until the board is reset. After spending more time debugging and attempting to reproduce the issue, it seems that a lockup of some kind occurs when "weak" NFC activity takes place. For example, moving the reader around too far from the device to properly read it. It works reliably if you put the phone NFC reader close to the NFC antenna and read it normally, but if you're off target or too far away, it won't read and won't function otherwise (including any NFC read attempts) until a reset. There are no log messages indicating any activity when this happens, nor are there any hard faults/resets. It simply appears to stop until reset by the reset pin or a POR.

The closest thing we got to a log response is the following snippet, but we only saw this once. Every other time we reproduced it there were no log messages.

[00:00:04.400,695] <dbg> nfc_platform: nfc_platform_event_handler: Field detected
[00:00:04.401,519] <inf> NRFX_NFCT: Reinitialize
[00:00:04.401,519] <dbg> nfc_platform: nfc_platform_event_handler: Field lost
[00:00:04.401,580] <inf> NFC: Field OFF
[00:00:04.941,619] <dbg> nfc_platform: nfc_platform_event_handler: Field detected
[00:00:04.942,535] <inf> NRFX_NFCT: Reinitialize
[00:00:04.942,565] <dbg> nfc_platform: nfc_platform_event_handler: Field lost
[00:00:04.942,626] <inf> NFC: Field OFF
[00:00:04.947,479] <dbg> nfc_platform: nfc_platform_event_handler: Field detected
[00:00:04.965,698] <inf> NRFX_NFCT: Reinitialize
[00:00:04.965,728] <dbg> nfc_platform: nfc_platform_event_handler: Field lost
[00:00:04.965,789] <inf> NFC: Field OFF
[00:00:04.970,642] <dbg> nfc_platform: nfc_platform_event_handler: Field detected
[00:00:05.002,655] <inf> NRFX_NFCT: Reinitialize
[00:00:05.002,655] <dbg> nfc_platform: nfc_platform_event_handler: Field lost
[00:00:05.002,716] <inf> NFC: Field OFF

We're using SDK 2.6.0. nfc code file is attached as well as configs. Thank you!

/************************************************************************//**
 *
 * \file ssum_nfc.c
 *
 * \addtogroup ssum_nfc ssum_nfc
 * \{
 *
 * \brief
 *
 * \note
 *
 * \author dylanjackson (Geocene, Inc)
 * \date 2024-03-19
 *
 ****************************************************************************/

/****************************************************************************
 *                              INCLUDE FILES                               *
 ****************************************************************************/

#include <stdio.h>
#include <string.h>
#include <nfc/ndef/msg.h>
#include <nfc_t4t_lib.h>
#include <nfc/t4t/ndef_file.h>
#include <nfc/ndef/uri_msg.h>
#include <zephyr/drivers/gpio.h>
#include <hal/nrf_gpio.h>

#include "ssum_nfc.h"
#include "ssum_nvs.h"
#include "ssum_ble_man.h"
#include "mission_ctrl.h"

#include <zephyr/logging/log.h>

/****************************************************************************
 *                      PRIVATE TYPES and DEFINITIONS                       *
 ****************************************************************************/

#define SERIAL_HEX_CHARS	6 // 3 bytes -> 6 hex characters
#define SUDO_BUTTON_NODE	DT_ALIAS(sudobutton)

#if !DT_NODE_HAS_STATUS(SUDO_BUTTON_NODE, okay)
#define DEV_BOARD
#endif

/****************************************************************************
 *                              PRIVATE DATA                                *
 ****************************************************************************/

static const uint8_t m_base_url[] = 
    {'g', 'e', 'o', 'c', 'e', 'n', 'e', ':', '/', '/','S','S','U','M','-'};
static uint8_t ndef_msg_buf[CONFIG_NDEF_FILE_SIZE]; /**< Buffer for NDEF file. */
#ifndef DEV_BOARD
static const struct gpio_dt_spec sudo_button = GPIO_DT_SPEC_GET_OR(SUDO_BUTTON_NODE, gpios, {0});
static struct gpio_callback sudo_button_cb_data;
#endif

/****************************************************************************
 *                     PRIVATE FUNCTION DECLARATIONS                        *
 ****************************************************************************/

static void nfc_callback(void *context, nfc_t4t_event_t event, 
    const uint8_t *data, size_t data_length, uint32_t flags);
#ifndef DEV_BOARD
static void sudo_button_cb(const struct device *dev, struct gpio_callback *cb, uint32_t pins);
#endif
static int ndef_file_init(uint8_t *buff, uint32_t *size);

/****************************************************************************
 *                          STATIC DECLARATIONS                             *
 ****************************************************************************/

LOG_MODULE_REGISTER(NFC, LOG_LEVEL_DBG);

/****************************************************************************
 *                     EXPORTED FUNCTION DEFINITIONS                        *
 ****************************************************************************/

int ssum_nfc_init(void)
{
    /* Set up NFC */
    int err = nfc_t4t_setup(nfc_callback, NULL);

    if (err < 0)
    {
        LOG_ERR("Cannot setup t4t library!");
    }

    /* Load NDEF message from the flash file. */
    uint32_t size = 0;
    if (ndef_file_init(ndef_msg_buf, &size) < 0)
    {
        LOG_ERR("Cannot init NDEF file!");
    }

    /* Run Read-Write mode for Type 4 Tag platform */
    if (nfc_t4t_ndef_staticpayload_set(ndef_msg_buf, sizeof(ndef_msg_buf)) < 0)
    {
        LOG_ERR("Cannot set payload!");
    }

#ifndef DEV_BOARD
    /* Set up sudo button */
    if (!gpio_is_ready_dt(&sudo_button))
    {
		LOG_ERR("Error: %s is not ready\n", sudo_button.port->name);
	}
    else
    {
        gpio_pin_configure_dt(&sudo_button, GPIO_INPUT);
        gpio_pin_interrupt_configure_dt(&sudo_button, GPIO_INT_EDGE_TO_ACTIVE);
        gpio_init_callback(&sudo_button_cb_data, sudo_button_cb, BIT(sudo_button.pin));
	    gpio_add_callback(sudo_button.port, &sudo_button_cb_data);
    }
#endif

    /* Start sensing NFC field */
    if (nfc_t4t_emulation_start() < 0)
    {
        LOG_ERR("Cannot start emulation!");
    }

    return err;
}

/****************************************************************************
 *                     PRIVATE FUNCTION DEFINITIONS                         *
 ****************************************************************************/

static void nfc_callback(void *context, nfc_t4t_event_t event, 
    const uint8_t *data, size_t data_length, uint32_t flags)
{
    ARG_UNUSED(context);
    ARG_UNUSED(data);
    ARG_UNUSED(data_length);

    switch (event) {
    case NFC_T4T_EVENT_FIELD_ON:
        LOG_INF("Field ON");
        break;
    case NFC_T4T_EVENT_FIELD_OFF:
        LOG_INF("Field OFF");
        break;
    case NFC_T4T_EVENT_NDEF_READ:
        LOG_INF("NDEF Read");
        if (mission_ctrl_get_state() != MISSION_SHIP_STATE)
        {
            mission_ctrl_sudo_boop_detected();
        }
        break;
    default:
        break;
    }
}

#ifndef DEV_BOARD
static void sudo_button_cb(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
    if (mission_ctrl_get_state() != MISSION_SHIP_STATE && pins & BIT(sudo_button.pin))
    {
        mission_ctrl_sudo_boop_detected();
    }
}
#endif

static int ndef_file_init(uint8_t *buff, uint32_t *size)
{
    int err;
    uint8_t url_size = sizeof(m_base_url);
    char msg[url_size + SERIAL_HEX_CHARS + 1]; // add a space for null-term
    memcpy(msg, m_base_url, url_size);

    // Read the device serial
    uint64_t id = ssum_nvs_get_device_id();
    // Tack only the last 3 bytes (6 hex chars) onto the end of the NFC message
    sprintf(&msg[url_size], "%06X", (uint32_t)(id & 0x00FFFFFF));
    LOG_INF("NFC msg: '%s'", msg);
    uint32_t ndef_size = nfc_t4t_ndef_file_msg_size_get(*size);
    err = nfc_ndef_uri_msg_encode(NFC_URI_NONE,
                    msg, sizeof(msg) - 1, // don't pass in null term as it messes with the NFC read on the app
                    nfc_t4t_ndef_file_msg_get(buff), &ndef_size);

    if (err < 0) {
        LOG_ERR("Cannot encode URI!");
    }
                    
    err = nfc_t4t_ndef_file_encode(buff, &ndef_size);

    *size = ndef_size;

    if (err < 0) {
        LOG_ERR("Cannot encode file!");
    }

    return err;
}

/************************************************************************//**
 * \brief
 * \param
 * \return
 ****************************************************************************/

/** \}*/

debug.conf

Parents
  • Hi there,

    Have you tried halting the CPU when it stops to see where it's stuck?

    When it stops, and you move the reader close to the device again, what is the status of the FIELDPRESENT register?

    regards

    Jared 

    Note that we are short on staff due to the summer vacation, so expect some delay in the handling of this case.

  • I feel like I've seen the CPU in a couple of different places, but reproducing it today it seems to usually be here:


    (specifically it seems to only happen if an NFC read does not complete, but a field is detected). After stopping and starting again in the debugger it hardfaults in the MSPL assert handler, but that only happens when I pause using the debugger and then run again or step through the code from this stopping point. Outside of the debugger I can just leave it and it will sit there until I reset it or power cycle.

    I have tried putting the phone close to the antenna after producing this condition but before pausing the debugger, and the FIELDPRESENT bit appears to still be 0.

    Also, I can confirm that those log prints I originally posted do not always precede this condition. Sometimes there are no messages at all.

    Thanks for the heads up about possible delays. I appreciate the assistance!

  • Hi,

    Thanks for the elaboration. Are you running this on a devkit? Would it be possible for you to provide a small sample that would reproduce the issue? That would make it much easier for us to investigate it,

    underpickled said:
    After stopping and starting again in the debugger it hardfaults in the MSPL assert handler, but that only happens when I pause using the debugger and then run again or step through the code from this stopping point.

    This is expected, as the Softdevice controller will automatically assert if the CPU is halted due to real time requirements not being met,

    regards

    Jared 

  • I'm not on a dev kit, but I bet I could build a stripped down sample that would run on one. Might not have it ready until next week due to the holiday this week, but I'll send something over when I do. Thank you!

Reply Children
Related