Exemplo n.º 1
0
/**
 * @brief  使能通道响应传输
 * @code
 *     //开启DMA 的0通道进行数据传输
 *     DMA_EnableRequest(HW_DMA_CH0);
 * @endcode
 * @param  chl: DMA通道号
 *         @arg HW_DMA_CH0
 *         @arg HW_DMA_CH1
 *         @arg HW_DMA_CH2
 *         @arg HW_DMA_CH3
 * @retval None
 */
void DMA_EnableRequest(uint8_t chl)
{
    DMA0->SERQ = DMA_SERQ_SERQ(chl);
}
Exemplo n.º 2
0
static status_t SPDIF_SubmitTransfer(edma_handle_t *handle, const edma_transfer_config_t *config, uint32_t rightChannel)
{
    edma_tcd_t *tcdRegs = (edma_tcd_t *)&handle->base->TCD[handle->channel];
    uint32_t primask;
    uint32_t csr;
    int8_t currentTcd;
    int8_t previousTcd;
    int8_t nextTcd;

    /* Check if tcd pool is full. */
    primask = DisableGlobalIRQ();
    if (handle->tcdUsed >= handle->tcdSize)
    {
        EnableGlobalIRQ(primask);

        return kStatus_EDMA_QueueFull;
    }
    currentTcd = handle->tail;
    handle->tcdUsed++;
    /* Calculate index of next TCD */
    nextTcd = currentTcd + 1U;
    if (nextTcd == handle->tcdSize)
    {
        nextTcd = 0U;
    }
    /* Advance queue tail index */
    handle->tail = nextTcd;
    EnableGlobalIRQ(primask);
    /* Calculate index of previous TCD */
    previousTcd = currentTcd ? currentTcd - 1U : handle->tcdSize - 1U;
    /* Configure current TCD block. */
    EDMA_TcdReset(&handle->tcdPool[currentTcd]);
    EDMA_TcdSetTransferConfig(&handle->tcdPool[currentTcd], config, NULL);
    /* Set channel link */
    EDMA_TcdSetChannelLink(&handle->tcdPool[currentTcd], kEDMA_MinorLink, rightChannel);
    EDMA_TcdSetChannelLink(&handle->tcdPool[currentTcd], kEDMA_MajorLink, rightChannel);
    /* Enable major interrupt */
    handle->tcdPool[currentTcd].CSR |= DMA_CSR_INTMAJOR_MASK;
    /* Link current TCD with next TCD for identification of current TCD */
    handle->tcdPool[currentTcd].DLAST_SGA = (uint32_t)&handle->tcdPool[nextTcd];
    /* Chain from previous descriptor unless tcd pool size is 1(this descriptor is its own predecessor). */
    if (currentTcd != previousTcd)
    {
        /* Enable scatter/gather feature in the previous TCD block. */
        csr = (handle->tcdPool[previousTcd].CSR | DMA_CSR_ESG_MASK) & ~DMA_CSR_DREQ_MASK;
        handle->tcdPool[previousTcd].CSR = csr;
        /*
            Check if the TCD blcok in the registers is the previous one (points to current TCD block). It
            is used to check if the previous TCD linked has been loaded in TCD register. If so, it need to
            link the TCD register in case link the current TCD with the dead chain when TCD loading occurs
            before link the previous TCD block.
        */
        if (tcdRegs->DLAST_SGA == (uint32_t)&handle->tcdPool[currentTcd])
        {
            /* Enable scatter/gather also in the TCD registers. */
            csr = (tcdRegs->CSR | DMA_CSR_ESG_MASK) & ~DMA_CSR_DREQ_MASK;
            /* Must write the CSR register one-time, because the transfer maybe finished anytime. */
            tcdRegs->CSR = csr;
            /*
                It is very important to check the ESG bit!
                Because this hardware design: if DONE bit is set, the ESG bit can not be set. So it can
                be used to check if the dynamic TCD link operation is successful. If ESG bit is not set
                and the DLAST_SGA is not the next TCD address(it means the dynamic TCD link succeed and
                the current TCD block has been loaded into TCD registers), it means transfer finished
                and TCD link operation fail, so must install TCD content into TCD registers and enable
                transfer again. And if ESG is set, it means transfer has notfinished, so TCD dynamic
                link succeed.
            */
            if (tcdRegs->CSR & DMA_CSR_ESG_MASK)
            {
                return kStatus_Success;
            }
            /*
                Check whether the current TCD block is already loaded in the TCD registers. It is another
                condition when ESG bit is not set: it means the dynamic TCD link succeed and the current
                TCD block has been loaded into TCD registers.
            */
            if (tcdRegs->DLAST_SGA == (uint32_t)&handle->tcdPool[nextTcd])
            {
                return kStatus_Success;
            }
            /*
                If go to this, means the previous transfer finished, and the DONE bit is set.
                So shall configure TCD registers.
            */
        }
        else if (tcdRegs->DLAST_SGA != 0)
        {
            /* The current TCD block has been linked successfully. */
            return kStatus_Success;
        }
        else
        {
            /*
                DLAST_SGA is 0 and it means the first submit transfer, so shall configure
                TCD registers.
            */
        }
    }
    /* There is no live chain, TCD block need to be installed in TCD registers. */
    EDMA_InstallTCD(handle->base, handle->channel, &handle->tcdPool[currentTcd]);
    /* Enable channel request again. */
    if (handle->flags & 0x80)
    {
        handle->base->SERQ = DMA_SERQ_SERQ(handle->channel);
    }

    return kStatus_Success;
}