1 /*
2 Unit tests for FreeRTOS preemption
3 */
4
5 #include <esp_types.h>
6 #include <stdio.h>
7
8 #include "freertos/FreeRTOS.h"
9 #include "freertos/task.h"
10 #include "freertos/semphr.h"
11 #include "freertos/queue.h"
12 #include "unity.h"
13 #include "soc/cpu.h"
14 #include "hal/cpu_hal.h"
15 #include "test_utils.h"
16 #include "sdkconfig.h"
17
18 static volatile bool trigger;
19 static volatile bool flag;
20
21 /* Task:
22 - Waits for 'trigger' variable to be set
23 - Reads the cycle count on this CPU
24 - Pushes it into a queue supplied as a param
25 - Busy-waits until the main task terminates it
26 */
task_send_to_queue(void * param)27 static void task_send_to_queue(void *param)
28 {
29 QueueHandle_t queue = (QueueHandle_t) param;
30 uint32_t ccount;
31
32 while(!trigger) {}
33
34 ccount = cpu_hal_get_cycle_count();
35 flag = true;
36 xQueueSendToBack(queue, &ccount, 0);
37 /* This is to ensure that higher priority task
38 won't wake anyhow, due to this task terminating.
39
40 The task runs until terminated by the main task.
41 */
42 while(1) {}
43 }
44
45 TEST_CASE("Yield from lower priority task, same CPU", "[freertos]")
46 {
47 /* Do this 3 times, mostly for the benchmark value - the first
48 run includes a cache miss so uses more cycles than it should. */
49 for (int i = 0; i < 3; i++) {
50 TaskHandle_t sender_task;
51 QueueHandle_t queue = xQueueCreate(1, sizeof(uint32_t));
52 flag = false;
53 trigger = false;
54
55 /* "yield" task sits on our CPU, lower priority to us */
56 xTaskCreatePinnedToCore(task_send_to_queue, "YIELD", 2048, (void *)queue, UNITY_FREERTOS_PRIORITY - 1, &sender_task, UNITY_FREERTOS_CPU);
57
58 vTaskDelay(1); /* make sure everything is set up */
59 trigger = true;
60
61 uint32_t yield_ccount, now_ccount, delta;
62 TEST_ASSERT( xQueueReceive(queue, &yield_ccount, 100 / portTICK_PERIOD_MS) );
63 now_ccount = cpu_hal_get_cycle_count();
64 TEST_ASSERT( flag );
65
66 delta = now_ccount - yield_ccount;
67 printf("Yielding from lower priority task took %u cycles\n", delta);
68 TEST_ASSERT(delta < 10000);
69
70 vTaskDelete(sender_task);
71 vQueueDelete(queue);
72 }
73 }
74
75
76 #if (portNUM_PROCESSORS == 2) && !CONFIG_FREERTOS_TASK_FUNCTIONS_INTO_FLASH
77 TEST_CASE("Yield from lower priority task, other CPU", "[freertos]")
78 {
79 uint32_t trigger_ccount, yield_ccount, now_ccount, delta;
80
81 /* Do this 3 times, mostly for the benchmark value - the first
82 run includes a cache miss so uses more cycles than it should. */
83 for (int i = 0; i < 3; i++) {
84 TaskHandle_t sender_task;
85 QueueHandle_t queue = xQueueCreate(1, sizeof(uint32_t));
86 trigger = false;
87 flag = false;
88
89 /* "send_to_queue" task sits on the other CPU, lower priority to us */
90 xTaskCreatePinnedToCore(task_send_to_queue, "YIELD", 2048, (void *)queue, UNITY_FREERTOS_PRIORITY - 1,
91 &sender_task, !UNITY_FREERTOS_CPU);
92
93 vTaskDelay(2); /* make sure everything is set up */
94 trigger = true;
95 trigger_ccount = cpu_hal_get_cycle_count();
96
97 // yield_ccount is not useful in this test as it's the other core's CCOUNT
98 // so we use trigger_ccount instead
99 TEST_ASSERT( xQueueReceive(queue, &yield_ccount, 100 / portTICK_PERIOD_MS) );
100 now_ccount = cpu_hal_get_cycle_count();
101 TEST_ASSERT( flag );
102
103 delta = now_ccount - trigger_ccount;
104 printf("Yielding from task on other core took %u cycles\n", delta);
105 TEST_ASSERT(delta < 10000);
106
107 vQueueDelete(queue);
108 vTaskDelete(sender_task);
109 }
110 }
111 #endif
112