knx/source/ti/drivers/I2S.h
Nanosonde e51b65f8c2 Squashed 'examples/knx-cc1310/coresdk_cc13xx_cc26xx/' content from commit 0d78d32
git-subtree-dir: examples/knx-cc1310/coresdk_cc13xx_cc26xx
git-subtree-split: 0d78d3280357416a5c0388148cda13717c9ffaa5
2020-10-21 10:00:49 +02:00

1189 lines
46 KiB
C

/*
* 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 <ti/drivers/I2S.h>
* @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 <b>Serial Clock (SCK)</b> also called Bit Clock (BCLK) or Multichannel
* Audio Frame Synchronization (McAFSX)
* @li <b>Word Select (WS)</b> also called Word Clock (WCLK), Left Right
* Clock (LRCLK) or Multichannel Audio Clock (McACLK)
* @li <b>Serial Data (SD0)</b> also called AD0, AD1, McAXR0, or possibly SDI
* @li <b>Serial Data (SD1)</b> also called AD1, ADI, McAXR1, or possibly SDI
* @li <b>Master Clock (MCLK)</b>
*
* <hr>
* @anchor ti_drivers_I2S_Usage
* # Usage #
*
* <b>The I2S driver provides the following APIs:</b>
* @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
*
* <hr>
* @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.
*
* <hr>
* @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.
*
* <hr>
* @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.
*
* <hr>
* @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"
*
* <hr>
* @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.
*
* <hr>
* @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.
*
* <hr>
* @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)
*
* <hr>
* @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<bufLength; k++) {buf[k] --;}
* for(k=0; k<bufLength; k++) {buf[k] ++;}
* }
* }
* }
*
* void *echoExampleThread(void *arg0)
* {
* I2S_Params i2sParams;
*
* I2S_init();
*
* // Initialize the treatmentList (this list is initially empty)
* List_clearList(&treatmentList);
*
* //Initialize I2S opening parameters
* I2S_Params_init(&i2sParams);
* i2sParams.fixedBufferLength = 1000;
* 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);
* I2S_Transaction_init(&i2sRead4);
* i2sRead1.bufPtr = readBuf1;
* i2sRead2.bufPtr = readBuf2;
* i2sRead3.bufPtr = readBuf3;
* i2sRead4.bufPtr = readBuf4;
* i2sRead1.bufSize = sizeof(readBuf1);
* i2sRead2.bufSize = sizeof(readBuf2);
* i2sRead3.bufSize = sizeof(readBuf3);
* i2sRead4.bufSize = sizeof(readBuf4);
* List_clearList(&i2sReadList);
* List_put(&i2sReadList, (List_Elem*)&i2sRead1);
* List_put(&i2sReadList, (List_Elem*)&i2sRead2);
* List_put(&i2sReadList, (List_Elem*)&i2sRead3);
* List_put(&i2sReadList, (List_Elem*)&i2sRead4);
*
* I2S_setReadQueueHead(i2sHandle, &i2sRead1);
*
* // Initialize the write-transactions
* I2S_Transaction_init(&i2sWrite1);
* I2S_Transaction_init(&i2sWrite2);
* I2S_Transaction_init(&i2sWrite3);
* I2S_Transaction_init(&i2sWrite4);
* i2sWrite1.bufPtr = writeBuf1;
* i2sWrite2.bufPtr = writeBuf2;
* i2sWrite3.bufPtr = writeBuf3;
* i2sWrite4.bufPtr = writeBuf4;
* i2sWrite1.bufSize = sizeof(writeBuf1);
* i2sWrite2.bufSize = sizeof(writeBuf2);
* i2sWrite3.bufSize = sizeof(writeBuf3);
* i2sWrite4.bufSize = sizeof(writeBuf4);
* List_clearList(&i2sWriteList);
* List_put(&i2sWriteList, (List_Elem*)&i2sWrite1);
* List_put(&i2sWriteList, (List_Elem*)&i2sWrite2);
* List_put(&i2sWriteList, (List_Elem*)&i2sWrite3);
* List_put(&i2sWriteList, (List_Elem*)&i2sWrite4);
*
* I2S_setWriteQueueHead(i2sHandle, &i2sWrite1);
*
* I2S_startClocks(i2sHandle);
* I2S_startWrite(i2sHandle);
* I2S_startRead(i2sHandle);
*
* while(1);
* }
* @endcode
*
* <hr>
* @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.
*
* <hr>
* @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.
*
* <hr>
* @anchor ti_drivers_I2S_Configuration
* # Configuration
*
* Refer to the @ref driver_configuration "Driver's Configuration" section
* for driver configuration information.
* <hr>
******************************************************************************
*/
#ifndef ti_drivers_I2S__include
#define ti_drivers_I2S__include
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include <ti/drivers/utils/List.h>
#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 */