1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//! This library supports I2S communication for SPI version 1.2 of STM32 microcontrollers (STM32F1,
//! STM32F2, STM32F4, STM32L0, and STM32L1). This library may also work with SPI version 1.3
//! (STM32F0 STM32F3 STM32F7 STM32L4 STM32L5)
//!
//! This library is normally used through a MCU HAL library providing types that implement
//! [`I2sPeripheral`] or [`DualI2sPeripheral`]. [`I2sDriver`](driver::I2sDriver) or
//! [`I2sTransfer`](transfer::I2sTransfer) objects can be created around I2sPeripheral objects to
//! have a single bus for I2S communication, and [`DualI2sDriver`](driver::DualI2sDriver) objects can
//! be created around DualI2sPeripheral for full duplex I2S
//! communication.
//!
//! # For STM32 MCU HAL implementers
//!
//! To support I2S by using this library, HAL implementers must implements [`I2sPeripheral`],
//! [`DualI2sPeripheral`] and [`WsPin`] and  trait and reexport this crate. It's also recommended
//! to create some examples. For reference, implementation and examples are (or will be soon)
//! available in [stm32f4xx-hal](https://github.com/stm32-rs/stm32f4xx-hal/).
//!
//! # For I2S users
//!
//! You should use use this library through a MCU HAL. For fine control and advanced usage,
//! see the [driver] module. For quick and basic usage, see the [transfer] module.
//!
//! # About PCM standards
//!
//! Almost all information you can get about PCM mode in STM32 datasheets are wrong, or confusing
//! at least. Compared to other modes:
//!  - PCM is monophonic; this is why the Channel flag information is meaningless.
//!  - With the same prescaler configuration, the sampling frequency is doubled. This is because
//!  the bit rate is the same with half the samples.
//!  - When master clock is enabled, its frequency is 128 * sampling_frequency, instead of 256 *
//!  sampling_frequency.
//!
//! # Issues and limitations
//! - In master transmit mode, the CHSIDE flag appears to be sporadically wrong, so don't use it.
//! - Depending on your chip, data corruption may occur under some configurations. Check the
//!   errata of your chip for more information.
//!
//!
#![no_std]

mod pac;

pub mod driver;
pub mod marker;
pub mod transfer;

mod sealed {
    pub trait Sealed {}
}

/// An object composed of a SPI device that can be used for I2S communication.
///
/// This trait is meant to be implemented on a type that represent a full SPI device. That means an
/// object composed of a SPI peripheral, pins that it uses, and eventually a clock object (which can be a
/// reference).
///
/// # Safety
///
/// It is only safe to implement this trait when:
///
/// * The implementing type has ownership of the peripheral, preventing any other accesses to the
///   register block.
/// * `REGISTERS` is a pointer to that peripheral's register block and can be safely accessed  as
///   long as ownership or a borrow of the implementing type is present.
pub unsafe trait I2sPeripheral {
    type WsPin: WsPin;
    /// Pointer to the SPI register block
    const REGISTERS: *const ();
    /// Get I2s clock source frequency from the I2s device.
    ///
    /// Implementers are allowed to panic in case i2s source frequency is unavailable.
    fn i2s_freq(&self) -> u32;
    /// Get a reference to WS pin.
    fn ws_pin(&self) -> &Self::WsPin;
    /// Get mutable reference to WS pin;
    fn ws_pin_mut(&mut self) -> &mut Self::WsPin;
    /// Reset the peripheral through the rcc register. This must be implemented with atomic
    /// operations through writes to the bit band region.
    fn rcc_reset(&mut self);
}

/// An object that can be used for full duplex I2S communication.
///
/// This trait is meant to be implemented on a type that represent a device supporting full duplex
/// I2S operation. This object should be composed of
///  - A SPI peripheral with I2S support
///  - The corresponding I2SEXT peripheral
///  - Pins that the peripherals use
///  - Eventually a clock object (or reference)
///
/// # Safety
///
/// It is only safe to implement this trait when:
///
/// * The implementing type has ownership of the peripherals, preventing any other accesses to the
/// register blocks.
/// * `MAIN_REGISTERS` and `EXT_REGISTERS` are pointers to that peripheral's register blocks and
/// can be safely accessed  as long as ownership or a borrow of the implementing type is present.
pub unsafe trait DualI2sPeripheral {
    type WsPin: WsPin;
    /// Pointer to the SPI register block
    const MAIN_REGISTERS: *const ();
    /// Pointer to the I2SEXT register block
    const EXT_REGISTERS: *const ();
    /// Get I2s clock source frequency from the I2s device.
    ///
    /// Implementers are allowed to panic in case i2s source frequency is unavailable.
    fn i2s_freq(&self) -> u32;
    /// Get a reference to WS pin.
    fn ws_pin(&self) -> &Self::WsPin;
    /// Get mutable reference to WS pin;
    fn ws_pin_mut(&mut self) -> &mut Self::WsPin;
    /// Reset the peripheral through the rcc register. This must be implemented with atomic
    /// operation through write to bit band region.
    fn rcc_reset(&mut self);
}

/// A pin carrying the WS (word select) signal from/to an i2s peripheral.
///
/// Implementing this trait means implementing read operation on a pin physically configured in
/// alternate mode.
pub trait WsPin {
    /// Return `true` if the level at WS pin is low.
    fn is_low(&self) -> bool;
    /// Return `true` if the level at WS pin is high.
    fn is_high(&self) -> bool;
}