aboutsummaryrefslogtreecommitdiff
path: root/embassy-mspm0/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-mspm0/src/lib.rs')
-rw-r--r--embassy-mspm0/src/lib.rs115
1 files changed, 112 insertions, 3 deletions
diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs
index 7ff60e946..bb8d91403 100644
--- a/embassy-mspm0/src/lib.rs
+++ b/embassy-mspm0/src/lib.rs
@@ -13,6 +13,7 @@ pub(crate) mod fmt;
13// This must be declared early as well for 13// This must be declared early as well for
14mod macros; 14mod macros;
15 15
16pub mod dma;
16pub mod gpio; 17pub mod gpio;
17pub mod timer; 18pub mod timer;
18pub mod uart; 19pub mod uart;
@@ -59,22 +60,106 @@ pub(crate) use mspm0_metapac as pac;
59 60
60pub use crate::_generated::interrupt; 61pub use crate::_generated::interrupt;
61 62
63/// Macro to bind interrupts to handlers.
64///
65/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
66/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
67/// prove at compile-time that the right interrupts have been bound.
68///
69/// Example of how to bind one interrupt:
70///
71/// ```rust,ignore
72/// use embassy_nrf::{bind_interrupts, spim, peripherals};
73///
74/// bind_interrupts!(
75/// /// Binds the SPIM3 interrupt.
76/// struct Irqs {
77/// SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
78/// }
79/// );
80/// ```
81///
82/// Example of how to bind multiple interrupts in a single macro invocation:
83///
84/// ```rust,ignore
85/// use embassy_nrf::{bind_interrupts, spim, twim, peripherals};
86///
87/// bind_interrupts!(struct Irqs {
88/// SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
89/// TWISPI0 => twim::InterruptHandler<peripherals::TWISPI0>;
90/// });
91/// ```
92
93// developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`.
94#[macro_export]
95macro_rules! bind_interrupts {
96 ($(#[$attr:meta])* $vis:vis struct $name:ident {
97 $(
98 $(#[cfg($cond_irq:meta)])?
99 $irq:ident => $(
100 $(#[cfg($cond_handler:meta)])?
101 $handler:ty
102 ),*;
103 )*
104 }) => {
105 #[derive(Copy, Clone)]
106 $(#[$attr])*
107 $vis struct $name;
108
109 $(
110 #[allow(non_snake_case)]
111 #[no_mangle]
112 $(#[cfg($cond_irq)])?
113 unsafe extern "C" fn $irq() {
114 $(
115 $(#[cfg($cond_handler)])?
116 <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
117
118 )*
119 }
120
121 $(#[cfg($cond_irq)])?
122 $crate::bind_interrupts!(@inner
123 $(
124 $(#[cfg($cond_handler)])?
125 unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
126 )*
127 );
128 )*
129 };
130 (@inner $($t:tt)*) => {
131 $($t)*
132 }
133}
134
62/// `embassy-mspm0` global configuration. 135/// `embassy-mspm0` global configuration.
63#[non_exhaustive] 136#[non_exhaustive]
64#[derive(Clone, Copy)] 137#[derive(Clone, Copy)]
65pub struct Config { 138pub struct Config {
66 // TODO 139 // TODO: OSC configuration.
140 /// The size of DMA block transfer burst.
141 ///
142 /// If this is set to a value
143 pub dma_burst_size: dma::BurstSize,
144
145 /// Whether the DMA channels are used in a fixed priority or a round robin fashion.
146 ///
147 /// If [`false`], the DMA priorities are fixed.
148 ///
149 /// If [`true`], after a channel finishes a transfer it becomes the lowest priority.
150 pub dma_round_robin: bool,
67} 151}
68 152
69impl Default for Config { 153impl Default for Config {
70 fn default() -> Self { 154 fn default() -> Self {
71 Self { 155 Self {
72 // TODO 156 dma_burst_size: dma::BurstSize::Complete,
157 dma_round_robin: false,
73 } 158 }
74 } 159 }
75} 160}
76 161
77pub fn init(_config: Config) -> Peripherals { 162pub fn init(config: Config) -> Peripherals {
78 critical_section::with(|cs| { 163 critical_section::with(|cs| {
79 let peripherals = Peripherals::take_with_cs(cs); 164 let peripherals = Peripherals::take_with_cs(cs);
80 165
@@ -112,9 +197,33 @@ pub fn init(_config: Config) -> Peripherals {
112 crate::interrupt::typelevel::GPIOA::enable(); 197 crate::interrupt::typelevel::GPIOA::enable();
113 } 198 }
114 199
200 // SAFETY: Peripherals::take_with_cs will only be run once or panic.
201 unsafe { dma::init(cs, config.dma_burst_size, config.dma_round_robin) };
202
115 #[cfg(feature = "_time-driver")] 203 #[cfg(feature = "_time-driver")]
116 time_driver::init(cs); 204 time_driver::init(cs);
117 205
118 peripherals 206 peripherals
119 }) 207 })
120} 208}
209
210pub(crate) mod sealed {
211 #[allow(dead_code)]
212 pub trait Sealed {}
213}
214
215struct BitIter(u32);
216
217impl Iterator for BitIter {
218 type Item = u32;
219
220 fn next(&mut self) -> Option<Self::Item> {
221 match self.0.trailing_zeros() {
222 32 => None,
223 b => {
224 self.0 &= !(1 << b);
225 Some(b)
226 }
227 }
228 }
229}