NuMaker tickless example

Committer:
ccli8
Date:
Fri Feb 21 11:19:30 2020 +0800
Revision:
16:ed2c228cbc9c
Parent:
12:b0d19e915d96
Child:
17:0f81445cbbf0
Update to mbed-os 5.15.1 and accompanying modifications

1. Remove OS_IDLE_THREAD_STACK_SIZE because mbed-os has has reasonable default value.
2. Configure tickless-from-us-ticker to false. It is needed to run tickless mode with lp_ticker instead of us_ticker for wake-up.
3. Disable WDT wake-up when Mbed OS watchog API is enabled.
4. Fix deprecated API.
5. Update readme.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ccli8 1:eb1da9d36e12 1 #include "mbed.h"
ccli8 1:eb1da9d36e12 2 #include "wakeup.h"
ccli8 1:eb1da9d36e12 3 #include "rtc_api.h"
ccli8 1:eb1da9d36e12 4 #include "mbed_mktime.h"
ccli8 1:eb1da9d36e12 5
ccli8 12:b0d19e915d96 6 /* Micro seconds per second */
ccli8 12:b0d19e915d96 7 #define NU_US_PER_SEC 1000000
ccli8 12:b0d19e915d96 8
ccli8 12:b0d19e915d96 9 /* Timer clock per second
ccli8 12:b0d19e915d96 10 *
ccli8 12:b0d19e915d96 11 * NOTE: This dependents on real hardware.
ccli8 12:b0d19e915d96 12 */
ccli8 12:b0d19e915d96 13 #if defined(TARGET_NUMAKER_PFM_NANO130)
ccli8 12:b0d19e915d96 14 #define NU_RTCCLK_PER_SEC (__LXT)
ccli8 12:b0d19e915d96 15 #else
ccli8 12:b0d19e915d96 16 #define NU_RTCCLK_PER_SEC ((CLK->CLKSEL3 & CLK_CLKSEL3_SC0SEL_Msk) ? __LIRC : __LXT)
ccli8 12:b0d19e915d96 17 #endif
ccli8 12:b0d19e915d96 18
ccli8 12:b0d19e915d96 19 /* Start year of struct TM*/
ccli8 12:b0d19e915d96 20 #define NU_TM_YEAR0 1900
ccli8 12:b0d19e915d96 21 /* Start year of POSIX time (set_time()/time()) */
ccli8 12:b0d19e915d96 22 #define NU_POSIX_YEAR0 1970
ccli8 12:b0d19e915d96 23 /* Start year of H/W RTC */
ccli8 12:b0d19e915d96 24 #define NU_HWRTC_YEAR0 2000
ccli8 1:eb1da9d36e12 25
ccli8 4:da41f0e17d5a 26 static Semaphore sem_rtc(0, 1);
ccli8 4:da41f0e17d5a 27
ccli8 4:da41f0e17d5a 28 static void rtc_loop(void);
ccli8 4:da41f0e17d5a 29 static void schedule_rtc_alarm(uint32_t secs);
ccli8 1:eb1da9d36e12 30
ccli8 12:b0d19e915d96 31 /* Convert date time from H/W RTC to struct TM */
ccli8 12:b0d19e915d96 32 static void rtc_convert_datetime_hwrtc_to_tm(struct tm *datetime_tm, const S_RTC_TIME_DATA_T *datetime_hwrtc);
ccli8 12:b0d19e915d96 33 /* Convert date time from struct TM to H/W RTC */
ccli8 12:b0d19e915d96 34 static void rtc_convert_datetime_tm_to_hwrtc(S_RTC_TIME_DATA_T *datetime_hwrtc, const struct tm *datetime_tm);
ccli8 12:b0d19e915d96 35
ccli8 10:d2e2c79389e1 36 #if defined(TARGET_NUMAKER_PFM_NANO130)
ccli8 10:d2e2c79389e1 37 /* This target doesn't support relocating vector table and requires overriding
ccli8 10:d2e2c79389e1 38 * vector handler at link-time. */
ccli8 10:d2e2c79389e1 39 extern "C" void RTC_IRQHandler(void)
ccli8 10:d2e2c79389e1 40 #else
ccli8 1:eb1da9d36e12 41 void RTC_IRQHandler(void)
ccli8 10:d2e2c79389e1 42 #endif
ccli8 1:eb1da9d36e12 43 {
ccli8 1:eb1da9d36e12 44 /* Check if RTC alarm interrupt has occurred */
ccli8 10:d2e2c79389e1 45 #if defined(TARGET_NUMAKER_PFM_NANO130)
ccli8 10:d2e2c79389e1 46 if (RTC->RIIR & RTC_RIIR_AIF_Msk) {
ccli8 10:d2e2c79389e1 47 /* Clear RTC alarm interrupt flag */
ccli8 10:d2e2c79389e1 48 RTC->RIIR = RTC_RIIR_AIF_Msk;
ccli8 10:d2e2c79389e1 49
ccli8 10:d2e2c79389e1 50 wakeup_eventflags.set(EventFlag_Wakeup_RTC_Alarm);
ccli8 10:d2e2c79389e1 51 }
ccli8 10:d2e2c79389e1 52 #elif defined(TARGET_NUMAKER_PFM_NUC472)
ccli8 1:eb1da9d36e12 53 if (RTC->INTSTS & RTC_INTSTS_ALMIF_Msk) {
ccli8 1:eb1da9d36e12 54 /* Clear RTC alarm interrupt flag */
ccli8 1:eb1da9d36e12 55 RTC->INTSTS = RTC_INTSTS_ALMIF_Msk;
ccli8 1:eb1da9d36e12 56
ccli8 1:eb1da9d36e12 57 wakeup_eventflags.set(EventFlag_Wakeup_RTC_Alarm);
ccli8 1:eb1da9d36e12 58 }
ccli8 1:eb1da9d36e12 59 #else
ccli8 1:eb1da9d36e12 60 if (RTC_GET_ALARM_INT_FLAG()) {
ccli8 1:eb1da9d36e12 61 /* Clear RTC alarm interrupt flag */
ccli8 1:eb1da9d36e12 62 RTC_CLEAR_ALARM_INT_FLAG();
ccli8 1:eb1da9d36e12 63
ccli8 1:eb1da9d36e12 64 wakeup_eventflags.set(EventFlag_Wakeup_RTC_Alarm);
ccli8 1:eb1da9d36e12 65 }
ccli8 1:eb1da9d36e12 66 #endif
ccli8 4:da41f0e17d5a 67
ccli8 4:da41f0e17d5a 68 /* Wake up RTC loop to schedule another RTC alarm */
ccli8 4:da41f0e17d5a 69 sem_rtc.release();
ccli8 1:eb1da9d36e12 70 }
ccli8 1:eb1da9d36e12 71
ccli8 1:eb1da9d36e12 72 void config_rtc_wakeup(void)
ccli8 1:eb1da9d36e12 73 {
ccli8 5:fdfb7a10cc59 74 static Thread thread_rtc(osPriorityNormal, 2048);
ccli8 4:da41f0e17d5a 75
ccli8 4:da41f0e17d5a 76 Callback<void()> callback(&rtc_loop);
ccli8 4:da41f0e17d5a 77 thread_rtc.start(callback);
ccli8 1:eb1da9d36e12 78 }
ccli8 1:eb1da9d36e12 79
ccli8 4:da41f0e17d5a 80 void rtc_loop(void)
ccli8 1:eb1da9d36e12 81 {
ccli8 4:da41f0e17d5a 82 /* Schedule RTC alarm in 3 secs */
ccli8 4:da41f0e17d5a 83 schedule_rtc_alarm(3);
ccli8 1:eb1da9d36e12 84
ccli8 4:da41f0e17d5a 85 while (true) {
ccli8 16:ed2c228cbc9c 86 sem_rtc.acquire();
ccli8 16:ed2c228cbc9c 87
ccli8 16:ed2c228cbc9c 88 /* Re-schedule RTC alarm in 3 secs */
ccli8 16:ed2c228cbc9c 89 schedule_rtc_alarm(3);
ccli8 4:da41f0e17d5a 90 }
ccli8 4:da41f0e17d5a 91 }
ccli8 4:da41f0e17d5a 92
ccli8 4:da41f0e17d5a 93 void schedule_rtc_alarm(uint32_t secs)
ccli8 4:da41f0e17d5a 94 {
ccli8 1:eb1da9d36e12 95 /* time() will call set_time(0) internally to set timestamp if rtc is not yet enabled, where the 0 timestamp
ccli8 1:eb1da9d36e12 96 * corresponds to 00:00 hours, Jan 1, 1970 UTC. But Nuvoton mcu's rtc supports calendar since 2000 and 1970
ccli8 1:eb1da9d36e12 97 * is not supported. For this test, a timestamp after 2000 is explicitly set. */
ccli8 1:eb1da9d36e12 98 {
ccli8 1:eb1da9d36e12 99 static bool time_inited = false;
ccli8 1:eb1da9d36e12 100
ccli8 1:eb1da9d36e12 101 if (! time_inited) {
ccli8 1:eb1da9d36e12 102 time_inited = true;
ccli8 1:eb1da9d36e12 103
ccli8 1:eb1da9d36e12 104 #define CUSTOM_TIME 1256729737
ccli8 1:eb1da9d36e12 105 set_time(CUSTOM_TIME); // Set RTC time to Wed, 28 Oct 2009 11:35:37
ccli8 1:eb1da9d36e12 106 }
ccli8 1:eb1da9d36e12 107 }
ccli8 1:eb1da9d36e12 108
ccli8 10:d2e2c79389e1 109 #if defined(TARGET_NUMAKER_PFM_NANO130)
ccli8 10:d2e2c79389e1 110 RTC_DisableInt(RTC_RIER_AIER_Msk);
ccli8 10:d2e2c79389e1 111 #else
ccli8 1:eb1da9d36e12 112 RTC_DisableInt(RTC_INTEN_ALMIEN_Msk);
ccli8 10:d2e2c79389e1 113 #endif
ccli8 1:eb1da9d36e12 114
ccli8 12:b0d19e915d96 115 /* Schedule RTC alarm
ccli8 12:b0d19e915d96 116 *
ccli8 12:b0d19e915d96 117 * Mbed OS RTC API doesn't support RTC alarm function. To enable it, we need to control RTC H/W directly.
ccli8 12:b0d19e915d96 118 * Because RTC H/W doesn't inevitably record real date time, we cannot calculate alarm time based on time()
ccli8 12:b0d19e915d96 119 * timestamp. Instead, we fetch date time recorded in RTC H/W for our calculation of scheduled alarm time.
ccli8 12:b0d19e915d96 120 *
ccli8 12:b0d19e915d96 121 * Control flow would be:
ccli8 12:b0d19e915d96 122 * 1. Fetch RTC H/W date time.
ccli8 12:b0d19e915d96 123 * 2. Convert RTC H/W date time to timestamp: S_RTC_TIME_DATA_T > struct tm > time_t
ccli8 12:b0d19e915d96 124 * 3. Calculate alarm time based on timestamp above
ccli8 12:b0d19e915d96 125 * 4. Convert calculated timestamp back to RTC H/W date time: time_t > struct tm > S_RTC_TIME_DATA_T
ccli8 12:b0d19e915d96 126 * 5. Control RTC H/W to schedule alarm
ccli8 12:b0d19e915d96 127 */
ccli8 12:b0d19e915d96 128 time_t t_alarm;
ccli8 12:b0d19e915d96 129 struct tm datetime_tm_alarm;
ccli8 12:b0d19e915d96 130 S_RTC_TIME_DATA_T datetime_hwrtc_alarm;
ccli8 12:b0d19e915d96 131
ccli8 12:b0d19e915d96 132 /* Fetch RTC H/W date time */
ccli8 12:b0d19e915d96 133 RTC_GetDateAndTime(&datetime_hwrtc_alarm);
ccli8 1:eb1da9d36e12 134
ccli8 12:b0d19e915d96 135 /* Convert date time from H/W RTC to struct TM */
ccli8 12:b0d19e915d96 136 rtc_convert_datetime_hwrtc_to_tm(&datetime_tm_alarm, &datetime_hwrtc_alarm);
ccli8 12:b0d19e915d96 137
ccli8 12:b0d19e915d96 138 /* Convert date time of struct TM to POSIX time */
ccli8 12:b0d19e915d96 139 if (! _rtc_maketime(&datetime_tm_alarm, &t_alarm, RTC_FULL_LEAP_YEAR_SUPPORT)) {
ccli8 12:b0d19e915d96 140 printf("%s: _rtc_maketime failed\n", __func__);
ccli8 1:eb1da9d36e12 141 return;
ccli8 1:eb1da9d36e12 142 }
ccli8 1:eb1da9d36e12 143
ccli8 12:b0d19e915d96 144 /* Calculate RTC alarm time */
ccli8 12:b0d19e915d96 145 t_alarm += secs;
ccli8 12:b0d19e915d96 146
ccli8 12:b0d19e915d96 147 /* Convert POSIX time to date time of struct TM */
ccli8 12:b0d19e915d96 148 if (! _rtc_localtime(t_alarm, &datetime_tm_alarm, RTC_FULL_LEAP_YEAR_SUPPORT)) {
ccli8 12:b0d19e915d96 149 printf("%s: _rtc_localtime failed\n", __func__);
ccli8 12:b0d19e915d96 150 return;
ccli8 12:b0d19e915d96 151 }
ccli8 12:b0d19e915d96 152
ccli8 12:b0d19e915d96 153 /* Convert date time from struct TM to H/W RTC */
ccli8 12:b0d19e915d96 154 rtc_convert_datetime_tm_to_hwrtc(&datetime_hwrtc_alarm, &datetime_tm_alarm);
ccli8 1:eb1da9d36e12 155
ccli8 12:b0d19e915d96 156 /* Control RTC H/W to schedule alarm */
ccli8 12:b0d19e915d96 157 RTC_SetAlarmDateAndTime(&datetime_hwrtc_alarm);
ccli8 12:b0d19e915d96 158 /* NOTE: When engine is clocked by low power clock source (LXT/LIRC), we need to wait for 3 engine clocks. */
ccli8 12:b0d19e915d96 159 wait_us((NU_US_PER_SEC / NU_RTCCLK_PER_SEC) * 3);
ccli8 1:eb1da9d36e12 160
ccli8 1:eb1da9d36e12 161 /* NOTE: The Mbed RTC HAL implementation of Nuvoton's targets doesn't use interrupt, so we can override vector
ccli8 1:eb1da9d36e12 162 handler (via NVIC_SetVector). */
ccli8 1:eb1da9d36e12 163 /* NOTE: The name of symbol PWRWU_IRQHandler is mangled in C++ and cannot override that in startup file in C.
ccli8 1:eb1da9d36e12 164 * So the NVIC_SetVector call cannot be left out. */
ccli8 1:eb1da9d36e12 165 NVIC_SetVector(RTC_IRQn, (uint32_t) RTC_IRQHandler);
ccli8 1:eb1da9d36e12 166 NVIC_EnableIRQ(RTC_IRQn);
ccli8 1:eb1da9d36e12 167 /* Enable RTC alarm interrupt and wake-up function will be enabled also */
ccli8 10:d2e2c79389e1 168 #if defined(TARGET_NUMAKER_PFM_NANO130)
ccli8 10:d2e2c79389e1 169 RTC_EnableInt(RTC_RIER_AIER_Msk);
ccli8 10:d2e2c79389e1 170 #else
ccli8 1:eb1da9d36e12 171 RTC_EnableInt(RTC_INTEN_ALMIEN_Msk);
ccli8 10:d2e2c79389e1 172 #endif
ccli8 1:eb1da9d36e12 173 }
ccli8 12:b0d19e915d96 174
ccli8 12:b0d19e915d96 175 /*
ccli8 12:b0d19e915d96 176 struct tm
ccli8 12:b0d19e915d96 177 tm_sec seconds after the minute 0-61
ccli8 12:b0d19e915d96 178 tm_min minutes after the hour 0-59
ccli8 12:b0d19e915d96 179 tm_hour hours since midnight 0-23
ccli8 12:b0d19e915d96 180 tm_mday day of the month 1-31
ccli8 12:b0d19e915d96 181 tm_mon months since January 0-11
ccli8 12:b0d19e915d96 182 tm_year years since 1900
ccli8 12:b0d19e915d96 183 tm_wday days since Sunday 0-6
ccli8 12:b0d19e915d96 184 tm_yday days since January 1 0-365
ccli8 12:b0d19e915d96 185 tm_isdst Daylight Saving Time flag
ccli8 12:b0d19e915d96 186 */
ccli8 12:b0d19e915d96 187 static void rtc_convert_datetime_hwrtc_to_tm(struct tm *datetime_tm, const S_RTC_TIME_DATA_T *datetime_hwrtc)
ccli8 12:b0d19e915d96 188 {
ccli8 12:b0d19e915d96 189 datetime_tm->tm_year = datetime_hwrtc->u32Year - NU_TM_YEAR0;
ccli8 12:b0d19e915d96 190 datetime_tm->tm_mon = datetime_hwrtc->u32Month - 1;
ccli8 12:b0d19e915d96 191 datetime_tm->tm_mday = datetime_hwrtc->u32Day;
ccli8 12:b0d19e915d96 192 datetime_tm->tm_wday = datetime_hwrtc->u32DayOfWeek;
ccli8 12:b0d19e915d96 193 datetime_tm->tm_hour = datetime_hwrtc->u32Hour;
ccli8 12:b0d19e915d96 194 if (datetime_hwrtc->u32TimeScale == RTC_CLOCK_12 && datetime_hwrtc->u32AmPm == RTC_PM) {
ccli8 12:b0d19e915d96 195 datetime_tm->tm_hour += 12;
ccli8 12:b0d19e915d96 196 }
ccli8 12:b0d19e915d96 197 datetime_tm->tm_min = datetime_hwrtc->u32Minute;
ccli8 12:b0d19e915d96 198 datetime_tm->tm_sec = datetime_hwrtc->u32Second;
ccli8 12:b0d19e915d96 199 }
ccli8 12:b0d19e915d96 200
ccli8 12:b0d19e915d96 201 static void rtc_convert_datetime_tm_to_hwrtc(S_RTC_TIME_DATA_T *datetime_hwrtc, const struct tm *datetime_tm)
ccli8 12:b0d19e915d96 202 {
ccli8 12:b0d19e915d96 203 datetime_hwrtc->u32Year = datetime_tm->tm_year + NU_TM_YEAR0;
ccli8 12:b0d19e915d96 204 datetime_hwrtc->u32Month = datetime_tm->tm_mon + 1;
ccli8 12:b0d19e915d96 205 datetime_hwrtc->u32Day = datetime_tm->tm_mday;
ccli8 12:b0d19e915d96 206 datetime_hwrtc->u32DayOfWeek = datetime_tm->tm_wday;
ccli8 12:b0d19e915d96 207 datetime_hwrtc->u32Hour = datetime_tm->tm_hour;
ccli8 12:b0d19e915d96 208 datetime_hwrtc->u32TimeScale = RTC_CLOCK_24;
ccli8 12:b0d19e915d96 209 datetime_hwrtc->u32Minute = datetime_tm->tm_min;
ccli8 12:b0d19e915d96 210 datetime_hwrtc->u32Second = datetime_tm->tm_sec;
ccli8 12:b0d19e915d96 211 }