diff options
Diffstat (limited to 'src/blink.rs')
-rw-r--r-- | src/blink.rs | 62 |
1 files changed, 35 insertions, 27 deletions
diff --git a/src/blink.rs b/src/blink.rs index bb53845..ba3d6ca 100644 --- a/src/blink.rs +++ b/src/blink.rs @@ -1,59 +1,67 @@ -use gd32vf103xx_hal::prelude::_embedded_hal_timer_CountDown; - use core::convert::Infallible; use gd32vf103xx_hal::{ eclic::{self, EclicExt}, pac::{self, Interrupt}, + prelude::*, time::Hertz, timer::{Event, Timer}, }; use nb; +use riscv::interrupt; use crate::led::LED; -enum State { - WaitForTimer, - ToggleLED, -} - pub struct Task { timer: Timer<pac::TIMER6>, frequency: Hertz, led: LED, - state: State, } +static mut TIMER_FIRED: bool = false; + impl Task { pub fn new(mut timer: Timer<pac::TIMER6>, frequency: Hertz, led: LED) -> Self { pac::ECLIC::setup(Interrupt::TIMER6, eclic::TriggerType::RisingEdge, eclic::Level::L0, eclic::Priority::P3); unsafe { pac::ECLIC::unmask(Interrupt::TIMER6); } - if !pac::ECLIC::is_enabled(Interrupt::TIMER6) { - panic!("timer6 interrupt not enabled"); - } + assert!(pac::ECLIC::is_enabled(Interrupt::TIMER6)); timer.listen(Event::Update); - Self { timer, frequency, led, state: State::ToggleLED } + Self { timer, frequency, led } } pub fn poll(&mut self) -> nb::Result<(), Infallible> { - match self.state { - State::WaitForTimer => { - if let Ok(_) = self.timer.wait() { - self.state = State::ToggleLED; - // self.timer.unlisten(Event::Update); - Ok(()) - } else { - Err(nb::Error::WouldBlock) - } - }, - State::ToggleLED => { + interrupt::free(|_cs| { + if unsafe { TIMER_FIRED } { + unsafe { TIMER_FIRED = false }; self.led.toggle(); self.timer.start(self.frequency); - self.state = State::WaitForTimer; - // self.timer.listen(Event::Update); - Err(nb::Error::WouldBlock) } - } + }); + Err(nb::Error::WouldBlock) } } + +/* + * because i'm using ‘wfi’ to sleep as much as possible, i need to + * actually schedule the timer to fire an interrupt. that, in turn, + * requires a handler. + * + * why? because, for efficiency reasons, ‘_irq_handler’ uses the + * bumblebee core ‘jalmnxti’ csr, and the default entry in the irq + * vector is ‘0’. so the core jumps to 0, which is the ‘_start’ entry + * point. but it does this *from the interrupt*, which masks the + * interrupt (because it's currently being serviced), so any + * subsequent firings are never triggered, nor any interrupts at lower + * priority. + * + * so it looks like the core resets every other time it's + * started. adding a real isr avoids these problems. + */ +#[export_name="TIMER6"] +fn timer6() { + // logln!("I timer6 I"); + let regs = unsafe { &*pac::TIMER6::ptr() }; + regs.intf.write(|w| w.upif().clear_bit()); + unsafe { TIMER_FIRED = true }; +} |