Quentin Roche / ST_I2S

Dependents:   X_NUCLEO_CCA02M1

Fork of ST_I2S by ST

Committer:
Davide Aliprandi
Date:
Wed Dec 21 20:24:16 2016 +0100
Revision:
4:21603d68bcf7
Parent:
0:752e74bf5ef1
Child:
9:c4c2240e06d6
Added algorithm to automatically harmonize two I2S peripherals' frequencies.

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
Davide Aliprandi 4:21603d68bcf7 276 float I2S::compute_real_frequency(I2S *dev_i2s)
Davide Aliprandi 4:21603d68bcf7 277 {
Davide Aliprandi 4:21603d68bcf7 278 uint32_t i2sclk = 0U, i2sdiv = 2U, i2sodd = 0U, packetlength = 1U, tmp = 0U;
Davide Aliprandi 4:21603d68bcf7 279 I2S_HandleTypeDef *hi2s;
Davide Aliprandi 4:21603d68bcf7 280
Davide Aliprandi 4:21603d68bcf7 281 /* Get the I2S handle. */
Davide Aliprandi 4:21603d68bcf7 282 hi2s = i2s_get_handle(&(dev_i2s->_i2s));
Davide Aliprandi 4:21603d68bcf7 283
Davide Aliprandi 4:21603d68bcf7 284 /* Check the frame length (For the Prescaler computing). */
Davide Aliprandi 4:21603d68bcf7 285 if (hi2s->Init.DataFormat != I2S_DATAFORMAT_16B)
Davide Aliprandi 4:21603d68bcf7 286 {
Davide Aliprandi 4:21603d68bcf7 287 /* Packet length is 32 bits */
Davide Aliprandi 4:21603d68bcf7 288 packetlength = 2U;
Davide Aliprandi 4:21603d68bcf7 289 }
Davide Aliprandi 4:21603d68bcf7 290
Davide Aliprandi 4:21603d68bcf7 291 /* Get I2S source Clock frequency. */
Davide Aliprandi 4:21603d68bcf7 292 i2sclk = I2S_GetInputClock(hi2s);
Davide Aliprandi 4:21603d68bcf7 293
Davide Aliprandi 4:21603d68bcf7 294 /* Compute the Real divider depending on the MCLK output state, with a floating point. */
Davide Aliprandi 4:21603d68bcf7 295 if (hi2s->Init.MCLKOutput == I2S_MCLKOUTPUT_ENABLE)
Davide Aliprandi 4:21603d68bcf7 296 {
Davide Aliprandi 4:21603d68bcf7 297 /* MCLK output is enabled. */
Davide Aliprandi 4:21603d68bcf7 298 tmp = (uint32_t)(((((i2sclk / 256U) * 10U) / hi2s->Init.AudioFreq)) + 5U);
Davide Aliprandi 4:21603d68bcf7 299 }
Davide Aliprandi 4:21603d68bcf7 300 else
Davide Aliprandi 4:21603d68bcf7 301 {
Davide Aliprandi 4:21603d68bcf7 302 /* MCLK output is disabled. */
Davide Aliprandi 4:21603d68bcf7 303 tmp = (uint32_t)(((((i2sclk / (32U * packetlength)) * 10U) / hi2s->Init.AudioFreq)) + 5U);
Davide Aliprandi 4:21603d68bcf7 304 }
Davide Aliprandi 4:21603d68bcf7 305
Davide Aliprandi 4:21603d68bcf7 306 /* Remove the flatting point. */
Davide Aliprandi 4:21603d68bcf7 307 tmp = tmp / 10U;
Davide Aliprandi 4:21603d68bcf7 308
Davide Aliprandi 4:21603d68bcf7 309 /* Check the parity of the divider. */
Davide Aliprandi 4:21603d68bcf7 310 i2sodd = (uint32_t)(tmp & (uint32_t)1U);
Davide Aliprandi 4:21603d68bcf7 311
Davide Aliprandi 4:21603d68bcf7 312 /* Compute the i2sdiv prescaler. */
Davide Aliprandi 4:21603d68bcf7 313 i2sdiv = (uint32_t)((tmp - i2sodd) / 2U);
Davide Aliprandi 4:21603d68bcf7 314
Davide Aliprandi 4:21603d68bcf7 315 /* Test if the divider is 1 or 0 or greater than 0xFF. */
Davide Aliprandi 4:21603d68bcf7 316 if ((i2sdiv < 2U) || (i2sdiv > 0xFFU))
Davide Aliprandi 4:21603d68bcf7 317 {
Davide Aliprandi 4:21603d68bcf7 318 /* Set the default values. */
Davide Aliprandi 4:21603d68bcf7 319 i2sdiv = 2U;
Davide Aliprandi 4:21603d68bcf7 320 i2sodd = 0U;
Davide Aliprandi 4:21603d68bcf7 321 }
Davide Aliprandi 4:21603d68bcf7 322
Davide Aliprandi 4:21603d68bcf7 323 /* Compute the I2S frequencies. */
Davide Aliprandi 4:21603d68bcf7 324 uint32_t format_factor = (hi2s->Init.DataFormat == I2S_DATAFORMAT_16B ? 16 : 32);
Davide Aliprandi 4:21603d68bcf7 325 uint32_t mclk_factor = (hi2s->Init.MCLKOutput == I2S_MCLKOUTPUT_ENABLE ? (format_factor == 16 ? 8 : 4) : 1);
Davide Aliprandi 4:21603d68bcf7 326 float f = i2sclk / (2 * format_factor * ((2 * i2sdiv) + i2sodd) * mclk_factor);
Davide Aliprandi 4:21603d68bcf7 327
Davide Aliprandi 4:21603d68bcf7 328 return f;
Davide Aliprandi 4:21603d68bcf7 329 }
Davide Aliprandi 4:21603d68bcf7 330
Davide Aliprandi 4:21603d68bcf7 331 /** Computes the two-div-plus-odd factor of a given I2S objects
Davide Aliprandi 4:21603d68bcf7 332 * on a desired frequency.
Davide Aliprandi 4:21603d68bcf7 333 *
Davide Aliprandi 4:21603d68bcf7 334 * @param dev_i2s reference to the I2S object.
Davide Aliprandi 4:21603d68bcf7 335 * @frequency the desired frequency.
Davide Aliprandi 4:21603d68bcf7 336 * @return the computed two-div-plus-odd factor.
Davide Aliprandi 4:21603d68bcf7 337 */
Davide Aliprandi 4:21603d68bcf7 338 float I2S::compute_magic_factor(I2S *dev_i2s, float f)
Davide Aliprandi 4:21603d68bcf7 339 {
Davide Aliprandi 4:21603d68bcf7 340 uint32_t i2sclk = 0U, i2sdiv = 2U, i2sodd = 0U, packetlength = 1U, tmp = 0U;
Davide Aliprandi 4:21603d68bcf7 341 I2S_HandleTypeDef *hi2s;
Davide Aliprandi 4:21603d68bcf7 342
Davide Aliprandi 4:21603d68bcf7 343 /* Get the I2S handle. */
Davide Aliprandi 4:21603d68bcf7 344 hi2s = i2s_get_handle(&(dev_i2s->_i2s));
Davide Aliprandi 4:21603d68bcf7 345
Davide Aliprandi 4:21603d68bcf7 346 /* Get I2S source Clock frequency. */
Davide Aliprandi 4:21603d68bcf7 347 i2sclk = I2S_GetInputClock(hi2s);
Davide Aliprandi 4:21603d68bcf7 348 /* Compute the I2S frequencies. */
Davide Aliprandi 4:21603d68bcf7 349 uint32_t format_factor = (hi2s->Init.DataFormat == I2S_DATAFORMAT_16B ? 16 : 32);
Davide Aliprandi 4:21603d68bcf7 350 uint32_t mclk_factor = (hi2s->Init.MCLKOutput == I2S_MCLKOUTPUT_ENABLE ? (format_factor == 16 ? 8 : 4) : 1);
Davide Aliprandi 4:21603d68bcf7 351 float mf = i2sclk / (2 * format_factor * f * mclk_factor);
Davide Aliprandi 4:21603d68bcf7 352
Davide Aliprandi 4:21603d68bcf7 353 return mf;
Davide Aliprandi 4:21603d68bcf7 354 }
Davide Aliprandi 4:21603d68bcf7 355
Davide Aliprandi 4:21603d68bcf7 356 float I2S::compute_desired_frequency(I2S *dev_i2s, float mf)
Davide Aliprandi 4:21603d68bcf7 357 {
Davide Aliprandi 4:21603d68bcf7 358 uint32_t i2sclk = 0U, i2sdiv = 2U, i2sodd = 0U, packetlength = 1U, tmp = 0U;
Davide Aliprandi 4:21603d68bcf7 359 I2S_HandleTypeDef *hi2s;
Davide Aliprandi 4:21603d68bcf7 360
Davide Aliprandi 4:21603d68bcf7 361 /* Get the I2S handle. */
Davide Aliprandi 4:21603d68bcf7 362 hi2s = i2s_get_handle(&(dev_i2s->_i2s));
Davide Aliprandi 4:21603d68bcf7 363
Davide Aliprandi 4:21603d68bcf7 364 /* Get I2S source Clock frequency. */
Davide Aliprandi 4:21603d68bcf7 365 i2sclk = I2S_GetInputClock(hi2s);
Davide Aliprandi 4:21603d68bcf7 366
Davide Aliprandi 4:21603d68bcf7 367 /* Compute the I2S frequencies. */
Davide Aliprandi 4:21603d68bcf7 368 uint32_t format_factor = (hi2s->Init.DataFormat == I2S_DATAFORMAT_16B ? 16 : 32);
Davide Aliprandi 4:21603d68bcf7 369 uint32_t mclk_factor = (hi2s->Init.MCLKOutput == I2S_MCLKOUTPUT_ENABLE ? (format_factor == 16 ? 8 : 4) : 1);
Davide Aliprandi 4:21603d68bcf7 370 float f = i2sclk / (2 * format_factor * mf * mclk_factor);
Davide Aliprandi 4:21603d68bcf7 371
Davide Aliprandi 4:21603d68bcf7 372 return f;
Davide Aliprandi 4:21603d68bcf7 373 }
Davide Aliprandi 4:21603d68bcf7 374
Davide Aliprandi 4:21603d68bcf7 375 int I2S::harmonize(I2S *dev_i2s_1, I2S *dev_i2s_2)
Davide Aliprandi 4:21603d68bcf7 376 {
Davide Aliprandi 4:21603d68bcf7 377 if (dev_i2s_1->_hz == dev_i2s_2->_hz)
Davide Aliprandi 4:21603d68bcf7 378 return 0;
Davide Aliprandi 4:21603d68bcf7 379
Davide Aliprandi 4:21603d68bcf7 380 /* Compute the real frequencies. */
Davide Aliprandi 4:21603d68bcf7 381 float f1 = compute_real_frequency(dev_i2s_1);
Davide Aliprandi 4:21603d68bcf7 382 float f2 = compute_real_frequency(dev_i2s_2);
Davide Aliprandi 4:21603d68bcf7 383
Davide Aliprandi 4:21603d68bcf7 384 //printf("REAL: %f %f\r\n", f1, f2);
Davide Aliprandi 4:21603d68bcf7 385
Davide Aliprandi 4:21603d68bcf7 386 /* Compute the desired frequencies so that they are multiple one of the
Davide Aliprandi 4:21603d68bcf7 387 other. */
Davide Aliprandi 4:21603d68bcf7 388 float q;
Davide Aliprandi 4:21603d68bcf7 389 if (f1 < f2)
Davide Aliprandi 4:21603d68bcf7 390 q = f2 / f1;
Davide Aliprandi 4:21603d68bcf7 391 else
Davide Aliprandi 4:21603d68bcf7 392 q = f1 / f2;
Davide Aliprandi 4:21603d68bcf7 393 float r = q - (uint32_t) q;
Davide Aliprandi 4:21603d68bcf7 394
Davide Aliprandi 4:21603d68bcf7 395 if (r > 0)
Davide Aliprandi 4:21603d68bcf7 396 {
Davide Aliprandi 4:21603d68bcf7 397 if (f1 < f2)
Davide Aliprandi 4:21603d68bcf7 398 {
Davide Aliprandi 4:21603d68bcf7 399 float mf = compute_magic_factor(dev_i2s_1, f2 / 2);
Davide Aliprandi 4:21603d68bcf7 400 r = mf - (uint32_t) mf;
Davide Aliprandi 4:21603d68bcf7 401 if (r > 0)
Davide Aliprandi 4:21603d68bcf7 402 {
Davide Aliprandi 4:21603d68bcf7 403 if (f2 > dev_i2s_2->_hz)
Davide Aliprandi 4:21603d68bcf7 404 f1 = compute_desired_frequency(dev_i2s_1, ((uint32_t) mf) + 1);
Davide Aliprandi 4:21603d68bcf7 405 else
Davide Aliprandi 4:21603d68bcf7 406 f1 = compute_desired_frequency(dev_i2s_1, ((uint32_t) mf) - 1);
Davide Aliprandi 4:21603d68bcf7 407 f2 = 2 * f1;
Davide Aliprandi 4:21603d68bcf7 408 }
Davide Aliprandi 4:21603d68bcf7 409 else
Davide Aliprandi 4:21603d68bcf7 410 f1 = f2 / 2;
Davide Aliprandi 4:21603d68bcf7 411 }
Davide Aliprandi 4:21603d68bcf7 412 else
Davide Aliprandi 4:21603d68bcf7 413 {
Davide Aliprandi 4:21603d68bcf7 414 float mf = compute_magic_factor(dev_i2s_2, f1 / 2);
Davide Aliprandi 4:21603d68bcf7 415 r = mf - (uint32_t) mf;
Davide Aliprandi 4:21603d68bcf7 416 if (r > 0)
Davide Aliprandi 4:21603d68bcf7 417 {
Davide Aliprandi 4:21603d68bcf7 418 if (f1 > dev_i2s_1->_hz)
Davide Aliprandi 4:21603d68bcf7 419 f2 = compute_desired_frequency(dev_i2s_2, ((uint32_t) mf) + 1);
Davide Aliprandi 4:21603d68bcf7 420 else
Davide Aliprandi 4:21603d68bcf7 421 f2 = compute_desired_frequency(dev_i2s_2, ((uint32_t) mf) - 1);
Davide Aliprandi 4:21603d68bcf7 422 f1 = 2 * f2;
Davide Aliprandi 4:21603d68bcf7 423 }
Davide Aliprandi 4:21603d68bcf7 424 else
Davide Aliprandi 4:21603d68bcf7 425 f2 = f1 / 2;
Davide Aliprandi 4:21603d68bcf7 426 }
Davide Aliprandi 4:21603d68bcf7 427 }
Davide Aliprandi 4:21603d68bcf7 428
Davide Aliprandi 4:21603d68bcf7 429 //printf("DESIRED: %f %f\r\n", f1, f2);
Davide Aliprandi 4:21603d68bcf7 430
Davide Aliprandi 4:21603d68bcf7 431 /* Set the desired frequencies. */
Davide Aliprandi 4:21603d68bcf7 432 dev_i2s_1->audio_frequency(f1);
Davide Aliprandi 4:21603d68bcf7 433 dev_i2s_2->audio_frequency(f2);
Davide Aliprandi 4:21603d68bcf7 434
Davide Aliprandi 4:21603d68bcf7 435 return 0;
Davide Aliprandi 4:21603d68bcf7 436 }
Davide Aliprandi 4:21603d68bcf7 437
Wolfgang Betz 0:752e74bf5ef1 438 } // namespace mbed
Wolfgang Betz 0:752e74bf5ef1 439
Wolfgang Betz 0:752e74bf5ef1 440 #endif