/** * @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); }
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; }