blob: dea61bb318af36b5e0c2b1cb24970e3488ccb6d2 [file] [log] [blame]
/******************************************************************************
* Filename: i2s.c
* Revised: 2015-05-11 13:56:01 +0200 (Mon, 11 May 2015)
* Revision: 43476
*
* Description: Driver for the I2S.
*
* Copyright (c) 2015 - 2016, 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:
*
* 1) Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2) 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.
*
* 3) Neither the name of the ORGANIZATION 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 HOLDER 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.
*
******************************************************************************/
#include <driverlib/i2s.h>
//*****************************************************************************
//
// Handle support for DriverLib in ROM:
// This section will undo prototype renaming made in the header file
//
//*****************************************************************************
#if !defined(DOXYGEN)
#undef I2SEnable
#define I2SEnable NOROM_I2SEnable
#undef I2SAudioFormatConfigure
#define I2SAudioFormatConfigure NOROM_I2SAudioFormatConfigure
#undef I2SChannelConfigure
#define I2SChannelConfigure NOROM_I2SChannelConfigure
#undef I2SBufferConfig
#define I2SBufferConfig NOROM_I2SBufferConfig
#undef I2SPointerUpdate
#define I2SPointerUpdate NOROM_I2SPointerUpdate
#undef I2SPointerSet
#define I2SPointerSet NOROM_I2SPointerSet
#undef I2SSampleStampConfigure
#define I2SSampleStampConfigure NOROM_I2SSampleStampConfigure
#undef I2SSampleStampGet
#define I2SSampleStampGet NOROM_I2SSampleStampGet
#endif
//*****************************************************************************
//
// Global pointer to the current I2S data structure
//
//*****************************************************************************
I2SControlTable *g_pControlTable;
//*****************************************************************************
//
//! Enables the I2S module for operation
//
//*****************************************************************************
void
I2SEnable(uint32_t ui32Base)
{
//
// Check the arguments.
//
ASSERT(I2SBaseValid(ui32Base));
(void)ui32Base;
//
// Make sure the control table pointer is setup to a memory location.
//
if(!(g_pControlTable))
{
return;
}
//
// Write the address to the first input/output buffer.
//
HWREG(I2S0_BASE + I2S_O_AIFINPTRNEXT) = g_pControlTable->ui32InBase;
g_pControlTable->ui32InOffset = 0;
HWREG(I2S0_BASE + I2S_O_AIFOUTPTRNEXT) = g_pControlTable->ui32OutBase;
g_pControlTable->ui32OutOffset = 0;
//
// Enable the I2S module.
//
HWREG(I2S0_BASE + I2S_O_AIFDMACFG) = (uint32_t)g_pControlTable->ui16DMABufSize - 1;
}
//*****************************************************************************
//
//! Configures the I2S module
//
//*****************************************************************************
void
I2SAudioFormatConfigure(uint32_t ui32Base, uint32_t ui32FmtCfg,
uint32_t ui32BitClkDelay)
{
//
// Check the arguments.
//
ASSERT(I2SBaseValid(ui32Base));
(void)ui32Base;
ASSERT(ui32BitClkDelay <= 255);
//
// Save the length of the audio words stored in memory.
//
g_pControlTable->ui16MemLen = (ui32FmtCfg & I2S_MEM_LENGTH_24) ? 24 : 16;
//
// Write the configuration.
//
HWREG(I2S0_BASE + I2S_O_AIFFMTCFG) = ui32FmtCfg | (ui32BitClkDelay << I2S_AIFFMTCFG_DATA_DELAY_S);
}
//****************************************************************************
//
//! Setup the audio channel configuration
//
//****************************************************************************
void
I2SChannelConfigure(uint32_t ui32Base, uint32_t ui32Chan0Cfg,
uint32_t ui32Chan1Cfg, uint32_t ui32Chan2Cfg)
{
uint32_t ui32InChan;
uint32_t ui32OutChan;
uint32_t ui32ChanMask;
//
// Check the arguments.
//
ASSERT(I2SBaseValid(ui32Base));
(void)ui32Base;
ASSERT(ui32Chan0Cfg & (I2S_CHAN_CFG_MASK | I2S_LINE_MASK))
ASSERT(ui32Chan1Cfg & (I2S_CHAN_CFG_MASK | I2S_LINE_MASK))
ASSERT(ui32Chan2Cfg & (I2S_CHAN_CFG_MASK | I2S_LINE_MASK))
ui32InChan = 0;
ui32OutChan = 0;
//
// Configure input/output channels.
//
HWREG(I2S0_BASE + I2S_O_AIFDIRCFG) = ((ui32Chan0Cfg << I2S_AIFDIRCFG_AD0_S)
& I2S_AIFDIRCFG_AD0_M) |
((ui32Chan1Cfg << I2S_AIFDIRCFG_AD1_S)
& I2S_AIFDIRCFG_AD1_M) |
((ui32Chan2Cfg << I2S_AIFDIRCFG_AD2_S)
& I2S_AIFDIRCFG_AD2_M);
//
// Configure the valid channel mask.
//
HWREG(I2S0_BASE + I2S_O_AIFWMASK0) = (ui32Chan0Cfg >> 8) & I2S_AIFWMASK0_MASK_M;
HWREG(I2S0_BASE + I2S_O_AIFWMASK1) = (ui32Chan1Cfg >> 8) & I2S_AIFWMASK1_MASK_M;
HWREG(I2S0_BASE + I2S_O_AIFWMASK2) = (ui32Chan2Cfg >> 8) & I2S_AIFWMASK2_MASK_M;
//
// Resolve and save the number of input and output channels.
//
ui32ChanMask = (ui32Chan0Cfg & I2S_CHAN_CFG_MASK) >> 8;
if(ui32Chan0Cfg & I2S_LINE_INPUT)
{
while(ui32ChanMask)
{
if(ui32ChanMask & 0x1)
{
ui32InChan++;
}
//
// Shift down channel mask
//
ui32ChanMask >>= 1;
}
}
else if(ui32Chan0Cfg & I2S_LINE_OUTPUT)
{
while(ui32ChanMask)
{
if(ui32ChanMask & 0x1)
{
ui32OutChan++;
}
//
// Shift down channel mask
//
ui32ChanMask >>= 1;
}
}
ui32ChanMask = (ui32Chan1Cfg & I2S_CHAN_CFG_MASK) >> 8;
if(ui32Chan1Cfg & I2S_LINE_INPUT)
{
while(ui32ChanMask)
{
if(ui32ChanMask & 0x1)
{
ui32InChan++;
}
//
// Shift down channel mask
//
ui32ChanMask >>= 1;
}
}
else if(ui32Chan1Cfg & I2S_LINE_OUTPUT)
{
while(ui32ChanMask)
{
if(ui32ChanMask & 0x1)
{
ui32OutChan++;
}
//
// Shift down channel mask
//
ui32ChanMask >>= 1;
}
}
ui32ChanMask = (ui32Chan2Cfg & I2S_CHAN_CFG_MASK) >> 8;
if(ui32Chan2Cfg & I2S_LINE_INPUT)
{
while(ui32ChanMask)
{
if(ui32ChanMask & 0x1)
{
ui32InChan++;
}
//
// Shift down channel mask
//
ui32ChanMask >>= 1;
}
}
else if(ui32Chan2Cfg & I2S_LINE_OUTPUT)
{
while(ui32ChanMask)
{
if(ui32ChanMask & 0x1)
{
ui32OutChan++;
}
//
// Shift down channel mask
//
ui32ChanMask >>= 1;
}
}
g_pControlTable->ui8InChan = (uint8_t)ui32InChan;
g_pControlTable->ui8OutChan = (uint8_t)ui32OutChan;
}
//****************************************************************************
//
//! Set the input buffer pointers
//
//****************************************************************************
void
I2SBufferConfig(uint32_t ui32Base, uint32_t ui32InBufBase,
uint32_t ui32OutBufBase, uint16_t ui16DMABufSize,
uint16_t ui16ChanBufSize)
{
//
// Check the arguments.
//
ASSERT(I2SBaseValid(ui32Base));
(void)ui32Base;
ASSERT(ui16DMABufSize > 0);
//
// Setup the input data pointer and buffer sizes.
//
g_pControlTable->ui16DMABufSize = ui16DMABufSize;
g_pControlTable->ui16ChBufSize = ui16ChanBufSize;
g_pControlTable->ui32InBase = ui32InBufBase;
g_pControlTable->ui32OutBase = ui32OutBufBase;
}
//****************************************************************************
//
//! Set the buffer pointers
//
//****************************************************************************
void
I2SPointerSet(uint32_t ui32Base, bool bInput, void * pNextPointer)
{
//
// Check the arguments.
//
ASSERT(I2SBaseValid(ui32Base));
(void)ui32Base;
//
// Update the next input/output pointer with the correct address.
//
if(bInput == true)
{
HWREG(I2S0_BASE + I2S_O_AIFINPTRNEXT) = (uint32_t)pNextPointer;
}
else
{
HWREG(I2S0_BASE + I2S_O_AIFOUTPTRNEXT) = (uint32_t)pNextPointer;
}
}
//****************************************************************************
//
//! Update the buffer pointers
//
//****************************************************************************
void
I2SPointerUpdate(uint32_t ui32Base, bool bInput)
{
uint32_t ui32NextPtr;
//
// Check the arguments.
//
ASSERT(I2SBaseValid(ui32Base));
(void)ui32Base;
//
// Update the next input/output pointer with the correct address.
//
if(bInput == true)
{
ui32NextPtr = (g_pControlTable->ui8InChan *
(g_pControlTable->ui16MemLen >> 3)) *
g_pControlTable->ui16DMABufSize;
g_pControlTable->ui32InOffset = ((g_pControlTable->ui32InOffset +
ui32NextPtr) %
g_pControlTable->ui16ChBufSize);
HWREG(I2S0_BASE + I2S_O_AIFINPTRNEXT) = g_pControlTable->ui32InOffset +
g_pControlTable->ui32InBase;
}
else
{
ui32NextPtr = (g_pControlTable->ui8OutChan *
(g_pControlTable->ui16MemLen >> 3)) *
g_pControlTable->ui16DMABufSize;
g_pControlTable->ui32OutOffset = ((g_pControlTable->ui32OutOffset +
ui32NextPtr) %
g_pControlTable->ui16ChBufSize);
HWREG(I2S0_BASE + I2S_O_AIFOUTPTRNEXT) =
g_pControlTable->ui32OutOffset +
g_pControlTable->ui32OutBase;
}
}
//*****************************************************************************
//
//! Configure the sample stamp generator
//
//*****************************************************************************
void
I2SSampleStampConfigure(uint32_t ui32Base, bool bInput, bool bOutput)
{
uint32_t ui32Trigger;
//
// Check the arguments.
//
ASSERT(I2SBaseValid(ui32Base));
(void)ui32Base;
ui32Trigger = HWREG(I2S0_BASE + I2S_O_STMPWCNT);
ui32Trigger = (ui32Trigger + 2) % g_pControlTable->ui16ChBufSize;
//
// Setup the sample stamp trigger for input streams.
//
if(bInput)
{
HWREG(I2S0_BASE + I2S_O_STMPINTRIG) = ui32Trigger;
}
//
// Setup the sample stamp trigger for output streams.
//
if(bOutput)
{
HWREG(I2S0_BASE + I2S_O_STMPOUTTRIG) = ui32Trigger;
}
}
//*****************************************************************************
//
//! Get the current value of a sample stamp counter
//
//*****************************************************************************
uint32_t
I2SSampleStampGet(uint32_t ui32Base, uint32_t ui32Channel)
{
uint32_t ui32FrameClkCnt;
uint32_t ui32SysClkCnt;
uint32_t ui32PeriodSysClkCnt;
uint32_t ui32SampleStamp;
(void)ui32Base;
(void)ui32Channel;
//
// Get the number of Frame clock counts since last stamp.
//
ui32FrameClkCnt = HWREG(I2S0_BASE + I2S_O_STMPWCNTCAPT0);
//
// Get the number of system clock ticks since last frame clock edge.
//
ui32SysClkCnt = HWREG(I2S0_BASE + I2S_O_STMPXCNTCAPT0);
//
// Get the number system clock ticks in the last frame clock period.
//
ui32PeriodSysClkCnt = HWREG(I2S0_BASE + I2S_O_STMPXPER);
//
// Calculate the sample stamp.
//
ui32SampleStamp = (ui32SysClkCnt << 16) / ui32PeriodSysClkCnt;
ui32SampleStamp = (ui32SampleStamp > I2S_STMP_SATURATION) ?
I2S_STMP_SATURATION : ui32SampleStamp;
ui32SampleStamp |= (ui32FrameClkCnt << 16);
return (ui32SampleStamp);
}