aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/build.rs4
-rw-r--r--embassy-stm32/src/cordic/mod.rs207
2 files changed, 199 insertions, 12 deletions
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 15bb8ea62..e224cc5a2 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -484,7 +484,7 @@ fn main() {
484 let expr = if let Some(mux) = self.chained_muxes.get(&v.name) { 484 let expr = if let Some(mux) = self.chained_muxes.get(&v.name) {
485 self.gen_mux(mux) 485 self.gen_mux(mux)
486 } else { 486 } else {
487 self.gen_clock(&v.name) 487 self.gen_clock(v.name)
488 }; 488 };
489 match_arms.extend(quote! { 489 match_arms.extend(quote! {
490 crate::pac::rcc::vals::#enum_name::#variant_name => #expr, 490 crate::pac::rcc::vals::#enum_name::#variant_name => #expr,
@@ -1139,6 +1139,8 @@ fn main() {
1139 (("timer", "CH2"), quote!(crate::timer::Ch2Dma)), 1139 (("timer", "CH2"), quote!(crate::timer::Ch2Dma)),
1140 (("timer", "CH3"), quote!(crate::timer::Ch3Dma)), 1140 (("timer", "CH3"), quote!(crate::timer::Ch3Dma)),
1141 (("timer", "CH4"), quote!(crate::timer::Ch4Dma)), 1141 (("timer", "CH4"), quote!(crate::timer::Ch4Dma)),
1142 (("cordic", "WRITE"), quote!(crate::cordic::WriteDma)),
1143 (("cordic", "READ"), quote!(crate::cordic::ReadDma)),
1142 ] 1144 ]
1143 .into(); 1145 .into();
1144 1146
diff --git a/embassy-stm32/src/cordic/mod.rs b/embassy-stm32/src/cordic/mod.rs
index 61277d7e1..9875d73bb 100644
--- a/embassy-stm32/src/cordic/mod.rs
+++ b/embassy-stm32/src/cordic/mod.rs
@@ -2,7 +2,7 @@
2 2
3use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 3use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
4 4
5use crate::peripherals; 5use crate::{dma, peripherals};
6 6
7mod enums; 7mod enums;
8pub use enums::*; 8pub use enums::*;
@@ -17,6 +17,8 @@ pub mod low_level {
17 pub use super::sealed::*; 17 pub use super::sealed::*;
18} 18}
19 19
20const INPUT_BUF_MAX_LEN: usize = 16;
21
20/// CORDIC driver 22/// CORDIC driver
21pub struct Cordic<'d, T: Instance> { 23pub struct Cordic<'d, T: Instance> {
22 peri: PeripheralRef<'d, T>, 24 peri: PeripheralRef<'d, T>,
@@ -98,7 +100,6 @@ impl<'d, T: Instance> Cordic<'d, T> {
98 warn!("At least 1 result hasn't been read, reconfigure will cause DATA LOST"); 100 warn!("At least 1 result hasn't been read, reconfigure will cause DATA LOST");
99 }; 101 };
100 102
101 self.peri.disable_irq();
102 self.peri.disable_write_dma(); 103 self.peri.disable_write_dma();
103 self.peri.disable_read_dma(); 104 self.peri.disable_read_dma();
104 105
@@ -111,11 +112,8 @@ impl<'d, T: Instance> Cordic<'d, T> {
111 self.peri.set_precision(self.config.precision); 112 self.peri.set_precision(self.config.precision);
112 self.peri.set_scale(self.config.scale); 113 self.peri.set_scale(self.config.scale);
113 114
114 if self.config.first_result { 115 // we don't set NRES in here, but to make sure NRES is set each time user call "calc"-ish functions,
115 self.peri.set_result_count(Count::One) 116 // since each "calc"-ish functions can have different ARGSIZE and RESSIZE, thus NRES should be change accrodingly.
116 } else {
117 self.peri.set_result_count(Count::Two)
118 }
119 } 117 }
120 118
121 fn blocking_read_f32(&mut self) -> (f32, Option<f32>) { 119 fn blocking_read_f32(&mut self) -> (f32, Option<f32>) {
@@ -143,7 +141,7 @@ impl<'d, T: Instance> Drop for Cordic<'d, T> {
143 141
144// q1.31 related 142// q1.31 related
145impl<'d, T: Instance> Cordic<'d, T> { 143impl<'d, T: Instance> Cordic<'d, T> {
146 /// Run a CORDIC calculation 144 /// Run a blocking CORDIC calculation
147 pub fn blocking_calc_32bit(&mut self, arg1s: &[f64], arg2s: Option<&[f64]>, output: &mut [f64]) -> usize { 145 pub fn blocking_calc_32bit(&mut self, arg1s: &[f64], arg2s: Option<&[f64]>, output: &mut [f64]) -> usize {
148 if arg1s.is_empty() { 146 if arg1s.is_empty() {
149 return 0; 147 return 0;
@@ -159,7 +157,6 @@ impl<'d, T: Instance> Cordic<'d, T> {
159 157
160 self.check_input_f64(arg1s, arg2s); 158 self.check_input_f64(arg1s, arg2s);
161 159
162 self.peri.disable_irq();
163 self.peri.disable_write_dma(); 160 self.peri.disable_write_dma();
164 self.peri.disable_read_dma(); 161 self.peri.disable_read_dma();
165 162
@@ -256,6 +253,192 @@ impl<'d, T: Instance> Cordic<'d, T> {
256 fn blocking_write_f64(&mut self, arg: f64) { 253 fn blocking_write_f64(&mut self, arg: f64) {
257 self.peri.write_argument(utils::f64_to_q1_31(arg)); 254 self.peri.write_argument(utils::f64_to_q1_31(arg));
258 } 255 }
256
257 /// Run a async CORDIC calculation
258 pub async fn async_calc_32bit(
259 &mut self,
260 write_dma: impl Peripheral<P = impl WriteDma<T>>,
261 read_dma: impl Peripheral<P = impl ReadDma<T>>,
262 arg1s: &[f64],
263 arg2s: Option<&[f64]>,
264 output: &mut [f64],
265 ) -> usize {
266 if arg1s.is_empty() {
267 return 0;
268 }
269
270 assert!(
271 match self.config.first_result {
272 true => output.len() >= arg1s.len(),
273 false => output.len() >= 2 * arg1s.len(),
274 },
275 "Output buf length is not long enough"
276 );
277
278 self.check_input_f64(arg1s, arg2s);
279
280 into_ref!(write_dma, read_dma);
281
282 self.peri.set_result_count(if self.config.first_result {
283 Count::One
284 } else {
285 Count::Two
286 });
287
288 self.peri.set_data_width(Width::Bits32, Width::Bits32);
289
290 let mut output_count = 0;
291 let mut consumed_input_len = 0;
292 let mut input_buf = [0u32; INPUT_BUF_MAX_LEN];
293 let mut input_buf_len = 0;
294
295 self.peri.enable_write_dma();
296 self.peri.enable_read_dma();
297
298 if !arg2s.unwrap_or_default().is_empty() {
299 let arg2s = arg2s.expect("It's infailable");
300
301 self.peri.set_argument_count(Count::Two);
302
303 let double_input = arg1s.iter().zip(arg2s);
304
305 consumed_input_len = double_input.len();
306
307 for (&arg1, &arg2) in double_input {
308 for &arg in [arg1, arg2].iter() {
309 input_buf[input_buf_len] = utils::f64_to_q1_31(arg);
310 input_buf_len += 1;
311 }
312
313 if input_buf_len == INPUT_BUF_MAX_LEN {
314 self.dma_calc_32bit(
315 &mut write_dma,
316 &mut read_dma,
317 true,
318 &input_buf[..input_buf_len],
319 output,
320 &mut output_count,
321 )
322 .await;
323
324 input_buf_len = 0;
325 }
326 }
327
328 if input_buf_len % 2 != 0 {
329 panic!("input buf len should be multiple of 2 in double mode")
330 }
331
332 if input_buf_len > 0 {
333 self.dma_calc_32bit(
334 &mut write_dma,
335 &mut read_dma,
336 true,
337 &input_buf[..input_buf_len],
338 output,
339 &mut output_count,
340 )
341 .await;
342
343 input_buf_len = 0;
344 }
345 }
346
347 // single input
348
349 if arg1s.len() > consumed_input_len {
350 let input_remain = &arg1s[consumed_input_len..];
351
352 self.peri.set_argument_count(Count::One);
353
354 for &arg in input_remain {
355 input_buf[input_buf_len] = utils::f64_to_q1_31(arg);
356 input_buf_len += 1;
357
358 if input_buf_len == INPUT_BUF_MAX_LEN {
359 self.dma_calc_32bit(
360 &mut write_dma,
361 &mut read_dma,
362 false,
363 &input_buf[..input_buf_len],
364 output,
365 &mut output_count,
366 )
367 .await;
368
369 input_buf_len = 0;
370 }
371 }
372
373 if input_buf_len > 0 {
374 self.dma_calc_32bit(
375 &mut write_dma,
376 &mut read_dma,
377 false,
378 &input_buf[..input_buf_len],
379 output,
380 &mut output_count,
381 )
382 .await;
383
384 // input_buf_len = 0;
385 }
386 }
387
388 output_count
389 }
390
391 async fn dma_calc_32bit(
392 &mut self,
393 write_dma: impl Peripheral<P = impl WriteDma<T>>,
394 read_dma: impl Peripheral<P = impl ReadDma<T>>,
395 double_input: bool,
396 input_buf: &[u32],
397 output: &mut [f64],
398 output_start_index: &mut usize,
399 ) {
400 into_ref!(write_dma, read_dma);
401
402 let write_req = write_dma.request();
403 let read_req = read_dma.request();
404
405 let mut output_buf = [0u32; INPUT_BUF_MAX_LEN * 2]; // make output_buf long enough
406
407 let mut output_buf_size = input_buf.len();
408 if !self.config.first_result {
409 output_buf_size *= 2;
410 };
411 if double_input {
412 output_buf_size /= 2;
413 }
414
415 let active_output_buf = &mut output_buf[..output_buf_size];
416
417 unsafe {
418 let write_transfer = dma::Transfer::new_write(
419 &mut write_dma,
420 write_req,
421 input_buf,
422 T::regs().wdata().as_ptr() as *mut _,
423 Default::default(),
424 );
425
426 let read_transfer = dma::Transfer::new_read(
427 &mut read_dma,
428 read_req,
429 T::regs().rdata().as_ptr() as *mut _,
430 active_output_buf,
431 Default::default(),
432 );
433
434 embassy_futures::join::join(write_transfer, read_transfer).await;
435 }
436
437 for &mut output_u32 in active_output_buf {
438 output[*output_start_index] = utils::q1_31_to_f64(output_u32);
439 *output_start_index += 1;
440 }
441 }
259} 442}
260 443
261// q1.15 related 444// q1.15 related
@@ -276,7 +459,6 @@ impl<'d, T: Instance> Cordic<'d, T> {
276 459
277 self.check_input_f32(arg1s, arg2s); 460 self.check_input_f32(arg1s, arg2s);
278 461
279 self.peri.disable_irq();
280 self.peri.disable_write_dma(); 462 self.peri.disable_write_dma();
281 self.peri.disable_read_dma(); 463 self.peri.disable_read_dma();
282 464
@@ -409,7 +591,7 @@ macro_rules! check_input_value {
409 }; 591 };
410 } 592 }
411 593
412 Function::Sqrt => match config.scale { 594 Sqrt => match config.scale {
413 Scale::A1_R1 => assert!( 595 Scale::A1_R1 => assert!(
414 arg1s.iter().all(|v| (0.027..0.75).contains(v)), 596 arg1s.iter().all(|v| (0.027..0.75).contains(v)),
415 "When SCALE set to 0, ARG1 should be: 0.027 <= ARG1 < 0.75" 597 "When SCALE set to 0, ARG1 should be: 0.027 <= ARG1 < 0.75"
@@ -462,3 +644,6 @@ foreach_interrupt!(
462 } 644 }
463 }; 645 };
464); 646);
647
648dma_trait!(WriteDma, Instance);
649dma_trait!(ReadDma, Instance);