|
| 1 | +/* |
| 2 | + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: Apache-2.0 |
| 5 | + */ |
| 6 | + |
| 7 | +#include <zephyr/kernel.h> |
| 8 | +#include <zephyr/ztest.h> |
| 9 | +#include <zephyr/device.h> |
| 10 | +#include <zephyr/devicetree.h> |
| 11 | +#include <zephyr/drivers/counter.h> |
| 12 | +#include <zephyr/sys/printk.h> |
| 13 | + |
| 14 | +/* Test sets the three timer units, each with different interrupt priority level. |
| 15 | + * Each timer/counter is set to respond to three separate alarms. |
| 16 | + * The alarm times are set so each would trigger one after another separated by |
| 17 | + * the `ALARM_DIFF_US` time. |
| 18 | + * Each ISR sets its corresponding token into its token slots and wait for the |
| 19 | + * subsequent alarm ISR to be called. |
| 20 | + * After the last alarm ISR finishes the main loop checks if the ISR were called. |
| 21 | + */ |
| 22 | + |
| 23 | +#define TOKEN_A 0xBEEFBABE |
| 24 | +#define TOKEN_B 0xC0FEB00B |
| 25 | +#define TOKEN_C 0xDEAD5AA5 |
| 26 | + |
| 27 | +#define ALARM_DIFF_US 1000 |
| 28 | +#define ALARM_A_US (1000 + ALARM_DIFF_US) |
| 29 | +#define ALARM_B_US (ALARM_A_US + ALARM_DIFF_US) |
| 30 | +#define ALARM_C_US (ALARM_B_US + ALARM_DIFF_US) |
| 31 | +#define ISR_DELAY_US (ALARM_DIFF_US * 3) |
| 32 | +#define CYCLE_MS 10 |
| 33 | +#define TEST_CYCLES 1000 |
| 34 | + |
| 35 | +static const struct device *const timer0 = DEVICE_DT_GET(DT_INST(0, espressif_esp32_counter)); |
| 36 | +static const struct device *const timer1 = DEVICE_DT_GET(DT_INST(1, espressif_esp32_counter)); |
| 37 | +static const struct device *const timer2 = DEVICE_DT_GET(DT_INST(2, espressif_esp32_counter)); |
| 38 | + |
| 39 | +static struct counter_alarm_cfg alarm_a; |
| 40 | +static struct counter_alarm_cfg alarm_b; |
| 41 | +static struct counter_alarm_cfg alarm_c; |
| 42 | + |
| 43 | +static int token[3]; |
| 44 | +static int success_cnt; |
| 45 | +static int error_cnt; |
| 46 | + |
| 47 | +static void alarm_handler_c(const struct device *dev, uint8_t chan_id, uint32_t counter, |
| 48 | + void *user_data) |
| 49 | +{ |
| 50 | + if (dev == timer2 && token[0] == TOKEN_A && token[1] == TOKEN_B && token[2] == 0) { |
| 51 | + token[2] = TOKEN_C; |
| 52 | + } |
| 53 | + |
| 54 | + k_busy_wait(ISR_DELAY_US); |
| 55 | +} |
| 56 | + |
| 57 | +static void alarm_handler_b(const struct device *dev, uint8_t chan_id, uint32_t counter, |
| 58 | + void *user_data) |
| 59 | +{ |
| 60 | + if (dev == timer1 && token[0] == TOKEN_A && token[1] == 0 && token[2] == 0) { |
| 61 | + token[1] = TOKEN_B; |
| 62 | + } |
| 63 | + |
| 64 | + k_busy_wait(ISR_DELAY_US); |
| 65 | +} |
| 66 | + |
| 67 | +static void alarm_handler_a(const struct device *dev, uint8_t chan_id, uint32_t counter, |
| 68 | + void *user_data) |
| 69 | +{ |
| 70 | + if (dev == timer0 && token[0] == 0 && token[1] == 0 && token[2] == 0) { |
| 71 | + token[0] = TOKEN_A; |
| 72 | + } |
| 73 | + |
| 74 | + k_busy_wait(ISR_DELAY_US); |
| 75 | +} |
| 76 | + |
| 77 | +static void *esp_interrupt_suite_setup(void) |
| 78 | +{ |
| 79 | + zassert_true(device_is_ready(timer0), "Device %s not ready", timer0->name); |
| 80 | + zassert_true(device_is_ready(timer1), "Device %s not ready", timer1->name); |
| 81 | + zassert_true(device_is_ready(timer2), "Device %s not ready", timer2->name); |
| 82 | + |
| 83 | + zassert_false(counter_start(timer0), "Timer 0 failed to start"); |
| 84 | + zassert_false(counter_start(timer1), "Timer 1 failed to start"); |
| 85 | + zassert_false(counter_start(timer2), "Timer 2 failed to start"); |
| 86 | + |
| 87 | + return NULL; |
| 88 | +} |
| 89 | + |
| 90 | + |
| 91 | +ZTEST(esp_interrupt, test_nested_isr) |
| 92 | +{ |
| 93 | + uint32_t cnt = TEST_CYCLES; |
| 94 | + |
| 95 | + success_cnt = 0; |
| 96 | + error_cnt = 0; |
| 97 | + |
| 98 | + while (cnt--) { |
| 99 | + alarm_a.ticks = counter_us_to_ticks(timer0, ALARM_A_US); |
| 100 | + alarm_a.callback = alarm_handler_a; |
| 101 | + |
| 102 | + alarm_b.ticks = counter_us_to_ticks(timer1, ALARM_B_US); |
| 103 | + alarm_b.callback = alarm_handler_b; |
| 104 | + |
| 105 | + alarm_c.ticks = counter_us_to_ticks(timer2, ALARM_C_US); |
| 106 | + alarm_c.callback = alarm_handler_c; |
| 107 | + |
| 108 | + counter_reset(timer0); |
| 109 | + counter_reset(timer1); |
| 110 | + counter_reset(timer2); |
| 111 | + |
| 112 | + zassert_false(counter_set_channel_alarm(timer0, 0, &alarm_a), |
| 113 | + "Failed to set alarm A"); |
| 114 | + zassert_false(counter_set_channel_alarm(timer1, 0, &alarm_b), |
| 115 | + "Failed to set alarm B"); |
| 116 | + zassert_false(counter_set_channel_alarm(timer2, 0, &alarm_c), |
| 117 | + "Failed to set alarm C"); |
| 118 | + |
| 119 | + k_msleep(CYCLE_MS); |
| 120 | + |
| 121 | + if (token[0] == TOKEN_A && token[1] == TOKEN_B && token[2] == TOKEN_C) { |
| 122 | + success_cnt++; |
| 123 | + } else { |
| 124 | + error_cnt++; |
| 125 | + } |
| 126 | + |
| 127 | + token[0] = 0; |
| 128 | + token[1] = 0; |
| 129 | + token[2] = 0; |
| 130 | + } |
| 131 | + |
| 132 | + zassert_true(error_cnt == 0, "Errors occurred (%d)", error_cnt); |
| 133 | + zassert_true(success_cnt == TEST_CYCLES, "Not all test cycles pssed (%d from %d)", |
| 134 | + success_cnt, TEST_CYCLES); |
| 135 | +} |
| 136 | + |
| 137 | +ZTEST_SUITE(esp_interrupt, NULL, esp_interrupt_suite_setup, NULL, NULL, NULL); |
0 commit comments