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; } } }