diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 04011e83d..02df5454b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -318,6 +318,7 @@ jobs: - soc: esp32h2 rust-target: riscv32imac-unknown-none-elf # Xtensa devices: + - soc: esp32s2 - soc: esp32s3 steps: @@ -339,4 +340,4 @@ jobs: ldproxy: false - uses: Swatinem/rust-cache@v2 - - run: cargo xtask build-examples hil-test ${{ matrix.target.soc }} + - run: cargo xtask build-tests ${{ matrix.target.soc }} diff --git a/.github/workflows/hil.yml b/.github/workflows/hil.yml index ae3f858ef..a445213b1 100644 --- a/.github/workflows/hil.yml +++ b/.github/workflows/hil.yml @@ -26,18 +26,21 @@ jobs: matrix: target: # RISC-V devices: - # - soc: esp32c3 - # rust-target: riscv32imc-unknown-none-elf + - soc: esp32c3 + rust-target: riscv32imc-unknown-none-elf - soc: esp32c6 rust-target: riscv32imac-unknown-none-elf - # - soc: esp32h2 - # rust-target: riscv32imac-unknown-none-elf + - soc: esp32h2 + rust-target: riscv32imac-unknown-none-elf # # Xtensa devices: - # - soc: esp32s3 + - soc: esp32s2 + rust-target: xtensa-esp32s2-none-elf + - soc: esp32s3 + rust-target: xtensa-esp32s3-none-elf + steps: - uses: actions/checkout@v4 if: github.event_name != 'workflow_dispatch' - - uses: actions/checkout@v4 if: github.event_name == 'workflow_dispatch' with: @@ -59,7 +62,7 @@ jobs: default: true ldproxy: false - - name: Run tests + - name: Build tests run: cargo xtask build-tests ${{ matrix.target.soc }} - name: Prepare artifact @@ -78,12 +81,12 @@ jobs: base_name="$(basename "$file" | cut -d'-' -f1)" mv "$file" "tests/$base_name" done - - uses: actions/upload-artifact@v4 with: name: tests-${{ matrix.target.soc }} path: /home/runner/work/esp-hal/esp-hal/tests if-no-files-found: error + overwrite: true hil: name: HIL Test | ${{ matrix.target.soc }} @@ -95,24 +98,25 @@ jobs: matrix: target: # RISC-V devices: - # - soc: esp32c3 - # runner: rustboard + - soc: esp32c3 + runner: esp32c3-usb - soc: esp32c6 runner: esp32c6-usb - # - soc: esp32h2 - # runner: esp32h2-usb - # # Xtensa devices: - # - soc: esp32s3 - # runner: esp32s3-usb + - soc: esp32h2 + runner: esp32h2-usb + # Xtensa devices: + - soc: esp32s2 + runner: esp32s2-jtag + - soc: esp32s3 + runner: esp32s3-usb steps: + - uses: actions/checkout@v4 - uses: actions/download-artifact@v4 with: name: tests-${{ matrix.target.soc }} - path: tests - - name: Run tests + path: tests-${{ matrix.target.soc }} + + - name: Run Tests run: | export PATH=$PATH:/home/espressif/.cargo/bin - for file in "tests"/*; do - probe-rs run --chip ${{ matrix.target.soc }} "$file" - done - + cargo xtask run-elfs ${{ matrix.target.soc }} tests-${{ matrix.target.soc }} diff --git a/hil-test/README.md b/hil-test/README.md index 38dadd265..736f32242 100644 --- a/hil-test/README.md +++ b/hil-test/README.md @@ -19,11 +19,9 @@ We use [embedded-test] as our testing framework, which relies on [defmt] interna 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=ddd59fa \ - --features=cli \ - --bin=probe-rs +cargo install probe-rs-tools \ + --git https://github.com/probe-rs/probe-rs \ + --rev 4dc1701 --force --locked ``` 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]. @@ -61,7 +59,7 @@ 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: Ubuntu 20.04.5 configured with the following [setup](#vm-setup) + - RPi: Raspbian 12 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. @@ -69,11 +67,16 @@ Our Virtual Machines have the following setup: - ESP32-H2 (`esp32h2-usb`): - Devkit: `ESP32-H2-DevKitM-1` connected via USB-Serial-JTAG (`USB` port). - `GPIO2` and `GPIO4` are connected. - - VM: Ubuntu 20.04.5 configured with the following [setup](#vm-setup) + - RPi: Raspbian 12 configured with the following [setup](#vm-setup) +- ESP32-S2 (`esp32s2-jtag`): + - Devkit: `ESP32-S2-Saola-1` connected via UART. + - `GPIO2` and `GPIO4` are connected. + - Probe: `ESP-Prog` connected with the [following connections](https://docs.espressif.com/projects/esp-idf/en/stable/esp32s2/api-guides/jtag-debugging/configure-other-jtag.html#configure-hardware) + - RPi: Raspbian 12 configured with the following [setup](#vm-setup) - ESP32-S3 (`esp32s3-usb`): - Devkit: `ESP32-S3-DevKitC-1` connected via USB-Serial-JTAG. - `GPIO2` and `GPIO4` are connected. - - VM: Ubuntu 22.04.4 configured with the following [setup](#vm-setup) + - RPi: Raspbian 12 configured with the following [setup](#vm-setup) [`hil.yml`]: https://github.com/esp-rs/esp-hal/blob/main/.github/workflows/hil.yml @@ -86,7 +89,7 @@ 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=ddd59fa --features=cli --bin=probe-rs --locked --force +cargo install probe-rs-tools --git https://github.com/probe-rs/probe-rs --rev 4dc1701 --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 diff --git a/hil-test/tests/delay.rs b/hil-test/tests/delay.rs index 26197ce2e..f9a4c235a 100644 --- a/hil-test/tests/delay.rs +++ b/hil-test/tests/delay.rs @@ -1,5 +1,7 @@ //! Delay Test +//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32s3 + #![no_std] #![no_main] diff --git a/hil-test/tests/get_time.rs b/hil-test/tests/get_time.rs index 278295a8a..36181ae37 100644 --- a/hil-test/tests/get_time.rs +++ b/hil-test/tests/get_time.rs @@ -1,6 +1,6 @@ //! current_time Test -//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 +//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32s2 esp32s3 #![no_std] #![no_main] diff --git a/hil-test/tests/gpio.rs b/hil-test/tests/gpio.rs index 497e104e3..cce2b2c17 100644 --- a/hil-test/tests/gpio.rs +++ b/hil-test/tests/gpio.rs @@ -4,6 +4,8 @@ //! GPIO2 //! GPIO4 +//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 + #![no_std] #![no_main] @@ -151,7 +153,6 @@ mod tests { } #[test] - // TODO: See https://github.com/esp-rs/esp-hal/issues/1413 #[cfg(not(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3")))] fn test_gpio_interrupt(mut ctx: Context) { critical_section::with(|cs| { diff --git a/hil-test/tests/spi_full_duplex.rs b/hil-test/tests/spi_full_duplex.rs index fdbcba5a0..e83555d87 100644 --- a/hil-test/tests/spi_full_duplex.rs +++ b/hil-test/tests/spi_full_duplex.rs @@ -8,6 +8,8 @@ //! //! Connect MISO (GPIO2) and MOSI (GPIO4) pins. +//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 + #![no_std] #![no_main] diff --git a/hil-test/tests/spi_full_duplex_dma.rs b/hil-test/tests/spi_full_duplex_dma.rs index 3feef3c8f..826c36be6 100644 --- a/hil-test/tests/spi_full_duplex_dma.rs +++ b/hil-test/tests/spi_full_duplex_dma.rs @@ -8,7 +8,7 @@ //! //! Connect MISO (GPIO2) and MOSI (GPIO4) pins. -//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 +//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s3 #![no_std] #![no_main] @@ -120,7 +120,7 @@ mod tests { let transfer = spi.dma_transfer(&mut send, &mut receive).unwrap(); transfer.wait().unwrap(); - assert_eq!(send[0], receive[0]); + assert_eq!(send[0..1], receive[0..1]); } #[test] diff --git a/hil-test/tests/uart.rs b/hil-test/tests/uart.rs index 5ba9cc525..b2418cf71 100644 --- a/hil-test/tests/uart.rs +++ b/hil-test/tests/uart.rs @@ -6,6 +6,8 @@ //! //! Connect TX (GPIO2) and RX (GPIO4) pins. +//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 + #![no_std] #![no_main] @@ -106,22 +108,43 @@ mod tests { // working as expected. We will also using different clock sources // while we're at it. - // 9600 baud, RC FAST clock source: - ctx.uart.change_baud(9600, ClockSource::RcFast, &ctx.clocks); - ctx.uart.write(7).ok(); - let read = block!(ctx.uart.read()); - assert_eq!(read, Ok(7)); + #[cfg(not(feature = "esp32s2"))] + { + #[cfg(not(feature = "esp32c3"))] + { + // 9600 baud, RC FAST clock source: + ctx.uart.change_baud(9600, ClockSource::RcFast, &ctx.clocks); + ctx.uart.write(7).ok(); + let read = block!(ctx.uart.read()); + assert_eq!(read, Ok(7)); + } - // 19,200 baud, XTAL clock source: - ctx.uart.change_baud(19_200, ClockSource::Xtal, &ctx.clocks); - ctx.uart.write(55).ok(); - let read = block!(ctx.uart.read()); - assert_eq!(read, Ok(55)); + // 19,200 baud, XTAL clock source: + ctx.uart.change_baud(19_200, ClockSource::Xtal, &ctx.clocks); + ctx.uart.write(55).ok(); + let read = block!(ctx.uart.read()); + assert_eq!(read, Ok(55)); - // 921,600 baud, APB clock source: - ctx.uart.change_baud(921_600, ClockSource::Apb, &ctx.clocks); - ctx.uart.write(253).ok(); - let read = block!(ctx.uart.read()); - assert_eq!(read, Ok(253)); + // 921,600 baud, APB clock source: + ctx.uart.change_baud(921_600, ClockSource::Apb, &ctx.clocks); + ctx.uart.write(253).ok(); + let read = block!(ctx.uart.read()); + assert_eq!(read, Ok(253)); + } + #[cfg(feature = "esp32s2")] + { + // 9600 baud, REF TICK clock source: + ctx.uart + .change_baud(9600, ClockSource::RefTick, &ctx.clocks); + ctx.uart.write(7).ok(); + let read = block!(ctx.uart.read()); + assert_eq!(read, Ok(7)); + + // 921,600 baud, APB clock source: + ctx.uart.change_baud(921_600, ClockSource::Apb, &ctx.clocks); + ctx.uart.write(253).ok(); + let read = block!(ctx.uart.read()); + assert_eq!(read, Ok(253)); + } } } diff --git a/hil-test/tests/uart_async.rs b/hil-test/tests/uart_async.rs index f0f2da4f4..4592de0bf 100644 --- a/hil-test/tests/uart_async.rs +++ b/hil-test/tests/uart_async.rs @@ -6,6 +6,8 @@ //! //! Connect TX (GPIO2) and RX (GPIO4) pins. +//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 + #![no_std] #![no_main] diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index aecc2503c..2f32615d7 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs @@ -257,14 +257,12 @@ pub fn execute_app( format!("--example={}", app.name()) }; (bin, "build") + } else if package.starts_with("src/bin") { + (format!("--bin={}", app.name()), "run") + } else if package.starts_with("tests") { + (format!("--test={}", app.name()), "test") } else { - if package.starts_with("src/bin") { - (format!("--bin={}", app.name()), "run") - } else if package.starts_with("tests") { - (format!("--test={}", app.name()), "test") - } else { - (format!("--example={}", app.name()), "run") - } + (format!("--example={}", app.name()), "run") }; let mut features = app.features().to_vec(); diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 02ff0c8bd..7aa2f2024 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -1,6 +1,7 @@ use std::{ fs, path::{Path, PathBuf}, + process::Command, }; use anyhow::{bail, Result}; @@ -29,6 +30,8 @@ enum Cli { RunExample(RunExampleArgs), /// Run all applicable tests or the specified test for a specified chip. RunTests(TestsArgs), + /// Run all ELFs in a folder. + RunElfs(RunElfArgs), } #[derive(Debug, Args)] @@ -114,6 +117,15 @@ struct TestsArgs { test: Option, } +#[derive(Debug, Args)] +struct RunElfArgs { + /// Which chip to run the tests for. + #[arg(value_enum)] + chip: Chip, + /// Path to the ELFs. + path: PathBuf, +} + // ---------------------------------------------------------------------------- // Application @@ -134,6 +146,7 @@ fn main() -> Result<()> { Cli::GenerateEfuseFields(args) => generate_efuse_src(&workspace, args), Cli::RunExample(args) => run_example(&workspace, args), Cli::RunTests(args) => execute_tests(&workspace, args, CargoAction::Run), + Cli::RunElfs(args) => run_elfs(args), } } @@ -396,6 +409,38 @@ fn execute_tests( Ok(()) } +fn run_elfs(args: RunElfArgs) -> Result<(), anyhow::Error> { + let elfs = fs::read_dir(&args.path)?; + let mut failed_elfs: Vec = Vec::new(); + for elf in elfs { + let elf = elf?; + let elf_path = elf.path(); + let elf_name = elf_path.file_name().unwrap().to_str().unwrap(); + let elf_name = elf_name.split('.').next().unwrap(); + let elf_name = elf_name.to_string(); + println!("Running '{}' test", elf_name); + + let command = Command::new("probe-rs") + .arg("run") + .arg("--chip") + .arg(args.chip.to_string()) + .arg(elf_path) + .output() + .expect("Failed to execute probe-rs run command"); + let stdout = String::from_utf8_lossy(&command.stdout); + let stderr = String::from_utf8_lossy(&command.stderr); + println!("{}\n{}", stderr, stdout); + if !command.status.success() { + failed_elfs.push(elf_name); + } + } + + if !failed_elfs.is_empty() { + bail!("Failed tests: {:?}", failed_elfs); + } + + Ok(()) +} // ---------------------------------------------------------------------------- // Helper Functions