Files
epd42/components/drivers_nrf/swi/nrf_drv_swi.c
Shuanglei Tao f353d23368 Initial commit
2024-11-11 15:35:36 +08:00

327 lines
8.5 KiB
C

/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is property of Nordic Semiconductor ASA.
* Terms and conditions of usage are described in detail in NORDIC
* SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
*
* Licensees are granted free, non-transferable use of the information. NO
* WARRANTY of ANY KIND is provided. This heading must NOT be removed from
* the file.
*
*/
#include "nrf_drv_common.h"
#include "nrf_error.h"
#include "nrf_assert.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "nrf_drv_swi.h"
#include "app_util_platform.h"
STATIC_ASSERT(SWI_COUNT > 0);
STATIC_ASSERT(SWI_COUNT <= SWI_MAX);
STATIC_ASSERT(SWI_MAX_FLAGS <= sizeof(nrf_swi_flags_t) * 8);
#ifdef SWI_DISABLE0
#undef SWI_DISABLE0
#define SWI_DISABLE0 1uL
#else
#if SWI_COUNT > 0
#define SWI_DISABLE0 0uL
#else
#define SWI_DISABLE0 1uL
#endif
#endif
#ifdef SWI_DISABLE1
#undef SWI_DISABLE1
#define SWI_DISABLE1 1uL
#else
#if SWI_COUNT > 1
#define SWI_DISABLE1 0uL
#else
#define SWI_DISABLE1 1uL
#endif
#endif
#ifdef SWI_DISABLE2
#undef SWI_DISABLE2
#define SWI_DISABLE2 1uL
#else
#if SWI_COUNT > 2
#define SWI_DISABLE2 0uL
#else
#define SWI_DISABLE2 1uL
#endif
#endif
#ifdef SWI_DISABLE3
#undef SWI_DISABLE3
#define SWI_DISABLE3 1uL
#else
#if SWI_COUNT > 3
#define SWI_DISABLE3 0uL
#else
#define SWI_DISABLE3 1uL
#endif
#endif
#ifdef SWI_DISABLE4
#undef SWI_DISABLE4
#define SWI_DISABLE4 1uL
#else
#if SWI_COUNT > 4
#define SWI_DISABLE4 0uL
#else
#define SWI_DISABLE4 1uL
#endif
#endif
#ifdef SWI_DISABLE5
#undef SWI_DISABLE5
#define SWI_DISABLE5 1uL
#else
#if SWI_COUNT > 5
#define SWI_DISABLE5 0uL
#else
#define SWI_DISABLE5 1uL
#endif
#endif
#define SWI_START_NUMBER ( (SWI_DISABLE0) \
+ (SWI_DISABLE0 * SWI_DISABLE1) \
+ (SWI_DISABLE0 * SWI_DISABLE1 * SWI_DISABLE2) \
+ (SWI_DISABLE0 * SWI_DISABLE1 * SWI_DISABLE2 * SWI_DISABLE3) \
+ (SWI_DISABLE0 * SWI_DISABLE1 * SWI_DISABLE2 * SWI_DISABLE3 * SWI_DISABLE4) \
+ (SWI_DISABLE0 * SWI_DISABLE1 * SWI_DISABLE2 * SWI_DISABLE3 * SWI_DISABLE4 \
* SWI_DISABLE5) )
#define SWI_ARRAY_SIZE (SWI_COUNT - SWI_START_NUMBER)
#if (SWI_COUNT <= SWI_START_NUMBER)
#undef SWI_ARRAY_SIZE
#define SWI_ARRAY_SIZE 1
#endif
static nrf_drv_state_t m_drv_state = NRF_DRV_STATE_UNINITIALIZED;
static nrf_swi_handler_t m_swi_handlers[SWI_ARRAY_SIZE];
#if !EGU_ENABLED
static nrf_swi_flags_t m_swi_flags[SWI_ARRAY_SIZE];
#endif
#if EGU_ENABLED > 0
/**@brief Get the specific EGU instance. */
__STATIC_INLINE NRF_EGU_Type * egu_instance_get(nrf_swi_t swi)
{
return (NRF_EGU_Type*) (NRF_EGU0_BASE + (((uint32_t) swi) * (NRF_EGU1_BASE - NRF_EGU0_BASE)));
}
/**@brief Software interrupt handler (using EGU). */
static void nrf_drv_swi_process(nrf_swi_t swi)
{
ASSERT(m_swi_handlers[swi - SWI_START_NUMBER]);
nrf_swi_flags_t flags = 0;
NRF_EGU_Type * NRF_EGUx = egu_instance_get(swi);
for (uint8_t i = 0; i < NRF_EGU_CHANNEL_COUNT; ++i)
{
nrf_egu_event_t egu_event = nrf_egu_event_triggered_get(i);
if (nrf_egu_event_check(NRF_EGUx, egu_event))
{
flags |= (1u << i);
nrf_egu_event_clear(NRF_EGUx, egu_event);
}
}
m_swi_handlers[swi - SWI_START_NUMBER](swi, flags);
}
#define SWI_HANDLER_TEMPLATE(NUM) void SWI##NUM##_EGU##NUM##_IRQHandler(void) \
{ \
nrf_drv_swi_process(NUM); \
}
#else
/**@brief Software interrupt handler (without EGU). */
static void nrf_drv_swi_process(nrf_swi_t swi, nrf_swi_flags_t flags)
{
ASSERT(m_swi_handlers[swi - SWI_START_NUMBER]);
m_swi_flags[swi - SWI_START_NUMBER] &= ~flags;
m_swi_handlers[swi - SWI_START_NUMBER](swi, flags);
}
#define SWI_HANDLER_TEMPLATE(NUM) void SWI##NUM##_IRQHandler(void) \
{ \
nrf_drv_swi_process((NUM), m_swi_flags[(NUM) - SWI_START_NUMBER]); \
}
#endif
#if SWI_DISABLE0 == 0
SWI_HANDLER_TEMPLATE(0)
#endif
#if SWI_DISABLE1 == 0
SWI_HANDLER_TEMPLATE(1)
#endif
#if SWI_DISABLE2 == 0
SWI_HANDLER_TEMPLATE(2)
#endif
#if SWI_DISABLE3 == 0
SWI_HANDLER_TEMPLATE(3)
#endif
#if SWI_DISABLE4 == 0
SWI_HANDLER_TEMPLATE(4)
#endif
#if SWI_DISABLE5 == 0
SWI_HANDLER_TEMPLATE(5)
#endif
#define AVAILABLE_SWI (0x3FuL & ~( \
(SWI_DISABLE0 << 0) | (SWI_DISABLE1 << 1) | (SWI_DISABLE2 << 2) \
| (SWI_DISABLE3 << 3) | (SWI_DISABLE4 << 4) | (SWI_DISABLE5 << 5) \
))
#if (AVAILABLE_SWI == 0)
#warning No available SWIs.
#endif
/**@brief Function for converting SWI number to system interrupt number.
*
* @param[in] swi SWI number.
*
* @retval IRQ number.
*/
__STATIC_INLINE IRQn_Type nrf_drv_swi_irq_of(nrf_swi_t swi)
{
return (IRQn_Type)((uint32_t)SWI0_IRQn + (uint32_t)swi);
}
/**@brief Function for checking if given SWI is allocated.
*
* @param[in] swi SWI number.
*/
__STATIC_INLINE bool swi_is_allocated(nrf_swi_t swi)
{
ASSERT(swi < SWI_COUNT);
#if SWI_START_NUMBER > 0
if (swi < SWI_START_NUMBER)
{
return false;
}
#endif
/*lint -e(661) out of range case handled by assert above*/
return m_swi_handlers[swi - SWI_START_NUMBER];
}
ret_code_t nrf_drv_swi_init(void)
{
if (m_drv_state == NRF_DRV_STATE_UNINITIALIZED)
{
m_drv_state = NRF_DRV_STATE_INITIALIZED;
return NRF_SUCCESS;
}
return MODULE_ALREADY_INITIALIZED;
}
void nrf_drv_swi_uninit(void)
{
ASSERT(m_drv_state != NRF_DRV_STATE_UNINITIALIZED)
for (uint32_t i = SWI_START_NUMBER; i < SWI_COUNT; ++i)
{
m_swi_handlers[i - SWI_START_NUMBER] = NULL;
nrf_drv_common_irq_disable(nrf_drv_swi_irq_of((nrf_swi_t) i));
#if EGU_ENABLED > 0
NRF_EGU_Type * NRF_EGUx = egu_instance_get(i);
nrf_egu_int_disable(NRF_EGUx, NRF_EGU_INT_ALL);
#endif
}
m_drv_state = NRF_DRV_STATE_UNINITIALIZED;
return;
}
void nrf_drv_swi_free(nrf_swi_t * p_swi)
{
ASSERT(swi_is_allocated(*p_swi));
nrf_drv_common_irq_disable(nrf_drv_swi_irq_of(*p_swi));
m_swi_handlers[(*p_swi) - SWI_START_NUMBER] = NULL;
*p_swi = NRF_SWI_UNALLOCATED;
}
ret_code_t nrf_drv_swi_alloc(nrf_swi_t * p_swi, nrf_swi_handler_t event_handler, uint32_t priority)
{
ASSERT(event_handler);
uint32_t err_code = NRF_ERROR_NO_MEM;
for (uint32_t i = SWI_START_NUMBER; i < SWI_COUNT; i++)
{
CRITICAL_REGION_ENTER();
if ((!swi_is_allocated(i)) && (AVAILABLE_SWI & (1 << i)))
{
m_swi_handlers[i - SWI_START_NUMBER] = event_handler;
*p_swi = (nrf_swi_t) i;
nrf_drv_common_irq_enable(nrf_drv_swi_irq_of(*p_swi), priority);
#if EGU_ENABLED > 0
NRF_EGU_Type * NRF_EGUx = egu_instance_get(i);
nrf_egu_int_enable(NRF_EGUx, NRF_EGU_INT_ALL);
#endif
err_code = NRF_SUCCESS;
}
CRITICAL_REGION_EXIT();
if (err_code == NRF_SUCCESS)
{
break;
}
}
return err_code;
}
void nrf_drv_swi_trigger(nrf_swi_t swi, uint8_t flag_number)
{
ASSERT(swi_is_allocated((uint32_t) swi));
#if EGU_ENABLED > 0
ASSERT(flag_number < NRF_EGU_CHANNEL_COUNT);
NRF_EGU_Type * NRF_EGUx = egu_instance_get(swi);
nrf_egu_task_trigger(NRF_EGUx, nrf_egu_task_trigger_get(flag_number));
#else
ASSERT(flag_number < SWI_MAX_FLAGS);
m_swi_flags[swi - SWI_START_NUMBER] |= (1 << flag_number);
NVIC_SetPendingIRQ(nrf_drv_swi_irq_of(swi));
#endif
}
#if EGU_ENABLED > 0
uint32_t nrf_drv_swi_task_trigger_address_get(nrf_swi_t swi, uint8_t channel)
{
NRF_EGU_Type * NRF_EGUx = egu_instance_get(swi);
return (uint32_t) nrf_egu_task_trigger_addres_get(NRF_EGUx, channel);
}
uint32_t nrf_drv_swi_event_triggered_address_get(nrf_swi_t swi, uint8_t channel)
{
NRF_EGU_Type * NRF_EGUx = egu_instance_get(swi);
return (uint32_t) nrf_egu_event_triggered_addres_get(NRF_EGUx, channel);
}
#endif