diff options
| author | Dickless <[email protected]> | 2024-07-05 02:33:30 +0900 |
|---|---|---|
| committer | Dickless <[email protected]> | 2024-07-05 02:33:30 +0900 |
| commit | 4ecdf31f9b887c4427ff06b70744ef438502f989 (patch) | |
| tree | 44f10ea4cb0e8cfeb4cafafdf452da1a3d71a07c /examples/stm32h7/src/bin | |
| parent | e2f9a48457c5d54546a3861fb067071ce93f9742 (diff) | |
add SAI example
Diffstat (limited to 'examples/stm32h7/src/bin')
| -rw-r--r-- | examples/stm32h7/src/bin/sai.rs | 189 |
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 | |||
| 6 | use defmt_rtt as _; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_stm32 as hal; | ||
| 9 | use grounded::uninit::GroundedArrayCell; | ||
| 10 | use hal::rcc::*; | ||
| 11 | use hal::sai::*; | ||
| 12 | use hal::time::Hertz; | ||
| 13 | use panic_probe as _; | ||
| 14 | |||
| 15 | const BLOCK_LENGTH: usize = 32; // 32 samples | ||
| 16 | const HALF_DMA_BUFFER_LENGTH: usize = BLOCK_LENGTH * 2; // 2 channels | ||
| 17 | const DMA_BUFFER_LENGTH: usize = HALF_DMA_BUFFER_LENGTH * 2; // 2 half-blocks | ||
| 18 | const 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"] | ||
| 22 | static mut TX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit(); | ||
| 23 | #[link_section = ".sram1_bss"] | ||
| 24 | static mut RX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit(); | ||
| 25 | |||
| 26 | #[embassy_executor::main] | ||
| 27 | async 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 | |||
| 122 | const 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 | } | ||
