diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4e1e1c6..2d321a3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,9 +11,8 @@ jobs: - uses: dtolnay/rust-toolchain@stable with: targets: "armv7a-none-eabihf" - - run: just check zynq - - run: just check tools - - run: just check zynq7000-boot-image + - run: just check firmware + - run: just check host build: name: Check build @@ -25,9 +24,8 @@ jobs: - uses: dtolnay/rust-toolchain@stable with: targets: "armv7a-none-eabihf" - - run: just build zynq - - run: just build tools - - run: just build zynq7000-boot-image + - run: just check firmware + - run: just check host fmt: name: Check formatting @@ -39,9 +37,8 @@ jobs: with: components: rustfmt targets: "armv7a-none-eabihf" - - run: just fmt zynq - - run: just fmt tools - - run: just fmt zynq7000-boot-image + - run: just check-fmt firmware + - run: just check-fmt host docs: name: Check Documentation Build @@ -65,10 +62,9 @@ jobs: with: components: clippy, rust-src targets: "armv7a-none-eabihf" - - run: just clippy zynq + - run: just clippy firmware - uses: dtolnay/rust-toolchain@stable with: components: clippy - - run: just clippy tools - - run: just clippy zynq7000-boot-image + - run: just clippy host diff --git a/README.md b/README.md index 306b4b3..50098e5 100644 --- a/README.md +++ b/README.md @@ -8,35 +8,35 @@ family of SoCs. This project contains the following crates: -## [Zynq Workspace](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq) +## [Firmware Workspace](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware) This workspace contains libraries and application which can only be run on the target system. -- The [`zynq7000-rt`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/zynq7000-rt) +- The [`zynq7000-rt`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware/zynq7000-rt) run-time crate containing basic low-level startup code necessary to boot a Rust app on the Zynq7000. -- The [`zynq7000`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/zynq7000) PAC +- The [`zynq7000`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware/zynq7000) PAC crate containing basic low-level register definitions. -- The [`zynq7000-mmu`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/zynq7000-hal) +- The [`zynq7000-mmu`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware/zynq7000-hal) crate containing common MMU abstractions used by both the HAL and the run-time crate. -- The [`zynq7000-hal`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/zynq7000-hal) +- The [`zynq7000-hal`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware/zynq7000-hal) HAL crate containing higher-level abstractions on top of the PAC register crate. -- The [`zynq7000-embassy`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/zynq7000-embassy) +- The [`zynq7000-embassy`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware/zynq7000-embassy) crate containing support for running the embassy-rs asynchronous run-time. This project was developed using a Zedboard, so there are several crates available targeted towards this board: -- The [`zedboard-bsp`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/zedboard-bsp) +- The [`zedboard-bsp`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware/zedboard-bsp) crate containing board specific components for the Zedboard. -- The [`zedboard-fsbl`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/zedboard-fsbl) +- The [`zedboard-fsbl`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware/zedboard-fsbl) contains a simple first-stage bootloader application for the Zedboard. -- The [`zedboard-qspi-flasher`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/zedboard-qspi-flasher) +- The [`zedboard-qspi-flasher`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware/zedboard-qspi-flasher) contains an application which is able to flash a boot binary from DDR to the QSPI. It also contains the following helper crates: -- The [`examples`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/examples) +- The [`examples`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware/examples) folder contains various example applications crates using the HAL and the PAC. This folder also contains dedicated example applications using the [`embassy`](https://github.com/embassy-rs/embassy) native Rust RTOS. @@ -46,10 +46,10 @@ It also contains the following helper crates: - The [`zedboard-fpga-design`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zedboard-fpga-design) folder contains a sample FPGA design and block design which was used in some of the provided software examples. The project was created with Vivado version 2024.1. The folder contains a README with all the steps required to load this project from a TCL script. -- The [`zynq7000-boot-image`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq7000-boot-image) +- The [`zynq7000-boot-image`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/host/zynq7000-boot-image) library contains generic helpers to interface with the AMD [boot binary](https://docs.amd.com/r/en-US/ug1283-bootgen-user-guide). -- The [`tools/zynq7000-ps7init-extract`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/tools/zynq7000-ps7init-extract) +- The [`tools/zynq7000-ps7init-extract`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/host/zynq7000-ps7init-extract) tool allows extracting configuration from the AMD generated `ps7init.tcl` file which contains static configuration parameters for DDR initialization. diff --git a/firmware/.cargo/config.toml b/firmware/.cargo/config.toml index 5954cf5..e95c744 100644 --- a/firmware/.cargo/config.toml +++ b/firmware/.cargo/config.toml @@ -6,6 +6,8 @@ rustflags = [ "-Ctarget-feature=+vfp3", "-Ctarget-feature=+neon", "-Clink-arg=-Tlink.x", + # Breaks builds not using/including defmt.. + # "-Clink-arg=-Tdefmt.x", # If this is not enabled, debugging / stepping can become problematic. "-Cforce-frame-pointers=yes", # Can be useful for debugging. @@ -14,3 +16,6 @@ rustflags = [ [build] target = "armv7a-none-eabihf" + +[env] +DEFMT_LOG = "info" diff --git a/firmware/Cargo.toml b/firmware/Cargo.toml index f56ccc7..d91102f 100644 --- a/firmware/Cargo.toml +++ b/firmware/Cargo.toml @@ -10,6 +10,7 @@ members = [ "examples/simple", "examples/embassy", "examples/zedboard", + "examples/defmt", "zedboard-bsp", "zedboard-qspi-flasher", diff --git a/firmware/examples/defmt/Cargo.toml b/firmware/examples/defmt/Cargo.toml new file mode 100644 index 0000000..178db63 --- /dev/null +++ b/firmware/examples/defmt/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "defmt" +version = "0.1.0" +authors = ["Robin Mueller "] +edition = "2024" +description = "DEFMT test app" +homepage = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs" +repository = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs" +license = "MIT OR Apache-2.0" + +[dependencies] +aarch32-cpu = { version = "0.1" } +zynq7000-rt = { path = "../../zynq7000-rt" } +zynq7000 = { path = "../../zynq7000" } +zynq7000-hal = { path = "../../zynq7000-hal", features = ["defmt"] } +defmt = "1" +defmt-rtt = "1" +embedded-io = "0.7" +embedded-hal = "1" +fugit = "0.3" +log = "0.4" diff --git a/firmware/examples/defmt/build.rs b/firmware/examples/defmt/build.rs new file mode 100644 index 0000000..ef48327 --- /dev/null +++ b/firmware/examples/defmt/build.rs @@ -0,0 +1,32 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + 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()); + println!("cargo:rustc-link-arg=-Tdefmt.x"); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); +} diff --git a/firmware/examples/defmt/memory.x b/firmware/examples/defmt/memory.x new file mode 100644 index 0000000..ebec824 --- /dev/null +++ b/firmware/examples/defmt/memory.x @@ -0,0 +1,24 @@ +MEMORY +{ + /* Zedboard: 512 MB DDR3. Only use 63 MB for now, should be plenty for a bare-metal app. + Leave 1 MB of memory which will be configured as uncached device memory by the MMU. This is + recommended for something like DMA descriptors. */ + /*CODE(rx) : ORIGIN = 0x00100000, LENGTH = 63M*/ + CODE(rx) : ORIGIN = 0x00000000, LENGTH = 192K + UNCACHED(rx): ORIGIN = 0x4000000, LENGTH = 1M +} + +REGION_ALIAS("VECTORS", CODE); +REGION_ALIAS("DATA", CODE); + +SECTIONS +{ + /* Uncached memory */ + .uncached (NOLOAD) : ALIGN(4) { + . = ALIGN(4); + _sbss_uncached = .; + *(.uncached .uncached.*); + . = ALIGN(4); + _ebss_uncached = .; + } > UNCACHED +} diff --git a/firmware/examples/defmt/src/main.rs b/firmware/examples/defmt/src/main.rs new file mode 100644 index 0000000..13036e1 --- /dev/null +++ b/firmware/examples/defmt/src/main.rs @@ -0,0 +1,83 @@ +//! Simple blinky app, showing a PAC variant and a HAL variant. +#![no_std] +#![no_main] + +use aarch32_cpu::asm::nop; +use core::panic::PanicInfo; +use defmt_rtt as _; +use embedded_hal::{delay::DelayNs, digital::StatefulOutputPin}; +use zynq7000_hal::{ + InteruptConfig, + clocks::Clocks, + gpio::{Output, PinState, mio}, + priv_tim::CpuPrivateTimer, + time::Hertz, +}; + +pub const LIB: Lib = Lib::Hal; + +// Define the clock frequency as a constant. +// +// Not required for the PAC mode, is required for clean delays in HAL mode. +const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_333); + +#[derive(Debug)] +pub enum Lib { + Pac, + Hal, +} + +#[zynq7000_rt::entry] +fn main() -> ! { + let dp = zynq7000_hal::init(zynq7000_hal::Config { + init_l2_cache: true, + level_shifter_config: Some(zynq7000_hal::LevelShifterConfig::EnableAll), + interrupt_config: Some(InteruptConfig::AllInterruptsToCpu0), + }) + .expect("Failed to initialize Zynq7000"); + + defmt::println!("-- Zynq7000 defmt test application --"); + let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); + defmt::info!("clocks {:?}", clocks); + // Unwrap okay, we only call this once on core 0 here. + let mut cpu_tim = CpuPrivateTimer::take(clocks.arm_clocks()).unwrap(); + let mio_pins = mio::Pins::new(dp.gpio); + let mut led = Output::new_for_mio(mio_pins.mio7, PinState::High); + loop { + defmt::info!("toggling LED!"); + led.toggle().unwrap(); + cpu_tim.delay_ms(1000); + } +} + +#[zynq7000_rt::irq] +fn irq_handler() {} + +#[zynq7000_rt::exception(DataAbort)] +fn data_abort_handler(_faulting_addr: usize) -> ! { + loop { + nop(); + } +} + +#[zynq7000_rt::exception(Undefined)] +fn undefined_handler(_faulting_addr: usize) -> ! { + loop { + nop(); + } +} + +#[zynq7000_rt::exception(PrefetchAbort)] +fn prefetch_handler(_faulting_addr: usize) -> ! { + loop { + nop(); + } +} + +/// Panic handler +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + loop { + nop(); + } +} diff --git a/firmware/zynq7000-hal/Cargo.toml b/firmware/zynq7000-hal/Cargo.toml index 2205688..3bba410 100644 --- a/firmware/zynq7000-hal/Cargo.toml +++ b/firmware/zynq7000-hal/Cargo.toml @@ -42,10 +42,12 @@ vcell = "0.1" raw-slicee = "0.1" embedded-io-async = "0.7" serde = { version = "1", optional = true, features = ["derive"] } +defmt = { version = "1", optional = true } [features] std = ["thiserror/std", "alloc"] alloc = [] +defmt = ["dep:defmt", "fugit/defmt"] # These devices have a lower pin count. 7z010-7z007s-clg225 = [] diff --git a/firmware/zynq7000-hal/src/clocks/mod.rs b/firmware/zynq7000-hal/src/clocks/mod.rs index a3aec6c..ac8e4ea 100644 --- a/firmware/zynq7000-hal/src/clocks/mod.rs +++ b/firmware/zynq7000-hal/src/clocks/mod.rs @@ -14,6 +14,7 @@ use zynq7000::slcr::{ use super::time::Hertz; #[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct ArmClocks { ref_clk: Hertz, cpu_1x_clk: Hertz, @@ -46,6 +47,7 @@ impl ArmClocks { } #[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct DdrClocks { /// DDR reference clock generated by the DDR PLL. ref_clk: Hertz, @@ -114,6 +116,7 @@ impl DdrClocks { } #[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct IoClocks { /// Reference clock provided by IO PLL which is used to calculate all other clock frequencies. ref_clk: Hertz, @@ -195,6 +198,7 @@ impl IoClocks { } #[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Clocks { ps_clk: Hertz, arm_pll_out: Hertz, diff --git a/justfile b/justfile index 7b42148..61b77d5 100644 --- a/justfile +++ b/justfile @@ -4,6 +4,7 @@ check-all: (check "firmware") (check "host") clean-all: (clean "firmware") (clean "host") build-all: build-zynq (build "host") fmt-all: (fmt "firmware") (fmt "host") +check-fmt-all: (check-fmt "firmware") (check-fmt "host") clippy-all: (clippy "firmware") (clippy "host") check target: @@ -18,6 +19,9 @@ build-zynq: (build "firmware") clean target: cd {{target}} && cargo clean +check-fmt target: + cd {{target}} && cargo +stable fmt --all -- --check + fmt target: cd {{target}} && cargo +stable fmt