api-hal-os.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. #include <api-hal-os.h>
  2. #include <api-hal-os-timer.h>
  3. #include <api-hal-power.h>
  4. #include <FreeRTOS.h>
  5. #include <cmsis_os.h>
  6. #define API_HAL_OS_CLK_FREQUENCY 32768
  7. #define API_HAL_OS_TICK_PER_SECOND 1024
  8. #define API_HAL_OS_CLK_PER_TICK (API_HAL_OS_CLK_FREQUENCY / API_HAL_OS_TICK_PER_SECOND)
  9. #define API_HAL_OS_TICK_PER_EPOCH (API_HAL_OS_TIMER_MAX / API_HAL_OS_CLK_PER_TICK)
  10. #define API_HAL_OS_MAX_SLEEP (API_HAL_OS_TICK_PER_EPOCH - 1)
  11. #ifdef API_HAL_OS_DEBUG
  12. #include <stm32wbxx_ll_gpio.h>
  13. #define LED_GREEN_PORT GPIOA
  14. #define LED_GREEN_PIN LL_GPIO_PIN_2
  15. #endif
  16. typedef struct {
  17. // Tick counters
  18. volatile uint32_t in_sleep;
  19. volatile uint32_t in_awake;
  20. // Error counters
  21. volatile uint32_t sleep_error;
  22. volatile uint32_t awake_error;
  23. } ApiHalOs;
  24. ApiHalOs api_hal_os = {
  25. .in_sleep = 0,
  26. .in_awake = 0,
  27. .sleep_error = 0,
  28. .awake_error = 0,
  29. };
  30. void api_hal_os_init() {
  31. api_hal_os_timer_init();
  32. LL_DBGMCU_APB1_GRP2_FreezePeriph(LL_DBGMCU_APB1_GRP2_LPTIM2_STOP);
  33. LL_LPTIM_EnableIT_CMPM(API_HAL_OS_TIMER);
  34. LL_LPTIM_EnableIT_ARRM(API_HAL_OS_TIMER);
  35. LL_LPTIM_SetAutoReload(API_HAL_OS_TIMER, API_HAL_OS_TIMER_MAX);
  36. LL_LPTIM_SetCompare(API_HAL_OS_TIMER, API_HAL_OS_CLK_PER_TICK);
  37. LL_LPTIM_StartCounter(API_HAL_OS_TIMER, LL_LPTIM_OPERATING_MODE_CONTINUOUS);
  38. }
  39. void LPTIM2_IRQHandler(void) {
  40. // Autoreload
  41. const bool arrm_flag = LL_LPTIM_IsActiveFlag_ARRM(API_HAL_OS_TIMER);
  42. if(arrm_flag) {
  43. LL_LPTIM_ClearFLAG_ARRM(API_HAL_OS_TIMER);
  44. }
  45. if(LL_LPTIM_IsActiveFlag_CMPM(API_HAL_OS_TIMER)) {
  46. LL_LPTIM_ClearFLAG_CMPM(API_HAL_OS_TIMER);
  47. // Store important value
  48. uint16_t cnt = api_hal_os_timer_get_cnt();
  49. uint16_t cmp = api_hal_os_timer_get_cmp();
  50. uint16_t current_tick = cnt / API_HAL_OS_CLK_PER_TICK;
  51. uint16_t compare_tick = cmp / API_HAL_OS_CLK_PER_TICK;
  52. // Calculate error
  53. // happens when HAL or other high priority IRQ takes our time
  54. int32_t error = (int32_t)compare_tick - current_tick;
  55. api_hal_os.awake_error += ((error>0) ? error : -error);
  56. // Calculate and set next tick
  57. uint16_t next_tick = current_tick + 1;
  58. api_hal_os_timer_set_cmp(next_tick * API_HAL_OS_CLK_PER_TICK);
  59. // Notify OS
  60. api_hal_os.in_awake ++;
  61. if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
  62. xPortSysTickHandler();
  63. }
  64. }
  65. }
  66. static inline uint32_t api_hal_os_sleep(TickType_t expected_idle_ticks) {
  67. // Store important value before going to sleep
  68. const uint16_t before_cnt = api_hal_os_timer_get_cnt();
  69. const uint16_t before_tick = before_cnt / API_HAL_OS_CLK_PER_TICK;
  70. // Calculate and set next wakeup compare value
  71. const uint16_t expected_cnt = (before_tick + expected_idle_ticks - 2) * API_HAL_OS_CLK_PER_TICK;
  72. api_hal_os_timer_set_cmp(expected_cnt);
  73. HAL_SuspendTick();
  74. // Go to stop2 mode
  75. #ifdef API_HAL_OS_DEBUG
  76. LL_GPIO_SetOutputPin(LED_GREEN_PORT, LED_GREEN_PIN);
  77. #endif
  78. api_hal_power_deep_sleep();
  79. #ifdef API_HAL_OS_DEBUG
  80. LL_GPIO_ResetOutputPin(LED_GREEN_PORT, LED_GREEN_PIN);
  81. #endif
  82. HAL_ResumeTick();
  83. // Spin till we are in timer safe zone
  84. while(!api_hal_os_timer_is_safe()) {}
  85. // Store current counter value, calculate current tick
  86. const uint16_t after_cnt = api_hal_os_timer_get_cnt();
  87. const uint16_t after_tick = after_cnt / API_HAL_OS_CLK_PER_TICK;
  88. // Store and clear interrupt flags
  89. // we don't want handler to be called after renabling IRQ
  90. bool arrm_flag = LL_LPTIM_IsActiveFlag_ARRM(API_HAL_OS_TIMER);
  91. // Calculate and set next wakeup compare value
  92. const uint16_t next_cmp = (after_tick + 1) * API_HAL_OS_CLK_PER_TICK;
  93. api_hal_os_timer_set_cmp(next_cmp);
  94. // Calculate ticks count spent in sleep and perform sanity checks
  95. int32_t completed_ticks = arrm_flag ? (int32_t)before_tick - after_tick : (int32_t)after_tick - before_tick;
  96. return completed_ticks;
  97. }
  98. void vPortSuppressTicksAndSleep(TickType_t expected_idle_ticks) {
  99. if (!api_hal_power_deep_available()) {
  100. return;
  101. }
  102. // Limit mount of ticks to maximum that timer can count
  103. if (expected_idle_ticks > API_HAL_OS_MAX_SLEEP) {
  104. expected_idle_ticks = API_HAL_OS_MAX_SLEEP;
  105. }
  106. // Stop IRQ handling, no one should disturb us till we finish
  107. __disable_irq();
  108. // Confirm OS that sleep is still possible
  109. // And check if timer is in safe zone
  110. // (8 clocks till any IRQ event or ongoing synchronization)
  111. if (eTaskConfirmSleepModeStatus() == eAbortSleep
  112. || !api_hal_os_timer_is_safe()) {
  113. __enable_irq();
  114. return;
  115. }
  116. uint32_t completed_ticks = api_hal_os_sleep(expected_idle_ticks);
  117. assert(completed_ticks >= 0);
  118. // Reenable IRQ
  119. __enable_irq();
  120. // Notify system about time spent in sleep
  121. if (completed_ticks > 0) {
  122. api_hal_os.in_sleep += completed_ticks;
  123. if (completed_ticks > expected_idle_ticks) {
  124. // We are late, count error
  125. api_hal_os.sleep_error += (completed_ticks - expected_idle_ticks);
  126. // Freertos is not happy when we overleep
  127. // But we are not going to tell her
  128. vTaskStepTick(expected_idle_ticks);
  129. } else {
  130. vTaskStepTick(completed_ticks);
  131. }
  132. }
  133. }
  134. void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName) {
  135. asm("bkpt 1");
  136. while(1) {};
  137. }