aboutsummaryrefslogtreecommitdiff
path: root/tests/stm32/src/bin
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-04-04 21:32:27 +0000
committerGitHub <[email protected]>2024-04-04 21:32:27 +0000
commit6c35a1769d9bce27805ed6dcbb09d1306be6e452 (patch)
tree3fba5b2ae92677744f7da246ecd4bd96fa2d48f7 /tests/stm32/src/bin
parent067e422863674762c0ee20178f3671ce16a5986c (diff)
parent6b2e15e318c05a66f17575cde4987353a52108a4 (diff)
Merge pull request #2697 from eZioPan/stm32-cordic
stm32 CORDIC driver
Diffstat (limited to 'tests/stm32/src/bin')
-rw-r--r--tests/stm32/src/bin/cordic.rs135
1 files changed, 135 insertions, 0 deletions
diff --git a/tests/stm32/src/bin/cordic.rs b/tests/stm32/src/bin/cordic.rs
new file mode 100644
index 000000000..400e10207
--- /dev/null
+++ b/tests/stm32/src/bin/cordic.rs
@@ -0,0 +1,135 @@
1// required-features: rng, cordic
2
3// Test Cordic driver, with Q1.31 format, Sin function, at 24 iterations (aka PRECISION = 6), using DMA transfer
4
5#![no_std]
6#![no_main]
7
8#[path = "../common.rs"]
9mod common;
10use common::*;
11use embassy_executor::Spawner;
12use embassy_stm32::cordic::utils;
13use embassy_stm32::{bind_interrupts, cordic, peripherals, rng};
14use num_traits::Float;
15use {defmt_rtt as _, panic_probe as _};
16
17bind_interrupts!(struct Irqs {
18 RNG => rng::InterruptHandler<peripherals::RNG>;
19});
20
21/* input value control, can be changed */
22
23const INPUT_U32_COUNT: usize = 9;
24const INPUT_U8_COUNT: usize = 4 * INPUT_U32_COUNT;
25
26// Assume first calculation needs 2 arguments, the reset needs 1 argument.
27// And all calculation generate 2 results.
28const OUTPUT_LENGTH: usize = (INPUT_U32_COUNT - 1) * 2;
29
30#[embassy_executor::main]
31async fn main(_spawner: Spawner) {
32 let dp = embassy_stm32::init(config());
33
34 //
35 // use RNG generate random Q1.31 value
36 //
37 // we don't generate floating-point value, since not all binary value are valid floating-point value,
38 // and Q1.31 only accept a fixed range of value.
39
40 let mut rng = rng::Rng::new(dp.RNG, Irqs);
41
42 let mut input_buf_u8 = [0u8; INPUT_U8_COUNT];
43 defmt::unwrap!(rng.async_fill_bytes(&mut input_buf_u8).await);
44
45 // convert every [u8; 4] to a u32, for a Q1.31 value
46 let mut input_q1_31 = unsafe { core::mem::transmute::<[u8; INPUT_U8_COUNT], [u32; INPUT_U32_COUNT]>(input_buf_u8) };
47
48 // 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.
49 input_q1_31[1] &= !(1u32 << 31);
50
51 //
52 // CORDIC calculation
53 //
54
55 let mut output_q1_31 = [0u32; OUTPUT_LENGTH];
56
57 // setup Cordic driver
58 let mut cordic = cordic::Cordic::new(
59 dp.CORDIC,
60 defmt::unwrap!(cordic::Config::new(
61 cordic::Function::Sin,
62 Default::default(),
63 Default::default(),
64 )),
65 );
66
67 #[cfg(feature = "stm32g491re")]
68 let (mut write_dma, mut read_dma) = (dp.DMA1_CH4, dp.DMA1_CH5);
69
70 #[cfg(any(feature = "stm32h563zi", feature = "stm32u585ai", feature = "stm32u5a5zj"))]
71 let (mut write_dma, mut read_dma) = (dp.GPDMA1_CH0, dp.GPDMA1_CH1);
72
73 // calculate first result using blocking mode
74 let cnt0 = defmt::unwrap!(cordic.blocking_calc_32bit(&input_q1_31[..2], &mut output_q1_31, false, false));
75
76 // calculate rest results using async mode
77 let cnt1 = defmt::unwrap!(
78 cordic
79 .async_calc_32bit(
80 &mut write_dma,
81 &mut read_dma,
82 &input_q1_31[2..],
83 &mut output_q1_31[cnt0..],
84 true,
85 false,
86 )
87 .await
88 );
89
90 // all output value length should be the same as our output buffer size
91 defmt::assert_eq!(cnt0 + cnt1, output_q1_31.len());
92
93 let mut cordic_result_f64 = [0.0f64; OUTPUT_LENGTH];
94
95 for (f64_val, u32_val) in cordic_result_f64.iter_mut().zip(output_q1_31) {
96 *f64_val = utils::q1_31_to_f64(u32_val);
97 }
98
99 //
100 // software calculation
101 //
102
103 let mut software_result_f64 = [0.0f64; OUTPUT_LENGTH];
104
105 let arg2 = utils::q1_31_to_f64(input_q1_31[1]);
106
107 for (&arg1, res) in input_q1_31
108 .iter()
109 .enumerate()
110 .filter_map(|(idx, val)| if idx != 1 { Some(val) } else { None })
111 .zip(software_result_f64.chunks_mut(2))
112 {
113 let arg1 = utils::q1_31_to_f64(arg1);
114
115 let (raw_res1, raw_res2) = (arg1 * core::f64::consts::PI).sin_cos();
116 (res[0], res[1]) = (raw_res1 * arg2, raw_res2 * arg2);
117 }
118
119 //
120 // check result are the same
121 //
122
123 for (cordic_res, software_res) in cordic_result_f64[..cnt0 + cnt1]
124 .chunks(2)
125 .zip(software_result_f64.chunks(2))
126 {
127 for (cord_res, soft_res) in cordic_res.iter().zip(software_res.iter()) {
128 // 2.0.powi(-19) is the max residual error for Sin function, in q1.31 format, with 24 iterations (aka PRECISION = 6)
129 defmt::assert!((cord_res - soft_res).abs() <= 2.0.powi(-19));
130 }
131 }
132
133 info!("Test OK");
134 cortex_m::asm::bkpt();
135}