프로젝트 정리: 미사용 드라이버 삭제

This commit is contained in:
2026-04-15 11:49:02 +09:00
parent edf656ce10
commit 82d3787b8a
59 changed files with 0 additions and 22169 deletions

View File

@@ -1,340 +0,0 @@
/**
* Copyright (c) 2015 - 2021, 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)
{
NRFX_IRQ_DISABLE(ADC_IRQn);
nrf_adc_int_disable(NRF_ADC_INT_END_MASK);
nrf_adc_task_trigger(NRF_ADC_TASK_STOP);
// Disable all channels. This must be done after the interrupt is disabled
// because adc_sample_process() dereferences this pointer when it needs to
// switch back to the first channel in the list (when the number of samples
// to read is bigger than the number of enabled channels).
m_cb.p_head = NULL;
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_all_channels_disable(void)
{
NRFX_ASSERT(!nrfx_adc_is_busy());
m_cb.p_head = NULL;
}
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)
{
// Make sure the list of channels has not been somehow removed
// (it is when all channels are disabled).
NRFX_ASSERT(m_cb.p_head);
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)

View File

@@ -1,212 +0,0 @@
/**
* Copyright (c) 2015 - 2021, 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_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);
nrf_comp_enable();
nrf_comp_task_trigger(NRF_COMP_TASK_STOP);
// 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);
NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(NRF_COMP), p_config->interrupt_priority);
NRFX_IRQ_ENABLE(nrfx_get_irq_number(NRF_COMP));
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(nrfx_get_irq_number(NRF_COMP));
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)

View File

@@ -1,319 +0,0 @@
/**
* Copyright (c) 2018 - 2021, 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_DPPI_ENABLED)
#include <nrfx_dppi.h>
#define NRFX_LOG_MODULE DPPI
#include <nrfx_log.h>
#if !defined(NRFX_DPPI_CHANNELS_USED)
// Default mask of DPPI channels reserved for other modules.
#define NRFX_DPPI_CHANNELS_USED 0x00000000uL
#endif
#if !defined(NRFX_DPPI_GROUPS_USED)
// Default mask of DPPI groups reserved for other modules.
#define NRFX_DPPI_GROUPS_USED 0x00000000uL
#endif
#define DPPI_AVAILABLE_CHANNELS_MASK \
(((1UL << DPPI_CH_NUM) - 1) & (~NRFX_DPPI_CHANNELS_USED))
#define DPPI_AVAILABLE_GROUPS_MASK \
(((1UL << DPPI_GROUP_NUM) - 1) & (~NRFX_DPPI_GROUPS_USED))
/** @brief Set bit at given position. */
#define DPPI_BIT_SET(pos) (1uL << (pos))
static uint32_t m_allocated_channels;
static uint8_t m_allocated_groups;
__STATIC_INLINE bool channel_is_allocated(uint8_t channel)
{
return ((m_allocated_channels & DPPI_BIT_SET(channel)) != 0);
}
__STATIC_INLINE bool group_is_allocated(nrf_dppi_channel_group_t group)
{
return ((m_allocated_groups & DPPI_BIT_SET(group)) != 0);
}
void nrfx_dppi_free(void)
{
uint32_t mask = m_allocated_groups;
nrf_dppi_channel_group_t group = NRF_DPPI_CHANNEL_GROUP0;
// Disable all channels
nrf_dppi_channels_disable(NRF_DPPIC, m_allocated_channels);
// Clear all groups configurations
while (mask)
{
if (mask & DPPI_BIT_SET(group))
{
nrf_dppi_group_clear(NRF_DPPIC, group);
mask &= ~DPPI_BIT_SET(group);
}
group++;
}
// Clear all allocated channels.
m_allocated_channels = 0;
// Clear all allocated groups.
m_allocated_groups = 0;
}
nrfx_err_t nrfx_dppi_channel_alloc(uint8_t * p_channel)
{
nrfx_err_t err_code;
// Get mask of available DPPI channels
uint32_t remaining_channels = DPPI_AVAILABLE_CHANNELS_MASK & ~(m_allocated_channels);
uint8_t channel = 0;
if (!remaining_channels)
{
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;
}
// Find first free channel
while (!(remaining_channels & DPPI_BIT_SET(channel)))
{
channel++;
}
m_allocated_channels |= DPPI_BIT_SET(channel);
*p_channel = channel;
err_code = NRFX_SUCCESS;
NRFX_LOG_INFO("Allocated channel: %d.", channel);
return err_code;
}
nrfx_err_t nrfx_dppi_channel_free(uint8_t channel)
{
nrfx_err_t err_code = NRFX_SUCCESS;
if (!channel_is_allocated(channel))
{
err_code = NRFX_ERROR_INVALID_PARAM;
}
else
{
// First disable this channel
nrf_dppi_channels_disable(NRF_DPPIC, DPPI_BIT_SET(channel));
// Clear channel allocated indication.
m_allocated_channels &= ~DPPI_BIT_SET(channel);
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_dppi_channel_enable(uint8_t channel)
{
nrfx_err_t err_code = NRFX_SUCCESS;
if (!channel_is_allocated(channel))
{
err_code = NRFX_ERROR_INVALID_PARAM;
}
else
{
nrf_dppi_channels_enable(NRF_DPPIC, DPPI_BIT_SET(channel));
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_dppi_channel_disable(uint8_t channel)
{
nrfx_err_t err_code = NRFX_SUCCESS;
if (!channel_is_allocated(channel))
{
err_code = NRFX_ERROR_INVALID_PARAM;
}
else
{
nrf_dppi_channels_disable(NRF_DPPIC, DPPI_BIT_SET(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_dppi_group_alloc(nrf_dppi_channel_group_t * p_group)
{
nrfx_err_t err_code;
// Get mask of available DPPI groups
uint32_t remaining_groups = DPPI_AVAILABLE_GROUPS_MASK & ~(m_allocated_groups);
nrf_dppi_channel_group_t group = NRF_DPPI_CHANNEL_GROUP0;
if (!remaining_groups)
{
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;
}
// Find first free group
while (!(remaining_groups & DPPI_BIT_SET(group)))
{
group++;
}
m_allocated_groups |= DPPI_BIT_SET(group);
*p_group = group;
err_code = NRFX_SUCCESS;
NRFX_LOG_INFO("Allocated channel: %d.", group);
return err_code;
}
nrfx_err_t nrfx_dppi_group_free(nrf_dppi_channel_group_t group)
{
nrfx_err_t err_code = NRFX_SUCCESS;
if (!group_is_allocated(group))
{
err_code = NRFX_ERROR_INVALID_PARAM;
}
else
{
nrf_dppi_group_disable(NRF_DPPIC, group);
// Set bit value to zero at position corresponding to the group number.
m_allocated_groups &= ~DPPI_BIT_SET(group);
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_dppi_channel_include_in_group(uint8_t channel,
nrf_dppi_channel_group_t group)
{
nrfx_err_t err_code = NRFX_SUCCESS;
if (!group_is_allocated(group) || !channel_is_allocated(channel))
{
err_code = NRFX_ERROR_INVALID_PARAM;
}
else
{
nrf_dppi_channels_include_in_group(NRF_DPPIC, DPPI_BIT_SET(channel), group);
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_dppi_channel_remove_from_group(uint8_t channel,
nrf_dppi_channel_group_t group)
{
nrfx_err_t err_code = NRFX_SUCCESS;
if (!group_is_allocated(group) || !channel_is_allocated(channel))
{
err_code = NRFX_ERROR_INVALID_PARAM;
}
else
{
nrf_dppi_channels_remove_from_group(NRF_DPPIC, DPPI_BIT_SET(channel), group);
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_dppi_group_clear(nrf_dppi_channel_group_t group)
{
nrfx_err_t err_code = NRFX_SUCCESS;
if (!group_is_allocated(group))
{
err_code = NRFX_ERROR_INVALID_PARAM;
}
else
{
nrf_dppi_channels_remove_from_group(NRF_DPPIC, DPPI_AVAILABLE_CHANNELS_MASK, group);
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_dppi_group_enable(nrf_dppi_channel_group_t group)
{
nrfx_err_t err_code = NRFX_SUCCESS;
if (!group_is_allocated(group))
{
err_code = NRFX_ERROR_INVALID_PARAM;
}
else
{
nrf_dppi_group_enable(NRF_DPPIC, group);
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_dppi_group_disable(nrf_dppi_channel_group_t group)
{
nrfx_err_t err_code = NRFX_SUCCESS;
if (!group_is_allocated(group))
{
err_code = NRFX_ERROR_INVALID_PARAM;
}
else
{
nrf_dppi_group_disable(NRF_DPPIC, group);
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
#endif // NRFX_CHECK(NRFX_DPPI_ENABLED)

View File

@@ -1,445 +0,0 @@
/**
* Copyright (c) 2015 - 2021, 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")))
#if !defined(USE_WORKAROUND_FOR_I2S_STOP_ANOMALY) && \
(defined(NRF52832_XXAA) || defined(NRF52832_XXAB) || defined(NRF52840_XXAA) || \
defined(NRF9160_XXAA))
// Enable workaround for nRF52832 and nRF52840 anomaly 194 / nrf9160 anomaly 1
// (STOP task does not switch off all resources).
#define USE_WORKAROUND_FOR_I2S_STOP_ANOMALY 1
#endif
// 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((p_initial_buffers->p_rx_buffer == NULL) ||
(nrfx_is_in_ram(p_initial_buffers->p_rx_buffer) &&
nrfx_is_word_aligned(p_initial_buffers->p_rx_buffer)));
NRFX_ASSERT((p_initial_buffers->p_tx_buffer == NULL) ||
(nrfx_is_in_ram(p_initial_buffers->p_tx_buffer) &&
nrfx_is_word_aligned(p_initial_buffers->p_tx_buffer)));
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_ASSERT((p_buffers->p_rx_buffer == NULL) ||
(nrfx_is_in_ram(p_buffers->p_rx_buffer) &&
nrfx_is_word_aligned(p_buffers->p_rx_buffer)));
NRFX_ASSERT((p_buffers->p_tx_buffer == NULL) ||
(nrfx_is_in_ram(p_buffers->p_tx_buffer) &&
nrfx_is_word_aligned(p_buffers->p_tx_buffer)));
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);
#if NRFX_CHECK(USE_WORKAROUND_FOR_I2S_STOP_ANOMALY)
*((volatile uint32_t *)(((uint32_t)NRF_I2S) + 0x38)) = 1;
*((volatile uint32_t *)(((uint32_t)NRF_I2S) + 0x3C)) = 1;
#endif
}
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)

View File

@@ -1,174 +0,0 @@
/**
* Copyright (c) 2015 - 2021, 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)

View File

@@ -1,867 +0,0 @@
/**
* Copyright (c) 2018 - 2021, 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_NFCT_ENABLED)
#include <nrfx_nfct.h>
#define NRFX_LOG_MODULE NFCT
#include <nrfx_log.h>
#if defined(NRF52832_XXAA) || defined(NRF52832_XXAB) || \
defined(NRF52833_XXAA) || defined(NRF52840_XXAA)
#define USE_TIMER_WORKAROUND
#endif
#if defined(USE_TIMER_WORKAROUND)
#include <nrfx_timer.h>
typedef struct
{
const nrfx_timer_t timer; /**< Timer instance that supports the correct NFC field detection. */
#if defined(NRF52833_XXAA) || defined(NRF52840_XXAA)
bool fieldevents_filter_active; /**< Flag that indicates that the field events are ignored. */
bool is_hfclk_on; /**< HFCLK has started - one of the NFC activation conditions. */
bool is_delayed; /**< Required time delay has passed - one of the NFC activation conditions. */
#else
uint32_t field_state_cnt; /**< Counter of the FIELDLOST events. */
#endif // defined(NRF52833_XXAA) || defined(NRF52840_XXAA)
} nrfx_nfct_timer_workaround_t;
#if defined(NRF52833_XXAA) || defined(NRF52840_XXAA)
#define NRFX_NFCT_ACTIVATE_DELAY 1000 /**< Minimal delay in us between NFC field detection and activation of NFCT. */
#define NRFX_NFCT_TIMER_PERIOD NRFX_NFCT_ACTIVATE_DELAY
#else
#define NRFX_NFCT_FIELDLOST_THR 7
#define NRFX_NFCT_FIELD_TIMER_PERIOD 100 /**< Field polling period in us. */
#define NRFX_NFCT_TIMER_PERIOD NRFX_NFCT_FIELD_TIMER_PERIOD
#endif // defined(NRF52833_XXAA) || defined(NRF52840_XXAA)
#define NRFX_NFCT_TIMER_INSTANCE 4 /**< Timer instance used for various workarounds for the NFCT HW issues.*/
static nrfx_nfct_timer_workaround_t m_timer_workaround =
{
.timer = NRFX_TIMER_INSTANCE(NRFX_NFCT_TIMER_INSTANCE),
};
#endif // defined(USE_TIMER_WORKAROUND)
#define NRFX_NFCT_FWT_MAX_DIFF 1u /**< The maximal difference between the requested FWT and HW-limited FWT settings.*/
#define NFCT_FRAMEDELAYMAX_DEFAULT (0x00001000UL) /**< Default value of the FRAMEDELAYMAX. */
/* Mask of all possible interrupts that are relevant for data reception. */
#define NRFX_NFCT_RX_INT_MASK (NRF_NFCT_INT_RXFRAMESTART_MASK | \
NRF_NFCT_INT_RXFRAMEEND_MASK | \
NRF_NFCT_INT_RXERROR_MASK)
/* Mask of all possible interrupts that are relevant for data transmission. */
#define NRFX_NFCT_TX_INT_MASK (NRF_NFCT_INT_TXFRAMESTART_MASK | \
NRF_NFCT_INT_TXFRAMEEND_MASK)
/* Mask of all possible errors from the @ref NRF_NFCT_EVENT_RXERROR event. */
#define NRFX_NFCT_FRAME_STATUS_RX_ALL_MASK (NRF_NFCT_RX_FRAME_STATUS_CRC_MASK | \
NRF_NFCT_RX_FRAME_STATUS_PARITY_MASK | \
NRF_NFCT_RX_FRAME_STATUS_OVERRUN_MASK)
/* Mask of all possible errors from the @ref NRF_NFCT_EVENT_ERROR event. */
#if defined (NRF52832_XXAA) || defined(NRF52832_XXAB)
#define NRFX_NFCT_ERROR_STATUS_ALL_MASK (NRF_NFCT_ERROR_FRAMEDELAYTIMEOUT_MASK | \
NRF_NFCT_ERROR_NFCFIELDTOOSTRONG_MASK | \
NRF_NFCT_ERROR_NFCFIELDTOOWEAK_MASK)
#else
#define NRFX_NFCT_ERROR_STATUS_ALL_MASK (NRF_NFCT_ERROR_FRAMEDELAYTIMEOUT_MASK)
#endif
/* Macros for conversion of bits to bytes. */
#define NRFX_NFCT_BYTES_TO_BITS(_bytes) ((_bytes) << 3)
#define NRFX_NFCT_BITS_TO_BYTES(_bits) ((_bits) >> 3)
/* Macro for checking whether the NFCT interrupt is active. */
#define NRFX_NFCT_EVT_ACTIVE(_name) (nrf_nfct_event_check(NRFX_CONCAT_2(NRF_NFCT_EVENT_, _name)) && \
nrf_nfct_int_enable_check(NRFX_CONCAT_3(NRF_NFCT_INT_, _name, _MASK)))
/* Macro for callback execution. */
#define NRFX_NFCT_CB_HANDLE(_cb, _evt) \
if (_cb != NULL) \
{ \
_cb(&_evt); \
}
typedef enum
{
NRFX_NFC_FIELD_STATE_NONE, /**< Initial value that indicates no NFCT field events. */
NRFX_NFC_FIELD_STATE_OFF, /**< The NFCT FIELDLOST event has been set. */
NRFX_NFC_FIELD_STATE_ON, /**< The NFCT FIELDDETECTED event has been set. */
NRFX_NFC_FIELD_STATE_UNKNOWN /**< Both NFCT field events have been set - ambiguous state. */
} nrfx_nfct_field_state_t;
/**@brief NFCT control block. */
typedef struct
{
nrfx_nfct_config_t config;
nrfx_drv_state_t state;
volatile bool field_on;
uint32_t frame_delay_max;
} nrfx_nfct_control_block_t;
static nrfx_nfct_control_block_t m_nfct_cb;
/**
* @brief Common part of the setup used for the NFCT initialization and reinitialization.
*/
static void nrfx_nfct_hw_init_setup(void)
{
// Use Window Grid frame delay mode.
nrf_nfct_frame_delay_mode_set(NRF_NFCT_FRAME_DELAY_MODE_WINDOWGRID);
/* Begin: Workaround for anomaly 25 */
/* Workaround for wrong SENSRES values require using SDD00001, but here SDD00100 is used
because it is required to operate with Windows Phone */
nrf_nfct_sensres_bit_frame_sdd_set(NRF_NFCT_SENSRES_BIT_FRAME_SDD_00100);
/* End: Workaround for anomaly 25 */
}
static void nrfx_nfct_frame_delay_max_set(bool default_delay)
{
if (default_delay)
{
nrf_nfct_frame_delay_max_set(NFCT_FRAMEDELAYMAX_DEFAULT);
}
else
{
nrf_nfct_frame_delay_max_set(m_nfct_cb.frame_delay_max);
}
}
/**@brief Function for evaluating and handling the NFC field events.
*
* @param[in] field_state Current field state.
*/
static void nrfx_nfct_field_event_handler(volatile nrfx_nfct_field_state_t field_state)
{
nrfx_nfct_evt_t nfct_evt;
#if defined(NRF52833_XXAA) || defined(NRF52840_XXAA)
if(m_timer_workaround.fieldevents_filter_active)
{
return;
}
#endif // defined(NRF52833_XXAA) || defined(NRF52840_XXAA)
if (field_state == NRFX_NFC_FIELD_STATE_UNKNOWN)
{
/* Probe NFC field */
field_state = (nrfx_nfct_field_check()) ? NRFX_NFC_FIELD_STATE_ON : NRFX_NFC_FIELD_STATE_OFF;
}
/* Field event service. Only take action on field transition -
* based on the value of m_nfct_cb.field_on
*/
switch (field_state)
{
case NRFX_NFC_FIELD_STATE_ON:
if (!m_nfct_cb.field_on)
{
#if defined(NRF52833_XXAA) || defined(NRF52840_XXAA)
/* Begin: Workaround for anomaly 190 */
m_timer_workaround.is_hfclk_on = false;
m_timer_workaround.is_delayed = false;
m_timer_workaround.fieldevents_filter_active = true;
nrfx_timer_clear(&m_timer_workaround.timer);
nrfx_timer_enable(&m_timer_workaround.timer);
/* End: Workaround for anomaly 190 */
#elif defined(NRF52832_XXAA) || defined(NRF52832_XXAB)
nrfx_timer_clear(&m_timer_workaround.timer);
nrfx_timer_enable(&m_timer_workaround.timer);
m_timer_workaround.field_state_cnt = 0;
#endif // defined(NRF52833_XXAA) || defined(NRF52840_XXAA)
m_nfct_cb.field_on = true;
nfct_evt.evt_id = NRFX_NFCT_EVT_FIELD_DETECTED;
NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt);
}
break;
case NRFX_NFC_FIELD_STATE_OFF:
if (m_nfct_cb.field_on)
{
nrf_nfct_task_trigger(NRF_NFCT_TASK_SENSE);
nrf_nfct_int_disable(NRFX_NFCT_RX_INT_MASK | NRFX_NFCT_TX_INT_MASK);
m_nfct_cb.field_on = false;
nfct_evt.evt_id = NRFX_NFCT_EVT_FIELD_LOST;
/* Begin: Workaround for anomaly 218 */
nrfx_nfct_frame_delay_max_set(true);
/* End: Workaround for anomaly 218 */
NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt);
}
break;
default:
/* No implementation required */
break;
}
}
#if defined(USE_TIMER_WORKAROUND)
#if defined(NRF52833_XXAA) || defined(NRF52840_XXAA)
static void nrfx_nfct_activate_check(void)
{
static bool is_field_validation_pending = false;
if (is_field_validation_pending)
{
is_field_validation_pending = false;
m_timer_workaround.fieldevents_filter_active = false;
// Check the field status and take action if field is lost.
nrfx_nfct_field_event_handler(NRFX_NFC_FIELD_STATE_UNKNOWN);
return;
}
if ((m_timer_workaround.is_hfclk_on) && (m_timer_workaround.is_delayed))
{
nrf_nfct_task_trigger(NRF_NFCT_TASK_ACTIVATE);
is_field_validation_pending = true;
// Start the timer second time to validate whether the tag has locked to the field.
nrfx_timer_clear(&m_timer_workaround.timer);
nrfx_timer_enable(&m_timer_workaround.timer);
}
}
#endif // defined(NRF52833_XXAA) || defined(NRF52840_XXAA)
#if defined(NRF52832_XXAA) || defined(NRF52832_XXAB)
/* Begin: Workaround for anomaly 116 */
static inline void nrfx_nfct_reset(void)
{
uint32_t fdm;
uint32_t int_enabled;
uint8_t nfcid1[NRF_NFCT_SENSRES_NFCID1_SIZE_TRIPLE];
nrf_nfct_sensres_nfcid1_size_t nfcid1_size;
nrf_nfct_selres_protocol_t protocol;
// Save parameter settings before the reset of the NFCT peripheral.
fdm = nrf_nfct_frame_delay_max_get();
nfcid1_size = nrf_nfct_nfcid1_get(nfcid1);
protocol = nrf_nfct_selsres_protocol_get();
int_enabled = nrf_nfct_int_enable_get();
// Reset the NFCT peripheral.
*(volatile uint32_t *)0x40005FFC = 0;
*(volatile uint32_t *)0x40005FFC;
*(volatile uint32_t *)0x40005FFC = 1;
// Restore parameter settings after the reset of the NFCT peripheral.
nrf_nfct_frame_delay_max_set(fdm);
nrf_nfct_nfcid1_set(nfcid1, nfcid1_size);
nrf_nfct_selres_protocol_set(protocol);
// Restore general HW configuration.
nrfx_nfct_hw_init_setup();
// Restore interrupts.
nrf_nfct_int_enable(int_enabled);
// Disable interrupts associated with data exchange.
nrf_nfct_int_disable(NRFX_NFCT_RX_INT_MASK | NRFX_NFCT_TX_INT_MASK);
NRFX_LOG_INFO("Reinitialize");
}
/* End: Workaround for anomaly 116 */
static void nrfx_nfct_field_poll(void)
{
if (!nrfx_nfct_field_check())
{
if (++m_timer_workaround.field_state_cnt > NRFX_NFCT_FIELDLOST_THR)
{
nrfx_nfct_evt_t nfct_evt =
{
.evt_id = NRFX_NFCT_EVT_FIELD_LOST,
};
nrfx_timer_disable(&m_timer_workaround.timer);
m_nfct_cb.field_on = false;
/* Begin: Workaround for anomaly 218 */
nrfx_nfct_frame_delay_max_set(true);
/* End: Workaround for anomaly 218 */
/* Begin: Workaround for anomaly 116 */
/* resume the NFCT to initialized state */
nrfx_nfct_reset();
/* End: Workaround for anomaly 116 */
NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt);
}
return;
}
m_timer_workaround.field_state_cnt = 0;
}
#endif // defined(NRF52832_XXAA) || defined(NRF52832_XXAB)
static void nrfx_nfct_field_timer_handler(nrf_timer_event_t event_type, void * p_context)
{
(void)p_context;
if (event_type != NRF_TIMER_EVENT_COMPARE0)
{
return;
}
#if defined(NRF52833_XXAA) || defined(NRF52840_XXAA)
m_timer_workaround.is_delayed = true;
nrfx_timer_disable(&m_timer_workaround.timer);
nrfx_nfct_activate_check();
#else
nrfx_nfct_field_poll();
#endif // defined(NRF52833_XXAA) || defined(NRF52840_XXAA)
}
static inline nrfx_err_t nrfx_nfct_field_timer_config(void)
{
nrfx_err_t err_code;
nrfx_timer_config_t timer_cfg =
{
.frequency = NRF_TIMER_FREQ_1MHz,
.mode = NRF_TIMER_MODE_TIMER,
.bit_width = NRF_TIMER_BIT_WIDTH_16,
.interrupt_priority = NRFX_NFCT_CONFIG_IRQ_PRIORITY
};
err_code = nrfx_timer_init(&m_timer_workaround.timer, &timer_cfg, nrfx_nfct_field_timer_handler);
if (err_code != NRFX_SUCCESS)
{
return err_code;
}
nrfx_timer_extended_compare(&m_timer_workaround.timer,
NRF_TIMER_CC_CHANNEL0,
nrfx_timer_us_to_ticks(&m_timer_workaround.timer, NRFX_NFCT_TIMER_PERIOD),
NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
true);
return err_code;
}
#endif // defined(USE_TIMER_WORKAROUND)
static inline nrf_nfct_sensres_nfcid1_size_t nrf_nfct_nfcid1_size_to_sensres_size(uint8_t nfcid1_size)
{
switch (nfcid1_size)
{
case NRFX_NFCT_NFCID1_SINGLE_SIZE:
return NRF_NFCT_SENSRES_NFCID1_SIZE_SINGLE;
case NRFX_NFCT_NFCID1_DOUBLE_SIZE:
return NRF_NFCT_SENSRES_NFCID1_SIZE_DOUBLE;
case NRFX_NFCT_NFCID1_TRIPLE_SIZE:
return NRF_NFCT_SENSRES_NFCID1_SIZE_TRIPLE;
default:
return NRF_NFCT_SENSRES_NFCID1_SIZE_DOUBLE;
}
}
static inline void nrfx_nfct_rxtx_int_enable(uint32_t rxtx_int_mask)
{
nrf_nfct_int_enable(rxtx_int_mask & m_nfct_cb.config.rxtx_int_mask);
}
nrfx_err_t nrfx_nfct_init(nrfx_nfct_config_t const * p_config)
{
NRFX_ASSERT(p_config);
nrfx_err_t err_code = NRFX_SUCCESS;
if (m_nfct_cb.state != NRFX_DRV_STATE_UNINITIALIZED)
{
return NRFX_ERROR_INVALID_STATE;
}
m_nfct_cb.config = *p_config;
nrfx_nfct_hw_init_setup();
NRFX_IRQ_PENDING_CLEAR(NFCT_IRQn);
NRFX_IRQ_PRIORITY_SET(NFCT_IRQn, NRFX_NFCT_CONFIG_IRQ_PRIORITY);
NRFX_IRQ_ENABLE(NFCT_IRQn);
#if defined(USE_TIMER_WORKAROUND)
/* Initialize Timer module as the workaround for NFCT HW issues. */
err_code = nrfx_nfct_field_timer_config();
#endif // defined(USE_TIMER_WORKAROUND)
if (err_code == NRFX_SUCCESS)
{
uint8_t default_nfcid1[NRFX_NFCT_NFCID1_DEFAULT_LEN];
err_code = nrfx_nfct_nfcid1_default_bytes_get(default_nfcid1, sizeof(default_nfcid1));
NRFX_ASSERT(err_code == NRFX_SUCCESS);
nrf_nfct_nfcid1_set(default_nfcid1, NRF_NFCT_SENSRES_NFCID1_SIZE_DEFAULT);
}
else
{
return err_code;
}
m_nfct_cb.state = NRFX_DRV_STATE_INITIALIZED;
m_nfct_cb.frame_delay_max = NFCT_FRAMEDELAYMAX_DEFAULT;
NRFX_LOG_INFO("Initialized");
return err_code;
}
void nrfx_nfct_uninit(void)
{
nrfx_nfct_disable();
NRFX_IRQ_DISABLE(NFCT_IRQn);
NRFX_IRQ_PENDING_CLEAR(NFCT_IRQn);
#if defined(USE_TIMER_WORKAROUND)
/* De-initialize Timer module as the workaround for NFCT HW issues. */
nrfx_timer_uninit(&m_timer_workaround.timer);
#endif // defined(USE_TIMER_WORKAROUND)
m_nfct_cb.state = NRFX_DRV_STATE_UNINITIALIZED;
}
void nrfx_nfct_enable(void)
{
nrf_nfct_error_status_clear(NRFX_NFCT_ERROR_STATUS_ALL_MASK);
nrf_nfct_task_trigger(NRF_NFCT_TASK_SENSE);
nrf_nfct_int_enable(NRF_NFCT_INT_FIELDDETECTED_MASK | NRF_NFCT_INT_ERROR_MASK |
NRF_NFCT_INT_SELECTED_MASK);
#if !defined(NRF52832_XXAA) && !defined(NRF52832_XXAB)
nrf_nfct_int_enable(NRF_NFCT_INT_FIELDLOST_MASK);
#endif // !defined(NRF52832_XXAA) && !defined(NRF52832_XXAB)
NRFX_LOG_INFO("Start");
}
void nrfx_nfct_disable(void)
{
nrf_nfct_int_disable(NRF_NFCT_DISABLE_ALL_INT);
nrf_nfct_task_trigger(NRF_NFCT_TASK_DISABLE);
NRFX_LOG_INFO("Stop");
}
bool nrfx_nfct_field_check(void)
{
uint32_t const field_state = nrf_nfct_field_status_get();
if (((field_state & NRF_NFCT_FIELD_STATE_PRESENT_MASK) == 0) &&
((field_state & NRF_NFCT_FIELD_STATE_LOCK_MASK) == 0))
{
/* Field is not active */
return false;
}
return true;
}
void nrfx_nfct_rx(nrfx_nfct_data_desc_t const * p_tx_data)
{
NRFX_ASSERT(p_tx_data);
nrf_nfct_rxtx_buffer_set((uint8_t *) p_tx_data->p_data, p_tx_data->data_size);
nrfx_nfct_rxtx_int_enable(NRFX_NFCT_RX_INT_MASK);
nrf_nfct_task_trigger(NRF_NFCT_TASK_ENABLERXDATA);
}
nrfx_err_t nrfx_nfct_tx(nrfx_nfct_data_desc_t const * p_tx_data,
nrf_nfct_frame_delay_mode_t delay_mode)
{
NRFX_ASSERT(p_tx_data);
NRFX_ASSERT(p_tx_data->p_data);
nrfx_err_t err = NRFX_SUCCESS;
if (p_tx_data->data_size == 0)
{
return NRFX_ERROR_INVALID_LENGTH;
}
NRFX_CRITICAL_SECTION_ENTER();
/* In case when NFC frame transmission has already started, it returns an error. */
if (NRFX_NFCT_EVT_ACTIVE(TXFRAMESTART))
{
err = NRFX_ERROR_BUSY;
}
else
{
/* In case when Tx operation was scheduled with delay, stop scheduled Tx operation. */
*(volatile uint32_t *)0x40005010 = 0x01;
nrf_nfct_rxtx_buffer_set((uint8_t *) p_tx_data->p_data, p_tx_data->data_size);
nrf_nfct_tx_bits_set(NRFX_NFCT_BYTES_TO_BITS(p_tx_data->data_size));
nrf_nfct_frame_delay_mode_set((nrf_nfct_frame_delay_mode_t) delay_mode);
nrfx_nfct_frame_delay_max_set(false);
nrfx_nfct_rxtx_int_enable(NRFX_NFCT_TX_INT_MASK);
nrf_nfct_task_trigger(NRF_NFCT_TASK_STARTTX);
NRFX_LOG_INFO("Tx start");
}
NRFX_CRITICAL_SECTION_EXIT();
return err;
}
void nrfx_nfct_state_force(nrfx_nfct_state_t state)
{
#if defined(NRF52833_XXAA) || defined(NRF52840_XXAA)
if (state == NRFX_NFCT_STATE_ACTIVATED)
{
m_timer_workaround.is_hfclk_on = true;
/* NFCT will be activated based on additional conditions */
nrfx_nfct_activate_check();
return;
}
#endif // defined(NRF52833_XXAA) || defined(NRF52840_XXAA)
nrf_nfct_task_trigger((nrf_nfct_task_t) state);
}
void nrfx_nfct_init_substate_force(nrfx_nfct_active_state_t sub_state)
{
if (sub_state == NRFX_NFCT_ACTIVE_STATE_DEFAULT)
{
#if defined(NRF52832_XXAA) || defined(NRF52832_XXAB)
if (((*(uint32_t volatile *)(0x40005420)) & 0x1UL) == (1UL))
#else
if (nrf_nfct_sleep_state_get() == NRF_NFCT_SLEEP_STATE_SLEEP_A)
#endif //defined(NRF52832_XXAA) || defined(NRF52832_XXAB)
{
// Default state is SLEEP_A
nrf_nfct_task_trigger(NRF_NFCT_TASK_GOSLEEP);
}
else
{
// Default state is IDLE
nrf_nfct_task_trigger(NRF_NFCT_TASK_GOIDLE);
}
}
else
{
nrf_nfct_task_trigger((nrf_nfct_task_t) sub_state);
}
/* Begin: Workaround for anomaly 218 */
nrfx_nfct_frame_delay_max_set(true);
/* End: Workaround for anomaly 218 */
/* Disable TX/RX here (will be enabled at SELECTED) */
nrf_nfct_int_disable(NRFX_NFCT_RX_INT_MASK | NRFX_NFCT_TX_INT_MASK);
}
nrfx_err_t nrfx_nfct_parameter_set(nrfx_nfct_param_t const * p_param)
{
NRFX_ASSERT(p_param);
switch (p_param->id)
{
case NRFX_NFCT_PARAM_ID_FDT:
{
uint32_t delay = p_param->data.fdt;
uint32_t delay_thr = NFCT_FRAMEDELAYMAX_FRAMEDELAYMAX_Msk;
// Delay validation.
if (delay > (delay_thr + NRFX_NFCT_FWT_MAX_DIFF))
{
return NRFX_ERROR_INVALID_PARAM;
}
delay = (delay > delay_thr) ? delay_thr : delay;
m_nfct_cb.frame_delay_max = delay;
break;
}
case NRFX_NFCT_PARAM_ID_SEL_RES:
if (p_param->data.sel_res_protocol > NRF_NFCT_SELRES_PROTOCOL_NFCDEP_T4AT)
{
return NRFX_ERROR_INVALID_PARAM;
}
nrf_nfct_selres_protocol_set((nrf_nfct_selres_protocol_t) p_param->data.sel_res_protocol);
break;
case NRFX_NFCT_PARAM_ID_NFCID1:
{
nrf_nfct_sensres_nfcid1_size_t id_size_mask;
id_size_mask = nrf_nfct_nfcid1_size_to_sensres_size(p_param->data.nfcid1.id_size);
nrf_nfct_nfcid1_set(p_param->data.nfcid1.p_id, id_size_mask);
break;
}
default:
break;
}
return NRFX_SUCCESS;
}
nrfx_err_t nrfx_nfct_nfcid1_default_bytes_get(uint8_t * const p_nfcid1_buff,
uint32_t nfcid1_buff_len)
{
if ((nfcid1_buff_len != NRFX_NFCT_NFCID1_SINGLE_SIZE) &&
(nfcid1_buff_len != NRFX_NFCT_NFCID1_DOUBLE_SIZE) &&
(nfcid1_buff_len != NRFX_NFCT_NFCID1_TRIPLE_SIZE))
{
return NRFX_ERROR_INVALID_LENGTH;
}
uint32_t nfc_tag_header0 = NRF_FICR->NFC.TAGHEADER0;
uint32_t nfc_tag_header1 = NRF_FICR->NFC.TAGHEADER1;
uint32_t nfc_tag_header2 = NRF_FICR->NFC.TAGHEADER2;
p_nfcid1_buff[0] = (uint8_t) (nfc_tag_header0 >> 0);
p_nfcid1_buff[1] = (uint8_t) (nfc_tag_header0 >> 8);
p_nfcid1_buff[2] = (uint8_t) (nfc_tag_header0 >> 16);
p_nfcid1_buff[3] = (uint8_t) (nfc_tag_header1 >> 0);
if (nfcid1_buff_len != NRFX_NFCT_NFCID1_SINGLE_SIZE)
{
p_nfcid1_buff[4] = (uint8_t) (nfc_tag_header1 >> 8);
p_nfcid1_buff[5] = (uint8_t) (nfc_tag_header1 >> 16);
p_nfcid1_buff[6] = (uint8_t) (nfc_tag_header1 >> 24);
if (nfcid1_buff_len == NRFX_NFCT_NFCID1_TRIPLE_SIZE)
{
p_nfcid1_buff[7] = (uint8_t) (nfc_tag_header2 >> 0);
p_nfcid1_buff[8] = (uint8_t) (nfc_tag_header2 >> 8);
p_nfcid1_buff[9] = (uint8_t) (nfc_tag_header2 >> 16);
}
/* Begin: Workaround for anomaly 181. */
/* Workaround for wrong value in NFCID1. Value 0x88 cannot be used as byte 3
of a double-size NFCID1, according to the NFC Forum Digital Protocol specification. */
else if (p_nfcid1_buff[3] == 0x88)
{
p_nfcid1_buff[3] |= 0x11;
}
/* End: Workaround for anomaly 181 */
}
return NRFX_SUCCESS;
}
void nrfx_nfct_autocolres_enable(void)
{
#if defined(NRF52832_XXAA) || defined(NRF52832_XXAB)
(*(uint32_t *)(0x4000559C)) &= (~(0x1UL));
#else
nrf_nfct_autocolres_enable();
#endif //defined(NRF52832_XXAA) || defined(NRF52832_XXAB)
}
void nrfx_nfct_autocolres_disable(void)
{
#if defined(NRF52832_XXAA) || defined(NRF52832_XXAB)
(*(uint32_t *)(0x4000559C)) |= (0x1UL);
#else
nrf_nfct_autocolres_disable();
#endif //defined(NRF52832_XXAA) || defined(NRF52832_XXAB)
}
void nrfx_nfct_irq_handler(void)
{
nrfx_nfct_field_state_t current_field = NRFX_NFC_FIELD_STATE_NONE;
if (NRFX_NFCT_EVT_ACTIVE(FIELDDETECTED))
{
nrf_nfct_event_clear(NRF_NFCT_EVENT_FIELDDETECTED);
current_field = NRFX_NFC_FIELD_STATE_ON;
NRFX_LOG_DEBUG("Field detected");
}
#if !defined(NRF52832_XXAA) && !defined(NRF52832_XXAB)
if (NRFX_NFCT_EVT_ACTIVE(FIELDLOST))
{
nrf_nfct_event_clear(NRF_NFCT_EVENT_FIELDLOST);
current_field = (current_field == NRFX_NFC_FIELD_STATE_NONE) ?
NRFX_NFC_FIELD_STATE_OFF : NRFX_NFC_FIELD_STATE_UNKNOWN;
NRFX_LOG_DEBUG("Field lost");
}
#endif //!defined(NRF52832_XXAA) && !defined(NRF52832_XXAB)
/* Perform actions if any FIELD event is active */
if (current_field != NRFX_NFC_FIELD_STATE_NONE)
{
nrfx_nfct_field_event_handler(current_field);
}
if (NRFX_NFCT_EVT_ACTIVE(RXFRAMEEND))
{
nrf_nfct_event_clear(NRF_NFCT_EVENT_RXFRAMEEND);
nrfx_nfct_evt_t nfct_evt =
{
.evt_id = NRFX_NFCT_EVT_RX_FRAMEEND
};
/* Take into account only the number of whole bytes. */
nfct_evt.params.rx_frameend.rx_status = 0;
nfct_evt.params.rx_frameend.rx_data.p_data = nrf_nfct_rxtx_buffer_get();
nfct_evt.params.rx_frameend.rx_data.data_size = NRFX_NFCT_BITS_TO_BYTES(nrf_nfct_rx_bits_get(true));
if (NRFX_NFCT_EVT_ACTIVE(RXERROR))
{
nfct_evt.params.rx_frameend.rx_status =
(nrf_nfct_rx_frame_status_get() & NRFX_NFCT_FRAME_STATUS_RX_ALL_MASK);
nrf_nfct_event_clear(NRF_NFCT_EVENT_RXERROR);
NRFX_LOG_DEBUG("Rx error (0x%x)", (unsigned int) nfct_evt.params.rx_frameend.rx_status);
/* Clear rx frame status */
nrf_nfct_rx_frame_status_clear(NRFX_NFCT_FRAME_STATUS_RX_ALL_MASK);
}
NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt);
/* Clear TXFRAMESTART EVENT so it can be checked in hal_nfc_send */
nrf_nfct_event_clear(NRF_NFCT_EVENT_TXFRAMESTART);
NRFX_LOG_DEBUG("Rx fend");
}
if (NRFX_NFCT_EVT_ACTIVE(TXFRAMEEND))
{
nrf_nfct_event_clear(NRF_NFCT_EVENT_TXFRAMEEND);
nrfx_nfct_evt_t nfct_evt =
{
.evt_id = NRFX_NFCT_EVT_TX_FRAMEEND
};
/* Disable TX END event to ignore frame transmission other than READ response */
nrf_nfct_int_disable(NRFX_NFCT_TX_INT_MASK);
NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt);
NRFX_LOG_DEBUG("Tx fend");
}
if (NRFX_NFCT_EVT_ACTIVE(SELECTED))
{
nrf_nfct_event_clear(NRF_NFCT_EVENT_SELECTED);
/* Clear also RX END and RXERROR events because SW does not take care of
commands that were received before selecting the tag. */
nrf_nfct_event_clear(NRF_NFCT_EVENT_RXFRAMEEND);
nrf_nfct_event_clear(NRF_NFCT_EVENT_RXERROR);
nrf_nfct_event_clear(NRF_NFCT_EVENT_TXFRAMESTART);
nrf_nfct_event_clear(NRF_NFCT_EVENT_TXFRAMEEND);
/* Begin: Workaround for anomaly 218 */
nrfx_nfct_frame_delay_max_set(false);
/* End: Workaround for anomaly 218 */
/* At this point any previous error status can be ignored. */
nrf_nfct_rx_frame_status_clear(NRFX_NFCT_FRAME_STATUS_RX_ALL_MASK);
nrf_nfct_error_status_clear(NRFX_NFCT_ERROR_STATUS_ALL_MASK);
nrfx_nfct_evt_t nfct_evt =
{
.evt_id = NRFX_NFCT_EVT_SELECTED
};
NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt);
NRFX_LOG_DEBUG("Selected");
}
if (NRFX_NFCT_EVT_ACTIVE(ERROR))
{
uint32_t err_status = nrf_nfct_error_status_get();
nrf_nfct_event_clear(NRF_NFCT_EVENT_ERROR);
nrfx_nfct_evt_t nfct_evt =
{
.evt_id = NRFX_NFCT_EVT_ERROR
};
/* Clear FRAMEDELAYTIMEOUT error (expected HW behaviour) when SLP_REQ command was received. */
if (err_status & NRF_NFCT_ERROR_FRAMEDELAYTIMEOUT_MASK)
{
nrf_nfct_error_status_clear(NRF_NFCT_ERROR_FRAMEDELAYTIMEOUT_MASK);
nfct_evt.params.error.reason = NRFX_NFCT_ERROR_FRAMEDELAYTIMEOUT;
NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt);
}
/* Report any other error. */
err_status &= ~NRF_NFCT_ERROR_FRAMEDELAYTIMEOUT_MASK;
if (err_status)
{
NRFX_LOG_DEBUG("Error (0x%x)", (unsigned int) err_status);
}
/* Clear error status. */
nrf_nfct_error_status_clear(NRFX_NFCT_ERROR_STATUS_ALL_MASK);
}
if (NRFX_NFCT_EVT_ACTIVE(TXFRAMESTART))
{
nrf_nfct_event_clear(NRF_NFCT_EVENT_TXFRAMESTART);
if (m_nfct_cb.config.cb != NULL)
{
nrfx_nfct_evt_t nfct_evt;
nfct_evt.evt_id = NRFX_NFCT_EVT_TX_FRAMESTART;
nfct_evt.params.tx_framestart.tx_data.p_data = nrf_nfct_rxtx_buffer_get();
nfct_evt.params.tx_framestart.tx_data.data_size = NRFX_NFCT_BITS_TO_BYTES(nrf_nfct_tx_bits_get());
m_nfct_cb.config.cb(&nfct_evt);
}
}
}
#endif // NRFX_CHECK(NRFX_NFCT_ENABLED)

View File

@@ -1,370 +0,0 @@
/**
* Copyright (c) 2015 - 2021, 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)

View File

@@ -1,204 +0,0 @@
/**
* Copyright (c) 2015 - 2021, 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->psela, NRF_GPIO_PIN_NOPULL);
nrf_gpio_cfg_input(p_config->pselb, NRF_GPIO_PIN_NOPULL);
if (p_config->pselled != NRF_QDEC_LED_NOT_CONNECTED)
{
nrf_gpio_cfg_input(p_config->pselled, NRF_GPIO_PIN_NOPULL);
nrf_qdec_ledpre_set(p_config->ledpre);
nrf_qdec_ledpol_set(p_config->ledpol);
}
nrf_qdec_pio_assign(p_config->psela, p_config->pselb, p_config->pselled);
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)

View File

@@ -1,464 +0,0 @@
/**
* Copyright (c) 2016 - 2021, 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>
#include <hal/nrf_gpio.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 Macro for initializing a QSPI pin.
*
* QSPI peripheral expects high drive pin strength.
*/
#define QSPI_PIN_INIT(_pin) nrf_gpio_cfg((_pin), \
NRF_GPIO_PIN_DIR_INPUT, \
NRF_GPIO_PIN_INPUT_DISCONNECT, \
NRF_GPIO_PIN_NOPULL, \
NRF_GPIO_PIN_H0H1, \
NRF_GPIO_PIN_NOSENSE)
/** @brief Control block - driver instance local data. */
typedef struct
{
nrfx_qspi_handler_t handler; /**< Handler. */
nrfx_drv_state_t state; /**< Driver state. */
volatile bool is_busy; /**< Flag indicating that an operation is currently being performed. */
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.is_busy)
{
return NRFX_ERROR_BUSY;
}
nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
if (m_cb.handler)
{
m_cb.is_busy = 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;
}
QSPI_PIN_INIT(p_config->sck_pin);
QSPI_PIN_INIT(p_config->csn_pin);
QSPI_PIN_INIT(p_config->io0_pin);
QSPI_PIN_INIT(p_config->io1_pin);
if (p_config->io2_pin != NRF_QSPI_PIN_NOT_CONNECTED)
{
QSPI_PIN_INIT(p_config->io2_pin);
}
if (p_config->io3_pin != NRF_QSPI_PIN_NOT_CONNECTED)
{
QSPI_PIN_INIT(p_config->io3_pin);
}
nrf_qspi_pins_set(NRF_QSPI, p_config);
return true;
}
static void qspi_pins_deconfigure(void)
{
nrf_qspi_pins_t pins;
nrf_qspi_pins_get(NRF_QSPI, &pins);
nrf_gpio_cfg_default(pins.sck_pin);
nrf_gpio_cfg_default(pins.csn_pin);
nrf_gpio_cfg_default(pins.io0_pin);
nrf_gpio_cfg_default(pins.io1_pin);
if (pins.io2_pin != NRF_QSPI_PIN_NOT_CONNECTED)
{
nrf_gpio_cfg_default(pins.io2_pin);
}
if (pins.io3_pin != NRF_QSPI_PIN_NOT_CONNECTED)
{
nrf_gpio_cfg_default(pins.io3_pin);
}
}
static nrfx_err_t qspi_ready_wait(void)
{
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_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.is_busy = 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
return qspi_ready_wait();
}
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.is_busy)
{
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);
if (qspi_ready_wait() == NRFX_ERROR_TIMEOUT)
{
// 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);
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_lfm_start(nrf_qspi_cinstr_conf_t const * p_config)
{
NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
NRFX_ASSERT(!(nrf_qspi_cinstr_long_transfer_is_ongoing(NRF_QSPI)));
NRFX_ASSERT(p_config->length == NRF_QSPI_CINSTR_LEN_1B);
if (m_cb.is_busy)
{
return NRFX_ERROR_BUSY;
}
nrf_qspi_cinstr_long_transfer_start(NRF_QSPI, p_config);
if (qspi_ready_wait() == NRFX_ERROR_TIMEOUT)
{
/* In case of error, abort long frame mode */
nrf_qspi_cinstr_long_transfer_continue(NRF_QSPI, NRF_QSPI_CINSTR_LEN_1B, true);
return NRFX_ERROR_TIMEOUT;
}
m_cb.is_busy = true;
return NRFX_SUCCESS;
}
nrfx_err_t nrfx_qspi_lfm_xfer(void const * p_tx_buffer,
void * p_rx_buffer,
size_t transfer_length,
bool finalize)
{
NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
NRFX_ASSERT(nrf_qspi_cinstr_long_transfer_is_ongoing(NRF_QSPI));
nrfx_err_t status = NRFX_SUCCESS;
/* Perform transfers in packets of 8 bytes. Last transfer may be shorter. */
nrf_qspi_cinstr_len_t length = NRF_QSPI_CINSTR_LEN_9B;
for (uint32_t curr_byte = 0; curr_byte < transfer_length; curr_byte += 8)
{
uint32_t remaining_bytes = transfer_length - curr_byte;
if (remaining_bytes < 8)
{
length = (nrf_qspi_cinstr_len_t)(remaining_bytes + 1);
}
if (p_tx_buffer)
{
nrf_qspi_cinstrdata_set(NRF_QSPI,
length,
&((uint8_t const *)p_tx_buffer)[curr_byte]);
}
nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
if (remaining_bytes <= 8)
{
nrf_qspi_cinstr_long_transfer_continue(NRF_QSPI, length, finalize);
}
else
{
nrf_qspi_cinstr_long_transfer_continue(NRF_QSPI, length, false);
}
if (qspi_ready_wait() == NRFX_ERROR_TIMEOUT)
{
/* In case of error, abort long frame mode */
nrf_qspi_cinstr_long_transfer_continue(NRF_QSPI, NRF_QSPI_CINSTR_LEN_1B, true);
status = NRFX_ERROR_TIMEOUT;
break;
}
if (p_rx_buffer)
{
nrf_qspi_cinstrdata_get(NRF_QSPI,
length,
&((uint8_t *)p_rx_buffer)[curr_byte]);
}
}
nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
if ((finalize) || (status == NRFX_ERROR_TIMEOUT))
{
m_cb.is_busy = false;
}
return status;
}
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);
if (nrf_qspi_cinstr_long_transfer_is_ongoing(NRF_QSPI))
{
nrf_qspi_cinstr_long_transfer_continue(NRF_QSPI, NRF_QSPI_CINSTR_LEN_1B, true);
}
NRFX_IRQ_DISABLE(QSPI_IRQn);
nrf_qspi_int_disable(NRF_QSPI, NRF_QSPI_INT_READY_MASK);
nrf_qspi_task_trigger(NRF_QSPI, NRF_QSPI_TASK_DEACTIVATE);
nrf_qspi_disable(NRF_QSPI);
nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
qspi_pins_deconfigure();
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) || !nrfx_is_word_aligned(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) || !nrfx_is_word_aligned(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);
if (!nrfx_is_word_aligned((void const *)start_address))
{
return NRFX_ERROR_INVALID_ADDR;
}
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.is_busy = 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)

View File

@@ -1,513 +0,0 @@
/**
* Copyright (c) 2013 - 2021, 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) || \
NRFX_CHECK(NRFX_SPIS3_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
#if NRFX_CHECK(NRFX_SPIS3_ENABLED)
#define SPIS3_LENGTH_VALIDATE(...) SPISX_LENGTH_VALIDATE(SPIS3, __VA_ARGS__)
#else
#define SPIS3_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) || \
SPIS3_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_CHECK(NRFX_SPIS3_ENABLED)
nrfx_spis_3_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
#if NRFX_CHECK(NRFX_SPIS3_ENABLED)
void nrfx_spis_3_irq_handler(void)
{
spis_irq_handler(NRF_SPIS3, &m_cb[NRFX_SPIS3_INST_IDX]);
}
#endif
#endif // NRFX_CHECK(NRFX_SPIS_ENABLED)

View File

@@ -1,439 +0,0 @@
/**
* Copyright (c) 2015 - 2021, 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)
{
#if defined(NRF_SWI)
return (IRQn_Type)(nrfx_get_irq_number(NRF_SWI) + swi);
#elif defined(NRF_SWI0)
return (IRQn_Type)(nrfx_get_irq_number(NRF_SWI0) + swi);
#else
return (IRQn_Type)(nrfx_get_irq_number(NRF_EGU0) + swi);
#endif
}
static void swi_int_enable(nrfx_swi_t swi)
{
#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 (m_swi_handlers[swi] == NULL)
{
return;
}
}
#endif
NRFX_IRQ_ENABLE(swi_irq_number_get(swi));
}
static void swi_int_disable(nrfx_swi_t swi)
{
NRFX_IRQ_DISABLE(swi_irq_number_get(swi));
#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
}
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;
NRFX_IRQ_PRIORITY_SET(swi_irq_number_get(swi), irq_priority);
swi_int_enable(swi);
}
static void swi_deallocate(nrfx_swi_t swi)
{
swi_int_disable(swi);
m_swi_handlers[swi] = NULL;
swi_mark_unallocated(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_int_disable(nrfx_swi_t swi)
{
NRFX_ASSERT(swi_is_allocated(swi));
swi_int_disable(swi);
}
void nrfx_swi_int_enable(nrfx_swi_t swi)
{
NRFX_ASSERT(swi_is_allocated(swi));
swi_int_enable(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));
swi_deallocate(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))
{
swi_deallocate(swi);
}
}
}
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)

View File

@@ -1,170 +0,0 @@
/**
* Copyright (c) 2016 - 2021, 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)

View File

@@ -1,155 +0,0 @@
/**
* Copyright (c) 2019 - 2021, 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_TEMP_ENABLED)
#include <nrfx_temp.h>
#if !defined(USE_WORKAROUND_FOR_TEMP_OFFSET_ANOMALY) && defined(NRF51)
// Enable workaround for nRF51 series anomaly 28
// (TEMP: Temperature offset value has to be manually loaded to the TEMP module).
#define USE_WORKAROUND_FOR_TEMP_OFFSET_ANOMALY 1
#endif
/** @brief Time of one check attempt.*/
#define NRFX_TEMP_TIME_US 4
/** @brief Maximum attempts to check whether conversion passed.*/
#define NRFX_TEMP_ATTEMPTS 10
/** @brief Internal state of TEMP driver. */
static nrfx_drv_state_t m_temp_state;
/** @brief Pointer to handler to be called from interrupt routine. */
static nrfx_temp_data_handler_t m_data_handler;
nrfx_err_t nrfx_temp_init(nrfx_temp_config_t const * p_config, nrfx_temp_data_handler_t handler)
{
NRFX_ASSERT(p_config);
if (m_temp_state != NRFX_DRV_STATE_UNINITIALIZED)
{
return NRFX_ERROR_ALREADY_INITIALIZED;
}
#if NRFX_CHECK(USE_WORKAROUND_FOR_TEMP_OFFSET_ANOMALY)
*(uint32_t volatile *)0x4000C504 = 0;
#endif
m_data_handler = handler;
if (m_data_handler)
{
nrf_temp_int_enable(NRF_TEMP, NRF_TEMP_INT_DATARDY_MASK);
NRFX_IRQ_PRIORITY_SET(TEMP_IRQn, p_config->interrupt_priority);
NRFX_IRQ_ENABLE(TEMP_IRQn);
}
m_temp_state = NRFX_DRV_STATE_INITIALIZED;
return NRFX_SUCCESS;
}
void nrfx_temp_uninit(void)
{
NRFX_ASSERT(m_temp_state == NRFX_DRV_STATE_INITIALIZED);
nrf_temp_task_trigger(NRF_TEMP, NRF_TEMP_TASK_STOP);
if (m_data_handler)
{
nrf_temp_int_disable(NRF_TEMP, NRF_TEMP_INT_DATARDY_MASK);
NRFX_IRQ_DISABLE(TEMP_IRQn);
}
m_temp_state = NRFX_DRV_STATE_UNINITIALIZED;
}
int32_t nrfx_temp_calculate(int32_t raw_measurement)
{
/* Raw temperature is a 2's complement signed value. Moreover, it is represented
* by 0.25[C] intervals, so division by 4 is needed. To preserve
* fractional part, raw value is multiplied by 100 before division.*/
return (raw_measurement * 100) / 4;
}
nrfx_err_t nrfx_temp_measure(void)
{
NRFX_ASSERT(m_temp_state == NRFX_DRV_STATE_INITIALIZED);
nrfx_err_t result = NRFX_SUCCESS;
nrf_temp_event_clear(NRF_TEMP, NRF_TEMP_EVENT_DATARDY);
nrf_temp_task_trigger(NRF_TEMP, NRF_TEMP_TASK_START);
if (!m_data_handler)
{
bool ev_result;
NRFX_WAIT_FOR(nrf_temp_event_check(NRF_TEMP, NRF_TEMP_EVENT_DATARDY),
NRFX_TEMP_ATTEMPTS,
NRFX_TEMP_TIME_US,
ev_result);
if (!ev_result)
{
result = NRFX_ERROR_INTERNAL;
}
else
{
nrf_temp_event_clear(NRF_TEMP, NRF_TEMP_EVENT_DATARDY);
}
nrf_temp_task_trigger(NRF_TEMP, NRF_TEMP_TASK_STOP);
}
return result;
}
void nrfx_temp_irq_handler(void)
{
NRFX_ASSERT(m_data_handler);
nrf_temp_task_trigger(NRF_TEMP, NRF_TEMP_TASK_STOP);
nrf_temp_event_clear(NRF_TEMP, NRF_TEMP_EVENT_DATARDY);
uint32_t raw_temp = nrfx_temp_result_get();
m_data_handler(raw_temp);
}
#endif // NRFX_CHECK(NRFX_TEMP_ENABLED)

View File

@@ -1,857 +0,0 @@
/**
* Copyright (c) 2015 - 2021, 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) || \
NRFX_CHECK(NRFX_TWIS2_ENABLED) || \
NRFX_CHECK(NRFX_TWIS3_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_CHECK(NRFX_TWIS2_ENABLED)
nrfx_twis_2_irq_handler,
#endif
#if NRFX_CHECK(NRFX_TWIS3_ENABLED)
nrfx_twis_3_irq_handler,
#endif
};
if (nrfx_prs_acquire(p_reg,
irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
{
err_code = NRFX_ERROR_BUSY;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
#endif // NRFX_CHECK(NRFX_PRS_ENABLED)
if (!NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY)
{
nrfx_twis_swreset(p_reg);
}
nrfx_twis_config_pin(p_config->scl, p_config->scl_pull);
nrfx_twis_config_pin(p_config->sda, p_config->sda_pull);
nrf_twis_config_addr_mask_t addr_mask = (nrf_twis_config_addr_mask_t)0;
if (0 == (p_config->addr[0] | p_config->addr[1]))
{
addr_mask = NRF_TWIS_CONFIG_ADDRESS0_MASK;
}
else
{
if (0 != p_config->addr[0])
{
addr_mask |= NRF_TWIS_CONFIG_ADDRESS0_MASK;
}
if (0 != p_config->addr[1])
{
addr_mask |= NRF_TWIS_CONFIG_ADDRESS1_MASK;
}
}
/* Peripheral interrupt configure
* (note - interrupts still needs to be configured in INTEN register.
* This is done in enable function) */
NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_reg),
p_config->interrupt_priority);
NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_reg));
/* Configure */
nrf_twis_pins_set (p_reg, p_config->scl, p_config->sda);
nrf_twis_address_set (p_reg, 0, p_config->addr[0]);
nrf_twis_address_set (p_reg, 1, p_config->addr[1]);
nrf_twis_config_address_set(p_reg, addr_mask);
/* Clear semaphore */
if (!NRFX_TWIS_NO_SYNC_MODE)
{
p_cb->semaphore = 0;
}
/* Set internal instance variables */
p_cb->substate = NRFX_TWIS_SUBSTATE_IDLE;
p_cb->ev_handler = event_handler;
p_cb->state = NRFX_DRV_STATE_INITIALIZED;
err_code = NRFX_SUCCESS;
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
void nrfx_twis_uninit(nrfx_twis_t const * p_instance)
{
NRF_TWIS_Type * p_reg = p_instance->p_reg;
twis_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
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,
size);
err_code = NRFX_SUCCESS;
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_err_t nrfx_twis_rx_prepare(nrfx_twis_t const * p_instance,
void * p_buf,
size_t size)
{
nrfx_err_t err_code;
twis_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx];
/* Check power state*/
if (p_cb->state != NRFX_DRV_STATE_POWERED_ON)
{
err_code = NRFX_ERROR_INVALID_STATE;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
/* Check data address */
if (!nrfx_is_in_ram(p_buf))
{
err_code = NRFX_ERROR_INVALID_ADDR;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
/* Check data size */
if ((size & TWIS_RXD_MAXCNT_MAXCNT_Msk) != size)
{
err_code = NRFX_ERROR_INVALID_LENGTH;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrf_twis_rx_prepare(p_instance->p_reg,
(uint8_t *)p_buf,
size);
err_code = NRFX_SUCCESS;
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
bool nrfx_twis_is_busy(nrfx_twis_t const * p_instance)
{
nrfx_twis_preprocess_status(p_instance);
twis_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx];
return NRFX_TWIS_SUBSTATE_IDLE != p_cb->substate;
}
bool nrfx_twis_is_waiting_tx_buff(nrfx_twis_t const * p_instance)
{
nrfx_twis_preprocess_status(p_instance);
twis_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx];
return NRFX_TWIS_SUBSTATE_READ_WAITING == p_cb->substate;
}
bool nrfx_twis_is_waiting_rx_buff(nrfx_twis_t const * p_instance)
{
nrfx_twis_preprocess_status(p_instance);
twis_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx];
return NRFX_TWIS_SUBSTATE_WRITE_WAITING == p_cb->substate;
}
bool nrfx_twis_is_pending_tx(nrfx_twis_t const * p_instance)
{
nrfx_twis_preprocess_status(p_instance);
twis_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx];
return NRFX_TWIS_SUBSTATE_READ_PENDING == p_cb->substate;
}
bool nrfx_twis_is_pending_rx(nrfx_twis_t const * p_instance)
{
nrfx_twis_preprocess_status(p_instance);
twis_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx];
return NRFX_TWIS_SUBSTATE_WRITE_PENDING == p_cb->substate;
}
#if NRFX_CHECK(NRFX_TWIS0_ENABLED)
void nrfx_twis_0_irq_handler(void)
{
nrfx_twis_state_machine(NRF_TWIS0, &m_cb[NRFX_TWIS0_INST_IDX]);
}
#endif
#if NRFX_CHECK(NRFX_TWIS1_ENABLED)
void nrfx_twis_1_irq_handler(void)
{
nrfx_twis_state_machine(NRF_TWIS1, &m_cb[NRFX_TWIS1_INST_IDX]);
}
#endif
#if NRFX_CHECK(NRFX_TWIS2_ENABLED)
void nrfx_twis_2_irq_handler(void)
{
nrfx_twis_state_machine(NRF_TWIS2, &m_cb[NRFX_TWIS2_INST_IDX]);
}
#endif
#if NRFX_CHECK(NRFX_TWIS3_ENABLED)
void nrfx_twis_3_irq_handler(void)
{
nrfx_twis_state_machine(NRF_TWIS3, &m_cb[NRFX_TWIS3_INST_IDX]);
}
#endif
#endif // NRFX_CHECK(NRFX_TWIS_ENABLED)

File diff suppressed because it is too large Load Diff

View File

@@ -1,93 +0,0 @@
/**
* Copyright (c) 2016 - 2021, 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_USBD_ERRATA_H__
#define NRFX_USBD_ERRATA_H__
#include <nrfx.h>
#include <nrf_erratas.h>
#ifndef NRFX_USBD_ERRATA_ENABLE
/**
* @brief The constant that informs if errata should be enabled at all.
*
* If this constant is set to 0, all the Errata bug fixes will be automatically disabled.
*/
#define NRFX_USBD_ERRATA_ENABLE 1
#endif
/* Errata: ISO double buffering not functional. */
static inline bool nrfx_usbd_errata_166(void)
{
return NRFX_USBD_ERRATA_ENABLE && nrf52_errata_166();
}
/* Errata: USBD might not reach its active state. */
static inline bool nrfx_usbd_errata_171(void)
{
return NRFX_USBD_ERRATA_ENABLE && nrf52_errata_171();
}
/* Errata: USB cannot be enabled. */
static inline bool nrfx_usbd_errata_187(void)
{
return NRFX_USBD_ERRATA_ENABLE && nrf52_errata_187();
}
/* Errata: USBD cannot receive tasks during DMA. */
static inline bool nrfx_usbd_errata_199(void)
{
return NRFX_USBD_ERRATA_ENABLE && nrf52_errata_199();
}
/* Errata: Device remains in SUSPEND too long. */
static inline bool nrfx_usbd_errata_211(void)
{
return NRFX_USBD_ERRATA_ENABLE && nrf52_errata_211();
}
/* Errata: Unexpected behavior after reset. **/
static inline bool nrfx_usbd_errata_223(void)
{
return NRFX_USBD_ERRATA_ENABLE && nrf52_errata_223();
}
#endif // NRFX_USBD_ERRATA_H__