I found a bug on the DMA code for the MK10 family, or did I?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

I found a bug on the DMA code for the MK10 family, or did I?

857 Views
m4l490n
Contributor V

I have been having a lot of problems making the ADC-DMA continuous conversion for the internal temp channel work on my custom MK10 board. I also have an FRDMK64 board and there is a sample project that has exactly what I need. The project is frdmk64f_adc16_continuous_edma. I just changed the channel they are using for the internal temp.

I used that project as a reference for my MK10 chip but it was not working. It was very strange because the ADC0 and DMA configuration are exactly the same for both, but the code for the MK10 was not working.

Then I decided to go deeper on the debugging and step into the EDMA API on the fsl_edma.c file and there is where I noticed something.

For the fsl_edma.c file on the FRDMK64 project, which is taken from the SDK_2.9.0, I see the following inside the EDMA_SubmitTransfer function:

edma_tcd_t *tcdRegs = (edma_tcd_t *)(uint32_t)&handle->base->TCD[handle->channel];

if (handle->tcdPool == NULL)
{
    /*
     *    Check if EDMA channel is busy:
     *    1. if channel active bit is set, it implies that minor loop is executing, then channel is busy
     *    2. if channel active bit is not set and BITER not equal to CITER, it implies that major loop is executing,
     * then channel is busy
     *
     *    There is one case can not be covered in below condition:
     *    When transfer request is submitted, but no request from peripheral, that is to say channel sevice doesn't
     *    begin, if application would like to submit another transfer , then the TCD will be overwritten, since the
     *    ACTIVE is 0 and BITER = CITER, for such case, it is a scatter gather(link TCD) case actually, so
     *    application should enabled TCD pool for dynamic scatter gather mode by calling EDMA_InstallTCDMemory.
     */
    if (((handle->base->TCD[handle->channel].CSR & DMA_CSR_ACTIVE_MASK) != 0U) ||
        (((handle->base->TCD[handle->channel].CITER_ELINKNO & DMA_CITER_ELINKNO_CITER_MASK) !=
          (handle->base->TCD[handle->channel].BITER_ELINKNO & DMA_BITER_ELINKNO_BITER_MASK))))
    {
        return kStatus_EDMA_Busy;
    }
    else
    {
        EDMA_SetTransferConfig(handle->base, handle->channel, config, NULL);
        /* Enable auto disable request feature */
        handle->base->TCD[handle->channel].CSR |= DMA_CSR_DREQ_MASK;
        /* Enable major interrupt */
        handle->base->TCD[handle->channel].CSR |= DMA_CSR_INTMAJOR_MASK;

        return kStatus_Success;
    }
}

 

But for the MK10 version, which is taken from the SDK_2.2.0 I see the following for the same function:

edma_tcd_t *tcdRegs = (edma_tcd_t *)&handle->base->TCD[handle->channel];

if (handle->tcdPool == NULL)
{
    /*
        Check if EDMA is busy: if the given channel started transfer, CSR will be not zero. Because
        if it is the last transfer, DREQ will be set. If not, ESG will be set. So in order to suit
        this check mechanism, EDMA_CreatHandle will clear CSR register.
    */
    if ((tcdRegs->CSR != 0) && ((tcdRegs->CSR & DMA_CSR_DONE_MASK) == 0))
    {
        return kStatus_EDMA_Busy;
    }
    else
    {
        EDMA_SetTransferConfig(handle->base, handle->channel, config, NULL);
        /* Enable auto disable request feature */
        handle->base->TCD[handle->channel].CSR |= DMA_CSR_DREQ_MASK;
        /* Enable major interrupt */
        handle->base->TCD[handle->channel].CSR |= DMA_CSR_INTMAJOR_MASK;

        return kStatus_Success;
    }
}

 

You can notice how the second if is different. In the case of MK10, the code always goes to the return kStatus_EDMA_Busy; even when this is executed at initialization and there is absolutely no DMA activity, nor the DMA is busy.

So I decided to make the second if the same as in the FRDMK64 code so I substituted this:

if ((tcdRegs->CSR != 0) && ((tcdRegs->CSR & DMA_CSR_DONE_MASK) == 0))

with this:

    if (((handle->base->TCD[handle->channel].CSR & DMA_CSR_ACTIVE_MASK) != 0U) ||
        (((handle->base->TCD[handle->channel].CITER_ELINKNO & DMA_CITER_ELINKNO_CITER_MASK) !=
          (handle->base->TCD[handle->channel].BITER_ELINKNO & DMA_BITER_ELINKNO_BITER_MASK))))

 

And voila!! Now the whole thing works beautifully! No issues at all.

1 Reply

838 Views
danielchen
NXP TechSupport
NXP TechSupport

Hi

 

Thanks for reporting this issue in SDK 2.2.

In SDK2.2 edma driver

/*
Check if EDMA is busy: if the given channel started transfer, CSR will be not zero. Because
if it is the last transfer, DREQ will be set. If not, ESG will be set. So in order to suit
this check mechanism, EDMA_CreatHandle will clear CSR register.

*/
tmpCSR = tcdRegs->CSR;
if ((tmpCSR != 0UL) && ((tmpCSR & DMA_CSR_DONE_MASK) == 0UL))

{ return kStatus_EDMA_Busy; }

 

The code logic states that the DMA is busy and the transfer will no longer be set (EDMA_SetTransferConfig will not be called).

 

Sometimes EDMA_SubmitTranfer will return DMA busy. This is an issue.

This issue is fixed in a later version. 

Looking into the TCD->CSR description,  there is also an ACTIVE bit that specify the status of the DMA. That bit can be checked to see if the DMA is active or not.

 

Thank you.

 

Regards

Daniel

 

0 Kudos