aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authori509VCB <[email protected]>2025-11-24 22:59:13 +0000
committerGitHub <[email protected]>2025-11-24 22:59:13 +0000
commit5ffb3698541674d57fddb22044ac0f06397c6113 (patch)
treee78c68d7702928ce5e7acc19a72b7e4f7bfb858f
parenta66d9f6bea6b6e55ba3dfe0f3b86152402e47d3f (diff)
parent672165572e36d04a59eb672e19ebf4c1726fc8aa (diff)
Merge pull request #4897 from bespsm/MSPM0-MATHACL
MSPSM0: module MATHACL
-rw-r--r--embassy-mspm0/CHANGELOG.md1
-rw-r--r--embassy-mspm0/Cargo.toml5
-rw-r--r--embassy-mspm0/build.rs1
-rw-r--r--embassy-mspm0/src/lib.rs2
-rw-r--r--embassy-mspm0/src/mathacl.rs255
-rw-r--r--examples/mspm0g3507/src/bin/mathacl_ops.rs39
6 files changed, 301 insertions, 2 deletions
diff --git a/embassy-mspm0/CHANGELOG.md b/embassy-mspm0/CHANGELOG.md
index f0b5868f4..6972a8472 100644
--- a/embassy-mspm0/CHANGELOG.md
+++ b/embassy-mspm0/CHANGELOG.md
@@ -19,3 +19,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
19- feat: Add i2c target implementation (#4605) 19- feat: Add i2c target implementation (#4605)
20- fix: group irq handlers must check for NO_INTR (#4785) 20- fix: group irq handlers must check for NO_INTR (#4785)
21- feat: Add read_reset_cause function 21- feat: Add read_reset_cause function
22- feat: Add module Mathacl & example for mspm0g3507 (#4897) \ No newline at end of file
diff --git a/embassy-mspm0/Cargo.toml b/embassy-mspm0/Cargo.toml
index b76bc7e41..254e0209b 100644
--- a/embassy-mspm0/Cargo.toml
+++ b/embassy-mspm0/Cargo.toml
@@ -70,9 +70,10 @@ log = { version = "0.4.14", optional = true }
70cortex-m-rt = ">=0.6.15,<0.8" 70cortex-m-rt = ">=0.6.15,<0.8"
71cortex-m = "0.7.6" 71cortex-m = "0.7.6"
72critical-section = "1.2.0" 72critical-section = "1.2.0"
73micromath = "2.0.0"
73 74
74# mspm0-metapac = { version = "" } 75# mspm0-metapac = { version = "" }
75mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-8542f260cc89645a983b7f1a874c87b21822279e" } 76mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-f21b04e9de074af4965bf67ec3646cb9fe1b9852" }
76 77
77[build-dependencies] 78[build-dependencies]
78proc-macro2 = "1.0.94" 79proc-macro2 = "1.0.94"
@@ -80,7 +81,7 @@ quote = "1.0.40"
80cfg_aliases = "0.2.1" 81cfg_aliases = "0.2.1"
81 82
82# mspm0-metapac = { version = "", default-features = false, features = ["metadata"] } 83# mspm0-metapac = { version = "", default-features = false, features = ["metadata"] }
83mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-8542f260cc89645a983b7f1a874c87b21822279e", default-features = false, features = ["metadata"] } 84mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-f21b04e9de074af4965bf67ec3646cb9fe1b9852", default-features = false, features = ["metadata"] }
84 85
85[features] 86[features]
86default = ["rt"] 87default = ["rt"]
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..c43c81853 100644
--- a/embassy-mspm0/src/lib.rs
+++ b/embassy-mspm0/src/lib.rs
@@ -19,6 +19,8 @@ pub mod dma;
19pub mod gpio; 19pub mod gpio;
20pub mod i2c; 20pub mod i2c;
21pub mod i2c_target; 21pub mod i2c_target;
22#[cfg(any(mspm0g150x, mspm0g151x, mspm0g350x, mspm0g351x))]
23pub mod mathacl;
22pub mod timer; 24pub mod timer;
23pub mod uart; 25pub mod uart;
24pub mod wwdt; 26pub mod wwdt;
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/examples/mspm0g3507/src/bin/mathacl_ops.rs b/examples/mspm0g3507/src/bin/mathacl_ops.rs
new file mode 100644
index 000000000..25d74b29b
--- /dev/null
+++ b/examples/mspm0g3507/src/bin/mathacl_ops.rs
@@ -0,0 +1,39 @@
1//! Example of using mathematical calculations performed by the MSPM0G3507 chip.
2//!
3//! It prints the result of basics trigonometric calculation.
4
5#![no_std]
6#![no_main]
7
8use core::f32::consts::PI;
9
10use defmt::*;
11use embassy_executor::Spawner;
12use embassy_mspm0::mathacl::{Mathacl, Precision};
13use embassy_time::Timer;
14use {defmt_rtt as _, panic_halt as _};
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) -> ! {
18 info!("Hello world!");
19
20 let d = embassy_mspm0::init(Default::default());
21
22 let mut macl = Mathacl::new(d.MATHACL);
23
24 // value radians [-PI; PI]
25 let rads = PI * 0.5;
26 match macl.sin(rads, Precision::High) {
27 Ok(res) => info!("sin({}) = {}", rads, res),
28 Err(e) => error!("sin Error: {:?}", e),
29 }
30
31 match macl.cos(rads, Precision::Medium) {
32 Ok(res) => info!("cos({}) = {}", rads, res),
33 Err(e) => error!("cos Error: {:?}", e),
34 }
35
36 loop {
37 Timer::after_millis(500).await;
38 }
39}