Add HIL testing (#1297)
* Create the `hil-test` package * Add a simple integration test to verify basic GPIO functionality * WIP * feat: Update with esp-hal unification * build: Update dependencies * feat: Add a simple CI workflow test * ci: Avoid using a gh-hosted-runner to build * ci: Remove building bins in gh-hosted-runner * ci: Remove HIL Gpio CI test * ci: Test all the available tests * test: Add spi_full_duplex test * docs: Add documentation * test: Add uart test * style: Remove unused imports * docs: Update wiring, document H2 VM * ci: Enable H2 tests * ci: Add rust-cache action * docs: Document H2 vm * test: Add timeout * ci: Enable ESP32-C3 tests * feat: Add timeouts * feat: Add aes test * ci: Avoid running CI workflow when we change hil-test stuff * test: Remove warnings * feat: Address feedback * feat: Update features names and spi methods * ci: Remove rust-cache action * Update HIL to probe-rs#2292 (#1307) * feat: Update probe-rs/embedded-test to probe-rs#2292 * feat: Remove lib * ci: Use a matrix * ci: Enable ESP32C3 * feat: Add a way to cfg away test for unsuported peripherals * ci: Update trigger conditions * feat: Update pins to make it work on s3 * feat: Changes enabling S3 * feat: Remove log feature * feat: Adapt for rebase * feat: Remove env * feat: enable S3 * chore: Remove todo * build: Pin dependencies * feat: Add target alias * docs: Update readme * fix: Fix traits imports after rebase. Use debug * build: Remove lto * feat: Build tests on release mode --------- Co-authored-by: Jesse Braham <jesse@beta7.io>
This commit is contained in:
parent
1444b62777
commit
baea915935
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -18,12 +18,14 @@ on:
|
||||
paths-ignore:
|
||||
- "**/CHANGELOG.md"
|
||||
- "**/README.md"
|
||||
- "**/hil-test/**"
|
||||
push:
|
||||
branches-ignore:
|
||||
- "gh-readonly-queue/**"
|
||||
paths-ignore:
|
||||
- "**/CHANGELOG.md"
|
||||
- "**/README.md"
|
||||
- "**/hil-test/**"
|
||||
merge_group:
|
||||
workflow_dispatch:
|
||||
|
||||
|
||||
59
.github/workflows/hil.yml
vendored
Normal file
59
.github/workflows/hil.yml
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
name: HIL
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
repository:
|
||||
description: "Owner and repository to test"
|
||||
required: true
|
||||
default: 'esp-rs/esp-hal'
|
||||
branch:
|
||||
description: "Branch, tag or SHA to checkout."
|
||||
required: true
|
||||
default: "main"
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
# Test RISC-V targets:
|
||||
riscv-hil:
|
||||
name: HIL Test | ${{ matrix.target.soc }}
|
||||
runs-on:
|
||||
labels: [self-hosted, "${{ matrix.target.runner }}"]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target:
|
||||
- soc: esp32c3
|
||||
runner: rustboard
|
||||
rust-target: riscv32imc-unknown-none-elf
|
||||
- soc: esp32c6
|
||||
runner: esp32c6-usb
|
||||
rust-target: riscv32imac-unknown-none-elf
|
||||
- soc: esp32h2
|
||||
runner: esp32h2-usb
|
||||
rust-target: riscv32imac-unknown-none-elf
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
if: github.event_name != 'workflow_dispatch'
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
with:
|
||||
repository: ${{ github.event.inputs.repository }}
|
||||
ref: ${{ github.event.inputs.branch }}
|
||||
|
||||
- uses: dtolnay/rust-toolchain@v1
|
||||
with:
|
||||
target: ${{ matrix.target.rust-target }}
|
||||
toolchain: nightly
|
||||
components: rust-src
|
||||
|
||||
- name: Run tests
|
||||
working-directory: hil-test
|
||||
run: cargo ${{ matrix.target.soc }}
|
||||
|
||||
# Test Xtensa targets:
|
||||
# TODO: Add jobs for Xtensa once supported by `probe-rs`
|
||||
@ -9,4 +9,5 @@ exclude = [
|
||||
"esp-metadata",
|
||||
"esp-riscv-rt",
|
||||
"examples",
|
||||
"hil-test",
|
||||
]
|
||||
|
||||
29
hil-test/.cargo/config.toml
Normal file
29
hil-test/.cargo/config.toml
Normal file
@ -0,0 +1,29 @@
|
||||
[alias]
|
||||
# esp32 = "test --release --features=esp32 --target=xtensa-esp32-none-elf -- --chip esp32-3.3v"
|
||||
# esp32c2 = "test --release --features=esp32c2 --target=riscv32imc-unknown-none-elf -- --chip esp32c2"
|
||||
esp32c3 = "test --release --features=esp32c3 --target=riscv32imc-unknown-none-elf -- --chip esp32c3"
|
||||
esp32c6 = "test --release --features=esp32c6 --target=riscv32imac-unknown-none-elf -- --chip esp32c6"
|
||||
esp32h2 = "test --release --features=esp32h2 --target=riscv32imac-unknown-none-elf -- --chip esp32h2"
|
||||
# esp32p4 = "test --release --features=esp32p4 --target=riscv32imafc-unknown-none-elf -- --chip esp32p4"
|
||||
# esp32s2 = "test --release --features=esp32s2 --target=xtensa-esp32s2-none-elf -- --chip esp32s2"
|
||||
esp32s3 = "test --release --features=esp32s3 --target=xtensa-esp32s3-none-elf -- --chip esp32s3"
|
||||
|
||||
[target.'cfg(target_arch = "riscv32")']
|
||||
runner = "probe-rs run"
|
||||
rustflags = [
|
||||
"-C", "link-arg=-Tlinkall.x",
|
||||
"-C", "link-arg=-Tembedded-test.x",
|
||||
"-C", "link-arg=-Tdefmt.x",
|
||||
]
|
||||
|
||||
[target.'cfg(target_arch = "xtensa")']
|
||||
runner = "probe-rs run"
|
||||
rustflags = [
|
||||
"-C", "link-arg=-nostartfiles",
|
||||
"-C", "link-arg=-Wl,-Tlinkall.x",
|
||||
"-C", "link-arg=-Tdefmt.x",
|
||||
"-C", "link-arg=-Tembedded-test.x",
|
||||
]
|
||||
|
||||
[unstable]
|
||||
build-std = ["core"]
|
||||
93
hil-test/Cargo.toml
Normal file
93
hil-test/Cargo.toml
Normal file
@ -0,0 +1,93 @@
|
||||
[package]
|
||||
name = "hil-test"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[[test]]
|
||||
name = "aes"
|
||||
harness = false
|
||||
|
||||
[[test]]
|
||||
name = "gpio"
|
||||
harness = false
|
||||
|
||||
[[test]]
|
||||
name = "spi_full_duplex"
|
||||
harness = false
|
||||
|
||||
[[test]]
|
||||
name = "uart"
|
||||
harness = false
|
||||
|
||||
[dependencies]
|
||||
defmt = { version = "0.3.5" }
|
||||
defmt-rtt = { version = "0.4.0" }
|
||||
esp-hal = { path = "../esp-hal", features = ["embedded-hal", "embedded-hal-02", "defmt"], optional = true }
|
||||
embedded-hal-02 = { version = "0.2.7", package = "embedded-hal", features = ["unproven"] }
|
||||
embedded-hal-async = { version = "1.0.0", optional = true }
|
||||
embedded-hal = { version = "1.0.0" }
|
||||
embedded-hal-nb = { version = "1.0.0", optional = true }
|
||||
embassy-executor = { default-features = false, version = "0.5.0", features = ["executor-thread", "arch-riscv32"], optional = true }
|
||||
semihosting = "0.1.6"
|
||||
|
||||
[dev-dependencies]
|
||||
# Add the `embedded-test/defmt` feature for more verbose testing
|
||||
embedded-test = {git = "https://github.com/probe-rs/embedded-test", rev = "8e3f925"}
|
||||
|
||||
[features]
|
||||
# Device support (required!):
|
||||
esp32 = ["esp-hal/esp32"]
|
||||
esp32c2 = ["esp-hal/esp32c2"]
|
||||
esp32c3 = ["esp-hal/esp32c3"]
|
||||
esp32c6 = ["esp-hal/esp32c6"]
|
||||
esp32h2 = ["esp-hal/esp32h2"]
|
||||
esp32s2 = ["esp-hal/esp32s2"]
|
||||
esp32s3 = ["esp-hal/esp32s3"]
|
||||
# Async & Embassy:
|
||||
async = ["dep:embedded-hal-async", "esp-hal?/async"]
|
||||
embassy = ["esp-hal?/embassy", "embedded-test/embassy", "dep:embassy-executor"]
|
||||
embassy-executor-interrupt = ["esp-hal?/embassy-executor-interrupt"]
|
||||
embassy-executor-thread = ["esp-hal?/embassy-executor-thread"]
|
||||
embassy-time-systick-16mhz = ["esp-hal?/embassy-time-systick-16mhz"]
|
||||
embassy-time-systick-80mhz = ["esp-hal?/embassy-time-systick-80mhz"]
|
||||
embassy-time-timg0 = ["esp-hal?/embassy-time-timg0"]
|
||||
|
||||
# cargo build/run
|
||||
[profile.dev]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = true # <-
|
||||
incremental = false
|
||||
opt-level = 'z' # <-
|
||||
overflow-checks = true # <-
|
||||
|
||||
# cargo test
|
||||
[profile.test]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = true # <-
|
||||
incremental = false
|
||||
opt-level = 3 # <-
|
||||
overflow-checks = true # <-
|
||||
|
||||
# cargo build/run --release
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = false # <-
|
||||
incremental = false
|
||||
opt-level = 3 # <-
|
||||
overflow-checks = false # <-
|
||||
|
||||
# cargo test --release
|
||||
[profile.bench]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = false # <-
|
||||
incremental = false
|
||||
opt-level = 3 # <-
|
||||
overflow-checks = false # <-
|
||||
|
||||
[patch.crates-io]
|
||||
semihosting = { git = "https://github.com/taiki-e/semihosting", rev = "c829c19" }
|
||||
95
hil-test/README.md
Normal file
95
hil-test/README.md
Normal file
@ -0,0 +1,95 @@
|
||||
# hil-test
|
||||
|
||||
Hardware-in-loop testing for `esp-hal`.
|
||||
|
||||
For assistance with this package please [open an issue] or [start a discussion].
|
||||
|
||||
[open an issue]: https://github.com/esp-rs/esp-hal/issues/new
|
||||
[start a discussion]: https://github.com/esp-rs/esp-hal/discussions/new/choose
|
||||
|
||||
## Quickstart
|
||||
|
||||
We use [embedded-test] as our testing framework, which relies on [defmt] internally. This allows us to write unit and integration tests much in the same way you would for a normal Rust project, when the standard library is available, and to execute them using Cargo's built-in test runner.
|
||||
|
||||
[embedded-test]: https://github.com/probe-rs/embedded-test
|
||||
[defmt]: https://github.com/knurling-rs/defmt
|
||||
|
||||
### Running Tests Locally
|
||||
|
||||
We use [probe-rs] for flashing and running the tests on a target device, however, this **MUST** be installed from the correct revision, and with the correct features enabled:
|
||||
|
||||
```text
|
||||
cargo install probe-rs \
|
||||
--git=https://github.com/probe-rs/probe-rs \
|
||||
--rev=b431b24 \
|
||||
--features=cli \
|
||||
--bin=probe-rs
|
||||
```
|
||||
|
||||
Target device **MUST** connected via its USB-Serial-JTAG port, or if unavailable (eg. ESP32, ESP32-C2, ESP32-S2) then you must connect a compatible debug probe such as an [ESP-Prog].
|
||||
|
||||
You can run all test for a given device using:
|
||||
|
||||
```shell
|
||||
cargo +nightly esp32c6
|
||||
# or
|
||||
cargo +esp esp32s3
|
||||
```
|
||||
|
||||
For running a single test on a target:
|
||||
|
||||
```shell
|
||||
# Run GPIO tests for ESP32-C6
|
||||
CARGO_BUILD_TARGET=riscv32imac-unknown-none-elf \
|
||||
PROBE_RS_CHIP=esp32c6 \
|
||||
cargo +nightly test --features=esp32c6 --test=gpio
|
||||
```
|
||||
- If the `--test` argument is omitted, then all tests will be run.
|
||||
- The build target **MUST** be specified via the `CARGO_BUILD_TARGET` environment variable or as an argument (`--target`).
|
||||
- The chip **MUST** be specified via the `PROBE_RS_CHIP` environment variable or as an argument of `probe-rs` (`--chip`).
|
||||
|
||||
Some tests will require physical connections, please see the current [configuration in our runners](#running-tests-remotes-ie-on-self-hosted-runners).
|
||||
|
||||
### Running Tests Remotes (ie. On Self-Hosted Runners)
|
||||
The [`hil.yml`] workflow builds the test suite for all our available targets and executes them.
|
||||
|
||||
Our Virtual Machines have the following setup:
|
||||
- ESP32-C3 (`rustboard`):
|
||||
- Devkit: `ESP32-C3-DevKit-RUST-1` connected via USB-Serial-JTAG.
|
||||
- `GPIO2` and `GPIO4` are connected.
|
||||
- VM: Configured with the following [setup](#vm-setup)
|
||||
- ESP32-C6 (`esp32c6-usb`):
|
||||
- Devkit: `ESP32-C6-DevKitC-1 V1.2` connected via USB-Serial-JTAG (`USB` port).
|
||||
- `GPIO2` and `GPIO4` are connected.
|
||||
- VM: Configured with the following [setup](#vm-setup)
|
||||
- ESP32-H2 (`esp32h2-usb`):
|
||||
- Devkit: `ESP32-H2-DevKitM-1` connected via USB-Serial-JTAG (`USB` port).
|
||||
- `GPIO2` and `GPIO4` are connected.
|
||||
- VM: Configured with the following [setup](#vm-setup)
|
||||
|
||||
[`hil.yml`]: https://github.com/esp-rs/esp-hal/blob/main/.github/workflows/hil.yml
|
||||
|
||||
#### VM Setup
|
||||
```bash
|
||||
# Install Rust:
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain stable -y --profile minimal
|
||||
# Source the current shell:
|
||||
source "$HOME/.cargo/env"
|
||||
# Install dependencies
|
||||
sudo apt install -y pkg-config libudev-dev
|
||||
# Install probe-rs
|
||||
cargo install probe-rs --git=https://github.com/probe-rs/probe-rs --rev=b431b24 --features=cli --bin=probe-rs --locked --force
|
||||
# Add the udev rules
|
||||
wget -O - https://probe.rs/files/69-probe-rs.rules | sudo tee /etc/udev/rules.d/69-probe-rs.rules > /dev/null
|
||||
# Add the user to plugdev group
|
||||
sudo usermod -a -G plugdev $USER
|
||||
# Reboot the VM
|
||||
```
|
||||
|
||||
## Adding New Tests
|
||||
|
||||
1. Create a new integration test file (`tests/$PERIPHERAL.rs`)
|
||||
2. Add a corresponding `[[test]]` entry to `Cargol.toml` (**MUST** set `harness = false`)
|
||||
3. Write the tests
|
||||
4. Document any necessary physical connections on boards connected to self-hosted runners
|
||||
5. Write some documentation at the top of the `tests/$PERIPHERAL.rs` file with the pins being used and the required connections, if applicable.
|
||||
99
hil-test/tests/aes.rs
Normal file
99
hil-test/tests/aes.rs
Normal file
@ -0,0 +1,99 @@
|
||||
//! AES Test
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt_rtt as _;
|
||||
use esp_hal::{
|
||||
aes::{Aes, Mode},
|
||||
peripherals::Peripherals,
|
||||
};
|
||||
|
||||
struct Context<'a> {
|
||||
aes: Aes<'a>,
|
||||
}
|
||||
|
||||
impl Context<'_> {
|
||||
pub fn init() -> Self {
|
||||
let peripherals = Peripherals::take();
|
||||
let aes = Aes::new(peripherals.AES);
|
||||
|
||||
Context { aes }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
feature = "esp32c3",
|
||||
feature = "esp32c6",
|
||||
feature = "esp32h2",
|
||||
feature = "esp32s3"
|
||||
)))]
|
||||
mod not_test {
|
||||
#[esp_hal::entry]
|
||||
fn main() -> ! {
|
||||
semihosting::process::exit(0)
|
||||
}
|
||||
#[panic_handler]
|
||||
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(any(
|
||||
feature = "esp32c3",
|
||||
feature = "esp32c6",
|
||||
feature = "esp32h2",
|
||||
feature = "esp32s3"
|
||||
))]
|
||||
#[embedded_test::tests]
|
||||
mod tests {
|
||||
use defmt::assert_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[init]
|
||||
fn init() -> Context<'static> {
|
||||
Context::init()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_aes_encryption(mut ctx: Context<'static>) {
|
||||
let keytext = "SUp4SeCp@sSw0rd".as_bytes();
|
||||
let plaintext = "message".as_bytes();
|
||||
let encrypted_message = [
|
||||
0xb3, 0xc8, 0xd2, 0x3b, 0xa7, 0x36, 0x5f, 0x18, 0x61, 0x70, 0x0, 0x3e, 0xd9, 0x3a,
|
||||
0x31, 0x96,
|
||||
];
|
||||
|
||||
// create an array with aes128 key size
|
||||
let mut keybuf = [0_u8; 16];
|
||||
keybuf[..keytext.len()].copy_from_slice(keytext);
|
||||
|
||||
// create an array with aes block size
|
||||
let mut block_buf = [0_u8; 16];
|
||||
block_buf[..plaintext.len()].copy_from_slice(plaintext);
|
||||
|
||||
let mut block = block_buf.clone();
|
||||
ctx.aes.process(&mut block, Mode::Encryption128, &keybuf);
|
||||
assert_eq!(block, encrypted_message);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_aes_decryption(mut ctx: Context<'static>) {
|
||||
let keytext = "SUp4SeCp@sSw0rd".as_bytes();
|
||||
let plaintext = "message".as_bytes();
|
||||
let mut encrypted_message = [
|
||||
0xb3, 0xc8, 0xd2, 0x3b, 0xa7, 0x36, 0x5f, 0x18, 0x61, 0x70, 0x0, 0x3e, 0xd9, 0x3a,
|
||||
0x31, 0x96,
|
||||
];
|
||||
|
||||
// create an array with aes128 key size
|
||||
let mut keybuf = [0_u8; 16];
|
||||
keybuf[..keytext.len()].copy_from_slice(keytext);
|
||||
|
||||
ctx.aes
|
||||
.process(&mut encrypted_message, Mode::Decryption128, &keybuf);
|
||||
assert_eq!(&encrypted_message[..plaintext.len()], plaintext);
|
||||
}
|
||||
}
|
||||
72
hil-test/tests/gpio.rs
Normal file
72
hil-test/tests/gpio.rs
Normal file
@ -0,0 +1,72 @@
|
||||
//! GPIO Test
|
||||
//!
|
||||
//! Folowing pins are used:
|
||||
//! GPIO2
|
||||
//! GPIO4
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt_rtt as _;
|
||||
use embedded_hal::digital::{InputPin as _, OutputPin as _, StatefulOutputPin as _};
|
||||
use esp_hal::{
|
||||
gpio::{GpioPin, Input, Output, PullDown, PushPull, IO},
|
||||
peripherals::Peripherals,
|
||||
};
|
||||
|
||||
struct Context {
|
||||
io2: GpioPin<Input<PullDown>, 2>,
|
||||
io4: GpioPin<Output<PushPull>, 4>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn init() -> Self {
|
||||
let peripherals = Peripherals::take();
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
Context {
|
||||
io2: io.pins.gpio2.into_pull_down_input(),
|
||||
io4: io.pins.gpio4.into_push_pull_output(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[embedded_test::tests]
|
||||
mod tests {
|
||||
use defmt::assert_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[init]
|
||||
fn init() -> Context {
|
||||
Context::init()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gpio_input(mut ctx: Context) {
|
||||
// `InputPin`:
|
||||
assert_eq!(ctx.io2.is_low(), Ok(true));
|
||||
assert_eq!(ctx.io2.is_high(), Ok(false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gpio_output(mut ctx: Context) {
|
||||
// `StatefulOutputPin`:
|
||||
assert_eq!(ctx.io4.is_set_low(), Ok(true));
|
||||
assert_eq!(ctx.io4.is_set_high(), Ok(false));
|
||||
assert!(ctx.io4.set_high().is_ok());
|
||||
assert_eq!(ctx.io4.is_set_low(), Ok(false));
|
||||
assert_eq!(ctx.io4.is_set_high(), Ok(true));
|
||||
|
||||
// `ToggleableOutputPin`:
|
||||
assert!(ctx.io4.toggle().is_ok());
|
||||
assert_eq!(ctx.io4.is_set_low(), Ok(true));
|
||||
assert_eq!(ctx.io4.is_set_high(), Ok(false));
|
||||
assert!(ctx.io4.toggle().is_ok());
|
||||
assert_eq!(ctx.io4.is_set_low(), Ok(false));
|
||||
assert_eq!(ctx.io4.is_set_high(), Ok(true));
|
||||
// Leave in initial state for next test
|
||||
assert!(ctx.io4.toggle().is_ok());
|
||||
}
|
||||
}
|
||||
115
hil-test/tests/spi_full_duplex.rs
Normal file
115
hil-test/tests/spi_full_duplex.rs
Normal file
@ -0,0 +1,115 @@
|
||||
//! SPI Full Duplex Test
|
||||
//!
|
||||
//! Folowing pins are used:
|
||||
//! SCLK GPIO0
|
||||
//! MISO GPIO2
|
||||
//! MOSI GPIO4
|
||||
//! CS GPIO5
|
||||
//!
|
||||
//! Connect MISO (GPIO2) and MOSI (GPIO4) pins.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt_rtt as _;
|
||||
use embedded_hal::spi::SpiBus;
|
||||
use esp_hal::{
|
||||
clock::ClockControl,
|
||||
gpio::IO,
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
spi::{master::Spi, FullDuplexMode, SpiMode},
|
||||
};
|
||||
|
||||
struct Context {
|
||||
spi: Spi<'static, esp_hal::peripherals::SPI2, FullDuplexMode>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn init() -> Self {
|
||||
let peripherals = Peripherals::take();
|
||||
let system = peripherals.SYSTEM.split();
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
let sclk = io.pins.gpio0;
|
||||
let miso = io.pins.gpio2;
|
||||
let mosi = io.pins.gpio4;
|
||||
let cs = io.pins.gpio5;
|
||||
|
||||
let spi = Spi::new(peripherals.SPI2, 1000u32.kHz(), SpiMode::Mode0, &clocks).with_pins(
|
||||
Some(sclk),
|
||||
Some(mosi),
|
||||
Some(miso),
|
||||
Some(cs),
|
||||
);
|
||||
|
||||
Context { spi }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[embedded_test::tests]
|
||||
mod tests {
|
||||
use defmt::assert_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[init]
|
||||
fn init() -> Context {
|
||||
Context::init()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_symestric_transfer(mut ctx: Context) {
|
||||
let write = [0xde, 0xad, 0xbe, 0xef];
|
||||
let mut read: [u8; 4] = [0x00u8; 4];
|
||||
|
||||
ctx.spi
|
||||
.transfer(&mut read[..], &write[..])
|
||||
.expect("Symmetric transfer failed");
|
||||
assert_eq!(write, read);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_asymestric_transfer(mut ctx: Context) {
|
||||
let write = [0xde, 0xad, 0xbe, 0xef];
|
||||
let mut read: [u8; 4] = [0x00; 4];
|
||||
|
||||
ctx.spi
|
||||
.transfer(&mut read[0..2], &write[..])
|
||||
.expect("Asymmetric transfer failed");
|
||||
assert_eq!(write[0], read[0]);
|
||||
assert_eq!(read[2], 0x00u8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_symestric_transfer_huge_buffer(mut ctx: Context) {
|
||||
let mut write = [0x55u8; 4096];
|
||||
for byte in 0..write.len() {
|
||||
write[byte] = byte as u8;
|
||||
}
|
||||
let mut read = [0x00u8; 4096];
|
||||
|
||||
ctx.spi
|
||||
.transfer(&mut read[..], &write[..])
|
||||
.expect("Huge transfer failed");
|
||||
assert_eq!(write, read);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[timeout(3)]
|
||||
fn test_symestric_transfer_huge_buffer_no_alloc(mut ctx: Context) {
|
||||
let mut write = [0x55u8; 4096];
|
||||
for byte in 0..write.len() {
|
||||
write[byte] = byte as u8;
|
||||
}
|
||||
|
||||
ctx.spi
|
||||
.transfer_in_place(&mut write[..])
|
||||
.expect("Huge transfer failed");
|
||||
for byte in 0..write.len() {
|
||||
assert_eq!(write[byte], byte as u8);
|
||||
}
|
||||
}
|
||||
}
|
||||
73
hil-test/tests/uart.rs
Normal file
73
hil-test/tests/uart.rs
Normal file
@ -0,0 +1,73 @@
|
||||
//! UART Test
|
||||
//!
|
||||
//! Folowing pins are used:
|
||||
//! TX GPIP2
|
||||
//! RX GPIO4
|
||||
//!
|
||||
//! Connect TX (GPIO2) and RX (GPIO4) pins.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt_rtt as _;
|
||||
use embedded_hal_02::serial::{Read, Write};
|
||||
use esp_hal::{
|
||||
clock::ClockControl,
|
||||
gpio::IO,
|
||||
peripherals::{Peripherals, UART0},
|
||||
prelude::*,
|
||||
uart::{
|
||||
config::{Config, DataBits, Parity, StopBits},
|
||||
TxRxPins,
|
||||
Uart,
|
||||
},
|
||||
};
|
||||
use nb::block;
|
||||
|
||||
struct Context {
|
||||
uart: Uart<'static, UART0>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn init() -> Self {
|
||||
let peripherals = Peripherals::take();
|
||||
let system = peripherals.SYSTEM.split();
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
let pins = TxRxPins::new_tx_rx(
|
||||
io.pins.gpio2.into_push_pull_output(),
|
||||
io.pins.gpio4.into_floating_input(),
|
||||
);
|
||||
let config = Config {
|
||||
baudrate: 115200,
|
||||
data_bits: DataBits::DataBits8,
|
||||
parity: Parity::ParityNone,
|
||||
stop_bits: StopBits::STOP1,
|
||||
};
|
||||
|
||||
let uart = Uart::new_with_config(peripherals.UART0, config, Some(pins), &clocks);
|
||||
|
||||
Context { uart }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[embedded_test::tests]
|
||||
mod tests {
|
||||
use defmt::assert_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[init]
|
||||
fn init() -> Context {
|
||||
Context::init()
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[timeout(3)]
|
||||
fn test_send_receive(mut ctx: Context) {
|
||||
ctx.uart.write(0x42).ok();
|
||||
let read = block!(ctx.uart.read());
|
||||
assert_eq!(read, Ok(0x42));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user