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