aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/cordic/errors.rs76
-rw-r--r--embassy-stm32/src/cordic/mod.rs53
-rw-r--r--embassy-stm32/src/cordic/utils.rs43
3 files changed, 109 insertions, 63 deletions
diff --git a/embassy-stm32/src/cordic/errors.rs b/embassy-stm32/src/cordic/errors.rs
index d0b2dc618..2c0aca4a2 100644
--- a/embassy-stm32/src/cordic/errors.rs
+++ b/embassy-stm32/src/cordic/errors.rs
@@ -9,6 +9,26 @@ pub enum CordicError {
9 ArgError(ArgError), 9 ArgError(ArgError),
10 /// Output buffer length error 10 /// Output buffer length error
11 OutputLengthNotEnough, 11 OutputLengthNotEnough,
12 /// Input value is out of range for Q1.x format
13 NumberOutOfRange(NumberOutOfRange),
14}
15
16impl From<ConfigError> for CordicError {
17 fn from(value: ConfigError) -> Self {
18 Self::ConfigError(value)
19 }
20}
21
22impl From<ArgError> for CordicError {
23 fn from(value: ArgError) -> Self {
24 Self::ArgError(value)
25 }
26}
27
28impl From<NumberOutOfRange> for CordicError {
29 fn from(value: NumberOutOfRange) -> Self {
30 Self::NumberOutOfRange(value)
31 }
12} 32}
13 33
14#[cfg(feature = "defmt")] 34#[cfg(feature = "defmt")]
@@ -19,6 +39,7 @@ impl defmt::Format for CordicError {
19 match self { 39 match self {
20 ConfigError(e) => defmt::write!(fmt, "{}", e), 40 ConfigError(e) => defmt::write!(fmt, "{}", e),
21 ArgError(e) => defmt::write!(fmt, "{}", e), 41 ArgError(e) => defmt::write!(fmt, "{}", e),
42 NumberOutOfRange(e) => defmt::write!(fmt, "{}", e),
22 OutputLengthNotEnough => defmt::write!(fmt, "Output buffer length is not long enough"), 43 OutputLengthNotEnough => defmt::write!(fmt, "Output buffer length is not long enough"),
23 } 44 }
24 } 45 }
@@ -68,28 +89,51 @@ impl defmt::Format for ArgError {
68 defmt::write!(fmt, " when SCALE is {},", scale); 89 defmt::write!(fmt, " when SCALE is {},", scale);
69 } 90 }
70 91
71 let arg_string = match self.arg_type { 92 defmt::write!(fmt, " {} should be", self.arg_type);
72 ArgType::Arg1 => "ARG1",
73 ArgType::Arg2 => "ARG2",
74 };
75
76 defmt::write!(fmt, " {} should be", arg_string);
77
78 let inclusive_string = if self.inclusive_upper_bound { "=" } else { "" };
79 93
80 defmt::write!( 94 if self.inclusive_upper_bound {
81 fmt, 95 defmt::write!(
82 " {} <= {} <{} {}", 96 fmt,
83 self.arg_range[0], 97 " {} <= {} <= {}",
84 arg_string, 98 self.arg_range[0],
85 inclusive_string, 99 self.arg_type,
86 self.arg_range[1] 100 self.arg_range[1]
87 ) 101 )
102 } else {
103 defmt::write!(
104 fmt,
105 " {} <= {} < {}",
106 self.arg_range[0],
107 self.arg_type,
108 self.arg_range[1]
109 )
110 };
88 } 111 }
89} 112}
90 113
91#[derive(Debug)] 114#[derive(Debug)]
115#[cfg_attr(feature = "defmt", derive(defmt::Format))]
92pub(super) enum ArgType { 116pub(super) enum ArgType {
93 Arg1, 117 Arg1,
94 Arg2, 118 Arg2,
95} 119}
120
121/// Input value is out of range for Q1.x format
122#[allow(missing_docs)]
123#[derive(Debug)]
124pub enum NumberOutOfRange {
125 BelowLowerBound,
126 AboveUpperBound,
127}
128
129#[cfg(feature = "defmt")]
130impl defmt::Format for NumberOutOfRange {
131 fn format(&self, fmt: defmt::Formatter) {
132 use NumberOutOfRange::*;
133
134 match self {
135 BelowLowerBound => defmt::write!(fmt, "input value should be equal or greater than -1"),
136 AboveUpperBound => defmt::write!(fmt, "input value should be equal or less than 1"),
137 }
138 }
139}
diff --git a/embassy-stm32/src/cordic/mod.rs b/embassy-stm32/src/cordic/mod.rs
index 5ac9addd8..b0db3f060 100644
--- a/embassy-stm32/src/cordic/mod.rs
+++ b/embassy-stm32/src/cordic/mod.rs
@@ -56,7 +56,7 @@ impl Config {
56 Ok(config) 56 Ok(config)
57 } 57 }
58 58
59 fn check_scale(&self) -> Result<(), CordicError> { 59 fn check_scale(&self) -> Result<(), ConfigError> {
60 use Function::*; 60 use Function::*;
61 61
62 let scale_raw = self.scale as u8; 62 let scale_raw = self.scale as u8;
@@ -76,10 +76,10 @@ impl Config {
76 }; 76 };
77 77
78 if let Some(range) = err_range { 78 if let Some(range) = err_range {
79 Err(CordicError::ConfigError(ConfigError { 79 Err(ConfigError {
80 func: self.function, 80 func: self.function,
81 scale_range: range, 81 scale_range: range,
82 })) 82 })
83 } else { 83 } else {
84 Ok(()) 84 Ok(())
85 } 85 }
@@ -226,20 +226,20 @@ impl<'d, T: Instance> Cordic<'d, T> {
226 consumed_input_len = double_input.len() + 1; 226 consumed_input_len = double_input.len() + 1;
227 227
228 // preload first value from arg1 to cordic 228 // preload first value from arg1 to cordic
229 self.blocking_write_f64(arg1s[0]); 229 self.blocking_write_f64(arg1s[0])?;
230 230
231 for (&arg1, &arg2) in double_input { 231 for (&arg1, &arg2) in double_input {
232 // Since we manually preload a value before, 232 // Since we manually preload a value before,
233 // we will write arg2 (from the actual last pair) first, (at this moment, cordic start to calculating,) 233 // we will write arg2 (from the actual last pair) first, (at this moment, cordic start to calculating,)
234 // and write arg1 (from the actual next pair), then read the result, to "keep preloading" 234 // and write arg1 (from the actual next pair), then read the result, to "keep preloading"
235 235
236 self.blocking_write_f64(arg2); 236 self.blocking_write_f64(arg2)?;
237 self.blocking_write_f64(arg1); 237 self.blocking_write_f64(arg1)?;
238 self.blocking_read_f64_to_buf(output, &mut output_count); 238 self.blocking_read_f64_to_buf(output, &mut output_count);
239 } 239 }
240 240
241 // write last input value from arg2s, then read out the result 241 // write last input value from arg2s, then read out the result
242 self.blocking_write_f64(arg2s[arg2s.len() - 1]); 242 self.blocking_write_f64(arg2s[arg2s.len() - 1])?;
243 self.blocking_read_f64_to_buf(output, &mut output_count); 243 self.blocking_read_f64_to_buf(output, &mut output_count);
244 } 244 }
245 245
@@ -253,12 +253,12 @@ impl<'d, T: Instance> Cordic<'d, T> {
253 self.peri.set_argument_count(AccessCount::One); 253 self.peri.set_argument_count(AccessCount::One);
254 254
255 // "preload" value to cordic (at this moment, cordic start to calculating) 255 // "preload" value to cordic (at this moment, cordic start to calculating)
256 self.blocking_write_f64(input_left[0]); 256 self.blocking_write_f64(input_left[0])?;
257 257
258 for &arg in input_left.iter().skip(1) { 258 for &arg in input_left.iter().skip(1) {
259 // this line write arg for next round caculation to cordic, 259 // this line write arg for next round caculation to cordic,
260 // and read result from last round 260 // and read result from last round
261 self.blocking_write_f64(arg); 261 self.blocking_write_f64(arg)?;
262 self.blocking_read_f64_to_buf(output, &mut output_count); 262 self.blocking_read_f64_to_buf(output, &mut output_count);
263 } 263 }
264 264
@@ -281,8 +281,9 @@ impl<'d, T: Instance> Cordic<'d, T> {
281 } 281 }
282 } 282 }
283 283
284 fn blocking_write_f64(&mut self, arg: f64) { 284 fn blocking_write_f64(&mut self, arg: f64) -> Result<(), NumberOutOfRange> {
285 self.peri.write_argument(utils::f64_to_q1_31(arg)); 285 self.peri.write_argument(utils::f64_to_q1_31(arg)?);
286 Ok(())
286 } 287 }
287 288
288 /// Run a async CORDIC calculation in q.1.31 format 289 /// Run a async CORDIC calculation in q.1.31 format
@@ -339,7 +340,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
339 340
340 for (&arg1, &arg2) in double_input { 341 for (&arg1, &arg2) in double_input {
341 for &arg in [arg1, arg2].iter() { 342 for &arg in [arg1, arg2].iter() {
342 input_buf[input_buf_len] = utils::f64_to_q1_31(arg); 343 input_buf[input_buf_len] = utils::f64_to_q1_31(arg)?;
343 input_buf_len += 1; 344 input_buf_len += 1;
344 } 345 }
345 346
@@ -383,7 +384,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
383 self.peri.set_argument_count(AccessCount::One); 384 self.peri.set_argument_count(AccessCount::One);
384 385
385 for &arg in input_remain { 386 for &arg in input_remain {
386 input_buf[input_buf_len] = utils::f64_to_q1_31(arg); 387 input_buf[input_buf_len] = utils::f64_to_q1_31(arg)?;
387 input_buf_len += 1; 388 input_buf_len += 1;
388 389
389 if input_buf_len == INPUT_BUF_MAX_LEN { 390 if input_buf_len == INPUT_BUF_MAX_LEN {
@@ -509,10 +510,10 @@ impl<'d, T: Instance> Cordic<'d, T> {
509 let (&arg1, &arg2) = args.next().unwrap(); 510 let (&arg1, &arg2) = args.next().unwrap();
510 511
511 // preloading 1 pair of arguments 512 // preloading 1 pair of arguments
512 self.blocking_write_f32(arg1, arg2); 513 self.blocking_write_f32(arg1, arg2)?;
513 514
514 for (&arg1, &arg2) in args { 515 for (&arg1, &arg2) in args {
515 self.blocking_write_f32(arg1, arg2); 516 self.blocking_write_f32(arg1, arg2)?;
516 self.blocking_read_f32_to_buf(output, &mut output_count); 517 self.blocking_read_f32_to_buf(output, &mut output_count);
517 } 518 }
518 519
@@ -522,15 +523,13 @@ impl<'d, T: Instance> Cordic<'d, T> {
522 Ok(output_count) 523 Ok(output_count)
523 } 524 }
524 525
525 fn blocking_write_f32(&mut self, arg1: f32, arg2: f32) { 526 fn blocking_write_f32(&mut self, arg1: f32, arg2: f32) -> Result<(), NumberOutOfRange> {
526 let reg_value: u32 = utils::f32_args_to_u32(arg1, arg2); 527 self.peri.write_argument(utils::f32_args_to_u32(arg1, arg2)?);
527 self.peri.write_argument(reg_value); 528 Ok(())
528 } 529 }
529 530
530 fn blocking_read_f32_to_buf(&mut self, result_buf: &mut [f32], result_index: &mut usize) { 531 fn blocking_read_f32_to_buf(&mut self, result_buf: &mut [f32], result_index: &mut usize) {
531 let reg_value = self.peri.read_result(); 532 let (res1, res2) = utils::u32_to_f32_res(self.peri.read_result());
532
533 let (res1, res2) = utils::u32_to_f32_res(reg_value);
534 533
535 result_buf[*result_index] = res1; 534 result_buf[*result_index] = res1;
536 *result_index += 1; 535 *result_index += 1;
@@ -597,7 +596,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
597 ); 596 );
598 597
599 for (&arg1, &arg2) in args { 598 for (&arg1, &arg2) in args {
600 input_buf[input_buf_len] = utils::f32_args_to_u32(arg1, arg2); 599 input_buf[input_buf_len] = utils::f32_args_to_u32(arg1, arg2)?;
601 input_buf_len += 1; 600 input_buf_len += 1;
602 601
603 if input_buf_len == INPUT_BUF_MAX_LEN { 602 if input_buf_len == INPUT_BUF_MAX_LEN {
@@ -655,7 +654,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
655macro_rules! check_input_value { 654macro_rules! check_input_value {
656 ($func_name:ident, $float_type:ty) => { 655 ($func_name:ident, $float_type:ty) => {
657 impl<'d, T: Instance> Cordic<'d, T> { 656 impl<'d, T: Instance> Cordic<'d, T> {
658 fn $func_name(&self, arg1s: &[$float_type], arg2s: Option<&[$float_type]>) -> Result<(), CordicError> { 657 fn $func_name(&self, arg1s: &[$float_type], arg2s: Option<&[$float_type]>) -> Result<(), ArgError> {
659 let config = &self.config; 658 let config = &self.config;
660 659
661 use Function::*; 660 use Function::*;
@@ -741,13 +740,13 @@ macro_rules! check_input_value {
741 }; 740 };
742 741
743 if let Some(err) = err_info { 742 if let Some(err) = err_info {
744 return Err(CordicError::ArgError(ArgError { 743 return Err(ArgError {
745 func: config.function, 744 func: config.function,
746 scale: err.scale, 745 scale: err.scale,
747 arg_range: err.range, 746 arg_range: err.range,
748 inclusive_upper_bound: err.inclusive_upper_bound, 747 inclusive_upper_bound: err.inclusive_upper_bound,
749 arg_type: ArgType::Arg1, 748 arg_type: ArgType::Arg1,
750 })); 749 });
751 } 750 }
752 751
753 // check ARG2 value 752 // check ARG2 value
@@ -769,13 +768,13 @@ macro_rules! check_input_value {
769 }; 768 };
770 769
771 if let Some(err) = err_info { 770 if let Some(err) = err_info {
772 return Err(CordicError::ArgError(ArgError { 771 return Err(ArgError {
773 func: config.function, 772 func: config.function,
774 scale: None, 773 scale: None,
775 arg_range: err.range, 774 arg_range: err.range,
776 inclusive_upper_bound: true, 775 inclusive_upper_bound: true,
777 arg_type: ArgType::Arg2, 776 arg_type: ArgType::Arg2,
778 })); 777 });
779 } 778 }
780 } 779 }
781 780
diff --git a/embassy-stm32/src/cordic/utils.rs b/embassy-stm32/src/cordic/utils.rs
index 79bef6b97..3c3ed224f 100644
--- a/embassy-stm32/src/cordic/utils.rs
+++ b/embassy-stm32/src/cordic/utils.rs
@@ -1,39 +1,42 @@
1//! Common match utils 1//! Common match utils
2use super::errors::NumberOutOfRange;
2 3
3macro_rules! floating_fixed_convert { 4macro_rules! floating_fixed_convert {
4 ($f_to_q:ident, $q_to_f:ident, $unsigned_bin_typ:ty, $signed_bin_typ:ty, $float_ty:ty, $offset:literal, $min_positive:literal) => { 5 ($f_to_q:ident, $q_to_f:ident, $unsigned_bin_typ:ty, $signed_bin_typ:ty, $float_ty:ty, $offset:literal, $min_positive:literal) => {
5 /// convert float point to fixed point format 6 /// convert float point to fixed point format
6 pub(crate) fn $f_to_q(value: $float_ty) -> $unsigned_bin_typ { 7 pub fn $f_to_q(value: $float_ty) -> Result<$unsigned_bin_typ, NumberOutOfRange> {
7 const MIN_POSITIVE: $float_ty = unsafe { core::mem::transmute($min_positive) }; 8 const MIN_POSITIVE: $float_ty = unsafe { core::mem::transmute($min_positive) };
8 9
9 assert!( 10 if value < -1.0 {
10 (-1.0 as $float_ty) <= value, 11 return Err(NumberOutOfRange::BelowLowerBound)
11 "input value {} should be equal or greater than -1", 12 }
12 value 13
13 ); 14 if value > 1.0 {
15 return Err(NumberOutOfRange::AboveUpperBound)
16 }
14 17
15 18
16 let value = if value == 1.0 as $float_ty{ 19 let value = if 1.0 - MIN_POSITIVE < value && value <= 1.0 {
17 // make a exception for user specifing exact 1.0 float point, 20 // make a exception for value between (1.0^{-x} , 1.0] float point,
18 // convert 1.0 to max representable value of q1.x format 21 // convert it to max representable value of q1.x format
19 (1.0 as $float_ty) - MIN_POSITIVE 22 (1.0 as $float_ty) - MIN_POSITIVE
20 } else { 23 } else {
21 assert!(
22 value <= (1.0 as $float_ty) - MIN_POSITIVE,
23 "input value {} should be equal or less than 1-2^(-{})",
24 value, $offset
25 );
26 value 24 value
27 }; 25 };
28 26
29 (value * ((1 as $unsigned_bin_typ << $offset) as $float_ty)) as $unsigned_bin_typ 27 // It's necessary to cast the float value to signed integer, before convert it to a unsigned value.
28 // Since value from register is actually a "signed value", a "as" cast will keep original binary format but mark it as unsgined value.
29 // see https://doc.rust-lang.org/reference/expressions/operator-expr.html#numeric-cast
30 Ok((value * ((1 as $unsigned_bin_typ << $offset) as $float_ty)) as $signed_bin_typ as $unsigned_bin_typ)
30 } 31 }
31 32
32 #[inline(always)] 33 #[inline(always)]
33 /// convert fixed point to float point format 34 /// convert fixed point to float point format
34 pub(crate) fn $q_to_f(value: $unsigned_bin_typ) -> $float_ty { 35 pub fn $q_to_f(value: $unsigned_bin_typ) -> $float_ty {
35 // It's needed to convert from unsigned to signed first, for correct result. 36 // It's necessary to cast the unsigned integer to signed integer, before convert it to a float value.
36 -(value as $signed_bin_typ as $float_ty) / ((1 as $unsigned_bin_typ << $offset) as $float_ty) 37 // Since value from register is actually a "signed value", a "as" cast will keep original binary format but mark it as signed value.
38 // see https://doc.rust-lang.org/reference/expressions/operator-expr.html#numeric-cast
39 (value as $signed_bin_typ as $float_ty) / ((1 as $unsigned_bin_typ << $offset) as $float_ty)
37 } 40 }
38 }; 41 };
39} 42}
@@ -59,8 +62,8 @@ floating_fixed_convert!(
59); 62);
60 63
61#[inline(always)] 64#[inline(always)]
62pub(crate) fn f32_args_to_u32(arg1: f32, arg2: f32) -> u32 { 65pub(crate) fn f32_args_to_u32(arg1: f32, arg2: f32) -> Result<u32, NumberOutOfRange> {
63 f32_to_q1_15(arg1) as u32 + ((f32_to_q1_15(arg2) as u32) << 16) 66 Ok(f32_to_q1_15(arg1)? as u32 + ((f32_to_q1_15(arg2)? as u32) << 16))
64} 67}
65 68
66#[inline(always)] 69#[inline(always)]