From f423f8e6ddb003d833cd340256a2967ac8d4cd21 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 10 Apr 2025 17:10:24 +0200 Subject: [PATCH] re-worked GPIO implementation --- .../embassy/src/bin/logger-non-blocking.rs | 12 +- examples/embassy/src/bin/pwm.rs | 10 +- examples/embassy/src/main.rs | 10 +- examples/simple/src/bin/gtc-ticks.rs | 10 +- examples/simple/src/bin/logger.rs | 10 +- examples/simple/src/main.rs | 6 +- examples/zedboard/Cargo.toml | 2 +- examples/zedboard/src/bin/l3gd20h-i2c-mio.rs | 43 +- examples/zedboard/src/bin/l3gd20h-spi-mio.rs | 51 +- examples/zedboard/src/bin/uart-blocking.rs | 77 ++- .../zedboard/src/bin/uart-non-blocking.rs | 81 ++- examples/zedboard/src/main.rs | 29 +- zynq7000-hal/Cargo.toml | 2 +- zynq7000-hal/src/gpio/dyn_mio.rs | 420 --------------- zynq7000-hal/src/gpio/emio.rs | 260 +-------- zynq7000-hal/src/gpio/ll.rs | 338 ++++++++++++ zynq7000-hal/src/gpio/mio.rs | 493 +++++++----------- zynq7000-hal/src/gpio/mod.rs | 382 +++++++++++++- zynq7000-hal/src/i2c.rs | 50 +- zynq7000-hal/src/lib.rs | 1 + zynq7000-hal/src/spi/mod.rs | 161 +++--- zynq7000-hal/src/ttc.rs | 79 ++- zynq7000-hal/src/uart/mod.rs | 40 +- zynq7000-rt/Cargo.toml | 4 +- zynq7000/src/spi.rs | 4 +- 25 files changed, 1254 insertions(+), 1321 deletions(-) delete mode 100644 zynq7000-hal/src/gpio/dyn_mio.rs create mode 100644 zynq7000-hal/src/gpio/ll.rs diff --git a/examples/embassy/src/bin/logger-non-blocking.rs b/examples/embassy/src/bin/logger-non-blocking.rs index aceb583..de45799 100644 --- a/examples/embassy/src/bin/logger-non-blocking.rs +++ b/examples/embassy/src/bin/logger-non-blocking.rs @@ -14,7 +14,7 @@ use zynq7000_hal::{ BootMode, clocks::Clocks, gic::{GicConfigurator, GicInterruptHelper, Interrupt}, - gpio::{Mio7, MioPin, MioPins, Output, PinState}, + gpio::{Output, PinState, mio}, gtc::Gtc, time::Hertz, uart::{ClkConfigRaw, TxAsync, Uart, UartConfig, on_interrupt_tx}, @@ -52,18 +52,16 @@ async fn main(spawner: Spawner) -> ! { let gtc = Gtc::new(dp.gtc, clocks.arm_clocks()); zynq7000_embassy::init(clocks.arm_clocks(), gtc); - let mio_pins = MioPins::new(dp.gpio); + let mio_pins = mio::Pins::new(dp.gpio); // Set up the UART, we are logging with it. let uart_clk_config = ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200) .unwrap() .0; - let uart_tx = mio_pins.mio48.into_uart(); - let uart_rx = mio_pins.mio49.into_uart(); let mut uart = Uart::new_with_mio( dp.uart_1, UartConfig::new_with_clk_config(uart_clk_config), - (uart_tx, uart_rx), + (mio_pins.mio48, mio_pins.mio49), ) .unwrap(); uart.write_all(b"-- Zynq 7000 Logging example --\n\r") @@ -77,7 +75,7 @@ async fn main(spawner: Spawner) -> ! { let boot_mode = BootMode::new(); info!("Boot mode: {:?}", boot_mode); - let led = mio_pins.mio7.into_output(PinState::Low); + let led = Output::new_for_mio(mio_pins.mio7, PinState::Low); spawner.spawn(led_task(led)).unwrap(); let mut log_buf: [u8; 2048] = [0; 2048]; let frame_queue = zynq7000_hal::log::rb::get_frame_queue(); @@ -89,7 +87,7 @@ async fn main(spawner: Spawner) -> ! { } #[embassy_executor::task] -async fn led_task(mut mio_led: MioPin) { +async fn led_task(mut mio_led: Output) { let mut ticker = Ticker::every(Duration::from_millis(1000)); loop { mio_led.toggle().unwrap(); diff --git a/examples/embassy/src/bin/pwm.rs b/examples/embassy/src/bin/pwm.rs index 14c76c9..7de4079 100644 --- a/examples/embassy/src/bin/pwm.rs +++ b/examples/embassy/src/bin/pwm.rs @@ -19,7 +19,7 @@ use zynq7000_hal::{ BootMode, clocks::Clocks, gic::{GicConfigurator, GicInterruptHelper, Interrupt}, - gpio::{MioPins, PinState}, + gpio::{Output, PinState, mio}, gtc::Gtc, time::Hertz, uart::{ClkConfigRaw, Uart, UartConfig}, @@ -54,7 +54,7 @@ async fn main(_spawner: Spawner) -> ! { unsafe { gic.enable_interrupts(); } - let mio_pins = MioPins::new(dp.gpio); + let mio_pins = mio::Pins::new(dp.gpio); // Set up global timer counter and embassy time driver. let gtc = Gtc::new(dp.gtc, clocks.arm_clocks()); @@ -71,12 +71,10 @@ async fn main(_spawner: Spawner) -> ! { let uart_clk_config = ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200) .unwrap() .0; - let uart_tx = mio_pins.mio48.into_uart(); - let uart_rx = mio_pins.mio49.into_uart(); let mut uart = Uart::new_with_mio( dp.uart_1, UartConfig::new_with_clk_config(uart_clk_config), - (uart_tx, uart_rx), + (mio_pins.mio48, mio_pins.mio49), ) .unwrap(); uart.write_all(b"-- Zynq 7000 Embassy Hello World --\n\r") @@ -94,7 +92,7 @@ async fn main(_spawner: Spawner) -> ! { info!("Boot mode: {:?}", boot_mode); let mut ticker = Ticker::every(Duration::from_millis(1000)); - let mut led = mio_pins.mio7.into_output(PinState::Low); + let mut led = Output::new_for_mio(mio_pins.mio7, PinState::Low); let mut current_duty = 0; loop { led.toggle().unwrap(); diff --git a/examples/embassy/src/main.rs b/examples/embassy/src/main.rs index a70da10..82919bf 100644 --- a/examples/embassy/src/main.rs +++ b/examples/embassy/src/main.rs @@ -12,7 +12,7 @@ use zynq7000_hal::{ BootMode, clocks::Clocks, gic::{GicConfigurator, GicInterruptHelper, Interrupt}, - gpio::{MioPins, PinState}, + gpio::{Output, PinState, mio}, gtc::Gtc, time::Hertz, uart::{ClkConfigRaw, Uart, UartConfig}, @@ -48,7 +48,7 @@ async fn main(_spawner: Spawner) -> ! { unsafe { gic.enable_interrupts(); } - let mio_pins = MioPins::new(dp.gpio); + let mio_pins = mio::Pins::new(dp.gpio); // Set up global timer counter and embassy time driver. let gtc = Gtc::new(dp.gtc, clocks.arm_clocks()); @@ -58,12 +58,10 @@ async fn main(_spawner: Spawner) -> ! { let uart_clk_config = ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200) .unwrap() .0; - let uart_tx = mio_pins.mio48.into_uart(); - let uart_rx = mio_pins.mio49.into_uart(); let mut uart = Uart::new_with_mio( dp.uart_1, UartConfig::new_with_clk_config(uart_clk_config), - (uart_tx, uart_rx), + (mio_pins.mio48, mio_pins.mio49), ) .unwrap(); uart.write_all(b"-- Zynq 7000 Embassy Hello World --\n\r") @@ -81,7 +79,7 @@ async fn main(_spawner: Spawner) -> ! { info!("Boot mode: {:?}", boot_mode); let mut ticker = Ticker::every(Duration::from_millis(1000)); - let mut led = mio_pins.mio7.into_output(PinState::Low); + let mut led = Output::new_for_mio(mio_pins.mio7, PinState::Low); loop { info!("Hello, world!"); led.toggle().unwrap(); diff --git a/examples/simple/src/bin/gtc-ticks.rs b/examples/simple/src/bin/gtc-ticks.rs index 565d673..f967777 100644 --- a/examples/simple/src/bin/gtc-ticks.rs +++ b/examples/simple/src/bin/gtc-ticks.rs @@ -10,7 +10,7 @@ use log::{error, info}; use zynq7000_hal::{ clocks::Clocks, gic::{GicConfigurator, GicInterruptHelper, Interrupt}, - gpio::{MioPins, PinState}, + gpio::{Output, PinState, mio}, gtc::Gtc, prelude::*, time::Hertz, @@ -58,13 +58,11 @@ pub fn main() -> ! { gtc.enable(); // This structure holds all MIO pins. - let mio_pins = MioPins::new(dp.gpio); - let uart_tx = mio_pins.mio48.into_uart(); - let uart_rx = mio_pins.mio49.into_uart(); + let mio_pins = mio::Pins::new(dp.gpio); let mut uart = Uart::new_with_mio( dp.uart_1, UartConfig::new_with_clk_config(uart_clk_config), - (uart_tx, uart_rx), + (mio_pins.mio48, mio_pins.mio49), ) .unwrap(); uart.write_all(b"-- Zynq 7000 GTC Ticks example --\n\r") @@ -78,7 +76,7 @@ pub fn main() -> ! { ) }; - let mut led = mio_pins.mio7.into_output(PinState::Low); + let mut led = Output::new_for_mio(mio_pins.mio7, PinState::Low); loop { info!( "MS_TICKS: {}", diff --git a/examples/simple/src/bin/logger.rs b/examples/simple/src/bin/logger.rs index 0e9a460..5253898 100644 --- a/examples/simple/src/bin/logger.rs +++ b/examples/simple/src/bin/logger.rs @@ -11,7 +11,7 @@ use zynq7000_hal::{ BootMode, clocks::Clocks, gic::{GicConfigurator, GicInterruptHelper, Interrupt}, - gpio::{MioPins, PinState}, + gpio::{Output, PinState, mio}, gtc::Gtc, prelude::*, time::Hertz, @@ -57,14 +57,12 @@ pub fn main() -> ! { gtc.enable_auto_increment(); gtc.enable_interrupt(); gtc.enable(); - let mio_pins = MioPins::new(dp.gpio); - let uart_tx = mio_pins.mio48.into_uart(); - let uart_rx = mio_pins.mio49.into_uart(); + let mio_pins = mio::Pins::new(dp.gpio); let mut uart = Uart::new_with_mio( dp.uart_1, UartConfig::new_with_clk_config(uart_clk_config), - (uart_tx, uart_rx), + (mio_pins.mio48, mio_pins.mio49), ) .unwrap(); uart.write_all(b"-- Zynq 7000 Logging example --\n\r") @@ -81,7 +79,7 @@ pub fn main() -> ! { let boot_mode = BootMode::new(); info!("Boot mode: {:?}", boot_mode); - let mut led = mio_pins.mio7.into_output(PinState::Low); + let mut led = Output::new_for_mio(mio_pins.mio7, PinState::Low); loop { let gtc = gtc.read_timer(); info!("Hello, world!"); diff --git a/examples/simple/src/main.rs b/examples/simple/src/main.rs index 2dd7555..ba75ba7 100644 --- a/examples/simple/src/main.rs +++ b/examples/simple/src/main.rs @@ -6,7 +6,7 @@ use core::panic::PanicInfo; use cortex_ar::asm::nop; use embedded_hal::digital::StatefulOutputPin; use zynq7000::PsPeripherals; -use zynq7000_hal::gpio::{MioPins, PinState}; +use zynq7000_hal::gpio::{Output, PinState, mio}; use zynq7000_rt as _; /// One user LED is MIO7 @@ -45,8 +45,8 @@ pub fn main() -> ! { } Lib::Hal => { let dp = PsPeripherals::take().unwrap(); - let mio_pins = MioPins::new(dp.gpio); - let mut led = mio_pins.mio7.into_output(PinState::High); + let mio_pins = mio::Pins::new(dp.gpio); + let mut led = Output::new_for_mio(mio_pins.mio7, PinState::High); loop { led.toggle().unwrap(); for _ in 0..5_000_000 { diff --git a/examples/zedboard/Cargo.toml b/examples/zedboard/Cargo.toml index 16dd211..5299bb8 100644 --- a/examples/zedboard/Cargo.toml +++ b/examples/zedboard/Cargo.toml @@ -11,7 +11,7 @@ keywords = ["no-std", "arm", "cortex-a", "amd", "zynq7000"] categories = ["embedded", "no-std", "hardware-support"] [dependencies] -cortex-ar = { git = "https://github.com/us-irs/cortex-ar.git", branch = "cortex-a-addition", features = ["critical-section-single-core"] } +cortex-ar = { git = "https://github.com/rust-embedded/cortex-ar", branch = "main", features = ["critical-section-single-core"] } zynq7000-rt = { path = "../../zynq7000-rt" } zynq7000 = { path = "../../zynq7000" } zynq7000-hal = { path = "../../zynq7000-hal" } diff --git a/examples/zedboard/src/bin/l3gd20h-i2c-mio.rs b/examples/zedboard/src/bin/l3gd20h-i2c-mio.rs index c6b3471..8d02e1e 100644 --- a/examples/zedboard/src/bin/l3gd20h-i2c-mio.rs +++ b/examples/zedboard/src/bin/l3gd20h-i2c-mio.rs @@ -22,7 +22,7 @@ use zynq7000_hal::{ clocks::Clocks, configure_level_shifter, gic::{GicConfigurator, GicInterruptHelper, Interrupt}, - gpio::{EmioPin, GpioPins, PinState}, + gpio::{GpioPins, Output, PinState}, gtc::Gtc, i2c, time::Hertz, @@ -73,12 +73,10 @@ async fn main(_spawner: Spawner) -> ! { let uart_clk_config = uart::ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200) .unwrap() .0; - let uart_tx = gpio_pins.mio.mio48.into_uart(); - let uart_rx = gpio_pins.mio.mio49.into_uart(); let mut uart = uart::Uart::new_with_mio( dp.uart_1, uart::UartConfig::new_with_clk_config(uart_clk_config), - (uart_tx, uart_rx), + (gpio_pins.mio.mio48, gpio_pins.mio.mio49), ) .unwrap(); uart.write_all(b"-- Zynq 7000 Zedboard I2C L3GD20H example --\n\r") @@ -95,45 +93,48 @@ async fn main(_spawner: Spawner) -> ! { let boot_mode = BootMode::new(); info!("Boot mode: {:?}", boot_mode); - let sck_pin = gpio_pins.mio.mio12.into_i2c(); - let sda_pin = gpio_pins.mio.mio13.into_i2c(); let pin_sel = match I2C_ADDR_SEL { I2cAddr::Sa0Low => PinState::Low, I2cAddr::Sa0High => PinState::High, }; - let _sa0_pin = gpio_pins.mio.mio11.into_output(pin_sel); + let _sa0_pin = Output::new_for_mio(gpio_pins.mio.mio11, pin_sel); // The CS pin must be pulled high. - let _cs_pin = gpio_pins.mio.mio10.into_output(PinState::High); + let _cs_pin = Output::new_for_mio(gpio_pins.mio.mio10, PinState::High); let clk_config = i2c::calculate_divisors( clocks.arm_clocks().cpu_1x_clk(), i2c::I2cSpeed::Normal100kHz, ) .unwrap(); - let i2c = i2c::I2c::new_with_mio(dp.i2c_1, clk_config, (sck_pin, sda_pin)).unwrap(); + let i2c = i2c::I2c::new_with_mio( + dp.i2c_1, + clk_config, + (gpio_pins.mio.mio12, gpio_pins.mio.mio13), + ) + .unwrap(); let mut l3gd20 = l3gd20::i2c::L3gd20::new(i2c, l3gd20::i2c::I2cAddr::Sa0Low).unwrap(); let who_am_i = l3gd20.who_am_i().unwrap(); info!("L3GD20 WHO_AM_I: 0x{:02X}", who_am_i); let mut delay = Delay; let mut ticker = Ticker::every(Duration::from_millis(400)); - let mut mio_led = gpio_pins.mio.mio7.into_output(PinState::Low); + let mut mio_led = Output::new_for_mio(gpio_pins.mio.mio7, PinState::Low); - let mut emio_leds: [EmioPin; 8] = [ - gpio_pins.emio.take(0).unwrap(), - gpio_pins.emio.take(1).unwrap(), - gpio_pins.emio.take(2).unwrap(), - gpio_pins.emio.take(3).unwrap(), - gpio_pins.emio.take(4).unwrap(), - gpio_pins.emio.take(5).unwrap(), - gpio_pins.emio.take(6).unwrap(), - gpio_pins.emio.take(7).unwrap(), + let mut emio_leds: [Output; 8] = [ + Output::new_for_emio(gpio_pins.emio.take(0).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(1).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(2).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(3).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(4).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(5).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(6).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(7).unwrap(), PinState::Low), ]; for (idx, led) in emio_leds.iter_mut().enumerate() { if idx % 2 == 0 { - led.into_output(PinState::High); + led.set_high(); } else { - led.into_output(PinState::Low); + led.set_low(); } } diff --git a/examples/zedboard/src/bin/l3gd20h-spi-mio.rs b/examples/zedboard/src/bin/l3gd20h-spi-mio.rs index 87ca3b5..f2afc8d 100644 --- a/examples/zedboard/src/bin/l3gd20h-spi-mio.rs +++ b/examples/zedboard/src/bin/l3gd20h-spi-mio.rs @@ -22,7 +22,7 @@ use zynq7000_hal::{ clocks::Clocks, configure_level_shifter, gic::{GicConfigurator, GicInterruptHelper, Interrupt}, - gpio::{DynMioPin, EmioPin, GpioPins, PinState}, + gpio::{GpioPins, Output, PinState}, gtc::Gtc, spi::{self, SpiAsync, SpiId, SpiWithHwCs, SpiWithHwCsAsync, on_interrupt}, time::Hertz, @@ -82,12 +82,10 @@ async fn main(spawner: Spawner) -> ! { let uart_clk_config = uart::ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200) .unwrap() .0; - let uart_tx = gpio_pins.mio.mio48.into_uart(); - let uart_rx = gpio_pins.mio.mio49.into_uart(); let mut uart = uart::Uart::new_with_mio( dp.uart_1, uart::UartConfig::new_with_clk_config(uart_clk_config), - (uart_tx, uart_rx), + (gpio_pins.mio.mio48, gpio_pins.mio.mio49), ) .unwrap(); uart.write_all(b"-- Zynq 7000 Zedboard SPI L3GD20H example --\n\r") @@ -106,10 +104,6 @@ async fn main(spawner: Spawner) -> ! { spi_ref_clk_div ); } - let sck_pin = gpio_pins.mio.mio12.into_spi(); - let mosi_pin = gpio_pins.mio.mio10.into_spi(); - let miso_pin = gpio_pins.mio.mio11.into_spi(); - let ss_pin = gpio_pins.mio.mio13.into_spi(); let mut spi = spi::Spi::new_one_hw_cs( dp.spi_1, @@ -121,8 +115,12 @@ async fn main(spawner: Spawner) -> ! { embedded_hal::spi::MODE_3, spi::SlaveSelectConfig::AutoWithAutoStart, ), - (sck_pin, mosi_pin, miso_pin), - ss_pin, + ( + gpio_pins.mio.mio12, + gpio_pins.mio.mio10, + gpio_pins.mio.mio11, + ), + gpio_pins.mio.mio13, ) .unwrap(); let mod_id = spi.regs().read_mod_id(); @@ -138,24 +136,25 @@ async fn main(spawner: Spawner) -> ! { .build(), ); - let mio_led = gpio_pins.mio.mio7.into_output(PinState::Low).downgrade(); - let mut emio_leds: [EmioPin; 8] = [ - gpio_pins.emio.take(0).unwrap(), - gpio_pins.emio.take(1).unwrap(), - gpio_pins.emio.take(2).unwrap(), - gpio_pins.emio.take(3).unwrap(), - gpio_pins.emio.take(4).unwrap(), - gpio_pins.emio.take(5).unwrap(), - gpio_pins.emio.take(6).unwrap(), - gpio_pins.emio.take(7).unwrap(), + let mio_led = Output::new_for_mio(gpio_pins.mio.mio7, PinState::Low); + let mut emio_leds: [Output; 8] = [ + Output::new_for_emio(gpio_pins.emio.take(0).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(1).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(2).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(3).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(4).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(5).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(6).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(7).unwrap(), PinState::Low), ]; for (idx, led) in emio_leds.iter_mut().enumerate() { if idx % 2 == 0 { - led.into_output(PinState::High); + led.set_high(); } else { - led.into_output(PinState::Low); + led.set_low(); } } + spawner.spawn(logger_task(uart)).unwrap(); if BLOCKING { blocking_application(mio_led, emio_leds, spi).await; @@ -178,8 +177,8 @@ pub async fn logger_task(uart: uart::Uart) { } pub async fn blocking_application( - mut mio_led: DynMioPin, - mut emio_leds: [EmioPin; 8], + mut mio_led: Output, + mut emio_leds: [Output; 8], spi: spi::Spi, ) -> ! { let mut delay = Delay; @@ -207,8 +206,8 @@ pub async fn blocking_application( } pub async fn non_blocking_application( - mut mio_led: DynMioPin, - mut emio_leds: [EmioPin; 8], + mut mio_led: Output, + mut emio_leds: [Output; 8], spi: spi::Spi, ) -> ! { let mut delay = Delay; diff --git a/examples/zedboard/src/bin/uart-blocking.rs b/examples/zedboard/src/bin/uart-blocking.rs index a874c6f..0b1535f 100644 --- a/examples/zedboard/src/bin/uart-blocking.rs +++ b/examples/zedboard/src/bin/uart-blocking.rs @@ -17,7 +17,7 @@ use zynq7000_hal::{ clocks::Clocks, configure_level_shifter, gic::{GicConfigurator, GicInterruptHelper, Interrupt}, - gpio::{EmioPin, GpioPins, PinState}, + gpio::{GpioPins, Output, PinState}, gtc::Gtc, uart::{ClkConfigRaw, Uart, UartConfig}, }; @@ -50,13 +50,13 @@ pub enum UartSel { } pub struct UartMultiplexer { - sel_pins: [EmioPin; 3], + sel_pins: [Output; 3], } impl UartMultiplexer { - pub fn new(mut sel_pins: [EmioPin; 3]) -> Self { + pub fn new(mut sel_pins: [Output; 3]) -> Self { for pin in sel_pins.iter_mut() { - pin.into_output(PinState::Low); + pin.set_low(); } Self { sel_pins } } @@ -65,34 +65,34 @@ impl UartMultiplexer { // TODO: A pin group switcher would be nice to do this in one go. match sel { UartSel::Uart0 => { - self.sel_pins[2].set_low().unwrap(); - self.sel_pins[1].set_low().unwrap(); - self.sel_pins[0].set_low().unwrap(); + self.sel_pins[2].set_low(); + self.sel_pins[1].set_low(); + self.sel_pins[0].set_low(); } UartSel::Uartlite => { - self.sel_pins[2].set_low().unwrap(); - self.sel_pins[1].set_low().unwrap(); - self.sel_pins[0].set_high().unwrap(); + self.sel_pins[2].set_low(); + self.sel_pins[1].set_low(); + self.sel_pins[0].set_high(); } UartSel::Uart16550 => { - self.sel_pins[2].set_low().unwrap(); - self.sel_pins[1].set_high().unwrap(); - self.sel_pins[0].set_low().unwrap(); + self.sel_pins[2].set_low(); + self.sel_pins[1].set_high(); + self.sel_pins[0].set_low(); } UartSel::Uart0ToUartlite => { - self.sel_pins[2].set_low().unwrap(); - self.sel_pins[1].set_high().unwrap(); - self.sel_pins[0].set_high().unwrap(); + self.sel_pins[2].set_low(); + self.sel_pins[1].set_high(); + self.sel_pins[0].set_high(); } UartSel::Uart0ToUart16550 => { - self.sel_pins[2].set_high().unwrap(); - self.sel_pins[1].set_low().unwrap(); - self.sel_pins[0].set_low().unwrap(); + self.sel_pins[2].set_high(); + self.sel_pins[1].set_low(); + self.sel_pins[0].set_low(); } UartSel::UartliteToUart16550 => { - self.sel_pins[2].set_high().unwrap(); - self.sel_pins[1].set_low().unwrap(); - self.sel_pins[0].set_high().unwrap(); + self.sel_pins[2].set_high(); + self.sel_pins[1].set_low(); + self.sel_pins[0].set_high(); } } } @@ -123,12 +123,10 @@ async fn main(_spawner: Spawner) -> ! { let uart_clk_config = ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200) .unwrap() .0; - let uart_tx = gpio_pins.mio.mio48.into_uart(); - let uart_rx = gpio_pins.mio.mio49.into_uart(); let mut log_uart = Uart::new_with_mio( dp.uart_1, UartConfig::new_with_clk_config(uart_clk_config), - (uart_tx, uart_rx), + (gpio_pins.mio.mio48, gpio_pins.mio.mio49), ) .unwrap(); log_uart.write_all(INIT_STRING.as_bytes()).unwrap(); @@ -163,26 +161,23 @@ async fn main(_spawner: Spawner) -> ! { info!("Boot mode: {:?}", boot_mode); let mut ticker = Ticker::every(Duration::from_millis(1000)); - let mut mio_led = gpio_pins.mio.mio7.into_output(PinState::Low); - let mut emio_leds: [EmioPin; 8] = [ - gpio_pins.emio.take(0).unwrap(), - gpio_pins.emio.take(1).unwrap(), - gpio_pins.emio.take(2).unwrap(), - gpio_pins.emio.take(3).unwrap(), - gpio_pins.emio.take(4).unwrap(), - gpio_pins.emio.take(5).unwrap(), - gpio_pins.emio.take(6).unwrap(), - gpio_pins.emio.take(7).unwrap(), + let mut mio_led = Output::new_for_mio(gpio_pins.mio.mio7, PinState::Low); + let mut emio_leds: [Output; 8] = [ + Output::new_for_emio(gpio_pins.emio.take(0).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(1).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(2).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(3).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(4).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(5).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(6).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(7).unwrap(), PinState::Low), ]; - for led in emio_leds.iter_mut() { - led.into_output(PinState::Low); - } let mut uart_mux = UartMultiplexer::new([ - gpio_pins.emio.take(8).unwrap(), - gpio_pins.emio.take(9).unwrap(), - gpio_pins.emio.take(10).unwrap(), + Output::new_for_emio(gpio_pins.emio.take(8).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(9).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(10).unwrap(), PinState::Low), ]); let mut current_sel = UartSel::Uart0; uart_mux.select(current_sel); diff --git a/examples/zedboard/src/bin/uart-non-blocking.rs b/examples/zedboard/src/bin/uart-non-blocking.rs index 4a2e983..6305f58 100644 --- a/examples/zedboard/src/bin/uart-non-blocking.rs +++ b/examples/zedboard/src/bin/uart-non-blocking.rs @@ -43,7 +43,7 @@ use zynq7000_hal::{ clocks::Clocks, configure_level_shifter, gic::{GicConfigurator, GicInterruptHelper, Interrupt}, - gpio::{EmioPin, GpioPins, Mio7, MioPin, Output, PinState}, + gpio::{GpioPins, Output, PinState}, gtc::Gtc, time::Hertz, uart::{ClkConfigRaw, Uart, UartConfig}, @@ -114,13 +114,13 @@ pub enum UartSel { } pub struct UartMultiplexer { - sel_pins: [EmioPin; 3], + sel_pins: [Output; 3], } impl UartMultiplexer { - pub fn new(mut sel_pins: [EmioPin; 3]) -> Self { + pub fn new(mut sel_pins: [Output; 3]) -> Self { for pin in sel_pins.iter_mut() { - pin.into_output(PinState::Low); + pin.set_low(); } Self { sel_pins } } @@ -129,38 +129,39 @@ impl UartMultiplexer { // TODO: A pin group switcher would be nice to do this in one go. match sel { UartSel::Uart0 => { - self.sel_pins[2].set_low().unwrap(); - self.sel_pins[1].set_low().unwrap(); - self.sel_pins[0].set_low().unwrap(); + self.sel_pins[2].set_low(); + self.sel_pins[1].set_low(); + self.sel_pins[0].set_low(); } UartSel::Uartlite => { - self.sel_pins[2].set_low().unwrap(); - self.sel_pins[1].set_low().unwrap(); - self.sel_pins[0].set_high().unwrap(); + self.sel_pins[2].set_low(); + self.sel_pins[1].set_low(); + self.sel_pins[0].set_high(); } UartSel::Uart16550 => { - self.sel_pins[2].set_low().unwrap(); - self.sel_pins[1].set_high().unwrap(); - self.sel_pins[0].set_low().unwrap(); + self.sel_pins[2].set_low(); + self.sel_pins[1].set_high(); + self.sel_pins[0].set_low(); } UartSel::Uart0ToUartlite => { - self.sel_pins[2].set_low().unwrap(); - self.sel_pins[1].set_high().unwrap(); - self.sel_pins[0].set_high().unwrap(); + self.sel_pins[2].set_low(); + self.sel_pins[1].set_high(); + self.sel_pins[0].set_high(); } UartSel::Uart0ToUart16550 => { - self.sel_pins[2].set_high().unwrap(); - self.sel_pins[1].set_low().unwrap(); - self.sel_pins[0].set_low().unwrap(); + self.sel_pins[2].set_high(); + self.sel_pins[1].set_low(); + self.sel_pins[0].set_low(); } UartSel::UartliteToUart16550 => { - self.sel_pins[2].set_high().unwrap(); - self.sel_pins[1].set_low().unwrap(); - self.sel_pins[0].set_high().unwrap(); + self.sel_pins[2].set_high(); + self.sel_pins[1].set_low(); + self.sel_pins[0].set_high(); } } } } + #[embassy_executor::main] #[unsafe(export_name = "main")] async fn main(spawner: Spawner) -> ! { @@ -192,12 +193,10 @@ async fn main(spawner: Spawner) -> ! { let uart_clk_config = ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200) .unwrap() .0; - let uart_tx = gpio_pins.mio.mio48.into_uart(); - let uart_rx = gpio_pins.mio.mio49.into_uart(); let mut log_uart = Uart::new_with_mio( dp.uart_1, UartConfig::new_with_clk_config(uart_clk_config), - (uart_tx, uart_rx), + (gpio_pins.mio.mio48, gpio_pins.mio.mio49), ) .unwrap(); log_uart.write_all(INIT_STRING.as_bytes()).unwrap(); @@ -222,9 +221,9 @@ async fn main(spawner: Spawner) -> ! { // Set up UART multiplexing before creating and configuring the UARTs. let mut uart_mux = UartMultiplexer::new([ - gpio_pins.emio.take(8).unwrap(), - gpio_pins.emio.take(9).unwrap(), - gpio_pins.emio.take(10).unwrap(), + Output::new_for_emio(gpio_pins.emio.take(8).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(9).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(10).unwrap(), PinState::Low), ]); match UART_MODE { UartMode::Uart0ToUartlite => uart_mux.select(UartSel::Uart0ToUartlite), @@ -254,21 +253,17 @@ async fn main(spawner: Spawner) -> ! { let boot_mode = BootMode::new(); info!("Boot mode: {:?}", boot_mode); - let mio_led = gpio_pins.mio.mio7.into_output(PinState::Low); - - let mut emio_leds: [EmioPin; 8] = [ - gpio_pins.emio.take(0).unwrap(), - gpio_pins.emio.take(1).unwrap(), - gpio_pins.emio.take(2).unwrap(), - gpio_pins.emio.take(3).unwrap(), - gpio_pins.emio.take(4).unwrap(), - gpio_pins.emio.take(5).unwrap(), - gpio_pins.emio.take(6).unwrap(), - gpio_pins.emio.take(7).unwrap(), + let mio_led = Output::new_for_mio(gpio_pins.mio.mio7, PinState::Low); + let emio_leds: [Output; 8] = [ + Output::new_for_emio(gpio_pins.emio.take(0).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(1).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(2).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(3).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(4).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(5).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(6).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(7).unwrap(), PinState::Low), ]; - for led in emio_leds.iter_mut() { - led.into_output(PinState::Low); - } let (uart_0_tx, mut uart_0_rx) = uart_0.split(); let (uartlite_tx, _uartlite_rx) = uartlite.split(); @@ -353,7 +348,7 @@ fn build_print_string(prefix: &str, base_str: &str) -> alloc::string::String { } #[embassy_executor::task] -async fn led_task(mut mio_led: MioPin, mut emio_leds: [EmioPin; 8]) { +async fn led_task(mut mio_led: Output, mut emio_leds: [Output; 8]) { let mut ticker = Ticker::every(Duration::from_millis(1000)); let mut led_idx = 0; loop { diff --git a/examples/zedboard/src/main.rs b/examples/zedboard/src/main.rs index 9d43c7f..2b3f28e 100644 --- a/examples/zedboard/src/main.rs +++ b/examples/zedboard/src/main.rs @@ -14,7 +14,7 @@ use zynq7000_hal::{ clocks::Clocks, configure_level_shifter, gic::{GicConfigurator, GicInterruptHelper, Interrupt}, - gpio::{EmioPin, GpioPins, PinState}, + gpio::{GpioPins, Output, PinState}, gtc::Gtc, uart::{ClkConfigRaw, Uart, UartConfig}, }; @@ -59,12 +59,10 @@ async fn main(_spawner: Spawner) -> ! { let uart_clk_config = ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200) .unwrap() .0; - let uart_tx = gpio_pins.mio.mio48.into_uart(); - let uart_rx = gpio_pins.mio.mio49.into_uart(); let mut uart = Uart::new_with_mio( dp.uart_1, UartConfig::new_with_clk_config(uart_clk_config), - (uart_tx, uart_rx), + (gpio_pins.mio.mio48, gpio_pins.mio.mio49), ) .unwrap(); uart.write_all(INIT_STRING.as_bytes()).unwrap(); @@ -81,21 +79,18 @@ async fn main(_spawner: Spawner) -> ! { info!("Boot mode: {:?}", boot_mode); let mut ticker = Ticker::every(Duration::from_millis(200)); - let mut mio_led = gpio_pins.mio.mio7.into_output(PinState::Low); - let mut emio_leds: [EmioPin; 8] = [ - gpio_pins.emio.take(0).unwrap(), - gpio_pins.emio.take(1).unwrap(), - gpio_pins.emio.take(2).unwrap(), - gpio_pins.emio.take(3).unwrap(), - gpio_pins.emio.take(4).unwrap(), - gpio_pins.emio.take(5).unwrap(), - gpio_pins.emio.take(6).unwrap(), - gpio_pins.emio.take(7).unwrap(), + let mut mio_led = Output::new_for_mio(gpio_pins.mio.mio7, PinState::Low); + let mut emio_leds: [Output; 8] = [ + Output::new_for_emio(gpio_pins.emio.take(0).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(1).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(2).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(3).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(4).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(5).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(6).unwrap(), PinState::Low), + Output::new_for_emio(gpio_pins.emio.take(7).unwrap(), PinState::Low), ]; - for led in emio_leds.iter_mut() { - led.into_output(PinState::Low); - } loop { mio_led.toggle().unwrap(); diff --git a/zynq7000-hal/Cargo.toml b/zynq7000-hal/Cargo.toml index e3bb7a2..281820f 100644 --- a/zynq7000-hal/Cargo.toml +++ b/zynq7000-hal/Cargo.toml @@ -11,7 +11,7 @@ keywords = ["no-std", "hal", "amd", "zynq7000", "xilinx", "bare-metal"] categories = ["embedded", "no-std", "hardware-support"] [dependencies] -cortex-ar = { path = "../../../Rust/cortex-ar/cortex-ar" } +cortex-ar = { git = "https://github.com/rust-embedded/cortex-ar", branch = "main", features = ["critical-section-single-core"] } zynq7000 = { path = "../zynq7000" } arbitrary-int = "1.3" diff --git a/zynq7000-hal/src/gpio/dyn_mio.rs b/zynq7000-hal/src/gpio/dyn_mio.rs deleted file mode 100644 index 0c3d1db..0000000 --- a/zynq7000-hal/src/gpio/dyn_mio.rs +++ /dev/null @@ -1,420 +0,0 @@ -//! Dynamic MIO pin module. -//! -//! This provides the type-erased MIO pin support. -use arbitrary_int::{u2, u3}; -use zynq7000::gpio::{Gpio, MaskedOutput, MmioGpio}; - -pub use crate::gpio::PinState; -use crate::slcr::Slcr; - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct MuxConf { - l3: u3, - l2: u2, - l1: bool, - l0: bool, -} - -impl From for MuxConf { - fn from(value: zynq7000::slcr::mio::Config) -> Self { - Self::new( - value.l0_sel(), - value.l1_sel(), - value.l2_sel(), - value.l3_sel(), - ) - } -} - -impl MuxConf { - #[inline] - pub const fn new(l0: bool, l1: bool, l2: u2, l3: u3) -> Self { - Self { l3, l2, l1, l0 } - } - - pub const fn new_with_l3(l3: u3) -> Self { - Self::new(false, false, u2::new(0b00), l3) - } - - pub const fn new_for_gpio() -> Self { - Self::new(false, false, u2::new(0), u3::new(0)) - } - - #[inline] - pub const fn l0_sel(&self) -> bool { - self.l0 - } - - #[inline] - pub const fn l1_sel(&self) -> bool { - self.l1 - } - - #[inline] - pub const fn l2_sel(&self) -> u2 { - self.l2 - } - - #[inline] - pub const fn l3_sel(&self) -> u3 { - self.l3 - } -} - -#[derive(Debug, Copy, Clone)] -pub enum DynPinModeMio { - Output, - InputFloating, - InputPullUp, - IoPeriph(MuxConf), -} - -#[derive(Debug, thiserror::Error)] -#[error("invalid pin mode for MIO pin: {0:?}")] -pub struct InvalidPinModeMio(pub DynPinModeMio); - -impl embedded_hal::digital::Error for InvalidPinModeMio { - fn kind(&self) -> embedded_hal::digital::ErrorKind { - embedded_hal::digital::ErrorKind::Other - } -} - -pub trait MioPinProvider { - fn mode(&self) -> &DynPinModeMio; - - fn offset(&self) -> usize; - - #[inline] - fn is_input(&self) -> bool { - matches!( - self.mode(), - DynPinModeMio::InputFloating | DynPinModeMio::InputPullUp - ) - } - #[inline] - fn is_output(&self) -> bool { - matches!(self.mode(), DynPinModeMio::Output) - } - #[inline] - fn is_io_periph(&self) -> bool { - matches!(self.mode(), DynPinModeMio::IoPeriph(_)) - } -} - -pub struct DynMioPin { - offset: usize, - dyn_mode: DynPinModeMio, - regs: MmioGpio<'static>, -} - -impl MioPinProvider for DynMioPin { - #[inline] - fn mode(&self) -> &DynPinModeMio { - &self.dyn_mode - } - #[inline] - fn offset(&self) -> usize { - self.offset - } -} - -#[derive(Debug, thiserror::Error)] -#[error("MIO pins 7 and 8 can only be output pins")] -pub struct PinIsOutputOnly; - -impl DynMioPin { - #[inline] - pub(crate) const fn new(offset: usize, dyn_mode: DynPinModeMio) -> Self { - Self { - offset, - dyn_mode, - regs: unsafe { Gpio::new_mmio_fixed() }, - } - } - - /// Convert the pin into an output pin. - pub fn into_output(&mut self, init_level: PinState) { - self.dyn_mode = DynPinModeMio::Output; - // The Pullup config does not matter for Output. Tri-state bit must be 0 for the - // output driver to work. - self.reconfigure_slcr_mio_cfg(false, None, Some(MuxConf::new_for_gpio())); - match self.offset { - 0..=31 => { - self.regs.bank_0().modify_dirm(|v| v | (1 << self.offset)); - self.regs.bank_0().modify_out_en(|v| v | (1 << self.offset)); - } - 32..=53 => { - self.regs - .bank_1() - .modify_dirm(|v| v | 1 << (self.offset - 32)); - self.regs - .bank_1() - .modify_out_en(|v| v | 1 << (self.offset - 32)); - } - _ => panic!("invalid GPIO pin offset"), - } - // Unwrap okay, just set mode. - self.write_state(self.offset, init_level).unwrap(); - } - - /// Convert the pin into a floating input pin. - pub fn into_input_floating(&mut self) -> Result<(), PinIsOutputOnly> { - if self.offset == 7 || self.offset == 8 { - return Err(PinIsOutputOnly); - } - self.reconfigure_slcr_mio_cfg(true, Some(false), Some(MuxConf::new_for_gpio())); - self.configure_input_pin(); - self.dyn_mode = DynPinModeMio::InputFloating; - Ok(()) - } - - /// Convert the pin into an input pin with a pull up. - pub fn into_input_pull_up(&mut self) -> Result<(), PinIsOutputOnly> { - if self.offset == 7 || self.offset == 8 { - return Err(PinIsOutputOnly); - } - self.reconfigure_slcr_mio_cfg(true, Some(true), Some(MuxConf::new_for_gpio())); - self.configure_input_pin(); - self.dyn_mode = DynPinModeMio::InputPullUp; - Ok(()) - } - - /// Convert the pin into an IO peripheral pin. - pub fn into_io_periph_pin(&mut self, mux_conf: MuxConf, pullup: Option) { - self.reconfigure_slcr_mio_cfg(false, pullup, Some(mux_conf)); - self.dyn_mode = DynPinModeMio::IoPeriph(mux_conf); - } - - pub fn is_low(&self) -> Result { - if !self.is_input() { - return Err(InvalidPinModeMio(self.dyn_mode)); - } - Ok(self.is_low_unchecked()) - } - - /// This variant does not check whether the [DynPinModeMio] is correct. - #[inline] - pub fn is_low_unchecked(&self) -> bool { - match self.offset { - 0..=31 => ((self.regs.read_in_0() >> self.offset) & 0b1) == 0, - 32..=53 => ((self.regs.read_in_1() >> (self.offset - 32)) & 0b1) == 0, - _ => panic!("invalid GPIO pin offset"), - } - } - - #[inline] - pub fn is_high(&self) -> Result { - self.is_low().map(|v| !v) - } - - /// This variant does not check whether the [DynPinModeMio] is correct. - #[inline] - pub fn is_high_unchecked(&self) -> bool { - !self.is_low_unchecked() - } - - #[inline] - pub fn is_set_low(&self) -> Result { - if !self.is_output() { - return Err(InvalidPinModeMio(self.dyn_mode)); - } - Ok(self.is_set_low_unchecked()) - } - - /// This variant does not check whether the [DynPinModeMio] is correct. - #[inline] - pub fn is_set_low_unchecked(&self) -> bool { - match self.offset { - 0..=31 => ((self.regs.read_out_0() >> self.offset) & 0b1) == 0, - 32..=53 => ((self.regs.read_out_1() >> (self.offset - 32)) & 0b1) == 0, - _ => panic!("invalid GPIO pin offset"), - } - } - - #[inline] - pub fn is_set_high(&self) -> Result { - self.is_set_low().map(|v| !v) - } - - /// This variant does not check whether the [DynPinModeMio] is correct. - #[inline] - pub fn is_set_high_unchecked(&self) -> bool { - !self.is_set_low_unchecked() - } - - #[inline] - pub fn set_low(&mut self) -> Result<(), InvalidPinModeMio> { - self.write_state(self.offset, PinState::Low) - } - - /// This variant does not check whether the [DynPinModeMio] is correct. - #[inline] - pub fn set_low_unchecked(&mut self) { - self.write_state_unchecked(self.offset, PinState::Low) - } - - #[inline] - pub fn set_high(&mut self) -> Result<(), InvalidPinModeMio> { - self.write_state(self.offset, PinState::High) - } - - /// This variant does not check whether the [DynPinModeMio] is correct. - #[inline] - pub fn set_high_unchecked(&mut self) { - self.write_state_unchecked(self.offset, PinState::High) - } - - #[inline(always)] - fn offset_to_masked_out_ptr_and_ptr_offset( - &mut self, - offset: usize, - ) -> (usize, *mut MaskedOutput) { - match offset { - 0..=15 => (offset, self.regs.pointer_to_masked_out_0_lsw()), - 16..=31 => (offset - 16, self.regs.pointer_to_masked_out_0_msw()), - 32..=47 => (offset - 32, self.regs.pointer_to_masked_out_1_lsw()), - 48..=53 => (offset - 48, self.regs.pointer_to_masked_out_1_msw()), - _ => unreachable!(), - } - } - - #[inline] - fn write_state(&mut self, offset: usize, level: PinState) -> Result<(), InvalidPinModeMio> { - if !self.is_output() { - return Err(InvalidPinModeMio(self.dyn_mode)); - } - self.write_state_unchecked(offset, level); - Ok(()) - } - - #[inline] - fn write_state_unchecked(&mut self, offset: usize, level: PinState) { - let (offset_in_reg, masked_out_ptr) = self.offset_to_masked_out_ptr_and_ptr_offset(offset); - unsafe { - core::ptr::write_volatile( - masked_out_ptr, - MaskedOutput::builder() - .with_mask(!(1 << offset_in_reg)) - .with_output((level as u16) << offset_in_reg) - .build(), - ); - } - } - - #[inline] - fn is_low_mut(&mut self) -> Result { - self.is_low() - } - - #[inline] - fn is_high_mut(&mut self) -> Result { - self.is_high() - } - - #[inline] - fn is_set_low_mut(&mut self) -> Result { - self.is_set_low() - } - - #[inline] - fn is_set_high_mut(&mut self) -> Result { - self.is_set_high() - } - - fn reconfigure_slcr_mio_cfg( - &mut self, - tristate: bool, - pullup: Option, - mux_conf: Option, - ) { - // Safety: We only modify the MIO config of the pin. - let mut slcr_wrapper = unsafe { Slcr::steal() }; - // We read first, because writing also required unlocking the SLCR. - // This allows the user to configure the SLCR themselves to avoid unnecessary - // re-configuration which might also be potentially unsafe at run-time. - let mio_cfg = slcr_wrapper.regs().read_mio_pins(self.offset).unwrap(); - if (pullup.is_some() && mio_cfg.pullup() != pullup.unwrap()) - || (mux_conf.is_some() && MuxConf::from(mio_cfg) != mux_conf.unwrap()) - || tristate != mio_cfg.tri_enable() - { - slcr_wrapper.modify(|mut_slcr| { - mut_slcr - .modify_mio_pins(self.offset, |mut val| { - if let Some(pullup) = pullup { - val.set_pullup(pullup); - } - if let Some(mux_conf) = mux_conf { - val.set_l0_sel(mux_conf.l0_sel()); - val.set_l1_sel(mux_conf.l1_sel()); - val.set_l2_sel(mux_conf.l2_sel()); - val.set_l3_sel(mux_conf.l3_sel()); - } - val.set_tri_enable(tristate); - val - }) - .unwrap(); - }); - } - } - - fn configure_input_pin(&mut self) { - match self.offset { - 0..=31 => { - self.regs.bank_0().modify_dirm(|mut v| { - v &= !(1 << self.offset); - v - }); - self.regs.bank_0().modify_out_en(|mut v| { - v &= !(1 << self.offset); - v - }); - } - 32..=53 => { - self.regs.bank_1().modify_dirm(|mut v| { - v &= !(1 << (self.offset - 32)); - v - }); - self.regs.bank_1().modify_out_en(|mut v| { - v &= !(1 << (self.offset - 32)); - v - }); - } - _ => panic!("invalid GPIO pin offset"), - } - } -} - -impl embedded_hal::digital::ErrorType for DynMioPin { - type Error = InvalidPinModeMio; -} - -impl embedded_hal::digital::OutputPin for DynMioPin { - fn set_low(&mut self) -> Result<(), Self::Error> { - self.set_low()?; - Ok(()) - } - fn set_high(&mut self) -> Result<(), Self::Error> { - self.set_high()?; - Ok(()) - } -} - -impl embedded_hal::digital::StatefulOutputPin for DynMioPin { - fn is_set_high(&mut self) -> Result { - self.is_set_high_mut() - } - - fn is_set_low(&mut self) -> Result { - self.is_set_low_mut() - } -} - -impl embedded_hal::digital::InputPin for DynMioPin { - fn is_high(&mut self) -> Result { - self.is_high_mut() - } - - fn is_low(&mut self) -> Result { - self.is_low_mut() - } -} diff --git a/zynq7000-hal/src/gpio/emio.rs b/zynq7000-hal/src/gpio/emio.rs index 9af24f2..635a059 100644 --- a/zynq7000-hal/src/gpio/emio.rs +++ b/zynq7000-hal/src/gpio/emio.rs @@ -1,263 +1,24 @@ -//! EMIO (Extended Multiplexed I/O) module. -use zynq7000::gpio::{Gpio, MaskedOutput, MmioGpio}; +//! EMIO (Extended Multiplexed I/O) resource management module. +use zynq7000::gpio::MmioGpio; pub use crate::gpio::PinState; -#[derive(Debug, thiserror::Error)] -#[error("invalid pin mode for MIO pin: {0:?}")] -pub struct InvalidPinModeEmio(pub DynPinModeEmio); - -impl embedded_hal::digital::Error for InvalidPinModeEmio { - fn kind(&self) -> embedded_hal::digital::ErrorKind { - embedded_hal::digital::ErrorKind::Other - } -} - -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub enum DynPinModeEmio { - Output, - Input, -} - pub struct EmioPin { - regs: MmioGpio<'static>, - mode: DynPinModeEmio, offset: usize, } impl EmioPin { - /// Unsafely steal an EMIO input pin. - /// - /// Unless you have no other option, it is recommended to use the [EmioPins::take] method - /// to retrieve the pins safely. Returns [None] if the offset is larger than 63. - /// - /// # Safety - /// - /// This allows potentially creating multiple input pin structures for the same GPIO - /// peripheral which can cause data races. - #[inline] - pub const unsafe fn steal(offset: usize) -> Option { - if offset >= 64 { - return None; - } - Some(Self { - regs: unsafe { Gpio::new_mmio_fixed() }, - mode: DynPinModeEmio::Input, - offset: 0, - }) - } - - pub fn into_input(&mut self) { - self.mode = DynPinModeEmio::Input; - match self.offset { - 0..=31 => { - self.regs - .bank_2() - .modify_dirm(|val| val & !(1 << self.offset)); - } - 32..=63 => { - self.regs - .bank_3() - .modify_dirm(|val| val & !(1 << self.offset)); - } - _ => unreachable!(), - } - } - - pub fn into_output(&mut self, init_level: PinState) { - self.mode = DynPinModeEmio::Output; - match self.offset { - 0..=31 => { - self.regs - .bank_2() - .modify_dirm(|val| val | (1 << self.offset)); - self.regs - .bank_2() - .modify_out_en(|val| val | (1 << self.offset)); - } - 32..=63 => { - self.regs - .bank_3() - .modify_dirm(|val| val | (1 << self.offset)); - self.regs - .bank_2() - .modify_out_en(|val| val | (1 << self.offset)); - } - _ => unreachable!(), - } - // Unwrap okay, just set mode. - self.write_state(self.offset, init_level).unwrap(); - } - - #[inline] - pub fn is_low(&self) -> Result { - if self.mode == DynPinModeEmio::Output { - return Err(InvalidPinModeEmio(self.mode)); - } - Ok(self.is_low_unchecked()) - } - - /// This variant does not check whether the [DynPinModeEmio] is correct. - #[inline] - pub fn is_low_unchecked(&self) -> bool { - match self.offset { - 0..=31 => ((self.regs.read_in_0() >> self.offset) & 0b1) == 0, - 32..=63 => ((self.regs.read_in_1() >> (self.offset - 32)) & 0b1) == 0, - _ => panic!("invalid GPIO pin offset"), - } - } - - #[inline] - pub fn is_high(&self) -> Result { - self.is_low().map(|v| !v) - } - - /// This variant does not check whether the [DynPinModeEmio] is correct. - #[inline] - pub fn is_high_unchecked(&self) -> bool { - !self.is_low_unchecked() - } - - #[inline(always)] - fn offset_to_masked_out_ptr_and_ptr_offset( - &mut self, - offset: usize, - ) -> (usize, *mut MaskedOutput) { - match offset { - 0..=15 => (offset, self.regs.pointer_to_masked_out_2_lsw()), - 16..=31 => (offset - 16, self.regs.pointer_to_masked_out_2_msw()), - 32..=47 => (offset - 32, self.regs.pointer_to_masked_out_3_lsw()), - 48..=63 => (offset - 48, self.regs.pointer_to_masked_out_3_msw()), - _ => unreachable!(), - } - } - - #[inline] - fn write_state(&mut self, offset: usize, level: PinState) -> Result<(), InvalidPinModeEmio> { - if self.mode == DynPinModeEmio::Input { - return Err(InvalidPinModeEmio(self.mode)); - } - self.write_state_unchecked(offset, level); - Ok(()) - } - - #[inline] - fn write_state_unchecked(&mut self, offset: usize, level: PinState) { - let (offset_in_reg, masked_out_ptr) = self.offset_to_masked_out_ptr_and_ptr_offset(offset); - unsafe { - core::ptr::write_volatile( - masked_out_ptr, - MaskedOutput::builder() - .with_mask(!(1 << offset_in_reg)) - .with_output((level as u16) << offset_in_reg) - .build(), - ); - } - } - - #[inline] - pub fn is_set_low(&mut self) -> Result { - if self.mode == DynPinModeEmio::Input { - return Err(InvalidPinModeEmio(self.mode)); - } - Ok(self.is_set_low_unchecked()) - } - - /// This variant does not check whether the [DynPinModeEmio] is correct. - #[inline] - pub fn is_set_low_unchecked(&mut self) -> bool { - match self.offset { - 0..=31 => ((self.regs.read_out_2() >> self.offset) & 0b1) == 0, - 32..=64 => ((self.regs.read_out_3() >> (self.offset - 32)) & 0b1) == 0, - _ => panic!("invalid GPIO pin offset"), - } - } - - #[inline] - pub fn is_set_high(&mut self) -> Result { - self.is_set_low().map(|v| !v) - } - - /// This variant does not check whether the [DynPinModeEmio] is correct. - #[inline] - pub fn is_set_high_unchecked(&mut self) -> bool { - !self.is_set_low_unchecked() - } - - #[inline] - pub fn set_high(&mut self) -> Result<(), InvalidPinModeEmio> { - self.write_state(self.offset, PinState::High) - } - - /// This variant does not check whether the [DynPinModeEmio] is correct. - #[inline] - pub fn set_high_unchecked(&mut self) { - self.write_state_unchecked(self.offset, PinState::High) - } - - #[inline] - pub fn set_low(&mut self) -> Result<(), InvalidPinModeEmio> { - self.write_state(self.offset, PinState::Low) - } - - /// This variant does not check whether the [DynPinModeEmio] is correct. - #[inline] - pub fn set_low_unchecked(&mut self) { - self.write_state_unchecked(self.offset, PinState::Low) - } - - #[inline] - fn is_high_mut(&mut self) -> Result { - self.is_high() - } - - #[inline] - fn is_low_mut(&mut self) -> Result { - self.is_low() + /// This offset ranges from 0 to 64. + pub fn offset(&self) -> usize { + self.offset } } -impl embedded_hal::digital::ErrorType for EmioPin { - type Error = InvalidPinModeEmio; -} - -impl embedded_hal::digital::InputPin for EmioPin { - #[inline] - fn is_high(&mut self) -> Result { - self.is_high_mut() - } - #[inline] - fn is_low(&mut self) -> Result { - self.is_low_mut() - } -} - -impl embedded_hal::digital::OutputPin for EmioPin { - #[inline] - fn set_high(&mut self) -> Result<(), Self::Error> { - self.set_high() - } - #[inline] - fn set_low(&mut self) -> Result<(), Self::Error> { - self.set_low() - } -} - -impl embedded_hal::digital::StatefulOutputPin for EmioPin { - fn is_set_high(&mut self) -> Result { - self.is_set_high() - } - - fn is_set_low(&mut self) -> Result { - self.is_set_low() - } -} - -pub struct EmioPins { +pub struct Pins { emios: [Option; 64], } -impl EmioPins { +impl Pins { /// Create a new EMIO pin structure. /// /// This structure is supposed to be used as a singleton. It will configure all @@ -270,12 +31,7 @@ impl EmioPins { mmio.bank_3().write_dirm(0); (0..64).for_each(|i| { - let mmio = unsafe { Gpio::new_mmio_fixed() }; - emios[i] = Some(EmioPin { - regs: mmio, - mode: DynPinModeEmio::Input, - offset: i, - }); + emios[i] = Some(EmioPin { offset: i }); }); Self { emios } } diff --git a/zynq7000-hal/src/gpio/ll.rs b/zynq7000-hal/src/gpio/ll.rs new file mode 100644 index 0000000..9440b78 --- /dev/null +++ b/zynq7000-hal/src/gpio/ll.rs @@ -0,0 +1,338 @@ +//! Low-level GPIO access module. +use embedded_hal::digital::PinState; +use zynq7000::gpio::{Gpio, MaskedOutput, MmioGpio}; + +use crate::slcr::Slcr; + +use super::{PinIsOutputOnly, mio::MuxConf}; + +#[derive(Debug, Clone, Copy)] +pub enum PinOffset { + Mio(usize), + Emio(usize), +} + +impl PinOffset { + /// Returs [None] if offset is larger than 53. + pub const fn new_for_mio(offset: usize) -> Option { + if offset > 53 { + return None; + } + Some(PinOffset::Mio(offset)) + } + + /// Returs [None] if offset is larger than 63. + pub const fn new_for_emio(offset: usize) -> Option { + if offset > 63 { + return None; + } + Some(PinOffset::Emio(offset)) + } + + pub fn is_mio(&self) -> bool { + match self { + PinOffset::Mio(_) => true, + PinOffset::Emio(_) => false, + } + } +} + +impl PinOffset { + pub fn offset(&self) -> usize { + match self { + PinOffset::Mio(offset) => *offset, + PinOffset::Emio(offset) => *offset, + } + } +} + +pub struct LowLevelGpio { + offset: PinOffset, + regs: MmioGpio<'static>, +} + +impl LowLevelGpio { + pub fn new(offset: PinOffset) -> Self { + Self { + offset, + regs: unsafe { Gpio::new_mmio_fixed() }, + } + } + + pub fn offset(&self) -> PinOffset { + self.offset + } + + /// Convert the pin into an output pin. + pub fn configure_as_output_push_pull(&mut self, init_level: PinState) { + let (offset, dirm, outen) = self.get_dirm_outen_regs_and_local_offset(); + if self.offset.is_mio() { + // Tri-state bit must be 0 for the output driver to work. + self.reconfigure_slcr_mio_cfg(false, None, Some(MuxConf::new_for_gpio())); + } + let mut curr_dirm = unsafe { core::ptr::read_volatile(dirm) }; + curr_dirm |= 1 << offset; + unsafe { core::ptr::write_volatile(dirm, curr_dirm) }; + let mut curr_outen = unsafe { core::ptr::read_volatile(outen) }; + curr_outen |= 1 << offset; + unsafe { core::ptr::write_volatile(outen, curr_outen) }; + // Unwrap okay, just set mode. + self.write_state(init_level); + } + + /// Convert the pin into an output pin with open drain emulation. + /// + /// This works by only enabling the output driver when the pin is driven low and letting + /// the pin float when it is driven high. A pin pull-up is used for MIO pins as well which + /// pulls the pin to a defined state if it is not driven. This allows something like 1-wire bus + /// operation because other devices can pull the pin low as well. + /// + /// For EMIO pins, the pull-up and the IO buffer necessary for open-drain usage must be + /// provided by the FPGA design. + pub fn configure_as_output_open_drain(&mut self, init_level: PinState) { + let (offset, dirm, outen) = self.get_dirm_outen_regs_and_local_offset(); + if self.offset.is_mio() { + // Tri-state bit must be 0 for the output driver to work. Enable the pullup pin. + self.reconfigure_slcr_mio_cfg(false, Some(true), Some(MuxConf::new_for_gpio())); + } + let mut curr_dirm = unsafe { core::ptr::read_volatile(dirm) }; + curr_dirm |= 1 << offset; + unsafe { core::ptr::write_volatile(dirm, curr_dirm) }; + // Disable the output driver depending on initial level. + let mut curr_outen = unsafe { core::ptr::read_volatile(outen) }; + if init_level == PinState::High { + curr_outen &= !(1 << offset); + } else { + curr_outen |= 1 << offset; + } + unsafe { core::ptr::write_volatile(outen, curr_outen) }; + // Unwrap okay, just set mode. + self.write_state(init_level); + } + + /// Convert the pin into a floating input pin. + pub fn configure_as_input_floating(&mut self) -> Result<(), PinIsOutputOnly> { + if self.offset.is_mio() { + let offset_raw = self.offset.offset(); + if offset_raw == 7 || offset_raw == 8 { + return Err(PinIsOutputOnly); + } + self.reconfigure_slcr_mio_cfg(true, Some(false), Some(MuxConf::new_for_gpio())); + } + self.configure_input_pin(); + Ok(()) + } + + /// Convert the pin into an input pin with a pull up. + pub fn configure_as_input_with_pull_up(&mut self) -> Result<(), PinIsOutputOnly> { + if self.offset.is_mio() { + let offset_raw = self.offset.offset(); + if offset_raw == 7 || offset_raw == 8 { + return Err(PinIsOutputOnly); + } + self.reconfigure_slcr_mio_cfg(true, Some(true), Some(MuxConf::new_for_gpio())); + } + self.configure_input_pin(); + Ok(()) + } + + /// Convert the pin into an IO peripheral pin. + pub fn configure_as_io_periph_pin(&mut self, mux_conf: MuxConf, pullup: Option) { + self.reconfigure_slcr_mio_cfg(false, pullup, Some(mux_conf)); + } + + #[inline] + pub fn is_low(&self) -> bool { + let (offset, in_reg) = self.get_data_in_reg_and_local_offset(); + let in_val = unsafe { core::ptr::read_volatile(in_reg) }; + ((in_val >> offset) & 0b1) == 0 + } + + #[inline] + pub fn is_high(&self) -> bool { + !self.is_low() + } + + #[inline] + pub fn is_set_low(&self) -> bool { + let (offset, out_reg) = self.get_data_out_reg_and_local_offset(); + let out_val = unsafe { core::ptr::read_volatile(out_reg) }; + ((out_val >> offset) & 0b1) == 0 + } + + #[inline] + pub fn is_set_high(&self) -> bool { + !self.is_set_low() + } + + #[inline] + pub fn enable_output_driver(&mut self) { + let (offset, _dirm, outen) = self.get_dirm_outen_regs_and_local_offset(); + let mut outen_reg = unsafe { core::ptr::read_volatile(outen) }; + outen_reg |= 1 << offset; + unsafe { core::ptr::write_volatile(outen, outen_reg) }; + } + + #[inline] + pub fn disable_output_driver(&mut self) { + let (offset, _dirm, outen) = self.get_dirm_outen_regs_and_local_offset(); + let mut outen_reg = unsafe { core::ptr::read_volatile(outen) }; + outen_reg &= !(1 << offset); + unsafe { core::ptr::write_volatile(outen, outen_reg) }; + } + + #[inline] + pub fn set_low(&mut self) { + self.write_state(PinState::Low) + } + + #[inline] + pub fn set_high(&mut self) { + self.write_state(PinState::High) + } + + #[inline] + fn write_state(&mut self, level: PinState) { + let (offset_in_reg, masked_out_ptr) = self.get_masked_out_reg_and_local_offset(); + unsafe { + core::ptr::write_volatile( + masked_out_ptr, + MaskedOutput::builder() + .with_mask(!(1 << offset_in_reg)) + .with_output((level as u16) << offset_in_reg) + .build(), + ); + } + } + + fn reconfigure_slcr_mio_cfg( + &mut self, + tristate: bool, + pullup: Option, + mux_conf: Option, + ) { + let raw_offset = self.offset.offset(); + // Safety: We only modify the MIO config of the pin. + let mut slcr_wrapper = unsafe { Slcr::steal() }; + // We read first, because writing also required unlocking the SLCR. + // This allows the user to configure the SLCR themselves to avoid unnecessary + // re-configuration which might also be potentially unsafe at run-time. + let mio_cfg = slcr_wrapper.regs().read_mio_pins(raw_offset).unwrap(); + if (pullup.is_some() && mio_cfg.pullup() != pullup.unwrap()) + || (mux_conf.is_some() && MuxConf::from(mio_cfg) != mux_conf.unwrap()) + || tristate != mio_cfg.tri_enable() + { + slcr_wrapper.modify(|mut_slcr| { + mut_slcr + .modify_mio_pins(raw_offset, |mut val| { + if let Some(pullup) = pullup { + val.set_pullup(pullup); + } + if let Some(mux_conf) = mux_conf { + val.set_l0_sel(mux_conf.l0_sel()); + val.set_l1_sel(mux_conf.l1_sel()); + val.set_l2_sel(mux_conf.l2_sel()); + val.set_l3_sel(mux_conf.l3_sel()); + } + val.set_tri_enable(tristate); + val + }) + .unwrap(); + }); + } + } + + fn configure_input_pin(&mut self) { + let (offset, dirm, outen) = self.get_dirm_outen_regs_and_local_offset(); + let mut curr_dirm = unsafe { core::ptr::read_volatile(dirm) }; + curr_dirm &= !(1 << offset); + unsafe { core::ptr::write_volatile(dirm, curr_dirm) }; + let mut curr_outen = unsafe { core::ptr::read_volatile(outen) }; + curr_outen &= !(1 << offset); + unsafe { core::ptr::write_volatile(outen, curr_outen) }; + } + + #[inline(always)] + fn get_data_in_reg_and_local_offset(&self) -> (usize, *mut u32) { + match self.offset { + PinOffset::Mio(offset) => match offset { + 0..=31 => (offset, self.regs.pointer_to_in_0()), + 32..=53 => (offset - 32, self.regs.pointer_to_in_1()), + _ => panic!("invalid MIO pin offset"), + }, + PinOffset::Emio(offset) => match offset { + 0..=31 => (offset, self.regs.pointer_to_in_2()), + 32..=63 => (offset - 32, self.regs.pointer_to_in_3()), + _ => panic!("invalid EMIO pin offset"), + }, + } + } + + #[inline(always)] + fn get_data_out_reg_and_local_offset(&self) -> (usize, *mut u32) { + match self.offset { + PinOffset::Mio(offset) => match offset { + 0..=31 => (offset, self.regs.pointer_to_out_0()), + 32..=53 => (offset - 32, self.regs.pointer_to_out_1()), + _ => panic!("invalid MIO pin offset"), + }, + PinOffset::Emio(offset) => match offset { + 0..=31 => (offset, self.regs.pointer_to_out_2()), + 32..=63 => (offset - 32, self.regs.pointer_to_out_3()), + _ => panic!("invalid EMIO pin offset"), + }, + } + } + + #[inline(always)] + fn get_dirm_outen_regs_and_local_offset(&self) -> (usize, *mut u32, *mut u32) { + match self.offset { + PinOffset::Mio(offset) => match offset { + 0..=31 => ( + offset, + self.regs.bank_0_shared().pointer_to_dirm(), + self.regs.bank_0_shared().pointer_to_out_en(), + ), + 32..=53 => ( + offset - 32, + self.regs.bank_1_shared().pointer_to_dirm(), + self.regs.bank_1_shared().pointer_to_out_en(), + ), + _ => panic!("invalid MIO pin offset"), + }, + PinOffset::Emio(offset) => match offset { + 0..=31 => ( + offset, + self.regs.bank_2_shared().pointer_to_dirm(), + self.regs.bank_2_shared().pointer_to_out_en(), + ), + 32..=63 => ( + offset - 32, + self.regs.bank_3_shared().pointer_to_dirm(), + self.regs.bank_3_shared().pointer_to_out_en(), + ), + _ => panic!("invalid EMIO pin offset"), + }, + } + } + + #[inline(always)] + fn get_masked_out_reg_and_local_offset(&mut self) -> (usize, *mut MaskedOutput) { + match self.offset { + PinOffset::Mio(offset) => match offset { + 0..=15 => (offset, self.regs.pointer_to_masked_out_0_lsw()), + 16..=31 => (offset - 16, self.regs.pointer_to_masked_out_0_msw()), + 32..=47 => (offset - 32, self.regs.pointer_to_masked_out_1_lsw()), + 48..=53 => (offset - 48, self.regs.pointer_to_masked_out_1_msw()), + _ => panic!("invalid MIO pin offset"), + }, + PinOffset::Emio(offset) => match offset { + 0..=15 => (offset, self.regs.pointer_to_masked_out_2_lsw()), + 16..=31 => (offset - 16, self.regs.pointer_to_masked_out_2_msw()), + 32..=47 => (offset - 32, self.regs.pointer_to_masked_out_3_lsw()), + 48..=63 => (offset - 48, self.regs.pointer_to_masked_out_3_msw()), + _ => panic!("invalid EMIO pin offset"), + }, + } + } +} diff --git a/zynq7000-hal/src/gpio/mio.rs b/zynq7000-hal/src/gpio/mio.rs index dc3b1b6..3ce38f2 100644 --- a/zynq7000-hal/src/gpio/mio.rs +++ b/zynq7000-hal/src/gpio/mio.rs @@ -1,48 +1,64 @@ //! Multiplexed I/O (MIO) module. //! -//! This module provides a type-state API for all MIO pins. This also allows associating -//! the pins, their modes and their IDs to the peripherals they are able to serve. -//! -//! The pins can be type-erased for easier handling, which also incurs some more run-time checks. -//! -//! # Examples -//! -//! - [Blinky](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/examples/simple/src/main.rs) -//! - [Logger example](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/examples/simple/src/bin/logger.rs) -//! which uses MIO pins for the UART. -use embedded_hal::digital::InputPin; +//! This module provides a [singleton][Pins] for the resource management of all MIO pins. This +//! also allows associating the pins, their modes and their IDs to the peripherals they are able to +//! serve. +use arbitrary_int::{u2, u3}; use zynq7000::gpio::MmioGpio; -use crate::sealed; +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct MuxConf { + l3: u3, + l2: u2, + l1: bool, + l0: bool, +} -use super::{DynMioPin, DynPinModeMio, MioPinProvider, MuxConf, PinIsOutputOnly, PinState}; +impl From for MuxConf { + fn from(value: zynq7000::slcr::mio::Config) -> Self { + Self::new( + value.l0_sel(), + value.l1_sel(), + value.l2_sel(), + value.l3_sel(), + ) + } +} -pub trait PinMode: sealed::Sealed {} -pub trait InputMode: sealed::Sealed {} +impl MuxConf { + #[inline] + pub const fn new(l0: bool, l1: bool, l2: u2, l3: u3) -> Self { + Self { l3, l2, l1, l0 } + } -pub struct Output; + pub const fn new_with_l3(l3: u3) -> Self { + Self::new(false, false, u2::new(0b00), l3) + } -impl PinMode for Output {} -impl sealed::Sealed for Output {} + pub const fn new_for_gpio() -> Self { + Self::new(false, false, u2::new(0), u3::new(0)) + } -pub struct Input(core::marker::PhantomData); + #[inline] + pub const fn l0_sel(&self) -> bool { + self.l0 + } -impl PinMode for Input {} -impl sealed::Sealed for Input {} + #[inline] + pub const fn l1_sel(&self) -> bool { + self.l1 + } -pub struct PullUp; -pub struct Floating; + #[inline] + pub const fn l2_sel(&self) -> u2 { + self.l2 + } -impl InputMode for PullUp {} -impl sealed::Sealed for PullUp {} -impl InputMode for Floating {} -impl sealed::Sealed for Floating {} - -pub struct IoPeriph; -impl sealed::Sealed for IoPeriph {} -impl PinMode for IoPeriph {} - -pub type Reset = Input; + #[inline] + pub const fn l3_sel(&self) -> u3 { + self.l3 + } +} pub trait PinId { const OFFSET: usize; @@ -141,29 +157,19 @@ pin_id!(Mio51, 51); pin_id!(Mio52, 52); pin_id!(Mio53, 53); -pub struct MioPin { - inner: DynMioPin, - phantom: core::marker::PhantomData<(I, S)>, +pub trait MioPinMarker { + fn offset(&self) -> usize; } -pub trait IoPeriphPin { - fn mux_conf(&self) -> MuxConf; +pub struct Pin { + phantom: core::marker::PhantomData, } -impl MioPinProvider for MioPin { - delegate::delegate! { - to self.inner { - fn mode(&self) -> &DynPinModeMio; - fn offset(&self) -> usize; - } - } -} - -impl MioPin { +impl Pin { #[inline] const unsafe fn new() -> Self { Self { - inner: DynMioPin::new(I::OFFSET, DynPinModeMio::InputPullUp), + //pin: LowLevelPin::new(I::OFFSET), phantom: core::marker::PhantomData, } } @@ -184,292 +190,175 @@ impl MioPin { pub const unsafe fn steal() -> Self { unsafe { Self::new() } } - - /// Convert the pin to the requested [`PinMode`] - #[inline] - pub fn into_mode(self) -> MioPin { - // Safe because we drop the existing Pin - MioPin { - inner: self.inner, - phantom: core::marker::PhantomData, - } - } - - pub fn into_floating_input(mut self) -> Result>, PinIsOutputOnly> { - self.inner.into_input_floating()?; - Ok(self.into_mode()) - } - - pub fn into_pull_up_input(mut self) -> Result>, PinIsOutputOnly> { - self.inner.into_input_pull_up()?; - Ok(self.into_mode()) - } - - pub fn into_output(mut self, init_level: PinState) -> MioPin { - self.inner.into_output(init_level); - self.into_mode() - } - - pub fn into_io_periph( - mut self, - mux_conf: MuxConf, - pullup: Option, - ) -> MioPin { - self.inner.into_io_periph_pin(mux_conf, pullup); - self.into_mode() - } - - /// Type-erase the pin. - #[inline] - pub const fn downgrade(self) -> DynMioPin { - self.inner - } } -impl MioPin { - #[inline] - pub fn set_high(&mut self) { - self.inner.set_high_unchecked(); - } +pub struct Pins { + pub mio0: Pin, + pub mio1: Pin, + pub mio2: Pin, + pub mio3: Pin, + pub mio4: Pin, + pub mio5: Pin, + pub mio6: Pin, + pub mio7: Pin, + pub mio8: Pin, + pub mio9: Pin, + pub mio10: Pin, + pub mio11: Pin, + pub mio12: Pin, + pub mio13: Pin, + pub mio14: Pin, + pub mio15: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio16: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio17: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio18: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio19: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio20: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio21: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio22: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio23: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio24: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio25: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio26: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio27: Pin, + pub mio28: Pin, + pub mio29: Pin, + pub mio30: Pin, + pub mio31: Pin, - #[inline] - pub fn set_low(&mut self) { - self.inner.set_low_unchecked(); - } - - #[inline] - pub fn is_set_high(&self) { - self.inner.is_set_high_unchecked(); - } - - #[inline] - pub fn is_set_low(&self) { - self.inner.is_set_low_unchecked(); - } + pub mio32: Pin, + pub mio33: Pin, + pub mio34: Pin, + pub mio35: Pin, + pub mio36: Pin, + pub mio37: Pin, + pub mio38: Pin, + pub mio39: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio40: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio41: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio42: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio43: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio44: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio45: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio46: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio47: Pin, + pub mio48: Pin, + pub mio49: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio50: Pin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio51: Pin, + pub mio52: Pin, + pub mio53: Pin, } -impl IoPeriphPin for MioPin { - #[inline] - fn mux_conf(&self) -> MuxConf { - if let DynPinModeMio::IoPeriph(mux_conf) = self.inner.mode() { - *mux_conf - } else { - // This should never happen due to type state guarantees. - panic!("unexpected pin state"); - } - } -} - -impl MioPin { - #[inline] - pub fn is_high(&self) -> bool { - self.inner.is_high_unchecked() - } - - #[inline] - pub fn is_low(&self) -> bool { - self.inner.is_low_unchecked() - } -} - -pub struct MioPins { - pub mio0: MioPin, - pub mio1: MioPin, - pub mio2: MioPin, - pub mio3: MioPin, - pub mio4: MioPin, - pub mio5: MioPin, - pub mio6: MioPin, - pub mio7: MioPin, - pub mio8: MioPin, - pub mio9: MioPin, - pub mio10: MioPin, - pub mio11: MioPin, - pub mio12: MioPin, - pub mio13: MioPin, - pub mio14: MioPin, - pub mio15: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio16: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio17: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio18: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio19: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio20: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio21: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio22: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio23: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio24: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio25: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio26: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio27: MioPin, - pub mio28: MioPin, - pub mio29: MioPin, - pub mio30: MioPin, - pub mio31: MioPin, - - pub mio32: MioPin, - pub mio33: MioPin, - pub mio34: MioPin, - pub mio35: MioPin, - pub mio36: MioPin, - pub mio37: MioPin, - pub mio38: MioPin, - pub mio39: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio40: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio41: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio42: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio43: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio44: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio45: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio46: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio47: MioPin, - pub mio48: MioPin, - pub mio49: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio50: MioPin, - #[cfg(not(feature = "7z010-7z007s-clg225"))] - pub mio51: MioPin, - pub mio52: MioPin, - pub mio53: MioPin, -} - -impl MioPins { +impl Pins { pub const fn new(_mmio: MmioGpio) -> Self { Self { - mio0: unsafe { MioPin::new() }, - mio1: unsafe { MioPin::new() }, - mio2: unsafe { MioPin::new() }, - mio3: unsafe { MioPin::new() }, - mio4: unsafe { MioPin::new() }, - mio5: unsafe { MioPin::new() }, - mio6: unsafe { MioPin::new() }, - mio7: unsafe { MioPin::new() }, - mio8: unsafe { MioPin::new() }, - mio9: unsafe { MioPin::new() }, - mio10: unsafe { MioPin::new() }, - mio11: unsafe { MioPin::new() }, - mio12: unsafe { MioPin::new() }, - mio13: unsafe { MioPin::new() }, - mio14: unsafe { MioPin::new() }, - mio15: unsafe { MioPin::new() }, + mio0: unsafe { Pin::new() }, + mio1: unsafe { Pin::new() }, + mio2: unsafe { Pin::new() }, + mio3: unsafe { Pin::new() }, + mio4: unsafe { Pin::new() }, + mio5: unsafe { Pin::new() }, + mio6: unsafe { Pin::new() }, + mio7: unsafe { Pin::new() }, + mio8: unsafe { Pin::new() }, + mio9: unsafe { Pin::new() }, + mio10: unsafe { Pin::new() }, + mio11: unsafe { Pin::new() }, + mio12: unsafe { Pin::new() }, + mio13: unsafe { Pin::new() }, + mio14: unsafe { Pin::new() }, + mio15: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio16: unsafe { MioPin::new() }, + mio16: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio17: unsafe { MioPin::new() }, + mio17: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio18: unsafe { MioPin::new() }, + mio18: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio19: unsafe { MioPin::new() }, + mio19: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio20: unsafe { MioPin::new() }, + mio20: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio21: unsafe { MioPin::new() }, + mio21: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio22: unsafe { MioPin::new() }, + mio22: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio23: unsafe { MioPin::new() }, + mio23: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio24: unsafe { MioPin::new() }, + mio24: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio25: unsafe { MioPin::new() }, + mio25: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio26: unsafe { MioPin::new() }, + mio26: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio27: unsafe { MioPin::new() }, - mio28: unsafe { MioPin::new() }, - mio29: unsafe { MioPin::new() }, - mio30: unsafe { MioPin::new() }, - mio31: unsafe { MioPin::new() }, + mio27: unsafe { Pin::new() }, + mio28: unsafe { Pin::new() }, + mio29: unsafe { Pin::new() }, + mio30: unsafe { Pin::new() }, + mio31: unsafe { Pin::new() }, - mio32: unsafe { MioPin::new() }, - mio33: unsafe { MioPin::new() }, - mio34: unsafe { MioPin::new() }, - mio35: unsafe { MioPin::new() }, - mio36: unsafe { MioPin::new() }, - mio37: unsafe { MioPin::new() }, - mio38: unsafe { MioPin::new() }, - mio39: unsafe { MioPin::new() }, + mio32: unsafe { Pin::new() }, + mio33: unsafe { Pin::new() }, + mio34: unsafe { Pin::new() }, + mio35: unsafe { Pin::new() }, + mio36: unsafe { Pin::new() }, + mio37: unsafe { Pin::new() }, + mio38: unsafe { Pin::new() }, + mio39: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio40: unsafe { MioPin::new() }, + mio40: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio41: unsafe { MioPin::new() }, + mio41: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio42: unsafe { MioPin::new() }, + mio42: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio43: unsafe { MioPin::new() }, + mio43: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio44: unsafe { MioPin::new() }, + mio44: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio45: unsafe { MioPin::new() }, + mio45: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio46: unsafe { MioPin::new() }, + mio46: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio47: unsafe { MioPin::new() }, - mio48: unsafe { MioPin::new() }, - mio49: unsafe { MioPin::new() }, + mio47: unsafe { Pin::new() }, + mio48: unsafe { Pin::new() }, + mio49: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio50: unsafe { MioPin::new() }, + mio50: unsafe { Pin::new() }, #[cfg(not(feature = "7z010-7z007s-clg225"))] - mio51: unsafe { MioPin::new() }, - mio52: unsafe { MioPin::new() }, - mio53: unsafe { MioPin::new() }, + mio51: unsafe { Pin::new() }, + mio52: unsafe { Pin::new() }, + mio53: unsafe { Pin::new() }, } } } -impl embedded_hal::digital::ErrorType for MioPin { - type Error = core::convert::Infallible; -} - -impl embedded_hal::digital::OutputPin for MioPin { - #[inline] - fn set_low(&mut self) -> Result<(), Self::Error> { - self.inner.set_low_unchecked(); - Ok(()) - } - #[inline] - fn set_high(&mut self) -> Result<(), Self::Error> { - self.inner.set_high_unchecked(); - Ok(()) - } -} - -impl embedded_hal::digital::StatefulOutputPin for MioPin { - fn is_set_high(&mut self) -> Result { - Ok(self.inner.is_set_high_unchecked()) - } - - fn is_set_low(&mut self) -> Result { - Ok(self.inner.is_set_low_unchecked()) - } -} - -impl embedded_hal::digital::InputPin for MioPin { - fn is_high(&mut self) -> Result { - Ok(self.inner.is_high_unchecked()) - } - - fn is_low(&mut self) -> Result { - Ok(self.inner.is_low_unchecked()) +impl MioPinMarker for Pin { + fn offset(&self) -> usize { + I::OFFSET } } diff --git a/zynq7000-hal/src/gpio/mod.rs b/zynq7000-hal/src/gpio/mod.rs index ac1cf6e..c7a895a 100644 --- a/zynq7000-hal/src/gpio/mod.rs +++ b/zynq7000-hal/src/gpio/mod.rs @@ -1,27 +1,42 @@ //! GPIO support module for the Zynq7000 SoC. -pub mod dyn_mio; +//! +//! This module contains a MIO and EMIO pin resource managements singleton as well as abstractions +//! to use these pins as GPIOs. +//! +//! # Examples +//! +//! - [Blinky](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/examples/simple/src/main.rs) +//! - [Logger example](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/examples/simple/src/bin/logger.rs) +//! which uses MIO pins for the UART. pub mod emio; +pub mod ll; pub mod mio; -use crate::{enable_amba_peripheral_clock, slcr::Slcr}; -pub use dyn_mio::*; -pub use emio::*; -pub use mio::*; +use core::convert::Infallible; +use ll::PinOffset; +use mio::{MioPinMarker, MuxConf}; +use crate::gpio::ll::LowLevelGpio; +use crate::{enable_amba_peripheral_clock, slcr::Slcr}; pub use embedded_hal::digital::PinState; use zynq7000::{gpio::MmioGpio, slcr::reset::GpioClockReset}; +#[derive(Debug, thiserror::Error)] +#[error("MIO pins 7 and 8 can only be output pins")] +pub struct PinIsOutputOnly; + +/// GPIO pin singleton to allow resource management of both MIO and EMIO pins. pub struct GpioPins { - pub mio: MioPins, - pub emio: EmioPins, + pub mio: mio::Pins, + pub emio: emio::Pins, } impl GpioPins { pub fn new(gpio: MmioGpio) -> Self { enable_amba_peripheral_clock(crate::PeripheralSelect::Gpio); Self { - mio: MioPins::new(unsafe { gpio.clone() }), - emio: EmioPins::new(gpio), + mio: mio::Pins::new(unsafe { gpio.clone() }), + emio: emio::Pins::new(gpio), } } } @@ -40,3 +55,352 @@ pub fn reset() { }); } } + +/// Enumeration of all pin modes. Some of the modes are only valid for MIO pins. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum PinMode { + OutputPushPull, + /// See [super::gpio] documentation for more information on running an output pin in + /// open-drain configuration. + OutputOpenDrain, + InputFloating, + InputPullUp, + /// MIO-only peripheral pin configuration + MioIoPeriph(MuxConf), +} + +#[derive(Debug, thiserror::Error)] +#[error("invalid pin mode for MIO pin: {0:?}")] +pub struct InvalidPinMode(pub PinMode); + +impl embedded_hal::digital::Error for InvalidPinMode { + fn kind(&self) -> embedded_hal::digital::ErrorKind { + embedded_hal::digital::ErrorKind::Other + } +} + +pub trait IoPinProvider { + fn mode(&self) -> PinMode; + + fn offset(&self) -> PinOffset; + + #[inline] + fn is_input(&self) -> bool { + matches!(self.mode(), PinMode::InputFloating | PinMode::InputPullUp) + } + #[inline] + fn is_output(&self) -> bool { + matches!( + self.mode(), + PinMode::OutputPushPull | PinMode::OutputOpenDrain + ) + } + + #[inline] + fn is_io_periph(&self) -> bool { + matches!(self.mode(), PinMode::MioIoPeriph(_)) + } +} + +/// Flex pin abstraction which can be dynamically re-configured. +/// +/// The following functions can be configured at run-time: +/// +/// - Input Floating +/// - Input with Pull-Up +/// - Output Push-Pull +/// - Output Open-Drain. +/// +/// Flex pins are always floating input pins after construction except for MIO7 and MIO8, +/// which are Push-Pull Output pins with initial low-level. +/// +/// ## Notes on [PinMode::OutputOpenDrain] configuration +/// +/// For MIO, the open-drain functionality is simulated by only enabling the output driver +/// when driving the pin low, and leaving the pin floating when the pin is driven high. +/// The internal pull-up will also be enabled to have a high state if the pin is not driven. +/// +/// For EMIO, the pull-up and the IO buffer needs to be provided in the FPGA design for the +/// used EMIO pins because the EMIO pins are just wires going out to the FPGA design. +/// The software will still perform the necessary logic when driving the pin low or high. +/// +/// ## Notes on [PinMode::InputPullUp] configuration +/// +/// For EMIO, the pull-up wiring needs to be provided by the FPGA design. +pub struct Flex { + ll: LowLevelGpio, + mode: PinMode, +} + +impl Flex { + pub fn new_for_mio(_pin: mio::Pin) -> Self { + let mut ll = LowLevelGpio::new(PinOffset::Mio(I::OFFSET)); + if I::OFFSET == 7 || I::OFFSET == 8 { + ll.configure_as_output_push_pull(PinState::Low); + } else { + ll.configure_as_input_floating().unwrap(); + } + Self { + ll, + mode: PinMode::InputFloating, + } + } + + pub fn new_for_emio(pin: emio::EmioPin) -> Self { + let mut ll = LowLevelGpio::new(PinOffset::new_for_emio(pin.offset()).unwrap()); + ll.configure_as_input_floating().unwrap(); + Self { + ll, + mode: PinMode::InputFloating, + } + } + + pub fn configure_as_input_floating(&mut self) -> Result<(), PinIsOutputOnly> { + self.mode = PinMode::InputFloating; + self.ll.configure_as_input_floating() + } + + pub fn configure_as_input_with_pull_up(&mut self) -> Result<(), PinIsOutputOnly> { + self.mode = PinMode::InputPullUp; + self.ll.configure_as_input_with_pull_up() + } + + pub fn configure_as_output_push_pull(&mut self, level: PinState) { + self.mode = PinMode::OutputPushPull; + self.ll.configure_as_output_push_pull(level); + } + + pub fn configure_as_output_open_drain(&mut self, level: PinState) { + self.mode = PinMode::OutputOpenDrain; + self.ll.configure_as_output_open_drain(level); + } + + /// If the pin is configured as an input pin, this function does nothing. + pub fn set_high(&mut self) { + if self.is_input() { + return; + } + if self.mode == PinMode::OutputOpenDrain { + self.ll.disable_output_driver(); + } else { + self.ll.set_high(); + } + } + + /// If the pin is configured as an input pin, this function does nothing. + pub fn set_low(&mut self) { + if self.is_input() { + return; + } + if self.mode == PinMode::OutputOpenDrain { + self.ll.enable_output_driver(); + } + self.ll.set_low(); + } + + /// Reads the input state of the pin, regardless of configured mode. + #[inline] + pub fn is_high(&self) -> bool { + self.ll.is_high() + } + + /// Reads the input state of the pin, regardless of configured mode. + #[inline] + pub fn is_low(&self) -> bool { + !self.ll.is_high() + } + + /// If the pin is not configured as a stateful output pin like Output Push-Pull, the result + /// of this function is undefined. + #[inline] + pub fn is_set_low(&self) -> bool { + self.ll.is_set_low() + } + + /// If the pin is not configured as a stateful output pin like Output Push-Pull, the result + /// of this function is undefined. + #[inline] + pub fn is_set_high(&self) -> bool { + !self.is_set_low() + } +} + +impl IoPinProvider for Flex { + fn mode(&self) -> PinMode { + self.mode + } + + fn offset(&self) -> PinOffset { + self.ll.offset() + } +} + +impl embedded_hal::digital::ErrorType for Flex { + type Error = Infallible; +} + +impl embedded_hal::digital::InputPin for Flex { + /// Reads the input state of the pin, regardless of configured mode. + #[inline] + fn is_high(&mut self) -> Result { + Ok(self.ll.is_high()) + } + + /// Reads the input state of the pin, regardless of configured mode. + #[inline] + fn is_low(&mut self) -> Result { + Ok(self.ll.is_high()) + } +} + +impl embedded_hal::digital::OutputPin for Flex { + /// If the pin is configured as an input pin, this function does nothing. + #[inline] + fn set_low(&mut self) -> Result<(), Self::Error> { + self.set_low(); + Ok(()) + } + + /// If the pin is configured as an input pin, this function does nothing. + #[inline] + fn set_high(&mut self) -> Result<(), Self::Error> { + self.set_high(); + Ok(()) + } +} + +impl embedded_hal::digital::StatefulOutputPin for Flex { + /// If the pin is not configured as a stateful output pin like Output Push-Pull, the result + /// of this function is undefined. + #[inline] + fn is_set_high(&mut self) -> Result { + Ok(self.ll.is_set_high()) + } + + /// If the pin is not configured as a stateful output pin like Output Push-Pull, the result + /// of this function is undefined. + #[inline] + fn is_set_low(&mut self) -> Result { + Ok(self.ll.is_set_low()) + } +} + +/// Push-Pull output pin. +pub struct Output(LowLevelGpio); + +impl Output { + pub fn new_for_mio(_pin: mio::Pin, init_level: PinState) -> Self { + let mut low_level = LowLevelGpio::new(PinOffset::Mio(I::OFFSET)); + low_level.configure_as_output_push_pull(init_level); + Self(low_level) + } + + pub fn new_for_emio(pin: emio::EmioPin, init_level: PinState) -> Self { + let mut low_level = LowLevelGpio::new(PinOffset::new_for_emio(pin.offset()).unwrap()); + low_level.configure_as_output_push_pull(init_level); + Self(low_level) + } + + #[inline] + pub fn set_low(&mut self) { + self.0.set_low(); + } + + #[inline] + pub fn set_high(&mut self) { + self.0.set_high(); + } +} + +impl embedded_hal::digital::ErrorType for Output { + type Error = Infallible; +} + +impl embedded_hal::digital::OutputPin for Output { + fn set_low(&mut self) -> Result<(), Self::Error> { + self.0.set_low(); + Ok(()) + } + fn set_high(&mut self) -> Result<(), Self::Error> { + self.0.set_high(); + Ok(()) + } +} + +impl embedded_hal::digital::StatefulOutputPin for Output { + fn is_set_high(&mut self) -> Result { + Ok(self.0.is_set_high()) + } + + fn is_set_low(&mut self) -> Result { + Ok(self.0.is_set_low()) + } +} + +/// Input pin. +pub struct Input(LowLevelGpio); + +impl Input { + pub fn new_for_mio(_pin: mio::Pin) -> Result { + let mut low_level = LowLevelGpio::new(PinOffset::Mio(I::OFFSET)); + low_level.configure_as_input_floating()?; + Ok(Self(low_level)) + } + + pub fn new_for_emio(pin: emio::EmioPin) -> Result { + let mut low_level = LowLevelGpio::new(PinOffset::new_for_emio(pin.offset()).unwrap()); + low_level.configure_as_input_floating()?; + Ok(Self(low_level)) + } + + pub fn is_high(&self) -> bool { + self.0.is_high() + } + + pub fn is_low(&self) -> bool { + self.0.is_low() + } +} + +impl embedded_hal::digital::ErrorType for Input { + type Error = Infallible; +} + +impl embedded_hal::digital::InputPin for Input { + fn is_high(&mut self) -> Result { + Ok(self.0.is_high()) + } + + fn is_low(&mut self) -> Result { + Ok(self.0.is_low()) + } +} + +/// IO peripheral pin. +pub struct IoPeriphPin { + pin: LowLevelGpio, + mux_conf: MuxConf, +} + +impl IoPeriphPin { + pub fn new(pin: impl MioPinMarker, mux_conf: MuxConf, pullup: Option) -> Self { + let mut low_level = LowLevelGpio::new(PinOffset::Mio(pin.offset())); + low_level.configure_as_io_periph_pin(mux_conf, pullup); + Self { + pin: low_level, + mux_conf, + } + } +} + +impl IoPinProvider for IoPeriphPin { + #[inline] + fn mode(&self) -> PinMode { + PinMode::MioIoPeriph(self.mux_conf) + } + + #[inline] + fn offset(&self) -> PinOffset { + self.pin.offset() + } +} diff --git a/zynq7000-hal/src/i2c.rs b/zynq7000-hal/src/i2c.rs index 7f6e523..139a927 100644 --- a/zynq7000-hal/src/i2c.rs +++ b/zynq7000-hal/src/i2c.rs @@ -6,16 +6,19 @@ use zynq7000::{ }; #[cfg(not(feature = "7z010-7z007s-clg225"))] -use crate::gpio::{ +use crate::gpio::mio::{ Mio16, Mio17, Mio18, Mio19, Mio20, Mio21, Mio22, Mio23, Mio24, Mio25, Mio26, Mio27, Mio40, Mio41, Mio42, Mio43, Mio44, Mio45, Mio46, Mio47, Mio50, Mio51, }; use crate::{ enable_amba_peripheral_clock, gpio::{ - IoPeriph, IoPeriphPin, Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, Mio30, - Mio31, Mio32, Mio33, Mio34, Mio35, Mio36, Mio37, Mio38, Mio39, Mio48, Mio49, Mio52, Mio53, - MioPin, MuxConf, PinMode, + IoPeriphPin, + mio::{ + Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, Mio30, Mio31, Mio32, Mio33, + Mio34, Mio35, Mio36, Mio37, Mio38, Mio39, Mio48, Mio49, Mio52, Mio53, MioPinMarker, + MuxConf, Pin, + }, }, slcr::Slcr, time::Hertz, @@ -55,16 +58,31 @@ impl PsI2c for MmioI2c<'static> { } } -pub trait SdaPin: IoPeriphPin { +pub trait SdaPin: MioPinMarker { const ID: I2cId; } -pub trait SckPin: IoPeriphPin { +pub trait SckPin: MioPinMarker { const ID: I2cId; } pub trait I2cPins {} +macro_rules! i2c_pin_impls { + ($Id: path, $SckMio:ident, $SdaMio:ident) => { + impl SckPin for Pin<$SckMio> { + const ID: I2cId = $Id; + } + + impl SdaPin for Pin<$SdaMio> { + const ID: I2cId = $Id; + } + + impl I2cPins for (Pin<$SckMio>, Pin<$SdaMio>) {} + }; +} + +/* macro_rules! into_i2c { ($($Mio:ident),+) => { $( @@ -80,20 +98,6 @@ macro_rules! into_i2c { }; } -macro_rules! i2c_pin_impls { - ($Id: path, $SckMio:ident, $SdaMio:ident) => { - impl SckPin for MioPin<$SckMio, IoPeriph> { - const ID: I2cId = $Id; - } - - impl SdaPin for MioPin<$SdaMio, IoPeriph> { - const ID: I2cId = $Id; - } - - impl I2cPins for (MioPin<$SckMio, IoPeriph>, MioPin<$SdaMio, IoPeriph>) {} - }; -} - into_i2c!( Mio10, Mio11, Mio14, Mio15, Mio30, Mio31, Mio34, Mio35, Mio38, Mio39, Mio12, Mio13, Mio28, Mio29, Mio32, Mio33, Mio36, Mio37, Mio48, Mio49, Mio52, Mio53 @@ -103,6 +107,7 @@ into_i2c!( Mio18, Mio19, Mio22, Mio23, Mio26, Mio27, Mio42, Mio43, Mio46, Mio47, Mio50, Mio51, Mio16, Mio17, Mio20, Mio21, Mio24, Mio25, Mio40, Mio41, Mio44, Mio45 ); +*/ i2c_pin_impls!(I2cId::I2c0, Mio10, Mio11); i2c_pin_impls!(I2cId::I2c0, Mio14, Mio15); @@ -318,9 +323,8 @@ impl I2c { if Sck::ID != Sda::ID { return Err(I2cConstructionError::PinInvalidForI2cId); } - if i2c_pins.0.mux_conf() != I2C_MUX_CONF || i2c_pins.1.mux_conf() != I2C_MUX_CONF { - return Err(I2cConstructionError::InvalidPinConf); - } + IoPeriphPin::new(i2c_pins.0, I2C_MUX_CONF, Some(true)); + IoPeriphPin::new(i2c_pins.1, I2C_MUX_CONF, Some(true)); Ok(Self::new_generic( i2c.id().unwrap(), i2c.reg_block(), diff --git a/zynq7000-hal/src/lib.rs b/zynq7000-hal/src/lib.rs index b241405..9ef1931 100644 --- a/zynq7000-hal/src/lib.rs +++ b/zynq7000-hal/src/lib.rs @@ -198,6 +198,7 @@ pub fn disable_amba_peripheral_clock(select: PeripheralSelect) { } } +#[allow(dead_code)] pub(crate) mod sealed { pub trait Sealed {} } diff --git a/zynq7000-hal/src/spi/mod.rs b/zynq7000-hal/src/spi/mod.rs index 8cda596..26ef457 100644 --- a/zynq7000-hal/src/spi/mod.rs +++ b/zynq7000-hal/src/spi/mod.rs @@ -3,12 +3,13 @@ use core::convert::Infallible; use crate::clocks::Clocks; use crate::enable_amba_peripheral_clock; -use crate::gpio::{ - IoPeriph, IoPeriphPin, Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, Mio30, Mio31, - Mio32, Mio33, Mio34, Mio35, Mio36, Mio37, Mio38, Mio39, MioPin, MuxConf, +use crate::gpio::IoPeriphPin; +use crate::gpio::mio::{ + Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, Mio30, Mio31, Mio32, Mio33, Mio34, + Mio35, Mio36, Mio37, Mio38, Mio39, MioPinMarker, MuxConf, Pin, }; #[cfg(not(feature = "7z010-7z007s-clg225"))] -use crate::gpio::{ +use crate::gpio::mio::{ Mio16, Mio17, Mio18, Mio19, Mio20, Mio21, Mio22, Mio23, Mio24, Mio25, Mio26, Mio27, Mio40, Mio41, Mio42, Mio43, Mio44, Mio45, Mio46, Mio47, Mio48, Mio49, Mio50, Mio51, }; @@ -59,22 +60,22 @@ impl PsSpi for MmioSpi<'static> { } } -pub trait SckPin: IoPeriphPin { +pub trait SckPin: MioPinMarker { const SPI: SpiId; const GROUP: usize; } -pub trait MosiPin: IoPeriphPin { +pub trait MosiPin: MioPinMarker { const SPI: SpiId; const GROUP: usize; } -pub trait MisoPin: IoPeriphPin { +pub trait MisoPin: MioPinMarker { const SPI: SpiId; const GROUP: usize; } -pub trait SsPin: IoPeriphPin { +pub trait SsPin: MioPinMarker { const IDX: usize; const SPI: SpiId; const GROUP: usize; @@ -82,15 +83,17 @@ pub trait SsPin: IoPeriphPin { pub const SPI_MUX_CONF: MuxConf = MuxConf::new_with_l3(u3::new(0b101)); +/* macro_rules! impl_into_spi { (($($Mio:ident),+)) => { $( - impl MioPin<$Mio, M> { + impl From> for IoPeriphPin { /// Convert the pin into SPI pins by configuring the pin routing via the /// MIO multiplexer bits. Also disables pull-ups for the pins. - pub fn into_spi(self) -> MioPin<$Mio, IoPeriph> { - self.into_io_periph(SPI_MUX_CONF, Some(false)) + fn from(pin: Pin<$Mio>) -> Self { + IoPeriphPin::new(pin, SPI_MUX_CONF, Some(false)) } + } )+ }; @@ -106,66 +109,67 @@ impl_into_spi!(( Mio28, Mio33, Mio29, Mio30, Mio31, Mio32, Mio12, Mio10, Mio11, Mio13, Mio14, Mio15, Mio36, Mio34, Mio35, Mio37, Mio38, Mio39 )); +*/ // SPI0, choice 1 #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl SckPin for MioPin { +impl SckPin for Pin { const SPI: SpiId = SpiId::Spi0; const GROUP: usize = 0; } #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl MosiPin for MioPin { +impl MosiPin for Pin { const SPI: SpiId = SpiId::Spi0; const GROUP: usize = 0; } #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl MisoPin for MioPin { +impl MisoPin for Pin { const SPI: SpiId = SpiId::Spi0; const GROUP: usize = 0; } #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl SsPin for MioPin { +impl SsPin for Pin { const SPI: SpiId = SpiId::Spi0; const GROUP: usize = 0; const IDX: usize = 0; } #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl SsPin for MioPin { +impl SsPin for Pin { const SPI: SpiId = SpiId::Spi0; const GROUP: usize = 0; const IDX: usize = 1; } #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl SsPin for MioPin { +impl SsPin for Pin { const SPI: SpiId = SpiId::Spi0; const GROUP: usize = 0; const IDX: usize = 2; } // SPI0, choice 2 -impl SckPin for MioPin { +impl SckPin for Pin { const SPI: SpiId = SpiId::Spi0; const GROUP: usize = 1; } -impl MosiPin for MioPin { +impl MosiPin for Pin { const SPI: SpiId = SpiId::Spi0; const GROUP: usize = 1; } -impl MisoPin for MioPin { +impl MisoPin for Pin { const SPI: SpiId = SpiId::Spi0; const GROUP: usize = 1; } -impl SsPin for MioPin { +impl SsPin for Pin { const SPI: SpiId = SpiId::Spi0; const GROUP: usize = 1; const IDX: usize = 0; } -impl SsPin for MioPin { +impl SsPin for Pin { const SPI: SpiId = SpiId::Spi0; const GROUP: usize = 1; const IDX: usize = 1; } -impl SsPin for MioPin { +impl SsPin for Pin { const SPI: SpiId = SpiId::Spi0; const GROUP: usize = 1; const IDX: usize = 2; @@ -173,63 +177,63 @@ impl SsPin for MioPin { // SPI0, choice 3 #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl SckPin for MioPin { +impl SckPin for Pin { const SPI: SpiId = SpiId::Spi0; const GROUP: usize = 2; } #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl MosiPin for MioPin { +impl MosiPin for Pin { const SPI: SpiId = SpiId::Spi0; const GROUP: usize = 2; } #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl MisoPin for MioPin { +impl MisoPin for Pin { const SPI: SpiId = SpiId::Spi0; const GROUP: usize = 2; } #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl SsPin for MioPin { +impl SsPin for Pin { const SPI: SpiId = SpiId::Spi0; const GROUP: usize = 2; const IDX: usize = 0; } #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl SsPin for MioPin { +impl SsPin for Pin { const SPI: SpiId = SpiId::Spi0; const GROUP: usize = 2; const IDX: usize = 1; } #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl SsPin for MioPin { +impl SsPin for Pin { const SPI: SpiId = SpiId::Spi0; const GROUP: usize = 2; const IDX: usize = 2; } // SPI1, choice 1 -impl SckPin for MioPin { +impl SckPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 0; } -impl MosiPin for MioPin { +impl MosiPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 0; } -impl MisoPin for MioPin { +impl MisoPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 0; } -impl SsPin for MioPin { +impl SsPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 0; const IDX: usize = 0; } -impl SsPin for MioPin { +impl SsPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 0; const IDX: usize = 1; } -impl SsPin for MioPin { +impl SsPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 0; const IDX: usize = 2; @@ -237,63 +241,63 @@ impl SsPin for MioPin { // SPI1, choice 2 #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl SckPin for MioPin { +impl SckPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 1; } #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl MosiPin for MioPin { +impl MosiPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 1; } #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl MisoPin for MioPin { +impl MisoPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 1; } #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl SsPin for MioPin { +impl SsPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 1; const IDX: usize = 0; } #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl SsPin for MioPin { +impl SsPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 1; const IDX: usize = 1; } #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl SsPin for MioPin { +impl SsPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 1; const IDX: usize = 2; } // SPI1, choice 2 -impl SckPin for MioPin { +impl SckPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 2; } -impl MosiPin for MioPin { +impl MosiPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 2; } -impl MisoPin for MioPin { +impl MisoPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 2; } -impl SsPin for MioPin { +impl SsPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 2; const IDX: usize = 0; } -impl SsPin for MioPin { +impl SsPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 2; const IDX: usize = 1; } -impl SsPin for MioPin { +impl SsPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 2; const IDX: usize = 2; @@ -301,34 +305,34 @@ impl SsPin for MioPin { // SPI1, choice 3 #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl SckPin for MioPin { +impl SckPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 3; } #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl MosiPin for MioPin { +impl MosiPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 3; } #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl MisoPin for MioPin { +impl MisoPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 3; } #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl SsPin for MioPin { +impl SsPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 3; const IDX: usize = 0; } #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl SsPin for MioPin { +impl SsPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 3; const IDX: usize = 1; } #[cfg(not(feature = "7z010-7z007s-clg225"))] -impl SsPin for MioPin { +impl SsPin for Pin { const SPI: SpiId = SpiId::Spi1; const GROUP: usize = 3; const IDX: usize = 2; @@ -555,8 +559,7 @@ impl SpiLowLevel { #[inline(always)] pub fn write_fifo_unchecked(&mut self, data: u8) { - self.regs - .write_txd(FifoWrite::new(data)); + self.regs.write_txd(FifoWrite::new(data)); } #[inline(always)] @@ -706,12 +709,9 @@ impl Spi { if Sck::SPI != spi_id || Mosi::SPI != spi_id || Miso::SPI != spi_id { return Err(SpiConstructionError::PinInvalidForSpiId); } - if spi_pins.0.mux_conf() != SPI_MUX_CONF - || spi_pins.0.mux_conf() != spi_pins.2.mux_conf() - || spi_pins.1.mux_conf() != spi_pins.2.mux_conf() - { - return Err(SpiConstructionError::InvalidPinConf); - } + IoPeriphPin::new(spi_pins.0, SPI_MUX_CONF, Some(false)); + IoPeriphPin::new(spi_pins.1, SPI_MUX_CONF, Some(false)); + IoPeriphPin::new(spi_pins.2, SPI_MUX_CONF, Some(false)); Ok(Self::new_generic_unchecked( spi_id, spi.reg_block(), @@ -738,13 +738,10 @@ impl Spi { if Sck::SPI != spi_id || Mosi::SPI != spi_id || Miso::SPI != spi_id || Ss::SPI != spi_id { return Err(SpiConstructionError::PinInvalidForSpiId); } - if spi_pins.0.mux_conf() != SPI_MUX_CONF - || spi_pins.0.mux_conf() != spi_pins.2.mux_conf() - || spi_pins.1.mux_conf() != spi_pins.2.mux_conf() - || ss_pin.mux_conf() != spi_pins.0.mux_conf() - { - return Err(SpiConstructionError::InvalidPinConf); - } + IoPeriphPin::new(spi_pins.0, SPI_MUX_CONF, Some(false)); + IoPeriphPin::new(spi_pins.1, SPI_MUX_CONF, Some(false)); + IoPeriphPin::new(spi_pins.2, SPI_MUX_CONF, Some(false)); + IoPeriphPin::new(ss_pin, SPI_MUX_CONF, Some(false)); Ok(Self::new_generic_unchecked( spi_id, spi.reg_block(), @@ -780,14 +777,11 @@ impl Spi { { return Err(SpiConstructionError::PinInvalidForSpiId); } - if spi_pins.0.mux_conf() != SPI_MUX_CONF - || spi_pins.0.mux_conf() != spi_pins.2.mux_conf() - || spi_pins.1.mux_conf() != spi_pins.2.mux_conf() - || ss_pins.0.mux_conf() != spi_pins.0.mux_conf() - || ss_pins.1.mux_conf() != spi_pins.0.mux_conf() - { - return Err(SpiConstructionError::InvalidPinConf); - } + IoPeriphPin::new(spi_pins.0, SPI_MUX_CONF, Some(false)); + IoPeriphPin::new(spi_pins.1, SPI_MUX_CONF, Some(false)); + IoPeriphPin::new(spi_pins.2, SPI_MUX_CONF, Some(false)); + IoPeriphPin::new(ss_pins.0, SPI_MUX_CONF, Some(false)); + IoPeriphPin::new(ss_pins.1, SPI_MUX_CONF, Some(false)); Ok(Self::new_generic_unchecked( spi_id, spi.reg_block(), @@ -832,15 +826,12 @@ impl Spi { { return Err(SpiConstructionError::PinInvalidForSpiId); } - if spi_pins.0.mux_conf() != SPI_MUX_CONF - || spi_pins.0.mux_conf() != spi_pins.2.mux_conf() - || spi_pins.1.mux_conf() != spi_pins.2.mux_conf() - || ss_pins.0.mux_conf() != spi_pins.0.mux_conf() - || ss_pins.1.mux_conf() != spi_pins.0.mux_conf() - || ss_pins.2.mux_conf() != spi_pins.2.mux_conf() - { - return Err(SpiConstructionError::InvalidPinConf); - } + IoPeriphPin::new(spi_pins.0, SPI_MUX_CONF, Some(false)); + IoPeriphPin::new(spi_pins.1, SPI_MUX_CONF, Some(false)); + IoPeriphPin::new(spi_pins.2, SPI_MUX_CONF, Some(false)); + IoPeriphPin::new(ss_pins.0, SPI_MUX_CONF, Some(false)); + IoPeriphPin::new(ss_pins.1, SPI_MUX_CONF, Some(false)); + IoPeriphPin::new(ss_pins.2, SPI_MUX_CONF, Some(false)); Ok(Self::new_generic_unchecked( spi_id, spi.reg_block(), diff --git a/zynq7000-hal/src/ttc.rs b/zynq7000-hal/src/ttc.rs index 4037c7d..d5139e7 100644 --- a/zynq7000-hal/src/ttc.rs +++ b/zynq7000-hal/src/ttc.rs @@ -8,10 +8,13 @@ use arbitrary_int::{Number, u3, u4}; use zynq7000::ttc::{MmioTtc, TTC_0_BASE_ADDR, TTC_1_BASE_ADDR}; #[cfg(not(feature = "7z010-7z007s-clg225"))] -use crate::gpio::{Mio16, Mio17, Mio18, Mio19, Mio40, Mio41, Mio42, Mio43}; +use crate::gpio::mio::{Mio16, Mio17, Mio18, Mio19, Mio40, Mio41, Mio42, Mio43}; use crate::{ clocks::ArmClocks, - gpio::{IoPeriph, IoPeriphPin, Mio28, Mio29, Mio30, Mio31, MioPin, MuxConf, PinMode}, + gpio::{ + IoPeriphPin, + mio::{Mio28, Mio29, Mio30, Mio31, MioPinMarker, MuxConf, Pin}, + }, time::Hertz, }; @@ -54,31 +57,65 @@ impl PsTtc for MmioTtc<'static> { pub const TTC_MUX_CONF: MuxConf = MuxConf::new_with_l3(u3::new(0b110)); -pub trait ClockInPin: IoPeriphPin { +pub trait ClockInPin: MioPinMarker { const ID: TtcId; } -pub trait WaveOutPin: IoPeriphPin { +pub trait WaveOutPin: MioPinMarker { const ID: TtcId; } -macro_rules! into_ttc { - ($($Mio:ident),+) => { - $( - impl MioPin<$Mio, M> { - /// Convert the pin into a TTC pin by configuring the pin routing via the - /// MIO multiplexer bits. - pub fn into_ttck(self) -> MioPin<$Mio, IoPeriph> { - self.into_io_periph(TTC_MUX_CONF, None) - } - } - )+ - }; -} +// TTC0 pin trait implementations. +impl ClockInPin for Pin { + const ID: TtcId = TtcId::Ttc0; +} #[cfg(not(feature = "7z010-7z007s-clg225"))] -into_ttc!(Mio16, Mio17, Mio18, Mio19, Mio40, Mio41, Mio42, Mio43); -into_ttc!(Mio28, Mio29, Mio30, Mio31); +impl ClockInPin for Pin { + const ID: TtcId = TtcId::Ttc0; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl ClockInPin for Pin { + const ID: TtcId = TtcId::Ttc0; +} + +impl WaveOutPin for Pin { + const ID: TtcId = TtcId::Ttc0; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl WaveOutPin for Pin { + const ID: TtcId = TtcId::Ttc0; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl WaveOutPin for Pin { + const ID: TtcId = TtcId::Ttc0; +} + +// TTC1 pin trait implementations. + +impl ClockInPin for Pin { + const ID: TtcId = TtcId::Ttc1; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl ClockInPin for Pin { + const ID: TtcId = TtcId::Ttc1; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl ClockInPin for Pin { + const ID: TtcId = TtcId::Ttc1; +} + +impl WaveOutPin for Pin { + const ID: TtcId = TtcId::Ttc1; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl WaveOutPin for Pin { + const ID: TtcId = TtcId::Ttc1; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl WaveOutPin for Pin { + const ID: TtcId = TtcId::Ttc1; +} pub struct Ttc { pub ch0: TtcChannel, @@ -187,9 +224,7 @@ impl Pwm { freq: Hertz, wave_out: impl WaveOutPin, ) -> Result { - if wave_out.mux_conf() != TTC_MUX_CONF { - return Err(InvalidTtcPinConfigError(wave_out.mux_conf()).into()); - } + IoPeriphPin::new(wave_out, TTC_MUX_CONF, None); Ok(Self::new_with_cpu_clk(channel, arm_clocks, freq)?) } diff --git a/zynq7000-hal/src/uart/mod.rs b/zynq7000-hal/src/uart/mod.rs index 273afe8..fb71cb2 100644 --- a/zynq7000-hal/src/uart/mod.rs +++ b/zynq7000-hal/src/uart/mod.rs @@ -16,15 +16,18 @@ use zynq7000::{ use crate::{ enable_amba_peripheral_clock, gpio::{ - IoPeriph, IoPeriphPin, Mio8, Mio9, Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, - Mio30, Mio31, Mio32, Mio33, Mio34, Mio35, Mio36, Mio37, Mio38, Mio39, Mio48, Mio49, Mio52, - Mio53, MioPin, MuxConf, PinMode, + IoPeriphPin, + mio::{ + Mio8, Mio9, Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, Mio30, Mio31, + Mio32, Mio33, Mio34, Mio35, Mio36, Mio37, Mio38, Mio39, Mio48, Mio49, Mio52, Mio53, + MioPinMarker, MuxConf, Pin, + }, }, slcr::Slcr, }; #[cfg(not(feature = "7z010-7z007s-clg225"))] -use crate::gpio::{ +use crate::gpio::mio::{ Mio16, Mio17, Mio18, Mio19, Mio20, Mio21, Mio22, Mio23, Mio24, Mio25, Mio26, Mio27, Mio40, Mio41, Mio42, Mio43, Mio44, Mio45, Mio46, Mio47, Mio50, Mio51, }; @@ -86,10 +89,10 @@ impl UartId { } } -pub trait RxPin { +pub trait RxPin: MioPinMarker { const UART_IDX: UartId; } -pub trait TxPin { +pub trait TxPin: MioPinMarker { const UART_IDX: UartId; } @@ -103,27 +106,27 @@ macro_rules! pin_pairs { ($UartPeriph:path, ($( [$(#[$meta:meta], )? $TxMio:ident, $RxMio:ident] ),+ $(,)? )) => { $( $( #[$meta] )? - impl TxPin for MioPin<$TxMio, IoPeriph> { + impl TxPin for Pin<$TxMio> { const UART_IDX: UartId = $UartPeriph; } - $( #[$meta] )? - impl RxPin for MioPin<$RxMio, IoPeriph> { + impl RxPin for Pin<$RxMio> { const UART_IDX: UartId = $UartPeriph; } - impl UartPins for (MioPin<$TxMio, IoPeriph>, MioPin<$RxMio, IoPeriph>) {} + impl UartPins for (Pin<$TxMio>, Pin<$RxMio>) {} )+ }; } +/* macro_rules! impl_into_uart { (($($Mio:ident),+)) => { $( - impl MioPin<$Mio, M> { - pub fn into_uart(self) -> MioPin<$Mio, IoPeriph> { - self.into_io_periph(UART_MUX_CONF, None) + impl From> for IoPeriphPin { + fn from(pin: Pin<$Mio>) -> Self { + IoPeriphPin::new(pin, UART_MUX_CONF, None) } } )+ @@ -140,6 +143,7 @@ impl_into_uart!(( Mio19, Mio18, Mio23, Mio22, Mio43, Mio42, Mio47, Mio46, Mio51, Mio50, Mio16, Mio17, Mio20, Mio21, Mio24, Mio25, Mio40, Mio41, Mio44, Mio45 )); +*/ pin_pairs!( UartId::Uart0, @@ -453,7 +457,7 @@ impl Uart { } /// This is the constructor to use the PS UART with MIO pins. - pub fn new_with_mio( + pub fn new_with_mio( uart: impl PsUart, cfg: UartConfig, pins: (TxPinI, RxPinI), @@ -468,12 +472,8 @@ impl Uart { if id.unwrap() != TxPinI::UART_IDX || id.unwrap() != RxPinI::UART_IDX { return Err(UartConstructionError::IdxMissmatch); } - if pins.0.mux_conf() != UART_MUX_CONF { - return Err(UartConstructionError::InvalidMuxConf(pins.0.mux_conf())); - } - if pins.1.mux_conf() != UART_MUX_CONF { - return Err(UartConstructionError::InvalidMuxConf(pins.1.mux_conf())); - } + 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(), diff --git a/zynq7000-rt/Cargo.toml b/zynq7000-rt/Cargo.toml index 9a4cfe2..69fb582 100644 --- a/zynq7000-rt/Cargo.toml +++ b/zynq7000-rt/Cargo.toml @@ -11,8 +11,8 @@ keywords = ["no-std", "arm", "cortex-a", "amd", "zynq7000"] categories = ["embedded", "no-std", "hardware-support"] [dependencies] -cortex-a-rt = { path = "/home/rmueller/Rust/cortex-ar/cortex-a-rt", optional = true, features = ["vfp-dp"] } -cortex-ar = { path = "/home/rmueller/Rust/cortex-ar/cortex-ar" } +cortex-a-rt = { git = "https://github.com/rust-embedded/cortex-ar", branch = "main", optional = true, features = ["vfp-dp"] } +cortex-ar = { git = "https://github.com/rust-embedded/cortex-ar", branch = "main", features = ["critical-section-single-core"] } [features] default = ["rt"] diff --git a/zynq7000/src/spi.rs b/zynq7000/src/spi.rs index 6645440..b732b07 100644 --- a/zynq7000/src/spi.rs +++ b/zynq7000/src/spi.rs @@ -1,5 +1,5 @@ //! SPI register module. -use arbitrary_int::{u4, Number}; +use arbitrary_int::{Number, u4}; pub const SPI_0_BASE_ADDR: usize = 0xE000_6000; pub const SPI_1_BASE_ADDR: usize = 0xE000_7000; @@ -140,7 +140,7 @@ impl FifoWrite { } #[inline] - pub fn write(&mut self, value:u8) { + pub fn write(&mut self, value: u8) { self.0 = value.into(); } }