慕容雪花 发表于 2025-1-13 08:54

【MCXA156开发板测评】-6-EDMA3例程代码分析

本帖最后由 慕容雪花 于 2025-1-12 20:16 编辑

<p>例程:edma3_ping_pong_transfer</p>

<p>1. 首先进行EDMA3初始化:</p>

<pre>
<code>/*!
* brief Initializes the eDMA peripheral.
*
* This function ungates the eDMA clock and configures the eDMA peripheral according
* to the configuration structure.
*
* param base eDMA peripheral base address.
* param config A pointer to the configuration structure, see "edma_config_t".
* note This function enables the minor loop map feature.
*/
void EDMA_Init(EDMA_Type *base, const edma_config_t *config)
{
    assert(config != NULL);
    assert(FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base) != -1);

    uint32_t tmpreg, i = 0U;

#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) &amp;&amp; FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
    /* Ungate EDMA peripheral clock */
    CLOCK_EnableClock(s_edmaClockName);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */

#if defined(EDMA_RESETS_ARRAY)
    RESET_ReleasePeripheralReset(s_edmaResets);
#endif

#if defined(FSL_EDMA_SOC_IP_EDMA) &amp;&amp; FSL_EDMA_SOC_IP_EDMA
    /* clear all the enabled request, status to make sure EDMA status is in normal condition */
    EDMA_BASE(base)-&gt;ERQ = 0U;
    EDMA_BASE(base)-&gt;INT = 0xFFFFFFFFU;
    EDMA_BASE(base)-&gt;ERR = 0xFFFFFFFFU;
    /* Configure EDMA peripheral according to the configuration structure. */
    tmpreg = EDMA_BASE(base)-&gt;CR;
    tmpreg &amp;= ~(DMA_CR_ERCA_MASK | DMA_CR_HOE_MASK | DMA_CR_CLM_MASK | DMA_CR_EDBG_MASK);
    tmpreg |= (DMA_CR_ERCA(config-&gt;enableRoundRobinArbitration) | DMA_CR_HOE(config-&gt;enableHaltOnError) |
               DMA_CR_CLM(config-&gt;enableContinuousLinkMode) | DMA_CR_EDBG(config-&gt;enableDebugMode) | DMA_CR_EMLM(1U));
    EDMA_BASE(base)-&gt;CR = tmpreg;
#else
    tmpreg = EDMA_MP_BASE(base)-&gt;MP_CSR;
#if defined FSL_FEATURE_EDMA_HAS_GLOBAL_MASTER_ID_REPLICATION &amp;&amp; FSL_FEATURE_EDMA_HAS_GLOBAL_MASTER_ID_REPLICATION
    tmpreg = (tmpreg &amp; ~(DMA_MP_CSR_HAE_MASK | DMA_MP_CSR_ERCA_MASK | DMA_MP_CSR_EDBG_MASK | DMA_MP_CSR_GCLC_MASK |
                         DMA_MP_CSR_GMRC_MASK | DMA_MP_CSR_HALT_MASK)) |
             DMA_MP_CSR_GMRC(config-&gt;enableMasterIdReplication) | DMA_MP_CSR_HAE(config-&gt;enableHaltOnError) |
             DMA_MP_CSR_ERCA(config-&gt;enableRoundRobinArbitration) | DMA_MP_CSR_EDBG(config-&gt;enableDebugMode) |
             DMA_MP_CSR_GCLC(config-&gt;enableGlobalChannelLink);
#else
    tmpreg = (tmpreg &amp; ~(DMA_MP_CSR_HAE_MASK | DMA_MP_CSR_ERCA_MASK | DMA_MP_CSR_EDBG_MASK | DMA_MP_CSR_GCLC_MASK |
                         DMA_MP_CSR_HALT_MASK)) |
             DMA_MP_CSR_HAE(config-&gt;enableHaltOnError) | DMA_MP_CSR_ERCA(config-&gt;enableRoundRobinArbitration) |
             DMA_MP_CSR_EDBG(config-&gt;enableDebugMode) | DMA_MP_CSR_GCLC(config-&gt;enableGlobalChannelLink);
#endif
    EDMA_MP_BASE(base)-&gt;MP_CSR = tmpreg;

#if defined FSL_FEATURE_EDMA_HAS_CHANNEL_CONFIG &amp;&amp; FSL_FEATURE_EDMA_HAS_CHANNEL_CONFIG
    /* channel transfer configuration */
    for (i = 0U; i &lt; (uint32_t)FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base); i++)
    {
      if (config-&gt;channelConfig != NULL)
      {
            EDMA_InitChannel(base, i, config-&gt;channelConfig);
      }
    }
#endif
#endif
}</code></pre>

<p>2. 紧接着创建一个edma句柄,用于后续操作edma:</p>

<pre>
<code>EDMA_CreateHandle(&amp;g_DMA_Handle, EXAMPLE_DMA_BASEADDR, DEMO_DMA_CHANNEL_0);

/*!
* brief Creates the eDMA handle.
*
* This function is called if using the transactional API for eDMA. This function
* initializes the internal state of the eDMA handle.
*
* param handle eDMA handle pointer. The eDMA handle stores callback function and
*               parameters.
* param base eDMA peripheral base address.
* param channel eDMA channel number.
*/
void EDMA_CreateHandle(edma_handle_t *handle, EDMA_Type *base, uint32_t channel)
{
    assert(handle != NULL);
    assert(FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base) != -1);
    assert(channel &lt; (uint32_t)FSL_FEATURE_EDMA_INSTANCE_CHANNELn(base));

    uint32_t edmaInstance;
    edma_tcd_t *tcdRegs;

    /* Zero the handle */
    (void)memset(handle, 0, sizeof(*handle));

    handle-&gt;channel = channel;

    /* Get the DMA instance number */
    edmaInstance                        = EDMA_GetInstance(base);
    s_EDMAHandle = handle;
    /* Enable NVIC interrupt */
    (void)EnableIRQ(s_edmaIRQNumber);

    handle-&gt;tcdBase   = EDMA_TCD_BASE(base, channel);
    handle-&gt;channelBase = EDMA_CHANNEL_BASE(base, channel);
    handle-&gt;base      = base;
    /*
       Reset TCD registers to zero. Unlike the EDMA_TcdReset(DREQ will be set),
       CSR will be 0. Because in order to suit EDMA busy check mechanism in
       EDMA_SubmitTransfer, CSR must be set 0.
    */
    tcdRegs                                       = handle-&gt;tcdBase;
    EDMA_TCD_SADDR(tcdRegs, EDMA_TCD_TYPE(base))   = 0;
    EDMA_TCD_SOFF(tcdRegs, EDMA_TCD_TYPE(base))      = 0;
    EDMA_TCD_ATTR(tcdRegs, EDMA_TCD_TYPE(base))      = 0;
    EDMA_TCD_NBYTES(tcdRegs, EDMA_TCD_TYPE(base))    = 0;
    EDMA_TCD_SLAST(tcdRegs, EDMA_TCD_TYPE(base))   = 0;
    EDMA_TCD_DADDR(tcdRegs, EDMA_TCD_TYPE(base))   = 0;
    EDMA_TCD_DOFF(tcdRegs, EDMA_TCD_TYPE(base))      = 0;
    EDMA_TCD_CITER(tcdRegs, EDMA_TCD_TYPE(base))   = 0;
    EDMA_TCD_DLAST_SGA(tcdRegs, EDMA_TCD_TYPE(base)) = 0;
    EDMA_TCD_CSR(tcdRegs, EDMA_TCD_TYPE(base))       = 0;
    EDMA_TCD_BITER(tcdRegs, EDMA_TCD_TYPE(base))   = 0;
}</code></pre>

<p>3. 设置传输完成后的回调函数:</p>

<pre>
<code>EDMA_SetCallback(&amp;g_DMA_Handle, DMA_Callback, NULL);

/* User callback function for EDMA transfer. */
void DMA_Callback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
{
    if (transferDone)
    {
      g_transferDone = true;
    }
}</code></pre>

<p>&nbsp;</p>

<p>4. 关联TCD 即传输控制描述符</p>

<pre>
<code>EDMA_InstallTCDMemory(&amp;g_DMA_Handle, g_DMA_Tcd, 2);

/*!
* brief Installs the TCDs memory pool into the eDMA handle.
*
* This function is called after the EDMA_CreateHandle to use scatter/gather feature. This function shall only be used
* while users need to use scatter gather mode. Scatter gather mode enables EDMA to load a new transfer control block
* (tcd) in hardware, and automatically reconfigure that DMA channel for a new transfer.
* Users need to prepare tcd memory and also configure tcds using interface EDMA_SubmitTransfer.
*
* param handle eDMA handle pointer.
* param tcdPool A memory pool to store TCDs. It must be 32 bytes aligned.
* param tcdSize The number of TCD slots.
*/
void EDMA_InstallTCDMemory(edma_handle_t *handle, edma_tcd_t *tcdPool, uint32_t tcdSize)
{
    assert(handle != NULL);
    assert(((uint32_t)tcdPool &amp; 0x1FU) == 0U);

    /* Initialize tcd queue attribute. */
    /* header should initial as 1, since that it is used to point to the next TCD to be loaded into TCD memory,
   * In EDMA driver IRQ handler, header will be used to calculate how many tcd has done, for example,
   * If application submit 4 transfer request, A-&gt;B-&gt;C-&gt;D,
   * when A finshed, the header is 0, C is the next TCD to be load, since B is already loaded,
   * according to EDMA driver IRQ handler, tcdDone = C - A - header = 2 - header = 2, but actually only 1 TCD done,
   * so the issue will be the wrong TCD done count will pass to application in first TCD interrupt.
   * During first submit, the header should be assigned to 1, since 0 is current one and 1 is next TCD to be loaded,
   * but software cannot know which submission is the first one, so assign 1 to header here.
   */
    handle-&gt;header= 1;
    handle-&gt;tcdUsed = 0;
    handle-&gt;tcdSize = (int8_t)tcdSize;
    handle-&gt;tcdPool = tcdPool;
}</code></pre>

<p>5. 设置传输的源地址、目的地址、传输数据量等:</p>

<pre>
<code>    EDMA_PrepareTransfer(&amp;transferConfig, &amp;srcAddr, sizeof(srcAddr), &amp;destAddr, sizeof(destAddr),
                         sizeof(uint32_t) * HALF_BUFFER_LENGTH, sizeof(uint32_t) * HALF_BUFFER_LENGTH,
                         kEDMA_MemoryToMemory);
    EDMA_PrepareTransfer(&amp;transferConfig, &amp;srcAddr, sizeof(srcAddr), &amp;destAddr, sizeof(destAddr),
                         sizeof(uint32_t) * HALF_BUFFER_LENGTH, sizeof(uint32_t) * HALF_BUFFER_LENGTH,
                         kEDMA_MemoryToMemory);
    EDMA_SubmitLoopTransfer(&amp;g_DMA_Handle, transferConfig, 2);
    EDMA_StartTransfer(&amp;g_DMA_Handle);</code></pre>

<p>&nbsp;</p>

<p>EDMA进行传输前,Destination Buffer内容为:</p>

<p> &nbsp;</p>

<p>&nbsp;</p>

<p>第一次DMA传输完成后:</p>

<p> &nbsp;</p>

<p>&nbsp;</p>

<p>第二次EDMA传输完成后:</p>

<p> &nbsp;</p>
页: [1]
查看完整版本: 【MCXA156开发板测评】-6-EDMA3例程代码分析