aboutsummaryrefslogtreecommitdiffstats
path: root/drivers_nrf/twis_slave
diff options
context:
space:
mode:
authortcsullivan <tullivan99@gmail.com>2019-03-10 15:37:07 -0400
committertcsullivan <tullivan99@gmail.com>2019-03-10 15:37:07 -0400
commitdd33956654589ded6644a75088e50069b1744ef9 (patch)
treeeddd51f1aac130f6c7082a2de53b8e46f0387187 /drivers_nrf/twis_slave
parent3c3f87b4cab153b49e3cde105dd2f34712e0b790 (diff)
rtc, keeping time
Diffstat (limited to 'drivers_nrf/twis_slave')
-rw-r--r--drivers_nrf/twis_slave/nrf_drv_twis.c942
-rw-r--r--drivers_nrf/twis_slave/nrf_drv_twis.h396
-rw-r--r--drivers_nrf/twis_slave/nrf_drv_twis_inst.def20
3 files changed, 1358 insertions, 0 deletions
diff --git a/drivers_nrf/twis_slave/nrf_drv_twis.c b/drivers_nrf/twis_slave/nrf_drv_twis.c
new file mode 100644
index 0000000..51a39f7
--- /dev/null
+++ b/drivers_nrf/twis_slave/nrf_drv_twis.c
@@ -0,0 +1,942 @@
+/**
+ * Copyright (c) 2015 - 2017, 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 "sdk_common.h"
+#if NRF_MODULE_ENABLED(TWIS)
+#define ENABLED_TWIS_COUNT (TWIS0_ENABLED+TWIS1_ENABLED)
+#if ENABLED_TWIS_COUNT
+#include "nrf_drv_twis.h"
+#include "nrf_assert.h"
+#include "app_util_platform.h"
+#include "compiler_abstraction.h"
+
+#define NRF_LOG_MODULE_NAME "TWIS"
+
+#if TWIS_CONFIG_LOG_ENABLED
+#define NRF_LOG_LEVEL TWIS_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR TWIS_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR TWIS_CONFIG_DEBUG_COLOR
+#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"))))))
+#else //TWIS_CONFIG_LOG_ENABLED
+#define EVT_TO_STR(event) ""
+#define NRF_LOG_LEVEL 0
+#endif //TWIS_CONFIG_LOG_ENABLED
+#include "nrf_log.h"
+#include "nrf_log_ctrl.h"
+
+/**
+ * @internal
+ * @ingroup lib_twis_drv
+ * @defgroup lib_twis_drv_ivars Software controlled TWI Slave internal variables
+ *
+ * Internal variables for TWIS.
+ * @{
+ */
+
+/**
+ * @brief Actual state of internal state machine
+ *
+ * Current substate of powered on state.
+ */
+typedef enum
+{
+ NRF_DRV_TWIS_SUBSTATE_IDLE, ///< No ongoing transmission
+ NRF_DRV_TWIS_SUBSTATE_READ_WAITING, ///< Read request received, waiting for data
+ NRF_DRV_TWIS_SUBSTATE_READ_PENDING, ///< Reading is actually pending (data sending)
+ NRF_DRV_TWIS_SUBSTATE_WRITE_WAITING, ///< Write request received, waiting for data buffer
+ NRF_DRV_TWIS_SUBSTATE_WRITE_PENDING, ///< Writing is actually pending (data receiving)
+}nrf_drv_twis_substate_t;
+
+/**
+ * @brief Constant instance part
+ *
+ * Instance data that have not to change.
+ * It may be placed in FLASH memory.
+ */
+typedef struct
+{
+ NRF_TWIS_Type * const p_reg; ///< Peripheral registry address
+} nrf_drv_twis_const_inst_t;
+
+/**
+ * @brief Variable instance part
+ *
+ * There are all informations for the instance that may change.
+ */
+typedef struct
+{
+ nrf_drv_state_t state; ///< Actual driver state
+ volatile nrf_drv_twis_substate_t substate; ///< Actual driver substate
+ nrf_drv_twis_event_handler_t ev_handler; ///< Event handler functiomn
+ volatile uint32_t error; ///< Internal error flags
+ /**< Internal copy of hardware errors flags merged
+ * with specific internal driver errors flags.
+ *
+ * @note 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.
+ */
+}nrf_drv_twis_var_inst_t;
+
+
+/** The constant instance part implementation */
+static const nrf_drv_twis_const_inst_t m_const_inst[ENABLED_TWIS_COUNT] =
+{
+ #define X(n) { .p_reg = NRF_TWIS##n },
+ #include "nrf_drv_twis_inst.def"
+};
+
+/** The variable instance part implementation */
+static nrf_drv_twis_var_inst_t m_var_inst[ENABLED_TWIS_COUNT] =
+{
+ #define X(n) { .state = NRF_DRV_STATE_UNINITIALIZED, \
+ .substate = NRF_DRV_TWIS_SUBSTATE_IDLE, \
+ .ev_handler = NULL, \
+ .error = 0 },
+ #include "nrf_drv_twis_inst.def"
+};
+
+#if NRF_MODULE_ENABLED(PERIPHERAL_RESOURCE_SHARING)
+ #define IRQ_HANDLER_NAME(n) irq_handler_for_instance_##n
+ #define IRQ_HANDLER(n) static void IRQ_HANDLER_NAME(n)(void)
+
+ #if NRF_MODULE_ENABLED(TWIS0)
+ IRQ_HANDLER(0);
+ #endif
+ #if NRF_MODULE_ENABLED(TWIS1)
+ IRQ_HANDLER(1);
+ #endif
+ static nrf_drv_irq_handler_t const m_irq_handlers[ENABLED_TWIS_COUNT] = {
+ #if NRF_MODULE_ENABLED(TWIS0)
+ IRQ_HANDLER_NAME(0),
+ #endif
+ #if NRF_MODULE_ENABLED(TWIS1)
+ IRQ_HANDLER_NAME(1),
+ #endif
+ };
+#else
+ #define IRQ_HANDLER(n) \
+ void SPIM##n##_SPIS##n##_TWIM##n##_TWIS##n##_SPI##n##_TWI##n##_IRQHandler(void)
+#endif // NRF_MODULE_ENABLED(PERIPHERAL_RESOURCE_SHARING)
+
+/**
+ * @brief State processing semaphore
+ *
+ * There are semaphores used when when working in synchronous mode (without interrupts activated).
+ * @note
+ * In synchronous mode before every state checking the state machine is executed.
+ * But the situation where state checking function is called from main task and in the same from
+ * interrupt task has to be considered.
+ * In such a situation the @ref nrf_drv_twis_state_machine function may be interrupted by second
+ * call to the same function.
+ * If in this second call any event will be detected it may be lost because new substate would be
+ * overwritten when interrupted function finishes.
+ * In the same time information about event would be lost because it is cleared in interrupting
+ * function.
+ * @note
+ * To make situation described above safe, simple semaphore is implemented.
+ * It is just a binary flag that informs that state machine is actually executing and should not
+ * be processed in any interrupting function.
+ * Because of how it is used no atomic instructions are required to support this kind of semaphore.
+ * It is not waitable semaphore - function executed or not depending of its state.
+ */
+static uint8_t m_sm_semaphore[ENABLED_TWIS_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;
+
+
+/** @} */ /* End of lib_driver_twis_slave_ivars */
+
+/**
+ * @internal
+ * @ingroup lib_twis_drv
+ * @defgroup lib_twis_drv_ifunc Software controlled TWI Slave auxiliary internal functions
+ *
+ * Internal variables for TWIS.
+ * @{
+ */
+
+/**
+ * @brief Clear all events
+ *
+ * Function clears all actually pending events
+ */
+static void nrf_drv_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 nrf_drv_twis_swreset(NRF_TWIS_Type * const 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 */
+ nrf_drv_common_irq_disable(nrf_drv_get_IRQn(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 nrf_drv_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 Call event handler
+ *
+ * Function that calls event handler.
+ * The event handler would be only called if its value is != NULL.
+ * @param instNr Driver instance number that has called this runtime.
+ * @param[in] pev Event structure to pass to event handler
+ * @note
+ * Remember about possible multithreading.
+ * It is acceptable to call old event function if it was already disabled.
+ * What is unacceptable is jump into NULL pointer.
+ */
+static void nrf_drv_call_event_handler(uint8_t instNr, nrf_drv_twis_evt_t const * const pev)
+{
+ nrf_drv_twis_event_handler_t evh = m_var_inst[instNr].ev_handler;
+ if (NULL != evh)
+ {
+ evh(pev);
+ }
+}
+
+/**
+ * @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 nrf_drv_event_to_bitpos
+ *
+ * @sa nrf_twis_event_get
+ * @sa nrf_drv_event_to_bitpos
+ */
+static inline uint32_t nrf_drv_twis_event_bit_get(NRF_TWIS_Type * const p_reg, nrf_twis_event_t ev)
+{
+ return (uint32_t)nrf_twis_event_get_and_clear(p_reg, ev) << nrf_drv_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 nrf_drv_twis_check_bit(uint32_t flags, nrf_twis_event_t ev)
+{
+ return 0 != (flags & (1U<<nrf_drv_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 nrf_drv_twis_clear_bit(uint32_t flags, nrf_twis_event_t ev)
+{
+ return flags & ~(1U<<nrf_drv_event_to_bitpos(ev));
+}
+
+/**
+ * @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 NRF_DRV_TWIS_ERROR_UNEXPECTED_EVENT
+ * would be set.
+ *
+ * @param instNr Instance number
+ * @param ev What error event raport to event handler
+ * @param error Error flags
+ */
+static inline void nrf_drv_twis_process_error(
+ uint8_t instNr,
+ nrf_drv_twis_evt_type_t ev,
+ uint32_t error)
+{
+ if (0 == error)
+ error = NRF_DRV_TWIS_ERROR_UNEXPECTED_EVENT;
+ nrf_drv_twis_evt_t evdata;
+ evdata.type = ev;
+ evdata.data.error = error;
+
+ m_var_inst[instNr].error |= error;
+
+ nrf_drv_call_event_handler(instNr, &evdata);
+}
+
+
+/**
+ * @brief State machine main function
+ *
+ * State machine function that reacts on events.
+ * This function gets all events and reacts on them only if there is any event detected.
+ * It makes it possible to use it either in interrupt or in polling mode.
+ * @param instNr Driver instance number that has called this runtime.
+ */
+static void nrf_drv_twis_state_machine(uint8_t instNr)
+{
+ if (!TWIS_NO_SYNC_MODE)
+ {
+ /* Exclude parallel processing of this function */
+ if (m_sm_semaphore[instNr])
+ {
+ return;
+ }
+ m_sm_semaphore[instNr] = 1;
+ }
+
+ NRF_TWIS_Type * const p_reg = m_const_inst[instNr].p_reg;
+ /* Event data structure to be passed into event handler */
+ nrf_drv_twis_evt_t evdata;
+ /* Current substate copy */
+ nrf_drv_twis_substate_t substate = m_var_inst[instNr].substate;
+ /* Event flags */
+ uint32_t ev = 0;
+
+ /* Get all events */
+ ev |= nrf_drv_twis_event_bit_get(p_reg, NRF_TWIS_EVENT_STOPPED);
+ ev |= nrf_drv_twis_event_bit_get(p_reg, NRF_TWIS_EVENT_ERROR);
+ ev |= nrf_drv_twis_event_bit_get(p_reg, NRF_TWIS_EVENT_RXSTARTED);
+ ev |= nrf_drv_twis_event_bit_get(p_reg, NRF_TWIS_EVENT_TXSTARTED);
+ ev |= nrf_drv_twis_event_bit_get(p_reg, NRF_TWIS_EVENT_WRITE);
+ ev |= nrf_drv_twis_event_bit_get(p_reg, NRF_TWIS_EVENT_READ);
+
+ /* State machine */
+ while (0 != ev)
+ {
+ switch (substate)
+ {
+ case NRF_DRV_TWIS_SUBSTATE_IDLE:
+ if (nrf_drv_twis_check_bit(ev, NRF_TWIS_EVENT_STOPPED))
+ {
+ /* Stopped event is always allowed in IDLE state - just ignore */
+ ev = nrf_drv_twis_clear_bit(ev, NRF_TWIS_EVENT_STOPPED);
+ }
+ else if (nrf_drv_twis_check_bit(ev, NRF_TWIS_EVENT_READ))
+ {
+ evdata.type = TWIS_EVT_READ_REQ;
+ if (nrf_drv_twis_check_bit(ev, NRF_TWIS_EVENT_TXSTARTED))
+ {
+ substate = NRF_DRV_TWIS_SUBSTATE_READ_PENDING;
+ evdata.data.buf_req = false;
+ }
+ else
+ {
+ substate = NRF_DRV_TWIS_SUBSTATE_READ_WAITING;
+ evdata.data.buf_req = true;
+ }
+ nrf_drv_call_event_handler(instNr, &evdata);
+ ev = nrf_drv_twis_clear_bit(ev, NRF_TWIS_EVENT_READ);
+ ev = nrf_drv_twis_clear_bit(ev, NRF_TWIS_EVENT_TXSTARTED);
+ ev = nrf_drv_twis_clear_bit(ev, NRF_TWIS_EVENT_WRITE);
+ ev = nrf_drv_twis_clear_bit(ev, NRF_TWIS_EVENT_RXSTARTED);
+ }
+ else if (nrf_drv_twis_check_bit(ev, NRF_TWIS_EVENT_WRITE))
+ {
+ evdata.type = TWIS_EVT_WRITE_REQ;
+ if (nrf_drv_twis_check_bit(ev, NRF_TWIS_EVENT_RXSTARTED))
+ {
+ substate = NRF_DRV_TWIS_SUBSTATE_WRITE_PENDING;
+ evdata.data.buf_req = false;
+ }
+ else
+ {
+ substate = NRF_DRV_TWIS_SUBSTATE_WRITE_WAITING;
+ evdata.data.buf_req = true;
+ }
+ nrf_drv_call_event_handler(instNr, &evdata);
+ ev = nrf_drv_twis_clear_bit(ev, NRF_TWIS_EVENT_READ);
+ ev = nrf_drv_twis_clear_bit(ev, NRF_TWIS_EVENT_TXSTARTED);
+ ev = nrf_drv_twis_clear_bit(ev, NRF_TWIS_EVENT_WRITE);
+ ev = nrf_drv_twis_clear_bit(ev, NRF_TWIS_EVENT_RXSTARTED);
+ }
+ else
+ {
+ nrf_drv_twis_process_error(instNr, TWIS_EVT_GENERAL_ERROR, nrf_twis_error_source_get_and_clear(p_reg));
+ ev = 0;
+ }
+ break;
+ case NRF_DRV_TWIS_SUBSTATE_READ_WAITING:
+ if (nrf_drv_twis_check_bit(ev, NRF_TWIS_EVENT_TXSTARTED) ||
+ nrf_drv_twis_check_bit(ev, NRF_TWIS_EVENT_WRITE) ||
+ nrf_drv_twis_check_bit(ev, NRF_TWIS_EVENT_READ) ||
+ nrf_drv_twis_check_bit(ev, NRF_TWIS_EVENT_STOPPED))
+ {
+ substate = NRF_DRV_TWIS_SUBSTATE_READ_PENDING;
+ /* Any other bits requires further processing in PENDING substate */
+ ev = nrf_drv_twis_clear_bit(ev, NRF_TWIS_EVENT_TXSTARTED);
+ }
+ else
+ {
+ nrf_drv_twis_process_error(instNr, TWIS_EVT_READ_ERROR, nrf_twis_error_source_get_and_clear(p_reg));
+ substate = NRF_DRV_TWIS_SUBSTATE_IDLE;
+ ev = 0;
+ }
+ break;
+ case NRF_DRV_TWIS_SUBSTATE_READ_PENDING:
+ if (nrf_drv_twis_check_bit(ev, NRF_TWIS_EVENT_WRITE)||
+ nrf_drv_twis_check_bit(ev, NRF_TWIS_EVENT_READ) ||
+ nrf_drv_twis_check_bit(ev, NRF_TWIS_EVENT_STOPPED))
+ {
+ evdata.type = TWIS_EVT_READ_DONE;
+ evdata.data.tx_amount = nrf_twis_tx_amount_get(p_reg);
+ NRF_LOG_INFO("Transfer rx_len:%d\r\n", evdata.data.tx_amount);
+ NRF_LOG_DEBUG("Tx data:\r\n");
+ NRF_LOG_HEXDUMP_DEBUG((uint8_t *)p_reg->TXD.PTR, evdata.data.tx_amount * sizeof(p_reg->TXD.PTR));
+ nrf_drv_call_event_handler(instNr, &evdata);
+ /* Go to idle and repeat the state machine if READ or WRITE events detected.
+ * This time READ or WRITE would be started */
+ substate = NRF_DRV_TWIS_SUBSTATE_IDLE;
+ ev = nrf_drv_twis_clear_bit(ev, NRF_TWIS_EVENT_STOPPED);
+ }
+ else
+ {
+ nrf_drv_twis_process_error(instNr, TWIS_EVT_READ_ERROR, nrf_twis_error_source_get_and_clear(p_reg));
+ substate = NRF_DRV_TWIS_SUBSTATE_IDLE;
+ ev = 0;
+ }
+ break;
+ case NRF_DRV_TWIS_SUBSTATE_WRITE_WAITING:
+ if (nrf_drv_twis_check_bit(ev, NRF_TWIS_EVENT_RXSTARTED) ||
+ nrf_drv_twis_check_bit(ev, NRF_TWIS_EVENT_WRITE) ||
+ nrf_drv_twis_check_bit(ev, NRF_TWIS_EVENT_READ) ||
+ nrf_drv_twis_check_bit(ev, NRF_TWIS_EVENT_STOPPED))
+ {
+ substate = NRF_DRV_TWIS_SUBSTATE_WRITE_PENDING;
+ /* Any other bits requires further processing in PENDING substate */
+ ev = nrf_drv_twis_clear_bit(ev, NRF_TWIS_EVENT_RXSTARTED);
+ }
+ else
+ {
+ nrf_drv_twis_process_error(instNr, TWIS_EVT_WRITE_ERROR, nrf_twis_error_source_get_and_clear(p_reg));
+ substate = NRF_DRV_TWIS_SUBSTATE_IDLE;
+ ev = 0;
+ }
+ break;
+ case NRF_DRV_TWIS_SUBSTATE_WRITE_PENDING:
+ if (nrf_drv_twis_check_bit(ev, NRF_TWIS_EVENT_WRITE)||
+ nrf_drv_twis_check_bit(ev, NRF_TWIS_EVENT_READ) ||
+ nrf_drv_twis_check_bit(ev, NRF_TWIS_EVENT_STOPPED))
+ {
+ evdata.type = TWIS_EVT_WRITE_DONE;
+ evdata.data.rx_amount = nrf_twis_rx_amount_get(p_reg);
+ nrf_drv_call_event_handler(instNr, &evdata);
+ /* Go to idle and repeat the state machine if READ or WRITE events detected.
+ * This time READ or WRITE would be started */
+ substate = NRF_DRV_TWIS_SUBSTATE_IDLE;
+ ev = nrf_drv_twis_clear_bit(ev, NRF_TWIS_EVENT_STOPPED);
+ }
+ else
+ {
+ nrf_drv_twis_process_error(instNr, TWIS_EVT_WRITE_ERROR, nrf_twis_error_source_get_and_clear(p_reg));
+ substate = NRF_DRV_TWIS_SUBSTATE_IDLE;
+ ev = 0;
+ }
+ break;
+ default:
+ substate = NRF_DRV_TWIS_SUBSTATE_IDLE;
+ /* Do not clear any events and repeat the machine */
+ break;
+ }
+ }
+
+ m_var_inst[instNr].substate = substate;
+ if (!TWIS_NO_SYNC_MODE)
+ {
+ m_sm_semaphore[instNr] = 0;
+ }
+}
+
+/**
+ * @brief This function
+ */
+static inline void nrf_drv_twis_preprocess_status(uint8_t instNr)
+{
+ if (!TWIS_NO_SYNC_MODE)
+ {
+ if (NULL == m_var_inst[instNr].ev_handler)
+ {
+ nrf_drv_twis_state_machine(instNr);
+ }
+ }
+}
+
+/**
+ * @brief Interrupt service
+ *
+ * This function is called by all interrupts runtime for instances enabled in this library.
+ * @param instNr Driver instance number that has called this runtime.
+ */
+static inline void nrf_drv_twis_on_ISR(uint8_t instNr)
+{
+ nrf_drv_twis_state_machine(instNr);
+}
+
+/** @} */ /* End of lib_driver_twis_slave_ifunc */
+
+
+/* -------------------------------------------------------------------------
+ * Implementation of IRQ Handlers
+ */
+#define X(n) \
+ IRQ_HANDLER(n) \
+ { \
+ nrf_drv_twis_on_ISR(TWIS##n##_INSTANCE_INDEX); \
+ }
+#include "nrf_drv_twis_inst.def"
+
+/* -------------------------------------------------------------------------
+ * Implementation of interface functions
+ *
+ */
+
+
+ret_code_t nrf_drv_twis_init(
+ nrf_drv_twis_t const * const p_instance,
+ nrf_drv_twis_config_t const * p_config,
+ nrf_drv_twis_event_handler_t const event_handler)
+{
+ ASSERT(p_config);
+ ASSERT(p_config->scl != p_config->sda);
+ uint8_t instNr = p_instance->instNr;
+ NRF_TWIS_Type * const p_reg = m_const_inst[instNr].p_reg;
+ nrf_twis_config_addr_mask_t addr_mask = (nrf_twis_config_addr_mask_t)0;
+ ret_code_t err_code;
+
+ if ( m_var_inst[instNr].state != NRF_DRV_STATE_UNINITIALIZED)
+ {
+ err_code = NRF_ERROR_INVALID_STATE;
+ NRF_LOG_WARNING("Function: %s, error code: %s.\r\n", (uint32_t)__func__, (uint32_t)NRF_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+ }
+
+#if NRF_MODULE_ENABLED(PERIPHERAL_RESOURCE_SHARING)
+ if (nrf_drv_common_per_res_acquire(p_reg, m_irq_handlers[instNr]) !=
+ NRF_SUCCESS)
+ {
+ err_code = NRF_ERROR_BUSY;
+ NRF_LOG_WARNING("Function: %s, error code: %s.\r\n", (uint32_t)__func__, (uint32_t)NRF_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+ }
+#endif
+
+ if (!TWIS_ASSUME_INIT_AFTER_RESET_ONLY)
+ {
+ nrf_drv_twis_swreset(p_reg);
+ }
+
+ nrf_drv_twis_config_pin(p_config->scl, p_config->scl_pull);
+ nrf_drv_twis_config_pin(p_config->sda, p_config->sda_pull);
+
+ 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) */
+ nrf_drv_common_irq_enable(nrf_drv_get_IRQn(p_reg), p_config->interrupt_priority);
+
+ /* 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 (!TWIS_NO_SYNC_MODE)
+ {
+ m_sm_semaphore[instNr] = 0;
+ }
+ /* Set internal instance variables */
+ m_var_inst[instNr].substate = NRF_DRV_TWIS_SUBSTATE_IDLE;
+ m_var_inst[instNr].ev_handler = event_handler;
+ m_var_inst[instNr].state = NRF_DRV_STATE_INITIALIZED;
+ err_code = NRF_SUCCESS;
+ NRF_LOG_INFO("Function: %s, error code: %s.\r\n", (uint32_t)__func__, (uint32_t)NRF_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+}
+
+
+void nrf_drv_twis_uninit(nrf_drv_twis_t const * const p_instance)
+{
+ uint8_t instNr = p_instance->instNr;
+ NRF_TWIS_Type * const p_reg = m_const_inst[instNr].p_reg;
+ TWIS_PSEL_Type psel = p_reg->PSEL;
+
+ ASSERT(m_var_inst[instNr].state != NRF_DRV_STATE_UNINITIALIZED);
+
+ nrf_drv_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 NRF_MODULE_ENABLED(PERIPHERAL_RESOURCE_SHARING)
+ nrf_drv_common_per_res_release(p_reg);
+#endif
+
+ /* Clear variables */
+ m_var_inst[instNr].ev_handler = NULL;
+ m_var_inst[instNr].state = NRF_DRV_STATE_UNINITIALIZED;
+}
+
+
+void nrf_drv_twis_enable(nrf_drv_twis_t const * const p_instance)
+{
+ uint8_t instNr = p_instance->instNr;
+ NRF_TWIS_Type * const p_reg = m_const_inst[instNr].p_reg;
+ nrf_drv_twis_var_inst_t * const p_var_inst = &m_var_inst[instNr];
+
+ ASSERT(m_var_inst[instNr].state == NRF_DRV_STATE_INITIALIZED);
+
+ nrf_drv_twis_clear_all_events(p_reg);
+
+ /* Enable interrupts */
+ if (NULL != p_var_inst->ev_handler)
+ {
+ nrf_twis_int_enable(p_reg, m_used_ints_mask);
+ }
+
+ nrf_twis_enable(p_reg);
+ p_var_inst->error = 0;
+ p_var_inst->state = NRF_DRV_STATE_POWERED_ON;
+ p_var_inst->substate = NRF_DRV_TWIS_SUBSTATE_IDLE;
+}
+
+
+void nrf_drv_twis_disable(nrf_drv_twis_t const * const p_instance)
+{
+ uint8_t instNr = p_instance->instNr;
+ NRF_TWIS_Type * const p_reg = m_const_inst[instNr].p_reg;
+
+ ASSERT(m_var_inst[instNr].state != NRF_DRV_STATE_UNINITIALIZED);
+
+ nrf_twis_int_disable(p_reg, m_used_ints_mask);
+
+ nrf_twis_disable(p_reg);
+ m_var_inst[instNr].state = NRF_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 nrf_drv_twis_error_get_and_clear_internal(uint32_t volatile * const perror)
+{
+ mov r3, r0
+ mov r1, #0
+nrf_drv_twis_error_get_and_clear_internal_try
+ ldrex r0, [r3]
+ strex r2, r1, [r3]
+ cmp r2, r1 /* did this succeed? */
+ bne nrf_drv_twis_error_get_and_clear_internal_try /* no – try again */
+ bx lr
+}
+#elif defined ( __GNUC__ )
+static uint32_t nrf_drv_twis_error_get_and_clear_internal(uint32_t volatile * const perror)
+{
+ uint32_t ret;
+ uint32_t temp;
+ __ASM volatile(
+ " .syntax unified \n"
+ "nrf_drv_twis_error_get_and_clear_internal_try: \n"
+ " ldrex %[ret], [%[perror]] \n"
+ " strex %[temp], %[zero], [%[perror]] \n"
+ " cmp %[temp], %[zero] \n"
+ " bne nrf_drv_twis_error_get_and_clear_internal_try \n"
+ : /* Output */
+ [ret]"=&l"(ret),
+ [temp]"=&l"(temp)
+ : /* Input */
+ [zero]"l"(0),
+ [perror]"l"(perror)
+ );
+ UNUSED_VARIABLE(temp);
+ return ret;
+}
+#elif defined ( __ICCARM__ )
+static uint32_t nrf_drv_twis_error_get_and_clear_internal(uint32_t volatile * const 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)
+ );
+ UNUSED_VARIABLE(temp);
+ return ret;
+}
+#else
+ #error Unknown compiler
+#endif
+//lint -restore
+
+uint32_t nrf_drv_twis_error_get_and_clear(nrf_drv_twis_t const * const p_instance)
+{
+ nrf_drv_twis_var_inst_t * const p_var_inst = &m_var_inst[p_instance->instNr];
+ nrf_drv_twis_preprocess_status(p_instance->instNr);
+ /* 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. */
+ return nrf_drv_twis_error_get_and_clear_internal(&p_var_inst->error);
+}
+
+
+ret_code_t nrf_drv_twis_tx_prepare(
+ nrf_drv_twis_t const * const p_instance,
+ void const * const p_buf,
+ size_t size)
+{
+ ret_code_t err_code = NRF_SUCCESS;
+ uint8_t instNr = p_instance->instNr;
+ NRF_TWIS_Type * const p_reg = m_const_inst[instNr].p_reg;
+ nrf_drv_twis_var_inst_t * const p_var_inst = &m_var_inst[instNr];
+
+ /* Check power state*/
+ if (p_var_inst->state != NRF_DRV_STATE_POWERED_ON)
+ {
+ err_code = NRF_ERROR_INVALID_STATE;
+ NRF_LOG_WARNING("Function: %s, error code: %s.\r\n", (uint32_t)__func__, (uint32_t)NRF_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+ }
+ /* Check data address */
+ if (!nrf_drv_is_in_RAM(p_buf))
+ {
+ err_code = NRF_ERROR_INVALID_ADDR;
+ NRF_LOG_WARNING("Function: %s, error code: %s.\r\n", (uint32_t)__func__, (uint32_t)NRF_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+ }
+ /* Check data size */
+ if ((size & TWIS_TXD_MAXCNT_MAXCNT_Msk) != size)
+ {
+ err_code = NRF_ERROR_INVALID_LENGTH;
+ NRF_LOG_WARNING("Function: %s, error code: %s.\r\n", (uint32_t)__func__, (uint32_t)NRF_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+ }
+
+ nrf_twis_tx_prepare(p_reg, (uint8_t const *)p_buf, (nrf_twis_amount_t)size);
+ NRF_LOG_INFO("Function: %s, error code: %s.\r\n", (uint32_t)__func__, (uint32_t)NRF_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+
+}
+
+
+size_t nrf_drv_twis_tx_amount(nrf_drv_twis_t const * const p_instance)
+{
+ uint8_t instNr = p_instance->instNr;
+ NRF_TWIS_Type const * const p_reg = m_const_inst[instNr].p_reg;
+
+ return nrf_twis_tx_amount_get(p_reg);
+}
+
+
+ret_code_t nrf_drv_twis_rx_prepare(
+ nrf_drv_twis_t const * const p_instance,
+ void * const p_buf,
+ size_t size)
+{
+ ret_code_t err_code;
+ uint8_t instNr = p_instance->instNr;
+ NRF_TWIS_Type * const p_reg = m_const_inst[instNr].p_reg;
+ nrf_drv_twis_var_inst_t * const p_var_inst = &m_var_inst[instNr];
+
+ /* Check power state*/
+ if (p_var_inst->state != NRF_DRV_STATE_POWERED_ON)
+ {
+ err_code = NRF_ERROR_INVALID_STATE;
+ NRF_LOG_WARNING("Function: %s, error code: %s.\r\n", (uint32_t)__func__, (uint32_t)NRF_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+ }
+ /* Check data address */
+ if (!nrf_drv_is_in_RAM(p_buf))
+ {
+ err_code = NRF_ERROR_INVALID_ADDR;
+ NRF_LOG_WARNING("Function: %s, error code: %s.\r\n", (uint32_t)__func__, (uint32_t)NRF_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+ }
+ /* Check data size */
+ if ((size & TWIS_RXD_MAXCNT_MAXCNT_Msk) != size)
+ {
+ err_code = NRF_ERROR_INVALID_LENGTH;
+ NRF_LOG_WARNING("Function: %s, error code: %s.\r\n", (uint32_t)__func__, (uint32_t)NRF_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+ }
+
+ nrf_twis_rx_prepare(p_reg, (uint8_t *)p_buf, (nrf_twis_amount_t)size);
+ err_code = NRF_SUCCESS;
+ NRF_LOG_INFO("Function: %s, error code: %s.\r\n", (uint32_t)__func__, (uint32_t)NRF_LOG_ERROR_STRING_GET(err_code));
+ return err_code;
+}
+
+
+size_t nrf_drv_twis_rx_amount(nrf_drv_twis_t const * const p_instance)
+{
+ uint8_t instNr = p_instance->instNr;
+ NRF_TWIS_Type const * const p_reg = m_const_inst[instNr].p_reg;
+
+ return nrf_twis_rx_amount_get(p_reg);
+}
+
+
+bool nrf_drv_twis_is_busy(nrf_drv_twis_t const * const p_instance)
+{
+ nrf_drv_twis_preprocess_status(p_instance->instNr);
+ return NRF_DRV_TWIS_SUBSTATE_IDLE != m_var_inst[(p_instance->instNr)].substate;
+}
+
+bool nrf_drv_twis_is_waiting_tx_buff(nrf_drv_twis_t const * const p_instance)
+{
+ nrf_drv_twis_preprocess_status(p_instance->instNr);
+ return NRF_DRV_TWIS_SUBSTATE_READ_WAITING == m_var_inst[(p_instance->instNr)].substate;
+}
+
+bool nrf_drv_twis_is_waiting_rx_buff(nrf_drv_twis_t const * const p_instance)
+{
+ nrf_drv_twis_preprocess_status(p_instance->instNr);
+ return NRF_DRV_TWIS_SUBSTATE_WRITE_WAITING == m_var_inst[(p_instance->instNr)].substate;
+}
+
+bool nrf_drv_twis_is_pending_tx(nrf_drv_twis_t const * const p_instance)
+{
+ nrf_drv_twis_preprocess_status(p_instance->instNr);
+ return NRF_DRV_TWIS_SUBSTATE_READ_PENDING == m_var_inst[(p_instance->instNr)].substate;
+}
+
+bool nrf_drv_twis_is_pending_rx(nrf_drv_twis_t const * const p_instance)
+{
+ nrf_drv_twis_preprocess_status(p_instance->instNr);
+ return NRF_DRV_TWIS_SUBSTATE_WRITE_PENDING == m_var_inst[(p_instance->instNr)].substate;
+}
+#endif // TWIS_COUNT
+#endif // NRF_MODULE_ENABLED(TWIS)
diff --git a/drivers_nrf/twis_slave/nrf_drv_twis.h b/drivers_nrf/twis_slave/nrf_drv_twis.h
new file mode 100644
index 0000000..9989bfb
--- /dev/null
+++ b/drivers_nrf/twis_slave/nrf_drv_twis.h
@@ -0,0 +1,396 @@
+/**
+ * Copyright (c) 2015 - 2017, 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.
+ *
+ */
+#ifndef NRF_DRV_TWIS_H__
+#define NRF_DRV_TWIS_H__
+
+#include "sdk_config.h"
+#include "nrf_drv_common.h"
+#include "nrf_gpio.h"
+#include "sdk_errors.h"
+#include "nrf_twis.h"
+#include <stdint.h>
+#include "app_util.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**@file
+ * @addtogroup nrf_twis Two Wire slave interface (TWIS)
+ * @ingroup nrf_drivers
+ * @brief Two Wire slave interface (TWIS) APIs.
+ *
+ *
+ * @defgroup nrf_drv_twis TWIS driver
+ * @{
+ * @ingroup nrf_twis
+ * @brief TWI slave APIs.
+ */
+
+/**
+ * @brief Event callback function event definitions.
+ */
+typedef enum
+{
+ TWIS_EVT_READ_REQ, ///< Read request detected
+ /**< If there is no buffer prepared, buf_req flag in the even will be set.
+ Call then @ref nrf_drv_twis_tx_prepare to give parameters for buffer.
+ */
+ TWIS_EVT_READ_DONE, ///< Read request has finished - free any data
+ TWIS_EVT_READ_ERROR, ///< Read request finished with error
+ TWIS_EVT_WRITE_REQ, ///< Write request detected
+ /**< If there is no buffer prepared, buf_req flag in the even will be set.
+ Call then @ref nrf_drv_twis_rx_prepare to give parameters for buffer.
+ */
+ TWIS_EVT_WRITE_DONE, ///< Write request has finished - process data
+ TWIS_EVT_WRITE_ERROR, ///< Write request finished with error
+ TWIS_EVT_GENERAL_ERROR ///< Error that happens not inside WRITE or READ transaction
+} nrf_drv_twis_evt_type_t;
+
+/**
+ * @brief TWIS driver instance structure
+ *
+ * @note We only need instance number here so we could really use just a number
+ * that would be send to every driver function.
+ * But for compatibility reason this number is inserted into the structure.
+ */
+typedef struct
+{
+ uint8_t instNr; /**< Instance number */
+}nrf_drv_twis_t;
+
+/**
+ * @brief TWIS driver event structure
+ */
+typedef struct
+{
+ nrf_drv_twis_evt_type_t type; ///< Event type
+ union
+ {
+ bool buf_req; ///< Flag for @ref TWIS_EVT_READ_REQ and @ref TWIS_EVT_WRITE_REQ
+ /**< Information if transmission buffer requires to be prepared */
+ uint32_t tx_amount; ///< Data for @ref TWIS_EVT_READ_DONE
+ uint32_t rx_amount; ///< Data for @ref TWIS_EVT_WRITE_DONE
+ uint32_t error; ///< Data for @ref TWIS_EVT_GENERAL_ERROR
+ }data;
+}nrf_drv_twis_evt_t;
+
+/**
+ * @brief TWI slave event callback function type.
+ *
+ * @param[in] p_event Event information structure.
+ */
+typedef void (*nrf_drv_twis_event_handler_t)(nrf_drv_twis_evt_t const * const p_event);
+
+/**
+ * @brief Structure for TWIS configuration
+ */
+typedef struct
+{
+ uint32_t addr[2]; //!< Set addresses that this slave should respond. Set 0 to disable.
+ uint32_t scl; //!< SCL pin number
+ nrf_gpio_pin_pull_t scl_pull; //!< SCL pin pull
+ uint32_t sda; //!< SDA pin number
+ nrf_gpio_pin_pull_t sda_pull; //!< SDA pin pull
+ uint8_t interrupt_priority; //!< The priority of interrupt for the module to set
+}nrf_drv_twis_config_t;
+
+/**
+ * @brief Possible error sources
+ *
+ * This is flag enum - values from this enum can be connected using logical or operator.
+ * @note
+ * We could use directly @ref nrf_twis_error_t. Error type enum is redefined here becouse
+ * of possible future extension (eg. supporting timeouts and synchronous mode).
+ */
+typedef enum
+{
+ NRF_DRV_TWIS_ERROR_OVERFLOW = NRF_TWIS_ERROR_OVERFLOW, /**< RX buffer overflow detected, and prevented */
+ NRF_DRV_TWIS_ERROR_DATA_NACK = NRF_TWIS_ERROR_DATA_NACK, /**< NACK sent after receiving a data byte */
+ NRF_DRV_TWIS_ERROR_OVERREAD = NRF_TWIS_ERROR_OVERREAD, /**< TX buffer over-read detected, and prevented */
+ NRF_DRV_TWIS_ERROR_UNEXPECTED_EVENT = 1 << 8 /**< Unexpected event detected by state machine */
+}nrf_drv_twis_error_t;
+
+/**
+ * @internal
+ * @brief Internal macro for creating TWIS driver instance
+ *
+ * Second level of indirection in creating the instance.
+ * Do not use this macro directly.
+ * Use @ref NRF_DRV_TWIS_INSTANCE instead.
+ */
+#define NRF_DRV_TWIS_INSTANCE_x(id) \
+ { \
+ TWIS##id##_INSTANCE_INDEX \
+ }
+
+/**
+ * @brief Macro for creating TWIS driver instance
+ *
+ * @param[in] id Instance index. Use 0 for TWIS0 and 1 for TWIS1
+ */
+#define NRF_DRV_TWIS_INSTANCE(id) NRF_DRV_TWIS_INSTANCE_x(id)
+
+#define TWIS0_INSTANCE_INDEX 0
+#define TWIS1_INSTANCE_INDEX TWIS0_INSTANCE_INDEX+TWIS0_ENABLED
+
+/**
+ * @brief Generate default configuration for TWIS driver instance
+ */
+#define NRF_DRV_TWIS_DEFAULT_CONFIG \
+{ \
+ .addr = { TWIS_DEFAULT_CONFIG_ADDR0, TWIS_DEFAULT_CONFIG_ADDR1 }, \
+ .scl = 31, \
+ .scl_pull = (nrf_gpio_pin_pull_t)TWIS_DEFAULT_CONFIG_SCL_PULL, \
+ .sda = 31, \
+ .sda_pull = (nrf_gpio_pin_pull_t)TWIS_DEFAULT_CONFIG_SDA_PULL, \
+ .interrupt_priority = TWIS_DEFAULT_CONFIG_IRQ_PRIORITY \
+}
+
+/**
+ * @brief Function for initializing the TWIS driver instance.
+ *
+ * Function initializes and enables TWIS driver.
+ * @attention After driver initialization enable it by @ref nrf_drv_twis_enable
+ *
+ * @param[in] p_instance Pointer to the driver instance structure.
+ * @attention @em p_instance has to be global object.
+ * It would be used by interrupts so make it sure that object
+ * would not be destroyed when function is leaving.
+ * @param[in] p_config Initial configuration.
+ * @param[in] event_handler Event handler provided by the user.
+ *
+ * @retval NRF_SUCCESS If initialization was successful.
+ * @retval NRF_ERROR_INVALID_STATE If the driver is already initialized.
+ * @retval NRF_ERROR_BUSY If some other peripheral with the same
+ * instance ID is already in use. This is
+ * possible only if PERIPHERAL_RESOURCE_SHARING_ENABLED
+ * is set to a value other than zero.
+ */
+ret_code_t nrf_drv_twis_init(
+ nrf_drv_twis_t const * const p_instance,
+ nrf_drv_twis_config_t const * p_config,
+ nrf_drv_twis_event_handler_t const event_handler);
+
+/**
+ * @brief Function for uninitializing the TWIS driver instance.
+ *
+ * Function initializes the peripheral and resets all registers to default values.
+ *
+ * @param[in] p_instance Pointer to the driver instance structure.
+ * @note
+ * It is safe to call nrf_drv_twis_uninit even before initialization.
+ * Actually @ref nrf_drv_twis_init function calls this function to
+ * make sure that TWIS state is known.
+ * @note
+ * If TWIS driver was in uninitialized state before calling this function,
+ * selected pins would not be reset to default configuration.
+ */
+void nrf_drv_twis_uninit(nrf_drv_twis_t const * const p_instance);
+
+/**
+ * @brief Enable TWIS instance
+ *
+ * This function enables TWIS instance.
+ * Function defined if there is needs for dynamically enabling and disabling the peripheral.
+ * Use @ref nrf_drv_twis_enable and @ref nrf_drv_twis_disable functions.
+ * They do not change any configuration registers.
+ *
+ * @param p_instance Pointer to the driver instance structure.
+ */
+void nrf_drv_twis_enable(nrf_drv_twis_t const * const p_instance);
+
+/**
+ * @brief Disable TWIS instance
+ *
+ * Disabling TWIS instance gives possibility to turn off the TWIS while
+ * holding configuration done by @ref nrf_drv_twis_init
+ *
+ * @param p_instance Pointer to the driver instance structure.
+ */
+void nrf_drv_twis_disable(nrf_drv_twis_t const * const p_instance);
+
+/**
+ * @brief Get and clear last error flags
+ *
+ * Function gets information about errors.
+ * This is also the only possibility to exit from error substate of the internal state machine.
+ *
+ * @param[in] p_instance Pointer to the driver instance structure.
+ * @return Error flags defined in @ref nrf_drv_twis_error_t
+ * @attention
+ * This function clears error state and flags.
+ */
+uint32_t nrf_drv_twis_error_get_and_clear(nrf_drv_twis_t const * const p_instance);
+
+
+/**
+ * @brief Prepare data for sending
+ *
+ * This function should be used in response for @ref TWIS_EVT_READ_REQ event.
+ *
+ * @param[in] p_instance Pointer to the driver instance structure.
+ * @param[in] p_buf Transmission buffer
+ * @attention Transmission buffer has to be placed in RAM.
+ * @param size Maximum number of bytes that master may read from buffer given.
+ *
+ * @retval NRF_SUCCESS Preparation finished properly
+ * @retval NRF_ERROR_INVALID_ADDR Given @em p_buf is not placed inside the RAM
+ * @retval NRF_ERROR_INVALID_LENGTH Wrong value in @em size parameter
+ * @retval NRF_ERROR_INVALID_STATE Module not initialized or not enabled
+ */
+ret_code_t nrf_drv_twis_tx_prepare(
+ nrf_drv_twis_t const * const p_instance,
+ void const * const p_buf,
+ size_t size);
+
+/**
+ * @brief Get number of transmitted bytes
+ *
+ * Function returns number of bytes sent.
+ * This function may be called after @ref TWIS_EVT_READ_DONE or @ref TWIS_EVT_READ_ERROR events.
+ *
+ * @param[in] p_instance Pointer to the driver instance structure.
+ *
+ * @return Number of bytes sent.
+ */
+size_t nrf_drv_twis_tx_amount(nrf_drv_twis_t const * const p_instance);
+
+/**
+ * @brief Prepare data for receiving
+ *
+ * This function should be used in response for @ref TWIS_EVT_WRITE_REQ event.
+ *
+ * @param[in] p_instance Pointer to the driver instance structure.
+ * @param[in] p_buf Buffer that would be filled with received data
+ * @attention Receiving buffer has to be placed in RAM.
+ * @param size Size of the buffer (maximum amount of data to receive)
+ *
+ * @retval NRF_SUCCESS Preparation finished properly
+ * @retval NRF_ERROR_INVALID_ADDR Given @em p_buf is not placed inside the RAM
+ * @retval NRF_ERROR_INVALID_LENGTH Wrong value in @em size parameter
+ * @retval NRF_ERROR_INVALID_STATE Module not initialized or not enabled
+ */
+ret_code_t nrf_drv_twis_rx_prepare(
+ nrf_drv_twis_t const * const p_instance,
+ void * const p_buf,
+ size_t size);
+
+/**
+ * @brief Get number of received bytes
+ *
+ * Function returns number of bytes received.
+ * This function may be called after @ref TWIS_EVT_WRITE_DONE or @ref TWIS_EVT_WRITE_ERROR events.
+ *
+ * @param[in] p_instance Pointer to the driver instance structure.
+ *
+ * @return Number of bytes received.
+ */
+size_t nrf_drv_twis_rx_amount(nrf_drv_twis_t const * const p_instance);
+
+/**
+ * @brief Function checks if driver is busy right now
+ *
+ * Actual driver substate is tested.
+ * If driver is in any other state than IDLE or ERROR this function returns true.
+ *
+ * @param[in] p_instance Pointer to the driver instance structure.
+ *
+ * @retval true Driver is in state other than ERROR or IDLE
+ * @retval false There is no transmission pending.
+ */
+bool nrf_drv_twis_is_busy(nrf_drv_twis_t const * const p_instance);
+
+/**
+ * @brief Function checks if driver is waiting for tx buffer
+ *
+ * If this function returns true, it means that driver is stalled expecting
+ * of the @ref nrf_drv_twis_tx_prepare function call.
+ *
+ * @param[in] p_instance Pointer to the driver instance structure.
+ *
+ * @retval true Driver waits for @ref nrf_drv_twis_tx_prepare
+ * @retval false Driver is not in the state where it waits for preparing tx buffer.
+ */
+bool nrf_drv_twis_is_waiting_tx_buff(nrf_drv_twis_t const * const p_instance);
+
+/**
+ * @brief Function checks if driver is waiting for rx buffer
+ *
+ * If this function returns true, it means that driver is staled expecting
+ * of the @ref nrf_drv_twis_rx_prepare function call.
+ *
+ * @param[in] p_instance Pointer to the driver instance structure.
+ *
+ * @retval true Driver waits for @ref nrf_drv_twis_rx_prepare
+ * @retval false Driver is not in the state where it waits for preparing rx buffer.
+ */
+bool nrf_drv_twis_is_waiting_rx_buff(nrf_drv_twis_t const * const p_instance);
+
+/**
+ * @brief Check if driver is sending data
+ *
+ * If this function returns true, it means that there is ongoing output transmission.
+ *
+ * @param[in] p_instance Pointer to the driver instance structure.
+ *
+ * @retval true There is ongoing output transmission.
+ * @retval false Driver is in other state.
+ */
+bool nrf_drv_twis_is_pending_tx(nrf_drv_twis_t const * const p_instance);
+
+/**
+ * @brief Check if driver is receiving data
+ *
+ * If this function returns true, it means that there is ongoing input transmission.
+ *
+ * @param[in] p_instance Pointer to the driver instance structure.
+ *
+ * @retval true There is ongoing input transmission.
+ * @retval false Driver is in other state.
+ */
+bool nrf_drv_twis_is_pending_rx(nrf_drv_twis_t const * const p_instance);
+
+/** @} */ /* End of lib_twis_drv group */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NRF_DRV_TWIS_H__ */
diff --git a/drivers_nrf/twis_slave/nrf_drv_twis_inst.def b/drivers_nrf/twis_slave/nrf_drv_twis_inst.def
new file mode 100644
index 0000000..be40002
--- /dev/null
+++ b/drivers_nrf/twis_slave/nrf_drv_twis_inst.def
@@ -0,0 +1,20 @@
+/**
+ * @file
+ * @brief Xmacro file with contains enumeration of TWIS instances to implement
+ *
+ * Use this file everywhere where anything has to be generated for all active TWIS instances.
+ * Xmacro format:
+ *
+ * @code
+ X(n)
+ * @endcode
+ *
+ * Where @em n is number of the instance itself (0 for NRF_TWIS0).
+ */
+#if (TWIS0_ENABLED == 1)
+ X(0)
+#endif
+#if (TWIS1_ENABLED == 1)
+ X(1)
+#endif
+#undef X