aboutsummaryrefslogtreecommitdiff
path: root/examples/stm32h7/src
diff options
context:
space:
mode:
authorDickless <[email protected]>2024-07-05 02:33:30 +0900
committerDickless <[email protected]>2024-07-05 02:33:30 +0900
commit4ecdf31f9b887c4427ff06b70744ef438502f989 (patch)
tree44f10ea4cb0e8cfeb4cafafdf452da1a3d71a07c /examples/stm32h7/src
parente2f9a48457c5d54546a3861fb067071ce93f9742 (diff)
add SAI example
Diffstat (limited to 'examples/stm32h7/src')
-rw-r--r--examples/stm32h7/src/bin/sai.rs189
1 files changed, 189 insertions, 0 deletions
diff --git a/examples/stm32h7/src/bin/sai.rs b/examples/stm32h7/src/bin/sai.rs
new file mode 100644
index 000000000..ef8479979
--- /dev/null
+++ b/examples/stm32h7/src/bin/sai.rs
@@ -0,0 +1,189 @@
1//! Daisy Seed rev.7(with PCM3060 codec)
2//! https://electro-smith.com/products/daisy-seed
3#![no_std]
4#![no_main]
5
6use defmt_rtt as _;
7use embassy_executor::Spawner;
8use embassy_stm32 as hal;
9use grounded::uninit::GroundedArrayCell;
10use hal::rcc::*;
11use hal::sai::*;
12use hal::time::Hertz;
13use panic_probe as _;
14
15const BLOCK_LENGTH: usize = 32; // 32 samples
16const HALF_DMA_BUFFER_LENGTH: usize = BLOCK_LENGTH * 2; // 2 channels
17const DMA_BUFFER_LENGTH: usize = HALF_DMA_BUFFER_LENGTH * 2; // 2 half-blocks
18const SAMPLE_RATE: u32 = 48000;
19
20//DMA buffer must be in special region. Refer https://embassy.dev/book/#_stm32_bdma_only_working_out_of_some_ram_regions
21#[link_section = ".sram1_bss"]
22static mut TX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit();
23#[link_section = ".sram1_bss"]
24static mut RX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit();
25
26#[embassy_executor::main]
27async fn main(_spawner: Spawner) {
28 let mut config = hal::Config::default();
29 config.rcc.pll1 = Some(Pll {
30 source: PllSource::HSE,
31 prediv: PllPreDiv::DIV4,
32 mul: PllMul::MUL200,
33 divp: Some(PllDiv::DIV2),
34 divq: Some(PllDiv::DIV5),
35 divr: Some(PllDiv::DIV2),
36 });
37 config.rcc.pll3 = Some(Pll {
38 source: PllSource::HSE,
39 prediv: PllPreDiv::DIV6,
40 mul: PllMul::MUL295,
41 divp: Some(PllDiv::DIV16),
42 divq: Some(PllDiv::DIV4),
43 divr: Some(PllDiv::DIV32),
44 });
45 config.rcc.sys = Sysclk::PLL1_P;
46 config.rcc.mux.sai1sel = hal::pac::rcc::vals::Saisel::PLL3_P;
47 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
48 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
49 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
50 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
51 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
52 config.rcc.hse = Some(Hse {
53 freq: Hertz::mhz(16),
54 mode: HseMode::Oscillator,
55 });
56
57 let p = hal::init(config);
58
59 let (sub_block_tx, sub_block_rx) = hal::sai::split_subblocks(p.SAI1);
60 let kernel_clock = hal::rcc::frequency::<hal::peripherals::SAI1>().0;
61 let mclk_div = mclk_div_from_u8((kernel_clock / (SAMPLE_RATE * 256)) as u8);
62
63 let mut tx_config = hal::sai::Config::default();
64 tx_config.mode = Mode::Master;
65 tx_config.tx_rx = TxRx::Transmitter;
66 tx_config.sync_output = true;
67 tx_config.clock_strobe = ClockStrobe::Falling;
68 tx_config.master_clock_divider = mclk_div;
69 tx_config.stereo_mono = StereoMono::Stereo;
70 tx_config.data_size = DataSize::Data24;
71 tx_config.bit_order = BitOrder::MsbFirst;
72 tx_config.frame_sync_polarity = FrameSyncPolarity::ActiveHigh;
73 tx_config.frame_sync_offset = FrameSyncOffset::OnFirstBit;
74 tx_config.frame_length = 64;
75 tx_config.frame_sync_active_level_length = embassy_stm32::sai::word::U7(32);
76 tx_config.fifo_threshold = FifoThreshold::Quarter;
77
78 let mut rx_config = tx_config.clone();
79 rx_config.mode = Mode::Slave;
80 rx_config.tx_rx = TxRx::Receiver;
81 rx_config.sync_input = SyncInput::Internal;
82 rx_config.clock_strobe = ClockStrobe::Rising;
83 rx_config.sync_output = false;
84
85 let tx_buffer: &mut [u32] = unsafe {
86 TX_BUFFER.initialize_all_copied(0);
87 let (ptr, len) = TX_BUFFER.get_ptr_len();
88 core::slice::from_raw_parts_mut(ptr, len)
89 };
90
91 let mut sai_transmitter = Sai::new_asynchronous_with_mclk(
92 sub_block_tx,
93 p.PE5,
94 p.PE6,
95 p.PE4,
96 p.PE2,
97 p.DMA1_CH0,
98 tx_buffer,
99 tx_config,
100 );
101
102 let rx_buffer: &mut [u32] = unsafe {
103 RX_BUFFER.initialize_all_copied(0);
104 let (ptr, len) = RX_BUFFER.get_ptr_len();
105 core::slice::from_raw_parts_mut(ptr, len)
106 };
107
108 let mut sai_receiver =
109 Sai::new_synchronous(sub_block_rx, p.PE3, p.DMA1_CH1, rx_buffer, rx_config);
110
111 sai_receiver.start();
112 sai_transmitter.start();
113
114 let mut buf = [0u32; HALF_DMA_BUFFER_LENGTH];
115
116 loop {
117 sai_receiver.read(&mut buf).await.unwrap();
118 sai_transmitter.write(&buf).await.unwrap();
119 }
120}
121
122const fn mclk_div_from_u8(v: u8) -> MasterClockDivider {
123 match v {
124 1 => MasterClockDivider::Div1,
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}