From f005c5c17865932dd9af22938439319d8de2be89 Mon Sep 17 00:00:00 2001 From: LongHairedHacker Date: Wed, 14 Apr 2021 20:19:33 +0200 Subject: [PATCH] Clock works with +-10ms Jitter --- Cargo.toml | 4 +- src/application/gps.rs | 32 ++++++++++++ src/application/mod.rs | 21 +++----- src/application/setup.rs | 10 ++++ src/lib.rs | 11 ++--- src/main.rs | 2 - src/time.rs | 104 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 158 insertions(+), 26 deletions(-) create mode 100644 src/application/gps.rs create mode 100644 src/time.rs diff --git a/Cargo.toml b/Cargo.toml index a1b79c2..99dc2cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,9 @@ defmt = "~0.2.0" defmt-rtt = "~0.2.0" panic-probe = { version = "~0.2.0", features = ["print-defmt"] } stm32f1xx-hal = { version = "~0.6.1", features = ["stm32f103", "rt"] } -embedded-hal = {version = "~0.2.3", feature = ["unproven"]} +embedded-hal = {version = "~0.2.3"} +nb = "~1.0.0" +nmea0183 = "~0.2.3" [features] # set logging levels here diff --git a/src/application/gps.rs b/src/application/gps.rs new file mode 100644 index 0000000..ee0c520 --- /dev/null +++ b/src/application/gps.rs @@ -0,0 +1,32 @@ +use nmea0183::{ParseResult, Parser}; +use stm32f1xx_hal::{ + delay::Delay, + prelude::*, + serial::{Config, Serial}, + stm32, +}; + +use crate::application::App; +use crate::time; + +impl App { + pub fn poll_gps(&mut self) -> () { + match self.serial.read() { + Ok(byte) => { + self.board_led.toggle().unwrap(); + if let Some(result) = self.gps_parser.parse_from_byte(byte) { + match result { + Ok(ParseResult::GGA(Some(gga))) => { + time::set(&gga.time); + defmt::info!("Got GGA") + } // Got GGA sentence + Ok(_) => {} // Some other sentences.. + Err(_) => {} // Got parse error + } + } + } + Err(nb::Error::WouldBlock) => {} + Err(nb::Error::Other(_)) => {} + } + } +} diff --git a/src/application/mod.rs b/src/application/mod.rs index 04cb79c..3fd26d5 100644 --- a/src/application/mod.rs +++ b/src/application/mod.rs @@ -10,11 +10,14 @@ use stm32f1xx_hal::{ stm32, }; +mod gps; mod setup; //use crate::exit; pub use setup::setup; +use crate::time; + pub struct App { delay: Delay, board_led: gpioc::PC13>, @@ -25,29 +28,17 @@ pub struct App { gpiob::PB11>, ), >, + gps_parser: Parser, } impl App { pub fn run(mut self) -> ! { defmt::info!("Application Startup!"); - let mut parser = Parser::new(); + let mut last_ts = 0; loop { - match self.serial.read() { - Ok(byte) => { - self.board_led.toggle().unwrap(); - if let Some(result) = parser.parse_from_byte(byte) { - match result { - Ok(ParseResult::GGA(Some(_))) => defmt::info!("Got GGA"), // Got GGA sentence - Ok(_) => {} // Some other sentences.. - Err(_) => {} // Got parse error - } - } - } - Err(nb::Error::WouldBlock) => {} - Err(nb::Error::Other(_)) => {} - } + self.poll_gps(); } //exit(); diff --git a/src/application/setup.rs b/src/application/setup.rs index 0828789..33e300d 100644 --- a/src/application/setup.rs +++ b/src/application/setup.rs @@ -1,11 +1,16 @@ use stm32f1xx_hal::{ delay::Delay, + pac::Interrupt, prelude::*, serial::{Config, Serial}, stm32, + timer::{Event, Timer}, }; +use nmea0183::Parser; + use crate::application::App; +use crate::time; pub fn setup(cp: cortex_m::peripheral::Peripherals, dp: stm32::Peripherals) -> App { // Take ownership over the raw flash and rcc devices and convert them into the corresponding @@ -52,9 +57,14 @@ pub fn setup(cp: cortex_m::peripheral::Peripherals, dp: stm32::Peripherals) -> A &mut rcc.apb1, ); + let gps_parser = Parser::new(); + + time::setup(dp.TIM2, &clocks, &mut rcc.apb1); + App { delay, board_led, serial, + gps_parser, } } diff --git a/src/lib.rs b/src/lib.rs index cc1e69a..2d2b88f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,11 @@ #![no_std] - -use core::sync::atomic::{AtomicUsize, Ordering}; - use defmt_rtt as _; // global logger use panic_probe as _; use stm32f1xx_hal as _; pub mod application; +pub mod time; // same panicking *behavior* as `panic-probe` but doesn't print a panic message // this prevents the panic message being printed *twice* when `defmt::panic` is invoked @@ -16,12 +14,9 @@ fn panic() -> ! { cortex_m::asm::udf() } -static COUNT: AtomicUsize = AtomicUsize::new(0); -defmt::timestamp!("{=usize}", { +defmt::timestamp!("{=u32}", { // NOTE(no-CAS) `timestamps` runs with interrupts disabled - let n = COUNT.load(Ordering::Relaxed); - COUNT.store(n + 1, Ordering::Relaxed); - n + time::get_timestamp() }); /// Terminates the application and makes `probe-run` exit with exit-code = 0 diff --git a/src/main.rs b/src/main.rs index b2733d7..a540bbf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,8 +7,6 @@ use wspr_beacon::application; #[cortex_m_rt::entry] fn main() -> ! { - defmt::info!("Hello, world!"); - // Get access to the core peripherals from the cortex-m crate let cp = cortex_m::Peripherals::take().unwrap(); // Get access to the device specific peripherals from the peripheral access crate diff --git a/src/time.rs b/src/time.rs new file mode 100644 index 0000000..c974f6d --- /dev/null +++ b/src/time.rs @@ -0,0 +1,104 @@ +use core::cell::RefCell; +use core::ops::DerefMut; +use cortex_m::interrupt::{free, Mutex}; +use stm32f1xx_hal::{ + delay::Delay, + pac::interrupt, + pac::{Interrupt, TIM2}, + prelude::*, + rcc::{Clocks, APB1}, + serial::{Config, Serial}, + stm32, + timer::{CountDownTimer, Event, Timer}, +}; + +use nmea0183::datetime::Time; + +static TIME: Mutex> = Mutex::new(RefCell::new(Time { + hours: 0, + minutes: 0, + seconds: 0.0, +})); + +static TIMER_TIM2: Mutex>>> = Mutex::new(RefCell::new(None)); + +pub fn setup(tim2: TIM2, clocks: &Clocks, apb1: &mut APB1) { + let mut timer = Timer::tim2(tim2, clocks, apb1).start_count_down(1.khz()); + // Generate an interrupt when the timer expires + timer.listen(Event::Update); + // Move the timer into our global storage + cortex_m::interrupt::free(|cs| *TIMER_TIM2.borrow(cs).borrow_mut() = Some(timer)); + + unsafe { + cortex_m::peripheral::NVIC::unmask(Interrupt::TIM2); + } +} + +#[interrupt] +fn TIM2() { + free(|cs| { + if let Some(ref mut tim2) = TIMER_TIM2.borrow(cs).borrow_mut().deref_mut() { + tim2.clear_update_interrupt_flag(); + } + + let mut time = TIME.borrow(cs).borrow_mut(); + time.seconds += 0.001; + + if time.seconds >= 60.0 { + time.seconds -= 60.0; + time.minutes += 1; + } + if time.minutes == 60 { + time.minutes = 0; + time.hours += 1; + } + if time.hours == 24 { + time.hours = 0; + } + }); +} + +pub fn get() -> Time { + let mut res = Time { + hours: 0, + minutes: 0, + seconds: 0.0, + }; + + free(|cs| { + let time = TIME.borrow(cs).borrow(); + res.seconds = time.seconds; + res.minutes = time.minutes; + res.hours = time.hours; + }); + + return res; +} + +pub fn set(new_time: &Time) -> () { + free(|cs| { + let mut time = TIME.borrow(cs).borrow_mut(); + let sec_delta = time.seconds - new_time.seconds; + if time.hours != new_time.hours + || time.minutes != new_time.minutes + || sec_delta > 0.05 + || sec_delta < -0.05 + { + time.seconds = new_time.seconds; + time.minutes = new_time.minutes; + time.hours = new_time.hours; + } + }); +} + +pub fn get_timestamp() -> u32 { + let mut res = 0; + free(|cs| { + let time = TIME.borrow(cs).borrow(); + res = (time.seconds * 1000.0) as u32; + res += (time.minutes as u32) * 60 * 1000; + res += (time.hours as u32) * 60 * 60 * 1000; + }); + + return res; +}