1use embassy_stm32::{
2 self as hal, Peri, peripherals,
3 sai::{
4 self, BitOrder, ClockStrobe, DataSize, FifoThreshold, FrameSyncOffset, FrameSyncPolarity,
5 Mode, StereoMono, SyncInput, TxRx,
6 },
7 time::Hertz,
8};
9use hal::peripherals::*;
10
11use defmt::{info, unwrap};
12use embassy_time::Timer;
13
14use crate::audio::{AudioConfig, AudioPeripherals, Fs};
15
16const I2C_FS: Hertz = Hertz(100_000);
17
18pub struct Codec<'a> {
20 i2c: hal::i2c::I2c<'a, hal::mode::Blocking, hal::i2c::Master>,
21 sai_tx: sai::Sai<'a, peripherals::SAI1, u32>,
22 sai_rx: sai::Sai<'a, peripherals::SAI1, u32>,
23 pub sai_tx_config: sai::Config,
24 pub sai_rx_config: sai::Config,
25}
26
27impl<'a> Codec<'a> {
28 pub async fn new(
29 p: AudioPeripherals<'a>,
30 audio_config: AudioConfig,
31 tx_buffer: &'a mut [u32],
32 rx_buffer: &'a mut [u32],
33 ) -> Self {
34 info!("set up i2c");
35 let mut i2c_config = hal::i2c::Config::default();
36 i2c_config.frequency = I2C_FS;
37 let i2c = embassy_stm32::i2c::I2c::new_blocking(
38 p.i2c2,
39 p.codec_pins.SCL,
40 p.codec_pins.SDA,
41 i2c_config,
42 );
43
44 info!("set up sai");
45 let (sub_block_rx, sub_block_tx) = hal::sai::split_subblocks(p.sai1);
46 let mut sai_rx_config = sai::Config::default();
47 sai_rx_config.mode = Mode::Master;
48 sai_rx_config.tx_rx = TxRx::Receiver;
49 sai_rx_config.sync_output = true;
50 sai_rx_config.clock_strobe = ClockStrobe::Falling;
51 sai_rx_config.master_clock_divider = audio_config.fs.into_clock_divider();
52 sai_rx_config.stereo_mono = StereoMono::Stereo;
53 sai_rx_config.data_size = DataSize::Data24;
54 sai_rx_config.bit_order = BitOrder::MsbFirst;
55 sai_rx_config.frame_sync_polarity = FrameSyncPolarity::ActiveHigh;
56 sai_rx_config.frame_sync_offset = FrameSyncOffset::OnFirstBit;
57 sai_rx_config.frame_length = 64;
58 sai_rx_config.frame_sync_active_level_length = embassy_stm32::sai::word::U7(32);
59 sai_rx_config.fifo_threshold = FifoThreshold::Quarter;
60
61 let mut sai_tx_config = sai_rx_config;
62 sai_tx_config.mode = Mode::Slave;
63 sai_tx_config.tx_rx = TxRx::Transmitter;
64 sai_tx_config.sync_input = SyncInput::Internal;
65 sai_tx_config.clock_strobe = ClockStrobe::Rising;
66 sai_tx_config.sync_output = false;
67
68 let sai_tx = hal::sai::Sai::new_synchronous(
69 sub_block_tx,
70 p.codec_pins.SD_B,
71 p.dma1_ch1,
72 tx_buffer,
73 sai_tx_config,
74 );
75
76 let sai_rx = hal::sai::Sai::new_asynchronous_with_mclk(
77 sub_block_rx,
78 p.codec_pins.SCK_A,
79 p.codec_pins.SD_A,
80 p.codec_pins.FS_A,
81 p.codec_pins.MCLK_A,
82 p.dma1_ch2,
83 rx_buffer,
84 sai_rx_config,
85 );
86
87 let mut codec = Self {
88 i2c,
89 sai_tx,
90 sai_rx,
91 sai_tx_config,
92 sai_rx_config,
93 };
94
95 codec.setup_wm8731(audio_config.fs).await;
96
97 codec
98 }
99
100 async fn setup_wm8731(&mut self, fs: Fs) {
102 use wm8731::WM8731;
103 info!("setup wm8731 from I2C");
104
105 Timer::after_micros(10).await;
106
107 self.write_wm8731_reg(WM8731::reset());
109 Timer::after_micros(10).await;
110
111 self.write_wm8731_reg(WM8731::power_down(|w| {
113 Self::final_power_settings(w);
114 w.output().power_off();
116 }));
117 Timer::after_micros(10).await;
118
119 self.write_wm8731_reg(WM8731::left_line_in(|w| {
121 w.both().enable();
122 w.mute().disable();
123 w.volume().nearest_dB(0);
124 }));
125 Timer::after_micros(10).await;
126
127 self.write_wm8731_reg(WM8731::analog_audio_path(|w| {
129 w.sidetone().disable();
130 w.dac_select().select();
131 w.bypass().disable();
132 w.input_select().line_input();
133 w.mute_mic().enable();
134 w.mic_boost().disable();
135 }));
136 Timer::after_micros(10).await;
137
138 self.write_wm8731_reg(WM8731::digital_audio_path(|w| {
140 w.dac_mut().disable();
141 w.deemphasis().frequency_48();
142 }));
143 Timer::after_micros(10).await;
144
145 self.write_wm8731_reg(WM8731::digital_audio_interface_format(|w| {
147 w.bit_clock_invert().no_invert();
148 w.master_slave().slave();
149 w.left_right_dac_clock_swap().right_channel_dac_data_right();
150 w.left_right_phase().data_when_daclrc_low();
151 w.bit_length().bits_24();
152 w.format().left_justified();
153 }));
154 Timer::after_micros(10).await;
155
156 self.write_wm8731_reg(WM8731::sampling(|w| {
158 w.core_clock_divider_select().normal();
159 w.base_oversampling_rate().normal_256();
160 match fs {
161 Fs::Fs8000 => {
162 w.sample_rate().adc_8();
163 }
164 Fs::Fs32000 => {
165 w.sample_rate().adc_32();
166 }
167 Fs::Fs44100 => {
168 w.sample_rate().adc_441();
169 }
170 Fs::Fs48000 => {
171 w.sample_rate().adc_48();
172 }
173 Fs::Fs88200 => {
174 w.sample_rate().adc_882();
175 }
176 Fs::Fs96000 => {
177 w.sample_rate().adc_96();
178 }
179 }
180 w.usb_normal().normal();
181 }));
182 Timer::after_micros(10).await;
183
184 self.write_wm8731_reg(WM8731::active().active());
186 Timer::after_micros(10).await;
187
188 }
190
191 fn write_wm8731_reg(&mut self, r: wm8731::Register) {
192 const AD: u8 = 0x1a; let byte1: u8 = ((r.address << 1) & 0b1111_1110) | (((r.value >> 8) & 0b0000_0001) as u8);
198 let byte2: u8 = (r.value & 0b1111_1111) as u8;
199 unwrap!(self.i2c.blocking_write(AD, &[byte1, byte2]));
200 }
201
202 fn final_power_settings(w: &mut wm8731::power_down::PowerDown) {
203 w.power_off().power_on();
204 w.clock_output().power_off();
205 w.oscillator().power_off();
206 w.output().power_on();
207 w.dac().power_on();
208 w.adc().power_on();
209 w.mic().power_off();
210 w.line_input().power_on();
211 }
212
213 pub async fn start(&mut self) -> Result<(), sai::Error> {
214 info!("start WM8731");
215 self.write_wm8731_reg(wm8731::WM8731::power_down(Self::final_power_settings));
216 embassy_time::Timer::after_micros(10).await;
217
218 info!("start SAI");
219 self.sai_rx.start()
220 }
221
222 pub fn release(
223 self,
224 ) -> (
225 sai::Sai<'a, SAI1, u32>,
226 sai::Sai<'a, SAI1, u32>,
227 hal::i2c::I2c<'a, hal::mode::Blocking, hal::i2c::Master>,
228 ) {
229 (self.sai_tx, self.sai_rx, self.i2c)
230 }
231
232 pub async fn read(&mut self, read_buf: &mut [u32]) -> Result<(), sai::Error> {
233 self.sai_rx.read(read_buf).await
234 }
235
236 pub async fn write(&mut self, write_buf: &[u32]) -> Result<(), sai::Error> {
237 self.sai_tx.write(write_buf).await
238 }
239}
240
241#[allow(non_snake_case)]
242pub struct Pins<'a> {
243 pub SCL: Peri<'a, PH4>, pub SDA: Peri<'a, PB11>, pub MCLK_A: Peri<'a, PE2>, pub SCK_A: Peri<'a, PE5>, pub FS_A: Peri<'a, PE4>, pub SD_A: Peri<'a, PE6>, pub SD_B: Peri<'a, PE3>, }