1 /*
2 Test of FreeRTOS task notifications. This test creates a sender and receiver
3 task under different core permutations. For each permutation, the sender task
4 will test the xTaskNotify(), xTaskNotifyGive(), xTaskNotifyFromISR(), and
5 vTaskNotifyGiveFromISR(), whereas the receiver task will test
6 xTaskNotifyWait() and ulTaskNotifyTake().
7 */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include "freertos/FreeRTOS.h"
11 #include "freertos/task.h"
12 #include <freertos/semphr.h>
13 #include "driver/timer.h"
14 #ifndef CONFIG_FREERTOS_UNICORE
15 #include "esp_ipc.h"
16 #endif
17 #include "unity.h"
18 #include "test_utils.h"
19
20 #ifdef CONFIG_IDF_TARGET_ESP32S2
21 #define int_clr_timers int_clr
22 #define update update.update
23 #define int_st_timers int_st
24 #endif
25
26 #define NO_OF_NOTIFS 4
27 #define NO_OF_TASKS 2 //Sender and receiver
28 #define TIMER_DIVIDER 10000
29 #define TIMER_COUNT 100
30 #define MESSAGE 0xFF
31
32 static uint32_t send_core_message = 0;
33 static TaskHandle_t rec_task_handle;
34 static bool isr_give = false;
35
36 static SemaphoreHandle_t trigger_send_semphr;
37 static SemaphoreHandle_t task_delete_semphr;
38
39 //Test tracking vars
40 static volatile uint32_t notifs_sent = 0;
41 static volatile uint32_t notifs_rec = 0;
42 static bool wrong_core = false;
43
sender_task(void * arg)44 static void sender_task (void* arg){
45 int curcore = xPortGetCoreID();
46
47 //Test xTaskNotify
48 xSemaphoreTake(trigger_send_semphr, portMAX_DELAY);
49 notifs_sent++;
50 xTaskNotify(rec_task_handle, (MESSAGE << curcore), eSetValueWithOverwrite);
51
52 //Test xTaskNotifyGive
53 xSemaphoreTake(trigger_send_semphr, portMAX_DELAY);
54 notifs_sent++;
55 xTaskNotifyGive(rec_task_handle);
56
57 //Test xTaskNotifyFromISR
58 xSemaphoreTake(trigger_send_semphr, portMAX_DELAY);
59 isr_give = false;
60 timer_start(TIMER_GROUP_0, curcore);
61
62 //Test vTaskNotifyGiveFromISR
63 xSemaphoreTake(trigger_send_semphr, portMAX_DELAY);
64 isr_give = true;
65 timer_start(TIMER_GROUP_0, curcore);
66
67 //Delete Task and Semaphores
68 xSemaphoreGive(task_delete_semphr);
69 vTaskDelete(NULL);
70 }
71
receiver_task(void * arg)72 static void receiver_task (void* arg){
73 uint32_t notify_value;
74
75 //Test xTaskNotifyWait from task
76 xTaskNotifyWait(0, 0xFFFFFFFF, ¬ify_value, portMAX_DELAY);
77 if(notify_value != send_core_message){
78 wrong_core = true;
79 }
80 notifs_rec++;
81
82 //Test ulTaskNotifyTake from task
83 xSemaphoreGive(trigger_send_semphr);
84 ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
85 notifs_rec++;
86
87 //Test xTaskNotifyWait from ISR
88 xSemaphoreGive(trigger_send_semphr);
89 xTaskNotifyWait(0, 0xFFFFFFFF, ¬ify_value, portMAX_DELAY);
90 if(notify_value != send_core_message){
91 wrong_core = true;
92 }
93 notifs_rec++;
94
95 //Test ulTaskNotifyTake from ISR
96 xSemaphoreGive(trigger_send_semphr);
97 ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
98 notifs_rec++;
99
100 //Test complete, stop timer and delete task
101 xSemaphoreGive(task_delete_semphr);
102 vTaskDelete(NULL);
103 }
104
sender_ISR(void * arg)105 static void IRAM_ATTR sender_ISR (void *arg)
106 {
107 int curcore = xPortGetCoreID();
108 timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, curcore);
109 timer_group_set_counter_enable_in_isr(TIMER_GROUP_0, curcore, TIMER_PAUSE);
110 //Re-enable alarm
111 timer_group_enable_alarm_in_isr(TIMER_GROUP_0, curcore);
112
113 if(isr_give){ //Test vTaskNotifyGiveFromISR() on same core
114 notifs_sent++;
115 vTaskNotifyGiveFromISR(rec_task_handle, NULL);
116 }
117 else { //Test xTaskNotifyFromISR()
118 notifs_sent++;
119 xTaskNotifyFromISR(rec_task_handle, (MESSAGE << curcore), eSetValueWithOverwrite, NULL);
120 }
121 portYIELD_FROM_ISR();
122 return;
123 }
124
timerg0_init(void * isr_handle)125 static void timerg0_init(void *isr_handle)
126 {
127 int timer_group = TIMER_GROUP_0;
128 int timer_idx = xPortGetCoreID();
129
130 timer_config_t config;
131 config.alarm_en = 1;
132 config.auto_reload = 1;
133 config.counter_dir = TIMER_COUNT_UP;
134 config.divider = TIMER_DIVIDER;
135 config.intr_type = TIMER_INTR_LEVEL;
136 config.counter_en = TIMER_PAUSE;
137
138 /*Configure timer*/
139 timer_init(timer_group, timer_idx, &config);
140 /*Stop timer counter*/
141 timer_pause(timer_group, timer_idx);
142 /*Load counter value */
143 timer_set_counter_value(timer_group, timer_idx, 0x00000000ULL);
144 /*Set alarm value*/
145 timer_set_alarm_value(timer_group, timer_idx, TIMER_COUNT);
146 /*Enable timer interrupt*/
147 timer_enable_intr(timer_group, timer_idx);
148 //Auto Reload
149 timer_set_auto_reload(timer_group, timer_idx, 1);
150 /*Set ISR handler*/
151 timer_isr_register(timer_group, timer_idx, sender_ISR, NULL, ESP_INTR_FLAG_IRAM, (intr_handle_t *)isr_handle);
152 }
153
timerg0_deinit(void * isr_handle)154 static void timerg0_deinit(void* isr_handle)
155 {
156 int timer_group = TIMER_GROUP_0;
157 int timer_idx = xPortGetCoreID();
158 intr_handle_t handle = *((intr_handle_t *) isr_handle);
159 //Pause timer then free registered ISR
160 timer_pause(timer_group, timer_idx);
161 esp_intr_free(handle);
162 }
163
164 TEST_CASE("Test Task_Notify", "[freertos]")
165 {
166 //Initialize and pause timers. Used to trigger ISR
167 intr_handle_t isr_handle_0 = NULL;
168 timerg0_init(&isr_handle_0); //Core 0 timer
169 #ifndef CONFIG_FREERTOS_UNICORE
170 intr_handle_t isr_handle_1 = NULL;
171 esp_ipc_call(1, timerg0_init, &isr_handle_1); //Core 1 timer
172 #endif
173
174 trigger_send_semphr = xSemaphoreCreateBinary();
175 task_delete_semphr = xQueueCreateCountingSemaphore(NO_OF_TASKS, 0);
176
177 for(int i = 0; i < portNUM_PROCESSORS; i++){ //Sending Core
178 for(int j = 0; j < portNUM_PROCESSORS; j++){ //Receiving Core
179 //Reset Values
180 notifs_sent = 0;
181 notifs_rec = 0;
182 wrong_core = false;
183
184 send_core_message = (0xFF << i); //0xFF if core 0, 0xFF0 if core 1
185
186 xTaskCreatePinnedToCore(receiver_task, "rec task", 1000, NULL, UNITY_FREERTOS_PRIORITY + 2, &rec_task_handle, j);
187 xTaskCreatePinnedToCore(sender_task, "send task", 1000, NULL, UNITY_FREERTOS_PRIORITY + 1, NULL, i);
188 vTaskDelay(5); //Wait for task creation to complete
189
190 xSemaphoreGive(trigger_send_semphr); //Trigger sender task
191 for(int k = 0; k < NO_OF_TASKS; k++){ //Wait for sender and receiver task deletion
192 TEST_ASSERT( xSemaphoreTake(task_delete_semphr, 1000 / portTICK_PERIOD_MS) );
193 }
194 vTaskDelay(5); //Give time tasks to delete
195
196 TEST_ASSERT(notifs_sent == NO_OF_NOTIFS);
197 TEST_ASSERT(notifs_rec == NO_OF_NOTIFS);
198 TEST_ASSERT(wrong_core == false);
199 }
200 }
201
202 //Delete Semaphroes and timer ISRs
203 vSemaphoreDelete(trigger_send_semphr);
204 vSemaphoreDelete(task_delete_semphr);
205 timerg0_deinit(&isr_handle_0);
206 isr_handle_0 = NULL;
207 #ifndef CONFIG_FREERTOS_UNICORE
208 esp_ipc_call(1, timerg0_deinit, &isr_handle_1);
209 isr_handle_1 = NULL;
210 #endif
211 }
212