re-worked GPIO implementation #3

Merged
muellerr merged 1 commits from rework-gpio-impl into main 2025-04-10 22:42:07 +02:00
25 changed files with 1254 additions and 1321 deletions

View File

@ -14,7 +14,7 @@ use zynq7000_hal::{
BootMode, BootMode,
clocks::Clocks, clocks::Clocks,
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{Mio7, MioPin, MioPins, Output, PinState}, gpio::{Output, PinState, mio},
gtc::Gtc, gtc::Gtc,
time::Hertz, time::Hertz,
uart::{ClkConfigRaw, TxAsync, Uart, UartConfig, on_interrupt_tx}, 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()); let gtc = Gtc::new(dp.gtc, clocks.arm_clocks());
zynq7000_embassy::init(clocks.arm_clocks(), gtc); 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. // Set up the UART, we are logging with it.
let uart_clk_config = ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200) let uart_clk_config = ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200)
.unwrap() .unwrap()
.0; .0;
let uart_tx = mio_pins.mio48.into_uart();
let uart_rx = mio_pins.mio49.into_uart();
let mut uart = Uart::new_with_mio( let mut uart = Uart::new_with_mio(
dp.uart_1, dp.uart_1,
UartConfig::new_with_clk_config(uart_clk_config), UartConfig::new_with_clk_config(uart_clk_config),
(uart_tx, uart_rx), (mio_pins.mio48, mio_pins.mio49),
) )
.unwrap(); .unwrap();
uart.write_all(b"-- Zynq 7000 Logging example --\n\r") uart.write_all(b"-- Zynq 7000 Logging example --\n\r")
@ -77,7 +75,7 @@ async fn main(spawner: Spawner) -> ! {
let boot_mode = BootMode::new(); let boot_mode = BootMode::new();
info!("Boot mode: {:?}", boot_mode); 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(); spawner.spawn(led_task(led)).unwrap();
let mut log_buf: [u8; 2048] = [0; 2048]; let mut log_buf: [u8; 2048] = [0; 2048];
let frame_queue = zynq7000_hal::log::rb::get_frame_queue(); let frame_queue = zynq7000_hal::log::rb::get_frame_queue();
@ -89,7 +87,7 @@ async fn main(spawner: Spawner) -> ! {
} }
#[embassy_executor::task] #[embassy_executor::task]
async fn led_task(mut mio_led: MioPin<Mio7, Output>) { async fn led_task(mut mio_led: Output) {
let mut ticker = Ticker::every(Duration::from_millis(1000)); let mut ticker = Ticker::every(Duration::from_millis(1000));
loop { loop {
mio_led.toggle().unwrap(); mio_led.toggle().unwrap();

View File

@ -19,7 +19,7 @@ use zynq7000_hal::{
BootMode, BootMode,
clocks::Clocks, clocks::Clocks,
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{MioPins, PinState}, gpio::{Output, PinState, mio},
gtc::Gtc, gtc::Gtc,
time::Hertz, time::Hertz,
uart::{ClkConfigRaw, Uart, UartConfig}, uart::{ClkConfigRaw, Uart, UartConfig},
@ -54,7 +54,7 @@ async fn main(_spawner: Spawner) -> ! {
unsafe { unsafe {
gic.enable_interrupts(); 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. // Set up global timer counter and embassy time driver.
let gtc = Gtc::new(dp.gtc, clocks.arm_clocks()); 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) let uart_clk_config = ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200)
.unwrap() .unwrap()
.0; .0;
let uart_tx = mio_pins.mio48.into_uart();
let uart_rx = mio_pins.mio49.into_uart();
let mut uart = Uart::new_with_mio( let mut uart = Uart::new_with_mio(
dp.uart_1, dp.uart_1,
UartConfig::new_with_clk_config(uart_clk_config), UartConfig::new_with_clk_config(uart_clk_config),
(uart_tx, uart_rx), (mio_pins.mio48, mio_pins.mio49),
) )
.unwrap(); .unwrap();
uart.write_all(b"-- Zynq 7000 Embassy Hello World --\n\r") 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); info!("Boot mode: {:?}", boot_mode);
let mut ticker = Ticker::every(Duration::from_millis(1000)); 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; let mut current_duty = 0;
loop { loop {
led.toggle().unwrap(); led.toggle().unwrap();

View File

@ -12,7 +12,7 @@ use zynq7000_hal::{
BootMode, BootMode,
clocks::Clocks, clocks::Clocks,
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{MioPins, PinState}, gpio::{Output, PinState, mio},
gtc::Gtc, gtc::Gtc,
time::Hertz, time::Hertz,
uart::{ClkConfigRaw, Uart, UartConfig}, uart::{ClkConfigRaw, Uart, UartConfig},
@ -48,7 +48,7 @@ async fn main(_spawner: Spawner) -> ! {
unsafe { unsafe {
gic.enable_interrupts(); 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. // Set up global timer counter and embassy time driver.
let gtc = Gtc::new(dp.gtc, clocks.arm_clocks()); 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) let uart_clk_config = ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200)
.unwrap() .unwrap()
.0; .0;
let uart_tx = mio_pins.mio48.into_uart();
let uart_rx = mio_pins.mio49.into_uart();
let mut uart = Uart::new_with_mio( let mut uart = Uart::new_with_mio(
dp.uart_1, dp.uart_1,
UartConfig::new_with_clk_config(uart_clk_config), UartConfig::new_with_clk_config(uart_clk_config),
(uart_tx, uart_rx), (mio_pins.mio48, mio_pins.mio49),
) )
.unwrap(); .unwrap();
uart.write_all(b"-- Zynq 7000 Embassy Hello World --\n\r") 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); info!("Boot mode: {:?}", boot_mode);
let mut ticker = Ticker::every(Duration::from_millis(1000)); 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 { loop {
info!("Hello, world!"); info!("Hello, world!");
led.toggle().unwrap(); led.toggle().unwrap();

View File

@ -10,7 +10,7 @@ use log::{error, info};
use zynq7000_hal::{ use zynq7000_hal::{
clocks::Clocks, clocks::Clocks,
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{MioPins, PinState}, gpio::{Output, PinState, mio},
gtc::Gtc, gtc::Gtc,
prelude::*, prelude::*,
time::Hertz, time::Hertz,
@ -58,13 +58,11 @@ pub fn main() -> ! {
gtc.enable(); gtc.enable();
// This structure holds all MIO pins. // This structure holds all MIO pins.
let mio_pins = MioPins::new(dp.gpio); let mio_pins = mio::Pins::new(dp.gpio);
let uart_tx = mio_pins.mio48.into_uart();
let uart_rx = mio_pins.mio49.into_uart();
let mut uart = Uart::new_with_mio( let mut uart = Uart::new_with_mio(
dp.uart_1, dp.uart_1,
UartConfig::new_with_clk_config(uart_clk_config), UartConfig::new_with_clk_config(uart_clk_config),
(uart_tx, uart_rx), (mio_pins.mio48, mio_pins.mio49),
) )
.unwrap(); .unwrap();
uart.write_all(b"-- Zynq 7000 GTC Ticks example --\n\r") 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 { loop {
info!( info!(
"MS_TICKS: {}", "MS_TICKS: {}",

View File

@ -11,7 +11,7 @@ use zynq7000_hal::{
BootMode, BootMode,
clocks::Clocks, clocks::Clocks,
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{MioPins, PinState}, gpio::{Output, PinState, mio},
gtc::Gtc, gtc::Gtc,
prelude::*, prelude::*,
time::Hertz, time::Hertz,
@ -57,14 +57,12 @@ pub fn main() -> ! {
gtc.enable_auto_increment(); gtc.enable_auto_increment();
gtc.enable_interrupt(); gtc.enable_interrupt();
gtc.enable(); gtc.enable();
let mio_pins = MioPins::new(dp.gpio); let mio_pins = mio::Pins::new(dp.gpio);
let uart_tx = mio_pins.mio48.into_uart();
let uart_rx = mio_pins.mio49.into_uart();
let mut uart = Uart::new_with_mio( let mut uart = Uart::new_with_mio(
dp.uart_1, dp.uart_1,
UartConfig::new_with_clk_config(uart_clk_config), UartConfig::new_with_clk_config(uart_clk_config),
(uart_tx, uart_rx), (mio_pins.mio48, mio_pins.mio49),
) )
.unwrap(); .unwrap();
uart.write_all(b"-- Zynq 7000 Logging example --\n\r") uart.write_all(b"-- Zynq 7000 Logging example --\n\r")
@ -81,7 +79,7 @@ pub fn main() -> ! {
let boot_mode = BootMode::new(); let boot_mode = BootMode::new();
info!("Boot mode: {:?}", boot_mode); 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 { loop {
let gtc = gtc.read_timer(); let gtc = gtc.read_timer();
info!("Hello, world!"); info!("Hello, world!");

View File

@ -6,7 +6,7 @@ use core::panic::PanicInfo;
use cortex_ar::asm::nop; use cortex_ar::asm::nop;
use embedded_hal::digital::StatefulOutputPin; use embedded_hal::digital::StatefulOutputPin;
use zynq7000::PsPeripherals; use zynq7000::PsPeripherals;
use zynq7000_hal::gpio::{MioPins, PinState}; use zynq7000_hal::gpio::{Output, PinState, mio};
use zynq7000_rt as _; use zynq7000_rt as _;
/// One user LED is MIO7 /// One user LED is MIO7
@ -45,8 +45,8 @@ pub fn main() -> ! {
} }
Lib::Hal => { Lib::Hal => {
let dp = PsPeripherals::take().unwrap(); let dp = PsPeripherals::take().unwrap();
let mio_pins = MioPins::new(dp.gpio); let mio_pins = mio::Pins::new(dp.gpio);
let mut led = mio_pins.mio7.into_output(PinState::High); let mut led = Output::new_for_mio(mio_pins.mio7, PinState::High);
loop { loop {
led.toggle().unwrap(); led.toggle().unwrap();
for _ in 0..5_000_000 { for _ in 0..5_000_000 {

View File

@ -11,7 +11,7 @@ keywords = ["no-std", "arm", "cortex-a", "amd", "zynq7000"]
categories = ["embedded", "no-std", "hardware-support"] categories = ["embedded", "no-std", "hardware-support"]
[dependencies] [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-rt = { path = "../../zynq7000-rt" }
zynq7000 = { path = "../../zynq7000" } zynq7000 = { path = "../../zynq7000" }
zynq7000-hal = { path = "../../zynq7000-hal" } zynq7000-hal = { path = "../../zynq7000-hal" }

View File

@ -22,7 +22,7 @@ use zynq7000_hal::{
clocks::Clocks, clocks::Clocks,
configure_level_shifter, configure_level_shifter,
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{EmioPin, GpioPins, PinState}, gpio::{GpioPins, Output, PinState},
gtc::Gtc, gtc::Gtc,
i2c, i2c,
time::Hertz, 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) let uart_clk_config = uart::ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200)
.unwrap() .unwrap()
.0; .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( let mut uart = uart::Uart::new_with_mio(
dp.uart_1, dp.uart_1,
uart::UartConfig::new_with_clk_config(uart_clk_config), uart::UartConfig::new_with_clk_config(uart_clk_config),
(uart_tx, uart_rx), (gpio_pins.mio.mio48, gpio_pins.mio.mio49),
) )
.unwrap(); .unwrap();
uart.write_all(b"-- Zynq 7000 Zedboard I2C L3GD20H example --\n\r") 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(); let boot_mode = BootMode::new();
info!("Boot mode: {:?}", boot_mode); 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 { let pin_sel = match I2C_ADDR_SEL {
I2cAddr::Sa0Low => PinState::Low, I2cAddr::Sa0Low => PinState::Low,
I2cAddr::Sa0High => PinState::High, 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. // 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( let clk_config = i2c::calculate_divisors(
clocks.arm_clocks().cpu_1x_clk(), clocks.arm_clocks().cpu_1x_clk(),
i2c::I2cSpeed::Normal100kHz, i2c::I2cSpeed::Normal100kHz,
) )
.unwrap(); .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 mut l3gd20 = l3gd20::i2c::L3gd20::new(i2c, l3gd20::i2c::I2cAddr::Sa0Low).unwrap();
let who_am_i = l3gd20.who_am_i().unwrap(); let who_am_i = l3gd20.who_am_i().unwrap();
info!("L3GD20 WHO_AM_I: 0x{:02X}", who_am_i); info!("L3GD20 WHO_AM_I: 0x{:02X}", who_am_i);
let mut delay = Delay; let mut delay = Delay;
let mut ticker = Ticker::every(Duration::from_millis(400)); 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] = [ let mut emio_leds: [Output; 8] = [
gpio_pins.emio.take(0).unwrap(), Output::new_for_emio(gpio_pins.emio.take(0).unwrap(), PinState::Low),
gpio_pins.emio.take(1).unwrap(), Output::new_for_emio(gpio_pins.emio.take(1).unwrap(), PinState::Low),
gpio_pins.emio.take(2).unwrap(), Output::new_for_emio(gpio_pins.emio.take(2).unwrap(), PinState::Low),
gpio_pins.emio.take(3).unwrap(), Output::new_for_emio(gpio_pins.emio.take(3).unwrap(), PinState::Low),
gpio_pins.emio.take(4).unwrap(), Output::new_for_emio(gpio_pins.emio.take(4).unwrap(), PinState::Low),
gpio_pins.emio.take(5).unwrap(), Output::new_for_emio(gpio_pins.emio.take(5).unwrap(), PinState::Low),
gpio_pins.emio.take(6).unwrap(), Output::new_for_emio(gpio_pins.emio.take(6).unwrap(), PinState::Low),
gpio_pins.emio.take(7).unwrap(), Output::new_for_emio(gpio_pins.emio.take(7).unwrap(), PinState::Low),
]; ];
for (idx, led) in emio_leds.iter_mut().enumerate() { for (idx, led) in emio_leds.iter_mut().enumerate() {
if idx % 2 == 0 { if idx % 2 == 0 {
led.into_output(PinState::High); led.set_high();
} else { } else {
led.into_output(PinState::Low); led.set_low();
} }
} }

View File

@ -22,7 +22,7 @@ use zynq7000_hal::{
clocks::Clocks, clocks::Clocks,
configure_level_shifter, configure_level_shifter,
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{DynMioPin, EmioPin, GpioPins, PinState}, gpio::{GpioPins, Output, PinState},
gtc::Gtc, gtc::Gtc,
spi::{self, SpiAsync, SpiId, SpiWithHwCs, SpiWithHwCsAsync, on_interrupt}, spi::{self, SpiAsync, SpiId, SpiWithHwCs, SpiWithHwCsAsync, on_interrupt},
time::Hertz, 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) let uart_clk_config = uart::ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200)
.unwrap() .unwrap()
.0; .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( let mut uart = uart::Uart::new_with_mio(
dp.uart_1, dp.uart_1,
uart::UartConfig::new_with_clk_config(uart_clk_config), uart::UartConfig::new_with_clk_config(uart_clk_config),
(uart_tx, uart_rx), (gpio_pins.mio.mio48, gpio_pins.mio.mio49),
) )
.unwrap(); .unwrap();
uart.write_all(b"-- Zynq 7000 Zedboard SPI L3GD20H example --\n\r") 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 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( let mut spi = spi::Spi::new_one_hw_cs(
dp.spi_1, dp.spi_1,
@ -121,8 +115,12 @@ async fn main(spawner: Spawner) -> ! {
embedded_hal::spi::MODE_3, embedded_hal::spi::MODE_3,
spi::SlaveSelectConfig::AutoWithAutoStart, 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(); .unwrap();
let mod_id = spi.regs().read_mod_id(); let mod_id = spi.regs().read_mod_id();
@ -138,24 +136,25 @@ async fn main(spawner: Spawner) -> ! {
.build(), .build(),
); );
let mio_led = gpio_pins.mio.mio7.into_output(PinState::Low).downgrade(); let mio_led = Output::new_for_mio(gpio_pins.mio.mio7, PinState::Low);
let mut emio_leds: [EmioPin; 8] = [ let mut emio_leds: [Output; 8] = [
gpio_pins.emio.take(0).unwrap(), Output::new_for_emio(gpio_pins.emio.take(0).unwrap(), PinState::Low),
gpio_pins.emio.take(1).unwrap(), Output::new_for_emio(gpio_pins.emio.take(1).unwrap(), PinState::Low),
gpio_pins.emio.take(2).unwrap(), Output::new_for_emio(gpio_pins.emio.take(2).unwrap(), PinState::Low),
gpio_pins.emio.take(3).unwrap(), Output::new_for_emio(gpio_pins.emio.take(3).unwrap(), PinState::Low),
gpio_pins.emio.take(4).unwrap(), Output::new_for_emio(gpio_pins.emio.take(4).unwrap(), PinState::Low),
gpio_pins.emio.take(5).unwrap(), Output::new_for_emio(gpio_pins.emio.take(5).unwrap(), PinState::Low),
gpio_pins.emio.take(6).unwrap(), Output::new_for_emio(gpio_pins.emio.take(6).unwrap(), PinState::Low),
gpio_pins.emio.take(7).unwrap(), Output::new_for_emio(gpio_pins.emio.take(7).unwrap(), PinState::Low),
]; ];
for (idx, led) in emio_leds.iter_mut().enumerate() { for (idx, led) in emio_leds.iter_mut().enumerate() {
if idx % 2 == 0 { if idx % 2 == 0 {
led.into_output(PinState::High); led.set_high();
} else { } else {
led.into_output(PinState::Low); led.set_low();
} }
} }
spawner.spawn(logger_task(uart)).unwrap(); spawner.spawn(logger_task(uart)).unwrap();
if BLOCKING { if BLOCKING {
blocking_application(mio_led, emio_leds, spi).await; 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( pub async fn blocking_application(
mut mio_led: DynMioPin, mut mio_led: Output,
mut emio_leds: [EmioPin; 8], mut emio_leds: [Output; 8],
spi: spi::Spi, spi: spi::Spi,
) -> ! { ) -> ! {
let mut delay = Delay; let mut delay = Delay;
@ -207,8 +206,8 @@ pub async fn blocking_application(
} }
pub async fn non_blocking_application( pub async fn non_blocking_application(
mut mio_led: DynMioPin, mut mio_led: Output,
mut emio_leds: [EmioPin; 8], mut emio_leds: [Output; 8],
spi: spi::Spi, spi: spi::Spi,
) -> ! { ) -> ! {
let mut delay = Delay; let mut delay = Delay;

View File

@ -17,7 +17,7 @@ use zynq7000_hal::{
clocks::Clocks, clocks::Clocks,
configure_level_shifter, configure_level_shifter,
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{EmioPin, GpioPins, PinState}, gpio::{GpioPins, Output, PinState},
gtc::Gtc, gtc::Gtc,
uart::{ClkConfigRaw, Uart, UartConfig}, uart::{ClkConfigRaw, Uart, UartConfig},
}; };
@ -50,13 +50,13 @@ pub enum UartSel {
} }
pub struct UartMultiplexer { pub struct UartMultiplexer {
sel_pins: [EmioPin; 3], sel_pins: [Output; 3],
} }
impl UartMultiplexer { 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() { for pin in sel_pins.iter_mut() {
pin.into_output(PinState::Low); pin.set_low();
} }
Self { sel_pins } Self { sel_pins }
} }
@ -65,34 +65,34 @@ impl UartMultiplexer {
// TODO: A pin group switcher would be nice to do this in one go. // TODO: A pin group switcher would be nice to do this in one go.
match sel { match sel {
UartSel::Uart0 => { UartSel::Uart0 => {
self.sel_pins[2].set_low().unwrap(); self.sel_pins[2].set_low();
self.sel_pins[1].set_low().unwrap(); self.sel_pins[1].set_low();
self.sel_pins[0].set_low().unwrap(); self.sel_pins[0].set_low();
} }
UartSel::Uartlite => { UartSel::Uartlite => {
self.sel_pins[2].set_low().unwrap(); self.sel_pins[2].set_low();
self.sel_pins[1].set_low().unwrap(); self.sel_pins[1].set_low();
self.sel_pins[0].set_high().unwrap(); self.sel_pins[0].set_high();
} }
UartSel::Uart16550 => { UartSel::Uart16550 => {
self.sel_pins[2].set_low().unwrap(); self.sel_pins[2].set_low();
self.sel_pins[1].set_high().unwrap(); self.sel_pins[1].set_high();
self.sel_pins[0].set_low().unwrap(); self.sel_pins[0].set_low();
} }
UartSel::Uart0ToUartlite => { UartSel::Uart0ToUartlite => {
self.sel_pins[2].set_low().unwrap(); self.sel_pins[2].set_low();
self.sel_pins[1].set_high().unwrap(); self.sel_pins[1].set_high();
self.sel_pins[0].set_high().unwrap(); self.sel_pins[0].set_high();
} }
UartSel::Uart0ToUart16550 => { UartSel::Uart0ToUart16550 => {
self.sel_pins[2].set_high().unwrap(); self.sel_pins[2].set_high();
self.sel_pins[1].set_low().unwrap(); self.sel_pins[1].set_low();
self.sel_pins[0].set_low().unwrap(); self.sel_pins[0].set_low();
} }
UartSel::UartliteToUart16550 => { UartSel::UartliteToUart16550 => {
self.sel_pins[2].set_high().unwrap(); self.sel_pins[2].set_high();
self.sel_pins[1].set_low().unwrap(); self.sel_pins[1].set_low();
self.sel_pins[0].set_high().unwrap(); 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) let uart_clk_config = ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200)
.unwrap() .unwrap()
.0; .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( let mut log_uart = Uart::new_with_mio(
dp.uart_1, dp.uart_1,
UartConfig::new_with_clk_config(uart_clk_config), UartConfig::new_with_clk_config(uart_clk_config),
(uart_tx, uart_rx), (gpio_pins.mio.mio48, gpio_pins.mio.mio49),
) )
.unwrap(); .unwrap();
log_uart.write_all(INIT_STRING.as_bytes()).unwrap(); log_uart.write_all(INIT_STRING.as_bytes()).unwrap();
@ -163,26 +161,23 @@ async fn main(_spawner: Spawner) -> ! {
info!("Boot mode: {:?}", boot_mode); info!("Boot mode: {:?}", boot_mode);
let mut ticker = Ticker::every(Duration::from_millis(1000)); 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] = [ let mut mio_led = Output::new_for_mio(gpio_pins.mio.mio7, PinState::Low);
gpio_pins.emio.take(0).unwrap(), let mut emio_leds: [Output; 8] = [
gpio_pins.emio.take(1).unwrap(), Output::new_for_emio(gpio_pins.emio.take(0).unwrap(), PinState::Low),
gpio_pins.emio.take(2).unwrap(), Output::new_for_emio(gpio_pins.emio.take(1).unwrap(), PinState::Low),
gpio_pins.emio.take(3).unwrap(), Output::new_for_emio(gpio_pins.emio.take(2).unwrap(), PinState::Low),
gpio_pins.emio.take(4).unwrap(), Output::new_for_emio(gpio_pins.emio.take(3).unwrap(), PinState::Low),
gpio_pins.emio.take(5).unwrap(), Output::new_for_emio(gpio_pins.emio.take(4).unwrap(), PinState::Low),
gpio_pins.emio.take(6).unwrap(), Output::new_for_emio(gpio_pins.emio.take(5).unwrap(), PinState::Low),
gpio_pins.emio.take(7).unwrap(), 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([ let mut uart_mux = UartMultiplexer::new([
gpio_pins.emio.take(8).unwrap(), Output::new_for_emio(gpio_pins.emio.take(8).unwrap(), PinState::Low),
gpio_pins.emio.take(9).unwrap(), Output::new_for_emio(gpio_pins.emio.take(9).unwrap(), PinState::Low),
gpio_pins.emio.take(10).unwrap(), Output::new_for_emio(gpio_pins.emio.take(10).unwrap(), PinState::Low),
]); ]);
let mut current_sel = UartSel::Uart0; let mut current_sel = UartSel::Uart0;
uart_mux.select(current_sel); uart_mux.select(current_sel);

View File

@ -43,7 +43,7 @@ use zynq7000_hal::{
clocks::Clocks, clocks::Clocks,
configure_level_shifter, configure_level_shifter,
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{EmioPin, GpioPins, Mio7, MioPin, Output, PinState}, gpio::{GpioPins, Output, PinState},
gtc::Gtc, gtc::Gtc,
time::Hertz, time::Hertz,
uart::{ClkConfigRaw, Uart, UartConfig}, uart::{ClkConfigRaw, Uart, UartConfig},
@ -114,13 +114,13 @@ pub enum UartSel {
} }
pub struct UartMultiplexer { pub struct UartMultiplexer {
sel_pins: [EmioPin; 3], sel_pins: [Output; 3],
} }
impl UartMultiplexer { 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() { for pin in sel_pins.iter_mut() {
pin.into_output(PinState::Low); pin.set_low();
} }
Self { sel_pins } Self { sel_pins }
} }
@ -129,38 +129,39 @@ impl UartMultiplexer {
// TODO: A pin group switcher would be nice to do this in one go. // TODO: A pin group switcher would be nice to do this in one go.
match sel { match sel {
UartSel::Uart0 => { UartSel::Uart0 => {
self.sel_pins[2].set_low().unwrap(); self.sel_pins[2].set_low();
self.sel_pins[1].set_low().unwrap(); self.sel_pins[1].set_low();
self.sel_pins[0].set_low().unwrap(); self.sel_pins[0].set_low();
} }
UartSel::Uartlite => { UartSel::Uartlite => {
self.sel_pins[2].set_low().unwrap(); self.sel_pins[2].set_low();
self.sel_pins[1].set_low().unwrap(); self.sel_pins[1].set_low();
self.sel_pins[0].set_high().unwrap(); self.sel_pins[0].set_high();
} }
UartSel::Uart16550 => { UartSel::Uart16550 => {
self.sel_pins[2].set_low().unwrap(); self.sel_pins[2].set_low();
self.sel_pins[1].set_high().unwrap(); self.sel_pins[1].set_high();
self.sel_pins[0].set_low().unwrap(); self.sel_pins[0].set_low();
} }
UartSel::Uart0ToUartlite => { UartSel::Uart0ToUartlite => {
self.sel_pins[2].set_low().unwrap(); self.sel_pins[2].set_low();
self.sel_pins[1].set_high().unwrap(); self.sel_pins[1].set_high();
self.sel_pins[0].set_high().unwrap(); self.sel_pins[0].set_high();
} }
UartSel::Uart0ToUart16550 => { UartSel::Uart0ToUart16550 => {
self.sel_pins[2].set_high().unwrap(); self.sel_pins[2].set_high();
self.sel_pins[1].set_low().unwrap(); self.sel_pins[1].set_low();
self.sel_pins[0].set_low().unwrap(); self.sel_pins[0].set_low();
} }
UartSel::UartliteToUart16550 => { UartSel::UartliteToUart16550 => {
self.sel_pins[2].set_high().unwrap(); self.sel_pins[2].set_high();
self.sel_pins[1].set_low().unwrap(); self.sel_pins[1].set_low();
self.sel_pins[0].set_high().unwrap(); self.sel_pins[0].set_high();
} }
} }
} }
} }
#[embassy_executor::main] #[embassy_executor::main]
#[unsafe(export_name = "main")] #[unsafe(export_name = "main")]
async fn main(spawner: Spawner) -> ! { 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) let uart_clk_config = ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200)
.unwrap() .unwrap()
.0; .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( let mut log_uart = Uart::new_with_mio(
dp.uart_1, dp.uart_1,
UartConfig::new_with_clk_config(uart_clk_config), UartConfig::new_with_clk_config(uart_clk_config),
(uart_tx, uart_rx), (gpio_pins.mio.mio48, gpio_pins.mio.mio49),
) )
.unwrap(); .unwrap();
log_uart.write_all(INIT_STRING.as_bytes()).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. // Set up UART multiplexing before creating and configuring the UARTs.
let mut uart_mux = UartMultiplexer::new([ let mut uart_mux = UartMultiplexer::new([
gpio_pins.emio.take(8).unwrap(), Output::new_for_emio(gpio_pins.emio.take(8).unwrap(), PinState::Low),
gpio_pins.emio.take(9).unwrap(), Output::new_for_emio(gpio_pins.emio.take(9).unwrap(), PinState::Low),
gpio_pins.emio.take(10).unwrap(), Output::new_for_emio(gpio_pins.emio.take(10).unwrap(), PinState::Low),
]); ]);
match UART_MODE { match UART_MODE {
UartMode::Uart0ToUartlite => uart_mux.select(UartSel::Uart0ToUartlite), UartMode::Uart0ToUartlite => uart_mux.select(UartSel::Uart0ToUartlite),
@ -254,21 +253,17 @@ async fn main(spawner: Spawner) -> ! {
let boot_mode = BootMode::new(); let boot_mode = BootMode::new();
info!("Boot mode: {:?}", boot_mode); info!("Boot mode: {:?}", boot_mode);
let mio_led = gpio_pins.mio.mio7.into_output(PinState::Low); let mio_led = Output::new_for_mio(gpio_pins.mio.mio7, PinState::Low);
let emio_leds: [Output; 8] = [
let mut emio_leds: [EmioPin; 8] = [ Output::new_for_emio(gpio_pins.emio.take(0).unwrap(), PinState::Low),
gpio_pins.emio.take(0).unwrap(), Output::new_for_emio(gpio_pins.emio.take(1).unwrap(), PinState::Low),
gpio_pins.emio.take(1).unwrap(), Output::new_for_emio(gpio_pins.emio.take(2).unwrap(), PinState::Low),
gpio_pins.emio.take(2).unwrap(), Output::new_for_emio(gpio_pins.emio.take(3).unwrap(), PinState::Low),
gpio_pins.emio.take(3).unwrap(), Output::new_for_emio(gpio_pins.emio.take(4).unwrap(), PinState::Low),
gpio_pins.emio.take(4).unwrap(), Output::new_for_emio(gpio_pins.emio.take(5).unwrap(), PinState::Low),
gpio_pins.emio.take(5).unwrap(), Output::new_for_emio(gpio_pins.emio.take(6).unwrap(), PinState::Low),
gpio_pins.emio.take(6).unwrap(), Output::new_for_emio(gpio_pins.emio.take(7).unwrap(), PinState::Low),
gpio_pins.emio.take(7).unwrap(),
]; ];
for led in emio_leds.iter_mut() {
led.into_output(PinState::Low);
}
let (uart_0_tx, mut uart_0_rx) = uart_0.split(); let (uart_0_tx, mut uart_0_rx) = uart_0.split();
let (uartlite_tx, _uartlite_rx) = uartlite.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] #[embassy_executor::task]
async fn led_task(mut mio_led: MioPin<Mio7, Output>, 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 ticker = Ticker::every(Duration::from_millis(1000));
let mut led_idx = 0; let mut led_idx = 0;
loop { loop {

View File

@ -14,7 +14,7 @@ use zynq7000_hal::{
clocks::Clocks, clocks::Clocks,
configure_level_shifter, configure_level_shifter,
gic::{GicConfigurator, GicInterruptHelper, Interrupt}, gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{EmioPin, GpioPins, PinState}, gpio::{GpioPins, Output, PinState},
gtc::Gtc, gtc::Gtc,
uart::{ClkConfigRaw, Uart, UartConfig}, 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) let uart_clk_config = ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200)
.unwrap() .unwrap()
.0; .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( let mut uart = Uart::new_with_mio(
dp.uart_1, dp.uart_1,
UartConfig::new_with_clk_config(uart_clk_config), UartConfig::new_with_clk_config(uart_clk_config),
(uart_tx, uart_rx), (gpio_pins.mio.mio48, gpio_pins.mio.mio49),
) )
.unwrap(); .unwrap();
uart.write_all(INIT_STRING.as_bytes()).unwrap(); uart.write_all(INIT_STRING.as_bytes()).unwrap();
@ -81,21 +79,18 @@ async fn main(_spawner: Spawner) -> ! {
info!("Boot mode: {:?}", boot_mode); info!("Boot mode: {:?}", boot_mode);
let mut ticker = Ticker::every(Duration::from_millis(200)); 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] = [ let mut mio_led = Output::new_for_mio(gpio_pins.mio.mio7, PinState::Low);
gpio_pins.emio.take(0).unwrap(), let mut emio_leds: [Output; 8] = [
gpio_pins.emio.take(1).unwrap(), Output::new_for_emio(gpio_pins.emio.take(0).unwrap(), PinState::Low),
gpio_pins.emio.take(2).unwrap(), Output::new_for_emio(gpio_pins.emio.take(1).unwrap(), PinState::Low),
gpio_pins.emio.take(3).unwrap(), Output::new_for_emio(gpio_pins.emio.take(2).unwrap(), PinState::Low),
gpio_pins.emio.take(4).unwrap(), Output::new_for_emio(gpio_pins.emio.take(3).unwrap(), PinState::Low),
gpio_pins.emio.take(5).unwrap(), Output::new_for_emio(gpio_pins.emio.take(4).unwrap(), PinState::Low),
gpio_pins.emio.take(6).unwrap(), Output::new_for_emio(gpio_pins.emio.take(5).unwrap(), PinState::Low),
gpio_pins.emio.take(7).unwrap(), 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 { loop {
mio_led.toggle().unwrap(); mio_led.toggle().unwrap();

View File

@ -11,7 +11,7 @@ keywords = ["no-std", "hal", "amd", "zynq7000", "xilinx", "bare-metal"]
categories = ["embedded", "no-std", "hardware-support"] categories = ["embedded", "no-std", "hardware-support"]
[dependencies] [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" } zynq7000 = { path = "../zynq7000" }
arbitrary-int = "1.3" arbitrary-int = "1.3"

View File

@ -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<zynq7000::slcr::mio::Config> 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<bool>) {
self.reconfigure_slcr_mio_cfg(false, pullup, Some(mux_conf));
self.dyn_mode = DynPinModeMio::IoPeriph(mux_conf);
}
pub fn is_low(&self) -> Result<bool, InvalidPinModeMio> {
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<bool, InvalidPinModeMio> {
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<bool, InvalidPinModeMio> {
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<bool, InvalidPinModeMio> {
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<bool, InvalidPinModeMio> {
self.is_low()
}
#[inline]
fn is_high_mut(&mut self) -> Result<bool, InvalidPinModeMio> {
self.is_high()
}
#[inline]
fn is_set_low_mut(&mut self) -> Result<bool, InvalidPinModeMio> {
self.is_set_low()
}
#[inline]
fn is_set_high_mut(&mut self) -> Result<bool, InvalidPinModeMio> {
self.is_set_high()
}
fn reconfigure_slcr_mio_cfg(
&mut self,
tristate: bool,
pullup: Option<bool>,
mux_conf: Option<MuxConf>,
) {
// 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<bool, Self::Error> {
self.is_set_high_mut()
}
fn is_set_low(&mut self) -> Result<bool, Self::Error> {
self.is_set_low_mut()
}
}
impl embedded_hal::digital::InputPin for DynMioPin {
fn is_high(&mut self) -> Result<bool, Self::Error> {
self.is_high_mut()
}
fn is_low(&mut self) -> Result<bool, Self::Error> {
self.is_low_mut()
}
}

View File

@ -1,263 +1,24 @@
//! EMIO (Extended Multiplexed I/O) module. //! EMIO (Extended Multiplexed I/O) resource management module.
use zynq7000::gpio::{Gpio, MaskedOutput, MmioGpio}; use zynq7000::gpio::MmioGpio;
pub use crate::gpio::PinState; 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 { pub struct EmioPin {
regs: MmioGpio<'static>,
mode: DynPinModeEmio,
offset: usize, offset: usize,
} }
impl EmioPin { impl EmioPin {
/// Unsafely steal an EMIO input pin. /// This offset ranges from 0 to 64.
/// pub fn offset(&self) -> usize {
/// Unless you have no other option, it is recommended to use the [EmioPins::take] method self.offset
/// 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<Self> {
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) { pub struct Pins {
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<bool, InvalidPinModeEmio> {
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<bool, InvalidPinModeEmio> {
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<bool, InvalidPinModeEmio> {
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<bool, InvalidPinModeEmio> {
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<bool, InvalidPinModeEmio> {
self.is_high()
}
#[inline]
fn is_low_mut(&mut self) -> Result<bool, InvalidPinModeEmio> {
self.is_low()
}
}
impl embedded_hal::digital::ErrorType for EmioPin {
type Error = InvalidPinModeEmio;
}
impl embedded_hal::digital::InputPin for EmioPin {
#[inline]
fn is_high(&mut self) -> Result<bool, Self::Error> {
self.is_high_mut()
}
#[inline]
fn is_low(&mut self) -> Result<bool, Self::Error> {
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<bool, Self::Error> {
self.is_set_high()
}
fn is_set_low(&mut self) -> Result<bool, Self::Error> {
self.is_set_low()
}
}
pub struct EmioPins {
emios: [Option<EmioPin>; 64], emios: [Option<EmioPin>; 64],
} }
impl EmioPins { impl Pins {
/// Create a new EMIO pin structure. /// Create a new EMIO pin structure.
/// ///
/// This structure is supposed to be used as a singleton. It will configure all /// 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); mmio.bank_3().write_dirm(0);
(0..64).for_each(|i| { (0..64).for_each(|i| {
let mmio = unsafe { Gpio::new_mmio_fixed() }; emios[i] = Some(EmioPin { offset: i });
emios[i] = Some(EmioPin {
regs: mmio,
mode: DynPinModeEmio::Input,
offset: i,
});
}); });
Self { emios } Self { emios }
} }

338
zynq7000-hal/src/gpio/ll.rs Normal file
View File

@ -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<Self> {
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<Self> {
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<bool>) {
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<bool>,
mux_conf: Option<MuxConf>,
) {
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"),
},
}
}
}

View File

@ -1,48 +1,64 @@
//! Multiplexed I/O (MIO) module. //! Multiplexed I/O (MIO) module.
//! //!
//! This module provides a type-state API for all MIO pins. This also allows associating //! This module provides a [singleton][Pins] for the resource management of all MIO pins. This
//! the pins, their modes and their IDs to the peripherals they are able to serve. //! 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. use arbitrary_int::{u2, u3};
//!
//! # 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;
use zynq7000::gpio::MmioGpio; 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<zynq7000::slcr::mio::Config> 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 {} impl MuxConf {
pub trait InputMode: sealed::Sealed {} #[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 {} pub const fn new_for_gpio() -> Self {
impl sealed::Sealed for Output {} Self::new(false, false, u2::new(0), u3::new(0))
}
pub struct Input<S: InputMode>(core::marker::PhantomData<S>); #[inline]
pub const fn l0_sel(&self) -> bool {
self.l0
}
impl<S: InputMode> PinMode for Input<S> {} #[inline]
impl<S: InputMode> sealed::Sealed for Input<S> {} pub const fn l1_sel(&self) -> bool {
self.l1
}
pub struct PullUp; #[inline]
pub struct Floating; pub const fn l2_sel(&self) -> u2 {
self.l2
}
impl InputMode for PullUp {} #[inline]
impl sealed::Sealed for PullUp {} pub const fn l3_sel(&self) -> u3 {
impl InputMode for Floating {} self.l3
impl sealed::Sealed for Floating {} }
}
pub struct IoPeriph;
impl sealed::Sealed for IoPeriph {}
impl PinMode for IoPeriph {}
pub type Reset = Input<PullUp>;
pub trait PinId { pub trait PinId {
const OFFSET: usize; const OFFSET: usize;
@ -141,29 +157,19 @@ pin_id!(Mio51, 51);
pin_id!(Mio52, 52); pin_id!(Mio52, 52);
pin_id!(Mio53, 53); pin_id!(Mio53, 53);
pub struct MioPin<I: PinId, S: PinMode> { pub trait MioPinMarker {
inner: DynMioPin,
phantom: core::marker::PhantomData<(I, S)>,
}
pub trait IoPeriphPin {
fn mux_conf(&self) -> MuxConf;
}
impl<I: PinId, M: PinMode> MioPinProvider for MioPin<I, M> {
delegate::delegate! {
to self.inner {
fn mode(&self) -> &DynPinModeMio;
fn offset(&self) -> usize; fn offset(&self) -> usize;
} }
}
pub struct Pin<I: PinId> {
phantom: core::marker::PhantomData<I>,
} }
impl<I: PinId, S: PinMode> MioPin<I, S> { impl<I: PinId> Pin<I> {
#[inline] #[inline]
const unsafe fn new() -> Self { const unsafe fn new() -> Self {
Self { Self {
inner: DynMioPin::new(I::OFFSET, DynPinModeMio::InputPullUp), //pin: LowLevelPin::new(I::OFFSET),
phantom: core::marker::PhantomData, phantom: core::marker::PhantomData,
} }
} }
@ -184,292 +190,175 @@ impl<I: PinId, S: PinMode> MioPin<I, S> {
pub const unsafe fn steal() -> Self { pub const unsafe fn steal() -> Self {
unsafe { Self::new() } unsafe { Self::new() }
} }
/// Convert the pin to the requested [`PinMode`]
#[inline]
pub fn into_mode<Mode: PinMode>(self) -> MioPin<I, Mode> {
// Safe because we drop the existing Pin
MioPin {
inner: self.inner,
phantom: core::marker::PhantomData,
}
} }
pub fn into_floating_input(mut self) -> Result<MioPin<I, Input<Floating>>, PinIsOutputOnly> { pub struct Pins {
self.inner.into_input_floating()?; pub mio0: Pin<Mio0>,
Ok(self.into_mode()) pub mio1: Pin<Mio1>,
pub mio2: Pin<Mio2>,
pub mio3: Pin<Mio3>,
pub mio4: Pin<Mio4>,
pub mio5: Pin<Mio5>,
pub mio6: Pin<Mio6>,
pub mio7: Pin<Mio7>,
pub mio8: Pin<Mio8>,
pub mio9: Pin<Mio9>,
pub mio10: Pin<Mio10>,
pub mio11: Pin<Mio11>,
pub mio12: Pin<Mio12>,
pub mio13: Pin<Mio13>,
pub mio14: Pin<Mio14>,
pub mio15: Pin<Mio15>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio16: Pin<Mio16>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio17: Pin<Mio17>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio18: Pin<Mio18>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio19: Pin<Mio19>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio20: Pin<Mio20>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio21: Pin<Mio21>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio22: Pin<Mio22>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio23: Pin<Mio23>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio24: Pin<Mio24>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio25: Pin<Mio25>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio26: Pin<Mio26>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio27: Pin<Mio27>,
pub mio28: Pin<Mio28>,
pub mio29: Pin<Mio29>,
pub mio30: Pin<Mio30>,
pub mio31: Pin<Mio31>,
pub mio32: Pin<Mio32>,
pub mio33: Pin<Mio33>,
pub mio34: Pin<Mio34>,
pub mio35: Pin<Mio35>,
pub mio36: Pin<Mio36>,
pub mio37: Pin<Mio37>,
pub mio38: Pin<Mio38>,
pub mio39: Pin<Mio39>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio40: Pin<Mio40>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio41: Pin<Mio41>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio42: Pin<Mio42>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio43: Pin<Mio43>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio44: Pin<Mio44>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio45: Pin<Mio45>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio46: Pin<Mio46>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio47: Pin<Mio47>,
pub mio48: Pin<Mio48>,
pub mio49: Pin<Mio49>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio50: Pin<Mio50>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio51: Pin<Mio51>,
pub mio52: Pin<Mio52>,
pub mio53: Pin<Mio53>,
} }
pub fn into_pull_up_input(mut self) -> Result<MioPin<I, Input<PullUp>>, PinIsOutputOnly> { impl Pins {
self.inner.into_input_pull_up()?;
Ok(self.into_mode())
}
pub fn into_output(mut self, init_level: PinState) -> MioPin<I, Output> {
self.inner.into_output(init_level);
self.into_mode()
}
pub fn into_io_periph(
mut self,
mux_conf: MuxConf,
pullup: Option<bool>,
) -> MioPin<I, IoPeriph> {
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<I: PinId> MioPin<I, Output> {
#[inline]
pub fn set_high(&mut self) {
self.inner.set_high_unchecked();
}
#[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();
}
}
impl<I: PinId> IoPeriphPin for MioPin<I, IoPeriph> {
#[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<I: PinId, S: InputPin + PinMode> MioPin<I, S> {
#[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<Mio0, Reset>,
pub mio1: MioPin<Mio1, Reset>,
pub mio2: MioPin<Mio2, Reset>,
pub mio3: MioPin<Mio3, Reset>,
pub mio4: MioPin<Mio4, Reset>,
pub mio5: MioPin<Mio5, Reset>,
pub mio6: MioPin<Mio6, Reset>,
pub mio7: MioPin<Mio7, Output>,
pub mio8: MioPin<Mio8, Output>,
pub mio9: MioPin<Mio9, Reset>,
pub mio10: MioPin<Mio10, Reset>,
pub mio11: MioPin<Mio11, Reset>,
pub mio12: MioPin<Mio12, Reset>,
pub mio13: MioPin<Mio13, Reset>,
pub mio14: MioPin<Mio14, Reset>,
pub mio15: MioPin<Mio15, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio16: MioPin<Mio16, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio17: MioPin<Mio17, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio18: MioPin<Mio18, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio19: MioPin<Mio19, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio20: MioPin<Mio20, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio21: MioPin<Mio21, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio22: MioPin<Mio22, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio23: MioPin<Mio23, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio24: MioPin<Mio24, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio25: MioPin<Mio25, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio26: MioPin<Mio26, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio27: MioPin<Mio27, Reset>,
pub mio28: MioPin<Mio28, Reset>,
pub mio29: MioPin<Mio29, Reset>,
pub mio30: MioPin<Mio30, Reset>,
pub mio31: MioPin<Mio31, Reset>,
pub mio32: MioPin<Mio32, Reset>,
pub mio33: MioPin<Mio33, Reset>,
pub mio34: MioPin<Mio34, Reset>,
pub mio35: MioPin<Mio35, Reset>,
pub mio36: MioPin<Mio36, Reset>,
pub mio37: MioPin<Mio37, Reset>,
pub mio38: MioPin<Mio38, Reset>,
pub mio39: MioPin<Mio39, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio40: MioPin<Mio40, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio41: MioPin<Mio41, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio42: MioPin<Mio42, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio43: MioPin<Mio43, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio44: MioPin<Mio44, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio45: MioPin<Mio45, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio46: MioPin<Mio46, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio47: MioPin<Mio47, Reset>,
pub mio48: MioPin<Mio48, Reset>,
pub mio49: MioPin<Mio49, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio50: MioPin<Mio50, Reset>,
#[cfg(not(feature = "7z010-7z007s-clg225"))]
pub mio51: MioPin<Mio51, Reset>,
pub mio52: MioPin<Mio52, Reset>,
pub mio53: MioPin<Mio53, Reset>,
}
impl MioPins {
pub const fn new(_mmio: MmioGpio) -> Self { pub const fn new(_mmio: MmioGpio) -> Self {
Self { Self {
mio0: unsafe { MioPin::new() }, mio0: unsafe { Pin::new() },
mio1: unsafe { MioPin::new() }, mio1: unsafe { Pin::new() },
mio2: unsafe { MioPin::new() }, mio2: unsafe { Pin::new() },
mio3: unsafe { MioPin::new() }, mio3: unsafe { Pin::new() },
mio4: unsafe { MioPin::new() }, mio4: unsafe { Pin::new() },
mio5: unsafe { MioPin::new() }, mio5: unsafe { Pin::new() },
mio6: unsafe { MioPin::new() }, mio6: unsafe { Pin::new() },
mio7: unsafe { MioPin::new() }, mio7: unsafe { Pin::new() },
mio8: unsafe { MioPin::new() }, mio8: unsafe { Pin::new() },
mio9: unsafe { MioPin::new() }, mio9: unsafe { Pin::new() },
mio10: unsafe { MioPin::new() }, mio10: unsafe { Pin::new() },
mio11: unsafe { MioPin::new() }, mio11: unsafe { Pin::new() },
mio12: unsafe { MioPin::new() }, mio12: unsafe { Pin::new() },
mio13: unsafe { MioPin::new() }, mio13: unsafe { Pin::new() },
mio14: unsafe { MioPin::new() }, mio14: unsafe { Pin::new() },
mio15: unsafe { MioPin::new() }, mio15: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio16: unsafe { MioPin::new() }, mio16: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio17: unsafe { MioPin::new() }, mio17: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio18: unsafe { MioPin::new() }, mio18: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio19: unsafe { MioPin::new() }, mio19: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio20: unsafe { MioPin::new() }, mio20: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio21: unsafe { MioPin::new() }, mio21: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio22: unsafe { MioPin::new() }, mio22: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio23: unsafe { MioPin::new() }, mio23: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio24: unsafe { MioPin::new() }, mio24: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio25: unsafe { MioPin::new() }, mio25: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio26: unsafe { MioPin::new() }, mio26: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio27: unsafe { MioPin::new() }, mio27: unsafe { Pin::new() },
mio28: unsafe { MioPin::new() }, mio28: unsafe { Pin::new() },
mio29: unsafe { MioPin::new() }, mio29: unsafe { Pin::new() },
mio30: unsafe { MioPin::new() }, mio30: unsafe { Pin::new() },
mio31: unsafe { MioPin::new() }, mio31: unsafe { Pin::new() },
mio32: unsafe { MioPin::new() }, mio32: unsafe { Pin::new() },
mio33: unsafe { MioPin::new() }, mio33: unsafe { Pin::new() },
mio34: unsafe { MioPin::new() }, mio34: unsafe { Pin::new() },
mio35: unsafe { MioPin::new() }, mio35: unsafe { Pin::new() },
mio36: unsafe { MioPin::new() }, mio36: unsafe { Pin::new() },
mio37: unsafe { MioPin::new() }, mio37: unsafe { Pin::new() },
mio38: unsafe { MioPin::new() }, mio38: unsafe { Pin::new() },
mio39: unsafe { MioPin::new() }, mio39: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio40: unsafe { MioPin::new() }, mio40: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio41: unsafe { MioPin::new() }, mio41: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio42: unsafe { MioPin::new() }, mio42: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio43: unsafe { MioPin::new() }, mio43: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio44: unsafe { MioPin::new() }, mio44: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio45: unsafe { MioPin::new() }, mio45: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio46: unsafe { MioPin::new() }, mio46: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio47: unsafe { MioPin::new() }, mio47: unsafe { Pin::new() },
mio48: unsafe { MioPin::new() }, mio48: unsafe { Pin::new() },
mio49: unsafe { MioPin::new() }, mio49: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio50: unsafe { MioPin::new() }, mio50: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
mio51: unsafe { MioPin::new() }, mio51: unsafe { Pin::new() },
mio52: unsafe { MioPin::new() }, mio52: unsafe { Pin::new() },
mio53: unsafe { MioPin::new() }, mio53: unsafe { Pin::new() },
} }
} }
} }
impl<I: PinId, M: PinMode> embedded_hal::digital::ErrorType for MioPin<I, M> { impl<I: PinId> MioPinMarker for Pin<I> {
type Error = core::convert::Infallible; fn offset(&self) -> usize {
} I::OFFSET
impl<I: PinId> embedded_hal::digital::OutputPin for MioPin<I, Output> {
#[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<I: PinId> embedded_hal::digital::StatefulOutputPin for MioPin<I, Output> {
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
Ok(self.inner.is_set_high_unchecked())
}
fn is_set_low(&mut self) -> Result<bool, Self::Error> {
Ok(self.inner.is_set_low_unchecked())
}
}
impl<I: PinId, M: InputMode + PinMode> embedded_hal::digital::InputPin for MioPin<I, M> {
fn is_high(&mut self) -> Result<bool, Self::Error> {
Ok(self.inner.is_high_unchecked())
}
fn is_low(&mut self) -> Result<bool, Self::Error> {
Ok(self.inner.is_low_unchecked())
} }
} }

View File

@ -1,27 +1,42 @@
//! GPIO support module for the Zynq7000 SoC. //! 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 emio;
pub mod ll;
pub mod mio; pub mod mio;
use crate::{enable_amba_peripheral_clock, slcr::Slcr}; use core::convert::Infallible;
pub use dyn_mio::*; use ll::PinOffset;
pub use emio::*; use mio::{MioPinMarker, MuxConf};
pub use mio::*;
use crate::gpio::ll::LowLevelGpio;
use crate::{enable_amba_peripheral_clock, slcr::Slcr};
pub use embedded_hal::digital::PinState; pub use embedded_hal::digital::PinState;
use zynq7000::{gpio::MmioGpio, slcr::reset::GpioClockReset}; 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 struct GpioPins {
pub mio: MioPins, pub mio: mio::Pins,
pub emio: EmioPins, pub emio: emio::Pins,
} }
impl GpioPins { impl GpioPins {
pub fn new(gpio: MmioGpio) -> Self { pub fn new(gpio: MmioGpio) -> Self {
enable_amba_peripheral_clock(crate::PeripheralSelect::Gpio); enable_amba_peripheral_clock(crate::PeripheralSelect::Gpio);
Self { Self {
mio: MioPins::new(unsafe { gpio.clone() }), mio: mio::Pins::new(unsafe { gpio.clone() }),
emio: EmioPins::new(gpio), 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<I: mio::PinId>(_pin: mio::Pin<I>) -> 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<bool, Self::Error> {
Ok(self.ll.is_high())
}
/// Reads the input state of the pin, regardless of configured mode.
#[inline]
fn is_low(&mut self) -> Result<bool, Self::Error> {
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<bool, Self::Error> {
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<bool, Self::Error> {
Ok(self.ll.is_set_low())
}
}
/// Push-Pull output pin.
pub struct Output(LowLevelGpio);
impl Output {
pub fn new_for_mio<I: mio::PinId>(_pin: mio::Pin<I>, 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<bool, Self::Error> {
Ok(self.0.is_set_high())
}
fn is_set_low(&mut self) -> Result<bool, Self::Error> {
Ok(self.0.is_set_low())
}
}
/// Input pin.
pub struct Input(LowLevelGpio);
impl Input {
pub fn new_for_mio<I: mio::PinId>(_pin: mio::Pin<I>) -> Result<Self, PinIsOutputOnly> {
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<Self, PinIsOutputOnly> {
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<bool, Self::Error> {
Ok(self.0.is_high())
}
fn is_low(&mut self) -> Result<bool, Self::Error> {
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<bool>) -> 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()
}
}

View File

@ -6,16 +6,19 @@ use zynq7000::{
}; };
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[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, Mio16, Mio17, Mio18, Mio19, Mio20, Mio21, Mio22, Mio23, Mio24, Mio25, Mio26, Mio27, Mio40,
Mio41, Mio42, Mio43, Mio44, Mio45, Mio46, Mio47, Mio50, Mio51, Mio41, Mio42, Mio43, Mio44, Mio45, Mio46, Mio47, Mio50, Mio51,
}; };
use crate::{ use crate::{
enable_amba_peripheral_clock, enable_amba_peripheral_clock,
gpio::{ gpio::{
IoPeriph, IoPeriphPin, Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, Mio30, IoPeriphPin,
Mio31, Mio32, Mio33, Mio34, Mio35, Mio36, Mio37, Mio38, Mio39, Mio48, Mio49, Mio52, Mio53, mio::{
MioPin, MuxConf, PinMode, 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, slcr::Slcr,
time::Hertz, time::Hertz,
@ -55,16 +58,31 @@ impl PsI2c for MmioI2c<'static> {
} }
} }
pub trait SdaPin: IoPeriphPin { pub trait SdaPin: MioPinMarker {
const ID: I2cId; const ID: I2cId;
} }
pub trait SckPin: IoPeriphPin { pub trait SckPin: MioPinMarker {
const ID: I2cId; const ID: I2cId;
} }
pub trait I2cPins {} 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 { macro_rules! into_i2c {
($($Mio:ident),+) => { ($($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!( into_i2c!(
Mio10, Mio11, Mio14, Mio15, Mio30, Mio31, Mio34, Mio35, Mio38, Mio39, Mio12, Mio13, Mio28, Mio10, Mio11, Mio14, Mio15, Mio30, Mio31, Mio34, Mio35, Mio38, Mio39, Mio12, Mio13, Mio28,
Mio29, Mio32, Mio33, Mio36, Mio37, Mio48, Mio49, Mio52, Mio53 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, Mio18, Mio19, Mio22, Mio23, Mio26, Mio27, Mio42, Mio43, Mio46, Mio47, Mio50, Mio51, Mio16,
Mio17, Mio20, Mio21, Mio24, Mio25, Mio40, Mio41, Mio44, Mio45 Mio17, Mio20, Mio21, Mio24, Mio25, Mio40, Mio41, Mio44, Mio45
); );
*/
i2c_pin_impls!(I2cId::I2c0, Mio10, Mio11); i2c_pin_impls!(I2cId::I2c0, Mio10, Mio11);
i2c_pin_impls!(I2cId::I2c0, Mio14, Mio15); i2c_pin_impls!(I2cId::I2c0, Mio14, Mio15);
@ -318,9 +323,8 @@ impl I2c {
if Sck::ID != Sda::ID { if Sck::ID != Sda::ID {
return Err(I2cConstructionError::PinInvalidForI2cId); return Err(I2cConstructionError::PinInvalidForI2cId);
} }
if i2c_pins.0.mux_conf() != I2C_MUX_CONF || i2c_pins.1.mux_conf() != I2C_MUX_CONF { IoPeriphPin::new(i2c_pins.0, I2C_MUX_CONF, Some(true));
return Err(I2cConstructionError::InvalidPinConf); IoPeriphPin::new(i2c_pins.1, I2C_MUX_CONF, Some(true));
}
Ok(Self::new_generic( Ok(Self::new_generic(
i2c.id().unwrap(), i2c.id().unwrap(),
i2c.reg_block(), i2c.reg_block(),

View File

@ -198,6 +198,7 @@ pub fn disable_amba_peripheral_clock(select: PeripheralSelect) {
} }
} }
#[allow(dead_code)]
pub(crate) mod sealed { pub(crate) mod sealed {
pub trait Sealed {} pub trait Sealed {}
} }

View File

@ -3,12 +3,13 @@ use core::convert::Infallible;
use crate::clocks::Clocks; use crate::clocks::Clocks;
use crate::enable_amba_peripheral_clock; use crate::enable_amba_peripheral_clock;
use crate::gpio::{ use crate::gpio::IoPeriphPin;
IoPeriph, IoPeriphPin, Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, Mio30, Mio31, use crate::gpio::mio::{
Mio32, Mio33, Mio34, Mio35, Mio36, Mio37, Mio38, Mio39, MioPin, MuxConf, 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"))] #[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, Mio16, Mio17, Mio18, Mio19, Mio20, Mio21, Mio22, Mio23, Mio24, Mio25, Mio26, Mio27, Mio40,
Mio41, Mio42, Mio43, Mio44, Mio45, Mio46, Mio47, Mio48, Mio49, Mio50, Mio51, 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 SPI: SpiId;
const GROUP: usize; const GROUP: usize;
} }
pub trait MosiPin: IoPeriphPin { pub trait MosiPin: MioPinMarker {
const SPI: SpiId; const SPI: SpiId;
const GROUP: usize; const GROUP: usize;
} }
pub trait MisoPin: IoPeriphPin { pub trait MisoPin: MioPinMarker {
const SPI: SpiId; const SPI: SpiId;
const GROUP: usize; const GROUP: usize;
} }
pub trait SsPin: IoPeriphPin { pub trait SsPin: MioPinMarker {
const IDX: usize; const IDX: usize;
const SPI: SpiId; const SPI: SpiId;
const GROUP: usize; const GROUP: usize;
@ -82,15 +83,17 @@ pub trait SsPin: IoPeriphPin {
pub const SPI_MUX_CONF: MuxConf = MuxConf::new_with_l3(u3::new(0b101)); pub const SPI_MUX_CONF: MuxConf = MuxConf::new_with_l3(u3::new(0b101));
/*
macro_rules! impl_into_spi { macro_rules! impl_into_spi {
(($($Mio:ident),+)) => { (($($Mio:ident),+)) => {
$( $(
impl<M: $crate::gpio::PinMode> MioPin<$Mio, M> { impl From<Pin<$Mio>> for IoPeriphPin {
/// Convert the pin into SPI pins by configuring the pin routing via the /// Convert the pin into SPI pins by configuring the pin routing via the
/// MIO multiplexer bits. Also disables pull-ups for the pins. /// MIO multiplexer bits. Also disables pull-ups for the pins.
pub fn into_spi(self) -> MioPin<$Mio, IoPeriph> { fn from(pin: Pin<$Mio>) -> Self {
self.into_io_periph(SPI_MUX_CONF, Some(false)) 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, Mio28, Mio33, Mio29, Mio30, Mio31, Mio32, Mio12, Mio10, Mio11, Mio13, Mio14, Mio15, Mio36,
Mio34, Mio35, Mio37, Mio38, Mio39 Mio34, Mio35, Mio37, Mio38, Mio39
)); ));
*/
// SPI0, choice 1 // SPI0, choice 1
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl SckPin for MioPin<Mio16, IoPeriph> { impl SckPin for Pin<Mio16> {
const SPI: SpiId = SpiId::Spi0; const SPI: SpiId = SpiId::Spi0;
const GROUP: usize = 0; const GROUP: usize = 0;
} }
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl MosiPin for MioPin<Mio21, IoPeriph> { impl MosiPin for Pin<Mio21> {
const SPI: SpiId = SpiId::Spi0; const SPI: SpiId = SpiId::Spi0;
const GROUP: usize = 0; const GROUP: usize = 0;
} }
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl MisoPin for MioPin<Mio17, IoPeriph> { impl MisoPin for Pin<Mio17> {
const SPI: SpiId = SpiId::Spi0; const SPI: SpiId = SpiId::Spi0;
const GROUP: usize = 0; const GROUP: usize = 0;
} }
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl SsPin for MioPin<Mio18, IoPeriph> { impl SsPin for Pin<Mio18> {
const SPI: SpiId = SpiId::Spi0; const SPI: SpiId = SpiId::Spi0;
const GROUP: usize = 0; const GROUP: usize = 0;
const IDX: usize = 0; const IDX: usize = 0;
} }
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl SsPin for MioPin<Mio19, IoPeriph> { impl SsPin for Pin<Mio19> {
const SPI: SpiId = SpiId::Spi0; const SPI: SpiId = SpiId::Spi0;
const GROUP: usize = 0; const GROUP: usize = 0;
const IDX: usize = 1; const IDX: usize = 1;
} }
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl SsPin for MioPin<Mio20, IoPeriph> { impl SsPin for Pin<Mio20> {
const SPI: SpiId = SpiId::Spi0; const SPI: SpiId = SpiId::Spi0;
const GROUP: usize = 0; const GROUP: usize = 0;
const IDX: usize = 2; const IDX: usize = 2;
} }
// SPI0, choice 2 // SPI0, choice 2
impl SckPin for MioPin<Mio28, IoPeriph> { impl SckPin for Pin<Mio28> {
const SPI: SpiId = SpiId::Spi0; const SPI: SpiId = SpiId::Spi0;
const GROUP: usize = 1; const GROUP: usize = 1;
} }
impl MosiPin for MioPin<Mio33, IoPeriph> { impl MosiPin for Pin<Mio33> {
const SPI: SpiId = SpiId::Spi0; const SPI: SpiId = SpiId::Spi0;
const GROUP: usize = 1; const GROUP: usize = 1;
} }
impl MisoPin for MioPin<Mio29, IoPeriph> { impl MisoPin for Pin<Mio29> {
const SPI: SpiId = SpiId::Spi0; const SPI: SpiId = SpiId::Spi0;
const GROUP: usize = 1; const GROUP: usize = 1;
} }
impl SsPin for MioPin<Mio30, IoPeriph> { impl SsPin for Pin<Mio30> {
const SPI: SpiId = SpiId::Spi0; const SPI: SpiId = SpiId::Spi0;
const GROUP: usize = 1; const GROUP: usize = 1;
const IDX: usize = 0; const IDX: usize = 0;
} }
impl SsPin for MioPin<Mio31, IoPeriph> { impl SsPin for Pin<Mio31> {
const SPI: SpiId = SpiId::Spi0; const SPI: SpiId = SpiId::Spi0;
const GROUP: usize = 1; const GROUP: usize = 1;
const IDX: usize = 1; const IDX: usize = 1;
} }
impl SsPin for MioPin<Mio32, IoPeriph> { impl SsPin for Pin<Mio32> {
const SPI: SpiId = SpiId::Spi0; const SPI: SpiId = SpiId::Spi0;
const GROUP: usize = 1; const GROUP: usize = 1;
const IDX: usize = 2; const IDX: usize = 2;
@ -173,63 +177,63 @@ impl SsPin for MioPin<Mio32, IoPeriph> {
// SPI0, choice 3 // SPI0, choice 3
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl SckPin for MioPin<Mio40, IoPeriph> { impl SckPin for Pin<Mio40> {
const SPI: SpiId = SpiId::Spi0; const SPI: SpiId = SpiId::Spi0;
const GROUP: usize = 2; const GROUP: usize = 2;
} }
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl MosiPin for MioPin<Mio45, IoPeriph> { impl MosiPin for Pin<Mio45> {
const SPI: SpiId = SpiId::Spi0; const SPI: SpiId = SpiId::Spi0;
const GROUP: usize = 2; const GROUP: usize = 2;
} }
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl MisoPin for MioPin<Mio41, IoPeriph> { impl MisoPin for Pin<Mio41> {
const SPI: SpiId = SpiId::Spi0; const SPI: SpiId = SpiId::Spi0;
const GROUP: usize = 2; const GROUP: usize = 2;
} }
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl SsPin for MioPin<Mio42, IoPeriph> { impl SsPin for Pin<Mio42> {
const SPI: SpiId = SpiId::Spi0; const SPI: SpiId = SpiId::Spi0;
const GROUP: usize = 2; const GROUP: usize = 2;
const IDX: usize = 0; const IDX: usize = 0;
} }
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl SsPin for MioPin<Mio43, IoPeriph> { impl SsPin for Pin<Mio43> {
const SPI: SpiId = SpiId::Spi0; const SPI: SpiId = SpiId::Spi0;
const GROUP: usize = 2; const GROUP: usize = 2;
const IDX: usize = 1; const IDX: usize = 1;
} }
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl SsPin for MioPin<Mio44, IoPeriph> { impl SsPin for Pin<Mio44> {
const SPI: SpiId = SpiId::Spi0; const SPI: SpiId = SpiId::Spi0;
const GROUP: usize = 2; const GROUP: usize = 2;
const IDX: usize = 2; const IDX: usize = 2;
} }
// SPI1, choice 1 // SPI1, choice 1
impl SckPin for MioPin<Mio12, IoPeriph> { impl SckPin for Pin<Mio12> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 0; const GROUP: usize = 0;
} }
impl MosiPin for MioPin<Mio10, IoPeriph> { impl MosiPin for Pin<Mio10> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 0; const GROUP: usize = 0;
} }
impl MisoPin for MioPin<Mio11, IoPeriph> { impl MisoPin for Pin<Mio11> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 0; const GROUP: usize = 0;
} }
impl SsPin for MioPin<Mio13, IoPeriph> { impl SsPin for Pin<Mio13> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 0; const GROUP: usize = 0;
const IDX: usize = 0; const IDX: usize = 0;
} }
impl SsPin for MioPin<Mio14, IoPeriph> { impl SsPin for Pin<Mio14> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 0; const GROUP: usize = 0;
const IDX: usize = 1; const IDX: usize = 1;
} }
impl SsPin for MioPin<Mio15, IoPeriph> { impl SsPin for Pin<Mio15> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 0; const GROUP: usize = 0;
const IDX: usize = 2; const IDX: usize = 2;
@ -237,63 +241,63 @@ impl SsPin for MioPin<Mio15, IoPeriph> {
// SPI1, choice 2 // SPI1, choice 2
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl SckPin for MioPin<Mio24, IoPeriph> { impl SckPin for Pin<Mio24> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 1; const GROUP: usize = 1;
} }
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl MosiPin for MioPin<Mio22, IoPeriph> { impl MosiPin for Pin<Mio22> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 1; const GROUP: usize = 1;
} }
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl MisoPin for MioPin<Mio23, IoPeriph> { impl MisoPin for Pin<Mio23> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 1; const GROUP: usize = 1;
} }
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl SsPin for MioPin<Mio25, IoPeriph> { impl SsPin for Pin<Mio25> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 1; const GROUP: usize = 1;
const IDX: usize = 0; const IDX: usize = 0;
} }
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl SsPin for MioPin<Mio26, IoPeriph> { impl SsPin for Pin<Mio26> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 1; const GROUP: usize = 1;
const IDX: usize = 1; const IDX: usize = 1;
} }
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl SsPin for MioPin<Mio27, IoPeriph> { impl SsPin for Pin<Mio27> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 1; const GROUP: usize = 1;
const IDX: usize = 2; const IDX: usize = 2;
} }
// SPI1, choice 2 // SPI1, choice 2
impl SckPin for MioPin<Mio36, IoPeriph> { impl SckPin for Pin<Mio36> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 2; const GROUP: usize = 2;
} }
impl MosiPin for MioPin<Mio34, IoPeriph> { impl MosiPin for Pin<Mio34> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 2; const GROUP: usize = 2;
} }
impl MisoPin for MioPin<Mio35, IoPeriph> { impl MisoPin for Pin<Mio35> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 2; const GROUP: usize = 2;
} }
impl SsPin for MioPin<Mio37, IoPeriph> { impl SsPin for Pin<Mio37> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 2; const GROUP: usize = 2;
const IDX: usize = 0; const IDX: usize = 0;
} }
impl SsPin for MioPin<Mio38, IoPeriph> { impl SsPin for Pin<Mio38> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 2; const GROUP: usize = 2;
const IDX: usize = 1; const IDX: usize = 1;
} }
impl SsPin for MioPin<Mio39, IoPeriph> { impl SsPin for Pin<Mio39> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 2; const GROUP: usize = 2;
const IDX: usize = 2; const IDX: usize = 2;
@ -301,34 +305,34 @@ impl SsPin for MioPin<Mio39, IoPeriph> {
// SPI1, choice 3 // SPI1, choice 3
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl SckPin for MioPin<Mio48, IoPeriph> { impl SckPin for Pin<Mio48> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 3; const GROUP: usize = 3;
} }
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl MosiPin for MioPin<Mio46, IoPeriph> { impl MosiPin for Pin<Mio46> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 3; const GROUP: usize = 3;
} }
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl MisoPin for MioPin<Mio47, IoPeriph> { impl MisoPin for Pin<Mio47> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 3; const GROUP: usize = 3;
} }
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl SsPin for MioPin<Mio49, IoPeriph> { impl SsPin for Pin<Mio49> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 3; const GROUP: usize = 3;
const IDX: usize = 0; const IDX: usize = 0;
} }
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl SsPin for MioPin<Mio50, IoPeriph> { impl SsPin for Pin<Mio50> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 3; const GROUP: usize = 3;
const IDX: usize = 1; const IDX: usize = 1;
} }
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
impl SsPin for MioPin<Mio51, IoPeriph> { impl SsPin for Pin<Mio51> {
const SPI: SpiId = SpiId::Spi1; const SPI: SpiId = SpiId::Spi1;
const GROUP: usize = 3; const GROUP: usize = 3;
const IDX: usize = 2; const IDX: usize = 2;
@ -555,8 +559,7 @@ impl SpiLowLevel {
#[inline(always)] #[inline(always)]
pub fn write_fifo_unchecked(&mut self, data: u8) { pub fn write_fifo_unchecked(&mut self, data: u8) {
self.regs self.regs.write_txd(FifoWrite::new(data));
.write_txd(FifoWrite::new(data));
} }
#[inline(always)] #[inline(always)]
@ -706,12 +709,9 @@ impl Spi {
if Sck::SPI != spi_id || Mosi::SPI != spi_id || Miso::SPI != spi_id { if Sck::SPI != spi_id || Mosi::SPI != spi_id || Miso::SPI != spi_id {
return Err(SpiConstructionError::PinInvalidForSpiId); return Err(SpiConstructionError::PinInvalidForSpiId);
} }
if spi_pins.0.mux_conf() != SPI_MUX_CONF IoPeriphPin::new(spi_pins.0, SPI_MUX_CONF, Some(false));
|| spi_pins.0.mux_conf() != spi_pins.2.mux_conf() IoPeriphPin::new(spi_pins.1, SPI_MUX_CONF, Some(false));
|| spi_pins.1.mux_conf() != spi_pins.2.mux_conf() IoPeriphPin::new(spi_pins.2, SPI_MUX_CONF, Some(false));
{
return Err(SpiConstructionError::InvalidPinConf);
}
Ok(Self::new_generic_unchecked( Ok(Self::new_generic_unchecked(
spi_id, spi_id,
spi.reg_block(), 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 { if Sck::SPI != spi_id || Mosi::SPI != spi_id || Miso::SPI != spi_id || Ss::SPI != spi_id {
return Err(SpiConstructionError::PinInvalidForSpiId); return Err(SpiConstructionError::PinInvalidForSpiId);
} }
if spi_pins.0.mux_conf() != SPI_MUX_CONF IoPeriphPin::new(spi_pins.0, SPI_MUX_CONF, Some(false));
|| spi_pins.0.mux_conf() != spi_pins.2.mux_conf() IoPeriphPin::new(spi_pins.1, SPI_MUX_CONF, Some(false));
|| spi_pins.1.mux_conf() != spi_pins.2.mux_conf() IoPeriphPin::new(spi_pins.2, SPI_MUX_CONF, Some(false));
|| ss_pin.mux_conf() != spi_pins.0.mux_conf() IoPeriphPin::new(ss_pin, SPI_MUX_CONF, Some(false));
{
return Err(SpiConstructionError::InvalidPinConf);
}
Ok(Self::new_generic_unchecked( Ok(Self::new_generic_unchecked(
spi_id, spi_id,
spi.reg_block(), spi.reg_block(),
@ -780,14 +777,11 @@ impl Spi {
{ {
return Err(SpiConstructionError::PinInvalidForSpiId); return Err(SpiConstructionError::PinInvalidForSpiId);
} }
if spi_pins.0.mux_conf() != SPI_MUX_CONF IoPeriphPin::new(spi_pins.0, SPI_MUX_CONF, Some(false));
|| spi_pins.0.mux_conf() != spi_pins.2.mux_conf() IoPeriphPin::new(spi_pins.1, SPI_MUX_CONF, Some(false));
|| spi_pins.1.mux_conf() != spi_pins.2.mux_conf() IoPeriphPin::new(spi_pins.2, SPI_MUX_CONF, Some(false));
|| ss_pins.0.mux_conf() != spi_pins.0.mux_conf() IoPeriphPin::new(ss_pins.0, SPI_MUX_CONF, Some(false));
|| ss_pins.1.mux_conf() != spi_pins.0.mux_conf() IoPeriphPin::new(ss_pins.1, SPI_MUX_CONF, Some(false));
{
return Err(SpiConstructionError::InvalidPinConf);
}
Ok(Self::new_generic_unchecked( Ok(Self::new_generic_unchecked(
spi_id, spi_id,
spi.reg_block(), spi.reg_block(),
@ -832,15 +826,12 @@ impl Spi {
{ {
return Err(SpiConstructionError::PinInvalidForSpiId); return Err(SpiConstructionError::PinInvalidForSpiId);
} }
if spi_pins.0.mux_conf() != SPI_MUX_CONF IoPeriphPin::new(spi_pins.0, SPI_MUX_CONF, Some(false));
|| spi_pins.0.mux_conf() != spi_pins.2.mux_conf() IoPeriphPin::new(spi_pins.1, SPI_MUX_CONF, Some(false));
|| spi_pins.1.mux_conf() != spi_pins.2.mux_conf() IoPeriphPin::new(spi_pins.2, SPI_MUX_CONF, Some(false));
|| ss_pins.0.mux_conf() != spi_pins.0.mux_conf() IoPeriphPin::new(ss_pins.0, SPI_MUX_CONF, Some(false));
|| ss_pins.1.mux_conf() != spi_pins.0.mux_conf() IoPeriphPin::new(ss_pins.1, SPI_MUX_CONF, Some(false));
|| ss_pins.2.mux_conf() != spi_pins.2.mux_conf() IoPeriphPin::new(ss_pins.2, SPI_MUX_CONF, Some(false));
{
return Err(SpiConstructionError::InvalidPinConf);
}
Ok(Self::new_generic_unchecked( Ok(Self::new_generic_unchecked(
spi_id, spi_id,
spi.reg_block(), spi.reg_block(),

View File

@ -8,10 +8,13 @@ use arbitrary_int::{Number, u3, u4};
use zynq7000::ttc::{MmioTtc, TTC_0_BASE_ADDR, TTC_1_BASE_ADDR}; use zynq7000::ttc::{MmioTtc, TTC_0_BASE_ADDR, TTC_1_BASE_ADDR};
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[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::{ use crate::{
clocks::ArmClocks, clocks::ArmClocks,
gpio::{IoPeriph, IoPeriphPin, Mio28, Mio29, Mio30, Mio31, MioPin, MuxConf, PinMode}, gpio::{
IoPeriphPin,
mio::{Mio28, Mio29, Mio30, Mio31, MioPinMarker, MuxConf, Pin},
},
time::Hertz, 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 const TTC_MUX_CONF: MuxConf = MuxConf::new_with_l3(u3::new(0b110));
pub trait ClockInPin: IoPeriphPin { pub trait ClockInPin: MioPinMarker {
const ID: TtcId; const ID: TtcId;
} }
pub trait WaveOutPin: IoPeriphPin { pub trait WaveOutPin: MioPinMarker {
const ID: TtcId; const ID: TtcId;
} }
macro_rules! into_ttc { // TTC0 pin trait implementations.
($($Mio:ident),+) => {
$(
impl <M: PinMode> 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)
}
}
)+
};
}
impl ClockInPin for Pin<Mio19> {
const ID: TtcId = TtcId::Ttc0;
}
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[cfg(not(feature = "7z010-7z007s-clg225"))]
into_ttc!(Mio16, Mio17, Mio18, Mio19, Mio40, Mio41, Mio42, Mio43); impl ClockInPin for Pin<Mio31> {
into_ttc!(Mio28, Mio29, Mio30, Mio31); const ID: TtcId = TtcId::Ttc0;
}
#[cfg(not(feature = "7z010-7z007s-clg225"))]
impl ClockInPin for Pin<Mio43> {
const ID: TtcId = TtcId::Ttc0;
}
impl WaveOutPin for Pin<Mio18> {
const ID: TtcId = TtcId::Ttc0;
}
#[cfg(not(feature = "7z010-7z007s-clg225"))]
impl WaveOutPin for Pin<Mio30> {
const ID: TtcId = TtcId::Ttc0;
}
#[cfg(not(feature = "7z010-7z007s-clg225"))]
impl WaveOutPin for Pin<Mio42> {
const ID: TtcId = TtcId::Ttc0;
}
// TTC1 pin trait implementations.
impl ClockInPin for Pin<Mio17> {
const ID: TtcId = TtcId::Ttc1;
}
#[cfg(not(feature = "7z010-7z007s-clg225"))]
impl ClockInPin for Pin<Mio29> {
const ID: TtcId = TtcId::Ttc1;
}
#[cfg(not(feature = "7z010-7z007s-clg225"))]
impl ClockInPin for Pin<Mio41> {
const ID: TtcId = TtcId::Ttc1;
}
impl WaveOutPin for Pin<Mio16> {
const ID: TtcId = TtcId::Ttc1;
}
#[cfg(not(feature = "7z010-7z007s-clg225"))]
impl WaveOutPin for Pin<Mio28> {
const ID: TtcId = TtcId::Ttc1;
}
#[cfg(not(feature = "7z010-7z007s-clg225"))]
impl WaveOutPin for Pin<Mio40> {
const ID: TtcId = TtcId::Ttc1;
}
pub struct Ttc { pub struct Ttc {
pub ch0: TtcChannel, pub ch0: TtcChannel,
@ -187,9 +224,7 @@ impl Pwm {
freq: Hertz, freq: Hertz,
wave_out: impl WaveOutPin, wave_out: impl WaveOutPin,
) -> Result<Self, TtcConstructionError> { ) -> Result<Self, TtcConstructionError> {
if wave_out.mux_conf() != TTC_MUX_CONF { IoPeriphPin::new(wave_out, TTC_MUX_CONF, None);
return Err(InvalidTtcPinConfigError(wave_out.mux_conf()).into());
}
Ok(Self::new_with_cpu_clk(channel, arm_clocks, freq)?) Ok(Self::new_with_cpu_clk(channel, arm_clocks, freq)?)
} }

View File

@ -16,15 +16,18 @@ use zynq7000::{
use crate::{ use crate::{
enable_amba_peripheral_clock, enable_amba_peripheral_clock,
gpio::{ gpio::{
IoPeriph, IoPeriphPin, Mio8, Mio9, Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, IoPeriphPin,
Mio30, Mio31, Mio32, Mio33, Mio34, Mio35, Mio36, Mio37, Mio38, Mio39, Mio48, Mio49, Mio52, mio::{
Mio53, MioPin, MuxConf, PinMode, 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, slcr::Slcr,
}; };
#[cfg(not(feature = "7z010-7z007s-clg225"))] #[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, Mio16, Mio17, Mio18, Mio19, Mio20, Mio21, Mio22, Mio23, Mio24, Mio25, Mio26, Mio27, Mio40,
Mio41, Mio42, Mio43, Mio44, Mio45, Mio46, Mio47, Mio50, Mio51, 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; const UART_IDX: UartId;
} }
pub trait TxPin { pub trait TxPin: MioPinMarker {
const UART_IDX: UartId; const UART_IDX: UartId;
} }
@ -103,27 +106,27 @@ macro_rules! pin_pairs {
($UartPeriph:path, ($( [$(#[$meta:meta], )? $TxMio:ident, $RxMio:ident] ),+ $(,)? )) => { ($UartPeriph:path, ($( [$(#[$meta:meta], )? $TxMio:ident, $RxMio:ident] ),+ $(,)? )) => {
$( $(
$( #[$meta] )? $( #[$meta] )?
impl TxPin for MioPin<$TxMio, IoPeriph> { impl TxPin for Pin<$TxMio> {
const UART_IDX: UartId = $UartPeriph; const UART_IDX: UartId = $UartPeriph;
} }
$( #[$meta] )? $( #[$meta] )?
impl RxPin for MioPin<$RxMio, IoPeriph> { impl RxPin for Pin<$RxMio> {
const UART_IDX: UartId = $UartPeriph; 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 { macro_rules! impl_into_uart {
(($($Mio:ident),+)) => { (($($Mio:ident),+)) => {
$( $(
impl<M: PinMode> MioPin<$Mio, M> { impl From<Pin<$Mio>> for IoPeriphPin {
pub fn into_uart(self) -> MioPin<$Mio, IoPeriph> { fn from(pin: Pin<$Mio>) -> Self {
self.into_io_periph(UART_MUX_CONF, None) 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, Mio19, Mio18, Mio23, Mio22, Mio43, Mio42, Mio47, Mio46, Mio51, Mio50, Mio16, Mio17, Mio20,
Mio21, Mio24, Mio25, Mio40, Mio41, Mio44, Mio45 Mio21, Mio24, Mio25, Mio40, Mio41, Mio44, Mio45
)); ));
*/
pin_pairs!( pin_pairs!(
UartId::Uart0, UartId::Uart0,
@ -453,7 +457,7 @@ impl Uart {
} }
/// This is the constructor to use the PS UART with MIO pins. /// This is the constructor to use the PS UART with MIO pins.
pub fn new_with_mio<TxPinI: TxPin + IoPeriphPin, RxPinI: RxPin + IoPeriphPin>( pub fn new_with_mio<TxPinI: TxPin, RxPinI: RxPin>(
uart: impl PsUart, uart: impl PsUart,
cfg: UartConfig, cfg: UartConfig,
pins: (TxPinI, RxPinI), pins: (TxPinI, RxPinI),
@ -468,12 +472,8 @@ impl Uart {
if id.unwrap() != TxPinI::UART_IDX || id.unwrap() != RxPinI::UART_IDX { if id.unwrap() != TxPinI::UART_IDX || id.unwrap() != RxPinI::UART_IDX {
return Err(UartConstructionError::IdxMissmatch); return Err(UartConstructionError::IdxMissmatch);
} }
if pins.0.mux_conf() != UART_MUX_CONF { IoPeriphPin::new(pins.0, UART_MUX_CONF, None);
return Err(UartConstructionError::InvalidMuxConf(pins.0.mux_conf())); IoPeriphPin::new(pins.1, UART_MUX_CONF, None);
}
if pins.1.mux_conf() != UART_MUX_CONF {
return Err(UartConstructionError::InvalidMuxConf(pins.1.mux_conf()));
}
Ok(Self::new_generic_unchecked( Ok(Self::new_generic_unchecked(
uart.reg_block(), uart.reg_block(),
id.unwrap(), id.unwrap(),

View File

@ -11,8 +11,8 @@ keywords = ["no-std", "arm", "cortex-a", "amd", "zynq7000"]
categories = ["embedded", "no-std", "hardware-support"] categories = ["embedded", "no-std", "hardware-support"]
[dependencies] [dependencies]
cortex-a-rt = { path = "/home/rmueller/Rust/cortex-ar/cortex-a-rt", optional = true, features = ["vfp-dp"] } cortex-a-rt = { git = "https://github.com/rust-embedded/cortex-ar", branch = "main", optional = true, features = ["vfp-dp"] }
cortex-ar = { path = "/home/rmueller/Rust/cortex-ar/cortex-ar" } cortex-ar = { git = "https://github.com/rust-embedded/cortex-ar", branch = "main", features = ["critical-section-single-core"] }
[features] [features]
default = ["rt"] default = ["rt"]

View File

@ -1,5 +1,5 @@
//! SPI register module. //! 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_0_BASE_ADDR: usize = 0xE000_6000;
pub const SPI_1_BASE_ADDR: usize = 0xE000_7000; pub const SPI_1_BASE_ADDR: usize = 0xE000_7000;