aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/clocks/mod.rs9
-rw-r--r--src/clocks/periph_helpers.rs113
-rw-r--r--src/i2c/controller.rs455
-rw-r--r--src/i2c/mod.rs171
-rw-r--r--src/interrupt.rs4
-rw-r--r--src/lib.rs1
6 files changed, 750 insertions, 3 deletions
diff --git a/src/clocks/mod.rs b/src/clocks/mod.rs
index cd6318c4b..9c9e6ef3d 100644
--- a/src/clocks/mod.rs
+++ b/src/clocks/mod.rs
@@ -553,7 +553,7 @@ impl Clocks {
553 return Err(ClockError::BadConfig { 553 return Err(ClockError::BadConfig {
554 clock: "main_clk", 554 clock: "main_clk",
555 reason: "not low power active", 555 reason: "not low power active",
556 }) 556 });
557 } 557 }
558 } 558 }
559 559
@@ -904,7 +904,7 @@ macro_rules! impl_cc_gate {
904pub(crate) mod gate { 904pub(crate) mod gate {
905 #[cfg(not(feature = "time"))] 905 #[cfg(not(feature = "time"))]
906 use super::periph_helpers::OsTimerConfig; 906 use super::periph_helpers::OsTimerConfig;
907 use super::periph_helpers::{AdcConfig, LpuartConfig, NoConfig}; 907 use super::periph_helpers::{AdcConfig, Lpi2cConfig, LpuartConfig, NoConfig};
908 use super::*; 908 use super::*;
909 909
910 // These peripherals have no additional upstream clocks or configuration required 910 // These peripherals have no additional upstream clocks or configuration required
@@ -928,6 +928,11 @@ pub(crate) mod gate {
928 #[cfg(not(feature = "time"))] 928 #[cfg(not(feature = "time"))]
929 impl_cc_gate!(OSTIMER0, mrcc_glb_cc1, mrcc_glb_rst1, ostimer0, OsTimerConfig); 929 impl_cc_gate!(OSTIMER0, mrcc_glb_cc1, mrcc_glb_rst1, ostimer0, OsTimerConfig);
930 930
931 impl_cc_gate!(LPI2C0, mrcc_glb_cc0, mrcc_glb_rst0, lpi2c0, Lpi2cConfig);
932 impl_cc_gate!(LPI2C1, mrcc_glb_cc0, mrcc_glb_rst0, lpi2c1, Lpi2cConfig);
933 impl_cc_gate!(LPI2C2, mrcc_glb_cc1, mrcc_glb_rst1, lpi2c2, Lpi2cConfig);
934 impl_cc_gate!(LPI2C3, mrcc_glb_cc1, mrcc_glb_rst1, lpi2c3, Lpi2cConfig);
935
931 impl_cc_gate!(LPUART0, mrcc_glb_cc0, mrcc_glb_rst0, lpuart0, LpuartConfig); 936 impl_cc_gate!(LPUART0, mrcc_glb_cc0, mrcc_glb_rst0, lpuart0, LpuartConfig);
932 impl_cc_gate!(LPUART1, mrcc_glb_cc0, mrcc_glb_rst0, lpuart1, LpuartConfig); 937 impl_cc_gate!(LPUART1, mrcc_glb_cc0, mrcc_glb_rst0, lpuart1, LpuartConfig);
933 impl_cc_gate!(LPUART2, mrcc_glb_cc0, mrcc_glb_rst0, lpuart2, LpuartConfig); 938 impl_cc_gate!(LPUART2, mrcc_glb_cc0, mrcc_glb_rst0, lpuart2, LpuartConfig);
diff --git a/src/clocks/periph_helpers.rs b/src/clocks/periph_helpers.rs
index eac3ef8dd..24d074e8a 100644
--- a/src/clocks/periph_helpers.rs
+++ b/src/clocks/periph_helpers.rs
@@ -124,6 +124,119 @@ impl SPConfHelper for NoConfig {
124} 124}
125 125
126// 126//
127// LPI2c
128//
129
130/// Selectable clocks for `Lpi2c` peripherals
131#[derive(Debug, Clone, Copy)]
132pub enum Lpi2cClockSel {
133 /// FRO12M/FRO_LF/SIRC clock source, passed through divider
134 /// "fro_lf_div"
135 FroLfDiv,
136 /// FRO180M/FRO_HF/FIRC clock source, passed through divider
137 /// "fro_hf_div"
138 FroHfDiv,
139 /// SOSC/XTAL/EXTAL clock source
140 ClkIn,
141 /// clk_1m/FRO_LF divided by 12
142 Clk1M,
143 /// Output of PLL1, passed through clock divider,
144 /// "pll1_clk_div", maybe "pll1_lf_div"?
145 Pll1ClkDiv,
146 /// Disabled
147 None,
148}
149
150/// Which instance of the `Lpi2c` is this?
151///
152/// Should not be directly selectable by end-users.
153#[derive(Copy, Clone, Debug, PartialEq, Eq)]
154pub enum Lpi2cInstance {
155 /// Instance 0
156 Lpi2c0,
157 /// Instance 1
158 Lpi2c1,
159 /// Instance 2
160 Lpi2c2,
161 /// Instance 3
162 Lpi2c3,
163}
164
165/// Top level configuration for `Lpi2c` instances.
166pub struct Lpi2cConfig {
167 /// Power state required for this peripheral
168 pub power: PoweredClock,
169 /// Clock source
170 pub source: Lpi2cClockSel,
171 /// Clock divisor
172 pub div: Div4,
173 /// Which instance is this?
174 // NOTE: should not be user settable
175 pub(crate) instance: Lpi2cInstance,
176}
177
178impl SPConfHelper for Lpi2cConfig {
179 fn post_enable_config(&self, clocks: &Clocks) -> Result<u32, ClockError> {
180 // check that source is suitable
181 let mrcc0 = unsafe { pac::Mrcc0::steal() };
182 use mcxa_pac::mrcc0::mrcc_lpi2c0_clksel::Mux;
183
184 let (clkdiv, clksel) = match self.instance {
185 Lpi2cInstance::Lpi2c0 => (mrcc0.mrcc_lpi2c0_clkdiv(), mrcc0.mrcc_lpi2c0_clksel()),
186 Lpi2cInstance::Lpi2c1 => (mrcc0.mrcc_lpi2c1_clkdiv(), mrcc0.mrcc_lpi2c1_clksel()),
187 Lpi2cInstance::Lpi2c2 => (mrcc0.mrcc_lpi2c2_clkdiv(), mrcc0.mrcc_lpi2c2_clksel()),
188 Lpi2cInstance::Lpi2c3 => (mrcc0.mrcc_lpi2c3_clkdiv(), mrcc0.mrcc_lpi2c3_clksel()),
189 };
190
191 let (freq, variant) = match self.source {
192 Lpi2cClockSel::FroLfDiv => {
193 let freq = clocks.ensure_fro_lf_div_active(&self.power)?;
194 (freq, Mux::ClkrootFunc0)
195 }
196 Lpi2cClockSel::FroHfDiv => {
197 let freq = clocks.ensure_fro_hf_div_active(&self.power)?;
198 (freq, Mux::ClkrootFunc2)
199 }
200 Lpi2cClockSel::ClkIn => {
201 let freq = clocks.ensure_clk_in_active(&self.power)?;
202 (freq, Mux::ClkrootFunc3)
203 }
204 Lpi2cClockSel::Clk1M => {
205 let freq = clocks.ensure_clk_1m_active(&self.power)?;
206 (freq, Mux::ClkrootFunc5)
207 }
208 Lpi2cClockSel::Pll1ClkDiv => {
209 let freq = clocks.ensure_pll1_clk_div_active(&self.power)?;
210 (freq, Mux::ClkrootFunc6)
211 }
212 Lpi2cClockSel::None => unsafe {
213 // no ClkrootFunc7, just write manually for now
214 clksel.write(|w| w.bits(0b111));
215 clkdiv.modify(|_r, w| w.reset().asserted().halt().asserted());
216 return Ok(0);
217 },
218 };
219
220 // set clksel
221 clksel.modify(|_r, w| w.mux().variant(variant));
222
223 // Set up clkdiv
224 clkdiv.modify(|_r, w| {
225 unsafe { w.div().bits(self.div.into_bits()) }
226 .halt()
227 .asserted()
228 .reset()
229 .asserted()
230 });
231 clkdiv.modify(|_r, w| w.halt().deasserted().reset().deasserted());
232
233 while clkdiv.read().unstab().is_unstable() {}
234
235 Ok(freq / self.div.into_divisor())
236 }
237}
238
239//
127// LPUart 240// LPUart
128// 241//
129 242
diff --git a/src/i2c/controller.rs b/src/i2c/controller.rs
new file mode 100644
index 000000000..41bbc821d
--- /dev/null
+++ b/src/i2c/controller.rs
@@ -0,0 +1,455 @@
1//! LPI2C controller driver
2
3use core::marker::PhantomData;
4
5use embassy_hal_internal::Peri;
6use mcxa_pac::lpi2c0::mtdr::Cmd;
7
8use super::{Blocking, Error, Instance, Mode, Result, SclPin, SdaPin};
9use crate::clocks::periph_helpers::{Div4, Lpi2cClockSel, Lpi2cConfig};
10use crate::clocks::{enable_and_reset, PoweredClock};
11use crate::AnyPin;
12
13/// Bus speed (nominal SCL, no clock stretching)
14#[derive(Clone, Copy, Default, PartialEq)]
15#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16pub enum Speed {
17 #[default]
18 /// 100 kbit/sec
19 Standard,
20 /// 400 kbit/sec
21 Fast,
22 /// 1 Mbit/sec
23 FastPlus,
24 /// 3.4 Mbit/sec
25 UltraFast,
26}
27
28impl From<Speed> for (u8, u8, u8, u8) {
29 fn from(value: Speed) -> (u8, u8, u8, u8) {
30 match value {
31 Speed::Standard => (0x3d, 0x37, 0x3b, 0x1d),
32 Speed::Fast => (0x0e, 0x0c, 0x0d, 0x06),
33 Speed::FastPlus => (0x04, 0x03, 0x03, 0x02),
34
35 // UltraFast is "special". Leaving it unimplemented until
36 // the driver and the clock API is further stabilized.
37 Speed::UltraFast => todo!(),
38 }
39 }
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43#[cfg_attr(feature = "defmt", derive(defmt::Format))]
44enum SendStop {
45 No,
46 Yes,
47}
48
49/// I2C controller configuration
50#[derive(Clone, Copy, Default)]
51#[non_exhaustive]
52pub struct Config {
53 /// Bus speed
54 pub speed: Speed,
55}
56
57/// I2C Controller Driver.
58pub struct I2c<'d, T: Instance, M: Mode> {
59 _peri: Peri<'d, T>,
60 _scl: Peri<'d, AnyPin>,
61 _sda: Peri<'d, AnyPin>,
62 _phantom: PhantomData<M>,
63 is_hs: bool,
64}
65
66impl<'d, T: Instance> I2c<'d, T, Blocking> {
67 /// Create a new blocking instance of the I2C Controller bus driver.
68 pub fn new_blocking(
69 peri: Peri<'d, T>,
70 scl: Peri<'d, impl SclPin<T>>,
71 sda: Peri<'d, impl SdaPin<T>>,
72 config: Config,
73 ) -> Result<Self> {
74 Self::new_inner(peri, scl, sda, config)
75 }
76}
77
78impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
79 fn new_inner(
80 _peri: Peri<'d, T>,
81 scl: Peri<'d, impl SclPin<T>>,
82 sda: Peri<'d, impl SdaPin<T>>,
83 config: Config,
84 ) -> Result<Self> {
85 let (power, source, div) = Self::clock_config(config.speed);
86
87 // Enable clocks
88 let conf = Lpi2cConfig {
89 power,
90 source,
91 div,
92 instance: T::CLOCK_INSTANCE,
93 };
94
95 _ = unsafe { enable_and_reset::<T>(&conf).map_err(Error::ClockSetup)? };
96
97 scl.mux();
98 sda.mux();
99
100 let _scl = scl.into();
101 let _sda = sda.into();
102
103 Self::set_config(&config)?;
104
105 Ok(Self {
106 _peri,
107 _scl,
108 _sda,
109 _phantom: PhantomData,
110 is_hs: config.speed == Speed::UltraFast,
111 })
112 }
113
114 fn set_config(config: &Config) -> Result<()> {
115 // Disable the controller.
116 critical_section::with(|_| T::regs().mcr().modify(|_, w| w.men().disabled()));
117
118 // Soft-reset the controller, read and write FIFOs.
119 critical_section::with(|_| {
120 T::regs()
121 .mcr()
122 .modify(|_, w| w.rst().reset().rtf().reset().rrf().reset());
123 // According to Reference Manual section 40.7.1.4, "There
124 // is no minimum delay required before clearing the
125 // software reset", therefore we clear it immediately.
126 T::regs().mcr().modify(|_, w| w.rst().not_reset());
127
128 T::regs().mcr().modify(|_, w| w.dozen().clear_bit().dbgen().clear_bit());
129 });
130
131 let (clklo, clkhi, sethold, datavd) = config.speed.into();
132
133 critical_section::with(|_| {
134 T::regs().mccr0().modify(|_, w| unsafe {
135 w.clklo()
136 .bits(clklo)
137 .clkhi()
138 .bits(clkhi)
139 .sethold()
140 .bits(sethold)
141 .datavd()
142 .bits(datavd)
143 })
144 });
145
146 // Enable the controller.
147 critical_section::with(|_| T::regs().mcr().modify(|_, w| w.men().enabled()));
148
149 // Clear all flags
150 T::regs().msr().write(|w| {
151 w.epf()
152 .clear_bit_by_one()
153 .sdf()
154 .clear_bit_by_one()
155 .ndf()
156 .clear_bit_by_one()
157 .alf()
158 .clear_bit_by_one()
159 .fef()
160 .clear_bit_by_one()
161 .pltf()
162 .clear_bit_by_one()
163 .dmf()
164 .clear_bit_by_one()
165 .stf()
166 .clear_bit_by_one()
167 });
168
169 Ok(())
170 }
171
172 // REVISIT: turn this into a function of the speed parameter
173 fn clock_config(speed: Speed) -> (PoweredClock, Lpi2cClockSel, Div4) {
174 match speed {
175 Speed::Standard | Speed::Fast | Speed::FastPlus => (
176 PoweredClock::NormalEnabledDeepSleepDisabled,
177 Lpi2cClockSel::FroLfDiv,
178 const { Div4::no_div() },
179 ),
180 Speed::UltraFast => (
181 PoweredClock::NormalEnabledDeepSleepDisabled,
182 Lpi2cClockSel::FroHfDiv,
183 const { Div4::no_div() },
184 ),
185 }
186 }
187
188 fn is_tx_fifo_full(&mut self) -> bool {
189 let txfifo_size = 1 << T::regs().param().read().mtxfifo().bits();
190 T::regs().mfsr().read().txcount().bits() == txfifo_size
191 }
192
193 fn is_tx_fifo_empty(&mut self) -> bool {
194 T::regs().mfsr().read().txcount() == 0
195 }
196
197 fn is_rx_fifo_empty(&mut self) -> bool {
198 T::regs().mfsr().read().rxcount() == 0
199 }
200
201 fn status(&mut self) -> Result<()> {
202 // Wait for TxFIFO to be drained
203 while !self.is_tx_fifo_empty() {}
204
205 let msr = T::regs().msr().read();
206 T::regs().msr().write(|w| {
207 w.epf()
208 .clear_bit_by_one()
209 .sdf()
210 .clear_bit_by_one()
211 .ndf()
212 .clear_bit_by_one()
213 .alf()
214 .clear_bit_by_one()
215 .fef()
216 .clear_bit_by_one()
217 .fef()
218 .clear_bit_by_one()
219 .pltf()
220 .clear_bit_by_one()
221 .dmf()
222 .clear_bit_by_one()
223 .stf()
224 .clear_bit_by_one()
225 });
226
227 if msr.ndf().bit_is_set() {
228 Err(Error::AddressNack)
229 } else if msr.alf().bit_is_set() {
230 Err(Error::ArbitrationLoss)
231 } else {
232 Ok(())
233 }
234 }
235
236 fn send_cmd(&mut self, cmd: Cmd, data: u8) {
237 #[cfg(feature = "defmt")]
238 defmt::trace!(
239 "Sending cmd '{}' ({}) with data '{:08x}' MSR: {:08x}",
240 cmd,
241 cmd as u8,
242 data,
243 T::regs().msr().read().bits()
244 );
245
246 T::regs()
247 .mtdr()
248 .write(|w| unsafe { w.data().bits(data) }.cmd().variant(cmd));
249 }
250
251 fn start(&mut self, address: u8, read: bool) -> Result<()> {
252 if address >= 0x80 {
253 return Err(Error::AddressOutOfRange(address));
254 }
255
256 // Wait until we have space in the TxFIFO
257 while self.is_tx_fifo_full() {}
258
259 let addr_rw = address << 1 | if read { 1 } else { 0 };
260 self.send_cmd(if self.is_hs { Cmd::StartHs } else { Cmd::Start }, addr_rw);
261
262 // Check controller status
263 self.status()
264 }
265
266 fn stop(&mut self) -> Result<()> {
267 // Wait until we have space in the TxFIFO
268 while self.is_tx_fifo_full() {}
269
270 self.send_cmd(Cmd::Stop, 0);
271 self.status()
272 }
273
274 fn blocking_read_internal(&mut self, address: u8, read: &mut [u8], send_stop: SendStop) -> Result<()> {
275 self.start(address, true)?;
276
277 if read.is_empty() {
278 return Err(Error::InvalidReadBufferLength);
279 }
280
281 for chunk in read.chunks_mut(256) {
282 // Wait until we have space in the TxFIFO
283 while self.is_tx_fifo_full() {}
284
285 self.send_cmd(Cmd::Receive, (chunk.len() - 1) as u8);
286
287 for byte in chunk.iter_mut() {
288 // Wait until there's data in the RxFIFO
289 while self.is_rx_fifo_empty() {}
290
291 *byte = T::regs().mrdr().read().data().bits();
292 }
293
294 if send_stop == SendStop::Yes {
295 self.stop()?;
296 }
297 }
298
299 Ok(())
300 }
301
302 fn blocking_write_internal(&mut self, address: u8, write: &[u8], send_stop: SendStop) -> Result<()> {
303 self.start(address, false)?;
304
305 // Usually, embassy HALs error out with an empty write,
306 // however empty writes are useful for writing I2C scanning
307 // logic through write probing. That is, we send a start with
308 // R/w bit cleared, but instead of writing any data, just send
309 // the stop onto the bus. This has the effect of checking if
310 // the resulting address got an ACK but causing no
311 // side-effects to the device on the other end.
312 //
313 // Because of this, we are not going to error out in case of
314 // empty writes.
315 #[cfg(feature = "defmt")]
316 if write.is_empty() {
317 defmt::trace!("Empty write, write probing?");
318 }
319
320 for byte in write {
321 // Wait until we have space in the TxFIFO
322 while self.is_tx_fifo_full() {}
323
324 self.send_cmd(Cmd::Transmit, *byte);
325 }
326
327 if send_stop == SendStop::Yes {
328 self.stop()?;
329 }
330
331 Ok(())
332 }
333
334 // Public API: Blocking
335
336 /// Read from address into buffer blocking caller until done.
337 pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<()> {
338 self.blocking_read_internal(address, read, SendStop::Yes)
339 // Automatic Stop
340 }
341
342 /// Write to address from buffer blocking caller until done.
343 pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<()> {
344 self.blocking_write_internal(address, write, SendStop::Yes)
345 }
346
347 /// Write to address from bytes and read from address into buffer blocking caller until done.
348 pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<()> {
349 self.blocking_write_internal(address, write, SendStop::No)?;
350 self.blocking_read_internal(address, read, SendStop::Yes)
351 }
352}
353
354impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, T, M> {
355 type Error = Error;
356
357 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<()> {
358 self.blocking_read(address, buffer)
359 }
360}
361
362impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Write for I2c<'d, T, M> {
363 type Error = Error;
364
365 fn write(&mut self, address: u8, bytes: &[u8]) -> Result<()> {
366 self.blocking_write(address, bytes)
367 }
368}
369
370impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T, M> {
371 type Error = Error;
372
373 fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<()> {
374 self.blocking_write_read(address, bytes, buffer)
375 }
376}
377
378impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Transactional for I2c<'d, T, M> {
379 type Error = Error;
380
381 fn exec(&mut self, address: u8, operations: &mut [embedded_hal_02::blocking::i2c::Operation<'_>]) -> Result<()> {
382 if let Some((last, rest)) = operations.split_last_mut() {
383 for op in rest {
384 match op {
385 embedded_hal_02::blocking::i2c::Operation::Read(buf) => {
386 self.blocking_read_internal(address, buf, SendStop::No)?
387 }
388 embedded_hal_02::blocking::i2c::Operation::Write(buf) => {
389 self.blocking_write_internal(address, buf, SendStop::No)?
390 }
391 }
392 }
393
394 match last {
395 embedded_hal_02::blocking::i2c::Operation::Read(buf) => {
396 self.blocking_read_internal(address, buf, SendStop::Yes)
397 }
398 embedded_hal_02::blocking::i2c::Operation::Write(buf) => {
399 self.blocking_write_internal(address, buf, SendStop::Yes)
400 }
401 }
402 } else {
403 Ok(())
404 }
405 }
406}
407
408impl embedded_hal_1::i2c::Error for Error {
409 fn kind(&self) -> embedded_hal_1::i2c::ErrorKind {
410 match *self {
411 Self::ArbitrationLoss => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss,
412 Self::AddressNack => {
413 embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address)
414 }
415 _ => embedded_hal_1::i2c::ErrorKind::Other,
416 }
417 }
418}
419
420impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::ErrorType for I2c<'d, T, M> {
421 type Error = Error;
422}
423
424impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, T, M> {
425 fn transaction(&mut self, address: u8, operations: &mut [embedded_hal_1::i2c::Operation<'_>]) -> Result<()> {
426 if let Some((last, rest)) = operations.split_last_mut() {
427 for op in rest {
428 match op {
429 embedded_hal_1::i2c::Operation::Read(buf) => {
430 self.blocking_read_internal(address, buf, SendStop::No)?
431 }
432 embedded_hal_1::i2c::Operation::Write(buf) => {
433 self.blocking_write_internal(address, buf, SendStop::No)?
434 }
435 }
436 }
437
438 match last {
439 embedded_hal_1::i2c::Operation::Read(buf) => self.blocking_read_internal(address, buf, SendStop::Yes),
440 embedded_hal_1::i2c::Operation::Write(buf) => self.blocking_write_internal(address, buf, SendStop::Yes),
441 }
442 } else {
443 Ok(())
444 }
445 }
446}
447
448impl<'d, T: Instance, M: Mode> embassy_embedded_hal::SetConfig for I2c<'d, T, M> {
449 type Config = Config;
450 type ConfigError = Error;
451
452 fn set_config(&mut self, config: &Self::Config) -> Result<()> {
453 Self::set_config(config)
454 }
455}
diff --git a/src/i2c/mod.rs b/src/i2c/mod.rs
new file mode 100644
index 000000000..a1f842029
--- /dev/null
+++ b/src/i2c/mod.rs
@@ -0,0 +1,171 @@
1//! I2C Support
2
3use core::marker::PhantomData;
4
5use embassy_hal_internal::PeripheralType;
6use embassy_sync::waitqueue::AtomicWaker;
7use paste::paste;
8
9use crate::clocks::periph_helpers::Lpi2cConfig;
10use crate::clocks::{ClockError, Gate};
11use crate::gpio::{GpioPin, SealedPin};
12use crate::{interrupt, pac};
13
14/// Shorthand for `Result<T>`.
15pub type Result<T> = core::result::Result<T, Error>;
16
17pub mod controller;
18
19/// Error information type
20#[derive(Debug, Copy, Clone, PartialEq, Eq)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22pub enum Error {
23 /// Clock configuration error.
24 ClockSetup(ClockError),
25 /// Reading for I2C failed.
26 ReadFail,
27 /// Writing to I2C failed.
28 WriteFail,
29 /// I2C address NAK condition.
30 AddressNack,
31 /// Bus level arbitration loss.
32 ArbitrationLoss,
33 /// Address out of range.
34 AddressOutOfRange(u8),
35 /// Invalid write buffer length.
36 InvalidWriteBufferLength,
37 /// Invalid read buffer length.
38 InvalidReadBufferLength,
39 /// Other internal errors or unexpected state.
40 Other,
41}
42
43/// I2C interrupt handler.
44pub struct InterruptHandler<T: Instance> {
45 _phantom: PhantomData<T>,
46}
47
48impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
49 unsafe fn on_interrupt() {
50 let waker = T::waker();
51
52 waker.wake();
53
54 todo!()
55 }
56}
57
58mod sealed {
59 /// Seal a trait
60 pub trait Sealed {}
61}
62
63impl<T: GpioPin> sealed::Sealed for T {}
64
65trait SealedInstance {
66 fn regs() -> &'static pac::lpi2c0::RegisterBlock;
67 fn waker() -> &'static AtomicWaker;
68}
69
70/// I2C Instance
71#[allow(private_bounds)]
72pub trait Instance: SealedInstance + PeripheralType + 'static + Send + Gate<MrccPeriphConfig = Lpi2cConfig> {
73 /// Interrupt for this I2C instance.
74 type Interrupt: interrupt::typelevel::Interrupt;
75 /// Clock instance
76 const CLOCK_INSTANCE: crate::clocks::periph_helpers::Lpi2cInstance;
77}
78
79macro_rules! impl_instance {
80 ($($n:expr),*) => {
81 $(
82 paste!{
83 impl SealedInstance for crate::peripherals::[<LPI2C $n>] {
84 fn regs() -> &'static pac::lpi2c0::RegisterBlock {
85 unsafe { &*pac::[<Lpi2c $n>]::ptr() }
86 }
87
88 fn waker() -> &'static AtomicWaker {
89 static WAKER: AtomicWaker = AtomicWaker::new();
90 &WAKER
91 }
92 }
93
94 impl Instance for crate::peripherals::[<LPI2C $n>] {
95 type Interrupt = crate::interrupt::typelevel::[<LPI2C $n>];
96 const CLOCK_INSTANCE: crate::clocks::periph_helpers::Lpi2cInstance
97 = crate::clocks::periph_helpers::Lpi2cInstance::[<Lpi2c $n>];
98 }
99 }
100 )*
101 };
102}
103
104impl_instance!(0, 1, 2, 3);
105
106/// SCL pin trait.
107pub trait SclPin<Instance>: GpioPin + sealed::Sealed + PeripheralType {
108 fn mux(&self);
109}
110
111/// SDA pin trait.
112pub trait SdaPin<Instance>: GpioPin + sealed::Sealed + PeripheralType {
113 fn mux(&self);
114}
115
116/// Driver mode.
117#[allow(private_bounds)]
118pub trait Mode: sealed::Sealed {}
119
120/// Blocking mode.
121pub struct Blocking;
122impl sealed::Sealed for Blocking {}
123impl Mode for Blocking {}
124
125/// Async mode.
126pub struct Async;
127impl sealed::Sealed for Async {}
128impl Mode for Async {}
129
130macro_rules! impl_pin {
131 ($pin:ident, $peri:ident, $fn:ident, $trait:ident) => {
132 impl $trait<crate::peripherals::$peri> for crate::peripherals::$pin {
133 fn mux(&self) {
134 self.set_pull(crate::gpio::Pull::Disabled);
135 self.set_slew_rate(crate::gpio::SlewRate::Fast.into());
136 self.set_drive_strength(crate::gpio::DriveStrength::Double.into());
137 self.set_function(crate::pac::port0::pcr0::Mux::$fn);
138 self.set_enable_input_buffer();
139 }
140 }
141 };
142}
143
144impl_pin!(P0_16, LPI2C0, Mux2, SdaPin);
145impl_pin!(P0_17, LPI2C0, Mux2, SclPin);
146impl_pin!(P0_18, LPI2C0, Mux2, SclPin);
147impl_pin!(P0_19, LPI2C0, Mux2, SdaPin);
148impl_pin!(P1_0, LPI2C1, Mux3, SdaPin);
149impl_pin!(P1_1, LPI2C1, Mux3, SclPin);
150impl_pin!(P1_2, LPI2C1, Mux3, SdaPin);
151impl_pin!(P1_3, LPI2C1, Mux3, SclPin);
152impl_pin!(P1_8, LPI2C2, Mux3, SdaPin);
153impl_pin!(P1_9, LPI2C2, Mux3, SclPin);
154impl_pin!(P1_10, LPI2C2, Mux3, SdaPin);
155impl_pin!(P1_11, LPI2C2, Mux3, SclPin);
156impl_pin!(P1_12, LPI2C1, Mux2, SdaPin);
157impl_pin!(P1_13, LPI2C1, Mux2, SclPin);
158impl_pin!(P1_14, LPI2C1, Mux2, SclPin);
159impl_pin!(P1_15, LPI2C1, Mux2, SdaPin);
160impl_pin!(P1_30, LPI2C0, Mux3, SdaPin);
161impl_pin!(P1_31, LPI2C0, Mux3, SclPin);
162impl_pin!(P3_27, LPI2C3, Mux2, SclPin);
163impl_pin!(P3_28, LPI2C3, Mux2, SdaPin);
164// impl_pin!(P3_29, LPI2C3, Mux2, HreqPin); What is this HREQ pin?
165impl_pin!(P3_30, LPI2C3, Mux2, SclPin);
166impl_pin!(P3_31, LPI2C3, Mux2, SdaPin);
167impl_pin!(P4_2, LPI2C2, Mux2, SdaPin);
168impl_pin!(P4_3, LPI2C0, Mux2, SclPin);
169impl_pin!(P4_4, LPI2C2, Mux2, SdaPin);
170impl_pin!(P4_5, LPI2C0, Mux2, SclPin);
171// impl_pin!(P4_6, LPI2C0, Mux2, HreqPin); What is this HREQ pin?
diff --git a/src/interrupt.rs b/src/interrupt.rs
index 4d409067a..f2f1cccac 100644
--- a/src/interrupt.rs
+++ b/src/interrupt.rs
@@ -7,7 +7,9 @@
7#![allow(clippy::missing_safety_doc)] 7#![allow(clippy::missing_safety_doc)]
8 8
9mod generated { 9mod generated {
10 embassy_hal_internal::interrupt_mod!(OS_EVENT, LPUART0, LPUART1, LPUART2, LPUART3, LPUART4, LPUART5, RTC, ADC1,); 10 embassy_hal_internal::interrupt_mod!(
11 OS_EVENT, LPUART0, LPI2C0, LPI2C1, LPI2C2, LPI2C3, LPUART1, LPUART2, LPUART3, LPUART4, LPUART5, RTC, ADC1,
12 );
11} 13}
12 14
13use core::sync::atomic::{AtomicU16, AtomicU32, Ordering}; 15use core::sync::atomic::{AtomicU16, AtomicU32, Ordering};
diff --git a/src/lib.rs b/src/lib.rs
index f9dda67d9..7fccc86c5 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -12,6 +12,7 @@ pub mod pins; // pin mux helpers
12pub mod adc; 12pub mod adc;
13pub mod clkout; 13pub mod clkout;
14pub mod config; 14pub mod config;
15pub mod i2c;
15pub mod interrupt; 16pub mod interrupt;
16pub mod lpuart; 17pub mod lpuart;
17pub mod ostimer; 18pub mod ostimer;