1 /*
2 * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7
8 #include <stdint.h>
9 #include <stdlib.h>
10 #include <stdbool.h>
11 #include "freertos/FreeRTOS.h"
12 #include "esp_attr.h"
13 #include "esp_freertos_hooks.h"
14 #include "esp_cpu.h"
15
16 #include "sdkconfig.h"
17
18 #if CONFIG_PM_ENABLE
19 #include "esp_pm.h"
20 #include "esp_private/pm_impl.h"
21 #endif
22
23 //We use just a static array here because it's not expected many components will need
24 //an idle or tick hook.
25 #define MAX_HOOKS 8
26
27 static portMUX_TYPE hooks_spinlock = portMUX_INITIALIZER_UNLOCKED;
28 static esp_freertos_idle_cb_t idle_cb[portNUM_PROCESSORS][MAX_HOOKS]={0};
29 static esp_freertos_tick_cb_t tick_cb[portNUM_PROCESSORS][MAX_HOOKS]={0};
30
esp_vApplicationTickHook(void)31 void IRAM_ATTR esp_vApplicationTickHook(void)
32 {
33 int n;
34 int core = xPortGetCoreID();
35 for (n=0; n<MAX_HOOKS; n++) {
36 if (tick_cb[core][n]!=NULL) {
37 tick_cb[core][n]();
38 }
39 }
40 }
41
esp_vApplicationIdleHook(void)42 void esp_vApplicationIdleHook(void)
43 {
44 bool can_go_idle=true;
45 int core = xPortGetCoreID();
46 for (int n = 0; n < MAX_HOOKS; n++) {
47 if (idle_cb[core][n] != NULL && !idle_cb[core][n]()) {
48 can_go_idle = false;
49 }
50 }
51 if (!can_go_idle) {
52 return;
53 }
54
55 #ifdef CONFIG_PM_ENABLE
56 esp_pm_impl_idle_hook();
57 esp_pm_impl_waiti();
58 #else
59 esp_cpu_wait_for_intr();
60 #endif
61
62
63 }
64
esp_register_freertos_idle_hook_for_cpu(esp_freertos_idle_cb_t new_idle_cb,UBaseType_t cpuid)65 esp_err_t esp_register_freertos_idle_hook_for_cpu(esp_freertos_idle_cb_t new_idle_cb, UBaseType_t cpuid)
66 {
67 if(cpuid >= portNUM_PROCESSORS){
68 return ESP_ERR_INVALID_ARG;
69 }
70 portENTER_CRITICAL(&hooks_spinlock);
71 for(int n = 0; n < MAX_HOOKS; n++){
72 if (idle_cb[cpuid][n]==NULL) {
73 idle_cb[cpuid][n]=new_idle_cb;
74 portEXIT_CRITICAL(&hooks_spinlock);
75 return ESP_OK;
76 }
77 }
78 portEXIT_CRITICAL(&hooks_spinlock);
79 return ESP_ERR_NO_MEM;
80 }
81
esp_register_freertos_idle_hook(esp_freertos_idle_cb_t new_idle_cb)82 esp_err_t esp_register_freertos_idle_hook(esp_freertos_idle_cb_t new_idle_cb)
83 {
84 return esp_register_freertos_idle_hook_for_cpu(new_idle_cb, xPortGetCoreID());
85 }
86
esp_register_freertos_tick_hook_for_cpu(esp_freertos_tick_cb_t new_tick_cb,UBaseType_t cpuid)87 esp_err_t esp_register_freertos_tick_hook_for_cpu(esp_freertos_tick_cb_t new_tick_cb, UBaseType_t cpuid)
88 {
89 if(cpuid >= portNUM_PROCESSORS){
90 return ESP_ERR_INVALID_ARG;
91 }
92 portENTER_CRITICAL(&hooks_spinlock);
93 for(int n = 0; n < MAX_HOOKS; n++){
94 if (tick_cb[cpuid][n]==NULL) {
95 tick_cb[cpuid][n]=new_tick_cb;
96 portEXIT_CRITICAL(&hooks_spinlock);
97 return ESP_OK;
98 }
99 }
100 portEXIT_CRITICAL(&hooks_spinlock);
101 return ESP_ERR_NO_MEM;
102 }
103
esp_register_freertos_tick_hook(esp_freertos_tick_cb_t new_tick_cb)104 esp_err_t esp_register_freertos_tick_hook(esp_freertos_tick_cb_t new_tick_cb)
105 {
106 return esp_register_freertos_tick_hook_for_cpu(new_tick_cb, xPortGetCoreID());
107 }
108
esp_deregister_freertos_idle_hook_for_cpu(esp_freertos_idle_cb_t old_idle_cb,UBaseType_t cpuid)109 void esp_deregister_freertos_idle_hook_for_cpu(esp_freertos_idle_cb_t old_idle_cb, UBaseType_t cpuid)
110 {
111 if(cpuid >= portNUM_PROCESSORS){
112 return;
113 }
114 portENTER_CRITICAL(&hooks_spinlock);
115 for(int n = 0; n < MAX_HOOKS; n++){
116 if(idle_cb[cpuid][n] == old_idle_cb) idle_cb[cpuid][n] = NULL;
117 }
118 portEXIT_CRITICAL(&hooks_spinlock);
119 }
120
esp_deregister_freertos_idle_hook(esp_freertos_idle_cb_t old_idle_cb)121 void esp_deregister_freertos_idle_hook(esp_freertos_idle_cb_t old_idle_cb)
122 {
123 portENTER_CRITICAL(&hooks_spinlock);
124 for(int m = 0; m < portNUM_PROCESSORS; m++) {
125 esp_deregister_freertos_idle_hook_for_cpu(old_idle_cb, m);
126 }
127 portEXIT_CRITICAL(&hooks_spinlock);
128 }
129
esp_deregister_freertos_tick_hook_for_cpu(esp_freertos_tick_cb_t old_tick_cb,UBaseType_t cpuid)130 void esp_deregister_freertos_tick_hook_for_cpu(esp_freertos_tick_cb_t old_tick_cb, UBaseType_t cpuid)
131 {
132 if(cpuid >= portNUM_PROCESSORS){
133 return;
134 }
135 portENTER_CRITICAL(&hooks_spinlock);
136 for(int n = 0; n < MAX_HOOKS; n++){
137 if(tick_cb[cpuid][n] == old_tick_cb) tick_cb[cpuid][n] = NULL;
138 }
139 portEXIT_CRITICAL(&hooks_spinlock);
140 }
141
esp_deregister_freertos_tick_hook(esp_freertos_tick_cb_t old_tick_cb)142 void esp_deregister_freertos_tick_hook(esp_freertos_tick_cb_t old_tick_cb)
143 {
144 portENTER_CRITICAL(&hooks_spinlock);
145 for(int m = 0; m < portNUM_PROCESSORS; m++){
146 esp_deregister_freertos_tick_hook_for_cpu(old_tick_cb, m);
147 }
148 portEXIT_CRITICAL(&hooks_spinlock);
149 }
150