aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/cordic/mod.rs180
1 files changed, 85 insertions, 95 deletions
diff --git a/embassy-stm32/src/cordic/mod.rs b/embassy-stm32/src/cordic/mod.rs
index b15521ca6..997ace113 100644
--- a/embassy-stm32/src/cordic/mod.rs
+++ b/embassy-stm32/src/cordic/mod.rs
@@ -22,9 +22,8 @@ pub mod low_level {
22 22
23/// CORDIC driver 23/// CORDIC driver
24pub struct Cordic<'d, T: Instance> { 24pub struct Cordic<'d, T: Instance> {
25 cordic: PeripheralRef<'d, T>, 25 peri: PeripheralRef<'d, T>,
26 config: Config, 26 config: Config,
27 state: State,
28} 27}
29 28
30/// CORDIC instance trait 29/// CORDIC instance trait
@@ -83,23 +82,16 @@ impl<'d, T: Instance> Cordic<'d, T> {
83 /// Note: 82 /// Note:
84 /// If you need a periperhal -> CORDIC -> peripehral mode, 83 /// If you need a periperhal -> CORDIC -> peripehral mode,
85 /// you may want to set Cordic into [Mode::ZeroOverhead] mode, and add extra arguemnts with [Self::extra_config] 84 /// you may want to set Cordic into [Mode::ZeroOverhead] mode, and add extra arguemnts with [Self::extra_config]
86 pub fn new(cordic: impl Peripheral<P = T> + 'd, config: Config) -> Self { 85 pub fn new(peri: impl Peripheral<P = T> + 'd, config: Config) -> Self {
87 T::enable_and_reset(); 86 T::enable_and_reset();
88 87
89 into_ref!(cordic); 88 into_ref!(peri);
90 89
91 if !config.check_scale() { 90 if !config.check_scale() {
92 panic!("Scale value is not compatible with Function") 91 panic!("Scale value is not compatible with Function")
93 } 92 }
94 93
95 let mut instance = Self { 94 let mut instance = Self { peri, config };
96 cordic,
97 config,
98 state: State {
99 input_buf: [0u32; 8],
100 buf_index: 0,
101 },
102 };
103 95
104 instance.reconfigure(); 96 instance.reconfigure();
105 97
@@ -114,51 +106,71 @@ impl<'d, T: Instance> Cordic<'d, T> {
114 106
115 /// Set extra config for data count and data width. 107 /// Set extra config for data count and data width.
116 pub fn extra_config(&mut self, arg_cnt: Count, arg_width: Width, res_width: Width) { 108 pub fn extra_config(&mut self, arg_cnt: Count, arg_width: Width, res_width: Width) {
117 let peri = &self.cordic; 109 self.peri.set_argument_count(arg_cnt);
118 peri.set_argument_count(arg_cnt); 110 self.peri.set_data_width(arg_width, res_width);
119 peri.set_data_width(arg_width, res_width);
120 } 111 }
121 112
122 fn reconfigure(&mut self) { 113 fn reconfigure(&mut self) {
123 let peri = &self.cordic; 114 if self.peri.ready_to_read() {
124 let config = &self.config;
125
126 if peri.ready_to_read() {
127 warn!("At least 1 result hasn't been read, reconfigure will cause DATA LOST"); 115 warn!("At least 1 result hasn't been read, reconfigure will cause DATA LOST");
128 }; 116 };
129 117
130 peri.disable_irq(); 118 self.peri.disable_irq();
131 peri.disable_write_dma(); 119 self.peri.disable_write_dma();
132 peri.disable_read_dma(); 120 self.peri.disable_read_dma();
133 121
134 // clean RRDY flag 122 // clean RRDY flag
135 while peri.ready_to_read() { 123 while self.peri.ready_to_read() {
136 peri.read_result(); 124 self.peri.read_result();
137 } 125 }
138 126
139 peri.set_func(config.function); 127 self.peri.set_func(self.config.function);
140 peri.set_precision(config.precision); 128 self.peri.set_precision(self.config.precision);
141 peri.set_scale(config.scale); 129 self.peri.set_scale(self.config.scale);
142 130
143 if config.first_result { 131 if self.config.first_result {
144 peri.set_result_count(Count::One) 132 self.peri.set_result_count(Count::One)
145 } else { 133 } else {
146 peri.set_result_count(Count::Two) 134 self.peri.set_result_count(Count::Two)
147 } 135 }
148 136
149 match config.mode { 137 match self.config.mode {
150 Mode::ZeroOverhead => (), 138 Mode::ZeroOverhead => (),
151 Mode::Interrupt => { 139 Mode::Interrupt => {
152 peri.enable_irq(); 140 self.peri.enable_irq();
153 } 141 }
154 Mode::Dma => { 142 Mode::Dma => {
155 peri.enable_write_dma(); 143 self.peri.enable_write_dma();
156 peri.enable_read_dma(); 144 self.peri.enable_read_dma();
157 } 145 }
158 } 146 }
147 }
148
149 fn blocking_read_f64(&mut self) -> (f64, Option<f64>) {
150 let res1 = utils::q1_31_to_f64(self.peri.read_result());
151
152 let res2 = if !self.config.first_result {
153 Some(utils::q1_31_to_f64(self.peri.read_result()))
154 } else {
155 None
156 };
157
158 (res1, res2)
159 }
160
161 fn blocking_read_f64_to_buf(&mut self, result_buf: &mut [f64], result_index: &mut usize) {
162 let (res1, res2) = self.blocking_read_f64();
163 result_buf[*result_index] = res1;
164 *result_index += 1;
165
166 if let Some(res2) = res2 {
167 result_buf[*result_index] = res2;
168 *result_index += 1;
169 }
170 }
159 171
160 self.state.input_buf.fill(0u32); 172 fn blocking_write_f64(&mut self, arg: f64) {
161 self.state.buf_index = 0; 173 self.peri.write_argument(utils::f64_to_q1_31(arg));
162 } 174 }
163} 175}
164 176
@@ -172,11 +184,8 @@ impl<'d, T: Instance> Drop for Cordic<'d, T> {
172impl<'d, T: Instance> Cordic<'d, T> { 184impl<'d, T: Instance> Cordic<'d, T> {
173 /// Run a CORDIC calculation 185 /// Run a CORDIC calculation
174 pub fn calc_32bit(&mut self, arg1s: &[f64], arg2s: Option<&[f64]>, output: &mut [f64]) -> usize { 186 pub fn calc_32bit(&mut self, arg1s: &[f64], arg2s: Option<&[f64]>, output: &mut [f64]) -> usize {
175 let peri = &self.cordic;
176 let config = &self.config;
177
178 assert!( 187 assert!(
179 match config.first_result { 188 match self.config.first_result {
180 true => output.len() >= arg1s.len(), 189 true => output.len() >= arg1s.len(),
181 false => output.len() >= 2 * arg1s.len(), 190 false => output.len() >= 2 * arg1s.len(),
182 }, 191 },
@@ -185,87 +194,68 @@ impl<'d, T: Instance> Cordic<'d, T> {
185 194
186 self.check_input_f64(arg1s, arg2s); 195 self.check_input_f64(arg1s, arg2s);
187 196
188 peri.set_result_count(if config.first_result { Count::One } else { Count::Two }); 197 self.peri.set_result_count(if self.config.first_result {
189 peri.set_data_width(Width::Bits32, Width::Bits32); 198 Count::One
199 } else {
200 Count::Two
201 });
190 202
191 let state = &mut self.state; 203 self.peri.set_data_width(Width::Bits32, Width::Bits32);
192 204
193 let mut output_count = 0; 205 let mut output_count = 0;
194 206
195 let mut consumed_input_len = 0; 207 let mut consumed_input_len = 0;
196 208
197 match config.mode { 209 match self.config.mode {
198 Mode::ZeroOverhead => { 210 Mode::ZeroOverhead => {
199 // put double input into cordic 211 // put double input into cordic
200 if arg2s.is_some() && !arg2s.unwrap().is_empty() { 212 if arg2s.is_some() && !arg2s.unwrap().is_empty() {
201 let arg2s = arg2s.unwrap(); 213 let arg2s = arg2s.unwrap();
202 214
203 peri.set_argument_count(Count::Two); 215 self.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]);
214 216
215 output[output_count] = utils::q1_31_to_f64(peri.read_result()); 217 // Skip 1st value from arg1s, this value will be manually "preload" to cordic, to make use of cordic preload function.
216 output_count += 1; 218 // And we preserve last value from arg2s, since it need to manually write to cordic, and read the result out.
219 let double_input = arg1s.iter().skip(1).zip(&arg2s[..arg2s.len() - 1]);
220 // Since we preload 1st value from arg1s, the consumed input length is double_input length + 1.
221 consumed_input_len = double_input.len() + 1;
217 222
218 if !config.first_result { 223 // preload first value from arg1 to cordic
219 output[output_count] = utils::q1_31_to_f64(peri.read_result()); 224 self.blocking_write_f64(arg1s[0]);
220 output_count += 1;
221 }
222 }
223 225
224 state.buf_index = 0; 226 for (&arg1, &arg2) in double_input {
225 } 227 // Since we manually preload a value before,
228 // we will write arg2 (from the actual last pair) first, (at this moment, cordic start to calculating,)
229 // and write arg1 (from the actual next pair), then read the result, to "keep preloading"
226 230
227 for &&arg in [arg1, arg2].iter() { 231 self.blocking_write_f64(arg2);
228 state.input_buf[state.buf_index] = utils::f64_to_q1_31(arg); 232 self.blocking_write_f64(arg1);
229 state.buf_index += 1; 233 self.blocking_read_f64_to_buf(output, &mut output_count);
230 }
231 } 234 }
232 235
233 // put left paired args into cordic 236 // write last input value from arg2s, then read out the result
234 if state.buf_index > 0 { 237 self.blocking_write_f64(arg2s[arg2s.len() - 1]);
235 for arg in state.input_buf[..state.buf_index].chunks(2) { 238 self.blocking_read_f64_to_buf(output, &mut output_count);
236 peri.write_argument(arg[0]);
237 peri.write_argument(arg[1]);
238
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 }
247
248 state.buf_index = 0;
249 }
250 } 239 }
251 240
252 // put single input into cordic 241 // put single input into cordic
253 let input_left = &arg1s[consumed_input_len..]; 242 let input_left = &arg1s[consumed_input_len..];
254 243
255 if !input_left.is_empty() { 244 if !input_left.is_empty() {
256 peri.set_argument_count(Count::One); 245 self.peri.set_argument_count(Count::One);
257
258 for &arg in input_left.iter() {
259 peri.write_argument(utils::f64_to_q1_31(arg));
260 246
261 output[output_count] = utils::q1_31_to_f64(peri.read_result()); 247 // "preload" value to cordic (at this moment, cordic start to calculating)
262 output_count += 1; 248 self.blocking_write_f64(input_left[0]);
263 249
264 if !config.first_result { 250 for &arg in input_left.iter().skip(1) {
265 output[output_count] = utils::q1_31_to_f64(peri.read_result()); 251 // this line write arg for next round caculation to cordic,
266 output_count += 1; 252 // and read result from last round
267 } 253 self.blocking_write_f64(arg);
254 self.blocking_read_f64_to_buf(output, &mut output_count);
268 } 255 }
256
257 // read the last output
258 self.blocking_read_f64_to_buf(output, &mut output_count);
269 } 259 }
270 260
271 output_count 261 output_count