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:

Committer:
Wolfgang Betz
Date:
Wed Jul 12 15:24:49 2017 +0200
Revision:
31:bb4bac0874da
Parent:
22:e04af8667cad
Merge branch 'master' into betzw_wb

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Wolfgang Betz 0:752e74bf5ef1 1 #ifndef MBED_I2S_H
Wolfgang Betz 0:752e74bf5ef1 2 #define MBED_I2S_H
Wolfgang Betz 0:752e74bf5ef1 3
Wolfgang Betz 0:752e74bf5ef1 4 #include "platform/platform.h"
Wolfgang Betz 0:752e74bf5ef1 5
Wolfgang Betz 0:752e74bf5ef1 6 #if DEVICE_I2S
Wolfgang Betz 0:752e74bf5ef1 7
Wolfgang Betz 0:752e74bf5ef1 8 #include "platform/PlatformMutex.h"
Wolfgang Betz 1:f90318e0923b 9 #include "hal/stm_i2s_api.h"
Wolfgang Betz 0:752e74bf5ef1 10 #include "platform/SingletonPtr.h"
Wolfgang Betz 0:752e74bf5ef1 11
Wolfgang Betz 0:752e74bf5ef1 12 #include "platform/CThunk.h"
Wolfgang Betz 1:f90318e0923b 13 #include "hal/stm_dma_api.h"
Wolfgang Betz 0:752e74bf5ef1 14 #include "platform/CircularBuffer.h"
Wolfgang Betz 0:752e74bf5ef1 15 #include "platform/FunctionPointer.h"
Wolfgang Betz 0:752e74bf5ef1 16 #include "platform/Transaction.h"
Wolfgang Betz 0:752e74bf5ef1 17
Wolfgang Betz 0:752e74bf5ef1 18 #include "events/EventQueue.h"
Wolfgang Betz 0:752e74bf5ef1 19
Wolfgang Betz 0:752e74bf5ef1 20 /** A I2S Master/Slave, used for communicating with I2S slave/master devices
Wolfgang Betz 0:752e74bf5ef1 21 *
Wolfgang Betz 0:752e74bf5ef1 22 * The default format is set to master transmission mode, one-shot (i.e. not circular)
Wolfgang Betz 0:752e74bf5ef1 23 * 16 data bits & 16 bits per frame, clock polarity 0,
Wolfgang Betz 0:752e74bf5ef1 24 * protocol PHILIPS, and a clock frequency of 44.1kHz
Wolfgang Betz 0:752e74bf5ef1 25 *
Wolfgang Betz 0:752e74bf5ef1 26 * Most I2S devices will also require Reset signals. These
Wolfgang Betz 0:752e74bf5ef1 27 * can be controlled using <DigitalOut> pins
Wolfgang Betz 0:752e74bf5ef1 28 *
Wolfgang Betz 0:752e74bf5ef1 29 * @Note Synchronization level: Thread safe
Wolfgang Betz 0:752e74bf5ef1 30 *
Wolfgang Betz 0:752e74bf5ef1 31 */
Wolfgang Betz 10:1a612c2e4a85 32 class I2S {
Wolfgang Betz 0:752e74bf5ef1 33
Wolfgang Betz 10:1a612c2e4a85 34 public:
Wolfgang Betz 10:1a612c2e4a85 35 /** Create a I2S master connected to the specified pins
Wolfgang Betz 10:1a612c2e4a85 36 *
Wolfgang Betz 10:1a612c2e4a85 37 * @param dpin I2S data input/output pin
Wolfgang Betz 10:1a612c2e4a85 38 * @param clk I2S clock output pin
Wolfgang Betz 10:1a612c2e4a85 39 * @param wsel I2S word select output pin (might be NC for PDM sources)
Wolfgang Betz 10:1a612c2e4a85 40 * @param fdpin I2S data input pin (for full-duplex operation, default = NC)
Wolfgang Betz 10:1a612c2e4a85 41 * @param mck I2S master clock output (additional pin when needed for some external audio devices, default = NC)
Wolfgang Betz 10:1a612c2e4a85 42 *
Wolfgang Betz 10:1a612c2e4a85 43 * @Note It is up to the application programmer to not generate at the same time two I2S instances with the
Wolfgang Betz 10:1a612c2e4a85 44 * same pin (NC excluded) for one of the parameters, otherwise the correct operation of this class cannot be
Wolfgang Betz 10:1a612c2e4a85 45 * guaranteed (e.g. things like SPI/I2S clock enabling and above all disabling might not work correctly)!
Wolfgang Betz 10:1a612c2e4a85 46 */
Wolfgang Betz 10:1a612c2e4a85 47 I2S(PinName dpin, PinName clk, PinName wsel, PinName fdpin = NC, PinName mck = NC);
Wolfgang Betz 0:752e74bf5ef1 48
Wolfgang Betz 10:1a612c2e4a85 49 /** Configure the data transmission format
Wolfgang Betz 10:1a612c2e4a85 50 *
Wolfgang Betz 10:1a612c2e4a85 51 * @param dbits Number of data bits per I2S frame (16, 24, or 32)
Wolfgang Betz 10:1a612c2e4a85 52 * @param fbits Number of bits per I2S frame (16 or 32)
Wolfgang Betz 10:1a612c2e4a85 53 * @param polarity Clock polarity (either 0/low or 1/high, default = 0)
Wolfgang Betz 10:1a612c2e4a85 54 * @return Zero if the usage was set, -1 if a transaction is on-going
Wolfgang Betz 10:1a612c2e4a85 55 */
Wolfgang Betz 10:1a612c2e4a85 56 int format(int dbits, int fbits, int polarity = 0);
Wolfgang Betz 0:752e74bf5ef1 57
Wolfgang Betz 10:1a612c2e4a85 58 /** Set the i2s audio frequency
Wolfgang Betz 10:1a612c2e4a85 59 *
Wolfgang Betz 10:1a612c2e4a85 60 * @param hz audio frequency in hz
Wolfgang Betz 10:1a612c2e4a85 61 * @return Zero if the usage was set, -1 if a transaction is on-going
Wolfgang Betz 10:1a612c2e4a85 62 */
Wolfgang Betz 10:1a612c2e4a85 63 int audio_frequency(unsigned int hz);
Wolfgang Betz 0:752e74bf5ef1 64
Wolfgang Betz 13:fa1b24df9025 65 /** Get the i2s audio frequency
Wolfgang Betz 13:fa1b24df9025 66 *
Wolfgang Betz 13:fa1b24df9025 67 * @return Currently set audio frequency
Wolfgang Betz 13:fa1b24df9025 68 */
Wolfgang Betz 13:fa1b24df9025 69 unsigned int get_audio_frequency(void) {
Wolfgang Betz 16:04e1abb4cca3 70 return _hz;
Wolfgang Betz 13:fa1b24df9025 71 }
Wolfgang Betz 13:fa1b24df9025 72
Wolfgang Betz 10:1a612c2e4a85 73 /** Set the i2s bus protocol
Wolfgang Betz 10:1a612c2e4a85 74 *
Wolfgang Betz 10:1a612c2e4a85 75 * @param protocol I2S protocol to be used
Wolfgang Betz 10:1a612c2e4a85 76 * @return Zero if the usage was set, -1 if a transaction is on-going
Wolfgang Betz 10:1a612c2e4a85 77 */
Wolfgang Betz 19:ef6ef1795e30 78 int protocol(i2s_bitorder_t protocol);
Wolfgang Betz 0:752e74bf5ef1 79
Wolfgang Betz 10:1a612c2e4a85 80 /** Set the i2s mode
Wolfgang Betz 10:1a612c2e4a85 81 *
Wolfgang Betz 10:1a612c2e4a85 82 * @param mode I2S mode to be used
Wolfgang Betz 10:1a612c2e4a85 83 * @param circular I2S should read/write buffers continuously (in circular mode)
Wolfgang Betz 10:1a612c2e4a85 84 * @return Zero if the usage was set, -1 if a transaction is on-going
Wolfgang Betz 10:1a612c2e4a85 85 */
Wolfgang Betz 19:ef6ef1795e30 86 int mode(i2s_mode_t mode, bool circular);
Wolfgang Betz 0:752e74bf5ef1 87
Wolfgang Betz 10:1a612c2e4a85 88 /** Start non-blocking I2S transfer as configured with above methods
Wolfgang Betz 10:1a612c2e4a85 89 *
Wolfgang Betz 10:1a612c2e4a85 90 * @param tx_buffer The TX buffer with data to be transfered. If NULL is passed,
Wolfgang Betz 10:1a612c2e4a85 91 * no transmission will be set up
Wolfgang Betz 10:1a612c2e4a85 92 * @param tx_length The length of TX buffer in bytes
Wolfgang Betz 10:1a612c2e4a85 93 * @param rx_buffer The RX buffer which is used for received data. If NULL is passed,
Wolfgang Betz 10:1a612c2e4a85 94 * received data will be ignored
Wolfgang Betz 10:1a612c2e4a85 95 * @param rx_length The length of RX buffer in bytes
Wolfgang Betz 10:1a612c2e4a85 96 * @param callback The event callback function
Wolfgang Betz 10:1a612c2e4a85 97 * @param event The logical OR of events to notify. Look at i2s hal header file for I2S events.
Wolfgang Betz 10:1a612c2e4a85 98 * @return Zero if the transfer has started (or been queued), or
Wolfgang Betz 10:1a612c2e4a85 99 * -1 if I2S peripheral is busy (or out of resources)
Wolfgang Betz 10:1a612c2e4a85 100 */
Wolfgang Betz 10:1a612c2e4a85 101 template<typename Type>
Wolfgang Betz 17:7a4a4631672c 102 int transfer(const Type *tx_buffer, int tx_length, Type *rx_buffer, int rx_length, const mbed::event_callback_t& callback, int event) {
Wolfgang Betz 10:1a612c2e4a85 103 int ret = 0;
Wolfgang Betz 0:752e74bf5ef1 104
Wolfgang Betz 10:1a612c2e4a85 105 lock();
Wolfgang Betz 10:1a612c2e4a85 106
Wolfgang Betz 10:1a612c2e4a85 107 if (i2s_active(&_i2s)
Wolfgang Betz 0:752e74bf5ef1 108 #if TRANSACTION_QUEUE_SIZE_I2S
Wolfgang Betz 10:1a612c2e4a85 109 || !_transaction_buffer.empty()
Wolfgang Betz 0:752e74bf5ef1 110 #endif
Wolfgang Betz 10:1a612c2e4a85 111 ) {
Wolfgang Betz 10:1a612c2e4a85 112 ret = queue_transfer(tx_buffer, tx_length, rx_buffer, rx_length, callback, event);
Wolfgang Betz 10:1a612c2e4a85 113 } else {
Wolfgang Betz 10:1a612c2e4a85 114 start_transfer(tx_buffer, tx_length, rx_buffer, rx_length, callback, event);
Wolfgang Betz 9:c4c2240e06d6 115 }
Wolfgang Betz 10:1a612c2e4a85 116
Wolfgang Betz 10:1a612c2e4a85 117 unlock();
Wolfgang Betz 10:1a612c2e4a85 118 return ret;
Wolfgang Betz 10:1a612c2e4a85 119 }
Wolfgang Betz 0:752e74bf5ef1 120
Wolfgang Betz 10:1a612c2e4a85 121 /** Abort the on-going I2S transfer, and continue with transfer's in the queue if any.
Wolfgang Betz 10:1a612c2e4a85 122 */
Wolfgang Betz 10:1a612c2e4a85 123 void abort_transfer();
Wolfgang Betz 0:752e74bf5ef1 124
Wolfgang Betz 10:1a612c2e4a85 125 /** Clear the transaction buffer
Wolfgang Betz 10:1a612c2e4a85 126 */
Wolfgang Betz 10:1a612c2e4a85 127 void clear_transfer_buffer();
Wolfgang Betz 0:752e74bf5ef1 128
Wolfgang Betz 10:1a612c2e4a85 129 /** Clear the transaction buffer and abort on-going transfer.
Wolfgang Betz 10:1a612c2e4a85 130 */
Wolfgang Betz 10:1a612c2e4a85 131 void abort_all_transfers();
Wolfgang Betz 0:752e74bf5ef1 132
Wolfgang Betz 10:1a612c2e4a85 133 /** Get transfer status
Wolfgang Betz 10:1a612c2e4a85 134 *
Wolfgang Betz 10:1a612c2e4a85 135 * @return -1 if a transaction is on-going, zero otherwise
Wolfgang Betz 10:1a612c2e4a85 136 */
Wolfgang Betz 10:1a612c2e4a85 137 int get_transfer_status();
Wolfgang Betz 0:752e74bf5ef1 138
Wolfgang Betz 10:1a612c2e4a85 139 /** Get internal module id
Wolfgang Betz 10:1a612c2e4a85 140 *
Wolfgang Betz 10:1a612c2e4a85 141 * @return internal module id
Wolfgang Betz 10:1a612c2e4a85 142 */
Wolfgang Betz 10:1a612c2e4a85 143 unsigned int get_module();
Wolfgang Betz 0:752e74bf5ef1 144
Wolfgang Betz 10:1a612c2e4a85 145 /** Configure DMA priority for transfers
Wolfgang Betz 10:1a612c2e4a85 146 *
Wolfgang Betz 10:1a612c2e4a85 147 * @param prio The DMA priority to be used
Wolfgang Betz 10:1a612c2e4a85 148 * @return Zero if the usage was set, -1 if a transaction is on-going
Wolfgang Betz 10:1a612c2e4a85 149 */
Wolfgang Betz 22:e04af8667cad 150 int dma_priority(i2s_dma_prio_t prio);
Davide Aliprandi 4:21603d68bcf7 151
Wolfgang Betz 10:1a612c2e4a85 152 /** Harmonize the frequencies of the given I2S objects so that they are
Wolfgang Betz 16:04e1abb4cca3 153 * the exact multiple one of the other. It can be useful whenever two I2S
Wolfgang Betz 10:1a612c2e4a85 154 * peripherals have to work together and no drift is allowed between them.
Wolfgang Betz 10:1a612c2e4a85 155 *
Wolfgang Betz 10:1a612c2e4a85 156 * @param dev_i2s_1 reference to the first I2S object.
Wolfgang Betz 10:1a612c2e4a85 157 * @param dev_i2s_2 reference to the second I2S object.
Wolfgang Betz 10:1a612c2e4a85 158 * @return Zero if the frequencies have been harmonized correctly, -1
Wolfgang Betz 10:1a612c2e4a85 159 * otherwise.
Wolfgang Betz 10:1a612c2e4a85 160 */
Wolfgang Betz 10:1a612c2e4a85 161 static int harmonize(I2S &dev_i2s_1, I2S &dev_i2s_2);
Wolfgang Betz 0:752e74bf5ef1 162
Wolfgang Betz 0:752e74bf5ef1 163
Wolfgang Betz 10:1a612c2e4a85 164 /** Bottom-half & transactions event queue for all I2S objects
Wolfgang Betz 10:1a612c2e4a85 165 * Must be used by application programmer to schedule/execute bottom-halves
Wolfgang Betz 10:1a612c2e4a85 166 * (i.e. transfer event callback functions) and automatically start queued
Wolfgang Betz 10:1a612c2e4a85 167 * transactions (i.e. transfers), e.g. by calling `events::EventQueue::dispatch_forever()`! */
Wolfgang Betz 16:04e1abb4cca3 168 static events::EventQueue i2s_bh_queue;
Wolfgang Betz 10:1a612c2e4a85 169
Wolfgang Betz 10:1a612c2e4a85 170 protected:
Wolfgang Betz 16:04e1abb4cca3 171 /** Acquire exclusive access to this I2S bus
Wolfgang Betz 16:04e1abb4cca3 172 */
Wolfgang Betz 16:04e1abb4cca3 173 virtual void lock(void);
Wolfgang Betz 16:04e1abb4cca3 174
Wolfgang Betz 16:04e1abb4cca3 175 /** Release exclusive access to this I2S bus
Wolfgang Betz 16:04e1abb4cca3 176 */
Wolfgang Betz 16:04e1abb4cca3 177 virtual void unlock(void);
Wolfgang Betz 16:04e1abb4cca3 178
Wolfgang Betz 10:1a612c2e4a85 179 /** I2S TX DMA IRQ handler
Wolfgang Betz 10:1a612c2e4a85 180 *
Wolfgang Betz 10:1a612c2e4a85 181 */
Wolfgang Betz 10:1a612c2e4a85 182 void irq_handler_asynch_tx(void);
Wolfgang Betz 0:752e74bf5ef1 183
Wolfgang Betz 10:1a612c2e4a85 184 /** I2S RX DMA IRQ handler
Wolfgang Betz 10:1a612c2e4a85 185 *
Wolfgang Betz 10:1a612c2e4a85 186 */
Wolfgang Betz 10:1a612c2e4a85 187 void irq_handler_asynch_rx(void);
Wolfgang Betz 0:752e74bf5ef1 188
Wolfgang Betz 10:1a612c2e4a85 189 /** Add a transfer to the queue
Wolfgang Betz 10:1a612c2e4a85 190 * @param data Transaction data
Wolfgang Betz 10:1a612c2e4a85 191 * @return Zero if a transfer was added to the queue, or -1 if the queue is full
Wolfgang Betz 10:1a612c2e4a85 192 */
Wolfgang Betz 10:1a612c2e4a85 193 int queue_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length,
Wolfgang Betz 17:7a4a4631672c 194 const mbed::event_callback_t& callback, int event);
Wolfgang Betz 10:1a612c2e4a85 195
Wolfgang Betz 10:1a612c2e4a85 196 /** Configures a callback, i2s peripheral and initiate a new transfer
Wolfgang Betz 10:1a612c2e4a85 197 *
Wolfgang Betz 10:1a612c2e4a85 198 * @param data Transaction data
Wolfgang Betz 10:1a612c2e4a85 199 */
Wolfgang Betz 10:1a612c2e4a85 200 void start_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length,
Wolfgang Betz 17:7a4a4631672c 201 const mbed::event_callback_t& callback, int event);
Wolfgang Betz 0:752e74bf5ef1 202
Wolfgang Betz 10:1a612c2e4a85 203 class I2sBhHandler {
Wolfgang Betz 10:1a612c2e4a85 204 friend class I2S;
Wolfgang Betz 0:752e74bf5ef1 205
Wolfgang Betz 17:7a4a4631672c 206 static void i2s_defer_function(const mbed::event_callback_t& bottom_half, int event) {
Wolfgang Betz 10:1a612c2e4a85 207 i2s_bh_queue.call(bottom_half, event);
Wolfgang Betz 10:1a612c2e4a85 208 }
Wolfgang Betz 0:752e74bf5ef1 209
Wolfgang Betz 17:7a4a4631672c 210 static void i2s_defer_function(const mbed::Callback<void()>& bottom_half) {
Wolfgang Betz 10:1a612c2e4a85 211 i2s_bh_queue.call(bottom_half);
Wolfgang Betz 10:1a612c2e4a85 212 }
Wolfgang Betz 10:1a612c2e4a85 213 };
Wolfgang Betz 0:752e74bf5ef1 214
Wolfgang Betz 0:752e74bf5ef1 215 #if TRANSACTION_QUEUE_SIZE_I2S
Wolfgang Betz 10:1a612c2e4a85 216 /** Start a new transaction
Wolfgang Betz 10:1a612c2e4a85 217 *
Wolfgang Betz 10:1a612c2e4a85 218 * @param data Transaction data
Wolfgang Betz 10:1a612c2e4a85 219 */
Wolfgang Betz 17:7a4a4631672c 220 void start_transaction(mbed::transaction_t *data);
Wolfgang Betz 0:752e74bf5ef1 221
Wolfgang Betz 10:1a612c2e4a85 222 /** Dequeue a transaction
Wolfgang Betz 10:1a612c2e4a85 223 *
Wolfgang Betz 10:1a612c2e4a85 224 */
Wolfgang Betz 10:1a612c2e4a85 225 void dequeue_transaction();
Wolfgang Betz 0:752e74bf5ef1 226
Wolfgang Betz 17:7a4a4631672c 227 mbed::CircularBuffer<mbed::Transaction<I2S>, TRANSACTION_QUEUE_SIZE_I2S> _transaction_buffer;
Wolfgang Betz 0:752e74bf5ef1 228 #endif // TRANSACTION_QUEUE_SIZE_I2S
Wolfgang Betz 0:752e74bf5ef1 229
Wolfgang Betz 10:1a612c2e4a85 230 public:
Wolfgang Betz 10:1a612c2e4a85 231 virtual ~I2S() {
Wolfgang Betz 19:ef6ef1795e30 232 /* TODO: cleanup has still to be revised completely! */
Wolfgang Betz 10:1a612c2e4a85 233 abort_all_transfers();
Wolfgang Betz 10:1a612c2e4a85 234 i2s_free(&_i2s);
Wolfgang Betz 10:1a612c2e4a85 235 }
Davide Aliprandi 4:21603d68bcf7 236
Wolfgang Betz 10:1a612c2e4a85 237 protected:
Wolfgang Betz 10:1a612c2e4a85 238 i2s_t _i2s;
Davide Aliprandi 4:21603d68bcf7 239
Wolfgang Betz 10:1a612c2e4a85 240 CThunk<I2S> _irq_tx;
Wolfgang Betz 10:1a612c2e4a85 241 CThunk<I2S> _irq_rx;
Wolfgang Betz 17:7a4a4631672c 242 mbed::event_callback_t _callback;
Wolfgang Betz 10:1a612c2e4a85 243 i2s_dma_prio_t _priority; // DMA priority
Wolfgang Betz 0:752e74bf5ef1 244
Wolfgang Betz 10:1a612c2e4a85 245 void acquire(void);
Wolfgang Betz 0:752e74bf5ef1 246
Wolfgang Betz 10:1a612c2e4a85 247 static I2S *_owner;
Wolfgang Betz 10:1a612c2e4a85 248 static SingletonPtr<PlatformMutex> _mutex;
Wolfgang Betz 0:752e74bf5ef1 249
Wolfgang Betz 10:1a612c2e4a85 250 int _dbits;
Wolfgang Betz 10:1a612c2e4a85 251 int _fbits;
Wolfgang Betz 10:1a612c2e4a85 252 int _polarity;
Wolfgang Betz 10:1a612c2e4a85 253 i2s_bitorder_t _protocol;
Wolfgang Betz 10:1a612c2e4a85 254 i2s_mode_t _mode;
Wolfgang Betz 10:1a612c2e4a85 255 bool _circular;
Wolfgang Betz 10:1a612c2e4a85 256 unsigned int _hz;
Wolfgang Betz 10:1a612c2e4a85 257 };
Wolfgang Betz 0:752e74bf5ef1 258
Wolfgang Betz 17:7a4a4631672c 259 #endif // DEVICE_I2S
Wolfgang Betz 0:752e74bf5ef1 260
Wolfgang Betz 17:7a4a4631672c 261 #endif // MBED_I2S_H