UART and docs update
Some checks are pending
ci / Check build (push) Waiting to run
ci / Check formatting (push) Waiting to run
ci / Check Documentation Build (push) Waiting to run
ci / Clippy (push) Waiting to run
ci / Check build (pull_request) Waiting to run
ci / Check formatting (pull_request) Waiting to run
ci / Check Documentation Build (pull_request) Waiting to run
ci / Clippy (pull_request) Waiting to run
Some checks are pending
ci / Check build (push) Waiting to run
ci / Check formatting (push) Waiting to run
ci / Check Documentation Build (push) Waiting to run
ci / Clippy (push) Waiting to run
ci / Check build (pull_request) Waiting to run
ci / Check formatting (pull_request) Waiting to run
ci / Check Documentation Build (pull_request) Waiting to run
ci / Clippy (pull_request) Waiting to run
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<Hertz>) -> 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| {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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: FnOnce(&mut MmioRegisters<'static>)>(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<F: FnMut(&mut MmioRegisters)>(&mut self, mut f: F) {
|
||||
self.0.write_unlock(UNLOCK_KEY);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<TtcId>;
|
||||
}
|
||||
|
||||
@@ -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<Mio40> {
|
||||
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<u4>, u16) {
|
||||
// TODO: Can this be optimized?
|
||||
let mut prescaler: Option<u32> = 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;
|
||||
|
||||
@@ -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<UartId>;
|
||||
}
|
||||
|
||||
@@ -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] ),+ $(,)? )) => {
|
||||
$(
|
||||
paste::paste! {
|
||||
$( #[$meta] )?
|
||||
impl TxPin for Pin<$TxMio> {
|
||||
const UART_IDX: UartId = $UartPeriph;
|
||||
}
|
||||
impl [<TxPin $index>] for Pin<$TxMio> {}
|
||||
|
||||
$( #[$meta] )?
|
||||
impl RxPin for Pin<$RxMio> {
|
||||
const UART_IDX: UartId = $UartPeriph;
|
||||
}
|
||||
impl [<RxPin $index>] for Pin<$RxMio> {}
|
||||
|
||||
impl UartPins for (Pin<$TxMio>, Pin<$RxMio>) {}
|
||||
impl [<UartPins $index>] 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<Self, DivisorZero> {
|
||||
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<TxPinI: TxPin, RxPinI: RxPin>(
|
||||
/// This is the constructor to use the PS UART with MIO pins for UART 0.
|
||||
pub fn new_with_mio_for_uart_0<TxPinI: TxPin0, RxPinI: RxPin0>(
|
||||
uart: impl PsUart,
|
||||
cfg: Config,
|
||||
pins: (TxPinI, RxPinI),
|
||||
) -> Result<Self, UartConstructionError>
|
||||
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<TxPinI: TxPin1, RxPinI: RxPin1>(
|
||||
uart: impl PsUart,
|
||||
cfg: Config,
|
||||
pins: (TxPinI, RxPinI),
|
||||
) -> Result<Self, UartConstructionError>
|
||||
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)
|
||||
|
||||
@@ -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<RxErrors> {
|
||||
self.errors
|
||||
}
|
||||
}
|
||||
|
||||
impl Rx {
|
||||
/// Read one byte from the FIFO in a non-blocking manner.
|
||||
#[inline]
|
||||
pub fn read_fifo(&mut self) -> nb::Result<u8, Infallible> {
|
||||
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(
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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<RefCell<TxContext>>; 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
|
||||
}
|
||||
|
||||
@@ -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::<GicDistributorRegisters>(), 0x1000);
|
||||
const_assert_eq!(core::mem::size_of::<DistributorRegisters>(), 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::<GicCpuInterfaceRegisters>(), 0x100);
|
||||
const_assert_eq!(core::mem::size_of::<CpuInterfaceRegisters>(), 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) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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::<MpCore>(), 0x2000);
|
||||
|
||||
Reference in New Issue
Block a user