embassy_stm32/spdifrx/
mod.rs1#![macro_use]
3#![cfg_attr(gpdma, allow(unused))]
4
5use core::marker::PhantomData;
6
7use embassy_hal_internal::{into_ref, PeripheralRef};
8use embassy_sync::waitqueue::AtomicWaker;
9
10use crate::dma::ringbuffer::Error as RingbufferError;
11pub use crate::dma::word;
12#[cfg(not(gpdma))]
13use crate::dma::ReadableRingBuffer;
14use crate::dma::{Channel, TransferOptions};
15use crate::gpio::{AfType, AnyPin, Pull, SealedPin as _};
16use crate::interrupt::typelevel::Interrupt;
17use crate::pac::spdifrx::Spdifrx as Regs;
18use crate::rcc::{RccInfo, SealedRccPeripheral};
19use crate::{interrupt, peripherals, Peripheral};
20
21#[allow(dead_code)]
23#[repr(u8)]
24enum PreambleType {
25 Unused = 0x00,
26 B = 0x01,
29 M = 0x02,
32 W = 0x03,
35}
36
37macro_rules! new_spdifrx_pin {
38 ($name:ident, $af_type:expr) => {{
39 let pin = $name.into_ref();
40 let input_sel = pin.input_sel();
41 pin.set_as_af(pin.af_num(), $af_type);
42 (Some(pin.map_into()), input_sel)
43 }};
44}
45
46macro_rules! impl_spdifrx_pin {
47 ($inst:ident, $pin:ident, $af:expr, $sel:expr) => {
48 impl crate::spdifrx::InPin<peripherals::$inst> for crate::peripherals::$pin {
49 fn af_num(&self) -> u8 {
50 $af
51 }
52 fn input_sel(&self) -> u8 {
53 $sel
54 }
55 }
56 };
57}
58
59#[cfg(not(gpdma))]
63pub struct Spdifrx<'d, T: Instance> {
64 _peri: PeripheralRef<'d, T>,
65 spdifrx_in: Option<PeripheralRef<'d, AnyPin>>,
66 data_ring_buffer: ReadableRingBuffer<'d, u32>,
67}
68
69fn dr_address(r: Regs) -> *mut u32 {
71 #[cfg(spdifrx_v1)]
72 let address = r.dr().as_ptr() as _;
73 #[cfg(spdifrx_h7)]
74 let address = r.fmt0_dr().as_ptr() as _; return address;
77}
78
79#[allow(unused)]
81fn csr_address(r: Regs) -> *mut u32 {
82 r.csr().as_ptr() as _
83}
84
85pub enum ControlChannelSelection {
87 A,
89 B,
91}
92
93pub struct Config {
95 pub control_channel_selection: ControlChannelSelection,
97}
98
99#[derive(Debug)]
101pub enum Error {
102 RingbufferError(RingbufferError),
104 ChannelSyncError,
106}
107
108impl From<RingbufferError> for Error {
109 fn from(error: RingbufferError) -> Self {
110 Self::RingbufferError(error)
111 }
112}
113
114impl Default for Config {
115 fn default() -> Self {
116 Self {
117 control_channel_selection: ControlChannelSelection::A,
118 }
119 }
120}
121
122#[cfg(not(gpdma))]
123impl<'d, T: Instance> Spdifrx<'d, T> {
124 fn dma_opts() -> TransferOptions {
125 TransferOptions {
126 half_transfer_ir: true,
127 ..Default::default()
129 }
130 }
131
132 pub fn new(
134 peri: impl Peripheral<P = T> + 'd,
135 _irq: impl interrupt::typelevel::Binding<T::GlobalInterrupt, GlobalInterruptHandler<T>> + 'd,
136 config: Config,
137 spdifrx_in: impl Peripheral<P = impl InPin<T>> + 'd,
138 data_dma: impl Peripheral<P = impl Channel + Dma<T>> + 'd,
139 data_dma_buf: &'d mut [u32],
140 ) -> Self {
141 let (spdifrx_in, input_sel) = new_spdifrx_pin!(spdifrx_in, AfType::input(Pull::None));
142 Self::setup(config, input_sel);
143
144 into_ref!(peri, data_dma);
145
146 let regs = T::info().regs;
147 let dr_request = data_dma.request();
148 let dr_ring_buffer =
149 unsafe { ReadableRingBuffer::new(data_dma, dr_request, dr_address(regs), data_dma_buf, Self::dma_opts()) };
150
151 Self {
152 _peri: peri,
153 spdifrx_in,
154 data_ring_buffer: dr_ring_buffer,
155 }
156 }
157
158 fn setup(config: Config, input_sel: u8) {
159 T::info().rcc.enable_and_reset();
160 T::GlobalInterrupt::unpend();
161 unsafe { T::GlobalInterrupt::enable() };
162
163 let regs = T::info().regs;
164
165 regs.imr().write(|imr| {
166 imr.set_ifeie(true); imr.set_syncdie(true); });
169
170 regs.cr().write(|cr| {
171 cr.set_spdifen(0x00); cr.set_rxdmaen(true); cr.set_cbdmaen(false); cr.set_rxsteo(true); cr.set_drfmt(0x01); cr.set_pmsk(false); cr.set_vmsk(false); cr.set_cumsk(true); cr.set_ptmsk(false); cr.set_chsel(match config.control_channel_selection {
185 ControlChannelSelection::A => false,
186 ControlChannelSelection::B => true,
187 }); cr.set_nbtr(0x02); cr.set_wfa(true); cr.set_insel(input_sel); #[cfg(stm32h7)]
194 cr.set_cksen(true); #[cfg(stm32h7)]
197 cr.set_cksbkpen(true); });
199 }
200
201 pub fn start(&mut self) {
203 self.data_ring_buffer.start();
204
205 T::info().regs.cr().modify(|cr| {
206 cr.set_spdifen(0x03); });
208 }
209
210 pub async fn read(&mut self, data: &mut [u32]) -> Result<(), Error> {
217 self.data_ring_buffer.read_exact(data).await?;
218
219 let first_preamble = (data[0] >> 4) & 0b11_u32;
220 if (first_preamble as u8) == (PreambleType::W as u8) {
221 trace!("S/PDIF left/right mismatch");
222
223 self.data_ring_buffer.clear();
225 return Err(Error::ChannelSyncError);
226 };
227
228 for sample in data.as_mut() {
229 if (*sample & (0x0002_u32)) == 0x0001 {
230 *sample = 0;
232 } else {
233 *sample &= 0xFFFFFF00;
235 }
236 }
237
238 Ok(())
239 }
240}
241
242#[cfg(not(gpdma))]
243impl<'d, T: Instance> Drop for Spdifrx<'d, T> {
244 fn drop(&mut self) {
245 T::info().regs.cr().modify(|cr| cr.set_spdifen(0x00));
246 self.spdifrx_in.as_ref().map(|x| x.set_as_disconnected());
247 }
248}
249
250struct State {
251 #[allow(unused)]
252 waker: AtomicWaker,
253}
254
255impl State {
256 const fn new() -> Self {
257 Self {
258 waker: AtomicWaker::new(),
259 }
260 }
261}
262
263struct Info {
264 regs: crate::pac::spdifrx::Spdifrx,
265 rcc: RccInfo,
266}
267
268peri_trait!(
269 irqs: [GlobalInterrupt],
270);
271
272pub trait InPin<T: Instance>: crate::gpio::Pin {
274 fn af_num(&self) -> u8;
276 fn input_sel(&self) -> u8;
278}
279
280dma_trait!(Dma, Instance);
281
282pub struct GlobalInterruptHandler<T: Instance> {
284 _phantom: PhantomData<T>,
285}
286
287impl<T: Instance> interrupt::typelevel::Handler<T::GlobalInterrupt> for GlobalInterruptHandler<T> {
288 unsafe fn on_interrupt() {
289 T::state().waker.wake();
290
291 let regs = T::info().regs;
292 let sr = regs.sr().read();
293
294 if sr.serr() || sr.terr() || sr.ferr() {
295 trace!("SPDIFRX error, resync");
296
297 regs.cr().modify(|cr| cr.set_spdifen(0x00));
299 regs.cr().modify(|cr| cr.set_spdifen(0x03));
300 } else if sr.syncd() {
301 trace!("SPDIFRX sync success");
303 }
304
305 regs.ifcr().write(|ifcr| {
307 ifcr.set_perrcf(true); ifcr.set_ovrcf(true); ifcr.set_sbdcf(true); ifcr.set_syncdcf(true); });
312 }
313}
314
315foreach_peripheral!(
316 (spdifrx, $inst:ident) => {
317 #[allow(private_interfaces)]
318 impl SealedInstance for peripherals::$inst {
319 fn info() -> &'static Info {
320 static INFO: Info = Info{
321 regs: crate::pac::$inst,
322 rcc: crate::peripherals::$inst::RCC_INFO,
323 };
324 &INFO
325 }
326 fn state() -> &'static State {
327 static STATE: State = State::new();
328 &STATE
329 }
330 }
331
332 impl Instance for peripherals::$inst {
333 type GlobalInterrupt = crate::_generated::peripheral_interrupts::$inst::GLOBAL;
334 }
335 };
336);