Skip to content

Commit 5fc93ec

Browse files
authored
Merge pull request #248 from mgottschlag/sai
wip: Serial audio interface (SAI)
2 parents 2ad56a7 + ca5a6bd commit 5fc93ec

File tree

10 files changed

+970
-47
lines changed

10 files changed

+970
-47
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1313
- Enable `sdio` for stm32f446
1414
- port LTDC implementation and example from stm32f7xx-hal [#731]
1515
- IrDA mode for USARTs
16+
- initial `SAI` support [#248]
1617
- initial `embedded-io` support [#725]
1718

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

26+
[#248]: https://github.com/stm32-rs/stm32f4xx-hal/pull/248
2527
[#566]: https://github.com/stm32-rs/stm32f4xx-hal/pull/566
2628
[#706]: https://github.com/stm32-rs/stm32f4xx-hal/pull/706
2729
[#731]: https://github.com/stm32-rs/stm32f4xx-hal/pull/731

Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,10 @@ required-features = ["stm32f411", "rtic1"] # stm32f411
693693
name = "rtic-usb-cdc-echo"
694694
required-features = ["stm32f411", "rtic1", "otg-fs", "usb_fs"] # stm32f411
695695

696+
[[example]]
697+
name = "sai-duplex"
698+
required-features = ["stm32f429"]
699+
696700
[[example]]
697701
name = "sd"
698702
required-features = ["gpiod", "sdio", "sdio-host"] # stm32f405

examples/sai-duplex.rs

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#![deny(unsafe_code)]
2+
#![deny(warnings)]
3+
#![no_main]
4+
#![no_std]
5+
6+
use panic_halt as _;
7+
8+
use stm32f4xx_hal as hal;
9+
10+
use crate::hal::{
11+
pac,
12+
prelude::*,
13+
sai::{Duplex, Protocol, SlotSize, Synchronization, WordSize},
14+
};
15+
use cortex_m_rt::entry;
16+
17+
#[entry]
18+
fn main() -> ! {
19+
let p = pac::Peripherals::take().unwrap();
20+
21+
// The following code configures the both sub-blocks of SAI for full-duplex communication using
22+
// I2S-encoded audio.
23+
24+
// Initialize clocks.
25+
let rcc = p.RCC.constrain();
26+
let clocks = rcc
27+
.cfgr
28+
.use_hse(8.MHz())
29+
.saia_clk(172.MHz())
30+
.saib_clk(172.MHz())
31+
.freeze();
32+
// Test that the SAI clock is suitable for 48000KHz audio.
33+
assert!(clocks.saia_clk() == Some(172.MHz()));
34+
assert!(clocks.saib_clk() == Some(172.MHz()));
35+
36+
let gpioe = p.GPIOE.split();
37+
// SAIB is made synchronous to A.
38+
let (saia, saib) = p.SAI.split_sync_b();
39+
let protocol = Protocol {
40+
sync: Synchronization::I2S,
41+
word_size: WordSize::Bit16,
42+
slot_size: SlotSize::DataSize,
43+
num_slots: 2,
44+
};
45+
let tx = saia.master_tx(
46+
(gpioe.pe2, gpioe.pe4, gpioe.pe5, gpioe.pe6),
47+
protocol,
48+
48.kHz(),
49+
&clocks,
50+
);
51+
let rx = saib.slave_rx(gpioe.pe3, protocol);
52+
53+
let mut duplex = Duplex::new(rx, tx);
54+
duplex.start();
55+
loop {
56+
duplex.try_send(0xaaaa, 0xf0f0).ok();
57+
let _input = duplex.try_read();
58+
}
59+
60+
/*
61+
// The following code configures the A sub-block of SAI as a master transmitter for PCM-encoded audio.
62+
63+
// Initialize clocks.
64+
let rcc = p.RCC.constrain();
65+
let clocks = rcc.cfgr.use_hse(8.MHz()).saia_clk(172.MHz()).freeze();
66+
// Test that the SAI clock is suitable for 48000KHz audio.
67+
assert!(clocks.saia_clk() == Some(172.MHz()));
68+
69+
let gpioe = p.GPIOE.split();
70+
let (saia, _) = p.SAI.split();
71+
let protocol = Protocol {
72+
sync: Synchronization::PCMShortFrame,
73+
word_size: WordSize::Bit16,
74+
slot_size: SlotSize::DataSize,
75+
// Stereo audio, two slots per frame.
76+
num_slots: 2,
77+
};
78+
let mut tx = saia.master_tx(
79+
(gpioe.pe2, gpioe.pe4, gpioe.pe5, gpioe.pe6),
80+
protocol,
81+
48.kHz(),
82+
&clocks,
83+
);
84+
tx.start();
85+
loop {
86+
tx.try_send(0xaaaa, 0xf0f0).ok();
87+
}
88+
*/
89+
}

src/dma/traits.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -355,12 +355,7 @@ pub struct FLT<T, const F: u8> {
355355
impl<T, const F: u8> crate::Sealed for FLT<T, F> {}
356356

357357
#[cfg(feature = "sai")]
358-
pub struct SAICH<T, const C: u8> {
359-
_per: PhantomData<T>,
360-
}
361-
362-
#[cfg(feature = "sai")]
363-
impl<T, const C: u8> crate::Sealed for SAICH<T, C> {}
358+
pub use crate::sai::SAICH;
364359

365360
dma_map!(
366361
(Stream0<DMA2>:0, MemoryToMemory<u8>, [MemoryToMemory<u8> | MemoryToMemory<u16> | MemoryToMemory<u32>]),

src/dma/traits/f4.rs

+7-26
Original file line numberDiff line numberDiff line change
@@ -475,38 +475,19 @@ mod sai1 {
475475
use pac::SAI1;
476476

477477
dma_map!(
478-
(Stream1<DMA2>:0, SAICH<SAI1, 0>, [MemoryToPeripheral | PeripheralToMemory]), //SAI1_A
479-
(Stream3<DMA2>:0, SAICH<SAI1, 0>, [MemoryToPeripheral | PeripheralToMemory]), //SAI1_A
480-
(Stream4<DMA2>:1, SAICH<SAI1, 1>, [MemoryToPeripheral | PeripheralToMemory]), //SAI1_B
481-
(Stream5<DMA2>:0, SAICH<SAI1, 1>, [MemoryToPeripheral | PeripheralToMemory]), //SAI1_B:DMA_CHANNEL_0
478+
(Stream1<DMA2>:0, SAICH<SAI1, false>, [MemoryToPeripheral | PeripheralToMemory]), //SAI1_A
479+
(Stream3<DMA2>:0, SAICH<SAI1, false>, [MemoryToPeripheral | PeripheralToMemory]), //SAI1_A
480+
(Stream4<DMA2>:1, SAICH<SAI1, true>, [MemoryToPeripheral | PeripheralToMemory]), //SAI1_B
481+
(Stream5<DMA2>:0, SAICH<SAI1, true>, [MemoryToPeripheral | PeripheralToMemory]), //SAI1_B:DMA_CHANNEL_0
482482
);
483-
484-
unsafe impl<const C: u8> PeriAddress for SAICH<SAI1, C> {
485-
#[inline(always)]
486-
fn address(&self) -> u32 {
487-
unsafe { (*SAI1::ptr()).ch(C as usize).dr().as_ptr() as u32 }
488-
}
489-
490-
type MemSize = u32;
491-
}
492483
}
493484
#[cfg(feature = "sai2")]
494485
dma_map!(
495-
(Stream4<DMA2>:3, SAICH<pac::SAI2, 0>, [MemoryToPeripheral | PeripheralToMemory]), //SAI2_A
496-
(Stream6<DMA2>:3, SAICH<pac::SAI2, 1>, [MemoryToPeripheral | PeripheralToMemory]), //SAI2_B
497-
(Stream7<DMA2>:0, SAICH<pac::SAI2, 1>, [MemoryToPeripheral | PeripheralToMemory]), //SAI2_B:DMA_CHANNEL_0
486+
(Stream4<DMA2>:3, SAICH<pac::SAI2, false>, [MemoryToPeripheral | PeripheralToMemory]), //SAI2_A
487+
(Stream6<DMA2>:3, SAICH<pac::SAI2, true>, [MemoryToPeripheral | PeripheralToMemory]), //SAI2_B
488+
(Stream7<DMA2>:0, SAICH<pac::SAI2, true>, [MemoryToPeripheral | PeripheralToMemory]), //SAI2_B:DMA_CHANNEL_0
498489
);
499490

500-
#[cfg(feature = "sai2")]
501-
unsafe impl<const C: u8> PeriAddress for SAICH<pac::SAI2, C> {
502-
#[inline(always)]
503-
fn address(&self) -> u32 {
504-
unsafe { (*pac::SAI2::ptr()).ch(C as usize).dr().as_ptr() as u32 }
505-
}
506-
507-
type MemSize = u32;
508-
}
509-
510491
#[cfg(feature = "spi6")]
511492
dma_map!(
512493
(Stream5<DMA2>:1, pac::SPI6, [MemoryToPeripheral]), //SPI6_TX

src/gpio/alt/f4.rs

+12-14
Original file line numberDiff line numberDiff line change
@@ -2502,7 +2502,7 @@ pub mod sai1 {
25022502
PF9<7>,
25032503
],
25042504

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

@@ -2516,7 +2516,7 @@ pub mod sai1 {
25162516
PG7<6>,
25172517
],
25182518

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

@@ -2611,19 +2611,18 @@ pub mod sai1 {
26112611
use crate::pac::SAI;
26122612
#[cfg(any(feature = "stm32f427", feature = "stm32f437", feature = "gpio-f446"))]
26132613
use crate::pac::SAI1 as SAI;
2614-
pub struct ChannelA;
2615-
pub struct ChannelB;
2614+
pub use crate::sai::{SAI1A, SAI1B};
26162615
impl SaiChannels for SAI {
2617-
type A = ChannelA;
2618-
type B = ChannelB;
2616+
type A = SAI1A;
2617+
type B = SAI1B;
26192618
}
2620-
impl SaiChannel for ChannelA {
2619+
impl SaiChannel for SAI1A {
26212620
type Fs = FsA;
26222621
type Mclk = MclkA;
26232622
type Sck = SckA;
26242623
type Sd = SdA;
26252624
}
2626-
impl SaiChannel for ChannelB {
2625+
impl SaiChannel for SAI1B {
26272626
type Fs = FsB;
26282627
type Mclk = MclkB;
26292628
type Sck = SckB;
@@ -2686,19 +2685,18 @@ pub mod sai2 {
26862685
}
26872686

26882687
use crate::pac::SAI2 as SAI;
2689-
pub struct ChannelA;
2690-
pub struct ChannelB;
2688+
pub use crate::sai::{SAI2A, SAI2B};
26912689
impl SaiChannels for SAI {
2692-
type A = ChannelA;
2693-
type B = ChannelB;
2690+
type A = SAI2A;
2691+
type B = SAI2B;
26942692
}
2695-
impl SaiChannel for ChannelA {
2693+
impl SaiChannel for SAI2A {
26962694
type Fs = FsA;
26972695
type Mclk = MclkA;
26982696
type Sck = SckA;
26992697
type Sd = SdA;
27002698
}
2701-
impl SaiChannel for ChannelB {
2699+
impl SaiChannel for SAI2B {
27022700
type Fs = FsB;
27032701
type Mclk = MclkB;
27042702
type Sck = SckB;

src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ pub mod qei;
117117
pub mod qspi;
118118
pub mod rcc;
119119
pub mod rtc;
120+
#[cfg(feature = "sai")]
121+
pub mod sai;
120122
#[cfg(all(feature = "sdio-host", feature = "sdio"))]
121123
pub mod sdio;
122124
pub mod serial;

src/prelude.rs

+2
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ pub use crate::qei::QeiExt as _stm32f4xx_hal_QeiExt;
6868
pub use crate::rcc::RccExt as _stm32f4xx_hal_rcc_RccExt;
6969
#[cfg(feature = "rng")]
7070
pub use crate::rng::RngExt as _stm32f4xx_hal_rng_RngExt;
71+
#[cfg(feature = "sai")]
72+
pub use crate::sai::SAIExt as _;
7173
pub use crate::serial::dma::SerialHandleIT as _stm32f4xx_hal_serial_dma_SerialHandleIT;
7274
pub use crate::serial::dma::SerialReadDMA as _stm32f4xx_hal_serial_dma_SerialReadDMA;
7375
pub use crate::serial::dma::SerialWriteDMA as _stm32f4xx_hal_serial_dma_SerialWriteDMA;

src/rcc/f4/enable.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,12 @@ bus_lpenable!(ADC3 => 10);
276276
#[cfg(feature = "adc3")]
277277
bus_reset!(ADC3 => 8);
278278

279-
#[cfg(feature = "stm32f413")]
279+
#[cfg(any(
280+
feature = "gpio-f413",
281+
feature = "gpio-f469",
282+
feature = "stm32f429",
283+
feature = "stm32f439"
284+
))]
280285
bus! {
281286
SAI => (APB2, 22),
282287
}

0 commit comments

Comments
 (0)