Repository: nrf-rs/microbit Branch: main Commit: 349d2991dd4f Files: 85 Total size: 151.9 KB Directory structure: gitextract_ax2jxq_v/ ├── .cargo/ │ └── config.toml ├── .github/ │ ├── dependabot.yml │ └── workflows/ │ ├── changelog.yml │ ├── ci.yaml │ ├── clippy.yml │ └── rustfmt.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-0BSD.txt ├── README.md ├── build.rs ├── examples/ │ ├── analog/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── main.rs │ ├── analog-v1/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── main.rs │ ├── analog-v2/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── main.rs │ ├── display-blocking/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── main.rs │ ├── display-nonblocking/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── main.rs │ ├── display-rtic/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── main.rs │ ├── display-text-rtic/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── main.rs │ ├── gpio-direct-blinky/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── main.rs │ ├── gpio-hal-blinky/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── main.rs │ ├── gpio-hal-ledbutton/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── main.rs │ ├── gpio-hal-printbuttons/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── main.rs │ ├── magnetometer/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── main.rs │ ├── rng-direct/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── main.rs │ ├── rng-hal/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── main.rs │ ├── serial-direct-echo/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── main.rs │ ├── serial-direct-helloworld/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── main.rs │ ├── serial-hal-blocking-echo/ │ │ ├── Cargo.toml │ │ └── src/ │ │ ├── main.rs │ │ └── serial_setup.rs │ ├── servo/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── main.rs │ ├── v2-microphone/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── main.rs │ └── v2-speaker/ │ ├── Cargo.toml │ └── src/ │ └── main.rs ├── memory.x ├── microbit/ │ ├── Cargo.toml │ └── src/ │ └── lib.rs ├── microbit-common/ │ ├── Cargo.toml │ └── src/ │ ├── adc.rs │ ├── board.rs │ ├── display/ │ │ ├── blocking.rs │ │ ├── mod.rs │ │ └── nonblocking/ │ │ ├── control.rs │ │ ├── image.rs │ │ ├── matrix.rs │ │ ├── mod.rs │ │ └── timer.rs │ ├── gpio.rs │ ├── lib.rs │ ├── v1/ │ │ ├── adc.rs │ │ ├── board.rs │ │ ├── gpio.rs │ │ └── mod.rs │ └── v2/ │ ├── adc.rs │ ├── board.rs │ ├── gpio.rs │ └── mod.rs ├── microbit-v2/ │ ├── Cargo.toml │ └── src/ │ └── lib.rs ├── tools/ │ └── capture_example_bloat.sh └── xtask/ ├── Cargo.toml └── src/ ├── bump.rs ├── ci.rs ├── lib.rs ├── main.rs └── publish.rs ================================================ FILE CONTENTS ================================================ ================================================ FILE: .cargo/config.toml ================================================ [alias] xtask = "run --package xtask --" # For micro:bit v1.x [target.thumbv6m-none-eabi] runner = 'probe-rs run --chip nRF51822_xxAA --protocol swd' rustflags = [ "-C", "linker=flip-link", "-C", "link-arg=-Tlink.x", "-C", "link-arg=-Tdefmt.x", ] # For micro:bit v2 [target.thumbv7em-none-eabi] runner = "probe-rs run --chip nRF52833_xxAA --protocol swd" rustflags = [ "-C", "linker=flip-link", "-C", "link-arg=-Tlink.x", "-C", "link-arg=-Tdefmt.x", ] [target.thumbv7em-none-eabihf] runner = "probe-rs run --chip nRF52833_xxAA --protocol swd" rustflags = [ "-C", "linker=flip-link", "-C", "link-arg=-Tlink.x", "-C", "link-arg=-Tdefmt.x", ] # Enable printing of defmt debug, info and warning messages by default [env] DEFMT_LOG="debug" ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: "cargo" directory: "/" schedule: interval: "daily" - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" ================================================ FILE: .github/workflows/changelog.yml ================================================ on: pull_request_target: types: [opened, synchronize, reopened, labeled, unlabeled] name: Changelog check jobs: changelog: name: Changelog check runs-on: ubuntu-latest steps: - name: Checkout sources uses: actions/checkout@v6 - name: Changelog updated uses: Zomzog/changelog-checker@v1.3.0 with: fileName: CHANGELOG.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .github/workflows/ci.yaml ================================================ on: push: branches: main pull_request: merge_group: jobs: ci: name: CI runs-on: ubuntu-latest needs: [build] if: always() steps: - name: Done run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' build: runs-on: ubuntu-latest strategy: matrix: rust: - stable - beta - nightly include: # Minimum supported rust version (MSRV) # Note this needs to be new enough to build the examples as well as # the library itself. - name: MSRV rust: 1.85.0 name: "build (${{ matrix.name || matrix.rust }})" steps: - uses: actions/checkout@v6 - name: Install Rust uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: ${{ matrix.rust }} override: true components: rustfmt, clippy - name: rustfmt run: cargo fmt -- --check - name: build run: cargo xtask ci ================================================ FILE: .github/workflows/clippy.yml ================================================ on: push: branches: main pull_request: merge_group: name: Clippy check jobs: clippy_check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - run: rustup component add clippy - uses: actions-rs/toolchain@v1 with: toolchain: stable target: thumbv6m-none-eabi override: true - name: microbit V1 run: cargo clippy --package microbit -- -D warnings - name: microbit V2 run: cargo clippy --package microbit-v2 -- -D warnings ================================================ FILE: .github/workflows/rustfmt.yml ================================================ on: push: branches: main pull_request: merge_group: name: Code formatting check jobs: fmt: name: Rustfmt runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true - run: rustup component add rustfmt - uses: actions-rs/cargo@v1 with: command: fmt args: --all -- --check ================================================ FILE: .gitignore ================================================ /target/ **/*.orig **/*.rs.bk bloat_log* !.gitignore !.github !.cargo ================================================ FILE: CHANGELOG.md ================================================ # Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] - Bumped MSRV to 1.85.0 - Updated `examples/hal-rng/` to use latest `rand_pcg`, removing `rand` dependency and bumping to Rust 2024 - Added SPIM peripherals to Board struct ## [0.16.0] - 2025-10-11 - Remove dead link to microbit Rust on Windows blog post in README. - Bumped MSRV to 1.81.0. - Add metadata for docs.rs - Bumped dependencies in `examples/` to latest versions. - Update HAL crates to 0.19.0. ## [0.15.1] - 2024-08-05 - Set MSRV for `microbit` and `microbit-v2` crates. - Bumped MSRV to 1.79.0. - Make various `I2C` `Pin` fields `pub` ## [0.15.0] - 2024-06-19 - Update HAL crates to 0.18.0. - Update installation instructions for `probe-rs` ## [0.14.0] - 2024-04-18 - Fix: non-blocking display on micro:bit V2 could spuriously light LEDs briefly - Fix the `blocking::Display::set_refresh_rate` calculation for the micro:bit V2 - Double the non-blocking display refresh frequency for the micro:bit V2 - Fix faulty doc test in `blocking.rs` - Update the non-blocking display documentation to better explain when methods should be called from within a critical section - Bump example dependencies to latest versions to fix build - Update examples to use RTIC 1.0 - Add ADC for micro:bit V1 - Add analog example - Increase minimum supported Rust version to 1.73 - Added support for the real time counters RTC1 and RTC2 - Add common types and structs for the edge connector pads and pins - Add common ADC types and initialization for ADC and SAADC - Common ADC example - Add support for PPI - Servo example using TIMER, GPIOTE and PPI - (NFC) GitHub CI changes - Feature: Exposed all remaining peripherals for both boards. - Update HAL crates to 0.17.1. - Update to `embedded-hal` 1.0. - Update magnetometer example to use `lsm303agr` 1.0. - Update debug tooling from probe-run to probe-rs ## [0.13.0] - 2022-05-24 - Drop ble-beacon example (since rubble is now archived as unmaintained) - Bump `defmt` versions to 0.3 - Increase minimum supported Rust version to 1.57 - Add display-text-rtic example - Make `Board::new(p, cp)` public and fix RTIC example - Fix display-nonblocking example - Fix timer for LED-display (GreyscaleImage with a empty Row did not work) - Add SAADC and microphone_pins for micro:bit V2. - Add microphone example ## [0.12.0] - 2021-11-10 ### Changed - Update dependencies nrf51-hal and nrf52833-hal to 0.14.0 - Added TEMP field to board - Fixed Issue where columns 2,3 and 4 of the nonblocking display were swapped ## [0.11.0] - 2021-09-13 ### Added - Added support for the thumbv7em-none-eabi target for microbit:v2 (same as thumbv7em-none-eabihf but without hardware floating point support) ### Changed - Rearrange LED display modules under the same root module and change their APIs to be more aligned with each other. - Add BLE Beacon demo. - Add a simple speaker demo for micro:bit V2. - Add Board struct following the pattern used in other nrf board support crates. - Add magnetometer example. - LEDs on the micro:bit V1 are now turned off per default - UART(E) is now exposed in the same way as I2C ## [0.10.1] - 2021-05-25 Republished without changes to fix missing README.md in crates.io. ## [0.10.0] - 2021-05-13 ### Added - Add support for micro:bit V2. This is a significant change that splits this repository into multiple crates. ## [0.9.0] - 2021-04-29 ### Added - Add `microbit::gpio` module with pins mapped to micro:bit names - Refactor `microbit::display` and `microbit::led` to accept `gpio::Pins` - Make probe-run the default runner - Rewrite `serial_port` as a macro ### Fixed - Fix rustdoc warnings - Upgrade nrf51-hal to 0.12.1 [Unreleased]: https://github.com/nrf-rs/microbit/compare/v0.16.0...HEAD [0.16.0]: https://github.com/nrf-rs/microbit/compare/v0.15.1...v0.16.0 [0.15.1]: https://github.com/nrf-rs/microbit/compare/v0.15.0...v0.15.1 [0.15.0]: https://github.com/nrf-rs/microbit/compare/v0.14.0...v0.15.0 [0.14.0]: https://github.com/nrf-rs/microbit/compare/v0.13.0...v0.14.0 [0.13.0]: https://github.com/nrf-rs/microbit/compare/v0.12.0...v0.13.0 [0.12.0]: https://github.com/nrf-rs/microbit/compare/v0.11.0...v0.12.0 [0.11.0]: https://github.com/nrf-rs/microbit/compare/v0.10.1...v0.11.0 [0.10.1]: https://github.com/nrf-rs/microbit/compare/v0.10.0...v0.10.1 [0.10.0]: https://github.com/nrf-rs/microbit/compare/v0.9.0...v0.10.0 [0.9.0]: https://github.com/nrf-rs/microbit/compare/v0.8.0...v0.9.0 ================================================ FILE: Cargo.toml ================================================ [workspace] resolver = "2" members = [ "microbit-common", "microbit", "microbit-v2", "examples/*", "xtask", ] # Modify default build profiles to make debugging easier [profile.release] debug = 2 lto = "off" [profile.dev] debug = 2 opt-level = 1 lto = "off" ================================================ FILE: LICENSE-0BSD.txt ================================================ Copyright (C) 2018 daniel@eggers-club.de Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ================================================ FILE: README.md ================================================ # microbit _microbit_ contains everything required getting started using Rust to create firmwares for the fabulous [BBC micro:bit](https://microbit.org) microcontroller board. This little board has everything and a kitchen sink built-in, even a capable debugging interface. ## Getting started All you need to start programming this device is: * A BBC micro:bit board * A computer (known to work with macOS, Linux and Windows) * A bit of open source software ### Know your version The micro:bit comes in different versions. There is a separate crate for each major board version. See the table below to identify which crate you need to use. | Crate | Board version | Board image | Docs | crates.io | target | | ------------------------------ | ------------- | ----------- | ---- | --------- | ------ | | [`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` | | [`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` | ### Install dependencies 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. In order to run the examples you need to install [`probe-rs`](https://probe.rs/docs/getting-started/installation) and [`flip-link`](https://github.com/knurling-rs/flip-link#installation). ```bash > cargo install probe-rs-tools flip-link ``` ### Run an example The first thing to try is one of the [examples](./examples) in this repository. Plug in your micro:bit and run one of the commands below. *For micro:bit V1* ```bash > cargo run --release --manifest-path ./examples/display-blocking/Cargo.toml --features v1 --target thumbv6m-none-eabi ``` *For micro:bit V2* ```bash > cargo run --release --manifest-path ./examples/display-blocking/Cargo.toml --features v2 --target thumbv7em-none-eabihf ``` You should see a lot of build output, the orange LED on the back of the micro:bit should flash quickly, and a message should appear on the LED display. Congratulations! You've flashed your first Rust program onto your micro:bit! ## Further reading 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/). Other useful resources: - [micro:bit developer community](https://tech.microbit.org) - [micro:bit hardware overview](https://tech.microbit.org/hardware/) - [nrf-hal](https://github.com/nrf-rs/nrf-hal#readme) the hardware abstraction layer (HAL) this repository is based on ## License [0-clause BSD license](LICENSE-0BSD.txt). ================================================ FILE: build.rs ================================================ use std::env; use std::fs::File; use std::io::Write; use std::path::PathBuf; fn main() { // Put the linker script somewhere the linker can find it let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); File::create(out.join("memory.x")) .unwrap() .write_all(include_bytes!("memory.x")) .unwrap(); println!("cargo:rustc-link-search={}", out.display()); // Only re-run the build script when memory.x is changed, // instead of when any part of the source code changes. println!("cargo:rerun-if-changed=memory.x"); } ================================================ FILE: examples/analog/Cargo.toml ================================================ [package] name = "analog" version = "0.1.0" edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.5" panic-halt = "1.0.0" defmt-rtt = "1.1.0" defmt = "1.0.1" [dependencies.microbit] path = "../../microbit" optional = true [dependencies.microbit-v2] path = "../../microbit-v2" optional = true [features] v1 = ["microbit"] v2 = ["microbit-v2"] default = [ "defmt-default", ] # do NOT modify these features defmt-default = [] defmt-trace = [] defmt-debug = [] defmt-info = [] defmt-warn = [] defmt-error = [] ================================================ FILE: examples/analog/src/main.rs ================================================ #![no_std] #![no_main] use defmt_rtt as _; use panic_halt as _; use cortex_m_rt::entry; use microbit::{ adc::{Adc, AdcConfig, Default}, board::Board, display::blocking::Display, hal::Timer, }; #[entry] fn main() -> ! { if let Some(board) = Board::take() { let mut timer = Timer::new(board.TIMER0); let mut display = Display::new(board.display_pins); let mut adc = Adc::new(board.ADC, AdcConfig::default_10bit()); let mut anapin = board.edge.e00.into_floating_input(); // PAD0 let numbers = [ [ [0, 0, 1, 0, 0], [0, 1, 0, 1, 0], [0, 1, 0, 1, 0], [0, 1, 0, 1, 0], [0, 0, 1, 0, 0], ], [ [0, 0, 1, 0, 0], [0, 1, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], ], [ [0, 0, 1, 0, 0], [0, 1, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0], [0, 1, 1, 1, 0], ], [ [0, 1, 1, 0, 0], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 0], [0, 1, 1, 0, 0], ], [ [0, 1, 0, 0, 0], [1, 0, 0, 0, 0], [1, 0, 1, 0, 0], [1, 1, 1, 1, 0], [0, 0, 1, 0, 0], ], ]; let sign_plus = [ [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [1, 1, 1, 1, 1], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], ]; #[cfg(feature = "v2")] #[allow(non_snake_case)] let letter_E = [ [0, 1, 1, 1, 0], [0, 1, 0, 0, 0], [0, 1, 1, 0, 0], [0, 1, 0, 0, 0], [0, 1, 1, 1, 0], ]; loop { let analog = adc.read_channel(&mut anapin); #[cfg(feature = "v2")] let Ok(analog) = analog else { display.show(&mut timer, letter_E, 10); continue; }; let n_iter = numbers.iter(); let mut count: usize = 0; for n_val in n_iter { if count == usize::from(i16::unsigned_abs(analog / 100)) { display.show(&mut timer, *n_val, 10); break; } count += 1; } if count == numbers.len() { display.show(&mut timer, sign_plus, 10); } } } panic!("End"); } ================================================ FILE: examples/analog-v1/Cargo.toml ================================================ [package] name = "analog-v1" version = "0.1.0" edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.5" panic-halt = "1.0.0" defmt-rtt = "1.1.0" defmt = "1.0.1" # NOTE: This currently only works with the microbit v1 due to naming issues! # ADC vs SAADC [dependencies.microbit] path = "../../microbit" [features] default = [ "defmt-default", ] # do NOT modify these features defmt-default = [] defmt-trace = [] defmt-debug = [] defmt-info = [] defmt-warn = [] defmt-error = [] ================================================ FILE: examples/analog-v1/src/main.rs ================================================ #![no_std] #![no_main] use defmt_rtt as _; use panic_halt as _; use cortex_m_rt::entry; use microbit::{ board::Board, display::blocking::Display, hal::{adc::AdcConfig, Adc, Timer}, }; #[entry] fn main() -> ! { if let Some(board) = Board::take() { let mut timer = Timer::new(board.TIMER0); let mut display = Display::new(board.display_pins); let mut adc: Adc = Adc::new(board.ADC, AdcConfig::default()); let mut anapin = board.edge.e00.into_floating_input(); // PAD1 let numbers = [ [ [0, 0, 1, 0, 0], [0, 1, 0, 1, 0], [0, 1, 0, 1, 0], [0, 1, 0, 1, 0], [0, 0, 1, 0, 0], ], [ [0, 0, 1, 0, 0], [0, 1, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], ], [ [0, 0, 1, 0, 0], [0, 1, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0], [0, 1, 1, 1, 0], ], [ [0, 1, 1, 0, 0], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 0], [0, 1, 1, 0, 0], ], [ [0, 1, 0, 0, 0], [1, 0, 0, 0, 0], [1, 0, 1, 0, 0], [1, 1, 1, 1, 0], [0, 0, 1, 0, 0], ], ]; let sign_plus = [ [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [1, 1, 1, 1, 1], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], ]; loop { let analog_value = adc.read_channel(&mut anapin); let n_iter = numbers.iter(); let mut count: usize = 0; for n_val in n_iter { if count == usize::from(i16::unsigned_abs(analog_value / 100)) { display.show(&mut timer, *n_val, 10); break; } count += 1; } if count == numbers.len() { display.show(&mut timer, sign_plus, 10); } } } panic!("End"); } ================================================ FILE: examples/analog-v2/Cargo.toml ================================================ [package] name = "analog-v2" version = "0.1.0" edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.5" panic-halt = "1.0.0" defmt-rtt = "1.1.0" defmt = "1.0.1" # NOTE: This currently only works with the microbit v2 due to naming issues! # ADC vs SAADC [dependencies.microbit-v2] path = "../../microbit-v2" [features] default = [ "defmt-default", ] # do NOT modify these features defmt-default = [] defmt-trace = [] defmt-debug = [] defmt-info = [] defmt-warn = [] defmt-error = [] ================================================ FILE: examples/analog-v2/src/main.rs ================================================ #![no_std] #![no_main] use defmt_rtt as _; use panic_halt as _; use cortex_m_rt::entry; use microbit::{ board::Board, display::blocking::Display, hal::{saadc::SaadcConfig, Saadc, Timer}, }; #[entry] fn main() -> ! { if let Some(board) = Board::take() { let mut timer = Timer::new(board.TIMER0); let mut display = Display::new(board.display_pins); let mut adc: Saadc = Saadc::new(board.ADC, SaadcConfig::default()); let mut anapin = board.edge.e00.into_floating_input(); // PAD1 let numbers = [ [ [0, 0, 1, 0, 0], [0, 1, 0, 1, 0], [0, 1, 0, 1, 0], [0, 1, 0, 1, 0], [0, 0, 1, 0, 0], ], [ [0, 0, 1, 0, 0], [0, 1, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], ], [ [0, 0, 1, 0, 0], [0, 1, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0], [0, 1, 1, 1, 0], ], [ [0, 1, 1, 0, 0], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 0], [0, 1, 1, 0, 0], ], [ [0, 1, 0, 0, 0], [1, 0, 0, 0, 0], [1, 0, 1, 0, 0], [1, 1, 1, 1, 0], [0, 0, 1, 0, 0], ], ]; let sign_plus = [ [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [1, 1, 1, 1, 1], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], ]; #[allow(non_snake_case)] let letter_E = [ [0, 1, 1, 1, 0], [0, 1, 0, 0, 0], [0, 1, 1, 0, 0], [0, 1, 0, 0, 0], [0, 1, 1, 1, 0], ]; loop { let analog = adc.read_channel(&mut anapin); match analog { Ok(v) => { let n_iter = numbers.iter(); let mut count: usize = 0; for n_val in n_iter { if count == usize::from(i16::unsigned_abs(v / 100)) { display.show(&mut timer, *n_val, 10); break; } count += 1; } if count == numbers.len() { display.show(&mut timer, sign_plus, 10); } } Err(_e) => display.show(&mut timer, letter_E, 10), } } } panic!("End"); } ================================================ FILE: examples/display-blocking/Cargo.toml ================================================ [package] name = "display-blocking" version = "0.1.0" edition = "2018" [dependencies] cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.5" panic-halt = "1.0.0" defmt-rtt = "1.1.0" defmt = "1.0.1" embedded-hal = "1.0.0" [dependencies.microbit] path = "../../microbit" optional = true [dependencies.microbit-v2] path = "../../microbit-v2" optional = true [features] v1 = ["microbit"] v2 = ["microbit-v2"] default = [ "defmt-default", ] # do NOT modify these features defmt-default = [] defmt-trace = [] defmt-debug = [] defmt-info = [] defmt-warn = [] defmt-error = [] ================================================ FILE: examples/display-blocking/src/main.rs ================================================ #![no_std] #![no_main] use defmt_rtt as _; use panic_halt as _; use cortex_m_rt::entry; use embedded_hal::delay::DelayNs; use microbit::{board::Board, display::blocking::Display, hal::Timer}; #[entry] fn main() -> ! { if let Some(board) = Board::take() { let mut timer = Timer::new(board.TIMER0); let mut display = Display::new(board.display_pins); #[allow(non_snake_case)] let letter_I = [ [0, 1, 1, 1, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 1, 1, 1, 0], ]; let heart = [ [0, 1, 0, 1, 0], [1, 0, 1, 0, 1], [1, 0, 0, 0, 1], [0, 1, 0, 1, 0], [0, 0, 1, 0, 0], ]; #[allow(non_snake_case)] let letter_R = [ [0, 1, 1, 0, 0], [0, 1, 0, 1, 0], [0, 1, 1, 0, 0], [0, 1, 0, 1, 0], [0, 1, 0, 1, 0], ]; #[allow(non_snake_case)] let letter_u = [ [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 1, 0, 1, 0], [0, 1, 0, 1, 0], [0, 1, 1, 1, 0], ]; #[allow(non_snake_case)] let letter_s = [ [0, 0, 0, 0, 0], [0, 0, 1, 1, 0], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 1, 1, 1, 0], ]; #[allow(non_snake_case)] let letter_t = [ [0, 0, 1, 0, 0], [0, 1, 1, 1, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], ]; loop { display.show(&mut timer, letter_I, 1000); display.show(&mut timer, heart, 1000); display.show(&mut timer, letter_R, 1000); display.show(&mut timer, letter_u, 1000); display.show(&mut timer, letter_s, 1000); display.show(&mut timer, letter_t, 1000); display.clear(); timer.delay_ms(250_u32); } } panic!("End"); } ================================================ FILE: examples/display-nonblocking/Cargo.toml ================================================ [package] name = "display-nonblocking" version = "0.1.0" edition = "2018" [dependencies] cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.5" panic-halt = "1.0.0" defmt-rtt = "1.1.0" defmt = "1.0.1" [dependencies.microbit] path = "../../microbit" optional = true [dependencies.microbit-v2] path = "../../microbit-v2" optional = true [features] v1 = ["microbit"] v2 = ["microbit-v2"] default = [ "defmt-default", ] # do NOT modify these features defmt-default = [] defmt-trace = [] defmt-debug = [] defmt-info = [] defmt-warn = [] defmt-error = [] ================================================ FILE: examples/display-nonblocking/src/main.rs ================================================ #![no_main] #![no_std] use defmt_rtt as _; use panic_halt as _; use core::cell::RefCell; use cortex_m::interrupt::Mutex; use cortex_m_rt::entry; use microbit::{ board::Board, display::nonblocking::{Display, GreyscaleImage}, hal::{ clocks::Clocks, rtc::{Rtc, RtcInterrupt}, }, pac::{self, interrupt, RTC0, TIMER1}, }; fn heart_image(inner_brightness: u8) -> GreyscaleImage { let b = inner_brightness; GreyscaleImage::new(&[ [0, 7, 0, 7, 0], [7, b, 7, b, 7], [7, b, b, b, 7], [0, 7, b, 7, 0], [0, 0, 7, 0, 0], ]) } // We use TIMER1 to drive the display, and RTC0 to update the animation. // We set the TIMER1 interrupt to a higher priority than RTC0. static DISPLAY: Mutex>>> = Mutex::new(RefCell::new(None)); static ANIM_TIMER: Mutex>>> = Mutex::new(RefCell::new(None)); #[entry] fn main() -> ! { if let Some(mut board) = Board::take() { // Starting the low-frequency clock (needed for RTC to work) Clocks::new(board.CLOCK).start_lfclk(); // RTC at 16Hz (32_768 / (2047 + 1)) // 62.5ms period let mut rtc0 = Rtc::new(board.RTC0, 2047).unwrap(); rtc0.enable_event(RtcInterrupt::Tick); rtc0.enable_interrupt(RtcInterrupt::Tick, None); rtc0.enable_counter(); // Create display let display = Display::new(board.TIMER1, board.display_pins); cortex_m::interrupt::free(move |cs| { *DISPLAY.borrow(cs).borrow_mut() = Some(display); *ANIM_TIMER.borrow(cs).borrow_mut() = Some(rtc0); }); unsafe { board.NVIC.set_priority(pac::Interrupt::RTC0, 64); board.NVIC.set_priority(pac::Interrupt::TIMER1, 128); pac::NVIC::unmask(pac::Interrupt::RTC0); pac::NVIC::unmask(pac::Interrupt::TIMER1); } } loop { continue; } } #[interrupt] fn TIMER1() { cortex_m::interrupt::free(|cs| { if let Some(display) = DISPLAY.borrow(cs).borrow_mut().as_mut() { display.handle_display_event(); } }); } #[interrupt] unsafe fn RTC0() { static mut STEP: u8 = 0; cortex_m::interrupt::free(|cs| { if let Some(rtc) = ANIM_TIMER.borrow(cs).borrow_mut().as_mut() { rtc.reset_event(RtcInterrupt::Tick); } }); let inner_brightness = match *STEP { 0..=8 => 9 - *STEP, 9..=12 => 0, _ => unreachable!(), }; cortex_m::interrupt::free(|cs| { if let Some(display) = DISPLAY.borrow(cs).borrow_mut().as_mut() { display.show(&heart_image(inner_brightness)); } }); *STEP += 1; if *STEP == 13 { *STEP = 0 }; } ================================================ FILE: examples/display-rtic/Cargo.toml ================================================ [package] name = "display-rtic" version = "0.1.0" edition = "2018" [dependencies] cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } panic-halt = "1.0.0" defmt-rtt = "1.1.0" defmt = "1.0.1" cortex-m-rtic = { version = "1.1.4" } [dependencies.microbit] path = "../../microbit" optional = true [dependencies.microbit-v2] path = "../../microbit-v2" optional = true [features] v1 = ["microbit"] v2 = ["microbit-v2"] default = [ "defmt-default", ] # do NOT modify these features defmt-default = [] defmt-trace = [] defmt-debug = [] defmt-info = [] defmt-warn = [] defmt-error = [] ================================================ FILE: examples/display-rtic/src/main.rs ================================================ //! A complete working example. //! //! This requires `cortex-m-rtic` v1.0. //! //! It uses `TIMER1` to drive the display, and `RTC0` to update a simple //! animated image. #![no_main] #![no_std] use defmt_rtt as _; use panic_halt as _; use rtic::app; #[app(device = microbit::pac, peripherals = true)] mod app { use microbit::{ board::Board, display::nonblocking::{Display, GreyscaleImage}, hal::{ clocks::Clocks, rtc::{Rtc, RtcInterrupt}, }, pac, }; fn heart_image(inner_brightness: u8) -> GreyscaleImage { let b = inner_brightness; GreyscaleImage::new(&[ [0, 7, 0, 7, 0], [7, b, 7, b, 7], [7, b, b, b, 7], [0, 7, b, 7, 0], [0, 0, 7, 0, 0], ]) } #[shared] struct Shared { display: Display, } #[local] struct Local { anim_timer: Rtc, } #[init] fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { let board = Board::new(cx.device, cx.core); // Starting the low-frequency clock (needed for RTC to work) Clocks::new(board.CLOCK).start_lfclk(); // RTC at 16Hz (32_768 / (2047 + 1)) // 16Hz; 62.5ms period let mut rtc0 = Rtc::new(board.RTC0, 2047).unwrap(); rtc0.enable_event(RtcInterrupt::Tick); rtc0.enable_interrupt(RtcInterrupt::Tick, None); rtc0.enable_counter(); let display = Display::new(board.TIMER1, board.display_pins); ( Shared { display }, Local { anim_timer: rtc0 }, init::Monotonics(), ) } #[task(binds = TIMER1, priority = 2, shared = [display])] fn timer1(mut cx: timer1::Context) { cx.shared .display .lock(|display| display.handle_display_event()); } #[task(binds = RTC0, priority = 1, shared = [display], local = [anim_timer, step: u8 = 0])] fn rtc0(cx: rtc0::Context) { let mut shared = cx.shared; let local = cx.local; local.anim_timer.reset_event(RtcInterrupt::Tick); let inner_brightness = match *local.step { 0..=8 => 9 - *local.step, 9..=12 => 0, _ => unreachable!(), }; shared.display.lock(|display| { display.show(&heart_image(inner_brightness)); }); *local.step += 1; if *local.step == 13 { *local.step = 0 }; } } ================================================ FILE: examples/display-text-rtic/Cargo.toml ================================================ [package] name = "display-text-rtic" version = "0.1.0" edition = "2018" [dependencies] cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } panic-halt = "1.0.0" defmt-rtt = "1.1.0" defmt = "1.0.1" cortex-m-rtic = { version = "1.1.4" } microbit-text = "1.0.0" [dependencies.microbit] path = "../../microbit" optional = true [dependencies.microbit-v2] path = "../../microbit-v2" optional = true [features] v1 = ["microbit"] v2 = ["microbit-v2"] default = [ "defmt-default", ] # do NOT modify these features defmt-default = [] defmt-trace = [] defmt-debug = [] defmt-info = [] defmt-warn = [] defmt-error = [] ================================================ FILE: examples/display-text-rtic/src/main.rs ================================================ //! An example of scrolling static text. //! //! It uses `TIMER1` to drive the display, and `RTC0` to animate the text. #![no_main] #![no_std] use defmt_rtt as _; use panic_halt as _; use rtic::app; #[app(device = microbit::pac, peripherals = true)] mod app { use microbit::{ board::Board, display::nonblocking::{Display, Frame, MicrobitFrame}, hal::{ clocks::Clocks, rtc::{Rtc, RtcInterrupt}, }, pac, }; use microbit_text::scrolling::Animate; use microbit_text::scrolling_text::ScrollingStaticText; const MESSAGE: &[u8] = b"Hello, world!"; #[shared] struct Shared { display: Display, } #[local] struct Local { anim_timer: Rtc, scroller: ScrollingStaticText, } #[init] fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { let board = Board::new(cx.device, cx.core); // Starting the low-frequency clock (needed for RTC to work) Clocks::new(board.CLOCK).start_lfclk(); // RTC at 16Hz (32_768 / (2047 + 1)) // 16Hz; 62.5ms period let mut rtc0 = Rtc::new(board.RTC0, 2047).unwrap(); rtc0.enable_event(RtcInterrupt::Tick); rtc0.enable_interrupt(RtcInterrupt::Tick, None); rtc0.enable_counter(); let display = Display::new(board.TIMER1, board.display_pins); let mut scroller = ScrollingStaticText::default(); scroller.set_message(MESSAGE); ( Shared { display }, Local { anim_timer: rtc0, scroller, }, init::Monotonics(), ) } #[task(binds = TIMER1, priority = 2, shared = [display])] fn timer1(mut cx: timer1::Context) { cx.shared .display .lock(|display| display.handle_display_event()); } #[task(binds = RTC0, priority = 1, shared = [display], local = [anim_timer, scroller, frame: MicrobitFrame = MicrobitFrame::default()])] fn rtc0(cx: rtc0::Context) { let mut shared = cx.shared; let local = cx.local; local.anim_timer.reset_event(RtcInterrupt::Tick); if !local.scroller.is_finished() { local.scroller.tick(); local.frame.set(local.scroller); shared.display.lock(|display| { display.show_frame(local.frame); }); } } } ================================================ FILE: examples/gpio-direct-blinky/Cargo.toml ================================================ [package] name = "gpio-direct-blinky" version = "0.1.0" edition = "2018" [dependencies] cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.5" panic-halt = "1.0.0" defmt = "1.0.1" [dependencies.microbit] path = "../../microbit" optional = true [dependencies.microbit-v2] path = "../../microbit-v2" optional = true [features] v1 = ["microbit"] v2 = ["microbit-v2"] default = [ "defmt-default", ] # do NOT modify these features defmt-default = [] defmt-trace = [] defmt-debug = [] defmt-info = [] defmt-warn = [] defmt-error = [] ================================================ FILE: examples/gpio-direct-blinky/src/main.rs ================================================ #![no_main] #![no_std] use panic_halt as _; use cortex_m_rt::entry; #[cfg(feature = "v1")] #[entry] fn main() -> ! { if let Some(p) = microbit::Peripherals::take() { p.GPIO.pin_cnf[4].write(|w| w.dir().output()); p.GPIO.pin_cnf[13].write(|w| w.dir().output()); p.GPIO.out.write(|w| unsafe { w.bits(1 << 13) }); let mut count: u8 = 0; loop { count += 1; if count & 1 == 1 { p.GPIO.out.write(|w| unsafe { w.bits(1 << 13) }); } else { p.GPIO.out.write(|w| unsafe { w.bits(0) }); } for _ in 0..50_000 { cortex_m::asm::nop(); } } }; loop { continue; } } #[cfg(feature = "v2")] #[entry] fn main() -> ! { if let Some(p) = microbit::Peripherals::take() { p.P0.pin_cnf[28].write(|w| w.dir().output()); p.P0.pin_cnf[21].write(|w| w.dir().output()); p.P0.out.write(|w| unsafe { w.bits(1 << 21) }); let mut count: u8 = 0; loop { count += 1; if count & 1 == 1 { p.P0.out.write(|w| unsafe { w.bits(1 << 21) }); } else { p.P0.out.write(|w| unsafe { w.bits(0) }); } for _ in 0..50_000 { cortex_m::asm::nop(); } } }; loop { continue; } } ================================================ FILE: examples/gpio-hal-blinky/Cargo.toml ================================================ [package] name = "gpio-hal-blinky" version = "0.1.0" edition = "2018" [dependencies] embedded-hal = "1.0.0" cortex-m-rt = "0.7.5" panic-halt = "1.0.0" defmt-rtt = "1.1.0" defmt = "1.0.1" [dependencies.microbit] path = "../../microbit" optional = true [dependencies.microbit-v2] path = "../../microbit-v2" optional = true [features] v1 = ["microbit"] v2 = ["microbit-v2"] default = [ "defmt-default", ] # do NOT modify these features defmt-default = [] defmt-trace = [] defmt-debug = [] defmt-info = [] defmt-warn = [] defmt-error = [] ================================================ FILE: examples/gpio-hal-blinky/src/main.rs ================================================ #![no_main] #![no_std] use panic_halt as _; use cortex_m_rt::entry; use embedded_hal::{delay::DelayNs, digital::OutputPin}; use microbit::{board::Board, hal::timer::Timer}; #[entry] fn main() -> ! { let mut board = Board::take().unwrap(); let mut timer = Timer::new(board.TIMER0); let _ = board.display_pins.col1.set_low(); let mut row1 = board.display_pins.row1; loop { let _ = row1.set_low(); timer.delay_ms(1_000); let _ = row1.set_high(); timer.delay_ms(1_000); } } ================================================ FILE: examples/gpio-hal-ledbutton/Cargo.toml ================================================ [package] name = "gpio-hal-ledbutton" version = "0.1.0" edition = "2018" [dependencies] cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.5" panic-halt = "1.0.0" defmt-rtt = "1.1.0" defmt = "1.0.1" embedded-hal = "1.0.0" [dependencies.microbit] path = "../../microbit" optional = true [dependencies.microbit-v2] path = "../../microbit-v2" optional = true [features] v1 = ["microbit"] v2 = ["microbit-v2"] default = [ "defmt-default", ] # do NOT modify these features defmt-default = [] defmt-trace = [] defmt-debug = [] defmt-info = [] defmt-warn = [] defmt-error = [] ================================================ FILE: examples/gpio-hal-ledbutton/src/main.rs ================================================ #![no_main] #![no_std] use defmt_rtt as _; use panic_halt as _; use cortex_m_rt::entry; use embedded_hal::digital::{InputPin, OutputPin}; use microbit::board::Board; #[entry] fn main() -> ! { let mut board = Board::take().unwrap(); board.display_pins.row1.set_high().unwrap(); let mut led1 = board.display_pins.col1; let mut led2 = board.display_pins.col2; loop { if let Ok(true) = board.buttons.button_a.is_high() { let _ = led1.set_high(); } else { let _ = led1.set_low(); } if let Ok(true) = board.buttons.button_b.is_high() { let _ = led2.set_high(); } else { let _ = led2.set_low(); } } } ================================================ FILE: examples/gpio-hal-printbuttons/Cargo.toml ================================================ [package] name = "gpio-hal-printbuttons" version = "0.1.0" edition = "2018" [dependencies] cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.5" panic-halt = "1.0.0" defmt-rtt = "1.1.0" defmt = "1.0.1" [dependencies.microbit] path = "../../microbit" optional = true [dependencies.microbit-v2] path = "../../microbit-v2" optional = true [features] v1 = ["microbit"] v2 = ["microbit-v2"] default = [ "defmt-default", ] # do NOT modify these features defmt-default = [] defmt-trace = [] defmt-debug = [] defmt-info = [] defmt-warn = [] defmt-error = [] ================================================ FILE: examples/gpio-hal-printbuttons/src/main.rs ================================================ #![no_main] #![no_std] use defmt_rtt as _; use panic_halt as _; use core::cell::RefCell; use cortex_m::interrupt::Mutex; use cortex_m_rt::entry; use microbit::{ board::Board, hal::gpiote::Gpiote, pac::{self, interrupt}, }; static GPIO: Mutex>> = Mutex::new(RefCell::new(None)); #[entry] fn main() -> ! { let board = Board::take().unwrap(); let gpiote = Gpiote::new(board.GPIOTE); let channel0 = gpiote.channel0(); channel0 .input_pin(&board.buttons.button_a.degrade()) .hi_to_lo() .enable_interrupt(); channel0.reset_events(); let channel1 = gpiote.channel1(); channel1 .input_pin(&board.buttons.button_b.degrade()) .hi_to_lo() .enable_interrupt(); channel1.reset_events(); cortex_m::interrupt::free(move |cs| { /* Enable external GPIO interrupts */ unsafe { pac::NVIC::unmask(pac::Interrupt::GPIOTE); } pac::NVIC::unpend(pac::Interrupt::GPIOTE); *GPIO.borrow(cs).borrow_mut() = Some(gpiote); defmt::info!("Welcome to the buttons demo. Press buttons A and/or B for some action."); }); loop { continue; } } // Define an interrupt, i.e. function to call when exception occurs. Here if we receive an // interrupt from a button press, the function will be called #[interrupt] fn GPIOTE() { /* Enter critical section */ cortex_m::interrupt::free(|cs| { if let Some(gpiote) = GPIO.borrow(cs).borrow().as_ref() { let buttonapressed = gpiote.channel0().is_event_triggered(); let buttonbpressed = gpiote.channel1().is_event_triggered(); /* Print buttons to the serial console */ defmt::info!( "Button pressed {:?}", match (buttonapressed, buttonbpressed) { (false, false) => "", (true, false) => "A", (false, true) => "B", (true, true) => "A + B", } ); /* Clear events */ gpiote.channel0().reset_events(); gpiote.channel1().reset_events(); } }); } ================================================ FILE: examples/magnetometer/Cargo.toml ================================================ [package] name = "magnetometer" version = "0.1.0" edition = "2018" [dependencies] cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.5" embedded-hal = "1.0.0" panic-halt = "1.0.0" defmt-rtt = "1.1.0" defmt = "1.0.1" lsm303agr = "1.1.0" [dependencies.microbit] path = "../../microbit" optional = true [dependencies.microbit-v2] path = "../../microbit-v2" optional = true [features] v1 = ["microbit"] v2 = ["microbit-v2"] default = [ "defmt-default", ] # do NOT modify these features defmt-default = [] defmt-trace = [] defmt-debug = [] defmt-info = [] defmt-warn = [] defmt-error = [] ================================================ FILE: examples/magnetometer/src/main.rs ================================================ #![no_std] #![no_main] use defmt_rtt as _; use panic_halt as _; use cortex_m_rt::entry; use embedded_hal::delay::DelayNs; use lsm303agr::{ interface::I2cInterface, mode::MagOneShot, AccelMode, AccelOutputDataRate, Lsm303agr, }; use microbit::hal::Timer; #[cfg(feature = "v1")] use microbit::{ hal::twi, pac::{twi0::frequency::FREQUENCY_A, TWI0}, }; #[cfg(feature = "v2")] use microbit::{ hal::twim, pac::{twim0::frequency::FREQUENCY_A, TWIM0}, }; #[entry] fn main() -> ! { let board = microbit::Board::take().unwrap(); let mut timer = Timer::new(board.TIMER0); #[cfg(feature = "v1")] let i2c = { twi::Twi::new(board.TWI0, board.i2c.into(), FREQUENCY_A::K100) }; #[cfg(feature = "v2")] let i2c = { twim::Twim::new(board.TWIM0, board.i2c_internal.into(), FREQUENCY_A::K100) }; let mut sensor = Lsm303agr::new_with_i2c(i2c); if let Ok(id) = sensor.accelerometer_id() { if !id.is_correct() { defmt::panic!("Accelerometer had unexpected ID {:#x}", id.raw()); } } else { defmt::panic!("Error getting accelerometer ID"); } sensor.init().unwrap(); defmt::info!("normal mode"); sensor .set_accel_mode_and_odr(&mut timer, AccelMode::Normal, AccelOutputDataRate::Hz50) .unwrap(); timer.delay_ms(1000_u32); get_data(&mut sensor); defmt::info!("low power mode"); sensor .set_accel_mode_and_odr(&mut timer, AccelMode::LowPower, AccelOutputDataRate::Hz50) .unwrap(); timer.delay_ms(1000_u32); get_data(&mut sensor); defmt::info!("high resolution mode"); sensor .set_accel_mode_and_odr( &mut timer, AccelMode::HighResolution, AccelOutputDataRate::Hz50, ) .unwrap(); timer.delay_ms(1000_u32); get_data(&mut sensor); loop { timer.delay_ms(100_u32); get_data(&mut sensor); } } #[cfg(feature = "v1")] type Sensor = Lsm303agr>, MagOneShot>; #[cfg(feature = "v2")] type Sensor = Lsm303agr>, MagOneShot>; fn get_data(sensor: &mut Sensor) { loop { if sensor.accel_status().unwrap().xyz_new_data() { let data = sensor.acceleration().unwrap(); defmt::info!("x {} y {} z {}", data.x_mg(), data.y_mg(), data.z_mg()); return; } } } ================================================ FILE: examples/rng-direct/Cargo.toml ================================================ [package] name = "rng-direct" version = "0.1.0" edition = "2018" [dependencies] cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.5" panic-halt = "1.0.0" defmt-rtt = "1.1.0" defmt = "1.0.1" [dependencies.microbit] path = "../../microbit" optional = true [dependencies.microbit-v2] path = "../../microbit-v2" optional = true [features] v1 = ["microbit"] v2 = ["microbit-v2"] default = [ "defmt-default", ] # do NOT modify these features defmt-default = [] defmt-trace = [] defmt-debug = [] defmt-info = [] defmt-warn = [] defmt-error = [] ================================================ FILE: examples/rng-direct/src/main.rs ================================================ #![no_main] #![no_std] use defmt_rtt as _; use panic_halt as _; use core::cell::RefCell; use microbit::pac::{self, interrupt}; use cortex_m::interrupt::Mutex; use cortex_m_rt::entry; static RNG: Mutex>> = Mutex::new(RefCell::new(None)); static RTC: Mutex>> = Mutex::new(RefCell::new(None)); #[entry] fn main() -> ! { if let Some(p) = microbit::Peripherals::take() { p.CLOCK.tasks_lfclkstart.write(|w| unsafe { w.bits(1) }); while p.CLOCK.events_lfclkstarted.read().bits() == 0 {} /* And then set it back to 0 again, just because ?!? */ p.CLOCK.events_lfclkstarted.write(|w| unsafe { w.bits(0) }); defmt::info!("Welcome to the random number printer!"); p.RTC0.prescaler.write(|w| unsafe { w.bits(1) }); p.RTC0.evtenset.write(|w| w.tick().set_bit()); p.RTC0.intenset.write(|w| w.tick().set_bit()); p.RTC0.tasks_start.write(|w| unsafe { w.bits(1) }); /* Enable error correction for better values */ p.RNG.config.write(|w| w.dercen().enabled()); /* Enable random number generation */ p.RNG.tasks_start.write(|w| unsafe { w.bits(1) }); cortex_m::interrupt::free(move |cs| { *RTC.borrow(cs).borrow_mut() = Some(p.RTC0); *RNG.borrow(cs).borrow_mut() = Some(p.RNG); }); unsafe { pac::NVIC::unmask(pac::Interrupt::RTC0); } pac::NVIC::unpend(pac::Interrupt::RTC0); } loop { continue; } } // Define an exception, i.e. function to call when exception occurs. Here if our timer // trips, we'll print some random number #[interrupt] fn RTC0() { /* Enter critical section */ cortex_m::interrupt::free(|cs| { if let Some(rtc) = RTC.borrow(cs).borrow().as_ref() { let count = if let Some(rng) = RNG.borrow(cs).borrow().as_ref() { /* Let's wait until we have a new random value */ while rng.events_valrdy.read().bits() == 0 {} let num = rng.value.read().bits(); /* Clear event for next random number value */ rng.events_valrdy.write(|w| unsafe { w.bits(0) }); num } else { 0 }; defmt::info!("{:?}", count); rtc.events_tick.write(|w| unsafe { w.bits(0) }); } }); } ================================================ FILE: examples/rng-hal/Cargo.toml ================================================ [package] name = "rng-hal-printrandserial" version = "0.1.0" edition = "2024" [dependencies] cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.5" panic-halt = "1.0.0" defmt-rtt = "1.1.0" defmt = "1.0.1" [dependencies.rand_pcg] default-features = false version = "0.10.2" [dependencies.microbit] path = "../../microbit" optional = true [dependencies.microbit-v2] path = "../../microbit-v2" optional = true [features] v1 = ["microbit"] v2 = ["microbit-v2"] default = [ "defmt-default", ] # do NOT modify these features defmt-default = [] defmt-trace = [] defmt-debug = [] defmt-info = [] defmt-warn = [] defmt-error = [] ================================================ FILE: examples/rng-hal/src/main.rs ================================================ #![no_main] #![no_std] use defmt_rtt as _; use panic_halt as _; use core::{cell::RefCell, ops::DerefMut}; use cortex_m::interrupt::Mutex; use cortex_m_rt::entry; use microbit::{ hal::{clocks, rng, rtc}, pac::{self, interrupt}, }; use rand_pcg::{ Pcg32, rand_core::{Rng, SeedableRng}, }; static RTC: Mutex>>> = Mutex::new(RefCell::new(None)); static RNG: Mutex>> = Mutex::new(RefCell::new(None)); #[entry] fn main() -> ! { let mut cp = pac::CorePeripherals::take().unwrap(); let p = microbit::Peripherals::take().unwrap(); cortex_m::interrupt::free(move |cs| { /* Start low frequency clock */ clocks::Clocks::new(p.CLOCK).start_lfclk(); defmt::info!("Welcome to the random number printer!"); /* Use hardware RNG to initialise PRNG */ let mut rng = rng::Rng::new(p.RNG); let mut seed: [u8; 16] = [0; 16]; /* Read 4 bytes of data from hardware RNG */ rng.random(&mut seed); let rng = Pcg32::from_seed(seed); *RNG.borrow(cs).borrow_mut() = Some(rng); let mut rtc = rtc::Rtc::new(p.RTC0, 1).unwrap(); rtc.enable_counter(); rtc.enable_interrupt(rtc::RtcInterrupt::Tick, Some(&mut cp.NVIC)); rtc.enable_event(rtc::RtcInterrupt::Tick); *RTC.borrow(cs).borrow_mut() = Some(rtc); pac::NVIC::unpend(pac::Interrupt::RTC0); }); loop { continue; } } // Define an exception, i.e. function to call when exception occurs. Here if our timer // trips, we'll print out a random number to the serial port #[interrupt] fn RTC0() { /* Enter critical section */ cortex_m::interrupt::free(|cs| { if let (Some(rtc), &mut Some(ref mut rng)) = ( RTC.borrow(cs).borrow().as_ref(), RNG.borrow(cs).borrow_mut().deref_mut(), ) { defmt::info!("{:?}", rng.next_u32()); rtc.reset_event(rtc::RtcInterrupt::Tick); } }); } ================================================ FILE: examples/serial-direct-echo/Cargo.toml ================================================ [package] name = "serial-direct-echo" version = "0.1.0" edition = "2018" [dependencies] cortex-m-rt = "0.7.5" panic-halt = "1.0.0" defmt-rtt = "1.1.0" [dependencies.microbit] path = "../../microbit" ================================================ FILE: examples/serial-direct-echo/src/main.rs ================================================ #![no_main] #![no_std] use panic_halt as _; use core::str; use cortex_m_rt::entry; #[entry] fn main() -> ! { if let Some(p) = microbit::Peripherals::take() { /* Configure RX and TX pins accordingly */ p.GPIO.pin_cnf[24].write(|w| w.pull().pullup().dir().output()); p.GPIO.pin_cnf[25].write(|w| w.pull().disabled().dir().input()); let uart0 = p.UART0; /* Tell UART which pins to use for sending and receiving */ uart0.pseltxd.write(|w| unsafe { w.bits(24) }); uart0.pselrxd.write(|w| unsafe { w.bits(25) }); /* Set a typical baud rate of 115200 */ uart0.baudrate.write(|w| w.baudrate().baud115200()); /* Enable UART function */ uart0.enable.write(|w| w.enable().enabled()); /* Print a nice hello message */ let _ = write_uart0(&uart0, "Please type characters to echo:\r\n"); /* Fire up receiving task */ uart0.tasks_startrx.write(|w| unsafe { w.bits(1) }); /* Endless loop */ loop { /* Busy wait for reception of data */ while uart0.events_rxdrdy.read().bits() == 0 {} /* We're going to pick up the data soon, let's signal the buffer is already waiting for * more data */ uart0.events_rxdrdy.write(|w| unsafe { w.bits(0) }); /* Read one 8bit value */ let c = uart0.rxd.read().bits() as u8; /* What comes in must go out, we don't care what it is */ let _ = write_uart0(&uart0, unsafe { str::from_utf8_unchecked(&[c; 1]) }); } } loop { continue; } } fn write_uart0(uart0: µbit::pac::UART0, s: &str) -> core::fmt::Result { /* Start UART sender */ uart0.tasks_starttx.write(|w| unsafe { w.bits(1) }); for c in s.as_bytes() { /* Write the current character to the output register */ uart0.txd.write(|w| unsafe { w.bits(u32::from(*c)) }); /* Wait until the UART is clear to send */ while uart0.events_txdrdy.read().bits() == 0 {} /* And then reset it for the next round */ uart0.events_txdrdy.write(|w| unsafe { w.bits(0) }); } /* Stop UART sender */ uart0.tasks_stoptx.write(|w| unsafe { w.bits(1) }); Ok(()) } ================================================ FILE: examples/serial-direct-helloworld/Cargo.toml ================================================ [package] name = "serial-direct-helloworld" version = "0.1.0" edition = "2018" [dependencies] cortex-m-rt = "0.7.5" panic-halt = "1.0.0" defmt-rtt = "1.1.0" [dependencies.microbit] path = "../../microbit" ================================================ FILE: examples/serial-direct-helloworld/src/main.rs ================================================ #![no_main] #![no_std] use panic_halt as _; use cortex_m_rt::entry; #[entry] fn main() -> ! { if let Some(p) = microbit::Peripherals::take() { p.GPIO.pin_cnf[24].write(|w| w.pull().pullup().dir().output()); p.GPIO.pin_cnf[25].write(|w| w.pull().disabled().dir().input()); p.UART0.pseltxd.write(|w| unsafe { w.bits(24) }); p.UART0.pselrxd.write(|w| unsafe { w.bits(25) }); p.UART0.baudrate.write(|w| w.baudrate().baud115200()); p.UART0.enable.write(|w| w.enable().enabled()); let _ = write_uart0(&p.UART0, "Hello World!\n"); } loop { continue; } } fn write_uart0(uart0: µbit::pac::UART0, s: &str) -> core::fmt::Result { uart0.tasks_starttx.write(|w| unsafe { w.bits(1) }); for c in s.as_bytes() { /* Write the current character to the output register */ uart0.txd.write(|w| unsafe { w.bits(u32::from(*c)) }); /* Wait until the UART is clear to send */ while uart0.events_txdrdy.read().bits() == 0 {} /* And then set it back to 0 again, just because ?!? */ uart0.events_txdrdy.write(|w| unsafe { w.bits(0) }); } uart0.tasks_stoptx.write(|w| unsafe { w.bits(1) }); Ok(()) } ================================================ FILE: examples/serial-hal-blocking-echo/Cargo.toml ================================================ [package] name = "serial-hal-blocking-echo" version = "0.1.0" edition = "2018" [dependencies] cortex-m-rt = "0.7" panic-halt = "1.0.0" defmt-rtt = "1.1" nb = "1.1.0" embedded-hal = "1.0.0" embedded-io = "0.7.1" [dependencies.microbit] path = "../../microbit" optional = true [dependencies.microbit-v2] path = "../../microbit-v2" optional = true [features] v1 = ["microbit"] v2 = ["microbit-v2"] ================================================ FILE: examples/serial-hal-blocking-echo/src/main.rs ================================================ #![no_main] #![no_std] use panic_halt as _; use core::fmt::Write; use cortex_m_rt::entry; use embedded_io::Read; #[cfg(feature = "v1")] use microbit::{ hal::uart, hal::uart::{Baudrate, Parity}, }; #[cfg(feature = "v2")] use microbit::{ hal::uarte, hal::uarte::{Baudrate, Parity}, }; #[cfg(feature = "v2")] mod serial_setup; #[cfg(feature = "v2")] use serial_setup::UartePort; #[entry] fn main() -> ! { let board = microbit::Board::take().unwrap(); #[cfg(feature = "v1")] let mut serial = { uart::Uart::new( board.UART0, board.uart.into(), Parity::EXCLUDED, Baudrate::BAUD115200, ) }; #[cfg(feature = "v2")] let mut serial = { let serial = uarte::Uarte::new( board.UARTE0, board.uart.into(), Parity::EXCLUDED, Baudrate::BAUD115200, ); UartePort::new(serial) }; loop { write!(serial, "Hello World:\r\n").unwrap(); let mut input = [0]; serial.read_exact(&mut input).unwrap(); write!(serial, "You said: {}\r\n", input[0] as char).unwrap(); } } ================================================ FILE: examples/serial-hal-blocking-echo/src/serial_setup.rs ================================================ use core::{fmt, ptr::addr_of_mut}; use microbit::hal::uarte::{Error, Instance, Uarte, UarteRx, UarteTx}; static mut TX_BUF: [u8; 1] = [0; 1]; static mut RX_BUF: [u8; 1] = [0; 1]; pub struct UartePort(UarteTx, UarteRx); impl UartePort { pub fn new(serial: Uarte) -> UartePort { let (tx, rx) = serial .split(unsafe { addr_of_mut!(TX_BUF).as_mut().unwrap() }, unsafe { addr_of_mut!(RX_BUF).as_mut().unwrap() }) .unwrap(); UartePort(tx, rx) } } impl fmt::Write for UartePort { fn write_str(&mut self, s: &str) -> fmt::Result { self.0.write_str(s) } } impl embedded_io::ErrorType for UartePort { type Error = Error; } impl embedded_io::Write for UartePort { fn write(&mut self, buffer: &[u8]) -> Result { self.0.write(buffer) } fn flush(&mut self) -> Result<(), Self::Error> { self.0.flush() } } impl embedded_io::Read for UartePort { fn read(&mut self, buffer: &mut [u8]) -> Result { self.1.read(buffer) } } ================================================ FILE: examples/servo/Cargo.toml ================================================ [package] name = "servo" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.5" panic-halt = "1.0.0" defmt-rtt = "1.1.0" defmt = "1.0.1" [dependencies.microbit] path = "../../microbit" optional = true [dependencies.microbit-v2] path = "../../microbit-v2" optional = true [features] v1 = ["microbit"] v2 = ["microbit-v2"] default = [ "defmt-default", ] # do NOT modify these features defmt-default = [] defmt-trace = [] defmt-debug = [] defmt-info = [] defmt-warn = [] defmt-error = [] ================================================ FILE: examples/servo/src/main.rs ================================================ #![no_std] #![no_main] use defmt_rtt as _; use panic_halt as _; use core::cell::RefCell; use cortex_m::interrupt::Mutex; use cortex_m_rt::entry; use microbit::{ board::Board, hal::{ gpio::Level, gpiote::*, pac::{self, interrupt, TIMER0}, ppi::{self, ConfigurablePpi, Ppi}, }, }; static SERVO_TIMER: Mutex>> = Mutex::new(RefCell::new(None)); #[entry] fn main() -> ! { if let Some(board) = Board::take() { let gpiote = Gpiote::new(board.GPIOTE); // Servo output pins let servopin1 = board.edge.e01.into_push_pull_output(Level::Low).degrade(); // PAD2 let servopin2 = board.edge.e02.into_push_pull_output(Level::Low).degrade(); // PAD3 // Output channel for Servo 1 gpiote .channel0() .output_pin(servopin1) .task_out_polarity(TaskOutPolarity::Toggle) .init_low(); gpiote.channel0().task_out().write(|w| unsafe { w.bits(1) }); // Output channel for Servo 2 gpiote .channel1() .output_pin(servopin2) .task_out_polarity(TaskOutPolarity::Toggle) .init_low(); gpiote.channel1().task_out().write(|w| unsafe { w.bits(1) }); let ppi_channels = ppi::Parts::new(board.PPI); // Set both servo outputs high form Timer0 CC[0] // Set each servo output low from the respective Timer0 CC[1] and CC[2] // Each timer can run 3 Servos let mut ppi0 = ppi_channels.ppi0; ppi0.set_task_endpoint(gpiote.channel0().task_out()); ppi0.set_event_endpoint(&board.TIMER0.events_compare[0]); ppi0.enable(); let mut ppi1 = ppi_channels.ppi1; ppi1.set_task_endpoint(gpiote.channel0().task_out()); ppi1.set_event_endpoint(&board.TIMER0.events_compare[1]); ppi1.enable(); let mut ppi2 = ppi_channels.ppi2; ppi2.set_task_endpoint(gpiote.channel1().task_out()); ppi2.set_event_endpoint(&board.TIMER0.events_compare[0]); ppi2.enable(); let mut ppi3 = ppi_channels.ppi3; ppi3.set_task_endpoint(gpiote.channel1().task_out()); ppi3.set_event_endpoint(&board.TIMER0.events_compare[2]); ppi3.enable(); // The Timer PAC is used directly as the HAL does not give full access to all registers board.TIMER0.mode.write(|w| unsafe { w.bits(0) }); board.TIMER0.bitmode.write(|w| unsafe { w.bits(0) }); // CC[0] every 20 ms (50 Hz) board.TIMER0.cc[0].write(|w| unsafe { w.bits(20000) }); board.TIMER0.shorts.write(|w| unsafe { w.bits(1) }); // Servo duty cycle is from 0.5 ms to 2.5 ms with 1.5 ms for center position board.TIMER0.cc[1].write(|w| unsafe { w.bits(1500) }); board.TIMER0.cc[2].write(|w| unsafe { w.bits(1500) }); board.TIMER0.tasks_start.write(|w| unsafe { w.bits(1) }); // Timer0 interrupt on CC[0] board.TIMER0.intenset.write(|w| unsafe { w.bits(1 << 16) }); cortex_m::interrupt::free(move |cs| { *SERVO_TIMER.borrow(cs).borrow_mut() = Some(board.TIMER0); }); unsafe { pac::NVIC::unmask(pac::Interrupt::TIMER0); } loop {} } panic!("End"); } #[interrupt] fn TIMER0() { // Change Servo position at the start of the duty cycle. Then there is no race condition // between changing the duty cycle and a CC event. static mut SPEED: i32 = 1500; static mut DIRECTION: i32 = 1; match SPEED { i32::MIN..=500 => *DIRECTION = 1, 2500..=i32::MAX => *DIRECTION = -1, _ => {} } *SPEED += *DIRECTION; cortex_m::interrupt::free(|cs| { // if let Some(cc_value) = CC_VALUE.borrow(cs).borrow().as_ref() { if let Some(timer) = SERVO_TIMER.borrow(cs).borrow_mut().as_mut() { //timer.cc[1].write(|w|unsafe { w.bits(u32::try_from(*cc_value).unwrap_or(1500)) }); let set_speed = u32::try_from(*SPEED).unwrap_or(1500); timer.cc[1].write(|w| unsafe { w.bits(set_speed) }); timer.cc[2].write(|w| unsafe { w.bits(set_speed) }); timer.events_compare[0].write(|w| unsafe { w.bits(0) }); } //} }); } ================================================ FILE: examples/v2-microphone/Cargo.toml ================================================ [package] name = "v2-microphone" version = "0.1.0" edition = "2018" [dependencies] cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } embedded-hal = "1.0.0" cortex-m-rt = "0.7.5" panic-halt = "1.0.0" defmt-rtt = "1.1.0" defmt = "1.0.1" [dependencies.microbit-v2] path = "../../microbit-v2" optional = true [features] v2 = ["microbit-v2"] default = ["defmt-default"] # do NOT modify these features defmt-default = [] defmt-trace = [] defmt-debug = [] defmt-info = [] defmt-warn = [] defmt-error = [] ================================================ FILE: examples/v2-microphone/src/main.rs ================================================ #![no_std] #![no_main] use defmt_rtt as _; use panic_halt as _; use cortex_m_rt::entry; use microbit::{ board::Board, display::blocking::Display, hal::{ gpio::{Level, OpenDrainConfig}, saadc::SaadcConfig, Saadc, Timer, }, }; #[entry] fn main() -> ! { if let Some(board) = Board::take() { let mut timer = Timer::new(board.TIMER0); let mut display = Display::new(board.display_pins); // initialize adc let saadc_config = SaadcConfig::default(); let mut saadc = Saadc::new(board.ADC, saadc_config); let mut mic_in = board.microphone_pins.mic_in.into_floating_input(); // enable microphone board .microphone_pins .mic_run .into_open_drain_output(OpenDrainConfig::Disconnect0HighDrive1, Level::High); let mut count: u64 = 0; let mut sum: u64 = 0; let mut max_value: u16 = 0; loop { let mic_value = saadc .read_channel(&mut mic_in) .expect("could not read value of microphone") as u16; // Smoothen the signal as audio comes in waves max_value = max_value.max(mic_value); sum += mic_value as u64; count += 1; if count % 100 == 0 { let avg = (sum / count) as u16; let image = [ [if max_value > avg + 100 { 1 } else { 0 }; 5], [if max_value > avg + 80 { 1 } else { 0 }; 5], [if max_value > avg + 60 { 1 } else { 0 }; 5], [if max_value > avg + 40 { 1 } else { 0 }; 5], [if max_value > avg + 20 { 1 } else { 0 }; 5], ]; display.show(&mut timer, image, 10); max_value = 0; } } } panic!("End"); } ================================================ FILE: examples/v2-speaker/Cargo.toml ================================================ [package] name = "v2-speaker" version = "0.1.0" edition = "2018" [dependencies] cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } embedded-hal = "1.0.0" cortex-m-rt = "0.7.5" panic-halt = "1.0.0" defmt-rtt = "1.1" defmt = "1.0.1" [dependencies.microbit-v2] path = "../../microbit-v2" optional = true [features] v2 = ["microbit-v2"] default = [ "defmt-default", ] # do NOT modify these features defmt-default = [] defmt-trace = [] defmt-debug = [] defmt-info = [] defmt-warn = [] defmt-error = [] ================================================ FILE: examples/v2-speaker/src/main.rs ================================================ #![no_main] #![no_std] use defmt_rtt as _; use panic_halt as _; use core::cell::RefCell; use cortex_m::interrupt::Mutex; use cortex_m_rt::entry; use embedded_hal::digital::OutputPin; use microbit::{ hal::{ clocks::Clocks, gpio, pwm, rtc::{Rtc, RtcInterrupt}, time::Hertz, }, pac::{self, interrupt}, Board, }; static RTC: Mutex>>> = Mutex::new(RefCell::new(None)); static SPEAKER: Mutex>>> = Mutex::new(RefCell::new(None)); #[entry] fn main() -> ! { if let Some(mut board) = Board::take() { cortex_m::interrupt::free(move |cs| { // NB: The LF CLK pin is used by the speaker let _clocks = Clocks::new(board.CLOCK) .enable_ext_hfosc() .set_lfclk_src_synth() .start_lfclk(); let mut rtc = Rtc::new(board.RTC0, 511).unwrap(); rtc.enable_counter(); rtc.enable_interrupt(RtcInterrupt::Tick, Some(&mut board.NVIC)); rtc.enable_event(RtcInterrupt::Tick); *RTC.borrow(cs).borrow_mut() = Some(rtc); let mut speaker_pin = board.speaker_pin.into_push_pull_output(gpio::Level::High); let _ = speaker_pin.set_low(); // Use the PWM peripheral to generate a waveform for the speaker let speaker = pwm::Pwm::new(board.PWM0); speaker // output the waveform on the speaker pin .set_output_pin(pwm::Channel::C0, speaker_pin.degrade()) // Use prescale by 16 to achive darker sounds .set_prescaler(pwm::Prescaler::Div16) // Initial frequency .set_period(Hertz(1u32)) // Configure for up and down counter mode .set_counter_mode(pwm::CounterMode::UpAndDown) // Set maximum duty cycle .set_max_duty(32767) // enable PWM .enable(); speaker .set_seq_refresh(pwm::Seq::Seq0, 0) .set_seq_end_delay(pwm::Seq::Seq0, 0); // Configure 50% duty cycle let max_duty = speaker.max_duty(); speaker.set_duty_on_common(max_duty / 2); *SPEAKER.borrow(cs).borrow_mut() = Some(speaker); // Configure RTC interrupt unsafe { pac::NVIC::unmask(pac::Interrupt::RTC0); } pac::NVIC::unpend(pac::Interrupt::RTC0); }); } loop { continue; } } const STOP_FREQUENCY: u32 = 500; // RTC interrupt, exectued for each RTC tick #[interrupt] fn RTC0() { static mut FREQUENCY: u32 = 1; /* Enter critical section */ cortex_m::interrupt::free(|cs| { /* Borrow devices */ if let (Some(speaker), Some(rtc)) = ( SPEAKER.borrow(cs).borrow().as_ref(), RTC.borrow(cs).borrow().as_ref(), ) { if *FREQUENCY < STOP_FREQUENCY { // Configure the new frequency, must not be zero. // Will change the max_duty speaker.set_period(Hertz(*FREQUENCY)); } else { // Continue at frequency speaker.set_period(Hertz(STOP_FREQUENCY)); } // Restart the PWM at 50% duty cycle let max_duty = speaker.max_duty(); speaker.set_duty_on_common(max_duty / 2); if *FREQUENCY >= STOP_FREQUENCY + 250 { defmt::info!("Fin"); // Stop speaker and RTC speaker.disable(); rtc.disable_counter(); }; // Clear the RTC interrupt rtc.reset_event(RtcInterrupt::Tick); } }); // Increase the frequency *FREQUENCY += 1; } ================================================ FILE: memory.x ================================================ MEMORY { /* NOTE K = KiBi = 1024 bytes */ FLASH : ORIGIN = 0x00000000, LENGTH = 256K RAM : ORIGIN = 0x20000000, LENGTH = 16K } ================================================ FILE: microbit/Cargo.toml ================================================ [package] name = "microbit" version = "0.16.0" description = "Board support crate for the BBC Micro:bit V1" edition = "2018" readme = "../README.md" rust-version = "1.79.0" repository = "https://github.com/nrf-rs/microbit" authors = [ "Daniel Egger ", "Michael Droogleever ", "Rob Young ", ] categories = ["hardware-support", "embedded", "no-std"] keywords = ["arm", "cortex-m", "nrf", "hal"] license = "0BSD" [dependencies] [dependencies.microbit-common] path = "../microbit-common" features = ["v1"] version = "=0.16.0" [features] embedded-hal-02 = ["microbit-common/embedded-hal-02"] ================================================ FILE: microbit/src/lib.rs ================================================ //! microbit contains everything required to get started with the use of Rust //! to create firmwares for the fabulous [BBC micro:bit](https://microbit.org) //! microcontroller board. //! //! This crate is for the original micro:bit (V1) pictured below on the left. If //! your micro:bit looks like the one on the right you need the //! [microbit-v2](https://crates.io/crates/microbit-v2) crate. //! //! [](https://github.com/microbit-foundation/microbit-svg/blob/master/microbit-drawing-back-1-5.png) //! [](https://github.com/microbit-foundation/microbit-svg/blob/master/microbit-drawing-back-2.png) #![doc(html_root_url = "https://docs.rs/microbit/0.16.0")] #![no_std] #![deny(missing_docs)] #![allow(non_camel_case_types)] pub use microbit_common::*; ================================================ FILE: microbit-common/Cargo.toml ================================================ [package] name = "microbit-common" version = "0.16.0" description = "Implementation details for the BBC Micro:bit board support crates" edition = "2018" readme = "../README.md" rust-version = "1.79.0" repository = "https://github.com/nrf-rs/microbit" authors = [ "Daniel Egger ", "Michael Droogleever ", "Rob Young ", ] categories = ["hardware-support", "embedded", "no-std"] keywords = ["arm", "cortex-m", "nrf", "hal"] license = "0BSD" [dependencies] tiny-led-matrix = "1.0.2" embedded-hal = "1.0.0" [dependencies.nrf51-hal] optional = true version = "0.19.0" default-features = false features = ["rt", "xxAB-package"] [dependencies.nrf52833-hal] optional = true version = "0.19.0" default-features = false features = ["rt"] [features] doc = [] v1 = ["nrf51-hal"] v2 = ["nrf52833-hal"] embedded-hal-02 = [ "nrf51-hal?/embedded-hal-02", "nrf52833-hal?/embedded-hal-02", ] [package.metadata.docs.rs] features = ["v2"] default-target = "thumbv7em-none-eabihf" ================================================ FILE: microbit-common/src/adc.rs ================================================ //! ADC #[cfg(feature = "v1")] pub use crate::v1::adc::*; #[cfg(feature = "v2")] pub use crate::v2::adc::*; ================================================ FILE: microbit-common/src/board.rs ================================================ //! Main Board #[cfg(feature = "v1")] pub use crate::v1::board::*; #[cfg(feature = "v2")] pub use crate::v2::board::*; ================================================ FILE: microbit-common/src/display/blocking.rs ================================================ //! Blocking support for the 5x5 LED display. //! //! This module provides a simple blocking interface //! to the on board 5x5 LED display. If you need a more sophisticated //! or non-blocking interface use the [`display::nonblocking`](crate::display::nonblocking) module. //! //! # Example //! //! ```no_run //! # use microbit_common as microbit; //! # use microbit::{ //! # Board, //! # hal, //! # display::blocking::Display, //! # }; //! # use embedded_hal::delay::DelayNs; //! // take the board //! let board = Board::take().unwrap(); //! // make a timer //! let mut timer = hal::Timer::new(board.TIMER0); //! // create the Display //! let mut display = Display::new(board.display_pins); //! // and light up some LEDs //! let heart = [ //! [0, 1, 0, 1, 0], //! [1, 0, 1, 0, 1], //! [1, 0, 0, 0, 1], //! [0, 1, 0, 1, 0], //! [0, 0, 1, 0, 0], //! ]; //! loop { //! display.show(&mut timer, heart, 1000); //! display.clear(); //! timer.delay_ms(250); //! } //! ``` //! //! The coordiante system is oriented so the 'bottom' (x,4) row is the edge with the edge //! connector. That means that //! //! ```no_run //! # use microbit_common as microbit; //! # use microbit::{ //! # Board, //! # hal, //! # display::blocking::Display, //! # }; //! # let board = Board::take().unwrap(); //! # let mut timer = hal::Timer::new(board.TIMER0); //! # let mut display = Display::new(board.display_pins); //! display.show( //! &mut timer, //! [ //! [0, 0, 1, 0, 0], //! [0, 1, 1, 1, 0], //! [1, 0, 1, 0, 1], //! [0, 0, 1, 0, 0], //! [0, 0, 1, 0, 0], //! ], //! 1000, //!); //! ``` //! Will display an arrow pointing towards the boards usb port. //! //! For a working example [`examples/display-blocking`](https://github.com/nrf-rs/microbit/tree/main/examples/display-blocking) use crate::gpio::{DisplayPins, NUM_COLS, NUM_ROWS}; use crate::hal::gpio::{Output, Pin, PushPull}; use embedded_hal::{delay::DelayNs, digital::OutputPin}; #[allow(clippy::upper_case_acronyms)] pub(crate) type LED = Pin>; const DEFAULT_DELAY_MS: u32 = 2; #[cfg(feature = "v1")] const LED_LAYOUT: [[(usize, usize); 5]; 5] = [ [(0, 0), (1, 3), (0, 1), (1, 4), (0, 2)], [(2, 3), (2, 4), (2, 5), (2, 6), (2, 7)], [(1, 1), (0, 8), (1, 2), (2, 8), (1, 0)], [(0, 7), (0, 6), (0, 5), (0, 4), (0, 3)], [(2, 2), (1, 6), (2, 0), (1, 5), (2, 1)], ]; /// Blocking interface to the on board LED display pub struct Display { delay_ms: u32, rows: [LED; NUM_ROWS], cols: [LED; NUM_COLS], } impl Display { /// Create and initialise the display driver /// /// The [`display_pins!`](crate::display_pins) macro can be used /// to create [`DisplayPins`]. pub fn new(pins: DisplayPins) -> Self { let (cols, rows) = pins.degrade(); Display { delay_ms: DEFAULT_DELAY_MS, rows, cols, } } /// Clear the display pub fn clear(&mut self) { for row in &mut self.rows { row.set_low().ok(); } for col in &mut self.cols { col.set_high().ok(); } } /// Set delay, time spent on each matrix row, in ms pub fn set_delay_ms(&mut self, delay_ms: u32) { self.delay_ms = delay_ms; } /// Set refresh rate, time for matrix scan pub fn set_refresh_rate(&mut self, freq_hz: u32) { self.delay_ms = 1000 / freq_hz / (NUM_ROWS as u32); } /// Convert 5x5 image to 3x9 matrix /// /// The pins are represented as a [3x9 matrix on the micro:bit /// V1](https://tech.microbit.org/hardware/1-5-revision/#display). #[cfg(feature = "v1")] fn image2matrix(led_image: [[u8; 5]; 5]) -> [[u8; 9]; 3] { let mut led_matrix: [[u8; 9]; 3] = [[0; 9]; 3]; for (led_image_row, layout_row) in led_image.iter().zip(LED_LAYOUT.iter()) { for (led_image_val, layout_loc) in led_image_row.iter().zip(layout_row) { led_matrix[layout_loc.0][layout_loc.1] = *led_image_val; } } led_matrix } /// Display 5x5 image for a given duration pub fn show(&mut self, delay: &mut D, led_display: [[u8; 5]; 5], duration_ms: u32) { #[cfg(feature = "v1")] { let led_matrix = Display::image2matrix(led_display); self.show_inner(delay, led_matrix, duration_ms); } #[cfg(feature = "v2")] self.show_inner(delay, led_display, duration_ms); } /// Display matrix image for a given duration (3x9 for V1 micro:bit) /// /// The pins are represented as a [3x9 matrix on the micro:bit /// V1](https://tech.microbit.org/hardware/1-5-revision/#display). fn show_inner( &mut self, delay: &mut D, led_matrix: [[u8; NUM_COLS]; NUM_ROWS], duration_ms: u32, ) { // TODO: something more intelligent with timers let loops = duration_ms / (self.rows.len() as u32 * self.delay_ms); for _ in 0..loops { for (row_line, led_matrix_row) in self.rows.iter_mut().zip(led_matrix.iter()) { row_line.set_high().ok(); for (col_line, led_matrix_val) in self.cols.iter_mut().zip(led_matrix_row.iter()) { // TODO : use value to set brightness if *led_matrix_val > 0 { col_line.set_low().ok(); } } delay.delay_us(self.delay_ms * 1000); for col_line in &mut self.cols { col_line.set_high().ok(); } row_line.set_low().ok(); } } } } ================================================ FILE: microbit-common/src/display/mod.rs ================================================ //! Support for the 5x5 LED display. //! //! There are two APIs for controlling the LED display, [`blocking`] and [`nonblocking`]. //! The `blocking` API is the simplest to get started with. pub mod blocking; pub mod nonblocking; ================================================ FILE: microbit-common/src/display/nonblocking/control.rs ================================================ //! Implementation of [`DisplayControl`] for the micro:bit's GPIO peripheral. //! //! This controls the micro:bit's 5×5 LED display. //! //! [`DisplayControl`]: tiny_led_matrix::DisplayControl use tiny_led_matrix::DisplayControl; use crate::{ gpio::{NUM_COLS, NUM_ROWS}, pac, }; const fn pin_bits(pins: &[usize]) -> u32 { let mut i: usize = 0; let mut bits: u32 = 0; while i < pins.len() { bits |= 1 << pins[i]; i += 1; } bits } #[cfg(feature = "v1")] mod pins { use super::{NUM_COLS, NUM_ROWS}; pub(super) const P0_COLS: [usize; NUM_COLS] = [4, 5, 6, 7, 8, 9, 10, 11, 12]; pub(super) const P0_ROWS: [usize; NUM_ROWS] = [13, 14, 15]; } #[cfg(feature = "v2")] mod pins { use super::{NUM_COLS, NUM_ROWS}; pub(super) const P0_COLS: [usize; NUM_COLS - 1] = [28, 11, 31, 30]; pub(super) const P1_COLS: [usize; 1] = [5]; pub(super) const P0_ROWS: [usize; NUM_ROWS] = [21, 22, 15, 24, 19]; } const P0_COL_BITS: u32 = pin_bits(&pins::P0_COLS); #[cfg(feature = "v2")] const P1_COL_BITS: u32 = pin_bits(&pins::P1_COLS); const P0_ROW_BITS: u32 = pin_bits(&pins::P0_ROWS); #[cfg(feature = "v1")] type P0 = pac::GPIO; #[cfg(feature = "v2")] type P0 = pac::P0; #[cfg(feature = "v2")] type P1 = pac::P1; /// This implements the `DisplayControl` trait. /// /// [`DisplayControl`]: tiny_led_matrix::DisplayControl pub(crate) struct MicrobitGpio; /// Returns the GPIO pin numbers corresponding to the columns in a Column fn column_pins(mut cols: u32, px_cols: &[usize]) -> u32 { let mut result = 0u32; for &pin in px_cols.iter() { result |= (cols & 1) << pin; cols >>= 1; } result } #[cfg(feature = "v1")] fn split_cols(cols: u32) -> (u32, u32) { (cols, 0u32) } #[cfg(feature = "v2")] fn split_cols(cols: u32) -> (u32, u32) { // get all except col 2 (4th from least significant) let p0_cols = ((cols & 0b10000) >> 1) | (0b00111 & cols); // get col 4 (4th from least significant) let p1_cols = (cols & 0b01000) >> 3; (p0_cols, p1_cols) } /// Implementation of [`DisplayControl`] for the micro:bit's GPIO peripheral. /// /// This controls the micro:bit's 5×5 LED display. /// /// The `initialise_for display` implementation assumes the port is in the /// state it would have after system reset. /// /// [`DisplayControl`]: tiny_led_matrix::DisplayControl impl DisplayControl for MicrobitGpio { fn initialise_for_display(&mut self) { unsafe { let p0 = &*P0::ptr(); for ii in pins::P0_COLS.iter() { p0.pin_cnf[*ii].write(|w| w.dir().output()); } for ii in pins::P0_ROWS.iter() { p0.pin_cnf[*ii].write(|w| w.dir().output()); } // Set all p0 cols high. p0.outset .write(|w| w.bits(pins::P0_COLS.iter().map(|pin| 1 << pin).sum())); #[cfg(feature = "v2")] { let p1 = &*P1::ptr(); for ii in pins::P1_COLS.iter() { p1.pin_cnf[*ii].write(|w| w.dir().output()); } // Set all p1 cols high. p1.outset .write(|w| w.bits(pins::P1_COLS.iter().map(|pin| 1 << pin).sum())); } } } fn display_row_leds(&mut self, row: usize, cols: u32) { unsafe { let p0 = &*P0::ptr(); #[allow(unused_variables)] let (p0cols, p1cols) = split_cols(cols); // To light an LED, we set the row bit and clear the col bit. let rows_to_set = 1 << pins::P0_ROWS[row]; let rows_to_clear = P0_ROW_BITS ^ rows_to_set; #[cfg(feature = "v1")] { let cols_to_clear = column_pins(p0cols, &pins::P0_COLS); let cols_to_set = P0_COL_BITS ^ cols_to_clear; p0.outset.write(|w| w.bits(rows_to_set | cols_to_set)); p0.outclr.write(|w| w.bits(rows_to_clear | cols_to_clear)); } #[cfg(feature = "v2")] { let p1 = &*P1::ptr(); let p0_cols_to_clear = column_pins(p0cols, &pins::P0_COLS); let p0_cols_to_set = P0_COL_BITS ^ p0_cols_to_clear; let p1_cols_to_clear = column_pins(p1cols, &pins::P1_COLS); let p1_cols_to_set = P1_COL_BITS ^ p1_cols_to_clear; // We do the row-clearing write first and the row-setting write last, so that // intermediate states never light LEDs which aren't lit in either the old or new state. p0.outclr .write(|w| w.bits(rows_to_clear | p0_cols_to_clear)); p1.outset.write(|w| w.bits(p1_cols_to_set)); p1.outclr.write(|w| w.bits(p1_cols_to_clear)); p0.outset.write(|w| w.bits(rows_to_set | p0_cols_to_set)); } } } fn light_current_row_leds(&mut self, cols: u32) { unsafe { #[allow(unused_variables)] let (p0cols, p1cols) = split_cols(cols); let p0 = &*P0::ptr(); p0.outclr .write(|w| w.bits(column_pins(p0cols, &pins::P0_COLS))); #[cfg(feature = "v2")] { let p1 = &*P1::ptr(); p1.outclr .write(|w| w.bits(column_pins(p1cols, &pins::P1_COLS))); } } } } ================================================ FILE: microbit-common/src/display/nonblocking/image.rs ================================================ //! Static 5×5 greyscale and black-and-white images. use tiny_led_matrix::{Render, MAX_BRIGHTNESS}; /// A 5×5 image supporting the full range of brightnesses for each LED. /// /// Uses 25 bytes of storage. #[derive(Copy, Clone, Debug)] pub struct GreyscaleImage([[u8; 5]; 5]); impl GreyscaleImage { /// Constructs a GreyscaleImage from an array of brightnesses. /// /// The data should be an array of 5 rows (top first), each of which is an /// array of 5 brightness values (left first). /// /// # Example /// /// ```no_run /// # use microbit_common as microbit; /// # use microbit::display::nonblocking::GreyscaleImage; /// const GREY_HEART: GreyscaleImage = GreyscaleImage::new(&[ /// [0, 9, 0, 9, 0], /// [9, 5, 9, 5, 9], /// [9, 5, 5, 5, 9], /// [0, 9, 5, 9, 0], /// [0, 0, 9, 0, 0], /// ]); /// ``` pub const fn new(data: &[[u8; 5]; 5]) -> GreyscaleImage { GreyscaleImage(*data) } /// Construct a GreyscaleImage with all LEDs turned off. pub const fn blank() -> GreyscaleImage { GreyscaleImage([[0; 5]; 5]) } } impl Render for GreyscaleImage { fn brightness_at(&self, x: usize, y: usize) -> u8 { self.0[y][x] } } impl Render for &GreyscaleImage { fn brightness_at(&self, x: usize, y: usize) -> u8 { GreyscaleImage::brightness_at(self, x, y) } } /// A 5×5 image supporting only two levels of brightness (on and off). /// /// Uses 5 bytes of storage. /// /// For display, each pixel is treated as having brightness either 0 or /// MAX_BRIGHTNESS. #[derive(Copy, Clone, Debug)] pub struct BitImage([u8; 5]); impl BitImage { /// Constructs a BitImage from an array of brightnesses. /// /// The data should be an array of 5 rows (top first), each of which is an /// array of 5 values (left first). Each value should be either 0 or 1. /// /// # Example /// /// ```no_run /// # use microbit_common as microbit; /// # use microbit::display::nonblocking::BitImage; /// const HEART: BitImage = BitImage::new(&[ /// [0, 1, 0, 1, 0], /// [1, 0, 1, 0, 1], /// [1, 0, 0, 0, 1], /// [0, 1, 0, 1, 0], /// [0, 0, 1, 0, 0], /// ]); /// ``` pub const fn new(im: &[[u8; 5]; 5]) -> BitImage { // FIXME: can we reject values other than 0 or 1? const fn row_byte(row: [u8; 5]) -> u8 { row[0] | (row[1] << 1) | (row[2] << 2) | (row[3] << 3) | (row[4] << 4) } BitImage([ row_byte(im[0]), row_byte(im[1]), row_byte(im[2]), row_byte(im[3]), row_byte(im[4]), ]) } /// Returns a new blank BitImage. /// /// All pixel values are 0. pub const fn blank() -> BitImage { BitImage([0; 5]) } } impl Render for BitImage { fn brightness_at(&self, x: usize, y: usize) -> u8 { let rowdata = self.0[y]; if rowdata & (1 << x) != 0 { MAX_BRIGHTNESS } else { 0 } } } impl Render for &BitImage { fn brightness_at(&self, x: usize, y: usize) -> u8 { BitImage::brightness_at(self, x, y) } } ================================================ FILE: microbit-common/src/display/nonblocking/matrix.rs ================================================ //! Implementation of [`Matrix`] and [`Frame`] for the micro:bit's LED display. //! //! This module describes the correspondence between the visible layout of //! micro:bit's LEDs and the pins controlling them. //! //! [`Matrix`]: tiny_led_matrix::Matrix //! [`Frame`]: tiny_led_matrix::Frame use crate::gpio::{NUM_COLS, NUM_ROWS}; use tiny_led_matrix::{Frame, Matrix, RowPlan}; /// Implementation of [`Matrix`] for the microbit's LED display. /// /// [`Matrix`]: tiny_led_matrix::Matrix pub struct MicrobitMatrix(); /// Gives the LED (x, y) coordinates for a given pin row and column. /// The origin is in the top-left. #[cfg(feature = "v1")] const MICROBIT_LED_LAYOUT: [[Option<(usize, usize)>; 3]; 9] = [ [Some((0, 0)), Some((4, 2)), Some((2, 4))], [Some((2, 0)), Some((0, 2)), Some((4, 4))], [Some((4, 0)), Some((2, 2)), Some((0, 4))], [Some((4, 3)), Some((1, 0)), Some((0, 1))], [Some((3, 3)), Some((3, 0)), Some((1, 1))], [Some((2, 3)), Some((3, 4)), Some((2, 1))], [Some((1, 3)), Some((1, 4)), Some((3, 1))], [Some((0, 3)), None, Some((4, 1))], [Some((1, 2)), None, Some((3, 2))], ]; impl Matrix for MicrobitMatrix { /// The number of pins connected to LED columns (3). const MATRIX_COLS: usize = NUM_COLS; /// The number of pins connected to LED rows (9). const MATRIX_ROWS: usize = NUM_ROWS; /// The number of visible LED columns (5). const IMAGE_COLS: usize = 5; /// The number of visible LED rows (5). const IMAGE_ROWS: usize = 5; #[cfg(feature = "v1")] fn image_coordinates(col: usize, row: usize) -> Option<(usize, usize)> { MICROBIT_LED_LAYOUT[col][row] } #[cfg(feature = "v2")] fn image_coordinates(col: usize, row: usize) -> Option<(usize, usize)> { Some((col, row)) } } /// A 'Compiled' representation of a 5×5 image to be displayed. /// /// Use the [`.set()`](`Frame::set`) method to store an image (something /// implementing [`Render`]) in the frame. /// /// Note you'll have to `use microbit::display::Frame` to make `set()` /// available. /// /// [`Frame`]: tiny_led_matrix::Frame /// [`Render`]: tiny_led_matrix::Render #[derive(Copy, Clone, Debug)] pub struct MicrobitFrame([RowPlan; MicrobitFrame::ROWS]); impl MicrobitFrame { /// Returns a new frame, initially blank. pub const fn default() -> MicrobitFrame { MicrobitFrame([RowPlan::default(); MicrobitFrame::ROWS]) } } impl Default for MicrobitFrame { /// Returns a new frame, initially blank. fn default() -> MicrobitFrame { MicrobitFrame::default() } } impl Frame for MicrobitFrame { type Mtx = MicrobitMatrix; fn row_plan(&self, row: usize) -> &RowPlan { &self.0[row] } fn row_plan_mut(&mut self, row: usize) -> &mut RowPlan { &mut self.0[row] } } ================================================ FILE: microbit-common/src/display/nonblocking/mod.rs ================================================ //! Non-blocking support for the 5×5 LED display. //! //! Together with [`tiny-led-matrix`](tiny_led_matrix), this module provides: //! - support for driving the LED display from a timer interrupt //! - ten levels of brightness for each LED //! - simple 5×5 greyscale and black-and-white image types. //! //! The module doesn't define interrupt handlers directly; instead it provides //! a function to be called from a timer interrupt. It knows how to program //! one of the micro:bit's timers to provide that interrupt. //! //! ## Example //! //! This shows general usage but is not a working example. //! For a working exaple see //! [`display_nonblocking`](https://github.com/nrf-rs/microbit/tree/main/examples/display-nonblocking). //! //! ```no_run //! # use microbit_common as microbit; //! use microbit::{ //! Board, //! hal, //! display::nonblocking::{Display, GreyscaleImage}, //! }; //! use embedded_hal::delay::DelayNs; //! //! let board = Board::take().unwrap(); //! //! let mut display = Display::new(board.TIMER1, board.display_pins); //! //! // in your main function //! { //! let mut timer2 = hal::Timer::new(board.TIMER0); //! loop { //! display.show(&GreyscaleImage::new(&[ //! [0, 7, 0, 7, 0], //! [7, 0, 7, 0, 7], //! [7, 0, 0, 0, 7], //! [0, 7, 0, 7, 0], //! [0, 0, 7, 0, 0], //! ])); //! timer2.delay_ms(1000); //! //! display.clear(); //! timer2.delay_ms(1000); //! } //! } //! //! // in a timer interrupt //! { //! display.handle_display_event(); //! } //! ``` //! //! ## Coordinate system //! //! The LEDs are identified using (x,y) coordinates as follows: //! //! ```text //! (0,0) ... (4,0) //! ... ... ... //! (0,4) ... (4,4) //! ``` //! //! where the 'bottom' (x,4) of the board is the edge connector. //! //! ## Greyscale model //! //! LED brightness levels are described using a scale from 0 (off) to 9 //! (brightest) inclusive. //! //! These are converted to time slices using the same timings as used by the //! [micro:bit MicroPython port][micropython] (this is different to the 0 to //! 255 scale used by the [micro:bit runtime][dal]). //! //! The time slice for each level above 1 is approximately 1.9× the slice for //! the previous level. //! #![cfg_attr( feature = "v1", 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)." )] #![cfg_attr( feature = "v2", doc = "An LED with brightness 9 is lit for one fifth of the time." )] //! //! ## Images //! //! An image is a type that implements the [`tiny_led_matrix::Render`] trait. Two image types are provided: //! - [`GreyscaleImage`](image::GreyscaleImage), allowing all 9 levels (using one byte for each LED) //! - [`BitImage`](image::BitImage), allowing only 'on' and 'off' (using five bytes) //! //! ## Display //! //! A [`Display`] instance controls the LEDs and programs a timer. There //! should normally be a single `Display` instance in the program. It is a wrapper //! around [`tiny_led_matrix::Display`] to expose an API similar to the blocking API. //! //! ## Frames //! //! Internally types implementing [`Render`](tiny_led_matrix::Render) aren't used directly with the [`Display`]; //! instead they're used to update a [`MicrobitFrame`] instance which is in //! turn passed to the `tiny_led_matrix::Display`. //! //! A `MicrobitFrame` instance is a 'compiled' representation of a 5×5 //! greyscale image, in a form that's more directly usable by the display //! code. //! //! This is exposed in the public API so that you can construct the //! `MicrobitFrame` representation in code running at a low priority. Then //! only [`Display::show_frame()`] has to be called in code that can't be //! interrupted by the display timer. //! //! ## Timer integration //! //! The [`Display`] expects to control a single timer. It can use the //! micro:bit's `TIMER0`, `TIMER1`, or `TIMER2`. //! //! For the micro:bit v1 this uses a 6ms period to light each of the three //! internal LED rows, so that the entire display is updated every 18ms. //! //! For the micro:bit v2 this uses a 3ms period to light each of the five //! internal LED rows, so that the entire display is updated every 15ms. //! //! When rendering greyscale images, the `Display` requests extra interrupts //! within each 6ms or 3ms period. It only requests interrupts for the //! greyscale levels which are actually required for what's currently being //! displayed. //! //! ### Technical details //! //! The timer is set to 16-bit mode, using a 62.5kHz or 135Khz clock (16 µs or //! 8µs ticks). It resets every 375 ticks. //! //! ## Usage //! //! Choose a timer to drive the display from (`TIMER0`, `TIMER1`, or `TIMER2`). //! //! When your program starts: //! - create a [`Display`] struct passing the timer and //! [`gpio::DisplayPins`](crate::gpio::DisplayPins) to [`Display::new()`]. //! //! In an interrupt handler for the timer call [`.handle_display_event()`](Display::handle_display_event) //! //! To change what's displayed; pass an image ([`GreyscaleImage`] or [`BitImage`]) to [`Display::show`]. //! //! You can call `show()` at any time, so long as you're not interrupting, or interruptable by, //! [`Display::handle_display_event()`]. //! //! See [`display_rtic`](https://github.com/nrf-rs/microbit/blob/master/examples/display_rtic) or //! [`display_nonblocking`](https://github.com/nrf-rs/microbit/blob/master/examples/display_nonblocking) //! example for a complete working example. //! //! [dal]: https://lancaster-university.github.io/microbit-docs/ //! [micropython]: https://microbit-micropython.readthedocs.io/ use tiny_led_matrix; #[doc(no_inline)] pub use tiny_led_matrix::{Frame, MAX_BRIGHTNESS}; mod control; mod image; mod matrix; mod timer; pub use image::{BitImage, GreyscaleImage}; pub use matrix::MicrobitFrame; use timer::MicrobitDisplayTimer; use crate::{gpio::DisplayPins, hal::timer::Instance}; use control::MicrobitGpio; /// Non-blocking interface to the on board 5x5 LED display pub struct Display { display: tiny_led_matrix::Display, timer: MicrobitDisplayTimer, pins: DisplayPins, frame: MicrobitFrame, } impl Display { /// Create and initialise the display driver /// /// [`DisplayPins`] can be used from [`Board::display_pins`](crate::Board::display_pins) /// or the [`display_pins!`](crate::display_pins) macro can be used is manually. pub fn new(timer: T, pins: DisplayPins) -> Self { let mut display = Self { display: tiny_led_matrix::Display::new(), timer: MicrobitDisplayTimer::new(timer), pins, frame: MicrobitFrame::default(), }; display.initialise(); display } /// Release the timer and pins pub fn free(self) -> (T, DisplayPins) { (self.timer.free(), self.pins) } /// Initialise the display /// /// This is usually called immediately after creating the display driver. /// It does not need to be called in a critical section. fn initialise(&mut self) { tiny_led_matrix::initialise_control(&mut MicrobitGpio {}); tiny_led_matrix::initialise_timer(&mut self.timer); } /// Update the LED display and timer state /// /// Call this in an interrupt handler for the timer you're using. This method /// takes care of updating the LED display and clearing the timer's event registers /// /// This may be called at any time, so long as the code calling it is not interrupting, or /// interruptable by `tiny_led_matrix::Display::handle_event()`. Within safe code, the borrow /// checker ensures that this requirement is fulfilled. When writing unsafe code, this method /// should be called from within a [critical /// section](https://docs.rs/cortex-m/0.7.2/cortex_m/interrupt/fn.free.html). pub fn handle_display_event(&mut self) { self.display .handle_event(&mut self.timer, &mut MicrobitGpio {}); } /// Show a new image /// /// This may be called at any time, so long as the code calling it is not interrupting, or /// interruptable by `tiny_led_matrix::Display::handle_event()`. Within safe code, the borrow /// checker ensures that this requirement is fulfilled. When writing unsafe code, this method /// should be called from within a [critical /// section](https://docs.rs/cortex-m/0.7.2/cortex_m/interrupt/fn.free.html). /// /// ## Example /// /// ```ignore /// display.show(&GreyscaleImage::new(&[ /// [0, 7, 0, 7, 0], /// [7, 0, 7, 0, 7], /// [7, 0, 0, 0, 7], /// [0, 7, 0, 7, 0], /// [0, 0, 7, 0, 0], /// ])); /// ``` pub fn show(&mut self, image: &R) { self.frame.set(image); self.display.set_frame(&self.frame); } /// Clear the display /// /// This may be called at any time, so long as the code calling it is not interrupting, or /// interruptable by `tiny_led_matrix::Display::handle_event()`. Within safe code, the borrow /// checker ensures that this requirement is fulfilled. When writing unsafe code, this method /// should be called from within a [critical /// section](https://docs.rs/cortex-m/0.7.2/cortex_m/interrupt/fn.free.html). pub fn clear(&mut self) { self.display.set_frame(&MicrobitFrame::default()); } /// Show a new frame /// /// This is similar to [`show`](Display::show) but accepts a [`MicrobitFrame`] instead. /// This may be useful if performance is a concern as calling `set` on the frame /// can be done outside the critical section. /// /// This may be called at any time, so long as the code calling it is not interrupting, or /// interruptable by `tiny_led_matrix::Display::handle_event()`. Within safe code, the borrow /// checker ensures that this requirement is fulfilled. When writing unsafe code, this method /// should be called from within a [critical /// section](https://docs.rs/cortex-m/0.7.2/cortex_m/interrupt/fn.free.html). /// /// ## Example /// /// ```ignore /// FRAME = MicrobitFrame::default(); /// FRAME.set(&GreyscaleImage::new(&[ /// [0, 7, 0, 7, 0], /// [7, 0, 7, 0, 7], /// [7, 0, 0, 0, 7], /// [0, 7, 0, 7, 0], /// [0, 0, 7, 0, 0], /// ])); /// /// // only this needs to be in a critical section /// display.show_frame(&FRAME); /// ``` pub fn show_frame(&mut self, frame: &MicrobitFrame) { self.display.set_frame(frame); } } ================================================ FILE: microbit-common/src/display/nonblocking/timer.rs ================================================ //! Implementation of [`DisplayTimer`] for the nRF51 `TIMER`s. //! //! [`DisplayTimer`]: tiny_led_matrix::DisplayTimer use tiny_led_matrix::DisplayTimer; use crate::hal::timer::Instance; /// A TIMER peripheral programmed to manage the display. /// /// `MicrobitDisplayTimer` instances implement the [`DisplayTimer`] trait. /// /// The timer is set to 16-bit mode. /// /// For micro:bit v1: uses a 62.5kHz clock clock (16 µs ticks). /// The primary cycle takes 6ms. /// /// For micro:bit v2: uses a 135kHz clock (8 µs ticks). /// The primary cycle takes 3ms. /// /// Uses CC0 for the primary cycle and CC1 for the secondary alarm. Uses the /// CC0_CLEAR shortcut to implement the primary cycle. /// /// [`DisplayTimer`]: tiny_led_matrix::DisplayTimer pub struct MicrobitDisplayTimer(T); impl MicrobitDisplayTimer { /// Returns a new `MicrobitDisplayTimer` wrapping the passed TIMER. /// /// Takes ownership of the TIMER peripheral. pub fn new(timer: T) -> MicrobitDisplayTimer { MicrobitDisplayTimer(timer) } /// Gives the underlying `nrf51::TIMER`*n* instance back. pub fn free(self) -> T { self.0 } } impl DisplayTimer for MicrobitDisplayTimer { fn initialise_cycle(&mut self, ticks: u16) { let timer0 = self.0.as_timer0(); // stop and reset timer timer0.tasks_stop.write(|w| unsafe { w.bits(1) }); timer0.tasks_clear.write(|w| unsafe { w.bits(1) }); // set as 16 bits timer0.bitmode.write(|w| w.bitmode()._16bit()); #[cfg(feature = "v1")] // set frequency to 62500Hz let prescaler = 8; #[cfg(feature = "v2")] // set frequency to 135000Hz let prescaler = 7; timer0.prescaler.write(|w| unsafe { w.bits(prescaler) }); // set compare register timer0.cc[0].write(|w| unsafe { w.bits(ticks.into()) }); // enable auto clear timer0.shorts.write(|w| w.compare0_clear().enabled()); // enable compare interrupt timer0.intenset.write(|w| w.compare0().set()); // start timer0.tasks_start.write(|w| unsafe { w.bits(1) }); // maybe? // timer0.tasks_start.write(|w| w.tasks_start().set_bit()); } fn enable_secondary(&mut self) { self.0.as_timer0().intenset.write(|w| w.compare1().set()); } fn disable_secondary(&mut self) { self.0 .as_timer0() .intenclr .write(|w| w.compare1().set_bit()); } fn program_secondary(&mut self, ticks: u16) { #[cfg(feature = "v1")] self.0.as_timer0().cc[1].write(|w| unsafe { w.bits(ticks.into()) }); #[cfg(feature = "v2")] self.0.as_timer0().cc[1].write(|w| unsafe { w.cc().bits(ticks.into()) }); } fn check_primary(&mut self) -> bool { // poll compare event let reg = &self.0.as_timer0().events_compare[0]; let fired = reg.read().bits() != 0; if fired { reg.reset(); } fired } fn check_secondary(&mut self) -> bool { // poll compare event let reg = &self.0.as_timer0().events_compare[1]; let fired = reg.read().bits() != 0; if fired { reg.reset(); } fired } } ================================================ FILE: microbit-common/src/gpio.rs ================================================ //! Named GPIO pin types //! //! This module maps the GPIO pin names as described in the //! [Pins and Signals section of the micro:bit site](https://tech.microbit.org/hardware/edgeconnector/#pins-and-signals) //! Where appropriate the pins are restricted with the appropriate `MODE` //! from `nrf-hal`. #[cfg(feature = "v1")] pub use crate::v1::gpio::*; #[cfg(feature = "v2")] pub use crate::v2::gpio::*; ================================================ FILE: microbit-common/src/lib.rs ================================================ //! microbit contains everything required to get started with the use of Rust //! to create firmwares for the fabulous [BBC micro:bit](https://microbit.org) //! microcontroller board. #![doc(html_root_url = "https://docs.rs/microbit-common/0.16.0")] #![no_std] #![deny(missing_docs)] #![allow(non_camel_case_types)] #[cfg(all(feature = "v1", feature = "v2"))] compile_error!("canot build for microbit v1 and v2 at the same time"); #[cfg(feature = "v1")] pub use nrf51_hal as hal; #[cfg(feature = "v2")] pub use nrf52833_hal as hal; pub use hal::pac; pub use hal::pac::Peripherals; pub mod adc; pub mod board; pub mod display; pub mod gpio; pub use board::Board; #[cfg(feature = "v1")] mod v1; #[cfg(feature = "v2")] mod v2; ================================================ FILE: microbit-common/src/v1/adc.rs ================================================ use crate::hal; /// Adc alias to unify v1 and v2 names pub type Adc = hal::Adc; /// AdcConfig alias to unify v1 and v2 names pub type AdcConfig = hal::adc::AdcConfig; /// Same resolution for v1 and v2 pub trait Default { /// v1 is limited to 10 bit fn default_10bit() -> Self; } impl Default for AdcConfig { fn default_10bit() -> Self { AdcConfig::default() } } ================================================ FILE: microbit-common/src/v1/board.rs ================================================ use super::gpio::{ DisplayPins, BTN_A, BTN_B, EDGE00, EDGE01, EDGE02, EDGE08, EDGE12, EDGE16, SCL, SDA, UART_RX, UART_TX, }; use crate::{ hal::{ gpio::{p0, Disconnected, Level}, twi, uart, }, pac, }; /// Provides access to the microbit #[allow(non_snake_case)] pub struct Board { /// GPIO pins that are not otherwise used pub pins: Pins, /// Unused GPIO pins on edge connector pub edge: Edge, /// display pins pub display_pins: DisplayPins, /// buttons pub buttons: Buttons, /// I2C shared internal and external bus pins pub i2c: I2CPins, /// UART to debugger pins pub uart: UartPins, /// Core peripheral: Cache and branch predictor maintenance operations pub CBP: pac::CBP, /// Core peripheral: CPUID pub CPUID: pac::CPUID, /// Core peripheral: Debug Control Block pub DCB: pac::DCB, /// Core peripheral: Data Watchpoint and Trace unit pub DWT: pac::DWT, /// Core peripheral: Flash Patch and Breakpoint unit pub FPB: pac::FPB, /// Core peripheral: Instrumentation Trace Macrocell pub ITM: pac::ITM, /// Core peripheral: Memory Protection Unit pub MPU: pac::MPU, /// Core peripheral: Nested Vector Interrupt Controller pub NVIC: pac::NVIC, /// Core peripheral: System Control Block pub SCB: pac::SCB, /// Core peripheral: SysTick Timer pub SYST: pac::SYST, /// Core peripheral: Trace Port Interface Unit pub TPIU: pac::TPIU, /// nRF51 peripheral: ADC pub ADC: pac::ADC, /// nRF51 peripheral: CLOCK pub CLOCK: pac::CLOCK, /// nRF51 peripheral: FICR pub FICR: pac::FICR, /// nRF51 peripheral: GPIOTE pub GPIOTE: pac::GPIOTE, /// nRF51 preipheral: PPI pub PPI: pac::PPI, /// nRF51 peripheral: RADIO pub RADIO: pac::RADIO, /// nRF51 peripheral: RNG pub RNG: pac::RNG, /// nRF51 peripheral: RTC0 pub RTC0: pac::RTC0, /// nRF51 peripheral: TEMP
/// Can be used with [`Temp::new()`](`crate::hal::temp::Temp::new()`) pub TEMP: pac::TEMP, /// nRF51 peripheral: TIMER0 pub TIMER0: pac::TIMER0, /// nRF51 peripheral: TIMER1 pub TIMER1: pac::TIMER1, /// nRF51 peripheral: TIMER2 pub TIMER2: pac::TIMER2, /// nRF51 peripheral: TWI0 pub TWI0: pac::TWI0, /// nrf51 peripheral: UART0 pub UART0: pac::UART0, /// nrf51 peripheral: POWER pub POWER: pac::POWER, /// nrf51 peripheral: SPI0 pub SPI0: pac::SPI0, /// nrf51 peripheral: SPI1 pub SPI1: pac::SPI1, /// nrf51 peripheral: TWI1 pub TWI1: pac::TWI1, /// nrf51 peripheral: SPIS1 pub SPIS1: pac::SPIS1, /// nrf51 peripheral: ECB pub ECB: pac::ECB, /// nrf51 peripheral: AAR pub AAR: pac::AAR, /// nrf51 peripheral: CCM pub CCM: pac::CCM, /// nrf51 peripheral: WDT pub WDT: pac::WDT, /// nrf51 peripheral: RTC1 pub RTC1: pac::RTC1, /// nrf51 peripheral: QDEC pub QDEC: pac::QDEC, /// nrf51 peripheral: LPCOMP pub LPCOMP: pac::LPCOMP, /// nrf51 peripheral: SWI pub SWI: pac::SWI, /// nrf51 peripheral: NVMC pub NVMC: pac::NVMC, /// nrf51 peripheral: UICR pub UICR: pac::UICR, } impl Board { /// Take the peripherals safely /// /// This method will return an instance of the board the first time it is /// called. It will return only `None` on subsequent calls. /// This function can also return `None` if one of the the peripherals was /// already taken. pub fn take() -> Option { Some(Self::new( pac::Peripherals::take()?, pac::CorePeripherals::take()?, )) } /// Fallback method in the case peripherals and core peripherals were taken /// elsewhere already. /// /// This method will take the peripherals and core peripherals and /// return an instance of the board. /// /// An exemplary usecase is shown in the rtic display example. pub fn new(p: pac::Peripherals, cp: pac::CorePeripherals) -> Self { let p0parts = p0::Parts::new(p.GPIO); Self { pins: Pins { //p0_01: p0parts.p0_01, //p0_02: p0parts.p0_02, //p0_03: p0parts.p0_03, //p0_16: p0parts.p0_16, //p0_18: p0parts.p0_18, p0_19: p0parts.p0_19, //p0_20: p0parts.p0_20, p0_21: p0parts.p0_21, p0_22: p0parts.p0_22, p0_23: p0parts.p0_23, p0_27: p0parts.p0_27, p0_28: p0parts.p0_28, p0_29: p0parts.p0_29, }, edge: Edge { e00: p0parts.p0_03, e01: p0parts.p0_02, e02: p0parts.p0_01, e08: p0parts.p0_18, e12: p0parts.p0_20, e16: p0parts.p0_16, }, display_pins: DisplayPins { row1: p0parts.p0_13.into_push_pull_output(Level::Low), row2: p0parts.p0_14.into_push_pull_output(Level::Low), row3: p0parts.p0_15.into_push_pull_output(Level::Low), col1: p0parts.p0_04.into_push_pull_output(Level::High), col2: p0parts.p0_05.into_push_pull_output(Level::High), col3: p0parts.p0_06.into_push_pull_output(Level::High), col4: p0parts.p0_07.into_push_pull_output(Level::High), col5: p0parts.p0_08.into_push_pull_output(Level::High), col6: p0parts.p0_09.into_push_pull_output(Level::High), col7: p0parts.p0_10.into_push_pull_output(Level::High), col8: p0parts.p0_11.into_push_pull_output(Level::High), col9: p0parts.p0_12.into_push_pull_output(Level::High), }, buttons: Buttons { button_a: p0parts.p0_17.into_floating_input(), button_b: p0parts.p0_26.into_floating_input(), }, i2c: I2CPins { scl: p0parts.p0_00.into_floating_input(), sda: p0parts.p0_30.into_floating_input(), }, uart: UartPins { tx: p0parts.p0_24.into_push_pull_output(Level::Low), rx: p0parts.p0_25.into_floating_input(), }, // Core peripherals CBP: cp.CBP, CPUID: cp.CPUID, DCB: cp.DCB, DWT: cp.DWT, FPB: cp.FPB, ITM: cp.ITM, MPU: cp.MPU, NVIC: cp.NVIC, SCB: cp.SCB, SYST: cp.SYST, TPIU: cp.TPIU, // nRF51 peripherals ADC: p.ADC, CLOCK: p.CLOCK, FICR: p.FICR, GPIOTE: p.GPIOTE, PPI: p.PPI, RADIO: p.RADIO, RNG: p.RNG, RTC0: p.RTC0, TEMP: p.TEMP, TIMER0: p.TIMER0, TIMER1: p.TIMER1, TIMER2: p.TIMER2, TWI0: p.TWI0, UART0: p.UART0, POWER: p.POWER, SPI0: p.SPI0, SPI1: p.SPI1, TWI1: p.TWI1, SPIS1: p.SPIS1, ECB: p.ECB, AAR: p.AAR, CCM: p.CCM, WDT: p.WDT, RTC1: p.RTC1, QDEC: p.QDEC, LPCOMP: p.LPCOMP, SWI: p.SWI, NVMC: p.NVMC, UICR: p.UICR, } } } /// Unused GPIO pins #[allow(missing_docs)] pub struct Pins { // pub p0_00: p0::P0_00, // SCL // pub p0_01: p0::P0_01, // PAD2, EDGE02 // pub p0_02: p0::P0_02, // PAD1, EDGE01 // pub p0_03: p0::P0_03, // PAD0, EDGE00 // pub p0_04: p0::P0_04, // LEDs // pub p0_05: p0::P0_05, // LEDs // pub p0_06: p0::P0_06, // LEDs // pub p0_07: p0::P0_07, // LEDs // pub p0_08: p0::P0_08, // LEDs // pub p0_09: p0::P0_09, // LEDs // pub p0_10: p0::P0_10, // LEDs // pub p0_11: p0::P0_11, // LEDs // pub p0_12: p0::P0_12, // LEDs // pub p0_13: p0::P0_13, // LEDs // pub p0_14: p0::P0_14, // LEDs // pub p0_15: p0::P0_15, // LEDs // pub p0_16: p0::P0_16, // EDGE16 // pub p0_17: p0::P0_17, // BTN_A // pub p0_18: p0::P0_18, // EDGE08 pub p0_19: p0::P0_19, // pub p0_20: p0::P0_20, // EDGE12 pub p0_21: p0::P0_21, pub p0_22: p0::P0_22, pub p0_23: p0::P0_23, // pub p0_24: p0::P0_24, // UART TX // pub p0_25: p0::P0_25, // UART RX // pub p0_26: p0::P0_26, // BTN_B pub p0_27: p0::P0_27, pub p0_28: p0::P0_28, pub p0_29: p0::P0_29, // pub p0_30: p0::P0_30, // SDA } /// Unused edge connector pins #[allow(missing_docs)] pub struct Edge { // pub e03: COL1, pub e00: EDGE00, // <- big pad 1 // pub e04: COL2, // pub e05: BTN_A, // pub e06: COL9, // pub e07: COL8, pub e01: EDGE01, // <- big pad 2 pub e08: EDGE08, // pub e09: COL7, // pub e10: COL3, // pub e11: BTN_B, pub e12: EDGE12, pub e02: EDGE02, // <- big pad 3 //pub e13: SCK, //pub e14: MISO, //pub e15: MOSI, pub e16: EDGE16, // +V // +V // +V // pub e19: SCL, // pub e20: SDA, // GND // GND // GND } /// Board buttons pub struct Buttons { /// Left hand side button pub button_a: BTN_A, /// Right hand side button pub button_b: BTN_B, } /// I2C shared internal and external bus pins pub struct I2CPins { /// I2C control pin pub scl: SCL, /// I2C data pin pub sda: SDA, } impl From for twi::Pins { fn from(pins: I2CPins) -> Self { Self { scl: pins.scl.degrade(), sda: pins.sda.degrade(), } } } /// UART to debugger pins pub struct UartPins { tx: UART_TX, rx: UART_RX, } impl From for uart::Pins { fn from(pins: UartPins) -> Self { Self { rxd: pins.rx.degrade(), txd: pins.tx.degrade(), cts: None, rts: None, } } } ================================================ FILE: microbit-common/src/v1/gpio.rs ================================================ //! Named GPIO pin types //! //! This module maps the GPIO pin names as described in the //! [Pins and Signals section of the micro:bit site](https://tech.microbit.org/hardware/edgeconnector/#pins-and-signals) //! Where appropriate the pins are restricted with the appropriate `MODE` //! from `nrf-hal`. #![allow(clippy::upper_case_acronyms, missing_docs)] use crate::hal::gpio::{p0, Floating, Input, Output, Pin, PushPull}; /* GPIO pads */ pub type PAD0 = p0::P0_03; pub type PAD1 = p0::P0_02; pub type PAD2 = p0::P0_01; /* LED display */ pub const NUM_COLS: usize = 9; pub type COL1 = p0::P0_04>; pub type COL2 = p0::P0_05>; pub type COL3 = p0::P0_06>; pub type COL4 = p0::P0_07>; pub type COL5 = p0::P0_08>; pub type COL6 = p0::P0_09>; pub type COL7 = p0::P0_10>; pub type COL8 = p0::P0_11>; pub type COL9 = p0::P0_12>; pub const NUM_ROWS: usize = 3; pub type ROW1 = p0::P0_13>; pub type ROW2 = p0::P0_14>; pub type ROW3 = p0::P0_15>; /// GPIO pins connected to the LED matrix /// /// The pins are represented as a [3x9 matrix on the micro:bit /// V1](https://tech.microbit.org/hardware/1-5-revision/#display). /// This is mapped to the physical 5x5 LED matrix in the [crate::display] /// modules. /// /// Use the [display_pins] macro for easier construction. pub struct DisplayPins { pub col1: COL1, pub col2: COL2, pub col3: COL3, pub col4: COL4, pub col5: COL5, pub col6: COL6, pub col7: COL7, pub col8: COL8, pub col9: COL9, pub row1: ROW1, pub row2: ROW2, pub row3: ROW3, } type LED = Pin>; impl DisplayPins { pub fn degrade(self) -> ([LED; NUM_COLS], [LED; NUM_ROWS]) { ( [ self.col1.degrade(), self.col2.degrade(), self.col3.degrade(), self.col4.degrade(), self.col5.degrade(), self.col6.degrade(), self.col7.degrade(), self.col8.degrade(), self.col9.degrade(), ], [ self.row1.degrade(), self.row2.degrade(), self.row3.degrade(), ], ) } } /// Create [DisplayPins] from a [GPIO Parts](crate::hal::gpio::p0::Parts) /// /// # Example /// /// ```no_run /// # use microbit_common as microbit; /// use microbit::{ /// display_pins, /// pac, /// hal::gpio::p0::Parts as P0Parts, /// }; /// /// // take the peripherals /// let p = pac::Peripherals::take().unwrap(); /// // split off the P0 GPIO port /// let p0parts = P0Parts::new(p.GPIO); /// /// let pins = display_pins!(p0parts); /// ``` #[macro_export] macro_rules! display_pins { ( $p0parts:expr ) => {{ use microbit::{gpio::DisplayPins, hal::gpio::Level}; DisplayPins { row1: $p0parts.p0_13.into_push_pull_output(Level::Low), row2: $p0parts.p0_14.into_push_pull_output(Level::Low), row3: $p0parts.p0_15.into_push_pull_output(Level::Low), col1: $p0parts.p0_04.into_push_pull_output(Level::Low), col2: $p0parts.p0_05.into_push_pull_output(Level::Low), col3: $p0parts.p0_06.into_push_pull_output(Level::Low), col4: $p0parts.p0_07.into_push_pull_output(Level::Low), col5: $p0parts.p0_08.into_push_pull_output(Level::Low), col6: $p0parts.p0_09.into_push_pull_output(Level::Low), col7: $p0parts.p0_10.into_push_pull_output(Level::Low), col8: $p0parts.p0_11.into_push_pull_output(Level::Low), col9: $p0parts.p0_12.into_push_pull_output(Level::Low), } }}; } /* buttons */ pub type BTN_A = p0::P0_17>; pub type BTN_B = p0::P0_26>; /* spi */ pub type MOSI = p0::P0_21; pub type MISO = p0::P0_22; pub type SCK = p0::P0_23; /* i2c - shared external and internal */ pub type SCL = p0::P0_00>; pub type SDA = p0::P0_30>; /* uart */ pub type UART_TX = p0::P0_24>; pub type UART_RX = p0::P0_25>; /* edge connector */ pub type EDGE03 = COL1; pub type EDGE00 = PAD0; // <- big pad 1 pub type EDGE04 = COL2; pub type EDGE05 = BTN_A; pub type EDGE06 = COL9; pub type EDGE07 = COL8; pub type EDGE01 = PAD1; // <- big pad 2 pub type EDGE08 = p0::P0_18; pub type EDGE09 = COL7; pub type EDGE10 = COL3; pub type EDGE11 = BTN_B; pub type EDGE12 = p0::P0_20; pub type EDGE02 = PAD2; // <- big pad 3 pub type EDGE13 = SCK; pub type EDGE14 = MISO; pub type EDGE15 = MOSI; pub type EDGE16 = p0::P0_16; // EDGE18 -> +V // EDGE19 -> +V // EDGE20 -> +V pub type EDGE19 = SCL; pub type EDGE20 = SDA; // EDGE23 -> GND // EDGE24 -> GND // EDGE25 -> GND ================================================ FILE: microbit-common/src/v1/mod.rs ================================================ pub mod adc; pub mod board; pub mod gpio; ================================================ FILE: microbit-common/src/v2/adc.rs ================================================ use crate::hal; /// Adc alias to unify v1 and v2 names pub type Adc = hal::Saadc; /// AdcConfig alias to unify v1 and v2 names pub type AdcConfig = hal::saadc::SaadcConfig; /// Same resolution for v1 and v2 pub trait Default { /// v1 is limited to 10 bit fn default_10bit() -> Self; } impl Default for AdcConfig { fn default_10bit() -> Self { AdcConfig { resolution: hal::saadc::Resolution::_10BIT, ..AdcConfig::default() } } } ================================================ FILE: microbit-common/src/v2/board.rs ================================================ use super::gpio::{ DisplayPins, MicrophonePins, BTN_A, BTN_B, EDGE00, EDGE01, EDGE02, EDGE08, EDGE09, EDGE12, EDGE16, INT_SCL, INT_SDA, SCL, SDA, UART_RX, UART_TX, }; use crate::{ hal::{ gpio::{p0, p1, Disconnected, Level, OpenDrainConfig::Disconnect0HighDrive1}, twim, twis, uarte, }, pac, }; /// Provides access to the microbit #[allow(non_snake_case)] pub struct Board { /// GPIO pins that are not otherwise used pub pins: Pins, /// Unused GPIO pins on edge connector pub edge: Edge, /// display pins pub display_pins: DisplayPins, /// buttons pub buttons: Buttons, /// speaker pub speaker_pin: p0::P0_00, /// microphone pins pub microphone_pins: MicrophonePins, /// I2C internal bus pins pub i2c_internal: I2CInternalPins, /// I2C external bus pins pub i2c_external: I2CExternalPins, /// UART to debugger pins pub uart: UartPins, /// Core peripheral: Cache and branch predictor maintenance operations pub CBP: pac::CBP, /// Core peripheral: CPUID pub CPUID: pac::CPUID, /// Core peripheral: Debug Control Block pub DCB: pac::DCB, /// Core peripheral: Data Watchpoint and Trace unit pub DWT: pac::DWT, /// Core peripheral: Flash Patch and Breakpoint unit pub FPB: pac::FPB, /// Core peripheral: Floating Point Unit pub FPU: pac::FPU, /// Core peripheral: Instrumentation Trace Macrocell pub ITM: pac::ITM, /// Core peripheral: Memory Protection Unit pub MPU: pac::MPU, /// Core peripheral: Nested Vector Interrupt Controller pub NVIC: pac::NVIC, /// Core peripheral: System Control Block pub SCB: pac::SCB, /// Core peripheral: SysTick Timer pub SYST: pac::SYST, /// Core peripheral: Trace Port Interface Unit pub TPIU: pac::TPIU, /// nRF52 peripheral: CLOCK pub CLOCK: pac::CLOCK, /// nRF52 peripheral: FICR pub FICR: pac::FICR, /// nRF52 peripheral: GPIOTE pub GPIOTE: pac::GPIOTE, /// nRF52 preipheral: PPI pub PPI: pac::PPI, /// nRF52 peripheral: PWM0 pub PWM0: pac::PWM0, /// nRF52 peripheral: PWM1 pub PWM1: pac::PWM1, /// nRF52 peripheral: PWM2 pub PWM2: pac::PWM2, /// nRF52 peripheral: PWM3 pub PWM3: pac::PWM3, /// nRF52 peripheral: RADIO pub RADIO: pac::RADIO, /// nRF52 peripheral: RNG pub RNG: pac::RNG, /// nRF52 peripheral: RTC0 pub RTC0: pac::RTC0, /// nRF52 peripheral: RTC1 pub RTC1: pac::RTC1, /// nRF52 peripheral: RTC2 pub RTC2: pac::RTC2, /// nRF52 peripheral: SPIM0 pub SPIM0: pac::SPIM0, /// nRF52 peripheral: SPIM1 pub SPIM1: pac::SPIM1, /// nRF52 peripheral: SPIM2 pub SPIM2: pac::SPIM2, /// nRF52 peripheral: SPIM3 pub SPIM3: pac::SPIM3, /// nRF52 peripheral: TEMP
/// Can be used with [`Temp::new()`](`crate::hal::temp::Temp::new()`) pub TEMP: pac::TEMP, /// nRF52 peripheral: TIMER0 pub TIMER0: pac::TIMER0, /// nRF52 peripheral: TIMER1 pub TIMER1: pac::TIMER1, /// nRF52 peripheral: TIMER2 pub TIMER2: pac::TIMER2, /// nRF52 peripheral: TIMER3 pub TIMER3: pac::TIMER3, /// nRF52 peripheral: TIMER4 pub TIMER4: pac::TIMER4, /// nRF52 peripheral: TWIM0 pub TWIM0: pac::TWIM0, /// nRF52 peripheral: TWIS0 pub TWIS0: pac::TWIS0, /// nRF52 peripheral: UARTE0 pub UARTE0: pac::UARTE0, /// nRF52 peripheral: UARTE1 pub UARTE1: pac::UARTE1, /// nRF52 peripheral: SAADC pub ADC: pac::SAADC, /// nRF52 peripheral: POWER pub POWER: pac::POWER, /// nRF52 peripheral: SPI0 pub SPI0: pac::SPI0, /// nRF52 peripheral: SPI1 pub SPI1: pac::SPI1, /// nRF52 peripheral: SPI2 pub SPI2: pac::SPI2, /// nRF52 peripheral: UART0 pub UART0: pac::UART0, /// nRF52 peripheral: TWI0 pub TWI0: pac::TWI0, /// nRF52 peripheral: TWI1 pub TWI1: pac::TWI1, /// nRF52 peripheral: SPIS1 pub SPIS1: pac::SPIS1, /// nRF52 peripheral: ECB pub ECB: pac::ECB, /// nRF52 peripheral: AAR pub AAR: pac::AAR, /// nRF52 peripheral: CCM pub CCM: pac::CCM, /// nRF52 peripheral: WDT pub WDT: pac::WDT, /// nRF52 peripheral: QDEC pub QDEC: pac::QDEC, /// nRF52 peripheral: LPCOMP pub LPCOMP: pac::LPCOMP, /// nRF52 peripheral: NVMC pub NVMC: pac::NVMC, /// nRF52 peripheral: UICR pub UICR: pac::UICR, } impl Board { /// Take the peripherals safely /// /// This method will return an instance of the board the first time it is /// called. It will return only `None` on subsequent calls. /// This function can also return `None` if one of the the peripherals was /// already taken. pub fn take() -> Option { Some(Self::new( pac::Peripherals::take()?, pac::CorePeripherals::take()?, )) } /// Fallback method in the case peripherals and core peripherals were taken /// elsewhere already. /// /// This method will take the peripherals and core peripherals and /// return an instance of the board. /// /// An exemplary usecase is shown in the rtic display example. pub fn new(p: pac::Peripherals, cp: pac::CorePeripherals) -> Self { let p0parts = p0::Parts::new(p.P0); let p1parts = p1::Parts::new(p.P1); Self { pins: Pins { p0_01: p0parts.p0_01, //p0_02: p0parts.p0_02, //p0_03: p0parts.p0_03, //p0_04: p0parts.p0_04, p0_07: p0parts.p0_07, //p0_09: p0parts.p0_09, //p0_10: p0parts.p0_10, //p0_12: p0parts.p0_12, p0_13: p0parts.p0_13, p0_17: p0parts.p0_17, p0_18: p0parts.p0_18, p0_25: p0parts.p0_25, p0_27: p0parts.p0_27, p0_29: p0parts.p0_29, p1_01: p1parts.p1_01, //p1_02: p1parts.p1_02, p1_03: p1parts.p1_03, p1_04: p1parts.p1_04, p1_06: p1parts.p1_06, p1_07: p1parts.p1_07, p1_09: p1parts.p1_09, }, edge: Edge { e00: p0parts.p0_02, e01: p0parts.p0_03, e02: p0parts.p0_04, e08: p0parts.p0_10, e09: p0parts.p0_09, e12: p0parts.p0_12, e16: p1parts.p1_02, }, display_pins: DisplayPins { col1: p0parts.p0_28.into_push_pull_output(Level::High), col2: p0parts.p0_11.into_push_pull_output(Level::High), col3: p0parts.p0_31.into_push_pull_output(Level::High), col4: p1parts.p1_05.into_push_pull_output(Level::High), col5: p0parts.p0_30.into_push_pull_output(Level::High), row1: p0parts.p0_21.into_push_pull_output(Level::Low), row2: p0parts.p0_22.into_push_pull_output(Level::Low), row3: p0parts.p0_15.into_push_pull_output(Level::Low), row4: p0parts.p0_24.into_push_pull_output(Level::Low), row5: p0parts.p0_19.into_push_pull_output(Level::Low), }, buttons: Buttons { button_a: p0parts.p0_14.into_floating_input(), button_b: p0parts.p0_23.into_floating_input(), }, speaker_pin: p0parts.p0_00, microphone_pins: MicrophonePins { mic_in: p0parts.p0_05.into_floating_input(), mic_run: p0parts .p0_20 .into_open_drain_output(Disconnect0HighDrive1, Level::Low), }, i2c_internal: I2CInternalPins { scl: p0parts.p0_08.into_floating_input(), sda: p0parts.p0_16.into_floating_input(), }, i2c_external: I2CExternalPins { scl: p0parts.p0_26.into_floating_input(), sda: p1parts.p1_00.into_floating_input(), }, uart: UartPins { tx: p0parts.p0_06.into_push_pull_output(Level::High), rx: p1parts.p1_08.into_floating_input(), }, // Core peripherals CBP: cp.CBP, CPUID: cp.CPUID, DCB: cp.DCB, DWT: cp.DWT, FPB: cp.FPB, FPU: cp.FPU, ITM: cp.ITM, MPU: cp.MPU, NVIC: cp.NVIC, SCB: cp.SCB, SYST: cp.SYST, TPIU: cp.TPIU, // nRF52 peripherals CLOCK: p.CLOCK, FICR: p.FICR, GPIOTE: p.GPIOTE, PPI: p.PPI, PWM0: p.PWM0, PWM1: p.PWM1, PWM2: p.PWM2, PWM3: p.PWM3, RADIO: p.RADIO, RNG: p.RNG, RTC0: p.RTC0, RTC1: p.RTC1, RTC2: p.RTC2, SPIM0: p.SPIM0, SPIM1: p.SPIM1, SPIM2: p.SPIM2, SPIM3: p.SPIM3, TEMP: p.TEMP, TIMER0: p.TIMER0, TIMER1: p.TIMER1, TIMER2: p.TIMER2, TIMER3: p.TIMER3, TIMER4: p.TIMER4, TWIM0: p.TWIM0, TWIS0: p.TWIS0, UARTE0: p.UARTE0, UARTE1: p.UARTE1, ADC: p.SAADC, SPI0: p.SPI0, SPI1: p.SPI1, SPI2: p.SPI2, POWER: p.POWER, UART0: p.UART0, TWI0: p.TWI0, TWI1: p.TWI1, SPIS1: p.SPIS1, ECB: p.ECB, AAR: p.AAR, CCM: p.CCM, WDT: p.WDT, QDEC: p.QDEC, LPCOMP: p.LPCOMP, NVMC: p.NVMC, UICR: p.UICR, } } } /// Unused GPIO pins #[allow(missing_docs)] pub struct Pins { // pub p0_00: p0::P0_00, // Speaker pub p0_01: p0::P0_01, // pub p0_02: p0::P0_02, // PAD0, EDGE00 // pub p0_03: p0::P0_03, // PAD1, EDGE01 // pub p0_04: p0::P0_04, // PAD2, EDGE02 // pub p0_05: p0::P0_05, // Microphone IN // pub p0_06: p0::P0_06, // UART RX pub p0_07: p0::P0_07, // pub p0_08: p0::P0_08, // INT_SCL // pub p0_09: p0::P0_09, // EDGE09 // pub p0_10: p0::P0_10, // EDGE08 // pub p0_11: p0::P0_11, // LEDs // pub p0_12: p0::P0_12, // EDGE12 pub p0_13: p0::P0_13, // pub p0_14: p0::P0_14, // BTN_A // pub p0_15: p0::P0_15, // LEDs // pub p0_16: p0::P0_16, // INT_SDA pub p0_17: p0::P0_17, pub p0_18: p0::P0_18, // pub p0_19: p0::P0_19, // LEDs // pub p0_20: p0::P0_20, // Microphone RUN // pub p0_21: p0::P0_21, // LEDs // pub p0_22: p0::P0_22, // LEDs // pub p0_23: p0::P0_23, // BTN_B // pub p0_24: p0::P0_24, // LEDs pub p0_25: p0::P0_25, // pub p0_26: p0::P0_26, // SCL pub p0_27: p0::P0_27, // pub p0_28: p0::P0_28, // LEDs pub p0_29: p0::P0_29, // pub p0_30: p0::P0_30, // LEDs // pub p0_31: p0::P0_31, // LEDs // pub p1_00: p1::P1_00, // SDA pub p1_01: p1::P1_01, // pub p1_02: p1::P1_02, // EDGE16 pub p1_03: p1::P1_03, pub p1_04: p1::P1_04, // pub p1_05: p1::P1_05, // LEDs pub p1_06: p1::P1_06, pub p1_07: p1::P1_07, // pub p1_08: p1::P1_08, // UART TX pub p1_09: p1::P1_09, } /// Unused edge connector pins #[allow(missing_docs)] pub struct Edge { /* edge connector */ // pub e03: COL3, pub e00: EDGE00, // <- big pad 1 // pub e04: COL1, // pub e05: BTN_A, // pub e06: COL4, // pub e07: COL2, pub e01: EDGE01, // <- big pad 2 pub e08: EDGE08, pub e09: EDGE09, // pub e10: COL5, // pub e11: BTN_B, pub e12: EDGE12, pub e02: EDGE02, // <- big pad 3 //pub e13: SCK, //pub e14: MISO, //pub e15: MOSI, pub e16: EDGE16, // +V // +V // +V // pub e19: SCL, // pub e20: SDA, // GND // GND // GND } /// Buttons pub struct Buttons { /// Left hand button pub button_a: BTN_A, /// Right hand button pub button_b: BTN_B, } /// I2C internal bus pins pub struct I2CInternalPins { /// Internal I2C clock pin pub scl: INT_SCL, /// Internal I2C data pin pub sda: INT_SDA, } impl From for twim::Pins { fn from(pins: I2CInternalPins) -> Self { Self { scl: pins.scl.degrade(), sda: pins.sda.degrade(), } } } impl From for twis::Pins { fn from(pins: I2CInternalPins) -> Self { Self { scl: pins.scl.degrade(), sda: pins.sda.degrade(), } } } /// I2C external bus pins pub struct I2CExternalPins { /// External I2C clock pin pub scl: SCL, /// External I2C data pin pub sda: SDA, } impl From for twim::Pins { fn from(pins: I2CExternalPins) -> Self { Self { scl: pins.scl.degrade(), sda: pins.sda.degrade(), } } } impl From for twis::Pins { fn from(pins: I2CExternalPins) -> Self { Self { scl: pins.scl.degrade(), sda: pins.sda.degrade(), } } } /// UART to debugger pins pub struct UartPins { tx: UART_TX, rx: UART_RX, } impl From for uarte::Pins { fn from(pins: UartPins) -> Self { Self { txd: pins.tx.degrade(), rxd: pins.rx.degrade(), cts: None, rts: None, } } } ================================================ FILE: microbit-common/src/v2/gpio.rs ================================================ #![allow(clippy::upper_case_acronyms, missing_docs)] use nrf52833_hal::gpio::{p0, p1, Floating, Input, OpenDrain, Output, Pin, PushPull}; /* GPIO pads */ pub type PAD0 = p0::P0_02; pub type PAD1 = p0::P0_03; pub type PAD2 = p0::P0_04; /* LED display */ pub const NUM_COLS: usize = 5; pub type COL1 = p0::P0_28>; pub type COL2 = p0::P0_11>; pub type COL3 = p0::P0_31>; pub type COL4 = p1::P1_05>; pub type COL5 = p0::P0_30>; pub const NUM_ROWS: usize = 5; pub type ROW1 = p0::P0_21>; pub type ROW2 = p0::P0_22>; pub type ROW3 = p0::P0_15>; pub type ROW4 = p0::P0_24>; pub type ROW5 = p0::P0_19>; /// GPIO pins connected to the LED matrix /// /// Use the [display_pins] macro for easier construction. pub struct DisplayPins { pub col1: COL1, pub col2: COL2, pub col3: COL3, pub col4: COL4, pub col5: COL5, pub row1: ROW1, pub row2: ROW2, pub row3: ROW3, pub row4: ROW4, pub row5: ROW5, } /// GPIO pins connected to the microphone pub struct MicrophonePins { pub mic_in: p0::P0_05>, pub mic_run: p0::P0_20>, } type LED = Pin>; impl DisplayPins { pub fn degrade(self) -> ([LED; NUM_COLS], [LED; NUM_ROWS]) { ( [ self.col1.degrade(), self.col2.degrade(), self.col3.degrade(), self.col4.degrade(), self.col5.degrade(), ], [ self.row1.degrade(), self.row2.degrade(), self.row3.degrade(), self.row4.degrade(), self.row5.degrade(), ], ) } } /// Create [DisplayPins] from a [GPIO Parts](crate::hal::gpio::p0::Parts) /// /// # Example /// /// ```no_run /// # use microbit_common as microbit; /// use microbit::{ /// display_pins, /// pac, /// hal::gpio::{p0::Parts as P0Parts, p1::Parts as P1Parts}, /// }; /// /// // take the peripherals /// let p = pac::Peripherals::take().unwrap(); /// // split off the P0 GPIO port /// let p0parts = P0Parts::new(p.P0); /// // split off the P1 GPIO port /// let p1parts = P1Parts::new(p.P1); /// /// let pins = display_pins!(p0parts, p1parts); /// ``` #[macro_export] macro_rules! display_pins { ( $p0parts:expr, $p1parts:expr ) => {{ use microbit::{gpio::DisplayPins, hal::gpio::Level}; DisplayPins { col1: $p0parts.p0_28.into_push_pull_output(Level::Low), col2: $p0parts.p0_11.into_push_pull_output(Level::Low), col3: $p0parts.p0_31.into_push_pull_output(Level::Low), col4: $p1parts.p1_05.into_push_pull_output(Level::Low), col5: $p0parts.p0_30.into_push_pull_output(Level::Low), row1: $p0parts.p0_21.into_push_pull_output(Level::Low), row2: $p0parts.p0_22.into_push_pull_output(Level::Low), row3: $p0parts.p0_15.into_push_pull_output(Level::Low), row4: $p0parts.p0_24.into_push_pull_output(Level::Low), row5: $p0parts.p0_19.into_push_pull_output(Level::Low), } }}; } /* buttons */ pub type BTN_A = p0::P0_14>; pub type BTN_B = p0::P0_23>; /* spi */ pub type MOSI = p0::P0_13; pub type MISO = p0::P0_01; pub type SCK = p0::P0_17; /* i2c - internal */ pub type INT_SCL = p0::P0_08>; pub type INT_SDA = p0::P0_16>; /* i2c - external */ pub type SCL = p0::P0_26>; pub type SDA = p1::P1_00>; /* uart */ pub type UART_TX = p0::P0_06>; pub type UART_RX = p1::P1_08>; /* speaker */ pub type SPEAKER = p0::P0_00>; /* edge connector */ pub type EDGE03 = COL3; pub type EDGE00 = PAD0; // <- big pad 1 pub type EDGE04 = COL1; pub type EDGE05 = BTN_A; pub type EDGE06 = COL4; pub type EDGE07 = COL2; pub type EDGE01 = PAD1; // <- big pad 2 pub type EDGE08 = p0::P0_10; pub type EDGE09 = p0::P0_09; pub type EDGE10 = COL5; pub type EDGE11 = BTN_B; pub type EDGE12 = p0::P0_12; pub type EDGE02 = PAD2; // <- big pad 3 pub type EDGE13 = SCK; pub type EDGE14 = MISO; pub type EDGE15 = MOSI; pub type EDGE16 = p1::P1_02; // EDGE18 -> +V // EDGE19 -> +V // EDGE20 -> +V pub type EDGE19 = SCL; pub type EDGE20 = SDA; // EDGE23 -> GND // EDGE24 -> GND // EDGE25 -> GND ================================================ FILE: microbit-common/src/v2/mod.rs ================================================ pub mod adc; pub mod board; pub mod gpio; ================================================ FILE: microbit-v2/Cargo.toml ================================================ [package] name = "microbit-v2" version = "0.16.0" description = "Board support crate for the BBC Micro:bit V2" edition = "2018" readme = "../README.md" rust-version = "1.79.0" repository = "https://github.com/nrf-rs/microbit" authors = [ "Daniel Egger ", "Michael Droogleever ", "Rob Young ", ] categories = ["hardware-support", "embedded", "no-std"] keywords = ["arm", "cortex-m", "nrf", "hal"] license = "0BSD" [lib] name = "microbit" path = "src/lib.rs" [dependencies] [dependencies.microbit-common] path = "../microbit-common" features = ["v2"] version = "=0.16.0" [features] embedded-hal-02 = ["microbit-common/embedded-hal-02"] ================================================ FILE: microbit-v2/src/lib.rs ================================================ //! microbit contains everything required to get started with the use of Rust //! to create firmwares for the fabulous [BBC micro:bit](https://microbit.org) //! microcontroller board. //! //! This crate is for the new micro:bit (V2) pictured below on the right. If //! your micro:bit looks like the one on the left you need the //! [microbit](https://crates.io/crates/microbit) crate. //! //! [](https://github.com/microbit-foundation/microbit-svg/blob/master/microbit-drawing-back-1-5.png) //! [](https://github.com/microbit-foundation/microbit-svg/blob/master/microbit-drawing-back-2.png) #![doc(html_root_url = "https://docs.rs/microbit-v2/0.16.0")] #![no_std] #![deny(missing_docs)] #![allow(non_camel_case_types)] pub use microbit_common::*; ================================================ FILE: tools/capture_example_bloat.sh ================================================ #!/bin/bash filename="bloat_log_"`date -Iminutes`".txt" for i in `find examples -name "*.rs"`; do name=$(echo $i | sed -e "s,examples/,,g" -e "s,\.rs,,g") echo "Processing example $name" echo >>$filename echo "Bloat for example $name" >>$filename cargo bloat --release --example $name >>$filename done echo "Captures bloat for all examples into $filename" ================================================ FILE: xtask/Cargo.toml ================================================ [package] name = "xtask" version = "0.1.0" edition = "2018" [dependencies] cargo_toml = "0.22.3" chrono = "0.4.44" ================================================ FILE: xtask/src/bump.rs ================================================ //! This has been copied pretty much wholesale from https://github.com/nrf-rs/nrf-hal/blob/master/xtask/src/lib.rs use super::CRATES; use chrono::Local; use std::fs; fn file_replace(path: &str, from: &str, to: &str, dry_run: bool) { let old_contents = fs::read_to_string(path).unwrap(); let new_contents = old_contents.replacen(from, to, 1); if old_contents == new_contents { panic!("failed to replace `{}` -> `{}` in `{}`", from, to, path); } if !dry_run { fs::write(path, new_contents).unwrap(); } } /// Bumps the versions of all crates and the changelog to `new_version`. /// /// Dependency declarations are updated automatically. `html_root_url` is updated automatically. pub fn bump_versions(new_version: &str, dry_run: bool) { let common_toml_path = "microbit-common/Cargo.toml"; let toml = fs::read_to_string(common_toml_path).unwrap(); let needle = "version = \""; let version_pos = toml.find(needle).unwrap() + needle.len(); let version_rest = &toml[version_pos..]; let end_pos = version_rest.find('"').unwrap(); let old_version = &version_rest[..end_pos]; { // Bump the changelog first, also check that it isn't empty. let changelog_path = "CHANGELOG.md"; let changelog = fs::read_to_string(changelog_path).unwrap(); // (ignore empty changelog when this is a dry_run, since that runs in normal CI) assert!( dry_run || !changelog.contains("(no changes)"), "changelog contains `(no changes)`; please fill it" ); // Prepend empty "[Unreleased]" section, promote the current one. let today = Local::now().date_naive().format("%Y-%m-%d").to_string(); let from = String::from("## [Unreleased]"); let to = format!( "## [Unreleased]\n\n(no changes)\n\n## [{}] - {}", new_version, today ); file_replace(changelog_path, &from, &to, dry_run); // Replace the Unreleased link let from = format!( r#"[Unreleased]: https://github.com/nrf-rs/microbit/compare/v{old_version}...HEAD"#, old_version = old_version, ); let to = format!( "[Unreleased]: https://github.com/nrf-rs/microbit/compare/v{new_version}...HEAD\n\ [{new_version}]: https://github.com/nrf-rs/microbit/compare/v{old_version}...v{new_version}", new_version = new_version, old_version = old_version, ); file_replace(changelog_path, &from, &to, dry_run); } { println!("microbit-common: {} -> {}", old_version, new_version); // Bump `microbit-common`'s version. let from = format!(r#"version = "{}""#, old_version); let to = format!(r#"version = "{}""#, new_version); file_replace("microbit-common/Cargo.toml", &from, &to, dry_run); // Bump the `html_root_url`. let from = format!( r#"#![doc(html_root_url = "https://docs.rs/microbit-common/{old_version}")]"#, old_version = old_version ); let to = format!( r#"#![doc(html_root_url = "https://docs.rs/microbit-common/{new_version}")]"#, new_version = new_version ); let librs_path = "microbit-common/src/lib.rs"; file_replace(librs_path, &from, &to, dry_run); } for (crate_name, _, _) in CRATES { println!("{}: {} -> {}", crate_name, old_version, new_version); let toml_path = format!("{}/Cargo.toml", crate_name); // Bump the crate's version. let from = format!(r#"version = "{}""#, old_version); let to = format!(r#"version = "{}""#, new_version); file_replace(&toml_path, &from, &to, dry_run); // Bump the crate's dependency on `microbit-common`. let from = format!(r#"version = "={}""#, old_version); let to = format!(r#"version = "={}""#, new_version); file_replace(&toml_path, &from, &to, dry_run); // Bump the crate's `html_root_url`. let from = format!( r#"#![doc(html_root_url = "https://docs.rs/{crate}/{old_version}")]"#, crate = crate_name, old_version = old_version ); let to = format!( r#"#![doc(html_root_url = "https://docs.rs/{crate}/{new_version}")]"#, crate = crate_name, new_version = new_version ); let librs_path = format!("{}/src/lib.rs", crate_name); file_replace(&librs_path, &from, &to, dry_run); } } ================================================ FILE: xtask/src/ci.rs ================================================ use super::CRATES; use std::{collections::HashMap, env, fs, path, process::Command}; pub static DEPENDENCIES: &[&str] = &["flip-link"]; fn install_targets() { let targets = CRATES .iter() .map(|(_, target, _)| *target) .collect::>(); let mut rustup = Command::new("rustup"); rustup.args(&["target", "add"]).args(&targets); let status = rustup .status() .map_err(|e| format!("couldn't execute {:?}: {}", rustup, e)) .unwrap(); assert!( status.success(), "failed to install targets with rustup: {:?}", rustup ); } /// Install global dependencies fn install_dependencies() { for dependency in DEPENDENCIES { let exists = Command::new("which") .arg(dependency) .output() .expect("failed to execute"); if !exists.status.success() { let mut cargo = Command::new("cargo"); cargo.args(&["install", dependency]); let status = cargo .status() .map_err(|e| format!("couldn't execute {:?}: {}", cargo, e)) .unwrap(); assert!(status.success(),); } } } /// Build-test each board support crate fn build_crates() { for (hal, target, _) in CRATES { let mut cargo = Command::new("cargo"); let toml_path = format!("{}/Cargo.toml", hal); let status = cargo .args(&["build", "--manifest-path", &toml_path, "--target", target]) .status() .map_err(|e| format!("could not execute {:?}: {}", cargo, e)) .unwrap(); assert!( status.success(), "command exited with error status: {:?}", cargo ); } } /// Build/Run doc-tests in `microbit-common` for each version. fn build_run_doc_tests() { for (_, _, feature) in CRATES { let mut cargo = Command::new("cargo"); let status = cargo .current_dir("microbit-common") .args(&["test", "--features", feature]) .status() .map_err(|e| format!("could not execute {:?}: {}", cargo, e)) .unwrap(); assert!( status.success(), "command exited with error status: {:?}", cargo ); } } /// Build all examples with the boards they support fn build_examples() { let feature_targets = CRATES .iter() .map(|(_, target, feature)| (feature.to_string(), target.to_string())) .collect::>(); let crate_targets = CRATES .iter() .map(|(name, target, _)| (name.to_string(), target.to_string())) .collect::>(); for example in fs::read_dir("examples").unwrap() { let dir = example.unwrap(); let manifest_path = dir.path().join("Cargo.toml"); // Skip if there is no manifest if !manifest_path.exists() { continue; } let manifest = cargo_toml::Manifest::from_path(&manifest_path).unwrap(); // find features and their targets supported by the example let mut features = manifest .features .keys() .filter_map(|feature| { feature_targets .get(feature) .map(|target| (Some(feature.to_owned()), target.to_owned())) }) .collect::>(); // if there are no features find the target from the dependencies if features.is_empty() { features = manifest .dependencies .keys() .filter_map(|name| { crate_targets .get(name) .map(|target| (None, target.to_owned())) }) .collect::>(); assert_eq!( features.len(), 1, "examples must depend on either microbit or microbit-v2" ); } for (feature, target) in features { build_example(&manifest_path, feature, target); } } } fn build_example(manifest_path: &path::Path, feature: Option, target: String) { let mut cargo = Command::new("cargo"); cargo.args(&[ "build", "--target", &target, "--manifest-path", manifest_path.to_str().unwrap(), ]); if let Some(feature) = feature { cargo.args(&["--features", &feature]); } let status = cargo .status() .map_err(|e| format!("could not execute {:?}: {}", cargo, e)) .unwrap(); assert!( status.success(), "command exited with error status: {:?}", cargo ); } fn start_group(is_ci: bool, name: &str) { if is_ci { println!("::group::{}", name); } } fn end_group(is_ci: bool) { if is_ci { println!("::endgroup::"); } } fn wrap_in_group(is_ci: bool, name: &str, callable: &dyn Fn()) { start_group(is_ci, name); callable(); end_group(is_ci); } pub fn ci() { let is_ci = env::var("CI").map_or(false, |ci| ci == "true"); // move up if we're running from inside xtask if env::current_dir().unwrap().ends_with("xtask") { env::set_current_dir("..").unwrap(); } wrap_in_group(is_ci, "install targets", &install_targets); wrap_in_group(is_ci, "install dependencies", &install_dependencies); wrap_in_group(is_ci, "build crates", &build_crates); wrap_in_group(is_ci, "build examples", &build_examples); wrap_in_group(is_ci, "run doc tests", &build_run_doc_tests); } ================================================ FILE: xtask/src/lib.rs ================================================ mod bump; mod ci; mod publish; pub static CRATES: &[(&str, &str, &str)] = &[ ("microbit", "thumbv6m-none-eabi", "v1"), ("microbit-v2", "thumbv7em-none-eabihf", "v2"), ]; pub use bump::bump_versions; pub use ci::ci; pub use publish::publish; ================================================ FILE: xtask/src/main.rs ================================================ use std::env; use xtask::{bump_versions, ci, publish}; fn main() { let mut args = env::args().skip(1); let subcommand = args.next(); match subcommand.as_deref() { Some("bump") => { let new_version = args.next().expect("missing argument"); bump_versions(&new_version, false); } Some("ci") => ci(), Some("publish") => publish(), _ => { eprintln!("usage: cargo xtask "); eprintln!(); eprintln!("subcommands:"); eprintln!(" ci - run continuous integration checks (build and clippy)"); eprintln!(" bump - bump the crate version and update docs and changelog"); eprintln!(" publish - publish all crates to crates.io"); } } } ================================================ FILE: xtask/src/publish.rs ================================================ use std::process::Command; use crate::CRATES; pub fn publish() { publish_package("microbit-common", "thumbv7em-none-eabihf", Some("v2")); for (name, target, _) in CRATES { publish_package(name, target, None); } } fn publish_package(package: &str, target: &str, feature: Option<&str>) { let mut cargo = Command::new("cargo"); cargo.args(&["publish", "--target", target, "--package", package]); if let Some(feature) = feature { cargo.args(&["--features", feature]); } let status = cargo .status() .map_err(|e| format!("could not execute {:?}: {}", cargo, e)) .unwrap(); assert!( status.success(), "command exited with error status: {:?}", cargo ); }