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
  • 0
    •  Analog Employees 
    on Oct 9, 2020 8:21 PM 1 month ago

    Hi,

    Sorry for the late reply, for some reason I did not get notification for the question.

    Could you clarify which screenshot is for TX (from ADSP to ADAU/DAC) and which is for RX (from ADAU/ADC to ADSP)?

    The setup seems too be a bit weird to me, it seems like you are using SPORT4A for RX and SPORT5A for TX. Generally we use half sport for one direction, and another half for another direction. For example, SPORT4A for TX and SPORT4B for RX.

    Another issue I can see here is that SPORT5A is being initialized twice however the SPORT4A is not being initialized?

    Regards,

    Wenting

  • Hi Wenting,

    thanks for your answer!

    I added the description to the screenshots.

    Thanks for the comment regarding the half sport. I will try changing that as you suggested.

    I also fixed the code snippets, since there were some copy & paste errors. (I only copied the code from my framework which is necessary to understand the problem.) The SPORT4A is therefore being initialized. Sorry for the confusion.

    Cheers,

    Jonas

  • One additional information may be useful: 

    The setup has already been working in I²S stereo mode operation. Only the adaption to TDM mode (with the code from above) fails.

Reply Children
No Data