aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authoreZio Pan <[email protected]>2024-03-22 17:29:10 +0800
committereZio Pan <[email protected]>2024-03-23 09:15:25 +0800
commit0abcccee966af0b12e62fc7fae8499fa03194823 (patch)
treeb0cf28261ee18b1bd111de61d93ef5cbddc5f29e /tests
parent83069e7b49bd181236e6a68005ad6119d39b39c3 (diff)
stm32 CORDIC: re-design API
Diffstat (limited to 'tests')
-rw-r--r--tests/stm32/src/bin/cordic.rs110
1 files changed, 48 insertions, 62 deletions
diff --git a/tests/stm32/src/bin/cordic.rs b/tests/stm32/src/bin/cordic.rs
index cd2e9d6f7..669fd96ab 100644
--- a/tests/stm32/src/bin/cordic.rs
+++ b/tests/stm32/src/bin/cordic.rs
@@ -14,6 +14,7 @@
14mod common; 14mod common;
15use common::*; 15use common::*;
16use embassy_executor::Spawner; 16use embassy_executor::Spawner;
17use embassy_stm32::cordic::utils;
17use embassy_stm32::{bind_interrupts, cordic, peripherals, rng}; 18use embassy_stm32::{bind_interrupts, cordic, peripherals, rng};
18use num_traits::Float; 19use num_traits::Float;
19use {defmt_rtt as _, panic_probe as _}; 20use {defmt_rtt as _, panic_probe as _};
@@ -24,11 +25,12 @@ bind_interrupts!(struct Irqs {
24 25
25/* input value control, can be changed */ 26/* input value control, can be changed */
26 27
27const ARG1_LENGTH: usize = 9; 28const INPUT_U32_COUNT: usize = 9;
28const ARG2_LENGTH: usize = 4; // this might not be the exact length of ARG2, since ARG2 need to be inside [0, 1] 29const INPUT_U8_COUNT: usize = 4 * INPUT_U32_COUNT;
29 30
30const INPUT_Q1_31_LENGTH: usize = ARG1_LENGTH + ARG2_LENGTH; 31// Assume first calculation needs 2 arguments, the reset needs 1 argument.
31const INPUT_U8_LENGTH: usize = 4 * INPUT_Q1_31_LENGTH; 32// And all calculation generate 2 results.
33const OUTPUT_LENGTH: usize = (INPUT_U32_COUNT - 1) * 2;
32 34
33#[embassy_executor::main] 35#[embassy_executor::main]
34async fn main(_spawner: Spawner) { 36async fn main(_spawner: Spawner) {
@@ -42,43 +44,28 @@ async fn main(_spawner: Spawner) {
42 44
43 let mut rng = rng::Rng::new(dp.RNG, Irqs); 45 let mut rng = rng::Rng::new(dp.RNG, Irqs);
44 46
45 let mut input_buf_u8 = [0u8; INPUT_U8_LENGTH]; 47 let mut input_buf_u8 = [0u8; INPUT_U8_COUNT];
46 defmt::unwrap!(rng.async_fill_bytes(&mut input_buf_u8).await); 48 defmt::unwrap!(rng.async_fill_bytes(&mut input_buf_u8).await);
47 49
48 // convert every [u8; 4] to a u32, for a Q1.31 value 50 // convert every [u8; 4] to a u32, for a Q1.31 value
49 let input_q1_31 = unsafe { core::mem::transmute::<[u8; INPUT_U8_LENGTH], [u32; INPUT_Q1_31_LENGTH]>(input_buf_u8) }; 51 let mut input_q1_31 = unsafe { core::mem::transmute::<[u8; INPUT_U8_COUNT], [u32; INPUT_U32_COUNT]>(input_buf_u8) };
50 52
51 let mut input_f64_buf = [0f64; INPUT_Q1_31_LENGTH]; 53 // ARG2 for Sin function should be inside [0, 1], set MSB to 0 of a Q1.31 value, will make sure it's no less than 0.
54 input_q1_31[1] &= !(1u32 << 31);
52 55
53 let mut cordic_output_f64_buf = [0f64; ARG1_LENGTH * 2]; 56 //
54 57 // CORDIC calculation
55 // convert Q1.31 value back to f64, for software calculation verify 58 //
56 for (val_u32, val_f64) in input_q1_31.iter().zip(input_f64_buf.iter_mut()) {
57 *val_f64 = cordic::utils::q1_31_to_f64(*val_u32);
58 }
59
60 let mut arg2_f64_buf = [0f64; ARG2_LENGTH];
61 let mut arg2_f64_len = 0;
62
63 // check if ARG2 is in range [0, 1] (limited by CORDIC peripheral with Sin mode)
64 for &arg2 in &input_f64_buf[ARG1_LENGTH..] {
65 if arg2 >= 0.0 {
66 arg2_f64_buf[arg2_f64_len] = arg2;
67 arg2_f64_len += 1;
68 }
69 }
70 59
71 // the actual value feed to CORDIC 60 let mut output_q1_31 = [0u32; OUTPUT_LENGTH];
72 let arg1_f64_ls = &input_f64_buf[..ARG1_LENGTH];
73 let arg2_f64_ls = &arg2_f64_buf[..arg2_f64_len];
74 61
62 // setup Cordic driver
75 let mut cordic = cordic::Cordic::new( 63 let mut cordic = cordic::Cordic::new(
76 dp.CORDIC, 64 dp.CORDIC,
77 defmt::unwrap!(cordic::Config::new( 65 defmt::unwrap!(cordic::Config::new(
78 cordic::Function::Sin, 66 cordic::Function::Sin,
79 Default::default(), 67 Default::default(),
80 Default::default(), 68 Default::default(),
81 false,
82 )), 69 )),
83 ); 70 );
84 71
@@ -88,67 +75,66 @@ async fn main(_spawner: Spawner) {
88 #[cfg(any(feature = "stm32h563zi", feature = "stm32u585ai", feature = "stm32u5a5zj"))] 75 #[cfg(any(feature = "stm32h563zi", feature = "stm32u585ai", feature = "stm32u5a5zj"))]
89 let (mut write_dma, mut read_dma) = (dp.GPDMA1_CH4, dp.GPDMA1_CH5); 76 let (mut write_dma, mut read_dma) = (dp.GPDMA1_CH4, dp.GPDMA1_CH5);
90 77
91 let cordic_start_point = embassy_time::Instant::now(); 78 // calculate first result using blocking mode
79 let cnt0 = defmt::unwrap!(cordic.blocking_calc_32bit(&input_q1_31[..2], &mut output_q1_31, false, false));
92 80
93 let cnt = unwrap!( 81 // calculate rest results using async mode
82 let cnt1 = defmt::unwrap!(
94 cordic 83 cordic
95 .async_calc_32bit( 84 .async_calc_32bit(
96 &mut write_dma, 85 &mut write_dma,
97 &mut read_dma, 86 &mut read_dma,
98 arg1_f64_ls, 87 &input_q1_31[2..],
99 Some(arg2_f64_ls), 88 &mut output_q1_31[cnt0..],
100 &mut cordic_output_f64_buf, 89 true,
90 false,
101 ) 91 )
102 .await 92 .await
103 ); 93 );
104 94
105 let cordic_end_point = embassy_time::Instant::now(); 95 // all output value length should be the same as our output buffer size
96 defmt::assert_eq!(cnt0 + cnt1, output_q1_31.len());
97
98 let mut cordic_result_f64 = [0.0f64; OUTPUT_LENGTH];
99
100 for (f64_val, u32_val) in cordic_result_f64.iter_mut().zip(output_q1_31) {
101 *f64_val = utils::q1_31_to_f64(u32_val);
102 }
106 103
107 // since we get 2 output for 1 calculation, the output length should be ARG1_LENGTH * 2 104 //
108 defmt::assert!(cnt == ARG1_LENGTH * 2); 105 // software calculation
106 //
109 107
110 let mut software_output_f64_buf = [0f64; ARG1_LENGTH * 2]; 108 let mut software_result_f64 = [0.0f64; OUTPUT_LENGTH];
111 109
112 // for software calc, if there is no ARG2 value, insert a 1.0 as value (the reset value for ARG2 in CORDIC) 110 let arg2 = utils::q1_31_to_f64(input_q1_31[1]);
113 let arg2_f64_ls = if arg2_f64_len == 0 { &[1.0] } else { arg2_f64_ls };
114 111
115 let software_inputs = arg1_f64_ls 112 for (&arg1, res) in input_q1_31
116 .iter() 113 .iter()
117 .zip( 114 .enumerate()
118 arg2_f64_ls 115 .filter_map(|(idx, val)| if idx != 1 { Some(val) } else { None })
119 .iter() 116 .zip(software_result_f64.chunks_mut(2))
120 .chain(core::iter::repeat(&arg2_f64_ls[arg2_f64_ls.len() - 1])), 117 {
121 ) 118 let arg1 = utils::q1_31_to_f64(arg1);
122 .zip(software_output_f64_buf.chunks_mut(2));
123
124 let software_start_point = embassy_time::Instant::now();
125 119
126 for ((arg1, arg2), res) in software_inputs {
127 let (raw_res1, raw_res2) = (arg1 * core::f64::consts::PI).sin_cos(); 120 let (raw_res1, raw_res2) = (arg1 * core::f64::consts::PI).sin_cos();
128
129 (res[0], res[1]) = (raw_res1 * arg2, raw_res2 * arg2); 121 (res[0], res[1]) = (raw_res1 * arg2, raw_res2 * arg2);
130 } 122 }
131 123
132 let software_end_point = embassy_time::Instant::now(); 124 //
125 // check result are the same
126 //
133 127
134 for (cordic_res, software_res) in cordic_output_f64_buf[..cnt] 128 for (cordic_res, software_res) in cordic_result_f64[..cnt0 + cnt1]
135 .chunks(2) 129 .chunks(2)
136 .zip(software_output_f64_buf.chunks(2)) 130 .zip(software_result_f64.chunks(2))
137 { 131 {
138 for (cord_res, soft_res) in cordic_res.iter().zip(software_res.iter()) { 132 for (cord_res, soft_res) in cordic_res.iter().zip(software_res.iter()) {
133 // 2.0.powi(-19) is the max residual error for Sin function, in q1.31 format, with 24 iterations (aka PRECISION = 6)
139 defmt::assert!((cord_res - soft_res).abs() <= 2.0.powi(-19)); 134 defmt::assert!((cord_res - soft_res).abs() <= 2.0.powi(-19));
140 } 135 }
141 } 136 }
142 137
143 // This comparison is just for fun. Since it not a equal compare:
144 // software use 64-bit floating point, but CORDIC use 32-bit fixed point.
145 defmt::trace!(
146 "calculate count: {}, Cordic time: {} us, software time: {} us",
147 ARG1_LENGTH,
148 (cordic_end_point - cordic_start_point).as_micros(),
149 (software_end_point - software_start_point).as_micros()
150 );
151
152 info!("Test OK"); 138 info!("Test OK");
153 cortex_m::asm::bkpt(); 139 cortex_m::asm::bkpt();
154} 140}