Skip to content

Commit

Permalink
Merge pull request #248 from mgottschlag/sai
Browse files Browse the repository at this point in the history
wip: Serial audio interface (SAI)
  • Loading branch information
burrbull authored Jul 25, 2024
2 parents 2ad56a7 + ca5a6bd commit 5fc93ec
Show file tree
Hide file tree
Showing 10 changed files with 970 additions and 47 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Enable `sdio` for stm32f446
- port LTDC implementation and example from stm32f7xx-hal [#731]
- IrDA mode for USARTs
- initial `SAI` support [#248]
- initial `embedded-io` support [#725]

### Changed
Expand All @@ -22,6 +23,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Allow different lengths of buffers in hal_1 SpiBus impl [#566]
- `steal` UART peripheral on `Rx::new`

[#248]: https://github.com/stm32-rs/stm32f4xx-hal/pull/248
[#566]: https://github.com/stm32-rs/stm32f4xx-hal/pull/566
[#706]: https://github.com/stm32-rs/stm32f4xx-hal/pull/706
[#731]: https://github.com/stm32-rs/stm32f4xx-hal/pull/731
Expand Down
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,10 @@ required-features = ["stm32f411", "rtic1"] # stm32f411
name = "rtic-usb-cdc-echo"
required-features = ["stm32f411", "rtic1", "otg-fs", "usb_fs"] # stm32f411

[[example]]
name = "sai-duplex"
required-features = ["stm32f429"]

[[example]]
name = "sd"
required-features = ["gpiod", "sdio", "sdio-host"] # stm32f405
Expand Down
89 changes: 89 additions & 0 deletions examples/sai-duplex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]

use panic_halt as _;

use stm32f4xx_hal as hal;

use crate::hal::{
pac,
prelude::*,
sai::{Duplex, Protocol, SlotSize, Synchronization, WordSize},
};
use cortex_m_rt::entry;

#[entry]
fn main() -> ! {
let p = pac::Peripherals::take().unwrap();

// The following code configures the both sub-blocks of SAI for full-duplex communication using
// I2S-encoded audio.

// Initialize clocks.
let rcc = p.RCC.constrain();
let clocks = rcc
.cfgr
.use_hse(8.MHz())
.saia_clk(172.MHz())
.saib_clk(172.MHz())
.freeze();
// Test that the SAI clock is suitable for 48000KHz audio.
assert!(clocks.saia_clk() == Some(172.MHz()));
assert!(clocks.saib_clk() == Some(172.MHz()));

let gpioe = p.GPIOE.split();
// SAIB is made synchronous to A.
let (saia, saib) = p.SAI.split_sync_b();
let protocol = Protocol {
sync: Synchronization::I2S,
word_size: WordSize::Bit16,
slot_size: SlotSize::DataSize,
num_slots: 2,
};
let tx = saia.master_tx(
(gpioe.pe2, gpioe.pe4, gpioe.pe5, gpioe.pe6),
protocol,
48.kHz(),
&clocks,
);
let rx = saib.slave_rx(gpioe.pe3, protocol);

let mut duplex = Duplex::new(rx, tx);
duplex.start();
loop {
duplex.try_send(0xaaaa, 0xf0f0).ok();
let _input = duplex.try_read();
}

/*
// The following code configures the A sub-block of SAI as a master transmitter for PCM-encoded audio.
// Initialize clocks.
let rcc = p.RCC.constrain();
let clocks = rcc.cfgr.use_hse(8.MHz()).saia_clk(172.MHz()).freeze();
// Test that the SAI clock is suitable for 48000KHz audio.
assert!(clocks.saia_clk() == Some(172.MHz()));
let gpioe = p.GPIOE.split();
let (saia, _) = p.SAI.split();
let protocol = Protocol {
sync: Synchronization::PCMShortFrame,
word_size: WordSize::Bit16,
slot_size: SlotSize::DataSize,
// Stereo audio, two slots per frame.
num_slots: 2,
};
let mut tx = saia.master_tx(
(gpioe.pe2, gpioe.pe4, gpioe.pe5, gpioe.pe6),
protocol,
48.kHz(),
&clocks,
);
tx.start();
loop {
tx.try_send(0xaaaa, 0xf0f0).ok();
}
*/
}
7 changes: 1 addition & 6 deletions src/dma/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,12 +355,7 @@ pub struct FLT<T, const F: u8> {
impl<T, const F: u8> crate::Sealed for FLT<T, F> {}

#[cfg(feature = "sai")]
pub struct SAICH<T, const C: u8> {
_per: PhantomData<T>,
}

#[cfg(feature = "sai")]
impl<T, const C: u8> crate::Sealed for SAICH<T, C> {}
pub use crate::sai::SAICH;

dma_map!(
(Stream0<DMA2>:0, MemoryToMemory<u8>, [MemoryToMemory<u8> | MemoryToMemory<u16> | MemoryToMemory<u32>]),
Expand Down
33 changes: 7 additions & 26 deletions src/dma/traits/f4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -475,38 +475,19 @@ mod sai1 {
use pac::SAI1;

dma_map!(
(Stream1<DMA2>:0, SAICH<SAI1, 0>, [MemoryToPeripheral | PeripheralToMemory]), //SAI1_A
(Stream3<DMA2>:0, SAICH<SAI1, 0>, [MemoryToPeripheral | PeripheralToMemory]), //SAI1_A
(Stream4<DMA2>:1, SAICH<SAI1, 1>, [MemoryToPeripheral | PeripheralToMemory]), //SAI1_B
(Stream5<DMA2>:0, SAICH<SAI1, 1>, [MemoryToPeripheral | PeripheralToMemory]), //SAI1_B:DMA_CHANNEL_0
(Stream1<DMA2>:0, SAICH<SAI1, false>, [MemoryToPeripheral | PeripheralToMemory]), //SAI1_A
(Stream3<DMA2>:0, SAICH<SAI1, false>, [MemoryToPeripheral | PeripheralToMemory]), //SAI1_A
(Stream4<DMA2>:1, SAICH<SAI1, true>, [MemoryToPeripheral | PeripheralToMemory]), //SAI1_B
(Stream5<DMA2>:0, SAICH<SAI1, true>, [MemoryToPeripheral | PeripheralToMemory]), //SAI1_B:DMA_CHANNEL_0
);

unsafe impl<const C: u8> PeriAddress for SAICH<SAI1, C> {
#[inline(always)]
fn address(&self) -> u32 {
unsafe { (*SAI1::ptr()).ch(C as usize).dr().as_ptr() as u32 }
}

type MemSize = u32;
}
}
#[cfg(feature = "sai2")]
dma_map!(
(Stream4<DMA2>:3, SAICH<pac::SAI2, 0>, [MemoryToPeripheral | PeripheralToMemory]), //SAI2_A
(Stream6<DMA2>:3, SAICH<pac::SAI2, 1>, [MemoryToPeripheral | PeripheralToMemory]), //SAI2_B
(Stream7<DMA2>:0, SAICH<pac::SAI2, 1>, [MemoryToPeripheral | PeripheralToMemory]), //SAI2_B:DMA_CHANNEL_0
(Stream4<DMA2>:3, SAICH<pac::SAI2, false>, [MemoryToPeripheral | PeripheralToMemory]), //SAI2_A
(Stream6<DMA2>:3, SAICH<pac::SAI2, true>, [MemoryToPeripheral | PeripheralToMemory]), //SAI2_B
(Stream7<DMA2>:0, SAICH<pac::SAI2, true>, [MemoryToPeripheral | PeripheralToMemory]), //SAI2_B:DMA_CHANNEL_0
);

#[cfg(feature = "sai2")]
unsafe impl<const C: u8> PeriAddress for SAICH<pac::SAI2, C> {
#[inline(always)]
fn address(&self) -> u32 {
unsafe { (*pac::SAI2::ptr()).ch(C as usize).dr().as_ptr() as u32 }
}

type MemSize = u32;
}

#[cfg(feature = "spi6")]
dma_map!(
(Stream5<DMA2>:1, pac::SPI6, [MemoryToPeripheral]), //SPI6_TX
Expand Down
26 changes: 12 additions & 14 deletions src/gpio/alt/f4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2502,7 +2502,7 @@ pub mod sai1 {
PF9<7>,
],

<MclkA, PushPull> for [
<MclkA, PushPull> for no:NoPin, [
#[cfg(feature = "gpio-f413")]
PA15<10>,

Expand All @@ -2516,7 +2516,7 @@ pub mod sai1 {
PG7<6>,
],

<MclkB, PushPull> for [
<MclkB, PushPull> for no:NoPin, [
#[cfg(feature = "gpio-f446")]
PC0<6>,

Expand Down Expand Up @@ -2611,19 +2611,18 @@ pub mod sai1 {
use crate::pac::SAI;
#[cfg(any(feature = "stm32f427", feature = "stm32f437", feature = "gpio-f446"))]
use crate::pac::SAI1 as SAI;
pub struct ChannelA;
pub struct ChannelB;
pub use crate::sai::{SAI1A, SAI1B};
impl SaiChannels for SAI {
type A = ChannelA;
type B = ChannelB;
type A = SAI1A;
type B = SAI1B;
}
impl SaiChannel for ChannelA {
impl SaiChannel for SAI1A {
type Fs = FsA;
type Mclk = MclkA;
type Sck = SckA;
type Sd = SdA;
}
impl SaiChannel for ChannelB {
impl SaiChannel for SAI1B {
type Fs = FsB;
type Mclk = MclkB;
type Sck = SckB;
Expand Down Expand Up @@ -2686,19 +2685,18 @@ pub mod sai2 {
}

use crate::pac::SAI2 as SAI;
pub struct ChannelA;
pub struct ChannelB;
pub use crate::sai::{SAI2A, SAI2B};
impl SaiChannels for SAI {
type A = ChannelA;
type B = ChannelB;
type A = SAI2A;
type B = SAI2B;
}
impl SaiChannel for ChannelA {
impl SaiChannel for SAI2A {
type Fs = FsA;
type Mclk = MclkA;
type Sck = SckA;
type Sd = SdA;
}
impl SaiChannel for ChannelB {
impl SaiChannel for SAI2B {
type Fs = FsB;
type Mclk = MclkB;
type Sck = SckB;
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ pub mod qei;
pub mod qspi;
pub mod rcc;
pub mod rtc;
#[cfg(feature = "sai")]
pub mod sai;
#[cfg(all(feature = "sdio-host", feature = "sdio"))]
pub mod sdio;
pub mod serial;
Expand Down
2 changes: 2 additions & 0 deletions src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ pub use crate::qei::QeiExt as _stm32f4xx_hal_QeiExt;
pub use crate::rcc::RccExt as _stm32f4xx_hal_rcc_RccExt;
#[cfg(feature = "rng")]
pub use crate::rng::RngExt as _stm32f4xx_hal_rng_RngExt;
#[cfg(feature = "sai")]
pub use crate::sai::SAIExt as _;
pub use crate::serial::dma::SerialHandleIT as _stm32f4xx_hal_serial_dma_SerialHandleIT;
pub use crate::serial::dma::SerialReadDMA as _stm32f4xx_hal_serial_dma_SerialReadDMA;
pub use crate::serial::dma::SerialWriteDMA as _stm32f4xx_hal_serial_dma_SerialWriteDMA;
Expand Down
7 changes: 6 additions & 1 deletion src/rcc/f4/enable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,12 @@ bus_lpenable!(ADC3 => 10);
#[cfg(feature = "adc3")]
bus_reset!(ADC3 => 8);

#[cfg(feature = "stm32f413")]
#[cfg(any(
feature = "gpio-f413",
feature = "gpio-f469",
feature = "stm32f429",
feature = "stm32f439"
))]
bus! {
SAI => (APB2, 22),
}
Expand Down
Loading

0 comments on commit 5fc93ec

Please sign in to comment.