port_common.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /*
  2. * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <string.h>
  7. #include "FreeRTOS.h"
  8. #include "task.h"
  9. #include "portmacro.h"
  10. #include "esp_private/esp_int_wdt.h"
  11. #include "esp_system.h"
  12. #include "esp_heap_caps_init.h"
  13. #include "esp_task_wdt.h"
  14. #include "esp_task.h"
  15. #include "esp_private/crosscore_int.h"
  16. #include "esp_log.h"
  17. #include "esp_memory_utils.h"
  18. #include "esp_freertos_hooks.h"
  19. #include "sdkconfig.h"
  20. #include "esp_freertos_hooks.h"
  21. #if CONFIG_SPIRAM
  22. #include "esp_psram.h"
  23. #include "esp_private/esp_psram_extram.h"
  24. #endif
  25. #if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL
  26. static const char* TAG = "cpu_start";
  27. #endif
  28. /* Architecture-agnostic parts of the FreeRTOS ESP-IDF port layer can go here.
  29. *
  30. * The actual call flow will be to call esp_startup_start_app() in <ARCH>/port.c,
  31. * which will then call esp_startup_start_app_common()
  32. */
  33. // Duplicate of inaccessible xSchedulerRunning; needed at startup to avoid counting nesting
  34. volatile unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0};
  35. // For now, running FreeRTOS on one core and a bare metal on the other (or other OSes)
  36. // is not supported. For now CONFIG_FREERTOS_UNICORE and CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
  37. // should mirror each other's values.
  38. //
  39. // And since this should be true, we can just check for CONFIG_FREERTOS_UNICORE.
  40. #if CONFIG_FREERTOS_UNICORE != CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
  41. #error "FreeRTOS and system configuration mismatch regarding the use of multiple cores."
  42. #endif
  43. static void main_task(void* args);
  44. #ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
  45. void esp_gdbstub_init(void);
  46. #endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
  47. extern void app_main(void);
  48. void esp_startup_start_app_common(void)
  49. {
  50. #if CONFIG_ESP_INT_WDT
  51. esp_int_wdt_init();
  52. //Initialize the interrupt watch dog for CPU0.
  53. esp_int_wdt_cpu_init();
  54. #endif
  55. esp_crosscore_int_init();
  56. #if CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME && !CONFIG_IDF_TARGET_ESP32C2
  57. esp_gdbstub_init();
  58. #endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
  59. portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main",
  60. ESP_TASK_MAIN_STACK, NULL,
  61. ESP_TASK_MAIN_PRIO, NULL, ESP_TASK_MAIN_CORE);
  62. assert(res == pdTRUE);
  63. (void)res;
  64. }
  65. #if !CONFIG_FREERTOS_UNICORE
  66. static volatile bool s_other_cpu_startup_done = false;
  67. static bool other_cpu_startup_idle_hook_cb(void)
  68. {
  69. s_other_cpu_startup_done = true;
  70. return true;
  71. }
  72. #endif
  73. static void main_task(void* args)
  74. {
  75. #if !CONFIG_FREERTOS_UNICORE
  76. // Wait for FreeRTOS initialization to finish on other core, before replacing its startup stack
  77. esp_register_freertos_idle_hook_for_cpu(other_cpu_startup_idle_hook_cb, !xPortGetCoreID());
  78. while (!s_other_cpu_startup_done) {
  79. ;
  80. }
  81. esp_deregister_freertos_idle_hook_for_cpu(other_cpu_startup_idle_hook_cb, !xPortGetCoreID());
  82. #endif
  83. // [refactor-todo] check if there is a way to move the following block to esp_system startup
  84. heap_caps_enable_nonos_stack_heaps();
  85. // Now we have startup stack RAM available for heap, enable any DMA pool memory
  86. #if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL
  87. if (esp_psram_is_initialized()) {
  88. esp_err_t r = esp_psram_extram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL);
  89. if (r != ESP_OK) {
  90. ESP_EARLY_LOGE(TAG, "Could not reserve internal/DMA pool (error 0x%x)", r);
  91. abort();
  92. }
  93. }
  94. #endif
  95. //Initialize TWDT if configured to do so
  96. #if CONFIG_ESP_TASK_WDT
  97. esp_task_wdt_config_t twdt_config = {
  98. .timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000,
  99. .idle_core_mask = 0,
  100. #if CONFIG_ESP_TASK_WDT_PANIC
  101. .trigger_panic = true,
  102. #endif
  103. };
  104. #if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0
  105. twdt_config.idle_core_mask |= (1 << 0);
  106. #endif
  107. #if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1
  108. twdt_config.idle_core_mask |= (1 << 1);
  109. #endif
  110. ESP_ERROR_CHECK(esp_task_wdt_init(&twdt_config));
  111. #endif // CONFIG_ESP_TASK_WDT
  112. app_main();
  113. vTaskDelete(NULL);
  114. }
  115. // -------------------- Heap Related -----------------------
  116. bool xPortCheckValidTCBMem(const void *ptr)
  117. {
  118. return esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr);
  119. }
  120. bool xPortcheckValidStackMem(const void *ptr)
  121. {
  122. #ifdef CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
  123. return esp_ptr_byte_accessible(ptr);
  124. #else
  125. return esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr);
  126. #endif
  127. }
  128. // ------------- FreeRTOS Static Allocation ----------------
  129. /*
  130. This function is required by FreeRTOS when configSUPPORT_STATIC_ALLOCATION is
  131. enabled and is used by FreeRTOS to obtain memory for its IDLE tasks.
  132. Like the pvPortMallocTcbMem() and pvPortMallocStackMem() macros, TCB and stack
  133. memory MUST be placed in internal RAM.
  134. */
  135. void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
  136. StackType_t **ppxIdleTaskStackBuffer,
  137. uint32_t *pulIdleTaskStackSize )
  138. {
  139. StaticTask_t *pxTCBBufferTemp;
  140. StackType_t *pxStackBufferTemp;
  141. /* If the stack grows down then allocate the stack then the TCB so the stack
  142. * does not grow into the TCB. Likewise if the stack grows up then allocate
  143. * the TCB then the stack. */
  144. #if (portSTACK_GROWTH > 0)
  145. {
  146. //Allocate TCB and stack buffer in internal memory
  147. pxTCBBufferTemp = pvPortMallocTcbMem(sizeof(StaticTask_t));
  148. pxStackBufferTemp = pvPortMallocStackMem(configIDLE_TASK_STACK_SIZE);
  149. }
  150. #else /* portSTACK_GROWTH */
  151. {
  152. //Allocate TCB and stack buffer in internal memory
  153. pxStackBufferTemp = pvPortMallocStackMem(configIDLE_TASK_STACK_SIZE);
  154. pxTCBBufferTemp = pvPortMallocTcbMem(sizeof(StaticTask_t));
  155. }
  156. #endif /* portSTACK_GROWTH */
  157. assert(pxTCBBufferTemp != NULL);
  158. assert(pxStackBufferTemp != NULL);
  159. //Write back pointers
  160. *ppxIdleTaskTCBBuffer = pxTCBBufferTemp;
  161. *ppxIdleTaskStackBuffer = pxStackBufferTemp;
  162. *pulIdleTaskStackSize = configIDLE_TASK_STACK_SIZE;
  163. }
  164. /*
  165. This function is required by FreeRTOS when configSUPPORT_STATIC_ALLOCATION is
  166. enabled and is used by the FreeRTOS Timer to obtain memory for its daemone task.
  167. Like the pvPortMallocTcbMem() and pvPortMallocStackMem() macros, TCB and stack
  168. memory MUST be placed in internal RAM.
  169. */
  170. void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
  171. StackType_t **ppxTimerTaskStackBuffer,
  172. uint32_t *pulTimerTaskStackSize )
  173. {
  174. StaticTask_t *pxTCBBufferTemp;
  175. StackType_t *pxStackBufferTemp;
  176. /* If the stack grows down then allocate the stack then the TCB so the stack
  177. * does not grow into the TCB. Likewise if the stack grows up then allocate
  178. * the TCB then the stack. */
  179. #if (portSTACK_GROWTH > 0)
  180. {
  181. //Allocate TCB and stack buffer in internal memory
  182. pxTCBBufferTemp = pvPortMallocTcbMem(sizeof(StaticTask_t));
  183. pxStackBufferTemp = pvPortMallocStackMem(configTIMER_TASK_STACK_DEPTH);
  184. }
  185. #else /* portSTACK_GROWTH */
  186. {
  187. //Allocate TCB and stack buffer in internal memory
  188. pxStackBufferTemp = pvPortMallocStackMem(configTIMER_TASK_STACK_DEPTH);
  189. pxTCBBufferTemp = pvPortMallocTcbMem(sizeof(StaticTask_t));
  190. }
  191. #endif /* portSTACK_GROWTH */
  192. assert(pxTCBBufferTemp != NULL);
  193. assert(pxStackBufferTemp != NULL);
  194. //Write back pointers
  195. *ppxTimerTaskTCBBuffer = pxTCBBufferTemp;
  196. *ppxTimerTaskStackBuffer = pxStackBufferTemp;
  197. *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
  198. }