| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839 |
- /* Copyright 2018 Canaan Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include <stdint.h>
- #include <stdlib.h>
- #include <time.h>
- #include "encoding.h"
- #include "printf.h"
- #include "rtc.h"
- #include "sysctl.h"
- volatile rtc_t *const rtc = (volatile rtc_t *)RTC_BASE_ADDR;
- struct tm rtc_timer_date_time;
- struct tm rtc_alarm_date_time;
- typedef struct _rtc_instance_t
- {
- plic_irq_callback_t rtc_tick_callback;
- void *tick_ctx;
- plic_irq_callback_t rtc_alarm_callback;
- void *alarm_ctx;
- bool tick_is_single_shot;
- bool alarm_is_single_shot;
- bool tick_enable_by_alarm;
- bool tick_enable_by_user;
- rtc_tick_interrupt_mode_t tick_mode_by_user;
- rtc_tick_interrupt_mode_t tick_mode_by_alarm;
- } rtc_instance_t;
- rtc_instance_t rtc_instance = (rtc_instance_t){
- .tick_mode_by_user = -1,
- .tick_mode_by_alarm = RTC_INT_MAX,
- };
- int rtc_timer_set_mode(rtc_timer_mode_t timer_mode)
- {
- rtc_register_ctrl_t register_ctrl = rtc->register_ctrl;
- switch(timer_mode)
- {
- case RTC_TIMER_PAUSE:
- register_ctrl.read_enable = 0;
- register_ctrl.write_enable = 0;
- break;
- case RTC_TIMER_RUNNING:
- register_ctrl.read_enable = 1;
- register_ctrl.write_enable = 0;
- break;
- case RTC_TIMER_SETTING:
- register_ctrl.read_enable = 0;
- register_ctrl.write_enable = 1;
- break;
- default:
- register_ctrl.read_enable = 0;
- register_ctrl.write_enable = 0;
- break;
- }
- /* Get CPU current freq */
- unsigned long freq = sysctl_clock_get_freq(SYSCTL_CLOCK_CPU);
- /* Set threshold to 1/26000000 s */
- freq = freq / 26000000;
- /* Get current CPU cycle */
- unsigned long start_cycle = read_csr(mcycle);
- /* Wait for 1/26000000 s to sync data */
- while(read_csr(mcycle) - start_cycle < freq)
- continue;
- rtc->register_ctrl = register_ctrl;
- return 0;
- }
- rtc_timer_mode_t rtc_timer_get_mode(void)
- {
- rtc_register_ctrl_t register_ctrl = rtc->register_ctrl;
- rtc_timer_mode_t timer_mode = RTC_TIMER_PAUSE;
- if((!register_ctrl.read_enable) && (!register_ctrl.write_enable))
- {
- /* RTC_TIMER_PAUSE */
- timer_mode = RTC_TIMER_PAUSE;
- } else if((register_ctrl.read_enable) && (!register_ctrl.write_enable))
- {
- /* RTC_TIMER_RUNNING */
- timer_mode = RTC_TIMER_RUNNING;
- } else if((!register_ctrl.read_enable) && (register_ctrl.write_enable))
- {
- /* RTC_TIMER_SETTING */
- timer_mode = RTC_TIMER_RUNNING;
- } else
- {
- /* Something is error, reset timer mode */
- rtc_timer_set_mode(timer_mode);
- }
- return timer_mode;
- }
- static inline int rtc_in_range(int value, int min, int max)
- {
- return ((value >= min) && (value <= max));
- }
- int rtc_timer_set_tm(const struct tm *tm)
- {
- rtc_date_t timer_date;
- rtc_time_t timer_time;
- rtc_extended_t timer_extended;
- if(tm)
- {
- /*
- * Range of tm->tm_sec could be [0,61]
- *
- * Range of tm->tm_sec allows for a positive leap second. Two
- * leap seconds in the same minute are not allowed (the C90
- * range 0..61 was a defect)
- */
- if(rtc_in_range(tm->tm_sec, 0, 59))
- timer_time.second = tm->tm_sec;
- else
- return -1;
- /* Range of tm->tm_min could be [0,59] */
- if(rtc_in_range(tm->tm_min, 0, 59))
- timer_time.minute = tm->tm_min;
- else
- return -1;
- /* Range of tm->tm_hour could be [0, 23] */
- if(rtc_in_range(tm->tm_hour, 0, 23))
- timer_time.hour = tm->tm_hour;
- else
- return -1;
- /* Range of tm->tm_mday could be [1, 31] */
- if(rtc_in_range(tm->tm_mday, 1, 31))
- timer_date.day = tm->tm_mday;
- else
- return -1;
- /*
- * Range of tm->tm_mon could be [0, 11]
- * But in this RTC, date.month should be [1, 12]
- */
- if(rtc_in_range(tm->tm_mon, 0, 11))
- timer_date.month = tm->tm_mon + 1;
- else
- return -1;
- /*
- * Range of tm->tm_year is the years since 1900
- * But in this RTC, year is split into year and century
- * In this RTC, century range is [0,31], year range is [0,99]
- */
- int human_year = tm->tm_year + 1900;
- int rtc_year = human_year % 100;
- int rtc_century = human_year / 100;
- if(rtc_in_range(rtc_year, 0, 99) &&
- rtc_in_range(rtc_century, 0, 31))
- {
- timer_date.year = rtc_year;
- timer_extended.century = rtc_century;
- } else
- return -1;
- /* Range of tm->tm_wday could be [0, 6] */
- if(rtc_in_range(tm->tm_wday, 0, 6))
- timer_date.week = tm->tm_wday;
- else
- return -1;
- /* Set RTC mode to timer setting mode */
- rtc_timer_set_mode(RTC_TIMER_SETTING);
- /* Write value to RTC */
- rtc->date = timer_date;
- rtc->time = timer_time;
- rtc->extended = timer_extended;
- /* Set RTC mode to timer running mode */
- rtc_timer_set_mode(RTC_TIMER_RUNNING);
- }
- return 0;
- }
- int rtc_alarm_set_tm(const struct tm *tm)
- {
- rtc_alarm_date_t alarm_date;
- rtc_alarm_time_t alarm_time;
- if(tm)
- {
- /*
- * Range of tm->tm_sec could be [0,61]
- *
- * Range of tm->tm_sec allows for a positive leap second. Two
- * leap seconds in the same minute are not allowed (the C90
- * range 0..61 was a defect)
- */
- if(rtc_in_range(tm->tm_sec, 0, 59))
- alarm_time.second = tm->tm_sec;
- else
- return -1;
- /* Range of tm->tm_min could be [0,59] */
- if(rtc_in_range(tm->tm_min, 0, 59))
- alarm_time.minute = tm->tm_min;
- else
- return -1;
- /* Range of tm->tm_hour could be [0, 23] */
- if(rtc_in_range(tm->tm_hour, 0, 23))
- alarm_time.hour = tm->tm_hour;
- else
- return -1;
- /* Range of tm->tm_mday could be [1, 31] */
- if(rtc_in_range(tm->tm_mday, 1, 31))
- alarm_date.day = tm->tm_mday;
- else
- return -1;
- /*
- * Range of tm->tm_mon could be [0, 11]
- * But in this RTC, date.month should be [1, 12]
- */
- if(rtc_in_range(tm->tm_mon, 0, 11))
- alarm_date.month = tm->tm_mon + 1;
- else
- return -1;
- /*
- * Range of tm->tm_year is the years since 1900
- * But in this RTC, year is split into year and century
- * In this RTC, century range is [0,31], year range is [0,99]
- */
- int human_year = tm->tm_year + 1900;
- int rtc_year = human_year % 100;
- int rtc_century = human_year / 100;
- if(rtc_in_range(rtc_year, 0, 99) &&
- rtc_in_range(rtc_century, 0, 31))
- {
- alarm_date.year = rtc_year;
- } else
- return -1;
- /* Range of tm->tm_wday could be [0, 6] */
- if(rtc_in_range(tm->tm_wday, 0, 6))
- alarm_date.week = tm->tm_wday;
- else
- return -1;
- /* Set RTC mode to timer setting mode */
- rtc_timer_set_mode(RTC_TIMER_SETTING);
- /* Write value to RTC */
- rtc->alarm_date = alarm_date;
- rtc->alarm_time = alarm_time;
- /* Set RTC mode to timer running mode */
- rtc_timer_set_mode(RTC_TIMER_RUNNING);
- }
- return 0;
- }
- int rtc_year_is_leap(int year)
- {
- return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
- }
- int rtc_get_yday(int year, int month, int day)
- {
- static const int days[2][13] = {
- {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
- {0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}};
- int leap = rtc_year_is_leap(year);
- return days[leap][month] + day;
- }
- int rtc_get_wday(int year, int month, int day)
- {
- /* Magic method to get weekday */
- int weekday = (day += month < 3 ? year-- : year - 2, 23 * month / 9 + day + 4 + year / 4 - year / 100 + year / 400) % 7;
- return weekday;
- }
- struct tm *rtc_timer_get_tm(void)
- {
- if(rtc_timer_get_mode() != RTC_TIMER_RUNNING)
- return NULL;
- rtc_date_t timer_date = rtc->date;
- rtc_time_t timer_time = rtc->time;
- rtc_extended_t timer_extended = rtc->extended;
- struct tm *tm = &rtc_timer_date_time;
- tm->tm_sec = timer_time.second % 61; /* 0-60, follow C99 */
- tm->tm_min = timer_time.minute % 60; /* 0-59 */
- tm->tm_hour = timer_time.hour % 24; /* 0-23 */
- tm->tm_mday = timer_date.day % 32; /* 1-31 */
- tm->tm_mon = (timer_date.month - 1) % 12; /* 0-11 */
- tm->tm_year = (timer_date.year % 100) + (timer_extended.century * 100) - 1900;
- tm->tm_wday = timer_date.week % 7; /* 0-6 */
- tm->tm_yday = rtc_get_yday(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday) % 366; /* 0-365 */
- tm->tm_isdst = -1;
- return tm;
- }
- struct tm *rtc_alarm_get_tm(void)
- {
- if(rtc_timer_get_mode() != RTC_TIMER_RUNNING)
- return NULL;
- rtc_alarm_date_t alarm_date = rtc->alarm_date;
- rtc_alarm_time_t alarm_time = rtc->alarm_time;
- rtc_extended_t timer_extended = rtc->extended;
- struct tm *tm = &rtc_alarm_date_time;
- tm->tm_sec = alarm_time.second % 61; /* 0-60, follow C99 */
- tm->tm_min = alarm_time.minute % 60; /* 0-59 */
- tm->tm_hour = alarm_time.hour % 24; /* 0-23 */
- tm->tm_mday = alarm_date.day % 32; /* 1-31 */
- tm->tm_mon = (alarm_date.month - 1) % 12; /* 0-11 */
- tm->tm_year = (alarm_date.year % 100) + (timer_extended.century * 100) - 1900;
- tm->tm_wday = alarm_date.week % 7; /* 0-6 */
- tm->tm_yday = rtc_get_yday(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday) % 366; /* 0-365 */
- tm->tm_isdst = -1;
- return tm;
- }
- int rtc_timer_set(int year, int month, int day, int hour, int minute, int second)
- {
- struct tm date_time = {
- .tm_sec = second,
- .tm_min = minute,
- .tm_hour = hour,
- .tm_mday = day,
- .tm_mon = month - 1,
- .tm_year = year - 1900,
- .tm_wday = rtc_get_wday(year, month, day),
- .tm_yday = rtc_get_yday(year, month, day),
- .tm_isdst = -1,
- };
- return rtc_timer_set_tm(&date_time);
- }
- int rtc_timer_get(int *year, int *month, int *day, int *hour, int *minute, int *second)
- {
- struct tm *tm = rtc_timer_get_tm();
- if(tm)
- {
- if(year)
- *year = tm->tm_year + 1900;
- if(month)
- *month = tm->tm_mon + 1;
- if(day)
- *day = tm->tm_mday;
- if(hour)
- *hour = tm->tm_hour;
- if(minute)
- *minute = tm->tm_min;
- if(second)
- *second = tm->tm_sec;
- } else
- return -1;
- return 0;
- }
- int rtc_alarm_set(int year, int month, int day, int hour, int minute, int second)
- {
- struct tm date_time = {
- .tm_sec = second,
- .tm_min = minute,
- .tm_hour = hour,
- .tm_mday = day,
- .tm_mon = month - 1,
- .tm_year = year - 1900,
- .tm_wday = rtc_get_wday(year, month, day),
- .tm_yday = rtc_get_yday(year, month, day),
- .tm_isdst = -1,
- };
- return rtc_alarm_set_tm(&date_time);
- }
- int rtc_alarm_get(int *year, int *month, int *day, int *hour, int *minute, int *second)
- {
- struct tm *tm = rtc_alarm_get_tm();
- if(tm)
- {
- if(year)
- *year = tm->tm_year + 1900;
- if(month)
- *month = tm->tm_mon + 1;
- if(day)
- *day = tm->tm_mday;
- if(hour)
- *hour = tm->tm_hour;
- if(minute)
- *minute = tm->tm_min;
- if(second)
- *second = tm->tm_sec;
- } else
- return -1;
- return 0;
- }
- int rtc_timer_set_clock_frequency(unsigned int frequency)
- {
- rtc_initial_count_t initial_count;
- initial_count.count = frequency;
- /* Set RTC mode to timer setting mode */
- rtc_timer_set_mode(RTC_TIMER_SETTING);
- rtc->initial_count = initial_count;
- /* Set RTC mode to timer running mode */
- rtc_timer_set_mode(RTC_TIMER_RUNNING);
- return 0;
- }
- unsigned int rtc_timer_get_clock_frequency(void)
- {
- return rtc->initial_count.count;
- }
- int rtc_timer_set_clock_count_value(unsigned int count)
- {
- rtc_current_count_t current_count;
- current_count.count = count;
- /* Set RTC mode to timer setting mode */
- rtc_timer_set_mode(RTC_TIMER_SETTING);
- rtc->current_count = current_count;
- /* Set RTC mode to timer running mode */
- rtc_timer_set_mode(RTC_TIMER_RUNNING);
- return 0;
- }
- unsigned int rtc_timer_get_clock_count_value(void)
- {
- return rtc->current_count.count;
- }
- int rtc_tick_set_interrupt(int enable)
- {
- rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
- interrupt_ctrl.tick_enable = enable;
- /* Set RTC mode to timer setting mode */
- rtc_timer_set_mode(RTC_TIMER_SETTING);
- rtc->interrupt_ctrl = interrupt_ctrl;
- rtc_timer_set_mode(RTC_TIMER_RUNNING);
- return 0;
- }
- int rtc_tick_get_interrupt(void)
- {
- rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
- return interrupt_ctrl.tick_enable;
- }
- int rtc_tick_set_interrupt_mode(rtc_tick_interrupt_mode_t mode)
- {
- rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
- interrupt_ctrl.tick_int_mode = mode;
- /* Set RTC mode to timer setting mode */
- rtc_timer_set_mode(RTC_TIMER_SETTING);
- rtc->interrupt_ctrl = interrupt_ctrl;
- /* Set RTC mode to timer running mode */
- rtc_timer_set_mode(RTC_TIMER_RUNNING);
- return 0;
- }
- rtc_tick_interrupt_mode_t rtc_tick_get_interrupt_mode(void)
- {
- rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
- return interrupt_ctrl.tick_int_mode;
- }
- int rtc_alarm_set_interrupt(int enable)
- {
- rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
- interrupt_ctrl.alarm_enable = enable;
- /* Set RTC mode to timer setting mode */
- rtc_timer_set_mode(RTC_TIMER_SETTING);
- rtc->interrupt_ctrl = interrupt_ctrl;
- /* Set RTC mode to timer running mode */
- rtc_timer_set_mode(RTC_TIMER_RUNNING);
- return 0;
- }
- int rtc_alarm_get_interrupt(void)
- {
- rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
- return interrupt_ctrl.alarm_enable;
- }
- int rtc_alarm_set_mask(rtc_mask_t mask)
- {
- rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
- interrupt_ctrl.alarm_compare_mask = *(uint8_t *)&mask;
- /* Set RTC mode to timer setting mode */
- rtc_timer_set_mode(RTC_TIMER_SETTING);
- rtc->interrupt_ctrl = interrupt_ctrl;
- /* Set RTC mode to timer running mode */
- rtc_timer_set_mode(RTC_TIMER_RUNNING);
- return 0;
- }
- rtc_mask_t rtc_alarm_get_mask(void)
- {
- rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
- uint8_t compare_mask = interrupt_ctrl.alarm_compare_mask;
- return *(rtc_mask_t *)&compare_mask;
- }
- int rtc_protect_set(int enable)
- {
- rtc_register_ctrl_t register_ctrl = rtc->register_ctrl;
- rtc_mask_t mask = {
- .second = 1, /* Second mask */
- .minute = 1, /* Minute mask */
- .hour = 1, /* Hour mask */
- .week = 1, /* Week mask */
- .day = 1, /* Day mask */
- .month = 1, /* Month mask */
- .year = 1, /* Year mask */
- };
- rtc_mask_t unmask = {
- .second = 0, /* Second mask */
- .minute = 0, /* Minute mask */
- .hour = 0, /* Hour mask */
- .week = 0, /* Week mask */
- .day = 0, /* Day mask */
- .month = 0, /* Month mask */
- .year = 0, /* Year mask */
- };
- if(enable)
- {
- /* Turn RTC in protect mode, no one can write time */
- register_ctrl.timer_mask = *(uint8_t *)&unmask;
- register_ctrl.alarm_mask = *(uint8_t *)&unmask;
- register_ctrl.initial_count_mask = 0;
- register_ctrl.interrupt_register_mask = 0;
- } else
- {
- /* Turn RTC in unprotect mode, everyone can write time */
- register_ctrl.timer_mask = *(uint8_t *)&mask;
- register_ctrl.alarm_mask = *(uint8_t *)&mask;
- register_ctrl.initial_count_mask = 1;
- register_ctrl.interrupt_register_mask = 1;
- }
- rtc->register_ctrl = register_ctrl;
- return 0;
- }
- int rtc_init(void)
- {
- /* Reset RTC */
- sysctl_reset(SYSCTL_RESET_RTC);
- /* Enable RTC */
- sysctl_clock_enable(SYSCTL_CLOCK_RTC);
- /* Unprotect RTC */
- rtc_protect_set(0);
- /* Set RTC clock frequency */
- rtc_timer_set_clock_frequency(
- sysctl_clock_get_freq(SYSCTL_CLOCK_IN0));
- rtc_timer_set_clock_count_value(1);
- /* Set RTC mode to timer running mode */
- rtc_timer_set_mode(RTC_TIMER_RUNNING);
- return 0;
- }
- int rtc_irq_callback(void *ctx)
- {
- rtc_instance_t *instance = (rtc_instance_t *)ctx;
- struct tm *now_tm = rtc_timer_get_tm();
- if(rtc_alarm_get_interrupt())
- {
- struct tm *alarm_tm = rtc_alarm_get_tm();
- rtc_mask_t alarm_mask = rtc_alarm_get_mask();
- if((*((uint8_t *)&alarm_mask) & 0xFE) == 0)
- {
- goto tick;
- }
- if(alarm_mask.year)
- {
- if(now_tm->tm_year != alarm_tm->tm_year)
- {
- goto tick;
- }
- }
- if(alarm_mask.month)
- {
- if(now_tm->tm_mon != alarm_tm->tm_mon)
- {
- goto tick;
- }
- }
- if(alarm_mask.day)
- {
- if(now_tm->tm_mday != alarm_tm->tm_mday)
- {
- goto tick;
- }
- }
- if(alarm_mask.hour)
- {
- if(now_tm->tm_hour != alarm_tm->tm_hour)
- {
- goto tick;
- }
- }
- if(alarm_mask.minute)
- {
- if(now_tm->tm_min != alarm_tm->tm_min)
- {
- goto tick;
- }
- }
- if(alarm_mask.second)
- {
- if(now_tm->tm_sec != alarm_tm->tm_sec)
- {
- goto tick;
- }
- }
- if(instance->alarm_is_single_shot)
- {
- rtc_alarm_set_interrupt(0);
- instance->tick_enable_by_alarm = false;
- instance->tick_mode_by_alarm = RTC_INT_MAX;
- if(instance->tick_enable_by_user)
- {
- if(instance->tick_mode_by_user > rtc_tick_get_interrupt_mode())
- {
- rtc_tick_set_interrupt(0);
- rtc_tick_set_interrupt_mode(instance->tick_mode_by_user);
- rtc_tick_set_interrupt(1);
- }
- } else
- {
- rtc_tick_set_interrupt(0);
- }
- }
- if(instance->rtc_alarm_callback)
- instance->rtc_alarm_callback(instance->alarm_ctx);
- }
- tick:
- if(instance->tick_enable_by_user)
- {
- switch(instance->tick_mode_by_user)
- {
- case RTC_INT_MINUTE:
- if(now_tm->tm_sec != 0)
- goto ret;
- break;
- case RTC_INT_HOUR:
- if(now_tm->tm_sec != 0 || now_tm->tm_min != 0)
- goto ret;
- break;
- case RTC_INT_DAY:
- if(now_tm->tm_sec != 0 || now_tm->tm_min != 0 || now_tm->tm_hour != 0)
- goto ret;
- break;
- case RTC_INT_SECOND:
- default:
- break;
- }
- if(instance->tick_is_single_shot)
- {
- rtc_tick_set_interrupt(0);
- instance->tick_enable_by_user = false;
- instance->tick_mode_by_user = -1;
- }
- if(instance->rtc_tick_callback)
- instance->rtc_tick_callback(instance->tick_ctx);
- }
- ret:
- return 0;
- }
- int rtc_tick_irq_register(bool is_single_shot, rtc_tick_interrupt_mode_t mode, plic_irq_callback_t callback, void *ctx, uint8_t priority)
- {
- plic_irq_disable(IRQN_RTC_INTERRUPT);
- rtc_tick_set_interrupt(0);
- rtc_instance.rtc_tick_callback = callback;
- rtc_instance.tick_ctx = ctx;
- rtc_instance.tick_is_single_shot = is_single_shot;
- rtc_instance.tick_enable_by_user = true;
- rtc_instance.tick_mode_by_user = mode;
- if(!rtc_instance.tick_enable_by_alarm || (rtc_instance.tick_enable_by_alarm && mode < rtc_tick_get_interrupt_mode()))
- {
- rtc_tick_set_interrupt_mode(mode);
- }
- plic_set_priority(IRQN_RTC_INTERRUPT, priority);
- plic_irq_register(IRQN_RTC_INTERRUPT, rtc_irq_callback, &rtc_instance);
- plic_irq_enable(IRQN_RTC_INTERRUPT);
- rtc_tick_set_interrupt(1);
- return 0;
- }
- void rtc_tick_irq_unregister(void)
- {
- /* Resolve interrupt dependency */
- if(!rtc_alarm_get_interrupt())
- {
- rtc_tick_set_interrupt(0);
- }
- rtc_instance.tick_enable_by_user = false;
- rtc_instance.tick_mode_by_user = -1;
- rtc_instance.rtc_tick_callback = NULL;
- rtc_instance.tick_ctx = NULL;
- if((!rtc_instance.rtc_tick_callback) && (!rtc_instance.rtc_alarm_callback))
- {
- plic_irq_unregister(IRQN_RTC_INTERRUPT);
- }
- }
- int rtc_alarm_irq_register(bool is_single_shot, rtc_mask_t mask, plic_irq_callback_t callback, void *ctx, uint8_t priority)
- {
- plic_irq_disable(IRQN_RTC_INTERRUPT);
- rtc_tick_set_interrupt(0);
- rtc_alarm_set_interrupt(0);
- rtc_instance.rtc_alarm_callback = callback;
- rtc_instance.alarm_ctx = ctx;
- rtc_instance.alarm_is_single_shot = is_single_shot;
- rtc_instance.tick_enable_by_alarm = true;
- if(mask.second)
- {
- rtc_instance.tick_mode_by_alarm = RTC_INT_SECOND;
- goto alarm_mode;
- }
- if(mask.minute)
- {
- rtc_instance.tick_mode_by_alarm = RTC_INT_MINUTE;
- goto alarm_mode;
- }
- if(mask.hour)
- {
- rtc_instance.tick_mode_by_alarm = RTC_INT_HOUR;
- goto alarm_mode;
- } else
- {
- rtc_instance.tick_mode_by_alarm = RTC_INT_DAY;
- }
- alarm_mode:
- if((rtc_instance.tick_enable_by_user && rtc_instance.tick_mode_by_alarm < rtc_tick_get_interrupt_mode()) || !rtc_instance.tick_enable_by_user)
- {
- rtc_tick_set_interrupt_mode(rtc_instance.tick_mode_by_alarm);
- }
- rtc_alarm_set_mask(mask);
- plic_set_priority(IRQN_RTC_INTERRUPT, priority);
- plic_irq_register(IRQN_RTC_INTERRUPT, rtc_irq_callback, &rtc_instance);
- plic_irq_enable(IRQN_RTC_INTERRUPT);
- rtc_alarm_set_interrupt(1);
- /* Must enable tick hardware interrupt */
- rtc_tick_set_interrupt(1);
- return 0;
- }
- void rtc_alarm_irq_unregister(void)
- {
- rtc_alarm_set_interrupt(0);
- rtc_instance.rtc_alarm_callback = NULL;
- rtc_instance.alarm_ctx = NULL;
- rtc_instance.tick_enable_by_alarm = false;
- rtc_instance.tick_mode_by_alarm = RTC_INT_MAX;
- if(rtc_instance.tick_enable_by_user)
- {
- if(rtc_instance.tick_mode_by_user > rtc_tick_get_interrupt_mode())
- {
- rtc_tick_set_interrupt(0);
- rtc_tick_set_interrupt_mode(rtc_instance.tick_mode_by_user);
- rtc_tick_set_interrupt(1);
- }
- } else
- {
- rtc_tick_set_interrupt(0);
- }
- if((!rtc_instance.rtc_tick_callback) && (!rtc_instance.rtc_alarm_callback))
- {
- plic_irq_unregister(IRQN_RTC_INTERRUPT);
- }
- }
|