diff --git a/inc/rtc.h b/inc/rtc.h --- a/inc/rtc.h +++ b/inc/rtc.h @@ -6,6 +6,7 @@ void rtc_init(void); RTC_TimeTypeDef* rtc_time(void); +uint64_t rtc_timestamp(void); RTC_HandleTypeDef* rtc_gethandle(void); diff --git a/src/main.c b/src/main.c --- a/src/main.c +++ b/src/main.c @@ -55,14 +55,16 @@ int main(void) uint16_t blink_rate = BLINK_FAST; uint8_t state = SYSTEM_GPSACQ; -//DEBUG: -// uint8_t state = SYSTEM_IDLE; + + // DEBUG EMZ FIXME + state = SYSTEM_IDLE; uint32_t gps_polltimer = 0; uint32_t fix_acq_starttime = 0; uint32_t nextwspr_time = 0; uint8_t nextwspr_time_valid = 0; uint32_t last_wspr_tx_time = 0; + uint64_t idle_blink_last = 0; uint8_t packet_type = 0; @@ -75,12 +77,9 @@ int main(void) // __DBGMCU_CLK_ENABLE() ; // (RCC->APB2ENR |= (RCC_APB2ENR_DBGMCUEN)) // HAL_EnableDBGStopMode(); // SET_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STOP); - uint32_t idle_blink_last = 0; while (1) { - // TODO: Disable GPIO port clocking when not needed! - // Every 10 minutes, wake up and try to wspr if(state == SYSTEM_IDLE && (HAL_GetTick() - last_wspr_tx_time > 60000 * 10)) { @@ -121,27 +120,42 @@ int main(void) // Idling: sleep and wait for RTC timeslot trigger case SYSTEM_IDLE: { - // Don't blink normally - blink_rate = 9999; //BLINK_SLOW; + // Don't blink with the usual method + blink_rate = BLINK_DISABLE; // If we haven't blinked for a while, blink now - if(HAL_GetTick() - idle_blink_last > 10 * 1000) + if(rtc_timestamp() - idle_blink_last > 10 * 1000) { HAL_GPIO_WritePin(LED_BLUE, 1); HAL_Delay(20); HAL_GPIO_WritePin(LED_BLUE, 0); - idle_blink_last = HAL_GetTick(); + idle_blink_last = rtc_timestamp(); } + + // Enter STOP mode for one second using RTC for wakeup + // 1s might not be accurate because we're entering STOP + // mode any time between 1s interrupt ticks... + + // TODO: Calculate full RTC timestamp before entering + // and after entering, find delta, this is the amount + // we use to increment SYSTICK + + // Enter sleep mode: wait for interrupt //HAL_PWR_EnterSLEEPMode(0, PWR_SLEEPENTRY_WFI); + + uint64_t start = rtc_timestamp(); + __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); HAL_SuspendTick(); HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); // We probably stopped for a second - HAL_IncTickBy(1000); // maybe check the RTC before and after this, increment tick by the delta? + uint32_t timedelta = rtc_timestamp() - start; + HAL_IncTickBy(timedelta); + //HAL_IncTickBy(1000); // maybe check the RTC before and after this, increment tick by the delta? HAL_ResumeTick(); // We have woken up! Clear wakeup flag @@ -271,6 +285,8 @@ int main(void) } } + + static void ledpulse(void) { HAL_GPIO_WritePin(LED_BLUE, 1); diff --git a/src/rtc.c b/src/rtc.c --- a/src/rtc.c +++ b/src/rtc.c @@ -34,8 +34,8 @@ void rtc_init(void) hrtc.Instance = RTC; hrtc.Init.HourFormat = RTC_HOURFORMAT_24; - hrtc.Init.AsynchPrediv = 124; - hrtc.Init.SynchPrediv = 322; // if this has enough bits should be 1.0018Hz based on 40kHz LSI + hrtc.Init.AsynchPrediv = 127; // Note that both these dividers actually divide by their value + 1 + hrtc.Init.SynchPrediv = 311; // About 1Hz with 40kHz LSI hrtc.Init.OutPut = RTC_OUTPUT_DISABLE; hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; @@ -102,6 +102,58 @@ RTC_TimeTypeDef* rtc_time(void) return &time_last; } +uint16_t __rtc_millis(uint32_t sub_seconds) +{ + // Subsecond counter counts down from SynchPrediv value to zero + return (hrtc.Init.SynchPrediv - sub_seconds) * 999 / hrtc.Init.SynchPrediv; // 0 - 999 mS +} + +#define JULIAN_DATE_BASE 2440588 // Unix epoch time in Julian calendar (UnixTime = 00:00:00 01.01.1970 => JDN = 2440588) + +uint64_t rtc_timestamp(void) +{ + RTC_TimeTypeDef time = {0}; + RTC_DateTypeDef date = {0}; + + HAL_RTC_GetTime(&hrtc, &time, RTC_FORMAT_BCD); + HAL_RTC_GetDate(&hrtc, &date, RTC_FORMAT_BCD); + + // Thanks to LonelyWolf: https://github.com/LonelyWolf/stm32/blob/master/stm32l-dosfs/RTC.c + // Convert Date/Time structures to epoch time + uint8_t a; + uint16_t y; + uint8_t m; + uint64_t JDN; + + // These hardcore math's are taken from http://en.wikipedia.org/wiki/Julian_day + + // Calculate some coefficients + a = (14 - date.Month) / 12; + y = (date.Year + 2000) + 4800 - a; // years since 1 March, 4801 BC + m = date.Month + (12 * a) - 3; // since 1 March, 4801 BC + + // Gregorian calendar date compute + JDN = date.Date; + JDN += (153 * m + 2) / 5; + JDN += 365 * y; + JDN += y / 4; + JDN += -y / 100; + JDN += y / 400; + JDN = JDN - 32045; + JDN = JDN - JULIAN_DATE_BASE; // Calculate from base date + JDN *= 86400; // Days to seconds + JDN += time.Hours * 3600; // ... and today seconds + JDN += time.Minutes * 60; + JDN += time.Seconds; + + JDN *= 1000; // Prepare to add ms + + JDN += __rtc_millis(time.SubSeconds); + + return JDN; + +} + void rtc_cal(void) { diff --git a/src/wspr.c b/src/wspr.c --- a/src/wspr.c +++ b/src/wspr.c @@ -254,8 +254,8 @@ void wspr_transmit(uint8_t* grid_locator //si5351_set_pll(SI5351_PLL_FIXED, SI5351_PLLA); //si5351_set_ms_source(SI5351_CLK0, SI5351_PLLA); si5351_set_freq(WSPR_DEFAULT_FREQ * 100, 0, SI5351_CLK0); -// si5351_drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA); // Set for max power if desired (8ma max) - si5351_drive_strength(SI5351_CLK0, SI5351_DRIVE_6MA); // Set for max power if desired (8ma max) + si5351_drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA); // Set for max power if desired (8ma max) +// si5351_drive_strength(SI5351_CLK0, SI5351_DRIVE_6MA); // Set for max power if desired (8ma max) // si5351_drive_strength(SI5351_CLK0, SI5351_DRIVE_2MA); // Set for max power if desired (8ma max) si5351_output_enable(SI5351_CLK0, 1); //si5351_pll_reset(SI5351_PLLA);