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.

MMCSD LLD bug

Other Parts Discussed in Thread: AM5728

Hi,

I'm using the MMCSD LLD v1.0.0.3 on a custom AM5728 hardware and I discovered two problems. A SD card is connected to the MMC1 interface.

1:
There seems to be a problem when reading or writing the controller data buffers in MMCSD_v1_xferStatusFxn(). This function gets continuously called during a data transfer, unitl the transfer competion status flag gets set. The problem is that this function reads or writes all the requested data with a single buffer ready event, which can be much more than the buffer size (1024 Bytes).

This is the receive data case:

static void MMCSD_v1_xferStatusFxn(uintptr_t arg)
{
    ...

    status = HSMMCSDIntrStatus(hwAttrs->baseAddr);

    /* Read data received from card */
    if (status & HS_MMCSD_INTR_MASK_BUFRDRDY)
    {
        if(1 == object->xferInProgress)
        {
            HSMMCSDIntrClear(hwAttrs->baseAddr,
                                   HS_MMCSD_INTR_MASK_BUFRDRDY);

            if (object->dataBufIdx != NULL)
            {
                dataLen = object->dataBlockCount * object->dataBlockSize;

                for (cnt = 0U; cnt < dataLen; cnt += 4U)
                {
                    HSMMCSDGetData(hwAttrs->baseAddr, (uint8_t *)&temp, 4U);
                    object->dataBufIdx[cnt] = *((uint8_t*)&temp);
                    object->dataBufIdx[cnt + 1U] = *((uint8_t*)&temp + 1U);
                    object->dataBufIdx[cnt + 2U] = *((uint8_t*)&temp + 2U);
                    object->dataBufIdx[cnt + 3U] = *((uint8_t*)&temp + 3U);
                }
            }
        }
    }
    ...

The additional buffer reading causes the BUFRDRDY flag to get set again. Then, the function gets called again and the complete amount is read again. But because the buffer is empty now, the destination buffer gets overwritten with 0s.

I changed the function to only copy only the block size and to update the data pointer for each event:

    /* Read data received from card */
    if (status & HS_MMCSD_INTR_MASK_BUFRDRDY)
    {
        if(1 == object->xferInProgress)
        {
            HSMMCSDIntrClear(hwAttrs->baseAddr,
                                   HS_MMCSD_INTR_MASK_BUFRDRDY);

            if (object->dataBufIdx != NULL)
            {
                dataLen = object->dataBlockSize;

                for (cnt = 0U; cnt < dataLen; cnt += 4U)
                {
                    HSMMCSDGetData(hwAttrs->baseAddr, (uint8_t *)&temp, 4U);
                    object->dataBufIdx[cnt] = *((uint8_t*)&temp);
                    object->dataBufIdx[cnt + 1U] = *((uint8_t*)&temp + 1U);
                    object->dataBufIdx[cnt + 2U] = *((uint8_t*)&temp + 2U);
                    object->dataBufIdx[cnt + 3U] = *((uint8_t*)&temp + 3U);
                }
                object->dataBufIdx += dataLen;
            }
        }
    }

The write case is similar and I think the interrupt handler MMCSD_v1_hwiFxn() has the same problem.

2:
In MMCSD_v1_write(), I had to add a delay after the stop transmission command (12):

        /* Send a STOP */
        if (transaction.blockCount > 1U)
        {
            transaction.cmd  = MMCSD_CMD(12U);
            transaction.flags = MMCSD_CMDRSP_BUSY;
            transaction.arg = 0U;
            ret = MMCSD_v1_transfer(handle, &transaction);
            delay(10U);
        }

Without this delay, I'm getting a timeout while executing the next command. I'm not sure why this is necessary.

Thanks,
Ralf