Skip to content

Commit 5e1e7af

Browse files
bors[bot]robyoung
andauthored
Merge #55
55: Refactor LED display modules r=therealprof a=robyoung Addresses #52 This change is pretty bold. I'm not sure if it's the right direction to go. Rename and refactor the two LED display modules so that their APIs are closer to each other and hopefully more familiar to people coming from the micropython APIs. *Blocking API* ```rust let mut display = Display::new(pins); loop { display.show(&mut timer, heart, 1000); display.clear(); timer.delay_ms(250u32); } ``` *Non-blocking API* ```rust let mut display = Display::new(timer, pins); display.initialise(); loop { display.show(heart); timer2.delay_ms(1000u32); display.clear(); timer2.delay_ms(500u32); } // in a timer interrupt display.handle_display_event(); ``` ## Rename the modules Move the two modules under a common `display` as `blocking` and `nonblocking` and rename all led examples to display. I went with display over led as this is the name used in the micropython API. I went with `blocking` and `nonblocking` under `display` rather than `blocking` and `nonblocking` at the top level like in `embedded-hal` because the non-blocking approach is quite unique to the display driver whereas in `embedded-hal` it's a standard non-blocking approach across the board. ## Introduce simplified non-blocking API Introduce a struct providing a simplified non-blocking API that is similar to the blocking API as an easier stepping stone towards the tiny-led-matrix. The simplified API does come with some performance costs. Most notably the fact that the frame setting is done inside the `show` method and therefore inside the critical section. This caused slightly more flickering in debug but had no visible effect in release mode. Throughout the docs I have pointed to the instructions and example for using tiny-led-matrix directly if performance becomes a concern. Co-authored-by: Rob Young <[email protected]>
2 parents a6dac6e + 17f3aec commit 5e1e7af

File tree

17 files changed

+394
-396
lines changed

17 files changed

+394
-396
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10-
(no changes)
10+
- Rearrange LED display modules under the same root module and change their
11+
APIs to be more aligned with each other.
1112

1213
## [0.10.1] - 2021-05-25
1314

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ run one of the commands below.
3939

4040
*For micro:bit V1*
4141
```bash
42-
> cargo run --release --manifest-path ./examples/led-blocking/Cargo.toml --features v1 --target thumbv6m-none-eabi
42+
> cargo run --release --manifest-path ./examples/display-blocking/Cargo.toml --features v1 --target thumbv6m-none-eabi
4343
```
4444

4545
*For micro:bit V2*
4646
```bash
47-
> cargo run --release --manifest-path ./examples/led-blocking/Cargo.toml --features v2 --target thumbv7em-none-eabihf
47+
> cargo run --release --manifest-path ./examples/display-blocking/Cargo.toml --features v2 --target thumbv7em-none-eabihf
4848
```
4949

5050
You should see a lot of build output, the orange LED on the back of the micro:bit should flash quickly and

examples/led-blocking/Cargo.toml renamed to examples/display-blocking/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[package]
2-
name = "led-blocking"
2+
name = "display-blocking"
33
version = "0.1.0"
44
edition = "2018"
55

examples/led-blocking/src/main.rs renamed to examples/display-blocking/src/main.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use microbit::{
1414
#[cfg(feature = "v2")]
1515
use microbit::hal::gpio::p1::Parts as P1Parts;
1616

17-
use microbit::led;
17+
use microbit::display::blocking::Display;
1818

1919
#[entry]
2020
fn main() -> ! {
@@ -36,7 +36,7 @@ fn main() -> ! {
3636
};
3737

3838
// Display
39-
let mut leds = led::Display::new(pins);
39+
let mut display = Display::new(pins);
4040

4141
#[allow(non_snake_case)]
4242
let letter_I = [
@@ -91,13 +91,13 @@ fn main() -> ! {
9191
[0, 0, 1, 0, 0],
9292
];
9393
loop {
94-
leds.display(&mut timer, letter_I, 1000);
95-
leds.display(&mut timer, heart, 1000);
96-
leds.display(&mut timer, letter_R, 1000);
97-
leds.display(&mut timer, letter_u, 1000);
98-
leds.display(&mut timer, letter_s, 1000);
99-
leds.display(&mut timer, letter_t, 1000);
100-
leds.clear();
94+
display.show(&mut timer, letter_I, 1000);
95+
display.show(&mut timer, heart, 1000);
96+
display.show(&mut timer, letter_R, 1000);
97+
display.show(&mut timer, letter_u, 1000);
98+
display.show(&mut timer, letter_s, 1000);
99+
display.show(&mut timer, letter_t, 1000);
100+
display.clear();
101101
timer.delay_ms(250_u32);
102102
}
103103
}

examples/led-nonblocking/Cargo.toml renamed to examples/display-nonblocking/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[package]
2-
name = "led-nonblocking"
2+
name = "display-nonblocking"
33
version = "0.1.0"
44
edition = "2018"
55

examples/led-nonblocking/src/main.rs renamed to examples/display-nonblocking/src/main.rs

Lines changed: 30 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@ use cortex_m::peripheral::Peripherals;
1010
use cortex_m_rt::entry;
1111

1212
use microbit::{
13-
display::{self, image::GreyscaleImage, Display, Frame, MicrobitDisplayTimer, MicrobitFrame},
13+
display::nonblocking::{Display, GreyscaleImage},
1414
display_pins,
15-
gpio::DisplayPins,
1615
hal::{
1716
gpio::p0::Parts as P0Parts,
1817
rtc::{Rtc, RtcInterrupt},
@@ -37,11 +36,8 @@ fn heart_image(inner_brightness: u8) -> GreyscaleImage {
3736
// We use TIMER1 to drive the display, and RTC0 to update the animation.
3837
// We set the TIMER1 interrupt to a higher priority than RTC0.
3938

40-
static LED_PINS: Mutex<RefCell<Option<DisplayPins>>> = Mutex::new(RefCell::new(None));
39+
static DISPLAY: Mutex<RefCell<Option<Display<TIMER1>>>> = Mutex::new(RefCell::new(None));
4140
static ANIM_TIMER: Mutex<RefCell<Option<Rtc<RTC0>>>> = Mutex::new(RefCell::new(None));
42-
static DISPLAY_TIMER: Mutex<RefCell<Option<MicrobitDisplayTimer<TIMER1>>>> =
43-
Mutex::new(RefCell::new(None));
44-
static DISPLAY: Mutex<RefCell<Option<Display<MicrobitFrame>>>> = Mutex::new(RefCell::new(None));
4541

4642
#[entry]
4743
fn main() -> ! {
@@ -51,35 +47,32 @@ fn main() -> ! {
5147
while p.CLOCK.events_lfclkstarted.read().bits() == 0 {}
5248
p.CLOCK.events_lfclkstarted.reset();
5349

50+
// RTC at 16Hz (32_768 / (2047 + 1))
51+
// 62.5ms period
52+
let mut rtc0 = Rtc::new(p.RTC0, 2047).unwrap();
53+
rtc0.enable_event(RtcInterrupt::Tick);
54+
rtc0.enable_interrupt(RtcInterrupt::Tick, None);
55+
rtc0.enable_counter();
56+
57+
// Set up pins
58+
#[cfg(feature = "v1")]
59+
let pins = {
60+
let p0parts = P0Parts::new(p.GPIO);
61+
display_pins!(p0parts)
62+
};
63+
64+
#[cfg(feature = "v2")]
65+
let pins = {
66+
let p0parts = P0Parts::new(p.P0);
67+
let p1parts = P1Parts::new(p.P1);
68+
display_pins!(p0parts, p1parts)
69+
};
70+
71+
let display = Display::new(p.TIMER1, pins);
72+
5473
cortex_m::interrupt::free(move |cs| {
55-
// RTC at 16Hz (32_768 / (2047 + 1))
56-
// 62.5ms period
57-
let mut rtc0 = Rtc::new(p.RTC0, 2047).unwrap();
58-
rtc0.enable_event(RtcInterrupt::Tick);
59-
rtc0.enable_interrupt(RtcInterrupt::Tick, None);
60-
rtc0.enable_counter();
61-
62-
let mut timer = MicrobitDisplayTimer::new(p.TIMER1);
63-
64-
// Set up pins
65-
#[cfg(feature = "v1")]
66-
let mut pins = {
67-
let p0parts = P0Parts::new(p.GPIO);
68-
display_pins!(p0parts)
69-
};
70-
71-
#[cfg(feature = "v2")]
72-
let mut pins = {
73-
let p0parts = P0Parts::new(p.P0);
74-
let p1parts = P1Parts::new(p.P1);
75-
display_pins!(p0parts, p1parts)
76-
};
77-
78-
display::initialise_display(&mut timer, &mut pins);
79-
*LED_PINS.borrow(cs).borrow_mut() = Some(pins);
74+
*DISPLAY.borrow(cs).borrow_mut() = Some(display);
8075
*ANIM_TIMER.borrow(cs).borrow_mut() = Some(rtc0);
81-
*DISPLAY_TIMER.borrow(cs).borrow_mut() = Some(timer);
82-
*DISPLAY.borrow(cs).borrow_mut() = Some(Display::new());
8376
});
8477
if let Some(mut cp) = Peripherals::take() {
8578
unsafe {
@@ -99,20 +92,15 @@ fn main() -> ! {
9992
#[interrupt]
10093
fn TIMER1() {
10194
cortex_m::interrupt::free(|cs| {
102-
if let Some(timer) = DISPLAY_TIMER.borrow(cs).borrow_mut().as_mut() {
103-
if let Some(pins) = LED_PINS.borrow(cs).borrow_mut().as_mut() {
104-
if let Some(d) = DISPLAY.borrow(cs).borrow_mut().as_mut() {
105-
display::handle_display_event(d, timer, pins);
106-
}
107-
}
95+
if let Some(display) = DISPLAY.borrow(cs).borrow_mut().as_mut() {
96+
display.handle_display_event();
10897
}
10998
});
11099
}
111100

112101
#[interrupt]
113102
unsafe fn RTC0() {
114103
static mut STEP: u8 = 0;
115-
static mut FRAME: MicrobitFrame = MicrobitFrame::const_default();
116104

117105
cortex_m::interrupt::free(|cs| {
118106
if let Some(rtc) = ANIM_TIMER.borrow(cs).borrow_mut().as_mut() {
@@ -126,11 +114,9 @@ unsafe fn RTC0() {
126114
_ => unreachable!(),
127115
};
128116

129-
FRAME.set(&heart_image(inner_brightness));
130-
131117
cortex_m::interrupt::free(|cs| {
132-
if let Some(d) = DISPLAY.borrow(cs).borrow_mut().as_mut() {
133-
d.set_frame(&FRAME);
118+
if let Some(display) = DISPLAY.borrow(cs).borrow_mut().as_mut() {
119+
display.show(&heart_image(inner_brightness));
134120
}
135121
});
136122

examples/led-rtic/Cargo.toml renamed to examples/display-rtic/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[package]
2-
name = "led-rtic"
2+
name = "display-rtic"
33
version = "0.1.0"
44
edition = "2018"
55

examples/led-rtic/src/main.rs renamed to examples/display-rtic/src/main.rs

Lines changed: 12 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@ use defmt_rtt as _;
1111
use panic_halt as _;
1212

1313
use microbit::{
14-
display::{self, image::GreyscaleImage, Display, Frame, MicrobitDisplayTimer, MicrobitFrame},
14+
display::nonblocking::{Display, GreyscaleImage},
1515
display_pins,
16-
gpio::DisplayPins,
1716
hal::{
1817
gpio::p0::Parts as P0Parts,
1918
rtc::{Rtc, RtcInterrupt},
@@ -40,10 +39,8 @@ fn heart_image(inner_brightness: u8) -> GreyscaleImage {
4039
#[app(device = microbit::pac, peripherals = true)]
4140
const APP: () = {
4241
struct Resources {
43-
display_pins: DisplayPins,
44-
display_timer: MicrobitDisplayTimer<pac::TIMER1>,
42+
display: Display<pac::TIMER1>,
4543
anim_timer: Rtc<pac::RTC0>,
46-
display: Display<MicrobitFrame>,
4744
}
4845

4946
#[init]
@@ -52,6 +49,7 @@ const APP: () = {
5249

5350
// Starting the low-frequency clock (needed for RTC to work)
5451
p.CLOCK.tasks_lfclkstart.write(|w| unsafe { w.bits(1) });
52+
5553
while p.CLOCK.events_lfclkstarted.read().bits() == 0 {}
5654
p.CLOCK.events_lfclkstarted.reset();
5755

@@ -62,46 +60,35 @@ const APP: () = {
6260
rtc0.enable_interrupt(RtcInterrupt::Tick, None);
6361
rtc0.enable_counter();
6462

65-
let mut timer = MicrobitDisplayTimer::new(p.TIMER1);
66-
6763
// Set up pins
6864
#[cfg(feature = "v1")]
69-
let mut pins = {
65+
let pins = {
7066
let p0parts = P0Parts::new(p.GPIO);
7167
display_pins!(p0parts)
7268
};
7369

7470
#[cfg(feature = "v2")]
75-
let mut pins = {
71+
let pins = {
7672
let p0parts = P0Parts::new(p.P0);
7773
let p1parts = P1Parts::new(p.P1);
7874
display_pins!(p0parts, p1parts)
7975
};
8076

81-
display::initialise_display(&mut timer, &mut pins);
77+
let display = Display::new(p.TIMER1, pins);
8278

8379
init::LateResources {
84-
display_pins: pins,
85-
display_timer: timer,
8680
anim_timer: rtc0,
87-
display: Display::new(),
81+
display,
8882
}
8983
}
9084

91-
#[task(binds = TIMER1, priority = 2,
92-
resources = [display_timer, display_pins, display])]
93-
fn timer1(mut cx: timer1::Context) {
94-
display::handle_display_event(
95-
&mut cx.resources.display,
96-
cx.resources.display_timer,
97-
cx.resources.display_pins,
98-
);
85+
#[task(binds = TIMER1, priority = 2, resources = [display])]
86+
fn timer1(cx: timer1::Context) {
87+
cx.resources.display.handle_display_event();
9988
}
10089

101-
#[task(binds = RTC0, priority = 1,
102-
resources = [anim_timer, display])]
90+
#[task(binds = RTC0, priority = 1, resources = [anim_timer, display])]
10391
fn rtc0(mut cx: rtc0::Context) {
104-
static mut FRAME: MicrobitFrame = MicrobitFrame::const_default();
10592
static mut STEP: u8 = 0;
10693

10794
cx.resources.anim_timer.reset_event(RtcInterrupt::Tick);
@@ -112,9 +99,8 @@ const APP: () = {
11299
_ => unreachable!(),
113100
};
114101

115-
FRAME.set(&heart_image(inner_brightness));
116102
cx.resources.display.lock(|display| {
117-
display.set_frame(FRAME);
103+
display.show(&heart_image(inner_brightness));
118104
});
119105

120106
*STEP += 1;

0 commit comments

Comments
 (0)