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.rs36
-rw-r--r--embassy-mspm0/src/i2c.rs21
-rw-r--r--embassy-mspm0/src/i2c_target.rs510
-rw-r--r--embassy-mspm0/src/lib.rs129
-rw-r--r--embassy-mspm0/src/macros.rs1
-rw-r--r--embassy-mspm0/src/mathacl.rs255
-rw-r--r--embassy-mspm0/src/time_driver.rs6
-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
12 files changed, 949 insertions, 44 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..709102c59 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);
@@ -836,6 +841,7 @@ impl<'d> embedded_hal_async::digital::Wait for OutputOpenDrain<'d> {
836 } 841 }
837} 842}
838 843
844#[cfg_attr(mspm0g518x, allow(dead_code))]
839#[derive(Copy, Clone)] 845#[derive(Copy, Clone)]
840pub struct PfType { 846pub struct PfType {
841 pull: Pull, 847 pull: Pull,
@@ -943,6 +949,7 @@ pub(crate) trait SealedPin {
943 }); 949 });
944 } 950 }
945 951
952 #[cfg_attr(mspm0g518x, allow(dead_code))]
946 fn update_pf(&self, ty: PfType) { 953 fn update_pf(&self, ty: PfType) {
947 let pincm = pac::IOMUX.pincm(self._pin_cm() as usize); 954 let pincm = pac::IOMUX.pincm(self._pin_cm() as usize);
948 let pf = pincm.read().pf(); 955 let pf = pincm.read().pf();
@@ -950,6 +957,7 @@ pub(crate) trait SealedPin {
950 set_pf(self._pin_cm() as usize, pf, ty); 957 set_pf(self._pin_cm() as usize, pf, ty);
951 } 958 }
952 959
960 #[cfg_attr(mspm0g518x, allow(dead_code))]
953 fn set_as_pf(&self, pf: u8, ty: PfType) { 961 fn set_as_pf(&self, pf: u8, ty: PfType) {
954 set_pf(self._pin_cm() as usize, pf, ty) 962 set_pf(self._pin_cm() as usize, pf, ty)
955 } 963 }
@@ -962,6 +970,7 @@ pub(crate) trait SealedPin {
962 /// 970 ///
963 /// Note that this also disables the internal weak pull-up and pull-down resistors. 971 /// Note that this also disables the internal weak pull-up and pull-down resistors.
964 #[inline] 972 #[inline]
973 #[cfg_attr(mspm0g518x, allow(dead_code))]
965 fn set_as_disconnected(&self) { 974 fn set_as_disconnected(&self) {
966 self.set_as_analog(); 975 self.set_as_analog();
967 } 976 }
@@ -1105,16 +1114,21 @@ fn irq_handler(gpio: gpio::Gpio, wakers: &[AtomicWaker; 32]) {
1105 } 1114 }
1106} 1115}
1107 1116
1117#[cfg(all(gpioa_interrupt, gpioa_group))]
1118compile_error!("gpioa_interrupt and gpioa_group are mutually exclusive cfgs");
1119#[cfg(all(gpiob_interrupt, gpiob_group))]
1120compile_error!("gpiob_interrupt and gpiob_group are mutually exclusive cfgs");
1121
1108// C110x and L110x have a dedicated interrupts just for GPIOA. 1122// C110x and L110x have a dedicated interrupts just for GPIOA.
1109// 1123//
1110// These chips do not have a GROUP1 interrupt. 1124// These chips do not have a GROUP1 interrupt.
1111#[cfg(all(feature = "rt", any(mspm0c110x, mspm0c1105_c1106, mspm0l110x)))] 1125#[cfg(all(feature = "rt", gpioa_interrupt))]
1112#[interrupt] 1126#[interrupt]
1113fn GPIOA() { 1127fn GPIOA() {
1114 irq_handler(pac::GPIOA, &PORTA_WAKERS); 1128 irq_handler(pac::GPIOA, &PORTA_WAKERS);
1115} 1129}
1116 1130
1117#[cfg(all(feature = "rt", mspm0c1105_c1106))] 1131#[cfg(all(feature = "rt", gpiob_interrupt))]
1118#[interrupt] 1132#[interrupt]
1119fn GPIOB() { 1133fn GPIOB() {
1120 irq_handler(pac::GPIOB, &PORTB_WAKERS); 1134 irq_handler(pac::GPIOB, &PORTB_WAKERS);
@@ -1124,23 +1138,23 @@ fn GPIOB() {
1124// 1138//
1125// Defining these as no_mangle is required so that the linker will pick these over the default handler. 1139// Defining these as no_mangle is required so that the linker will pick these over the default handler.
1126 1140
1127#[cfg(all(feature = "rt", not(any(mspm0c110x, mspm0c1105_c1106, mspm0l110x))))] 1141#[cfg(all(feature = "rt", gpioa_group))]
1128#[no_mangle] 1142#[unsafe(no_mangle)]
1129#[allow(non_snake_case)] 1143#[allow(non_snake_case)]
1130fn GPIOA() { 1144fn GPIOA() {
1131 irq_handler(pac::GPIOA, &PORTA_WAKERS); 1145 irq_handler(pac::GPIOA, &PORTA_WAKERS);
1132} 1146}
1133 1147
1134#[cfg(all(feature = "rt", gpio_pb, not(mspm0c1105_c1106)))] 1148#[cfg(all(feature = "rt", gpiob_group))]
1135#[no_mangle] 1149#[unsafe(no_mangle)]
1136#[allow(non_snake_case)] 1150#[allow(non_snake_case)]
1137fn GPIOB() { 1151fn GPIOB() {
1138 irq_handler(pac::GPIOB, &PORTB_WAKERS); 1152 irq_handler(pac::GPIOB, &PORTB_WAKERS);
1139} 1153}
1140 1154
1141#[cfg(all(feature = "rt", gpio_pc))] 1155#[cfg(all(feature = "rt", gpioc_group))]
1142#[allow(non_snake_case)] 1156#[allow(non_snake_case)]
1143#[no_mangle] 1157#[unsafe(no_mangle)]
1144fn GPIOC() { 1158fn GPIOC() {
1145 irq_handler(pac::GPIOC, &PORTC_WAKERS); 1159 irq_handler(pac::GPIOC, &PORTC_WAKERS);
1146} 1160}
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..e371fa903
--- /dev/null
+++ b/embassy-mspm0/src/i2c_target.rs
@@ -0,0 +1,510 @@
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};
15// Re-use I2c controller types
16use crate::i2c::{ClockSel, ConfigError, Info, Instance, InterruptHandler, SclPin, SdaPin, State};
17use crate::interrupt::InterruptExt;
18use crate::mode::{Async, Blocking, Mode};
19use crate::pac::i2c::vals;
20use crate::pac::{self};
21use crate::{Peri, i2c, i2c_target, interrupt};
22
23#[non_exhaustive]
24#[derive(Clone, Copy, PartialEq, Eq, Debug)]
25/// Config
26pub struct Config {
27 /// 7-bit Target Address
28 pub target_addr: u8,
29
30 /// Control if the target should ack to and report general calls.
31 pub general_call: bool,
32}
33
34impl Default for Config {
35 fn default() -> Self {
36 Self {
37 target_addr: 0x48,
38 general_call: false,
39 }
40 }
41}
42
43/// I2C error
44#[derive(Debug, PartialEq, Eq, Clone, Copy)]
45#[cfg_attr(feature = "defmt", derive(defmt::Format))]
46#[non_exhaustive]
47pub enum Error {
48 /// User passed in a response buffer that was 0 length
49 InvalidResponseBufferLength,
50 /// The response buffer length was too short to contain the message
51 ///
52 /// The length parameter will always be the length of the buffer, and is
53 /// provided as a convenience for matching alongside `Command::Write`.
54 PartialWrite(usize),
55 /// The response buffer length was too short to contain the message
56 ///
57 /// The length parameter will always be the length of the buffer, and is
58 /// provided as a convenience for matching alongside `Command::GeneralCall`.
59 PartialGeneralCall(usize),
60}
61
62/// Received command from the controller.
63#[derive(Debug, Copy, Clone, Eq, PartialEq)]
64#[cfg_attr(feature = "defmt", derive(defmt::Format))]
65pub enum Command {
66 /// General Call Write: Controller sent the General Call address (0x00) followed by data.
67 /// Contains the number of bytes written by the controller.
68 GeneralCall(usize),
69 /// Read: Controller wants to read data from the target.
70 Read,
71 /// Write: Controller sent the target's address followed by data.
72 /// Contains the number of bytes written by the controller.
73 Write(usize),
74 /// Write followed by Read (Repeated Start): Controller wrote data, then issued a repeated
75 /// start and wants to read data. Contains the number of bytes written before the read.
76 WriteRead(usize),
77}
78
79/// Status after responding to a controller read request.
80#[derive(Debug, Copy, Clone, Eq, PartialEq)]
81#[cfg_attr(feature = "defmt", derive(defmt::Format))]
82pub enum ReadStatus {
83 /// Transaction completed successfully. The controller either NACKed the last byte
84 /// or sent a STOP condition.
85 Done,
86 /// Transaction incomplete, controller trying to read more bytes than were provided
87 NeedMoreBytes,
88 /// Transaction complete, but controller stopped reading bytes before we ran out
89 LeftoverBytes(u16),
90}
91
92/// I2C Target driver.
93// Use the same Instance, SclPin, SdaPin traits as the controller
94pub struct I2cTarget<'d, M: Mode> {
95 info: &'static Info,
96 state: &'static State,
97 scl: Option<Peri<'d, AnyPin>>,
98 sda: Option<Peri<'d, AnyPin>>,
99 config: i2c::Config,
100 target_config: i2c_target::Config,
101 _phantom: PhantomData<M>,
102}
103
104impl<'d> SetConfig for I2cTarget<'d, Async> {
105 type Config = (i2c::Config, i2c_target::Config);
106 type ConfigError = ConfigError;
107
108 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
109 self.info.interrupt.disable();
110
111 if let Some(ref sda) = self.sda {
112 sda.update_pf(config.0.sda_pf());
113 }
114
115 if let Some(ref scl) = self.scl {
116 scl.update_pf(config.0.scl_pf());
117 }
118
119 self.config = config.0.clone();
120 self.target_config = config.1.clone();
121
122 self.reset()
123 }
124}
125
126impl<'d> SetConfig for I2cTarget<'d, Blocking> {
127 type Config = (i2c::Config, i2c_target::Config);
128 type ConfigError = ConfigError;
129
130 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
131 if let Some(ref sda) = self.sda {
132 sda.update_pf(config.0.sda_pf());
133 }
134
135 if let Some(ref scl) = self.scl {
136 scl.update_pf(config.0.scl_pf());
137 }
138
139 self.config = config.0.clone();
140 self.target_config = config.1.clone();
141
142 self.reset()
143 }
144}
145
146impl<'d> I2cTarget<'d, Async> {
147 /// Create a new asynchronous I2C target driver using interrupts
148 /// The `config` reuses the i2c controller config to setup the clock while `target_config`
149 /// configures i2c target specific parameters.
150 pub fn new<T: Instance>(
151 peri: Peri<'d, T>,
152 scl: Peri<'d, impl SclPin<T>>,
153 sda: Peri<'d, impl SdaPin<T>>,
154 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
155 config: i2c::Config,
156 target_config: i2c_target::Config,
157 ) -> Result<Self, ConfigError> {
158 let mut this = Self::new_inner(
159 peri,
160 new_pin!(scl, config.scl_pf()),
161 new_pin!(sda, config.sda_pf()),
162 config,
163 target_config,
164 );
165 this.reset()?;
166 Ok(this)
167 }
168
169 /// Reset the i2c peripheral. If you cancel a respond_to_read, you may stall the bus.
170 /// You can recover the bus by calling this function, but doing so will almost certainly cause
171 /// an i/o error in the controller.
172 pub fn reset(&mut self) -> Result<(), ConfigError> {
173 self.init()?;
174 unsafe { self.info.interrupt.enable() };
175 Ok(())
176 }
177}
178
179impl<'d> I2cTarget<'d, Blocking> {
180 /// Create a new blocking I2C target driver.
181 /// The `config` reuses the i2c controller config to setup the clock while `target_config`
182 /// configures i2c target specific parameters.
183 pub fn new_blocking<T: Instance>(
184 peri: Peri<'d, T>,
185 scl: Peri<'d, impl SclPin<T>>,
186 sda: Peri<'d, impl SdaPin<T>>,
187 config: i2c::Config,
188 target_config: i2c_target::Config,
189 ) -> Result<Self, ConfigError> {
190 let mut this = Self::new_inner(
191 peri,
192 new_pin!(scl, config.scl_pf()),
193 new_pin!(sda, config.sda_pf()),
194 config,
195 target_config,
196 );
197 this.reset()?;
198 Ok(this)
199 }
200
201 /// Reset the i2c peripheral. If you cancel a respond_to_read, you may stall the bus.
202 /// You can recover the bus by calling this function, but doing so will almost certainly cause
203 /// an i/o error in the controller.
204 pub fn reset(&mut self) -> Result<(), ConfigError> {
205 self.init()?;
206 Ok(())
207 }
208}
209
210impl<'d, M: Mode> I2cTarget<'d, M> {
211 fn new_inner<T: Instance>(
212 _peri: Peri<'d, T>,
213 scl: Option<Peri<'d, AnyPin>>,
214 sda: Option<Peri<'d, AnyPin>>,
215 config: i2c::Config,
216 target_config: i2c_target::Config,
217 ) -> Self {
218 if let Some(ref scl) = scl {
219 let pincm = pac::IOMUX.pincm(scl._pin_cm() as usize);
220 pincm.modify(|w| {
221 w.set_hiz1(true);
222 });
223 }
224 if let Some(ref sda) = sda {
225 let pincm = pac::IOMUX.pincm(sda._pin_cm() as usize);
226 pincm.modify(|w| {
227 w.set_hiz1(true);
228 });
229 }
230
231 Self {
232 info: T::info(),
233 state: T::state(),
234 scl,
235 sda,
236 config,
237 target_config,
238 _phantom: PhantomData,
239 }
240 }
241
242 fn init(&mut self) -> Result<(), ConfigError> {
243 let mut config = self.config;
244 let target_config = self.target_config;
245 let regs = self.info.regs;
246
247 config.check_config()?;
248 // Target address must be 7-bit
249 if !(target_config.target_addr < 0x80) {
250 return Err(ConfigError::InvalidTargetAddress);
251 }
252
253 regs.target(0).tctr().modify(|w| {
254 w.set_active(false);
255 });
256
257 // Init power for I2C
258 regs.gprcm(0).rstctl().write(|w| {
259 w.set_resetstkyclr(true);
260 w.set_resetassert(true);
261 w.set_key(vals::ResetKey::KEY);
262 });
263
264 regs.gprcm(0).pwren().write(|w| {
265 w.set_enable(true);
266 w.set_key(vals::PwrenKey::KEY);
267 });
268
269 self.info.interrupt.disable();
270
271 // Init delay from the M0 examples by TI in CCStudio (16 cycles)
272 cortex_m::asm::delay(16);
273
274 // Select and configure the I2C clock using the CLKSEL and CLKDIV registers
275 regs.clksel().write(|w| match config.clock_source {
276 ClockSel::BusClk => {
277 w.set_mfclk_sel(false);
278 w.set_busclk_sel(true);
279 }
280 ClockSel::MfClk => {
281 w.set_mfclk_sel(true);
282 w.set_busclk_sel(false);
283 }
284 });
285 regs.clkdiv().write(|w| w.set_ratio(config.clock_div.into()));
286
287 // Configure at least one target address by writing the 7-bit address to I2Cx.SOAR register. The additional
288 // target address can be enabled and configured by using I2Cx.TOAR2 register.
289 regs.target(0).toar().modify(|w| {
290 w.set_oaren(true);
291 w.set_oar(target_config.target_addr as u16);
292 });
293
294 self.state
295 .clock
296 .store(config.calculate_clock_source(), Ordering::Relaxed);
297
298 regs.target(0).tctr().modify(|w| {
299 w.set_gencall(target_config.general_call);
300 w.set_tclkstretch(true);
301 // Disable target wakeup, follow TI example. (TI note: Workaround for errata I2C_ERR_04.)
302 w.set_twuen(false);
303 w.set_txempty_on_treq(true);
304 });
305
306 // Enable the I2C target mode by setting the ACTIVE bit in I2Cx.TCTR register.
307 regs.target(0).tctr().modify(|w| {
308 w.set_active(true);
309 });
310
311 Ok(())
312 }
313
314 #[inline(always)]
315 fn drain_fifo(&mut self, buffer: &mut [u8], offset: &mut usize) {
316 let regs = self.info.regs;
317
318 for b in &mut buffer[*offset..] {
319 if regs.target(0).tfifosr().read().rxfifocnt() == 0 {
320 break;
321 }
322
323 *b = regs.target(0).trxdata().read().value();
324 *offset += 1;
325 }
326 }
327
328 /// Blocking function to empty the tx fifo
329 ///
330 /// This function can be used to empty the transmit FIFO if data remains after handling a 'read' command (LeftoverBytes).
331 pub fn flush_tx_fifo(&mut self) {
332 self.info.regs.target(0).tfifoctl().modify(|w| {
333 w.set_txflush(true);
334 });
335 while self.info.regs.target(0).tfifosr().read().txfifocnt() as usize != self.info.fifo_size {}
336 self.info.regs.target(0).tfifoctl().modify(|w| {
337 w.set_txflush(false);
338 });
339 }
340}
341
342impl<'d> I2cTarget<'d, Async> {
343 /// Wait asynchronously for commands from an I2C controller.
344 /// `buffer` is provided in case controller does a 'write', 'write read', or 'general call' and is unused for 'read'.
345 pub async fn listen(&mut self, buffer: &mut [u8]) -> Result<Command, Error> {
346 let regs = self.info.regs;
347
348 let mut len = 0;
349
350 // Set the rx fifo interrupt to avoid a fifo overflow
351 regs.target(0).tfifoctl().modify(|r| {
352 r.set_rxtrig(vals::TfifoctlRxtrig::LEVEL_6);
353 });
354
355 self.wait_on(
356 |me| {
357 // Check if address matches the General Call address (0x00)
358 let is_gencall = regs.target(0).tsr().read().addrmatch() == 0;
359
360 if regs.target(0).tfifosr().read().rxfifocnt() > 0 {
361 me.drain_fifo(buffer, &mut len);
362 }
363
364 if buffer.len() == len && regs.target(0).tfifosr().read().rxfifocnt() > 0 {
365 if is_gencall {
366 return Poll::Ready(Err(Error::PartialGeneralCall(buffer.len())));
367 } else {
368 return Poll::Ready(Err(Error::PartialWrite(buffer.len())));
369 }
370 }
371
372 let iidx = regs.cpu_int(0).iidx().read().stat();
373 trace!("ls:{} len:{}", iidx as u8, len);
374 let result = match iidx {
375 CpuIntIidxStat::TTXEMPTY => match len {
376 0 => Poll::Ready(Ok(Command::Read)),
377 w => Poll::Ready(Ok(Command::WriteRead(w))),
378 },
379 CpuIntIidxStat::TSTOPFG => match (is_gencall, len) {
380 (_, 0) => Poll::Pending,
381 (true, w) => Poll::Ready(Ok(Command::GeneralCall(w))),
382 (false, w) => Poll::Ready(Ok(Command::Write(w))),
383 },
384 _ => Poll::Pending,
385 };
386 if !result.is_pending() {
387 regs.cpu_int(0).imask().write(|_| {});
388 }
389 result
390 },
391 |_me| {
392 regs.cpu_int(0).imask().write(|_| {});
393 regs.cpu_int(0).imask().modify(|w| {
394 w.set_tgencall(true);
395 w.set_trxfifotrg(true);
396 w.set_tstop(true);
397 w.set_ttxempty(true);
398 });
399 },
400 )
401 .await
402 }
403
404 /// Respond to an I2C controller 'read' command, asynchronously.
405 pub async fn respond_to_read(&mut self, buffer: &[u8]) -> Result<ReadStatus, Error> {
406 if buffer.is_empty() {
407 return Err(Error::InvalidResponseBufferLength);
408 }
409
410 let regs = self.info.regs;
411 let fifo_size = self.info.fifo_size;
412 let mut chunks = buffer.chunks(self.info.fifo_size);
413
414 self.wait_on(
415 |_me| {
416 if let Some(chunk) = chunks.next() {
417 for byte in chunk {
418 regs.target(0).ttxdata().write(|w| w.set_value(*byte));
419 }
420
421 return Poll::Pending;
422 }
423
424 let iidx = regs.cpu_int(0).iidx().read().stat();
425 let fifo_bytes = fifo_size - regs.target(0).tfifosr().read().txfifocnt() as usize;
426 trace!("rs:{}, fifo:{}", iidx as u8, fifo_bytes);
427
428 let result = match iidx {
429 CpuIntIidxStat::TTXEMPTY => Poll::Ready(Ok(ReadStatus::NeedMoreBytes)),
430 CpuIntIidxStat::TSTOPFG => match fifo_bytes {
431 0 => Poll::Ready(Ok(ReadStatus::Done)),
432 w => Poll::Ready(Ok(ReadStatus::LeftoverBytes(w as u16))),
433 },
434 _ => Poll::Pending,
435 };
436 if !result.is_pending() {
437 regs.cpu_int(0).imask().write(|_| {});
438 }
439 result
440 },
441 |_me| {
442 regs.cpu_int(0).imask().write(|_| {});
443 regs.cpu_int(0).imask().modify(|w| {
444 w.set_ttxempty(true);
445 w.set_tstop(true);
446 });
447 },
448 )
449 .await
450 }
451
452 /// Respond to reads with the fill byte until the controller stops asking
453 pub async fn respond_till_stop(&mut self, fill: u8) -> Result<(), Error> {
454 // The buffer size could be increased to reduce interrupt noise but has higher probability
455 // of LeftoverBytes
456 let buff = [fill];
457 loop {
458 match self.respond_to_read(&buff).await {
459 Ok(ReadStatus::NeedMoreBytes) => (),
460 Ok(_) => break Ok(()),
461 Err(e) => break Err(e),
462 }
463 }
464 }
465
466 /// Respond to a controller read, then fill any remaining read bytes with `fill`
467 pub async fn respond_and_fill(&mut self, buffer: &[u8], fill: u8) -> Result<ReadStatus, Error> {
468 let resp_stat = self.respond_to_read(buffer).await?;
469
470 if resp_stat == ReadStatus::NeedMoreBytes {
471 self.respond_till_stop(fill).await?;
472 Ok(ReadStatus::Done)
473 } else {
474 Ok(resp_stat)
475 }
476 }
477
478 /// Calls `f` to check if we are ready or not.
479 /// If not, `g` is called once(to eg enable the required interrupts).
480 /// The waker will always be registered prior to calling `f`.
481 #[inline(always)]
482 async fn wait_on<F, U, G>(&mut self, mut f: F, mut g: G) -> U
483 where
484 F: FnMut(&mut Self) -> Poll<U>,
485 G: FnMut(&mut Self),
486 {
487 poll_fn(|cx| {
488 // Register prior to checking the condition
489 self.state.waker.register(cx.waker());
490 let r = f(self);
491
492 if r.is_pending() {
493 g(self);
494 }
495
496 r
497 })
498 .await
499 }
500}
501
502impl<'d, M: Mode> Drop for I2cTarget<'d, M> {
503 fn drop(&mut self) {
504 // Ensure peripheral is disabled and pins are reset
505 self.info.regs.target(0).tctr().modify(|w| w.set_active(false));
506
507 self.scl.as_ref().map(|x| x.set_as_disconnected());
508 self.sda.as_ref().map(|x| x.set_as_disconnected());
509 }
510}
diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs
index 13f0ce662..548fb33ca 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(
@@ -7,17 +8,23 @@
7)] 8)]
8#![doc = include_str!("../README.md")] 9#![doc = include_str!("../README.md")]
9 10
10// This mod MUST go first, so that the others see its macros. 11// These mods MUST go first, so that the others see the macros.
11pub(crate) mod fmt; 12pub(crate) mod fmt;
12
13// This must be declared early as well for
14mod macros; 13mod macros;
15 14
16pub mod adc; 15pub mod adc;
17pub mod dma; 16pub mod dma;
18pub mod gpio; 17pub mod gpio;
18// TODO: I2C unicomm
19#[cfg(not(unicomm))]
19pub mod i2c; 20pub mod i2c;
21#[cfg(not(unicomm))]
22pub mod i2c_target;
23#[cfg(any(mspm0g150x, mspm0g151x, mspm0g350x, mspm0g351x))]
24pub mod mathacl;
20pub mod timer; 25pub mod timer;
26// TODO: UART unicomm
27#[cfg(not(unicomm))]
21pub mod uart; 28pub mod uart;
22pub mod wwdt; 29pub mod wwdt;
23 30
@@ -54,7 +61,7 @@ pub(crate) mod _generated {
54 61
55// Reexports 62// Reexports
56pub(crate) use _generated::gpio_pincm; 63pub(crate) use _generated::gpio_pincm;
57pub use _generated::{peripherals, Peripherals}; 64pub use _generated::{Peripherals, peripherals};
58pub use embassy_hal_internal::Peri; 65pub use embassy_hal_internal::Peri;
59#[cfg(feature = "unstable-pac")] 66#[cfg(feature = "unstable-pac")]
60pub use mspm0_metapac as pac; 67pub use mspm0_metapac as pac;
@@ -111,7 +118,7 @@ macro_rules! bind_interrupts {
111 118
112 $( 119 $(
113 #[allow(non_snake_case)] 120 #[allow(non_snake_case)]
114 #[no_mangle] 121 #[unsafe(no_mangle)]
115 $(#[cfg($cond_irq)])? 122 $(#[cfg($cond_irq)])?
116 unsafe extern "C" fn $irq() { 123 unsafe extern "C" fn $irq() {
117 unsafe { 124 unsafe {
@@ -232,3 +239,115 @@ impl Iterator for BitIter {
232 } 239 }
233 } 240 }
234} 241}
242
243/// Reset cause values from SYSCTL.RSTCAUSE register.
244/// Based on MSPM0 L-series Technical Reference Manual Table 2-9 and
245/// MSPM0 G-series Technical Reference Manual Table 2-12.
246#[derive(Clone, Copy, PartialEq, Eq, Debug)]
247#[cfg_attr(feature = "defmt", derive(defmt::Format))]
248pub enum ResetCause {
249 /// No reset since last read
250 NoReset,
251 /// VDD < POR- violation, PMU trim parity fault, or SHUTDNSTOREx parity fault
252 PorHwFailure,
253 /// NRST pin reset (>1s)
254 PorExternalNrst,
255 /// Software-triggered POR
256 PorSwTriggered,
257 /// VDD < BOR- violation
258 BorSupplyFailure,
259 /// Wake from SHUTDOWN
260 BorWakeFromShutdown,
261 /// Non-PMU trim parity fault
262 #[cfg(not(any(
263 mspm0c110x,
264 mspm0c1105_c1106,
265 mspm0g110x,
266 mspm0g150x,
267 mspm0g151x,
268 mspm0g310x,
269 mspm0g350x,
270 mspm0g351x
271 )))]
272 BootrstNonPmuParityFault,
273 /// Fatal clock fault
274 BootrstClockFault,
275 /// Software-triggered BOOTRST
276 BootrstSwTriggered,
277 /// NRST pin reset (<1s)
278 BootrstExternalNrst,
279 /// WWDT0 violation
280 BootrstWwdt0Violation,
281 /// WWDT1 violation (G-series only)
282 #[cfg(any(mspm0g110x, mspm0g150x, mspm0g151x, mspm0g310x, mspm0g350x, mspm0g351x, mspm0g518x))]
283 SysrstWwdt1Violation,
284 /// BSL exit (if present)
285 SysrstBslExit,
286 /// BSL entry (if present)
287 SysrstBslEntry,
288 /// Uncorrectable flash ECC error (if present)
289 #[cfg(not(any(mspm0c110x, mspm0c1105_c1106, mspm0g351x, mspm0g151x)))]
290 SysrstFlashEccError,
291 /// CPU lockup violation
292 SysrstCpuLockupViolation,
293 /// Debug-triggered SYSRST
294 SysrstDebugTriggered,
295 /// Software-triggered SYSRST
296 SysrstSwTriggered,
297 /// Debug-triggered CPURST
298 CpurstDebugTriggered,
299 /// Software-triggered CPURST
300 CpurstSwTriggered,
301}
302
303/// Read the reset cause from the SYSCTL.RSTCAUSE register.
304///
305/// This function reads the reset cause register which indicates why the last
306/// system reset occurred. The register is automatically cleared after being read,
307/// so this should be called only once per application startup.
308///
309/// If the reset cause is not recognized, an `Err` containing the raw value is returned.
310#[must_use = "Reading reset cause will clear it"]
311pub fn read_reset_cause() -> Result<ResetCause, u8> {
312 let cause_raw = pac::SYSCTL.rstcause().read().id();
313
314 use ResetCause::*;
315 use pac::sysctl::vals::Id;
316
317 match cause_raw {
318 Id::NORST => Ok(NoReset),
319 Id::PORHWFAIL => Ok(PorHwFailure),
320 Id::POREXNRST => Ok(PorExternalNrst),
321 Id::PORSW => Ok(PorSwTriggered),
322 Id::BORSUPPLY => Ok(BorSupplyFailure),
323 Id::BORWAKESHUTDN => Ok(BorWakeFromShutdown),
324 #[cfg(not(any(
325 mspm0c110x,
326 mspm0c1105_c1106,
327 mspm0g110x,
328 mspm0g150x,
329 mspm0g151x,
330 mspm0g310x,
331 mspm0g350x,
332 mspm0g351x,
333 mspm0g518x,
334 )))]
335 Id::BOOTNONPMUPARITY => Ok(BootrstNonPmuParityFault),
336 Id::BOOTCLKFAIL => Ok(BootrstClockFault),
337 Id::BOOTSW => Ok(BootrstSwTriggered),
338 Id::BOOTEXNRST => Ok(BootrstExternalNrst),
339 Id::BOOTWWDT0 => Ok(BootrstWwdt0Violation),
340 Id::SYSBSLEXIT => Ok(SysrstBslExit),
341 Id::SYSBSLENTRY => Ok(SysrstBslEntry),
342 #[cfg(any(mspm0g110x, mspm0g150x, mspm0g151x, mspm0g310x, mspm0g350x, mspm0g351x, mspm0g518x))]
343 Id::SYSWWDT1 => Ok(SysrstWwdt1Violation),
344 #[cfg(not(any(mspm0c110x, mspm0c1105_c1106, mspm0g351x, mspm0g151x)))]
345 Id::SYSFLASHECC => Ok(SysrstFlashEccError),
346 Id::SYSCPULOCK => Ok(SysrstCpuLockupViolation),
347 Id::SYSDBG => Ok(SysrstDebugTriggered),
348 Id::SYSSW => Ok(SysrstSwTriggered),
349 Id::CPUDBG => Ok(CpurstDebugTriggered),
350 Id::CPUSW => Ok(CpurstSwTriggered),
351 other => Err(other as u8),
352 }
353}
diff --git a/embassy-mspm0/src/macros.rs b/embassy-mspm0/src/macros.rs
index 5355e7d59..3a12a528a 100644
--- a/embassy-mspm0/src/macros.rs
+++ b/embassy-mspm0/src/macros.rs
@@ -1,5 +1,6 @@
1#![macro_use] 1#![macro_use]
2 2
3#[allow(unused)]
3macro_rules! new_pin { 4macro_rules! new_pin {
4 ($name: ident, $pf_type: expr) => {{ 5 ($name: ident, $pf_type: expr) => {{
5 let pin = $name; 6 let pin = $name;
diff --git a/embassy-mspm0/src/mathacl.rs b/embassy-mspm0/src/mathacl.rs
new file mode 100644
index 000000000..e29f4a59e
--- /dev/null
+++ b/embassy-mspm0/src/mathacl.rs
@@ -0,0 +1,255 @@
1//! MATHACL
2//!
3//! This HAL implements mathematical calculations performed by the CPU.
4
5#![macro_use]
6
7use core::f32::consts::PI;
8use core::marker::PhantomData;
9
10use embassy_hal_internal::PeripheralType;
11use micromath::F32Ext;
12
13use crate::Peri;
14use crate::pac::mathacl::{Mathacl as Regs, vals};
15
16pub enum Precision {
17 High = 31,
18 Medium = 15,
19 Low = 1,
20}
21
22/// Serial error
23#[derive(Debug, Eq, PartialEq, Copy, Clone)]
24#[cfg_attr(feature = "defmt", derive(defmt::Format))]
25#[non_exhaustive]
26pub enum Error {
27 ValueInWrongRange,
28 NBitsTooBig,
29}
30
31pub struct Mathacl<'d> {
32 regs: &'static Regs,
33 _phantom: PhantomData<&'d mut ()>,
34}
35
36impl<'d> Mathacl<'d> {
37 /// Mathacl initialization.
38 pub fn new<T: Instance>(_instance: Peri<'d, T>) -> Self {
39 // Init power
40 T::regs().gprcm(0).rstctl().write(|w| {
41 w.set_resetstkyclr(vals::Resetstkyclr::CLR);
42 w.set_resetassert(vals::Resetassert::ASSERT);
43 w.set_key(vals::ResetKey::KEY);
44 });
45
46 // Enable power
47 T::regs().gprcm(0).pwren().write(|w| {
48 w.set_enable(true);
49 w.set_key(vals::PwrenKey::KEY);
50 });
51
52 // init delay, 16 cycles
53 cortex_m::asm::delay(16);
54
55 Self {
56 regs: T::regs(),
57 _phantom: PhantomData,
58 }
59 }
60
61 /// Internal helper SINCOS function.
62 fn sincos(&mut self, rad: f32, precision: Precision, sin: bool) -> Result<f32, Error> {
63 self.regs.ctl().write(|w| {
64 w.set_func(vals::Func::SINCOS);
65 w.set_numiter(precision as u8);
66 });
67
68 if rad > PI || rad < -PI {
69 return Err(Error::ValueInWrongRange);
70 }
71
72 // TODO: make f32 division on CPU
73 let native = rad / PI;
74
75 match signed_f32_to_register(native, 0) {
76 Ok(val) => self.regs.op1().write(|w| {
77 w.set_data(val);
78 }),
79 Err(er) => return Err(er),
80 };
81
82 // check if done
83 while self.regs.status().read().busy() == vals::Busy::NOTDONE {}
84
85 match sin {
86 true => register_to_signed_f32(self.regs.res2().read().data(), 0),
87 false => register_to_signed_f32(self.regs.res1().read().data(), 0),
88 }
89 }
90
91 /// Calsulates trigonometric sine operation in the range [-1,1) with a give precision.
92 pub fn sin(&mut self, rad: f32, precision: Precision) -> Result<f32, Error> {
93 self.sincos(rad, precision, true)
94 }
95
96 /// Calsulates trigonometric cosine operation in the range [-1,1) with a give precision.
97 pub fn cos(&mut self, rad: f32, precision: Precision) -> Result<f32, Error> {
98 self.sincos(rad, precision, false)
99 }
100}
101
102pub(crate) trait SealedInstance {
103 fn regs() -> &'static Regs;
104}
105
106/// Mathacl instance trait
107#[allow(private_bounds)]
108pub trait Instance: SealedInstance + PeripheralType {}
109
110macro_rules! impl_mathacl_instance {
111 ($instance: ident) => {
112 impl crate::mathacl::SealedInstance for crate::peripherals::$instance {
113 fn regs() -> &'static crate::pac::mathacl::Mathacl {
114 &crate::pac::$instance
115 }
116 }
117
118 impl crate::mathacl::Instance for crate::peripherals::$instance {}
119 };
120}
121
122/// Convert f32 data to understandable by M0 format.
123fn signed_f32_to_register(data: f32, n_bits: u8) -> Result<u32, Error> {
124 let mut res: u32 = 0;
125 // check if negative
126 let negative = data < 0.0;
127
128 // absolute value for extraction
129 let abs = data.abs();
130
131 // total integer bit count
132 let total_bits = 31;
133
134 // Validate n_bits
135 if n_bits > 31 {
136 return Err(Error::NBitsTooBig);
137 }
138
139 // number of fractional bits
140 let shift = total_bits - n_bits;
141
142 // Compute masks
143 let (n_mask, m_mask) = if n_bits == 0 {
144 (0, 0x7FFFFFFF)
145 } else if n_bits == 31 {
146 (0x7FFFFFFF, 0)
147 } else {
148 ((1u32 << n_bits) - 1, (1u32 << shift) - 1)
149 };
150
151 // calc. integer(n) & fractional(m) parts
152 let n = abs.floor() as u32;
153 let mut m = ((abs - abs.floor()) * (1u32 << shift) as f32).round() as u32;
154
155 // Handle trimming integer part
156 if n_bits == 0 && n > 0 {
157 m = 0x7FFFFFFF;
158 }
159
160 // calculate result
161 if n_bits > 0 {
162 res = n << shift & n_mask;
163 }
164 if shift > 0 {
165 res = res | m & m_mask;
166 }
167
168 // if negative, do 2’s compliment
169 if negative {
170 res = !res + 1;
171 }
172 Ok(res)
173}
174
175/// Reversely converts M0-register format to native f32.
176fn register_to_signed_f32(data: u32, n_bits: u8) -> Result<f32, Error> {
177 // Validate n_bits
178 if n_bits > 31 {
179 return Err(Error::NBitsTooBig);
180 }
181
182 // total integer bit count
183 let total_bits = 31;
184
185 let negative = (data >> 31) == 1;
186
187 // number of fractional bits
188 let shift = total_bits - n_bits;
189
190 // Compute masks
191 let (n_mask, m_mask) = if n_bits == 0 {
192 (0, 0x7FFFFFFF)
193 } else if n_bits == 31 {
194 (0x7FFFFFFF, 0)
195 } else {
196 ((1u32 << n_bits) - 1, (1u32 << shift) - 1)
197 };
198
199 // Compute n and m
200 let mut n = if n_bits == 0 {
201 0
202 } else if shift >= 32 {
203 data & n_mask
204 } else {
205 (data >> shift) & n_mask
206 };
207 let mut m = data & m_mask;
208
209 // if negative, do 2’s compliment
210 if negative {
211 n = !n & n_mask;
212 m = (!m & m_mask) + 1;
213 }
214
215 let mut value = (n as f32) + (m as f32) / (1u32 << shift) as f32;
216 if negative {
217 value = -value;
218 }
219 return Ok(value);
220}
221
222#[cfg(test)]
223mod tests {
224 use super::*;
225
226 #[test]
227 fn mathacl_convert_func_errors() {
228 assert_eq!(signed_f32_to_register(0.0, 32), Err(Error::NBitsTooBig));
229 assert_eq!(register_to_signed_f32(0, 32), Err(Error::NBitsTooBig));
230 }
231
232 #[test]
233 fn mathacl_signed_f32_to_register() {
234 let mut test_float = 1.0;
235 assert_eq!(signed_f32_to_register(test_float, 0).unwrap(), 0x7FFFFFFF);
236
237 test_float = 0.0;
238 assert_eq!(signed_f32_to_register(test_float, 0).unwrap(), 0x0);
239
240 test_float = -1.0;
241 assert_eq!(signed_f32_to_register(test_float, 0).unwrap(), 0x80000001);
242 }
243
244 #[test]
245 fn mathacl_register_to_signed_f32() {
246 let mut test_u32: u32 = 0x7FFFFFFF;
247 assert_eq!(register_to_signed_f32(test_u32, 0u8).unwrap(), 1.0);
248
249 test_u32 = 0x0;
250 assert_eq!(register_to_signed_f32(test_u32, 0u8).unwrap(), 0.0);
251
252 test_u32 = 0x80000001;
253 assert_eq!(register_to_signed_f32(test_u32, 0u8).unwrap(), -1.0);
254 }
255}
diff --git a/embassy-mspm0/src/time_driver.rs b/embassy-mspm0/src/time_driver.rs
index e80e89e55..b42ff61c2 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};
@@ -16,6 +16,8 @@ use crate::timer::SealedTimer;
16compile_error!("TIMG12 and TIMG13 are not supported by the time driver yet"); 16compile_error!("TIMG12 and TIMG13 are not supported by the time driver yet");
17 17
18// Currently TIMG12 and TIMG13 are excluded because those are 32-bit timers. 18// Currently TIMG12 and TIMG13 are excluded because those are 32-bit timers.
19#[cfg(time_driver_timb0)]
20type T = peripherals::TIMB0;
19#[cfg(time_driver_timg0)] 21#[cfg(time_driver_timg0)]
20type T = peripherals::TIMG0; 22type T = peripherals::TIMG0;
21#[cfg(time_driver_timg1)] 23#[cfg(time_driver_timg1)]
@@ -333,6 +335,8 @@ pub(crate) fn init(cs: CriticalSection) {
333 DRIVER.init(cs); 335 DRIVER.init(cs);
334} 336}
335 337
338// TODO: TIMB0
339
336#[cfg(time_driver_timg0)] 340#[cfg(time_driver_timg0)]
337#[interrupt] 341#[interrupt]
338fn TIMG0() { 342fn TIMG0() {
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)]