test_freertos_eventgroups.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. #include <stdio.h>
  2. #include "freertos/FreeRTOS.h"
  3. #include "freertos/task.h"
  4. #include "freertos/semphr.h"
  5. #include "freertos/queue.h"
  6. #include "freertos/event_groups.h"
  7. #include "driver/timer.h"
  8. #include "unity.h"
  9. #define BIT_CALL (1 << 0)
  10. #define BIT_RESPONSE(TASK) (1 << (TASK+1))
  11. #define ALL_RESPONSE_BITS (((1 << NUM_TASKS) - 1) << 1)
  12. static const int NUM_TASKS = 8;
  13. static const int COUNT = 1000;
  14. static EventGroupHandle_t eg;
  15. static SemaphoreHandle_t done_sem;
  16. static void task_event_group_call_response(void *param)
  17. {
  18. int task_num = (int)param;
  19. printf("Started %d\n", task_num);
  20. for (int i = 0; i < COUNT; i++) {
  21. /* Wait until the common "call" bit is set, starts off all tasks
  22. (clear on return) */
  23. TEST_ASSERT( xEventGroupWaitBits(eg, BIT_CALL, true, false, portMAX_DELAY) );
  24. /* Set our individual "response" bit */
  25. xEventGroupSetBits(eg, BIT_RESPONSE(task_num));
  26. }
  27. printf("Task %d done\n", task_num);
  28. xSemaphoreGive(done_sem);
  29. vTaskDelete(NULL);
  30. }
  31. TEST_CASE("FreeRTOS Event Groups", "[freertos]")
  32. {
  33. eg = xEventGroupCreate();
  34. done_sem = xSemaphoreCreateCounting(NUM_TASKS, 0);
  35. /* Note: task_event_group_call_response all have higher priority than this task, so on this core
  36. they will always preempt this task.
  37. This is important because we need to know all tasks have blocked on BIT_CALL each time we signal it,
  38. or they get out of sync.
  39. */
  40. for (int c = 0; c < NUM_TASKS; c++) {
  41. xTaskCreatePinnedToCore(task_event_group_call_response, "tsk_call_resp", 4096, (void *)c, configMAX_PRIORITIES - 1, NULL, c % portNUM_PROCESSORS);
  42. }
  43. /* Tasks all start instantly, but this task will resume running at the same time as the higher priority tasks on the
  44. other processor may still be setting up, so allow time for them to also block on BIT_CALL... */
  45. vTaskDelay(10);
  46. for (int i = 0; i < COUNT; i++) {
  47. /* signal all tasks with "CALL" bit... */
  48. xEventGroupSetBits(eg, BIT_CALL);
  49. /* Only wait for 1 tick, the wakeup should be immediate... */
  50. TEST_ASSERT_EQUAL_HEX16(ALL_RESPONSE_BITS, xEventGroupWaitBits(eg, ALL_RESPONSE_BITS, true, true, 1));
  51. }
  52. /* Ensure all tasks cleaned up correctly */
  53. for (int c = 0; c < NUM_TASKS; c++) {
  54. TEST_ASSERT( xSemaphoreTake(done_sem, 100/portTICK_PERIOD_MS) );
  55. }
  56. vSemaphoreDelete(done_sem);
  57. vEventGroupDelete(eg);
  58. }
  59. #define BIT_DONE(X) (1<<(NUM_TASKS+1+X))
  60. static void task_test_sync(void *param)
  61. {
  62. int task_num = (int)param;
  63. printf("Started %d\n", task_num);
  64. for (int i = 0; i < COUNT; i++) {
  65. /* set our bit, and wait on all tasks to set their bits */
  66. xEventGroupSync(eg, BIT_RESPONSE(task_num), ALL_RESPONSE_BITS, portMAX_DELAY);
  67. /* clear our bit */
  68. xEventGroupClearBits(eg, BIT_RESPONSE(task_num));
  69. }
  70. int after_done = xEventGroupSetBits(eg, BIT_DONE(task_num));
  71. printf("Done %d = 0x%08x\n", task_num, after_done);
  72. xSemaphoreGive(done_sem);
  73. vTaskDelete(NULL);
  74. }
  75. TEST_CASE("FreeRTOS Event Group Sync", "[freertos]")
  76. {
  77. eg = xEventGroupCreate();
  78. done_sem = xSemaphoreCreateCounting(NUM_TASKS, 0);
  79. for (int c = 0; c < NUM_TASKS; c++) {
  80. xTaskCreatePinnedToCore(task_test_sync, "task_test_sync", 4096, (void *)c, configMAX_PRIORITIES - 1, NULL, c % portNUM_PROCESSORS);
  81. }
  82. for (int c = 0; c < NUM_TASKS; c++) {
  83. printf("Waiting on %d (0x%08x)\n", c, BIT_DONE(c));
  84. TEST_ASSERT( xEventGroupWaitBits(eg, BIT_DONE(c), false, false, portMAX_DELAY) );
  85. }
  86. /* Ensure all tasks cleaned up correctly */
  87. for (int c = 0; c < NUM_TASKS; c++) {
  88. TEST_ASSERT( xSemaphoreTake(done_sem, 100/portTICK_PERIOD_MS) );
  89. }
  90. vSemaphoreDelete(done_sem);
  91. vEventGroupDelete(eg);
  92. }
  93. /*-----------------Test case for event group trace facilities-----------------*/
  94. #ifdef CONFIG_FREERTOS_USE_TRACE_FACILITY
  95. /*
  96. * Test event group Trace Facility functions such as
  97. * xEventGroupClearBitsFromISR(), xEventGroupSetBitsFromISR()
  98. */
  99. //Use a timer to trigger an ISr
  100. #define TIMER_DIVIDER 10000
  101. #define TIMER_COUNT 100
  102. #define TIMER_NUMBER 0
  103. #define BITS 0xAA
  104. static timer_isr_handle_t isr_handle;
  105. static bool test_set_bits;
  106. static bool test_clear_bits;
  107. static void IRAM_ATTR event_group_isr()
  108. {
  109. portBASE_TYPE task_woken = pdFALSE;
  110. TIMERG0.int_clr_timers.t0 = 1;
  111. TIMERG0.hw_timer[xPortGetCoreID()].config.alarm_en = 1;
  112. if(test_set_bits){
  113. xEventGroupSetBitsFromISR(eg, BITS, &task_woken);
  114. timer_pause(TIMER_GROUP_0, TIMER_NUMBER);
  115. test_set_bits = false;
  116. } else if (test_clear_bits){
  117. xEventGroupClearBitsFromISR(eg, BITS);
  118. xSemaphoreGiveFromISR(done_sem, &task_woken);
  119. timer_pause(TIMER_GROUP_0, TIMER_NUMBER);
  120. test_clear_bits = false;
  121. }
  122. //Switch context if necessary
  123. if(task_woken == pdTRUE){
  124. portYIELD_FROM_ISR();
  125. }
  126. }
  127. static void setup_timer()
  128. {
  129. //Setup timer for ISR
  130. int timer_group = TIMER_GROUP_0;
  131. int timer_idx = TIMER_NUMBER;
  132. timer_config_t config;
  133. config.alarm_en = 1;
  134. config.auto_reload = 1;
  135. config.counter_dir = TIMER_COUNT_UP;
  136. config.divider = TIMER_DIVIDER;
  137. config.intr_type = TIMER_INTR_LEVEL;
  138. config.counter_en = TIMER_PAUSE;
  139. timer_init(timer_group, timer_idx, &config); //Configure timer
  140. timer_pause(timer_group, timer_idx); //Stop timer counter
  141. timer_set_counter_value(timer_group, timer_idx, 0x00000000ULL); //Load counter value
  142. timer_set_alarm_value(timer_group, timer_idx, TIMER_COUNT); //Set alarm value
  143. timer_enable_intr(timer_group, timer_idx); //Enable timer interrupt
  144. timer_set_auto_reload(timer_group, timer_idx, 1); //Auto Reload
  145. timer_isr_register(timer_group, timer_idx, event_group_isr, NULL, ESP_INTR_FLAG_IRAM, &isr_handle); //Set ISR handler
  146. }
  147. static void cleanup_timer()
  148. {
  149. timer_disable_intr(TIMER_GROUP_0, TIMER_NUMBER);
  150. esp_intr_free(isr_handle);
  151. }
  152. TEST_CASE("FreeRTOS Event Group ISR", "[freertos]")
  153. {
  154. done_sem = xSemaphoreCreateBinary();
  155. eg = xEventGroupCreate();
  156. test_set_bits = false;
  157. test_clear_bits = false;
  158. setup_timer(); //Init timer to trigger ISR
  159. //Test set bits
  160. test_set_bits = true;
  161. timer_start(TIMER_GROUP_0, TIMER_NUMBER);
  162. TEST_ASSERT_EQUAL(BITS, xEventGroupWaitBits(eg, BITS, pdFALSE, pdTRUE, portMAX_DELAY)); //Let ISR set event group bits
  163. //Test clear bits
  164. xEventGroupSetBits(eg, BITS); //Set bits to be cleared
  165. test_clear_bits = true;
  166. timer_start(TIMER_GROUP_0, TIMER_NUMBER);
  167. xSemaphoreTake(done_sem, portMAX_DELAY); //Wait for ISR to clear bits
  168. vTaskDelay(10); //Event group clear bits runs via daemon task, delay so daemon can run
  169. TEST_ASSERT_EQUAL(0, xEventGroupGetBits(eg)); //Check bits are cleared
  170. //Clean up
  171. cleanup_timer();
  172. vEventGroupDelete(eg);
  173. vSemaphoreDelete(done_sem);
  174. vTaskDelay(10); //Give time for idle task to clear up deleted tasks
  175. }
  176. #endif //CONFIG_FREERTOS_USE_TRACE_FACILITY