aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreZio Pan <[email protected]>2024-03-19 22:19:06 +0800
committereZio Pan <[email protected]>2024-03-23 09:15:25 +0800
commit641da3602e1d7565d08180e0f5608f1ab81c309a (patch)
tree227a07e1dfa77e349b164dd3a9c5dcc3bba56476
parent10a9cce855fbf383a8f0ea5511526777062a03c4 (diff)
stm32 CORDIC: error handle
-rw-r--r--embassy-stm32/src/cordic/enums.rs29
-rw-r--r--embassy-stm32/src/cordic/errors.rs95
-rw-r--r--embassy-stm32/src/cordic/mod.rs516
-rw-r--r--embassy-stm32/src/cordic/sealed.rs12
4 files changed, 388 insertions, 264 deletions
diff --git a/embassy-stm32/src/cordic/enums.rs b/embassy-stm32/src/cordic/enums.rs
index 37c73f549..4b92a6cf8 100644
--- a/embassy-stm32/src/cordic/enums.rs
+++ b/embassy-stm32/src/cordic/enums.rs
@@ -1,6 +1,7 @@
1/// CORDIC function 1/// CORDIC function
2#[allow(missing_docs)] 2#[allow(missing_docs)]
3#[derive(Clone, Copy)] 3#[derive(Debug, Clone, Copy)]
4#[cfg_attr(feature = "defmt", derive(defmt::Format))]
4pub enum Function { 5pub enum Function {
5 Cos = 0, 6 Cos = 0,
6 Sin, 7 Sin,
@@ -16,7 +17,7 @@ pub enum Function {
16 17
17/// CORDIC precision 18/// CORDIC precision
18#[allow(missing_docs)] 19#[allow(missing_docs)]
19#[derive(Clone, Copy, Default)] 20#[derive(Debug, Clone, Copy, Default)]
20pub enum Precision { 21pub enum Precision {
21 Iters4 = 1, 22 Iters4 = 1,
22 Iters8, 23 Iters8,
@@ -37,25 +38,25 @@ pub enum Precision {
37} 38}
38 39
39/// CORDIC scale 40/// CORDIC scale
40#[allow(non_camel_case_types)]
41#[allow(missing_docs)] 41#[allow(missing_docs)]
42#[derive(Clone, Copy, Default, PartialEq)] 42#[derive(Debug, Clone, Copy, Default, PartialEq)]
43#[cfg_attr(feature = "defmt", derive(defmt::Format))]
43pub enum Scale { 44pub enum Scale {
44 #[default] 45 #[default]
45 A1_R1 = 0, 46 Arg1Res1 = 0,
46 A1o2_R2, 47 Arg1o2Res2,
47 A1o4_R4, 48 Arg1o4Res4,
48 A1o8_R8, 49 Arg1o8Res8,
49 A1o16_R16, 50 Arg1o16Res16,
50 A1o32_R32, 51 Arg1o32Res32,
51 A1o64_R64, 52 Arg1o64Res64,
52 A1o128_R128, 53 Arg1o128Res128,
53} 54}
54 55
55/// CORDIC argument/result count 56/// CORDIC argument/result register access count
56#[allow(missing_docs)] 57#[allow(missing_docs)]
57#[derive(Clone, Copy, Default)] 58#[derive(Clone, Copy, Default)]
58pub enum Count { 59pub enum AccessCount {
59 #[default] 60 #[default]
60 One, 61 One,
61 Two, 62 Two,
diff --git a/embassy-stm32/src/cordic/errors.rs b/embassy-stm32/src/cordic/errors.rs
new file mode 100644
index 000000000..d0b2dc618
--- /dev/null
+++ b/embassy-stm32/src/cordic/errors.rs
@@ -0,0 +1,95 @@
1use super::{Function, Scale};
2
3/// Error for [Cordic](super::Cordic)
4#[derive(Debug)]
5pub enum CordicError {
6 /// Config error
7 ConfigError(ConfigError),
8 /// Argument error
9 ArgError(ArgError),
10 /// Output buffer length error
11 OutputLengthNotEnough,
12}
13
14#[cfg(feature = "defmt")]
15impl defmt::Format for CordicError {
16 fn format(&self, fmt: defmt::Formatter) {
17 use CordicError::*;
18
19 match self {
20 ConfigError(e) => defmt::write!(fmt, "{}", e),
21 ArgError(e) => defmt::write!(fmt, "{}", e),
22 OutputLengthNotEnough => defmt::write!(fmt, "Output buffer length is not long enough"),
23 }
24 }
25}
26
27/// Error dring parsing [Cordic::Config](super::Config)
28#[derive(Debug)]
29pub struct ConfigError {
30 pub(super) func: Function,
31 pub(super) scale_range: [u8; 2],
32}
33
34#[cfg(feature = "defmt")]
35impl defmt::Format for ConfigError {
36 fn format(&self, fmt: defmt::Formatter) {
37 defmt::write!(fmt, "For FUNCTION: {},", self.func);
38
39 if self.scale_range[0] == self.scale_range[1] {
40 defmt::write!(fmt, " SCALE value should be {}", self.scale_range[0])
41 } else {
42 defmt::write!(
43 fmt,
44 " SCALE value should be {} <= SCALE <= {}",
45 self.scale_range[0],
46 self.scale_range[1]
47 )
48 }
49 }
50}
51
52/// Error on checking input arguments
53#[derive(Debug)]
54pub struct ArgError {
55 pub(super) func: Function,
56 pub(super) scale: Option<Scale>,
57 pub(super) arg_range: [f32; 2], // only for debug display, f32 is ok
58 pub(super) inclusive_upper_bound: bool,
59 pub(super) arg_type: ArgType,
60}
61
62#[cfg(feature = "defmt")]
63impl defmt::Format for ArgError {
64 fn format(&self, fmt: defmt::Formatter) {
65 defmt::write!(fmt, "For FUNCTION: {},", self.func);
66
67 if let Some(scale) = self.scale {
68 defmt::write!(fmt, " when SCALE is {},", scale);
69 }
70
71 let arg_string = match 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
80 defmt::write!(
81 fmt,
82 " {} <= {} <{} {}",
83 self.arg_range[0],
84 arg_string,
85 inclusive_string,
86 self.arg_range[1]
87 )
88 }
89}
90
91#[derive(Debug)]
92pub(super) enum ArgType {
93 Arg1,
94 Arg2,
95}
diff --git a/embassy-stm32/src/cordic/mod.rs b/embassy-stm32/src/cordic/mod.rs
index a4b98a770..5ac9addd8 100644
--- a/embassy-stm32/src/cordic/mod.rs
+++ b/embassy-stm32/src/cordic/mod.rs
@@ -1,4 +1,4 @@
1//! CORDIC co-processor 1//! coordinate rotation digital computer (CORDIC)
2 2
3use embassy_hal_internal::drop::OnDrop; 3use embassy_hal_internal::drop::OnDrop;
4use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 4use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
@@ -8,6 +8,9 @@ use crate::{dma, peripherals};
8mod enums; 8mod enums;
9pub use enums::*; 9pub use enums::*;
10 10
11mod errors;
12pub use errors::*;
13
11pub mod utils; 14pub mod utils;
12 15
13pub(crate) mod sealed; 16pub(crate) mod sealed;
@@ -30,33 +33,55 @@ pub struct Cordic<'d, T: Instance> {
30pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral {} 33pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral {}
31 34
32/// CORDIC configuration 35/// CORDIC configuration
36#[derive(Debug)]
33pub struct Config { 37pub struct Config {
34 function: Function, 38 function: Function,
35 precision: Precision, 39 precision: Precision,
36 scale: Scale, 40 scale: Scale,
37 first_result: bool, 41 res1_only: bool,
38} 42}
39 43
40impl Config { 44impl Config {
41 /// Create a config for Cordic driver 45 /// Create a config for Cordic driver
42 pub fn new(function: Function, precision: Option<Precision>, scale: Option<Scale>, first_result: bool) -> Self { 46 pub fn new(function: Function, precision: Precision, scale: Scale, res1_only: bool) -> Result<Self, CordicError> {
43 Self { 47 let config = Self {
44 function, 48 function,
45 precision: precision.unwrap_or_default(), 49 precision,
46 scale: scale.unwrap_or_default(), 50 scale,
47 first_result, 51 res1_only,
48 } 52 };
53
54 config.check_scale()?;
55
56 Ok(config)
49 } 57 }
50 58
51 fn check_scale(&self) -> bool { 59 fn check_scale(&self) -> Result<(), CordicError> {
60 use Function::*;
61
52 let scale_raw = self.scale as u8; 62 let scale_raw = self.scale as u8;
53 63
54 match self.function { 64 let err_range = match self.function {
55 Function::Cos | Function::Sin | Function::Phase | Function::Modulus => 0 == scale_raw, 65 Cos | Sin | Phase | Modulus if !(0..=0).contains(&scale_raw) => Some([0, 0]),
56 Function::Arctan => (0..=7).contains(&scale_raw), 66
57 Function::Cosh | Function::Sinh | Function::Arctanh => 1 == scale_raw, 67 Arctan if !(0..=7).contains(&scale_raw) => Some([0, 7]),
58 Function::Ln => (1..=4).contains(&scale_raw), 68
59 Function::Sqrt => (0..=2).contains(&scale_raw), 69 Cosh | Sinh | Arctanh if !(1..=1).contains(&scale_raw) => Some([1, 1]),
70
71 Ln if !(1..=4).contains(&scale_raw) => Some([1, 4]),
72
73 Sqrt if !(0..=2).contains(&scale_raw) => Some([0, 2]),
74
75 Cos | Sin | Phase | Modulus | Arctan | Cosh | Sinh | Arctanh | Ln | Sqrt => None,
76 };
77
78 if let Some(range) = err_range {
79 Err(CordicError::ConfigError(ConfigError {
80 func: self.function,
81 scale_range: range,
82 }))
83 } else {
84 Ok(())
60 } 85 }
61 } 86 }
62} 87}
@@ -73,10 +98,6 @@ impl<'d, T: Instance> Cordic<'d, T> {
73 98
74 into_ref!(peri); 99 into_ref!(peri);
75 100
76 if !config.check_scale() {
77 panic!("Scale value is not compatible with Function")
78 }
79
80 let mut instance = Self { peri, config }; 101 let mut instance = Self { peri, config };
81 102
82 instance.reconfigure(); 103 instance.reconfigure();
@@ -91,21 +112,12 @@ impl<'d, T: Instance> Cordic<'d, T> {
91 } 112 }
92 113
93 /// Set extra config for data count and data width. 114 /// Set extra config for data count and data width.
94 pub fn extra_config(&mut self, arg_cnt: Count, arg_width: Width, res_width: Width) { 115 pub fn extra_config(&mut self, arg_cnt: AccessCount, arg_width: Width, res_width: Width) {
95 self.peri.set_argument_count(arg_cnt); 116 self.peri.set_argument_count(arg_cnt);
96 self.peri.set_data_width(arg_width, res_width); 117 self.peri.set_data_width(arg_width, res_width);
97 } 118 }
98 119
99 fn reconfigure(&mut self) { 120 fn reconfigure(&mut self) {
100 if self.peri.ready_to_read() {
101 warn!("At least 1 result hasn't been read, reconfigure will cause DATA LOST");
102 };
103
104 // clean RRDY flag
105 while self.peri.ready_to_read() {
106 self.peri.read_result();
107 }
108
109 self.peri.set_func(self.config.function); 121 self.peri.set_func(self.config.function);
110 self.peri.set_precision(self.config.precision); 122 self.peri.set_precision(self.config.precision);
111 self.peri.set_scale(self.config.scale); 123 self.peri.set_scale(self.config.scale);
@@ -113,6 +125,47 @@ impl<'d, T: Instance> Cordic<'d, T> {
113 // we don't set NRES in here, but to make sure NRES is set each time user call "calc"-ish functions, 125 // we don't set NRES in here, but to make sure NRES is set each time user call "calc"-ish functions,
114 // since each "calc"-ish functions can have different ARGSIZE and RESSIZE, thus NRES should be change accrodingly. 126 // since each "calc"-ish functions can have different ARGSIZE and RESSIZE, thus NRES should be change accrodingly.
115 } 127 }
128
129 async fn launch_a_dma_transfer(
130 &mut self,
131 write_dma: impl Peripheral<P = impl WriteDma<T>>,
132 read_dma: impl Peripheral<P = impl ReadDma<T>>,
133 input: &[u32],
134 output: &mut [u32],
135 ) {
136 into_ref!(write_dma, read_dma);
137
138 let write_req = write_dma.request();
139 let read_req = read_dma.request();
140
141 self.peri.enable_write_dma();
142 self.peri.enable_read_dma();
143
144 let _on_drop = OnDrop::new(|| {
145 self.peri.disable_write_dma();
146 self.peri.disable_read_dma();
147 });
148
149 unsafe {
150 let write_transfer = dma::Transfer::new_write(
151 &mut write_dma,
152 write_req,
153 input,
154 T::regs().wdata().as_ptr() as *mut _,
155 Default::default(),
156 );
157
158 let read_transfer = dma::Transfer::new_read(
159 &mut read_dma,
160 read_req,
161 T::regs().rdata().as_ptr() as *mut _,
162 output,
163 Default::default(),
164 );
165
166 embassy_futures::join::join(write_transfer, read_transfer).await;
167 }
168 }
116} 169}
117 170
118impl<'d, T: Instance> Drop for Cordic<'d, T> { 171impl<'d, T: Instance> Drop for Cordic<'d, T> {
@@ -124,25 +177,31 @@ impl<'d, T: Instance> Drop for Cordic<'d, T> {
124// q1.31 related 177// q1.31 related
125impl<'d, T: Instance> Cordic<'d, T> { 178impl<'d, T: Instance> Cordic<'d, T> {
126 /// Run a blocking CORDIC calculation in q1.31 format 179 /// Run a blocking CORDIC calculation in q1.31 format
127 pub fn blocking_calc_32bit(&mut self, arg1s: &[f64], arg2s: Option<&[f64]>, output: &mut [f64]) -> usize { 180 pub fn blocking_calc_32bit(
181 &mut self,
182 arg1s: &[f64],
183 arg2s: Option<&[f64]>,
184 output: &mut [f64],
185 ) -> Result<usize, CordicError> {
128 if arg1s.is_empty() { 186 if arg1s.is_empty() {
129 return 0; 187 return Ok(0);
130 } 188 }
131 189
132 assert!( 190 let output_length_enough = match self.config.res1_only {
133 match self.config.first_result { 191 true => output.len() >= arg1s.len(),
134 true => output.len() >= arg1s.len(), 192 false => output.len() >= 2 * arg1s.len(),
135 false => output.len() >= 2 * arg1s.len(), 193 };
136 },
137 "Output buf length is not long enough"
138 );
139 194
140 self.check_input_f64(arg1s, arg2s); 195 if !output_length_enough {
196 return Err(CordicError::OutputLengthNotEnough);
197 }
198
199 self.check_input_f64(arg1s, arg2s)?;
141 200
142 self.peri.set_result_count(if self.config.first_result { 201 self.peri.set_result_count(if self.config.res1_only {
143 Count::One 202 AccessCount::One
144 } else { 203 } else {
145 Count::Two 204 AccessCount::Two
146 }); 205 });
147 206
148 self.peri.set_data_width(Width::Bits32, Width::Bits32); 207 self.peri.set_data_width(Width::Bits32, Width::Bits32);
@@ -155,10 +214,10 @@ impl<'d, T: Instance> Cordic<'d, T> {
155 // handle 2 input args calculation 214 // handle 2 input args calculation
156 // 215 //
157 216
158 if arg2s.is_some() && !arg2s.expect("It's infailable").is_empty() { 217 if arg2s.is_some() && !arg2s.unwrap().is_empty() {
159 let arg2s = arg2s.expect("It's infailable"); 218 let arg2s = arg2s.unwrap();
160 219
161 self.peri.set_argument_count(Count::Two); 220 self.peri.set_argument_count(AccessCount::Two);
162 221
163 // Skip 1st value from arg1s, this value will be manually "preload" to cordic, to make use of cordic preload function. 222 // Skip 1st value from arg1s, this value will be manually "preload" to cordic, to make use of cordic preload function.
164 // And we preserve last value from arg2s, since it need to manually write to cordic, and read the result out. 223 // And we preserve last value from arg2s, since it need to manually write to cordic, and read the result out.
@@ -191,7 +250,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
191 let input_left = &arg1s[consumed_input_len..]; 250 let input_left = &arg1s[consumed_input_len..];
192 251
193 if !input_left.is_empty() { 252 if !input_left.is_empty() {
194 self.peri.set_argument_count(Count::One); 253 self.peri.set_argument_count(AccessCount::One);
195 254
196 // "preload" value to cordic (at this moment, cordic start to calculating) 255 // "preload" value to cordic (at this moment, cordic start to calculating)
197 self.blocking_write_f64(input_left[0]); 256 self.blocking_write_f64(input_left[0]);
@@ -207,7 +266,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
207 self.blocking_read_f64_to_buf(output, &mut output_count); 266 self.blocking_read_f64_to_buf(output, &mut output_count);
208 } 267 }
209 268
210 output_count 269 Ok(output_count)
211 } 270 }
212 271
213 fn blocking_read_f64_to_buf(&mut self, result_buf: &mut [f64], result_index: &mut usize) { 272 fn blocking_read_f64_to_buf(&mut self, result_buf: &mut [f64], result_index: &mut usize) {
@@ -216,7 +275,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
216 275
217 // We don't care about whether the function return 1 or 2 results, 276 // We don't care about whether the function return 1 or 2 results,
218 // the only thing matter is whether user want 1 or 2 results. 277 // the only thing matter is whether user want 1 or 2 results.
219 if !self.config.first_result { 278 if !self.config.res1_only {
220 result_buf[*result_index] = utils::q1_31_to_f64(self.peri.read_result()); 279 result_buf[*result_index] = utils::q1_31_to_f64(self.peri.read_result());
221 *result_index += 1; 280 *result_index += 1;
222 } 281 }
@@ -234,27 +293,28 @@ impl<'d, T: Instance> Cordic<'d, T> {
234 arg1s: &[f64], 293 arg1s: &[f64],
235 arg2s: Option<&[f64]>, 294 arg2s: Option<&[f64]>,
236 output: &mut [f64], 295 output: &mut [f64],
237 ) -> usize { 296 ) -> Result<usize, CordicError> {
238 if arg1s.is_empty() { 297 if arg1s.is_empty() {
239 return 0; 298 return Ok(0);
240 } 299 }
241 300
242 assert!( 301 let output_length_enough = match self.config.res1_only {
243 match self.config.first_result { 302 true => output.len() >= arg1s.len(),
244 true => output.len() >= arg1s.len(), 303 false => output.len() >= 2 * arg1s.len(),
245 false => output.len() >= 2 * arg1s.len(), 304 };
246 },
247 "Output buf length is not long enough"
248 );
249 305
250 self.check_input_f64(arg1s, arg2s); 306 if !output_length_enough {
307 return Err(CordicError::OutputLengthNotEnough);
308 }
309
310 self.check_input_f64(arg1s, arg2s)?;
251 311
252 into_ref!(write_dma, read_dma); 312 into_ref!(write_dma, read_dma);
253 313
254 self.peri.set_result_count(if self.config.first_result { 314 self.peri.set_result_count(if self.config.res1_only {
255 Count::One 315 AccessCount::One
256 } else { 316 } else {
257 Count::Two 317 AccessCount::Two
258 }); 318 });
259 319
260 self.peri.set_data_width(Width::Bits32, Width::Bits32); 320 self.peri.set_data_width(Width::Bits32, Width::Bits32);
@@ -269,9 +329,9 @@ impl<'d, T: Instance> Cordic<'d, T> {
269 // 329 //
270 330
271 if !arg2s.unwrap_or_default().is_empty() { 331 if !arg2s.unwrap_or_default().is_empty() {
272 let arg2s = arg2s.expect("It's infailable"); 332 let arg2s = arg2s.unwrap();
273 333
274 self.peri.set_argument_count(Count::Two); 334 self.peri.set_argument_count(AccessCount::Two);
275 335
276 let double_input = arg1s.iter().zip(arg2s); 336 let double_input = arg1s.iter().zip(arg2s);
277 337
@@ -320,7 +380,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
320 if arg1s.len() > consumed_input_len { 380 if arg1s.len() > consumed_input_len {
321 let input_remain = &arg1s[consumed_input_len..]; 381 let input_remain = &arg1s[consumed_input_len..];
322 382
323 self.peri.set_argument_count(Count::One); 383 self.peri.set_argument_count(AccessCount::One);
324 384
325 for &arg in input_remain { 385 for &arg in input_remain {
326 input_buf[input_buf_len] = utils::f64_to_q1_31(arg); 386 input_buf[input_buf_len] = utils::f64_to_q1_31(arg);
@@ -356,7 +416,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
356 } 416 }
357 } 417 }
358 418
359 output_count 419 Ok(output_count)
360 } 420 }
361 421
362 // this function is highly coupled with async_calc_32bit, and is not intended to use in other place 422 // this function is highly coupled with async_calc_32bit, and is not intended to use in other place
@@ -369,11 +429,6 @@ impl<'d, T: Instance> Cordic<'d, T> {
369 output: &mut [f64], // caller uses should this as a final output array 429 output: &mut [f64], // caller uses should this as a final output array
370 output_start_index: &mut usize, // the index of start point of the output for this round of calculation 430 output_start_index: &mut usize, // the index of start point of the output for this round of calculation
371 ) { 431 ) {
372 into_ref!(write_dma, read_dma);
373
374 let write_req = write_dma.request();
375 let read_req = read_dma.request();
376
377 // output_buf is the place to store raw value from CORDIC (via DMA). 432 // output_buf is the place to store raw value from CORDIC (via DMA).
378 // For buf size, we assume in this round of calculation: 433 // For buf size, we assume in this round of calculation:
379 // all input is 1 arg, and all calculation need 2 output, 434 // all input is 1 arg, and all calculation need 2 output,
@@ -381,7 +436,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
381 let mut output_buf = [0u32; INPUT_BUF_MAX_LEN * 2]; 436 let mut output_buf = [0u32; INPUT_BUF_MAX_LEN * 2];
382 437
383 let mut output_buf_size = input_buf.len(); 438 let mut output_buf_size = input_buf.len();
384 if !self.config.first_result { 439 if !self.config.res1_only {
385 // if we need 2 result for 1 input, then output_buf length should be 2x long. 440 // if we need 2 result for 1 input, then output_buf length should be 2x long.
386 output_buf_size *= 2; 441 output_buf_size *= 2;
387 }; 442 };
@@ -392,35 +447,8 @@ impl<'d, T: Instance> Cordic<'d, T> {
392 447
393 let active_output_buf = &mut output_buf[..output_buf_size]; 448 let active_output_buf = &mut output_buf[..output_buf_size];
394 449
395 self.peri.enable_write_dma(); 450 self.launch_a_dma_transfer(write_dma, read_dma, input_buf, active_output_buf)
396 self.peri.enable_read_dma(); 451 .await;
397
398 let on_drop = OnDrop::new(|| {
399 self.peri.disable_write_dma();
400 self.peri.disable_read_dma();
401 });
402
403 unsafe {
404 let write_transfer = dma::Transfer::new_write(
405 &mut write_dma,
406 write_req,
407 input_buf,
408 T::regs().wdata().as_ptr() as *mut _,
409 Default::default(),
410 );
411
412 let read_transfer = dma::Transfer::new_read(
413 &mut read_dma,
414 read_req,
415 T::regs().rdata().as_ptr() as *mut _,
416 active_output_buf,
417 Default::default(),
418 );
419
420 embassy_futures::join::join(write_transfer, read_transfer).await;
421 }
422
423 drop(on_drop);
424 452
425 for &mut output_u32 in active_output_buf { 453 for &mut output_u32 in active_output_buf {
426 output[*output_start_index] = utils::q1_31_to_f64(output_u32); 454 output[*output_start_index] = utils::q1_31_to_f64(output_u32);
@@ -432,24 +460,30 @@ impl<'d, T: Instance> Cordic<'d, T> {
432// q1.15 related 460// q1.15 related
433impl<'d, T: Instance> Cordic<'d, T> { 461impl<'d, T: Instance> Cordic<'d, T> {
434 /// Run a blocking CORDIC calculation in q1.15 format 462 /// Run a blocking CORDIC calculation in q1.15 format
435 pub fn blocking_calc_16bit(&mut self, arg1s: &[f32], arg2s: Option<&[f32]>, output: &mut [f32]) -> usize { 463 pub fn blocking_calc_16bit(
464 &mut self,
465 arg1s: &[f32],
466 arg2s: Option<&[f32]>,
467 output: &mut [f32],
468 ) -> Result<usize, CordicError> {
436 if arg1s.is_empty() { 469 if arg1s.is_empty() {
437 return 0; 470 return Ok(0);
438 } 471 }
439 472
440 assert!( 473 let output_length_enough = match self.config.res1_only {
441 match self.config.first_result { 474 true => output.len() >= arg1s.len(),
442 true => output.len() >= arg1s.len(), 475 false => output.len() >= 2 * arg1s.len(),
443 false => output.len() >= 2 * arg1s.len(), 476 };
444 }, 477
445 "Output buf length is not long enough" 478 if !output_length_enough {
446 ); 479 return Err(CordicError::OutputLengthNotEnough);
480 }
447 481
448 self.check_input_f32(arg1s, arg2s); 482 self.check_input_f32(arg1s, arg2s)?;
449 483
450 // In q1.15 mode, 1 write/read to access 2 arguments/results 484 // In q1.15 mode, 1 write/read to access 2 arguments/results
451 self.peri.set_argument_count(Count::One); 485 self.peri.set_argument_count(AccessCount::One);
452 self.peri.set_result_count(Count::One); 486 self.peri.set_result_count(AccessCount::One);
453 487
454 self.peri.set_data_width(Width::Bits16, Width::Bits16); 488 self.peri.set_data_width(Width::Bits16, Width::Bits16);
455 489
@@ -472,9 +506,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
472 .chain(core::iter::repeat(&arg2_default_value)), 506 .chain(core::iter::repeat(&arg2_default_value)),
473 ); 507 );
474 508
475 let (&arg1, &arg2) = args 509 let (&arg1, &arg2) = args.next().unwrap();
476 .next()
477 .expect("This should be infallible, since arg1s is not empty");
478 510
479 // preloading 1 pair of arguments 511 // preloading 1 pair of arguments
480 self.blocking_write_f32(arg1, arg2); 512 self.blocking_write_f32(arg1, arg2);
@@ -487,7 +519,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
487 // read last pair of value from cordic 519 // read last pair of value from cordic
488 self.blocking_read_f32_to_buf(output, &mut output_count); 520 self.blocking_read_f32_to_buf(output, &mut output_count);
489 521
490 output_count 522 Ok(output_count)
491 } 523 }
492 524
493 fn blocking_write_f32(&mut self, arg1: f32, arg2: f32) { 525 fn blocking_write_f32(&mut self, arg1: f32, arg2: f32) {
@@ -505,7 +537,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
505 537
506 // We don't care about whether the function return 1 or 2 results, 538 // We don't care about whether the function return 1 or 2 results,
507 // the only thing matter is whether user want 1 or 2 results. 539 // the only thing matter is whether user want 1 or 2 results.
508 if !self.config.first_result { 540 if !self.config.res1_only {
509 result_buf[*result_index] = res2; 541 result_buf[*result_index] = res2;
510 *result_index += 1; 542 *result_index += 1;
511 } 543 }
@@ -519,26 +551,27 @@ impl<'d, T: Instance> Cordic<'d, T> {
519 arg1s: &[f32], 551 arg1s: &[f32],
520 arg2s: Option<&[f32]>, 552 arg2s: Option<&[f32]>,
521 output: &mut [f32], 553 output: &mut [f32],
522 ) -> usize { 554 ) -> Result<usize, CordicError> {
523 if arg1s.is_empty() { 555 if arg1s.is_empty() {
524 return 0; 556 return Ok(0);
525 } 557 }
526 558
527 assert!( 559 let output_length_enough = match self.config.res1_only {
528 match self.config.first_result { 560 true => output.len() >= arg1s.len(),
529 true => output.len() >= arg1s.len(), 561 false => output.len() >= 2 * arg1s.len(),
530 false => output.len() >= 2 * arg1s.len(), 562 };
531 },
532 "Output buf length is not long enough"
533 );
534 563
535 self.check_input_f32(arg1s, arg2s); 564 if !output_length_enough {
565 return Err(CordicError::OutputLengthNotEnough);
566 }
567
568 self.check_input_f32(arg1s, arg2s)?;
536 569
537 into_ref!(write_dma, read_dma); 570 into_ref!(write_dma, read_dma);
538 571
539 // In q1.15 mode, 1 write/read to access 2 arguments/results 572 // In q1.15 mode, 1 write/read to access 2 arguments/results
540 self.peri.set_argument_count(Count::One); 573 self.peri.set_argument_count(AccessCount::One);
541 self.peri.set_result_count(Count::One); 574 self.peri.set_result_count(AccessCount::One);
542 575
543 self.peri.set_data_width(Width::Bits16, Width::Bits16); 576 self.peri.set_data_width(Width::Bits16, Width::Bits16);
544 577
@@ -584,7 +617,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
584 .await; 617 .await;
585 } 618 }
586 619
587 output_count 620 Ok(output_count)
588 } 621 }
589 622
590 // this function is highly coupled with async_calc_16bit, and is not intended to use in other place 623 // this function is highly coupled with async_calc_16bit, and is not intended to use in other place
@@ -596,45 +629,13 @@ impl<'d, T: Instance> Cordic<'d, T> {
596 output: &mut [f32], // caller uses should this as a final output array 629 output: &mut [f32], // caller uses should this as a final output array
597 output_start_index: &mut usize, // the index of start point of the output for this round of calculation 630 output_start_index: &mut usize, // the index of start point of the output for this round of calculation
598 ) { 631 ) {
599 into_ref!(write_dma, read_dma);
600
601 let write_req = write_dma.request();
602 let read_req = read_dma.request();
603
604 // output_buf is the place to store raw value from CORDIC (via DMA). 632 // output_buf is the place to store raw value from CORDIC (via DMA).
605 let mut output_buf = [0u32; INPUT_BUF_MAX_LEN]; 633 let mut output_buf = [0u32; INPUT_BUF_MAX_LEN];
606 634
607 let active_output_buf = &mut output_buf[..input_buf.len()]; 635 let active_output_buf = &mut output_buf[..input_buf.len()];
608 636
609 self.peri.enable_write_dma(); 637 self.launch_a_dma_transfer(write_dma, read_dma, input_buf, active_output_buf)
610 self.peri.enable_read_dma(); 638 .await;
611
612 let on_drop = OnDrop::new(|| {
613 self.peri.disable_write_dma();
614 self.peri.disable_read_dma();
615 });
616
617 unsafe {
618 let write_transfer = dma::Transfer::new_write(
619 &mut write_dma,
620 write_req,
621 input_buf,
622 T::regs().wdata().as_ptr() as *mut _,
623 Default::default(),
624 );
625
626 let read_transfer = dma::Transfer::new_read(
627 &mut read_dma,
628 read_req,
629 T::regs().rdata().as_ptr() as *mut _,
630 active_output_buf,
631 Default::default(),
632 );
633
634 embassy_futures::join::join(write_transfer, read_transfer).await;
635 }
636
637 drop(on_drop);
638 639
639 for &mut output_u32 in active_output_buf { 640 for &mut output_u32 in active_output_buf {
640 let (res1, res2) = utils::u32_to_f32_res(output_u32); 641 let (res1, res2) = utils::u32_to_f32_res(output_u32);
@@ -642,7 +643,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
642 output[*output_start_index] = res1; 643 output[*output_start_index] = res1;
643 *output_start_index += 1; 644 *output_start_index += 1;
644 645
645 if !self.config.first_result { 646 if !self.config.res1_only {
646 output[*output_start_index] = res2; 647 output[*output_start_index] = res2;
647 *output_start_index += 1; 648 *output_start_index += 1;
648 } 649 }
@@ -654,104 +655,131 @@ impl<'d, T: Instance> Cordic<'d, T> {
654macro_rules! check_input_value { 655macro_rules! check_input_value {
655 ($func_name:ident, $float_type:ty) => { 656 ($func_name:ident, $float_type:ty) => {
656 impl<'d, T: Instance> Cordic<'d, T> { 657 impl<'d, T: Instance> Cordic<'d, T> {
657 fn $func_name(&self, arg1s: &[$float_type], arg2s: Option<&[$float_type]>) { 658 fn $func_name(&self, arg1s: &[$float_type], arg2s: Option<&[$float_type]>) -> Result<(), CordicError> {
658 let config = &self.config; 659 let config = &self.config;
659 660
660 use Function::*; 661 use Function::*;
661 662
662 // check SCALE value 663 struct Arg1ErrInfo {
663 match config.function { 664 scale: Option<Scale>,
664 Cos | Sin | Phase | Modulus => assert!(Scale::A1_R1 == config.scale, "SCALE should be 0"), 665 range: [f32; 2],
665 Arctan => assert!( 666 inclusive_upper_bound: bool,
666 (0..=7).contains(&(config.scale as u8)),
667 "SCALE should be: 0 <= SCALE <= 7"
668 ),
669 Cosh | Sinh | Arctanh => assert!(Scale::A1o2_R2 == config.scale, "SCALE should be 1"),
670
671 Ln => assert!(
672 (1..=4).contains(&(config.scale as u8)),
673 "SCALE should be: 1 <= SCALE <= 4"
674 ),
675 Sqrt => assert!(
676 (0..=2).contains(&(config.scale as u8)),
677 "SCALE should be: 0 <= SCALE <= 2"
678 ),
679 } 667 }
680 668
681 // check ARG1 value 669 // check ARG1 value
682 match config.function { 670 let err_info = match config.function {
683 Cos | Sin | Phase | Modulus | Arctan => { 671 Cos | Sin | Phase | Modulus | Arctan if arg1s.iter().any(|v| !(-1.0..=1.0).contains(v)) => {
684 assert!( 672 Some(Arg1ErrInfo {
685 arg1s.iter().all(|v| (-1.0..=1.0).contains(v)), 673 scale: None,
686 "ARG1 should be: -1 <= ARG1 <= 1" 674 range: [-1.0, 1.0],
687 ); 675 inclusive_upper_bound: true,
676 })
688 } 677 }
689 678
690 Cosh | Sinh => assert!( 679 Cosh | Sinh if arg1s.iter().any(|v| !(-0.559..=0.559).contains(v)) => Some(Arg1ErrInfo {
691 arg1s.iter().all(|v| (-0.559..=0.559).contains(v)), 680 scale: None,
692 "ARG1 should be: -0.559 <= ARG1 <= 0.559" 681 range: [-0.559, 0.559],
693 ), 682 inclusive_upper_bound: true,
694 683 }),
695 Arctanh => assert!( 684
696 arg1s.iter().all(|v| (-0.403..=0.403).contains(v)), 685 Arctanh if arg1s.iter().any(|v| !(-0.403..=0.403).contains(v)) => Some(Arg1ErrInfo {
697 "ARG1 should be: -0.403 <= ARG1 <= 0.403" 686 scale: None,
698 ), 687 range: [-0.403, 0.403],
699 688 inclusive_upper_bound: true,
700 Ln => { 689 }),
701 match config.scale { 690
702 Scale::A1o2_R2 => assert!( 691 Ln => match config.scale {
703 arg1s.iter().all(|v| (0.05354..0.5).contains(v)), 692 Scale::Arg1o2Res2 if arg1s.iter().any(|v| !(0.0535..0.5).contains(v)) => Some(Arg1ErrInfo {
704 "When SCALE set to 1, ARG1 should be: 0.05354 <= ARG1 < 0.5" 693 scale: Some(Scale::Arg1o2Res2),
705 ), 694 range: [0.0535, 0.5],
706 Scale::A1o4_R4 => assert!( 695 inclusive_upper_bound: false,
707 arg1s.iter().all(|v| (0.25..0.75).contains(v)), 696 }),
708 "When SCALE set to 2, ARG1 should be: 0.25 <= ARG1 < 0.75" 697 Scale::Arg1o4Res4 if arg1s.iter().any(|v| !(0.25..0.75).contains(v)) => Some(Arg1ErrInfo {
709 ), 698 scale: Some(Scale::Arg1o4Res4),
710 Scale::A1o8_R8 => assert!( 699 range: [0.25, 0.75],
711 arg1s.iter().all(|v| (0.375..0.875).contains(v)), 700 inclusive_upper_bound: false,
712 "When SCALE set to 3, ARG1 should be: 0.375 <= ARG1 < 0.875" 701 }),
713 ), 702 Scale::Arg1o8Res8 if arg1s.iter().any(|v| !(0.375..0.875).contains(v)) => Some(Arg1ErrInfo {
714 Scale::A1o16_R16 => assert!( 703 scale: Some(Scale::Arg1o8Res8),
715 arg1s.iter().all(|v| (0.4375..0.584).contains(v)), 704 range: [0.375, 0.875],
716 "When SCALE set to 4, ARG1 should be: 0.4375 <= ARG1 < 0.584" 705 inclusive_upper_bound: false,
717 ), 706 }),
718 _ => unreachable!(), 707 Scale::Arg1o16Res16 if arg1s.iter().any(|v| !(0.4375..0.584).contains(v)) => {
719 }; 708 Some(Arg1ErrInfo {
720 } 709 scale: Some(Scale::Arg1o16Res16),
710 range: [0.4375, 0.584],
711 inclusive_upper_bound: false,
712 })
713 }
714
715 Scale::Arg1o2Res2 | Scale::Arg1o4Res4 | Scale::Arg1o8Res8 | Scale::Arg1o16Res16 => None,
716
717 _ => unreachable!(),
718 },
721 719
722 Sqrt => match config.scale { 720 Sqrt => match config.scale {
723 Scale::A1_R1 => assert!( 721 Scale::Arg1Res1 if arg1s.iter().any(|v| !(0.027..0.75).contains(v)) => Some(Arg1ErrInfo {
724 arg1s.iter().all(|v| (0.027..0.75).contains(v)), 722 scale: Some(Scale::Arg1Res1),
725 "When SCALE set to 0, ARG1 should be: 0.027 <= ARG1 < 0.75" 723 range: [0.027, 0.75],
726 ), 724 inclusive_upper_bound: false,
727 Scale::A1o2_R2 => assert!( 725 }),
728 arg1s.iter().all(|v| (0.375..0.875).contains(v)), 726 Scale::Arg1o2Res2 if arg1s.iter().any(|v| !(0.375..0.875).contains(v)) => Some(Arg1ErrInfo {
729 "When SCALE set to 1, ARG1 should be: 0.375 <= ARG1 < 0.875" 727 scale: Some(Scale::Arg1o2Res2),
730 ), 728 range: [0.375, 0.875],
731 Scale::A1o4_R4 => assert!( 729 inclusive_upper_bound: false,
732 arg1s.iter().all(|v| (0.4375..0.585).contains(v)), 730 }),
733 "When SCALE set to 2, ARG1 should be: 0.4375 <= ARG1 < 0.585" 731 Scale::Arg1o4Res4 if arg1s.iter().any(|v| !(0.4375..0.584).contains(v)) => Some(Arg1ErrInfo {
734 ), 732 scale: Some(Scale::Arg1o4Res4),
733 range: [0.4375, 0.584],
734 inclusive_upper_bound: false,
735 }),
736 Scale::Arg1Res1 | Scale::Arg1o2Res2 | Scale::Arg1o4Res4 => None,
735 _ => unreachable!(), 737 _ => unreachable!(),
736 }, 738 },
739
740 Cos | Sin | Phase | Modulus | Arctan | Cosh | Sinh | Arctanh => None,
741 };
742
743 if let Some(err) = err_info {
744 return Err(CordicError::ArgError(ArgError {
745 func: config.function,
746 scale: err.scale,
747 arg_range: err.range,
748 inclusive_upper_bound: err.inclusive_upper_bound,
749 arg_type: ArgType::Arg1,
750 }));
737 } 751 }
738 752
739 // check ARG2 value 753 // check ARG2 value
740 if let Some(arg2s) = arg2s { 754 if let Some(arg2s) = arg2s {
741 match config.function { 755 struct Arg2ErrInfo {
742 Cos | Sin => assert!( 756 range: [f32; 2],
743 arg2s.iter().all(|v| (0.0..=1.0).contains(v)), 757 }
744 "ARG2 should be: 0 <= ARG2 <= 1" 758
745 ), 759 let err_info = match config.function {
746 760 Cos | Sin if arg2s.iter().any(|v| !(0.0..=1.0).contains(v)) => {
747 Phase | Modulus => assert!( 761 Some(Arg2ErrInfo { range: [0.0, 1.0] })
748 arg2s.iter().all(|v| (-1.0..=1.0).contains(v)), 762 }
749 "ARG2 should be: -1 <= ARG2 <= 1" 763
750 ), 764 Phase | Modulus if arg2s.iter().any(|v| !(-1.0..=1.0).contains(v)) => {
751 765 Some(Arg2ErrInfo { range: [-1.0, 1.0] })
752 _ => (), 766 }
767
768 Cos | Sin | Phase | Modulus | Arctan | Cosh | Sinh | Arctanh | Ln | Sqrt => None,
769 };
770
771 if let Some(err) = err_info {
772 return Err(CordicError::ArgError(ArgError {
773 func: config.function,
774 scale: None,
775 arg_range: err.range,
776 inclusive_upper_bound: true,
777 arg_type: ArgType::Arg2,
778 }));
753 } 779 }
754 } 780 }
781
782 Ok(())
755 } 783 }
756 } 784 }
757 }; 785 };
diff --git a/embassy-stm32/src/cordic/sealed.rs b/embassy-stm32/src/cordic/sealed.rs
index 0f00e380c..f9521ff7a 100644
--- a/embassy-stm32/src/cordic/sealed.rs
+++ b/embassy-stm32/src/cordic/sealed.rs
@@ -66,21 +66,21 @@ pub trait Instance {
66 } 66 }
67 67
68 /// Set NARGS value 68 /// Set NARGS value
69 fn set_argument_count(&self, n: Count) { 69 fn set_argument_count(&self, n: AccessCount) {
70 Self::regs().csr().modify(|v| { 70 Self::regs().csr().modify(|v| {
71 v.set_nargs(match n { 71 v.set_nargs(match n {
72 Count::One => vals::Num::NUM1, 72 AccessCount::One => vals::Num::NUM1,
73 Count::Two => vals::Num::NUM2, 73 AccessCount::Two => vals::Num::NUM2,
74 }) 74 })
75 }) 75 })
76 } 76 }
77 77
78 /// Set NRES value 78 /// Set NRES value
79 fn set_result_count(&self, n: Count) { 79 fn set_result_count(&self, n: AccessCount) {
80 Self::regs().csr().modify(|v| { 80 Self::regs().csr().modify(|v| {
81 v.set_nres(match n { 81 v.set_nres(match n {
82 Count::One => vals::Num::NUM1, 82 AccessCount::One => vals::Num::NUM1,
83 Count::Two => vals::Num::NUM2, 83 AccessCount::Two => vals::Num::NUM2,
84 }); 84 });
85 }) 85 })
86 } 86 }