SC589: SPORT TDM implementation using API functions

Hi!

I'm trying to implement a SPORT TDM (using DMA) connection between the SC589-MINI board and an ADAU1787 using the ADAU API functions. 

However, TDM mode is not working. The configuration code is attached below.

In the below images i tried to investigate the DAI1 Pins (where i routed the I²S clocks and data signals to) using a logic analyser.

It seems like the synchronisation doesn't work and completely random data is being generated by the ADSP (i can hear it as scratching noise when connectiong a headphone to the input SPORT of the ADAU).

Has anyone an idea why this does not work?

Cheers,

Blofeld

This is a snapshot of the data being sent by the ADAU1787 (FSYNC and MCLK are generated by the ADSP)

This is a snapshot of the data being sent by the ADAU1787 (FSYNC and MCLK are generated by the ADSP) (RX)

This is a snapshot of the data generated by the ADSP configured as mentioned above.

This is a snapshot of the data generated by the ADSP which is configured as mentioned above. (TX)

    // main

    NUM_TX_CHANNELS (4)
    BUFFER_SIZE (160)
int main(int argc, char *argv[])
{    
    uint32_t rxBuffer1[BUFFER_SIZE * NUM_RX_CHANNELS] = {0};
    uint32_t rxBuffer2[BUFFER_SIZE * NUM_RX_CHANNELS] = {0};
    
    uint32_t txBuffer1[BUFFER_SIZE * NUM_TX_CHANNELS] = {0};
    uint32_t txBuffer2[BUFFER_SIZE * NUM_TX_CHANNELS] = {0};
    
    static uint8_t sportRxMemory[ADI_SPORT_DMA_MEMORY_SIZE];
    static uint8_t sportTxMemory[ADI_SPORT_DMA_MEMORY_SIZE];
    
    ADI_SPORT_RESULT result;
    ADI_SPORT_DEVICE *txDevice;
    ADI_SPORT_DEVICE *rxDevice;
    
    // enable corresponding SPUs (74 for receive channel (Sport 4a)), (74 for transmit channel (Sport 5a))
    if (adi_spu_EnableMasterSecure(spuHandle, 74u, true) != ADI_SPU_SUCCESS) {
        printf("Failed to enable Master secure for SPORT 4A\n");
        return ADI_SPU_FAILURE;
    }
    
    if (adi_spu_EnableMasterSecure(spuHandle, 76u , true) != ADI_SPU_SUCCESS) {
        printf("Failed to enable Master secure for SPORT 5A DMA\n");
        return ADI_SPU_FAILURE;
    }
    
    // setup for tx device
    result = adi_sport_Close(txDevice);
    CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_Close()");

    result = adi_sport_Open(5, 0, ADI_SPORT_DIR_TX, ADAU1787_SPORT_TDM4_MODE, sportTxMemory, ADI_SPORT_DMA_MEMORY_SIZE, txDevice);
    CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_Open()");

    fsDivisor = 4 * 32 - 1;
    clockRatio = (112500 / ((fsDivisor+1) * 48)) - 1;

    result = adi_sport_ConfigClock(*txDevice, clockRatio, true, false, false);
    CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_ConfigClock()");

    result = adi_sport_ConfigFrameSync(*txDevice, fsDivisor, true, true, true, false, false, false);
    CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_ConfigFrameSync()");

    if (mode == ADI_SPORT_MC_MODE) {
			// Configure multi channel operation
			result = adi_sport_ConfigMC(*txDevice, 0u, 3u, 0u, false);
			CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_ConfigMC()");
			result = adi_sport_SelectChannel(*txDevice,0u,3u);
			CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_SelectChannel()");
	}
    result = adi_sport_EnableDMAMode(*txDevice, true);
    CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_EnableDMAMode()");


    result = adi_sport_ConfigData(*txDevice, ADI_SPORT_DTYPE_ZERO_FILL, 23u, false, false, false);
	CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_ConfigData()");


    if (adi_pdma_EnableBufferRepeat(txDevice->hDMAChnl, true) != ADI_DMA_SUCCESS) {
        printf("Failed to execute adi_pdma_EnableBufferRepeat().\n");
    }
    
    // setup for rx device
    result = adi_sport_Close(rxDevice);
    CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_Close()");

    result = adi_sport_Open(4, 0, ADI_SPORT_DIR_RX, ADAU1787_SPORT_TDM4_MODE, sportRxMemory, ADI_SPORT_DMA_MEMORY_SIZE, rxDevice);
    CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_Open()");

    fsDivisor = 4 * 32 - 1;
    clockRatio = (112500 / ((fsDivisor+1) * 48)) - 1;

    result = adi_sport_ConfigClock(*rxDevice, clockRatio, true, false, false);
    CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_ConfigClock()");

    result = adi_sport_ConfigFrameSync(*rxDevice, fsDivisor, true, true, true, false, false, false);
    CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_ConfigFrameSync()");

    if (mode == ADI_SPORT_MC_MODE) {
			// Configure multi channel operation
			result = adi_sport_ConfigMC(*rxDevice, 0u, 3u, 0u, false);
			CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_ConfigMC()");
			result = adi_sport_SelectChannel(*rxDevice,0u,3u);
			CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_SelectChannel()");
	}
    result = adi_sport_EnableDMAMode(*rxDevice, true);
    CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_EnableDMAMode()");


    result = adi_sport_ConfigData(*rxDevice, ADI_SPORT_DTYPE_ZERO_FILL, 23u, false, false, false);
	CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_ConfigData()");


    if (adi_pdma_EnableBufferRepeat(rxDevice->hDMAChnl, true) != ADI_DMA_SUCCESS) {
        printf("Failed to execute adi_pdma_EnableBufferRepeat().\n");
    }
    
    result = adi_sport_RegisterCallback(txDevice, &tx_callback, NULL);
    CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_RegisterCallback()");
    result = adi_sport_RegisterCallback(rxDevice, &rx_callback, NULL);
    CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_RegisterCallback()");
    
    
    result = adi_sport_SubmitBuffer(txDevice, txBuffer1, sizeof(txBuffer1));
    CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_SubmitBuffer()");
    result = adi_sport_SubmitBuffer(txDevice, txBuffer2, sizeof(txBuffer2));
    CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_SubmitBuffer()");
    
    
    result = adi_sport_SubmitBuffer(rxDevice, rxBuffer1, sizeof(rxBuffer1));
    CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_SubmitBuffer()");
    result = adi_sport_SubmitBuffer(rxDevice, rxBuffer2, sizeof(rxBuffer2));
    CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_SubmitBuffer()");
    
    
    result = adi_sport_Enable(txDevice, true);
    CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_Enable()");
    
    result = adi_sport_Enable(rxDevice, true);
    CHECK_SPORT_RESULT(result, "Failed to execute: adi_sport_Enable()");
    
    while (true) {
        process_buffers(txDevice,rxDevice);
    }
}
void process_buffers(ADI_SPORT_HANDLE txDevice,ADI_SPORT_HANDLE rxDevice)
{
    if ((rxBufferToProcess != NULL || rxDevice == NULL) &&(txBufferToProcess != NULL||txBufferToProcess == NULL))
    {
        enum ErrorType error;
        float32_t txData[NUM_TX_CHANNELS][BUFFER_SIZE];
        float32_t rxData[NUM_TX_CHANNELS][BUFFER_SIZE];
        void *txBufferTemp,*rxBufferTemp;

        txBufferTemp          = (void *) txBufferToProcess;
        rxBufferTemp          = (void *) rxBufferToProcess;

        rxBufferToProcess          = NULL;
        txBufferToProcess          = NULL;

        sport_deinterleave(rxBufferTemp, NUM_RX_CHANNELS, BUFFER_SIZE, rxData);

         for (int sample = 0; sample < BUFFER_SIZE; sample++) {
//TDM 4 hearthrough
        txData[0][sample] = rxData[0][sample]; 
        txData[1][sample] = rxData[1][sample]; 

        txData[2][sample] = rxData[2][sample]; 
        txData[3][sample] = rxData[3][sample]; 
        }

        sport_interleave(txBufferTemp, NUM_TX_CHANNELS, BUFFER_SIZE, txData);
    }
}
void sport_deinterleave(const uint32_t *const inputBuffer,
                        const size_t outputBufferChannels,
                        const size_t outputBufferSize,
						float32_t outputBuffers[outputBufferChannels][outputBufferSize])
{
    uint32_t i, channel;

        for (i = 0; i < outputBufferSize; i++) {
            for (channel = 0; channel < outputBufferChannels; channel++) {
                outputBuffers[channel][i] = uint24_to_float(inputBuffer[i * outputBufferChannels + channel]);
            }
        }
    
}
void sport_interleave(uint32_t *const outputBuffer,
                      const size_t inputBufferChannels,
                      const size_t inputBufferSize,
                      float32_t inputBuffers[inputBufferChannels][inputBufferSize])
{
    uint32_t i, channel;

    for (i = 0; i < inputBufferSize; i++) {
        for (channel = 0; channel < inputBufferChannels; channel++) {
            outputBuffer[i * inputBufferChannels + channel] = float_to_uint24(inputBuffers[channel][i]);
        }
    }
}
// SRU routing
    /**
     * SPORT 4A (RX from ADAU1787)
     */

    SRU2(SPT5_ACLK_O, SPT4_ACLK_I);
    SRU2(SPT5_AFS_O, SPT4_AFS_I);
    SRU2(DAI1_PB01_O, SPT4_AD0_I);


    /**
     * SPORT 5A (TX to ADAU1787)
     */

    SRU2(SPT5_AD0_O, DAI1_PB02_I);
    SRU2(SPT5_AD0_PBEN_O, DAI1_PBEN02_I);

    SRU2(SPT5_ACLK_O, DAI1_PB03_I);
    SRU2(HIGH, DAI1_PBEN03_I);

    SRU2(SPT5_AFS_O, DAI1_PB04_I);
    SRU2(HIGH, DAI1_PBEN04_I);
    
    *pREG_PADS0_DAI1_IE = (0x1<<1);    // Pin 1 Input Enable: routed to SPT4_AD0_I
    // register callback
    void tx_callback(void *handle, uint32_t event, void *buffer)
    {
    switch(event) {
        case ADI_SPORT_EVENT_TX_BUFFER_PROCESSED:
            txBufferToProcess = buffer;
            break;
        default:
            sportCallbackFailed = true;
            break;
    }
    }
    



Added description of the screenshots, fixed some instructions in the code.
[edited by: Blofeld at 8:52 AM (GMT -4) on 12 Oct 2020]
Parents
  • Hi everyone, 

    I now discovered another strange behaviour. The last channel of the TDM 4 respectively the last two channels TDM 8 configuration (from SC-589-Mini) does not work and sends randomly generated data (see attached Image). 

    TDM 8 Failure

    TDM 8 Error

    I checked the SPORT_CTL and the SPORT_MCTL registers already as well as the SPORT_CS0 register. They are initialised as desired. 

    Anyone an idea why this is happening?

    Regards,

    Jonas

  • 0
    •  Analog Employees 
    on Oct 14, 2020 2:51 PM 1 month ago in reply to Blofeld

    Hi,

    This could be a DMA related issue, however it is hard to say at this point. Could you maybe attach your project or the main code so I can try to reproduce the issue and test at my end?

    Regards,

    Wenting

  • Hi Wenting,

    thanks for your quick reply.

    Attached you'll find the code.

    Test Adau.zip

    Best Regards,

    Jonas

  • +1
    •  Analog Employees 
    on Oct 15, 2020 9:03 PM 1 month ago in reply to Blofeld

    Hi,

    The reason of corruption is the data word length.

    I think you are trying to implement TDM8 mode, with 32 bit per slot (ADAU1787_SPORT_BCLKS_32), but only 24 bit (dataWordLength = 23;) left justified data, right?

    However in the code, data word length configured in adi_sport_ConfigData it is being set to 24 bits, implying 24 bit per slot, so the SPORT would only receive and transmit 24*8=192 bits per frame, then release the bus. 192 / 32bit = 6, so it seems like the SPORT is only transmitting 6 32 bit slots.

    To solve the issue, either set the data word length to 32 bit then manually shift the data words to be left justified, or set the frame sync to use 24 bit per slot.

    By the way, I also noticed some SoftConfig code in the beginning of the main function. SoftConfig is only required for EZ-KITs. SC589-MINI doesn't have that kind of multiplexer hardware.

    Regards,

    Wenting

Reply
  • +1
    •  Analog Employees 
    on Oct 15, 2020 9:03 PM 1 month ago in reply to Blofeld

    Hi,

    The reason of corruption is the data word length.

    I think you are trying to implement TDM8 mode, with 32 bit per slot (ADAU1787_SPORT_BCLKS_32), but only 24 bit (dataWordLength = 23;) left justified data, right?

    However in the code, data word length configured in adi_sport_ConfigData it is being set to 24 bits, implying 24 bit per slot, so the SPORT would only receive and transmit 24*8=192 bits per frame, then release the bus. 192 / 32bit = 6, so it seems like the SPORT is only transmitting 6 32 bit slots.

    To solve the issue, either set the data word length to 32 bit then manually shift the data words to be left justified, or set the frame sync to use 24 bit per slot.

    By the way, I also noticed some SoftConfig code in the beginning of the main function. SoftConfig is only required for EZ-KITs. SC589-MINI doesn't have that kind of multiplexer hardware.

    Regards,

    Wenting

Children