1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
//! Wrapper for a Display, its GPIO pins, and a timer. use nrf51_hal::hi_res_timer::As16BitTimer; use tiny_led_matrix::{Display, Event as DisplayEvent}; use crate::display::display_port::DisplayPort; use crate::display::matrix::MicrobitFrame; use crate::display::timer::MicrobitDisplayTimer; /// The micro:bit's display, and one timer to drive it. pub struct MicrobitDisplay<T: As16BitTimer> { timer: MicrobitDisplayTimer<T>, port: DisplayPort, display: Display<MicrobitFrame>, } impl<T: As16BitTimer> MicrobitDisplay<T> { /// Takes ownership of the display port and one TIMER, and returns a /// `MicrobitDisplay`. /// /// The `timer` parameter can be any of the three `nrf51::TIMER`*n* /// peripherals. /// /// Initialises the micro:bit hardware to use the display driver. /// /// The display is initially clear. /// /// # Example /// /// ```ignore /// use rmicrobit::prelude::*; /// use rmicrobit::gpio::PinsByKind; /// use rmicrobit::display::{DisplayPort, MicrobitDisplay}; /// let p: nrf51::Peripherals = _; /// let PinsByKind {display_pins, ..} = p.GPIO.split_by_kind(); /// let display_port = DisplayPort::new(display_pins); /// let mut display = MicrobitDisplay::new(display_port, p.TIMER1); /// ``` pub fn new(mut port: DisplayPort, timer: T) -> MicrobitDisplay<T> { let mut timer = MicrobitDisplayTimer::new(timer); tiny_led_matrix::initialise_control(&mut port); tiny_led_matrix::initialise_timer(&mut timer); let display = Display::new(); MicrobitDisplay {timer, port, display} } /// Gives the underlying devices back. /// /// Returns the `DisplayPort` and `nrf51::TIMER`*n* instance. /// /// Turns all the LEDs off and stops the TIMER. pub fn free(mut self) -> (DisplayPort, T) { self.port.blank(); (self.port, self.timer.free()) } /// Updates the LEDs and timer state during a timer interrupt. /// /// Call this in an interrupt handler for the `MicrobitDisplay`'s timer. /// /// See [`Display::handle_event()`] for details. /// /// Returns a [`DisplayEvent`] indicating the reason for the interrupt. /// You can check this if you wish to perform some other action once every /// 6ms. /// /// # Example /// /// In the style of `cortex-m-rtfm` v0.5: /// /// ```ignore /// #[task(binds = TIMER1, priority = 2, resources = [display])] /// fn timer1(cx: timer1::Context) { /// let display_event = cx.resources.display.handle_event(); /// if display_event.is_new_row() { /// ... /// } /// } /// ``` pub fn handle_event(&mut self) -> DisplayEvent { self.display.handle_event(&mut self.timer, &mut self.port) } /// Accepts a new image to be displayed. /// /// The code that calls this method must not be interrupting, or /// interruptable by, [`handle_event()`]. /// /// After calling this, it's safe to modify the frame again (its data is /// copied). /// /// # Example /// /// In the style of `cortex-m-rtfm` v0.5: /// /// ```ignore /// #[task(binds = RTC0, priority = 1, resources = [rtc0, display])] /// fn rtc0(mut cx: rtc0::Context) { /// static mut FRAME: MicrobitFrame = MicrobitFrame::const_default(); /// &cx.resources.rtc0.clear_tick_event(); /// FRAME.set(GreyscaleImage::blank()); /// cx.resources.display.lock(|display| { /// display.set_frame(FRAME); /// }); /// } /// ``` /// /// [`handle_event()`]: MicrobitDisplay::handle_event pub fn set_frame(&mut self, frame: &MicrobitFrame) { self.display.set_frame(frame); } }