From 893d2e870ef479d0c823a9694612582214248679 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 28 Nov 2025 13:06:39 +0100 Subject: [PATCH] UART and docs update --- zynq/Cargo.toml | 20 +++ zynq/examples/embassy/Cargo.toml | 21 --- .../embassy/src/bin/dht22-open-drain-pins.rs | 2 +- .../examples/embassy/src/bin/embassy-hello.rs | 2 +- .../embassy/src/bin/logger-non-blocking.rs | 2 +- zynq/examples/embassy/src/bin/pwm.rs | 2 +- zynq/examples/simple/Cargo.toml | 5 - zynq/examples/simple/src/bin/gtc-ticks.rs | 2 +- zynq/examples/simple/src/bin/logger.rs | 2 +- zynq/examples/zedboard/Cargo.toml | 9 +- zynq/examples/zedboard/src/bin/ethernet.rs | 2 +- .../zedboard/src/bin/l3gd20h-i2c-mio.rs | 2 +- .../zedboard/src/bin/l3gd20h-spi-mio.rs | 2 +- zynq/examples/zedboard/src/bin/qspi.rs | 2 +- .../zedboard/src/bin/uart-blocking.rs | 4 +- .../zedboard/src/bin/uart-non-blocking.rs | 14 +- zynq/examples/zedboard/src/main.rs | 2 +- zynq/zedboard-fsbl/Cargo.toml | 20 +++ zynq/zedboard-fsbl/src/main.rs | 2 +- zynq/zedboard-qspi-flasher/src/main.rs | 2 +- zynq/zynq7000-hal/CHANGELOG.md | 5 + zynq/zynq7000-hal/src/gic.rs | 23 ++- zynq/zynq7000-hal/src/gtc.rs | 11 +- zynq/zynq7000-hal/src/l2_cache.rs | 3 +- zynq/zynq7000-hal/src/priv_tim.rs | 3 + zynq/zynq7000-hal/src/slcr.rs | 8 +- zynq/zynq7000-hal/src/time.rs | 4 + zynq/zynq7000-hal/src/ttc.rs | 37 ++++- zynq/zynq7000-hal/src/uart/mod.rs | 142 +++++++++++++++--- zynq/zynq7000-hal/src/uart/rx.rs | 30 +++- zynq/zynq7000-hal/src/uart/tx.rs | 16 ++ zynq/zynq7000-hal/src/uart/tx_async.rs | 15 +- zynq/zynq7000/src/gic.rs | 22 ++- zynq/zynq7000/src/lib.rs | 8 +- zynq/zynq7000/src/mpcore.rs | 8 +- 35 files changed, 330 insertions(+), 124 deletions(-) diff --git a/zynq/Cargo.toml b/zynq/Cargo.toml index 9101e86..f56ccc7 100644 --- a/zynq/Cargo.toml +++ b/zynq/Cargo.toml @@ -19,3 +19,23 @@ exclude = [ # Exclude, can not be built with debug optimization level, too large. "zedboard-fsbl", ] + +# cargo build/run +[profile.dev] +# default is opt-level = '0', but that makes very +# verbose machine code +opt-level = 's' +# trade compile speed for slightly better optimisations +codegen-units = 1 + +# cargo build/run --release +[profile.release] +# Optimize for maximum speed. +opt-level = 3 +# trade compile speed for slightly better optimisations +codegen-units = 1 +# Use Link Time Optimisations to further inline things across +# crates +lto = 'fat' +# Leave the debug symbols in (default is no debug info) +debug = 2 diff --git a/zynq/examples/embassy/Cargo.toml b/zynq/examples/embassy/Cargo.toml index 0f4ffab..eed85c8 100644 --- a/zynq/examples/embassy/Cargo.toml +++ b/zynq/examples/embassy/Cargo.toml @@ -31,24 +31,3 @@ embassy-executor = { version = "0.9", features = [ ]} # TODO: Remove generic-queue-16 feature as soon as upstream executor is used again. embassy-time = { version = "0.5", features = ["tick-hz-1_000_000", "generic-queue-16"] } - -# cargo build/run -[profile.dev] -# default is opt-level = '0', but that makes very -# verbose machine code -opt-level = 's' -# trade compile speed for slightly better optimisations -codegen-units = 1 - -# cargo build/run --release -[profile.release] -# default is opt-level = '3', but that makes quite -# verbose machine code -opt-level = 's' -# trade compile speed for slightly better optimisations -codegen-units = 1 -# Use Link Time Optimisations to further inline things across -# crates -lto = 'fat' -# Leave the debug symbols in (default is no debug info) -debug = 2 diff --git a/zynq/examples/embassy/src/bin/dht22-open-drain-pins.rs b/zynq/examples/embassy/src/bin/dht22-open-drain-pins.rs index 93ba6a9..fa6862c 100644 --- a/zynq/examples/embassy/src/bin/dht22-open-drain-pins.rs +++ b/zynq/examples/embassy/src/bin/dht22-open-drain-pins.rs @@ -67,7 +67,7 @@ async fn main(_spawner: Spawner) -> ! { let uart_clk_config = ClockConfig::new_autocalc_with_error(clocks.io_clocks(), 115200) .unwrap() .0; - let mut uart = Uart::new_with_mio( + let mut uart = Uart::new_with_mio_for_uart_1( dp.uart_1, Config::new_with_clk_config(uart_clk_config), (mio_pins.mio48, mio_pins.mio49), diff --git a/zynq/examples/embassy/src/bin/embassy-hello.rs b/zynq/examples/embassy/src/bin/embassy-hello.rs index bbf53b8..d52d64b 100644 --- a/zynq/examples/embassy/src/bin/embassy-hello.rs +++ b/zynq/examples/embassy/src/bin/embassy-hello.rs @@ -45,7 +45,7 @@ async fn main(_spawner: Spawner) -> ! { let uart_clk_config = uart::ClockConfig::new_autocalc_with_error(clocks.io_clocks(), 115200) .unwrap() .0; - let mut uart = uart::Uart::new_with_mio( + let mut uart = uart::Uart::new_with_mio_for_uart_1( periphs.uart_1, uart::Config::new_with_clk_config(uart_clk_config), (mio_pins.mio48, mio_pins.mio49), diff --git a/zynq/examples/embassy/src/bin/logger-non-blocking.rs b/zynq/examples/embassy/src/bin/logger-non-blocking.rs index 3a1050f..5cbc8c8 100644 --- a/zynq/examples/embassy/src/bin/logger-non-blocking.rs +++ b/zynq/examples/embassy/src/bin/logger-non-blocking.rs @@ -61,7 +61,7 @@ async fn main(spawner: Spawner) -> ! { let uart_clk_config = ClockConfig::new_autocalc_with_error(clocks.io_clocks(), 115200) .unwrap() .0; - let mut uart = Uart::new_with_mio( + let mut uart = Uart::new_with_mio_for_uart_1( dp.uart_1, Config::new_with_clk_config(uart_clk_config), (mio_pins.mio48, mio_pins.mio49), diff --git a/zynq/examples/embassy/src/bin/pwm.rs b/zynq/examples/embassy/src/bin/pwm.rs index d7e1085..6bc15ce 100644 --- a/zynq/examples/embassy/src/bin/pwm.rs +++ b/zynq/examples/embassy/src/bin/pwm.rs @@ -74,7 +74,7 @@ async fn main(_spawner: Spawner) -> ! { let uart_clk_config = ClockConfig::new_autocalc_with_error(clocks.io_clocks(), 115200) .unwrap() .0; - let mut uart = Uart::new_with_mio( + let mut uart = Uart::new_with_mio_for_uart_1( dp.uart_1, Config::new_with_clk_config(uart_clk_config), (mio_pins.mio48, mio_pins.mio49), diff --git a/zynq/examples/simple/Cargo.toml b/zynq/examples/simple/Cargo.toml index bb83f0f..7148d1f 100644 --- a/zynq/examples/simple/Cargo.toml +++ b/zynq/examples/simple/Cargo.toml @@ -17,8 +17,3 @@ embedded-io = "0.7" embedded-hal = "1" fugit = "0.3" log = "0.4" - -[profile.release] -codegen-units = 1 -debug = true -lto = true diff --git a/zynq/examples/simple/src/bin/gtc-ticks.rs b/zynq/examples/simple/src/bin/gtc-ticks.rs index bc0f0fe..d0d7fe2 100644 --- a/zynq/examples/simple/src/bin/gtc-ticks.rs +++ b/zynq/examples/simple/src/bin/gtc-ticks.rs @@ -62,7 +62,7 @@ pub fn main() -> ! { // This structure holds all MIO pins. let mio_pins = mio::Pins::new(dp.gpio); - let mut uart = Uart::new_with_mio( + let mut uart = Uart::new_with_mio_for_uart_1( dp.uart_1, Config::new_with_clk_config(uart_clk_config), (mio_pins.mio48, mio_pins.mio49), diff --git a/zynq/examples/simple/src/bin/logger.rs b/zynq/examples/simple/src/bin/logger.rs index d8e5871..31e5096 100644 --- a/zynq/examples/simple/src/bin/logger.rs +++ b/zynq/examples/simple/src/bin/logger.rs @@ -62,7 +62,7 @@ pub fn main() -> ! { gtc.enable(); let mio_pins = mio::Pins::new(dp.gpio); - let mut uart = Uart::new_with_mio( + let mut uart = Uart::new_with_mio_for_uart_1( dp.uart_1, Config::new_with_clk_config(uart_clk_config), (mio_pins.mio48, mio_pins.mio49), diff --git a/zynq/examples/zedboard/Cargo.toml b/zynq/examples/zedboard/Cargo.toml index be7424c..e680b9f 100644 --- a/zynq/examples/zedboard/Cargo.toml +++ b/zynq/examples/zedboard/Cargo.toml @@ -42,10 +42,5 @@ embassy-net = { version = "0.7", features = ["dhcpv4", "packet-trace", "medium-e embassy-sync = { version = "0.7" } # TODO: Bump as soon as new compatible smoltcp/embassy-net version is released. heapless = "0.8" -axi-uartlite = { git = "https://egit.irs.uni-stuttgart.de/rust/axi-uartlite.git" } -axi-uart16550 = { git = "https://egit.irs.uni-stuttgart.de/rust/axi-uart16550.git" } - -[profile.release] -codegen-units = 1 -debug = true -lto = true +axi-uartlite = { version = "0.1" } +axi-uart16550 = { version = "0.1" } diff --git a/zynq/examples/zedboard/src/bin/ethernet.rs b/zynq/examples/zedboard/src/bin/ethernet.rs index 8270dbd..65eb859 100644 --- a/zynq/examples/zedboard/src/bin/ethernet.rs +++ b/zynq/examples/zedboard/src/bin/ethernet.rs @@ -237,7 +237,7 @@ async fn main(spawner: Spawner) -> ! { let uart_clk_config = ClockConfig::new_autocalc_with_error(clocks.io_clocks(), 115200) .unwrap() .0; - let mut uart = Uart::new_with_mio( + let mut uart = Uart::new_with_mio_for_uart_1( dp.uart_1, Config::new_with_clk_config(uart_clk_config), (gpio_pins.mio.mio48, gpio_pins.mio.mio49), diff --git a/zynq/examples/zedboard/src/bin/l3gd20h-i2c-mio.rs b/zynq/examples/zedboard/src/bin/l3gd20h-i2c-mio.rs index 606c1d8..24db741 100644 --- a/zynq/examples/zedboard/src/bin/l3gd20h-i2c-mio.rs +++ b/zynq/examples/zedboard/src/bin/l3gd20h-i2c-mio.rs @@ -76,7 +76,7 @@ async fn main(_spawner: Spawner) -> ! { let uart_clk_config = uart::ClockConfig::new_autocalc_with_error(clocks.io_clocks(), 115200) .unwrap() .0; - let mut uart = uart::Uart::new_with_mio( + let mut uart = uart::Uart::new_with_mio_for_uart_1( dp.uart_1, uart::Config::new_with_clk_config(uart_clk_config), (gpio_pins.mio.mio48, gpio_pins.mio.mio49), diff --git a/zynq/examples/zedboard/src/bin/l3gd20h-spi-mio.rs b/zynq/examples/zedboard/src/bin/l3gd20h-spi-mio.rs index 1060902..7c887d2 100644 --- a/zynq/examples/zedboard/src/bin/l3gd20h-spi-mio.rs +++ b/zynq/examples/zedboard/src/bin/l3gd20h-spi-mio.rs @@ -86,7 +86,7 @@ async fn main(spawner: Spawner) -> ! { let uart_clk_config = uart::ClockConfig::new_autocalc_with_error(clocks.io_clocks(), 115200) .unwrap() .0; - let mut uart = uart::Uart::new_with_mio( + let mut uart = uart::Uart::new_with_mio_for_uart_1( dp.uart_1, uart::Config::new_with_clk_config(uart_clk_config), (gpio_pins.mio.mio48, gpio_pins.mio.mio49), diff --git a/zynq/examples/zedboard/src/bin/qspi.rs b/zynq/examples/zedboard/src/bin/qspi.rs index 0749462..4162ca1 100644 --- a/zynq/examples/zedboard/src/bin/qspi.rs +++ b/zynq/examples/zedboard/src/bin/qspi.rs @@ -54,7 +54,7 @@ async fn main(_spawner: Spawner) -> ! { let uart_clk_config = uart::ClockConfig::new_autocalc_with_error(clocks.io_clocks(), 115200) .unwrap() .0; - let mut uart = uart::Uart::new_with_mio( + let mut uart = uart::Uart::new_with_mio_for_uart_1( periphs.uart_1, uart::Config::new_with_clk_config(uart_clk_config), (gpio_pins.mio.mio48, gpio_pins.mio.mio49), diff --git a/zynq/examples/zedboard/src/bin/uart-blocking.rs b/zynq/examples/zedboard/src/bin/uart-blocking.rs index be38b27..25dace2 100644 --- a/zynq/examples/zedboard/src/bin/uart-blocking.rs +++ b/zynq/examples/zedboard/src/bin/uart-blocking.rs @@ -126,7 +126,7 @@ async fn main(_spawner: Spawner) -> ! { let uart_clk_config = ClockConfig::new_autocalc_with_error(clocks.io_clocks(), 115200) .unwrap() .0; - let mut log_uart = Uart::new_with_mio( + let mut log_uart = Uart::new_with_mio_for_uart_1( dp.uart_1, Config::new_with_clk_config(uart_clk_config), (gpio_pins.mio.mio48, gpio_pins.mio.mio49), @@ -151,7 +151,7 @@ async fn main(_spawner: Spawner) -> ! { // TODO: Can we determine/read the clock frequency to the FPGAs as well? let (clk_config, error) = - axi_uart16550::ClkConfig::new_autocalc_with_error(100.MHz(), 115200).unwrap(); + axi_uart16550::ClockConfig::new_autocalc_with_error(100.MHz(), 115200).unwrap(); assert!(error < 0.02); let mut uart_16550 = unsafe { AxiUart16550::new( diff --git a/zynq/examples/zedboard/src/bin/uart-non-blocking.rs b/zynq/examples/zedboard/src/bin/uart-non-blocking.rs index b4fb5a0..8965a7d 100644 --- a/zynq/examples/zedboard/src/bin/uart-non-blocking.rs +++ b/zynq/examples/zedboard/src/bin/uart-non-blocking.rs @@ -197,7 +197,7 @@ async fn main(spawner: Spawner) -> ! { let uart_clk_config = ClockConfig::new_autocalc_with_error(clocks.io_clocks(), 115200) .unwrap() .0; - let mut log_uart = Uart::new_with_mio( + let mut log_uart = Uart::new_with_mio_for_uart_1( dp.uart_1, Config::new_with_clk_config(uart_clk_config), (gpio_pins.mio.mio48, gpio_pins.mio.mio49), @@ -245,7 +245,7 @@ async fn main(spawner: Spawner) -> ! { uartlite.enable_interrupt(); let (clk_config, error) = - axi_uart16550::ClkConfig::new_autocalc_with_error(clocks.pl_clocks()[0], 115200).unwrap(); + axi_uart16550::ClockConfig::new_autocalc_with_error(clocks.pl_clocks()[0], 115200).unwrap(); assert!(error < 0.02); let _uart_16550 = unsafe { AxiUart16550::new( @@ -492,19 +492,19 @@ fn on_interrupt_axi_16550() { let iir = rx.read_iir(); if let Ok(int_id) = iir.int_id() { match int_id { - axi_uart16550::registers::IntId2::ReceiverLineStatus => { + axi_uart16550::registers::InterruptId2::ReceiverLineStatus => { let errors = rx.on_interrupt_receiver_line_status(iir); warn!("Receiver line status error: {errors:?}"); } - axi_uart16550::registers::IntId2::RxDataAvailable - | axi_uart16550::registers::IntId2::CharTimeout => { + axi_uart16550::registers::InterruptId2::RxDataAvailable + | axi_uart16550::registers::InterruptId2::CharTimeout => { read_bytes = rx.on_interrupt_data_available_or_char_timeout(int_id, &mut buf); } - axi_uart16550::registers::IntId2::ThrEmpty => { + axi_uart16550::registers::InterruptId2::ThrEmpty => { let mut tx = unsafe { axi_uart16550::Tx::steal(AXI_UAR16550_BASE_ADDR as usize) }; axi_uart16550::tx_async::on_interrupt_tx(&mut tx, 0); } - axi_uart16550::registers::IntId2::ModemStatus => (), + axi_uart16550::registers::InterruptId2::ModemStatus => (), } } // Send received RX data to main task. diff --git a/zynq/examples/zedboard/src/main.rs b/zynq/examples/zedboard/src/main.rs index b83dc7b..bd51ff1 100644 --- a/zynq/examples/zedboard/src/main.rs +++ b/zynq/examples/zedboard/src/main.rs @@ -46,7 +46,7 @@ async fn main(_spawner: Spawner) -> ! { let uart_clk_config = uart::ClockConfig::new_autocalc_with_error(clocks.io_clocks(), 115200) .unwrap() .0; - let mut uart = uart::Uart::new_with_mio( + let mut uart = uart::Uart::new_with_mio_for_uart_1( periphs.uart_1, uart::Config::new_with_clk_config(uart_clk_config), (gpio_pins.mio.mio48, gpio_pins.mio.mio49), diff --git a/zynq/zedboard-fsbl/Cargo.toml b/zynq/zedboard-fsbl/Cargo.toml index e1884e4..5eb69b7 100644 --- a/zynq/zedboard-fsbl/Cargo.toml +++ b/zynq/zedboard-fsbl/Cargo.toml @@ -20,3 +20,23 @@ embedded-hal = "1" fugit = "0.3" log = "0.4" arbitrary-int = "2" + +# cargo build/run +[profile.dev] +# default is opt-level = '0', but that makes very +# verbose machine code +opt-level = 's' +# trade compile speed for slightly better optimisations +codegen-units = 1 + +# cargo build/run --release +[profile.release] +# Optimize for size. +opt-level = 's' +# trade compile speed for slightly better optimisations +codegen-units = 1 +# Use Link Time Optimisations to further inline things across +# crates +lto = 'fat' +# Leave the debug symbols in (default is no debug info) +debug = 2 diff --git a/zynq/zedboard-fsbl/src/main.rs b/zynq/zedboard-fsbl/src/main.rs index 1680e82..1e3a1f6 100644 --- a/zynq/zedboard-fsbl/src/main.rs +++ b/zynq/zedboard-fsbl/src/main.rs @@ -94,7 +94,7 @@ pub fn main() -> ! { let uart_clk_config = ClockConfig::new_autocalc_with_error(clocks.io_clocks(), 115200) .unwrap() .0; - let mut logger_uart = Uart::new_with_mio( + let mut logger_uart = Uart::new_with_mio_for_uart_1( periphs.uart_1, Config::new_with_clk_config(uart_clk_config), (mio_pins.mio48, mio_pins.mio49), diff --git a/zynq/zedboard-qspi-flasher/src/main.rs b/zynq/zedboard-qspi-flasher/src/main.rs index dc62696..6c5dcf9 100644 --- a/zynq/zedboard-qspi-flasher/src/main.rs +++ b/zynq/zedboard-qspi-flasher/src/main.rs @@ -66,7 +66,7 @@ pub fn main() -> ! { let uart_clk_config = uart::ClockConfig::new_autocalc_with_error(clocks.io_clocks(), 115200) .unwrap() .0; - let mut uart = uart::Uart::new_with_mio( + let mut uart = uart::Uart::new_with_mio_for_uart_1( periphs.uart_1, uart::Config::new_with_clk_config(uart_clk_config), (gpio_pins.mio.mio48, gpio_pins.mio.mio49), diff --git a/zynq/zynq7000-hal/CHANGELOG.md b/zynq/zynq7000-hal/CHANGELOG.md index cebf3b4..52bae6c 100644 --- a/zynq/zynq7000-hal/CHANGELOG.md +++ b/zynq/zynq7000-hal/CHANGELOG.md @@ -8,6 +8,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). # [unreleased] +## Changed + +- Increased UART type safety by providing dedicated MIO constructors for UART 0 and UART 1 + respectively. + # [v0.1.1] 2025-10-10 Documentation fixes. diff --git a/zynq/zynq7000-hal/src/gic.rs b/zynq/zynq7000-hal/src/gic.rs index d31d4af..a523f22 100644 --- a/zynq/zynq7000-hal/src/gic.rs +++ b/zynq/zynq7000-hal/src/gic.rs @@ -10,9 +10,8 @@ use arbitrary_int::prelude::*; use aarch32_cpu::interrupt; use zynq7000::gic::{ - DistributorControlRegister, GicCpuInterfaceRegisters, GicDistributorRegisters, - InterfaceControl, InterruptSignalRegister, MmioGicCpuInterfaceRegisters, - MmioGicDistributorRegisters, PriorityRegister, + CpuInterfaceRegisters, DistributorControlRegister, DistributorRegisters, InterfaceControl, + InterruptSignalRegister, MmioCpuInterfaceRegisters, MmioDistributorRegisters, PriorityRegister, }; const SPURIOUS_INTERRUPT_ID: u32 = 1023; @@ -193,7 +192,7 @@ pub struct InvalidSgiInterruptId(pub usize); /// The flow of using this controller is as follows: /// /// 1. Create the controller using [Self::new_with_init]. You can use the [zynq7000::Peripherals] -/// structure or the [zynq7000::gic::GicCpuInterface::new_mmio] and [zynq7000::gic::GicDistributor::new_mmio] +/// structure or the [zynq7000::gic::CpuInterfaceRegisters::new_mmio] and [zynq7000::gic::DistributorRegisters::new_mmio] /// functions to retrieve the MMIO instances. The constructor configures all PL interrupts /// sensivities to high-level sensitivity and configures all sensitivities which are expected /// to have a certain value. It also sets the priority mask to 0xff by calling @@ -225,8 +224,8 @@ pub struct InvalidSgiInterruptId(pub usize); /// For the handling of the interrupts, you can use the [GicInterruptHelper] which assumes a /// properly configured GIC. pub struct GicConfigurator { - pub gicc: MmioGicCpuInterfaceRegisters<'static>, - pub gicd: MmioGicDistributorRegisters<'static>, + pub gicc: MmioCpuInterfaceRegisters<'static>, + pub gicd: MmioDistributorRegisters<'static>, } impl GicConfigurator { @@ -234,8 +233,8 @@ impl GicConfigurator { /// strongly recommended initialization routines for the GIC. #[inline] pub fn new_with_init( - gicc: MmioGicCpuInterfaceRegisters<'static>, - gicd: MmioGicDistributorRegisters<'static>, + gicc: MmioCpuInterfaceRegisters<'static>, + gicd: MmioDistributorRegisters<'static>, ) -> Self { let mut gic = GicConfigurator { gicc, gicd }; gic.initialize(); @@ -252,8 +251,8 @@ impl GicConfigurator { #[inline] pub unsafe fn steal() -> Self { GicConfigurator { - gicc: unsafe { GicCpuInterfaceRegisters::new_mmio_fixed() }, - gicd: unsafe { GicDistributorRegisters::new_mmio_fixed() }, + gicc: unsafe { CpuInterfaceRegisters::new_mmio_fixed() }, + gicd: unsafe { DistributorRegisters::new_mmio_fixed() }, } } @@ -489,12 +488,12 @@ impl GicConfigurator { /// Helper structure which should only be used inside the interrupt handler once the GIC has /// been configured with the [GicConfigurator]. -pub struct GicInterruptHelper(MmioGicCpuInterfaceRegisters<'static>); +pub struct GicInterruptHelper(MmioCpuInterfaceRegisters<'static>); impl GicInterruptHelper { /// Create the interrupt helper with the fixed GICC MMIO instance. pub const fn new() -> Self { - GicInterruptHelper(unsafe { GicCpuInterfaceRegisters::new_mmio_fixed() }) + GicInterruptHelper(unsafe { CpuInterfaceRegisters::new_mmio_fixed() }) } /// Acknowledges an interrupt by reading the IAR register and returning the interrupt context diff --git a/zynq/zynq7000-hal/src/gtc.rs b/zynq/zynq7000-hal/src/gtc.rs index 2a058f8..0acda1f 100644 --- a/zynq/zynq7000-hal/src/gtc.rs +++ b/zynq/zynq7000-hal/src/gtc.rs @@ -4,6 +4,7 @@ //! //! - [GTC ticks example](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/examples/simple/src/bin/gtc-ticks.rs) //! - [Embassy Timer Driver](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/zynq7000-embassy/src/lib.rs) +#![deny(missing_docs)] use zynq7000::gtc::MmioRegisters; use crate::{clocks::ArmClocks, time::Hertz}; @@ -20,6 +21,7 @@ pub struct GlobalTimerCounter { unsafe impl Send for GlobalTimerCounter {} +/// Convert a frequency to GTC ticks given a clock frequency. pub const fn frequency_to_ticks(clock: Hertz, frequency: Hertz) -> u32 { clock.raw().div_ceil(frequency.raw()) } @@ -38,7 +40,7 @@ impl GlobalTimerCounter { /// # Safety /// /// This function allows creating an arbitrary amount of memory-mapped peripheral drivers. - /// See the [zynq7000::gtc::GlobalTimerCounter::new_mmio] docs for more safety information. + /// See the [zynq7000::gtc::Registers::new_mmio] docs for more safety information. #[inline] pub const unsafe fn steal_fixed(cpu_3x2x_clk: Option) -> Self { Self { @@ -47,6 +49,7 @@ impl GlobalTimerCounter { } } + /// Set the CPU 3x2x clock frequency. #[inline] pub fn set_cpu_3x2x_clock(&mut self, clock: Hertz) { self.cpu_3x2x_clock = Some(clock); @@ -85,6 +88,7 @@ impl GlobalTimerCounter { }); } + /// Convert a frequency to GTC ticks. pub fn frequency_to_ticks(&self, frequency: Hertz) -> u32 { if self.cpu_3x2x_clock.is_none() { return 0; @@ -99,12 +103,14 @@ impl GlobalTimerCounter { self.regs.write_auto_increment(value); } + /// Set auto-increment value for a given frequency. #[inline] pub fn set_auto_increment_value_for_frequency(&mut self, frequency: Hertz) { self.regs .write_auto_increment(self.frequency_to_ticks(frequency)); } + /// Enable the GTC. #[inline] pub fn enable(&mut self) { self.regs.modify_ctrl(|mut ctrl| { @@ -113,6 +119,7 @@ impl GlobalTimerCounter { }); } + /// Enable auto-increment. #[inline] pub fn enable_auto_increment(&mut self) { self.regs.modify_ctrl(|mut ctrl| { @@ -121,6 +128,7 @@ impl GlobalTimerCounter { }); } + /// Set a pre-scaler. #[inline] pub fn set_prescaler(&mut self, prescaler: u8) { self.regs.modify_ctrl(|mut ctrl| { @@ -129,6 +137,7 @@ impl GlobalTimerCounter { }); } + /// Disable the GTC. #[inline] pub fn disable(&mut self) { self.regs.modify_ctrl(|mut ctrl| { diff --git a/zynq/zynq7000-hal/src/l2_cache.rs b/zynq/zynq7000-hal/src/l2_cache.rs index 238fcfc..e350a6e 100644 --- a/zynq/zynq7000-hal/src/l2_cache.rs +++ b/zynq/zynq7000-hal/src/l2_cache.rs @@ -1,4 +1,5 @@ //! # L2 cache module +#![deny(missing_docs)] use core::sync::atomic::compiler_fence; use arbitrary_int::{u2, u3}; @@ -44,7 +45,7 @@ pub const DEFAULT_DATA_RAM_LATENCY: LatencyConfig = LatencyConfig::builder() .with_setup_latency(u3::new(0b001)) .build(); -// SLCR L2C ram configuration. +/// SLCR L2C RAM configuration magic value. pub const SLCR_L2C_CONFIG_MAGIC_VALUE: u32 = 0x00020202; /// Similar to [init], but uses Xilinx/AMD defaults for the latency configurations. diff --git a/zynq/zynq7000-hal/src/priv_tim.rs b/zynq/zynq7000-hal/src/priv_tim.rs index 212eeaa..36ad87c 100644 --- a/zynq/zynq7000-hal/src/priv_tim.rs +++ b/zynq/zynq7000-hal/src/priv_tim.rs @@ -3,6 +3,7 @@ //! ## Examples //! //! - Private timer as delay provider in [blinky](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/examples/simple/src/bin/blinky.rs) +#![deny(missing_docs)] use core::{marker::PhantomData, sync::atomic::AtomicBool}; use zynq7000::priv_tim::InterruptStatus; @@ -62,11 +63,13 @@ impl CpuPrivateTimer { self.regs.write_reload(value); } + /// Write the current counter value. #[inline] pub fn write_counter(&mut self, value: u32) { self.regs.write_counter(value); } + /// Read the current counter value. #[inline] pub fn counter(&self) -> u32 { self.regs.read_counter() diff --git a/zynq/zynq7000-hal/src/slcr.rs b/zynq/zynq7000-hal/src/slcr.rs index f72f80e..ce921eb 100644 --- a/zynq/zynq7000-hal/src/slcr.rs +++ b/zynq/zynq7000-hal/src/slcr.rs @@ -1,9 +1,13 @@ //! # System Level Control Register (SLCR) module +#![deny(missing_docs)] use zynq7000::slcr::MmioRegisters; +/// Lock key for the SLCR registers. pub const LOCK_KEY: u32 = 0x767B; +/// Unlock key for the SLCR registers. pub const UNLOCK_KEY: u32 = 0xDF0D; +/// SLCR helper structure. pub struct Slcr(zynq7000::slcr::MmioRegisters<'static>); impl Slcr { @@ -12,7 +16,7 @@ impl Slcr { /// # Safety /// /// This method unsafely steals the SLCR MMIO block and then calls a user provided function - /// with the [SLCR MMIO][MmioSlcr] block as an input argument. It is the user's responsibility + /// with the [SLCR MMIO][MmioRegisters] block as an input argument. It is the user's responsibility /// that the SLCR is not used concurrently in a way which leads to data races. pub unsafe fn with)>(f: F) { let mut slcr = unsafe { zynq7000::slcr::Registers::new_mmio_fixed() }; @@ -47,7 +51,7 @@ impl Slcr { /// Modify the SLCR register. /// /// This method unlocks the SLCR registers and then calls a user provided function - /// with the [SLCR MMIO][MmioSlcr] block as an input argument. This allows the user + /// with the [SLCR MMIO][MmioRegisters] block as an input argument. This allows the user /// to safely modify the SLCR registers. The SLCR will be locked afte the operation. pub fn modify(&mut self, mut f: F) { self.0.write_unlock(UNLOCK_KEY); diff --git a/zynq/zynq7000-hal/src/time.rs b/zynq/zynq7000-hal/src/time.rs index 0cfcf6d..6326e12 100644 --- a/zynq/zynq7000-hal/src/time.rs +++ b/zynq/zynq7000-hal/src/time.rs @@ -1,17 +1,21 @@ //! # Time units +#![deny(missing_docs)] // Frequency based /// Hertz pub type Hertz = fugit::HertzU32; +/// Type alias for Hertz. pub type Hz = Hertz; /// KiloHertz pub type KiloHertz = fugit::KilohertzU32; +/// Type alias for Kilo Hertz. pub type KHz = KiloHertz; /// MegaHertz pub type MegaHertz = fugit::MegahertzU32; +/// Type alias for Mega Hertz. pub type MHz = MegaHertz; // Period based diff --git a/zynq/zynq7000-hal/src/ttc.rs b/zynq/zynq7000-hal/src/ttc.rs index e1b9ea3..38fb421 100644 --- a/zynq/zynq7000-hal/src/ttc.rs +++ b/zynq/zynq7000-hal/src/ttc.rs @@ -5,7 +5,7 @@ //! ## Examples //! //! - [PWM](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/examples/embassy/src/bin/pwm.rs) - +#![deny(missing_docs)] use core::convert::Infallible; use arbitrary_int::{prelude::*, u3, u4}; @@ -25,19 +25,28 @@ use crate::{ /// Each TTC consists of three independent timers/counters. #[derive(Debug, Copy, Clone)] pub enum TtcId { + /// TTC 0. Ttc0 = 0, + /// TTC 1. Ttc1 = 1, } +/// Each TTC has 3 channels. #[derive(Debug, Copy, Clone)] pub enum ChannelId { + /// Channel 0. Ch0 = 0, + /// Channel 1. Ch1 = 1, + /// Channel 2. Ch2 = 2, } +/// Common trait for TTC register blocks. pub trait PsTtc { + /// Register block. fn reg_block(&self) -> MmioRegisters<'static>; + /// ID. fn id(&self) -> Option; } @@ -59,13 +68,18 @@ impl PsTtc for MmioRegisters<'static> { } } +/// TTC pin configuration pub const TTC_MUX_CONF: MuxConfig = MuxConfig::new_with_l3(u3::new(0b110)); +/// Input clock pin trait. pub trait ClockInPin: MioPin { + /// TTC ID. const ID: TtcId; } +/// Output wave pin trait. pub trait WaveOutPin: MioPin { + /// TTC ID. const ID: TtcId; } @@ -121,9 +135,13 @@ impl WaveOutPin for Pin { const ID: TtcId = TtcId::Ttc1; } +/// Triple-timer counter (TTC) peripheral. pub struct Ttc { + /// TTC channel 0. pub ch0: TtcChannel, + /// TTC channel 1. pub ch1: TtcChannel, + /// TTC channel 2. pub ch2: TtcChannel, } @@ -151,16 +169,20 @@ impl Ttc { } } +/// Single TTC channel. pub struct TtcChannel { regs: MmioRegisters<'static>, id: ChannelId, } impl TtcChannel { + /// Raw access to the TTC MMIO registers. + #[inline] pub fn regs_mut(&mut self) -> &mut MmioRegisters<'static> { &mut self.regs } + /// Read the current counter value. #[inline] pub fn read_counter(&self) -> u16 { self.regs @@ -169,27 +191,36 @@ impl TtcChannel { .count() } + /// Channel ID. + #[inline] pub fn id(&self) -> ChannelId { self.id } } +/// Invalid TTC pin configuration error. #[derive(Debug, thiserror::Error)] #[error("invalid TTC pin configuration")] pub struct InvalidTtcPinConfigError(pub MuxConfig); +/// Frequency is zero error. #[derive(Debug, thiserror::Error)] #[error("frequency is zero")] pub struct FrequencyIsZeroError; +/// TTC construction error. #[derive(Debug, thiserror::Error)] pub enum TtcConstructionError { + /// Invalid TTC pin configuration. #[error("invalid TTC pin configuration")] InvalidTtcPinConfig(#[from] InvalidTtcPinConfigError), + /// Frequency is zero. #[error("frequency is zero")] FrequencyIsZero(#[from] FrequencyIsZeroError), } +/// Calculate prescaler register value and interval ticks for a given reference clock and +/// frequency. pub fn calc_prescaler_reg_and_interval_ticks(mut ref_clk: Hertz, freq: Hertz) -> (Option, u16) { // TODO: Can this be optimized? let mut prescaler: Option = None; @@ -210,6 +241,7 @@ pub fn calc_prescaler_reg_and_interval_ticks(mut ref_clk: Hertz, freq: Hertz) -> (prescaler.map(|v| u4::new(v as u8)), tick_val as u16) } +/// PWM driver using a TTC channel. pub struct Pwm { channel: TtcChannel, ref_clk: Hertz, @@ -266,11 +298,13 @@ impl Pwm { Ok(()) } + /// Mutable access to the underlying TTC channel. #[inline] pub fn ttc_channel_mut(&mut self) -> &mut TtcChannel { &mut self.channel } + /// Maximum duty cycle value. #[inline] pub fn max_duty_cycle(&self) -> u16 { self.channel @@ -280,6 +314,7 @@ impl Pwm { .value() } + /// Set duty cycle value. #[inline] pub fn set_duty_cycle(&mut self, duty: u16) { let id = self.channel.id() as usize; diff --git a/zynq/zynq7000-hal/src/uart/mod.rs b/zynq/zynq7000-hal/src/uart/mod.rs index 7eb390f..38e143a 100644 --- a/zynq/zynq7000-hal/src/uart/mod.rs +++ b/zynq/zynq7000-hal/src/uart/mod.rs @@ -7,6 +7,7 @@ //! - [Logger through UART](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/examples/simple/src/bin/logger.rs) //! - [Zedboard Blocking UART](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/examples/zedboard/src/bin/uart-blocking.rs) //! - [Zedboard Non-Blocking UART](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq/examples/zedboard/src/bin/uart-non-blocking.rs) +#![deny(missing_docs)] use core::convert::Infallible; use arbitrary_int::u3; @@ -49,18 +50,27 @@ pub use tx_async::*; pub mod rx; pub use rx::*; +/// FIFO depth of the UART peripheral. pub const FIFO_DEPTH: usize = 64; +/// Default RX trigger level. pub const DEFAULT_RX_TRIGGER_LEVEL: u8 = 32; +/// UART pin configuration. pub const UART_MUX_CONF: MuxConfig = MuxConfig::new_with_l3(u3::new(0b111)); +/// UART ID. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum UartId { + /// UART 0. Uart0 = 0, + /// UART 1. Uart1 = 1, } +/// Common trait for PS UART peripherals. pub trait PsUart { + /// UART register block. fn reg_block(&self) -> MmioRegisters<'static>; + /// UART ID. fn uart_id(&self) -> Option; } @@ -95,38 +105,57 @@ impl UartId { } } -pub trait RxPin: MioPin { - const UART_IDX: UartId; +/// Receiver (RX) pin for UART 0. +pub trait RxPin0: MioPin { + /// UART index. + const UART_IDX: UartId = UartId::Uart0; } -pub trait TxPin: MioPin { - const UART_IDX: UartId; +/// Transmitter (TX) pin for UART 0. +pub trait TxPin0: MioPin { + /// UART index. + const UART_IDX: UartId = UartId::Uart0; } -pub trait UartPins {} +/// Receiver (RX) pin for UART 1. +pub trait RxPin1: MioPin { + /// UART index. + const UART_IDX: UartId = UartId::Uart0; +} +/// Transmitter (TX) pin for UART 1. +pub trait TxPin1: MioPin { + /// UART index. + const UART_IDX: UartId = UartId::Uart0; +} +/// UART pin pair trait for UART 0. +pub trait UartPins0 {} + +/// UART pin pair trait for UART 1. +pub trait UartPins1 {} + +/// Divisor zero error. #[derive(Debug, thiserror::Error)] #[error("divisor is zero")] pub struct DivisorZero; macro_rules! pin_pairs { - ($UartPeriph:path, ($( [$(#[$meta:meta], )? $TxMio:ident, $RxMio:ident] ),+ $(,)? )) => { + ($index:literal, $UartPeriph:path, ($( [$(#[$meta:meta], )? $TxMio:ident, $RxMio:ident] ),+ $(,)? )) => { $( - $( #[$meta] )? - impl TxPin for Pin<$TxMio> { - const UART_IDX: UartId = $UartPeriph; - } + paste::paste! { + $( #[$meta] )? + impl [] for Pin<$TxMio> {} - $( #[$meta] )? - impl RxPin for Pin<$RxMio> { - const UART_IDX: UartId = $UartPeriph; - } + $( #[$meta] )? + impl [] for Pin<$RxMio> {} - impl UartPins for (Pin<$TxMio>, Pin<$RxMio>) {} + impl [] for (Pin<$TxMio>, Pin<$RxMio>) {} + } )+ }; } pin_pairs!( + 0, UartId::Uart0, ( [Mio11, Mio10], @@ -144,7 +173,7 @@ pin_pairs!( ); pin_pairs!( - UartId::Uart1, + 1, UartId::Uart1, ( [Mio8, Mio9], [Mio12, Mio13], @@ -166,38 +195,53 @@ pub const MAX_BAUD_RATE: u32 = 6240000; /// Based on values provided by the vendor library. pub const MIN_BAUD_RATE: u32 = 110; +/// Maximum acceptable baud rate error rate (0.5 %). pub const MAX_BAUDERROR_RATE: f32 = 0.005; +/// Parity configuration. #[derive(Debug, Default, Clone, Copy)] pub enum Parity { + /// Even parity. Even, + /// Odd parity. Odd, + /// No parity (default). #[default] None, } +/// Stopbit configuration. #[derive(Debug, Default, Clone, Copy)] pub enum Stopbits { + /// One stop bit (default). #[default] One, + /// 1.5 stopbits. OnePointFive, + /// 2 stopbits. Two, } +/// Character length configuration. #[derive(Debug, Default, Clone, Copy)] pub enum CharLen { + /// 6 bits. SixBits, + /// 7 bits. SevenBits, + /// 8 bits (default). #[default] EightBits, } +/// Clock configuration for baud rate generation. #[derive(Debug, Clone, Copy)] pub struct ClockConfig { cd: u16, bdiv: u8, } +/// Calculate all viable clock configurations. #[cfg(feature = "alloc")] pub fn calculate_viable_configs( mut uart_clk: Hertz, @@ -265,6 +309,7 @@ pub fn calculate_raw_baud_cfg_smallest_error( } impl ClockConfig { + /// Constructor. #[inline] pub const fn new(cd: u16, bdiv: u8) -> Result { if cd == 0 { @@ -285,6 +330,7 @@ impl ClockConfig { Self::new_autocalc_generic(io_clks, ClockSelect::UartRefClk, target_baud) } + /// New generic autocalculating constructor. pub fn new_autocalc_generic( io_clks: &IoClocks, clk_sel: ClockSelect, @@ -293,6 +339,7 @@ impl ClockConfig { Self::new_autocalc_with_raw_clk(io_clks.uart_clk(), clk_sel, target_baud) } + /// New generic autocalculating constructor using a raw UART Input clock. pub fn new_autocalc_with_raw_clk( uart_clk: Hertz, clk_sel: ClockSelect, @@ -301,21 +348,25 @@ impl ClockConfig { calculate_raw_baud_cfg_smallest_error(uart_clk, clk_sel, target_baud) } + /// CD value. #[inline] pub const fn cd(&self) -> u16 { self.cd } + /// Baud divisor value. #[inline] pub const fn bdiv(&self) -> u8 { self.bdiv } + /// Rounded baudrate. #[inline] pub fn rounded_baud(&self, sel_clk: Hertz) -> u32 { round(self.actual_baud(sel_clk)) as u32 } + /// Actual baudrate. #[inline] pub fn actual_baud(&self, sel_clk: Hertz) -> f64 { sel_clk.raw() as f64 / (self.cd as f64 * (self.bdiv + 1) as f64) @@ -329,6 +380,7 @@ impl Default for ClockConfig { } } +/// UART configuration. #[derive(Debug)] pub struct Config { clk_config: ClockConfig, @@ -340,6 +392,7 @@ pub struct Config { } impl Config { + /// Create a new configuration from a given clock configuartion. pub fn new_with_clk_config(clk_config: ClockConfig) -> Self { Self::new( clk_config, @@ -351,6 +404,7 @@ impl Config { ) } + /// Constructor. #[inline] pub const fn new( clk_config: ClockConfig, @@ -370,54 +424,63 @@ impl Config { } } + /// Raw clock configuration. #[inline] pub const fn raw_clk_config(&self) -> ClockConfig { self.clk_config } + /// Character mode. #[inline] pub const fn chmode(&self) -> ChMode { self.chmode } + /// Parity configuration. #[inline] pub const fn parity(&self) -> Parity { self.parity } + /// Stopbits configuration. #[inline] pub const fn stopbits(&self) -> Stopbits { self.stopbits } + /// Character length configuration. #[inline] - pub const fn chrl(&self) -> CharLen { + pub const fn charlen(&self) -> CharLen { self.chrl } + /// Clock select configuration. #[inline] pub const fn clksel(&self) -> ClockSelect { self.clk_sel } } -// TODO: Impl Debug +/// UART peripheral driver. +#[derive(Debug)] pub struct Uart { rx: Rx, tx: Tx, cfg: Config, } +/// Invalid PS UART error. #[derive(Debug, thiserror::Error)] #[error("invalid UART ID")] pub struct InvalidPsUart; +/// UART construction error. #[derive(Debug, thiserror::Error)] pub enum UartConstructionError { + /// Invalid PS UART error. #[error("invalid UART ID")] InvalidPsUart(#[from] InvalidPsUart), - #[error("missmatch between pins index and passed index")] - IdxMissmatch, + /// Invalid pin configuration. #[error("invalid pin mux conf for UART")] InvalidMuxConf(MuxConfig), } @@ -439,21 +502,46 @@ impl Uart { )) } - /// This is the constructor to use the PS UART with MIO pins. - pub fn new_with_mio( + /// This is the constructor to use the PS UART with MIO pins for UART 0. + pub fn new_with_mio_for_uart_0( uart: impl PsUart, cfg: Config, pins: (TxPinI, RxPinI), ) -> Result where - (TxPinI, RxPinI): UartPins, + (TxPinI, RxPinI): UartPins0, { let id = uart.uart_id(); if id.is_none() { return Err(InvalidPsUart.into()); } - if id.unwrap() != TxPinI::UART_IDX || id.unwrap() != RxPinI::UART_IDX { - return Err(UartConstructionError::IdxMissmatch); + if id.unwrap() != UartId::Uart0 { + return Err(InvalidPsUart.into()); + } + IoPeriphPin::new(pins.0, UART_MUX_CONF, None); + IoPeriphPin::new(pins.1, UART_MUX_CONF, None); + Ok(Self::new_generic_unchecked( + uart.reg_block(), + id.unwrap(), + cfg, + )) + } + + /// This is the constructor to use the PS UART with MIO pins for UART 1. + pub fn new_with_mio_for_uart_1( + uart: impl PsUart, + cfg: Config, + pins: (TxPinI, RxPinI), + ) -> Result + where + (TxPinI, RxPinI): UartPins1, + { + let id = uart.uart_id(); + if id.is_none() { + return Err(InvalidPsUart.into()); + } + if id.unwrap() != UartId::Uart1 { + return Err(InvalidPsUart.into()); } IoPeriphPin::new(pins.0, UART_MUX_CONF, None); IoPeriphPin::new(pins.1, UART_MUX_CONF, None); @@ -549,6 +637,7 @@ impl Uart { } } + /// Set character mode. #[inline] pub fn set_mode(&mut self, mode: ChMode) { self.regs().modify_mr(|mut mr| { @@ -557,16 +646,19 @@ impl Uart { }); } + /// Raw access to the UART registers. #[inline] pub const fn regs(&mut self) -> &mut MmioRegisters<'static> { &mut self.rx.regs } + /// Configuration. #[inline] pub const fn cfg(&self) -> &Config { &self.cfg } + /// Split into TX and RX halves. #[inline] pub const fn split(self) -> (Tx, Rx) { (self.tx, self.rx) diff --git a/zynq/zynq7000-hal/src/uart/rx.rs b/zynq/zynq7000-hal/src/uart/rx.rs index 6c2c9c6..0ea352b 100644 --- a/zynq/zynq7000-hal/src/uart/rx.rs +++ b/zynq/zynq7000-hal/src/uart/rx.rs @@ -1,3 +1,4 @@ +//! # Receiver (RX) support module use core::convert::Infallible; use arbitrary_int::prelude::*; @@ -5,12 +6,23 @@ use zynq7000::uart::{InterruptControl, InterruptStatus, MmioRegisters}; use super::FIFO_DEPTH; +/// Receiver (RX) driver. pub struct Rx { pub(crate) regs: MmioRegisters<'static>, } -// TODO: Remove once this is impelemnted for MmioUart + +impl core::fmt::Debug for Rx { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("Rx").finish_non_exhaustive() + } +} + +/// # Safety +/// +/// This is not a CPU specific register block. unsafe impl Send for Rx {} +/// RX errors structure. #[derive(Debug, Default, Clone, Copy)] pub struct RxErrors { framing: bool, @@ -19,20 +31,26 @@ pub struct RxErrors { } impl RxErrors { + /// Framing error occurred. #[inline] pub const fn framing(&self) -> bool { self.framing } + + /// Overrun error occurred. #[inline] pub const fn overrun(&self) -> bool { self.overrun } + + /// Parity error occurred. #[inline] pub const fn parity(&self) -> bool { self.parity } } +/// RX interrupt result structure. #[derive(Debug, Default)] pub struct RxInterruptResult { read_bytes: usize, @@ -40,16 +58,19 @@ pub struct RxInterruptResult { } impl RxInterruptResult { + /// Bytes read during the interrupt. pub fn read_bytes(&self) -> usize { self.read_bytes } + /// Errors occurred during reception. pub fn errors(&self) -> Option { self.errors } } impl Rx { + /// Read one byte from the FIFO in a non-blocking manner. #[inline] pub fn read_fifo(&mut self) -> nb::Result { if self.regs.read_sr().rx_empty() { @@ -58,6 +79,7 @@ impl Rx { Ok(self.regs.read_fifo().fifo()) } + /// Read one byte from the FIFO without checking if data is available. #[inline(always)] pub fn read_fifo_unchecked(&mut self) -> u8 { self.regs.read_fifo().fifo() @@ -74,6 +96,7 @@ impl Rx { self.regs.write_rx_tout(rto as u32); } + /// Perform a soft-reset of the RX side of the UART. #[inline] pub fn soft_reset(&mut self) { self.regs.modify_cr(|mut cr| { @@ -121,6 +144,9 @@ impl Rx { ); } + /// This function should be called from the UART interrupt handler. + /// + /// It reads all available data from the RX FIFO into the provided buffer. pub fn on_interrupt( &mut self, buf: &mut [u8; FIFO_DEPTH], @@ -180,7 +206,7 @@ impl Rx { result } - // This clears all RX related interrupts. + /// This clears all RX related interrupts. #[inline] pub fn clear_interrupts(&mut self) { self.regs.write_isr( diff --git a/zynq/zynq7000-hal/src/uart/tx.rs b/zynq/zynq7000-hal/src/uart/tx.rs index 6685114..7381eef 100644 --- a/zynq/zynq7000-hal/src/uart/tx.rs +++ b/zynq/zynq7000-hal/src/uart/tx.rs @@ -1,14 +1,22 @@ +//! # Transmitter (TX) support module use core::convert::Infallible; use zynq7000::uart::{Fifo, InterruptControl, InterruptStatus, MmioRegisters}; use super::UartId; +/// Transmitter (TX) driver. pub struct Tx { pub(crate) regs: MmioRegisters<'static>, pub(crate) idx: UartId, } +impl core::fmt::Debug for Tx { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("Tx").field("idx", &self.idx).finish() + } +} + impl Tx { /// Steal the TX side of the UART for a given UART index. /// @@ -23,16 +31,21 @@ impl Tx { } } + /// UART index. #[inline] pub const fn uart_idx(&self) -> UartId { self.idx } + /// Direct access to the UART MMIO registers. #[inline] pub const fn regs(&mut self) -> &mut MmioRegisters<'static> { &mut self.regs } + /// Write a byte to the TX FIFO. + /// + /// [nb] API which returns [nb::Error::WouldBlock] if the FIFO is full. #[inline] pub fn write_fifo(&mut self, word: u8) -> nb::Result<(), Infallible> { if self.regs.read_sr().tx_full() { @@ -65,6 +78,7 @@ impl Tx { }); } + /// Performs a soft-reset of the TX side of the UART. #[inline] pub fn soft_reset(&mut self) { self.regs.modify_cr(|mut val| { @@ -78,10 +92,12 @@ impl Tx { } } + /// Flushes the TX FIFO by blocking until it is empty. pub fn flush(&mut self) { while !self.regs.read_sr().tx_empty() {} } + /// Write a byte to the TX FIFO without checking if there is space available. #[inline] pub fn write_fifo_unchecked(&mut self, word: u8) { self.regs.write_fifo(Fifo::new_with_raw_value(word as u32)); diff --git a/zynq/zynq7000-hal/src/uart/tx_async.rs b/zynq/zynq7000-hal/src/uart/tx_async.rs index 3033123..f9caeb3 100644 --- a/zynq/zynq7000-hal/src/uart/tx_async.rs +++ b/zynq/zynq7000-hal/src/uart/tx_async.rs @@ -1,3 +1,4 @@ +//! Asynchronous UART transmitter (TX) implementation. use core::{cell::RefCell, convert::Infallible, sync::atomic::AtomicBool}; use critical_section::Mutex; @@ -6,14 +7,6 @@ use raw_slice::RawBufSlice; use crate::uart::{FIFO_DEPTH, Tx, UartId}; -#[derive(Debug)] -pub enum TransferType { - Read, - Write, - Transfer, - TransferInPlace, -} - static UART_TX_WAKERS: [AtomicWaker; 2] = [const { AtomicWaker::new() }; 2]; static TX_CONTEXTS: [Mutex>; 2] = [const { Mutex::new(RefCell::new(TxContext::new())) }; 2]; @@ -84,7 +77,7 @@ pub fn on_interrupt_tx(peripheral: UartId) { } #[derive(Debug, Copy, Clone)] -pub struct TxContext { +struct TxContext { progress: usize, tx_overrun: bool, slice: RawBufSlice, @@ -101,6 +94,7 @@ impl TxContext { } } +/// Transmission future for UART TX. pub struct TxFuture { id: UartId, } @@ -164,11 +158,13 @@ impl Drop for TxFuture { } } +/// Asynchronous UART transmitter (TX) driver. pub struct TxAsync { tx: Tx, } impl TxAsync { + /// Constructor. pub fn new(tx: Tx) -> Self { Self { tx } } @@ -185,6 +181,7 @@ impl TxAsync { fut.await } + /// Release the underlying blocking TX driver. pub fn release(self) -> Tx { self.tx } diff --git a/zynq/zynq7000/src/gic.rs b/zynq/zynq7000/src/gic.rs index f002d15..73bb1cc 100644 --- a/zynq/zynq7000/src/gic.rs +++ b/zynq/zynq7000/src/gic.rs @@ -40,10 +40,13 @@ impl TypeRegister { pub type Typer = TypeRegister; +#[deprecated(note = "Use DistributorRegisters instead")] +pub type GicDistributorTyper = DistributorRegisters; + /// GIC Distributor registers. #[derive(derive_mmio::Mmio)] #[repr(C, align(8))] -pub struct GicDistributorRegisters { +pub struct DistributorRegisters { /// Distributor Control Register pub dcr: DistributorControlRegister, /// Interrupt Controller Type Register @@ -109,9 +112,9 @@ pub struct GicDistributorRegisters { pub cidr: [u32; 4], } -const_assert_eq!(core::mem::size_of::(), 0x1000); +const_assert_eq!(core::mem::size_of::(), 0x1000); -impl GicDistributorRegisters { +impl DistributorRegisters { /// Create a new Global Interrupt Controller Distributor MMIO instance at the fixed address of /// the processing system. /// @@ -121,7 +124,7 @@ impl GicDistributorRegisters { /// from multiple threads. The user must ensure that concurrent accesses are safe and do not /// interfere with each other. #[inline] - pub const unsafe fn new_mmio_fixed() -> MmioGicDistributorRegisters<'static> { + pub const unsafe fn new_mmio_fixed() -> MmioDistributorRegisters<'static> { unsafe { Self::new_mmio_at(GICD_BASE_ADDR) } } } @@ -157,10 +160,13 @@ pub struct InterruptSignalRegister { ack_int_id: u10, } +#[deprecated(note = "Use DistributorRegisters instead")] +pub type GicCpuInterfaceIar = CpuInterfaceRegisters; + /// GIC CPU interface registers. #[derive(derive_mmio::Mmio)] #[repr(C, align(8))] -pub struct GicCpuInterfaceRegisters { +pub struct CpuInterfaceRegisters { /// CPU Interface Control Register (ICR). pub icr: InterfaceControl, /// Interrupt Priority Mask Register. @@ -183,9 +189,9 @@ pub struct GicCpuInterfaceRegisters { pub iidr: u32, } -const_assert_eq!(core::mem::size_of::(), 0x100); +const_assert_eq!(core::mem::size_of::(), 0x100); -impl GicCpuInterfaceRegisters { +impl CpuInterfaceRegisters { /// Create a new Global Interrupt Controller CPU MMIO instance at the fixed address of the /// processing system. /// @@ -195,7 +201,7 @@ impl GicCpuInterfaceRegisters { /// from multiple threads. The user must ensure that concurrent accesses are safe and do not /// interfere with each other. #[inline] - pub const unsafe fn new_mmio_fixed() -> MmioGicCpuInterfaceRegisters<'static> { + pub const unsafe fn new_mmio_fixed() -> MmioCpuInterfaceRegisters<'static> { unsafe { Self::new_mmio_at(GICC_BASE_ADDR) } } } diff --git a/zynq/zynq7000/src/lib.rs b/zynq/zynq7000/src/lib.rs index 96cc85a..379654d 100644 --- a/zynq/zynq7000/src/lib.rs +++ b/zynq/zynq7000/src/lib.rs @@ -43,8 +43,8 @@ static PERIPHERALS_TAKEN: AtomicBool = AtomicBool::new(false); /// The [`svd2rust` documentation](https://docs.rs/svd2rust/latest/svd2rust/#peripheral-api) /// provides some more information about this. pub struct Peripherals { - pub gicc: gic::MmioGicCpuInterfaceRegisters<'static>, - pub gicd: gic::MmioGicDistributorRegisters<'static>, + pub gicc: gic::MmioCpuInterfaceRegisters<'static>, + pub gicd: gic::MmioDistributorRegisters<'static>, pub l2c: l2_cache::MmioRegisters<'static>, pub ddrc: ddrc::MmioRegisters<'static>, pub uart_0: uart::MmioRegisters<'static>, @@ -83,8 +83,8 @@ impl Peripherals { pub unsafe fn steal() -> Self { unsafe { Self { - gicc: gic::GicCpuInterfaceRegisters::new_mmio_fixed(), - gicd: gic::GicDistributorRegisters::new_mmio_fixed(), + gicc: gic::CpuInterfaceRegisters::new_mmio_fixed(), + gicd: gic::DistributorRegisters::new_mmio_fixed(), l2c: l2_cache::Registers::new_mmio_fixed(), ddrc: ddrc::Registers::new_mmio_fixed(), uart_0: uart::Registers::new_mmio_fixed_0(), diff --git a/zynq/zynq7000/src/mpcore.rs b/zynq/zynq7000/src/mpcore.rs index 8b875bb..6bff3af 100644 --- a/zynq/zynq7000/src/mpcore.rs +++ b/zynq/zynq7000/src/mpcore.rs @@ -5,8 +5,8 @@ use static_assertions::const_assert_eq; use crate::{ gic::{ - GicCpuInterfaceRegisters, GicDistributorRegisters, MmioGicCpuInterfaceRegisters, - MmioGicDistributorRegisters, + CpuInterfaceRegisters, DistributorRegisters, MmioCpuInterfaceRegisters, + MmioDistributorRegisters, }, gtc::{MmioRegisters, Registers}, }; @@ -57,7 +57,7 @@ pub struct MpCore { _reserved_0: [u32; 0x2A], #[mmio(Inner)] - gicc: GicCpuInterfaceRegisters, + gicc: CpuInterfaceRegisters, #[mmio(Inner)] gt: Registers, @@ -81,7 +81,7 @@ pub struct MpCore { _reserved_3: [u32; 0x272], #[mmio(Inner)] - gicd: GicDistributorRegisters, + gicd: DistributorRegisters, } const_assert_eq!(core::mem::size_of::(), 0x2000);