From 67710e47c7313cc56a15748e485079831ee6a3af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karol=20Laso=C5=84czyk?= Date: Fri, 21 Sep 2018 15:15:26 +0200 Subject: [PATCH] nrfx 1.3.0 release --- CHANGELOG.md | 21 +- doc/config_dox/nrfx_nfct_dox_config.h | 88 + doc/config_dox/nrfx_usbd_dox_config.h | 56 + doc/drv_supp_matrix.dox | 1 + doc/nrf52832.dox | 2 + doc/nrf52840.dox | 2 + doc/nrfx.doxyfile | 2 +- doc/nrfx_api.dox | 2 + drivers/include/nrfx_nfct.h | 366 ++++ drivers/include/nrfx_usbd.h | 862 +++++++++ drivers/nrfx_common.h | 21 + drivers/src/nrfx_nfct.c | 884 ++++++++++ drivers/src/nrfx_power.c | 19 + drivers/src/nrfx_power_clock.c | 43 - drivers/src/nrfx_usbd.c | 2349 +++++++++++++++++++++++++ drivers/src/nrfx_usbd_errata.h | 117 ++ hal/nrf_nfct.h | 1070 +++++++++++ hal/nrf_power.h | 6 +- hal/nrf_saadc.h | 14 + hal/nrf_usbd.h | 16 +- soc/nrfx_atomic.c | 390 ++++ soc/nrfx_atomic.h | 279 +++ soc/nrfx_atomic_internal.h | 325 ++++ soc/nrfx_irqs_nrf52832.h | 1 + soc/nrfx_irqs_nrf52840.h | 2 + templates/nRF52832/nrfx_config.h | 73 + templates/nRF52840/nrfx_config.h | 168 ++ templates/nrfx_glue.h | 71 + 28 files changed, 7191 insertions(+), 59 deletions(-) create mode 100644 doc/config_dox/nrfx_nfct_dox_config.h create mode 100644 doc/config_dox/nrfx_usbd_dox_config.h create mode 100644 drivers/include/nrfx_nfct.h create mode 100644 drivers/include/nrfx_usbd.h create mode 100644 drivers/src/nrfx_nfct.c delete mode 100644 drivers/src/nrfx_power_clock.c create mode 100644 drivers/src/nrfx_usbd.c create mode 100644 drivers/src/nrfx_usbd_errata.h create mode 100644 hal/nrf_nfct.h create mode 100644 soc/nrfx_atomic.c create mode 100644 soc/nrfx_atomic.h create mode 100644 soc/nrfx_atomic_internal.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 462a6edd4..57ac5a7fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,19 @@ # Changelog All notable changes to this project are documented in this file. +## [1.3.0] - 2018-09-21 +### Added +- Added HAL and driver for NFCT. +- Added driver for USBD. +- Added function for setting the burst mode in the SAADC HAL. +- Added the NRFX_ARRAY_SIZE macro. + +### Changed +- Moved the implementation of nrfx_power_clock_irq_handler() to nrfx_power.c, removed nrfx_power_clock.c. + +### Fixed +- Replaced ARRAY_SIZE macro calls with NRFX_ARRAY_SIZE ones. + ## [1.2.0] - 2018-09-06 ### Added - Added function for checking if a specific channel is enabled in the GPIOTE HAL. @@ -8,13 +21,13 @@ All notable changes to this project are documented in this file. - Added functions for modifying only the event endpoint or only the task endpoint in the PPI HAL. - Added function for reading the pin pull configuration in the GPIO HAL. +### Changed +- Corrected ISOSPLIT enumerator names in the USBD HAL. + ### Fixed - Fixed a double buffering bug that occurred in the UARTE driver after the RX abort. - Fixed the TXRX transfers in the TWIM driver. They can now be started after transfers that are not ended with the stop condition. -### Changed -- Corrected ISOSPLIT enumerator names in the USBD HAL. - ## [1.1.0] - 2018-06-15 ### Added - Implemented workaround for nRF52832 and nRF52840 anomaly 194 in the I2S driver. @@ -51,7 +64,7 @@ All notable changes to this project are documented in this file. - Changed the RNG bias correction configuration option to be enabled by default. - Refactored the ADC driver and HAL. - Corrected assertions in the TIMER driver to make it usable in debug version with PPI. -- Improved buffer handling in the I2S driver. The API of the driver has been sligthly modified. +- Improved buffer handling in the I2S driver. The API of the driver has been slightly modified. - Enhanced SPIS driver API: added the "p_context" parameter, allowed NULL pointers for zero-length buffers. ### Fixed diff --git a/doc/config_dox/nrfx_nfct_dox_config.h b/doc/config_dox/nrfx_nfct_dox_config.h new file mode 100644 index 000000000..d484e5c1d --- /dev/null +++ b/doc/config_dox/nrfx_nfct_dox_config.h @@ -0,0 +1,88 @@ +/** + * + * @defgroup nrfx_nfct_config NFCT peripheral driver configuration + * @{ + * @ingroup nrfx_nfct + */ +/** @brief Enable NFCT driver. + * + * Set to 1 to activate. + * + * @note This is an NRF_CONFIG macro. + */ +#define NRFX_NFCT_ENABLED + +/** @brief Interrupt priority. + * + * The following options are available: + * - 0 - 0 (highest) + * - 1 - 1 + * - 2 - 2 + * - 3 - 3 + * - 4 - 4 (Software Component only) + * - 5 - 5 (Software Component only) + * - 6 - 6 (Software Component only) + * - 7 - 7 (Software Component only) + * + * @note This is an NRF_CONFIG macro. + */ +#define NRFX_NFCT_CONFIG_IRQ_PRIORITY + +/** @brief Enables logging in the module. + * + * Set to 1 to activate. + * + * @note This is an NRF_CONFIG macro. + */ +#define NRFX_NFCT_CONFIG_LOG_ENABLED + +/** @brief Default Severity level. + * + * The following options are available: + * - 0 - Off + * - 1 - Error + * - 2 - Warning + * - 3 - Info + * - 4 - Debug + * + * @note This is an NRF_CONFIG macro. + */ +#define NRFX_NFCT_CONFIG_LOG_LEVEL + +/** @brief ANSI escape code prefix. + * + * The following options are available: + * - 0 - Default + * - 1 - Black + * - 2 - Red + * - 3 - Green + * - 4 - Yellow + * - 5 - Blue + * - 6 - Magenta + * - 7 - Cyan + * - 8 - White + * + * @note This is an NRF_CONFIG macro. + */ +#define NRFX_NFCT_CONFIG_INFO_COLOR + +/** @brief ANSI escape code prefix. + * + * The following options are available: + * - 0 - Default + * - 1 - Black + * - 2 - Red + * - 3 - Green + * - 4 - Yellow + * - 5 - Blue + * - 6 - Magenta + * - 7 - Cyan + * - 8 - White + * + * @note This is an NRF_CONFIG macro. + */ +#define NRFX_NFCT_CONFIG_DEBUG_COLOR + + + +/** @} */ diff --git a/doc/config_dox/nrfx_usbd_dox_config.h b/doc/config_dox/nrfx_usbd_dox_config.h new file mode 100644 index 000000000..1aed3088e --- /dev/null +++ b/doc/config_dox/nrfx_usbd_dox_config.h @@ -0,0 +1,56 @@ +/** + * + * @defgroup nrfx_usbd_config USBD peripheral driver configuration + * @{ + * @ingroup nrfx_usbd + */ +/** @brief Enable USB driver + * + * Set to 1 to activate. + * + * @note This is an NRF_CONFIG macro. + */ +#define NRFX_USBD_ENABLED +/** @brief Interrupt priority + * + * Following options are available: + * - 0 - 0 (highest) + * - 1 - 1 + * - 2 - 2 + * - 3 - 3 + * - 4 - 4 (Software Component only) + * - 5 - 5 (Software Component only) + * - 6 - 6 (Software Component only) + * - 7 - 7 (Software Component only) + * + * @note This is an NRF_CONFIG macro. + */ +#define NRFX_USBD_CONFIG_IRQ_PRIORITY + +/** @brief Give priority to isochronous transfers + * + * This option gives priority to isochronous transfers. + * Enabling it assures that isochronous transfers are always processed, + * even if multiple other transfers are pending. + * Isochronous endpoints are prioritized before the usbd_dma_scheduler_algorithm + * function is called, so the option is independent of the algorithm chosen. + * + * Set to 1 to activate. + * + * @note This is an NRF_CONFIG macro. + */ +#define NRFX_USBD_CONFIG_DMASCHEDULER_ISO_BOOST + +/** @brief Respond to an IN token on ISO IN endpoint with ZLP when no data is ready + * + * If set, ISO IN endpoint will respond to an IN token with ZLP when no data is ready to be sent. + * Else, there will be no response. + * + * Set to 1 to activate. + * + * @note This is an NRF_CONFIG macro. + */ +#define NRFX_USBD_CONFIG_ISO_IN_ZLP + + +/** @} */ diff --git a/doc/drv_supp_matrix.dox b/doc/drv_supp_matrix.dox index 8c1f7c507..633a12307 100644 --- a/doc/drv_supp_matrix.dox +++ b/doc/drv_supp_matrix.dox @@ -14,6 +14,7 @@ Driver | nRF51 Series | nRF52810 | nRF52832 | nRF52840 | @ref nrf_gpiote |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick | @ref nrf_i2s |@tagRedCross |@tagRedCross |@tagGreenTick |@tagGreenTick | @ref nrf_lpcomp |@tagGreenTick |@tagRedCross |@tagGreenTick |@tagGreenTick | +@ref nrf_nfct |@tagRedCross |@tagRedCross |@tagGreenTick |@tagGreenTick | @ref nrf_nvmc |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick | @ref nrf_pdm |@tagRedCross |@tagGreenTick |@tagGreenTick |@tagGreenTick | @ref nrf_power |@tagGreenTick |@tagGreenTick |@tagGreenTick |@tagGreenTick | diff --git a/doc/nrf52832.dox b/doc/nrf52832.dox index b8a6c463c..10a51729a 100644 --- a/doc/nrf52832.dox +++ b/doc/nrf52832.dox @@ -18,6 +18,8 @@ @ref nrf_lpcomp +@ref nrf_nfct + @ref nrf_nvmc @ref nrf_pdm diff --git a/doc/nrf52840.dox b/doc/nrf52840.dox index ece763931..f9e3a56f6 100644 --- a/doc/nrf52840.dox +++ b/doc/nrf52840.dox @@ -18,6 +18,8 @@ @ref nrf_lpcomp +@ref nrf_nfct + @ref nrf_nvmc @ref nrf_pdm diff --git a/doc/nrfx.doxyfile b/doc/nrfx.doxyfile index 3b0c5e9aa..d02eb0f34 100644 --- a/doc/nrfx.doxyfile +++ b/doc/nrfx.doxyfile @@ -33,7 +33,7 @@ PROJECT_NAME = "nrfx" # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = "1.2" +PROJECT_NUMBER = "1.3" ### EDIT THIS ### # Using the PROJECT_BRIEF tag one can provide an optional one line description diff --git a/doc/nrfx_api.dox b/doc/nrfx_api.dox index cd31c344d..4162c681e 100644 --- a/doc/nrfx_api.dox +++ b/doc/nrfx_api.dox @@ -20,6 +20,8 @@ @defgroup nrf_lpcomp LPCOMP +@defgroup nrf_nfct NFCT + @defgroup nrf_nvmc NVMC @defgroup nrf_pdm PDM diff --git a/drivers/include/nrfx_nfct.h b/drivers/include/nrfx_nfct.h new file mode 100644 index 000000000..ceb5a340b --- /dev/null +++ b/drivers/include/nrfx_nfct.h @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2018, Nordic Semiconductor ASA + * All rights reserved. + * + * 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. + */ + +#ifndef NRFX_NFCT_H__ +#define NRFX_NFCT_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup nrfx_nfct NFCT driver + * @{ + * @ingroup nrf_nfct + * @brief Near Field Communication Tag (NFCT) peripheral driver. + */ + +#define NRFX_NFCT_NFCID1_SINGLE_SIZE 4u ///< Length of single-size NFCID1. +#define NRFX_NFCT_NFCID1_DOUBLE_SIZE 7u ///< Length of double-size NFCID1. +#define NRFX_NFCT_NFCID1_TRIPLE_SIZE 10u ///< Length of triple-size NFCID1. + +#define NRFX_NFCT_NFCID1_DEFAULT_LEN NRFX_NFCT_NFCID1_DOUBLE_SIZE ///< Default length of NFC ID. */ + +/** + * @brief NFCT hardware states. + */ +typedef enum +{ + NRFX_NFCT_STATE_DISABLED = NRF_NFCT_TASK_DISABLE, ///< NFC Tag is disabled (no sensing of an external NFC field). + NRFX_NFCT_STATE_SENSING = NRF_NFCT_TASK_SENSE, ///< NFC Tag is sensing whether there is an external NFC field. + NRFX_NFCT_STATE_ACTIVATED = NRF_NFCT_TASK_ACTIVATE, ///< NFC Tag is powered-up (see @ref nrfx_nfct_active_state_t for possible substates). +} nrfx_nfct_state_t; + +/** + * @brief NFC tag states, when NFCT hardware is activated. + * + * @details These states are substates of the @ref NRFX_NFCT_STATE_ACTIVATED state. + */ +typedef enum +{ + NRFX_NFCT_ACTIVE_STATE_IDLE = NRF_NFCT_TASK_GOIDLE, ///< NFC Tag is activated and idle (not selected by a reader). + NRFX_NFCT_ACTIVE_STATE_SLEEP = NRF_NFCT_TASK_GOSLEEP, ///< NFC Tag is sleeping. + NRFX_NFCT_ACTIVE_STATE_DEFAULT, ///< NFC Tag is either sleeping or idle, depending on the previous state before being selected by a poller. +} nrfx_nfct_active_state_t; + +/** + * @brief NFCT driver event types, passed to the upper-layer callback function + * provided during the initialization. + */ +typedef enum +{ + NRFX_NFCT_EVT_FIELD_DETECTED = NRF_NFCT_INT_FIELDDETECTED_MASK, ///< External NFC field is detected. + NRFX_NFCT_EVT_FIELD_LOST = NRF_NFCT_INT_FIELDLOST_MASK, ///< External NFC Field is lost. + NRFX_NFCT_EVT_SELECTED = NRF_NFCT_INT_SELECTED_MASK, ///< Tag was selected by the poller. + NRFX_NFCT_EVT_RX_FRAMESTART = NRF_NFCT_INT_RXFRAMESTART_MASK, ///< Data frame reception started. + NRFX_NFCT_EVT_RX_FRAMEEND = NRF_NFCT_INT_RXFRAMEEND_MASK, ///< Data frame is received. + NRFX_NFCT_EVT_TX_FRAMESTART = NRF_NFCT_INT_TXFRAMESTART_MASK, ///< Data frame transmission started. + NRFX_NFCT_EVT_TX_FRAMEEND = NRF_NFCT_INT_TXFRAMEEND_MASK, ///< Data frame is transmitted. + NRFX_NFCT_EVT_ERROR = NRF_NFCT_INT_ERROR_MASK, ///< Error occurred in an NFC communication. +} nrfx_nfct_evt_id_t; + +/** + * @brief NFCT timing-related error types. + */ +typedef enum +{ + NRFX_NFCT_ERROR_FRAMEDELAYTIMEOUT, ///< No response frame was transmitted to the poller in the transmit window. + NRFX_NFCT_ERROR_NUM, ///< Total number of possible errors. +} nrfx_nfct_error_t; + +/** + * @brief NFCT driver parameter types. + */ +typedef enum +{ + NRFX_NFCT_PARAM_ID_FDT, ///< NFC-A Frame Delay Time parameter. + NRFX_NFCT_PARAM_ID_SEL_RES, ///< Value of the 'Protocol' field in the NFC-A SEL_RES frame. + NRFX_NFCT_PARAM_ID_NFCID1, ///< NFC-A NFCID1 setting (NFC tag identifier). +} nrfx_nfct_param_id_t; + +/** + * @brief NFCID1 descriptor. + */ +typedef struct +{ + uint8_t const * p_id; ///< NFCID1 data. + uint8_t id_size; ///< NFCID1 size. +} nrfx_nfct_nfcid1_t; + +/** + * @brief NFCT driver parameter descriptor. + */ +typedef struct +{ + nrfx_nfct_param_id_t id; ///< Type of parameter. + union + { + uint32_t fdt; ///< NFC-A Frame Delay Time. Filled when nrfx_nfct_param_t::id is @ref NRFX_NFCT_PARAM_ID_FDT. + uint8_t sel_res_protocol; ///< NFC-A value of the 'Protocol' field in the SEL_RES frame. Filled when nrfx_nfct_param_t::id is @ref NRFX_NFCT_PARAM_ID_SEL_RES. + nrfx_nfct_nfcid1_t nfcid1; ///< NFC-A NFCID1 value (tag identifier). Filled when nrfx_nfct_param_t::id is @ref NRFX_NFCT_PARAM_ID_NFCID1. + } data; +} nrfx_nfct_param_t; + +/** + * @brief NFCT driver RX/TX buffer descriptor. + */ +typedef struct +{ + uint32_t data_size; ///< RX/TX buffer size. + uint8_t const * p_data; ///< RX/TX buffer. +} nrfx_nfct_data_desc_t; + +/** + * @brief Structure used to describe the @ref NRFX_NFCT_EVT_RX_FRAMEEND event type. + */ +typedef struct +{ + uint32_t rx_status; ///< RX error status. + nrfx_nfct_data_desc_t rx_data; ///< RX buffer. +} nrfx_nfct_evt_rx_frameend_t; + +/** + * @brief Structure used to describe the @ref NRFX_NFCT_EVT_TX_FRAMESTART event type. + */ +typedef struct +{ + nrfx_nfct_data_desc_t tx_data; ///< TX buffer. +} nrfx_nfct_evt_tx_framestart_t; + +/** + * @brief Structure used to describe the @ref NRFX_NFCT_EVT_ERROR event type. + */ +typedef struct +{ + nrfx_nfct_error_t reason; ///< Reason for error. +} nrfx_nfct_evt_error_t; + +/** + * @brief NFCT driver event. + */ +typedef struct +{ + nrfx_nfct_evt_id_t evt_id; ///< Type of event. + union + { + nrfx_nfct_evt_rx_frameend_t rx_frameend; ///< End of the RX frame data. Filled when nrfx_nfct_evt_t::evt_id is @ref NRFX_NFCT_EVT_RX_FRAMEEND. + nrfx_nfct_evt_tx_framestart_t tx_framestart; ///< Start of the TX frame data. Filled when nrfx_nfct_evt_t::evt_id is @ref NRFX_NFCT_EVT_TX_FRAMESTART. + nrfx_nfct_evt_error_t error; ///< Error data. Filled when nrfx_nfct_evt_t::evt_id is @ref NRFX_NFCT_EVT_ERROR. + } params; +} nrfx_nfct_evt_t; + +/** + * @brief Callback descriptor to pass events from the NFCT driver to the upper layer. + * + * @param[in] p_event Pointer to the event descriptor. + */ +typedef void (*nrfx_nfct_handler_t)(nrfx_nfct_evt_t const * p_event); + +/** + * @brief NFCT driver configuration structure. + */ +typedef struct +{ + uint32_t rxtx_int_mask; ///< Mask for enabling RX/TX events. Indicate which events must be forwarded to the upper layer by using @ref nrfx_nfct_evt_id_t. By default, no events are enabled. */ + nrfx_nfct_handler_t cb; ///< Callback. +} nrfx_nfct_config_t; + +/** + * @brief Function for initializing the NFCT driver. + * + * @param[in] p_config Pointer to the NFCT driver configuration structure. + * + * @retval NRFX_SUCCESS If the NFCT driver was initialized successfully. + * @retval NRFX_ERROR_INVALID_STATE If the NFCT driver is already initialized. + */ +nrfx_err_t nrfx_nfct_init(nrfx_nfct_config_t const * p_config); + +/** + * @brief Function for uninitializing the NFCT driver. + * + * After uninitialization, the instance is in disabled state. + */ +void nrfx_nfct_uninit(void); + +/** + * @brief Function for starting the NFC subsystem. + * + * After this function completes, NFC readers are able to detect the tag. + */ +void nrfx_nfct_enable(void); + +/** + * @brief Function for disabling the NFCT driver. + * + * After this function returns, NFC readers are no longer able to connect + * to the tag. + */ +void nrfx_nfct_disable(void); + +/** + * @brief Function for checking whether the external NFC field is present in the range of the tag. + * + * @retval true If the NFC field is present. + * @retval false If no NFC field is present. + */ +bool nrfx_nfct_field_check(void); + +/** + * @brief Function for preparing the NFCT driver for receiving an NFC frame. + * + * @param[in] p_rx_data Pointer to the RX buffer. + */ +void nrfx_nfct_rx(nrfx_nfct_data_desc_t const * p_rx_data); + +/** + * @brief Function for transmitting an NFC frame. + * + * @param[in] p_tx_data Pointer to the TX buffer. + * @param[in] delay_mode Delay mode of the NFCT frame timer. + * + * @retval NRFX_SUCCESS If the operation was successful. + * @retval NRFX_ERROR_INVALID_LENGTH If the TX buffer size is invalid. + */ +nrfx_err_t nrfx_nfct_tx(nrfx_nfct_data_desc_t const * p_tx_data, + nrf_nfct_frame_delay_mode_t delay_mode); + +/** + * @brief Function for moving the NFCT to a new state. + * + * @note The HFCLK must be running before activating the NFCT with + * @ref NRFX_NFCT_STATE_ACTIVATED. + * + * @param[in] state The required state. + */ +void nrfx_nfct_state_force(nrfx_nfct_state_t state); + +/** + * @brief Function for moving the NFCT to a new initial substate within @ref NRFX_NFCT_STATE_ACTIVATED. + * + * @param[in] sub_state The required substate. + */ +void nrfx_nfct_init_substate_force(nrfx_nfct_active_state_t sub_state); + +/** + * @brief Function for setting the NFC communication parameter. + * + * @note Parameter validation for length and acceptable values. + * + * @param[in] p_param Pointer to parameter descriptor. + * + * @retval NRFX_SUCCESS If the operation was successful. + * @retval NRFX_ERROR_INVALID_PARAM If the parameter data is invalid. + */ +nrfx_err_t nrfx_nfct_parameter_set(nrfx_nfct_param_t const * p_param); + +/** + * @brief Function for getting default bytes for NFCID1. + * + * @param[in,out] p_nfcid1_buff In: empty buffer for data; + * Out: buffer with the NFCID1 default data. These values + * can be used to fill the Type 2 Tag Internal Bytes. + * @param[in] nfcid1_buff_len Length of the NFCID1 buffer. + * + * @retval NRFX_SUCCESS If the operation was successful. + * @retval NRFX_ERROR_INVALID_LENGTH If length of the NFCID buffer is different than + * @ref NRFX_NFCT_NFCID1_SINGLE_SIZE, + * @ref NRFX_NFCT_NFCID1_DOUBLE_SIZE, or + * @ref NRFX_NFCT_NFCID1_TRIPLE_SIZE. + */ +nrfx_err_t nrfx_nfct_nfcid1_default_bytes_get(uint8_t * const p_nfcid1_buff, + uint32_t nfcid1_buff_len); + +/** + * @brief Function for enabling the automatic collision resolution. + * + * @details As defined by the NFC Forum Digital Protocol Technical Specification (and ISO 14443-3), + * the automatic collision resolution is implemented in the NFCT hardware. + * This function allows enabling and disabling this feature. + */ +void nrfx_nfct_autocolres_enable(void); + +/** + * @brief Function for disabling the automatic collision resolution. + * + * @details See also details in @ref nrfx_nfct_autocolres_enable. + */ +void nrfx_nfct_autocolres_disable(void); + + +void nrfx_nfct_irq_handler(void); + + +/** @} */ + +#ifdef __cplusplus +} +#endif + + +/** + * @defgroup nrfx_nfct_fixes NFCT driver fixes and workarounds + * @{ + * @ingroup nrf_nfct + * @brief Fixes for hardware-related anomalies. + * + * If you are using the nRF52832 chip, the workarounds for the following anomalies are applied: + * - 79. NFCT: A false EVENTS_FIELDDETECTED event occurs after the field is lost. + * - 116. NFCT does not release HFCLK when switching from ACTIVATED to SENSE mode. + * To implement the first workaround, an instance of NRF_TIMER is used. After the NFC field is detected, + * the timing module periodically polls its state to determine when the field is turned off. + * To implement the second workaround, power reset is used to release the clock acquired by NFCT + * after the field is turned off. Note that the NFCT register configuration is restored to defaults. + * + * If you are using the nRF52840 chip, rev. Engineering A, the workarounds for the following anomalies + * are applied: + * - 98. NFCT: The NFCT is not able to communicate with the peer. + * - 116. NFCT does not release HFCLK when switching from ACTIVATED to SENSE mode. + * - 144. NFCT: Not optimal NFC performance + * + * If you are using the nRF52840 chip, rev. 1, or rev. Engineering B or C, the workarounds for the following + * anomalies are applied: + * - 190. NFCT: Event FIELDDETECTED can be generated too early. + * To implement this workaround, an instance of NRF_TIMER is used. After the NFC field is detected, + * the timing module measures the necessary waiting period after which NFCT can be activated. + * This debouncing technique is used to filter possible field instabilities. + * + * The application of the implemented workarounds for the nRF52840 chip is determined at runtime and depends + * on the chip variant. + * + * The current code contains a patch for the anomaly 25 (NFCT: Reset value of + * SENSRES register is incorrect), so that the module now works on Windows Phone. + * @} + */ + +#endif // NRFX_NFCT_H__ diff --git a/drivers/include/nrfx_usbd.h b/drivers/include/nrfx_usbd.h new file mode 100644 index 000000000..d9dc8301a --- /dev/null +++ b/drivers/include/nrfx_usbd.h @@ -0,0 +1,862 @@ +/* + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * All rights reserved. + * + * 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. + */ + +#ifndef NRFX_USBD_H__ +#define NRFX_USBD_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup nrfx_usbd USBD driver + * @{ + * @ingroup nrf_usbd + * @brief Universal Serial Bus Device (USBD) peripheral driver. + */ + +/** + * @brief Number of bytes in the endpoint. + */ +#define NRFX_USBD_EPSIZE 64 + +/** + * @brief Number of bytes for isochronous endpoints. + * + * Number of bytes for isochronous endpoints in total. + * This number would be shared between IN and OUT endpoint. + * It may be also assigned totaly to one endpoint. + * @sa nrf_usbd_isosplit_set + * @sa nrf_usbd_isosplit_get + */ +#define NRFX_USBD_ISOSIZE 1024 + +/** + * @brief The size of internal feeder buffer. + * + * @sa nrfx_usbd_feeder_buffer_get + */ +#define NRFX_USBD_FEEDER_BUFFER_SIZE NRFX_USBD_EPSIZE + +/** + * @name Macros for creating endpoint identifiers. + * + * Auxiliary macros for creating endpoint identifiers compatible with the USB specification. + * @{ + * @brief Create identifier for IN endpoint. + * + * Simple macro to create IN endpoint identifier for given endpoint number. + * + * @param[in] n Endpoint number. + * + * @return Endpoint identifier that connects endpoint number and endpoint direction. + */ +#define NRFX_USBD_EPIN(n) ((nrfx_usbd_ep_t)NRF_USBD_EPIN(n)) +/** + * @brief Create identifier for OUT endpoint. + * + * Simple macro to create OUT endpoint identifier for given endpoint number. + * + * @param[in] n Endpoint number. + * + * @return Endpoint identifier that connects endpoint number and endpoint direction. + */ +#define NRFX_USBD_EPOUT(n) ((nrfx_usbd_ep_t)NRF_USBD_EPOUT(n)) +/** @} */ + +/** + * @brief Endpoint identifier. + * + * Endpoint identifier used in the driver. + * This endpoint number is consistent with USB 2.0 specification. + */ +typedef enum +{ + NRFX_USBD_EPOUT0 = NRF_USBD_EPOUT(0), /**< Endpoint OUT 0 */ + NRFX_USBD_EPOUT1 = NRF_USBD_EPOUT(1), /**< Endpoint OUT 1 */ + NRFX_USBD_EPOUT2 = NRF_USBD_EPOUT(2), /**< Endpoint OUT 2 */ + NRFX_USBD_EPOUT3 = NRF_USBD_EPOUT(3), /**< Endpoint OUT 3 */ + NRFX_USBD_EPOUT4 = NRF_USBD_EPOUT(4), /**< Endpoint OUT 4 */ + NRFX_USBD_EPOUT5 = NRF_USBD_EPOUT(5), /**< Endpoint OUT 5 */ + NRFX_USBD_EPOUT6 = NRF_USBD_EPOUT(6), /**< Endpoint OUT 6 */ + NRFX_USBD_EPOUT7 = NRF_USBD_EPOUT(7), /**< Endpoint OUT 7 */ + NRFX_USBD_EPOUT8 = NRF_USBD_EPOUT(8), /**< Endpoint OUT 8 */ + + NRFX_USBD_EPIN0 = NRF_USBD_EPIN(0), /**< Endpoint IN 0 */ + NRFX_USBD_EPIN1 = NRF_USBD_EPIN(1), /**< Endpoint IN 1 */ + NRFX_USBD_EPIN2 = NRF_USBD_EPIN(2), /**< Endpoint IN 2 */ + NRFX_USBD_EPIN3 = NRF_USBD_EPIN(3), /**< Endpoint IN 3 */ + NRFX_USBD_EPIN4 = NRF_USBD_EPIN(4), /**< Endpoint IN 4 */ + NRFX_USBD_EPIN5 = NRF_USBD_EPIN(5), /**< Endpoint IN 5 */ + NRFX_USBD_EPIN6 = NRF_USBD_EPIN(6), /**< Endpoint IN 6 */ + NRFX_USBD_EPIN7 = NRF_USBD_EPIN(7), /**< Endpoint IN 7 */ + NRFX_USBD_EPIN8 = NRF_USBD_EPIN(8), /**< Endpoint IN 8 */ +} nrfx_usbd_ep_t; + +/** + * @brief Events generated by the driver. + * + * Enumeration of possible events that may be generated by the driver. + */ +typedef enum +{ + NRFX_USBD_EVT_SOF, /**< Start Of Frame event on USB bus detected. */ + NRFX_USBD_EVT_RESET, /**< Reset condition on USB bus detected. */ + NRFX_USBD_EVT_SUSPEND, /**< This device should go to suspend mode now. */ + NRFX_USBD_EVT_RESUME, /**< This device should resume from suspend now. */ + NRFX_USBD_EVT_WUREQ, /**< Wakeup request - the USBD peripheral is ready to generate + WAKEUP signal after exiting low power mode. */ + NRFX_USBD_EVT_SETUP, /**< Setup frame received and decoded. */ + NRFX_USBD_EVT_EPTRANSFER, /**< For Rx (OUT: Host->Device): + * 1. The packet has been received but there is no buffer prepared for transfer already. + * 2. Whole transfer has been finished. + * + * For Tx (IN: Device->Host): + * The last packet from requested transfer has been transfered over USB bus and acknowledged. + */ + NRFX_USBD_EVT_CNT /**< Number of defined events. */ +} nrfx_usbd_event_type_t; + +/** + * @brief Possible endpoint error codes. + * + * Error codes that may be returned with @ref NRFX_USBD_EVT_EPTRANSFER. + */ +typedef enum +{ + NRFX_USBD_EP_OK, /**< No error */ + NRFX_USBD_EP_WAITING, /**< Data received, no buffer prepared already - waiting for configured transfer. */ + NRFX_USBD_EP_OVERLOAD, /**< Received number of bytes cannot fit given buffer. + * This error would also be returned when next_transfer function has been defined + * but currently received data cannot fit completely in current buffer. + * No data split from single endpoint transmission is supported. + * + * When this error is reported - data is left inside endpoint buffer. + * Clear endpoint or prepare new buffer and read it. + */ + NRFX_USBD_EP_ABORTED, /**< EP0 transfer can be aborted when new setup comes. + * Any other transfer can be aborted by USB reset or driver stopping. + */ +} nrfx_usbd_ep_status_t; + +/** + * @brief Event structure. + * + * Structure passed to event handler. + */ +typedef struct +{ + nrfx_usbd_event_type_t type; + union + { + struct { + uint16_t framecnt; /**< Current value of frame counter. */ + } sof; /**< Data available for @ref NRFX_USBD_EVT_SOF. */ + struct { + nrfx_usbd_ep_t ep; /**< Endpoint number. */ + } isocrc; + struct { + nrfx_usbd_ep_t ep; /**< Endpoint number. */ + nrfx_usbd_ep_status_t status; /**< Status for the endpoint. */ + } eptransfer; + } data; +} nrfx_usbd_evt_t; + +/** + * @brief USBD event callback function type. + * + * @param[in] p_event Event information structure. + */ +typedef void (*nrfx_usbd_event_handler_t)(nrfx_usbd_evt_t const * p_event); + +/** + * @brief Universal data pointer. + * + * Universal data pointer that can be used for any type of transfer. + */ +typedef union +{ + void const * tx; //!< Constant TX buffer pointer. + void * rx; //!< Writable RX buffer pointer. + uint32_t addr; //!< Numeric value used internally by the driver. +} nrfx_usbd_data_ptr_t; + +/** + * @brief Structure to be filled with information about the next transfer. + * + * This is used mainly for transfer feeders and consumers. + * It describes a single endpoint transfer and therefore the size of the buffer + * can never be higher than the endpoint size. + */ +typedef struct +{ + nrfx_usbd_data_ptr_t p_data; //!< Union with available data pointers used by the driver. + size_t size; //!< Size of the requested transfer. +} nrfx_usbd_ep_transfer_t; + +/** + * @brief Flags for the current transfer. + * + * Flags configured for the transfer that can be merged using the bitwise 'or' operator (|). + */ +typedef enum +{ + NRFX_USBD_TRANSFER_ZLP_FLAG = 1U << 0, //!< Add a zero-length packet. +} nrfx_usbd_transfer_flags_t; + +/** + * @brief Total transfer configuration. + * + * This structure is used to configure total transfer information. + * It is used by internal built-in feeders and consumers. + */ +typedef struct +{ + nrfx_usbd_data_ptr_t p_data; //!< Union with available data pointers used by the driver. + size_t size; //!< Total size of the requested transfer. + uint32_t flags; //!< Transfer flags. + /**< Use the @ref nrfx_usbd_transfer_flags_t values. */ +} nrfx_usbd_transfer_t; + +/** + * @brief Auxiliary macro for declaring IN transfer description with optional flags. + * + * The base macro for creating transfers with any configuration option. + * + * @param name Instance name. + * @param tx_buff Buffer to transfer. + * @param tx_size Transfer size. + * @param tx_flags Flags for the transfer (see @ref nrfx_usbd_transfer_flags_t). + * + * @return Configured variable with total transfer description. + */ +#define NRFX_USBD_TRANSFER_IN(name, tx_buff, tx_size, tx_flags) \ + const nrfx_usbd_transfer_t name = { \ + .p_data = { .tx = (tx_buff) }, \ + .size = (tx_size), \ + .flags = (tx_flags) \ + } + +/** + * @brief Helper macro for declaring OUT transfer item (@ref nrfx_usbd_transfer_t). + * + * @param name Instance name. + * @param rx_buff Buffer to transfer. + * @param rx_size Transfer size. + * */ +#define NRFX_USBD_TRANSFER_OUT(name, rx_buff, rx_size) \ + const nrfx_usbd_transfer_t name = { \ + .p_data = { .rx = (rx_buff) }, \ + .size = (rx_size), \ + .flags = 0 \ + } + +/** + * @brief USBD transfer feeder. + * + * Pointer for a transfer feeder. + * Transfer feeder is a feedback function used to prepare a single + * TX (Device->Host) endpoint transfer. + * + * The transfers provided by the feeder must be simple: + * - The size of the transfer provided by this function is limited to a single endpoint buffer. + * Bigger transfers are not handled automatically in this case. + * - Flash transfers are not automatically supported- you must copy them to the RAM buffer before. + * + * @note + * This function may use @ref nrfx_usbd_feeder_buffer_get to gain a temporary buffer + * that can be used to prepare transfer. + * + * @param[out] p_next Structure with the data for the next transfer to be filled. + * Required only if the function returns true. + * @param[in,out] p_context Context variable configured with the transfer. + * @param[in] ep_size The endpoint size. + * + * @retval false The current transfer is the last one - you do not need to call + * the function again. + * @retval true There is more data to be prepared and when the current transfer + * finishes, the feeder function is expected to be called again. + */ +typedef bool (*nrfx_usbd_feeder_t)(nrfx_usbd_ep_transfer_t * p_next, + void * p_context, + size_t ep_size); + +/** + * @brief USBD transfer consumer. + * + * Pointer for a transfer consumer. + * Transfer consumer is a feedback function used to prepare a single + * RX (Host->Device) endpoint transfer. + * + * The transfer must provide a buffer big enough to fit the whole data from the endpoint. + * Otherwise, the NRFX_USBD_EP_OVERLOAD event is generated. + * + * @param[out] p_next Structure with the data for the next transfer to be filled. + * Required only if the function returns true. + * @param[in,out] p_context Context variable configured with the transfer. + * @param[in] ep_size The endpoint size. + * @param[in] data_size Number of received bytes in the endpoint buffer. + * + * @retval false Current transfer is the last one - you do not need to call + * the function again. + * @retval true There is more data to be prepared and when current transfer + * finishes, the feeder function is expected to be called again. + */ +typedef bool (*nrfx_usbd_consumer_t)(nrfx_usbd_ep_transfer_t * p_next, + void * p_context, + size_t ep_size, + size_t data_size); + +/** + * @brief Universal transfer handler. + * + * Union with feeder and consumer function pointer. + */ +typedef union +{ + nrfx_usbd_feeder_t feeder; //!< Feeder function pointer. + nrfx_usbd_consumer_t consumer; //!< Consumer function pointer. +} nrfx_usbd_handler_t; + +/** + * @brief USBD transfer descriptor. + * + * Universal structure that may hold the setup for callback configuration for + * IN or OUT type of the transfer. + */ +typedef struct +{ + nrfx_usbd_handler_t handler; //!< Handler for the current transfer, function pointer. + void * p_context; //!< Context for the transfer handler. +} nrfx_usbd_handler_desc_t; + +/** + * @brief Setup packet structure. + * + * Structure that contains interpreted SETUP packet as described in USB specification. + */ +typedef struct +{ + uint8_t bmRequestType; //!< byte 0 + uint8_t bmRequest; //!< byte 1 + uint16_t wValue; //!< byte 2, 3 + uint16_t wIndex; //!< byte 4, 5 + uint16_t wLength; //!< byte 6, 7 +} nrfx_usbd_setup_t; + +/** + * @brief Driver initialization. + * + * @param[in] event_handler Event handler provided by the user. Cannot be null. + * + * @retval NRFX_SUCCESS Initialization successful. + * @retval NRFX_ERROR_INVALID_STATE Driver was already initialized. + */ +nrfx_err_t nrfx_usbd_init(nrfx_usbd_event_handler_t event_handler); + +/** + * @brief Driver deinitialization. + */ +void nrfx_usbd_uninit(void); + +/** + * @brief Enable the USBD port. + * + * After calling this function USBD peripheral would be enabled. + * The USB LDO would be enabled. + * Enabled USBD peripheral would request HFCLK. + * This function does not enable external oscillator, so if it is not enabled by other part of the + * program after enabling USBD driver HFINT would be used for the USBD peripheral. + * It is perfectly fine until USBD is started. See @ref nrfx_usbd_start. + * + * In normal situation this function should be called in reaction to USBDETECTED + * event from POWER peripheral. + * + * Interrupts and USB pins pull-up would stay disabled until @ref nrfx_usbd_start + * function is called. + */ +void nrfx_usbd_enable(void); + +/** + * @brief Disable the USBD port. + * + * After calling this function USBD peripheral would be disabled. + * No events would be detected or processed by the driver. + * Clock for the peripheral would be disconnected. + */ +void nrfx_usbd_disable(void); + +/** + * @brief Start USB functionality. + * + * After calling this function USBD peripheral should be fully functional + * and all new incoming events / interrupts would be processed by the driver. + * + * Also only after calling this function host sees new connected device. + * + * Call this function when USBD power LDO regulator is ready - on USBPWRRDY event + * from POWER peripheral. + * + * Before USBD interrupts are enabled, external HFXO is requested. + * + * @param enable_sof The flag that is used to enable SOF processing. + * If it is false, SOF interrupt is left disabled and will not be generated. + * This improves power saving if SOF is not required. + * + * @note If the isochronous endpoints are going to be used, + * it is required to enable the SOF. + * In other case any isochronous endpoint would stay busy + * after first transmission. + */ +void nrfx_usbd_start(bool enable_sof); + +/** + * @brief Stop USB functionality. + * + * This function disables USBD pull-up and interrupts. + * + * The HFXO request is released in this function. + * + * @note + * This function can also be used to logically disconnect USB from the HOST that + * would force it to enumerate device after calling @ref nrfx_usbd_start. + */ +void nrfx_usbd_stop(void); + +/** + * @brief Check if driver is initialized. + * + * @retval false Driver is not initialized. + * @retval true Driver is initialized. + */ +bool nrfx_usbd_is_initialized(void); + +/** + * @brief Check if driver is enabled. + * + * @retval false Driver is disabled. + * @retval true Driver is enabled. + */ +bool nrfx_usbd_is_enabled(void); + +/** + * @brief Check if driver is started. + * + * @retval false Driver is not started. + * @retval true Driver is started (fully functional). + * @note The USBD peripheral interrupt state is checked. + */ +bool nrfx_usbd_is_started(void); + +/** + * @brief Suspend USBD operation. + * + * The USBD peripheral is forced to go into the low power mode. + * The function has to be called in the reaction to @ref NRFX_USBD_EVT_SUSPEND event + * when the firmware is ready. + * + * After successful call of this function most of the USBD registers would be unavailable. + * + * @note Check returned value for the feedback if suspending was successful. + * + * @retval true USBD peripheral successfully suspended. + * @retval false USBD peripheral was not suspended due to resume detection. + */ +bool nrfx_usbd_suspend(void); + +/** + * @brief Start wake up procedure. + * + * The USBD peripheral is forced to quit the low power mode. + * After calling this function all the USBD registers would be available. + * + * The hardware starts measuring time when wake up is possible. + * This may take 0-5 ms depending on how long the SUSPEND state was kept on the USB line. + + * When NRFX_USBD_EVT_WUREQ event is generated it means that Wake Up signaling has just been + * started on the USB lines. + * + * @note Do not expect only @ref NRFX_USBD_EVT_WUREQ event. + * There always may appear @ref NRFX_USBD_EVT_RESUME event. + * @note NRFX_USBD_EVT_WUREQ event means that Remote WakeUp signal + * has just begun to be generated. + * This may take up to 20 ms for the bus to become active. + * + * @retval true WakeUp procedure started. + * @retval false No WakeUp procedure started - bus is already active. + */ +bool nrfx_usbd_wakeup_req(void); + +/** + * @brief Check if USBD is in SUSPEND mode. + * + * @note This is the information about peripheral itself, not about the bus state. + * + * @retval true USBD peripheral is suspended. + * @retval false USBD peripheral is active. + */ +bool nrfx_usbd_suspend_check(void); + +/** + * @brief Enable only interrupts that should be processed in SUSPEND mode. + * + * Auxiliary function to help with SUSPEND mode integration. + * It enables only the interrupts that can be properly processed without stable HFCLK. + * + * Normally all the interrupts are enabled. + * Use this function to suspend interrupt processing that may require stable HFCLK until the + * clock is enabled. + * + * @sa nrfx_usbd_active_irq_config + */ +void nrfx_usbd_suspend_irq_config(void); + +/** + * @brief Default active interrupt configuration. + * + * Default interrupt configuration. + * Use in a pair with @ref nrfx_usbd_active_irq_config. + * + * @sa nrfx_usbd_suspend_irq_config + */ +void nrfx_usbd_active_irq_config(void); + +/** + * @brief Check the bus state. + * + * This function checks if the bus state is suspended. + * + * @note The value returned by this function changes on SUSPEND and RESUME event processing. + * + * @retval true USBD bus is suspended. + * @retval false USBD bus is active. + */ +bool nrfx_usbd_bus_suspend_check(void); + +/** + * @brief Force the bus state to active + */ +void nrfx_usbd_force_bus_wakeup(void); + +/** + * @brief Configure packet size that should be supported by the endpoint. + * + * The real endpoint buffer size is always the same. + * This value sets max packet size that would be transmitted over the endpoint. + * This is required by the driver. + * + * @param[in] ep Endpoint number. + * @param[in] size Required maximum packet size. + * + * @note Endpoint size is always set to @ref NRFX_USBD_EPSIZE or @ref NRFX_USBD_ISOSIZE / 2 + * when @ref nrfx_usbd_ep_enable function is called. + */ +void nrfx_usbd_ep_max_packet_size_set(nrfx_usbd_ep_t ep, uint16_t size); + +/** + * @brief Get configured endpoint packet size. + * + * Function to get configured endpoint size on the buffer. + * + * @param[in] ep Endpoint number. + * + * @return Maximum pocket size configured on selected endpoint. + */ +uint16_t nrfx_usbd_ep_max_packet_size_get(nrfx_usbd_ep_t ep); + +/** + * @brief Check if the selected endpoint is enabled. + * + * @param[in] ep Endpoint number to check. + * + * @retval true Endpoint is enabled. + * @retval false Endpoint is disabled. + */ +bool nrfx_usbd_ep_enable_check(nrfx_usbd_ep_t ep); + +/** + * @brief Enable selected endpoint. + * + * This function enables endpoint itself and its interrupts. + * + * @param[in] ep Endpoint number to enable. + * + * @note + * Max packet size is set to endpoint default maximum value. + * + * @sa nrfx_usbd_ep_max_packet_size_set + */ +void nrfx_usbd_ep_enable(nrfx_usbd_ep_t ep); + +/** + * @brief Disable selected endpoint. + * + * This function disables endpoint itself and its interrupts. + * + * @param[in] ep Endpoint number to disable. + */ +void nrfx_usbd_ep_disable(nrfx_usbd_ep_t ep); + +/** + * @brief Disable all endpoints except for EP0. + * + * Disable all endpoints that can be disabled in USB device while it is still active. + */ +void nrfx_usbd_ep_default_config(void); + +/** + * @brief Start sending data over endpoint. + * + * Function initializes endpoint transmission. + * This is asynchronous function - it finishes immediately after configuration + * for transmission is prepared. + * + * @note Data buffer pointed by p_data have to be kept active till + * @ref NRFX_USBD_EVT_EPTRANSFER event is generated. + * + * @param[in] ep Endpoint number. + * For IN endpoint sending would be initiated. + * For OUT endpoint receiving would be initiated. + * @param[in] p_transfer Transfer parameters. + * + * @retval NRFX_SUCCESS Transfer queued or started. + * @retval NRFX_ERROR_BUSY Selected endpoint is pending. + * @retval NRFX_ERROR_INVALID_ADDR Unexpected transfer on EPIN0 or EPOUT0. + */ +nrfx_err_t nrfx_usbd_ep_transfer(nrfx_usbd_ep_t ep, + nrfx_usbd_transfer_t const * p_transfer); + +/** + * @brief Start sending data over the endpoint using the transfer handler function. + * + * This function initializes an endpoint transmission. + * Just before data is transmitted, the transfer handler + * is called and it prepares a data chunk. + * + * @param[in] ep Endpoint number. + * For an IN endpoint, sending is initiated. + * For an OUT endpoint, receiving is initiated. + * @param[in] p_handler Transfer handler - feeder for IN direction and consumer for + * OUT direction. + * + * @retval NRFX_SUCCESS Transfer queued or started. + * @retval NRFX_ERROR_BUSY Selected endpoint is pending. + * @retval NRFX_ERROR_INVALID_ADDR Unexpected transfer on EPIN0 or EPOUT0. + */ +nrfx_err_t nrfx_usbd_ep_handled_transfer(nrfx_usbd_ep_t ep, + nrfx_usbd_handler_desc_t const * p_handler); + +/** + * @brief Get the temporary buffer to be used by the feeder. + * + * This buffer is used for TX transfers and it can be reused automatically + * when the transfer is finished. + * Use it for transfer preparation. + * + * May be used inside the feeder configured in @ref nrfx_usbd_ep_handled_transfer. + * + * @return Pointer to the buffer that can be used temporarily. + * + * @sa NRFX_USBD_FEEDER_BUFFER_SIZE + */ +void * nrfx_usbd_feeder_buffer_get(void); + +/** + * @brief Get the information about last finished or current transfer. + * + * Function returns the status of the last buffer set for transfer on selected endpoint. + * The status considers last buffer set by @ref nrfx_usbd_ep_transfer function or + * by transfer callback function. + * + * @param[in] ep Endpoint number. + * @param[out] p_size Information about the current/last transfer size. + * + * @retval NRFX_SUCCESS Transfer already finished. + * @retval NRFX_ERROR_BUSY Ongoing transfer. + * @retval NRFX_ERROR_DATA_SIZE Too much of data received that cannot fit into buffer and cannot be splited into chunks. + * This may happen if buffer size is not a multiplication of endpoint buffer size. + */ +nrfx_err_t nrfx_usbd_ep_status_get(nrfx_usbd_ep_t ep, size_t * p_size); + +/** + * @brief Get number of received bytes. + * + * Get the number of received bytes. + * The function behavior is undefined when called on IN endpoint. + * + * @param[in] ep Endpoint number. + * + * @return Number of received bytes. + */ +size_t nrfx_usbd_epout_size_get(nrfx_usbd_ep_t ep); + +/** + * @brief Check if endpoint buffer is ready or is under USB IP control. + * + * Function to test if endpoint is busy. + * Endpoint that is busy cannot be accessed by MCU. + * It means that: + * - OUT (TX) endpoint: Last uploaded data is still in endpoint and is waiting + * to be received by the host. + * - IN (RX) endpoint: Endpoint is ready to receive data from the host + * and the endpoint does not have any data. + * When endpoint is not busy: + * - OUT (TX) endpoint: New data can be uploaded. + * - IN (RX) endpoint: New data can be downloaded using @ref nrfx_usbd_ep_transfer + * function. + * + * @param[in] ep Endpoint number. + * + * @retval false Endpoint is not busy. + * @retval true Endpoint is busy. + */ +bool nrfx_usbd_ep_is_busy(nrfx_usbd_ep_t ep); + +/** + * @brief Stall endpoint + * + * Stall endpoit to send error information during next transfer request from + * the host. + * + * @note To stall endpoint it is safer to use @ref nrfx_usbd_setup_stall + * @note Stalled endpoint would not be cleared when DMA transfer finishes. + * + * @param[in] ep Endpoint number to stall. + */ +void nrfx_usbd_ep_stall(nrfx_usbd_ep_t ep); + +/** + * @brief Clear stall flag on endpoint. + * + * This function clears endpoint that is stalled. + * @note + * If it is OUT endpoint (receiving) it would be also prepared for reception. + * It means that busy flag would be set. + * @note + * In endpoint (transmitting) would not be cleared - it gives possibility to + * write new data before transmitting. + * + * @param[in] ep Endpoint number. + */ +void nrfx_usbd_ep_stall_clear(nrfx_usbd_ep_t ep); + +/** + * @brief Check if endpoint is stalled. + * + * This function gets stall state of selected endpoint. + * + * @param[in] ep Endpoint number to check. + * + * @retval false Endpoint is not stalled. + * @retval true Endpoint is stalled. + */ +bool nrfx_usbd_ep_stall_check(nrfx_usbd_ep_t ep); + +/** + * @brief Clear current endpoint data toggle. + * + * @param[in] ep Endpoint number to clear. + */ +void nrfx_usbd_ep_dtoggle_clear(nrfx_usbd_ep_t ep); + +/** + * @brief Get parsed setup data. + * + * Function fills the parsed setup data structure. + * + * @param[out] p_setup Pointer to data structure that would be filled by + * parsed data. + */ +void nrfx_usbd_setup_get(nrfx_usbd_setup_t * p_setup); + +/** + * @brief Clear the control endpoint for packet reception during DATA stage. + * + * This function may be called if any more data in control write transfer is expected. + * Clears only OUT endpoint to be able to take another OUT data token. + * It does not allow STATUS stage. + * @sa nrfx_usbd_setup_clear + */ +void nrfx_usbd_setup_data_clear(void); + +/** + * @brief Clear setup endpoint. + * + * This function acknowledges setup when SETUP command was received and processed. + * It has to be called if no data respond for the SETUP command is sent. + */ +void nrfx_usbd_setup_clear(void); + +/** + * @brief Stall setup endpoint. + * + * Mark an error on setup endpoint. + */ +void nrfx_usbd_setup_stall(void); + +/** + * @brief Abort pending transfer on selected endpoint. + * + * @param[in] ep Endpoint number. + */ +void nrfx_usbd_ep_abort(nrfx_usbd_ep_t ep); + +/** + * @brief Get the information about expected transfer SETUP data direction. + * + * Function returns the information about last expected transfer direction. + * + * @retval NRFX_USBD_EPOUT0 Expecting OUT (Host->Device) direction or no data. + * @retval NRFX_USBD_EPIN0 Expecting IN (Device->Host) direction. + */ +nrfx_usbd_ep_t nrfx_usbd_last_setup_dir_get(void); + +/** + * @brief Drop transfer on OUT endpoint. + * + * @param[in] ep OUT endpoint ID. + */ +void nrfx_usbd_transfer_out_drop(nrfx_usbd_ep_t ep); + + +void nrfx_usbd_irq_handler(void); + + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif // NRFX_USBD_H__ diff --git a/drivers/nrfx_common.h b/drivers/nrfx_common.h index 40b73fe35..537f1ef6c 100644 --- a/drivers/nrfx_common.h +++ b/drivers/nrfx_common.h @@ -117,6 +117,27 @@ extern "C" { */ #define NRFX_ROUNDED_DIV(a, b) (((a) + ((b) / 2)) / (b)) +/**@brief Macro for performing integer division, making sure the result is rounded up. + * + * @details A typical use case for this macro is to compute the number of objects + * with size @c b required to hold @c a number of bytes. + * + * @param a Numerator. + * @param b Denominator. + * + * @return Integer result of dividing @c a by @c b, rounded up. + */ +#define NRFX_CEIL_DIV(a, b) ((((a) - 1) / (b)) + 1) + +/** + * @brief Macro for getting the number of elements in an array. + * + * @param array Name of the array. + * + * @return Array element count. + */ +#define NRFX_ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) + /**@brief Macro for checking if given lengths of EasyDMA transfers do not exceed * the limit of the specified peripheral. * diff --git a/drivers/src/nrfx_nfct.c b/drivers/src/nrfx_nfct.c new file mode 100644 index 000000000..3a52e2aab --- /dev/null +++ b/drivers/src/nrfx_nfct.c @@ -0,0 +1,884 @@ +/* + * Copyright (c) 2018, Nordic Semiconductor ASA + * All rights reserved. + * + * 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 + +#if NRFX_CHECK(NRFX_NFCT_ENABLED) + +#include + +#define NRFX_LOG_MODULE NFCT +#include + +#if defined(NRF52832_XXAA) || defined(NRF52832_XXAB) || defined(NRF52840_XXAA) +#define USE_TIMER_WORKAROUND +#endif + +#ifdef USE_TIMER_WORKAROUND +#include + +typedef struct +{ + const nrfx_timer_t timer; /**< Timer instance that supports the correct NFC field detection. */ +#ifdef NRF52840_XXAA + 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. */ +#else + uint32_t field_state_cnt; /**< Counter of the FIELDLOST events. */ +#endif // NRF52840_XXAA +} nrfx_nfct_timer_workaround_t; + +#ifdef NRF52840_XXAA + #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 +#else + #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 // NRF52840_XXAA +#define NRFX_NFCT_TIMER_INSTANCE 4 /**< Timer instance used for various workarounds for the NFCT HW issues.*/ + +static nrfx_nfct_timer_workaround_t m_timer_workaround = +{ + .timer = NRFX_TIMER_INSTANCE(NRFX_NFCT_TIMER_INSTANCE), +}; +#endif // USE_TIMER_WORKAROUND + +#define NRFX_NFCT_FRAMEDELAYMAX_52840S (0xFFFFUL) /**< Bit mask of the FRAMEDELAYMAX field for the first sample of 52840.*/ +#define NRFX_NFCT_FWT_MAX_DIFF 1u /**< The maximal difference between the requested FWT and HW-limited FWT settings.*/ + +/* 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(NRFX_CONCAT_2(NRF_NFCT_EVENT_, _name)) && \ + nrf_nfct_int_enable_check(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; + +#ifdef NRF52840_XXAA +/** + * @brief Internal auxiliary function for checking whether the program is running on the NRF52840 chip. + * + * @retval true It is NRF52480 chip. + * @retval false It is an other chip. + */ +static inline bool nrfx_nfct_type_52840_check(void) +{ + return ((((*(uint32_t *)0xF0000FE0) & 0xFF) == 0x08) && + (((*(uint32_t *)0xF0000FE4) & 0x0F) == 0x0)); +} + +/** + * @brief Internal auxiliary function for checking whether the program is running on the first sample of + * the nRF52840 chip. + * + * @retval true It is the nRF52480 chip and it is the first sample version. + * @retval false It is an other chip. + */ +static inline bool nrfx_nfct_type_52840_sample_check(void) +{ + return ( nrfx_nfct_type_52840_check() && + ( ((*(uint32_t *)0xF0000FE8) & 0xF0) == 0x00 ) && + ( ((*(uint32_t *)0xF0000FEC) & 0xF0) == 0x00 ) ); +} + +/** + * @brief Internal auxiliary function for checking whether the program is running on the final version of + * the nRF52840 chip. + * + * @retval true It is the nRF52480 chip and it is the final version. + * @retval false It is an other chip. + */ +static inline bool nrfx_nfct_type_52840_final_check(void) +{ + return ( nrfx_nfct_type_52840_check() && + ( ( ((*(uint32_t *)0xF0000FE8) & 0xF0) != 0x00 ) || + ( ((*(uint32_t *)0xF0000FEC) & 0xF0) != 0x00 ) )); +} + +typedef struct +{ + bool eng_a; /**< Engineering sample A of the NRF52840 chip. */ + bool eng_bc; /**< Engineering sample B, C of the NRF52840 chip, or its final version. */ +} nrfx_nfct_nrf52840_ver_t; + +static nrfx_nfct_nrf52840_ver_t m_nrf52840; +#endif // NRF52840_XXAA + +/**@brief NFCT control block. */ +typedef struct +{ + nrfx_nfct_config_t config; + nrfx_drv_state_t state; + volatile bool field_on; +} 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) +{ +#ifdef NRF52840_XXAA + if (m_nrf52840.eng_a) + { + /* Begin: Bugfix for FTPAN-98 */ + *(volatile uint32_t *) 0x4000568C = 0x00038148; + /* End: Bugfix for FTPAN-98 */ + /* Begin: Bugfix for FTPAN-144 */ + *(volatile uint32_t *) 0x4000561c = 0x01; + *(volatile uint32_t *) 0x4000562c = 0x3F; + *(volatile uint32_t *) 0x4000563c = 0x0; + /* End: Bugfix for FTPAN-144 */ + } +#endif // NRF52840_XXAA + + //Enable necessary interrupts. + nrf_nfct_int_enable(NRF_NFCT_INT_FIELDDETECTED_MASK | NRF_NFCT_INT_ERROR_MASK | + NRF_NFCT_INT_SELECTED_MASK); +#if !defined(NRF52832_XXAA) && !defined(NRF52832_XXAB) + nrf_nfct_int_enable(NRF_NFCT_INT_FIELDLOST_MASK); +#endif //!defined(NRF52832_XXAA) && !defined(NRF52832_XXAB) + + // Use Window Grid frame delay mode. + nrf_nfct_frame_delay_mode_set(NRF_NFCT_FRAME_DELAY_MODE_WINDOWGRID); + + /* Begin: Bugfix for FTPAN-25 (IC-9929) */ + /* 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_SENSRES_BIT_FRAME_SDD_00100); + /* End: Bugfix for FTPAN-25 (IC-9929) */ +} + +/**@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; + +#ifdef NRF52840_XXAA + if((!m_nrf52840.eng_a) && (m_timer_workaround.fieldevents_filter_active)) + { + return; + } +#endif // NRF52840_XXAA + + 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 */ + switch (field_state) + { + case NRFX_NFC_FIELD_STATE_ON: + if (!m_nfct_cb.field_on) + { +#ifdef NRF52840_XXAA + /* Begin: Bugfix for FTPAN-190 */ + if (!m_nrf52840.eng_a) + { + 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); + } + /* END: Bugfix for FTPAN-190 */ +#elif defined(NRF52832_XXAA) || defined(NRF52832_XXAB) + nrfx_timer_clear(&m_timer_workaround.timer); + nrfx_timer_enable(&m_timer_workaround.timer); + m_timer_workaround.field_state_cnt = 0; +#endif // NRF52840_XXAA + + 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: + nrfx_nfct_state_force(NRFX_NFCT_STATE_SENSING); +#ifdef NRF52840_XXAA + /* Begin: Bugfix for FTPAN-116 (IC-12886) */ + if (m_nrf52840.eng_a) + { + *(volatile uint32_t *)0x40005010 = 1; + } + /* END: Bugfix for FTPAN-116 (IC-12886) */ +#endif // NRF52840_XXAA + nrf_nfct_int_disable(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; + + NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt); + break; + + default: + /* No implementation required */ + break; + } +} + +#ifdef USE_TIMER_WORKAROUND + +#ifdef NRF52840_XXAA +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_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 // NRF52840_XXAA + +#if defined(NRF52832_XXAA) || defined(NRF52832_XXAB) +static inline void nrfx_nfct_reset(void) +{ + uint32_t fdm; + 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. + fdm = nrf_nfct_frame_delay_max_get(); + nfcid1_size = nrf_nfct_nfcid1_get(nfcid1); + protocol = nrf_nfct_selsres_protocol_get(); + + // 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(fdm); + nrf_nfct_nfcid1_set(nfcid1, nfcid1_size); + nrf_nfct_selres_protocol_set(protocol); + + // Restore general HW configuration. + nrfx_nfct_hw_init_setup(); + NRFX_LOG_INFO("Reinitialize"); +} + +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; + + /* Begin: Bugfix for FTPAN-116 */ + // resume the NFCT to initialized state + nrfx_nfct_reset(); + /* End: Bugfix for FTPAN-116 */ + + NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt); + } + return; + } + + m_timer_workaround.field_state_cnt = 0; +} +#endif // defined(NRF52832_XXAA) || defined(NRF52832_XXAB) + +static void nrfx_nfct_field_timer_handler(nrf_timer_event_t event_type, void * p_context) +{ + UNUSED_PARAMETER(p_context); + + if (event_type != NRF_TIMER_EVENT_COMPARE0) + { + return; + } + +#ifdef NRF52840_XXAA + m_timer_workaround.is_delayed = true; + + nrfx_timer_disable(&m_timer_workaround.timer); + nrfx_nfct_activate_check(); +#else + nrfx_nfct_field_poll(); +#endif //NRF52840_XXAA +} + +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_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 // USE_TIMER_WORKAROUND + +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(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; + } + +#ifdef NRF52840_XXAA + m_nrf52840.eng_a = nrfx_nfct_type_52840_sample_check(); + m_nrf52840.eng_bc = nrfx_nfct_type_52840_final_check(); +#endif // NRF52840_XXAA + + memcpy(&m_nfct_cb.config, p_config, sizeof(nrfx_nfct_config_t)); + nrfx_nfct_hw_init_setup(); + +#ifdef USE_TIMER_WORKAROUND + /* Initialize Timer module as the workaround for NFCT HW issues. */ + #ifdef NRF52840_XXAA + if (!m_nrf52840.eng_a) + #endif // NRF52840_XXAA + { + err_code = nrfx_nfct_field_timer_config(); + } +#endif // USE_TIMER_WORKAROUND + + if (err_code == NRFX_SUCCESS) + { + uint8_t default_nfcid1[NRFX_NFCT_NFCID1_DEFAULT_LEN]; + err_code = nrfx_nfct_nfcid1_default_bytes_get(default_nfcid1, sizeof(default_nfcid1)); + NRFX_ASSERT(err_code == NRFX_SUCCESS); + nrf_nfct_nfcid1_set(default_nfcid1, NRF_NFCT_SENSRES_NFCID1_SIZE_DEFAULT); + } + else + { + return err_code; + } + + m_nfct_cb.state = NRFX_DRV_STATE_INITIALIZED; + + NRFX_LOG_INFO("Initialized"); + return err_code; +} + +void nrfx_nfct_uninit(void) +{ + nrfx_nfct_disable(); + +#ifdef USE_TIMER_WORKAROUND + /* Initialize Timer module as the workaround for NFCT HW issues. */ + #ifdef NRF52840_XXAA + if (!m_nrf52840.eng_a) + #endif // NRF52840_XXAA + { + nrfx_timer_uninit(&m_timer_workaround.timer); + } +#endif // USE_TIMER_WORKAROUND + + m_nfct_cb.state = NRFX_DRV_STATE_UNINITIALIZED; +} + +void nrfx_nfct_enable(void) +{ + nrf_nfct_error_status_clear(NRFX_NFCT_ERROR_STATUS_ALL_MASK); + nrf_nfct_task_trigger(NRF_NFCT_TASK_SENSE); + + NRFX_IRQ_PENDING_CLEAR(NFCT_IRQn); + NRFX_IRQ_PRIORITY_SET(NFCT_IRQn, NRFX_NFCT_CONFIG_IRQ_PRIORITY); + NRFX_IRQ_ENABLE(NFCT_IRQn); + + NRFX_LOG_INFO("Start"); +} + +void nrfx_nfct_disable(void) +{ + nrf_nfct_task_trigger(NRF_NFCT_TASK_DISABLE); + + NRFX_LOG_INFO("Stop"); +} + +bool nrfx_nfct_field_check(void) +{ + uint32_t const field_state = nrf_nfct_field_status_get(); + + 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((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_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); + + if (p_tx_data->data_size == 0) + { + return NRFX_ERROR_INVALID_LENGTH; + } + + nrf_nfct_rxtx_buffer_set((uint8_t *) p_tx_data->p_data, p_tx_data->data_size); + nrf_nfct_tx_bits_set(NRFX_NFCT_BYTES_TO_BITS(p_tx_data->data_size)); + nrf_nfct_frame_delay_mode_set((nrf_nfct_frame_delay_mode_t) delay_mode); + + nrfx_nfct_rxtx_int_enable(NRFX_NFCT_TX_INT_MASK); + nrf_nfct_task_trigger(NRF_NFCT_TASK_STARTTX); + + NRF_LOG_INFO("Tx start"); + return NRFX_SUCCESS; +} + +void nrfx_nfct_state_force(nrfx_nfct_state_t state) +{ +#ifdef NRF52840_XXAA + if ((m_nrf52840.eng_bc) && (state == NRFX_NFCT_STATE_ACTIVATED)) + { + m_timer_workaround.is_hfclk_on = true; + nrfx_nfct_activate_check(); + } +#endif + { + nrf_nfct_task_trigger((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_SLEEP_STATE_SLEEP_A) +#endif //defined(NRF52832_XXAA) || defined(NRF52832_XXAB) + { + // Default state is SLEEP_A + nrf_nfct_task_trigger(NRF_NFCT_TASK_GOSLEEP); + } + else + { + // Default state is IDLE + nrf_nfct_task_trigger(NRF_NFCT_TASK_GOIDLE); + } + } + else + { + nrf_nfct_task_trigger((nrf_nfct_task_t) sub_state); + } + + /* Disable TX/RX here (will be enabled at SELECTED) */ + nrf_nfct_int_disable(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; + +#ifdef NRF52840_XXAA + delay_thr = (m_nrf52840.eng_a) ? NRFX_NFCT_FRAMEDELAYMAX_52840S : delay_thr; +#endif // NRF52840_XXAA + + // Delay validation. + if (delay > (delay_thr + NRFX_NFCT_FWT_MAX_DIFF)) + { + return NRFX_ERROR_INVALID_PARAM; + } + + delay = (delay > delay_thr) ? delay_thr : delay; + nrf_nfct_frame_delay_max_set(delay); + 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_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(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; + } + + 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; + + 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: Bugfix for FTPAN-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: Bugfix for FTPAN-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(); +#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(); +#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_EVENT_FIELDDETECTED); + current_field = NRFX_NFC_FIELD_STATE_ON; + + NRFX_LOG_DEBUG("Field detected"); + } + +#if !defined(NRF52832_XXAA) && !defined(NRF52832_XXAB) + if (NRFX_NFCT_EVT_ACTIVE(FIELDLOST)) + { + nrf_nfct_event_clear(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 //!defined(NRF52832_XXAA) && !defined(NRF52832_XXAB) + + /* 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(RXFRAMEEND)) + { + nrf_nfct_event_clear(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(); + nfct_evt.params.rx_frameend.rx_data.data_size = NRFX_NFCT_BITS_TO_BYTES(nrf_nfct_rx_bits_get(true)); + + if (NRFX_NFCT_EVT_ACTIVE(RXERROR)) + { + nfct_evt.params.rx_frameend.rx_status = + (nrf_nfct_rx_frame_status_get() & NRFX_NFCT_FRAME_STATUS_RX_ALL_MASK); + nrf_nfct_event_clear(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(NRFX_NFCT_FRAME_STATUS_RX_ALL_MASK); + } + + NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt); + + /* Clear TXFRAMESTART EVENT so it can be checked in hal_nfc_send */ + nrf_nfct_event_clear(NRF_NFCT_EVENT_TXFRAMESTART); + + NRFX_LOG_DEBUG("Rx fend"); + } + + if (NRFX_NFCT_EVT_ACTIVE(TXFRAMEEND)) + { + nrf_nfct_event_clear(NRF_NFCT_EVENT_TXFRAMEEND); + + nrfx_nfct_evt_t nfct_evt = + { + .evt_id = NRFX_NFCT_EVT_TX_FRAMEEND + }; + + /* Disable TX END event to ignore frame transmission other than READ response */ + nrf_nfct_int_disable(NRFX_NFCT_TX_INT_MASK); + + NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt); + + NRFX_LOG_DEBUG("Tx fend"); + } + + if (NRFX_NFCT_EVT_ACTIVE(SELECTED)) + { + nrf_nfct_event_clear(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_EVENT_RXFRAMEEND); + nrf_nfct_event_clear(NRF_NFCT_EVENT_RXERROR); + nrf_nfct_event_clear(NRF_NFCT_EVENT_TXFRAMESTART); + nrf_nfct_event_clear(NRF_NFCT_EVENT_TXFRAMEEND); + + /* At this point any previous error status can be ignored. */ + nrf_nfct_rx_frame_status_clear(NRFX_NFCT_FRAME_STATUS_RX_ALL_MASK); + nrf_nfct_error_status_clear(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_event_clear(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_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(NRFX_NFCT_ERROR_STATUS_ALL_MASK); + } + + if (NRFX_NFCT_EVT_ACTIVE(TXFRAMESTART)) + { + nrf_nfct_event_clear(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(); + nfct_evt.params.tx_framestart.tx_data.data_size = NRFX_NFCT_BITS_TO_BYTES(nrf_nfct_tx_bits_get()); + + m_nfct_cb.config.cb(&nfct_evt); + } + } +} + +#endif // NRFX_CHECK(NRFX_NFCT_ENABLED) diff --git a/drivers/src/nrfx_power.c b/drivers/src/nrfx_power.c index 3d21ed724..194ce60f2 100644 --- a/drivers/src/nrfx_power.c +++ b/drivers/src/nrfx_power.c @@ -37,6 +37,7 @@ #if NRFX_CHECK(NRFX_CLOCK_ENABLED) extern bool nrfx_clock_irq_enabled; +extern void nrfx_clock_irq_handler(void); #endif /** @@ -294,4 +295,22 @@ void nrfx_power_irq_handler(void) #endif } +#if NRFX_CHECK(NRFX_CLOCK_ENABLED) +/* + * If both POWER and CLOCK drivers are used, a common IRQ handler function must + * be used that calls the handlers in these two drivers. This is because these + * two peripherals share one interrupt. + * This function is located here, not in a separate nrfx_power_clock.c file, + * so that it does not end up as the only symbol in a separate object when + * a library with nrfx is created. In such case, forcing a linker to use this + * function instead of another one defined as weak will require additional + * actions, and might be even impossible. + */ +void nrfx_power_clock_irq_handler(void) +{ + nrfx_power_irq_handler(); + nrfx_clock_irq_handler(); +} +#endif + #endif // NRFX_CHECK(NRFX_POWER_ENABLED) diff --git a/drivers/src/nrfx_power_clock.c b/drivers/src/nrfx_power_clock.c deleted file mode 100644 index 600f5368f..000000000 --- a/drivers/src/nrfx_power_clock.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA - * All rights reserved. - * - * 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 -#include -#include - - -#if NRFX_CHECK(NRFX_POWER_ENABLED) && NRFX_CHECK(NRFX_CLOCK_ENABLED) -void nrfx_power_clock_irq_handler(void) -{ - nrfx_power_irq_handler(); - nrfx_clock_irq_handler(); -} -#endif diff --git a/drivers/src/nrfx_usbd.c b/drivers/src/nrfx_usbd.c new file mode 100644 index 000000000..4bc9914de --- /dev/null +++ b/drivers/src/nrfx_usbd.c @@ -0,0 +1,2349 @@ +/* + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * All rights reserved. + * + * 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 + +#if NRFX_CHECK(NRFX_USBD_ENABLED) + +#include +#include "nrfx_usbd_errata.h" +#include /* Marker to delete when not required anymore: >> NRFX_USBD_ERRATA_ENABLE << */ +#include + +#define NRFX_LOG_MODULE USBD +#include + +#ifndef NRFX_USBD_EARLY_DMA_PROCESS +/* Try to process DMA request when endpoint transmission has been detected + * and just after last EasyDMA has been processed. + * It speeds up the transmission a little (about 10% measured) + * with a cost of more CPU power used. + */ +#define NRFX_USBD_EARLY_DMA_PROCESS 1 +#endif + +#ifndef NRFX_USBD_PROTO1_FIX_DEBUG +/* Debug information when events are fixed*/ +#define NRFX_USBD_PROTO1_FIX_DEBUG 1 +#endif + +#define NRFX_USBD_LOG_PROTO1_FIX_PRINTF(...) \ + do{ \ + if (NRFX_USBD_PROTO1_FIX_DEBUG){ NRFX_LOG_DEBUG(__VA_ARGS__); }\ + } while (0) + +#ifndef NRFX_USBD_STARTED_EV_ENABLE +#define NRFX_USBD_STARTED_EV_ENABLE 0 +#endif + +#ifndef NRFX_USBD_CONFIG_ISO_IN_ZLP +#define NRFX_USBD_CONFIG_ISO_IN_ZLP 0 +#endif + +#ifndef NRFX_USBD_ISO_DEBUG +/* Also generate information about ISOCHRONOUS events and transfers. + * Turn this off if no ISOCHRONOUS transfers are going to be debugged and this + * option generates a lot of useless messages. */ +#define NRFX_USBD_ISO_DEBUG 1 +#endif + +#ifndef NRFX_USBD_FAILED_TRANSFERS_DEBUG +/* Also generate debug information for failed transfers. + * It might be useful but may generate a lot of useless debug messages + * in some library usages (for example when transfer is generated and the + * result is used to check whatever endpoint was busy. */ +#define NRFX_USBD_FAILED_TRANSFERS_DEBUG 1 +#endif + +#ifndef NRFX_USBD_DMAREQ_PROCESS_DEBUG +/* Generate additional messages that mark the status inside + * @ref usbd_dmareq_process. + * It is useful to debug library internals but may generate a lot of + * useless debug messages. */ +#define NRFX_USBD_DMAREQ_PROCESS_DEBUG 1 +#endif + + +/** + * @defgroup nrfx_usbd_int USB Device driver internal part + * @internal + * @ingroup nrfx_usbd + * + * This part contains auxiliary internal macros, variables and functions. + * @{ + */ + +/** + * @brief Assert endpoint number validity. + * + * Internal macro to be used during program creation in debug mode. + * Generates assertion if endpoint number is not valid. + * + * @param ep Endpoint number to validity check. + */ +#define NRFX_USBD_ASSERT_EP_VALID(ep) NRFX_ASSERT( \ + ((NRF_USBD_EPIN_CHECK(ep) && (NRF_USBD_EP_NR_GET(ep) < NRF_USBD_EPIN_CNT )) \ + || \ + (NRF_USBD_EPOUT_CHECK(ep) && (NRF_USBD_EP_NR_GET(ep) < NRF_USBD_EPOUT_CNT))) \ +); + +/** + * @brief Lowest position of bit for IN endpoint. + * + * The first bit position corresponding to IN endpoint. + * @sa ep2bit bit2ep + */ +#define NRFX_USBD_EPIN_BITPOS_0 0 + +/** + * @brief Lowest position of bit for OUT endpoint. + * + * The first bit position corresponding to OUT endpoint + * @sa ep2bit bit2ep + */ +#define NRFX_USBD_EPOUT_BITPOS_0 16 + +/** + * @brief Input endpoint bits mask. + */ +#define NRFX_USBD_EPIN_BIT_MASK (0xFFFFU << NRFX_USBD_EPIN_BITPOS_0) + +/** + * @brief Output endpoint bits mask. + */ +#define NRFX_USBD_EPOUT_BIT_MASK (0xFFFFU << NRFX_USBD_EPOUT_BITPOS_0) + +/** + * @brief Isochronous endpoint bit mask + */ +#define USBD_EPISO_BIT_MASK \ + ((1U << NRFX_USBD_EP_BITPOS(NRFX_USBD_EPOUT8)) | \ + (1U << NRFX_USBD_EP_BITPOS(NRFX_USBD_EPIN8))) + +/** + * @brief Auxiliary macro to change EP number into bit position. + * + * This macro is used by @ref ep2bit function but also for statically check + * the bitpos values integrity during compilation. + * + * @param[in] ep Endpoint number. + * @return Endpoint bit position. + */ +#define NRFX_USBD_EP_BITPOS(ep) \ + ((NRF_USBD_EPIN_CHECK(ep) ? NRFX_USBD_EPIN_BITPOS_0 : NRFX_USBD_EPOUT_BITPOS_0) \ + + NRF_USBD_EP_NR_GET(ep)) + +/** + * @brief Helper macro for creating an endpoint transfer event. + * + * @param[in] name Name of the created transfer event variable. + * @param[in] endpoint Endpoint number. + * @param[in] ep_stat Endpoint state to report. + * + * @return Initialized event constant variable. + */ +#define NRFX_USBD_EP_TRANSFER_EVENT(name, endpont, ep_stat) \ + const nrfx_usbd_evt_t name = { \ + NRFX_USBD_EVT_EPTRANSFER, \ + .data = { \ + .eptransfer = { \ + .ep = endpont, \ + .status = ep_stat \ + } \ + } \ + } + +/* Check it the bit positions values match defined DATAEPSTATUS bit positions */ +NRFX_STATIC_ASSERT(NRFX_USBD_EP_BITPOS(NRFX_USBD_EPIN1) == USBD_EPDATASTATUS_EPIN1_Pos ); +NRFX_STATIC_ASSERT(NRFX_USBD_EP_BITPOS(NRFX_USBD_EPIN2) == USBD_EPDATASTATUS_EPIN2_Pos ); +NRFX_STATIC_ASSERT(NRFX_USBD_EP_BITPOS(NRFX_USBD_EPIN3) == USBD_EPDATASTATUS_EPIN3_Pos ); +NRFX_STATIC_ASSERT(NRFX_USBD_EP_BITPOS(NRFX_USBD_EPIN4) == USBD_EPDATASTATUS_EPIN4_Pos ); +NRFX_STATIC_ASSERT(NRFX_USBD_EP_BITPOS(NRFX_USBD_EPIN5) == USBD_EPDATASTATUS_EPIN5_Pos ); +NRFX_STATIC_ASSERT(NRFX_USBD_EP_BITPOS(NRFX_USBD_EPIN6) == USBD_EPDATASTATUS_EPIN6_Pos ); +NRFX_STATIC_ASSERT(NRFX_USBD_EP_BITPOS(NRFX_USBD_EPIN7) == USBD_EPDATASTATUS_EPIN7_Pos ); +NRFX_STATIC_ASSERT(NRFX_USBD_EP_BITPOS(NRFX_USBD_EPOUT1) == USBD_EPDATASTATUS_EPOUT1_Pos); +NRFX_STATIC_ASSERT(NRFX_USBD_EP_BITPOS(NRFX_USBD_EPOUT2) == USBD_EPDATASTATUS_EPOUT2_Pos); +NRFX_STATIC_ASSERT(NRFX_USBD_EP_BITPOS(NRFX_USBD_EPOUT3) == USBD_EPDATASTATUS_EPOUT3_Pos); +NRFX_STATIC_ASSERT(NRFX_USBD_EP_BITPOS(NRFX_USBD_EPOUT4) == USBD_EPDATASTATUS_EPOUT4_Pos); +NRFX_STATIC_ASSERT(NRFX_USBD_EP_BITPOS(NRFX_USBD_EPOUT5) == USBD_EPDATASTATUS_EPOUT5_Pos); +NRFX_STATIC_ASSERT(NRFX_USBD_EP_BITPOS(NRFX_USBD_EPOUT6) == USBD_EPDATASTATUS_EPOUT6_Pos); +NRFX_STATIC_ASSERT(NRFX_USBD_EP_BITPOS(NRFX_USBD_EPOUT7) == USBD_EPDATASTATUS_EPOUT7_Pos); + + +/** + * @brief Current driver state. + */ +static nrfx_drv_state_t m_drv_state = NRFX_DRV_STATE_UNINITIALIZED; + +/** + * @brief Event handler for the driver. + * + * Event handler that would be called on events. + * + * @note Currently it cannot be null if any interrupt is activated. + */ +static nrfx_usbd_event_handler_t m_event_handler; + +/** + * @brief Detected state of the bus. + * + * Internal state changed in interrupts handling when + * RESUME or SUSPEND event is processed. + * + * Values: + * - true - bus suspended + * - false - ongoing normal communication on the bus + * + * @note This is only the bus state and does not mean that the peripheral is in suspend state. + */ +static volatile bool m_bus_suspend; + +/** + * @brief Internal constant that contains interrupts disabled in suspend state. + * + * Internal constant used in @ref nrfx_usbd_suspend_irq_config and @ref nrfx_usbd_active_irq_config + * functions. + */ +static const uint32_t m_irq_disabled_in_suspend = + NRF_USBD_INT_ENDEPIN0_MASK | + NRF_USBD_INT_EP0DATADONE_MASK | + NRF_USBD_INT_ENDEPOUT0_MASK | + NRF_USBD_INT_EP0SETUP_MASK | + NRF_USBD_INT_DATAEP_MASK; + +/** + * @brief Direction of last received Setup transfer. + * + * This variable is used to redirect internal setup data event + * into selected endpoint (IN or OUT). + */ +static nrfx_usbd_ep_t m_last_setup_dir; + +/** + * @brief Mark endpoint readiness for DMA transfer. + * + * Bits in this variable are cleared and set in interrupts. + * 1 means that endpoint is ready for DMA transfer. + * 0 means that DMA transfer cannot be performed on selected endpoint. + */ +static uint32_t m_ep_ready; + +/** + * @brief Mark endpoint with prepared data to transfer by DMA. + * + * This variable can be from any place in the code (interrupt or main thread). + * It would be cleared only from USBD interrupt. + * + * Mask prepared USBD data for transmission. + * It is cleared when no more data to transmit left. + */ +static uint32_t m_ep_dma_waiting; + +/** + * @brief Current EasyDMA state. + * + * Single flag, updated only inside interrupts, that marks current EasyDMA state. + * In USBD there is only one DMA channel working in background, and new transfer + * cannot be started when there is ongoing transfer on any other channel. + */ +static bool m_dma_pending; + +/** + * @brief Simulated data EP status bits required for errata 104. + * + * Marker to delete when not required anymore: >> NRFX_USBD_ERRATA_ENABLE <<. + */ +static uint32_t m_simulated_dataepstatus; + +/** + * @brief The structure that would hold transfer configuration to every endpoint + * + * The structure that holds all the data required by the endpoint to proceed + * with LIST functionality and generate quick callback directly when data + * buffer is ready. + */ +typedef struct +{ + nrfx_usbd_handler_t handler; //!< Handler for current transfer, function pointer. + void * p_context; //!< Context for transfer handler. + size_t transfer_cnt; //!< Number of transferred bytes in the current transfer. + uint16_t max_packet_size; //!< Configured endpoint size. + nrfx_usbd_ep_status_t status; //!< NRFX_SUCCESS or error code, never NRFX_ERROR_BUSY - this one is calculated. +} usbd_ep_state_t; + +/** + * @brief The array of transfer configurations for the endpoints. + * + * The status of the transfer on each endpoint. + */ +static struct +{ + usbd_ep_state_t ep_out[NRF_USBD_EPOUT_CNT]; //!< Status for OUT endpoints. + usbd_ep_state_t ep_in [NRF_USBD_EPIN_CNT ]; //!< Status for IN endpoints. +} m_ep_state; + +/** + * @brief Status variables for integrated feeders. + * + * Current status for integrated feeders (IN transfers). + * Integrated feeders are used for default transfers: + * 1. Simple RAM transfer. + * 2. Simple flash transfer. + * 3. RAM transfer with automatic ZLP. + * 4. Flash transfer with automatic ZLP. + */ +nrfx_usbd_transfer_t m_ep_feeder_state[NRF_USBD_EPIN_CNT]; + +/** + * @brief Status variables for integrated consumers. + * + * Current status for integrated consumers. + * Currently one type of transfer is supported: + * 1. Transfer to RAM. + * + * Transfer is finished automatically when received data block is smaller + * than the endpoint buffer or all the required data is received. + */ +nrfx_usbd_transfer_t m_ep_consumer_state[NRF_USBD_EPOUT_CNT]; + + +/** + * @brief Buffer used to send data directly from FLASH. + * + * This is internal buffer that would be used to emulate the possibility + * to transfer data directly from FLASH. + * We do not have to care about the source of data when calling transfer functions. + * + * We do not need more buffers that one, because only one transfer can be pending + * at once. + */ +static uint32_t m_tx_buffer[NRFX_CEIL_DIV( + NRFX_USBD_FEEDER_BUFFER_SIZE, sizeof(uint32_t))]; + +/* Early declaration. Documentation above definition. */ +static void usbd_dmareq_process(void); + + +/** + * @brief Change endpoint number to endpoint event code. + * + * @param ep Endpoint number. + * + * @return Connected endpoint event code. + * + * Marker to delete when not required anymore: >> NRFX_USBD_ERRATA_ENABLE <<. + */ +static inline nrf_usbd_event_t nrfx_usbd_ep_to_endevent(nrfx_usbd_ep_t ep) +{ + NRFX_USBD_ASSERT_EP_VALID(ep); + + static const nrf_usbd_event_t epin_endev[] = + { + NRF_USBD_EVENT_ENDEPIN0, + NRF_USBD_EVENT_ENDEPIN1, + NRF_USBD_EVENT_ENDEPIN2, + NRF_USBD_EVENT_ENDEPIN3, + NRF_USBD_EVENT_ENDEPIN4, + NRF_USBD_EVENT_ENDEPIN5, + NRF_USBD_EVENT_ENDEPIN6, + NRF_USBD_EVENT_ENDEPIN7, + NRF_USBD_EVENT_ENDISOIN0 + }; + static const nrf_usbd_event_t epout_endev[] = + { + NRF_USBD_EVENT_ENDEPOUT0, + NRF_USBD_EVENT_ENDEPOUT1, + NRF_USBD_EVENT_ENDEPOUT2, + NRF_USBD_EVENT_ENDEPOUT3, + NRF_USBD_EVENT_ENDEPOUT4, + NRF_USBD_EVENT_ENDEPOUT5, + NRF_USBD_EVENT_ENDEPOUT6, + NRF_USBD_EVENT_ENDEPOUT7, + NRF_USBD_EVENT_ENDISOOUT0 + }; + + return (NRF_USBD_EPIN_CHECK(ep) ? epin_endev : epout_endev)[NRF_USBD_EP_NR_GET(ep)]; +} + + +/** + * @brief Get interrupt mask for selected endpoint. + * + * @param[in] ep Endpoint number. + * + * @return Interrupt mask related to the EasyDMA transfer end for the + * chosen endpoint. + */ +static inline uint32_t nrfx_usbd_ep_to_int(nrfx_usbd_ep_t ep) +{ + NRFX_USBD_ASSERT_EP_VALID(ep); + + static const uint8_t epin_bitpos[] = + { + USBD_INTEN_ENDEPIN0_Pos, + USBD_INTEN_ENDEPIN1_Pos, + USBD_INTEN_ENDEPIN2_Pos, + USBD_INTEN_ENDEPIN3_Pos, + USBD_INTEN_ENDEPIN4_Pos, + USBD_INTEN_ENDEPIN5_Pos, + USBD_INTEN_ENDEPIN6_Pos, + USBD_INTEN_ENDEPIN7_Pos, + USBD_INTEN_ENDISOIN_Pos + }; + static const uint8_t epout_bitpos[] = + { + USBD_INTEN_ENDEPOUT0_Pos, + USBD_INTEN_ENDEPOUT1_Pos, + USBD_INTEN_ENDEPOUT2_Pos, + USBD_INTEN_ENDEPOUT3_Pos, + USBD_INTEN_ENDEPOUT4_Pos, + USBD_INTEN_ENDEPOUT5_Pos, + USBD_INTEN_ENDEPOUT6_Pos, + USBD_INTEN_ENDEPOUT7_Pos, + USBD_INTEN_ENDISOOUT_Pos + }; + + return 1UL << (NRF_USBD_EPIN_CHECK(ep) ? epin_bitpos : epout_bitpos)[NRF_USBD_EP_NR_GET(ep)]; +} + +/** + * @name Integrated feeders and consumers + * + * Internal, default functions for transfer processing. + * @{ + */ + +/** + * @brief Integrated consumer to RAM buffer. + * + * @param p_next See @ref nrfx_usbd_consumer_t documentation. + * @param p_context See @ref nrfx_usbd_consumer_t documentation. + * @param ep_size See @ref nrfx_usbd_consumer_t documentation. + * @param data_size See @ref nrfx_usbd_consumer_t documentation. + * + * @retval true Continue transfer. + * @retval false This was the last transfer. + */ +bool nrfx_usbd_consumer( + nrfx_usbd_ep_transfer_t * p_next, + void * p_context, + size_t ep_size, + size_t data_size) +{ + nrfx_usbd_transfer_t * p_transfer = p_context; + NRFX_ASSERT(ep_size >= data_size); + NRFX_ASSERT((p_transfer->p_data.rx == NULL) || + nrfx_is_in_ram(p_transfer->p_data.rx)); + + size_t size = p_transfer->size; + if (size < data_size) + { + NRFX_LOG_DEBUG("consumer: buffer too small: r: %u, l: %u", data_size, size); + /* Buffer size to small */ + p_next->size = 0; + p_next->p_data = p_transfer->p_data; + } + else + { + p_next->size = data_size; + p_next->p_data = p_transfer->p_data; + size -= data_size; + p_transfer->size = size; + p_transfer->p_data.addr += data_size; + } + return (ep_size == data_size) && (size != 0); +} + +/** + * @brief Integrated feeder from RAM source. + * + * @param[out] p_next See @ref nrfx_usbd_feeder_t documentation. + * @param[in,out] p_context See @ref nrfx_usbd_feeder_t documentation. + * @param[in] ep_size See @ref nrfx_usbd_feeder_t documentation. + * + * @retval true Continue transfer. + * @retval false This was the last transfer. + */ +bool nrfx_usbd_feeder_ram( + nrfx_usbd_ep_transfer_t * p_next, + void * p_context, + size_t ep_size) +{ + nrfx_usbd_transfer_t * p_transfer = p_context; + NRFX_ASSERT(nrfx_is_in_ram(p_transfer->p_data.tx)); + + size_t tx_size = p_transfer->size; + if (tx_size > ep_size) + { + tx_size = ep_size; + } + + p_next->p_data = p_transfer->p_data; + p_next->size = tx_size; + + p_transfer->size -= tx_size; + p_transfer->p_data.addr += tx_size; + + return (p_transfer->size != 0); +} + +/** + * @brief Integrated feeder from RAM source with ZLP. + * + * @param[out] p_next See @ref nrfx_usbd_feeder_t documentation. + * @param[in,out] p_context See @ref nrfx_usbd_feeder_t documentation. + * @param[in] ep_size See @ref nrfx_usbd_feeder_t documentation. + * + * @retval true Continue transfer. + * @retval false This was the last transfer. + */ +bool nrfx_usbd_feeder_ram_zlp( + nrfx_usbd_ep_transfer_t * p_next, + void * p_context, + size_t ep_size) +{ + nrfx_usbd_transfer_t * p_transfer = p_context; + NRFX_ASSERT(nrfx_is_in_ram(p_transfer->p_data.tx)); + + size_t tx_size = p_transfer->size; + if (tx_size > ep_size) + { + tx_size = ep_size; + } + + p_next->p_data.tx = (tx_size == 0) ? NULL : p_transfer->p_data.tx; + p_next->size = tx_size; + + p_transfer->size -= tx_size; + p_transfer->p_data.addr += tx_size; + + return (tx_size != 0); +} + +/** + * @brief Integrated feeder from a flash source. + * + * @param[out] p_next See @ref nrfx_usbd_feeder_t documentation. + * @param[in,out] p_context See @ref nrfx_usbd_feeder_t documentation. + * @param[in] ep_size See @ref nrfx_usbd_feeder_t documentation. + * + * @retval true Continue transfer. + * @retval false This was the last transfer. + */ +bool nrfx_usbd_feeder_flash(nrfx_usbd_ep_transfer_t * p_next, void * p_context, size_t ep_size) +{ + nrfx_usbd_transfer_t * p_transfer = p_context; + NRFX_ASSERT(!nrfx_is_in_ram(p_transfer->p_data.tx)); + + size_t tx_size = p_transfer->size; + void * p_buffer = nrfx_usbd_feeder_buffer_get(); + + if (tx_size > ep_size) + { + tx_size = ep_size; + } + + NRFX_ASSERT(tx_size <= NRFX_USBD_FEEDER_BUFFER_SIZE); + memcpy(p_buffer, (p_transfer->p_data.tx), tx_size); + + p_next->p_data.tx = p_buffer; + p_next->size = tx_size; + + p_transfer->size -= tx_size; + p_transfer->p_data.addr += tx_size; + + return (p_transfer->size != 0); +} + +/** + * @brief Integrated feeder from a flash source with ZLP. + * + * @param[out] p_next See @ref nrfx_usbd_feeder_t documentation. + * @param[in,out] p_context See @ref nrfx_usbd_feeder_t documentation. + * @param[in] ep_size See @ref nrfx_usbd_feeder_t documentation. + * + * @retval true Continue transfer. + * @retval false This was the last transfer. + */ +bool nrfx_usbd_feeder_flash_zlp(nrfx_usbd_ep_transfer_t * p_next, void * p_context, size_t ep_size) +{ + nrfx_usbd_transfer_t * p_transfer = p_context; + NRFX_ASSERT(!nrfx_is_in_ram(p_transfer->p_data.tx)); + + size_t tx_size = p_transfer->size; + void * p_buffer = nrfx_usbd_feeder_buffer_get(); + + if (tx_size > ep_size) + { + tx_size = ep_size; + } + + NRFX_ASSERT(tx_size <= NRFX_USBD_FEEDER_BUFFER_SIZE); + + if (tx_size != 0) + { + memcpy(p_buffer, (p_transfer->p_data.tx), tx_size); + p_next->p_data.tx = p_buffer; + } + else + { + p_next->p_data.tx = NULL; + } + p_next->size = tx_size; + + p_transfer->size -= tx_size; + p_transfer->p_data.addr += tx_size; + + return (tx_size != 0); +} + +/** @} */ + +/** + * @brief Change Driver endpoint number to HAL endpoint number. + * + * @param ep Driver endpoint identifier. + * + * @return Endpoint identifier in HAL. + * + * @sa nrfx_usbd_ep_from_hal + */ +static inline uint8_t ep_to_hal(nrfx_usbd_ep_t ep) +{ + NRFX_USBD_ASSERT_EP_VALID(ep); + return (uint8_t)ep; +} + +/** + * @brief Generate start task number for selected endpoint index. + * + * @param ep Endpoint number. + * + * @return Task for starting EasyDMA transfer on selected endpoint. + */ +static inline nrf_usbd_task_t task_start_ep(nrfx_usbd_ep_t ep) +{ + NRFX_USBD_ASSERT_EP_VALID(ep); + return (nrf_usbd_task_t)( + (NRF_USBD_EPIN_CHECK(ep) ? NRF_USBD_TASK_STARTEPIN0 : NRF_USBD_TASK_STARTEPOUT0) + + (NRF_USBD_EP_NR_GET(ep) * sizeof(uint32_t))); +} + +/** + * @brief Access selected endpoint state structure. + * + * Function used to change or just read the state of selected endpoint. + * It is used for internal transmission state. + * + * @param ep Endpoint number. + */ +static inline usbd_ep_state_t* ep_state_access(nrfx_usbd_ep_t ep) +{ + NRFX_USBD_ASSERT_EP_VALID(ep); + return ((NRF_USBD_EPIN_CHECK(ep) ? m_ep_state.ep_in : m_ep_state.ep_out) + + NRF_USBD_EP_NR_GET(ep)); +} + +/** + * @brief Change endpoint number to bit position. + * + * Bit positions are defined the same way as they are placed in DATAEPSTATUS register, + * but bits for endpoint 0 are included. + * + * @param ep Endpoint number. + * + * @return Bit position related to the given endpoint number. + * + * @sa bit2ep + */ +static inline uint8_t ep2bit(nrfx_usbd_ep_t ep) +{ + NRFX_USBD_ASSERT_EP_VALID(ep); + return NRFX_USBD_EP_BITPOS(ep); +} + +/** + * @brief Change bit position to endpoint number. + * + * @param bitpos Bit position. + * + * @return Endpoint number corresponding to given bit position. + * + * @sa ep2bit + */ +static inline nrfx_usbd_ep_t bit2ep(uint8_t bitpos) +{ + NRFX_STATIC_ASSERT(NRFX_USBD_EPOUT_BITPOS_0 > NRFX_USBD_EPIN_BITPOS_0); + return (nrfx_usbd_ep_t)((bitpos >= NRFX_USBD_EPOUT_BITPOS_0) ? + NRF_USBD_EPOUT(bitpos - NRFX_USBD_EPOUT_BITPOS_0) : NRF_USBD_EPIN(bitpos)); +} + +/** + * @brief Mark that EasyDMA is working. + * + * Internal function to set the flag informing about EasyDMA transfer pending. + * This function is called always just after the EasyDMA transfer is started. + */ +static inline void usbd_dma_pending_set(void) +{ + if (nrfx_usbd_errata_199()) + { + *((volatile uint32_t *)0x40027C1C) = 0x00000082; + } + m_dma_pending = true; +} + +/** + * @brief Mark that EasyDMA is free. + * + * Internal function to clear the flag informing about EasyDMA transfer pending. + * This function is called always just after the finished EasyDMA transfer is detected. + */ +static inline void usbd_dma_pending_clear(void) +{ + if (nrfx_usbd_errata_199()) + { + *((volatile uint32_t *)0x40027C1C) = 0x00000000; + } + m_dma_pending = false; +} + +/** + * @brief Start selected EasyDMA transmission. + * + * This is internal auxiliary function. + * No checking is made if EasyDMA is ready for new transmission. + * + * @param[in] ep Number of endpoint for transmission. + * If it is OUT endpoint transmission would be directed from endpoint to RAM. + * If it is in endpoint transmission would be directed from RAM to endpoint. + */ +static inline void usbd_dma_start(nrfx_usbd_ep_t ep) +{ + nrf_usbd_task_trigger(task_start_ep(ep)); +} + +void nrfx_usbd_isoinconfig_set(nrf_usbd_isoinconfig_t config) +{ + NRFX_ASSERT(!nrfx_usbd_errata_type_52840_eng_a()); + nrf_usbd_isoinconfig_set(config); +} + +nrf_usbd_isoinconfig_t nrfx_usbd_isoinconfig_get(void) +{ + NRFX_ASSERT(!nrfx_usbd_errata_type_52840_eng_a()); + return nrf_usbd_isoinconfig_get(); +} + +/** + * @brief Abort pending transfer on selected endpoint. + * + * @param ep Endpoint number. + * + * @note + * This function locks interrupts that may be costly. + * It is good idea to test if the endpoint is still busy before calling this function: + * @code + (m_ep_dma_waiting & (1U << ep2bit(ep))) + * @endcode + * This function would check it again, but it makes it inside critical section. + */ +static inline void usbd_ep_abort(nrfx_usbd_ep_t ep) +{ + NRFX_CRITICAL_SECTION_ENTER(); + + usbd_ep_state_t * p_state = ep_state_access(ep); + + if (NRF_USBD_EPOUT_CHECK(ep)) + { + /* Host -> Device */ + if ((~m_ep_dma_waiting) & (1U << ep2bit(ep))) + { + /* If the bit in m_ep_dma_waiting in cleared - nothing would be + * processed inside transfer processing */ + nrfx_usbd_transfer_out_drop(ep); + } + else + { + p_state->handler.consumer = NULL; + m_ep_dma_waiting &= ~(1U << ep2bit(ep)); + m_ep_ready &= ~(1U << ep2bit(ep)); + } + /* Aborted */ + p_state->status = NRFX_USBD_EP_ABORTED; + } + else + { + if(!NRF_USBD_EPISO_CHECK(ep)) + { + /* Workaround: Disarm the endpoint if there is any data buffered. */ + if(ep != NRFX_USBD_EPIN0) + { + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7B6 + (2u * (NRF_USBD_EP_NR_GET(ep) - 1)); + uint8_t temp = *((volatile uint32_t *)(NRF_USBD_BASE + 0x804)); + temp |= (1U << 1); + *((volatile uint32_t *)(NRF_USBD_BASE + 0x804)) |= temp; + (void)(*((volatile uint32_t *)(NRF_USBD_BASE + 0x804))); + } + else + { + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7B4; + uint8_t temp = *((volatile uint32_t *)(NRF_USBD_BASE + 0x804)); + temp |= (1U << 2); + *((volatile uint32_t *)(NRF_USBD_BASE + 0x804)) |= temp; + (void)(*((volatile uint32_t *)(NRF_USBD_BASE + 0x804))); + } + } + if ((m_ep_dma_waiting | (~m_ep_ready)) & (1U << ep2bit(ep))) + { + /* Device -> Host */ + m_ep_dma_waiting &= ~(1U << ep2bit(ep)); + m_ep_ready |= 1U << ep2bit(ep) ; + + p_state->handler.feeder = NULL; + p_state->status = NRFX_USBD_EP_ABORTED; + NRFX_USBD_EP_TRANSFER_EVENT(evt, ep, NRFX_USBD_EP_ABORTED); + m_event_handler(&evt); + } + } + NRFX_CRITICAL_SECTION_EXIT(); +} + +void nrfx_usbd_ep_abort(nrfx_usbd_ep_t ep) +{ + usbd_ep_abort(ep); +} + + +/** + * @brief Abort all pending endpoints. + * + * Function aborts all pending endpoint transfers. + */ +static void usbd_ep_abort_all(void) +{ + uint32_t ep_waiting = m_ep_dma_waiting | (m_ep_ready & NRFX_USBD_EPOUT_BIT_MASK); + while (0 != ep_waiting) + { + uint8_t bitpos = __CLZ(__RBIT(ep_waiting)); + if (!NRF_USBD_EPISO_CHECK(bit2ep(bitpos))) + { + usbd_ep_abort(bit2ep(bitpos)); + } + ep_waiting &= ~(1U << bitpos); + } + + m_ep_ready = (((1U << NRF_USBD_EPIN_CNT) - 1U) << NRFX_USBD_EPIN_BITPOS_0); +} + +/** + * @brief Force the USBD interrupt into pending state. + * + * This function is used to force USBD interrupt to be processed right now. + * It makes it possible to process all EasyDMA access on one thread priority level. + */ +static inline void usbd_int_rise(void) +{ + NRFX_IRQ_PENDING_SET(USBD_IRQn); +} + +/** + * @name USBD interrupt runtimes. + * + * Interrupt runtimes that would be vectorized using @ref m_isr. + * @{ + */ + +static void ev_usbreset_handler(void) +{ + m_bus_suspend = false; + m_last_setup_dir = NRFX_USBD_EPOUT0; + + const nrfx_usbd_evt_t evt = { + .type = NRFX_USBD_EVT_RESET + }; + + m_event_handler(&evt); +} + +static void ev_started_handler(void) +{ +#if NRFX_USBD_STARTED_EV_ENABLE + // Handler not used by the stack. + // May be used for debugging. +#endif +} + +/** + * @brief Handler for EasyDMA event without endpoint clearing. + * + * This handler would be called when EasyDMA transfer for endpoints that does not require clearing. + * All in endpoints are cleared automatically when new EasyDMA transfer is initialized. + * For endpoint 0 see @ref nrf_usbd_ep0out_dma_handler. + * + * @param[in] ep Endpoint number. + */ +static inline void nrf_usbd_ep0in_dma_handler(void) +{ + const nrfx_usbd_ep_t ep = NRFX_USBD_EPIN0; + NRFX_LOG_DEBUG("USB event: DMA ready IN0"); + usbd_dma_pending_clear(); + + usbd_ep_state_t * p_state = ep_state_access(ep); + if (NRFX_USBD_EP_ABORTED == p_state->status) + { + /* Clear transfer information just in case */ + (void)(NRFX_ATOMIC_FETCH_AND(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + } + else if (p_state->handler.feeder == NULL) + { + (void)(NRFX_ATOMIC_FETCH_AND(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + } + else + { + /* Nothing to do */ + } +} + +/** + * @brief Handler for EasyDMA event without endpoint clearing. + * + * This handler would be called when EasyDMA transfer for endpoints that does not require clearing. + * All in endpoints are cleared automatically when new EasyDMA transfer is initialized. + * For endpoint 0 see @ref nrf_usbd_ep0out_dma_handler. + * + * @param[in] ep Endpoint number. + */ +static inline void nrf_usbd_epin_dma_handler(nrfx_usbd_ep_t ep) +{ + NRFX_LOG_DEBUG("USB event: DMA ready IN: %x", ep); + NRFX_ASSERT(NRF_USBD_EPIN_CHECK(ep)); + NRFX_ASSERT(!NRF_USBD_EPISO_CHECK(ep)); + NRFX_ASSERT(NRF_USBD_EP_NR_GET(ep) > 0); + usbd_dma_pending_clear(); + + usbd_ep_state_t * p_state = ep_state_access(ep); + if (NRFX_USBD_EP_ABORTED == p_state->status) + { + /* Clear transfer information just in case */ + (void)(NRFX_ATOMIC_FETCH_AND(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + } + else if (p_state->handler.feeder == NULL) + { + (void)(NRFX_ATOMIC_FETCH_AND(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + } + else + { + /* Nothing to do */ + } +} + +/** + * @brief Handler for EasyDMA event from in isochronous endpoint. + */ +static inline void nrf_usbd_epiniso_dma_handler(nrfx_usbd_ep_t ep) +{ + if (NRFX_USBD_ISO_DEBUG) + { + NRFX_LOG_DEBUG("USB event: DMA ready ISOIN: %x", ep); + } + NRFX_ASSERT(NRF_USBD_EPIN_CHECK(ep)); + NRFX_ASSERT(NRF_USBD_EPISO_CHECK(ep)); + usbd_dma_pending_clear(); + + usbd_ep_state_t * p_state = ep_state_access(ep); + if (NRFX_USBD_EP_ABORTED == p_state->status) + { + /* Clear transfer information just in case */ + (void)(NRFX_ATOMIC_FETCH_AND(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + } + else if (p_state->handler.feeder == NULL) + { + (void)(NRFX_ATOMIC_FETCH_AND(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + /* Send event to the user - for an ISO IN endpoint, the whole transfer is finished in this moment */ + NRFX_USBD_EP_TRANSFER_EVENT(evt, ep, NRFX_USBD_EP_OK); + m_event_handler(&evt); + } + else + { + /* Nothing to do */ + } +} + +/** + * @brief Handler for EasyDMA event for OUT endpoint 0. + * + * EP0 OUT have to be cleared automatically in special way - only in the middle of the transfer. + * It cannot be cleared when required transfer is finished because it means the same that accepting the comment. + */ +static inline void nrf_usbd_ep0out_dma_handler(void) +{ + const nrfx_usbd_ep_t ep = NRFX_USBD_EPOUT0; + NRFX_LOG_DEBUG("USB event: DMA ready OUT0"); + usbd_dma_pending_clear(); + + usbd_ep_state_t * p_state = ep_state_access(ep); + if (NRFX_USBD_EP_ABORTED == p_state->status) + { + /* Clear transfer information just in case */ + (void)(NRFX_ATOMIC_FETCH_AND(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + } + else if (p_state->handler.consumer == NULL) + { + (void)(NRFX_ATOMIC_FETCH_AND(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + /* Send event to the user - for an OUT endpoint, the whole transfer is finished in this moment */ + NRFX_USBD_EP_TRANSFER_EVENT(evt, ep, NRFX_USBD_EP_OK); + m_event_handler(&evt); + } + else + { + nrfx_usbd_setup_data_clear(); + } +} + +/** + * @brief Handler for EasyDMA event from endpoinpoint that requires clearing. + * + * This handler would be called when EasyDMA transfer for OUT endpoint has been finished. + * + * @param[in] ep Endpoint number. + */ +static inline void nrf_usbd_epout_dma_handler(nrfx_usbd_ep_t ep) +{ + NRFX_LOG_DEBUG("DMA ready OUT: %x", ep); + NRFX_ASSERT(NRF_USBD_EPOUT_CHECK(ep)); + NRFX_ASSERT(!NRF_USBD_EPISO_CHECK(ep)); + NRFX_ASSERT(NRF_USBD_EP_NR_GET(ep) > 0); + usbd_dma_pending_clear(); + + usbd_ep_state_t * p_state = ep_state_access(ep); + if (NRFX_USBD_EP_ABORTED == p_state->status) + { + /* Clear transfer information just in case */ + (void)(NRFX_ATOMIC_FETCH_AND(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + } + else if (p_state->handler.consumer == NULL) + { + (void)(NRFX_ATOMIC_FETCH_AND(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + /* Send event to the user - for an OUT endpoint, the whole transfer is finished in this moment */ + NRFX_USBD_EP_TRANSFER_EVENT(evt, ep, NRFX_USBD_EP_OK); + m_event_handler(&evt); + } + else + { + /* Nothing to do */ + } + +#if NRFX_USBD_EARLY_DMA_PROCESS + /* Speed up */ + usbd_dmareq_process(); +#endif +} + +/** + * @brief Handler for EasyDMA event from out isochronous endpoint. + */ +static inline void nrf_usbd_epoutiso_dma_handler(nrfx_usbd_ep_t ep) +{ + if (NRFX_USBD_ISO_DEBUG) + { + NRFX_LOG_DEBUG("DMA ready ISOOUT: %x", ep); + } + NRFX_ASSERT(NRF_USBD_EPISO_CHECK(ep)); + usbd_dma_pending_clear(); + + usbd_ep_state_t * p_state = ep_state_access(ep); + if (NRFX_USBD_EP_ABORTED == p_state->status) + { + /* Nothing to do - just ignore */ + } + else if (p_state->handler.consumer == NULL) + { + (void)(NRFX_ATOMIC_FETCH_AND(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + /* Send event to the user - for an OUT endpoint, the whole transfer is finished in this moment */ + NRFX_USBD_EP_TRANSFER_EVENT(evt, ep, NRFX_USBD_EP_OK); + m_event_handler(&evt); + } + else + { + /* Nothing to do */ + } +} + + +static void ev_dma_epin0_handler(void) { nrf_usbd_ep0in_dma_handler(); } +static void ev_dma_epin1_handler(void) { nrf_usbd_epin_dma_handler(NRFX_USBD_EPIN1 ); } +static void ev_dma_epin2_handler(void) { nrf_usbd_epin_dma_handler(NRFX_USBD_EPIN2 ); } +static void ev_dma_epin3_handler(void) { nrf_usbd_epin_dma_handler(NRFX_USBD_EPIN3 ); } +static void ev_dma_epin4_handler(void) { nrf_usbd_epin_dma_handler(NRFX_USBD_EPIN4 ); } +static void ev_dma_epin5_handler(void) { nrf_usbd_epin_dma_handler(NRFX_USBD_EPIN5 ); } +static void ev_dma_epin6_handler(void) { nrf_usbd_epin_dma_handler(NRFX_USBD_EPIN6 ); } +static void ev_dma_epin7_handler(void) { nrf_usbd_epin_dma_handler(NRFX_USBD_EPIN7 ); } +static void ev_dma_epin8_handler(void) { nrf_usbd_epiniso_dma_handler(NRFX_USBD_EPIN8 ); } + +static void ev_dma_epout0_handler(void) { nrf_usbd_ep0out_dma_handler(); } +static void ev_dma_epout1_handler(void) { nrf_usbd_epout_dma_handler(NRFX_USBD_EPOUT1); } +static void ev_dma_epout2_handler(void) { nrf_usbd_epout_dma_handler(NRFX_USBD_EPOUT2); } +static void ev_dma_epout3_handler(void) { nrf_usbd_epout_dma_handler(NRFX_USBD_EPOUT3); } +static void ev_dma_epout4_handler(void) { nrf_usbd_epout_dma_handler(NRFX_USBD_EPOUT4); } +static void ev_dma_epout5_handler(void) { nrf_usbd_epout_dma_handler(NRFX_USBD_EPOUT5); } +static void ev_dma_epout6_handler(void) { nrf_usbd_epout_dma_handler(NRFX_USBD_EPOUT6); } +static void ev_dma_epout7_handler(void) { nrf_usbd_epout_dma_handler(NRFX_USBD_EPOUT7); } +static void ev_dma_epout8_handler(void) { nrf_usbd_epoutiso_dma_handler(NRFX_USBD_EPOUT8); } + +static void ev_sof_handler(void) +{ + nrfx_usbd_evt_t evt = { + NRFX_USBD_EVT_SOF, + .data = { .sof = { .framecnt = nrf_usbd_framecntr_get() }} + }; + + /* Process isochronous endpoints */ + uint32_t iso_ready_mask = (1U << ep2bit(NRFX_USBD_EPIN8)); + if (nrf_usbd_episoout_size_get(NRFX_USBD_EPOUT8) != NRF_USBD_EPISOOUT_NO_DATA) + { + iso_ready_mask |= (1U << ep2bit(NRFX_USBD_EPOUT8)); + } + m_ep_ready |= iso_ready_mask; + + m_event_handler(&evt); +} + +/** + * @brief React on data transfer finished. + * + * Auxiliary internal function. + * @param ep Endpoint number. + * @param bitpos Bit position for selected endpoint number. + */ +static void usbd_ep_data_handler(nrfx_usbd_ep_t ep, uint8_t bitpos) +{ + NRFX_LOG_DEBUG("USBD event: EndpointData: %x", ep); + /* Mark endpoint ready for next DMA access */ + m_ep_ready |= (1U << bitpos); + + if (NRF_USBD_EPIN_CHECK(ep)) + { + /* IN endpoint (Device -> Host) */ + if (0 == (m_ep_dma_waiting & (1U << bitpos))) + { + NRFX_LOG_DEBUG("USBD event: EndpointData: In finished"); + /* No more data to be send - transmission finished */ + NRFX_USBD_EP_TRANSFER_EVENT(evt, ep, NRFX_USBD_EP_OK); + m_event_handler(&evt); + } + } + else + { + /* OUT endpoint (Host -> Device) */ + if (0 == (m_ep_dma_waiting & (1U << bitpos))) + { + NRFX_LOG_DEBUG("USBD event: EndpointData: Out waiting"); + /* No buffer prepared - send event to the application */ + NRFX_USBD_EP_TRANSFER_EVENT(evt, ep, NRFX_USBD_EP_WAITING); + m_event_handler(&evt); + } + } +} + +static void ev_setup_data_handler(void) +{ + usbd_ep_data_handler(m_last_setup_dir, ep2bit(m_last_setup_dir)); +} + +static void ev_setup_handler(void) +{ + NRFX_LOG_DEBUG("USBD event: Setup (rt:%.2x r:%.2x v:%.4x i:%.4x l:%u )", + nrf_usbd_setup_bmrequesttype_get(), + nrf_usbd_setup_brequest_get(), + nrf_usbd_setup_wvalue_get(), + nrf_usbd_setup_windex_get(), + nrf_usbd_setup_wlength_get()); + uint8_t bmRequestType = nrf_usbd_setup_bmrequesttype_get(); + + if ((m_ep_dma_waiting | ((~m_ep_ready) & NRFX_USBD_EPIN_BIT_MASK)) + & (1U <handler.feeder) != NULL); + + if (NRF_USBD_EPIN_CHECK(ep)) + { + /* Device -> Host */ + continue_transfer = p_state->handler.feeder( + &transfer, + p_state->p_context, + p_state->max_packet_size); + + if (!continue_transfer) + { + p_state->handler.feeder = NULL; + } + } + else + { + /* Host -> Device */ + const size_t rx_size = nrfx_usbd_epout_size_get(ep); + continue_transfer = p_state->handler.consumer( + &transfer, + p_state->p_context, + p_state->max_packet_size, + rx_size); + + if (transfer.p_data.rx == NULL) + { + /* Dropping transfer - allow processing */ + NRFX_ASSERT(transfer.size == 0); + } + else if (transfer.size < rx_size) + { + NRFX_LOG_DEBUG("Endpoint %x overload (r: %u, e: %u)", ep, rx_size, transfer.size); + p_state->status = NRFX_USBD_EP_OVERLOAD; + (void)(NRFX_ATOMIC_FETCH_AND(&m_ep_dma_waiting, ~(1U << pos))); + NRFX_USBD_EP_TRANSFER_EVENT(evt, ep, NRFX_USBD_EP_OVERLOAD); + m_event_handler(&evt); + /* This endpoint will not be transmitted now, repeat the loop */ + continue; + } + else + { + /* Nothing to do - only check integrity if assertions are enabled */ + NRFX_ASSERT(transfer.size == rx_size); + } + + if (!continue_transfer) + { + p_state->handler.consumer = NULL; + } + } + + usbd_dma_pending_set(); + m_ep_ready &= ~(1U << pos); + if (NRFX_USBD_ISO_DEBUG || (!NRF_USBD_EPISO_CHECK(ep))) + { + NRFX_LOG_DEBUG( + "USB DMA process: Starting transfer on EP: %x, size: %u", + ep, + transfer.size); + } + /* Update number of currently transferred bytes */ + p_state->transfer_cnt += transfer.size; + /* Start transfer to the endpoint buffer */ + nrf_usbd_ep_easydma_set(ep, transfer.p_data.addr, (uint32_t)transfer.size); + + if (nrfx_usbd_errata_104()) + { + uint32_t cnt_end = (uint32_t)(-1); + do + { + uint32_t cnt = (uint32_t)(-1); + do + { + nrf_usbd_event_clear(NRF_USBD_EVENT_STARTED); + usbd_dma_start(ep); + nrfx_systick_delay_us(2); + ++cnt; + }while (!nrf_usbd_event_check(NRF_USBD_EVENT_STARTED)); + if (cnt) + { + NRFX_USBD_LOG_PROTO1_FIX_PRINTF(" DMA restarted: %u times", cnt); + } + + nrfx_systick_delay_us(30); + while (0 == (0x20 & *((volatile uint32_t *)(NRF_USBD_BASE + 0x474)))) + { + nrfx_systick_delay_us(2); + } + nrfx_systick_delay_us(1); + + ++cnt_end; + } while (!nrf_usbd_event_check(nrfx_usbd_ep_to_endevent(ep))); + if (cnt_end) + { + NRFX_USBD_LOG_PROTO1_FIX_PRINTF(" DMA fully restarted: %u times", cnt_end); + } + } + else + { + usbd_dma_start(ep); + /* There is a lot of USBD registers that cannot be accessed during EasyDMA transfer. + * This is quick fix to maintain stability of the stack. + * It cost some performance but makes stack stable. */ + while (!nrf_usbd_event_check(nrfx_usbd_ep_to_endevent(ep))) + { + /* Empty */ + } + } + + if (NRFX_USBD_DMAREQ_PROCESS_DEBUG) + { + NRFX_LOG_DEBUG("USB DMA process - finishing"); + } + /* Transfer started - exit the loop */ + break; + } + } + else + { + if (NRFX_USBD_DMAREQ_PROCESS_DEBUG) + { + NRFX_LOG_DEBUG("USB DMA process - EasyDMA busy"); + } + } +} +/** @} */ + +/** + * @brief USBD interrupt service routines. + * + */ +static const nrfx_irq_handler_t m_isr[] = +{ + [USBD_INTEN_USBRESET_Pos ] = ev_usbreset_handler, + [USBD_INTEN_STARTED_Pos ] = ev_started_handler, + [USBD_INTEN_ENDEPIN0_Pos ] = ev_dma_epin0_handler, + [USBD_INTEN_ENDEPIN1_Pos ] = ev_dma_epin1_handler, + [USBD_INTEN_ENDEPIN2_Pos ] = ev_dma_epin2_handler, + [USBD_INTEN_ENDEPIN3_Pos ] = ev_dma_epin3_handler, + [USBD_INTEN_ENDEPIN4_Pos ] = ev_dma_epin4_handler, + [USBD_INTEN_ENDEPIN5_Pos ] = ev_dma_epin5_handler, + [USBD_INTEN_ENDEPIN6_Pos ] = ev_dma_epin6_handler, + [USBD_INTEN_ENDEPIN7_Pos ] = ev_dma_epin7_handler, + [USBD_INTEN_EP0DATADONE_Pos] = ev_setup_data_handler, + [USBD_INTEN_ENDISOIN_Pos ] = ev_dma_epin8_handler, + [USBD_INTEN_ENDEPOUT0_Pos ] = ev_dma_epout0_handler, + [USBD_INTEN_ENDEPOUT1_Pos ] = ev_dma_epout1_handler, + [USBD_INTEN_ENDEPOUT2_Pos ] = ev_dma_epout2_handler, + [USBD_INTEN_ENDEPOUT3_Pos ] = ev_dma_epout3_handler, + [USBD_INTEN_ENDEPOUT4_Pos ] = ev_dma_epout4_handler, + [USBD_INTEN_ENDEPOUT5_Pos ] = ev_dma_epout5_handler, + [USBD_INTEN_ENDEPOUT6_Pos ] = ev_dma_epout6_handler, + [USBD_INTEN_ENDEPOUT7_Pos ] = ev_dma_epout7_handler, + [USBD_INTEN_ENDISOOUT_Pos ] = ev_dma_epout8_handler, + [USBD_INTEN_SOF_Pos ] = ev_sof_handler, + [USBD_INTEN_USBEVENT_Pos ] = ev_usbevent_handler, + [USBD_INTEN_EP0SETUP_Pos ] = ev_setup_handler, + [USBD_INTEN_EPDATA_Pos ] = ev_epdata_handler +}; + +/** + * @name Interrupt handlers + * + * @{ + */ +void nrfx_usbd_irq_handler(void) +{ + const uint32_t enabled = nrf_usbd_int_enable_get(); + uint32_t to_process = enabled; + uint32_t active = 0; + + /* Check all enabled interrupts */ + while (to_process) + { + uint8_t event_nr = __CLZ(__RBIT(to_process)); + if (nrf_usbd_event_get_and_clear((nrf_usbd_event_t)nrfx_bitpos_to_event(event_nr))) + { + active |= 1UL << event_nr; + } + to_process &= ~(1UL << event_nr); + } + + if (nrfx_usbd_errata_104()) + { + /* Event correcting */ + if ((!m_dma_pending) && (0 != (active & (USBD_INTEN_SOF_Msk)))) + { + uint8_t usbi, uoi, uii; + /* Testing */ + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7A9; + uii = (uint8_t)(*((volatile uint32_t *)(NRF_USBD_BASE + 0x804))); + if (0 != uii) + { + uii &= (uint8_t)(*((volatile uint32_t *)(NRF_USBD_BASE + 0x804))); + } + + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7AA; + uoi = (uint8_t)(*((volatile uint32_t *)(NRF_USBD_BASE + 0x804))); + if (0 != uoi) + { + uoi &= (uint8_t)(*((volatile uint32_t *)(NRF_USBD_BASE + 0x804))); + } + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7AB; + usbi = (uint8_t)(*((volatile uint32_t *)(NRF_USBD_BASE + 0x804))); + if (0 != usbi) + { + usbi &= (uint8_t)(*((volatile uint32_t *)(NRF_USBD_BASE + 0x804))); + } + /* Processing */ + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7AC; + uii &= (uint8_t)*((volatile uint32_t *)(NRF_USBD_BASE + 0x804)); + if (0 != uii) + { + uint8_t rb; + m_simulated_dataepstatus |= ((uint32_t)uii) << NRFX_USBD_EPIN_BITPOS_0; + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7A9; + *((volatile uint32_t *)(NRF_USBD_BASE + 0x804)) = uii; + rb = (uint8_t)*((volatile uint32_t *)(NRF_USBD_BASE + 0x804)); + NRFX_USBD_LOG_PROTO1_FIX_PRINTF(" uii: 0x%.2x (0x%.2x)", uii, rb); + } + + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7AD; + uoi &= (uint8_t)*((volatile uint32_t *)(NRF_USBD_BASE + 0x804)); + if (0 != uoi) + { + uint8_t rb; + m_simulated_dataepstatus |= ((uint32_t)uoi) << NRFX_USBD_EPOUT_BITPOS_0; + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7AA; + *((volatile uint32_t *)(NRF_USBD_BASE + 0x804)) = uoi; + rb = (uint8_t)*((volatile uint32_t *)(NRF_USBD_BASE + 0x804)); + NRFX_USBD_LOG_PROTO1_FIX_PRINTF(" uoi: 0x%.2u (0x%.2x)", uoi, rb); + } + + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7AE; + usbi &= (uint8_t)*((volatile uint32_t *)(NRF_USBD_BASE + 0x804)); + if (0 != usbi) + { + uint8_t rb; + if (usbi & 0x01) + { + active |= USBD_INTEN_EP0SETUP_Msk; + } + if (usbi & 0x10) + { + active |= USBD_INTEN_USBRESET_Msk; + } + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7AB; + *((volatile uint32_t *)(NRF_USBD_BASE + 0x804)) = usbi; + rb = (uint8_t)*((volatile uint32_t *)(NRF_USBD_BASE + 0x804)); + NRFX_USBD_LOG_PROTO1_FIX_PRINTF(" usbi: 0x%.2u (0x%.2x)", usbi, rb); + } + + if (0 != (m_simulated_dataepstatus & + ~((1U << NRFX_USBD_EPOUT_BITPOS_0) | (1U << NRFX_USBD_EPIN_BITPOS_0)))) + { + active |= enabled & NRF_USBD_INT_DATAEP_MASK; + } + if (0 != (m_simulated_dataepstatus & + ((1U << NRFX_USBD_EPOUT_BITPOS_0) | (1U << NRFX_USBD_EPIN_BITPOS_0)))) + { + if (0 != (enabled & NRF_USBD_INT_EP0DATADONE_MASK)) + { + m_simulated_dataepstatus &= + ~((1U << NRFX_USBD_EPOUT_BITPOS_0) | (1U << NRFX_USBD_EPIN_BITPOS_0)); + active |= NRF_USBD_INT_EP0DATADONE_MASK; + } + } + } + } + + /* Process the active interrupts */ + bool setup_active = 0 != (active & NRF_USBD_INT_EP0SETUP_MASK); + active &= ~NRF_USBD_INT_EP0SETUP_MASK; + + while (active) + { + uint8_t event_nr = __CLZ(__RBIT(active)); + m_isr[event_nr](); + active &= ~(1UL << event_nr); + } + usbd_dmareq_process(); + + if (setup_active) + { + m_isr[USBD_INTEN_EP0SETUP_Pos](); + } +} + +/** @} */ +/** @} */ + +nrfx_err_t nrfx_usbd_init(nrfx_usbd_event_handler_t event_handler) +{ + NRFX_ASSERT((nrfx_usbd_errata_type_52840_eng_a() || + nrfx_usbd_errata_type_52840_eng_b() || + nrfx_usbd_errata_type_52840_eng_c() || + nrfx_usbd_errata_type_52840_eng_d()) + ); + + NRFX_ASSERT(event_handler); + + if (m_drv_state != NRFX_DRV_STATE_UNINITIALIZED) + { + return NRFX_ERROR_INVALID_STATE; + } + + m_event_handler = event_handler; + m_drv_state = NRFX_DRV_STATE_INITIALIZED; + + uint8_t n; + for (n = 0; n < NRF_USBD_EPIN_CNT; ++n) + { + nrfx_usbd_ep_t ep = NRFX_USBD_EPIN(n); + nrfx_usbd_ep_max_packet_size_set(ep, NRF_USBD_EPISO_CHECK(ep) ? + (NRFX_USBD_ISOSIZE / 2) : NRFX_USBD_EPSIZE); + usbd_ep_state_t * p_state = ep_state_access(ep); + p_state->status = NRFX_USBD_EP_OK; + p_state->handler.feeder = NULL; + p_state->transfer_cnt = 0; + } + for (n = 0; n < NRF_USBD_EPOUT_CNT; ++n) + { + nrfx_usbd_ep_t ep = NRFX_USBD_EPOUT(n); + nrfx_usbd_ep_max_packet_size_set(ep, NRF_USBD_EPISO_CHECK(ep) ? + (NRFX_USBD_ISOSIZE / 2) : NRFX_USBD_EPSIZE); + usbd_ep_state_t * p_state = ep_state_access(ep); + p_state->status = NRFX_USBD_EP_OK; + p_state->handler.consumer = NULL; + p_state->transfer_cnt = 0; + } + + return NRFX_SUCCESS; +} + +void nrfx_usbd_uninit(void) +{ + NRFX_ASSERT(m_drv_state == NRFX_DRV_STATE_INITIALIZED); + + m_event_handler = NULL; + m_drv_state = NRFX_DRV_STATE_UNINITIALIZED; + return; +} + +void nrfx_usbd_enable(void) +{ + NRFX_ASSERT(m_drv_state == NRFX_DRV_STATE_INITIALIZED); + + /* Prepare for READY event receiving */ + nrf_usbd_eventcause_clear(NRF_USBD_EVENTCAUSE_READY_MASK); + + if (nrfx_usbd_errata_187()) + { + NRFX_CRITICAL_SECTION_ENTER(); + if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000) + { + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + *((volatile uint32_t *)(0x4006ED14)) = 0x00000003; + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + } + else + { + *((volatile uint32_t *)(0x4006ED14)) = 0x00000003; + } + NRFX_CRITICAL_SECTION_EXIT(); + } + + if (nrfx_usbd_errata_171()) + { + NRFX_CRITICAL_SECTION_ENTER(); + if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000) + { + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0; + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + } + else + { + *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0; + } + NRFX_CRITICAL_SECTION_EXIT(); + } + + /* Enable the peripheral */ + nrf_usbd_enable(); + /* Waiting for peripheral to enable, this should take a few us */ + while (0 == (NRF_USBD_EVENTCAUSE_READY_MASK & nrf_usbd_eventcause_get())) + { + /* Empty loop */ + } + nrf_usbd_eventcause_clear(NRF_USBD_EVENTCAUSE_READY_MASK); + + if (nrfx_usbd_errata_171()) + { + NRFX_CRITICAL_SECTION_ENTER(); + if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000) + { + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + *((volatile uint32_t *)(0x4006EC14)) = 0x00000000; + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + } + else + { + *((volatile uint32_t *)(0x4006EC14)) = 0x00000000; + } + + NRFX_CRITICAL_SECTION_EXIT(); + } + + if (nrfx_usbd_errata_166()) + { + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7E3; + *((volatile uint32_t *)(NRF_USBD_BASE + 0x804)) = 0x40; + __ISB(); + __DSB(); + } + + nrf_usbd_isosplit_set(NRF_USBD_ISOSPLIT_HALF); + + if (NRFX_USBD_CONFIG_ISO_IN_ZLP) + { + nrfx_usbd_isoinconfig_set(NRF_USBD_ISOINCONFIG_ZERODATA); + } + else + { + nrfx_usbd_isoinconfig_set(NRF_USBD_ISOINCONFIG_NORESP); + } + + m_ep_ready = (((1U << NRF_USBD_EPIN_CNT) - 1U) << NRFX_USBD_EPIN_BITPOS_0); + m_ep_dma_waiting = 0; + usbd_dma_pending_clear(); + m_last_setup_dir = NRFX_USBD_EPOUT0; + + m_drv_state = NRFX_DRV_STATE_POWERED_ON; + + if (nrfx_usbd_errata_187()) + { + CRITICAL_REGION_ENTER(); + if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000) + { + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + *((volatile uint32_t *)(0x4006ED14)) = 0x00000000; + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + } + else + { + *((volatile uint32_t *)(0x4006ED14)) = 0x00000000; + } + CRITICAL_REGION_EXIT(); + } +} + +void nrfx_usbd_disable(void) +{ + NRFX_ASSERT(m_drv_state != NRFX_DRV_STATE_UNINITIALIZED); + + /* Stop just in case */ + nrfx_usbd_stop(); + + /* Disable all parts */ + nrf_usbd_int_disable(nrf_usbd_int_enable_get()); + nrf_usbd_disable(); + usbd_dma_pending_clear(); + m_drv_state = NRFX_DRV_STATE_INITIALIZED; +} + +void nrfx_usbd_start(bool enable_sof) +{ + NRFX_ASSERT(m_drv_state == NRFX_DRV_STATE_POWERED_ON); + m_bus_suspend = false; + + uint32_t ints_to_enable = + NRF_USBD_INT_USBRESET_MASK | + NRF_USBD_INT_STARTED_MASK | + NRF_USBD_INT_ENDEPIN0_MASK | + NRF_USBD_INT_EP0DATADONE_MASK | + NRF_USBD_INT_ENDEPOUT0_MASK | + NRF_USBD_INT_USBEVENT_MASK | + NRF_USBD_INT_EP0SETUP_MASK | + NRF_USBD_INT_DATAEP_MASK; + + if (enable_sof || nrfx_usbd_errata_104()) + { + ints_to_enable |= NRF_USBD_INT_SOF_MASK; + } + + /* Enable all required interrupts */ + nrf_usbd_int_enable(ints_to_enable); + + /* Enable interrupt globally */ + NRFX_IRQ_PRIORITY_SET(USBD_IRQn, NRFX_USBD_CONFIG_IRQ_PRIORITY); + NRFX_IRQ_ENABLE(USBD_IRQn); + + /* Enable pullups */ + nrf_usbd_pullup_enable(); +} + +void nrfx_usbd_stop(void) +{ + NRFX_ASSERT(m_drv_state == NRFX_DRV_STATE_POWERED_ON); + + if (NRFX_IRQ_IS_ENABLED(USBD_IRQn)) + { + /* Abort transfers */ + usbd_ep_abort_all(); + + /* Disable pullups */ + nrf_usbd_pullup_disable(); + + /* Disable interrupt globally */ + NRFX_IRQ_DISABLE(USBD_IRQn); + + /* Disable all interrupts */ + nrf_usbd_int_disable(~0U); + } +} + +bool nrfx_usbd_is_initialized(void) +{ + return (m_drv_state >= NRFX_DRV_STATE_INITIALIZED); +} + +bool nrfx_usbd_is_enabled(void) +{ + return (m_drv_state >= NRFX_DRV_STATE_POWERED_ON); +} + +bool nrfx_usbd_is_started(void) +{ + return (nrfx_usbd_is_enabled() && NRFX_IRQ_IS_ENABLED(USBD_IRQn)); +} + +bool nrfx_usbd_suspend(void) +{ + bool suspended = false; + + NRFX_CRITICAL_SECTION_ENTER(); + if (m_bus_suspend) + { + usbd_ep_abort_all(); + + if (!(nrf_usbd_eventcause_get() & NRF_USBD_EVENTCAUSE_RESUME_MASK)) + { + nrf_usbd_lowpower_enable(); + if (nrf_usbd_eventcause_get() & NRF_USBD_EVENTCAUSE_RESUME_MASK) + { + nrf_usbd_lowpower_disable(); + } + else + { + suspended = true; + + if (nrfx_usbd_errata_171()) + { + if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000) + { + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + *((volatile uint32_t *)(0x4006EC14)) = 0x00000000; + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + } + else + { + *((volatile uint32_t *)(0x4006EC14)) = 0x00000000; + } + } + } + } + } + NRFX_CRITICAL_SECTION_EXIT(); + + return suspended; +} + +bool nrfx_usbd_wakeup_req(void) +{ + bool started = false; + + NRFX_CRITICAL_SECTION_ENTER(); + if (m_bus_suspend && nrf_usbd_lowpower_check()) + { + nrf_usbd_lowpower_disable(); + started = true; + + if (nrfx_usbd_errata_171()) + { + if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000) + { + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0; + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + } + else + { + *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0; + } + + } + } + NRFX_CRITICAL_SECTION_EXIT(); + + return started; +} + +bool nrfx_usbd_suspend_check(void) +{ + return nrf_usbd_lowpower_check(); +} + +void nrfx_usbd_suspend_irq_config(void) +{ + nrf_usbd_int_disable(m_irq_disabled_in_suspend); +} + +void nrfx_usbd_active_irq_config(void) +{ + nrf_usbd_int_enable(m_irq_disabled_in_suspend); +} + +bool nrfx_usbd_bus_suspend_check(void) +{ + return m_bus_suspend; +} + +void nrfx_usbd_force_bus_wakeup(void) +{ + m_bus_suspend = false; +} + +void nrfx_usbd_ep_max_packet_size_set(nrfx_usbd_ep_t ep, uint16_t size) +{ + /* Only power of 2 size allowed */ + NRFX_ASSERT((size != 0) && (size & (size - 1)) == 0); + /* Packet size cannot be higher than maximum buffer size */ + NRFX_ASSERT((NRF_USBD_EPISO_CHECK(ep) && (size <= usbd_ep_iso_capacity(ep))) || + (!NRF_USBD_EPISO_CHECK(ep) && (size <= NRFX_USBD_EPSIZE))); + + usbd_ep_state_t * p_state = ep_state_access(ep); + p_state->max_packet_size = size; +} + +uint16_t nrfx_usbd_ep_max_packet_size_get(nrfx_usbd_ep_t ep) +{ + usbd_ep_state_t const * p_state = ep_state_access(ep); + return p_state->max_packet_size; +} + +bool nrfx_usbd_ep_enable_check(nrfx_usbd_ep_t ep) +{ + return nrf_usbd_ep_enable_check(ep_to_hal(ep)); +} + +void nrfx_usbd_ep_enable(nrfx_usbd_ep_t ep) +{ + nrf_usbd_int_enable(nrfx_usbd_ep_to_int(ep)); + + if (nrf_usbd_ep_enable_check(ep)) + { + return; + } + nrf_usbd_ep_enable(ep_to_hal(ep)); + if ((NRF_USBD_EP_NR_GET(ep) != 0) && + NRF_USBD_EPOUT_CHECK(ep) && + !NRF_USBD_EPISO_CHECK(ep)) + { + NRFX_CRITICAL_SECTION_ENTER(); + nrfx_usbd_transfer_out_drop(ep); + m_ep_dma_waiting &= ~(1U << ep2bit(ep)); + NRFX_CRITICAL_SECTION_EXIT(); + } +} + +void nrfx_usbd_ep_disable(nrfx_usbd_ep_t ep) +{ + usbd_ep_abort(ep); + nrf_usbd_ep_disable(ep_to_hal(ep)); + nrf_usbd_int_disable(nrfx_usbd_ep_to_int(ep)); +} + +void nrfx_usbd_ep_default_config(void) +{ + nrf_usbd_int_disable( + NRF_USBD_INT_ENDEPIN1_MASK | + NRF_USBD_INT_ENDEPIN2_MASK | + NRF_USBD_INT_ENDEPIN3_MASK | + NRF_USBD_INT_ENDEPIN4_MASK | + NRF_USBD_INT_ENDEPIN5_MASK | + NRF_USBD_INT_ENDEPIN6_MASK | + NRF_USBD_INT_ENDEPIN7_MASK | + NRF_USBD_INT_ENDISOIN0_MASK | + NRF_USBD_INT_ENDEPOUT1_MASK | + NRF_USBD_INT_ENDEPOUT2_MASK | + NRF_USBD_INT_ENDEPOUT3_MASK | + NRF_USBD_INT_ENDEPOUT4_MASK | + NRF_USBD_INT_ENDEPOUT5_MASK | + NRF_USBD_INT_ENDEPOUT6_MASK | + NRF_USBD_INT_ENDEPOUT7_MASK | + NRF_USBD_INT_ENDISOOUT0_MASK + ); + nrf_usbd_int_enable(NRF_USBD_INT_ENDEPIN0_MASK | NRF_USBD_INT_ENDEPOUT0_MASK); + nrf_usbd_ep_all_disable(); +} + +nrfx_err_t nrfx_usbd_ep_transfer( + nrfx_usbd_ep_t ep, + nrfx_usbd_transfer_t const * p_transfer) +{ + nrfx_err_t ret; + const uint8_t ep_bitpos = ep2bit(ep); + NRFX_ASSERT(NULL != p_transfer); + + NRFX_CRITICAL_SECTION_ENTER(); + /* Setup data transaction can go only in one direction at a time */ + if ((NRF_USBD_EP_NR_GET(ep) == 0) && (ep != m_last_setup_dir)) + { + ret = NRFX_ERROR_INVALID_ADDR; + if (NRFX_USBD_FAILED_TRANSFERS_DEBUG && + (NRFX_USBD_ISO_DEBUG || (!NRF_USBD_EPISO_CHECK(ep)))) + { + NRFX_LOG_DEBUG("Transfer failed: Invalid EPr\n"); + } + } + else if ((m_ep_dma_waiting | ((~m_ep_ready) & NRFX_USBD_EPIN_BIT_MASK)) & (1U << ep_bitpos)) + { + /* IN (Device -> Host) transfer has to be transmitted out to allow new transmission */ + ret = NRFX_ERROR_BUSY; + if (NRFX_USBD_FAILED_TRANSFERS_DEBUG) + { + NRFX_LOG_DEBUG("Transfer failed: EP is busy"); + } + } + else + { + usbd_ep_state_t * p_state = ep_state_access(ep); + /* Prepare transfer context and handler description */ + nrfx_usbd_transfer_t * p_context; + if (NRF_USBD_EPIN_CHECK(ep)) + { + p_context = m_ep_feeder_state + NRF_USBD_EP_NR_GET(ep); + if (nrfx_is_in_ram(p_transfer->p_data.tx)) + { + /* RAM */ + if (0 == (p_transfer->flags & NRFX_USBD_TRANSFER_ZLP_FLAG)) + { + p_state->handler.feeder = nrfx_usbd_feeder_ram; + if (NRFX_USBD_ISO_DEBUG || (!NRF_USBD_EPISO_CHECK(ep))) + { + NRFX_LOG_DEBUG( + "Transfer called on endpoint %x, size: %u, mode: " + "RAM", + ep, + p_transfer->size); + } + } + else + { + p_state->handler.feeder = nrfx_usbd_feeder_ram_zlp; + if (NRFX_USBD_ISO_DEBUG || (!NRF_USBD_EPISO_CHECK(ep))) + { + NRFX_LOG_DEBUG( + "Transfer called on endpoint %x, size: %u, mode: " + "RAM_ZLP", + ep, + p_transfer->size); + } + } + } + else + { + /* Flash */ + if (0 == (p_transfer->flags & NRFX_USBD_TRANSFER_ZLP_FLAG)) + { + p_state->handler.feeder = nrfx_usbd_feeder_flash; + if (NRFX_USBD_ISO_DEBUG || (!NRF_USBD_EPISO_CHECK(ep))) + { + NRFX_LOG_DEBUG( + "Transfer called on endpoint %x, size: %u, mode: " + "FLASH", + ep, + p_transfer->size); + } + } + else + { + p_state->handler.feeder = nrfx_usbd_feeder_flash_zlp; + if (NRFX_USBD_ISO_DEBUG || (!NRF_USBD_EPISO_CHECK(ep))) + { + NRFX_LOG_DEBUG( + "Transfer called on endpoint %x, size: %u, mode: " + "FLASH_ZLP", + ep, + p_transfer->size); + } + } + } + } + else + { + p_context = m_ep_consumer_state + NRF_USBD_EP_NR_GET(ep); + NRFX_ASSERT((p_transfer->p_data.rx == NULL) || (nrfx_is_in_ram(p_transfer->p_data.rx))); + p_state->handler.consumer = nrfx_usbd_consumer; + } + *p_context = *p_transfer; + p_state->p_context = p_context; + + p_state->transfer_cnt = 0; + p_state->status = NRFX_USBD_EP_OK; + m_ep_dma_waiting |= 1U << ep_bitpos; + ret = NRFX_SUCCESS; + usbd_int_rise(); + } + NRFX_CRITICAL_SECTION_EXIT(); + return ret; +} + +nrfx_err_t nrfx_usbd_ep_handled_transfer( + nrfx_usbd_ep_t ep, + nrfx_usbd_handler_desc_t const * p_handler) +{ + nrfx_err_t ret; + const uint8_t ep_bitpos = ep2bit(ep); + NRFX_ASSERT(NULL != p_handler); + + NRFX_CRITICAL_SECTION_ENTER(); + /* Setup data transaction can go only in one direction at a time */ + if ((NRF_USBD_EP_NR_GET(ep) == 0) && (ep != m_last_setup_dir)) + { + ret = NRFX_ERROR_INVALID_ADDR; + if (NRFX_USBD_FAILED_TRANSFERS_DEBUG && (NRFX_USBD_ISO_DEBUG || (!NRF_USBD_EPISO_CHECK(ep)))) + { + NRFX_LOG_DEBUG("Transfer failed: Invalid EP"); + } + } + else if ((m_ep_dma_waiting | ((~m_ep_ready) & NRFX_USBD_EPIN_BIT_MASK)) & (1U << ep_bitpos)) + { + /* IN (Device -> Host) transfer has to be transmitted out to allow a new transmission */ + ret = NRFX_ERROR_BUSY; + if (NRFX_USBD_FAILED_TRANSFERS_DEBUG && (NRFX_USBD_ISO_DEBUG || (!NRF_USBD_EPISO_CHECK(ep)))) + { + NRFX_LOG_DEBUG("Transfer failed: EP is busy"); + } + } + else + { + /* Transfer can be configured now */ + usbd_ep_state_t * p_state = ep_state_access(ep); + + p_state->transfer_cnt = 0; + p_state->handler = p_handler->handler; + p_state->p_context = p_handler->p_context; + p_state->status = NRFX_USBD_EP_OK; + m_ep_dma_waiting |= 1U << ep_bitpos; + + ret = NRFX_SUCCESS; + if (NRFX_USBD_ISO_DEBUG || (!NRF_USBD_EPISO_CHECK(ep))) + { + NRFX_LOG_DEBUG("Transfer called on endpoint %x, mode: Handler", ep); + } + usbd_int_rise(); + } + NRFX_CRITICAL_SECTION_EXIT(); + return ret; +} + +void * nrfx_usbd_feeder_buffer_get(void) +{ + return m_tx_buffer; +} + +nrfx_err_t nrfx_usbd_ep_status_get(nrfx_usbd_ep_t ep, size_t * p_size) +{ + nrfx_err_t ret; + + usbd_ep_state_t const * p_state = ep_state_access(ep); + NRFX_CRITICAL_SECTION_ENTER(); + *p_size = p_state->transfer_cnt; + ret = (p_state->handler.consumer == NULL) ? p_state->status : NRFX_ERROR_BUSY; + NRFX_CRITICAL_SECTION_EXIT(); + return ret; +} + +size_t nrfx_usbd_epout_size_get(nrfx_usbd_ep_t ep) +{ + return nrf_usbd_epout_size_get(ep_to_hal(ep)); +} + +bool nrfx_usbd_ep_is_busy(nrfx_usbd_ep_t ep) +{ + return (0 != ((m_ep_dma_waiting | ((~m_ep_ready) & NRFX_USBD_EPIN_BIT_MASK)) & (1U << ep2bit(ep)))); +} + +void nrfx_usbd_ep_stall(nrfx_usbd_ep_t ep) +{ + NRFX_LOG_DEBUG("USB: EP %x stalled.", ep); + nrf_usbd_ep_stall(ep_to_hal(ep)); +} + +void nrfx_usbd_ep_stall_clear(nrfx_usbd_ep_t ep) +{ + if (NRF_USBD_EPOUT_CHECK(ep) && nrfx_usbd_ep_stall_check(ep)) + { + nrfx_usbd_transfer_out_drop(ep); + } + nrf_usbd_ep_unstall(ep_to_hal(ep)); +} + +bool nrfx_usbd_ep_stall_check(nrfx_usbd_ep_t ep) +{ + return nrf_usbd_ep_is_stall(ep_to_hal(ep)); +} + +void nrfx_usbd_ep_dtoggle_clear(nrfx_usbd_ep_t ep) +{ + nrf_usbd_dtoggle_set(ep, NRF_USBD_DTOGGLE_DATA0); +} + +void nrfx_usbd_setup_get(nrfx_usbd_setup_t * p_setup) +{ + memset(p_setup, 0, sizeof(nrfx_usbd_setup_t)); + p_setup->bmRequestType = nrf_usbd_setup_bmrequesttype_get(); + p_setup->bmRequest = nrf_usbd_setup_brequest_get(); + p_setup->wValue = nrf_usbd_setup_wvalue_get(); + p_setup->wIndex = nrf_usbd_setup_windex_get(); + p_setup->wLength = nrf_usbd_setup_wlength_get(); +} + +void nrfx_usbd_setup_data_clear(void) +{ + if (nrfx_usbd_errata_104()) + { + /* For this fix to work properly, it must be ensured that the task is + * executed twice one after another - blocking ISR. This is however a temporary + * solution to be used only before production version of the chip. */ + uint32_t primask_copy = __get_PRIMASK(); + __disable_irq(); + nrf_usbd_task_trigger(NRF_USBD_TASK_EP0RCVOUT); + nrf_usbd_task_trigger(NRF_USBD_TASK_EP0RCVOUT); + __set_PRIMASK(primask_copy); + } + else + { + nrf_usbd_task_trigger(NRF_USBD_TASK_EP0RCVOUT); + } +} + +void nrfx_usbd_setup_clear(void) +{ + NRFX_LOG_DEBUG(">> ep0status >>"); + nrf_usbd_task_trigger(NRF_USBD_TASK_EP0STATUS); +} + +void nrfx_usbd_setup_stall(void) +{ + NRFX_LOG_DEBUG("Setup stalled."); + nrf_usbd_task_trigger(NRF_USBD_TASK_EP0STALL); +} + +nrfx_usbd_ep_t nrfx_usbd_last_setup_dir_get(void) +{ + return m_last_setup_dir; +} + +void nrfx_usbd_transfer_out_drop(nrfx_usbd_ep_t ep) +{ + NRFX_ASSERT(NRF_USBD_EPOUT_CHECK(ep)); + + if (nrfx_usbd_errata_200()) + { + NRFX_CRITICAL_SECTION_ENTER(); + m_ep_ready &= ~(1U << ep2bit(ep)); + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7C5 + (2u * NRF_USBD_EP_NR_GET(ep)); + *((volatile uint32_t *)(NRF_USBD_BASE + 0x804)) = 0; + (void)(*((volatile uint32_t *)(NRF_USBD_BASE + 0x804))); + NRFX_CRITICAL_SECTION_EXIT(); + } + else + { + NRFX_CRITICAL_SECTION_ENTER(); + m_ep_ready &= ~(1U << ep2bit(ep)); + if (!NRF_USBD_EPISO_CHECK(ep)) + { + nrf_usbd_epout_clear(ep); + } + NRFX_CRITICAL_SECTION_EXIT(); + } +} + +#endif // NRFX_CHECK(NRFX_USBD_ENABLED) diff --git a/drivers/src/nrfx_usbd_errata.h b/drivers/src/nrfx_usbd_errata.h new file mode 100644 index 000000000..b95d780b3 --- /dev/null +++ b/drivers/src/nrfx_usbd_errata.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * All rights reserved. + * + * 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. + */ + +#ifndef NRFX_USBD_ERRATA_H__ +#define NRFX_USBD_ERRATA_H__ + +#include + +#ifndef NRFX_USBD_ERRATA_ENABLE +/** + * @brief The constant that informs if errata should be enabled at all. + * + * If this constant is set to 0, all the Errata bug fixes will be automatically disabled. + */ +#define NRFX_USBD_ERRATA_ENABLE 1 +#endif + +static inline bool nrfx_usbd_errata_type_52840(void) +{ + return (*(uint32_t *)0x10000130UL == 0x8UL); +} + +static inline bool nrfx_usbd_errata_type_52840_eng_a(void) +{ + return (nrfx_usbd_errata_type_52840() && (*(uint32_t *)0x10000134UL == 0x0UL)); +} + +static inline bool nrfx_usbd_errata_type_52840_eng_b(void) +{ + return (nrfx_usbd_errata_type_52840() && (*(uint32_t *)0x10000134UL == 0x1UL)); +} + +static inline bool nrfx_usbd_errata_type_52840_eng_c(void) +{ + return (nrfx_usbd_errata_type_52840() && (*(uint32_t *)0x10000134UL == 0x2UL)); +} + +static inline bool nrfx_usbd_errata_type_52840_eng_d(void) +{ + return (nrfx_usbd_errata_type_52840() && (*(uint32_t *)0x10000134UL == 0x3UL)); +} + +/* Errata: USBD: EPDATA event is not always generated. */ +static inline bool nrfx_usbd_errata_104(void) +{ + return (NRFX_USBD_ERRATA_ENABLE && nrfx_usbd_errata_type_52840_eng_a()); +} + +/* Errata: During setup read/write transfer USBD acknowledges setup stage without SETUP task. */ +static inline bool nrfx_usbd_errata_154(void) +{ + return (NRFX_USBD_ERRATA_ENABLE && nrfx_usbd_errata_type_52840_eng_a()); +} + +/* Errata: ISO double buffering not functional. */ +static inline bool nrfx_usbd_errata_166(void) +{ + return (NRFX_USBD_ERRATA_ENABLE && true); +} + +/* Errata: USBD might not reach its active state. */ +static inline bool nrfx_usbd_errata_171(void) +{ + return (NRFX_USBD_ERRATA_ENABLE && true); +} + +/* Errata: USB cannot be enabled. */ +static inline bool nrfx_usbd_errata_187(void) +{ + return (NRFX_USBD_ERRATA_ENABLE && + (nrfx_usbd_errata_type_52840_eng_b() || + nrfx_usbd_errata_type_52840_eng_c() || + nrfx_usbd_errata_type_52840_eng_d()) + ); +} + +/* Errata: USBD cannot receive tasks during DMA. */ +static inline bool nrfx_usbd_errata_199(void) +{ + return (NRFX_USBD_ERRATA_ENABLE && true); +} + +/* Errata: SIZE.EPOUT not writable. */ +static inline bool nrfx_usbd_errata_200(void) +{ + return (NRFX_USBD_ERRATA_ENABLE && nrfx_usbd_errata_type_52840_eng_a()); +} + +#endif // NRFX_USBD_ERRATA_H__ diff --git a/hal/nrf_nfct.h b/hal/nrf_nfct.h new file mode 100644 index 000000000..57560e16f --- /dev/null +++ b/hal/nrf_nfct.h @@ -0,0 +1,1070 @@ +/* + * Copyright (c) 2018, Nordic Semiconductor ASA + * All rights reserved. + * + * 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. + */ + +#ifndef NRF_NFCT_H__ +#define NRF_NFCT_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup nrf_nfct_hal NFCT HAL + * @{ + * @ingroup nrf_nfct + * + * @brief Hardware access layer (HAL) for the Near Field Communication Tag (NFCT) peripheral. + */ + +#define NRF_NFCT_CRC_SIZE 2 /**< CRC size in bytes. */ + +/** + * @brief NFCT tasks + */ +typedef enum /*lint -save -e30 */ +{ + NRF_NFCT_TASK_ACTIVATE = offsetof(NRF_NFCT_Type, TASKS_ACTIVATE), /**< Activate the NFCT peripheral for the incoming and outgoing frames, change state to activated. */ + NRF_NFCT_TASK_DISABLE = offsetof(NRF_NFCT_Type, TASKS_DISABLE), /**< Disable the NFCT peripheral. */ + NRF_NFCT_TASK_SENSE = offsetof(NRF_NFCT_Type, TASKS_SENSE), /**< Enable the NFC sense field mode, change state to sense mode. */ + NRF_NFCT_TASK_STARTTX = offsetof(NRF_NFCT_Type, TASKS_STARTTX), /**< Start the transmission of an outgoing frame, change state to transmit. */ + NRF_NFCT_TASK_ENABLERXDATA = offsetof(NRF_NFCT_Type, TASKS_ENABLERXDATA), /**< Initialize EasyDMA for receive. */ + NRF_NFCT_TASK_GOIDLE = offsetof(NRF_NFCT_Type, TASKS_GOIDLE), /**< Force state machine to the IDLE state. */ + NRF_NFCT_TASK_GOSLEEP = offsetof(NRF_NFCT_Type, TASKS_GOSLEEP), /**< Force state machine to the SLEEP_A state. */ +} nrf_nfct_task_t; /*lint -restore */ + +/** + * @brief NFCT events + */ +typedef enum /*lint -save -e30 */ +{ + NRF_NFCT_EVENT_READY = offsetof(NRF_NFCT_Type, EVENTS_READY), /**< The NFCT peripheral is ready to receive and send frames. */ + NRF_NFCT_EVENT_FIELDDETECTED = offsetof(NRF_NFCT_Type, EVENTS_FIELDDETECTED), /**< Remote NFC field is detected. */ + NRF_NFCT_EVENT_FIELDLOST = offsetof(NRF_NFCT_Type, EVENTS_FIELDLOST), /**< Remote NFC field is lost. */ + NRF_NFCT_EVENT_TXFRAMESTART = offsetof(NRF_NFCT_Type, EVENTS_TXFRAMESTART), /**< The start of the first symbol of a transmitted frame. */ + NRF_NFCT_EVENT_TXFRAMEEND = offsetof(NRF_NFCT_Type, EVENTS_TXFRAMEEND), /**< The end of the last transmitted on-air symbol of a frame. */ + NRF_NFCT_EVENT_RXFRAMESTART = offsetof(NRF_NFCT_Type, EVENTS_RXFRAMESTART), /**< The end of the first symbol of a received frame. */ + NRF_NFCT_EVENT_RXFRAMEEND = offsetof(NRF_NFCT_Type, EVENTS_RXFRAMEEND), /**< Received data was checked (CRC, parity) and transferred to RAM, and EasyDMA ended accessing the RX buffer. */ + NRF_NFCT_EVENT_ERROR = offsetof(NRF_NFCT_Type, EVENTS_ERROR), /**< NFC error reported. The ERRORSTATUS register contains details on the source of the error. */ + NRF_NFCT_EVENT_RXERROR = offsetof(NRF_NFCT_Type, EVENTS_RXERROR), /**< NFC RX frame error reported. The FRAMESTATUS.RX register contains details on the source of the error. */ + NRF_NFCT_EVENT_ENDRX = offsetof(NRF_NFCT_Type, EVENTS_ENDRX), /**< RX buffer (as defined by PACKETPTR and MAXLEN) in Data RAM full. */ + NRF_NFCT_EVENT_ENDTX = offsetof(NRF_NFCT_Type, EVENTS_ENDTX), /**< Transmission of data in RAM ended, and EasyDMA ended accessing the TX buffer. */ + NRF_NFCT_EVENT_AUTOCOLRESSTARTED = offsetof(NRF_NFCT_Type, EVENTS_AUTOCOLRESSTARTED), /**< Auto collision resolution process started. */ + NRF_NFCT_EVENT_COLLISION = offsetof(NRF_NFCT_Type, EVENTS_COLLISION), /**< NFC auto collision resolution error reported. */ + NRF_NFCT_EVENT_SELECTED = offsetof(NRF_NFCT_Type, EVENTS_SELECTED), /**< NFC auto collision resolution successfully completed. */ + NRF_NFCT_EVENT_STARTED = offsetof(NRF_NFCT_Type, EVENTS_STARTED), /**< EasyDMA is ready to receive or send frames. */ +} nrf_nfct_event_t; /*lint -restore */ + +/** + * @brief NFCT shorts + */ +typedef enum +{ + NRF_NFCT_SHORT_FIELDDETECTED_ACTIVATE_MASK = NFCT_SHORTS_FIELDDETECTED_ACTIVATE_Msk, /**< Shortcut between the FIELDDETECTED event and the ACTIVATE task. */ + NRF_NFCT_SHORT_FIELDLOST_SENSE_MASK = NFCT_SHORTS_FIELDLOST_SENSE_Msk, /**< Shortcut between the FIELDLOST event and the SENSE task. */ +#if defined(NFCT_SHORTS_TXFRAMEEND_ENABLERXDATA_Msk) || defined(__NRFX_DOXYGEN__) + NRF_NFCT_SHORT_TXFRAMEEND_ENABLERXDATA_MASK = NFCT_SHORTS_TXFRAMEEND_ENABLERXDATA_Msk, /**< Shortcut between the TXFRAMEEND event and the ENABLERXDATA task. */ +#endif // defined(NFCT_SHORTS_TXFRAMEEND_ENABLERXDATA_Msk) || defined(__NRFX_DOXYGEN__) +} nrf_nfct_short_mask_t; + +/** + * @brief NFCT interrupts + */ +typedef enum +{ + NRF_NFCT_INT_READY_MASK = NFCT_INTEN_READY_Msk, /**< Interrupt on READY event. */ + NRF_NFCT_INT_FIELDDETECTED_MASK = NFCT_INTEN_FIELDDETECTED_Msk, /**< Interrupt on FIELDDETECTED event. */ + NRF_NFCT_INT_FIELDLOST_MASK = NFCT_INTEN_FIELDLOST_Msk, /**< Interrupt on FIELDLOST event. */ + NRF_NFCT_INT_TXFRAMESTART_MASK = NFCT_INTEN_TXFRAMESTART_Msk, /**< Interrupt on TXFRAMESTART event. */ + NRF_NFCT_INT_TXFRAMEEND_MASK = NFCT_INTEN_TXFRAMEEND_Msk, /**< Interrupt on TXFRAMEEND event. */ + NRF_NFCT_INT_RXFRAMESTART_MASK = NFCT_INTEN_RXFRAMESTART_Msk, /**< Interrupt on RXFRAMESTART event. */ + NRF_NFCT_INT_RXFRAMEEND_MASK = NFCT_INTEN_RXFRAMEEND_Msk, /**< Interrupt on RXFRAMEEND event. */ + NRF_NFCT_INT_ERROR_MASK = NFCT_INTEN_ERROR_Msk, /**< Interrupt on ERROR event. */ + NRF_NFCT_INT_RXERROR_MASK = NFCT_INTEN_RXERROR_Msk, /**< Interrupt on RXERROR event. */ + NRF_NFCT_INT_ENDRX_MASK = NFCT_INTEN_ENDRX_Msk, /**< Interrupt on ENDRX event. */ + NRF_NFCT_INT_ENDTX_MASK = NFCT_INTEN_ENDTX_Msk, /**< Interrupt on ENDTX event. */ + NRF_NFCT_INT_AUTOCOLRESSTARTED_MASK = NFCT_INTEN_AUTOCOLRESSTARTED_Msk, /**< Interrupt on AUTOCOLRESSTARTED event. */ + NRF_NFCT_INT_COLLISION_MASK = NFCT_INTEN_COLLISION_Msk, /**< Interrupt on COLLISION event. */ + NRF_NFCT_INT_SELECTED_MASK = NFCT_INTEN_SELECTED_Msk, /**< Interrupt on SELECTED event. */ + NRF_NFCT_INT_STARTED_MASK = NFCT_INTEN_STARTED_Msk, /**< Interrupt on STARTED event. */ +} nrf_nfct_int_mask_t; + +/** + * @brief NFC error status bit masks. + */ +typedef enum +{ + NRF_NFCT_ERROR_FRAMEDELAYTIMEOUT_MASK = NFCT_ERRORSTATUS_FRAMEDELAYTIMEOUT_Msk, /**< Timeout of the Frame Delay Timer (no frame transmission started in the FDT window). */ +#if defined(NFCT_ERRORSTATUS_NFCFIELDTOOSTRONG_Msk) || defined(__NRFX_DOXYGEN__) + NRF_NFCT_ERROR_NFCFIELDTOOSTRONG_MASK = NFCT_ERRORSTATUS_NFCFIELDTOOSTRONG_Msk, /**< Field level is too high at maximum load resistance. */ +#endif // defined(NFCT_ERRORSTATUS_NFCFIELDTOOSTRONG_Msk) || defined(__NRFX_DOXYGEN__) +#if defined(NFCT_ERRORSTATUS_NFCFIELDTOOWEAK_Msk) || defined(__NRFX_DOXYGEN__) + NRF_NFCT_ERROR_NFCFIELDTOOWEAK_MASK = NFCT_ERRORSTATUS_NFCFIELDTOOWEAK_Msk, /**< Field level is too low at minimum load resistance. */ +#endif // defined(NFCT_ERRORSTATUS_NFCFIELDTOOWEAK_Msk) || defined(__NRFX_DOXYGEN__) +} nrf_nfct_error_status_t; + +/** + * @brief NFC received frame status bit masks. + */ +typedef enum +{ + NRF_NFCT_RX_FRAME_STATUS_CRC_MASK = NFCT_FRAMESTATUS_RX_CRCERROR_Msk, /**< CRC status mask. */ + NRF_NFCT_RX_FRAME_STATUS_PARITY_MASK = NFCT_FRAMESTATUS_RX_PARITYSTATUS_Msk, /**< Parity status mask. */ + NRF_NFCT_RX_FRAME_STATUS_OVERRUN_MASK = NFCT_FRAMESTATUS_RX_OVERRUN_Msk, /**< Overrun status mask. */ +} nrf_nfct_rx_frame_status_t; + +#if defined(NFCT_NFCTAGSTATE_NFCTAGSTATE_Msk) || defined(__NRFX_DOXYGEN__) +/** + * @brief NFC tag state. + */ +typedef enum +{ + NRF_NFCT_TAG_STATE_DISABLED = NFCT_NFCTAGSTATE_NFCTAGSTATE_Disabled, /**< Disabled or sensing NFC field. */ + NRF_NFCT_TAG_STATE_RAMP_UP = NFCT_NFCTAGSTATE_NFCTAGSTATE_RampUp, /**< Ramping up. */ + NRF_NFCT_TAG_STATE_IDLE = NFCT_NFCTAGSTATE_NFCTAGSTATE_Idle, /**< Idle. */ + NRF_NFCT_TAG_STATE_RECEIVE = NFCT_NFCTAGSTATE_NFCTAGSTATE_Receive, /**< Receiving data. */ + NRF_NFCT_TAG_STATE_FRAME_DELAY = NFCT_NFCTAGSTATE_NFCTAGSTATE_FrameDelay, /**< Counting Frame Delay Time since the last symbol of the last received frame. */ + NRF_NFCT_TAG_STATE_TRANSMIT = NFCT_NFCTAGSTATE_NFCTAGSTATE_Transmit /**< Transmitting data. */ +} nrf_nfct_tag_state_t; +#endif // defined(NFCT_NFCTAGSTATE_NFCTAGSTATE_Msk) || defined(__NRFX_DOXYGEN__) + +#if defined (NFCT_SLEEPSTATE_SLEEPSTATE_Msk) || defined(__NRFX_DOXYGEN__) +/** + * @brief NFC tag sleep state. + * + * @details Shows the sleep state during automatic collision resolution + * according to the NFC Forum Activity Technical Specification v2.0. + */ +typedef enum +{ + NRF_NFCT_SLEEP_STATE_IDLE = NFCT_SLEEPSTATE_SLEEPSTATE_Idle, /**< 'IDLE' state. */ + NRF_NFCT_SLEEP_STATE_SLEEP_A = NFCT_SLEEPSTATE_SLEEPSTATE_SleepA /**< 'SLEEP_A' state. */ +} nrf_nfct_sleep_state_t; +#endif // defined (NFCT_SLEEPSTATE_SLEEPSTATE_Msk) || defined(__NRFX_DOXYGEN__) + +/** + * @brief NFC field state bit masks. + */ +typedef enum +{ + NRF_NFCT_FIELD_STATE_PRESENT_MASK = NFCT_FIELDPRESENT_FIELDPRESENT_Msk, /**< Field presence mask. */ + NRF_NFCT_FIELD_STATE_LOCK_MASK = NFCT_FIELDPRESENT_LOCKDETECT_Msk /**< Field lock mask. */ +} nrf_nfct_field_state_t; + +/** + * @brief NFC frame delay mode for data transmission. + */ +typedef enum +{ + NRF_NFCT_FRAME_DELAY_MODE_FREERUN = NFCT_FRAMEDELAYMODE_FRAMEDELAYMODE_FreeRun, /**< Frame transmission starts when @ref NRF_NFCT_TASK_STARTTX is set (delay timer is not used). */ + NRF_NFCT_FRAME_DELAY_MODE_WINDOW = NFCT_FRAMEDELAYMODE_FRAMEDELAYMODE_Window, /**< Frame transmission starts in a window between FRAMEDELAYMIN and FRAMEDELAYMAX. */ + NRF_NFCT_FRAME_DELAY_MODE_EXACTVAL = NFCT_FRAMEDELAYMODE_FRAMEDELAYMODE_ExactVal, /**< Frame transmission starts when the delay timer reaches FRAMEDELAYMAX. */ + NRF_NFCT_FRAME_DELAY_MODE_WINDOWGRID = NFCT_FRAMEDELAYMODE_FRAMEDELAYMODE_WindowGrid /**< Frame transmission starts in a bit grid between FRAMEDELAYMIN and FRAMEDELAYMAX. */ +} nrf_nfct_frame_delay_mode_t; + +/** + * @brief Bit masks for NFC transmission frame configuration. + */ +typedef enum +{ + NRF_NFCT_TX_FRAME_CONFIG_PARITY = NFCT_TXD_FRAMECONFIG_PARITY_Msk, /**< Indicates whether parity is added in the transmitted frames. */ + NRF_NFCT_TX_FRAME_CONFIG_DISCARD_START = NFCT_TXD_FRAMECONFIG_DISCARDMODE_Msk, /**< Indicates whether unused bits are discarded at the start or at the end of the transmitted frames. */ + NRF_NFCT_TX_FRAME_CONFIG_SOF = NFCT_TXD_FRAMECONFIG_SOF_Msk, /**< Indicates whether SoF symbol is added in the transmitted frames. */ + NRF_NFCT_TX_FRAME_CONFIG_CRC16 = NFCT_TXD_FRAMECONFIG_CRCMODETX_Msk /**< Indicates whether CRC is added in the transmitted frames. */ +} nrf_nfct_tx_frame_config_t; + +/** + * @brief Bit masks for NFC reception frame configuration. + */ +typedef enum +{ + NRF_NFCT_RX_FRAME_CONFIG_PARITY = NFCT_RXD_FRAMECONFIG_PARITY_Msk, /**< Indicates whether parity is expected in the received frames. */ + NRF_NFCT_RX_FRAME_CONFIG_SOF = NFCT_RXD_FRAMECONFIG_SOF_Msk, /**< Indicates whether SoF symbol is expected in the received frames. */ + NRF_NFCT_RX_FRAME_CONFIG_CRC16 = NFCT_RXD_FRAMECONFIG_CRCMODERX_Msk /**< Indicates whether CRC is expected and checked in the received frames. */ +} nrf_nfct_rx_frame_config_t; + +/** + * @brief 'NFCI1 size' NFC field configuration for the SENS_RES frame according to the NFC Forum Digital Protocol Technical Specification. + */ +typedef enum +{ + NRF_NFCT_SENSRES_NFCID1_SIZE_SINGLE = + NFCT_SENSRES_NFCIDSIZE_NFCID1Single << NFCT_SENSRES_NFCIDSIZE_Pos, /**< Single size NFCID1 (4 bytes). */ + NRF_NFCT_SENSRES_NFCID1_SIZE_DOUBLE = + NFCT_SENSRES_NFCIDSIZE_NFCID1Double << NFCT_SENSRES_NFCIDSIZE_Pos, /**< Double size NFCID1 (7 bytes). */ + NRF_NFCT_SENSRES_NFCID1_SIZE_TRIPLE = + NFCT_SENSRES_NFCIDSIZE_NFCID1Triple << NFCT_SENSRES_NFCIDSIZE_Pos, /**< Triple size NFCID1 (10 bytes). */ + NRF_NFCT_SENSRES_NFCID1_SIZE_DEFAULT = + NFCT_SENSRES_NFCIDSIZE_Msk /**< Default size. Use this option to leave NFCID1 size unchanged. */ +} nrf_nfct_sensres_nfcid1_size_t; + +/** + * @brief 'Bit frame SDD' NFC field configuration for the SENS_RES frame according to the NFC Forum Digital Protocol Technical Specification. + */ +typedef enum +{ + NRF_NFCT_SENSRES_BIT_FRAME_SDD_00000 = + NFCT_SENSRES_BITFRAMESDD_SDD00000 << NFCT_SENSRES_BITFRAMESDD_Pos, /**< SDD pattern 00000. */ + NRF_NFCT_SENSRES_BIT_FRAME_SDD_00001 = + NFCT_SENSRES_BITFRAMESDD_SDD00001 << NFCT_SENSRES_BITFRAMESDD_Pos, /**< SDD pattern 00001. */ + NRF_NFCT_SENSRES_BIT_FRAME_SDD_00010 = + NFCT_SENSRES_BITFRAMESDD_SDD00010 << NFCT_SENSRES_BITFRAMESDD_Pos, /**< SDD pattern 00010. */ + NRF_NFCT_SENSRES_BIT_FRAME_SDD_00100 = + NFCT_SENSRES_BITFRAMESDD_SDD00100 << NFCT_SENSRES_BITFRAMESDD_Pos, /**< SDD pattern 00100. */ + NRF_NFCT_SENSRES_BIT_FRAME_SDD_01000 = + NFCT_SENSRES_BITFRAMESDD_SDD01000 << NFCT_SENSRES_BITFRAMESDD_Pos, /**< SDD pattern 01000. */ + NRF_NFCT_SENSRES_BIT_FRAME_SDD_10000 = + NFCT_SENSRES_BITFRAMESDD_SDD10000 << NFCT_SENSRES_BITFRAMESDD_Pos /**< SDD pattern 10000. */ +} nrf_nfct_sensres_bit_frame_sdd_t; + +/** + * @brief 'Platofrm Config' NFC field configuration for the SENS_RES frame according to the NFC Forum Digital Protocol Technical Specification. + */ +typedef enum +{ + /**< SENS_RES 'Platform Config' field (b4-b1) value for Type 1 Tag platform. */ + NRF_NFCT_SENSRES_PLATFORM_CONFIG_T1T = 6 << NFCT_SENSRES_PLATFCONFIG_Pos, + /**< SENS_RES 'Platform Config' field (b7-b6) value for any platform except Type 1 Tag platform. */ + NRF_NFCT_SENSRES_PLATFORM_CONFIG_OTHER = 0 << NFCT_SENSRES_PLATFCONFIG_Pos +} nrf_nfct_sensres_platform_config_t; + +/** + * @brief Bit masks for SEL_RES NFC frame configuration. + */ +typedef enum +{ + NRF_NFCT_SELRES_CASCADE_MASK = NFCT_SELRES_CASCADE_Msk, /**< SEL_RES Cascade field bit mask. */ + NRF_NFCT_SELRES_PROTOCOL_MASK = NFCT_SELRES_PROTOCOL_Msk /**< SEL_RES Protocol field bit mask. */ +} nrf_nfct_selres_t; + +/** + * @brief Protocol NFC field (bits b7 and b6) configuration for the SEL_RES frame according to the NFC Forum Digital Protocol Technical Specification. + */ +typedef enum +{ + NRF_NFCT_SELRES_PROTOCOL_T2T = 0, /**< Type 2 Tag platform. */ + NRF_NFCT_SELRES_PROTOCOL_T4AT = 1, /**< Type 4A Tag platform. */ + NRF_NFCT_SELRES_PROTOCOL_NFCDEP = 2, /**< NFC-DEP Protocol. */ + NRF_NFCT_SELRES_PROTOCOL_NFCDEP_T4AT = 3, /**< NFC-DEP Protocol and Type 4A Tag platform). */ +} nrf_nfct_selres_protocol_t; + +/** + * @brief Function for activating a specific NFCT task. + * + * @param[in] task Task. + */ +__STATIC_INLINE void nrf_nfct_task_trigger(nrf_nfct_task_t task); + +/** + * @brief Function for returning the address of a specific NFCT task register. + * + * @param[in] task Task. + * + * @return Task address. + */ +__STATIC_INLINE uint32_t nrf_nfct_task_address_get(nrf_nfct_task_t task); + +/** + * @brief Function for clearing a specific event. + * + * @param[in] event Event. + */ +__STATIC_INLINE void nrf_nfct_event_clear(nrf_nfct_event_t event); + +/** + * @brief Function for returning the state of a specific event. + * + * @param[in] event Event. + * + * @retval true If the event is set. + * @retval false If the event is not set. + */ +__STATIC_INLINE bool nrf_nfct_event_check(nrf_nfct_event_t event); + +/** + * @brief Function for returning the address of a specific NFCT event register. + * + * @param[in] event Event. + * + * @return Address. + */ +__STATIC_INLINE uint32_t nrf_nfct_event_address_get(nrf_nfct_event_t event); + +/** + * @brief Function for enabling selected shortcuts. + * + * @param[in] short_mask Shortcut mask. + */ +__STATIC_INLINE void nrf_nfct_shorts_enable(uint32_t short_mask); + +/** + * @brief Function for disabling selected shortcuts. + * + * @param[in] short_mask Shortcut mask. + */ +__STATIC_INLINE void nrf_nfct_shorts_disable(uint32_t short_mask); + +/** + * @brief Function for retrieving the enabled shortcuts. + * + * @return Flags of the currently enabled shortcuts. + */ +__STATIC_INLINE uint32_t nrf_nfct_shorts_get(void); + +/** + * @brief Function for setting shortcuts. + * + * @param[in] short_mask Shortcut mask. + */ +__STATIC_INLINE void nrf_nfct_shorts_set(uint32_t short_mask); + +/** + * @brief Function for enabling the selected interrupts. + * + * @param[in] int_mask Interrupt mask. + */ +__STATIC_INLINE void nrf_nfct_int_enable(uint32_t int_mask); + +/** + * @brief Function for retrieving the state of the selected interrupts. + * + * @param[in] int_mask Interrupt mask. + * + * @retval true If any of the selected interrupts is enabled. + * @retval false If none of the selected interrupts is enabled. + */ +__STATIC_INLINE bool nrf_nfct_int_enable_check(uint32_t int_mask); + +/** + * @brief Function for retrieving the information about enabled interrupts. + * + * @return The flags of the enabled interrupts. + */ +__STATIC_INLINE uint32_t nrf_nfct_int_enable_get(void); + +/** + * @brief Function for disabling the selected interrupts. + * + * @param[in] int_mask Interrupt mask. + */ +__STATIC_INLINE void nrf_nfct_int_disable(uint32_t int_mask); + +/** + * @brief Function for getting the NFCT error status. + * + * @return The NFCT error status flags, defined in @ref nrf_nfct_error_status_t. + */ +__STATIC_INLINE uint32_t nrf_nfct_error_status_get(void); + +/** + * @brief Function for clearing the NFCT error status. + * + * @param[in] error_flag Error flags to be cleared, defined in @ref nrf_nfct_error_status_t. + */ +__STATIC_INLINE void nrf_nfct_error_status_clear(uint32_t error_flag); + +/** + * @brief Function for getting the NFC frame reception status. + * + * @return The flags of the NFC frame reception status, defined in @ref nrf_nfct_rx_frame_status_t. + */ +__STATIC_INLINE uint32_t nrf_nfct_rx_frame_status_get(void); + +/** + * @brief Function for clearing the NFC frame reception status. + * + * @param[in] framestatus_flags Status flags to be cleared, defined in @ref nrf_nfct_rx_frame_status_t. + */ +__STATIC_INLINE void nrf_nfct_rx_frame_status_clear(uint32_t framestatus_flags); + +#if defined(NFCT_NFCTAGSTATE_NFCTAGSTATE_Msk) || defined(__NRFX_DOXYGEN__) +/** + * @brief Function for getting the NFC tag state. + * + * @retval NRF_NFCT_TAG_STATE_DISABLED NFC tag is disabled. + * @retval NRF_NFCT_TAG_STATE_RAMP_UP NFC tag is ramping up. + * @retval NRF_NFCT_TAG_STATE_IDLE NFC tag is activated and idle. + * @retval NRF_NFCT_TAG_STATE_RECEIVE NFC tag is receiving data. + * @retval NRF_NFCT_TAG_STATE_FRAME_DELAY Frame Delay Timer of the NFC tag is counting ticks + * since the last symbol of the last received frame. + * @retval NRF_NFCT_TAG_STATE_TRANSMIT NFC tag is transmitting data. + */ +__STATIC_INLINE nrf_nfct_tag_state_t nrf_nfct_tag_state_get(void); +#endif // defined(NFCT_NFCTAGSTATE_NFCTAGSTATE_Msk) || defined(__NRFX_DOXYGEN__) + +#if defined (NFCT_SLEEPSTATE_SLEEPSTATE_Msk) || defined(__NRFX_DOXYGEN__) +/** + * @brief Function for getting the NFC tag sleep state during the automatic collision resolution. + * + * @details The returned value is the last state before the autimatic collision resolution started. + * + * @retval NRF_NFCT_SLEEP_STATE_IDLE NFC tag was in IDLE state before the automatic collision resolution started. + * @retval NRF_NFCT_SLEEP_STATE_SLEEP_A NFC tag was in SLEEP_A state before the automatic collision resolution started. + */ +__STATIC_INLINE nrf_nfct_sleep_state_t nrf_nfct_sleep_state_get(void); +#endif // defined (NFCT_SLEEPSTATE_SLEEPSTATE_Msk) || defined(__NRFX_DOXYGEN__) + +/** + * @brief Function for getting the status of the external NFC field detection. + * + * @return The NFC field detection status. Status bits can be checked by using @ref nrf_nfct_field_state_t. + */ +__STATIC_INLINE uint8_t nrf_nfct_field_status_get(void); + +/** + * @brief Function for getting the minimum Frame Delay Time value. + * + * @details This is the minimum value for Frame Delay Timer. It controls the shortest time between + * the last symbol of the last received frame and the start of the transmission of a new TX frame. + * + * + * @return The minimum Frame Delay Time value in 13.56-MHz clock ticks. + */ +__STATIC_INLINE uint16_t nrf_nfct_frame_delay_min_get(void); + +/** + * @brief Function for setting the minimum Frame Delay Time value. + * + * @details This is the minimum value for Frame Delay Timer. It controls the shortest time between + * the last symbol of the last received frame and the start of the transmission of a new TX frame. + * + * @param[in] frame_delay_min Minimum Frame Delay Time value in 13.56-MHz clock ticks. + */ +__STATIC_INLINE void nrf_nfct_frame_delay_min_set(uint16_t frame_delay_min); + +/** + * @brief Function for getting the maximum Frame Delay Time value. + * + * @details This is the maximum value for Frame Delay Timer. It controls the longest time between + * the last symbol of the last received frame and the start of the transmission of a new TX frame. + * If no transmission starts before the Frame Delay Timer timeout, + * @ref NRF_NFCT_ERROR_FRAMEDELAYTIMEOUT_MASK is set. + * + * @return The maximum Frame Delay Time value in 13.56-MHz clock ticks. + */ +__STATIC_INLINE uint32_t nrf_nfct_frame_delay_max_get(void); + +/** + * @brief Function for setting the maximum Frame Delay Time value. + * + * @details This is the maximum value for Frame Delay Timer. It controls the longest time between + * the last symbol of the last received frame and the start of the transmission of a new TX frame. + * If no transmission starts before the Frame Delay Timer timeout, + * @ref NRF_NFCT_ERROR_FRAMEDELAYTIMEOUT_MASK is set. + * + * @param[in] frame_delay_max Maximum Frame Delay Time value in 13.56-MHz clock ticks. + */ +__STATIC_INLINE void nrf_nfct_frame_delay_max_set(uint32_t frame_delay_max); + +/** + * @brief Function for getting the Frame Delay Mode configuration. + * + * @return The configured Frame Delay Mode. + */ +__STATIC_INLINE nrf_nfct_frame_delay_mode_t nrf_nfct_frame_delay_mode_get(void); + +/** + * @brief Function for setting the NFC Frame Delay Mode configuration. + * + * @param[in] frame_delay_mode Frame Delay Mode configuration. + */ +__STATIC_INLINE void nrf_nfct_frame_delay_mode_set(nrf_nfct_frame_delay_mode_t frame_delay_mode); + +/** + * @brief Function for getting the pointer to the NFCT RX/TX buffer. + * + * @return The configured pointer to the receive or transmit buffer. + */ +__STATIC_INLINE uint8_t * nrf_nfct_rxtx_buffer_get(void); + +/** + * @brief Function for setting the the NFCT RX/TX buffer (address and maximum length). + * + * @note Buffer for the NFC RX/TX data is used by EasyDMA and must be located in RAM. + * + * @param[in] p_rxtx_buf Pointer to the receive or transmit buffer. + * @param[in] max_txrx_len Maximum receive or transmit length in bytes (size of the RAM buffer for EasyDMA). + */ +__STATIC_INLINE void nrf_nfct_rxtx_buffer_set(uint8_t * p_rxtx_buf, + uint16_t max_txrx_len); + +/** + * @brief Function for getting the NFCT RX/TX maximum buffer length. + * + * @return The configured maximum receive or transmit length in bytes (size of the RX/TX buffer for EasyDMA). + */ +__STATIC_INLINE uint16_t nrf_nfct_max_rxtx_length_get(void); + +/** + * @brief Function for getting the flags for NFC frame transmission configuration. + * + * @return The flags of the NFCT frame transmission configuration, defined in @ref nrf_nfct_tx_frame_config_t. + */ +__STATIC_INLINE uint8_t nrf_nfct_tx_frame_config_get(void); + +/** + * @brief Function for setting up the flags of the NFC frame transmission configuration. + * + * @param[in] flags Flags for NFCT TX configuration. Use @ref nrf_nfct_tx_frame_config_t for setting. + */ +__STATIC_INLINE void nrf_nfct_tx_frame_config_set(uint8_t flags); + +/** + * @brief Function for getting the length of the configured transmission frame. + * + * @note NFC frames do not have to consist of full bytes only, therefore data amount for transmission + * is configured in number of bits. + * + * @return Number of bits to be sent excluding CRC, parity, SoF, and EoF. + */ +__STATIC_INLINE uint16_t nrf_nfct_tx_bits_get(void); + +/** + * @brief Function for setting up the NFC frame transmission. + * + * @details Set the number of TX bits excluding CRC, parity, SoF, and EoF. + * + * @note Source of data for transmission is set by using @ref nrf_nfct_rxtx_buffer_set. + * @note NFC frames do not have to consist of full bytes only, therefore data amount for transmission + * is configured in number of bits. + * + * @param[in] tx_bits Overall number of bits to be sent. + */ +__STATIC_INLINE void nrf_nfct_tx_bits_set(uint16_t tx_bits); + +/** + * @brief Function for getting the flags of the NFC frame reception configuration. + * + * @return The flags for NFCT frame reception configuration, defined in @ref nrf_nfct_rx_frame_config_t. + */ +__STATIC_INLINE uint8_t nrf_nfct_rx_frame_config_get(void); + +/** + * @brief Function for setting up the NFC frame reception. + * + * @note Destination for the received data is set using @ref nrf_nfct_rxtx_buffer_set. + * + * @param[in] flags NFCT RX configuration flags. Use @ref nrf_nfct_rx_frame_config_t for setting + * the desired configuration. + */ +__STATIC_INLINE void nrf_nfct_rx_frame_config_set(uint8_t flags); + +/** + * @brief Function for getting the number of bits received from the NFC poller. + * + * @param[in] crc_excluded Flag for excluding CRC size from calculation. + * + * @return Number of received bits including or excluding CRC, and excluding parity and SoF/EoF framing. + */ +__STATIC_INLINE uint16_t nrf_nfct_rx_bits_get(bool crc_excluded); + +/** + * @brief Function for getting the NFCID1 (NFC tag identifier). + * + * @note This function always returns the full configuration of the NFCID1 setting (10 bytes), regardless + * of the NFCID1 size. The NFCID1 size can be configured using @ref nrf_nfct_sensres_nfcid1_size_set or + * @ref nrf_nfct_nfcid1_set. + * + * @param[out] p_nfcid1_buf Pointer to a buffer for the NDFCID1 parameter. The NFCID1 values are in + * little endian order, that is: |NFCID1_3RD_LAST|NFCID1_2ND_LAST|NFCID1_LAST|. + * + * @return Configured NFCID1 length + */ +__STATIC_INLINE nrf_nfct_sensres_nfcid1_size_t nrf_nfct_nfcid1_get(uint8_t * p_nfcid1_buf); + +/** + * @brief Function for setting the NFCID1 (NFC tag identifier). + * + * @note This function also configures the NFCIDSIZE field in the SENSRES register of the NRF_NFCT peripheral. + * + * @param[in] p_nfcid1_buf Pointer to the buffer with NDFCID1 bytes. + * @param[in] nfcid1_size Size of the NFCID1 in bytes. + */ +__STATIC_INLINE void nrf_nfct_nfcid1_set(uint8_t const * p_nfcid1_buf, + nrf_nfct_sensres_nfcid1_size_t nfcid1_size); + +#if defined (NFCT_AUTOCOLRESCONFIG_MODE_Msk) || defined(__NRFX_DOXYGEN__) +/** + * @brief Function for getting the setting for the automatic collision resolution. + * + * @details The automatic collision resolution mechanism as defined in ISO 14443-3 and NFC Forum + * Digital Protocol Technical Specification 2.0, section 6. + * + * @retval true If automatic collision resolution is enabled. + * @retval false If automatic collision resolution is disabled. + */ +__STATIC_INLINE bool nrf_nfct_autocolres_is_enabled(void); + +/** + * @brief Function for enabling the automatic collision resolution. + * + * @details The automatic collision resolution mechanism as defined in ISO 14443-3 and NFC Forum + * Digital Protocol Technical Specification 2.0, section 6. + */ +__STATIC_INLINE void nrf_nfct_autocolres_enable(void); + +/** + * @brief Function for disabling the automatic collision resolution. + * + * @details The automatic collision resolution mechanism as defined in ISO 14443-3 and NFC Forum + * Digital Protocol Technical Specification 2.0, section 6. + */ +__STATIC_INLINE void nrf_nfct_autocolres_disable(void); +#endif // defined (NFCT_AUTOCOLRESCONFIG_MODE_Msk) || defined(__NRFX_DOXYGEN__) + +/** + * @brief Function for getting the NFCID1 size from the SENS_RES frame configuration. + * + * @details The SENS_RES frame is handled automatically by the NFCT hardware. + * + * @return NFCID1 (tag identifier) size. + */ +__STATIC_INLINE nrf_nfct_sensres_nfcid1_size_t nrf_nfct_sensres_nfcid1_size_get(void); + +/** + * @brief Function for setting the NFCID1 (tag identifier) size.field in the SENS_RES frame + * configuration. + * + * @note The SENS_RES frame is handled automatically by the NFCT hardware. + * + * @param[in] nfcid1_size NFCID1 (tag identifier) size. + * + * @sa nrf_nfct_nfcid1_set() + */ +__STATIC_INLINE void nrf_nfct_sensres_nfcid1_size_set(nrf_nfct_sensres_nfcid1_size_t nfcid1_size); + +/** + * @brief Function for getting the Bit Frame SDD field from the SENS_RES frame configuration. + * + * @details The SENS_RES frame is handled automatically by the NFCT hardware. + * + * @return The Bit Frame SDD field configuration. + */ +__STATIC_INLINE nrf_nfct_sensres_bit_frame_sdd_t nrf_nfct_sensres_bit_frame_sdd_get(void); + +/** + * @brief Function for setting the Bit Frame SDD field in the SENS_RES frame configuration. + * + * @note The SENS_RES frame is handled automatically by the NFCT hardware. + * + * @param[in] bit_frame_sdd The Bit Frame SDD field configuration. + */ +__STATIC_INLINE void nrf_nfct_sensres_bit_frame_sdd_set(nrf_nfct_sensres_bit_frame_sdd_t bit_frame_sdd); + +/** + * @brief Function for getting the Platform Config field from the SENS_RES frame configuration. + * + * @details The SENS_RES frame is handled automatically by the NFCT hardware. + * + * @return The Platform Config field configuration. + */ +__STATIC_INLINE nrf_nfct_sensres_platform_config_t nrf_nfct_sensres_platform_config_get(void); + +/** + * @brief Function for setting the Platform Config field in the SENS_RES frame configuration. + * + * @note The SENS_RES frame is handled automatically by the NFCT hardware. + * + * @param[in] platform_config The Platform Config field configuration. + */ +__STATIC_INLINE void nrf_nfct_sensres_platform_config_set(nrf_nfct_sensres_platform_config_t platform_config); + +/** + * @brief Function for checking the CASCADE bit of the SEL_RES frame. + * + * @details The CASCADE bit in the SEL_RES register is handled automatically by the NFCT hardware + * and indicates the status of the NFCID1 read operation to the NFC poller according to + * the NFC Forum Digital Protocol Speficiation 2.0, section 6.8.2. + * + * @retval true If NFCID1 read procedure is not complete. + * @retval false If NFCID1 read procedure is complete. + */ +__STATIC_INLINE bool nrf_nfct_selsres_cascade_check(void); + +/** + * @brief Function for getting the Protocol field in the SEL_RES frame. + * + * @details The SEL_RES frame is handled automatically by the NFCT hardware. + * + * @return Value of the Protocol field in the SEL_RES frame. + */ +__STATIC_INLINE nrf_nfct_selres_protocol_t nrf_nfct_selsres_protocol_get(void); + +/** + * @brief Function for setting the Protocol field in the SEL_RES frame configuration. + * + * @details The SEL_RES frame is handled automatically by the NFCT hardware. + * + * @param[in] sel_res_protocol Value of the Protocol field in the SEL_RES frame. + */ +__STATIC_INLINE void nrf_nfct_selres_protocol_set(nrf_nfct_selres_protocol_t sel_res_protocol); + +#ifndef SUPPRESS_INLINE_IMPLEMENTATION +__STATIC_INLINE void nrf_nfct_task_trigger(nrf_nfct_task_t task) +{ + *((volatile uint32_t *)((uint8_t *)NRF_NFCT + (uint32_t)task)) = 1UL; +} + +__STATIC_INLINE uint32_t nrf_nfct_task_address_get(nrf_nfct_task_t task) +{ + return (uint32_t)((uint8_t *)NRF_NFCT + (uint32_t)task); +} + +__STATIC_INLINE void nrf_nfct_event_clear(nrf_nfct_event_t event) +{ + *((volatile uint32_t *)((uint8_t *)NRF_NFCT + (uint32_t)event)) = 0UL; + __DSB(); +} + +__STATIC_INLINE bool nrf_nfct_event_check(nrf_nfct_event_t event) +{ + return (bool)*(volatile const uint32_t *)((uint8_t *)NRF_NFCT + (uint32_t)event); +} + +__STATIC_INLINE uint32_t nrf_nfct_event_address_get(nrf_nfct_event_t event) +{ + return (uint32_t)((uint8_t *)NRF_NFCT + (uint32_t)event); +} + +__STATIC_INLINE void nrf_nfct_shorts_enable(uint32_t short_mask) +{ + NRF_NFCT->SHORTS |= short_mask; +} + +__STATIC_INLINE void nrf_nfct_shorts_disable(uint32_t short_mask) +{ + NRF_NFCT->SHORTS &= ~short_mask; +} + +__STATIC_INLINE uint32_t nrf_nfct_shorts_get(void) +{ + return NRF_NFCT->SHORTS; +} + +__STATIC_INLINE void nrf_nfct_shorts_set(uint32_t short_mask) +{ + NRF_NFCT->SHORTS = short_mask; +} + +__STATIC_INLINE void nrf_nfct_int_enable(uint32_t int_mask) +{ + NRF_NFCT->INTENSET = int_mask; +} + +__STATIC_INLINE bool nrf_nfct_int_enable_check(uint32_t int_mask) +{ + return (bool)(NRF_NFCT->INTENSET & int_mask); +} + +__STATIC_INLINE uint32_t nrf_nfct_int_enable_get(void) +{ + return NRF_NFCT->INTENSET; +} + +__STATIC_INLINE void nrf_nfct_int_disable(uint32_t int_mask) +{ + NRF_NFCT->INTENCLR = int_mask; +} + +__STATIC_INLINE uint32_t nrf_nfct_error_status_get(void) +{ + return NRF_NFCT->ERRORSTATUS; +} + +__STATIC_INLINE void nrf_nfct_error_status_clear(uint32_t error_flags) +{ + NRF_NFCT->ERRORSTATUS = error_flags; +} + +__STATIC_INLINE uint32_t nrf_nfct_rx_frame_status_get(void) +{ + return NRF_NFCT->FRAMESTATUS.RX; +} + +__STATIC_INLINE void nrf_nfct_rx_frame_status_clear(uint32_t framestatus_flags) +{ + NRF_NFCT->FRAMESTATUS.RX = framestatus_flags; +} + +#if defined(NFCT_NFCTAGSTATE_NFCTAGSTATE_Msk) || defined(__NRFX_DOXYGEN__) +__STATIC_INLINE nrf_nfct_tag_state_t nrf_nfct_tag_state_get(void) +{ + return (nrf_nfct_tag_state_t)((NRF_NFCT->NFCTAGSTATE & NFCT_NFCTAGSTATE_NFCTAGSTATE_Msk) >> + NFCT_NFCTAGSTATE_NFCTAGSTATE_Pos); +} +#endif // defined(NFCT_NFCTAGSTATE_NFCTAGSTATE_Msk) || defined(__NRFX_DOXYGEN__) + +#if defined (NFCT_SLEEPSTATE_SLEEPSTATE_Msk) || defined(__NRFX_DOXYGEN__) +__STATIC_INLINE nrf_nfct_sleep_state_t nrf_nfct_sleep_state_get(void) +{ + return (nrf_nfct_sleep_state_t)((NRF_NFCT->SLEEPSTATE & NFCT_SLEEPSTATE_SLEEPSTATE_Msk) >> + NFCT_SLEEPSTATE_SLEEPSTATE_Pos); +} +#endif // defined (NFCT_SLEEPSTATE_SLEEPSTATE_Msk) || defined(__NRFX_DOXYGEN__) + +__STATIC_INLINE uint8_t nrf_nfct_field_status_get(void) +{ + return (uint8_t)(NRF_NFCT->FIELDPRESENT); +} + +__STATIC_INLINE uint16_t nrf_nfct_frame_delay_min_get(void) +{ + return (uint16_t)((NRF_NFCT->FRAMEDELAYMIN & NFCT_FRAMEDELAYMIN_FRAMEDELAYMIN_Msk) >> + NFCT_FRAMEDELAYMIN_FRAMEDELAYMIN_Pos); +} + +__STATIC_INLINE void nrf_nfct_frame_delay_min_set(uint16_t frame_delay_min) +{ + NRF_NFCT->FRAMEDELAYMIN = + ((uint32_t)frame_delay_min << NFCT_FRAMEDELAYMIN_FRAMEDELAYMIN_Pos) & + NFCT_FRAMEDELAYMIN_FRAMEDELAYMIN_Msk; +} + +__STATIC_INLINE uint32_t nrf_nfct_frame_delay_max_get(void) +{ + return (NRF_NFCT->FRAMEDELAYMAX & NFCT_FRAMEDELAYMAX_FRAMEDELAYMAX_Msk) >> + NFCT_FRAMEDELAYMAX_FRAMEDELAYMAX_Pos; +} + +__STATIC_INLINE void nrf_nfct_frame_delay_max_set(uint32_t frame_delay_max) +{ + NRF_NFCT->FRAMEDELAYMAX = + ((uint32_t)frame_delay_max << NFCT_FRAMEDELAYMAX_FRAMEDELAYMAX_Pos) & + NFCT_FRAMEDELAYMAX_FRAMEDELAYMAX_Msk; +} + +__STATIC_INLINE nrf_nfct_frame_delay_mode_t nrf_nfct_frame_delay_mode_get(void) +{ + return (nrf_nfct_frame_delay_mode_t)(NRF_NFCT->FRAMEDELAYMODE & + NFCT_FRAMEDELAYMODE_FRAMEDELAYMODE_Msk); +} + +__STATIC_INLINE void nrf_nfct_frame_delay_mode_set(nrf_nfct_frame_delay_mode_t frame_delay_mode) +{ + NRF_NFCT->FRAMEDELAYMODE = (uint32_t)frame_delay_mode; +} + +__STATIC_INLINE uint8_t * nrf_nfct_rxtx_buffer_get(void) +{ + return (uint8_t *)(NRF_NFCT->PACKETPTR); +} + +__STATIC_INLINE void nrf_nfct_rxtx_buffer_set(uint8_t * p_rxtx_buf, + uint16_t max_txrx_len) +{ + NRF_NFCT->PACKETPTR = (uint32_t)p_rxtx_buf; + NRF_NFCT->MAXLEN = ((uint32_t)max_txrx_len << NFCT_MAXLEN_MAXLEN_Pos) & + NFCT_MAXLEN_MAXLEN_Msk; +} + +__STATIC_INLINE uint16_t nrf_nfct_max_rxtx_length_get(void) +{ + return (uint16_t)((NRF_NFCT->MAXLEN & NFCT_MAXLEN_MAXLEN_Msk) >> NFCT_MAXLEN_MAXLEN_Pos); +} + +__STATIC_INLINE uint8_t nrf_nfct_tx_frame_config_get(void) +{ + return (uint8_t)(NRF_NFCT->TXD.FRAMECONFIG); +} + +__STATIC_INLINE void nrf_nfct_tx_frame_config_set(uint8_t flags) +{ + NRF_NFCT->TXD.FRAMECONFIG = flags; +} + +__STATIC_INLINE uint16_t nrf_nfct_tx_bits_get(void) +{ + return (uint16_t)(NRF_NFCT->TXD.AMOUNT & (NFCT_TXD_AMOUNT_TXDATABITS_Msk | + NFCT_TXD_AMOUNT_TXDATABYTES_Msk)); +} + +__STATIC_INLINE void nrf_nfct_tx_bits_set(uint16_t tx_bits) +{ + NRF_NFCT->TXD.AMOUNT = (tx_bits & (NFCT_TXD_AMOUNT_TXDATABITS_Msk | NFCT_TXD_AMOUNT_TXDATABYTES_Msk)); +} + +__STATIC_INLINE uint8_t nrf_nfct_rx_frame_config_get(void) +{ + return (uint8_t)(NRF_NFCT->RXD.FRAMECONFIG); +} + +__STATIC_INLINE void nrf_nfct_rx_frame_config_set(uint8_t flags) +{ + NRF_NFCT->RXD.FRAMECONFIG = flags; +} + +__STATIC_INLINE uint16_t nrf_nfct_rx_bits_get(bool crc_excluded) +{ + uint16_t rx_bits = NRF_NFCT->RXD.AMOUNT & (NFCT_RXD_AMOUNT_RXDATABITS_Msk | + NFCT_RXD_AMOUNT_RXDATABYTES_Msk); + return rx_bits - (crc_excluded ? (8u * NRF_NFCT_CRC_SIZE) : 0); +} + +__STATIC_INLINE nrf_nfct_sensres_nfcid1_size_t nrf_nfct_nfcid1_get(uint8_t * p_nfcid1_buf) +{ + uint32_t nfcid1_last = NRF_NFCT->NFCID1_LAST; + nrf_nfct_sensres_nfcid1_size_t size = + (nrf_nfct_sensres_nfcid1_size_t)(NRF_NFCT->SENSRES & NFCT_SENSRES_NFCIDSIZE_Msk); + + if (size != NRF_NFCT_SENSRES_NFCID1_SIZE_SINGLE) + { + uint32_t nfcid1_2nd_last = NRF_NFCT->NFCID1_2ND_LAST; + + if (size == NRF_NFCT_SENSRES_NFCID1_SIZE_TRIPLE) + { + uint32_t nfcid1_3rd_last = NRF_NFCT->NFCID1_3RD_LAST; + + *p_nfcid1_buf++ = (uint8_t)(nfcid1_3rd_last >> 16UL); + *p_nfcid1_buf++ = (uint8_t)(nfcid1_3rd_last >> 8UL); + *p_nfcid1_buf++ = (uint8_t)(nfcid1_3rd_last >> 0UL); + } + + *p_nfcid1_buf++ = (uint8_t)(nfcid1_2nd_last >> 16UL); + *p_nfcid1_buf++ = (uint8_t)(nfcid1_2nd_last >> 8UL); + *p_nfcid1_buf++ = (uint8_t)(nfcid1_2nd_last >> 0UL); + } + + *p_nfcid1_buf++ = (uint8_t)(nfcid1_last >> 24UL); + *p_nfcid1_buf++ = (uint8_t)(nfcid1_last >> 16UL); + *p_nfcid1_buf++ = (uint8_t)(nfcid1_last >> 8UL); + *p_nfcid1_buf++ = (uint8_t)(nfcid1_last >> 0UL); + + return size; +} + +__STATIC_INLINE void nrf_nfct_nfcid1_set(uint8_t const * p_nfcid1_buf, + nrf_nfct_sensres_nfcid1_size_t nfcid1_size) +{ + nrf_nfct_sensres_nfcid1_size_t size = (nfcid1_size == NRF_NFCT_SENSRES_NFCID1_SIZE_DEFAULT) ? + NRF_NFCT_SENSRES_NFCID1_SIZE_DOUBLE : nfcid1_size; + + if (size != NRF_NFCT_SENSRES_NFCID1_SIZE_SINGLE) + { + if (size == NRF_NFCT_SENSRES_NFCID1_SIZE_TRIPLE) + { + NRF_NFCT->NFCID1_3RD_LAST = ((uint32_t)p_nfcid1_buf[0] << 16UL) | + ((uint32_t)p_nfcid1_buf[1] << 8UL) | + ((uint32_t)p_nfcid1_buf[2] << 0UL); + p_nfcid1_buf += 3UL; + } + NRF_NFCT->NFCID1_2ND_LAST = ((uint32_t)p_nfcid1_buf[0] << 16UL) | + ((uint32_t)p_nfcid1_buf[1] << 8UL) | + ((uint32_t)p_nfcid1_buf[2] << 0UL); + p_nfcid1_buf += 3UL; + } + + NRF_NFCT->NFCID1_LAST = ((uint32_t)p_nfcid1_buf[0] << 24UL) | + ((uint32_t)p_nfcid1_buf[1] << 16UL) | + ((uint32_t)p_nfcid1_buf[2] << 8UL) | + ((uint32_t)p_nfcid1_buf[3] << 0UL); + + NRF_NFCT->SENSRES = ((NRF_NFCT->SENSRES & ~NFCT_SENSRES_NFCIDSIZE_Msk) | + (uint32_t)size); +} + +#if defined (NFCT_AUTOCOLRESCONFIG_MODE_Msk) || defined(__NRFX_DOXYGEN__) +__STATIC_INLINE bool nrf_nfct_autocolres_is_enabled(void) +{ + return (NRF_NFCT->AUTOCOLRESCONFIG & NFCT_AUTOCOLRESCONFIG_MODE_Msk) == + (NFCT_AUTOCOLRESCONFIG_MODE_Enabled << NFCT_AUTOCOLRESCONFIG_MODE_Pos); +} + +__STATIC_INLINE void nrf_nfct_autocolres_enable(void) +{ + NRF_NFCT->AUTOCOLRESCONFIG = + (NRF_NFCT->AUTOCOLRESCONFIG & ~NFCT_AUTOCOLRESCONFIG_MODE_Msk) | + (NFCT_AUTOCOLRESCONFIG_MODE_Enabled << NFCT_AUTOCOLRESCONFIG_MODE_Pos); +} + +__STATIC_INLINE void nrf_nfct_autocolres_disable(void) +{ + NRF_NFCT->AUTOCOLRESCONFIG = + (NRF_NFCT->AUTOCOLRESCONFIG & ~NFCT_AUTOCOLRESCONFIG_MODE_Msk) | + (NFCT_AUTOCOLRESCONFIG_MODE_Disabled << NFCT_AUTOCOLRESCONFIG_MODE_Pos); +} +#endif // defined (NFCT_AUTOCOLRESCONFIG_MODE_Msk) || defined(__NRFX_DOXYGEN__) + +__STATIC_INLINE nrf_nfct_sensres_nfcid1_size_t nrf_nfct_sensres_nfcid1_size_get(void) +{ + return (nrf_nfct_sensres_nfcid1_size_t)(NRF_NFCT->SENSRES & NFCT_SENSRES_NFCIDSIZE_Msk); +} + +__STATIC_INLINE void nrf_nfct_sensres_nfcid1_size_set(nrf_nfct_sensres_nfcid1_size_t nfcid1_size) +{ + NRF_NFCT->SENSRES = ((NRF_NFCT->SENSRES & ~(NFCT_SENSRES_NFCIDSIZE_Msk)) | (uint32_t)nfcid1_size); +} + +__STATIC_INLINE nrf_nfct_sensres_bit_frame_sdd_t nrf_nfct_sensres_bit_frame_sdd_get(void) +{ + return (nrf_nfct_sensres_bit_frame_sdd_t)(NRF_NFCT->SENSRES & NFCT_SENSRES_BITFRAMESDD_Msk); +} + +__STATIC_INLINE void nrf_nfct_sensres_bit_frame_sdd_set(nrf_nfct_sensres_bit_frame_sdd_t bit_frame_sdd) +{ + NRF_NFCT->SENSRES = ((NRF_NFCT->SENSRES & ~(NFCT_SENSRES_BITFRAMESDD_Msk)) | (uint32_t)bit_frame_sdd); +} + +__STATIC_INLINE nrf_nfct_sensres_platform_config_t nrf_nfct_sensres_platform_config_get(void) +{ + return (nrf_nfct_sensres_platform_config_t)(NRF_NFCT->SENSRES & NFCT_SENSRES_PLATFCONFIG_Msk); +} + +__STATIC_INLINE void nrf_nfct_sensres_platform_config_set(nrf_nfct_sensres_platform_config_t platform_config) +{ + NRF_NFCT->SENSRES = ((NRF_NFCT->SENSRES & ~(NFCT_SENSRES_PLATFCONFIG_Msk)) | (uint32_t)platform_config); +} + +__STATIC_INLINE bool nrf_nfct_selsres_cascade_check(void) +{ + return (bool)(NRF_NFCT->SELRES & NFCT_SELRES_CASCADE_Msk); +} + +__STATIC_INLINE nrf_nfct_selres_protocol_t nrf_nfct_selsres_protocol_get(void) +{ + return (nrf_nfct_selres_protocol_t)((NRF_NFCT->SELRES & NFCT_SELRES_PROTOCOL_Msk) >> + NFCT_SELRES_PROTOCOL_Pos); +} + +__STATIC_INLINE void nrf_nfct_selres_protocol_set(nrf_nfct_selres_protocol_t sel_res_protocol) +{ + NRF_NFCT->SELRES = (NRF_NFCT->SELRES & ~NFCT_SELRES_PROTOCOL_Msk) | + ((uint32_t)sel_res_protocol << NFCT_SELRES_PROTOCOL_Pos); +} +#endif /* SUPPRESS_INLINE_IMPLEMENTATION */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* NRF_NFCT_H__ */ diff --git a/hal/nrf_power.h b/hal/nrf_power.h index 344b8812c..b44e6819d 100644 --- a/hal/nrf_power.h +++ b/hal/nrf_power.h @@ -966,19 +966,19 @@ __STATIC_INLINE bool nrf_power_dcdcen_get(void) #if NRF_POWER_HAS_RAMPOWER_REGS __STATIC_INLINE void nrf_power_rampower_mask_on(uint8_t block, uint32_t section_mask) { - NRFX_ASSERT(block < ARRAY_SIZE(NRF_POWER->RAM)); + NRFX_ASSERT(block < NRFX_ARRAY_SIZE(NRF_POWER->RAM)); NRF_POWER->RAM[block].POWERSET = section_mask; } __STATIC_INLINE void nrf_power_rampower_mask_off(uint8_t block, uint32_t section_mask) { - NRFX_ASSERT(block < ARRAY_SIZE(NRF_POWER->RAM)); + NRFX_ASSERT(block < NRFX_ARRAY_SIZE(NRF_POWER->RAM)); NRF_POWER->RAM[block].POWERCLR = section_mask; } __STATIC_INLINE uint32_t nrf_power_rampower_mask_get(uint8_t block) { - NRFX_ASSERT(block < ARRAY_SIZE(NRF_POWER->RAM)); + NRFX_ASSERT(block < NRFX_ARRAY_SIZE(NRF_POWER->RAM)); return NRF_POWER->RAM[block].POWER; } #endif /* NRF_POWER_HAS_RAMPOWER_REGS */ diff --git a/hal/nrf_saadc.h b/hal/nrf_saadc.h index 0c40ae1a1..537141885 100644 --- a/hal/nrf_saadc.h +++ b/hal/nrf_saadc.h @@ -635,6 +635,20 @@ __STATIC_INLINE void nrf_saadc_channel_init(uint8_t nrf_saadc_channel_input_set(channel, config->pin_p, config->pin_n); } +/** + * @brief Function for configuring the burst mode for the specified channel. + * + * @param[in] channel Channel number. + * @param[in] burst Burst mode setting. + */ +__STATIC_INLINE void nrf_saadc_burst_set(uint8_t channel, + nrf_saadc_burst_t burst) +{ + NRF_SAADC->CH[channel].CONFIG = + (NRF_SAADC->CH[channel].CONFIG & ~SAADC_CH_CONFIG_BURST_Msk) | + (burst << SAADC_CH_CONFIG_BURST_Pos); +} + /** @} */ #ifdef __cplusplus diff --git a/hal/nrf_usbd.h b/hal/nrf_usbd.h index 46fa1ab20..681367f60 100644 --- a/hal/nrf_usbd.h +++ b/hal/nrf_usbd.h @@ -1046,12 +1046,12 @@ uint32_t nrf_usbd_haltedep(uint8_t ep) uint8_t epnr = NRF_USBD_EP_NR_GET(ep); if (NRF_USBD_EPIN_CHECK(ep)) { - NRFX_ASSERT(epnr < ARRAY_SIZE(NRF_USBD->HALTED.EPIN)); + NRFX_ASSERT(epnr < NRFX_ARRAY_SIZE(NRF_USBD->HALTED.EPIN)); return NRF_USBD->HALTED.EPIN[epnr]; } else { - NRFX_ASSERT(epnr < ARRAY_SIZE(NRF_USBD->HALTED.EPOUT)); + NRFX_ASSERT(epnr < NRFX_ARRAY_SIZE(NRF_USBD->HALTED.EPOUT)); return NRF_USBD->HALTED.EPOUT[epnr]; } } @@ -1145,7 +1145,7 @@ size_t nrf_usbd_epout_size_get(uint8_t ep) return size_isoout; } - NRFX_ASSERT(NRF_USBD_EP_NR_GET(ep) < ARRAY_SIZE(NRF_USBD->SIZE.EPOUT)); + NRFX_ASSERT(NRF_USBD_EP_NR_GET(ep) < NRFX_ARRAY_SIZE(NRF_USBD->SIZE.EPOUT)); return NRF_USBD->SIZE.EPOUT[NRF_USBD_EP_NR_GET(ep)]; } @@ -1169,7 +1169,7 @@ size_t nrf_usbd_episoout_size_get(uint8_t ep) void nrf_usbd_epout_clear(uint8_t ep) { - NRFX_ASSERT(NRF_USBD_EPOUT_CHECK(ep) && (NRF_USBD_EP_NR_GET(ep) < ARRAY_SIZE(NRF_USBD->SIZE.EPOUT))); + NRFX_ASSERT(NRF_USBD_EPOUT_CHECK(ep) && (NRF_USBD_EP_NR_GET(ep) < NRFX_ARRAY_SIZE(NRF_USBD->SIZE.EPOUT))); NRF_USBD->SIZE.EPOUT[NRF_USBD_EP_NR_GET(ep)] = 0; __ISB(); __DSB(); @@ -1346,7 +1346,7 @@ void nrf_usbd_ep_easydma_set(uint8_t ep, uint32_t ptr, uint32_t maxcnt) else { uint8_t epnr = NRF_USBD_EP_NR_GET(ep); - NRFX_ASSERT(epnr < ARRAY_SIZE(NRF_USBD->EPIN)); + NRFX_ASSERT(epnr < NRFX_ARRAY_SIZE(NRF_USBD->EPIN)); NRF_USBD->EPIN[epnr].PTR = ptr; NRF_USBD->EPIN[epnr].MAXCNT = maxcnt; } @@ -1361,7 +1361,7 @@ void nrf_usbd_ep_easydma_set(uint8_t ep, uint32_t ptr, uint32_t maxcnt) else { uint8_t epnr = NRF_USBD_EP_NR_GET(ep); - NRFX_ASSERT(epnr < ARRAY_SIZE(NRF_USBD->EPOUT)); + NRFX_ASSERT(epnr < NRFX_ARRAY_SIZE(NRF_USBD->EPOUT)); NRF_USBD->EPOUT[epnr].PTR = ptr; NRF_USBD->EPOUT[epnr].MAXCNT = maxcnt; } @@ -1381,7 +1381,7 @@ uint32_t nrf_usbd_ep_amount_get(uint8_t ep) else { uint8_t epnr = NRF_USBD_EP_NR_GET(ep); - NRFX_ASSERT(epnr < ARRAY_SIZE(NRF_USBD->EPOUT)); + NRFX_ASSERT(epnr < NRFX_ARRAY_SIZE(NRF_USBD->EPOUT)); ret = NRF_USBD->EPIN[epnr].AMOUNT; } } @@ -1394,7 +1394,7 @@ uint32_t nrf_usbd_ep_amount_get(uint8_t ep) else { uint8_t epnr = NRF_USBD_EP_NR_GET(ep); - NRFX_ASSERT(epnr < ARRAY_SIZE(NRF_USBD->EPOUT)); + NRFX_ASSERT(epnr < NRFX_ARRAY_SIZE(NRF_USBD->EPOUT)); ret = NRF_USBD->EPOUT[epnr].AMOUNT; } } diff --git a/soc/nrfx_atomic.c b/soc/nrfx_atomic.c new file mode 100644 index 000000000..4fd064423 --- /dev/null +++ b/soc/nrfx_atomic.c @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2018, Nordic Semiconductor ASA + * All rights reserved. + * + * 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_atomic.h" + +#ifndef NRFX_ATOMIC_USE_BUILT_IN +#if (defined(__GNUC__) && defined(WIN32)) + #define NRFX_ATOMIC_USE_BUILT_IN 1 +#else + #define NRFX_ATOMIC_USE_BUILT_IN 0 +#endif +#endif // NRFX_ATOMIC_USE_BUILT_IN + +#if ((__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U)) +#define NRFX_ATOMIC_STREX_LDREX_PRESENT +#endif + +#if (NRFX_ATOMIC_USE_BUILT_IN == 0) && defined(NRFX_ATOMIC_STREX_LDREX_PRESENT) +#include "nrfx_atomic_internal.h" +#endif + +uint32_t nrfx_atomic_u32_fetch_store(nrfx_atomic_u32_t * p_data, uint32_t value) +{ +#if NRFX_ATOMIC_USE_BUILT_IN + return __atomic_exchange_n(p_data, value, __ATOMIC_SEQ_CST); +#elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT) + uint32_t old_val; + uint32_t new_val; + NRFX_ATOMIC_OP(mov, old_val, new_val, p_data, value); + (void) new_val; + return old_val; +#else + NRFX_CRITICAL_SECTION_ENTER(); + uint32_t old_val = *p_data; + *p_data = value; + NRFX_CRITICAL_SECTION_EXIT(); + return old_val; +#endif // NRFX_ATOMIC_USE_BUILT_IN +} + +uint32_t nrfx_atomic_u32_store(nrfx_atomic_u32_t * p_data, uint32_t value) +{ +#if NRFX_ATOMIC_USE_BUILT_IN + __atomic_store_n(p_data, value, __ATOMIC_SEQ_CST); + return value; +#elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT) + uint32_t old_val; + uint32_t new_val; + NRFX_ATOMIC_OP(mov, old_val, new_val, p_data, value); + (void) old_val; + return new_val; +#else + NRFX_CRITICAL_SECTION_ENTER(); + *p_data = value; + NRFX_CRITICAL_SECTION_EXIT(); + return value; +#endif //NRFX_ATOMIC_USE_BUILT_IN +} + +uint32_t nrfx_atomic_u32_fetch_or(nrfx_atomic_u32_t * p_data, uint32_t value) +{ +#if NRFX_ATOMIC_USE_BUILT_IN + return __atomic_fetch_or(p_data, value, __ATOMIC_SEQ_CST); +#elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT) + uint32_t old_val; + uint32_t new_val; + NRFX_ATOMIC_OP(orr, old_val, new_val, p_data, value); + (void) new_val; + return old_val; +#else + NRFX_CRITICAL_SECTION_ENTER(); + uint32_t old_val = *p_data; + *p_data |= value; + NRFX_CRITICAL_SECTION_EXIT(); + return old_val; +#endif //NRFX_ATOMIC_USE_BUILT_IN +} + +uint32_t nrfx_atomic_u32_or(nrfx_atomic_u32_t * p_data, uint32_t value) +{ +#if NRFX_ATOMIC_USE_BUILT_IN + return __atomic_or_fetch(p_data, value, __ATOMIC_SEQ_CST); +#elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT) + uint32_t old_val; + uint32_t new_val; + NRFX_ATOMIC_OP(orr, old_val, new_val, p_data, value); + (void) old_val; + return new_val; +#else + NRFX_CRITICAL_SECTION_ENTER(); + *p_data |= value; + uint32_t new_value = *p_data; + NRFX_CRITICAL_SECTION_EXIT(); + return new_value; +#endif //NRFX_ATOMIC_USE_BUILT_IN +} + +uint32_t nrfx_atomic_u32_fetch_and(nrfx_atomic_u32_t * p_data, uint32_t value) +{ +#if NRFX_ATOMIC_USE_BUILT_IN + return __atomic_fetch_and(p_data, value, __ATOMIC_SEQ_CST); +#elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT) + uint32_t old_val; + uint32_t new_val; + NRFX_ATOMIC_OP(and, old_val, new_val, p_data, value); + (void) new_val; + return old_val; +#else + NRFX_CRITICAL_SECTION_ENTER(); + uint32_t old_val = *p_data; + *p_data &= value; + NRFX_CRITICAL_SECTION_EXIT(); + return old_val; +#endif //NRFX_ATOMIC_USE_BUILT_IN +} + +uint32_t nrfx_atomic_u32_and(nrfx_atomic_u32_t * p_data, uint32_t value) +{ +#if NRFX_ATOMIC_USE_BUILT_IN + return __atomic_and_fetch(p_data, value, __ATOMIC_SEQ_CST); +#elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT) + uint32_t old_val; + uint32_t new_val; + NRFX_ATOMIC_OP(and, old_val, new_val, p_data, value); + (void) old_val; + return new_val; +#else + NRFX_CRITICAL_SECTION_ENTER(); + *p_data &= value; + uint32_t new_value = *p_data; + NRFX_CRITICAL_SECTION_EXIT(); + return new_value; +#endif //NRFX_ATOMIC_USE_BUILT_IN +} + +uint32_t nrfx_atomic_u32_fetch_xor(nrfx_atomic_u32_t * p_data, uint32_t value) +{ +#if NRFX_ATOMIC_USE_BUILT_IN + return __atomic_fetch_xor(p_data, value, __ATOMIC_SEQ_CST); +#elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT) + uint32_t old_val; + uint32_t new_val; + NRFX_ATOMIC_OP(eor, old_val, new_val, p_data, value); + (void) new_val; + return old_val; +#else + NRFX_CRITICAL_SECTION_ENTER(); + uint32_t old_val = *p_data; + *p_data ^= value; + NRFX_CRITICAL_SECTION_EXIT(); + return old_val; +#endif //NRFX_ATOMIC_USE_BUILT_IN +} + +uint32_t nrfx_atomic_u32_xor(nrfx_atomic_u32_t * p_data, uint32_t value) +{ +#if NRFX_ATOMIC_USE_BUILT_IN + return __atomic_xor_fetch(p_data, value, __ATOMIC_SEQ_CST); +#elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT) + uint32_t old_val; + uint32_t new_val; + NRFX_ATOMIC_OP(eor, old_val, new_val, p_data, value); + (void) old_val; + return new_val; +#else + NRFX_CRITICAL_SECTION_ENTER(); + *p_data ^= value; + uint32_t new_value = *p_data; + NRFX_CRITICAL_SECTION_EXIT(); + return new_value; +#endif //NRFX_ATOMIC_USE_BUILT_IN +} + +uint32_t nrfx_atomic_u32_fetch_add(nrfx_atomic_u32_t * p_data, uint32_t value) +{ +#if NRFX_ATOMIC_USE_BUILT_IN + return __atomic_fetch_add(p_data, value, __ATOMIC_SEQ_CST); +#elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT) + uint32_t old_val; + uint32_t new_val; + NRFX_ATOMIC_OP(add, old_val, new_val, p_data, value); + (void) new_val; + return old_val; +#else + NRFX_CRITICAL_SECTION_ENTER(); + uint32_t old_val = *p_data; + *p_data += value; + NRFX_CRITICAL_SECTION_EXIT(); + return old_val; +#endif //NRFX_ATOMIC_USE_BUILT_IN +} + +uint32_t nrfx_atomic_u32_add(nrfx_atomic_u32_t * p_data, uint32_t value) +{ +#if NRFX_ATOMIC_USE_BUILT_IN + return __atomic_add_fetch(p_data, value, __ATOMIC_SEQ_CST); +#elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT) + uint32_t old_val; + uint32_t new_val; + NRFX_ATOMIC_OP(add, old_val, new_val, p_data, value); + (void) old_val; + return new_val; +#else + NRFX_CRITICAL_SECTION_ENTER(); + *p_data += value; + uint32_t new_value = *p_data; + NRFX_CRITICAL_SECTION_EXIT(); + return new_value; +#endif //NRFX_ATOMIC_USE_BUILT_IN +} + +uint32_t nrfx_atomic_u32_fetch_sub(nrfx_atomic_u32_t * p_data, uint32_t value) +{ +#if NRFX_ATOMIC_USE_BUILT_IN + return __atomic_fetch_sub(p_data, value, __ATOMIC_SEQ_CST); +#elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT) + uint32_t old_val; + uint32_t new_val; + NRFX_ATOMIC_OP(sub, old_val, new_val, p_data, value); + (void) new_val; + return old_val; +#else + NRFX_CRITICAL_SECTION_ENTER(); + uint32_t old_val = *p_data; + *p_data -= value; + NRFX_CRITICAL_SECTION_EXIT(); + return old_val; +#endif //NRFX_ATOMIC_USE_BUILT_IN +} + +uint32_t nrfx_atomic_u32_sub(nrfx_atomic_u32_t * p_data, uint32_t value) +{ +#if NRFX_ATOMIC_USE_BUILT_IN + return __atomic_sub_fetch(p_data, value, __ATOMIC_SEQ_CST); +#elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT) + uint32_t old_val; + uint32_t new_val; + NRFX_ATOMIC_OP(sub, old_val, new_val, p_data, value); + (void) old_val; + return new_val; +#else + NRFX_CRITICAL_SECTION_ENTER(); + *p_data -= value; + uint32_t new_value = *p_data; + NRFX_CRITICAL_SECTION_EXIT(); + return new_value; +#endif //NRFX_ATOMIC_USE_BUILT_IN +} + +bool nrfx_atomic_u32_cmp_exch(nrfx_atomic_u32_t * p_data, + uint32_t * p_expected, + uint32_t desired) +{ +#if NRFX_ATOMIC_USE_BUILT_IN + return __atomic_compare_exchange(p_data, + p_expected, + &desired, + 1, + __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST); +#elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT) + return nrfx_atomic_internal_cmp_exch(p_data, p_expected, desired); +#else + bool result; + NRFX_CRITICAL_SECTION_ENTER(); + if (*p_data == *p_expected) + { + *p_data = desired; + result = true; + } + else + { + *p_expected = *p_data; + result = false; + } + NRFX_CRITICAL_SECTION_EXIT(); + return result; +#endif +} + +uint32_t nrfx_atomic_u32_fetch_sub_hs(nrfx_atomic_u32_t * p_data, uint32_t value) +{ +#if NRFX_ATOMIC_USE_BUILT_IN + uint32_t expected = *p_data; + uint32_t new_val; + do { + if (expected >= value) + { + new_val = expected - value; + } + else + { + new_val = expected; + } + } while (!__atomic_compare_exchange(p_data, &expected, &new_val, + 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)); + return expected; +#elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT) + uint32_t old_val; + uint32_t new_val; + NRFX_ATOMIC_OP(sub_hs, old_val, new_val, p_data, value); + (void) new_val; + return old_val; +#else + NRFX_CRITICAL_SECTION_ENTER(); + uint32_t old_val = *p_data; + *p_data -= value; + NRFX_CRITICAL_SECTION_EXIT(); + return old_val; +#endif //NRFX_ATOMIC_USE_BUILT_IN +} + +uint32_t nrfx_atomic_u32_sub_hs(nrfx_atomic_u32_t * p_data, uint32_t value) +{ +#if NRFX_ATOMIC_USE_BUILT_IN + uint32_t expected = *p_data; + uint32_t new_val; + do { + if (expected >= value) + { + new_val = expected - value; + } + else + { + new_val = expected; + } + } while (!__atomic_compare_exchange(p_data, &expected, &new_val, + 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)); + return new_val; +#elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT) + uint32_t old_val; + uint32_t new_val; + NRFX_ATOMIC_OP(sub_hs, old_val, new_val, p_data, value); + (void) old_val; + return new_val; +#else + NRFX_CRITICAL_SECTION_ENTER(); + *p_data -= value; + uint32_t new_value = *p_data; + NRFX_CRITICAL_SECTION_EXIT(); + return new_value; +#endif //NRFX_ATOMIC_USE_BUILT_IN +} + +uint32_t nrfx_atomic_flag_set_fetch(nrfx_atomic_flag_t * p_data) +{ + return nrfx_atomic_u32_fetch_or(p_data, 1); +} + +uint32_t nrfx_atomic_flag_set(nrfx_atomic_flag_t * p_data) +{ + return nrfx_atomic_u32_or(p_data, 1); +} + +uint32_t nrfx_atomic_flag_clear_fetch(nrfx_atomic_flag_t * p_data) +{ + return nrfx_atomic_u32_fetch_and(p_data, 0); +} + +uint32_t nrfx_atomic_flag_clear(nrfx_atomic_flag_t * p_data) +{ + return nrfx_atomic_u32_and(p_data, 0); +} diff --git a/soc/nrfx_atomic.h b/soc/nrfx_atomic.h new file mode 100644 index 000000000..5b68a314e --- /dev/null +++ b/soc/nrfx_atomic.h @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * All rights reserved. + * + * 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. + */ + +#ifndef NRFX_ATOMIC_H__ +#define NRFX_ATOMIC_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup nrfx_atomic Atomic operations API + * @ingroup nrfx + * @{ + * + * @brief This module implements C11 stdatomic.h simplified API. + * + * At this point, only Cortex-M3 and M4 cores are supported (LDREX/STREX instructions). + * Atomic types are limited to @ref nrfx_atomic_u32_t and @ref nrfx_atomic_flag_t. + */ + + +/** + * @brief Atomic 32-bit unsigned type. + */ +typedef volatile uint32_t nrfx_atomic_u32_t; + +/** + * @brief Atomic 1-bit flag type (technically 32-bit). + */ +typedef volatile uint32_t nrfx_atomic_flag_t; + +/** + * @brief Function for storing a value to an atomic object and returning its previous value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value to store. + * + * @return Previous value stored in the atomic object. + */ +uint32_t nrfx_atomic_u32_fetch_store(nrfx_atomic_u32_t * p_data, uint32_t value); + +/** + * @brief Function for storing a value to an atomic object and returning its new value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value to store. + * + * @return New value stored in the atomic object. + */ +uint32_t nrfx_atomic_u32_store(nrfx_atomic_u32_t * p_data, uint32_t value); + +/** + * @brief Function for running a logical OR operation on an atomic object + * and returning its previous value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of the second operand in the OR operation. + * + * @return Previous value stored in the atomic object. + */ +uint32_t nrfx_atomic_u32_fetch_or(nrfx_atomic_u32_t * p_data, uint32_t value); + +/** + * @brief Function for running a logical OR operation on an atomic object + * and returning its new value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of the second operand in the OR operation. + * + * @return New value stored in the atomic object. + */ +uint32_t nrfx_atomic_u32_or(nrfx_atomic_u32_t * p_data, uint32_t value); + +/** + * @brief Function for running a logical AND operation on an atomic object + * and returning its previous value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of the second operand in the AND operation. + * + * @return Previous value stored in the atomic object. + */ +uint32_t nrfx_atomic_u32_fetch_and(nrfx_atomic_u32_t * p_data, uint32_t value); + +/** + * @brief Function for running a logical AND operation on an atomic object + * and returning its new value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of the second operand in the AND operation. + * + * @return New value stored in the atomic object. + */ +uint32_t nrfx_atomic_u32_and(nrfx_atomic_u32_t * p_data, uint32_t value); + +/** + * @brief Function for running a logical XOR operation on an atomic object + * and returning its previous value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of the second operand in the XOR operation. + * + * @return Previous value stored in the atomic object. + */ +uint32_t nrfx_atomic_u32_fetch_xor(nrfx_atomic_u32_t * p_data, uint32_t value); + +/** + * @brief Function for running a logical XOR operation on an atomic object + * and returning its new value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of the second operand in the XOR operation. + * + * @return New value stored in the atomic object. + */ +uint32_t nrfx_atomic_u32_xor(nrfx_atomic_u32_t * p_data, uint32_t value); + +/** + * @brief Function for running an arithmetic ADD operation on an atomic object + * and returning its previous value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of the second operand in the ADD operation. + * + * @return Previous value stored in the atomic object. + */ +uint32_t nrfx_atomic_u32_fetch_add(nrfx_atomic_u32_t * p_data, uint32_t value); + +/** + * @brief Function for running an arithmetic ADD operation on an atomic object + * and returning its new value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of the second operand in the ADD operation. + * + * @return New value stored in the atomic object. + */ +uint32_t nrfx_atomic_u32_add(nrfx_atomic_u32_t * p_data, uint32_t value); + +/** + * @brief Function for running an arithmetic SUB operation on an atomic object + * and returning its previous value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of the second operand in the SUB operation. + * + * @return Old value stored in the atomic object. + */ +uint32_t nrfx_atomic_u32_fetch_sub(nrfx_atomic_u32_t * p_data, uint32_t value); + +/** + * @brief Function for running an arithmetic SUB operation on an atomic object + * and returning its new value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of the second operand in the SUB operation. + * + * @return New value stored in the atomic object. + */ +uint32_t nrfx_atomic_u32_sub(nrfx_atomic_u32_t * p_data, uint32_t value); + +/** + * @brief Function for atomic conditional value replacement. + * + * Atomically compares the value pointed to by @p p_data with the value pointed to by @p p_expected. + * If those are equal, replaces the former with desired. Otherwise, loads the actual value + * pointed to by @p p_data into @p *p_expected. + * + * @param p_data Atomic memory pointer to test and modify. + * @param p_expected Pointer to the test value. + * @param desired Value to be stored to atomic memory. + * + * @retval true @p *p_data was equal to @p *p_expected. + * @retval false @p *p_data was not equal to @p *p_expected. + */ +bool nrfx_atomic_u32_cmp_exch(nrfx_atomic_u32_t * p_data, + uint32_t * p_expected, + uint32_t desired); + +/** + * @brief Function for running an arithmetic SUB operation on an atomic object + * if object >= value, and returning its previous value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of the second operand in the SUB operation. + * + * @return Previous value stored in the atomic object. + */ +uint32_t nrfx_atomic_u32_fetch_sub_hs(nrfx_atomic_u32_t * p_data, uint32_t value); + +/** + * @brief Function for running an arithmetic SUB operation on an atomic object + * if object >= value, and returning its new value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of the second operand in the SUB operation. + * + * @return New value stored in the atomic object. + */ +uint32_t nrfx_atomic_u32_sub_hs(nrfx_atomic_u32_t * p_data, uint32_t value); + +/** + * @brief Function for running a logical one bit flag set operation + * on an atomic object and returning its previous value. + * + * @param[in] p_data Atomic flag memory pointer. + * + * @return Previous flag value. + */ +uint32_t nrfx_atomic_flag_set_fetch(nrfx_atomic_flag_t * p_data); + +/** + * @brief Function for running a logical one bit flag set operation + * on an atomic object and returning its new value. + * + * @param[in] p_data Atomic flag memory pointer. + * + * @return New flag value. + */ +uint32_t nrfx_atomic_flag_set(nrfx_atomic_flag_t * p_data); + +/** + * @brief Function for running a logical one bit flag clear operation + * on an atomic object and returning its previous value. + * + * @param[in] p_data Atomic flag memory pointer. + * + * @return Previous flag value. + */ +uint32_t nrfx_atomic_flag_clear_fetch(nrfx_atomic_flag_t * p_data); + +/** + * @brief Function for running a logical one bit flag clear operation + * on an atomic object and returning its new value. + * + * @param[in] p_data Atomic flag memory pointer. + * + * @return New flag value. + */ +uint32_t nrfx_atomic_flag_clear(nrfx_atomic_flag_t * p_data); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif // NRFX_ATOMIC_H__ diff --git a/soc/nrfx_atomic_internal.h b/soc/nrfx_atomic_internal.h new file mode 100644 index 000000000..e528e4f39 --- /dev/null +++ b/soc/nrfx_atomic_internal.h @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * All rights reserved. + * + * 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. + */ + +#ifndef NRFX_ATOMIC_INTERNAL_H__ +#define NRFX_ATOMIC_INTERNAL_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Only Cortex-M cores > 3 support LDREX/STREX instructions. */ +#if ((__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U)) == 0 +#error "Unsupported core version" +#endif + +#if defined ( __CC_ARM ) +static __asm uint32_t nrfx_atomic_internal_mov(nrfx_atomic_u32_t * p_ptr, + uint32_t value, + uint32_t * p_new) +{ + /* The base standard specifies that arguments are passed in core registers r0-r3 and on the stack. + * Registers r4 and r5 must be saved on the stack. Note that only even number of register pushes are + * allowed. This is a requirement of the Procedure Call Standard for the ARM Architecture [AAPCS]. + */ + push {r4, r5} + mov r4, r0 + +loop_mov + ldrex r0, [r4] + mov r5, r1 + strex r3, r5, [r4] + cmp r3, #0 + bne loop_mov + + str r5, [r2] + pop {r4, r5} + bx lr +} + + +static __asm uint32_t nrfx_atomic_internal_orr(nrfx_atomic_u32_t * p_ptr, + uint32_t value, + uint32_t * p_new) +{ + push {r4, r5} + mov r4, r0 + +loop_orr + ldrex r0, [r4] + orr r5, r0, r1 + strex r3, r5, [r4] + cmp r3, #0 + bne loop_orr + + str r5, [r2] + pop {r4, r5} + bx lr +} + +static __asm uint32_t nrfx_atomic_internal_and(nrfx_atomic_u32_t * p_ptr, + uint32_t value, + uint32_t * p_new) +{ + push {r4, r5} + mov r4, r0 + +loop_and + ldrex r0, [r4] + and r5, r0, r1 + strex r3, r5, [r4] + cmp r3, #0 + bne loop_and + + str r5, [r2] + pop {r4, r5} + bx lr +} + +static __asm uint32_t nrfx_atomic_internal_eor(nrfx_atomic_u32_t * p_ptr, + uint32_t value, + uint32_t * p_new) +{ + push {r4, r5} + mov r4, r0 + +loop_eor + ldrex r0, [r4] + eor r5, r0, r1 + strex r3, r5, [r4] + cmp r3, #0 + bne loop_eor + + str r5, [r2] + pop {r4, r5} + bx lr +} + +static __asm uint32_t nrfx_atomic_internal_add(nrfx_atomic_u32_t * p_ptr, + uint32_t value, + uint32_t * p_new) +{ + push {r4, r5} + mov r4, r0 + +loop_add + ldrex r0, [r4] + add r5, r0, r1 + strex r3, r5, [r4] + cmp r3, #0 + bne loop_add + + str r5, [r2] + pop {r4, r5} + bx lr +} + +static __asm uint32_t nrfx_atomic_internal_sub(nrfx_atomic_u32_t * p_ptr, + uint32_t value, + uint32_t * p_new) +{ + push {r4, r5} + mov r4, r0 + +loop_sub + ldrex r0, [r4] + sub r5, r0, r1 + strex r3, r5, [r4] + cmp r3, #0 + bne loop_sub + + str r5, [r2] + pop {r4, r5} + bx lr +} + +static __asm bool nrfx_atomic_internal_cmp_exch(nrfx_atomic_u32_t * p_data, + uint32_t * p_expected, + uint32_t value) +{ +#define RET_REG r0 +#define P_EXPC r1 +#define VALUE r2 +#define STR_RES r3 +#define P_DATA r4 +#define EXPC_VAL r5 +#define ACT_VAL r6 + + push {r4-r6} + mov P_DATA, r0 + mov RET_REG, #0 + +loop_cmp_exch + ldrex ACT_VAL, [P_DATA] + ldr EXPC_VAL, [P_EXPC] + cmp ACT_VAL, EXPC_VAL + ittee eq + strexeq STR_RES, VALUE, [P_DATA] + moveq RET_REG, #1 + strexne STR_RES, ACT_VAL, [P_DATA] + strne ACT_VAL, [P_EXPC] + cmp STR_RES, #0 + itt ne + movne RET_REG, #0 + bne loop_cmp_exch + + pop {r4-r6} + bx lr + +#undef RET_REG +#undef P_EXPC +#undef VALUE +#undef STR_RES +#undef P_DATA +#undef EXPC_VAL +#undef ACT_VAL +} + +static __asm uint32_t nrfx_atomic_internal_sub_hs(nrfx_atomic_u32_t * p_ptr, + uint32_t value, + uint32_t * p_new) +{ + push {r4, r5} + mov r4, r0 + +loop_sub_ge + ldrex r0, [r4] + cmp r0, r1 + ite hs + subhs r5, r0, r1 + movlo r5, r0 + strex r3, r5, [r4] + cmp r3, #0 + bne loop_sub_ge + + str r5, [r2] + pop {r4, r5} + bx lr +} + + +#define NRFX_ATOMIC_OP(asm_op, old_val, new_val, ptr, value) \ + old_val = nrfx_atomic_internal_##asm_op(ptr, value, &new_val) + +#elif defined ( __ICCARM__ ) || defined ( __GNUC__ ) + +/** + * @brief Atomic operation generic macro. + * + * @param[in] asm_op Operation: mov, orr, and, eor, add, sub. + * @param[out] old_val Atomic object output (uint32_t), value before operation. + * @param[out] new_val Atomic object output (uint32_t), value after operation. + * @param[in] value Atomic operation operand. + */ +#define NRFX_ATOMIC_OP(asm_op, old_val, new_val, ptr, value) \ +{ \ + uint32_t tmp_reg; \ + __ASM volatile( \ + "1: ldrex %["#old_val"], [%["#ptr"]]\n" \ + NRFX_ATOMIC_OP_##asm_op(new_val, old_val, value) \ + " strex %[tmp_reg], %["#new_val"], [%["#ptr"]]\n" \ + " teq %[tmp_reg], #0\n" \ + " bne.n 1b" \ + : \ + [old_val] "=&r" (old_val), \ + [new_val] "=&r" (new_val), \ + [tmp_reg] "=&r" (tmp_reg) \ + : \ + [ptr] "r" (ptr), \ + [value] "r" (value) \ + : "cc"); \ + (void)tmp_reg; \ +} + +#define NRFX_ATOMIC_OP_mov(new_val, old_val, value) "mov %["#new_val"], %["#value"]\n" +#define NRFX_ATOMIC_OP_orr(new_val, old_val, value) "orr %["#new_val"], %["#old_val"], %["#value"]\n" +#define NRFX_ATOMIC_OP_and(new_val, old_val, value) "and %["#new_val"], %["#old_val"], %["#value"]\n" +#define NRFX_ATOMIC_OP_eor(new_val, old_val, value) "eor %["#new_val"], %["#old_val"], %["#value"]\n" +#define NRFX_ATOMIC_OP_add(new_val, old_val, value) "add %["#new_val"], %["#old_val"], %["#value"]\n" +#define NRFX_ATOMIC_OP_sub(new_val, old_val, value) "sub %["#new_val"], %["#old_val"], %["#value"]\n" +#define NRFX_ATOMIC_OP_sub_hs(new_val, old_val, value) \ + "cmp %["#old_val"], %["#value"]\n " \ + "ite hs\n" \ + "subhs %["#new_val"], %["#old_val"], %["#value"]\n" \ + "movlo %["#new_val"], %["#old_val"]\n" + +static inline bool nrfx_atomic_internal_cmp_exch(nrfx_atomic_u32_t * p_data, + uint32_t * p_expected, + uint32_t value) +{ + bool res = false; + /* Temporary register used in the inline asm code for getting the result + * of the strex* operations (no need to initialize it). + */ + uint32_t tmp_reg; + uint32_t act_val = 0; + uint32_t exp_val = 0; + __ASM volatile( + "1: ldrex %[act_val], [%[ptr]]\n" + " ldr %[exp_val], [%[expc]]\n" + " cmp %[act_val], %[exp_val]\n" + " ittee eq\n" + " strexeq %[tmp_reg], %[value], [%[ptr]]\n" + " moveq %[res], #1\n" + " strexne %[tmp_reg], %[act_val], [%[ptr]]\n" + " strne %[act_val], [%[expc]]\n" + " cmp %[tmp_reg], #0\n" + " itt ne\n" + " movne %[res], #0\n" + " bne.n 1b" + : + [res] "=&r" (res), + [exp_val] "=&r" (exp_val), + [act_val] "=&r" (act_val), + [tmp_reg] "=&r" (tmp_reg) + : + "0" (res), + "1" (exp_val), + "2" (act_val), + [expc] "r" (p_expected), + [ptr] "r" (p_data), + [value] "r" (value) + : "cc"); + (void)tmp_reg; + return res; +} + +#else +#error "Unsupported compiler" +#endif + +#ifdef __cplusplus +} +#endif + +#endif // NRFX_ATOMIC_INTERNAL_H__ diff --git a/soc/nrfx_irqs_nrf52832.h b/soc/nrfx_irqs_nrf52832.h index 69acff598..0ad4b68a8 100644 --- a/soc/nrfx_irqs_nrf52832.h +++ b/soc/nrfx_irqs_nrf52832.h @@ -75,6 +75,7 @@ extern "C" { #endif // NFCT_IRQn +#define nrfx_nfct_irq_handler NFCT_IRQHandler // GPIOTE_IRQn #define nrfx_gpiote_irq_handler GPIOTE_IRQHandler diff --git a/soc/nrfx_irqs_nrf52840.h b/soc/nrfx_irqs_nrf52840.h index 9840a530a..37dc39db2 100644 --- a/soc/nrfx_irqs_nrf52840.h +++ b/soc/nrfx_irqs_nrf52840.h @@ -75,6 +75,7 @@ extern "C" { #endif // NFCT_IRQn +#define nrfx_nfct_irq_handler NFCT_IRQHandler // GPIOTE_IRQn #define nrfx_gpiote_irq_handler GPIOTE_IRQHandler @@ -176,6 +177,7 @@ extern "C" { // FPU_IRQn // USBD_IRQn +#define nrfx_usbd_irq_handler USBD_IRQHandler // UARTE1_IRQn #define nrfx_uarte_1_irq_handler UARTE1_IRQHandler diff --git a/templates/nRF52832/nrfx_config.h b/templates/nRF52832/nrfx_config.h index 524f3a276..318b9311c 100644 --- a/templates/nRF52832/nrfx_config.h +++ b/templates/nRF52832/nrfx_config.h @@ -631,6 +631,79 @@ // +// NRFX_NFCT_ENABLED - nrfx_nfct - NFCT peripheral driver +//========================================================== +#ifndef NRFX_NFCT_ENABLED +#define NRFX_NFCT_ENABLED 1 +#endif +// NRFX_NFCT_CONFIG_IRQ_PRIORITY - Interrupt priority + +// <0=> 0 (highest) +// <1=> 1 +// <2=> 2 +// <3=> 3 +// <4=> 4 +// <5=> 5 +// <6=> 6 +// <7=> 7 + +#ifndef NRFX_NFCT_CONFIG_IRQ_PRIORITY +#define NRFX_NFCT_CONFIG_IRQ_PRIORITY 7 +#endif + +// NRFX_NFCT_CONFIG_LOG_ENABLED - Enables logging in the module. +//========================================================== +#ifndef NRFX_NFCT_CONFIG_LOG_ENABLED +#define NRFX_NFCT_CONFIG_LOG_ENABLED 0 +#endif +// NRFX_NFCT_CONFIG_LOG_LEVEL - Default Severity level + +// <0=> Off +// <1=> Error +// <2=> Warning +// <3=> Info +// <4=> Debug + +#ifndef NRFX_NFCT_CONFIG_LOG_LEVEL +#define NRFX_NFCT_CONFIG_LOG_LEVEL 3 +#endif + +// NRFX_NFCT_CONFIG_INFO_COLOR - ANSI escape code prefix. + +// <0=> Default +// <1=> Black +// <2=> Red +// <3=> Green +// <4=> Yellow +// <5=> Blue +// <6=> Magenta +// <7=> Cyan +// <8=> White + +#ifndef NRFX_NFCT_CONFIG_INFO_COLOR +#define NRFX_NFCT_CONFIG_INFO_COLOR 0 +#endif + +// NRFX_NFCT_CONFIG_DEBUG_COLOR - ANSI escape code prefix. + +// <0=> Default +// <1=> Black +// <2=> Red +// <3=> Green +// <4=> Yellow +// <5=> Blue +// <6=> Magenta +// <7=> Cyan +// <8=> White + +#ifndef NRFX_NFCT_CONFIG_DEBUG_COLOR +#define NRFX_NFCT_CONFIG_DEBUG_COLOR 0 +#endif + +// + +// + // NRFX_PDM_ENABLED - nrfx_pdm - PDM peripheral driver //========================================================== #ifndef NRFX_PDM_ENABLED diff --git a/templates/nRF52840/nrfx_config.h b/templates/nRF52840/nrfx_config.h index d9fbd9949..7bd70d82e 100644 --- a/templates/nRF52840/nrfx_config.h +++ b/templates/nRF52840/nrfx_config.h @@ -631,6 +631,79 @@ // +// NRFX_NFCT_ENABLED - nrfx_nfct - NFCT peripheral driver +//========================================================== +#ifndef NRFX_NFCT_ENABLED +#define NRFX_NFCT_ENABLED 1 +#endif +// NRFX_NFCT_CONFIG_IRQ_PRIORITY - Interrupt priority + +// <0=> 0 (highest) +// <1=> 1 +// <2=> 2 +// <3=> 3 +// <4=> 4 +// <5=> 5 +// <6=> 6 +// <7=> 7 + +#ifndef NRFX_NFCT_CONFIG_IRQ_PRIORITY +#define NRFX_NFCT_CONFIG_IRQ_PRIORITY 7 +#endif + +// NRFX_NFCT_CONFIG_LOG_ENABLED - Enables logging in the module. +//========================================================== +#ifndef NRFX_NFCT_CONFIG_LOG_ENABLED +#define NRFX_NFCT_CONFIG_LOG_ENABLED 0 +#endif +// NRFX_NFCT_CONFIG_LOG_LEVEL - Default Severity level + +// <0=> Off +// <1=> Error +// <2=> Warning +// <3=> Info +// <4=> Debug + +#ifndef NRFX_NFCT_CONFIG_LOG_LEVEL +#define NRFX_NFCT_CONFIG_LOG_LEVEL 3 +#endif + +// NRFX_NFCT_CONFIG_INFO_COLOR - ANSI escape code prefix. + +// <0=> Default +// <1=> Black +// <2=> Red +// <3=> Green +// <4=> Yellow +// <5=> Blue +// <6=> Magenta +// <7=> Cyan +// <8=> White + +#ifndef NRFX_NFCT_CONFIG_INFO_COLOR +#define NRFX_NFCT_CONFIG_INFO_COLOR 0 +#endif + +// NRFX_NFCT_CONFIG_DEBUG_COLOR - ANSI escape code prefix. + +// <0=> Default +// <1=> Black +// <2=> Red +// <3=> Green +// <4=> Yellow +// <5=> Blue +// <6=> Magenta +// <7=> Cyan +// <8=> White + +#ifndef NRFX_NFCT_CONFIG_DEBUG_COLOR +#define NRFX_NFCT_CONFIG_DEBUG_COLOR 0 +#endif + +// + +// + // NRFX_PDM_ENABLED - nrfx_pdm - PDM peripheral driver //========================================================== #ifndef NRFX_PDM_ENABLED @@ -2870,6 +2943,101 @@ // +// NRFX_USBD_ENABLED - nrfx_usbd - USBD peripheral driver +//========================================================== +#ifndef NRFX_USBD_ENABLED +#define NRFX_USBD_ENABLED 1 +#endif +// NRFX_USBD_CONFIG_IRQ_PRIORITY - Interrupt priority + +// <0=> 0 (highest) +// <1=> 1 +// <2=> 2 +// <3=> 3 +// <4=> 4 +// <5=> 5 +// <6=> 6 +// <7=> 7 + +#ifndef NRFX_USBD_CONFIG_IRQ_PRIORITY +#define NRFX_USBD_CONFIG_IRQ_PRIORITY 7 +#endif + +// USBD_CONFIG_DMASCHEDULER_ISO_BOOST - Give priority to isochronous transfers + +// This option gives priority to isochronous transfers. +// Enabling it assures that isochronous transfers are always processed, +// even if multiple other transfers are pending. +// Isochronous endpoints are prioritized before the usbd_dma_scheduler_algorithm +// function is called, so the option is independent of the algorithm chosen. + +#ifndef NRFX_USBD_CONFIG_DMASCHEDULER_ISO_BOOST +#define NRFX_USBD_CONFIG_DMASCHEDULER_ISO_BOOST 1 +#endif + +// USBD_CONFIG_ISO_IN_ZLP - Respond to an IN token on ISO IN endpoint with ZLP when no data is ready + + +// If set, ISO IN endpoint will respond to an IN token with ZLP when no data is ready to be sent. +// Else, there will be no response. + +#ifndef NRFX_USBD_CONFIG_ISO_IN_ZLP +#define NRFX_USBD_CONFIG_ISO_IN_ZLP 0 +#endif + +// NRFX_USBD_CONFIG_LOG_ENABLED - Enable logging in the module +//========================================================== +#ifndef NRFX_USBD_CONFIG_LOG_ENABLED +#define NRFX_USBD_CONFIG_LOG_ENABLED 0 +#endif +// NRFX_USBD_CONFIG_LOG_LEVEL - Default Severity level + +// <0=> Off +// <1=> Error +// <2=> Warning +// <3=> Info +// <4=> Debug + +#ifndef NRFX_USBD_CONFIG_LOG_LEVEL +#define NRFX_USBD_CONFIG_LOG_LEVEL 3 +#endif + +// NRFX_USBD_CONFIG_INFO_COLOR - ANSI escape code prefix. + +// <0=> Default +// <1=> Black +// <2=> Red +// <3=> Green +// <4=> Yellow +// <5=> Blue +// <6=> Magenta +// <7=> Cyan +// <8=> White + +#ifndef NRFX_USBD_CONFIG_INFO_COLOR +#define NRFX_USBD_CONFIG_INFO_COLOR 0 +#endif + +// NRFX_USBD_CONFIG_DEBUG_COLOR - ANSI escape code prefix. + +// <0=> Default +// <1=> Black +// <2=> Red +// <3=> Green +// <4=> Yellow +// <5=> Blue +// <6=> Magenta +// <7=> Cyan +// <8=> White + +#ifndef NRFX_USBD_CONFIG_DEBUG_COLOR +#define NRFX_USBD_CONFIG_DEBUG_COLOR 0 +#endif + +// + +// + // NRFX_WDT_ENABLED - nrfx_wdt - WDT peripheral driver //========================================================== #ifndef NRFX_WDT_ENABLED diff --git a/templates/nrfx_glue.h b/templates/nrfx_glue.h index 98351a5c9..88c3456f7 100644 --- a/templates/nrfx_glue.h +++ b/templates/nrfx_glue.h @@ -156,6 +156,77 @@ extern "C" { //------------------------------------------------------------------------------ +/** + * @brief Atomic 32-bit unsigned type. + */ +#define nrfx_atomic_t + +/** + * @brief Macro for storing a value to an atomic object and returning its previous value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value to store. + * + * @return Previous value of the atomic object. + */ +#define NRFX_ATOMIC_FETCH_STORE(p_data, value) + +/** + * @brief Macro for running a bitwise OR operation on an atomic object and returning its previous value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of the second operand in the OR operation. + * + * @return Previous value of the atomic object. + */ +#define NRFX_ATOMIC_FETCH_OR(p_data, value) + +/** + * @brief Macro for running a bitwise AND operation on an atomic object + * and returning its previous value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of the second operand in the AND operation. + * + * @return Previous value of the atomic object. + */ +#define NRFX_ATOMIC_FETCH_AND(p_data, value) + +/** + * @brief Macro for running a bitwise XOR operation on an atomic object + * and returning its previous value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of the second operand in the XOR operation. + * + * @return Previous value of the atomic object. + */ +#define NRFX_ATOMIC_FETCH_XOR(p_data, value) + +/** + * @brief Macro for running an addition operation on an atomic object + * and returning its previous value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of the second operand in the ADD operation. + * + * @return Previous value of the atomic object. + */ +#define NRFX_ATOMIC_FETCH_ADD(p_data, value) + +/** + * @brief Macro for running a subtraction operation on an atomic object + * and returning its previous value. + * + * @param[in] p_data Atomic memory pointer. + * @param[in] value Value of the second operand in the SUB operation. + * + * @return Previous value of the atomic object. + */ +#define NRFX_ATOMIC_FETCH_SUB(p_data, value) + +//------------------------------------------------------------------------------ + /** * @brief When set to a non-zero value, this macro specifies that the * @ref nrfx_error_codes and the @ref nrfx_err_t type itself are defined