Nuvoton
/
NuMaker-mbed-tickless-example
NuMaker tickless example
wakeup_rtc.cpp@10:d2e2c79389e1, 2017-10-02 (annotated)
- Committer:
- ccli8
- Date:
- Mon Oct 02 11:24:10 2017 +0800
- Revision:
- 10:d2e2c79389e1
- Parent:
- 5:fdfb7a10cc59
- Child:
- 11:0c4b39c54af2
Support NANO130
Who changed what in which revision?
User | Revision | Line number | New 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 |
1:eb1da9d36e12 | 6 | #define YEAR0 1900 |
ccli8 |
1:eb1da9d36e12 | 7 | |
ccli8 |
4:da41f0e17d5a | 8 | static Semaphore sem_rtc(0, 1); |
ccli8 |
4:da41f0e17d5a | 9 | |
ccli8 |
4:da41f0e17d5a | 10 | static void rtc_loop(void); |
ccli8 |
4:da41f0e17d5a | 11 | static void schedule_rtc_alarm(uint32_t secs); |
ccli8 |
1:eb1da9d36e12 | 12 | |
ccli8 |
10:d2e2c79389e1 | 13 | #if defined(TARGET_NUMAKER_PFM_NANO130) |
ccli8 |
10:d2e2c79389e1 | 14 | /* This target doesn't support relocating vector table and requires overriding |
ccli8 |
10:d2e2c79389e1 | 15 | * vector handler at link-time. */ |
ccli8 |
10:d2e2c79389e1 | 16 | extern "C" void RTC_IRQHandler(void) |
ccli8 |
10:d2e2c79389e1 | 17 | #else |
ccli8 |
1:eb1da9d36e12 | 18 | void RTC_IRQHandler(void) |
ccli8 |
10:d2e2c79389e1 | 19 | #endif |
ccli8 |
1:eb1da9d36e12 | 20 | { |
ccli8 |
1:eb1da9d36e12 | 21 | /* Check if RTC alarm interrupt has occurred */ |
ccli8 |
10:d2e2c79389e1 | 22 | #if defined(TARGET_NUMAKER_PFM_NANO130) |
ccli8 |
10:d2e2c79389e1 | 23 | if (RTC->RIIR & RTC_RIIR_AIF_Msk) { |
ccli8 |
10:d2e2c79389e1 | 24 | /* Clear RTC alarm interrupt flag */ |
ccli8 |
10:d2e2c79389e1 | 25 | RTC->RIIR = RTC_RIIR_AIF_Msk; |
ccli8 |
10:d2e2c79389e1 | 26 | |
ccli8 |
10:d2e2c79389e1 | 27 | wakeup_eventflags.set(EventFlag_Wakeup_RTC_Alarm); |
ccli8 |
10:d2e2c79389e1 | 28 | } |
ccli8 |
10:d2e2c79389e1 | 29 | #elif defined(TARGET_NUMAKER_PFM_NUC472) |
ccli8 |
1:eb1da9d36e12 | 30 | if (RTC->INTSTS & RTC_INTSTS_ALMIF_Msk) { |
ccli8 |
1:eb1da9d36e12 | 31 | /* Clear RTC alarm interrupt flag */ |
ccli8 |
1:eb1da9d36e12 | 32 | RTC->INTSTS = RTC_INTSTS_ALMIF_Msk; |
ccli8 |
1:eb1da9d36e12 | 33 | |
ccli8 |
1:eb1da9d36e12 | 34 | wakeup_eventflags.set(EventFlag_Wakeup_RTC_Alarm); |
ccli8 |
1:eb1da9d36e12 | 35 | } |
ccli8 |
1:eb1da9d36e12 | 36 | #else |
ccli8 |
1:eb1da9d36e12 | 37 | if (RTC_GET_ALARM_INT_FLAG()) { |
ccli8 |
1:eb1da9d36e12 | 38 | /* Clear RTC alarm interrupt flag */ |
ccli8 |
1:eb1da9d36e12 | 39 | RTC_CLEAR_ALARM_INT_FLAG(); |
ccli8 |
1:eb1da9d36e12 | 40 | |
ccli8 |
1:eb1da9d36e12 | 41 | wakeup_eventflags.set(EventFlag_Wakeup_RTC_Alarm); |
ccli8 |
1:eb1da9d36e12 | 42 | } |
ccli8 |
1:eb1da9d36e12 | 43 | #endif |
ccli8 |
4:da41f0e17d5a | 44 | |
ccli8 |
4:da41f0e17d5a | 45 | /* Wake up RTC loop to schedule another RTC alarm */ |
ccli8 |
4:da41f0e17d5a | 46 | sem_rtc.release(); |
ccli8 |
1:eb1da9d36e12 | 47 | } |
ccli8 |
1:eb1da9d36e12 | 48 | |
ccli8 |
1:eb1da9d36e12 | 49 | void config_rtc_wakeup(void) |
ccli8 |
1:eb1da9d36e12 | 50 | { |
ccli8 |
5:fdfb7a10cc59 | 51 | static Thread thread_rtc(osPriorityNormal, 2048); |
ccli8 |
4:da41f0e17d5a | 52 | |
ccli8 |
4:da41f0e17d5a | 53 | Callback<void()> callback(&rtc_loop); |
ccli8 |
4:da41f0e17d5a | 54 | thread_rtc.start(callback); |
ccli8 |
1:eb1da9d36e12 | 55 | } |
ccli8 |
1:eb1da9d36e12 | 56 | |
ccli8 |
4:da41f0e17d5a | 57 | void rtc_loop(void) |
ccli8 |
1:eb1da9d36e12 | 58 | { |
ccli8 |
4:da41f0e17d5a | 59 | /* Schedule RTC alarm in 3 secs */ |
ccli8 |
4:da41f0e17d5a | 60 | schedule_rtc_alarm(3); |
ccli8 |
1:eb1da9d36e12 | 61 | |
ccli8 |
4:da41f0e17d5a | 62 | while (true) { |
ccli8 |
4:da41f0e17d5a | 63 | int32_t sem_tokens = sem_rtc.wait(osWaitForever); |
ccli8 |
4:da41f0e17d5a | 64 | if (sem_tokens < 1) { |
ccli8 |
4:da41f0e17d5a | 65 | printf("RTC Alarm fails with Semaphore.wait(): %d\n", sem_tokens); |
ccli8 |
4:da41f0e17d5a | 66 | } |
ccli8 |
4:da41f0e17d5a | 67 | else { |
ccli8 |
4:da41f0e17d5a | 68 | /* Re-schedule RTC alarm in 3 secs */ |
ccli8 |
4:da41f0e17d5a | 69 | schedule_rtc_alarm(3); |
ccli8 |
4:da41f0e17d5a | 70 | } |
ccli8 |
4:da41f0e17d5a | 71 | } |
ccli8 |
4:da41f0e17d5a | 72 | } |
ccli8 |
4:da41f0e17d5a | 73 | |
ccli8 |
4:da41f0e17d5a | 74 | void schedule_rtc_alarm(uint32_t secs) |
ccli8 |
4:da41f0e17d5a | 75 | { |
ccli8 |
1:eb1da9d36e12 | 76 | /* time() will call set_time(0) internally to set timestamp if rtc is not yet enabled, where the 0 timestamp |
ccli8 |
1:eb1da9d36e12 | 77 | * corresponds to 00:00 hours, Jan 1, 1970 UTC. But Nuvoton mcu's rtc supports calendar since 2000 and 1970 |
ccli8 |
1:eb1da9d36e12 | 78 | * is not supported. For this test, a timestamp after 2000 is explicitly set. */ |
ccli8 |
1:eb1da9d36e12 | 79 | { |
ccli8 |
1:eb1da9d36e12 | 80 | static bool time_inited = false; |
ccli8 |
1:eb1da9d36e12 | 81 | |
ccli8 |
1:eb1da9d36e12 | 82 | if (! time_inited) { |
ccli8 |
1:eb1da9d36e12 | 83 | time_inited = true; |
ccli8 |
1:eb1da9d36e12 | 84 | |
ccli8 |
1:eb1da9d36e12 | 85 | #define CUSTOM_TIME 1256729737 |
ccli8 |
1:eb1da9d36e12 | 86 | set_time(CUSTOM_TIME); // Set RTC time to Wed, 28 Oct 2009 11:35:37 |
ccli8 |
1:eb1da9d36e12 | 87 | } |
ccli8 |
1:eb1da9d36e12 | 88 | } |
ccli8 |
1:eb1da9d36e12 | 89 | |
ccli8 |
10:d2e2c79389e1 | 90 | #if defined(TARGET_NUMAKER_PFM_NANO130) |
ccli8 |
10:d2e2c79389e1 | 91 | RTC_DisableInt(RTC_RIER_AIER_Msk); |
ccli8 |
10:d2e2c79389e1 | 92 | #else |
ccli8 |
1:eb1da9d36e12 | 93 | RTC_DisableInt(RTC_INTEN_ALMIEN_Msk); |
ccli8 |
10:d2e2c79389e1 | 94 | #endif |
ccli8 |
1:eb1da9d36e12 | 95 | |
ccli8 |
1:eb1da9d36e12 | 96 | time_t t = time(NULL); |
ccli8 |
1:eb1da9d36e12 | 97 | t += secs; // Schedule RTC alarm after secs |
ccli8 |
1:eb1da9d36e12 | 98 | |
ccli8 |
1:eb1da9d36e12 | 99 | // Convert timestamp to struct tm |
ccli8 |
1:eb1da9d36e12 | 100 | struct tm timeinfo; |
ccli8 |
1:eb1da9d36e12 | 101 | if (_rtc_localtime(t, &timeinfo) == false) { |
ccli8 |
1:eb1da9d36e12 | 102 | printf("config_rtc_alarm() fails\n"); |
ccli8 |
1:eb1da9d36e12 | 103 | return; |
ccli8 |
1:eb1da9d36e12 | 104 | } |
ccli8 |
1:eb1da9d36e12 | 105 | |
ccli8 |
1:eb1da9d36e12 | 106 | S_RTC_TIME_DATA_T rtc_datetime; |
ccli8 |
1:eb1da9d36e12 | 107 | |
ccli8 |
1:eb1da9d36e12 | 108 | // Convert struct tm to S_RTC_TIME_DATA_T |
ccli8 |
1:eb1da9d36e12 | 109 | rtc_datetime.u32Year = timeinfo.tm_year + YEAR0; |
ccli8 |
1:eb1da9d36e12 | 110 | rtc_datetime.u32Month = timeinfo.tm_mon + 1; |
ccli8 |
1:eb1da9d36e12 | 111 | rtc_datetime.u32Day = timeinfo.tm_mday; |
ccli8 |
1:eb1da9d36e12 | 112 | rtc_datetime.u32DayOfWeek = timeinfo.tm_wday; |
ccli8 |
1:eb1da9d36e12 | 113 | rtc_datetime.u32Hour = timeinfo.tm_hour; |
ccli8 |
1:eb1da9d36e12 | 114 | rtc_datetime.u32Minute = timeinfo.tm_min; |
ccli8 |
1:eb1da9d36e12 | 115 | rtc_datetime.u32Second = timeinfo.tm_sec; |
ccli8 |
1:eb1da9d36e12 | 116 | rtc_datetime.u32TimeScale = RTC_CLOCK_24; |
ccli8 |
1:eb1da9d36e12 | 117 | |
ccli8 |
1:eb1da9d36e12 | 118 | RTC_SetAlarmDateAndTime(&rtc_datetime); |
ccli8 |
1:eb1da9d36e12 | 119 | |
ccli8 |
1:eb1da9d36e12 | 120 | /* NOTE: The Mbed RTC HAL implementation of Nuvoton's targets doesn't use interrupt, so we can override vector |
ccli8 |
1:eb1da9d36e12 | 121 | handler (via NVIC_SetVector). */ |
ccli8 |
1:eb1da9d36e12 | 122 | /* NOTE: The name of symbol PWRWU_IRQHandler is mangled in C++ and cannot override that in startup file in C. |
ccli8 |
1:eb1da9d36e12 | 123 | * So the NVIC_SetVector call cannot be left out. */ |
ccli8 |
1:eb1da9d36e12 | 124 | NVIC_SetVector(RTC_IRQn, (uint32_t) RTC_IRQHandler); |
ccli8 |
1:eb1da9d36e12 | 125 | NVIC_EnableIRQ(RTC_IRQn); |
ccli8 |
1:eb1da9d36e12 | 126 | /* Enable RTC alarm interrupt and wake-up function will be enabled also */ |
ccli8 |
10:d2e2c79389e1 | 127 | #if defined(TARGET_NUMAKER_PFM_NANO130) |
ccli8 |
10:d2e2c79389e1 | 128 | RTC_EnableInt(RTC_RIER_AIER_Msk); |
ccli8 |
10:d2e2c79389e1 | 129 | #else |
ccli8 |
1:eb1da9d36e12 | 130 | RTC_EnableInt(RTC_INTEN_ALMIEN_Msk); |
ccli8 |
10:d2e2c79389e1 | 131 | #endif |
ccli8 |
1:eb1da9d36e12 | 132 | } |