/* Copyright (c) 2005, Jorgen Birkler All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include // ********************************************** // * Configuration // ********************************************** /** * TIMER2_CLOCK_FREQ is set to the external crystal frequency in Hz, Usually 32768Hz. * * TIMER2_RTC_UPDATE_TIME should be set to the time between * updates to the RTC (Real Time Clock). Usually 1000 ms. * * When using a crystal to clock the core the chip waits 35ms for the clock * to stabilize before any code is executed. The 35ms is default but can be changed * to 1ms if using a ceramic resonator by changing a fuse bit. See * the application note AN1259 about the RTC clock. * * Larger updates times give lower power consumption but timers with less resolution * (usually not a problem) timers. * Lower values gives more accurate timers but higher power consumption. * * Accuracy of the RTC is only affected by the accuracy of the * crystal not by the selected TIMER2_RTC_UPDATE_TIME. The resolution * of the RTC is TIMER2_RTC_UPDATE_TIME/256. * */ #ifndef RTC_TIMER2_CLOCK_FREQ #define RTC_TIMER2_CLOCK_FREQ 32768 //Hz #error "RTC_TIMER2_CLOCK_FREQ not defined. See config info." #endif //TIMER2_CLOCK_FREQ #ifndef RTC_TIMER2_RTC_UPDATE_TIME #define RTC_TIMER2_RTC_UPDATE_TIME 1000 //ms #error "RTC_TIMER2_RTC_UPDATE_TIME not defined. See config info." #endif //TIMER2_RTC_UPDATE_TIME ///Prescaler requested by user #define RTC_TIMER2_REQUESTED_PRESCALER \ ((RTC_TIMER2_CLOCK_FREQ /*Hz*/) * 1000L /*ms*// \ (256L /*overflow*/ * (RTC_TIMER2_RTC_UPDATE_TIME/*ms*/))) //Now check the validity of the requested RTC update time #if (256L * RTC_TIMER2_REQUESTED_PRESCALER * RTC_TIMER2_RTC_UPDATE_TIME != 1000L * (RTC_TIMER2_CLOCK_FREQ)) #error "Cannot prescale clock (RTC_TIMER2_CLOCK_FREQ) to suit selected RTC_TIMER2_RTC_UPDATE_TIME." #endif //check update time #if (((RTC_TIMER2_RTC_UPDATE_TIME) / 1000) * 1000 == (RTC_TIMER2_RTC_UPDATE_TIME)) #define RTC_UPDATE_TIME ((RTC_TIMER2_RTC_UPDATE_TIME) / 1000) #endif #if !defined(RTC_TIMER2_CLOCK_FREQ) || !defined(RTC_TIMER2_RTC_UPDATE_TIME) || !defined(RTC_TIMER2_REQUESTED_PRESCALER) #error "Requested prescaler not calculated" #elif (RTC_TIMER2_REQUESTED_PRESCALER == 1) #define RTC_TCCR2_PRESCALE TCCR2_PRESCALE_1 #elif (RTC_TIMER2_REQUESTED_PRESCALER == 8) #define RTC_TCCR2_PRESCALE TCCR2_PRESCALE_8 #elif (RTC_TIMER2_REQUESTED_PRESCALER == 32) #define RTC_TCCR2_PRESCALE TCCR2_PRESCALE_32 #elif (RTC_TIMER2_REQUESTED_PRESCALER == 64) #define RTC_TCCR2_PRESCALE TCCR2_PRESCALE_64 #elif (RTC_TIMER2_REQUESTED_PRESCALER == 128) #define RTC_TCCR2_PRESCALE TCCR2_PRESCALE_128 #elif (RTC_TIMER2_REQUESTED_PRESCALER == 256) #define RTC_TCCR2_PRESCALE TCCR2_PRESCALE_256 #elif (RTC_TIMER2_REQUESTED_PRESCALER == 1024) #define RTC_TCCR2_PRESCALE TCCR2_PRESCALE_1024 #else #error "Requested RTC_TIMER2_RTC_UPDATE_TIME not supported by TIMER2 prescaler. See config info." #define RTC_TCCR2_PRESCALE TCCR2_PRESCALE_STOPPED #endif // ********************************************** // * Hardware binding // ********************************************** #define RTC_TIMER2_ENABLE_OVERFLOW_INTERRUPT() TIMSK|=_BV(TOIE2) //Do not destroy the other flags (write zero to those) #define RTC_TIMER2_CLEAR_COMPARE_FLAG() TIFR = _BV(OCF2) #define RTC_TIMER2_CLEAR_OVERFLOW_FLAG() TIFR = _BV(TOV2) #define RTC_TIMER2_IS_COMPARE_FLAG_SET() bit_is_set(TIFR,OCF2) #define RTC_TIMER2_DISABLE_OVERFLOW_INTERRUPT() TIMSK&=~_BV(TOIE2) #define RTC_TIMER2_ENABLE_ASYNCHRONOUS() ASSR|=_BV(AS2) #define RTC_TIMER2_SET_COMPARE_VALUE(_val) OCR2 = _val #define RTC_TIMER2_COUNTER() TCNT2 #define RTC_TIMER2_SET_COUNTER(_val) TCNT2 = (_val) #define RTC_TIMER2_DISABLE_COMPARE_INTERRUPT() TIMSK &= ~_BV(OCIE2) #define RTC_TIMER2_ENABLE_COMPARE_INTERRUPT() TIMSK|=_BV(OCIE2) #define RTC_TIMER2_COMPARE_INTERRUPT_ENABLED() bit_is_set(TIMSK,OCIE2) #define RTC_TIMER2_COMPARE_INTERRUPT_DISABLED() bit_is_clear(TIMSK,OCIE2) #define RTC_TIMER2_ASYNC_SAFETY (1) #define RTC_TIMER2_WAIT_ASYNC_UPDATE() { \ uint8_t busy_flag;\ do { \ busy_flag = ASSR; \ busy_flag &= _BV(TCN2UB) | _BV(OCR2UB) | _BV(TCR2UB); \ } while (busy_flag); } #define TCCR2_CLEAR_ON_COMP_MATCH 0x80 #define TCCR2_COM_SET_OC2 _BV(COM21) | _BV(COM20) #define TCCR2_COM_TOGGLE_OC2 _BV(COM21) #define TCCR2_COM_CLEAR_OC2 _BV(COM20) #define TCCR2_COM_DISCONNECT_OC2 0x00 #define TCCR2_PRESCALE_STOPPED 0x00 #define TCCR2_PRESCALE_1 0x01 #define TCCR2_PRESCALE_8 0x02 #define TCCR2_PRESCALE_32 0x03 #define TCCR2_PRESCALE_64 0x04 #define TCCR2_PRESCALE_128 0x05 #define TCCR2_PRESCALE_256 0x06 #define TCCR2_PRESCALE_1024 0x07 extern void rtc_update(time_t deltaSeconds); extern void rtc_set_time(time_t time); ///Timer2 overflow interrupt SIGNAL(SIG_OVERFLOW2) { rtc_update(RTC_UPDATE_TIME); } /** * Initlializes and starts RTC clock and enables Timer2 interrupt */ static void rtc_init(void) { RTC_TIMER2_DISABLE_COMPARE_INTERRUPT(); RTC_TIMER2_DISABLE_OVERFLOW_INTERRUPT(); RTC_TIMER2_ENABLE_ASYNCHRONOUS(); TCCR2 = TCCR2_COM_DISCONNECT_OC2 | RTC_TCCR2_PRESCALE; RTC_TIMER2_SET_COUNTER(0); RTC_TIMER2_SET_COMPARE_VALUE(0); { /* TimerId_t id; for (id=0;id < TIMER_LAST;id++) { Timers[id]=TIMER_RESET; }*/ } RTC_TIMER2_WAIT_ASYNC_UPDATE(); RTC_TIMER2_ENABLE_OVERFLOW_INTERRUPT(); }