diff --git a/components/freertos/test/integration/portTestMacro.h b/components/freertos/test/integration/portTestMacro.h index 42bfb2662c..f46a2048aa 100644 --- a/components/freertos/test/integration/portTestMacro.h +++ b/components/freertos/test/integration/portTestMacro.h @@ -5,9 +5,12 @@ */ #include "test_utils.h" -#include "esp_cpu.h" #define configTEST_DEFAULT_STACK_SIZE 4096 #define configTEST_UNITY_TASK_PRIORITY UNITY_FREERTOS_PRIORITY -#define portTEST_GET_TIME() ((UBaseType_t) esp_cpu_get_cycle_count()) +#define portTEST_REF_CLOCK_TYPE uint32_t +#define portTEST_REF_CLOCK_INIT() ref_clock_init() +#define portTEST_REF_CLOCK_DEINIT() ref_clock_deinit() +#define portTEST_REF_CLOCK_GET_TIME() ((uint32_t) ref_clock_get()) +#define portTEST_TICKS_TO_REF_CLOCK(ticks) ((ticks) * (1000000/configTICK_RATE_HZ)) diff --git a/components/freertos/test/integration/tasks/test_task_delay.c b/components/freertos/test/integration/tasks/test_task_delay.c index 921427e8ea..9a54db40b5 100644 --- a/components/freertos/test/integration/tasks/test_task_delay.c +++ b/components/freertos/test/integration/tasks/test_task_delay.c @@ -4,76 +4,160 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" +#include "unity.h" +#include "freertos_test_utils.h" +#include "portTestMacro.h" + +/* ------------------------------------------------------------------------------------------------------------------ */ + /* - Test for FreeRTOS vTaskDelayUntil() function by comparing the delay period of - the function to comparing it to ref clock. +Test vTaskDelay + +Purpose: + - Test that vTaskDelay is accurate +Procedure: + - The test contains TEST_VTASKDELAY_ITERATIONS number of iterations. For each iteration... + - vTaskDelay(1) to align to next tick boundary + - Store current tick count and current time (using ref clock) + - vTaskDelay for TEST_VTASKDELAY_TICKS + - Get post delay tick count and ref clock time + - For single core, run the test directly from the UnityTask + - For SMP, run the test once on each core (using vTestOnAllCores()) +Expected: + - The elapsed ticks should be TEST_VTASKDELAY_TICKS, with 1 tick of error allowed (in case ref clock functions last + long enough to cross a tick boundary). + - The elapsed time should be equivalent to TEST_VTASKDELAY_TICKS tick periods, with 1 tick period of error allowed + (in case ref clock functions last longer that a tick period). */ -#include -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include "unity.h" -#include "test_utils.h" +#if ( INCLUDE_vTaskDelay == 1 ) -#define TSK_PRIORITY (UNITY_FREERTOS_PRIORITY + 1) +#define TEST_VTASKDELAY_TICKS 5 // Number of ticks to delay in test +#define TEST_VTASKDELAY_ITERATIONS 5 // Number of iterations in test -#define NO_OF_CYCLES 5 -#define NO_OF_TASKS_PER_CORE 2 -#define TICKS_TO_DELAY 10 -#define TICK_RATE configTICK_RATE_HZ -#define TICK_PERIOD_US (1000000/TICK_RATE) -#define IDEAL_DELAY_PERIOD_MS ((1000*TICKS_TO_DELAY)/TICK_RATE) -#define IDEAL_DELAY_PERIOD_US (IDEAL_DELAY_PERIOD_MS*1000) - -#define TICKS_TO_MS(x) (((x)*1000)/TICK_RATE) -#define REF_TO_ROUND_MS(x) (((x)+500)/1000) - -static SemaphoreHandle_t task_delete_semphr; - -static void delaying_task(void* arg) +static void test_vTaskDelay(void *arg) { - uint64_t ref_prev, ref_current; - TickType_t last_wake_time; - TickType_t ticks_before_delay; + for (int i = 0; i < TEST_VTASKDELAY_ITERATIONS; i++) { + TickType_t tick_start, tick_end; + portTEST_REF_CLOCK_TYPE ref_clock_start, ref_clock_end; - vTaskDelay(1); //Delay until next tick to synchronize operations to tick boundaries + /* Delay until the next tick boundary */ + vTaskDelay(1); - last_wake_time = xTaskGetTickCount(); - ticks_before_delay = last_wake_time; - ref_prev = ref_clock_get(); + /* Get the current tick count and ref clock time */ + tick_start = xTaskGetTickCount(); + ref_clock_start = portTEST_REF_CLOCK_GET_TIME(); - for(int i = 0; i < NO_OF_CYCLES; i++){ - //Delay of TICKS_TO_DELAY - vTaskDelayUntil(&last_wake_time, TICKS_TO_DELAY); - //Get current ref clock - TEST_ASSERT_EQUAL(IDEAL_DELAY_PERIOD_MS, TICKS_TO_MS(xTaskGetTickCount() - ticks_before_delay)); - ref_current = ref_clock_get(); - TEST_ASSERT_UINT32_WITHIN(TICK_PERIOD_US, IDEAL_DELAY_PERIOD_US, (uint32_t)(ref_current - ref_prev)); - ref_prev = ref_current; - ticks_before_delay = last_wake_time; + vTaskDelay(TEST_VTASKDELAY_TICKS); + + /* Get the post delay tick count and ref clock time */ + tick_end = xTaskGetTickCount(); + ref_clock_end = portTEST_REF_CLOCK_GET_TIME(); + + /* Check that elapsed ticks and ref clock is accurate. We allow 1 tick of error in case vTaskDelay() was called + * right before/after the tick boundary. */ + #if ( configUSE_16_BIT_TICKS == 1 ) + TEST_ASSERT_UINT16_WITHIN(1, TEST_VTASKDELAY_TICKS, tick_end - tick_start); + #else + TEST_ASSERT_UINT32_WITHIN(1, TEST_VTASKDELAY_TICKS, tick_end - tick_start); + #endif + TEST_ASSERT_UINT32_WITHIN(portTEST_TICKS_TO_REF_CLOCK(1), + portTEST_TICKS_TO_REF_CLOCK(TEST_VTASKDELAY_TICKS), + ref_clock_end - ref_clock_start); } - - //Delete Task after prescribed number of cycles - xSemaphoreGive(task_delete_semphr); - vTaskDelete(NULL); } -TEST_CASE("Test vTaskDelayUntil", "[freertos]") +TEST_CASE("Tasks: Test vTaskDelay", "[freertos]") { - task_delete_semphr = xQueueCreateCountingSemaphore(NO_OF_TASKS_PER_CORE*portNUM_PROCESSORS, 0); - ref_clock_init(); + portTEST_REF_CLOCK_INIT(); - for(int i = 0; i < portNUM_PROCESSORS; i++){ - xTaskCreatePinnedToCore(delaying_task, "delay_pinned", 1024, NULL, TSK_PRIORITY, NULL, i); - xTaskCreatePinnedToCore(delaying_task, "delay_no_aff", 1024, NULL, TSK_PRIORITY, NULL, tskNO_AFFINITY); - } + #if ( configNUM_CORES > 1 ) + vTestOnAllCores(test_vTaskDelay, NULL, configTEST_DEFAULT_STACK_SIZE, configTEST_UNITY_TASK_PRIORITY - 1); + #else + /* Test vTaskDelay directly on the current core */ + test_vTaskDelay(NULL); + #endif - for(int i = 0; i < NO_OF_TASKS_PER_CORE*portNUM_PROCESSORS; i++){ - xSemaphoreTake(task_delete_semphr, portMAX_DELAY); - } - //Cleanup - vSemaphoreDelete(task_delete_semphr); - ref_clock_deinit(); + portTEST_REF_CLOCK_DEINIT(); } + +#endif /* ( INCLUDE_vTaskDelay == 1 ) */ + +/* ------------------------------------------------------------------------------------------------------------------ */ + +/* +Test vTaskDelayUntil + +Purpose: + - Test that vTaskDelayUntil is accurate +Procedure: + - The test contains TEST_VTASKDELAYUNTIL_ITERATIONS number of iterations. For each iteration... + - vTaskDelay(1) to align to next tick boundary + - Store current tick count and current time (using ref clock) + - Call vTaskDelayUntil() for TEST_VTASKDELAYUNTIL_TICKS, using the stored tick count as the previous wake time + - Get post delay tick count and ref clock time + - For single core, run the test directly from the UnityTask + - For SMP, run the test once on each core (using vTestOnAllCores()) +Expected: + - The elapsed ticks should be exactly TEST_VTASKDELAYUNTIL_TICKS since vTaskDelayUntil() is relative to the previous + wake time + - The elapsed time should be equivalent to TEST_VTASKDELAYUNTIL_TICKS tick periods, with 1 tick period of error + allowed (in case ref clock functions last longer that a tick period). +*/ + +#if ( INCLUDE_xTaskDelayUntil == 1 ) + +#define TEST_VTASKDELAYUNTIL_TICKS 5 // Number of ticks to delay in test +#define TEST_VTASKDELAYUNTIL_ITERATIONS 5 // Number of iterations in test + +static void test_vTaskDelayUntil(void *arg) +{ + /* Delay until the next tick boundary */ + vTaskDelay(1); + + for (int i = 0; i < TEST_VTASKDELAYUNTIL_ITERATIONS; i++) { + TickType_t tick_start, tick_end, last_wake_tick; + portTEST_REF_CLOCK_TYPE ref_clock_start, ref_clock_end; + + /* Get the current tick count and ref clock time */ + tick_start = xTaskGetTickCount(); + last_wake_tick = tick_start; + ref_clock_start = portTEST_REF_CLOCK_GET_TIME(); + + vTaskDelayUntil(&last_wake_tick, TEST_VTASKDELAYUNTIL_TICKS); + + /* Get the post delay tick count and ref clock time */ + tick_end = xTaskGetTickCount(); + ref_clock_end = portTEST_REF_CLOCK_GET_TIME(); + + /* Check that the elapsed ticks is accurate. Elapsed ticks should be exact as vTaskDelayUntil() executes a + * delay relative to last_wake_tick. */ + TEST_ASSERT_EQUAL(TEST_VTASKDELAYUNTIL_TICKS, tick_end - tick_start); + TEST_ASSERT_EQUAL(tick_end, last_wake_tick); + + /* Check that the elapsed ref clock time is accurate. We allow 1 tick time worth of error to account for the + * the execution time of the ref clock functions. */ + TEST_ASSERT_UINT32_WITHIN(portTEST_TICKS_TO_REF_CLOCK(1), + portTEST_TICKS_TO_REF_CLOCK(TEST_VTASKDELAYUNTIL_TICKS), + ref_clock_end - ref_clock_start); + } +} + +TEST_CASE("Tasks: Test vTaskDelayUntil", "[freertos]") +{ + portTEST_REF_CLOCK_INIT(); + + #if ( configNUM_CORES > 1 ) + vTestOnAllCores(test_vTaskDelayUntil, NULL, configTEST_DEFAULT_STACK_SIZE, configTEST_UNITY_TASK_PRIORITY - 1); + #else + /* Test vTaskDelay directly on the current core */ + test_vTaskDelayUntil(NULL); + #endif + + portTEST_REF_CLOCK_DEINIT(); +} + +#endif /* ( INCLUDE_xTaskDelayUntil == 1 ) */