### Run Example Program from examples/foo.rs Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/05-meet-your-software/README.md Compiles and runs a specific Rust example program located in the `examples/` directory. The `--example` flag specifies which example to run. ```bash cargo embed --example foo # or car go run --example foo ``` -------------------------------- ### Blinky Example for Sipeed Longan Nano (Rust) Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/06-hello-world/portability.md A basic blinky program for the Sipeed Longan Nano board. This example showcases the portability of embedded Rust code, with the core logic remaining consistent across different hardware platforms. It uses an older HAL crate, leading to some setup differences. ```rust use embedded_hal::digital::v2::OutputPin; use panic_halt as _; use stm32f1xx_hal::prelude::* use stm32f1xx_hal::pac; use cortex_m_rt::entry; #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); let mut gpioc = dp.GPIOC.split(); let mut led = gpioc.pc13.into_push_pull_output(); loop { led.set_high().unwrap(); // Delay led.set_low().unwrap(); // Delay } } ``` -------------------------------- ### Verify ARM GCC Installation on Windows Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/03-setup/windows.md This snippet demonstrates how to verify the installation of the ARM GCC toolchain on a Windows system. After installation, the `arm-none-eabi-gcc -v` command should output the installed GCC version. Ensure the toolchain is added to your system's PATH environment variable. ```console $ arm-none-eabi-gcc -v (..) gcc version 5.4.1 20160919 (release) (..) ``` -------------------------------- ### Install cargo-binutils and Verify Version Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/03-setup/README.md Installs the `cargo-binutils` component and verifies its installation by checking its version. This tool provides utilities for inspecting Rust binaries, which is essential for embedded development. ```console $ rustup component add llvm-tools $ cargo install cargo-binutils --vers '^0.3' $ cargo size --version cargo-size 0.3.6 ``` -------------------------------- ### Clone Discovery-MB2 Project Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/05-meet-your-software/README.md This command clones the entire Discovery-MB2 project repository from GitHub. This is the first step to access the book's source code and examples. ```bash git clone http://github.com/rust-embedded/discovery-mb2 ``` -------------------------------- ### Blinky Example using microbit-v2 Crate Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/06-hello-world/board-support-crate.md A basic blinky application demonstrating the use of the `microbit-v2` board support crate. This example leverages the abstractions provided by the BSP to control LEDs without direct interaction with the PAC or HAL. ```rust #[entry] fn main() -> ! { // ... application logic ... loop { // ... blinky logic ... } } ``` -------------------------------- ### Install probe-rs-tools using Cargo Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/03-setup/README.md Installs the `probe-rs-tools` package using Cargo. This command installs a suite of tools for debugging and flashing embedded devices, including `probe-rs` and `cargo-embed`. Note that this method may sometimes fail. ```console $ cargo install --locked probe-rs-tools ``` -------------------------------- ### Install GDB, Minicom, and lsusb on macOS using Homebrew Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/03-setup/macos.md Installs essential command-line tools for embedded development on macOS. GDB is a debugger, Minicom is a serial communication program, and lsusb lists USB devices. These are installed using the Homebrew package manager. ```bash brew install gdb brew install minicom brew install lsusb ``` -------------------------------- ### Set Breakpoints and Continue Execution in GDB Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/05-meet-your-software/debug-it.md Demonstrates setting a breakpoint at the 'main' function and continuing program execution until the breakpoint is hit. This allows you to start debugging from the entry point of your application. ```shell (gdb) break main (gdb) continue ``` -------------------------------- ### Blink LED - Rust Example Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/06-hello-world/toggle-it.md This Rust code snippet demonstrates how to blink an LED on the Discovery-MB2 board. It utilizes the embedded-hal crate for hardware interaction, allowing for portable code across different Rust HAL implementations. The example shows setting and unsetting an LED pin to create a blinking effect. ```rust use embedded_hal::digital::v2::OutputPin; use stm32f4xx_hal::prelude::*; use stm32f4xx_hal::pac; fn main() { let dp = pac::Peripherals::take().unwrap(); let cp = cortex_m::Peripherals::take().unwrap(); let mut rcc = dp.RCC.constrain(); let mut flash = dp.FLASH.constrain(); let mut gpioa = dp.GPIOA.constrain(); let mut gpiob = dp.GPIOB.constrain(); let clocks = rcc.cfgr.freeze(&mut flash.acr, &mut rcc.ahb, &mut rcc.apb1, &mut rcc.apb2); // Assuming LED1 is PA5 and LED2 is PB0 based on common STM32 boards let mut led1 = gpioa.pa5.into_push_pull_output(&mut gpioa.moder, &mut gpioa.otyper); let mut led2 = gpiob.pb0.into_push_pull_output(&mut gpiob.moder, &mut gpiob.otyper); // Turn LED1 on led1.set_high().unwrap(); // This loop would toggle LED2 rapidly, but due to high speed, it won't be visible without delays. // The original text implies this rapid toggling is happening. loop { led2.toggle().unwrap(); // A delay would be needed here for visible blinking, e.g.: // cortex_m::asm::delay(clocks.hclk().0 / 1000); // Example delay } } ``` -------------------------------- ### Clone Project Repository using Git Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/03-setup/README.md Clones the project repository from GitHub using Git. This is a standard method for obtaining the project's source code, including any example codebases used in the book. ```console git clone https://github.com/rust-embedded/discovery-mb2.git ``` -------------------------------- ### Verify cargo-embed Version Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/03-setup/README.md Checks the installed version of `cargo-embed` to confirm that `probe-rs-tools` was installed successfully. `cargo-embed` is a key tool for managing embedded projects with Cargo. ```console $ cargo embed --version cargo-embed 0.24.0 (git commit: crates.io) ``` -------------------------------- ### Uninstall Old Probe-rs Tools Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/03-setup/README.md Removes potentially conflicting older versions of `probe-run`, `probe-rs`, and `cargo-embed`. This step is recommended before installing the latest `probe-rs-tools` to avoid issues. ```console $ cargo uninstall cargo-embed $ cargo uninstall probe-run $ cargo uninstall probe-rs $ cargo uninstall probe-rs-cli ``` -------------------------------- ### Verify Rust Toolchain Version Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/03-setup/README.md Checks the installed Rust compiler version to ensure it meets the minimum requirement. This is crucial for compatibility with the project's build system and dependencies. ```console $ rustc -V rustc 1.79.0 (129f3b996 2024-06-10) ``` -------------------------------- ### Rust Spin Wait Example Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/06-hello-world/spin-wait.md This Rust code snippet demonstrates a basic 'spin wait' implementation to introduce a delay. It's a simple but inefficient method for timing, suitable for basic examples but not recommended for precise or power-sensitive applications. The code iterates a large number of times to approximate a half-second delay. ```rust use {{crate_name}}::hal::prelude::*; use {{crate_name}}::hal::delay::*; use {{crate_name}}::pac; #[rtic::app(device = pac)] mod app { use super::*; #[init] fn init(cx: init::Context) -> (init::LateResources, init::Monotonics) { let mut delay = Delay::new(cx.core.SYST); loop { // Toggle LED // Delay for ~0.5 seconds delay.delay_ms(500_u32); } } // The rest of the app is empty #[idle] fn idle(_: idle::Context) -> ! { loop { // Enter low power mode cortex_m::asm::wfi(); } } } ``` -------------------------------- ### Reset and Continue Program Execution in GDB Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/05-meet-your-software/debug-it.md The `monitor reset` command resets the microcontroller, and `c` (or `continue`) then runs the program until it hits a breakpoint, typically at the `main` function. This combination is useful for returning to the start of your program after unintended execution paths or errors. ```gdb (gdb) monitor reset (gdb) c Continuing. Breakpoint 1, init::__cortex_m_rt_main_trampoline () at src/05-meet-your-software/src/main.rs:9 9 #[entry] (gdb) ``` -------------------------------- ### Release Binary Size Report Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/07-led-roulette/my-solution.md Example output from the `cargo size` command, detailing the size of different sections within the release binary. This includes program instructions, read-only data, and statically allocated RAM variables. ```text Finished release [optimized + debuginfo] target(s) in 0.02s led-roulette : section size addr .vector_table 256 0x0 .text 6332 0x100 .rodata 648 0x19bc .data 0 0x20000000 .bss 1076 0x20000000 .uninit 0 0x20000434 .debug_loc 9036 0x0 .debug_abbrev 2754 0x0 .debug_info 96460 0x0 .debug_aranges 1120 0x0 .debug_ranges 11520 0x0 .debug_str 71325 0x0 .debug_pubnames 32316 0x0 .debug_pubtypes 29294 0x0 .Arm.attributes 58 0x0 .debug_frame 2108 0x0 .debug_line 19303 0x0 .comment 109 0x0 Total 283715 ``` -------------------------------- ### Embed Example: Send Byte (Rust) Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/11-uart/send-a-single-byte.md This is the complete example code for sending a single byte via UART, as found in the `send-byte.rs` file. It includes the necessary setup and transmission logic. ```rust #![no_std] use arduino_hal::prelude::*; use arduino_hal::uarte; use arduino_hal::uarte::{Baudrate, Parity}; #[arduino_hal::entry] fn main() -> ! { let dp = arduino_hal::Peripherals::take().unwrap(); let mut delay = arduino_hal::Delay::new(); let mut serial = uarte::Uarte::new( dp.UARTE0, dp.uart.into(), Parity::EXCLUDED, Baudrate::BAUD115200, ); loop { serial.write(b'X').unwrap(); serial.flush().unwrap(); delay.delay_ms(1000); } } ``` -------------------------------- ### Step Through Code Execution in GDB Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/05-meet-your-software/debug-it.md Illustrates how to execute code line by line using the 'next' command in GDB. This allows for detailed analysis of program flow and variable changes. ```shell (gdb) next (gdb) print _y ``` -------------------------------- ### Example: Display Magnetic Field Magnitude in Rust Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/13-led-compass/magnitude.md An example Rust program demonstrating how to read magnetic field data from the LSM303AGR sensor and display its magnitude in nanotesla (nT) and milligauss (mG). It includes the necessary setup for the sensor and conversion to milligauss. The program requires the `lsm303agr` and `libm` crates. ```rust #[macro_use] extern crate log; use lsm303agr::{Lsm303agr, Mode, OutputDataRate}; use libm::sqrtf; fn main() { let mut sensor = Lsm303agr::new().unwrap(); sensor.set_mode(Mode::MagContinuous).unwrap(); sensor.set_output_data_rate(OutputDataRate::Hz10).unwrap(); loop { let data = sensor.magnetic_field().unwrap(); let x = data.x as f32; let y = data.y as f32; let z = data.z as f32; let magnitude = sqrtf(x * x + y * y + z * z); let magnitude_milligauss = magnitude / 100.0; info!("Magnitude: {:.2} nT ({:.2} mG)", magnitude, magnitude_milligauss); std::thread::sleep(std::time::Duration::from_secs(1)); } } ``` -------------------------------- ### Receive Byte from Serial Port in Rust Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/11-uart/receive-a-single-byte.md This Rust code snippet demonstrates how to receive a single byte from a serial port on the discovery-mb2 board. It utilizes the `serial.read()` function to wait for incoming data and prints the received byte to the RTT debugging console. This example assumes a basic setup for serial communication and RTT logging. ```rust use panic_halt as _; // panic is the default, so we can use it use stm32f4xx_hal as hal; use crate::hal::{prelude::*, serial::Serial, rcc::Clocks}; use crate::hal::stm32f4xx_hal::serial::config::Config; #[entry] fn main() -> ! { let dp = hal::pac::Peripherals::take().unwrap(); // Constrain the STM32 clock registers let rcc = dp.RCC.constrain(); // UNCOMMENT these lines if you want to use the RTT // let rtt = hal::rtt::Rtt::new(dp.DWT, dp.RTT, dp.TPIU); // let mut stdout = rtt.log.borrow(rtt.wr); // Activate the clocks let clocks = rcc.cfgr.freeze(); // Enable the serial port let mut serial = Serial::usart2( dp.USART2, (dp.PA2, dp.PA3), Config::default().baudrate(9600.bps()), clocks, ).unwrap(); loop { let byte = nb::block!(serial.read()).unwrap(); // UNCOMMENT these lines if you want to use the RTT // writeln!("{} \n", byte).unwrap(); // NOTE: The received byte is a u8. If you want to print it as a char, // you need to convert it first. // For example: // let char = byte as char; // writeln!("{}", char).unwrap(); } } ``` -------------------------------- ### Launch GDB and Connect to Target Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/05-meet-your-software/debug-it.md This snippet shows how to launch GDB and connect to a remote debugging stub running on localhost:1337. Ensure the binary path is correct for your project structure. ```shell gdb ../../../target/thumbv7em-none-eabihf/debug/examples/init (gdb) target remote :1337 ``` -------------------------------- ### Superloop Example: Blink LED on Button Hold (Rust) Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/08-inputs-and-outputs/polling-sucks.md Demonstrates a simplified superloop implementation in Rust that blinks an LED when a specific button (Button A) is held down. This example highlights the core logic of polling buttons and controlling LED states within a main loop to ensure responsiveness. ```rust #![no_std] use panic_halt as _; use stm32f4xx_hal::{ pac, prelude::*, gpio::{Output, PushPull, GpioExt}, timer::Timer }; #[macro_use] extern crate cortex_m_rt; // for entry macro #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); // Constrain the STM32f4xx peripherals to the HAL types let rcc = dp.RCC.constrain(); let gpiod = dp.GPIOD.constrain(); // Configure the clock let clocks = rcc.cfgr.freeze(); // Configure LED pin let mut led = gpiod.pd12.into_push_pull_output(); // Configure Button pin let button = gpiod.pd0.into_floating_input(); // Use a timer for delays let mut timer = Timer::new(dp.TIM4, &clocks); loop { if button.is_low() { // Button is pressed, blink the LED led.set_high(); timer.delay_ms(100_u16); led.set_low(); timer.delay_ms(100_u16); } else { // Button is not pressed, turn LED off led.set_low(); } } } ``` -------------------------------- ### Initialize micro:bit v2 Board and Control LEDs Source: https://context7.com/rust-embedded/discovery-mb2/llms.txt Demonstrates taking ownership of micro:bit v2 peripherals using the Board Support Package (BSP) and configuring GPIO pins for LED control. Requires `cortex-m-rt`, `embedded-hal`, `microbit`, and `panic-halt` crates. ```rust #![no_main] #![no_std] use cortex_m_rt::entry; use embedded_hal::digital::OutputPin; use microbit::board::Board; use panic_halt as _; #[entry] fn main() -> ! { // Take ownership of all board peripherals let mut board = Board::take().unwrap(); // Configure LED matrix pins - set column low to enable, row high to light LED board.display_pins.col1.set_low().unwrap(); board.display_pins.row1.set_high().unwrap(); loop {} } ``` -------------------------------- ### Run Binary Program from src/main.rs Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/05-meet-your-software/README.md Compiles and runs a Rust binary program located at `src/main.rs`. This is the default entry point for Cargo projects and requires no special flags. ```bash cargo embed # or car go run ``` -------------------------------- ### Volatile Operations Example (Rust) Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/09-registers/misoptimization.md A Rust code snippet demonstrating the use of volatile operations. This is a common pattern to prevent the compiler from optimizing away memory accesses, particularly when interacting with hardware registers. ```rust use volatile::Volatile; #[repr(C)] struct Registers { out: Volatile, } #[link_section = ".my_section"] // Example section, adjust as needed static REGISTERS: Registers = Registers { out: Volatile::new(0) }; fn main() { // Example of reading and writing to the OUT register using volatile operations let mut current_value = REGISTERS.out.read(); current_value |= 0x200000; REGISTERS.out.write(current_value); let mut another_value = REGISTERS.out.read(); another_value &= !0x80000; REGISTERS.out.write(another_value); } ``` -------------------------------- ### Rust Embedded Program Initialization (`init.rs`) Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/05-meet-your-software/embedded-setup.md This Rust code snippet demonstrates a basic embedded program initialization. It uses `#![no_std]` to avoid the standard library and `#![no_main]` to define a custom entry point using the `cortex-m-rt` crate. The entry point function `main` has a signature `fn() -> !`, indicating it never returns. ```rust #![no_std] #![no_main] use cortex_m_rt::entry; #[entry] fn main() -> ! { // Program logic goes here loop { // Infinite loop to keep the program running } } ``` -------------------------------- ### Run Binary Program from src/bin/bar.rs Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/05-meet-your-software/README.md Compiles and runs a Rust binary program located in the `src/bin/` directory. The `--bin` flag specifies which binary to run. ```bash cargo embed --bin bar # or car go run --bin bar ``` -------------------------------- ### Get Next Turn Direction Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/16-snake-game/controls.md Provides a function to retrieve the current turn direction from the shared TURN Mutex. It optionally resets the turn direction to None after retrieval. ```rust use cortex_m::interrupt; use crate::Turn; pub fn get_next_turn(reset: bool) -> Turn { interrupt::free(|cs| { let mut turn_ref = crate::TURN.borrow_mut(cs); let current_turn = turn_ref.take().unwrap_or(Turn::None); if reset { turn_ref.replace(Some(Turn::None)); } else { turn_ref.replace(Some(current_turn)); } current_turn }) } ``` -------------------------------- ### Atomic Counter and GPIOTE Peripheral Sharing (Rust) Source: https://github.com/rust-embedded/discovery-mb2/blob/main/mdbook/src/15-interrupts/sharing-data-with-globals.md Demonstrates sharing an atomic counter and the GPIOTE peripheral between an interrupt handler and the main program using `AtomicUsize` and `LockMut`. This allows safe, concurrent updates to shared state. ```rust use core::cell::RefCell; use critical_section::LockRef; use critical_section_lock_mut::LockMut; use embedded_hal::digital::v2::InputPin; use nrf_gpiote::{Gpiote, Port; use rtt_target::{rprintln, init as rtt_init}; use core::sync::atomic::{AtomicUsize, Ordering}; #[rtic::app(device = nrf_hal::pac, peripherals = true)] mod app { use super::*; static COUNTER: AtomicUsize = AtomicUsize::new(0); static GPIOTE_PERIPHERAL: LockMut>> = LockMut::new(RefCell::new(None)); #[init] fn init(mut p: nrf_hal::pac::Peripherals) -> (Shared, Local) { rtt_init!(); rprintln!("Initializing..."); let gpiote = Gpiote::new(p.GPIOTE); gpiote.enable(Port::Port0, 14); gpiote.enable(Port::Port0, 15); // Store the GPIOTE peripheral in the global LockMut GPIOTE_PERIPHERAL.borrow(critical_section::acquire()).replace(Some(gpiote)); // Configure button pins let mut p0 = nrf_hal::gpio::p0::Parts::new(p.P0); let button_a = p0.pin0.into_pullup_input(); let button_b = p0.pin1.into_pullup_input(); // Enable interrupts for buttons button_a.enable_interrupt().unwrap(); button_b.enable_interrupt().unwrap(); (Shared {}, Local {}) } #[idle] fn idle(_: Idle) -> ! { loop { rprintln!("Count: {}", COUNTER.load(Ordering::SeqCst)); cortex_m::asm::wfi(); } } #[task(binds = GPIOTE, priority = 1)] fn GPIOTE_HANDLER(mut _ctx: GPIOTE_HANDLER) { // Access the GPIOTE peripheral safely let mut gpiote = GPIOTE_PERIPHERAL.borrow(critical_section::acquire()); if let Some(ref mut gpiote_ref) = *gpiote { if gpiote_ref.is_event_triggered(Port::Port0, 14) { // Button A pressed COUNTER.fetch_add(1, Ordering::SeqCst); gpiote_ref.reset_event(Port::Port0, 14); } if gpiote_ref.is_event_triggered(Port::Port0, 15) { // Button B pressed COUNTER.fetch_add(1, Ordering::SeqCst); gpiote_ref.reset_event(Port::Port0, 15); } } } #[shared] struct Shared {} #[local] struct Local {} } ```