AnsweredAssumed Answered

Why doesn't my I2S controller transmit data?

Question asked by Don Turner on Sep 14, 2016
Latest reply on Sep 18, 2016 by xiangjun.rong

I'm trying to output sound using a K22F microcontroller connected to an SGTL5000 audio codec. I have been able to configure all the required clocks (TX_FS, TX_BCLK and MCLK) but am unable to produce any data on the I2S0_TXD0 pin of the K22F. I'm using version 2.0 of the Kinetis SDK.


Here's my setup code for the I2S/SAI controller:


// Initialise the SAI/I2S module
g_sai_tx_config.protocol = kSAI_BusI2S;
g_sai_tx_config.syncMode = kSAI_ModeAsync; // Since the MCU is providing MCLK
g_sai_tx_config.mclkOutputEnable = true;
g_sai_tx_config.mclkSource = kSAI_MclkSourceSysclk;
g_sai_tx_config.bclkSource = kSAI_BclkSourceMclkDiv;
g_sai_tx_config.masterSlave = kSAI_Master;

SAI_TxInit(I2S0, &g_sai_tx_config);


// Set the format of the data
g_sai_tx_format.bitWidth = kSAI_WordWidth16bits; = 0; // Taken from Kinetis Serial Audio Training P17
g_sai_tx_format.sampleRate_Hz = kSAI_SampleRate48KHz;
g_sai_tx_format.masterClockHz = 256 * kSAI_SampleRate48KHz; //12.288MHz
g_sai_tx_format.stereo = kSAI_Stereo;
g_sai_tx_format.protocol = kSAI_BusI2S;
g_sai_tx_format.watermark = 4;


SAI_TxSetFormat(I2S0, &g_sai_tx_format, CLOCK_GetCoreSysClkFreq(), g_sai_tx_format.masterClockHz);

SAI_TxEnable(I2S0, true);


And here's my attempt to output some audio data (a 1kHz square wave)


#define I2S_BUFFER_SIZE 96
uint8_t buffer[I2S_BUFFER_SIZE];
int8_t amplitude = 1;

I2S0->TCSR |= I2S_TCSR_FEF_MASK; // Write 1 to clear transmit underrun flag


for(;;) { /* Infinite loop to avoid leaving the main function */

    // Transmit a square wave - alternately send a full buffer of 0xFF then 0x00
    for (int i = 0; i < I2S_BUFFER_SIZE; i++){
        buffer[i] = (0xFF * amplitude);

    amplitude ^= 1;

    SAI_WriteBlocking(I2S0, 0, kSAI_WordWidth16bits, buffer, I2S_BUFFER_SIZE);


The problem is that I don't see any data being generated on the TX pin, pausing execution I can see the code is caught in this loop in the SAI_WriteBlocking method:


/* Wait until it can write data */
while (!(base->TCSR & I2S_TCSR_FWF_MASK))


This implies (and I have verified) that the I2S0->TCSR->FWF register (FIFO warning flag) is 0 which means "No enabled transmit FIFO is empty.". Why isn't the transmit FIFO being sent (and emptied) by the I2S controller?


It may also be relevant that when I pause execution I can see that the I2S0->TCSR->FEF (FIFO error flag) register is 1 indicating "Transmit underrun detected.". What could be causing the underrun? I've tried clearing this flag but as soon as I queue data again it is immediately set to 1 again.


Any help greatly appreciated.