diff options
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src')
30 files changed, 12207 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_adc.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_adc.c new file mode 100644 index 0000000..cbe51fa --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_adc.c @@ -0,0 +1,324 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_ADC_ENABLED) + +#include <nrfx_adc.h> + +#define NRFX_LOG_MODULE ADC +#include <nrfx_log.h> + +#define EVT_TO_STR(event) (event == NRF_ADC_EVENT_END ? "NRF_ADC_EVENT_END" : "UNKNOWN EVENT") + +typedef struct +{ + nrfx_adc_event_handler_t event_handler; + nrfx_adc_channel_t * p_head; + nrfx_adc_channel_t * p_current_conv; + nrf_adc_value_t * p_buffer; + uint16_t size; + uint16_t idx; + nrfx_drv_state_t state; +} adc_cb_t; + +static adc_cb_t m_cb; + +nrfx_err_t nrfx_adc_init(nrfx_adc_config_t const * p_config, + nrfx_adc_event_handler_t event_handler) +{ + NRFX_ASSERT(p_config); + nrfx_err_t err_code; + + if (m_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; + } + + nrf_adc_event_clear(NRF_ADC_EVENT_END); + if (event_handler) + { + NRFX_IRQ_PRIORITY_SET(ADC_IRQn, p_config->interrupt_priority); + NRFX_IRQ_ENABLE(ADC_IRQn); + } + m_cb.event_handler = event_handler; + m_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_adc_uninit(void) +{ + m_cb.p_head = NULL; + NRFX_IRQ_DISABLE(ADC_IRQn); + nrf_adc_int_disable(NRF_ADC_INT_END_MASK); + nrf_adc_task_trigger(NRF_ADC_TASK_STOP); + + m_cb.state = NRFX_DRV_STATE_UNINITIALIZED; +} + +void nrfx_adc_channel_enable(nrfx_adc_channel_t * const p_channel) +{ + NRFX_ASSERT(!nrfx_adc_is_busy()); + + p_channel->p_next = NULL; + if (m_cb.p_head == NULL) + { + m_cb.p_head = p_channel; + } + else + { + nrfx_adc_channel_t * p_curr_channel = m_cb.p_head; + while (p_curr_channel->p_next != NULL) + { + NRFX_ASSERT(p_channel != p_curr_channel); + p_curr_channel = p_curr_channel->p_next; + } + p_curr_channel->p_next = p_channel; + } + + NRFX_LOG_INFO("Enabled."); +} + +void nrfx_adc_channel_disable(nrfx_adc_channel_t * const p_channel) +{ + NRFX_ASSERT(m_cb.p_head); + NRFX_ASSERT(!nrfx_adc_is_busy()); + + nrfx_adc_channel_t * p_curr_channel = m_cb.p_head; + nrfx_adc_channel_t * p_prev_channel = NULL; + while (p_curr_channel != p_channel) + { + p_prev_channel = p_curr_channel; + p_curr_channel = p_curr_channel->p_next; + NRFX_ASSERT(p_curr_channel != NULL); + } + if (p_prev_channel) + { + p_prev_channel->p_next = p_curr_channel->p_next; + } + else + { + m_cb.p_head = p_curr_channel->p_next; + } + + NRFX_LOG_INFO("Disabled."); +} + +void nrfx_adc_sample(void) +{ + NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); + NRFX_ASSERT(!nrf_adc_busy_check()); + nrf_adc_task_trigger(NRF_ADC_TASK_START); +} + +nrfx_err_t nrfx_adc_sample_convert(nrfx_adc_channel_t const * const p_channel, + nrf_adc_value_t * p_value) +{ + nrfx_err_t err_code; + + NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); + if (m_cb.state == NRFX_DRV_STATE_POWERED_ON) + { + err_code = NRFX_ERROR_BUSY; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + else + { + m_cb.state = NRFX_DRV_STATE_POWERED_ON; + + nrf_adc_init(&p_channel->config); + nrf_adc_enable(); + nrf_adc_int_disable(NRF_ADC_INT_END_MASK); + nrf_adc_task_trigger(NRF_ADC_TASK_START); + if (p_value) + { + while (!nrf_adc_event_check(NRF_ADC_EVENT_END)) {} + nrf_adc_event_clear(NRF_ADC_EVENT_END); + *p_value = (nrf_adc_value_t)nrf_adc_result_get(); + nrf_adc_disable(); + + m_cb.state = NRFX_DRV_STATE_INITIALIZED; + } + else + { + NRFX_ASSERT(m_cb.event_handler); + m_cb.p_buffer = NULL; + nrf_adc_int_enable(NRF_ADC_INT_END_MASK); + } + err_code = NRFX_SUCCESS; + NRFX_LOG_INFO("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } +} + +static bool adc_sample_process() +{ + nrf_adc_event_clear(NRF_ADC_EVENT_END); + nrf_adc_disable(); + m_cb.p_buffer[m_cb.idx] = (nrf_adc_value_t)nrf_adc_result_get(); + m_cb.idx++; + if (m_cb.idx < m_cb.size) + { + bool task_trigger = false; + if (m_cb.p_current_conv->p_next == NULL) + { + m_cb.p_current_conv = m_cb.p_head; + } + else + { + m_cb.p_current_conv = m_cb.p_current_conv->p_next; + task_trigger = true; + } + nrf_adc_init(&m_cb.p_current_conv->config); + nrf_adc_enable(); + if (task_trigger) + { + nrf_adc_task_trigger(NRF_ADC_TASK_START); + } + return false; + } + else + { + return true; + } +} + +nrfx_err_t nrfx_adc_buffer_convert(nrf_adc_value_t * buffer, uint16_t size) +{ + NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); + + nrfx_err_t err_code; + + NRFX_LOG_INFO("Number of samples requested to convert: %d.", size); + + if (m_cb.state == NRFX_DRV_STATE_POWERED_ON) + { + err_code = NRFX_ERROR_BUSY; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + else + { + m_cb.state = NRFX_DRV_STATE_POWERED_ON; + m_cb.p_current_conv = m_cb.p_head; + m_cb.size = size; + m_cb.idx = 0; + m_cb.p_buffer = buffer; + nrf_adc_init(&m_cb.p_current_conv->config); + nrf_adc_event_clear(NRF_ADC_EVENT_END); + nrf_adc_enable(); + if (m_cb.event_handler) + { + nrf_adc_int_enable(NRF_ADC_INT_END_MASK); + } + else + { + while (1) + { + while (!nrf_adc_event_check(NRF_ADC_EVENT_END)){} + + if (adc_sample_process()) + { + m_cb.state = NRFX_DRV_STATE_INITIALIZED; + break; + } + } + } + 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_adc_is_busy(void) +{ + NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); + return (m_cb.state == NRFX_DRV_STATE_POWERED_ON) ? true : false; +} + +void nrfx_adc_irq_handler(void) +{ + if (m_cb.p_buffer == NULL) + { + nrf_adc_event_clear(NRF_ADC_EVENT_END); + NRFX_LOG_DEBUG("Event: %s.",NRFX_LOG_ERROR_STRING_GET(NRF_ADC_EVENT_END)); + nrf_adc_int_disable(NRF_ADC_INT_END_MASK); + nrf_adc_disable(); + nrfx_adc_evt_t evt; + evt.type = NRFX_ADC_EVT_SAMPLE; + evt.data.sample.sample = (nrf_adc_value_t)nrf_adc_result_get(); + NRFX_LOG_DEBUG("ADC data:"); + NRFX_LOG_HEXDUMP_DEBUG((uint8_t *)(&evt.data.sample.sample), sizeof(nrf_adc_value_t)); + m_cb.state = NRFX_DRV_STATE_INITIALIZED; + m_cb.event_handler(&evt); + } + else if (adc_sample_process()) + { + NRFX_LOG_DEBUG("Event: %s.", NRFX_LOG_ERROR_STRING_GET(NRF_ADC_EVENT_END)); + nrf_adc_int_disable(NRF_ADC_INT_END_MASK); + nrfx_adc_evt_t evt; + evt.type = NRFX_ADC_EVT_DONE; + evt.data.done.p_buffer = m_cb.p_buffer; + evt.data.done.size = m_cb.size; + m_cb.state = NRFX_DRV_STATE_INITIALIZED; + NRFX_LOG_DEBUG("ADC data:"); + NRFX_LOG_HEXDUMP_DEBUG((uint8_t *)m_cb.p_buffer, m_cb.size * sizeof(nrf_adc_value_t)); + m_cb.event_handler(&evt); + } +} + +#endif // NRFX_CHECK(NRFX_ADC_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_clock.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_clock.c new file mode 100644 index 0000000..8e1d14e --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_clock.c @@ -0,0 +1,381 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_CLOCK_ENABLED) + +#include <nrfx_clock.h> + +#define NRFX_LOG_MODULE CLOCK +#include <nrfx_log.h> + +#if NRFX_CHECK(NRFX_POWER_ENABLED) +extern bool nrfx_power_irq_enabled; +#endif + +#define EVT_TO_STR(event) \ + (event == NRF_CLOCK_EVENT_HFCLKSTARTED ? "NRF_CLOCK_EVENT_HFCLKSTARTED" : \ + (event == NRF_CLOCK_EVENT_LFCLKSTARTED ? "NRF_CLOCK_EVENT_LFCLKSTARTED" : \ + (event == NRF_CLOCK_EVENT_DONE ? "NRF_CLOCK_EVENT_DONE" : \ + (event == NRF_CLOCK_EVENT_CTTO ? "NRF_CLOCK_EVENT_CTTO" : \ + "UNKNOWN EVENT")))) + + +/*lint -save -e652 */ +#define NRF_CLOCK_LFCLK_RC CLOCK_LFCLKSRC_SRC_RC +#define NRF_CLOCK_LFCLK_Xtal CLOCK_LFCLKSRC_SRC_Xtal +#define NRF_CLOCK_LFCLK_Synth CLOCK_LFCLKSRC_SRC_Synth +/*lint -restore */ + +#if (NRFX_CLOCK_CONFIG_LF_SRC == NRF_CLOCK_LFCLK_RC) +#define CALIBRATION_SUPPORT 1 +#else +#define CALIBRATION_SUPPORT 0 +#endif + +#if defined(NRF52810_XXAA) || \ + defined(NRF52832_XXAA) || defined(NRF52832_XXAB) || \ + defined(NRF52840_XXAA) +// Enable workaround for nRF52 anomaly 192 (LFRC oscillator frequency is wrong +// after calibration, exceeding 500 ppm). +#define USE_WORKAROUND_FOR_ANOMALY_192 + +// Enable workaround for nRF52 anomaly 201 (EVENTS_HFCLKSTARTED might be generated twice). +#define USE_WORKAROUND_FOR_ANOMALY_201 +#endif + +typedef enum +{ + CAL_STATE_IDLE, + CAL_STATE_CAL +} nrfx_clock_cal_state_t; + +/**@brief CLOCK control block. */ +typedef struct +{ + nrfx_clock_event_handler_t event_handler; + bool module_initialized; /*< Indicate the state of module */ +#if defined(USE_WORKAROUND_FOR_ANOMALY_201) + bool hfclk_started; /*< Anomaly 201 workaround. */ +#endif + +#if CALIBRATION_SUPPORT + volatile nrfx_clock_cal_state_t cal_state; +#endif // CALIBRATION_SUPPORT +} nrfx_clock_cb_t; + +static nrfx_clock_cb_t m_clock_cb; + +/** + * This variable is used to check whether common POWER_CLOCK common interrupt + * should be disabled or not if @ref nrfx_power tries to disable the interrupt. + */ +#if NRFX_CHECK(NRFX_POWER_ENABLED) +bool nrfx_clock_irq_enabled; +#endif + +#if defined(NRF52832_XXAA) || defined(NRF52832_XXAB) + +// ANOMALY 132 - LFCLK needs to avoid frame from 66us to 138us after LFCLK stop. This solution +// applies delay of 138us before starting LFCLK. +#define ANOMALY_132_REQ_DELAY_US 138UL + +// nRF52832 is clocked with 64MHz. +#define ANOMALY_132_NRF52832_FREQ_MHZ 64UL + +// Convert time to cycles. +#define ANOMALY_132_DELAY_CYCLES (ANOMALY_132_REQ_DELAY_US * ANOMALY_132_NRF52832_FREQ_MHZ) + +/** + * @brief Function for applying delay of 138us before starting LFCLK. + */ +static void nrfx_clock_anomaly_132(void) +{ + uint32_t cyccnt_inital; + uint32_t core_debug; + uint32_t dwt_ctrl; + + // Preserve DEMCR register to do not influence into its configuration. Enable the trace and + // debug blocks. It is required to read and write data to DWT block. + core_debug = CoreDebug->DEMCR; + CoreDebug->DEMCR = core_debug | CoreDebug_DEMCR_TRCENA_Msk; + + // Preserve CTRL register in DWT block to do not influence into its configuration. Make sure + // that cycle counter is enabled. + dwt_ctrl = DWT->CTRL; + DWT->CTRL = dwt_ctrl | DWT_CTRL_CYCCNTENA_Msk; + + // Store start value of cycle counter. + cyccnt_inital = DWT->CYCCNT; + + // Delay required time. + while ((DWT->CYCCNT - cyccnt_inital) < ANOMALY_132_DELAY_CYCLES) + {} + + // Restore preserved registers. + DWT->CTRL = dwt_ctrl; + CoreDebug->DEMCR = core_debug; +} + +#endif // defined(NRF52832_XXAA) || defined(NRF52832_XXAB) + +nrfx_err_t nrfx_clock_init(nrfx_clock_event_handler_t event_handler) +{ + NRFX_ASSERT(event_handler); + + nrfx_err_t err_code = NRFX_SUCCESS; + if (m_clock_cb.module_initialized) + { + err_code = NRFX_ERROR_ALREADY_INITIALIZED; + } + else + { +#if CALIBRATION_SUPPORT + m_clock_cb.cal_state = CAL_STATE_IDLE; +#endif + m_clock_cb.event_handler = event_handler; + m_clock_cb.module_initialized = true; +#if defined(USE_WORKAROUND_FOR_ANOMALY_201) + m_clock_cb.hfclk_started = false; +#endif + } + + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + +void nrfx_clock_enable(void) +{ + NRFX_ASSERT(m_clock_cb.module_initialized); + nrfx_power_clock_irq_init(); + nrf_clock_lf_src_set((nrf_clock_lfclk_t)NRFX_CLOCK_CONFIG_LF_SRC); + +#if NRFX_CHECK(NRFX_POWER_ENABLED) + nrfx_clock_irq_enabled = true; +#endif + + NRFX_LOG_INFO("Module enabled."); +} + +void nrfx_clock_disable(void) +{ + NRFX_ASSERT(m_clock_cb.module_initialized); +#if NRFX_CHECK(NRFX_POWER_ENABLED) + NRFX_ASSERT(nrfx_clock_irq_enabled); + if (!nrfx_power_irq_enabled) +#endif + { + NRFX_IRQ_DISABLE(POWER_CLOCK_IRQn); + } + nrf_clock_int_disable(CLOCK_INTENSET_HFCLKSTARTED_Msk | + CLOCK_INTENSET_LFCLKSTARTED_Msk | + CLOCK_INTENSET_DONE_Msk | + CLOCK_INTENSET_CTTO_Msk); +#if NRFX_CHECK(NRFX_POWER_ENABLED) + nrfx_clock_irq_enabled = false; +#endif + NRFX_LOG_INFO("Module disabled."); +} + +void nrfx_clock_uninit(void) +{ + NRFX_ASSERT(m_clock_cb.module_initialized); + nrfx_clock_lfclk_stop(); + nrfx_clock_hfclk_stop(); + m_clock_cb.module_initialized = false; + NRFX_LOG_INFO("Uninitialized."); +} + +void nrfx_clock_lfclk_start(void) +{ + NRFX_ASSERT(m_clock_cb.module_initialized); + nrf_clock_event_clear(NRF_CLOCK_EVENT_LFCLKSTARTED); + nrf_clock_int_enable(NRF_CLOCK_INT_LF_STARTED_MASK); + +#if defined(NRF52832_XXAA) || defined(NRF52832_XXAB) + nrfx_clock_anomaly_132(); +#endif + + nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTART); +} + +void nrfx_clock_lfclk_stop(void) +{ + NRFX_ASSERT(m_clock_cb.module_initialized); + nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTOP); + while (nrf_clock_lf_is_running()) + {} +} + +void nrfx_clock_hfclk_start(void) +{ + NRFX_ASSERT(m_clock_cb.module_initialized); + nrf_clock_event_clear(NRF_CLOCK_EVENT_HFCLKSTARTED); + nrf_clock_int_enable(NRF_CLOCK_INT_HF_STARTED_MASK); + nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTART); +} + +void nrfx_clock_hfclk_stop(void) +{ + NRFX_ASSERT(m_clock_cb.module_initialized); + nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTOP); + while (nrf_clock_hf_is_running(NRF_CLOCK_HFCLK_HIGH_ACCURACY)) + {} +#if defined(USE_WORKAROUND_FOR_ANOMALY_201) + m_clock_cb.hfclk_started = false; +#endif +} + +nrfx_err_t nrfx_clock_calibration_start(void) +{ + nrfx_err_t err_code = NRFX_SUCCESS; +#if CALIBRATION_SUPPORT + if (nrfx_clock_hfclk_is_running() == false) + { + return NRFX_ERROR_INVALID_STATE; + } + + if (nrfx_clock_lfclk_is_running() == false) + { + return NRFX_ERROR_INVALID_STATE; + } + + if (m_clock_cb.cal_state == CAL_STATE_IDLE) + { + nrf_clock_event_clear(NRF_CLOCK_EVENT_DONE); + nrf_clock_int_enable(NRF_CLOCK_INT_DONE_MASK); + m_clock_cb.cal_state = CAL_STATE_CAL; +#if defined(USE_WORKAROUND_FOR_ANOMALY_192) + *(volatile uint32_t *)0x40000C34 = 0x00000002; +#endif + nrf_clock_task_trigger(NRF_CLOCK_TASK_CAL); + } + else + { + err_code = NRFX_ERROR_BUSY; + } +#endif // CALIBRATION_SUPPORT + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + +nrfx_err_t nrfx_clock_is_calibrating(void) +{ +#if CALIBRATION_SUPPORT + if (m_clock_cb.cal_state == CAL_STATE_CAL) + { + return NRFX_ERROR_BUSY; + } +#endif + return NRFX_SUCCESS; +} + +void nrfx_clock_calibration_timer_start(uint8_t interval) +{ + nrf_clock_cal_timer_timeout_set(interval); + nrf_clock_event_clear(NRF_CLOCK_EVENT_CTTO); + nrf_clock_int_enable(NRF_CLOCK_INT_CTTO_MASK); + nrf_clock_task_trigger(NRF_CLOCK_TASK_CTSTART); +} + +void nrfx_clock_calibration_timer_stop(void) +{ + nrf_clock_int_disable(NRF_CLOCK_INT_CTTO_MASK); + nrf_clock_task_trigger(NRF_CLOCK_TASK_CTSTOP); +} + +void nrfx_clock_irq_handler(void) +{ + if (nrf_clock_event_check(NRF_CLOCK_EVENT_HFCLKSTARTED)) + { + nrf_clock_event_clear(NRF_CLOCK_EVENT_HFCLKSTARTED); + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_CLOCK_EVENT_HFCLKSTARTED)); + nrf_clock_int_disable(NRF_CLOCK_INT_HF_STARTED_MASK); + +#if defined(USE_WORKAROUND_FOR_ANOMALY_201) + if (!m_clock_cb.hfclk_started) + { + m_clock_cb.hfclk_started = true; + m_clock_cb.event_handler(NRFX_CLOCK_EVT_HFCLK_STARTED); + } +#else + m_clock_cb.event_handler(NRFX_CLOCK_EVT_HFCLK_STARTED); +#endif + } + if (nrf_clock_event_check(NRF_CLOCK_EVENT_LFCLKSTARTED)) + { + nrf_clock_event_clear(NRF_CLOCK_EVENT_LFCLKSTARTED); + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_CLOCK_EVENT_LFCLKSTARTED)); + nrf_clock_int_disable(NRF_CLOCK_INT_LF_STARTED_MASK); + + m_clock_cb.event_handler(NRFX_CLOCK_EVT_LFCLK_STARTED); + } +#if CALIBRATION_SUPPORT + if (nrf_clock_event_check(NRF_CLOCK_EVENT_CTTO)) + { + nrf_clock_event_clear(NRF_CLOCK_EVENT_CTTO); + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_CLOCK_EVENT_CTTO)); + nrf_clock_int_disable(NRF_CLOCK_INT_CTTO_MASK); + + m_clock_cb.event_handler(NRFX_CLOCK_EVT_CTTO); + } + + if (nrf_clock_event_check(NRF_CLOCK_EVENT_DONE)) + { +#if defined(USE_WORKAROUND_FOR_ANOMALY_192) + *(volatile uint32_t *)0x40000C34 = 0x00000000; +#endif + nrf_clock_event_clear(NRF_CLOCK_EVENT_DONE); + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_CLOCK_EVENT_DONE)); + nrf_clock_int_disable(NRF_CLOCK_INT_DONE_MASK); + m_clock_cb.cal_state = CAL_STATE_IDLE; + m_clock_cb.event_handler(NRFX_CLOCK_EVT_CAL_DONE); + } +#endif // CALIBRATION_SUPPORT +} + +#undef NRF_CLOCK_LFCLK_RC +#undef NRF_CLOCK_LFCLK_Xtal +#undef NRF_CLOCK_LFCLK_Synth + +#endif // NRFX_CHECK(NRFX_CLOCK_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_comp.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_comp.c new file mode 100644 index 0000000..63572d5 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_comp.c @@ -0,0 +1,211 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_COMP_ENABLED) + +#include <nrfx_comp.h> +#include "prs/nrfx_prs.h" + +#define NRFX_LOG_MODULE COMP +#include <nrfx_log.h> + +#define EVT_TO_STR(event) \ + (event == NRF_COMP_EVENT_READY ? "NRF_COMP_EVENT_READY" : \ + (event == NRF_COMP_EVENT_DOWN ? "NRF_COMP_EVENT_DOWN" : \ + (event == NRF_COMP_EVENT_UP ? "NRF_COMP_EVENT_UP" : \ + (event == NRF_COMP_EVENT_CROSS ? "NRF_COMP_EVENT_CROSS" : \ + "UNKNOWN ERROR")))) + + +static nrfx_comp_event_handler_t m_comp_event_handler = NULL; +static nrfx_drv_state_t m_state = NRFX_DRV_STATE_UNINITIALIZED; + +static void comp_execute_handler(nrf_comp_event_t event, uint32_t event_mask) +{ + if (nrf_comp_event_check(event) && nrf_comp_int_enable_check(event_mask)) + { + nrf_comp_event_clear(event); + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(event)); + + m_comp_event_handler(event); + } +} + +void nrfx_comp_irq_handler(void) +{ + comp_execute_handler(NRF_COMP_EVENT_READY, COMP_INTENSET_READY_Msk); + comp_execute_handler(NRF_COMP_EVENT_DOWN, COMP_INTENSET_DOWN_Msk); + comp_execute_handler(NRF_COMP_EVENT_UP, COMP_INTENSET_UP_Msk); + comp_execute_handler(NRF_COMP_EVENT_CROSS, COMP_INTENSET_CROSS_Msk); +} + + +nrfx_err_t nrfx_comp_init(nrfx_comp_config_t const * p_config, + nrfx_comp_event_handler_t event_handler) +{ + NRFX_ASSERT(p_config); + NRFX_ASSERT(event_handler); + nrfx_err_t err_code; + + if (m_state != NRFX_DRV_STATE_UNINITIALIZED) + { // COMP driver is already initialized + 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; + } + + m_comp_event_handler = event_handler; + +#if NRFX_CHECK(NRFX_PRS_ENABLED) + if (nrfx_prs_acquire(NRF_COMP, nrfx_comp_irq_handler) != 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 + + nrf_comp_task_trigger(NRF_COMP_TASK_STOP); + nrf_comp_enable(); + + // Clear events to be sure there are no leftovers. + nrf_comp_event_clear(NRF_COMP_EVENT_READY); + nrf_comp_event_clear(NRF_COMP_EVENT_DOWN); + nrf_comp_event_clear(NRF_COMP_EVENT_UP); + nrf_comp_event_clear(NRF_COMP_EVENT_CROSS); + + nrf_comp_ref_set(p_config->reference); + + //If external source is chosen, write to appropriate register. + if (p_config->reference == COMP_REFSEL_REFSEL_ARef) + { + nrf_comp_ext_ref_set(p_config->ext_ref); + } + + nrf_comp_th_set(p_config->threshold); + nrf_comp_main_mode_set(p_config->main_mode); + nrf_comp_speed_mode_set(p_config->speed_mode); + nrf_comp_hysteresis_set(p_config->hyst); +#if defined (COMP_ISOURCE_ISOURCE_Msk) + nrf_comp_isource_set(p_config->isource); +#endif + nrf_comp_shorts_disable(NRFX_COMP_SHORT_STOP_AFTER_CROSS_EVT | + NRFX_COMP_SHORT_STOP_AFTER_UP_EVT | + NRFX_COMP_SHORT_STOP_AFTER_DOWN_EVT); + nrf_comp_int_disable(COMP_INTENCLR_CROSS_Msk | + COMP_INTENCLR_UP_Msk | + COMP_INTENCLR_DOWN_Msk | + COMP_INTENCLR_READY_Msk); + + nrf_comp_input_select(p_config->input); + + NRFX_IRQ_PRIORITY_SET(COMP_LPCOMP_IRQn, p_config->interrupt_priority); + NRFX_IRQ_ENABLE(COMP_LPCOMP_IRQn); + + m_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_comp_uninit(void) +{ + NRFX_ASSERT(m_state != NRFX_DRV_STATE_UNINITIALIZED); + NRFX_IRQ_DISABLE(COMP_LPCOMP_IRQn); + nrf_comp_disable(); +#if NRFX_CHECK(NRFX_PRS_ENABLED) + nrfx_prs_release(NRF_COMP); +#endif + m_state = NRFX_DRV_STATE_UNINITIALIZED; + m_comp_event_handler = NULL; + NRFX_LOG_INFO("Uninitialized."); +} + +void nrfx_comp_pin_select(nrf_comp_input_t psel) +{ + bool comp_enable_state = nrf_comp_enable_check(); + nrf_comp_task_trigger(NRF_COMP_TASK_STOP); + if (m_state == NRFX_DRV_STATE_POWERED_ON) + { + m_state = NRFX_DRV_STATE_INITIALIZED; + } + nrf_comp_disable(); + nrf_comp_input_select(psel); + if (comp_enable_state == true) + { + nrf_comp_enable(); + } +} + +void nrfx_comp_start(uint32_t comp_int_mask, uint32_t comp_shorts_mask) +{ + NRFX_ASSERT(m_state == NRFX_DRV_STATE_INITIALIZED); + nrf_comp_int_enable(comp_int_mask); + nrf_comp_shorts_enable(comp_shorts_mask); + nrf_comp_task_trigger(NRF_COMP_TASK_START); + m_state = NRFX_DRV_STATE_POWERED_ON; + NRFX_LOG_INFO("Enabled."); +} + +void nrfx_comp_stop(void) +{ + NRFX_ASSERT(m_state == NRFX_DRV_STATE_POWERED_ON); + nrf_comp_shorts_disable(UINT32_MAX); + nrf_comp_int_disable(UINT32_MAX); + nrf_comp_task_trigger(NRF_COMP_TASK_STOP); + m_state = NRFX_DRV_STATE_INITIALIZED; + NRFX_LOG_INFO("Disabled."); +} + +uint32_t nrfx_comp_sample() +{ + NRFX_ASSERT(m_state == NRFX_DRV_STATE_POWERED_ON); + nrf_comp_task_trigger(NRF_COMP_TASK_SAMPLE); + return nrf_comp_result_get(); +} + +#endif // NRFX_CHECK(NRFX_COMP_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_gpiote.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_gpiote.c new file mode 100644 index 0000000..8412b60 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_gpiote.c @@ -0,0 +1,826 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_GPIOTE_ENABLED) + +#include <nrfx_gpiote.h> +#include "nrf_bitmask.h" +#include <string.h> + +#define NRFX_LOG_MODULE GPIOTE +#include <nrfx_log.h> + + +#define FORBIDDEN_HANDLER_ADDRESS ((nrfx_gpiote_evt_handler_t)UINT32_MAX) +#define PIN_NOT_USED (-1) +#define PIN_USED (-2) +#define NO_CHANNELS (-1) +#define SENSE_FIELD_POS (6) +#define SENSE_FIELD_MASK (0xC0) + +/** + * @brief Macro for converting task-event index to an address of an event register. + * + * Macro utilizes the fact that registers are grouped together in ascending order. + */ +#define TE_IDX_TO_EVENT_ADDR(idx) (nrf_gpiote_events_t)((uint32_t)NRF_GPIOTE_EVENTS_IN_0 + \ + (sizeof(uint32_t) * (idx))) + +/** + * @brief Macro for converting task-event index of OUT task to an address of a task register. + * + * Macro utilizes the fact that registers are grouped together in ascending order. + */ +#define TE_OUT_IDX_TO_TASK_ADDR(idx) (nrf_gpiote_tasks_t)((uint32_t)NRF_GPIOTE_TASKS_OUT_0 + \ + (sizeof(uint32_t) * (idx))) + +#if defined(GPIOTE_FEATURE_SET_PRESENT) || defined(__NRFX_DOXYGEN__) +/** + * @brief Macro for converting task-event index of SET task to an address of a task register. + * + * Macro utilizes the fact that registers are grouped together in ascending order. + */ +#define TE_SET_IDX_TO_TASK_ADDR(idx) (nrf_gpiote_tasks_t)((uint32_t)NRF_GPIOTE_TASKS_SET_0 + \ + (sizeof(uint32_t) * (idx))) + +#endif // defined(GPIOTE_FEATURE_SET_PRESENT) || defined(__NRFX_DOXYGEN__) + +#if defined(GPIOTE_FEATURE_CLR_PRESENT) || defined(__NRFX_DOXYGEN__) +/** + * @brief Macro for converting task-event index of CLR task to an address of a task register. + * + * Macro utilizes the fact that registers are grouped together in ascending order. + */ +#define TE_CLR_IDX_TO_TASK_ADDR(idx) (nrf_gpiote_tasks_t)((uint32_t)NRF_GPIOTE_TASKS_CLR_0 + \ + (sizeof(uint32_t) * (idx))) + +#endif // defined(GPIOTE_FEATURE_CLR_PRESENT) || defined(__NRFX_DOXYGEN__) + +/*lint -save -e571*/ /* Suppress "Warning 571: Suspicious cast" */ +typedef struct +{ + nrfx_gpiote_evt_handler_t handlers[GPIOTE_CH_NUM + NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS]; + int8_t pin_assignments[NUMBER_OF_PINS]; + int8_t port_handlers_pins[NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS]; + uint8_t configured_pins[((NUMBER_OF_PINS)+7) / 8]; + nrfx_drv_state_t state; +} gpiote_control_block_t; + +static gpiote_control_block_t m_cb; + +__STATIC_INLINE bool pin_in_use(uint32_t pin) +{ + return (m_cb.pin_assignments[pin] != PIN_NOT_USED); +} + + +__STATIC_INLINE bool pin_in_use_as_non_task_out(uint32_t pin) +{ + return (m_cb.pin_assignments[pin] == PIN_USED); +} + + +__STATIC_INLINE bool pin_in_use_by_te(uint32_t pin) +{ + return (m_cb.pin_assignments[pin] >= 0 && m_cb.pin_assignments[pin] < GPIOTE_CH_NUM) ? + true : false; +} + + +__STATIC_INLINE bool pin_in_use_by_port(uint32_t pin) +{ + return (m_cb.pin_assignments[pin] >= GPIOTE_CH_NUM); +} + + +__STATIC_INLINE bool pin_in_use_by_gpiote(uint32_t pin) +{ + return (m_cb.pin_assignments[pin] >= 0); +} + + +__STATIC_INLINE void pin_in_use_by_te_set(uint32_t pin, + uint32_t channel_id, + nrfx_gpiote_evt_handler_t handler, + bool is_channel) +{ + m_cb.pin_assignments[pin] = channel_id; + m_cb.handlers[channel_id] = handler; + if (!is_channel) + { + m_cb.port_handlers_pins[channel_id - GPIOTE_CH_NUM] = (int8_t)pin; + } +} + + +__STATIC_INLINE void pin_in_use_set(uint32_t pin) +{ + m_cb.pin_assignments[pin] = PIN_USED; +} + + +__STATIC_INLINE void pin_in_use_clear(uint32_t pin) +{ + m_cb.pin_assignments[pin] = PIN_NOT_USED; +} + + +__STATIC_INLINE void pin_configured_set(uint32_t pin) +{ + nrf_bitmask_bit_set(pin, m_cb.configured_pins); +} + +__STATIC_INLINE void pin_configured_clear(uint32_t pin) +{ + nrf_bitmask_bit_clear(pin, m_cb.configured_pins); +} + +__STATIC_INLINE bool pin_configured_check(uint32_t pin) +{ + return 0 != nrf_bitmask_bit_is_set(pin, m_cb.configured_pins); +} + +__STATIC_INLINE int8_t channel_port_get(uint32_t pin) +{ + return m_cb.pin_assignments[pin]; +} + + +__STATIC_INLINE nrfx_gpiote_evt_handler_t channel_handler_get(uint32_t channel) +{ + return m_cb.handlers[channel]; +} + + +static int8_t channel_port_alloc(uint32_t pin, nrfx_gpiote_evt_handler_t handler, bool channel) +{ + int8_t channel_id = NO_CHANNELS; + uint32_t i; + + uint32_t start_idx = channel ? 0 : GPIOTE_CH_NUM; + uint32_t end_idx = + channel ? GPIOTE_CH_NUM : (GPIOTE_CH_NUM + NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS); + + // critical section + + for (i = start_idx; i < end_idx; i++) + { + if (m_cb.handlers[i] == FORBIDDEN_HANDLER_ADDRESS) + { + pin_in_use_by_te_set(pin, i, handler, channel); + channel_id = i; + break; + } + } + // critical section + return channel_id; +} + + +static void channel_free(uint8_t channel_id) +{ + m_cb.handlers[channel_id] = FORBIDDEN_HANDLER_ADDRESS; + if (channel_id >= GPIOTE_CH_NUM) + { + m_cb.port_handlers_pins[channel_id - GPIOTE_CH_NUM] = (int8_t)PIN_NOT_USED; + } +} + + +nrfx_err_t nrfx_gpiote_init(void) +{ + nrfx_err_t err_code; + + if (m_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; + } + + uint8_t i; + + for (i = 0; i < NUMBER_OF_PINS; i++) + { + pin_in_use_clear(i); + } + + for (i = 0; i < (GPIOTE_CH_NUM + NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS); i++) + { + channel_free(i); + } + + memset(m_cb.configured_pins, 0, sizeof(m_cb.configured_pins)); + + NRFX_IRQ_PRIORITY_SET(GPIOTE_IRQn, NRFX_GPIOTE_CONFIG_IRQ_PRIORITY); + NRFX_IRQ_ENABLE(GPIOTE_IRQn); + nrf_gpiote_event_clear(NRF_GPIOTE_EVENTS_PORT); + nrf_gpiote_int_enable(GPIOTE_INTENSET_PORT_Msk); + m_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; +} + + +bool nrfx_gpiote_is_init(void) +{ + return (m_cb.state != NRFX_DRV_STATE_UNINITIALIZED) ? true : false; +} + + +void nrfx_gpiote_uninit(void) +{ + NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); + + uint32_t i; + + for (i = 0; i < NUMBER_OF_PINS; i++) + { + if (pin_in_use_as_non_task_out(i)) + { + nrfx_gpiote_out_uninit(i); + } + else if ( pin_in_use_by_gpiote(i)) + { + /* Disable gpiote_in is having the same effect on out pin as gpiote_out_uninit on + * so it can be called on all pins used by GPIOTE. + */ + nrfx_gpiote_in_uninit(i); + } + } + m_cb.state = NRFX_DRV_STATE_UNINITIALIZED; + NRFX_LOG_INFO("Uninitialized."); +} + + +nrfx_err_t nrfx_gpiote_out_init(nrfx_gpiote_pin_t pin, + nrfx_gpiote_out_config_t const * p_config) +{ + NRFX_ASSERT(pin < NUMBER_OF_PINS); + NRFX_ASSERT(m_cb.state == NRFX_DRV_STATE_INITIALIZED); + NRFX_ASSERT(p_config); + + nrfx_err_t err_code = NRFX_SUCCESS; + + if (pin_in_use(pin)) + { + err_code = NRFX_ERROR_INVALID_STATE; + } + else + { + if (p_config->task_pin) + { + int8_t channel = channel_port_alloc(pin, NULL, true); + + if (channel != NO_CHANNELS) + { + nrf_gpiote_task_configure((uint32_t)channel, + pin, + p_config->action, + p_config->init_state); + } + else + { + err_code = NRFX_ERROR_NO_MEM; + } + } + else + { + pin_in_use_set(pin); + } + + if (err_code == NRFX_SUCCESS) + { + if (p_config->init_state == NRF_GPIOTE_INITIAL_VALUE_HIGH) + { + nrf_gpio_pin_set(pin); + } + else + { + nrf_gpio_pin_clear(pin); + } + + nrf_gpio_cfg_output(pin); + pin_configured_set(pin); + } + } + + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + + +void nrfx_gpiote_out_uninit(nrfx_gpiote_pin_t pin) +{ + NRFX_ASSERT(pin < NUMBER_OF_PINS); + NRFX_ASSERT(pin_in_use(pin)); + + if (pin_in_use_by_te(pin)) + { + channel_free((uint8_t)channel_port_get(pin)); + nrf_gpiote_te_default((uint32_t)channel_port_get(pin)); + } + pin_in_use_clear(pin); + + if (pin_configured_check(pin)) + { + nrf_gpio_cfg_default(pin); + pin_configured_clear(pin); + } +} + + +void nrfx_gpiote_out_set(nrfx_gpiote_pin_t pin) +{ + NRFX_ASSERT(pin < NUMBER_OF_PINS); + NRFX_ASSERT(pin_in_use(pin)); + NRFX_ASSERT(!pin_in_use_by_te(pin)); + + nrf_gpio_pin_set(pin); +} + + +void nrfx_gpiote_out_clear(nrfx_gpiote_pin_t pin) +{ + NRFX_ASSERT(pin < NUMBER_OF_PINS); + NRFX_ASSERT(pin_in_use(pin)); + NRFX_ASSERT(!pin_in_use_by_te(pin)); + + nrf_gpio_pin_clear(pin); +} + + +void nrfx_gpiote_out_toggle(nrfx_gpiote_pin_t pin) +{ + NRFX_ASSERT(pin < NUMBER_OF_PINS); + NRFX_ASSERT(pin_in_use(pin)); + NRFX_ASSERT(!pin_in_use_by_te(pin)); + + nrf_gpio_pin_toggle(pin); +} + + +void nrfx_gpiote_out_task_enable(nrfx_gpiote_pin_t pin) +{ + NRFX_ASSERT(pin < NUMBER_OF_PINS); + NRFX_ASSERT(pin_in_use(pin)); + NRFX_ASSERT(pin_in_use_by_te(pin)); + + nrf_gpiote_task_enable((uint32_t)m_cb.pin_assignments[pin]); +} + + +void nrfx_gpiote_out_task_disable(nrfx_gpiote_pin_t pin) +{ + NRFX_ASSERT(pin < NUMBER_OF_PINS); + NRFX_ASSERT(pin_in_use(pin)); + NRFX_ASSERT(pin_in_use_by_te(pin)); + + nrf_gpiote_task_disable((uint32_t)m_cb.pin_assignments[pin]); +} + + +uint32_t nrfx_gpiote_out_task_addr_get(nrfx_gpiote_pin_t pin) +{ + NRFX_ASSERT(pin < NUMBER_OF_PINS); + NRFX_ASSERT(pin_in_use_by_te(pin)); + + nrf_gpiote_tasks_t task = TE_OUT_IDX_TO_TASK_ADDR((uint32_t)channel_port_get(pin)); + return nrf_gpiote_task_addr_get(task); +} + + +#if defined(GPIOTE_FEATURE_SET_PRESENT) +uint32_t nrfx_gpiote_set_task_addr_get(nrfx_gpiote_pin_t pin) +{ + NRFX_ASSERT(pin < NUMBER_OF_PINS); + NRFX_ASSERT(pin_in_use_by_te(pin)); + + nrf_gpiote_tasks_t task = TE_SET_IDX_TO_TASK_ADDR((uint32_t)channel_port_get(pin)); + return nrf_gpiote_task_addr_get(task); +} + + +#endif // defined(GPIOTE_FEATURE_SET_PRESENT) + +#if defined(GPIOTE_FEATURE_CLR_PRESENT) +uint32_t nrfx_gpiote_clr_task_addr_get(nrfx_gpiote_pin_t pin) +{ + NRFX_ASSERT(pin < NUMBER_OF_PINS); + NRFX_ASSERT(pin_in_use_by_te(pin)); + + nrf_gpiote_tasks_t task = TE_CLR_IDX_TO_TASK_ADDR((uint32_t)channel_port_get(pin)); + return nrf_gpiote_task_addr_get(task); +} + + +#endif // defined(GPIOTE_FEATURE_CLR_PRESENT) + +void nrfx_gpiote_out_task_force(nrfx_gpiote_pin_t pin, uint8_t state) +{ + NRFX_ASSERT(pin < NUMBER_OF_PINS); + NRFX_ASSERT(pin_in_use(pin)); + NRFX_ASSERT(pin_in_use_by_te(pin)); + + nrf_gpiote_outinit_t init_val = + state ? NRF_GPIOTE_INITIAL_VALUE_HIGH : NRF_GPIOTE_INITIAL_VALUE_LOW; + nrf_gpiote_task_force((uint32_t)m_cb.pin_assignments[pin], init_val); +} + + +void nrfx_gpiote_out_task_trigger(nrfx_gpiote_pin_t pin) +{ + NRFX_ASSERT(pin < NUMBER_OF_PINS); + NRFX_ASSERT(pin_in_use(pin)); + NRFX_ASSERT(pin_in_use_by_te(pin)); + + nrf_gpiote_tasks_t task = TE_OUT_IDX_TO_TASK_ADDR((uint32_t)channel_port_get(pin)); + nrf_gpiote_task_set(task); +} + + +#if defined(GPIOTE_FEATURE_SET_PRESENT) +void nrfx_gpiote_set_task_trigger(nrfx_gpiote_pin_t pin) +{ + NRFX_ASSERT(pin < NUMBER_OF_PINS); + NRFX_ASSERT(pin_in_use(pin)); + NRFX_ASSERT(pin_in_use_by_te(pin)); + + nrf_gpiote_tasks_t task = TE_SET_IDX_TO_TASK_ADDR((uint32_t)channel_port_get(pin)); + nrf_gpiote_task_set(task); +} + + +#endif // defined(GPIOTE_FEATURE_SET_PRESENT) + +#if defined(GPIOTE_FEATURE_CLR_PRESENT) +void nrfx_gpiote_clr_task_trigger(nrfx_gpiote_pin_t pin) +{ + NRFX_ASSERT(pin < NUMBER_OF_PINS); + NRFX_ASSERT(pin_in_use(pin)); + NRFX_ASSERT(pin_in_use_by_te(pin)); + + nrf_gpiote_tasks_t task = TE_CLR_IDX_TO_TASK_ADDR((uint32_t)channel_port_get(pin)); + nrf_gpiote_task_set(task); +} + + +#endif // defined(GPIOTE_FEATURE_CLR_PRESENT) + +nrfx_err_t nrfx_gpiote_in_init(nrfx_gpiote_pin_t pin, + nrfx_gpiote_in_config_t const * p_config, + nrfx_gpiote_evt_handler_t evt_handler) +{ + NRFX_ASSERT(pin < NUMBER_OF_PINS); + nrfx_err_t err_code = NRFX_SUCCESS; + + /* Only one GPIOTE channel can be assigned to one physical pin. */ + if (pin_in_use_by_gpiote(pin)) + { + err_code = NRFX_ERROR_INVALID_STATE; + } + else + { + int8_t channel = channel_port_alloc(pin, evt_handler, p_config->hi_accuracy); + if (channel != NO_CHANNELS) + { + if (!p_config->skip_gpio_setup) + { + if (p_config->is_watcher) + { + nrf_gpio_cfg_watcher(pin); + } + else + { + nrf_gpio_cfg_input(pin, p_config->pull); + } + pin_configured_set(pin); + } + + if (p_config->hi_accuracy) + { + nrf_gpiote_event_configure((uint32_t)channel, pin, p_config->sense); + } + else + { + m_cb.port_handlers_pins[channel - + GPIOTE_CH_NUM] |= (p_config->sense) << SENSE_FIELD_POS; + } + } + else + { + err_code = NRFX_ERROR_NO_MEM; + } + } + + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + +void nrfx_gpiote_in_event_enable(nrfx_gpiote_pin_t pin, bool int_enable) +{ + NRFX_ASSERT(pin < NUMBER_OF_PINS); + NRFX_ASSERT(pin_in_use_by_gpiote(pin)); + if (pin_in_use_by_port(pin)) + { + uint8_t pin_and_sense = (uint8_t) + m_cb.port_handlers_pins[channel_port_get(pin) - GPIOTE_CH_NUM]; + nrf_gpiote_polarity_t polarity = + (nrf_gpiote_polarity_t)(pin_and_sense >> SENSE_FIELD_POS); + nrf_gpio_pin_sense_t sense; + if (polarity == NRF_GPIOTE_POLARITY_TOGGLE) + { + /* read current pin state and set for next sense to oposit */ + sense = (nrf_gpio_pin_read(pin)) ? + NRF_GPIO_PIN_SENSE_LOW : NRF_GPIO_PIN_SENSE_HIGH; + } + else + { + sense = (polarity == NRF_GPIOTE_POLARITY_LOTOHI) ? + NRF_GPIO_PIN_SENSE_HIGH : NRF_GPIO_PIN_SENSE_LOW; + } + nrf_gpio_cfg_sense_set(pin, sense); + } + else if (pin_in_use_by_te(pin)) + { + int32_t channel = (int32_t)channel_port_get(pin); + nrf_gpiote_events_t event = TE_IDX_TO_EVENT_ADDR((uint32_t)channel); + + nrf_gpiote_event_enable((uint32_t)channel); + + nrf_gpiote_event_clear(event); + if (int_enable) + { + nrfx_gpiote_evt_handler_t handler = channel_handler_get((uint32_t)channel_port_get(pin)); + // Enable the interrupt only if event handler was provided. + if (handler) + { + nrf_gpiote_int_enable(1 << channel); + } + } + } +} + + +void nrfx_gpiote_in_event_disable(nrfx_gpiote_pin_t pin) +{ + NRFX_ASSERT(pin < NUMBER_OF_PINS); + NRFX_ASSERT(pin_in_use_by_gpiote(pin)); + if (pin_in_use_by_port(pin)) + { + nrf_gpio_cfg_sense_set(pin, NRF_GPIO_PIN_NOSENSE); + } + else if (pin_in_use_by_te(pin)) + { + int32_t channel = (int32_t)channel_port_get(pin); + nrf_gpiote_event_disable((uint32_t)channel); + nrf_gpiote_int_disable(1 << channel); + } +} + + +void nrfx_gpiote_in_uninit(nrfx_gpiote_pin_t pin) +{ + NRFX_ASSERT(pin < NUMBER_OF_PINS); + NRFX_ASSERT(pin_in_use_by_gpiote(pin)); + nrfx_gpiote_in_event_disable(pin); + if (pin_in_use_by_te(pin)) + { + nrf_gpiote_te_default((uint32_t)channel_port_get(pin)); + } + if (pin_configured_check(pin)) + { + nrf_gpio_cfg_default(pin); + pin_configured_clear(pin); + } + channel_free((uint8_t)channel_port_get(pin)); + pin_in_use_clear(pin); +} + + +bool nrfx_gpiote_in_is_set(nrfx_gpiote_pin_t pin) +{ + NRFX_ASSERT(pin < NUMBER_OF_PINS); + return nrf_gpio_pin_read(pin) ? true : false; +} + + +uint32_t nrfx_gpiote_in_event_addr_get(nrfx_gpiote_pin_t pin) +{ + NRFX_ASSERT(pin < NUMBER_OF_PINS); + NRFX_ASSERT(pin_in_use_by_port(pin) || pin_in_use_by_te(pin)); + + nrf_gpiote_events_t event = NRF_GPIOTE_EVENTS_PORT; + + if (pin_in_use_by_te(pin)) + { + event = TE_IDX_TO_EVENT_ADDR((uint32_t)channel_port_get(pin)); + } + return nrf_gpiote_event_addr_get(event); +} + + +void nrfx_gpiote_irq_handler(void) +{ + uint32_t status = 0; + uint32_t input[GPIO_COUNT] = {0}; + + /* collect status of all GPIOTE pin events. Processing is done once all are collected and cleared.*/ + uint32_t i; + nrf_gpiote_events_t event = NRF_GPIOTE_EVENTS_IN_0; + uint32_t mask = (uint32_t)NRF_GPIOTE_INT_IN0_MASK; + + for (i = 0; i < GPIOTE_CH_NUM; i++) + { + if (nrf_gpiote_event_is_set(event) && nrf_gpiote_int_is_enabled(mask)) + { + nrf_gpiote_event_clear(event); + status |= mask; + } + mask <<= 1; + /* Incrementing to next event, utilizing the fact that events are grouped together + * in ascending order. */ + event = (nrf_gpiote_events_t)((uint32_t)event + sizeof(uint32_t)); + } + + /* collect PORT status event, if event is set read pins state. Processing is postponed to the + * end of interrupt. */ + if (nrf_gpiote_event_is_set(NRF_GPIOTE_EVENTS_PORT)) + { + nrf_gpiote_event_clear(NRF_GPIOTE_EVENTS_PORT); + status |= (uint32_t)NRF_GPIOTE_INT_PORT_MASK; + nrf_gpio_ports_read(0, GPIO_COUNT, input); + } + + /* Process pin events. */ + if (status & NRF_GPIOTE_INT_IN_MASK) + { + mask = (uint32_t)NRF_GPIOTE_INT_IN0_MASK; + + for (i = 0; i < GPIOTE_CH_NUM; i++) + { + if (mask & status) + { + nrfx_gpiote_pin_t pin = nrf_gpiote_event_pin_get(i); + NRFX_LOG_DEBUG("Event in number: %d.", i); + nrf_gpiote_polarity_t polarity = nrf_gpiote_event_polarity_get(i); + nrfx_gpiote_evt_handler_t handler = channel_handler_get(i); + NRFX_LOG_DEBUG("Pin: %d, polarity: %d.", pin, polarity); + if (handler) + { + handler(pin, polarity); + } + } + mask <<= 1; + } + } + + if (status & (uint32_t)NRF_GPIOTE_INT_PORT_MASK) + { + /* Process port event. */ + uint32_t port_idx; + uint8_t repeat = 0; + uint32_t toggle_mask[GPIO_COUNT] = {0}; + uint32_t pins_to_check[GPIO_COUNT]; + + // Faster way of doing memset because in interrupt context. + for (port_idx = 0; port_idx < GPIO_COUNT; port_idx++) + { + pins_to_check[port_idx] = 0xFFFFFFFF; + } + + do + { + repeat = 0; + + for (i = 0; i < NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS; i++) + { + uint8_t pin_and_sense = (uint8_t)m_cb.port_handlers_pins[i]; + nrfx_gpiote_pin_t pin = (pin_and_sense & ~SENSE_FIELD_MASK); + + if ((m_cb.port_handlers_pins[i] != PIN_NOT_USED) + && nrf_bitmask_bit_is_set(pin, pins_to_check)) + { + nrf_gpiote_polarity_t polarity = + (nrf_gpiote_polarity_t)((pin_and_sense & + SENSE_FIELD_MASK) >> SENSE_FIELD_POS); + nrfx_gpiote_evt_handler_t handler = + channel_handler_get((uint32_t)channel_port_get(pin)); + if (handler || (polarity == NRF_GPIOTE_POLARITY_TOGGLE)) + { + if (polarity == NRF_GPIOTE_POLARITY_TOGGLE) + { + nrf_bitmask_bit_set(pin, toggle_mask); + } + nrf_gpio_pin_sense_t sense = nrf_gpio_pin_sense_get(pin); + uint32_t pin_state = nrf_bitmask_bit_is_set(pin, input); + if ((pin_state && (sense == NRF_GPIO_PIN_SENSE_HIGH)) || + (!pin_state && (sense == NRF_GPIO_PIN_SENSE_LOW)) ) + { + NRFX_LOG_DEBUG("PORT event for pin: %d, polarity: %d.", pin, polarity); + if (polarity == NRF_GPIOTE_POLARITY_TOGGLE) + { + nrf_gpio_pin_sense_t next_sense = + (sense == NRF_GPIO_PIN_SENSE_HIGH) ? + NRF_GPIO_PIN_SENSE_LOW : + NRF_GPIO_PIN_SENSE_HIGH; + nrf_gpio_cfg_sense_set(pin, next_sense); + ++repeat; + + } + if (handler) + { + handler(pin, polarity); + } + } + } + } + } + + if (repeat) + { + // When one of the pins in low-accuracy and toggle mode becomes active, + // it's sense mode is inverted to clear the internal SENSE signal. + // State of any other enabled low-accuracy input in toggle mode must be checked + // explicitly, because it does not trigger the interrput when SENSE signal is active. + // For more information about SENSE functionality, refer to Product Specification. + + uint32_t new_input[GPIO_COUNT]; + bool input_unchanged = true; + nrf_gpio_ports_read(0, GPIO_COUNT, new_input); + + // Faster way of doing memcmp because in interrupt context. + for (port_idx = 0; port_idx < GPIO_COUNT; port_idx++) + { + if (new_input[port_idx] != input[port_idx]) + { + input_unchanged = false; + break; + } + } + + if (input_unchanged) + { + // No change. + repeat = 0; + } + else + { + // Faster way of doing memcpy because in interrupt context. + for (port_idx = 0; port_idx < GPIO_COUNT; port_idx++) + { + input[port_idx] = new_input[port_idx]; + pins_to_check[port_idx] = toggle_mask[port_idx]; + } + } + } + } + while (repeat); + } +} + + +/*lint -restore*/ +#endif // NRFX_CHECK(NRFX_GPIOTE_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_i2s.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_i2s.c new file mode 100644 index 0000000..35beaab --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_i2s.c @@ -0,0 +1,420 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_I2S_ENABLED) + +#include <nrfx_i2s.h> +#include <hal/nrf_gpio.h> + +#define NRFX_LOG_MODULE I2S +#include <nrfx_log.h> + +#define EVT_TO_STR(event) \ + (event == NRF_I2S_EVENT_RXPTRUPD ? "NRF_I2S_EVENT_RXPTRUPD" : \ + (event == NRF_I2S_EVENT_TXPTRUPD ? "NRF_I2S_EVENT_TXPTRUPD" : \ + (event == NRF_I2S_EVENT_STOPPED ? "NRF_I2S_EVENT_STOPPED" : \ + "UNKNOWN EVENT"))) + +// Control block - driver instance local data. +typedef struct +{ + nrfx_i2s_data_handler_t handler; + nrfx_drv_state_t state; + + bool use_rx : 1; + bool use_tx : 1; + bool rx_ready : 1; + bool tx_ready : 1; + bool buffers_needed : 1; + bool buffers_reused : 1; + + uint16_t buffer_size; + nrfx_i2s_buffers_t next_buffers; + nrfx_i2s_buffers_t current_buffers; +} i2s_control_block_t; +static i2s_control_block_t m_cb; + + +static void configure_pins(nrfx_i2s_config_t const * p_config) +{ + uint32_t mck_pin, sdout_pin, sdin_pin; + + // Configure pins used by the peripheral: + + // - SCK and LRCK (required) - depending on the mode of operation these + // pins are configured as outputs (in Master mode) or inputs (in Slave + // mode). + if (p_config->mode == NRF_I2S_MODE_MASTER) + { + nrf_gpio_cfg_output(p_config->sck_pin); + nrf_gpio_cfg_output(p_config->lrck_pin); + } + else + { + nrf_gpio_cfg_input(p_config->sck_pin, NRF_GPIO_PIN_NOPULL); + nrf_gpio_cfg_input(p_config->lrck_pin, NRF_GPIO_PIN_NOPULL); + } + + // - MCK (optional) - always output, + if (p_config->mck_pin != NRFX_I2S_PIN_NOT_USED) + { + mck_pin = p_config->mck_pin; + nrf_gpio_cfg_output(mck_pin); + } + else + { + mck_pin = NRF_I2S_PIN_NOT_CONNECTED; + } + + // - SDOUT (optional) - always output, + if (p_config->sdout_pin != NRFX_I2S_PIN_NOT_USED) + { + sdout_pin = p_config->sdout_pin; + nrf_gpio_cfg_output(sdout_pin); + } + else + { + sdout_pin = NRF_I2S_PIN_NOT_CONNECTED; + } + + // - SDIN (optional) - always input. + if (p_config->sdin_pin != NRFX_I2S_PIN_NOT_USED) + { + sdin_pin = p_config->sdin_pin; + nrf_gpio_cfg_input(sdin_pin, NRF_GPIO_PIN_NOPULL); + } + else + { + sdin_pin = NRF_I2S_PIN_NOT_CONNECTED; + } + + nrf_i2s_pins_set(NRF_I2S, + p_config->sck_pin, + p_config->lrck_pin, + mck_pin, + sdout_pin, + sdin_pin); +} + + +nrfx_err_t nrfx_i2s_init(nrfx_i2s_config_t const * p_config, + nrfx_i2s_data_handler_t handler) +{ + NRFX_ASSERT(p_config); + NRFX_ASSERT(handler); + + nrfx_err_t err_code; + + if (m_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 (!nrf_i2s_configure(NRF_I2S, + p_config->mode, + p_config->format, + p_config->alignment, + p_config->sample_width, + p_config->channels, + p_config->mck_setup, + p_config->ratio)) + { + err_code = NRFX_ERROR_INVALID_PARAM; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + configure_pins(p_config); + + m_cb.handler = handler; + + NRFX_IRQ_PRIORITY_SET(I2S_IRQn, p_config->irq_priority); + NRFX_IRQ_ENABLE(I2S_IRQn); + + m_cb.state = NRFX_DRV_STATE_INITIALIZED; + + NRFX_LOG_INFO("Initialized."); + return NRFX_SUCCESS; +} + + +void nrfx_i2s_uninit(void) +{ + NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); + + nrfx_i2s_stop(); + + NRFX_IRQ_DISABLE(I2S_IRQn); + + nrf_i2s_pins_set(NRF_I2S, + NRF_I2S_PIN_NOT_CONNECTED, + NRF_I2S_PIN_NOT_CONNECTED, + NRF_I2S_PIN_NOT_CONNECTED, + NRF_I2S_PIN_NOT_CONNECTED, + NRF_I2S_PIN_NOT_CONNECTED); + + m_cb.state = NRFX_DRV_STATE_UNINITIALIZED; + NRFX_LOG_INFO("Uninitialized."); +} + + +nrfx_err_t nrfx_i2s_start(nrfx_i2s_buffers_t const * p_initial_buffers, + uint16_t buffer_size, + uint8_t flags) +{ + NRFX_ASSERT(p_initial_buffers != NULL); + NRFX_ASSERT(p_initial_buffers->p_rx_buffer != NULL || + p_initial_buffers->p_tx_buffer != NULL); + NRFX_ASSERT(buffer_size != 0); + (void)(flags); + + nrfx_err_t err_code; + + if (m_cb.state != NRFX_DRV_STATE_INITIALIZED) + { + 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 (((p_initial_buffers->p_rx_buffer != NULL) + && !nrfx_is_in_ram(p_initial_buffers->p_rx_buffer)) + || + ((p_initial_buffers->p_tx_buffer != NULL) + && !nrfx_is_in_ram(p_initial_buffers->p_tx_buffer))) + { + 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; + } + + m_cb.use_rx = (p_initial_buffers->p_rx_buffer != NULL); + m_cb.use_tx = (p_initial_buffers->p_tx_buffer != NULL); + m_cb.rx_ready = false; + m_cb.tx_ready = false; + m_cb.buffers_needed = false; + m_cb.buffer_size = buffer_size; + + // Set the provided initial buffers as next, they will become the current + // ones after the IRQ handler is called for the first time, what will occur + // right after the START task is triggered. + m_cb.next_buffers = *p_initial_buffers; + m_cb.current_buffers.p_rx_buffer = NULL; + m_cb.current_buffers.p_tx_buffer = NULL; + + nrf_i2s_transfer_set(NRF_I2S, + m_cb.buffer_size, + m_cb.next_buffers.p_rx_buffer, + m_cb.next_buffers.p_tx_buffer); + + nrf_i2s_enable(NRF_I2S); + + m_cb.state = NRFX_DRV_STATE_POWERED_ON; + + nrf_i2s_event_clear(NRF_I2S, NRF_I2S_EVENT_RXPTRUPD); + nrf_i2s_event_clear(NRF_I2S, NRF_I2S_EVENT_TXPTRUPD); + nrf_i2s_event_clear(NRF_I2S, NRF_I2S_EVENT_STOPPED); + nrf_i2s_int_enable(NRF_I2S, (m_cb.use_rx ? NRF_I2S_INT_RXPTRUPD_MASK : 0) | + (m_cb.use_tx ? NRF_I2S_INT_TXPTRUPD_MASK : 0) | + NRF_I2S_INT_STOPPED_MASK); + nrf_i2s_task_trigger(NRF_I2S, NRF_I2S_TASK_START); + + NRFX_LOG_INFO("Started."); + return NRFX_SUCCESS; +} + + +nrfx_err_t nrfx_i2s_next_buffers_set(nrfx_i2s_buffers_t const * p_buffers) +{ + NRFX_ASSERT(m_cb.state == NRFX_DRV_STATE_POWERED_ON); + NRFX_ASSERT(p_buffers); + + nrfx_err_t err_code; + + if (!m_cb.buffers_needed) + { + 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 (((p_buffers->p_rx_buffer != NULL) + && !nrfx_is_in_ram(p_buffers->p_rx_buffer)) + || + ((p_buffers->p_tx_buffer != NULL) + && !nrfx_is_in_ram(p_buffers->p_tx_buffer))) + { + 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; + } + + if (m_cb.use_tx) + { + NRFX_ASSERT(p_buffers->p_tx_buffer != NULL); + nrf_i2s_tx_buffer_set(NRF_I2S, p_buffers->p_tx_buffer); + } + if (m_cb.use_rx) + { + NRFX_ASSERT(p_buffers->p_rx_buffer != NULL); + nrf_i2s_rx_buffer_set(NRF_I2S, p_buffers->p_rx_buffer); + } + + m_cb.next_buffers = *p_buffers; + m_cb.buffers_needed = false; + + return NRFX_SUCCESS; +} + + +void nrfx_i2s_stop(void) +{ + NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); + + m_cb.buffers_needed = false; + + // First disable interrupts, then trigger the STOP task, so no spurious + // RXPTRUPD and TXPTRUPD events (see nRF52 anomaly 55) are processed. + nrf_i2s_int_disable(NRF_I2S, NRF_I2S_INT_RXPTRUPD_MASK | + NRF_I2S_INT_TXPTRUPD_MASK); + nrf_i2s_task_trigger(NRF_I2S, NRF_I2S_TASK_STOP); +} + + +void nrfx_i2s_irq_handler(void) +{ + if (nrf_i2s_event_check(NRF_I2S, NRF_I2S_EVENT_TXPTRUPD)) + { + nrf_i2s_event_clear(NRF_I2S, NRF_I2S_EVENT_TXPTRUPD); + m_cb.tx_ready = true; + if (m_cb.use_tx && m_cb.buffers_needed) + { + m_cb.buffers_reused = true; + } + } + if (nrf_i2s_event_check(NRF_I2S, NRF_I2S_EVENT_RXPTRUPD)) + { + nrf_i2s_event_clear(NRF_I2S, NRF_I2S_EVENT_RXPTRUPD); + m_cb.rx_ready = true; + if (m_cb.use_rx && m_cb.buffers_needed) + { + m_cb.buffers_reused = true; + } + } + + if (nrf_i2s_event_check(NRF_I2S, NRF_I2S_EVENT_STOPPED)) + { + nrf_i2s_event_clear(NRF_I2S, NRF_I2S_EVENT_STOPPED); + nrf_i2s_int_disable(NRF_I2S, NRF_I2S_INT_STOPPED_MASK); + nrf_i2s_disable(NRF_I2S); + + // When stopped, release all buffers, including these scheduled for + // the next transfer. + m_cb.handler(&m_cb.current_buffers, 0); + m_cb.handler(&m_cb.next_buffers, 0); + + m_cb.state = NRFX_DRV_STATE_INITIALIZED; + NRFX_LOG_INFO("Stopped."); + } + else + { + // Check if the requested transfer has been completed: + // - full-duplex mode + if ((m_cb.use_tx && m_cb.use_rx && m_cb.tx_ready && m_cb.rx_ready) || + // - TX only mode + (!m_cb.use_rx && m_cb.tx_ready) || + // - RX only mode + (!m_cb.use_tx && m_cb.rx_ready)) + { + m_cb.tx_ready = false; + m_cb.rx_ready = false; + + // If the application did not supply the buffers for the next + // part of the transfer until this moment, the current buffers + // cannot be released, since the I2S peripheral already started + // using them. Signal this situation to the application by + // passing NULL instead of the structure with released buffers. + if (m_cb.buffers_reused) + { + m_cb.buffers_reused = false; + // This will most likely be set at this point. However, there is + // a small time window between TXPTRUPD and RXPTRUPD events, + // and it is theoretically possible that next buffers will be + // set in this window, so to be sure this flag is set to true, + // set it explicitly. + m_cb.buffers_needed = true; + m_cb.handler(NULL, + NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED); + } + else + { + // Buffers that have been used by the I2S peripheral (current) + // are now released and will be returned to the application, + // and the ones scheduled to be used as next become the current + // ones. + nrfx_i2s_buffers_t released_buffers = m_cb.current_buffers; + m_cb.current_buffers = m_cb.next_buffers; + m_cb.next_buffers.p_rx_buffer = NULL; + m_cb.next_buffers.p_tx_buffer = NULL; + m_cb.buffers_needed = true; + m_cb.handler(&released_buffers, + NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED); + } + + } + } +} + +#endif // NRFX_CHECK(NRFX_I2S_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_lpcomp.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_lpcomp.c new file mode 100644 index 0000000..024eda6 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_lpcomp.c @@ -0,0 +1,174 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_LPCOMP_ENABLED) + +#include <nrfx_lpcomp.h> +#include "prs/nrfx_prs.h" + +#define NRFX_LOG_MODULE LPCOMP +#include <nrfx_log.h> + +#define EVT_TO_STR(event) \ + (event == NRF_LPCOMP_EVENT_READY ? "NRF_LPCOMP_EVENT_READY" : \ + (event == NRF_LPCOMP_EVENT_DOWN ? "NRF_LPCOMP_EVENT_DOWN" : \ + (event == NRF_LPCOMP_EVENT_UP ? "NRF_LPCOMP_EVENT_UP" : \ + (event == NRF_LPCOMP_EVENT_CROSS ? "NRF_LPCOMP_EVENT_CROSS" : \ + "UNKNOWN EVENT")))) + + +static nrfx_lpcomp_event_handler_t m_lpcomp_event_handler = NULL; +static nrfx_drv_state_t m_state = NRFX_DRV_STATE_UNINITIALIZED; + +static void lpcomp_execute_handler(nrf_lpcomp_event_t event, uint32_t event_mask) +{ + if (nrf_lpcomp_event_check(event) && nrf_lpcomp_int_enable_check(event_mask)) + { + nrf_lpcomp_event_clear(event); + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(event)); + + m_lpcomp_event_handler(event); + } +} + +void nrfx_lpcomp_irq_handler(void) +{ + lpcomp_execute_handler(NRF_LPCOMP_EVENT_READY, LPCOMP_INTENSET_READY_Msk); + lpcomp_execute_handler(NRF_LPCOMP_EVENT_DOWN, LPCOMP_INTENSET_DOWN_Msk); + lpcomp_execute_handler(NRF_LPCOMP_EVENT_UP, LPCOMP_INTENSET_UP_Msk); + lpcomp_execute_handler(NRF_LPCOMP_EVENT_CROSS, LPCOMP_INTENSET_CROSS_Msk); +} + +nrfx_err_t nrfx_lpcomp_init(nrfx_lpcomp_config_t const * p_config, + nrfx_lpcomp_event_handler_t event_handler) +{ + NRFX_ASSERT(p_config); + NRFX_ASSERT(event_handler); + nrfx_err_t err_code; + + if (m_state != NRFX_DRV_STATE_UNINITIALIZED) + { // LPCOMP driver is already initialized + 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; + } + + m_lpcomp_event_handler = event_handler; + +#if NRFX_CHECK(NRFX_PRS_ENABLED) + if (nrfx_prs_acquire(NRF_LPCOMP, nrfx_lpcomp_irq_handler) != 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 + + nrf_lpcomp_configure(&(p_config->hal)); + + nrf_lpcomp_input_select(p_config->input); + + switch (p_config->hal.detection) + { + case NRF_LPCOMP_DETECT_UP: + nrf_lpcomp_int_enable(LPCOMP_INTENSET_UP_Msk); + break; + + case NRF_LPCOMP_DETECT_DOWN: + nrf_lpcomp_int_enable(LPCOMP_INTENSET_DOWN_Msk); + break; + + case NRF_LPCOMP_DETECT_CROSS: + nrf_lpcomp_int_enable(LPCOMP_INTENSET_CROSS_Msk); + break; + + default: + break; + } + nrf_lpcomp_shorts_enable(NRF_LPCOMP_SHORT_READY_SAMPLE_MASK); + + NRFX_IRQ_PRIORITY_SET(LPCOMP_IRQn, p_config->interrupt_priority); + NRFX_IRQ_ENABLE(LPCOMP_IRQn); + + m_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_lpcomp_uninit(void) +{ + NRFX_ASSERT(m_state != NRFX_DRV_STATE_UNINITIALIZED); + NRFX_IRQ_DISABLE(LPCOMP_IRQn); + nrfx_lpcomp_disable(); +#if NRFX_CHECK(NRFX_PRS_ENABLED) + nrfx_prs_release(NRF_LPCOMP); +#endif + m_state = NRFX_DRV_STATE_UNINITIALIZED; + m_lpcomp_event_handler = NULL; + NRFX_LOG_INFO("Uninitialized."); +} + +void nrfx_lpcomp_enable(void) +{ + NRFX_ASSERT(m_state == NRFX_DRV_STATE_INITIALIZED); + nrf_lpcomp_enable(); + nrf_lpcomp_task_trigger(NRF_LPCOMP_TASK_START); + m_state = NRFX_DRV_STATE_POWERED_ON; + NRFX_LOG_INFO("Enabled."); +} + +void nrfx_lpcomp_disable(void) +{ + NRFX_ASSERT(m_state == NRFX_DRV_STATE_POWERED_ON); + nrf_lpcomp_disable(); + nrf_lpcomp_task_trigger(NRF_LPCOMP_TASK_STOP); + m_state = NRFX_DRV_STATE_INITIALIZED; + NRFX_LOG_INFO("Disabled."); +} + +#endif // NRFX_CHECK(NRFX_LPCOMP_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_pdm.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_pdm.c new file mode 100644 index 0000000..db0945e --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_pdm.c @@ -0,0 +1,370 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_PDM_ENABLED) + +#include <nrfx_pdm.h> +#include <hal/nrf_gpio.h> + +#define NRFX_LOG_MODULE PDM +#include <nrfx_log.h> + +#define EVT_TO_STR(event) \ + (event == NRF_PDM_EVENT_STARTED ? "NRF_PDM_EVENT_STARTED" : \ + (event == NRF_PDM_EVENT_STOPPED ? "NRF_PDM_EVENT_STOPPED" : \ + (event == NRF_PDM_EVENT_END ? "NRF_PDM_EVENT_END" : \ + "UNKNOWN EVENT"))) + + +/** @brief PDM interface status. */ +typedef enum +{ + NRFX_PDM_STATE_IDLE, + NRFX_PDM_STATE_RUNNING, + NRFX_PDM_STATE_STARTING, + NRFX_PDM_STATE_STOPPING +} nrfx_pdm_state_t; + +/** @brief PDM interface control block.*/ +typedef struct +{ + nrfx_pdm_event_handler_t event_handler; ///< Event handler function pointer. + int16_t * buff_address[2]; ///< Sample buffers. + uint16_t buff_length[2]; ///< Length of the sample buffers. + nrfx_drv_state_t drv_state; ///< Driver state. + volatile nrfx_pdm_state_t op_state; ///< PDM peripheral operation state. + uint8_t active_buffer; ///< Number of currently active buffer. + uint8_t error; ///< Driver error flag. + volatile uint8_t irq_buff_request; ///< Request the next buffer in the ISR. +} nrfx_pdm_cb_t; + +static nrfx_pdm_cb_t m_cb; + + +void nrfx_pdm_irq_handler(void) +{ + if (nrf_pdm_event_check(NRF_PDM_EVENT_STARTED)) + { + nrf_pdm_event_clear(NRF_PDM_EVENT_STARTED); + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_PDM_EVENT_STARTED)); + + uint8_t finished_buffer = m_cb.active_buffer; + + // Check if the next buffer was set before. + uint8_t next_buffer = (~m_cb.active_buffer) & 0x01; + if (m_cb.buff_address[next_buffer] || + m_cb.op_state == NRFX_PDM_STATE_STARTING) + { + nrfx_pdm_evt_t evt; + evt.error = NRFX_PDM_NO_ERROR; + m_cb.error = 0; + + // Release the full buffer if ready and request the next one. + if (m_cb.op_state == NRFX_PDM_STATE_STARTING) + { + evt.buffer_released = 0; + m_cb.op_state = NRFX_PDM_STATE_RUNNING; + } + else + { + evt.buffer_released = m_cb.buff_address[finished_buffer]; + m_cb.buff_address[finished_buffer] = 0; + m_cb.active_buffer = next_buffer; + } + evt.buffer_requested = true; + m_cb.event_handler(&evt); + } + else + { + // No next buffer available. Report an error. + // Do not request the new buffer as it was already done. + if (m_cb.error == 0) + { + nrfx_pdm_evt_t const evt = { + .buffer_requested = false, + .buffer_released = NULL, + .error = NRFX_PDM_ERROR_OVERFLOW + }; + m_cb.error = 1; + m_cb.event_handler(&evt); + } + } + + if (m_cb.op_state == NRFX_PDM_STATE_STARTING) + { + m_cb.op_state = NRFX_PDM_STATE_RUNNING; + } + } + else if (nrf_pdm_event_check(NRF_PDM_EVENT_STOPPED)) + { + nrf_pdm_event_clear(NRF_PDM_EVENT_STOPPED); + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_PDM_EVENT_STOPPED)); + nrf_pdm_disable(); + m_cb.op_state = NRFX_PDM_STATE_IDLE; + + // Release the buffers. + nrfx_pdm_evt_t evt; + evt.error = NRFX_PDM_NO_ERROR; + evt.buffer_requested = false; + if (m_cb.buff_address[m_cb.active_buffer]) + { + evt.buffer_released = m_cb.buff_address[m_cb.active_buffer]; + m_cb.buff_address[m_cb.active_buffer] = 0; + m_cb.event_handler(&evt); + } + + uint8_t second_buffer = (~m_cb.active_buffer) & 0x01; + if (m_cb.buff_address[second_buffer]) + { + evt.buffer_released = m_cb.buff_address[second_buffer]; + m_cb.buff_address[second_buffer] = 0; + m_cb.event_handler(&evt); + } + m_cb.active_buffer = 0; + } + + if (m_cb.irq_buff_request) + { + nrfx_pdm_evt_t const evt = + { + .buffer_requested = true, + .buffer_released = NULL, + .error = NRFX_PDM_NO_ERROR, + }; + m_cb.irq_buff_request = 0; + m_cb.event_handler(&evt); + } +} + + +nrfx_err_t nrfx_pdm_init(nrfx_pdm_config_t const * p_config, + nrfx_pdm_event_handler_t event_handler) +{ + NRFX_ASSERT(p_config); + NRFX_ASSERT(event_handler); + nrfx_err_t err_code; + + if (m_cb.drv_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 (p_config->gain_l > NRF_PDM_GAIN_MAXIMUM || + p_config->gain_r > NRF_PDM_GAIN_MAXIMUM) + { + err_code = NRFX_ERROR_INVALID_PARAM; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + + m_cb.buff_address[0] = 0; + m_cb.buff_address[1] = 0; + m_cb.active_buffer = 0; + m_cb.error = 0; + m_cb.event_handler = event_handler; + m_cb.op_state = NRFX_PDM_STATE_IDLE; + + nrf_pdm_clock_set(p_config->clock_freq); + nrf_pdm_mode_set(p_config->mode, p_config->edge); + nrf_pdm_gain_set(p_config->gain_l, p_config->gain_r); + + nrf_gpio_cfg_output(p_config->pin_clk); + nrf_gpio_pin_clear(p_config->pin_clk); + nrf_gpio_cfg_input(p_config->pin_din, NRF_GPIO_PIN_NOPULL); + nrf_pdm_psel_connect(p_config->pin_clk, p_config->pin_din); + + nrf_pdm_event_clear(NRF_PDM_EVENT_STARTED); + nrf_pdm_event_clear(NRF_PDM_EVENT_END); + nrf_pdm_event_clear(NRF_PDM_EVENT_STOPPED); + nrf_pdm_int_enable(NRF_PDM_INT_STARTED | NRF_PDM_INT_STOPPED); + NRFX_IRQ_PRIORITY_SET(PDM_IRQn, p_config->interrupt_priority); + NRFX_IRQ_ENABLE(PDM_IRQn); + m_cb.drv_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_pdm_uninit(void) +{ + nrf_pdm_disable(); + nrf_pdm_psel_disconnect(); + m_cb.drv_state = NRFX_DRV_STATE_UNINITIALIZED; + NRFX_LOG_INFO("Uninitialized."); +} + +static void pdm_start() +{ + m_cb.drv_state = NRFX_DRV_STATE_POWERED_ON; + nrf_pdm_enable(); + nrf_pdm_event_clear(NRF_PDM_EVENT_STARTED); + nrf_pdm_task_trigger(NRF_PDM_TASK_START); +} + +static void pdm_buf_request() +{ + m_cb.irq_buff_request = 1; + NRFX_IRQ_PENDING_SET(PDM_IRQn); +} + +nrfx_err_t nrfx_pdm_start(void) +{ + NRFX_ASSERT(m_cb.drv_state != NRFX_DRV_STATE_UNINITIALIZED); + nrfx_err_t err_code; + + if (m_cb.op_state != NRFX_PDM_STATE_IDLE) + { + if (m_cb.op_state == NRFX_PDM_STATE_RUNNING) + { + err_code = NRFX_SUCCESS; + NRFX_LOG_INFO("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + err_code = NRFX_ERROR_BUSY; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + + m_cb.op_state = NRFX_PDM_STATE_STARTING; + pdm_buf_request(); + + 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_pdm_buffer_set(int16_t * buffer, uint16_t buffer_length) +{ + if (m_cb.drv_state == NRFX_DRV_STATE_UNINITIALIZED) + { + return NRFX_ERROR_INVALID_STATE; + } + if (m_cb.op_state == NRFX_PDM_STATE_STOPPING) + { + return NRFX_ERROR_BUSY; + } + if ((buffer == NULL) || (buffer_length > NRFX_PDM_MAX_BUFFER_SIZE)) + { + return NRFX_ERROR_INVALID_PARAM; + } + + nrfx_err_t err_code = NRFX_SUCCESS; + + // Enter the PDM critical section. + NRFX_IRQ_DISABLE(PDM_IRQn); + + uint8_t next_buffer = (~m_cb.active_buffer) & 0x01; + if (m_cb.op_state == NRFX_PDM_STATE_STARTING) + { + next_buffer = 0; + } + + if (m_cb.buff_address[next_buffer]) + { + // Buffer already set. + err_code = NRFX_ERROR_BUSY; + } + else + { + m_cb.buff_address[next_buffer] = buffer; + m_cb.buff_length[next_buffer] = buffer_length; + nrf_pdm_buffer_set((uint32_t *)buffer, buffer_length); + + if (m_cb.drv_state != NRFX_DRV_STATE_POWERED_ON) + { + pdm_start(); + } + } + + NRFX_IRQ_ENABLE(PDM_IRQn); + return err_code; +} + +nrfx_err_t nrfx_pdm_stop(void) +{ + NRFX_ASSERT(m_cb.drv_state != NRFX_DRV_STATE_UNINITIALIZED); + nrfx_err_t err_code; + + if (m_cb.op_state != NRFX_PDM_STATE_RUNNING) + { + if (m_cb.op_state == NRFX_PDM_STATE_IDLE || + m_cb.op_state == NRFX_PDM_STATE_STARTING) + { + nrf_pdm_disable(); + m_cb.op_state = NRFX_PDM_STATE_IDLE; + err_code = NRFX_SUCCESS; + NRFX_LOG_INFO("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + err_code = NRFX_ERROR_BUSY; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + m_cb.drv_state = NRFX_DRV_STATE_INITIALIZED; + m_cb.op_state = NRFX_PDM_STATE_STOPPING; + + nrf_pdm_task_trigger(NRF_PDM_TASK_STOP); + err_code = NRFX_SUCCESS; + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + +#endif // NRFX_CHECK(NRFX_PDM_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_power.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_power.c new file mode 100644 index 0000000..d861951 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_power.c @@ -0,0 +1,306 @@ +/** + * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_POWER_ENABLED) + +#include <nrfx_power.h> + +#if NRFX_CHECK(NRFX_CLOCK_ENABLED) +extern bool nrfx_clock_irq_enabled; +#endif + +/** + * @internal + * @defgroup nrfx_power_internals POWER driver internals + * @ingroup nrfx_power + * + * Internal variables, auxiliary macros and functions of POWER driver. + * @{ + */ + +/** + * This variable is used to check whether common POWER_CLOCK common interrupt + * should be disabled or not if @ref nrfx_clock tries to disable the interrupt. + */ + +bool nrfx_power_irq_enabled; + +/** + * @brief The initialization flag + */ + +#define m_initialized nrfx_power_irq_enabled + +/** + * @brief The handler of power fail comparator warning event + */ +static nrfx_power_pofwarn_event_handler_t m_pofwarn_handler; + +#if NRF_POWER_HAS_SLEEPEVT || defined(__NRFX_DOXYGEN__) +/** + * @brief The handler of sleep event handler + */ +static nrfx_power_sleep_event_handler_t m_sleepevt_handler; +#endif + +#if NRF_POWER_HAS_USBREG || defined(__NRFX_DOXYGEN__) +/** + * @brief The handler of USB power events + */ +static nrfx_power_usb_event_handler_t m_usbevt_handler; +#endif + +/** @} */ + +nrfx_power_pofwarn_event_handler_t nrfx_power_pof_handler_get(void) +{ + return m_pofwarn_handler; +} + +#if NRF_POWER_HAS_USBREG +nrfx_power_usb_event_handler_t nrfx_power_usb_handler_get(void) +{ + return m_usbevt_handler; +} +#endif + +nrfx_err_t nrfx_power_init(nrfx_power_config_t const * p_config) +{ + NRFX_ASSERT(p_config); + if (m_initialized) + { + return NRFX_ERROR_ALREADY_INITIALIZED; + } + +#if NRF_POWER_HAS_VDDH + nrf_power_dcdcen_vddh_set(p_config->dcdcenhv); +#endif + nrf_power_dcdcen_set(p_config->dcdcen); + + nrfx_power_clock_irq_init(); + + m_initialized = true; + return NRFX_SUCCESS; +} + + +void nrfx_power_uninit(void) +{ + NRFX_ASSERT(m_initialized); + +#if NRFX_CHECK(NRFX_CLOCK_ENABLED) + if (!nrfx_clock_irq_enabled) +#endif + { + NRFX_IRQ_DISABLE(POWER_CLOCK_IRQn); + } + + nrfx_power_pof_uninit(); +#if NRF_POWER_HAS_SLEEPEVT || defined(__NRFX_DOXYGEN__) + nrfx_power_sleepevt_uninit(); +#endif +#if NRF_POWER_HAS_USBREG || defined(__NRFX_DOXYGEN__) + nrfx_power_usbevt_uninit(); +#endif + m_initialized = false; +} + +void nrfx_power_pof_init(nrfx_power_pofwarn_config_t const * p_config) +{ + NRFX_ASSERT(p_config != NULL); + + nrfx_power_pof_uninit(); + + if (p_config->handler != NULL) + { + m_pofwarn_handler = p_config->handler; + } +} + +void nrfx_power_pof_enable(nrfx_power_pofwarn_config_t const * p_config) +{ + nrf_power_pofcon_set(true, p_config->thr); +#if NRF_POWER_HAS_VDDH || defined(__NRFX_DOXYGEN__) + nrf_power_pofcon_vddh_set(p_config->thrvddh); +#endif + if (m_pofwarn_handler != NULL) + { + nrf_power_int_enable(NRF_POWER_INT_POFWARN_MASK); + } +} + +void nrfx_power_pof_disable(void) +{ + nrf_power_int_disable(NRF_POWER_INT_POFWARN_MASK); +} + +void nrfx_power_pof_uninit(void) +{ + m_pofwarn_handler = NULL; +} + +#if NRF_POWER_HAS_SLEEPEVT || defined(__NRFX_DOXYGEN__) +void nrfx_power_sleepevt_init(nrfx_power_sleepevt_config_t const * p_config) +{ + NRFX_ASSERT(p_config != NULL); + + nrfx_power_sleepevt_uninit(); + if (p_config->handler != NULL) + { + m_sleepevt_handler = p_config->handler; + } +} + +void nrfx_power_sleepevt_enable(nrfx_power_sleepevt_config_t const * p_config) +{ + uint32_t enmask = 0; + if (p_config->en_enter) + { + enmask |= NRF_POWER_INT_SLEEPENTER_MASK; + nrf_power_event_clear(NRF_POWER_EVENT_SLEEPENTER); + } + if (p_config->en_exit) + { + enmask |= NRF_POWER_INT_SLEEPEXIT_MASK; + nrf_power_event_clear(NRF_POWER_EVENT_SLEEPEXIT); + } + nrf_power_int_enable(enmask); +} + +void nrfx_power_sleepevt_disable(void) +{ + nrf_power_int_disable( + NRF_POWER_INT_SLEEPENTER_MASK | + NRF_POWER_INT_SLEEPEXIT_MASK); +} + +void nrfx_power_sleepevt_uninit(void) +{ + m_sleepevt_handler = NULL; +} +#endif /* NRF_POWER_HAS_SLEEPEVT */ + +#if NRF_POWER_HAS_USBREG || defined(__NRFX_DOXYGEN__) +void nrfx_power_usbevt_init(nrfx_power_usbevt_config_t const * p_config) +{ + nrfx_power_usbevt_uninit(); + if (p_config->handler != NULL) + { + m_usbevt_handler = p_config->handler; + } +} + +void nrfx_power_usbevt_enable(void) +{ + nrf_power_int_enable( + NRF_POWER_INT_USBDETECTED_MASK | + NRF_POWER_INT_USBREMOVED_MASK | + NRF_POWER_INT_USBPWRRDY_MASK); +} + +void nrfx_power_usbevt_disable(void) +{ + nrf_power_int_disable( + NRF_POWER_INT_USBDETECTED_MASK | + NRF_POWER_INT_USBREMOVED_MASK | + NRF_POWER_INT_USBPWRRDY_MASK); +} + +void nrfx_power_usbevt_uninit(void) +{ + m_usbevt_handler = NULL; +} +#endif /* NRF_POWER_HAS_USBREG */ + + +void nrfx_power_irq_handler(void) +{ + uint32_t enabled = nrf_power_int_enable_get(); + if ((0 != (enabled & NRF_POWER_INT_POFWARN_MASK)) && + nrf_power_event_get_and_clear(NRF_POWER_EVENT_POFWARN)) + { + /* Cannot be null if event is enabled */ + NRFX_ASSERT(m_pofwarn_handler != NULL); + m_pofwarn_handler(); + } +#if NRF_POWER_HAS_SLEEPEVT || defined(__NRFX_DOXYGEN__) + if ((0 != (enabled & NRF_POWER_INT_SLEEPENTER_MASK)) && + nrf_power_event_get_and_clear(NRF_POWER_EVENT_SLEEPENTER)) + { + /* Cannot be null if event is enabled */ + NRFX_ASSERT(m_sleepevt_handler != NULL); + m_sleepevt_handler(NRFX_POWER_SLEEP_EVT_ENTER); + } + if ((0 != (enabled & NRF_POWER_INT_SLEEPEXIT_MASK)) && + nrf_power_event_get_and_clear(NRF_POWER_EVENT_SLEEPEXIT)) + { + /* Cannot be null if event is enabled */ + NRFX_ASSERT(m_sleepevt_handler != NULL); + m_sleepevt_handler(NRFX_POWER_SLEEP_EVT_EXIT); + } +#endif +#if NRF_POWER_HAS_USBREG || defined(__NRFX_DOXYGEN__) + if ((0 != (enabled & NRF_POWER_INT_USBDETECTED_MASK)) && + nrf_power_event_get_and_clear(NRF_POWER_EVENT_USBDETECTED)) + { + /* Cannot be null if event is enabled */ + NRFX_ASSERT(m_usbevt_handler != NULL); + m_usbevt_handler(NRFX_POWER_USB_EVT_DETECTED); + } + if ((0 != (enabled & NRF_POWER_INT_USBREMOVED_MASK)) && + nrf_power_event_get_and_clear(NRF_POWER_EVENT_USBREMOVED)) + { + /* Cannot be null if event is enabled */ + NRFX_ASSERT(m_usbevt_handler != NULL); + m_usbevt_handler(NRFX_POWER_USB_EVT_REMOVED); + } + if ((0 != (enabled & NRF_POWER_INT_USBPWRRDY_MASK)) && + nrf_power_event_get_and_clear(NRF_POWER_EVENT_USBPWRRDY)) + { + /* Cannot be null if event is enabled */ + NRFX_ASSERT(m_usbevt_handler != NULL); + m_usbevt_handler(NRFX_POWER_USB_EVT_READY); + } +#endif +} + +#endif // NRFX_CHECK(NRFX_POWER_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_power_clock.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_power_clock.c new file mode 100644 index 0000000..ff69bf7 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_power_clock.c @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> +#include <nrfx_power.h> +#include <nrfx_clock.h> + + +#if NRFX_CHECK(NRFX_POWER_ENABLED) && NRFX_CHECK(NRFX_CLOCK_ENABLED) +void nrfx_power_clock_irq_handler(void) +{ + nrfx_power_irq_handler(); + nrfx_clock_irq_handler(); +} +#endif diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_ppi.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_ppi.c new file mode 100644 index 0000000..067ba18 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_ppi.c @@ -0,0 +1,534 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_PPI_ENABLED) + +#include <nrfx_ppi.h> + +#define NRFX_LOG_MODULE_NAME PPI +#include <nrfx_log.h> + + +static uint32_t m_channels_allocated; /**< Bitmap representing channels availability. 1 when a channel is allocated, 0 otherwise. */ +static uint8_t m_groups_allocated; /**< Bitmap representing groups availability. 1 when a group is allocated, 0 otherwise.*/ + + +/** + * @brief Compute a group mask (needed for driver internals, not used for NRF_PPI registers). + * + * @param[in] group Group number to transform to a mask. + * + * @retval Group mask. + */ +__STATIC_INLINE uint32_t group_to_mask(nrf_ppi_channel_group_t group) +{ + return (1uL << (uint32_t) group); +} + + +/** + * @brief Check whether a channel is a programmable channel and can be used by an application. + * + * @param[in] channel Channel to check. + * + * @retval true The channel is a programmable application channel. + * @retval false The channel is used by a stack (for example SoftDevice) or is preprogrammed. + */ +__STATIC_INLINE bool is_programmable_app_channel(nrf_ppi_channel_t channel) +{ + return ((NRFX_PPI_PROG_APP_CHANNELS_MASK & nrfx_ppi_channel_to_mask(channel)) != 0); +} + + +/** + * @brief Check whether channels can be used by an application. + * + * @param[in] channel_mask Channel mask to check. + * + * @retval true All specified channels can be used by an application. + * @retval false At least one specified channel is used by a stack (for example SoftDevice). + */ +__STATIC_INLINE bool are_app_channels(uint32_t channel_mask) +{ + //lint -e(587) + return ((~(NRFX_PPI_ALL_APP_CHANNELS_MASK) & channel_mask) == 0); +} + + +/** + * @brief Check whether a channel can be used by an application. + * + * @param[in] channel Channel to check. + * + * @retval true The channel can be used by an application. + * @retval false The channel is used by a stack (for example SoftDevice). + */ +__STATIC_INLINE bool is_app_channel(nrf_ppi_channel_t channel) +{ + return are_app_channels(nrfx_ppi_channel_to_mask(channel)); +} + + +/** + * @brief Check whether a channel group can be used by an application. + * + * @param[in] group Group to check. + * + * @retval true The group is an application group. + * @retval false The group is not an application group (this group either does not exist or + * it is used by a stack (for example SoftDevice)). + */ +__STATIC_INLINE bool is_app_group(nrf_ppi_channel_group_t group) +{ + return ((NRFX_PPI_ALL_APP_GROUPS_MASK & group_to_mask(group)) != 0); +} + + +/** + * @brief Check whether a channel is allocated. + * + * @param[in] channel_num Channel number to check. + * + * @retval true The channel is allocated. + * @retval false The channel is not allocated. + */ +__STATIC_INLINE bool is_allocated_channel(nrf_ppi_channel_t channel) +{ + return ((m_channels_allocated & nrfx_ppi_channel_to_mask(channel)) != 0); +} + + +/** + * @brief Set channel allocated indication. + * + * @param[in] channel_num Specifies the channel to set the "allocated" indication. + */ +__STATIC_INLINE void channel_allocated_set(nrf_ppi_channel_t channel) +{ + m_channels_allocated |= nrfx_ppi_channel_to_mask(channel); +} + + +/** + * @brief Clear channel allocated indication. + * + * @param[in] channel_num Specifies the channel to clear the "allocated" indication. + */ +__STATIC_INLINE void channel_allocated_clr(nrf_ppi_channel_t channel) +{ + m_channels_allocated &= ~nrfx_ppi_channel_to_mask(channel); +} + + +/** + * @brief Clear all allocated channels. + */ +__STATIC_INLINE void channel_allocated_clr_all(void) +{ + m_channels_allocated &= ~NRFX_PPI_ALL_APP_CHANNELS_MASK; +} + + +/** + * @brief Check whether a group is allocated. + * + * @param[in] group_num Group number to check. + * + * @retval true The group is allocated. + * false The group is not allocated. + */ +__STATIC_INLINE bool is_allocated_group(nrf_ppi_channel_group_t group) +{ + return ((m_groups_allocated & group_to_mask(group)) != 0); +} + + +/** + * @brief Set group allocated indication. + * + * @param[in] group_num Specifies the group to set the "allocated" indication. + */ +__STATIC_INLINE void group_allocated_set(nrf_ppi_channel_group_t group) +{ + m_groups_allocated |= group_to_mask(group); +} + + +/** + * @brief Clear group allocated indication. + * + * @param[in] group_num Specifies the group to clear the "allocated" indication. + */ +__STATIC_INLINE void group_allocated_clr(nrf_ppi_channel_group_t group) +{ + m_groups_allocated &= ~group_to_mask(group); +} + + +/** + * @brief Clear all allocated groups. + */ +__STATIC_INLINE void group_allocated_clr_all() +{ + m_groups_allocated &= ~NRFX_PPI_ALL_APP_GROUPS_MASK; +} + + +void nrfx_ppi_free_all(void) +{ + uint32_t mask = NRFX_PPI_ALL_APP_GROUPS_MASK; + nrf_ppi_channel_group_t group; + + // Disable all channels and groups + nrf_ppi_channels_disable(NRFX_PPI_ALL_APP_CHANNELS_MASK); + + for (group = NRF_PPI_CHANNEL_GROUP0; mask != 0; mask &= ~group_to_mask(group), group++) + { + if (mask & group_to_mask(group)) + { + nrf_ppi_channel_group_clear(group); + } + } + channel_allocated_clr_all(); + group_allocated_clr_all(); +} + + +nrfx_err_t nrfx_ppi_channel_alloc(nrf_ppi_channel_t * p_channel) +{ + nrfx_err_t err_code = NRFX_SUCCESS; + nrf_ppi_channel_t channel; + uint32_t mask = 0; + err_code = NRFX_ERROR_NO_MEM; + + mask = NRFX_PPI_PROG_APP_CHANNELS_MASK; + for (channel = NRF_PPI_CHANNEL0; + mask != 0; + mask &= ~nrfx_ppi_channel_to_mask(channel), channel++) + { + NRFX_CRITICAL_SECTION_ENTER(); + if ((mask & nrfx_ppi_channel_to_mask(channel)) && (!is_allocated_channel(channel))) + { + channel_allocated_set(channel); + *p_channel = channel; + err_code = NRFX_SUCCESS; + } + NRFX_CRITICAL_SECTION_EXIT(); + if (err_code == NRFX_SUCCESS) + { + NRFX_LOG_INFO("Allocated channel: %d.", channel); + break; + } + } + + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + + +nrfx_err_t nrfx_ppi_channel_free(nrf_ppi_channel_t channel) +{ + nrfx_err_t err_code = NRFX_SUCCESS; + + if (!is_programmable_app_channel(channel)) + { + err_code = NRFX_ERROR_INVALID_PARAM; + } + else + { + // First disable this channel + nrf_ppi_channel_disable(channel); + NRFX_CRITICAL_SECTION_ENTER(); + channel_allocated_clr(channel); + NRFX_CRITICAL_SECTION_EXIT(); + } + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + + +nrfx_err_t nrfx_ppi_channel_assign(nrf_ppi_channel_t channel, uint32_t eep, uint32_t tep) +{ + if ((uint32_t *)eep == NULL || (uint32_t *)tep == NULL) + { + return NRFX_ERROR_NULL; + } + + nrfx_err_t err_code = NRFX_SUCCESS; + + if (!is_programmable_app_channel(channel)) + { + err_code = NRFX_ERROR_INVALID_PARAM; + } + else if (!is_allocated_channel(channel)) + { + err_code = NRFX_ERROR_INVALID_STATE; + } + else + { + nrf_ppi_channel_endpoint_setup(channel, eep, tep); + NRFX_LOG_INFO("Assigned channel: %d, event end point: %x, task end point: %x.", + channel, + eep, + tep); + } + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + +nrfx_err_t nrfx_ppi_channel_fork_assign(nrf_ppi_channel_t channel, uint32_t fork_tep) +{ + nrfx_err_t err_code = NRFX_SUCCESS; +#ifdef PPI_FEATURE_FORKS_PRESENT + if (!is_programmable_app_channel(channel)) + { + err_code = NRFX_ERROR_INVALID_PARAM; + } + else if (!is_allocated_channel(channel)) + { + err_code = NRFX_ERROR_INVALID_STATE; + } + else + { + nrf_ppi_fork_endpoint_setup(channel, fork_tep); + NRFX_LOG_INFO("Fork assigned channel: %d, task end point: %d.", channel, fork_tep); + } + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +#else + err_code = NRFX_ERROR_NOT_SUPPORTED; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +#endif +} + +nrfx_err_t nrfx_ppi_channel_enable(nrf_ppi_channel_t channel) +{ + nrfx_err_t err_code = NRFX_SUCCESS; + + if (!is_app_channel(channel)) + { + err_code = NRFX_ERROR_INVALID_PARAM; + } + else if (is_programmable_app_channel(channel) && !is_allocated_channel(channel)) + { + err_code = NRFX_ERROR_INVALID_STATE; + } + else + { + nrf_ppi_channel_enable(channel); + } + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + + +nrfx_err_t nrfx_ppi_channel_disable(nrf_ppi_channel_t channel) +{ + nrfx_err_t err_code = NRFX_SUCCESS; + + if (!is_app_channel(channel)) + { + err_code = NRFX_ERROR_INVALID_PARAM; + } + else if (is_programmable_app_channel(channel) && !is_allocated_channel(channel)) + { + err_code = NRFX_ERROR_INVALID_STATE; + } + else + { + nrf_ppi_channel_disable(channel); + 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_ppi_group_alloc(nrf_ppi_channel_group_t * p_group) +{ + nrfx_err_t err_code; + uint32_t mask = 0; + nrf_ppi_channel_group_t group; + + err_code = NRFX_ERROR_NO_MEM; + + mask = NRFX_PPI_ALL_APP_GROUPS_MASK; + for (group = NRF_PPI_CHANNEL_GROUP0; mask != 0; mask &= ~group_to_mask(group), group++) + { + NRFX_CRITICAL_SECTION_ENTER(); + if ((mask & group_to_mask(group)) && (!is_allocated_group(group))) + { + group_allocated_set(group); + *p_group = group; + err_code = NRFX_SUCCESS; + } + NRFX_CRITICAL_SECTION_EXIT(); + if (err_code == NRFX_SUCCESS) + { + NRFX_LOG_INFO("Allocated group: %d.", group); + break; + } + } + + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + + +nrfx_err_t nrfx_ppi_group_free(nrf_ppi_channel_group_t group) +{ + nrfx_err_t err_code = NRFX_SUCCESS; + + if (!is_app_group(group)) + { + err_code = NRFX_ERROR_INVALID_PARAM; + } + if (!is_allocated_group(group)) + { + err_code = NRFX_ERROR_INVALID_STATE; + } + else + { + nrf_ppi_group_disable(group); + NRFX_CRITICAL_SECTION_ENTER(); + group_allocated_clr(group); + NRFX_CRITICAL_SECTION_EXIT(); + } + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + + +nrfx_err_t nrfx_ppi_group_enable(nrf_ppi_channel_group_t group) +{ + nrfx_err_t err_code = NRFX_SUCCESS; + + if (!is_app_group(group)) + { + err_code = NRFX_ERROR_INVALID_PARAM; + } + else if (!is_allocated_group(group)) + { + err_code = NRFX_ERROR_INVALID_STATE; + } + else + { + nrf_ppi_group_enable(group); + } + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + + +nrfx_err_t nrfx_ppi_group_disable(nrf_ppi_channel_group_t group) +{ + nrfx_err_t err_code = NRFX_SUCCESS; + + if (!is_app_group(group)) + { + err_code = NRFX_ERROR_INVALID_PARAM; + } + else + { + nrf_ppi_group_disable(group); + } + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + +nrfx_err_t nrfx_ppi_channels_remove_from_group(uint32_t channel_mask, + nrf_ppi_channel_group_t group) +{ + nrfx_err_t err_code = NRFX_SUCCESS; + + if (!is_app_group(group)) + { + err_code = NRFX_ERROR_INVALID_PARAM; + } + else if (!is_allocated_group(group)) + { + err_code = NRFX_ERROR_INVALID_STATE; + } + else if (!are_app_channels(channel_mask)) + { + err_code = NRFX_ERROR_INVALID_PARAM; + } + else + { + NRFX_CRITICAL_SECTION_ENTER(); + nrf_ppi_channels_remove_from_group(channel_mask, group); + NRFX_CRITICAL_SECTION_EXIT(); + } + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + +nrfx_err_t nrfx_ppi_channels_include_in_group(uint32_t channel_mask, + nrf_ppi_channel_group_t group) +{ + nrfx_err_t err_code = NRFX_SUCCESS; + + if (!is_app_group(group)) + { + err_code = NRFX_ERROR_INVALID_PARAM; + } + else if (!is_allocated_group(group)) + { + err_code = NRFX_ERROR_INVALID_STATE; + } + else if (!are_app_channels(channel_mask)) + { + err_code = NRFX_ERROR_INVALID_PARAM; + } + else + { + NRFX_CRITICAL_SECTION_ENTER(); + nrf_ppi_channels_include_in_group(channel_mask, group); + NRFX_CRITICAL_SECTION_EXIT(); + } + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} +#endif // NRFX_CHECK(NRFX_PPI_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_pwm.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_pwm.c new file mode 100644 index 0000000..3a6581f --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_pwm.c @@ -0,0 +1,515 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_PWM_ENABLED) + +#if !(NRFX_CHECK(NRFX_PWM0_ENABLED) || NRFX_CHECK(NRFX_PWM1_ENABLED) || \ + NRFX_CHECK(NRFX_PWM2_ENABLED) || NRFX_CHECK(NRFX_PWM3_ENABLED)) +#error "No enabled PWM instances. Check <nrfx_config.h>." +#endif + +#include <nrfx_pwm.h> +#include <hal/nrf_gpio.h> + +#define NRFX_LOG_MODULE PWM +#include <nrfx_log.h> + +#if NRFX_CHECK(NRFX_PWM_NRF52_ANOMALY_109_WORKAROUND_ENABLED) +// The workaround uses interrupts to wake up the CPU and ensure it is active +// when PWM is about to start a DMA transfer. For initial transfer, done when +// a playback is started via PPI, a specific EGU instance is used to generate +// an interrupt. During the playback, the PWM interrupt triggered on SEQEND +// event of a preceding sequence is used to protect the transfer done for +// the next sequence to be played. +#include <hal/nrf_egu.h> +#define USE_DMA_ISSUE_WORKAROUND +#endif +#if defined(USE_DMA_ISSUE_WORKAROUND) +#define EGU_IRQn(i) EGU_IRQn_(i) +#define EGU_IRQn_(i) SWI##i##_EGU##i##_IRQn +#define EGU_IRQHandler(i) EGU_IRQHandler_(i) +#define EGU_IRQHandler_(i) nrfx_swi_##i##_irq_handler +#define DMA_ISSUE_EGU_IDX NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE +#define DMA_ISSUE_EGU NRFX_CONCAT_2(NRF_EGU, DMA_ISSUE_EGU_IDX) +#define DMA_ISSUE_EGU_IRQn EGU_IRQn(DMA_ISSUE_EGU_IDX) +#define DMA_ISSUE_EGU_IRQHandler EGU_IRQHandler(DMA_ISSUE_EGU_IDX) +#endif + +// Control block - driver instance local data. +typedef struct +{ +#if defined(USE_DMA_ISSUE_WORKAROUND) + uint32_t starting_task_address; +#endif + nrfx_pwm_handler_t handler; + nrfx_drv_state_t volatile state; + uint8_t flags; +} pwm_control_block_t; +static pwm_control_block_t m_cb[NRFX_PWM_ENABLED_COUNT]; + +static void configure_pins(nrfx_pwm_t const * const p_instance, + nrfx_pwm_config_t const * p_config) +{ + uint32_t out_pins[NRF_PWM_CHANNEL_COUNT]; + uint8_t i; + + for (i = 0; i < NRF_PWM_CHANNEL_COUNT; ++i) + { + uint8_t output_pin = p_config->output_pins[i]; + if (output_pin != NRFX_PWM_PIN_NOT_USED) + { + bool inverted = output_pin & NRFX_PWM_PIN_INVERTED; + out_pins[i] = output_pin & ~NRFX_PWM_PIN_INVERTED; + + if (inverted) + { + nrf_gpio_pin_set(out_pins[i]); + } + else + { + nrf_gpio_pin_clear(out_pins[i]); + } + + nrf_gpio_cfg_output(out_pins[i]); + } + else + { + out_pins[i] = NRF_PWM_PIN_NOT_CONNECTED; + } + } + + nrf_pwm_pins_set(p_instance->p_registers, out_pins); +} + + +nrfx_err_t nrfx_pwm_init(nrfx_pwm_t const * const p_instance, + nrfx_pwm_config_t const * p_config, + nrfx_pwm_handler_t handler) +{ + NRFX_ASSERT(p_config); + + nrfx_err_t err_code; + + pwm_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; + } + + p_cb->handler = handler; + + configure_pins(p_instance, p_config); + + nrf_pwm_enable(p_instance->p_registers); + nrf_pwm_configure(p_instance->p_registers, + p_config->base_clock, p_config->count_mode, p_config->top_value); + nrf_pwm_decoder_set(p_instance->p_registers, + p_config->load_mode, p_config->step_mode); + + nrf_pwm_shorts_set(p_instance->p_registers, 0); + nrf_pwm_int_set(p_instance->p_registers, 0); + nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_LOOPSDONE); + nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_SEQEND0); + nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_SEQEND1); + nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_STOPPED); + + // The workaround for nRF52 Anomaly 109 "protects" DMA transfers by handling + // interrupts generated on SEQEND0 and SEQEND1 events (this ensures that + // the 64 MHz clock is ready when data for the next sequence to be played + // is read). Therefore, the PWM interrupt must be enabled even if the event + // handler is not used. +#if defined(USE_DMA_ISSUE_WORKAROUND) + NRFX_IRQ_PRIORITY_SET(DMA_ISSUE_EGU_IRQn, p_config->irq_priority); + NRFX_IRQ_ENABLE(DMA_ISSUE_EGU_IRQn); +#else + if (p_cb->handler) +#endif + { + NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_registers), + p_config->irq_priority); + NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_registers)); + } + + 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_pwm_uninit(nrfx_pwm_t const * const p_instance) +{ + pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED); + + NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_registers)); +#if defined(USE_DMA_ISSUE_WORKAROUND) + NRFX_IRQ_DISABLE(DMA_ISSUE_EGU_IRQn); +#endif + + nrf_pwm_disable(p_instance->p_registers); + + p_cb->state = NRFX_DRV_STATE_UNINITIALIZED; +} + + +static uint32_t start_playback(nrfx_pwm_t const * const p_instance, + pwm_control_block_t * p_cb, + uint8_t flags, + nrf_pwm_task_t starting_task) +{ + p_cb->state = NRFX_DRV_STATE_POWERED_ON; + p_cb->flags = flags; + + if (p_cb->handler) + { + // The notification about finished playback is by default enabled, + // but this can be suppressed. + // The notification that the peripheral has stopped is always enabled. + uint32_t int_mask = NRF_PWM_INT_LOOPSDONE_MASK | + NRF_PWM_INT_STOPPED_MASK; + + // The workaround for nRF52 Anomaly 109 "protects" DMA transfers by + // handling interrupts generated on SEQEND0 and SEQEND1 events (see + // 'nrfx_pwm_init'), hence these events must be always enabled + // to generate interrupts. + // However, the user handler is called for them only when requested + // (see 'irq_handler'). +#if defined(USE_DMA_ISSUE_WORKAROUND) + int_mask |= NRF_PWM_INT_SEQEND0_MASK | NRF_PWM_INT_SEQEND1_MASK; +#else + if (flags & NRFX_PWM_FLAG_SIGNAL_END_SEQ0) + { + int_mask |= NRF_PWM_INT_SEQEND0_MASK; + } + if (flags & NRFX_PWM_FLAG_SIGNAL_END_SEQ1) + { + int_mask |= NRF_PWM_INT_SEQEND1_MASK; + } +#endif + if (flags & NRFX_PWM_FLAG_NO_EVT_FINISHED) + { + int_mask &= ~NRF_PWM_INT_LOOPSDONE_MASK; + } + + nrf_pwm_int_set(p_instance->p_registers, int_mask); + } +#if defined(USE_DMA_ISSUE_WORKAROUND) + else + { + nrf_pwm_int_set(p_instance->p_registers, + NRF_PWM_INT_SEQEND0_MASK | NRF_PWM_INT_SEQEND1_MASK); + } +#endif + + nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_STOPPED); + + if (flags & NRFX_PWM_FLAG_START_VIA_TASK) + { + uint32_t starting_task_address = + nrf_pwm_task_address_get(p_instance->p_registers, starting_task); + +#if defined(USE_DMA_ISSUE_WORKAROUND) + // To "protect" the initial DMA transfer it is required to start + // the PWM by triggering the proper task from EGU interrupt handler, + // it is not safe to do it directly via PPI. + p_cb->starting_task_address = starting_task_address; + nrf_egu_int_enable(DMA_ISSUE_EGU, + nrf_egu_int_get(DMA_ISSUE_EGU, p_instance->drv_inst_idx)); + return (uint32_t)nrf_egu_task_trigger_address_get(DMA_ISSUE_EGU, + p_instance->drv_inst_idx); +#else + return starting_task_address; +#endif + } + + nrf_pwm_task_trigger(p_instance->p_registers, starting_task); + return 0; +} + + +uint32_t nrfx_pwm_simple_playback(nrfx_pwm_t const * const p_instance, + nrf_pwm_sequence_t const * p_sequence, + uint16_t playback_count, + uint32_t flags) +{ + pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED); + NRFX_ASSERT(playback_count > 0); + NRFX_ASSERT(nrfx_is_in_ram(p_sequence->values.p_raw)); + + // To take advantage of the looping mechanism, we need to use both sequences + // (single sequence can be played back only once). + nrf_pwm_sequence_set(p_instance->p_registers, 0, p_sequence); + nrf_pwm_sequence_set(p_instance->p_registers, 1, p_sequence); + bool odd = (playback_count & 1); + nrf_pwm_loop_set(p_instance->p_registers, + (playback_count / 2) + (odd ? 1 : 0)); + + uint32_t shorts_mask; + if (flags & NRFX_PWM_FLAG_STOP) + { + shorts_mask = NRF_PWM_SHORT_LOOPSDONE_STOP_MASK; + } + else if (flags & NRFX_PWM_FLAG_LOOP) + { + shorts_mask = odd ? NRF_PWM_SHORT_LOOPSDONE_SEQSTART1_MASK + : NRF_PWM_SHORT_LOOPSDONE_SEQSTART0_MASK; + } + else + { + shorts_mask = 0; + } + nrf_pwm_shorts_set(p_instance->p_registers, shorts_mask); + + NRFX_LOG_INFO("Function: %s, sequence length: %d.", + __func__, + p_sequence->length); + NRFX_LOG_DEBUG("Sequence data:"); + NRFX_LOG_HEXDUMP_DEBUG((uint8_t *)p_sequence->values.p_raw, + p_sequence->length * sizeof(uint16_t)); + return start_playback(p_instance, p_cb, flags, + odd ? NRF_PWM_TASK_SEQSTART1 : NRF_PWM_TASK_SEQSTART0); +} + + +uint32_t nrfx_pwm_complex_playback(nrfx_pwm_t const * const p_instance, + nrf_pwm_sequence_t const * p_sequence_0, + nrf_pwm_sequence_t const * p_sequence_1, + uint16_t playback_count, + uint32_t flags) +{ + pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED); + NRFX_ASSERT(playback_count > 0); + NRFX_ASSERT(nrfx_is_in_ram(p_sequence_0->values.p_raw)); + NRFX_ASSERT(nrfx_is_in_ram(p_sequence_1->values.p_raw)); + + nrf_pwm_sequence_set(p_instance->p_registers, 0, p_sequence_0); + nrf_pwm_sequence_set(p_instance->p_registers, 1, p_sequence_1); + nrf_pwm_loop_set(p_instance->p_registers, playback_count); + + uint32_t shorts_mask; + if (flags & NRFX_PWM_FLAG_STOP) + { + shorts_mask = NRF_PWM_SHORT_LOOPSDONE_STOP_MASK; + } + else if (flags & NRFX_PWM_FLAG_LOOP) + { + shorts_mask = NRF_PWM_SHORT_LOOPSDONE_SEQSTART0_MASK; + } + else + { + shorts_mask = 0; + } + nrf_pwm_shorts_set(p_instance->p_registers, shorts_mask); + + NRFX_LOG_INFO("Function: %s, sequence 0 length: %d.", + __func__, + p_sequence_0->length); + NRFX_LOG_INFO("Function: %s, sequence 1 length: %d.", + __func__, + p_sequence_1->length); + NRFX_LOG_DEBUG("Sequence 0 data:"); + NRFX_LOG_HEXDUMP_DEBUG(p_sequence_0->values.p_raw, + p_sequence_0->length * sizeof(uint16_t)); + NRFX_LOG_DEBUG("Sequence 1 data:"); + NRFX_LOG_HEXDUMP_DEBUG(p_sequence_1->values.p_raw, + p_sequence_1->length * sizeof(uint16_t)); + return start_playback(p_instance, p_cb, flags, NRF_PWM_TASK_SEQSTART0); +} + + +bool nrfx_pwm_stop(nrfx_pwm_t const * const p_instance, + bool wait_until_stopped) +{ + NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state != NRFX_DRV_STATE_UNINITIALIZED); + + bool ret_val = false; + + if (nrfx_pwm_is_stopped(p_instance)) + { + ret_val = true; + } + else + { + nrf_pwm_task_trigger(p_instance->p_registers, NRF_PWM_TASK_STOP); + + do { + if (nrfx_pwm_is_stopped(p_instance)) + { + ret_val = true; + break; + } + } while (wait_until_stopped); + } + + NRFX_LOG_INFO("%s returned %d.", __func__, ret_val); + return ret_val; +} + + +bool nrfx_pwm_is_stopped(nrfx_pwm_t const * const p_instance) +{ + pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED); + + bool ret_val = false; + + // If the event handler is used (interrupts are enabled), the state will + // be changed in interrupt handler when the STOPPED event occurs. + if (p_cb->state != NRFX_DRV_STATE_POWERED_ON) + { + ret_val = true; + } + // If interrupts are disabled, we must check the STOPPED event here. + if (nrf_pwm_event_check(p_instance->p_registers, NRF_PWM_EVENT_STOPPED)) + { + p_cb->state = NRFX_DRV_STATE_INITIALIZED; + NRFX_LOG_INFO("Disabled."); + ret_val = true; + } + + NRFX_LOG_INFO("%s returned %d.", __func__, ret_val); + return ret_val; +} + + +static void irq_handler(NRF_PWM_Type * p_pwm, pwm_control_block_t * p_cb) +{ + // The user handler is called for SEQEND0 and SEQEND1 events only when the + // user asks for it (by setting proper flags when starting the playback). + if (nrf_pwm_event_check(p_pwm, NRF_PWM_EVENT_SEQEND0)) + { + nrf_pwm_event_clear(p_pwm, NRF_PWM_EVENT_SEQEND0); + if ((p_cb->flags & NRFX_PWM_FLAG_SIGNAL_END_SEQ0) && p_cb->handler) + { + p_cb->handler(NRFX_PWM_EVT_END_SEQ0); + } + } + if (nrf_pwm_event_check(p_pwm, NRF_PWM_EVENT_SEQEND1)) + { + nrf_pwm_event_clear(p_pwm, NRF_PWM_EVENT_SEQEND1); + if ((p_cb->flags & NRFX_PWM_FLAG_SIGNAL_END_SEQ1) && p_cb->handler) + { + p_cb->handler(NRFX_PWM_EVT_END_SEQ1); + } + } + // For LOOPSDONE the handler is called by default, but the user can disable + // this (via flags). + if (nrf_pwm_event_check(p_pwm, NRF_PWM_EVENT_LOOPSDONE)) + { + nrf_pwm_event_clear(p_pwm, NRF_PWM_EVENT_LOOPSDONE); + if (!(p_cb->flags & NRFX_PWM_FLAG_NO_EVT_FINISHED) && p_cb->handler) + { + p_cb->handler(NRFX_PWM_EVT_FINISHED); + } + } + + // The STOPPED event is always propagated to the user handler. + if (nrf_pwm_event_check(p_pwm, NRF_PWM_EVENT_STOPPED)) + { + nrf_pwm_event_clear(p_pwm, NRF_PWM_EVENT_STOPPED); + + p_cb->state = NRFX_DRV_STATE_INITIALIZED; + if (p_cb->handler) + { + p_cb->handler(NRFX_PWM_EVT_STOPPED); + } + } +} + + +#if defined(USE_DMA_ISSUE_WORKAROUND) +// See 'start_playback' why this is needed. +void DMA_ISSUE_EGU_IRQHandler(void) +{ + int i; + for (i = 0; i < NRFX_PWM_ENABLED_COUNT; ++i) + { + volatile uint32_t * p_event_reg = + nrf_egu_event_triggered_address_get(DMA_ISSUE_EGU, i); + if (*p_event_reg) + { + *p_event_reg = 0; + *(volatile uint32_t *)(m_cb[i].starting_task_address) = 1; + } + } +} +#endif + + +#if NRFX_CHECK(NRFX_PWM0_ENABLED) +void nrfx_pwm_0_irq_handler(void) +{ + irq_handler(NRF_PWM0, &m_cb[NRFX_PWM0_INST_IDX]); +} +#endif + +#if NRFX_CHECK(NRFX_PWM1_ENABLED) +void nrfx_pwm_1_irq_handler(void) +{ + irq_handler(NRF_PWM1, &m_cb[NRFX_PWM1_INST_IDX]); +} +#endif + +#if NRFX_CHECK(NRFX_PWM2_ENABLED) +void nrfx_pwm_2_irq_handler(void) +{ + irq_handler(NRF_PWM2, &m_cb[NRFX_PWM2_INST_IDX]); +} +#endif + +#if NRFX_CHECK(NRFX_PWM3_ENABLED) +void nrfx_pwm_3_irq_handler(void) +{ + irq_handler(NRF_PWM3, &m_cb[NRFX_PWM3_INST_IDX]); +} +#endif + +#endif // NRFX_CHECK(NRFX_PWM_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_qdec.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_qdec.c new file mode 100644 index 0000000..c7994d1 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_qdec.c @@ -0,0 +1,201 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_QDEC_ENABLED) + +#include <nrfx_qdec.h> +#include <hal/nrf_gpio.h> + +#define NRFX_LOG_MODULE QDEC +#include <nrfx_log.h> + +#define EVT_TO_STR(event) \ + (event == NRF_QDEC_EVENT_SAMPLERDY ? "NRF_QDEC_EVENT_SAMPLERDY" : \ + (event == NRF_QDEC_EVENT_REPORTRDY ? "NRF_QDEC_EVENT_REPORTRDY" : \ + (event == NRF_QDEC_EVENT_ACCOF ? "NRF_QDEC_EVENT_ACCOF" : \ + "UNKNOWN EVENT"))) + + +static nrfx_qdec_event_handler_t m_qdec_event_handler = NULL; +static nrfx_drv_state_t m_state = NRFX_DRV_STATE_UNINITIALIZED; + +void nrfx_qdec_irq_handler(void) +{ + nrfx_qdec_event_t event; + if ( nrf_qdec_event_check(NRF_QDEC_EVENT_SAMPLERDY) && + nrf_qdec_int_enable_check(NRF_QDEC_INT_SAMPLERDY_MASK) ) + { + nrf_qdec_event_clear(NRF_QDEC_EVENT_SAMPLERDY); + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_QDEC_EVENT_SAMPLERDY)); + + event.type = NRF_QDEC_EVENT_SAMPLERDY; + event.data.sample.value = (int8_t)nrf_qdec_sample_get(); + m_qdec_event_handler(event); + } + + if ( nrf_qdec_event_check(NRF_QDEC_EVENT_REPORTRDY) && + nrf_qdec_int_enable_check(NRF_QDEC_INT_REPORTRDY_MASK) ) + { + nrf_qdec_event_clear(NRF_QDEC_EVENT_REPORTRDY); + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_QDEC_EVENT_REPORTRDY)); + + event.type = NRF_QDEC_EVENT_REPORTRDY; + + event.data.report.acc = (int16_t)nrf_qdec_accread_get(); + event.data.report.accdbl = (uint16_t)nrf_qdec_accdblread_get(); + m_qdec_event_handler(event); + } + + if ( nrf_qdec_event_check(NRF_QDEC_EVENT_ACCOF) && + nrf_qdec_int_enable_check(NRF_QDEC_INT_ACCOF_MASK) ) + { + nrf_qdec_event_clear(NRF_QDEC_EVENT_ACCOF); + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_QDEC_EVENT_ACCOF)); + + event.type = NRF_QDEC_EVENT_ACCOF; + m_qdec_event_handler(event); + } +} + + +nrfx_err_t nrfx_qdec_init(nrfx_qdec_config_t const * p_config, + nrfx_qdec_event_handler_t event_handler) +{ + NRFX_ASSERT(p_config); + NRFX_ASSERT(event_handler); + nrfx_err_t err_code; + + if (m_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; + } + + m_qdec_event_handler = event_handler; + + nrf_qdec_sampleper_set(p_config->sampleper); + nrf_gpio_cfg_input(p_config->pselled, NRF_GPIO_PIN_NOPULL); + nrf_gpio_cfg_input(p_config->psela, NRF_GPIO_PIN_NOPULL); + nrf_gpio_cfg_input(p_config->pselb, NRF_GPIO_PIN_NOPULL); + nrf_qdec_pio_assign(p_config->psela, p_config->pselb, p_config->pselled); + nrf_qdec_ledpre_set(p_config->ledpre); + nrf_qdec_ledpol_set(p_config->ledpol); + nrf_qdec_shorts_enable(NRF_QDEC_SHORT_REPORTRDY_READCLRACC_MASK); + + if (p_config->dbfen) + { + nrf_qdec_dbfen_enable(); + } + else + { + nrf_qdec_dbfen_disable(); + } + + uint32_t int_mask = NRF_QDEC_INT_ACCOF_MASK; + + if (p_config->reportper != NRF_QDEC_REPORTPER_DISABLED) + { + nrf_qdec_reportper_set(p_config->reportper); + int_mask |= NRF_QDEC_INT_REPORTRDY_MASK; + } + + if (p_config->sample_inten) + { + int_mask |= NRF_QDEC_INT_SAMPLERDY_MASK; + } + + nrf_qdec_int_enable(int_mask); + NRFX_IRQ_PRIORITY_SET(QDEC_IRQn, p_config->interrupt_priority); + NRFX_IRQ_ENABLE(QDEC_IRQn); + + m_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_qdec_uninit(void) +{ + NRFX_ASSERT(m_state != NRFX_DRV_STATE_UNINITIALIZED); + nrfx_qdec_disable(); + NRFX_IRQ_DISABLE(QDEC_IRQn); + m_state = NRFX_DRV_STATE_UNINITIALIZED; + NRFX_LOG_INFO("Uninitialized."); +} + +void nrfx_qdec_enable(void) +{ + NRFX_ASSERT(m_state == NRFX_DRV_STATE_INITIALIZED); + nrf_qdec_enable(); + nrf_qdec_task_trigger(NRF_QDEC_TASK_START); + m_state = NRFX_DRV_STATE_POWERED_ON; + NRFX_LOG_INFO("Enabled."); +} + +void nrfx_qdec_disable(void) +{ + NRFX_ASSERT(m_state == NRFX_DRV_STATE_POWERED_ON); + nrf_qdec_task_trigger(NRF_QDEC_TASK_STOP); + nrf_qdec_disable(); + m_state = NRFX_DRV_STATE_INITIALIZED; + NRFX_LOG_INFO("Disabled."); +} + +void nrfx_qdec_accumulators_read(int16_t * p_acc, int16_t * p_accdbl) +{ + NRFX_ASSERT(m_state == NRFX_DRV_STATE_POWERED_ON); + nrf_qdec_task_trigger(NRF_QDEC_TASK_READCLRACC); + + *p_acc = (int16_t)nrf_qdec_accread_get(); + *p_accdbl = (int16_t)nrf_qdec_accdblread_get(); + + NRFX_LOG_DEBUG("Accumulators data, ACC register:"); + NRFX_LOG_HEXDUMP_DEBUG((uint8_t *)p_acc, sizeof(p_acc[0])); + NRFX_LOG_DEBUG("Accumulators data, ACCDBL register:"); + NRFX_LOG_HEXDUMP_DEBUG((uint8_t *)p_accdbl, sizeof(p_accdbl[0])); +} + +#endif // NRFX_CHECK(NRFX_QDEC_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_qspi.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_qspi.c new file mode 100644 index 0000000..93ffeff --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_qspi.c @@ -0,0 +1,337 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_QSPI_ENABLED) + +#include <nrfx_qspi.h> + + +/** + * @brief Command byte used to read status register. + * + */ +#define QSPI_STD_CMD_RDSR 0x05 + +/** + * @brief Byte used to mask status register and retrieve the write-in-progess bit. + * + */ +#define QSPI_MEM_STATUSREG_WIP_Pos 0x01 + +/** + * @brief Default time used in timeout function. + */ +#define QSPI_DEF_WAIT_TIME_US 10 + +/** + * @brief Default number of tries in timeout function. + */ +#define QSPI_DEF_WAIT_ATTEMPTS 100 + +/** + * @brief Control block - driver instance local data. + */ +typedef struct +{ + nrfx_qspi_handler_t handler; /**< Handler. */ + nrfx_drv_state_t state; /**< Driver state. */ + volatile bool interrupt_driven; /**< Information if the current operation is performed and is interrupt-driven. */ + void * p_context; /**< Driver context used in interrupt. */ +} qspi_control_block_t; + +static qspi_control_block_t m_cb; + +static nrfx_err_t qspi_task_perform(nrf_qspi_task_t task) +{ + // Wait for peripheral + if (m_cb.interrupt_driven) + { + return NRFX_ERROR_BUSY; + } + + nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY); + + if (m_cb.handler) + { + m_cb.interrupt_driven = true; + nrf_qspi_int_enable(NRF_QSPI, NRF_QSPI_INT_READY_MASK); + } + + nrf_qspi_task_trigger(NRF_QSPI, task); + + if (m_cb.handler == NULL) + { + while (!nrf_qspi_event_check(NRF_QSPI, NRF_QSPI_EVENT_READY)) + {}; + } + return NRFX_SUCCESS; +} + +static bool qspi_pins_configure(nrf_qspi_pins_t const * p_config) +{ + // Check if the user set meaningful values to struct fields. If not, return false. + if ((p_config->sck_pin == NRF_QSPI_PIN_NOT_CONNECTED) || + (p_config->csn_pin == NRF_QSPI_PIN_NOT_CONNECTED) || + (p_config->io0_pin == NRF_QSPI_PIN_NOT_CONNECTED) || + (p_config->io1_pin == NRF_QSPI_PIN_NOT_CONNECTED)) + { + return false; + } + + nrf_qspi_pins_set(NRF_QSPI, p_config); + + return true; +} + +nrfx_err_t nrfx_qspi_init(nrfx_qspi_config_t const * p_config, + nrfx_qspi_handler_t handler, + void * p_context) +{ + NRFX_ASSERT(p_config); + if (m_cb.state != NRFX_DRV_STATE_UNINITIALIZED) + { + return NRFX_ERROR_INVALID_STATE; + } + + if (!qspi_pins_configure(&p_config->pins)) + { + return NRFX_ERROR_INVALID_PARAM; + } + + nrf_qspi_xip_offset_set(NRF_QSPI, p_config->xip_offset); + nrf_qspi_ifconfig0_set(NRF_QSPI, &p_config->prot_if); + nrf_qspi_ifconfig1_set(NRF_QSPI, &p_config->phy_if); + + m_cb.interrupt_driven = false; + m_cb.handler = handler; + m_cb.p_context = p_context; + + /* QSPI interrupt is disabled because the device should be enabled in polling mode (wait for activate + task event ready)*/ + nrf_qspi_int_disable(NRF_QSPI, NRF_QSPI_INT_READY_MASK); + + if (handler) + { + NRFX_IRQ_PRIORITY_SET(QSPI_IRQn, p_config->irq_priority); + NRFX_IRQ_ENABLE(QSPI_IRQn); + } + + m_cb.state = NRFX_DRV_STATE_INITIALIZED; + + nrf_qspi_enable(NRF_QSPI); + + nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY); + nrf_qspi_task_trigger(NRF_QSPI, NRF_QSPI_TASK_ACTIVATE); + + // Waiting for the peripheral to activate + bool result; + NRFX_WAIT_FOR(nrf_qspi_event_check(NRF_QSPI, NRF_QSPI_EVENT_READY), + QSPI_DEF_WAIT_ATTEMPTS, + QSPI_DEF_WAIT_TIME_US, + result); + + if (!result) + { + return NRFX_ERROR_TIMEOUT; + } + + return NRFX_SUCCESS; +} + +nrfx_err_t nrfx_qspi_cinstr_xfer(nrf_qspi_cinstr_conf_t const * p_config, + void const * p_tx_buffer, + void * p_rx_buffer) +{ + NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); + + if (m_cb.interrupt_driven) + { + return NRFX_ERROR_BUSY; + } + + nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY); + /* In some cases, only opcode should be sent. To prevent execution, set function code is + * surrounded by an if. + */ + if (p_tx_buffer) + { + nrf_qspi_cinstrdata_set(NRF_QSPI, p_config->length, p_tx_buffer); + } + nrf_qspi_int_disable(NRF_QSPI, NRF_QSPI_INT_READY_MASK); + + nrf_qspi_cinstr_transfer_start(NRF_QSPI, p_config); + + bool result; + NRFX_WAIT_FOR(nrf_qspi_event_check(NRF_QSPI, NRF_QSPI_EVENT_READY), + QSPI_DEF_WAIT_ATTEMPTS, + QSPI_DEF_WAIT_TIME_US, + result); + + if (!result) + { + // This timeout should never occur when WIPWAIT is not active, since in this + // case the QSPI peripheral should send the command immediately, without any + // waiting for previous write to complete. + NRFX_ASSERT(p_config->wipwait); + + return NRFX_ERROR_TIMEOUT; + } + nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY); + nrf_qspi_int_enable(NRF_QSPI, NRF_QSPI_INT_READY_MASK); + + if (p_rx_buffer) + { + nrf_qspi_cinstrdata_get(NRF_QSPI, p_config->length, p_rx_buffer); + } + + return NRFX_SUCCESS; +} + +nrfx_err_t nrfx_qspi_cinstr_quick_send(uint8_t opcode, + nrf_qspi_cinstr_len_t length, + void const * p_tx_buffer) +{ + nrf_qspi_cinstr_conf_t config = NRFX_QSPI_DEFAULT_CINSTR(opcode, length); + return nrfx_qspi_cinstr_xfer(&config, p_tx_buffer, NULL); +} + +nrfx_err_t nrfx_qspi_mem_busy_check(void) +{ + nrfx_err_t ret_code; + uint8_t status_value = 0; + + nrf_qspi_cinstr_conf_t const config = + NRFX_QSPI_DEFAULT_CINSTR(QSPI_STD_CMD_RDSR, + NRF_QSPI_CINSTR_LEN_2B); + ret_code = nrfx_qspi_cinstr_xfer(&config, &status_value, &status_value); + + if (ret_code != NRFX_SUCCESS) + { + return ret_code; + } + + if ((status_value & QSPI_MEM_STATUSREG_WIP_Pos) != 0x00) + { + return NRFX_ERROR_BUSY; + } + + return NRFX_SUCCESS; +} + +void nrfx_qspi_uninit(void) +{ + NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); + + nrf_qspi_int_disable(NRF_QSPI, NRF_QSPI_INT_READY_MASK); + + nrf_qspi_disable(NRF_QSPI); + + nrf_qspi_task_trigger(NRF_QSPI, NRF_QSPI_TASK_DEACTIVATE); + + // Workaround for nRF52840 anomaly 122: Current consumption is too high. + *(volatile uint32_t *)0x40029054ul = 1ul; + + NRFX_IRQ_DISABLE(QSPI_IRQn); + + nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY); + + m_cb.state = NRFX_DRV_STATE_UNINITIALIZED; +} + +nrfx_err_t nrfx_qspi_write(void const * p_tx_buffer, + size_t tx_buffer_length, + uint32_t dst_address) +{ + NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); + NRFX_ASSERT(p_tx_buffer != NULL); + + if (!nrfx_is_in_ram(p_tx_buffer)) + { + return NRFX_ERROR_INVALID_ADDR; + } + + nrf_qspi_write_buffer_set(NRF_QSPI, p_tx_buffer, tx_buffer_length, dst_address); + return qspi_task_perform(NRF_QSPI_TASK_WRITESTART); + +} + +nrfx_err_t nrfx_qspi_read(void * p_rx_buffer, + size_t rx_buffer_length, + uint32_t src_address) +{ + NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); + NRFX_ASSERT(p_rx_buffer != NULL); + + if (!nrfx_is_in_ram(p_rx_buffer)) + { + return NRFX_ERROR_INVALID_ADDR; + } + + nrf_qspi_read_buffer_set(NRF_QSPI, p_rx_buffer, rx_buffer_length, src_address); + return qspi_task_perform(NRF_QSPI_TASK_READSTART); +} + +nrfx_err_t nrfx_qspi_erase(nrf_qspi_erase_len_t length, + uint32_t start_address) +{ + NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); + nrf_qspi_erase_ptr_set(NRF_QSPI, start_address, length); + return qspi_task_perform(NRF_QSPI_TASK_ERASESTART); +} + +nrfx_err_t nrfx_qspi_chip_erase(void) +{ + return nrfx_qspi_erase(NRF_QSPI_ERASE_LEN_ALL, 0); +} + +void nrfx_qspi_irq_handler(void) +{ + // Catch Event ready interrupts + if (nrf_qspi_event_check(NRF_QSPI, NRF_QSPI_EVENT_READY)) + { + m_cb.interrupt_driven = false; + nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY); + m_cb.handler(NRFX_QSPI_EVENT_DONE, m_cb.p_context); + } +} + +#endif // NRFX_CHECK(NRFX_QSPI_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_rng.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_rng.c new file mode 100644 index 0000000..a179f7c --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_rng.c @@ -0,0 +1,122 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_RNG_ENABLED) + +#include <nrfx_rng.h> + +#define NRFX_LOG_MODULE RNG +#include <nrfx_log.h> + +/** + * @brief Internal state of RNG driver. + */ +static nrfx_drv_state_t m_rng_state; + +/** + * @brief Pointer to handler calling from interrupt routine. + */ +static nrfx_rng_evt_handler_t m_rng_hndl; + +nrfx_err_t nrfx_rng_init(nrfx_rng_config_t const * p_config, nrfx_rng_evt_handler_t handler) +{ + NRFX_ASSERT(p_config); + NRFX_ASSERT(handler); + if (m_rng_state != NRFX_DRV_STATE_UNINITIALIZED) + { + return NRFX_ERROR_ALREADY_INITIALIZED; + } + + m_rng_hndl = handler; + + if (p_config->error_correction) + { + nrf_rng_error_correction_enable(); + } + nrf_rng_shorts_disable(NRF_RNG_SHORT_VALRDY_STOP_MASK); + NRFX_IRQ_PRIORITY_SET(RNG_IRQn, p_config->interrupt_priority); + NRFX_IRQ_ENABLE(RNG_IRQn); + + m_rng_state = NRFX_DRV_STATE_INITIALIZED; + + return NRFX_SUCCESS; +} + +void nrfx_rng_start(void) +{ + NRFX_ASSERT(m_rng_state == NRFX_DRV_STATE_INITIALIZED); + nrf_rng_event_clear(NRF_RNG_EVENT_VALRDY); + nrf_rng_int_enable(NRF_RNG_INT_VALRDY_MASK); + nrf_rng_task_trigger(NRF_RNG_TASK_START); +} + +void nrfx_rng_stop(void) +{ + NRFX_ASSERT(m_rng_state == NRFX_DRV_STATE_INITIALIZED); + nrf_rng_int_disable(NRF_RNG_INT_VALRDY_MASK); + nrf_rng_task_trigger(NRF_RNG_TASK_STOP); +} + +void nrfx_rng_uninit(void) +{ + NRFX_ASSERT(m_rng_state == NRFX_DRV_STATE_INITIALIZED); + + nrf_rng_int_disable(NRF_RNG_INT_VALRDY_MASK); + nrf_rng_task_trigger(NRF_RNG_TASK_STOP); + NRFX_IRQ_DISABLE(RNG_IRQn); + + m_rng_state = NRFX_DRV_STATE_UNINITIALIZED; + NRFX_LOG_INFO("Uninitialized."); +} + +void nrfx_rng_irq_handler(void) +{ + nrf_rng_event_clear(NRF_RNG_EVENT_VALRDY); + + uint8_t rng_value = nrf_rng_random_value_get(); + + m_rng_hndl(rng_value); + + NRFX_LOG_DEBUG("Event: NRF_RNG_EVENT_VALRDY."); +} + +#endif // NRFX_CHECK(NRFX_RNG_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_rtc.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_rtc.c new file mode 100644 index 0000000..95e8605 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_rtc.c @@ -0,0 +1,348 @@ +/** + * Copyright (c) 2014 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_RTC_ENABLED) + +#if !(NRFX_CHECK(NRFX_RTC0_ENABLED) || NRFX_CHECK(NRFX_RTC1_ENABLED) || \ + NRFX_CHECK(NRFX_RTC2_ENABLED)) +#error "No enabled RTC instances. Check <nrfx_config.h>." +#endif + +#include <nrfx_rtc.h> + +#define NRFX_LOG_MODULE RTC +#include <nrfx_log.h> + +#define EVT_TO_STR(event) \ + (event == NRF_RTC_EVENT_TICK ? "NRF_RTC_EVENT_TICK" : \ + (event == NRF_RTC_EVENT_OVERFLOW ? "NRF_RTC_EVENT_OVERFLOW" : \ + (event == NRF_RTC_EVENT_COMPARE_0 ? "NRF_RTC_EVENT_COMPARE_0" : \ + (event == NRF_RTC_EVENT_COMPARE_1 ? "NRF_RTC_EVENT_COMPARE_1" : \ + (event == NRF_RTC_EVENT_COMPARE_2 ? "NRF_RTC_EVENT_COMPARE_2" : \ + (event == NRF_RTC_EVENT_COMPARE_3 ? "NRF_RTC_EVENT_COMPARE_3" : \ + "UNKNOWN EVENT")))))) + + +/**@brief RTC driver instance control block structure. */ +typedef struct +{ + nrfx_drv_state_t state; /**< Instance state. */ + bool reliable; /**< Reliable mode flag. */ + uint8_t tick_latency; /**< Maximum length of interrupt handler in ticks (max 7.7 ms). */ +} nrfx_rtc_cb_t; + +// User callbacks local storage. +static nrfx_rtc_handler_t m_handlers[NRFX_RTC_ENABLED_COUNT]; +static nrfx_rtc_cb_t m_cb[NRFX_RTC_ENABLED_COUNT]; + +nrfx_err_t nrfx_rtc_init(nrfx_rtc_t const * const p_instance, + nrfx_rtc_config_t const * p_config, + nrfx_rtc_handler_t handler) +{ + NRFX_ASSERT(p_config); + NRFX_ASSERT(handler); + nrfx_err_t err_code; + + m_handlers[p_instance->instance_id] = handler; + + if (m_cb[p_instance->instance_id].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; + } + + NRFX_IRQ_PRIORITY_SET(p_instance->irq, p_config->interrupt_priority); + NRFX_IRQ_ENABLE(p_instance->irq); + nrf_rtc_prescaler_set(p_instance->p_reg, p_config->prescaler); + m_cb[p_instance->instance_id].reliable = p_config->reliable; + m_cb[p_instance->instance_id].tick_latency = p_config->tick_latency; + m_cb[p_instance->instance_id].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_rtc_uninit(nrfx_rtc_t const * const p_instance) +{ + uint32_t mask = NRF_RTC_INT_TICK_MASK | + NRF_RTC_INT_OVERFLOW_MASK | + NRF_RTC_INT_COMPARE0_MASK | + NRF_RTC_INT_COMPARE1_MASK | + NRF_RTC_INT_COMPARE2_MASK | + NRF_RTC_INT_COMPARE3_MASK; + NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED); + + NRFX_IRQ_DISABLE(p_instance->irq); + + nrf_rtc_task_trigger(p_instance->p_reg, NRF_RTC_TASK_STOP); + nrf_rtc_event_disable(p_instance->p_reg, mask); + nrf_rtc_int_disable(p_instance->p_reg, mask); + + m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_UNINITIALIZED; + NRFX_LOG_INFO("Uninitialized."); +} + +void nrfx_rtc_enable(nrfx_rtc_t const * const p_instance) +{ + NRFX_ASSERT(m_cb[p_instance->instance_id].state == NRFX_DRV_STATE_INITIALIZED); + + nrf_rtc_task_trigger(p_instance->p_reg, NRF_RTC_TASK_START); + m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_POWERED_ON; + NRFX_LOG_INFO("Enabled."); +} + +void nrfx_rtc_disable(nrfx_rtc_t const * const p_instance) +{ + NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED); + + nrf_rtc_task_trigger(p_instance->p_reg, NRF_RTC_TASK_STOP); + m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_INITIALIZED; + NRFX_LOG_INFO("Disabled."); +} + +nrfx_err_t nrfx_rtc_cc_disable(nrfx_rtc_t const * const p_instance, uint32_t channel) +{ + NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED); + NRFX_ASSERT(channel<p_instance->cc_channel_count); + + nrfx_err_t err_code; + uint32_t int_mask = RTC_CHANNEL_INT_MASK(channel); + nrf_rtc_event_t event = RTC_CHANNEL_EVENT_ADDR(channel); + + nrf_rtc_event_disable(p_instance->p_reg,int_mask); + if (nrf_rtc_int_is_enabled(p_instance->p_reg,int_mask)) + { + nrf_rtc_int_disable(p_instance->p_reg,int_mask); + if (nrf_rtc_event_pending(p_instance->p_reg,event)) + { + nrf_rtc_event_clear(p_instance->p_reg,event); + err_code = NRFX_ERROR_TIMEOUT; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + } + NRFX_LOG_INFO("RTC id: %d, channel disabled: %lu.", p_instance->instance_id, channel); + 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_rtc_cc_set(nrfx_rtc_t const * const p_instance, + uint32_t channel, + uint32_t val, + bool enable_irq) +{ + NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED); + NRFX_ASSERT(channel<p_instance->cc_channel_count); + + nrfx_err_t err_code; + uint32_t int_mask = RTC_CHANNEL_INT_MASK(channel); + nrf_rtc_event_t event = RTC_CHANNEL_EVENT_ADDR(channel); + + nrf_rtc_event_disable(p_instance->p_reg, int_mask); + nrf_rtc_int_disable(p_instance->p_reg, int_mask); + + val = RTC_WRAP(val); + if (m_cb[p_instance->instance_id].reliable) + { + nrf_rtc_cc_set(p_instance->p_reg,channel,val); + uint32_t cnt = nrf_rtc_counter_get(p_instance->p_reg); + int32_t diff = cnt - val; + if (cnt < val) + { + diff += RTC_COUNTER_COUNTER_Msk; + } + if (diff < m_cb[p_instance->instance_id].tick_latency) + { + err_code = NRFX_ERROR_TIMEOUT; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + } + else + { + nrf_rtc_cc_set(p_instance->p_reg,channel,val); + } + + if (enable_irq) + { + nrf_rtc_event_clear(p_instance->p_reg,event); + nrf_rtc_int_enable(p_instance->p_reg, int_mask); + } + nrf_rtc_event_enable(p_instance->p_reg,int_mask); + + NRFX_LOG_INFO("RTC id: %d, channel enabled: %lu, compare value: %lu.", + p_instance->instance_id, + channel, + val); + 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_rtc_tick_enable(nrfx_rtc_t const * const p_instance, bool enable_irq) +{ + nrf_rtc_event_t event = NRF_RTC_EVENT_TICK; + uint32_t mask = NRF_RTC_INT_TICK_MASK; + + nrf_rtc_event_clear(p_instance->p_reg, event); + nrf_rtc_event_enable(p_instance->p_reg, mask); + if (enable_irq) + { + nrf_rtc_int_enable(p_instance->p_reg, mask); + } + NRFX_LOG_INFO("Tick events enabled."); +} + +void nrfx_rtc_tick_disable(nrfx_rtc_t const * const p_instance) +{ + uint32_t mask = NRF_RTC_INT_TICK_MASK; + + nrf_rtc_event_disable(p_instance->p_reg, mask); + nrf_rtc_int_disable(p_instance->p_reg, mask); + NRFX_LOG_INFO("Tick events disabled."); +} + +void nrfx_rtc_overflow_enable(nrfx_rtc_t const * const p_instance, bool enable_irq) +{ + nrf_rtc_event_t event = NRF_RTC_EVENT_OVERFLOW; + uint32_t mask = NRF_RTC_INT_OVERFLOW_MASK; + + nrf_rtc_event_clear(p_instance->p_reg, event); + nrf_rtc_event_enable(p_instance->p_reg, mask); + if (enable_irq) + { + nrf_rtc_int_enable(p_instance->p_reg, mask); + } +} + +void nrfx_rtc_overflow_disable(nrfx_rtc_t const * const p_instance) +{ + uint32_t mask = NRF_RTC_INT_OVERFLOW_MASK; + nrf_rtc_event_disable(p_instance->p_reg, mask); + nrf_rtc_int_disable(p_instance->p_reg, mask); +} + +uint32_t nrfx_rtc_max_ticks_get(nrfx_rtc_t const * const p_instance) +{ + uint32_t ticks; + if (m_cb[p_instance->instance_id].reliable) + { + ticks = RTC_COUNTER_COUNTER_Msk - m_cb[p_instance->instance_id].tick_latency; + } + else + { + ticks = RTC_COUNTER_COUNTER_Msk; + } + return ticks; +} + +static void irq_handler(NRF_RTC_Type * p_reg, + uint32_t instance_id, + uint32_t channel_count) +{ + uint32_t i; + uint32_t int_mask = (uint32_t)NRF_RTC_INT_COMPARE0_MASK; + nrf_rtc_event_t event = NRF_RTC_EVENT_COMPARE_0; + + for (i = 0; i < channel_count; i++) + { + if (nrf_rtc_int_is_enabled(p_reg,int_mask) && nrf_rtc_event_pending(p_reg,event)) + { + nrf_rtc_event_disable(p_reg,int_mask); + nrf_rtc_int_disable(p_reg,int_mask); + nrf_rtc_event_clear(p_reg,event); + NRFX_LOG_DEBUG("Event: %s, instance id: %lu.", EVT_TO_STR(event), instance_id); + m_handlers[instance_id]((nrfx_rtc_int_type_t)i); + } + int_mask <<= 1; + event = (nrf_rtc_event_t)((uint32_t)event + sizeof(uint32_t)); + } + event = NRF_RTC_EVENT_TICK; + if (nrf_rtc_int_is_enabled(p_reg,NRF_RTC_INT_TICK_MASK) && + nrf_rtc_event_pending(p_reg, event)) + { + nrf_rtc_event_clear(p_reg, event); + NRFX_LOG_DEBUG("Event: %s, instance id: %lu.", EVT_TO_STR(event), instance_id); + m_handlers[instance_id](NRFX_RTC_INT_TICK); + } + + event = NRF_RTC_EVENT_OVERFLOW; + if (nrf_rtc_int_is_enabled(p_reg,NRF_RTC_INT_OVERFLOW_MASK) && + nrf_rtc_event_pending(p_reg, event)) + { + nrf_rtc_event_clear(p_reg,event); + NRFX_LOG_DEBUG("Event: %s, instance id: %lu.", EVT_TO_STR(event), instance_id); + m_handlers[instance_id](NRFX_RTC_INT_OVERFLOW); + } +} + +#if NRFX_CHECK(NRFX_RTC0_ENABLED) +void nrfx_rtc_0_irq_handler(void) +{ + irq_handler(NRF_RTC0, NRFX_RTC0_INST_IDX, NRF_RTC_CC_CHANNEL_COUNT(0)); +} +#endif + +#if NRFX_CHECK(NRFX_RTC1_ENABLED) +void nrfx_rtc_1_irq_handler(void) +{ + irq_handler(NRF_RTC1, NRFX_RTC1_INST_IDX, NRF_RTC_CC_CHANNEL_COUNT(1)); +} +#endif + +#if NRFX_CHECK(NRFX_RTC2_ENABLED) +void nrfx_rtc_2_irq_handler(void) +{ + irq_handler(NRF_RTC2, NRFX_RTC2_INST_IDX, NRF_RTC_CC_CHANNEL_COUNT(2)); +} +#endif + +#endif // NRFX_CHECK(NRFX_RTC_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_saadc.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_saadc.c new file mode 100644 index 0000000..4ab3409 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_saadc.c @@ -0,0 +1,639 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_SAADC_ENABLED) +#include <nrfx_saadc.h> + +#define NRFX_LOG_MODULE SAADC +#include <nrfx_log.h> + +#define EVT_TO_STR(event) \ + (event == NRF_SAADC_EVENT_STARTED ? "NRF_SAADC_EVENT_STARTED" : \ + (event == NRF_SAADC_EVENT_END ? "NRF_SAADC_EVENT_END" : \ + (event == NRF_SAADC_EVENT_DONE ? "NRF_SAADC_EVENT_DONE" : \ + (event == NRF_SAADC_EVENT_RESULTDONE ? "NRF_SAADC_EVENT_RESULTDONE" : \ + (event == NRF_SAADC_EVENT_CALIBRATEDONE ? "NRF_SAADC_EVENT_CALIBRATEDONE" : \ + (event == NRF_SAADC_EVENT_STOPPED ? "NRF_SAADC_EVENT_STOPPED" : \ + "UNKNOWN EVENT")))))) + + +typedef enum +{ + NRF_SAADC_STATE_IDLE = 0, + NRF_SAADC_STATE_BUSY = 1, + NRF_SAADC_STATE_CALIBRATION = 2 +} nrf_saadc_state_t; + + +typedef struct +{ + nrf_saadc_input_t pselp; + nrf_saadc_input_t pseln; +} nrf_saadc_psel_buffer; + +/** @brief SAADC control block.*/ +typedef struct +{ + nrfx_saadc_event_handler_t event_handler; ///< Event handler function pointer. + volatile nrf_saadc_value_t * p_buffer; ///< Sample buffer. + volatile uint16_t buffer_size; ///< Size of the sample buffer. + volatile nrf_saadc_value_t * p_secondary_buffer; ///< Secondary sample buffer. + volatile nrf_saadc_state_t adc_state; ///< State of the SAADC. + uint32_t limits_enabled_flags; ///< Enabled limits flags. + uint16_t secondary_buffer_size; ///< Size of the secondary buffer. + uint16_t buffer_size_left; ///< When low power mode is active indicates how many samples left to convert on current buffer. + nrf_saadc_psel_buffer psel[NRF_SAADC_CHANNEL_COUNT]; ///< Pin configurations of SAADC channels. + nrfx_drv_state_t state; ///< Driver initialization state. + uint8_t active_channels; ///< Number of enabled SAADC channels. + bool low_power_mode; ///< Indicates if low power mode is active. + bool conversions_end; ///< When low power mode is active indicates end of conversions on current buffer. +} nrfx_saadc_cb_t; + +static nrfx_saadc_cb_t m_cb; + +#define LOW_LIMIT_TO_FLAG(channel) ((2 * channel + 1)) +#define HIGH_LIMIT_TO_FLAG(channel) ((2 * channel)) +#define FLAG_IDX_TO_EVENT(idx) ((nrf_saadc_event_t)((uint32_t)NRF_SAADC_EVENT_CH0_LIMITH + \ + 4 * idx)) +#define LIMIT_EVENT_TO_CHANNEL(event) (uint8_t)(((uint32_t)event - \ + (uint32_t)NRF_SAADC_EVENT_CH0_LIMITH) / 8) +#define LIMIT_EVENT_TO_LIMIT_TYPE(event)((((uint32_t)event - (uint32_t)NRF_SAADC_EVENT_CH0_LIMITH) & 4) \ + ? NRF_SAADC_LIMIT_LOW : NRF_SAADC_LIMIT_HIGH) +#define HW_TIMEOUT 10000 + +void nrfx_saadc_irq_handler(void) +{ + if (nrf_saadc_event_check(NRF_SAADC_EVENT_END)) + { + nrf_saadc_event_clear(NRF_SAADC_EVENT_END); + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_SAADC_EVENT_END)); + + if (!m_cb.low_power_mode || m_cb.conversions_end) + { + nrfx_saadc_evt_t evt; + evt.type = NRFX_SAADC_EVT_DONE; + evt.data.done.p_buffer = (nrf_saadc_value_t *)m_cb.p_buffer; + evt.data.done.size = m_cb.buffer_size; + + if (m_cb.p_secondary_buffer == NULL) + { + m_cb.adc_state = NRF_SAADC_STATE_IDLE; + } + else + { + m_cb.buffer_size_left = m_cb.secondary_buffer_size; + m_cb.p_buffer = m_cb.p_secondary_buffer; + m_cb.buffer_size = m_cb.secondary_buffer_size; + m_cb.p_secondary_buffer = NULL; + if (!m_cb.low_power_mode) + { + nrf_saadc_task_trigger(NRF_SAADC_TASK_START); + } + } + m_cb.event_handler(&evt); + m_cb.conversions_end = false; + } + } + if (m_cb.low_power_mode && nrf_saadc_event_check(NRF_SAADC_EVENT_STARTED)) + { + nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED); + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_SAADC_EVENT_STARTED)); + + if (m_cb.buffer_size_left > m_cb.active_channels) + { + // More samples to convert than for single event. + m_cb.buffer_size_left -= m_cb.active_channels; + nrf_saadc_buffer_init((nrf_saadc_value_t *)&m_cb.p_buffer[m_cb.buffer_size - + m_cb.buffer_size_left], + m_cb.active_channels); + } + else if ((m_cb.buffer_size_left == m_cb.active_channels) && + + (m_cb.p_secondary_buffer != NULL)) + { + // Samples to convert for one event, prepare next buffer. + m_cb.conversions_end = true; + m_cb.buffer_size_left = 0; + nrf_saadc_buffer_init((nrf_saadc_value_t *)m_cb.p_secondary_buffer, + m_cb.active_channels); + } + else if (m_cb.buffer_size_left == m_cb.active_channels) + { + // Samples to convert for one event, but no second buffer. + m_cb.conversions_end = true; + m_cb.buffer_size_left = 0; + } + nrf_saadc_event_clear(NRF_SAADC_EVENT_END); + nrf_saadc_task_trigger(NRF_SAADC_TASK_SAMPLE); + } + if (nrf_saadc_event_check(NRF_SAADC_EVENT_CALIBRATEDONE)) + { + nrf_saadc_event_clear(NRF_SAADC_EVENT_CALIBRATEDONE); + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_SAADC_EVENT_CALIBRATEDONE)); + m_cb.adc_state = NRF_SAADC_STATE_IDLE; + + nrfx_saadc_evt_t evt; + evt.type = NRFX_SAADC_EVT_CALIBRATEDONE; + m_cb.event_handler(&evt); + } + if (nrf_saadc_event_check(NRF_SAADC_EVENT_STOPPED)) + { + nrf_saadc_event_clear(NRF_SAADC_EVENT_STOPPED); + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_SAADC_EVENT_STOPPED)); + m_cb.adc_state = NRF_SAADC_STATE_IDLE; + } + else + { + uint32_t limit_flags = m_cb.limits_enabled_flags; + uint32_t flag_idx; + nrf_saadc_event_t event; + + while (limit_flags) + { + flag_idx = __CLZ(limit_flags); + limit_flags &= ~((1UL << 31) >> flag_idx); + event = FLAG_IDX_TO_EVENT(flag_idx); + if (nrf_saadc_event_check(event)) + { + nrf_saadc_event_clear(event); + nrfx_saadc_evt_t evt; + evt.type = NRFX_SAADC_EVT_LIMIT; + evt.data.limit.channel = LIMIT_EVENT_TO_CHANNEL(event); + evt.data.limit.limit_type = LIMIT_EVENT_TO_LIMIT_TYPE(event); + NRFX_LOG_DEBUG("Event limit, channel: %d, limit type: %d.", + evt.data.limit.channel, + evt.data.limit.limit_type); + m_cb.event_handler(&evt); + } + } + } +} + + +nrfx_err_t nrfx_saadc_init(nrfx_saadc_config_t const * p_config, + nrfx_saadc_event_handler_t event_handler) +{ + NRFX_ASSERT(p_config); + NRFX_ASSERT(event_handler); + nrfx_err_t err_code; + + if (m_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; + } + + m_cb.event_handler = event_handler; + nrf_saadc_resolution_set(p_config->resolution); + nrf_saadc_oversample_set(p_config->oversample); + m_cb.low_power_mode = p_config->low_power_mode; + m_cb.state = NRFX_DRV_STATE_INITIALIZED; + m_cb.adc_state = NRF_SAADC_STATE_IDLE; + m_cb.active_channels = 0; + m_cb.limits_enabled_flags = 0; + m_cb.conversions_end = false; + + nrf_saadc_int_disable(NRF_SAADC_INT_ALL); + nrf_saadc_event_clear(NRF_SAADC_EVENT_END); + nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED); + NRFX_IRQ_PRIORITY_SET(SAADC_IRQn, p_config->interrupt_priority); + NRFX_IRQ_ENABLE(SAADC_IRQn); + nrf_saadc_int_enable(NRF_SAADC_INT_END); + + if (m_cb.low_power_mode) + { + nrf_saadc_int_enable(NRF_SAADC_INT_STARTED); + } + + nrf_saadc_enable(); + + 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_saadc_uninit(void) +{ + NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); + + nrf_saadc_int_disable(NRF_SAADC_INT_ALL); + NRFX_IRQ_DISABLE(SAADC_IRQn); + nrf_saadc_task_trigger(NRF_SAADC_TASK_STOP); + + // Wait for ADC being stopped. + bool result; + NRFX_WAIT_FOR(nrf_saadc_event_check(NRF_SAADC_EVENT_STOPPED), HW_TIMEOUT, 0, result); + NRFX_ASSERT(result); + + nrf_saadc_disable(); + m_cb.adc_state = NRF_SAADC_STATE_IDLE; + + for (uint32_t channel = 0; channel < NRF_SAADC_CHANNEL_COUNT; ++channel) + { + if (m_cb.psel[channel].pselp != NRF_SAADC_INPUT_DISABLED) + { + nrfx_err_t err_code = nrfx_saadc_channel_uninit(channel); + NRFX_ASSERT(err_code == NRFX_SUCCESS); + } + } + + m_cb.state = NRFX_DRV_STATE_UNINITIALIZED; +} + + +nrfx_err_t nrfx_saadc_channel_init(uint8_t channel, + nrf_saadc_channel_config_t const * const p_config) +{ + NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); + NRFX_ASSERT(channel < NRF_SAADC_CHANNEL_COUNT); + // Oversampling can be used only with one channel. + NRFX_ASSERT((nrf_saadc_oversample_get() == NRF_SAADC_OVERSAMPLE_DISABLED) || + (m_cb.active_channels == 0)); + NRFX_ASSERT((p_config->pin_p <= NRF_SAADC_INPUT_VDD) && + (p_config->pin_p > NRF_SAADC_INPUT_DISABLED)); + NRFX_ASSERT(p_config->pin_n <= NRF_SAADC_INPUT_VDD); + + nrfx_err_t err_code; + + // A channel can only be initialized if the driver is in the idle state. + if (m_cb.adc_state != NRF_SAADC_STATE_IDLE) + { + err_code = NRFX_ERROR_BUSY; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + +#ifdef NRF52_PAN_74 + if ((p_config->acq_time == NRF_SAADC_ACQTIME_3US) || + (p_config->acq_time == NRF_SAADC_ACQTIME_5US)) + { + nrf_saadc_disable(); + } +#endif //NRF52_PAN_74 + + if (m_cb.psel[channel].pselp == NRF_SAADC_INPUT_DISABLED) + { + ++m_cb.active_channels; + } + m_cb.psel[channel].pselp = p_config->pin_p; + m_cb.psel[channel].pseln = p_config->pin_n; + nrf_saadc_channel_init(channel, p_config); + nrf_saadc_channel_input_set(channel, p_config->pin_p, p_config->pin_n); + +#ifdef NRF52_PAN_74 + if ((p_config->acq_time == NRF_SAADC_ACQTIME_3US) || + (p_config->acq_time == NRF_SAADC_ACQTIME_5US)) + { + nrf_saadc_enable(); + } +#endif //NRF52_PAN_74 + + NRFX_LOG_INFO("Channel initialized: %d.", channel); + 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_saadc_channel_uninit(uint8_t channel) +{ + NRFX_ASSERT(channel < NRF_SAADC_CHANNEL_COUNT); + NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); + + nrfx_err_t err_code; + + // A channel can only be uninitialized if the driver is in the idle state. + if (m_cb.adc_state != NRF_SAADC_STATE_IDLE) + { + err_code = NRFX_ERROR_BUSY; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + + if (m_cb.psel[channel].pselp != NRF_SAADC_INPUT_DISABLED) + { + --m_cb.active_channels; + } + m_cb.psel[channel].pselp = NRF_SAADC_INPUT_DISABLED; + m_cb.psel[channel].pseln = NRF_SAADC_INPUT_DISABLED; + nrf_saadc_channel_input_set(channel, NRF_SAADC_INPUT_DISABLED, NRF_SAADC_INPUT_DISABLED); + nrfx_saadc_limits_set(channel, NRFX_SAADC_LIMITL_DISABLED, NRFX_SAADC_LIMITH_DISABLED); + NRFX_LOG_INFO("Channel denitialized: %d.", channel); + + err_code = NRFX_SUCCESS; + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + + +uint32_t nrfx_saadc_sample_task_get(void) +{ + return nrf_saadc_task_address_get( + m_cb.low_power_mode ? NRF_SAADC_TASK_START : NRF_SAADC_TASK_SAMPLE); +} + + +nrfx_err_t nrfx_saadc_sample_convert(uint8_t channel, nrf_saadc_value_t * p_value) +{ + nrfx_err_t err_code; + + if (m_cb.adc_state != NRF_SAADC_STATE_IDLE) + { + err_code = NRFX_ERROR_BUSY; + NRFX_LOG_WARNING("Function: %s error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + m_cb.adc_state = NRF_SAADC_STATE_BUSY; + nrf_saadc_int_disable(NRF_SAADC_INT_STARTED | NRF_SAADC_INT_END); + nrf_saadc_buffer_init(p_value, 1); + if (m_cb.active_channels > 1) + { + for (uint32_t i = 0; i < NRF_SAADC_CHANNEL_COUNT; ++i) + { + nrf_saadc_channel_input_set(i, NRF_SAADC_INPUT_DISABLED, NRF_SAADC_INPUT_DISABLED); + } + } + nrf_saadc_channel_input_set(channel, m_cb.psel[channel].pselp, m_cb.psel[channel].pseln); + nrf_saadc_task_trigger(NRF_SAADC_TASK_START); + nrf_saadc_task_trigger(NRF_SAADC_TASK_SAMPLE); + + bool result; + NRFX_WAIT_FOR(nrf_saadc_event_check(NRF_SAADC_EVENT_END), HW_TIMEOUT, 0, result); + NRFX_ASSERT(result); + + nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED); + nrf_saadc_event_clear(NRF_SAADC_EVENT_END); + + NRFX_LOG_INFO("Conversion value: %d, channel %d.", *p_value, channel); + + if (m_cb.active_channels > 1) + { + for (uint32_t i = 0; i < NRF_SAADC_CHANNEL_COUNT; ++i) + { + nrf_saadc_channel_input_set(i, m_cb.psel[i].pselp, m_cb.psel[i].pseln); + } + } + + if (m_cb.low_power_mode) + { + nrf_saadc_int_enable(NRF_SAADC_INT_STARTED | NRF_SAADC_INT_END); + } + else + { + nrf_saadc_int_enable(NRF_SAADC_INT_END); + } + + m_cb.adc_state = NRF_SAADC_STATE_IDLE; + + err_code = NRFX_SUCCESS; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + + +nrfx_err_t nrfx_saadc_buffer_convert(nrf_saadc_value_t * p_buffer, uint16_t size) +{ + NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); + NRFX_ASSERT((size % m_cb.active_channels) == 0); + nrfx_err_t err_code; + + nrf_saadc_int_disable(NRF_SAADC_INT_END | NRF_SAADC_INT_CALIBRATEDONE); + if (m_cb.adc_state == NRF_SAADC_STATE_CALIBRATION) + { + nrf_saadc_int_enable(NRF_SAADC_INT_END | NRF_SAADC_INT_CALIBRATEDONE); + err_code = NRFX_ERROR_BUSY; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + if (m_cb.adc_state == NRF_SAADC_STATE_BUSY) + { + if ( m_cb.p_secondary_buffer) + { + nrf_saadc_int_enable(NRF_SAADC_INT_END); + err_code = NRFX_ERROR_BUSY; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + else + { + m_cb.p_secondary_buffer = p_buffer; + m_cb.secondary_buffer_size = size; + if (!m_cb.low_power_mode) + { + while (nrf_saadc_event_check(NRF_SAADC_EVENT_STARTED) == 0); + nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED); + nrf_saadc_buffer_init(p_buffer, size); + } + nrf_saadc_int_enable(NRF_SAADC_INT_END); + err_code = NRFX_SUCCESS; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + } + nrf_saadc_int_enable(NRF_SAADC_INT_END); + m_cb.adc_state = NRF_SAADC_STATE_BUSY; + + m_cb.p_buffer = p_buffer; + m_cb.buffer_size = size; + m_cb.p_secondary_buffer = NULL; + + NRFX_LOG_INFO("Function: %s, buffer length: %d, active channels: %d.", + __func__, + size, + m_cb.active_channels); + + if (m_cb.low_power_mode) + { + m_cb.buffer_size_left = size; + nrf_saadc_buffer_init(p_buffer, m_cb.active_channels); + } + else + { + nrf_saadc_buffer_init(p_buffer, size); + nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED); + nrf_saadc_task_trigger(NRF_SAADC_TASK_START); + } + + 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_saadc_sample() +{ + NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); + + nrfx_err_t err_code = NRFX_SUCCESS; + if (m_cb.adc_state != NRF_SAADC_STATE_BUSY) + { + err_code = NRFX_ERROR_INVALID_STATE; + } + else if (m_cb.low_power_mode) + { + nrf_saadc_task_trigger(NRF_SAADC_TASK_START); + } + else + { + nrf_saadc_task_trigger(NRF_SAADC_TASK_SAMPLE); + } + + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + + +nrfx_err_t nrfx_saadc_calibrate_offset() +{ + NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); + + nrfx_err_t err_code; + + if (m_cb.adc_state != NRF_SAADC_STATE_IDLE) + { + err_code = NRFX_ERROR_BUSY; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + + m_cb.adc_state = NRF_SAADC_STATE_CALIBRATION; + + nrf_saadc_event_clear(NRF_SAADC_EVENT_CALIBRATEDONE); + nrf_saadc_int_enable(NRF_SAADC_INT_CALIBRATEDONE); + nrf_saadc_task_trigger(NRF_SAADC_TASK_CALIBRATEOFFSET); + 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_saadc_is_busy(void) +{ + return (m_cb.adc_state != NRF_SAADC_STATE_IDLE); +} + + +void nrfx_saadc_abort(void) +{ + if (nrfx_saadc_is_busy()) + { + nrf_saadc_event_clear(NRF_SAADC_EVENT_STOPPED); + nrf_saadc_int_enable(NRF_SAADC_INT_STOPPED); + nrf_saadc_task_trigger(NRF_SAADC_TASK_STOP); + + if (m_cb.adc_state == NRF_SAADC_STATE_CALIBRATION) + { + m_cb.adc_state = NRF_SAADC_STATE_IDLE; + } + else + { + // Wait for ADC being stopped. + bool result; + NRFX_WAIT_FOR((m_cb.adc_state != NRF_SAADC_STATE_IDLE), HW_TIMEOUT, 0, result); + NRFX_ASSERT(result); + } + + nrf_saadc_int_disable(NRF_SAADC_INT_STOPPED); + + m_cb.p_buffer = 0; + m_cb.p_secondary_buffer = 0; + NRFX_LOG_INFO("Conversion aborted."); + } +} + + +void nrfx_saadc_limits_set(uint8_t channel, int16_t limit_low, int16_t limit_high) +{ + NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); + NRFX_ASSERT(m_cb.event_handler); // only non blocking mode supported + NRFX_ASSERT(limit_low >= NRFX_SAADC_LIMITL_DISABLED); + NRFX_ASSERT(limit_high <= NRFX_SAADC_LIMITH_DISABLED); + NRFX_ASSERT(limit_low < limit_high); + nrf_saadc_channel_limits_set(channel, limit_low, limit_high); + + uint32_t int_mask = nrf_saadc_limit_int_get(channel, NRF_SAADC_LIMIT_LOW); + if (limit_low == NRFX_SAADC_LIMITL_DISABLED) + { + m_cb.limits_enabled_flags &= ~(0x80000000 >> LOW_LIMIT_TO_FLAG(channel)); + nrf_saadc_int_disable(int_mask); + } + else + { + m_cb.limits_enabled_flags |= (0x80000000 >> LOW_LIMIT_TO_FLAG(channel)); + nrf_saadc_int_enable(int_mask); + } + + int_mask = nrf_saadc_limit_int_get(channel, NRF_SAADC_LIMIT_HIGH); + if (limit_high == NRFX_SAADC_LIMITH_DISABLED) + { + m_cb.limits_enabled_flags &= ~(0x80000000 >> HIGH_LIMIT_TO_FLAG(channel)); + nrf_saadc_int_disable(int_mask); + } + else + { + m_cb.limits_enabled_flags |= (0x80000000 >> HIGH_LIMIT_TO_FLAG(channel)); + nrf_saadc_int_enable(int_mask); + } +} +#endif // NRFX_CHECK(NRFX_SAADC_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_spi.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_spi.c new file mode 100644 index 0000000..2c6bb44 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_spi.c @@ -0,0 +1,441 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_SPI_ENABLED) + +#if !(NRFX_CHECK(NRFX_SPI0_ENABLED) || NRFX_CHECK(NRFX_SPI1_ENABLED) || \ + NRFX_CHECK(NRFX_SPI2_ENABLED)) +#error "No enabled SPI instances. Check <nrfx_config.h>." +#endif + +#include <nrfx_spi.h> +#include "prs/nrfx_prs.h" +#include <hal/nrf_gpio.h> + +#define NRFX_LOG_MODULE SPI +#include <nrfx_log.h> + +// Control block - driver instance local data. +typedef struct +{ + nrfx_spi_evt_handler_t handler; + void * p_context; + nrfx_spi_evt_t evt; // Keep the struct that is ready for event handler. Less memcpy. + nrfx_drv_state_t state; + volatile bool transfer_in_progress; + + // [no need for 'volatile' attribute for the following members, as they + // are not concurrently used in IRQ handlers and main line code] + uint8_t ss_pin; + uint8_t miso_pin; + uint8_t orc; + size_t bytes_transferred; + + bool abort; +} spi_control_block_t; +static spi_control_block_t m_cb[NRFX_SPI_ENABLED_COUNT]; + + +nrfx_err_t nrfx_spi_init(nrfx_spi_t const * const p_instance, + nrfx_spi_config_t const * p_config, + nrfx_spi_evt_handler_t handler, + void * p_context) +{ + NRFX_ASSERT(p_config); + spi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + nrfx_err_t err_code; + + 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_SPI_ENABLED_COUNT] = { + #if NRFX_CHECK(NRFX_SPI0_ENABLED) + nrfx_spi_0_irq_handler, + #endif + #if NRFX_CHECK(NRFX_SPI1_ENABLED) + nrfx_spi_1_irq_handler, + #endif + #if NRFX_CHECK(NRFX_SPI2_ENABLED) + nrfx_spi_2_irq_handler, + #endif + }; + if (nrfx_prs_acquire(p_instance->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) + + p_cb->handler = handler; + p_cb->p_context = p_context; + + uint32_t mosi_pin; + uint32_t miso_pin; + // Configure pins used by the peripheral: + // - SCK - output with initial value corresponding with the SPI mode used: + // 0 - for modes 0 and 1 (CPOL = 0), 1 - for modes 2 and 3 (CPOL = 1); + // according to the reference manual guidelines this pin and its input + // buffer must always be connected for the SPI to work. + if (p_config->mode <= NRF_SPI_MODE_1) + { + nrf_gpio_pin_clear(p_config->sck_pin); + } + else + { + nrf_gpio_pin_set(p_config->sck_pin); + } + nrf_gpio_cfg(p_config->sck_pin, + NRF_GPIO_PIN_DIR_OUTPUT, + NRF_GPIO_PIN_INPUT_CONNECT, + NRF_GPIO_PIN_NOPULL, + NRF_GPIO_PIN_S0S1, + NRF_GPIO_PIN_NOSENSE); + // - MOSI (optional) - output with initial value 0, + if (p_config->mosi_pin != NRFX_SPI_PIN_NOT_USED) + { + mosi_pin = p_config->mosi_pin; + nrf_gpio_pin_clear(mosi_pin); + nrf_gpio_cfg_output(mosi_pin); + } + else + { + mosi_pin = NRF_SPI_PIN_NOT_CONNECTED; + } + // - MISO (optional) - input, + if (p_config->miso_pin != NRFX_SPI_PIN_NOT_USED) + { + miso_pin = p_config->miso_pin; + nrf_gpio_cfg_input(miso_pin, (nrf_gpio_pin_pull_t)NRFX_SPI_MISO_PULL_CFG); + } + else + { + miso_pin = NRF_SPI_PIN_NOT_CONNECTED; + } + m_cb[p_instance->drv_inst_idx].miso_pin = p_config->miso_pin; + // - Slave Select (optional) - output with initial value 1 (inactive). + if (p_config->ss_pin != NRFX_SPI_PIN_NOT_USED) + { + nrf_gpio_pin_set(p_config->ss_pin); + nrf_gpio_cfg_output(p_config->ss_pin); + } + m_cb[p_instance->drv_inst_idx].ss_pin = p_config->ss_pin; + + NRF_SPI_Type * p_spi = p_instance->p_reg; + nrf_spi_pins_set(p_spi, p_config->sck_pin, mosi_pin, miso_pin); + nrf_spi_frequency_set(p_spi, p_config->frequency); + nrf_spi_configure(p_spi, p_config->mode, p_config->bit_order); + + m_cb[p_instance->drv_inst_idx].orc = p_config->orc; + + if (p_cb->handler) + { + nrf_spi_int_enable(p_spi, NRF_SPI_INT_READY_MASK); + } + + nrf_spi_enable(p_spi); + + if (p_cb->handler) + { + NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg), + p_config->irq_priority); + NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg)); + } + + p_cb->transfer_in_progress = false; + 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_spi_uninit(nrfx_spi_t const * const p_instance) +{ + spi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED); + + if (p_cb->handler) + { + NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_reg)); + } + + NRF_SPI_Type * p_spi = p_instance->p_reg; + if (p_cb->handler) + { + nrf_spi_int_disable(p_spi, NRF_SPI_ALL_INTS_MASK); + } + + if (p_cb->miso_pin != NRFX_SPI_PIN_NOT_USED) + { + nrf_gpio_cfg_default(p_cb->miso_pin); + } + nrf_spi_disable(p_spi); + +#if NRFX_CHECK(NRFX_PRS_ENABLED) + nrfx_prs_release(p_instance->p_reg); +#endif + + p_cb->state = NRFX_DRV_STATE_UNINITIALIZED; +} + +static void finish_transfer(spi_control_block_t * p_cb) +{ + // If Slave Select signal is used, this is the time to deactivate it. + if (p_cb->ss_pin != NRFX_SPI_PIN_NOT_USED) + { + nrf_gpio_pin_set(p_cb->ss_pin); + } + + // By clearing this flag before calling the handler we allow subsequent + // transfers to be started directly from the handler function. + p_cb->transfer_in_progress = false; + + p_cb->evt.type = NRFX_SPI_EVENT_DONE; + p_cb->handler(&p_cb->evt, p_cb->p_context); +} + +// This function is called from the IRQ handler or, in blocking mode, directly +// from the 'spi_xfer' function. +// It returns true as long as the transfer should be continued, otherwise (when +// there is nothing more to send/receive) it returns false. +static bool transfer_byte(NRF_SPI_Type * p_spi, spi_control_block_t * p_cb) +{ + // Read the data byte received in this transfer (always, because no further + // READY event can be generated until the current byte is read out from the + // RXD register), and store it in the RX buffer (only when needed). + volatile uint8_t rx_data = nrf_spi_rxd_get(p_spi); + if (p_cb->bytes_transferred < p_cb->evt.xfer_desc.rx_length) + { + p_cb->evt.xfer_desc.p_rx_buffer[p_cb->bytes_transferred] = rx_data; + } + + ++p_cb->bytes_transferred; + + // Check if there are more bytes to send or receive and write proper data + // byte (next one from TX buffer or over-run character) to the TXD register + // when needed. + // NOTE - we've already used 'p_cb->bytes_transferred + 1' bytes from our + // buffers, because we take advantage of double buffering of TXD + // register (so in effect one byte is still being transmitted now); + // see how the transfer is started in the 'spi_xfer' function. + size_t bytes_used = p_cb->bytes_transferred + 1; + + if (p_cb->abort) + { + if (bytes_used < p_cb->evt.xfer_desc.tx_length) + { + p_cb->evt.xfer_desc.tx_length = bytes_used; + } + if (bytes_used < p_cb->evt.xfer_desc.rx_length) + { + p_cb->evt.xfer_desc.rx_length = bytes_used; + } + } + + if (bytes_used < p_cb->evt.xfer_desc.tx_length) + { + nrf_spi_txd_set(p_spi, p_cb->evt.xfer_desc.p_tx_buffer[bytes_used]); + return true; + } + else if (bytes_used < p_cb->evt.xfer_desc.rx_length) + { + nrf_spi_txd_set(p_spi, p_cb->orc); + return true; + } + + return (p_cb->bytes_transferred < p_cb->evt.xfer_desc.tx_length || + p_cb->bytes_transferred < p_cb->evt.xfer_desc.rx_length); +} + +static void spi_xfer(NRF_SPI_Type * p_spi, + spi_control_block_t * p_cb, + nrfx_spi_xfer_desc_t const * p_xfer_desc) +{ + p_cb->bytes_transferred = 0; + nrf_spi_int_disable(p_spi, NRF_SPI_INT_READY_MASK); + + nrf_spi_event_clear(p_spi, NRF_SPI_EVENT_READY); + + // Start the transfer by writing some byte to the TXD register; + // if TX buffer is not empty, take the first byte from this buffer, + // otherwise - use over-run character. + nrf_spi_txd_set(p_spi, + (p_xfer_desc->tx_length > 0 ? p_xfer_desc->p_tx_buffer[0] : p_cb->orc)); + + // TXD register is double buffered, so next byte to be transmitted can + // be written immediately, if needed, i.e. if TX or RX transfer is to + // be more that 1 byte long. Again - if there is something more in TX + // buffer send it, otherwise use over-run character. + if (p_xfer_desc->tx_length > 1) + { + nrf_spi_txd_set(p_spi, p_xfer_desc->p_tx_buffer[1]); + } + else if (p_xfer_desc->rx_length > 1) + { + nrf_spi_txd_set(p_spi, p_cb->orc); + } + + // For blocking mode (user handler not provided) wait here for READY + // events (indicating that the byte from TXD register was transmitted + // and a new incoming byte was moved to the RXD register) and continue + // transaction until all requested bytes are transferred. + // In non-blocking mode - IRQ service routine will do this stuff. + if (p_cb->handler) + { + nrf_spi_int_enable(p_spi, NRF_SPI_INT_READY_MASK); + } + else + { + do { + while (!nrf_spi_event_check(p_spi, NRF_SPI_EVENT_READY)) {} + nrf_spi_event_clear(p_spi, NRF_SPI_EVENT_READY); + NRFX_LOG_DEBUG("SPI: Event: NRF_SPI_EVENT_READY."); + } while (transfer_byte(p_spi, p_cb)); + if (p_cb->ss_pin != NRFX_SPI_PIN_NOT_USED) + { + nrf_gpio_pin_set(p_cb->ss_pin); + } + } +} + +nrfx_err_t nrfx_spi_xfer(nrfx_spi_t const * const p_instance, + nrfx_spi_xfer_desc_t const * p_xfer_desc, + uint32_t flags) +{ + spi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED); + NRFX_ASSERT(p_xfer_desc->p_tx_buffer != NULL || p_xfer_desc->tx_length == 0); + NRFX_ASSERT(p_xfer_desc->p_rx_buffer != NULL || p_xfer_desc->rx_length == 0); + + nrfx_err_t err_code = NRFX_SUCCESS; + + if (p_cb->transfer_in_progress) + { + err_code = NRFX_ERROR_BUSY; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + else + { + if (p_cb->handler) + { + p_cb->transfer_in_progress = true; + } + } + + p_cb->evt.xfer_desc = *p_xfer_desc; + p_cb->abort = false; + + if (p_cb->ss_pin != NRFX_SPI_PIN_NOT_USED) + { + nrf_gpio_pin_clear(p_cb->ss_pin); + } + if (flags) + { + p_cb->transfer_in_progress = false; + err_code = NRFX_ERROR_NOT_SUPPORTED; + } + else + { + spi_xfer(p_instance->p_reg, p_cb, p_xfer_desc); + } + NRFX_LOG_INFO("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + +void nrfx_spi_abort(nrfx_spi_t const * p_instance) +{ + spi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED); + p_cb->abort = true; +} + +static void irq_handler(NRF_SPI_Type * p_spi, spi_control_block_t * p_cb) +{ + NRFX_ASSERT(p_cb->handler); + + nrf_spi_event_clear(p_spi, NRF_SPI_EVENT_READY); + NRFX_LOG_DEBUG("Event: NRF_SPI_EVENT_READY."); + + if (!transfer_byte(p_spi, p_cb)) + { + finish_transfer(p_cb); + } +} + +#if NRFX_CHECK(NRFX_SPI0_ENABLED) +void nrfx_spi_0_irq_handler(void) +{ + irq_handler(NRF_SPI0, &m_cb[NRFX_SPI0_INST_IDX]); +} +#endif + +#if NRFX_CHECK(NRFX_SPI1_ENABLED) +void nrfx_spi_1_irq_handler(void) +{ + irq_handler(NRF_SPI1, &m_cb[NRFX_SPI1_INST_IDX]); +} +#endif + +#if NRFX_CHECK(NRFX_SPI2_ENABLED) +void nrfx_spi_2_irq_handler(void) +{ + irq_handler(NRF_SPI2, &m_cb[NRFX_SPI2_INST_IDX]); +} +#endif + +#endif // NRFX_CHECK(NRFX_SPI_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_spim.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_spim.c new file mode 100644 index 0000000..cf16e26 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_spim.c @@ -0,0 +1,688 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_SPIM_ENABLED) + +#if !(NRFX_CHECK(NRFX_SPIM0_ENABLED) || NRFX_CHECK(NRFX_SPIM1_ENABLED) || \ + NRFX_CHECK(NRFX_SPIM2_ENABLED) || NRFX_CHECK(NRFX_SPIM3_ENABLED)) +#error "No enabled SPIM instances. Check <nrfx_config.h>." +#endif + +#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) && !NRFX_CHECK(NRFX_SPIM3_ENABLED) +#error "Extended options are available only in SPIM3 on the nRF52840 SoC." +#endif + +#include <nrfx_spim.h> +#include "prs/nrfx_prs.h" +#include <hal/nrf_gpio.h> + +#define NRFX_LOG_MODULE SPIM +#include <nrfx_log.h> + +#define SPIMX_LENGTH_VALIDATE(peripheral, drv_inst_idx, rx_len, tx_len) \ + (((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) && \ + NRFX_EASYDMA_LENGTH_VALIDATE(peripheral, rx_len, tx_len)) + +#if NRFX_CHECK(NRFX_SPIM0_ENABLED) +#define SPIM0_LENGTH_VALIDATE(...) SPIMX_LENGTH_VALIDATE(SPIM0, __VA_ARGS__) +#else +#define SPIM0_LENGTH_VALIDATE(...) 0 +#endif + +#if NRFX_CHECK(NRFX_SPIM1_ENABLED) +#define SPIM1_LENGTH_VALIDATE(...) SPIMX_LENGTH_VALIDATE(SPIM1, __VA_ARGS__) +#else +#define SPIM1_LENGTH_VALIDATE(...) 0 +#endif + +#if NRFX_CHECK(NRFX_SPIM2_ENABLED) +#define SPIM2_LENGTH_VALIDATE(...) SPIMX_LENGTH_VALIDATE(SPIM2, __VA_ARGS__) +#else +#define SPIM2_LENGTH_VALIDATE(...) 0 +#endif + +#if NRFX_CHECK(NRFX_SPIM3_ENABLED) +#define SPIM3_LENGTH_VALIDATE(...) SPIMX_LENGTH_VALIDATE(SPIM3, __VA_ARGS__) +#else +#define SPIM3_LENGTH_VALIDATE(...) 0 +#endif + +#define SPIM_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) \ + (SPIM0_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \ + SPIM1_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \ + SPIM2_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \ + SPIM3_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len)) + + +// Control block - driver instance local data. +typedef struct +{ + nrfx_spim_evt_handler_t handler; + void * p_context; + nrfx_spim_evt_t evt; // Keep the struct that is ready for event handler. Less memcpy. + nrfx_drv_state_t state; + volatile bool transfer_in_progress; + +#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) + bool use_hw_ss; +#endif + + // [no need for 'volatile' attribute for the following members, as they + // are not concurrently used in IRQ handlers and main line code] + bool ss_active_high; + uint8_t ss_pin; + uint8_t miso_pin; + uint8_t orc; + +#if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED) + size_t tx_length; + size_t rx_length; +#endif +} spim_control_block_t; +static spim_control_block_t m_cb[NRFX_SPIM_ENABLED_COUNT]; + +#if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED) + +// Workaround for nRF52840 anomaly 198: SPIM3 transmit data might be corrupted. + +static uint32_t m_anomaly_198_preserved_value; + +static void anomaly_198_enable(uint8_t const * p_buffer, size_t buf_len) +{ + m_anomaly_198_preserved_value = *((volatile uint32_t *)0x40000E00); + + if (buf_len == 0) + { + return; + } + uint32_t buffer_end_addr = ((uint32_t)p_buffer) + buf_len; + uint32_t block_addr = ((uint32_t)p_buffer) & ~0x1FFF; + uint32_t block_flag = (1UL << ((block_addr >> 13) & 0xFFFF)); + uint32_t occupied_blocks = 0; + + if (block_addr >= 0x20010000) + { + occupied_blocks = (1UL << 8); + } + else + { + do { + occupied_blocks |= block_flag; + block_flag <<= 1; + block_addr += 0x2000; + } while ((block_addr < buffer_end_addr) && (block_addr < 0x20012000)); + } + + *((volatile uint32_t *)0x40000E00) = occupied_blocks; +} + +static void anomaly_198_disable(void) +{ + *((volatile uint32_t *)0x40000E00) = m_anomaly_198_preserved_value; +} +#endif // NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED) + +nrfx_err_t nrfx_spim_init(nrfx_spim_t const * const p_instance, + nrfx_spim_config_t const * p_config, + nrfx_spim_evt_handler_t handler, + void * p_context) +{ + NRFX_ASSERT(p_config); + spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + nrfx_err_t err_code; + + 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_SPIM_EXTENDED_ENABLED) + + // Currently, only SPIM3 in nRF52840 supports the extended features. Other instances must be checked. + if ((p_instance->drv_inst_idx != NRFX_SPIM3_INST_IDX) && + ((p_config->dcx_pin != NRFX_SPIM_PIN_NOT_USED) || + (p_config->frequency == NRF_SPIM_FREQ_16M) || + (p_config->frequency == NRF_SPIM_FREQ_32M) || + (p_config->rx_delay != 0x00) || + (p_config->use_hw_ss))) + { + err_code = NRFX_ERROR_NOT_SUPPORTED; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } +#endif + + NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg; + +#if NRFX_CHECK(NRFX_PRS_ENABLED) + static nrfx_irq_handler_t const irq_handlers[NRFX_SPIM_ENABLED_COUNT] = { + #if NRFX_CHECK(NRFX_SPIM0_ENABLED) + nrfx_spim_0_irq_handler, + #endif + #if NRFX_CHECK(NRFX_SPIM1_ENABLED) + nrfx_spim_1_irq_handler, + #endif + #if NRFX_CHECK(NRFX_SPIM2_ENABLED) + nrfx_spim_2_irq_handler, + #endif + #if NRFX_CHECK(NRFX_SPIM3_ENABLED) + nrfx_spim_3_irq_handler, + #endif + }; + if (nrfx_prs_acquire(p_instance->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) + + p_cb->handler = handler; + p_cb->p_context = p_context; + + uint32_t mosi_pin; + uint32_t miso_pin; + // Configure pins used by the peripheral: + // - SCK - output with initial value corresponding with the SPI mode used: + // 0 - for modes 0 and 1 (CPOL = 0), 1 - for modes 2 and 3 (CPOL = 1); + // according to the reference manual guidelines this pin and its input + // buffer must always be connected for the SPI to work. + if (p_config->mode <= NRF_SPIM_MODE_1) + { + nrf_gpio_pin_clear(p_config->sck_pin); + } + else + { + nrf_gpio_pin_set(p_config->sck_pin); + } + nrf_gpio_cfg(p_config->sck_pin, + NRF_GPIO_PIN_DIR_OUTPUT, + NRF_GPIO_PIN_INPUT_CONNECT, + NRF_GPIO_PIN_NOPULL, + NRF_GPIO_PIN_S0S1, + NRF_GPIO_PIN_NOSENSE); + // - MOSI (optional) - output with initial value 0, + if (p_config->mosi_pin != NRFX_SPIM_PIN_NOT_USED) + { + mosi_pin = p_config->mosi_pin; + nrf_gpio_pin_clear(mosi_pin); + nrf_gpio_cfg_output(mosi_pin); + } + else + { + mosi_pin = NRF_SPIM_PIN_NOT_CONNECTED; + } + // - MISO (optional) - input, + if (p_config->miso_pin != NRFX_SPIM_PIN_NOT_USED) + { + miso_pin = p_config->miso_pin; + nrf_gpio_cfg_input(miso_pin, (nrf_gpio_pin_pull_t)NRFX_SPIM_MISO_PULL_CFG); + } + else + { + miso_pin = NRF_SPIM_PIN_NOT_CONNECTED; + } + m_cb[p_instance->drv_inst_idx].miso_pin = p_config->miso_pin; + // - Slave Select (optional) - output with initial value 1 (inactive). + if (p_config->ss_pin != NRFX_SPIM_PIN_NOT_USED) + { + if (p_config->ss_active_high) + { + nrf_gpio_pin_clear(p_config->ss_pin); + } + else + { + nrf_gpio_pin_set(p_config->ss_pin); + } + nrf_gpio_cfg_output(p_config->ss_pin); +#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) + if (p_config->use_hw_ss) + { + m_cb[p_instance->drv_inst_idx].use_hw_ss = p_config->use_hw_ss; + nrf_spim_csn_configure(p_spim, + p_config->ss_pin, + (p_config->ss_active_high == true ? + NRF_SPIM_CSN_POL_HIGH : NRF_SPIM_CSN_POL_LOW), + p_config->ss_duration); + } +#endif + m_cb[p_instance->drv_inst_idx].ss_pin = p_config->ss_pin; + m_cb[p_instance->drv_inst_idx].ss_active_high = p_config->ss_active_high; + } + +#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) + // - DCX (optional) - output. + if (p_config->dcx_pin != NRFX_SPIM_PIN_NOT_USED) + { + nrf_gpio_pin_set(p_config->dcx_pin); + nrf_gpio_cfg_output(p_config->dcx_pin); + nrf_spim_dcx_pin_set(p_spim, p_config->dcx_pin); + } + + // Change rx delay + nrf_spim_iftiming_set(p_spim, p_config->rx_delay); +#endif + + + nrf_spim_pins_set(p_spim, p_config->sck_pin, mosi_pin, miso_pin); + nrf_spim_frequency_set(p_spim, p_config->frequency); + nrf_spim_configure(p_spim, p_config->mode, p_config->bit_order); + + nrf_spim_orc_set(p_spim, p_config->orc); + + if (p_cb->handler) + { + nrf_spim_int_enable(p_spim, NRF_SPIM_INT_END_MASK); + } + + nrf_spim_enable(p_spim); + + if (p_cb->handler) + { + NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg), + p_config->irq_priority); + NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg)); + } + + p_cb->transfer_in_progress = false; + 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_spim_uninit(nrfx_spim_t const * const p_instance) +{ + spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED); + + if (p_cb->handler) + { + NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_reg)); + } + + NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg; + if (p_cb->handler) + { + nrf_spim_int_disable(p_spim, NRF_SPIM_ALL_INTS_MASK); + if (p_cb->transfer_in_progress) + { + // Ensure that SPI is not performing any transfer. + nrf_spim_task_trigger(p_spim, NRF_SPIM_TASK_STOP); + while (!nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_STOPPED)) + {} + p_cb->transfer_in_progress = false; + } + } + + if (p_cb->miso_pin != NRFX_SPIM_PIN_NOT_USED) + { + nrf_gpio_cfg_default(p_cb->miso_pin); + } + nrf_spim_disable(p_spim); + +#if NRFX_CHECK(NRFX_PRS_ENABLED) + nrfx_prs_release(p_instance->p_reg); +#endif + + p_cb->state = NRFX_DRV_STATE_UNINITIALIZED; +} + +#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) +nrfx_err_t nrfx_spim_xfer_dcx(nrfx_spim_t const * const p_instance, + nrfx_spim_xfer_desc_t const * p_xfer_desc, + uint32_t flags, + uint8_t cmd_length) +{ + NRFX_ASSERT(cmd_length <= NRF_SPIM_DCX_CNT_ALL_CMD); + nrf_spim_dcx_cnt_set((NRF_SPIM_Type *)p_instance->p_reg, cmd_length); + return nrfx_spim_xfer(p_instance, p_xfer_desc, 0); +} +#endif + +static void finish_transfer(spim_control_block_t * p_cb) +{ + // If Slave Select signal is used, this is the time to deactivate it. + if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED) + { +#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) + if (!p_cb->use_hw_ss) +#endif + { + if (p_cb->ss_active_high) + { + nrf_gpio_pin_clear(p_cb->ss_pin); + } + else + { + nrf_gpio_pin_set(p_cb->ss_pin); + } + } + } + + // By clearing this flag before calling the handler we allow subsequent + // transfers to be started directly from the handler function. + p_cb->transfer_in_progress = false; + + p_cb->evt.type = NRFX_SPIM_EVENT_DONE; + p_cb->handler(&p_cb->evt, p_cb->p_context); +} + +__STATIC_INLINE void spim_int_enable(NRF_SPIM_Type * p_spim, bool enable) +{ + if (!enable) + { + nrf_spim_int_disable(p_spim, NRF_SPIM_INT_END_MASK); + } + else + { + nrf_spim_int_enable(p_spim, NRF_SPIM_INT_END_MASK); + } +} + +__STATIC_INLINE void spim_list_enable_handle(NRF_SPIM_Type * p_spim, uint32_t flags) +{ + if (NRFX_SPIM_FLAG_TX_POSTINC & flags) + { + nrf_spim_tx_list_enable(p_spim); + } + else + { + nrf_spim_tx_list_disable(p_spim); + } + + if (NRFX_SPIM_FLAG_RX_POSTINC & flags) + { + nrf_spim_rx_list_enable(p_spim); + } + else + { + nrf_spim_rx_list_disable(p_spim); + } +} + +static nrfx_err_t spim_xfer(NRF_SPIM_Type * p_spim, + spim_control_block_t * p_cb, + nrfx_spim_xfer_desc_t const * p_xfer_desc, + uint32_t flags) +{ + nrfx_err_t err_code; + // EasyDMA requires that transfer buffers are placed in Data RAM region; + // signal error if they are not. + if ((p_xfer_desc->p_tx_buffer != NULL && !nrfx_is_in_ram(p_xfer_desc->p_tx_buffer)) || + (p_xfer_desc->p_rx_buffer != NULL && !nrfx_is_in_ram(p_xfer_desc->p_rx_buffer))) + { + p_cb->transfer_in_progress = false; + 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; + } + +#if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED) + p_cb->tx_length = 0; + p_cb->rx_length = 0; +#endif + + nrf_spim_tx_buffer_set(p_spim, p_xfer_desc->p_tx_buffer, p_xfer_desc->tx_length); + nrf_spim_rx_buffer_set(p_spim, p_xfer_desc->p_rx_buffer, p_xfer_desc->rx_length); + +#if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED) + if (p_spim == NRF_SPIM3) + { + anomaly_198_enable(p_xfer_desc->p_tx_buffer, p_xfer_desc->tx_length); + } +#endif + + nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END); + + spim_list_enable_handle(p_spim, flags); + + if (!(flags & NRFX_SPIM_FLAG_HOLD_XFER)) + { + nrf_spim_task_trigger(p_spim, NRF_SPIM_TASK_START); + } +#if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED) + if (flags & NRFX_SPIM_FLAG_HOLD_XFER) + { + nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED); + p_cb->tx_length = p_xfer_desc->tx_length; + p_cb->rx_length = p_xfer_desc->rx_length; + nrf_spim_tx_buffer_set(p_spim, p_xfer_desc->p_tx_buffer, 0); + nrf_spim_rx_buffer_set(p_spim, p_xfer_desc->p_rx_buffer, 0); + nrf_spim_int_enable(p_spim, NRF_SPIM_INT_STARTED_MASK); + } +#endif + + if (!p_cb->handler) + { + while (!nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_END)){} + +#if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED) + if (p_spim == NRF_SPIM3) + { + anomaly_198_disable(); + } +#endif + if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED) + { +#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) + if (!p_cb->use_hw_ss) +#endif + { + if (p_cb->ss_active_high) + { + nrf_gpio_pin_clear(p_cb->ss_pin); + } + else + { + nrf_gpio_pin_set(p_cb->ss_pin); + } + } + } + } + else + { + spim_int_enable(p_spim, !(flags & NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER)); + } + 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_spim_xfer(nrfx_spim_t const * const p_instance, + nrfx_spim_xfer_desc_t const * p_xfer_desc, + uint32_t flags) +{ + spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED); + NRFX_ASSERT(p_xfer_desc->p_tx_buffer != NULL || p_xfer_desc->tx_length == 0); + NRFX_ASSERT(p_xfer_desc->p_rx_buffer != NULL || p_xfer_desc->rx_length == 0); + NRFX_ASSERT(SPIM_LENGTH_VALIDATE(p_instance->drv_inst_idx, + p_xfer_desc->rx_length, + p_xfer_desc->tx_length)); + + nrfx_err_t err_code = NRFX_SUCCESS; + + if (p_cb->transfer_in_progress) + { + err_code = NRFX_ERROR_BUSY; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + else + { + if (p_cb->handler && !(flags & (NRFX_SPIM_FLAG_REPEATED_XFER | + NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER))) + { + p_cb->transfer_in_progress = true; + } + } + + p_cb->evt.xfer_desc = *p_xfer_desc; + + if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED) + { +#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) + if (!p_cb->use_hw_ss) +#endif + { + if (p_cb->ss_active_high) + { + nrf_gpio_pin_set(p_cb->ss_pin); + } + else + { + nrf_gpio_pin_clear(p_cb->ss_pin); + } + } + } + + return spim_xfer(p_instance->p_reg, p_cb, p_xfer_desc, flags); +} + +void nrfx_spim_abort(nrfx_spim_t const * p_instance) +{ + spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED); + + nrf_spim_task_trigger(p_instance->p_reg, NRF_SPIM_TASK_STOP); + while (!nrf_spim_event_check(p_instance->p_reg, NRF_SPIM_EVENT_STOPPED)) + {} + p_cb->transfer_in_progress = false; +} + +uint32_t nrfx_spim_start_task_get(nrfx_spim_t const * p_instance) +{ + NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg; + return nrf_spim_task_address_get(p_spim, NRF_SPIM_TASK_START); +} + +uint32_t nrfx_spim_end_event_get(nrfx_spim_t const * p_instance) +{ + NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg; + return nrf_spim_event_address_get(p_spim, NRF_SPIM_EVENT_END); +} + +static void irq_handler(NRF_SPIM_Type * p_spim, spim_control_block_t * p_cb) +{ + +#if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED) + if ((nrf_spim_int_enable_check(p_spim, NRF_SPIM_INT_STARTED_MASK)) && + (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_STARTED)) ) + { + /* Handle first, zero-length, auxiliary transmission. */ + nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED); + nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END); + + NRFX_ASSERT(p_spim->TXD.MAXCNT == 0); + p_spim->TXD.MAXCNT = p_cb->tx_length; + + NRFX_ASSERT(p_spim->RXD.MAXCNT == 0); + p_spim->RXD.MAXCNT = p_cb->rx_length; + + /* Disable STARTED interrupt, used only in auxiliary transmission. */ + nrf_spim_int_disable(p_spim, NRF_SPIM_INT_STARTED_MASK); + + /* Start the actual, glitch-free transmission. */ + nrf_spim_task_trigger(p_spim, NRF_SPIM_TASK_START); + return; + } +#endif + + if (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_END)) + { +#if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED) + if (p_spim == NRF_SPIM3) + { + anomaly_198_disable(); + } +#endif + nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END); + NRFX_ASSERT(p_cb->handler); + NRFX_LOG_DEBUG("Event: NRF_SPIM_EVENT_END."); + finish_transfer(p_cb); + } +} + +#if NRFX_CHECK(NRFX_SPIM0_ENABLED) +void nrfx_spim_0_irq_handler(void) +{ + irq_handler(NRF_SPIM0, &m_cb[NRFX_SPIM0_INST_IDX]); +} +#endif + +#if NRFX_CHECK(NRFX_SPIM1_ENABLED) +void nrfx_spim_1_irq_handler(void) +{ + irq_handler(NRF_SPIM1, &m_cb[NRFX_SPIM1_INST_IDX]); +} +#endif + +#if NRFX_CHECK(NRFX_SPIM2_ENABLED) +void nrfx_spim_2_irq_handler(void) +{ + irq_handler(NRF_SPIM2, &m_cb[NRFX_SPIM2_INST_IDX]); +} +#endif + +#if NRFX_CHECK(NRFX_SPIM3_ENABLED) +void nrfx_spim_3_irq_handler(void) +{ + irq_handler(NRF_SPIM3, &m_cb[NRFX_SPIM3_INST_IDX]); +} +#endif + +#endif // NRFX_CHECK(NRFX_SPIM_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_spis.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_spis.c new file mode 100644 index 0000000..53075f0 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_spis.c @@ -0,0 +1,494 @@ +/** + * Copyright (c) 2013 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_SPIS_ENABLED) + +#if !(NRFX_CHECK(NRFX_SPIS0_ENABLED) || NRFX_CHECK(NRFX_SPIS1_ENABLED) || \ + NRFX_CHECK(NRFX_SPIS2_ENABLED)) +#error "No enabled SPIS instances. Check <nrfx_config.h>." +#endif + +#include <nrfx_spis.h> +#include "prs/nrfx_prs.h" + +#define NRFX_LOG_MODULE SPIS +#include <nrfx_log.h> + +#define EVT_TO_STR(event) \ + (event == NRF_SPIS_EVENT_ACQUIRED ? "NRF_SPIS_EVENT_ACQUIRED" : \ + (event == NRF_SPIS_EVENT_END ? "NRF_SPIS_EVENT_END" : \ + "UNKNOWN ERROR")) + +#define SPISX_LENGTH_VALIDATE(peripheral, drv_inst_idx, rx_len, tx_len) \ + (((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) && \ + NRFX_EASYDMA_LENGTH_VALIDATE(peripheral, rx_len, tx_len)) + +#if NRFX_CHECK(NRFX_SPIS0_ENABLED) +#define SPIS0_LENGTH_VALIDATE(...) SPISX_LENGTH_VALIDATE(SPIS0, __VA_ARGS__) +#else +#define SPIS0_LENGTH_VALIDATE(...) 0 +#endif + +#if NRFX_CHECK(NRFX_SPIS1_ENABLED) +#define SPIS1_LENGTH_VALIDATE(...) SPISX_LENGTH_VALIDATE(SPIS1, __VA_ARGS__) +#else +#define SPIS1_LENGTH_VALIDATE(...) 0 +#endif + +#if NRFX_CHECK(NRFX_SPIS2_ENABLED) +#define SPIS2_LENGTH_VALIDATE(...) SPISX_LENGTH_VALIDATE(SPIS2, __VA_ARGS__) +#else +#define SPIS2_LENGTH_VALIDATE(...) 0 +#endif + +#define SPIS_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) \ + (SPIS0_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \ + SPIS1_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \ + SPIS2_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len)) + + +#if NRFX_CHECK(NRFX_SPIS_NRF52_ANOMALY_109_WORKAROUND_ENABLED) +#include <nrfx_gpiote.h> +#define USE_DMA_ISSUE_WORKAROUND +// This handler is called by the GPIOTE driver when a falling edge is detected +// on the CSN line. There is no need to do anything here. The handling of the +// interrupt itself provides a protection for DMA transfers. +static void csn_event_handler(nrfx_gpiote_pin_t pin, + nrf_gpiote_polarity_t action) +{ +} +#endif + + +/**@brief States of the SPI transaction state machine. */ +typedef enum +{ + SPIS_STATE_INIT, /**< Initialization state. In this state the module waits for a call to @ref spi_slave_buffers_set. */ + SPIS_BUFFER_RESOURCE_REQUESTED, /**< State where the configuration of the memory buffers, which are to be used in SPI transaction, has started. */ + SPIS_BUFFER_RESOURCE_CONFIGURED, /**< State where the configuration of the memory buffers, which are to be used in SPI transaction, has completed. */ + SPIS_XFER_COMPLETED /**< State where SPI transaction has been completed. */ +} nrfx_spis_state_t; + +/**@brief SPIS control block - driver instance local data. */ +typedef struct +{ + volatile uint32_t tx_buffer_size; //!< SPI slave TX buffer size in bytes. + volatile uint32_t rx_buffer_size; //!< SPI slave RX buffer size in bytes. + nrfx_spis_event_handler_t handler; //!< SPI event handler. + volatile const uint8_t * tx_buffer; //!< SPI slave TX buffer. + volatile uint8_t * rx_buffer; //!< SPI slave RX buffer. + nrfx_drv_state_t state; //!< driver initialization state. + volatile nrfx_spis_state_t spi_state; //!< SPI slave state. + void * p_context; //!< Context set on initialization. +} spis_cb_t; + +static spis_cb_t m_cb[NRFX_SPIS_ENABLED_COUNT]; + +nrfx_err_t nrfx_spis_init(nrfx_spis_t const * const p_instance, + nrfx_spis_config_t const * p_config, + nrfx_spis_event_handler_t event_handler, + void * p_context) +{ + NRFX_ASSERT(p_config); + NRFX_ASSERT(event_handler); + spis_cb_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + nrfx_err_t err_code; + + NRF_SPIS_Type * p_spis = p_instance->p_reg; + + 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 ((uint32_t)p_config->mode > (uint32_t)NRF_SPIS_MODE_3) + { + err_code = NRFX_ERROR_INVALID_PARAM; + 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_SPIS_ENABLED_COUNT] = { + #if NRFX_CHECK(NRFX_SPIS0_ENABLED) + nrfx_spis_0_irq_handler, + #endif + #if NRFX_CHECK(NRFX_SPIS1_ENABLED) + nrfx_spis_1_irq_handler, + #endif + #if NRFX_CHECK(NRFX_SPIS2_ENABLED) + nrfx_spis_2_irq_handler, + #endif + }; + if (nrfx_prs_acquire(p_spis, + 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) + + // Configure the SPI pins for input. + uint32_t mosi_pin; + uint32_t miso_pin; + + if (p_config->miso_pin != NRFX_SPIS_PIN_NOT_USED) + { + nrf_gpio_cfg(p_config->miso_pin, + NRF_GPIO_PIN_DIR_INPUT, + NRF_GPIO_PIN_INPUT_CONNECT, + NRF_GPIO_PIN_NOPULL, + p_config->miso_drive, + NRF_GPIO_PIN_NOSENSE); + miso_pin = p_config->miso_pin; + } + else + { + miso_pin = NRF_SPIS_PIN_NOT_CONNECTED; + } + + if (p_config->mosi_pin != NRFX_SPIS_PIN_NOT_USED) + { + nrf_gpio_cfg(p_config->mosi_pin, + NRF_GPIO_PIN_DIR_INPUT, + NRF_GPIO_PIN_INPUT_CONNECT, + NRF_GPIO_PIN_NOPULL, + NRF_GPIO_PIN_S0S1, + NRF_GPIO_PIN_NOSENSE); + mosi_pin = p_config->mosi_pin; + } + else + { + mosi_pin = NRF_SPIS_PIN_NOT_CONNECTED; + } + + nrf_gpio_cfg(p_config->csn_pin, + NRF_GPIO_PIN_DIR_INPUT, + NRF_GPIO_PIN_INPUT_CONNECT, + p_config->csn_pullup, + NRF_GPIO_PIN_S0S1, + NRF_GPIO_PIN_NOSENSE); + + nrf_gpio_cfg(p_config->sck_pin, + NRF_GPIO_PIN_DIR_INPUT, + NRF_GPIO_PIN_INPUT_CONNECT, + NRF_GPIO_PIN_NOPULL, + NRF_GPIO_PIN_S0S1, + NRF_GPIO_PIN_NOSENSE); + + nrf_spis_pins_set(p_spis, p_config->sck_pin, mosi_pin, miso_pin, p_config->csn_pin); + + nrf_spis_rx_buffer_set(p_spis, NULL, 0); + nrf_spis_tx_buffer_set(p_spis, NULL, 0); + + // Configure SPI mode. + nrf_spis_configure(p_spis, p_config->mode, p_config->bit_order); + + // Configure DEF and ORC characters. + nrf_spis_def_set(p_spis, p_config->def); + nrf_spis_orc_set(p_spis, p_config->orc); + + // Clear possible pending events. + nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_END); + nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_ACQUIRED); + + // Enable END_ACQUIRE shortcut. + nrf_spis_shorts_enable(p_spis, NRF_SPIS_SHORT_END_ACQUIRE); + + p_cb->spi_state = SPIS_STATE_INIT; + p_cb->handler = event_handler; + p_cb->p_context = p_context; + +#if defined(USE_DMA_ISSUE_WORKAROUND) + // Configure a GPIOTE channel to generate interrupts on each falling edge + // on the CSN line. Handling of these interrupts will make the CPU active, + // and thus will protect the DMA transfers started by SPIS right after it + // is selected for communication. + // [the GPIOTE driver may be already initialized at this point (by this + // driver when another SPIS instance is used, or by an application code), + // so just ignore the returned value] + (void)nrfx_gpiote_init(); + static nrfx_gpiote_in_config_t const csn_gpiote_config = + NRFX_GPIOTE_CONFIG_IN_SENSE_HITOLO(true); + nrfx_err_t gpiote_err_code = nrfx_gpiote_in_init(p_config->csn_pin, + &csn_gpiote_config, csn_event_handler); + if (gpiote_err_code != NRFX_SUCCESS) + { + err_code = NRFX_ERROR_INTERNAL; + NRFX_LOG_INFO("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + nrfx_gpiote_in_event_enable(p_config->csn_pin, true); +#endif + + // Enable IRQ. + nrf_spis_int_enable(p_spis, NRF_SPIS_INT_ACQUIRED_MASK | + NRF_SPIS_INT_END_MASK); + NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg), + p_config->irq_priority); + NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg)); + + p_cb->state = NRFX_DRV_STATE_INITIALIZED; + + // Enable SPI slave device. + nrf_spis_enable(p_spis); + + NRFX_LOG_INFO("Initialized."); + return NRFX_SUCCESS; +} + + +void nrfx_spis_uninit(nrfx_spis_t const * const p_instance) +{ + spis_cb_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED); + + NRF_SPIS_Type * p_spis = p_instance->p_reg; + + #define DISABLE_ALL 0xFFFFFFFF + nrf_spis_disable(p_spis); + NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_reg)); + nrf_spis_int_disable(p_spis, DISABLE_ALL); + #undef DISABLE_ALL + +#if NRFX_CHECK(NRFX_PRS_ENABLED) + nrfx_prs_release(p_spis); +#endif + + p_cb->state = NRFX_DRV_STATE_UNINITIALIZED; + NRFX_LOG_INFO("Uninitialized."); +} + + +/**@brief Function for executing the state entry action. */ +static void spis_state_entry_action_execute(NRF_SPIS_Type * p_spis, + spis_cb_t * p_cb) +{ + nrfx_spis_evt_t event; + + switch (p_cb->spi_state) + { + case SPIS_BUFFER_RESOURCE_REQUESTED: + nrf_spis_task_trigger(p_spis, NRF_SPIS_TASK_ACQUIRE); + break; + + case SPIS_BUFFER_RESOURCE_CONFIGURED: + event.evt_type = NRFX_SPIS_BUFFERS_SET_DONE; + event.rx_amount = 0; + event.tx_amount = 0; + + NRFX_ASSERT(p_cb->handler != NULL); + p_cb->handler(&event, p_cb->p_context); + break; + + case SPIS_XFER_COMPLETED: + event.evt_type = NRFX_SPIS_XFER_DONE; + event.rx_amount = nrf_spis_rx_amount_get(p_spis); + event.tx_amount = nrf_spis_tx_amount_get(p_spis); + NRFX_LOG_INFO("Transfer rx_len:%d.", event.rx_amount); + NRFX_LOG_DEBUG("Rx data:"); + NRFX_LOG_HEXDUMP_DEBUG((uint8_t const *)p_cb->rx_buffer, + event.rx_amount * sizeof(p_cb->rx_buffer[0])); + NRFX_ASSERT(p_cb->handler != NULL); + p_cb->handler(&event, p_cb->p_context); + break; + + default: + // No implementation required. + break; + } +} + +/**@brief Function for changing the state of the SPI state machine. + * + * @param[in] p_spis SPIS instance register. + * @param[in] p_cb SPIS instance control block. + * @param[in] new_state State where the state machine transits to. + */ +static void spis_state_change(NRF_SPIS_Type * p_spis, + spis_cb_t * p_cb, + nrfx_spis_state_t new_state) +{ + p_cb->spi_state = new_state; + spis_state_entry_action_execute(p_spis, p_cb); +} + +nrfx_err_t nrfx_spis_buffers_set(nrfx_spis_t const * const p_instance, + uint8_t const * p_tx_buffer, + size_t tx_buffer_length, + uint8_t * p_rx_buffer, + size_t rx_buffer_length) +{ + NRFX_ASSERT(p_tx_buffer != NULL || tx_buffer_length == 0); + NRFX_ASSERT(p_rx_buffer != NULL || rx_buffer_length == 0); + + spis_cb_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + nrfx_err_t err_code; + + if (!SPIS_LENGTH_VALIDATE(p_instance->drv_inst_idx, + rx_buffer_length, + tx_buffer_length)) + { + return NRFX_ERROR_INVALID_LENGTH; + } + + // EasyDMA requires that transfer buffers are placed in Data RAM region; + // signal error if they are not. + if ((p_tx_buffer != NULL && !nrfx_is_in_ram(p_tx_buffer)) || + (p_rx_buffer != NULL && !nrfx_is_in_ram(p_rx_buffer))) + { + 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; + } + + switch (p_cb->spi_state) + { + case SPIS_STATE_INIT: + case SPIS_XFER_COMPLETED: + case SPIS_BUFFER_RESOURCE_CONFIGURED: + p_cb->tx_buffer = p_tx_buffer; + p_cb->rx_buffer = p_rx_buffer; + p_cb->tx_buffer_size = tx_buffer_length; + p_cb->rx_buffer_size = rx_buffer_length; + err_code = NRFX_SUCCESS; + + spis_state_change(p_instance->p_reg, p_cb, SPIS_BUFFER_RESOURCE_REQUESTED); + break; + + case SPIS_BUFFER_RESOURCE_REQUESTED: + err_code = NRFX_ERROR_INVALID_STATE; + break; + + default: + // @note: execution of this code path would imply internal error in the design. + err_code = NRFX_ERROR_INTERNAL; + break; + } + + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + +static void spis_irq_handler(NRF_SPIS_Type * p_spis, spis_cb_t * p_cb) +{ + // @note: as multiple events can be pending for processing, the correct event processing order + // is as follows: + // - SPI semaphore acquired event. + // - SPI transaction complete event. + + // Check for SPI semaphore acquired event. + if (nrf_spis_event_check(p_spis, NRF_SPIS_EVENT_ACQUIRED)) + { + nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_ACQUIRED); + NRFX_LOG_DEBUG("SPIS: Event: %s.", EVT_TO_STR(NRF_SPIS_EVENT_ACQUIRED)); + + switch (p_cb->spi_state) + { + case SPIS_BUFFER_RESOURCE_REQUESTED: + nrf_spis_tx_buffer_set(p_spis, (uint8_t *)p_cb->tx_buffer, p_cb->tx_buffer_size); + nrf_spis_rx_buffer_set(p_spis, (uint8_t *)p_cb->rx_buffer, p_cb->rx_buffer_size); + + nrf_spis_task_trigger(p_spis, NRF_SPIS_TASK_RELEASE); + + spis_state_change(p_spis, p_cb, SPIS_BUFFER_RESOURCE_CONFIGURED); + break; + + default: + // No implementation required. + break; + } + } + + // Check for SPI transaction complete event. + if (nrf_spis_event_check(p_spis, NRF_SPIS_EVENT_END)) + { + nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_END); + NRFX_LOG_DEBUG("SPIS: Event: %s.", EVT_TO_STR(NRF_SPIS_EVENT_END)); + + switch (p_cb->spi_state) + { + case SPIS_BUFFER_RESOURCE_CONFIGURED: + spis_state_change(p_spis, p_cb, SPIS_XFER_COMPLETED); + break; + + default: + // No implementation required. + break; + } + } +} + +#if NRFX_CHECK(NRFX_SPIS0_ENABLED) +void nrfx_spis_0_irq_handler(void) +{ + spis_irq_handler(NRF_SPIS0, &m_cb[NRFX_SPIS0_INST_IDX]); +} +#endif + +#if NRFX_CHECK(NRFX_SPIS1_ENABLED) +void nrfx_spis_1_irq_handler(void) +{ + spis_irq_handler(NRF_SPIS1, &m_cb[NRFX_SPIS1_INST_IDX]); +} +#endif + +#if NRFX_CHECK(NRFX_SPIS2_ENABLED) +void nrfx_spis_2_irq_handler(void) +{ + spis_irq_handler(NRF_SPIS2, &m_cb[NRFX_SPIS2_INST_IDX]); +} +#endif + +#endif // NRFX_CHECK(NRFX_SPIS_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_swi.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_swi.c new file mode 100644 index 0000000..4a6dcc4 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_swi.c @@ -0,0 +1,412 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_SWI_ENABLED) + +#include <nrfx_swi.h> + +#define NRFX_LOG_MODULE SWI +#include <nrfx_log.h> + + +// NRFX_SWI_RESERVED_MASK - SWIs reserved for use by external modules. +#if NRFX_CHECK(NRFX_PWM_NRF52_ANOMALY_109_WORKAROUND_ENABLED) +#define NRFX_SWI_RESERVED_MASK ((NRFX_SWI_USED) | \ + (1u << NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE)) +#else +#define NRFX_SWI_RESERVED_MASK (NRFX_SWI_USED) +#endif + +// NRFX_SWI_DISABLED_MASK - SWIs excluded from use in <nrfx_config.h>. +#if NRFX_CHECK(NRFX_SWI0_DISABLED) +#define NRFX_SWI0_DISABLED_MASK (1u << 0) +#else +#define NRFX_SWI0_DISABLED_MASK 0u +#endif +#if NRFX_CHECK(NRFX_SWI1_DISABLED) +#define NRFX_SWI1_DISABLED_MASK (1u << 1) +#else +#define NRFX_SWI1_DISABLED_MASK 0u +#endif +#if NRFX_CHECK(NRFX_SWI2_DISABLED) +#define NRFX_SWI2_DISABLED_MASK (1u << 2) +#else +#define NRFX_SWI2_DISABLED_MASK 0u +#endif +#if NRFX_CHECK(NRFX_SWI3_DISABLED) +#define NRFX_SWI3_DISABLED_MASK (1u << 3) +#else +#define NRFX_SWI3_DISABLED_MASK 0u +#endif +#if NRFX_CHECK(NRFX_SWI4_DISABLED) +#define NRFX_SWI4_DISABLED_MASK (1u << 4) +#else +#define NRFX_SWI4_DISABLED_MASK 0u +#endif +#if NRFX_CHECK(NRFX_SWI5_DISABLED) +#define NRFX_SWI5_DISABLED_MASK (1u << 5) +#else +#define NRFX_SWI5_DISABLED_MASK 0u +#endif +#define NRFX_SWI_DISABLED_MASK (NRFX_SWI0_DISABLED_MASK | \ + NRFX_SWI1_DISABLED_MASK | \ + NRFX_SWI2_DISABLED_MASK | \ + NRFX_SWI3_DISABLED_MASK | \ + NRFX_SWI4_DISABLED_MASK | \ + NRFX_SWI5_DISABLED_MASK) + +#if (NRFX_SWI_RESERVED_MASK & NRFX_SWI_DISABLED_MASK) +#error "A reserved SWI configured to be disabled. Check <nrfx_config.h> and NRFX_SWI_USED." +#endif + +// NRFX_SWI_AVAILABLE_MASK - SWIs available for this module, i.e. present +// in the hardware and neither reserved by external modules nor disabled +// in <nrfx_config.h>. +#define NRFX_SWI_PRESENT_MASK ((1u << (SWI_COUNT)) - 1u) +#define NRFX_SWI_AVAILABLE_MASK (NRFX_SWI_PRESENT_MASK & \ + ~(NRFX_SWI_RESERVED_MASK | \ + NRFX_SWI_DISABLED_MASK)) + +#if (NRFX_SWI_AVAILABLE_MASK == 0) +#error "No available SWI instances. Check <nrfx_config.h> and NRFX_SWI_USED." +#endif + +#define NRFX_SWI_IS_AVAILABLE(idx) ((NRFX_SWI_AVAILABLE_MASK >> (idx)) & 1u) + +#define NRFX_SWI_FIRST (NRFX_SWI_IS_AVAILABLE(0) ? 0u : \ + (NRFX_SWI_IS_AVAILABLE(1) ? 1u : \ + (NRFX_SWI_IS_AVAILABLE(2) ? 2u : \ + (NRFX_SWI_IS_AVAILABLE(3) ? 3u : \ + (NRFX_SWI_IS_AVAILABLE(4) ? 4u : \ + 5u))))) +#define NRFX_SWI_LAST (NRFX_SWI_IS_AVAILABLE(5) ? 5u : \ + (NRFX_SWI_IS_AVAILABLE(4) ? 4u : \ + (NRFX_SWI_IS_AVAILABLE(3) ? 3u : \ + (NRFX_SWI_IS_AVAILABLE(2) ? 2u : \ + (NRFX_SWI_IS_AVAILABLE(1) ? 1u : \ + 0u))))) + +// NRFX_SWI_EGU_COUNT - number of EGU instances to be used by this module +// (note - if EGU is not present, EGU_COUNT is not defined). +#if NRFX_CHECK(NRFX_EGU_ENABLED) +#define NRFX_SWI_EGU_COUNT EGU_COUNT +#else +#define NRFX_SWI_EGU_COUNT 0 +#endif + +// These flags are needed only for SWIs that have no corresponding EGU unit +// (in EGU such flags are available in hardware). +#if (NRFX_SWI_EGU_COUNT < SWI_COUNT) +static nrfx_swi_flags_t m_swi_flags[SWI_COUNT - NRFX_SWI_EGU_COUNT]; +#endif +static nrfx_swi_handler_t m_swi_handlers[SWI_COUNT]; +static uint8_t m_swi_allocated_mask; + + +static void swi_mark_allocated(nrfx_swi_t swi) +{ + m_swi_allocated_mask |= (1u << swi); +} + +static void swi_mark_unallocated(nrfx_swi_t swi) +{ + m_swi_allocated_mask &= ~(1u << swi); +} + +static bool swi_is_allocated(nrfx_swi_t swi) +{ + return (m_swi_allocated_mask & (1u << swi)); +} + +static bool swi_is_available(nrfx_swi_t swi) +{ + return NRFX_SWI_IS_AVAILABLE(swi); +} + +static IRQn_Type swi_irq_number_get(nrfx_swi_t swi) +{ + return (IRQn_Type)((uint32_t)SWI0_IRQn + (uint32_t)swi); +} + +static void swi_handler_setup(nrfx_swi_t swi, + nrfx_swi_handler_t event_handler, + uint32_t irq_priority) +{ + m_swi_handlers[swi] = event_handler; + +#if NRFX_SWI_EGU_COUNT + if (swi < NRFX_SWI_EGU_COUNT) + { + NRF_EGU_Type * p_egu = nrfx_swi_egu_instance_get(swi); + NRFX_ASSERT(p_egu != NULL); + nrf_egu_int_enable(p_egu, NRF_EGU_INT_ALL); + + if (event_handler == NULL) + { + return; + } + } +#endif + + NRFX_ASSERT(event_handler != NULL); + + NRFX_IRQ_PRIORITY_SET(swi_irq_number_get(swi), irq_priority); + NRFX_IRQ_ENABLE(swi_irq_number_get(swi)); +} + +nrfx_err_t nrfx_swi_alloc(nrfx_swi_t * p_swi, + nrfx_swi_handler_t event_handler, + uint32_t irq_priority) +{ + NRFX_ASSERT(p_swi != NULL); + + nrfx_err_t err_code; + + for (nrfx_swi_t swi = NRFX_SWI_FIRST; swi <= NRFX_SWI_LAST; ++swi) + { + if (swi_is_available(swi)) + { + bool allocated = false; + NRFX_CRITICAL_SECTION_ENTER(); + if (!swi_is_allocated(swi)) + { + swi_mark_allocated(swi); + allocated = true; + } + NRFX_CRITICAL_SECTION_EXIT(); + + if (allocated) + { + swi_handler_setup(swi, event_handler, irq_priority); + + *p_swi = swi; + NRFX_LOG_INFO("SWI channel allocated: %d.", (*p_swi)); + return NRFX_SUCCESS; + } + } + } + + err_code = NRFX_ERROR_NO_MEM; + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + +bool nrfx_swi_is_allocated(nrfx_swi_t swi) +{ + return swi_is_allocated(swi); +} + +void nrfx_swi_free(nrfx_swi_t * p_swi) +{ + NRFX_ASSERT(p_swi != NULL); + nrfx_swi_t swi = *p_swi; + + NRFX_ASSERT(swi_is_allocated(swi)); + NRFX_IRQ_DISABLE(swi_irq_number_get(swi)); + m_swi_handlers[swi] = NULL; + + swi_mark_unallocated(swi); + *p_swi = NRFX_SWI_UNALLOCATED; +} + +void nrfx_swi_all_free(void) +{ + for (nrfx_swi_t swi = NRFX_SWI_FIRST; swi <= NRFX_SWI_LAST; ++swi) + { + if (swi_is_allocated(swi)) + { + NRFX_IRQ_DISABLE(swi_irq_number_get(swi)); + m_swi_handlers[swi] = NULL; +#if NRFX_SWI_EGU_COUNT + if (swi < NRFX_SWI_EGU_COUNT) + { + nrf_egu_int_disable(nrfx_swi_egu_instance_get(swi), + NRF_EGU_INT_ALL); + } +#endif + } + } + + m_swi_allocated_mask = 0; +} + +void nrfx_swi_trigger(nrfx_swi_t swi, uint8_t flag_number) +{ + NRFX_ASSERT(swi_is_allocated(swi)); + +#if NRFX_SWI_EGU_COUNT + + NRF_EGU_Type * p_egu = nrfx_swi_egu_instance_get(swi); +#if (NRFX_SWI_EGU_COUNT < SWI_COUNT) + if (p_egu == NULL) + { + m_swi_flags[swi - NRFX_SWI_EGU_COUNT] |= (1 << flag_number); + NRFX_IRQ_PENDING_SET(swi_irq_number_get(swi)); + } + else +#endif // (NRFX_SWI_EGU_COUNT < SWI_COUNT) + { + nrf_egu_task_trigger(p_egu, + nrf_egu_task_trigger_get(p_egu, flag_number)); + } + +#else // -> #if !NRFX_SWI_EGU_COUNT + + m_swi_flags[swi - NRFX_SWI_EGU_COUNT] |= (1 << flag_number); + NRFX_IRQ_PENDING_SET(swi_irq_number_get(swi)); + +#endif +} + +#if NRFX_SWI_EGU_COUNT +static void egu_irq_handler(nrfx_swi_t swi, uint8_t egu_channel_count) +{ +#if (NRFX_SWI_FIRST > 0) + NRFX_ASSERT(swi >= NRFX_SWI_FIRST); +#endif + NRFX_ASSERT(swi <= NRFX_SWI_LAST); + nrfx_swi_handler_t handler = m_swi_handlers[swi]; + NRFX_ASSERT(handler != NULL); + + NRF_EGU_Type * p_egu = nrfx_swi_egu_instance_get(swi); + NRFX_ASSERT(p_egu != NULL); + + nrfx_swi_flags_t flags = 0; + for (uint8_t i = 0; i < egu_channel_count; ++i) + { + nrf_egu_event_t egu_event = nrf_egu_event_triggered_get(p_egu, i); + if (nrf_egu_event_check(p_egu, egu_event)) + { + flags |= (1u << i); + nrf_egu_event_clear(p_egu, egu_event); + } + } + + handler(swi, flags); +} +#endif // NRFX_SWI_EGU_COUNT + +#if (NRFX_SWI_EGU_COUNT < SWI_COUNT) +static void swi_irq_handler(nrfx_swi_t swi) +{ +#if (NRFX_SWI_FIRST > 0) + NRFX_ASSERT(swi >= NRFX_SWI_FIRST); +#endif + NRFX_ASSERT(swi <= NRFX_SWI_LAST); + nrfx_swi_handler_t handler = m_swi_handlers[swi]; + NRFX_ASSERT(handler != NULL); + + nrfx_swi_flags_t flags = m_swi_flags[swi - NRFX_SWI_EGU_COUNT]; + m_swi_flags[swi - NRFX_SWI_EGU_COUNT] &= ~flags; + + handler(swi, flags); +} +#endif // (NRFX_SWI_EGU_COUNT < SWI_COUNT) + + +#if NRFX_SWI_IS_AVAILABLE(0) +void nrfx_swi_0_irq_handler(void) +{ +#if (NRFX_SWI_EGU_COUNT > 0) + egu_irq_handler(0, EGU0_CH_NUM); +#else + swi_irq_handler(0); +#endif +} +#endif // NRFX_SWI_IS_AVAILABLE(0) + +#if NRFX_SWI_IS_AVAILABLE(1) +void nrfx_swi_1_irq_handler(void) +{ +#if (NRFX_SWI_EGU_COUNT > 1) + egu_irq_handler(1, EGU1_CH_NUM); +#else + swi_irq_handler(1); +#endif +} +#endif // NRFX_SWI_IS_AVAILABLE(1) + +#if NRFX_SWI_IS_AVAILABLE(2) +void nrfx_swi_2_irq_handler(void) +{ +#if (NRFX_SWI_EGU_COUNT > 2) + egu_irq_handler(2, EGU2_CH_NUM); +#else + swi_irq_handler(2); +#endif +} +#endif // NRFX_SWI_IS_AVAILABLE(2) + +#if NRFX_SWI_IS_AVAILABLE(3) +void nrfx_swi_3_irq_handler(void) +{ +#if (NRFX_SWI_EGU_COUNT > 3) + egu_irq_handler(3, EGU3_CH_NUM); +#else + swi_irq_handler(3); +#endif +} +#endif // NRFX_SWI_IS_AVAILABLE(3) + +#if NRFX_SWI_IS_AVAILABLE(4) +void nrfx_swi_4_irq_handler(void) +{ +#if (NRFX_SWI_EGU_COUNT > 4) + egu_irq_handler(4, EGU4_CH_NUM); +#else + swi_irq_handler(4); +#endif +} +#endif // NRFX_SWI_IS_AVAILABLE(4) + +#if NRFX_SWI_IS_AVAILABLE(5) +void nrfx_swi_5_irq_handler(void) +{ +#if (NRFX_SWI_EGU_COUNT > 5) + egu_irq_handler(5, EGU5_CH_NUM); +#else + swi_irq_handler(5); +#endif +} +#endif // NRFX_SWI_IS_AVAILABLE(5) + +#endif // NRFX_CHECK(NRFX_SWI_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_systick.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_systick.c new file mode 100644 index 0000000..ef38b0f --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_systick.c @@ -0,0 +1,170 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_SYSTICK_ENABLED) +#include <nrfx_systick.h> + +/** + * @brief Maximum number of ticks to delay + * + * The maximum number of ticks should be much lower than + * Physical maximum count of the SysTick timer. + * It is dictated by the fact that it would be impossible to detect delay + * properly when the timer value warps around the starting point. + */ +#define NRFX_SYSTICK_TICKS_MAX (NRF_SYSTICK_VAL_MASK / 2UL) + +/** + * @brief Number of milliseconds in a second + */ +#define NRFX_SYSTICK_MS (1000UL) + +/** + * @brief Number of microseconds in a second + */ +#define NRFX_SYSTICK_US (1000UL * NRFX_SYSTICK_MS) + +/** + * @brief Number of milliseconds to wait in single loop + * + * Constant used by @ref nrd_drv_systick_delay_ms function + * to split waiting into loops and rest. + * + * It describes the number of milliseconds to wait in single loop. + * + * See @ref nrfx_systick_delay_ms source code for details. + */ +#define NRFX_SYSTICK_MS_STEP (64U) + +/** + * @brief Checks if the given time is in correct range + * + * Function tests given time is not to big for this library. + * Assertion is used for testing. + * + * @param us Time in microseconds to check + */ +#define NRFX_SYSTICK_ASSERT_TIMEOUT(us) \ + NRFX_ASSERT(us <= (NRFX_SYSTICK_TICKS_MAX / ((SystemCoreClock) / NRFX_SYSTICK_US))); + +/** + * @brief Function that converts microseconds to ticks + * + * Function converts from microseconds to CPU ticks. + * + * @param us Number of microseconds + * + * @return Number of ticks + * + * @sa nrfx_systick_ms_tick + */ +static inline uint32_t nrfx_systick_us_tick(uint32_t us) +{ + return us * ((SystemCoreClock) / NRFX_SYSTICK_US); +} + +/** + * @brief Function that converts milliseconds to ticks + * + * Function converts from milliseconds to CPU ticks. + * + * @param us Number of milliseconds + * + * @return Number of ticks + * + * @sa nrfx_systick_us_tick + */ +static inline uint32_t nrfx_systick_ms_tick(uint32_t ms) +{ + return ms * ((SystemCoreClock) / NRFX_SYSTICK_MS); +} + +void nrfx_systick_init(void) +{ + nrf_systick_load_set(NRF_SYSTICK_VAL_MASK); + nrf_systick_csr_set( + NRF_SYSTICK_CSR_CLKSOURCE_CPU | + NRF_SYSTICK_CSR_TICKINT_DISABLE | + NRF_SYSTICK_CSR_ENABLE); +} + +void nrfx_systick_get(nrfx_systick_state_t * p_state) +{ + p_state->time = nrf_systick_val_get(); +} + +bool nrfx_systick_test(nrfx_systick_state_t const * p_state, uint32_t us) +{ + NRFX_SYSTICK_ASSERT_TIMEOUT(us); + + const uint32_t diff = NRF_SYSTICK_VAL_MASK & ((p_state->time) - nrf_systick_val_get()); + return (diff >= nrfx_systick_us_tick(us)); +} + +void nrfx_systick_delay_ticks(uint32_t ticks) +{ + NRFX_ASSERT(ticks <= NRFX_SYSTICK_TICKS_MAX); + + const uint32_t start = nrf_systick_val_get(); + while ((NRF_SYSTICK_VAL_MASK & (start - nrf_systick_val_get())) < ticks) + { + /* Nothing to do */ + } +} + +void nrfx_systick_delay_us(uint32_t us) +{ + NRFX_SYSTICK_ASSERT_TIMEOUT(us); + nrfx_systick_delay_ticks(nrfx_systick_us_tick(us)); +} + +void nrfx_systick_delay_ms(uint32_t ms) +{ + uint32_t n = ms / NRFX_SYSTICK_MS_STEP; + uint32_t r = ms % NRFX_SYSTICK_MS_STEP; + while (0 != (n--)) + { + nrfx_systick_delay_ticks(nrfx_systick_ms_tick(NRFX_SYSTICK_MS_STEP)); + } + nrfx_systick_delay_ticks(nrfx_systick_ms_tick(r)); +} + +#endif // NRFX_CHECK(NRFX_SYSTICK_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_timer.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_timer.c new file mode 100644 index 0000000..024958e --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_timer.c @@ -0,0 +1,330 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_TIMER_ENABLED) + +#if !(NRFX_CHECK(NRFX_TIMER0_ENABLED) || NRFX_CHECK(NRFX_TIMER1_ENABLED) || \ + NRFX_CHECK(NRFX_TIMER2_ENABLED) || NRFX_CHECK(NRFX_TIMER3_ENABLED) || \ + NRFX_CHECK(NRFX_TIMER4_ENABLED)) +#error "No enabled TIMER instances. Check <nrfx_config.h>." +#endif + +#include <nrfx_timer.h> + +#define NRFX_LOG_MODULE TIMER +#include <nrfx_log.h> + +/**@brief Timer control block. */ +typedef struct +{ + nrfx_timer_event_handler_t handler; + void * context; + nrfx_drv_state_t state; +} timer_control_block_t; + +static timer_control_block_t m_cb[NRFX_TIMER_ENABLED_COUNT]; + +nrfx_err_t nrfx_timer_init(nrfx_timer_t const * const p_instance, + nrfx_timer_config_t const * p_config, + nrfx_timer_event_handler_t timer_event_handler) +{ + timer_control_block_t * p_cb = &m_cb[p_instance->instance_id]; +#ifdef SOFTDEVICE_PRESENT + NRFX_ASSERT(p_instance->p_reg != NRF_TIMER0); +#endif + NRFX_ASSERT(p_config); + NRFX_ASSERT(timer_event_handler); + + nrfx_err_t err_code; + + 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; + } + + /* Warning 685: Relational operator '<=' always evaluates to 'true'" + * Warning in NRF_TIMER_IS_BIT_WIDTH_VALID macro. Macro validate timers resolution. + * Not necessary in nRF52 based systems. Obligatory in nRF51 based systems. + */ + + /*lint -save -e685 */ + + NRFX_ASSERT(NRF_TIMER_IS_BIT_WIDTH_VALID(p_instance->p_reg, p_config->bit_width)); + + //lint -restore + + p_cb->handler = timer_event_handler; + p_cb->context = p_config->p_context; + + uint8_t i; + for (i = 0; i < p_instance->cc_channel_count; ++i) + { + nrf_timer_event_clear(p_instance->p_reg, + nrf_timer_compare_event_get(i)); + } + + NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg), + p_config->interrupt_priority); + NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg)); + + nrf_timer_mode_set(p_instance->p_reg, p_config->mode); + nrf_timer_bit_width_set(p_instance->p_reg, p_config->bit_width); + nrf_timer_frequency_set(p_instance->p_reg, p_config->frequency); + + 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_timer_uninit(nrfx_timer_t const * const p_instance) +{ + NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_reg)); + + #define DISABLE_ALL UINT32_MAX + nrf_timer_shorts_disable(p_instance->p_reg, DISABLE_ALL); + nrf_timer_int_disable(p_instance->p_reg, DISABLE_ALL); + #undef DISABLE_ALL + + nrfx_timer_disable(p_instance); + + m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_UNINITIALIZED; + NRFX_LOG_INFO("Uninitialized instance: %d.", p_instance->instance_id); +} + +void nrfx_timer_enable(nrfx_timer_t const * const p_instance) +{ + NRFX_ASSERT(m_cb[p_instance->instance_id].state == NRFX_DRV_STATE_INITIALIZED); + nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_START); + m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_POWERED_ON; + NRFX_LOG_INFO("Enabled instance: %d.", p_instance->instance_id); +} + +void nrfx_timer_disable(nrfx_timer_t const * const p_instance) +{ + NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED); + nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_SHUTDOWN); + m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_INITIALIZED; + NRFX_LOG_INFO("Disabled instance: %d.", p_instance->instance_id); +} + +bool nrfx_timer_is_enabled(nrfx_timer_t const * const p_instance) +{ + NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED); + return (m_cb[p_instance->instance_id].state == NRFX_DRV_STATE_POWERED_ON); +} + +void nrfx_timer_resume(nrfx_timer_t const * const p_instance) +{ + NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED); + nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_START); + NRFX_LOG_INFO("Resumed instance: %d.", p_instance->instance_id); +} + +void nrfx_timer_pause(nrfx_timer_t const * const p_instance) +{ + NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED); + nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_STOP); + NRFX_LOG_INFO("Paused instance: %d.", p_instance->instance_id); +} + +void nrfx_timer_clear(nrfx_timer_t const * const p_instance) +{ + NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED); + nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_CLEAR); +} + +void nrfx_timer_increment(nrfx_timer_t const * const p_instance) +{ + NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED); + NRFX_ASSERT(nrf_timer_mode_get(p_instance->p_reg) != NRF_TIMER_MODE_TIMER); + + nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_COUNT); +} + +uint32_t nrfx_timer_capture(nrfx_timer_t const * const p_instance, + nrf_timer_cc_channel_t cc_channel) +{ + NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED); + NRFX_ASSERT(cc_channel < p_instance->cc_channel_count); + + nrf_timer_task_trigger(p_instance->p_reg, + nrf_timer_capture_task_get(cc_channel)); + return nrf_timer_cc_read(p_instance->p_reg, cc_channel); +} + +void nrfx_timer_compare(nrfx_timer_t const * const p_instance, + nrf_timer_cc_channel_t cc_channel, + uint32_t cc_value, + bool enable_int) +{ + nrf_timer_int_mask_t timer_int = nrf_timer_compare_int_get(cc_channel); + + if (enable_int) + { + nrf_timer_event_clear(p_instance->p_reg, nrf_timer_compare_event_get(cc_channel)); + nrf_timer_int_enable(p_instance->p_reg, timer_int); + } + else + { + nrf_timer_int_disable(p_instance->p_reg, timer_int); + } + + nrf_timer_cc_write(p_instance->p_reg, cc_channel, cc_value); + NRFX_LOG_INFO("Timer id: %d, capture value set: %lu, channel: %d.", + p_instance->instance_id, + cc_value, + cc_channel); +} + +void nrfx_timer_extended_compare(nrfx_timer_t const * const p_instance, + nrf_timer_cc_channel_t cc_channel, + uint32_t cc_value, + nrf_timer_short_mask_t timer_short_mask, + bool enable_int) +{ + nrf_timer_shorts_disable(p_instance->p_reg, + (TIMER_SHORTS_COMPARE0_STOP_Msk << cc_channel) | + (TIMER_SHORTS_COMPARE0_CLEAR_Msk << cc_channel)); + + nrf_timer_shorts_enable(p_instance->p_reg, timer_short_mask); + + nrfx_timer_compare(p_instance, + cc_channel, + cc_value, + enable_int); + NRFX_LOG_INFO("Timer id: %d, capture value set: %lu, channel: %d.", + p_instance->instance_id, + cc_value, + cc_channel); +} + +void nrfx_timer_compare_int_enable(nrfx_timer_t const * const p_instance, + uint32_t channel) +{ + NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED); + NRFX_ASSERT(channel < p_instance->cc_channel_count); + + nrf_timer_event_clear(p_instance->p_reg, + nrf_timer_compare_event_get(channel)); + nrf_timer_int_enable(p_instance->p_reg, + nrf_timer_compare_int_get(channel)); +} + +void nrfx_timer_compare_int_disable(nrfx_timer_t const * const p_instance, + uint32_t channel) +{ + NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED); + NRFX_ASSERT(channel < p_instance->cc_channel_count); + + nrf_timer_int_disable(p_instance->p_reg, + nrf_timer_compare_int_get(channel)); +} + +static void irq_handler(NRF_TIMER_Type * p_reg, + timer_control_block_t * p_cb, + uint8_t channel_count) +{ + uint8_t i; + for (i = 0; i < channel_count; ++i) + { + nrf_timer_event_t event = nrf_timer_compare_event_get(i); + nrf_timer_int_mask_t int_mask = nrf_timer_compare_int_get(i); + + if (nrf_timer_event_check(p_reg, event) && + nrf_timer_int_enable_check(p_reg, int_mask)) + { + nrf_timer_event_clear(p_reg, event); + NRFX_LOG_DEBUG("Compare event, channel: %d.", i); + p_cb->handler(event, p_cb->context); + } + } +} + +#if NRFX_CHECK(NRFX_TIMER0_ENABLED) +void nrfx_timer_0_irq_handler(void) +{ + irq_handler(NRF_TIMER0, &m_cb[NRFX_TIMER0_INST_IDX], + NRF_TIMER_CC_CHANNEL_COUNT(0)); +} +#endif + +#if NRFX_CHECK(NRFX_TIMER1_ENABLED) +void nrfx_timer_1_irq_handler(void) +{ + irq_handler(NRF_TIMER1, &m_cb[NRFX_TIMER1_INST_IDX], + NRF_TIMER_CC_CHANNEL_COUNT(1)); +} +#endif + +#if NRFX_CHECK(NRFX_TIMER2_ENABLED) +void nrfx_timer_2_irq_handler(void) +{ + irq_handler(NRF_TIMER2, &m_cb[NRFX_TIMER2_INST_IDX], + NRF_TIMER_CC_CHANNEL_COUNT(2)); +} +#endif + +#if NRFX_CHECK(NRFX_TIMER3_ENABLED) +void nrfx_timer_3_irq_handler(void) +{ + irq_handler(NRF_TIMER3, &m_cb[NRFX_TIMER3_INST_IDX], + NRF_TIMER_CC_CHANNEL_COUNT(3)); +} +#endif + +#if NRFX_CHECK(NRFX_TIMER4_ENABLED) +void nrfx_timer_4_irq_handler(void) +{ + irq_handler(NRF_TIMER4, &m_cb[NRFX_TIMER4_INST_IDX], + NRF_TIMER_CC_CHANNEL_COUNT(4)); +} +#endif + +#endif // NRFX_CHECK(NRFX_TIMER_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_twi.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_twi.c new file mode 100644 index 0000000..c7492bd --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_twi.c @@ -0,0 +1,723 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_TWI_ENABLED) + +#if !(NRFX_CHECK(NRFX_TWI0_ENABLED) || NRFX_CHECK(NRFX_TWI1_ENABLED)) +#error "No enabled TWI instances. Check <nrfx_config.h>." +#endif + +#include <nrfx_twi.h> +#include <hal/nrf_gpio.h> +#include "prs/nrfx_prs.h" + +#define NRFX_LOG_MODULE TWI +#include <nrfx_log.h> + +#define EVT_TO_STR(event) \ + (event == NRFX_TWI_EVT_DONE ? "EVT_DONE" : \ + (event == NRFX_TWI_EVT_ADDRESS_NACK ? "EVT_ADDRESS_NACK" : \ + (event == NRFX_TWI_EVT_DATA_NACK ? "EVT_DATA_NACK" : \ + "UNKNOWN ERROR"))) + +#define EVT_TO_STR_TWI(event) \ + (event == NRF_TWI_EVENT_STOPPED ? "NRF_TWI_EVENT_STOPPED" : \ + (event == NRF_TWI_EVENT_RXDREADY ? "NRF_TWI_EVENT_RXDREADY" : \ + (event == NRF_TWI_EVENT_TXDSENT ? "NRF_TWI_EVENT_TXDSENT" : \ + (event == NRF_TWI_EVENT_ERROR ? "NRF_TWI_EVENT_ERROR" : \ + (event == NRF_TWI_EVENT_BB ? "NRF_TWI_EVENT_BB" : \ + (event == NRF_TWI_EVENT_SUSPENDED ? "NRF_TWI_EVENT_SUSPENDED" : \ + "UNKNOWN ERROR")))))) + +#define TRANSFER_TO_STR(type) \ + (type == NRFX_TWI_XFER_TX ? "XFER_TX" : \ + (type == NRFX_TWI_XFER_RX ? "XFER_RX" : \ + (type == NRFX_TWI_XFER_TXRX ? "XFER_TXRX" : \ + (type == NRFX_TWI_XFER_TXTX ? "XFER_TXTX" : \ + "UNKNOWN TRANSFER TYPE")))) + +#define TWI_PIN_INIT(_pin) nrf_gpio_cfg((_pin), \ + NRF_GPIO_PIN_DIR_INPUT, \ + NRF_GPIO_PIN_INPUT_CONNECT, \ + NRF_GPIO_PIN_PULLUP, \ + NRF_GPIO_PIN_S0D1, \ + NRF_GPIO_PIN_NOSENSE) + +#define HW_TIMEOUT 10000 + +// Control block - driver instance local data. +typedef struct +{ + nrfx_twi_evt_handler_t handler; + void * p_context; + volatile uint32_t int_mask; + nrfx_twi_xfer_desc_t xfer_desc; + uint32_t flags; + uint8_t * p_curr_buf; + uint8_t curr_length; + bool curr_no_stop; + nrfx_drv_state_t state; + bool error; + volatile bool busy; + bool repeated; + uint8_t bytes_transferred; + bool hold_bus_uninit; +} twi_control_block_t; + +static twi_control_block_t m_cb[NRFX_TWI_ENABLED_COUNT]; + +static nrfx_err_t twi_process_error(uint32_t errorsrc) +{ + nrfx_err_t ret = NRFX_ERROR_INTERNAL; + + if (errorsrc & NRF_TWI_ERROR_OVERRUN) + { + ret = NRFX_ERROR_DRV_TWI_ERR_OVERRUN; + } + + if (errorsrc & NRF_TWI_ERROR_ADDRESS_NACK) + { + ret = NRFX_ERROR_DRV_TWI_ERR_ANACK; + } + + if (errorsrc & NRF_TWI_ERROR_DATA_NACK) + { + ret = NRFX_ERROR_DRV_TWI_ERR_DNACK; + } + + return ret; +} + + + +nrfx_err_t nrfx_twi_init(nrfx_twi_t const * p_instance, + nrfx_twi_config_t const * p_config, + nrfx_twi_evt_handler_t event_handler, + void * p_context) +{ + NRFX_ASSERT(p_config); + NRFX_ASSERT(p_config->scl != p_config->sda); + twi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + nrfx_err_t err_code; + + 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_TWI_ENABLED_COUNT] = { + #if NRFX_CHECK(NRFX_TWI0_ENABLED) + nrfx_twi_0_irq_handler, + #endif + #if NRFX_CHECK(NRFX_TWI1_ENABLED) + nrfx_twi_1_irq_handler, + #endif + }; + if (nrfx_prs_acquire(p_instance->p_twi, + 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) + + p_cb->handler = event_handler; + p_cb->p_context = p_context; + p_cb->int_mask = 0; + p_cb->repeated = false; + p_cb->busy = false; + p_cb->hold_bus_uninit = p_config->hold_bus_uninit; + + /* To secure correct signal levels on the pins used by the TWI + master when the system is in OFF mode, and when the TWI master is + disabled, these pins must be configured in the GPIO peripheral. + */ + TWI_PIN_INIT(p_config->scl); + TWI_PIN_INIT(p_config->sda); + + NRF_TWI_Type * p_twi = p_instance->p_twi; + nrf_twi_pins_set(p_twi, p_config->scl, p_config->sda); + nrf_twi_frequency_set(p_twi, + (nrf_twi_frequency_t)p_config->frequency); + + if (p_cb->handler) + { + NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_twi), + p_config->interrupt_priority); + NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_twi)); + } + + 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_twi_uninit(nrfx_twi_t const * p_instance) +{ + twi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED); + + if (p_cb->handler) + { + NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_twi)); + } + nrfx_twi_disable(p_instance); + +#if NRFX_CHECK(NRFX_PRS_ENABLED) + nrfx_prs_release(p_instance->p_twi); +#endif + + if (!p_cb->hold_bus_uninit) + { + nrf_gpio_cfg_default(p_instance->p_twi->PSELSCL); + nrf_gpio_cfg_default(p_instance->p_twi->PSELSDA); + } + + p_cb->state = NRFX_DRV_STATE_UNINITIALIZED; + NRFX_LOG_INFO("Instance uninitialized: %d.", p_instance->drv_inst_idx); +} + +void nrfx_twi_enable(nrfx_twi_t const * p_instance) +{ + twi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED); + + NRF_TWI_Type * p_twi = p_instance->p_twi; + nrf_twi_enable(p_twi); + + p_cb->state = NRFX_DRV_STATE_POWERED_ON; + NRFX_LOG_INFO("Instance enabled: %d.", p_instance->drv_inst_idx); +} + +void nrfx_twi_disable(nrfx_twi_t const * p_instance) +{ + twi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED); + + NRF_TWI_Type * p_twi = p_instance->p_twi; + nrf_twi_int_disable(p_twi, NRF_TWI_ALL_INTS_MASK); + nrf_twi_shorts_disable(p_twi, NRF_TWI_ALL_SHORTS_MASK); + nrf_twi_disable(p_twi); + + p_cb->state = NRFX_DRV_STATE_INITIALIZED; + NRFX_LOG_INFO("Instance disabled: %d.", p_instance->drv_inst_idx); +} + +static bool twi_send_byte(NRF_TWI_Type * p_twi, + uint8_t const * p_data, + uint8_t length, + uint8_t * p_bytes_transferred, + bool no_stop) +{ + if (*p_bytes_transferred < length) + { + nrf_twi_txd_set(p_twi, p_data[*p_bytes_transferred]); + ++(*p_bytes_transferred); + } + else + { + if (no_stop) + { + nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_SUSPEND); + return false; + } + else + { + nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STOP); + } + } + return true; +} + +static void twi_receive_byte(NRF_TWI_Type * p_twi, + uint8_t * p_data, + uint8_t length, + uint8_t * p_bytes_transferred) +{ + if (*p_bytes_transferred < length) + { + p_data[*p_bytes_transferred] = nrf_twi_rxd_get(p_twi); + + ++(*p_bytes_transferred); + + if (*p_bytes_transferred == length - 1) + { + nrf_twi_shorts_set(p_twi, NRF_TWI_SHORT_BB_STOP_MASK); + } + else if (*p_bytes_transferred == length) + { + return; + } + + nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_RESUME); + } +} + +static bool twi_transfer(NRF_TWI_Type * p_twi, + bool * p_error, + uint8_t * p_bytes_transferred, + uint8_t * p_data, + uint8_t length, + bool no_stop) +{ + bool do_stop_check = ((*p_error) || ((*p_bytes_transferred) == length)); + + if (*p_error) + { + nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR); + nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_TXDSENT); + nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_RXDREADY); + } + else if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_ERROR)) + { + nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR); + NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_ERROR)); + nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STOP); + *p_error = true; + } + else + { + if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_TXDSENT)) + { + nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_TXDSENT); + NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_TXDSENT)); + if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_ERROR)) + { + nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR); + NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_ERROR)); + nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STOP); + *p_error = true; + } + else + { + if (!twi_send_byte(p_twi, p_data, length, p_bytes_transferred, no_stop)) + { + return false; + } + } + } + else if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_RXDREADY)) + { + nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_RXDREADY); + NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_RXDREADY)); + if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_ERROR)) + { + NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_ERROR)); + nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR); + nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STOP); + *p_error = true; + } + else + { + twi_receive_byte(p_twi, p_data, length, p_bytes_transferred); + } + } + } + + if (do_stop_check && nrf_twi_event_check(p_twi, NRF_TWI_EVENT_STOPPED)) + { + nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_STOPPED); + NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_STOPPED)); + return false; + } + + return true; +} + +static nrfx_err_t twi_tx_start_transfer(twi_control_block_t * p_cb, + NRF_TWI_Type * p_twi, + uint8_t const * p_data, + uint8_t length, + bool no_stop) +{ + nrfx_err_t ret_code = NRFX_SUCCESS; + volatile int32_t hw_timeout; + + hw_timeout = HW_TIMEOUT; + + nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_STOPPED); + nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR); + nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_TXDSENT); + nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_RXDREADY); + nrf_twi_shorts_set(p_twi, 0); + + p_cb->bytes_transferred = 0; + p_cb->error = false; + + // In case TWI is suspended resume its operation. + nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_RESUME); + nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STARTTX); + + (void)twi_send_byte(p_twi, p_data, length, &p_cb->bytes_transferred, no_stop); + + if (p_cb->handler) + { + p_cb->int_mask = NRF_TWI_INT_STOPPED_MASK | + NRF_TWI_INT_ERROR_MASK | + NRF_TWI_INT_TXDSENT_MASK | + NRF_TWI_INT_RXDREADY_MASK; + nrf_twi_int_enable(p_twi, p_cb->int_mask); + } + else + { + while ((hw_timeout > 0) && + twi_transfer(p_twi, + &p_cb->error, + &p_cb->bytes_transferred, + (uint8_t *)p_data, + length, + no_stop)) + { + hw_timeout--; + } + + if (p_cb->error) + { + uint32_t errorsrc = nrf_twi_errorsrc_get_and_clear(p_twi); + + if (errorsrc) + { + ret_code = twi_process_error(errorsrc); + } + } + + if (hw_timeout <= 0) + { + nrf_twi_disable(p_twi); + nrf_twi_enable(p_twi); + ret_code = NRFX_ERROR_INTERNAL; + } + + } + return ret_code; +} + +static nrfx_err_t twi_rx_start_transfer(twi_control_block_t * p_cb, + NRF_TWI_Type * p_twi, + uint8_t const * p_data, + uint8_t length) +{ + nrfx_err_t ret_code = NRFX_SUCCESS; + volatile int32_t hw_timeout; + + hw_timeout = HW_TIMEOUT; + + nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_STOPPED); + nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR); + nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_TXDSENT); + nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_RXDREADY); + + p_cb->bytes_transferred = 0; + p_cb->error = false; + + if (length == 1) + { + nrf_twi_shorts_set(p_twi, NRF_TWI_SHORT_BB_STOP_MASK); + } + else + { + nrf_twi_shorts_set(p_twi, NRF_TWI_SHORT_BB_SUSPEND_MASK); + } + // In case TWI is suspended resume its operation. + nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_RESUME); + nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STARTRX); + + if (p_cb->handler) + { + p_cb->int_mask = NRF_TWI_INT_STOPPED_MASK | + NRF_TWI_INT_ERROR_MASK | + NRF_TWI_INT_TXDSENT_MASK | + NRF_TWI_INT_RXDREADY_MASK; + nrf_twi_int_enable(p_twi, p_cb->int_mask); + } + else + { + while ((hw_timeout > 0) && + twi_transfer(p_twi, + &p_cb->error, + &p_cb->bytes_transferred, + (uint8_t*)p_data, + length, + false)) + { + hw_timeout--; + } + + if (p_cb->error) + { + uint32_t errorsrc = nrf_twi_errorsrc_get_and_clear(p_twi); + + if (errorsrc) + { + ret_code = twi_process_error(errorsrc); + } + } + if (hw_timeout <= 0) + { + nrf_twi_disable(p_twi); + nrf_twi_enable(p_twi); + ret_code = NRFX_ERROR_INTERNAL; + } + } + return ret_code; +} + +__STATIC_INLINE nrfx_err_t twi_xfer(twi_control_block_t * p_cb, + NRF_TWI_Type * p_twi, + nrfx_twi_xfer_desc_t const * p_xfer_desc, + uint32_t flags) +{ + + nrfx_err_t err_code = NRFX_SUCCESS; + + /* Block TWI interrupts to ensure that function is not interrupted by TWI interrupt. */ + nrf_twi_int_disable(p_twi, NRF_TWI_ALL_INTS_MASK); + + if (p_cb->busy) + { + nrf_twi_int_enable(p_twi, p_cb->int_mask); + err_code = NRFX_ERROR_BUSY; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + else + { + p_cb->busy = (NRFX_TWI_FLAG_NO_XFER_EVT_HANDLER & flags) ? false : true; + } + + p_cb->flags = flags; + p_cb->xfer_desc = *p_xfer_desc; + p_cb->curr_length = p_xfer_desc->primary_length; + p_cb->p_curr_buf = p_xfer_desc->p_primary_buf; + nrf_twi_address_set(p_twi, p_xfer_desc->address); + + if (p_xfer_desc->type != NRFX_TWI_XFER_RX) + { + p_cb->curr_no_stop = ((p_xfer_desc->type == NRFX_TWI_XFER_TX) && + !(flags & NRFX_TWI_FLAG_TX_NO_STOP)) ? false : true; + + err_code = twi_tx_start_transfer(p_cb, + p_twi, + p_xfer_desc->p_primary_buf, + p_xfer_desc->primary_length, + p_cb->curr_no_stop); + } + else + { + p_cb->curr_no_stop = false; + + err_code = twi_rx_start_transfer(p_cb, + p_twi, + p_xfer_desc->p_primary_buf, + p_xfer_desc->primary_length); + } + if (p_cb->handler == NULL) + { + p_cb->busy = false; + } + return err_code; +} + +bool nrfx_twi_is_busy(nrfx_twi_t const * p_instance) +{ + twi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + return p_cb->busy; +} + +nrfx_err_t nrfx_twi_xfer(nrfx_twi_t const * p_instance, + nrfx_twi_xfer_desc_t const * p_xfer_desc, + uint32_t flags) +{ + + nrfx_err_t err_code = NRFX_SUCCESS; + twi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + + // TXRX and TXTX transfers are supported only in non-blocking mode. + NRFX_ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRFX_TWI_XFER_TXRX))); + NRFX_ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRFX_TWI_XFER_TXTX))); + + NRFX_LOG_INFO("Transfer type: %s.", TRANSFER_TO_STR(p_xfer_desc->type)); + NRFX_LOG_INFO("Transfer buffers length: primary: %d, secondary: %d.", + p_xfer_desc->primary_length, + p_xfer_desc->secondary_length); + NRFX_LOG_DEBUG("Primary buffer data:"); + NRFX_LOG_HEXDUMP_DEBUG(p_xfer_desc->p_primary_buf, + p_xfer_desc->primary_length * sizeof(p_xfer_desc->p_primary_buf[0])); + NRFX_LOG_DEBUG("Secondary buffer data:"); + NRFX_LOG_HEXDUMP_DEBUG(p_xfer_desc->p_secondary_buf, + p_xfer_desc->secondary_length * sizeof(p_xfer_desc->p_secondary_buf[0])); + + err_code = twi_xfer(p_cb, (NRF_TWI_Type *)p_instance->p_twi, p_xfer_desc, flags); + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + +nrfx_err_t nrfx_twi_tx(nrfx_twi_t const * p_instance, + uint8_t address, + uint8_t const * p_data, + size_t length, + bool no_stop) +{ + nrfx_twi_xfer_desc_t xfer = NRFX_TWI_XFER_DESC_TX(address, (uint8_t*)p_data, length); + + return nrfx_twi_xfer(p_instance, &xfer, no_stop ? NRFX_TWI_FLAG_TX_NO_STOP : 0); +} + +nrfx_err_t nrfx_twi_rx(nrfx_twi_t const * p_instance, + uint8_t address, + uint8_t * p_data, + size_t length) +{ + nrfx_twi_xfer_desc_t xfer = NRFX_TWI_XFER_DESC_RX(address, p_data, length); + return nrfx_twi_xfer(p_instance, &xfer, 0); +} + +size_t nrfx_twi_data_count_get(nrfx_twi_t const * const p_instance) +{ + return m_cb[p_instance->drv_inst_idx].bytes_transferred; +} + +uint32_t nrfx_twi_stopped_event_get(nrfx_twi_t const * p_instance) +{ + return (uint32_t)nrf_twi_event_address_get(p_instance->p_twi, NRF_TWI_EVENT_STOPPED); +} + +static void twi_irq_handler(NRF_TWI_Type * p_twi, twi_control_block_t * p_cb) +{ + NRFX_ASSERT(p_cb->handler); + + if (twi_transfer(p_twi, + &p_cb->error, + &p_cb->bytes_transferred, + p_cb->p_curr_buf, + p_cb->curr_length, + p_cb->curr_no_stop )) + { + return; + } + + if (!p_cb->error && + ((p_cb->xfer_desc.type == NRFX_TWI_XFER_TXRX) || + (p_cb->xfer_desc.type == NRFX_TWI_XFER_TXTX)) && + p_cb->p_curr_buf == p_cb->xfer_desc.p_primary_buf) + { + p_cb->p_curr_buf = p_cb->xfer_desc.p_secondary_buf; + p_cb->curr_length = p_cb->xfer_desc.secondary_length; + p_cb->curr_no_stop = (p_cb->flags & NRFX_TWI_FLAG_TX_NO_STOP); + + if (p_cb->xfer_desc.type == NRFX_TWI_XFER_TXTX) + { + (void)twi_tx_start_transfer(p_cb, + p_twi, + p_cb->p_curr_buf, + p_cb->curr_length, + p_cb->curr_no_stop); + } + else + { + (void)twi_rx_start_transfer(p_cb, p_twi, p_cb->p_curr_buf, p_cb->curr_length); + } + } + else + { + nrfx_twi_evt_t event; + event.xfer_desc = p_cb->xfer_desc; + + if (p_cb->error) + { + uint32_t errorsrc = nrf_twi_errorsrc_get_and_clear(p_twi); + if (errorsrc & NRF_TWI_ERROR_ADDRESS_NACK) + { + event.type = NRFX_TWI_EVT_ADDRESS_NACK; + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWI_EVT_ADDRESS_NACK)); + } + else if (errorsrc & NRF_TWI_ERROR_DATA_NACK) + { + event.type = NRFX_TWI_EVT_DATA_NACK; + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWI_EVT_DATA_NACK)); + } + } + else + { + event.type = NRFX_TWI_EVT_DONE; + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWI_EVT_DONE)); + } + + p_cb->busy = false; + + if (!(NRFX_TWI_FLAG_NO_XFER_EVT_HANDLER & p_cb->flags)) + { + p_cb->handler(&event, p_cb->p_context); + } + } + +} + +#if NRFX_CHECK(NRFX_TWI0_ENABLED) +void nrfx_twi_0_irq_handler(void) +{ + twi_irq_handler(NRF_TWI0, &m_cb[NRFX_TWI0_INST_IDX]); +} +#endif + +#if NRFX_CHECK(NRFX_TWI1_ENABLED) +void nrfx_twi_1_irq_handler(void) +{ + twi_irq_handler(NRF_TWI1, &m_cb[NRFX_TWI1_INST_IDX]); +} +#endif + +#endif // NRFX_CHECK(NRFX_TWI_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_twim.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_twim.c new file mode 100644 index 0000000..7d9cb36 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_twim.c @@ -0,0 +1,664 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_TWIM_ENABLED) + +#if !(NRFX_CHECK(NRFX_TWIM0_ENABLED) || NRFX_CHECK(NRFX_TWIM1_ENABLED)) +#error "No enabled TWIM instances. Check <nrfx_config.h>." +#endif + +#include <nrfx_twim.h> +#include <hal/nrf_gpio.h> +#include "prs/nrfx_prs.h" + +#define NRFX_LOG_MODULE TWIM +#include <nrfx_log.h> + +#define EVT_TO_STR(event) \ + (event == NRFX_TWIM_EVT_DONE ? "EVT_DONE" : \ + (event == NRFX_TWIM_EVT_ADDRESS_NACK ? "EVT_ADDRESS_NACK" : \ + (event == NRFX_TWIM_EVT_DATA_NACK ? "EVT_DATA_NACK" : \ + "UNKNOWN ERROR"))) + +#define EVT_TO_STR_TWIM(event) \ + (event == NRF_TWIM_EVENT_STOPPED ? "NRF_TWIM_EVENT_STOPPED" : \ + (event == NRF_TWIM_EVENT_ERROR ? "NRF_TWIM_EVENT_ERROR" : \ + (event == NRF_TWIM_EVENT_SUSPENDED ? "NRF_TWIM_EVENT_SUSPENDED" : \ + (event == NRF_TWIM_EVENT_RXSTARTED ? "NRF_TWIM_EVENT_RXSTARTED" : \ + (event == NRF_TWIM_EVENT_TXSTARTED ? "NRF_TWIM_EVENT_TXSTARTED" : \ + (event == NRF_TWIM_EVENT_LASTRX ? "NRF_TWIM_EVENT_LASTRX" : \ + (event == NRF_TWIM_EVENT_LASTTX ? "NRF_TWIM_EVENT_LASTTX" : \ + "UNKNOWN ERROR"))))))) + +#define TRANSFER_TO_STR(type) \ + (type == NRFX_TWIM_XFER_TX ? "XFER_TX" : \ + (type == NRFX_TWIM_XFER_RX ? "XFER_RX" : \ + (type == NRFX_TWIM_XFER_TXRX ? "XFER_TXRX" : \ + (type == NRFX_TWIM_XFER_TXTX ? "XFER_TXTX" : \ + "UNKNOWN TRANSFER TYPE")))) + +#define TWIM_PIN_INIT(_pin) nrf_gpio_cfg((_pin), \ + NRF_GPIO_PIN_DIR_INPUT, \ + NRF_GPIO_PIN_INPUT_CONNECT, \ + NRF_GPIO_PIN_PULLUP, \ + NRF_GPIO_PIN_S0D1, \ + NRF_GPIO_PIN_NOSENSE) + +#define TWIMX_LENGTH_VALIDATE(peripheral, drv_inst_idx, len1, len2) \ + (((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) && \ + NRFX_EASYDMA_LENGTH_VALIDATE(peripheral, len1, len2)) + +#if NRFX_CHECK(NRFX_TWIM0_ENABLED) +#define TWIM0_LENGTH_VALIDATE(...) TWIMX_LENGTH_VALIDATE(TWIM0, __VA_ARGS__) +#else +#define TWIM0_LENGTH_VALIDATE(...) 0 +#endif + +#if NRFX_CHECK(NRFX_TWIM1_ENABLED) +#define TWIM1_LENGTH_VALIDATE(...) TWIMX_LENGTH_VALIDATE(TWIM1, __VA_ARGS__) +#else +#define TWIM1_LENGTH_VALIDATE(...) 0 +#endif + +#define TWIM_LENGTH_VALIDATE(drv_inst_idx, len1, len2) \ + (TWIM0_LENGTH_VALIDATE(drv_inst_idx, len1, len2) || \ + TWIM1_LENGTH_VALIDATE(drv_inst_idx, len1, len2)) + +// Control block - driver instance local data. +typedef struct +{ + nrfx_twim_evt_handler_t handler; + void * p_context; + volatile uint32_t int_mask; + nrfx_twim_xfer_desc_t xfer_desc; + uint32_t flags; + uint8_t * p_curr_buf; + size_t curr_length; + bool curr_no_stop; + nrfx_drv_state_t state; + bool error; + volatile bool busy; + bool repeated; + uint8_t bytes_transferred; + bool hold_bus_uninit; +#if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED) + nrf_twim_frequency_t bus_frequency; +#endif +} twim_control_block_t; + +static twim_control_block_t m_cb[NRFX_TWIM_ENABLED_COUNT]; + +static nrfx_err_t twi_process_error(uint32_t errorsrc) +{ + nrfx_err_t ret = NRFX_ERROR_INTERNAL; + + if (errorsrc & NRF_TWIM_ERROR_ADDRESS_NACK) + { + ret = NRFX_ERROR_DRV_TWI_ERR_ANACK; + } + + if (errorsrc & NRF_TWIM_ERROR_DATA_NACK) + { + ret = NRFX_ERROR_DRV_TWI_ERR_DNACK; + } + + return ret; +} + +nrfx_err_t nrfx_twim_init(nrfx_twim_t const * p_instance, + nrfx_twim_config_t const * p_config, + nrfx_twim_evt_handler_t event_handler, + void * p_context) +{ + NRFX_ASSERT(p_config); + NRFX_ASSERT(p_config->scl != p_config->sda); + twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + nrfx_err_t err_code; + + 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_TWIM_ENABLED_COUNT] = { + #if NRFX_CHECK(NRFX_TWIM0_ENABLED) + nrfx_twim_0_irq_handler, + #endif + #if NRFX_CHECK(NRFX_TWIM1_ENABLED) + nrfx_twim_1_irq_handler, + #endif + }; + if (nrfx_prs_acquire(p_instance->p_twim, + 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) + + p_cb->handler = event_handler; + p_cb->p_context = p_context; + p_cb->int_mask = 0; + p_cb->repeated = false; + p_cb->busy = false; + p_cb->hold_bus_uninit = p_config->hold_bus_uninit; +#if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED) + p_cb->bus_frequency = (nrf_twim_frequency_t)p_config->frequency; +#endif + + /* To secure correct signal levels on the pins used by the TWI + master when the system is in OFF mode, and when the TWI master is + disabled, these pins must be configured in the GPIO peripheral. + */ + TWIM_PIN_INIT(p_config->scl); + TWIM_PIN_INIT(p_config->sda); + + NRF_TWIM_Type * p_twim = p_instance->p_twim; + nrf_twim_pins_set(p_twim, p_config->scl, p_config->sda); + nrf_twim_frequency_set(p_twim, + (nrf_twim_frequency_t)p_config->frequency); + + if (p_cb->handler) + { + NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_twim), + p_config->interrupt_priority); + NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_twim)); + } + + 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_twim_uninit(nrfx_twim_t const * p_instance) +{ + twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED); + + if (p_cb->handler) + { + NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_twim)); + } + nrfx_twim_disable(p_instance); + +#if NRFX_CHECK(NRFX_PRS_ENABLED) + nrfx_prs_release(p_instance->p_twim); +#endif + + if (!p_cb->hold_bus_uninit) + { + nrf_gpio_cfg_default(p_instance->p_twim->PSEL.SCL); + nrf_gpio_cfg_default(p_instance->p_twim->PSEL.SDA); + } + + p_cb->state = NRFX_DRV_STATE_UNINITIALIZED; + NRFX_LOG_INFO("Instance uninitialized: %d.", p_instance->drv_inst_idx); +} + +void nrfx_twim_enable(nrfx_twim_t const * p_instance) +{ + twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED); + + nrf_twim_enable(p_instance->p_twim); + + p_cb->state = NRFX_DRV_STATE_POWERED_ON; + NRFX_LOG_INFO("Instance enabled: %d.", p_instance->drv_inst_idx); +} + +void nrfx_twim_disable(nrfx_twim_t const * p_instance) +{ + twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED); + + NRF_TWIM_Type * p_twim = p_instance->p_twim; + p_cb->int_mask = 0; + nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK); + nrf_twim_shorts_disable(p_twim, NRF_TWIM_ALL_SHORTS_MASK); + nrf_twim_disable(p_twim); + + p_cb->state = NRFX_DRV_STATE_INITIALIZED; + NRFX_LOG_INFO("Instance disabled: %d.", p_instance->drv_inst_idx); +} + + +bool nrfx_twim_is_busy(nrfx_twim_t const * p_instance) +{ + twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + return p_cb->busy; +} + + +__STATIC_INLINE void twim_list_enable_handle(NRF_TWIM_Type * p_twim, uint32_t flags) +{ + if (NRFX_TWIM_FLAG_TX_POSTINC & flags) + { + nrf_twim_tx_list_enable(p_twim); + } + else + { + nrf_twim_tx_list_disable(p_twim); + } + + if (NRFX_TWIM_FLAG_RX_POSTINC & flags) + { + nrf_twim_rx_list_enable(p_twim); + } + else + { + nrf_twim_rx_list_disable(p_twim); + } +} +__STATIC_INLINE nrfx_err_t twim_xfer(twim_control_block_t * p_cb, + NRF_TWIM_Type * p_twim, + nrfx_twim_xfer_desc_t const * p_xfer_desc, + uint32_t flags) +{ + nrfx_err_t err_code = NRFX_SUCCESS; + nrf_twim_task_t start_task = NRF_TWIM_TASK_STARTTX; + nrf_twim_event_t evt_to_wait = NRF_TWIM_EVENT_STOPPED; + + if (!nrfx_is_in_ram(p_xfer_desc->p_primary_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; + } + /* Block TWI interrupts to ensure that function is not interrupted by TWI interrupt. */ + nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK); + if (p_cb->busy) + { + nrf_twim_int_enable(p_twim, p_cb->int_mask); + err_code = NRFX_ERROR_BUSY; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + else + { + p_cb->busy = ((NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER & flags) || + (NRFX_TWIM_FLAG_REPEATED_XFER & flags)) ? false: true; + } + + p_cb->xfer_desc = *p_xfer_desc; + p_cb->repeated = (flags & NRFX_TWIM_FLAG_REPEATED_XFER) ? true : false; + nrf_twim_address_set(p_twim, p_xfer_desc->address); + + nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_STOPPED); + nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR); + + twim_list_enable_handle(p_twim, flags); + switch (p_xfer_desc->type) + { + case NRFX_TWIM_XFER_TXTX: + NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_REPEATED_XFER)); + NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_HOLD_XFER)); + NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER)); + if (!nrfx_is_in_ram(p_xfer_desc->p_secondary_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; + } + nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_SUSPEND_MASK); + nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length); + nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED); + nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTTX); + nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED); + nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME); + nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STARTTX); + while (!nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_TXSTARTED)) + {} + NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_TXSTARTED)); + nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED); + nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_secondary_buf, p_xfer_desc->secondary_length); + p_cb->int_mask = NRF_TWIM_INT_SUSPENDED_MASK | NRF_TWIM_INT_ERROR_MASK; + break; + case NRFX_TWIM_XFER_TXRX: + nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length); + if (!nrfx_is_in_ram(p_xfer_desc->p_secondary_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; + } + nrf_twim_rx_buffer_set(p_twim, p_xfer_desc->p_secondary_buf, p_xfer_desc->secondary_length); + nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STARTRX_MASK | + NRF_TWIM_SHORT_LASTRX_STOP_MASK); + p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK; + break; + case NRFX_TWIM_XFER_TX: + nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length); + if (NRFX_TWIM_FLAG_TX_NO_STOP & flags) + { + nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_SUSPEND_MASK); + p_cb->int_mask = NRF_TWIM_INT_SUSPENDED_MASK | NRF_TWIM_INT_ERROR_MASK; + nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED); + evt_to_wait = NRF_TWIM_EVENT_SUSPENDED; + } + else + { + nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STOP_MASK); + p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK; + } + nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME); + break; + case NRFX_TWIM_XFER_RX: + nrf_twim_rx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length); + nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTRX_STOP_MASK); + p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK; + start_task = NRF_TWIM_TASK_STARTRX; + nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME); + break; + default: + err_code = NRFX_ERROR_INVALID_PARAM; + break; + } + + if (!(flags & NRFX_TWIM_FLAG_HOLD_XFER) && (p_xfer_desc->type != NRFX_TWIM_XFER_TXTX)) + { + nrf_twim_task_trigger(p_twim, start_task); + } + + if (p_cb->handler) + { + if (flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER) + { + p_cb->int_mask = NRF_TWIM_INT_ERROR_MASK; + } + nrf_twim_int_enable(p_twim, p_cb->int_mask); + +#if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED) + if ((flags & NRFX_TWIM_FLAG_HOLD_XFER) && ((p_xfer_desc->type == NRFX_TWIM_XFER_TX) || + (p_xfer_desc->type == NRFX_TWIM_XFER_TXRX))) + { + p_cb->flags = flags; + twim_list_enable_handle(p_twim, 0); + p_twim->FREQUENCY = 0; + nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED); + nrf_twim_int_enable(p_twim, NRF_TWIM_INT_TXSTARTED_MASK); + } +#endif + } + else + { + while (!nrf_twim_event_check(p_twim, evt_to_wait)) + { + if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_ERROR)) + { + NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_ERROR)); + nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR); + nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME); + nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STOP); + evt_to_wait = NRF_TWIM_EVENT_STOPPED; + } + } + + uint32_t errorsrc = nrf_twim_errorsrc_get_and_clear(p_twim); + + p_cb->busy = false; + + if (errorsrc) + { + err_code = twi_process_error(errorsrc); + } + } + return err_code; +} + + +nrfx_err_t nrfx_twim_xfer(nrfx_twim_t const * p_instance, + nrfx_twim_xfer_desc_t const * p_xfer_desc, + uint32_t flags) +{ + NRFX_ASSERT(TWIM_LENGTH_VALIDATE(p_instance->drv_inst_idx, + p_xfer_desc->primary_length, + p_xfer_desc->secondary_length)); + + nrfx_err_t err_code = NRFX_SUCCESS; + twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + + // TXRX and TXTX transfers are supported only in non-blocking mode. + NRFX_ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRFX_TWIM_XFER_TXRX))); + NRFX_ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRFX_TWIM_XFER_TXTX))); + + NRFX_LOG_INFO("Transfer type: %s.", TRANSFER_TO_STR(p_xfer_desc->type)); + NRFX_LOG_INFO("Transfer buffers length: primary: %d, secondary: %d.", + p_xfer_desc->primary_length, + p_xfer_desc->secondary_length); + NRFX_LOG_DEBUG("Primary buffer data:"); + NRFX_LOG_HEXDUMP_DEBUG(p_xfer_desc->p_primary_buf, + p_xfer_desc->primary_length * sizeof(p_xfer_desc->p_primary_buf[0])); + NRFX_LOG_DEBUG("Secondary buffer data:"); + NRFX_LOG_HEXDUMP_DEBUG(p_xfer_desc->p_secondary_buf, + p_xfer_desc->secondary_length * sizeof(p_xfer_desc->p_secondary_buf[0])); + + err_code = twim_xfer(p_cb, (NRF_TWIM_Type *)p_instance->p_twim, p_xfer_desc, flags); + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + +nrfx_err_t nrfx_twim_tx(nrfx_twim_t const * p_instance, + uint8_t address, + uint8_t const * p_data, + size_t length, + bool no_stop) +{ + nrfx_twim_xfer_desc_t xfer = NRFX_TWIM_XFER_DESC_TX(address, (uint8_t*)p_data, length); + + return nrfx_twim_xfer(p_instance, &xfer, no_stop ? NRFX_TWIM_FLAG_TX_NO_STOP : 0); +} + +nrfx_err_t nrfx_twim_rx(nrfx_twim_t const * p_instance, + uint8_t address, + uint8_t * p_data, + size_t length) +{ + nrfx_twim_xfer_desc_t xfer = NRFX_TWIM_XFER_DESC_RX(address, p_data, length); + return nrfx_twim_xfer(p_instance, &xfer, 0); +} + +uint32_t nrfx_twim_start_task_get(nrfx_twim_t const * p_instance, + nrfx_twim_xfer_type_t xfer_type) +{ + return (uint32_t)nrf_twim_task_address_get(p_instance->p_twim, + (xfer_type != NRFX_TWIM_XFER_RX) ? NRF_TWIM_TASK_STARTTX : NRF_TWIM_TASK_STARTRX); +} + +uint32_t nrfx_twim_stopped_event_get(nrfx_twim_t const * p_instance) +{ + return (uint32_t)nrf_twim_event_address_get(p_instance->p_twim, NRF_TWIM_EVENT_STOPPED); +} + +static void twim_irq_handler(NRF_TWIM_Type * p_twim, twim_control_block_t * p_cb) +{ + +#if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED) + /* Handle only workaround case. Can be used without TWIM handler in IRQs. */ + if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_TXSTARTED)) + { + nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED); + nrf_twim_int_disable(p_twim, NRF_TWIM_INT_TXSTARTED_MASK); + if (p_twim->FREQUENCY == 0) + { + // Set enable to zero to reset TWIM internal state. + nrf_twim_disable(p_twim); + nrf_twim_enable(p_twim); + + // Set proper frequency. + nrf_twim_frequency_set(p_twim, p_cb->bus_frequency); + twim_list_enable_handle(p_twim, p_cb->flags); + + // Start proper transmission. + nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STARTTX); + return; + } + } +#endif + + NRFX_ASSERT(p_cb->handler); + + if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_ERROR)) + { + nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR); + NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_ERROR)); + if (!nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_STOPPED)) + { + nrf_twim_int_disable(p_twim, p_cb->int_mask); + p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK; + nrf_twim_int_enable(p_twim, p_cb->int_mask); + + nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME); + nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STOP); + return; + } + } + + nrfx_twim_evt_t event; + + if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_STOPPED)) + { + NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_STOPPED)); + nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_STOPPED); + event.xfer_desc = p_cb->xfer_desc; + if (p_cb->error) + { + + event.xfer_desc.primary_length = (p_cb->xfer_desc.type == NRFX_TWIM_XFER_RX) ? + nrf_twim_rxd_amount_get(p_twim) : nrf_twim_txd_amount_get(p_twim); + event.xfer_desc.secondary_length = (p_cb->xfer_desc.type == NRFX_TWIM_XFER_TXRX) ? + nrf_twim_rxd_amount_get(p_twim) : nrf_twim_txd_amount_get(p_twim); + + } + nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTTX); + nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTRX); + if (!p_cb->repeated || p_cb->error) + { + nrf_twim_shorts_set(p_twim, 0); + p_cb->int_mask = 0; + nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK); + } + } + else + { + nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED); + NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_SUSPENDED)); + if (p_cb->xfer_desc.type == NRFX_TWIM_XFER_TX) + { + event.xfer_desc = p_cb->xfer_desc; + if (!p_cb->repeated) + { + nrf_twim_shorts_set(p_twim, 0); + p_cb->int_mask = 0; + nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK); + } + } + else + { + nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STOP_MASK); + p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK; + nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK); + nrf_twim_int_enable(p_twim, p_cb->int_mask); + nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STARTTX); + nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME); + return; + } + } + + uint32_t errorsrc = nrf_twim_errorsrc_get_and_clear(p_twim); + if (errorsrc & NRF_TWIM_ERROR_ADDRESS_NACK) + { + event.type = NRFX_TWIM_EVT_ADDRESS_NACK; + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_ADDRESS_NACK)); + } + else if (errorsrc & NRF_TWIM_ERROR_DATA_NACK) + { + event.type = NRFX_TWIM_EVT_DATA_NACK; + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_DATA_NACK)); + } + else + { + event.type = NRFX_TWIM_EVT_DONE; + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_DONE)); + } + + if (!p_cb->repeated) + { + p_cb->busy = false; + } + p_cb->handler(&event, p_cb->p_context); +} + +#if NRFX_CHECK(NRFX_TWIM0_ENABLED) +void nrfx_twim_0_irq_handler(void) +{ + twim_irq_handler(NRF_TWIM0, &m_cb[NRFX_TWIM0_INST_IDX]); +} +#endif + +#if NRFX_CHECK(NRFX_TWIM1_ENABLED) +void nrfx_twim_1_irq_handler(void) +{ + twim_irq_handler(NRF_TWIM1, &m_cb[NRFX_TWIM1_INST_IDX]); +} +#endif + +#endif // NRFX_CHECK(NRFX_TWIM_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_twis.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_twis.c new file mode 100644 index 0000000..9fb7a49 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_twis.c @@ -0,0 +1,834 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_TWIS_ENABLED) + +#if !(NRFX_CHECK(NRFX_TWIS0_ENABLED) || NRFX_CHECK(NRFX_TWIS1_ENABLED)) +#error "No enabled TWIS instances. Check <nrfx_config.h>." +#endif + +#include <nrfx_twis.h> +#include "prs/nrfx_prs.h" + +#define NRFX_LOG_MODULE TWIS +#include <nrfx_log.h> + +#define EVT_TO_STR(event) \ + (event == NRF_TWIS_EVENT_STOPPED ? "NRF_TWIS_EVENT_STOPPED" : \ + (event == NRF_TWIS_EVENT_ERROR ? "NRF_TWIS_EVENT_ERROR" : \ + (event == NRF_TWIS_EVENT_RXSTARTED ? "NRF_TWIS_EVENT_RXSTARTED" : \ + (event == NRF_TWIS_EVENT_TXSTARTED ? "NRF_TWIS_EVENT_TXSTARTED" : \ + (event == NRF_TWIS_EVENT_WRITE ? "NRF_TWIS_EVENT_WRITE" : \ + (event == NRF_TWIS_EVENT_READ ? "NRF_TWIS_EVENT_READ" : \ + "UNKNOWN EVENT")))))) + + +/** + * @brief Actual state of internal state machine + * + * Current substate of powered on state. + */ +typedef enum +{ + NRFX_TWIS_SUBSTATE_IDLE, ///< No ongoing transmission + NRFX_TWIS_SUBSTATE_READ_WAITING, ///< Read request received, waiting for data + NRFX_TWIS_SUBSTATE_READ_PENDING, ///< Reading is actually pending (data sending) + NRFX_TWIS_SUBSTATE_WRITE_WAITING, ///< Write request received, waiting for data buffer + NRFX_TWIS_SUBSTATE_WRITE_PENDING, ///< Writing is actually pending (data receiving) +} nrfx_twis_substate_t; + +// Control block - driver instance local data. +typedef struct +{ + nrfx_twis_event_handler_t ev_handler; + // Internal copy of hardware errors flags merged with specific internal + // driver errors flags. + // This value can be changed in the interrupt and cleared in the main program. + // Always use Atomic load-store when updating this value in main loop. + volatile uint32_t error; + nrfx_drv_state_t state; + volatile nrfx_twis_substate_t substate; + + volatile bool semaphore; +} twis_control_block_t; +static twis_control_block_t m_cb[NRFX_TWIS_ENABLED_COUNT]; + +/** + * @brief Used interrupts mask + * + * Mask for all interrupts used by this library + */ +static const uint32_t m_used_ints_mask = NRF_TWIS_INT_STOPPED_MASK | + NRF_TWIS_INT_ERROR_MASK | + NRF_TWIS_INT_RXSTARTED_MASK | + NRF_TWIS_INT_TXSTARTED_MASK | + NRF_TWIS_INT_WRITE_MASK | + NRF_TWIS_INT_READ_MASK; + +/** + * @brief Clear all events + * + * Function clears all actually pending events + */ +static void nrfx_twis_clear_all_events(NRF_TWIS_Type * const p_reg) +{ + /* Clear all events */ + nrf_twis_event_clear(p_reg, NRF_TWIS_EVENT_STOPPED); + nrf_twis_event_clear(p_reg, NRF_TWIS_EVENT_ERROR); + nrf_twis_event_clear(p_reg, NRF_TWIS_EVENT_RXSTARTED); + nrf_twis_event_clear(p_reg, NRF_TWIS_EVENT_TXSTARTED); + nrf_twis_event_clear(p_reg, NRF_TWIS_EVENT_WRITE); + nrf_twis_event_clear(p_reg, NRF_TWIS_EVENT_READ); +} + +/** + * @brief Reset all the registers to known state + * + * This function clears all registers that requires it to known state. + * TWIS is left disabled after this function. + * All events are cleared. + * @param[out] p_reg TWIS to reset register address + */ +static inline void nrfx_twis_swreset(NRF_TWIS_Type * p_reg) +{ + /* Disable TWIS */ + nrf_twis_disable(p_reg); + + /* Disconnect pins */ + nrf_twis_pins_set(p_reg, ~0U, ~0U); + + /* Disable interrupt global for the instance */ + NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_reg)); + + /* Disable interrupts */ + nrf_twis_int_disable(p_reg, ~0U); +} + +/** + * @brief Configure pin + * + * Function configures selected for work as SDA or SCL. + * @param pin Pin number to configure + */ +static inline void nrfx_twis_config_pin(uint32_t pin, nrf_gpio_pin_pull_t pull) +{ + nrf_gpio_cfg(pin, + NRF_GPIO_PIN_DIR_INPUT, + NRF_GPIO_PIN_INPUT_DISCONNECT, + pull, + NRF_GPIO_PIN_S0D1, + NRF_GPIO_PIN_NOSENSE); +} + +/** + * @brief Auxiliary function for getting event state on right bit possition + * + * This function calls @ref nrf_twis_event_get function but the the result + * is shifted to match INTEN register scheme. + * + * @param[in,out] p_reg TWIS to read event from + * @param ev Event code + * + * @return Selected event state shifted by @ref nrfx_event_to_bitpos + * + * @sa nrf_twis_event_get + * @sa nrfx_event_to_bitpos + */ +static inline uint32_t nrfx_twis_event_bit_get(NRF_TWIS_Type * p_reg, + nrf_twis_event_t ev) +{ + return (uint32_t)nrf_twis_event_get_and_clear(p_reg, ev) << nrfx_event_to_bitpos(ev); +} + +/** + * @brief Auxiliary function for checking event bit inside given flags value + * + * Function used here to check presence of the event inside given flags value. + * It transforms given event to bit possition and then checks if in given variable it is cleared. + * + * @param flags Flags to test + * @param ev Event code + * + * @retval true Flag for selected event is set + * @retval false Flag for selected event is cleared + */ +static inline bool nrfx_twis_check_bit(uint32_t flags, + nrf_twis_event_t ev) +{ + return 0 != (flags & (1U << nrfx_event_to_bitpos(ev))); +} + +/** + * @brief Auxiliary function for clearing event bit in given flags value + * + * Function used to clear selected event bit. + * + * @param flags Flags to process + * @param ev Event code to clear + * + * @return Value @em flags with cleared event bit that matches given @em ev + */ +static inline uint32_t nrfx_twis_clear_bit(uint32_t flags, + nrf_twis_event_t ev) +{ + return flags & ~(1U << nrfx_event_to_bitpos(ev)); +} + +static void call_event_handler(twis_control_block_t const * p_cb, + nrfx_twis_evt_t const * p_evt) +{ + nrfx_twis_event_handler_t handler = p_cb->ev_handler; + if (handler != NULL) + { + handler(p_evt); + } +} + +/** + * @brief Auxiliary function for error processing + * + * Function called when in current substate the event apears and it cannot be processed. + * It should be called also on ERROR event. + * If given @em error parameter has zero value the @ref NRFX_TWIS_ERROR_UNEXPECTED_EVENT + * would be set. + * + * @param p_cb Pointer to the driver instance control block. + * @param evt What error event raport to event handler + * @param error Error flags + */ +static inline void nrfx_twis_process_error(twis_control_block_t * p_cb, + nrfx_twis_evt_type_t evt, + uint32_t error) +{ + if (0 == error) + { + error = NRFX_TWIS_ERROR_UNEXPECTED_EVENT; + } + nrfx_twis_evt_t evdata; + evdata.type = evt; + evdata.data.error = error; + + p_cb->error |= error; + + call_event_handler(p_cb, &evdata); +} + +static void nrfx_twis_state_machine(NRF_TWIS_Type * p_reg, + twis_control_block_t * p_cb) +{ + if (!NRFX_TWIS_NO_SYNC_MODE) + { + /* Exclude parallel processing of this function */ + if (p_cb->semaphore) + { + return; + } + p_cb->semaphore = 1; + } + + /* Event data structure to be passed into event handler */ + nrfx_twis_evt_t evdata; + /* Current substate copy */ + nrfx_twis_substate_t substate = p_cb->substate; + /* Event flags */ + uint32_t ev = 0; + + /* Get all events */ + ev |= nrfx_twis_event_bit_get(p_reg, NRF_TWIS_EVENT_STOPPED); + ev |= nrfx_twis_event_bit_get(p_reg, NRF_TWIS_EVENT_ERROR); + ev |= nrfx_twis_event_bit_get(p_reg, NRF_TWIS_EVENT_RXSTARTED); + ev |= nrfx_twis_event_bit_get(p_reg, NRF_TWIS_EVENT_TXSTARTED); + ev |= nrfx_twis_event_bit_get(p_reg, NRF_TWIS_EVENT_WRITE); + ev |= nrfx_twis_event_bit_get(p_reg, NRF_TWIS_EVENT_READ); + + /* State machine */ + while (0 != ev) + { + switch (substate) + { + case NRFX_TWIS_SUBSTATE_IDLE: + if (nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_STOPPED)) + { + /* Stopped event is always allowed in IDLE state - just ignore */ + ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_STOPPED); + } + else if (nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_READ)) + { + evdata.type = NRFX_TWIS_EVT_READ_REQ; + if (nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_TXSTARTED)) + { + substate = NRFX_TWIS_SUBSTATE_READ_PENDING; + evdata.data.buf_req = false; + } + else + { + substate = NRFX_TWIS_SUBSTATE_READ_WAITING; + evdata.data.buf_req = true; + } + call_event_handler(p_cb, &evdata); + ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_READ); + ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_TXSTARTED); + ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_WRITE); + ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_RXSTARTED); + } + else if (nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_WRITE)) + { + evdata.type = NRFX_TWIS_EVT_WRITE_REQ; + if (nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_RXSTARTED)) + { + substate = NRFX_TWIS_SUBSTATE_WRITE_PENDING; + evdata.data.buf_req = false; + } + else + { + substate = NRFX_TWIS_SUBSTATE_WRITE_WAITING; + evdata.data.buf_req = true; + } + call_event_handler(p_cb, &evdata); + ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_READ); + ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_TXSTARTED); + ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_WRITE); + ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_RXSTARTED); + } + else + { + nrfx_twis_process_error(p_cb, + NRFX_TWIS_EVT_GENERAL_ERROR, + nrf_twis_error_source_get_and_clear(p_reg)); + ev = 0; + } + break; + case NRFX_TWIS_SUBSTATE_READ_WAITING: + if (nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_TXSTARTED) || + nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_WRITE) || + nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_READ) || + nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_STOPPED)) + { + substate = NRFX_TWIS_SUBSTATE_READ_PENDING; + /* Any other bits requires further processing in PENDING substate */ + ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_TXSTARTED); + } + else + { + nrfx_twis_process_error(p_cb, + NRFX_TWIS_EVT_READ_ERROR, + nrf_twis_error_source_get_and_clear(p_reg)); + substate = NRFX_TWIS_SUBSTATE_IDLE; + ev = 0; + } + break; + case NRFX_TWIS_SUBSTATE_READ_PENDING: + if (nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_WRITE) || + nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_READ) || + nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_STOPPED)) + { + evdata.type = NRFX_TWIS_EVT_READ_DONE; + evdata.data.tx_amount = nrf_twis_tx_amount_get(p_reg); + NRFX_LOG_INFO("Transfer tx_len:%d", evdata.data.tx_amount); + NRFX_LOG_DEBUG("Tx data:"); + NRFX_LOG_HEXDUMP_DEBUG((uint8_t const *)p_reg->TXD.PTR, + evdata.data.tx_amount * sizeof(uint8_t)); + call_event_handler(p_cb, &evdata); + /* Go to idle and repeat the state machine if READ or WRITE events detected. + * This time READ or WRITE would be started */ + substate = NRFX_TWIS_SUBSTATE_IDLE; + ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_STOPPED); + } + else + { + nrfx_twis_process_error(p_cb, + NRFX_TWIS_EVT_READ_ERROR, + nrf_twis_error_source_get_and_clear(p_reg)); + substate = NRFX_TWIS_SUBSTATE_IDLE; + ev = 0; + } + break; + case NRFX_TWIS_SUBSTATE_WRITE_WAITING: + if (nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_RXSTARTED) || + nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_WRITE) || + nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_READ) || + nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_STOPPED)) + { + substate = NRFX_TWIS_SUBSTATE_WRITE_PENDING; + /* Any other bits requires further processing in PENDING substate */ + ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_RXSTARTED); + } + else + { + nrfx_twis_process_error(p_cb, + NRFX_TWIS_EVT_WRITE_ERROR, + nrf_twis_error_source_get_and_clear(p_reg)); + substate = NRFX_TWIS_SUBSTATE_IDLE; + ev = 0; + } + break; + case NRFX_TWIS_SUBSTATE_WRITE_PENDING: + if (nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_WRITE) || + nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_READ) || + nrfx_twis_check_bit(ev, NRF_TWIS_EVENT_STOPPED)) + { + evdata.type = NRFX_TWIS_EVT_WRITE_DONE; + evdata.data.rx_amount = nrf_twis_rx_amount_get(p_reg); + call_event_handler(p_cb, &evdata); + /* Go to idle and repeat the state machine if READ or WRITE events detected. + * This time READ or WRITE would be started */ + substate = NRFX_TWIS_SUBSTATE_IDLE; + ev = nrfx_twis_clear_bit(ev, NRF_TWIS_EVENT_STOPPED); + } + else + { + nrfx_twis_process_error(p_cb, + NRFX_TWIS_EVT_WRITE_ERROR, + nrf_twis_error_source_get_and_clear(p_reg)); + substate = NRFX_TWIS_SUBSTATE_IDLE; + ev = 0; + } + break; + default: + substate = NRFX_TWIS_SUBSTATE_IDLE; + /* Do not clear any events and repeat the machine */ + break; + } + } + + p_cb->substate = substate; + if (!NRFX_TWIS_NO_SYNC_MODE) + { + p_cb->semaphore = 0; + } +} + + +static inline void nrfx_twis_preprocess_status(nrfx_twis_t const * p_instance) +{ + if (!NRFX_TWIS_NO_SYNC_MODE) + { + NRF_TWIS_Type * p_reg = p_instance->p_reg; + twis_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + if (NULL == p_cb->ev_handler) + { + nrfx_twis_state_machine(p_reg, p_cb); + } + } +} + + +/* ------------------------------------------------------------------------- + * Implementation of interface functions + * + */ + + +nrfx_err_t nrfx_twis_init(nrfx_twis_t const * p_instance, + nrfx_twis_config_t const * p_config, + nrfx_twis_event_handler_t event_handler) +{ + NRFX_ASSERT(p_config); + NRFX_ASSERT(p_config->scl != p_config->sda); + nrfx_err_t err_code; + + NRF_TWIS_Type * p_reg = p_instance->p_reg; + twis_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + + if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED) + { + err_code = NRFX_ERROR_INVALID_STATE; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + +#if NRFX_CHECK(NRFX_PRS_ENABLED) + static nrfx_irq_handler_t const irq_handlers[NRFX_TWIS_ENABLED_COUNT] = { + #if NRFX_CHECK(NRFX_TWIS0_ENABLED) + nrfx_twis_0_irq_handler, + #endif + #if NRFX_CHECK(NRFX_TWIS1_ENABLED) + nrfx_twis_1_irq_handler, + #endif + }; + if (nrfx_prs_acquire(p_reg, + irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS) + { + err_code = NRFX_ERROR_BUSY; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } +#endif // NRFX_CHECK(NRFX_PRS_ENABLED) + + if (!NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY) + { + nrfx_twis_swreset(p_reg); + } + + nrfx_twis_config_pin(p_config->scl, p_config->scl_pull); + nrfx_twis_config_pin(p_config->sda, p_config->sda_pull); + + nrf_twis_config_addr_mask_t addr_mask = (nrf_twis_config_addr_mask_t)0; + if (0 == (p_config->addr[0] | p_config->addr[1])) + { + addr_mask = NRF_TWIS_CONFIG_ADDRESS0_MASK; + } + else + { + if (0 != p_config->addr[0]) + { + addr_mask |= NRF_TWIS_CONFIG_ADDRESS0_MASK; + } + if (0 != p_config->addr[1]) + { + addr_mask |= NRF_TWIS_CONFIG_ADDRESS1_MASK; + } + } + + /* Peripheral interrupt configure + * (note - interrupts still needs to be configured in INTEN register. + * This is done in enable function) */ + NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_reg), + p_config->interrupt_priority); + NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_reg)); + + /* Configure */ + nrf_twis_pins_set (p_reg, p_config->scl, p_config->sda); + nrf_twis_address_set (p_reg, 0, p_config->addr[0]); + nrf_twis_address_set (p_reg, 1, p_config->addr[1]); + nrf_twis_config_address_set(p_reg, addr_mask); + + /* Clear semaphore */ + if (!NRFX_TWIS_NO_SYNC_MODE) + { + p_cb->semaphore = 0; + } + /* Set internal instance variables */ + p_cb->substate = NRFX_TWIS_SUBSTATE_IDLE; + p_cb->ev_handler = event_handler; + p_cb->state = NRFX_DRV_STATE_INITIALIZED; + err_code = NRFX_SUCCESS; + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + + +void nrfx_twis_uninit(nrfx_twis_t const * p_instance) +{ + NRF_TWIS_Type * p_reg = p_instance->p_reg; + twis_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED); + + TWIS_PSEL_Type psel = p_reg->PSEL; + + nrfx_twis_swreset(p_reg); + + /* Clear pins state if */ + if (!(TWIS_PSEL_SCL_CONNECT_Msk & psel.SCL)) + { + nrf_gpio_cfg_default(psel.SCL); + } + if (!(TWIS_PSEL_SDA_CONNECT_Msk & psel.SDA)) + { + nrf_gpio_cfg_default(psel.SDA); + } + +#if NRFX_CHECK(NRFX_PRS_ENABLED) + nrfx_prs_release(p_reg); +#endif + + /* Clear variables */ + p_cb->ev_handler = NULL; + p_cb->state = NRFX_DRV_STATE_UNINITIALIZED; +} + + +void nrfx_twis_enable(nrfx_twis_t const * p_instance) +{ + NRF_TWIS_Type * p_reg = p_instance->p_reg; + twis_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED); + + nrfx_twis_clear_all_events(p_reg); + + /* Enable interrupts */ + if (NULL != p_cb->ev_handler) + { + nrf_twis_int_enable(p_reg, m_used_ints_mask); + } + + nrf_twis_enable(p_reg); + p_cb->error = 0; + p_cb->state = NRFX_DRV_STATE_POWERED_ON; + p_cb->substate = NRFX_TWIS_SUBSTATE_IDLE; +} + + +void nrfx_twis_disable(nrfx_twis_t const * p_instance) +{ + NRF_TWIS_Type * p_reg = p_instance->p_reg; + twis_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED); + + nrf_twis_int_disable(p_reg, m_used_ints_mask); + + nrf_twis_disable(p_reg); + p_cb->state = NRFX_DRV_STATE_INITIALIZED; +} + +/* ARM recommends not using the LDREX and STREX instructions in C code. + * This is because the compiler might generate loads and stores between + * LDREX and STREX, potentially clearing the exclusive monitor set by LDREX. + * This recommendation also applies to the byte, halfword, and doubleword + * variants LDREXB, STREXB, LDREXH, STREXH, LDREXD, and STREXD. + * + * This is the reason for the function below to be implemented in assembly. + */ +//lint -save -e578 +#if defined (__CC_ARM ) +static __ASM uint32_t nrfx_twis_error_get_and_clear_internal(uint32_t volatile * perror) +{ + mov r3, r0 + mov r1, #0 +nrfx_twis_error_get_and_clear_internal_try + ldrex r0, [r3] + strex r2, r1, [r3] + cmp r2, r1 /* did this succeed? */ + bne nrfx_twis_error_get_and_clear_internal_try /* no - try again */ + bx lr +} +#elif defined ( __GNUC__ ) +static uint32_t nrfx_twis_error_get_and_clear_internal(uint32_t volatile * perror) +{ + uint32_t ret; + uint32_t temp; + __ASM volatile( + " .syntax unified \n" + "nrfx_twis_error_get_and_clear_internal_try: \n" + " ldrex %[ret], [%[perror]] \n" + " strex %[temp], %[zero], [%[perror]] \n" + " cmp %[temp], %[zero] \n" + " bne nrfx_twis_error_get_and_clear_internal_try \n" + : /* Output */ + [ret]"=&l"(ret), + [temp]"=&l"(temp) + : /* Input */ + [zero]"l"(0), + [perror]"l"(perror) + ); + (void)temp; + return ret; +} +#elif defined ( __ICCARM__ ) +static uint32_t nrfx_twis_error_get_and_clear_internal(uint32_t volatile * perror) +{ + uint32_t ret; + uint32_t temp; + __ASM volatile( + "1: \n" + " ldrex %[ret], [%[perror]] \n" + " strex %[temp], %[zero], [%[perror]] \n" + " cmp %[temp], %[zero] \n" + " bne.n 1b \n" + : /* Output */ + [ret]"=&l"(ret), + [temp]"=&l"(temp) + : /* Input */ + [zero]"l"(0), + [perror]"l"(perror) + ); + (void)temp; + return ret; +} +#else + #error Unknown compiler +#endif +//lint -restore + +uint32_t nrfx_twis_error_get_and_clear(nrfx_twis_t const * p_instance) +{ + nrfx_twis_preprocess_status(p_instance); + /* Make sure that access to error member is atomic + * so there is no bit that is cleared if it is not copied to local variable already. */ + twis_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + return nrfx_twis_error_get_and_clear_internal(&p_cb->error); +} + + +nrfx_err_t nrfx_twis_tx_prepare(nrfx_twis_t const * p_instance, + void const * p_buf, + size_t size) +{ + nrfx_err_t err_code; + twis_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx]; + + /* Check power state*/ + if (p_cb->state != NRFX_DRV_STATE_POWERED_ON) + { + err_code = NRFX_ERROR_INVALID_STATE; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + /* Check data address */ + if (!nrfx_is_in_ram(p_buf)) + { + err_code = NRFX_ERROR_INVALID_ADDR; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + /* Check data size */ + if ((size & TWIS_TXD_MAXCNT_MAXCNT_Msk) != size) + { + err_code = NRFX_ERROR_INVALID_LENGTH; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + + nrf_twis_tx_prepare(p_instance->p_reg, + (uint8_t const *)p_buf, + (nrf_twis_amount_t)size); + err_code = NRFX_SUCCESS; + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + + +nrfx_err_t nrfx_twis_rx_prepare(nrfx_twis_t const * p_instance, + void * p_buf, + size_t size) +{ + nrfx_err_t err_code; + twis_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx]; + + /* Check power state*/ + if (p_cb->state != NRFX_DRV_STATE_POWERED_ON) + { + err_code = NRFX_ERROR_INVALID_STATE; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + /* Check data address */ + if (!nrfx_is_in_ram(p_buf)) + { + err_code = NRFX_ERROR_INVALID_ADDR; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + /* Check data size */ + if ((size & TWIS_RXD_MAXCNT_MAXCNT_Msk) != size) + { + err_code = NRFX_ERROR_INVALID_LENGTH; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + + nrf_twis_rx_prepare(p_instance->p_reg, + (uint8_t *)p_buf, + (nrf_twis_amount_t)size); + err_code = NRFX_SUCCESS; + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + + +bool nrfx_twis_is_busy(nrfx_twis_t const * p_instance) +{ + nrfx_twis_preprocess_status(p_instance); + twis_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx]; + return NRFX_TWIS_SUBSTATE_IDLE != p_cb->substate; +} + +bool nrfx_twis_is_waiting_tx_buff(nrfx_twis_t const * p_instance) +{ + nrfx_twis_preprocess_status(p_instance); + twis_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx]; + return NRFX_TWIS_SUBSTATE_READ_WAITING == p_cb->substate; +} + +bool nrfx_twis_is_waiting_rx_buff(nrfx_twis_t const * p_instance) +{ + nrfx_twis_preprocess_status(p_instance); + twis_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx]; + return NRFX_TWIS_SUBSTATE_WRITE_WAITING == p_cb->substate; +} + +bool nrfx_twis_is_pending_tx(nrfx_twis_t const * p_instance) +{ + nrfx_twis_preprocess_status(p_instance); + twis_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx]; + return NRFX_TWIS_SUBSTATE_READ_PENDING == p_cb->substate; +} + +bool nrfx_twis_is_pending_rx(nrfx_twis_t const * p_instance) +{ + nrfx_twis_preprocess_status(p_instance); + twis_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx]; + return NRFX_TWIS_SUBSTATE_WRITE_PENDING == p_cb->substate; +} + + +#if NRFX_CHECK(NRFX_TWIS0_ENABLED) +void nrfx_twis_0_irq_handler(void) +{ + nrfx_twis_state_machine(NRF_TWIS0, &m_cb[NRFX_TWIS0_INST_IDX]); +} +#endif + +#if NRFX_CHECK(NRFX_TWIS1_ENABLED) +void nrfx_twis_1_irq_handler(void) +{ + nrfx_twis_state_machine(NRF_TWIS1, &m_cb[NRFX_TWIS1_INST_IDX]); +} +#endif + +#endif // NRFX_CHECK(NRFX_TWIS_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_uart.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_uart.c new file mode 100644 index 0000000..8c5f487 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_uart.c @@ -0,0 +1,649 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_UART_ENABLED) + +#if !NRFX_CHECK(NRFX_UART0_ENABLED) +#error "No enabled UART instances. Check <nrfx_config.h>." +#endif + +#include <nrfx_uart.h> +#include "prs/nrfx_prs.h" +#include <hal/nrf_gpio.h> + +#define NRFX_LOG_MODULE UART +#include <nrfx_log.h> + +#define EVT_TO_STR(event) \ + (event == NRF_UART_EVENT_ERROR ? "NRF_UART_EVENT_ERROR" : \ + "UNKNOWN EVENT") + + +#define TX_COUNTER_ABORT_REQ_VALUE UINT32_MAX + +typedef struct +{ + void * p_context; + nrfx_uart_event_handler_t handler; + uint8_t const * p_tx_buffer; + uint8_t * p_rx_buffer; + uint8_t * p_rx_secondary_buffer; + size_t tx_buffer_length; + size_t rx_buffer_length; + size_t rx_secondary_buffer_length; + volatile size_t tx_counter; + volatile size_t rx_counter; + volatile bool tx_abort; + bool rx_enabled; + nrfx_drv_state_t state; +} uart_control_block_t; +static uart_control_block_t m_cb[NRFX_UART_ENABLED_COUNT]; + +static void apply_config(nrfx_uart_t const * p_instance, + nrfx_uart_config_t const * p_config) +{ + if (p_config->pseltxd != NRF_UART_PSEL_DISCONNECTED) + { + nrf_gpio_pin_set(p_config->pseltxd); + nrf_gpio_cfg_output(p_config->pseltxd); + } + if (p_config->pselrxd != NRF_UART_PSEL_DISCONNECTED) + { + nrf_gpio_cfg_input(p_config->pselrxd, NRF_GPIO_PIN_NOPULL); + } + + nrf_uart_baudrate_set(p_instance->p_reg, p_config->baudrate); + nrf_uart_configure(p_instance->p_reg, p_config->parity, p_config->hwfc); + nrf_uart_txrx_pins_set(p_instance->p_reg, p_config->pseltxd, p_config->pselrxd); + if (p_config->hwfc == NRF_UART_HWFC_ENABLED) + { + if (p_config->pselcts != NRF_UART_PSEL_DISCONNECTED) + { + nrf_gpio_cfg_input(p_config->pselcts, NRF_GPIO_PIN_NOPULL); + } + if (p_config->pselrts != NRF_UART_PSEL_DISCONNECTED) + { + nrf_gpio_pin_set(p_config->pselrts); + nrf_gpio_cfg_output(p_config->pselrts); + } + nrf_uart_hwfc_pins_set(p_instance->p_reg, p_config->pselrts, p_config->pselcts); + } +} + +static void interrupts_enable(nrfx_uart_t const * p_instance, + uint8_t interrupt_priority) +{ + nrf_uart_event_clear(p_instance->p_reg, NRF_UART_EVENT_TXDRDY); + nrf_uart_event_clear(p_instance->p_reg, NRF_UART_EVENT_RXTO); + nrf_uart_int_enable(p_instance->p_reg, NRF_UART_INT_MASK_TXDRDY | + NRF_UART_INT_MASK_RXTO); + NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number((void *)p_instance->p_reg), + interrupt_priority); + NRFX_IRQ_ENABLE(nrfx_get_irq_number((void *)p_instance->p_reg)); +} + +static void interrupts_disable(nrfx_uart_t const * p_instance) +{ + nrf_uart_int_disable(p_instance->p_reg, NRF_UART_INT_MASK_RXDRDY | + NRF_UART_INT_MASK_TXDRDY | + NRF_UART_INT_MASK_ERROR | + NRF_UART_INT_MASK_RXTO); + NRFX_IRQ_DISABLE(nrfx_get_irq_number((void *)p_instance->p_reg)); +} + +static void pins_to_default(nrfx_uart_t const * p_instance) +{ + /* Reset pins to default states */ + uint32_t txd; + uint32_t rxd; + uint32_t rts; + uint32_t cts; + + txd = nrf_uart_tx_pin_get(p_instance->p_reg); + rxd = nrf_uart_rx_pin_get(p_instance->p_reg); + rts = nrf_uart_rts_pin_get(p_instance->p_reg); + cts = nrf_uart_cts_pin_get(p_instance->p_reg); + nrf_uart_txrx_pins_disconnect(p_instance->p_reg); + nrf_uart_hwfc_pins_disconnect(p_instance->p_reg); + + if (txd != NRF_UART_PSEL_DISCONNECTED) + { + nrf_gpio_cfg_default(txd); + } + if (rxd != NRF_UART_PSEL_DISCONNECTED) + { + nrf_gpio_cfg_default(rxd); + } + if (cts != NRF_UART_PSEL_DISCONNECTED) + { + nrf_gpio_cfg_default(cts); + } + if (rts != NRF_UART_PSEL_DISCONNECTED) + { + nrf_gpio_cfg_default(rts); + } +} + +nrfx_err_t nrfx_uart_init(nrfx_uart_t const * p_instance, + nrfx_uart_config_t const * p_config, + nrfx_uart_event_handler_t event_handler) +{ + NRFX_ASSERT(p_config); + uart_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + nrfx_err_t err_code = NRFX_SUCCESS; + + 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_UART_ENABLED_COUNT] = { + #if NRFX_CHECK(NRFX_UART0_ENABLED) + nrfx_uart_0_irq_handler, + #endif + }; + if (nrfx_prs_acquire(p_instance->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) + + apply_config(p_instance, p_config); + + p_cb->handler = event_handler; + p_cb->p_context = p_config->p_context; + + if (p_cb->handler) + { + interrupts_enable(p_instance, p_config->interrupt_priority); + } + + nrf_uart_enable(p_instance->p_reg); + p_cb->rx_buffer_length = 0; + p_cb->rx_secondary_buffer_length = 0; + p_cb->rx_enabled = false; + p_cb->tx_buffer_length = 0; + p_cb->state = NRFX_DRV_STATE_INITIALIZED; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + +void nrfx_uart_uninit(nrfx_uart_t const * p_instance) +{ + uart_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + + nrf_uart_disable(p_instance->p_reg); + + if (p_cb->handler) + { + interrupts_disable(p_instance); + } + + pins_to_default(p_instance); + +#if NRFX_CHECK(NRFX_PRS_ENABLED) + nrfx_prs_release(p_instance->p_reg); +#endif + + p_cb->state = NRFX_DRV_STATE_UNINITIALIZED; + p_cb->handler = NULL; + NRFX_LOG_INFO("Instance uninitialized: %d.", p_instance->drv_inst_idx); +} + +static void tx_byte(NRF_UART_Type * p_uart, uart_control_block_t * p_cb) +{ + nrf_uart_event_clear(p_uart, NRF_UART_EVENT_TXDRDY); + uint8_t txd = p_cb->p_tx_buffer[p_cb->tx_counter]; + p_cb->tx_counter++; + nrf_uart_txd_set(p_uart, txd); +} + +static bool tx_blocking(NRF_UART_Type * p_uart, uart_control_block_t * p_cb) +{ + while (p_cb->tx_counter < p_cb->tx_buffer_length) + { + // Wait until the transmitter is ready to accept a new byte. + // Exit immediately if the transfer has been aborted. + while (!nrf_uart_event_check(p_uart, NRF_UART_EVENT_TXDRDY)) + { + if (p_cb->tx_abort) + { + return false; + } + } + + tx_byte(p_uart, p_cb); + } + + return true; +} + +nrfx_err_t nrfx_uart_tx(nrfx_uart_t const * p_instance, + uint8_t const * p_data, + size_t length) +{ + uart_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED); + NRFX_ASSERT(p_data); + NRFX_ASSERT(length > 0); + + nrfx_err_t err_code; + + if (nrfx_uart_tx_in_progress(p_instance)) + { + err_code = NRFX_ERROR_BUSY; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + p_cb->tx_buffer_length = length; + p_cb->p_tx_buffer = p_data; + p_cb->tx_counter = 0; + p_cb->tx_abort = false; + + NRFX_LOG_INFO("Transfer tx_len: %d.", p_cb->tx_buffer_length); + NRFX_LOG_DEBUG("Tx data:"); + NRFX_LOG_HEXDUMP_DEBUG(p_cb->p_tx_buffer, + p_cb->tx_buffer_length * sizeof(p_cb->p_tx_buffer[0])); + + err_code = NRFX_SUCCESS; + + nrf_uart_event_clear(p_instance->p_reg, NRF_UART_EVENT_TXDRDY); + nrf_uart_task_trigger(p_instance->p_reg, NRF_UART_TASK_STARTTX); + + tx_byte(p_instance->p_reg, p_cb); + + if (p_cb->handler == NULL) + { + if (!tx_blocking(p_instance->p_reg, p_cb)) + { + // The transfer has been aborted. + err_code = NRFX_ERROR_FORBIDDEN; + } + else + { + // Wait until the last byte is completely transmitted. + while (!nrf_uart_event_check(p_instance->p_reg, NRF_UART_EVENT_TXDRDY)) + {} + nrf_uart_task_trigger(p_instance->p_reg, NRF_UART_TASK_STOPTX); + } + p_cb->tx_buffer_length = 0; + } + + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + +bool nrfx_uart_tx_in_progress(nrfx_uart_t const * p_instance) +{ + return (m_cb[p_instance->drv_inst_idx].tx_buffer_length != 0); +} + +static void rx_enable(nrfx_uart_t const * p_instance) +{ + nrf_uart_event_clear(p_instance->p_reg, NRF_UART_EVENT_ERROR); + nrf_uart_event_clear(p_instance->p_reg, NRF_UART_EVENT_RXDRDY); + nrf_uart_task_trigger(p_instance->p_reg, NRF_UART_TASK_STARTRX); +} + +static void rx_byte(NRF_UART_Type * p_uart, uart_control_block_t * p_cb) +{ + if (!p_cb->rx_buffer_length) + { + nrf_uart_event_clear(p_uart, NRF_UART_EVENT_RXDRDY); + // Byte received when buffer is not set - data lost. + (void) nrf_uart_rxd_get(p_uart); + return; + } + nrf_uart_event_clear(p_uart, NRF_UART_EVENT_RXDRDY); + p_cb->p_rx_buffer[p_cb->rx_counter] = nrf_uart_rxd_get(p_uart); + p_cb->rx_counter++; +} + +nrfx_err_t nrfx_uart_rx(nrfx_uart_t const * p_instance, + uint8_t * p_data, + size_t length) +{ + uart_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + + NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state == NRFX_DRV_STATE_INITIALIZED); + NRFX_ASSERT(p_data); + NRFX_ASSERT(length > 0); + + nrfx_err_t err_code; + + bool second_buffer = false; + + if (p_cb->handler) + { + nrf_uart_int_disable(p_instance->p_reg, NRF_UART_INT_MASK_RXDRDY | + NRF_UART_INT_MASK_ERROR); + } + if (p_cb->rx_buffer_length != 0) + { + if (p_cb->rx_secondary_buffer_length != 0) + { + if (p_cb->handler) + { + nrf_uart_int_enable(p_instance->p_reg, NRF_UART_INT_MASK_RXDRDY | + NRF_UART_INT_MASK_ERROR); + } + err_code = NRFX_ERROR_BUSY; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + second_buffer = true; + } + + if (!second_buffer) + { + p_cb->rx_buffer_length = length; + p_cb->p_rx_buffer = p_data; + p_cb->rx_counter = 0; + p_cb->rx_secondary_buffer_length = 0; + } + else + { + p_cb->p_rx_secondary_buffer = p_data; + p_cb->rx_secondary_buffer_length = length; + } + + NRFX_LOG_INFO("Transfer rx_len: %d.", length); + + if ((!p_cb->rx_enabled) && (!second_buffer)) + { + rx_enable(p_instance); + } + + if (p_cb->handler == NULL) + { + nrf_uart_event_clear(p_instance->p_reg, NRF_UART_EVENT_RXTO); + + bool rxrdy; + bool rxto; + bool error; + do + { + do + { + error = nrf_uart_event_check(p_instance->p_reg, NRF_UART_EVENT_ERROR); + rxrdy = nrf_uart_event_check(p_instance->p_reg, NRF_UART_EVENT_RXDRDY); + rxto = nrf_uart_event_check(p_instance->p_reg, NRF_UART_EVENT_RXTO); + } while ((!rxrdy) && (!rxto) && (!error)); + + if (error || rxto) + { + break; + } + rx_byte(p_instance->p_reg, p_cb); + } while (p_cb->rx_buffer_length > p_cb->rx_counter); + + p_cb->rx_buffer_length = 0; + if (error) + { + err_code = NRFX_ERROR_INTERNAL; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + + if (rxto) + { + err_code = NRFX_ERROR_FORBIDDEN; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + + if (p_cb->rx_enabled) + { + nrf_uart_task_trigger(p_instance->p_reg, NRF_UART_TASK_STARTRX); + } + else + { + // Skip stopping RX if driver is forced to be enabled. + nrf_uart_task_trigger(p_instance->p_reg, NRF_UART_TASK_STOPRX); + } + } + else + { + nrf_uart_int_enable(p_instance->p_reg, NRF_UART_INT_MASK_RXDRDY | + NRF_UART_INT_MASK_ERROR); + } + 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_uart_rx_ready(nrfx_uart_t const * p_instance) +{ + return nrf_uart_event_check(p_instance->p_reg, NRF_UART_EVENT_RXDRDY); +} + +void nrfx_uart_rx_enable(nrfx_uart_t const * p_instance) +{ + if (!m_cb[p_instance->drv_inst_idx].rx_enabled) + { + rx_enable(p_instance); + m_cb[p_instance->drv_inst_idx].rx_enabled = true; + } +} + +void nrfx_uart_rx_disable(nrfx_uart_t const * p_instance) +{ + nrf_uart_task_trigger(p_instance->p_reg, NRF_UART_TASK_STOPRX); + m_cb[p_instance->drv_inst_idx].rx_enabled = false; +} + +uint32_t nrfx_uart_errorsrc_get(nrfx_uart_t const * p_instance) +{ + nrf_uart_event_clear(p_instance->p_reg, NRF_UART_EVENT_ERROR); + return nrf_uart_errorsrc_get_and_clear(p_instance->p_reg); +} + +static void rx_done_event(uart_control_block_t * p_cb, + size_t bytes, + uint8_t * p_data) +{ + nrfx_uart_event_t event; + + event.type = NRFX_UART_EVT_RX_DONE; + event.data.rxtx.bytes = bytes; + event.data.rxtx.p_data = p_data; + + p_cb->handler(&event, p_cb->p_context); +} + +static void tx_done_event(uart_control_block_t * p_cb, + size_t bytes) +{ + nrfx_uart_event_t event; + + event.type = NRFX_UART_EVT_TX_DONE; + event.data.rxtx.bytes = bytes; + event.data.rxtx.p_data = (uint8_t *)p_cb->p_tx_buffer; + + p_cb->tx_buffer_length = 0; + + p_cb->handler(&event, p_cb->p_context); +} + +void nrfx_uart_tx_abort(nrfx_uart_t const * p_instance) +{ + uart_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + + p_cb->tx_abort = true; + nrf_uart_task_trigger(p_instance->p_reg, NRF_UART_TASK_STOPTX); + if (p_cb->handler) + { + tx_done_event(p_cb, p_cb->tx_counter); + } + + NRFX_LOG_INFO("TX transaction aborted."); +} + +void nrfx_uart_rx_abort(nrfx_uart_t const * p_instance) +{ + nrf_uart_int_disable(p_instance->p_reg, NRF_UART_INT_MASK_RXDRDY | + NRF_UART_INT_MASK_ERROR); + nrf_uart_task_trigger(p_instance->p_reg, NRF_UART_TASK_STOPRX); + + NRFX_LOG_INFO("RX transaction aborted."); +} + +static void uart_irq_handler(NRF_UART_Type * p_uart, + uart_control_block_t * p_cb) +{ + if (nrf_uart_int_enable_check(p_uart, NRF_UART_INT_MASK_ERROR) && + nrf_uart_event_check(p_uart, NRF_UART_EVENT_ERROR)) + { + nrfx_uart_event_t event; + nrf_uart_event_clear(p_uart, NRF_UART_EVENT_ERROR); + NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_UART_EVENT_ERROR)); + nrf_uart_int_disable(p_uart, NRF_UART_INT_MASK_RXDRDY | + NRF_UART_INT_MASK_ERROR); + if (!p_cb->rx_enabled) + { + nrf_uart_task_trigger(p_uart, NRF_UART_TASK_STOPRX); + } + event.type = NRFX_UART_EVT_ERROR; + event.data.error.error_mask = nrf_uart_errorsrc_get_and_clear(p_uart); + event.data.error.rxtx.bytes = p_cb->rx_buffer_length; + event.data.error.rxtx.p_data = p_cb->p_rx_buffer; + + // Abort transfer. + p_cb->rx_buffer_length = 0; + p_cb->rx_secondary_buffer_length = 0; + + p_cb->handler(&event,p_cb->p_context); + } + else if (nrf_uart_int_enable_check(p_uart, NRF_UART_INT_MASK_RXDRDY) && + nrf_uart_event_check(p_uart, NRF_UART_EVENT_RXDRDY)) + { + rx_byte(p_uart, p_cb); + if (p_cb->rx_buffer_length == p_cb->rx_counter) + { + if (p_cb->rx_secondary_buffer_length) + { + uint8_t * p_data = p_cb->p_rx_buffer; + size_t rx_counter = p_cb->rx_counter; + + // Switch to secondary buffer. + p_cb->rx_buffer_length = p_cb->rx_secondary_buffer_length; + p_cb->p_rx_buffer = p_cb->p_rx_secondary_buffer; + p_cb->rx_secondary_buffer_length = 0; + p_cb->rx_counter = 0; + rx_done_event(p_cb, rx_counter, p_data); + } + else + { + if (!p_cb->rx_enabled) + { + nrf_uart_task_trigger(p_uart, NRF_UART_TASK_STOPRX); + } + nrf_uart_int_disable(p_uart, NRF_UART_INT_MASK_RXDRDY | + NRF_UART_INT_MASK_ERROR); + p_cb->rx_buffer_length = 0; + rx_done_event(p_cb, p_cb->rx_counter, p_cb->p_rx_buffer); + } + } + } + + if (nrf_uart_event_check(p_uart, NRF_UART_EVENT_TXDRDY)) + { + if (p_cb->tx_counter < p_cb->tx_buffer_length && + !p_cb->tx_abort) + { + tx_byte(p_uart, p_cb); + } + else + { + nrf_uart_event_clear(p_uart, NRF_UART_EVENT_TXDRDY); + if (p_cb->tx_buffer_length) + { + tx_done_event(p_cb, p_cb->tx_buffer_length); + } + } + } + + if (nrf_uart_event_check(p_uart, NRF_UART_EVENT_RXTO)) + { + nrf_uart_event_clear(p_uart, NRF_UART_EVENT_RXTO); + + // RXTO event may be triggered as a result of abort call. In th + if (p_cb->rx_enabled) + { + nrf_uart_task_trigger(p_uart, NRF_UART_TASK_STARTRX); + } + if (p_cb->rx_buffer_length) + { + p_cb->rx_buffer_length = 0; + rx_done_event(p_cb, p_cb->rx_counter, p_cb->p_rx_buffer); + } + } +} + +#if NRFX_CHECK(NRFX_UART0_ENABLED) +void nrfx_uart_0_irq_handler(void) +{ + uart_irq_handler(NRF_UART0, &m_cb[NRFX_UART0_INST_IDX]); +} +#endif + +#endif // NRFX_CHECK(NRFX_UART_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_uarte.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_uarte.c new file mode 100644 index 0000000..1d5bf09 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_uarte.c @@ -0,0 +1,583 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_UARTE_ENABLED) + +#if !(NRFX_CHECK(NRFX_UARTE0_ENABLED) || NRFX_CHECK(NRFX_UARTE1_ENABLED)) +#error "No enabled UARTE instances. Check <nrfx_config.h>." +#endif + +#include <nrfx_uarte.h> +#include "prs/nrfx_prs.h" +#include <hal/nrf_gpio.h> + +#define NRFX_LOG_MODULE UARTE +#include <nrfx_log.h> + +#define EVT_TO_STR(event) \ + (event == NRF_UARTE_EVENT_ERROR ? "NRF_UARTE_EVENT_ERROR" : \ + "UNKNOWN EVENT") + +#define UARTEX_LENGTH_VALIDATE(peripheral, drv_inst_idx, len1, len2) \ + (((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) && \ + NRFX_EASYDMA_LENGTH_VALIDATE(peripheral, len1, len2)) + +#if NRFX_CHECK(NRFX_UARTE0_ENABLED) +#define UARTE0_LENGTH_VALIDATE(...) UARTEX_LENGTH_VALIDATE(UARTE0, __VA_ARGS__) +#else +#define UARTE0_LENGTH_VALIDATE(...) 0 +#endif + +#if NRFX_CHECK(NRFX_UARTE1_ENABLED) +#define UARTE1_LENGTH_VALIDATE(...) UARTEX_LENGTH_VALIDATE(UARTE1, __VA_ARGS__) +#else +#define UARTE1_LENGTH_VALIDATE(...) 0 +#endif + +#define UARTE_LENGTH_VALIDATE(drv_inst_idx, length) \ + (UARTE0_LENGTH_VALIDATE(drv_inst_idx, length, 0) || \ + UARTE1_LENGTH_VALIDATE(drv_inst_idx, length, 0)) + + +typedef struct +{ + void * p_context; + nrfx_uarte_event_handler_t handler; + uint8_t const * p_tx_buffer; + uint8_t * p_rx_buffer; + uint8_t * p_rx_secondary_buffer; + size_t tx_buffer_length; + size_t rx_buffer_length; + size_t rx_secondary_buffer_length; + nrfx_drv_state_t state; +} uarte_control_block_t; +static uarte_control_block_t m_cb[NRFX_UARTE_ENABLED_COUNT]; + +static void apply_config(nrfx_uarte_t const * p_instance, + nrfx_uarte_config_t const * p_config) +{ + if (p_config->pseltxd != NRF_UARTE_PSEL_DISCONNECTED) + { + nrf_gpio_pin_set(p_config->pseltxd); + nrf_gpio_cfg_output(p_config->pseltxd); + } + if (p_config->pselrxd != NRF_UARTE_PSEL_DISCONNECTED) + { + nrf_gpio_cfg_input(p_config->pselrxd, NRF_GPIO_PIN_NOPULL); + } + + nrf_uarte_baudrate_set(p_instance->p_reg, p_config->baudrate); + nrf_uarte_configure(p_instance->p_reg, p_config->parity, p_config->hwfc); + nrf_uarte_txrx_pins_set(p_instance->p_reg, p_config->pseltxd, p_config->pselrxd); + if (p_config->hwfc == NRF_UARTE_HWFC_ENABLED) + { + if (p_config->pselcts != NRF_UARTE_PSEL_DISCONNECTED) + { + nrf_gpio_cfg_input(p_config->pselcts, NRF_GPIO_PIN_NOPULL); + } + if (p_config->pselrts != NRF_UARTE_PSEL_DISCONNECTED) + { + nrf_gpio_pin_set(p_config->pselrts); + nrf_gpio_cfg_output(p_config->pselrts); + } + nrf_uarte_hwfc_pins_set(p_instance->p_reg, p_config->pselrts, p_config->pselcts); + } +} + +static void interrupts_enable(nrfx_uarte_t const * p_instance, + uint8_t interrupt_priority) +{ + nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_ENDRX); + nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_ENDTX); + nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_ERROR); + nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_RXTO); + nrf_uarte_int_enable(p_instance->p_reg, NRF_UARTE_INT_ENDRX_MASK | + NRF_UARTE_INT_ENDTX_MASK | + NRF_UARTE_INT_ERROR_MASK | + NRF_UARTE_INT_RXTO_MASK); + NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number((void *)p_instance->p_reg), + interrupt_priority); + NRFX_IRQ_ENABLE(nrfx_get_irq_number((void *)p_instance->p_reg)); +} + +static void interrupts_disable(nrfx_uarte_t const * p_instance) +{ + nrf_uarte_int_disable(p_instance->p_reg, NRF_UARTE_INT_ENDRX_MASK | + NRF_UARTE_INT_ENDTX_MASK | + NRF_UARTE_INT_ERROR_MASK | + NRF_UARTE_INT_RXTO_MASK); + NRFX_IRQ_DISABLE(nrfx_get_irq_number((void *)p_instance->p_reg)); +} + +static void pins_to_default(nrfx_uarte_t const * p_instance) +{ + /* Reset pins to default states */ + uint32_t txd; + uint32_t rxd; + uint32_t rts; + uint32_t cts; + + txd = nrf_uarte_tx_pin_get(p_instance->p_reg); + rxd = nrf_uarte_rx_pin_get(p_instance->p_reg); + rts = nrf_uarte_rts_pin_get(p_instance->p_reg); + cts = nrf_uarte_cts_pin_get(p_instance->p_reg); + nrf_uarte_txrx_pins_disconnect(p_instance->p_reg); + nrf_uarte_hwfc_pins_disconnect(p_instance->p_reg); + + if (txd != NRF_UARTE_PSEL_DISCONNECTED) + { + nrf_gpio_cfg_default(txd); + } + if (rxd != NRF_UARTE_PSEL_DISCONNECTED) + { + nrf_gpio_cfg_default(rxd); + } + if (cts != NRF_UARTE_PSEL_DISCONNECTED) + { + nrf_gpio_cfg_default(cts); + } + if (rts != NRF_UARTE_PSEL_DISCONNECTED) + { + nrf_gpio_cfg_default(rts); + } +} + +nrfx_err_t nrfx_uarte_init(nrfx_uarte_t const * p_instance, + nrfx_uarte_config_t const * p_config, + nrfx_uarte_event_handler_t event_handler) +{ + NRFX_ASSERT(p_config); + uarte_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + nrfx_err_t err_code = NRFX_SUCCESS; + + 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_UARTE_ENABLED_COUNT] = { + #if NRFX_CHECK(NRFX_UARTE0_ENABLED) + nrfx_uarte_0_irq_handler, + #endif + #if NRFX_CHECK(NRFX_UARTE1_ENABLED) + nrfx_uarte_1_irq_handler, + #endif + }; + if (nrfx_prs_acquire(p_instance->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) + + apply_config(p_instance, p_config); + + p_cb->handler = event_handler; + p_cb->p_context = p_config->p_context; + + if (p_cb->handler) + { + interrupts_enable(p_instance, p_config->interrupt_priority); + } + + nrf_uarte_enable(p_instance->p_reg); + p_cb->rx_buffer_length = 0; + p_cb->rx_secondary_buffer_length = 0; + p_cb->tx_buffer_length = 0; + p_cb->state = NRFX_DRV_STATE_INITIALIZED; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + +void nrfx_uarte_uninit(nrfx_uarte_t const * p_instance) +{ + uarte_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + + nrf_uarte_disable(p_instance->p_reg); + + if (p_cb->handler) + { + interrupts_disable(p_instance); + } + + pins_to_default(p_instance); + +#if NRFX_CHECK(NRFX_PRS_ENABLED) + nrfx_prs_release(p_instance->p_reg); +#endif + + p_cb->state = NRFX_DRV_STATE_UNINITIALIZED; + p_cb->handler = NULL; + NRFX_LOG_INFO("Instance uninitialized: %d.", p_instance->drv_inst_idx); +} + +nrfx_err_t nrfx_uarte_tx(nrfx_uarte_t const * p_instance, + uint8_t const * p_data, + size_t length) +{ + uarte_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED); + NRFX_ASSERT(p_data); + NRFX_ASSERT(length > 0); + NRFX_ASSERT(UARTE_LENGTH_VALIDATE(p_instance->drv_inst_idx, length)); + + nrfx_err_t err_code; + + // EasyDMA requires that transfer buffers are placed in DataRAM, + // signal error if the are not. + if (!nrfx_is_in_ram(p_data)) + { + 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; + } + + if (nrfx_uarte_tx_in_progress(p_instance)) + { + err_code = NRFX_ERROR_BUSY; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + p_cb->tx_buffer_length = length; + p_cb->p_tx_buffer = p_data; + + NRFX_LOG_INFO("Transfer tx_len: %d.", p_cb->tx_buffer_length); + NRFX_LOG_DEBUG("Tx data:"); + NRFX_LOG_HEXDUMP_DEBUG(p_cb->p_tx_buffer, + p_cb->tx_buffer_length * sizeof(p_cb->p_tx_buffer[0])); + + err_code = NRFX_SUCCESS; + + nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_ENDTX); + nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_TXSTOPPED); + nrf_uarte_tx_buffer_set(p_instance->p_reg, p_cb->p_tx_buffer, p_cb->tx_buffer_length); + nrf_uarte_task_trigger(p_instance->p_reg, NRF_UARTE_TASK_STARTTX); + + if (p_cb->handler == NULL) + { + bool endtx; + bool txstopped; + do + { + endtx = nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_ENDTX); + txstopped = nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_TXSTOPPED); + } + while ((!endtx) && (!txstopped)); + + if (txstopped) + { + err_code = NRFX_ERROR_FORBIDDEN; + } + p_cb->tx_buffer_length = 0; + } + + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + +bool nrfx_uarte_tx_in_progress(nrfx_uarte_t const * p_instance) +{ + return (m_cb[p_instance->drv_inst_idx].tx_buffer_length != 0); +} + +nrfx_err_t nrfx_uarte_rx(nrfx_uarte_t const * p_instance, + uint8_t * p_data, + size_t length) +{ + uarte_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + + NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state == NRFX_DRV_STATE_INITIALIZED); + NRFX_ASSERT(p_data); + NRFX_ASSERT(length > 0); + NRFX_ASSERT(UARTE_LENGTH_VALIDATE(p_instance->drv_inst_idx, length)); + + nrfx_err_t err_code; + + // EasyDMA requires that transfer buffers are placed in DataRAM, + // signal error if the are not. + if (!nrfx_is_in_ram(p_data)) + { + 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; + } + + bool second_buffer = false; + + if (p_cb->handler) + { + nrf_uarte_int_disable(p_instance->p_reg, NRF_UARTE_INT_ERROR_MASK | + NRF_UARTE_INT_ENDRX_MASK); + } + if (p_cb->rx_buffer_length != 0) + { + if (p_cb->rx_secondary_buffer_length != 0) + { + if (p_cb->handler) + { + nrf_uarte_int_enable(p_instance->p_reg, NRF_UARTE_INT_ERROR_MASK | + NRF_UARTE_INT_ENDRX_MASK); + } + err_code = NRFX_ERROR_BUSY; + NRFX_LOG_WARNING("Function: %s, error code: %s.", + __func__, + NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; + } + second_buffer = true; + } + + if (!second_buffer) + { + p_cb->rx_buffer_length = length; + p_cb->p_rx_buffer = p_data; + p_cb->rx_secondary_buffer_length = 0; + } + else + { + p_cb->p_rx_secondary_buffer = p_data; + p_cb->rx_secondary_buffer_length = length; + } + + NRFX_LOG_INFO("Transfer rx_len: %d.", length); + + err_code = NRFX_SUCCESS; + + nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_ENDRX); + nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_RXTO); + nrf_uarte_rx_buffer_set(p_instance->p_reg, p_data, length); + if (!second_buffer) + { + nrf_uarte_task_trigger(p_instance->p_reg, NRF_UARTE_TASK_STARTRX); + } + else + { + nrf_uarte_shorts_enable(p_instance->p_reg, NRF_UARTE_SHORT_ENDRX_STARTRX); + } + + if (m_cb[p_instance->drv_inst_idx].handler == NULL) + { + bool endrx; + bool rxto; + bool error; + do { + endrx = nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_ENDRX); + rxto = nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_RXTO); + error = nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_ERROR); + } while ((!endrx) && (!rxto) && (!error)); + + m_cb[p_instance->drv_inst_idx].rx_buffer_length = 0; + + if (error) + { + err_code = NRFX_ERROR_INTERNAL; + } + + if (rxto) + { + err_code = NRFX_ERROR_FORBIDDEN; + } + } + else + { + nrf_uarte_int_enable(p_instance->p_reg, NRF_UARTE_INT_ERROR_MASK | + NRF_UARTE_INT_ENDRX_MASK); + } + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); + return err_code; +} + +bool nrfx_uarte_rx_ready(nrfx_uarte_t const * p_instance) +{ + return nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_ENDRX); +} + +uint32_t nrfx_uarte_errorsrc_get(nrfx_uarte_t const * p_instance) +{ + nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_ERROR); + return nrf_uarte_errorsrc_get_and_clear(p_instance->p_reg); +} + +static void rx_done_event(uarte_control_block_t * p_cb, + size_t bytes, + uint8_t * p_data) +{ + nrfx_uarte_event_t event; + + event.type = NRFX_UARTE_EVT_RX_DONE; + event.data.rxtx.bytes = bytes; + event.data.rxtx.p_data = p_data; + + p_cb->handler(&event, p_cb->p_context); +} + +static void tx_done_event(uarte_control_block_t * p_cb, + size_t bytes) +{ + nrfx_uarte_event_t event; + + event.type = NRFX_UARTE_EVT_TX_DONE; + event.data.rxtx.bytes = bytes; + event.data.rxtx.p_data = (uint8_t *)p_cb->p_tx_buffer; + + p_cb->tx_buffer_length = 0; + + p_cb->handler(&event, p_cb->p_context); +} + +void nrfx_uarte_tx_abort(nrfx_uarte_t const * p_instance) +{ + uarte_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; + + nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_TXSTOPPED); + nrf_uarte_task_trigger(p_instance->p_reg, NRF_UARTE_TASK_STOPTX); + if (p_cb->handler == NULL) + { + while (!nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_TXSTOPPED)) + {} + } + NRFX_LOG_INFO("TX transaction aborted."); +} + +void nrfx_uarte_rx_abort(nrfx_uarte_t const * p_instance) +{ + nrf_uarte_task_trigger(p_instance->p_reg, NRF_UARTE_TASK_STOPRX); + NRFX_LOG_INFO("RX transaction aborted."); +} + +static void uarte_irq_handler(NRF_UARTE_Type * p_uarte, + uarte_control_block_t * p_cb) +{ + if (nrf_uarte_event_check(p_uarte, NRF_UARTE_EVENT_ERROR)) + { + nrfx_uarte_event_t event; + + nrf_uarte_event_clear(p_uarte, NRF_UARTE_EVENT_ERROR); + + event.type = NRFX_UARTE_EVT_ERROR; + event.data.error.error_mask = nrf_uarte_errorsrc_get_and_clear(p_uarte); + event.data.error.rxtx.bytes = nrf_uarte_rx_amount_get(p_uarte); + event.data.error.rxtx.p_data = p_cb->p_rx_buffer; + + // Abort transfer. + p_cb->rx_buffer_length = 0; + p_cb->rx_secondary_buffer_length = 0; + + p_cb->handler(&event, p_cb->p_context); + } + else if (nrf_uarte_event_check(p_uarte, NRF_UARTE_EVENT_ENDRX)) + { + nrf_uarte_event_clear(p_uarte, NRF_UARTE_EVENT_ENDRX); + size_t amount = nrf_uarte_rx_amount_get(p_uarte); + // If the transfer was stopped before completion, amount of transfered bytes + // will not be equal to the buffer length. Interrupted transfer is ignored. + if (amount == p_cb->rx_buffer_length) + { + if (p_cb->rx_secondary_buffer_length) + { + uint8_t * p_data = p_cb->p_rx_buffer; + nrf_uarte_shorts_disable(p_uarte, NRF_UARTE_SHORT_ENDRX_STARTRX); + p_cb->rx_buffer_length = p_cb->rx_secondary_buffer_length; + p_cb->p_rx_buffer = p_cb->p_rx_secondary_buffer; + p_cb->rx_secondary_buffer_length = 0; + rx_done_event(p_cb, amount, p_data); + } + else + { + p_cb->rx_buffer_length = 0; + rx_done_event(p_cb, amount, p_cb->p_rx_buffer); + } + } + } + + if (nrf_uarte_event_check(p_uarte, NRF_UARTE_EVENT_RXTO)) + { + nrf_uarte_event_clear(p_uarte, NRF_UARTE_EVENT_RXTO); + if (p_cb->rx_buffer_length) + { + p_cb->rx_buffer_length = 0; + rx_done_event(p_cb, nrf_uarte_rx_amount_get(p_uarte), p_cb->p_rx_buffer); + } + } + + if (nrf_uarte_event_check(p_uarte, NRF_UARTE_EVENT_ENDTX)) + { + nrf_uarte_event_clear(p_uarte, NRF_UARTE_EVENT_ENDTX); + if (p_cb->tx_buffer_length) + { + tx_done_event(p_cb, nrf_uarte_tx_amount_get(p_uarte)); + } + } +} + +#if NRFX_CHECK(NRFX_UARTE0_ENABLED) +void nrfx_uarte_0_irq_handler(void) +{ + uarte_irq_handler(NRF_UARTE0, &m_cb[NRFX_UARTE0_INST_IDX]); +} +#endif + +#if NRFX_CHECK(NRFX_UARTE1_ENABLED) +void nrfx_uarte_1_irq_handler(void) +{ + uarte_irq_handler(NRF_UARTE1, &m_cb[NRFX_UARTE1_INST_IDX]); +} +#endif + +#endif // NRFX_CHECK(NRFX_UARTE_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_wdt.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_wdt.c new file mode 100644 index 0000000..d4d33b1 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/nrfx_wdt.c @@ -0,0 +1,153 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_WDT_ENABLED) +#include <nrfx_wdt.h> + +#define NRFX_LOG_MODULE WDT +#include <nrfx_log.h> + + +/**@brief WDT event handler. */ +static nrfx_wdt_event_handler_t m_wdt_event_handler; + +/**@brief WDT state. */ +static nrfx_drv_state_t m_state; + +/**@brief WDT alloc table. */ +static uint32_t m_alloc_index; + +/**@brief WDT interrupt handler. */ +void nrfx_wdt_irq_handler(void) +{ + if (nrf_wdt_int_enable_check(NRF_WDT_INT_TIMEOUT_MASK) == true) + { + nrf_wdt_event_clear(NRF_WDT_EVENT_TIMEOUT); + m_wdt_event_handler(); + } +} + + +nrfx_err_t nrfx_wdt_init(nrfx_wdt_config_t const * p_config, + nrfx_wdt_event_handler_t wdt_event_handler) +{ + NRFX_ASSERT(p_config); + NRFX_ASSERT(wdt_event_handler != NULL); + nrfx_err_t err_code; + m_wdt_event_handler = wdt_event_handler; + + if (m_state == NRFX_DRV_STATE_UNINITIALIZED) + { + m_state = NRFX_DRV_STATE_INITIALIZED; + } + else + { + 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; + } + + nrf_wdt_behaviour_set(p_config->behaviour); + + nrf_wdt_reload_value_set((p_config->reload_value * 32768) / 1000); + + NRFX_IRQ_PRIORITY_SET(WDT_IRQn, p_config->interrupt_priority); + NRFX_IRQ_ENABLE(WDT_IRQn); + + 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_wdt_enable(void) +{ + NRFX_ASSERT(m_alloc_index != 0); + NRFX_ASSERT(m_state == NRFX_DRV_STATE_INITIALIZED); + nrf_wdt_int_enable(NRF_WDT_INT_TIMEOUT_MASK); + nrf_wdt_task_trigger(NRF_WDT_TASK_START); + m_state = NRFX_DRV_STATE_POWERED_ON; + NRFX_LOG_INFO("Enabled."); +} + + +void nrfx_wdt_feed(void) +{ + NRFX_ASSERT(m_state == NRFX_DRV_STATE_POWERED_ON); + for (uint32_t i = 0; i < m_alloc_index; i++) + { + nrf_wdt_reload_request_set((nrf_wdt_rr_register_t)(NRF_WDT_RR0 + i)); + } +} + +nrfx_err_t nrfx_wdt_channel_alloc(nrfx_wdt_channel_id * p_channel_id) +{ + nrfx_err_t result; + NRFX_ASSERT(p_channel_id); + NRFX_ASSERT(m_state == NRFX_DRV_STATE_INITIALIZED); + + NRFX_CRITICAL_SECTION_ENTER(); + if (m_alloc_index < NRF_WDT_CHANNEL_NUMBER) + { + *p_channel_id = (nrfx_wdt_channel_id)(NRF_WDT_RR0 + m_alloc_index); + m_alloc_index++; + nrf_wdt_reload_request_enable(*p_channel_id); + result = NRFX_SUCCESS; + } + else + { + result = NRFX_ERROR_NO_MEM; + } + NRFX_CRITICAL_SECTION_EXIT(); + NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(result)); + return result; +} + +void nrfx_wdt_channel_feed(nrfx_wdt_channel_id channel_id) +{ + NRFX_ASSERT(m_state == NRFX_DRV_STATE_POWERED_ON); + nrf_wdt_reload_request_set(channel_id); +} + +#endif // NRFX_CHECK(NRFX_WDT_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/prs/nrfx_prs.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/prs/nrfx_prs.c new file mode 100644 index 0000000..e7a105f --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/prs/nrfx_prs.c @@ -0,0 +1,166 @@ +/** + * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <nrfx.h> + +#if NRFX_CHECK(NRFX_PRS_ENABLED) +#include "nrfx_prs.h" + +#define NRFX_LOG_MODULE PRS +#include <nrfx_log.h> + +#define LOG_FUNCTION_EXIT(level, ret_code) \ + NRFX_LOG_##level("Function: %s, error code: %s.", \ + __func__, \ + NRFX_LOG_ERROR_STRING_GET(ret_code)) + + +typedef struct { + nrfx_irq_handler_t handler; + bool acquired; +} prs_box_t; + +#define PRS_BOX_DEFINE(n) \ + static prs_box_t m_prs_box_##n = { .handler = NULL, .acquired = false }; \ + void nrfx_prs_box_##n##_irq_handler(void) \ + { \ + NRFX_ASSERT(m_prs_box_##n.handler); \ + m_prs_box_##n.handler(); \ + } + +#if defined(NRFX_PRS_BOX_0_ADDR) && NRFX_CHECK(NRFX_PRS_BOX_0_ENABLED) +PRS_BOX_DEFINE(0) +#endif +#if defined(NRFX_PRS_BOX_1_ADDR) && NRFX_CHECK(NRFX_PRS_BOX_1_ENABLED) +PRS_BOX_DEFINE(1) +#endif +#if defined(NRFX_PRS_BOX_2_ADDR) && NRFX_CHECK(NRFX_PRS_BOX_2_ENABLED) +PRS_BOX_DEFINE(2) +#endif +#if defined(NRFX_PRS_BOX_3_ADDR) && NRFX_CHECK(NRFX_PRS_BOX_3_ENABLED) +PRS_BOX_DEFINE(3) +#endif +#if defined(NRFX_PRS_BOX_4_ADDR) && NRFX_CHECK(NRFX_PRS_BOX_4_ENABLED) +PRS_BOX_DEFINE(4) +#endif + + +static prs_box_t * prs_box_get(void const * p_base_addr) +{ +#if !defined(IS_PRS_BOX) +#define IS_PRS_BOX(n, p_base_addr) ((p_base_addr) == NRFX_PRS_BOX_##n##_ADDR) +#endif + +#if defined(NRFX_PRS_BOX_0_ADDR) && NRFX_CHECK(NRFX_PRS_BOX_0_ENABLED) + if (IS_PRS_BOX(0, p_base_addr)) { return &m_prs_box_0; } + else +#endif +#if defined(NRFX_PRS_BOX_1_ADDR) && NRFX_CHECK(NRFX_PRS_BOX_1_ENABLED) + if (IS_PRS_BOX(1, p_base_addr)) { return &m_prs_box_1; } + else +#endif +#if defined(NRFX_PRS_BOX_2_ADDR) && NRFX_CHECK(NRFX_PRS_BOX_2_ENABLED) + if (IS_PRS_BOX(2, p_base_addr)) { return &m_prs_box_2; } + else +#endif +#if defined(NRFX_PRS_BOX_3_ADDR) && NRFX_CHECK(NRFX_PRS_BOX_3_ENABLED) + if (IS_PRS_BOX(3, p_base_addr)) { return &m_prs_box_3; } + else +#endif +#if defined(NRFX_PRS_BOX_4_ADDR) && NRFX_CHECK(NRFX_PRS_BOX_4_ENABLED) + if (IS_PRS_BOX(4, p_base_addr)) { return &m_prs_box_4; } + else +#endif + { + return NULL; + } +} + +nrfx_err_t nrfx_prs_acquire(void const * p_base_addr, + nrfx_irq_handler_t irq_handler) +{ + NRFX_ASSERT(p_base_addr); + + nrfx_err_t ret_code; + + prs_box_t * p_box = prs_box_get(p_base_addr); + if (p_box != NULL) + { + bool busy = false; + + NRFX_CRITICAL_SECTION_ENTER(); + if (p_box->acquired) + { + busy = true; + } + else + { + p_box->handler = irq_handler; + p_box->acquired = true; + } + NRFX_CRITICAL_SECTION_EXIT(); + + if (busy) + { + ret_code = NRFX_ERROR_BUSY; + LOG_FUNCTION_EXIT(WARNING, ret_code); + return ret_code; + } + } + + ret_code = NRFX_SUCCESS; + LOG_FUNCTION_EXIT(INFO, ret_code); + return ret_code; +} + +void nrfx_prs_release(void const * p_base_addr) +{ + NRFX_ASSERT(p_base_addr); + + prs_box_t * p_box = prs_box_get(p_base_addr); + if (p_box != NULL) + { + p_box->handler = NULL; + p_box->acquired = false; + } +} + + +#endif // NRFX_CHECK(NRFX_PRS_ENABLED) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/prs/nrfx_prs.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/prs/nrfx_prs.h new file mode 100644 index 0000000..f585fa1 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/modules/nrfx/drivers/src/prs/nrfx_prs.h @@ -0,0 +1,140 @@ +/** + * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef NRFX_PRS_H__ +#define NRFX_PRS_H__ + +#include <nrfx.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup nrfx_prs Peripheral Resource Sharing (PRS) + * @{ + * @ingroup nrfx + * + * @brief Peripheral Resource Sharing interface (PRS). + */ + +#if defined(NRF51) + // SPI0, TWI0 + #define NRFX_PRS_BOX_0_ADDR NRF_SPI0 + // SPI1, SPIS1, TWI1 + #define NRFX_PRS_BOX_1_ADDR NRF_SPI1 +#elif defined(NRF52810_XXAA) + // TWIM0, TWIS0 + #define NRFX_PRS_BOX_0_ADDR NRF_TWIM0 + // SPIM0, SPIS0 + #define NRFX_PRS_BOX_1_ADDR NRF_SPIM0 +#elif defined(NRF52832_XXAA) || defined (NRF52832_XXAB) + // SPIM0, SPIS0, TWIM0, TWIS0, SPI0, TWI0 + #define NRFX_PRS_BOX_0_ADDR NRF_SPIM0 + // SPIM1, SPIS1, TWIM1, TWIS1, SPI1, TWI1 + #define NRFX_PRS_BOX_1_ADDR NRF_SPIM1 + // SPIM2, SPIS2, SPI2 + #define NRFX_PRS_BOX_2_ADDR NRF_SPIM2 + // COMP, LPCOMP + #define NRFX_PRS_BOX_3_ADDR NRF_COMP + // UARTE0, UART0 + #define NRFX_PRS_BOX_4_ADDR NRF_UARTE0 +#elif defined(NRF52840_XXAA) + // SPIM0, SPIS0, TWIM0, TWIS0, SPI0, TWI0 + #define NRFX_PRS_BOX_0_ADDR NRF_SPIM0 + // SPIM1, SPIS1, TWIM1, TWIS1, SPI1, TWI1 + #define NRFX_PRS_BOX_1_ADDR NRF_SPIM1 + // SPIM2, SPIS2, SPI2 + #define NRFX_PRS_BOX_2_ADDR NRF_SPIM2 + // COMP, LPCOMP + #define NRFX_PRS_BOX_3_ADDR NRF_COMP + // UARTE0, UART0 + #define NRFX_PRS_BOX_4_ADDR NRF_UARTE0 +#else + #error "Unknown device." +#endif + +/** + * @brief Function for acquiring shared peripheral resources associated with + * the specified peripheral. + * + * Certain resources and registers are shared among peripherals that have + * the same ID (for example: SPI0, SPIM0, SPIS0, TWI0, TWIM0, and TWIS0 in + * nRF52832). Only one of them can be utilized at a given time. This function + * reserves proper resources to be used by the specified peripheral. + * If NRFX_PRS_ENABLED is set to a non-zero value, IRQ handlers for peripherals + * that are sharing resources with others are implemented by the @ref nrfx_prs + * module instead of individual drivers. The drivers must then specify their + * interrupt handling routines and register them by using this function. + * + * @param[in] p_base_addr Requested peripheral base pointer. + * @param[in] irq_handler Interrupt handler to register. + * + * @retval NRFX_SUCCESS If resources were acquired successfully or the + * specified peripheral is not handled by the PRS + * subsystem and there is no need to acquire resources + * for it. + * @retval NRFX_ERROR_BUSY If resources were already acquired. + */ +nrfx_err_t nrfx_prs_acquire(void const * p_base_addr, + nrfx_irq_handler_t irq_handler); + +/** + * @brief Function for releasing shared resources reserved previously by + * @ref nrfx_prs_acquire() for the specified peripheral. + * + * @param[in] p_base_addr Released peripheral base pointer. + */ +void nrfx_prs_release(void const * p_base_addr); + + +void nrfx_prs_box_0_irq_handler(void); +void nrfx_prs_box_1_irq_handler(void); +void nrfx_prs_box_2_irq_handler(void); +void nrfx_prs_box_3_irq_handler(void); +void nrfx_prs_box_4_irq_handler(void); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif // NRFX_PRS_H__ |