aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/cordic/enums.rs7
-rw-r--r--embassy-stm32/src/cordic/mod.rs262
2 files changed, 227 insertions, 42 deletions
diff --git a/embassy-stm32/src/cordic/enums.rs b/embassy-stm32/src/cordic/enums.rs
index 4697a1df1..3e1c47f7f 100644
--- a/embassy-stm32/src/cordic/enums.rs
+++ b/embassy-stm32/src/cordic/enums.rs
@@ -16,14 +16,15 @@ pub enum Function {
16 16
17/// CORDIC precision 17/// CORDIC precision
18#[allow(missing_docs)] 18#[allow(missing_docs)]
19#[derive(Clone, Copy)] 19#[derive(Clone, Copy, Default)]
20pub enum Precision { 20pub enum Precision {
21 Iters4 = 1, 21 Iters4 = 1,
22 Iters8, 22 Iters8,
23 Iters12, 23 Iters12,
24 Iters16, 24 Iters16,
25 Iters20, 25 Iters20,
26 Iters24, 26 #[default]
27 Iters24, // this value is recomended by Reference Manual
27 Iters28, 28 Iters28,
28 Iters32, 29 Iters32,
29 Iters36, 30 Iters36,
@@ -38,7 +39,7 @@ pub enum Precision {
38/// CORDIC scale 39/// CORDIC scale
39#[allow(non_camel_case_types)] 40#[allow(non_camel_case_types)]
40#[allow(missing_docs)] 41#[allow(missing_docs)]
41#[derive(Clone, Copy, Default)] 42#[derive(Clone, Copy, Default, PartialEq)]
42pub enum Scale { 43pub enum Scale {
43 #[default] 44 #[default]
44 A1_R1 = 0, 45 A1_R1 = 0,
diff --git a/embassy-stm32/src/cordic/mod.rs b/embassy-stm32/src/cordic/mod.rs
index c0a69b757..b15521ca6 100644
--- a/embassy-stm32/src/cordic/mod.rs
+++ b/embassy-stm32/src/cordic/mod.rs
@@ -10,6 +10,10 @@ pub mod utils;
10 10
11pub(crate) mod sealed; 11pub(crate) mod sealed;
12 12
13// length of pre-allocated [u32] memory for CORDIC input,
14// length should be multiple of 2
15const INPUT_BUF_LEN: usize = 8;
16
13/// Low-level CORDIC access. 17/// Low-level CORDIC access.
14#[cfg(feature = "unstable-pac")] 18#[cfg(feature = "unstable-pac")]
15pub mod low_level { 19pub mod low_level {
@@ -20,7 +24,7 @@ pub mod low_level {
20pub struct Cordic<'d, T: Instance> { 24pub struct Cordic<'d, T: Instance> {
21 cordic: PeripheralRef<'d, T>, 25 cordic: PeripheralRef<'d, T>,
22 config: Config, 26 config: Config,
23 //state: State, 27 state: State,
24} 28}
25 29
26/// CORDIC instance trait 30/// CORDIC instance trait
@@ -28,27 +32,33 @@ pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPer
28 32
29/// CORDIC configuration 33/// CORDIC configuration
30pub struct Config { 34pub struct Config {
35 mode: Mode,
31 function: Function, 36 function: Function,
32 precision: Precision, 37 precision: Precision,
33 scale: Scale, 38 scale: Scale,
34 mode: Mode,
35 first_result: bool, 39 first_result: bool,
36} 40}
37 41
38// CORDIC running state 42// CORDIC running state
39//struct State { 43struct State {
40// input_buf: [u32; 8], 44 input_buf: [u32; INPUT_BUF_LEN],
41// buf_len: usize, 45 buf_index: usize,
42//} 46}
43 47
44impl Config { 48impl Config {
45 /// Create a config for Cordic driver 49 /// Create a config for Cordic driver
46 pub fn new(function: Function, precision: Precision, scale: Option<Scale>, mode: Mode, first_result: bool) -> Self { 50 pub fn new(
51 mode: Mode,
52 function: Function,
53 precision: Option<Precision>,
54 scale: Option<Scale>,
55 first_result: bool,
56 ) -> Self {
47 Self { 57 Self {
58 mode,
48 function, 59 function,
49 precision, 60 precision: precision.unwrap_or_default(),
50 scale: scale.unwrap_or_default(), 61 scale: scale.unwrap_or_default(),
51 mode,
52 first_result, 62 first_result,
53 } 63 }
54 } 64 }
@@ -66,6 +76,7 @@ impl Config {
66 } 76 }
67} 77}
68 78
79// common method
69impl<'d, T: Instance> Cordic<'d, T> { 80impl<'d, T: Instance> Cordic<'d, T> {
70 /// Create a Cordic driver instance 81 /// Create a Cordic driver instance
71 /// 82 ///
@@ -84,10 +95,10 @@ impl<'d, T: Instance> Cordic<'d, T> {
84 let mut instance = Self { 95 let mut instance = Self {
85 cordic, 96 cordic,
86 config, 97 config,
87 // state: State { 98 state: State {
88 // input_buf: [0u32; 8], 99 input_buf: [0u32; 8],
89 // buf_len: 0, 100 buf_index: 0,
90 // }, 101 },
91 }; 102 };
92 103
93 instance.reconfigure(); 104 instance.reconfigure();
@@ -128,6 +139,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
128 peri.set_func(config.function); 139 peri.set_func(config.function);
129 peri.set_precision(config.precision); 140 peri.set_precision(config.precision);
130 peri.set_scale(config.scale); 141 peri.set_scale(config.scale);
142
131 if config.first_result { 143 if config.first_result {
132 peri.set_result_count(Count::One) 144 peri.set_result_count(Count::One)
133 } else { 145 } else {
@@ -145,55 +157,227 @@ impl<'d, T: Instance> Cordic<'d, T> {
145 } 157 }
146 } 158 }
147 159
148 //self.state.input_buf.fill(0u32); 160 self.state.input_buf.fill(0u32);
161 self.state.buf_index = 0;
162 }
163}
164
165impl<'d, T: Instance> Drop for Cordic<'d, T> {
166 fn drop(&mut self) {
167 T::disable();
149 } 168 }
169}
150 170
171// q1.31 related
172impl<'d, T: Instance> Cordic<'d, T> {
151 /// Run a CORDIC calculation 173 /// Run a CORDIC calculation
152 pub fn calc_32bit(&mut self, arg1s: &[f64], arg2s: Option<&[f64]>, output: &mut [f64]) -> usize { 174 pub fn calc_32bit(&mut self, arg1s: &[f64], arg2s: Option<&[f64]>, output: &mut [f64]) -> usize {
153 match self.config.mode { 175 let peri = &self.cordic;
176 let config = &self.config;
177
178 assert!(
179 match config.first_result {
180 true => output.len() >= arg1s.len(),
181 false => output.len() >= 2 * arg1s.len(),
182 },
183 "Output buf length is not long enough"
184 );
185
186 self.check_input_f64(arg1s, arg2s);
187
188 peri.set_result_count(if config.first_result { Count::One } else { Count::Two });
189 peri.set_data_width(Width::Bits32, Width::Bits32);
190
191 let state = &mut self.state;
192
193 let mut output_count = 0;
194
195 let mut consumed_input_len = 0;
196
197 match config.mode {
154 Mode::ZeroOverhead => { 198 Mode::ZeroOverhead => {
155 if arg2s.is_none() { 199 // put double input into cordic
156 self.cordic.set_argument_count(Count::One); 200 if arg2s.is_some() && !arg2s.unwrap().is_empty() {
201 let arg2s = arg2s.unwrap();
202
203 peri.set_argument_count(Count::Two);
204
205 let double_value = arg1s.iter().zip(arg2s);
206 consumed_input_len = double_value.len();
207
208 for (arg1, arg2) in double_value {
209 // if input_buf is full, send values to cordic
210 if state.buf_index == INPUT_BUF_LEN - 1 {
211 for arg in state.input_buf.chunks(2) {
212 peri.write_argument(arg[0]);
213 peri.write_argument(arg[1]);
157 214
158 self.cordic.set_result_count(if self.config.first_result { 215 output[output_count] = utils::q1_31_to_f64(peri.read_result());
159 if output.len() < arg1s.len() { 216 output_count += 1;
160 panic!("Output buf length is not long enough") 217
218 if !config.first_result {
219 output[output_count] = utils::q1_31_to_f64(peri.read_result());
220 output_count += 1;
221 }
222 }
223
224 state.buf_index = 0;
161 } 225 }
162 Count::One 226
163 } else { 227 for &&arg in [arg1, arg2].iter() {
164 if output.len() < 2 * arg1s.len() { 228 state.input_buf[state.buf_index] = utils::f64_to_q1_31(arg);
165 panic!("Output buf length is not long enough") 229 state.buf_index += 1;
166 } 230 }
167 Count::Two 231 }
168 }); 232
233 // put left paired args into cordic
234 if state.buf_index > 0 {
235 for arg in state.input_buf[..state.buf_index].chunks(2) {
236 peri.write_argument(arg[0]);
237 peri.write_argument(arg[1]);
169 238
170 let mut cnt = 0; 239 output[output_count] = utils::q1_31_to_f64(peri.read_result());
240 output_count += 1;
241
242 if !config.first_result {
243 output[output_count] = utils::q1_31_to_f64(peri.read_result());
244 output_count += 1;
245 }
246 }
171 247
172 for &arg in arg1s.iter() { 248 state.buf_index = 0;
173 self.cordic.write_argument(utils::f64_to_q1_31(arg));
174 output[cnt] = utils::q1_31_to_f64(self.cordic.read_result());
175 cnt += 1;
176 } 249 }
250 }
251
252 // put single input into cordic
253 let input_left = &arg1s[consumed_input_len..];
254
255 if !input_left.is_empty() {
256 peri.set_argument_count(Count::One);
257
258 for &arg in input_left.iter() {
259 peri.write_argument(utils::f64_to_q1_31(arg));
177 260
178 cnt 261 output[output_count] = utils::q1_31_to_f64(peri.read_result());
179 } else { 262 output_count += 1;
180 todo!() 263
264 if !config.first_result {
265 output[output_count] = utils::q1_31_to_f64(peri.read_result());
266 output_count += 1;
267 }
268 }
181 } 269 }
270
271 output_count
182 } 272 }
183 Mode::Interrupt => todo!(), 273 Mode::Interrupt => todo!(),
184 Mode::Dma => todo!(), 274 Mode::Dma => todo!(),
185 } 275 }
186 } 276 }
187}
188 277
189impl<'d, T: Instance> Drop for Cordic<'d, T> { 278 fn check_input_f64(&self, arg1s: &[f64], arg2s: Option<&[f64]>) {
190 fn drop(&mut self) { 279 let config = &self.config;
191 T::disable(); 280
281 use Function::*;
282
283 // check SCALE value
284 match config.function {
285 Cos | Sin | Phase | Modulus => assert!(Scale::A1_R1 == config.scale, "SCALE should be 0"),
286 Arctan => assert!(
287 (0..=7).contains(&(config.scale as u8)),
288 "SCALE should be: 0 <= SCALE <= 7"
289 ),
290 Cosh | Sinh | Arctanh => assert!(Scale::A1o2_R2 == config.scale, "SCALE should be 1"),
291
292 Ln => assert!(
293 (1..=4).contains(&(config.scale as u8)),
294 "SCALE should be: 1 <= SCALE <= 4"
295 ),
296 Sqrt => assert!(
297 (0..=2).contains(&(config.scale as u8)),
298 "SCALE should be: 0 <= SCALE <= 2"
299 ),
300 }
301
302 // check ARG1 value
303 match config.function {
304 Cos | Sin | Phase | Modulus | Arctan => {
305 assert!(
306 arg1s.iter().all(|v| (-1.0..=1.0).contains(v)),
307 "ARG1 should be: -1 <= ARG1 <= 1"
308 );
309 }
310
311 Cosh | Sinh => assert!(
312 arg1s.iter().all(|v| (-0.559..=0.559).contains(v)),
313 "ARG1 should be: -0.559 <= ARG1 <= 0.559"
314 ),
315
316 Arctanh => assert!(
317 arg1s.iter().all(|v| (-0.403..=0.403).contains(v)),
318 "ARG1 should be: -0.403 <= ARG1 <= 0.403"
319 ),
320
321 Ln => {
322 match config.scale {
323 Scale::A1o2_R2 => assert!(
324 arg1s.iter().all(|v| (0.05354..0.5).contains(v)),
325 "When SCALE set to 1, ARG1 should be: 0.05354 <= ARG1 < 0.5"
326 ),
327 Scale::A1o4_R4 => assert!(
328 arg1s.iter().all(|v| (0.25..0.75).contains(v)),
329 "When SCALE set to 2, ARG1 should be: 0.25 <= ARG1 < 0.75"
330 ),
331 Scale::A1o8_R8 => assert!(
332 arg1s.iter().all(|v| (0.375..0.875).contains(v)),
333 "When SCALE set to 3, ARG1 should be: 0.375 <= ARG1 < 0.875"
334 ),
335 Scale::A1o16_R16 => assert!(
336 arg1s.iter().all(|v| (0.4375f64..0.584f64).contains(v)),
337 "When SCALE set to 4, ARG1 should be: 0.4375 <= ARG1 < 0.584"
338 ),
339 _ => unreachable!(),
340 };
341 }
342
343 Function::Sqrt => match config.scale {
344 Scale::A1_R1 => assert!(
345 arg1s.iter().all(|v| (0.027..0.75).contains(v)),
346 "When SCALE set to 0, ARG1 should be: 0.027 <= ARG1 < 0.75"
347 ),
348 Scale::A1o2_R2 => assert!(
349 arg1s.iter().all(|v| (0.375..0.875).contains(v)),
350 "When SCALE set to 1, ARG1 should be: 0.375 <= ARG1 < 0.875"
351 ),
352 Scale::A1o4_R4 => assert!(
353 arg1s.iter().all(|v| (0.4375..0.585).contains(v)),
354 "When SCALE set to 2, ARG1 should be: 0.4375 <= ARG1 < 0.585"
355 ),
356 _ => unreachable!(),
357 },
358 }
359
360 // check ARG2 value
361 if let Some(arg2s) = arg2s {
362 match config.function {
363 Cos | Sin => assert!(
364 arg2s.iter().all(|v| (0.0..=1.0).contains(v)),
365 "ARG2 should be: 0 <= ARG2 <= 1"
366 ),
367
368 Phase | Modulus => assert!(
369 arg2s.iter().all(|v| (-1.0..=1.0).contains(v)),
370 "ARG2 should be: -1 <= ARG2 <= 1"
371 ),
372
373 _ => (),
374 }
375 }
192 } 376 }
193} 377}
194 378
195foreach_interrupt!( 379foreach_interrupt!(
196 ($inst:ident, cordic, CORDIC, GLOBAL, $irq:ident) => { 380 ($inst:ident, cordic, $block:ident, GLOBAL, $irq:ident) => {
197 impl Instance for peripherals::$inst { 381 impl Instance for peripherals::$inst {
198 } 382 }
199 383