Hi everybody, I new here and I need your experience and assistance. I am trying to emulate I2S by SSI on DK-129x kit and TLV320AIC3107EVM-k. Base on www.ti.com/.../spma042b.pdf
I meet a problem on my code it loop on SoundIntHandle() when playing audio file.
I use SSI2 for I2S chanel 0 and SSI0 for I2c channel 1.
Can you check which problem on my confiure ?
Here is my code configure:
//*****************************************************************************
//
// Definitions of psuedo I2S pins used for the sound driver.
//
//*****************************************************************************
#define I2S_CHAN0_PERIPH (SYSCTL_PERIPH_SSI2)
#define I2S_CHAN0_GPIO (SYSCTL_PERIPH_GPIOD)
#define I2S_CHAN0_CLK (GPIO_PD3_SSI2CLK)
#define I2S_CHAN0_FSS (GPIO_PD2_SSI2FSS)
#define I2S_CHAN0_RX (GPIO_PD0_SSI2XDAT1)
#define I2S_CHAN0_TX (GPIO_PD1_SSI2XDAT0)
#define I2S_CHAN0_PORT (GPIO_PORTD_BASE)
#define I2S_CHAN0_BASE (SSI2_BASE)
#define I2S_CHAN0_UDMA_TX (UDMA_CH13_SSI2TX)
#define I2S_CHAN0_INT (INT_SSI2)
#define I2S_UDMA_PERIPH (SYSCTL_PERIPH_UDMA)
#define I2S_CHAN1_PERIPH (SYSCTL_PERIPH_SSI0)
#define I2S_CHAN1_GPIO (SYSCTL_PERIPH_GPIOA)
#define I2S_CHAN1_CLK (GPIO_PA2_SSI0CLK)
#define I2S_CHAN1_RX (GPIO_PA5_SSI0XDAT1)
#define I2S_CHAN1_TX (GPIO_PA4_SSI0XDAT0)
#define I2S_CHAN1_PORT (GPIO_PORTA_BASE)
#define I2S_CHAN1_BASE (SSI0_BASE)
#define I2S_CHAN1_UDMA_TX (UDMA_CH11_SSI0TX)
#define I2S_CHAN1_INT (INT_SSI0)
#define I2S_CHAN1_FSS_GPIO_BASE (GPIO_PORTE_BASE)
#define I2S_CHAN1_FSS (GPIO_PIN_0)
#define I2S_MASTERCLK_PERIPH (SYSCTL_PERIPH_TIMER5)
#define I2S_MASTERCLK_GPIO (SYSCTL_PERIPH_GPIOM)
#define I2S_MASTERCLK_PORT (GPIO_PM7_T5CCP1)
#define I2S_MASTERCLK_BASE (GPIO_PORTM_BASE)
#define I2S_MASTERCLK_PIN (GPIO_PIN_7)
#define I2S_MASTERCLK_TMR (TIMER_B)
#define I2S_MASTERCLK_TMR_B (TIMER5_BASE)
//*****************************************************************************
//
//! Initialize the sound driver.
//!
//! This function initializes the hardware components of the LM4F board,
//! necessary for audio playback.
//!
//! \return None.
//
//*****************************************************************************
void
SoundInit(void)
{
//
// Set the current active buffer to zero.
//
g_ulPlaying = 0;
//
// Initialize the DAC.
//
DACInit();
//
// Enable and reset the necessary peripherals.
//
SysCtlPeripheralEnable(I2S_CHAN1_PERIPH);
SysCtlPeripheralEnable(I2S_CHAN0_PERIPH);
SysCtlPeripheralEnable(I2S_CHAN1_FSS_GPIO_BASE);
SysCtlPeripheralEnable(I2S_UDMA_PERIPH);
SysCtlPeripheralEnable(I2S_CHAN0_GPIO);
SysCtlPeripheralEnable(I2S_CHAN1_GPIO);
SysCtlPeripheralReset(I2S_CHAN0_GPIO);
SysCtlPeripheralReset(I2S_CHAN1_GPIO);
//
// Set up Timer to periodically call WavePlayContinue().
// Timer is enabled when playback is started.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER2);
TimerConfigure(TIMER2_BASE, TIMER_CFG_PERIODIC);
//
// Set up the pin mux for both SSI ports.
//
GPIOPinConfigure(I2S_CHAN1_CLK);
GPIOPinConfigure(I2S_CHAN1_FSS);
GPIOPinConfigure(I2S_CHAN1_RX);
GPIOPinConfigure(I2S_CHAN1_TX);
GPIOPinConfigure(I2S_CHAN0_RX);
GPIOPinConfigure(I2S_CHAN0_TX);
GPIOPinConfigure(I2S_CHAN0_CLK);
GPIOPinConfigure(I2S_CHAN0_FSS);
GPIOPinTypeGPIOOutput(I2S_CHAN1_FSS_GPIO_BASE, I2S_CHAN1_FSS);
//
// Select alternate functions for all of the SSI pins.
//
GPIOPinTypeSSI(I2S_CHAN0_PORT,
I2S_MASTERCLK_PIN|GPIO_PIN_2|GPIO_PIN_1|GPIO_PIN_0);
GPIOPinTypeSSI(I2S_CHAN1_PORT,
I2S_MASTERCLK_PIN|GPIO_PIN_2|GPIO_PIN_4|GPIO_PIN_5);
//
// Set up the DMA.
//
ROM_uDMAControlBaseSet(&sDMAControlTable[0]);
ROM_uDMAEnable();
//
// Configure the SSI clock (CCP timer).
//
setupCCP();
//
// Clear out all pending interrupts.
// SSI_TXFF: TX FIFO half full or less
//
SSIIntClear(I2S_CHAN0_BASE, SSI_TXFF );
SSIIntClear(I2S_CHAN1_BASE, SSI_TXFF );
//
// Enables individual SSI interrupt source.
// We'll use SSI1's empty interrupt status to drive the FIFO transfers
// for both SSI1 and SSI3. This interrupt occurs whenever the TX FIFO
// is half full or less.
//
SSIIntEnable(I2S_CHAN0_BASE, SSI_TXFF);
//SSIIntEnable(I2S_CHAN1_BASE, SSI_TXFF);
//
// Disable all uDMA attributes.
//
uDMAChannelAttributeDisable(I2S_CHAN0_UDMA_TX, UDMA_ATTR_ALL);
uDMAChannelAttributeDisable(I2S_CHAN1_UDMA_TX, UDMA_ATTR_ALL);
//
// Configure the synchronous serial interfaces, SSI1 and SSI3.
// Clock each at the system clock rate of 50MHz.
// Use the Motorola Mode 2 protocol.
// As the DAC is the master, set the SSI as a slave device.
// Set the bit rate to 1M.
// Set the width of the data transfers to the maximum : 16bits.
//
SSIConfigSetExpClk(I2S_CHAN0_BASE, g_ui32SysClock, SSI_FRF_MOTO_MODE_2,
SSI_MODE_SLAVE, 1000000, 16);
SSIConfigSetExpClk(I2S_CHAN1_BASE, g_ui32SysClock, SSI_FRF_MOTO_MODE_2,
SSI_MODE_SLAVE, 1000000, 16);
//
// Enable the SSI controller.
//
SSIEnable(I2S_CHAN0_BASE);
SSIEnable(I2S_CHAN1_BASE);
//
// Enable SSI DMA transmit operation.
//
SSIDMAEnable(I2S_CHAN0_BASE, SSI_DMA_TX);
SSIDMAEnable(I2S_CHAN1_BASE, SSI_DMA_TX);
}
//*****************************************************************************
//
// Interrupt handler for the SSI sound driver.
//
// This interrupt function is called by the processor due to an interrupt from
// the SSI peripheral. uDMA is used in ping-pong mode to keep sound buffer
// data flowing to the dual-SSI audio output. As each buffer transfer is
// complete, the client callback function that was specified in the call
// to SoundBufferPlay() will be called. The client can then take action
// to start the next buffer playing.
//
// This function is called by the interrupt system and should not be
// called directly from application code.
//
//*****************************************************************************
void
SoundIntHandler(void)
{
unsigned long ulStatus;
unsigned long *pulTemp;
//
// Get the interrupt status and clear any pending interrupts.
//
ulStatus = SSIIntStatus(I2S_CHAN0_BASE, 1);
SSIIntClear(I2S_CHAN0_BASE, ulStatus);
//
// Handle the TX channel interrupt
//
if(HWREGBITW(&g_ulDMAFlags, FLAG_TX_PENDING))
{
//
// If the TX DMA is done, then call the callback if present.
//
if(ROM_uDMAChannelModeGet(I2S_CHAN0_UDMA_TX | UDMA_PRI_SELECT) ==
UDMA_MODE_STOP)
{
//
// Save a temp pointer so that the current pointer can be set to
// zero before calling the callback.
//
pulTemp = g_sOutBuffers[0].pulData;
//
// If at the mid point then refill the first half of the buffer.
//
if((g_sOutBuffers[0].pfnBufferCallback) &&
(g_sOutBuffers[0].pulData != 0))
{
g_sOutBuffers[0].pulData = 0;
g_sOutBuffers[0].pfnBufferCallback(pulTemp, BUFFER_EVENT_FREE);
}
}
//
// If the TX DMA is done, then call the callback if present.
//
if(ROM_uDMAChannelModeGet(I2S_CHAN0_UDMA_TX | UDMA_ALT_SELECT) ==
UDMA_MODE_STOP)
{
//
// Save a temporary pointer so that the current pointer can be set
// to zero before calling the callback.
//
pulTemp = g_sOutBuffers[1].pulData;
//
// If at the mid point then refill the first half of the buffer.
//
if((g_sOutBuffers[1].pfnBufferCallback) &&
(g_sOutBuffers[1].pulData != 0))
{
g_sOutBuffers[1].pulData = 0;
g_sOutBuffers[1].pfnBufferCallback(pulTemp, BUFFER_EVENT_FREE);
}
}
//
// If no more buffers are pending then clear the flag.
//
if((g_sOutBuffers[0].pulData == 0) && (g_sOutBuffers[1].pulData == 0))
{
HWREGBITW(&g_ulDMAFlags, FLAG_TX_PENDING) = 0;
}
}
}