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