Xmega Application Note


rtc.c

Go to the documentation of this file.
00001 
00038 #include <compiler.h>
00039 #include <sysclk.h>
00040 #include <sleepmgr.h>
00041 #include <rtc.h>
00042 
00043 #ifdef CONFIG_RTC_OVERFLOW_INT_LEVEL
00044 # define RTC_OVERFLOW_INT_LEVEL CONFIG_RTC_OVERFLOW_INT_LEVEL
00045 #else
00046 # define RTC_OVERFLOW_INT_LEVEL RTC_OVFINTLVL_LO_gc
00047 #endif
00048 
00049 #ifdef CONFIG_RTC_COMPARE_INT_LEVEL
00050 # define RTC_COMPARE_INT_LEVEL CONFIG_RTC_COMPARE_INT_LEVEL
00051 #else
00052 # define RTC_COMPARE_INT_LEVEL RTC_COMPINTLVL_LO_gc
00053 #endif
00054 
00059 struct rtc_data_struct {
00061         uint16_t counter_high;
00063         uint16_t alarm_high;
00065         uint16_t alarm_low;
00067         rtc_callback_t callback;
00068 };
00069 
00074 struct rtc_data_struct rtc_data;
00075 
00080 static bool rtc_is_busy(void)
00081 {
00082         return RTC.STATUS & RTC_SYNCBUSY_bm;
00083 }
00084 
00090 void rtc_set_time(uint32_t time)
00091 {
00092         RTC.CTRL = RTC_PRESCALER_OFF_gc;
00093         while (rtc_is_busy());
00094         RTC.CNT = time;
00095         rtc_data.counter_high = time >> 16;
00096         RTC.CTRL = CONFIG_RTC_PRESCALER;
00097 }
00098 
00107 uint32_t rtc_get_time(void)
00108 {
00109         irqflags_t flags;
00110         uint16_t   count_high;
00111         uint16_t   count_low;
00112 
00113         flags = cpu_irq_save();
00114         count_high = rtc_data.counter_high;
00115         count_low = RTC.CNT;
00116         // Test for possible pending increase of high count value
00117         if ((count_low == 0) && (RTC.INTFLAGS & RTC_OVFIF_bm))
00118                 count_high++;
00119         cpu_irq_restore(flags);
00120         return ((uint32_t)count_high << 16) | count_low;
00121 }
00122 
00135 void rtc_set_alarm(uint32_t time)
00136 {
00137         RTC.INTCTRL = RTC_OVERFLOW_INT_LEVEL;
00138         while (rtc_is_busy());
00139         RTC.COMP = time;
00140         rtc_data.alarm_low = time;
00141         rtc_data.alarm_high = time >> 16;
00142         while (rtc_is_busy());
00143         RTC.INTCTRL = RTC_COMPARE_INT_LEVEL
00144                 | RTC_OVERFLOW_INT_LEVEL;
00145 }
00146 
00153 bool rtc_alarm_has_triggered(void)
00154 {
00155         // Interrupt enable is used on pending alarm
00156         return !(RTC.INTCTRL & RTC_COMPARE_INT_LEVEL);
00157 }
00158 
00164 void rtc_set_callback(rtc_callback_t callback)
00165 {
00166         rtc_data.callback = callback;
00167 }
00168 
00174 void rtc_init(void)
00175 {
00176         sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_RTC);
00177         CLK.RTCCTRL = CONFIG_RTC_CLOCK_SOURCE | CLK_RTCEN_bm;
00178         RTC.PER = 0xffff;
00179         RTC.CNT = 0;
00180         /* Since overflow interrupt is needed all the time we limit sleep to
00181          * power-save.
00182          */
00183         sleepmgr_lock_mode(SLEEPMGR_PSAVE);
00184         RTC.INTCTRL = RTC_OVERFLOW_INT_LEVEL;
00185         RTC.CTRL = CONFIG_RTC_PRESCALER;
00186 }
00187 
00192 ISR(RTC_OVF_vect)
00193 {
00194         rtc_data.counter_high++;
00195 }
00196 
00201 ISR(RTC_COMP_vect)
00202 {
00203         if (rtc_data.counter_high >= rtc_data.alarm_high) {
00204                 RTC.INTCTRL = RTC_OVERFLOW_INT_LEVEL;
00205                 if (rtc_data.callback) {
00206                         uint32_t count = ((uint32_t)rtc_data.counter_high << 16)
00207                                         | RTC.CNT;
00208                         uint32_t alarm = ((uint32_t)rtc_data.alarm_high << 16)
00209                                         | rtc_data.alarm_low;
00210                         /* Workaround for errata. Count might not be updated
00211                          * when waking up from sleep, so in this case use alarm
00212                          * time pluss one.
00213                          */
00214                         if (alarm >= count)
00215                                 count = alarm + 1;
00216                         rtc_data.callback(count);
00217                 }
00218         }
00219 }
@DOC_TITLE@
Generated on Fri Oct 22 12:15:25 2010 for AVR1300 Using the Xmega ADC by doxygen 1.6.3