aboutsummaryrefslogtreecommitdiff
path: root/embassy-mspm0/src
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-mspm0/src')
-rw-r--r--embassy-mspm0/src/adc.rs6
-rw-r--r--embassy-mspm0/src/dma.rs8
-rw-r--r--embassy-mspm0/src/gpio.rs32
-rw-r--r--embassy-mspm0/src/i2c.rs21
-rw-r--r--embassy-mspm0/src/i2c_target.rs509
-rw-r--r--embassy-mspm0/src/lib.rs6
-rw-r--r--embassy-mspm0/src/time_driver.rs2
-rw-r--r--embassy-mspm0/src/uart/buffered.rs4
-rw-r--r--embassy-mspm0/src/uart/mod.rs13
-rw-r--r--embassy-mspm0/src/wwdt.rs4
10 files changed, 564 insertions, 41 deletions
diff --git a/embassy-mspm0/src/adc.rs b/embassy-mspm0/src/adc.rs
index 5b93e9a6e..948801679 100644
--- a/embassy-mspm0/src/adc.rs
+++ b/embassy-mspm0/src/adc.rs
@@ -4,13 +4,13 @@ use core::future::poll_fn;
4use core::marker::PhantomData; 4use core::marker::PhantomData;
5use core::task::Poll; 5use core::task::Poll;
6 6
7use embassy_hal_internal::{impl_peripheral, PeripheralType}; 7use embassy_hal_internal::{PeripheralType, impl_peripheral};
8use embassy_sync::waitqueue::AtomicWaker; 8use embassy_sync::waitqueue::AtomicWaker;
9 9
10use crate::interrupt::{Interrupt, InterruptExt}; 10use crate::interrupt::{Interrupt, InterruptExt};
11use crate::mode::{Async, Blocking, Mode}; 11use crate::mode::{Async, Blocking, Mode};
12use crate::pac::adc::{vals, Adc as Regs}; 12use crate::pac::adc::{Adc as Regs, vals};
13use crate::{interrupt, Peri}; 13use crate::{Peri, interrupt};
14 14
15/// Interrupt handler. 15/// Interrupt handler.
16pub struct InterruptHandler<T: Instance> { 16pub struct InterruptHandler<T: Instance> {
diff --git a/embassy-mspm0/src/dma.rs b/embassy-mspm0/src/dma.rs
index 66b79709c..58b087761 100644
--- a/embassy-mspm0/src/dma.rs
+++ b/embassy-mspm0/src/dma.rs
@@ -5,18 +5,18 @@
5use core::future::Future; 5use core::future::Future;
6use core::mem; 6use core::mem;
7use core::pin::Pin; 7use core::pin::Pin;
8use core::sync::atomic::{compiler_fence, Ordering}; 8use core::sync::atomic::{Ordering, compiler_fence};
9use core::task::{Context, Poll}; 9use core::task::{Context, Poll};
10 10
11use critical_section::CriticalSection; 11use critical_section::CriticalSection;
12use embassy_hal_internal::interrupt::InterruptExt; 12use embassy_hal_internal::interrupt::InterruptExt;
13use embassy_hal_internal::{impl_peripheral, PeripheralType}; 13use embassy_hal_internal::{PeripheralType, impl_peripheral};
14use embassy_sync::waitqueue::AtomicWaker; 14use embassy_sync::waitqueue::AtomicWaker;
15use mspm0_metapac::common::{Reg, RW}; 15use mspm0_metapac::common::{RW, Reg};
16use mspm0_metapac::dma::regs; 16use mspm0_metapac::dma::regs;
17use mspm0_metapac::dma::vals::{self, Autoen, Em, Incr, Preirq, Wdth}; 17use mspm0_metapac::dma::vals::{self, Autoen, Em, Incr, Preirq, Wdth};
18 18
19use crate::{interrupt, pac, Peri}; 19use crate::{Peri, interrupt, pac};
20 20
21/// The burst size of a DMA transfer. 21/// The burst size of a DMA transfer.
22#[derive(Debug, Clone, Copy, PartialEq, Eq)] 22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
diff --git a/embassy-mspm0/src/gpio.rs b/embassy-mspm0/src/gpio.rs
index d5fd36dbf..d8eb42dc2 100644
--- a/embassy-mspm0/src/gpio.rs
+++ b/embassy-mspm0/src/gpio.rs
@@ -5,12 +5,12 @@ use core::future::Future;
5use core::pin::Pin as FuturePin; 5use core::pin::Pin as FuturePin;
6use core::task::{Context, Poll}; 6use core::task::{Context, Poll};
7 7
8use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; 8use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral};
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10 10
11use crate::pac::gpio::vals::*; 11use crate::pac::gpio::vals::*;
12use crate::pac::gpio::{self}; 12use crate::pac::gpio::{self};
13#[cfg(all(feature = "rt", any(mspm0c110x, mspm0c1105_c1106, mspm0l110x)))] 13#[cfg(all(feature = "rt", any(gpioa_interrupt, gpiob_interrupt)))]
14use crate::pac::interrupt; 14use crate::pac::interrupt;
15use crate::pac::{self}; 15use crate::pac::{self};
16 16
@@ -156,7 +156,12 @@ impl<'d> Flex<'d> {
156 w.set_pf(GPIO_PF); 156 w.set_pf(GPIO_PF);
157 w.set_hiz1(true); 157 w.set_hiz1(true);
158 w.set_pc(true); 158 w.set_pc(true);
159 w.set_inena(false); 159 w.set_inena(true);
160 });
161
162 // Enable output driver (DOE) - required for open-drain to drive low
163 self.pin.block().doeset31_0().write(|w| {
164 w.set_dio(self.pin.bit_index(), true);
160 }); 165 });
161 166
162 self.set_pull(Pull::None); 167 self.set_pull(Pull::None);
@@ -1105,16 +1110,21 @@ fn irq_handler(gpio: gpio::Gpio, wakers: &[AtomicWaker; 32]) {
1105 } 1110 }
1106} 1111}
1107 1112
1113#[cfg(all(gpioa_interrupt, gpioa_group))]
1114compile_error!("gpioa_interrupt and gpioa_group are mutually exclusive cfgs");
1115#[cfg(all(gpiob_interrupt, gpiob_group))]
1116compile_error!("gpiob_interrupt and gpiob_group are mutually exclusive cfgs");
1117
1108// C110x and L110x have a dedicated interrupts just for GPIOA. 1118// C110x and L110x have a dedicated interrupts just for GPIOA.
1109// 1119//
1110// These chips do not have a GROUP1 interrupt. 1120// These chips do not have a GROUP1 interrupt.
1111#[cfg(all(feature = "rt", any(mspm0c110x, mspm0c1105_c1106, mspm0l110x)))] 1121#[cfg(all(feature = "rt", gpioa_interrupt))]
1112#[interrupt] 1122#[interrupt]
1113fn GPIOA() { 1123fn GPIOA() {
1114 irq_handler(pac::GPIOA, &PORTA_WAKERS); 1124 irq_handler(pac::GPIOA, &PORTA_WAKERS);
1115} 1125}
1116 1126
1117#[cfg(all(feature = "rt", mspm0c1105_c1106))] 1127#[cfg(all(feature = "rt", gpiob_interrupt))]
1118#[interrupt] 1128#[interrupt]
1119fn GPIOB() { 1129fn GPIOB() {
1120 irq_handler(pac::GPIOB, &PORTB_WAKERS); 1130 irq_handler(pac::GPIOB, &PORTB_WAKERS);
@@ -1124,23 +1134,23 @@ fn GPIOB() {
1124// 1134//
1125// Defining these as no_mangle is required so that the linker will pick these over the default handler. 1135// Defining these as no_mangle is required so that the linker will pick these over the default handler.
1126 1136
1127#[cfg(all(feature = "rt", not(any(mspm0c110x, mspm0c1105_c1106, mspm0l110x))))] 1137#[cfg(all(feature = "rt", gpioa_group))]
1128#[no_mangle] 1138#[unsafe(no_mangle)]
1129#[allow(non_snake_case)] 1139#[allow(non_snake_case)]
1130fn GPIOA() { 1140fn GPIOA() {
1131 irq_handler(pac::GPIOA, &PORTA_WAKERS); 1141 irq_handler(pac::GPIOA, &PORTA_WAKERS);
1132} 1142}
1133 1143
1134#[cfg(all(feature = "rt", gpio_pb, not(mspm0c1105_c1106)))] 1144#[cfg(all(feature = "rt", gpiob_group))]
1135#[no_mangle] 1145#[unsafe(no_mangle)]
1136#[allow(non_snake_case)] 1146#[allow(non_snake_case)]
1137fn GPIOB() { 1147fn GPIOB() {
1138 irq_handler(pac::GPIOB, &PORTB_WAKERS); 1148 irq_handler(pac::GPIOB, &PORTB_WAKERS);
1139} 1149}
1140 1150
1141#[cfg(all(feature = "rt", gpio_pc))] 1151#[cfg(all(feature = "rt", gpioc_group))]
1142#[allow(non_snake_case)] 1152#[allow(non_snake_case)]
1143#[no_mangle] 1153#[unsafe(no_mangle)]
1144fn GPIOC() { 1154fn GPIOC() {
1145 irq_handler(pac::GPIOC, &PORTC_WAKERS); 1155 irq_handler(pac::GPIOC, &PORTC_WAKERS);
1146} 1156}
diff --git a/embassy-mspm0/src/i2c.rs b/embassy-mspm0/src/i2c.rs
index 1906e37ba..3067f4833 100644
--- a/embassy-mspm0/src/i2c.rs
+++ b/embassy-mspm0/src/i2c.rs
@@ -10,13 +10,13 @@ use embassy_hal_internal::PeripheralType;
10use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
11use mspm0_metapac::i2c; 11use mspm0_metapac::i2c;
12 12
13use crate::Peri;
13use crate::gpio::{AnyPin, PfType, Pull, SealedPin}; 14use crate::gpio::{AnyPin, PfType, Pull, SealedPin};
14use crate::interrupt::typelevel::Binding; 15use crate::interrupt::typelevel::Binding;
15use crate::interrupt::{Interrupt, InterruptExt}; 16use crate::interrupt::{Interrupt, InterruptExt};
16use crate::mode::{Async, Blocking, Mode}; 17use crate::mode::{Async, Blocking, Mode};
17use crate::pac::i2c::{vals, I2c as Regs}; 18use crate::pac::i2c::{I2c as Regs, vals};
18use crate::pac::{self}; 19use crate::pac::{self};
19use crate::Peri;
20 20
21/// The clock source for the I2C. 21/// The clock source for the I2C.
22#[derive(Clone, Copy, PartialEq, Eq, Debug)] 22#[derive(Clone, Copy, PartialEq, Eq, Debug)]
@@ -56,7 +56,7 @@ pub enum ClockDiv {
56} 56}
57 57
58impl ClockDiv { 58impl ClockDiv {
59 fn into(self) -> vals::Ratio { 59 pub(crate) fn into(self) -> vals::Ratio {
60 match self { 60 match self {
61 Self::DivBy1 => vals::Ratio::DIV_BY_1, 61 Self::DivBy1 => vals::Ratio::DIV_BY_1,
62 Self::DivBy2 => vals::Ratio::DIV_BY_2, 62 Self::DivBy2 => vals::Ratio::DIV_BY_2,
@@ -133,6 +133,11 @@ pub enum ConfigError {
133 /// 133 ///
134 /// The clock soure is not enabled is SYSCTL. 134 /// The clock soure is not enabled is SYSCTL.
135 ClockSourceNotEnabled, 135 ClockSourceNotEnabled,
136
137 /// Invalid target address.
138 ///
139 /// The target address is not 7-bit.
140 InvalidTargetAddress,
136} 141}
137 142
138#[non_exhaustive] 143#[non_exhaustive]
@@ -140,7 +145,7 @@ pub enum ConfigError {
140/// Config 145/// Config
141pub struct Config { 146pub struct Config {
142 /// I2C clock source. 147 /// I2C clock source.
143 clock_source: ClockSel, 148 pub(crate) clock_source: ClockSel,
144 149
145 /// I2C clock divider. 150 /// I2C clock divider.
146 pub clock_div: ClockDiv, 151 pub clock_div: ClockDiv,
@@ -196,7 +201,7 @@ impl Config {
196 } 201 }
197 202
198 #[cfg(any(mspm0c110x, mspm0c1105_c1106))] 203 #[cfg(any(mspm0c110x, mspm0c1105_c1106))]
199 fn calculate_clock_source(&self) -> u32 { 204 pub(crate) fn calculate_clock_source(&self) -> u32 {
200 // Assume that BusClk has default value. 205 // Assume that BusClk has default value.
201 // TODO: calculate BusClk more precisely. 206 // TODO: calculate BusClk more precisely.
202 match self.clock_source { 207 match self.clock_source {
@@ -206,10 +211,10 @@ impl Config {
206 } 211 }
207 212
208 #[cfg(any( 213 #[cfg(any(
209 mspm0g110x, mspm0g150x, mspm0g151x, mspm0g310x, mspm0g350x, mspm0g351x, mspm0l110x, mspm0l122x, mspm0l130x, 214 mspm0g110x, mspm0g150x, mspm0g151x, mspm0g310x, mspm0g350x, mspm0g351x, mspm0h321x, mspm0l110x, mspm0l122x,
210 mspm0l134x, mspm0l222x 215 mspm0l130x, mspm0l134x, mspm0l222x
211 ))] 216 ))]
212 fn calculate_clock_source(&self) -> u32 { 217 pub(crate) fn calculate_clock_source(&self) -> u32 {
213 // Assume that BusClk has default value. 218 // Assume that BusClk has default value.
214 // TODO: calculate BusClk more precisely. 219 // TODO: calculate BusClk more precisely.
215 match self.clock_source { 220 match self.clock_source {
diff --git a/embassy-mspm0/src/i2c_target.rs b/embassy-mspm0/src/i2c_target.rs
new file mode 100644
index 000000000..86be91415
--- /dev/null
+++ b/embassy-mspm0/src/i2c_target.rs
@@ -0,0 +1,509 @@
1//! Inter-Integrated-Circuit (I2C) Target
2// The following code is modified from embassy-stm32 and embassy-rp
3// https://github.com/embassy-rs/embassy/tree/main/embassy-stm32
4// https://github.com/embassy-rs/embassy/tree/main/embassy-rp
5
6use core::future::poll_fn;
7use core::marker::PhantomData;
8use core::sync::atomic::Ordering;
9use core::task::Poll;
10
11use embassy_embedded_hal::SetConfig;
12use mspm0_metapac::i2c::vals::CpuIntIidxStat;
13
14use crate::gpio::{AnyPin, SealedPin};
15use crate::interrupt::InterruptExt;
16use crate::mode::{Async, Blocking, Mode};
17use crate::pac::{self, i2c::vals};
18use crate::{i2c, i2c_target, interrupt, Peri};
19// Re-use I2c controller types
20use crate::i2c::{ClockSel, ConfigError, Info, Instance, InterruptHandler, SclPin, SdaPin, State};
21
22#[non_exhaustive]
23#[derive(Clone, Copy, PartialEq, Eq, Debug)]
24/// Config
25pub struct Config {
26 /// 7-bit Target Address
27 pub target_addr: u8,
28
29 /// Control if the target should ack to and report general calls.
30 pub general_call: bool,
31}
32
33impl Default for Config {
34 fn default() -> Self {
35 Self {
36 target_addr: 0x48,
37 general_call: false,
38 }
39 }
40}
41
42/// I2C error
43#[derive(Debug, PartialEq, Eq, Clone, Copy)]
44#[cfg_attr(feature = "defmt", derive(defmt::Format))]
45#[non_exhaustive]
46pub enum Error {
47 /// User passed in a response buffer that was 0 length
48 InvalidResponseBufferLength,
49 /// The response buffer length was too short to contain the message
50 ///
51 /// The length parameter will always be the length of the buffer, and is
52 /// provided as a convenience for matching alongside `Command::Write`.
53 PartialWrite(usize),
54 /// The response buffer length was too short to contain the message
55 ///
56 /// The length parameter will always be the length of the buffer, and is
57 /// provided as a convenience for matching alongside `Command::GeneralCall`.
58 PartialGeneralCall(usize),
59}
60
61/// Received command from the controller.
62#[derive(Debug, Copy, Clone, Eq, PartialEq)]
63#[cfg_attr(feature = "defmt", derive(defmt::Format))]
64pub enum Command {
65 /// General Call Write: Controller sent the General Call address (0x00) followed by data.
66 /// Contains the number of bytes written by the controller.
67 GeneralCall(usize),
68 /// Read: Controller wants to read data from the target.
69 Read,
70 /// Write: Controller sent the target's address followed by data.
71 /// Contains the number of bytes written by the controller.
72 Write(usize),
73 /// Write followed by Read (Repeated Start): Controller wrote data, then issued a repeated
74 /// start and wants to read data. Contains the number of bytes written before the read.
75 WriteRead(usize),
76}
77
78/// Status after responding to a controller read request.
79#[derive(Debug, Copy, Clone, Eq, PartialEq)]
80#[cfg_attr(feature = "defmt", derive(defmt::Format))]
81pub enum ReadStatus {
82 /// Transaction completed successfully. The controller either NACKed the last byte
83 /// or sent a STOP condition.
84 Done,
85 /// Transaction incomplete, controller trying to read more bytes than were provided
86 NeedMoreBytes,
87 /// Transaction complete, but controller stopped reading bytes before we ran out
88 LeftoverBytes(u16),
89}
90
91/// I2C Target driver.
92// Use the same Instance, SclPin, SdaPin traits as the controller
93pub struct I2cTarget<'d, M: Mode> {
94 info: &'static Info,
95 state: &'static State,
96 scl: Option<Peri<'d, AnyPin>>,
97 sda: Option<Peri<'d, AnyPin>>,
98 config: i2c::Config,
99 target_config: i2c_target::Config,
100 _phantom: PhantomData<M>,
101}
102
103impl<'d> SetConfig for I2cTarget<'d, Async> {
104 type Config = (i2c::Config, i2c_target::Config);
105 type ConfigError = ConfigError;
106
107 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
108 self.info.interrupt.disable();
109
110 if let Some(ref sda) = self.sda {
111 sda.update_pf(config.0.sda_pf());
112 }
113
114 if let Some(ref scl) = self.scl {
115 scl.update_pf(config.0.scl_pf());
116 }
117
118 self.config = config.0.clone();
119 self.target_config = config.1.clone();
120
121 self.reset()
122 }
123}
124
125impl<'d> SetConfig for I2cTarget<'d, Blocking> {
126 type Config = (i2c::Config, i2c_target::Config);
127 type ConfigError = ConfigError;
128
129 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
130 if let Some(ref sda) = self.sda {
131 sda.update_pf(config.0.sda_pf());
132 }
133
134 if let Some(ref scl) = self.scl {
135 scl.update_pf(config.0.scl_pf());
136 }
137
138 self.config = config.0.clone();
139 self.target_config = config.1.clone();
140
141 self.reset()
142 }
143}
144
145impl<'d> I2cTarget<'d, Async> {
146 /// Create a new asynchronous I2C target driver using interrupts
147 /// The `config` reuses the i2c controller config to setup the clock while `target_config`
148 /// configures i2c target specific parameters.
149 pub fn new<T: Instance>(
150 peri: Peri<'d, T>,
151 scl: Peri<'d, impl SclPin<T>>,
152 sda: Peri<'d, impl SdaPin<T>>,
153 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
154 config: i2c::Config,
155 target_config: i2c_target::Config,
156 ) -> Result<Self, ConfigError> {
157 let mut this = Self::new_inner(
158 peri,
159 new_pin!(scl, config.scl_pf()),
160 new_pin!(sda, config.sda_pf()),
161 config,
162 target_config,
163 );
164 this.reset()?;
165 Ok(this)
166 }
167
168 /// Reset the i2c peripheral. If you cancel a respond_to_read, you may stall the bus.
169 /// You can recover the bus by calling this function, but doing so will almost certainly cause
170 /// an i/o error in the controller.
171 pub fn reset(&mut self) -> Result<(), ConfigError> {
172 self.init()?;
173 unsafe { self.info.interrupt.enable() };
174 Ok(())
175 }
176}
177
178impl<'d> I2cTarget<'d, Blocking> {
179 /// Create a new blocking I2C target driver.
180 /// The `config` reuses the i2c controller config to setup the clock while `target_config`
181 /// configures i2c target specific parameters.
182 pub fn new_blocking<T: Instance>(
183 peri: Peri<'d, T>,
184 scl: Peri<'d, impl SclPin<T>>,
185 sda: Peri<'d, impl SdaPin<T>>,
186 config: i2c::Config,
187 target_config: i2c_target::Config,
188 ) -> Result<Self, ConfigError> {
189 let mut this = Self::new_inner(
190 peri,
191 new_pin!(scl, config.scl_pf()),
192 new_pin!(sda, config.sda_pf()),
193 config,
194 target_config,
195 );
196 this.reset()?;
197 Ok(this)
198 }
199
200 /// Reset the i2c peripheral. If you cancel a respond_to_read, you may stall the bus.
201 /// You can recover the bus by calling this function, but doing so will almost certainly cause
202 /// an i/o error in the controller.
203 pub fn reset(&mut self) -> Result<(), ConfigError> {
204 self.init()?;
205 Ok(())
206 }
207}
208
209impl<'d, M: Mode> I2cTarget<'d, M> {
210 fn new_inner<T: Instance>(
211 _peri: Peri<'d, T>,
212 scl: Option<Peri<'d, AnyPin>>,
213 sda: Option<Peri<'d, AnyPin>>,
214 config: i2c::Config,
215 target_config: i2c_target::Config,
216 ) -> Self {
217 if let Some(ref scl) = scl {
218 let pincm = pac::IOMUX.pincm(scl._pin_cm() as usize);
219 pincm.modify(|w| {
220 w.set_hiz1(true);
221 });
222 }
223 if let Some(ref sda) = sda {
224 let pincm = pac::IOMUX.pincm(sda._pin_cm() as usize);
225 pincm.modify(|w| {
226 w.set_hiz1(true);
227 });
228 }
229
230 Self {
231 info: T::info(),
232 state: T::state(),
233 scl,
234 sda,
235 config,
236 target_config,
237 _phantom: PhantomData,
238 }
239 }
240
241 fn init(&mut self) -> Result<(), ConfigError> {
242 let mut config = self.config;
243 let target_config = self.target_config;
244 let regs = self.info.regs;
245
246 config.check_config()?;
247 // Target address must be 7-bit
248 if !(target_config.target_addr < 0x80) {
249 return Err(ConfigError::InvalidTargetAddress);
250 }
251
252 regs.target(0).tctr().modify(|w| {
253 w.set_active(false);
254 });
255
256 // Init power for I2C
257 regs.gprcm(0).rstctl().write(|w| {
258 w.set_resetstkyclr(true);
259 w.set_resetassert(true);
260 w.set_key(vals::ResetKey::KEY);
261 });
262
263 regs.gprcm(0).pwren().write(|w| {
264 w.set_enable(true);
265 w.set_key(vals::PwrenKey::KEY);
266 });
267
268 self.info.interrupt.disable();
269
270 // Init delay from the M0 examples by TI in CCStudio (16 cycles)
271 cortex_m::asm::delay(16);
272
273 // Select and configure the I2C clock using the CLKSEL and CLKDIV registers
274 regs.clksel().write(|w| match config.clock_source {
275 ClockSel::BusClk => {
276 w.set_mfclk_sel(false);
277 w.set_busclk_sel(true);
278 }
279 ClockSel::MfClk => {
280 w.set_mfclk_sel(true);
281 w.set_busclk_sel(false);
282 }
283 });
284 regs.clkdiv().write(|w| w.set_ratio(config.clock_div.into()));
285
286 // Configure at least one target address by writing the 7-bit address to I2Cx.SOAR register. The additional
287 // target address can be enabled and configured by using I2Cx.TOAR2 register.
288 regs.target(0).toar().modify(|w| {
289 w.set_oaren(true);
290 w.set_oar(target_config.target_addr as u16);
291 });
292
293 self.state
294 .clock
295 .store(config.calculate_clock_source(), Ordering::Relaxed);
296
297 regs.target(0).tctr().modify(|w| {
298 w.set_gencall(target_config.general_call);
299 w.set_tclkstretch(true);
300 // Disable target wakeup, follow TI example. (TI note: Workaround for errata I2C_ERR_04.)
301 w.set_twuen(false);
302 w.set_txempty_on_treq(true);
303 });
304
305 // Enable the I2C target mode by setting the ACTIVE bit in I2Cx.TCTR register.
306 regs.target(0).tctr().modify(|w| {
307 w.set_active(true);
308 });
309
310 Ok(())
311 }
312
313 #[inline(always)]
314 fn drain_fifo(&mut self, buffer: &mut [u8], offset: &mut usize) {
315 let regs = self.info.regs;
316
317 for b in &mut buffer[*offset..] {
318 if regs.target(0).tfifosr().read().rxfifocnt() == 0 {
319 break;
320 }
321
322 *b = regs.target(0).trxdata().read().value();
323 *offset += 1;
324 }
325 }
326
327 /// Blocking function to empty the tx fifo
328 ///
329 /// This function can be used to empty the transmit FIFO if data remains after handling a 'read' command (LeftoverBytes).
330 pub fn flush_tx_fifo(&mut self) {
331 self.info.regs.target(0).tfifoctl().modify(|w| {
332 w.set_txflush(true);
333 });
334 while self.info.regs.target(0).tfifosr().read().txfifocnt() as usize != self.info.fifo_size {}
335 self.info.regs.target(0).tfifoctl().modify(|w| {
336 w.set_txflush(false);
337 });
338 }
339}
340
341impl<'d> I2cTarget<'d, Async> {
342 /// Wait asynchronously for commands from an I2C controller.
343 /// `buffer` is provided in case controller does a 'write', 'write read', or 'general call' and is unused for 'read'.
344 pub async fn listen(&mut self, buffer: &mut [u8]) -> Result<Command, Error> {
345 let regs = self.info.regs;
346
347 let mut len = 0;
348
349 // Set the rx fifo interrupt to avoid a fifo overflow
350 regs.target(0).tfifoctl().modify(|r| {
351 r.set_rxtrig(vals::TfifoctlRxtrig::LEVEL_6);
352 });
353
354 self.wait_on(
355 |me| {
356 // Check if address matches the General Call address (0x00)
357 let is_gencall = regs.target(0).tsr().read().addrmatch() == 0;
358
359 if regs.target(0).tfifosr().read().rxfifocnt() > 0 {
360 me.drain_fifo(buffer, &mut len);
361 }
362
363 if buffer.len() == len && regs.target(0).tfifosr().read().rxfifocnt() > 0 {
364 if is_gencall {
365 return Poll::Ready(Err(Error::PartialGeneralCall(buffer.len())));
366 } else {
367 return Poll::Ready(Err(Error::PartialWrite(buffer.len())));
368 }
369 }
370
371 let iidx = regs.cpu_int(0).iidx().read().stat();
372 trace!("ls:{} len:{}", iidx as u8, len);
373 let result = match iidx {
374 CpuIntIidxStat::TTXEMPTY => match len {
375 0 => Poll::Ready(Ok(Command::Read)),
376 w => Poll::Ready(Ok(Command::WriteRead(w))),
377 },
378 CpuIntIidxStat::TSTOPFG => match (is_gencall, len) {
379 (_, 0) => Poll::Pending,
380 (true, w) => Poll::Ready(Ok(Command::GeneralCall(w))),
381 (false, w) => Poll::Ready(Ok(Command::Write(w))),
382 },
383 _ => Poll::Pending,
384 };
385 if !result.is_pending() {
386 regs.cpu_int(0).imask().write(|_| {});
387 }
388 result
389 },
390 |_me| {
391 regs.cpu_int(0).imask().write(|_| {});
392 regs.cpu_int(0).imask().modify(|w| {
393 w.set_tgencall(true);
394 w.set_trxfifotrg(true);
395 w.set_tstop(true);
396 w.set_ttxempty(true);
397 });
398 },
399 )
400 .await
401 }
402
403 /// Respond to an I2C controller 'read' command, asynchronously.
404 pub async fn respond_to_read(&mut self, buffer: &[u8]) -> Result<ReadStatus, Error> {
405 if buffer.is_empty() {
406 return Err(Error::InvalidResponseBufferLength);
407 }
408
409 let regs = self.info.regs;
410 let fifo_size = self.info.fifo_size;
411 let mut chunks = buffer.chunks(self.info.fifo_size);
412
413 self.wait_on(
414 |_me| {
415 if let Some(chunk) = chunks.next() {
416 for byte in chunk {
417 regs.target(0).ttxdata().write(|w| w.set_value(*byte));
418 }
419
420 return Poll::Pending;
421 }
422
423 let iidx = regs.cpu_int(0).iidx().read().stat();
424 let fifo_bytes = fifo_size - regs.target(0).tfifosr().read().txfifocnt() as usize;
425 trace!("rs:{}, fifo:{}", iidx as u8, fifo_bytes);
426
427 let result = match iidx {
428 CpuIntIidxStat::TTXEMPTY => Poll::Ready(Ok(ReadStatus::NeedMoreBytes)),
429 CpuIntIidxStat::TSTOPFG => match fifo_bytes {
430 0 => Poll::Ready(Ok(ReadStatus::Done)),
431 w => Poll::Ready(Ok(ReadStatus::LeftoverBytes(w as u16))),
432 },
433 _ => Poll::Pending,
434 };
435 if !result.is_pending() {
436 regs.cpu_int(0).imask().write(|_| {});
437 }
438 result
439 },
440 |_me| {
441 regs.cpu_int(0).imask().write(|_| {});
442 regs.cpu_int(0).imask().modify(|w| {
443 w.set_ttxempty(true);
444 w.set_tstop(true);
445 });
446 },
447 )
448 .await
449 }
450
451 /// Respond to reads with the fill byte until the controller stops asking
452 pub async fn respond_till_stop(&mut self, fill: u8) -> Result<(), Error> {
453 // The buffer size could be increased to reduce interrupt noise but has higher probability
454 // of LeftoverBytes
455 let buff = [fill];
456 loop {
457 match self.respond_to_read(&buff).await {
458 Ok(ReadStatus::NeedMoreBytes) => (),
459 Ok(_) => break Ok(()),
460 Err(e) => break Err(e),
461 }
462 }
463 }
464
465 /// Respond to a controller read, then fill any remaining read bytes with `fill`
466 pub async fn respond_and_fill(&mut self, buffer: &[u8], fill: u8) -> Result<ReadStatus, Error> {
467 let resp_stat = self.respond_to_read(buffer).await?;
468
469 if resp_stat == ReadStatus::NeedMoreBytes {
470 self.respond_till_stop(fill).await?;
471 Ok(ReadStatus::Done)
472 } else {
473 Ok(resp_stat)
474 }
475 }
476
477 /// Calls `f` to check if we are ready or not.
478 /// If not, `g` is called once(to eg enable the required interrupts).
479 /// The waker will always be registered prior to calling `f`.
480 #[inline(always)]
481 async fn wait_on<F, U, G>(&mut self, mut f: F, mut g: G) -> U
482 where
483 F: FnMut(&mut Self) -> Poll<U>,
484 G: FnMut(&mut Self),
485 {
486 poll_fn(|cx| {
487 // Register prior to checking the condition
488 self.state.waker.register(cx.waker());
489 let r = f(self);
490
491 if r.is_pending() {
492 g(self);
493 }
494
495 r
496 })
497 .await
498 }
499}
500
501impl<'d, M: Mode> Drop for I2cTarget<'d, M> {
502 fn drop(&mut self) {
503 // Ensure peripheral is disabled and pins are reset
504 self.info.regs.target(0).tctr().modify(|w| w.set_active(false));
505
506 self.scl.as_ref().map(|x| x.set_as_disconnected());
507 self.sda.as_ref().map(|x| x.set_as_disconnected());
508 }
509}
diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs
index 13f0ce662..7135dd9f0 100644
--- a/embassy-mspm0/src/lib.rs
+++ b/embassy-mspm0/src/lib.rs
@@ -1,4 +1,5 @@
1#![no_std] 1#![no_std]
2#![allow(unsafe_op_in_unsafe_fn)]
2// Doc feature labels can be tested locally by running RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc 3// Doc feature labels can be tested locally by running RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc
3#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg_hide), doc(cfg_hide(doc, docsrs)))] 4#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg_hide), doc(cfg_hide(doc, docsrs)))]
4#![cfg_attr( 5#![cfg_attr(
@@ -17,6 +18,7 @@ pub mod adc;
17pub mod dma; 18pub mod dma;
18pub mod gpio; 19pub mod gpio;
19pub mod i2c; 20pub mod i2c;
21pub mod i2c_target;
20pub mod timer; 22pub mod timer;
21pub mod uart; 23pub mod uart;
22pub mod wwdt; 24pub mod wwdt;
@@ -54,7 +56,7 @@ pub(crate) mod _generated {
54 56
55// Reexports 57// Reexports
56pub(crate) use _generated::gpio_pincm; 58pub(crate) use _generated::gpio_pincm;
57pub use _generated::{peripherals, Peripherals}; 59pub use _generated::{Peripherals, peripherals};
58pub use embassy_hal_internal::Peri; 60pub use embassy_hal_internal::Peri;
59#[cfg(feature = "unstable-pac")] 61#[cfg(feature = "unstable-pac")]
60pub use mspm0_metapac as pac; 62pub use mspm0_metapac as pac;
@@ -111,7 +113,7 @@ macro_rules! bind_interrupts {
111 113
112 $( 114 $(
113 #[allow(non_snake_case)] 115 #[allow(non_snake_case)]
114 #[no_mangle] 116 #[unsafe(no_mangle)]
115 $(#[cfg($cond_irq)])? 117 $(#[cfg($cond_irq)])?
116 unsafe extern "C" fn $irq() { 118 unsafe extern "C" fn $irq() {
117 unsafe { 119 unsafe {
diff --git a/embassy-mspm0/src/time_driver.rs b/embassy-mspm0/src/time_driver.rs
index e80e89e55..0743c667b 100644
--- a/embassy-mspm0/src/time_driver.rs
+++ b/embassy-mspm0/src/time_driver.rs
@@ -1,5 +1,5 @@
1use core::cell::{Cell, RefCell}; 1use core::cell::{Cell, RefCell};
2use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; 2use core::sync::atomic::{AtomicU32, Ordering, compiler_fence};
3use core::task::Waker; 3use core::task::Waker;
4 4
5use critical_section::{CriticalSection, Mutex}; 5use critical_section::{CriticalSection, Mutex};
diff --git a/embassy-mspm0/src/uart/buffered.rs b/embassy-mspm0/src/uart/buffered.rs
index cbc0b6c80..89e6bcc7b 100644
--- a/embassy-mspm0/src/uart/buffered.rs
+++ b/embassy-mspm0/src/uart/buffered.rs
@@ -1,4 +1,4 @@
1use core::future::{poll_fn, Future}; 1use core::future::{Future, poll_fn};
2use core::marker::PhantomData; 2use core::marker::PhantomData;
3use core::slice; 3use core::slice;
4use core::sync::atomic::{AtomicU8, Ordering}; 4use core::sync::atomic::{AtomicU8, Ordering};
@@ -14,7 +14,7 @@ use crate::gpio::{AnyPin, SealedPin};
14use crate::interrupt::typelevel::Binding; 14use crate::interrupt::typelevel::Binding;
15use crate::pac::uart::Uart as Regs; 15use crate::pac::uart::Uart as Regs;
16use crate::uart::{Config, ConfigError, CtsPin, Error, Info, Instance, RtsPin, RxPin, State, TxPin}; 16use crate::uart::{Config, ConfigError, CtsPin, Error, Info, Instance, RtsPin, RxPin, State, TxPin};
17use crate::{interrupt, Peri}; 17use crate::{Peri, interrupt};
18 18
19/// Interrupt handler. 19/// Interrupt handler.
20pub struct BufferedInterruptHandler<T: Instance> { 20pub struct BufferedInterruptHandler<T: Instance> {
diff --git a/embassy-mspm0/src/uart/mod.rs b/embassy-mspm0/src/uart/mod.rs
index 6599cea06..03e68d297 100644
--- a/embassy-mspm0/src/uart/mod.rs
+++ b/embassy-mspm0/src/uart/mod.rs
@@ -3,17 +3,17 @@
3mod buffered; 3mod buffered;
4 4
5use core::marker::PhantomData; 5use core::marker::PhantomData;
6use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; 6use core::sync::atomic::{AtomicU32, Ordering, compiler_fence};
7 7
8pub use buffered::*; 8pub use buffered::*;
9use embassy_embedded_hal::SetConfig; 9use embassy_embedded_hal::SetConfig;
10use embassy_hal_internal::PeripheralType; 10use embassy_hal_internal::PeripheralType;
11 11
12use crate::Peri;
12use crate::gpio::{AnyPin, PfType, Pull, SealedPin}; 13use crate::gpio::{AnyPin, PfType, Pull, SealedPin};
13use crate::interrupt::{Interrupt, InterruptExt}; 14use crate::interrupt::{Interrupt, InterruptExt};
14use crate::mode::{Blocking, Mode}; 15use crate::mode::{Blocking, Mode};
15use crate::pac::uart::{vals, Uart as Regs}; 16use crate::pac::uart::{Uart as Regs, vals};
16use crate::Peri;
17 17
18/// The clock source for the UART. 18/// The clock source for the UART.
19#[derive(Clone, Copy, PartialEq, Eq, Debug)] 19#[derive(Clone, Copy, PartialEq, Eq, Debug)]
@@ -931,8 +931,7 @@ fn set_baudrate_inner(regs: Regs, clock: u32, baudrate: u32) -> Result<(), Confi
931 let Some(min_clock) = baudrate.checked_mul(oversampling as u32) else { 931 let Some(min_clock) = baudrate.checked_mul(oversampling as u32) else {
932 trace!( 932 trace!(
933 "{}x oversampling would cause overflow for clock: {} Hz", 933 "{}x oversampling would cause overflow for clock: {} Hz",
934 oversampling, 934 oversampling, clock
935 clock
936 ); 935 );
937 continue; 936 continue;
938 }; 937 };
@@ -945,9 +944,7 @@ fn set_baudrate_inner(regs: Regs, clock: u32, baudrate: u32) -> Result<(), Confi
945 for &(div, div_value) in &DIVS { 944 for &(div, div_value) in &DIVS {
946 trace!( 945 trace!(
947 "Trying div: {}, oversampling {} for {} baud", 946 "Trying div: {}, oversampling {} for {} baud",
948 div, 947 div, oversampling, baudrate
949 oversampling,
950 baudrate
951 ); 948 );
952 949
953 let Some((ibrd, fbrd)) = calculate_brd(clock, div, baudrate, oversampling) else { 950 let Some((ibrd, fbrd)) = calculate_brd(clock, div, baudrate, oversampling) else {
diff --git a/embassy-mspm0/src/wwdt.rs b/embassy-mspm0/src/wwdt.rs
index e5c62c660..92aeb8b40 100644
--- a/embassy-mspm0/src/wwdt.rs
+++ b/embassy-mspm0/src/wwdt.rs
@@ -6,9 +6,9 @@
6 6
7use embassy_hal_internal::PeripheralType; 7use embassy_hal_internal::PeripheralType;
8 8
9use crate::pac::wwdt::{vals, Wwdt as Regs};
10use crate::pac::{self};
11use crate::Peri; 9use crate::Peri;
10use crate::pac::wwdt::{Wwdt as Regs, vals};
11use crate::pac::{self};
12 12
13/// Possible watchdog timeout values. 13/// Possible watchdog timeout values.
14#[derive(Clone, Copy, PartialEq, Eq, Debug)] 14#[derive(Clone, Copy, PartialEq, Eq, Debug)]