test_freertos_eventgroups.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /*
  2. * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stdio.h>
  7. #include "freertos/FreeRTOS.h"
  8. #include "freertos/task.h"
  9. #include "freertos/semphr.h"
  10. #include "freertos/queue.h"
  11. #include "freertos/event_groups.h"
  12. #include "driver/gptimer.h"
  13. #include "unity.h"
  14. #include "unity_test_utils.h"
  15. #define NUM_TASKS 8
  16. #define ALL_TASK_BITS ((1 << NUM_TASKS) - 1)
  17. #define BIT_CALL(task) (1 << (task))
  18. #define BIT_RESPONSE(task) (1 << ((task) + NUM_TASKS))
  19. #define ALL_CALL_BITS (ALL_TASK_BITS)
  20. #define ALL_RESPONSE_BITS (ALL_TASK_BITS << NUM_TASKS)
  21. static const int COUNT = 1000;
  22. static EventGroupHandle_t eg;
  23. static SemaphoreHandle_t done_sem;
  24. static void task_event_group_call_response(void *param)
  25. {
  26. int task_num = (int)param;
  27. printf("Started %d\n", task_num);
  28. for (int i = 0; i < COUNT; i++) {
  29. /* Wait until the common "call" bit is set, starts off all tasks
  30. (clear on return) */
  31. TEST_ASSERT( xEventGroupWaitBits(eg, BIT_CALL(task_num), true, false, portMAX_DELAY) );
  32. /* Set our individual "response" bit */
  33. xEventGroupSetBits(eg, BIT_RESPONSE(task_num));
  34. }
  35. printf("Task %d done\n", task_num);
  36. xSemaphoreGive(done_sem);
  37. // Wait to be deleted
  38. vTaskSuspend(NULL);
  39. }
  40. TEST_CASE("FreeRTOS Event Groups", "[freertos]")
  41. {
  42. eg = xEventGroupCreate();
  43. done_sem = xSemaphoreCreateCounting(NUM_TASKS, 0);
  44. TaskHandle_t task_handles[NUM_TASKS];
  45. /* Note: task_event_group_call_response all have higher priority than this task, so on this core
  46. they will always preempt this task.
  47. This is important because we need to know all tasks have blocked on their own BIT_CALL(task_num) each time we
  48. signal it, or they get out of sync.
  49. */
  50. for (int c = 0; c < NUM_TASKS; c++) {
  51. xTaskCreatePinnedToCore(task_event_group_call_response, "tsk_call_resp", 4096, (void *)c, configMAX_PRIORITIES - 1, &task_handles[c], c % portNUM_PROCESSORS);
  52. }
  53. /* Tasks all start instantly, but this task will resume running at the same time as the higher priority tasks on the
  54. other processor may still be setting up, so allow time for them to also block on BIT_CALL()... */
  55. vTaskDelay(10);
  56. for (int i = 0; i < COUNT; i++) {
  57. /* signal all the "CALL" bits of each task */
  58. xEventGroupSetBits(eg, ALL_CALL_BITS);
  59. /* Wait until all tasks have set their respective response bits */
  60. TEST_ASSERT_EQUAL_HEX16(ALL_RESPONSE_BITS, xEventGroupWaitBits(eg, ALL_RESPONSE_BITS, true, true, portMAX_DELAY));
  61. }
  62. /* Ensure all tasks have suspend themselves */
  63. for (int c = 0; c < NUM_TASKS; c++) {
  64. TEST_ASSERT( xSemaphoreTake(done_sem, 100 / portTICK_PERIOD_MS) );
  65. }
  66. for (int c = 0; c < NUM_TASKS; c++) {
  67. unity_utils_task_delete(task_handles[c]);
  68. }
  69. vSemaphoreDelete(done_sem);
  70. vEventGroupDelete(eg);
  71. }
  72. static void task_test_sync(void *param)
  73. {
  74. int task_num = (int)param;
  75. printf("Started %d\n", task_num);
  76. for (int i = 0; i < COUNT; i++) {
  77. /* set our bit, and wait on all tasks to set their bits */
  78. xEventGroupSync(eg, BIT_CALL(task_num), ALL_CALL_BITS, portMAX_DELAY);
  79. /* clear our bit */
  80. xEventGroupClearBits(eg, BIT_CALL(task_num));
  81. }
  82. int after_done = xEventGroupSetBits(eg, BIT_RESPONSE(task_num));
  83. printf("Done %d = 0x%08x\n", task_num, after_done);
  84. xSemaphoreGive(done_sem);
  85. vTaskDelete(NULL);
  86. }
  87. TEST_CASE("FreeRTOS Event Group Sync", "[freertos]")
  88. {
  89. eg = xEventGroupCreate();
  90. done_sem = xSemaphoreCreateCounting(NUM_TASKS, 0);
  91. for (int c = 0; c < NUM_TASKS; c++) {
  92. xTaskCreatePinnedToCore(task_test_sync, "task_test_sync", 4096, (void *)c, configMAX_PRIORITIES - 1, NULL, c % portNUM_PROCESSORS);
  93. }
  94. for (int c = 0; c < NUM_TASKS; c++) {
  95. printf("Waiting on %d (0x%08x)\n", c, BIT_RESPONSE(c));
  96. TEST_ASSERT( xEventGroupWaitBits(eg, BIT_RESPONSE(c), false, false, portMAX_DELAY) );
  97. }
  98. /* Ensure all tasks cleaned up correctly */
  99. for (int c = 0; c < NUM_TASKS; c++) {
  100. TEST_ASSERT( xSemaphoreTake(done_sem, 100 / portTICK_PERIOD_MS) );
  101. }
  102. vSemaphoreDelete(done_sem);
  103. vEventGroupDelete(eg);
  104. }
  105. /*-----------------Test case for event group trace facilities-----------------*/
  106. #ifdef CONFIG_FREERTOS_USE_TRACE_FACILITY
  107. /*
  108. * Test event group Trace Facility functions such as
  109. * xEventGroupClearBitsFromISR(), xEventGroupSetBitsFromISR()
  110. */
  111. //Use a timer to trigger an ISr
  112. #define BITS 0xAA
  113. static gptimer_handle_t gptimer;
  114. static bool test_set_bits;
  115. static bool test_clear_bits;
  116. static bool on_timer_alarm_cb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx)
  117. {
  118. portBASE_TYPE task_woken = pdFALSE;
  119. gptimer_stop(timer);
  120. if (test_set_bits) {
  121. xEventGroupSetBitsFromISR(eg, BITS, &task_woken);
  122. test_set_bits = false;
  123. } else if (test_clear_bits) {
  124. xEventGroupClearBitsFromISR(eg, BITS);
  125. xSemaphoreGiveFromISR(done_sem, &task_woken);
  126. test_clear_bits = false;
  127. }
  128. //Switch context if necessary
  129. return task_woken == pdTRUE;
  130. }
  131. TEST_CASE("FreeRTOS Event Group ISR", "[freertos]")
  132. {
  133. done_sem = xSemaphoreCreateBinary();
  134. eg = xEventGroupCreate();
  135. test_set_bits = false;
  136. test_clear_bits = false;
  137. //Setup timer for ISR
  138. gptimer_config_t config = {
  139. .clk_src = GPTIMER_CLK_SRC_DEFAULT,
  140. .direction = GPTIMER_COUNT_UP,
  141. .resolution_hz = 1000000,
  142. };
  143. TEST_ESP_OK(gptimer_new_timer(&config, &gptimer));
  144. gptimer_alarm_config_t alarm_config = {
  145. .reload_count = 0,
  146. .alarm_count = 200000,
  147. };
  148. gptimer_event_callbacks_t cbs = {
  149. .on_alarm = on_timer_alarm_cb,
  150. };
  151. TEST_ESP_OK(gptimer_register_event_callbacks(gptimer, &cbs, NULL));
  152. TEST_ESP_OK(gptimer_enable(gptimer));
  153. TEST_ESP_OK(gptimer_set_alarm_action(gptimer, &alarm_config));
  154. //Test set bits
  155. printf("test set bits\r\n");
  156. test_set_bits = true;
  157. TEST_ESP_OK(gptimer_start(gptimer));
  158. TEST_ASSERT_EQUAL(BITS, xEventGroupWaitBits(eg, BITS, pdFALSE, pdTRUE, portMAX_DELAY)); //Let ISR set event group bits
  159. //Test clear bits
  160. printf("test clear bits\r\n");
  161. xEventGroupSetBits(eg, BITS); //Set bits to be cleared
  162. test_clear_bits = true;
  163. TEST_ESP_OK(gptimer_set_raw_count(gptimer, 0));
  164. TEST_ESP_OK(gptimer_start(gptimer));
  165. xSemaphoreTake(done_sem, portMAX_DELAY); //Wait for ISR to clear bits
  166. vTaskDelay(10); //Event group clear bits runs via daemon task, delay so daemon can run
  167. TEST_ASSERT_EQUAL(0, xEventGroupGetBits(eg)); //Check bits are cleared
  168. //Clean up
  169. TEST_ESP_OK(gptimer_disable(gptimer));
  170. TEST_ESP_OK(gptimer_del_timer(gptimer));
  171. vEventGroupDelete(eg);
  172. vSemaphoreDelete(done_sem);
  173. vTaskDelay(10); //Give time for idle task to clear up deleted tasks
  174. }
  175. #endif //CONFIG_FREERTOS_USE_TRACE_FACILITY