mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
ci freertos: Add test configs for some of the optional FreeRTOS 10 configurations
Also unit tests for the legacy hook functions.
This commit is contained in:
parent
bb74334830
commit
8a70b1cdc9
@ -1,7 +1,8 @@
|
||||
#include "sdkconfig.h"
|
||||
#include "unity.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
|
||||
#if defined(__XTENSA__)
|
||||
#if defined(__XTENSA__) && CONFIG_FREERTOS_CORETIMER_0
|
||||
#include "xtensa/config/core-isa.h"
|
||||
#include "xtensa/hal.h"
|
||||
#if defined(XCHAL_HAVE_WINDOWED)
|
||||
@ -40,4 +41,4 @@ TEST_CASE("context save doesn't corrupt return address register", "[freertos]")
|
||||
}
|
||||
|
||||
#endif // XCHAL_HAVE_WINDOWED
|
||||
#endif // __XTENSA__
|
||||
#endif // __XTENSA__ && CONFIG_FREERTOS_CORETIMER_0
|
||||
|
@ -216,6 +216,16 @@ TEST_CASE("Test FreeRTOS backported eventgroup functions", "[freertos]")
|
||||
//The variables pointed to by Thread Local Storage Pointer
|
||||
static uint32_t task_storage[portNUM_PROCESSORS][NO_OF_TLSP] = {0};
|
||||
|
||||
/* If static task cleanup is defined, can't set index 0 even if the calling task is not a pthread,
|
||||
as the cleanup is called for every task.
|
||||
*/
|
||||
#if defined(CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP)
|
||||
static const int skip_index = 0; /*PTHREAD_TLS_INDEX*/
|
||||
#else
|
||||
static const int skip_index = -1;
|
||||
#endif
|
||||
|
||||
|
||||
static void del_cb(int index, void *ptr)
|
||||
{
|
||||
*((uint32_t *)ptr) = (TLSP_DEL_BASE << index); //Indicate deletion by setting task storage element to a unique value
|
||||
@ -225,11 +235,19 @@ static void task_cb(void *arg)
|
||||
{
|
||||
int core = xPortGetCoreID();
|
||||
for(int i = 0; i < NO_OF_TLSP; i++){
|
||||
if (i == skip_index) {
|
||||
continue;
|
||||
}
|
||||
|
||||
task_storage[core][i] = (TLSP_SET_BASE << i); //Give each element of task_storage a unique number
|
||||
vTaskSetThreadLocalStoragePointerAndDelCallback(NULL, i, (void *)&task_storage[core][i], del_cb); //Set each TLSP to point to a task storage element
|
||||
}
|
||||
|
||||
for(int i = 0; i < NO_OF_TLSP; i++){
|
||||
if (i == skip_index) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t * tlsp = (uint32_t *)pvTaskGetThreadLocalStoragePointer(NULL, i);
|
||||
TEST_ASSERT_EQUAL(*tlsp, (TLSP_SET_BASE << i)); //Check if TLSP points to the correct task storage element by checking unique value
|
||||
}
|
||||
@ -247,6 +265,9 @@ TEST_CASE("Test FreeRTOS thread local storage pointers and del cb", "[freertos]"
|
||||
|
||||
for(int core = 0; core < portNUM_PROCESSORS; core++){
|
||||
for(int i = 0; i < NO_OF_TLSP; i++){
|
||||
if (i == skip_index) {
|
||||
continue;
|
||||
}
|
||||
TEST_ASSERT_EQUAL((TLSP_DEL_BASE << i), task_storage[core][i]); //Check del_cb ran by checking task storage for unique value
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "xtensa/hal.h"
|
||||
#include "esp_rom_sys.h"
|
||||
|
||||
#if CONFIG_FREERTOS_CORETIMER_0
|
||||
|
||||
static volatile int in_int_context, int_handled;
|
||||
|
||||
|
||||
@ -52,3 +54,5 @@ TEST_CASE("xPortInIsrContext test", "[freertos]")
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -4,6 +4,9 @@
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
/* If assertions aren't set to fail this code still crashes, but not with an abort... */
|
||||
#if CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER && CONFIG_FREERTOS_ASSERT_FAIL_ABORT
|
||||
|
||||
static void mutex_release_task(void* arg)
|
||||
{
|
||||
SemaphoreHandle_t mutex = (SemaphoreHandle_t) arg;
|
||||
@ -18,3 +21,5 @@ TEST_CASE("mutex released not by owner causes an assert", "[freertos][reset=abor
|
||||
xTaskCreate(&mutex_release_task, "mutex_release", 2048, mutex, UNITY_FREERTOS_PRIORITY + 1, NULL);
|
||||
vTaskDelay(1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
78
components/freertos/test/test_legacy_hooks.c
Normal file
78
components/freertos/test/test_legacy_hooks.c
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
Test of FreeRTOS "legacy" hook functions, and delete hook
|
||||
|
||||
Only compiled in if the relevant options are enabled.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include <freertos/semphr.h>
|
||||
#include "driver/timer.h"
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
#if CONFIG_FREERTOS_LEGACY_HOOKS
|
||||
|
||||
static volatile unsigned idle_count;
|
||||
|
||||
void vApplicationIdleHook(void)
|
||||
{
|
||||
idle_count++;
|
||||
}
|
||||
|
||||
TEST_CASE("legacy idle hook is correctly called based on config", "[freertos]")
|
||||
{
|
||||
idle_count = 0;
|
||||
vTaskDelay(10);
|
||||
TEST_ASSERT_NOT_EQUAL(0, idle_count); // The legacy idle hook should be called at least once
|
||||
}
|
||||
|
||||
static volatile unsigned tick_count;
|
||||
|
||||
void IRAM_ATTR vApplicationTickHook(void)
|
||||
{
|
||||
tick_count++;
|
||||
}
|
||||
|
||||
TEST_CASE("legacy tick hook is called based on config", "[freertos]")
|
||||
{
|
||||
unsigned before = xTaskGetTickCount();
|
||||
const unsigned SLEEP_FOR = 20;
|
||||
tick_count = before;
|
||||
vTaskDelay(SLEEP_FOR);
|
||||
TEST_ASSERT_UINT32_WITHIN_MESSAGE(3 * portNUM_PROCESSORS, before + SLEEP_FOR * portNUM_PROCESSORS, tick_count,
|
||||
"The legacy tick hook should have been called approx 1 time per tick per CPU");
|
||||
}
|
||||
|
||||
#endif // CONFIG_FREERTOS_LEGACY_HOOKS
|
||||
|
||||
#if CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP
|
||||
|
||||
static volatile void *deleted_tcb;
|
||||
|
||||
static void taskDeletesItself(void *ignored)
|
||||
{
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void vPortCleanUpTCB(void *pxTCB)
|
||||
{
|
||||
deleted_tcb = pxTCB;
|
||||
}
|
||||
|
||||
TEST_CASE("static task cleanup hook is called based on config", "[freertos]")
|
||||
{
|
||||
for(int i = 0; i < portNUM_PROCESSORS; i++) {
|
||||
printf("Creating task CPU %d\n", i);
|
||||
TaskHandle_t new_task = NULL;
|
||||
deleted_tcb = NULL;
|
||||
xTaskCreatePinnedToCore(taskDeletesItself, "delete", 2048, NULL, UNITY_FREERTOS_PRIORITY, &new_task, i);
|
||||
vTaskDelay(5);
|
||||
TEST_ASSERT_EQUAL_PTR(deleted_tcb, new_task); // TCB & TaskHandle are the same in FreeRTOS
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP
|
||||
|
||||
|
@ -129,6 +129,7 @@ void IRAM_ATTR timer_group0_isr(void *vp_arg)
|
||||
timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_0);
|
||||
|
||||
timer_isr_fired = true;
|
||||
|
||||
TaskHandle_t handle = vp_arg;
|
||||
BaseType_t higherPriorityTaskWoken = pdFALSE;
|
||||
higherPriorityTaskWoken = xTaskResumeFromISR(handle);
|
||||
@ -137,44 +138,70 @@ void IRAM_ATTR timer_group0_isr(void *vp_arg)
|
||||
}
|
||||
}
|
||||
|
||||
/* Task suspends itself, then sets parameter value to the current timer group counter and deletes itself */
|
||||
static void task_suspend_self_with_timer(void *vp_resumed)
|
||||
{
|
||||
volatile uint64_t *resumed_counter = vp_resumed;
|
||||
*resumed_counter = 0;
|
||||
vTaskSuspend(NULL);
|
||||
timer_get_counter_value(TIMER_GROUP_0, TIMER_0, vp_resumed);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
|
||||
/* Create a task which suspends itself, then resume it from a timer
|
||||
* interrupt. */
|
||||
static void test_resume_task_from_isr(int target_core)
|
||||
{
|
||||
volatile bool resumed = false;
|
||||
volatile uint64_t resumed_counter = 99;
|
||||
TaskHandle_t suspend_task;
|
||||
|
||||
xTaskCreatePinnedToCore(task_suspend_self, "suspend_self", 2048,
|
||||
(void *)&resumed, UNITY_FREERTOS_PRIORITY + 1,
|
||||
xTaskCreatePinnedToCore(task_suspend_self_with_timer, "suspend_self", 2048,
|
||||
(void *)&resumed_counter, UNITY_FREERTOS_PRIORITY + 1,
|
||||
&suspend_task, target_core);
|
||||
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_FALSE(resumed);
|
||||
TEST_ASSERT_EQUAL(0, resumed_counter);
|
||||
|
||||
const unsigned APB_CYCLES_PER_TICK = TIMER_BASE_CLK / configTICK_RATE_HZ;
|
||||
const unsigned TEST_TIMER_DIV = 2;
|
||||
const unsigned TEST_TIMER_CYCLES_PER_TICK = APB_CYCLES_PER_TICK / TEST_TIMER_DIV;
|
||||
const unsigned TEST_TIMER_CYCLES_PER_MS = TIMER_BASE_CLK / 1000 / TEST_TIMER_DIV;
|
||||
const unsigned TEST_TIMER_ALARM = TEST_TIMER_CYCLES_PER_TICK / 2; // half an RTOS tick
|
||||
|
||||
/* Configure timer ISR */
|
||||
timer_isr_handle_t isr_handle;
|
||||
const timer_config_t config = {
|
||||
.alarm_en = 1,
|
||||
.auto_reload = 0,
|
||||
.counter_dir = TIMER_COUNT_UP,
|
||||
.divider = 2, //Range is 2 to 65536
|
||||
.divider = TEST_TIMER_DIV,
|
||||
.intr_type = TIMER_INTR_LEVEL,
|
||||
.counter_en = TIMER_PAUSE,
|
||||
};
|
||||
/*Configure timer*/
|
||||
timer_init(TIMER_GROUP_0, TIMER_0, &config);
|
||||
timer_pause(TIMER_GROUP_0, TIMER_0);
|
||||
timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0);
|
||||
timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, 1000);
|
||||
timer_enable_intr(TIMER_GROUP_0, TIMER_0);
|
||||
timer_isr_register(TIMER_GROUP_0, TIMER_0, timer_group0_isr, (void*)suspend_task, ESP_INTR_FLAG_IRAM, NULL);
|
||||
ESP_ERROR_CHECK( timer_init(TIMER_GROUP_0, TIMER_0, &config) );
|
||||
ESP_ERROR_CHECK( timer_pause(TIMER_GROUP_0, TIMER_0) );
|
||||
ESP_ERROR_CHECK( timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0) );
|
||||
ESP_ERROR_CHECK( timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, TEST_TIMER_ALARM) );
|
||||
ESP_ERROR_CHECK( timer_enable_intr(TIMER_GROUP_0, TIMER_0) );
|
||||
ESP_ERROR_CHECK( timer_isr_register(TIMER_GROUP_0, TIMER_0, timer_group0_isr, (void*)suspend_task, ESP_INTR_FLAG_IRAM, &isr_handle) );
|
||||
timer_isr_fired = false;
|
||||
timer_start(TIMER_GROUP_0, TIMER_0);
|
||||
vTaskDelay(1); // Make sure we're at the start of a new tick
|
||||
|
||||
vTaskDelay(1);
|
||||
ESP_ERROR_CHECK( timer_start(TIMER_GROUP_0, TIMER_0) );
|
||||
|
||||
vTaskDelay(1); // We expect timer group will fire half-way through this delay
|
||||
|
||||
timer_deinit(TIMER_GROUP_0, TIMER_0);
|
||||
TEST_ASSERT_TRUE(timer_isr_fired);
|
||||
TEST_ASSERT_TRUE(resumed);
|
||||
TEST_ASSERT_NOT_EQUAL(0, resumed_counter);
|
||||
// The task should have woken within 500us of the timer interrupt event (note: task may be a flash cache miss)
|
||||
printf("alarm value %u task resumed at %u\n", TEST_TIMER_ALARM, (unsigned)resumed_counter);
|
||||
TEST_ASSERT_UINT32_WITHIN(TEST_TIMER_CYCLES_PER_MS/2, TEST_TIMER_ALARM, (unsigned)resumed_counter);
|
||||
|
||||
// clean up
|
||||
timer_deinit(TIMER_GROUP_0, TIMER_0);
|
||||
ESP_ERROR_CHECK( esp_intr_free(isr_handle) );
|
||||
}
|
||||
|
||||
TEST_CASE("Resume task from ISR (same core)", "[freertos]")
|
||||
@ -293,11 +320,11 @@ TEST_CASE("Test the waiting task not missed due to scheduler suspension on one C
|
||||
test_scheduler_suspend1(1);
|
||||
}
|
||||
|
||||
static uint32_t count_tick[2];
|
||||
static uint32_t tick_hook_ms[2];
|
||||
|
||||
static void IRAM_ATTR tick_hook(void)
|
||||
{
|
||||
++count_tick[xPortGetCoreID()];
|
||||
tick_hook_ms[xPortGetCoreID()] += portTICK_PERIOD_MS;
|
||||
}
|
||||
|
||||
static void test_scheduler_suspend2(int cpu)
|
||||
@ -305,7 +332,7 @@ static void test_scheduler_suspend2(int cpu)
|
||||
esp_register_freertos_tick_hook_for_cpu(tick_hook, 0);
|
||||
esp_register_freertos_tick_hook_for_cpu(tick_hook, 1);
|
||||
|
||||
memset(count_tick, 0, sizeof(count_tick));
|
||||
memset(tick_hook_ms, 0, sizeof(tick_hook_ms));
|
||||
|
||||
printf("Test for CPU%d\n", cpu);
|
||||
xTaskCreatePinnedToCore(&control_task, "control_task", 8192, NULL, 5, NULL, cpu);
|
||||
@ -313,10 +340,10 @@ static void test_scheduler_suspend2(int cpu)
|
||||
vTaskDelay(waiting_ms * 2 / portTICK_PERIOD_MS);
|
||||
esp_deregister_freertos_tick_hook(tick_hook);
|
||||
|
||||
printf("count_tick[cpu0] = %d, count_tick[cpu1] = %d\n", count_tick[0], count_tick[1]);
|
||||
printf("tick_hook_ms[cpu0] = %d, tick_hook_ms[cpu1] = %d\n", tick_hook_ms[0], tick_hook_ms[1]);
|
||||
|
||||
TEST_ASSERT_INT_WITHIN(1, waiting_ms * 2, count_tick[0]);
|
||||
TEST_ASSERT_INT_WITHIN(1, waiting_ms * 2, count_tick[1]);
|
||||
TEST_ASSERT_INT_WITHIN(portTICK_PERIOD_MS, waiting_ms * 2, tick_hook_ms[0]);
|
||||
TEST_ASSERT_INT_WITHIN(portTICK_PERIOD_MS, waiting_ms * 2, tick_hook_ms[1]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@ -337,7 +364,7 @@ static int duration_timer_ms;
|
||||
|
||||
static void timer_callback(void *arg)
|
||||
{
|
||||
++duration_timer_ms;
|
||||
duration_timer_ms += portTICK_PERIOD_MS;
|
||||
}
|
||||
|
||||
static void test_scheduler_suspend3(int cpu)
|
||||
|
@ -506,6 +506,9 @@ and ``vApplicationTickHook()`` can only be defined once. However, the ESP32 is d
|
||||
in nature, therefore same Idle Hook and Tick Hook are used for both cores (in other words,
|
||||
the hooks are symmetrical for both cores).
|
||||
|
||||
In a dual core system, ``vApplicationTickHook()`` must be located in IRAM (for example
|
||||
by adding the IRAM_ATTR attribute).
|
||||
|
||||
ESP-IDF Idle and Tick Hooks
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Due to the the dual core nature of the ESP32, it may be necessary for some
|
||||
|
24
tools/unit-test-app/configs/freertos_options
Normal file
24
tools/unit-test-app/configs/freertos_options
Normal file
@ -0,0 +1,24 @@
|
||||
# This is a small set of tests where we enable as many as possible of the optional features
|
||||
# in FreeRTOS that are gated behind config
|
||||
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
TEST_COMPONENTS=freertos
|
||||
|
||||
CONFIG_FREERTOS_CORETIMER_1=y
|
||||
CONFIG_FREERTOS_OPTIMIZED_SCHEDULER=n
|
||||
CONFIG_FREERTOS_HZ=500
|
||||
CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL=y
|
||||
CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y
|
||||
CONFIG_FREERTOS_INTERRUPT_BACKTRACE=n
|
||||
CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE=y
|
||||
CONFIG_FREERTOS_LEGACY_HOOKS=y
|
||||
CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
|
||||
CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP=y
|
||||
CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=10
|
||||
CONFIG_FREERTOS_USE_TRACE_FACILITY=y
|
||||
CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y
|
||||
CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y
|
||||
CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y
|
||||
CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
|
||||
CONFIG_FREERTOS_FPU_IN_ISR=y
|
||||
CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=16
|
23
tools/unit-test-app/configs/freertos_options_s2
Normal file
23
tools/unit-test-app/configs/freertos_options_s2
Normal file
@ -0,0 +1,23 @@
|
||||
# This is a small set of tests where we enable as many as possible of the optional features
|
||||
# in FreeRTOS that are gated behind config
|
||||
|
||||
CONFIG_IDF_TARGET="esp32s2"
|
||||
TEST_COMPONENTS=freertos
|
||||
|
||||
CONFIG_FREERTOS_CORETIMER_1=y
|
||||
CONFIG_FREERTOS_OPTIMIZED_SCHEDULER=n
|
||||
CONFIG_FREERTOS_HZ=500
|
||||
CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL=y
|
||||
CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y
|
||||
CONFIG_FREERTOS_INTERRUPT_BACKTRACE=n
|
||||
CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE=y
|
||||
CONFIG_FREERTOS_LEGACY_HOOKS=y
|
||||
CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
|
||||
CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP=y
|
||||
CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=10
|
||||
CONFIG_FREERTOS_USE_TRACE_FACILITY=y
|
||||
CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y
|
||||
CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y
|
||||
CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y
|
||||
CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
|
||||
CONFIG_FREERTOS_FPU_IN_ISR=y
|
Loading…
x
Reference in New Issue
Block a user