1 /**
2 ****************************************************************************************
3 * @file app_gpiote.c
4 * @author BLE Driver Team
5 * @brief HAL APP module driver.
6 ****************************************************************************************
7 * @attention
8 #####Copyright (c) 2019 GOODIX
9 All rights reserved.
10
11 Redistribution and use in source and binary forms, with or without
12 modification, are permitted provided that the following conditions are met:
13 * Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
15 * Redistributions in binary form must reproduce the above copyright
16 notice, this list of conditions and the following disclaimer in the
17 documentation and/or other materials provided with the distribution.
18 * Neither the name of GOODIX nor the names of its contributors may be used
19 to endorse or promote products derived from this software without
20 specific prior written permission.
21
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
26 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 POSSIBILITY OF SUCH DAMAGE.
33 ****************************************************************************************
34 */
35
36 /*
37 * INCLUDE FILES
38 *****************************************************************************************
39 */
40 #include <string.h>
41 #include "app_pwr_mgmt.h"
42 #include "platform_sdk.h"
43 #include "app_gpiote.h"
44
45 /*
46 * DEFINES
47 *****************************************************************************************
48 */
49 #define BIT_8 8
50 #define BIT_16 16
51 #define BIT_24 24
52
53 #define GPIOTE_USE_PATTERN 0x47
54 #define GPIOTE_USE_MAX 32
55 #define GPIOTE_AON_PIN_USE_MAX 8
56 /*
57 * STRUCT DEFINE
58 *****************************************************************************************
59 */
60 struct gpiote_env_t {
61 uint8_t total_used;
62 app_gpiote_param_t params[GPIOTE_USE_MAX];
63 };
64
65 /*
66 * LOCAL FUNCTION DECLARATION
67 *****************************************************************************************
68 */
69 static bool gpiote_prepare_for_sleep(void);
70 static void gpiote_sleep_canceled(void);
71 static void gpiote_wake_up_ind(void);
72
73 /*
74 * LOCAL VARIABLE DEFINITIONS
75 *****************************************************************************************
76 */
77 static struct gpiote_env_t s_gpiote_env;
78
79 static bool s_sleep_cb_registered_flag = false;
80 static uint16_t s_gpiote_pwr_id;
81
82 static const app_sleep_callbacks_t gpiote_sleep_cb = {
83 .app_prepare_for_sleep = gpiote_prepare_for_sleep,
84 .app_sleep_canceled = gpiote_sleep_canceled,
85 .app_wake_up_ind = gpiote_wake_up_ind
86 };
87
88 static app_io_callback_t aon_cb_called_table[GPIOTE_AON_PIN_USE_MAX];
89 /*
90 * LOCAL FUNCTION DEFINITIONS
91 *****************************************************************************************
92 */
gpiote_prepare_for_sleep(void)93 static bool gpiote_prepare_for_sleep(void)
94 {
95 return true;
96 }
97
gpiote_sleep_canceled(void)98 static void gpiote_sleep_canceled(void)
99 {
100 }
101
gpiote_wake_up_ind(void)102 SECTION_RAM_CODE static void gpiote_wake_up_ind(void)
103 {
104 bool is_ext0_need_enable = false;
105 bool is_ext1_need_enable = false;
106
107 for (int idx = 0; idx < s_gpiote_env.total_used; idx++) {
108 if (s_gpiote_env.params[idx].type == APP_IO_TYPE_NORMAL) {
109 if (APP_IO_PINS_0_15 & s_gpiote_env.params[idx].pin) {
110 is_ext0_need_enable = true;
111 continue;
112 }
113 if (APP_IO_PINS_16_31 & s_gpiote_env.params[idx].pin) {
114 is_ext1_need_enable = true;
115 continue;
116 }
117 }
118 }
119
120 if (is_ext0_need_enable) {
121 hal_nvic_enable_irq(EXT0_IRQn);
122 }
123
124 if (is_ext1_need_enable) {
125 hal_nvic_enable_irq(EXT1_IRQn);
126 }
127
128 return;
129 }
130
params_check(const app_gpiote_param_t * p_params,uint8_t table_cnt)131 static uint16_t params_check(const app_gpiote_param_t *p_params, uint8_t table_cnt)
132 {
133 if (p_params == NULL) {
134 return APP_DRV_ERR_POINTER_NULL;
135 }
136
137 if (((s_gpiote_env.total_used + table_cnt) > GPIOTE_USE_MAX) && table_cnt) {
138 return APP_DRV_ERR_INVALID_PARAM;
139 }
140
141 return APP_DRV_SUCCESS;
142 }
143
gpiote_wakeup_mode_config(uint8_t idx,const app_gpiote_param_t * p_params)144 static void gpiote_wakeup_mode_config(uint8_t idx, const app_gpiote_param_t *p_params)
145 {
146 if ((p_params[idx].handle_mode == APP_IO_ENABLE_WAKEUP) && (p_params[idx].type == APP_IO_TYPE_AON)) {
147 switch (p_params[idx].mode) {
148 case APP_IO_MODE_IT_RISING:
149 hal_pwr_config_ext_wakeup(p_params[idx].pin, PWR_EXTWKUP_TYPE_RISING);
150 break;
151
152 case APP_IO_MODE_IT_FALLING:
153 hal_pwr_config_ext_wakeup(p_params[idx].pin, PWR_EXTWKUP_TYPE_FALLING);
154 break;
155
156 case APP_IO_MODE_IT_HIGH:
157 hal_pwr_config_ext_wakeup(p_params[idx].pin, PWR_EXTWKUP_TYPE_HIGH);
158 break;
159
160 case APP_IO_MODE_IT_LOW:
161 hal_pwr_config_ext_wakeup(p_params[idx].pin, PWR_EXTWKUP_TYPE_LOW);
162 break;
163
164 default:
165 break;
166 }
167 pwr_mgmt_wakeup_source_setup(PWR_WKUP_COND_EXT);
168 }
169 }
170
register_cb(void)171 static uint16_t register_cb(void)
172 {
173 if (!s_sleep_cb_registered_flag) { // register sleep callback
174 s_gpiote_pwr_id = pwr_register_sleep_cb(&gpiote_sleep_cb, APP_DRIVER_GPIOTE_WAPEUP_PRIORITY);
175 if (s_gpiote_pwr_id < 0) {
176 return APP_DRV_ERR_INVALID_PARAM;
177 }
178 s_sleep_cb_registered_flag = true;
179 }
180
181 return APP_DRV_SUCCESS;
182 }
183
184 /*
185 * GLOBAL FUNCTION DEFINITIONS
186 ****************************************************************************************
187 */
app_gpiote_init(const app_gpiote_param_t * p_params,uint8_t table_cnt)188 uint16_t app_gpiote_init(const app_gpiote_param_t *p_params, uint8_t table_cnt)
189 {
190 static uint8_t exit_flag = 0x0;
191 app_io_init_t io_init;
192 app_drv_err_t err_code;
193
194 err_code = params_check(p_params, table_cnt);
195 APP_DRV_ERR_CODE_CHECK(err_code);
196
197 for (uint8_t idx = 0; idx < table_cnt; idx++) {
198 exit_flag = 0x0;
199
200 for (uint8_t index = 0; index < s_gpiote_env.total_used; index ++) {
201 if (s_gpiote_env.params[index].pin == p_params[idx].pin && \
202 s_gpiote_env.params[index].type == p_params[idx].type) {
203 exit_flag = 0x1;
204 break;
205 }
206 }
207
208 io_init.pin = p_params[idx].pin;
209 io_init.mode = p_params[idx].mode;
210 io_init.pull = p_params[idx].pull;
211 io_init.mux = APP_IO_MUX_7;
212
213 app_io_deinit(p_params[idx].type, io_init.pin);
214 err_code = app_io_init(p_params[idx].type, &io_init);
215 APP_DRV_ERR_CODE_CHECK(err_code);
216
217 if (exit_flag) {
218 continue;
219 }
220
221 memcpy_s(&s_gpiote_env.params[s_gpiote_env.total_used],
222 sizeof(s_gpiote_env.params[s_gpiote_env.total_used]),
223 &p_params[idx], sizeof(app_gpiote_param_t));
224
225 gpiote_wakeup_mode_config(idx, p_params);
226
227 if (p_params[idx].type == APP_IO_TYPE_NORMAL) {
228 hal_nvic_clear_pending_irq(EXT0_IRQn);
229 hal_nvic_enable_irq(EXT0_IRQn);
230 hal_nvic_clear_pending_irq(EXT1_IRQn);
231 hal_nvic_enable_irq(EXT1_IRQn);
232 } else if (p_params[idx].type == APP_IO_TYPE_AON) {
233 hal_nvic_clear_pending_irq(EXT2_IRQn);
234 hal_nvic_enable_irq(EXT2_IRQn);
235 }
236
237 s_gpiote_env.total_used += 1;
238 }
239
240 err_code = register_cb();
241 APP_DRV_ERR_CODE_CHECK(err_code);
242
243 return APP_DRV_SUCCESS;
244 }
245
gpiote_config_wake_up_config(const app_gpiote_param_t * p_config)246 static void gpiote_config_wake_up_config(const app_gpiote_param_t *p_config)
247 {
248 if ((p_config->handle_mode == APP_IO_ENABLE_WAKEUP) && (p_config->type == APP_IO_TYPE_AON)) {
249 switch (p_config->mode) {
250 case APP_IO_MODE_IT_RISING:
251 hal_pwr_config_ext_wakeup(p_config->pin, PWR_EXTWKUP_TYPE_RISING);
252 break;
253
254 case APP_IO_MODE_IT_FALLING:
255 hal_pwr_config_ext_wakeup(p_config->pin, PWR_EXTWKUP_TYPE_FALLING);
256 break;
257
258 case APP_IO_MODE_IT_HIGH:
259 hal_pwr_config_ext_wakeup(p_config->pin, PWR_EXTWKUP_TYPE_HIGH);
260 break;
261
262 case APP_IO_MODE_IT_LOW:
263 hal_pwr_config_ext_wakeup(p_config->pin, PWR_EXTWKUP_TYPE_LOW);
264 break;
265
266 default:
267 break;
268 }
269 pwr_mgmt_wakeup_source_setup(PWR_WKUP_COND_EXT);
270 }
271 }
272
app_gpiote_config(const app_gpiote_param_t * p_config)273 uint16_t app_gpiote_config(const app_gpiote_param_t *p_config)
274 {
275 uint8_t exit_flag = 0x0;
276 uint8_t index;
277 app_io_init_t io_init;
278 app_drv_err_t err_code;
279
280 if (p_config == NULL) {
281 return APP_DRV_ERR_POINTER_NULL;
282 }
283
284 for (index = 0; index < s_gpiote_env.total_used; index ++) {
285 if (s_gpiote_env.params[index].pin == p_config->pin && \
286 s_gpiote_env.params[index].type == p_config->type) {
287 exit_flag = 0x1;
288 break;
289 }
290 }
291
292 if (!exit_flag || index >= GPIOTE_USE_MAX) {
293 return APP_DRV_ERR_INVALID_PARAM;
294 }
295
296 memcpy_s(&s_gpiote_env.params[index], sizeof(s_gpiote_env.params[index]),
297 p_config, sizeof(app_gpiote_param_t));
298
299 io_init.pin = p_config->pin;
300 io_init.mode = p_config->mode;
301 io_init.pull = p_config->pull;
302 io_init.mux = APP_IO_MUX_7;
303
304 app_io_deinit(p_config->type, p_config->pin);
305 err_code = app_io_init(p_config->type, &io_init);
306 APP_DRV_ERR_CODE_CHECK(err_code);
307
308 gpiote_config_wake_up_config(p_config);
309
310 if ((p_config->handle_mode == APP_IO_DISABLE_WAKEUP) && (p_config->type == APP_IO_TYPE_AON)) {
311 hal_pwr_disable_ext_wakeup(p_config->pin);
312 }
313
314 if (p_config->type == APP_IO_TYPE_NORMAL) {
315 hal_nvic_clear_pending_irq(EXT0_IRQn);
316 hal_nvic_enable_irq(EXT0_IRQn);
317 hal_nvic_clear_pending_irq(EXT1_IRQn);
318 hal_nvic_enable_irq(EXT1_IRQn);
319 } else if (p_config->type == APP_IO_TYPE_AON) {
320 hal_nvic_clear_pending_irq(EXT2_IRQn);
321 hal_nvic_enable_irq(EXT2_IRQn);
322 }
323
324 return APP_DRV_SUCCESS;
325 }
326
app_gpiote_deinit(void)327 void app_gpiote_deinit(void)
328 {
329 for (int idx = 0; idx < s_gpiote_env.total_used; idx++) {
330 app_io_deinit(s_gpiote_env.params[idx].type, s_gpiote_env.params[idx].pin);
331 }
332 hal_nvic_disable_irq(EXT0_IRQn);
333 hal_nvic_disable_irq(EXT1_IRQn);
334 hal_nvic_disable_irq(EXT2_IRQn);
335 pwr_unregister_sleep_cb(s_gpiote_pwr_id);
336 s_gpiote_env.total_used = 0;
337 }
338
hal_gpio_exti_callback(gpio_regs_t * GPIOx,uint16_t gpio_pin)339 void hal_gpio_exti_callback(gpio_regs_t *GPIOx, uint16_t gpio_pin)
340 {
341 uint32_t io_pin = gpio_pin;
342 app_gpiote_evt_t gpiote_evt;
343
344 if (GPIO1 == GPIOx) {
345 io_pin = (uint32_t)(gpio_pin << BIT_16);
346 }
347
348 gpiote_evt.type = APP_IO_TYPE_NORMAL;
349 gpiote_evt.pin = io_pin;
350 gpiote_evt.ctx_type = APP_IO_CTX_INT;
351
352 for (uint8_t idx = 0; idx < s_gpiote_env.total_used; idx++) {
353 if ((s_gpiote_env.params[idx].type == APP_IO_TYPE_NORMAL) && (io_pin == s_gpiote_env.params[idx].pin)) {
354 if (s_gpiote_env.params[idx].io_evt_cb)
355 s_gpiote_env.params[idx].io_evt_cb(&gpiote_evt);
356 }
357 }
358 }
359
gpio_callback_config(uint8_t idx,uint16_t aon_gpio_pin,uint8_t * p_called_flag,uint8_t * p_called_table_used_pos,app_gpiote_evt_t gpiote_evt)360 static void gpio_callback_config(uint8_t idx, uint16_t aon_gpio_pin, uint8_t *p_called_flag,
361 uint8_t *p_called_table_used_pos, app_gpiote_evt_t gpiote_evt)
362 {
363 if ((s_gpiote_env.params[idx].type == APP_IO_TYPE_AON) && \
364 (aon_gpio_pin & s_gpiote_env.params[idx].pin) && \
365 (s_gpiote_env.params[idx].io_evt_cb)) {
366 for (uint8_t i = 0; i < *p_called_table_used_pos; i++) {
367 if (aon_cb_called_table[i] == s_gpiote_env.params[idx].io_evt_cb) {
368 *p_called_flag = 1;
369 break;
370 } else {
371 *p_called_flag = 0;
372 }
373 }
374 if (*p_called_flag == 0) {
375 s_gpiote_env.params[idx].io_evt_cb(&gpiote_evt);
376 aon_cb_called_table[*p_called_table_used_pos] = s_gpiote_env.params[idx].io_evt_cb;
377 *p_called_table_used_pos++;
378 }
379 }
380 }
381
hal_aon_gpio_callback(uint16_t aon_gpio_pin)382 void hal_aon_gpio_callback(uint16_t aon_gpio_pin)
383 {
384 uint8_t called_table_used_pos = 0;
385 uint8_t called_flag = 0;
386
387 app_gpiote_evt_t gpiote_evt;
388
389 gpiote_evt.type = APP_IO_TYPE_AON;
390 gpiote_evt.pin = aon_gpio_pin;
391
392 if (pwr_mgmt_get_wakeup_flag() == WARM_BOOT) {
393 gpiote_evt.ctx_type = APP_IO_CTX_WAKEUP;
394 } else {
395 gpiote_evt.ctx_type = APP_IO_CTX_INT;
396 }
397
398 memset_s(aon_cb_called_table, sizeof(aon_cb_called_table), 0, sizeof(aon_cb_called_table));
399 for (uint8_t idx = 0; idx < s_gpiote_env.total_used; idx++) {
400 gpio_callback_config(idx, aon_gpio_pin, &called_flag,
401 &called_table_used_pos, gpiote_evt);
402 }
403 }
404
EXT0_IRQHandler(void)405 SECTION_RAM_CODE void EXT0_IRQHandler(void)
406 {
407 #if FLASH_PROTECT_PRIORITY
408 platform_interrupt_protection_push();
409 #endif
410 hal_gpio_exti_irq_handler(GPIO0);
411 #if FLASH_PROTECT_PRIORITY
412 platform_interrupt_protection_pop();
413 #endif
414 }
415
EXT1_IRQHandler(void)416 SECTION_RAM_CODE void EXT1_IRQHandler(void)
417 {
418 #if FLASH_PROTECT_PRIORITY
419 platform_interrupt_protection_push();
420 #endif
421 hal_gpio_exti_irq_handler(GPIO1);
422 #if FLASH_PROTECT_PRIORITY
423 platform_interrupt_protection_pop();
424 #endif
425 }
426
EXT2_IRQHandler(void)427 SECTION_RAM_CODE void EXT2_IRQHandler(void)
428 {
429 #if FLASH_PROTECT_PRIORITY
430 platform_interrupt_protection_push();
431 #endif
432 hal_aon_gpio_irq_handler();
433 #if FLASH_PROTECT_PRIORITY
434 platform_interrupt_protection_pop();
435 #endif
436 }
437