/** * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form, except as embedded into a Nordic * Semiconductor ASA integrated circuit in a product or a software update for * such product, must reproduce the above copyright notice, this list of * conditions and the following disclaimer in the documentation and/or other * materials provided with the distribution. * * 3. Neither the name of Nordic Semiconductor ASA nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * 4. This software, with or without modification, must only be used with a * Nordic Semiconductor ASA integrated circuit. * * 5. Any software provided in binary form under this license must not be reverse * engineered, decompiled, modified and/or disassembled. * * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #if NRFX_CHECK(NRFX_SWI_ENABLED) #include #define NRFX_LOG_MODULE SWI #include // 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 . #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 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 . #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 and NRFX_SWI_USED." #endif #define NRFX_SWI_IS_AVAILABLE(idx) ((NRFX_SWI_AVAILABLE_MASK >> (idx)) & 1u) #define NRFX_SWI_FIRST (NRFX_SWI_IS_AVAILABLE(0) ? 0u : \ (NRFX_SWI_IS_AVAILABLE(1) ? 1u : \ (NRFX_SWI_IS_AVAILABLE(2) ? 2u : \ (NRFX_SWI_IS_AVAILABLE(3) ? 3u : \ (NRFX_SWI_IS_AVAILABLE(4) ? 4u : \ 5u))))) #define NRFX_SWI_LAST (NRFX_SWI_IS_AVAILABLE(5) ? 5u : \ (NRFX_SWI_IS_AVAILABLE(4) ? 4u : \ (NRFX_SWI_IS_AVAILABLE(3) ? 3u : \ (NRFX_SWI_IS_AVAILABLE(2) ? 2u : \ (NRFX_SWI_IS_AVAILABLE(1) ? 1u : \ 0u))))) // NRFX_SWI_EGU_COUNT - number of EGU instances to be used by this module // (note - if EGU is not present, EGU_COUNT is not defined). #if NRFX_CHECK(NRFX_EGU_ENABLED) #define NRFX_SWI_EGU_COUNT EGU_COUNT #else #define NRFX_SWI_EGU_COUNT 0 #endif // These flags are needed only for SWIs that have no corresponding EGU unit // (in EGU such flags are available in hardware). #if (NRFX_SWI_EGU_COUNT < SWI_COUNT) static nrfx_swi_flags_t m_swi_flags[SWI_COUNT - NRFX_SWI_EGU_COUNT]; #endif static nrfx_swi_handler_t m_swi_handlers[SWI_COUNT]; static uint8_t m_swi_allocated_mask; static void swi_mark_allocated(nrfx_swi_t swi) { m_swi_allocated_mask |= (1u << swi); } static void swi_mark_unallocated(nrfx_swi_t swi) { m_swi_allocated_mask &= ~(1u << swi); } static bool swi_is_allocated(nrfx_swi_t swi) { return (m_swi_allocated_mask & (1u << swi)); } static bool swi_is_available(nrfx_swi_t swi) { return NRFX_SWI_IS_AVAILABLE(swi); } static IRQn_Type swi_irq_number_get(nrfx_swi_t swi) { return (IRQn_Type)((uint32_t)SWI0_IRQn + (uint32_t)swi); } static void swi_handler_setup(nrfx_swi_t swi, nrfx_swi_handler_t event_handler, uint32_t irq_priority) { m_swi_handlers[swi] = event_handler; #if NRFX_SWI_EGU_COUNT if (swi < NRFX_SWI_EGU_COUNT) { NRF_EGU_Type * p_egu = nrfx_swi_egu_instance_get(swi); NRFX_ASSERT(p_egu != NULL); nrf_egu_int_enable(p_egu, NRF_EGU_INT_ALL); if (event_handler == NULL) { return; } } #endif NRFX_ASSERT(event_handler != NULL); NRFX_IRQ_PRIORITY_SET(swi_irq_number_get(swi), irq_priority); NRFX_IRQ_ENABLE(swi_irq_number_get(swi)); } nrfx_err_t nrfx_swi_alloc(nrfx_swi_t * p_swi, nrfx_swi_handler_t event_handler, uint32_t irq_priority) { NRFX_ASSERT(p_swi != NULL); nrfx_err_t err_code; for (nrfx_swi_t swi = NRFX_SWI_FIRST; swi <= NRFX_SWI_LAST; ++swi) { if (swi_is_available(swi)) { bool allocated = false; NRFX_CRITICAL_SECTION_ENTER(); if (!swi_is_allocated(swi)) { swi_mark_allocated(swi); allocated = true; } NRFX_CRITICAL_SECTION_EXIT(); if (allocated) { swi_handler_setup(swi, event_handler, irq_priority); *p_swi = swi; NRFX_LOG_INFO("SWI channel allocated: %d.", (*p_swi)); return NRFX_SUCCESS; } } } err_code = NRFX_ERROR_NO_MEM; NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); return err_code; } bool nrfx_swi_is_allocated(nrfx_swi_t swi) { return swi_is_allocated(swi); } void nrfx_swi_free(nrfx_swi_t * p_swi) { NRFX_ASSERT(p_swi != NULL); nrfx_swi_t swi = *p_swi; NRFX_ASSERT(swi_is_allocated(swi)); NRFX_IRQ_DISABLE(swi_irq_number_get(swi)); m_swi_handlers[swi] = NULL; swi_mark_unallocated(swi); *p_swi = NRFX_SWI_UNALLOCATED; } void nrfx_swi_all_free(void) { for (nrfx_swi_t swi = NRFX_SWI_FIRST; swi <= NRFX_SWI_LAST; ++swi) { if (swi_is_allocated(swi)) { NRFX_IRQ_DISABLE(swi_irq_number_get(swi)); m_swi_handlers[swi] = NULL; #if NRFX_SWI_EGU_COUNT if (swi < NRFX_SWI_EGU_COUNT) { nrf_egu_int_disable(nrfx_swi_egu_instance_get(swi), NRF_EGU_INT_ALL); } #endif } } m_swi_allocated_mask = 0; } void nrfx_swi_trigger(nrfx_swi_t swi, uint8_t flag_number) { NRFX_ASSERT(swi_is_allocated(swi)); #if NRFX_SWI_EGU_COUNT NRF_EGU_Type * p_egu = nrfx_swi_egu_instance_get(swi); #if (NRFX_SWI_EGU_COUNT < SWI_COUNT) if (p_egu == NULL) { m_swi_flags[swi - NRFX_SWI_EGU_COUNT] |= (1 << flag_number); NRFX_IRQ_PENDING_SET(swi_irq_number_get(swi)); } else #endif // (NRFX_SWI_EGU_COUNT < SWI_COUNT) { nrf_egu_task_trigger(p_egu, nrf_egu_task_trigger_get(p_egu, flag_number)); } #else // -> #if !NRFX_SWI_EGU_COUNT m_swi_flags[swi - NRFX_SWI_EGU_COUNT] |= (1 << flag_number); NRFX_IRQ_PENDING_SET(swi_irq_number_get(swi)); #endif } #if NRFX_SWI_EGU_COUNT static void egu_irq_handler(nrfx_swi_t swi, uint8_t egu_channel_count) { #if (NRFX_SWI_FIRST > 0) NRFX_ASSERT(swi >= NRFX_SWI_FIRST); #endif NRFX_ASSERT(swi <= NRFX_SWI_LAST); nrfx_swi_handler_t handler = m_swi_handlers[swi]; NRFX_ASSERT(handler != NULL); NRF_EGU_Type * p_egu = nrfx_swi_egu_instance_get(swi); NRFX_ASSERT(p_egu != NULL); nrfx_swi_flags_t flags = 0; for (uint8_t i = 0; i < egu_channel_count; ++i) { nrf_egu_event_t egu_event = nrf_egu_event_triggered_get(p_egu, i); if (nrf_egu_event_check(p_egu, egu_event)) { flags |= (1u << i); nrf_egu_event_clear(p_egu, egu_event); } } handler(swi, flags); } #endif // NRFX_SWI_EGU_COUNT #if (NRFX_SWI_EGU_COUNT < SWI_COUNT) static void swi_irq_handler(nrfx_swi_t swi) { #if (NRFX_SWI_FIRST > 0) NRFX_ASSERT(swi >= NRFX_SWI_FIRST); #endif NRFX_ASSERT(swi <= NRFX_SWI_LAST); nrfx_swi_handler_t handler = m_swi_handlers[swi]; NRFX_ASSERT(handler != NULL); nrfx_swi_flags_t flags = m_swi_flags[swi - NRFX_SWI_EGU_COUNT]; m_swi_flags[swi - NRFX_SWI_EGU_COUNT] &= ~flags; handler(swi, flags); } #endif // (NRFX_SWI_EGU_COUNT < SWI_COUNT) #if NRFX_SWI_IS_AVAILABLE(0) void nrfx_swi_0_irq_handler(void) { #if (NRFX_SWI_EGU_COUNT > 0) egu_irq_handler(0, EGU0_CH_NUM); #else swi_irq_handler(0); #endif } #endif // NRFX_SWI_IS_AVAILABLE(0) #if NRFX_SWI_IS_AVAILABLE(1) void nrfx_swi_1_irq_handler(void) { #if (NRFX_SWI_EGU_COUNT > 1) egu_irq_handler(1, EGU1_CH_NUM); #else swi_irq_handler(1); #endif } #endif // NRFX_SWI_IS_AVAILABLE(1) #if NRFX_SWI_IS_AVAILABLE(2) void nrfx_swi_2_irq_handler(void) { #if (NRFX_SWI_EGU_COUNT > 2) egu_irq_handler(2, EGU2_CH_NUM); #else swi_irq_handler(2); #endif } #endif // NRFX_SWI_IS_AVAILABLE(2) #if NRFX_SWI_IS_AVAILABLE(3) void nrfx_swi_3_irq_handler(void) { #if (NRFX_SWI_EGU_COUNT > 3) egu_irq_handler(3, EGU3_CH_NUM); #else swi_irq_handler(3); #endif } #endif // NRFX_SWI_IS_AVAILABLE(3) #if NRFX_SWI_IS_AVAILABLE(4) void nrfx_swi_4_irq_handler(void) { #if (NRFX_SWI_EGU_COUNT > 4) egu_irq_handler(4, EGU4_CH_NUM); #else swi_irq_handler(4); #endif } #endif // NRFX_SWI_IS_AVAILABLE(4) #if NRFX_SWI_IS_AVAILABLE(5) void nrfx_swi_5_irq_handler(void) { #if (NRFX_SWI_EGU_COUNT > 5) egu_irq_handler(5, EGU5_CH_NUM); #else swi_irq_handler(5); #endif } #endif // NRFX_SWI_IS_AVAILABLE(5) #endif // NRFX_CHECK(NRFX_SWI_ENABLED)