aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_twis.c
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_twis.c')
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_twis.c834
1 files changed, 834 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_twis.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_twis.c
new file mode 100644
index 0000000..9fb7a49
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_twis.c
@@ -0,0 +1,834 @@
+/**
+ * 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, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, 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 Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <nrfx.h>
+
+#if NRFX_CHECK(NRFX_TWIS_ENABLED)
+
+#if !(NRFX_CHECK(NRFX_TWIS0_ENABLED) || NRFX_CHECK(NRFX_TWIS1_ENABLED))
+#error "No enabled TWIS instances. Check <nrfx_config.h>."
+#endif
+
+#include <nrfx_twis.h>
+#include "prs/nrfx_prs.h"
+
+#define NRFX_LOG_MODULE TWIS
+#include <nrfx_log.h>
+
+#define EVT_TO_STR(event) \
+ (event == NRF_TWIS_EVENT_STOPPED ? "NRF_TWIS_EVENT_STOPPED" : \
+ (event == NRF_TWIS_EVENT_ERROR ? "NRF_TWIS_EVENT_ERROR" : \
+ (event == NRF_TWIS_EVENT_RXSTARTED ? "NRF_TWIS_EVENT_RXSTARTED" : \
+ (event == NRF_TWIS_EVENT_TXSTARTED ? "NRF_TWIS_EVENT_TXSTARTED" : \
+ (event == NRF_TWIS_EVENT_WRITE ? "NRF_TWIS_EVENT_WRITE" : \
+ (event == NRF_TWIS_EVENT_READ ? "NRF_TWIS_EVENT_READ" : \
+ "UNKNOWN EVENT"))))))
+
+
+/**
+ * @brief Actual state of internal state machine
+ *
+ * Current substate of powered on state.
+ */
+typedef enum
+{
+ NRFX_TWIS_SUBSTATE_IDLE, ///< No ongoing transmission
+ NRFX_TWIS_SUBSTATE_READ_WAITING, ///< Read request received, waiting for data
+ NRFX_TWIS_SUBSTATE_READ_PENDING, ///< Reading is actually pending (data sending)
+ NRFX_TWIS_SUBSTATE_WRITE_WAITING, ///< Write request received, waiting for data buffer
+ NRFX_TWIS_SUBSTATE_WRITE_PENDING, ///< Writing is actually pending (data receiving)
+} nrfx_twis_substate_t;
+
+// Control block - driver instance local data.
+typedef struct
+{
+ nrfx_twis_event_handler_t ev_handler;
+ // Internal copy of hardware errors flags merged with specific internal
+ // driver errors flags.
+ // This value can be changed in the interrupt and cleared in the main program.
+ // Always use Atomic load-store when updating this value in main loop.
+ volatile uint32_t error;
+ nrfx_drv_state_t state;
+ volatile nrfx_twis_substate_t substate;
+
+ volatile bool semaphore;
+} twis_control_block_t;
+static twis_control_block_t m_cb[NRFX_TWIS_ENABLED_COUNT];
+
+/**
+ * @brief Used interrupts mask
+ *
+ * Mask for all interrupts used by this library
+ */
+static const uint32_t m_used_ints_mask = NRF_TWIS_INT_STOPPED_MASK |
+ NRF_TWIS_INT_ERROR_MASK |
+ NRF_TWIS_INT_RXSTARTED_MASK |
+ NRF_TWIS_INT_TXSTARTED_MASK |
+ NRF_TWIS_INT_WRITE_MASK |
+ NRF_TWIS_INT_READ_MASK;
+
+/**
+ * @brief Clear all events
+ *
+ * Function clears all actually pending events
+ */
+static void nrfx_twis_clear_all_events(NRF_TWIS_Type * const p_reg)
+{
+ /* Clear all events */
+ nrf_twis_event_clear(p_reg, NRF_TWIS_EVENT_STOPPED);
+ nrf_twis_event_clear(p_reg, NRF_TWIS_EVENT_ERROR);
+ nrf_twis_event_clear(p_reg, NRF_TWIS_EVENT_RXSTARTED);
+ nrf_twis_event_clear(p_reg, NRF_TWIS_EVENT_TXSTARTED);
+ nrf_twis_event_clear(p_reg, NRF_TWIS_EVENT_WRITE);
+ nrf_twis_event_clear(p_reg, NRF_TWIS_EVENT_READ);
+}
+
+/**
+ * @brief Reset all the registers to known state
+ *
+ * This function clears all registers that requires it to known state.
+ * TWIS is left disabled after this function.
+ * All events are cleared.
+ * @param[out] p_reg TWIS to reset register address
+ */
+static inline void nrfx_twis_swreset(NRF_TWIS_Type * p_reg)
+{
+ /* Disable TWIS */
+ nrf_twis_disable(p_reg);
+
+ /* Disconnect pins */
+ nrf_twis_pins_set(p_reg, ~0U, ~0U);
+
+ /* Disable interrupt global for the instance */
+ NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_reg));
+
+ /* Disable interrupts */
+ nrf_twis_int_disable(p_reg, ~0U);
+}
+
+/**
+ * @brief Configure pin
+ *
+ * Function configures selected for work as SDA or SCL.
+ * @param pin Pin number to configure
+ */
+static inline void nrfx_twis_config_pin(uint32_t pin, nrf_gpio_pin_pull_t pull)
+{
+ nrf_gpio_cfg(pin,
+ NRF_GPIO_PIN_DIR_INPUT,
+ NRF_GPIO_PIN_INPUT_DISCONNECT,
+ pull,
+ NRF_GPIO_PIN_S0D1,
+ NRF_GPIO_PIN_NOSENSE);
+}
+
+/**
+ * @brief Auxiliary function for getting event state on right bit possition
+ *
+ * This function calls @ref nrf_twis_event_get function but the the result
+ * is shifted to match INTEN register scheme.
+ *
+ * @param[in,out] p_reg TWIS to read event from
+ * @param ev Event code
+ *
+ * @return Selected event state shifted by @ref nrfx_event_to_bitpos
+ *
+ * @sa nrf_twis_event_get
+ * @sa nrfx_event_to_bitpos
+ */
+static inline uint32_t nrfx_twis_event_bit_get(NRF_TWIS_Type * p_reg,
+ nrf_twis_event_t ev)
+{
+ return (uint32_t)nrf_twis_event_get_and_clear(p_reg, ev) << nrfx_event_to_bitpos(ev);
+}
+
+/**
+ * @brief Auxiliary function for checking event bit inside given flags value
+ *
+ * Function used here to check presence of the event inside given flags value.
+ * It transforms given event to bit possition and then checks if in given variable it is cleared.
+ *
+ * @param flags Flags to test
+ * @param ev Event code
+ *
+ * @retval true Flag for selected event is set
+ * @retval false Flag for selected event is cleared
+ */
+static inline bool nrfx_twis_check_bit(uint32_t flags,
+ nrf_twis_event_t ev)
+{
+ return 0 != (flags & (1U << nrfx_event_to_bitpos(ev)));
+}
+
+/**
+ * @brief Auxiliary function for clearing event bit in given flags value
+ *
+ * Function used to clear selected event bit.
+ *
+ * @param flags Flags to process
+ * @param ev Event code to clear
+ *
+ * @return Value @em flags with cleared event bit that matches given @em ev
+ */
+static inline uint32_t nrfx_twis_clear_bit(uint32_t flags,
+ nrf_twis_event_t ev)
+{
+ return flags & ~(1U << nrfx_event_to_bitpos(ev));
+}
+
+static void call_event_handler(twis_control_block_t const * p_cb,
+ nrfx_twis_evt_t const * p_evt)
+{
+ nrfx_twis_event_handler_t handler = p_cb->ev_handler;
+ if (handler != NULL)
+ {
+ handler(p_evt);
+ }
+}
+
+/**
+ * @brief Auxiliary function for error processing
+ *
+ * Function called when in current substate the event apears and it cannot be processed.
+ * It should be called also on ERROR event.
+ * If given @em error parameter has zero value the @ref NRFX_TWIS_ERROR_UNEXPECTED_EVENT
+ * would be set.
+ *
+ * @param p_cb Pointer to the driver instance control block.
+ * @param evt What error event raport to event handler
+ * @param error Error flags
+ */
+static inline void nrfx_twis_process_error(twis_control_block_t * p_cb,
+ nrfx_twis_evt_type_t evt,
+ uint32_t error)
+{
+ if (0 == error)
+ {
+ error = NRFX_TWIS_ERROR_UNEXPECTED_EVENT;
+ }
+ nrfx_twis_evt_t evdata;
+ evdata.type = evt;
+ evdata.data.error = error;
+
+ p_cb->error |= error;
+
+ call_event_handler(p_cb, &evdata);
+}
+
+static void nrfx_twis_state_machine(NRF_TWIS_Type * p_reg,
+ twis_control_block_t * p_cb)
+{
+ if (!NRFX_TWIS_NO_SYNC_MODE)
+ {
+ /* Exclude parallel processing of this function */
+ if (p_cb->semaphore)
+ {
+ return;
+ }
+ p_cb->semaphore = 1;
+ }
+
+ /* Event data structure to be passed into event handler */
+ nrfx_twis_evt_t evdata;
+ /* Current substate copy */
+ nrfx_twis_substate_t substate = p_cb->substate;
+ /* Event flags */
+ uint32_t ev = 0;
+
+ /* Get all events */
+ ev |= nrfx_twis_event_bit_get(p_reg, NRF_TWIS_EVENT_STOPPED);
+ ev |= nrfx_twis_event_bit_get(p_reg, NRF_TWIS_EVENT_ERROR);
+ ev |= nrfx_twis_event_bit_get(p_reg, NRF_TWIS_EVENT_RXSTARTED);
+ ev |= nrfx_twis_event_bit_get(p_reg, NRF_TWIS_EVENT_TXSTARTED);
+ ev |= nrfx_twis_event_bit_get(p_reg, NRF_TWIS_EVENT_WRITE);
+ ev |= nrfx_twis_event_bit_get(p_reg, NRF_TWIS_EVENT_READ);
+
+ /* State machine */
+ while (0 != ev)
+ {
+ switch (substate)
+ {
+ case NRFX_TWIS_SUBSTATE_IDLE:
+ if (nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_STOPPED))
+ {
+ /* Stopped event is always allowed in IDLE state - just ignore */
+ ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_STOPPED);
+ }
+ else if (nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_READ))
+ {
+ evdata.type = NRFX_TWIS_EVT_READ_REQ;
+ if (nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_TXSTARTED))
+ {
+ substate = NRFX_TWIS_SUBSTATE_READ_PENDING;
+ evdata.data.buf_req = false;
+ }
+ else
+ {
+ substate = NRFX_TWIS_SUBSTATE_READ_WAITING;
+ evdata.data.buf_req = true;
+ }
+ call_event_handler(p_cb, &evdata);
+ ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_READ);
+ ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_TXSTARTED);
+ ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_WRITE);
+ ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_RXSTARTED);
+ }
+ else if (nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_WRITE))
+ {
+ evdata.type = NRFX_TWIS_EVT_WRITE_REQ;
+ if (nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_RXSTARTED))
+ {
+ substate = NRFX_TWIS_SUBSTATE_WRITE_PENDING;
+ evdata.data.buf_req = false;
+ }
+ else
+ {
+ substate = NRFX_TWIS_SUBSTATE_WRITE_WAITING;
+ evdata.data.buf_req = true;
+ }
+ call_event_handler(p_cb, &evdata);
+ ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_READ);
+ ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_TXSTARTED);
+ ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_WRITE);
+ ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_RXSTARTED);
+ }
+ else
+ {
+ nrfx_twis_process_error(p_cb,
+ NRFX_TWIS_EVT_GENERAL_ERROR,
+ nrf_twis_error_source_get_and_clear(p_reg));
+ ev = 0;
+ }
+ break;
+ case NRFX_TWIS_SUBSTATE_READ_WAITING:
+ if (nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_TXSTARTED) ||
+ nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_WRITE) ||
+ nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_READ) ||
+ nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_STOPPED))
+ {
+ substate = NRFX_TWIS_SUBSTATE_READ_PENDING;
+ /* Any other bits requires further processing in PENDING substate */
+ ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_TXSTARTED);
+ }
+ else
+ {
+ nrfx_twis_process_error(p_cb,
+ NRFX_TWIS_EVT_READ_ERROR,
+ nrf_twis_error_source_get_and_clear(p_reg));
+ substate = NRFX_TWIS_SUBSTATE_IDLE;
+ ev = 0;
+ }
+ break;
+ case NRFX_TWIS_SUBSTATE_READ_PENDING:
+ if (nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_WRITE) ||
+ nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_READ) ||
+ nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_STOPPED))
+ {
+ evdata.type = NRFX_TWIS_EVT_READ_DONE;
+ evdata.data.tx_amount = nrf_twis_tx_amount_get(p_reg);
+ NRFX_LOG_INFO("Transfer tx_len:%d", evdata.data.tx_amount);
+ NRFX_LOG_DEBUG("Tx data:");
+ NRFX_LOG_HEXDUMP_DEBUG((uint8_t const *)p_reg->TXD.PTR,
+ evdata.data.tx_amount * sizeof(uint8_t));
+ call_event_handler(p_cb, &evdata);
+ /* Go to idle and repeat the state machine if READ or WRITE events detected.
+ * This time READ or WRITE would be started */
+ substate = NRFX_TWIS_SUBSTATE_IDLE;
+ ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_STOPPED);
+ }
+ else
+ {
+ nrfx_twis_process_error(p_cb,
+ NRFX_TWIS_EVT_READ_ERROR,
+ nrf_twis_error_source_get_and_clear(p_reg));
+ substate = NRFX_TWIS_SUBSTATE_IDLE;
+ ev = 0;
+ }
+ break;
+ case NRFX_TWIS_SUBSTATE_WRITE_WAITING:
+ if (nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_RXSTARTED) ||
+ nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_WRITE) ||
+ nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_READ) ||
+ nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_STOPPED))
+ {
+ substate = NRFX_TWIS_SUBSTATE_WRITE_PENDING;
+ /* Any other bits requires further processing in PENDING substate */
+ ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_RXSTARTED);
+ }
+ else
+ {
+ nrfx_twis_process_error(p_cb,
+ NRFX_TWIS_EVT_WRITE_ERROR,
+ nrf_twis_error_source_get_and_clear(p_reg));
+ substate = NRFX_TWIS_SUBSTATE_IDLE;
+ ev = 0;
+ }
+ break;
+ case NRFX_TWIS_SUBSTATE_WRITE_PENDING:
+ if (nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_WRITE) ||
+ nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_READ) ||
+ nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_STOPPED))
+ {
+ evdata.type = NRFX_TWIS_EVT_WRITE_DONE;
+ evdata.data.rx_amount = nrf_twis_rx_amount_get(p_reg);
+ call_event_handler(p_cb, &evdata);
+ /* Go to idle and repeat the state machine if READ or WRITE events detected.
+ * This time READ or WRITE would be started */
+ substate = NRFX_TWIS_SUBSTATE_IDLE;
+ ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_STOPPED);
+ }
+ else
+ {
+ nrfx_twis_process_error(p_cb,
+ NRFX_TWIS_EVT_WRITE_ERROR,
+ nrf_twis_error_source_get_and_clear(p_reg));
+ substate = NRFX_TWIS_SUBSTATE_IDLE;
+ ev = 0;
+ }
+ break;
+ default:
+ substate = NRFX_TWIS_SUBSTATE_IDLE;
+ /* Do not clear any events and repeat the machine */
+ break;
+ }
+ }
+
+ p_cb->substate = substate;
+ if (!NRFX_TWIS_NO_SYNC_MODE)
+ {
+ p_cb->semaphore = 0;
+ }
+}
+
+
+static inline void nrfx_twis_preprocess_status(nrfx_twis_t const * p_instance)
+{
+ if (!NRFX_TWIS_NO_SYNC_MODE)
+ {
+ NRF_TWIS_Type * p_reg = p_instance->p_reg;
+ twis_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
+ if (NULL == p_cb->ev_handler)
+ {
+ nrfx_twis_state_machine(p_reg, p_cb);
+ }
+ }
+}
+
+
+/* -------------------------------------------------------------------------
+ * Implementation of interface functions
+ *
+ */
+
+
+nrfx_err_t nrfx_twis_init(nrfx_twis_t const * p_instance,
+ nrfx_twis_config_t const * p_config,
+ nrfx_twis_event_handler_t event_handler)
+{
+ NRFX_ASSERT(p_config);
+ NRFX_ASSERT(p_config->scl != p_config->sda);
+ nrfx_err_t err_code;
+
+ NRF_TWIS_Type * p_reg = p_instance->p_reg;
+ twis_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
+
+ if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
+ {
+ err_code = NRFX_ERROR_INVALID_STATE;
+ NRFX_LOG_WARNING("Function: %s, error code: %s.",
+ __func__,
+ NRFX_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+ }
+
+#if NRFX_CHECK(NRFX_PRS_ENABLED)
+ static nrfx_irq_handler_t const irq_handlers[NRFX_TWIS_ENABLED_COUNT] = {
+ #if NRFX_CHECK(NRFX_TWIS0_ENABLED)
+ nrfx_twis_0_irq_handler,
+ #endif
+ #if NRFX_CHECK(NRFX_TWIS1_ENABLED)
+ nrfx_twis_1_irq_handler,
+ #endif
+ };
+ if (nrfx_prs_acquire(p_reg,
+ irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
+ {
+ err_code = NRFX_ERROR_BUSY;
+ NRFX_LOG_WARNING("Function: %s, error code: %s.",
+ __func__,
+ NRFX_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+ }
+#endif // NRFX_CHECK(NRFX_PRS_ENABLED)
+
+ if (!NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY)
+ {
+ nrfx_twis_swreset(p_reg);
+ }
+
+ nrfx_twis_config_pin(p_config->scl, p_config->scl_pull);
+ nrfx_twis_config_pin(p_config->sda, p_config->sda_pull);
+
+ nrf_twis_config_addr_mask_t addr_mask = (nrf_twis_config_addr_mask_t)0;
+ if (0 == (p_config->addr[0] | p_config->addr[1]))
+ {
+ addr_mask = NRF_TWIS_CONFIG_ADDRESS0_MASK;
+ }
+ else
+ {
+ if (0 != p_config->addr[0])
+ {
+ addr_mask |= NRF_TWIS_CONFIG_ADDRESS0_MASK;
+ }
+ if (0 != p_config->addr[1])
+ {
+ addr_mask |= NRF_TWIS_CONFIG_ADDRESS1_MASK;
+ }
+ }
+
+ /* Peripheral interrupt configure
+ * (note - interrupts still needs to be configured in INTEN register.
+ * This is done in enable function) */
+ NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_reg),
+ p_config->interrupt_priority);
+ NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_reg));
+
+ /* Configure */
+ nrf_twis_pins_set (p_reg, p_config->scl, p_config->sda);
+ nrf_twis_address_set (p_reg, 0, p_config->addr[0]);
+ nrf_twis_address_set (p_reg, 1, p_config->addr[1]);
+ nrf_twis_config_address_set(p_reg, addr_mask);
+
+ /* Clear semaphore */
+ if (!NRFX_TWIS_NO_SYNC_MODE)
+ {
+ p_cb->semaphore = 0;
+ }
+ /* Set internal instance variables */
+ p_cb->substate = NRFX_TWIS_SUBSTATE_IDLE;
+ p_cb->ev_handler = event_handler;
+ p_cb->state = NRFX_DRV_STATE_INITIALIZED;
+ err_code = NRFX_SUCCESS;
+ NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+}
+
+
+void nrfx_twis_uninit(nrfx_twis_t const * p_instance)
+{
+ NRF_TWIS_Type * p_reg = p_instance->p_reg;
+ twis_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
+ NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
+
+ TWIS_PSEL_Type psel = p_reg->PSEL;
+
+ nrfx_twis_swreset(p_reg);
+
+ /* Clear pins state if */
+ if (!(TWIS_PSEL_SCL_CONNECT_Msk & psel.SCL))
+ {
+ nrf_gpio_cfg_default(psel.SCL);
+ }
+ if (!(TWIS_PSEL_SDA_CONNECT_Msk & psel.SDA))
+ {
+ nrf_gpio_cfg_default(psel.SDA);
+ }
+
+#if NRFX_CHECK(NRFX_PRS_ENABLED)
+ nrfx_prs_release(p_reg);
+#endif
+
+ /* Clear variables */
+ p_cb->ev_handler = NULL;
+ p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
+}
+
+
+void nrfx_twis_enable(nrfx_twis_t const * p_instance)
+{
+ NRF_TWIS_Type * p_reg = p_instance->p_reg;
+ twis_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
+ NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED);
+
+ nrfx_twis_clear_all_events(p_reg);
+
+ /* Enable interrupts */
+ if (NULL != p_cb->ev_handler)
+ {
+ nrf_twis_int_enable(p_reg, m_used_ints_mask);
+ }
+
+ nrf_twis_enable(p_reg);
+ p_cb->error = 0;
+ p_cb->state = NRFX_DRV_STATE_POWERED_ON;
+ p_cb->substate = NRFX_TWIS_SUBSTATE_IDLE;
+}
+
+
+void nrfx_twis_disable(nrfx_twis_t const * p_instance)
+{
+ NRF_TWIS_Type * p_reg = p_instance->p_reg;
+ twis_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
+ NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
+
+ nrf_twis_int_disable(p_reg, m_used_ints_mask);
+
+ nrf_twis_disable(p_reg);
+ p_cb->state = NRFX_DRV_STATE_INITIALIZED;
+}
+
+/* ARM recommends not using the LDREX and STREX instructions in C code.
+ * This is because the compiler might generate loads and stores between
+ * LDREX and STREX, potentially clearing the exclusive monitor set by LDREX.
+ * This recommendation also applies to the byte, halfword, and doubleword
+ * variants LDREXB, STREXB, LDREXH, STREXH, LDREXD, and STREXD.
+ *
+ * This is the reason for the function below to be implemented in assembly.
+ */
+//lint -save -e578
+#if defined (__CC_ARM )
+static __ASM uint32_t nrfx_twis_error_get_and_clear_internal(uint32_t volatile * perror)
+{
+ mov r3, r0
+ mov r1, #0
+nrfx_twis_error_get_and_clear_internal_try
+ ldrex r0, [r3]
+ strex r2, r1, [r3]
+ cmp r2, r1 /* did this succeed? */
+ bne nrfx_twis_error_get_and_clear_internal_try /* no - try again */
+ bx lr
+}
+#elif defined ( __GNUC__ )
+static uint32_t nrfx_twis_error_get_and_clear_internal(uint32_t volatile * perror)
+{
+ uint32_t ret;
+ uint32_t temp;
+ __ASM volatile(
+ " .syntax unified \n"
+ "nrfx_twis_error_get_and_clear_internal_try: \n"
+ " ldrex %[ret], [%[perror]] \n"
+ " strex %[temp], %[zero], [%[perror]] \n"
+ " cmp %[temp], %[zero] \n"
+ " bne nrfx_twis_error_get_and_clear_internal_try \n"
+ : /* Output */
+ [ret]"=&l"(ret),
+ [temp]"=&l"(temp)
+ : /* Input */
+ [zero]"l"(0),
+ [perror]"l"(perror)
+ );
+ (void)temp;
+ return ret;
+}
+#elif defined ( __ICCARM__ )
+static uint32_t nrfx_twis_error_get_and_clear_internal(uint32_t volatile * perror)
+{
+ uint32_t ret;
+ uint32_t temp;
+ __ASM volatile(
+ "1: \n"
+ " ldrex %[ret], [%[perror]] \n"
+ " strex %[temp], %[zero], [%[perror]] \n"
+ " cmp %[temp], %[zero] \n"
+ " bne.n 1b \n"
+ : /* Output */
+ [ret]"=&l"(ret),
+ [temp]"=&l"(temp)
+ : /* Input */
+ [zero]"l"(0),
+ [perror]"l"(perror)
+ );
+ (void)temp;
+ return ret;
+}
+#else
+ #error Unknown compiler
+#endif
+//lint -restore
+
+uint32_t nrfx_twis_error_get_and_clear(nrfx_twis_t const * p_instance)
+{
+ nrfx_twis_preprocess_status(p_instance);
+ /* Make sure that access to error member is atomic
+ * so there is no bit that is cleared if it is not copied to local variable already. */
+ twis_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
+ return nrfx_twis_error_get_and_clear_internal(&p_cb->error);
+}
+
+
+nrfx_err_t nrfx_twis_tx_prepare(nrfx_twis_t const * p_instance,
+ void const * p_buf,
+ size_t size)
+{
+ nrfx_err_t err_code;
+ twis_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx];
+
+ /* Check power state*/
+ if (p_cb->state != NRFX_DRV_STATE_POWERED_ON)
+ {
+ err_code = NRFX_ERROR_INVALID_STATE;
+ NRFX_LOG_WARNING("Function: %s, error code: %s.",
+ __func__,
+ NRFX_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+ }
+ /* Check data address */
+ if (!nrfx_is_in_ram(p_buf))
+ {
+ err_code = NRFX_ERROR_INVALID_ADDR;
+ NRFX_LOG_WARNING("Function: %s, error code: %s.",
+ __func__,
+ NRFX_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+ }
+ /* Check data size */
+ if ((size & TWIS_TXD_MAXCNT_MAXCNT_Msk) != size)
+ {
+ err_code = NRFX_ERROR_INVALID_LENGTH;
+ NRFX_LOG_WARNING("Function: %s, error code: %s.",
+ __func__,
+ NRFX_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+ }
+
+ nrf_twis_tx_prepare(p_instance->p_reg,
+ (uint8_t const *)p_buf,
+ (nrf_twis_amount_t)size);
+ err_code = NRFX_SUCCESS;
+ NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+}
+
+
+nrfx_err_t nrfx_twis_rx_prepare(nrfx_twis_t const * p_instance,
+ void * p_buf,
+ size_t size)
+{
+ nrfx_err_t err_code;
+ twis_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx];
+
+ /* Check power state*/
+ if (p_cb->state != NRFX_DRV_STATE_POWERED_ON)
+ {
+ err_code = NRFX_ERROR_INVALID_STATE;
+ NRFX_LOG_WARNING("Function: %s, error code: %s.",
+ __func__,
+ NRFX_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+ }
+ /* Check data address */
+ if (!nrfx_is_in_ram(p_buf))
+ {
+ err_code = NRFX_ERROR_INVALID_ADDR;
+ NRFX_LOG_WARNING("Function: %s, error code: %s.",
+ __func__,
+ NRFX_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+ }
+ /* Check data size */
+ if ((size & TWIS_RXD_MAXCNT_MAXCNT_Msk) != size)
+ {
+ err_code = NRFX_ERROR_INVALID_LENGTH;
+ NRFX_LOG_WARNING("Function: %s, error code: %s.",
+ __func__,
+ NRFX_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+ }
+
+ nrf_twis_rx_prepare(p_instance->p_reg,
+ (uint8_t *)p_buf,
+ (nrf_twis_amount_t)size);
+ err_code = NRFX_SUCCESS;
+ NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+}
+
+
+bool nrfx_twis_is_busy(nrfx_twis_t const * p_instance)
+{
+ nrfx_twis_preprocess_status(p_instance);
+ twis_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx];
+ return NRFX_TWIS_SUBSTATE_IDLE != p_cb->substate;
+}
+
+bool nrfx_twis_is_waiting_tx_buff(nrfx_twis_t const * p_instance)
+{
+ nrfx_twis_preprocess_status(p_instance);
+ twis_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx];
+ return NRFX_TWIS_SUBSTATE_READ_WAITING == p_cb->substate;
+}
+
+bool nrfx_twis_is_waiting_rx_buff(nrfx_twis_t const * p_instance)
+{
+ nrfx_twis_preprocess_status(p_instance);
+ twis_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx];
+ return NRFX_TWIS_SUBSTATE_WRITE_WAITING == p_cb->substate;
+}
+
+bool nrfx_twis_is_pending_tx(nrfx_twis_t const * p_instance)
+{
+ nrfx_twis_preprocess_status(p_instance);
+ twis_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx];
+ return NRFX_TWIS_SUBSTATE_READ_PENDING == p_cb->substate;
+}
+
+bool nrfx_twis_is_pending_rx(nrfx_twis_t const * p_instance)
+{
+ nrfx_twis_preprocess_status(p_instance);
+ twis_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx];
+ return NRFX_TWIS_SUBSTATE_WRITE_PENDING == p_cb->substate;
+}
+
+
+#if NRFX_CHECK(NRFX_TWIS0_ENABLED)
+void nrfx_twis_0_irq_handler(void)
+{
+ nrfx_twis_state_machine(NRF_TWIS0, &m_cb[NRFX_TWIS0_INST_IDX]);
+}
+#endif
+
+#if NRFX_CHECK(NRFX_TWIS1_ENABLED)
+void nrfx_twis_1_irq_handler(void)
+{
+ nrfx_twis_state_machine(NRF_TWIS1, &m_cb[NRFX_TWIS1_INST_IDX]);
+}
+#endif
+
+#endif // NRFX_CHECK(NRFX_TWIS_ENABLED)