mirror of
https://github.com/pengwon/epd42.git
synced 2026-05-12 02:34:52 +08:00
327 lines
8.5 KiB
C
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
|
|
|