int rtc_init(volatile avr32_rtc_t *rtc, unsigned char osc_type, unsigned char psel) { // If exit, it means that the configuration has not been set correctly if (osc_type > (1 << AVR32_RTC_CTRL_CLK32_SIZE) - 1 || psel > (1 << AVR32_RTC_CTRL_PSEL_SIZE) - 1) return 0; // If we use the 32-kHz oscillator, we have to enable it first if (osc_type == RTC_OSC_32KHZ) { // Select the 32-kHz oscillator crystal pm_enable_osc32_crystal(&AVR32_PM); // Enable the 32-kHz clock and wait until the osc32 clock is ready. pm_enable_clk32(&AVR32_PM, AVR32_PM_OSCCTRL32_STARTUP_0_RCOSC); } // Wait until the rtc accepts writes to the CTRL register while (rtc_is_busy(rtc)); // Set the new RTC configuration rtc->ctrl = osc_type << AVR32_RTC_CTRL_CLK32_OFFSET | psel << AVR32_RTC_CTRL_PSEL_OFFSET | AVR32_RTC_CTRL_CLKEN_MASK; // Wait until write is done while (rtc_is_busy(rtc)); // Set the counter value to 0 rtc_set_value(rtc, 0x00000000); // Set the top value to 0xFFFFFFFF rtc_set_top_value(rtc, 0xFFFFFFFF); return 1; }
void rtc_set_value(volatile avr32_rtc_t *rtc, unsigned long val) { // Wait until we can write into the VAL register while (rtc_is_busy(rtc)); // Set the new val value rtc->val = val; // Wait until write is done while (rtc_is_busy(rtc)); }
void rtc_disable(volatile avr32_rtc_t *rtc) { // Wait until the rtc CTRL register is up-to-date while (rtc_is_busy(rtc)); // Disable the RTC rtc->ctrl &= ~AVR32_RTC_CTRL_EN_MASK; // Wait until write is done while (rtc_is_busy(rtc)); }
void rtc_enable_wake_up(volatile avr32_rtc_t *rtc) { // Wait until the rtc CTRL register is up-to-date while (rtc_is_busy(rtc)); // Enable the wake up of the RTC rtc->ctrl |= AVR32_RTC_CTRL_WAKE_EN_MASK; // Wait until write is done while (rtc_is_busy(rtc)); }
/** * \brief Set alarm time * * Will set absolute alarm time that will call the callback specifed by \ref * rtc_set_callback on completion. Or possibly use \ref * rtc_alarm_has_triggered to check for it. * * Any pending alarm will be overwritten with this function. * * \param time Absolute time value. See also \ref rtc_min_alarm_time * \pre Needs interrupts disabled if used from several contexts */ void rtc_set_alarm(uint32_t time) { RTC.INTCTRL = RTC_OVERFLOW_INT_LEVEL; while (rtc_is_busy()); RTC.COMP = time; rtc_data.alarm_low = time; rtc_data.alarm_high = time >> 16; while (rtc_is_busy()); RTC.INTCTRL = RTC_COMPARE_INT_LEVEL | RTC_OVERFLOW_INT_LEVEL; }
static int omaprtc_settime(todr_chip_handle_t tch, struct clock_ymdhms *dt) { struct omaprtc_softc *sc = tch->cookie; int s; s = disable_interrupts(I32_bit); while (rtc_is_busy()) { ; } /* It's ok to write these without stopping the * RTC, because the BUSY mechanism lets us guarantee * that we're not in the middle of, e.g., rolling * seconds into minutes. */ bus_space_write_1(sc->sc_iot, sc->sc_ioh, YEARS_REG, TOBCD(dt->dt_year - BASEYEAR)); bus_space_write_1(sc->sc_iot, sc->sc_ioh, MONTHS_REG, TOBCD(dt->dt_mon)); bus_space_write_1(sc->sc_iot, sc->sc_ioh, WEEKS_REG, TOBCD(dt->dt_wday & 0x0f)); bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAYS_REG, TOBCD(dt->dt_day)); bus_space_write_1(sc->sc_iot, sc->sc_ioh, SECONDS_REG, TOBCD(dt->dt_sec)); bus_space_write_1(sc->sc_iot, sc->sc_ioh, HOURS_REG, TOBCD(dt->dt_hour)); bus_space_write_1(sc->sc_iot, sc->sc_ioh, MINUTES_REG, TOBCD(dt->dt_min)); restore_interrupts(s); return 0; }
/** * \brief Set current time * * \param time Time value to set */ void rtc_set_time(uint32_t time) { RTC.CTRL = RTC_PRESCALER_OFF_gc; while (rtc_is_busy()); RTC.CNT = time; rtc_data.counter_high = time >> 16; RTC.CTRL = CONFIG_RTC_PRESCALER; }
static int omaprtc_gettime(todr_chip_handle_t tch, struct clock_ymdhms *dt) { struct omaprtc_softc *sc = tch->cookie; int s; /* Wait for RTC_STATUS_REG:BUSY to go low to * guarantee our read is correct. BUSY will * only be high for one 32kHz period (30.5us) * each second, so we'll usually pass right * through. * * Watch RTC_CTRL_REG:STOP_RTC as well so * we don't spin forever if someone disables the RTC. * * Turn interrupts off, because we are only allowed * to read/write the registers for 1/2 of a 32kHz * clock period (= 15us) after detecting that BUSY * is low. */ s = disable_interrupts(I32_bit); while (rtc_is_busy()) { ; } dt->dt_year = FROMBCD(bus_space_read_1(sc->sc_iot, sc->sc_ioh, YEARS_REG)) + BASEYEAR; dt->dt_mon = FROMBCD(bus_space_read_1(sc->sc_iot, sc->sc_ioh, MONTHS_REG)); dt->dt_wday = FROMBCD(bus_space_read_1(sc->sc_iot, sc->sc_ioh, WEEKS_REG) & 0x0f); dt->dt_day = FROMBCD(bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAYS_REG)); dt->dt_sec = FROMBCD(bus_space_read_1(sc->sc_iot, sc->sc_ioh, SECONDS_REG)); dt->dt_hour = FROMBCD(bus_space_read_1(sc->sc_iot, sc->sc_ioh, HOURS_REG)); dt->dt_min = FROMBCD(bus_space_read_1(sc->sc_iot, sc->sc_ioh, MINUTES_REG)); restore_interrupts(s); return 0; }
/** * \brief Set current time * * \param time Time value to set */ void rtc_set_time(uint32_t time) { RTC32.CTRL = 0; while (rtc_is_busy()); RTC32.CNT = time; RTC32.CTRL = RTC32_ENABLE_bm; }
/** * \brief Initialize the 32kHz oscillator and RTC32 * * Starts up the 32kHz oscillator in the backup system and initializes the * RTC32. * * \note When the backup system is used, the function \ref * rtc_vbat_system_check should be called to determine if a re-initialization * must be done. */ void rtc_init(void) { sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_RTC); // Set up VBAT system and start oscillator vbat_init(); // Disable the RTC32 module before setting it up RTC32.CTRL = 0; while (rtc_is_busy()); // Set up maximum period and start at 0 RTC32.PER = 0xffffffff; RTC32.CNT = 0; while (rtc_is_busy()); RTC32.INTCTRL = 0; RTC32.CTRL = RTC32_ENABLE_bm; // Make sure it's sync'ed before return while (rtc_is_busy()); }
/** * \brief Get current time * * \return Current time value * * \note For devices with the errata "RTC Counter value not correctly read * after sleep", this can return old values shortly after waking up from * sleep. * \note Without this errata this function can block for up to 1 RTC * clock source cycle after waking up from sleep. */ uint32_t rtc_get_time(void) { irqflags_t flags; uint16_t count_high; uint16_t count_low; while (rtc_is_busy()); flags = cpu_irq_save(); count_high = rtc_data.counter_high; count_low = RTC.CNT; // Test for possible pending increase of high count value if ((count_low == 0) && (RTC.INTFLAGS & RTC_OVFIF_bm)) count_high++; cpu_irq_restore(flags); return ((uint32_t)count_high << 16) | count_low; }