diff options
| author | eZio Pan <[email protected]> | 2024-03-18 23:09:18 +0800 |
|---|---|---|
| committer | eZio Pan <[email protected]> | 2024-03-23 09:15:25 +0800 |
| commit | 2fa04d93ed93bed97c7575019aea32c2543e322c (patch) | |
| tree | 3fcefb362cd688abb93325bac3318ca055666e99 | |
| parent | c9f759bb21782eb0487c96a59500310d1283694c (diff) | |
stm32 CORDIC: DMA for q1.31
| -rw-r--r-- | embassy-stm32/build.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/cordic/mod.rs | 207 |
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 | ||
| 3 | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; | 3 | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; |
| 4 | 4 | ||
| 5 | use crate::peripherals; | 5 | use crate::{dma, peripherals}; |
| 6 | 6 | ||
| 7 | mod enums; | 7 | mod enums; |
| 8 | pub use enums::*; | 8 | pub use enums::*; |
| @@ -17,6 +17,8 @@ pub mod low_level { | |||
| 17 | pub use super::sealed::*; | 17 | pub use super::sealed::*; |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | const INPUT_BUF_MAX_LEN: usize = 16; | ||
| 21 | |||
| 20 | /// CORDIC driver | 22 | /// CORDIC driver |
| 21 | pub struct Cordic<'d, T: Instance> { | 23 | pub 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 |
| 145 | impl<'d, T: Instance> Cordic<'d, T> { | 143 | impl<'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 | |||
| 648 | dma_trait!(WriteDma, Instance); | ||
| 649 | dma_trait!(ReadDma, Instance); | ||
