Quentin Roche / ST_I2S

Dependents:   X_NUCLEO_CCA02M1

Fork of ST_I2S by ST

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