aboutsummaryrefslogtreecommitdiffstats
path: root/src-riscv/blink.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src-riscv/blink.rs')
-rw-r--r--src-riscv/blink.rs70
1 files changed, 70 insertions, 0 deletions
diff --git a/src-riscv/blink.rs b/src-riscv/blink.rs
new file mode 100644
index 0000000..967cde6
--- /dev/null
+++ b/src-riscv/blink.rs
@@ -0,0 +1,70 @@
+use core::convert::Infallible;
+
+// use gd32vf103xx_hal as hal;
+use stm32f30x_hal as hal;
+
+use hal::{
+ //eclic::{self, EclicExt},
+ pac::{self, Interrupt},
+ prelude::*,
+ time::Hertz,
+ timer::{Event, Timer},
+};
+use nb;
+use riscv::interrupt;
+
+use crate::led::LED;
+
+pub struct Task {
+ timer: Timer<pac::TIMER6>,
+ frequency: Hertz,
+ led: LED,
+}
+
+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); }
+ // assert!(pac::ECLIC::is_enabled(Interrupt::TIMER6));
+ timer.listen(Event::Update);
+
+ Self { timer, frequency, led }
+ }
+
+ pub fn poll(&mut self) -> nb::Result<(), Infallible> {
+ interrupt::free(|_cs| {
+ if unsafe { TIMER_FIRED } {
+ unsafe { TIMER_FIRED = false };
+ self.led.toggle();
+ self.timer.start(self.frequency);
+ }
+ });
+ 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 };
+}