aboutsummaryrefslogtreecommitdiff
path: root/embassy-mspm0
diff options
context:
space:
mode:
authorSiarhei B <[email protected]>2025-11-16 01:15:18 +0100
committerSiarhei B <[email protected]>2025-11-16 01:26:28 +0100
commit535c6d378fb68083623338f8534b5da8efd6a139 (patch)
tree088c52aed6cffcc7e4c84ccb930466dff28e4a57 /embassy-mspm0
parent80a8d7d9798514cd1cfa7f4188c51f25334952dc (diff)
mspm0: add MATHACL module and following operations: sin,cos
Diffstat (limited to 'embassy-mspm0')
-rw-r--r--embassy-mspm0/build.rs1
-rw-r--r--embassy-mspm0/src/lib.rs1
-rw-r--r--embassy-mspm0/src/mathacl.rs244
3 files changed, 246 insertions, 0 deletions
diff --git a/embassy-mspm0/build.rs b/embassy-mspm0/build.rs
index 4942364aa..0fe056c4e 100644
--- a/embassy-mspm0/build.rs
+++ b/embassy-mspm0/build.rs
@@ -591,6 +591,7 @@ fn generate_peripheral_instances() -> TokenStream {
591 "i2c" => Some(quote! { impl_i2c_instance!(#peri, #fifo_size); }), 591 "i2c" => Some(quote! { impl_i2c_instance!(#peri, #fifo_size); }),
592 "wwdt" => Some(quote! { impl_wwdt_instance!(#peri); }), 592 "wwdt" => Some(quote! { impl_wwdt_instance!(#peri); }),
593 "adc" => Some(quote! { impl_adc_instance!(#peri); }), 593 "adc" => Some(quote! { impl_adc_instance!(#peri); }),
594 "mathacl" => Some(quote! { impl_mathacl_instance!(#peri); }),
594 _ => None, 595 _ => None,
595 }; 596 };
596 597
diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs
index 9f3e4d5e8..dda8c373c 100644
--- a/embassy-mspm0/src/lib.rs
+++ b/embassy-mspm0/src/lib.rs
@@ -19,6 +19,7 @@ pub mod dma;
19pub mod gpio; 19pub mod gpio;
20pub mod i2c; 20pub mod i2c;
21pub mod i2c_target; 21pub mod i2c_target;
22pub mod mathacl;
22pub mod timer; 23pub mod timer;
23pub mod uart; 24pub mod uart;
24pub mod wwdt; 25pub mod wwdt;
diff --git a/embassy-mspm0/src/mathacl.rs b/embassy-mspm0/src/mathacl.rs
new file mode 100644
index 000000000..59687ce49
--- /dev/null
+++ b/embassy-mspm0/src/mathacl.rs
@@ -0,0 +1,244 @@
1//! MATHACL
2//!
3//! This HAL implements mathematical calculations performed by the CPU.
4
5#![macro_use]
6
7use embassy_hal_internal::PeripheralType;
8
9use crate::Peri;
10use crate::pac::mathacl::{Mathacl as Regs, vals};
11use micromath::F32Ext;
12
13pub enum Precision {
14 High = 31,
15 Medium = 15,
16 Low = 1,
17}
18
19/// Serial error
20#[derive(Debug, Eq, PartialEq, Copy, Clone)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22#[non_exhaustive]
23pub enum Error {
24 AngleInWrongRange,
25 NBitsTooBig,
26}
27
28#[derive(Copy, Clone)]
29pub struct Mathacl {
30 regs: &'static Regs,
31}
32
33impl Mathacl {
34 /// Mathacl initialization.
35 pub fn new<T: Instance>(_instance: Peri<T>) -> Self {
36 // Init power
37 T::regs().gprcm(0).rstctl().write(|w| {
38 w.set_resetstkyclr(vals::Resetstkyclr::CLR);
39 w.set_resetassert(vals::Resetassert::ASSERT);
40 w.set_key(vals::ResetKey::KEY);
41 });
42
43 // Enable power
44 T::regs().gprcm(0).pwren().write(|w| {
45 w.set_enable(true);
46 w.set_key(vals::PwrenKey::KEY);
47 });
48
49 // init delay, 16 cycles
50 cortex_m::asm::delay(16);
51
52 Self { regs: T::regs() }
53 }
54
55 /// Internal helper SINCOS function.
56 fn sincos(&mut self, angle: f32, precision: Precision, sin: bool) -> Result<f32, Error> {
57 self.regs.ctl().write(|w| {
58 w.set_func(vals::Func::SINCOS);
59 w.set_numiter(precision as u8);
60 });
61
62 if angle > 1.0 || angle < -1.0 {
63 return Err(Error::AngleInWrongRange);
64 }
65
66 match signed_f32_to_register(angle, 0) {
67 Ok(val) => self.regs.op1().write(|w| {w.set_data(val);}),
68 Err(er) => return Err(er),
69 };
70
71 // check if done
72 while self.regs.status().read().busy() == vals::Busy::NOTDONE {}
73
74 match sin {
75 true => register_to_signed_f32(self.regs.res2().read().data(), 0),
76 false => register_to_signed_f32(self.regs.res1().read().data(), 0),
77 }
78 }
79
80 /// Calsulates trigonometric sine operation in the range [-1,1) with a give precision.
81 pub fn sin(&mut self, angle: f32, precision: Precision) -> Result<f32, Error> {
82 self.sincos(angle, precision, true)
83 }
84
85 /// Calsulates trigonometric cosine operation in the range [-1,1) with a give precision.
86 pub fn cos(&mut self, angle: f32, precision: Precision) -> Result<f32, Error> {
87 self.sincos(angle, precision, false)
88 }
89}
90
91pub(crate) trait SealedInstance {
92 fn regs() -> &'static Regs;
93}
94
95/// Mathacl instance trait
96#[allow(private_bounds)]
97pub trait Instance: SealedInstance + PeripheralType {}
98
99macro_rules! impl_mathacl_instance {
100 ($instance: ident) => {
101 impl crate::mathacl::SealedInstance for crate::peripherals::$instance {
102 fn regs() -> &'static crate::pac::mathacl::Mathacl {
103 &crate::pac::$instance
104 }
105 }
106
107 impl crate::mathacl::Instance for crate::peripherals::$instance {}
108 };
109}
110
111/// Convert f32 data to understandable by M0 format.
112fn signed_f32_to_register(data: f32, n_bits: u8) -> Result<u32, Error> {
113 let mut res: u32 = 0;
114 // check if negative
115 let negative = data < 0.0;
116
117 // absolute value for extraction
118 let abs = data.abs();
119
120 // total integer bit count
121 let total_bits = 31;
122
123 // Validate n_bits
124 if n_bits > 31 {
125 return Err(Error::NBitsTooBig);
126 }
127
128 // number of fractional bits
129 let shift = total_bits - n_bits;
130
131 // Compute masks
132 let (n_mask, m_mask) = if n_bits == 0 {
133 (0, 0x7FFFFFFF)
134 } else if n_bits == 31 {
135 (0x7FFFFFFF, 0)
136 } else {
137 ((1u32 << n_bits) - 1, (1u32 << shift) - 1)
138 };
139
140 // calc. integer(n) & fractional(m) parts
141 let n = abs.floor() as u32;
142 let mut m = ((abs - abs.floor()) * (1u32 << shift) as f32).round() as u32;
143
144 // Handle trimming integer part
145 if n_bits == 0 && n > 0 {
146 m = 0x7FFFFFFF;
147 }
148
149 // calculate result
150 if n_bits > 0 {
151 res = n << shift & n_mask;
152 }
153 if shift > 0 {
154 res = res | m & m_mask;
155 }
156
157 // if negative, do 2’s compliment
158 if negative {
159 res = !res + 1;
160 }
161 Ok(res)
162}
163
164/// Reversely converts M0-register format to native f32.
165fn register_to_signed_f32(data: u32, n_bits: u8) -> Result<f32, Error> {
166 // Validate n_bits
167 if n_bits > 31 {
168 return Err(Error::NBitsTooBig);
169 }
170
171 // total integer bit count
172 let total_bits = 31;
173
174 let negative = (data >> 31) == 1;
175
176 // number of fractional bits
177 let shift = total_bits - n_bits;
178
179 // Compute masks
180 let (n_mask, m_mask) = if n_bits == 0 {
181 (0, 0x7FFFFFFF)
182 } else if n_bits == 31 {
183 (0x7FFFFFFF, 0)
184 } else {
185 ((1u32 << n_bits) - 1, (1u32 << shift) - 1)
186 };
187
188 // Compute n and m
189 let mut n = if n_bits == 0 {
190 0
191 } else if shift >= 32 {
192 data & n_mask
193 } else {
194 (data >> shift) & n_mask
195 };
196 let mut m = data & m_mask;
197
198 // if negative, do 2’s compliment
199 if negative {
200 n = !n & n_mask;
201 m = (!m & m_mask) + 1;
202 }
203
204 let mut value = (n as f32) + (m as f32) / (1u32 << shift) as f32;
205 if negative {
206 value = -value;
207 }
208 return Ok(value);
209}
210
211#[cfg(test)]
212mod tests {
213 use super::*;
214
215 #[test]
216 fn mathacl_convert_func_errors() {
217 assert_eq!(signed_f32_to_register(0.0, 32), Err(Error::NBitsTooBig));
218 assert_eq!(register_to_signed_f32(0, 32), Err(Error::NBitsTooBig));
219 }
220
221 #[test]
222 fn mathacl_signed_f32_to_register() {
223 let mut test_float = 1.0;
224 assert_eq!(signed_f32_to_register(test_float, 0).unwrap(), 0x7FFFFFFF);
225
226 test_float = 0.0;
227 assert_eq!(signed_f32_to_register(test_float, 0).unwrap(), 0x0);
228
229 test_float = -1.0;
230 assert_eq!(signed_f32_to_register(test_float, 0).unwrap(), 0x80000001);
231 }
232
233 #[test]
234 fn mathacl_register_to_signed_f32() {
235 let mut test_u32: u32 = 0x7FFFFFFF;
236 assert_eq!(register_to_signed_f32(test_u32, 0u8).unwrap(), 1.0);
237
238 test_u32 = 0x0;
239 assert_eq!(register_to_signed_f32(test_u32, 0u8).unwrap(), 0.0);
240
241 test_u32 = 0x80000001;
242 assert_eq!(register_to_signed_f32(test_u32, 0u8).unwrap(), -1.0);
243 }
244}