Compare commits

..

2 Commits

Author SHA1 Message Date
90423f6fee
add TTC driver 2025-04-01 10:59:23 +02:00
198e17c134
move AXI UART drivers to separate crates 2025-03-31 19:52:19 +02:00
7 changed files with 53 additions and 376 deletions

View File

@ -13,9 +13,9 @@ use crate::gpio::{
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,
IoPeriph, 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,
},
slcr::Slcr,
time::Hertz,
@ -55,11 +55,11 @@ impl PsI2c for MmioI2c<'static> {
}
}
pub trait SdaPin: IoPeriphPin {
pub trait SdaPin {
const ID: I2cId;
}
pub trait SckPin: IoPeriphPin {
pub trait SckPin {
const ID: I2cId;
}
@ -291,16 +291,14 @@ impl ClockConfig {
#[derive(Debug, thiserror::Error)]
#[error("invalid I2C ID")]
pub struct InvalidPsI2cError;
pub struct InvalidI2cIdError;
#[derive(Debug, thiserror::Error)]
pub enum I2cConstructionError {
#[error("invalid I2C ID {0}")]
InvalidPsI2c(#[from] InvalidPsI2cError),
InvalidI2cId(#[from] InvalidI2cIdError),
#[error("pin invalid for I2C ID")]
PinInvalidForI2cId,
#[error("invalid pin configuration for I2C")]
InvalidPinConf,
}
pub struct I2c {
regs: MmioI2c<'static>,
@ -310,17 +308,14 @@ impl I2c {
pub fn new_with_mio<Sck: SckPin, Sda: SdaPin>(
i2c: impl PsI2c,
clk_cfg: ClockConfig,
i2c_pins: (Sck, Sda),
_i2c_pins: (Sck, Sda),
) -> Result<Self, I2cConstructionError> {
if i2c.id().is_none() {
return Err(InvalidPsI2cError.into());
return Err(InvalidI2cIdError.into());
}
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);
}
Ok(Self::new_generic(
i2c.id().unwrap(),
i2c.reg_block(),
@ -328,9 +323,9 @@ impl I2c {
))
}
pub fn new_with_emio(i2c: impl PsI2c, clk_cfg: ClockConfig) -> Result<Self, InvalidPsI2cError> {
pub fn new_with_emio(i2c: impl PsI2c, clk_cfg: ClockConfig) -> Result<Self, InvalidI2cIdError> {
if i2c.id().is_none() {
return Err(InvalidPsI2cError);
return Err(InvalidI2cIdError);
}
Ok(Self::new_generic(
i2c.id().unwrap(),

View File

@ -22,8 +22,8 @@ pub mod prelude;
pub mod slcr;
pub mod spi;
pub mod time;
pub mod ttc;
pub mod uart;
pub mod ttc;
/// This enumeration encodes the various boot sources.
#[derive(Debug, Copy, Clone)]

View File

@ -3,8 +3,8 @@ 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,
IoPeriph, Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, Mio30, Mio31, Mio32, Mio33,
Mio34, Mio35, Mio36, Mio37, Mio38, Mio39, MioPin, MuxConf,
};
#[cfg(not(feature = "7z010-7z007s-clg225"))]
use crate::gpio::{
@ -54,22 +54,22 @@ impl PsSpi for MmioSpi<'static> {
}
}
pub trait SckPin: IoPeriphPin {
pub trait SckPin {
const SPI: SpiId;
const GROUP: usize;
}
pub trait MosiPin: IoPeriphPin {
pub trait MosiPin {
const SPI: SpiId;
const GROUP: usize;
}
pub trait MisoPin: IoPeriphPin {
pub trait MisoPin {
const SPI: SpiId;
const GROUP: usize;
}
pub trait SsPin: IoPeriphPin {
pub trait SsPin {
const IDX: usize;
const SPI: SpiId;
const GROUP: usize;
@ -413,21 +413,18 @@ pub struct Spi {
#[derive(Debug, thiserror::Error)]
#[error("invalid SPI ID")]
pub struct InvalidPsSpiError;
pub struct InvalidSpiIdError;
// TODO: Add and handle MUX config check.
#[derive(Debug, thiserror::Error)]
pub enum SpiConstructionError {
#[error("invalid SPI ID {0}")]
InvalidPsSpi(#[from] InvalidPsSpiError),
InvalidSpiId(#[from] InvalidSpiIdError),
/// The specified pins are not compatible to the specified SPI peripheral.
#[error("pin invalid for SPI ID")]
PinInvalidForSpiId,
/// The specified pins are not from the same pin group.
#[error("pin group missmatch")]
GroupMissmatch,
#[error("invalid pin configuration for SPI")]
InvalidPinConf,
}
impl Spi {
@ -435,11 +432,11 @@ impl Spi {
spi: impl PsSpi,
clocks: &IoClocks,
config: Config,
spi_pins: (Sck, Mosi, Miso),
_spi_pins: (Sck, Mosi, Miso),
) -> Result<Self, SpiConstructionError> {
let spi_id = spi.id();
if spi_id.is_none() {
return Err(InvalidPsSpiError.into());
return Err(InvalidSpiIdError.into());
}
let spi_id = spi_id.unwrap();
if Sck::GROUP != Mosi::GROUP || Sck::GROUP != Miso::GROUP {
@ -448,12 +445,6 @@ 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);
}
Ok(Self::new_generic_unchecked(
spi_id,
spi.reg_block(),
@ -466,12 +457,12 @@ impl Spi {
spi: impl PsSpi,
clocks: &IoClocks,
config: Config,
spi_pins: (Sck, Mosi, Miso),
ss_pin: Ss,
_spi_pins: (Sck, Mosi, Miso),
_ss_pin: Ss,
) -> Result<Self, SpiConstructionError> {
let spi_id = spi.id();
if spi_id.is_none() {
return Err(InvalidPsSpiError.into());
return Err(InvalidSpiIdError.into());
}
let spi_id = spi_id.unwrap();
if Sck::GROUP != Mosi::GROUP || Sck::GROUP != Miso::GROUP || Sck::GROUP != Ss::GROUP {
@ -480,13 +471,6 @@ 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);
}
Ok(Self::new_generic_unchecked(
spi_id,
spi.reg_block(),
@ -499,12 +483,12 @@ impl Spi {
spi: impl PsSpi,
clocks: &IoClocks,
config: Config,
spi_pins: (Sck, Mosi, Miso),
ss_pins: (Ss0, Ss1),
_spi_pins: (Sck, Mosi, Miso),
_ss_pins: (Ss0, Ss1),
) -> Result<Self, SpiConstructionError> {
let spi_id = spi.id();
if spi_id.is_none() {
return Err(InvalidPsSpiError.into());
return Err(InvalidSpiIdError.into());
}
let spi_id = spi_id.unwrap();
if Sck::GROUP != Mosi::GROUP
@ -522,14 +506,6 @@ 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);
}
Ok(Self::new_generic_unchecked(
spi_id,
spi.reg_block(),
@ -549,12 +525,12 @@ impl Spi {
spi: impl PsSpi,
clocks: &IoClocks,
config: Config,
spi_pins: (Sck, Mosi, Miso),
ss_pins: (Ss0, Ss1, Ss2),
_spi_pins: (Sck, Mosi, Miso),
_ss_pins: (Ss0, Ss1, Ss2),
) -> Result<Self, SpiConstructionError> {
let spi_id = spi.id();
if spi_id.is_none() {
return Err(InvalidPsSpiError.into());
return Err(InvalidSpiIdError.into());
}
let spi_id = spi_id.unwrap();
if Sck::GROUP != Mosi::GROUP
@ -574,15 +550,6 @@ 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);
}
Ok(Self::new_generic_unchecked(
spi_id,
spi.reg_block(),

View File

@ -1,17 +1,10 @@
//! Triple-timer counter (TTC) high-level driver.
use core::convert::Infallible;
use arbitrary_int::{u3, u4};
use zynq7000::ttc::{MmioTtc, TTC_0_BASE_ADDR, TTC_1_BASE_ADDR};
use arbitrary_int::u3;
use crate::gpio::{IoPeriph, Mio30, Mio31, MioPin, MuxConf, PinMode};
#[cfg(not(feature = "7z010-7z007s-clg225"))]
use crate::gpio::{Mio16, Mio17, Mio18, Mio19, Mio40, Mio41, Mio42, Mio43};
use crate::{
clocks::ArmClocks,
gpio::{IoPeriph, IoPeriphPin, Mio28, Mio29, Mio30, Mio31, MioPin, MuxConf, PinMode},
time::Hertz,
};
use crate::gpio::{Mio18, Mio19, Mio42, Mio43};
/// Each TTC consists of three independent timers/counters.
#[derive(Debug, Copy, Clone)]
@ -20,43 +13,13 @@ pub enum TtcId {
Ttc1 = 1,
}
#[derive(Debug, Copy, Clone)]
pub enum ChannelId {
Ch0 = 0,
Ch1 = 1,
Ch2 = 2,
}
pub trait PsTtc {
fn reg_block(&self) -> MmioTtc<'static>;
fn id(&self) -> Option<TtcId>;
}
impl PsTtc for MmioTtc<'static> {
#[inline]
fn reg_block(&self) -> MmioTtc<'static> {
unsafe { self.clone() }
}
#[inline]
fn id(&self) -> Option<TtcId> {
let base_addr = unsafe { self.ptr() } as usize;
if base_addr == TTC_0_BASE_ADDR {
return Some(TtcId::Ttc0);
} else if base_addr == TTC_1_BASE_ADDR {
return Some(TtcId::Ttc1);
}
None
}
}
pub const TTC_MUX_CONF: MuxConf = MuxConf::new_with_l3(u3::new(0b110));
pub trait ClockInPin: IoPeriphPin {
pub trait ClockInPin {
const ID: TtcId;
}
pub trait WaveOutPin: IoPeriphPin {
pub trait WaveOutPin {
const ID: TtcId;
}
@ -67,6 +30,7 @@ macro_rules! into_ttc {
/// 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)
}
}
@ -75,223 +39,7 @@ macro_rules! into_ttc {
}
#[cfg(not(feature = "7z010-7z007s-clg225"))]
into_ttc!(Mio16, Mio17, Mio18, Mio19, Mio40, Mio41, Mio42, Mio43);
into_ttc!(Mio28, Mio29, Mio30, Mio31);
into_ttc!(Mio18, Mio19, Mio42, Mio43);
into_ttc!(Mio30, Mio31);
pub struct Ttc {
pub ch0: TtcChannel,
pub ch1: TtcChannel,
pub ch2: TtcChannel,
}
impl Ttc {
/// Create a new TTC instance. The passed TTC peripheral instance MUST point to a valid
/// processing system TTC peripheral.
pub fn new(ps_ttc: impl PsTtc) -> Option<Self> {
ps_ttc.id()?;
let regs = ps_ttc.reg_block();
let ch0 = TtcChannel {
regs: unsafe { regs.clone() },
id: ChannelId::Ch0,
};
let ch1 = TtcChannel {
regs: unsafe { regs.clone() },
id: ChannelId::Ch1,
};
let ch2 = TtcChannel {
regs,
id: ChannelId::Ch2,
};
Some(Self { ch0, ch1, ch2 })
}
}
pub struct TtcChannel {
regs: MmioTtc<'static>,
id: ChannelId,
}
impl TtcChannel {
pub fn regs_mut(&mut self) -> &mut MmioTtc<'static> {
&mut self.regs
}
pub fn id(&self) -> ChannelId {
self.id
}
}
#[derive(Debug, thiserror::Error)]
#[error("invalid TTC pin configuration")]
pub struct InvalidTtcPinConfigError(pub MuxConf);
#[derive(Debug, thiserror::Error)]
#[error("frequency is zero")]
pub struct FrequencyIsZeroError;
#[derive(Debug, thiserror::Error)]
pub enum TtcConstructionError {
#[error("invalid TTC pin configuration")]
InvalidTtcPinConfig(#[from] InvalidTtcPinConfigError),
#[error("frequency is zero")]
FrequencyIsZero(#[from] FrequencyIsZeroError),
}
pub fn calculate_prescaler_reg_and_interval_ticks(mut ref_clk: Hertz, freq: Hertz) -> (u4, u16) {
// TODO: Can this be optimized?
let mut prescaler_reg = 0;
let mut tick_val = ref_clk / freq;
while tick_val > u16::MAX as u32 {
ref_clk /= 2;
prescaler_reg += 1;
tick_val = ref_clk / freq;
}
(u4::new(prescaler_reg), tick_val as u16)
}
pub struct Pwm {
channel: TtcChannel,
ref_clk: Hertz,
}
impl Pwm {
/// Create a new PWM instance which uses the CPU 1x clock as the clock source.
pub fn new_with_mio_wave_out(
channel: TtcChannel,
arm_clocks: &ArmClocks,
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());
}
if freq.raw() == 0 {
return Err(FrequencyIsZeroError.into());
}
let (prescaler_reg, tick_val) =
calculate_prescaler_reg_and_interval_ticks(arm_clocks.cpu_1x_clk(), freq);
let id = channel.id() as usize;
let mut pwm = Self {
channel,
ref_clk: arm_clocks.cpu_1x_clk(),
};
pwm.set_up_and_configure_pwm(id, prescaler_reg, tick_val);
Ok(pwm)
}
/// Set a new frequency for the PWM cycle.
///
/// This resets the duty cycle to 0%.
pub fn set_frequency(&mut self, freq: Hertz) -> Result<(), FrequencyIsZeroError> {
if freq.raw() == 0 {
return Err(FrequencyIsZeroError);
}
let id = self.channel.id() as usize;
let (prescaler_reg, tick_val) =
calculate_prescaler_reg_and_interval_ticks(self.ref_clk, freq);
self.set_up_and_configure_pwm(id, prescaler_reg, tick_val);
Ok(())
}
#[inline]
pub fn max_duty_cycle(&self) -> u16 {
self.channel
.regs
.read_interval_value(self.channel.id() as usize)
.unwrap()
.value()
}
#[inline]
pub fn set_duty_cycle(&mut self, duty: u16) {
let id = self.channel.id() as usize;
self.channel
.regs
.modify_cnt_ctrl(id, |mut val| {
val.set_disable(true);
val
})
.unwrap();
self.channel
.regs
.write_match_value_0(
self.channel.id() as usize,
zynq7000::ttc::RwValue::new_with_raw_value(duty as u32),
)
.unwrap();
self.channel
.regs
.modify_cnt_ctrl(id, |mut val| {
val.set_disable(false);
val.set_reset(true);
val
})
.unwrap();
}
fn set_up_and_configure_pwm(&mut self, id: usize, prescaler_reg: u4, tick_val: u16) {
// Disable the counter first.
self.channel
.regs
.write_cnt_ctrl(id, zynq7000::ttc::CounterControl::new_with_raw_value(1))
.unwrap();
// Clock configuration
self.channel
.regs
.write_clk_cntr(
id,
zynq7000::ttc::ClockControl::builder()
.with_ext_clk_edge(false)
.with_clk_src(zynq7000::ttc::ClockSource::Pclk)
.with_prescaler(prescaler_reg)
.with_prescale_enable(prescaler_reg.value() > 0)
.build(),
)
.unwrap();
self.channel
.regs
.write_interval_value(
id,
zynq7000::ttc::RwValue::new_with_raw_value(tick_val as u32),
)
.unwrap();
// Corresponds to duty cycle 0.
self.channel
.regs
.write_match_value_0(id, zynq7000::ttc::RwValue::new_with_raw_value(0))
.unwrap();
self.channel
.regs
.write_cnt_ctrl(
id,
zynq7000::ttc::CounterControl::builder()
.with_wave_polarity(zynq7000::ttc::WavePolarity::HighToLowOnMatch1)
.with_wave_enable_n(zynq7000::ttc::WaveEnable::Enable)
.with_reset(true)
.with_match_enable(false)
.with_decrementing(false)
.with_mode(zynq7000::ttc::Mode::Interval)
.with_disable(false)
.build(),
)
.unwrap();
}
}
impl embedded_hal::pwm::ErrorType for Pwm {
type Error = Infallible;
}
impl embedded_hal::pwm::SetDutyCycle for Pwm {
#[inline]
fn max_duty_cycle(&self) -> u16 {
self.max_duty_cycle()
}
#[inline]
fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
self.set_duty_cycle(duty);
Ok(())
}
}
pub struct Pwm {}

View File

@ -99,6 +99,7 @@ pub trait UartPins {}
#[error("divisor is zero")]
pub struct DivisorZero;
/// TODO: Integrate into macro.
macro_rules! pin_pairs {
($UartPeriph:path, ($( [$(#[$meta:meta], )? $TxMio:ident, $RxMio:ident] ),+ $(,)? )) => {
$(
@ -423,12 +424,12 @@ pub struct Uart {
#[derive(Debug, thiserror::Error)]
#[error("invalid UART ID")]
pub struct InvalidPsUart;
pub struct InvalidUartIdError;
#[derive(Debug, thiserror::Error)]
pub enum UartConstructionError {
#[error("invalid UART ID")]
InvalidPsUart(#[from] InvalidPsUart),
#[error("invalid UART ID: {0}")]
InvalidUartId(#[from] InvalidUartIdError),
#[error("missmatch between pins index and passed index")]
IdxMissmatch,
#[error("invalid pin mux conf for UART")]
@ -441,9 +442,9 @@ impl Uart {
///
/// A valid PL design which routes the UART pins through into the PL must be used for this to
/// work.
pub fn new_with_emio(uart: impl PsUart, cfg: UartConfig) -> Result<Uart, InvalidPsUart> {
pub fn new_with_emio(uart: impl PsUart, cfg: UartConfig) -> Result<Uart, InvalidUartIdError> {
if uart.uart_id().is_none() {
return Err(InvalidPsUart);
return Err(InvalidUartIdError);
}
Ok(Self::new_generic_unchecked(
uart.reg_block(),
@ -463,7 +464,7 @@ impl Uart {
{
let id = uart.uart_id();
if id.is_none() {
return Err(InvalidPsUart.into());
return Err(InvalidUartIdError.into());
}
if id.unwrap() != TxPinI::UART_IDX || id.unwrap() != RxPinI::UART_IDX {
return Err(UartConstructionError::IdxMissmatch);

View File

@ -22,8 +22,8 @@ pub mod i2c;
pub mod mpcore;
pub mod slcr;
pub mod spi;
pub mod ttc;
pub mod uart;
pub mod ttc;
static PERIPHERALS_TAKEN: AtomicBool = AtomicBool::new(false);
@ -44,8 +44,6 @@ pub struct PsPeripherals {
pub gtc: gtc::MmioGtc<'static>,
pub gpio: gpio::MmioGpio<'static>,
pub slcr: slcr::MmioSlcr<'static>,
pub ttc_0: ttc::MmioTtc<'static>,
pub ttc_1: ttc::MmioTtc<'static>,
}
impl PsPeripherals {
@ -77,8 +75,6 @@ impl PsPeripherals {
spi_1: spi::Spi::new_mmio_fixed_1(),
i2c_0: i2c::I2c::new_mmio_fixed_0(),
i2c_1: i2c::I2c::new_mmio_fixed_1(),
ttc_0: ttc::Ttc::new_mmio_fixed_0(),
ttc_1: ttc::Ttc::new_mmio_fixed_1(),
}
}
}

View File

@ -1,17 +1,13 @@
//! Triple-timer counter (TTC) register module.
use arbitrary_int::u4;
pub const TTC_0_BASE_ADDR: usize = 0xF800_1004;
pub const TTC_1_BASE_ADDR: usize = 0xF800_2004;
#[bitbybit::bitenum(u1, exhaustive = true)]
pub enum ClockSource {
/// PS internal bus clock.
Pclk = 0b0,
External = 0b1,
Extewrnal = 0b1,
}
#[bitbybit::bitfield(u32, default = 0x0)]
#[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.
@ -31,12 +27,10 @@ pub enum Mode {
Interval = 0b1,
}
#[derive(Default)]
#[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.
#[default]
HighToLowOnMatch1 = 0b0,
/// The waveform output goes from low to high on a match 0 interrupt and returns low on
/// overflow or interval interrupt.
@ -49,8 +43,8 @@ pub enum WaveEnable {
Disable = 0b1,
}
#[bitbybit::bitfield(u32, default = 0x0)]
pub struct CounterControl {
#[bitbybit::bitfield(u32)]
pub struct CountControl {
#[bit(6, rw)]
wave_polarity: WavePolarity,
/// Output waveform enable, active low. Reset value 1.
@ -143,7 +137,7 @@ pub struct EventCount {
#[repr(C)]
pub struct Ttc {
clk_cntr: [ClockControl; 3],
cnt_ctrl: [CounterControl; 3],
cnt_ctrl: [CountControl; 3],
#[mmio(PureRead)]
current_counter: [Counter; 3],
interval_value: [RwValue; 3],
@ -157,27 +151,3 @@ pub struct Ttc {
#[mmio(PureRead)]
event_reg: [EventCount; 3],
}
impl Ttc {
/// Create a new TTC MMIO instance for TTC0 at address [TTC_0_BASE_ADDR].
///
/// # Safety
///
/// This API can be used to potentially create a driver to the same peripheral structure
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
/// interfere with each other.
pub const unsafe fn new_mmio_fixed_0() -> MmioTtc<'static> {
unsafe { Self::new_mmio_at(TTC_0_BASE_ADDR) }
}
/// Create a new TTC MMIO instance for TTC1 at address [TTC_1_BASE_ADDR].
///
/// # Safety
///
/// This API can be used to potentially create a driver to the same peripheral structure
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
/// interfere with each other.
pub const unsafe fn new_mmio_fixed_1() -> MmioTtc<'static> {
unsafe { Self::new_mmio_at(TTC_1_BASE_ADDR) }
}
}