embassy_rp/
lib.rs

1#![no_std]
2#![allow(async_fn_in_trait)]
3#![doc = include_str!("../README.md")]
4#![warn(missing_docs)]
5
6//! ## Feature flags
7#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
8
9// This mod MUST go first, so that the others see its macros.
10pub(crate) mod fmt;
11
12#[cfg(feature = "binary-info")]
13pub use rp_binary_info as binary_info;
14
15#[cfg(feature = "critical-section-impl")]
16mod critical_section_impl;
17
18#[cfg(feature = "rp2040")]
19mod intrinsics;
20
21pub mod adc;
22#[cfg(feature = "_rp235x")]
23pub mod block;
24#[cfg(feature = "rp2040")]
25pub mod bootsel;
26pub mod clocks;
27pub mod dma;
28pub mod flash;
29#[cfg(feature = "rp2040")]
30mod float;
31pub mod gpio;
32pub mod i2c;
33pub mod i2c_slave;
34pub mod multicore;
35#[cfg(feature = "_rp235x")]
36pub mod otp;
37pub mod pio_programs;
38pub mod pwm;
39mod reset;
40pub mod rom_data;
41#[cfg(feature = "rp2040")]
42pub mod rtc;
43pub mod spi;
44mod spinlock;
45pub mod spinlock_mutex;
46#[cfg(feature = "time-driver")]
47pub mod time_driver;
48#[cfg(feature = "_rp235x")]
49pub mod trng;
50pub mod uart;
51pub mod usb;
52pub mod watchdog;
53
54// PIO
55pub mod pio;
56pub(crate) mod relocate;
57
58// Reexports
59pub use embassy_hal_internal::{Peri, PeripheralType};
60#[cfg(feature = "unstable-pac")]
61pub use rp_pac as pac;
62#[cfg(not(feature = "unstable-pac"))]
63pub(crate) use rp_pac as pac;
64
65#[cfg(feature = "rt")]
66pub use crate::pac::NVIC_PRIO_BITS;
67
68#[cfg(feature = "rp2040")]
69embassy_hal_internal::interrupt_mod!(
70    TIMER_IRQ_0,
71    TIMER_IRQ_1,
72    TIMER_IRQ_2,
73    TIMER_IRQ_3,
74    PWM_IRQ_WRAP,
75    USBCTRL_IRQ,
76    XIP_IRQ,
77    PIO0_IRQ_0,
78    PIO0_IRQ_1,
79    PIO1_IRQ_0,
80    PIO1_IRQ_1,
81    DMA_IRQ_0,
82    DMA_IRQ_1,
83    IO_IRQ_BANK0,
84    IO_IRQ_QSPI,
85    SIO_IRQ_PROC0,
86    SIO_IRQ_PROC1,
87    CLOCKS_IRQ,
88    SPI0_IRQ,
89    SPI1_IRQ,
90    UART0_IRQ,
91    UART1_IRQ,
92    ADC_IRQ_FIFO,
93    I2C0_IRQ,
94    I2C1_IRQ,
95    RTC_IRQ,
96    SWI_IRQ_0,
97    SWI_IRQ_1,
98    SWI_IRQ_2,
99    SWI_IRQ_3,
100    SWI_IRQ_4,
101    SWI_IRQ_5,
102);
103
104#[cfg(feature = "_rp235x")]
105embassy_hal_internal::interrupt_mod!(
106    TIMER0_IRQ_0,
107    TIMER0_IRQ_1,
108    TIMER0_IRQ_2,
109    TIMER0_IRQ_3,
110    TIMER1_IRQ_0,
111    TIMER1_IRQ_1,
112    TIMER1_IRQ_2,
113    TIMER1_IRQ_3,
114    PWM_IRQ_WRAP_0,
115    PWM_IRQ_WRAP_1,
116    DMA_IRQ_0,
117    DMA_IRQ_1,
118    USBCTRL_IRQ,
119    PIO0_IRQ_0,
120    PIO0_IRQ_1,
121    PIO1_IRQ_0,
122    PIO1_IRQ_1,
123    PIO2_IRQ_0,
124    PIO2_IRQ_1,
125    IO_IRQ_BANK0,
126    IO_IRQ_BANK0_NS,
127    IO_IRQ_QSPI,
128    IO_IRQ_QSPI_NS,
129    SIO_IRQ_FIFO,
130    SIO_IRQ_BELL,
131    SIO_IRQ_FIFO_NS,
132    SIO_IRQ_BELL_NS,
133    CLOCKS_IRQ,
134    SPI0_IRQ,
135    SPI1_IRQ,
136    UART0_IRQ,
137    UART1_IRQ,
138    ADC_IRQ_FIFO,
139    I2C0_IRQ,
140    I2C1_IRQ,
141    TRNG_IRQ,
142    PLL_SYS_IRQ,
143    PLL_USB_IRQ,
144    SWI_IRQ_0,
145    SWI_IRQ_1,
146    SWI_IRQ_2,
147    SWI_IRQ_3,
148    SWI_IRQ_4,
149    SWI_IRQ_5,
150);
151
152/// Macro to bind interrupts to handlers.
153///
154/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
155/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
156/// prove at compile-time that the right interrupts have been bound.
157///
158/// Example of how to bind one interrupt:
159///
160/// ```rust,ignore
161/// use embassy_rp::{bind_interrupts, usb, peripherals};
162///
163/// bind_interrupts!(
164///     /// Binds the USB Interrupts.
165///     struct Irqs {
166///         USBCTRL_IRQ => usb::InterruptHandler<peripherals::USB>;
167///     }
168/// );
169/// ```
170///
171// developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`.
172#[macro_export]
173macro_rules! bind_interrupts {
174    ($(#[$attr:meta])* $vis:vis struct $name:ident {
175        $(
176            $(#[cfg($cond_irq:meta)])?
177            $irq:ident => $(
178                $(#[cfg($cond_handler:meta)])?
179                $handler:ty
180            ),*;
181        )*
182    }) => {
183        #[derive(Copy, Clone)]
184        $(#[$attr])*
185        $vis struct $name;
186
187        $(
188            #[allow(non_snake_case)]
189            #[no_mangle]
190            $(#[cfg($cond_irq)])?
191            unsafe extern "C" fn $irq() {
192                unsafe {
193                    $(
194                        $(#[cfg($cond_handler)])?
195                        <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
196
197                    )*
198                }
199            }
200
201            $(#[cfg($cond_irq)])?
202            $crate::bind_interrupts!(@inner
203                $(
204                    $(#[cfg($cond_handler)])?
205                    unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
206                )*
207            );
208        )*
209    };
210    (@inner $($t:tt)*) => {
211        $($t)*
212    }
213}
214
215#[cfg(feature = "rp2040")]
216embassy_hal_internal::peripherals! {
217    PIN_0,
218    PIN_1,
219    PIN_2,
220    PIN_3,
221    PIN_4,
222    PIN_5,
223    PIN_6,
224    PIN_7,
225    PIN_8,
226    PIN_9,
227    PIN_10,
228    PIN_11,
229    PIN_12,
230    PIN_13,
231    PIN_14,
232    PIN_15,
233    PIN_16,
234    PIN_17,
235    PIN_18,
236    PIN_19,
237    PIN_20,
238    PIN_21,
239    PIN_22,
240    PIN_23,
241    PIN_24,
242    PIN_25,
243    PIN_26,
244    PIN_27,
245    PIN_28,
246    PIN_29,
247    PIN_QSPI_SCLK,
248    PIN_QSPI_SS,
249    PIN_QSPI_SD0,
250    PIN_QSPI_SD1,
251    PIN_QSPI_SD2,
252    PIN_QSPI_SD3,
253
254    UART0,
255    UART1,
256
257    SPI0,
258    SPI1,
259
260    I2C0,
261    I2C1,
262
263    DMA_CH0,
264    DMA_CH1,
265    DMA_CH2,
266    DMA_CH3,
267    DMA_CH4,
268    DMA_CH5,
269    DMA_CH6,
270    DMA_CH7,
271    DMA_CH8,
272    DMA_CH9,
273    DMA_CH10,
274    DMA_CH11,
275
276    PWM_SLICE0,
277    PWM_SLICE1,
278    PWM_SLICE2,
279    PWM_SLICE3,
280    PWM_SLICE4,
281    PWM_SLICE5,
282    PWM_SLICE6,
283    PWM_SLICE7,
284
285    USB,
286
287    RTC,
288
289    FLASH,
290
291    ADC,
292    ADC_TEMP_SENSOR,
293
294    CORE1,
295
296    PIO0,
297    PIO1,
298
299    WATCHDOG,
300    BOOTSEL,
301}
302
303#[cfg(feature = "_rp235x")]
304embassy_hal_internal::peripherals! {
305    PIN_0,
306    PIN_1,
307    PIN_2,
308    PIN_3,
309    PIN_4,
310    PIN_5,
311    PIN_6,
312    PIN_7,
313    PIN_8,
314    PIN_9,
315    PIN_10,
316    PIN_11,
317    PIN_12,
318    PIN_13,
319    PIN_14,
320    PIN_15,
321    PIN_16,
322    PIN_17,
323    PIN_18,
324    PIN_19,
325    PIN_20,
326    PIN_21,
327    PIN_22,
328    PIN_23,
329    PIN_24,
330    PIN_25,
331    PIN_26,
332    PIN_27,
333    PIN_28,
334    PIN_29,
335    #[cfg(feature = "rp235xb")]
336    PIN_30,
337    #[cfg(feature = "rp235xb")]
338    PIN_31,
339    #[cfg(feature = "rp235xb")]
340    PIN_32,
341    #[cfg(feature = "rp235xb")]
342    PIN_33,
343    #[cfg(feature = "rp235xb")]
344    PIN_34,
345    #[cfg(feature = "rp235xb")]
346    PIN_35,
347    #[cfg(feature = "rp235xb")]
348    PIN_36,
349    #[cfg(feature = "rp235xb")]
350    PIN_37,
351    #[cfg(feature = "rp235xb")]
352    PIN_38,
353    #[cfg(feature = "rp235xb")]
354    PIN_39,
355    #[cfg(feature = "rp235xb")]
356    PIN_40,
357    #[cfg(feature = "rp235xb")]
358    PIN_41,
359    #[cfg(feature = "rp235xb")]
360    PIN_42,
361    #[cfg(feature = "rp235xb")]
362    PIN_43,
363    #[cfg(feature = "rp235xb")]
364    PIN_44,
365    #[cfg(feature = "rp235xb")]
366    PIN_45,
367    #[cfg(feature = "rp235xb")]
368    PIN_46,
369    #[cfg(feature = "rp235xb")]
370    PIN_47,
371    PIN_QSPI_SCLK,
372    PIN_QSPI_SS,
373    PIN_QSPI_SD0,
374    PIN_QSPI_SD1,
375    PIN_QSPI_SD2,
376    PIN_QSPI_SD3,
377
378    UART0,
379    UART1,
380
381    SPI0,
382    SPI1,
383
384    I2C0,
385    I2C1,
386
387    DMA_CH0,
388    DMA_CH1,
389    DMA_CH2,
390    DMA_CH3,
391    DMA_CH4,
392    DMA_CH5,
393    DMA_CH6,
394    DMA_CH7,
395    DMA_CH8,
396    DMA_CH9,
397    DMA_CH10,
398    DMA_CH11,
399    DMA_CH12,
400    DMA_CH13,
401    DMA_CH14,
402    DMA_CH15,
403
404    PWM_SLICE0,
405    PWM_SLICE1,
406    PWM_SLICE2,
407    PWM_SLICE3,
408    PWM_SLICE4,
409    PWM_SLICE5,
410    PWM_SLICE6,
411    PWM_SLICE7,
412    PWM_SLICE8,
413    PWM_SLICE9,
414    PWM_SLICE10,
415    PWM_SLICE11,
416
417    USB,
418
419    RTC,
420
421    FLASH,
422
423    ADC,
424    ADC_TEMP_SENSOR,
425
426    CORE1,
427
428    PIO0,
429    PIO1,
430    PIO2,
431
432    WATCHDOG,
433    BOOTSEL,
434
435    TRNG
436}
437
438#[cfg(all(not(feature = "boot2-none"), feature = "rp2040"))]
439macro_rules! select_bootloader {
440    ( $( $feature:literal => $loader:ident, )+ default => $default:ident ) => {
441        $(
442            #[cfg(feature = $feature)]
443            #[link_section = ".boot2"]
444            #[used]
445            static BOOT2: [u8; 256] = rp2040_boot2::$loader;
446        )*
447
448        #[cfg(not(any( $( feature = $feature),* )))]
449        #[link_section = ".boot2"]
450        #[used]
451        static BOOT2: [u8; 256] = rp2040_boot2::$default;
452    }
453}
454
455#[cfg(all(not(feature = "boot2-none"), feature = "rp2040"))]
456select_bootloader! {
457    "boot2-at25sf128a" => BOOT_LOADER_AT25SF128A,
458    "boot2-gd25q64cs" => BOOT_LOADER_GD25Q64CS,
459    "boot2-generic-03h" => BOOT_LOADER_GENERIC_03H,
460    "boot2-is25lp080" => BOOT_LOADER_IS25LP080,
461    "boot2-ram-memcpy" => BOOT_LOADER_RAM_MEMCPY,
462    "boot2-w25q080" => BOOT_LOADER_W25Q080,
463    "boot2-w25x10cl" => BOOT_LOADER_W25X10CL,
464    default => BOOT_LOADER_W25Q080
465}
466
467#[cfg(all(not(feature = "imagedef-none"), feature = "_rp235x"))]
468macro_rules! select_imagedef {
469    ( $( $feature:literal => $imagedef:ident, )+ default => $default:ident ) => {
470        $(
471            #[cfg(feature = $feature)]
472            #[link_section = ".start_block"]
473            #[used]
474            static IMAGE_DEF: crate::block::ImageDef = crate::block::ImageDef::$imagedef();
475        )*
476
477        #[cfg(not(any( $( feature = $feature),* )))]
478        #[link_section = ".start_block"]
479        #[used]
480        static IMAGE_DEF: crate::block::ImageDef = crate::block::ImageDef::$default();
481    }
482}
483
484#[cfg(all(not(feature = "imagedef-none"), feature = "_rp235x"))]
485select_imagedef! {
486    "imagedef-secure-exe" => secure_exe,
487    "imagedef-nonsecure-exe" => non_secure_exe,
488    default => secure_exe
489}
490
491/// Installs a stack guard for the CORE0 stack in MPU region 0.
492/// Will fail if the MPU is already configured. This function requires
493/// a `_stack_end` symbol to be defined by the linker script, and expects
494/// `_stack_end` to be located at the lowest address (largest depth) of
495/// the stack.
496///
497/// This method can *only* set up stack guards on the currently
498/// executing core. Stack guards for CORE1 are set up automatically,
499/// only CORE0 should ever use this.
500///
501/// # Usage
502///
503/// ```no_run
504/// use embassy_rp::install_core0_stack_guard;
505/// use embassy_executor::{Executor, Spawner};
506///
507/// #[embassy_executor::main]
508/// async fn main(_spawner: Spawner) {
509///     // set up by the linker as follows:
510///     //
511///     //     MEMORY {
512///     //       STACK0: ORIGIN = 0x20040000, LENGTH = 4K
513///     //     }
514///     //
515///     //     _stack_end = ORIGIN(STACK0);
516///     //     _stack_start = _stack_end + LENGTH(STACK0);
517///     //
518///     install_core0_stack_guard().expect("MPU already configured");
519///     let p = embassy_rp::init(Default::default());
520///
521///     // ...
522/// }
523/// ```
524pub fn install_core0_stack_guard() -> Result<(), ()> {
525    extern "C" {
526        static mut _stack_end: usize;
527    }
528    unsafe { install_stack_guard(core::ptr::addr_of_mut!(_stack_end)) }
529}
530
531#[cfg(all(feature = "rp2040", not(feature = "_test")))]
532#[inline(always)]
533unsafe fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> {
534    let core = unsafe { cortex_m::Peripherals::steal() };
535
536    // Fail if MPU is already configured
537    if core.MPU.ctrl.read() != 0 {
538        return Err(());
539    }
540
541    // The minimum we can protect is 32 bytes on a 32 byte boundary, so round up which will
542    // just shorten the valid stack range a tad.
543    let addr = (stack_bottom as u32 + 31) & !31;
544    // Mask is 1 bit per 32 bytes of the 256 byte range... clear the bit for the segment we want
545    let subregion_select = 0xff ^ (1 << ((addr >> 5) & 7));
546    unsafe {
547        core.MPU.ctrl.write(5); // enable mpu with background default map
548        core.MPU.rbar.write((addr & !0xff) | (1 << 4)); // set address and update RNR
549        core.MPU.rasr.write(
550            1 // enable region
551               | (0x7 << 1) // size 2^(7 + 1) = 256
552               | (subregion_select << 8)
553               | 0x10000000, // XN = disable instruction fetch; no other bits means no permissions
554        );
555    }
556    Ok(())
557}
558
559#[cfg(all(feature = "_rp235x", not(feature = "_test")))]
560#[inline(always)]
561unsafe fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> {
562    let core = unsafe { cortex_m::Peripherals::steal() };
563
564    // Fail if MPU is already configured
565    if core.MPU.ctrl.read() != 0 {
566        return Err(());
567    }
568
569    unsafe {
570        core.MPU.ctrl.write(5); // enable mpu with background default map
571        core.MPU.rbar.write(stack_bottom as u32 & !0xff); // set address
572        core.MPU.rlar.write(((stack_bottom as usize + 255) as u32) | 1);
573    }
574    Ok(())
575}
576
577// This is to hack around cortex_m defaulting to ARMv7 when building tests,
578// so the compile fails when we try to use ARMv8 peripherals.
579#[cfg(feature = "_test")]
580#[inline(always)]
581unsafe fn install_stack_guard(_stack_bottom: *mut usize) -> Result<(), ()> {
582    Ok(())
583}
584
585/// HAL configuration for RP.
586pub mod config {
587    use crate::clocks::ClockConfig;
588
589    /// HAL configuration passed when initializing.
590    #[non_exhaustive]
591    pub struct Config {
592        /// Clock configuration.
593        pub clocks: ClockConfig,
594    }
595
596    impl Default for Config {
597        fn default() -> Self {
598            Self {
599                clocks: ClockConfig::crystal(12_000_000),
600            }
601        }
602    }
603
604    impl Config {
605        /// Create a new configuration with the provided clock config.
606        pub fn new(clocks: ClockConfig) -> Self {
607            Self { clocks }
608        }
609    }
610}
611
612/// Initialize the `embassy-rp` HAL with the provided configuration.
613///
614/// This returns the peripheral singletons that can be used for creating drivers.
615///
616/// This should only be called once at startup, otherwise it panics.
617pub fn init(config: config::Config) -> Peripherals {
618    // Do this first, so that it panics if user is calling `init` a second time
619    // before doing anything important.
620    let peripherals = Peripherals::take();
621
622    unsafe {
623        clocks::init(config.clocks);
624        #[cfg(feature = "time-driver")]
625        time_driver::init();
626        dma::init();
627        gpio::init();
628    }
629
630    peripherals
631}
632
633#[cfg(feature = "rt")]
634#[cortex_m_rt::pre_init]
635unsafe fn pre_init() {
636    // SIO does not get reset when core0 is reset with either `scb::sys_reset()` or with SWD.
637    // Since we're using SIO spinlock 31 for the critical-section impl, this causes random
638    // hangs if we reset in the middle of a CS, because the next boot sees the spinlock
639    // as locked and waits forever.
640    //
641    // See https://github.com/embassy-rs/embassy/issues/1736
642    // and https://github.com/rp-rs/rp-hal/issues/292
643    // and https://matrix.to/#/!vhKMWjizPZBgKeknOo:matrix.org/$VfOkQgyf1PjmaXZbtycFzrCje1RorAXd8BQFHTl4d5M
644    //
645    // According to Raspberry Pi, this is considered Working As Intended, and not an errata,
646    // even though this behavior is different from every other ARM chip (sys_reset usually resets
647    // the *system* as its name implies, not just the current core).
648    //
649    // To fix this, reset SIO on boot. We must do this in pre_init because it's unsound to do it
650    // in `embassy_rp::init`, since the user could've acquired a CS by then. pre_init is guaranteed
651    // to run before any user code.
652    //
653    // A similar thing could happen with PROC1. It is unclear whether it's possible for PROC1
654    // to stay unreset through a PROC0 reset, so we reset it anyway just in case.
655    //
656    // Important info from PSM logic (from Luke Wren in above Matrix thread)
657    //
658    //     The logic is, each PSM stage is reset if either of the following is true:
659    //     - The previous stage is in reset and FRCE_ON is false
660    //     - FRCE_OFF is true
661    //
662    // The PSM order is SIO -> PROC0 -> PROC1.
663    // So, we have to force-on PROC0 to prevent it from getting reset when resetting SIO.
664    #[cfg(feature = "rp2040")]
665    {
666        pac::PSM.frce_on().write_and_wait(|w| {
667            w.set_proc0(true);
668        });
669        // Then reset SIO and PROC1.
670        pac::PSM.frce_off().write_and_wait(|w| {
671            w.set_sio(true);
672            w.set_proc1(true);
673        });
674        // clear force_off first, force_on second. The other way around would reset PROC0.
675        pac::PSM.frce_off().write_and_wait(|_| {});
676        pac::PSM.frce_on().write_and_wait(|_| {});
677    }
678
679    #[cfg(feature = "_rp235x")]
680    {
681        // on RP235x, datasheet says "The FRCE_ON register is a development feature that does nothing in production devices."
682        // No idea why they removed it. Removing it means we can't use PSM to reset SIO, because it comes before
683        // PROC0, so we'd need FRCE_ON to prevent resetting ourselves.
684        //
685        // So we just unlock the spinlock manually.
686        pac::SIO.spinlock(31).write_value(1);
687
688        // We can still use PSM to reset PROC1 since it comes after PROC0 in the state machine.
689        pac::PSM.frce_off().write_and_wait(|w| w.set_proc1(true));
690        pac::PSM.frce_off().write_and_wait(|_| {});
691
692        // Make atomics work between cores.
693        enable_actlr_extexclall();
694    }
695}
696
697/// Set the EXTEXCLALL bit in ACTLR.
698///
699/// The default MPU memory map marks all memory as non-shareable, so atomics don't
700/// synchronize memory accesses between cores at all. This bit forces all memory to be
701/// considered shareable regardless of what the MPU says.
702///
703/// TODO: does this interfere somehow if the user wants to use a custom MPU configuration?
704/// maybe we need to add a way to disable this?
705///
706/// This must be done FOR EACH CORE.
707#[cfg(feature = "_rp235x")]
708unsafe fn enable_actlr_extexclall() {
709    (&*cortex_m::peripheral::ICB::PTR).actlr.modify(|w| w | (1 << 29));
710}
711
712/// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes.
713#[allow(unused)]
714trait RegExt<T: Copy> {
715    #[allow(unused)]
716    fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
717    fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
718    fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
719    fn write_and_wait<R>(&self, f: impl FnOnce(&mut T) -> R) -> R
720    where
721        T: PartialEq;
722}
723
724impl<T: Default + Copy, A: pac::common::Write> RegExt<T> for pac::common::Reg<T, A> {
725    fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
726        let mut val = Default::default();
727        let res = f(&mut val);
728        unsafe {
729            let ptr = (self.as_ptr() as *mut u8).add(0x1000) as *mut T;
730            ptr.write_volatile(val);
731        }
732        res
733    }
734
735    fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
736        let mut val = Default::default();
737        let res = f(&mut val);
738        unsafe {
739            let ptr = (self.as_ptr() as *mut u8).add(0x2000) as *mut T;
740            ptr.write_volatile(val);
741        }
742        res
743    }
744
745    fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
746        let mut val = Default::default();
747        let res = f(&mut val);
748        unsafe {
749            let ptr = (self.as_ptr() as *mut u8).add(0x3000) as *mut T;
750            ptr.write_volatile(val);
751        }
752        res
753    }
754
755    fn write_and_wait<R>(&self, f: impl FnOnce(&mut T) -> R) -> R
756    where
757        T: PartialEq,
758    {
759        let mut val = Default::default();
760        let res = f(&mut val);
761        unsafe {
762            self.as_ptr().write_volatile(val);
763            while self.as_ptr().read_volatile() != val {}
764        }
765        res
766    }
767}