Post Go back to editing

ASRC 16 Bit left justified to I2S

Thread Summary

The user encountered noisy output from the DAC when using the ASRC on the ADSP-21569. Disabling the 'bEnablePack' flag in the adi_sport_ConfigData() call resolved the issue. The user also noted that the ASRC can produce distorted signals during a debug session, which is not a known behavior and should be investigated further.
AI Generated Content
Category: Software
Product Number: ADSP-21569
Software Version: CCES 2.12.1

Hey together, 

I have another question regarding the SPORTs and the ASRC of the ADSP-21569. Maybe you can help. So far I am able to receive and transmit data via SPORT + DMA while running the ADSP als clock master. I also tried it by using the internal clock for the SPORTs as well as the PCGA as clock source. Everything fine so far. Now I am trying to get the ASRCs running. Here I'm a bit lost and I get only some crappy noise out of the DAC.

My plan is the following: 

The first question would be: 

- Q1: Is it really required to route the CRS outputs of the PCGA to a DAI1 PinBuffer? Is there no internal way to route the signals from PCGA to DAI1? 

- Q2: How should the configuration of the ASRC look like? What is right in my setup and what is wrong?

- Q3: When I am using the PCGA as clock source for the SPORTs, is the "nClockRatio" in the adi_sport_ConfigClock() required? 

Below is my code for the ASRC and the SPORT4A. Excuse by rought code, it is really hardcoded stuff but it is just for evaluation purpose.

#define COUNT 128
ADI_CACHE_ALIGN static int   int_SP4ABuffer0[COUNT];
ADI_CACHE_ALIGN static int   int_SP4ABuffer1[COUNT];

ADI_PDMA_DESC_LIST iSRC_LIST_1_SP4A;
ADI_PDMA_DESC_LIST iSRC_LIST_2_SP4A;
static uint8_t SPORTMemory4A[ADI_SPORT_MEMORY_SIZE];
static ADI_SPORT_HANDLE hSPORTDev4ARx; //ASRC RX

/*
Static Code for all other SPORTs and DMAs ...
*/


int SPU_init(void){
    if(adi_spu_Init(0, SpuMemory, NULL, NULL, &ghSpu) != ADI_SPU_SUCCESS)
    {
    	REPORT_ERROR("Failed to initialize SPU service\n");
		return FAILED;
    }

    /* Make SPORT 3A to generate secure transactions */
    if(adi_spu_EnableMasterSecure(ghSpu, SPORT_3A_SPU, true) != ADI_SPU_SUCCESS)
    {
    	REPORT_ERROR("Failed to enable Master secure for SPORT3A\n");
		return FAILED;
    }

    /* Make SPORT 3B to generate secure transactions */
    if(adi_spu_EnableMasterSecure(ghSpu, SPORT_3B_SPU, true) != ADI_SPU_SUCCESS)
    {
    	REPORT_ERROR("Failed to enable Master secure for SPORT3B\n");
		return FAILED;
    }

    /* Make SPORT 4A to generate secure transactions */
    if(adi_spu_EnableMasterSecure(ghSpu, SPORT_4A_SPU, true) != ADI_SPU_SUCCESS)
    {
    	REPORT_ERROR("Failed to enable Master secure for SPORT4A\n");
		return FAILED;
    }

    return SUCCESS;
}

static void PCG_init(void){
	ADI_PCG_CLK_INFO gClkInfoA;
	gClkInfoA.eClkInput = ADI_PCG_CLK_SCLK0;               /* Clock Source */
	gClkInfoA.nDiv = OUTPUT_PCG_CLOCK_DIV;               /* Clock Divisor */
	gClkInfoA.bExternalTrigger = false;                    /* External Trigger */

	ADI_PCG_FS_INFO gFsInfoA;
	gFsInfoA.eClkInput = ADI_PCG_FS_SCLK0;                 					/* Clock Source */
	gFsInfoA.nDiv = (OUTPUT_PCG_CLOCK_DIV)*(ADI_SPORT0A_CTL_SLEN + 1)*(2);	/* Frame Sync Divisor */
	gFsInfoA.nPulseWidth = (gFsInfoA.nDiv)/2;              					/* Pulse Width */
	gFsInfoA.nPhase = (OUTPUT_PCG_CLOCK_DIV)/2;                  			/* Phase */
	gFsInfoA.bExternalTrigger = false;                     					/* External Trigger */
	gFsInfoA.eFsBypassMode = ADI_PCG_FSBYPASS_MODE_NORMAL; 					/* Bypass Mode */

	adi_pcg_Init(ADI_PCG_DEV_A,&gClkInfoA,&gFsInfoA);

}

static int ASRC_init(void){
	ADI_ASRC_RESULT eAsrcResult = ADI_ASRC_FAILED;
	eAsrcResult = adi_asrc_Open(1u,                   /* Block number */
								0u,                   /* Device number */
								gAsrcMem,             /* Pointer to Memory */
								ADI_ASRC_MEMORY_SIZE, /* Memory Size */
								&hAsrc);
	if(eAsrcResult != ADI_ASRC_SUCCESS)
	{
		REPORT_ERROR("Could not Open ASRC  0x%08X\n", eAsrcResult);
		return FAILED;
	}
	eAsrcResult = adi_asrc_SetSerialFormat(hAsrc, ADI_ASRC_INPUT_16BIT_RIGHT_JUSTIFIED, ADI_ASRC_OUTPUT_I2S, ADI_ASRC_WORD_LENGTH_24);

    eAsrcResult = adi_asrc_RegisterCallback(hAsrc,AsrcCallback,NULL);
	if(eAsrcResult != ADI_ASRC_SUCCESS)
	{
		REPORT_ERROR("Could not Register callback for ASRC  0x%08X\n", eAsrcResult);
		return FAILED;
	}

	eAsrcResult = adi_asrc_Enable(hAsrc,true);
	if(eAsrcResult != ADI_ASRC_SUCCESS)
	{
		REPORT_ERROR("Could not Enable ASRC  0x%08X\n", eAsrcResult);
		return FAILED;
	}

	return SUCCESS;
}

static void PrepareDescriptors (void)
{

	iDESC_LIST_1_SP3A.pStartAddr	= (int *)int_SP0ABuffer1; /* Data array */
	iDESC_LIST_1_SP3A.Config		= ENUM_DMA_CFG_XCNT_INT ;
	iDESC_LIST_1_SP3A.XCount		= COUNT;
	iDESC_LIST_1_SP3A.XModify		= 4; /* Increase data address */
	iDESC_LIST_1_SP3A.YCount		= 0;
	iDESC_LIST_1_SP3A.YModify		= 0;
	iDESC_LIST_1_SP3A.pNxtDscp		= &iDESC_LIST_2_SP3A;

	iDESC_LIST_2_SP3A.pStartAddr	= (int *)int_SP0ABuffer2; /* Data array */
	iDESC_LIST_2_SP3A.Config		= ENUM_DMA_CFG_XCNT_INT ;
	iDESC_LIST_2_SP3A.XCount		= COUNT;
	iDESC_LIST_2_SP3A.XModify		= 4; /* Increase data address */
	iDESC_LIST_2_SP3A.YCount		= 0;
	iDESC_LIST_2_SP3A.YModify		= 0;
	iDESC_LIST_2_SP3A.pNxtDscp		= &iDESC_LIST_1_SP3A; /* Points to the first descriptor */

	iSRC_LIST_1_SP4A.pStartAddr	= (int *)int_SP4ABuffer0; /* Data array */
	iSRC_LIST_1_SP4A.Config		= ENUM_DMA_CFG_XCNT_INT ;
	iSRC_LIST_1_SP4A.XCount		= COUNT;
	iSRC_LIST_1_SP4A.XModify		= 4; /* Increase data address */
	iSRC_LIST_1_SP4A.YCount		= 0;
	iSRC_LIST_1_SP4A.YModify		= 0;
	iSRC_LIST_1_SP4A.pNxtDscp		= &iSRC_LIST_2_SP4A;

	iSRC_LIST_2_SP4A.pStartAddr	= (int *)int_SP4ABuffer1; /* Data array */
	iSRC_LIST_2_SP4A.Config		= ENUM_DMA_CFG_XCNT_INT ;
	iSRC_LIST_2_SP4A.XCount		= COUNT;
	iSRC_LIST_2_SP4A.XModify		= 4; /* Increase data address */
	iSRC_LIST_2_SP4A.YCount		= 0;
	iSRC_LIST_2_SP4A.YModify		= 0;
	iSRC_LIST_2_SP4A.pNxtDscp		= &iSRC_LIST_1_SP4A; /* Points to the first descriptor */
}

static void SPORTCallback(void *pAppHandle,uint32_t nEvent,void *pArg){
	int i;
    /* CASEOF (event type) */
    switch (nEvent){
        /* CASE (buffer processed) */
        case ADI_SPORT_EVENT_RX_BUFFER_PROCESSED:
        	adi_gpio_Toggle(GPIO_DAC_PORT,GPIO_DAC_PIN);
        break;
        default:
        break;
    }
}


static void SPORTCallbackASRC(void *pAppHandle, uint32_t nEvent, void *pArg){
	int i;
    /* CASEOF (event type) */
    switch (nEvent){
        /* CASE (buffer processed) */
        case ADI_SPORT_EVENT_RX_BUFFER_PROCESSED:
        	adi_gpio_Toggle(GPIO_ASRC_PORT,GPIO_ASRC_PIN);
			#if FORWARD_ASRC
			TestCallbackCount +=1;
			AsrcCallbackCount +=1;
			if(AsrcCallbackCount==1){
				for(i=0;i<COUNT;i+=2){
					int_SP0ABuffer1[i]=int_SP4ABuffer0[i];/*Copy ASRC Buffer to DAC */
					int_SP0ABuffer1[i+1]=int_SP4ABuffer0[i+1];/*Copy ASRC Buffer to DAC */
					++copyCount;
				}
			}
			if(AsrcCallbackCount==2){
				for(i=0;i<COUNT;i+=2){
					int_SP0ABuffer2[i]=int_SP4ABuffer1[i];/*Copy ASRC Buffer to DAC */
					int_SP0ABuffer2[i+1]=int_SP4ABuffer1[i+1];/*Copy ASRC Buffer to DAC */
					++copyCount;
				}
				AsrcCallbackCount=0;
			}
			#endif
        break;
        default:
        break;
    }
}

int Sport_init(bool slave, bool rxCH12, bool rxCH34){

	PCG_init();

    /* SPORT return code */
    ADI_SPORT_RESULT    eResult;

	/* Open the SPORT Device 3a */
	eResult = adi_sport_Open(SPORT_DEVICE_3A,ADI_HALF_SPORT_A,ADI_SPORT_DIR_TX, ADI_SPORT_I2S_MODE, SPORTMemory3A,ADI_SPORT_MEMORY_SIZE,&hSPORTDev3ATx);
	/* Try to enable the clock */
	adi_sport_ConfigClock(hSPORTDev3ATx,39,false,false,false);
	adi_sport_ConfigFrameSync(hSPORTDev3ATx,ADI_SPORT0A_CTL_SLEN,false,false,false,true,false,false);


	/* Open the SPORT Device 3B*/
	eResult = adi_sport_Open(SPORT_DEVICE_3B,ADI_HALF_SPORT_B,ADI_SPORT_DIR_RX, ADI_SPORT_I2S_MODE, SPORTMemory3B,ADI_SPORT_MEMORY_SIZE,&hSPORTDev3BRx);
	adi_sport_ConfigClock(hSPORTDev3BRx,39,false,false,false);
	adi_sport_ConfigFrameSync(hSPORTDev3BRx,ADI_SPORT0A_CTL_SLEN,false,false,false,true,false,false);

	/* Register SPORT Callback function */
	eResult = adi_sport_RegisterCallback(hSPORTDev3BRx,SPORTCallback,NULL);
	eResult = adi_sport_RegisterCallback(hSPORTDev3ATx,SPORTCallbackTx,NULL);

	/* Prepare descriptors */
	PrepareDescriptors();

	/* Open the SPORT Device 4A ASRC */
	eResult = adi_sport_Open(SPORT_DEVICE_4A, ADI_HALF_SPORT_A, ADI_SPORT_DIR_RX, ADI_SPORT_I2S_MODE, SPORTMemory4A, ADI_SPORT_MEMORY_SIZE, &hSPORTDev4ARx);
	CHECK_RESULT(eResult);
	adi_sport_ConfigData(hSPORTDev4ARx, ADI_SPORT_DTYPE_SIGN_FILL, 31, false, true, false);
	adi_sport_ConfigClock(hSPORTDev4ARx, 39, false, false, false);
	adi_sport_ConfigFrameSync(hSPORTDev4ARx, 31, false, false, false, false, false, false);
	eResult = adi_sport_RegisterCallback(hSPORTDev4ARx, SPORTCallbackASRC, NULL);
	ASRC_init();
	eResult = adi_sport_DMATransfer(hSPORTDev4ARx,&iSRC_LIST_1_SP4A,(DMA_NUM_DESC),ADI_PDMA_DESCRIPTOR_LIST, ADI_SPORT_CHANNEL_PRIM);

	/* Submit the first buffer for Rx.  */
	eResult = adi_sport_DMATransfer(hSPORTDev3BRx,&iSRC_LIST_1_SP3B,(DMA_NUM_DESC),ADI_PDMA_DESCRIPTOR_LIST, ADI_SPORT_CHANNEL_PRIM);
	eResult = adi_sport_DMATransfer(hSPORTDev3BRx,&iSRC_LIST_1_SP3B,(DMA_NUM_DESC),ADI_PDMA_DESCRIPTOR_LIST, ADI_SPORT_CHANNEL_SEC);

	/* Submit the first buffer for Tx.  */
	eResult = adi_sport_DMATransfer(hSPORTDev3ATx,&iDESC_LIST_1_SP3A,(DMA_NUM_DESC),ADI_PDMA_DESCRIPTOR_LIST, ADI_SPORT_CHANNEL_PRIM);

	/*Enable the Sport Device 4B */
	eResult = adi_sport_Enable(hSPORTDev3BRx,true);
	/*Enable the Sport Device 3a */
	eResult = adi_sport_Enable(hSPORTDev3ATx,true);
	/*Enable the Sport Device 4a */
	eResult = adi_sport_Enable(hSPORTDev4ARx,true);
	return eResult;
}

int main(int argc, char *argv[])
{
	/**
	 * Initialize managed drivers and/or services that have been added to 
	 * the project.
	 * @return zero on success 
	 */
	adi_initComponents();
	adi_pwr_SetClkOutSelectRegister(ADI_PWR_CGU0, ADI_PWR_CLKOUT_CGU0_CCLK0);
	/* Begin adding your custom code here */
	ADI_UART_RESULT    eUartResult;
	ADI_TWI_RESULT 	eTwiResult;
    if(result == SUCCESS){
    	result = ADAU1372_init(!slave);
    	if(result == SUCCESS){
    		result = Sport_init(slave, rxCH12, rxCH34);
    		if(result == SUCCESS){
    		
    		}
    	}
    }
    while(1){

	}
//	return 0;
}

Thanks a lot in advance. 

Best regards,

Eric

Parents
  • Hi,

    Regarding "Q1"
    >>>Yes, it is required to use the PCGA CRS pin to route with DAI1 Pin Buffer.

    For more details, please refer to the below FAQ:
    Interconnecting DAI1 and DAI0 using PCG_CRS pins 

    Regarding "Q2"
    >>> The ASRC configuration seems to be correct. Please use the below example as a reference and adjust it as needed for your requirements.


    We have an example to SPDIF_ASRC_DAC_AudioPassthrough example for ADSP-2156x,which demonstrates the usage of the ADAU1962a DAC with ASRC & SPDIF interface in I2S mode.

    Please download BSP package of ADSP-21569 using the below link:
    download.analog.com/.../ADI_EV-2156x_EZ-KIT-Rel3.0.0.exe

    After installation, please navigate to the following path:
    <installation path>\Analog Devices\EV-2156x_EZ-KIT-Rel3.0.0\EV-2156x_EZ-KIT\Examples\drivers\adc\SPDIF_ASRC_DAC_AudioPassthrough

    If you encounter any issues, please let us know.

    Regarding "Q3"
    >>>Yes, when using the PCG as the clock source (internal or external), configuring the nClockRatio is not required.

    Regards,
    Nandini C

  • Hey  ,

    thanks a lot for your reply. I found out the root cause of the issue. The problem was that I enabled the "bEnablePack" in the adi_sport_ConfigData() call. As soon as i disabled it, it worked.

    - Q1: Can you explain this flag a bit more in detail? From the source code documentation I dont understand it completly i guess.

    Also one thing i noticed is that when I use the ASRC while being in a Debug Session can cause strange output noise. Interesstingly the ASRC always locks with the correct ratio, no matter if i'm in a running debug session or if i stop the debugger. But sometimes the signal is a little bit distorted. Also if i only had a single breakpoint in the start of main(). When I run the application without a debug session it is always perfectly clean. 

    - Q2: Is this a known behavior? 

    Best regards,

    Eric

  • Hi,

    Thanks for the update.

    Regarding "Q1"

    >>>We are checking on this and will get back to you as soon as possible.

    Regards,
    Nandini C

  • Hi,

    Regarding "Q1"
    >>> We have checked the SPDIF_ASRC_DAC_AudioPassthrough example for the ADSP-2156x, and it works as expected on our end.
    Could you please share a simple project that replicates your issue on the ADSP-21569 board?

    Regards,
    Nandini C

  • Hi  ,

    it works on my end. My questions are not about if it is working. Q1 was about more information about the "bEnablePack". Q2 was to know that it is normal that the ASRC can produce noisy signals while an active debug session is running? 

    When I run it while i'm booting from flash everything is fine. 

    Best regards.

    Eric

  • Hi,

    Regarding "Q1"
    >>>The bEnablePack bit enables the SPORT to pack two 16-bit received samples into one 32-bit word and to unpack each 32-bit transmitted word into two 16-bit samples. This improves data transfer efficiency with 32-bit DMA. When enabled, interrupts occur per 32-bit packed word, and packing can be used with companding if needed.

    Can you please refer the "Transmit Path" [Page No:1107/2453] and "SPORT_CTL_A.PACK"[Page No:1158/2453]in the hardware Reference Manual. Please find the below link,
    https://www.analog.com/media/en/dsp-documentation/processor-manuals/adsp-2156x_hwr.pdf

    Regarding "Q2"
    >>>No, it is not normal for the ASRC to produce noisy signals while a debug session is active, such behavior suggests a configuration or clocking problem.

    Regards,
    Nandini C

Reply
  • Hi,

    Regarding "Q1"
    >>>The bEnablePack bit enables the SPORT to pack two 16-bit received samples into one 32-bit word and to unpack each 32-bit transmitted word into two 16-bit samples. This improves data transfer efficiency with 32-bit DMA. When enabled, interrupts occur per 32-bit packed word, and packing can be used with companding if needed.

    Can you please refer the "Transmit Path" [Page No:1107/2453] and "SPORT_CTL_A.PACK"[Page No:1158/2453]in the hardware Reference Manual. Please find the below link,
    https://www.analog.com/media/en/dsp-documentation/processor-manuals/adsp-2156x_hwr.pdf

    Regarding "Q2"
    >>>No, it is not normal for the ASRC to produce noisy signals while a debug session is active, such behavior suggests a configuration or clocking problem.

    Regards,
    Nandini C

Children
No Data