diff options
author | tcsullivan <tullivan99@gmail.com> | 2019-03-10 15:37:07 -0400 |
---|---|---|
committer | tcsullivan <tullivan99@gmail.com> | 2019-03-10 15:37:07 -0400 |
commit | dd33956654589ded6644a75088e50069b1744ef9 (patch) | |
tree | eddd51f1aac130f6c7082a2de53b8e46f0387187 /drivers_nrf/twis_slave | |
parent | 3c3f87b4cab153b49e3cde105dd2f34712e0b790 (diff) |
rtc, keeping time
Diffstat (limited to 'drivers_nrf/twis_slave')
-rw-r--r-- | drivers_nrf/twis_slave/nrf_drv_twis.c | 942 | ||||
-rw-r--r-- | drivers_nrf/twis_slave/nrf_drv_twis.h | 396 | ||||
-rw-r--r-- | drivers_nrf/twis_slave/nrf_drv_twis_inst.def | 20 |
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 |