Quentin Roche / ST_I2S

Dependents:   X_NUCLEO_CCA02M1

Fork of ST_I2S by ST

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers I2S.h Source File

I2S.h

00001 #ifndef MBED_I2S_H
00002 #define MBED_I2S_H
00003 
00004 #include "platform.h"
00005 
00006 #if DEVICE_I2S
00007 
00008 #include "platform/PlatformMutex.h"
00009 #include "hal/stm_i2s_api.h"
00010 #include "platform/SingletonPtr.h"
00011 
00012 #include "platform/CThunk.h"
00013 #include "hal/stm_dma_api.h"
00014 #include "platform/CircularBuffer.h"
00015 #include "platform/FunctionPointer.h"
00016 #include "platform/Transaction.h"
00017 
00018 #include "events/EventQueue.h"
00019 
00020 /** A I2S Master/Slave, used for communicating with I2S slave/master devices
00021  *
00022  * The default format is set to master transmission mode, one-shot (i.e. not circular) 
00023  * 16 data bits & 16 bits per frame, clock polarity 0, 
00024  * protocol PHILIPS, and a clock frequency of 44.1kHz
00025  *
00026  * Most I2S devices will also require Reset signals. These
00027  * can be controlled using <DigitalOut> pins
00028  *
00029  * @Note Synchronization level: Thread safe
00030  *
00031  */
00032 class I2S {
00033 
00034 public:
00035     /** Create a I2S master connected to the specified pins
00036      *
00037      *  @param dpin  I2S data input/output pin
00038      *  @param clk   I2S clock output pin
00039      *  @param wsel  I2S word select output pin (might be NC for PDM sources)
00040      *  @param fdpin I2S data input pin (for full-duplex operation, default = NC)
00041      *  @param mck   I2S master clock output (additional pin when needed for some external audio devices, default = NC)
00042      *
00043      *  @Note It is up to the application programmer to not generate at the same time two I2S instances with the
00044      *        same pin (NC excluded) for one of the parameters, otherwise the correct operation of this class cannot be
00045      *        guaranteed (e.g. things like SPI/I2S clock enabling and above all disabling might not work correctly)!
00046      */
00047     I2S(PinName dpin, PinName clk, PinName wsel, PinName fdpin = NC, PinName mck = NC);
00048 
00049     /** Configure the data transmission format
00050      *
00051      *  @param dbits Number of data bits per I2S frame (16, 24, or 32)
00052      *  @param fbits Number of bits per I2S frame (16 or 32)
00053      *  @param polarity Clock polarity (either 0/low or 1/high, default = 0)
00054      *  @return Zero if the usage was set, -1 if a transaction is on-going
00055      */
00056     int format(int dbits, int fbits, int polarity = 0);
00057 
00058     /** Set the i2s audio frequency
00059      *
00060      *  @param hz audio frequency in hz
00061      *  @return Zero if the usage was set, -1 if a transaction is on-going
00062      */
00063     int audio_frequency(unsigned int hz);
00064 
00065     /** Get the i2s audio frequency
00066      *
00067      *  @return Currently set audio frequency
00068      */
00069     unsigned int get_audio_frequency(void) {
00070     return _hz;
00071     }
00072 
00073     /** Set the i2s bus protocol
00074      *
00075      *  @param protocol I2S protocol to be used
00076      *  @return Zero if the usage was set, -1 if a transaction is on-going
00077      */
00078     int protocol(i2s_bitorder_t protocol);
00079 
00080     /** Set the i2s mode
00081      *
00082      *  @param mode     I2S mode to be used
00083      *  @param circular I2S should read/write buffers continuously (in circular mode)
00084      *  @return Zero if the usage was set, -1 if a transaction is on-going
00085      */
00086     int mode(i2s_mode_t mode, bool circular);
00087 
00088     /** Start non-blocking I2S transfer as configured with above methods
00089      *
00090      * @param tx_buffer The TX buffer with data to be transfered. If NULL is passed,
00091      *                  no transmission will be set up 
00092      * @param tx_length The length of TX buffer in bytes
00093      * @param rx_buffer The RX buffer which is used for received data. If NULL is passed,
00094      *                  received data will be ignored
00095      * @param rx_length The length of RX buffer in bytes
00096      * @param callback  The event callback function
00097      * @param event     The logical OR of events to notify. Look at i2s hal header file for I2S events.
00098      * @return Zero if the transfer has started (or been queued), or 
00099      *         -1   if I2S peripheral is busy (or out of resources)
00100      */
00101     template<typename Type>
00102     int transfer(const Type *tx_buffer, int tx_length, Type *rx_buffer, int rx_length, const mbed::event_callback_t& callback, int event) {
00103     int ret = 0;
00104 
00105     lock();
00106 
00107     if (i2s_active(&_i2s)
00108 #if TRANSACTION_QUEUE_SIZE_I2S
00109         || !_transaction_buffer.empty()
00110 #endif
00111         ) {
00112         ret = queue_transfer(tx_buffer, tx_length, rx_buffer, rx_length, callback, event);
00113     } else {
00114         start_transfer(tx_buffer, tx_length, rx_buffer, rx_length, callback, event);
00115     }
00116 
00117     unlock();
00118     return ret;
00119     }
00120     
00121     /** Abort the on-going I2S transfer, and continue with transfer's in the queue if any.
00122      */
00123     void abort_transfer();
00124 
00125     /** Clear the transaction buffer
00126      */
00127     void clear_transfer_buffer();
00128 
00129     /** Clear the transaction buffer and abort on-going transfer.
00130      */
00131     void abort_all_transfers();
00132 
00133     /** Get transfer status
00134      *
00135      *  @return -1 if a transaction is on-going, zero otherwise
00136      */
00137     int get_transfer_status();
00138 
00139     /** Get internal module id
00140      *
00141      *  @return internal module id
00142      */
00143     unsigned int get_module();
00144 
00145     /** Configure DMA priority for transfers
00146      *
00147      *  @param prio The DMA priority to be used
00148      *  @return Zero if the usage was set, -1 if a transaction is on-going
00149      */
00150     int dma_priority(i2s_dma_prio_t prio);
00151 
00152     /** Harmonize the frequencies of the given I2S objects so that they are
00153      *  the exact multiple one of the other. It can be useful whenever two I2S
00154      *  peripherals have to work together and no drift is allowed between them.
00155      *
00156      *  @param dev_i2s_1 reference to the first I2S object.
00157      *  @param dev_i2s_2 reference to the second I2S object.
00158      *  @return Zero if the frequencies have been harmonized correctly, -1
00159      *          otherwise.
00160      */
00161     static int harmonize(I2S &dev_i2s_1, I2S &dev_i2s_2);
00162 
00163 
00164     /** Bottom-half & transactions event queue for all I2S objects
00165      *  Must be used by application programmer to schedule/execute bottom-halves
00166      *  (i.e. transfer event callback functions) and automatically start queued
00167      *  transactions (i.e. transfers), e.g. by calling `events::EventQueue::dispatch_forever()`! */
00168     static events::EventQueue i2s_bh_queue;
00169 
00170 protected:
00171     /** Acquire exclusive access to this I2S bus
00172      */
00173     virtual void lock(void);
00174 
00175     /** Release exclusive access to this I2S bus
00176      */
00177     virtual void unlock(void);
00178 
00179     /** I2S TX DMA IRQ handler
00180      *
00181      */
00182     void irq_handler_asynch_tx(void);
00183 
00184     /** I2S RX DMA IRQ handler
00185      *
00186      */
00187     void irq_handler_asynch_rx(void);
00188 
00189     /** Add a transfer to the queue
00190      * @param data Transaction data
00191      * @return Zero if a transfer was added to the queue, or -1 if the queue is full
00192      */
00193     int queue_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, 
00194                const mbed::event_callback_t& callback, int event);
00195     
00196     /** Configures a callback, i2s peripheral and initiate a new transfer
00197      *
00198      * @param data Transaction data
00199      */
00200     void start_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, 
00201             const mbed::event_callback_t& callback, int event);
00202 
00203     class I2sBhHandler {
00204     friend class I2S;
00205 
00206     static void i2s_defer_function(const mbed::event_callback_t& bottom_half, int event) {
00207         i2s_bh_queue.call(bottom_half, event);
00208     }
00209 
00210     static void i2s_defer_function(const mbed::Callback<void()>& bottom_half) {
00211         i2s_bh_queue.call(bottom_half);
00212     }
00213     };
00214 
00215 #if TRANSACTION_QUEUE_SIZE_I2S
00216     /** Start a new transaction
00217      *
00218      *  @param data Transaction data
00219      */
00220     void start_transaction(mbed::transaction_t *data);
00221 
00222     /** Dequeue a transaction
00223      *
00224      */
00225     void dequeue_transaction();
00226 
00227     mbed::CircularBuffer<mbed::Transaction<I2S>, TRANSACTION_QUEUE_SIZE_I2S> _transaction_buffer;
00228 #endif // TRANSACTION_QUEUE_SIZE_I2S
00229 
00230 public:
00231     virtual ~I2S() {
00232     /* TODO: cleanup has still to be revised completely! */
00233     abort_all_transfers();
00234     i2s_free(&_i2s);
00235     }
00236 
00237 protected:
00238     i2s_t _i2s;
00239 
00240     CThunk<I2S> _irq_tx;
00241     CThunk<I2S> _irq_rx;
00242     mbed::event_callback_t _callback;
00243     i2s_dma_prio_t _priority; // DMA priority
00244 
00245     void acquire(void);
00246 
00247     static I2S *_owner;
00248     static SingletonPtr<PlatformMutex> _mutex;
00249 
00250     int _dbits;
00251     int _fbits;
00252     int _polarity;
00253     i2s_bitorder_t _protocol;
00254     i2s_mode_t _mode;
00255     bool _circular;
00256     unsigned int _hz;
00257 };
00258 
00259 #endif // DEVICE_I2S
00260 
00261 #endif // MBED_I2S_H