/* * Copyright (c) 2022 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #define TIMER_NO 2 #define TIMER_INSTANCE NRFX_CONCAT_2(NRF_TIMER, TIMER_NO) #define TIMER_IRQ TIMER2_IRQn #define TIMER_INT NRF_TIMER_INT_COMPARE0_MASK #define TIMER_PRIORITY 5 #define TIMER_DELAY_TICKS 100 #define EGU_DELAY_USEC 200 struct timer_isr_context { unsigned int egu_channel; }; #define NRF_NEGUs 6 #define NRF_NEGU_NEVENTS 16 static const NRF_EGU_Type *EGU[NRF_NEGUs] = { NRF_EGU0, NRF_EGU1, NRF_EGU2, NRF_EGU3, NRF_EGU4, NRF_EGU5 }; ZTEST(nrf_egu_tests, test_channels_count) { for (int i = 0; i < NRF_NEGUs; i++) { zassert_equal(16, nrf_egu_channel_count(EGU[i]), "NRF_EGU%d incorrect number of channels", i); } } ZTEST(nrf_egu_tests, test_task_address_get) { nrf_egu_task_t egu_tasks[NRF_NEGU_NEVENTS] = { NRF_EGU_TASK_TRIGGER0, NRF_EGU_TASK_TRIGGER1, NRF_EGU_TASK_TRIGGER2, NRF_EGU_TASK_TRIGGER3, NRF_EGU_TASK_TRIGGER4, NRF_EGU_TASK_TRIGGER5, NRF_EGU_TASK_TRIGGER6, NRF_EGU_TASK_TRIGGER7, NRF_EGU_TASK_TRIGGER8, NRF_EGU_TASK_TRIGGER9, NRF_EGU_TASK_TRIGGER10, NRF_EGU_TASK_TRIGGER11, NRF_EGU_TASK_TRIGGER12, NRF_EGU_TASK_TRIGGER13, NRF_EGU_TASK_TRIGGER14, NRF_EGU_TASK_TRIGGER15 }; for (int i = 0; i < NRF_NEGUs; i++) { for (int j = 0; j < NRF_NEGU_NEVENTS; j++) { zassert_equal((size_t)&EGU[i]->TASKS_TRIGGER[j], nrf_egu_task_address_get(EGU[i], egu_tasks[j]), "NRF_EGU_%i incorrect address of task trigger %i", i, j); } } } ZTEST(nrf_egu_tests, test_event_address_get) { nrf_egu_event_t egu_events[NRF_NEGU_NEVENTS] = { NRF_EGU_EVENT_TRIGGERED0, NRF_EGU_EVENT_TRIGGERED1, NRF_EGU_EVENT_TRIGGERED2, NRF_EGU_EVENT_TRIGGERED3, NRF_EGU_EVENT_TRIGGERED4, NRF_EGU_EVENT_TRIGGERED5, NRF_EGU_EVENT_TRIGGERED6, NRF_EGU_EVENT_TRIGGERED7, NRF_EGU_EVENT_TRIGGERED8, NRF_EGU_EVENT_TRIGGERED9, NRF_EGU_EVENT_TRIGGERED10, NRF_EGU_EVENT_TRIGGERED11, NRF_EGU_EVENT_TRIGGERED12, NRF_EGU_EVENT_TRIGGERED13, NRF_EGU_EVENT_TRIGGERED14, NRF_EGU_EVENT_TRIGGERED15 }; for (int i = 0; i < NRF_NEGUs; i++) { for (int j = 0; j < NRF_NEGU_NEVENTS; j++) { zassert_equal((size_t)&EGU[i]->EVENTS_TRIGGERED[j], nrf_egu_event_address_get(EGU[i], egu_events[j]), "NRF_EGU_%i incorrect address of event trigger %i", i, j); } } } ZTEST(nrf_egu_tests, test_channel_int_get) { nrf_egu_int_mask_t egu_masks[NRF_NEGU_NEVENTS] = { NRF_EGU_INT_TRIGGERED0, NRF_EGU_INT_TRIGGERED1, NRF_EGU_INT_TRIGGERED2, NRF_EGU_INT_TRIGGERED3, NRF_EGU_INT_TRIGGERED4, NRF_EGU_INT_TRIGGERED5, NRF_EGU_INT_TRIGGERED6, NRF_EGU_INT_TRIGGERED7, NRF_EGU_INT_TRIGGERED8, NRF_EGU_INT_TRIGGERED9, NRF_EGU_INT_TRIGGERED10, NRF_EGU_INT_TRIGGERED11, NRF_EGU_INT_TRIGGERED12, NRF_EGU_INT_TRIGGERED13, NRF_EGU_INT_TRIGGERED14, NRF_EGU_INT_TRIGGERED15 }; for (int i = 0; i < NRF_NEGU_NEVENTS; i++) { zassert_equal(egu_masks[i], nrf_egu_channel_int_get(i), "Incorrect offset for channel %i", i); } } struct SWI_trigger_assert_parameter { bool triggered[EGU5_CH_NUM]; uint32_t call_count; }; static struct SWI_trigger_assert_parameter event_triggered_flag; void SWI5_trigger_function(const void *param) { event_triggered_flag.call_count++; for (uint8_t i = 0; i < nrf_egu_channel_count(NRF_EGU5); i++) { const nrf_egu_event_t check_event = nrf_egu_triggered_event_get(i); event_triggered_flag.triggered[i] = nrf_egu_event_check(NRF_EGU5, check_event); if (event_triggered_flag.triggered[i]) { nrf_egu_event_clear(NRF_EGU5, check_event); } } } ZTEST(nrf_egu_tests, test_task_trigger_not_int) { nrf_egu_int_disable(NRF_EGU5, NRF_EGU_INT_TRIGGERED1); zassert_equal(0, nrf_egu_int_enable_check(NRF_EGU5, NRF_EGU_INT_TRIGGERED1), "interrupt has not been disabled"); memset(&event_triggered_flag, 0, sizeof(event_triggered_flag)); irq_connect_dynamic(SWI5_EGU5_IRQn, 0, SWI5_trigger_function, NULL, BIT(0)); irq_enable(SWI5_EGU5_IRQn); nrf_egu_task_t task_to_trigger = nrf_egu_trigger_task_get(0); nrf_egu_task_trigger(NRF_EGU5, task_to_trigger); k_busy_wait(1000); irq_disable(SWI5_EGU5_IRQn); nrf_egu_int_disable(NRF_EGU5, NRF_EGU_INT_TRIGGERED1); zassert_equal(0, event_triggered_flag.call_count, "interrupt has been called"); for (int i = 0 ; i < NRF_NEGU_NEVENTS; i++) { zassert_false(event_triggered_flag.triggered[i], "Event %i has been triggered", i); } zassert_true(nrf_egu_event_check(NRF_EGU5, nrf_egu_triggered_event_get(0)), "event has not been triggered"); for (uint8_t i = 1; i < nrf_egu_channel_count(NRF_EGU5); i++) { const nrf_egu_event_t check_event = nrf_egu_triggered_event_get(i); zassert_false(nrf_egu_event_check(NRF_EGU5, check_event), "event %d has been triggered, but it shouldn't", i); } } ZTEST(nrf_egu_tests, test_task_trigger) { nrf_egu_int_enable(NRF_EGU5, NRF_EGU_INT_TRIGGERED0); zassert_equal(NRF_EGU_INT_TRIGGERED0, nrf_egu_int_enable_check(NRF_EGU5, NRF_EGU_INT_TRIGGERED0), "failed to enable interrupt"); memset(&event_triggered_flag, 0, sizeof(event_triggered_flag)); irq_connect_dynamic(SWI5_EGU5_IRQn, 0, SWI5_trigger_function, NULL, BIT(0)); irq_enable(SWI5_EGU5_IRQn); nrf_egu_task_t task_to_trigger = nrf_egu_trigger_task_get(0); nrf_egu_task_trigger(NRF_EGU5, task_to_trigger); k_busy_wait(1000); irq_disable(SWI5_EGU5_IRQn); nrf_egu_int_disable(NRF_EGU5, NRF_EGU_INT_TRIGGERED0); zassert_equal(1, event_triggered_flag.call_count, "zassert failed count = %d ", event_triggered_flag.call_count); zassert_true(event_triggered_flag.triggered[0], "Event 0 has not been triggered"); for (int i = 1 ; i < NRF_NEGU_NEVENTS; i++) { zassert_false(event_triggered_flag.triggered[i], "Event %i has been triggered", i); } for (uint8_t i = 0; i < nrf_egu_channel_count(NRF_EGU5); i++) { const nrf_egu_event_t check_event = nrf_egu_triggered_event_get(i); zassert_false(nrf_egu_event_check(NRF_EGU5, check_event), "event %d has been triggered, but it shouldn't", i); } } ZTEST(nrf_egu_tests, test_task_configure_not_trigger) { nrf_egu_int_mask_t egu_int_mask = nrf_egu_channel_int_get(0); zassert_equal(NRF_EGU_INT_TRIGGERED0, egu_int_mask, "interrupt mask is invalid"); nrf_egu_int_enable(NRF_EGU5, egu_int_mask); zassert_equal(egu_int_mask, nrf_egu_int_enable_check(NRF_EGU5, egu_int_mask), "failed to enable interrupt"); memset(&event_triggered_flag, 0, sizeof(event_triggered_flag)); irq_connect_dynamic(SWI5_EGU5_IRQn, 0, SWI5_trigger_function, NULL, BIT(0)); irq_enable(SWI5_EGU5_IRQn); k_busy_wait(1000); irq_disable(SWI5_EGU5_IRQn); nrf_egu_int_disable(NRF_EGU5, egu_int_mask); zassert_equal(0, event_triggered_flag.call_count, "interrupt has been called"); for (int i = 0 ; i < NRF_NEGU_NEVENTS; i++) { zassert_false(event_triggered_flag.triggered[i], "Event %i has been triggered", i); } for (uint8_t i = 0; i < nrf_egu_channel_count(NRF_EGU5); i++) { const nrf_egu_event_t check_event = nrf_egu_triggered_event_get(i); zassert_false(nrf_egu_event_check(NRF_EGU5, check_event), "event %d has been triggered, but it shouldn't", i); } } static void timer_isr(const void *timer_isr_ctx) { struct timer_isr_context *ctx = (struct timer_isr_context *)timer_isr_ctx; if (ctx) { nrf_egu_task_trigger(NRF_EGU5, nrf_egu_trigger_task_get(ctx->egu_channel)); } nrf_timer_event_clear(TIMER_INSTANCE, NRF_TIMER_EVENT_COMPARE0); nrf_timer_int_disable(TIMER_INSTANCE, TIMER_INT); } ZTEST(nrf_egu_tests, test_trigger_from_another_irq) { uint32_t call_cnt_expected = event_triggered_flag.call_count + 1; static struct timer_isr_context timer_isr_ctx = { .egu_channel = 0 }; /* Timer cleanup */ nrf_timer_event_clear(TIMER_INSTANCE, NRF_TIMER_EVENT_COMPARE0); nrf_timer_task_trigger(TIMER_INSTANCE, NRF_TIMER_TASK_STOP); nrf_timer_task_trigger(TIMER_INSTANCE, NRF_TIMER_TASK_CLEAR); /* Timer setup */ irq_connect_dynamic(TIMER_IRQ, TIMER_PRIORITY, timer_isr, &timer_isr_ctx, 0); irq_enable(TIMER_IRQ); nrf_timer_mode_set(TIMER_INSTANCE, NRF_TIMER_MODE_TIMER); nrf_timer_bit_width_set(TIMER_INSTANCE, TIMER_BITMODE_BITMODE_16Bit); nrf_timer_prescaler_set(TIMER_INSTANCE, NRF_TIMER_PRESCALER_CALCULATE( NRF_TIMER_BASE_FREQUENCY_GET(TIMER_INSTANCE), NRFX_MHZ_TO_HZ(1))); nrf_timer_cc_set(TIMER_INSTANCE, NRF_TIMER_CC_CHANNEL0, TIMER_DELAY_TICKS); nrf_timer_int_enable(TIMER_INSTANCE, TIMER_INT); /* EGU setup */ nrf_egu_int_enable(NRF_EGU5, NRF_EGU_INT_TRIGGERED0); irq_connect_dynamic(SWI5_EGU5_IRQn, 0, SWI5_trigger_function, NULL, BIT(0)); irq_enable(SWI5_EGU5_IRQn); nrf_timer_task_trigger(TIMER_INSTANCE, NRF_TIMER_TASK_START); k_busy_wait(EGU_DELAY_USEC); zassert_equal(call_cnt_expected, event_triggered_flag.call_count, "interrupt called unexpected number of times %d", event_triggered_flag.call_count); } static struct SWI_trigger_assert_parameter SWI4_event_triggered_flag; static void SWI4_trigger_function(const void *param) { for (uint8_t i = 0; i < nrf_egu_channel_count(NRF_EGU4); i++) { const nrf_egu_event_t check_event = nrf_egu_triggered_event_get(i); SWI4_event_triggered_flag.triggered[i] = nrf_egu_event_check(NRF_EGU4, check_event); if (SWI4_event_triggered_flag.triggered[i]) { nrf_egu_event_clear(NRF_EGU4, check_event); } } } ZTEST(nrf_egu_tests, test_trigger_by_PPI) { nrf_ppi_channel_enable(NRF_PPI, NRF_PPI_CHANNEL0); nrf_ppi_channel_endpoint_setup(NRF_PPI, NRF_PPI_CHANNEL0, nrf_egu_event_address_get(NRF_EGU3, NRF_EGU_EVENT_TRIGGERED0), nrf_egu_task_address_get(NRF_EGU4, NRF_EGU_TASK_TRIGGER0)); memset(&SWI4_event_triggered_flag, 0, sizeof(SWI4_event_triggered_flag)); irq_connect_dynamic(SWI4_EGU4_IRQn, 0, SWI4_trigger_function, NULL, BIT(0)); /* configure egu4 */ nrf_egu_int_enable(NRF_EGU4, NRF_EGU_INT_TRIGGERED0); irq_enable(SWI4_EGU4_IRQn); /* trigger egu3 */ nrf_egu_task_trigger(NRF_EGU3, NRF_EGU_TASK_TRIGGER0); k_busy_wait(1000); irq_disable(SWI4_EGU4_IRQn); nrf_egu_int_disable(NRF_EGU4, NRF_EGU_INT_TRIGGERED0); /* EGU3 should forward the trigger to EGU4 via PPI, and SWI4 IRQ is expected */ /* IRQ for EGU3 is not enabled */ zassert_true(SWI4_event_triggered_flag.triggered[0], "Event 0 has not been triggered"); for (int i = 1 ; i < NRF_NEGU_NEVENTS; i++) { zassert_false(SWI4_event_triggered_flag.triggered[i], "Event %i has been triggered", i); } for (uint8_t i = 0; i < nrf_egu_channel_count(NRF_EGU4); i++) { const nrf_egu_event_t check_event = nrf_egu_triggered_event_get(i); zassert_false(nrf_egu_event_check(NRF_EGU4, check_event), "event %d has been triggered, but it shouldn't", i); } } static void test_clean_egu(void *ignored) { ARG_UNUSED(ignored); memset(NRF_EGU5, 0, sizeof(*NRF_EGU5)); } ZTEST_SUITE(nrf_egu_tests, NULL, NULL, test_clean_egu, test_clean_egu, NULL);