mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-07-07 04:58:00 +02:00
113 lines
6.3 KiB
Markdown
113 lines
6.3 KiB
Markdown
# 0x0f Flash Rust Driver
|
|
|
|
This repository contains a Bare-Metal Rust driver demonstrating **Hardware Flash Memory** access (reading, erasing, and writing) on the **RP2350** (and RP2040) microcontrollers.
|
|
|
|
It includes:
|
|
- A demo (`src/main.rs`) that erases a sector of flash, writes a message into it, reads the message back out of flash, and prints it over UART.
|
|
- A reusable library module (`src/flash.rs`) providing a hardware-agnostic `flash_lib` containing constants, buffer preparation, and formatting helpers.
|
|
- Board initialization logic (`src/board.rs`).
|
|
|
|
## 🚀 Getting Started from Scratch
|
|
|
|
If you're starting with a fresh machine, follow these exact steps to install the toolchain, build the code, and flash it to your microcontroller.
|
|
|
|
### 1. Install Rust
|
|
First, install `rustup` (the Rust toolchain installer) if you haven't already:
|
|
```bash
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
|
```
|
|
*Note: Restart your terminal or run `source $HOME/.cargo/env` after this finishes.*
|
|
|
|
Ensure your Rust compiler is up to date:
|
|
```bash
|
|
rustup update
|
|
```
|
|
|
|
### 2. Install the Target Architecture
|
|
This project is configured for the **RP2350** (ARM Cortex-M33). We need to install the cross-compilation target for it:
|
|
```bash
|
|
rustup target add thumbv8m.main-none-eabihf
|
|
```
|
|
*(If you were targeting the RP2040, you would use `thumbv6m-none-eabi` instead).*
|
|
|
|
### 3. Install Build Tools
|
|
You will need a few extra tools to help link and format the firmware for the RP-series chips.
|
|
|
|
Install `flip-link` (adds zero-cost stack overflow protection):
|
|
```bash
|
|
cargo install flip-link
|
|
```
|
|
|
|
Install `picotool` (used by `cargo run` to flash the chip):
|
|
- **macOS:** `brew install picotool`
|
|
- **Linux/Windows:** Follow the official Raspberry Pi documentation to install `picotool` or build it from source.
|
|
|
|
### 4. Building the Code
|
|
To compile the code for the microcontroller, simply run:
|
|
```bash
|
|
cargo build
|
|
```
|
|
|
|
To build a highly optimized release version (smaller and faster):
|
|
```bash
|
|
cargo build --release
|
|
```
|
|
|
|
### 5. Flashing to the Microcontroller
|
|
This project is pre-configured in `.cargo/config.toml` to use `picotool` as the custom runner.
|
|
|
|
To flash the code:
|
|
1. Hold down the **BOOTSEL** button on your RP2350 board.
|
|
2. Plug it into your computer via USB (or press the RUN/RESET button while holding BOOTSEL).
|
|
3. Run the following command:
|
|
|
|
```bash
|
|
cargo run --release
|
|
```
|
|
*`cargo` will compile the code and automatically use `picotool` to upload the `.elf` file directly to your board and start executing it!*
|
|
|
|
### 6. Testing on the Host
|
|
Because the data manipulation and string formatting logic is separated into a reusable library without touching hardware registers, you can run the unit tests natively on your computer!
|
|
|
|
However, because this project sets a default bare-metal target (`thumbv8m.main-none-eabihf`) in `.cargo/config.toml`, running a plain `cargo test` will fail because the standard library doesn't exist on the microcontroller. You must explicitly tell Cargo to compile the tests for your host computer's processor architecture:
|
|
|
|
**Mac (Apple Silicon):**
|
|
```bash
|
|
cargo test --lib --target aarch64-apple-darwin
|
|
```
|
|
|
|
**Linux (Intel/AMD 64-bit):**
|
|
```bash
|
|
cargo test --lib --target x86_64-unknown-linux-gnu
|
|
```
|
|
|
|
**Windows (64-bit):**
|
|
```bash
|
|
cargo test --lib --target x86_64-pc-windows-msvc
|
|
```
|
|
|
|
## 🧠 Code Walkthrough
|
|
|
|
This section explains exactly how the code works, where the entry point is, and traces the flow of execution as if you were stepping through it line-by-line.
|
|
|
|
### 1. The Entry Point (`src/main.rs`)
|
|
Unlike a standard computer program, bare-metal microcontrollers do not have an operating system to call `main()`. Instead, we use the `#[entry]` macro from the HAL (Hardware Abstraction Layer) to define the very first function that runs after the chip boots up.
|
|
|
|
* **`main() -> !`**: This is the absolute start of our code. It takes ownership of all the hardware peripherals (`hal::pac::Peripherals::take().unwrap()`) and immediately passes them into `board::run(...)`. The `-> !` means this function never returns (because embedded devices run in an infinite loop).
|
|
|
|
### 2. Board Initialization (`src/board.rs`)
|
|
Once execution enters `board.rs`, we initialize the system clocks, pins, UART (for logging), and interact with the hardware Flash peripheral.
|
|
|
|
* **`run(...)`**: The master setup function. Initializes the clocks and UART, then runs the `flash_demo(...)`. After the demo finishes, it parks the CPU in a low-power `wfe` (wait for event) infinite loop.
|
|
* **`flash_demo(...)`**: Orchestrates the core flash workflow. It prepares a write buffer in RAM (filling it with `0xFF` and inserting a demo string), calls `flash_write(...)` to program it to the last sector of flash memory, reads the data back into a `read_buf`, and then formats/prints the result.
|
|
* **`flash_write(...)`**: A high-level wrapper that ensures flash modification is safe. It wraps the low-level flash operations in an interrupt-free critical section (`cortex_m::interrupt::free`) to prevent the CPU from trying to fetch instructions from flash while it is being erased or programmed.
|
|
* **`flash_prepare_sector(...)` / `flash_program_and_restore(...)`**: Low-level, `unsafe` functions that call directly into the RP2040/RP2350 BootROM routines. They disconnect flash from the XIP (eXecute In Place) cache, erase the target sector, program the new data, flush the hardware cache, and then safely restore XIP mode so the CPU can resume executing code from flash.
|
|
* **`flash_read(...)`**: Since the flash memory on the RP2350/RP2040 is mapped directly into the CPU's memory address space (XIP), reading from flash is as simple as performing a standard pointer read from `XIP_BASE + offset`.
|
|
|
|
### 3. The Reusable Flash Library (`src/flash.rs`)
|
|
While `board.rs` directly manipulates the flash via BootROM calls, `flash.rs` defines the memory layout constants and handles buffer manipulation and string formatting for logging.
|
|
|
|
* **Constants**: Defines `FLASH_SIZE_BYTES`, `FLASH_SECTOR_SIZE`, `FLASH_PAGE_SIZE`, and `XIP_BASE`, keeping magic numbers out of the application code.
|
|
* **`prepare_write_buf(...)`**: Fills a provided buffer with `0xFF` (representing the erased state of flash memory) and then copies our `DEMO_MSG` into the start of the buffer.
|
|
* **`format_readback(...)`**: Extracts the NUL-terminated C-style string from the raw flash read buffer and formats it nicely for printing over UART.
|