task_wdt_impl_timergroup.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stdint.h>
  7. #include <stdbool.h>
  8. #include <stdio.h>
  9. #include "sdkconfig.h"
  10. #include "hal/wdt_hal.h"
  11. #include "hal/mwdt_ll.h"
  12. #include "hal/timer_ll.h"
  13. #include "esp_err.h"
  14. #include "esp_attr.h"
  15. #include "esp_intr_alloc.h"
  16. #include "esp_private/system_internal.h"
  17. #include "esp_private/periph_ctrl.h"
  18. #include "esp_private/esp_task_wdt_impl.h"
  19. #define TWDT_INSTANCE WDT_MWDT0
  20. #define TWDT_TICKS_PER_US 500
  21. #define TWDT_PRESCALER MWDT_LL_DEFAULT_CLK_PRESCALER // Tick period of 500us if WDT source clock is 80MHz
  22. #define TWDT_PERIPH_MODULE PERIPH_TIMG0_MODULE
  23. #define TWDT_TIMER_GROUP 0
  24. #define TWDT_INTR_SOURCE ETS_TG0_WDT_LEVEL_INTR_SOURCE
  25. /**
  26. * Context for the software implementation of the Task WatchDog Timer.
  27. * This will be passed as a parameter to public functions below. */
  28. typedef struct {
  29. wdt_hal_context_t hal;
  30. intr_handle_t intr_handle;
  31. } twdt_ctx_hard_t;
  32. /**
  33. * Declare the initial context as static. It will be passed to the
  34. * task_wdt implementation as the implementation context in the
  35. * init function. */
  36. static twdt_ctx_hard_t init_context;
  37. esp_err_t esp_task_wdt_impl_timer_allocate(const esp_task_wdt_config_t *config,
  38. twdt_isr_callback callback,
  39. twdt_ctx_t *obj)
  40. {
  41. esp_err_t ret = ESP_OK;
  42. twdt_ctx_hard_t *ctx = &init_context;
  43. if (config == NULL || obj == NULL) {
  44. ret = ESP_ERR_INVALID_STATE;
  45. }
  46. if (ret == ESP_OK) {
  47. esp_intr_alloc(TWDT_INTR_SOURCE, 0, callback, NULL, &ctx->intr_handle);
  48. }
  49. if (ret == ESP_OK) {
  50. // enable bus clock for the timer group registers
  51. PERIPH_RCC_ACQUIRE_ATOMIC(TWDT_PERIPH_MODULE, ref_count) {
  52. if (ref_count == 0) {
  53. timer_ll_enable_bus_clock(TWDT_TIMER_GROUP, true);
  54. timer_ll_reset_register(TWDT_TIMER_GROUP);
  55. }
  56. }
  57. wdt_hal_init(&ctx->hal, TWDT_INSTANCE, TWDT_PRESCALER, true);
  58. wdt_hal_write_protect_disable(&ctx->hal);
  59. // Configure 1st stage timeout and behavior
  60. wdt_hal_config_stage(&ctx->hal, WDT_STAGE0, config->timeout_ms * (1000 / TWDT_TICKS_PER_US), WDT_STAGE_ACTION_INT);
  61. // Configure 2nd stage timeout and behavior
  62. wdt_hal_config_stage(&ctx->hal, WDT_STAGE1, config->timeout_ms * (2 * 1000 / TWDT_TICKS_PER_US), WDT_STAGE_ACTION_RESET_SYSTEM);
  63. // No need to enable to enable the WDT here, it will be enabled with `esp_task_wdt_impl_timer_restart`
  64. wdt_hal_write_protect_enable(&ctx->hal);
  65. /* Return the implementation context to the caller */
  66. *obj = (twdt_ctx_t) ctx;
  67. }
  68. return ret;
  69. }
  70. esp_err_t esp_task_wdt_impl_timer_reconfigure(twdt_ctx_t obj, const esp_task_wdt_config_t *config)
  71. {
  72. esp_err_t ret = ESP_OK;
  73. twdt_ctx_hard_t* ctx = (twdt_ctx_hard_t*) obj;
  74. if (config == NULL || ctx == NULL) {
  75. ret = ESP_ERR_INVALID_STATE;
  76. }
  77. if (ret == ESP_OK) {
  78. wdt_hal_write_protect_disable(&ctx->hal);
  79. /* Reconfigure the 1st and 2nd stage timeout */
  80. wdt_hal_config_stage(&ctx->hal, WDT_STAGE0, config->timeout_ms * (1000 / TWDT_TICKS_PER_US), WDT_STAGE_ACTION_INT);
  81. wdt_hal_config_stage(&ctx->hal, WDT_STAGE1, config->timeout_ms * (2 * 1000 / TWDT_TICKS_PER_US), WDT_STAGE_ACTION_RESET_SYSTEM);
  82. wdt_hal_write_protect_enable(&ctx->hal);
  83. }
  84. return ret;
  85. }
  86. void esp_task_wdt_impl_timer_free(twdt_ctx_t obj)
  87. {
  88. twdt_ctx_hard_t* ctx = (twdt_ctx_hard_t*) obj;
  89. if (ctx != NULL) {
  90. /* Stop hardware timer and the interrupt associated */
  91. wdt_hal_deinit(&ctx->hal);
  92. ESP_ERROR_CHECK(esp_intr_disable(ctx->intr_handle));
  93. /* Disable the Timer Group module */
  94. PERIPH_RCC_RELEASE_ATOMIC(TWDT_PERIPH_MODULE, ref_count) {
  95. if (ref_count == 0) {
  96. timer_ll_enable_bus_clock(TWDT_TIMER_GROUP, false);
  97. }
  98. }
  99. /* Deregister interrupt */
  100. ESP_ERROR_CHECK(esp_intr_free(ctx->intr_handle));
  101. }
  102. }
  103. esp_err_t esp_task_wdt_impl_timer_feed(twdt_ctx_t obj)
  104. {
  105. esp_err_t ret = ESP_OK;
  106. twdt_ctx_hard_t* ctx = (twdt_ctx_hard_t*) obj;
  107. if (ctx == NULL) {
  108. ret = ESP_ERR_INVALID_STATE;
  109. }
  110. if (ret == ESP_OK) {
  111. wdt_hal_write_protect_disable(&ctx->hal);
  112. wdt_hal_feed(&ctx->hal);
  113. wdt_hal_write_protect_enable(&ctx->hal);
  114. }
  115. return ret;
  116. }
  117. void esp_task_wdt_impl_timeout_triggered(twdt_ctx_t obj)
  118. {
  119. twdt_ctx_hard_t* ctx = (twdt_ctx_hard_t*) obj;
  120. if (ctx != NULL) {
  121. /* Reset hardware timer so that 2nd stage timeout is not reached (will trigger system reset) */
  122. wdt_hal_write_protect_disable(&ctx->hal);
  123. wdt_hal_handle_intr(&ctx->hal); // Feeds WDT and clears acknowledges interrupt
  124. wdt_hal_write_protect_enable(&ctx->hal);
  125. }
  126. }
  127. esp_err_t esp_task_wdt_impl_timer_stop(twdt_ctx_t obj)
  128. {
  129. esp_err_t ret = ESP_OK;
  130. twdt_ctx_hard_t* ctx = (twdt_ctx_hard_t*) obj;
  131. if (ctx == NULL) {
  132. ret = ESP_ERR_INVALID_STATE;
  133. }
  134. if (ret == ESP_OK) {
  135. wdt_hal_write_protect_disable(&ctx->hal);
  136. wdt_hal_disable(&ctx->hal);
  137. wdt_hal_write_protect_enable(&ctx->hal);
  138. }
  139. return ret;
  140. }
  141. esp_err_t esp_task_wdt_impl_timer_restart(twdt_ctx_t obj)
  142. {
  143. esp_err_t ret = ESP_OK;
  144. twdt_ctx_hard_t* ctx = (twdt_ctx_hard_t*) obj;
  145. if (ctx == NULL) {
  146. ret = ESP_ERR_INVALID_STATE;
  147. }
  148. if (ret == ESP_OK) {
  149. wdt_hal_write_protect_disable(&ctx->hal);
  150. wdt_hal_enable(&ctx->hal);
  151. wdt_hal_feed(&ctx->hal);
  152. wdt_hal_write_protect_enable(&ctx->hal);
  153. }
  154. return ret;
  155. }