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]