From 837ebe405feabfbee92e9f5e4fc36a5ac56a281c Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Fri, 16 Jun 2023 01:32:18 +0200
Subject: [PATCH] rp: update rp-pac.

---
 embassy-rp/Cargo.toml                   |   2 +-
 embassy-rp/src/adc.rs                   | 120 +++----
 embassy-rp/src/clocks.rs                |  82 ++---
 embassy-rp/src/critical_section_impl.rs |  19 +-
 embassy-rp/src/dma.rs                   |  48 ++-
 embassy-rp/src/flash.rs                 |   2 +-
 embassy-rp/src/float/div.rs             |  70 ++--
 embassy-rp/src/gpio.rs                  | 170 +++++----
 embassy-rp/src/i2c.rs                   | 312 ++++++++--------
 embassy-rp/src/lib.rs                   |  30 +-
 embassy-rp/src/multicore.rs             |  56 ++-
 embassy-rp/src/pio.rs                   | 450 ++++++++++--------------
 embassy-rp/src/pwm.rs                   |  88 ++---
 embassy-rp/src/reset.rs                 |   4 +-
 embassy-rp/src/rtc/mod.rs               |  81 ++---
 embassy-rp/src/spi.rs                   | 207 +++++------
 embassy-rp/src/timer.rs                 |  30 +-
 embassy-rp/src/uart/buffered.rs         | 275 +++++++--------
 embassy-rp/src/uart/mod.rs              | 317 ++++++++---------
 embassy-rp/src/usb.rs                   | 299 ++++++++--------
 embassy-rp/src/watchdog.rs              |  60 ++--
 tests/rp/src/bin/float.rs               |  10 +-
 22 files changed, 1239 insertions(+), 1493 deletions(-)

diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index b68f95385..49aa6a4d5 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -76,7 +76,7 @@ embedded-storage = { version = "0.3" }
 rand_core = "0.6.4"
 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-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true}
diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs
index f29c4dfe1..b96d5a4a8 100644
--- a/embassy-rp/src/adc.rs
+++ b/embassy-rp/src/adc.rs
@@ -50,16 +50,14 @@ impl<'d> Adc<'d> {
         _irq: impl Binding<interrupt::typelevel::ADC_IRQ_FIFO, InterruptHandler>,
         _config: Config,
     ) -> Self {
-        unsafe {
-            let reset = Self::reset();
-            crate::reset::reset(reset);
-            crate::reset::unreset_wait(reset);
-            let r = Self::regs();
-            // Enable ADC
-            r.cs().write(|w| w.set_en(true));
-            // Wait for ADC ready
-            while !r.cs().read().ready() {}
-        }
+        let reset = Self::reset();
+        crate::reset::reset(reset);
+        crate::reset::unreset_wait(reset);
+        let r = Self::regs();
+        // Enable ADC
+        r.cs().write(|w| w.set_en(true));
+        // Wait for ADC ready
+        while !r.cs().read().ready() {}
 
         // Setup IRQ
         interrupt::ADC_IRQ_FIFO.unpend();
@@ -70,80 +68,70 @@ impl<'d> Adc<'d> {
 
     async fn wait_for_ready() {
         let r = Self::regs();
-        unsafe {
-            r.inte().write(|w| w.set_fifo(true));
-            compiler_fence(Ordering::SeqCst);
-            poll_fn(|cx| {
-                WAKER.register(cx.waker());
-                if r.cs().read().ready() {
-                    return Poll::Ready(());
-                }
-                Poll::Pending
-            })
-            .await;
-        }
+        r.inte().write(|w| w.set_fifo(true));
+        compiler_fence(Ordering::SeqCst);
+        poll_fn(|cx| {
+            WAKER.register(cx.waker());
+            if r.cs().read().ready() {
+                return Poll::Ready(());
+            }
+            Poll::Pending
+        })
+        .await;
     }
 
     pub async fn read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 {
         let r = Self::regs();
-        unsafe {
-            // disable pull-down and pull-up resistors
-            // pull-down resistors are enabled by default
-            pin.pad_ctrl().modify(|w| {
-                w.set_ie(true);
-                let (pu, pd) = (false, false);
-                w.set_pue(pu);
-                w.set_pde(pd);
-            });
-            r.cs().modify(|w| {
-                w.set_ainsel(PIN::channel());
-                w.set_start_once(true)
-            });
-            Self::wait_for_ready().await;
-            r.result().read().result().into()
-        }
+        // disable pull-down and pull-up resistors
+        // pull-down resistors are enabled by default
+        pin.pad_ctrl().modify(|w| {
+            w.set_ie(true);
+            let (pu, pd) = (false, false);
+            w.set_pue(pu);
+            w.set_pde(pd);
+        });
+        r.cs().modify(|w| {
+            w.set_ainsel(PIN::channel());
+            w.set_start_once(true)
+        });
+        Self::wait_for_ready().await;
+        r.result().read().result().into()
     }
 
     pub async fn read_temperature(&mut self) -> u16 {
         let r = Self::regs();
-        unsafe {
-            r.cs().modify(|w| w.set_ts_en(true));
-            if !r.cs().read().ready() {
-                Self::wait_for_ready().await;
-            }
-            r.cs().modify(|w| {
-                w.set_ainsel(4);
-                w.set_start_once(true)
-            });
+        r.cs().modify(|w| w.set_ts_en(true));
+        if !r.cs().read().ready() {
             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 {
         let r = Self::regs();
-        unsafe {
-            r.cs().modify(|w| {
-                w.set_ainsel(PIN::channel());
-                w.set_start_once(true)
-            });
-            while !r.cs().read().ready() {}
-            r.result().read().result().into()
-        }
+        r.cs().modify(|w| {
+            w.set_ainsel(PIN::channel());
+            w.set_start_once(true)
+        });
+        while !r.cs().read().ready() {}
+        r.result().read().result().into()
     }
 
     pub fn blocking_read_temperature(&mut self) -> u16 {
         let r = Self::regs();
-        unsafe {
-            r.cs().modify(|w| w.set_ts_en(true));
-            while !r.cs().read().ready() {}
-            r.cs().modify(|w| {
-                w.set_ainsel(4);
-                w.set_start_once(true)
-            });
-            while !r.cs().read().ready() {}
-            r.result().read().result().into()
-        }
+        r.cs().modify(|w| w.set_ts_en(true));
+        while !r.cs().read().ready() {}
+        r.cs().modify(|w| {
+            w.set_ainsel(4);
+            w.set_start_once(true)
+        });
+        while !r.cs().read().ready() {}
+        r.result().read().result().into()
     }
 }
 
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index 67439fda3..4c6223107 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -542,7 +542,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
     reset::unreset_wait(peris);
 }
 
-unsafe fn configure_rosc(config: RoscConfig) -> u32 {
+fn configure_rosc(config: RoscConfig) -> u32 {
     let p = pac::ROSC;
 
     p.freqa().write(|w| {
@@ -620,7 +620,7 @@ pub fn clk_rtc_freq() -> u16 {
     CLOCKS.rtc.load(Ordering::Relaxed)
 }
 
-unsafe fn start_xosc(crystal_hz: u32) {
+fn start_xosc(crystal_hz: u32) {
     pac::XOSC
         .ctrl()
         .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)]
-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;
     assert!(config.fbdiv >= 16 && config.fbdiv <= 320);
     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> {
         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.map_into(),
@@ -717,12 +715,10 @@ impl<'d, T: Pin> Gpin<'d, T> {
 
 impl<'d, T: Pin> Drop for Gpin<'d, T> {
     fn drop(&mut self) {
-        unsafe {
-            self.gpin
-                .io()
-                .ctrl()
-                .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0));
-        }
+        self.gpin
+            .io()
+            .ctrl()
+            .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 {
         into_ref!(gpout);
 
-        unsafe {
-            gpout.io().ctrl().write(|w| w.set_funcsel(0x08));
-        }
+        gpout.io().ctrl().write(|w| w.set_funcsel(0x08));
 
         Self { gpout }
     }
 
     pub fn set_div(&self, int: u32, frac: u8) {
-        unsafe {
-            let c = pac::CLOCKS;
-            c.clk_gpout_div(self.gpout.number()).write(|w| {
-                w.set_int(int);
-                w.set_frac(frac);
-            });
-        }
+        let c = pac::CLOCKS;
+        c.clk_gpout_div(self.gpout.number()).write(|w| {
+            w.set_int(int);
+            w.set_frac(frac);
+        });
     }
 
     pub fn set_src(&self, src: GpoutSrc) {
-        unsafe {
-            let c = pac::CLOCKS;
-            c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
-                w.set_auxsrc(ClkGpoutCtrlAuxsrc(src as _));
-            });
-        }
+        let c = pac::CLOCKS;
+        c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
+            w.set_auxsrc(ClkGpoutCtrlAuxsrc(src as _));
+        });
     }
 
     pub fn enable(&self) {
-        unsafe {
-            let c = pac::CLOCKS;
-            c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
-                w.set_enable(true);
-            });
-        }
+        let c = pac::CLOCKS;
+        c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
+            w.set_enable(true);
+        });
     }
 
     pub fn disable(&self) {
-        unsafe {
-            let c = pac::CLOCKS;
-            c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
-                w.set_enable(false);
-            });
-        }
+        let c = pac::CLOCKS;
+        c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
+            w.set_enable(false);
+        });
     }
 
     pub fn get_freq(&self) -> u32 {
         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 {
             ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(),
@@ -831,7 +817,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
             _ => 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 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> {
     fn drop(&mut self) {
         self.disable();
-        unsafe {
-            self.gpout
-                .io()
-                .ctrl()
-                .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0));
-        }
+        self.gpout
+            .io()
+            .ctrl()
+            .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0));
     }
 }
 
@@ -864,7 +848,7 @@ impl RoscRng {
         let mut acc = 0;
         for _ in 0..u8::BITS {
             acc <<= 1;
-            acc |= unsafe { random_reg.read().randombit() as u8 };
+            acc |= random_reg.read().randombit() as u8;
         }
         acc
     }
diff --git a/embassy-rp/src/critical_section_impl.rs b/embassy-rp/src/critical_section_impl.rs
index ce284c856..d233e6fab 100644
--- a/embassy-rp/src/critical_section_impl.rs
+++ b/embassy-rp/src/critical_section_impl.rs
@@ -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
     /// already in use somewhere else.
     pub fn try_claim() -> Option<Self> {
-        // Safety: We're only reading from this register
-        unsafe {
-            let lock = pac::SIO.spinlock(N).read();
-            if lock > 0 {
-                Some(Self(core::marker::PhantomData))
-            } else {
-                None
-            }
+        let lock = pac::SIO.spinlock(N).read();
+        if lock > 0 {
+            Some(Self(core::marker::PhantomData))
+        } else {
+            None
         }
     }
 
@@ -120,10 +117,8 @@ where
     ///
     /// Only call this function if you hold the spin-lock.
     pub unsafe fn release() {
-        unsafe {
-            // Write (any value): release the lock
-            pac::SIO.spinlock(N).write_value(1);
-        }
+        // Write (any value): release the lock
+        pac::SIO.spinlock(N).write_value(1);
     }
 }
 
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs
index 25819f03e..1a458778c 100644
--- a/embassy-rp/src/dma.rs
+++ b/embassy-rp/src/dma.rs
@@ -14,7 +14,7 @@ use crate::{interrupt, pac, peripherals};
 
 #[cfg(feature = "rt")]
 #[interrupt]
-unsafe fn DMA_IRQ_0() {
+fn DMA_IRQ_0() {
     let ints0 = pac::DMA.ints0().read().ints0();
     for channel in 0..CHANNEL_COUNT {
         let ctrl_trig = pac::DMA.ch(channel).ctrl_trig().read();
@@ -128,28 +128,26 @@ fn copy_inner<'a, C: Channel>(
 ) -> Transfer<'a, C> {
     into_ref!(ch);
 
-    unsafe {
-        let p = ch.regs();
+    let p = ch.regs();
 
-        p.read_addr().write_value(from as u32);
-        p.write_addr().write_value(to as u32);
-        p.trans_count().write_value(len as u32);
+    p.read_addr().write_value(from as u32);
+    p.write_addr().write_value(to as u32);
+    p.trans_count().write_value(len as u32);
 
-        compiler_fence(Ordering::SeqCst);
+    compiler_fence(Ordering::SeqCst);
 
-        p.ctrl_trig().write(|w| {
-            // TODO: Add all DREQ options to pac vals::TreqSel, and use
-            // `set_treq:sel`
-            w.0 = ((dreq as u32) & 0x3f) << 15usize;
-            w.set_data_size(data_size);
-            w.set_incr_read(incr_read);
-            w.set_incr_write(incr_write);
-            w.set_chain_to(ch.number());
-            w.set_en(true);
-        });
+    p.ctrl_trig().write(|w| {
+        // TODO: Add all DREQ options to pac vals::TreqSel, and use
+        // `set_treq:sel`
+        w.0 = ((dreq as u32) & 0x3f) << 15usize;
+        w.set_data_size(data_size);
+        w.set_incr_read(incr_read);
+        w.set_incr_write(incr_write);
+        w.set_chain_to(ch.number());
+        w.set_en(true);
+    });
 
-        compiler_fence(Ordering::SeqCst);
-    }
+    compiler_fence(Ordering::SeqCst);
     Transfer::new(ch)
 }
 
@@ -169,12 +167,10 @@ impl<'a, C: Channel> Transfer<'a, C> {
 impl<'a, C: Channel> Drop for Transfer<'a, C> {
     fn drop(&mut self) {
         let p = self.channel.regs();
-        unsafe {
-            pac::DMA
-                .chan_abort()
-                .modify(|m| m.set_chan_abort(1 << self.channel.number()));
-            while p.ctrl_trig().read().busy() {}
-        }
+        pac::DMA
+            .chan_abort()
+            .modify(|m| m.set_chan_abort(1 << self.channel.number()));
+        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.
         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
         } else {
             Poll::Ready(())
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs
index 5d928abad..96d2d4541 100644
--- a/embassy-rp/src/flash.rs
+++ b/embassy-rp/src/flash.rs
@@ -167,7 +167,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
     /// - DMA must not access flash memory
     unsafe fn in_ram(&mut self, operation: impl FnOnce()) -> Result<(), Error> {
         // 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 {
             return Err(Error::InvalidCore);
         }
diff --git a/embassy-rp/src/float/div.rs b/embassy-rp/src/float/div.rs
index 094dec446..aff0dcb07 100644
--- a/embassy-rp/src/float/div.rs
+++ b/embassy-rp/src/float/div.rs
@@ -17,45 +17,43 @@ where
 {
     let sio = rp_pac::SIO;
 
-    unsafe {
-        // 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.
-        // 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,
-        // just use an explicit wait.
-        while !sio.div().csr().read().ready() {}
+    // 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.
+    // 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,
+    // just use an explicit wait.
+    while !sio.div().csr().read().ready() {}
 
-        // Read the quotient last, since that's what clears the dirty flag
-        let dividend = sio.div().udividend().read();
-        let divisor = sio.div().udivisor().read();
-        let remainder = sio.div().remainder().read();
-        let quotient = sio.div().quotient().read();
+    // Read the quotient last, since that's what clears the dirty flag
+    let dividend = sio.div().udividend().read();
+    let divisor = sio.div().udivisor().read();
+    let remainder = sio.div().remainder().read();
+    let quotient = sio.div().quotient().read();
 
-        // 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
-        // write happens and the DIRTY flag is set, the interruptor becomes responsible for
-        // restoring our state.
-        let result = f();
+    // 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
+    // write happens and the DIRTY flag is set, the interruptor becomes responsible for
+    // restoring our state.
+    let result = f();
 
-        // 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.
-        // This sets DIRTY, so any interruptor will save the state.
-        sio.div().udividend().write_value(dividend);
-        // If we are interrupted here, the the interruptor may start the calculation using
-        // incorrectly signed inputs, but we'll restore the result ourselves.
-        // This sets DIRTY, so any interruptor will save the state.
-        sio.div().udivisor().write_value(divisor);
-        // 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
-        // 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.
-        sio.div().remainder().write_value(remainder);
-        // State fully restored after the quotient write.  This sets both DIRTY and READY, so
-        // whatever we may have interrupted can read the result.
-        sio.div().quotient().write_value(quotient);
+    // 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.
+    // This sets DIRTY, so any interruptor will save the state.
+    sio.div().udividend().write_value(dividend);
+    // If we are interrupted here, the the interruptor may start the calculation using
+    // incorrectly signed inputs, but we'll restore the result ourselves.
+    // This sets DIRTY, so any interruptor will save the state.
+    sio.div().udivisor().write_value(divisor);
+    // 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
+    // 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.
+    sio.div().remainder().write_value(remainder);
+    // State fully restored after the quotient write.  This sets both DIRTY and READY, so
+    // whatever we may have interrupted can read the result.
+    sio.div().quotient().write_value(quotient);
 
-        result
-    }
+    result
 }
 
 fn save_divider<F, R>(f: F) -> R
@@ -63,7 +61,7 @@ where
     F: FnOnce() -> R,
 {
     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
         // issue it directly without a save/restore.
         f()
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index 66faa2489..ce0d02557 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -144,7 +144,7 @@ pub(crate) unsafe fn init() {
 
 #[cfg(feature = "rt")]
 #[interrupt]
-unsafe fn IO_IRQ_BANK0() {
+fn IO_IRQ_BANK0() {
     let cpu = SIO.cpuid().read() as usize;
     // 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
@@ -185,46 +185,44 @@ struct InputFuture<'a, T: Pin> {
 impl<'d, T: Pin> InputFuture<'d, T> {
     pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self {
         into_ref!(pin);
-        unsafe {
-            let pin_group = (pin.pin() % 8) as usize;
-            // first, clear the INTR register bits. without this INTR will still
-            // contain reports of previous edges, causing the IRQ to fire early
-            // on stale state. clearing these means that we can only detect edges
-            // that occur *after* the clear happened, but since both this and the
-            // alternative are fundamentally racy it's probably fine.
-            // (the alternative being checking the current level and waiting for
-            // its inverse, but that requires reading the current level and thus
-            // missing anything that happened before the level was read.)
-            pac::IO_BANK0.intr(pin.pin() as usize / 8).write(|w| {
-                w.set_edge_high(pin_group, true);
-                w.set_edge_low(pin_group, true);
-            });
+        let pin_group = (pin.pin() % 8) as usize;
+        // first, clear the INTR register bits. without this INTR will still
+        // contain reports of previous edges, causing the IRQ to fire early
+        // on stale state. clearing these means that we can only detect edges
+        // that occur *after* the clear happened, but since both this and the
+        // alternative are fundamentally racy it's probably fine.
+        // (the alternative being checking the current level and waiting for
+        // its inverse, but that requires reading the current level and thus
+        // missing anything that happened before the level was read.)
+        pac::IO_BANK0.intr(pin.pin() as usize / 8).write(|w| {
+            w.set_edge_high(pin_group, true);
+            w.set_edge_low(pin_group, true);
+        });
 
-            // Each INTR register is divided into 8 groups, one group for each
-            // pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW,
-            // and EGDE_HIGH.
-            pin.int_proc()
-                .inte((pin.pin() / 8) as usize)
-                .write_set(|w| match level {
-                    InterruptTrigger::LevelHigh => {
-                        trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin());
-                        w.set_level_high(pin_group, true);
-                    }
-                    InterruptTrigger::LevelLow => {
-                        w.set_level_low(pin_group, true);
-                    }
-                    InterruptTrigger::EdgeHigh => {
-                        w.set_edge_high(pin_group, true);
-                    }
-                    InterruptTrigger::EdgeLow => {
-                        w.set_edge_low(pin_group, true);
-                    }
-                    InterruptTrigger::AnyEdge => {
-                        w.set_edge_high(pin_group, true);
-                        w.set_edge_low(pin_group, true);
-                    }
-                });
-        }
+        // Each INTR register is divided into 8 groups, one group for each
+        // pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW,
+        // and EGDE_HIGH.
+        pin.int_proc()
+            .inte((pin.pin() / 8) as usize)
+            .write_set(|w| match level {
+                InterruptTrigger::LevelHigh => {
+                    trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin());
+                    w.set_level_high(pin_group, true);
+                }
+                InterruptTrigger::LevelLow => {
+                    w.set_level_low(pin_group, true);
+                }
+                InterruptTrigger::EdgeHigh => {
+                    w.set_edge_high(pin_group, true);
+                }
+                InterruptTrigger::EdgeLow => {
+                    w.set_edge_low(pin_group, true);
+                }
+                InterruptTrigger::AnyEdge => {
+                    w.set_edge_high(pin_group, true);
+                    w.set_edge_low(pin_group, true);
+                }
+            });
 
         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
         // pin (there are 4 of these PROC0_INTE0, PROC0_INTE1, PROC0_INTE2, and
         // 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
         // each pin. Each group consists of four trigger levels LEVEL_LOW,
         // 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 {
         into_ref!(pin);
 
-        unsafe {
-            pin.pad_ctrl().write(|w| {
-                w.set_ie(true);
-            });
+        pin.pad_ctrl().write(|w| {
+            w.set_ie(true);
+        });
 
-            pin.io().ctrl().write(|w| {
-                w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0.0);
-            });
-        }
+        pin.io().ctrl().write(|w| {
+            w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0.0);
+        });
 
         Self { pin }
     }
@@ -470,43 +466,37 @@ impl<'d, T: Pin> Flex<'d, T> {
     /// Set the pin's pull.
     #[inline]
     pub fn set_pull(&mut self, pull: Pull) {
-        unsafe {
-            self.pin.pad_ctrl().modify(|w| {
-                w.set_ie(true);
-                let (pu, pd) = match pull {
-                    Pull::Up => (true, false),
-                    Pull::Down => (false, true),
-                    Pull::None => (false, false),
-                };
-                w.set_pue(pu);
-                w.set_pde(pd);
-            });
-        }
+        self.pin.pad_ctrl().modify(|w| {
+            w.set_ie(true);
+            let (pu, pd) = match pull {
+                Pull::Up => (true, false),
+                Pull::Down => (false, true),
+                Pull::None => (false, false),
+            };
+            w.set_pue(pu);
+            w.set_pde(pd);
+        });
     }
 
     /// Set the pin's drive strength.
     #[inline]
     pub fn set_drive_strength(&mut self, strength: Drive) {
-        unsafe {
-            self.pin.pad_ctrl().modify(|w| {
-                w.set_drive(match strength {
-                    Drive::_2mA => pac::pads::vals::Drive::_2MA,
-                    Drive::_4mA => pac::pads::vals::Drive::_4MA,
-                    Drive::_8mA => pac::pads::vals::Drive::_8MA,
-                    Drive::_12mA => pac::pads::vals::Drive::_12MA,
-                });
+        self.pin.pad_ctrl().modify(|w| {
+            w.set_drive(match strength {
+                Drive::_2mA => pac::pads::vals::Drive::_2MA,
+                Drive::_4mA => pac::pads::vals::Drive::_4MA,
+                Drive::_8mA => pac::pads::vals::Drive::_8MA,
+                Drive::_12mA => pac::pads::vals::Drive::_12MA,
             });
-        }
+        });
     }
 
     // Set the pin's slew rate.
     #[inline]
     pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
-        unsafe {
-            self.pin.pad_ctrl().modify(|w| {
-                w.set_slewfast(slew_rate == SlewRate::Fast);
-            });
-        }
+        self.pin.pad_ctrl().modify(|w| {
+            w.set_slewfast(slew_rate == SlewRate::Fast);
+        });
     }
 
     /// Put the pin into input mode.
@@ -514,7 +504,7 @@ impl<'d, T: Pin> Flex<'d, T> {
     /// The pull setting is left unchanged.
     #[inline]
     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.
@@ -523,17 +513,17 @@ impl<'d, T: Pin> Flex<'d, T> {
     /// at a specific level, call `set_high`/`set_low` on the pin first.
     #[inline]
     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]
     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]
     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]
@@ -543,7 +533,7 @@ impl<'d, T: Pin> Flex<'d, T> {
 
     #[inline]
     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
@@ -555,13 +545,13 @@ impl<'d, T: Pin> Flex<'d, T> {
     /// Set the output as high.
     #[inline]
     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.
     #[inline]
     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.
@@ -576,7 +566,7 @@ impl<'d, T: Pin> Flex<'d, T> {
     /// Is the output level high?
     #[inline]
     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?
@@ -594,7 +584,7 @@ impl<'d, T: Pin> Flex<'d, T> {
     /// Toggle pin output
     #[inline]
     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]
@@ -626,12 +616,10 @@ impl<'d, T: Pin> Flex<'d, T> {
 impl<'d, T: Pin> Drop for Flex<'d, T> {
     #[inline]
     fn drop(&mut self) {
-        unsafe {
-            self.pin.pad_ctrl().write(|_| {});
-            self.pin.io().ctrl().write(|w| {
-                w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0);
-            });
-        }
+        self.pin.pad_ctrl().write(|_| {});
+        self.pin.io().ctrl().write(|w| {
+            w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0);
+        });
     }
 }
 
@@ -688,7 +676,7 @@ pub(crate) mod sealed {
                 Bank::Bank0 => crate::pac::IO_BANK0,
                 Bank::Qspi => crate::pac::IO_QSPI,
             };
-            let proc = unsafe { SIO.cpuid().read() };
+            let proc = SIO.cpuid().read();
             io_block.int_proc(proc as _)
         }
     }
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index ce9a082a2..791c64554 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -85,7 +85,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
         let r = T::regs();
 
         // 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();
         unsafe { T::Interrupt::enable() };
 
@@ -135,13 +135,11 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
                 let last = remaining_queue == 0;
                 batch += 1;
 
-                unsafe {
-                    p.ic_data_cmd().write(|w| {
-                        w.set_restart(restart && remaining_queue == buffer.len() - 1);
-                        w.set_stop(last && send_stop);
-                        w.set_cmd(true);
-                    });
-                }
+                p.ic_data_cmd().write(|w| {
+                    w.set_restart(restart && remaining_queue == buffer.len() - 1);
+                    w.set_stop(last && send_stop);
+                    w.set_cmd(true);
+                });
             }
 
             // 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
                         }
                     },
-                    |_me| unsafe {
+                    |_me| {
                         // Set the read threshold to the number of bytes we're
                         // expecting so we don't get spurious interrupts.
                         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 received = buffer.len() - remaining;
                     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;
                 }
@@ -211,13 +209,11 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
                 if let Some(byte) = bytes.next() {
                     let last = bytes.peek().is_none();
 
-                    unsafe {
-                        p.ic_data_cmd().write(|w| {
-                            w.set_stop(last && send_stop);
-                            w.set_cmd(false);
-                            w.set_dat(byte);
-                        });
-                    }
+                    p.ic_data_cmd().write(|w| {
+                        w.set_stop(last && send_stop);
+                        w.set_cmd(false);
+                        w.set_dat(byte);
+                    });
                 } else {
                     break 'xmit Ok(());
                 }
@@ -235,7 +231,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
                             Poll::Pending
                         }
                     },
-                    |_me| unsafe {
+                    |_me| {
                         // Set tx "free" threshold a little high so that we get
                         // woken before the fifo completely drains to minimize
                         // transfer stalls.
@@ -267,7 +263,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
 
             let had_abort2 = self
                 .wait_on(
-                    |me| unsafe {
+                    |me| {
                         // We could see an abort while processing fifo backlog,
                         // so handle it here.
                         let abort = me.read_and_clear_abort_reason();
@@ -279,7 +275,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
                             Poll::Pending
                         }
                     },
-                    |_me| unsafe {
+                    |_me| {
                         p.ic_intr_mask().modify(|w| {
                             w.set_m_stop_det(true);
                             w.set_m_tx_abrt(true);
@@ -287,9 +283,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
                     },
                 )
                 .await;
-            unsafe {
-                p.ic_clr_stop_det().read();
-            }
+            p.ic_clr_stop_det().read();
 
             had_abort.and(had_abort2)
         } else {
@@ -336,95 +330,93 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
 
         let p = T::regs();
 
-        unsafe {
-            let reset = T::reset();
-            crate::reset::reset(reset);
-            crate::reset::unreset_wait(reset);
+        let reset = T::reset();
+        crate::reset::reset(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
-            p.ic_con().modify(|w| {
-                // Always use "fast" mode (<= 400 kHz, works fine for standard
-                // mode too)
-                w.set_speed(i2c::vals::Speed::FAST);
-                w.set_master_mode(true);
-                w.set_ic_slave_disable(true);
-                w.set_ic_restart_en(true);
-                w.set_tx_empty_ctrl(true);
-            });
+        // Select controller mode & speed
+        p.ic_con().modify(|w| {
+            // Always use "fast" mode (<= 400 kHz, works fine for standard
+            // mode too)
+            w.set_speed(i2c::vals::Speed::FAST);
+            w.set_master_mode(true);
+            w.set_ic_slave_disable(true);
+            w.set_ic_restart_en(true);
+            w.set_tx_empty_ctrl(true);
+        });
 
-            // Set FIFO watermarks to 1 to make things simpler. This is encoded
-            // by a register value of 0.
-            p.ic_tx_tl().write(|w| w.set_tx_tl(0));
-            p.ic_rx_tl().write(|w| w.set_rx_tl(0));
+        // Set FIFO watermarks to 1 to make things simpler. This is encoded
+        // by a register value of 0.
+        p.ic_tx_tl().write(|w| w.set_tx_tl(0));
+        p.ic_rx_tl().write(|w| w.set_rx_tl(0));
 
-            // Configure SCL & SDA pins
-            scl.io().ctrl().write(|w| w.set_funcsel(3));
-            sda.io().ctrl().write(|w| w.set_funcsel(3));
+        // Configure SCL & SDA pins
+        scl.io().ctrl().write(|w| w.set_funcsel(3));
+        sda.io().ctrl().write(|w| w.set_funcsel(3));
 
-            scl.pad_ctrl().write(|w| {
-                w.set_schmitt(true);
-                w.set_ie(true);
-                w.set_od(false);
-                w.set_pue(true);
-                w.set_pde(false);
-            });
-            sda.pad_ctrl().write(|w| {
-                w.set_schmitt(true);
-                w.set_ie(true);
-                w.set_od(false);
-                w.set_pue(true);
-                w.set_pde(false);
-            });
+        scl.pad_ctrl().write(|w| {
+            w.set_schmitt(true);
+            w.set_ie(true);
+            w.set_od(false);
+            w.set_pue(true);
+            w.set_pde(false);
+        });
+        sda.pad_ctrl().write(|w| {
+            w.set_schmitt(true);
+            w.set_ie(true);
+            w.set_od(false);
+            w.set_pue(true);
+            w.set_pde(false);
+        });
 
-            // Configure baudrate
+        // Configure baudrate
 
-            // There are some subtleties to I2C timing which we are completely
-            // ignoring here See:
-            // https://github.com/raspberrypi/pico-sdk/blob/bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7/src/rp2_common/hardware_i2c/i2c.c#L69
-            let clk_base = crate::clocks::clk_peri_freq();
+        // There are some subtleties to I2C timing which we are completely
+        // ignoring here See:
+        // 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 period = (clk_base + config.frequency / 2) / config.frequency;
-            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 period = (clk_base + config.frequency / 2) / config.frequency;
+        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
 
-            // Check for out-of-range divisors:
-            assert!(hcnt <= 0xffff);
-            assert!(lcnt <= 0xffff);
-            assert!(hcnt >= 8);
-            assert!(lcnt >= 8);
+        // Check for out-of-range divisors:
+        assert!(hcnt <= 0xffff);
+        assert!(lcnt <= 0xffff);
+        assert!(hcnt >= 8);
+        assert!(lcnt >= 8);
 
-            // Per I2C-bus specification a device in standard or fast mode must
-            // internally provide a hold time of at least 300ns for the SDA
-            // signal to bridge the undefined region of the falling edge of SCL.
-            // A smaller hold time of 120ns is used for fast mode plus.
-            let sda_tx_hold_count = if config.frequency < 1_000_000 {
-                // sda_tx_hold_count = clk_base [cycles/s] * 300ns * (1s /
-                // 1e9ns) Reduce 300/1e9 to 3/1e7 to avoid numbers that don't
-                // fit in uint. Add 1 to avoid division truncation.
-                ((clk_base * 3) / 10_000_000) + 1
-            } else {
-                // fast mode plus requires a clk_base > 32MHz
-                assert!(clk_base >= 32_000_000);
+        // Per I2C-bus specification a device in standard or fast mode must
+        // internally provide a hold time of at least 300ns for the SDA
+        // signal to bridge the undefined region of the falling edge of SCL.
+        // A smaller hold time of 120ns is used for fast mode plus.
+        let sda_tx_hold_count = if config.frequency < 1_000_000 {
+            // sda_tx_hold_count = clk_base [cycles/s] * 300ns * (1s /
+            // 1e9ns) Reduce 300/1e9 to 3/1e7 to avoid numbers that don't
+            // fit in uint. Add 1 to avoid division truncation.
+            ((clk_base * 3) / 10_000_000) + 1
+        } else {
+            // fast mode plus requires a clk_base > 32MHz
+            assert!(clk_base >= 32_000_000);
 
-                // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s /
-                // 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't
-                // fit in uint. Add 1 to avoid division truncation.
-                ((clk_base * 3) / 25_000_000) + 1
-            };
-            assert!(sda_tx_hold_count <= lcnt - 2);
+            // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s /
+            // 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't
+            // fit in uint. Add 1 to avoid division truncation.
+            ((clk_base * 3) / 25_000_000) + 1
+        };
+        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_lcnt().write(|w| w.set_ic_fs_scl_lcnt(lcnt as u16));
-            p.ic_fs_spklen()
-                .write(|w| w.set_ic_fs_spklen(if lcnt < 16 { 1 } else { (lcnt / 16) as u8 }));
-            p.ic_sda_hold()
-                .modify(|w| w.set_ic_sda_tx_hold(sda_tx_hold_count 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_spklen()
+            .write(|w| w.set_ic_fs_spklen(if lcnt < 16 { 1 } else { (lcnt / 16) as u8 }));
+        p.ic_sda_hold()
+            .modify(|w| w.set_ic_sda_tx_hold(sda_tx_hold_count as u16));
 
-            // Enable I2C block
-            p.ic_enable().write(|w| w.set_enable(true));
-        }
+        // Enable I2C block
+        p.ic_enable().write(|w| w.set_enable(true));
 
         Self { phantom: PhantomData }
     }
@@ -439,11 +431,9 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
         }
 
         let p = T::regs();
-        unsafe {
-            p.ic_enable().write(|w| w.set_enable(false));
-            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(false));
+        p.ic_tar().write(|w| w.set_ic_tar(addr));
+        p.ic_enable().write(|w| w.set_enable(true));
         Ok(())
     }
 
@@ -455,40 +445,38 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
     #[inline]
     fn tx_fifo_capacity() -> u8 {
         let p = T::regs();
-        unsafe { FIFO_SIZE - p.ic_txflr().read().txflr() }
+        FIFO_SIZE - p.ic_txflr().read().txflr()
     }
 
     #[inline]
     fn rx_fifo_len() -> u8 {
         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> {
         let p = T::regs();
-        unsafe {
-            let abort_reason = p.ic_tx_abrt_source().read();
-            if abort_reason.0 != 0 {
-                // Note clearing the abort flag also clears the reason, and this
-                // instance of flag is clear-on-read! Note also the
-                // IC_CLR_TX_ABRT register always reads as 0.
-                p.ic_clr_tx_abrt().read();
+        let abort_reason = p.ic_tx_abrt_source().read();
+        if abort_reason.0 != 0 {
+            // Note clearing the abort flag also clears the reason, and this
+            // instance of flag is clear-on-read! Note also the
+            // IC_CLR_TX_ABRT register always reads as 0.
+            p.ic_clr_tx_abrt().read();
 
-                let reason = if abort_reason.abrt_7b_addr_noack()
-                    | abort_reason.abrt_10addr1_noack()
-                    | abort_reason.abrt_10addr2_noack()
-                {
-                    AbortReason::NoAcknowledge
-                } else if abort_reason.arb_lost() {
-                    AbortReason::ArbitrationLoss
-                } else {
-                    AbortReason::Other(abort_reason.0)
-                };
-
-                Err(Error::Abort(reason))
+            let reason = if abort_reason.abrt_7b_addr_noack()
+                | abort_reason.abrt_10addr1_noack()
+                | abort_reason.abrt_10addr2_noack()
+            {
+                AbortReason::NoAcknowledge
+            } else if abort_reason.arb_lost() {
+                AbortReason::ArbitrationLoss
             } 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 last = i == lastindex;
 
-            // NOTE(unsafe) We have &mut self
-            unsafe {
-                // wait until there is space in the FIFO to write the next byte
-                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| {
-                    w.set_restart(restart && first);
-                    w.set_stop(send_stop && last);
+            p.ic_data_cmd().write(|w| {
+                w.set_restart(restart && first);
+                w.set_stop(send_stop && last);
 
-                    w.set_cmd(true);
-                });
+                w.set_cmd(true);
+            });
 
-                while Self::rx_fifo_len() == 0 {
-                    self.read_and_clear_abort_reason()?;
-                }
-
-                *byte = p.ic_data_cmd().read().dat();
+            while Self::rx_fifo_len() == 0 {
+                self.read_and_clear_abort_reason()?;
             }
+
+            *byte = p.ic_data_cmd().read().dat();
         }
 
         Ok(())
@@ -536,36 +521,33 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
         for (i, byte) in write.iter().enumerate() {
             let last = i == write.len() - 1;
 
-            // NOTE(unsafe) We have &mut self
-            unsafe {
-                p.ic_data_cmd().write(|w| {
-                    w.set_stop(send_stop && last);
-                    w.set_dat(*byte);
-                });
+            p.ic_data_cmd().write(|w| {
+                w.set_stop(send_stop && last);
+                w.set_dat(*byte);
+            });
 
-                // Wait until the transmission of the address/data from the
-                // internal shift register has completed. For this to function
-                // correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The
-                // TX_EMPTY_CTRL flag was set in i2c_init.
-                while !p.ic_raw_intr_stat().read().tx_empty() {}
+            // Wait until the transmission of the address/data from the
+            // internal shift register has completed. For this to function
+            // correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The
+            // TX_EMPTY_CTRL flag was set in i2c_init.
+            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 the transaction was aborted or if it completed
-                    // successfully wait until the STOP condition has occurred.
+            if abort_reason.is_err() || (send_stop && last) {
+                // If the transaction was aborted or if it completed
+                // 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();
-                }
-
-                // 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?;
+                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?;
         }
         Ok(())
     }
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index d6f73219f..4fd3cb46a 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -261,33 +261,39 @@ pub fn init(config: config::Config) -> Peripherals {
 
 /// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes.
 trait RegExt<T: Copy> {
-    unsafe 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;
-    unsafe fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
+    fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
+    fn write_set<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> {
-    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 res = f(&mut val);
-        let ptr = (self.ptr() as *mut u8).add(0x1000) as *mut T;
-        ptr.write_volatile(val);
+        unsafe {
+            let ptr = (self.as_ptr() as *mut u8).add(0x1000) as *mut T;
+            ptr.write_volatile(val);
+        }
         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 res = f(&mut val);
-        let ptr = (self.ptr() as *mut u8).add(0x2000) as *mut T;
-        ptr.write_volatile(val);
+        unsafe {
+            let ptr = (self.as_ptr() as *mut u8).add(0x2000) as *mut T;
+            ptr.write_volatile(val);
+        }
         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 res = f(&mut val);
-        let ptr = (self.ptr() as *mut u8).add(0x3000) as *mut T;
-        ptr.write_volatile(val);
+        unsafe {
+            let ptr = (self.as_ptr() as *mut u8).add(0x3000) as *mut T;
+            ptr.write_volatile(val);
+        }
         res
     }
 }
diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs
index 2a7e4822a..468e8470a 100644
--- a/embassy-rp/src/multicore.rs
+++ b/embassy-rp/src/multicore.rs
@@ -163,14 +163,12 @@ where
     }
 
     // Reset the core
-    unsafe {
-        let psm = pac::PSM;
-        psm.frce_off().modify(|w| w.set_proc1(true));
-        while !psm.frce_off().read().proc1() {
-            cortex_m::asm::nop();
-        }
-        psm.frce_off().modify(|w| w.set_proc1(false));
+    let psm = pac::PSM;
+    psm.frce_off().modify(|w| w.set_proc1(true));
+    while !psm.frce_off().read().proc1() {
+        cortex_m::asm::nop();
     }
+    psm.frce_off().modify(|w| w.set_proc1(false));
 
     // The ARM AAPCS ABI requires 8-byte stack alignment.
     // #[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
 #[inline(always)]
 fn fifo_write(value: u32) {
-    unsafe {
-        let sio = pac::SIO;
-        // Wait for the FIFO to have enough space
-        while !sio.fifo().st().read().rdy() {
-            cortex_m::asm::nop();
-        }
-        sio.fifo().wr().write_value(value);
+    let sio = pac::SIO;
+    // Wait for the FIFO to have enough space
+    while !sio.fifo().st().read().rdy() {
+        cortex_m::asm::nop();
     }
+    sio.fifo().wr().write_value(value);
     // Fire off an event to the other core.
     // This is required as the other core may be `wfe` (waiting for event)
     cortex_m::asm::sev();
@@ -286,38 +282,32 @@ fn fifo_write(value: u32) {
 // Pop a value from inter-core FIFO, block until available
 #[inline(always)]
 fn fifo_read() -> u32 {
-    unsafe {
-        let sio = pac::SIO;
-        // Wait until FIFO has data
-        while !sio.fifo().st().read().vld() {
-            cortex_m::asm::nop();
-        }
-        sio.fifo().rd().read()
+    let sio = pac::SIO;
+    // Wait until FIFO has data
+    while !sio.fifo().st().read().vld() {
+        cortex_m::asm::nop();
     }
+    sio.fifo().rd().read()
 }
 
 // Pop a value from inter-core FIFO, `wfe` until available
 #[inline(always)]
 #[allow(unused)]
 fn fifo_read_wfe() -> u32 {
-    unsafe {
-        let sio = pac::SIO;
-        // Wait until FIFO has data
-        while !sio.fifo().st().read().vld() {
-            cortex_m::asm::wfe();
-        }
-        sio.fifo().rd().read()
+    let sio = pac::SIO;
+    // Wait until FIFO has data
+    while !sio.fifo().st().read().vld() {
+        cortex_m::asm::wfe();
     }
+    sio.fifo().rd().read()
 }
 
 // Drain inter-core FIFO
 #[inline(always)]
 fn fifo_drain() {
-    unsafe {
-        let sio = pac::SIO;
-        while sio.fifo().st().read().vld() {
-            let _ = sio.fifo().rd().read();
-        }
+    let sio = pac::SIO;
+    while sio.fifo().st().read().vld() {
+        let _ = sio.fifo().rd().read();
     }
 }
 
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs
index 0fa3bd771..1b36e0a54 100644
--- a/embassy-rp/src/pio.rs
+++ b/embassy-rp/src/pio.rs
@@ -87,7 +87,7 @@ const SMIRQ_MASK: u32 = 1 << 8;
 
 #[cfg(feature = "rt")]
 #[interrupt]
-unsafe fn PIO0_IRQ_0() {
+fn PIO0_IRQ_0() {
     use crate::pac;
     let ints = pac::PIO0.irqs(0).ints().read().0;
     for bit in 0..12 {
@@ -100,7 +100,7 @@ unsafe fn PIO0_IRQ_0() {
 
 #[cfg(feature = "rt")]
 #[interrupt]
-unsafe fn PIO1_IRQ_0() {
+fn PIO1_IRQ_0() {
     use crate::pac;
     let ints = pac::PIO1.irqs(0).ints().read().0;
     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(())
         } else {
             WAKERS[PIO::PIO_NO as usize].fifo_out()[SM].register(cx.waker());
-            unsafe {
-                PIO::PIO.irqs(0).inte().write_set(|m| {
-                    m.0 = TXNFULL_MASK << SM;
-                });
-            }
+            PIO::PIO.irqs(0).inte().write_set(|m| {
+                m.0 = TXNFULL_MASK << SM;
+            });
             // debug!("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> {
     fn drop(&mut self) {
-        unsafe {
-            PIO::PIO.irqs(0).inte().write_clear(|m| {
-                m.0 = TXNFULL_MASK << SM;
-            });
-        }
+        PIO::PIO.irqs(0).inte().write_clear(|m| {
+            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)
         } else {
             WAKERS[PIO::PIO_NO as usize].fifo_in()[SM].register(cx.waker());
-            unsafe {
-                PIO::PIO.irqs(0).inte().write_set(|m| {
-                    m.0 = RXNEMPTY_MASK << SM;
-                });
-            }
+            PIO::PIO.irqs(0).inte().write_set(|m| {
+                m.0 = RXNEMPTY_MASK << SM;
+            });
             //debug!("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> {
     fn drop(&mut self) {
-        unsafe {
-            PIO::PIO.irqs(0).inte().write_clear(|m| {
-                m.0 = RXNEMPTY_MASK << SM;
-            });
-        }
+        PIO::PIO.irqs(0).inte().write_clear(|m| {
+            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);
 
         // Check if IRQ flag is already set
-        if unsafe { PIO::PIO.irq().read().0 & (1 << self.irq_no) != 0 } {
-            unsafe {
-                PIO::PIO.irq().write(|m| m.0 = 1 << self.irq_no);
-            }
+        if PIO::PIO.irq().read().0 & (1 << self.irq_no) != 0 {
+            PIO::PIO.irq().write(|m| m.0 = 1 << self.irq_no);
             return Poll::Ready(());
         }
 
         WAKERS[PIO::PIO_NO as usize].irq()[self.irq_no as usize].register(cx.waker());
-        unsafe {
-            PIO::PIO.irqs(0).inte().write_set(|m| {
-                m.0 = SMIRQ_MASK << self.irq_no;
-            });
-        }
+        PIO::PIO.irqs(0).inte().write_set(|m| {
+            m.0 = SMIRQ_MASK << self.irq_no;
+        });
         Poll::Pending
     }
 }
 
 impl<'a, 'd, PIO: Instance> Drop for IrqFuture<'a, 'd, PIO> {
     fn drop(&mut self) {
-        unsafe {
-            PIO::PIO.irqs(0).inte().write_clear(|m| {
-                m.0 = SMIRQ_MASK << self.irq_no;
-            });
-        }
+        PIO::PIO.irqs(0).inte().write_clear(|m| {
+            m.0 = SMIRQ_MASK << self.irq_no;
+        });
     }
 }
 
@@ -256,57 +242,47 @@ impl<'l, PIO: Instance> Pin<'l, PIO> {
     /// Set the pin's drive strength.
     #[inline]
     pub fn set_drive_strength(&mut self, strength: Drive) {
-        unsafe {
-            self.pin.pad_ctrl().modify(|w| {
-                w.set_drive(match strength {
-                    Drive::_2mA => pac::pads::vals::Drive::_2MA,
-                    Drive::_4mA => pac::pads::vals::Drive::_4MA,
-                    Drive::_8mA => pac::pads::vals::Drive::_8MA,
-                    Drive::_12mA => pac::pads::vals::Drive::_12MA,
-                });
+        self.pin.pad_ctrl().modify(|w| {
+            w.set_drive(match strength {
+                Drive::_2mA => pac::pads::vals::Drive::_2MA,
+                Drive::_4mA => pac::pads::vals::Drive::_4MA,
+                Drive::_8mA => pac::pads::vals::Drive::_8MA,
+                Drive::_12mA => pac::pads::vals::Drive::_12MA,
             });
-        }
+        });
     }
 
     // Set the pin's slew rate.
     #[inline]
     pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
-        unsafe {
-            self.pin.pad_ctrl().modify(|w| {
-                w.set_slewfast(slew_rate == SlewRate::Fast);
-            });
-        }
+        self.pin.pad_ctrl().modify(|w| {
+            w.set_slewfast(slew_rate == SlewRate::Fast);
+        });
     }
 
     /// Set the pin's pull.
     #[inline]
     pub fn set_pull(&mut self, pull: Pull) {
-        unsafe {
-            self.pin.pad_ctrl().modify(|w| {
-                w.set_pue(pull == Pull::Up);
-                w.set_pde(pull == Pull::Down);
-            });
-        }
+        self.pin.pad_ctrl().modify(|w| {
+            w.set_pue(pull == Pull::Up);
+            w.set_pde(pull == Pull::Down);
+        });
     }
 
     /// Set the pin's schmitt trigger.
     #[inline]
     pub fn set_schmitt(&mut self, enable: bool) {
-        unsafe {
-            self.pin.pad_ctrl().modify(|w| {
-                w.set_schmitt(enable);
-            });
-        }
+        self.pin.pad_ctrl().modify(|w| {
+            w.set_schmitt(enable);
+        });
     }
 
     pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) {
         let mask = 1 << self.pin();
-        unsafe {
-            if bypass {
-                PIO::PIO.input_sync_bypass().write_set(|w| *w = mask);
-            } else {
-                PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask);
-            }
+        if bypass {
+            PIO::PIO.input_sync_bypass().write_set(|w| *w = mask);
+        } else {
+            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> {
     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 {
-        unsafe { PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0 }
+        PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0
     }
 
     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 {
-        unsafe {
-            let fdebug = PIO::PIO.fdebug();
-            let ret = fdebug.read().rxstall() & (1 << SM) != 0;
-            if ret {
-                fdebug.write(|w| w.set_rxstall(1 << SM));
-            }
-            ret
+        let fdebug = PIO::PIO.fdebug();
+        let ret = fdebug.read().rxstall() & (1 << SM) != 0;
+        if ret {
+            fdebug.write(|w| w.set_rxstall(1 << SM));
         }
+        ret
     }
 
     pub fn underflowed(&self) -> bool {
-        unsafe {
-            let fdebug = PIO::PIO.fdebug();
-            let ret = fdebug.read().rxunder() & (1 << SM) != 0;
-            if ret {
-                fdebug.write(|w| w.set_rxunder(1 << SM));
-            }
-            ret
+        let fdebug = PIO::PIO.fdebug();
+        let ret = fdebug.read().rxunder() & (1 << SM) != 0;
+        if ret {
+            fdebug.write(|w| w.set_rxunder(1 << SM));
         }
+        ret
     }
 
     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> {
@@ -374,24 +346,22 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
         ch: PeripheralRef<'a, C>,
         data: &'a mut [W],
     ) -> Transfer<'a, C> {
-        unsafe {
-            let pio_no = PIO::PIO_NO;
-            let p = ch.regs();
-            p.write_addr().write_value(data.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);
-            compiler_fence(Ordering::SeqCst);
-            p.ctrl_trig().write(|w| {
-                // Set RX DREQ for this statemachine
-                w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8 + 4));
-                w.set_data_size(W::size());
-                w.set_chain_to(ch.number());
-                w.set_incr_read(false);
-                w.set_incr_write(true);
-                w.set_en(true);
-            });
-            compiler_fence(Ordering::SeqCst);
-        }
+        let pio_no = PIO::PIO_NO;
+        let p = ch.regs();
+        p.write_addr().write_value(data.as_ptr() as u32);
+        p.read_addr().write_value(PIO::PIO.rxf(SM).as_ptr() as u32);
+        p.trans_count().write_value(data.len() as u32);
+        compiler_fence(Ordering::SeqCst);
+        p.ctrl_trig().write(|w| {
+            // Set RX DREQ for this statemachine
+            w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8 + 4));
+            w.set_data_size(W::size());
+            w.set_chain_to(ch.number());
+            w.set_incr_read(false);
+            w.set_incr_write(true);
+            w.set_en(true);
+        });
+        compiler_fence(Ordering::SeqCst);
         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> {
     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 {
-        unsafe { PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0 }
+        PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0
     }
 
     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 {
-        unsafe {
-            let fdebug = PIO::PIO.fdebug();
-            let ret = fdebug.read().txstall() & (1 << SM) != 0;
-            if ret {
-                fdebug.write(|w| w.set_txstall(1 << SM));
-            }
-            ret
+        let fdebug = PIO::PIO.fdebug();
+        let ret = fdebug.read().txstall() & (1 << SM) != 0;
+        if ret {
+            fdebug.write(|w| w.set_txstall(1 << SM));
         }
+        ret
     }
 
     pub fn overflowed(&self) -> bool {
-        unsafe {
-            let fdebug = PIO::PIO.fdebug();
-            let ret = fdebug.read().txover() & (1 << SM) != 0;
-            if ret {
-                fdebug.write(|w| w.set_txover(1 << SM));
-            }
-            ret
+        let fdebug = PIO::PIO.fdebug();
+        let ret = fdebug.read().txover() & (1 << SM) != 0;
+        if ret {
+            fdebug.write(|w| w.set_txover(1 << SM));
         }
+        ret
     }
 
     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 {
@@ -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> {
-        unsafe {
-            let pio_no = PIO::PIO_NO;
-            let p = ch.regs();
-            p.read_addr().write_value(data.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);
-            compiler_fence(Ordering::SeqCst);
-            p.ctrl_trig().write(|w| {
-                // Set TX DREQ for this statemachine
-                w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8));
-                w.set_data_size(W::size());
-                w.set_chain_to(ch.number());
-                w.set_incr_read(true);
-                w.set_incr_write(false);
-                w.set_en(true);
-            });
-            compiler_fence(Ordering::SeqCst);
-        }
+        let pio_no = PIO::PIO_NO;
+        let p = ch.regs();
+        p.read_addr().write_value(data.as_ptr() as u32);
+        p.write_addr().write_value(PIO::PIO.txf(SM).as_ptr() as u32);
+        p.trans_count().write_value(data.len() as u32);
+        compiler_fence(Ordering::SeqCst);
+        p.ctrl_trig().write(|w| {
+            // Set TX DREQ for this statemachine
+            w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8));
+            w.set_data_size(W::size());
+            w.set_chain_to(ch.number());
+            w.set_incr_read(true);
+            w.set_incr_write(false);
+            w.set_en(true);
+        });
+        compiler_fence(Ordering::SeqCst);
         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> {
     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>();
     }
 }
@@ -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_out.threshold <= 32, "shift_out.threshold must be <= 32");
         let sm = Self::this_sm();
-        unsafe {
-            sm.clkdiv().write(|w| w.0 = config.clock_divider.to_bits() << 8);
-            sm.execctrl().write(|w| {
-                w.set_side_en(config.exec.side_en);
-                w.set_side_pindir(config.exec.side_pindir);
-                w.set_jmp_pin(config.exec.jmp_pin);
-                w.set_out_en_sel(config.out_en_sel);
-                w.set_inline_out_en(config.inline_out_en);
-                w.set_out_sticky(config.out_sticky);
-                w.set_wrap_top(config.exec.wrap_top);
-                w.set_wrap_bottom(config.exec.wrap_bottom);
-                w.set_status_sel(match config.status_sel {
-                    StatusSource::TxFifoLevel => SmExecctrlStatusSel::TXLEVEL,
-                    StatusSource::RxFifoLevel => SmExecctrlStatusSel::RXLEVEL,
-                });
-                w.set_status_n(config.status_n);
+        sm.clkdiv().write(|w| w.0 = config.clock_divider.to_bits() << 8);
+        sm.execctrl().write(|w| {
+            w.set_side_en(config.exec.side_en);
+            w.set_side_pindir(config.exec.side_pindir);
+            w.set_jmp_pin(config.exec.jmp_pin);
+            w.set_out_en_sel(config.out_en_sel);
+            w.set_inline_out_en(config.inline_out_en);
+            w.set_out_sticky(config.out_sticky);
+            w.set_wrap_top(config.exec.wrap_top);
+            w.set_wrap_bottom(config.exec.wrap_bottom);
+            w.set_status_sel(match config.status_sel {
+                StatusSource::TxFifoLevel => SmExecctrlStatusSel::TXLEVEL,
+                StatusSource::RxFifoLevel => SmExecctrlStatusSel::RXLEVEL,
             });
-            sm.shiftctrl().write(|w| {
-                w.set_fjoin_rx(config.fifo_join == FifoJoin::RxOnly);
-                w.set_fjoin_tx(config.fifo_join == FifoJoin::TxOnly);
-                w.set_pull_thresh(config.shift_out.threshold);
-                w.set_push_thresh(config.shift_in.threshold);
-                w.set_out_shiftdir(config.shift_out.direction == ShiftDirection::Right);
-                w.set_in_shiftdir(config.shift_in.direction == ShiftDirection::Right);
-                w.set_autopull(config.shift_out.auto_fill);
-                w.set_autopush(config.shift_in.auto_fill);
-            });
-            sm.pinctrl().write(|w| {
-                w.set_sideset_count(config.pins.sideset_count);
-                w.set_set_count(config.pins.set_count);
-                w.set_out_count(config.pins.out_count);
-                w.set_in_base(config.pins.in_base);
-                w.set_sideset_base(config.pins.sideset_base);
-                w.set_set_base(config.pins.set_base);
-                w.set_out_base(config.pins.out_base);
-            });
-            if let Some(origin) = config.origin {
-                pio_instr_util::exec_jmp(self, origin);
-            }
+            w.set_status_n(config.status_n);
+        });
+        sm.shiftctrl().write(|w| {
+            w.set_fjoin_rx(config.fifo_join == FifoJoin::RxOnly);
+            w.set_fjoin_tx(config.fifo_join == FifoJoin::TxOnly);
+            w.set_pull_thresh(config.shift_out.threshold);
+            w.set_push_thresh(config.shift_in.threshold);
+            w.set_out_shiftdir(config.shift_out.direction == ShiftDirection::Right);
+            w.set_in_shiftdir(config.shift_in.direction == ShiftDirection::Right);
+            w.set_autopull(config.shift_out.auto_fill);
+            w.set_autopush(config.shift_in.auto_fill);
+        });
+        sm.pinctrl().write(|w| {
+            w.set_sideset_count(config.pins.sideset_count);
+            w.set_set_count(config.pins.set_count);
+            w.set_out_count(config.pins.out_count);
+            w.set_in_base(config.pins.in_base);
+            w.set_sideset_base(config.pins.sideset_base);
+            w.set_set_base(config.pins.set_base);
+            w.set_out_base(config.pins.out_base);
+        });
+        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) {
         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) {
         let mask = 1u8 << SM;
-        unsafe {
-            if enable {
-                PIO::PIO.ctrl().write_set(|w| w.set_sm_enable(mask));
-            } else {
-                PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask));
-            }
+        if enable {
+            PIO::PIO.ctrl().write_set(|w| w.set_sm_enable(mask));
+        } else {
+            PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask));
         }
     }
 
     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) {
         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)) {
         let enabled = self.is_enabled();
         self.set_enable(false);
-        let pincfg = unsafe { Self::this_sm().pinctrl().read() };
-        let execcfg = unsafe { Self::this_sm().execctrl().read() };
-        unsafe {
-            Self::this_sm().execctrl().write_clear(|w| w.set_out_sticky(true));
-        }
+        let pincfg = Self::this_sm().pinctrl().read();
+        let execcfg = Self::this_sm().execctrl().read();
+        Self::this_sm().execctrl().write_clear(|w| w.set_out_sticky(true));
         f(self);
-        unsafe {
-            Self::this_sm().pinctrl().write_value(pincfg);
-            Self::this_sm().execctrl().write_value(execcfg);
-        }
+        Self::this_sm().pinctrl().write_value(pincfg);
+        Self::this_sm().execctrl().write_value(execcfg);
         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>]) {
         self.with_paused(|sm| {
             for pin in pins {
-                unsafe {
-                    Self::this_sm().pinctrl().write(|w| {
-                        w.set_set_base(pin.pin());
-                        w.set_set_count(1);
-                    });
-                    // SET PINDIRS, (dir)
-                    sm.exec_instr(0b111_00000_100_00000 | dir as u16);
-                }
+                Self::this_sm().pinctrl().write(|w| {
+                    w.set_set_base(pin.pin());
+                    w.set_set_count(1);
+                });
+                // SET PINDIRS, (dir)
+                unsafe { 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>]) {
         self.with_paused(|sm| {
             for pin in pins {
-                unsafe {
-                    Self::this_sm().pinctrl().write(|w| {
-                        w.set_set_base(pin.pin());
-                        w.set_set_count(1);
-                    });
-                    // SET PINS, (dir)
-                    sm.exec_instr(0b111_00000_000_00000 | level as u16);
-                }
+                Self::this_sm().pinctrl().write(|w| {
+                    w.set_set_base(pin.pin());
+                    w.set_set_count(1);
+                });
+                // SET PINS, (dir)
+                unsafe { sm.exec_instr(0b111_00000_000_00000 | level as u16) };
             }
         });
     }
 
     pub fn clear_fifos(&mut self) {
         // Toggle FJOIN_RX to flush FIFOs
-        unsafe {
-            let shiftctrl = Self::this_sm().shiftctrl();
-            shiftctrl.modify(|w| {
-                w.set_fjoin_rx(!w.fjoin_rx());
-            });
-            shiftctrl.modify(|w| {
-                w.set_fjoin_rx(!w.fjoin_rx());
-            });
-        }
+        let shiftctrl = Self::this_sm().shiftctrl();
+        shiftctrl.modify(|w| {
+            w.set_fjoin_rx(!w.fjoin_rx());
+        });
+        shiftctrl.modify(|w| {
+            w.set_fjoin_rx(!w.fjoin_rx());
+        });
     }
 
     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 {
                 return Err(addr);
             }
-            unsafe {
-                PIO::PIO.instr_mem(addr).write(|w| {
-                    w.set_instr_mem(instr);
-                });
-            }
+            PIO::PIO.instr_mem(addr).write(|w| {
+                w.set_instr_mem(instr);
+            });
             used_mask |= 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) {
-        unsafe {
-            // this can interfere with per-pin bypass functions. splitting the
-            // modification is going to be fine since nothing that relies on
-            // it can reasonably run before we finish.
-            PIO::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass);
-            PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass);
-        }
+        // this can interfere with per-pin bypass functions. splitting the
+        // modification is going to be fine since nothing that relies on
+        // it can reasonably run before we finish.
+        PIO::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass);
+        PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass);
     }
 
     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
@@ -896,9 +834,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
     /// 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> {
         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
         PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed);
         Pin {
@@ -916,13 +852,11 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
             _pio: PhantomData,
         };
         f(&mut batch);
-        unsafe {
-            PIO::PIO.ctrl().modify(|w| {
-                w.set_clkdiv_restart(batch.clkdiv_restart);
-                w.set_sm_restart(batch.sm_restart);
-                w.set_sm_enable((w.sm_enable() & !batch.sm_enable_mask) | batch.sm_enable);
-            });
-        }
+        PIO::PIO.ctrl().modify(|w| {
+            w.set_clkdiv_restart(batch.clkdiv_restart);
+            w.set_sm_restart(batch.sm_restart);
+            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 {
-        unsafe { PIO::PIO.irq().read().irq() & irqs != 0 }
+        PIO::PIO.irq().read().irq() & irqs != 0
     }
 
     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) {
@@ -987,7 +921,7 @@ impl<'d, PIO: Instance> IrqFlags<'d, PIO> {
     }
 
     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) {
@@ -996,7 +930,7 @@ impl<'d, PIO: Instance> IrqFlags<'d, PIO> {
     }
 
     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.
         for i in 0..30 {
             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));
             }
         }
     }
diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs
index 0f9dcf479..20bb88446 100644
--- a/embassy-rp/src/pwm.rs
+++ b/embassy-rp/src/pwm.rs
@@ -71,20 +71,18 @@ impl<'d, T: Channel> Pwm<'d, T> {
         into_ref!(inner);
 
         let p = inner.regs();
-        unsafe {
-            p.csr().modify(|w| {
-                w.set_divmode(divmode);
-                w.set_en(false);
-            });
-            p.ctr().write(|w| w.0 = 0);
-            Self::configure(p, &config);
+        p.csr().modify(|w| {
+            w.set_divmode(divmode);
+            w.set_en(false);
+        });
+        p.ctr().write(|w| w.0 = 0);
+        Self::configure(p, &config);
 
-            if let Some(pin) = &a {
-                pin.io().ctrl().write(|w| w.set_funcsel(4));
-            }
-            if let Some(pin) = &b {
-                pin.io().ctrl().write(|w| w.set_funcsel(4));
-            }
+        if let Some(pin) = &a {
+            pin.io().ctrl().write(|w| w.set_funcsel(4));
+        }
+        if let Some(pin) = &b {
+            pin.io().ctrl().write(|w| w.set_funcsel(4));
         }
         Self {
             inner,
@@ -161,31 +159,29 @@ impl<'d, T: Channel> Pwm<'d, T> {
             panic!("Requested divider is too large");
         }
 
-        unsafe {
-            p.div().write_value(ChDiv(config.divider.to_bits() as u32));
-            p.cc().write(|w| {
-                w.set_a(config.compare_a);
-                w.set_b(config.compare_b);
-            });
-            p.top().write(|w| w.set_top(config.top));
-            p.csr().modify(|w| {
-                w.set_a_inv(config.invert_a);
-                w.set_b_inv(config.invert_b);
-                w.set_ph_correct(config.phase_correct);
-                w.set_en(config.enable);
-            });
-        }
+        p.div().write_value(ChDiv(config.divider.to_bits() as u32));
+        p.cc().write(|w| {
+            w.set_a(config.compare_a);
+            w.set_b(config.compare_b);
+        });
+        p.top().write(|w| w.set_top(config.top));
+        p.csr().modify(|w| {
+            w.set_a_inv(config.invert_a);
+            w.set_b_inv(config.invert_b);
+            w.set_ph_correct(config.phase_correct);
+            w.set_en(config.enable);
+        });
     }
 
     #[inline]
-    pub unsafe fn phase_advance(&mut self) {
+    pub fn phase_advance(&mut self) {
         let p = self.inner.regs();
         p.csr().write_set(|w| w.set_ph_adv(true));
         while p.csr().read().ph_adv() {}
     }
 
     #[inline]
-    pub unsafe fn phase_retard(&mut self) {
+    pub fn phase_retard(&mut self) {
         let p = self.inner.regs();
         p.csr().write_set(|w| w.set_ph_ret(true));
         while p.csr().read().ph_ret() {}
@@ -193,12 +189,12 @@ impl<'d, T: Channel> Pwm<'d, T> {
 
     #[inline]
     pub fn counter(&self) -> u16 {
-        unsafe { self.inner.regs().ctr().read().ctr() }
+        self.inner.regs().ctr().read().ctr()
     }
 
     #[inline]
     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]
@@ -209,14 +205,12 @@ impl<'d, T: Channel> Pwm<'d, T> {
 
     #[inline]
     pub fn wrapped(&mut self) -> bool {
-        unsafe { pac::PWM.intr().read().0 & self.bit() != 0 }
+        pac::PWM.intr().read().0 & self.bit() != 0
     }
 
     #[inline]
     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]
@@ -237,26 +231,22 @@ impl PwmBatch {
     pub fn set_enabled(enabled: bool, batch: impl FnOnce(&mut PwmBatch)) {
         let mut en = PwmBatch(0);
         batch(&mut en);
-        unsafe {
-            if enabled {
-                pac::PWM.en().write_set(|w| w.0 = en.0);
-            } else {
-                pac::PWM.en().write_clear(|w| w.0 = en.0);
-            }
+        if enabled {
+            pac::PWM.en().write_set(|w| w.0 = en.0);
+        } else {
+            pac::PWM.en().write_clear(|w| w.0 = en.0);
         }
     }
 }
 
 impl<'d, T: Channel> Drop for Pwm<'d, T> {
     fn drop(&mut self) {
-        unsafe {
-            self.inner.regs().csr().write_clear(|w| w.set_en(false));
-            if let Some(pin) = &self.pin_a {
-                pin.io().ctrl().write(|w| w.set_funcsel(31));
-            }
-            if let Some(pin) = &self.pin_b {
-                pin.io().ctrl().write(|w| w.set_funcsel(31));
-            }
+        self.inner.regs().csr().write_clear(|w| w.set_en(false));
+        if let Some(pin) = &self.pin_a {
+            pin.io().ctrl().write(|w| w.set_funcsel(31));
+        }
+        if let Some(pin) = &self.pin_b {
+            pin.io().ctrl().write(|w| w.set_funcsel(31));
         }
     }
 }
diff --git a/embassy-rp/src/reset.rs b/embassy-rp/src/reset.rs
index edd47c223..70512fa14 100644
--- a/embassy-rp/src/reset.rs
+++ b/embassy-rp/src/reset.rs
@@ -4,11 +4,11 @@ use crate::pac;
 
 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);
 }
 
-pub unsafe fn unreset_wait(peris: Peripherals) {
+pub(crate) fn unreset_wait(peris: Peripherals) {
     // TODO use the "atomic clear" register version
     pac::RESETS.reset().modify(|v| *v = Peripherals(v.0 & !peris.0));
     while ((!pac::RESETS.reset_done().read().0) & peris.0) != 0 {}
diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs
index e1d886d4a..b18f12fc4 100644
--- a/embassy-rp/src/rtc/mod.rs
+++ b/embassy-rp/src/rtc/mod.rs
@@ -26,7 +26,7 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
         into_ref!(inner);
 
         // 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 };
         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.
     pub fn set_leap_year_check(&mut self, leap_year_check_enabled: bool) {
-        unsafe {
-            self.inner
-                .regs()
-                .ctrl()
-                .modify(|w| w.set_force_notleapyear(!leap_year_check_enabled))
-        };
+        self.inner.regs().ctrl().modify(|w| {
+            w.set_force_notleapyear(!leap_year_check_enabled);
+        });
     }
 
     /// Checks to see if this RealTimeClock is running
     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.
@@ -60,25 +57,23 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
         self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?;
 
         // disable RTC while we configure it
-        unsafe {
-            self.inner.regs().ctrl().modify(|w| w.set_rtc_enable(false));
-            while self.inner.regs().ctrl().read().rtc_active() {
-                core::hint::spin_loop();
-            }
+        self.inner.regs().ctrl().modify(|w| w.set_rtc_enable(false));
+        while self.inner.regs().ctrl().read().rtc_active() {
+            core::hint::spin_loop();
+        }
 
-            self.inner.regs().setup_0().write(|w| {
-                self::datetime::write_setup_0(&t, w);
-            });
-            self.inner.regs().setup_1().write(|w| {
-                self::datetime::write_setup_1(&t, w);
-            });
+        self.inner.regs().setup_0().write(|w| {
+            self::datetime::write_setup_0(&t, w);
+        });
+        self.inner.regs().setup_1().write(|w| {
+            self::datetime::write_setup_1(&t, w);
+        });
 
-            // 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_rtc_enable(true));
-            while !self.inner.regs().ctrl().read().rtc_active() {
-                core::hint::spin_loop();
-            }
+        // 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_rtc_enable(true));
+        while !self.inner.regs().ctrl().read().rtc_active() {
+            core::hint::spin_loop();
         }
         Ok(())
     }
@@ -93,8 +88,8 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
             return Err(RtcError::NotRunning);
         }
 
-        let rtc_0 = unsafe { self.inner.regs().rtc_0().read() };
-        let rtc_1 = unsafe { self.inner.regs().rtc_1().read() };
+        let rtc_0 = self.inner.regs().rtc_0().read();
+        let rtc_1 = self.inner.regs().rtc_1().read();
 
         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
     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() {
-                core::hint::spin_loop();
-            }
+        while self.inner.regs().irq_setup_0().read().match_active() {
+            core::hint::spin_loop();
         }
     }
 
@@ -132,21 +125,19 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
     pub fn schedule_alarm(&mut self, filter: DateTimeFilter) {
         self.disable_alarm();
 
-        unsafe {
-            self.inner.regs().irq_setup_0().write(|w| {
-                filter.write_setup_0(w);
-            });
-            self.inner.regs().irq_setup_1().write(|w| {
-                filter.write_setup_1(w);
-            });
+        self.inner.regs().irq_setup_0().write(|w| {
+            filter.write_setup_0(w);
+        });
+        self.inner.regs().irq_setup_1().write(|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
-            self.inner.regs().irq_setup_0().modify(|w| w.set_match_ena(true));
-            while !self.inner.regs().irq_setup_0().read().match_active() {
-                core::hint::spin_loop();
-            }
+        // Set the enable bit and check if it is set
+        self.inner.regs().irq_setup_0().modify(|w| w.set_match_ena(true));
+        while !self.inner.regs().irq_setup_0().read().match_active() {
+            core::hint::spin_loop();
         }
     }
 
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs
index 7da214743..e817d074e 100644
--- a/embassy-rp/src/spi.rs
+++ b/embassy-rp/src/spi.rs
@@ -79,39 +79,37 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
     ) -> Self {
         into_ref!(inner);
 
-        unsafe {
-            let p = inner.regs();
-            let (presc, postdiv) = calc_prescs(config.frequency);
+        let p = inner.regs();
+        let (presc, postdiv) = calc_prescs(config.frequency);
 
-            p.cpsr().write(|w| w.set_cpsdvsr(presc));
-            p.cr0().write(|w| {
-                w.set_dss(0b0111); // 8bit
-                w.set_spo(config.polarity == Polarity::IdleHigh);
-                w.set_sph(config.phase == Phase::CaptureOnSecondTransition);
-                w.set_scr(postdiv);
-            });
+        p.cpsr().write(|w| w.set_cpsdvsr(presc));
+        p.cr0().write(|w| {
+            w.set_dss(0b0111); // 8bit
+            w.set_spo(config.polarity == Polarity::IdleHigh);
+            w.set_sph(config.phase == Phase::CaptureOnSecondTransition);
+            w.set_scr(postdiv);
+        });
 
-            // Always enable DREQ signals -- harmless if DMA is not listening
-            p.dmacr().write(|reg| {
-                reg.set_rxdmae(true);
-                reg.set_txdmae(true);
-            });
+        // Always enable DREQ signals -- harmless if DMA is not listening
+        p.dmacr().write(|reg| {
+            reg.set_rxdmae(true);
+            reg.set_txdmae(true);
+        });
 
-            // finally, enable.
-            p.cr1().write(|w| w.set_sse(true));
+        // finally, enable.
+        p.cr1().write(|w| w.set_sse(true));
 
-            if let Some(pin) = &clk {
-                pin.io().ctrl().write(|w| w.set_funcsel(1));
-            }
-            if let Some(pin) = &mosi {
-                pin.io().ctrl().write(|w| w.set_funcsel(1));
-            }
-            if let Some(pin) = &miso {
-                pin.io().ctrl().write(|w| w.set_funcsel(1));
-            }
-            if let Some(pin) = &cs {
-                pin.io().ctrl().write(|w| w.set_funcsel(1));
-            }
+        if let Some(pin) = &clk {
+            pin.io().ctrl().write(|w| w.set_funcsel(1));
+        }
+        if let Some(pin) = &mosi {
+            pin.io().ctrl().write(|w| w.set_funcsel(1));
+        }
+        if let Some(pin) = &miso {
+            pin.io().ctrl().write(|w| w.set_funcsel(1));
+        }
+        if let Some(pin) = &cs {
+            pin.io().ctrl().write(|w| w.set_funcsel(1));
         }
         Self {
             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> {
-        unsafe {
-            let p = self.inner.regs();
-            for &b in data {
-                while !p.sr().read().tnf() {}
-                p.dr().write(|w| w.set_data(b as _));
-                while !p.sr().read().rne() {}
-                let _ = p.dr().read();
-            }
+        let p = self.inner.regs();
+        for &b in data {
+            while !p.sr().read().tnf() {}
+            p.dr().write(|w| w.set_data(b as _));
+            while !p.sr().read().rne() {}
+            let _ = p.dr().read();
         }
         self.flush()?;
         Ok(())
     }
 
     pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> {
-        unsafe {
-            let p = self.inner.regs();
-            for b in data {
-                while !p.sr().read().tnf() {}
-                p.dr().write(|w| w.set_data(*b as _));
-                while !p.sr().read().rne() {}
-                *b = p.dr().read().data() as u8;
-            }
+        let p = self.inner.regs();
+        for b in data {
+            while !p.sr().read().tnf() {}
+            p.dr().write(|w| w.set_data(*b as _));
+            while !p.sr().read().rne() {}
+            *b = p.dr().read().data() as u8;
         }
         self.flush()?;
         Ok(())
     }
 
     pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> {
-        unsafe {
-            let p = self.inner.regs();
-            for b in data {
-                while !p.sr().read().tnf() {}
-                p.dr().write(|w| w.set_data(0));
-                while !p.sr().read().rne() {}
-                *b = p.dr().read().data() as u8;
-            }
+        let p = self.inner.regs();
+        for b in data {
+            while !p.sr().read().tnf() {}
+            p.dr().write(|w| w.set_data(0));
+            while !p.sr().read().rne() {}
+            *b = p.dr().read().data() as u8;
         }
         self.flush()?;
         Ok(())
     }
 
     pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
-        unsafe {
-            let p = self.inner.regs();
-            let len = read.len().max(write.len());
-            for i in 0..len {
-                let wb = write.get(i).copied().unwrap_or(0);
-                while !p.sr().read().tnf() {}
-                p.dr().write(|w| w.set_data(wb as _));
-                while !p.sr().read().rne() {}
-                let rb = p.dr().read().data() as u8;
-                if let Some(r) = read.get_mut(i) {
-                    *r = rb;
-                }
+        let p = self.inner.regs();
+        let len = read.len().max(write.len());
+        for i in 0..len {
+            let wb = write.get(i).copied().unwrap_or(0);
+            while !p.sr().read().tnf() {}
+            p.dr().write(|w| w.set_data(wb as _));
+            while !p.sr().read().rne() {}
+            let rb = p.dr().read().data() as u8;
+            if let Some(r) = read.get_mut(i) {
+                *r = rb;
             }
         }
         self.flush()?;
@@ -183,29 +173,25 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
     }
 
     pub fn flush(&mut self) -> Result<(), Error> {
-        unsafe {
-            let p = self.inner.regs();
-            while p.sr().read().bsy() {}
-        }
+        let p = self.inner.regs();
+        while p.sr().read().bsy() {}
         Ok(())
     }
 
     pub fn set_frequency(&mut self, freq: u32) {
         let (presc, postdiv) = calc_prescs(freq);
         let p = self.inner.regs();
-        unsafe {
-            // disable
-            p.cr1().write(|w| w.set_sse(false));
+        // disable
+        p.cr1().write(|w| w.set_sse(false));
 
-            // change stuff
-            p.cpsr().write(|w| w.set_cpsdvsr(presc));
-            p.cr0().modify(|w| {
-                w.set_scr(postdiv);
-            });
+        // change stuff
+        p.cpsr().write(|w| w.set_cpsdvsr(presc));
+        p.cr0().modify(|w| {
+            w.set_scr(postdiv);
+        });
 
-            // enable
-            p.cr1().write(|w| w.set_sse(true));
-        }
+        // enable
+        p.cr1().write(|w| w.set_sse(true));
     }
 }
 
@@ -337,21 +323,19 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
         let tx_transfer = unsafe {
             // If we don't assign future to a variable, the data register pointer
             // 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;
 
         let p = self.inner.regs();
-        unsafe {
-            while p.sr().read().bsy() {}
+        while p.sr().read().bsy() {}
 
-            // clear RX FIFO contents to prevent stale reads
-            while p.sr().read().rne() {
-                let _: u16 = p.dr().read().data();
-            }
-            // clear RX overrun interrupt
-            p.icr().write(|w| w.set_roric(true));
+        // clear RX FIFO contents to prevent stale reads
+        while p.sr().read().rne() {
+            let _: u16 = p.dr().read().data();
         }
+        // clear RX overrun interrupt
+        p.icr().write(|w| w.set_roric(true));
 
         Ok(())
     }
@@ -363,14 +347,19 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
         let rx_transfer = unsafe {
             // If we don't assign future to a variable, the data register pointer
             // 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_transfer = unsafe {
             // If we don't assign future to a variable, the data register pointer
             // 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;
         Ok(())
@@ -394,7 +383,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
         let rx_transfer = unsafe {
             // If we don't assign future to a variable, the data register pointer
             // 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();
@@ -403,13 +392,13 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
         let tx_transfer = async {
             let p = self.inner.regs();
             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 {
                     let write_bytes_len = rx_len - tx_len;
                     // write dummy data
                     // 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_len > rx_len {
             let p = self.inner.regs();
-            unsafe {
-                while p.sr().read().bsy() {}
+            while p.sr().read().bsy() {}
 
-                // clear RX FIFO contents to prevent stale reads
-                while p.sr().read().rne() {
-                    let _: u16 = p.dr().read().data();
-                }
-                // clear RX overrun interrupt
-                p.icr().write(|w| w.set_roric(true));
+            // clear RX FIFO contents to prevent stale reads
+            while p.sr().read().rne() {
+                let _: u16 = p.dr().read().data();
             }
+            // clear RX overrun interrupt
+            p.icr().write(|w| w.set_roric(true));
         }
 
         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) {
         let p = self.inner.regs();
         let (presc, postdiv) = calc_prescs(config.frequency);
-        unsafe {
-            p.cpsr().write(|w| w.set_cpsdvsr(presc));
-            p.cr0().write(|w| {
-                w.set_dss(0b0111); // 8bit
-                w.set_spo(config.polarity == Polarity::IdleHigh);
-                w.set_sph(config.phase == Phase::CaptureOnSecondTransition);
-                w.set_scr(postdiv);
-            });
-        }
+        p.cpsr().write(|w| w.set_cpsdvsr(presc));
+        p.cr0().write(|w| {
+            w.set_dss(0b0111); // 8bit
+            w.set_spo(config.polarity == Polarity::IdleHigh);
+            w.set_sph(config.phase == Phase::CaptureOnSecondTransition);
+            w.set_scr(postdiv);
+        });
     }
 }
diff --git a/embassy-rp/src/timer.rs b/embassy-rp/src/timer.rs
index ca8c96c0f..faa8df037 100644
--- a/embassy-rp/src/timer.rs
+++ b/embassy-rp/src/timer.rs
@@ -34,13 +34,11 @@ embassy_time::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{
 impl Driver for TimerDriver {
     fn now(&self) -> u64 {
         loop {
-            unsafe {
-                let hi = pac::TIMER.timerawh().read();
-                let lo = pac::TIMER.timerawl().read();
-                let hi2 = pac::TIMER.timerawh().read();
-                if hi == hi2 {
-                    return (hi as u64) << 32 | (lo as u64);
-                }
+            let hi = pac::TIMER.timerawh().read();
+            let lo = pac::TIMER.timerawl().read();
+            let hi2 = pac::TIMER.timerawh().read();
+            if hi == hi2 {
+                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
             // 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.
-            unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) };
+            pac::TIMER.alarm(n).write_value(timestamp as u32);
 
             let now = self.now();
             if timestamp <= now {
                 // If alarm timestamp has passed the alarm will not fire.
                 // 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);
 
@@ -106,17 +104,17 @@ impl TimerDriver {
             } else {
                 // Not elapsed, arm it again.
                 // 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
-        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) {
         // 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];
         alarm.timestamp.set(u64::MAX);
@@ -153,24 +151,24 @@ pub unsafe fn init() {
 
 #[cfg(feature = "rt")]
 #[interrupt]
-unsafe fn TIMER_IRQ_0() {
+fn TIMER_IRQ_0() {
     DRIVER.check_alarm(0)
 }
 
 #[cfg(feature = "rt")]
 #[interrupt]
-unsafe fn TIMER_IRQ_1() {
+fn TIMER_IRQ_1() {
     DRIVER.check_alarm(1)
 }
 
 #[cfg(feature = "rt")]
 #[interrupt]
-unsafe fn TIMER_IRQ_2() {
+fn TIMER_IRQ_2() {
     DRIVER.check_alarm(2)
 }
 
 #[cfg(feature = "rt")]
 #[interrupt]
-unsafe fn TIMER_IRQ_3() {
+fn TIMER_IRQ_3() {
     DRIVER.check_alarm(3)
 }
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs
index 6660d5dc9..30eeb5476 100644
--- a/embassy-rp/src/uart/buffered.rs
+++ b/embassy-rp/src/uart/buffered.rs
@@ -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
     // to pend the ISR when we want data transmission to start.
     let regs = T::regs();
-    unsafe {
-        regs.uartimsc().write(|w| {
-            w.set_rxim(true);
-            w.set_rtim(true);
-            w.set_txim(true);
-        });
+    regs.uartimsc().write(|w| {
+        w.set_rxim(true);
+        w.set_rtim(true);
+        w.set_txim(true);
+    });
 
-        T::Interrupt::unpend();
-        T::Interrupt::enable();
-    };
+    T::Interrupt::unpend();
+    unsafe { T::Interrupt::enable() };
 }
 
 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
         // disabled because the buffer was full or errors were detected.
         let regs = T::regs();
-        unsafe {
-            regs.uartimsc().write_set(|w| {
-                w.set_rxim(true);
-                w.set_rtim(true);
-            });
-        }
+        regs.uartimsc().write_set(|w| {
+            w.set_rxim(true);
+            w.set_rtim(true);
+        });
 
         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
         // disabled because the buffer was full or errors were detected.
         let regs = T::regs();
-        unsafe {
-            regs.uartimsc().write_set(|w| {
-                w.set_rxim(true);
-                w.set_rtim(true);
-            });
-        }
+        regs.uartimsc().write_set(|w| {
+            w.set_rxim(true);
+            w.set_rtim(true);
+        });
     }
 }
 
@@ -414,7 +408,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
     }
 
     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,
@@ -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.
     pub async fn send_break(&mut self, bits: u32) {
         let regs = T::regs();
-        let bits = bits.max(unsafe {
+        let bits = bits.max({
             let lcr = regs.uartlcr_h().read();
             let width = lcr.wlen() as u32 + 5;
             let parity = lcr.pen() as u32;
             let stops = 1 + lcr.stp2() as u32;
             2 * (1 + width + parity + stops)
         });
-        let divx64 = unsafe {
-            ((regs.uartibrd().read().baud_divint() as u32) << 6) + regs.uartfbrd().read().baud_divfrac() as u32
-        } as u64;
+        let divx64 = (((regs.uartibrd().read().baud_divint() as u32) << 6)
+            + regs.uartfbrd().read().baud_divfrac() as u32) as u64;
         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;
 
         Self::flush().await.unwrap();
         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;
-        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> {
     fn drop(&mut self) {
         let state = T::buffered_state();
-        unsafe {
-            state.rx_buf.deinit();
+        unsafe { state.rx_buf.deinit() }
 
-            // TX is inactive if the the buffer is not available.
-            // We can now unregister the interrupt handler
-            if state.tx_buf.len() == 0 {
-                T::Interrupt::disable();
-            }
+        // TX is inactive if the the buffer is not available.
+        // We can now unregister the interrupt handler
+        if state.tx_buf.len() == 0 {
+            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> {
     fn drop(&mut self) {
         let state = T::buffered_state();
-        unsafe {
-            state.tx_buf.deinit();
+        unsafe { state.tx_buf.deinit() }
 
-            // RX is inactive if the the buffer is not available.
-            // We can now unregister the interrupt handler
-            if state.rx_buf.len() == 0 {
-                T::Interrupt::disable();
-            }
+        // RX is inactive if the the buffer is not available.
+        // We can now unregister the interrupt handler
+        if state.rx_buf.len() == 0 {
+            T::Interrupt::disable();
         }
     }
 }
@@ -494,94 +479,92 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterr
 
         let s = T::buffered_state();
 
-        unsafe {
-            // Clear TX and error interrupt flags
-            // RX interrupt flags are cleared by reading from the FIFO.
-            let ris = r.uartris().read();
-            r.uarticr().write(|w| {
-                w.set_txic(ris.txris());
-                w.set_feic(ris.feris());
-                w.set_peic(ris.peris());
-                w.set_beic(ris.beris());
-                w.set_oeic(ris.oeris());
-            });
+        // Clear TX and error interrupt flags
+        // RX interrupt flags are cleared by reading from the FIFO.
+        let ris = r.uartris().read();
+        r.uarticr().write(|w| {
+            w.set_txic(ris.txris());
+            w.set_feic(ris.feris());
+            w.set_peic(ris.peris());
+            w.set_beic(ris.beris());
+            w.set_oeic(ris.oeris());
+        });
 
-            trace!("on_interrupt ris={:#X}", ris.0);
+        trace!("on_interrupt ris={:#X}", ris.0);
 
-            // Errors
-            if ris.feris() {
-                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.
+        // Errors
+        if ris.feris() {
+            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 = 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>> {
             let r = T::regs();
-            unsafe {
-                if r.uartfr().read().rxfe() {
-                    return Err(nb::Error::WouldBlock);
-                }
+            if r.uartfr().read().rxfe() {
+                return Err(nb::Error::WouldBlock);
+            }
 
-                let dr = r.uartdr().read();
+            let dr = r.uartdr().read();
 
-                if dr.oe() {
-                    Err(nb::Error::Other(Error::Overrun))
-                } else if dr.be() {
-                    Err(nb::Error::Other(Error::Break))
-                } else if dr.pe() {
-                    Err(nb::Error::Other(Error::Parity))
-                } else if dr.fe() {
-                    Err(nb::Error::Other(Error::Framing))
-                } else {
-                    Ok(dr.data())
-                }
+            if dr.oe() {
+                Err(nb::Error::Other(Error::Overrun))
+            } else if dr.be() {
+                Err(nb::Error::Other(Error::Break))
+            } else if dr.pe() {
+                Err(nb::Error::Other(Error::Parity))
+            } else if dr.fe() {
+                Err(nb::Error::Other(Error::Framing))
+            } else {
+                Ok(dr.data())
             }
         }
     }
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index 5e3ae8a25..7b94bce5e 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -146,23 +146,21 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
 
     pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
         let r = T::regs();
-        unsafe {
-            for &b in buffer {
-                while r.uartfr().read().txff() {}
-                r.uartdr().write(|w| w.set_data(b));
-            }
+        for &b in buffer {
+            while r.uartfr().read().txff() {}
+            r.uartdr().write(|w| w.set_data(b));
         }
         Ok(())
     }
 
     pub fn blocking_flush(&mut self) -> Result<(), Error> {
         let r = T::regs();
-        unsafe { while !r.uartfr().read().txfe() {} }
+        while !r.uartfr().read().txfe() {}
         Ok(())
     }
 
     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,
@@ -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.
     pub async fn send_break(&mut self, bits: u32) {
         let regs = T::regs();
-        let bits = bits.max(unsafe {
+        let bits = bits.max({
             let lcr = regs.uartlcr_h().read();
             let width = lcr.wlen() as u32 + 5;
             let parity = lcr.pen() as u32;
             let stops = 1 + lcr.stp2() as u32;
             2 * (1 + width + parity + stops)
         });
-        let divx64 = unsafe {
-            ((regs.uartibrd().read().baud_divint() as u32) << 6) + regs.uartfbrd().read().baud_divfrac() as u32
-        } as u64;
+        let divx64 = (((regs.uartibrd().read().baud_divint() as u32) << 6)
+            + regs.uartfbrd().read().baud_divfrac() as u32) as u64;
         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;
 
         self.blocking_flush().unwrap();
         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;
-        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
             // 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;
         Ok(())
@@ -246,7 +239,7 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
         debug_assert_eq!(has_irq, rx_dma.is_some());
         if has_irq {
             // 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();
             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> {
         let r = T::regs();
         for (i, b) in buffer.iter_mut().enumerate() {
-            if unsafe { r.uartfr().read().rxfe() } {
+            if r.uartfr().read().rxfe() {
                 return Ok(i);
             }
 
-            let dr = unsafe { r.uartdr().read() };
+            let dr = r.uartdr().read();
 
             if dr.oe() {
                 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> {
     fn drop(&mut self) {
         if let Some(_) = self.rx_dma {
-            unsafe {
-                T::Interrupt::disable();
-                // clear dma flags. irq handlers use these to disambiguate among themselves.
-                T::regs().uartdmacr().write_clear(|reg| {
-                    reg.set_rxdmae(true);
-                    reg.set_txdmae(true);
-                    reg.set_dmaonerr(true);
-                });
-            }
+            T::Interrupt::disable();
+            // clear dma flags. irq handlers use these to disambiguate among themselves.
+            T::regs().uartdmacr().write_clear(|reg| {
+                reg.set_rxdmae(true);
+                reg.set_txdmae(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
         // in the flags will also be present in the fifo.
         T::dma_state().rx_errs.store(0, Ordering::Relaxed);
-        unsafe {
-            T::regs().uarticr().write(|w| {
-                w.set_oeic(true);
-                w.set_beic(true);
-                w.set_peic(true);
-                w.set_feic(true);
-            });
-        }
+        T::regs().uarticr().write(|w| {
+            w.set_oeic(true);
+            w.set_beic(true);
+            w.set_peic(true);
+            w.set_feic(true);
+        });
 
         // then drain the fifo. we need to read at most 32 bytes. errors that apply
         // 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
         // by the interrupt handler.
         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 {
-            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
             // 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.
@@ -575,81 +564,79 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
         config: Config,
     ) {
         let r = T::regs();
-        unsafe {
-            if let Some(pin) = &tx {
-                pin.io().ctrl().write(|w| {
-                    w.set_funcsel(2);
-                    w.set_outover(if config.invert_tx {
-                        Outover::INVERT
-                    } else {
-                        Outover::NORMAL
-                    });
+        if let Some(pin) = &tx {
+            pin.io().ctrl().write(|w| {
+                w.set_funcsel(2);
+                w.set_outover(if config.invert_tx {
+                    Outover::INVERT
+                } else {
+                    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    
@@ -674,15 +661,13 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
             baud_fbrd = 0;
         }
 
-        unsafe {
-            // Load PL011's baud divisor registers
-            r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
-            r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
+        // Load PL011's baud divisor registers
+        r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
+        r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
 
-            // PL011 needs a (dummy) line control register write to latch in the
-            // divisors. We don't want to actually change LCR contents here.
-            r.uartlcr_h().modify(|_| {});
-        }
+        // PL011 needs a (dummy) line control register write to latch in the
+        // divisors. We don't want to actually change LCR contents here.
+        r.uartlcr_h().modify(|_| {});
     }
 }
 
@@ -731,24 +716,22 @@ mod eh02 {
         type Error = Error;
         fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
             let r = T::regs();
-            unsafe {
-                if r.uartfr().read().rxfe() {
-                    return Err(nb::Error::WouldBlock);
-                }
+            if r.uartfr().read().rxfe() {
+                return Err(nb::Error::WouldBlock);
+            }
 
-                let dr = r.uartdr().read();
+            let dr = r.uartdr().read();
 
-                if dr.oe() {
-                    Err(nb::Error::Other(Error::Overrun))
-                } else if dr.be() {
-                    Err(nb::Error::Other(Error::Break))
-                } else if dr.pe() {
-                    Err(nb::Error::Other(Error::Parity))
-                } else if dr.fe() {
-                    Err(nb::Error::Other(Error::Framing))
-                } else {
-                    Ok(dr.data())
-                }
+            if dr.oe() {
+                Err(nb::Error::Other(Error::Overrun))
+            } else if dr.be() {
+                Err(nb::Error::Other(Error::Break))
+            } else if dr.pe() {
+                Err(nb::Error::Other(Error::Parity))
+            } else if dr.fe() {
+                Err(nb::Error::Other(Error::Framing))
+            } else {
+                Ok(dr.data())
             }
         }
     }
@@ -758,22 +741,18 @@ mod eh02 {
 
         fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> {
             let r = T::regs();
-            unsafe {
-                if r.uartfr().read().txff() {
-                    return Err(nb::Error::WouldBlock);
-                }
-
-                r.uartdr().write(|w| w.set_data(word));
+            if r.uartfr().read().txff() {
+                return Err(nb::Error::WouldBlock);
             }
+
+            r.uartdr().write(|w| w.set_data(word));
             Ok(())
         }
 
         fn flush(&mut self) -> Result<(), nb::Error<Self::Error>> {
             let r = T::regs();
-            unsafe {
-                if !r.uartfr().read().txfe() {
-                    return Err(nb::Error::WouldBlock);
-                }
+            if !r.uartfr().read().txfe() {
+                return Err(nb::Error::WouldBlock);
             }
             Ok(())
         }
@@ -854,22 +833,20 @@ mod eh1 {
     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> {
             let r = T::regs();
-            unsafe {
-                let dr = r.uartdr().read();
+            let dr = r.uartdr().read();
 
-                if dr.oe() {
-                    Err(nb::Error::Other(Error::Overrun))
-                } else if dr.be() {
-                    Err(nb::Error::Other(Error::Break))
-                } else if dr.pe() {
-                    Err(nb::Error::Other(Error::Parity))
-                } else if dr.fe() {
-                    Err(nb::Error::Other(Error::Framing))
-                } else if dr.fe() {
-                    Ok(dr.data())
-                } else {
-                    Err(nb::Error::WouldBlock)
-                }
+            if dr.oe() {
+                Err(nb::Error::Other(Error::Overrun))
+            } else if dr.be() {
+                Err(nb::Error::Other(Error::Break))
+            } else if dr.pe() {
+                Err(nb::Error::Other(Error::Parity))
+            } else if dr.fe() {
+                Err(nb::Error::Other(Error::Framing))
+            } else if dr.fe() {
+                Ok(dr.data())
+            } else {
+                Err(nb::Error::WouldBlock)
             }
         }
     }
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs
index 9fb0dfb70..1900ab416 100644
--- a/embassy-rp/src/usb.rs
+++ b/embassy-rp/src/usb.rs
@@ -39,7 +39,7 @@ impl crate::usb::Instance for peripherals::USB {
 
 const EP_COUNT: usize = 16;
 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();
 static BUS_WAKER: AtomicWaker = NEW_AW;
@@ -111,7 +111,7 @@ impl<'d, T: Instance> Driver<'d, T> {
         let regs = T::regs();
         unsafe {
             // zero fill regs
-            let p = regs.0 as *mut u32;
+            let p = regs.as_ptr() as *mut u32;
             for i in 0..0x9c / 4 {
                 p.add(i).write_volatile(0)
             }
@@ -121,20 +121,20 @@ impl<'d, T: Instance> Driver<'d, T> {
             for i in 0..0x100 / 4 {
                 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
         BUS_WAKER.wake();
 
@@ -213,22 +213,18 @@ impl<'d, T: Instance> Driver<'d, T> {
         };
 
         match D::dir() {
-            Direction::Out => unsafe {
-                T::dpram().ep_out_control(index - 1).write(|w| {
-                    w.set_enable(false);
-                    w.set_buffer_address(addr);
-                    w.set_interrupt_per_buff(true);
-                    w.set_endpoint_type(ep_type_reg);
-                })
-            },
-            Direction::In => unsafe {
-                T::dpram().ep_in_control(index - 1).write(|w| {
-                    w.set_enable(false);
-                    w.set_buffer_address(addr);
-                    w.set_interrupt_per_buff(true);
-                    w.set_endpoint_type(ep_type_reg);
-                })
-            },
+            Direction::Out => T::dpram().ep_out_control(index - 1).write(|w| {
+                w.set_enable(false);
+                w.set_buffer_address(addr);
+                w.set_interrupt_per_buff(true);
+                w.set_endpoint_type(ep_type_reg);
+            }),
+            Direction::In => T::dpram().ep_in_control(index - 1).write(|w| {
+                w.set_enable(false);
+                w.set_buffer_address(addr);
+                w.set_interrupt_per_buff(true);
+                w.set_endpoint_type(ep_type_reg);
+            }),
         }
 
         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) {
         let regs = T::regs();
-        unsafe {
-            regs.inte().write(|w| {
-                w.set_bus_reset(true);
-                w.set_buff_status(true);
-                w.set_dev_resume_from_host(true);
-                w.set_dev_suspend(true);
-                w.set_setup_req(true);
-            });
-            regs.int_ep_ctrl().write(|w| {
-                w.set_int_ep_active(0xFFFE); // all EPs
-            });
-            regs.sie_ctrl().write(|w| {
-                w.set_ep0_int_1buf(true);
-                w.set_pullup_en(true);
-            })
-        }
+        regs.inte().write(|w| {
+            w.set_bus_reset(true);
+            w.set_buff_status(true);
+            w.set_dev_resume_from_host(true);
+            w.set_dev_suspend(true);
+            w.set_setup_req(true);
+        });
+        regs.int_ep_ctrl().write(|w| {
+            w.set_int_ep_active(0xFFFE); // all EPs
+        });
+        regs.sie_ctrl().write(|w| {
+            w.set_ep0_int_1buf(true);
+            w.set_pullup_en(true);
+        });
+
         trace!("enabled");
 
         (
@@ -355,7 +350,7 @@ pub struct Bus<'d, T: Instance> {
 
 impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
     async fn poll(&mut self) -> Event {
-        poll_fn(move |cx| unsafe {
+        poll_fn(move |cx| {
             BUS_WAKER.register(cx.waker());
 
             if !self.inited {
@@ -425,14 +420,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
 
         let n = ep_addr.index();
         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_buffer_control(ep_addr.index()).write(|w| {
                     w.set_pid(0, true); // first packet is DATA0, but PID is flipped before
                 });
                 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_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);
                 });
                 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();
         poll_fn(|cx| {
             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() {
                 Poll::Ready(())
             } else {
@@ -526,7 +521,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, Out> {
         let index = self.info.addr.index();
         poll_fn(|cx| {
             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() {
                 Poll::Ready(())
             } 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> {
         trace!("READ WAITING, buf.len() = {}", buf.len());
         let index = self.info.addr.index();
-        let val = poll_fn(|cx| unsafe {
+        let val = poll_fn(|cx| {
             EP_OUT_WAKERS[index].register(cx.waker());
             let val = T::dpram().ep_out_buffer_control(index).read();
             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);
 
-        unsafe {
-            let pid = !val.pid(0);
-            T::dpram().ep_out_buffer_control(index).write(|w| {
-                w.set_pid(0, pid);
-                w.set_length(0, self.info.max_packet_size);
-            });
-            cortex_m::asm::delay(12);
-            T::dpram().ep_out_buffer_control(index).write(|w| {
-                w.set_pid(0, pid);
-                w.set_length(0, self.info.max_packet_size);
-                w.set_available(0, true);
-            });
-        }
+        let pid = !val.pid(0);
+        T::dpram().ep_out_buffer_control(index).write(|w| {
+            w.set_pid(0, pid);
+            w.set_length(0, self.info.max_packet_size);
+        });
+        cortex_m::asm::delay(12);
+        T::dpram().ep_out_buffer_control(index).write(|w| {
+            w.set_pid(0, pid);
+            w.set_length(0, self.info.max_packet_size);
+            w.set_available(0, true);
+        });
 
         Ok(rx_len)
     }
@@ -588,7 +581,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
         trace!("WRITE WAITING");
 
         let index = self.info.addr.index();
-        let val = poll_fn(|cx| unsafe {
+        let val = poll_fn(|cx| {
             EP_IN_WAKERS[index].register(cx.waker());
             let val = T::dpram().ep_in_buffer_control(index).read();
             if val.available(0) {
@@ -601,21 +594,19 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
 
         self.buf.write(buf);
 
-        unsafe {
-            let pid = !val.pid(0);
-            T::dpram().ep_in_buffer_control(index).write(|w| {
-                w.set_pid(0, pid);
-                w.set_length(0, buf.len() as _);
-                w.set_full(0, true);
-            });
-            cortex_m::asm::delay(12);
-            T::dpram().ep_in_buffer_control(index).write(|w| {
-                w.set_pid(0, pid);
-                w.set_length(0, buf.len() as _);
-                w.set_full(0, true);
-                w.set_available(0, true);
-            });
-        }
+        let pid = !val.pid(0);
+        T::dpram().ep_in_buffer_control(index).write(|w| {
+            w.set_pid(0, pid);
+            w.set_length(0, buf.len() as _);
+            w.set_full(0, true);
+        });
+        cortex_m::asm::delay(12);
+        T::dpram().ep_in_buffer_control(index).write(|w| {
+            w.set_pid(0, pid);
+            w.set_length(0, buf.len() as _);
+            w.set_full(0, true);
+            w.set_available(0, true);
+        });
 
         trace!("WRITE OK");
 
@@ -637,9 +628,9 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
         loop {
             trace!("SETUP read waiting");
             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());
                 let regs = T::regs();
                 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);
 
             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
-                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));
-            }
+            // 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_out_buffer_control(0).write(|w| w.set_pid(0, false));
 
             trace!("SETUP read ok");
             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> {
-        unsafe {
-            let bufcontrol = T::dpram().ep_out_buffer_control(0);
-            let pid = !bufcontrol.read().pid(0);
-            bufcontrol.write(|w| {
-                w.set_length(0, self.max_packet_size);
-                w.set_pid(0, pid);
-            });
-            cortex_m::asm::delay(12);
-            bufcontrol.write(|w| {
-                w.set_length(0, self.max_packet_size);
-                w.set_pid(0, pid);
-                w.set_available(0, true);
-            });
-        }
+        let bufcontrol = T::dpram().ep_out_buffer_control(0);
+        let pid = !bufcontrol.read().pid(0);
+        bufcontrol.write(|w| {
+            w.set_length(0, self.max_packet_size);
+            w.set_pid(0, pid);
+        });
+        cortex_m::asm::delay(12);
+        bufcontrol.write(|w| {
+            w.set_length(0, self.max_packet_size);
+            w.set_pid(0, pid);
+            w.set_available(0, true);
+        });
 
         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());
             let val = T::dpram().ep_out_buffer_control(0).read();
             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);
 
-        unsafe {
-            let bufcontrol = T::dpram().ep_in_buffer_control(0);
-            let pid = !bufcontrol.read().pid(0);
-            bufcontrol.write(|w| {
-                w.set_length(0, data.len() as _);
-                w.set_pid(0, pid);
-                w.set_full(0, true);
-            });
-            cortex_m::asm::delay(12);
-            bufcontrol.write(|w| {
-                w.set_length(0, data.len() as _);
-                w.set_pid(0, pid);
-                w.set_full(0, true);
-                w.set_available(0, true);
-            });
-        }
+        let bufcontrol = T::dpram().ep_in_buffer_control(0);
+        let pid = !bufcontrol.read().pid(0);
+        bufcontrol.write(|w| {
+            w.set_length(0, data.len() as _);
+            w.set_pid(0, pid);
+            w.set_full(0, true);
+        });
+        cortex_m::asm::delay(12);
+        bufcontrol.write(|w| {
+            w.set_length(0, data.len() as _);
+            w.set_pid(0, pid);
+            w.set_full(0, true);
+            w.set_available(0, true);
+        });
 
-        poll_fn(|cx| unsafe {
+        poll_fn(|cx| {
             EP_IN_WAKERS[0].register(cx.waker());
             let bufcontrol = T::dpram().ep_in_buffer_control(0);
             if bufcontrol.read().available(0) {
@@ -745,19 +730,17 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
 
         if last {
             // prepare status phase right away.
-            unsafe {
-                let bufcontrol = T::dpram().ep_out_buffer_control(0);
-                bufcontrol.write(|w| {
-                    w.set_length(0, 0);
-                    w.set_pid(0, true);
-                });
-                cortex_m::asm::delay(12);
-                bufcontrol.write(|w| {
-                    w.set_length(0, 0);
-                    w.set_pid(0, true);
-                    w.set_available(0, true);
-                });
-            }
+            let bufcontrol = T::dpram().ep_out_buffer_control(0);
+            bufcontrol.write(|w| {
+                w.set_length(0, 0);
+                w.set_pid(0, true);
+            });
+            cortex_m::asm::delay(12);
+            bufcontrol.write(|w| {
+                w.set_length(0, 0);
+                w.set_pid(0, true);
+                w.set_available(0, true);
+            });
         }
 
         Ok(())
@@ -767,26 +750,24 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
         trace!("control: accept");
 
         let bufcontrol = T::dpram().ep_in_buffer_control(0);
-        unsafe {
-            bufcontrol.write(|w| {
-                w.set_length(0, 0);
-                w.set_pid(0, true);
-                w.set_full(0, true);
-            });
-            cortex_m::asm::delay(12);
-            bufcontrol.write(|w| {
-                w.set_length(0, 0);
-                w.set_pid(0, true);
-                w.set_full(0, true);
-                w.set_available(0, true);
-            });
-        }
+        bufcontrol.write(|w| {
+            w.set_length(0, 0);
+            w.set_pid(0, true);
+            w.set_full(0, true);
+        });
+        cortex_m::asm::delay(12);
+        bufcontrol.write(|w| {
+            w.set_length(0, 0);
+            w.set_pid(0, true);
+            w.set_full(0, true);
+            w.set_available(0, true);
+        });
 
         // wait for completion before returning, needed so
         // set_address() doesn't happen early.
         poll_fn(|cx| {
             EP_IN_WAKERS[0].register(cx.waker());
-            if unsafe { bufcontrol.read().available(0) } {
+            if bufcontrol.read().available(0) {
                 Poll::Pending
             } else {
                 Poll::Ready(())
@@ -799,14 +780,12 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
         trace!("control: reject");
 
         let regs = T::regs();
-        unsafe {
-            regs.ep_stall_arm().write_set(|w| {
-                w.set_ep0_in(true);
-                w.set_ep0_out(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));
-        }
+        regs.ep_stall_arm().write_set(|w| {
+            w.set_ep0_in(true);
+            w.set_ep0_out(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));
     }
 
     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();
         trace!("setting addr: {}", addr);
-        unsafe { regs.addr_endp().write(|w| w.set_address(addr)) }
+        regs.addr_endp().write(|w| w.set_address(addr))
     }
 }
diff --git a/embassy-rp/src/watchdog.rs b/embassy-rp/src/watchdog.rs
index 78a295ae7..d37795cc9 100644
--- a/embassy-rp/src/watchdog.rs
+++ b/embassy-rp/src/watchdog.rs
@@ -35,45 +35,37 @@ impl Watchdog {
     /// * `cycles` - Total number of tick cycles before the next tick is generated.
     ///   It is expected to be the frequency in MHz of clk_ref.
     pub fn enable_tick_generation(&mut self, cycles: u8) {
-        unsafe {
-            let watchdog = pac::WATCHDOG;
-            watchdog.tick().write(|w| {
-                w.set_enable(true);
-                w.set_cycles(cycles.into())
-            });
-        }
+        let watchdog = pac::WATCHDOG;
+        watchdog.tick().write(|w| {
+            w.set_enable(true);
+            w.set_cycles(cycles.into())
+        });
     }
 
     /// Defines whether or not the watchdog timer should be paused when processor(s) are in debug mode
     /// or when JTAG is accessing bus fabric
     pub fn pause_on_debug(&mut self, pause: bool) {
-        unsafe {
-            let watchdog = pac::WATCHDOG;
-            watchdog.ctrl().write(|w| {
-                w.set_pause_dbg0(pause);
-                w.set_pause_dbg1(pause);
-                w.set_pause_jtag(pause);
-            })
-        }
+        let watchdog = pac::WATCHDOG;
+        watchdog.ctrl().write(|w| {
+            w.set_pause_dbg0(pause);
+            w.set_pause_dbg1(pause);
+            w.set_pause_jtag(pause);
+        })
     }
 
     fn load_counter(&self, counter: u32) {
-        unsafe {
-            let watchdog = pac::WATCHDOG;
-            watchdog.load().write_value(pac::watchdog::regs::Load(counter));
-        }
+        let watchdog = pac::WATCHDOG;
+        watchdog.load().write_value(pac::watchdog::regs::Load(counter));
     }
 
     fn enable(&self, bit: bool) {
-        unsafe {
-            let watchdog = pac::WATCHDOG;
-            watchdog.ctrl().write(|w| w.set_enable(bit))
-        }
+        let watchdog = pac::WATCHDOG;
+        watchdog.ctrl().write(|w| w.set_enable(bit))
     }
 
     // Configure which hardware will be reset by the watchdog
     // (everything except ROSC, XOSC)
-    unsafe fn configure_wdog_reset_triggers(&self) {
+    fn configure_wdog_reset_triggers(&self) {
         let psm = pac::PSM;
         psm.wdsel().write_value(pac::psm::regs::Wdsel(
             0x0001ffff & !(0x01 << 0usize) & !(0x01 << 1usize),
@@ -100,23 +92,19 @@ impl Watchdog {
         self.load_value = delay_us * 2;
 
         self.enable(false);
-        unsafe {
-            self.configure_wdog_reset_triggers();
-        }
+        self.configure_wdog_reset_triggers();
         self.load_counter(self.load_value);
         self.enable(true);
     }
 
     /// Trigger a system reset
     pub fn trigger_reset(&mut self) {
-        unsafe {
-            self.configure_wdog_reset_triggers();
-            self.pause_on_debug(false);
-            self.enable(true);
-            let watchdog = pac::WATCHDOG;
-            watchdog.ctrl().write(|w| {
-                w.set_trigger(true);
-            })
-        }
+        self.configure_wdog_reset_triggers();
+        self.pause_on_debug(false);
+        self.enable(true);
+        let watchdog = pac::WATCHDOG;
+        watchdog.ctrl().write(|w| {
+            w.set_trigger(true);
+        })
     }
 }
diff --git a/tests/rp/src/bin/float.rs b/tests/rp/src/bin/float.rs
index 6a982507a..0e0de85fa 100644
--- a/tests/rp/src/bin/float.rs
+++ b/tests/rp/src/bin/float.rs
@@ -18,11 +18,9 @@ async fn main(_spawner: Spawner) {
     const PI_F: f32 = 3.1415926535f32;
     const PI_D: f64 = 3.14159265358979323846f64;
 
-    unsafe {
-        pac::BUSCTRL
-            .perfsel(0)
-            .write(|r| r.set_perfsel(pac::busctrl::vals::Perfsel::ROM));
-    }
+    pac::BUSCTRL
+        .perfsel(0)
+        .write(|r| r.set_perfsel(pac::busctrl::vals::Perfsel::ROM));
 
     for i in 0..=360 {
         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;
     }
 
-    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
     defmt::assert!(rom_accesses >= 360 * 12 * 10);