diff options
| author | eZio Pan <[email protected]> | 2024-03-19 22:19:06 +0800 |
|---|---|---|
| committer | eZio Pan <[email protected]> | 2024-03-23 09:15:25 +0800 |
| commit | 641da3602e1d7565d08180e0f5608f1ab81c309a (patch) | |
| tree | 227a07e1dfa77e349b164dd3a9c5dcc3bba56476 | |
| parent | 10a9cce855fbf383a8f0ea5511526777062a03c4 (diff) | |
stm32 CORDIC: error handle
| -rw-r--r-- | embassy-stm32/src/cordic/enums.rs | 29 | ||||
| -rw-r--r-- | embassy-stm32/src/cordic/errors.rs | 95 | ||||
| -rw-r--r-- | embassy-stm32/src/cordic/mod.rs | 516 | ||||
| -rw-r--r-- | embassy-stm32/src/cordic/sealed.rs | 12 |
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))] | ||
| 4 | pub enum Function { | 5 | pub 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)] |
| 20 | pub enum Precision { | 21 | pub 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))] | ||
| 43 | pub enum Scale { | 44 | pub 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)] |
| 58 | pub enum Count { | 59 | pub 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 @@ | |||
| 1 | use super::{Function, Scale}; | ||
| 2 | |||
| 3 | /// Error for [Cordic](super::Cordic) | ||
| 4 | #[derive(Debug)] | ||
| 5 | pub 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")] | ||
| 15 | impl 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)] | ||
| 29 | pub struct ConfigError { | ||
| 30 | pub(super) func: Function, | ||
| 31 | pub(super) scale_range: [u8; 2], | ||
| 32 | } | ||
| 33 | |||
| 34 | #[cfg(feature = "defmt")] | ||
| 35 | impl 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)] | ||
| 54 | pub 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")] | ||
| 63 | impl 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)] | ||
| 92 | pub(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 | ||
| 3 | use embassy_hal_internal::drop::OnDrop; | 3 | use embassy_hal_internal::drop::OnDrop; |
| 4 | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; | 4 | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; |
| @@ -8,6 +8,9 @@ use crate::{dma, peripherals}; | |||
| 8 | mod enums; | 8 | mod enums; |
| 9 | pub use enums::*; | 9 | pub use enums::*; |
| 10 | 10 | ||
| 11 | mod errors; | ||
| 12 | pub use errors::*; | ||
| 13 | |||
| 11 | pub mod utils; | 14 | pub mod utils; |
| 12 | 15 | ||
| 13 | pub(crate) mod sealed; | 16 | pub(crate) mod sealed; |
| @@ -30,33 +33,55 @@ pub struct Cordic<'d, T: Instance> { | |||
| 30 | pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral {} | 33 | pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral {} |
| 31 | 34 | ||
| 32 | /// CORDIC configuration | 35 | /// CORDIC configuration |
| 36 | #[derive(Debug)] | ||
| 33 | pub struct Config { | 37 | pub 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 | ||
| 40 | impl Config { | 44 | impl 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 | ||
| 118 | impl<'d, T: Instance> Drop for Cordic<'d, T> { | 171 | impl<'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 |
| 125 | impl<'d, T: Instance> Cordic<'d, T> { | 178 | impl<'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 |
| 433 | impl<'d, T: Instance> Cordic<'d, T> { | 461 | impl<'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> { | |||
| 654 | macro_rules! check_input_value { | 655 | macro_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 | } |
