diff --git a/zynq7000-hal/src/lib.rs b/zynq7000-hal/src/lib.rs index 4b6be52..2ea0b71 100644 --- a/zynq7000-hal/src/lib.rs +++ b/zynq7000-hal/src/lib.rs @@ -23,6 +23,7 @@ pub mod slcr; pub mod spi; pub mod time; pub mod uart; +pub mod ttc; /// This enumeration encodes the various boot sources. #[derive(Debug, Copy, Clone)] diff --git a/zynq7000-hal/src/ttc.rs b/zynq7000-hal/src/ttc.rs new file mode 100644 index 0000000..a192252 --- /dev/null +++ b/zynq7000-hal/src/ttc.rs @@ -0,0 +1,45 @@ +//! Triple-timer counter (TTC) high-level driver. + +use arbitrary_int::u3; + +use crate::gpio::{IoPeriph, Mio30, Mio31, MioPin, MuxConf, PinMode}; +#[cfg(not(feature = "7z010-7z007s-clg225"))] +use crate::gpio::{Mio18, Mio19, Mio42, Mio43}; + +/// Each TTC consists of three independent timers/counters. +#[derive(Debug, Copy, Clone)] +pub enum TtcId { + Ttc0 = 0, + Ttc1 = 1, +} + +pub const TTC_MUX_CONF: MuxConf = MuxConf::new_with_l3(u3::new(0b110)); + +pub trait ClockInPin { + const ID: TtcId; +} + +pub trait WaveOutPin { + const ID: TtcId; +} + +macro_rules! into_ttc { + ($($Mio:ident),+) => { + $( + impl MioPin<$Mio, M> { + /// Convert the pin into a TTC pin by configuring the pin routing via the + /// MIO multiplexer bits. + pub fn into_ttck(self) -> MioPin<$Mio, IoPeriph> { + // Enable pull-ups for the I2C pins. + self.into_io_periph(TTC_MUX_CONF, None) + } + } + )+ + }; +} + +#[cfg(not(feature = "7z010-7z007s-clg225"))] +into_ttc!(Mio18, Mio19, Mio42, Mio43); +into_ttc!(Mio30, Mio31); + +pub struct Pwm {} diff --git a/zynq7000/src/i2c.rs b/zynq7000/src/i2c.rs index 3f05b33..b06d2f8 100644 --- a/zynq7000/src/i2c.rs +++ b/zynq7000/src/i2c.rs @@ -1,3 +1,4 @@ +//! SPI register module. use arbitrary_int::{u2, u6, u10}; pub const I2C_0_BASE_ADDR: usize = 0xE000_4000; diff --git a/zynq7000/src/lib.rs b/zynq7000/src/lib.rs index fb8dc5f..faac935 100644 --- a/zynq7000/src/lib.rs +++ b/zynq7000/src/lib.rs @@ -23,6 +23,7 @@ pub mod mpcore; pub mod slcr; pub mod spi; pub mod uart; +pub mod ttc; static PERIPHERALS_TAKEN: AtomicBool = AtomicBool::new(false); diff --git a/zynq7000/src/spi.rs b/zynq7000/src/spi.rs index d87ccbf..74087fa 100644 --- a/zynq7000/src/spi.rs +++ b/zynq7000/src/spi.rs @@ -1,3 +1,4 @@ +//! SPI register module. use arbitrary_int::u4; pub const SPI_0_BASE_ADDR: usize = 0xE000_6000; diff --git a/zynq7000/src/ttc.rs b/zynq7000/src/ttc.rs new file mode 100644 index 0000000..041e0f0 --- /dev/null +++ b/zynq7000/src/ttc.rs @@ -0,0 +1,153 @@ +//! Triple-timer counter (TTC) register module. +use arbitrary_int::u4; + +#[bitbybit::bitenum(u1, exhaustive = true)] +pub enum ClockSource { + Pclk = 0b0, + Extewrnal = 0b1, +} + +#[bitbybit::bitfield(u32)] +pub struct ClockControl { + /// When this bit is set and the external clock is selected, the counter clocks on the + /// negative edge of the external clock input. + #[bit(6, rw)] + ext_clk_edge: bool, + #[bit(5, rw)] + clk_src: ClockSource, + #[bits(1..=4, rw)] + prescaler: u4, + #[bit(0, rw)] + prescale_enable: bool, +} + +#[bitbybit::bitenum(u1, exhaustive = true)] +pub enum Mode { + Overflow = 0b0, + Interval = 0b1, +} + +#[bitbybit::bitenum(u1, exhaustive = true)] +pub enum WavePolarity { + /// The waveform output goes from high to low on a match 0 interrupt and returns high on + /// overflow or interval interrupt. + HighToLowOnMatch1 = 0b0, + /// The waveform output goes from low to high on a match 0 interrupt and returns low on + /// overflow or interval interrupt. + LowToHighOnMatch1 = 0b1, +} + +#[bitbybit::bitenum(u1, exhaustive = true)] +pub enum WaveEnable { + Enable = 0b0, + Disable = 0b1, +} + +#[bitbybit::bitfield(u32)] +pub struct CountControl { + #[bit(6, rw)] + wave_polarity: WavePolarity, + /// Output waveform enable, active low. Reset value 1. + #[bit(5, rw)] + wave_enable_n: WaveEnable, + /// Resets the counter and restarts counting. Automatically cleared on restart. + #[bit(4, rw)] + reset: bool, + /// When this bit is set, an interrupt is generated when the count value matches one of the + /// three match registers and the corresponding bit is set in the IER register. + #[bit(3, rw)] + match_enable: bool, + /// When this bit is high, the timer counts down. + #[bit(2, rw)] + decrementing: bool, + #[bit(1, rw)] + mode: Mode, + #[bit(0, rw)] + disable: bool, +} + +#[bitbybit::bitfield(u32)] +pub struct Counter { + #[bits(0..=15, r)] + count: u16, +} + +#[bitbybit::bitfield(u32)] +pub struct RwValue { + #[bits(0..=15, rw)] + value: u16, +} + +#[bitbybit::bitfield(u32)] +pub struct InterruptStatus { + /// Even timer overflow interrupt. + #[bit(5, r)] + event: bool, + #[bit(4, r)] + counter_overflow: bool, + #[bit(3, r)] + match_2: bool, + #[bit(2, r)] + match_1: bool, + #[bit(1, r)] + match_0: bool, + #[bit(0, r)] + interval: bool, +} + +#[bitbybit::bitfield(u32)] +pub struct InterruptControl { + /// Even timer overflow interrupt. + #[bit(5, rw)] + event: bool, + #[bit(4, rw)] + counter_overflow: bool, + #[bit(3, rw)] + match_2: bool, + #[bit(2, rw)] + match_1: bool, + #[bit(1, rw)] + match_0: bool, + #[bit(0, rw)] + interval: bool, +} + +#[bitbybit::bitfield(u32)] +pub struct EventControl { + /// E_Ov bit. When set to 0, the event timer is disabled and set to 0 when an event timer + /// register overflow occurs. Otherwise, continue counting on overflow. + #[bit(2, rw)] + continuous_mode: bool, + /// E_Lo bit. When set to 1, counts PCLK cycles during low level duration of the external + /// clock. Otherwise, counts it during high level duration. + #[bit(1, rw)] + count_low_level_of_ext_clk: bool, + #[bit(0, rw)] + enable: bool, +} + +#[bitbybit::bitfield(u32)] +pub struct EventCount { + #[bits(0..=15, r)] + count: u16, +} + +/// Triple-timer counter +#[derive(derive_mmio::Mmio)] +#[repr(C)] +pub struct Ttc { + clk_cntr: [ClockControl; 3], + cnt_ctrl: [CountControl; 3], + #[mmio(PureRead)] + current_counter: [Counter; 3], + interval_value: [RwValue; 3], + match_value_0: [RwValue; 3], + match_value_1: [RwValue; 3], + match_value_2: [RwValue; 3], + #[mmio(Read)] + isr: [InterruptStatus; 3], + ier: [InterruptControl; 3], + event_cntrl: [EventControl; 3], + #[mmio(PureRead)] + event_reg: [EventCount; 3], +} diff --git a/zynq7000/src/uart.rs b/zynq7000/src/uart.rs index 915e009..d04b42b 100644 --- a/zynq7000/src/uart.rs +++ b/zynq7000/src/uart.rs @@ -1,4 +1,4 @@ -//! UART register module. +//! PS UART register module. use arbitrary_int::u6; pub const UART_0_BASE: usize = 0xE000_0000;