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) | [](https://docs.rs/microbit) | [](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) | [](https://docs.rs/microbit-v2) | [](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