diff --git a/src/microbit/.gdbinit b/src/microbit/.gdbinit new file mode 100644 index 0000000..f59995c --- /dev/null +++ b/src/microbit/.gdbinit @@ -0,0 +1,10 @@ +# Connects GDB to OpenOCD server port +target remote :3333 +# (optional) Unmangle function names when debugging +set print asm-demangle on +# Enable semihosting +monitor arm semihosting enable +# Load your program, breaks at entry +load +# Continue with execution +continue \ No newline at end of file diff --git a/src/microbit/00.00.README.md b/src/microbit/00.00.README.md new file mode 100644 index 0000000..6782856 --- /dev/null +++ b/src/microbit/00.00.README.md @@ -0,0 +1,10 @@ +# micro:bit HAL + +This chapter will demosntrate the common uses of the micro:bit crate, +and its specific hardware abstraction layer (HAL) features. +The content in this chapter should be deduceable from the HAL crate, +but are given here as a reference. + +More examples can be found in the [micro:bit crate's examples][eg]. + +[eg]: https://github.com/therealprof/microbit/tree/master/examples diff --git a/src/microbit/01.00.BUTTONS.md b/src/microbit/01.00.BUTTONS.md new file mode 100644 index 0000000..212469a --- /dev/null +++ b/src/microbit/01.00.BUTTONS.md @@ -0,0 +1,9 @@ +# Buttons + +The micro:bit as 3 hardware buttons, 2 user buttons and the reset button. + +## User Buttons + +The user buttons are wired up to be high when unpressed and low when pressed. + +{{#include examples/buttons.rs}} diff --git a/src/microbit/02.00.DELAY.md b/src/microbit/02.00.DELAY.md new file mode 100644 index 0000000..7196f22 --- /dev/null +++ b/src/microbit/02.00.DELAY.md @@ -0,0 +1,10 @@ +# Delays + +The microbit has 3 timers, the micro:bit crate currently only supports using TIMER0. + +``` rust +if let Some(p) = microbit::Peripherals::take() { + let mut delay = Delay::new(p.TIMER0); + delay.delay_ms(1000_u32); +} +``` diff --git a/src/microbit/03.00.DISPLAY.md b/src/microbit/03.00.DISPLAY.md new file mode 100644 index 0000000..189bc50 --- /dev/null +++ b/src/microbit/03.00.DISPLAY.md @@ -0,0 +1,11 @@ +# Display + +The micro:bit display is not trivial to control, so a driver is needed; +see [the display chapter](display/00.00.README.html) for more details. + +Display calls for now are only blocking, and can either be for binary images (0 for off, 1 for on), +or for monochrome images with differing brightness levels + +## Blocking binary image display + +{{#include examples/display_blocking.rs}} diff --git a/src/microbit/Cargo.toml b/src/microbit/Cargo.toml new file mode 100644 index 0000000..6c033ad --- /dev/null +++ b/src/microbit/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "microbit" +version = "0.1.0" + +[dependencies] +cortex-m-rt="~0.5" +cortex-m-semihosting="" +panic-abort = "~0.2" +panic-semihosting = "~0.3" +microbit="~0.5" diff --git a/src/microbit/examples/buttons.rs b/src/microbit/examples/buttons.rs new file mode 100644 index 0000000..6d2a358 --- /dev/null +++ b/src/microbit/examples/buttons.rs @@ -0,0 +1,69 @@ +#![no_std] +#![no_main] + +extern crate panic_abort; +extern crate cortex_m_rt as rt; + +#[macro_use(entry, exception)] +extern crate microbit; + +use core::fmt::Write; +use rt::ExceptionFrame; + +use microbit::hal::prelude::*; +use microbit::hal::serial; +use microbit::hal::serial::BAUD115200; + +exception!(HardFault, hard_fault); + +fn hard_fault(ef: &ExceptionFrame) -> ! { + panic!("{:#?}", ef); +} + +exception!(*, default_handler); + +fn default_handler(irqn: i16) { + panic!("Unhandled exception (IRQn = {})", irqn); +} + +entry!(main); +fn main() -> ! { + if let Some(p) = microbit::Peripherals::take() { + // Split GPIO + let mut gpio = p.GPIO.split(); + // Configure RX and TX pins accordingly + let tx = gpio.pin24.into_push_pull_output().downgrade(); + let rx = gpio.pin25.into_floating_input().downgrade(); + // Configure serial communication + let (mut tx, _) = serial::Serial::uart0(p.UART0, tx, rx, BAUD115200).split(); + // Configure button GPIOs as inputs + let button_a = gpio.pin17.into_floating_input(); + let button_b = gpio.pin26.into_floating_input(); + // loop variables + let mut state_a_low = false; + let mut state_b_low = false; + loop { + // Get button states + let button_a_low = button_a.is_low(); + let button_b_low = button_b.is_low(); + if button_a_low && !state_a_low { + writeln!(tx, "Button A down").unwrap(); + } + if button_b_low && !state_b_low { + writeln!(tx, "Button B down").unwrap(); + } + if !button_a_low && state_a_low { + writeln!(tx, "Button A up").unwrap(); + } + if !button_b_low && state_b_low { + writeln!(tx, "Button B up").unwrap(); + } + // Store buttons states + // This should not read the GPIO pins again, as the state + // may have changed and the change will not be recorded + state_a_low = button_a_low; + state_b_low = button_b_low; + } + } + panic!("End"); +} diff --git a/src/microbit/examples/buttons_poll.rs b/src/microbit/examples/buttons_poll.rs new file mode 100644 index 0000000..53afa01 --- /dev/null +++ b/src/microbit/examples/buttons_poll.rs @@ -0,0 +1,57 @@ +#![no_std] +#![no_main] + +extern crate panic_abort; +extern crate cortex_m_rt as rt; + +#[macro_use(entry, exception)] +extern crate microbit; + +use core::fmt::Write; +use rt::ExceptionFrame; + +use microbit::hal::prelude::*; +use microbit::hal::delay::Delay; +use microbit::hal::serial; +use microbit::hal::serial::BAUD115200; + +exception!(HardFault, hard_fault); + +fn hard_fault(ef: &ExceptionFrame) -> ! { + panic!("{:#?}", ef); +} + +exception!(*, default_handler); + +fn default_handler(irqn: i16) { + panic!("Unhandled exception (IRQn = {})", irqn); +} + +entry!(main); +fn main() -> ! { + if let Some(p) = microbit::Peripherals::take() { + // Split GPIO + let mut gpio = p.GPIO.split(); + // Configure RX and TX pins accordingly + let tx = gpio.pin24.into_push_pull_output().downgrade(); + let rx = gpio.pin25.into_floating_input().downgrade(); + // Configure serial communication + let (mut tx, _) = serial::Serial::uart0(p.UART0, tx, rx, BAUD115200).split(); + // Configure button GPIOs as inputs + let button_a = gpio.pin17.into_floating_input(); + let button_b = gpio.pin26.into_floating_input(); + // delay + let mut delay = Delay::new(p.TIMER0); + loop { + writeln!( + tx, "Button A(down:{}, up:{}) B(down:{}, up:{})", + button_a.is_low(), + button_a.is_high(), + button_b.is_low(), + button_b.is_high(), + ).unwrap(); + delay.delay_ms(100_u8); + } + } + panic!("End"); +} diff --git a/src/microbit/examples/display_blocking.rs b/src/microbit/examples/display_blocking.rs new file mode 100644 index 0000000..f6ad6e7 --- /dev/null +++ b/src/microbit/examples/display_blocking.rs @@ -0,0 +1,101 @@ +#![no_std] +#![no_main] + +#[macro_use(entry, exception)] +extern crate microbit; +extern crate cortex_m_rt as rt; +extern crate cortex_m_semihosting as sh; +extern crate panic_abort; + +use core::fmt::Write; + +use rt::ExceptionFrame; + +use microbit::hal::delay::Delay; +use microbit::hal::prelude::*; +use microbit::hal::serial; +use microbit::hal::serial::BAUD115200; + +use microbit::led; + +exception!(HardFault, hard_fault); + +fn hard_fault(ef: &ExceptionFrame) -> ! { + panic!("{:#?}", ef); +} + +exception!(*, default_handler); + +fn default_handler(irqn: i16) { + panic!("Unhandled exception (IRQn = {})", irqn); +} + +entry!(main); +fn main() -> ! { + if let Some(p) = microbit::Peripherals::take() { + let mut gpio = p.GPIO.split(); + let mut delay = Delay::new(p.TIMER0); + + // Display + let row1 = gpio.pin13.into_push_pull_output().downgrade(); + let row2 = gpio.pin14.into_push_pull_output().downgrade(); + let row3 = gpio.pin15.into_push_pull_output().downgrade(); + let col1 = gpio.pin4.into_push_pull_output().downgrade(); + let col2 = gpio.pin5.into_push_pull_output().downgrade(); + let col3 = gpio.pin6.into_push_pull_output().downgrade(); + let col4 = gpio.pin7.into_push_pull_output().downgrade(); + let col5 = gpio.pin8.into_push_pull_output().downgrade(); + let col6 = gpio.pin9.into_push_pull_output().downgrade(); + let col7 = gpio.pin10.into_push_pull_output().downgrade(); + let col8 = gpio.pin11.into_push_pull_output().downgrade(); + let col9 = gpio.pin12.into_push_pull_output().downgrade(); + + // Configure RX and TX pins accordingly + let tx = gpio.pin24.into_push_pull_output().downgrade(); + let rx = gpio.pin25.into_floating_input().downgrade(); + + let mut leds = led::Display::new( + row1, row2, row3, col1, col2, col3, col4, col5, col6, col7, col8, col9, + ); + + let (mut tx, _) = serial::Serial::uart0(p.UART0, tx, rx, BAUD115200).split(); + + let _ = write!(tx, "\n\rStarting!\n\r"); + + #[allow(non_snake_case)] + let letter_I = [ + [0, 1, 1, 1, 0], + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 1, 1, 1, 0], + ]; + + let heart = [ + [0, 1, 0, 1, 0], + [1, 0, 1, 0, 1], + [1, 0, 0, 0, 1], + [0, 1, 0, 1, 0], + [0, 0, 1, 0, 0], + ]; + + #[allow(non_snake_case)] + let letter_U = [ + [0, 1, 0, 1, 0], + [0, 1, 0, 1, 0], + [0, 1, 0, 1, 0], + [0, 1, 0, 1, 0], + [0, 1, 1, 1, 0], + ]; + + loop { + let _ = write!(tx, "I <3 Rust!\n\r"); + leds.display(&mut delay, letter_I, 1000); + leds.display(&mut delay, heart, 1000); + leds.display(&mut delay, letter_U, 1000); + leds.clear(); + delay.delay_ms(250_u32); + } + } + panic!("End"); +} \ No newline at end of file