Xmega Application Note | |||||
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 }
Generated on Fri Oct 22 12:15:25 2010 for AVR1300 Using the Xmega ADC by ![]() |