From d70961ad58375260b5eea5c622167d5f00f88cb1 Mon Sep 17 00:00:00 2001 From: morris Date: Fri, 3 Apr 2020 17:11:39 +0800 Subject: [PATCH] esp32s2: add more unit test for esp32s2 Most of the test cases are copied from esp32 add int_alloc test add delay test add random test --- components/esp32/test/test_intr_alloc.c | 16 +- components/esp32s2/test/test_delay.c | 73 ++++++ components/esp32s2/test/test_intr_alloc.c | 291 ++++++++++++++++++++++ components/esp32s2/test/test_random.c | 66 +++++ tools/ci/config/target-test.yml | 2 +- 5 files changed, 437 insertions(+), 11 deletions(-) create mode 100644 components/esp32s2/test/test_delay.c create mode 100644 components/esp32s2/test/test_intr_alloc.c create mode 100644 components/esp32s2/test/test_random.c diff --git a/components/esp32/test/test_intr_alloc.c b/components/esp32/test/test_intr_alloc.c index a477c543c..07442c33f 100644 --- a/components/esp32/test/test_intr_alloc.c +++ b/components/esp32/test/test_intr_alloc.c @@ -4,11 +4,7 @@ #include #include -#if CONFIG_IDF_TARGET_ESP32 #include "esp32/rom/ets_sys.h" -#elif CONFIG_IDF_TARGET_ESP32S2 -#include "esp32s2/rom/ets_sys.h" -#endif #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" @@ -187,22 +183,22 @@ void local_timer_test(void) } -TEST_CASE("Intr_alloc test, CPU-local int source", "[esp32]") +TEST_CASE("Intr_alloc test, CPU-local int source", "[intr_alloc]") { local_timer_test(); } -TEST_CASE("Intr_alloc test, private ints", "[esp32]") +TEST_CASE("Intr_alloc test, private ints", "[intr_alloc]") { timer_test(0); } -TEST_CASE("Intr_alloc test, shared ints", "[esp32]") +TEST_CASE("Intr_alloc test, shared ints", "[intr_alloc]") { timer_test(ESP_INTR_FLAG_SHARED); } -TEST_CASE("Can allocate IRAM int only with an IRAM handler", "[esp32]") +TEST_CASE("Can allocate IRAM int only with an IRAM handler", "[intr_alloc]") { void dummy(void* arg) { @@ -261,7 +257,7 @@ void IRAM_ATTR int_handler2(void* arg) } } -TEST_CASE("allocate 2 handlers for a same source and remove the later one","[esp32]") +TEST_CASE("allocate 2 handlers for a same source and remove the later one","[intr_alloc]") { intr_alloc_test_ctx_t ctx = {false, false, false, false }; intr_handle_t handle1, handle2; @@ -328,7 +324,7 @@ void isr_alloc_free_test(void) printf("test passed\n"); } -TEST_CASE("alloc and free isr handle on different core", "[esp32]") +TEST_CASE("alloc and free isr handle on different core", "[intr_alloc]") { isr_alloc_free_test(); } diff --git a/components/esp32s2/test/test_delay.c b/components/esp32s2/test/test_delay.c new file mode 100644 index 000000000..d04642c83 --- /dev/null +++ b/components/esp32s2/test/test_delay.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include "esp32s2/rom/ets_sys.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "unity.h" +#include "test_utils.h" + +typedef struct { + int delay_us; + int method; + int result; + SemaphoreHandle_t done; +} delay_test_arg_t; + +static void test_delay_task(void *p) +{ + delay_test_arg_t *arg = (delay_test_arg_t *)p; + vTaskDelay(1); + uint64_t start = ref_clock_get(); + switch (arg->method) { + case 0: + ets_delay_us(arg->delay_us); + break; + case 1: + vTaskDelay(arg->delay_us / portTICK_PERIOD_MS / 1000); + break; + default: + TEST_FAIL(); + } + uint64_t stop = ref_clock_get(); + + arg->result = (int)(stop - start); + xSemaphoreGive(arg->done); + vTaskDelete(NULL); +} + +TEST_CASE("ets_delay produces correct delay", "[delay]") +{ + int delay_ms = 50; + const delay_test_arg_t args = { + .delay_us = delay_ms * 1000, + .method = 0, + .done = xSemaphoreCreateBinary() + }; + ref_clock_init(); + xTaskCreatePinnedToCore(test_delay_task, "", 2048, (void *)&args, 3, NULL, 0); + TEST_ASSERT(xSemaphoreTake(args.done, delay_ms * 2 / portTICK_PERIOD_MS)); + TEST_ASSERT_INT32_WITHIN(1000, args.delay_us, args.result); + + ref_clock_deinit(); + vSemaphoreDelete(args.done); +} + +TEST_CASE("vTaskDelay produces correct delay", "[delay]") +{ + int delay_ms = 50; + const delay_test_arg_t args = { + .delay_us = delay_ms * 1000, + .method = 1, + .done = xSemaphoreCreateBinary() + }; + ref_clock_init(); + xTaskCreatePinnedToCore(test_delay_task, "", 2048, (void *)&args, 3, NULL, 0); + TEST_ASSERT(xSemaphoreTake(args.done, delay_ms * 2 / portTICK_PERIOD_MS)); + TEST_ASSERT_INT32_WITHIN(1000, args.delay_us, args.result); + + ref_clock_deinit(); + vSemaphoreDelete(args.done); +} diff --git a/components/esp32s2/test/test_intr_alloc.c b/components/esp32s2/test/test_intr_alloc.c new file mode 100644 index 000000000..b136a4720 --- /dev/null +++ b/components/esp32s2/test/test_intr_alloc.c @@ -0,0 +1,291 @@ +/* + Tests for the interrupt allocator. +*/ + +#include +#include "unity.h" +#include "esp_types.h" +#include "esp32s2/rom/ets_sys.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/queue.h" +#include "freertos/xtensa_api.h" +#include "soc/uart_periph.h" +#include "soc/dport_reg.h" +#include "soc/gpio_periph.h" +#include "esp_intr_alloc.h" +#include "driver/periph_ctrl.h" +#include "driver/timer.h" + +#define TIMER_DIVIDER 16 /*!< Hardware timer clock divider */ +#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) /*!< used to calculate counter value */ +#define TIMER_INTERVAL0_SEC (3.4179) /*!< test interval for timer 0 */ +#define TIMER_INTERVAL1_SEC (5.78) /*!< test interval for timer 1 */ + +static void my_timer_init(int timer_group, int timer_idx, int ival) +{ + timer_config_t config; + config.alarm_en = 1; + config.auto_reload = 1; + config.counter_dir = TIMER_COUNT_UP; + config.divider = TIMER_DIVIDER; + config.intr_type = TIMER_INTR_LEVEL; + config.counter_en = TIMER_PAUSE; + /*Configure timer*/ + timer_init(timer_group, timer_idx, &config); + /*Stop timer counter*/ + timer_pause(timer_group, timer_idx); + /*Load counter value */ + timer_set_counter_value(timer_group, timer_idx, 0x00000000ULL); + /*Set alarm value*/ + timer_set_alarm_value(timer_group, timer_idx, ival); + /*Enable timer interrupt*/ + timer_enable_intr(timer_group, timer_idx); +} + +static volatile int count[4] = {0, 0, 0, 0}; + +static void timer_isr(void *arg) +{ + int timer_idx = (int)arg; + count[timer_idx]++; + if (timer_idx == 0) { + timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_0); + timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_0); + } + if (timer_idx == 1) { + timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_1); + timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_1); + } + if (timer_idx == 2) { + timer_group_clr_intr_status_in_isr(TIMER_GROUP_1, TIMER_0); + timer_group_enable_alarm_in_isr(TIMER_GROUP_1, TIMER_0); + } + if (timer_idx == 3) { + timer_group_clr_intr_status_in_isr(TIMER_GROUP_1, TIMER_1); + timer_group_enable_alarm_in_isr(TIMER_GROUP_1, TIMER_1); + } +} + +static void timer_test(int flags) +{ + int x; + timer_isr_handle_t inth[4]; + my_timer_init(TIMER_GROUP_0, TIMER_0, 110000); + my_timer_init(TIMER_GROUP_0, TIMER_1, 120000); + my_timer_init(TIMER_GROUP_1, TIMER_0, 130000); + my_timer_init(TIMER_GROUP_1, TIMER_1, 140000); + timer_isr_register(TIMER_GROUP_0, TIMER_0, timer_isr, (void *)0, flags | ESP_INTR_FLAG_INTRDISABLED, &inth[0]); + timer_isr_register(TIMER_GROUP_0, TIMER_1, timer_isr, (void *)1, flags, &inth[1]); + timer_isr_register(TIMER_GROUP_1, TIMER_0, timer_isr, (void *)2, flags, &inth[2]); + timer_isr_register(TIMER_GROUP_1, TIMER_1, timer_isr, (void *)3, flags, &inth[3]); + timer_start(TIMER_GROUP_0, TIMER_0); + timer_start(TIMER_GROUP_0, TIMER_1); + timer_start(TIMER_GROUP_1, TIMER_0); + timer_start(TIMER_GROUP_1, TIMER_1); + + for (x = 0; x < 4; x++) { + count[x] = 0; + } + printf("Interrupts allocated: %d (dis) %d %d %d\n", + esp_intr_get_intno(inth[0]), esp_intr_get_intno(inth[1]), + esp_intr_get_intno(inth[2]), esp_intr_get_intno(inth[3])); + printf("Timer values on start: %d %d %d %d\n", count[0], count[1], count[2], count[3]); + vTaskDelay(1000 / portTICK_PERIOD_MS); + printf("Timer values after 1 sec: %d %d %d %d\n", count[0], count[1], count[2], count[3]); + TEST_ASSERT(count[0] == 0); + TEST_ASSERT(count[1] != 0); + TEST_ASSERT(count[2] != 0); + TEST_ASSERT(count[3] != 0); + + printf("Disabling timers 1 and 2...\n"); + esp_intr_enable(inth[0]); + esp_intr_disable(inth[1]); + esp_intr_disable(inth[2]); + for (x = 0; x < 4; x++) { + count[x] = 0; + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + printf("Timer values after 1 sec: %d %d %d %d\n", count[0], count[1], count[2], count[3]); + TEST_ASSERT(count[0] != 0); + TEST_ASSERT(count[1] == 0); + TEST_ASSERT(count[2] == 0); + TEST_ASSERT(count[3] != 0); + printf("Disabling other half...\n"); + esp_intr_enable(inth[1]); + esp_intr_enable(inth[2]); + esp_intr_disable(inth[0]); + esp_intr_disable(inth[3]); + for (x = 0; x < 4; x++) { + count[x] = 0; + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + printf("Timer values after 1 sec: %d %d %d %d\n", count[0], count[1], count[2], count[3]); + TEST_ASSERT(count[0] == 0); + TEST_ASSERT(count[1] != 0); + TEST_ASSERT(count[2] != 0); + TEST_ASSERT(count[3] == 0); + printf("Done.\n"); + esp_intr_free(inth[0]); + esp_intr_free(inth[1]); + esp_intr_free(inth[2]); + esp_intr_free(inth[3]); +} + +static volatile int int_timer_ctr; + +void int_timer_handler(void *arg) +{ + xthal_set_ccompare(1, xthal_get_ccount() + 8000000); + int_timer_ctr++; +} + +void local_timer_test(void) +{ + intr_handle_t ih; + esp_err_t r; + r = esp_intr_alloc(ETS_INTERNAL_TIMER1_INTR_SOURCE, 0, int_timer_handler, NULL, &ih); + TEST_ASSERT(r == ESP_OK); + printf("Int timer 1 intno %d\n", esp_intr_get_intno(ih)); + xthal_set_ccompare(1, xthal_get_ccount() + 8000000); + int_timer_ctr = 0; + vTaskDelay(1000 / portTICK_PERIOD_MS); + printf("Timer val after 1 sec: %d\n", int_timer_ctr); + TEST_ASSERT(int_timer_ctr != 0); + printf("Disabling int\n"); + esp_intr_disable(ih); + int_timer_ctr = 0; + vTaskDelay(1000 / portTICK_PERIOD_MS); + printf("Timer val after 1 sec: %d\n", int_timer_ctr); + TEST_ASSERT(int_timer_ctr == 0); + printf("Re-enabling\n"); + esp_intr_enable(ih); + vTaskDelay(1000 / portTICK_PERIOD_MS); + printf("Timer val after 1 sec: %d\n", int_timer_ctr); + TEST_ASSERT(int_timer_ctr != 0); + + printf("Free int, re-alloc disabled\n"); + r = esp_intr_free(ih); + TEST_ASSERT(r == ESP_OK); + r = esp_intr_alloc(ETS_INTERNAL_TIMER1_INTR_SOURCE, ESP_INTR_FLAG_INTRDISABLED, int_timer_handler, NULL, &ih); + TEST_ASSERT(r == ESP_OK); + int_timer_ctr = 0; + vTaskDelay(1000 / portTICK_PERIOD_MS); + printf("Timer val after 1 sec: %d\n", int_timer_ctr); + TEST_ASSERT(int_timer_ctr == 0); + printf("Re-enabling\n"); + esp_intr_enable(ih); + vTaskDelay(1000 / portTICK_PERIOD_MS); + printf("Timer val after 1 sec: %d\n", int_timer_ctr); + TEST_ASSERT(int_timer_ctr != 0); + r = esp_intr_free(ih); + TEST_ASSERT(r == ESP_OK); + printf("Done.\n"); +} + +TEST_CASE("Intr_alloc test, CPU-local int source", "[intr_alloc]") +{ + local_timer_test(); +} + +TEST_CASE("Intr_alloc test, private ints", "[intr_alloc]") +{ + timer_test(0); +} + +TEST_CASE("Intr_alloc test, shared ints", "[intr_alloc]") +{ + timer_test(ESP_INTR_FLAG_SHARED); +} + +TEST_CASE("Can allocate IRAM int only with an IRAM handler", "[intr_alloc]") +{ + void dummy(void *arg) { + } + IRAM_ATTR void dummy_iram(void *arg) { + } + RTC_IRAM_ATTR void dummy_rtc(void *arg) { + } + intr_handle_t ih; + esp_err_t err = esp_intr_alloc(ETS_INTERNAL_SW0_INTR_SOURCE, + ESP_INTR_FLAG_IRAM, &dummy, NULL, &ih); + TEST_ASSERT_EQUAL_INT(ESP_ERR_INVALID_ARG, err); + err = esp_intr_alloc(ETS_INTERNAL_SW0_INTR_SOURCE, + ESP_INTR_FLAG_IRAM, &dummy_iram, NULL, &ih); + TEST_ESP_OK(err); + err = esp_intr_free(ih); + TEST_ESP_OK(err); + err = esp_intr_alloc(ETS_INTERNAL_SW0_INTR_SOURCE, + ESP_INTR_FLAG_IRAM, &dummy_rtc, NULL, &ih); + TEST_ESP_OK(err); + err = esp_intr_free(ih); + TEST_ESP_OK(err); +} + +#include "soc/spi_periph.h" +typedef struct { + bool flag1; + bool flag2; + bool flag3; + bool flag4; +} intr_alloc_test_ctx_t; + +void IRAM_ATTR int_handler1(void *arg) +{ + intr_alloc_test_ctx_t *ctx = (intr_alloc_test_ctx_t *)arg; + ets_printf("handler 1 called.\n"); + if (ctx->flag1) { + ctx->flag3 = true; + } else { + ctx->flag1 = true; + } + GPSPI2.slave.trans_done = 0; +} + +void IRAM_ATTR int_handler2(void *arg) +{ + intr_alloc_test_ctx_t *ctx = (intr_alloc_test_ctx_t *)arg; + ets_printf("handler 2 called.\n"); + if (ctx->flag2) { + ctx->flag4 = true; + } else { + ctx->flag2 = true; + } +} + +TEST_CASE("allocate 2 handlers for a same source and remove the later one", "[intr_alloc]") +{ + intr_alloc_test_ctx_t ctx = {false, false, false, false}; + intr_handle_t handle1, handle2; + + //enable SPI2 + periph_module_enable(PERIPH_FSPI_MODULE); + + esp_err_t r; + r = esp_intr_alloc(ETS_SPI2_INTR_SOURCE, ESP_INTR_FLAG_SHARED, int_handler1, &ctx, &handle1); + TEST_ESP_OK(r); + //try an invalid assign first + r = esp_intr_alloc(ETS_SPI2_INTR_SOURCE, 0, int_handler2, NULL, &handle2); + TEST_ASSERT_EQUAL_INT(r, ESP_ERR_NOT_FOUND); + //assign shared then + r = esp_intr_alloc(ETS_SPI2_INTR_SOURCE, ESP_INTR_FLAG_SHARED, int_handler2, &ctx, &handle2); + TEST_ESP_OK(r); + GPSPI2.slave.int_trans_done_en = 1; + + printf("trigger first time.\n"); + GPSPI2.slave.trans_done = 1; + + vTaskDelay(100); + TEST_ASSERT(ctx.flag1 && ctx.flag2); + + printf("remove intr 1.\n"); + r = esp_intr_free(handle2); + + printf("trigger second time.\n"); + GPSPI2.slave.trans_done = 1; + + vTaskDelay(500); + TEST_ASSERT(ctx.flag3 && !ctx.flag4); + printf("test passed.\n"); +} diff --git a/components/esp32s2/test/test_random.c b/components/esp32s2/test/test_random.c new file mode 100644 index 000000000..083c79124 --- /dev/null +++ b/components/esp32s2/test/test_random.c @@ -0,0 +1,66 @@ +#include +#include +#include "unity.h" +#include "esp_system.h" + +/* Note: these are just sanity tests, not the same as + entropy tests +*/ + +TEST_CASE("call esp_random()", "[random]") +{ + const size_t NUM_RANDOM = 128; /* in most cases this is massive overkill */ + + uint32_t zeroes = UINT32_MAX; + uint32_t ones = 0; + for (int i = 0; i < NUM_RANDOM - 1; i++) { + uint32_t r = esp_random(); + ones |= r; + zeroes &= ~r; + } + + /* assuming a 'white' random distribution, we can expect + usually at least one time each bit will be zero and at + least one time each will be one. Statistically this + can still fail, just *very* unlikely to. */ + TEST_ASSERT_EQUAL_HEX32(0, zeroes); + TEST_ASSERT_EQUAL_HEX32(UINT32_MAX, ones); +} + +TEST_CASE("call esp_fill_random()", "[random]") +{ + const size_t NUM_BUF = 200; + const size_t BUF_SZ = 16; + uint8_t buf[NUM_BUF][BUF_SZ]; + uint8_t zero_buf[BUF_SZ]; + uint8_t one_buf[BUF_SZ]; + + bzero(buf, sizeof(buf)); + bzero(one_buf, sizeof(zero_buf)); + memset(zero_buf, 0xFF, sizeof(one_buf)); + + for (int i = 0; i < NUM_BUF; i++) { + esp_fill_random(buf[i], BUF_SZ); + } + /* No two 128-bit buffers should be the same + (again, statistically this could happen but it's very unlikely) */ + for (int i = 0; i < NUM_BUF; i++) { + for (int j = 0; j < NUM_BUF; j++) { + if (i != j) { + TEST_ASSERT_NOT_EQUAL(0, memcmp(buf[i], buf[j], BUF_SZ)); + } + } + } + + /* Do the same all bits are zero and one at least once test across the buffers */ + for (int i = 0; i < NUM_BUF; i++) { + for (int x = 0; x < BUF_SZ; x++) { + zero_buf[x] &= ~buf[i][x]; + one_buf[x] |= buf[i][x]; + } + } + for (int x = 0; x < BUF_SZ; x++) { + TEST_ASSERT_EQUAL_HEX8(0, zero_buf[x]); + TEST_ASSERT_EQUAL_HEX8(0xFF, one_buf[x]); + } +} diff --git a/tools/ci/config/target-test.yml b/tools/ci/config/target-test.yml index ba088a397..1ec77eac6 100644 --- a/tools/ci/config/target-test.yml +++ b/tools/ci/config/target-test.yml @@ -539,7 +539,7 @@ UT_034: UT_035: extends: .unit_test_s2_template - parallel: 36 + parallel: 38 tags: - ESP32S2_IDF - UT_T1_1