├── microbit-common ├── src │ ├── v1 │ │ ├── mod.rs │ │ ├── adc.rs │ │ ├── gpio.rs │ │ └── board.rs │ ├── v2 │ │ ├── mod.rs │ │ ├── adc.rs │ │ ├── gpio.rs │ │ └── board.rs │ ├── adc.rs │ ├── board.rs │ ├── display │ │ ├── mod.rs │ │ ├── nonblocking │ │ │ ├── matrix.rs │ │ │ ├── image.rs │ │ │ ├── timer.rs │ │ │ ├── control.rs │ │ │ └── mod.rs │ │ └── blocking.rs │ ├── gpio.rs │ └── lib.rs └── Cargo.toml ├── .gitignore ├── memory.x ├── xtask ├── Cargo.toml └── src │ ├── lib.rs │ ├── publish.rs │ ├── main.rs │ ├── bump.rs │ └── ci.rs ├── .github ├── dependabot.yml └── workflows │ ├── changelog.yml │ ├── rustfmt.yml │ ├── clippy.yml │ └── ci.yaml ├── examples ├── serial-direct-echo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── serial-direct-helloworld │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── serial-hal-blocking-echo │ ├── Cargo.toml │ └── src │ │ ├── serial_setup.rs │ │ └── main.rs ├── gpio-hal-blinky │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── v2-microphone │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── v2-speaker │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── gpio-direct-blinky │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── rng-direct │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── display-nonblocking │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── display-rtic │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── gpio-hal-printbuttons │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── analog-v1 │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── display-blocking │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── gpio-hal-ledbutton │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── analog-v2 │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── display-text-rtic │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── magnetometer │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── servo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── analog │ ├── Cargo.toml │ └── src │ │ └── main.rs └── rng-hal │ ├── Cargo.toml │ └── src │ └── main.rs ├── Cargo.toml ├── tools └── capture_example_bloat.sh ├── LICENSE-0BSD.txt ├── microbit ├── Cargo.toml └── src │ └── lib.rs ├── microbit-v2 ├── Cargo.toml └── src │ └── lib.rs ├── .cargo └── config.toml ├── README.md ├── CHANGELOG.md └── Cargo.lock /microbit-common/src/v1/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod adc; 2 | pub mod board; 3 | pub mod gpio; 4 | -------------------------------------------------------------------------------- /microbit-common/src/v2/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod adc; 2 | pub mod board; 3 | pub mod gpio; 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | **/*.orig 3 | **/*.rs.bk 4 | bloat_log* 5 | !.gitignore 6 | !.github 7 | !.cargo 8 | -------------------------------------------------------------------------------- /microbit-common/src/adc.rs: -------------------------------------------------------------------------------- 1 | //! ADC 2 | #[cfg(feature = "v1")] 3 | pub use crate::v1::adc::*; 4 | 5 | #[cfg(feature = "v2")] 6 | pub use crate::v2::adc::*; 7 | -------------------------------------------------------------------------------- /memory.x: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | /* NOTE K = KiBi = 1024 bytes */ 4 | FLASH : ORIGIN = 0x00000000, LENGTH = 256K 5 | RAM : ORIGIN = 0x20000000, LENGTH = 16K 6 | } 7 | -------------------------------------------------------------------------------- /xtask/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "xtask" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | cargo_toml = "0.22.3" 8 | chrono = "0.4.42" 9 | -------------------------------------------------------------------------------- /microbit-common/src/board.rs: -------------------------------------------------------------------------------- 1 | //! Main Board 2 | #[cfg(feature = "v1")] 3 | pub use crate::v1::board::*; 4 | 5 | #[cfg(feature = "v2")] 6 | pub use crate::v2::board::*; 7 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "cargo" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | - package-ecosystem: "github-actions" 8 | directory: "/" 9 | schedule: 10 | interval: "weekly" 11 | -------------------------------------------------------------------------------- /microbit-common/src/display/mod.rs: -------------------------------------------------------------------------------- 1 | //! Support for the 5x5 LED display. 2 | //! 3 | //! There are two APIs for controlling the LED display, [`blocking`] and [`nonblocking`]. 4 | //! The `blocking` API is the simplest to get started with. 5 | pub mod blocking; 6 | pub mod nonblocking; 7 | -------------------------------------------------------------------------------- /examples/serial-direct-echo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "serial-direct-echo" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | cortex-m-rt = "0.7.5" 8 | panic-halt = "1.0.0" 9 | defmt-rtt = "1.1.0" 10 | 11 | [dependencies.microbit] 12 | path = "../../microbit" 13 | -------------------------------------------------------------------------------- /examples/serial-direct-helloworld/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "serial-direct-helloworld" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | cortex-m-rt = "0.7.5" 8 | panic-halt = "1.0.0" 9 | defmt-rtt = "1.1.0" 10 | 11 | [dependencies.microbit] 12 | path = "../../microbit" 13 | -------------------------------------------------------------------------------- /xtask/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod bump; 2 | mod ci; 3 | mod publish; 4 | 5 | pub static CRATES: &[(&str, &str, &str)] = &[ 6 | ("microbit", "thumbv6m-none-eabi", "v1"), 7 | ("microbit-v2", "thumbv7em-none-eabihf", "v2"), 8 | ]; 9 | 10 | pub use bump::bump_versions; 11 | pub use ci::ci; 12 | pub use publish::publish; 13 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "microbit-common", 5 | "microbit", 6 | "microbit-v2", 7 | "examples/*", 8 | "xtask", 9 | ] 10 | 11 | # Modify default build profiles to make debugging easier 12 | [profile.release] 13 | debug = 2 14 | lto = "off" 15 | 16 | [profile.dev] 17 | debug = 2 18 | opt-level = 1 19 | lto = "off" 20 | -------------------------------------------------------------------------------- /microbit-common/src/gpio.rs: -------------------------------------------------------------------------------- 1 | //! Named GPIO pin types 2 | //! 3 | //! This module maps the GPIO pin names as described in the 4 | //! [Pins and Signals section of the micro:bit site](https://tech.microbit.org/hardware/edgeconnector/#pins-and-signals) 5 | //! Where appropriate the pins are restricted with the appropriate `MODE` 6 | //! from `nrf-hal`. 7 | #[cfg(feature = "v1")] 8 | pub use crate::v1::gpio::*; 9 | 10 | #[cfg(feature = "v2")] 11 | pub use crate::v2::gpio::*; 12 | -------------------------------------------------------------------------------- /tools/capture_example_bloat.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | filename="bloat_log_"`date -Iminutes`".txt" 4 | 5 | for i in `find examples -name "*.rs"`; do 6 | name=$(echo $i | sed -e "s,examples/,,g" -e "s,\.rs,,g") 7 | echo "Processing example $name" 8 | echo >>$filename 9 | echo "Bloat for example $name" >>$filename 10 | cargo bloat --release --example $name >>$filename 11 | done 12 | 13 | echo "Captures bloat for all examples into $filename" 14 | -------------------------------------------------------------------------------- /microbit-common/src/v1/adc.rs: -------------------------------------------------------------------------------- 1 | use crate::hal; 2 | 3 | /// Adc alias to unify v1 and v2 names 4 | pub type Adc = hal::Adc; 5 | /// AdcConfig alias to unify v1 and v2 names 6 | pub type AdcConfig = hal::adc::AdcConfig; 7 | 8 | /// Same resolution for v1 and v2 9 | pub trait Default { 10 | /// v1 is limited to 10 bit 11 | fn default_10bit() -> Self; 12 | } 13 | 14 | impl Default for AdcConfig { 15 | fn default_10bit() -> Self { 16 | AdcConfig::default() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/serial-hal-blocking-echo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "serial-hal-blocking-echo" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | cortex-m-rt = "0.7" 8 | panic-halt = "1.0.0" 9 | defmt-rtt = "1.1" 10 | nb = "1.1.0" 11 | embedded-hal = "1.0.0" 12 | embedded-io = "0.7.1" 13 | 14 | [dependencies.microbit] 15 | path = "../../microbit" 16 | optional = true 17 | 18 | [dependencies.microbit-v2] 19 | path = "../../microbit-v2" 20 | optional = true 21 | 22 | [features] 23 | v1 = ["microbit"] 24 | v2 = ["microbit-v2"] 25 | -------------------------------------------------------------------------------- /.github/workflows/changelog.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request_target: 3 | types: [opened, synchronize, reopened, labeled, unlabeled] 4 | 5 | name: Changelog check 6 | 7 | jobs: 8 | changelog: 9 | name: Changelog check 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout sources 13 | uses: actions/checkout@v6 14 | 15 | - name: Changelog updated 16 | uses: Zomzog/changelog-checker@v1.3.0 17 | with: 18 | fileName: CHANGELOG.md 19 | env: 20 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 21 | -------------------------------------------------------------------------------- /.github/workflows/rustfmt.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: main 4 | pull_request: 5 | merge_group: 6 | 7 | name: Code formatting check 8 | 9 | jobs: 10 | fmt: 11 | name: Rustfmt 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v6 15 | - uses: actions-rs/toolchain@v1 16 | with: 17 | profile: minimal 18 | toolchain: stable 19 | override: true 20 | - run: rustup component add rustfmt 21 | - uses: actions-rs/cargo@v1 22 | with: 23 | command: fmt 24 | args: --all -- --check 25 | -------------------------------------------------------------------------------- /microbit-common/src/v2/adc.rs: -------------------------------------------------------------------------------- 1 | use crate::hal; 2 | 3 | /// Adc alias to unify v1 and v2 names 4 | pub type Adc = hal::Saadc; 5 | /// AdcConfig alias to unify v1 and v2 names 6 | pub type AdcConfig = hal::saadc::SaadcConfig; 7 | 8 | /// Same resolution for v1 and v2 9 | pub trait Default { 10 | /// v1 is limited to 10 bit 11 | fn default_10bit() -> Self; 12 | } 13 | 14 | impl Default for AdcConfig { 15 | fn default_10bit() -> Self { 16 | AdcConfig { 17 | resolution: hal::saadc::Resolution::_10BIT, 18 | ..AdcConfig::default() 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.github/workflows/clippy.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: main 4 | pull_request: 5 | merge_group: 6 | 7 | name: Clippy check 8 | jobs: 9 | clippy_check: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v6 13 | - run: rustup component add clippy 14 | - uses: actions-rs/toolchain@v1 15 | with: 16 | toolchain: stable 17 | target: thumbv6m-none-eabi 18 | override: true 19 | 20 | - name: microbit V1 21 | run: cargo clippy --package microbit -- -D warnings 22 | 23 | - name: microbit V2 24 | run: cargo clippy --package microbit-v2 -- -D warnings 25 | -------------------------------------------------------------------------------- /examples/gpio-hal-blinky/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | use panic_halt as _; 5 | 6 | use cortex_m_rt::entry; 7 | use embedded_hal::{delay::DelayNs, digital::OutputPin}; 8 | use microbit::{board::Board, hal::timer::Timer}; 9 | 10 | #[entry] 11 | fn main() -> ! { 12 | let mut board = Board::take().unwrap(); 13 | 14 | let mut timer = Timer::new(board.TIMER0); 15 | 16 | let _ = board.display_pins.col1.set_low(); 17 | let mut row1 = board.display_pins.row1; 18 | 19 | loop { 20 | let _ = row1.set_low(); 21 | timer.delay_ms(1_000); 22 | let _ = row1.set_high(); 23 | timer.delay_ms(1_000); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/v2-microphone/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "v2-microphone" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } 8 | embedded-hal = "1.0.0" 9 | cortex-m-rt = "0.7.5" 10 | panic-halt = "1.0.0" 11 | defmt-rtt = "1.1.0" 12 | defmt = "1.0.1" 13 | 14 | [dependencies.microbit-v2] 15 | path = "../../microbit-v2" 16 | optional = true 17 | 18 | [features] 19 | v2 = ["microbit-v2"] 20 | 21 | default = ["defmt-default"] 22 | 23 | # do NOT modify these features 24 | defmt-default = [] 25 | defmt-trace = [] 26 | defmt-debug = [] 27 | defmt-info = [] 28 | defmt-warn = [] 29 | defmt-error = [] 30 | -------------------------------------------------------------------------------- /examples/v2-speaker/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "v2-speaker" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } 8 | embedded-hal = "1.0.0" 9 | cortex-m-rt = "0.7.5" 10 | panic-halt = "1.0.0" 11 | defmt-rtt = "1.1" 12 | defmt = "1.0.1" 13 | 14 | [dependencies.microbit-v2] 15 | path = "../../microbit-v2" 16 | optional = true 17 | 18 | [features] 19 | v2 = ["microbit-v2"] 20 | 21 | default = [ 22 | "defmt-default", 23 | ] 24 | 25 | # do NOT modify these features 26 | defmt-default = [] 27 | defmt-trace = [] 28 | defmt-debug = [] 29 | defmt-info = [] 30 | defmt-warn = [] 31 | defmt-error = [] 32 | -------------------------------------------------------------------------------- /LICENSE-0BSD.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 2018 daniel@eggers-club.de 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted. 5 | 6 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 7 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 8 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 9 | SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 10 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 11 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 12 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 13 | -------------------------------------------------------------------------------- /examples/gpio-hal-blinky/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "gpio-hal-blinky" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | embedded-hal = "1.0.0" 8 | cortex-m-rt = "0.7.5" 9 | panic-halt = "1.0.0" 10 | defmt-rtt = "1.1.0" 11 | defmt = "1.0.1" 12 | 13 | [dependencies.microbit] 14 | path = "../../microbit" 15 | optional = true 16 | 17 | [dependencies.microbit-v2] 18 | path = "../../microbit-v2" 19 | optional = true 20 | 21 | [features] 22 | v1 = ["microbit"] 23 | v2 = ["microbit-v2"] 24 | 25 | default = [ 26 | "defmt-default", 27 | ] 28 | 29 | # do NOT modify these features 30 | defmt-default = [] 31 | defmt-trace = [] 32 | defmt-debug = [] 33 | defmt-info = [] 34 | defmt-warn = [] 35 | defmt-error = [] 36 | -------------------------------------------------------------------------------- /examples/gpio-direct-blinky/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "gpio-direct-blinky" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } 8 | cortex-m-rt = "0.7.5" 9 | panic-halt = "1.0.0" 10 | defmt = "1.0.1" 11 | 12 | [dependencies.microbit] 13 | path = "../../microbit" 14 | optional = true 15 | 16 | [dependencies.microbit-v2] 17 | path = "../../microbit-v2" 18 | optional = true 19 | 20 | [features] 21 | v1 = ["microbit"] 22 | v2 = ["microbit-v2"] 23 | 24 | default = [ 25 | "defmt-default", 26 | ] 27 | 28 | # do NOT modify these features 29 | defmt-default = [] 30 | defmt-trace = [] 31 | defmt-debug = [] 32 | defmt-info = [] 33 | defmt-warn = [] 34 | defmt-error = [] 35 | -------------------------------------------------------------------------------- /examples/rng-direct/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rng-direct" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } 8 | cortex-m-rt = "0.7.5" 9 | panic-halt = "1.0.0" 10 | defmt-rtt = "1.1.0" 11 | defmt = "1.0.1" 12 | 13 | [dependencies.microbit] 14 | path = "../../microbit" 15 | optional = true 16 | 17 | [dependencies.microbit-v2] 18 | path = "../../microbit-v2" 19 | optional = true 20 | 21 | [features] 22 | v1 = ["microbit"] 23 | v2 = ["microbit-v2"] 24 | 25 | default = [ 26 | "defmt-default", 27 | ] 28 | 29 | # do NOT modify these features 30 | defmt-default = [] 31 | defmt-trace = [] 32 | defmt-debug = [] 33 | defmt-info = [] 34 | defmt-warn = [] 35 | defmt-error = [] 36 | -------------------------------------------------------------------------------- /examples/display-nonblocking/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "display-nonblocking" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } 8 | cortex-m-rt = "0.7.5" 9 | panic-halt = "1.0.0" 10 | defmt-rtt = "1.1.0" 11 | defmt = "1.0.1" 12 | 13 | [dependencies.microbit] 14 | path = "../../microbit" 15 | optional = true 16 | 17 | [dependencies.microbit-v2] 18 | path = "../../microbit-v2" 19 | optional = true 20 | 21 | [features] 22 | v1 = ["microbit"] 23 | v2 = ["microbit-v2"] 24 | 25 | default = [ 26 | "defmt-default", 27 | ] 28 | 29 | # do NOT modify these features 30 | defmt-default = [] 31 | defmt-trace = [] 32 | defmt-debug = [] 33 | defmt-info = [] 34 | defmt-warn = [] 35 | defmt-error = [] 36 | -------------------------------------------------------------------------------- /microbit/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "microbit" 3 | version = "0.16.0" 4 | description = "Board support crate for the BBC Micro:bit V1" 5 | edition = "2018" 6 | readme = "../README.md" 7 | rust-version = "1.79.0" 8 | 9 | repository = "https://github.com/nrf-rs/microbit" 10 | authors = [ 11 | "Daniel Egger ", 12 | "Michael Droogleever ", 13 | "Rob Young ", 14 | ] 15 | categories = ["hardware-support", "embedded", "no-std"] 16 | keywords = ["arm", "cortex-m", "nrf", "hal"] 17 | license = "0BSD" 18 | 19 | [dependencies] 20 | 21 | [dependencies.microbit-common] 22 | path = "../microbit-common" 23 | features = ["v1"] 24 | version = "=0.16.0" 25 | 26 | [features] 27 | embedded-hal-02 = ["microbit-common/embedded-hal-02"] 28 | -------------------------------------------------------------------------------- /examples/display-rtic/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "display-rtic" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } 8 | panic-halt = "1.0.0" 9 | defmt-rtt = "1.1.0" 10 | defmt = "1.0.1" 11 | cortex-m-rtic = { version = "1.1.4" } 12 | 13 | [dependencies.microbit] 14 | path = "../../microbit" 15 | optional = true 16 | 17 | [dependencies.microbit-v2] 18 | path = "../../microbit-v2" 19 | optional = true 20 | 21 | [features] 22 | v1 = ["microbit"] 23 | v2 = ["microbit-v2"] 24 | 25 | default = [ 26 | "defmt-default", 27 | ] 28 | 29 | # do NOT modify these features 30 | defmt-default = [] 31 | defmt-trace = [] 32 | defmt-debug = [] 33 | defmt-info = [] 34 | defmt-warn = [] 35 | defmt-error = [] 36 | -------------------------------------------------------------------------------- /examples/gpio-hal-printbuttons/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "gpio-hal-printbuttons" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } 8 | cortex-m-rt = "0.7.5" 9 | panic-halt = "1.0.0" 10 | defmt-rtt = "1.1.0" 11 | defmt = "1.0.1" 12 | 13 | [dependencies.microbit] 14 | path = "../../microbit" 15 | optional = true 16 | 17 | [dependencies.microbit-v2] 18 | path = "../../microbit-v2" 19 | optional = true 20 | 21 | [features] 22 | v1 = ["microbit"] 23 | v2 = ["microbit-v2"] 24 | 25 | default = [ 26 | "defmt-default", 27 | ] 28 | 29 | # do NOT modify these features 30 | defmt-default = [] 31 | defmt-trace = [] 32 | defmt-debug = [] 33 | defmt-info = [] 34 | defmt-warn = [] 35 | defmt-error = [] 36 | -------------------------------------------------------------------------------- /examples/analog-v1/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "analog-v1" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } 10 | cortex-m-rt = "0.7.5" 11 | panic-halt = "1.0.0" 12 | defmt-rtt = "1.1.0" 13 | defmt = "1.0.1" 14 | 15 | # NOTE: This currently only works with the microbit v1 due to naming issues! 16 | # ADC vs SAADC 17 | [dependencies.microbit] 18 | path = "../../microbit" 19 | 20 | [features] 21 | default = [ 22 | "defmt-default", 23 | ] 24 | 25 | # do NOT modify these features 26 | defmt-default = [] 27 | defmt-trace = [] 28 | defmt-debug = [] 29 | defmt-info = [] 30 | defmt-warn = [] 31 | defmt-error = [] 32 | -------------------------------------------------------------------------------- /examples/display-blocking/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "display-blocking" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } 8 | cortex-m-rt = "0.7.5" 9 | panic-halt = "1.0.0" 10 | defmt-rtt = "1.1.0" 11 | defmt = "1.0.1" 12 | embedded-hal = "1.0.0" 13 | 14 | [dependencies.microbit] 15 | path = "../../microbit" 16 | optional = true 17 | 18 | [dependencies.microbit-v2] 19 | path = "../../microbit-v2" 20 | optional = true 21 | 22 | [features] 23 | v1 = ["microbit"] 24 | v2 = ["microbit-v2"] 25 | 26 | default = [ 27 | "defmt-default", 28 | ] 29 | 30 | # do NOT modify these features 31 | defmt-default = [] 32 | defmt-trace = [] 33 | defmt-debug = [] 34 | defmt-info = [] 35 | defmt-warn = [] 36 | defmt-error = [] 37 | -------------------------------------------------------------------------------- /examples/gpio-hal-ledbutton/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "gpio-hal-ledbutton" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } 8 | cortex-m-rt = "0.7.5" 9 | panic-halt = "1.0.0" 10 | defmt-rtt = "1.1.0" 11 | defmt = "1.0.1" 12 | embedded-hal = "1.0.0" 13 | 14 | [dependencies.microbit] 15 | path = "../../microbit" 16 | optional = true 17 | 18 | [dependencies.microbit-v2] 19 | path = "../../microbit-v2" 20 | optional = true 21 | 22 | [features] 23 | v1 = ["microbit"] 24 | v2 = ["microbit-v2"] 25 | 26 | default = [ 27 | "defmt-default", 28 | ] 29 | 30 | # do NOT modify these features 31 | defmt-default = [] 32 | defmt-trace = [] 33 | defmt-debug = [] 34 | defmt-info = [] 35 | defmt-warn = [] 36 | defmt-error = [] 37 | -------------------------------------------------------------------------------- /examples/analog-v2/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "analog-v2" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } 10 | cortex-m-rt = "0.7.5" 11 | panic-halt = "1.0.0" 12 | defmt-rtt = "1.1.0" 13 | defmt = "1.0.1" 14 | 15 | # NOTE: This currently only works with the microbit v2 due to naming issues! 16 | # ADC vs SAADC 17 | [dependencies.microbit-v2] 18 | path = "../../microbit-v2" 19 | 20 | [features] 21 | default = [ 22 | "defmt-default", 23 | ] 24 | 25 | # do NOT modify these features 26 | defmt-default = [] 27 | defmt-trace = [] 28 | defmt-debug = [] 29 | defmt-info = [] 30 | defmt-warn = [] 31 | defmt-error = [] 32 | -------------------------------------------------------------------------------- /examples/display-text-rtic/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "display-text-rtic" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } 8 | panic-halt = "1.0.0" 9 | defmt-rtt = "1.1.0" 10 | defmt = "1.0.1" 11 | cortex-m-rtic = { version = "1.1.4" } 12 | microbit-text = "1.0.0" 13 | 14 | [dependencies.microbit] 15 | path = "../../microbit" 16 | optional = true 17 | 18 | [dependencies.microbit-v2] 19 | path = "../../microbit-v2" 20 | optional = true 21 | 22 | [features] 23 | v1 = ["microbit"] 24 | v2 = ["microbit-v2"] 25 | 26 | default = [ 27 | "defmt-default", 28 | ] 29 | 30 | # do NOT modify these features 31 | defmt-default = [] 32 | defmt-trace = [] 33 | defmt-debug = [] 34 | defmt-info = [] 35 | defmt-warn = [] 36 | defmt-error = [] 37 | -------------------------------------------------------------------------------- /examples/magnetometer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "magnetometer" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } 8 | cortex-m-rt = "0.7.5" 9 | embedded-hal = "1.0.0" 10 | panic-halt = "1.0.0" 11 | defmt-rtt = "1.1.0" 12 | defmt = "1.0.1" 13 | lsm303agr = "1.1.0" 14 | 15 | [dependencies.microbit] 16 | path = "../../microbit" 17 | optional = true 18 | 19 | [dependencies.microbit-v2] 20 | path = "../../microbit-v2" 21 | optional = true 22 | 23 | [features] 24 | v1 = ["microbit"] 25 | v2 = ["microbit-v2"] 26 | 27 | default = [ 28 | "defmt-default", 29 | ] 30 | 31 | # do NOT modify these features 32 | defmt-default = [] 33 | defmt-trace = [] 34 | defmt-debug = [] 35 | defmt-info = [] 36 | defmt-warn = [] 37 | defmt-error = [] 38 | -------------------------------------------------------------------------------- /microbit-v2/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "microbit-v2" 3 | version = "0.16.0" 4 | description = "Board support crate for the BBC Micro:bit V2" 5 | edition = "2018" 6 | readme = "../README.md" 7 | rust-version = "1.79.0" 8 | 9 | repository = "https://github.com/nrf-rs/microbit" 10 | authors = [ 11 | "Daniel Egger ", 12 | "Michael Droogleever ", 13 | "Rob Young ", 14 | ] 15 | categories = ["hardware-support", "embedded", "no-std"] 16 | keywords = ["arm", "cortex-m", "nrf", "hal"] 17 | license = "0BSD" 18 | 19 | [lib] 20 | name = "microbit" 21 | path = "src/lib.rs" 22 | 23 | [dependencies] 24 | 25 | [dependencies.microbit-common] 26 | path = "../microbit-common" 27 | features = ["v2"] 28 | version = "=0.16.0" 29 | 30 | [features] 31 | embedded-hal-02 = ["microbit-common/embedded-hal-02"] 32 | -------------------------------------------------------------------------------- /examples/servo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "servo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } 10 | cortex-m-rt = "0.7.5" 11 | panic-halt = "1.0.0" 12 | defmt-rtt = "1.1.0" 13 | defmt = "1.0.1" 14 | 15 | [dependencies.microbit] 16 | path = "../../microbit" 17 | optional = true 18 | 19 | [dependencies.microbit-v2] 20 | path = "../../microbit-v2" 21 | optional = true 22 | 23 | [features] 24 | v1 = ["microbit"] 25 | v2 = ["microbit-v2"] 26 | 27 | default = [ 28 | "defmt-default", 29 | ] 30 | 31 | # do NOT modify these features 32 | defmt-default = [] 33 | defmt-trace = [] 34 | defmt-debug = [] 35 | defmt-info = [] 36 | defmt-warn = [] 37 | defmt-error = [] 38 | -------------------------------------------------------------------------------- /examples/analog/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "analog" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } 10 | cortex-m-rt = "0.7.5" 11 | panic-halt = "1.0.0" 12 | defmt-rtt = "1.1.0" 13 | defmt = "1.0.1" 14 | 15 | [dependencies.microbit] 16 | path = "../../microbit" 17 | optional = true 18 | 19 | [dependencies.microbit-v2] 20 | path = "../../microbit-v2" 21 | optional = true 22 | 23 | [features] 24 | v1 = ["microbit"] 25 | v2 = ["microbit-v2"] 26 | 27 | default = [ 28 | "defmt-default", 29 | ] 30 | 31 | # do NOT modify these features 32 | defmt-default = [] 33 | defmt-trace = [] 34 | defmt-debug = [] 35 | defmt-info = [] 36 | defmt-warn = [] 37 | defmt-error = [] 38 | -------------------------------------------------------------------------------- /microbit-common/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! microbit contains everything required to get started with the use of Rust 2 | //! to create firmwares for the fabulous [BBC micro:bit](https://microbit.org) 3 | //! microcontroller board. 4 | #![doc(html_root_url = "https://docs.rs/microbit-common/0.16.0")] 5 | #![no_std] 6 | #![deny(missing_docs)] 7 | #![allow(non_camel_case_types)] 8 | 9 | #[cfg(all(feature = "v1", feature = "v2"))] 10 | compile_error!("canot build for microbit v1 and v2 at the same time"); 11 | 12 | #[cfg(feature = "v1")] 13 | pub use nrf51_hal as hal; 14 | 15 | #[cfg(feature = "v2")] 16 | pub use nrf52833_hal as hal; 17 | 18 | pub use hal::pac; 19 | pub use hal::pac::Peripherals; 20 | 21 | pub mod adc; 22 | pub mod board; 23 | pub mod display; 24 | pub mod gpio; 25 | 26 | pub use board::Board; 27 | 28 | #[cfg(feature = "v1")] 29 | mod v1; 30 | 31 | #[cfg(feature = "v2")] 32 | mod v2; 33 | -------------------------------------------------------------------------------- /examples/gpio-hal-ledbutton/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | use defmt_rtt as _; 5 | use panic_halt as _; 6 | 7 | use cortex_m_rt::entry; 8 | use embedded_hal::digital::{InputPin, OutputPin}; 9 | use microbit::board::Board; 10 | 11 | #[entry] 12 | fn main() -> ! { 13 | let mut board = Board::take().unwrap(); 14 | 15 | board.display_pins.row1.set_high().unwrap(); 16 | 17 | let mut led1 = board.display_pins.col1; 18 | let mut led2 = board.display_pins.col2; 19 | 20 | loop { 21 | if let Ok(true) = board.buttons.button_a.is_high() { 22 | let _ = led1.set_high(); 23 | } else { 24 | let _ = led1.set_low(); 25 | } 26 | 27 | if let Ok(true) = board.buttons.button_b.is_high() { 28 | let _ = led2.set_high(); 29 | } else { 30 | let _ = led2.set_low(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /xtask/src/publish.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | 3 | use crate::CRATES; 4 | 5 | pub fn publish() { 6 | publish_package("microbit-common", "thumbv7em-none-eabihf", Some("v2")); 7 | 8 | for (name, target, _) in CRATES { 9 | publish_package(name, target, None); 10 | } 11 | } 12 | 13 | fn publish_package(package: &str, target: &str, feature: Option<&str>) { 14 | let mut cargo = Command::new("cargo"); 15 | cargo.args(&["publish", "--target", target, "--package", package]); 16 | if let Some(feature) = feature { 17 | cargo.args(&["--features", feature]); 18 | } 19 | 20 | let status = cargo 21 | .status() 22 | .map_err(|e| format!("could not execute {:?}: {}", cargo, e)) 23 | .unwrap(); 24 | 25 | assert!( 26 | status.success(), 27 | "command exited with error status: {:?}", 28 | cargo 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [alias] 2 | xtask = "run --package xtask --" 3 | 4 | # For micro:bit v1.x 5 | 6 | [target.thumbv6m-none-eabi] 7 | runner = 'probe-rs run --chip nRF51822_xxAA --protocol swd' 8 | rustflags = [ 9 | "-C", "linker=flip-link", 10 | "-C", "link-arg=-Tlink.x", 11 | "-C", "link-arg=-Tdefmt.x", 12 | ] 13 | 14 | # For micro:bit v2 15 | 16 | [target.thumbv7em-none-eabi] 17 | runner = "probe-rs run --chip nRF52833_xxAA --protocol swd" 18 | rustflags = [ 19 | "-C", "linker=flip-link", 20 | "-C", "link-arg=-Tlink.x", 21 | "-C", "link-arg=-Tdefmt.x", 22 | ] 23 | 24 | [target.thumbv7em-none-eabihf] 25 | runner = "probe-rs run --chip nRF52833_xxAA --protocol swd" 26 | rustflags = [ 27 | "-C", "linker=flip-link", 28 | "-C", "link-arg=-Tlink.x", 29 | "-C", "link-arg=-Tdefmt.x", 30 | ] 31 | 32 | # Enable printing of defmt debug, info and warning messages by default 33 | [env] 34 | DEFMT_LOG="debug" 35 | -------------------------------------------------------------------------------- /xtask/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | use xtask::{bump_versions, ci, publish}; 4 | 5 | fn main() { 6 | let mut args = env::args().skip(1); 7 | let subcommand = args.next(); 8 | match subcommand.as_deref() { 9 | Some("bump") => { 10 | let new_version = args.next().expect("missing argument"); 11 | bump_versions(&new_version, false); 12 | } 13 | Some("ci") => ci(), 14 | Some("publish") => publish(), 15 | _ => { 16 | eprintln!("usage: cargo xtask "); 17 | eprintln!(); 18 | eprintln!("subcommands:"); 19 | eprintln!(" ci - run continuous integration checks (build and clippy)"); 20 | eprintln!(" bump - bump the crate version and update docs and changelog"); 21 | eprintln!(" publish - publish all crates to crates.io"); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/rng-hal/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rng-hal-printrandserial" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } 8 | cortex-m-rt = "0.7.5" 9 | panic-halt = "1.0.0" 10 | defmt-rtt = "1.1.0" 11 | defmt = "1.0.1" 12 | 13 | [dependencies.rand] 14 | default-features = false 15 | version = "0.9.2" 16 | 17 | [dependencies.rand_pcg] 18 | default-features = false 19 | version = "0.9.0" 20 | 21 | [dependencies.microbit] 22 | path = "../../microbit" 23 | optional = true 24 | 25 | [dependencies.microbit-v2] 26 | path = "../../microbit-v2" 27 | optional = true 28 | 29 | [features] 30 | v1 = ["microbit"] 31 | v2 = ["microbit-v2"] 32 | 33 | default = [ 34 | "defmt-default", 35 | ] 36 | 37 | # do NOT modify these features 38 | defmt-default = [] 39 | defmt-trace = [] 40 | defmt-debug = [] 41 | defmt-info = [] 42 | defmt-warn = [] 43 | defmt-error = [] 44 | -------------------------------------------------------------------------------- /microbit-v2/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! microbit contains everything required to get started with the use of Rust 2 | //! to create firmwares for the fabulous [BBC micro:bit](https://microbit.org) 3 | //! microcontroller board. 4 | //! 5 | //! This crate is for the new micro:bit (V2) pictured below on the right. If 6 | //! your micro:bit looks like the one on the left you need the 7 | //! [microbit](https://crates.io/crates/microbit) crate. 8 | //! 9 | //! [](https://github.com/microbit-foundation/microbit-svg/blob/master/microbit-drawing-back-1-5.png) 10 | //! [](https://github.com/microbit-foundation/microbit-svg/blob/master/microbit-drawing-back-2.png) 11 | #![doc(html_root_url = "https://docs.rs/microbit-v2/0.16.0")] 12 | #![no_std] 13 | #![deny(missing_docs)] 14 | #![allow(non_camel_case_types)] 15 | 16 | pub use microbit_common::*; 17 | -------------------------------------------------------------------------------- /microbit/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! microbit contains everything required to get started with the use of Rust 2 | //! to create firmwares for the fabulous [BBC micro:bit](https://microbit.org) 3 | //! microcontroller board. 4 | //! 5 | //! This crate is for the original micro:bit (V1) pictured below on the left. If 6 | //! your micro:bit looks like the one on the right you need the 7 | //! [microbit-v2](https://crates.io/crates/microbit-v2) crate. 8 | //! 9 | //! [](https://github.com/microbit-foundation/microbit-svg/blob/master/microbit-drawing-back-1-5.png) 10 | //! [](https://github.com/microbit-foundation/microbit-svg/blob/master/microbit-drawing-back-2.png) 11 | #![doc(html_root_url = "https://docs.rs/microbit/0.16.0")] 12 | #![no_std] 13 | #![deny(missing_docs)] 14 | #![allow(non_camel_case_types)] 15 | 16 | pub use microbit_common::*; 17 | -------------------------------------------------------------------------------- /microbit-common/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "microbit-common" 3 | version = "0.16.0" 4 | description = "Implementation details for the BBC Micro:bit board support crates" 5 | edition = "2018" 6 | readme = "../README.md" 7 | rust-version = "1.79.0" 8 | 9 | repository = "https://github.com/nrf-rs/microbit" 10 | authors = [ 11 | "Daniel Egger ", 12 | "Michael Droogleever ", 13 | "Rob Young ", 14 | ] 15 | categories = ["hardware-support", "embedded", "no-std"] 16 | keywords = ["arm", "cortex-m", "nrf", "hal"] 17 | license = "0BSD" 18 | 19 | [dependencies] 20 | tiny-led-matrix = "1.0.2" 21 | embedded-hal = "1.0.0" 22 | 23 | [dependencies.nrf51-hal] 24 | optional = true 25 | version = "0.19.0" 26 | default-features = false 27 | features = ["rt", "xxAB-package"] 28 | 29 | [dependencies.nrf52833-hal] 30 | optional = true 31 | version = "0.19.0" 32 | default-features = false 33 | features = ["rt"] 34 | 35 | [features] 36 | doc = [] 37 | v1 = ["nrf51-hal"] 38 | v2 = ["nrf52833-hal"] 39 | embedded-hal-02 = [ 40 | "nrf51-hal?/embedded-hal-02", 41 | "nrf52833-hal?/embedded-hal-02", 42 | ] 43 | 44 | [package.metadata.docs.rs] 45 | features = ["v2"] 46 | default-target = "thumbv7em-none-eabihf" 47 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: main 4 | pull_request: 5 | merge_group: 6 | 7 | jobs: 8 | ci: 9 | name: CI 10 | runs-on: ubuntu-latest 11 | needs: [build] 12 | if: always() 13 | steps: 14 | - name: Done 15 | run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' 16 | 17 | build: 18 | runs-on: ubuntu-latest 19 | 20 | strategy: 21 | matrix: 22 | rust: 23 | - stable 24 | - beta 25 | - nightly 26 | include: 27 | # Minimum supported rust version (MSRV) 28 | # Note this needs to be new enough to build the examples as well as 29 | # the library itself. 30 | - name: MSRV 31 | rust: 1.81.0 32 | 33 | name: "build (${{ matrix.name || matrix.rust }})" 34 | 35 | steps: 36 | - uses: actions/checkout@v6 37 | 38 | - name: Install Rust 39 | uses: actions-rs/toolchain@v1 40 | with: 41 | profile: minimal 42 | toolchain: ${{ matrix.rust }} 43 | override: true 44 | components: rustfmt, clippy 45 | 46 | - name: rustfmt 47 | run: cargo fmt -- --check 48 | 49 | - name: build 50 | run: cargo xtask ci 51 | -------------------------------------------------------------------------------- /examples/serial-hal-blocking-echo/src/serial_setup.rs: -------------------------------------------------------------------------------- 1 | use core::{fmt, ptr::addr_of_mut}; 2 | use microbit::hal::uarte::{Error, Instance, Uarte, UarteRx, UarteTx}; 3 | 4 | static mut TX_BUF: [u8; 1] = [0; 1]; 5 | static mut RX_BUF: [u8; 1] = [0; 1]; 6 | 7 | pub struct UartePort(UarteTx, UarteRx); 8 | 9 | impl UartePort { 10 | pub fn new(serial: Uarte) -> UartePort { 11 | let (tx, rx) = serial 12 | .split(unsafe { addr_of_mut!(TX_BUF).as_mut().unwrap() }, unsafe { 13 | addr_of_mut!(RX_BUF).as_mut().unwrap() 14 | }) 15 | .unwrap(); 16 | UartePort(tx, rx) 17 | } 18 | } 19 | 20 | impl fmt::Write for UartePort { 21 | fn write_str(&mut self, s: &str) -> fmt::Result { 22 | self.0.write_str(s) 23 | } 24 | } 25 | 26 | impl embedded_io::ErrorType for UartePort { 27 | type Error = Error; 28 | } 29 | 30 | impl embedded_io::Write for UartePort { 31 | fn write(&mut self, buffer: &[u8]) -> Result { 32 | self.0.write(buffer) 33 | } 34 | 35 | fn flush(&mut self) -> Result<(), Self::Error> { 36 | self.0.flush() 37 | } 38 | } 39 | 40 | impl embedded_io::Read for UartePort { 41 | fn read(&mut self, buffer: &mut [u8]) -> Result { 42 | self.1.read(buffer) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /examples/serial-direct-helloworld/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | use panic_halt as _; 5 | 6 | use cortex_m_rt::entry; 7 | 8 | #[entry] 9 | fn main() -> ! { 10 | if let Some(p) = microbit::Peripherals::take() { 11 | p.GPIO.pin_cnf[24].write(|w| w.pull().pullup().dir().output()); 12 | p.GPIO.pin_cnf[25].write(|w| w.pull().disabled().dir().input()); 13 | 14 | p.UART0.pseltxd.write(|w| unsafe { w.bits(24) }); 15 | p.UART0.pselrxd.write(|w| unsafe { w.bits(25) }); 16 | 17 | p.UART0.baudrate.write(|w| w.baudrate().baud115200()); 18 | p.UART0.enable.write(|w| w.enable().enabled()); 19 | 20 | let _ = write_uart0(&p.UART0, "Hello World!\n"); 21 | } 22 | 23 | loop { 24 | continue; 25 | } 26 | } 27 | 28 | fn write_uart0(uart0: µbit::pac::UART0, s: &str) -> core::fmt::Result { 29 | uart0.tasks_starttx.write(|w| unsafe { w.bits(1) }); 30 | for c in s.as_bytes() { 31 | /* Write the current character to the output register */ 32 | uart0.txd.write(|w| unsafe { w.bits(u32::from(*c)) }); 33 | 34 | /* Wait until the UART is clear to send */ 35 | while uart0.events_txdrdy.read().bits() == 0 {} 36 | 37 | /* And then set it back to 0 again, just because ?!? */ 38 | uart0.events_txdrdy.write(|w| unsafe { w.bits(0) }); 39 | } 40 | uart0.tasks_stoptx.write(|w| unsafe { w.bits(1) }); 41 | Ok(()) 42 | } 43 | -------------------------------------------------------------------------------- /examples/serial-hal-blocking-echo/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | use panic_halt as _; 5 | 6 | use core::fmt::Write; 7 | use cortex_m_rt::entry; 8 | use embedded_io::Read; 9 | 10 | #[cfg(feature = "v1")] 11 | use microbit::{ 12 | hal::uart, 13 | hal::uart::{Baudrate, Parity}, 14 | }; 15 | 16 | #[cfg(feature = "v2")] 17 | use microbit::{ 18 | hal::uarte, 19 | hal::uarte::{Baudrate, Parity}, 20 | }; 21 | 22 | #[cfg(feature = "v2")] 23 | mod serial_setup; 24 | #[cfg(feature = "v2")] 25 | use serial_setup::UartePort; 26 | 27 | #[entry] 28 | fn main() -> ! { 29 | let board = microbit::Board::take().unwrap(); 30 | 31 | #[cfg(feature = "v1")] 32 | let mut serial = { 33 | uart::Uart::new( 34 | board.UART0, 35 | board.uart.into(), 36 | Parity::EXCLUDED, 37 | Baudrate::BAUD115200, 38 | ) 39 | }; 40 | 41 | #[cfg(feature = "v2")] 42 | let mut serial = { 43 | let serial = uarte::Uarte::new( 44 | board.UARTE0, 45 | board.uart.into(), 46 | Parity::EXCLUDED, 47 | Baudrate::BAUD115200, 48 | ); 49 | UartePort::new(serial) 50 | }; 51 | 52 | loop { 53 | write!(serial, "Hello World:\r\n").unwrap(); 54 | let mut input = [0]; 55 | serial.read_exact(&mut input).unwrap(); 56 | write!(serial, "You said: {}\r\n", input[0] as char).unwrap(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /examples/gpio-direct-blinky/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | use panic_halt as _; 5 | 6 | use cortex_m_rt::entry; 7 | 8 | #[cfg(feature = "v1")] 9 | #[entry] 10 | fn main() -> ! { 11 | if let Some(p) = microbit::Peripherals::take() { 12 | p.GPIO.pin_cnf[4].write(|w| w.dir().output()); 13 | p.GPIO.pin_cnf[13].write(|w| w.dir().output()); 14 | 15 | p.GPIO.out.write(|w| unsafe { w.bits(1 << 13) }); 16 | 17 | let mut count: u8 = 0; 18 | loop { 19 | count += 1; 20 | 21 | if count & 1 == 1 { 22 | p.GPIO.out.write(|w| unsafe { w.bits(1 << 13) }); 23 | } else { 24 | p.GPIO.out.write(|w| unsafe { w.bits(0) }); 25 | } 26 | 27 | for _ in 0..50_000 { 28 | cortex_m::asm::nop(); 29 | } 30 | } 31 | }; 32 | 33 | loop { 34 | continue; 35 | } 36 | } 37 | 38 | #[cfg(feature = "v2")] 39 | #[entry] 40 | fn main() -> ! { 41 | if let Some(p) = microbit::Peripherals::take() { 42 | p.P0.pin_cnf[28].write(|w| w.dir().output()); 43 | p.P0.pin_cnf[21].write(|w| w.dir().output()); 44 | 45 | p.P0.out.write(|w| unsafe { w.bits(1 << 21) }); 46 | 47 | let mut count: u8 = 0; 48 | loop { 49 | count += 1; 50 | 51 | if count & 1 == 1 { 52 | p.P0.out.write(|w| unsafe { w.bits(1 << 21) }); 53 | } else { 54 | p.P0.out.write(|w| unsafe { w.bits(0) }); 55 | } 56 | 57 | for _ in 0..50_000 { 58 | cortex_m::asm::nop(); 59 | } 60 | } 61 | }; 62 | 63 | loop { 64 | continue; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /examples/v2-microphone/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use defmt_rtt as _; 5 | use panic_halt as _; 6 | 7 | use cortex_m_rt::entry; 8 | use microbit::{ 9 | board::Board, 10 | display::blocking::Display, 11 | hal::{ 12 | gpio::{Level, OpenDrainConfig}, 13 | saadc::SaadcConfig, 14 | Saadc, Timer, 15 | }, 16 | }; 17 | 18 | #[entry] 19 | fn main() -> ! { 20 | if let Some(board) = Board::take() { 21 | let mut timer = Timer::new(board.TIMER0); 22 | let mut display = Display::new(board.display_pins); 23 | 24 | // initialize adc 25 | let saadc_config = SaadcConfig::default(); 26 | let mut saadc = Saadc::new(board.ADC, saadc_config); 27 | let mut mic_in = board.microphone_pins.mic_in.into_floating_input(); 28 | 29 | // enable microphone 30 | board 31 | .microphone_pins 32 | .mic_run 33 | .into_open_drain_output(OpenDrainConfig::Disconnect0HighDrive1, Level::High); 34 | 35 | let mut count: u64 = 0; 36 | let mut sum: u64 = 0; 37 | let mut max_value: u16 = 0; 38 | loop { 39 | let mic_value = saadc 40 | .read_channel(&mut mic_in) 41 | .expect("could not read value of microphone") as u16; 42 | 43 | // Smoothen the signal as audio comes in waves 44 | max_value = max_value.max(mic_value); 45 | sum += mic_value as u64; 46 | count += 1; 47 | 48 | if count % 100 == 0 { 49 | let avg = (sum / count) as u16; 50 | let image = [ 51 | [if max_value > avg + 100 { 1 } else { 0 }; 5], 52 | [if max_value > avg + 80 { 1 } else { 0 }; 5], 53 | [if max_value > avg + 60 { 1 } else { 0 }; 5], 54 | [if max_value > avg + 40 { 1 } else { 0 }; 5], 55 | [if max_value > avg + 20 { 1 } else { 0 }; 5], 56 | ]; 57 | display.show(&mut timer, image, 10); 58 | max_value = 0; 59 | } 60 | } 61 | } 62 | 63 | panic!("End"); 64 | } 65 | -------------------------------------------------------------------------------- /examples/rng-hal/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | use defmt_rtt as _; 5 | use panic_halt as _; 6 | 7 | use core::{cell::RefCell, ops::DerefMut}; 8 | 9 | use cortex_m::interrupt::Mutex; 10 | use cortex_m_rt::entry; 11 | 12 | use microbit::{ 13 | hal::{clocks, rng, rtc}, 14 | pac::{self, interrupt}, 15 | }; 16 | 17 | use rand::{RngCore, SeedableRng}; 18 | use rand_pcg::Pcg32; 19 | 20 | static RTC: Mutex>>> = Mutex::new(RefCell::new(None)); 21 | static RNG: Mutex>> = Mutex::new(RefCell::new(None)); 22 | 23 | #[entry] 24 | fn main() -> ! { 25 | let mut cp = pac::CorePeripherals::take().unwrap(); 26 | let p = microbit::Peripherals::take().unwrap(); 27 | 28 | cortex_m::interrupt::free(move |cs| { 29 | /* Start low frequency clock */ 30 | clocks::Clocks::new(p.CLOCK).start_lfclk(); 31 | 32 | defmt::info!("Welcome to the random number printer!"); 33 | 34 | /* Use hardware RNG to initialise PRNG */ 35 | let mut rng = rng::Rng::new(p.RNG); 36 | 37 | let mut seed: [u8; 16] = [0; 16]; 38 | 39 | /* Read 4 bytes of data from hardware RNG */ 40 | rng.random(&mut seed); 41 | 42 | let rng = Pcg32::from_seed(seed); 43 | *RNG.borrow(cs).borrow_mut() = Some(rng); 44 | 45 | let mut rtc = rtc::Rtc::new(p.RTC0, 1).unwrap(); 46 | rtc.enable_counter(); 47 | rtc.enable_interrupt(rtc::RtcInterrupt::Tick, Some(&mut cp.NVIC)); 48 | rtc.enable_event(rtc::RtcInterrupt::Tick); 49 | 50 | *RTC.borrow(cs).borrow_mut() = Some(rtc); 51 | 52 | pac::NVIC::unpend(pac::Interrupt::RTC0); 53 | }); 54 | 55 | loop { 56 | continue; 57 | } 58 | } 59 | 60 | // Define an exception, i.e. function to call when exception occurs. Here if our timer 61 | // trips, we'll print out a random number to the serial port 62 | #[interrupt] 63 | fn RTC0() { 64 | /* Enter critical section */ 65 | cortex_m::interrupt::free(|cs| { 66 | if let (Some(rtc), &mut Some(ref mut rng)) = ( 67 | RTC.borrow(cs).borrow().as_ref(), 68 | RNG.borrow(cs).borrow_mut().deref_mut(), 69 | ) { 70 | defmt::info!("{:?}", rng.next_u32()); 71 | rtc.reset_event(rtc::RtcInterrupt::Tick); 72 | } 73 | }); 74 | } 75 | -------------------------------------------------------------------------------- /examples/display-blocking/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use defmt_rtt as _; 5 | use panic_halt as _; 6 | 7 | use cortex_m_rt::entry; 8 | use embedded_hal::delay::DelayNs; 9 | use microbit::{board::Board, display::blocking::Display, hal::Timer}; 10 | 11 | #[entry] 12 | fn main() -> ! { 13 | if let Some(board) = Board::take() { 14 | let mut timer = Timer::new(board.TIMER0); 15 | let mut display = Display::new(board.display_pins); 16 | 17 | #[allow(non_snake_case)] 18 | let letter_I = [ 19 | [0, 1, 1, 1, 0], 20 | [0, 0, 1, 0, 0], 21 | [0, 0, 1, 0, 0], 22 | [0, 0, 1, 0, 0], 23 | [0, 1, 1, 1, 0], 24 | ]; 25 | 26 | let heart = [ 27 | [0, 1, 0, 1, 0], 28 | [1, 0, 1, 0, 1], 29 | [1, 0, 0, 0, 1], 30 | [0, 1, 0, 1, 0], 31 | [0, 0, 1, 0, 0], 32 | ]; 33 | 34 | #[allow(non_snake_case)] 35 | let letter_R = [ 36 | [0, 1, 1, 0, 0], 37 | [0, 1, 0, 1, 0], 38 | [0, 1, 1, 0, 0], 39 | [0, 1, 0, 1, 0], 40 | [0, 1, 0, 1, 0], 41 | ]; 42 | 43 | #[allow(non_snake_case)] 44 | let letter_u = [ 45 | [0, 0, 0, 0, 0], 46 | [0, 0, 0, 0, 0], 47 | [0, 1, 0, 1, 0], 48 | [0, 1, 0, 1, 0], 49 | [0, 1, 1, 1, 0], 50 | ]; 51 | 52 | #[allow(non_snake_case)] 53 | let letter_s = [ 54 | [0, 0, 0, 0, 0], 55 | [0, 0, 1, 1, 0], 56 | [0, 1, 0, 0, 0], 57 | [0, 0, 1, 0, 0], 58 | [0, 1, 1, 1, 0], 59 | ]; 60 | 61 | #[allow(non_snake_case)] 62 | let letter_t = [ 63 | [0, 0, 1, 0, 0], 64 | [0, 1, 1, 1, 0], 65 | [0, 0, 1, 0, 0], 66 | [0, 0, 1, 0, 0], 67 | [0, 0, 1, 0, 0], 68 | ]; 69 | loop { 70 | display.show(&mut timer, letter_I, 1000); 71 | display.show(&mut timer, heart, 1000); 72 | display.show(&mut timer, letter_R, 1000); 73 | display.show(&mut timer, letter_u, 1000); 74 | display.show(&mut timer, letter_s, 1000); 75 | display.show(&mut timer, letter_t, 1000); 76 | display.clear(); 77 | timer.delay_ms(250_u32); 78 | } 79 | } 80 | 81 | panic!("End"); 82 | } 83 | -------------------------------------------------------------------------------- /examples/gpio-hal-printbuttons/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | use defmt_rtt as _; 5 | use panic_halt as _; 6 | 7 | use core::cell::RefCell; 8 | 9 | use cortex_m::interrupt::Mutex; 10 | use cortex_m_rt::entry; 11 | use microbit::{ 12 | board::Board, 13 | hal::gpiote::Gpiote, 14 | pac::{self, interrupt}, 15 | }; 16 | 17 | static GPIO: Mutex>> = Mutex::new(RefCell::new(None)); 18 | 19 | #[entry] 20 | fn main() -> ! { 21 | let board = Board::take().unwrap(); 22 | 23 | let gpiote = Gpiote::new(board.GPIOTE); 24 | 25 | let channel0 = gpiote.channel0(); 26 | channel0 27 | .input_pin(&board.buttons.button_a.degrade()) 28 | .hi_to_lo() 29 | .enable_interrupt(); 30 | channel0.reset_events(); 31 | 32 | let channel1 = gpiote.channel1(); 33 | channel1 34 | .input_pin(&board.buttons.button_b.degrade()) 35 | .hi_to_lo() 36 | .enable_interrupt(); 37 | channel1.reset_events(); 38 | 39 | cortex_m::interrupt::free(move |cs| { 40 | /* Enable external GPIO interrupts */ 41 | unsafe { 42 | pac::NVIC::unmask(pac::Interrupt::GPIOTE); 43 | } 44 | pac::NVIC::unpend(pac::Interrupt::GPIOTE); 45 | 46 | *GPIO.borrow(cs).borrow_mut() = Some(gpiote); 47 | 48 | defmt::info!("Welcome to the buttons demo. Press buttons A and/or B for some action."); 49 | }); 50 | 51 | loop { 52 | continue; 53 | } 54 | } 55 | 56 | // Define an interrupt, i.e. function to call when exception occurs. Here if we receive an 57 | // interrupt from a button press, the function will be called 58 | #[interrupt] 59 | fn GPIOTE() { 60 | /* Enter critical section */ 61 | cortex_m::interrupt::free(|cs| { 62 | if let Some(gpiote) = GPIO.borrow(cs).borrow().as_ref() { 63 | let buttonapressed = gpiote.channel0().is_event_triggered(); 64 | let buttonbpressed = gpiote.channel1().is_event_triggered(); 65 | 66 | /* Print buttons to the serial console */ 67 | defmt::info!( 68 | "Button pressed {:?}", 69 | match (buttonapressed, buttonbpressed) { 70 | (false, false) => "", 71 | (true, false) => "A", 72 | (false, true) => "B", 73 | (true, true) => "A + B", 74 | } 75 | ); 76 | 77 | /* Clear events */ 78 | gpiote.channel0().reset_events(); 79 | gpiote.channel1().reset_events(); 80 | } 81 | }); 82 | } 83 | -------------------------------------------------------------------------------- /examples/serial-direct-echo/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | use panic_halt as _; 5 | 6 | use core::str; 7 | use cortex_m_rt::entry; 8 | 9 | #[entry] 10 | fn main() -> ! { 11 | if let Some(p) = microbit::Peripherals::take() { 12 | /* Configure RX and TX pins accordingly */ 13 | p.GPIO.pin_cnf[24].write(|w| w.pull().pullup().dir().output()); 14 | p.GPIO.pin_cnf[25].write(|w| w.pull().disabled().dir().input()); 15 | 16 | let uart0 = p.UART0; 17 | /* Tell UART which pins to use for sending and receiving */ 18 | uart0.pseltxd.write(|w| unsafe { w.bits(24) }); 19 | uart0.pselrxd.write(|w| unsafe { w.bits(25) }); 20 | 21 | /* Set a typical baud rate of 115200 */ 22 | uart0.baudrate.write(|w| w.baudrate().baud115200()); 23 | 24 | /* Enable UART function */ 25 | uart0.enable.write(|w| w.enable().enabled()); 26 | 27 | /* Print a nice hello message */ 28 | let _ = write_uart0(&uart0, "Please type characters to echo:\r\n"); 29 | 30 | /* Fire up receiving task */ 31 | uart0.tasks_startrx.write(|w| unsafe { w.bits(1) }); 32 | 33 | /* Endless loop */ 34 | loop { 35 | /* Busy wait for reception of data */ 36 | while uart0.events_rxdrdy.read().bits() == 0 {} 37 | 38 | /* We're going to pick up the data soon, let's signal the buffer is already waiting for 39 | * more data */ 40 | uart0.events_rxdrdy.write(|w| unsafe { w.bits(0) }); 41 | 42 | /* Read one 8bit value */ 43 | let c = uart0.rxd.read().bits() as u8; 44 | 45 | /* What comes in must go out, we don't care what it is */ 46 | let _ = write_uart0(&uart0, unsafe { str::from_utf8_unchecked(&[c; 1]) }); 47 | } 48 | } 49 | 50 | loop { 51 | continue; 52 | } 53 | } 54 | 55 | fn write_uart0(uart0: µbit::pac::UART0, s: &str) -> core::fmt::Result { 56 | /* Start UART sender */ 57 | uart0.tasks_starttx.write(|w| unsafe { w.bits(1) }); 58 | 59 | for c in s.as_bytes() { 60 | /* Write the current character to the output register */ 61 | uart0.txd.write(|w| unsafe { w.bits(u32::from(*c)) }); 62 | 63 | /* Wait until the UART is clear to send */ 64 | while uart0.events_txdrdy.read().bits() == 0 {} 65 | 66 | /* And then reset it for the next round */ 67 | uart0.events_txdrdy.write(|w| unsafe { w.bits(0) }); 68 | } 69 | 70 | /* Stop UART sender */ 71 | uart0.tasks_stoptx.write(|w| unsafe { w.bits(1) }); 72 | Ok(()) 73 | } 74 | -------------------------------------------------------------------------------- /examples/analog-v1/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use defmt_rtt as _; 5 | use panic_halt as _; 6 | 7 | use cortex_m_rt::entry; 8 | use microbit::{ 9 | board::Board, 10 | display::blocking::Display, 11 | hal::{adc::AdcConfig, Adc, Timer}, 12 | }; 13 | 14 | #[entry] 15 | fn main() -> ! { 16 | if let Some(board) = Board::take() { 17 | let mut timer = Timer::new(board.TIMER0); 18 | let mut display = Display::new(board.display_pins); 19 | let mut adc: Adc = Adc::new(board.ADC, AdcConfig::default()); 20 | let mut anapin = board.edge.e00.into_floating_input(); // PAD1 21 | 22 | let numbers = [ 23 | [ 24 | [0, 0, 1, 0, 0], 25 | [0, 1, 0, 1, 0], 26 | [0, 1, 0, 1, 0], 27 | [0, 1, 0, 1, 0], 28 | [0, 0, 1, 0, 0], 29 | ], 30 | [ 31 | [0, 0, 1, 0, 0], 32 | [0, 1, 1, 0, 0], 33 | [0, 0, 1, 0, 0], 34 | [0, 0, 1, 0, 0], 35 | [0, 0, 1, 0, 0], 36 | ], 37 | [ 38 | [0, 0, 1, 0, 0], 39 | [0, 1, 0, 1, 0], 40 | [0, 0, 1, 0, 0], 41 | [0, 1, 0, 0, 0], 42 | [0, 1, 1, 1, 0], 43 | ], 44 | [ 45 | [0, 1, 1, 0, 0], 46 | [0, 0, 0, 1, 0], 47 | [0, 0, 1, 0, 0], 48 | [0, 0, 0, 1, 0], 49 | [0, 1, 1, 0, 0], 50 | ], 51 | [ 52 | [0, 1, 0, 0, 0], 53 | [1, 0, 0, 0, 0], 54 | [1, 0, 1, 0, 0], 55 | [1, 1, 1, 1, 0], 56 | [0, 0, 1, 0, 0], 57 | ], 58 | ]; 59 | 60 | let sign_plus = [ 61 | [0, 0, 1, 0, 0], 62 | [0, 0, 1, 0, 0], 63 | [1, 1, 1, 1, 1], 64 | [0, 0, 1, 0, 0], 65 | [0, 0, 1, 0, 0], 66 | ]; 67 | 68 | loop { 69 | let analog_value = adc.read_channel(&mut anapin); 70 | let n_iter = numbers.iter(); 71 | let mut count: usize = 0; 72 | for n_val in n_iter { 73 | if count == usize::from(i16::unsigned_abs(analog_value / 100)) { 74 | display.show(&mut timer, *n_val, 10); 75 | break; 76 | } 77 | count += 1; 78 | } 79 | if count == numbers.len() { 80 | display.show(&mut timer, sign_plus, 10); 81 | } 82 | } 83 | } 84 | panic!("End"); 85 | } 86 | -------------------------------------------------------------------------------- /examples/rng-direct/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | use defmt_rtt as _; 5 | use panic_halt as _; 6 | 7 | use core::cell::RefCell; 8 | 9 | use microbit::pac::{self, interrupt}; 10 | 11 | use cortex_m::interrupt::Mutex; 12 | use cortex_m_rt::entry; 13 | 14 | static RNG: Mutex>> = Mutex::new(RefCell::new(None)); 15 | static RTC: Mutex>> = Mutex::new(RefCell::new(None)); 16 | 17 | #[entry] 18 | fn main() -> ! { 19 | if let Some(p) = microbit::Peripherals::take() { 20 | p.CLOCK.tasks_lfclkstart.write(|w| unsafe { w.bits(1) }); 21 | 22 | while p.CLOCK.events_lfclkstarted.read().bits() == 0 {} 23 | 24 | /* And then set it back to 0 again, just because ?!? */ 25 | p.CLOCK.events_lfclkstarted.write(|w| unsafe { w.bits(0) }); 26 | 27 | defmt::info!("Welcome to the random number printer!"); 28 | 29 | p.RTC0.prescaler.write(|w| unsafe { w.bits(1) }); 30 | p.RTC0.evtenset.write(|w| w.tick().set_bit()); 31 | p.RTC0.intenset.write(|w| w.tick().set_bit()); 32 | p.RTC0.tasks_start.write(|w| unsafe { w.bits(1) }); 33 | 34 | /* Enable error correction for better values */ 35 | p.RNG.config.write(|w| w.dercen().enabled()); 36 | 37 | /* Enable random number generation */ 38 | p.RNG.tasks_start.write(|w| unsafe { w.bits(1) }); 39 | 40 | cortex_m::interrupt::free(move |cs| { 41 | *RTC.borrow(cs).borrow_mut() = Some(p.RTC0); 42 | *RNG.borrow(cs).borrow_mut() = Some(p.RNG); 43 | }); 44 | 45 | unsafe { 46 | pac::NVIC::unmask(pac::Interrupt::RTC0); 47 | } 48 | pac::NVIC::unpend(pac::Interrupt::RTC0); 49 | } 50 | 51 | loop { 52 | continue; 53 | } 54 | } 55 | 56 | // Define an exception, i.e. function to call when exception occurs. Here if our timer 57 | // trips, we'll print some random number 58 | #[interrupt] 59 | fn RTC0() { 60 | /* Enter critical section */ 61 | cortex_m::interrupt::free(|cs| { 62 | if let Some(rtc) = RTC.borrow(cs).borrow().as_ref() { 63 | let count = if let Some(rng) = RNG.borrow(cs).borrow().as_ref() { 64 | /* Let's wait until we have a new random value */ 65 | while rng.events_valrdy.read().bits() == 0 {} 66 | 67 | let num = rng.value.read().bits(); 68 | 69 | /* Clear event for next random number value */ 70 | rng.events_valrdy.write(|w| unsafe { w.bits(0) }); 71 | 72 | num 73 | } else { 74 | 0 75 | }; 76 | 77 | defmt::info!("{:?}", count); 78 | rtc.events_tick.write(|w| unsafe { w.bits(0) }); 79 | } 80 | }); 81 | } 82 | -------------------------------------------------------------------------------- /examples/magnetometer/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use defmt_rtt as _; 5 | use panic_halt as _; 6 | 7 | use cortex_m_rt::entry; 8 | use embedded_hal::delay::DelayNs; 9 | use lsm303agr::{ 10 | interface::I2cInterface, mode::MagOneShot, AccelMode, AccelOutputDataRate, Lsm303agr, 11 | }; 12 | use microbit::hal::Timer; 13 | 14 | #[cfg(feature = "v1")] 15 | use microbit::{ 16 | hal::twi, 17 | pac::{twi0::frequency::FREQUENCY_A, TWI0}, 18 | }; 19 | #[cfg(feature = "v2")] 20 | use microbit::{ 21 | hal::twim, 22 | pac::{twim0::frequency::FREQUENCY_A, TWIM0}, 23 | }; 24 | 25 | #[entry] 26 | fn main() -> ! { 27 | let board = microbit::Board::take().unwrap(); 28 | let mut timer = Timer::new(board.TIMER0); 29 | 30 | #[cfg(feature = "v1")] 31 | let i2c = { twi::Twi::new(board.TWI0, board.i2c.into(), FREQUENCY_A::K100) }; 32 | 33 | #[cfg(feature = "v2")] 34 | let i2c = { twim::Twim::new(board.TWIM0, board.i2c_internal.into(), FREQUENCY_A::K100) }; 35 | 36 | let mut sensor = Lsm303agr::new_with_i2c(i2c); 37 | if let Ok(id) = sensor.accelerometer_id() { 38 | if !id.is_correct() { 39 | defmt::panic!("Accelerometer had unexpected ID {:#x}", id.raw()); 40 | } 41 | } else { 42 | defmt::panic!("Error getting accelerometer ID"); 43 | } 44 | sensor.init().unwrap(); 45 | 46 | defmt::info!("normal mode"); 47 | sensor 48 | .set_accel_mode_and_odr(&mut timer, AccelMode::Normal, AccelOutputDataRate::Hz50) 49 | .unwrap(); 50 | timer.delay_ms(1000_u32); 51 | get_data(&mut sensor); 52 | 53 | defmt::info!("low power mode"); 54 | sensor 55 | .set_accel_mode_and_odr(&mut timer, AccelMode::LowPower, AccelOutputDataRate::Hz50) 56 | .unwrap(); 57 | timer.delay_ms(1000_u32); 58 | get_data(&mut sensor); 59 | 60 | defmt::info!("high resolution mode"); 61 | sensor 62 | .set_accel_mode_and_odr( 63 | &mut timer, 64 | AccelMode::HighResolution, 65 | AccelOutputDataRate::Hz50, 66 | ) 67 | .unwrap(); 68 | timer.delay_ms(1000_u32); 69 | get_data(&mut sensor); 70 | 71 | loop { 72 | timer.delay_ms(100_u32); 73 | get_data(&mut sensor); 74 | } 75 | } 76 | 77 | #[cfg(feature = "v1")] 78 | type Sensor = Lsm303agr>, MagOneShot>; 79 | 80 | #[cfg(feature = "v2")] 81 | type Sensor = Lsm303agr>, MagOneShot>; 82 | 83 | fn get_data(sensor: &mut Sensor) { 84 | loop { 85 | if sensor.accel_status().unwrap().xyz_new_data() { 86 | let data = sensor.acceleration().unwrap(); 87 | defmt::info!("x {} y {} z {}", data.x_mg(), data.y_mg(), data.z_mg()); 88 | return; 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /examples/display-text-rtic/src/main.rs: -------------------------------------------------------------------------------- 1 | //! An example of scrolling static text. 2 | //! 3 | //! It uses `TIMER1` to drive the display, and `RTC0` to animate the text. 4 | #![no_main] 5 | #![no_std] 6 | 7 | use defmt_rtt as _; 8 | use panic_halt as _; 9 | 10 | use rtic::app; 11 | 12 | #[app(device = microbit::pac, peripherals = true)] 13 | mod app { 14 | 15 | use microbit::{ 16 | board::Board, 17 | display::nonblocking::{Display, Frame, MicrobitFrame}, 18 | hal::{ 19 | clocks::Clocks, 20 | rtc::{Rtc, RtcInterrupt}, 21 | }, 22 | pac, 23 | }; 24 | use microbit_text::scrolling::Animate; 25 | use microbit_text::scrolling_text::ScrollingStaticText; 26 | 27 | const MESSAGE: &[u8] = b"Hello, world!"; 28 | 29 | #[shared] 30 | struct Shared { 31 | display: Display, 32 | } 33 | 34 | #[local] 35 | struct Local { 36 | anim_timer: Rtc, 37 | scroller: ScrollingStaticText, 38 | } 39 | 40 | #[init] 41 | fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { 42 | let board = Board::new(cx.device, cx.core); 43 | 44 | // Starting the low-frequency clock (needed for RTC to work) 45 | Clocks::new(board.CLOCK).start_lfclk(); 46 | 47 | // RTC at 16Hz (32_768 / (2047 + 1)) 48 | // 16Hz; 62.5ms period 49 | let mut rtc0 = Rtc::new(board.RTC0, 2047).unwrap(); 50 | rtc0.enable_event(RtcInterrupt::Tick); 51 | rtc0.enable_interrupt(RtcInterrupt::Tick, None); 52 | rtc0.enable_counter(); 53 | 54 | let display = Display::new(board.TIMER1, board.display_pins); 55 | 56 | let mut scroller = ScrollingStaticText::default(); 57 | scroller.set_message(MESSAGE); 58 | 59 | ( 60 | Shared { display }, 61 | Local { 62 | anim_timer: rtc0, 63 | scroller, 64 | }, 65 | init::Monotonics(), 66 | ) 67 | } 68 | 69 | #[task(binds = TIMER1, priority = 2, shared = [display])] 70 | fn timer1(mut cx: timer1::Context) { 71 | cx.shared 72 | .display 73 | .lock(|display| display.handle_display_event()); 74 | } 75 | 76 | #[task(binds = RTC0, priority = 1, shared = [display], 77 | local = [anim_timer, scroller, 78 | frame: MicrobitFrame = MicrobitFrame::default()])] 79 | fn rtc0(cx: rtc0::Context) { 80 | let mut shared = cx.shared; 81 | let local = cx.local; 82 | local.anim_timer.reset_event(RtcInterrupt::Tick); 83 | if !local.scroller.is_finished() { 84 | local.scroller.tick(); 85 | local.frame.set(local.scroller); 86 | shared.display.lock(|display| { 87 | display.show_frame(local.frame); 88 | }); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /examples/display-rtic/src/main.rs: -------------------------------------------------------------------------------- 1 | //! A complete working example. 2 | //! 3 | //! This requires `cortex-m-rtic` v1.0. 4 | //! 5 | //! It uses `TIMER1` to drive the display, and `RTC0` to update a simple 6 | //! animated image. 7 | #![no_main] 8 | #![no_std] 9 | 10 | use defmt_rtt as _; 11 | use panic_halt as _; 12 | 13 | use rtic::app; 14 | 15 | #[app(device = microbit::pac, peripherals = true)] 16 | mod app { 17 | 18 | use microbit::{ 19 | board::Board, 20 | display::nonblocking::{Display, GreyscaleImage}, 21 | hal::{ 22 | clocks::Clocks, 23 | rtc::{Rtc, RtcInterrupt}, 24 | }, 25 | pac, 26 | }; 27 | 28 | fn heart_image(inner_brightness: u8) -> GreyscaleImage { 29 | let b = inner_brightness; 30 | GreyscaleImage::new(&[ 31 | [0, 7, 0, 7, 0], 32 | [7, b, 7, b, 7], 33 | [7, b, b, b, 7], 34 | [0, 7, b, 7, 0], 35 | [0, 0, 7, 0, 0], 36 | ]) 37 | } 38 | 39 | #[shared] 40 | struct Shared { 41 | display: Display, 42 | } 43 | 44 | #[local] 45 | struct Local { 46 | anim_timer: Rtc, 47 | } 48 | 49 | #[init] 50 | fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { 51 | let board = Board::new(cx.device, cx.core); 52 | 53 | // Starting the low-frequency clock (needed for RTC to work) 54 | Clocks::new(board.CLOCK).start_lfclk(); 55 | 56 | // RTC at 16Hz (32_768 / (2047 + 1)) 57 | // 16Hz; 62.5ms period 58 | let mut rtc0 = Rtc::new(board.RTC0, 2047).unwrap(); 59 | rtc0.enable_event(RtcInterrupt::Tick); 60 | rtc0.enable_interrupt(RtcInterrupt::Tick, None); 61 | rtc0.enable_counter(); 62 | 63 | let display = Display::new(board.TIMER1, board.display_pins); 64 | ( 65 | Shared { display }, 66 | Local { anim_timer: rtc0 }, 67 | init::Monotonics(), 68 | ) 69 | } 70 | 71 | #[task(binds = TIMER1, priority = 2, shared = [display])] 72 | fn timer1(mut cx: timer1::Context) { 73 | cx.shared 74 | .display 75 | .lock(|display| display.handle_display_event()); 76 | } 77 | 78 | #[task(binds = RTC0, priority = 1, shared = [display], 79 | local = [anim_timer, step: u8 = 0])] 80 | fn rtc0(cx: rtc0::Context) { 81 | let mut shared = cx.shared; 82 | let local = cx.local; 83 | 84 | local.anim_timer.reset_event(RtcInterrupt::Tick); 85 | 86 | let inner_brightness = match *local.step { 87 | 0..=8 => 9 - *local.step, 88 | 9..=12 => 0, 89 | _ => unreachable!(), 90 | }; 91 | 92 | shared.display.lock(|display| { 93 | display.show(&heart_image(inner_brightness)); 94 | }); 95 | 96 | *local.step += 1; 97 | if *local.step == 13 { 98 | *local.step = 0 99 | }; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /microbit-common/src/display/nonblocking/matrix.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of [`Matrix`] and [`Frame`] for the micro:bit's LED display. 2 | //! 3 | //! This module describes the correspondence between the visible layout of 4 | //! micro:bit's LEDs and the pins controlling them. 5 | //! 6 | //! [`Matrix`]: tiny_led_matrix::Matrix 7 | //! [`Frame`]: tiny_led_matrix::Frame 8 | 9 | use crate::gpio::{NUM_COLS, NUM_ROWS}; 10 | use tiny_led_matrix::{Frame, Matrix, RowPlan}; 11 | 12 | /// Implementation of [`Matrix`] for the microbit's LED display. 13 | /// 14 | /// [`Matrix`]: tiny_led_matrix::Matrix 15 | pub struct MicrobitMatrix(); 16 | 17 | /// Gives the LED (x, y) coordinates for a given pin row and column. 18 | /// The origin is in the top-left. 19 | #[cfg(feature = "v1")] 20 | const MICROBIT_LED_LAYOUT: [[Option<(usize, usize)>; 3]; 9] = [ 21 | [Some((0, 0)), Some((4, 2)), Some((2, 4))], 22 | [Some((2, 0)), Some((0, 2)), Some((4, 4))], 23 | [Some((4, 0)), Some((2, 2)), Some((0, 4))], 24 | [Some((4, 3)), Some((1, 0)), Some((0, 1))], 25 | [Some((3, 3)), Some((3, 0)), Some((1, 1))], 26 | [Some((2, 3)), Some((3, 4)), Some((2, 1))], 27 | [Some((1, 3)), Some((1, 4)), Some((3, 1))], 28 | [Some((0, 3)), None, Some((4, 1))], 29 | [Some((1, 2)), None, Some((3, 2))], 30 | ]; 31 | 32 | impl Matrix for MicrobitMatrix { 33 | /// The number of pins connected to LED columns (3). 34 | const MATRIX_COLS: usize = NUM_COLS; 35 | /// The number of pins connected to LED rows (9). 36 | const MATRIX_ROWS: usize = NUM_ROWS; 37 | /// The number of visible LED columns (5). 38 | const IMAGE_COLS: usize = 5; 39 | /// The number of visible LED rows (5). 40 | const IMAGE_ROWS: usize = 5; 41 | 42 | #[cfg(feature = "v1")] 43 | fn image_coordinates(col: usize, row: usize) -> Option<(usize, usize)> { 44 | MICROBIT_LED_LAYOUT[col][row] 45 | } 46 | 47 | #[cfg(feature = "v2")] 48 | fn image_coordinates(col: usize, row: usize) -> Option<(usize, usize)> { 49 | Some((col, row)) 50 | } 51 | } 52 | 53 | /// A 'Compiled' representation of a 5×5 image to be displayed. 54 | /// 55 | /// Use the [`.set()`](`Frame::set`) method to store an image (something 56 | /// implementing [`Render`]) in the frame. 57 | /// 58 | /// Note you'll have to `use microbit::display::Frame` to make `set()` 59 | /// available. 60 | /// 61 | /// [`Frame`]: tiny_led_matrix::Frame 62 | /// [`Render`]: tiny_led_matrix::Render 63 | #[derive(Copy, Clone, Debug)] 64 | pub struct MicrobitFrame([RowPlan; MicrobitFrame::ROWS]); 65 | 66 | impl MicrobitFrame { 67 | /// Returns a new frame, initially blank. 68 | pub const fn default() -> MicrobitFrame { 69 | MicrobitFrame([RowPlan::default(); MicrobitFrame::ROWS]) 70 | } 71 | } 72 | 73 | impl Default for MicrobitFrame { 74 | /// Returns a new frame, initially blank. 75 | fn default() -> MicrobitFrame { 76 | MicrobitFrame::default() 77 | } 78 | } 79 | 80 | impl Frame for MicrobitFrame { 81 | type Mtx = MicrobitMatrix; 82 | 83 | fn row_plan(&self, row: usize) -> &RowPlan { 84 | &self.0[row] 85 | } 86 | 87 | fn row_plan_mut(&mut self, row: usize) -> &mut RowPlan { 88 | &mut self.0[row] 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /examples/analog/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use defmt_rtt as _; 5 | use panic_halt as _; 6 | 7 | use cortex_m_rt::entry; 8 | use microbit::{ 9 | adc::{Adc, AdcConfig, Default}, 10 | board::Board, 11 | display::blocking::Display, 12 | hal::Timer, 13 | }; 14 | 15 | #[entry] 16 | fn main() -> ! { 17 | if let Some(board) = Board::take() { 18 | let mut timer = Timer::new(board.TIMER0); 19 | let mut display = Display::new(board.display_pins); 20 | let mut adc = Adc::new(board.ADC, AdcConfig::default_10bit()); 21 | let mut anapin = board.edge.e00.into_floating_input(); // PAD0 22 | 23 | let numbers = [ 24 | [ 25 | [0, 0, 1, 0, 0], 26 | [0, 1, 0, 1, 0], 27 | [0, 1, 0, 1, 0], 28 | [0, 1, 0, 1, 0], 29 | [0, 0, 1, 0, 0], 30 | ], 31 | [ 32 | [0, 0, 1, 0, 0], 33 | [0, 1, 1, 0, 0], 34 | [0, 0, 1, 0, 0], 35 | [0, 0, 1, 0, 0], 36 | [0, 0, 1, 0, 0], 37 | ], 38 | [ 39 | [0, 0, 1, 0, 0], 40 | [0, 1, 0, 1, 0], 41 | [0, 0, 1, 0, 0], 42 | [0, 1, 0, 0, 0], 43 | [0, 1, 1, 1, 0], 44 | ], 45 | [ 46 | [0, 1, 1, 0, 0], 47 | [0, 0, 0, 1, 0], 48 | [0, 0, 1, 0, 0], 49 | [0, 0, 0, 1, 0], 50 | [0, 1, 1, 0, 0], 51 | ], 52 | [ 53 | [0, 1, 0, 0, 0], 54 | [1, 0, 0, 0, 0], 55 | [1, 0, 1, 0, 0], 56 | [1, 1, 1, 1, 0], 57 | [0, 0, 1, 0, 0], 58 | ], 59 | ]; 60 | 61 | let sign_plus = [ 62 | [0, 0, 1, 0, 0], 63 | [0, 0, 1, 0, 0], 64 | [1, 1, 1, 1, 1], 65 | [0, 0, 1, 0, 0], 66 | [0, 0, 1, 0, 0], 67 | ]; 68 | 69 | #[cfg(feature = "v2")] 70 | #[allow(non_snake_case)] 71 | let letter_E = [ 72 | [0, 1, 1, 1, 0], 73 | [0, 1, 0, 0, 0], 74 | [0, 1, 1, 0, 0], 75 | [0, 1, 0, 0, 0], 76 | [0, 1, 1, 1, 0], 77 | ]; 78 | 79 | loop { 80 | let analog = adc.read_channel(&mut anapin); 81 | #[cfg(feature = "v2")] 82 | let Ok(analog) = analog 83 | else { 84 | display.show(&mut timer, letter_E, 10); 85 | continue; 86 | }; 87 | let n_iter = numbers.iter(); 88 | let mut count: usize = 0; 89 | for n_val in n_iter { 90 | if count == usize::from(i16::unsigned_abs(analog / 100)) { 91 | display.show(&mut timer, *n_val, 10); 92 | break; 93 | } 94 | count += 1; 95 | } 96 | if count == numbers.len() { 97 | display.show(&mut timer, sign_plus, 10); 98 | } 99 | } 100 | } 101 | panic!("End"); 102 | } 103 | -------------------------------------------------------------------------------- /examples/analog-v2/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use defmt_rtt as _; 5 | use panic_halt as _; 6 | 7 | use cortex_m_rt::entry; 8 | use microbit::{ 9 | board::Board, 10 | display::blocking::Display, 11 | hal::{saadc::SaadcConfig, Saadc, Timer}, 12 | }; 13 | 14 | #[entry] 15 | fn main() -> ! { 16 | if let Some(board) = Board::take() { 17 | let mut timer = Timer::new(board.TIMER0); 18 | let mut display = Display::new(board.display_pins); 19 | let mut adc: Saadc = Saadc::new(board.ADC, SaadcConfig::default()); 20 | let mut anapin = board.edge.e00.into_floating_input(); // PAD1 21 | 22 | let numbers = [ 23 | [ 24 | [0, 0, 1, 0, 0], 25 | [0, 1, 0, 1, 0], 26 | [0, 1, 0, 1, 0], 27 | [0, 1, 0, 1, 0], 28 | [0, 0, 1, 0, 0], 29 | ], 30 | [ 31 | [0, 0, 1, 0, 0], 32 | [0, 1, 1, 0, 0], 33 | [0, 0, 1, 0, 0], 34 | [0, 0, 1, 0, 0], 35 | [0, 0, 1, 0, 0], 36 | ], 37 | [ 38 | [0, 0, 1, 0, 0], 39 | [0, 1, 0, 1, 0], 40 | [0, 0, 1, 0, 0], 41 | [0, 1, 0, 0, 0], 42 | [0, 1, 1, 1, 0], 43 | ], 44 | [ 45 | [0, 1, 1, 0, 0], 46 | [0, 0, 0, 1, 0], 47 | [0, 0, 1, 0, 0], 48 | [0, 0, 0, 1, 0], 49 | [0, 1, 1, 0, 0], 50 | ], 51 | [ 52 | [0, 1, 0, 0, 0], 53 | [1, 0, 0, 0, 0], 54 | [1, 0, 1, 0, 0], 55 | [1, 1, 1, 1, 0], 56 | [0, 0, 1, 0, 0], 57 | ], 58 | ]; 59 | 60 | let sign_plus = [ 61 | [0, 0, 1, 0, 0], 62 | [0, 0, 1, 0, 0], 63 | [1, 1, 1, 1, 1], 64 | [0, 0, 1, 0, 0], 65 | [0, 0, 1, 0, 0], 66 | ]; 67 | 68 | #[allow(non_snake_case)] 69 | let letter_E = [ 70 | [0, 1, 1, 1, 0], 71 | [0, 1, 0, 0, 0], 72 | [0, 1, 1, 0, 0], 73 | [0, 1, 0, 0, 0], 74 | [0, 1, 1, 1, 0], 75 | ]; 76 | 77 | loop { 78 | let analog = adc.read_channel(&mut anapin); 79 | match analog { 80 | Ok(v) => { 81 | let n_iter = numbers.iter(); 82 | let mut count: usize = 0; 83 | for n_val in n_iter { 84 | if count == usize::from(i16::unsigned_abs(v / 100)) { 85 | display.show(&mut timer, *n_val, 10); 86 | break; 87 | } 88 | count += 1; 89 | } 90 | if count == numbers.len() { 91 | display.show(&mut timer, sign_plus, 10); 92 | } 93 | } 94 | Err(_e) => display.show(&mut timer, letter_E, 10), 95 | } 96 | } 97 | } 98 | panic!("End"); 99 | } 100 | -------------------------------------------------------------------------------- /examples/display-nonblocking/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | use defmt_rtt as _; 5 | use panic_halt as _; 6 | 7 | use core::cell::RefCell; 8 | use cortex_m::interrupt::Mutex; 9 | use cortex_m_rt::entry; 10 | 11 | use microbit::{ 12 | board::Board, 13 | display::nonblocking::{Display, GreyscaleImage}, 14 | hal::{ 15 | clocks::Clocks, 16 | rtc::{Rtc, RtcInterrupt}, 17 | }, 18 | pac::{self, interrupt, RTC0, TIMER1}, 19 | }; 20 | 21 | fn heart_image(inner_brightness: u8) -> GreyscaleImage { 22 | let b = inner_brightness; 23 | GreyscaleImage::new(&[ 24 | [0, 7, 0, 7, 0], 25 | [7, b, 7, b, 7], 26 | [7, b, b, b, 7], 27 | [0, 7, b, 7, 0], 28 | [0, 0, 7, 0, 0], 29 | ]) 30 | } 31 | 32 | // We use TIMER1 to drive the display, and RTC0 to update the animation. 33 | // We set the TIMER1 interrupt to a higher priority than RTC0. 34 | 35 | static DISPLAY: Mutex>>> = Mutex::new(RefCell::new(None)); 36 | static ANIM_TIMER: Mutex>>> = Mutex::new(RefCell::new(None)); 37 | 38 | #[entry] 39 | fn main() -> ! { 40 | if let Some(mut board) = Board::take() { 41 | // Starting the low-frequency clock (needed for RTC to work) 42 | Clocks::new(board.CLOCK).start_lfclk(); 43 | 44 | // RTC at 16Hz (32_768 / (2047 + 1)) 45 | // 62.5ms period 46 | let mut rtc0 = Rtc::new(board.RTC0, 2047).unwrap(); 47 | rtc0.enable_event(RtcInterrupt::Tick); 48 | rtc0.enable_interrupt(RtcInterrupt::Tick, None); 49 | rtc0.enable_counter(); 50 | 51 | // Create display 52 | let display = Display::new(board.TIMER1, board.display_pins); 53 | 54 | cortex_m::interrupt::free(move |cs| { 55 | *DISPLAY.borrow(cs).borrow_mut() = Some(display); 56 | *ANIM_TIMER.borrow(cs).borrow_mut() = Some(rtc0); 57 | }); 58 | unsafe { 59 | board.NVIC.set_priority(pac::Interrupt::RTC0, 64); 60 | board.NVIC.set_priority(pac::Interrupt::TIMER1, 128); 61 | pac::NVIC::unmask(pac::Interrupt::RTC0); 62 | pac::NVIC::unmask(pac::Interrupt::TIMER1); 63 | } 64 | } 65 | 66 | loop { 67 | continue; 68 | } 69 | } 70 | 71 | #[interrupt] 72 | fn TIMER1() { 73 | cortex_m::interrupt::free(|cs| { 74 | if let Some(display) = DISPLAY.borrow(cs).borrow_mut().as_mut() { 75 | display.handle_display_event(); 76 | } 77 | }); 78 | } 79 | 80 | #[interrupt] 81 | unsafe fn RTC0() { 82 | static mut STEP: u8 = 0; 83 | 84 | cortex_m::interrupt::free(|cs| { 85 | if let Some(rtc) = ANIM_TIMER.borrow(cs).borrow_mut().as_mut() { 86 | rtc.reset_event(RtcInterrupt::Tick); 87 | } 88 | }); 89 | 90 | let inner_brightness = match *STEP { 91 | 0..=8 => 9 - *STEP, 92 | 9..=12 => 0, 93 | _ => unreachable!(), 94 | }; 95 | 96 | cortex_m::interrupt::free(|cs| { 97 | if let Some(display) = DISPLAY.borrow(cs).borrow_mut().as_mut() { 98 | display.show(&heart_image(inner_brightness)); 99 | } 100 | }); 101 | 102 | *STEP += 1; 103 | if *STEP == 13 { 104 | *STEP = 0 105 | }; 106 | } 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # microbit 2 | 3 | _microbit_ contains everything required getting started using Rust to create firmwares for the fabulous 4 | [BBC micro:bit](https://microbit.org) microcontroller board. This little board has everything and a kitchen sink built-in, 5 | even a capable debugging interface. 6 | 7 | ## Getting started 8 | 9 | All you need to start programming this device is: 10 | 11 | * A BBC micro:bit board 12 | * A computer (known to work with macOS, Linux and Windows) 13 | * A bit of open source software 14 | 15 | ### Know your version 16 | 17 | The micro:bit comes in different versions. There is a separate crate for each major board version. See the table below to identify 18 | which crate you need to use. 19 | 20 | | Crate | Board version | Board image | Docs | crates.io | target | 21 | | ------------------------------ | ------------- | ----------- | ---- | --------- | ------ | 22 | | [`microbit`](./microbit) | V1 | [](https://github.com/microbit-foundation/microbit-svg/blob/master/microbit-drawing-back-1-5.png) | [![docs.rs](https://docs.rs/microbit/badge.svg)](https://docs.rs/microbit) | [![crates.io](https://img.shields.io/crates/d/microbit.svg)](https://crates.io/crates/microbit) | `thumbv6m-none-eabi` | 23 | | [`microbit-v2`](./microbit-v2) | V2 | [](https://github.com/microbit-foundation/microbit-svg/blob/master/microbit-drawing-back-2.png) | [![docs.rs](https://docs.rs/microbit-v2/badge.svg)](https://docs.rs/microbit-v2) | [![crates.io](https://img.shields.io/crates/d/microbit-v2.svg)](https://crates.io/crates/microbit-v2) | `thumbv7em-none-eabihf` | 24 | 25 | ### Install dependencies 26 | 27 | The examples make use of some of the fantastic tooling from the [knurling](https://knurling.ferrous-systems.com/) and [probe-rs](https://probe.rs/) projects. 28 | In order to run the examples you need to install [`probe-rs`](https://probe.rs/docs/getting-started/installation) 29 | and [`flip-link`](https://github.com/knurling-rs/flip-link#installation). 30 | 31 | ```bash 32 | > cargo install probe-rs-tools flip-link 33 | ``` 34 | 35 | ### Run an example 36 | 37 | The first thing to try is one of the [examples](./examples) in this repository. Plug in your micro:bit and 38 | run one of the commands below. 39 | 40 | *For micro:bit V1* 41 | ```bash 42 | > cargo run --release --manifest-path ./examples/display-blocking/Cargo.toml --features v1 --target thumbv6m-none-eabi 43 | ``` 44 | 45 | *For micro:bit V2* 46 | ```bash 47 | > cargo run --release --manifest-path ./examples/display-blocking/Cargo.toml --features v2 --target thumbv7em-none-eabihf 48 | ``` 49 | 50 | You should see a lot of build output, the orange LED on the back of the micro:bit should flash quickly, and 51 | a message should appear on the LED display. 52 | 53 | Congratulations! You've flashed your first Rust program onto your micro:bit! 54 | 55 | ## Further reading 56 | 57 | A guide to embedded development with Rust on the _micro:bit_ using this crate can be found in the [MicroRust book](https://droogmic.github.io/microrust/). 58 | 59 | Other useful resources: 60 | - [micro:bit developer community](https://tech.microbit.org) 61 | - [micro:bit hardware overview](https://tech.microbit.org/hardware/) 62 | - [nrf-hal](https://github.com/nrf-rs/nrf-hal#readme) the hardware abstraction layer (HAL) this repository is based on 63 | 64 | ## License 65 | 66 | [0-clause BSD license](LICENSE-0BSD.txt). 67 | -------------------------------------------------------------------------------- /microbit-common/src/display/nonblocking/image.rs: -------------------------------------------------------------------------------- 1 | //! Static 5×5 greyscale and black-and-white images. 2 | 3 | use tiny_led_matrix::{Render, MAX_BRIGHTNESS}; 4 | 5 | /// A 5×5 image supporting the full range of brightnesses for each LED. 6 | /// 7 | /// Uses 25 bytes of storage. 8 | #[derive(Copy, Clone, Debug)] 9 | pub struct GreyscaleImage([[u8; 5]; 5]); 10 | 11 | impl GreyscaleImage { 12 | /// Constructs a GreyscaleImage from an array of brightnesses. 13 | /// 14 | /// The data should be an array of 5 rows (top first), each of which is an 15 | /// array of 5 brightness values (left first). 16 | /// 17 | /// # Example 18 | /// 19 | /// ```no_run 20 | /// # use microbit_common as microbit; 21 | /// # use microbit::display::nonblocking::GreyscaleImage; 22 | /// const GREY_HEART: GreyscaleImage = GreyscaleImage::new(&[ 23 | /// [0, 9, 0, 9, 0], 24 | /// [9, 5, 9, 5, 9], 25 | /// [9, 5, 5, 5, 9], 26 | /// [0, 9, 5, 9, 0], 27 | /// [0, 0, 9, 0, 0], 28 | /// ]); 29 | /// ``` 30 | pub const fn new(data: &[[u8; 5]; 5]) -> GreyscaleImage { 31 | GreyscaleImage(*data) 32 | } 33 | 34 | /// Construct a GreyscaleImage with all LEDs turned off. 35 | pub const fn blank() -> GreyscaleImage { 36 | GreyscaleImage([[0; 5]; 5]) 37 | } 38 | } 39 | 40 | impl Render for GreyscaleImage { 41 | fn brightness_at(&self, x: usize, y: usize) -> u8 { 42 | self.0[y][x] 43 | } 44 | } 45 | 46 | impl Render for &GreyscaleImage { 47 | fn brightness_at(&self, x: usize, y: usize) -> u8 { 48 | GreyscaleImage::brightness_at(self, x, y) 49 | } 50 | } 51 | 52 | /// A 5×5 image supporting only two levels of brightness (on and off). 53 | /// 54 | /// Uses 5 bytes of storage. 55 | /// 56 | /// For display, each pixel is treated as having brightness either 0 or 57 | /// MAX_BRIGHTNESS. 58 | #[derive(Copy, Clone, Debug)] 59 | pub struct BitImage([u8; 5]); 60 | 61 | impl BitImage { 62 | /// Constructs a BitImage from an array of brightnesses. 63 | /// 64 | /// The data should be an array of 5 rows (top first), each of which is an 65 | /// array of 5 values (left first). Each value should be either 0 or 1. 66 | /// 67 | /// # Example 68 | /// 69 | /// ```no_run 70 | /// # use microbit_common as microbit; 71 | /// # use microbit::display::nonblocking::BitImage; 72 | /// const HEART: BitImage = BitImage::new(&[ 73 | /// [0, 1, 0, 1, 0], 74 | /// [1, 0, 1, 0, 1], 75 | /// [1, 0, 0, 0, 1], 76 | /// [0, 1, 0, 1, 0], 77 | /// [0, 0, 1, 0, 0], 78 | /// ]); 79 | /// ``` 80 | pub const fn new(im: &[[u8; 5]; 5]) -> BitImage { 81 | // FIXME: can we reject values other than 0 or 1? 82 | const fn row_byte(row: [u8; 5]) -> u8 { 83 | row[0] | (row[1] << 1) | (row[2] << 2) | (row[3] << 3) | (row[4] << 4) 84 | } 85 | BitImage([ 86 | row_byte(im[0]), 87 | row_byte(im[1]), 88 | row_byte(im[2]), 89 | row_byte(im[3]), 90 | row_byte(im[4]), 91 | ]) 92 | } 93 | 94 | /// Returns a new blank BitImage. 95 | /// 96 | /// All pixel values are 0. 97 | pub const fn blank() -> BitImage { 98 | BitImage([0; 5]) 99 | } 100 | } 101 | 102 | impl Render for BitImage { 103 | fn brightness_at(&self, x: usize, y: usize) -> u8 { 104 | let rowdata = self.0[y]; 105 | if rowdata & (1 << x) != 0 { 106 | MAX_BRIGHTNESS 107 | } else { 108 | 0 109 | } 110 | } 111 | } 112 | 113 | impl Render for &BitImage { 114 | fn brightness_at(&self, x: usize, y: usize) -> u8 { 115 | BitImage::brightness_at(self, x, y) 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /microbit-common/src/display/nonblocking/timer.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of [`DisplayTimer`] for the nRF51 `TIMER`s. 2 | //! 3 | //! [`DisplayTimer`]: tiny_led_matrix::DisplayTimer 4 | 5 | use tiny_led_matrix::DisplayTimer; 6 | 7 | use crate::hal::timer::Instance; 8 | 9 | /// A TIMER peripheral programmed to manage the display. 10 | /// 11 | /// `MicrobitDisplayTimer` instances implement the [`DisplayTimer`] trait. 12 | /// 13 | /// The timer is set to 16-bit mode. 14 | /// 15 | /// For micro:bit v1: uses a 62.5kHz clock clock (16 µs ticks). 16 | /// The primary cycle takes 6ms. 17 | /// 18 | /// For micro:bit v2: uses a 135kHz clock (8 µs ticks). 19 | /// The primary cycle takes 3ms. 20 | /// 21 | /// Uses CC0 for the primary cycle and CC1 for the secondary alarm. Uses the 22 | /// CC0_CLEAR shortcut to implement the primary cycle. 23 | /// 24 | /// [`DisplayTimer`]: tiny_led_matrix::DisplayTimer 25 | pub struct MicrobitDisplayTimer(T); 26 | 27 | impl MicrobitDisplayTimer { 28 | /// Returns a new `MicrobitDisplayTimer` wrapping the passed TIMER. 29 | /// 30 | /// Takes ownership of the TIMER peripheral. 31 | pub fn new(timer: T) -> MicrobitDisplayTimer { 32 | MicrobitDisplayTimer(timer) 33 | } 34 | 35 | /// Gives the underlying `nrf51::TIMER`*n* instance back. 36 | pub fn free(self) -> T { 37 | self.0 38 | } 39 | } 40 | 41 | impl DisplayTimer for MicrobitDisplayTimer { 42 | fn initialise_cycle(&mut self, ticks: u16) { 43 | let timer0 = self.0.as_timer0(); 44 | // stop and reset timer 45 | timer0.tasks_stop.write(|w| unsafe { w.bits(1) }); 46 | timer0.tasks_clear.write(|w| unsafe { w.bits(1) }); 47 | 48 | // set as 16 bits 49 | timer0.bitmode.write(|w| w.bitmode()._16bit()); 50 | 51 | #[cfg(feature = "v1")] 52 | // set frequency to 62500Hz 53 | let prescaler = 8; 54 | #[cfg(feature = "v2")] 55 | // set frequency to 135000Hz 56 | let prescaler = 7; 57 | timer0.prescaler.write(|w| unsafe { w.bits(prescaler) }); 58 | 59 | // set compare register 60 | timer0.cc[0].write(|w| unsafe { w.bits(ticks.into()) }); 61 | 62 | // enable auto clear 63 | timer0.shorts.write(|w| w.compare0_clear().enabled()); 64 | 65 | // enable compare interrupt 66 | timer0.intenset.write(|w| w.compare0().set()); 67 | 68 | // start 69 | timer0.tasks_start.write(|w| unsafe { w.bits(1) }); 70 | // maybe? 71 | // timer0.tasks_start.write(|w| w.tasks_start().set_bit()); 72 | } 73 | 74 | fn enable_secondary(&mut self) { 75 | self.0.as_timer0().intenset.write(|w| w.compare1().set()); 76 | } 77 | 78 | fn disable_secondary(&mut self) { 79 | self.0 80 | .as_timer0() 81 | .intenclr 82 | .write(|w| w.compare1().set_bit()); 83 | } 84 | 85 | fn program_secondary(&mut self, ticks: u16) { 86 | #[cfg(feature = "v1")] 87 | self.0.as_timer0().cc[1].write(|w| unsafe { w.bits(ticks.into()) }); 88 | #[cfg(feature = "v2")] 89 | self.0.as_timer0().cc[1].write(|w| unsafe { w.cc().bits(ticks.into()) }); 90 | } 91 | 92 | fn check_primary(&mut self) -> bool { 93 | // poll compare event 94 | let reg = &self.0.as_timer0().events_compare[0]; 95 | let fired = reg.read().bits() != 0; 96 | if fired { 97 | reg.reset(); 98 | } 99 | fired 100 | } 101 | 102 | fn check_secondary(&mut self) -> bool { 103 | // poll compare event 104 | let reg = &self.0.as_timer0().events_compare[1]; 105 | let fired = reg.read().bits() != 0; 106 | if fired { 107 | reg.reset(); 108 | } 109 | fired 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /examples/v2-speaker/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | use defmt_rtt as _; 5 | use panic_halt as _; 6 | 7 | use core::cell::RefCell; 8 | use cortex_m::interrupt::Mutex; 9 | use cortex_m_rt::entry; 10 | use embedded_hal::digital::OutputPin; 11 | use microbit::{ 12 | hal::{ 13 | clocks::Clocks, 14 | gpio, pwm, 15 | rtc::{Rtc, RtcInterrupt}, 16 | time::Hertz, 17 | }, 18 | pac::{self, interrupt}, 19 | Board, 20 | }; 21 | 22 | static RTC: Mutex>>> = Mutex::new(RefCell::new(None)); 23 | static SPEAKER: Mutex>>> = Mutex::new(RefCell::new(None)); 24 | 25 | #[entry] 26 | fn main() -> ! { 27 | if let Some(mut board) = Board::take() { 28 | cortex_m::interrupt::free(move |cs| { 29 | // NB: The LF CLK pin is used by the speaker 30 | let _clocks = Clocks::new(board.CLOCK) 31 | .enable_ext_hfosc() 32 | .set_lfclk_src_synth() 33 | .start_lfclk(); 34 | 35 | let mut rtc = Rtc::new(board.RTC0, 511).unwrap(); 36 | rtc.enable_counter(); 37 | rtc.enable_interrupt(RtcInterrupt::Tick, Some(&mut board.NVIC)); 38 | rtc.enable_event(RtcInterrupt::Tick); 39 | 40 | *RTC.borrow(cs).borrow_mut() = Some(rtc); 41 | 42 | let mut speaker_pin = board.speaker_pin.into_push_pull_output(gpio::Level::High); 43 | let _ = speaker_pin.set_low(); 44 | 45 | // Use the PWM peripheral to generate a waveform for the speaker 46 | let speaker = pwm::Pwm::new(board.PWM0); 47 | speaker 48 | // output the waveform on the speaker pin 49 | .set_output_pin(pwm::Channel::C0, speaker_pin.degrade()) 50 | // Use prescale by 16 to achive darker sounds 51 | .set_prescaler(pwm::Prescaler::Div16) 52 | // Initial frequency 53 | .set_period(Hertz(1u32)) 54 | // Configure for up and down counter mode 55 | .set_counter_mode(pwm::CounterMode::UpAndDown) 56 | // Set maximum duty cycle 57 | .set_max_duty(32767) 58 | // enable PWM 59 | .enable(); 60 | 61 | speaker 62 | .set_seq_refresh(pwm::Seq::Seq0, 0) 63 | .set_seq_end_delay(pwm::Seq::Seq0, 0); 64 | 65 | // Configure 50% duty cycle 66 | let max_duty = speaker.max_duty(); 67 | speaker.set_duty_on_common(max_duty / 2); 68 | 69 | *SPEAKER.borrow(cs).borrow_mut() = Some(speaker); 70 | 71 | // Configure RTC interrupt 72 | unsafe { 73 | pac::NVIC::unmask(pac::Interrupt::RTC0); 74 | } 75 | pac::NVIC::unpend(pac::Interrupt::RTC0); 76 | }); 77 | } 78 | 79 | loop { 80 | continue; 81 | } 82 | } 83 | 84 | const STOP_FREQUENCY: u32 = 500; 85 | 86 | // RTC interrupt, exectued for each RTC tick 87 | #[interrupt] 88 | fn RTC0() { 89 | static mut FREQUENCY: u32 = 1; 90 | /* Enter critical section */ 91 | cortex_m::interrupt::free(|cs| { 92 | /* Borrow devices */ 93 | if let (Some(speaker), Some(rtc)) = ( 94 | SPEAKER.borrow(cs).borrow().as_ref(), 95 | RTC.borrow(cs).borrow().as_ref(), 96 | ) { 97 | if *FREQUENCY < STOP_FREQUENCY { 98 | // Configure the new frequency, must not be zero. 99 | // Will change the max_duty 100 | speaker.set_period(Hertz(*FREQUENCY)); 101 | } else { 102 | // Continue at frequency 103 | speaker.set_period(Hertz(STOP_FREQUENCY)); 104 | } 105 | // Restart the PWM at 50% duty cycle 106 | let max_duty = speaker.max_duty(); 107 | speaker.set_duty_on_common(max_duty / 2); 108 | if *FREQUENCY >= STOP_FREQUENCY + 250 { 109 | defmt::info!("Fin"); 110 | // Stop speaker and RTC 111 | speaker.disable(); 112 | rtc.disable_counter(); 113 | }; 114 | // Clear the RTC interrupt 115 | rtc.reset_event(RtcInterrupt::Tick); 116 | } 117 | }); 118 | // Increase the frequency 119 | *FREQUENCY += 1; 120 | } 121 | -------------------------------------------------------------------------------- /examples/servo/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use defmt_rtt as _; 5 | use panic_halt as _; 6 | 7 | use core::cell::RefCell; 8 | use cortex_m::interrupt::Mutex; 9 | use cortex_m_rt::entry; 10 | 11 | use microbit::{ 12 | board::Board, 13 | hal::{ 14 | gpio::Level, 15 | gpiote::*, 16 | pac::{self, interrupt, TIMER0}, 17 | ppi::{self, ConfigurablePpi, Ppi}, 18 | }, 19 | }; 20 | 21 | static SERVO_TIMER: Mutex>> = Mutex::new(RefCell::new(None)); 22 | 23 | #[entry] 24 | fn main() -> ! { 25 | if let Some(board) = Board::take() { 26 | let gpiote = Gpiote::new(board.GPIOTE); 27 | // Servo output pins 28 | let servopin1 = board.edge.e01.into_push_pull_output(Level::Low).degrade(); // PAD2 29 | let servopin2 = board.edge.e02.into_push_pull_output(Level::Low).degrade(); // PAD3 30 | 31 | // Output channel for Servo 1 32 | gpiote 33 | .channel0() 34 | .output_pin(servopin1) 35 | .task_out_polarity(TaskOutPolarity::Toggle) 36 | .init_low(); 37 | gpiote.channel0().task_out().write(|w| unsafe { w.bits(1) }); 38 | // Output channel for Servo 2 39 | gpiote 40 | .channel1() 41 | .output_pin(servopin2) 42 | .task_out_polarity(TaskOutPolarity::Toggle) 43 | .init_low(); 44 | gpiote.channel1().task_out().write(|w| unsafe { w.bits(1) }); 45 | 46 | let ppi_channels = ppi::Parts::new(board.PPI); 47 | // Set both servo outputs high form Timer0 CC[0] 48 | // Set each servo output low from the respective Timer0 CC[1] and CC[2] 49 | // Each timer can run 3 Servos 50 | let mut ppi0 = ppi_channels.ppi0; 51 | ppi0.set_task_endpoint(gpiote.channel0().task_out()); 52 | ppi0.set_event_endpoint(&board.TIMER0.events_compare[0]); 53 | ppi0.enable(); 54 | let mut ppi1 = ppi_channels.ppi1; 55 | ppi1.set_task_endpoint(gpiote.channel0().task_out()); 56 | ppi1.set_event_endpoint(&board.TIMER0.events_compare[1]); 57 | ppi1.enable(); 58 | let mut ppi2 = ppi_channels.ppi2; 59 | ppi2.set_task_endpoint(gpiote.channel1().task_out()); 60 | ppi2.set_event_endpoint(&board.TIMER0.events_compare[0]); 61 | ppi2.enable(); 62 | let mut ppi3 = ppi_channels.ppi3; 63 | ppi3.set_task_endpoint(gpiote.channel1().task_out()); 64 | ppi3.set_event_endpoint(&board.TIMER0.events_compare[2]); 65 | ppi3.enable(); 66 | 67 | // The Timer PAC is used directly as the HAL does not give full access to all registers 68 | board.TIMER0.mode.write(|w| unsafe { w.bits(0) }); 69 | board.TIMER0.bitmode.write(|w| unsafe { w.bits(0) }); 70 | // CC[0] every 20 ms (50 Hz) 71 | board.TIMER0.cc[0].write(|w| unsafe { w.bits(20000) }); 72 | board.TIMER0.shorts.write(|w| unsafe { w.bits(1) }); 73 | // Servo duty cycle is from 0.5 ms to 2.5 ms with 1.5 ms for center position 74 | board.TIMER0.cc[1].write(|w| unsafe { w.bits(1500) }); 75 | board.TIMER0.cc[2].write(|w| unsafe { w.bits(1500) }); 76 | board.TIMER0.tasks_start.write(|w| unsafe { w.bits(1) }); 77 | // Timer0 interrupt on CC[0] 78 | board.TIMER0.intenset.write(|w| unsafe { w.bits(1 << 16) }); 79 | 80 | cortex_m::interrupt::free(move |cs| { 81 | *SERVO_TIMER.borrow(cs).borrow_mut() = Some(board.TIMER0); 82 | }); 83 | unsafe { 84 | pac::NVIC::unmask(pac::Interrupt::TIMER0); 85 | } 86 | 87 | loop {} 88 | } 89 | panic!("End"); 90 | } 91 | 92 | #[interrupt] 93 | fn TIMER0() { 94 | // Change Servo position at the start of the duty cycle. Then there is no race condition 95 | // between changing the duty cycle and a CC event. 96 | static mut SPEED: i32 = 1500; 97 | static mut DIRECTION: i32 = 1; 98 | match SPEED { 99 | i32::MIN..=500 => *DIRECTION = 1, 100 | 2500..=i32::MAX => *DIRECTION = -1, 101 | _ => {} 102 | } 103 | *SPEED += *DIRECTION; 104 | cortex_m::interrupt::free(|cs| { 105 | // if let Some(cc_value) = CC_VALUE.borrow(cs).borrow().as_ref() { 106 | if let Some(timer) = SERVO_TIMER.borrow(cs).borrow_mut().as_mut() { 107 | //timer.cc[1].write(|w|unsafe { w.bits(u32::try_from(*cc_value).unwrap_or(1500)) }); 108 | let set_speed = u32::try_from(*SPEED).unwrap_or(1500); 109 | timer.cc[1].write(|w| unsafe { w.bits(set_speed) }); 110 | timer.cc[2].write(|w| unsafe { w.bits(set_speed) }); 111 | timer.events_compare[0].write(|w| unsafe { w.bits(0) }); 112 | } 113 | //} 114 | }); 115 | } 116 | -------------------------------------------------------------------------------- /xtask/src/bump.rs: -------------------------------------------------------------------------------- 1 | //! This has been copied pretty much wholesale from https://github.com/nrf-rs/nrf-hal/blob/master/xtask/src/lib.rs 2 | use super::CRATES; 3 | use chrono::Local; 4 | use std::fs; 5 | 6 | fn file_replace(path: &str, from: &str, to: &str, dry_run: bool) { 7 | let old_contents = fs::read_to_string(path).unwrap(); 8 | let new_contents = old_contents.replacen(from, to, 1); 9 | if old_contents == new_contents { 10 | panic!("failed to replace `{}` -> `{}` in `{}`", from, to, path); 11 | } 12 | 13 | if !dry_run { 14 | fs::write(path, new_contents).unwrap(); 15 | } 16 | } 17 | 18 | /// Bumps the versions of all crates and the changelog to `new_version`. 19 | /// 20 | /// Dependency declarations are updated automatically. `html_root_url` is updated automatically. 21 | pub fn bump_versions(new_version: &str, dry_run: bool) { 22 | let common_toml_path = "microbit-common/Cargo.toml"; 23 | let toml = fs::read_to_string(common_toml_path).unwrap(); 24 | 25 | let needle = "version = \""; 26 | let version_pos = toml.find(needle).unwrap() + needle.len(); 27 | let version_rest = &toml[version_pos..]; 28 | let end_pos = version_rest.find('"').unwrap(); 29 | let old_version = &version_rest[..end_pos]; 30 | 31 | { 32 | // Bump the changelog first, also check that it isn't empty. 33 | let changelog_path = "CHANGELOG.md"; 34 | let changelog = fs::read_to_string(changelog_path).unwrap(); 35 | // (ignore empty changelog when this is a dry_run, since that runs in normal CI) 36 | assert!( 37 | dry_run || !changelog.contains("(no changes)"), 38 | "changelog contains `(no changes)`; please fill it" 39 | ); 40 | 41 | // Prepend empty "[Unreleased]" section, promote the current one. 42 | let today = Local::now().date_naive().format("%Y-%m-%d").to_string(); 43 | let from = String::from("## [Unreleased]"); 44 | let to = format!( 45 | "## [Unreleased]\n\n(no changes)\n\n## [{}] - {}", 46 | new_version, today 47 | ); 48 | file_replace(changelog_path, &from, &to, dry_run); 49 | 50 | // Replace the Unreleased link 51 | let from = format!( 52 | r#"[Unreleased]: https://github.com/nrf-rs/microbit/compare/v{old_version}...HEAD"#, 53 | old_version = old_version, 54 | ); 55 | let to = format!( 56 | "[Unreleased]: https://github.com/nrf-rs/microbit/compare/v{new_version}...HEAD\n\ 57 | [{new_version}]: https://github.com/nrf-rs/microbit/compare/v{old_version}...v{new_version}", 58 | new_version = new_version, 59 | old_version = old_version, 60 | ); 61 | file_replace(changelog_path, &from, &to, dry_run); 62 | } 63 | 64 | { 65 | println!("microbit-common: {} -> {}", old_version, new_version); 66 | 67 | // Bump `microbit-common`'s version. 68 | let from = format!(r#"version = "{}""#, old_version); 69 | let to = format!(r#"version = "{}""#, new_version); 70 | file_replace("microbit-common/Cargo.toml", &from, &to, dry_run); 71 | 72 | // Bump the `html_root_url`. 73 | let from = format!( 74 | r#"#![doc(html_root_url = "https://docs.rs/microbit-common/{old_version}")]"#, 75 | old_version = old_version 76 | ); 77 | let to = format!( 78 | r#"#![doc(html_root_url = "https://docs.rs/microbit-common/{new_version}")]"#, 79 | new_version = new_version 80 | ); 81 | let librs_path = "microbit-common/src/lib.rs"; 82 | file_replace(librs_path, &from, &to, dry_run); 83 | } 84 | 85 | for (crate_name, _, _) in CRATES { 86 | println!("{}: {} -> {}", crate_name, old_version, new_version); 87 | let toml_path = format!("{}/Cargo.toml", crate_name); 88 | 89 | // Bump the crate's version. 90 | let from = format!(r#"version = "{}""#, old_version); 91 | let to = format!(r#"version = "{}""#, new_version); 92 | file_replace(&toml_path, &from, &to, dry_run); 93 | 94 | // Bump the crate's dependency on `microbit-common`. 95 | let from = format!(r#"version = "={}""#, old_version); 96 | let to = format!(r#"version = "={}""#, new_version); 97 | file_replace(&toml_path, &from, &to, dry_run); 98 | 99 | // Bump the crate's `html_root_url`. 100 | let from = format!( 101 | r#"#![doc(html_root_url = "https://docs.rs/{crate}/{old_version}")]"#, 102 | crate = crate_name, 103 | old_version = old_version 104 | ); 105 | let to = format!( 106 | r#"#![doc(html_root_url = "https://docs.rs/{crate}/{new_version}")]"#, 107 | crate = crate_name, 108 | new_version = new_version 109 | ); 110 | let librs_path = format!("{}/src/lib.rs", crate_name); 111 | file_replace(&librs_path, &from, &to, dry_run); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](http://keepachangelog.com/) 6 | and this project adheres to [Semantic Versioning](http://semver.org/). 7 | 8 | ## [Unreleased] 9 | 10 | (no changes) 11 | 12 | ## [0.16.0] - 2025-10-11 13 | 14 | - Remove dead link to microbit Rust on Windows blog post in README. 15 | - Bumped MSRV to 1.81.0. 16 | - Add metadata for docs.rs 17 | - Bumped dependencies in `examples/` to latest versions. 18 | - Update HAL crates to 0.19.0. 19 | 20 | ## [0.15.1] - 2024-08-05 21 | 22 | - Set MSRV for `microbit` and `microbit-v2` crates. 23 | - Bumped MSRV to 1.79.0. 24 | - Make various `I2C` `Pin` fields `pub` 25 | 26 | ## [0.15.0] - 2024-06-19 27 | 28 | - Update HAL crates to 0.18.0. 29 | - Update installation instructions for `probe-rs` 30 | 31 | ## [0.14.0] - 2024-04-18 32 | 33 | - Fix: non-blocking display on micro:bit V2 could spuriously light LEDs briefly 34 | - Fix the `blocking::Display::set_refresh_rate` calculation for the micro:bit V2 35 | - Double the non-blocking display refresh frequency for the micro:bit V2 36 | - Fix faulty doc test in `blocking.rs` 37 | - Update the non-blocking display documentation to better explain when methods 38 | should be called from within a critical section 39 | - Bump example dependencies to latest versions to fix build 40 | - Update examples to use RTIC 1.0 41 | - Add ADC for micro:bit V1 42 | - Add analog example 43 | - Increase minimum supported Rust version to 1.73 44 | - Added support for the real time counters RTC1 and RTC2 45 | - Add common types and structs for the edge connector pads and pins 46 | - Add common ADC types and initialization for ADC and SAADC 47 | - Common ADC example 48 | - Add support for PPI 49 | - Servo example using TIMER, GPIOTE and PPI 50 | - (NFC) GitHub CI changes 51 | - Feature: Exposed all remaining peripherals for both boards. 52 | - Update HAL crates to 0.17.1. 53 | - Update to `embedded-hal` 1.0. 54 | - Update magnetometer example to use `lsm303agr` 1.0. 55 | - Update debug tooling from probe-run to probe-rs 56 | 57 | ## [0.13.0] - 2022-05-24 58 | 59 | - Drop ble-beacon example (since rubble is now archived as unmaintained) 60 | - Bump `defmt` versions to 0.3 61 | - Increase minimum supported Rust version to 1.57 62 | - Add display-text-rtic example 63 | - Make `Board::new(p, cp)` public and fix RTIC example 64 | - Fix display-nonblocking example 65 | - Fix timer for LED-display (GreyscaleImage with a empty Row did not work) 66 | - Add SAADC and microphone_pins for micro:bit V2. 67 | - Add microphone example 68 | 69 | ## [0.12.0] - 2021-11-10 70 | 71 | ### Changed 72 | 73 | - Update dependencies nrf51-hal and nrf52833-hal to 0.14.0 74 | - Added TEMP field to board 75 | - Fixed Issue where columns 2,3 and 4 of the nonblocking display were swapped 76 | 77 | ## [0.11.0] - 2021-09-13 78 | 79 | ### Added 80 | 81 | - Added support for the thumbv7em-none-eabi target for microbit:v2 (same as 82 | thumbv7em-none-eabihf but without hardware floating point support) 83 | 84 | ### Changed 85 | 86 | - Rearrange LED display modules under the same root module and change their 87 | APIs to be more aligned with each other. 88 | - Add BLE Beacon demo. 89 | - Add a simple speaker demo for micro:bit V2. 90 | - Add Board struct following the pattern used in other nrf board support crates. 91 | - Add magnetometer example. 92 | - LEDs on the micro:bit V1 are now turned off per default 93 | - UART(E) is now exposed in the same way as I2C 94 | 95 | ## [0.10.1] - 2021-05-25 96 | 97 | Republished without changes to fix missing README.md in crates.io. 98 | 99 | ## [0.10.0] - 2021-05-13 100 | 101 | ### Added 102 | 103 | - Add support for micro:bit V2. This is a significant change that splits 104 | this repository into multiple crates. 105 | 106 | ## [0.9.0] - 2021-04-29 107 | 108 | ### Added 109 | 110 | - Add `microbit::gpio` module with pins mapped to micro:bit names 111 | - Refactor `microbit::display` and `microbit::led` to accept `gpio::Pins` 112 | - Make probe-run the default runner 113 | - Rewrite `serial_port` as a macro 114 | 115 | ### Fixed 116 | 117 | - Fix rustdoc warnings 118 | - Upgrade nrf51-hal to 0.12.1 119 | 120 | [Unreleased]: https://github.com/nrf-rs/microbit/compare/v0.16.0...HEAD 121 | [0.16.0]: https://github.com/nrf-rs/microbit/compare/v0.15.1...v0.16.0 122 | [0.15.1]: https://github.com/nrf-rs/microbit/compare/v0.15.0...v0.15.1 123 | [0.15.0]: https://github.com/nrf-rs/microbit/compare/v0.14.0...v0.15.0 124 | [0.14.0]: https://github.com/nrf-rs/microbit/compare/v0.13.0...v0.14.0 125 | [0.13.0]: https://github.com/nrf-rs/microbit/compare/v0.12.0...v0.13.0 126 | [0.12.0]: https://github.com/nrf-rs/microbit/compare/v0.11.0...v0.12.0 127 | [0.11.0]: https://github.com/nrf-rs/microbit/compare/v0.10.1...v0.11.0 128 | [0.10.1]: https://github.com/nrf-rs/microbit/compare/v0.10.0...v0.10.1 129 | [0.10.0]: https://github.com/nrf-rs/microbit/compare/v0.9.0...v0.10.0 130 | [0.9.0]: https://github.com/nrf-rs/microbit/compare/v0.8.0...v0.9.0 131 | -------------------------------------------------------------------------------- /microbit-common/src/v2/gpio.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::upper_case_acronyms, missing_docs)] 2 | use nrf52833_hal::gpio::{p0, p1, Floating, Input, OpenDrain, Output, Pin, PushPull}; 3 | 4 | /* GPIO pads */ 5 | pub type PAD0 = p0::P0_02; 6 | pub type PAD1 = p0::P0_03; 7 | pub type PAD2 = p0::P0_04; 8 | 9 | /* LED display */ 10 | pub const NUM_COLS: usize = 5; 11 | pub type COL1 = p0::P0_28>; 12 | pub type COL2 = p0::P0_11>; 13 | pub type COL3 = p0::P0_31>; 14 | pub type COL4 = p1::P1_05>; 15 | pub type COL5 = p0::P0_30>; 16 | 17 | pub const NUM_ROWS: usize = 5; 18 | pub type ROW1 = p0::P0_21>; 19 | pub type ROW2 = p0::P0_22>; 20 | pub type ROW3 = p0::P0_15>; 21 | pub type ROW4 = p0::P0_24>; 22 | pub type ROW5 = p0::P0_19>; 23 | 24 | /// GPIO pins connected to the LED matrix 25 | /// 26 | /// Use the [display_pins] macro for easier construction. 27 | pub struct DisplayPins { 28 | pub col1: COL1, 29 | pub col2: COL2, 30 | pub col3: COL3, 31 | pub col4: COL4, 32 | pub col5: COL5, 33 | pub row1: ROW1, 34 | pub row2: ROW2, 35 | pub row3: ROW3, 36 | pub row4: ROW4, 37 | pub row5: ROW5, 38 | } 39 | 40 | /// GPIO pins connected to the microphone 41 | pub struct MicrophonePins { 42 | pub mic_in: p0::P0_05>, 43 | pub mic_run: p0::P0_20>, 44 | } 45 | 46 | type LED = Pin>; 47 | 48 | impl DisplayPins { 49 | pub fn degrade(self) -> ([LED; NUM_COLS], [LED; NUM_ROWS]) { 50 | ( 51 | [ 52 | self.col1.degrade(), 53 | self.col2.degrade(), 54 | self.col3.degrade(), 55 | self.col4.degrade(), 56 | self.col5.degrade(), 57 | ], 58 | [ 59 | self.row1.degrade(), 60 | self.row2.degrade(), 61 | self.row3.degrade(), 62 | self.row4.degrade(), 63 | self.row5.degrade(), 64 | ], 65 | ) 66 | } 67 | } 68 | 69 | /// Create [DisplayPins] from a [GPIO Parts](crate::hal::gpio::p0::Parts) 70 | /// 71 | /// # Example 72 | /// 73 | /// ```no_run 74 | /// # use microbit_common as microbit; 75 | /// use microbit::{ 76 | /// display_pins, 77 | /// pac, 78 | /// hal::gpio::{p0::Parts as P0Parts, p1::Parts as P1Parts}, 79 | /// }; 80 | /// 81 | /// // take the peripherals 82 | /// let p = pac::Peripherals::take().unwrap(); 83 | /// // split off the P0 GPIO port 84 | /// let p0parts = P0Parts::new(p.P0); 85 | /// // split off the P1 GPIO port 86 | /// let p1parts = P1Parts::new(p.P1); 87 | /// 88 | /// let pins = display_pins!(p0parts, p1parts); 89 | /// ``` 90 | #[macro_export] 91 | macro_rules! display_pins { 92 | ( $p0parts:expr, $p1parts:expr ) => {{ 93 | use microbit::{gpio::DisplayPins, hal::gpio::Level}; 94 | 95 | DisplayPins { 96 | col1: $p0parts.p0_28.into_push_pull_output(Level::Low), 97 | col2: $p0parts.p0_11.into_push_pull_output(Level::Low), 98 | col3: $p0parts.p0_31.into_push_pull_output(Level::Low), 99 | col4: $p1parts.p1_05.into_push_pull_output(Level::Low), 100 | col5: $p0parts.p0_30.into_push_pull_output(Level::Low), 101 | row1: $p0parts.p0_21.into_push_pull_output(Level::Low), 102 | row2: $p0parts.p0_22.into_push_pull_output(Level::Low), 103 | row3: $p0parts.p0_15.into_push_pull_output(Level::Low), 104 | row4: $p0parts.p0_24.into_push_pull_output(Level::Low), 105 | row5: $p0parts.p0_19.into_push_pull_output(Level::Low), 106 | } 107 | }}; 108 | } 109 | 110 | /* buttons */ 111 | pub type BTN_A = p0::P0_14>; 112 | pub type BTN_B = p0::P0_23>; 113 | 114 | /* spi */ 115 | pub type MOSI = p0::P0_13; 116 | pub type MISO = p0::P0_01; 117 | pub type SCK = p0::P0_17; 118 | 119 | /* i2c - internal */ 120 | pub type INT_SCL = p0::P0_08>; 121 | pub type INT_SDA = p0::P0_16>; 122 | 123 | /* i2c - external */ 124 | pub type SCL = p0::P0_26>; 125 | pub type SDA = p1::P1_00>; 126 | 127 | /* uart */ 128 | pub type UART_TX = p0::P0_06>; 129 | pub type UART_RX = p1::P1_08>; 130 | 131 | /* speaker */ 132 | pub type SPEAKER = p0::P0_00>; 133 | 134 | /* edge connector */ 135 | pub type EDGE03 = COL3; 136 | pub type EDGE00 = PAD0; // <- big pad 1 137 | pub type EDGE04 = COL1; 138 | pub type EDGE05 = BTN_A; 139 | pub type EDGE06 = COL4; 140 | pub type EDGE07 = COL2; 141 | pub type EDGE01 = PAD1; // <- big pad 2 142 | pub type EDGE08 = p0::P0_10; 143 | pub type EDGE09 = p0::P0_09; 144 | pub type EDGE10 = COL5; 145 | pub type EDGE11 = BTN_B; 146 | pub type EDGE12 = p0::P0_12; 147 | pub type EDGE02 = PAD2; // <- big pad 3 148 | pub type EDGE13 = SCK; 149 | pub type EDGE14 = MISO; 150 | pub type EDGE15 = MOSI; 151 | pub type EDGE16 = p1::P1_02; 152 | // EDGE18 -> +V 153 | // EDGE19 -> +V 154 | // EDGE20 -> +V 155 | pub type EDGE19 = SCL; 156 | pub type EDGE20 = SDA; 157 | // EDGE23 -> GND 158 | // EDGE24 -> GND 159 | // EDGE25 -> GND 160 | -------------------------------------------------------------------------------- /microbit-common/src/v1/gpio.rs: -------------------------------------------------------------------------------- 1 | //! Named GPIO pin types 2 | //! 3 | //! This module maps the GPIO pin names as described in the 4 | //! [Pins and Signals section of the micro:bit site](https://tech.microbit.org/hardware/edgeconnector/#pins-and-signals) 5 | //! Where appropriate the pins are restricted with the appropriate `MODE` 6 | //! from `nrf-hal`. 7 | #![allow(clippy::upper_case_acronyms, missing_docs)] 8 | use crate::hal::gpio::{p0, Floating, Input, Output, Pin, PushPull}; 9 | 10 | /* GPIO pads */ 11 | pub type PAD0 = p0::P0_03; 12 | pub type PAD1 = p0::P0_02; 13 | pub type PAD2 = p0::P0_01; 14 | 15 | /* LED display */ 16 | pub const NUM_COLS: usize = 9; 17 | pub type COL1 = p0::P0_04>; 18 | pub type COL2 = p0::P0_05>; 19 | pub type COL3 = p0::P0_06>; 20 | pub type COL4 = p0::P0_07>; 21 | pub type COL5 = p0::P0_08>; 22 | pub type COL6 = p0::P0_09>; 23 | pub type COL7 = p0::P0_10>; 24 | pub type COL8 = p0::P0_11>; 25 | pub type COL9 = p0::P0_12>; 26 | 27 | pub const NUM_ROWS: usize = 3; 28 | pub type ROW1 = p0::P0_13>; 29 | pub type ROW2 = p0::P0_14>; 30 | pub type ROW3 = p0::P0_15>; 31 | 32 | /// GPIO pins connected to the LED matrix 33 | /// 34 | /// The pins are represented as a [3x9 matrix on the micro:bit 35 | /// V1](https://tech.microbit.org/hardware/1-5-revision/#display). 36 | /// This is mapped to the physical 5x5 LED matrix in the [crate::display] 37 | /// modules. 38 | /// 39 | /// Use the [display_pins] macro for easier construction. 40 | pub struct DisplayPins { 41 | pub col1: COL1, 42 | pub col2: COL2, 43 | pub col3: COL3, 44 | pub col4: COL4, 45 | pub col5: COL5, 46 | pub col6: COL6, 47 | pub col7: COL7, 48 | pub col8: COL8, 49 | pub col9: COL9, 50 | pub row1: ROW1, 51 | pub row2: ROW2, 52 | pub row3: ROW3, 53 | } 54 | 55 | type LED = Pin>; 56 | 57 | impl DisplayPins { 58 | pub fn degrade(self) -> ([LED; NUM_COLS], [LED; NUM_ROWS]) { 59 | ( 60 | [ 61 | self.col1.degrade(), 62 | self.col2.degrade(), 63 | self.col3.degrade(), 64 | self.col4.degrade(), 65 | self.col5.degrade(), 66 | self.col6.degrade(), 67 | self.col7.degrade(), 68 | self.col8.degrade(), 69 | self.col9.degrade(), 70 | ], 71 | [ 72 | self.row1.degrade(), 73 | self.row2.degrade(), 74 | self.row3.degrade(), 75 | ], 76 | ) 77 | } 78 | } 79 | 80 | /// Create [DisplayPins] from a [GPIO Parts](crate::hal::gpio::p0::Parts) 81 | /// 82 | /// # Example 83 | /// 84 | /// ```no_run 85 | /// # use microbit_common as microbit; 86 | /// use microbit::{ 87 | /// display_pins, 88 | /// pac, 89 | /// hal::gpio::p0::Parts as P0Parts, 90 | /// }; 91 | /// 92 | /// // take the peripherals 93 | /// let p = pac::Peripherals::take().unwrap(); 94 | /// // split off the P0 GPIO port 95 | /// let p0parts = P0Parts::new(p.GPIO); 96 | /// 97 | /// let pins = display_pins!(p0parts); 98 | /// ``` 99 | #[macro_export] 100 | macro_rules! display_pins { 101 | ( $p0parts:expr ) => {{ 102 | use microbit::{gpio::DisplayPins, hal::gpio::Level}; 103 | 104 | DisplayPins { 105 | row1: $p0parts.p0_13.into_push_pull_output(Level::Low), 106 | row2: $p0parts.p0_14.into_push_pull_output(Level::Low), 107 | row3: $p0parts.p0_15.into_push_pull_output(Level::Low), 108 | col1: $p0parts.p0_04.into_push_pull_output(Level::Low), 109 | col2: $p0parts.p0_05.into_push_pull_output(Level::Low), 110 | col3: $p0parts.p0_06.into_push_pull_output(Level::Low), 111 | col4: $p0parts.p0_07.into_push_pull_output(Level::Low), 112 | col5: $p0parts.p0_08.into_push_pull_output(Level::Low), 113 | col6: $p0parts.p0_09.into_push_pull_output(Level::Low), 114 | col7: $p0parts.p0_10.into_push_pull_output(Level::Low), 115 | col8: $p0parts.p0_11.into_push_pull_output(Level::Low), 116 | col9: $p0parts.p0_12.into_push_pull_output(Level::Low), 117 | } 118 | }}; 119 | } 120 | 121 | /* buttons */ 122 | pub type BTN_A = p0::P0_17>; 123 | pub type BTN_B = p0::P0_26>; 124 | 125 | /* spi */ 126 | pub type MOSI = p0::P0_21; 127 | pub type MISO = p0::P0_22; 128 | pub type SCK = p0::P0_23; 129 | 130 | /* i2c - shared external and internal */ 131 | pub type SCL = p0::P0_00>; 132 | pub type SDA = p0::P0_30>; 133 | 134 | /* uart */ 135 | pub type UART_TX = p0::P0_24>; 136 | pub type UART_RX = p0::P0_25>; 137 | 138 | /* edge connector */ 139 | pub type EDGE03 = COL1; 140 | pub type EDGE00 = PAD0; // <- big pad 1 141 | pub type EDGE04 = COL2; 142 | pub type EDGE05 = BTN_A; 143 | pub type EDGE06 = COL9; 144 | pub type EDGE07 = COL8; 145 | pub type EDGE01 = PAD1; // <- big pad 2 146 | pub type EDGE08 = p0::P0_18; 147 | pub type EDGE09 = COL7; 148 | pub type EDGE10 = COL3; 149 | pub type EDGE11 = BTN_B; 150 | pub type EDGE12 = p0::P0_20; 151 | pub type EDGE02 = PAD2; // <- big pad 3 152 | pub type EDGE13 = SCK; 153 | pub type EDGE14 = MISO; 154 | pub type EDGE15 = MOSI; 155 | pub type EDGE16 = p0::P0_16; 156 | // EDGE18 -> +V 157 | // EDGE19 -> +V 158 | // EDGE20 -> +V 159 | pub type EDGE19 = SCL; 160 | pub type EDGE20 = SDA; 161 | // EDGE23 -> GND 162 | // EDGE24 -> GND 163 | // EDGE25 -> GND 164 | -------------------------------------------------------------------------------- /microbit-common/src/display/nonblocking/control.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of [`DisplayControl`] for the micro:bit's GPIO peripheral. 2 | //! 3 | //! This controls the micro:bit's 5×5 LED display. 4 | //! 5 | //! [`DisplayControl`]: tiny_led_matrix::DisplayControl 6 | 7 | use tiny_led_matrix::DisplayControl; 8 | 9 | use crate::{ 10 | gpio::{NUM_COLS, NUM_ROWS}, 11 | pac, 12 | }; 13 | 14 | const fn pin_bits(pins: &[usize]) -> u32 { 15 | let mut i: usize = 0; 16 | let mut bits: u32 = 0; 17 | while i < pins.len() { 18 | bits |= 1 << pins[i]; 19 | i += 1; 20 | } 21 | bits 22 | } 23 | 24 | #[cfg(feature = "v1")] 25 | mod pins { 26 | use super::{NUM_COLS, NUM_ROWS}; 27 | pub(super) const P0_COLS: [usize; NUM_COLS] = [4, 5, 6, 7, 8, 9, 10, 11, 12]; 28 | pub(super) const P0_ROWS: [usize; NUM_ROWS] = [13, 14, 15]; 29 | } 30 | 31 | #[cfg(feature = "v2")] 32 | mod pins { 33 | use super::{NUM_COLS, NUM_ROWS}; 34 | pub(super) const P0_COLS: [usize; NUM_COLS - 1] = [28, 11, 31, 30]; 35 | pub(super) const P1_COLS: [usize; 1] = [5]; 36 | 37 | pub(super) const P0_ROWS: [usize; NUM_ROWS] = [21, 22, 15, 24, 19]; 38 | } 39 | 40 | const P0_COL_BITS: u32 = pin_bits(&pins::P0_COLS); 41 | #[cfg(feature = "v2")] 42 | const P1_COL_BITS: u32 = pin_bits(&pins::P1_COLS); 43 | 44 | const P0_ROW_BITS: u32 = pin_bits(&pins::P0_ROWS); 45 | 46 | #[cfg(feature = "v1")] 47 | type P0 = pac::GPIO; 48 | 49 | #[cfg(feature = "v2")] 50 | type P0 = pac::P0; 51 | 52 | #[cfg(feature = "v2")] 53 | type P1 = pac::P1; 54 | 55 | /// This implements the `DisplayControl` trait. 56 | /// 57 | /// [`DisplayControl`]: tiny_led_matrix::DisplayControl 58 | pub(crate) struct MicrobitGpio; 59 | 60 | /// Returns the GPIO pin numbers corresponding to the columns in a Column 61 | fn column_pins(mut cols: u32, px_cols: &[usize]) -> u32 { 62 | let mut result = 0u32; 63 | for &pin in px_cols.iter() { 64 | result |= (cols & 1) << pin; 65 | cols >>= 1; 66 | } 67 | result 68 | } 69 | 70 | #[cfg(feature = "v1")] 71 | fn split_cols(cols: u32) -> (u32, u32) { 72 | (cols, 0u32) 73 | } 74 | 75 | #[cfg(feature = "v2")] 76 | fn split_cols(cols: u32) -> (u32, u32) { 77 | // get all except col 2 (4th from least significant) 78 | let p0_cols = ((cols & 0b10000) >> 1) | (0b00111 & cols); 79 | // get col 4 (4th from least significant) 80 | let p1_cols = (cols & 0b01000) >> 3; 81 | (p0_cols, p1_cols) 82 | } 83 | 84 | /// Implementation of [`DisplayControl`] for the micro:bit's GPIO peripheral. 85 | /// 86 | /// This controls the micro:bit's 5×5 LED display. 87 | /// 88 | /// The `initialise_for display` implementation assumes the port is in the 89 | /// state it would have after system reset. 90 | /// 91 | /// [`DisplayControl`]: tiny_led_matrix::DisplayControl 92 | impl DisplayControl for MicrobitGpio { 93 | fn initialise_for_display(&mut self) { 94 | unsafe { 95 | let p0 = &*P0::ptr(); 96 | for ii in pins::P0_COLS.iter() { 97 | p0.pin_cnf[*ii].write(|w| w.dir().output()); 98 | } 99 | for ii in pins::P0_ROWS.iter() { 100 | p0.pin_cnf[*ii].write(|w| w.dir().output()); 101 | } 102 | 103 | // Set all p0 cols high. 104 | p0.outset 105 | .write(|w| w.bits(pins::P0_COLS.iter().map(|pin| 1 << pin).sum())); 106 | 107 | #[cfg(feature = "v2")] 108 | { 109 | let p1 = &*P1::ptr(); 110 | for ii in pins::P1_COLS.iter() { 111 | p1.pin_cnf[*ii].write(|w| w.dir().output()); 112 | } 113 | // Set all p1 cols high. 114 | p1.outset 115 | .write(|w| w.bits(pins::P1_COLS.iter().map(|pin| 1 << pin).sum())); 116 | } 117 | } 118 | } 119 | 120 | fn display_row_leds(&mut self, row: usize, cols: u32) { 121 | unsafe { 122 | let p0 = &*P0::ptr(); 123 | 124 | #[allow(unused_variables)] 125 | let (p0cols, p1cols) = split_cols(cols); 126 | 127 | // To light an LED, we set the row bit and clear the col bit. 128 | let rows_to_set = 1 << pins::P0_ROWS[row]; 129 | let rows_to_clear = P0_ROW_BITS ^ rows_to_set; 130 | 131 | #[cfg(feature = "v1")] 132 | { 133 | let cols_to_clear = column_pins(p0cols, &pins::P0_COLS); 134 | let cols_to_set = P0_COL_BITS ^ cols_to_clear; 135 | p0.outset.write(|w| w.bits(rows_to_set | cols_to_set)); 136 | p0.outclr.write(|w| w.bits(rows_to_clear | cols_to_clear)); 137 | } 138 | 139 | #[cfg(feature = "v2")] 140 | { 141 | let p1 = &*P1::ptr(); 142 | let p0_cols_to_clear = column_pins(p0cols, &pins::P0_COLS); 143 | let p0_cols_to_set = P0_COL_BITS ^ p0_cols_to_clear; 144 | let p1_cols_to_clear = column_pins(p1cols, &pins::P1_COLS); 145 | let p1_cols_to_set = P1_COL_BITS ^ p1_cols_to_clear; 146 | // We do the row-clearing write first and the row-setting write last, so that 147 | // intermediate states never light LEDs which aren't lit in either the old or new state. 148 | p0.outclr 149 | .write(|w| w.bits(rows_to_clear | p0_cols_to_clear)); 150 | p1.outset.write(|w| w.bits(p1_cols_to_set)); 151 | p1.outclr.write(|w| w.bits(p1_cols_to_clear)); 152 | p0.outset.write(|w| w.bits(rows_to_set | p0_cols_to_set)); 153 | } 154 | } 155 | } 156 | 157 | fn light_current_row_leds(&mut self, cols: u32) { 158 | unsafe { 159 | #[allow(unused_variables)] 160 | let (p0cols, p1cols) = split_cols(cols); 161 | let p0 = &*P0::ptr(); 162 | p0.outclr 163 | .write(|w| w.bits(column_pins(p0cols, &pins::P0_COLS))); 164 | 165 | #[cfg(feature = "v2")] 166 | { 167 | let p1 = &*P1::ptr(); 168 | p1.outclr 169 | .write(|w| w.bits(column_pins(p1cols, &pins::P1_COLS))); 170 | } 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /xtask/src/ci.rs: -------------------------------------------------------------------------------- 1 | use super::CRATES; 2 | use std::{collections::HashMap, env, fs, path, process::Command}; 3 | 4 | pub static DEPENDENCIES: &[&str] = &["flip-link"]; 5 | 6 | fn install_targets() { 7 | let targets = CRATES 8 | .iter() 9 | .map(|(_, target, _)| *target) 10 | .collect::>(); 11 | 12 | let mut rustup = Command::new("rustup"); 13 | rustup.args(&["target", "add"]).args(&targets); 14 | let status = rustup 15 | .status() 16 | .map_err(|e| format!("couldn't execute {:?}: {}", rustup, e)) 17 | .unwrap(); 18 | assert!( 19 | status.success(), 20 | "failed to install targets with rustup: {:?}", 21 | rustup 22 | ); 23 | } 24 | 25 | /// Install global dependencies 26 | fn install_dependencies() { 27 | for dependency in DEPENDENCIES { 28 | let exists = Command::new("which") 29 | .arg(dependency) 30 | .output() 31 | .expect("failed to execute"); 32 | if !exists.status.success() { 33 | let mut cargo = Command::new("cargo"); 34 | cargo.args(&["install", dependency]); 35 | let status = cargo 36 | .status() 37 | .map_err(|e| format!("couldn't execute {:?}: {}", cargo, e)) 38 | .unwrap(); 39 | assert!(status.success(),); 40 | } 41 | } 42 | } 43 | 44 | /// Build-test each board support crate 45 | fn build_crates() { 46 | for (hal, target, _) in CRATES { 47 | let mut cargo = Command::new("cargo"); 48 | let toml_path = format!("{}/Cargo.toml", hal); 49 | let status = cargo 50 | .args(&["build", "--manifest-path", &toml_path, "--target", target]) 51 | .status() 52 | .map_err(|e| format!("could not execute {:?}: {}", cargo, e)) 53 | .unwrap(); 54 | assert!( 55 | status.success(), 56 | "command exited with error status: {:?}", 57 | cargo 58 | ); 59 | } 60 | } 61 | 62 | /// Build/Run doc-tests in `microbit-common` for each version. 63 | fn build_run_doc_tests() { 64 | for (_, _, feature) in CRATES { 65 | let mut cargo = Command::new("cargo"); 66 | let status = cargo 67 | .current_dir("microbit-common") 68 | .args(&["test", "--features", feature]) 69 | .status() 70 | .map_err(|e| format!("could not execute {:?}: {}", cargo, e)) 71 | .unwrap(); 72 | assert!( 73 | status.success(), 74 | "command exited with error status: {:?}", 75 | cargo 76 | ); 77 | } 78 | } 79 | 80 | /// Build all examples with the boards they support 81 | fn build_examples() { 82 | let feature_targets = CRATES 83 | .iter() 84 | .map(|(_, target, feature)| (feature.to_string(), target.to_string())) 85 | .collect::>(); 86 | 87 | let crate_targets = CRATES 88 | .iter() 89 | .map(|(name, target, _)| (name.to_string(), target.to_string())) 90 | .collect::>(); 91 | 92 | for example in fs::read_dir("examples").unwrap() { 93 | let dir = example.unwrap(); 94 | let manifest_path = dir.path().join("Cargo.toml"); 95 | 96 | // Skip if there is no manifest 97 | if !manifest_path.exists() { 98 | continue; 99 | } 100 | 101 | let manifest = cargo_toml::Manifest::from_path(&manifest_path).unwrap(); 102 | 103 | // find features and their targets supported by the example 104 | let mut features = manifest 105 | .features 106 | .keys() 107 | .filter_map(|feature| { 108 | feature_targets 109 | .get(feature) 110 | .map(|target| (Some(feature.to_owned()), target.to_owned())) 111 | }) 112 | .collect::>(); 113 | 114 | // if there are no features find the target from the dependencies 115 | if features.is_empty() { 116 | features = manifest 117 | .dependencies 118 | .keys() 119 | .filter_map(|name| { 120 | crate_targets 121 | .get(name) 122 | .map(|target| (None, target.to_owned())) 123 | }) 124 | .collect::>(); 125 | assert_eq!( 126 | features.len(), 127 | 1, 128 | "examples must depend on either microbit or microbit-v2" 129 | ); 130 | } 131 | 132 | for (feature, target) in features { 133 | build_example(&manifest_path, feature, target); 134 | } 135 | } 136 | } 137 | 138 | fn build_example(manifest_path: &path::Path, feature: Option, target: String) { 139 | let mut cargo = Command::new("cargo"); 140 | cargo.args(&[ 141 | "build", 142 | "--target", 143 | &target, 144 | "--manifest-path", 145 | manifest_path.to_str().unwrap(), 146 | ]); 147 | if let Some(feature) = feature { 148 | cargo.args(&["--features", &feature]); 149 | } 150 | 151 | let status = cargo 152 | .status() 153 | .map_err(|e| format!("could not execute {:?}: {}", cargo, e)) 154 | .unwrap(); 155 | 156 | assert!( 157 | status.success(), 158 | "command exited with error status: {:?}", 159 | cargo 160 | ); 161 | } 162 | 163 | fn start_group(is_ci: bool, name: &str) { 164 | if is_ci { 165 | println!("::group::{}", name); 166 | } 167 | } 168 | 169 | fn end_group(is_ci: bool) { 170 | if is_ci { 171 | println!("::endgroup::"); 172 | } 173 | } 174 | 175 | fn wrap_in_group(is_ci: bool, name: &str, callable: &dyn Fn()) { 176 | start_group(is_ci, name); 177 | callable(); 178 | end_group(is_ci); 179 | } 180 | 181 | pub fn ci() { 182 | let is_ci = env::var("CI").map_or(false, |ci| ci == "true"); 183 | 184 | // move up if we're running from inside xtask 185 | if env::current_dir().unwrap().ends_with("xtask") { 186 | env::set_current_dir("..").unwrap(); 187 | } 188 | 189 | wrap_in_group(is_ci, "install targets", &install_targets); 190 | wrap_in_group(is_ci, "install dependencies", &install_dependencies); 191 | wrap_in_group(is_ci, "build crates", &build_crates); 192 | wrap_in_group(is_ci, "build examples", &build_examples); 193 | wrap_in_group(is_ci, "run doc tests", &build_run_doc_tests); 194 | } 195 | -------------------------------------------------------------------------------- /microbit-common/src/display/blocking.rs: -------------------------------------------------------------------------------- 1 | //! Blocking support for the 5x5 LED display. 2 | //! 3 | //! This module provides a simple blocking interface 4 | //! to the on board 5x5 LED display. If you need a more sophisticated 5 | //! or non-blocking interface use the [`display::nonblocking`](crate::display::nonblocking) module. 6 | //! 7 | //! # Example 8 | //! 9 | //! ```no_run 10 | //! # use microbit_common as microbit; 11 | //! # use microbit::{ 12 | //! # Board, 13 | //! # hal, 14 | //! # display::blocking::Display, 15 | //! # }; 16 | //! # use embedded_hal::delay::DelayNs; 17 | //! // take the board 18 | //! let board = Board::take().unwrap(); 19 | //! // make a timer 20 | //! let mut timer = hal::Timer::new(board.TIMER0); 21 | //! // create the Display 22 | //! let mut display = Display::new(board.display_pins); 23 | //! // and light up some LEDs 24 | //! let heart = [ 25 | //! [0, 1, 0, 1, 0], 26 | //! [1, 0, 1, 0, 1], 27 | //! [1, 0, 0, 0, 1], 28 | //! [0, 1, 0, 1, 0], 29 | //! [0, 0, 1, 0, 0], 30 | //! ]; 31 | //! loop { 32 | //! display.show(&mut timer, heart, 1000); 33 | //! display.clear(); 34 | //! timer.delay_ms(250); 35 | //! } 36 | //! ``` 37 | //! 38 | //! The coordiante system is oriented so the 'bottom' (x,4) row is the edge with the edge 39 | //! connector. That means that 40 | //! 41 | //! ```no_run 42 | //! # use microbit_common as microbit; 43 | //! # use microbit::{ 44 | //! # Board, 45 | //! # hal, 46 | //! # display::blocking::Display, 47 | //! # }; 48 | //! # let board = Board::take().unwrap(); 49 | //! # let mut timer = hal::Timer::new(board.TIMER0); 50 | //! # let mut display = Display::new(board.display_pins); 51 | //! display.show( 52 | //! &mut timer, 53 | //! [ 54 | //! [0, 0, 1, 0, 0], 55 | //! [0, 1, 1, 1, 0], 56 | //! [1, 0, 1, 0, 1], 57 | //! [0, 0, 1, 0, 0], 58 | //! [0, 0, 1, 0, 0], 59 | //! ], 60 | //! 1000, 61 | //!); 62 | //! ``` 63 | //! Will display an arrow pointing towards the boards usb port. 64 | //! 65 | //! For a working example [`examples/display-blocking`](https://github.com/nrf-rs/microbit/tree/main/examples/display-blocking) 66 | use crate::gpio::{DisplayPins, NUM_COLS, NUM_ROWS}; 67 | use crate::hal::gpio::{Output, Pin, PushPull}; 68 | use embedded_hal::{delay::DelayNs, digital::OutputPin}; 69 | 70 | #[allow(clippy::upper_case_acronyms)] 71 | pub(crate) type LED = Pin>; 72 | 73 | const DEFAULT_DELAY_MS: u32 = 2; 74 | #[cfg(feature = "v1")] 75 | const LED_LAYOUT: [[(usize, usize); 5]; 5] = [ 76 | [(0, 0), (1, 3), (0, 1), (1, 4), (0, 2)], 77 | [(2, 3), (2, 4), (2, 5), (2, 6), (2, 7)], 78 | [(1, 1), (0, 8), (1, 2), (2, 8), (1, 0)], 79 | [(0, 7), (0, 6), (0, 5), (0, 4), (0, 3)], 80 | [(2, 2), (1, 6), (2, 0), (1, 5), (2, 1)], 81 | ]; 82 | 83 | /// Blocking interface to the on board LED display 84 | pub struct Display { 85 | delay_ms: u32, 86 | rows: [LED; NUM_ROWS], 87 | cols: [LED; NUM_COLS], 88 | } 89 | 90 | impl Display { 91 | /// Create and initialise the display driver 92 | /// 93 | /// The [`display_pins!`](crate::display_pins) macro can be used 94 | /// to create [`DisplayPins`]. 95 | pub fn new(pins: DisplayPins) -> Self { 96 | let (cols, rows) = pins.degrade(); 97 | Display { 98 | delay_ms: DEFAULT_DELAY_MS, 99 | rows, 100 | cols, 101 | } 102 | } 103 | 104 | /// Clear the display 105 | pub fn clear(&mut self) { 106 | for row in &mut self.rows { 107 | row.set_low().ok(); 108 | } 109 | for col in &mut self.cols { 110 | col.set_high().ok(); 111 | } 112 | } 113 | 114 | /// Set delay, time spent on each matrix row, in ms 115 | pub fn set_delay_ms(&mut self, delay_ms: u32) { 116 | self.delay_ms = delay_ms; 117 | } 118 | 119 | /// Set refresh rate, time for matrix scan 120 | pub fn set_refresh_rate(&mut self, freq_hz: u32) { 121 | self.delay_ms = 1000 / freq_hz / (NUM_ROWS as u32); 122 | } 123 | 124 | /// Convert 5x5 image to 3x9 matrix 125 | /// 126 | /// The pins are represented as a [3x9 matrix on the micro:bit 127 | /// V1](https://tech.microbit.org/hardware/1-5-revision/#display). 128 | #[cfg(feature = "v1")] 129 | fn image2matrix(led_image: [[u8; 5]; 5]) -> [[u8; 9]; 3] { 130 | let mut led_matrix: [[u8; 9]; 3] = [[0; 9]; 3]; 131 | for (led_image_row, layout_row) in led_image.iter().zip(LED_LAYOUT.iter()) { 132 | for (led_image_val, layout_loc) in led_image_row.iter().zip(layout_row) { 133 | led_matrix[layout_loc.0][layout_loc.1] = *led_image_val; 134 | } 135 | } 136 | led_matrix 137 | } 138 | 139 | /// Display 5x5 image for a given duration 140 | pub fn show(&mut self, delay: &mut D, led_display: [[u8; 5]; 5], duration_ms: u32) { 141 | #[cfg(feature = "v1")] 142 | { 143 | let led_matrix = Display::image2matrix(led_display); 144 | self.show_inner(delay, led_matrix, duration_ms); 145 | } 146 | #[cfg(feature = "v2")] 147 | self.show_inner(delay, led_display, duration_ms); 148 | } 149 | 150 | /// Display matrix image for a given duration (3x9 for V1 micro:bit) 151 | /// 152 | /// The pins are represented as a [3x9 matrix on the micro:bit 153 | /// V1](https://tech.microbit.org/hardware/1-5-revision/#display). 154 | fn show_inner( 155 | &mut self, 156 | delay: &mut D, 157 | led_matrix: [[u8; NUM_COLS]; NUM_ROWS], 158 | duration_ms: u32, 159 | ) { 160 | // TODO: something more intelligent with timers 161 | let loops = duration_ms / (self.rows.len() as u32 * self.delay_ms); 162 | for _ in 0..loops { 163 | for (row_line, led_matrix_row) in self.rows.iter_mut().zip(led_matrix.iter()) { 164 | row_line.set_high().ok(); 165 | for (col_line, led_matrix_val) in self.cols.iter_mut().zip(led_matrix_row.iter()) { 166 | // TODO : use value to set brightness 167 | if *led_matrix_val > 0 { 168 | col_line.set_low().ok(); 169 | } 170 | } 171 | delay.delay_us(self.delay_ms * 1000); 172 | for col_line in &mut self.cols { 173 | col_line.set_high().ok(); 174 | } 175 | row_line.set_low().ok(); 176 | } 177 | } 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /microbit-common/src/display/nonblocking/mod.rs: -------------------------------------------------------------------------------- 1 | //! Non-blocking support for the 5×5 LED display. 2 | //! 3 | //! Together with [`tiny-led-matrix`](tiny_led_matrix), this module provides: 4 | //! - support for driving the LED display from a timer interrupt 5 | //! - ten levels of brightness for each LED 6 | //! - simple 5×5 greyscale and black-and-white image types. 7 | //! 8 | //! The module doesn't define interrupt handlers directly; instead it provides 9 | //! a function to be called from a timer interrupt. It knows how to program 10 | //! one of the micro:bit's timers to provide that interrupt. 11 | //! 12 | //! ## Example 13 | //! 14 | //! This shows general usage but is not a working example. 15 | //! For a working exaple see 16 | //! [`display_nonblocking`](https://github.com/nrf-rs/microbit/tree/main/examples/display-nonblocking). 17 | //! 18 | //! ```no_run 19 | //! # use microbit_common as microbit; 20 | //! use microbit::{ 21 | //! Board, 22 | //! hal, 23 | //! display::nonblocking::{Display, GreyscaleImage}, 24 | //! }; 25 | //! use embedded_hal::delay::DelayNs; 26 | //! 27 | //! let board = Board::take().unwrap(); 28 | //! 29 | //! let mut display = Display::new(board.TIMER1, board.display_pins); 30 | //! 31 | //! // in your main function 32 | //! { 33 | //! let mut timer2 = hal::Timer::new(board.TIMER0); 34 | //! loop { 35 | //! display.show(&GreyscaleImage::new(&[ 36 | //! [0, 7, 0, 7, 0], 37 | //! [7, 0, 7, 0, 7], 38 | //! [7, 0, 0, 0, 7], 39 | //! [0, 7, 0, 7, 0], 40 | //! [0, 0, 7, 0, 0], 41 | //! ])); 42 | //! timer2.delay_ms(1000); 43 | //! 44 | //! display.clear(); 45 | //! timer2.delay_ms(1000); 46 | //! } 47 | //! } 48 | //! 49 | //! // in a timer interrupt 50 | //! { 51 | //! display.handle_display_event(); 52 | //! } 53 | //! ``` 54 | //! 55 | //! ## Coordinate system 56 | //! 57 | //! The LEDs are identified using (x,y) coordinates as follows: 58 | //! 59 | //! ```text 60 | //! (0,0) ... (4,0) 61 | //! ... ... ... 62 | //! (0,4) ... (4,4) 63 | //! ``` 64 | //! 65 | //! where the 'bottom' (x,4) of the board is the edge connector. 66 | //! 67 | //! ## Greyscale model 68 | //! 69 | //! LED brightness levels are described using a scale from 0 (off) to 9 70 | //! (brightest) inclusive. 71 | //! 72 | //! These are converted to time slices using the same timings as used by the 73 | //! [micro:bit MicroPython port][micropython] (this is different to the 0 to 74 | //! 255 scale used by the [micro:bit runtime][dal]). 75 | //! 76 | //! The time slice for each level above 1 is approximately 1.9× the slice for 77 | //! the previous level. 78 | //! 79 | #![cfg_attr( 80 | feature = "v1", 81 | doc = "An LED with brightness 9 is lit for one third of the time (because internally there are three 'rows' of LEDs which have to be addressed one at a time)." 82 | )] 83 | #![cfg_attr( 84 | feature = "v2", 85 | doc = "An LED with brightness 9 is lit for one fifth of the time." 86 | )] 87 | //! 88 | //! ## Images 89 | //! 90 | //! An image is a type that implements the [`tiny_led_matrix::Render`] trait. Two image types are provided: 91 | //! - [`GreyscaleImage`](image::GreyscaleImage), allowing all 9 levels (using one byte for each LED) 92 | //! - [`BitImage`](image::BitImage), allowing only 'on' and 'off' (using five bytes) 93 | //! 94 | //! ## Display 95 | //! 96 | //! A [`Display`] instance controls the LEDs and programs a timer. There 97 | //! should normally be a single `Display` instance in the program. It is a wrapper 98 | //! around [`tiny_led_matrix::Display`] to expose an API similar to the blocking API. 99 | //! 100 | //! ## Frames 101 | //! 102 | //! Internally types implementing [`Render`](tiny_led_matrix::Render) aren't used directly with the [`Display`]; 103 | //! instead they're used to update a [`MicrobitFrame`] instance which is in 104 | //! turn passed to the `tiny_led_matrix::Display`. 105 | //! 106 | //! A `MicrobitFrame` instance is a 'compiled' representation of a 5×5 107 | //! greyscale image, in a form that's more directly usable by the display 108 | //! code. 109 | //! 110 | //! This is exposed in the public API so that you can construct the 111 | //! `MicrobitFrame` representation in code running at a low priority. Then 112 | //! only [`Display::show_frame()`] has to be called in code that can't be 113 | //! interrupted by the display timer. 114 | //! 115 | //! ## Timer integration 116 | //! 117 | //! The [`Display`] expects to control a single timer. It can use the 118 | //! micro:bit's `TIMER0`, `TIMER1`, or `TIMER2`. 119 | //! 120 | //! For the micro:bit v1 this uses a 6ms period to light each of the three 121 | //! internal LED rows, so that the entire display is updated every 18ms. 122 | //! 123 | //! For the micro:bit v2 this uses a 3ms period to light each of the five 124 | //! internal LED rows, so that the entire display is updated every 15ms. 125 | //! 126 | //! When rendering greyscale images, the `Display` requests extra interrupts 127 | //! within each 6ms or 3ms period. It only requests interrupts for the 128 | //! greyscale levels which are actually required for what's currently being 129 | //! displayed. 130 | //! 131 | //! ### Technical details 132 | //! 133 | //! The timer is set to 16-bit mode, using a 62.5kHz or 135Khz clock (16 µs or 134 | //! 8µs ticks). It resets every 375 ticks. 135 | //! 136 | //! ## Usage 137 | //! 138 | //! Choose a timer to drive the display from (`TIMER0`, `TIMER1`, or `TIMER2`). 139 | //! 140 | //! When your program starts: 141 | //! - create a [`Display`] struct passing the timer and 142 | //! [`gpio::DisplayPins`](crate::gpio::DisplayPins) to [`Display::new()`]. 143 | //! 144 | //! In an interrupt handler for the timer call [`.handle_display_event()`](Display::handle_display_event) 145 | //! 146 | //! To change what's displayed; pass an image ([`GreyscaleImage`] or [`BitImage`]) to [`Display::show`]. 147 | //! 148 | //! You can call `show()` at any time, so long as you're not interrupting, or interruptable by, 149 | //! [`Display::handle_display_event()`]. 150 | //! 151 | //! See [`display_rtic`](https://github.com/nrf-rs/microbit/blob/master/examples/display_rtic) or 152 | //! [`display_nonblocking`](https://github.com/nrf-rs/microbit/blob/master/examples/display_nonblocking) 153 | //! example for a complete working example. 154 | //! 155 | //! [dal]: https://lancaster-university.github.io/microbit-docs/ 156 | //! [micropython]: https://microbit-micropython.readthedocs.io/ 157 | 158 | use tiny_led_matrix; 159 | #[doc(no_inline)] 160 | pub use tiny_led_matrix::{Frame, MAX_BRIGHTNESS}; 161 | 162 | mod control; 163 | mod image; 164 | mod matrix; 165 | mod timer; 166 | 167 | pub use image::{BitImage, GreyscaleImage}; 168 | pub use matrix::MicrobitFrame; 169 | use timer::MicrobitDisplayTimer; 170 | 171 | use crate::{gpio::DisplayPins, hal::timer::Instance}; 172 | 173 | use control::MicrobitGpio; 174 | 175 | /// Non-blocking interface to the on board 5x5 LED display 176 | pub struct Display { 177 | display: tiny_led_matrix::Display, 178 | timer: MicrobitDisplayTimer, 179 | pins: DisplayPins, 180 | frame: MicrobitFrame, 181 | } 182 | 183 | impl Display { 184 | /// Create and initialise the display driver 185 | /// 186 | /// [`DisplayPins`] can be used from [`Board::display_pins`](crate::Board::display_pins) 187 | /// or the [`display_pins!`](crate::display_pins) macro can be used is manually. 188 | pub fn new(timer: T, pins: DisplayPins) -> Self { 189 | let mut display = Self { 190 | display: tiny_led_matrix::Display::new(), 191 | timer: MicrobitDisplayTimer::new(timer), 192 | pins, 193 | frame: MicrobitFrame::default(), 194 | }; 195 | display.initialise(); 196 | display 197 | } 198 | 199 | /// Release the timer and pins 200 | pub fn free(self) -> (T, DisplayPins) { 201 | (self.timer.free(), self.pins) 202 | } 203 | 204 | /// Initialise the display 205 | /// 206 | /// This is usually called immediately after creating the display driver. 207 | /// It does not need to be called in a critical section. 208 | fn initialise(&mut self) { 209 | tiny_led_matrix::initialise_control(&mut MicrobitGpio {}); 210 | tiny_led_matrix::initialise_timer(&mut self.timer); 211 | } 212 | 213 | /// Update the LED display and timer state 214 | /// 215 | /// Call this in an interrupt handler for the timer you're using. This method 216 | /// takes care of updating the LED display and clearing the timer's event registers 217 | /// 218 | /// This may be called at any time, so long as the code calling it is not interrupting, or 219 | /// interruptable by `tiny_led_matrix::Display::handle_event()`. Within safe code, the borrow 220 | /// checker ensures that this requirement is fulfilled. When writing unsafe code, this method 221 | /// should be called from within a [critical 222 | /// section](https://docs.rs/cortex-m/0.7.2/cortex_m/interrupt/fn.free.html). 223 | pub fn handle_display_event(&mut self) { 224 | self.display 225 | .handle_event(&mut self.timer, &mut MicrobitGpio {}); 226 | } 227 | 228 | /// Show a new image 229 | /// 230 | /// This may be called at any time, so long as the code calling it is not interrupting, or 231 | /// interruptable by `tiny_led_matrix::Display::handle_event()`. Within safe code, the borrow 232 | /// checker ensures that this requirement is fulfilled. When writing unsafe code, this method 233 | /// should be called from within a [critical 234 | /// section](https://docs.rs/cortex-m/0.7.2/cortex_m/interrupt/fn.free.html). 235 | /// 236 | /// ## Example 237 | /// 238 | /// ```ignore 239 | /// display.show(&GreyscaleImage::new(&[ 240 | /// [0, 7, 0, 7, 0], 241 | /// [7, 0, 7, 0, 7], 242 | /// [7, 0, 0, 0, 7], 243 | /// [0, 7, 0, 7, 0], 244 | /// [0, 0, 7, 0, 0], 245 | /// ])); 246 | /// ``` 247 | pub fn show(&mut self, image: &R) { 248 | self.frame.set(image); 249 | self.display.set_frame(&self.frame); 250 | } 251 | 252 | /// Clear the display 253 | /// 254 | /// This may be called at any time, so long as the code calling it is not interrupting, or 255 | /// interruptable by `tiny_led_matrix::Display::handle_event()`. Within safe code, the borrow 256 | /// checker ensures that this requirement is fulfilled. When writing unsafe code, this method 257 | /// should be called from within a [critical 258 | /// section](https://docs.rs/cortex-m/0.7.2/cortex_m/interrupt/fn.free.html). 259 | pub fn clear(&mut self) { 260 | self.display.set_frame(&MicrobitFrame::default()); 261 | } 262 | 263 | /// Show a new frame 264 | /// 265 | /// This is similar to [`show`](Display::show) but accepts a [`MicrobitFrame`] instead. 266 | /// This may be useful if performance is a concern as calling `set` on the frame 267 | /// can be done outside the critical section. 268 | /// 269 | /// This may be called at any time, so long as the code calling it is not interrupting, or 270 | /// interruptable by `tiny_led_matrix::Display::handle_event()`. Within safe code, the borrow 271 | /// checker ensures that this requirement is fulfilled. When writing unsafe code, this method 272 | /// should be called from within a [critical 273 | /// section](https://docs.rs/cortex-m/0.7.2/cortex_m/interrupt/fn.free.html). 274 | /// 275 | /// ## Example 276 | /// 277 | /// ```ignore 278 | /// FRAME = MicrobitFrame::default(); 279 | /// FRAME.set(&GreyscaleImage::new(&[ 280 | /// [0, 7, 0, 7, 0], 281 | /// [7, 0, 7, 0, 7], 282 | /// [7, 0, 0, 0, 7], 283 | /// [0, 7, 0, 7, 0], 284 | /// [0, 0, 7, 0, 0], 285 | /// ])); 286 | /// 287 | /// // only this needs to be in a critical section 288 | /// display.show_frame(&FRAME); 289 | /// ``` 290 | pub fn show_frame(&mut self, frame: &MicrobitFrame) { 291 | self.display.set_frame(frame); 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /microbit-common/src/v1/board.rs: -------------------------------------------------------------------------------- 1 | use super::gpio::{ 2 | DisplayPins, BTN_A, BTN_B, EDGE00, EDGE01, EDGE02, EDGE08, EDGE12, EDGE16, SCL, SDA, UART_RX, 3 | UART_TX, 4 | }; 5 | use crate::{ 6 | hal::{ 7 | gpio::{p0, Disconnected, Level}, 8 | twi, uart, 9 | }, 10 | pac, 11 | }; 12 | 13 | /// Provides access to the microbit 14 | #[allow(non_snake_case)] 15 | pub struct Board { 16 | /// GPIO pins that are not otherwise used 17 | pub pins: Pins, 18 | 19 | /// Unused GPIO pins on edge connector 20 | pub edge: Edge, 21 | 22 | /// display pins 23 | pub display_pins: DisplayPins, 24 | 25 | /// buttons 26 | pub buttons: Buttons, 27 | 28 | /// I2C shared internal and external bus pins 29 | pub i2c: I2CPins, 30 | 31 | /// UART to debugger pins 32 | pub uart: UartPins, 33 | 34 | /// Core peripheral: Cache and branch predictor maintenance operations 35 | pub CBP: pac::CBP, 36 | 37 | /// Core peripheral: CPUID 38 | pub CPUID: pac::CPUID, 39 | 40 | /// Core peripheral: Debug Control Block 41 | pub DCB: pac::DCB, 42 | 43 | /// Core peripheral: Data Watchpoint and Trace unit 44 | pub DWT: pac::DWT, 45 | 46 | /// Core peripheral: Flash Patch and Breakpoint unit 47 | pub FPB: pac::FPB, 48 | 49 | /// Core peripheral: Instrumentation Trace Macrocell 50 | pub ITM: pac::ITM, 51 | 52 | /// Core peripheral: Memory Protection Unit 53 | pub MPU: pac::MPU, 54 | 55 | /// Core peripheral: Nested Vector Interrupt Controller 56 | pub NVIC: pac::NVIC, 57 | 58 | /// Core peripheral: System Control Block 59 | pub SCB: pac::SCB, 60 | 61 | /// Core peripheral: SysTick Timer 62 | pub SYST: pac::SYST, 63 | 64 | /// Core peripheral: Trace Port Interface Unit 65 | pub TPIU: pac::TPIU, 66 | 67 | /// nRF51 peripheral: ADC 68 | pub ADC: pac::ADC, 69 | 70 | /// nRF51 peripheral: CLOCK 71 | pub CLOCK: pac::CLOCK, 72 | 73 | /// nRF51 peripheral: FICR 74 | pub FICR: pac::FICR, 75 | 76 | /// nRF51 peripheral: GPIOTE 77 | pub GPIOTE: pac::GPIOTE, 78 | 79 | /// nRF51 preipheral: PPI 80 | pub PPI: pac::PPI, 81 | 82 | /// nRF51 peripheral: RADIO 83 | pub RADIO: pac::RADIO, 84 | 85 | /// nRF51 peripheral: RNG 86 | pub RNG: pac::RNG, 87 | 88 | /// nRF51 peripheral: RTC0 89 | pub RTC0: pac::RTC0, 90 | 91 | /// nRF51 peripheral: TEMP
92 | /// Can be used with [`Temp::new()`](`crate::hal::temp::Temp::new()`) 93 | pub TEMP: pac::TEMP, 94 | 95 | /// nRF51 peripheral: TIMER0 96 | pub TIMER0: pac::TIMER0, 97 | 98 | /// nRF51 peripheral: TIMER1 99 | pub TIMER1: pac::TIMER1, 100 | 101 | /// nRF51 peripheral: TIMER2 102 | pub TIMER2: pac::TIMER2, 103 | 104 | /// nRF51 peripheral: TWI0 105 | pub TWI0: pac::TWI0, 106 | 107 | /// nrf51 peripheral: UART0 108 | pub UART0: pac::UART0, 109 | 110 | /// nrf51 peripheral: POWER 111 | pub POWER: pac::POWER, 112 | 113 | /// nrf51 peripheral: SPI0 114 | pub SPI0: pac::SPI0, 115 | 116 | /// nrf51 peripheral: SPI1 117 | pub SPI1: pac::SPI1, 118 | 119 | /// nrf51 peripheral: TWI1 120 | pub TWI1: pac::TWI1, 121 | 122 | /// nrf51 peripheral: SPIS1 123 | pub SPIS1: pac::SPIS1, 124 | 125 | /// nrf51 peripheral: ECB 126 | pub ECB: pac::ECB, 127 | 128 | /// nrf51 peripheral: AAR 129 | pub AAR: pac::AAR, 130 | 131 | /// nrf51 peripheral: CCM 132 | pub CCM: pac::CCM, 133 | 134 | /// nrf51 peripheral: WDT 135 | pub WDT: pac::WDT, 136 | 137 | /// nrf51 peripheral: RTC1 138 | pub RTC1: pac::RTC1, 139 | 140 | /// nrf51 peripheral: QDEC 141 | pub QDEC: pac::QDEC, 142 | 143 | /// nrf51 peripheral: LPCOMP 144 | pub LPCOMP: pac::LPCOMP, 145 | 146 | /// nrf51 peripheral: SWI 147 | pub SWI: pac::SWI, 148 | 149 | /// nrf51 peripheral: NVMC 150 | pub NVMC: pac::NVMC, 151 | 152 | /// nrf51 peripheral: UICR 153 | pub UICR: pac::UICR, 154 | } 155 | 156 | impl Board { 157 | /// Take the peripherals safely 158 | /// 159 | /// This method will return an instance of the board the first time it is 160 | /// called. It will return only `None` on subsequent calls. 161 | /// This function can also return `None` if one of the the peripherals was 162 | /// already taken. 163 | pub fn take() -> Option { 164 | Some(Self::new( 165 | pac::Peripherals::take()?, 166 | pac::CorePeripherals::take()?, 167 | )) 168 | } 169 | 170 | /// Fallback method in the case peripherals and core peripherals were taken 171 | /// elsewhere already. 172 | /// 173 | /// This method will take the peripherals and core peripherals and 174 | /// return an instance of the board. 175 | /// 176 | /// An exemplary usecase is shown in the rtic display example. 177 | pub fn new(p: pac::Peripherals, cp: pac::CorePeripherals) -> Self { 178 | let p0parts = p0::Parts::new(p.GPIO); 179 | Self { 180 | pins: Pins { 181 | //p0_01: p0parts.p0_01, 182 | //p0_02: p0parts.p0_02, 183 | //p0_03: p0parts.p0_03, 184 | //p0_16: p0parts.p0_16, 185 | //p0_18: p0parts.p0_18, 186 | p0_19: p0parts.p0_19, 187 | //p0_20: p0parts.p0_20, 188 | p0_21: p0parts.p0_21, 189 | p0_22: p0parts.p0_22, 190 | p0_23: p0parts.p0_23, 191 | p0_27: p0parts.p0_27, 192 | p0_28: p0parts.p0_28, 193 | p0_29: p0parts.p0_29, 194 | }, 195 | edge: Edge { 196 | e00: p0parts.p0_03, 197 | e01: p0parts.p0_02, 198 | e02: p0parts.p0_01, 199 | e08: p0parts.p0_18, 200 | e12: p0parts.p0_20, 201 | e16: p0parts.p0_16, 202 | }, 203 | display_pins: DisplayPins { 204 | row1: p0parts.p0_13.into_push_pull_output(Level::Low), 205 | row2: p0parts.p0_14.into_push_pull_output(Level::Low), 206 | row3: p0parts.p0_15.into_push_pull_output(Level::Low), 207 | col1: p0parts.p0_04.into_push_pull_output(Level::High), 208 | col2: p0parts.p0_05.into_push_pull_output(Level::High), 209 | col3: p0parts.p0_06.into_push_pull_output(Level::High), 210 | col4: p0parts.p0_07.into_push_pull_output(Level::High), 211 | col5: p0parts.p0_08.into_push_pull_output(Level::High), 212 | col6: p0parts.p0_09.into_push_pull_output(Level::High), 213 | col7: p0parts.p0_10.into_push_pull_output(Level::High), 214 | col8: p0parts.p0_11.into_push_pull_output(Level::High), 215 | col9: p0parts.p0_12.into_push_pull_output(Level::High), 216 | }, 217 | buttons: Buttons { 218 | button_a: p0parts.p0_17.into_floating_input(), 219 | button_b: p0parts.p0_26.into_floating_input(), 220 | }, 221 | i2c: I2CPins { 222 | scl: p0parts.p0_00.into_floating_input(), 223 | sda: p0parts.p0_30.into_floating_input(), 224 | }, 225 | uart: UartPins { 226 | tx: p0parts.p0_24.into_push_pull_output(Level::Low), 227 | rx: p0parts.p0_25.into_floating_input(), 228 | }, 229 | 230 | // Core peripherals 231 | CBP: cp.CBP, 232 | CPUID: cp.CPUID, 233 | DCB: cp.DCB, 234 | DWT: cp.DWT, 235 | FPB: cp.FPB, 236 | ITM: cp.ITM, 237 | MPU: cp.MPU, 238 | NVIC: cp.NVIC, 239 | SCB: cp.SCB, 240 | SYST: cp.SYST, 241 | TPIU: cp.TPIU, 242 | 243 | // nRF51 peripherals 244 | ADC: p.ADC, 245 | CLOCK: p.CLOCK, 246 | FICR: p.FICR, 247 | GPIOTE: p.GPIOTE, 248 | PPI: p.PPI, 249 | RADIO: p.RADIO, 250 | RNG: p.RNG, 251 | RTC0: p.RTC0, 252 | TEMP: p.TEMP, 253 | TIMER0: p.TIMER0, 254 | TIMER1: p.TIMER1, 255 | TIMER2: p.TIMER2, 256 | TWI0: p.TWI0, 257 | UART0: p.UART0, 258 | POWER: p.POWER, 259 | SPI0: p.SPI0, 260 | SPI1: p.SPI1, 261 | TWI1: p.TWI1, 262 | SPIS1: p.SPIS1, 263 | ECB: p.ECB, 264 | AAR: p.AAR, 265 | CCM: p.CCM, 266 | WDT: p.WDT, 267 | RTC1: p.RTC1, 268 | QDEC: p.QDEC, 269 | LPCOMP: p.LPCOMP, 270 | SWI: p.SWI, 271 | NVMC: p.NVMC, 272 | UICR: p.UICR, 273 | } 274 | } 275 | } 276 | 277 | /// Unused GPIO pins 278 | #[allow(missing_docs)] 279 | pub struct Pins { 280 | // pub p0_00: p0::P0_00, // SCL 281 | // pub p0_01: p0::P0_01, // PAD2, EDGE02 282 | // pub p0_02: p0::P0_02, // PAD1, EDGE01 283 | // pub p0_03: p0::P0_03, // PAD0, EDGE00 284 | // pub p0_04: p0::P0_04, // LEDs 285 | // pub p0_05: p0::P0_05, // LEDs 286 | // pub p0_06: p0::P0_06, // LEDs 287 | // pub p0_07: p0::P0_07, // LEDs 288 | // pub p0_08: p0::P0_08, // LEDs 289 | // pub p0_09: p0::P0_09, // LEDs 290 | // pub p0_10: p0::P0_10, // LEDs 291 | // pub p0_11: p0::P0_11, // LEDs 292 | // pub p0_12: p0::P0_12, // LEDs 293 | // pub p0_13: p0::P0_13, // LEDs 294 | // pub p0_14: p0::P0_14, // LEDs 295 | // pub p0_15: p0::P0_15, // LEDs 296 | // pub p0_16: p0::P0_16, // EDGE16 297 | // pub p0_17: p0::P0_17, // BTN_A 298 | // pub p0_18: p0::P0_18, // EDGE08 299 | pub p0_19: p0::P0_19, 300 | // pub p0_20: p0::P0_20, // EDGE12 301 | pub p0_21: p0::P0_21, 302 | pub p0_22: p0::P0_22, 303 | pub p0_23: p0::P0_23, 304 | // pub p0_24: p0::P0_24, // UART TX 305 | // pub p0_25: p0::P0_25, // UART RX 306 | // pub p0_26: p0::P0_26, // BTN_B 307 | pub p0_27: p0::P0_27, 308 | pub p0_28: p0::P0_28, 309 | pub p0_29: p0::P0_29, 310 | // pub p0_30: p0::P0_30, // SDA 311 | } 312 | 313 | /// Unused edge connector pins 314 | #[allow(missing_docs)] 315 | pub struct Edge { 316 | // pub e03: COL1, 317 | pub e00: EDGE00, // <- big pad 1 318 | // pub e04: COL2, 319 | // pub e05: BTN_A, 320 | // pub e06: COL9, 321 | // pub e07: COL8, 322 | pub e01: EDGE01, // <- big pad 2 323 | pub e08: EDGE08, 324 | // pub e09: COL7, 325 | // pub e10: COL3, 326 | // pub e11: BTN_B, 327 | pub e12: EDGE12, 328 | pub e02: EDGE02, // <- big pad 3 329 | //pub e13: SCK, 330 | //pub e14: MISO, 331 | //pub e15: MOSI, 332 | pub e16: EDGE16, 333 | // +V 334 | // +V 335 | // +V 336 | // pub e19: SCL, 337 | // pub e20: SDA, 338 | // GND 339 | // GND 340 | // GND 341 | } 342 | 343 | /// Board buttons 344 | pub struct Buttons { 345 | /// Left hand side button 346 | pub button_a: BTN_A, 347 | /// Right hand side button 348 | pub button_b: BTN_B, 349 | } 350 | 351 | /// I2C shared internal and external bus pins 352 | pub struct I2CPins { 353 | /// I2C control pin 354 | pub scl: SCL, 355 | /// I2C data pin 356 | pub sda: SDA, 357 | } 358 | 359 | impl From for twi::Pins { 360 | fn from(pins: I2CPins) -> Self { 361 | Self { 362 | scl: pins.scl.degrade(), 363 | sda: pins.sda.degrade(), 364 | } 365 | } 366 | } 367 | 368 | /// UART to debugger pins 369 | pub struct UartPins { 370 | tx: UART_TX, 371 | rx: UART_RX, 372 | } 373 | 374 | impl From for uart::Pins { 375 | fn from(pins: UartPins) -> Self { 376 | Self { 377 | rxd: pins.rx.degrade(), 378 | txd: pins.tx.degrade(), 379 | cts: None, 380 | rts: None, 381 | } 382 | } 383 | } 384 | -------------------------------------------------------------------------------- /microbit-common/src/v2/board.rs: -------------------------------------------------------------------------------- 1 | use super::gpio::{ 2 | DisplayPins, MicrophonePins, BTN_A, BTN_B, EDGE00, EDGE01, EDGE02, EDGE08, EDGE09, EDGE12, 3 | EDGE16, INT_SCL, INT_SDA, SCL, SDA, UART_RX, UART_TX, 4 | }; 5 | use crate::{ 6 | hal::{ 7 | gpio::{p0, p1, Disconnected, Level, OpenDrainConfig::Disconnect0HighDrive1}, 8 | twim, twis, uarte, 9 | }, 10 | pac, 11 | }; 12 | 13 | /// Provides access to the microbit 14 | #[allow(non_snake_case)] 15 | pub struct Board { 16 | /// GPIO pins that are not otherwise used 17 | pub pins: Pins, 18 | 19 | /// Unused GPIO pins on edge connector 20 | pub edge: Edge, 21 | 22 | /// display pins 23 | pub display_pins: DisplayPins, 24 | 25 | /// buttons 26 | pub buttons: Buttons, 27 | 28 | /// speaker 29 | pub speaker_pin: p0::P0_00, 30 | 31 | /// microphone pins 32 | pub microphone_pins: MicrophonePins, 33 | 34 | /// I2C internal bus pins 35 | pub i2c_internal: I2CInternalPins, 36 | 37 | /// I2C external bus pins 38 | pub i2c_external: I2CExternalPins, 39 | 40 | /// UART to debugger pins 41 | pub uart: UartPins, 42 | 43 | /// Core peripheral: Cache and branch predictor maintenance operations 44 | pub CBP: pac::CBP, 45 | 46 | /// Core peripheral: CPUID 47 | pub CPUID: pac::CPUID, 48 | 49 | /// Core peripheral: Debug Control Block 50 | pub DCB: pac::DCB, 51 | 52 | /// Core peripheral: Data Watchpoint and Trace unit 53 | pub DWT: pac::DWT, 54 | 55 | /// Core peripheral: Flash Patch and Breakpoint unit 56 | pub FPB: pac::FPB, 57 | 58 | /// Core peripheral: Floating Point Unit 59 | pub FPU: pac::FPU, 60 | 61 | /// Core peripheral: Instrumentation Trace Macrocell 62 | pub ITM: pac::ITM, 63 | 64 | /// Core peripheral: Memory Protection Unit 65 | pub MPU: pac::MPU, 66 | 67 | /// Core peripheral: Nested Vector Interrupt Controller 68 | pub NVIC: pac::NVIC, 69 | 70 | /// Core peripheral: System Control Block 71 | pub SCB: pac::SCB, 72 | 73 | /// Core peripheral: SysTick Timer 74 | pub SYST: pac::SYST, 75 | 76 | /// Core peripheral: Trace Port Interface Unit 77 | pub TPIU: pac::TPIU, 78 | 79 | /// nRF52 peripheral: CLOCK 80 | pub CLOCK: pac::CLOCK, 81 | 82 | /// nRF52 peripheral: FICR 83 | pub FICR: pac::FICR, 84 | 85 | /// nRF52 peripheral: GPIOTE 86 | pub GPIOTE: pac::GPIOTE, 87 | 88 | /// nRF52 preipheral: PPI 89 | pub PPI: pac::PPI, 90 | 91 | /// nRF52 peripheral: PWM0 92 | pub PWM0: pac::PWM0, 93 | 94 | /// nRF52 peripheral: PWM1 95 | pub PWM1: pac::PWM1, 96 | 97 | /// nRF52 peripheral: PWM2 98 | pub PWM2: pac::PWM2, 99 | 100 | /// nRF52 peripheral: PWM3 101 | pub PWM3: pac::PWM3, 102 | 103 | /// nRF52 peripheral: RADIO 104 | pub RADIO: pac::RADIO, 105 | 106 | /// nRF52 peripheral: RNG 107 | pub RNG: pac::RNG, 108 | 109 | /// nRF52 peripheral: RTC0 110 | pub RTC0: pac::RTC0, 111 | 112 | /// nRF52 peripheral: RTC1 113 | pub RTC1: pac::RTC1, 114 | 115 | /// nRF52 peripheral: RTC2 116 | pub RTC2: pac::RTC2, 117 | 118 | /// nRF52 peripheral: TEMP
119 | /// Can be used with [`Temp::new()`](`crate::hal::temp::Temp::new()`) 120 | pub TEMP: pac::TEMP, 121 | 122 | /// nRF52 peripheral: TIMER0 123 | pub TIMER0: pac::TIMER0, 124 | 125 | /// nRF52 peripheral: TIMER1 126 | pub TIMER1: pac::TIMER1, 127 | 128 | /// nRF52 peripheral: TIMER2 129 | pub TIMER2: pac::TIMER2, 130 | 131 | /// nRF52 peripheral: TIMER3 132 | pub TIMER3: pac::TIMER3, 133 | 134 | /// nRF52 peripheral: TIMER4 135 | pub TIMER4: pac::TIMER4, 136 | 137 | /// nRF52 peripheral: TWIM0 138 | pub TWIM0: pac::TWIM0, 139 | 140 | /// nRF52 peripheral: TWIS0 141 | pub TWIS0: pac::TWIS0, 142 | 143 | /// nRF52 peripheral: UARTE0 144 | pub UARTE0: pac::UARTE0, 145 | 146 | /// nRF52 peripheral: UARTE1 147 | pub UARTE1: pac::UARTE1, 148 | 149 | /// nRF52 peripheral: SAADC 150 | pub ADC: pac::SAADC, 151 | 152 | /// nRF52 peripheral: POWER 153 | pub POWER: pac::POWER, 154 | 155 | /// nRF52 peripheral: SPI0 156 | pub SPI0: pac::SPI0, 157 | 158 | /// nRF52 peripheral: SPI1 159 | pub SPI1: pac::SPI1, 160 | 161 | /// nRF52 peripheral: SPI2 162 | pub SPI2: pac::SPI2, 163 | 164 | /// nRF52 peripheral: UART0 165 | pub UART0: pac::UART0, 166 | 167 | /// nRF52 peripheral: TWI0 168 | pub TWI0: pac::TWI0, 169 | 170 | /// nRF52 peripheral: TWI1 171 | pub TWI1: pac::TWI1, 172 | 173 | /// nRF52 peripheral: SPIS1 174 | pub SPIS1: pac::SPIS1, 175 | 176 | /// nRF52 peripheral: ECB 177 | pub ECB: pac::ECB, 178 | 179 | /// nRF52 peripheral: AAR 180 | pub AAR: pac::AAR, 181 | 182 | /// nRF52 peripheral: CCM 183 | pub CCM: pac::CCM, 184 | 185 | /// nRF52 peripheral: WDT 186 | pub WDT: pac::WDT, 187 | 188 | /// nRF52 peripheral: QDEC 189 | pub QDEC: pac::QDEC, 190 | 191 | /// nRF52 peripheral: LPCOMP 192 | pub LPCOMP: pac::LPCOMP, 193 | 194 | /// nRF52 peripheral: NVMC 195 | pub NVMC: pac::NVMC, 196 | 197 | /// nRF52 peripheral: UICR 198 | pub UICR: pac::UICR, 199 | } 200 | 201 | impl Board { 202 | /// Take the peripherals safely 203 | /// 204 | /// This method will return an instance of the board the first time it is 205 | /// called. It will return only `None` on subsequent calls. 206 | /// This function can also return `None` if one of the the peripherals was 207 | /// already taken. 208 | pub fn take() -> Option { 209 | Some(Self::new( 210 | pac::Peripherals::take()?, 211 | pac::CorePeripherals::take()?, 212 | )) 213 | } 214 | 215 | /// Fallback method in the case peripherals and core peripherals were taken 216 | /// elsewhere already. 217 | /// 218 | /// This method will take the peripherals and core peripherals and 219 | /// return an instance of the board. 220 | /// 221 | /// An exemplary usecase is shown in the rtic display example. 222 | pub fn new(p: pac::Peripherals, cp: pac::CorePeripherals) -> Self { 223 | let p0parts = p0::Parts::new(p.P0); 224 | let p1parts = p1::Parts::new(p.P1); 225 | Self { 226 | pins: Pins { 227 | p0_01: p0parts.p0_01, 228 | //p0_02: p0parts.p0_02, 229 | //p0_03: p0parts.p0_03, 230 | //p0_04: p0parts.p0_04, 231 | p0_07: p0parts.p0_07, 232 | //p0_09: p0parts.p0_09, 233 | //p0_10: p0parts.p0_10, 234 | //p0_12: p0parts.p0_12, 235 | p0_13: p0parts.p0_13, 236 | p0_17: p0parts.p0_17, 237 | p0_18: p0parts.p0_18, 238 | p0_25: p0parts.p0_25, 239 | p0_27: p0parts.p0_27, 240 | p0_29: p0parts.p0_29, 241 | p1_01: p1parts.p1_01, 242 | //p1_02: p1parts.p1_02, 243 | p1_03: p1parts.p1_03, 244 | p1_04: p1parts.p1_04, 245 | p1_06: p1parts.p1_06, 246 | p1_07: p1parts.p1_07, 247 | p1_09: p1parts.p1_09, 248 | }, 249 | edge: Edge { 250 | e00: p0parts.p0_02, 251 | e01: p0parts.p0_03, 252 | e02: p0parts.p0_04, 253 | e08: p0parts.p0_10, 254 | e09: p0parts.p0_09, 255 | e12: p0parts.p0_12, 256 | e16: p1parts.p1_02, 257 | }, 258 | display_pins: DisplayPins { 259 | col1: p0parts.p0_28.into_push_pull_output(Level::High), 260 | col2: p0parts.p0_11.into_push_pull_output(Level::High), 261 | col3: p0parts.p0_31.into_push_pull_output(Level::High), 262 | col4: p1parts.p1_05.into_push_pull_output(Level::High), 263 | col5: p0parts.p0_30.into_push_pull_output(Level::High), 264 | row1: p0parts.p0_21.into_push_pull_output(Level::Low), 265 | row2: p0parts.p0_22.into_push_pull_output(Level::Low), 266 | row3: p0parts.p0_15.into_push_pull_output(Level::Low), 267 | row4: p0parts.p0_24.into_push_pull_output(Level::Low), 268 | row5: p0parts.p0_19.into_push_pull_output(Level::Low), 269 | }, 270 | buttons: Buttons { 271 | button_a: p0parts.p0_14.into_floating_input(), 272 | button_b: p0parts.p0_23.into_floating_input(), 273 | }, 274 | speaker_pin: p0parts.p0_00, 275 | microphone_pins: MicrophonePins { 276 | mic_in: p0parts.p0_05.into_floating_input(), 277 | mic_run: p0parts 278 | .p0_20 279 | .into_open_drain_output(Disconnect0HighDrive1, Level::Low), 280 | }, 281 | i2c_internal: I2CInternalPins { 282 | scl: p0parts.p0_08.into_floating_input(), 283 | sda: p0parts.p0_16.into_floating_input(), 284 | }, 285 | i2c_external: I2CExternalPins { 286 | scl: p0parts.p0_26.into_floating_input(), 287 | sda: p1parts.p1_00.into_floating_input(), 288 | }, 289 | uart: UartPins { 290 | tx: p0parts.p0_06.into_push_pull_output(Level::High), 291 | rx: p1parts.p1_08.into_floating_input(), 292 | }, 293 | 294 | // Core peripherals 295 | CBP: cp.CBP, 296 | CPUID: cp.CPUID, 297 | DCB: cp.DCB, 298 | DWT: cp.DWT, 299 | FPB: cp.FPB, 300 | FPU: cp.FPU, 301 | ITM: cp.ITM, 302 | MPU: cp.MPU, 303 | NVIC: cp.NVIC, 304 | SCB: cp.SCB, 305 | SYST: cp.SYST, 306 | TPIU: cp.TPIU, 307 | 308 | // nRF52 peripherals 309 | CLOCK: p.CLOCK, 310 | FICR: p.FICR, 311 | GPIOTE: p.GPIOTE, 312 | PPI: p.PPI, 313 | PWM0: p.PWM0, 314 | PWM1: p.PWM1, 315 | PWM2: p.PWM2, 316 | PWM3: p.PWM3, 317 | RADIO: p.RADIO, 318 | RNG: p.RNG, 319 | RTC0: p.RTC0, 320 | RTC1: p.RTC1, 321 | RTC2: p.RTC2, 322 | TEMP: p.TEMP, 323 | TIMER0: p.TIMER0, 324 | TIMER1: p.TIMER1, 325 | TIMER2: p.TIMER2, 326 | TIMER3: p.TIMER3, 327 | TIMER4: p.TIMER4, 328 | TWIM0: p.TWIM0, 329 | TWIS0: p.TWIS0, 330 | UARTE0: p.UARTE0, 331 | UARTE1: p.UARTE1, 332 | ADC: p.SAADC, 333 | SPI0: p.SPI0, 334 | SPI1: p.SPI1, 335 | SPI2: p.SPI2, 336 | POWER: p.POWER, 337 | UART0: p.UART0, 338 | TWI0: p.TWI0, 339 | TWI1: p.TWI1, 340 | SPIS1: p.SPIS1, 341 | ECB: p.ECB, 342 | AAR: p.AAR, 343 | CCM: p.CCM, 344 | WDT: p.WDT, 345 | QDEC: p.QDEC, 346 | LPCOMP: p.LPCOMP, 347 | NVMC: p.NVMC, 348 | UICR: p.UICR, 349 | } 350 | } 351 | } 352 | 353 | /// Unused GPIO pins 354 | #[allow(missing_docs)] 355 | pub struct Pins { 356 | // pub p0_00: p0::P0_00, // Speaker 357 | pub p0_01: p0::P0_01, 358 | // pub p0_02: p0::P0_02, // PAD0, EDGE00 359 | // pub p0_03: p0::P0_03, // PAD1, EDGE01 360 | // pub p0_04: p0::P0_04, // PAD2, EDGE02 361 | // pub p0_05: p0::P0_05, // Microphone IN 362 | // pub p0_06: p0::P0_06, // UART RX 363 | pub p0_07: p0::P0_07, 364 | // pub p0_08: p0::P0_08, // INT_SCL 365 | // pub p0_09: p0::P0_09, // EDGE09 366 | // pub p0_10: p0::P0_10, // EDGE08 367 | // pub p0_11: p0::P0_11, // LEDs 368 | // pub p0_12: p0::P0_12, // EDGE12 369 | pub p0_13: p0::P0_13, 370 | // pub p0_14: p0::P0_14, // BTN_A 371 | // pub p0_15: p0::P0_15, // LEDs 372 | // pub p0_16: p0::P0_16, // INT_SDA 373 | pub p0_17: p0::P0_17, 374 | pub p0_18: p0::P0_18, 375 | // pub p0_19: p0::P0_19, // LEDs 376 | // pub p0_20: p0::P0_20, // Microphone RUN 377 | // pub p0_21: p0::P0_21, // LEDs 378 | // pub p0_22: p0::P0_22, // LEDs 379 | // pub p0_23: p0::P0_23, // BTN_B 380 | // pub p0_24: p0::P0_24, // LEDs 381 | pub p0_25: p0::P0_25, 382 | // pub p0_26: p0::P0_26, // SCL 383 | pub p0_27: p0::P0_27, 384 | // pub p0_28: p0::P0_28, // LEDs 385 | pub p0_29: p0::P0_29, 386 | // pub p0_30: p0::P0_30, // LEDs 387 | // pub p0_31: p0::P0_31, // LEDs 388 | // pub p1_00: p1::P1_00, // SDA 389 | pub p1_01: p1::P1_01, 390 | // pub p1_02: p1::P1_02, // EDGE16 391 | pub p1_03: p1::P1_03, 392 | pub p1_04: p1::P1_04, 393 | // pub p1_05: p1::P1_05, // LEDs 394 | pub p1_06: p1::P1_06, 395 | pub p1_07: p1::P1_07, 396 | // pub p1_08: p1::P1_08, // UART TX 397 | pub p1_09: p1::P1_09, 398 | } 399 | 400 | /// Unused edge connector pins 401 | #[allow(missing_docs)] 402 | pub struct Edge { 403 | /* edge connector */ 404 | // pub e03: COL3, 405 | pub e00: EDGE00, // <- big pad 1 406 | // pub e04: COL1, 407 | // pub e05: BTN_A, 408 | // pub e06: COL4, 409 | // pub e07: COL2, 410 | pub e01: EDGE01, // <- big pad 2 411 | pub e08: EDGE08, 412 | pub e09: EDGE09, 413 | // pub e10: COL5, 414 | // pub e11: BTN_B, 415 | pub e12: EDGE12, 416 | pub e02: EDGE02, // <- big pad 3 417 | //pub e13: SCK, 418 | //pub e14: MISO, 419 | //pub e15: MOSI, 420 | pub e16: EDGE16, 421 | // +V 422 | // +V 423 | // +V 424 | // pub e19: SCL, 425 | // pub e20: SDA, 426 | // GND 427 | // GND 428 | // GND 429 | } 430 | 431 | /// Buttons 432 | pub struct Buttons { 433 | /// Left hand button 434 | pub button_a: BTN_A, 435 | /// Right hand button 436 | pub button_b: BTN_B, 437 | } 438 | 439 | /// I2C internal bus pins 440 | pub struct I2CInternalPins { 441 | /// Internal I2C clock pin 442 | pub scl: INT_SCL, 443 | /// Internal I2C data pin 444 | pub sda: INT_SDA, 445 | } 446 | 447 | impl From for twim::Pins { 448 | fn from(pins: I2CInternalPins) -> Self { 449 | Self { 450 | scl: pins.scl.degrade(), 451 | sda: pins.sda.degrade(), 452 | } 453 | } 454 | } 455 | 456 | impl From for twis::Pins { 457 | fn from(pins: I2CInternalPins) -> Self { 458 | Self { 459 | scl: pins.scl.degrade(), 460 | sda: pins.sda.degrade(), 461 | } 462 | } 463 | } 464 | 465 | /// I2C external bus pins 466 | pub struct I2CExternalPins { 467 | /// External I2C clock pin 468 | pub scl: SCL, 469 | /// External I2C data pin 470 | pub sda: SDA, 471 | } 472 | 473 | impl From for twim::Pins { 474 | fn from(pins: I2CExternalPins) -> Self { 475 | Self { 476 | scl: pins.scl.degrade(), 477 | sda: pins.sda.degrade(), 478 | } 479 | } 480 | } 481 | 482 | impl From for twis::Pins { 483 | fn from(pins: I2CExternalPins) -> Self { 484 | Self { 485 | scl: pins.scl.degrade(), 486 | sda: pins.sda.degrade(), 487 | } 488 | } 489 | } 490 | 491 | /// UART to debugger pins 492 | pub struct UartPins { 493 | tx: UART_TX, 494 | rx: UART_RX, 495 | } 496 | 497 | impl From for uarte::Pins { 498 | fn from(pins: UartPins) -> Self { 499 | Self { 500 | txd: pins.tx.degrade(), 501 | rxd: pins.rx.degrade(), 502 | cts: None, 503 | rts: None, 504 | } 505 | } 506 | } 507 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "analog" 7 | version = "0.1.0" 8 | dependencies = [ 9 | "cortex-m", 10 | "cortex-m-rt", 11 | "defmt", 12 | "defmt-rtt", 13 | "microbit", 14 | "microbit-v2", 15 | "panic-halt", 16 | ] 17 | 18 | [[package]] 19 | name = "analog-v1" 20 | version = "0.1.0" 21 | dependencies = [ 22 | "cortex-m", 23 | "cortex-m-rt", 24 | "defmt", 25 | "defmt-rtt", 26 | "microbit", 27 | "panic-halt", 28 | ] 29 | 30 | [[package]] 31 | name = "analog-v2" 32 | version = "0.1.0" 33 | dependencies = [ 34 | "cortex-m", 35 | "cortex-m-rt", 36 | "defmt", 37 | "defmt-rtt", 38 | "microbit-v2", 39 | "panic-halt", 40 | ] 41 | 42 | [[package]] 43 | name = "android_system_properties" 44 | version = "0.1.5" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 47 | dependencies = [ 48 | "libc", 49 | ] 50 | 51 | [[package]] 52 | name = "atomic-polyfill" 53 | version = "1.0.3" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" 56 | dependencies = [ 57 | "critical-section", 58 | ] 59 | 60 | [[package]] 61 | name = "autocfg" 62 | version = "1.3.0" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 65 | 66 | [[package]] 67 | name = "az" 68 | version = "1.2.1" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" 71 | 72 | [[package]] 73 | name = "bare-metal" 74 | version = "0.2.5" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" 77 | dependencies = [ 78 | "rustc_version 0.2.3", 79 | ] 80 | 81 | [[package]] 82 | name = "bare-metal" 83 | version = "1.0.0" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" 86 | 87 | [[package]] 88 | name = "bitfield" 89 | version = "0.13.2" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" 92 | 93 | [[package]] 94 | name = "bitflags" 95 | version = "1.3.2" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 98 | 99 | [[package]] 100 | name = "bitflags" 101 | version = "2.9.1" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" 104 | 105 | [[package]] 106 | name = "bumpalo" 107 | version = "3.16.0" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 110 | 111 | [[package]] 112 | name = "bytemuck" 113 | version = "1.16.3" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "102087e286b4677862ea56cf8fc58bb2cdfa8725c40ffb80fe3a008eb7f2fc83" 116 | 117 | [[package]] 118 | name = "byteorder" 119 | version = "1.5.0" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 122 | 123 | [[package]] 124 | name = "cargo_toml" 125 | version = "0.22.3" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" 128 | dependencies = [ 129 | "serde", 130 | "toml", 131 | ] 132 | 133 | [[package]] 134 | name = "cast" 135 | version = "0.3.0" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" 138 | 139 | [[package]] 140 | name = "cc" 141 | version = "1.1.7" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" 144 | 145 | [[package]] 146 | name = "cfg-if" 147 | version = "1.0.0" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 150 | 151 | [[package]] 152 | name = "chrono" 153 | version = "0.4.42" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" 156 | dependencies = [ 157 | "iana-time-zone", 158 | "js-sys", 159 | "num-traits", 160 | "wasm-bindgen", 161 | "windows-link", 162 | ] 163 | 164 | [[package]] 165 | name = "core-foundation-sys" 166 | version = "0.8.6" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" 169 | 170 | [[package]] 171 | name = "cortex-m" 172 | version = "0.7.7" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" 175 | dependencies = [ 176 | "bare-metal 0.2.5", 177 | "bitfield", 178 | "critical-section", 179 | "embedded-hal 0.2.7", 180 | "volatile-register", 181 | ] 182 | 183 | [[package]] 184 | name = "cortex-m-rt" 185 | version = "0.7.5" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6" 188 | dependencies = [ 189 | "cortex-m-rt-macros", 190 | ] 191 | 192 | [[package]] 193 | name = "cortex-m-rt-macros" 194 | version = "0.7.5" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" 197 | dependencies = [ 198 | "proc-macro2", 199 | "quote", 200 | "syn 2.0.89", 201 | ] 202 | 203 | [[package]] 204 | name = "cortex-m-rtic" 205 | version = "1.1.4" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "d696ae7390bdb9f7978f71ca7144256a2c4616240a6df9002da3c451f9fc8f02" 208 | dependencies = [ 209 | "bare-metal 1.0.0", 210 | "cortex-m", 211 | "cortex-m-rtic-macros", 212 | "heapless 0.7.17", 213 | "rtic-core", 214 | "rtic-monotonic", 215 | "version_check", 216 | ] 217 | 218 | [[package]] 219 | name = "cortex-m-rtic-macros" 220 | version = "1.1.6" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "eefb40b1ca901c759d29526e5c8a0a1b246c20caaa5b4cc5d0f0b94debecd4c7" 223 | dependencies = [ 224 | "proc-macro-error", 225 | "proc-macro2", 226 | "quote", 227 | "rtic-syntax", 228 | "syn 1.0.109", 229 | ] 230 | 231 | [[package]] 232 | name = "critical-section" 233 | version = "1.2.0" 234 | source = "registry+https://github.com/rust-lang/crates.io-index" 235 | checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" 236 | 237 | [[package]] 238 | name = "crunchy" 239 | version = "0.2.2" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" 242 | 243 | [[package]] 244 | name = "defmt" 245 | version = "1.0.1" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78" 248 | dependencies = [ 249 | "bitflags 1.3.2", 250 | "defmt-macros", 251 | ] 252 | 253 | [[package]] 254 | name = "defmt-macros" 255 | version = "1.0.1" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e" 258 | dependencies = [ 259 | "defmt-parser", 260 | "proc-macro-error2", 261 | "proc-macro2", 262 | "quote", 263 | "syn 2.0.89", 264 | ] 265 | 266 | [[package]] 267 | name = "defmt-parser" 268 | version = "1.0.0" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" 271 | dependencies = [ 272 | "thiserror", 273 | ] 274 | 275 | [[package]] 276 | name = "defmt-rtt" 277 | version = "1.1.0" 278 | source = "registry+https://github.com/rust-lang/crates.io-index" 279 | checksum = "93d5a25c99d89c40f5676bec8cefe0614f17f0f40e916f98e345dae941807f9e" 280 | dependencies = [ 281 | "critical-section", 282 | "defmt", 283 | ] 284 | 285 | [[package]] 286 | name = "display-blocking" 287 | version = "0.1.0" 288 | dependencies = [ 289 | "cortex-m", 290 | "cortex-m-rt", 291 | "defmt", 292 | "defmt-rtt", 293 | "embedded-hal 1.0.0", 294 | "microbit", 295 | "microbit-v2", 296 | "panic-halt", 297 | ] 298 | 299 | [[package]] 300 | name = "display-nonblocking" 301 | version = "0.1.0" 302 | dependencies = [ 303 | "cortex-m", 304 | "cortex-m-rt", 305 | "defmt", 306 | "defmt-rtt", 307 | "microbit", 308 | "microbit-v2", 309 | "panic-halt", 310 | ] 311 | 312 | [[package]] 313 | name = "display-rtic" 314 | version = "0.1.0" 315 | dependencies = [ 316 | "cortex-m", 317 | "cortex-m-rtic", 318 | "defmt", 319 | "defmt-rtt", 320 | "microbit", 321 | "microbit-v2", 322 | "panic-halt", 323 | ] 324 | 325 | [[package]] 326 | name = "display-text-rtic" 327 | version = "0.1.0" 328 | dependencies = [ 329 | "cortex-m", 330 | "cortex-m-rtic", 331 | "defmt", 332 | "defmt-rtt", 333 | "microbit", 334 | "microbit-text", 335 | "microbit-v2", 336 | "panic-halt", 337 | ] 338 | 339 | [[package]] 340 | name = "embedded-dma" 341 | version = "0.2.0" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "994f7e5b5cb23521c22304927195f236813053eb9c065dd2226a32ba64695446" 344 | dependencies = [ 345 | "stable_deref_trait", 346 | ] 347 | 348 | [[package]] 349 | name = "embedded-hal" 350 | version = "0.2.7" 351 | source = "registry+https://github.com/rust-lang/crates.io-index" 352 | checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" 353 | dependencies = [ 354 | "nb 0.1.3", 355 | "void", 356 | ] 357 | 358 | [[package]] 359 | name = "embedded-hal" 360 | version = "1.0.0" 361 | source = "registry+https://github.com/rust-lang/crates.io-index" 362 | checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" 363 | 364 | [[package]] 365 | name = "embedded-io" 366 | version = "0.7.1" 367 | source = "registry+https://github.com/rust-lang/crates.io-index" 368 | checksum = "9eb1aa714776b75c7e67e1da744b81a129b3ff919c8712b5e1b32252c1f07cc7" 369 | 370 | [[package]] 371 | name = "embedded-storage" 372 | version = "0.3.1" 373 | source = "registry+https://github.com/rust-lang/crates.io-index" 374 | checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" 375 | 376 | [[package]] 377 | name = "equivalent" 378 | version = "1.0.1" 379 | source = "registry+https://github.com/rust-lang/crates.io-index" 380 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 381 | 382 | [[package]] 383 | name = "fixed" 384 | version = "1.28.0" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "85c6e0b89bf864acd20590dbdbad56f69aeb898abfc9443008fd7bd48b2cc85a" 387 | dependencies = [ 388 | "az", 389 | "bytemuck", 390 | "half", 391 | "typenum", 392 | ] 393 | 394 | [[package]] 395 | name = "gpio-direct-blinky" 396 | version = "0.1.0" 397 | dependencies = [ 398 | "cortex-m", 399 | "cortex-m-rt", 400 | "defmt", 401 | "microbit", 402 | "microbit-v2", 403 | "panic-halt", 404 | ] 405 | 406 | [[package]] 407 | name = "gpio-hal-blinky" 408 | version = "0.1.0" 409 | dependencies = [ 410 | "cortex-m-rt", 411 | "defmt", 412 | "defmt-rtt", 413 | "embedded-hal 1.0.0", 414 | "microbit", 415 | "microbit-v2", 416 | "panic-halt", 417 | ] 418 | 419 | [[package]] 420 | name = "gpio-hal-ledbutton" 421 | version = "0.1.0" 422 | dependencies = [ 423 | "cortex-m", 424 | "cortex-m-rt", 425 | "defmt", 426 | "defmt-rtt", 427 | "embedded-hal 1.0.0", 428 | "microbit", 429 | "microbit-v2", 430 | "panic-halt", 431 | ] 432 | 433 | [[package]] 434 | name = "gpio-hal-printbuttons" 435 | version = "0.1.0" 436 | dependencies = [ 437 | "cortex-m", 438 | "cortex-m-rt", 439 | "defmt", 440 | "defmt-rtt", 441 | "microbit", 442 | "microbit-v2", 443 | "panic-halt", 444 | ] 445 | 446 | [[package]] 447 | name = "half" 448 | version = "2.4.1" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" 451 | dependencies = [ 452 | "cfg-if", 453 | "crunchy", 454 | ] 455 | 456 | [[package]] 457 | name = "hash32" 458 | version = "0.2.1" 459 | source = "registry+https://github.com/rust-lang/crates.io-index" 460 | checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" 461 | dependencies = [ 462 | "byteorder", 463 | ] 464 | 465 | [[package]] 466 | name = "hash32" 467 | version = "0.3.1" 468 | source = "registry+https://github.com/rust-lang/crates.io-index" 469 | checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" 470 | dependencies = [ 471 | "byteorder", 472 | ] 473 | 474 | [[package]] 475 | name = "hashbrown" 476 | version = "0.12.3" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 479 | 480 | [[package]] 481 | name = "hashbrown" 482 | version = "0.14.5" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 485 | 486 | [[package]] 487 | name = "heapless" 488 | version = "0.7.17" 489 | source = "registry+https://github.com/rust-lang/crates.io-index" 490 | checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" 491 | dependencies = [ 492 | "atomic-polyfill", 493 | "hash32 0.2.1", 494 | "rustc_version 0.4.0", 495 | "spin", 496 | "stable_deref_trait", 497 | ] 498 | 499 | [[package]] 500 | name = "heapless" 501 | version = "0.8.0" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" 504 | dependencies = [ 505 | "hash32 0.3.1", 506 | "stable_deref_trait", 507 | ] 508 | 509 | [[package]] 510 | name = "iana-time-zone" 511 | version = "0.1.60" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" 514 | dependencies = [ 515 | "android_system_properties", 516 | "core-foundation-sys", 517 | "iana-time-zone-haiku", 518 | "js-sys", 519 | "wasm-bindgen", 520 | "windows-core", 521 | ] 522 | 523 | [[package]] 524 | name = "iana-time-zone-haiku" 525 | version = "0.1.2" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 528 | dependencies = [ 529 | "cc", 530 | ] 531 | 532 | [[package]] 533 | name = "indexmap" 534 | version = "1.9.3" 535 | source = "registry+https://github.com/rust-lang/crates.io-index" 536 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 537 | dependencies = [ 538 | "autocfg", 539 | "hashbrown 0.12.3", 540 | ] 541 | 542 | [[package]] 543 | name = "indexmap" 544 | version = "2.3.0" 545 | source = "registry+https://github.com/rust-lang/crates.io-index" 546 | checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" 547 | dependencies = [ 548 | "equivalent", 549 | "hashbrown 0.14.5", 550 | ] 551 | 552 | [[package]] 553 | name = "js-sys" 554 | version = "0.3.69" 555 | source = "registry+https://github.com/rust-lang/crates.io-index" 556 | checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" 557 | dependencies = [ 558 | "wasm-bindgen", 559 | ] 560 | 561 | [[package]] 562 | name = "libc" 563 | version = "0.2.155" 564 | source = "registry+https://github.com/rust-lang/crates.io-index" 565 | checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" 566 | 567 | [[package]] 568 | name = "lock_api" 569 | version = "0.4.12" 570 | source = "registry+https://github.com/rust-lang/crates.io-index" 571 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 572 | dependencies = [ 573 | "autocfg", 574 | "scopeguard", 575 | ] 576 | 577 | [[package]] 578 | name = "log" 579 | version = "0.4.22" 580 | source = "registry+https://github.com/rust-lang/crates.io-index" 581 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 582 | 583 | [[package]] 584 | name = "lsm303agr" 585 | version = "1.1.0" 586 | source = "registry+https://github.com/rust-lang/crates.io-index" 587 | checksum = "f24b486ceef047c043c19c24669379f1049269927430c09f0444aac4685d2c2f" 588 | dependencies = [ 589 | "bitflags 2.9.1", 590 | "embedded-hal 1.0.0", 591 | "maybe-async-cfg", 592 | "nb 1.1.0", 593 | ] 594 | 595 | [[package]] 596 | name = "magnetometer" 597 | version = "0.1.0" 598 | dependencies = [ 599 | "cortex-m", 600 | "cortex-m-rt", 601 | "defmt", 602 | "defmt-rtt", 603 | "embedded-hal 1.0.0", 604 | "lsm303agr", 605 | "microbit", 606 | "microbit-v2", 607 | "panic-halt", 608 | ] 609 | 610 | [[package]] 611 | name = "manyhow" 612 | version = "0.11.4" 613 | source = "registry+https://github.com/rust-lang/crates.io-index" 614 | checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587" 615 | dependencies = [ 616 | "manyhow-macros", 617 | "proc-macro2", 618 | "quote", 619 | "syn 1.0.109", 620 | "syn 2.0.89", 621 | ] 622 | 623 | [[package]] 624 | name = "manyhow-macros" 625 | version = "0.11.4" 626 | source = "registry+https://github.com/rust-lang/crates.io-index" 627 | checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495" 628 | dependencies = [ 629 | "proc-macro-utils", 630 | "proc-macro2", 631 | "quote", 632 | ] 633 | 634 | [[package]] 635 | name = "maybe-async-cfg" 636 | version = "0.2.5" 637 | source = "registry+https://github.com/rust-lang/crates.io-index" 638 | checksum = "8dbfaa67a76e2623580df07d6bb5e7956c0a4bae4b418314083a9c619bd66627" 639 | dependencies = [ 640 | "manyhow", 641 | "proc-macro2", 642 | "pulldown-cmark", 643 | "quote", 644 | "syn 1.0.109", 645 | ] 646 | 647 | [[package]] 648 | name = "memchr" 649 | version = "2.7.5" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" 652 | 653 | [[package]] 654 | name = "microbit" 655 | version = "0.16.0" 656 | dependencies = [ 657 | "microbit-common", 658 | ] 659 | 660 | [[package]] 661 | name = "microbit-common" 662 | version = "0.16.0" 663 | dependencies = [ 664 | "embedded-hal 1.0.0", 665 | "nrf51-hal", 666 | "nrf52833-hal", 667 | "tiny-led-matrix", 668 | ] 669 | 670 | [[package]] 671 | name = "microbit-text" 672 | version = "1.0.0" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | checksum = "029db169f7b5f0253f2b348a1f580ed532f7df769fc88ca9e1871ca92ec04c40" 675 | dependencies = [ 676 | "tiny-led-matrix", 677 | ] 678 | 679 | [[package]] 680 | name = "microbit-v2" 681 | version = "0.16.0" 682 | dependencies = [ 683 | "microbit-common", 684 | ] 685 | 686 | [[package]] 687 | name = "nb" 688 | version = "0.1.3" 689 | source = "registry+https://github.com/rust-lang/crates.io-index" 690 | checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" 691 | dependencies = [ 692 | "nb 1.1.0", 693 | ] 694 | 695 | [[package]] 696 | name = "nb" 697 | version = "1.1.0" 698 | source = "registry+https://github.com/rust-lang/crates.io-index" 699 | checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" 700 | 701 | [[package]] 702 | name = "nrf-hal-common" 703 | version = "0.19.0" 704 | source = "registry+https://github.com/rust-lang/crates.io-index" 705 | checksum = "9d8100d0bf6d732ea9b0a294fa2d2dad9cba4fbc5bb655d0afaa984d03d528fe" 706 | dependencies = [ 707 | "cast", 708 | "cfg-if", 709 | "cortex-m", 710 | "embedded-dma", 711 | "embedded-hal 0.2.7", 712 | "embedded-hal 1.0.0", 713 | "embedded-io", 714 | "embedded-storage", 715 | "fixed", 716 | "nb 1.1.0", 717 | "nrf-usbd", 718 | "nrf51-pac", 719 | "nrf52833-pac", 720 | "rand_core", 721 | "void", 722 | ] 723 | 724 | [[package]] 725 | name = "nrf-usbd" 726 | version = "0.3.0" 727 | source = "registry+https://github.com/rust-lang/crates.io-index" 728 | checksum = "aedf862f941154442271ae9914777bd1c93f6d2e0dc9db4cafa160e55ffb9085" 729 | dependencies = [ 730 | "cortex-m", 731 | "critical-section", 732 | "usb-device", 733 | "vcell", 734 | ] 735 | 736 | [[package]] 737 | name = "nrf51-hal" 738 | version = "0.19.0" 739 | source = "registry+https://github.com/rust-lang/crates.io-index" 740 | checksum = "2ec8325f08b5eecc24da8f257c6339b3dc7ee66025ef96e58fc414bbb30aebf6" 741 | dependencies = [ 742 | "nrf-hal-common", 743 | "nrf51-pac", 744 | ] 745 | 746 | [[package]] 747 | name = "nrf51-pac" 748 | version = "0.12.2" 749 | source = "registry+https://github.com/rust-lang/crates.io-index" 750 | checksum = "137f187dc6ee482e27312086bd3c3a83e1c273512782cf131a61957f72fc4219" 751 | dependencies = [ 752 | "cortex-m", 753 | "cortex-m-rt", 754 | "vcell", 755 | ] 756 | 757 | [[package]] 758 | name = "nrf52833-hal" 759 | version = "0.19.0" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "5fa51030952f3454f2faffc64061456f17aec15f492d7b6ef68777bfc438c561" 762 | dependencies = [ 763 | "nrf-hal-common", 764 | "nrf52833-pac", 765 | ] 766 | 767 | [[package]] 768 | name = "nrf52833-pac" 769 | version = "0.12.2" 770 | source = "registry+https://github.com/rust-lang/crates.io-index" 771 | checksum = "10e1358255b360cdc816dd7b6ef81be8c8499c0998277e5249bed222bd0f5241" 772 | dependencies = [ 773 | "cortex-m", 774 | "cortex-m-rt", 775 | "vcell", 776 | ] 777 | 778 | [[package]] 779 | name = "num-traits" 780 | version = "0.2.19" 781 | source = "registry+https://github.com/rust-lang/crates.io-index" 782 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 783 | dependencies = [ 784 | "autocfg", 785 | ] 786 | 787 | [[package]] 788 | name = "once_cell" 789 | version = "1.19.0" 790 | source = "registry+https://github.com/rust-lang/crates.io-index" 791 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 792 | 793 | [[package]] 794 | name = "panic-halt" 795 | version = "1.0.0" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "a513e167849a384b7f9b746e517604398518590a9142f4846a32e3c2a4de7b11" 798 | 799 | [[package]] 800 | name = "portable-atomic" 801 | version = "1.7.0" 802 | source = "registry+https://github.com/rust-lang/crates.io-index" 803 | checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" 804 | 805 | [[package]] 806 | name = "proc-macro-error" 807 | version = "1.0.4" 808 | source = "registry+https://github.com/rust-lang/crates.io-index" 809 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 810 | dependencies = [ 811 | "proc-macro-error-attr", 812 | "proc-macro2", 813 | "quote", 814 | "syn 1.0.109", 815 | "version_check", 816 | ] 817 | 818 | [[package]] 819 | name = "proc-macro-error-attr" 820 | version = "1.0.4" 821 | source = "registry+https://github.com/rust-lang/crates.io-index" 822 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 823 | dependencies = [ 824 | "proc-macro2", 825 | "quote", 826 | "version_check", 827 | ] 828 | 829 | [[package]] 830 | name = "proc-macro-error-attr2" 831 | version = "2.0.0" 832 | source = "registry+https://github.com/rust-lang/crates.io-index" 833 | checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" 834 | dependencies = [ 835 | "proc-macro2", 836 | "quote", 837 | ] 838 | 839 | [[package]] 840 | name = "proc-macro-error2" 841 | version = "2.0.1" 842 | source = "registry+https://github.com/rust-lang/crates.io-index" 843 | checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" 844 | dependencies = [ 845 | "proc-macro-error-attr2", 846 | "proc-macro2", 847 | "quote", 848 | "syn 2.0.89", 849 | ] 850 | 851 | [[package]] 852 | name = "proc-macro-utils" 853 | version = "0.10.0" 854 | source = "registry+https://github.com/rust-lang/crates.io-index" 855 | checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071" 856 | dependencies = [ 857 | "proc-macro2", 858 | "quote", 859 | "smallvec", 860 | ] 861 | 862 | [[package]] 863 | name = "proc-macro2" 864 | version = "1.0.95" 865 | source = "registry+https://github.com/rust-lang/crates.io-index" 866 | checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" 867 | dependencies = [ 868 | "unicode-ident", 869 | ] 870 | 871 | [[package]] 872 | name = "pulldown-cmark" 873 | version = "0.11.3" 874 | source = "registry+https://github.com/rust-lang/crates.io-index" 875 | checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625" 876 | dependencies = [ 877 | "bitflags 2.9.1", 878 | "memchr", 879 | "unicase", 880 | ] 881 | 882 | [[package]] 883 | name = "quote" 884 | version = "1.0.40" 885 | source = "registry+https://github.com/rust-lang/crates.io-index" 886 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 887 | dependencies = [ 888 | "proc-macro2", 889 | ] 890 | 891 | [[package]] 892 | name = "rand" 893 | version = "0.9.2" 894 | source = "registry+https://github.com/rust-lang/crates.io-index" 895 | checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" 896 | dependencies = [ 897 | "rand_core", 898 | ] 899 | 900 | [[package]] 901 | name = "rand_core" 902 | version = "0.9.3" 903 | source = "registry+https://github.com/rust-lang/crates.io-index" 904 | checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" 905 | 906 | [[package]] 907 | name = "rand_pcg" 908 | version = "0.9.0" 909 | source = "registry+https://github.com/rust-lang/crates.io-index" 910 | checksum = "b48ac3f7ffaab7fac4d2376632268aa5f89abdb55f7ebf8f4d11fffccb2320f7" 911 | dependencies = [ 912 | "rand_core", 913 | ] 914 | 915 | [[package]] 916 | name = "rng-direct" 917 | version = "0.1.0" 918 | dependencies = [ 919 | "cortex-m", 920 | "cortex-m-rt", 921 | "defmt", 922 | "defmt-rtt", 923 | "microbit", 924 | "microbit-v2", 925 | "panic-halt", 926 | ] 927 | 928 | [[package]] 929 | name = "rng-hal-printrandserial" 930 | version = "0.1.0" 931 | dependencies = [ 932 | "cortex-m", 933 | "cortex-m-rt", 934 | "defmt", 935 | "defmt-rtt", 936 | "microbit", 937 | "microbit-v2", 938 | "panic-halt", 939 | "rand", 940 | "rand_pcg", 941 | ] 942 | 943 | [[package]] 944 | name = "rtic-core" 945 | version = "1.0.0" 946 | source = "registry+https://github.com/rust-lang/crates.io-index" 947 | checksum = "d9369355b04d06a3780ec0f51ea2d225624db777acbc60abd8ca4832da5c1a42" 948 | 949 | [[package]] 950 | name = "rtic-monotonic" 951 | version = "1.0.0" 952 | source = "registry+https://github.com/rust-lang/crates.io-index" 953 | checksum = "fb8b0b822d1a366470b9cea83a1d4e788392db763539dc4ba022bcc787fece82" 954 | 955 | [[package]] 956 | name = "rtic-syntax" 957 | version = "1.0.3" 958 | source = "registry+https://github.com/rust-lang/crates.io-index" 959 | checksum = "5f5e215601dc467752c2bddc6284a622c6f3d2bab569d992adcd5ab7e4cb9478" 960 | dependencies = [ 961 | "indexmap 1.9.3", 962 | "proc-macro2", 963 | "quote", 964 | "syn 1.0.109", 965 | ] 966 | 967 | [[package]] 968 | name = "rustc_version" 969 | version = "0.2.3" 970 | source = "registry+https://github.com/rust-lang/crates.io-index" 971 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 972 | dependencies = [ 973 | "semver 0.9.0", 974 | ] 975 | 976 | [[package]] 977 | name = "rustc_version" 978 | version = "0.4.0" 979 | source = "registry+https://github.com/rust-lang/crates.io-index" 980 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 981 | dependencies = [ 982 | "semver 1.0.23", 983 | ] 984 | 985 | [[package]] 986 | name = "scopeguard" 987 | version = "1.2.0" 988 | source = "registry+https://github.com/rust-lang/crates.io-index" 989 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 990 | 991 | [[package]] 992 | name = "semver" 993 | version = "0.9.0" 994 | source = "registry+https://github.com/rust-lang/crates.io-index" 995 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 996 | dependencies = [ 997 | "semver-parser", 998 | ] 999 | 1000 | [[package]] 1001 | name = "semver" 1002 | version = "1.0.23" 1003 | source = "registry+https://github.com/rust-lang/crates.io-index" 1004 | checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" 1005 | 1006 | [[package]] 1007 | name = "semver-parser" 1008 | version = "0.7.0" 1009 | source = "registry+https://github.com/rust-lang/crates.io-index" 1010 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 1011 | 1012 | [[package]] 1013 | name = "serde" 1014 | version = "1.0.219" 1015 | source = "registry+https://github.com/rust-lang/crates.io-index" 1016 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 1017 | dependencies = [ 1018 | "serde_derive", 1019 | ] 1020 | 1021 | [[package]] 1022 | name = "serde_derive" 1023 | version = "1.0.219" 1024 | source = "registry+https://github.com/rust-lang/crates.io-index" 1025 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 1026 | dependencies = [ 1027 | "proc-macro2", 1028 | "quote", 1029 | "syn 2.0.89", 1030 | ] 1031 | 1032 | [[package]] 1033 | name = "serde_spanned" 1034 | version = "1.0.0" 1035 | source = "registry+https://github.com/rust-lang/crates.io-index" 1036 | checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" 1037 | dependencies = [ 1038 | "serde", 1039 | ] 1040 | 1041 | [[package]] 1042 | name = "serial-direct-echo" 1043 | version = "0.1.0" 1044 | dependencies = [ 1045 | "cortex-m-rt", 1046 | "defmt-rtt", 1047 | "microbit", 1048 | "panic-halt", 1049 | ] 1050 | 1051 | [[package]] 1052 | name = "serial-direct-helloworld" 1053 | version = "0.1.0" 1054 | dependencies = [ 1055 | "cortex-m-rt", 1056 | "defmt-rtt", 1057 | "microbit", 1058 | "panic-halt", 1059 | ] 1060 | 1061 | [[package]] 1062 | name = "serial-hal-blocking-echo" 1063 | version = "0.1.0" 1064 | dependencies = [ 1065 | "cortex-m-rt", 1066 | "defmt-rtt", 1067 | "embedded-hal 1.0.0", 1068 | "embedded-io", 1069 | "microbit", 1070 | "microbit-v2", 1071 | "nb 1.1.0", 1072 | "panic-halt", 1073 | ] 1074 | 1075 | [[package]] 1076 | name = "servo" 1077 | version = "0.1.0" 1078 | dependencies = [ 1079 | "cortex-m", 1080 | "cortex-m-rt", 1081 | "defmt", 1082 | "defmt-rtt", 1083 | "microbit", 1084 | "microbit-v2", 1085 | "panic-halt", 1086 | ] 1087 | 1088 | [[package]] 1089 | name = "smallvec" 1090 | version = "1.15.1" 1091 | source = "registry+https://github.com/rust-lang/crates.io-index" 1092 | checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 1093 | 1094 | [[package]] 1095 | name = "spin" 1096 | version = "0.9.8" 1097 | source = "registry+https://github.com/rust-lang/crates.io-index" 1098 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1099 | dependencies = [ 1100 | "lock_api", 1101 | ] 1102 | 1103 | [[package]] 1104 | name = "stable_deref_trait" 1105 | version = "1.2.0" 1106 | source = "registry+https://github.com/rust-lang/crates.io-index" 1107 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1108 | 1109 | [[package]] 1110 | name = "syn" 1111 | version = "1.0.109" 1112 | source = "registry+https://github.com/rust-lang/crates.io-index" 1113 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 1114 | dependencies = [ 1115 | "proc-macro2", 1116 | "quote", 1117 | "unicode-ident", 1118 | ] 1119 | 1120 | [[package]] 1121 | name = "syn" 1122 | version = "2.0.89" 1123 | source = "registry+https://github.com/rust-lang/crates.io-index" 1124 | checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" 1125 | dependencies = [ 1126 | "proc-macro2", 1127 | "quote", 1128 | "unicode-ident", 1129 | ] 1130 | 1131 | [[package]] 1132 | name = "thiserror" 1133 | version = "2.0.3" 1134 | source = "registry+https://github.com/rust-lang/crates.io-index" 1135 | checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" 1136 | dependencies = [ 1137 | "thiserror-impl", 1138 | ] 1139 | 1140 | [[package]] 1141 | name = "thiserror-impl" 1142 | version = "2.0.3" 1143 | source = "registry+https://github.com/rust-lang/crates.io-index" 1144 | checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" 1145 | dependencies = [ 1146 | "proc-macro2", 1147 | "quote", 1148 | "syn 2.0.89", 1149 | ] 1150 | 1151 | [[package]] 1152 | name = "tiny-led-matrix" 1153 | version = "1.0.2" 1154 | source = "registry+https://github.com/rust-lang/crates.io-index" 1155 | checksum = "a718c727b686154a7c7913f70d7ebc8956f701cbab466bc22035cb27f378882b" 1156 | 1157 | [[package]] 1158 | name = "toml" 1159 | version = "0.9.2" 1160 | source = "registry+https://github.com/rust-lang/crates.io-index" 1161 | checksum = "ed0aee96c12fa71097902e0bb061a5e1ebd766a6636bb605ba401c45c1650eac" 1162 | dependencies = [ 1163 | "indexmap 2.3.0", 1164 | "serde", 1165 | "serde_spanned", 1166 | "toml_datetime", 1167 | "toml_parser", 1168 | "toml_writer", 1169 | "winnow", 1170 | ] 1171 | 1172 | [[package]] 1173 | name = "toml_datetime" 1174 | version = "0.7.0" 1175 | source = "registry+https://github.com/rust-lang/crates.io-index" 1176 | checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" 1177 | dependencies = [ 1178 | "serde", 1179 | ] 1180 | 1181 | [[package]] 1182 | name = "toml_parser" 1183 | version = "1.0.1" 1184 | source = "registry+https://github.com/rust-lang/crates.io-index" 1185 | checksum = "97200572db069e74c512a14117b296ba0a80a30123fbbb5aa1f4a348f639ca30" 1186 | dependencies = [ 1187 | "winnow", 1188 | ] 1189 | 1190 | [[package]] 1191 | name = "toml_writer" 1192 | version = "1.0.2" 1193 | source = "registry+https://github.com/rust-lang/crates.io-index" 1194 | checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" 1195 | 1196 | [[package]] 1197 | name = "typenum" 1198 | version = "1.17.0" 1199 | source = "registry+https://github.com/rust-lang/crates.io-index" 1200 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 1201 | 1202 | [[package]] 1203 | name = "unicase" 1204 | version = "2.8.1" 1205 | source = "registry+https://github.com/rust-lang/crates.io-index" 1206 | checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" 1207 | 1208 | [[package]] 1209 | name = "unicode-ident" 1210 | version = "1.0.18" 1211 | source = "registry+https://github.com/rust-lang/crates.io-index" 1212 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 1213 | 1214 | [[package]] 1215 | name = "usb-device" 1216 | version = "0.3.2" 1217 | source = "registry+https://github.com/rust-lang/crates.io-index" 1218 | checksum = "98816b1accafbb09085168b90f27e93d790b4bfa19d883466b5e53315b5f06a6" 1219 | dependencies = [ 1220 | "heapless 0.8.0", 1221 | "portable-atomic", 1222 | ] 1223 | 1224 | [[package]] 1225 | name = "v2-microphone" 1226 | version = "0.1.0" 1227 | dependencies = [ 1228 | "cortex-m", 1229 | "cortex-m-rt", 1230 | "defmt", 1231 | "defmt-rtt", 1232 | "embedded-hal 1.0.0", 1233 | "microbit-v2", 1234 | "panic-halt", 1235 | ] 1236 | 1237 | [[package]] 1238 | name = "v2-speaker" 1239 | version = "0.1.0" 1240 | dependencies = [ 1241 | "cortex-m", 1242 | "cortex-m-rt", 1243 | "defmt", 1244 | "defmt-rtt", 1245 | "embedded-hal 1.0.0", 1246 | "microbit-v2", 1247 | "panic-halt", 1248 | ] 1249 | 1250 | [[package]] 1251 | name = "vcell" 1252 | version = "0.1.3" 1253 | source = "registry+https://github.com/rust-lang/crates.io-index" 1254 | checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" 1255 | 1256 | [[package]] 1257 | name = "version_check" 1258 | version = "0.9.5" 1259 | source = "registry+https://github.com/rust-lang/crates.io-index" 1260 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1261 | 1262 | [[package]] 1263 | name = "void" 1264 | version = "1.0.2" 1265 | source = "registry+https://github.com/rust-lang/crates.io-index" 1266 | checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 1267 | 1268 | [[package]] 1269 | name = "volatile-register" 1270 | version = "0.2.2" 1271 | source = "registry+https://github.com/rust-lang/crates.io-index" 1272 | checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" 1273 | dependencies = [ 1274 | "vcell", 1275 | ] 1276 | 1277 | [[package]] 1278 | name = "wasm-bindgen" 1279 | version = "0.2.92" 1280 | source = "registry+https://github.com/rust-lang/crates.io-index" 1281 | checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" 1282 | dependencies = [ 1283 | "cfg-if", 1284 | "wasm-bindgen-macro", 1285 | ] 1286 | 1287 | [[package]] 1288 | name = "wasm-bindgen-backend" 1289 | version = "0.2.92" 1290 | source = "registry+https://github.com/rust-lang/crates.io-index" 1291 | checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" 1292 | dependencies = [ 1293 | "bumpalo", 1294 | "log", 1295 | "once_cell", 1296 | "proc-macro2", 1297 | "quote", 1298 | "syn 2.0.89", 1299 | "wasm-bindgen-shared", 1300 | ] 1301 | 1302 | [[package]] 1303 | name = "wasm-bindgen-macro" 1304 | version = "0.2.92" 1305 | source = "registry+https://github.com/rust-lang/crates.io-index" 1306 | checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" 1307 | dependencies = [ 1308 | "quote", 1309 | "wasm-bindgen-macro-support", 1310 | ] 1311 | 1312 | [[package]] 1313 | name = "wasm-bindgen-macro-support" 1314 | version = "0.2.92" 1315 | source = "registry+https://github.com/rust-lang/crates.io-index" 1316 | checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" 1317 | dependencies = [ 1318 | "proc-macro2", 1319 | "quote", 1320 | "syn 2.0.89", 1321 | "wasm-bindgen-backend", 1322 | "wasm-bindgen-shared", 1323 | ] 1324 | 1325 | [[package]] 1326 | name = "wasm-bindgen-shared" 1327 | version = "0.2.92" 1328 | source = "registry+https://github.com/rust-lang/crates.io-index" 1329 | checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" 1330 | 1331 | [[package]] 1332 | name = "windows-core" 1333 | version = "0.52.0" 1334 | source = "registry+https://github.com/rust-lang/crates.io-index" 1335 | checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" 1336 | dependencies = [ 1337 | "windows-targets", 1338 | ] 1339 | 1340 | [[package]] 1341 | name = "windows-link" 1342 | version = "0.2.0" 1343 | source = "registry+https://github.com/rust-lang/crates.io-index" 1344 | checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" 1345 | 1346 | [[package]] 1347 | name = "windows-targets" 1348 | version = "0.52.6" 1349 | source = "registry+https://github.com/rust-lang/crates.io-index" 1350 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1351 | dependencies = [ 1352 | "windows_aarch64_gnullvm", 1353 | "windows_aarch64_msvc", 1354 | "windows_i686_gnu", 1355 | "windows_i686_gnullvm", 1356 | "windows_i686_msvc", 1357 | "windows_x86_64_gnu", 1358 | "windows_x86_64_gnullvm", 1359 | "windows_x86_64_msvc", 1360 | ] 1361 | 1362 | [[package]] 1363 | name = "windows_aarch64_gnullvm" 1364 | version = "0.52.6" 1365 | source = "registry+https://github.com/rust-lang/crates.io-index" 1366 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1367 | 1368 | [[package]] 1369 | name = "windows_aarch64_msvc" 1370 | version = "0.52.6" 1371 | source = "registry+https://github.com/rust-lang/crates.io-index" 1372 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1373 | 1374 | [[package]] 1375 | name = "windows_i686_gnu" 1376 | version = "0.52.6" 1377 | source = "registry+https://github.com/rust-lang/crates.io-index" 1378 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1379 | 1380 | [[package]] 1381 | name = "windows_i686_gnullvm" 1382 | version = "0.52.6" 1383 | source = "registry+https://github.com/rust-lang/crates.io-index" 1384 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1385 | 1386 | [[package]] 1387 | name = "windows_i686_msvc" 1388 | version = "0.52.6" 1389 | source = "registry+https://github.com/rust-lang/crates.io-index" 1390 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1391 | 1392 | [[package]] 1393 | name = "windows_x86_64_gnu" 1394 | version = "0.52.6" 1395 | source = "registry+https://github.com/rust-lang/crates.io-index" 1396 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1397 | 1398 | [[package]] 1399 | name = "windows_x86_64_gnullvm" 1400 | version = "0.52.6" 1401 | source = "registry+https://github.com/rust-lang/crates.io-index" 1402 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1403 | 1404 | [[package]] 1405 | name = "windows_x86_64_msvc" 1406 | version = "0.52.6" 1407 | source = "registry+https://github.com/rust-lang/crates.io-index" 1408 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1409 | 1410 | [[package]] 1411 | name = "winnow" 1412 | version = "0.7.12" 1413 | source = "registry+https://github.com/rust-lang/crates.io-index" 1414 | checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" 1415 | 1416 | [[package]] 1417 | name = "xtask" 1418 | version = "0.1.0" 1419 | dependencies = [ 1420 | "cargo_toml", 1421 | "chrono", 1422 | ] 1423 | --------------------------------------------------------------------------------