NuMaker tickless example

Committer:
SHLIU1@OANBE02333.nuvoton.com
Date:
Thu Feb 25 15:25:00 2021 +0800
Revision:
21:5424989f037f
Parent:
13:c1c711d573f2
Support the both V5.X and V6.X for mbed-os

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ccli8 1:eb1da9d36e12 1 #include "mbed.h"
ccli8 1:eb1da9d36e12 2 #include <limits.h>
ccli8 1:eb1da9d36e12 3 #include <vector>
ccli8 1:eb1da9d36e12 4
ccli8 1:eb1da9d36e12 5 #include "wakeup.h"
ccli8 1:eb1da9d36e12 6
ccli8 1:eb1da9d36e12 7 static void flush_stdio_uart_fifo(void);
ccli8 1:eb1da9d36e12 8 static void check_wakeup_source(uint32_t, bool deepsleep);
ccli8 13:c1c711d573f2 9 #if (! defined(MBED_TICKLESS))
ccli8 6:de274e3aed9d 10 static void idle_hdlr(void);
ccli8 13:c1c711d573f2 11 #endif
ccli8 1:eb1da9d36e12 12
ccli8 1:eb1da9d36e12 13 EventFlags wakeup_eventflags;
ccli8 1:eb1da9d36e12 14
ccli8 1:eb1da9d36e12 15 int main() {
SHLIU1@OANBE02333.nuvoton.com 21:5424989f037f 16 #ifdef MBED_MAJOR_VERSION
SHLIU1@OANBE02333.nuvoton.com 21:5424989f037f 17 printf("Mbed OS version %d.%d.%d\r\n\n", MBED_MAJOR_VERSION, MBED_MINOR_VERSION, MBED_PATCH_VERSION);
SHLIU1@OANBE02333.nuvoton.com 21:5424989f037f 18 #endif
ccli8 1:eb1da9d36e12 19 config_pwrctl();
ccli8 1:eb1da9d36e12 20 config_button_wakeup();
ccli8 1:eb1da9d36e12 21 config_wdt_wakeup();
ccli8 1:eb1da9d36e12 22 config_rtc_wakeup();
ccli8 1:eb1da9d36e12 23 /* TODO */
ccli8 1:eb1da9d36e12 24 //config_uart_wakeup();
ccli8 1:eb1da9d36e12 25 //config_i2c_wakeup();
ccli8 1:eb1da9d36e12 26
ccli8 13:c1c711d573f2 27 #if defined(MBED_TICKLESS)
ccli8 13:c1c711d573f2 28 /* Run Mbed OS internal idle handler */
ccli8 13:c1c711d573f2 29 #else
ccli8 1:eb1da9d36e12 30 /* Register idle handler which supports tickless */
ccli8 6:de274e3aed9d 31 Thread::attach_idle_hook(idle_hdlr);
ccli8 13:c1c711d573f2 32 #endif
ccli8 13:c1c711d573f2 33
ccli8 1:eb1da9d36e12 34 while (true) {
ccli8 1:eb1da9d36e12 35
ccli8 1:eb1da9d36e12 36 printf("I am going to shallow/deep sleep\n");
ccli8 1:eb1da9d36e12 37 /* Flush STDIO UART before entering Idle/Power-down mode */
ccli8 1:eb1da9d36e12 38 fflush(stdout);
ccli8 1:eb1da9d36e12 39 flush_stdio_uart_fifo();
ccli8 1:eb1da9d36e12 40
ccli8 1:eb1da9d36e12 41 /* Wait for any wake-up event */
ccli8 1:eb1da9d36e12 42 uint32_t flags = wakeup_eventflags.wait_any(EventFlag_Wakeup_All, osWaitForever, true);
ccli8 1:eb1da9d36e12 43 if (flags & osFlagsError) {
ccli8 1:eb1da9d36e12 44 if (flags != osFlagsErrorTimeout) {
ccli8 1:eb1da9d36e12 45 printf("OS error code: 0x%08lX\n", flags);
ccli8 1:eb1da9d36e12 46 }
ccli8 1:eb1da9d36e12 47 continue;
ccli8 1:eb1da9d36e12 48 }
ccli8 1:eb1da9d36e12 49
ccli8 1:eb1da9d36e12 50 /* EventFlag_Wakeup_UnID is set in PWRWU_IRQHandler to indicate unidentified wake-up from power-down.
ccli8 1:eb1da9d36e12 51 * It could be deferred. Wait for it. */
ccli8 1:eb1da9d36e12 52 uint32_t flags2 = wakeup_eventflags.wait_any(EventFlag_Wakeup_UnID, 100, true);
ccli8 1:eb1da9d36e12 53 if (flags2 & osFlagsError) {
ccli8 1:eb1da9d36e12 54 if (flags2 != osFlagsErrorTimeout) {
ccli8 1:eb1da9d36e12 55 printf("OS error code: 0x%08lX\n", flags2);
ccli8 1:eb1da9d36e12 56 }
ccli8 1:eb1da9d36e12 57 else {
ccli8 1:eb1da9d36e12 58 flags2 = 0;
ccli8 1:eb1da9d36e12 59 }
ccli8 1:eb1da9d36e12 60 }
ccli8 1:eb1da9d36e12 61 flags |= flags2;
ccli8 1:eb1da9d36e12 62
ccli8 1:eb1da9d36e12 63 /* EventFlag_Wakeup_UnID means unidentified wake-up source from power-down.
ccli8 1:eb1da9d36e12 64 *
ccli8 1:eb1da9d36e12 65 * If EventFlag_Wakeup_UnID is set, we wake up from power-down mode (deep sleep) but its wake-up
ccli8 1:eb1da9d36e12 66 * source is not yet identified. Wait for it to be identified if no other wake-up sources have been
ccli8 1:eb1da9d36e12 67 * identified.
ccli8 1:eb1da9d36e12 68 *
ccli8 1:eb1da9d36e12 69 * If EventFlag_Wakeup_UnID is not set, we wake up from idle mode (shallow sleep). Wake-up source
ccli8 1:eb1da9d36e12 70 * would have been identified.
ccli8 1:eb1da9d36e12 71 */
ccli8 1:eb1da9d36e12 72 if (flags == EventFlag_Wakeup_UnID) {
ccli8 1:eb1da9d36e12 73 uint32_t flags3 = wakeup_eventflags.wait_any(EventFlag_Wakeup_All & ~EventFlag_Wakeup_UnID, 100, true);
ccli8 1:eb1da9d36e12 74 if (flags3 & osFlagsError) {
ccli8 1:eb1da9d36e12 75 if (flags3 != osFlagsErrorTimeout) {
ccli8 1:eb1da9d36e12 76 printf("OS error code: 0x%08lX\n", flags3);
ccli8 1:eb1da9d36e12 77 }
ccli8 1:eb1da9d36e12 78 else {
ccli8 1:eb1da9d36e12 79 flags3 = 0;
ccli8 1:eb1da9d36e12 80 }
ccli8 1:eb1da9d36e12 81 }
ccli8 1:eb1da9d36e12 82 flags |= flags3;
ccli8 1:eb1da9d36e12 83 }
ccli8 1:eb1da9d36e12 84
ccli8 1:eb1da9d36e12 85 /* Clear wake-up flags caused by short time EventFlags::wait_any() above. These wake-up flags are
ccli8 1:eb1da9d36e12 86 * just for program control and not actual wake-up events we want to track. This has a side effect of
ccli8 1:eb1da9d36e12 87 * losing actual wake-up events in this short time. */
ccli8 1:eb1da9d36e12 88 wakeup_eventflags.clear();
ccli8 1:eb1da9d36e12 89
ccli8 1:eb1da9d36e12 90 bool deepsleep = (flags & EventFlag_Wakeup_UnID) ? true : false;
ccli8 1:eb1da9d36e12 91
ccli8 1:eb1da9d36e12 92 /* Remove EventFlag_Wakeup_UnID if any other wake-up source is identified */
ccli8 1:eb1da9d36e12 93 if ((flags & ~EventFlag_Wakeup_UnID)) {
ccli8 1:eb1da9d36e12 94 flags &= ~EventFlag_Wakeup_UnID;
ccli8 1:eb1da9d36e12 95 }
ccli8 1:eb1da9d36e12 96 check_wakeup_source(flags, deepsleep);
ccli8 1:eb1da9d36e12 97
ccli8 1:eb1da9d36e12 98 printf("\n");
ccli8 1:eb1da9d36e12 99 }
ccli8 1:eb1da9d36e12 100
ccli8 1:eb1da9d36e12 101 return 0;
ccli8 1:eb1da9d36e12 102 }
ccli8 1:eb1da9d36e12 103
ccli8 1:eb1da9d36e12 104 void flush_stdio_uart_fifo(void)
ccli8 1:eb1da9d36e12 105 {
ccli8 1:eb1da9d36e12 106 UART_T *uart_base = (UART_T *) NU_MODBASE(STDIO_UART);
ccli8 1:eb1da9d36e12 107
ccli8 1:eb1da9d36e12 108 while (! UART_IS_TX_EMPTY(uart_base));
ccli8 1:eb1da9d36e12 109 }
ccli8 1:eb1da9d36e12 110
ccli8 1:eb1da9d36e12 111 void check_wakeup_source(uint32_t flags, bool deepsleep)
ccli8 1:eb1da9d36e12 112 {
ccli8 1:eb1da9d36e12 113 typedef std::pair<uint32_t, const char *> WakeupName;
ccli8 1:eb1da9d36e12 114
ccli8 1:eb1da9d36e12 115 static const WakeupName wakeup_name_arr[] = {
ccli8 1:eb1da9d36e12 116 WakeupName(EventFlag_Wakeup_Button1, "Button1"),
ccli8 1:eb1da9d36e12 117 WakeupName(EventFlag_Wakeup_Button2, "Button2"),
ccli8 1:eb1da9d36e12 118 WakeupName(EventFlag_Wakeup_LPTicker, "lp_ticker"),
ccli8 1:eb1da9d36e12 119 WakeupName(EventFlag_Wakeup_WDT_Timeout, "WDT timeout"),
ccli8 1:eb1da9d36e12 120 WakeupName(EventFlag_Wakeup_RTC_Alarm, "RTC alarm"),
ccli8 1:eb1da9d36e12 121 WakeupName(EventFlag_Wakeup_UART_CTS, "UART CTS"),
ccli8 1:eb1da9d36e12 122 WakeupName(EventFlag_Wakeup_I2C_AddrMatch, "I2C address match"),
ccli8 1:eb1da9d36e12 123
ccli8 1:eb1da9d36e12 124 WakeupName(EventFlag_Wakeup_UnID, "Unidentified"),
ccli8 1:eb1da9d36e12 125 };
ccli8 1:eb1da9d36e12 126
ccli8 1:eb1da9d36e12 127 const char *sleep_mode = deepsleep ? "deep sleep" : "shallow sleep";
ccli8 1:eb1da9d36e12 128
ccli8 1:eb1da9d36e12 129 if (flags) {
ccli8 1:eb1da9d36e12 130 const WakeupName *wakeup_name_pos = wakeup_name_arr;
ccli8 1:eb1da9d36e12 131 const WakeupName *wakeup_name_end = wakeup_name_arr + (sizeof (wakeup_name_arr) / sizeof (wakeup_name_arr[0]));
ccli8 1:eb1da9d36e12 132
ccli8 1:eb1da9d36e12 133 for (; wakeup_name_pos != wakeup_name_end; wakeup_name_pos ++) {
ccli8 1:eb1da9d36e12 134 if (flags & wakeup_name_pos->first) {
ccli8 1:eb1da9d36e12 135 printf("Wake up by %s from %s\n", wakeup_name_pos->second, sleep_mode);
ccli8 1:eb1da9d36e12 136 }
ccli8 1:eb1da9d36e12 137 }
ccli8 1:eb1da9d36e12 138 }
ccli8 1:eb1da9d36e12 139 }
ccli8 1:eb1da9d36e12 140
ccli8 13:c1c711d573f2 141 #if (! defined(MBED_TICKLESS))
ccli8 13:c1c711d573f2 142
ccli8 1:eb1da9d36e12 143 #define US_PER_SEC (1000 * 1000)
ccli8 1:eb1da9d36e12 144 #define US_PER_OS_TICK (US_PER_SEC / OS_TICK_FREQ)
ccli8 1:eb1da9d36e12 145
ccli8 1:eb1da9d36e12 146 void dummy_cb(void) {}
ccli8 1:eb1da9d36e12 147
ccli8 6:de274e3aed9d 148 void idle_hdlr(void) {
ccli8 1:eb1da9d36e12 149
ccli8 1:eb1da9d36e12 150 const int max_us_sleep = (INT_MAX / OS_TICK_FREQ) * OS_TICK_FREQ;
ccli8 1:eb1da9d36e12 151 /* Keep track of the time asleep */
ccli8 1:eb1da9d36e12 152 LowPowerTimer asleep_watch;
ccli8 1:eb1da9d36e12 153 /* Will wake up the system (by lp_ticker) if no other wake-up event */
ccli8 1:eb1da9d36e12 154 LowPowerTimeout alarm_clock;
ccli8 1:eb1da9d36e12 155
ccli8 6:de274e3aed9d 156 /* Suspend the system */
ccli8 6:de274e3aed9d 157 uint32_t ticks_to_sleep = osKernelSuspend();
ccli8 6:de274e3aed9d 158 uint32_t elapsed_ticks = 0;
ccli8 1:eb1da9d36e12 159
ccli8 6:de274e3aed9d 160 if (ticks_to_sleep) {
ccli8 6:de274e3aed9d 161 uint64_t us_to_sleep = ticks_to_sleep * US_PER_OS_TICK;
ccli8 1:eb1da9d36e12 162
ccli8 6:de274e3aed9d 163 if (us_to_sleep > max_us_sleep) {
ccli8 6:de274e3aed9d 164 us_to_sleep = max_us_sleep;
ccli8 1:eb1da9d36e12 165 }
ccli8 1:eb1da9d36e12 166
ccli8 6:de274e3aed9d 167 /* Start the asleep_watch and setup the alarm_clock to wake up the system in us_to_sleep */
ccli8 6:de274e3aed9d 168 asleep_watch.start();
ccli8 6:de274e3aed9d 169 alarm_clock.attach_us(dummy_cb, us_to_sleep);
ccli8 6:de274e3aed9d 170
ccli8 6:de274e3aed9d 171 /* Go to deep sleep */
ccli8 6:de274e3aed9d 172 deepsleep();
ccli8 6:de274e3aed9d 173
ccli8 6:de274e3aed9d 174 /* Woken up by lp_ticker or other wake-up event */
ccli8 6:de274e3aed9d 175 int us_asleep = asleep_watch.read_us();
ccli8 6:de274e3aed9d 176
ccli8 6:de274e3aed9d 177 /* Clean up asleep_watch and alarm_clock */
ccli8 6:de274e3aed9d 178 asleep_watch.stop();
ccli8 6:de274e3aed9d 179 asleep_watch.reset();
ccli8 6:de274e3aed9d 180 alarm_clock.detach();
ccli8 6:de274e3aed9d 181
ccli8 6:de274e3aed9d 182 /* Translate us_asleep into ticks */
ccli8 6:de274e3aed9d 183 elapsed_ticks = us_asleep / US_PER_OS_TICK;
ccli8 1:eb1da9d36e12 184 }
ccli8 6:de274e3aed9d 185
ccli8 6:de274e3aed9d 186 /* Resume the system */
ccli8 6:de274e3aed9d 187 osKernelResume(elapsed_ticks);
ccli8 1:eb1da9d36e12 188 }
ccli8 13:c1c711d573f2 189
ccli8 13:c1c711d573f2 190 #endif