STMicroelectronics' implementation of an I2S driver, also including DMA support.
Dependents: temp X_NUCLEO_CCA01M1 X_NUCLEO_CCA01M1 X_NUCLEO_CCA02M1
Platform compatibility
This driver has been designed to support a wide range of the Nucleo F4 Family of platforms and MCUs, but not all members of this family support I2S and/or some of the members might require slight modifications to the sources of this driver in order to make it work on those.
This driver has for now been tested only with the following platforms:
hal/stm_i2s_api.h@31:bb4bac0874da, 2017-07-12 (annotated)
- Committer:
- Wolfgang Betz
- Date:
- Wed Jul 12 15:24:49 2017 +0200
- Revision:
- 31:bb4bac0874da
- Parent:
- 9:c4c2240e06d6
Merge branch 'master' into betzw_wb
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| Wolfgang Betz |
1:f90318e0923b | 1 | #ifndef STM_I2S_API_H |
| Wolfgang Betz |
1:f90318e0923b | 2 | #define STM_I2S_API_H |
| Wolfgang Betz |
1:f90318e0923b | 3 | |
| Wolfgang Betz |
1:f90318e0923b | 4 | #include <stdbool.h> |
| Wolfgang Betz |
1:f90318e0923b | 5 | |
| Wolfgang Betz |
1:f90318e0923b | 6 | #include "device.h" |
| Wolfgang Betz |
1:f90318e0923b | 7 | #include "stm_objects.h" |
| Wolfgang Betz |
1:f90318e0923b | 8 | #include "hal/stm_dma_api.h" |
| Wolfgang Betz |
1:f90318e0923b | 9 | #include "hal/buffer.h" |
| Wolfgang Betz |
1:f90318e0923b | 10 | |
| Wolfgang Betz |
1:f90318e0923b | 11 | #if DEVICE_I2S |
| Wolfgang Betz |
1:f90318e0923b | 12 | |
| Wolfgang Betz |
1:f90318e0923b | 13 | #define I2S_EVENT_RX_ERROR (1 << 1) // 0x2 |
| Wolfgang Betz |
1:f90318e0923b | 14 | #define I2S_EVENT_RX_COMPLETE (1 << 2) // 0x4 |
| Wolfgang Betz |
1:f90318e0923b | 15 | #define I2S_EVENT_RX_OVERFLOW (1 << 3) // 0x8 |
| Wolfgang Betz |
1:f90318e0923b | 16 | #define I2S_EVENT_RX_HALF_COMPLETE (1 << 4) // 0x10 |
| Wolfgang Betz |
1:f90318e0923b | 17 | |
| Wolfgang Betz |
1:f90318e0923b | 18 | #define I2S_EVENT_TX_ERROR (I2S_EVENT_RX_ERROR << 8) // 0x200 |
| Wolfgang Betz |
1:f90318e0923b | 19 | #define I2S_EVENT_TX_COMPLETE (I2S_EVENT_RX_COMPLETE << 8) // 0x400 |
| Wolfgang Betz |
1:f90318e0923b | 20 | #define I2S_EVENT_TX_UNDERRUN (I2S_EVENT_RX_OVERFLOW << 8) // 0x800 |
| Wolfgang Betz |
1:f90318e0923b | 21 | #define I2S_EVENT_TX_HALF_COMPLETE (I2S_EVENT_RX_HALF_COMPLETE << 8) // 0x1000 |
| Wolfgang Betz |
1:f90318e0923b | 22 | |
| Wolfgang Betz |
1:f90318e0923b | 23 | #define I2S_EVENT_ALL ((I2S_EVENT_RX_ERROR | I2S_EVENT_RX_COMPLETE | I2S_EVENT_RX_OVERFLOW | I2S_EVENT_RX_HALF_COMPLETE) | \ |
| Wolfgang Betz |
1:f90318e0923b | 24 | (I2S_EVENT_TX_ERROR | I2S_EVENT_TX_COMPLETE | I2S_EVENT_TX_UNDERRUN | I2S_EVENT_TX_HALF_COMPLETE)) |
| Wolfgang Betz |
1:f90318e0923b | 25 | |
| Wolfgang Betz |
1:f90318e0923b | 26 | #define I2S_EVENT_INTERNAL_TRANSFER_COMPLETE (1 << 30) // Internal flag to report that an event occurred |
| Wolfgang Betz |
1:f90318e0923b | 27 | |
| Wolfgang Betz |
1:f90318e0923b | 28 | #define I2S_TX_EVENT (0x0) // see DMA_TX |
| Wolfgang Betz |
1:f90318e0923b | 29 | #define I2S_RX_EVENT (0x1) // see DMA_RX |
| Wolfgang Betz |
1:f90318e0923b | 30 | |
| Wolfgang Betz |
1:f90318e0923b | 31 | typedef enum { |
| Wolfgang Betz |
9:c4c2240e06d6 | 32 | PHILIPS, |
| Wolfgang Betz |
9:c4c2240e06d6 | 33 | MSB, |
| Wolfgang Betz |
9:c4c2240e06d6 | 34 | LSB, |
| Wolfgang Betz |
9:c4c2240e06d6 | 35 | PCM_SHORT, |
| Wolfgang Betz |
9:c4c2240e06d6 | 36 | PCM_LONG |
| Wolfgang Betz |
1:f90318e0923b | 37 | } i2s_bitorder_t; |
| Wolfgang Betz |
1:f90318e0923b | 38 | |
| Wolfgang Betz |
1:f90318e0923b | 39 | typedef enum { |
| Wolfgang Betz |
9:c4c2240e06d6 | 40 | SLAVE_TX, |
| Wolfgang Betz |
9:c4c2240e06d6 | 41 | SLAVE_RX, |
| Wolfgang Betz |
9:c4c2240e06d6 | 42 | MASTER_TX, |
| Wolfgang Betz |
9:c4c2240e06d6 | 43 | MASTER_RX |
| Wolfgang Betz |
1:f90318e0923b | 44 | } i2s_mode_t; |
| Wolfgang Betz |
1:f90318e0923b | 45 | |
| Wolfgang Betz |
1:f90318e0923b | 46 | typedef enum { |
| Wolfgang Betz |
9:c4c2240e06d6 | 47 | LOW, |
| Wolfgang Betz |
9:c4c2240e06d6 | 48 | MEDIUM, |
| Wolfgang Betz |
9:c4c2240e06d6 | 49 | HIGH, |
| Wolfgang Betz |
9:c4c2240e06d6 | 50 | URGENT |
| Wolfgang Betz |
1:f90318e0923b | 51 | } i2s_dma_prio_t; |
| Wolfgang Betz |
1:f90318e0923b | 52 | |
| Wolfgang Betz |
1:f90318e0923b | 53 | /** Asynch I2S HAL structure |
| Wolfgang Betz |
1:f90318e0923b | 54 | */ |
| Wolfgang Betz |
1:f90318e0923b | 55 | typedef struct { |
| Wolfgang Betz |
1:f90318e0923b | 56 | struct i2s_s i2s; /**< Target specific I2S structure */ |
| Wolfgang Betz |
1:f90318e0923b | 57 | struct dma_s dma; /**< Target specific DMA structure */ |
| Wolfgang Betz |
1:f90318e0923b | 58 | struct buffer_s tx_buff; /**< Tx buffer */ |
| Wolfgang Betz |
1:f90318e0923b | 59 | struct buffer_s rx_buff; /**< Rx buffer */ |
| Wolfgang Betz |
1:f90318e0923b | 60 | } i2s_t; |
| Wolfgang Betz |
1:f90318e0923b | 61 | |
| Wolfgang Betz |
1:f90318e0923b | 62 | #ifdef __cplusplus |
| Wolfgang Betz |
1:f90318e0923b | 63 | extern "C" { |
| Wolfgang Betz |
1:f90318e0923b | 64 | #endif |
| Wolfgang Betz |
1:f90318e0923b | 65 | |
| Wolfgang Betz |
1:f90318e0923b | 66 | /** |
| Wolfgang Betz |
1:f90318e0923b | 67 | * \defgroup hal_GeneralI2S I2S Configuration Functions |
| Wolfgang Betz |
1:f90318e0923b | 68 | * @{ |
| Wolfgang Betz |
1:f90318e0923b | 69 | */ |
| Wolfgang Betz |
1:f90318e0923b | 70 | |
| Wolfgang Betz |
1:f90318e0923b | 71 | /** Initialize the I2S peripheral |
| Wolfgang Betz |
1:f90318e0923b | 72 | * |
| Wolfgang Betz |
1:f90318e0923b | 73 | * Configures the pins used by I2S, sets a default format and frequency, and enables the peripheral |
| Wolfgang Betz |
1:f90318e0923b | 74 | * @param[out] obj The I2S object to initialize |
| Wolfgang Betz |
1:f90318e0923b | 75 | * @param[in] data I2S data input/output pin |
| Wolfgang Betz |
1:f90318e0923b | 76 | * @param[in] sclk I2S clock output pin |
| Wolfgang Betz |
1:f90318e0923b | 77 | * @param[in] wsel I2S word select output pin (might be NC for PDM sources) |
| Wolfgang Betz |
1:f90318e0923b | 78 | * @param[in] fdpx I2S data input pin (for full-duplex operation, default = NC) |
| Wolfgang Betz |
1:f90318e0923b | 79 | * @param[in] mclk I2S master clock output pin (default = NC, enables master clock output when not NC) |
| Wolfgang Betz |
1:f90318e0923b | 80 | * @param[in] mode I2S mode to be applied |
| Wolfgang Betz |
1:f90318e0923b | 81 | */ |
| Wolfgang Betz |
9:c4c2240e06d6 | 82 | void i2s_init(i2s_t *obj, PinName data, PinName sclk, PinName wsel, PinName fdpx, PinName mclk, i2s_mode_t mode); |
| Wolfgang Betz |
1:f90318e0923b | 83 | |
| Wolfgang Betz |
1:f90318e0923b | 84 | /** Release a I2S object |
| Wolfgang Betz |
1:f90318e0923b | 85 | * |
| Wolfgang Betz |
1:f90318e0923b | 86 | * TODO: i2s_free is currently unimplemented |
| Wolfgang Betz |
1:f90318e0923b | 87 | * This will require reference counting at the C++ level to be safe |
| Wolfgang Betz |
1:f90318e0923b | 88 | * |
| Wolfgang Betz |
1:f90318e0923b | 89 | * Return the pins owned by the I2S object to their reset state |
| Wolfgang Betz |
1:f90318e0923b | 90 | * Disable the I2S peripheral |
| Wolfgang Betz |
1:f90318e0923b | 91 | * Disable the I2S clock |
| Wolfgang Betz |
1:f90318e0923b | 92 | * @param[in] obj The I2S object to deinitialize |
| Wolfgang Betz |
1:f90318e0923b | 93 | */ |
| Wolfgang Betz |
9:c4c2240e06d6 | 94 | void i2s_free(i2s_t *obj); |
| Wolfgang Betz |
1:f90318e0923b | 95 | |
| Wolfgang Betz |
1:f90318e0923b | 96 | /** Configure the I2S format |
| Wolfgang Betz |
1:f90318e0923b | 97 | * |
| Wolfgang Betz |
1:f90318e0923b | 98 | * Set the number of bits per frame, configure clock polarity and phase, shift order and master/slave mode |
| Wolfgang Betz |
1:f90318e0923b | 99 | * @param[in,out] obj The I2S object to configure |
| Wolfgang Betz |
1:f90318e0923b | 100 | * @param[in] dbits Number of data bits per I2S frame (16, 24, or 32) |
| Wolfgang Betz |
1:f90318e0923b | 101 | * @param[in] fbits Number of bits per I2S frame (16 or 32) |
| Wolfgang Betz |
1:f90318e0923b | 102 | * @param[in] polarity Clock polarity (either 0 or 1, default = 0) |
| Wolfgang Betz |
1:f90318e0923b | 103 | */ |
| Wolfgang Betz |
9:c4c2240e06d6 | 104 | void i2s_format(i2s_t *obj, int dbits, int fbits, int polarity); |
| Wolfgang Betz |
1:f90318e0923b | 105 | |
| Wolfgang Betz |
1:f90318e0923b | 106 | /** Configure the I2S protocol |
| Wolfgang Betz |
1:f90318e0923b | 107 | * |
| Wolfgang Betz |
1:f90318e0923b | 108 | * @param[in,out] obj The I2S object to configure |
| Wolfgang Betz |
1:f90318e0923b | 109 | * @param[in] protocol I2S protocol to be used |
| Wolfgang Betz |
1:f90318e0923b | 110 | */ |
| Wolfgang Betz |
9:c4c2240e06d6 | 111 | void i2s_set_protocol(i2s_t *obj, i2s_bitorder_t protocol); |
| Wolfgang Betz |
1:f90318e0923b | 112 | |
| Wolfgang Betz |
1:f90318e0923b | 113 | /** Configure the I2S mode |
| Wolfgang Betz |
1:f90318e0923b | 114 | * |
| Wolfgang Betz |
1:f90318e0923b | 115 | * @param[in,out] obj The I2S object to configure |
| Wolfgang Betz |
1:f90318e0923b | 116 | * @param[in] mode I2S mode to be applied |
| Wolfgang Betz |
1:f90318e0923b | 117 | */ |
| Wolfgang Betz |
9:c4c2240e06d6 | 118 | void i2s_set_mode(i2s_t *obj, i2s_mode_t mode); |
| Wolfgang Betz |
1:f90318e0923b | 119 | |
| Wolfgang Betz |
1:f90318e0923b | 120 | /** Set the I2S audio frequency |
| Wolfgang Betz |
1:f90318e0923b | 121 | * |
| Wolfgang Betz |
1:f90318e0923b | 122 | * Actual frequency may differ from the desired frequency due to available dividers and bus clock |
| Wolfgang Betz |
1:f90318e0923b | 123 | * Configures the I2S audio frequency |
| Wolfgang Betz |
1:f90318e0923b | 124 | * @param[in,out] obj The I2S object to configure |
| Wolfgang Betz |
1:f90318e0923b | 125 | * @param[in] hz The baud rate in Hz |
| Wolfgang Betz |
1:f90318e0923b | 126 | */ |
| Wolfgang Betz |
9:c4c2240e06d6 | 127 | void i2s_audio_frequency(i2s_t *obj, uint32_t hz); |
| Wolfgang Betz |
1:f90318e0923b | 128 | |
| Wolfgang Betz |
1:f90318e0923b | 129 | /**@}*/ |
| Wolfgang Betz |
1:f90318e0923b | 130 | /** |
| Wolfgang Betz |
1:f90318e0923b | 131 | * \defgroup SynchI2S Synchronous I2S Hardware Abstraction Layer |
| Wolfgang Betz |
1:f90318e0923b | 132 | * @{ |
| Wolfgang Betz |
1:f90318e0923b | 133 | */ |
| Wolfgang Betz |
1:f90318e0923b | 134 | |
| Wolfgang Betz |
1:f90318e0923b | 135 | /** Get the module number |
| Wolfgang Betz |
1:f90318e0923b | 136 | * |
| Wolfgang Betz |
1:f90318e0923b | 137 | * @param[in] obj The I2S peripheral to check |
| Wolfgang Betz |
1:f90318e0923b | 138 | * @return The module number |
| Wolfgang Betz |
1:f90318e0923b | 139 | */ |
| Wolfgang Betz |
9:c4c2240e06d6 | 140 | uint8_t i2s_get_module(i2s_t *obj); |
| Wolfgang Betz |
1:f90318e0923b | 141 | |
| Wolfgang Betz |
1:f90318e0923b | 142 | /**@}*/ |
| Wolfgang Betz |
1:f90318e0923b | 143 | |
| Wolfgang Betz |
1:f90318e0923b | 144 | /** |
| Wolfgang Betz |
1:f90318e0923b | 145 | * \defgroup AsynchI2S Asynchronous I2S Hardware Abstraction Layer |
| Wolfgang Betz |
1:f90318e0923b | 146 | * @{ |
| Wolfgang Betz |
1:f90318e0923b | 147 | */ |
| Wolfgang Betz |
1:f90318e0923b | 148 | |
| Wolfgang Betz |
1:f90318e0923b | 149 | /** Begin the I2S transfer. Buffer pointers and lengths are specified in tx_buff and rx_buff |
| Wolfgang Betz |
1:f90318e0923b | 150 | * |
| Wolfgang Betz |
1:f90318e0923b | 151 | * @param[in] obj The I2S object that holds the transfer information |
| Wolfgang Betz |
1:f90318e0923b | 152 | * @param[in] tx The transmit buffer |
| Wolfgang Betz |
1:f90318e0923b | 153 | * @param[in] tx_length The number of bytes to transmit |
| Wolfgang Betz |
1:f90318e0923b | 154 | * @param[in] rx The receive buffer |
| Wolfgang Betz |
1:f90318e0923b | 155 | * @param[in] rx_length The number of bytes to receive |
| Wolfgang Betz |
1:f90318e0923b | 156 | * @param[in] circular Enable circular buffer transfer |
| Wolfgang Betz |
1:f90318e0923b | 157 | * @param[in] prio DMA priority of the transfer |
| Wolfgang Betz |
1:f90318e0923b | 158 | * @param[in] handler_tx I2S tx interrupt handler |
| Wolfgang Betz |
1:f90318e0923b | 159 | * @param[in] handler_rx I2S rx interrupt handler |
| Wolfgang Betz |
1:f90318e0923b | 160 | * @param[in] event The logical OR of events to be registered |
| Wolfgang Betz |
1:f90318e0923b | 161 | */ |
| Wolfgang Betz |
9:c4c2240e06d6 | 162 | void i2s_transfer(i2s_t *obj, void *tx, int tx_length, void *rx, int rx_length, |
| Wolfgang Betz |
9:c4c2240e06d6 | 163 | bool circular, i2s_dma_prio_t prio, |
| Wolfgang Betz |
9:c4c2240e06d6 | 164 | uint32_t handler_tx, uint32_t handler_rx, |
| Wolfgang Betz |
9:c4c2240e06d6 | 165 | uint32_t event); |
| Wolfgang Betz |
1:f90318e0923b | 166 | |
| Wolfgang Betz |
1:f90318e0923b | 167 | /** The asynchronous IRQ handler |
| Wolfgang Betz |
1:f90318e0923b | 168 | * |
| Wolfgang Betz |
1:f90318e0923b | 169 | * Reads the received values out of the RX FIFO, writes values into the TX FIFO and checks for transfer termination |
| Wolfgang Betz |
1:f90318e0923b | 170 | * conditions, such as buffer overflows or transfer complete. |
| Wolfgang Betz |
1:f90318e0923b | 171 | * @param[in] obj The I2S object that holds the transfer information |
| Wolfgang Betz |
1:f90318e0923b | 172 | * @param[in] direction From whom is the irq coming (RX or TX) |
| Wolfgang Betz |
1:f90318e0923b | 173 | * @return Event flags if a transfer termination condition was met; otherwise 0. |
| Wolfgang Betz |
1:f90318e0923b | 174 | */ |
| Wolfgang Betz |
9:c4c2240e06d6 | 175 | uint32_t i2s_irq_handler_asynch(i2s_t *obj, uint8_t direction); |
| Wolfgang Betz |
1:f90318e0923b | 176 | |
| Wolfgang Betz |
1:f90318e0923b | 177 | /** Attempts to determine if the I2S peripheral is already in use |
| Wolfgang Betz |
1:f90318e0923b | 178 | * |
| Wolfgang Betz |
1:f90318e0923b | 179 | * For each assigned buffer, check |
| Wolfgang Betz |
1:f90318e0923b | 180 | * if the corresponding buffer position is less than the buffer length. If buffers do not indicate activity, check if |
| Wolfgang Betz |
1:f90318e0923b | 181 | * there are any bytes in the FIFOs. |
| Wolfgang Betz |
1:f90318e0923b | 182 | * @param[in] obj The I2S object to check for activity |
| Wolfgang Betz |
1:f90318e0923b | 183 | * @return Non-zero if the I2S port is active or zero if it is not. |
| Wolfgang Betz |
1:f90318e0923b | 184 | */ |
| Wolfgang Betz |
9:c4c2240e06d6 | 185 | uint8_t i2s_active(i2s_t *obj); |
| Wolfgang Betz |
1:f90318e0923b | 186 | |
| Wolfgang Betz |
1:f90318e0923b | 187 | /** Abort an I2S transfer |
| Wolfgang Betz |
1:f90318e0923b | 188 | * |
| Wolfgang Betz |
1:f90318e0923b | 189 | * @param obj The I2S peripheral to stop |
| Wolfgang Betz |
1:f90318e0923b | 190 | */ |
| Wolfgang Betz |
9:c4c2240e06d6 | 191 | void i2s_abort_asynch(i2s_t *obj); |
| Wolfgang Betz |
1:f90318e0923b | 192 | |
| Davide Aliprandi |
4:21603d68bcf7 | 193 | /** |
| Wolfgang Betz |
9:c4c2240e06d6 | 194 | * @brief Harmonize frequencies of two I2S devices |
| Wolfgang Betz |
9:c4c2240e06d6 | 195 | * TODO: doxygen description |
| Wolfgang Betz |
9:c4c2240e06d6 | 196 | * @return Zero if the frequencies have been harmonized correctly, -1 |
| Wolfgang Betz |
9:c4c2240e06d6 | 197 | * otherwise. |
| Wolfgang Betz |
9:c4c2240e06d6 | 198 | */ |
| Wolfgang Betz |
9:c4c2240e06d6 | 199 | int8_t i2s_harmonize(i2s_t *dev_i2s_1, uint32_t *freq_i2s_1, i2s_t *dev_i2s_2, uint32_t *freq_i2s_2); |
| Wolfgang Betz |
1:f90318e0923b | 200 | |
| Wolfgang Betz |
1:f90318e0923b | 201 | /**@}*/ |
| Wolfgang Betz |
1:f90318e0923b | 202 | |
| Wolfgang Betz |
1:f90318e0923b | 203 | #ifdef __cplusplus |
| Wolfgang Betz |
1:f90318e0923b | 204 | } |
| Wolfgang Betz |
1:f90318e0923b | 205 | #endif // __cplusplus |
| Wolfgang Betz |
1:f90318e0923b | 206 | |
| Wolfgang Betz |
1:f90318e0923b | 207 | #endif // DEVICE_I2S |
| Wolfgang Betz |
1:f90318e0923b | 208 | |
| Wolfgang Betz |
1:f90318e0923b | 209 | #endif // STM_I2S_API_H |