Skip to content

Commit 5ffb369

Browse files
authored
Merge pull request #4897 from bespsm/MSPM0-MATHACL
MSPSM0: module MATHACL
2 parents a66d9f6 + 6721655 commit 5ffb369

File tree

6 files changed

+301
-2
lines changed

6 files changed

+301
-2
lines changed

embassy-mspm0/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1919
- feat: Add i2c target implementation (#4605)
2020
- fix: group irq handlers must check for NO_INTR (#4785)
2121
- feat: Add read_reset_cause function
22+
- feat: Add module Mathacl & example for mspm0g3507 (#4897)

embassy-mspm0/Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,17 +70,18 @@ log = { version = "0.4.14", optional = true }
7070
cortex-m-rt = ">=0.6.15,<0.8"
7171
cortex-m = "0.7.6"
7272
critical-section = "1.2.0"
73+
micromath = "2.0.0"
7374

7475
# mspm0-metapac = { version = "" }
75-
mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-8542f260cc89645a983b7f1a874c87b21822279e" }
76+
mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-f21b04e9de074af4965bf67ec3646cb9fe1b9852" }
7677

7778
[build-dependencies]
7879
proc-macro2 = "1.0.94"
7980
quote = "1.0.40"
8081
cfg_aliases = "0.2.1"
8182

8283
# mspm0-metapac = { version = "", default-features = false, features = ["metadata"] }
83-
mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-8542f260cc89645a983b7f1a874c87b21822279e", default-features = false, features = ["metadata"] }
84+
mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-f21b04e9de074af4965bf67ec3646cb9fe1b9852", default-features = false, features = ["metadata"] }
8485

8586
[features]
8687
default = ["rt"]

embassy-mspm0/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,7 @@ fn generate_peripheral_instances() -> TokenStream {
591591
"i2c" => Some(quote! { impl_i2c_instance!(#peri, #fifo_size); }),
592592
"wwdt" => Some(quote! { impl_wwdt_instance!(#peri); }),
593593
"adc" => Some(quote! { impl_adc_instance!(#peri); }),
594+
"mathacl" => Some(quote! { impl_mathacl_instance!(#peri); }),
594595
_ => None,
595596
};
596597

embassy-mspm0/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ pub mod dma;
1919
pub mod gpio;
2020
pub mod i2c;
2121
pub mod i2c_target;
22+
#[cfg(any(mspm0g150x, mspm0g151x, mspm0g350x, mspm0g351x))]
23+
pub mod mathacl;
2224
pub mod timer;
2325
pub mod uart;
2426
pub mod wwdt;

embassy-mspm0/src/mathacl.rs

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
//! MATHACL
2+
//!
3+
//! This HAL implements mathematical calculations performed by the CPU.
4+
5+
#![macro_use]
6+
7+
use core::f32::consts::PI;
8+
use core::marker::PhantomData;
9+
10+
use embassy_hal_internal::PeripheralType;
11+
use micromath::F32Ext;
12+
13+
use crate::Peri;
14+
use crate::pac::mathacl::{Mathacl as Regs, vals};
15+
16+
pub 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]
26+
pub enum Error {
27+
ValueInWrongRange,
28+
NBitsTooBig,
29+
}
30+
31+
pub struct Mathacl<'d> {
32+
regs: &'static Regs,
33+
_phantom: PhantomData<&'d mut ()>,
34+
}
35+
36+
impl<'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+
102+
pub(crate) trait SealedInstance {
103+
fn regs() -> &'static Regs;
104+
}
105+
106+
/// Mathacl instance trait
107+
#[allow(private_bounds)]
108+
pub trait Instance: SealedInstance + PeripheralType {}
109+
110+
macro_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.
123+
fn 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.
176+
fn 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)]
223+
mod 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+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
8+
use core::f32::consts::PI;
9+
10+
use defmt::*;
11+
use embassy_executor::Spawner;
12+
use embassy_mspm0::mathacl::{Mathacl, Precision};
13+
use embassy_time::Timer;
14+
use {defmt_rtt as _, panic_halt as _};
15+
16+
#[embassy_executor::main]
17+
async 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+
}

0 commit comments

Comments
 (0)