/* * Copyright (c) 2015-2019, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*!**************************************************************************** * @file I2S.h * @brief Inter-Integrated Circuit Sound (I2S) Bus Driver * * The I2S header file should be included in an application as follows: * @code * #include * @endcode * * @anchor ti_drivers_I2S_Overview * # Overview # * * The I2S driver facilitates the use of Inter-IC Sound (I2S), which is * used to connect digital audio devices so that audio signals can be * communicated between devices. The I2S driver simplifies reading and * writing to any of the Multichannel Audio Serial Port (McASP) peripherals * on the board with Receive and Transmit support. These include read and * write characters on the McASP peripheral. * * I2S interfaces typically consist of 4 or 5 signals. The 5th signal is not * systematically used. * @li Serial Clock (SCK) also called Bit Clock (BCLK) or Multichannel * Audio Frame Synchronization (McAFSX) * @li Word Select (WS) also called Word Clock (WCLK), Left Right * Clock (LRCLK) or Multichannel Audio Clock (McACLK) * @li Serial Data (SD0) also called AD0, AD1, McAXR0, or possibly SDI * @li Serial Data (SD1) also called AD1, ADI, McAXR1, or possibly SDI * @li Master Clock (MCLK) * *
* @anchor ti_drivers_I2S_Usage * # Usage # * * The I2S driver provides the following APIs: * @li I2S_init(): @copybrief I2S_init * @li I2S_open(): @copybrief I2S_open * @li I2S_Params_init(): @copybrief I2S_Params_init * @li I2S_Transaction_init(): @copybrief I2S_Transaction_init * @li I2S_setReadQueueHead(): @copybrief I2S_setReadQueueHead * @li I2S_startClocks(): @copybrief I2S_startClocks * @li I2S_startRead(): @copybrief I2S_startRead * @li I2S_stopRead(): @copybrief I2S_stopRead * @li I2S_stopClocks(): @copybrief I2S_stopClocks * @li I2S_close(): @copybrief I2S_close * *
* @anchor ti_drivers_I2S_Driver_Transactions * ### Transactions # * * Data transfers are achieved through #I2S_Transaction structures. Application is * responsible to maintain the transactions queues. The I2S driver completes the * transactions one by one. When a transaction is over, the I2S driver takes in * consideration the next transaction (if the next transaction is NULL, the I2S * drivers signals this to the user). * The I2S driver relies on the following fields of the #I2S_Transaction to * complete it: * - the buffer * - the length of the buffer * - a pointer on the next transaction to achieve (kept in a List_Elem structure) * . * The I2S driver provides the following elements (fields of the #I2S_Transaction): * - the number of untransferred bytes: the driver is designed to avoid memory corruption and will * not complete an incomplete transaction (meaning a transaction where the buffer size would not * permit to send or receive a whole number of samples). In this case, the system considers the * samples of the beginning of the buffer and read/write as much as possible samples and ignore the * end of the buffer. The number of untransafered bytes is the number of bytes left at the end of * the buffer) * - the number of completions of the transaction. This value is basically incremented by one * every time the transaction is completed. * . * Please note that these two fields are valid only when the transaction has been completed. * Consult examples to get more details on the transaction usage. * *
* @anchor ti_drivers_I2S_Driver_ProvidingData * ### Providing data to the I2S driver # * Application is responsible to handle the queues of transactions. * Application is also responsible to provide to the driver a pointer on * the first transaction to consider (considering that all the following * transactions are correctly queued). * #I2S_setReadQueueHead() and #I2S_setWriteQueueHead() allow the user to * set the first transaction to consider. These functions should be used only * when no transaction is running on the considered interface. * *
* @anchor ti_drivers_I2S_Driver_StartStopClocks * ### Start and stop clocks and transactions # * Clocks can be started and stopped by the application. * Read and write can be started and stopped independently. * To start a transfer, clocks must be running. * To stop the clocks no transfer must be running. * Refer to the following functions for more details: * @li I2S_startClocks() @li I2S_startRead() @li I2S_startWrite() * @li I2S_stopRead() @li I2S_stopWrite() @li I2S_stopClocks() * * @note * @li In #I2S_SLAVE mode, clocks must be started and stopped exactly like * it is done in #I2S_MASTER mode. * @li If the queue of transaction is not empty, the calls to #I2S_stopRead() * and #I2S_stopWrite() are blocking and potentially long. * *
* @anchor ti_drivers_I2S_Examples * ## Examples # * * @li @ref ti_drivers_I2S_Example_PlayAndStop "Play and Stop" * @li @ref ti_drivers_I2S_Example_Streaming "Streaming" * @li @ref ti_drivers_I2S_Example_RepeatMode "Repeat" * *
* @anchor ti_drivers_I2S_Example_PlayAndStop * ### Mode Play and Stop # * The following example shows how to simultaneously receive and send out a given amount of data. * *
* @anchor ti_drivers_I2S_Example_PlayAndStop_Code * @code * static I2S_Handle i2sHandle; * static I2S_Config i2sConfig; * * static uint16_t readBuf1[500]; // the data read will end up in this buffer * static uint16_t readBuf2[500]; // the data read will end up in this buffer * static uint16_t readBuf3[500]; // the data read will end up in this buffer * static uint16_t writeBuf1[250] = {...some data...}; // this buffer will be sent out * static uint16_t writeBuf2[250] = {...some data...}; // this buffer will be sent out * static uint16_t writeBuf3[250] = {...some data...}; // this buffer will be sent out * * static I2S_Transaction i2sRead1; * static I2S_Transaction i2sRead2; * static I2S_Transaction i2sRead3; * static I2S_Transaction i2sWrite1; * static I2S_Transaction i2sWrite2; * static I2S_Transaction i2sWrite3; * * List_List i2sReadList; * List_List i2sWriteList; * * static volatile bool readStopped = (bool)true; * static volatile bool writeStopped = (bool)true; * * static void writeCallbackFxn(I2S_Handle handle, int_fast16_t status, I2S_Transaction *transactionPtr) { * * if(status & I2S_ALL_TRANSACTIONS_SUCCESS){ * * //Note: You should normally avoid to use I2S_stopRead() / I2S_stopWrite() in the callback. * //However, here we do not have any transaction left in the queue (cf. status' value) so * //the call to I2S_stoWrite() will not block. * //Moreover, by delaying I2S_stopWrite() the driver could raise an error (data underflow). * * I2S_stopWrite(i2sHandle); * writeStopped = (bool)true; * } * } * * static void readCallbackFxn(I2S_Handle handle, int_fast16_t status, I2S_Transaction *transactionPtr) { * * if(status & I2S_ALL_TRANSACTIONS_SUCCESS){ * * //Note: You should normally avoid to use I2S_stopRead() / I2S_stopWrite() in the callback. * //However, here we do not have any transaction left in the queue (cf. status' value) so * //the call to I2S_stopRead() will not block. * //Moreover, by delaying I2S_stopRead() the driver could raise an error (data overflow). * * I2S_stopRead(i2sHandle); * readStopped = (bool)true; * } * } * * static void errCallbackFxn(I2S_Handle handle, int_fast16_t status, I2S_Transaction *transactionPtr) { * I2S_stopRead(handle); * I2S_stopWrite(handle); * I2S_stopClocks(handle); * I2S_close(handle); * } * * void *modePlayAndStopThread(void *arg0) * { * I2S_Params i2sParams; * * I2S_init(); * * // Initialize I2S opening parameters * I2S_Params_init(&i2sParams); * i2sParams.fixedBufferLength = 500; // fixedBufferLength is the greatest common * // divisor of all the different buffers * // (here buffers' size are 500 and 1000 bytes) * i2sParams.writeCallback = writeCallbackFxn ; * i2sParams.readCallback = readCallbackFxn ; * i2sParams.errorCallback = errCallbackFxn; * * i2sHandle = I2S_open(Board_I2S0, &i2sParams); * * // Initialize the read-transactions * I2S_Transaction_init(&i2sRead1); * I2S_Transaction_init(&i2sRead2); * I2S_Transaction_init(&i2sRead3); * i2sRead1.bufPtr = readBuf1; * i2sRead2.bufPtr = readBuf2; * i2sRead3.bufPtr = readBuf3; * i2sRead1.bufSize = sizeof(readBuf1); * i2sRead2.bufSize = sizeof(readBuf2); * i2sRead3.bufSize = sizeof(readBuf3); * List_put(&i2sReadList, (List_Elem*)&i2sRead1); * List_put(&i2sReadList, (List_Elem*)&i2sRead2); * List_put(&i2sReadList, (List_Elem*)&i2sRead3); * * I2S_setReadQueueHead(i2sHandle, &i2sRead1); * * // Initialize the write-transactions * I2S_Transaction_init(&i2sWrite1); * I2S_Transaction_init(&i2sWrite2); * I2S_Transaction_init(&i2sWrite3); * i2sWrite1.bufPtr = writeBuf1; * i2sWrite2.bufPtr = writeBuf2; * i2sWrite3.bufPtr = writeBuf3; * i2sWrite1.bufSize = sizeof(writeBuf1); * i2sWrite2.bufSize = sizeof(writeBuf2); * i2sWrite3.bufSize = sizeof(writeBuf3); * List_put(&i2sWriteList, (List_Elem*)&i2sWrite1); * List_put(&i2sWriteList, (List_Elem*)&i2sWrite2); * List_put(&i2sWriteList, (List_Elem*)&i2sWrite3); * * I2S_setWriteQueueHead(i2sHandle, &i2sWrite1); * * I2S_startClocks(i2sHandle); * I2S_startWrite(i2sHandle); * I2S_startRead(i2sHandle); * * readStopped = (bool)false; * writeStopped = (bool)false; * * while(1) { * * if(readStopped && writeStopped) { * I2S_stopClocks(i2sHandle); * I2S_close(i2sHandle); * while(1); * } * } * } * @endcode * * \note If you desire to put only one transaction in the queue, fixedBufferLength must be inferior to half the length (in bytes) of the buffer to transfer. * *
* @anchor ti_drivers_I2S_Example_Streaming * ### Writing Data in Continuous Streaming Mode # * The following example shows how to read and write data in streaming mode. * A dummy treatment of the data is also done. * This example is not complete (semaphore and tasks creation are not shown) * *
* @anchor ti_drivers_I2S_Example_Streaming_Code * @code * static I2S_Handle i2sHandle; * static I2S_Config i2sConfig; * * // These buffers will successively be written, treated and sent out * static uint16_t readBuf1[500]; * static uint16_t readBuf2[500]; * static uint16_t readBuf3[500]; * static uint16_t readBuf4[500]; * static uint16_t writeBuf1[500]={0}; * static uint16_t writeBuf2[500]={0}; * static uint16_t writeBuf3[500]={0}; * static uint16_t writeBuf4[500]={0}; * * // These transactions will successively be part of the * // i2sReadList, the treatmentList and the i2sWriteList * static I2S_Transaction i2sRead1; * static I2S_Transaction i2sRead2; * static I2S_Transaction i2sRead3; * static I2S_Transaction i2sRead4; * static I2S_Transaction i2sWrite1; * static I2S_Transaction i2sWrite2; * static I2S_Transaction i2sWrite3; * static I2S_Transaction i2sWrite4; * * List_List i2sReadList; * List_List treatmentList; * List_List i2sWriteList; * * static void writeCallbackFxn(I2S_Handle handle, int_fast16_t status, I2S_Transaction *transactionPtr) { * * // We must remove the previous transaction (the current one is not over) * I2S_Transaction *transactionFinished = (I2S_Transaction*)List_prev(&transactionPtr->queueElement); * * if(transactionFinished != NULL){ * // Remove the finished transaction from the write queue * List_remove(&i2sWriteList, (List_Elem*)transactionFinished); * * // This transaction must now feed the read queue (we do not need anymore the data of this transaction) * transactionFinished->queueElement.next = NULL; * List_put(&i2sReadList, (List_Elem*)transactionFinished); * * // We need to queue a new transaction: let's take one in the treatment queue * I2S_Transaction *newTransaction = (I2S_Transaction*)List_head(&treatmentList); * if(newTransaction != NULL){ * List_remove(&treatmentList, (List_Elem*)newTransaction); * newTransaction->queueElement.next = NULL; * List_put(&i2sWriteList, (List_Elem*)newTransaction); * } * } * } * * static void readCallbackFxn(I2S_Handle handle, int_fast16_t status, I2S_Transaction *transactionPtr) { * * // We must remove the previous transaction (the current one is not over) * I2S_Transaction *transactionFinished = (I2S_Transaction*)List_prev(&transactionPtr->queueElement); * * if(transactionFinished != NULL){ * // The finished transaction contains data that must be treated * List_remove(&i2sReadList, (List_Elem*)transactionFinished); * transactionFinished->queueElement.next = NULL; * List_put(&treatmentList, (List_Elem*)transactionFinished); * * // Start the treatment of the data * Semaphore_post(dataReadyForTreatment); * * // We do not need to queue transaction here: writeCallbackFxn takes care of this :) * } * } * * static void errCallbackFxn(I2S_Handle handle, int_fast16_t status, I2S_Transaction *transactionPtr) { * * } * * void *myTreatmentThread(void *arg0){ * * int k; * * while(1) { * Semaphore_pend(dataReadyForTreatment, BIOS_WAIT_FOREVER); * * if(lastAchievedReadTransaction != NULL) { * * // Need a critical section to be sure to have corresponding bufPtr and bufSize * uintptr_t key = HwiP_disable(); * uint16_t *buf = lastAchievedReadTransaction->bufPtr; * uint16_t bufLength = lastAchievedReadTransaction->bufSize / sizeof(uint16_t); * HwiP_restore(key); * * // My dummy data treatment... * for(k=0; k * @anchor ti_drivers_I2S_Example_RepeatMode * ### Writing Data in repeat Mode # * The following example shows how to read and write data in repeat mode. * The same buffers are continuously written and send out while the driver is not stopped. * Here, we decide to only stop sending out after an arbitrary number of sending. * *
* @anchor ti_drivers_I2S_Example_RepeatMode_Code * @code * static I2S_Handle i2sHandle; * static I2S_Config i2sConfig; * static I2SCC26XX_Object i2sObject; * * // This buffer will be continuously re-written * static uint16_t readBuf[500]; * // This data will be continuously sent out * static uint16_t writeBuf[500] = {...some cool data...}; * * static I2S_Transaction i2sRead; * static I2S_Transaction i2sWrite; * * List_List i2sReadList; * List_List i2sWriteList; * * static volatile bool writeFinished = (bool)false; * static void writeCallbackFxn(I2S_Handle handle, int_fast16_t status, I2S_Transaction *transactionPtr) { * * // Nothing to do here: the buffer(s) are queued in a ring list, the transfers are * // executed without any action from the application. * * // We must consider the previous transaction (ok, when you have only one transaction it's the same) * I2S_Transaction *transactionFinished = (I2S_Transaction*)List_prev(&transactionPtr->queueElement); * * if(transactionFinished != NULL){ * // After an arbitrary number of completion of the transaction, we will stop writting * if(transactionFinished->numberOfCompletions >= 10) { * * // Note: You should avoid to use I2S_stopRead() / I2S_stopWrite() in the callback, * // especially if you do not want to stop both read and write transfers. * // The execution of these functions is potentially blocking and can mess up the * // other transfers. * * writeFinished = (bool)true; * } * } * } * * static void readCallbackFxn(I2S_Handle handle, int_fast16_t status, I2S_Transaction *transactionPtr) { * // Nothing to do here: the buffer(s) are queued in a ring list, the transfers are * // executed without any action from the application. * } * * static void errCallbackFxn(I2S_Handle handle, int_fast16_t status, I2S_Transaction *transactionPtr) { * * } * * void *modeRepeat(void *arg0) * { * I2S_Params i2sParams; * * // Initialize I2S opening parameters * I2S_Params_init(&i2sParams); * i2sParams.fixedBufferLength = 1000; // No problem here: the driver consider * // the list as an infinite list. * i2sParams.writeCallback = writeCallbackFxn ; * i2sParams.readCallback = readCallbackFxn ; * i2sParams.errorCallback = errCallbackFxn; * * i2sHandle = I2S_open(0, &i2sParams); * * // Initialize the read-transactions * I2S_Transaction_init(&i2sRead); * i2sRead.bufPtr = readBuf; * i2sRead.bufSize = sizeof(readBuf); * List_put(&i2sReadList, (List_Elem*)&i2sRead); * List_tail(&i2sReadList)->next = List_head(&i2sReadList);// Read buffers are queued in a ring-list * List_head(&i2sReadList)->prev = List_tail(&i2sReadList); * * I2S_setReadQueueHead(i2sHandle, &i2sRead); * * // Initialize the write-transactions * I2S_Transaction_init(&i2sWrite); * i2sWrite.bufPtr = writeBuf; * i2sWrite.bufSize = sizeof(writeBuf); * List_put(&i2sWriteList, (List_Elem*)&i2sWrite); * List_tail(&i2sWriteList)->next = List_head(&i2sWriteList); // Write buffers are queued in a ring-list * List_head(&i2sWriteList)->prev = List_tail(&i2sWriteList); * * I2S_setWriteQueueHead(i2sHandle, &i2sWrite); * * I2S_startClocks(i2sHandle); * I2S_startWrite(i2sHandle); * I2S_startRead(i2sHandle); * * while(1){ * * if(writeFinished){ * writeFinished = (bool)false; * I2S_stopWrite(i2sHandle); * } * } * } * @endcode * * @note In the case of circular lists, there is no problem to put only * one buffer in the queue. * *
* @anchor ti_drivers_I2S_Configuration * # Configuration * * Refer to the @ref driver_configuration "Driver's Configuration" section * for driver configuration information. *
****************************************************************************** */ #ifndef ti_drivers_I2S__include #define ti_drivers_I2S__include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** * @defgroup I2S_STATUS Status Codes * I2S_STATUS_* macros are general status codes used when user callback is called * @{ * @ingroup I2S_CONTROL */ /*! * @brief Successful status code returned by I2S driver functions. * * I2S driver functions return I2S_ALL_TRANSACTION_SUCCESS if ALL the queued transactions * were executed successfully. */ #define I2S_ALL_TRANSACTIONS_SUCCESS (0x0001U) /*! * @brief Successful status code returned by I2S driver functions. * * I2S driver functions return I2S_TRANSACTION_SUCCESS if ONE queued transaction * was executed successfully. */ #define I2S_TRANSACTION_SUCCESS (0x0002U) /*! * @brief Error status code returned by I2S driver functions. * * I2S driver functions return I2S_TIMEOUT_ERROR if I2S module lost the audio clock. * If this error has been raised, I2S module must be reseted and restarted. */ #define I2S_TIMEOUT_ERROR (0x0100U) /*! * @brief Error status code returned by I2S driver functions. * * I2S driver functions return I2S_BUS_ERROR if I2S module faced problem with the DMA * bus (DMA transfer not completed in time). * If this error has been raised, I2S module must be reseted and restarted. */ #define I2S_BUS_ERROR (0x0200U) /*! * @brief Error status code returned by I2S driver functions. * * I2S driver functions return I2S_WS_ERROR if I2S module detect noise on the WS signal. * If this error has been raised, I2S module must be reseted and restarted. */ #define I2S_WS_ERROR (0x0400U) /*! * @brief Error status code returned by I2S driver functions. * * I2S driver functions return I2S_PTR_READ_ERROR if I2S module ran out of data * on the read interface (DMA pointer not loaded in time). * If this error has been raised, I2S module must be reseted and restarted. */ #define I2S_PTR_READ_ERROR (0x0800U) /*! * @brief Error status code returned by I2S driver functions. * * I2S driver functions return I2S_PTR_WRITE_ERROR if I2S module ran out of data * on the write interface (DMA pointer not loaded in time). * If this error has been raised, I2S module must be reseted and restarted. */ #define I2S_PTR_WRITE_ERROR (0x1000U) /** @}*/ /*! * @brief A handle that is returned from a I2S_open() call. */ typedef struct I2S_Config_ *I2S_Handle; /*! * @brief I2S transaction descriptor. */ typedef struct I2S_Transaction_ { /*! Used internally to link descriptors together */ List_Elem queueElement; /*! Pointer to the buffer */ void *bufPtr; /*! Size of the buffer. */ size_t bufSize; /*! Internal use only. Number of bytes written to or read from the buffer. */ size_t bytesTransferred; /*! Number of non-transfered bytes at transaction's end. */ size_t untransferredBytes; /*! Parameter incremented each time the transaction is completed. */ uint16_t numberOfCompletions; /*! Internal argument. Application must not modify this element. */ uintptr_t arg; } I2S_Transaction; /*! * @brief The definition of a user-callback function used by the I2S driver * * @param I2S_Handle I2S_Handle * * @param status Status of the operation (possible values are : * :I2S_STATUS_SUCCESS, :I2S_STATUS_ERROR, * :I2S_STATUS_BUFFER_UNAVAILABLE, :I2S_STATUS_TIMEOUT) * * @param I2S_Transaction *transactionPtr: Pointer on the transaction just completed. * For error calbacks, transactionPtr points on NULL. * */ typedef void (*I2S_Callback)(I2S_Handle handle, int_fast16_t status, I2S_Transaction *transactionPtr); /*! * @brief The definition of a function used to set the I2S register * * @param uint32_t ui32Base: base address of the I2S module. * * @param uint32_t ui32NextPointer: pointer on an I2S buffer. * */ typedef void (*I2S_RegUpdate)(uint32_t ui32Base, uint32_t ui32NextPointer); /*! * @brief I2S slot memory length setting * * The enum defines if the module uses a 16 bits or a 24 bits buffer in memory. * This value has no influence on the number of bit transmitted. */ typedef enum I2S_MemoryLength_ { I2S_MEMORY_LENGTH_8BITS = 8U, /*!< Buffer used is 8 bits length. Not available for CC26XX. */ I2S_MEMORY_LENGTH_16BITS = 16U, /*!< Buffer used is 16 bits length. */ I2S_MEMORY_LENGTH_24BITS = 24U, /*!< Buffer used is 24 bits length. */ I2S_MEMORY_LENGTH_32BITS = 32U /*!< Buffer used is 32 bits length. Not available for CC26XX. */ } I2S_MemoryLength; /*! * @brief I2S master / slave selection * * The enum defines if the module acts like a master (clocks are internally generated) * or a slave (the clocks are externally generated). */ typedef enum I2S_Role_ { I2S_SLAVE = 0, /*!< Module is a slave, clocks are externally generated. */ I2S_MASTER = 1 /*!< Module is a master, clocks are internally generated. */ } I2S_Role; /*! * @brief I2S sampling setting * * The enum defines if sampling is done on BLCK rising or falling edges. */ typedef enum I2S_SamplingEdge_ { I2S_SAMPLING_EDGE_FALLING = 0, /*!< Sampling on falling edges. */ I2S_SAMPLING_EDGE_RISING = 1 /*!< Sampling on rising edges. */ } I2S_SamplingEdge; /*! * @brief I2S phase setting * * The enum defines if the I2S if set with single or dual phase. */ typedef enum I2S_PhaseType_ { I2S_PHASE_TYPE_SINGLE = 0U, /*!< Single phase */ I2S_PHASE_TYPE_DUAL = 1U, /*!< Dual phase */ } I2S_PhaseType; /*! * @brief I2S data interface configuration * * The enum defines the different settings for the data interfaces (SD0 and SD1). */ typedef enum I2S_DataInterfaceUse_ { I2S_SD0_DISABLED = 0x00U, /*!< SD0 is disabled */ I2S_SD0_INPUT = 0x01U, /*!< SD0 is an input */ I2S_SD0_OUTPUT = 0x02U, /*!< SD0 is an output */ I2S_SD1_DISABLED = 0x00U, /*!< SD1 is disabled */ I2S_SD1_INPUT = 0x10U, /*!< SD1 is an input */ I2S_SD1_OUTPUT = 0x20U /*!< SD1 is an output */ } I2S_DataInterfaceUse; /*! * @brief Channels used selection * * The enum defines different settings to activate the expected channels. */ typedef enum I2S_ChannelConfig_ { I2S_CHANNELS_NONE = 0x00U, /*!< No channel activated */ I2S_CHANNELS_MONO = 0x01U, /*!< MONO: only channel one is activated */ I2S_CHANNELS_MONO_INV = 0x02U, /*!< MONO INVERERTED: only channel two is activated */ I2S_CHANNELS_STEREO = 0x03U, /*!< STEREO: channels one and two are activated */ I2S_1_CHANNEL = 0x01U, /*!< 1 channel is activated */ I2S_2_CHANNELS = 0x03U, /*!< 2 channels are activated */ I2S_3_CHANNELS = 0x07U, /*!< 3 channels are activated */ I2S_4_CHANNELS = 0x0FU, /*!< 4 channels are activated */ I2S_5_CHANNELS = 0x1FU, /*!< 5 channels are activated */ I2S_6_CHANNELS = 0x3FU, /*!< 6 channels are activated */ I2S_7_CHANNELS = 0x7FU, /*!< 7 channels are activated */ I2S_8_CHANNELS = 0xFFU, /*!< 8 channels are activated */ I2S_CHANNELS_ALL = 0xFFU /*!< All the eight channels are activated */ } I2S_ChannelConfig; /*! * @brief Basic I2S Parameters * * I2S parameters are used to with the I2S_open() call. Default values for * these parameters are set using I2S_Params_init(). * * @sa I2S_Params_init() */ typedef struct I2S_Params_ { bool invertWS; /*!< WS must be internally inverted when using I2S data format. * false: The WS signal is not internally inverted. * true: The WS signal is internally inverted. */ bool isMSBFirst; /*!< Endianness selection. Not available on CC26XX. * false: The samples are transmitted LSB first. * true: The samples are transmitted MSB first. */ bool isDMAUnused; /*!< Selection between DMA transmissions and CPU transmissions. * false: Transmission are performed by DMA. * true: Transmission are performed by CPU. * Not available for CC26XX: all transmissions are performed by CPU. */ I2S_MemoryLength memorySlotLength; /*!< Memory buffer used. * #I2S_MEMORY_LENGTH_8BITS: Memory length is 8 bits (not available for CC26XX). * #I2S_MEMORY_LENGTH_16BITS: Memory length is 16 bits. * #I2S_MEMORY_LENGTH_24BITS: Memory length is 24 bits. * #I2S_MEMORY_LENGTH_32BITS: Memory length is 32 bits (not available for CC26XX).*/ uint8_t beforeWordPadding; /*!< Number of SCK periods between the first WS edge and the MSB of the first audio channel data transferred during the phase.*/ uint8_t afterWordPadding; /*!< Number of SCK periods between the first WS edge and the MSB of the first audio channel data transferred during the phase.*/ uint8_t bitsPerWord; /*!< Bits per sample (Word length): must be between 8 and 24 bits. */ I2S_Role moduleRole; /*!< Select if the I2S module is a Slave or a Master. * - #I2S_SLAVE: The device is a slave (clocks are generated externally). * - #I2S_MASTER: The device is a master (clocks are generated internally). */ I2S_SamplingEdge samplingEdge; /*!< Select edge sampling type. * - #I2S_SAMPLING_EDGE_FALLING: Sampling on falling edges (for DSP data format). * - #I2S_SAMPLING_EDGE_RISING: Sampling on rising edges (for I2S, LJF and RJF data formats). */ I2S_DataInterfaceUse SD0Use; /*!< Select if SD0 is an input, an output or disabled. * - #I2S_SD0_DISABLED: Disabled. * - #I2S_SD0_INPUT: Input. * - #I2S_SD0_OUTPUT: Output. */ I2S_DataInterfaceUse SD1Use; /*!< Select if SD1 is an input, an output or disabled. * - #I2S_SD1_DISABLED: Disabled. * - #I2S_SD1_INPUT: Input. * - #I2S_SD1_OUTPUT: Output. */ I2S_ChannelConfig SD0Channels; /*!< This parameter is a bit mask indicating which channels are valid on SD0. * If phase type is "dual", maximum channels number is two. * Valid channels on SD1 and SD0 can be different. * For dual phase mode: * - #I2S_CHANNELS_NONE: No channel activated: * read -> I2S does not receive anything (no buffer consumption) * write -> I2S does not send anything (no buffer consumption) * - #I2S_CHANNELS_MONO: Only channel 1 is activated: * read -> I2S only reads channel 1 * write -> I2S transmits the data on channel 1 and duplicates it on channel 2 * - #I2S_CHANNELS_MONO_INV: Only channel 2 is activated: * read -> I2S only reads channel 2 * write -> I2S transmits the data on channel 2 and duplicates it on the channel 1 of the next word * - #I2S_CHANNELS_STEREO: STEREO: * read -> I2S reads both channel 1 and channel 2 * write -> I2S transmits data both on channel 1 and channel 2 * . * For single phase mode: * - Various number of channels can be activated using: #I2S_1_CHANNEL, #I2S_2_CHANNELS, #I2S_3_CHANNELS, #I2S_4_CHANNELS, * #I2S_5_CHANNELS, #I2S_6_CHANNELS, #I2S_7_CHANNELS, #I2S_8_CHANNELS. * - #I2S_CHANNELS_ALL: The eight channels are activated */ I2S_ChannelConfig SD1Channels; /*!< This parameter is a bit mask indicating which channels are valid on SD1. * If phase type is "dual", maximum channels number is two. * Valid channels on SD1 and SD0 can be different. * For dual phase mode: * - #I2S_CHANNELS_NONE: No channel activated: * read -> I2S does not receive anything (no buffer consumption) * write -> I2S does not send anything (no buffer consumption) * - #I2S_CHANNELS_MONO: Only channel 1 is activated: * read -> I2S only reads channel 1 * write -> I2S transmits the data on channel 1 and duplicates it on channel 2 * - #I2S_CHANNELS_MONO_INV: Only channel 2 is activated: * read -> I2S only reads channel 2 * write -> I2S transmits the data on channel 2 and duplicates it on the channel 1 of the next word * - #I2S_CHANNELS_STEREO: STEREO: * read -> I2S reads both channel 1 and channel 2 * write -> I2S transmits data both on channel 1 and channel 2 * . * For single phase mode: * - Various number of channels can be activated using: #I2S_1_CHANNEL, #I2S_2_CHANNELS, #I2S_3_CHANNELS, #I2S_4_CHANNELS, * #I2S_5_CHANNELS, #I2S_6_CHANNELS, #I2S_7_CHANNELS, #I2S_8_CHANNELS. * - #I2S_CHANNELS_ALL: The eight channels are activated */ I2S_PhaseType phaseType; /*!< Select phase type. * - #I2S_PHASE_TYPE_SINGLE: Single phase (for DSP format): up to eight channels are usable. * - #I2S_PHASE_TYPE_DUAL: Dual phase (for I2S, LJF and RJF data formats): up to two channels are usable. * . * This parameter must not be considered on CC32XX. This chip only allows dual phase formats.*/ uint16_t fixedBufferLength; /*!< Number of consecutive bytes of the samples buffers. This field must be set to a value x different from 0. * All the data buffers used (both for input and output) must contain N*x bytes (with N an integer verifying N>0). */ uint16_t startUpDelay; /*!< Time (in number of WS cycles) to wait before the first transfer. */ uint16_t MCLKDivider; /*!< Select the frequency divider for MCLK signal. Final value of MCLK is 48MHz/MCLKDivider. Value must be selected between 2 and 1024. */ uint32_t samplingFrequency; /*!< I2S sampling frequency configuration in samples/second. * SCK frequency limits: *- For CC26XX, SCK frequency should be between 47 kHz and 4 MHz. *- For CC32XX, SCK frequency should be between 57 Hz and 8 MHz. */ I2S_Callback readCallback; /*!< Pointer to read callback. Cannot be NULL if a read interface is activated. */ I2S_Callback writeCallback; /*!< Pointer to write callback. Cannot be NULL if a write interface is activated. */ I2S_Callback errorCallback; /*!< Pointer to error callback. Cannot be NULL. */ void *custom; /*!< Pointer to device specific custom params */ } I2S_Params; /*! * @brief Default I2S_Params structure * * @sa I2S_Params_init() */ extern const I2S_Params I2S_defaultParams; /*! @brief I2S Global configuration * * The I2S_Config structure contains a set of pointers used to characterize * the I2S driver implementation. * * This structure needs to be defined before calling I2S_init() and it must * not be changed thereafter. * * @sa I2S_init() */ typedef struct I2S_Config_ { /*! Pointer to a driver specific data object */ void *object; /*! Pointer to a driver specific hardware attributes structure */ void const *hwAttrs; } I2S_Config; /*! * @brief Function to close a given I2S peripheral specified by the I2S * handle. * * @pre I2S_open() had to be called first. * * @param [in] handle An I2S_Handle returned from I2S_open * * @sa I2S_open() */ extern void I2S_close(I2S_Handle handle); /*! * @brief Function to initializes the I2S module * * @pre The I2S_config structure must exist and be persistent before this * function can be called. This function must also be called before * any other I2S driver APIs. This function call does not modify any * peripheral registers. */ extern void I2S_init(void); /*! * @brief Function to initialize a given I2S peripheral specified by the * particular index value. The parameter specifies which mode the I2S * will operate. * * @pre I2S controller has been initialized * * @param [inout] index Logical peripheral number for the I2S indexed into * the I2S_config table * * @param [in] params Pointer to an parameter block. * All the fields in this structure are RO (read-only). * Provide a NULL pointer cannot open the module. * * @return An I2S_Handle on success or a NULL on an error or if it has been * opened already. * * @sa I2S_init() * @sa I2S_close() */ extern I2S_Handle I2S_open(uint_least8_t index, I2S_Params *params); /*! * @brief Function to initialize the I2S_Params struct to its defaults * * @param [out] params An pointer to I2S_Params structure for * initialization * * Defaults values are: * @code * params.samplingFrequency = 8000; * params.isMemory24Bits = I2S_MEMORY_LENGTH_16BITS; * params.isMaster = I2S_MASTER; * params.invertWS = (bool)true; * params.isMSBFirst = (bool)true; * params.isDMAUnused = (bool)false; * params.samplingEdge = I2S_SAMPLING_EDGE_RISING; * params.beforeWordPadding = 0; * params.bitsPerWord = 16; * params.afterWordPadding = 0; * params.fixedBufferLength = 1; * params.SD0Use = I2S_SD0_OUTPUT; * params.SD1Use = I2S_SD1_INPUT; * params.SD0Channels = I2S_CHANNELS_STEREO; * params.SD1Channels = I2S_CHANNELS_STEREO; * params.phaseType = I2S_PHASE_TYPE_DUAL; * params.startUpDelay = 0; * params.MCLKDivider = 40; * params.readCallback = NULL; * params.writeCallback = NULL; * params.errorCallback = NULL; * params.custom = NULL; * @endcode * * @param params Parameter structure to initialize */ extern void I2S_Params_init(I2S_Params *params); /*! * @brief Initialize an I2S_Transaction struct to known state. * * The I2S_Transaction struct is put in a known state. The application is * still responsible for populating some of the fields. * For example, the user is responsible to provide the buffer containing the * data and the size of it. * User provided buffer's size must matche with the I2S settings. * If the buffer size is not adapted, the I2S module will truncate it. * Authorized buffer sizes depend on the number of activated outputs, the number * of channels activated, the memory slots length (16 or 24 bits), and the * fixed-buffer-size eventually provided. * Authorized buffer sizes are all the multiple values of the value of * handle->object->memoryStepOut. * * @param [out] transaction Transaction struct to initialize. */ extern void I2S_Transaction_init(I2S_Transaction *transaction); /*! * @brief Function to set the first read-transaction to consider * * At the end of each transaction, I2S driver takes in consideration the next * transaction. Application is responsible to handle the queue. * * @param [in] handle An I2S_Handle. * * @param [in] transaction A pointer to an I2S_Transaction object. The bufPtr * and bufSize fields must be set to a buffer and the * size of the buffer before passing to this function. * * @return void * * @sa I2S_setWriteQueueHead() */ extern void I2S_setReadQueueHead(I2S_Handle handle, I2S_Transaction *transaction); /*! * @brief Function to set the first write-transaction to consider * * At the end of each transaction, I2S driver takes in consideration the next * transaction. Application is responsible to handle the queue. * * @param [in] handle An I2S_Handle. * * @param [in] transaction A pointer to an I2S_Transaction object. The bufPtr * and bufSize fields must be set to a buffer and the * size of the buffer before passing to this function. * * @return void * * @sa I2S_setReadQueueHead() */ extern void I2S_setWriteQueueHead(I2S_Handle handle, I2S_Transaction *transaction); /*! * @brief Start the WS, SCK and MCLK clocks. * * This function enable WS, SCK and MCLK (if activated) clocks. This is required before starting * any reading or a writing transaction. * This function is supposed to be executed both in slave and master mode. * * @param [in] handle An I2S_Handle. * * @return void * * @sa I2S_stopClocks() */ extern void I2S_startClocks(I2S_Handle handle); /*! * @brief Stops the WS, SCK and MCLK clocks. * * This function disable WS, SCK and MCLK clocks. * This function must be executed only if no transaction is in progress. * This function is supposed to be executed both in slave and master mode. * * @param [in] handle An I2S_Handle. * * @return void * * @sa I2S_stopRead() * @sa I2S_stopWrite() */ extern void I2S_stopClocks(I2S_Handle handle); /*! * @brief Start read transactions. * * This function starts reception of the transactions stored in the read-queue. * and returns immediately. At the end of the transaction(s) the readCallback * provided is executed. * Clocks must be running before calling this function. * * @param [in] handle An I2S_Handle. * * @return void * * @sa I2S_stopRead() */ extern void I2S_startRead(I2S_Handle handle); /*! * @brief Start write transactions. * * This function starts transmission of the transactions stored in the write-queue * and returns immediately. At the end of the transaction(s) the writeCallback * provided is executed. * Clocks must be running before calling this function. * * @param [in] handle An I2S_Handle. * * @return void * * @sa I2S_startClocks */ extern void I2S_startWrite(I2S_Handle handle); /*! * @brief Stop read transactions. * * This function stops reception of the transactions stored in the read-queue. * To avoid the apparition of errors, this function blocks while currently * received sample is not completely done. * * @param [in] handle An I2S_Handle. * * @return void */ extern void I2S_stopRead(I2S_Handle handle); /*! * @brief Stop write transactions. * * This function stops transmission of the transactions stored in the write-queue. * To avoid the apparition of errors, this function blocks while currently * transmitted sample is not completely done. * * @param [in] handle An I2S_Handle. * * @return void */ extern void I2S_stopWrite(I2S_Handle handle); #ifdef __cplusplus } #endif #endif /* ti_drivers_I2S__include */