rp: update rp-pac.

This commit is contained in:
Dario Nieuwenhuis 2023-06-16 01:32:18 +02:00
parent 64e3310e64
commit 837ebe405f
22 changed files with 1239 additions and 1493 deletions

View File

@ -76,7 +76,7 @@ embedded-storage = { version = "0.3" }
rand_core = "0.6.4" rand_core = "0.6.4"
fixed = "1.23.1" fixed = "1.23.1"
rp-pac = { version = "4" } rp-pac = { version = "5" }
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true}

View File

@ -50,16 +50,14 @@ impl<'d> Adc<'d> {
_irq: impl Binding<interrupt::typelevel::ADC_IRQ_FIFO, InterruptHandler>, _irq: impl Binding<interrupt::typelevel::ADC_IRQ_FIFO, InterruptHandler>,
_config: Config, _config: Config,
) -> Self { ) -> Self {
unsafe { let reset = Self::reset();
let reset = Self::reset(); crate::reset::reset(reset);
crate::reset::reset(reset); crate::reset::unreset_wait(reset);
crate::reset::unreset_wait(reset); let r = Self::regs();
let r = Self::regs(); // Enable ADC
// Enable ADC r.cs().write(|w| w.set_en(true));
r.cs().write(|w| w.set_en(true)); // Wait for ADC ready
// Wait for ADC ready while !r.cs().read().ready() {}
while !r.cs().read().ready() {}
}
// Setup IRQ // Setup IRQ
interrupt::ADC_IRQ_FIFO.unpend(); interrupt::ADC_IRQ_FIFO.unpend();
@ -70,80 +68,70 @@ impl<'d> Adc<'d> {
async fn wait_for_ready() { async fn wait_for_ready() {
let r = Self::regs(); let r = Self::regs();
unsafe { r.inte().write(|w| w.set_fifo(true));
r.inte().write(|w| w.set_fifo(true)); compiler_fence(Ordering::SeqCst);
compiler_fence(Ordering::SeqCst); poll_fn(|cx| {
poll_fn(|cx| { WAKER.register(cx.waker());
WAKER.register(cx.waker()); if r.cs().read().ready() {
if r.cs().read().ready() { return Poll::Ready(());
return Poll::Ready(()); }
} Poll::Pending
Poll::Pending })
}) .await;
.await;
}
} }
pub async fn read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 { pub async fn read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 {
let r = Self::regs(); let r = Self::regs();
unsafe { // disable pull-down and pull-up resistors
// disable pull-down and pull-up resistors // pull-down resistors are enabled by default
// pull-down resistors are enabled by default pin.pad_ctrl().modify(|w| {
pin.pad_ctrl().modify(|w| { w.set_ie(true);
w.set_ie(true); let (pu, pd) = (false, false);
let (pu, pd) = (false, false); w.set_pue(pu);
w.set_pue(pu); w.set_pde(pd);
w.set_pde(pd); });
}); r.cs().modify(|w| {
r.cs().modify(|w| { w.set_ainsel(PIN::channel());
w.set_ainsel(PIN::channel()); w.set_start_once(true)
w.set_start_once(true) });
}); Self::wait_for_ready().await;
Self::wait_for_ready().await; r.result().read().result().into()
r.result().read().result().into()
}
} }
pub async fn read_temperature(&mut self) -> u16 { pub async fn read_temperature(&mut self) -> u16 {
let r = Self::regs(); let r = Self::regs();
unsafe { r.cs().modify(|w| w.set_ts_en(true));
r.cs().modify(|w| w.set_ts_en(true)); if !r.cs().read().ready() {
if !r.cs().read().ready() {
Self::wait_for_ready().await;
}
r.cs().modify(|w| {
w.set_ainsel(4);
w.set_start_once(true)
});
Self::wait_for_ready().await; Self::wait_for_ready().await;
r.result().read().result().into()
} }
r.cs().modify(|w| {
w.set_ainsel(4);
w.set_start_once(true)
});
Self::wait_for_ready().await;
r.result().read().result().into()
} }
pub fn blocking_read<PIN: Channel<Adc<'d>, ID = u8>>(&mut self, _pin: &mut PIN) -> u16 { pub fn blocking_read<PIN: Channel<Adc<'d>, ID = u8>>(&mut self, _pin: &mut PIN) -> u16 {
let r = Self::regs(); let r = Self::regs();
unsafe { r.cs().modify(|w| {
r.cs().modify(|w| { w.set_ainsel(PIN::channel());
w.set_ainsel(PIN::channel()); w.set_start_once(true)
w.set_start_once(true) });
}); while !r.cs().read().ready() {}
while !r.cs().read().ready() {} r.result().read().result().into()
r.result().read().result().into()
}
} }
pub fn blocking_read_temperature(&mut self) -> u16 { pub fn blocking_read_temperature(&mut self) -> u16 {
let r = Self::regs(); let r = Self::regs();
unsafe { r.cs().modify(|w| w.set_ts_en(true));
r.cs().modify(|w| w.set_ts_en(true)); while !r.cs().read().ready() {}
while !r.cs().read().ready() {} r.cs().modify(|w| {
r.cs().modify(|w| { w.set_ainsel(4);
w.set_ainsel(4); w.set_start_once(true)
w.set_start_once(true) });
}); while !r.cs().read().ready() {}
while !r.cs().read().ready() {} r.result().read().result().into()
r.result().read().result().into()
}
} }
} }

View File

@ -542,7 +542,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
reset::unreset_wait(peris); reset::unreset_wait(peris);
} }
unsafe fn configure_rosc(config: RoscConfig) -> u32 { fn configure_rosc(config: RoscConfig) -> u32 {
let p = pac::ROSC; let p = pac::ROSC;
p.freqa().write(|w| { p.freqa().write(|w| {
@ -620,7 +620,7 @@ pub fn clk_rtc_freq() -> u16 {
CLOCKS.rtc.load(Ordering::Relaxed) CLOCKS.rtc.load(Ordering::Relaxed)
} }
unsafe fn start_xosc(crystal_hz: u32) { fn start_xosc(crystal_hz: u32) {
pac::XOSC pac::XOSC
.ctrl() .ctrl()
.write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ)); .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ));
@ -635,7 +635,7 @@ unsafe fn start_xosc(crystal_hz: u32) {
} }
#[inline(always)] #[inline(always)]
unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 { fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 {
let ref_freq = input_freq / config.refdiv as u32; let ref_freq = input_freq / config.refdiv as u32;
assert!(config.fbdiv >= 16 && config.fbdiv <= 320); assert!(config.fbdiv >= 16 && config.fbdiv <= 320);
assert!(config.post_div1 >= 1 && config.post_div1 <= 7); assert!(config.post_div1 >= 1 && config.post_div1 <= 7);
@ -700,9 +700,7 @@ impl<'d, T: Pin> Gpin<'d, T> {
pub fn new<P: GpinPin>(gpin: impl Peripheral<P = P> + 'd) -> Gpin<'d, P> { pub fn new<P: GpinPin>(gpin: impl Peripheral<P = P> + 'd) -> Gpin<'d, P> {
into_ref!(gpin); into_ref!(gpin);
unsafe { gpin.io().ctrl().write(|w| w.set_funcsel(0x08));
gpin.io().ctrl().write(|w| w.set_funcsel(0x08));
}
Gpin { Gpin {
gpin: gpin.map_into(), gpin: gpin.map_into(),
@ -717,12 +715,10 @@ impl<'d, T: Pin> Gpin<'d, T> {
impl<'d, T: Pin> Drop for Gpin<'d, T> { impl<'d, T: Pin> Drop for Gpin<'d, T> {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { self.gpin
self.gpin .io()
.io() .ctrl()
.ctrl() .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0));
.write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0));
}
} }
} }
@ -768,53 +764,43 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
pub fn new(gpout: impl Peripheral<P = T> + 'd) -> Self { pub fn new(gpout: impl Peripheral<P = T> + 'd) -> Self {
into_ref!(gpout); into_ref!(gpout);
unsafe { gpout.io().ctrl().write(|w| w.set_funcsel(0x08));
gpout.io().ctrl().write(|w| w.set_funcsel(0x08));
}
Self { gpout } Self { gpout }
} }
pub fn set_div(&self, int: u32, frac: u8) { pub fn set_div(&self, int: u32, frac: u8) {
unsafe { let c = pac::CLOCKS;
let c = pac::CLOCKS; c.clk_gpout_div(self.gpout.number()).write(|w| {
c.clk_gpout_div(self.gpout.number()).write(|w| { w.set_int(int);
w.set_int(int); w.set_frac(frac);
w.set_frac(frac); });
});
}
} }
pub fn set_src(&self, src: GpoutSrc) { pub fn set_src(&self, src: GpoutSrc) {
unsafe { let c = pac::CLOCKS;
let c = pac::CLOCKS; c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { w.set_auxsrc(ClkGpoutCtrlAuxsrc(src as _));
w.set_auxsrc(ClkGpoutCtrlAuxsrc(src as _)); });
});
}
} }
pub fn enable(&self) { pub fn enable(&self) {
unsafe { let c = pac::CLOCKS;
let c = pac::CLOCKS; c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { w.set_enable(true);
w.set_enable(true); });
});
}
} }
pub fn disable(&self) { pub fn disable(&self) {
unsafe { let c = pac::CLOCKS;
let c = pac::CLOCKS; c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { w.set_enable(false);
w.set_enable(false); });
});
}
} }
pub fn get_freq(&self) -> u32 { pub fn get_freq(&self) -> u32 {
let c = pac::CLOCKS; let c = pac::CLOCKS;
let src = unsafe { c.clk_gpout_ctrl(self.gpout.number()).read().auxsrc() }; let src = c.clk_gpout_ctrl(self.gpout.number()).read().auxsrc();
let base = match src { let base = match src {
ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(),
@ -831,7 +817,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
_ => unreachable!(), _ => unreachable!(),
}; };
let div = unsafe { c.clk_gpout_div(self.gpout.number()).read() }; let div = c.clk_gpout_div(self.gpout.number()).read();
let int = if div.int() == 0 { 65536 } else { div.int() } as u64; let int = if div.int() == 0 { 65536 } else { div.int() } as u64;
let frac = div.frac() as u64; let frac = div.frac() as u64;
@ -842,12 +828,10 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
impl<'d, T: GpoutPin> Drop for Gpout<'d, T> { impl<'d, T: GpoutPin> Drop for Gpout<'d, T> {
fn drop(&mut self) { fn drop(&mut self) {
self.disable(); self.disable();
unsafe { self.gpout
self.gpout .io()
.io() .ctrl()
.ctrl() .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0));
.write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0));
}
} }
} }
@ -864,7 +848,7 @@ impl RoscRng {
let mut acc = 0; let mut acc = 0;
for _ in 0..u8::BITS { for _ in 0..u8::BITS {
acc <<= 1; acc <<= 1;
acc |= unsafe { random_reg.read().randombit() as u8 }; acc |= random_reg.read().randombit() as u8;
} }
acc acc
} }

View File

@ -103,14 +103,11 @@ where
/// Try to claim the spinlock. Will return `Some(Self)` if the lock is obtained, and `None` if the lock is /// Try to claim the spinlock. Will return `Some(Self)` if the lock is obtained, and `None` if the lock is
/// already in use somewhere else. /// already in use somewhere else.
pub fn try_claim() -> Option<Self> { pub fn try_claim() -> Option<Self> {
// Safety: We're only reading from this register let lock = pac::SIO.spinlock(N).read();
unsafe { if lock > 0 {
let lock = pac::SIO.spinlock(N).read(); Some(Self(core::marker::PhantomData))
if lock > 0 { } else {
Some(Self(core::marker::PhantomData)) None
} else {
None
}
} }
} }
@ -120,10 +117,8 @@ where
/// ///
/// Only call this function if you hold the spin-lock. /// Only call this function if you hold the spin-lock.
pub unsafe fn release() { pub unsafe fn release() {
unsafe { // Write (any value): release the lock
// Write (any value): release the lock pac::SIO.spinlock(N).write_value(1);
pac::SIO.spinlock(N).write_value(1);
}
} }
} }

View File

@ -14,7 +14,7 @@ use crate::{interrupt, pac, peripherals};
#[cfg(feature = "rt")] #[cfg(feature = "rt")]
#[interrupt] #[interrupt]
unsafe fn DMA_IRQ_0() { fn DMA_IRQ_0() {
let ints0 = pac::DMA.ints0().read().ints0(); let ints0 = pac::DMA.ints0().read().ints0();
for channel in 0..CHANNEL_COUNT { for channel in 0..CHANNEL_COUNT {
let ctrl_trig = pac::DMA.ch(channel).ctrl_trig().read(); let ctrl_trig = pac::DMA.ch(channel).ctrl_trig().read();
@ -128,28 +128,26 @@ fn copy_inner<'a, C: Channel>(
) -> Transfer<'a, C> { ) -> Transfer<'a, C> {
into_ref!(ch); into_ref!(ch);
unsafe { let p = ch.regs();
let p = ch.regs();
p.read_addr().write_value(from as u32); p.read_addr().write_value(from as u32);
p.write_addr().write_value(to as u32); p.write_addr().write_value(to as u32);
p.trans_count().write_value(len as u32); p.trans_count().write_value(len as u32);
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
p.ctrl_trig().write(|w| { p.ctrl_trig().write(|w| {
// TODO: Add all DREQ options to pac vals::TreqSel, and use // TODO: Add all DREQ options to pac vals::TreqSel, and use
// `set_treq:sel` // `set_treq:sel`
w.0 = ((dreq as u32) & 0x3f) << 15usize; w.0 = ((dreq as u32) & 0x3f) << 15usize;
w.set_data_size(data_size); w.set_data_size(data_size);
w.set_incr_read(incr_read); w.set_incr_read(incr_read);
w.set_incr_write(incr_write); w.set_incr_write(incr_write);
w.set_chain_to(ch.number()); w.set_chain_to(ch.number());
w.set_en(true); w.set_en(true);
}); });
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
}
Transfer::new(ch) Transfer::new(ch)
} }
@ -169,12 +167,10 @@ impl<'a, C: Channel> Transfer<'a, C> {
impl<'a, C: Channel> Drop for Transfer<'a, C> { impl<'a, C: Channel> Drop for Transfer<'a, C> {
fn drop(&mut self) { fn drop(&mut self) {
let p = self.channel.regs(); let p = self.channel.regs();
unsafe { pac::DMA
pac::DMA .chan_abort()
.chan_abort() .modify(|m| m.set_chan_abort(1 << self.channel.number()));
.modify(|m| m.set_chan_abort(1 << self.channel.number())); while p.ctrl_trig().read().busy() {}
while p.ctrl_trig().read().busy() {}
}
} }
} }
@ -186,7 +182,7 @@ impl<'a, C: Channel> Future for Transfer<'a, C> {
// calls to wake will deregister the waker. // calls to wake will deregister the waker.
CHANNEL_WAKERS[self.channel.number() as usize].register(cx.waker()); CHANNEL_WAKERS[self.channel.number() as usize].register(cx.waker());
if unsafe { self.channel.regs().ctrl_trig().read().busy() } { if self.channel.regs().ctrl_trig().read().busy() {
Poll::Pending Poll::Pending
} else { } else {
Poll::Ready(()) Poll::Ready(())

View File

@ -167,7 +167,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
/// - DMA must not access flash memory /// - DMA must not access flash memory
unsafe fn in_ram(&mut self, operation: impl FnOnce()) -> Result<(), Error> { unsafe fn in_ram(&mut self, operation: impl FnOnce()) -> Result<(), Error> {
// Make sure we're running on CORE0 // Make sure we're running on CORE0
let core_id: u32 = unsafe { pac::SIO.cpuid().read() }; let core_id: u32 = pac::SIO.cpuid().read();
if core_id != 0 { if core_id != 0 {
return Err(Error::InvalidCore); return Err(Error::InvalidCore);
} }

View File

@ -17,45 +17,43 @@ where
{ {
let sio = rp_pac::SIO; let sio = rp_pac::SIO;
unsafe { // Since we can't save the signed-ness of the calculation, we have to make
// Since we can't save the signed-ness of the calculation, we have to make // sure that there's at least an 8 cycle delay before we read the result.
// sure that there's at least an 8 cycle delay before we read the result. // The Pico SDK ensures this by using a 6 cycle push and two 1 cycle reads.
// The Pico SDK ensures this by using a 6 cycle push and two 1 cycle reads. // Since we can't be sure the Rust implementation will optimize to the same,
// Since we can't be sure the Rust implementation will optimize to the same, // just use an explicit wait.
// just use an explicit wait. while !sio.div().csr().read().ready() {}
while !sio.div().csr().read().ready() {}
// Read the quotient last, since that's what clears the dirty flag // Read the quotient last, since that's what clears the dirty flag
let dividend = sio.div().udividend().read(); let dividend = sio.div().udividend().read();
let divisor = sio.div().udivisor().read(); let divisor = sio.div().udivisor().read();
let remainder = sio.div().remainder().read(); let remainder = sio.div().remainder().read();
let quotient = sio.div().quotient().read(); let quotient = sio.div().quotient().read();
// If we get interrupted here (before a write sets the DIRTY flag) its fine, since // If we get interrupted here (before a write sets the DIRTY flag) its fine, since
// we have the full state, so the interruptor doesn't have to restore it. Once the // we have the full state, so the interruptor doesn't have to restore it. Once the
// write happens and the DIRTY flag is set, the interruptor becomes responsible for // write happens and the DIRTY flag is set, the interruptor becomes responsible for
// restoring our state. // restoring our state.
let result = f(); let result = f();
// If we are interrupted here, then the interruptor will start an incorrect calculation // If we are interrupted here, then the interruptor will start an incorrect calculation
// using a wrong divisor, but we'll restore the divisor and result ourselves correctly. // using a wrong divisor, but we'll restore the divisor and result ourselves correctly.
// This sets DIRTY, so any interruptor will save the state. // This sets DIRTY, so any interruptor will save the state.
sio.div().udividend().write_value(dividend); sio.div().udividend().write_value(dividend);
// If we are interrupted here, the the interruptor may start the calculation using // If we are interrupted here, the the interruptor may start the calculation using
// incorrectly signed inputs, but we'll restore the result ourselves. // incorrectly signed inputs, but we'll restore the result ourselves.
// This sets DIRTY, so any interruptor will save the state. // This sets DIRTY, so any interruptor will save the state.
sio.div().udivisor().write_value(divisor); sio.div().udivisor().write_value(divisor);
// If we are interrupted here, the interruptor will have restored everything but the // If we are interrupted here, the interruptor will have restored everything but the
// quotient may be wrongly signed. If the calculation started by the above writes is // quotient may be wrongly signed. If the calculation started by the above writes is
// still ongoing it is stopped, so it won't replace the result we're restoring. // still ongoing it is stopped, so it won't replace the result we're restoring.
// DIRTY and READY set, but only DIRTY matters to make the interruptor save the state. // DIRTY and READY set, but only DIRTY matters to make the interruptor save the state.
sio.div().remainder().write_value(remainder); sio.div().remainder().write_value(remainder);
// State fully restored after the quotient write. This sets both DIRTY and READY, so // State fully restored after the quotient write. This sets both DIRTY and READY, so
// whatever we may have interrupted can read the result. // whatever we may have interrupted can read the result.
sio.div().quotient().write_value(quotient); sio.div().quotient().write_value(quotient);
result result
}
} }
fn save_divider<F, R>(f: F) -> R fn save_divider<F, R>(f: F) -> R
@ -63,7 +61,7 @@ where
F: FnOnce() -> R, F: FnOnce() -> R,
{ {
let sio = rp_pac::SIO; let sio = rp_pac::SIO;
if unsafe { !sio.div().csr().read().dirty() } { if !sio.div().csr().read().dirty() {
// Not dirty, so nothing is waiting for the calculation. So we can just // Not dirty, so nothing is waiting for the calculation. So we can just
// issue it directly without a save/restore. // issue it directly without a save/restore.
f() f()

View File

@ -144,7 +144,7 @@ pub(crate) unsafe fn init() {
#[cfg(feature = "rt")] #[cfg(feature = "rt")]
#[interrupt] #[interrupt]
unsafe fn IO_IRQ_BANK0() { fn IO_IRQ_BANK0() {
let cpu = SIO.cpuid().read() as usize; let cpu = SIO.cpuid().read() as usize;
// There are two sets of interrupt registers, one for cpu0 and one for cpu1 // There are two sets of interrupt registers, one for cpu0 and one for cpu1
// and here we are selecting the set that belongs to the currently executing // and here we are selecting the set that belongs to the currently executing
@ -185,46 +185,44 @@ struct InputFuture<'a, T: Pin> {
impl<'d, T: Pin> InputFuture<'d, T> { impl<'d, T: Pin> InputFuture<'d, T> {
pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self { pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self {
into_ref!(pin); into_ref!(pin);
unsafe { let pin_group = (pin.pin() % 8) as usize;
let pin_group = (pin.pin() % 8) as usize; // first, clear the INTR register bits. without this INTR will still
// first, clear the INTR register bits. without this INTR will still // contain reports of previous edges, causing the IRQ to fire early
// contain reports of previous edges, causing the IRQ to fire early // on stale state. clearing these means that we can only detect edges
// on stale state. clearing these means that we can only detect edges // that occur *after* the clear happened, but since both this and the
// that occur *after* the clear happened, but since both this and the // alternative are fundamentally racy it's probably fine.
// alternative are fundamentally racy it's probably fine. // (the alternative being checking the current level and waiting for
// (the alternative being checking the current level and waiting for // its inverse, but that requires reading the current level and thus
// its inverse, but that requires reading the current level and thus // missing anything that happened before the level was read.)
// missing anything that happened before the level was read.) pac::IO_BANK0.intr(pin.pin() as usize / 8).write(|w| {
pac::IO_BANK0.intr(pin.pin() as usize / 8).write(|w| { w.set_edge_high(pin_group, true);
w.set_edge_high(pin_group, true); w.set_edge_low(pin_group, true);
w.set_edge_low(pin_group, true); });
});
// Each INTR register is divided into 8 groups, one group for each // Each INTR register is divided into 8 groups, one group for each
// pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, // pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW,
// and EGDE_HIGH. // and EGDE_HIGH.
pin.int_proc() pin.int_proc()
.inte((pin.pin() / 8) as usize) .inte((pin.pin() / 8) as usize)
.write_set(|w| match level { .write_set(|w| match level {
InterruptTrigger::LevelHigh => { InterruptTrigger::LevelHigh => {
trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin()); trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin());
w.set_level_high(pin_group, true); w.set_level_high(pin_group, true);
} }
InterruptTrigger::LevelLow => { InterruptTrigger::LevelLow => {
w.set_level_low(pin_group, true); w.set_level_low(pin_group, true);
} }
InterruptTrigger::EdgeHigh => { InterruptTrigger::EdgeHigh => {
w.set_edge_high(pin_group, true); w.set_edge_high(pin_group, true);
} }
InterruptTrigger::EdgeLow => { InterruptTrigger::EdgeLow => {
w.set_edge_low(pin_group, true); w.set_edge_low(pin_group, true);
} }
InterruptTrigger::AnyEdge => { InterruptTrigger::AnyEdge => {
w.set_edge_high(pin_group, true); w.set_edge_high(pin_group, true);
w.set_edge_low(pin_group, true); w.set_edge_low(pin_group, true);
} }
}); });
}
Self { pin, level } Self { pin, level }
} }
@ -242,7 +240,7 @@ impl<'d, T: Pin> Future for InputFuture<'d, T> {
// then we want to access the interrupt enable register for our // then we want to access the interrupt enable register for our
// pin (there are 4 of these PROC0_INTE0, PROC0_INTE1, PROC0_INTE2, and // pin (there are 4 of these PROC0_INTE0, PROC0_INTE1, PROC0_INTE2, and
// PROC0_INTE3 per cpu). // PROC0_INTE3 per cpu).
let inte: pac::io::regs::Int = unsafe { self.pin.int_proc().inte((self.pin.pin() / 8) as usize).read() }; let inte: pac::io::regs::Int = self.pin.int_proc().inte((self.pin.pin() / 8) as usize).read();
// The register is divided into groups of four, one group for // The register is divided into groups of four, one group for
// each pin. Each group consists of four trigger levels LEVEL_LOW, // each pin. Each group consists of four trigger levels LEVEL_LOW,
// LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin. // LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin.
@ -449,15 +447,13 @@ impl<'d, T: Pin> Flex<'d, T> {
pub fn new(pin: impl Peripheral<P = T> + 'd) -> Self { pub fn new(pin: impl Peripheral<P = T> + 'd) -> Self {
into_ref!(pin); into_ref!(pin);
unsafe { pin.pad_ctrl().write(|w| {
pin.pad_ctrl().write(|w| { w.set_ie(true);
w.set_ie(true); });
});
pin.io().ctrl().write(|w| { pin.io().ctrl().write(|w| {
w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0.0); w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0.0);
}); });
}
Self { pin } Self { pin }
} }
@ -470,43 +466,37 @@ impl<'d, T: Pin> Flex<'d, T> {
/// Set the pin's pull. /// Set the pin's pull.
#[inline] #[inline]
pub fn set_pull(&mut self, pull: Pull) { pub fn set_pull(&mut self, pull: Pull) {
unsafe { self.pin.pad_ctrl().modify(|w| {
self.pin.pad_ctrl().modify(|w| { w.set_ie(true);
w.set_ie(true); let (pu, pd) = match pull {
let (pu, pd) = match pull { Pull::Up => (true, false),
Pull::Up => (true, false), Pull::Down => (false, true),
Pull::Down => (false, true), Pull::None => (false, false),
Pull::None => (false, false), };
}; w.set_pue(pu);
w.set_pue(pu); w.set_pde(pd);
w.set_pde(pd); });
});
}
} }
/// Set the pin's drive strength. /// Set the pin's drive strength.
#[inline] #[inline]
pub fn set_drive_strength(&mut self, strength: Drive) { pub fn set_drive_strength(&mut self, strength: Drive) {
unsafe { self.pin.pad_ctrl().modify(|w| {
self.pin.pad_ctrl().modify(|w| { w.set_drive(match strength {
w.set_drive(match strength { Drive::_2mA => pac::pads::vals::Drive::_2MA,
Drive::_2mA => pac::pads::vals::Drive::_2MA, Drive::_4mA => pac::pads::vals::Drive::_4MA,
Drive::_4mA => pac::pads::vals::Drive::_4MA, Drive::_8mA => pac::pads::vals::Drive::_8MA,
Drive::_8mA => pac::pads::vals::Drive::_8MA, Drive::_12mA => pac::pads::vals::Drive::_12MA,
Drive::_12mA => pac::pads::vals::Drive::_12MA,
});
}); });
} });
} }
// Set the pin's slew rate. // Set the pin's slew rate.
#[inline] #[inline]
pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
unsafe { self.pin.pad_ctrl().modify(|w| {
self.pin.pad_ctrl().modify(|w| { w.set_slewfast(slew_rate == SlewRate::Fast);
w.set_slewfast(slew_rate == SlewRate::Fast); });
});
}
} }
/// Put the pin into input mode. /// Put the pin into input mode.
@ -514,7 +504,7 @@ impl<'d, T: Pin> Flex<'d, T> {
/// The pull setting is left unchanged. /// The pull setting is left unchanged.
#[inline] #[inline]
pub fn set_as_input(&mut self) { pub fn set_as_input(&mut self) {
unsafe { self.pin.sio_oe().value_clr().write_value(self.bit()) } self.pin.sio_oe().value_clr().write_value(self.bit())
} }
/// Put the pin into output mode. /// Put the pin into output mode.
@ -523,17 +513,17 @@ impl<'d, T: Pin> Flex<'d, T> {
/// at a specific level, call `set_high`/`set_low` on the pin first. /// at a specific level, call `set_high`/`set_low` on the pin first.
#[inline] #[inline]
pub fn set_as_output(&mut self) { pub fn set_as_output(&mut self) {
unsafe { self.pin.sio_oe().value_set().write_value(self.bit()) } self.pin.sio_oe().value_set().write_value(self.bit())
} }
#[inline] #[inline]
fn is_set_as_output(&self) -> bool { fn is_set_as_output(&self) -> bool {
unsafe { (self.pin.sio_oe().value().read() & self.bit()) != 0 } (self.pin.sio_oe().value().read() & self.bit()) != 0
} }
#[inline] #[inline]
pub fn toggle_set_as_output(&mut self) { pub fn toggle_set_as_output(&mut self) {
unsafe { self.pin.sio_oe().value_xor().write_value(self.bit()) } self.pin.sio_oe().value_xor().write_value(self.bit())
} }
#[inline] #[inline]
@ -543,7 +533,7 @@ impl<'d, T: Pin> Flex<'d, T> {
#[inline] #[inline]
pub fn is_low(&self) -> bool { pub fn is_low(&self) -> bool {
unsafe { self.pin.sio_in().read() & self.bit() == 0 } self.pin.sio_in().read() & self.bit() == 0
} }
/// Returns current pin level /// Returns current pin level
@ -555,13 +545,13 @@ impl<'d, T: Pin> Flex<'d, T> {
/// Set the output as high. /// Set the output as high.
#[inline] #[inline]
pub fn set_high(&mut self) { pub fn set_high(&mut self) {
unsafe { self.pin.sio_out().value_set().write_value(self.bit()) } self.pin.sio_out().value_set().write_value(self.bit())
} }
/// Set the output as low. /// Set the output as low.
#[inline] #[inline]
pub fn set_low(&mut self) { pub fn set_low(&mut self) {
unsafe { self.pin.sio_out().value_clr().write_value(self.bit()) } self.pin.sio_out().value_clr().write_value(self.bit())
} }
/// Set the output level. /// Set the output level.
@ -576,7 +566,7 @@ impl<'d, T: Pin> Flex<'d, T> {
/// Is the output level high? /// Is the output level high?
#[inline] #[inline]
pub fn is_set_high(&self) -> bool { pub fn is_set_high(&self) -> bool {
unsafe { (self.pin.sio_out().value().read() & self.bit()) == 0 } (self.pin.sio_out().value().read() & self.bit()) == 0
} }
/// Is the output level low? /// Is the output level low?
@ -594,7 +584,7 @@ impl<'d, T: Pin> Flex<'d, T> {
/// Toggle pin output /// Toggle pin output
#[inline] #[inline]
pub fn toggle(&mut self) { pub fn toggle(&mut self) {
unsafe { self.pin.sio_out().value_xor().write_value(self.bit()) } self.pin.sio_out().value_xor().write_value(self.bit())
} }
#[inline] #[inline]
@ -626,12 +616,10 @@ impl<'d, T: Pin> Flex<'d, T> {
impl<'d, T: Pin> Drop for Flex<'d, T> { impl<'d, T: Pin> Drop for Flex<'d, T> {
#[inline] #[inline]
fn drop(&mut self) { fn drop(&mut self) {
unsafe { self.pin.pad_ctrl().write(|_| {});
self.pin.pad_ctrl().write(|_| {}); self.pin.io().ctrl().write(|w| {
self.pin.io().ctrl().write(|w| { w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0);
w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0); });
});
}
} }
} }
@ -688,7 +676,7 @@ pub(crate) mod sealed {
Bank::Bank0 => crate::pac::IO_BANK0, Bank::Bank0 => crate::pac::IO_BANK0,
Bank::Qspi => crate::pac::IO_QSPI, Bank::Qspi => crate::pac::IO_QSPI,
}; };
let proc = unsafe { SIO.cpuid().read() }; let proc = SIO.cpuid().read();
io_block.int_proc(proc as _) io_block.int_proc(proc as _)
} }
} }

View File

@ -85,7 +85,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
let r = T::regs(); let r = T::regs();
// mask everything initially // mask everything initially
unsafe { r.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0)) } r.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0));
T::Interrupt::unpend(); T::Interrupt::unpend();
unsafe { T::Interrupt::enable() }; unsafe { T::Interrupt::enable() };
@ -135,13 +135,11 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
let last = remaining_queue == 0; let last = remaining_queue == 0;
batch += 1; batch += 1;
unsafe { p.ic_data_cmd().write(|w| {
p.ic_data_cmd().write(|w| { w.set_restart(restart && remaining_queue == buffer.len() - 1);
w.set_restart(restart && remaining_queue == buffer.len() - 1); w.set_stop(last && send_stop);
w.set_stop(last && send_stop); w.set_cmd(true);
w.set_cmd(true); });
});
}
} }
// We've either run out of txfifo or just plain finished setting up // We've either run out of txfifo or just plain finished setting up
@ -161,7 +159,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
Poll::Pending Poll::Pending
} }
}, },
|_me| unsafe { |_me| {
// Set the read threshold to the number of bytes we're // Set the read threshold to the number of bytes we're
// expecting so we don't get spurious interrupts. // expecting so we don't get spurious interrupts.
p.ic_rx_tl().write(|w| w.set_rx_tl(batch - 1)); p.ic_rx_tl().write(|w| w.set_rx_tl(batch - 1));
@ -185,7 +183,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
let rxbytes = (rxfifo as usize).min(remaining); let rxbytes = (rxfifo as usize).min(remaining);
let received = buffer.len() - remaining; let received = buffer.len() - remaining;
for b in &mut buffer[received..received + rxbytes] { for b in &mut buffer[received..received + rxbytes] {
*b = unsafe { p.ic_data_cmd().read().dat() }; *b = p.ic_data_cmd().read().dat();
} }
remaining -= rxbytes; remaining -= rxbytes;
} }
@ -211,13 +209,11 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
if let Some(byte) = bytes.next() { if let Some(byte) = bytes.next() {
let last = bytes.peek().is_none(); let last = bytes.peek().is_none();
unsafe { p.ic_data_cmd().write(|w| {
p.ic_data_cmd().write(|w| { w.set_stop(last && send_stop);
w.set_stop(last && send_stop); w.set_cmd(false);
w.set_cmd(false); w.set_dat(byte);
w.set_dat(byte); });
});
}
} else { } else {
break 'xmit Ok(()); break 'xmit Ok(());
} }
@ -235,7 +231,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
Poll::Pending Poll::Pending
} }
}, },
|_me| unsafe { |_me| {
// Set tx "free" threshold a little high so that we get // Set tx "free" threshold a little high so that we get
// woken before the fifo completely drains to minimize // woken before the fifo completely drains to minimize
// transfer stalls. // transfer stalls.
@ -267,7 +263,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
let had_abort2 = self let had_abort2 = self
.wait_on( .wait_on(
|me| unsafe { |me| {
// We could see an abort while processing fifo backlog, // We could see an abort while processing fifo backlog,
// so handle it here. // so handle it here.
let abort = me.read_and_clear_abort_reason(); let abort = me.read_and_clear_abort_reason();
@ -279,7 +275,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
Poll::Pending Poll::Pending
} }
}, },
|_me| unsafe { |_me| {
p.ic_intr_mask().modify(|w| { p.ic_intr_mask().modify(|w| {
w.set_m_stop_det(true); w.set_m_stop_det(true);
w.set_m_tx_abrt(true); w.set_m_tx_abrt(true);
@ -287,9 +283,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
}, },
) )
.await; .await;
unsafe { p.ic_clr_stop_det().read();
p.ic_clr_stop_det().read();
}
had_abort.and(had_abort2) had_abort.and(had_abort2)
} else { } else {
@ -336,95 +330,93 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
let p = T::regs(); let p = T::regs();
unsafe { let reset = T::reset();
let reset = T::reset(); crate::reset::reset(reset);
crate::reset::reset(reset); crate::reset::unreset_wait(reset);
crate::reset::unreset_wait(reset);
p.ic_enable().write(|w| w.set_enable(false)); p.ic_enable().write(|w| w.set_enable(false));
// Select controller mode & speed // Select controller mode & speed
p.ic_con().modify(|w| { p.ic_con().modify(|w| {
// Always use "fast" mode (<= 400 kHz, works fine for standard // Always use "fast" mode (<= 400 kHz, works fine for standard
// mode too) // mode too)
w.set_speed(i2c::vals::Speed::FAST); w.set_speed(i2c::vals::Speed::FAST);
w.set_master_mode(true); w.set_master_mode(true);
w.set_ic_slave_disable(true); w.set_ic_slave_disable(true);
w.set_ic_restart_en(true); w.set_ic_restart_en(true);
w.set_tx_empty_ctrl(true); w.set_tx_empty_ctrl(true);
}); });
// Set FIFO watermarks to 1 to make things simpler. This is encoded // Set FIFO watermarks to 1 to make things simpler. This is encoded
// by a register value of 0. // by a register value of 0.
p.ic_tx_tl().write(|w| w.set_tx_tl(0)); p.ic_tx_tl().write(|w| w.set_tx_tl(0));
p.ic_rx_tl().write(|w| w.set_rx_tl(0)); p.ic_rx_tl().write(|w| w.set_rx_tl(0));
// Configure SCL & SDA pins // Configure SCL & SDA pins
scl.io().ctrl().write(|w| w.set_funcsel(3)); scl.io().ctrl().write(|w| w.set_funcsel(3));
sda.io().ctrl().write(|w| w.set_funcsel(3)); sda.io().ctrl().write(|w| w.set_funcsel(3));
scl.pad_ctrl().write(|w| { scl.pad_ctrl().write(|w| {
w.set_schmitt(true); w.set_schmitt(true);
w.set_ie(true); w.set_ie(true);
w.set_od(false); w.set_od(false);
w.set_pue(true); w.set_pue(true);
w.set_pde(false); w.set_pde(false);
}); });
sda.pad_ctrl().write(|w| { sda.pad_ctrl().write(|w| {
w.set_schmitt(true); w.set_schmitt(true);
w.set_ie(true); w.set_ie(true);
w.set_od(false); w.set_od(false);
w.set_pue(true); w.set_pue(true);
w.set_pde(false); w.set_pde(false);
}); });
// Configure baudrate // Configure baudrate
// There are some subtleties to I2C timing which we are completely // There are some subtleties to I2C timing which we are completely
// ignoring here See: // ignoring here See:
// https://github.com/raspberrypi/pico-sdk/blob/bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7/src/rp2_common/hardware_i2c/i2c.c#L69 // https://github.com/raspberrypi/pico-sdk/blob/bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7/src/rp2_common/hardware_i2c/i2c.c#L69
let clk_base = crate::clocks::clk_peri_freq(); let clk_base = crate::clocks::clk_peri_freq();
let period = (clk_base + config.frequency / 2) / config.frequency; let period = (clk_base + config.frequency / 2) / config.frequency;
let lcnt = period * 3 / 5; // spend 3/5 (60%) of the period low let lcnt = period * 3 / 5; // spend 3/5 (60%) of the period low
let hcnt = period - lcnt; // and 2/5 (40%) of the period high let hcnt = period - lcnt; // and 2/5 (40%) of the period high
// Check for out-of-range divisors: // Check for out-of-range divisors:
assert!(hcnt <= 0xffff); assert!(hcnt <= 0xffff);
assert!(lcnt <= 0xffff); assert!(lcnt <= 0xffff);
assert!(hcnt >= 8); assert!(hcnt >= 8);
assert!(lcnt >= 8); assert!(lcnt >= 8);
// Per I2C-bus specification a device in standard or fast mode must // Per I2C-bus specification a device in standard or fast mode must
// internally provide a hold time of at least 300ns for the SDA // internally provide a hold time of at least 300ns for the SDA
// signal to bridge the undefined region of the falling edge of SCL. // signal to bridge the undefined region of the falling edge of SCL.
// A smaller hold time of 120ns is used for fast mode plus. // A smaller hold time of 120ns is used for fast mode plus.
let sda_tx_hold_count = if config.frequency < 1_000_000 { let sda_tx_hold_count = if config.frequency < 1_000_000 {
// sda_tx_hold_count = clk_base [cycles/s] * 300ns * (1s / // sda_tx_hold_count = clk_base [cycles/s] * 300ns * (1s /
// 1e9ns) Reduce 300/1e9 to 3/1e7 to avoid numbers that don't // 1e9ns) Reduce 300/1e9 to 3/1e7 to avoid numbers that don't
// fit in uint. Add 1 to avoid division truncation. // fit in uint. Add 1 to avoid division truncation.
((clk_base * 3) / 10_000_000) + 1 ((clk_base * 3) / 10_000_000) + 1
} else { } else {
// fast mode plus requires a clk_base > 32MHz // fast mode plus requires a clk_base > 32MHz
assert!(clk_base >= 32_000_000); assert!(clk_base >= 32_000_000);
// sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s / // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s /
// 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't // 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't
// fit in uint. Add 1 to avoid division truncation. // fit in uint. Add 1 to avoid division truncation.
((clk_base * 3) / 25_000_000) + 1 ((clk_base * 3) / 25_000_000) + 1
}; };
assert!(sda_tx_hold_count <= lcnt - 2); assert!(sda_tx_hold_count <= lcnt - 2);
p.ic_fs_scl_hcnt().write(|w| w.set_ic_fs_scl_hcnt(hcnt as u16)); p.ic_fs_scl_hcnt().write(|w| w.set_ic_fs_scl_hcnt(hcnt as u16));
p.ic_fs_scl_lcnt().write(|w| w.set_ic_fs_scl_lcnt(lcnt as u16)); p.ic_fs_scl_lcnt().write(|w| w.set_ic_fs_scl_lcnt(lcnt as u16));
p.ic_fs_spklen() p.ic_fs_spklen()
.write(|w| w.set_ic_fs_spklen(if lcnt < 16 { 1 } else { (lcnt / 16) as u8 })); .write(|w| w.set_ic_fs_spklen(if lcnt < 16 { 1 } else { (lcnt / 16) as u8 }));
p.ic_sda_hold() p.ic_sda_hold()
.modify(|w| w.set_ic_sda_tx_hold(sda_tx_hold_count as u16)); .modify(|w| w.set_ic_sda_tx_hold(sda_tx_hold_count as u16));
// Enable I2C block // Enable I2C block
p.ic_enable().write(|w| w.set_enable(true)); p.ic_enable().write(|w| w.set_enable(true));
}
Self { phantom: PhantomData } Self { phantom: PhantomData }
} }
@ -439,11 +431,9 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
} }
let p = T::regs(); let p = T::regs();
unsafe { p.ic_enable().write(|w| w.set_enable(false));
p.ic_enable().write(|w| w.set_enable(false)); p.ic_tar().write(|w| w.set_ic_tar(addr));
p.ic_tar().write(|w| w.set_ic_tar(addr)); p.ic_enable().write(|w| w.set_enable(true));
p.ic_enable().write(|w| w.set_enable(true));
}
Ok(()) Ok(())
} }
@ -455,40 +445,38 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
#[inline] #[inline]
fn tx_fifo_capacity() -> u8 { fn tx_fifo_capacity() -> u8 {
let p = T::regs(); let p = T::regs();
unsafe { FIFO_SIZE - p.ic_txflr().read().txflr() } FIFO_SIZE - p.ic_txflr().read().txflr()
} }
#[inline] #[inline]
fn rx_fifo_len() -> u8 { fn rx_fifo_len() -> u8 {
let p = T::regs(); let p = T::regs();
unsafe { p.ic_rxflr().read().rxflr() } p.ic_rxflr().read().rxflr()
} }
fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> {
let p = T::regs(); let p = T::regs();
unsafe { let abort_reason = p.ic_tx_abrt_source().read();
let abort_reason = p.ic_tx_abrt_source().read(); if abort_reason.0 != 0 {
if abort_reason.0 != 0 { // Note clearing the abort flag also clears the reason, and this
// Note clearing the abort flag also clears the reason, and this // instance of flag is clear-on-read! Note also the
// instance of flag is clear-on-read! Note also the // IC_CLR_TX_ABRT register always reads as 0.
// IC_CLR_TX_ABRT register always reads as 0. p.ic_clr_tx_abrt().read();
p.ic_clr_tx_abrt().read();
let reason = if abort_reason.abrt_7b_addr_noack() let reason = if abort_reason.abrt_7b_addr_noack()
| abort_reason.abrt_10addr1_noack() | abort_reason.abrt_10addr1_noack()
| abort_reason.abrt_10addr2_noack() | abort_reason.abrt_10addr2_noack()
{ {
AbortReason::NoAcknowledge AbortReason::NoAcknowledge
} else if abort_reason.arb_lost() { } else if abort_reason.arb_lost() {
AbortReason::ArbitrationLoss AbortReason::ArbitrationLoss
} else {
AbortReason::Other(abort_reason.0)
};
Err(Error::Abort(reason))
} else { } else {
Ok(()) AbortReason::Other(abort_reason.0)
} };
Err(Error::Abort(reason))
} else {
Ok(())
} }
} }
@ -503,24 +491,21 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
let first = i == 0; let first = i == 0;
let last = i == lastindex; let last = i == lastindex;
// NOTE(unsafe) We have &mut self // wait until there is space in the FIFO to write the next byte
unsafe { while Self::tx_fifo_full() {}
// wait until there is space in the FIFO to write the next byte
while Self::tx_fifo_full() {}
p.ic_data_cmd().write(|w| { p.ic_data_cmd().write(|w| {
w.set_restart(restart && first); w.set_restart(restart && first);
w.set_stop(send_stop && last); w.set_stop(send_stop && last);
w.set_cmd(true); w.set_cmd(true);
}); });
while Self::rx_fifo_len() == 0 { while Self::rx_fifo_len() == 0 {
self.read_and_clear_abort_reason()?; self.read_and_clear_abort_reason()?;
}
*byte = p.ic_data_cmd().read().dat();
} }
*byte = p.ic_data_cmd().read().dat();
} }
Ok(()) Ok(())
@ -536,36 +521,33 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
for (i, byte) in write.iter().enumerate() { for (i, byte) in write.iter().enumerate() {
let last = i == write.len() - 1; let last = i == write.len() - 1;
// NOTE(unsafe) We have &mut self p.ic_data_cmd().write(|w| {
unsafe { w.set_stop(send_stop && last);
p.ic_data_cmd().write(|w| { w.set_dat(*byte);
w.set_stop(send_stop && last); });
w.set_dat(*byte);
});
// Wait until the transmission of the address/data from the // Wait until the transmission of the address/data from the
// internal shift register has completed. For this to function // internal shift register has completed. For this to function
// correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The // correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The
// TX_EMPTY_CTRL flag was set in i2c_init. // TX_EMPTY_CTRL flag was set in i2c_init.
while !p.ic_raw_intr_stat().read().tx_empty() {} while !p.ic_raw_intr_stat().read().tx_empty() {}
let abort_reason = self.read_and_clear_abort_reason(); let abort_reason = self.read_and_clear_abort_reason();
if abort_reason.is_err() || (send_stop && last) { if abort_reason.is_err() || (send_stop && last) {
// If the transaction was aborted or if it completed // If the transaction was aborted or if it completed
// successfully wait until the STOP condition has occurred. // successfully wait until the STOP condition has occurred.
while !p.ic_raw_intr_stat().read().stop_det() {} while !p.ic_raw_intr_stat().read().stop_det() {}
p.ic_clr_stop_det().read().clr_stop_det(); p.ic_clr_stop_det().read().clr_stop_det();
}
// Note the hardware issues a STOP automatically on an abort
// condition. Note also the hardware clears RX FIFO as well as
// TX on abort, ecause we set hwparam
// IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0.
abort_reason?;
} }
// Note the hardware issues a STOP automatically on an abort
// condition. Note also the hardware clears RX FIFO as well as
// TX on abort, ecause we set hwparam
// IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0.
abort_reason?;
} }
Ok(()) Ok(())
} }

View File

@ -261,33 +261,39 @@ pub fn init(config: config::Config) -> Peripherals {
/// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes. /// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes.
trait RegExt<T: Copy> { trait RegExt<T: Copy> {
unsafe fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
unsafe fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
unsafe fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
} }
impl<T: Default + Copy, A: pac::common::Write> RegExt<T> for pac::common::Reg<T, A> { impl<T: Default + Copy, A: pac::common::Write> RegExt<T> for pac::common::Reg<T, A> {
unsafe fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
let mut val = Default::default(); let mut val = Default::default();
let res = f(&mut val); let res = f(&mut val);
let ptr = (self.ptr() as *mut u8).add(0x1000) as *mut T; unsafe {
ptr.write_volatile(val); let ptr = (self.as_ptr() as *mut u8).add(0x1000) as *mut T;
ptr.write_volatile(val);
}
res res
} }
unsafe fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
let mut val = Default::default(); let mut val = Default::default();
let res = f(&mut val); let res = f(&mut val);
let ptr = (self.ptr() as *mut u8).add(0x2000) as *mut T; unsafe {
ptr.write_volatile(val); let ptr = (self.as_ptr() as *mut u8).add(0x2000) as *mut T;
ptr.write_volatile(val);
}
res res
} }
unsafe fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
let mut val = Default::default(); let mut val = Default::default();
let res = f(&mut val); let res = f(&mut val);
let ptr = (self.ptr() as *mut u8).add(0x3000) as *mut T; unsafe {
ptr.write_volatile(val); let ptr = (self.as_ptr() as *mut u8).add(0x3000) as *mut T;
ptr.write_volatile(val);
}
res res
} }
} }

View File

@ -163,14 +163,12 @@ where
} }
// Reset the core // Reset the core
unsafe { let psm = pac::PSM;
let psm = pac::PSM; psm.frce_off().modify(|w| w.set_proc1(true));
psm.frce_off().modify(|w| w.set_proc1(true)); while !psm.frce_off().read().proc1() {
while !psm.frce_off().read().proc1() { cortex_m::asm::nop();
cortex_m::asm::nop();
}
psm.frce_off().modify(|w| w.set_proc1(false));
} }
psm.frce_off().modify(|w| w.set_proc1(false));
// The ARM AAPCS ABI requires 8-byte stack alignment. // The ARM AAPCS ABI requires 8-byte stack alignment.
// #[align] on `struct Stack` ensures the bottom is aligned, but the top could still be // #[align] on `struct Stack` ensures the bottom is aligned, but the top could still be
@ -270,14 +268,12 @@ pub fn resume_core1() {
// Push a value to the inter-core FIFO, block until space is available // Push a value to the inter-core FIFO, block until space is available
#[inline(always)] #[inline(always)]
fn fifo_write(value: u32) { fn fifo_write(value: u32) {
unsafe { let sio = pac::SIO;
let sio = pac::SIO; // Wait for the FIFO to have enough space
// Wait for the FIFO to have enough space while !sio.fifo().st().read().rdy() {
while !sio.fifo().st().read().rdy() { cortex_m::asm::nop();
cortex_m::asm::nop();
}
sio.fifo().wr().write_value(value);
} }
sio.fifo().wr().write_value(value);
// Fire off an event to the other core. // Fire off an event to the other core.
// This is required as the other core may be `wfe` (waiting for event) // This is required as the other core may be `wfe` (waiting for event)
cortex_m::asm::sev(); cortex_m::asm::sev();
@ -286,38 +282,32 @@ fn fifo_write(value: u32) {
// Pop a value from inter-core FIFO, block until available // Pop a value from inter-core FIFO, block until available
#[inline(always)] #[inline(always)]
fn fifo_read() -> u32 { fn fifo_read() -> u32 {
unsafe { let sio = pac::SIO;
let sio = pac::SIO; // Wait until FIFO has data
// Wait until FIFO has data while !sio.fifo().st().read().vld() {
while !sio.fifo().st().read().vld() { cortex_m::asm::nop();
cortex_m::asm::nop();
}
sio.fifo().rd().read()
} }
sio.fifo().rd().read()
} }
// Pop a value from inter-core FIFO, `wfe` until available // Pop a value from inter-core FIFO, `wfe` until available
#[inline(always)] #[inline(always)]
#[allow(unused)] #[allow(unused)]
fn fifo_read_wfe() -> u32 { fn fifo_read_wfe() -> u32 {
unsafe { let sio = pac::SIO;
let sio = pac::SIO; // Wait until FIFO has data
// Wait until FIFO has data while !sio.fifo().st().read().vld() {
while !sio.fifo().st().read().vld() { cortex_m::asm::wfe();
cortex_m::asm::wfe();
}
sio.fifo().rd().read()
} }
sio.fifo().rd().read()
} }
// Drain inter-core FIFO // Drain inter-core FIFO
#[inline(always)] #[inline(always)]
fn fifo_drain() { fn fifo_drain() {
unsafe { let sio = pac::SIO;
let sio = pac::SIO; while sio.fifo().st().read().vld() {
while sio.fifo().st().read().vld() { let _ = sio.fifo().rd().read();
let _ = sio.fifo().rd().read();
}
} }
} }

View File

@ -87,7 +87,7 @@ const SMIRQ_MASK: u32 = 1 << 8;
#[cfg(feature = "rt")] #[cfg(feature = "rt")]
#[interrupt] #[interrupt]
unsafe fn PIO0_IRQ_0() { fn PIO0_IRQ_0() {
use crate::pac; use crate::pac;
let ints = pac::PIO0.irqs(0).ints().read().0; let ints = pac::PIO0.irqs(0).ints().read().0;
for bit in 0..12 { for bit in 0..12 {
@ -100,7 +100,7 @@ unsafe fn PIO0_IRQ_0() {
#[cfg(feature = "rt")] #[cfg(feature = "rt")]
#[interrupt] #[interrupt]
unsafe fn PIO1_IRQ_0() { fn PIO1_IRQ_0() {
use crate::pac; use crate::pac;
let ints = pac::PIO1.irqs(0).ints().read().0; let ints = pac::PIO1.irqs(0).ints().read().0;
for bit in 0..12 { for bit in 0..12 {
@ -145,11 +145,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoOutFuture<'a, 'd, PI
Poll::Ready(()) Poll::Ready(())
} else { } else {
WAKERS[PIO::PIO_NO as usize].fifo_out()[SM].register(cx.waker()); WAKERS[PIO::PIO_NO as usize].fifo_out()[SM].register(cx.waker());
unsafe { PIO::PIO.irqs(0).inte().write_set(|m| {
PIO::PIO.irqs(0).inte().write_set(|m| { m.0 = TXNFULL_MASK << SM;
m.0 = TXNFULL_MASK << SM; });
});
}
// debug!("Pending"); // debug!("Pending");
Poll::Pending Poll::Pending
} }
@ -158,11 +156,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoOutFuture<'a, 'd, PI
impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoOutFuture<'a, 'd, PIO, SM> { impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoOutFuture<'a, 'd, PIO, SM> {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { PIO::PIO.irqs(0).inte().write_clear(|m| {
PIO::PIO.irqs(0).inte().write_clear(|m| { m.0 = TXNFULL_MASK << SM;
m.0 = TXNFULL_MASK << SM; });
});
}
} }
} }
@ -186,11 +182,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoInFuture<'a, 'd, PIO
Poll::Ready(v) Poll::Ready(v)
} else { } else {
WAKERS[PIO::PIO_NO as usize].fifo_in()[SM].register(cx.waker()); WAKERS[PIO::PIO_NO as usize].fifo_in()[SM].register(cx.waker());
unsafe { PIO::PIO.irqs(0).inte().write_set(|m| {
PIO::PIO.irqs(0).inte().write_set(|m| { m.0 = RXNEMPTY_MASK << SM;
m.0 = RXNEMPTY_MASK << SM; });
});
}
//debug!("Pending"); //debug!("Pending");
Poll::Pending Poll::Pending
} }
@ -199,11 +193,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoInFuture<'a, 'd, PIO
impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoInFuture<'a, 'd, PIO, SM> { impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoInFuture<'a, 'd, PIO, SM> {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { PIO::PIO.irqs(0).inte().write_clear(|m| {
PIO::PIO.irqs(0).inte().write_clear(|m| { m.0 = RXNEMPTY_MASK << SM;
m.0 = RXNEMPTY_MASK << SM; });
});
}
} }
} }
@ -220,30 +212,24 @@ impl<'a, 'd, PIO: Instance> Future for IrqFuture<'a, 'd, PIO> {
//debug!("Poll {},{}", PIO::PIO_NO, SM); //debug!("Poll {},{}", PIO::PIO_NO, SM);
// Check if IRQ flag is already set // Check if IRQ flag is already set
if unsafe { PIO::PIO.irq().read().0 & (1 << self.irq_no) != 0 } { if PIO::PIO.irq().read().0 & (1 << self.irq_no) != 0 {
unsafe { PIO::PIO.irq().write(|m| m.0 = 1 << self.irq_no);
PIO::PIO.irq().write(|m| m.0 = 1 << self.irq_no);
}
return Poll::Ready(()); return Poll::Ready(());
} }
WAKERS[PIO::PIO_NO as usize].irq()[self.irq_no as usize].register(cx.waker()); WAKERS[PIO::PIO_NO as usize].irq()[self.irq_no as usize].register(cx.waker());
unsafe { PIO::PIO.irqs(0).inte().write_set(|m| {
PIO::PIO.irqs(0).inte().write_set(|m| { m.0 = SMIRQ_MASK << self.irq_no;
m.0 = SMIRQ_MASK << self.irq_no; });
});
}
Poll::Pending Poll::Pending
} }
} }
impl<'a, 'd, PIO: Instance> Drop for IrqFuture<'a, 'd, PIO> { impl<'a, 'd, PIO: Instance> Drop for IrqFuture<'a, 'd, PIO> {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { PIO::PIO.irqs(0).inte().write_clear(|m| {
PIO::PIO.irqs(0).inte().write_clear(|m| { m.0 = SMIRQ_MASK << self.irq_no;
m.0 = SMIRQ_MASK << self.irq_no; });
});
}
} }
} }
@ -256,57 +242,47 @@ impl<'l, PIO: Instance> Pin<'l, PIO> {
/// Set the pin's drive strength. /// Set the pin's drive strength.
#[inline] #[inline]
pub fn set_drive_strength(&mut self, strength: Drive) { pub fn set_drive_strength(&mut self, strength: Drive) {
unsafe { self.pin.pad_ctrl().modify(|w| {
self.pin.pad_ctrl().modify(|w| { w.set_drive(match strength {
w.set_drive(match strength { Drive::_2mA => pac::pads::vals::Drive::_2MA,
Drive::_2mA => pac::pads::vals::Drive::_2MA, Drive::_4mA => pac::pads::vals::Drive::_4MA,
Drive::_4mA => pac::pads::vals::Drive::_4MA, Drive::_8mA => pac::pads::vals::Drive::_8MA,
Drive::_8mA => pac::pads::vals::Drive::_8MA, Drive::_12mA => pac::pads::vals::Drive::_12MA,
Drive::_12mA => pac::pads::vals::Drive::_12MA,
});
}); });
} });
} }
// Set the pin's slew rate. // Set the pin's slew rate.
#[inline] #[inline]
pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
unsafe { self.pin.pad_ctrl().modify(|w| {
self.pin.pad_ctrl().modify(|w| { w.set_slewfast(slew_rate == SlewRate::Fast);
w.set_slewfast(slew_rate == SlewRate::Fast); });
});
}
} }
/// Set the pin's pull. /// Set the pin's pull.
#[inline] #[inline]
pub fn set_pull(&mut self, pull: Pull) { pub fn set_pull(&mut self, pull: Pull) {
unsafe { self.pin.pad_ctrl().modify(|w| {
self.pin.pad_ctrl().modify(|w| { w.set_pue(pull == Pull::Up);
w.set_pue(pull == Pull::Up); w.set_pde(pull == Pull::Down);
w.set_pde(pull == Pull::Down); });
});
}
} }
/// Set the pin's schmitt trigger. /// Set the pin's schmitt trigger.
#[inline] #[inline]
pub fn set_schmitt(&mut self, enable: bool) { pub fn set_schmitt(&mut self, enable: bool) {
unsafe { self.pin.pad_ctrl().modify(|w| {
self.pin.pad_ctrl().modify(|w| { w.set_schmitt(enable);
w.set_schmitt(enable); });
});
}
} }
pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) { pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) {
let mask = 1 << self.pin(); let mask = 1 << self.pin();
unsafe { if bypass {
if bypass { PIO::PIO.input_sync_bypass().write_set(|w| *w = mask);
PIO::PIO.input_sync_bypass().write_set(|w| *w = mask); } else {
} else { PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask);
PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask);
}
} }
} }
@ -321,41 +297,37 @@ pub struct StateMachineRx<'d, PIO: Instance, const SM: usize> {
impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
pub fn empty(&self) -> bool { pub fn empty(&self) -> bool {
unsafe { PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0 } PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0
} }
pub fn full(&self) -> bool { pub fn full(&self) -> bool {
unsafe { PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0 } PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0
} }
pub fn level(&self) -> u8 { pub fn level(&self) -> u8 {
unsafe { (PIO::PIO.flevel().read().0 >> (SM * 8 + 4)) as u8 & 0x0f } (PIO::PIO.flevel().read().0 >> (SM * 8 + 4)) as u8 & 0x0f
} }
pub fn stalled(&self) -> bool { pub fn stalled(&self) -> bool {
unsafe { let fdebug = PIO::PIO.fdebug();
let fdebug = PIO::PIO.fdebug(); let ret = fdebug.read().rxstall() & (1 << SM) != 0;
let ret = fdebug.read().rxstall() & (1 << SM) != 0; if ret {
if ret { fdebug.write(|w| w.set_rxstall(1 << SM));
fdebug.write(|w| w.set_rxstall(1 << SM));
}
ret
} }
ret
} }
pub fn underflowed(&self) -> bool { pub fn underflowed(&self) -> bool {
unsafe { let fdebug = PIO::PIO.fdebug();
let fdebug = PIO::PIO.fdebug(); let ret = fdebug.read().rxunder() & (1 << SM) != 0;
let ret = fdebug.read().rxunder() & (1 << SM) != 0; if ret {
if ret { fdebug.write(|w| w.set_rxunder(1 << SM));
fdebug.write(|w| w.set_rxunder(1 << SM));
}
ret
} }
ret
} }
pub fn pull(&mut self) -> u32 { pub fn pull(&mut self) -> u32 {
unsafe { PIO::PIO.rxf(SM).read() } PIO::PIO.rxf(SM).read()
} }
pub fn try_pull(&mut self) -> Option<u32> { pub fn try_pull(&mut self) -> Option<u32> {
@ -374,24 +346,22 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
ch: PeripheralRef<'a, C>, ch: PeripheralRef<'a, C>,
data: &'a mut [W], data: &'a mut [W],
) -> Transfer<'a, C> { ) -> Transfer<'a, C> {
unsafe { let pio_no = PIO::PIO_NO;
let pio_no = PIO::PIO_NO; let p = ch.regs();
let p = ch.regs(); p.write_addr().write_value(data.as_ptr() as u32);
p.write_addr().write_value(data.as_ptr() as u32); p.read_addr().write_value(PIO::PIO.rxf(SM).as_ptr() as u32);
p.read_addr().write_value(PIO::PIO.rxf(SM).ptr() as u32); p.trans_count().write_value(data.len() as u32);
p.trans_count().write_value(data.len() as u32); compiler_fence(Ordering::SeqCst);
compiler_fence(Ordering::SeqCst); p.ctrl_trig().write(|w| {
p.ctrl_trig().write(|w| { // Set RX DREQ for this statemachine
// Set RX DREQ for this statemachine w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8 + 4));
w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8 + 4)); w.set_data_size(W::size());
w.set_data_size(W::size()); w.set_chain_to(ch.number());
w.set_chain_to(ch.number()); w.set_incr_read(false);
w.set_incr_read(false); w.set_incr_write(true);
w.set_incr_write(true); w.set_en(true);
w.set_en(true); });
}); compiler_fence(Ordering::SeqCst);
compiler_fence(Ordering::SeqCst);
}
Transfer::new(ch) Transfer::new(ch)
} }
} }
@ -402,42 +372,36 @@ pub struct StateMachineTx<'d, PIO: Instance, const SM: usize> {
impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
pub fn empty(&self) -> bool { pub fn empty(&self) -> bool {
unsafe { PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0 } PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0
} }
pub fn full(&self) -> bool { pub fn full(&self) -> bool {
unsafe { PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0 } PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0
} }
pub fn level(&self) -> u8 { pub fn level(&self) -> u8 {
unsafe { (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f } (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f
} }
pub fn stalled(&self) -> bool { pub fn stalled(&self) -> bool {
unsafe { let fdebug = PIO::PIO.fdebug();
let fdebug = PIO::PIO.fdebug(); let ret = fdebug.read().txstall() & (1 << SM) != 0;
let ret = fdebug.read().txstall() & (1 << SM) != 0; if ret {
if ret { fdebug.write(|w| w.set_txstall(1 << SM));
fdebug.write(|w| w.set_txstall(1 << SM));
}
ret
} }
ret
} }
pub fn overflowed(&self) -> bool { pub fn overflowed(&self) -> bool {
unsafe { let fdebug = PIO::PIO.fdebug();
let fdebug = PIO::PIO.fdebug(); let ret = fdebug.read().txover() & (1 << SM) != 0;
let ret = fdebug.read().txover() & (1 << SM) != 0; if ret {
if ret { fdebug.write(|w| w.set_txover(1 << SM));
fdebug.write(|w| w.set_txover(1 << SM));
}
ret
} }
ret
} }
pub fn push(&mut self, v: u32) { pub fn push(&mut self, v: u32) {
unsafe { PIO::PIO.txf(SM).write_value(v);
PIO::PIO.txf(SM).write_value(v);
}
} }
pub fn try_push(&mut self, v: u32) -> bool { pub fn try_push(&mut self, v: u32) -> bool {
@ -453,24 +417,22 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
} }
pub fn dma_push<'a, C: Channel, W: Word>(&'a mut self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> { pub fn dma_push<'a, C: Channel, W: Word>(&'a mut self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> {
unsafe { let pio_no = PIO::PIO_NO;
let pio_no = PIO::PIO_NO; let p = ch.regs();
let p = ch.regs(); p.read_addr().write_value(data.as_ptr() as u32);
p.read_addr().write_value(data.as_ptr() as u32); p.write_addr().write_value(PIO::PIO.txf(SM).as_ptr() as u32);
p.write_addr().write_value(PIO::PIO.txf(SM).ptr() as u32); p.trans_count().write_value(data.len() as u32);
p.trans_count().write_value(data.len() as u32); compiler_fence(Ordering::SeqCst);
compiler_fence(Ordering::SeqCst); p.ctrl_trig().write(|w| {
p.ctrl_trig().write(|w| { // Set TX DREQ for this statemachine
// Set TX DREQ for this statemachine w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8));
w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8)); w.set_data_size(W::size());
w.set_data_size(W::size()); w.set_chain_to(ch.number());
w.set_chain_to(ch.number()); w.set_incr_read(true);
w.set_incr_read(true); w.set_incr_write(false);
w.set_incr_write(false); w.set_en(true);
w.set_en(true); });
}); compiler_fence(Ordering::SeqCst);
compiler_fence(Ordering::SeqCst);
}
Transfer::new(ch) Transfer::new(ch)
} }
} }
@ -482,9 +444,7 @@ pub struct StateMachine<'d, PIO: Instance, const SM: usize> {
impl<'d, PIO: Instance, const SM: usize> Drop for StateMachine<'d, PIO, SM> { impl<'d, PIO: Instance, const SM: usize> Drop for StateMachine<'d, PIO, SM> {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(1 << SM));
PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(1 << SM));
}
on_pio_drop::<PIO>(); on_pio_drop::<PIO>();
} }
} }
@ -647,45 +607,43 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
assert!(config.shift_in.threshold <= 32, "shift_in.threshold must be <= 32"); assert!(config.shift_in.threshold <= 32, "shift_in.threshold must be <= 32");
assert!(config.shift_out.threshold <= 32, "shift_out.threshold must be <= 32"); assert!(config.shift_out.threshold <= 32, "shift_out.threshold must be <= 32");
let sm = Self::this_sm(); let sm = Self::this_sm();
unsafe { sm.clkdiv().write(|w| w.0 = config.clock_divider.to_bits() << 8);
sm.clkdiv().write(|w| w.0 = config.clock_divider.to_bits() << 8); sm.execctrl().write(|w| {
sm.execctrl().write(|w| { w.set_side_en(config.exec.side_en);
w.set_side_en(config.exec.side_en); w.set_side_pindir(config.exec.side_pindir);
w.set_side_pindir(config.exec.side_pindir); w.set_jmp_pin(config.exec.jmp_pin);
w.set_jmp_pin(config.exec.jmp_pin); w.set_out_en_sel(config.out_en_sel);
w.set_out_en_sel(config.out_en_sel); w.set_inline_out_en(config.inline_out_en);
w.set_inline_out_en(config.inline_out_en); w.set_out_sticky(config.out_sticky);
w.set_out_sticky(config.out_sticky); w.set_wrap_top(config.exec.wrap_top);
w.set_wrap_top(config.exec.wrap_top); w.set_wrap_bottom(config.exec.wrap_bottom);
w.set_wrap_bottom(config.exec.wrap_bottom); w.set_status_sel(match config.status_sel {
w.set_status_sel(match config.status_sel { StatusSource::TxFifoLevel => SmExecctrlStatusSel::TXLEVEL,
StatusSource::TxFifoLevel => SmExecctrlStatusSel::TXLEVEL, StatusSource::RxFifoLevel => SmExecctrlStatusSel::RXLEVEL,
StatusSource::RxFifoLevel => SmExecctrlStatusSel::RXLEVEL,
});
w.set_status_n(config.status_n);
}); });
sm.shiftctrl().write(|w| { w.set_status_n(config.status_n);
w.set_fjoin_rx(config.fifo_join == FifoJoin::RxOnly); });
w.set_fjoin_tx(config.fifo_join == FifoJoin::TxOnly); sm.shiftctrl().write(|w| {
w.set_pull_thresh(config.shift_out.threshold); w.set_fjoin_rx(config.fifo_join == FifoJoin::RxOnly);
w.set_push_thresh(config.shift_in.threshold); w.set_fjoin_tx(config.fifo_join == FifoJoin::TxOnly);
w.set_out_shiftdir(config.shift_out.direction == ShiftDirection::Right); w.set_pull_thresh(config.shift_out.threshold);
w.set_in_shiftdir(config.shift_in.direction == ShiftDirection::Right); w.set_push_thresh(config.shift_in.threshold);
w.set_autopull(config.shift_out.auto_fill); w.set_out_shiftdir(config.shift_out.direction == ShiftDirection::Right);
w.set_autopush(config.shift_in.auto_fill); w.set_in_shiftdir(config.shift_in.direction == ShiftDirection::Right);
}); w.set_autopull(config.shift_out.auto_fill);
sm.pinctrl().write(|w| { w.set_autopush(config.shift_in.auto_fill);
w.set_sideset_count(config.pins.sideset_count); });
w.set_set_count(config.pins.set_count); sm.pinctrl().write(|w| {
w.set_out_count(config.pins.out_count); w.set_sideset_count(config.pins.sideset_count);
w.set_in_base(config.pins.in_base); w.set_set_count(config.pins.set_count);
w.set_sideset_base(config.pins.sideset_base); w.set_out_count(config.pins.out_count);
w.set_set_base(config.pins.set_base); w.set_in_base(config.pins.in_base);
w.set_out_base(config.pins.out_base); w.set_sideset_base(config.pins.sideset_base);
}); w.set_set_base(config.pins.set_base);
if let Some(origin) = config.origin { w.set_out_base(config.pins.out_base);
pio_instr_util::exec_jmp(self, origin); });
} if let Some(origin) = config.origin {
unsafe { pio_instr_util::exec_jmp(self, origin) }
} }
} }
@ -696,45 +654,35 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
pub fn restart(&mut self) { pub fn restart(&mut self) {
let mask = 1u8 << SM; let mask = 1u8 << SM;
unsafe { PIO::PIO.ctrl().write_set(|w| w.set_sm_restart(mask));
PIO::PIO.ctrl().write_set(|w| w.set_sm_restart(mask));
}
} }
pub fn set_enable(&mut self, enable: bool) { pub fn set_enable(&mut self, enable: bool) {
let mask = 1u8 << SM; let mask = 1u8 << SM;
unsafe { if enable {
if enable { PIO::PIO.ctrl().write_set(|w| w.set_sm_enable(mask));
PIO::PIO.ctrl().write_set(|w| w.set_sm_enable(mask)); } else {
} else { PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask));
PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask));
}
} }
} }
pub fn is_enabled(&self) -> bool { pub fn is_enabled(&self) -> bool {
unsafe { PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0 } PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0
} }
pub fn clkdiv_restart(&mut self) { pub fn clkdiv_restart(&mut self) {
let mask = 1u8 << SM; let mask = 1u8 << SM;
unsafe { PIO::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask));
PIO::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask));
}
} }
fn with_paused(&mut self, f: impl FnOnce(&mut Self)) { fn with_paused(&mut self, f: impl FnOnce(&mut Self)) {
let enabled = self.is_enabled(); let enabled = self.is_enabled();
self.set_enable(false); self.set_enable(false);
let pincfg = unsafe { Self::this_sm().pinctrl().read() }; let pincfg = Self::this_sm().pinctrl().read();
let execcfg = unsafe { Self::this_sm().execctrl().read() }; let execcfg = Self::this_sm().execctrl().read();
unsafe { Self::this_sm().execctrl().write_clear(|w| w.set_out_sticky(true));
Self::this_sm().execctrl().write_clear(|w| w.set_out_sticky(true));
}
f(self); f(self);
unsafe { Self::this_sm().pinctrl().write_value(pincfg);
Self::this_sm().pinctrl().write_value(pincfg); Self::this_sm().execctrl().write_value(execcfg);
Self::this_sm().execctrl().write_value(execcfg);
}
self.set_enable(enabled); self.set_enable(enabled);
} }
@ -743,14 +691,12 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
pub fn set_pin_dirs(&mut self, dir: Direction, pins: &[&Pin<'d, PIO>]) { pub fn set_pin_dirs(&mut self, dir: Direction, pins: &[&Pin<'d, PIO>]) {
self.with_paused(|sm| { self.with_paused(|sm| {
for pin in pins { for pin in pins {
unsafe { Self::this_sm().pinctrl().write(|w| {
Self::this_sm().pinctrl().write(|w| { w.set_set_base(pin.pin());
w.set_set_base(pin.pin()); w.set_set_count(1);
w.set_set_count(1); });
}); // SET PINDIRS, (dir)
// SET PINDIRS, (dir) unsafe { sm.exec_instr(0b111_00000_100_00000 | dir as u16) };
sm.exec_instr(0b111_00000_100_00000 | dir as u16);
}
} }
}); });
} }
@ -760,29 +706,25 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
pub fn set_pins(&mut self, level: Level, pins: &[&Pin<'d, PIO>]) { pub fn set_pins(&mut self, level: Level, pins: &[&Pin<'d, PIO>]) {
self.with_paused(|sm| { self.with_paused(|sm| {
for pin in pins { for pin in pins {
unsafe { Self::this_sm().pinctrl().write(|w| {
Self::this_sm().pinctrl().write(|w| { w.set_set_base(pin.pin());
w.set_set_base(pin.pin()); w.set_set_count(1);
w.set_set_count(1); });
}); // SET PINS, (dir)
// SET PINS, (dir) unsafe { sm.exec_instr(0b111_00000_000_00000 | level as u16) };
sm.exec_instr(0b111_00000_000_00000 | level as u16);
}
} }
}); });
} }
pub fn clear_fifos(&mut self) { pub fn clear_fifos(&mut self) {
// Toggle FJOIN_RX to flush FIFOs // Toggle FJOIN_RX to flush FIFOs
unsafe { let shiftctrl = Self::this_sm().shiftctrl();
let shiftctrl = Self::this_sm().shiftctrl(); shiftctrl.modify(|w| {
shiftctrl.modify(|w| { w.set_fjoin_rx(!w.fjoin_rx());
w.set_fjoin_rx(!w.fjoin_rx()); });
}); shiftctrl.modify(|w| {
shiftctrl.modify(|w| { w.set_fjoin_rx(!w.fjoin_rx());
w.set_fjoin_rx(!w.fjoin_rx()); });
});
}
} }
pub unsafe fn exec_instr(&mut self, instr: u16) { pub unsafe fn exec_instr(&mut self, instr: u16) {
@ -856,11 +798,9 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
if (self.instructions_used | used_mask) & mask != 0 { if (self.instructions_used | used_mask) & mask != 0 {
return Err(addr); return Err(addr);
} }
unsafe { PIO::PIO.instr_mem(addr).write(|w| {
PIO::PIO.instr_mem(addr).write(|w| { w.set_instr_mem(instr);
w.set_instr_mem(instr); });
});
}
used_mask |= mask; used_mask |= mask;
} }
self.instructions_used |= used_mask; self.instructions_used |= used_mask;
@ -877,17 +817,15 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
} }
pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) { pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) {
unsafe { // this can interfere with per-pin bypass functions. splitting the
// this can interfere with per-pin bypass functions. splitting the // modification is going to be fine since nothing that relies on
// modification is going to be fine since nothing that relies on // it can reasonably run before we finish.
// it can reasonably run before we finish. PIO::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass);
PIO::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass); PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass);
PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass);
}
} }
pub fn get_input_sync_bypass(&self) -> u32 { pub fn get_input_sync_bypass(&self) -> u32 {
unsafe { PIO::PIO.input_sync_bypass().read() } PIO::PIO.input_sync_bypass().read()
} }
/// Register a pin for PIO usage. Pins will be released from the PIO block /// Register a pin for PIO usage. Pins will be released from the PIO block
@ -896,9 +834,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
/// of [`Pio`] do not keep pin registrations alive.** /// of [`Pio`] do not keep pin registrations alive.**
pub fn make_pio_pin(&mut self, pin: impl Peripheral<P = impl PioPin + 'd> + 'd) -> Pin<'d, PIO> { pub fn make_pio_pin(&mut self, pin: impl Peripheral<P = impl PioPin + 'd> + 'd) -> Pin<'d, PIO> {
into_ref!(pin); into_ref!(pin);
unsafe { pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0));
pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0));
}
// we can be relaxed about this because we're &mut here and nothing is cached // we can be relaxed about this because we're &mut here and nothing is cached
PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed); PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed);
Pin { Pin {
@ -916,13 +852,11 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
_pio: PhantomData, _pio: PhantomData,
}; };
f(&mut batch); f(&mut batch);
unsafe { PIO::PIO.ctrl().modify(|w| {
PIO::PIO.ctrl().modify(|w| { w.set_clkdiv_restart(batch.clkdiv_restart);
w.set_clkdiv_restart(batch.clkdiv_restart); w.set_sm_restart(batch.sm_restart);
w.set_sm_restart(batch.sm_restart); w.set_sm_enable((w.sm_enable() & !batch.sm_enable_mask) | batch.sm_enable);
w.set_sm_enable((w.sm_enable() & !batch.sm_enable_mask) | batch.sm_enable); });
});
}
} }
} }
@ -974,11 +908,11 @@ impl<'d, PIO: Instance> IrqFlags<'d, PIO> {
} }
pub fn check_any(&self, irqs: u8) -> bool { pub fn check_any(&self, irqs: u8) -> bool {
unsafe { PIO::PIO.irq().read().irq() & irqs != 0 } PIO::PIO.irq().read().irq() & irqs != 0
} }
pub fn check_all(&self, irqs: u8) -> bool { pub fn check_all(&self, irqs: u8) -> bool {
unsafe { PIO::PIO.irq().read().irq() & irqs == irqs } PIO::PIO.irq().read().irq() & irqs == irqs
} }
pub fn clear(&self, irq_no: usize) { pub fn clear(&self, irq_no: usize) {
@ -987,7 +921,7 @@ impl<'d, PIO: Instance> IrqFlags<'d, PIO> {
} }
pub fn clear_all(&self, irqs: u8) { pub fn clear_all(&self, irqs: u8) {
unsafe { PIO::PIO.irq().write(|w| w.set_irq(irqs)) } PIO::PIO.irq().write(|w| w.set_irq(irqs))
} }
pub fn set(&self, irq_no: usize) { pub fn set(&self, irq_no: usize) {
@ -996,7 +930,7 @@ impl<'d, PIO: Instance> IrqFlags<'d, PIO> {
} }
pub fn set_all(&self, irqs: u8) { pub fn set_all(&self, irqs: u8) {
unsafe { PIO::PIO.irq_force().write(|w| w.set_irq_force(irqs)) } PIO::PIO.irq_force().write(|w| w.set_irq_force(irqs))
} }
} }
@ -1068,9 +1002,7 @@ fn on_pio_drop<PIO: Instance>() {
// we only have 30 pins. don't test the other two since gpio() asserts. // we only have 30 pins. don't test the other two since gpio() asserts.
for i in 0..30 { for i in 0..30 {
if used_pins & (1 << i) != 0 { if used_pins & (1 << i) != 0 {
unsafe { pac::IO_BANK0.gpio(i).ctrl().write(|w| w.set_funcsel(null));
pac::IO_BANK0.gpio(i).ctrl().write(|w| w.set_funcsel(null));
}
} }
} }
} }

View File

@ -71,20 +71,18 @@ impl<'d, T: Channel> Pwm<'d, T> {
into_ref!(inner); into_ref!(inner);
let p = inner.regs(); let p = inner.regs();
unsafe { p.csr().modify(|w| {
p.csr().modify(|w| { w.set_divmode(divmode);
w.set_divmode(divmode); w.set_en(false);
w.set_en(false); });
}); p.ctr().write(|w| w.0 = 0);
p.ctr().write(|w| w.0 = 0); Self::configure(p, &config);
Self::configure(p, &config);
if let Some(pin) = &a { if let Some(pin) = &a {
pin.io().ctrl().write(|w| w.set_funcsel(4)); pin.io().ctrl().write(|w| w.set_funcsel(4));
} }
if let Some(pin) = &b { if let Some(pin) = &b {
pin.io().ctrl().write(|w| w.set_funcsel(4)); pin.io().ctrl().write(|w| w.set_funcsel(4));
}
} }
Self { Self {
inner, inner,
@ -161,31 +159,29 @@ impl<'d, T: Channel> Pwm<'d, T> {
panic!("Requested divider is too large"); panic!("Requested divider is too large");
} }
unsafe { p.div().write_value(ChDiv(config.divider.to_bits() as u32));
p.div().write_value(ChDiv(config.divider.to_bits() as u32)); p.cc().write(|w| {
p.cc().write(|w| { w.set_a(config.compare_a);
w.set_a(config.compare_a); w.set_b(config.compare_b);
w.set_b(config.compare_b); });
}); p.top().write(|w| w.set_top(config.top));
p.top().write(|w| w.set_top(config.top)); p.csr().modify(|w| {
p.csr().modify(|w| { w.set_a_inv(config.invert_a);
w.set_a_inv(config.invert_a); w.set_b_inv(config.invert_b);
w.set_b_inv(config.invert_b); w.set_ph_correct(config.phase_correct);
w.set_ph_correct(config.phase_correct); w.set_en(config.enable);
w.set_en(config.enable); });
});
}
} }
#[inline] #[inline]
pub unsafe fn phase_advance(&mut self) { pub fn phase_advance(&mut self) {
let p = self.inner.regs(); let p = self.inner.regs();
p.csr().write_set(|w| w.set_ph_adv(true)); p.csr().write_set(|w| w.set_ph_adv(true));
while p.csr().read().ph_adv() {} while p.csr().read().ph_adv() {}
} }
#[inline] #[inline]
pub unsafe fn phase_retard(&mut self) { pub fn phase_retard(&mut self) {
let p = self.inner.regs(); let p = self.inner.regs();
p.csr().write_set(|w| w.set_ph_ret(true)); p.csr().write_set(|w| w.set_ph_ret(true));
while p.csr().read().ph_ret() {} while p.csr().read().ph_ret() {}
@ -193,12 +189,12 @@ impl<'d, T: Channel> Pwm<'d, T> {
#[inline] #[inline]
pub fn counter(&self) -> u16 { pub fn counter(&self) -> u16 {
unsafe { self.inner.regs().ctr().read().ctr() } self.inner.regs().ctr().read().ctr()
} }
#[inline] #[inline]
pub fn set_counter(&self, ctr: u16) { pub fn set_counter(&self, ctr: u16) {
unsafe { self.inner.regs().ctr().write(|w| w.set_ctr(ctr)) } self.inner.regs().ctr().write(|w| w.set_ctr(ctr))
} }
#[inline] #[inline]
@ -209,14 +205,12 @@ impl<'d, T: Channel> Pwm<'d, T> {
#[inline] #[inline]
pub fn wrapped(&mut self) -> bool { pub fn wrapped(&mut self) -> bool {
unsafe { pac::PWM.intr().read().0 & self.bit() != 0 } pac::PWM.intr().read().0 & self.bit() != 0
} }
#[inline] #[inline]
pub fn clear_wrapped(&mut self) { pub fn clear_wrapped(&mut self) {
unsafe { pac::PWM.intr().write_value(Intr(self.bit() as _));
pac::PWM.intr().write_value(Intr(self.bit() as _));
}
} }
#[inline] #[inline]
@ -237,26 +231,22 @@ impl PwmBatch {
pub fn set_enabled(enabled: bool, batch: impl FnOnce(&mut PwmBatch)) { pub fn set_enabled(enabled: bool, batch: impl FnOnce(&mut PwmBatch)) {
let mut en = PwmBatch(0); let mut en = PwmBatch(0);
batch(&mut en); batch(&mut en);
unsafe { if enabled {
if enabled { pac::PWM.en().write_set(|w| w.0 = en.0);
pac::PWM.en().write_set(|w| w.0 = en.0); } else {
} else { pac::PWM.en().write_clear(|w| w.0 = en.0);
pac::PWM.en().write_clear(|w| w.0 = en.0);
}
} }
} }
} }
impl<'d, T: Channel> Drop for Pwm<'d, T> { impl<'d, T: Channel> Drop for Pwm<'d, T> {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { self.inner.regs().csr().write_clear(|w| w.set_en(false));
self.inner.regs().csr().write_clear(|w| w.set_en(false)); if let Some(pin) = &self.pin_a {
if let Some(pin) = &self.pin_a { pin.io().ctrl().write(|w| w.set_funcsel(31));
pin.io().ctrl().write(|w| w.set_funcsel(31)); }
} if let Some(pin) = &self.pin_b {
if let Some(pin) = &self.pin_b { pin.io().ctrl().write(|w| w.set_funcsel(31));
pin.io().ctrl().write(|w| w.set_funcsel(31));
}
} }
} }
} }

View File

@ -4,11 +4,11 @@ use crate::pac;
pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ffffff); pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ffffff);
pub unsafe fn reset(peris: Peripherals) { pub(crate) fn reset(peris: Peripherals) {
pac::RESETS.reset().write_value(peris); pac::RESETS.reset().write_value(peris);
} }
pub unsafe fn unreset_wait(peris: Peripherals) { pub(crate) fn unreset_wait(peris: Peripherals) {
// TODO use the "atomic clear" register version // TODO use the "atomic clear" register version
pac::RESETS.reset().modify(|v| *v = Peripherals(v.0 & !peris.0)); pac::RESETS.reset().modify(|v| *v = Peripherals(v.0 & !peris.0));
while ((!pac::RESETS.reset_done().read().0) & peris.0) != 0 {} while ((!pac::RESETS.reset_done().read().0) & peris.0) != 0 {}

View File

@ -26,7 +26,7 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
into_ref!(inner); into_ref!(inner);
// Set the RTC divider // Set the RTC divider
unsafe { inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1)) }; inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1));
let mut result = Self { inner }; let mut result = Self { inner };
result.set_leap_year_check(true); // should be on by default, make sure this is the case. result.set_leap_year_check(true); // should be on by default, make sure this is the case.
@ -38,17 +38,14 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
/// ///
/// Leap year checking is enabled by default. /// Leap year checking is enabled by default.
pub fn set_leap_year_check(&mut self, leap_year_check_enabled: bool) { pub fn set_leap_year_check(&mut self, leap_year_check_enabled: bool) {
unsafe { self.inner.regs().ctrl().modify(|w| {
self.inner w.set_force_notleapyear(!leap_year_check_enabled);
.regs() });
.ctrl()
.modify(|w| w.set_force_notleapyear(!leap_year_check_enabled))
};
} }
/// Checks to see if this RealTimeClock is running /// Checks to see if this RealTimeClock is running
pub fn is_running(&self) -> bool { pub fn is_running(&self) -> bool {
unsafe { self.inner.regs().ctrl().read().rtc_active() } self.inner.regs().ctrl().read().rtc_active()
} }
/// Set the datetime to a new value. /// Set the datetime to a new value.
@ -60,25 +57,23 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?; self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?;
// disable RTC while we configure it // disable RTC while we configure it
unsafe { self.inner.regs().ctrl().modify(|w| w.set_rtc_enable(false));
self.inner.regs().ctrl().modify(|w| w.set_rtc_enable(false)); while self.inner.regs().ctrl().read().rtc_active() {
while self.inner.regs().ctrl().read().rtc_active() { core::hint::spin_loop();
core::hint::spin_loop(); }
}
self.inner.regs().setup_0().write(|w| { self.inner.regs().setup_0().write(|w| {
self::datetime::write_setup_0(&t, w); self::datetime::write_setup_0(&t, w);
}); });
self.inner.regs().setup_1().write(|w| { self.inner.regs().setup_1().write(|w| {
self::datetime::write_setup_1(&t, w); self::datetime::write_setup_1(&t, w);
}); });
// Load the new datetime and re-enable RTC // Load the new datetime and re-enable RTC
self.inner.regs().ctrl().write(|w| w.set_load(true)); self.inner.regs().ctrl().write(|w| w.set_load(true));
self.inner.regs().ctrl().write(|w| w.set_rtc_enable(true)); self.inner.regs().ctrl().write(|w| w.set_rtc_enable(true));
while !self.inner.regs().ctrl().read().rtc_active() { while !self.inner.regs().ctrl().read().rtc_active() {
core::hint::spin_loop(); core::hint::spin_loop();
}
} }
Ok(()) Ok(())
} }
@ -93,8 +88,8 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
return Err(RtcError::NotRunning); return Err(RtcError::NotRunning);
} }
let rtc_0 = unsafe { self.inner.regs().rtc_0().read() }; let rtc_0 = self.inner.regs().rtc_0().read();
let rtc_1 = unsafe { self.inner.regs().rtc_1().read() }; let rtc_1 = self.inner.regs().rtc_1().read();
self::datetime::datetime_from_registers(rtc_0, rtc_1).map_err(RtcError::InvalidDateTime) self::datetime::datetime_from_registers(rtc_0, rtc_1).map_err(RtcError::InvalidDateTime)
} }
@ -103,12 +98,10 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
/// ///
/// [`schedule_alarm`]: #method.schedule_alarm /// [`schedule_alarm`]: #method.schedule_alarm
pub fn disable_alarm(&mut self) { pub fn disable_alarm(&mut self) {
unsafe { self.inner.regs().irq_setup_0().modify(|s| s.set_match_ena(false));
self.inner.regs().irq_setup_0().modify(|s| s.set_match_ena(false));
while self.inner.regs().irq_setup_0().read().match_active() { while self.inner.regs().irq_setup_0().read().match_active() {
core::hint::spin_loop(); core::hint::spin_loop();
}
} }
} }
@ -132,21 +125,19 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
pub fn schedule_alarm(&mut self, filter: DateTimeFilter) { pub fn schedule_alarm(&mut self, filter: DateTimeFilter) {
self.disable_alarm(); self.disable_alarm();
unsafe { self.inner.regs().irq_setup_0().write(|w| {
self.inner.regs().irq_setup_0().write(|w| { filter.write_setup_0(w);
filter.write_setup_0(w); });
}); self.inner.regs().irq_setup_1().write(|w| {
self.inner.regs().irq_setup_1().write(|w| { filter.write_setup_1(w);
filter.write_setup_1(w); });
});
self.inner.regs().inte().modify(|w| w.set_rtc(true)); self.inner.regs().inte().modify(|w| w.set_rtc(true));
// Set the enable bit and check if it is set // Set the enable bit and check if it is set
self.inner.regs().irq_setup_0().modify(|w| w.set_match_ena(true)); self.inner.regs().irq_setup_0().modify(|w| w.set_match_ena(true));
while !self.inner.regs().irq_setup_0().read().match_active() { while !self.inner.regs().irq_setup_0().read().match_active() {
core::hint::spin_loop(); core::hint::spin_loop();
}
} }
} }

View File

@ -79,39 +79,37 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
) -> Self { ) -> Self {
into_ref!(inner); into_ref!(inner);
unsafe { let p = inner.regs();
let p = inner.regs(); let (presc, postdiv) = calc_prescs(config.frequency);
let (presc, postdiv) = calc_prescs(config.frequency);
p.cpsr().write(|w| w.set_cpsdvsr(presc)); p.cpsr().write(|w| w.set_cpsdvsr(presc));
p.cr0().write(|w| { p.cr0().write(|w| {
w.set_dss(0b0111); // 8bit w.set_dss(0b0111); // 8bit
w.set_spo(config.polarity == Polarity::IdleHigh); w.set_spo(config.polarity == Polarity::IdleHigh);
w.set_sph(config.phase == Phase::CaptureOnSecondTransition); w.set_sph(config.phase == Phase::CaptureOnSecondTransition);
w.set_scr(postdiv); w.set_scr(postdiv);
}); });
// Always enable DREQ signals -- harmless if DMA is not listening // Always enable DREQ signals -- harmless if DMA is not listening
p.dmacr().write(|reg| { p.dmacr().write(|reg| {
reg.set_rxdmae(true); reg.set_rxdmae(true);
reg.set_txdmae(true); reg.set_txdmae(true);
}); });
// finally, enable. // finally, enable.
p.cr1().write(|w| w.set_sse(true)); p.cr1().write(|w| w.set_sse(true));
if let Some(pin) = &clk { if let Some(pin) = &clk {
pin.io().ctrl().write(|w| w.set_funcsel(1)); pin.io().ctrl().write(|w| w.set_funcsel(1));
} }
if let Some(pin) = &mosi { if let Some(pin) = &mosi {
pin.io().ctrl().write(|w| w.set_funcsel(1)); pin.io().ctrl().write(|w| w.set_funcsel(1));
} }
if let Some(pin) = &miso { if let Some(pin) = &miso {
pin.io().ctrl().write(|w| w.set_funcsel(1)); pin.io().ctrl().write(|w| w.set_funcsel(1));
} }
if let Some(pin) = &cs { if let Some(pin) = &cs {
pin.io().ctrl().write(|w| w.set_funcsel(1)); pin.io().ctrl().write(|w| w.set_funcsel(1));
}
} }
Self { Self {
inner, inner,
@ -122,60 +120,52 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
} }
pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> { pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> {
unsafe { let p = self.inner.regs();
let p = self.inner.regs(); for &b in data {
for &b in data { while !p.sr().read().tnf() {}
while !p.sr().read().tnf() {} p.dr().write(|w| w.set_data(b as _));
p.dr().write(|w| w.set_data(b as _)); while !p.sr().read().rne() {}
while !p.sr().read().rne() {} let _ = p.dr().read();
let _ = p.dr().read();
}
} }
self.flush()?; self.flush()?;
Ok(()) Ok(())
} }
pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> { pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> {
unsafe { let p = self.inner.regs();
let p = self.inner.regs(); for b in data {
for b in data { while !p.sr().read().tnf() {}
while !p.sr().read().tnf() {} p.dr().write(|w| w.set_data(*b as _));
p.dr().write(|w| w.set_data(*b as _)); while !p.sr().read().rne() {}
while !p.sr().read().rne() {} *b = p.dr().read().data() as u8;
*b = p.dr().read().data() as u8;
}
} }
self.flush()?; self.flush()?;
Ok(()) Ok(())
} }
pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> { pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> {
unsafe { let p = self.inner.regs();
let p = self.inner.regs(); for b in data {
for b in data { while !p.sr().read().tnf() {}
while !p.sr().read().tnf() {} p.dr().write(|w| w.set_data(0));
p.dr().write(|w| w.set_data(0)); while !p.sr().read().rne() {}
while !p.sr().read().rne() {} *b = p.dr().read().data() as u8;
*b = p.dr().read().data() as u8;
}
} }
self.flush()?; self.flush()?;
Ok(()) Ok(())
} }
pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> { pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
unsafe { let p = self.inner.regs();
let p = self.inner.regs(); let len = read.len().max(write.len());
let len = read.len().max(write.len()); for i in 0..len {
for i in 0..len { let wb = write.get(i).copied().unwrap_or(0);
let wb = write.get(i).copied().unwrap_or(0); while !p.sr().read().tnf() {}
while !p.sr().read().tnf() {} p.dr().write(|w| w.set_data(wb as _));
p.dr().write(|w| w.set_data(wb as _)); while !p.sr().read().rne() {}
while !p.sr().read().rne() {} let rb = p.dr().read().data() as u8;
let rb = p.dr().read().data() as u8; if let Some(r) = read.get_mut(i) {
if let Some(r) = read.get_mut(i) { *r = rb;
*r = rb;
}
} }
} }
self.flush()?; self.flush()?;
@ -183,29 +173,25 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
} }
pub fn flush(&mut self) -> Result<(), Error> { pub fn flush(&mut self) -> Result<(), Error> {
unsafe { let p = self.inner.regs();
let p = self.inner.regs(); while p.sr().read().bsy() {}
while p.sr().read().bsy() {}
}
Ok(()) Ok(())
} }
pub fn set_frequency(&mut self, freq: u32) { pub fn set_frequency(&mut self, freq: u32) {
let (presc, postdiv) = calc_prescs(freq); let (presc, postdiv) = calc_prescs(freq);
let p = self.inner.regs(); let p = self.inner.regs();
unsafe { // disable
// disable p.cr1().write(|w| w.set_sse(false));
p.cr1().write(|w| w.set_sse(false));
// change stuff // change stuff
p.cpsr().write(|w| w.set_cpsdvsr(presc)); p.cpsr().write(|w| w.set_cpsdvsr(presc));
p.cr0().modify(|w| { p.cr0().modify(|w| {
w.set_scr(postdiv); w.set_scr(postdiv);
}); });
// enable // enable
p.cr1().write(|w| w.set_sse(true)); p.cr1().write(|w| w.set_sse(true));
}
} }
} }
@ -337,21 +323,19 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
let tx_transfer = unsafe { let tx_transfer = unsafe {
// If we don't assign future to a variable, the data register pointer // If we don't assign future to a variable, the data register pointer
// is held across an await and makes the future non-Send. // is held across an await and makes the future non-Send.
crate::dma::write(tx_ch, buffer, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ) crate::dma::write(tx_ch, buffer, self.inner.regs().dr().as_ptr() as *mut _, T::TX_DREQ)
}; };
tx_transfer.await; tx_transfer.await;
let p = self.inner.regs(); let p = self.inner.regs();
unsafe { while p.sr().read().bsy() {}
while p.sr().read().bsy() {}
// clear RX FIFO contents to prevent stale reads // clear RX FIFO contents to prevent stale reads
while p.sr().read().rne() { while p.sr().read().rne() {
let _: u16 = p.dr().read().data(); let _: u16 = p.dr().read().data();
}
// clear RX overrun interrupt
p.icr().write(|w| w.set_roric(true));
} }
// clear RX overrun interrupt
p.icr().write(|w| w.set_roric(true));
Ok(()) Ok(())
} }
@ -363,14 +347,19 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
let rx_transfer = unsafe { let rx_transfer = unsafe {
// If we don't assign future to a variable, the data register pointer // If we don't assign future to a variable, the data register pointer
// is held across an await and makes the future non-Send. // is held across an await and makes the future non-Send.
crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, buffer, T::RX_DREQ) crate::dma::read(rx_ch, self.inner.regs().dr().as_ptr() as *const _, buffer, T::RX_DREQ)
}; };
let tx_ch = self.tx_dma.as_mut().unwrap(); let tx_ch = self.tx_dma.as_mut().unwrap();
let tx_transfer = unsafe { let tx_transfer = unsafe {
// If we don't assign future to a variable, the data register pointer // If we don't assign future to a variable, the data register pointer
// is held across an await and makes the future non-Send. // is held across an await and makes the future non-Send.
crate::dma::write_repeated(tx_ch, self.inner.regs().dr().ptr() as *mut u8, buffer.len(), T::TX_DREQ) crate::dma::write_repeated(
tx_ch,
self.inner.regs().dr().as_ptr() as *mut u8,
buffer.len(),
T::TX_DREQ,
)
}; };
join(tx_transfer, rx_transfer).await; join(tx_transfer, rx_transfer).await;
Ok(()) Ok(())
@ -394,7 +383,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
let rx_transfer = unsafe { let rx_transfer = unsafe {
// If we don't assign future to a variable, the data register pointer // If we don't assign future to a variable, the data register pointer
// is held across an await and makes the future non-Send. // is held across an await and makes the future non-Send.
crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, rx_ptr, T::RX_DREQ) crate::dma::read(rx_ch, self.inner.regs().dr().as_ptr() as *const _, rx_ptr, T::RX_DREQ)
}; };
let mut tx_ch = self.tx_dma.as_mut().unwrap(); let mut tx_ch = self.tx_dma.as_mut().unwrap();
@ -403,13 +392,13 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
let tx_transfer = async { let tx_transfer = async {
let p = self.inner.regs(); let p = self.inner.regs();
unsafe { unsafe {
crate::dma::write(&mut tx_ch, tx_ptr, p.dr().ptr() as *mut _, T::TX_DREQ).await; crate::dma::write(&mut tx_ch, tx_ptr, p.dr().as_ptr() as *mut _, T::TX_DREQ).await;
if rx_len > tx_len { if rx_len > tx_len {
let write_bytes_len = rx_len - tx_len; let write_bytes_len = rx_len - tx_len;
// write dummy data // write dummy data
// this will disable incrementation of the buffers // this will disable incrementation of the buffers
crate::dma::write_repeated(tx_ch, p.dr().ptr() as *mut u8, write_bytes_len, T::TX_DREQ).await crate::dma::write_repeated(tx_ch, p.dr().as_ptr() as *mut u8, write_bytes_len, T::TX_DREQ).await
} }
} }
}; };
@ -418,16 +407,14 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
// if tx > rx we should clear any overflow of the FIFO SPI buffer // if tx > rx we should clear any overflow of the FIFO SPI buffer
if tx_len > rx_len { if tx_len > rx_len {
let p = self.inner.regs(); let p = self.inner.regs();
unsafe { while p.sr().read().bsy() {}
while p.sr().read().bsy() {}
// clear RX FIFO contents to prevent stale reads // clear RX FIFO contents to prevent stale reads
while p.sr().read().rne() { while p.sr().read().rne() {
let _: u16 = p.dr().read().data(); let _: u16 = p.dr().read().data();
}
// clear RX overrun interrupt
p.icr().write(|w| w.set_roric(true));
} }
// clear RX overrun interrupt
p.icr().write(|w| w.set_roric(true));
} }
Ok(()) Ok(())
@ -625,14 +612,12 @@ impl<'d, T: Instance, M: Mode> SetConfig for Spi<'d, T, M> {
fn set_config(&mut self, config: &Self::Config) { fn set_config(&mut self, config: &Self::Config) {
let p = self.inner.regs(); let p = self.inner.regs();
let (presc, postdiv) = calc_prescs(config.frequency); let (presc, postdiv) = calc_prescs(config.frequency);
unsafe { p.cpsr().write(|w| w.set_cpsdvsr(presc));
p.cpsr().write(|w| w.set_cpsdvsr(presc)); p.cr0().write(|w| {
p.cr0().write(|w| { w.set_dss(0b0111); // 8bit
w.set_dss(0b0111); // 8bit w.set_spo(config.polarity == Polarity::IdleHigh);
w.set_spo(config.polarity == Polarity::IdleHigh); w.set_sph(config.phase == Phase::CaptureOnSecondTransition);
w.set_sph(config.phase == Phase::CaptureOnSecondTransition); w.set_scr(postdiv);
w.set_scr(postdiv); });
});
}
} }
} }

View File

@ -34,13 +34,11 @@ embassy_time::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{
impl Driver for TimerDriver { impl Driver for TimerDriver {
fn now(&self) -> u64 { fn now(&self) -> u64 {
loop { loop {
unsafe { let hi = pac::TIMER.timerawh().read();
let hi = pac::TIMER.timerawh().read(); let lo = pac::TIMER.timerawl().read();
let lo = pac::TIMER.timerawl().read(); let hi2 = pac::TIMER.timerawh().read();
let hi2 = pac::TIMER.timerawh().read(); if hi == hi2 {
if hi == hi2 { return (hi as u64) << 32 | (lo as u64);
return (hi as u64) << 32 | (lo as u64);
}
} }
} }
} }
@ -78,13 +76,13 @@ impl Driver for TimerDriver {
// Note that we're not checking the high bits at all. This means the irq may fire early // Note that we're not checking the high bits at all. This means the irq may fire early
// if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire // if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire
// it is checked if the alarm time has passed. // it is checked if the alarm time has passed.
unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) }; pac::TIMER.alarm(n).write_value(timestamp as u32);
let now = self.now(); let now = self.now();
if timestamp <= now { if timestamp <= now {
// If alarm timestamp has passed the alarm will not fire. // If alarm timestamp has passed the alarm will not fire.
// Disarm the alarm and return `false` to indicate that. // Disarm the alarm and return `false` to indicate that.
unsafe { pac::TIMER.armed().write(|w| w.set_armed(1 << n)) } pac::TIMER.armed().write(|w| w.set_armed(1 << n));
alarm.timestamp.set(u64::MAX); alarm.timestamp.set(u64::MAX);
@ -106,17 +104,17 @@ impl TimerDriver {
} else { } else {
// Not elapsed, arm it again. // Not elapsed, arm it again.
// This can happen if it was set more than 2^32 us in the future. // This can happen if it was set more than 2^32 us in the future.
unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) }; pac::TIMER.alarm(n).write_value(timestamp as u32);
} }
}); });
// clear the irq // clear the irq
unsafe { pac::TIMER.intr().write(|w| w.set_alarm(n, true)) } pac::TIMER.intr().write(|w| w.set_alarm(n, true));
} }
fn trigger_alarm(&self, n: usize, cs: CriticalSection) { fn trigger_alarm(&self, n: usize, cs: CriticalSection) {
// disarm // disarm
unsafe { pac::TIMER.armed().write(|w| w.set_armed(1 << n)) } pac::TIMER.armed().write(|w| w.set_armed(1 << n));
let alarm = &self.alarms.borrow(cs)[n]; let alarm = &self.alarms.borrow(cs)[n];
alarm.timestamp.set(u64::MAX); alarm.timestamp.set(u64::MAX);
@ -153,24 +151,24 @@ pub unsafe fn init() {
#[cfg(feature = "rt")] #[cfg(feature = "rt")]
#[interrupt] #[interrupt]
unsafe fn TIMER_IRQ_0() { fn TIMER_IRQ_0() {
DRIVER.check_alarm(0) DRIVER.check_alarm(0)
} }
#[cfg(feature = "rt")] #[cfg(feature = "rt")]
#[interrupt] #[interrupt]
unsafe fn TIMER_IRQ_1() { fn TIMER_IRQ_1() {
DRIVER.check_alarm(1) DRIVER.check_alarm(1)
} }
#[cfg(feature = "rt")] #[cfg(feature = "rt")]
#[interrupt] #[interrupt]
unsafe fn TIMER_IRQ_2() { fn TIMER_IRQ_2() {
DRIVER.check_alarm(2) DRIVER.check_alarm(2)
} }
#[cfg(feature = "rt")] #[cfg(feature = "rt")]
#[interrupt] #[interrupt]
unsafe fn TIMER_IRQ_3() { fn TIMER_IRQ_3() {
DRIVER.check_alarm(3) DRIVER.check_alarm(3)
} }

View File

@ -73,16 +73,14 @@ pub(crate) fn init_buffers<'d, T: Instance + 'd>(
// we clear it after it happens. The downside is that the we manually have // we clear it after it happens. The downside is that the we manually have
// to pend the ISR when we want data transmission to start. // to pend the ISR when we want data transmission to start.
let regs = T::regs(); let regs = T::regs();
unsafe { regs.uartimsc().write(|w| {
regs.uartimsc().write(|w| { w.set_rxim(true);
w.set_rxim(true); w.set_rtim(true);
w.set_rtim(true); w.set_txim(true);
w.set_txim(true); });
});
T::Interrupt::unpend(); T::Interrupt::unpend();
T::Interrupt::enable(); unsafe { T::Interrupt::enable() };
};
} }
impl<'d, T: Instance> BufferedUart<'d, T> { impl<'d, T: Instance> BufferedUart<'d, T> {
@ -247,12 +245,10 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
// (Re-)Enable the interrupt to receive more data in case it was // (Re-)Enable the interrupt to receive more data in case it was
// disabled because the buffer was full or errors were detected. // disabled because the buffer was full or errors were detected.
let regs = T::regs(); let regs = T::regs();
unsafe { regs.uartimsc().write_set(|w| {
regs.uartimsc().write_set(|w| { w.set_rxim(true);
w.set_rxim(true); w.set_rtim(true);
w.set_rtim(true); });
});
}
Poll::Ready(result) Poll::Ready(result)
} }
@ -299,12 +295,10 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
// (Re-)Enable the interrupt to receive more data in case it was // (Re-)Enable the interrupt to receive more data in case it was
// disabled because the buffer was full or errors were detected. // disabled because the buffer was full or errors were detected.
let regs = T::regs(); let regs = T::regs();
unsafe { regs.uartimsc().write_set(|w| {
regs.uartimsc().write_set(|w| { w.set_rxim(true);
w.set_rxim(true); w.set_rtim(true);
w.set_rtim(true); });
});
}
} }
} }
@ -414,7 +408,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
} }
pub fn busy(&self) -> bool { pub fn busy(&self) -> bool {
unsafe { T::regs().uartfr().read().busy() } T::regs().uartfr().read().busy()
} }
/// Assert a break condition after waiting for the transmit buffers to empty, /// Assert a break condition after waiting for the transmit buffers to empty,
@ -426,42 +420,35 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
/// for the transmit fifo to empty, which may take a while on slow links. /// for the transmit fifo to empty, which may take a while on slow links.
pub async fn send_break(&mut self, bits: u32) { pub async fn send_break(&mut self, bits: u32) {
let regs = T::regs(); let regs = T::regs();
let bits = bits.max(unsafe { let bits = bits.max({
let lcr = regs.uartlcr_h().read(); let lcr = regs.uartlcr_h().read();
let width = lcr.wlen() as u32 + 5; let width = lcr.wlen() as u32 + 5;
let parity = lcr.pen() as u32; let parity = lcr.pen() as u32;
let stops = 1 + lcr.stp2() as u32; let stops = 1 + lcr.stp2() as u32;
2 * (1 + width + parity + stops) 2 * (1 + width + parity + stops)
}); });
let divx64 = unsafe { let divx64 = (((regs.uartibrd().read().baud_divint() as u32) << 6)
((regs.uartibrd().read().baud_divint() as u32) << 6) + regs.uartfbrd().read().baud_divfrac() as u32 + regs.uartfbrd().read().baud_divfrac() as u32) as u64;
} as u64;
let div_clk = clk_peri_freq() as u64 * 64; let div_clk = clk_peri_freq() as u64 * 64;
let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk; let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk;
Self::flush().await.unwrap(); Self::flush().await.unwrap();
while self.busy() {} while self.busy() {}
unsafe { regs.uartlcr_h().write_set(|w| w.set_brk(true));
regs.uartlcr_h().write_set(|w| w.set_brk(true));
}
Timer::after(Duration::from_micros(wait_usecs)).await; Timer::after(Duration::from_micros(wait_usecs)).await;
unsafe { regs.uartlcr_h().write_clear(|w| w.set_brk(true));
regs.uartlcr_h().write_clear(|w| w.set_brk(true));
}
} }
} }
impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> { impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> {
fn drop(&mut self) { fn drop(&mut self) {
let state = T::buffered_state(); let state = T::buffered_state();
unsafe { unsafe { state.rx_buf.deinit() }
state.rx_buf.deinit();
// TX is inactive if the the buffer is not available. // TX is inactive if the the buffer is not available.
// We can now unregister the interrupt handler // We can now unregister the interrupt handler
if state.tx_buf.len() == 0 { if state.tx_buf.len() == 0 {
T::Interrupt::disable(); T::Interrupt::disable();
}
} }
} }
} }
@ -469,14 +456,12 @@ impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> {
impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> { impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> {
fn drop(&mut self) { fn drop(&mut self) {
let state = T::buffered_state(); let state = T::buffered_state();
unsafe { unsafe { state.tx_buf.deinit() }
state.tx_buf.deinit();
// RX is inactive if the the buffer is not available. // RX is inactive if the the buffer is not available.
// We can now unregister the interrupt handler // We can now unregister the interrupt handler
if state.rx_buf.len() == 0 { if state.rx_buf.len() == 0 {
T::Interrupt::disable(); T::Interrupt::disable();
}
} }
} }
} }
@ -494,94 +479,92 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterr
let s = T::buffered_state(); let s = T::buffered_state();
unsafe { // Clear TX and error interrupt flags
// Clear TX and error interrupt flags // RX interrupt flags are cleared by reading from the FIFO.
// RX interrupt flags are cleared by reading from the FIFO. let ris = r.uartris().read();
let ris = r.uartris().read(); r.uarticr().write(|w| {
r.uarticr().write(|w| { w.set_txic(ris.txris());
w.set_txic(ris.txris()); w.set_feic(ris.feris());
w.set_feic(ris.feris()); w.set_peic(ris.peris());
w.set_peic(ris.peris()); w.set_beic(ris.beris());
w.set_beic(ris.beris()); w.set_oeic(ris.oeris());
w.set_oeic(ris.oeris()); });
});
trace!("on_interrupt ris={:#X}", ris.0); trace!("on_interrupt ris={:#X}", ris.0);
// Errors // Errors
if ris.feris() { if ris.feris() {
warn!("Framing error"); warn!("Framing error");
}
if ris.peris() {
warn!("Parity error");
}
if ris.beris() {
warn!("Break error");
}
if ris.oeris() {
warn!("Overrun error");
}
// RX
let mut rx_writer = s.rx_buf.writer();
let rx_buf = rx_writer.push_slice();
let mut n_read = 0;
let mut error = false;
for rx_byte in rx_buf {
if r.uartfr().read().rxfe() {
break;
}
let dr = r.uartdr().read();
if (dr.0 >> 8) != 0 {
s.rx_error.fetch_or((dr.0 >> 8) as u8, Ordering::Relaxed);
error = true;
// only fill the buffer with valid characters. the current character is fine
// if the error is an overrun, but if we add it to the buffer we'll report
// the overrun one character too late. drop it instead and pretend we were
// a bit slower at draining the rx fifo than we actually were.
// this is consistent with blocking uart error reporting.
break;
}
*rx_byte = dr.data();
n_read += 1;
}
if n_read > 0 {
rx_writer.push_done(n_read);
s.rx_waker.wake();
} else if error {
s.rx_waker.wake();
}
// Disable any further RX interrupts when the buffer becomes full or
// errors have occurred. This lets us buffer additional errors in the
// fifo without needing more error storage locations, and most applications
// will want to do a full reset of their uart state anyway once an error
// has happened.
if s.rx_buf.is_full() || error {
r.uartimsc().write_clear(|w| {
w.set_rxim(true);
w.set_rtim(true);
});
}
// TX
let mut tx_reader = s.tx_buf.reader();
let tx_buf = tx_reader.pop_slice();
let mut n_written = 0;
for tx_byte in tx_buf.iter_mut() {
if r.uartfr().read().txff() {
break;
}
r.uartdr().write(|w| w.set_data(*tx_byte));
n_written += 1;
}
if n_written > 0 {
tx_reader.pop_done(n_written);
s.tx_waker.wake();
}
// The TX interrupt only triggers once when the FIFO threshold is
// crossed. No need to disable it when the buffer becomes empty
// as it does re-trigger anymore once we have cleared it.
} }
if ris.peris() {
warn!("Parity error");
}
if ris.beris() {
warn!("Break error");
}
if ris.oeris() {
warn!("Overrun error");
}
// RX
let mut rx_writer = unsafe { s.rx_buf.writer() };
let rx_buf = rx_writer.push_slice();
let mut n_read = 0;
let mut error = false;
for rx_byte in rx_buf {
if r.uartfr().read().rxfe() {
break;
}
let dr = r.uartdr().read();
if (dr.0 >> 8) != 0 {
s.rx_error.fetch_or((dr.0 >> 8) as u8, Ordering::Relaxed);
error = true;
// only fill the buffer with valid characters. the current character is fine
// if the error is an overrun, but if we add it to the buffer we'll report
// the overrun one character too late. drop it instead and pretend we were
// a bit slower at draining the rx fifo than we actually were.
// this is consistent with blocking uart error reporting.
break;
}
*rx_byte = dr.data();
n_read += 1;
}
if n_read > 0 {
rx_writer.push_done(n_read);
s.rx_waker.wake();
} else if error {
s.rx_waker.wake();
}
// Disable any further RX interrupts when the buffer becomes full or
// errors have occurred. This lets us buffer additional errors in the
// fifo without needing more error storage locations, and most applications
// will want to do a full reset of their uart state anyway once an error
// has happened.
if s.rx_buf.is_full() || error {
r.uartimsc().write_clear(|w| {
w.set_rxim(true);
w.set_rtim(true);
});
}
// TX
let mut tx_reader = unsafe { s.tx_buf.reader() };
let tx_buf = tx_reader.pop_slice();
let mut n_written = 0;
for tx_byte in tx_buf.iter_mut() {
if r.uartfr().read().txff() {
break;
}
r.uartdr().write(|w| w.set_data(*tx_byte));
n_written += 1;
}
if n_written > 0 {
tx_reader.pop_done(n_written);
s.tx_waker.wake();
}
// The TX interrupt only triggers once when the FIFO threshold is
// crossed. No need to disable it when the buffer becomes empty
// as it does re-trigger anymore once we have cleared it.
} }
} }
@ -695,24 +678,22 @@ mod eh02 {
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
let r = T::regs(); let r = T::regs();
unsafe { if r.uartfr().read().rxfe() {
if r.uartfr().read().rxfe() { return Err(nb::Error::WouldBlock);
return Err(nb::Error::WouldBlock); }
}
let dr = r.uartdr().read(); let dr = r.uartdr().read();
if dr.oe() { if dr.oe() {
Err(nb::Error::Other(Error::Overrun)) Err(nb::Error::Other(Error::Overrun))
} else if dr.be() { } else if dr.be() {
Err(nb::Error::Other(Error::Break)) Err(nb::Error::Other(Error::Break))
} else if dr.pe() { } else if dr.pe() {
Err(nb::Error::Other(Error::Parity)) Err(nb::Error::Other(Error::Parity))
} else if dr.fe() { } else if dr.fe() {
Err(nb::Error::Other(Error::Framing)) Err(nb::Error::Other(Error::Framing))
} else { } else {
Ok(dr.data()) Ok(dr.data())
}
} }
} }
} }

View File

@ -146,23 +146,21 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
let r = T::regs(); let r = T::regs();
unsafe { for &b in buffer {
for &b in buffer { while r.uartfr().read().txff() {}
while r.uartfr().read().txff() {} r.uartdr().write(|w| w.set_data(b));
r.uartdr().write(|w| w.set_data(b));
}
} }
Ok(()) Ok(())
} }
pub fn blocking_flush(&mut self) -> Result<(), Error> { pub fn blocking_flush(&mut self) -> Result<(), Error> {
let r = T::regs(); let r = T::regs();
unsafe { while !r.uartfr().read().txfe() {} } while !r.uartfr().read().txfe() {}
Ok(()) Ok(())
} }
pub fn busy(&self) -> bool { pub fn busy(&self) -> bool {
unsafe { T::regs().uartfr().read().busy() } T::regs().uartfr().read().busy()
} }
/// Assert a break condition after waiting for the transmit buffers to empty, /// Assert a break condition after waiting for the transmit buffers to empty,
@ -174,28 +172,23 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
/// for the transmit fifo to empty, which may take a while on slow links. /// for the transmit fifo to empty, which may take a while on slow links.
pub async fn send_break(&mut self, bits: u32) { pub async fn send_break(&mut self, bits: u32) {
let regs = T::regs(); let regs = T::regs();
let bits = bits.max(unsafe { let bits = bits.max({
let lcr = regs.uartlcr_h().read(); let lcr = regs.uartlcr_h().read();
let width = lcr.wlen() as u32 + 5; let width = lcr.wlen() as u32 + 5;
let parity = lcr.pen() as u32; let parity = lcr.pen() as u32;
let stops = 1 + lcr.stp2() as u32; let stops = 1 + lcr.stp2() as u32;
2 * (1 + width + parity + stops) 2 * (1 + width + parity + stops)
}); });
let divx64 = unsafe { let divx64 = (((regs.uartibrd().read().baud_divint() as u32) << 6)
((regs.uartibrd().read().baud_divint() as u32) << 6) + regs.uartfbrd().read().baud_divfrac() as u32 + regs.uartfbrd().read().baud_divfrac() as u32) as u64;
} as u64;
let div_clk = clk_peri_freq() as u64 * 64; let div_clk = clk_peri_freq() as u64 * 64;
let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk; let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk;
self.blocking_flush().unwrap(); self.blocking_flush().unwrap();
while self.busy() {} while self.busy() {}
unsafe { regs.uartlcr_h().write_set(|w| w.set_brk(true));
regs.uartlcr_h().write_set(|w| w.set_brk(true));
}
Timer::after(Duration::from_micros(wait_usecs)).await; Timer::after(Duration::from_micros(wait_usecs)).await;
unsafe { regs.uartlcr_h().write_clear(|w| w.set_brk(true));
regs.uartlcr_h().write_clear(|w| w.set_brk(true));
}
} }
} }
@ -221,7 +214,7 @@ impl<'d, T: Instance> UartTx<'d, T, Async> {
}); });
// If we don't assign future to a variable, the data register pointer // If we don't assign future to a variable, the data register pointer
// is held across an await and makes the future non-Send. // is held across an await and makes the future non-Send.
crate::dma::write(ch, buffer, T::regs().uartdr().ptr() as *mut _, T::TX_DREQ) crate::dma::write(ch, buffer, T::regs().uartdr().as_ptr() as *mut _, T::TX_DREQ)
}; };
transfer.await; transfer.await;
Ok(()) Ok(())
@ -246,7 +239,7 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
debug_assert_eq!(has_irq, rx_dma.is_some()); debug_assert_eq!(has_irq, rx_dma.is_some());
if has_irq { if has_irq {
// disable all error interrupts initially // disable all error interrupts initially
unsafe { T::regs().uartimsc().write(|w| w.0 = 0) } T::regs().uartimsc().write(|w| w.0 = 0);
T::Interrupt::unpend(); T::Interrupt::unpend();
unsafe { T::Interrupt::enable() }; unsafe { T::Interrupt::enable() };
} }
@ -267,11 +260,11 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
let r = T::regs(); let r = T::regs();
for (i, b) in buffer.iter_mut().enumerate() { for (i, b) in buffer.iter_mut().enumerate() {
if unsafe { r.uartfr().read().rxfe() } { if r.uartfr().read().rxfe() {
return Ok(i); return Ok(i);
} }
let dr = unsafe { r.uartdr().read() }; let dr = r.uartdr().read();
if dr.oe() { if dr.oe() {
return Err(Error::Overrun); return Err(Error::Overrun);
@ -292,15 +285,13 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> { impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> {
fn drop(&mut self) { fn drop(&mut self) {
if let Some(_) = self.rx_dma { if let Some(_) = self.rx_dma {
unsafe { T::Interrupt::disable();
T::Interrupt::disable(); // clear dma flags. irq handlers use these to disambiguate among themselves.
// clear dma flags. irq handlers use these to disambiguate among themselves. T::regs().uartdmacr().write_clear(|reg| {
T::regs().uartdmacr().write_clear(|reg| { reg.set_rxdmae(true);
reg.set_rxdmae(true); reg.set_txdmae(true);
reg.set_txdmae(true); reg.set_dmaonerr(true);
reg.set_dmaonerr(true); });
});
}
} }
} }
} }
@ -355,14 +346,12 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
// clear error flags before we drain the fifo. errors that have accumulated // clear error flags before we drain the fifo. errors that have accumulated
// in the flags will also be present in the fifo. // in the flags will also be present in the fifo.
T::dma_state().rx_errs.store(0, Ordering::Relaxed); T::dma_state().rx_errs.store(0, Ordering::Relaxed);
unsafe { T::regs().uarticr().write(|w| {
T::regs().uarticr().write(|w| { w.set_oeic(true);
w.set_oeic(true); w.set_beic(true);
w.set_beic(true); w.set_peic(true);
w.set_peic(true); w.set_feic(true);
w.set_feic(true); });
});
}
// then drain the fifo. we need to read at most 32 bytes. errors that apply // then drain the fifo. we need to read at most 32 bytes. errors that apply
// to fifo bytes will be reported directly. // to fifo bytes will be reported directly.
@ -379,20 +368,20 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
// interrupt flags will have been raised, and those will be picked up immediately // interrupt flags will have been raised, and those will be picked up immediately
// by the interrupt handler. // by the interrupt handler.
let ch = self.rx_dma.as_mut().unwrap(); let ch = self.rx_dma.as_mut().unwrap();
T::regs().uartimsc().write_set(|w| {
w.set_oeim(true);
w.set_beim(true);
w.set_peim(true);
w.set_feim(true);
});
T::regs().uartdmacr().write_set(|reg| {
reg.set_rxdmae(true);
reg.set_dmaonerr(true);
});
let transfer = unsafe { let transfer = unsafe {
T::regs().uartimsc().write_set(|w| {
w.set_oeim(true);
w.set_beim(true);
w.set_peim(true);
w.set_feim(true);
});
T::regs().uartdmacr().write_set(|reg| {
reg.set_rxdmae(true);
reg.set_dmaonerr(true);
});
// If we don't assign future to a variable, the data register pointer // If we don't assign future to a variable, the data register pointer
// is held across an await and makes the future non-Send. // is held across an await and makes the future non-Send.
crate::dma::read(ch, T::regs().uartdr().ptr() as *const _, buffer, T::RX_DREQ) crate::dma::read(ch, T::regs().uartdr().as_ptr() as *const _, buffer, T::RX_DREQ)
}; };
// wait for either the transfer to complete or an error to happen. // wait for either the transfer to complete or an error to happen.
@ -575,81 +564,79 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
config: Config, config: Config,
) { ) {
let r = T::regs(); let r = T::regs();
unsafe { if let Some(pin) = &tx {
if let Some(pin) = &tx { pin.io().ctrl().write(|w| {
pin.io().ctrl().write(|w| { w.set_funcsel(2);
w.set_funcsel(2); w.set_outover(if config.invert_tx {
w.set_outover(if config.invert_tx { Outover::INVERT
Outover::INVERT } else {
} else { Outover::NORMAL
Outover::NORMAL
});
}); });
pin.pad_ctrl().write(|w| w.set_ie(true));
}
if let Some(pin) = &rx {
pin.io().ctrl().write(|w| {
w.set_funcsel(2);
w.set_inover(if config.invert_rx {
Inover::INVERT
} else {
Inover::NORMAL
});
});
pin.pad_ctrl().write(|w| w.set_ie(true));
}
if let Some(pin) = &cts {
pin.io().ctrl().write(|w| {
w.set_funcsel(2);
w.set_inover(if config.invert_cts {
Inover::INVERT
} else {
Inover::NORMAL
});
});
pin.pad_ctrl().write(|w| w.set_ie(true));
}
if let Some(pin) = &rts {
pin.io().ctrl().write(|w| {
w.set_funcsel(2);
w.set_outover(if config.invert_rts {
Outover::INVERT
} else {
Outover::NORMAL
});
});
pin.pad_ctrl().write(|w| w.set_ie(true));
}
Self::set_baudrate_inner(config.baudrate);
let (pen, eps) = match config.parity {
Parity::ParityNone => (false, false),
Parity::ParityOdd => (true, false),
Parity::ParityEven => (true, true),
};
r.uartlcr_h().write(|w| {
w.set_wlen(config.data_bits.bits());
w.set_stp2(config.stop_bits == StopBits::STOP2);
w.set_pen(pen);
w.set_eps(eps);
w.set_fen(true);
});
r.uartifls().write(|w| {
w.set_rxiflsel(0b000);
w.set_txiflsel(0b000);
});
r.uartcr().write(|w| {
w.set_uarten(true);
w.set_rxe(true);
w.set_txe(true);
w.set_ctsen(cts.is_some());
w.set_rtsen(rts.is_some());
}); });
pin.pad_ctrl().write(|w| w.set_ie(true));
} }
if let Some(pin) = &rx {
pin.io().ctrl().write(|w| {
w.set_funcsel(2);
w.set_inover(if config.invert_rx {
Inover::INVERT
} else {
Inover::NORMAL
});
});
pin.pad_ctrl().write(|w| w.set_ie(true));
}
if let Some(pin) = &cts {
pin.io().ctrl().write(|w| {
w.set_funcsel(2);
w.set_inover(if config.invert_cts {
Inover::INVERT
} else {
Inover::NORMAL
});
});
pin.pad_ctrl().write(|w| w.set_ie(true));
}
if let Some(pin) = &rts {
pin.io().ctrl().write(|w| {
w.set_funcsel(2);
w.set_outover(if config.invert_rts {
Outover::INVERT
} else {
Outover::NORMAL
});
});
pin.pad_ctrl().write(|w| w.set_ie(true));
}
Self::set_baudrate_inner(config.baudrate);
let (pen, eps) = match config.parity {
Parity::ParityNone => (false, false),
Parity::ParityOdd => (true, false),
Parity::ParityEven => (true, true),
};
r.uartlcr_h().write(|w| {
w.set_wlen(config.data_bits.bits());
w.set_stp2(config.stop_bits == StopBits::STOP2);
w.set_pen(pen);
w.set_eps(eps);
w.set_fen(true);
});
r.uartifls().write(|w| {
w.set_rxiflsel(0b000);
w.set_txiflsel(0b000);
});
r.uartcr().write(|w| {
w.set_uarten(true);
w.set_rxe(true);
w.set_txe(true);
w.set_ctsen(cts.is_some());
w.set_rtsen(rts.is_some());
});
} }
/// sets baudrate on runtime /// sets baudrate on runtime
@ -674,15 +661,13 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
baud_fbrd = 0; baud_fbrd = 0;
} }
unsafe { // Load PL011's baud divisor registers
// Load PL011's baud divisor registers r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd)); r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
// PL011 needs a (dummy) line control register write to latch in the // PL011 needs a (dummy) line control register write to latch in the
// divisors. We don't want to actually change LCR contents here. // divisors. We don't want to actually change LCR contents here.
r.uartlcr_h().modify(|_| {}); r.uartlcr_h().modify(|_| {});
}
} }
} }
@ -731,24 +716,22 @@ mod eh02 {
type Error = Error; type Error = Error;
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
let r = T::regs(); let r = T::regs();
unsafe { if r.uartfr().read().rxfe() {
if r.uartfr().read().rxfe() { return Err(nb::Error::WouldBlock);
return Err(nb::Error::WouldBlock); }
}
let dr = r.uartdr().read(); let dr = r.uartdr().read();
if dr.oe() { if dr.oe() {
Err(nb::Error::Other(Error::Overrun)) Err(nb::Error::Other(Error::Overrun))
} else if dr.be() { } else if dr.be() {
Err(nb::Error::Other(Error::Break)) Err(nb::Error::Other(Error::Break))
} else if dr.pe() { } else if dr.pe() {
Err(nb::Error::Other(Error::Parity)) Err(nb::Error::Other(Error::Parity))
} else if dr.fe() { } else if dr.fe() {
Err(nb::Error::Other(Error::Framing)) Err(nb::Error::Other(Error::Framing))
} else { } else {
Ok(dr.data()) Ok(dr.data())
}
} }
} }
} }
@ -758,22 +741,18 @@ mod eh02 {
fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> { fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> {
let r = T::regs(); let r = T::regs();
unsafe { if r.uartfr().read().txff() {
if r.uartfr().read().txff() { return Err(nb::Error::WouldBlock);
return Err(nb::Error::WouldBlock);
}
r.uartdr().write(|w| w.set_data(word));
} }
r.uartdr().write(|w| w.set_data(word));
Ok(()) Ok(())
} }
fn flush(&mut self) -> Result<(), nb::Error<Self::Error>> { fn flush(&mut self) -> Result<(), nb::Error<Self::Error>> {
let r = T::regs(); let r = T::regs();
unsafe { if !r.uartfr().read().txfe() {
if !r.uartfr().read().txfe() { return Err(nb::Error::WouldBlock);
return Err(nb::Error::WouldBlock);
}
} }
Ok(()) Ok(())
} }
@ -854,22 +833,20 @@ mod eh1 {
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> { impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> {
fn read(&mut self) -> nb::Result<u8, Self::Error> { fn read(&mut self) -> nb::Result<u8, Self::Error> {
let r = T::regs(); let r = T::regs();
unsafe { let dr = r.uartdr().read();
let dr = r.uartdr().read();
if dr.oe() { if dr.oe() {
Err(nb::Error::Other(Error::Overrun)) Err(nb::Error::Other(Error::Overrun))
} else if dr.be() { } else if dr.be() {
Err(nb::Error::Other(Error::Break)) Err(nb::Error::Other(Error::Break))
} else if dr.pe() { } else if dr.pe() {
Err(nb::Error::Other(Error::Parity)) Err(nb::Error::Other(Error::Parity))
} else if dr.fe() { } else if dr.fe() {
Err(nb::Error::Other(Error::Framing)) Err(nb::Error::Other(Error::Framing))
} else if dr.fe() { } else if dr.fe() {
Ok(dr.data()) Ok(dr.data())
} else { } else {
Err(nb::Error::WouldBlock) Err(nb::Error::WouldBlock)
}
} }
} }
} }

View File

@ -39,7 +39,7 @@ impl crate::usb::Instance for peripherals::USB {
const EP_COUNT: usize = 16; const EP_COUNT: usize = 16;
const EP_MEMORY_SIZE: usize = 4096; const EP_MEMORY_SIZE: usize = 4096;
const EP_MEMORY: *mut u8 = pac::USBCTRL_DPRAM.0; const EP_MEMORY: *mut u8 = pac::USBCTRL_DPRAM.as_ptr() as *mut u8;
const NEW_AW: AtomicWaker = AtomicWaker::new(); const NEW_AW: AtomicWaker = AtomicWaker::new();
static BUS_WAKER: AtomicWaker = NEW_AW; static BUS_WAKER: AtomicWaker = NEW_AW;
@ -111,7 +111,7 @@ impl<'d, T: Instance> Driver<'d, T> {
let regs = T::regs(); let regs = T::regs();
unsafe { unsafe {
// zero fill regs // zero fill regs
let p = regs.0 as *mut u32; let p = regs.as_ptr() as *mut u32;
for i in 0..0x9c / 4 { for i in 0..0x9c / 4 {
p.add(i).write_volatile(0) p.add(i).write_volatile(0)
} }
@ -121,20 +121,20 @@ impl<'d, T: Instance> Driver<'d, T> {
for i in 0..0x100 / 4 { for i in 0..0x100 / 4 {
p.add(i).write_volatile(0) p.add(i).write_volatile(0)
} }
regs.usb_muxing().write(|w| {
w.set_to_phy(true);
w.set_softcon(true);
});
regs.usb_pwr().write(|w| {
w.set_vbus_detect(true);
w.set_vbus_detect_override_en(true);
});
regs.main_ctrl().write(|w| {
w.set_controller_en(true);
});
} }
regs.usb_muxing().write(|w| {
w.set_to_phy(true);
w.set_softcon(true);
});
regs.usb_pwr().write(|w| {
w.set_vbus_detect(true);
w.set_vbus_detect_override_en(true);
});
regs.main_ctrl().write(|w| {
w.set_controller_en(true);
});
// Initialize the bus so that it signals that power is available // Initialize the bus so that it signals that power is available
BUS_WAKER.wake(); BUS_WAKER.wake();
@ -213,22 +213,18 @@ impl<'d, T: Instance> Driver<'d, T> {
}; };
match D::dir() { match D::dir() {
Direction::Out => unsafe { Direction::Out => T::dpram().ep_out_control(index - 1).write(|w| {
T::dpram().ep_out_control(index - 1).write(|w| { w.set_enable(false);
w.set_enable(false); w.set_buffer_address(addr);
w.set_buffer_address(addr); w.set_interrupt_per_buff(true);
w.set_interrupt_per_buff(true); w.set_endpoint_type(ep_type_reg);
w.set_endpoint_type(ep_type_reg); }),
}) Direction::In => T::dpram().ep_in_control(index - 1).write(|w| {
}, w.set_enable(false);
Direction::In => unsafe { w.set_buffer_address(addr);
T::dpram().ep_in_control(index - 1).write(|w| { w.set_interrupt_per_buff(true);
w.set_enable(false); w.set_endpoint_type(ep_type_reg);
w.set_buffer_address(addr); }),
w.set_interrupt_per_buff(true);
w.set_endpoint_type(ep_type_reg);
})
},
} }
Ok(Endpoint { Ok(Endpoint {
@ -315,22 +311,21 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
let regs = T::regs(); let regs = T::regs();
unsafe { regs.inte().write(|w| {
regs.inte().write(|w| { w.set_bus_reset(true);
w.set_bus_reset(true); w.set_buff_status(true);
w.set_buff_status(true); w.set_dev_resume_from_host(true);
w.set_dev_resume_from_host(true); w.set_dev_suspend(true);
w.set_dev_suspend(true); w.set_setup_req(true);
w.set_setup_req(true); });
}); regs.int_ep_ctrl().write(|w| {
regs.int_ep_ctrl().write(|w| { w.set_int_ep_active(0xFFFE); // all EPs
w.set_int_ep_active(0xFFFE); // all EPs });
}); regs.sie_ctrl().write(|w| {
regs.sie_ctrl().write(|w| { w.set_ep0_int_1buf(true);
w.set_ep0_int_1buf(true); w.set_pullup_en(true);
w.set_pullup_en(true); });
})
}
trace!("enabled"); trace!("enabled");
( (
@ -355,7 +350,7 @@ pub struct Bus<'d, T: Instance> {
impl<'d, T: Instance> driver::Bus for Bus<'d, T> { impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
async fn poll(&mut self) -> Event { async fn poll(&mut self) -> Event {
poll_fn(move |cx| unsafe { poll_fn(move |cx| {
BUS_WAKER.register(cx.waker()); BUS_WAKER.register(cx.waker());
if !self.inited { if !self.inited {
@ -425,14 +420,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
let n = ep_addr.index(); let n = ep_addr.index();
match ep_addr.direction() { match ep_addr.direction() {
Direction::In => unsafe { Direction::In => {
T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled)); T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled));
T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| { T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| {
w.set_pid(0, true); // first packet is DATA0, but PID is flipped before w.set_pid(0, true); // first packet is DATA0, but PID is flipped before
}); });
EP_IN_WAKERS[n].wake(); EP_IN_WAKERS[n].wake();
}, }
Direction::Out => unsafe { Direction::Out => {
T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled)); T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled));
T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| { T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| {
@ -446,7 +441,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
w.set_available(0, true); w.set_available(0, true);
}); });
EP_OUT_WAKERS[n].wake(); EP_OUT_WAKERS[n].wake();
}, }
} }
} }
@ -504,7 +499,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
let index = self.info.addr.index(); let index = self.info.addr.index();
poll_fn(|cx| { poll_fn(|cx| {
EP_IN_WAKERS[index].register(cx.waker()); EP_IN_WAKERS[index].register(cx.waker());
let val = unsafe { T::dpram().ep_in_control(self.info.addr.index() - 1).read() }; let val = T::dpram().ep_in_control(self.info.addr.index() - 1).read();
if val.enable() { if val.enable() {
Poll::Ready(()) Poll::Ready(())
} else { } else {
@ -526,7 +521,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, Out> {
let index = self.info.addr.index(); let index = self.info.addr.index();
poll_fn(|cx| { poll_fn(|cx| {
EP_OUT_WAKERS[index].register(cx.waker()); EP_OUT_WAKERS[index].register(cx.waker());
let val = unsafe { T::dpram().ep_out_control(self.info.addr.index() - 1).read() }; let val = T::dpram().ep_out_control(self.info.addr.index() - 1).read();
if val.enable() { if val.enable() {
Poll::Ready(()) Poll::Ready(())
} else { } else {
@ -542,7 +537,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
trace!("READ WAITING, buf.len() = {}", buf.len()); trace!("READ WAITING, buf.len() = {}", buf.len());
let index = self.info.addr.index(); let index = self.info.addr.index();
let val = poll_fn(|cx| unsafe { let val = poll_fn(|cx| {
EP_OUT_WAKERS[index].register(cx.waker()); EP_OUT_WAKERS[index].register(cx.waker());
let val = T::dpram().ep_out_buffer_control(index).read(); let val = T::dpram().ep_out_buffer_control(index).read();
if val.available(0) { if val.available(0) {
@ -561,19 +556,17 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
trace!("READ OK, rx_len = {}", rx_len); trace!("READ OK, rx_len = {}", rx_len);
unsafe { let pid = !val.pid(0);
let pid = !val.pid(0); T::dpram().ep_out_buffer_control(index).write(|w| {
T::dpram().ep_out_buffer_control(index).write(|w| { w.set_pid(0, pid);
w.set_pid(0, pid); w.set_length(0, self.info.max_packet_size);
w.set_length(0, self.info.max_packet_size); });
}); cortex_m::asm::delay(12);
cortex_m::asm::delay(12); T::dpram().ep_out_buffer_control(index).write(|w| {
T::dpram().ep_out_buffer_control(index).write(|w| { w.set_pid(0, pid);
w.set_pid(0, pid); w.set_length(0, self.info.max_packet_size);
w.set_length(0, self.info.max_packet_size); w.set_available(0, true);
w.set_available(0, true); });
});
}
Ok(rx_len) Ok(rx_len)
} }
@ -588,7 +581,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
trace!("WRITE WAITING"); trace!("WRITE WAITING");
let index = self.info.addr.index(); let index = self.info.addr.index();
let val = poll_fn(|cx| unsafe { let val = poll_fn(|cx| {
EP_IN_WAKERS[index].register(cx.waker()); EP_IN_WAKERS[index].register(cx.waker());
let val = T::dpram().ep_in_buffer_control(index).read(); let val = T::dpram().ep_in_buffer_control(index).read();
if val.available(0) { if val.available(0) {
@ -601,21 +594,19 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
self.buf.write(buf); self.buf.write(buf);
unsafe { let pid = !val.pid(0);
let pid = !val.pid(0); T::dpram().ep_in_buffer_control(index).write(|w| {
T::dpram().ep_in_buffer_control(index).write(|w| { w.set_pid(0, pid);
w.set_pid(0, pid); w.set_length(0, buf.len() as _);
w.set_length(0, buf.len() as _); w.set_full(0, true);
w.set_full(0, true); });
}); cortex_m::asm::delay(12);
cortex_m::asm::delay(12); T::dpram().ep_in_buffer_control(index).write(|w| {
T::dpram().ep_in_buffer_control(index).write(|w| { w.set_pid(0, pid);
w.set_pid(0, pid); w.set_length(0, buf.len() as _);
w.set_length(0, buf.len() as _); w.set_full(0, true);
w.set_full(0, true); w.set_available(0, true);
w.set_available(0, true); });
});
}
trace!("WRITE OK"); trace!("WRITE OK");
@ -637,9 +628,9 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
loop { loop {
trace!("SETUP read waiting"); trace!("SETUP read waiting");
let regs = T::regs(); let regs = T::regs();
unsafe { regs.inte().write_set(|w| w.set_setup_req(true)) }; regs.inte().write_set(|w| w.set_setup_req(true));
poll_fn(|cx| unsafe { poll_fn(|cx| {
EP_OUT_WAKERS[0].register(cx.waker()); EP_OUT_WAKERS[0].register(cx.waker());
let regs = T::regs(); let regs = T::regs();
if regs.sie_status().read().setup_rec() { if regs.sie_status().read().setup_rec() {
@ -654,13 +645,11 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
EndpointBuffer::<T>::new(0, 8).read(&mut buf); EndpointBuffer::<T>::new(0, 8).read(&mut buf);
let regs = T::regs(); let regs = T::regs();
unsafe { regs.sie_status().write(|w| w.set_setup_rec(true));
regs.sie_status().write(|w| w.set_setup_rec(true));
// set PID to 0, so (after toggling) first DATA is PID 1 // set PID to 0, so (after toggling) first DATA is PID 1
T::dpram().ep_in_buffer_control(0).write(|w| w.set_pid(0, false)); T::dpram().ep_in_buffer_control(0).write(|w| w.set_pid(0, false));
T::dpram().ep_out_buffer_control(0).write(|w| w.set_pid(0, false)); T::dpram().ep_out_buffer_control(0).write(|w| w.set_pid(0, false));
}
trace!("SETUP read ok"); trace!("SETUP read ok");
return buf; return buf;
@ -668,23 +657,21 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
} }
async fn data_out(&mut self, buf: &mut [u8], first: bool, last: bool) -> Result<usize, EndpointError> { async fn data_out(&mut self, buf: &mut [u8], first: bool, last: bool) -> Result<usize, EndpointError> {
unsafe { let bufcontrol = T::dpram().ep_out_buffer_control(0);
let bufcontrol = T::dpram().ep_out_buffer_control(0); let pid = !bufcontrol.read().pid(0);
let pid = !bufcontrol.read().pid(0); bufcontrol.write(|w| {
bufcontrol.write(|w| { w.set_length(0, self.max_packet_size);
w.set_length(0, self.max_packet_size); w.set_pid(0, pid);
w.set_pid(0, pid); });
}); cortex_m::asm::delay(12);
cortex_m::asm::delay(12); bufcontrol.write(|w| {
bufcontrol.write(|w| { w.set_length(0, self.max_packet_size);
w.set_length(0, self.max_packet_size); w.set_pid(0, pid);
w.set_pid(0, pid); w.set_available(0, true);
w.set_available(0, true); });
});
}
trace!("control: data_out len={} first={} last={}", buf.len(), first, last); trace!("control: data_out len={} first={} last={}", buf.len(), first, last);
let val = poll_fn(|cx| unsafe { let val = poll_fn(|cx| {
EP_OUT_WAKERS[0].register(cx.waker()); EP_OUT_WAKERS[0].register(cx.waker());
let val = T::dpram().ep_out_buffer_control(0).read(); let val = T::dpram().ep_out_buffer_control(0).read();
if val.available(0) { if val.available(0) {
@ -714,24 +701,22 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
} }
EndpointBuffer::<T>::new(0x100, 64).write(data); EndpointBuffer::<T>::new(0x100, 64).write(data);
unsafe { let bufcontrol = T::dpram().ep_in_buffer_control(0);
let bufcontrol = T::dpram().ep_in_buffer_control(0); let pid = !bufcontrol.read().pid(0);
let pid = !bufcontrol.read().pid(0); bufcontrol.write(|w| {
bufcontrol.write(|w| { w.set_length(0, data.len() as _);
w.set_length(0, data.len() as _); w.set_pid(0, pid);
w.set_pid(0, pid); w.set_full(0, true);
w.set_full(0, true); });
}); cortex_m::asm::delay(12);
cortex_m::asm::delay(12); bufcontrol.write(|w| {
bufcontrol.write(|w| { w.set_length(0, data.len() as _);
w.set_length(0, data.len() as _); w.set_pid(0, pid);
w.set_pid(0, pid); w.set_full(0, true);
w.set_full(0, true); w.set_available(0, true);
w.set_available(0, true); });
});
}
poll_fn(|cx| unsafe { poll_fn(|cx| {
EP_IN_WAKERS[0].register(cx.waker()); EP_IN_WAKERS[0].register(cx.waker());
let bufcontrol = T::dpram().ep_in_buffer_control(0); let bufcontrol = T::dpram().ep_in_buffer_control(0);
if bufcontrol.read().available(0) { if bufcontrol.read().available(0) {
@ -745,19 +730,17 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
if last { if last {
// prepare status phase right away. // prepare status phase right away.
unsafe { let bufcontrol = T::dpram().ep_out_buffer_control(0);
let bufcontrol = T::dpram().ep_out_buffer_control(0); bufcontrol.write(|w| {
bufcontrol.write(|w| { w.set_length(0, 0);
w.set_length(0, 0); w.set_pid(0, true);
w.set_pid(0, true); });
}); cortex_m::asm::delay(12);
cortex_m::asm::delay(12); bufcontrol.write(|w| {
bufcontrol.write(|w| { w.set_length(0, 0);
w.set_length(0, 0); w.set_pid(0, true);
w.set_pid(0, true); w.set_available(0, true);
w.set_available(0, true); });
});
}
} }
Ok(()) Ok(())
@ -767,26 +750,24 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
trace!("control: accept"); trace!("control: accept");
let bufcontrol = T::dpram().ep_in_buffer_control(0); let bufcontrol = T::dpram().ep_in_buffer_control(0);
unsafe { bufcontrol.write(|w| {
bufcontrol.write(|w| { w.set_length(0, 0);
w.set_length(0, 0); w.set_pid(0, true);
w.set_pid(0, true); w.set_full(0, true);
w.set_full(0, true); });
}); cortex_m::asm::delay(12);
cortex_m::asm::delay(12); bufcontrol.write(|w| {
bufcontrol.write(|w| { w.set_length(0, 0);
w.set_length(0, 0); w.set_pid(0, true);
w.set_pid(0, true); w.set_full(0, true);
w.set_full(0, true); w.set_available(0, true);
w.set_available(0, true); });
});
}
// wait for completion before returning, needed so // wait for completion before returning, needed so
// set_address() doesn't happen early. // set_address() doesn't happen early.
poll_fn(|cx| { poll_fn(|cx| {
EP_IN_WAKERS[0].register(cx.waker()); EP_IN_WAKERS[0].register(cx.waker());
if unsafe { bufcontrol.read().available(0) } { if bufcontrol.read().available(0) {
Poll::Pending Poll::Pending
} else { } else {
Poll::Ready(()) Poll::Ready(())
@ -799,14 +780,12 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
trace!("control: reject"); trace!("control: reject");
let regs = T::regs(); let regs = T::regs();
unsafe { regs.ep_stall_arm().write_set(|w| {
regs.ep_stall_arm().write_set(|w| { w.set_ep0_in(true);
w.set_ep0_in(true); w.set_ep0_out(true);
w.set_ep0_out(true); });
}); T::dpram().ep_out_buffer_control(0).write(|w| w.set_stall(true));
T::dpram().ep_out_buffer_control(0).write(|w| w.set_stall(true)); T::dpram().ep_in_buffer_control(0).write(|w| w.set_stall(true));
T::dpram().ep_in_buffer_control(0).write(|w| w.set_stall(true));
}
} }
async fn accept_set_address(&mut self, addr: u8) { async fn accept_set_address(&mut self, addr: u8) {
@ -814,6 +793,6 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
let regs = T::regs(); let regs = T::regs();
trace!("setting addr: {}", addr); trace!("setting addr: {}", addr);
unsafe { regs.addr_endp().write(|w| w.set_address(addr)) } regs.addr_endp().write(|w| w.set_address(addr))
} }
} }

View File

@ -35,45 +35,37 @@ impl Watchdog {
/// * `cycles` - Total number of tick cycles before the next tick is generated. /// * `cycles` - Total number of tick cycles before the next tick is generated.
/// It is expected to be the frequency in MHz of clk_ref. /// It is expected to be the frequency in MHz of clk_ref.
pub fn enable_tick_generation(&mut self, cycles: u8) { pub fn enable_tick_generation(&mut self, cycles: u8) {
unsafe { let watchdog = pac::WATCHDOG;
let watchdog = pac::WATCHDOG; watchdog.tick().write(|w| {
watchdog.tick().write(|w| { w.set_enable(true);
w.set_enable(true); w.set_cycles(cycles.into())
w.set_cycles(cycles.into()) });
});
}
} }
/// Defines whether or not the watchdog timer should be paused when processor(s) are in debug mode /// Defines whether or not the watchdog timer should be paused when processor(s) are in debug mode
/// or when JTAG is accessing bus fabric /// or when JTAG is accessing bus fabric
pub fn pause_on_debug(&mut self, pause: bool) { pub fn pause_on_debug(&mut self, pause: bool) {
unsafe { let watchdog = pac::WATCHDOG;
let watchdog = pac::WATCHDOG; watchdog.ctrl().write(|w| {
watchdog.ctrl().write(|w| { w.set_pause_dbg0(pause);
w.set_pause_dbg0(pause); w.set_pause_dbg1(pause);
w.set_pause_dbg1(pause); w.set_pause_jtag(pause);
w.set_pause_jtag(pause); })
})
}
} }
fn load_counter(&self, counter: u32) { fn load_counter(&self, counter: u32) {
unsafe { let watchdog = pac::WATCHDOG;
let watchdog = pac::WATCHDOG; watchdog.load().write_value(pac::watchdog::regs::Load(counter));
watchdog.load().write_value(pac::watchdog::regs::Load(counter));
}
} }
fn enable(&self, bit: bool) { fn enable(&self, bit: bool) {
unsafe { let watchdog = pac::WATCHDOG;
let watchdog = pac::WATCHDOG; watchdog.ctrl().write(|w| w.set_enable(bit))
watchdog.ctrl().write(|w| w.set_enable(bit))
}
} }
// Configure which hardware will be reset by the watchdog // Configure which hardware will be reset by the watchdog
// (everything except ROSC, XOSC) // (everything except ROSC, XOSC)
unsafe fn configure_wdog_reset_triggers(&self) { fn configure_wdog_reset_triggers(&self) {
let psm = pac::PSM; let psm = pac::PSM;
psm.wdsel().write_value(pac::psm::regs::Wdsel( psm.wdsel().write_value(pac::psm::regs::Wdsel(
0x0001ffff & !(0x01 << 0usize) & !(0x01 << 1usize), 0x0001ffff & !(0x01 << 0usize) & !(0x01 << 1usize),
@ -100,23 +92,19 @@ impl Watchdog {
self.load_value = delay_us * 2; self.load_value = delay_us * 2;
self.enable(false); self.enable(false);
unsafe { self.configure_wdog_reset_triggers();
self.configure_wdog_reset_triggers();
}
self.load_counter(self.load_value); self.load_counter(self.load_value);
self.enable(true); self.enable(true);
} }
/// Trigger a system reset /// Trigger a system reset
pub fn trigger_reset(&mut self) { pub fn trigger_reset(&mut self) {
unsafe { self.configure_wdog_reset_triggers();
self.configure_wdog_reset_triggers(); self.pause_on_debug(false);
self.pause_on_debug(false); self.enable(true);
self.enable(true); let watchdog = pac::WATCHDOG;
let watchdog = pac::WATCHDOG; watchdog.ctrl().write(|w| {
watchdog.ctrl().write(|w| { w.set_trigger(true);
w.set_trigger(true); })
})
}
} }
} }

View File

@ -18,11 +18,9 @@ async fn main(_spawner: Spawner) {
const PI_F: f32 = 3.1415926535f32; const PI_F: f32 = 3.1415926535f32;
const PI_D: f64 = 3.14159265358979323846f64; const PI_D: f64 = 3.14159265358979323846f64;
unsafe { pac::BUSCTRL
pac::BUSCTRL .perfsel(0)
.perfsel(0) .write(|r| r.set_perfsel(pac::busctrl::vals::Perfsel::ROM));
.write(|r| r.set_perfsel(pac::busctrl::vals::Perfsel::ROM));
}
for i in 0..=360 { for i in 0..=360 {
let rad_f = (i as f32) * PI_F / 180.0; let rad_f = (i as f32) * PI_F / 180.0;
@ -46,7 +44,7 @@ async fn main(_spawner: Spawner) {
Timer::after(Duration::from_millis(10)).await; Timer::after(Duration::from_millis(10)).await;
} }
let rom_accesses = unsafe { pac::BUSCTRL.perfctr(0).read().perfctr() }; let rom_accesses = pac::BUSCTRL.perfctr(0).read().perfctr();
// every float operation used here uses at least 10 cycles // every float operation used here uses at least 10 cycles
defmt::assert!(rom_accesses >= 360 * 12 * 10); defmt::assert!(rom_accesses >= 360 * 12 * 10);