This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Left/Right channels are swapped by PSP McASP driver at startup

Other Parts Discussed in Thread: PCM1803A, OMAPL138

Hello,

my problem is close to this one : http://e2e.ti.com/support/embedded/tirtos/f/355/t/117092.aspx.

First, my configuration is "OMAP L138 with PSP drivers 1.30.01"

The DSP drives 4 stereo ADCs (PCM1803A) . They communicate in I2S through McASP.

ADCs are slaves and send data on 24bits.

Acquisition works fine except about every tenth startup, left channels (odd) and right channels (even) are swapped : chan1 <-> chan2, chan3 <-> chan4 ...

Swap doesn't seem to change during runtime, only at startup.

Here is my McASP configuration :

===================================================================================

#define NO_CHANNELS 8
#define MCASP_SIZE_BUFFER 2048
#define NO_BUFFERS 3

static Mcasp_HwSetupData sMcaspSetup = 
{
	.mask = 0x00FFFFFF, 
	.fmt = 
		( CSL_MCASP_RFMT_RDATDLY_1BIT << CSL_MCASP_RFMT_RDATDLY_SHIFT		) |
		( CSL_MCASP_RFMT_RRVRS_MSBFIRST << CSL_MCASP_RFMT_RRVRS_SHIFT		) |
		( CSL_MCASP_RFMT_RPAD_RPBIT << CSL_MCASP_RFMT_RPAD_SHIFT			) |
		( 23 << CSL_MCASP_RFMT_RPBIT_SHIFT									) |
		( CSL_MCASP_RFMT_RSSZ_24BITS << CSL_MCASP_RFMT_RSSZ_SHIFT			) |
		( CSL_MCASP_RFMT_RBUSEL_VBUSP << CSL_MCASP_RFMT_RBUSEL_SHIFT		) |
		( CSL_MCASP_RFMT_RROT_NONE << CSL_MCASP_RFMT_RROT_SHIFT				) ,
	.frSyncCtl =
		( CSL_MCASP_AFSRCTL_RMOD_I2S << CSL_MCASP_AFSRCTL_RMOD_SHIFT		) |
		( CSL_MCASP_AFSRCTL_FRWID_WORD << CSL_MCASP_AFSRCTL_FRWID_SHIFT		) |
		( CSL_MCASP_AFSRCTL_FSRM_INTERNAL << CSL_MCASP_AFSRCTL_FSRM_SHIFT	) |
		( CSL_MCASP_AFSRCTL_FSRP_FALLINGEDGE << CSL_MCASP_AFSRCTL_FSRP_SHIFT) ,
	.tdm  = 0x00000003,
	.intCtl = 
		( CSL_MCASP_RINTCTL_RSTAFRM_DISABLE << CSL_MCASP_RINTCTL_RSTAFRM_SHIFT	) |
		( CSL_MCASP_RINTCTL_RDATA_DISABLE << CSL_MCASP_RINTCTL_RDATA_SHIFT		) |
		( CSL_MCASP_RINTCTL_RLAST_DISABLE << CSL_MCASP_RINTCTL_RLAST_SHIFT		) |
		( CSL_MCASP_RINTCTL_RDMAERR_DISABLE << CSL_MCASP_RINTCTL_RDMAERR_SHIFT	) |
		( CSL_MCASP_RINTCTL_RCKFAIL_DISABLE << CSL_MCASP_RINTCTL_RCKFAIL_SHIFT	) |
		( CSL_MCASP_RINTCTL_RSYNCERR_DISABLE << CSL_MCASP_RINTCTL_RSYNCERR_SHIFT) |
		( CSL_MCASP_RINTCTL_ROVRN_DISABLE << CSL_MCASP_RINTCTL_ROVRN_SHIFT		) ,
	.stat = 0x000001FF,      // RSTAT reset any existing status bits
	.evtCtl = 
		( CSL_MCASP_REVTCTL_RDATDMA_ENABLE << CSL_MCASP_REVTCTL_RDATDMA_SHIFT) ,
	{
		// Diviseur pour AHCLKR : 24 MHz(AUXCLK) / 384(PCM1803) / 62.5kHz = 1
		.clkSetupHiClk =
			( CSL_MCASP_AHCLKRCTL_HCLKRM_INTERNAL << CSL_MCASP_AHCLKRCTL_HCLKRM_SHIFT	) |
			( CSL_MCASP_AHCLKRCTL_HCLKRP_NOTINVERTED << CSL_MCASP_AHCLKRCTL_HCLKRP_SHIFT) |
			( 0 << CSL_MCASP_AHCLKRCTL_HCLKRDIV_SHIFT									) ,	// Div par 1
		// Diviseur pour ACLKR : 24 MHz (AHCLKR) / 48 bits / 62.5kHz = 8
		.clkSetupClk = 			// 
			( CSL_MCASP_ACLKRCTL_CLKRP_RISINGEDGE << CSL_MCASP_ACLKRCTL_CLKRP_SHIFT		) |
			( CSL_MCASP_ACLKRCTL_CLKRM_INTERNAL << CSL_MCASP_ACLKRCTL_CLKRM_SHIFT		) |
			( 7 << CSL_MCASP_ACLKRCTL_CLKRDIV_SHIFT	) ,	// Div par 8
		.clkChk = 0
	}
};

/// Paramètres du canal McASP
Mcasp_ChanParams  mcaspChanParams =
{
    .noOfSerRequested = 4,                     // number of serializers
    .indexOfSersRequested = 
    	{
			Mcasp_SerializerNum_9,
			Mcasp_SerializerNum_10,
			Mcasp_SerializerNum_11,
			Mcasp_SerializerNum_12,
    	},
    .mcaspSetup = &sMcaspSetup,
    .isDmaDriven = TRUE,
    .channelMode = Mcasp_OpMode_TDM,         // TDM MODE
    .wordWidth = Mcasp_WordLength_24,        // word width
    .userLoopJobBuffer = NULL,
    .userLoopJobLength = 0,
    .edmaHandle = 0,
    .gblCbk = sMcAspErr,
    .noOfChannels = 2,
    .dataFormat = Mcasp_BufferFormat_MULTISER_MULTISLOT_SEMI_INTERLEAVED_1,
    .enableHwFifo = TRUE,
    .isDataPacked = FALSE
};

#pragma DATA_ALIGN(sMcaspBuffer, CACHE_ALIGN);
static int sMcaspBuffer[NO_BUFFERS][MCASP_SIZE_BUFFER*NO_CHANNELS];
Mcasp_Params mcaspParams;

/**
 *	Initialize driver
 */
void user_mcAspDrvInit()
{
    Mcasp_init();
    
    mcaspParams = Mcasp_PARAMS;
    mcaspParams.hwiNumber = 8;
	mcaspParams.pscPwrmEnable = FALSE;
	// Configure le mode asynchrone sinon AFSR n'est pas commandé
	mcaspParams.mcaspHwSetup.tx.clk.clkSetupClk = 0x40;
}

/**
 *	Create SIO
 */
static void sMcAspBoot()
{
	SIO_Attrs   sioAttrs;

	mcaspChanParams.edmaHandle = hEdma[0];

	sioAttrs       = SIO_ATTRS;
    sioAttrs.nbufs = NO_BUFFERS;			// Ping-pong
    sioAttrs.align = CACHE_ALIGN;			// Optimisation avec le cache
    sioAttrs.model = SIO_ISSUERECLAIM;		// Driver plus léger


	sHw.audio = SIO_create("/dioMcasp", SIO_INPUT, 
		MCASP_SIZE_BUFFER*NO_CHANNELS*sizeof(int), &sioAttrs);
	assert(	sHw.audio);
	SIO_ctrl(sHw.audio, Mcasp_IOCTL_STOP_PORT, 0);
}

/**
 *	Start acquisition
 */
void startMcAsp()
{
	int i;
	for(i=0;i<NO_BUFFERS;++i)
	{
		giveBuf(sMcaspBuffer[i]);
	}
	SIO_ctrl(sHw.audio, Mcasp_IOCTL_START_PORT, 0);
}

int* waitBuf()
{
	int* buf;
	int retour;
	retour = SIO_reclaim(sHw.audio, (Ptr*)&buf, 0);
	assert(retour == MCASP_SIZE_BUFFER*NO_CHANNELS*sizeof(int));
	return buf;
}

void giveBuf(int* buf)
{
	int retour;
	assert(((unsigned int)buf)%CACHE_ALIGN == 0);
	retour = SIO_issue(sHw.audio, buf, 
		MCASP_SIZE_BUFFER*NO_CHANNELS*sizeof(int), 0);
	assert(retour == SYS_OK);
}

I tried to set userLoopJobLength to  "no_of_ser=4" x "no_of_slots=2" x "size_of_slot=4" = 32, but that doesn't solve my problem.

Do I do anything wrong during initialization ?

Thanks for your help,

Romain

Edit 1 : Before calling SIO_create, AFSR is not driven. After calling SIO_create, AFSR is driven at 24MHz ! It is finaly driven at 62.5kHz only after sending Mcasp_IOCTL_START_PORT. Is it the standard behaviour ?

  • Hi Romain,

    Thanks for your post.

    Usually, if SIO_Create instance is not successful, the McASP driver wouldn't have generated the frame sync, clock & data when it is configured as Tx/Rx. I mean McASP expects these signals to tranmit data out or to receive data in.

    In general, if the user application doesn't meet the real time needs of Tx/Rx. of data, the McASP driver would be configured to send out a known pattern using userLoopJobBuffer & userLoopJobLength. Usually, Mcasp driver expects the data (samples) to be arranged in a specific format while requesting for an IO transfer.

    In your case, what is userloopjob buffer size for each serializer ?  I mean, whether the user application provides the userLoopJobLength or it is precalculated properly for  slot width, number of slot and the number of serializers.

    I think, there is a criteria which needs to be satisfied as mentioned in the omapl138 bios psp user guide for the channels to swap which is, you need to ensure that, the calculated buffer size either by user appliation or precalculated for word width of slot, should not match the logical end of slots, then the channels shall be swapped. A quick way to check is to monitor the frame sync and data lines on scope and send out unique pattern in each slot of the idle time buffer.

    How did you configure the number of channels & number of slots in your application? it is required to be equal.

    Whether the buffer size calculation is compliant to the recommended method as per PSP user guide?

    Please check Sections 9.3.3, 9.4.2 & 9.4.3 in the OMAPl138 bios psp user guide.

    Thanks & regards,

    Sivaraj K

    -------------------------------------------------------------------------------------------------------
    Please click the Verify Answer button on this post if it answers your question.
    -------------------------------------------------------------------------------------------------------

     

     

  • Hello Sivaraj K,

    as I use I2S, number of slots is 2, which is why I set "mcaspChanParams.noOfChannels = 2" and let driver decide automatically what size should be used. Is it ok ?

    Regards,

    Romain

  • Romain,

    Thanks for your update.

    Yes, you are right. You need to ensure that no. of channels & no. of slots should be equal but  userLoopJobLength (buffer size) for each serializer shall be calculated by user application or precalculated for word width of slot, no. of slots & no. of serializers and again, the buffer size should not match the logical end of slots, then the channels can be swapped. So, it is your option for the driver decide automatically (which is precalculated by default) or you shall configure on your own

    Thanks & regards,

    Sivaraj K

    -------------------------------------------------------------------------------------------------------
    Please click the Verify Answer button on this post if it answers your question.
    -------------------------------------------------------------------------------------------------------