stm32f7xx_hal/
dma.rs

1//! Interface the the DMA peripheral
2
3use core::{
4    fmt,
5    marker::PhantomData,
6    ops::Deref,
7    pin::Pin,
8    sync::atomic::{self, Ordering},
9};
10
11use as_slice::AsSlice;
12
13use crate::{
14    pac::{
15        self,
16        dma2::{self, st::cr},
17        Interrupt, DMA1, DMA2, NVIC,
18    },
19    qspi,
20    rcc::{Enable, RccBus, Reset},
21    serial, spi, state,
22};
23
24/// Entry point to the DMA API
25pub struct DMA<I> {
26    /// Handle to the DMA instance
27    pub handle: Handle<I, state::Disabled>,
28
29    /// The streams associated with this DMA instance
30    pub streams: Streams<I>,
31}
32
33impl<I> DMA<I>
34where
35    I: Instance + Enable + Reset,
36{
37    /// Creates a new instance of `DMA`
38    ///
39    /// This just wraps the PAC API, but does no initialization.
40    pub fn new(instance: I) -> Self {
41        DMA {
42            handle: Handle::new(instance),
43            streams: Streams::new(),
44        }
45    }
46}
47
48/// Handle to the DMA instance
49///
50/// Controls access to the DMA registers and makes sure that access from
51/// multiple streams can not conflict.
52pub struct Handle<I, State> {
53    dma: I,
54    _state: State,
55}
56
57impl<I> Handle<I, state::Disabled>
58where
59    I: Instance + Reset + Enable,
60{
61    fn new(instance: I) -> Self {
62        Self {
63            dma: instance,
64            _state: state::Disabled,
65        }
66    }
67
68    /// Initializes the DMA instance
69    pub fn enable(self, apb: &mut <I as RccBus>::Bus) -> Handle<I, state::Enabled> {
70        I::reset(apb);
71        I::enable(apb);
72
73        Handle {
74            dma: self.dma,
75            _state: state::Enabled,
76        }
77    }
78}
79
80/// Represents an ongoing DMA transfer
81///
82/// Peripheral APIs that support DMA have methods like `write_all` and
83/// `read_all`, which return instances of this struct.
84pub struct Transfer<T: Target, B, State> {
85    res: TransferResources<T, B>,
86    _state: State,
87}
88
89impl<T, B> Transfer<T, B, Ready>
90where
91    T: Target,
92    B: 'static,
93{
94    /// Internal constructor to create a new `Transfer`
95    ///
96    /// # Safety
97    ///
98    /// [`Buffer`] can be used to acquire a raw pointer and a length. This
99    /// defines a memory region, i.e. "the buffer".
100    ///
101    /// If this method is used to prepare a memory-to-peripheral transfer, the
102    /// caller must make sure that the buffer can be read from safely.
103    ///
104    /// If this method is used to prepare a peripheral-to-memory transfer, the
105    /// caller must make sure that the buffer can be written to safely.
106    pub(crate) unsafe fn new<Word>(
107        handle: &Handle<T::Instance, state::Enabled>,
108        stream: T::Stream,
109        buffer: Pin<B>,
110        target: T,
111        address: u32,
112        direction: Direction,
113    ) -> Self
114    where
115        B: Deref,
116        B::Target: Buffer<Word>,
117        Word: SupportedWordSize,
118    {
119        assert!(buffer.len() <= u16::max_value() as usize);
120
121        // The following configuration procedure is documented in the reference
122        // manual for STM32F75xxx and STM32F74xxx, section 8.3.18.
123
124        let nr = T::Stream::number();
125
126        // Disable stream
127        handle.dma.st[nr].cr.modify(|_, w| w.en().disabled());
128        while handle.dma.st[nr].cr.read().en().is_enabled() {}
129
130        T::Stream::clear_status_flags(&handle.dma);
131
132        // Set peripheral port register address
133        handle.dma.st[nr].par.write(|w| w.pa().bits(address));
134
135        // Set memory address
136        let memory_address = buffer.as_ptr() as u32;
137        handle.dma.st[nr]
138            .m0ar
139            .write(|w| w.m0a().bits(memory_address));
140
141        // Write number of data items to transfer
142        //
143        // We've asserted that `data.len()` fits into a `u16`, so the cast
144        // should be fine.
145        handle.dma.st[nr]
146            .ndtr
147            .write(|w| w.ndt().bits(buffer.len() as u16));
148
149        // Configure FIFO
150        handle.dma.st[nr].fcr.modify(|_, w| {
151            w
152                // Interrupt disabled
153                .feie()
154                .disabled()
155                // Direct mode enabled (FIFO disabled)
156                .dmdis()
157                .enabled()
158        });
159
160        // Select channel
161        handle.dma.st[nr].cr.write(|w| {
162            let w = T::Channel::select(w);
163
164            let w = match direction {
165                Direction::MemoryToPeripheral => w.dir().memory_to_peripheral(),
166                Direction::PeripheralToMemory => w.dir().peripheral_to_memory(),
167            };
168
169            w
170                // Single transfer
171                .mburst()
172                .single()
173                .pburst()
174                .single()
175                // Double-buffer mode disabled
176                .dbm()
177                .disabled()
178                // Very high priority
179                .pl()
180                .very_high()
181                // Memory data size
182                .msize()
183                .variant(Word::msize())
184                // Peripheral data size
185                .psize()
186                .variant(Word::psize())
187                // Memory increment mode
188                .minc()
189                .incremented()
190                // Peripheral increment mode
191                .pinc()
192                .fixed()
193                // Circular mode disabled
194                .circ()
195                .disabled()
196                // DMA is the flow controller
197                .pfctrl()
198                .dma()
199                // All interrupts disabled
200                .tcie()
201                .disabled()
202                .htie()
203                .disabled()
204                .teie()
205                .disabled()
206                .dmeie()
207                .disabled()
208        });
209
210        Transfer {
211            res: TransferResources {
212                stream,
213                buffer,
214                target,
215            },
216            _state: Ready,
217        }
218    }
219
220    /// Enables the given interrupts for this DMA transfer
221    ///
222    /// These interrupts are only enabled for this transfer. The settings
223    /// doesn't affect other transfers, nor subsequent transfers using the same
224    /// DMA stream.
225    pub fn enable_interrupts(
226        &mut self,
227        handle: &Handle<T::Instance, state::Enabled>,
228        interrupts: Interrupts,
229    ) {
230        handle.dma.st[T::Stream::number()].cr.modify(|_, w| {
231            let w = if interrupts.transfer_complete {
232                w.tcie().enabled()
233            } else {
234                w
235            };
236
237            let w = if interrupts.half_transfer {
238                w.htie().enabled()
239            } else {
240                w
241            };
242
243            let w = if interrupts.transfer_error {
244                w.teie().enabled()
245            } else {
246                w
247            };
248
249            let w = if interrupts.direct_mode_error {
250                w.dmeie().enabled()
251            } else {
252                w
253            };
254
255            w
256        });
257
258        // Enable interrupt.
259        unsafe { NVIC::unmask(T::INTERRUPT) };
260    }
261
262    /// Start the DMA transfer
263    ///
264    /// Consumes this instance of `Transfer` and returns another instance with
265    /// its type state set to indicate the transfer has been started.
266    pub fn start(self, handle: &Handle<T::Instance, state::Enabled>) -> Transfer<T, B, Started> {
267        T::Stream::clear_status_flags(&handle.dma);
268        atomic::fence(Ordering::SeqCst);
269
270        handle.dma.st[T::Stream::number()]
271            .cr
272            .modify(|_, w| w.en().enabled());
273
274        Transfer {
275            res: self.res,
276            _state: Started,
277        }
278    }
279}
280
281impl<T, B> Transfer<T, B, Started>
282where
283    T: Target,
284{
285    /// Checks whether the transfer is still ongoing
286    pub fn is_active(&self, handle: &Handle<T::Instance, state::Enabled>) -> bool {
287        handle.dma.st[T::Stream::number()]
288            .cr
289            .read()
290            .en()
291            .is_enabled()
292    }
293
294    /// Try to cancel an in process transfer. Check is_active to verify cancellation
295    pub fn cancel(&self, handle: &Handle<T::Instance, state::Enabled>) {
296        handle.dma.st[T::Stream::number()]
297            .cr
298            .write(|w| w.en().disabled());
299    }
300
301    /// Waits for the transfer to end
302    ///
303    /// This method will block if the transfer is still ongoing. If you want
304    /// this method to return immediately, first check whether the transfer is
305    /// still ongoing by calling `is_active`.
306    ///
307    /// An ongoing transfer needs exlusive access to some resources, namely the
308    /// data buffer, the DMA stream, and the peripheral. Those have been moved
309    /// into the `Transfer` instance to prevent concurrent access to them. This
310    /// method returns those resources, so they can be used again.
311    pub fn wait(
312        self,
313        handle: &Handle<T::Instance, state::Enabled>,
314    ) -> Result<TransferResources<T, B>, (TransferResources<T, B>, Error)> {
315        // Disable interrupt.
316        NVIC::mask(T::INTERRUPT);
317
318        // Wait for transfer to finish
319        while self.is_active(handle) {
320            if let Err(error) = Error::check::<T::Stream>(&handle.dma) {
321                return Err((self.res, error));
322            }
323        }
324
325        atomic::fence(Ordering::SeqCst);
326
327        if let Err(error) = Error::check::<T::Stream>(&handle.dma) {
328            return Err((self.res, error));
329        }
330
331        Ok(self.res)
332    }
333}
334
335/// The resources that an ongoing transfer needs exclusive access to
336pub struct TransferResources<T: Target, B> {
337    pub stream: T::Stream,
338    pub buffer: Pin<B>,
339    pub target: T,
340}
341
342// As `TransferResources` is used in the error variant of `Result`, it needs a
343// `Debug` implementation to enable stuff like `unwrap` and `expect`. This can't
344// be derived without putting requirements on the type arguments.
345impl<T, B> fmt::Debug for TransferResources<T, B>
346where
347    T: Target,
348{
349    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
350        write!(f, "TransferResources {{ .. }}")
351    }
352}
353
354pub(crate) enum Direction {
355    MemoryToPeripheral,
356    PeripheralToMemory,
357}
358
359/// Implemented for all peripheral APIs that support DMA transfers
360///
361/// This is an internal trait. End users neither need to implement it, nor use
362/// it directly.
363pub trait Target {
364    type Instance: Deref<Target = dma2::RegisterBlock>;
365    type Stream: Stream;
366    type Channel: Channel;
367
368    const INTERRUPT: Interrupt;
369}
370
371macro_rules! impl_target {
372    (
373        $(
374            $ty:ty,
375            $instance:ty,
376            $stream:ident,
377            $channel:ty,
378            $interrupt:ident;
379        )*
380    ) => {
381        $(
382            impl Target for $ty {
383                type Instance = $instance;
384                type Stream   = $stream<$instance>;
385                type Channel  = $channel;
386
387                const INTERRUPT: Interrupt = Interrupt::$interrupt;
388            }
389        )*
390    }
391}
392
393// See section 8.3.4, tables 25 and 26
394//
395// Some peripherals can be used with multiple stream/channel combinations. To
396// model this, we'd need to implement `Tx` multiple times, which means `Tx`
397// would need a type parameter. When attempting to do this, I ran into errors
398// about unconstrained type parameters when trying to use `Tx`.
399//
400// There's probably a smart way to achieve this, but I decided to declare
401// victory and leave this problem to someone who actually needs this capability.
402impl_target!(
403    // SPI receive
404    spi::Rx<pac::SPI1>, DMA2, Stream0, Channel3, DMA2_STREAM0;
405    // SPI1 for DMA2, stream 2, channel 3 is unsupported
406    spi::Rx<pac::SPI2>, DMA1, Stream3, Channel0, DMA1_STREAM3;
407    spi::Rx<pac::SPI3>, DMA1, Stream0, Channel0, DMA1_STREAM0;
408    // SPI3 for DMA1, stream 2, channel 0 is unsupported
409    spi::Rx<pac::SPI4>, DMA2, Stream0, Channel4, DMA2_STREAM0;
410    // SPI4 for DMA2, stream 3, channel 5 is unsupported
411    spi::Rx<pac::SPI5>, DMA2, Stream3, Channel2, DMA2_STREAM3;
412    // SPI5 for DMA2, stream 5, channel 7 is unsupported
413
414    // SPI transmit
415    spi::Tx<pac::SPI1>, DMA2, Stream3, Channel3, DMA2_STREAM3;
416    // SPI1 for DMA2, stream 5, channel 3 is unsupported
417    spi::Tx<pac::SPI2>, DMA1, Stream4, Channel0, DMA1_STREAM4;
418    spi::Tx<pac::SPI3>, DMA1, Stream5, Channel0, DMA1_STREAM5;
419    // SPI3 for DMA1, stream 7, channel 0 is unsupported
420    spi::Tx<pac::SPI4>, DMA2, Stream1, Channel4, DMA2_STREAM1;
421    // SPI4 for DMA2, stream 4, channel 5 is unsupported
422    spi::Tx<pac::SPI5>, DMA2, Stream4, Channel2, DMA2_STREAM4;
423    // SPI5 for DMA2, stream 6, channel 7 is unsupported
424
425    // USART receive
426    serial::Rx<pac::USART1>, DMA2, Stream2, Channel4, DMA2_STREAM2;
427    // USART1 for DMA2, stream 5, channel 4 is unsupported
428    serial::Rx<pac::USART2>, DMA1, Stream5, Channel4, DMA1_STREAM5;
429    serial::Rx<pac::USART3>, DMA1, Stream1, Channel4, DMA1_STREAM1;
430    serial::Rx<pac::UART4>, DMA1, Stream2, Channel4, DMA1_STREAM2;
431    serial::Rx<pac::UART5>, DMA1, Stream0, Channel4, DMA1_STREAM0;
432    serial::Rx<pac::USART6>, DMA2, Stream1, Channel5, DMA2_STREAM1;
433    // USART6 for DMA2, stream 2, channel 5 is unsupported
434    serial::Rx<pac::UART7>, DMA1, Stream3, Channel5, DMA1_STREAM3;
435    serial::Rx<pac::UART8>, DMA1, Stream6, Channel5, DMA1_STREAM6;
436
437    // USART transmit
438    serial::Tx<pac::USART1>, DMA2, Stream7, Channel4, DMA2_STREAM7;
439    serial::Tx<pac::USART2>, DMA1, Stream6, Channel4, DMA1_STREAM6;
440    serial::Tx<pac::USART3>, DMA1, Stream3, Channel4, DMA1_STREAM3;
441    // USART3 for DMA1, stream 4, channel 7 is unsupported
442    serial::Tx<pac::UART4>,  DMA1, Stream4, Channel4, DMA1_STREAM4;
443    serial::Tx<pac::UART5>,  DMA1, Stream7, Channel4, DMA1_STREAM7;
444    serial::Tx<pac::USART6>, DMA2, Stream6, Channel5, DMA2_STREAM6;
445    // USART6 for DMA2, stream 7, channel 5 is unsupported
446    serial::Tx<pac::UART7>,  DMA1, Stream1, Channel5, DMA1_STREAM1;
447    serial::Tx<pac::UART8>,  DMA1, Stream0, Channel5, DMA1_STREAM0;
448
449    // QUADSPI is half-duplex, uses one channel for both send/receive
450    qspi::RxTx<pac::QUADSPI>, DMA2, Stream7, Channel3, DMA2_STREAM7;
451);
452
453#[cfg(any(
454    feature = "stm32f745",
455    feature = "stm32f746",
456    feature = "stm32f756",
457    feature = "stm32f765",
458    feature = "stm32f767",
459    feature = "stm32f769",
460    feature = "stm32f777",
461    feature = "stm32f778",
462    feature = "stm32f779",
463))]
464impl_target!(
465    spi::Rx<pac::SPI6>, DMA2, Stream6, Channel1, DMA2_STREAM6;
466    spi::Tx<pac::SPI6>, DMA2, Stream5, Channel1, DMA2_STREAM5;
467);
468
469/// Implemented for all types that represent DMA streams
470///
471/// This is an internal trait. End users neither need to implement it, nor use
472/// it directly.
473pub trait Stream {
474    fn number() -> usize;
475
476    fn clear_status_flags(dma: &dma2::RegisterBlock);
477
478    fn is_transfer_complete(dma: &dma2::RegisterBlock) -> bool;
479    fn is_half_transfer(dma: &dma2::RegisterBlock) -> bool;
480    fn is_transfer_error(dma: &dma2::RegisterBlock) -> bool;
481    fn is_direct_mode_error(dma: &dma2::RegisterBlock) -> bool;
482    fn is_fifo_error(dma: &dma2::RegisterBlock) -> bool;
483}
484
485macro_rules! impl_stream {
486    (
487        $(
488            $name:ident,
489            $name_lower:ident,
490            $number:expr,
491            $flag_reg:ident,
492            $feif:ident,
493            $dmeif:ident,
494            $teif:ident,
495            $htif:ident,
496            $tcif:ident,
497            $flag_clear_reg:ident,
498            ($($flag_clear_field:ident,)*);
499        )*
500    ) => {
501        pub struct Streams<I> {
502            $(pub $name_lower: $name<I>,)*
503        }
504
505        impl<I> Streams<I> {
506            fn new() -> Self {
507                Self {
508                    $($name_lower: $name(PhantomData),)*
509                }
510            }
511        }
512
513
514        $(
515            pub struct $name<I>(PhantomData<I>);
516
517            impl<I> Stream for $name<I> {
518                fn number() -> usize { $number }
519
520                fn clear_status_flags(dma: &dma2::RegisterBlock) {
521                    dma.$flag_clear_reg.write(|w|
522                        w
523                            $(.$flag_clear_field().clear())*
524                    );
525                }
526
527                fn is_transfer_complete(dma: &dma2::RegisterBlock) -> bool {
528                    dma.$flag_reg.read().$tcif().is_complete()
529                }
530                fn is_half_transfer(dma: &dma2::RegisterBlock) -> bool {
531                    dma.$flag_reg.read().$htif().is_half()
532                }
533                fn is_transfer_error(dma: &dma2::RegisterBlock) -> bool {
534                    dma.$flag_reg.read().$teif().is_error()
535                }
536                fn is_direct_mode_error(dma: &dma2::RegisterBlock) -> bool {
537                    dma.$flag_reg.read().$dmeif().is_error()
538                }
539                fn is_fifo_error(dma: &dma2::RegisterBlock) -> bool {
540                    dma.$flag_reg.read().$feif().is_error()
541                }
542            }
543        )*
544    }
545}
546
547impl_stream!(
548    Stream0, stream0, 0,
549        lisr, feif0, dmeif0, teif0, htif0, tcif0,
550        lifcr, (cfeif0, cdmeif0, cteif0, chtif0, ctcif0,);
551    Stream1, stream1, 1,
552        lisr, feif1, dmeif1, teif1, htif1, tcif1,
553        lifcr, (cfeif1, cdmeif1, cteif1, chtif1, ctcif1,);
554    Stream2, stream2, 2,
555        lisr, feif2, dmeif2, teif2, htif2, tcif2,
556        lifcr, (cfeif2, cdmeif2, cteif2, chtif2, ctcif2,);
557    Stream3, stream3, 3,
558        lisr, feif3, dmeif3, teif3, htif3, tcif3,
559        lifcr, (cfeif3, cdmeif3, cteif3, chtif3, ctcif3,);
560    Stream4, stream4, 4,
561        hisr, feif4, dmeif4, teif4, htif4, tcif4,
562        hifcr, (cfeif4, cdmeif4, cteif4, chtif4, ctcif4,);
563    Stream5, stream5, 5,
564        hisr, feif5, dmeif5, teif5, htif5, tcif5,
565        hifcr, (cfeif5, cdmeif5, cteif5, chtif5, ctcif5,);
566    Stream6, stream6, 6,
567        hisr, feif6, dmeif6, teif6, htif6, tcif6,
568        hifcr, (cfeif6, cdmeif6, cteif6, chtif6, ctcif6,);
569    Stream7, stream7, 7,
570        hisr, feif7, dmeif7, teif7, htif7, tcif7,
571        hifcr, (cfeif7, cdmeif7, cteif7, chtif7, ctcif7,);
572);
573
574/// Implemented for all types that represent DMA channels
575///
576/// This is an internal trait. End users neither need to implement it, nor use
577/// it directly.
578pub trait Channel {
579    fn select(w: &mut dma2::st::cr::W) -> &mut dma2::st::cr::W;
580}
581
582macro_rules! impl_channel {
583    ($($name:ident, $number:expr;)*) => {
584        $(
585            pub struct $name;
586
587            impl Channel for $name {
588                fn select<'r>(w: &'r mut dma2::st::cr::W)
589                    -> &'r mut dma2::st::cr::W
590                {
591                    // This is safe, as long as the macro caller passes in valid
592                    // channel numbers.
593                    w.chsel().bits($number)
594                }
595            }
596        )*
597    }
598}
599
600impl_channel!(
601    Channel0, 0;
602    Channel1, 1;
603    Channel2, 2;
604    Channel3, 3;
605    Channel4, 4;
606    Channel5, 5;
607    Channel6, 6;
608    Channel7, 7;
609);
610
611/// Implemented for all DMA instances
612///
613/// This is an internal trait. End users neither need to implement it, nor use
614/// it directly.
615pub trait Instance {}
616
617macro_rules! impl_instance {
618    ($($name:ty;)*) => {
619        $(
620            impl Instance for $name {
621            }
622        )*
623    }
624}
625
626impl_instance!(
627    DMA1;
628    DMA2;
629);
630
631/// Used by [`Transfer::enable_interrupts`] to identify DMA interrupts
632#[derive(Clone, Copy)]
633pub struct Interrupts {
634    pub transfer_complete: bool,
635    pub half_transfer: bool,
636    pub transfer_error: bool,
637    pub direct_mode_error: bool,
638}
639
640impl Default for Interrupts {
641    fn default() -> Self {
642        Self {
643            transfer_complete: false,
644            half_transfer: false,
645            transfer_error: false,
646            direct_mode_error: false,
647        }
648    }
649}
650
651/// A DMA error
652#[derive(Debug)]
653pub enum Error {
654    Transfer,
655    DirectMode,
656}
657
658impl Error {
659    pub(crate) fn check<S>(dma: &dma2::RegisterBlock) -> Result<(), Self>
660    where
661        S: Stream,
662    {
663        if S::is_transfer_error(dma) {
664            return Err(Error::Transfer);
665        }
666        if S::is_direct_mode_error(dma) {
667            return Err(Error::DirectMode);
668        }
669        // We're not checking for FIFO errors here. FIFO mode is not enabled
670        // anyway, but the error flag is still set for some reason, even though
671        // everything works.
672
673        Ok(())
674    }
675}
676
677/// Indicates that a DMA transfer is ready to be started
678pub struct Ready;
679
680/// Indicates that a DMA transfer has been started
681pub struct Started;
682
683/// Implemented for types that can be used as a buffer for DMA transfers
684pub(crate) trait Buffer<Word> {
685    fn as_ptr(&self) -> *const Word;
686    fn len(&self) -> usize;
687}
688
689impl<T, Word> Buffer<Word> for T
690where
691    T: ?Sized + AsSlice<Element = Word>,
692{
693    fn as_ptr(&self) -> *const Word {
694        self.as_slice().as_ptr()
695    }
696
697    fn len(&self) -> usize {
698        self.as_slice().len()
699    }
700}
701
702/// Can be used as a fallback [`Buffer`], if safer implementations can't be used
703///
704/// The `ptr` and `len` fields MUST define a valid memory region.
705pub(crate) struct PtrBuffer<Word: SupportedWordSize> {
706    pub ptr: *const Word,
707    pub len: usize,
708}
709
710// Required to make in possible to put this in a `Pin`, in a way that satisfies
711// the requirements on `Transfer::new`.
712impl<Word> Deref for PtrBuffer<Word>
713where
714    Word: SupportedWordSize,
715{
716    type Target = Self;
717
718    fn deref(&self) -> &Self::Target {
719        self
720    }
721}
722
723impl<Word> Buffer<Word> for PtrBuffer<Word>
724where
725    Word: SupportedWordSize,
726{
727    fn as_ptr(&self) -> *const Word {
728        self.ptr
729    }
730
731    fn len(&self) -> usize {
732        self.len
733    }
734}
735
736pub trait SupportedWordSize: private::Sealed + Unpin + 'static {
737    fn msize() -> cr::MSIZE_A;
738    fn psize() -> cr::PSIZE_A;
739}
740
741impl private::Sealed for u8 {}
742impl SupportedWordSize for u8 {
743    fn msize() -> cr::MSIZE_A {
744        cr::MSIZE_A::Bits8
745    }
746
747    fn psize() -> cr::PSIZE_A {
748        cr::MSIZE_A::Bits8
749    }
750}
751
752impl private::Sealed for u16 {}
753impl SupportedWordSize for u16 {
754    fn msize() -> cr::MSIZE_A {
755        cr::MSIZE_A::Bits16
756    }
757
758    fn psize() -> cr::PSIZE_A {
759        cr::MSIZE_A::Bits16
760    }
761}
762
763mod private {
764    /// Prevents code outside of the parent module from implementing traits
765    ///
766    /// This trait is located in a module that is not accessible outside of the
767    /// parent module. This means that any trait that requires `Sealed` cannot
768    /// be implemented only in the parent module.
769    pub trait Sealed {}
770}