diff options
| author | Dario Nieuwenhuis <[email protected]> | 2025-09-05 14:13:10 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-09-05 14:13:10 +0000 |
| commit | 1c2fa92293e52157582b92766e75381a228bbaf1 (patch) | |
| tree | 77b065f52abf07298b5f4ed5feaa97ebfb3c345b | |
| parent | 581594d1f5b403363a109e41b5d354f9364b4724 (diff) | |
| parent | 683ca6595ff7f4c6f0e70e90d3cdeab13d0b1c07 (diff) | |
Merge pull request #4620 from embassy-rs/lolsai
stm32: add i2s support for all versions, cleanup spi/i2s/sai versions.
| -rw-r--r-- | embassy-stm32/CHANGELOG.md | 1 | ||||
| -rw-r--r-- | embassy-stm32/Cargo.toml | 8 | ||||
| -rw-r--r-- | embassy-stm32/build.rs | 29 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/mod.rs | 68 | ||||
| -rw-r--r-- | embassy-stm32/src/i2s.rs | 183 | ||||
| -rw-r--r-- | embassy-stm32/src/lib.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/sai/mod.rs | 328 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/mod.rs | 134 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/sai.rs | 72 | ||||
| -rw-r--r-- | examples/stm32h723/src/bin/spdifrx.rs | 2 |
10 files changed, 269 insertions, 558 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index fe2fb64f2..50bdc1072 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md | |||
| @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 12 | - feat: Derive Clone, Copy for QSPI Config | 12 | - feat: Derive Clone, Copy for QSPI Config |
| 13 | - fix: stm32/i2c in master mode (blocking): subsequent transmissions failed after a NACK was received | 13 | - fix: stm32/i2c in master mode (blocking): subsequent transmissions failed after a NACK was received |
| 14 | - feat: stm32/timer: add set_polarity functions for main and complementary outputs in complementary_pwm | 14 | - feat: stm32/timer: add set_polarity functions for main and complementary outputs in complementary_pwm |
| 15 | - Add I2S support for STM32F1, STM32C0, STM32F0, STM32F3, STM32F7, STM32G0, STM32WL, STM32H5, STM32H7RS | ||
| 15 | 16 | ||
| 16 | ## 0.4.0 - 2025-08-26 | 17 | ## 0.4.0 - 2025-08-26 |
| 17 | 18 | ||
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index cdb4e07d1..9c2ba1f53 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -173,8 +173,8 @@ cortex-m = "0.7.6" | |||
| 173 | futures-util = { version = "0.3.30", default-features = false } | 173 | futures-util = { version = "0.3.30", default-features = false } |
| 174 | sdio-host = "0.9.0" | 174 | sdio-host = "0.9.0" |
| 175 | critical-section = "1.1" | 175 | critical-section = "1.1" |
| 176 | stm32-metapac = { version = "18" } | 176 | #stm32-metapac = { version = "18" } |
| 177 | #stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ecb93d42a6cbcd9e09cab74873908a2ca22327f7" } | 177 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d8432edd0406495adec19d31923584e80b8e03cb" } |
| 178 | 178 | ||
| 179 | vcell = "0.1.3" | 179 | vcell = "0.1.3" |
| 180 | nb = "1.0.0" | 180 | nb = "1.0.0" |
| @@ -202,8 +202,8 @@ proptest-state-machine = "0.3.0" | |||
| 202 | proc-macro2 = "1.0.36" | 202 | proc-macro2 = "1.0.36" |
| 203 | quote = "1.0.15" | 203 | quote = "1.0.15" |
| 204 | 204 | ||
| 205 | stm32-metapac = { version = "18", default-features = false, features = ["metadata"]} | 205 | #stm32-metapac = { version = "18", default-features = false, features = ["metadata"]} |
| 206 | #stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ecb93d42a6cbcd9e09cab74873908a2ca22327f7", default-features = false, features = ["metadata"] } | 206 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d8432edd0406495adec19d31923584e80b8e03cb", default-features = false, features = ["metadata"] } |
| 207 | 207 | ||
| 208 | [features] | 208 | [features] |
| 209 | default = ["rt"] | 209 | default = ["rt"] |
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index deefb13c1..b731012c6 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -16,6 +16,27 @@ use stm32_metapac::metadata::{ | |||
| 16 | #[path = "./build_common.rs"] | 16 | #[path = "./build_common.rs"] |
| 17 | mod common; | 17 | mod common; |
| 18 | 18 | ||
| 19 | /// Helper function to handle peripheral versions with underscores. | ||
| 20 | /// For a version like "v1_foo_bar", this generates all prefix combinations: | ||
| 21 | /// - "kind_v1" | ||
| 22 | /// - "kind_v1_foo" | ||
| 23 | /// - "kind_v1_foo_bar" | ||
| 24 | fn foreach_version_cfg( | ||
| 25 | cfgs: &mut common::CfgSet, | ||
| 26 | kind: &str, | ||
| 27 | version: &str, | ||
| 28 | mut cfg_fn: impl FnMut(&mut common::CfgSet, &str), | ||
| 29 | ) { | ||
| 30 | let parts: Vec<&str> = version.split('_').collect(); | ||
| 31 | |||
| 32 | // Generate all possible prefix combinations | ||
| 33 | for i in 1..=parts.len() { | ||
| 34 | let partial_version = parts[0..i].join("_"); | ||
| 35 | let cfg_name = format!("{}_{}", kind, partial_version); | ||
| 36 | cfg_fn(cfgs, &cfg_name); | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 19 | fn main() { | 40 | fn main() { |
| 20 | let mut cfgs = common::CfgSet::new(); | 41 | let mut cfgs = common::CfgSet::new(); |
| 21 | common::set_target_cfgs(&mut cfgs); | 42 | common::set_target_cfgs(&mut cfgs); |
| @@ -38,14 +59,18 @@ fn main() { | |||
| 38 | for p in METADATA.peripherals { | 59 | for p in METADATA.peripherals { |
| 39 | if let Some(r) = &p.registers { | 60 | if let Some(r) = &p.registers { |
| 40 | cfgs.enable(r.kind); | 61 | cfgs.enable(r.kind); |
| 41 | cfgs.enable(format!("{}_{}", r.kind, r.version)); | 62 | foreach_version_cfg(&mut cfgs, r.kind, r.version, |cfgs, cfg_name| { |
| 63 | cfgs.enable(cfg_name); | ||
| 64 | }); | ||
| 42 | } | 65 | } |
| 43 | } | 66 | } |
| 44 | 67 | ||
| 45 | for &(kind, versions) in ALL_PERIPHERAL_VERSIONS.iter() { | 68 | for &(kind, versions) in ALL_PERIPHERAL_VERSIONS.iter() { |
| 46 | cfgs.declare(kind); | 69 | cfgs.declare(kind); |
| 47 | for &version in versions.iter() { | 70 | for &version in versions.iter() { |
| 48 | cfgs.declare(format!("{}_{}", kind, version)); | 71 | foreach_version_cfg(&mut cfgs, kind, version, |cfgs, cfg_name| { |
| 72 | cfgs.declare(cfg_name); | ||
| 73 | }); | ||
| 49 | } | 74 | } |
| 50 | } | 75 | } |
| 51 | 76 | ||
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 778edc6f6..ea986f4cf 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs | |||
| @@ -2,12 +2,12 @@ | |||
| 2 | 2 | ||
| 3 | #![macro_use] | 3 | #![macro_use] |
| 4 | #![allow(missing_docs)] // TODO | 4 | #![allow(missing_docs)] // TODO |
| 5 | #![cfg_attr(adc_f3_v2, allow(unused))] | 5 | #![cfg_attr(adc_f3v3, allow(unused))] |
| 6 | 6 | ||
| 7 | #[cfg(not(any(adc_f3_v2, adc_wba)))] | 7 | #[cfg(not(any(adc_f3v3, adc_wba)))] |
| 8 | #[cfg_attr(adc_f1, path = "f1.rs")] | 8 | #[cfg_attr(adc_f1, path = "f1.rs")] |
| 9 | #[cfg_attr(adc_f3, path = "f3.rs")] | 9 | #[cfg_attr(adc_f3v1, path = "f3.rs")] |
| 10 | #[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")] | 10 | #[cfg_attr(adc_f3v2, path = "f3_v1_1.rs")] |
| 11 | #[cfg_attr(adc_v1, path = "v1.rs")] | 11 | #[cfg_attr(adc_v1, path = "v1.rs")] |
| 12 | #[cfg_attr(adc_l0, path = "v1.rs")] | 12 | #[cfg_attr(adc_l0, path = "v1.rs")] |
| 13 | #[cfg_attr(adc_v2, path = "v2.rs")] | 13 | #[cfg_attr(adc_v2, path = "v2.rs")] |
| @@ -20,10 +20,10 @@ mod _version; | |||
| 20 | use core::marker::PhantomData; | 20 | use core::marker::PhantomData; |
| 21 | 21 | ||
| 22 | #[allow(unused)] | 22 | #[allow(unused)] |
| 23 | #[cfg(not(any(adc_f3_v2, adc_wba)))] | 23 | #[cfg(not(any(adc_f3v3, adc_wba)))] |
| 24 | pub use _version::*; | 24 | pub use _version::*; |
| 25 | use embassy_hal_internal::{impl_peripheral, PeripheralType}; | 25 | use embassy_hal_internal::{impl_peripheral, PeripheralType}; |
| 26 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] | 26 | #[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] |
| 27 | use embassy_sync::waitqueue::AtomicWaker; | 27 | use embassy_sync::waitqueue::AtomicWaker; |
| 28 | 28 | ||
| 29 | #[cfg(any(adc_u5, adc_wba))] | 29 | #[cfg(any(adc_u5, adc_wba))] |
| @@ -31,7 +31,7 @@ use embassy_sync::waitqueue::AtomicWaker; | |||
| 31 | pub mod adc4; | 31 | pub mod adc4; |
| 32 | 32 | ||
| 33 | pub use crate::pac::adc::vals; | 33 | pub use crate::pac::adc::vals; |
| 34 | #[cfg(not(any(adc_f1, adc_f3_v2)))] | 34 | #[cfg(not(any(adc_f1, adc_f3v3)))] |
| 35 | pub use crate::pac::adc::vals::Res as Resolution; | 35 | pub use crate::pac::adc::vals::Res as Resolution; |
| 36 | pub use crate::pac::adc::vals::SampleTime; | 36 | pub use crate::pac::adc::vals::SampleTime; |
| 37 | use crate::peripherals; | 37 | use crate::peripherals; |
| @@ -47,16 +47,16 @@ dma_trait!(RxDma4, adc4::Instance); | |||
| 47 | pub struct Adc<'d, T: Instance> { | 47 | pub struct Adc<'d, T: Instance> { |
| 48 | #[allow(unused)] | 48 | #[allow(unused)] |
| 49 | adc: crate::Peri<'d, T>, | 49 | adc: crate::Peri<'d, T>, |
| 50 | #[cfg(not(any(adc_f3_v2, adc_f3_v1_1, adc_wba)))] | 50 | #[cfg(not(any(adc_f3v3, adc_f3v2, adc_wba)))] |
| 51 | sample_time: SampleTime, | 51 | sample_time: SampleTime, |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] | 54 | #[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] |
| 55 | pub struct State { | 55 | pub struct State { |
| 56 | pub waker: AtomicWaker, | 56 | pub waker: AtomicWaker, |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] | 59 | #[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] |
| 60 | impl State { | 60 | impl State { |
| 61 | pub const fn new() -> Self { | 61 | pub const fn new() -> Self { |
| 62 | Self { | 62 | Self { |
| @@ -69,10 +69,10 @@ trait SealedInstance { | |||
| 69 | #[cfg(not(adc_wba))] | 69 | #[cfg(not(adc_wba))] |
| 70 | #[allow(unused)] | 70 | #[allow(unused)] |
| 71 | fn regs() -> crate::pac::adc::Adc; | 71 | fn regs() -> crate::pac::adc::Adc; |
| 72 | #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] | 72 | #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3v3, adc_f3v2, adc_g0)))] |
| 73 | #[allow(unused)] | 73 | #[allow(unused)] |
| 74 | fn common_regs() -> crate::pac::adccommon::AdcCommon; | 74 | fn common_regs() -> crate::pac::adccommon::AdcCommon; |
| 75 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] | 75 | #[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] |
| 76 | fn state() -> &'static State; | 76 | fn state() -> &'static State; |
| 77 | } | 77 | } |
| 78 | 78 | ||
| @@ -100,22 +100,8 @@ pub(crate) fn blocking_delay_us(us: u32) { | |||
| 100 | 100 | ||
| 101 | /// ADC instance. | 101 | /// ADC instance. |
| 102 | #[cfg(not(any( | 102 | #[cfg(not(any( |
| 103 | adc_f1, | 103 | adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_g4, adc_f3v1, adc_f3v2, adc_g0, adc_u0, adc_h5, adc_h7rs, |
| 104 | adc_v1, | 104 | adc_u5, adc_c0, adc_wba, |
| 105 | adc_l0, | ||
| 106 | adc_v2, | ||
| 107 | adc_v3, | ||
| 108 | adc_v4, | ||
| 109 | adc_g4, | ||
| 110 | adc_f3, | ||
| 111 | adc_f3_v1_1, | ||
| 112 | adc_g0, | ||
| 113 | adc_u0, | ||
| 114 | adc_h5, | ||
| 115 | adc_h7rs, | ||
| 116 | adc_u5, | ||
| 117 | adc_c0, | ||
| 118 | adc_wba, | ||
| 119 | )))] | 105 | )))] |
| 120 | #[allow(private_bounds)] | 106 | #[allow(private_bounds)] |
| 121 | pub trait Instance: SealedInstance + crate::PeripheralType { | 107 | pub trait Instance: SealedInstance + crate::PeripheralType { |
| @@ -123,22 +109,8 @@ pub trait Instance: SealedInstance + crate::PeripheralType { | |||
| 123 | } | 109 | } |
| 124 | /// ADC instance. | 110 | /// ADC instance. |
| 125 | #[cfg(any( | 111 | #[cfg(any( |
| 126 | adc_f1, | 112 | adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_g4, adc_f3v1, adc_f3v2, adc_g0, adc_u0, adc_h5, adc_h7rs, |
| 127 | adc_v1, | 113 | adc_u5, adc_c0, adc_wba, |
| 128 | adc_l0, | ||
| 129 | adc_v2, | ||
| 130 | adc_v3, | ||
| 131 | adc_v4, | ||
| 132 | adc_g4, | ||
| 133 | adc_f3, | ||
| 134 | adc_f3_v1_1, | ||
| 135 | adc_g0, | ||
| 136 | adc_u0, | ||
| 137 | adc_h5, | ||
| 138 | adc_h7rs, | ||
| 139 | adc_u5, | ||
| 140 | adc_c0, | ||
| 141 | adc_wba, | ||
| 142 | ))] | 114 | ))] |
| 143 | #[allow(private_bounds)] | 115 | #[allow(private_bounds)] |
| 144 | pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeripheral { | 116 | pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeripheral { |
| @@ -258,12 +230,12 @@ foreach_adc!( | |||
| 258 | crate::pac::$inst | 230 | crate::pac::$inst |
| 259 | } | 231 | } |
| 260 | 232 | ||
| 261 | #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0, adc_u5, adc_wba)))] | 233 | #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3v3, adc_f3v2, adc_g0, adc_u5, adc_wba)))] |
| 262 | fn common_regs() -> crate::pac::adccommon::AdcCommon { | 234 | fn common_regs() -> crate::pac::adccommon::AdcCommon { |
| 263 | return crate::pac::$common_inst | 235 | return crate::pac::$common_inst |
| 264 | } | 236 | } |
| 265 | 237 | ||
| 266 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] | 238 | #[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] |
| 267 | fn state() -> &'static State { | 239 | fn state() -> &'static State { |
| 268 | static STATE: State = State::new(); | 240 | static STATE: State = State::new(); |
| 269 | &STATE | 241 | &STATE |
| @@ -295,7 +267,7 @@ macro_rules! impl_adc_pin { | |||
| 295 | /// Get the maximum reading value for this resolution. | 267 | /// Get the maximum reading value for this resolution. |
| 296 | /// | 268 | /// |
| 297 | /// This is `2**n - 1`. | 269 | /// This is `2**n - 1`. |
| 298 | #[cfg(not(any(adc_f1, adc_f3_v2)))] | 270 | #[cfg(not(any(adc_f1, adc_f3v3)))] |
| 299 | pub const fn resolution_to_max_count(res: Resolution) -> u32 { | 271 | pub const fn resolution_to_max_count(res: Resolution) -> u32 { |
| 300 | match res { | 272 | match res { |
| 301 | #[cfg(adc_v4)] | 273 | #[cfg(adc_v4)] |
| @@ -309,7 +281,7 @@ pub const fn resolution_to_max_count(res: Resolution) -> u32 { | |||
| 309 | Resolution::BITS12 => (1 << 12) - 1, | 281 | Resolution::BITS12 => (1 << 12) - 1, |
| 310 | Resolution::BITS10 => (1 << 10) - 1, | 282 | Resolution::BITS10 => (1 << 10) - 1, |
| 311 | Resolution::BITS8 => (1 << 8) - 1, | 283 | Resolution::BITS8 => (1 << 8) - 1, |
| 312 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_c0, adc_g0, adc_f3, adc_f3_v1_1, adc_h5))] | 284 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_c0, adc_g0, adc_f3v1, adc_f3v2, adc_h5))] |
| 313 | Resolution::BITS6 => (1 << 6) - 1, | 285 | Resolution::BITS6 => (1 << 6) - 1, |
| 314 | #[allow(unreachable_patterns)] | 286 | #[allow(unreachable_patterns)] |
| 315 | _ => core::unreachable!(), | 287 | _ => core::unreachable!(), |
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs index a51d21bb0..0c4ab56e3 100644 --- a/embassy-stm32/src/i2s.rs +++ b/embassy-stm32/src/i2s.rs | |||
| @@ -27,7 +27,8 @@ enum Function { | |||
| 27 | Transmit, | 27 | Transmit, |
| 28 | /// Receive audio data | 28 | /// Receive audio data |
| 29 | Receive, | 29 | Receive, |
| 30 | #[cfg(spi_v3)] | 30 | #[cfg(any(spi_v4, spi_v5))] |
| 31 | |||
| 31 | /// Transmit and Receive audio data | 32 | /// Transmit and Receive audio data |
| 32 | FullDuplex, | 33 | FullDuplex, |
| 33 | } | 34 | } |
| @@ -72,7 +73,6 @@ impl From<ringbuffer::Error> for Error { | |||
| 72 | } | 73 | } |
| 73 | 74 | ||
| 74 | impl Standard { | 75 | impl Standard { |
| 75 | #[cfg(any(spi_v1, spi_v3, spi_f1))] | ||
| 76 | const fn i2sstd(&self) -> vals::I2sstd { | 76 | const fn i2sstd(&self) -> vals::I2sstd { |
| 77 | match self { | 77 | match self { |
| 78 | Standard::Philips => vals::I2sstd::PHILIPS, | 78 | Standard::Philips => vals::I2sstd::PHILIPS, |
| @@ -83,7 +83,6 @@ impl Standard { | |||
| 83 | } | 83 | } |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | #[cfg(any(spi_v1, spi_v3, spi_f1))] | ||
| 87 | const fn pcmsync(&self) -> vals::Pcmsync { | 86 | const fn pcmsync(&self) -> vals::Pcmsync { |
| 88 | match self { | 87 | match self { |
| 89 | Standard::PcmLongSync => vals::Pcmsync::LONG, | 88 | Standard::PcmLongSync => vals::Pcmsync::LONG, |
| @@ -106,7 +105,6 @@ pub enum Format { | |||
| 106 | } | 105 | } |
| 107 | 106 | ||
| 108 | impl Format { | 107 | impl Format { |
| 109 | #[cfg(any(spi_v1, spi_v3, spi_f1))] | ||
| 110 | const fn datlen(&self) -> vals::Datlen { | 108 | const fn datlen(&self) -> vals::Datlen { |
| 111 | match self { | 109 | match self { |
| 112 | Format::Data16Channel16 => vals::Datlen::BITS16, | 110 | Format::Data16Channel16 => vals::Datlen::BITS16, |
| @@ -116,7 +114,6 @@ impl Format { | |||
| 116 | } | 114 | } |
| 117 | } | 115 | } |
| 118 | 116 | ||
| 119 | #[cfg(any(spi_v1, spi_v3, spi_f1))] | ||
| 120 | const fn chlen(&self) -> vals::Chlen { | 117 | const fn chlen(&self) -> vals::Chlen { |
| 121 | match self { | 118 | match self { |
| 122 | Format::Data16Channel16 => vals::Chlen::BITS16, | 119 | Format::Data16Channel16 => vals::Chlen::BITS16, |
| @@ -137,7 +134,6 @@ pub enum ClockPolarity { | |||
| 137 | } | 134 | } |
| 138 | 135 | ||
| 139 | impl ClockPolarity { | 136 | impl ClockPolarity { |
| 140 | #[cfg(any(spi_v1, spi_v3, spi_f1))] | ||
| 141 | const fn ckpol(&self) -> vals::Ckpol { | 137 | const fn ckpol(&self) -> vals::Ckpol { |
| 142 | match self { | 138 | match self { |
| 143 | ClockPolarity::IdleHigh => vals::Ckpol::IDLE_HIGH, | 139 | ClockPolarity::IdleHigh => vals::Ckpol::IDLE_HIGH, |
| @@ -314,7 +310,8 @@ impl<'d, W: Word> I2S<'d, W> { | |||
| 314 | ) | 310 | ) |
| 315 | } | 311 | } |
| 316 | 312 | ||
| 317 | #[cfg(spi_v3)] | 313 | #[cfg(any(spi_v4, spi_v5))] |
| 314 | |||
| 318 | /// Create a full duplex driver. | 315 | /// Create a full duplex driver. |
| 319 | pub fn new_full_duplex<T: Instance>( | 316 | pub fn new_full_duplex<T: Instance>( |
| 320 | peri: Peri<'d, T>, | 317 | peri: Peri<'d, T>, |
| @@ -357,7 +354,7 @@ impl<'d, W: Word> I2S<'d, W> { | |||
| 357 | if let Some(rx_ring_buffer) = &mut self.rx_ring_buffer { | 354 | if let Some(rx_ring_buffer) = &mut self.rx_ring_buffer { |
| 358 | rx_ring_buffer.start(); | 355 | rx_ring_buffer.start(); |
| 359 | // SPIv3 clears rxfifo on SPE=0 | 356 | // SPIv3 clears rxfifo on SPE=0 |
| 360 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | 357 | #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] |
| 361 | flush_rx_fifo(self.spi.info.regs); | 358 | flush_rx_fifo(self.spi.info.regs); |
| 362 | 359 | ||
| 363 | set_rxdmaen(self.spi.info.regs, true); | 360 | set_rxdmaen(self.spi.info.regs, true); |
| @@ -365,7 +362,7 @@ impl<'d, W: Word> I2S<'d, W> { | |||
| 365 | self.spi.info.regs.cr1().modify(|w| { | 362 | self.spi.info.regs.cr1().modify(|w| { |
| 366 | w.set_spe(true); | 363 | w.set_spe(true); |
| 367 | }); | 364 | }); |
| 368 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 365 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 369 | self.spi.info.regs.cr1().modify(|w| { | 366 | self.spi.info.regs.cr1().modify(|w| { |
| 370 | w.set_cstart(true); | 367 | w.set_cstart(true); |
| 371 | }); | 368 | }); |
| @@ -404,7 +401,7 @@ impl<'d, W: Word> I2S<'d, W> { | |||
| 404 | 401 | ||
| 405 | join(rx_f, tx_f).await; | 402 | join(rx_f, tx_f).await; |
| 406 | 403 | ||
| 407 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 404 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 408 | { | 405 | { |
| 409 | if let Mode::Master = self.mode { | 406 | if let Mode::Master = self.mode { |
| 410 | regs.cr1().modify(|w| { | 407 | regs.cr1().modify(|w| { |
| @@ -492,103 +489,98 @@ impl<'d, W: Word> I2S<'d, W> { | |||
| 492 | 489 | ||
| 493 | let (odd, div) = compute_baud_rate(pclk, config.frequency, config.master_clock, config.format); | 490 | let (odd, div) = compute_baud_rate(pclk, config.frequency, config.master_clock, config.format); |
| 494 | 491 | ||
| 495 | #[cfg(any(spi_v1, spi_v3, spi_f1))] | 492 | #[cfg(any(spi_v4, spi_v5))] |
| 496 | { | 493 | { |
| 497 | #[cfg(spi_v3)] | 494 | regs.cr1().modify(|w| w.set_spe(false)); |
| 498 | { | ||
| 499 | regs.cr1().modify(|w| w.set_spe(false)); | ||
| 500 | 495 | ||
| 501 | reset_incompatible_bitfields::<T>(); | 496 | reset_incompatible_bitfields::<T>(); |
| 502 | } | 497 | } |
| 503 | 498 | ||
| 504 | use stm32_metapac::spi::vals::{I2scfg, Odd}; | 499 | use stm32_metapac::spi::vals::{I2scfg, Odd}; |
| 505 | 500 | ||
| 506 | // 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR/SPI_I2SCFGR register to define the serial clock baud | 501 | // 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR/SPI_I2SCFGR register to define the serial clock baud |
| 507 | // rate to reach the proper audio sample frequency. The ODD bit in the | 502 | // rate to reach the proper audio sample frequency. The ODD bit in the |
| 508 | // SPI_I2SPR/SPI_I2SCFGR register also has to be defined. | 503 | // SPI_I2SPR/SPI_I2SCFGR register also has to be defined. |
| 509 | |||
| 510 | // 2. Select the CKPOL bit to define the steady level for the communication clock. Set the | ||
| 511 | // MCKOE bit in the SPI_I2SPR/SPI_I2SCFGR register if the master clock MCK needs to be provided to | ||
| 512 | // the external DAC/ADC audio component (the I2SDIV and ODD values should be | ||
| 513 | // computed depending on the state of the MCK output, for more details refer to | ||
| 514 | // Section 28.4.4: Clock generator). | ||
| 515 | |||
| 516 | // 3. Set the I2SMOD bit in SPI_I2SCFGR to activate the I2S functionalities and choose the | ||
| 517 | // I2S standard through the I2SSTD[1:0] and PCMSYNC bits, the data length through the | ||
| 518 | // DATLEN[1:0] bits and the number of bits per channel by configuring the CHLEN bit. | ||
| 519 | // Select also the I2S master mode and direction (Transmitter or Receiver) through the | ||
| 520 | // I2SCFG[1:0] bits in the SPI_I2SCFGR register. | ||
| 521 | |||
| 522 | // 4. If needed, select all the potential interruption sources and the DMA capabilities by | ||
| 523 | // writing the SPI_CR2 register. | ||
| 524 | |||
| 525 | // 5. The I2SE bit in SPI_I2SCFGR register must be set. | ||
| 526 | |||
| 527 | let clk_reg = { | ||
| 528 | #[cfg(any(spi_v1, spi_f1))] | ||
| 529 | { | ||
| 530 | regs.i2spr() | ||
| 531 | } | ||
| 532 | #[cfg(spi_v3)] | ||
| 533 | { | ||
| 534 | regs.i2scfgr() | ||
| 535 | } | ||
| 536 | }; | ||
| 537 | |||
| 538 | clk_reg.modify(|w| { | ||
| 539 | w.set_i2sdiv(div); | ||
| 540 | w.set_odd(match odd { | ||
| 541 | true => Odd::ODD, | ||
| 542 | false => Odd::EVEN, | ||
| 543 | }); | ||
| 544 | 504 | ||
| 545 | w.set_mckoe(config.master_clock); | 505 | // 2. Select the CKPOL bit to define the steady level for the communication clock. Set the |
| 506 | // MCKOE bit in the SPI_I2SPR/SPI_I2SCFGR register if the master clock MCK needs to be provided to | ||
| 507 | // the external DAC/ADC audio component (the I2SDIV and ODD values should be | ||
| 508 | // computed depending on the state of the MCK output, for more details refer to | ||
| 509 | // Section 28.4.4: Clock generator). | ||
| 510 | |||
| 511 | // 3. Set the I2SMOD bit in SPI_I2SCFGR to activate the I2S functionalities and choose the | ||
| 512 | // I2S standard through the I2SSTD[1:0] and PCMSYNC bits, the data length through the | ||
| 513 | // DATLEN[1:0] bits and the number of bits per channel by configuring the CHLEN bit. | ||
| 514 | // Select also the I2S master mode and direction (Transmitter or Receiver) through the | ||
| 515 | // I2SCFG[1:0] bits in the SPI_I2SCFGR register. | ||
| 516 | |||
| 517 | // 4. If needed, select all the potential interruption sources and the DMA capabilities by | ||
| 518 | // writing the SPI_CR2 register. | ||
| 519 | |||
| 520 | // 5. The I2SE bit in SPI_I2SCFGR register must be set. | ||
| 521 | |||
| 522 | let clk_reg = { | ||
| 523 | #[cfg(any(spi_v1, spi_v2, spi_v3))] | ||
| 524 | { | ||
| 525 | regs.i2spr() | ||
| 526 | } | ||
| 527 | #[cfg(any(spi_v4, spi_v5))] | ||
| 528 | { | ||
| 529 | regs.i2scfgr() | ||
| 530 | } | ||
| 531 | }; | ||
| 532 | |||
| 533 | clk_reg.modify(|w| { | ||
| 534 | w.set_i2sdiv(div); | ||
| 535 | w.set_odd(match odd { | ||
| 536 | true => Odd::ODD, | ||
| 537 | false => Odd::EVEN, | ||
| 546 | }); | 538 | }); |
| 547 | 539 | ||
| 548 | regs.i2scfgr().modify(|w| { | 540 | w.set_mckoe(config.master_clock); |
| 549 | w.set_ckpol(config.clock_polarity.ckpol()); | 541 | }); |
| 550 | 542 | ||
| 551 | w.set_i2smod(true); | 543 | regs.i2scfgr().modify(|w| { |
| 544 | w.set_ckpol(config.clock_polarity.ckpol()); | ||
| 552 | 545 | ||
| 553 | w.set_i2sstd(config.standard.i2sstd()); | 546 | w.set_i2smod(true); |
| 554 | w.set_pcmsync(config.standard.pcmsync()); | ||
| 555 | 547 | ||
| 556 | w.set_datlen(config.format.datlen()); | 548 | w.set_i2sstd(config.standard.i2sstd()); |
| 557 | w.set_chlen(config.format.chlen()); | 549 | w.set_pcmsync(config.standard.pcmsync()); |
| 558 | 550 | ||
| 559 | w.set_i2scfg(match (config.mode, function) { | 551 | w.set_datlen(config.format.datlen()); |
| 560 | (Mode::Master, Function::Transmit) => I2scfg::MASTER_TX, | 552 | w.set_chlen(config.format.chlen()); |
| 561 | (Mode::Master, Function::Receive) => I2scfg::MASTER_RX, | ||
| 562 | #[cfg(spi_v3)] | ||
| 563 | (Mode::Master, Function::FullDuplex) => I2scfg::MASTER_FULL_DUPLEX, | ||
| 564 | (Mode::Slave, Function::Transmit) => I2scfg::SLAVE_TX, | ||
| 565 | (Mode::Slave, Function::Receive) => I2scfg::SLAVE_RX, | ||
| 566 | #[cfg(spi_v3)] | ||
| 567 | (Mode::Slave, Function::FullDuplex) => I2scfg::SLAVE_FULL_DUPLEX, | ||
| 568 | }); | ||
| 569 | 553 | ||
| 570 | #[cfg(any(spi_v1, spi_f1))] | 554 | w.set_i2scfg(match (config.mode, function) { |
| 571 | w.set_i2se(true); | 555 | (Mode::Master, Function::Transmit) => I2scfg::MASTER_TX, |
| 556 | (Mode::Master, Function::Receive) => I2scfg::MASTER_RX, | ||
| 557 | #[cfg(any(spi_v4, spi_v5))] | ||
| 558 | (Mode::Master, Function::FullDuplex) => I2scfg::MASTER_FULL_DUPLEX, | ||
| 559 | (Mode::Slave, Function::Transmit) => I2scfg::SLAVE_TX, | ||
| 560 | (Mode::Slave, Function::Receive) => I2scfg::SLAVE_RX, | ||
| 561 | #[cfg(any(spi_v4, spi_v5))] | ||
| 562 | (Mode::Slave, Function::FullDuplex) => I2scfg::SLAVE_FULL_DUPLEX, | ||
| 572 | }); | 563 | }); |
| 573 | 564 | ||
| 574 | let mut opts = TransferOptions::default(); | 565 | #[cfg(any(spi_v1, spi_v2, spi_v3))] |
| 575 | opts.half_transfer_ir = true; | 566 | w.set_i2se(true); |
| 576 | 567 | }); | |
| 577 | Self { | 568 | |
| 578 | mode: config.mode, | 569 | let mut opts = TransferOptions::default(); |
| 579 | spi, | 570 | opts.half_transfer_ir = true; |
| 580 | txsd: txsd.map(|w| w.into()), | 571 | |
| 581 | rxsd: rxsd.map(|w| w.into()), | 572 | Self { |
| 582 | ws: Some(ws.into()), | 573 | mode: config.mode, |
| 583 | ck: Some(ck.into()), | 574 | spi, |
| 584 | mck: mck.map(|w| w.into()), | 575 | txsd: txsd.map(|w| w.into()), |
| 585 | tx_ring_buffer: txdma.map(|(ch, buf)| unsafe { | 576 | rxsd: rxsd.map(|w| w.into()), |
| 586 | WritableRingBuffer::new(ch.channel, ch.request, regs.tx_ptr(), buf, opts) | 577 | ws: Some(ws.into()), |
| 587 | }), | 578 | ck: Some(ck.into()), |
| 588 | rx_ring_buffer: rxdma.map(|(ch, buf)| unsafe { | 579 | mck: mck.map(|w| w.into()), |
| 589 | ReadableRingBuffer::new(ch.channel, ch.request, regs.rx_ptr(), buf, opts) | 580 | tx_ring_buffer: txdma |
| 590 | }), | 581 | .map(|(ch, buf)| unsafe { WritableRingBuffer::new(ch.channel, ch.request, regs.tx_ptr(), buf, opts) }), |
| 591 | } | 582 | rx_ring_buffer: rxdma |
| 583 | .map(|(ch, buf)| unsafe { ReadableRingBuffer::new(ch.channel, ch.request, regs.rx_ptr(), buf, opts) }), | ||
| 592 | } | 584 | } |
| 593 | } | 585 | } |
| 594 | } | 586 | } |
| @@ -639,7 +631,8 @@ fn compute_baud_rate(i2s_clock: Hertz, request_freq: Hertz, mclk: bool, data_for | |||
| 639 | } | 631 | } |
| 640 | } | 632 | } |
| 641 | 633 | ||
| 642 | #[cfg(spi_v3)] | 634 | #[cfg(any(spi_v4, spi_v5))] |
| 635 | |||
| 643 | // The STM32H7 reference manual specifies that any incompatible bitfields should be reset | 636 | // The STM32H7 reference manual specifies that any incompatible bitfields should be reset |
| 644 | // to their reset values while operating in I2S mode. | 637 | // to their reset values while operating in I2S mode. |
| 645 | fn reset_incompatible_bitfields<T: Instance>() { | 638 | fn reset_incompatible_bitfields<T: Instance>() { |
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 3be98c462..7e0f7884e 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -87,7 +87,7 @@ pub mod hsem; | |||
| 87 | pub mod hspi; | 87 | pub mod hspi; |
| 88 | #[cfg(i2c)] | 88 | #[cfg(i2c)] |
| 89 | pub mod i2c; | 89 | pub mod i2c; |
| 90 | #[cfg(any(all(spi_v1, rcc_f4), spi_v3))] | 90 | #[cfg(any(spi_v1_i2s, spi_v2_i2s, spi_v3_i2s, spi_v4_i2s, spi_v5_i2s))] |
| 91 | pub mod i2s; | 91 | pub mod i2s; |
| 92 | #[cfg(stm32wb)] | 92 | #[cfg(stm32wb)] |
| 93 | pub mod ipcc; | 93 | pub mod ipcc; |
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 88cc225dd..cde2a56c2 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs | |||
| @@ -8,6 +8,7 @@ use embassy_hal_internal::PeripheralType; | |||
| 8 | pub use crate::dma::word; | 8 | pub use crate::dma::word; |
| 9 | use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; | 9 | use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; |
| 10 | use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; | 10 | use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; |
| 11 | pub use crate::pac::sai::vals::Mckdiv as MasterClockDivider; | ||
| 11 | use crate::pac::sai::{vals, Sai as Regs}; | 12 | use crate::pac::sai::{vals, Sai as Regs}; |
| 12 | use crate::rcc::{self, RccPeripheral}; | 13 | use crate::rcc::{self, RccPeripheral}; |
| 13 | use crate::{peripherals, Peri}; | 14 | use crate::{peripherals, Peri}; |
| @@ -45,7 +46,6 @@ pub enum Mode { | |||
| 45 | } | 46 | } |
| 46 | 47 | ||
| 47 | impl Mode { | 48 | impl Mode { |
| 48 | #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | ||
| 49 | const fn mode(&self, tx_rx: TxRx) -> vals::Mode { | 49 | const fn mode(&self, tx_rx: TxRx) -> vals::Mode { |
| 50 | match tx_rx { | 50 | match tx_rx { |
| 51 | TxRx::Transmitter => match self { | 51 | TxRx::Transmitter => match self { |
| @@ -80,7 +80,6 @@ pub enum SlotSize { | |||
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | impl SlotSize { | 82 | impl SlotSize { |
| 83 | #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | ||
| 84 | const fn slotsz(&self) -> vals::Slotsz { | 83 | const fn slotsz(&self) -> vals::Slotsz { |
| 85 | match self { | 84 | match self { |
| 86 | SlotSize::DataSize => vals::Slotsz::DATA_SIZE, | 85 | SlotSize::DataSize => vals::Slotsz::DATA_SIZE, |
| @@ -103,7 +102,6 @@ pub enum DataSize { | |||
| 103 | } | 102 | } |
| 104 | 103 | ||
| 105 | impl DataSize { | 104 | impl DataSize { |
| 106 | #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | ||
| 107 | const fn ds(&self) -> vals::Ds { | 105 | const fn ds(&self) -> vals::Ds { |
| 108 | match self { | 106 | match self { |
| 109 | DataSize::Data8 => vals::Ds::BIT8, | 107 | DataSize::Data8 => vals::Ds::BIT8, |
| @@ -128,7 +126,6 @@ pub enum FifoThreshold { | |||
| 128 | } | 126 | } |
| 129 | 127 | ||
| 130 | impl FifoThreshold { | 128 | impl FifoThreshold { |
| 131 | #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | ||
| 132 | const fn fth(&self) -> vals::Fth { | 129 | const fn fth(&self) -> vals::Fth { |
| 133 | match self { | 130 | match self { |
| 134 | FifoThreshold::Empty => vals::Fth::EMPTY, | 131 | FifoThreshold::Empty => vals::Fth::EMPTY, |
| @@ -149,7 +146,6 @@ pub enum MuteValue { | |||
| 149 | } | 146 | } |
| 150 | 147 | ||
| 151 | impl MuteValue { | 148 | impl MuteValue { |
| 152 | #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | ||
| 153 | const fn muteval(&self) -> vals::Muteval { | 149 | const fn muteval(&self) -> vals::Muteval { |
| 154 | match self { | 150 | match self { |
| 155 | MuteValue::Zero => vals::Muteval::SEND_ZERO, | 151 | MuteValue::Zero => vals::Muteval::SEND_ZERO, |
| @@ -168,7 +164,6 @@ pub enum Protocol { | |||
| 168 | } | 164 | } |
| 169 | 165 | ||
| 170 | impl Protocol { | 166 | impl Protocol { |
| 171 | #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | ||
| 172 | const fn prtcfg(&self) -> vals::Prtcfg { | 167 | const fn prtcfg(&self) -> vals::Prtcfg { |
| 173 | match self { | 168 | match self { |
| 174 | Protocol::Free => vals::Prtcfg::FREE, | 169 | Protocol::Free => vals::Prtcfg::FREE, |
| @@ -187,7 +182,7 @@ pub enum SyncInput { | |||
| 187 | /// Syncs with the other A/B sub-block within the SAI unit | 182 | /// Syncs with the other A/B sub-block within the SAI unit |
| 188 | Internal, | 183 | Internal, |
| 189 | /// Syncs with a sub-block in the other SAI unit | 184 | /// Syncs with a sub-block in the other SAI unit |
| 190 | #[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | 185 | #[cfg(any(sai_v3, sai_v4))] |
| 191 | External(SyncInputInstance), | 186 | External(SyncInputInstance), |
| 192 | } | 187 | } |
| 193 | 188 | ||
| @@ -196,14 +191,14 @@ impl SyncInput { | |||
| 196 | match self { | 191 | match self { |
| 197 | SyncInput::None => vals::Syncen::ASYNCHRONOUS, | 192 | SyncInput::None => vals::Syncen::ASYNCHRONOUS, |
| 198 | SyncInput::Internal => vals::Syncen::INTERNAL, | 193 | SyncInput::Internal => vals::Syncen::INTERNAL, |
| 199 | #[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | 194 | #[cfg(any(sai_v3, sai_v4))] |
| 200 | SyncInput::External(_) => vals::Syncen::EXTERNAL, | 195 | SyncInput::External(_) => vals::Syncen::EXTERNAL, |
| 201 | } | 196 | } |
| 202 | } | 197 | } |
| 203 | } | 198 | } |
| 204 | 199 | ||
| 205 | /// SAI instance to sync from. | 200 | /// SAI instance to sync from. |
| 206 | #[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | 201 | #[cfg(any(sai_v3, sai_v4))] |
| 207 | #[derive(Copy, Clone, PartialEq)] | 202 | #[derive(Copy, Clone, PartialEq)] |
| 208 | #[allow(missing_docs)] | 203 | #[allow(missing_docs)] |
| 209 | pub enum SyncInputInstance { | 204 | pub enum SyncInputInstance { |
| @@ -226,7 +221,6 @@ pub enum StereoMono { | |||
| 226 | } | 221 | } |
| 227 | 222 | ||
| 228 | impl StereoMono { | 223 | impl StereoMono { |
| 229 | #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | ||
| 230 | const fn mono(&self) -> vals::Mono { | 224 | const fn mono(&self) -> vals::Mono { |
| 231 | match self { | 225 | match self { |
| 232 | StereoMono::Stereo => vals::Mono::STEREO, | 226 | StereoMono::Stereo => vals::Mono::STEREO, |
| @@ -245,7 +239,6 @@ pub enum BitOrder { | |||
| 245 | } | 239 | } |
| 246 | 240 | ||
| 247 | impl BitOrder { | 241 | impl BitOrder { |
| 248 | #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | ||
| 249 | const fn lsbfirst(&self) -> vals::Lsbfirst { | 242 | const fn lsbfirst(&self) -> vals::Lsbfirst { |
| 250 | match self { | 243 | match self { |
| 251 | BitOrder::LsbFirst => vals::Lsbfirst::LSB_FIRST, | 244 | BitOrder::LsbFirst => vals::Lsbfirst::LSB_FIRST, |
| @@ -264,7 +257,6 @@ pub enum FrameSyncOffset { | |||
| 264 | } | 257 | } |
| 265 | 258 | ||
| 266 | impl FrameSyncOffset { | 259 | impl FrameSyncOffset { |
| 267 | #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | ||
| 268 | const fn fsoff(&self) -> vals::Fsoff { | 260 | const fn fsoff(&self) -> vals::Fsoff { |
| 269 | match self { | 261 | match self { |
| 270 | FrameSyncOffset::OnFirstBit => vals::Fsoff::ON_FIRST, | 262 | FrameSyncOffset::OnFirstBit => vals::Fsoff::ON_FIRST, |
| @@ -283,7 +275,6 @@ pub enum FrameSyncPolarity { | |||
| 283 | } | 275 | } |
| 284 | 276 | ||
| 285 | impl FrameSyncPolarity { | 277 | impl FrameSyncPolarity { |
| 286 | #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | ||
| 287 | const fn fspol(&self) -> vals::Fspol { | 278 | const fn fspol(&self) -> vals::Fspol { |
| 288 | match self { | 279 | match self { |
| 289 | FrameSyncPolarity::ActiveLow => vals::Fspol::FALLING_EDGE, | 280 | FrameSyncPolarity::ActiveLow => vals::Fspol::FALLING_EDGE, |
| @@ -301,7 +292,6 @@ pub enum FrameSyncDefinition { | |||
| 301 | } | 292 | } |
| 302 | 293 | ||
| 303 | impl FrameSyncDefinition { | 294 | impl FrameSyncDefinition { |
| 304 | #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | ||
| 305 | const fn fsdef(&self) -> bool { | 295 | const fn fsdef(&self) -> bool { |
| 306 | match self { | 296 | match self { |
| 307 | FrameSyncDefinition::StartOfFrame => false, | 297 | FrameSyncDefinition::StartOfFrame => false, |
| @@ -319,7 +309,6 @@ pub enum ClockStrobe { | |||
| 319 | } | 309 | } |
| 320 | 310 | ||
| 321 | impl ClockStrobe { | 311 | impl ClockStrobe { |
| 322 | #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | ||
| 323 | const fn ckstr(&self) -> vals::Ckstr { | 312 | const fn ckstr(&self) -> vals::Ckstr { |
| 324 | match self { | 313 | match self { |
| 325 | ClockStrobe::Falling => vals::Ckstr::FALLING_EDGE, | 314 | ClockStrobe::Falling => vals::Ckstr::FALLING_EDGE, |
| @@ -337,7 +326,6 @@ pub enum ComplementFormat { | |||
| 337 | } | 326 | } |
| 338 | 327 | ||
| 339 | impl ComplementFormat { | 328 | impl ComplementFormat { |
| 340 | #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | ||
| 341 | const fn cpl(&self) -> vals::Cpl { | 329 | const fn cpl(&self) -> vals::Cpl { |
| 342 | match self { | 330 | match self { |
| 343 | ComplementFormat::OnesComplement => vals::Cpl::ONES_COMPLEMENT, | 331 | ComplementFormat::OnesComplement => vals::Cpl::ONES_COMPLEMENT, |
| @@ -356,7 +344,6 @@ pub enum Companding { | |||
| 356 | } | 344 | } |
| 357 | 345 | ||
| 358 | impl Companding { | 346 | impl Companding { |
| 359 | #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | ||
| 360 | const fn comp(&self) -> vals::Comp { | 347 | const fn comp(&self) -> vals::Comp { |
| 361 | match self { | 348 | match self { |
| 362 | Companding::None => vals::Comp::NO_COMPANDING, | 349 | Companding::None => vals::Comp::NO_COMPANDING, |
| @@ -375,7 +362,6 @@ pub enum OutputDrive { | |||
| 375 | } | 362 | } |
| 376 | 363 | ||
| 377 | impl OutputDrive { | 364 | impl OutputDrive { |
| 378 | #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | ||
| 379 | const fn outdriv(&self) -> vals::Outdriv { | 365 | const fn outdriv(&self) -> vals::Outdriv { |
| 380 | match self { | 366 | match self { |
| 381 | OutputDrive::OnStart => vals::Outdriv::ON_START, | 367 | OutputDrive::OnStart => vals::Outdriv::ON_START, |
| @@ -384,196 +370,6 @@ impl OutputDrive { | |||
| 384 | } | 370 | } |
| 385 | } | 371 | } |
| 386 | 372 | ||
| 387 | /// Master clock divider. | ||
| 388 | #[derive(Copy, Clone, PartialEq)] | ||
| 389 | #[allow(missing_docs)] | ||
| 390 | #[cfg(any(sai_v1, sai_v2))] | ||
| 391 | pub enum MasterClockDivider { | ||
| 392 | MasterClockDisabled, | ||
| 393 | Div1, | ||
| 394 | Div2, | ||
| 395 | Div4, | ||
| 396 | Div6, | ||
| 397 | Div8, | ||
| 398 | Div10, | ||
| 399 | Div12, | ||
| 400 | Div14, | ||
| 401 | Div16, | ||
| 402 | Div18, | ||
| 403 | Div20, | ||
| 404 | Div22, | ||
| 405 | Div24, | ||
| 406 | Div26, | ||
| 407 | Div28, | ||
| 408 | Div30, | ||
| 409 | } | ||
| 410 | |||
| 411 | /// Master clock divider. | ||
| 412 | #[derive(Copy, Clone, PartialEq)] | ||
| 413 | #[allow(missing_docs)] | ||
| 414 | #[cfg(any(sai_v1_4pdm, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | ||
| 415 | pub enum MasterClockDivider { | ||
| 416 | MasterClockDisabled, | ||
| 417 | Div1, | ||
| 418 | Div2, | ||
| 419 | Div3, | ||
| 420 | Div4, | ||
| 421 | Div5, | ||
| 422 | Div6, | ||
| 423 | Div7, | ||
| 424 | Div8, | ||
| 425 | Div9, | ||
| 426 | Div10, | ||
| 427 | Div11, | ||
| 428 | Div12, | ||
| 429 | Div13, | ||
| 430 | Div14, | ||
| 431 | Div15, | ||
| 432 | Div16, | ||
| 433 | Div17, | ||
| 434 | Div18, | ||
| 435 | Div19, | ||
| 436 | Div20, | ||
| 437 | Div21, | ||
| 438 | Div22, | ||
| 439 | Div23, | ||
| 440 | Div24, | ||
| 441 | Div25, | ||
| 442 | Div26, | ||
| 443 | Div27, | ||
| 444 | Div28, | ||
| 445 | Div29, | ||
| 446 | Div30, | ||
| 447 | Div31, | ||
| 448 | Div32, | ||
| 449 | Div33, | ||
| 450 | Div34, | ||
| 451 | Div35, | ||
| 452 | Div36, | ||
| 453 | Div37, | ||
| 454 | Div38, | ||
| 455 | Div39, | ||
| 456 | Div40, | ||
| 457 | Div41, | ||
| 458 | Div42, | ||
| 459 | Div43, | ||
| 460 | Div44, | ||
| 461 | Div45, | ||
| 462 | Div46, | ||
| 463 | Div47, | ||
| 464 | Div48, | ||
| 465 | Div49, | ||
| 466 | Div50, | ||
| 467 | Div51, | ||
| 468 | Div52, | ||
| 469 | Div53, | ||
| 470 | Div54, | ||
| 471 | Div55, | ||
| 472 | Div56, | ||
| 473 | Div57, | ||
| 474 | Div58, | ||
| 475 | Div59, | ||
| 476 | Div60, | ||
| 477 | Div61, | ||
| 478 | Div62, | ||
| 479 | Div63, | ||
| 480 | } | ||
| 481 | |||
| 482 | impl MasterClockDivider { | ||
| 483 | #[cfg(any(sai_v1, sai_v2))] | ||
| 484 | const fn mckdiv(&self) -> u8 { | ||
| 485 | match self { | ||
| 486 | MasterClockDivider::MasterClockDisabled => 0, | ||
| 487 | MasterClockDivider::Div1 => 0, | ||
| 488 | MasterClockDivider::Div2 => 1, | ||
| 489 | MasterClockDivider::Div4 => 2, | ||
| 490 | MasterClockDivider::Div6 => 3, | ||
| 491 | MasterClockDivider::Div8 => 4, | ||
| 492 | MasterClockDivider::Div10 => 5, | ||
| 493 | MasterClockDivider::Div12 => 6, | ||
| 494 | MasterClockDivider::Div14 => 7, | ||
| 495 | MasterClockDivider::Div16 => 8, | ||
| 496 | MasterClockDivider::Div18 => 9, | ||
| 497 | MasterClockDivider::Div20 => 10, | ||
| 498 | MasterClockDivider::Div22 => 11, | ||
| 499 | MasterClockDivider::Div24 => 12, | ||
| 500 | MasterClockDivider::Div26 => 13, | ||
| 501 | MasterClockDivider::Div28 => 14, | ||
| 502 | MasterClockDivider::Div30 => 15, | ||
| 503 | } | ||
| 504 | } | ||
| 505 | |||
| 506 | #[cfg(any(sai_v1_4pdm, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | ||
| 507 | const fn mckdiv(&self) -> u8 { | ||
| 508 | match self { | ||
| 509 | MasterClockDivider::MasterClockDisabled => 0, | ||
| 510 | MasterClockDivider::Div1 => 1, | ||
| 511 | MasterClockDivider::Div2 => 2, | ||
| 512 | MasterClockDivider::Div3 => 3, | ||
| 513 | MasterClockDivider::Div4 => 4, | ||
| 514 | MasterClockDivider::Div5 => 5, | ||
| 515 | MasterClockDivider::Div6 => 6, | ||
| 516 | MasterClockDivider::Div7 => 7, | ||
| 517 | MasterClockDivider::Div8 => 8, | ||
| 518 | MasterClockDivider::Div9 => 9, | ||
| 519 | MasterClockDivider::Div10 => 10, | ||
| 520 | MasterClockDivider::Div11 => 11, | ||
| 521 | MasterClockDivider::Div12 => 12, | ||
| 522 | MasterClockDivider::Div13 => 13, | ||
| 523 | MasterClockDivider::Div14 => 14, | ||
| 524 | MasterClockDivider::Div15 => 15, | ||
| 525 | MasterClockDivider::Div16 => 16, | ||
| 526 | MasterClockDivider::Div17 => 17, | ||
| 527 | MasterClockDivider::Div18 => 18, | ||
| 528 | MasterClockDivider::Div19 => 19, | ||
| 529 | MasterClockDivider::Div20 => 20, | ||
| 530 | MasterClockDivider::Div21 => 21, | ||
| 531 | MasterClockDivider::Div22 => 22, | ||
| 532 | MasterClockDivider::Div23 => 23, | ||
| 533 | MasterClockDivider::Div24 => 24, | ||
| 534 | MasterClockDivider::Div25 => 25, | ||
| 535 | MasterClockDivider::Div26 => 26, | ||
| 536 | MasterClockDivider::Div27 => 27, | ||
| 537 | MasterClockDivider::Div28 => 28, | ||
| 538 | MasterClockDivider::Div29 => 29, | ||
| 539 | MasterClockDivider::Div30 => 30, | ||
| 540 | MasterClockDivider::Div31 => 31, | ||
| 541 | MasterClockDivider::Div32 => 32, | ||
| 542 | MasterClockDivider::Div33 => 33, | ||
| 543 | MasterClockDivider::Div34 => 34, | ||
| 544 | MasterClockDivider::Div35 => 35, | ||
| 545 | MasterClockDivider::Div36 => 36, | ||
| 546 | MasterClockDivider::Div37 => 37, | ||
| 547 | MasterClockDivider::Div38 => 38, | ||
| 548 | MasterClockDivider::Div39 => 39, | ||
| 549 | MasterClockDivider::Div40 => 40, | ||
| 550 | MasterClockDivider::Div41 => 41, | ||
| 551 | MasterClockDivider::Div42 => 42, | ||
| 552 | MasterClockDivider::Div43 => 43, | ||
| 553 | MasterClockDivider::Div44 => 44, | ||
| 554 | MasterClockDivider::Div45 => 45, | ||
| 555 | MasterClockDivider::Div46 => 46, | ||
| 556 | MasterClockDivider::Div47 => 47, | ||
| 557 | MasterClockDivider::Div48 => 48, | ||
| 558 | MasterClockDivider::Div49 => 49, | ||
| 559 | MasterClockDivider::Div50 => 50, | ||
| 560 | MasterClockDivider::Div51 => 51, | ||
| 561 | MasterClockDivider::Div52 => 52, | ||
| 562 | MasterClockDivider::Div53 => 53, | ||
| 563 | MasterClockDivider::Div54 => 54, | ||
| 564 | MasterClockDivider::Div55 => 55, | ||
| 565 | MasterClockDivider::Div56 => 56, | ||
| 566 | MasterClockDivider::Div57 => 57, | ||
| 567 | MasterClockDivider::Div58 => 58, | ||
| 568 | MasterClockDivider::Div59 => 59, | ||
| 569 | MasterClockDivider::Div60 => 60, | ||
| 570 | MasterClockDivider::Div61 => 61, | ||
| 571 | MasterClockDivider::Div62 => 62, | ||
| 572 | MasterClockDivider::Div63 => 63, | ||
| 573 | } | ||
| 574 | } | ||
| 575 | } | ||
| 576 | |||
| 577 | /// [`SAI`] configuration. | 373 | /// [`SAI`] configuration. |
| 578 | #[allow(missing_docs)] | 374 | #[allow(missing_docs)] |
| 579 | #[non_exhaustive] | 375 | #[non_exhaustive] |
| @@ -598,8 +394,7 @@ pub struct Config { | |||
| 598 | pub frame_length: u8, | 394 | pub frame_length: u8, |
| 599 | pub clock_strobe: ClockStrobe, | 395 | pub clock_strobe: ClockStrobe, |
| 600 | pub output_drive: OutputDrive, | 396 | pub output_drive: OutputDrive, |
| 601 | pub master_clock_divider: MasterClockDivider, | 397 | pub master_clock_divider: Option<MasterClockDivider>, |
| 602 | pub nodiv: bool, | ||
| 603 | pub is_high_impedance_on_inactive_slot: bool, | 398 | pub is_high_impedance_on_inactive_slot: bool, |
| 604 | pub fifo_threshold: FifoThreshold, | 399 | pub fifo_threshold: FifoThreshold, |
| 605 | pub companding: Companding, | 400 | pub companding: Companding, |
| @@ -628,8 +423,7 @@ impl Default for Config { | |||
| 628 | frame_sync_active_level_length: word::U7(16), | 423 | frame_sync_active_level_length: word::U7(16), |
| 629 | frame_sync_definition: FrameSyncDefinition::ChannelIdentification, | 424 | frame_sync_definition: FrameSyncDefinition::ChannelIdentification, |
| 630 | frame_length: 32, | 425 | frame_length: 32, |
| 631 | master_clock_divider: MasterClockDivider::MasterClockDisabled, | 426 | master_clock_divider: None, |
| 632 | nodiv: false, | ||
| 633 | clock_strobe: ClockStrobe::Rising, | 427 | clock_strobe: ClockStrobe::Rising, |
| 634 | output_drive: OutputDrive::Immediately, | 428 | output_drive: OutputDrive::Immediately, |
| 635 | is_high_impedance_on_inactive_slot: false, | 429 | is_high_impedance_on_inactive_slot: false, |
| @@ -706,7 +500,7 @@ fn update_synchronous_config(config: &mut Config) { | |||
| 706 | config.sync_input = SyncInput::Internal; | 500 | config.sync_input = SyncInput::Internal; |
| 707 | } | 501 | } |
| 708 | 502 | ||
| 709 | #[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | 503 | #[cfg(any(sai_v3, sai_v4))] |
| 710 | { | 504 | { |
| 711 | //this must either be Internal or External | 505 | //this must either be Internal or External |
| 712 | //The asynchronous sub-block on the same SAI needs to enable sync_output | 506 | //The asynchronous sub-block on the same SAI needs to enable sync_output |
| @@ -761,15 +555,11 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { | |||
| 761 | mclk: Peri<'d, impl MclkPin<T, S>>, | 555 | mclk: Peri<'d, impl MclkPin<T, S>>, |
| 762 | dma: Peri<'d, impl Channel + Dma<T, S>>, | 556 | dma: Peri<'d, impl Channel + Dma<T, S>>, |
| 763 | dma_buf: &'d mut [W], | 557 | dma_buf: &'d mut [W], |
| 764 | mut config: Config, | 558 | config: Config, |
| 765 | ) -> Self { | 559 | ) -> Self { |
| 766 | let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); | 560 | let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); |
| 767 | mclk.set_as_af(mclk.af_num(), ck_af_type); | 561 | mclk.set_as_af(mclk.af_num(), ck_af_type); |
| 768 | 562 | ||
| 769 | if config.master_clock_divider == MasterClockDivider::MasterClockDisabled { | ||
| 770 | config.master_clock_divider = MasterClockDivider::Div1; | ||
| 771 | } | ||
| 772 | |||
| 773 | Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config) | 563 | Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config) |
| 774 | } | 564 | } |
| 775 | 565 | ||
| @@ -851,14 +641,11 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { | |||
| 851 | ) -> Self { | 641 | ) -> Self { |
| 852 | let ch = T::REGS.ch(sub_block as usize); | 642 | let ch = T::REGS.ch(sub_block as usize); |
| 853 | 643 | ||
| 854 | #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | 644 | ch.cr1().modify(|w| w.set_saien(false)); |
| 855 | { | ||
| 856 | ch.cr1().modify(|w| w.set_saien(false)); | ||
| 857 | } | ||
| 858 | 645 | ||
| 859 | ch.cr2().modify(|w| w.set_fflush(true)); | 646 | ch.cr2().modify(|w| w.set_fflush(true)); |
| 860 | 647 | ||
| 861 | #[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | 648 | #[cfg(any(sai_v3, sai_v4))] |
| 862 | { | 649 | { |
| 863 | if let SyncInput::External(i) = config.sync_input { | 650 | if let SyncInput::External(i) = config.sync_input { |
| 864 | T::REGS.gcr().modify(|w| { | 651 | T::REGS.gcr().modify(|w| { |
| @@ -877,55 +664,52 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { | |||
| 877 | } | 664 | } |
| 878 | } | 665 | } |
| 879 | 666 | ||
| 880 | #[cfg(any(sai_v1, sai_v1_4pdm, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] | 667 | ch.cr1().modify(|w| { |
| 881 | { | 668 | w.set_mode(config.mode.mode(if Self::is_transmitter(&ring_buffer) { |
| 882 | ch.cr1().modify(|w| { | 669 | TxRx::Transmitter |
| 883 | w.set_mode(config.mode.mode(if Self::is_transmitter(&ring_buffer) { | 670 | } else { |
| 884 | TxRx::Transmitter | 671 | TxRx::Receiver |
| 885 | } else { | 672 | })); |
| 886 | TxRx::Receiver | 673 | w.set_prtcfg(config.protocol.prtcfg()); |
| 887 | })); | 674 | w.set_ds(config.data_size.ds()); |
| 888 | w.set_prtcfg(config.protocol.prtcfg()); | 675 | w.set_lsbfirst(config.bit_order.lsbfirst()); |
| 889 | w.set_ds(config.data_size.ds()); | 676 | w.set_ckstr(config.clock_strobe.ckstr()); |
| 890 | w.set_lsbfirst(config.bit_order.lsbfirst()); | 677 | w.set_syncen(config.sync_input.syncen()); |
| 891 | w.set_ckstr(config.clock_strobe.ckstr()); | 678 | w.set_mono(config.stereo_mono.mono()); |
| 892 | w.set_syncen(config.sync_input.syncen()); | 679 | w.set_outdriv(config.output_drive.outdriv()); |
| 893 | w.set_mono(config.stereo_mono.mono()); | 680 | w.set_mckdiv(config.master_clock_divider.unwrap_or(MasterClockDivider::DIV1)); |
| 894 | w.set_outdriv(config.output_drive.outdriv()); | 681 | w.set_nodiv(config.master_clock_divider.is_none()); |
| 895 | w.set_mckdiv(config.master_clock_divider.mckdiv().into()); | 682 | w.set_dmaen(true); |
| 896 | w.set_nodiv(config.nodiv); | 683 | }); |
| 897 | w.set_dmaen(true); | 684 | |
| 898 | }); | 685 | ch.cr2().modify(|w| { |
| 899 | 686 | w.set_fth(config.fifo_threshold.fth()); | |
| 900 | ch.cr2().modify(|w| { | 687 | w.set_comp(config.companding.comp()); |
| 901 | w.set_fth(config.fifo_threshold.fth()); | 688 | w.set_cpl(config.complement_format.cpl()); |
| 902 | w.set_comp(config.companding.comp()); | 689 | w.set_muteval(config.mute_value.muteval()); |
| 903 | w.set_cpl(config.complement_format.cpl()); | 690 | w.set_mutecnt(config.mute_detection_counter.0 as u8); |
| 904 | w.set_muteval(config.mute_value.muteval()); | 691 | w.set_tris(config.is_high_impedance_on_inactive_slot); |
| 905 | w.set_mutecnt(config.mute_detection_counter.0 as u8); | 692 | }); |
| 906 | w.set_tris(config.is_high_impedance_on_inactive_slot); | 693 | |
| 907 | }); | 694 | ch.frcr().modify(|w| { |
| 908 | 695 | w.set_fsoff(config.frame_sync_offset.fsoff()); | |
| 909 | ch.frcr().modify(|w| { | 696 | w.set_fspol(config.frame_sync_polarity.fspol()); |
| 910 | w.set_fsoff(config.frame_sync_offset.fsoff()); | 697 | w.set_fsdef(config.frame_sync_definition.fsdef()); |
| 911 | w.set_fspol(config.frame_sync_polarity.fspol()); | 698 | w.set_fsall(config.frame_sync_active_level_length.0 as u8 - 1); |
| 912 | w.set_fsdef(config.frame_sync_definition.fsdef()); | 699 | w.set_frl(config.frame_length - 1); |
| 913 | w.set_fsall(config.frame_sync_active_level_length.0 as u8 - 1); | 700 | }); |
| 914 | w.set_frl(config.frame_length - 1); | 701 | |
| 915 | }); | 702 | ch.slotr().modify(|w| { |
| 916 | 703 | w.set_nbslot(config.slot_count.0 as u8 - 1); | |
| 917 | ch.slotr().modify(|w| { | 704 | w.set_slotsz(config.slot_size.slotsz()); |
| 918 | w.set_nbslot(config.slot_count.0 as u8 - 1); | 705 | w.set_fboff(config.first_bit_offset.0 as u8); |
| 919 | w.set_slotsz(config.slot_size.slotsz()); | 706 | w.set_sloten(vals::Sloten::from_bits(config.slot_enable as u16)); |
| 920 | w.set_fboff(config.first_bit_offset.0 as u8); | 707 | }); |
| 921 | w.set_sloten(vals::Sloten::from_bits(config.slot_enable as u16)); | 708 | |
| 922 | }); | 709 | ch.cr1().modify(|w| w.set_saien(true)); |
| 923 | 710 | ||
| 924 | ch.cr1().modify(|w| w.set_saien(true)); | 711 | if ch.cr1().read().saien() == false { |
| 925 | 712 | panic!("SAI failed to enable. Check that config is valid (frame length, slot count, etc)"); | |
| 926 | if ch.cr1().read().saien() == false { | ||
| 927 | panic!("SAI failed to enable. Check that config is valid (frame length, slot count, etc)"); | ||
| 928 | } | ||
| 929 | } | 713 | } |
| 930 | 714 | ||
| 931 | Self { | 715 | Self { |
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 4c5308eba..a49ebcbee 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs | |||
| @@ -174,7 +174,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { | |||
| 174 | self.info.rcc.enable_and_reset(); | 174 | self.info.rcc.enable_and_reset(); |
| 175 | 175 | ||
| 176 | let regs = self.info.regs; | 176 | let regs = self.info.regs; |
| 177 | #[cfg(any(spi_v1, spi_f1))] | 177 | #[cfg(any(spi_v1, spi_v2))] |
| 178 | { | 178 | { |
| 179 | regs.cr2().modify(|w| { | 179 | regs.cr2().modify(|w| { |
| 180 | w.set_ssoe(false); | 180 | w.set_ssoe(false); |
| @@ -198,7 +198,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { | |||
| 198 | w.set_dff(<u8 as SealedWord>::CONFIG) | 198 | w.set_dff(<u8 as SealedWord>::CONFIG) |
| 199 | }); | 199 | }); |
| 200 | } | 200 | } |
| 201 | #[cfg(spi_v2)] | 201 | #[cfg(spi_v3)] |
| 202 | { | 202 | { |
| 203 | regs.cr2().modify(|w| { | 203 | regs.cr2().modify(|w| { |
| 204 | let (ds, frxth) = <u8 as SealedWord>::CONFIG; | 204 | let (ds, frxth) = <u8 as SealedWord>::CONFIG; |
| @@ -220,7 +220,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { | |||
| 220 | w.set_spe(true); | 220 | w.set_spe(true); |
| 221 | }); | 221 | }); |
| 222 | } | 222 | } |
| 223 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 223 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 224 | { | 224 | { |
| 225 | regs.ifcr().write(|w| w.0 = 0xffff_ffff); | 225 | regs.ifcr().write(|w| w.0 = 0xffff_ffff); |
| 226 | regs.cfg2().modify(|w| { | 226 | regs.cfg2().modify(|w| { |
| @@ -274,7 +274,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { | |||
| 274 | } | 274 | } |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | #[cfg(any(spi_v1, spi_f1, spi_v2))] | 277 | #[cfg(any(spi_v1, spi_v2, spi_v3))] |
| 278 | self.info.regs.cr1().modify(|w| { | 278 | self.info.regs.cr1().modify(|w| { |
| 279 | w.set_cpha(cpha); | 279 | w.set_cpha(cpha); |
| 280 | w.set_cpol(cpol); | 280 | w.set_cpol(cpol); |
| @@ -282,7 +282,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { | |||
| 282 | w.set_lsbfirst(lsbfirst); | 282 | w.set_lsbfirst(lsbfirst); |
| 283 | }); | 283 | }); |
| 284 | 284 | ||
| 285 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 285 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 286 | { | 286 | { |
| 287 | self.info.regs.cr1().modify(|w| { | 287 | self.info.regs.cr1().modify(|w| { |
| 288 | w.set_spe(false); | 288 | w.set_spe(false); |
| @@ -306,11 +306,11 @@ impl<'d, M: PeriMode> Spi<'d, M> { | |||
| 306 | 306 | ||
| 307 | /// Get current SPI configuration. | 307 | /// Get current SPI configuration. |
| 308 | pub fn get_current_config(&self) -> Config { | 308 | pub fn get_current_config(&self) -> Config { |
| 309 | #[cfg(any(spi_v1, spi_f1, spi_v2))] | 309 | #[cfg(any(spi_v1, spi_v2, spi_v3))] |
| 310 | let cfg = self.info.regs.cr1().read(); | 310 | let cfg = self.info.regs.cr1().read(); |
| 311 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 311 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 312 | let cfg = self.info.regs.cfg2().read(); | 312 | let cfg = self.info.regs.cfg2().read(); |
| 313 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 313 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 314 | let cfg1 = self.info.regs.cfg1().read(); | 314 | let cfg1 = self.info.regs.cfg1().read(); |
| 315 | 315 | ||
| 316 | let polarity = if cfg.cpol() == vals::Cpol::IDLE_LOW { | 316 | let polarity = if cfg.cpol() == vals::Cpol::IDLE_LOW { |
| @@ -335,9 +335,9 @@ impl<'d, M: PeriMode> Spi<'d, M> { | |||
| 335 | Some(pin) => pin.pull(), | 335 | Some(pin) => pin.pull(), |
| 336 | }; | 336 | }; |
| 337 | 337 | ||
| 338 | #[cfg(any(spi_v1, spi_f1, spi_v2))] | 338 | #[cfg(any(spi_v1, spi_v2, spi_v3))] |
| 339 | let br = cfg.br(); | 339 | let br = cfg.br(); |
| 340 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 340 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 341 | let br = cfg1.mbr(); | 341 | let br = cfg1.mbr(); |
| 342 | 342 | ||
| 343 | let frequency = compute_frequency(self.kernel_clock, br); | 343 | let frequency = compute_frequency(self.kernel_clock, br); |
| @@ -360,16 +360,16 @@ impl<'d, M: PeriMode> Spi<'d, M> { | |||
| 360 | w.set_spe(false); | 360 | w.set_spe(false); |
| 361 | }); | 361 | }); |
| 362 | 362 | ||
| 363 | #[cfg(any(spi_v1, spi_f1))] | 363 | #[cfg(any(spi_v1, spi_v2))] |
| 364 | self.info.regs.cr1().modify(|reg| { | 364 | self.info.regs.cr1().modify(|reg| { |
| 365 | reg.set_dff(word_size); | 365 | reg.set_dff(word_size); |
| 366 | }); | 366 | }); |
| 367 | #[cfg(spi_v2)] | 367 | #[cfg(spi_v3)] |
| 368 | self.info.regs.cr2().modify(|w| { | 368 | self.info.regs.cr2().modify(|w| { |
| 369 | w.set_frxth(word_size.1); | 369 | w.set_frxth(word_size.1); |
| 370 | w.set_ds(word_size.0); | 370 | w.set_ds(word_size.0); |
| 371 | }); | 371 | }); |
| 372 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 372 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 373 | self.info.regs.cfg1().modify(|w| { | 373 | self.info.regs.cfg1().modify(|w| { |
| 374 | w.set_dsize(word_size); | 374 | w.set_dsize(word_size); |
| 375 | }); | 375 | }); |
| @@ -380,7 +380,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { | |||
| 380 | /// Blocking write. | 380 | /// Blocking write. |
| 381 | pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> { | 381 | pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> { |
| 382 | // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? | 382 | // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? |
| 383 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 383 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 384 | self.info.regs.cr1().modify(|w| w.set_spe(false)); | 384 | self.info.regs.cr1().modify(|w| w.set_spe(false)); |
| 385 | self.set_word_size(W::CONFIG); | 385 | self.set_word_size(W::CONFIG); |
| 386 | self.info.regs.cr1().modify(|w| w.set_spe(true)); | 386 | self.info.regs.cr1().modify(|w| w.set_spe(true)); |
| @@ -391,7 +391,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { | |||
| 391 | // This is the case when the SPI has been created with `new_(blocking_?)txonly_nosck`. | 391 | // This is the case when the SPI has been created with `new_(blocking_?)txonly_nosck`. |
| 392 | // See https://github.com/embassy-rs/embassy/issues/2902 | 392 | // See https://github.com/embassy-rs/embassy/issues/2902 |
| 393 | // This is not documented as an errata by ST, and I've been unable to find anything online... | 393 | // This is not documented as an errata by ST, and I've been unable to find anything online... |
| 394 | #[cfg(not(any(spi_v1, spi_f1)))] | 394 | #[cfg(not(any(spi_v1, spi_v2)))] |
| 395 | write_word(self.info.regs, *word)?; | 395 | write_word(self.info.regs, *word)?; |
| 396 | 396 | ||
| 397 | // if we're doing tx only, after writing the last byte to FIFO we have to wait | 397 | // if we're doing tx only, after writing the last byte to FIFO we have to wait |
| @@ -401,14 +401,14 @@ impl<'d, M: PeriMode> Spi<'d, M> { | |||
| 401 | // Luckily this doesn't affect SPIv2+. | 401 | // Luckily this doesn't affect SPIv2+. |
| 402 | // See http://efton.sk/STM32/gotcha/g68.html | 402 | // See http://efton.sk/STM32/gotcha/g68.html |
| 403 | // ST doesn't seem to document this in errata sheets (?) | 403 | // ST doesn't seem to document this in errata sheets (?) |
| 404 | #[cfg(any(spi_v1, spi_f1))] | 404 | #[cfg(any(spi_v1, spi_v2))] |
| 405 | transfer_word(self.info.regs, *word)?; | 405 | transfer_word(self.info.regs, *word)?; |
| 406 | } | 406 | } |
| 407 | 407 | ||
| 408 | // wait until last word is transmitted. (except on v1, see above) | 408 | // wait until last word is transmitted. (except on v1, see above) |
| 409 | #[cfg(not(any(spi_v1, spi_f1, spi_v2)))] | 409 | #[cfg(not(any(spi_v1, spi_v2, spi_v3)))] |
| 410 | while !self.info.regs.sr().read().txc() {} | 410 | while !self.info.regs.sr().read().txc() {} |
| 411 | #[cfg(spi_v2)] | 411 | #[cfg(spi_v3)] |
| 412 | while self.info.regs.sr().read().bsy() {} | 412 | while self.info.regs.sr().read().bsy() {} |
| 413 | 413 | ||
| 414 | Ok(()) | 414 | Ok(()) |
| @@ -417,7 +417,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { | |||
| 417 | /// Blocking read. | 417 | /// Blocking read. |
| 418 | pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { | 418 | pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { |
| 419 | // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? | 419 | // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? |
| 420 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 420 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 421 | self.info.regs.cr1().modify(|w| w.set_spe(false)); | 421 | self.info.regs.cr1().modify(|w| w.set_spe(false)); |
| 422 | self.set_word_size(W::CONFIG); | 422 | self.set_word_size(W::CONFIG); |
| 423 | self.info.regs.cr1().modify(|w| w.set_spe(true)); | 423 | self.info.regs.cr1().modify(|w| w.set_spe(true)); |
| @@ -433,7 +433,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { | |||
| 433 | /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time. | 433 | /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time. |
| 434 | pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { | 434 | pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { |
| 435 | // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? | 435 | // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? |
| 436 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 436 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 437 | self.info.regs.cr1().modify(|w| w.set_spe(false)); | 437 | self.info.regs.cr1().modify(|w| w.set_spe(false)); |
| 438 | self.set_word_size(W::CONFIG); | 438 | self.set_word_size(W::CONFIG); |
| 439 | self.info.regs.cr1().modify(|w| w.set_spe(true)); | 439 | self.info.regs.cr1().modify(|w| w.set_spe(true)); |
| @@ -452,7 +452,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { | |||
| 452 | /// If `write` is shorter it is padded with zero bytes. | 452 | /// If `write` is shorter it is padded with zero bytes. |
| 453 | pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { | 453 | pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { |
| 454 | // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? | 454 | // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? |
| 455 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 455 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 456 | self.info.regs.cr1().modify(|w| w.set_spe(false)); | 456 | self.info.regs.cr1().modify(|w| w.set_spe(false)); |
| 457 | self.set_word_size(W::CONFIG); | 457 | self.set_word_size(W::CONFIG); |
| 458 | self.info.regs.cr1().modify(|w| w.set_spe(true)); | 458 | self.info.regs.cr1().modify(|w| w.set_spe(true)); |
| @@ -572,7 +572,7 @@ impl<'d> Spi<'d, Async> { | |||
| 572 | peri: Peri<'d, T>, | 572 | peri: Peri<'d, T>, |
| 573 | sck: Peri<'d, impl SckPin<T>>, | 573 | sck: Peri<'d, impl SckPin<T>>, |
| 574 | miso: Peri<'d, impl MisoPin<T>>, | 574 | miso: Peri<'d, impl MisoPin<T>>, |
| 575 | #[cfg(any(spi_v1, spi_f1, spi_v2))] tx_dma: Peri<'d, impl TxDma<T>>, | 575 | #[cfg(any(spi_v1, spi_v2, spi_v3))] tx_dma: Peri<'d, impl TxDma<T>>, |
| 576 | rx_dma: Peri<'d, impl RxDma<T>>, | 576 | rx_dma: Peri<'d, impl RxDma<T>>, |
| 577 | config: Config, | 577 | config: Config, |
| 578 | ) -> Self { | 578 | ) -> Self { |
| @@ -581,9 +581,9 @@ impl<'d> Spi<'d, Async> { | |||
| 581 | new_pin!(sck, config.sck_af()), | 581 | new_pin!(sck, config.sck_af()), |
| 582 | None, | 582 | None, |
| 583 | new_pin!(miso, AfType::input(config.miso_pull)), | 583 | new_pin!(miso, AfType::input(config.miso_pull)), |
| 584 | #[cfg(any(spi_v1, spi_f1, spi_v2))] | 584 | #[cfg(any(spi_v1, spi_v2, spi_v3))] |
| 585 | new_dma!(tx_dma), | 585 | new_dma!(tx_dma), |
| 586 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 586 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 587 | None, | 587 | None, |
| 588 | new_dma!(rx_dma), | 588 | new_dma!(rx_dma), |
| 589 | config, | 589 | config, |
| @@ -677,7 +677,7 @@ impl<'d> Spi<'d, Async> { | |||
| 677 | self.info.regs.cr1().modify(|w| { | 677 | self.info.regs.cr1().modify(|w| { |
| 678 | w.set_spe(true); | 678 | w.set_spe(true); |
| 679 | }); | 679 | }); |
| 680 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 680 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 681 | self.info.regs.cr1().modify(|w| { | 681 | self.info.regs.cr1().modify(|w| { |
| 682 | w.set_cstart(true); | 682 | w.set_cstart(true); |
| 683 | }); | 683 | }); |
| @@ -690,7 +690,7 @@ impl<'d> Spi<'d, Async> { | |||
| 690 | } | 690 | } |
| 691 | 691 | ||
| 692 | /// SPI read, using DMA. | 692 | /// SPI read, using DMA. |
| 693 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 693 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 694 | pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> { | 694 | pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> { |
| 695 | if data.is_empty() { | 695 | if data.is_empty() { |
| 696 | return Ok(()); | 696 | return Ok(()); |
| @@ -710,7 +710,7 @@ impl<'d> Spi<'d, Async> { | |||
| 710 | prev | 710 | prev |
| 711 | }); | 711 | }); |
| 712 | 712 | ||
| 713 | #[cfg(spi_v3)] | 713 | #[cfg(spi_v4)] |
| 714 | let i2scfg = regs.i2scfgr().modify(|w| { | 714 | let i2scfg = regs.i2scfgr().modify(|w| { |
| 715 | w.i2smod().then(|| { | 715 | w.i2smod().then(|| { |
| 716 | let prev = w.i2scfg(); | 716 | let prev = w.i2scfg(); |
| @@ -766,7 +766,7 @@ impl<'d> Spi<'d, Async> { | |||
| 766 | w.set_tsize(0); | 766 | w.set_tsize(0); |
| 767 | }); | 767 | }); |
| 768 | 768 | ||
| 769 | #[cfg(spi_v3)] | 769 | #[cfg(spi_v4)] |
| 770 | if let Some(i2scfg) = i2scfg { | 770 | if let Some(i2scfg) = i2scfg { |
| 771 | regs.i2scfgr().modify(|w| { | 771 | regs.i2scfgr().modify(|w| { |
| 772 | w.set_i2scfg(i2scfg); | 772 | w.set_i2scfg(i2scfg); |
| @@ -777,7 +777,7 @@ impl<'d> Spi<'d, Async> { | |||
| 777 | } | 777 | } |
| 778 | 778 | ||
| 779 | /// SPI read, using DMA. | 779 | /// SPI read, using DMA. |
| 780 | #[cfg(any(spi_v1, spi_f1, spi_v2))] | 780 | #[cfg(any(spi_v1, spi_v2, spi_v3))] |
| 781 | pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> { | 781 | pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> { |
| 782 | if data.is_empty() { | 782 | if data.is_empty() { |
| 783 | return Ok(()); | 783 | return Ok(()); |
| @@ -790,7 +790,7 @@ impl<'d> Spi<'d, Async> { | |||
| 790 | self.set_word_size(W::CONFIG); | 790 | self.set_word_size(W::CONFIG); |
| 791 | 791 | ||
| 792 | // SPIv3 clears rxfifo on SPE=0 | 792 | // SPIv3 clears rxfifo on SPE=0 |
| 793 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | 793 | #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] |
| 794 | flush_rx_fifo(self.info.regs); | 794 | flush_rx_fifo(self.info.regs); |
| 795 | 795 | ||
| 796 | set_rxdmaen(self.info.regs, true); | 796 | set_rxdmaen(self.info.regs, true); |
| @@ -813,7 +813,7 @@ impl<'d> Spi<'d, Async> { | |||
| 813 | self.info.regs.cr1().modify(|w| { | 813 | self.info.regs.cr1().modify(|w| { |
| 814 | w.set_spe(true); | 814 | w.set_spe(true); |
| 815 | }); | 815 | }); |
| 816 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 816 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 817 | self.info.regs.cr1().modify(|w| { | 817 | self.info.regs.cr1().modify(|w| { |
| 818 | w.set_cstart(true); | 818 | w.set_cstart(true); |
| 819 | }); | 819 | }); |
| @@ -838,7 +838,7 @@ impl<'d> Spi<'d, Async> { | |||
| 838 | self.set_word_size(W::CONFIG); | 838 | self.set_word_size(W::CONFIG); |
| 839 | 839 | ||
| 840 | // SPIv3 clears rxfifo on SPE=0 | 840 | // SPIv3 clears rxfifo on SPE=0 |
| 841 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | 841 | #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] |
| 842 | flush_rx_fifo(self.info.regs); | 842 | flush_rx_fifo(self.info.regs); |
| 843 | 843 | ||
| 844 | set_rxdmaen(self.info.regs, true); | 844 | set_rxdmaen(self.info.regs, true); |
| @@ -858,7 +858,7 @@ impl<'d> Spi<'d, Async> { | |||
| 858 | self.info.regs.cr1().modify(|w| { | 858 | self.info.regs.cr1().modify(|w| { |
| 859 | w.set_spe(true); | 859 | w.set_spe(true); |
| 860 | }); | 860 | }); |
| 861 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 861 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 862 | self.info.regs.cr1().modify(|w| { | 862 | self.info.regs.cr1().modify(|w| { |
| 863 | w.set_cstart(true); | 863 | w.set_cstart(true); |
| 864 | }); | 864 | }); |
| @@ -898,9 +898,9 @@ impl<'d, M: PeriMode> Drop for Spi<'d, M> { | |||
| 898 | } | 898 | } |
| 899 | } | 899 | } |
| 900 | 900 | ||
| 901 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | 901 | #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] |
| 902 | use vals::Br; | 902 | use vals::Br; |
| 903 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 903 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 904 | use vals::Mbr as Br; | 904 | use vals::Mbr as Br; |
| 905 | 905 | ||
| 906 | fn compute_baud_rate(kernel_clock: Hertz, freq: Hertz) -> Br { | 906 | fn compute_baud_rate(kernel_clock: Hertz, freq: Hertz) -> Br { |
| @@ -941,21 +941,21 @@ pub(crate) trait RegsExt { | |||
| 941 | 941 | ||
| 942 | impl RegsExt for Regs { | 942 | impl RegsExt for Regs { |
| 943 | fn tx_ptr<W>(&self) -> *mut W { | 943 | fn tx_ptr<W>(&self) -> *mut W { |
| 944 | #[cfg(any(spi_v1, spi_f1))] | 944 | #[cfg(any(spi_v1, spi_v2))] |
| 945 | let dr = self.dr(); | 945 | let dr = self.dr(); |
| 946 | #[cfg(spi_v2)] | 946 | #[cfg(spi_v3)] |
| 947 | let dr = self.dr16(); | 947 | let dr = self.dr16(); |
| 948 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 948 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 949 | let dr = self.txdr32(); | 949 | let dr = self.txdr32(); |
| 950 | dr.as_ptr() as *mut W | 950 | dr.as_ptr() as *mut W |
| 951 | } | 951 | } |
| 952 | 952 | ||
| 953 | fn rx_ptr<W>(&self) -> *mut W { | 953 | fn rx_ptr<W>(&self) -> *mut W { |
| 954 | #[cfg(any(spi_v1, spi_f1))] | 954 | #[cfg(any(spi_v1, spi_v2))] |
| 955 | let dr = self.dr(); | 955 | let dr = self.dr(); |
| 956 | #[cfg(spi_v2)] | 956 | #[cfg(spi_v3)] |
| 957 | let dr = self.dr16(); | 957 | let dr = self.dr16(); |
| 958 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 958 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 959 | let dr = self.rxdr32(); | 959 | let dr = self.rxdr32(); |
| 960 | dr.as_ptr() as *mut W | 960 | dr.as_ptr() as *mut W |
| 961 | } | 961 | } |
| @@ -965,22 +965,22 @@ fn check_error_flags(sr: regs::Sr, ovr: bool) -> Result<(), Error> { | |||
| 965 | if sr.ovr() && ovr { | 965 | if sr.ovr() && ovr { |
| 966 | return Err(Error::Overrun); | 966 | return Err(Error::Overrun); |
| 967 | } | 967 | } |
| 968 | #[cfg(not(any(spi_f1, spi_v3, spi_v4, spi_v5)))] | 968 | #[cfg(not(any(spi_v1, spi_v4, spi_v5, spi_v6)))] |
| 969 | if sr.fre() { | 969 | if sr.fre() { |
| 970 | return Err(Error::Framing); | 970 | return Err(Error::Framing); |
| 971 | } | 971 | } |
| 972 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 972 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 973 | if sr.tifre() { | 973 | if sr.tifre() { |
| 974 | return Err(Error::Framing); | 974 | return Err(Error::Framing); |
| 975 | } | 975 | } |
| 976 | if sr.modf() { | 976 | if sr.modf() { |
| 977 | return Err(Error::ModeFault); | 977 | return Err(Error::ModeFault); |
| 978 | } | 978 | } |
| 979 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | 979 | #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] |
| 980 | if sr.crcerr() { | 980 | if sr.crcerr() { |
| 981 | return Err(Error::Crc); | 981 | return Err(Error::Crc); |
| 982 | } | 982 | } |
| 983 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 983 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 984 | if sr.crce() { | 984 | if sr.crce() { |
| 985 | return Err(Error::Crc); | 985 | return Err(Error::Crc); |
| 986 | } | 986 | } |
| @@ -994,11 +994,11 @@ fn spin_until_tx_ready(regs: Regs, ovr: bool) -> Result<(), Error> { | |||
| 994 | 994 | ||
| 995 | check_error_flags(sr, ovr)?; | 995 | check_error_flags(sr, ovr)?; |
| 996 | 996 | ||
| 997 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | 997 | #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] |
| 998 | if sr.txe() { | 998 | if sr.txe() { |
| 999 | return Ok(()); | 999 | return Ok(()); |
| 1000 | } | 1000 | } |
| 1001 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 1001 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 1002 | if sr.txp() { | 1002 | if sr.txp() { |
| 1003 | return Ok(()); | 1003 | return Ok(()); |
| 1004 | } | 1004 | } |
| @@ -1011,11 +1011,11 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> { | |||
| 1011 | 1011 | ||
| 1012 | check_error_flags(sr, true)?; | 1012 | check_error_flags(sr, true)?; |
| 1013 | 1013 | ||
| 1014 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | 1014 | #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] |
| 1015 | if sr.rxne() { | 1015 | if sr.rxne() { |
| 1016 | return Ok(()); | 1016 | return Ok(()); |
| 1017 | } | 1017 | } |
| 1018 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 1018 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 1019 | if sr.rxp() { | 1019 | if sr.rxp() { |
| 1020 | return Ok(()); | 1020 | return Ok(()); |
| 1021 | } | 1021 | } |
| @@ -1023,46 +1023,46 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> { | |||
| 1023 | } | 1023 | } |
| 1024 | 1024 | ||
| 1025 | pub(crate) fn flush_rx_fifo(regs: Regs) { | 1025 | pub(crate) fn flush_rx_fifo(regs: Regs) { |
| 1026 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | 1026 | #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] |
| 1027 | while regs.sr().read().rxne() { | 1027 | while regs.sr().read().rxne() { |
| 1028 | #[cfg(not(spi_v2))] | 1028 | #[cfg(not(spi_v3))] |
| 1029 | let _ = regs.dr().read(); | 1029 | let _ = regs.dr().read(); |
| 1030 | #[cfg(spi_v2)] | 1030 | #[cfg(spi_v3)] |
| 1031 | let _ = regs.dr16().read(); | 1031 | let _ = regs.dr16().read(); |
| 1032 | } | 1032 | } |
| 1033 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 1033 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 1034 | while regs.sr().read().rxp() { | 1034 | while regs.sr().read().rxp() { |
| 1035 | let _ = regs.rxdr32().read(); | 1035 | let _ = regs.rxdr32().read(); |
| 1036 | } | 1036 | } |
| 1037 | } | 1037 | } |
| 1038 | 1038 | ||
| 1039 | pub(crate) fn set_txdmaen(regs: Regs, val: bool) { | 1039 | pub(crate) fn set_txdmaen(regs: Regs, val: bool) { |
| 1040 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | 1040 | #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] |
| 1041 | regs.cr2().modify(|reg| { | 1041 | regs.cr2().modify(|reg| { |
| 1042 | reg.set_txdmaen(val); | 1042 | reg.set_txdmaen(val); |
| 1043 | }); | 1043 | }); |
| 1044 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 1044 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 1045 | regs.cfg1().modify(|reg| { | 1045 | regs.cfg1().modify(|reg| { |
| 1046 | reg.set_txdmaen(val); | 1046 | reg.set_txdmaen(val); |
| 1047 | }); | 1047 | }); |
| 1048 | } | 1048 | } |
| 1049 | 1049 | ||
| 1050 | pub(crate) fn set_rxdmaen(regs: Regs, val: bool) { | 1050 | pub(crate) fn set_rxdmaen(regs: Regs, val: bool) { |
| 1051 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | 1051 | #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] |
| 1052 | regs.cr2().modify(|reg| { | 1052 | regs.cr2().modify(|reg| { |
| 1053 | reg.set_rxdmaen(val); | 1053 | reg.set_rxdmaen(val); |
| 1054 | }); | 1054 | }); |
| 1055 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 1055 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 1056 | regs.cfg1().modify(|reg| { | 1056 | regs.cfg1().modify(|reg| { |
| 1057 | reg.set_rxdmaen(val); | 1057 | reg.set_rxdmaen(val); |
| 1058 | }); | 1058 | }); |
| 1059 | } | 1059 | } |
| 1060 | 1060 | ||
| 1061 | fn finish_dma(regs: Regs) { | 1061 | fn finish_dma(regs: Regs) { |
| 1062 | #[cfg(spi_v2)] | 1062 | #[cfg(spi_v3)] |
| 1063 | while regs.sr().read().ftlvl().to_bits() > 0 {} | 1063 | while regs.sr().read().ftlvl().to_bits() > 0 {} |
| 1064 | 1064 | ||
| 1065 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 1065 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 1066 | { | 1066 | { |
| 1067 | if regs.cr2().read().tsize() == 0 { | 1067 | if regs.cr2().read().tsize() == 0 { |
| 1068 | while !regs.sr().read().txc() {} | 1068 | while !regs.sr().read().txc() {} |
| @@ -1070,7 +1070,7 @@ fn finish_dma(regs: Regs) { | |||
| 1070 | while !regs.sr().read().eot() {} | 1070 | while !regs.sr().read().eot() {} |
| 1071 | } | 1071 | } |
| 1072 | } | 1072 | } |
| 1073 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | 1073 | #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] |
| 1074 | while regs.sr().read().bsy() {} | 1074 | while regs.sr().read().bsy() {} |
| 1075 | 1075 | ||
| 1076 | // Disable the spi peripheral | 1076 | // Disable the spi peripheral |
| @@ -1080,12 +1080,12 @@ fn finish_dma(regs: Regs) { | |||
| 1080 | 1080 | ||
| 1081 | // The peripheral automatically disables the DMA stream on completion without error, | 1081 | // The peripheral automatically disables the DMA stream on completion without error, |
| 1082 | // but it does not clear the RXDMAEN/TXDMAEN flag in CR2. | 1082 | // but it does not clear the RXDMAEN/TXDMAEN flag in CR2. |
| 1083 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | 1083 | #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] |
| 1084 | regs.cr2().modify(|reg| { | 1084 | regs.cr2().modify(|reg| { |
| 1085 | reg.set_txdmaen(false); | 1085 | reg.set_txdmaen(false); |
| 1086 | reg.set_rxdmaen(false); | 1086 | reg.set_rxdmaen(false); |
| 1087 | }); | 1087 | }); |
| 1088 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 1088 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 1089 | regs.cfg1().modify(|reg| { | 1089 | regs.cfg1().modify(|reg| { |
| 1090 | reg.set_txdmaen(false); | 1090 | reg.set_txdmaen(false); |
| 1091 | reg.set_rxdmaen(false); | 1091 | reg.set_rxdmaen(false); |
| @@ -1098,7 +1098,7 @@ fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> { | |||
| 1098 | unsafe { | 1098 | unsafe { |
| 1099 | ptr::write_volatile(regs.tx_ptr(), tx_word); | 1099 | ptr::write_volatile(regs.tx_ptr(), tx_word); |
| 1100 | 1100 | ||
| 1101 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 1101 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 1102 | regs.cr1().modify(|reg| reg.set_cstart(true)); | 1102 | regs.cr1().modify(|reg| reg.set_cstart(true)); |
| 1103 | } | 1103 | } |
| 1104 | 1104 | ||
| @@ -1117,7 +1117,7 @@ fn write_word<W: Word>(regs: Regs, tx_word: W) -> Result<(), Error> { | |||
| 1117 | unsafe { | 1117 | unsafe { |
| 1118 | ptr::write_volatile(regs.tx_ptr(), tx_word); | 1118 | ptr::write_volatile(regs.tx_ptr(), tx_word); |
| 1119 | 1119 | ||
| 1120 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 1120 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 1121 | regs.cr1().modify(|reg| reg.set_cstart(true)); | 1121 | regs.cr1().modify(|reg| reg.set_cstart(true)); |
| 1122 | } | 1122 | } |
| 1123 | Ok(()) | 1123 | Ok(()) |
| @@ -1225,7 +1225,7 @@ macro_rules! impl_word { | |||
| 1225 | }; | 1225 | }; |
| 1226 | } | 1226 | } |
| 1227 | 1227 | ||
| 1228 | #[cfg(any(spi_v1, spi_f1))] | 1228 | #[cfg(any(spi_v1, spi_v2))] |
| 1229 | mod word_impl { | 1229 | mod word_impl { |
| 1230 | use super::*; | 1230 | use super::*; |
| 1231 | 1231 | ||
| @@ -1235,7 +1235,7 @@ mod word_impl { | |||
| 1235 | impl_word!(u16, vals::Dff::BITS16); | 1235 | impl_word!(u16, vals::Dff::BITS16); |
| 1236 | } | 1236 | } |
| 1237 | 1237 | ||
| 1238 | #[cfg(spi_v2)] | 1238 | #[cfg(spi_v3)] |
| 1239 | mod word_impl { | 1239 | mod word_impl { |
| 1240 | use super::*; | 1240 | use super::*; |
| 1241 | 1241 | ||
| @@ -1256,7 +1256,7 @@ mod word_impl { | |||
| 1256 | impl_word!(u16, (vals::Ds::BITS16, vals::Frxth::HALF)); | 1256 | impl_word!(u16, (vals::Ds::BITS16, vals::Frxth::HALF)); |
| 1257 | } | 1257 | } |
| 1258 | 1258 | ||
| 1259 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 1259 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 1260 | mod word_impl { | 1260 | mod word_impl { |
| 1261 | use super::*; | 1261 | use super::*; |
| 1262 | 1262 | ||
diff --git a/examples/stm32h7/src/bin/sai.rs b/examples/stm32h7/src/bin/sai.rs index 01937593a..847b70c85 100644 --- a/examples/stm32h7/src/bin/sai.rs +++ b/examples/stm32h7/src/bin/sai.rs | |||
| @@ -63,7 +63,7 @@ async fn main(_spawner: Spawner) { | |||
| 63 | tx_config.tx_rx = TxRx::Transmitter; | 63 | tx_config.tx_rx = TxRx::Transmitter; |
| 64 | tx_config.sync_output = true; | 64 | tx_config.sync_output = true; |
| 65 | tx_config.clock_strobe = ClockStrobe::Falling; | 65 | tx_config.clock_strobe = ClockStrobe::Falling; |
| 66 | tx_config.master_clock_divider = mclk_div; | 66 | tx_config.master_clock_divider = Some(mclk_div); |
| 67 | tx_config.stereo_mono = StereoMono::Stereo; | 67 | tx_config.stereo_mono = StereoMono::Stereo; |
| 68 | tx_config.data_size = DataSize::Data24; | 68 | tx_config.data_size = DataSize::Data24; |
| 69 | tx_config.bit_order = BitOrder::MsbFirst; | 69 | tx_config.bit_order = BitOrder::MsbFirst; |
| @@ -119,71 +119,7 @@ async fn main(_spawner: Spawner) { | |||
| 119 | } | 119 | } |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | const fn mclk_div_from_u8(v: u8) -> MasterClockDivider { | 122 | fn mclk_div_from_u8(v: u8) -> MasterClockDivider { |
| 123 | match v { | 123 | assert!((1..=63).contains(&v)); |
| 124 | 1 => MasterClockDivider::Div1, | 124 | MasterClockDivider::from_bits(v) |
| 125 | 2 => MasterClockDivider::Div2, | ||
| 126 | 3 => MasterClockDivider::Div3, | ||
| 127 | 4 => MasterClockDivider::Div4, | ||
| 128 | 5 => MasterClockDivider::Div5, | ||
| 129 | 6 => MasterClockDivider::Div6, | ||
| 130 | 7 => MasterClockDivider::Div7, | ||
| 131 | 8 => MasterClockDivider::Div8, | ||
| 132 | 9 => MasterClockDivider::Div9, | ||
| 133 | 10 => MasterClockDivider::Div10, | ||
| 134 | 11 => MasterClockDivider::Div11, | ||
| 135 | 12 => MasterClockDivider::Div12, | ||
| 136 | 13 => MasterClockDivider::Div13, | ||
| 137 | 14 => MasterClockDivider::Div14, | ||
| 138 | 15 => MasterClockDivider::Div15, | ||
| 139 | 16 => MasterClockDivider::Div16, | ||
| 140 | 17 => MasterClockDivider::Div17, | ||
| 141 | 18 => MasterClockDivider::Div18, | ||
| 142 | 19 => MasterClockDivider::Div19, | ||
| 143 | 20 => MasterClockDivider::Div20, | ||
| 144 | 21 => MasterClockDivider::Div21, | ||
| 145 | 22 => MasterClockDivider::Div22, | ||
| 146 | 23 => MasterClockDivider::Div23, | ||
| 147 | 24 => MasterClockDivider::Div24, | ||
| 148 | 25 => MasterClockDivider::Div25, | ||
| 149 | 26 => MasterClockDivider::Div26, | ||
| 150 | 27 => MasterClockDivider::Div27, | ||
| 151 | 28 => MasterClockDivider::Div28, | ||
| 152 | 29 => MasterClockDivider::Div29, | ||
| 153 | 30 => MasterClockDivider::Div30, | ||
| 154 | 31 => MasterClockDivider::Div31, | ||
| 155 | 32 => MasterClockDivider::Div32, | ||
| 156 | 33 => MasterClockDivider::Div33, | ||
| 157 | 34 => MasterClockDivider::Div34, | ||
| 158 | 35 => MasterClockDivider::Div35, | ||
| 159 | 36 => MasterClockDivider::Div36, | ||
| 160 | 37 => MasterClockDivider::Div37, | ||
| 161 | 38 => MasterClockDivider::Div38, | ||
| 162 | 39 => MasterClockDivider::Div39, | ||
| 163 | 40 => MasterClockDivider::Div40, | ||
| 164 | 41 => MasterClockDivider::Div41, | ||
| 165 | 42 => MasterClockDivider::Div42, | ||
| 166 | 43 => MasterClockDivider::Div43, | ||
| 167 | 44 => MasterClockDivider::Div44, | ||
| 168 | 45 => MasterClockDivider::Div45, | ||
| 169 | 46 => MasterClockDivider::Div46, | ||
| 170 | 47 => MasterClockDivider::Div47, | ||
| 171 | 48 => MasterClockDivider::Div48, | ||
| 172 | 49 => MasterClockDivider::Div49, | ||
| 173 | 50 => MasterClockDivider::Div50, | ||
| 174 | 51 => MasterClockDivider::Div51, | ||
| 175 | 52 => MasterClockDivider::Div52, | ||
| 176 | 53 => MasterClockDivider::Div53, | ||
| 177 | 54 => MasterClockDivider::Div54, | ||
| 178 | 55 => MasterClockDivider::Div55, | ||
| 179 | 56 => MasterClockDivider::Div56, | ||
| 180 | 57 => MasterClockDivider::Div57, | ||
| 181 | 58 => MasterClockDivider::Div58, | ||
| 182 | 59 => MasterClockDivider::Div59, | ||
| 183 | 60 => MasterClockDivider::Div60, | ||
| 184 | 61 => MasterClockDivider::Div61, | ||
| 185 | 62 => MasterClockDivider::Div62, | ||
| 186 | 63 => MasterClockDivider::Div63, | ||
| 187 | _ => panic!(), | ||
| 188 | } | ||
| 189 | } | 125 | } |
diff --git a/examples/stm32h723/src/bin/spdifrx.rs b/examples/stm32h723/src/bin/spdifrx.rs index 6d29e8a4d..b75a03ae8 100644 --- a/examples/stm32h723/src/bin/spdifrx.rs +++ b/examples/stm32h723/src/bin/spdifrx.rs | |||
| @@ -168,7 +168,7 @@ fn new_sai_transmitter<'d>( | |||
| 168 | sai_config.slot_enable = 0xFFFF; // All slots | 168 | sai_config.slot_enable = 0xFFFF; // All slots |
| 169 | sai_config.data_size = sai::DataSize::Data32; | 169 | sai_config.data_size = sai::DataSize::Data32; |
| 170 | sai_config.frame_length = (CHANNEL_COUNT * 32) as u8; | 170 | sai_config.frame_length = (CHANNEL_COUNT * 32) as u8; |
| 171 | sai_config.master_clock_divider = hal::sai::MasterClockDivider::MasterClockDisabled; | 171 | sai_config.master_clock_divider = None; |
| 172 | 172 | ||
| 173 | let (sub_block_tx, _) = hal::sai::split_subblocks(sai); | 173 | let (sub_block_tx, _) = hal::sai::split_subblocks(sai); |
| 174 | Sai::new_asynchronous(sub_block_tx, sck, sd, fs, dma, buf, sai_config) | 174 | Sai::new_asynchronous(sub_block_tx, sck, sd, fs, dma, buf, sai_config) |
