DWORD get_fattime(void) { rtc_init_finalise(); RTC_TimeTypeDef time; RTC_DateTypeDef date; HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN); HAL_RTC_GetDate(&RTCHandle, &date, FORMAT_BIN); return ((2000 + date.Year - 1980) << 25) | ((date.Month) << 21) | ((date.Date) << 16) | ((time.Hours) << 11) | ((time.Minutes) << 5) | (time.Seconds / 2); }
/// \function time() /// Returns the number of seconds, as an integer, since 1/1/2000. STATIC mp_obj_t time_time(void) { // get date and time // note: need to call get time then get date to correctly access the registers rtc_init_finalise(); RTC_DateTypeDef date; RTC_TimeTypeDef time; HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN); HAL_RTC_GetDate(&RTCHandle, &date, FORMAT_BIN); return mp_obj_new_int(timeutils_seconds_since_2000(2000 + date.Year, date.Month, date.Date, time.Hours, time.Minutes, time.Seconds)); }
MP_WEAK DWORD get_fattime(void) { #if MICROPY_HW_ENABLE_RTC rtc_init_finalise(); RTC_TimeTypeDef time; RTC_DateTypeDef date; HAL_RTC_GetTime(&RTCHandle, &time, RTC_FORMAT_BIN); HAL_RTC_GetDate(&RTCHandle, &date, RTC_FORMAT_BIN); return ((2000 + date.Year - 1980) << 25) | ((date.Month) << 21) | ((date.Date) << 16) | ((time.Hours) << 11) | ((time.Minutes) << 5) | (time.Seconds / 2); #else // Jan 1st, 2018 at midnight. Not sure what timezone. return ((2018 - 1980) << 25) | ((1) << 21) | ((1) << 16) | ((0) << 11) | ((0) << 5) | (0 / 2); #endif }
// calibration(None) // calibration(cal) // When an integer argument is provided, check that it falls in the range [-511 to 512] // and set the calibration value; otherwise return calibration value mp_obj_t pyb_rtc_calibration(mp_uint_t n_args, const mp_obj_t *args) { rtc_init_finalise(); mp_int_t cal; if (n_args == 2) { cal = mp_obj_get_int(args[1]); mp_uint_t cal_p, cal_m; if (cal < -511 || cal > 512) { #if defined(MICROPY_HW_RTC_USE_CALOUT) && MICROPY_HW_RTC_USE_CALOUT if ((cal & 0xfffe) == 0x0ffe) { // turn on/off X18 (PC13) 512Hz output // Note: // Output will stay active even in VBAT mode (and inrease current) if (cal & 1) { HAL_RTCEx_SetCalibrationOutPut(&RTCHandle, RTC_CALIBOUTPUT_512HZ); } else { HAL_RTCEx_DeactivateCalibrationOutPut(&RTCHandle); } return mp_obj_new_int(cal & 1); } else { nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "calibration value out of range")); } #else nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "calibration value out of range")); #endif } if (cal > 0) { cal_p = RTC_SMOOTHCALIB_PLUSPULSES_SET; cal_m = 512 - cal; } else { cal_p = RTC_SMOOTHCALIB_PLUSPULSES_RESET; cal_m = -cal; } HAL_RTCEx_SetSmoothCalib(&RTCHandle, RTC_SMOOTHCALIB_PERIOD_32SEC, cal_p, cal_m); return mp_const_none; } else { // printf("CALR = 0x%x\n", (mp_uint_t) RTCHandle.Instance->CALR); // DEBUG // Test if CALP bit is set in CALR: if (RTCHandle.Instance->CALR & 0x8000) { cal = 512 - (RTCHandle.Instance->CALR & 0x1ff); } else { cal = -(RTCHandle.Instance->CALR & 0x1ff); } return mp_obj_new_int(cal); } }
mp_obj_t pyb_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) { rtc_init_finalise(); if (n_args == 1) { // get date and time // note: need to call get time then get date to correctly access the registers RTC_DateTypeDef date; RTC_TimeTypeDef time; HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN); HAL_RTC_GetDate(&RTCHandle, &date, FORMAT_BIN); mp_obj_t tuple[8] = { mp_obj_new_int(2000 + date.Year), mp_obj_new_int(date.Month), mp_obj_new_int(date.Date), mp_obj_new_int(date.WeekDay), mp_obj_new_int(time.Hours), mp_obj_new_int(time.Minutes), mp_obj_new_int(time.Seconds), mp_obj_new_int(rtc_subsec_to_us(time.SubSeconds)), }; return mp_obj_new_tuple(8, tuple); } else { // set date and time mp_obj_t *items; mp_obj_get_array_fixed_n(args[1], 8, &items); RTC_DateTypeDef date; date.Year = mp_obj_get_int(items[0]) - 2000; date.Month = mp_obj_get_int(items[1]); date.Date = mp_obj_get_int(items[2]); date.WeekDay = mp_obj_get_int(items[3]); HAL_RTC_SetDate(&RTCHandle, &date, FORMAT_BIN); RTC_TimeTypeDef time; time.Hours = mp_obj_get_int(items[4]); time.Minutes = mp_obj_get_int(items[5]); time.Seconds = mp_obj_get_int(items[6]); time.SubSeconds = rtc_us_to_subsec(mp_obj_get_int(items[7])); time.TimeFormat = RTC_HOURFORMAT12_AM; time.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; time.StoreOperation = RTC_STOREOPERATION_SET; HAL_RTC_SetTime(&RTCHandle, &time, FORMAT_BIN); return mp_const_none; } }
STATIC mp_obj_t machine_deepsleep(void) { rtc_init_finalise(); #if defined(MCU_SERIES_F7) printf("machine.deepsleep not supported yet\n"); #else // We need to clear the PWR wake-up-flag before entering standby, since // the flag may have been set by a previous wake-up event. Furthermore, // we need to disable the wake-up sources while clearing this flag, so // that if a source is active it does actually wake the device. // See section 5.3.7 of RM0090. // Note: we only support RTC ALRA, ALRB, WUT and TS. // TODO support TAMP and WKUP (PA0 external pin). uint32_t irq_bits = RTC_CR_ALRAIE | RTC_CR_ALRBIE | RTC_CR_WUTIE | RTC_CR_TSIE; // save RTC interrupts uint32_t save_irq_bits = RTC->CR & irq_bits; // disable RTC interrupts RTC->CR &= ~irq_bits; // clear RTC wake-up flags RTC->ISR &= ~(RTC_ISR_ALRAF | RTC_ISR_ALRBF | RTC_ISR_WUTF | RTC_ISR_TSF); // clear global wake-up flag PWR->CR |= PWR_CR_CWUF; // enable previously-enabled RTC interrupts RTC->CR |= save_irq_bits; // enter standby mode HAL_PWR_EnterSTANDBYMode(); // we never return; MCU is reset on exit from standby #endif return mp_const_none; }
/// \function localtime([secs]) /// Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which /// contains: (year, month, mday, hour, minute, second, weekday, yearday) /// If secs is not provided or None, then the current time from the RTC is used. /// year includes the century (for example 2014) /// month is 1-12 /// mday is 1-31 /// hour is 0-23 /// minute is 0-59 /// second is 0-59 /// weekday is 0-6 for Mon-Sun. /// yearday is 1-366 STATIC mp_obj_t time_localtime(mp_uint_t n_args, const mp_obj_t *args) { if (n_args == 0 || args[0] == mp_const_none) { // get current date and time // note: need to call get time then get date to correctly access the registers rtc_init_finalise(); RTC_DateTypeDef date; RTC_TimeTypeDef time; HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN); HAL_RTC_GetDate(&RTCHandle, &date, FORMAT_BIN); mp_obj_t tuple[8] = { mp_obj_new_int(2000 + date.Year), mp_obj_new_int(date.Month), mp_obj_new_int(date.Date), mp_obj_new_int(time.Hours), mp_obj_new_int(time.Minutes), mp_obj_new_int(time.Seconds), mp_obj_new_int(date.WeekDay - 1), mp_obj_new_int(timeutils_year_day(2000 + date.Year, date.Month, date.Date)), }; return mp_obj_new_tuple(8, tuple); } else { mp_int_t seconds = mp_obj_get_int(args[0]); timeutils_struct_time_t tm; timeutils_seconds_since_2000_to_struct_time(seconds, &tm); mp_obj_t tuple[8] = { tuple[0] = mp_obj_new_int(tm.tm_year), tuple[1] = mp_obj_new_int(tm.tm_mon), tuple[2] = mp_obj_new_int(tm.tm_mday), tuple[3] = mp_obj_new_int(tm.tm_hour), tuple[4] = mp_obj_new_int(tm.tm_min), tuple[5] = mp_obj_new_int(tm.tm_sec), tuple[6] = mp_obj_new_int(tm.tm_wday), tuple[7] = mp_obj_new_int(tm.tm_yday), }; return mp_obj_new_tuple(8, tuple); } }
// wakeup(None) // wakeup(ms, callback=None) // wakeup(wucksel, wut, callback) mp_obj_t pyb_rtc_wakeup(mp_uint_t n_args, const mp_obj_t *args) { // wut is wakeup counter start value, wucksel is clock source // counter is decremented at wucksel rate, and wakes the MCU when it gets to 0 // wucksel=0b000 is RTC/16 (RTC runs at 32768Hz) // wucksel=0b001 is RTC/8 // wucksel=0b010 is RTC/4 // wucksel=0b011 is RTC/2 // wucksel=0b100 is 1Hz clock // wucksel=0b110 is 1Hz clock with 0x10000 added to wut // so a 1 second wakeup could be wut=2047, wucksel=0b000, or wut=4095, wucksel=0b001, etc rtc_init_finalise(); // disable wakeup IRQ while we configure it HAL_NVIC_DisableIRQ(RTC_WKUP_IRQn); bool enable = false; mp_int_t wucksel; mp_int_t wut; mp_obj_t callback = mp_const_none; if (n_args <= 3) { if (args[1] == mp_const_none) { // disable wakeup } else { // time given in ms mp_int_t ms = mp_obj_get_int(args[1]); mp_int_t div = 2; wucksel = 3; while (div <= 16 && ms > 2000 * div) { div *= 2; wucksel -= 1; } if (div <= 16) { wut = 32768 / div * ms / 1000; } else { // use 1Hz clock wucksel = 4; wut = ms / 1000; if (wut > 0x10000) { // wut too large for 16-bit register, try to offset by 0x10000 wucksel = 6; wut -= 0x10000; if (wut > 0x10000) { // wut still too large nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "wakeup value too large")); } } } // wut register should be 1 less than desired value, but guard against wut=0 if (wut > 0) { wut -= 1; } enable = true; } if (n_args == 3) { callback = args[2]; } } else { // config values given directly wucksel = mp_obj_get_int(args[1]); wut = mp_obj_get_int(args[2]); callback = args[3]; enable = true; } // set the callback MP_STATE_PORT(pyb_extint_callback)[22] = callback; // disable register write protection RTC->WPR = 0xca; RTC->WPR = 0x53; // clear WUTE RTC->CR &= ~(1 << 10); // wait until WUTWF is set while (!(RTC->ISR & (1 << 2))) { } if (enable) { // program WUT RTC->WUTR = wut; // set WUTIE to enable wakeup interrupts // set WUTE to enable wakeup // program WUCKSEL RTC->CR = (RTC->CR & ~7) | (1 << 14) | (1 << 10) | (wucksel & 7); // enable register write protection RTC->WPR = 0xff; // enable external interrupts on line 22 #if defined(MCU_SERIES_L4) EXTI->IMR1 |= 1 << 22; EXTI->RTSR1 |= 1 << 22; #else EXTI->IMR |= 1 << 22; EXTI->RTSR |= 1 << 22; #endif // clear interrupt flags RTC->ISR &= ~(1 << 10); #if defined(MCU_SERIES_L4) EXTI->PR1 = 1 << 22; #else EXTI->PR = 1 << 22; #endif HAL_NVIC_SetPriority(RTC_WKUP_IRQn, IRQ_PRI_RTC_WKUP, IRQ_SUBPRI_RTC_WKUP); HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn); //printf("wut=%d wucksel=%d\n", wut, wucksel); } else { // clear WUTIE to disable interrupts RTC->CR &= ~(1 << 14); // enable register write protection RTC->WPR = 0xff; // disable external interrupts on line 22 #if defined(MCU_SERIES_L4) EXTI->IMR1 &= ~(1 << 22); #else EXTI->IMR &= ~(1 << 22); #endif } return mp_const_none; }
// force rtc to re-initialise mp_obj_t pyb_rtc_init(mp_obj_t self_in) { rtc_init_start(true); rtc_init_finalise(); return mp_const_none; }