Skip to content

Commit 8dae48e

Browse files
authored
Merge pull request #34 from robyoung/allow-noncontiguous-pins-in-display
Allow noncontiguous pins in display
2 parents d97d7db + 056fc90 commit 8dae48e

File tree

9 files changed

+143
-113
lines changed

9 files changed

+143
-113
lines changed

examples/led_blocking.rs

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@ use panic_halt as _;
66

77
use cortex_m_rt::entry;
88

9-
use microbit::hal::{
10-
gpio::{p0::Parts as P0Parts, Level},
11-
prelude::*,
12-
Timer,
9+
use microbit::{
10+
display_pins,
11+
hal::{gpio::p0::Parts as P0Parts, prelude::*, Timer},
1312
};
1413

1514
use microbit::led;
@@ -21,20 +20,7 @@ fn main() -> ! {
2120
let p0parts = P0Parts::new(p.GPIO);
2221

2322
// Display
24-
let pins = led::Pins {
25-
row1: p0parts.p0_13.into_push_pull_output(Level::Low),
26-
row2: p0parts.p0_14.into_push_pull_output(Level::Low),
27-
row3: p0parts.p0_15.into_push_pull_output(Level::Low),
28-
col1: p0parts.p0_04.into_push_pull_output(Level::Low),
29-
col2: p0parts.p0_05.into_push_pull_output(Level::Low),
30-
col3: p0parts.p0_06.into_push_pull_output(Level::Low),
31-
col4: p0parts.p0_07.into_push_pull_output(Level::Low),
32-
col5: p0parts.p0_08.into_push_pull_output(Level::Low),
33-
col6: p0parts.p0_09.into_push_pull_output(Level::Low),
34-
col7: p0parts.p0_10.into_push_pull_output(Level::Low),
35-
col8: p0parts.p0_11.into_push_pull_output(Level::Low),
36-
col9: p0parts.p0_12.into_push_pull_output(Level::Low),
37-
};
23+
let pins = display_pins!(p0parts);
3824
let mut leds = led::Display::new(pins);
3925

4026
#[allow(non_snake_case)]

examples/led_nonblocking.rs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,13 @@ use cortex_m_rt::entry;
1111

1212
use microbit::{
1313
display::{self, image::GreyscaleImage, Display, Frame, MicrobitDisplayTimer, MicrobitFrame},
14-
hal::rtc::{Rtc, RtcInterrupt},
15-
pac::{self, interrupt, GPIO, RTC0, TIMER1},
14+
display_pins,
15+
gpio::DisplayPins,
16+
hal::{
17+
gpio::p0::Parts as P0Parts,
18+
rtc::{Rtc, RtcInterrupt},
19+
},
20+
pac::{self, interrupt, RTC0, TIMER1},
1621
};
1722

1823
fn heart_image(inner_brightness: u8) -> GreyscaleImage {
@@ -29,7 +34,7 @@ fn heart_image(inner_brightness: u8) -> GreyscaleImage {
2934
// We use TIMER1 to drive the display, and RTC0 to update the animation.
3035
// We set the TIMER1 interrupt to a higher priority than RTC0.
3136

32-
static GPIO: Mutex<RefCell<Option<GPIO>>> = Mutex::new(RefCell::new(None));
37+
static LED_PINS: Mutex<RefCell<Option<DisplayPins>>> = Mutex::new(RefCell::new(None));
3338
static ANIM_TIMER: Mutex<RefCell<Option<Rtc<RTC0>>>> = Mutex::new(RefCell::new(None));
3439
static DISPLAY_TIMER: Mutex<RefCell<Option<MicrobitDisplayTimer<TIMER1>>>> =
3540
Mutex::new(RefCell::new(None));
@@ -52,9 +57,11 @@ fn main() -> ! {
5257
rtc0.enable_counter();
5358

5459
let mut timer = MicrobitDisplayTimer::new(p.TIMER1);
55-
let mut gpio = p.GPIO;
56-
display::initialise_display(&mut timer, &mut gpio);
57-
*GPIO.borrow(cs).borrow_mut() = Some(gpio);
60+
61+
let p0parts = P0Parts::new(p.GPIO);
62+
let mut pins = display_pins!(p0parts);
63+
display::initialise_display(&mut timer, &mut pins);
64+
*LED_PINS.borrow(cs).borrow_mut() = Some(pins);
5865
*ANIM_TIMER.borrow(cs).borrow_mut() = Some(rtc0);
5966
*DISPLAY_TIMER.borrow(cs).borrow_mut() = Some(timer);
6067
*DISPLAY.borrow(cs).borrow_mut() = Some(Display::new());
@@ -78,9 +85,9 @@ fn main() -> ! {
7885
fn TIMER1() {
7986
cortex_m::interrupt::free(|cs| {
8087
if let Some(timer) = DISPLAY_TIMER.borrow(cs).borrow_mut().as_mut() {
81-
if let Some(gpio) = GPIO.borrow(cs).borrow_mut().as_mut() {
88+
if let Some(pins) = LED_PINS.borrow(cs).borrow_mut().as_mut() {
8289
if let Some(d) = DISPLAY.borrow(cs).borrow_mut().as_mut() {
83-
display::handle_display_event(d, timer, gpio);
90+
display::handle_display_event(d, timer, pins);
8491
}
8592
}
8693
}

examples/led_rtfm.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@ use panic_halt as _;
1111

1212
use microbit::{
1313
display::{self, image::GreyscaleImage, Display, Frame, MicrobitDisplayTimer, MicrobitFrame},
14-
hal::rtc::{Rtc, RtcInterrupt},
14+
display_pins,
15+
gpio::DisplayPins,
16+
hal::{
17+
gpio::p0::Parts as P0Parts,
18+
rtc::{Rtc, RtcInterrupt},
19+
},
1520
pac,
1621
};
1722
use rtic::app;
@@ -30,15 +35,15 @@ fn heart_image(inner_brightness: u8) -> GreyscaleImage {
3035
#[app(device = microbit::pac, peripherals = true)]
3136
const APP: () = {
3237
struct Resources {
33-
gpio: pac::GPIO,
38+
display_pins: DisplayPins,
3439
display_timer: MicrobitDisplayTimer<pac::TIMER1>,
3540
anim_timer: Rtc<pac::RTC0>,
3641
display: Display<MicrobitFrame>,
3742
}
3843

3944
#[init]
4045
fn init(cx: init::Context) -> init::LateResources {
41-
let mut p: pac::Peripherals = cx.device;
46+
let p: pac::Peripherals = cx.device;
4247

4348
// Starting the low-frequency clock (needed for RTC to work)
4449
p.CLOCK.tasks_lfclkstart.write(|w| unsafe { w.bits(1) });
@@ -53,23 +58,27 @@ const APP: () = {
5358
rtc0.enable_counter();
5459

5560
let mut timer = MicrobitDisplayTimer::new(p.TIMER1);
56-
display::initialise_display(&mut timer, &mut p.GPIO);
61+
62+
let p0parts = P0Parts::new(p.GPIO);
63+
let mut pins = display_pins!(p0parts);
64+
65+
display::initialise_display(&mut timer, &mut pins);
5766

5867
init::LateResources {
59-
gpio: p.GPIO,
68+
display_pins: pins,
6069
display_timer: timer,
6170
anim_timer: rtc0,
6271
display: Display::new(),
6372
}
6473
}
6574

6675
#[task(binds = TIMER1, priority = 2,
67-
resources = [display_timer, gpio, display])]
76+
resources = [display_timer, display_pins, display])]
6877
fn timer1(mut cx: timer1::Context) {
6978
display::handle_display_event(
7079
&mut cx.resources.display,
7180
cx.resources.display_timer,
72-
cx.resources.gpio,
81+
cx.resources.display_pins,
7382
);
7483
}
7584

src/display/control.rs

Lines changed: 49 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,39 @@
77
use crate::pac;
88
use tiny_led_matrix::DisplayControl;
99

10-
const fn bit_range(lo: usize, count: usize) -> u32 {
11-
((1 << count) - 1) << lo
10+
const fn pin_bits(pins: &[usize]) -> u32 {
11+
let mut i: usize = 0;
12+
let mut bits: u32 = 0;
13+
while i < pins.len() {
14+
bits |= 1 << pins[i];
15+
i += 1;
16+
}
17+
bits
1218
}
1319

1420
pub(crate) const MATRIX_COLS: usize = 9;
15-
const FIRST_COL_PIN: usize = 4;
16-
const LAST_COL_PIN: usize = FIRST_COL_PIN + MATRIX_COLS - 1;
17-
const COL_BITS: u32 = bit_range(FIRST_COL_PIN, MATRIX_COLS);
21+
const COLS: [usize; MATRIX_COLS] = [4, 5, 6, 7, 8, 9, 10, 11, 12];
22+
const COL_BITS: u32 = pin_bits(&COLS);
1823

1924
pub(crate) const MATRIX_ROWS: usize = 3;
20-
const FIRST_ROW_PIN: usize = 13;
21-
const LAST_ROW_PIN: usize = FIRST_ROW_PIN + MATRIX_ROWS - 1;
22-
const ROW_BITS: u32 = bit_range(FIRST_ROW_PIN, MATRIX_ROWS);
25+
const ROWS: [usize; MATRIX_ROWS] = [13, 14, 15];
26+
const ROW_BITS: u32 = pin_bits(&ROWS);
2327

2428
/// Wrapper for `nrf51::GPIO` for passing to the display code.
2529
///
2630
/// This implements the `DisplayControl` trait.
2731
///
2832
/// [`DisplayControl`]: tiny_led_matrix::DisplayControl
29-
pub(crate) struct MicrobitGpio<'a>(pub &'a pac::GPIO);
33+
pub(crate) struct MicrobitGpio;
3034

31-
/// Returns the GPIO pin numbers corresponding to the columns in a ColumnSet.
32-
fn column_pins(cols: u32) -> u32 {
33-
cols << FIRST_COL_PIN
35+
/// Returns the GPIO pin numbers corresponding to the columns in a Columnt et.
36+
fn column_pins(mut cols: u32) -> u32 {
37+
let mut result = 0u32;
38+
for pin in COLS.iter() {
39+
result |= (cols & 1) << pin;
40+
cols >>= 1;
41+
}
42+
result
3443
}
3544

3645
/// Implementation of [`DisplayControl`] for the micro:bit's GPIO peripheral.
@@ -41,37 +50,42 @@ fn column_pins(cols: u32) -> u32 {
4150
/// state it would have after system reset.
4251
///
4352
/// [`DisplayControl`]: tiny_led_matrix::DisplayControl
44-
impl DisplayControl for MicrobitGpio<'_> {
53+
impl DisplayControl for MicrobitGpio {
4554
fn initialise_for_display(&mut self) {
46-
let gpio = &self.0;
47-
for ii in FIRST_COL_PIN..=LAST_COL_PIN {
48-
gpio.pin_cnf[ii].write(|w| w.dir().output());
49-
}
50-
for ii in FIRST_ROW_PIN..=LAST_ROW_PIN {
51-
gpio.pin_cnf[ii].write(|w| w.dir().output());
52-
}
55+
unsafe {
56+
let gpio = &*pac::GPIO::ptr();
57+
for ii in COLS.iter() {
58+
gpio.pin_cnf[*ii].write(|w| w.dir().output());
59+
}
60+
for ii in ROWS.iter() {
61+
gpio.pin_cnf[*ii].write(|w| w.dir().output());
62+
}
5363

54-
// Set all cols high.
55-
gpio.outset
56-
.write(|w| unsafe { w.bits((FIRST_COL_PIN..=LAST_COL_PIN).map(|pin| 1 << pin).sum()) });
64+
// Set all cols high.
65+
gpio.outset
66+
.write(|w| w.bits(COLS.iter().map(|pin| 1 << pin).sum()));
67+
}
5768
}
5869

5970
fn display_row_leds(&mut self, row: usize, cols: u32) {
60-
let gpio = &self.0;
61-
// To light an LED, we set the row bit and clear the col bit.
62-
let rows_to_set = 1 << (FIRST_ROW_PIN + row);
63-
let rows_to_clear = ROW_BITS ^ rows_to_set;
64-
let cols_to_clear = column_pins(cols);
65-
let cols_to_set = COL_BITS ^ cols_to_clear;
71+
unsafe {
72+
let gpio = &*pac::GPIO::ptr();
73+
// To light an LED, we set the row bit and clear the col bit.
74+
let rows_to_set = 1 << ROWS[row];
75+
let rows_to_clear = ROW_BITS ^ rows_to_set;
76+
77+
let cols_to_clear = column_pins(cols);
78+
let cols_to_set = COL_BITS ^ cols_to_clear;
6679

67-
gpio.outset
68-
.write(|w| unsafe { w.bits(rows_to_set | cols_to_set) });
69-
gpio.outclr
70-
.write(|w| unsafe { w.bits(rows_to_clear | cols_to_clear) });
80+
gpio.outset.write(|w| w.bits(rows_to_set | cols_to_set));
81+
gpio.outclr.write(|w| w.bits(rows_to_clear | cols_to_clear));
82+
}
7183
}
7284

7385
fn light_current_row_leds(&mut self, cols: u32) {
74-
let gpio = &self.0;
75-
gpio.outclr.write(|w| unsafe { w.bits(column_pins(cols)) });
86+
unsafe {
87+
let gpio = &*crate::pac::GPIO::ptr();
88+
gpio.outclr.write(|w| w.bits(column_pins(cols)));
89+
}
7690
}
7791
}

src/display/image.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ impl GreyscaleImage {
2929
GreyscaleImage(*data)
3030
}
3131

32+
/// Construct a GreyscaleImage with all LEDs turned off.
3233
pub const fn blank() -> GreyscaleImage {
3334
GreyscaleImage([[0; 5]; 5])
3435
}

src/display/mod.rs

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@
4747
//! The [`Render`] trait defines the interface that an image-like type needs
4848
//! to provide in order to be displayed.
4949
//!
50-
//! It contains a single function: [`brightness_at(x,
51-
//! y)`][display::Render::brightness_at], returning a brightness level.
50+
//! It contains a single function: [`brightness_at(x, y)`](Render::brightness_at),
51+
//! returning a brightness level.
5252
//!
5353
//! The [`image`] submodule provides two static image types implementing
5454
//! `Render`:
@@ -77,7 +77,7 @@
7777
//!
7878
//! # Timer integration
7979
//!
80-
//! The `Display` expects to control a single timer. It can use the
80+
//! The [`Display`] expects to control a single timer. It can use the
8181
//! micro:bit's `TIMER0`, `TIMER1`, or `TIMER2`.
8282
//!
8383
//! This uses a 6ms period to light each of the three internal LED rows, so
@@ -100,14 +100,14 @@
100100
//! When your program starts:
101101
//! * create a [`MicrobitDisplayTimer`] struct, passing the timer you chose to
102102
//! [`MicrobitDisplayTimer::new()`]
103-
//! * call [`initialise_display()`], passing it the `MicrobitDisplayTimer` and
104-
//! the gpio peripheral
103+
//! * call [`initialise_display()`], passing it the `MicrobitDisplayTimer` and the
104+
//! [`crate::led::Pins`]
105105
//! * create a [`Display`] struct (a `Display<MicrobitFrame>`).
106106
//!
107107
//! In an interrupt handler for the timer, call [`handle_display_event()`].
108108
//!
109109
//! To change what's displayed: create a [`MicrobitFrame`] instance, use
110-
//! [`.set()`](`display::Frame::set()`) to put an image (something implementing
110+
//! [`.set()`](`Frame::set()`) to put an image (something implementing
111111
//! [`Render`]) in it, then call [`Display::set_frame()`]. Note you'll have to
112112
//! `use microbit::display::Frame` to make `set()` available.
113113
//!
@@ -121,22 +121,6 @@
121121
//!
122122
//! [dal]: https://lancaster-university.github.io/microbit-docs/
123123
//! [micropython]: https://microbit-micropython.readthedocs.io/
124-
//!
125-
//! [`BitImage`]: display::image::BitImage
126-
//! [`Display`]: display::Display
127-
//! [`Display::set_frame()`]: display::Display::set_frame
128-
//! [`Frame`]: display::Frame
129-
//! [`Matrix`]: display::Matrix
130-
//! [`MicrobitFrame`]: display::MicrobitFrame
131-
//! [`MicrobitDisplayTimer`]: display::MicrobitDisplayTimer
132-
//! [`MicrobitDisplayTimer::new()`]: display::MicrobitDisplayTimer::new
133-
//! [`Render`]: display::Render
134-
//! [`image`]: display::image
135-
//! [`handle_display_event()`]: display::handle_display_event
136-
//! [`initialise_display()`]: display::initialise_display
137-
//! [`DisplayTimer`]: tiny_led_matrix::DisplayTimer
138-
//! [`GreyscaleImage`]: display::image::GreyscaleImage
139-
//!
140124
141125
#[doc(no_inline)]
142126
pub use tiny_led_matrix::{Display, Frame, Render, MAX_BRIGHTNESS};
@@ -150,7 +134,7 @@ pub mod image;
150134
pub use matrix::MicrobitFrame;
151135
pub use timer::MicrobitDisplayTimer;
152136

153-
use crate::hal::timer::Instance;
137+
use crate::{gpio::DisplayPins, hal::timer::Instance};
154138

155139
use control::MicrobitGpio;
156140

@@ -167,9 +151,9 @@ use control::MicrobitGpio;
167151
/// ```
168152
pub fn initialise_display<T: Instance>(
169153
timer: &mut MicrobitDisplayTimer<T>,
170-
gpio: &mut crate::pac::GPIO,
154+
_pins: &mut DisplayPins,
171155
) {
172-
tiny_led_matrix::initialise_control(&mut MicrobitGpio(gpio));
156+
tiny_led_matrix::initialise_control(&mut MicrobitGpio {});
173157
tiny_led_matrix::initialise_timer(timer);
174158
}
175159

@@ -202,7 +186,7 @@ pub fn initialise_display<T: Instance>(
202186
pub fn handle_display_event<T: Instance>(
203187
display: &mut Display<MicrobitFrame>,
204188
timer: &mut MicrobitDisplayTimer<T>,
205-
gpio: &mut crate::pac::GPIO,
189+
_pins: &mut DisplayPins,
206190
) {
207-
display.handle_event(timer, &mut MicrobitGpio(gpio));
191+
display.handle_event(timer, &mut MicrobitGpio {});
208192
}

0 commit comments

Comments
 (0)