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, &notify_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, &notify_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