re-worked GPIO implementation

This commit is contained in:
Robin Müller 2025-04-10 17:10:24 +02:00
parent 1bbfc98a0a
commit f423f8e6dd
25 changed files with 1254 additions and 1321 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -11,7 +11,7 @@ keywords = ["no-std", "arm", "cortex-a", "amd", "zynq7000"]
categories = ["embedded", "no-std", "hardware-support"]
[dependencies]
cortex-ar = { git = "https://github.com/us-irs/cortex-ar.git", branch = "cortex-a-addition", features = ["critical-section-single-core"] }
cortex-ar = { git = "https://github.com/rust-embedded/cortex-ar", branch = "main", features = ["critical-section-single-core"] }
zynq7000-rt = { path = "../../zynq7000-rt" }
zynq7000 = { path = "../../zynq7000" }
zynq7000-hal = { path = "../../zynq7000-hal" }

View File

@ -22,7 +22,7 @@ use zynq7000_hal::{
clocks::Clocks,
configure_level_shifter,
gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gpio::{EmioPin, GpioPins, PinState},
gpio::{GpioPins, Output, PinState},
gtc::Gtc,
i2c,
time::Hertz,
@ -73,12 +73,10 @@ async fn main(_spawner: Spawner) -> ! {
let uart_clk_config = uart::ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200)
.unwrap()
.0;
let uart_tx = gpio_pins.mio.mio48.into_uart();
let uart_rx = gpio_pins.mio.mio49.into_uart();
let mut uart = uart::Uart::new_with_mio(
dp.uart_1,
uart::UartConfig::new_with_clk_config(uart_clk_config),
(uart_tx, uart_rx),
(gpio_pins.mio.mio48, gpio_pins.mio.mio49),
)
.unwrap();
uart.write_all(b"-- Zynq 7000 Zedboard I2C L3GD20H example --\n\r")
@ -95,45 +93,48 @@ async fn main(_spawner: Spawner) -> ! {
let boot_mode = BootMode::new();
info!("Boot mode: {:?}", boot_mode);
let sck_pin = gpio_pins.mio.mio12.into_i2c();
let sda_pin = gpio_pins.mio.mio13.into_i2c();
let pin_sel = match I2C_ADDR_SEL {
I2cAddr::Sa0Low => PinState::Low,
I2cAddr::Sa0High => PinState::High,
};
let _sa0_pin = gpio_pins.mio.mio11.into_output(pin_sel);
let _sa0_pin = Output::new_for_mio(gpio_pins.mio.mio11, pin_sel);
// The CS pin must be pulled high.
let _cs_pin = gpio_pins.mio.mio10.into_output(PinState::High);
let _cs_pin = Output::new_for_mio(gpio_pins.mio.mio10, PinState::High);
let clk_config = i2c::calculate_divisors(
clocks.arm_clocks().cpu_1x_clk(),
i2c::I2cSpeed::Normal100kHz,
)
.unwrap();
let i2c = i2c::I2c::new_with_mio(dp.i2c_1, clk_config, (sck_pin, sda_pin)).unwrap();
let i2c = i2c::I2c::new_with_mio(
dp.i2c_1,
clk_config,
(gpio_pins.mio.mio12, gpio_pins.mio.mio13),
)
.unwrap();
let mut l3gd20 = l3gd20::i2c::L3gd20::new(i2c, l3gd20::i2c::I2cAddr::Sa0Low).unwrap();
let who_am_i = l3gd20.who_am_i().unwrap();
info!("L3GD20 WHO_AM_I: 0x{:02X}", who_am_i);
let mut delay = Delay;
let mut ticker = Ticker::every(Duration::from_millis(400));
let mut mio_led = gpio_pins.mio.mio7.into_output(PinState::Low);
let mut mio_led = Output::new_for_mio(gpio_pins.mio.mio7, PinState::Low);
let mut emio_leds: [EmioPin; 8] = [
gpio_pins.emio.take(0).unwrap(),
gpio_pins.emio.take(1).unwrap(),
gpio_pins.emio.take(2).unwrap(),
gpio_pins.emio.take(3).unwrap(),
gpio_pins.emio.take(4).unwrap(),
gpio_pins.emio.take(5).unwrap(),
gpio_pins.emio.take(6).unwrap(),
gpio_pins.emio.take(7).unwrap(),
let mut emio_leds: [Output; 8] = [
Output::new_for_emio(gpio_pins.emio.take(0).unwrap(), PinState::Low),
Output::new_for_emio(gpio_pins.emio.take(1).unwrap(), PinState::Low),
Output::new_for_emio(gpio_pins.emio.take(2).unwrap(), PinState::Low),
Output::new_for_emio(gpio_pins.emio.take(3).unwrap(), PinState::Low),
Output::new_for_emio(gpio_pins.emio.take(4).unwrap(), PinState::Low),
Output::new_for_emio(gpio_pins.emio.take(5).unwrap(), PinState::Low),
Output::new_for_emio(gpio_pins.emio.take(6).unwrap(), PinState::Low),
Output::new_for_emio(gpio_pins.emio.take(7).unwrap(), PinState::Low),
];
for (idx, led) in emio_leds.iter_mut().enumerate() {
if idx % 2 == 0 {
led.into_output(PinState::High);
led.set_high();
} else {
led.into_output(PinState::Low);
led.set_low();
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -11,7 +11,7 @@ keywords = ["no-std", "hal", "amd", "zynq7000", "xilinx", "bare-metal"]
categories = ["embedded", "no-std", "hardware-support"]
[dependencies]
cortex-ar = { path = "../../../Rust/cortex-ar/cortex-ar" }
cortex-ar = { git = "https://github.com/rust-embedded/cortex-ar", branch = "main", features = ["critical-section-single-core"] }
zynq7000 = { path = "../zynq7000" }
arbitrary-int = "1.3"

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.
use zynq7000::gpio::{Gpio, MaskedOutput, MmioGpio};
//! EMIO (Extended Multiplexed I/O) resource management module.
use zynq7000::gpio::MmioGpio;
pub use crate::gpio::PinState;
#[derive(Debug, thiserror::Error)]
#[error("invalid pin mode for MIO pin: {0:?}")]
pub struct InvalidPinModeEmio(pub DynPinModeEmio);
impl embedded_hal::digital::Error for InvalidPinModeEmio {
fn kind(&self) -> embedded_hal::digital::ErrorKind {
embedded_hal::digital::ErrorKind::Other
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum DynPinModeEmio {
Output,
Input,
}
pub struct EmioPin {
regs: MmioGpio<'static>,
mode: DynPinModeEmio,
offset: usize,
}
impl EmioPin {
/// Unsafely steal an EMIO input pin.
///
/// Unless you have no other option, it is recommended to use the [EmioPins::take] method
/// to retrieve the pins safely. Returns [None] if the offset is larger than 63.
///
/// # Safety
///
/// This allows potentially creating multiple input pin structures for the same GPIO
/// peripheral which can cause data races.
#[inline]
pub const unsafe fn steal(offset: usize) -> Option<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) {
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()
/// This offset ranges from 0 to 64.
pub fn offset(&self) -> usize {
self.offset
}
}
impl embedded_hal::digital::ErrorType for EmioPin {
type Error = InvalidPinModeEmio;
}
impl embedded_hal::digital::InputPin for EmioPin {
#[inline]
fn is_high(&mut self) -> Result<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 {
pub struct Pins {
emios: [Option<EmioPin>; 64],
}
impl EmioPins {
impl Pins {
/// Create a new EMIO pin structure.
///
/// This structure is supposed to be used as a singleton. It will configure all
@ -270,12 +31,7 @@ impl EmioPins {
mmio.bank_3().write_dirm(0);
(0..64).for_each(|i| {
let mmio = unsafe { Gpio::new_mmio_fixed() };
emios[i] = Some(EmioPin {
regs: mmio,
mode: DynPinModeEmio::Input,
offset: i,
});
emios[i] = Some(EmioPin { offset: i });
});
Self { emios }
}

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.
//!
//! This module provides a type-state API for all MIO pins. This also allows associating
//! the pins, their modes and their IDs to the peripherals they are able to serve.
//!
//! The pins can be type-erased for easier handling, which also incurs some more run-time checks.
//!
//! # Examples
//!
//! - [Blinky](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/examples/simple/src/main.rs)
//! - [Logger example](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/examples/simple/src/bin/logger.rs)
//! which uses MIO pins for the UART.
use embedded_hal::digital::InputPin;
//! This module provides a [singleton][Pins] for the resource management of all MIO pins. This
//! also allows associating the pins, their modes and their IDs to the peripherals they are able to
//! serve.
use arbitrary_int::{u2, u3};
use zynq7000::gpio::MmioGpio;
use crate::sealed;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct MuxConf {
l3: u3,
l2: u2,
l1: bool,
l0: bool,
}
use super::{DynMioPin, DynPinModeMio, MioPinProvider, MuxConf, PinIsOutputOnly, PinState};
impl From<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 {}
pub trait InputMode: sealed::Sealed {}
impl MuxConf {
#[inline]
pub const fn new(l0: bool, l1: bool, l2: u2, l3: u3) -> Self {
Self { l3, l2, l1, l0 }
}
pub struct Output;
pub const fn new_with_l3(l3: u3) -> Self {
Self::new(false, false, u2::new(0b00), l3)
}
impl PinMode for Output {}
impl sealed::Sealed for Output {}
pub const fn new_for_gpio() -> Self {
Self::new(false, false, u2::new(0), u3::new(0))
}
pub struct Input<S: InputMode>(core::marker::PhantomData<S>);
#[inline]
pub const fn l0_sel(&self) -> bool {
self.l0
}
impl<S: InputMode> PinMode for Input<S> {}
impl<S: InputMode> sealed::Sealed for Input<S> {}
#[inline]
pub const fn l1_sel(&self) -> bool {
self.l1
}
pub struct PullUp;
pub struct Floating;
#[inline]
pub const fn l2_sel(&self) -> u2 {
self.l2
}
impl InputMode for PullUp {}
impl sealed::Sealed for PullUp {}
impl InputMode for Floating {}
impl sealed::Sealed for Floating {}
pub struct IoPeriph;
impl sealed::Sealed for IoPeriph {}
impl PinMode for IoPeriph {}
pub type Reset = Input<PullUp>;
#[inline]
pub const fn l3_sel(&self) -> u3 {
self.l3
}
}
pub trait PinId {
const OFFSET: usize;
@ -141,29 +157,19 @@ pin_id!(Mio51, 51);
pin_id!(Mio52, 52);
pin_id!(Mio53, 53);
pub struct MioPin<I: PinId, S: PinMode> {
inner: DynMioPin,
phantom: core::marker::PhantomData<(I, S)>,
pub trait MioPinMarker {
fn offset(&self) -> usize;
}
pub trait IoPeriphPin {
fn mux_conf(&self) -> MuxConf;
pub struct Pin<I: PinId> {
phantom: core::marker::PhantomData<I>,
}
impl<I: PinId, M: PinMode> MioPinProvider for MioPin<I, M> {
delegate::delegate! {
to self.inner {
fn mode(&self) -> &DynPinModeMio;
fn offset(&self) -> usize;
}
}
}
impl<I: PinId, S: PinMode> MioPin<I, S> {
impl<I: PinId> Pin<I> {
#[inline]
const unsafe fn new() -> Self {
Self {
inner: DynMioPin::new(I::OFFSET, DynPinModeMio::InputPullUp),
//pin: LowLevelPin::new(I::OFFSET),
phantom: core::marker::PhantomData,
}
}
@ -184,292 +190,175 @@ impl<I: PinId, S: PinMode> MioPin<I, S> {
pub const unsafe fn steal() -> Self {
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> {
self.inner.into_input_floating()?;
Ok(self.into_mode())
}
pub fn into_pull_up_input(mut self) -> Result<MioPin<I, Input<PullUp>>, PinIsOutputOnly> {
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();
}
pub struct Pins {
pub mio0: Pin<Mio0>,
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>,
#[inline]
pub fn set_low(&mut self) {
self.inner.set_low_unchecked();
}
#[inline]
pub fn is_set_high(&self) {
self.inner.is_set_high_unchecked();
}
#[inline]
pub fn is_set_low(&self) {
self.inner.is_set_low_unchecked();
}
pub mio32: Pin<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>,
}
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 {
impl Pins {
pub const fn new(_mmio: MmioGpio) -> Self {
Self {
mio0: unsafe { MioPin::new() },
mio1: unsafe { MioPin::new() },
mio2: unsafe { MioPin::new() },
mio3: unsafe { MioPin::new() },
mio4: unsafe { MioPin::new() },
mio5: unsafe { MioPin::new() },
mio6: unsafe { MioPin::new() },
mio7: unsafe { MioPin::new() },
mio8: unsafe { MioPin::new() },
mio9: unsafe { MioPin::new() },
mio10: unsafe { MioPin::new() },
mio11: unsafe { MioPin::new() },
mio12: unsafe { MioPin::new() },
mio13: unsafe { MioPin::new() },
mio14: unsafe { MioPin::new() },
mio15: unsafe { MioPin::new() },
mio0: unsafe { Pin::new() },
mio1: unsafe { Pin::new() },
mio2: unsafe { Pin::new() },
mio3: unsafe { Pin::new() },
mio4: unsafe { Pin::new() },
mio5: unsafe { Pin::new() },
mio6: unsafe { Pin::new() },
mio7: unsafe { Pin::new() },
mio8: unsafe { Pin::new() },
mio9: unsafe { Pin::new() },
mio10: unsafe { Pin::new() },
mio11: unsafe { Pin::new() },
mio12: unsafe { Pin::new() },
mio13: unsafe { Pin::new() },
mio14: unsafe { Pin::new() },
mio15: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio16: unsafe { MioPin::new() },
mio16: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio17: unsafe { MioPin::new() },
mio17: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio18: unsafe { MioPin::new() },
mio18: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio19: unsafe { MioPin::new() },
mio19: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio20: unsafe { MioPin::new() },
mio20: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio21: unsafe { MioPin::new() },
mio21: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio22: unsafe { MioPin::new() },
mio22: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio23: unsafe { MioPin::new() },
mio23: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio24: unsafe { MioPin::new() },
mio24: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio25: unsafe { MioPin::new() },
mio25: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio26: unsafe { MioPin::new() },
mio26: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio27: unsafe { MioPin::new() },
mio28: unsafe { MioPin::new() },
mio29: unsafe { MioPin::new() },
mio30: unsafe { MioPin::new() },
mio31: unsafe { MioPin::new() },
mio27: unsafe { Pin::new() },
mio28: unsafe { Pin::new() },
mio29: unsafe { Pin::new() },
mio30: unsafe { Pin::new() },
mio31: unsafe { Pin::new() },
mio32: unsafe { MioPin::new() },
mio33: unsafe { MioPin::new() },
mio34: unsafe { MioPin::new() },
mio35: unsafe { MioPin::new() },
mio36: unsafe { MioPin::new() },
mio37: unsafe { MioPin::new() },
mio38: unsafe { MioPin::new() },
mio39: unsafe { MioPin::new() },
mio32: unsafe { Pin::new() },
mio33: unsafe { Pin::new() },
mio34: unsafe { Pin::new() },
mio35: unsafe { Pin::new() },
mio36: unsafe { Pin::new() },
mio37: unsafe { Pin::new() },
mio38: unsafe { Pin::new() },
mio39: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio40: unsafe { MioPin::new() },
mio40: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio41: unsafe { MioPin::new() },
mio41: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio42: unsafe { MioPin::new() },
mio42: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio43: unsafe { MioPin::new() },
mio43: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio44: unsafe { MioPin::new() },
mio44: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio45: unsafe { MioPin::new() },
mio45: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio46: unsafe { MioPin::new() },
mio46: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio47: unsafe { MioPin::new() },
mio48: unsafe { MioPin::new() },
mio49: unsafe { MioPin::new() },
mio47: unsafe { Pin::new() },
mio48: unsafe { Pin::new() },
mio49: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio50: unsafe { MioPin::new() },
mio50: unsafe { Pin::new() },
#[cfg(not(feature = "7z010-7z007s-clg225"))]
mio51: unsafe { MioPin::new() },
mio52: unsafe { MioPin::new() },
mio53: unsafe { MioPin::new() },
mio51: unsafe { Pin::new() },
mio52: unsafe { Pin::new() },
mio53: unsafe { Pin::new() },
}
}
}
impl<I: PinId, M: PinMode> embedded_hal::digital::ErrorType for MioPin<I, M> {
type Error = core::convert::Infallible;
}
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())
impl<I: PinId> MioPinMarker for Pin<I> {
fn offset(&self) -> usize {
I::OFFSET
}
}

View File

@ -1,27 +1,42 @@
//! GPIO support module for the Zynq7000 SoC.
pub mod dyn_mio;
//!
//! This module contains a MIO and EMIO pin resource managements singleton as well as abstractions
//! to use these pins as GPIOs.
//!
//! # Examples
//!
//! - [Blinky](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/examples/simple/src/main.rs)
//! - [Logger example](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/examples/simple/src/bin/logger.rs)
//! which uses MIO pins for the UART.
pub mod emio;
pub mod ll;
pub mod mio;
use crate::{enable_amba_peripheral_clock, slcr::Slcr};
pub use dyn_mio::*;
pub use emio::*;
pub use mio::*;
use core::convert::Infallible;
use ll::PinOffset;
use mio::{MioPinMarker, MuxConf};
use crate::gpio::ll::LowLevelGpio;
use crate::{enable_amba_peripheral_clock, slcr::Slcr};
pub use embedded_hal::digital::PinState;
use zynq7000::{gpio::MmioGpio, slcr::reset::GpioClockReset};
#[derive(Debug, thiserror::Error)]
#[error("MIO pins 7 and 8 can only be output pins")]
pub struct PinIsOutputOnly;
/// GPIO pin singleton to allow resource management of both MIO and EMIO pins.
pub struct GpioPins {
pub mio: MioPins,
pub emio: EmioPins,
pub mio: mio::Pins,
pub emio: emio::Pins,
}
impl GpioPins {
pub fn new(gpio: MmioGpio) -> Self {
enable_amba_peripheral_clock(crate::PeripheralSelect::Gpio);
Self {
mio: MioPins::new(unsafe { gpio.clone() }),
emio: EmioPins::new(gpio),
mio: mio::Pins::new(unsafe { gpio.clone() }),
emio: emio::Pins::new(gpio),
}
}
}
@ -40,3 +55,352 @@ pub fn reset() {
});
}
}
/// Enumeration of all pin modes. Some of the modes are only valid for MIO pins.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum PinMode {
OutputPushPull,
/// See [super::gpio] documentation for more information on running an output pin in
/// open-drain configuration.
OutputOpenDrain,
InputFloating,
InputPullUp,
/// MIO-only peripheral pin configuration
MioIoPeriph(MuxConf),
}
#[derive(Debug, thiserror::Error)]
#[error("invalid pin mode for MIO pin: {0:?}")]
pub struct InvalidPinMode(pub PinMode);
impl embedded_hal::digital::Error for InvalidPinMode {
fn kind(&self) -> embedded_hal::digital::ErrorKind {
embedded_hal::digital::ErrorKind::Other
}
}
pub trait IoPinProvider {
fn mode(&self) -> PinMode;
fn offset(&self) -> PinOffset;
#[inline]
fn is_input(&self) -> bool {
matches!(self.mode(), PinMode::InputFloating | PinMode::InputPullUp)
}
#[inline]
fn is_output(&self) -> bool {
matches!(
self.mode(),
PinMode::OutputPushPull | PinMode::OutputOpenDrain
)
}
#[inline]
fn is_io_periph(&self) -> bool {
matches!(self.mode(), PinMode::MioIoPeriph(_))
}
}
/// Flex pin abstraction which can be dynamically re-configured.
///
/// The following functions can be configured at run-time:
///
/// - Input Floating
/// - Input with Pull-Up
/// - Output Push-Pull
/// - Output Open-Drain.
///
/// Flex pins are always floating input pins after construction except for MIO7 and MIO8,
/// which are Push-Pull Output pins with initial low-level.
///
/// ## Notes on [PinMode::OutputOpenDrain] configuration
///
/// For MIO, the open-drain functionality is simulated by only enabling the output driver
/// when driving the pin low, and leaving the pin floating when the pin is driven high.
/// The internal pull-up will also be enabled to have a high state if the pin is not driven.
///
/// For EMIO, the pull-up and the IO buffer needs to be provided in the FPGA design for the
/// used EMIO pins because the EMIO pins are just wires going out to the FPGA design.
/// The software will still perform the necessary logic when driving the pin low or high.
///
/// ## Notes on [PinMode::InputPullUp] configuration
///
/// For EMIO, the pull-up wiring needs to be provided by the FPGA design.
pub struct Flex {
ll: LowLevelGpio,
mode: PinMode,
}
impl Flex {
pub fn new_for_mio<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"))]
use crate::gpio::{
use crate::gpio::mio::{
Mio16, Mio17, Mio18, Mio19, Mio20, Mio21, Mio22, Mio23, Mio24, Mio25, Mio26, Mio27, Mio40,
Mio41, Mio42, Mio43, Mio44, Mio45, Mio46, Mio47, Mio50, Mio51,
};
use crate::{
enable_amba_peripheral_clock,
gpio::{
IoPeriph, IoPeriphPin, Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, Mio30,
Mio31, Mio32, Mio33, Mio34, Mio35, Mio36, Mio37, Mio38, Mio39, Mio48, Mio49, Mio52, Mio53,
MioPin, MuxConf, PinMode,
IoPeriphPin,
mio::{
Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, Mio30, Mio31, Mio32, Mio33,
Mio34, Mio35, Mio36, Mio37, Mio38, Mio39, Mio48, Mio49, Mio52, Mio53, MioPinMarker,
MuxConf, Pin,
},
},
slcr::Slcr,
time::Hertz,
@ -55,16 +58,31 @@ impl PsI2c for MmioI2c<'static> {
}
}
pub trait SdaPin: IoPeriphPin {
pub trait SdaPin: MioPinMarker {
const ID: I2cId;
}
pub trait SckPin: IoPeriphPin {
pub trait SckPin: MioPinMarker {
const ID: I2cId;
}
pub trait I2cPins {}
macro_rules! i2c_pin_impls {
($Id: path, $SckMio:ident, $SdaMio:ident) => {
impl SckPin for Pin<$SckMio> {
const ID: I2cId = $Id;
}
impl SdaPin for Pin<$SdaMio> {
const ID: I2cId = $Id;
}
impl I2cPins for (Pin<$SckMio>, Pin<$SdaMio>) {}
};
}
/*
macro_rules! into_i2c {
($($Mio:ident),+) => {
$(
@ -80,20 +98,6 @@ macro_rules! into_i2c {
};
}
macro_rules! i2c_pin_impls {
($Id: path, $SckMio:ident, $SdaMio:ident) => {
impl SckPin for MioPin<$SckMio, IoPeriph> {
const ID: I2cId = $Id;
}
impl SdaPin for MioPin<$SdaMio, IoPeriph> {
const ID: I2cId = $Id;
}
impl I2cPins for (MioPin<$SckMio, IoPeriph>, MioPin<$SdaMio, IoPeriph>) {}
};
}
into_i2c!(
Mio10, Mio11, Mio14, Mio15, Mio30, Mio31, Mio34, Mio35, Mio38, Mio39, Mio12, Mio13, Mio28,
Mio29, Mio32, Mio33, Mio36, Mio37, Mio48, Mio49, Mio52, Mio53
@ -103,6 +107,7 @@ into_i2c!(
Mio18, Mio19, Mio22, Mio23, Mio26, Mio27, Mio42, Mio43, Mio46, Mio47, Mio50, Mio51, Mio16,
Mio17, Mio20, Mio21, Mio24, Mio25, Mio40, Mio41, Mio44, Mio45
);
*/
i2c_pin_impls!(I2cId::I2c0, Mio10, Mio11);
i2c_pin_impls!(I2cId::I2c0, Mio14, Mio15);
@ -318,9 +323,8 @@ impl I2c {
if Sck::ID != Sda::ID {
return Err(I2cConstructionError::PinInvalidForI2cId);
}
if i2c_pins.0.mux_conf() != I2C_MUX_CONF || i2c_pins.1.mux_conf() != I2C_MUX_CONF {
return Err(I2cConstructionError::InvalidPinConf);
}
IoPeriphPin::new(i2c_pins.0, I2C_MUX_CONF, Some(true));
IoPeriphPin::new(i2c_pins.1, I2C_MUX_CONF, Some(true));
Ok(Self::new_generic(
i2c.id().unwrap(),
i2c.reg_block(),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
//! SPI register module.
use arbitrary_int::{u4, Number};
use arbitrary_int::{Number, u4};
pub const SPI_0_BASE_ADDR: usize = 0xE000_6000;
pub const SPI_1_BASE_ADDR: usize = 0xE000_7000;
@ -140,7 +140,7 @@ impl FifoWrite {
}
#[inline]
pub fn write(&mut self, value:u8) {
pub fn write(&mut self, value: u8) {
self.0 = value.into();
}
}