94|0

139

帖子

2

TA的资源

一粒金砂(高级)

楼主
 

【MCXA156开发板测评】-6-EDMA3例程代码分析 [复制链接]

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

例程:edma3_ping_pong_transfer

1. 首先进行EDMA3初始化:

/*!
 * 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) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
    /* Ungate EDMA peripheral clock */
    CLOCK_EnableClock(s_edmaClockName[EDMA_GetInstance(base)]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */

#if defined(EDMA_RESETS_ARRAY)
    RESET_ReleasePeripheralReset(s_edmaResets[EDMA_GetInstance(base)]);
#endif

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

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

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

EDMA_CreateHandle(&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 < (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->channel = channel;

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

    handle->tcdBase     = EDMA_TCD_BASE(base, channel);
    handle->channelBase = EDMA_CHANNEL_BASE(base, channel);
    handle->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->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;
}

3. 设置传输完成后的回调函数:

EDMA_SetCallback(&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;
    }
}

 

4. 关联TCD 即传输控制描述符

EDMA_InstallTCDMemory(&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 & 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->B->C->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->header  = 1;
    handle->tcdUsed = 0;
    handle->tcdSize = (int8_t)tcdSize;
    handle->tcdPool = tcdPool;
}

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

    EDMA_PrepareTransfer(&transferConfig[0], &srcAddr[0], sizeof(srcAddr[0]), &destAddr[0], sizeof(destAddr[0]),
                         sizeof(uint32_t) * HALF_BUFFER_LENGTH, sizeof(uint32_t) * HALF_BUFFER_LENGTH,
                         kEDMA_MemoryToMemory);
    EDMA_PrepareTransfer(&transferConfig[1], &srcAddr[4], sizeof(srcAddr[0]), &destAddr[4], sizeof(destAddr[0]),
                         sizeof(uint32_t) * HALF_BUFFER_LENGTH, sizeof(uint32_t) * HALF_BUFFER_LENGTH,
                         kEDMA_MemoryToMemory);
    EDMA_SubmitLoopTransfer(&g_DMA_Handle, transferConfig, 2);
    EDMA_StartTransfer(&g_DMA_Handle);

 

EDMA进行传输前,Destination Buffer内容为:

 

 

第一次DMA传输完成后:

 

 

第二次EDMA传输完成后:

 

此帖出自NXP MCU论坛
点赞 关注
 

回复
举报
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表