hal_nordic/nrfx/drivers/src/nrfx_nfct.c

962 lines
32 KiB
C

/*
* Copyright (c) 2018 - 2022, Nordic Semiconductor ASA
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <nrfx.h>
#if NRFX_CHECK(NRFX_NFCT_ENABLED)
#include <nrfx_nfct.h>
#define NRFX_LOG_MODULE NFCT
#include <nrfx_log.h>
#if !defined(USE_WORKAROUND_FOR_ANOMALY_79) && \
(defined(NRF52832_XXAA) || defined(NRF52832_XXAB))
#define USE_WORKAROUND_FOR_ANOMALY_79 1
#endif
#if !defined(USE_WORKAROUND_FOR_ANOMALY_190) && \
(defined(NRF52833_XXAA) || defined(NRF52840_XXAA) || \
defined(NRF5340_XXAA_APPLICATION))
#define USE_WORKAROUND_FOR_ANOMALY_190 1
#endif
#if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_79) || NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_190)
#define NFCT_WORKAROUND_USES_TIMER 1
#endif
#if NRFX_CHECK(NFCT_WORKAROUND_USES_TIMER)
#include <nrfx_timer.h>
typedef struct
{
const nrfx_timer_t timer; /**< Timer instance that supports the correct NFC field detection. */
#if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_190)
bool fieldevents_filter_active; /**< Flag that indicates that the field events are ignored. */
bool is_hfclk_on; /**< HFCLK has started - one of the NFC activation conditions. */
bool is_delayed; /**< Required time delay has passed - one of the NFC activation conditions. */
#elif NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_79)
uint32_t field_state_cnt; /**< Counter of the FIELDLOST events. */
#endif // NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_190)
} nrfx_nfct_timer_workaround_t;
#if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_190)
#define NRFX_NFCT_ACTIVATE_DELAY 1000 /**< Minimal delay in us between NFC field detection and activation of NFCT. */
#define NRFX_NFCT_TIMER_PERIOD NRFX_NFCT_ACTIVATE_DELAY
#elif NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_79)
#define NRFX_NFCT_FIELDLOST_THR 7
#define NRFX_NFCT_FIELD_TIMER_PERIOD 100 /**< Field polling period in us. */
#define NRFX_NFCT_TIMER_PERIOD NRFX_NFCT_FIELD_TIMER_PERIOD
#endif // NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_190)
static nrfx_nfct_timer_workaround_t m_timer_workaround =
{
.timer = NRFX_TIMER_INSTANCE(NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID),
};
#endif // NRFX_CHECK(NFCT_WORKAROUND_USES_TIMER)
#define NFCT_FRAMEDELAYMAX_DEFAULT (0x00001000UL) /**< Default value of the FRAMEDELAYMAX. */
#define NFCT_FRAMEDELAYMIN_DEFAULT (0x00000480UL) /**< Default value of the FRAMEDELAYMIN. */
/* Mask of all possible interrupts that are relevant for data reception. */
#define NRFX_NFCT_RX_INT_MASK (NRF_NFCT_INT_RXFRAMESTART_MASK | \
NRF_NFCT_INT_RXFRAMEEND_MASK | \
NRF_NFCT_INT_RXERROR_MASK)
/* Mask of all possible interrupts that are relevant for data transmission. */
#define NRFX_NFCT_TX_INT_MASK (NRF_NFCT_INT_TXFRAMESTART_MASK | \
NRF_NFCT_INT_TXFRAMEEND_MASK)
/* Mask of all possible errors from the @ref NRF_NFCT_EVENT_RXERROR event. */
#define NRFX_NFCT_FRAME_STATUS_RX_ALL_MASK (NRF_NFCT_RX_FRAME_STATUS_CRC_MASK | \
NRF_NFCT_RX_FRAME_STATUS_PARITY_MASK | \
NRF_NFCT_RX_FRAME_STATUS_OVERRUN_MASK)
/* Mask of all possible errors from the @ref NRF_NFCT_EVENT_ERROR event. */
#if defined (NRF52832_XXAA) || defined(NRF52832_XXAB)
#define NRFX_NFCT_ERROR_STATUS_ALL_MASK (NRF_NFCT_ERROR_FRAMEDELAYTIMEOUT_MASK | \
NRF_NFCT_ERROR_NFCFIELDTOOSTRONG_MASK | \
NRF_NFCT_ERROR_NFCFIELDTOOWEAK_MASK)
#else
#define NRFX_NFCT_ERROR_STATUS_ALL_MASK (NRF_NFCT_ERROR_FRAMEDELAYTIMEOUT_MASK)
#endif
/* Macros for conversion of bits to bytes. */
#define NRFX_NFCT_BYTES_TO_BITS(_bytes) ((_bytes) << 3)
#define NRFX_NFCT_BITS_TO_BYTES(_bits) ((_bits) >> 3)
/* Macro for checking whether the NFCT interrupt is active. */
#define NRFX_NFCT_EVT_ACTIVE(_name) \
(nrf_nfct_event_check(NRF_NFCT, NRFX_CONCAT_2(NRF_NFCT_EVENT_, _name)) && \
nrf_nfct_int_enable_check(NRF_NFCT, NRFX_CONCAT_3(NRF_NFCT_INT_, _name, _MASK)))
/* Macro for callback execution. */
#define NRFX_NFCT_CB_HANDLE(_cb, _evt) \
if (_cb != NULL) \
{ \
_cb(&_evt); \
}
typedef enum
{
NRFX_NFC_FIELD_STATE_NONE, /**< Initial value that indicates no NFCT field events. */
NRFX_NFC_FIELD_STATE_OFF, /**< The NFCT FIELDLOST event has been set. */
NRFX_NFC_FIELD_STATE_ON, /**< The NFCT FIELDDETECTED event has been set. */
NRFX_NFC_FIELD_STATE_UNKNOWN /**< Both NFCT field events have been set - ambiguous state. */
} nrfx_nfct_field_state_t;
/** @brief NFCT control block. */
typedef struct
{
nrfx_nfct_config_t config;
nrfx_drv_state_t state;
volatile bool field_on;
uint32_t frame_delay_max;
uint32_t frame_delay_min;
} nrfx_nfct_control_block_t;
static nrfx_nfct_control_block_t m_nfct_cb;
/**
* @brief Common part of the setup used for the NFCT initialization and reinitialization.
*/
static void nrfx_nfct_hw_init_setup(void)
{
// Use Window Grid frame delay mode.
nrf_nfct_frame_delay_mode_set(NRF_NFCT, NRF_NFCT_FRAME_DELAY_MODE_WINDOWGRID);
/* Begin: Workaround for anomaly 25 */
/* Workaround for wrong SENSRES values require using SDD00001, but here SDD00100 is used
because it is required to operate with Windows Phone */
nrf_nfct_sensres_bit_frame_sdd_set(NRF_NFCT, NRF_NFCT_SENSRES_BIT_FRAME_SDD_00100);
/* End: Workaround for anomaly 25 */
}
static void nrfx_nfct_frame_delay_max_set(bool default_delay)
{
if (default_delay)
{
nrf_nfct_frame_delay_max_set(NRF_NFCT, NFCT_FRAMEDELAYMAX_DEFAULT);
}
else
{
nrf_nfct_frame_delay_max_set(NRF_NFCT, m_nfct_cb.frame_delay_max);
}
}
/** @brief Function for evaluating and handling the NFC field events.
*
* @param[in] field_state Current field state.
*/
static void nrfx_nfct_field_event_handler(volatile nrfx_nfct_field_state_t field_state)
{
nrfx_nfct_evt_t nfct_evt;
#if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_190)
if(m_timer_workaround.fieldevents_filter_active)
{
return;
}
#endif // NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_190)
if (field_state == NRFX_NFC_FIELD_STATE_UNKNOWN)
{
/* Probe NFC field */
field_state = (nrfx_nfct_field_check()) ? NRFX_NFC_FIELD_STATE_ON :
NRFX_NFC_FIELD_STATE_OFF;
}
/* Field event service. Only take action on field transition -
* based on the value of m_nfct_cb.field_on
*/
switch (field_state)
{
case NRFX_NFC_FIELD_STATE_ON:
if (!m_nfct_cb.field_on)
{
#if NRFX_CHECK(NFCT_WORKAROUND_USES_TIMER)
#if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_190)
m_timer_workaround.is_hfclk_on = false;
m_timer_workaround.is_delayed = false;
m_timer_workaround.fieldevents_filter_active = true;
nrfx_timer_clear(&m_timer_workaround.timer);
nrfx_timer_enable(&m_timer_workaround.timer);
#elif NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_79)
nrfx_timer_clear(&m_timer_workaround.timer);
nrfx_timer_enable(&m_timer_workaround.timer);
m_timer_workaround.field_state_cnt = 0;
#endif // NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_190)
#endif // NRFX_CHECK(NFCT_WORKAROUND_USES_TIMER)
m_nfct_cb.field_on = true;
nfct_evt.evt_id = NRFX_NFCT_EVT_FIELD_DETECTED;
NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt);
}
break;
case NRFX_NFC_FIELD_STATE_OFF:
if (m_nfct_cb.field_on)
{
nrf_nfct_task_trigger(NRF_NFCT, NRF_NFCT_TASK_SENSE);
nrf_nfct_int_disable(NRF_NFCT, NRFX_NFCT_RX_INT_MASK | NRFX_NFCT_TX_INT_MASK);
m_nfct_cb.field_on = false;
nfct_evt.evt_id = NRFX_NFCT_EVT_FIELD_LOST;
/* Begin: Workaround for anomaly 218 */
nrfx_nfct_frame_delay_max_set(true);
/* End: Workaround for anomaly 218 */
NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt);
}
break;
default:
/* No implementation required */
break;
}
}
#if NRFX_CHECK(NFCT_WORKAROUND_USES_TIMER)
#if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_190)
static void nrfx_nfct_activate_check(void)
{
static bool is_field_validation_pending = false;
if (is_field_validation_pending)
{
is_field_validation_pending = false;
m_timer_workaround.fieldevents_filter_active = false;
// Check the field status and take action if field is lost.
nrfx_nfct_field_event_handler(NRFX_NFC_FIELD_STATE_UNKNOWN);
return;
}
if ((m_timer_workaround.is_hfclk_on) && (m_timer_workaround.is_delayed))
{
nrf_nfct_task_trigger(NRF_NFCT, NRF_NFCT_TASK_ACTIVATE);
is_field_validation_pending = true;
// Start the timer second time to validate whether the tag has locked to the field.
nrfx_timer_clear(&m_timer_workaround.timer);
nrfx_timer_enable(&m_timer_workaround.timer);
}
}
#endif // NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_190)
#if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_79)
/* Begin: Workaround for anomaly 116 */
static inline void nrfx_nfct_reset(void)
{
uint32_t fdmax;
uint32_t fdmin;
uint32_t int_enabled;
uint8_t nfcid1[NRF_NFCT_SENSRES_NFCID1_SIZE_TRIPLE];
nrf_nfct_sensres_nfcid1_size_t nfcid1_size;
nrf_nfct_selres_protocol_t protocol;
// Save parameter settings before the reset of the NFCT peripheral.
fdmax = nrf_nfct_frame_delay_max_get(NRF_NFCT);
fdmin = nrf_nfct_frame_delay_min_get(NRF_NFCT);
nfcid1_size = nrf_nfct_nfcid1_get(NRF_NFCT, nfcid1);
protocol = nrf_nfct_selres_protocol_get(NRF_NFCT);
int_enabled = nrf_nfct_int_enable_get(NRF_NFCT);
// Reset the NFCT peripheral.
*(volatile uint32_t *)0x40005FFC = 0;
*(volatile uint32_t *)0x40005FFC;
*(volatile uint32_t *)0x40005FFC = 1;
// Restore parameter settings after the reset of the NFCT peripheral.
nrf_nfct_frame_delay_max_set(NRF_NFCT, fdmax);
nrf_nfct_frame_delay_min_set(NRF_NFCT, fdmin);
nrf_nfct_nfcid1_set(NRF_NFCT, nfcid1, nfcid1_size);
nrf_nfct_selres_protocol_set(NRF_NFCT, protocol);
// Restore general HW configuration.
nrfx_nfct_hw_init_setup();
// Restore interrupts.
nrf_nfct_int_enable(NRF_NFCT, int_enabled);
// Disable interrupts associated with data exchange.
nrf_nfct_int_disable(NRF_NFCT, NRFX_NFCT_RX_INT_MASK | NRFX_NFCT_TX_INT_MASK);
NRFX_LOG_INFO("Reinitialize");
}
/* End: Workaround for anomaly 116 */
static void nrfx_nfct_field_poll(void)
{
if (!nrfx_nfct_field_check())
{
if (++m_timer_workaround.field_state_cnt > NRFX_NFCT_FIELDLOST_THR)
{
nrfx_nfct_evt_t nfct_evt =
{
.evt_id = NRFX_NFCT_EVT_FIELD_LOST,
};
nrfx_timer_disable(&m_timer_workaround.timer);
m_nfct_cb.field_on = false;
nrfx_nfct_frame_delay_max_set(true);
/* Begin: Workaround for anomaly 116 */
/* resume the NFCT to initialized state */
nrfx_nfct_reset();
/* End: Workaround for anomaly 116 */
NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt);
}
return;
}
m_timer_workaround.field_state_cnt = 0;
}
#endif // NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_79)
static void nrfx_nfct_field_timer_handler(nrf_timer_event_t event_type, void * p_context)
{
(void)p_context;
if (event_type != NRF_TIMER_EVENT_COMPARE0)
{
return;
}
#if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_190)
m_timer_workaround.is_delayed = true;
nrfx_timer_disable(&m_timer_workaround.timer);
nrfx_nfct_activate_check();
#elif NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_79)
nrfx_nfct_field_poll();
#endif // NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_190)
}
static inline nrfx_err_t nrfx_nfct_field_timer_config(void)
{
nrfx_err_t err_code;
nrfx_timer_config_t timer_cfg =
{
.frequency = NRF_TIMER_FREQ_1MHz,
.mode = NRF_TIMER_MODE_TIMER,
.bit_width = NRF_TIMER_BIT_WIDTH_16,
.interrupt_priority = NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY
};
err_code = nrfx_timer_init(&m_timer_workaround.timer,
&timer_cfg,
nrfx_nfct_field_timer_handler);
if (err_code != NRFX_SUCCESS)
{
return err_code;
}
nrfx_timer_extended_compare(&m_timer_workaround.timer,
NRF_TIMER_CC_CHANNEL0,
nrfx_timer_us_to_ticks(&m_timer_workaround.timer,
NRFX_NFCT_TIMER_PERIOD),
NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
true);
return err_code;
}
#endif // NRFX_CHECK(NFCT_WORKAROUND_USES_TIMER)
static inline
nrf_nfct_sensres_nfcid1_size_t nrf_nfct_nfcid1_size_to_sensres_size(uint8_t nfcid1_size)
{
switch (nfcid1_size)
{
case NRFX_NFCT_NFCID1_SINGLE_SIZE:
return NRF_NFCT_SENSRES_NFCID1_SIZE_SINGLE;
case NRFX_NFCT_NFCID1_DOUBLE_SIZE:
return NRF_NFCT_SENSRES_NFCID1_SIZE_DOUBLE;
case NRFX_NFCT_NFCID1_TRIPLE_SIZE:
return NRF_NFCT_SENSRES_NFCID1_SIZE_TRIPLE;
default:
return NRF_NFCT_SENSRES_NFCID1_SIZE_DOUBLE;
}
}
static inline void nrfx_nfct_rxtx_int_enable(uint32_t rxtx_int_mask)
{
nrf_nfct_int_enable(NRF_NFCT, rxtx_int_mask & m_nfct_cb.config.rxtx_int_mask);
}
nrfx_err_t nrfx_nfct_init(nrfx_nfct_config_t const * p_config)
{
NRFX_ASSERT(p_config);
nrfx_err_t err_code = NRFX_SUCCESS;
if (m_nfct_cb.state != NRFX_DRV_STATE_UNINITIALIZED)
{
return NRFX_ERROR_INVALID_STATE;
}
m_nfct_cb.config = *p_config;
nrfx_nfct_hw_init_setup();
NRFX_IRQ_PENDING_CLEAR(NFCT_IRQn);
NRFX_IRQ_PRIORITY_SET(NFCT_IRQn, NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY);
NRFX_IRQ_ENABLE(NFCT_IRQn);
#if NRFX_CHECK(NFCT_WORKAROUND_USES_TIMER)
/* Initialize Timer module as the workaround for NFCT HW issues. */
err_code = nrfx_nfct_field_timer_config();
#endif // NRFX_CHECK(NFCT_WORKAROUND_USES_TIMER)
m_nfct_cb.state = NRFX_DRV_STATE_INITIALIZED;
m_nfct_cb.frame_delay_max = NFCT_FRAMEDELAYMAX_DEFAULT;
m_nfct_cb.frame_delay_min = NFCT_FRAMEDELAYMIN_DEFAULT;
NRFX_LOG_INFO("Initialized");
return err_code;
}
void nrfx_nfct_uninit(void)
{
nrfx_nfct_disable();
NRFX_IRQ_DISABLE(NFCT_IRQn);
NRFX_IRQ_PENDING_CLEAR(NFCT_IRQn);
#if NRFX_CHECK(NFCT_WORKAROUND_USES_TIMER)
/* De-initialize Timer module as the workaround for NFCT HW issues. */
nrfx_timer_uninit(&m_timer_workaround.timer);
#endif // NRFX_CHECK(NFCT_WORKAROUND_USES_TIMER)
m_nfct_cb.state = NRFX_DRV_STATE_UNINITIALIZED;
}
void nrfx_nfct_enable(void)
{
nrf_nfct_error_status_clear(NRF_NFCT, NRFX_NFCT_ERROR_STATUS_ALL_MASK);
nrf_nfct_task_trigger(NRF_NFCT, NRF_NFCT_TASK_SENSE);
nrf_nfct_int_enable(NRF_NFCT, NRF_NFCT_INT_FIELDDETECTED_MASK |
NRF_NFCT_INT_ERROR_MASK |
NRF_NFCT_INT_SELECTED_MASK);
#if !NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_79)
nrf_nfct_int_enable(NRF_NFCT, NRF_NFCT_INT_FIELDLOST_MASK);
#endif // !NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_79)
NRFX_LOG_INFO("Start");
}
void nrfx_nfct_disable(void)
{
nrf_nfct_int_disable(NRF_NFCT, NRF_NFCT_DISABLE_ALL_INT);
nrf_nfct_task_trigger(NRF_NFCT, NRF_NFCT_TASK_DISABLE);
NRFX_LOG_INFO("Stop");
}
bool nrfx_nfct_field_check(void)
{
uint32_t const field_state = nrf_nfct_field_status_get(NRF_NFCT);
if (((field_state & NRF_NFCT_FIELD_STATE_PRESENT_MASK) == 0) &&
((field_state & NRF_NFCT_FIELD_STATE_LOCK_MASK) == 0))
{
/* Field is not active */
return false;
}
return true;
}
void nrfx_nfct_rx(nrfx_nfct_data_desc_t const * p_tx_data)
{
NRFX_ASSERT(p_tx_data);
nrf_nfct_rxtx_buffer_set(NRF_NFCT, (uint8_t *) p_tx_data->p_data, p_tx_data->data_size);
nrfx_nfct_rxtx_int_enable(NRFX_NFCT_RX_INT_MASK);
nrf_nfct_task_trigger(NRF_NFCT, NRF_NFCT_TASK_ENABLERXDATA);
}
nrfx_err_t nrfx_nfct_tx(nrfx_nfct_data_desc_t const * p_tx_data,
nrf_nfct_frame_delay_mode_t delay_mode)
{
NRFX_ASSERT(p_tx_data);
NRFX_ASSERT(p_tx_data->p_data);
nrfx_err_t err = NRFX_SUCCESS;
if (p_tx_data->data_size == 0)
{
return NRFX_ERROR_INVALID_LENGTH;
}
NRFX_CRITICAL_SECTION_ENTER();
/* In case when NFC frame transmission has already started, it returns an error. */
if (NRFX_NFCT_EVT_ACTIVE(TXFRAMESTART))
{
err = NRFX_ERROR_BUSY;
}
else
{
/* In case when Tx operation was scheduled with delay, stop scheduled Tx operation. */
#if defined(NRF52_SERIES)
*(volatile uint32_t *)0x40005010 = 0x01;
#elif defined(NRF5340_XXAA_APPLICATION) && defined(NRF_TRUSTZONE_NONSECURE)
*(volatile uint32_t *)0x4002D010 = 0x01;
#elif defined(NRF5340_XXAA_APPLICATION)
*(volatile uint32_t *)0x5002D010 = 0x01;
#endif
nrf_nfct_rxtx_buffer_set(NRF_NFCT, (uint8_t *) p_tx_data->p_data, p_tx_data->data_size);
nrf_nfct_tx_bits_set(NRF_NFCT, NRFX_NFCT_BYTES_TO_BITS(p_tx_data->data_size));
nrf_nfct_frame_delay_mode_set(NRF_NFCT, (nrf_nfct_frame_delay_mode_t) delay_mode);
nrfx_nfct_frame_delay_max_set(false);
nrfx_nfct_rxtx_int_enable(NRFX_NFCT_TX_INT_MASK);
nrf_nfct_task_trigger(NRF_NFCT, NRF_NFCT_TASK_STARTTX);
}
NRFX_CRITICAL_SECTION_EXIT();
if (err == NRFX_SUCCESS)
{
NRFX_LOG_INFO("Tx start");
}
return err;
}
nrfx_err_t nrfx_nfct_bits_tx(nrfx_nfct_data_desc_t const * p_tx_data,
nrf_nfct_frame_delay_mode_t delay_mode)
{
NRFX_ASSERT(p_tx_data);
NRFX_ASSERT(p_tx_data->p_data);
nrfx_err_t err = NRFX_SUCCESS;
if (p_tx_data->data_size == 0)
{
return NRFX_ERROR_INVALID_LENGTH;
}
/* Get buffer length, add additional byte if bits go beyond last whole byte */
uint32_t buffer_length = NRFX_NFCT_BITS_TO_BYTES(p_tx_data->data_size);
if (p_tx_data->data_size & NFCT_TXD_AMOUNT_TXDATABITS_Msk)
{
++buffer_length;
}
NRFX_CRITICAL_SECTION_ENTER();
/* In case when NFC frame transmission has already started, it returns an error. */
if (NRFX_NFCT_EVT_ACTIVE(TXFRAMESTART))
{
err = NRFX_ERROR_BUSY;
}
else
{
/* In case when Tx operation was scheduled with delay, stop scheduled Tx operation. */
#if defined(NRF52_SERIES)
*(volatile uint32_t *)0x40005010 = 0x01;
#elif defined(NRF5340_XXAA_APPLICATION) && defined(NRF_TRUSTZONE_NONSECURE)
*(volatile uint32_t *)0x4002D010 = 0x01;
#elif defined(NRF5340_XXAA_APPLICATION)
*(volatile uint32_t *)0x5002D010 = 0x01;
#endif
nrf_nfct_rxtx_buffer_set(NRF_NFCT, (uint8_t *) p_tx_data->p_data, buffer_length);
nrf_nfct_tx_bits_set(NRF_NFCT, p_tx_data->data_size);
nrf_nfct_frame_delay_mode_set(NRF_NFCT, (nrf_nfct_frame_delay_mode_t) delay_mode);
nrfx_nfct_frame_delay_max_set(false);
nrfx_nfct_rxtx_int_enable(NRFX_NFCT_TX_INT_MASK);
nrf_nfct_task_trigger(NRF_NFCT, NRF_NFCT_TASK_STARTTX);
}
NRFX_CRITICAL_SECTION_EXIT();
if (err == NRFX_SUCCESS)
{
NRFX_LOG_INFO("Tx start");
}
return err;
}
void nrfx_nfct_state_force(nrfx_nfct_state_t state)
{
#if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_190)
if (state == NRFX_NFCT_STATE_ACTIVATED)
{
m_timer_workaround.is_hfclk_on = true;
/* NFCT will be activated based on additional conditions */
nrfx_nfct_activate_check();
return;
}
#endif // NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_190)
nrf_nfct_task_trigger(NRF_NFCT, (nrf_nfct_task_t) state);
}
void nrfx_nfct_init_substate_force(nrfx_nfct_active_state_t sub_state)
{
if (sub_state == NRFX_NFCT_ACTIVE_STATE_DEFAULT)
{
#if defined(NRF52832_XXAA) || defined(NRF52832_XXAB)
if (((*(uint32_t volatile *)(0x40005420)) & 0x1UL) == (1UL))
#else
if (nrf_nfct_sleep_state_get(NRF_NFCT) == NRF_NFCT_SLEEP_STATE_SLEEP_A)
#endif //defined(NRF52832_XXAA) || defined(NRF52832_XXAB)
{
// Default state is SLEEP_A
nrf_nfct_task_trigger(NRF_NFCT, NRF_NFCT_TASK_GOSLEEP);
}
else
{
// Default state is IDLE
nrf_nfct_task_trigger(NRF_NFCT, NRF_NFCT_TASK_GOIDLE);
}
}
else
{
nrf_nfct_task_trigger(NRF_NFCT, (nrf_nfct_task_t) sub_state);
}
nrfx_nfct_frame_delay_max_set(true);
/* Disable TX/RX here (will be enabled at SELECTED) */
nrf_nfct_int_disable(NRF_NFCT, NRFX_NFCT_RX_INT_MASK | NRFX_NFCT_TX_INT_MASK);
}
nrfx_err_t nrfx_nfct_parameter_set(nrfx_nfct_param_t const * p_param)
{
NRFX_ASSERT(p_param);
switch (p_param->id)
{
case NRFX_NFCT_PARAM_ID_FDT:
{
uint32_t delay = p_param->data.fdt;
uint32_t delay_thr = NFCT_FRAMEDELAYMAX_FRAMEDELAYMAX_Msk;
uint32_t delay_max;
delay_max = (delay > delay_thr) ? delay_thr : delay;
if (delay_max < m_nfct_cb.frame_delay_min)
{
return NRFX_ERROR_INVALID_PARAM;
}
m_nfct_cb.frame_delay_max = delay_max;
break;
}
case NRFX_NFCT_PARAM_ID_FDT_MIN:
{
uint32_t delay = p_param->data.fdt_min;
uint32_t delay_thr = NFCT_FRAMEDELAYMAX_FRAMEDELAYMAX_Msk;
uint32_t delay_min;
delay_min = (delay > delay_thr) ? delay_thr : delay;
if (delay_min > m_nfct_cb.frame_delay_max)
{
return NRFX_ERROR_INVALID_PARAM;
}
m_nfct_cb.frame_delay_min = delay_min;
nrf_nfct_frame_delay_min_set(NRF_NFCT, m_nfct_cb.frame_delay_min);
break;
}
case NRFX_NFCT_PARAM_ID_SEL_RES:
if (p_param->data.sel_res_protocol > NRF_NFCT_SELRES_PROTOCOL_NFCDEP_T4AT)
{
return NRFX_ERROR_INVALID_PARAM;
}
nrf_nfct_selres_protocol_set(NRF_NFCT,
(nrf_nfct_selres_protocol_t) p_param->data.sel_res_protocol);
break;
case NRFX_NFCT_PARAM_ID_NFCID1:
{
nrf_nfct_sensres_nfcid1_size_t id_size_mask;
id_size_mask = nrf_nfct_nfcid1_size_to_sensres_size(p_param->data.nfcid1.id_size);
nrf_nfct_nfcid1_set(NRF_NFCT, p_param->data.nfcid1.p_id, id_size_mask);
break;
}
default:
break;
}
return NRFX_SUCCESS;
}
nrfx_err_t nrfx_nfct_nfcid1_default_bytes_get(uint8_t * const p_nfcid1_buff,
uint32_t nfcid1_buff_len)
{
if ((nfcid1_buff_len != NRFX_NFCT_NFCID1_SINGLE_SIZE) &&
(nfcid1_buff_len != NRFX_NFCT_NFCID1_DOUBLE_SIZE) &&
(nfcid1_buff_len != NRFX_NFCT_NFCID1_TRIPLE_SIZE))
{
return NRFX_ERROR_INVALID_LENGTH;
}
#if defined(FICR_NFC_TAGHEADER0_MFGID_Msk) && !defined(NRF_TRUSTZONE_NONSECURE)
uint32_t nfc_tag_header0 = NRF_FICR->NFC.TAGHEADER0;
uint32_t nfc_tag_header1 = NRF_FICR->NFC.TAGHEADER1;
uint32_t nfc_tag_header2 = NRF_FICR->NFC.TAGHEADER2;
#else
uint32_t nfc_tag_header0 = 0x5F;
uint32_t nfc_tag_header1 = 0;
uint32_t nfc_tag_header2 = 0;
#endif
p_nfcid1_buff[0] = (uint8_t) (nfc_tag_header0 >> 0);
p_nfcid1_buff[1] = (uint8_t) (nfc_tag_header0 >> 8);
p_nfcid1_buff[2] = (uint8_t) (nfc_tag_header0 >> 16);
p_nfcid1_buff[3] = (uint8_t) (nfc_tag_header1 >> 0);
if (nfcid1_buff_len != NRFX_NFCT_NFCID1_SINGLE_SIZE)
{
p_nfcid1_buff[4] = (uint8_t) (nfc_tag_header1 >> 8);
p_nfcid1_buff[5] = (uint8_t) (nfc_tag_header1 >> 16);
p_nfcid1_buff[6] = (uint8_t) (nfc_tag_header1 >> 24);
if (nfcid1_buff_len == NRFX_NFCT_NFCID1_TRIPLE_SIZE)
{
p_nfcid1_buff[7] = (uint8_t) (nfc_tag_header2 >> 0);
p_nfcid1_buff[8] = (uint8_t) (nfc_tag_header2 >> 8);
p_nfcid1_buff[9] = (uint8_t) (nfc_tag_header2 >> 16);
}
/* Begin: Workaround for anomaly 181. */
/* Workaround for wrong value in NFCID1. Value 0x88 cannot be used as byte 3
of a double-size NFCID1, according to the NFC Forum Digital Protocol specification. */
else if (p_nfcid1_buff[3] == 0x88)
{
p_nfcid1_buff[3] |= 0x11;
}
/* End: Workaround for anomaly 181 */
}
return NRFX_SUCCESS;
}
void nrfx_nfct_autocolres_enable(void)
{
#if defined(NRF52832_XXAA) || defined(NRF52832_XXAB)
(*(uint32_t *)(0x4000559C)) &= (~(0x1UL));
#else
nrf_nfct_autocolres_enable(NRF_NFCT);
#endif //defined(NRF52832_XXAA) || defined(NRF52832_XXAB)
}
void nrfx_nfct_autocolres_disable(void)
{
#if defined(NRF52832_XXAA) || defined(NRF52832_XXAB)
(*(uint32_t *)(0x4000559C)) |= (0x1UL);
#else
nrf_nfct_autocolres_disable(NRF_NFCT);
#endif //defined(NRF52832_XXAA) || defined(NRF52832_XXAB)
}
void nrfx_nfct_irq_handler(void)
{
nrfx_nfct_field_state_t current_field = NRFX_NFC_FIELD_STATE_NONE;
if (NRFX_NFCT_EVT_ACTIVE(FIELDDETECTED))
{
nrf_nfct_event_clear(NRF_NFCT, NRF_NFCT_EVENT_FIELDDETECTED);
current_field = NRFX_NFC_FIELD_STATE_ON;
NRFX_LOG_DEBUG("Field detected");
}
#if !NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_79)
if (NRFX_NFCT_EVT_ACTIVE(FIELDLOST))
{
nrf_nfct_event_clear(NRF_NFCT, NRF_NFCT_EVENT_FIELDLOST);
current_field = (current_field == NRFX_NFC_FIELD_STATE_NONE) ?
NRFX_NFC_FIELD_STATE_OFF : NRFX_NFC_FIELD_STATE_UNKNOWN;
NRFX_LOG_DEBUG("Field lost");
}
#endif //!NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_79)
/* Perform actions if any FIELD event is active */
if (current_field != NRFX_NFC_FIELD_STATE_NONE)
{
nrfx_nfct_field_event_handler(current_field);
}
if (NRFX_NFCT_EVT_ACTIVE(RXFRAMESTART))
{
nrf_nfct_event_clear(NRF_NFCT, NRF_NFCT_EVENT_RXFRAMESTART);
nrfx_nfct_evt_t nfct_evt =
{
.evt_id = NRFX_NFCT_EVT_RX_FRAMESTART
};
NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt);
}
if (NRFX_NFCT_EVT_ACTIVE(RXFRAMEEND))
{
nrf_nfct_event_clear(NRF_NFCT, NRF_NFCT_EVENT_RXFRAMEEND);
nrfx_nfct_evt_t nfct_evt =
{
.evt_id = NRFX_NFCT_EVT_RX_FRAMEEND
};
/* Take into account only the number of whole bytes. */
nfct_evt.params.rx_frameend.rx_status = 0;
nfct_evt.params.rx_frameend.rx_data.p_data = nrf_nfct_rxtx_buffer_get(NRF_NFCT);
nfct_evt.params.rx_frameend.rx_data.data_size =
NRFX_NFCT_BITS_TO_BYTES(nrf_nfct_rx_bits_get(NRF_NFCT, true));
if (NRFX_NFCT_EVT_ACTIVE(RXERROR))
{
nfct_evt.params.rx_frameend.rx_status =
(nrf_nfct_rx_frame_status_get(NRF_NFCT) & NRFX_NFCT_FRAME_STATUS_RX_ALL_MASK);
nrf_nfct_event_clear(NRF_NFCT, NRF_NFCT_EVENT_RXERROR);
NRFX_LOG_DEBUG("Rx error (0x%x)", (unsigned int) nfct_evt.params.rx_frameend.rx_status);
/* Clear rx frame status */
nrf_nfct_rx_frame_status_clear(NRF_NFCT, NRFX_NFCT_FRAME_STATUS_RX_ALL_MASK);
}
NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt);
NRFX_LOG_DEBUG("Rx fend");
}
if (NRFX_NFCT_EVT_ACTIVE(SELECTED))
{
nrf_nfct_event_clear(NRF_NFCT, NRF_NFCT_EVENT_SELECTED);
/* Clear also RX END and RXERROR events because SW does not take care of
commands that were received before selecting the tag. */
nrf_nfct_event_clear(NRF_NFCT, NRF_NFCT_EVENT_RXFRAMEEND);
nrf_nfct_event_clear(NRF_NFCT, NRF_NFCT_EVENT_RXERROR);
nrf_nfct_event_clear(NRF_NFCT, NRF_NFCT_EVENT_TXFRAMESTART);
nrf_nfct_event_clear(NRF_NFCT, NRF_NFCT_EVENT_TXFRAMEEND);
nrfx_nfct_frame_delay_max_set(false);
/* At this point any previous error status can be ignored. */
nrf_nfct_rx_frame_status_clear(NRF_NFCT, NRFX_NFCT_FRAME_STATUS_RX_ALL_MASK);
nrf_nfct_error_status_clear(NRF_NFCT, NRFX_NFCT_ERROR_STATUS_ALL_MASK);
nrfx_nfct_evt_t nfct_evt =
{
.evt_id = NRFX_NFCT_EVT_SELECTED
};
NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt);
NRFX_LOG_DEBUG("Selected");
}
if (NRFX_NFCT_EVT_ACTIVE(ERROR))
{
uint32_t err_status = nrf_nfct_error_status_get(NRF_NFCT);
nrf_nfct_event_clear(NRF_NFCT, NRF_NFCT_EVENT_ERROR);
nrfx_nfct_evt_t nfct_evt =
{
.evt_id = NRFX_NFCT_EVT_ERROR
};
/* Clear FRAMEDELAYTIMEOUT error (expected HW behaviour) when SLP_REQ command was received. */
if (err_status & NRF_NFCT_ERROR_FRAMEDELAYTIMEOUT_MASK)
{
nrf_nfct_error_status_clear(NRF_NFCT, NRF_NFCT_ERROR_FRAMEDELAYTIMEOUT_MASK);
nfct_evt.params.error.reason = NRFX_NFCT_ERROR_FRAMEDELAYTIMEOUT;
NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt);
}
/* Report any other error. */
err_status &= ~NRF_NFCT_ERROR_FRAMEDELAYTIMEOUT_MASK;
if (err_status)
{
NRFX_LOG_DEBUG("Error (0x%x)", (unsigned int) err_status);
}
/* Clear error status. */
nrf_nfct_error_status_clear(NRF_NFCT, NRFX_NFCT_ERROR_STATUS_ALL_MASK);
}
if (NRFX_NFCT_EVT_ACTIVE(TXFRAMESTART))
{
nrf_nfct_event_clear(NRF_NFCT, NRF_NFCT_EVENT_TXFRAMESTART);
if (m_nfct_cb.config.cb != NULL)
{
nrfx_nfct_evt_t nfct_evt;
nfct_evt.evt_id = NRFX_NFCT_EVT_TX_FRAMESTART;
nfct_evt.params.tx_framestart.tx_data.p_data = nrf_nfct_rxtx_buffer_get(NRF_NFCT);
nfct_evt.params.tx_framestart.tx_data.data_size =
NRFX_NFCT_BITS_TO_BYTES(nrf_nfct_tx_bits_get(NRF_NFCT));
m_nfct_cb.config.cb(&nfct_evt);
}
}
if (NRFX_NFCT_EVT_ACTIVE(TXFRAMEEND))
{
nrf_nfct_event_clear(NRF_NFCT, NRF_NFCT_EVENT_TXFRAMEEND);
nrfx_nfct_evt_t nfct_evt =
{
.evt_id = NRFX_NFCT_EVT_TX_FRAMEEND
};
/* Ignore any frame transmission until a new TX is scheduled by nrfx_nfct_tx() */
nrf_nfct_int_disable(NRF_NFCT, NRFX_NFCT_TX_INT_MASK);
NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt);
NRFX_LOG_DEBUG("Tx fend");
}
}
#endif // NRFX_CHECK(NRFX_NFCT_ENABLED)