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.

TMS320C5535: stuck in MMC_read() function

Part Number: TMS320C5535

Hi experts,

My customer is using "TMS320VC55XCSL-LOWPWR03_08_ 1_00" and has a problem with being stuck in a loop when using "csl_mmcsd.c"'s MMC_read() function.
C:\ti\c55_lp\c55_csl_3.08.01\src

Q1: They can't get out of the 3820~3829 line loop, is there a possible cause?

After sending a read command to the SD, it should break because MMCST0's DRRDY is normally set. However, there are cases where the loop continues.
Monitors MMCST1 and checks for FIFO empty before throwing a read command. Verify that MMCST1 is FIFO full and DRFUL when waiting for DRRDY without exiting the while loop.

Here is an excerpt from the MMC_read() function and a comment:.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

CSL_Status MMC_read(CSL_MmcsdHandle    hMmcsd,
                    Uint32             cardAddr,
                    Uint16             noOfBytes,
                    Uint16             *pReadBuffer)
{
	volatile Uint32	   response;
	volatile Int16     status;
	volatile Uint16    mmcStatus;
	volatile Uint16    count;
	Uint16             stopCmdRetryCnt;
	CSL_Status         result;
    Uint16             *pReadBuff;
    Uint16             rdCntMmc;
    Uint16             readRetryCount;
	Uint16             blkCnt;
	Uint16             reIssueReadFlag;
	Uint16             readCmd;
	Bool		       reStartDma;
	Uint16			   saved;

	reStartDma     = 0;
	readRetryCount = CSL_MMSCD_READ_WRITE_RETRY_COUNT;

    if((hMmcsd !=  NULL) && (pReadBuffer != NULL))
    {
		/* Set block length */
        if(noOfBytes != 0)
        {
			/*
			 * For standard capacity memory cards, it is possible to set
			 * the block length other than 512. Block length configured
			 * using MMC_setBlockLength() API will be stored in MMCSD
			 * handle.
			 */
			if((hMmcsd->blockLen != 0) &&
			   (hMmcsd->cardObj->sdHcDetected != TRUE))
			{
				blkCnt = (noOfBytes)/(hMmcsd->blockLen);
				CSL_FINS(hMmcsd->mmcRegs->MMCBLEN, MMCSD_MMCBLEN_BLEN,
						 hMmcsd->blockLen);
			}
			else
			{
				blkCnt = (noOfBytes)/(CSL_MMCSD_BLOCK_LENGTH);
				CSL_FINS(hMmcsd->mmcRegs->MMCBLEN, MMCSD_MMCBLEN_BLEN,
						 CSL_MMCSD_BLOCK_LENGTH);
			}

            CSL_FINS(hMmcsd->mmcRegs->MMCNBLK, MMCSD_MMCNBLK_NBLK, blkCnt);

			mmcStatus = CSL_MMCSD_BUSY_STATE;
            do
            {
				status = hMmcsd->mmcRegs->MMCST1;
				mmcStatus |= status & CSL_MMCSD_FIFO_EMPTY;

				if((status & CSL_MMCSD_BUSY_STATE) == 0)
				{
					mmcStatus &= ~CSL_MMCSD_BUSY_STATE;
				}
            } while(((mmcStatus & CSL_MMCSD_FIFO_EMPTY) != CSL_MMCSD_FIFO_EMPTY) ||
                     ((mmcStatus & CSL_MMCSD_BUSY_STATE) == CSL_MMCSD_BUSY_STATE));
        }
        else
        {
            return (CSL_ESYS_INVPARAMS);
        }

		/* Set Endian mode */
		CSL_FINS (hMmcsd->mmcRegs->MMCCTL, MMCSD_MMCCTL_PERMDR,
				  hMmcsd->readEndianMode);

        /* Reset FIFO */
        CSL_FINST(hMmcsd->mmcRegs->MMCFIFOCTL, MMCSD_MMCFIFOCTL_FIFORST, RESET);     //Verify that the FIFO has been reset to empty at this point
        /* Configure FIFO for read */
        CSL_FINST(hMmcsd->mmcRegs->MMCFIFOCTL, MMCSD_MMCFIFOCTL_FIFODIR, READ);
        /* Set FIFO access width */
		if(CSL_MMCSD_OPMODE_POLLED == hMmcsd->opMode)
		{
        	CSL_FINST(hMmcsd->mmcRegs->MMCFIFOCTL, MMCSD_MMCFIFOCTL_ACCWD, 2BYTES);
		}
		else
		{
        	CSL_FINST(hMmcsd->mmcRegs->MMCFIFOCTL, MMCSD_MMCFIFOCTL_ACCWD, 4BYTES);
		}

        /* Set FIFO threshold */
        CSL_FINST(hMmcsd->mmcRegs->MMCFIFOCTL,MMCSD_MMCFIFOCTL_FIFOLEV, 256BIT);

		if(blkCnt > 1)
		{
			readCmd = CSL_MMCSD_READ_MULTIPLE_BLOCK_CMD;
		}
		else
		{
			readCmd = CSL_MMCSD_READ_BLOCK_CMD;                          //blkCnt is 1, single block read
		}

		if(CSL_MMCSD_OPMODE_POLLED == hMmcsd->opMode)
		{
			do
			{
				readRetryCount--;                                    //Verify there are no retries
				if(readRetryCount == 0)
				{
					return (CSL_EMMCSD_TIMEOUT);
				}

				/*
				 * This flag enables the reading process to re-start
				 * right from sending the command incase of errors
				 * during the read operation
				 */
				reIssueReadFlag = 0; /* KR032010 */
				pReadBuff       = pReadBuffer;
        		rdCntMmc        = 0;

				status = MMC_sendCmd(hMmcsd,                          //DRRDY does not stand before read command, FIFO checks empty
				                     (Uint32)readCmd,
				                     (Uint32)cardAddr,
				                     CSL_MMCSD_EVENT_EOFCMD);

				if(reIssueReadFlag == 1)
				{
					continue;
				}

				do                                               //Occurs immediately after a read command, not in the middle of reading a block
				{
					do
					{
						status = hMmcsd->mmcRegs->MMCST0;
						if((status & CSL_MMCSD_DATA_TOUT_CRC_ERROR) != 0) 
						{
							reIssueReadFlag = 1;
							break;
						}

					} while((status & CSL_MMCSD_READ_READY) != CSL_MMCSD_READ_READY);

					if(reIssueReadFlag == 1)
					{
						break;
					}

					/*
					 * Read from MMCDRR1 register for little endian mode
					 * Read from MMCDRR2 register for big endian mode
					 */
					if(hMmcsd->readEndianMode == CSL_MMCSD_ENDIAN_LITTLE)
					{
						/*
						 * Since FIFO level is configured for 256 bits,
						 * there will be 32 bytes available in the FIFO.
						 * Loop runs 16 times and 2bytes are read in each
						 * interation.
						 */
						for(count = 0; count < 16; count++)
						{
							*pReadBuff++ = CSL_FEXT(hMmcsd->mmcRegs->MMCDRR1,
													MMCSD_MMCDRR1_DRR1);

							rdCntMmc += 2;
						}
					}
					else
					{
						/*
						 * Since FIFO level is configured for 256 bits,
						 * there will be 32 bytes available in the FIFO.
						 * Loop runs 16 times and 2bytes are read in each
						 * interation.
						 */
						for(count = 0; count < 16; count++)
						{
							*pReadBuff++ = CSL_FEXT(hMmcsd->mmcRegs->MMCDRR2,
													MMCSD_MMCDRR2_DRR2);

							rdCntMmc += 2;
						}
					}

				} while(rdCntMmc < noOfBytes);
} while(reIssueReadFlag); /* End of re-issue read command loop */

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Best Regards,
O.H

csl_mmcsd.c

  • Hi O.H

    First of all the loop from 3820 - 3829 is to check whether the data is ready to be read. I do not know why it is stuck there forever. Here are a few things you can try:

    1. Change to a different SD cards to rule out the bad sectors on the card.

    2. Try different examples (Interrupt or DMA) to rule out that the error only happens to the CPU polling mode

    3. Check whether the reIssueReadFlag has been set or not.

    Ming

  • Hi Ming

    Thank you for your reply.

    Ming Wei said:
    1. Change to a different SD cards to rule out the bad sectors on the card.


    Currently, two types of SD cards (TOSHIBA and Transcend) are available.
    They have confirmed the same phenomenon.

    Ming Wei said:
    2. Try different examples (Interrupt or DMA) to rule out that the error only happens to the CPU polling mode


    sorry, but due to the file system and SD card integration, they can't change the CPU polling mode easily and can't check it.

    Ming Wei said:
    3. Check whether the reIssueReadFlag has been set or not.


    reIssueReadFlag is at 0.

    Best Reghards,
    O.H

  • Hi Ming,

    If you have any opinions on the above survey results, could you please reply to me?

    If there is anything else I should check, could you tell me?

    My customer is in a hurry and I would appreciate it if you could reply by July 6 if possible.

    Best Regards,
    O.H

  • Hi O.H,

    The only thing I can think of is that add the  reIssueReadFlag = 1 after the do-while loop reach certain threshold (for example >30000) to force the read command to be re-issued. 

         loopCount = 0;

         do
         {
          status = hMmcsd->mmcRegs->MMCST0;
          if (((status & CSL_MMCSD_DATA_TOUT_CRC_ERROR) != 0) || (loopCount>30000))
          {
           reIssueReadFlag = 1;
           break;
          }

          loopCount++;

         } while((status & CSL_MMCSD_READ_READY) != CSL_MMCSD_READ_READY);

    Best regards,

    Ming

  • Hi Ming,

    Thank you for your answer.

    Ming Wei said:

    The only thing I can think of is that add the  reIssueReadFlag = 1 after the do-while loop reach certain threshold (for example >30000) to force the read command to be re-issued. 

         loopCount = 0;

         do
         {
          status = hMmcsd->mmcRegs->MMCST0;
          if (((status & CSL_MMCSD_DATA_TOUT_CRC_ERROR) != 0) || (loopCount>30000))
          {
           reIssueReadFlag = 1;
           break;
          }

          loopCount++;

         } while((status & CSL_MMCSD_READ_READY) != CSL_MMCSD_READ_READY);

    The current phenomenon is "After sending READ command, data is accumulated in FIFO, but DRRDY of MMCST0 register is not set.".

    In the method of setting reIssueReadFlag = 1, it seems that FIFO clearing is not performed, so DRRDY is not set because it remains FIFO full after the READ command is retransmitted.
    Also, even if DRRDY is set, unintended data in FIFO can be read.
    Is the above idea correct?

    I have additional questions, so could you please let me know?
    Q:Is DRRDY set in MMC_sendCmd() function? Or is it set by the loop on line 3820 ~ 3829?

    A customer investigation has shown that a software interrupt in the MMC_sendCmd() function may occur.
    (The above interrupts are based on customer software specifications.)

    When an interrupt occurs, MMCST0 is called at the timing of completion of RAED command transmission and DRRDY is cleared. They think this may be the cause.
    However, if the actual timing of setting DRRDY is the loop at line 3820 ~ 3829, it can be assumed that the interrupt has no effect.

    Best Regards,
    O.H

  • Hi

    Using the evaluation board to monitor when DRRDY was set, it was set immediately after the MMC_sendCmd() function.

    On my customer's system, there seems to be an interrupt just after the MMC_sendCmd() function to READ MMCST0.
    It seems that the reason was that DRRDY was cleared as a result of reading MMCST0 by interrupt processing.

    We have identified the cause, so please close the thread.
    Thank you for your support.

    Best Regards,
    O.H

  • Hi O.H.

    Would you mind mark this thread as resolved? Thanks!

    Ming