aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorHenrik Alsér <[email protected]>2024-07-04 18:32:51 +0000
committerGitHub <[email protected]>2024-07-04 18:32:51 +0000
commitf91244bae6a4b277f8464c499e50c492a7671039 (patch)
tree690d70aa04130417c262844984f89cc3b55d2bbb /examples
parente2f9a48457c5d54546a3861fb067071ce93f9742 (diff)
parent4f649caa8155c5031592d74c2b5e94f400332a88 (diff)
Merge pull request #3152 from Dicklessgreat/main
add SAI example
Diffstat (limited to 'examples')
-rw-r--r--examples/stm32h7/Cargo.toml1
-rw-r--r--examples/stm32h7/src/bin/sai.rs186
2 files changed, 187 insertions, 0 deletions
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index 0584f3916..78343b74f 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -34,6 +34,7 @@ stm32-fmc = "0.3.0"
34embedded-storage = "0.3.1" 34embedded-storage = "0.3.1"
35static_cell = "2" 35static_cell = "2"
36chrono = { version = "^0.4", default-features = false } 36chrono = { version = "^0.4", default-features = false }
37grounded = "0.2.0"
37 38
38# cargo build/run 39# cargo build/run
39[profile.dev] 40[profile.dev]
diff --git a/examples/stm32h7/src/bin/sai.rs b/examples/stm32h7/src/bin/sai.rs
new file mode 100644
index 000000000..f6735e235
--- /dev/null
+++ b/examples/stm32h7/src/bin/sai.rs
@@ -0,0 +1,186 @@
1//! Daisy Seed rev.7(with PCM3060 codec)
2//! https://electro-smith.com/products/daisy-seed
3#![no_std]
4#![no_main]
5
6use embassy_executor::Spawner;
7use grounded::uninit::GroundedArrayCell;
8use hal::rcc::*;
9use hal::sai::*;
10use hal::time::Hertz;
11use {defmt_rtt as _, embassy_stm32 as hal, panic_probe as _};
12
13const BLOCK_LENGTH: usize = 32; // 32 samples
14const HALF_DMA_BUFFER_LENGTH: usize = BLOCK_LENGTH * 2; // 2 channels
15const DMA_BUFFER_LENGTH: usize = HALF_DMA_BUFFER_LENGTH * 2; // 2 half-blocks
16const SAMPLE_RATE: u32 = 48000;
17
18//DMA buffer must be in special region. Refer https://embassy.dev/book/#_stm32_bdma_only_working_out_of_some_ram_regions
19#[link_section = ".sram1_bss"]
20static mut TX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit();
21#[link_section = ".sram1_bss"]
22static mut RX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit();
23
24#[embassy_executor::main]
25async fn main(_spawner: Spawner) {
26 let mut config = hal::Config::default();
27 config.rcc.pll1 = Some(Pll {
28 source: PllSource::HSE,
29 prediv: PllPreDiv::DIV4,
30 mul: PllMul::MUL200,
31 divp: Some(PllDiv::DIV2),
32 divq: Some(PllDiv::DIV5),
33 divr: Some(PllDiv::DIV2),
34 });
35 config.rcc.pll3 = Some(Pll {
36 source: PllSource::HSE,
37 prediv: PllPreDiv::DIV6,
38 mul: PllMul::MUL295,
39 divp: Some(PllDiv::DIV16),
40 divq: Some(PllDiv::DIV4),
41 divr: Some(PllDiv::DIV32),
42 });
43 config.rcc.sys = Sysclk::PLL1_P;
44 config.rcc.mux.sai1sel = hal::pac::rcc::vals::Saisel::PLL3_P;
45 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
46 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
47 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
48 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
49 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
50 config.rcc.hse = Some(Hse {
51 freq: Hertz::mhz(16),
52 mode: HseMode::Oscillator,
53 });
54
55 let p = hal::init(config);
56
57 let (sub_block_tx, sub_block_rx) = hal::sai::split_subblocks(p.SAI1);
58 let kernel_clock = hal::rcc::frequency::<hal::peripherals::SAI1>().0;
59 let mclk_div = mclk_div_from_u8((kernel_clock / (SAMPLE_RATE * 256)) as u8);
60
61 let mut tx_config = hal::sai::Config::default();
62 tx_config.mode = Mode::Master;
63 tx_config.tx_rx = TxRx::Transmitter;
64 tx_config.sync_output = true;
65 tx_config.clock_strobe = ClockStrobe::Falling;
66 tx_config.master_clock_divider = mclk_div;
67 tx_config.stereo_mono = StereoMono::Stereo;
68 tx_config.data_size = DataSize::Data24;
69 tx_config.bit_order = BitOrder::MsbFirst;
70 tx_config.frame_sync_polarity = FrameSyncPolarity::ActiveHigh;
71 tx_config.frame_sync_offset = FrameSyncOffset::OnFirstBit;
72 tx_config.frame_length = 64;
73 tx_config.frame_sync_active_level_length = embassy_stm32::sai::word::U7(32);
74 tx_config.fifo_threshold = FifoThreshold::Quarter;
75
76 let mut rx_config = tx_config.clone();
77 rx_config.mode = Mode::Slave;
78 rx_config.tx_rx = TxRx::Receiver;
79 rx_config.sync_input = SyncInput::Internal;
80 rx_config.clock_strobe = ClockStrobe::Rising;
81 rx_config.sync_output = false;
82
83 let tx_buffer: &mut [u32] = unsafe {
84 TX_BUFFER.initialize_all_copied(0);
85 let (ptr, len) = TX_BUFFER.get_ptr_len();
86 core::slice::from_raw_parts_mut(ptr, len)
87 };
88
89 let mut sai_transmitter = Sai::new_asynchronous_with_mclk(
90 sub_block_tx,
91 p.PE5,
92 p.PE6,
93 p.PE4,
94 p.PE2,
95 p.DMA1_CH0,
96 tx_buffer,
97 tx_config,
98 );
99
100 let rx_buffer: &mut [u32] = unsafe {
101 RX_BUFFER.initialize_all_copied(0);
102 let (ptr, len) = RX_BUFFER.get_ptr_len();
103 core::slice::from_raw_parts_mut(ptr, len)
104 };
105
106 let mut sai_receiver = Sai::new_synchronous(sub_block_rx, p.PE3, p.DMA1_CH1, rx_buffer, rx_config);
107
108 sai_receiver.start();
109 sai_transmitter.start();
110
111 let mut buf = [0u32; HALF_DMA_BUFFER_LENGTH];
112
113 loop {
114 sai_receiver.read(&mut buf).await.unwrap();
115 sai_transmitter.write(&buf).await.unwrap();
116 }
117}
118
119const fn mclk_div_from_u8(v: u8) -> MasterClockDivider {
120 match v {
121 1 => MasterClockDivider::Div1,
122 2 => MasterClockDivider::Div2,
123 3 => MasterClockDivider::Div3,
124 4 => MasterClockDivider::Div4,
125 5 => MasterClockDivider::Div5,
126 6 => MasterClockDivider::Div6,
127 7 => MasterClockDivider::Div7,
128 8 => MasterClockDivider::Div8,
129 9 => MasterClockDivider::Div9,
130 10 => MasterClockDivider::Div10,
131 11 => MasterClockDivider::Div11,
132 12 => MasterClockDivider::Div12,
133 13 => MasterClockDivider::Div13,
134 14 => MasterClockDivider::Div14,
135 15 => MasterClockDivider::Div15,
136 16 => MasterClockDivider::Div16,
137 17 => MasterClockDivider::Div17,
138 18 => MasterClockDivider::Div18,
139 19 => MasterClockDivider::Div19,
140 20 => MasterClockDivider::Div20,
141 21 => MasterClockDivider::Div21,
142 22 => MasterClockDivider::Div22,
143 23 => MasterClockDivider::Div23,
144 24 => MasterClockDivider::Div24,
145 25 => MasterClockDivider::Div25,
146 26 => MasterClockDivider::Div26,
147 27 => MasterClockDivider::Div27,
148 28 => MasterClockDivider::Div28,
149 29 => MasterClockDivider::Div29,
150 30 => MasterClockDivider::Div30,
151 31 => MasterClockDivider::Div31,
152 32 => MasterClockDivider::Div32,
153 33 => MasterClockDivider::Div33,
154 34 => MasterClockDivider::Div34,
155 35 => MasterClockDivider::Div35,
156 36 => MasterClockDivider::Div36,
157 37 => MasterClockDivider::Div37,
158 38 => MasterClockDivider::Div38,
159 39 => MasterClockDivider::Div39,
160 40 => MasterClockDivider::Div40,
161 41 => MasterClockDivider::Div41,
162 42 => MasterClockDivider::Div42,
163 43 => MasterClockDivider::Div43,
164 44 => MasterClockDivider::Div44,
165 45 => MasterClockDivider::Div45,
166 46 => MasterClockDivider::Div46,
167 47 => MasterClockDivider::Div47,
168 48 => MasterClockDivider::Div48,
169 49 => MasterClockDivider::Div49,
170 50 => MasterClockDivider::Div50,
171 51 => MasterClockDivider::Div51,
172 52 => MasterClockDivider::Div52,
173 53 => MasterClockDivider::Div53,
174 54 => MasterClockDivider::Div54,
175 55 => MasterClockDivider::Div55,
176 56 => MasterClockDivider::Div56,
177 57 => MasterClockDivider::Div57,
178 58 => MasterClockDivider::Div58,
179 59 => MasterClockDivider::Div59,
180 60 => MasterClockDivider::Div60,
181 61 => MasterClockDivider::Div61,
182 62 => MasterClockDivider::Div62,
183 63 => MasterClockDivider::Div63,
184 _ => panic!(),
185 }
186}