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:
Tue Nov 29 14:02:28 2016 +0100
Revision:
0:752e74bf5ef1
Child:
4:21603d68bcf7
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Wolfgang Betz 0:752e74bf5ef1 1 #include "drivers/I2S.h"
Wolfgang Betz 0:752e74bf5ef1 2 #include "platform/critical.h"
Wolfgang Betz 0:752e74bf5ef1 3 #include "platform/mbed_assert.h"
Wolfgang Betz 0:752e74bf5ef1 4
Wolfgang Betz 0:752e74bf5ef1 5 #if DEVICE_I2S
Wolfgang Betz 0:752e74bf5ef1 6
Wolfgang Betz 0:752e74bf5ef1 7 namespace mbed {
Wolfgang Betz 0:752e74bf5ef1 8
Wolfgang Betz 0:752e74bf5ef1 9 /* betzw - WAS
Wolfgang Betz 0:752e74bf5ef1 10 #if TRANSACTION_QUEUE_SIZE_I2S
Wolfgang Betz 0:752e74bf5ef1 11 CircularBuffer<Transaction<I2S>, TRANSACTION_QUEUE_SIZE_I2S> I2S::_transaction_buffer;
Wolfgang Betz 0:752e74bf5ef1 12 #endif
Wolfgang Betz 0:752e74bf5ef1 13 */
Wolfgang Betz 0:752e74bf5ef1 14
Wolfgang Betz 0:752e74bf5ef1 15 I2S* I2S::_owner = NULL;
Wolfgang Betz 0:752e74bf5ef1 16 SingletonPtr<PlatformMutex> I2S::_mutex; // intentional class level lock!
Wolfgang Betz 0:752e74bf5ef1 17
Wolfgang Betz 0:752e74bf5ef1 18 rtos::Thread I2S::I2sBhHandler::_i2s_bh_daemon;
Wolfgang Betz 0:752e74bf5ef1 19 events::EventQueue I2S::I2sBhHandler::_i2s_bh_queue;
Wolfgang Betz 0:752e74bf5ef1 20
Wolfgang Betz 0:752e74bf5ef1 21 void I2S::lock() {
Wolfgang Betz 0:752e74bf5ef1 22 #ifdef NDEBUG
Wolfgang Betz 0:752e74bf5ef1 23 _mutex->lock(); // intentional class level lock!
Wolfgang Betz 0:752e74bf5ef1 24 #else
Wolfgang Betz 0:752e74bf5ef1 25 osStatus ret = _mutex->lock(); // intentional class level lock!
Wolfgang Betz 0:752e74bf5ef1 26 MBED_ASSERT(ret == osOK);
Wolfgang Betz 0:752e74bf5ef1 27 #endif
Wolfgang Betz 0:752e74bf5ef1 28 }
Wolfgang Betz 0:752e74bf5ef1 29
Wolfgang Betz 0:752e74bf5ef1 30 void I2S::unlock() {
Wolfgang Betz 0:752e74bf5ef1 31 #ifdef NDEBUG
Wolfgang Betz 0:752e74bf5ef1 32 _mutex->unlock(); // intentional class level lock!
Wolfgang Betz 0:752e74bf5ef1 33 #else
Wolfgang Betz 0:752e74bf5ef1 34 osStatus ret = _mutex->unlock(); // intentional class level lock!
Wolfgang Betz 0:752e74bf5ef1 35 MBED_ASSERT(ret == osOK);
Wolfgang Betz 0:752e74bf5ef1 36 #endif
Wolfgang Betz 0:752e74bf5ef1 37 }
Wolfgang Betz 0:752e74bf5ef1 38
Wolfgang Betz 0:752e74bf5ef1 39 I2S::I2S(PinName dpin, PinName clk, PinName wsel, PinName fdpin, PinName mck) :
Wolfgang Betz 0:752e74bf5ef1 40 _i2s(),
Wolfgang Betz 0:752e74bf5ef1 41 _irq_tx(this), _irq_rx(this),
Wolfgang Betz 0:752e74bf5ef1 42 _priority(MEDIUM),
Wolfgang Betz 0:752e74bf5ef1 43 _dbits(16),
Wolfgang Betz 0:752e74bf5ef1 44 _fbits(16),
Wolfgang Betz 0:752e74bf5ef1 45 _polarity(0),
Wolfgang Betz 0:752e74bf5ef1 46 _protocol(PHILIPS),
Wolfgang Betz 0:752e74bf5ef1 47 _mode(MASTER_TX),
Wolfgang Betz 0:752e74bf5ef1 48 _circular(false),
Wolfgang Betz 0:752e74bf5ef1 49 _hz(44100) {
Wolfgang Betz 0:752e74bf5ef1 50 lock();
Wolfgang Betz 0:752e74bf5ef1 51 /* Init instance */
Wolfgang Betz 0:752e74bf5ef1 52 i2s_init(&_i2s, dpin, clk, wsel, fdpin, mck, _mode);
Wolfgang Betz 0:752e74bf5ef1 53 acquire();
Wolfgang Betz 0:752e74bf5ef1 54 #if TRANSACTION_QUEUE_SIZE_I2S
Wolfgang Betz 0:752e74bf5ef1 55 /* Init bottom half daemon */
Wolfgang Betz 0:752e74bf5ef1 56 I2sBhHandler::init();
Wolfgang Betz 0:752e74bf5ef1 57 #endif
Wolfgang Betz 0:752e74bf5ef1 58 unlock();
Wolfgang Betz 0:752e74bf5ef1 59 }
Wolfgang Betz 0:752e74bf5ef1 60
Wolfgang Betz 0:752e74bf5ef1 61 int I2S::format(int dbits, int fbits, int polarity) {
Wolfgang Betz 0:752e74bf5ef1 62 lock();
Wolfgang Betz 0:752e74bf5ef1 63 if (i2s_active(&_i2s)) {
Wolfgang Betz 0:752e74bf5ef1 64 unlock();
Wolfgang Betz 0:752e74bf5ef1 65 return -1;
Wolfgang Betz 0:752e74bf5ef1 66 }
Wolfgang Betz 0:752e74bf5ef1 67 _dbits = dbits;
Wolfgang Betz 0:752e74bf5ef1 68 _fbits = fbits;
Wolfgang Betz 0:752e74bf5ef1 69 _polarity = polarity;
Wolfgang Betz 0:752e74bf5ef1 70 I2S::_owner = NULL; // Not that elegant, but works. rmeyer
Wolfgang Betz 0:752e74bf5ef1 71 acquire();
Wolfgang Betz 0:752e74bf5ef1 72 unlock();
Wolfgang Betz 0:752e74bf5ef1 73 return 0;
Wolfgang Betz 0:752e74bf5ef1 74 }
Wolfgang Betz 0:752e74bf5ef1 75
Wolfgang Betz 0:752e74bf5ef1 76 int I2S::audio_frequency(unsigned int hz) {
Wolfgang Betz 0:752e74bf5ef1 77 lock();
Wolfgang Betz 0:752e74bf5ef1 78 if (i2s_active(&_i2s)) {
Wolfgang Betz 0:752e74bf5ef1 79 unlock();
Wolfgang Betz 0:752e74bf5ef1 80 return -1;
Wolfgang Betz 0:752e74bf5ef1 81 }
Wolfgang Betz 0:752e74bf5ef1 82 _hz = hz;
Wolfgang Betz 0:752e74bf5ef1 83 I2S::_owner = NULL; // Not that elegant, but works. rmeyer
Wolfgang Betz 0:752e74bf5ef1 84 acquire();
Wolfgang Betz 0:752e74bf5ef1 85 unlock();
Wolfgang Betz 0:752e74bf5ef1 86 return 0;
Wolfgang Betz 0:752e74bf5ef1 87 }
Wolfgang Betz 0:752e74bf5ef1 88
Wolfgang Betz 0:752e74bf5ef1 89 int I2S::set_protocol(i2s_bitorder_t protocol) {
Wolfgang Betz 0:752e74bf5ef1 90 lock();
Wolfgang Betz 0:752e74bf5ef1 91 if (i2s_active(&_i2s)) {
Wolfgang Betz 0:752e74bf5ef1 92 unlock();
Wolfgang Betz 0:752e74bf5ef1 93 return -1;
Wolfgang Betz 0:752e74bf5ef1 94 }
Wolfgang Betz 0:752e74bf5ef1 95 _protocol = protocol;
Wolfgang Betz 0:752e74bf5ef1 96 I2S::_owner = NULL; // Not that elegant, but works. rmeyer
Wolfgang Betz 0:752e74bf5ef1 97 acquire();
Wolfgang Betz 0:752e74bf5ef1 98 unlock();
Wolfgang Betz 0:752e74bf5ef1 99 return 0;
Wolfgang Betz 0:752e74bf5ef1 100 }
Wolfgang Betz 0:752e74bf5ef1 101
Wolfgang Betz 0:752e74bf5ef1 102 int I2S::set_mode(i2s_mode_t mode, bool circular) {
Wolfgang Betz 0:752e74bf5ef1 103 lock();
Wolfgang Betz 0:752e74bf5ef1 104 if (i2s_active(&_i2s)) {
Wolfgang Betz 0:752e74bf5ef1 105 unlock();
Wolfgang Betz 0:752e74bf5ef1 106 return -1;
Wolfgang Betz 0:752e74bf5ef1 107 }
Wolfgang Betz 0:752e74bf5ef1 108 _mode = mode;
Wolfgang Betz 0:752e74bf5ef1 109 _circular = circular;
Wolfgang Betz 0:752e74bf5ef1 110 I2S::_owner = NULL; // Not that elegant, but works. rmeyer
Wolfgang Betz 0:752e74bf5ef1 111 acquire();
Wolfgang Betz 0:752e74bf5ef1 112 unlock();
Wolfgang Betz 0:752e74bf5ef1 113 return 0;
Wolfgang Betz 0:752e74bf5ef1 114 }
Wolfgang Betz 0:752e74bf5ef1 115
Wolfgang Betz 0:752e74bf5ef1 116 void I2S::abort_transfer()
Wolfgang Betz 0:752e74bf5ef1 117 {
Wolfgang Betz 0:752e74bf5ef1 118 lock();
Wolfgang Betz 0:752e74bf5ef1 119 i2s_abort_asynch(&_i2s);
Wolfgang Betz 0:752e74bf5ef1 120 #if TRANSACTION_QUEUE_SIZE_I2S
Wolfgang Betz 0:752e74bf5ef1 121 dequeue_transaction();
Wolfgang Betz 0:752e74bf5ef1 122 #endif
Wolfgang Betz 0:752e74bf5ef1 123 unlock();
Wolfgang Betz 0:752e74bf5ef1 124 }
Wolfgang Betz 0:752e74bf5ef1 125
Wolfgang Betz 0:752e74bf5ef1 126
Wolfgang Betz 0:752e74bf5ef1 127 void I2S::clear_transfer_buffer()
Wolfgang Betz 0:752e74bf5ef1 128 {
Wolfgang Betz 0:752e74bf5ef1 129 #if TRANSACTION_QUEUE_SIZE_I2S
Wolfgang Betz 0:752e74bf5ef1 130 lock();
Wolfgang Betz 0:752e74bf5ef1 131 _transaction_buffer.reset();
Wolfgang Betz 0:752e74bf5ef1 132 unlock();
Wolfgang Betz 0:752e74bf5ef1 133 #endif
Wolfgang Betz 0:752e74bf5ef1 134 }
Wolfgang Betz 0:752e74bf5ef1 135
Wolfgang Betz 0:752e74bf5ef1 136 void I2S::abort_all_transfers()
Wolfgang Betz 0:752e74bf5ef1 137 {
Wolfgang Betz 0:752e74bf5ef1 138 lock();
Wolfgang Betz 0:752e74bf5ef1 139 clear_transfer_buffer();
Wolfgang Betz 0:752e74bf5ef1 140 abort_transfer();
Wolfgang Betz 0:752e74bf5ef1 141 unlock();
Wolfgang Betz 0:752e74bf5ef1 142 }
Wolfgang Betz 0:752e74bf5ef1 143
Wolfgang Betz 0:752e74bf5ef1 144 int I2S::get_transfer_status()
Wolfgang Betz 0:752e74bf5ef1 145 {
Wolfgang Betz 0:752e74bf5ef1 146 lock();
Wolfgang Betz 0:752e74bf5ef1 147 if (i2s_active(&_i2s)) {
Wolfgang Betz 0:752e74bf5ef1 148 unlock();
Wolfgang Betz 0:752e74bf5ef1 149 return -1;
Wolfgang Betz 0:752e74bf5ef1 150 }
Wolfgang Betz 0:752e74bf5ef1 151 unlock();
Wolfgang Betz 0:752e74bf5ef1 152 return 0;
Wolfgang Betz 0:752e74bf5ef1 153 }
Wolfgang Betz 0:752e74bf5ef1 154
Wolfgang Betz 0:752e74bf5ef1 155 unsigned int I2S::get_module()
Wolfgang Betz 0:752e74bf5ef1 156 {
Wolfgang Betz 0:752e74bf5ef1 157 return i2s_get_module(&_i2s);
Wolfgang Betz 0:752e74bf5ef1 158 }
Wolfgang Betz 0:752e74bf5ef1 159
Wolfgang Betz 0:752e74bf5ef1 160 int I2S::set_dma_priority(i2s_dma_prio_t prio)
Wolfgang Betz 0:752e74bf5ef1 161 {
Wolfgang Betz 0:752e74bf5ef1 162 lock();
Wolfgang Betz 0:752e74bf5ef1 163 if (i2s_active(&_i2s)) {
Wolfgang Betz 0:752e74bf5ef1 164 unlock();
Wolfgang Betz 0:752e74bf5ef1 165 return -1;
Wolfgang Betz 0:752e74bf5ef1 166 }
Wolfgang Betz 0:752e74bf5ef1 167 _priority = prio;
Wolfgang Betz 0:752e74bf5ef1 168 unlock();
Wolfgang Betz 0:752e74bf5ef1 169 return 0;
Wolfgang Betz 0:752e74bf5ef1 170 }
Wolfgang Betz 0:752e74bf5ef1 171
Wolfgang Betz 0:752e74bf5ef1 172 int I2S::queue_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, const event_callback_t& callback, int event)
Wolfgang Betz 0:752e74bf5ef1 173 { // betzw: MUST be called with lock held!
Wolfgang Betz 0:752e74bf5ef1 174 #if TRANSACTION_QUEUE_SIZE_I2S
Wolfgang Betz 0:752e74bf5ef1 175 transaction_t t;
Wolfgang Betz 0:752e74bf5ef1 176
Wolfgang Betz 0:752e74bf5ef1 177 t.tx_buffer = const_cast<void *>(tx_buffer);
Wolfgang Betz 0:752e74bf5ef1 178 t.tx_length = tx_length;
Wolfgang Betz 0:752e74bf5ef1 179 t.rx_buffer = rx_buffer;
Wolfgang Betz 0:752e74bf5ef1 180 t.rx_length = rx_length;
Wolfgang Betz 0:752e74bf5ef1 181 t.event = event;
Wolfgang Betz 0:752e74bf5ef1 182 t.callback = callback;
Wolfgang Betz 0:752e74bf5ef1 183 t.width = 16;
Wolfgang Betz 0:752e74bf5ef1 184 Transaction<I2S> transaction(this, t);
Wolfgang Betz 0:752e74bf5ef1 185 core_util_critical_section_enter();
Wolfgang Betz 0:752e74bf5ef1 186 if (_transaction_buffer.full()) {
Wolfgang Betz 0:752e74bf5ef1 187 core_util_critical_section_enter();
Wolfgang Betz 0:752e74bf5ef1 188 return -1; // the buffer is full
Wolfgang Betz 0:752e74bf5ef1 189 } else {
Wolfgang Betz 0:752e74bf5ef1 190 _transaction_buffer.push(transaction);
Wolfgang Betz 0:752e74bf5ef1 191 core_util_critical_section_exit();
Wolfgang Betz 0:752e74bf5ef1 192 // betzw - seems to be redundant - WAS: dequeue_transaction();
Wolfgang Betz 0:752e74bf5ef1 193 return 0;
Wolfgang Betz 0:752e74bf5ef1 194 }
Wolfgang Betz 0:752e74bf5ef1 195 #else
Wolfgang Betz 0:752e74bf5ef1 196 return -1;
Wolfgang Betz 0:752e74bf5ef1 197 #endif
Wolfgang Betz 0:752e74bf5ef1 198 }
Wolfgang Betz 0:752e74bf5ef1 199
Wolfgang Betz 0:752e74bf5ef1 200
Wolfgang Betz 0:752e74bf5ef1 201 // ignore the fact there are multiple physical i2s's, and always update if it wasn't us last
Wolfgang Betz 0:752e74bf5ef1 202 void I2S::acquire() { // betzw: MUST be called with lock held!
Wolfgang Betz 0:752e74bf5ef1 203 if (_owner != this) {
Wolfgang Betz 0:752e74bf5ef1 204 i2s_format(&_i2s, _dbits, _fbits, _polarity);
Wolfgang Betz 0:752e74bf5ef1 205 i2s_audio_frequency(&_i2s, _hz);
Wolfgang Betz 0:752e74bf5ef1 206 i2s_set_protocol(&_i2s, _protocol);
Wolfgang Betz 0:752e74bf5ef1 207 i2s_set_mode(&_i2s, _mode);
Wolfgang Betz 0:752e74bf5ef1 208 _owner = this;
Wolfgang Betz 0:752e74bf5ef1 209 }
Wolfgang Betz 0:752e74bf5ef1 210 }
Wolfgang Betz 0:752e74bf5ef1 211
Wolfgang Betz 0:752e74bf5ef1 212 void I2S::start_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length,
Wolfgang Betz 0:752e74bf5ef1 213 const event_callback_t& callback, int event)
Wolfgang Betz 0:752e74bf5ef1 214 { // betzw: MUST be called with lock held!
Wolfgang Betz 0:752e74bf5ef1 215 acquire();
Wolfgang Betz 0:752e74bf5ef1 216 _callback = callback;
Wolfgang Betz 0:752e74bf5ef1 217 _irq_tx.callback(&I2S::irq_handler_asynch_tx);
Wolfgang Betz 0:752e74bf5ef1 218 _irq_rx.callback(&I2S::irq_handler_asynch_rx);
Wolfgang Betz 0:752e74bf5ef1 219 i2s_transfer(&_i2s,
Wolfgang Betz 0:752e74bf5ef1 220 const_cast<void *>(tx_buffer), tx_length, rx_buffer, rx_length,
Wolfgang Betz 0:752e74bf5ef1 221 _circular, _priority,
Wolfgang Betz 0:752e74bf5ef1 222 _irq_tx.entry(), _irq_rx.entry(),
Wolfgang Betz 0:752e74bf5ef1 223 event);
Wolfgang Betz 0:752e74bf5ef1 224 }
Wolfgang Betz 0:752e74bf5ef1 225
Wolfgang Betz 0:752e74bf5ef1 226 #if TRANSACTION_QUEUE_SIZE_I2S
Wolfgang Betz 0:752e74bf5ef1 227
Wolfgang Betz 0:752e74bf5ef1 228 void I2S::start_transaction(transaction_t *data)
Wolfgang Betz 0:752e74bf5ef1 229 { // betzw: MUST be called with lock held!
Wolfgang Betz 0:752e74bf5ef1 230 start_transfer(data->tx_buffer, data->tx_length, data->rx_buffer, data->rx_length, data->callback, data->event);
Wolfgang Betz 0:752e74bf5ef1 231 }
Wolfgang Betz 0:752e74bf5ef1 232
Wolfgang Betz 0:752e74bf5ef1 233 void I2S::dequeue_transaction()
Wolfgang Betz 0:752e74bf5ef1 234 {
Wolfgang Betz 0:752e74bf5ef1 235 lock();
Wolfgang Betz 0:752e74bf5ef1 236 if (!i2s_active(&_i2s)) {
Wolfgang Betz 0:752e74bf5ef1 237 Transaction<I2S> t;
Wolfgang Betz 0:752e74bf5ef1 238 if (_transaction_buffer.pop(t)) {
Wolfgang Betz 0:752e74bf5ef1 239 I2S* obj = t.get_object();
Wolfgang Betz 0:752e74bf5ef1 240 transaction_t* data = t.get_transaction();
Wolfgang Betz 0:752e74bf5ef1 241 MBED_ASSERT(obj == this); // betzw: what if 'obj' is NOT equal to 'this'?
Wolfgang Betz 0:752e74bf5ef1 242 obj->start_transaction(data);
Wolfgang Betz 0:752e74bf5ef1 243 }
Wolfgang Betz 0:752e74bf5ef1 244 }
Wolfgang Betz 0:752e74bf5ef1 245 unlock();
Wolfgang Betz 0:752e74bf5ef1 246 }
Wolfgang Betz 0:752e74bf5ef1 247
Wolfgang Betz 0:752e74bf5ef1 248 #endif
Wolfgang Betz 0:752e74bf5ef1 249
Wolfgang Betz 0:752e74bf5ef1 250 void I2S::irq_handler_asynch_rx(void)
Wolfgang Betz 0:752e74bf5ef1 251 {
Wolfgang Betz 0:752e74bf5ef1 252 int event = i2s_irq_handler_asynch(&_i2s, I2S_RX_EVENT);
Wolfgang Betz 0:752e74bf5ef1 253 if (_callback && (event & I2S_EVENT_ALL)) {
Wolfgang Betz 0:752e74bf5ef1 254 I2sBhHandler::i2s_defer_function(_callback, event & I2S_EVENT_ALL);
Wolfgang Betz 0:752e74bf5ef1 255 }
Wolfgang Betz 0:752e74bf5ef1 256 #if TRANSACTION_QUEUE_SIZE_I2S
Wolfgang Betz 0:752e74bf5ef1 257 if (event & I2S_EVENT_INTERNAL_TRANSFER_COMPLETE) {
Wolfgang Betz 0:752e74bf5ef1 258 I2sBhHandler::i2s_defer_function(Callback<void()>(this, &I2S::dequeue_transaction));
Wolfgang Betz 0:752e74bf5ef1 259 }
Wolfgang Betz 0:752e74bf5ef1 260 #endif
Wolfgang Betz 0:752e74bf5ef1 261 }
Wolfgang Betz 0:752e74bf5ef1 262
Wolfgang Betz 0:752e74bf5ef1 263 void I2S::irq_handler_asynch_tx(void)
Wolfgang Betz 0:752e74bf5ef1 264 {
Wolfgang Betz 0:752e74bf5ef1 265 int event = i2s_irq_handler_asynch(&_i2s, I2S_TX_EVENT);
Wolfgang Betz 0:752e74bf5ef1 266 if (_callback && (event & I2S_EVENT_ALL)) {
Wolfgang Betz 0:752e74bf5ef1 267 I2sBhHandler::i2s_defer_function(_callback, event & I2S_EVENT_ALL);
Wolfgang Betz 0:752e74bf5ef1 268 }
Wolfgang Betz 0:752e74bf5ef1 269 #if TRANSACTION_QUEUE_SIZE_I2S
Wolfgang Betz 0:752e74bf5ef1 270 if (event & I2S_EVENT_INTERNAL_TRANSFER_COMPLETE) {
Wolfgang Betz 0:752e74bf5ef1 271 I2sBhHandler::i2s_defer_function(Callback<void()>(this, &I2S::dequeue_transaction));
Wolfgang Betz 0:752e74bf5ef1 272 }
Wolfgang Betz 0:752e74bf5ef1 273 #endif
Wolfgang Betz 0:752e74bf5ef1 274 }
Wolfgang Betz 0:752e74bf5ef1 275
Wolfgang Betz 0:752e74bf5ef1 276 } // namespace mbed
Wolfgang Betz 0:752e74bf5ef1 277
Wolfgang Betz 0:752e74bf5ef1 278 #endif