Post Go back to editing

I2S passthrough on custom board

Thread Summary

The user encountered issues with I2S data signals on a custom board using ADSP-21565, PCM1808 ADC, and PCM5102 DAC. The problem was resolved by adding SPORT data and clock configuration APIs in the application code. The SRU configuration in system.svc is not mandatory if SRU and SRU2 functions are used in the application, and the SPORT driver in system.svc is not required for I2S audio passthrough if the necessary configurations are done via APIs.
AI Generated Content
Category: Hardware

Hello,

I am bringing up a custom board with ADSP-21565, and I2S ADC/DAC (PCM1808 and PCM5102).

I went through a lot of examples and explanations, but I am still struggling.

Currently I generate I2S clocks from an external clock coming on pin (DAI0 PIN08) routed to PCGA.

My ADC is on DAI0 and the DAC is on DAI1, so I used cross connections to share the clocks. PCG is configured as follow:

static void PCG_init(void)
{
	/* PCG A for I2S - ADC and DAC */
	ADI_PCG_CLK_INFO gClkInfoI2S =
	{
		ADI_PCG_CLK_EXT,	             /* Clock Source */
		8u,          					 /* Clock Divisor for 3.072 MHz = (24.576 MHz / 8) */
		false                            /* External Trigger */
	};

	ADI_PCG_FS_INFO gFsInfoI2S =		 /* 48k */
	{
		ADI_PCG_FS_EXT,		             /* Clock Source */
		512u,     						 /* Frame Sync Divisor for 48k = (24.576 MHz / 512) */
		256u,                            /* Pulse Width */
		1u,                              /* Phase */
		false,                           /* External Trigger */
		ADI_PCG_FSBYPASS_MODE_NORMAL     /* Bypass Mode */
	};

	adi_pcg_Init(ADI_PCG_DEV_A, &gClkInfoI2S, &gFsInfoI2S);
}

SRU is configured as follow:

void SRU_init(void)
{
	/* 20 bits to activate DAI0 and DAI1 inputs */
	*pREG_PADS0_DAI0_IE=0x000FFFFF;
	*pREG_PADS0_DAI1_IE=0x000FFFFF;

	/* MCLK input from DAI0 PIN8 to PCGA */
    SRU(DAI0_PB08_O, PCG0_EXTCLKA_I);
    SRU(LOW, DAI0_PBEN08_I);

    /* I2S ADC */
    /* SCLK output from PCGA to DAI0 PIN10 */
    SRU(PCG0_CLKA_O, DAI0_PB10_I);
    SRU(HIGH, DAI0_PBEN10_I);
    /* SCLK output from PCGA to SPORT 0A */
    SRU(DAI0_PB10_O, SPT0_ACLK_I);
    /* LRCK output from PCGA to DAI0 PIN9 */
    SRU(PCG0_FSA_O, DAI0_PB09_I);
    SRU(HIGH, DAI0_PBEN09_I);
    /* LRCK output from PCGA to SPORT 0A */
    SRU(DAI0_PB09_O, SPT0_AFS_I);
    /* ADC IN 0 to SPORT 1A */
    SRU(DAI0_PB19_O, SPT0_AD0_I);
    SRU(LOW, DAI0_PBEN19_I);

    /* I2S DAC */
    /* SCLK output from PCGA to DAI1 PIN8 and SPORT4A */
    SRU2(PCG0_CRS_CLKA_O, DAI1_PB08_I);
    SRU2(DAI1_PB08_O, SPT4_ACLK_I);
    SRU2(HIGH, DAI1_PBEN08_I);

    /* LRCK output from PCGA to DAI1 PIN7 and SPORT4A */
    SRU2(PCG0_CRS_FSA_O, DAI1_PB07_I);
    SRU2(DAI1_PB07_O, SPT4_AFS_I);
    SRU2(HIGH, DAI1_PBEN07_I);

    /* SPORT4A data to DAC - DAI1 PIN09 */
    SRU2(SPT4_AD0_O, DAI1_PB09_I);
    SRU2(HIGH, DAI1_PBEN09_I);
}

All clocks seem correct at the ADC and DAC pins, but not data signals. I suspect an issue with my SPORT configurations.

Here is data output of the DSP sent to the DAC, with test values. Frame signal below, data signal up:

Some bits correspond to my test values, but the 32 bits seem truncated, and 2 values out of 3 are full logic highs (which I never send).

My SPORTs are configured as follow:

static int SPORT_Init(void)
{
    /* SPORT return code */
    ADI_SPORT_RESULT result;

	/* Open the SPORT Device 0A */
    result = adi_sport_Open(SPORT_DEVICE_0, ADI_HALF_SPORT_A, ADI_SPORT_DIR_RX, ADI_SPORT_I2S_MODE, SPORT_0A_Memory, ADI_SPORT_MEMORY_SIZE, &h_SPORT_0A_Rx);
	if(result!=ADI_SPORT_SUCCESS)
	{
		printf("SPORT 0A open Failed\n");
		return FAILED;
	}

	/* Open the SPORT Device 4A */
	result = adi_sport_Open(SPORT_DEVICE_4, ADI_HALF_SPORT_A, ADI_SPORT_DIR_TX, ADI_SPORT_I2S_MODE, SPORT_4A_Memory, ADI_SPORT_MEMORY_SIZE, &h_SPORT_4A_Tx);
	if(result!=ADI_SPORT_SUCCESS)
	{
		printf("SPORT 4A open Failed\n");
		return FAILED;
	}

	/* Register SPORT Callback function */
	result = adi_sport_RegisterCallback(h_SPORT_0A_Rx, SPORT_Callback, NULL);
	check_result(result);
	result = adi_sport_RegisterCallback(h_SPORT_4A_Tx, SPORT_Callback, NULL);
	check_result(result);

	/* Prepare descriptors */
	SPORT_PrepareDescriptors();
	SPORT_PrepareDataBuffers();

	/* Submit the first buffer for Rx.  */
	result = adi_sport_DMATransfer(h_SPORT_0A_Rx, &SPORT_0A_descriptor_1_ADC, (DMA_NUM_DESC), ADI_PDMA_DESCRIPTOR_LIST, ADI_SPORT_CHANNEL_PRIM);
	check_result(result);

	result = adi_sport_DMATransfer(h_SPORT_4A_Tx, &SPORT_4A_descriptor_1_DAC, (DMA_NUM_DESC), ADI_PDMA_DESCRIPTOR_LIST, ADI_SPORT_CHANNEL_PRIM);
	check_result(result);

	/*Enable Sport Devices */
	result = adi_sport_Enable(h_SPORT_0A_Rx, true);
	check_result(result);
	result = adi_sport_Enable(h_SPORT_4A_Tx, true);
	check_result(result);

	return SUCCESS;
}

And DMA as follow:

/* ADC */
ADI_PDMA_DESC_LIST SPORT_0A_descriptor_1_ADC;
ADI_PDMA_DESC_LIST SPORT_0A_descriptor_2_ADC;
int32_t ADC_Buffer_1[BLOCK_SIZE * ADC_NB_CH];
int32_t ADC_Buffer_2[BLOCK_SIZE * ADC_NB_CH];
static uint8_t SPORT_0A_Memory[ADI_SPORT_MEMORY_SIZE];
static ADI_SPORT_HANDLE h_SPORT_0A_Rx;

/* DAC */
ADI_PDMA_DESC_LIST SPORT_4A_descriptor_1_DAC;
ADI_PDMA_DESC_LIST SPORT_4A_descriptor_2_DAC;
int32_t DAC_Buffer_1[BLOCK_SIZE * DAC_NB_CH];
int32_t DAC_Buffer_2[BLOCK_SIZE * DAC_NB_CH];
static uint8_t SPORT_4A_Memory[ADI_SPORT_MEMORY_SIZE];
static ADI_SPORT_HANDLE h_SPORT_4A_Tx;

volatile uint8_t SPORTCallbackCount = 0;
volatile uint32_t data_available=0;

void SPORT_PrepareDescriptors(void){
	/* ADC - Populate descriptor for SPORT 1 DMA transfer */
	SPORT_0A_descriptor_1_ADC.pStartAddr	= (int32_t*)ADC_Buffer_1;
	SPORT_0A_descriptor_1_ADC.Config		= ENUM_DMA_CFG_XCNT_INT;
	SPORT_0A_descriptor_1_ADC.XCount		= BLOCK_SIZE * ADC_NB_CH;
	SPORT_0A_descriptor_1_ADC.XModify		= 4;
	SPORT_0A_descriptor_1_ADC.YCount		= 0;
	SPORT_0A_descriptor_1_ADC.YModify		= 0;
	SPORT_0A_descriptor_1_ADC.pNxtDscp		= &SPORT_0A_descriptor_2_ADC;

	SPORT_0A_descriptor_2_ADC.pStartAddr	= (int32_t*)ADC_Buffer_2;
	SPORT_0A_descriptor_2_ADC.Config		= ENUM_DMA_CFG_XCNT_INT;
	SPORT_0A_descriptor_2_ADC.XCount		= BLOCK_SIZE * ADC_NB_CH;
	SPORT_0A_descriptor_2_ADC.XModify		= 4;
	SPORT_0A_descriptor_2_ADC.YCount		= 0;
	SPORT_0A_descriptor_2_ADC.YModify		= 0;
	SPORT_0A_descriptor_2_ADC.pNxtDscp		= &SPORT_0A_descriptor_1_ADC;

	/* DAC - Populate descriptor for SPORT 4 DMA transfer */
	SPORT_4A_descriptor_1_DAC.pStartAddr	= (int32_t*)DAC_Buffer_1;
	SPORT_4A_descriptor_1_DAC.Config		= ENUM_DMA_CFG_XCNT_INT ;
	SPORT_4A_descriptor_1_DAC.XCount		= BLOCK_SIZE * DAC_NB_CH;
	SPORT_4A_descriptor_1_DAC.XModify		= 4;
	SPORT_4A_descriptor_1_DAC.YCount		= 0;
	SPORT_4A_descriptor_1_DAC.YModify		= 0;
	SPORT_4A_descriptor_1_DAC.pNxtDscp		= &SPORT_4A_descriptor_2_DAC;

	SPORT_4A_descriptor_2_DAC.pStartAddr	= (int32_t*)DAC_Buffer_2;
	SPORT_4A_descriptor_2_DAC.Config		= ENUM_DMA_CFG_XCNT_INT ;
	SPORT_4A_descriptor_2_DAC.XCount		= BLOCK_SIZE * DAC_NB_CH;
	SPORT_4A_descriptor_2_DAC.XModify		= 4;
	SPORT_4A_descriptor_2_DAC.YCount		= 0;
	SPORT_4A_descriptor_2_DAC.YModify		= 0;
	SPORT_4A_descriptor_2_DAC.pNxtDscp		= &SPORT_4A_descriptor_1_DAC;
}

RX and TX callback work properly.

1-) can you please confirm my SRU config is correct?

2-) what is the default configuration of a SPORT? Does it always work with 32 bits?

3-) Can you help me understand the behavior I witness? 2 values out of 3 seem wrong

The DSP is master, ADC and DAC are configured as slave and I2S format.

Thank you,

Fabien

Thread Notes