aboutsummaryrefslogtreecommitdiffstats
path: root/src/blink.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/blink.rs')
-rw-r--r--src/blink.rs62
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 };
+}