summaryrefslogtreecommitdiffstats
path: root/stm32/app/rtc.c
diff options
context:
space:
mode:
Diffstat (limited to 'stm32/app/rtc.c')
-rw-r--r--stm32/app/rtc.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/stm32/app/rtc.c b/stm32/app/rtc.c
new file mode 100644
index 0000000..0030cfd
--- /dev/null
+++ b/stm32/app/rtc.c
@@ -0,0 +1,170 @@
+#include "project.h"
+
+static volatile uint32_t hz = HZ;
+static volatile uint32_t cycle_ref;
+static volatile uint32_t rtc_ref;
+
+#define RTC_IN_LH 0x21f7
+#define RTC_IN_UH 0x6a6d
+
+static EPOCH rtc_offset;
+static uint16_t rtc_half;
+
+volatile unsigned rtc_ready;
+
+
+
+
+static EPOCH bkp_read_off (void)
+{
+ EPOCH e;
+ uint64_t v;
+
+ v = BKP_DR1 & 0xffff;
+ v <<= 16;
+ v |= (BKP_DR2 & 0xffff);
+ v <<= 16;
+ v |= (BKP_DR3 & 0xffff);
+ v <<= 16;
+ v |= (BKP_DR4 & 0xffff);
+
+ e.s = (int64_t) v;
+
+ v = BKP_DR5 & 0xffff;
+ v <<= 16;
+ v |= (BKP_DR6 & 0xffff);
+
+ e.ns = (int64_t) v;
+
+ return e;
+}
+
+static void bkp_write_off (EPOCH e)
+{
+ uint64_t v;
+
+ v = (uint64_t) e.s;
+
+ BKP_DR4 = (uint16_t) (v & 0xffff);
+ v >>= 16;
+ BKP_DR3 = (uint16_t) (v & 0xffff);
+ v >>= 16;
+ BKP_DR2 = (uint16_t) (v & 0xffff);
+ v >>= 16;
+ BKP_DR1 = (uint16_t) (v & 0xffff);
+
+ v = (uint64_t) e.ns;
+
+ BKP_DR6 = (uint16_t) (v & 0xffff);
+ v >>= 16;
+ BKP_DR5 = (uint16_t) (v & 0xffff);
+
+}
+
+
+
+void rtc_isr (void)
+{
+ uint32_t now;
+ static uint32_t then;
+ uint32_t v;
+ static int warm_up = 3;
+
+
+ now = DWT_CYCCNT;
+ compiler_mb();
+ rtc_clear_flag (RTC_SEC);
+
+ v = rtc_get_counter_val();
+
+ TOGGLE (LED1);
+
+ cycle_ref = now;
+
+ if (warm_up) warm_up--;
+ else hz = now - then;
+
+
+ switch (rtc_half) {
+ case RTC_IN_LH:
+ if (! (v & 0x8000000)) break;
+
+ BKP_DR7 = rtc_half = RTC_IN_UH;
+ break;
+
+ case RTC_IN_UH:
+ if (v & 0x8000000) break;
+
+ BKP_DR7 = rtc_half = RTC_IN_LH;
+ rtc_offset.s += 0x100000000ULL;
+ bkp_write_off (rtc_offset);
+ break;
+
+ default:
+ if (v & 0x8000000)
+ BKP_DR7 = rtc_half = RTC_IN_UH;
+ else
+ BKP_DR7 = rtc_half = RTC_IN_LH;
+ }
+
+
+ compiler_mb();
+ rtc_ref = v;
+ rtc_ready = 1;
+
+
+ // printf ("Ctr %d %u %u\r\n", (int) v, (int) (now - then),(unsigned) rtc_offset.s);
+
+ then = now;
+}
+
+
+EPOCH rtc_get (void)
+{
+ EPOCH e, o;
+ uint32_t h, c, r1, r2;
+ uint32_t now = DWT_CYCCNT;
+
+ do {
+ r1 = rtc_ref;
+ compiler_mb();
+ c = cycle_ref;
+ h = hz;
+ o = rtc_offset;
+ compiler_mb();
+ r2 = rtc_ref;
+ } while (r1 != r2);
+
+ now -= c;
+
+ e.ns = now;
+ e.ns *= 1000000000ULL;
+
+ if (h) e.ns /= h;
+ else e.ns /= HZ;
+
+ e.s = r1;
+
+ return time_epoch_add (e, o);
+}
+
+
+void rtc_init (void)
+{
+ rtc_offset = bkp_read_off();
+ rtc_half = BKP_DR7;
+
+#if 1
+ rtc_offset.s = 1637490753;
+ rtc_offset.ns = 498866999;
+ bkp_write_off (rtc_offset);
+#endif
+
+
+ rtc_auto_awake (RCC_LSE, 0x7fff); //32768Hz
+ rtc_interrupt_enable (RTC_SEC);
+ nvic_enable_irq (NVIC_RTC_IRQ);
+
+}
+
+