1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
|
#![no_std]
#![allow(unsafe_op_in_unsafe_fn)]
// This mod MUST go first, so that the others see its macros.
pub(crate) mod fmt;
#[cfg(feature = "lpc55-core0")]
pub mod dma;
pub mod gpio;
#[cfg(feature = "lpc55-core0")]
pub mod pint;
#[cfg(feature = "lpc55-core0")]
pub mod pwm;
#[cfg(feature = "lpc55-core0")]
pub mod usart;
#[cfg(feature = "_time_driver")]
#[cfg_attr(feature = "time-driver-pit", path = "time_driver/pit.rs")]
#[cfg_attr(feature = "time-driver-rtc", path = "time_driver/rtc.rs")]
mod time_driver;
// This mod MUST go last, so that it sees all the `impl_foo!` macros
#[cfg_attr(feature = "lpc55-core0", path = "chips/lpc55.rs")]
#[cfg_attr(feature = "mimxrt1011", path = "chips/mimxrt1011.rs")]
#[cfg_attr(feature = "mimxrt1062", path = "chips/mimxrt1062.rs")]
mod chip;
// TODO: Remove when this module is implemented for other chips
#[cfg(feature = "lpc55-core0")]
pub use chip::interrupt;
#[cfg(feature = "unstable-pac")]
pub use chip::pac;
#[cfg(not(feature = "unstable-pac"))]
pub(crate) use chip::pac;
pub use chip::{Peripherals, peripherals};
pub use embassy_hal_internal::{Peri, PeripheralType};
/// Macro to bind interrupts to handlers.
/// (Copied from `embassy-rp`)
/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
/// prove at compile-time that the right interrupts have been bound.
///
/// Example of how to bind one interrupt:
///
/// ```rust,ignore
/// use embassy_nxp::{bind_interrupts, usart, peripherals};
///
/// bind_interrupts!(
/// /// Binds the USART Interrupts.
/// struct Irqs {
/// FLEXCOMM0 => usart::InterruptHandler<peripherals::USART0>;
/// }
/// );
/// ```
#[macro_export]
macro_rules! bind_interrupts {
($(#[$attr:meta])* $vis:vis struct $name:ident {
$(
$(#[cfg($cond_irq:meta)])?
$irq:ident => $(
$(#[cfg($cond_handler:meta)])?
$handler:ty
),*;
)*
}) => {
#[derive(Copy, Clone)]
$(#[$attr])*
$vis struct $name;
$(
#[allow(non_snake_case)]
#[unsafe(no_mangle)]
$(#[cfg($cond_irq)])?
unsafe extern "C" fn $irq() {
unsafe {
$(
$(#[cfg($cond_handler)])?
<$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
)*
}
}
$(#[cfg($cond_irq)])?
$crate::bind_interrupts!(@inner
$(
$(#[cfg($cond_handler)])?
unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
)*
);
)*
};
(@inner $($t:tt)*) => {
$($t)*
}
}
/// Initialize the `embassy-nxp` HAL with the provided configuration.
///
/// This returns the peripheral singletons that can be used for creating drivers.
///
/// This should only be called once and at startup, otherwise it panics.
pub fn init(_config: config::Config) -> Peripherals {
// Do this first, so that it panics if user is calling `init` a second time
// before doing anything important.
let peripherals = Peripherals::take();
#[cfg(feature = "mimxrt1011")]
{
// The RT1010 Reference manual states that core clock root must be switched before
// reprogramming PLL2.
pac::CCM.cbcdr().modify(|w| {
w.set_periph_clk_sel(pac::ccm::vals::PeriphClkSel::PERIPH_CLK_SEL_1);
});
while matches!(
pac::CCM.cdhipr().read().periph_clk_sel_busy(),
pac::ccm::vals::PeriphClkSelBusy::PERIPH_CLK_SEL_BUSY_1
) {}
info!("Core clock root switched");
// 480 * 18 / 24 = 360
pac::CCM_ANALOG.pfd_480().modify(|x| x.set_pfd2_frac(12));
//480*18/24(pfd0)/4
pac::CCM_ANALOG.pfd_480().modify(|x| x.set_pfd0_frac(24));
pac::CCM.cscmr1().modify(|x| x.set_flexspi_podf(3.into()));
// CPU Core
pac::CCM_ANALOG.pfd_528().modify(|x| x.set_pfd3_frac(18));
cortex_m::asm::delay(500_000);
// Clock core clock with PLL 2.
pac::CCM
.cbcdr()
.modify(|x| x.set_periph_clk_sel(pac::ccm::vals::PeriphClkSel::PERIPH_CLK_SEL_0)); // false
while matches!(
pac::CCM.cdhipr().read().periph_clk_sel_busy(),
pac::ccm::vals::PeriphClkSelBusy::PERIPH_CLK_SEL_BUSY_1
) {}
pac::CCM
.cbcmr()
.write(|v| v.set_pre_periph_clk_sel(pac::ccm::vals::PrePeriphClkSel::PRE_PERIPH_CLK_SEL_0));
// TODO: Some for USB PLLs
// DCDC clock?
pac::CCM.ccgr6().modify(|v| v.set_cg0(1));
}
#[cfg(any(feature = "lpc55-core0", rt1xxx))]
gpio::init();
#[cfg(feature = "lpc55-core0")]
{
pint::init();
pwm::Pwm::reset();
}
#[cfg(feature = "_time_driver")]
time_driver::init();
#[cfg(feature = "lpc55-core0")]
dma::init();
peripherals
}
/// HAL configuration for the NXP board.
pub mod config {
#[derive(Default)]
pub struct Config {}
}
#[allow(unused)]
struct BitIter(u32);
impl Iterator for BitIter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
match self.0.trailing_zeros() {
32 => None,
b => {
self.0 &= !(1 << b);
Some(b)
}
}
}
}
trait SealedMode {}
/// UART mode.
#[allow(private_bounds)]
pub trait Mode: SealedMode {}
macro_rules! impl_mode {
($name:ident) => {
impl SealedMode for $name {}
impl Mode for $name {}
};
}
/// Blocking mode.
pub struct Blocking;
/// Asynchronous mode.
pub struct Async;
impl_mode!(Blocking);
impl_mode!(Async);
|