华大 HC32F460 DMA数据传输实验代码详解

声明:以下内容均为本人学习心得

一、基础知识

HC32F460拥有2个DMA控制单元,共8个独立通道,可以独立操作不同的DMA传输功能

每次请求传输一个数据块,最小是1个数据,最大是1024个数据。

每个数据的宽度可配置为8bit、16bit或32bit。

可以配置最多65535次传输。

源地址和目标地址可以独立配置为固定,自增,自减,循环或制定偏移量的跳转

可产生3种中断:块传输完成中断、传输完成中断、传输错误中断。

每个DMA控制单元有4个独立通道,4个通道优先级顺序为:通道0>通道1>通道2>通道3;当一个DMA单元有多个通道请求传输时将按照优先级顺序执行。但已处于传输中的通道不会被打断,高优先通道需等当前通道传输完成后才会启动。

二、实验代码详解

本样例为DMA连续数据传输,通过软件触发DMA传输数据。

现象:传输按预期完成,可观察到蓝色灯亮,否则红灯亮。

①相关参数配置定义

#define DMA_UNIT (CM_DMA2) //DMA第二个单元基地址

#define DMA_CH (DMA_CH3) //通道3地址

#define DMA_TC (4UL) //DMA传输次数

#define DMA_BC (5UL) //传输数据块的大小

#define DMA_DW (DMA_DATAWIDTH_32BIT) //传输数据的宽度

#define DMA_INT_SRC (INT_SRC_DMA2_TC3) //DMA中断序号 39U

#define DMA_IRQn (INT000_IRQn) //中断回调函数

#define DMA_TRIGGER_CH (AOS_DMA2_3) //AOS触发源为DMA2_3

特别声明:对于小白来说,中断序号为啥是39U,很多小白都是迷迷糊糊的,这是因为通过用户手册查看中断INTC里面的中断事件请求序号可以查找到DMA2_TC3对应的中断事件请求序号为27H,换算成10进制就是39U。

②定义软件触发事件变量、源地址缓存区、目标地址缓存区以及预期目标地址缓存区

__IO static en_flag_status_t m_u8DmaTcEnd = RESET;
static const uint32_t u32SrcBuf[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
                                       11, 12, 13, 14, 15, 16, 17, 18,
                                       19, 20
                                      };
static uint32_t u32DestBuf[20] = {0};
static uint32_t u32ExpectDestBufData[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
                                            13, 14, 15, 16, 17, 18, 19, 20
                                           };

m_u8DmaTcEnd= RESET; 此变量目的是为了产生一次软件触发事件,后面主函数会体现。再DMA产生中断里置为SET,就不会再次产生软件触发事件,需要重新置为 RESET

u32SrcBuf[20]、u32DestBuf[20] 模拟的是片外设备和片内设备之间的内存。

u32ExpectDestBufData[20] 目的是:传输的数据不能是盲目的,预期知道需要传输什么数据。

③DMA初始化

static void DmaInit(void)
{
    stc_dma_init_t stcDmaInit; //DMA初始化结构体

    AOS_SetTriggerEventSrc(DMA_TRIGGER_CH, EVT_SRC_AOS_STRG);

    (void)DMA_StructInit(&stcDmaInit);//DMA结构体的初始化

    stcDmaInit.u32IntEn      = DMA_INT_ENABLE;
    stcDmaInit.u32BlockSize  = DMA_BC;
    stcDmaInit.u32TransCount = DMA_TC;
    stcDmaInit.u32DataWidth  = DMA_DW;
    stcDmaInit.u32DestAddr   = (uint32_t)(&u32DestBuf[0]);
    stcDmaInit.u32SrcAddr    = (uint32_t)(&u32SrcBuf[0]);
    stcDmaInit.u32SrcAddrInc     = DMA_SRC_ADDR_INC;
    stcDmaInit.u32DestAddrInc    = DMA_DEST_ADDR_INC;

    (void)DMA_Init(DMA_UNIT, DMA_CH, &stcDmaInit);
}

具体参数配置说明上面说了,我们看看DMA结构体成员有哪些:

typedef struct {
    uint32_t u32IntEn;          /*!<  使能DMA中断   */
    uint32_t u32SrcAddr;        /*!< 选择DMA触发源地址        */
    uint32_t u32DestAddr;       /*!< 声明DMA传输的目标地址   */
    uint32_t u32DataWidth;      /*!< 设置DMA数据传输宽度,由DMA_CHxCTL.HIZE决定 */
    uint32_t u32BlockSize;      /*!< 设置数据块大小  */
    uint32_t u32TransCount;     /*!< 设置DMA传输次数 */
    uint32_t u32SrcAddrInc;     /*!< 设置源地址更新方式为:固定、递增、递减、重载或者不连续跳转。 */
    uint32_t u32DestAddrInc;    /*!< 设置目标地址更新方式为:固定、递增、递减、重载或者不连续跳转 */
} stc_dma_init_t;

AOS_SetTriggerEventSrc(DMA_TRIGGER_CH, EVT_SRC_AOS_STRG); 作用是:选择DMA2为传输启动触发源。

④DMA中断配置 以及 中断回调函数

static void DmaIntInit(void)
{
    stc_irq_signin_config_t stcIrqSignConfig;

    stcIrqSignConfig.enIntSrc   = DMA_INT_SRC;
    stcIrqSignConfig.enIRQn     = DMA_IRQn;
    stcIrqSignConfig.pfnCallback = &DMA2_CH3_TransEnd_IrqCallback;

    (void)INTC_IrqSignIn(&stcIrqSignConfig);
    DMA_ClearTransCompleteStatus(DMA_UNIT, DMA_FLAG_TC_CH3);

    /* NVIC setting */
    NVIC_ClearPendingIRQ(DMA_IRQn);
    NVIC_SetPriority(DMA_IRQn, DDL_IRQ_PRIO_DEFAULT);
    NVIC_EnableIRQ(DMA_IRQn);
}

static void DMA2_CH3_TransEnd_IrqCallback(void)
{
    m_u8DmaTcEnd = SET;
    DMA_ClearTransCompleteStatus(DMA_UNIT, DMA_FLAG_TC_CH3);
}

中断配置在之前文章有详解过,这里就不多解释了,需要特别说明的是:在中断回调函数中,m_u8DmaTcEnd = SET; 要将软件触发变量置1,这样就不会产生第二次软件触发事件。

⑤主函数

int32_t main(void)
{
    /* Register write enable for some required peripherals. */
    LL_PERIPH_WE(LL_PERIPH_GPIO | LL_PERIPH_PWC_CLK_RMU | LL_PERIPH_FCG | LL_PERIPH_EFM | LL_PERIPH_SRAM);
    /* System clock init */
    BSP_CLK_Init();
    /* LED init */
    BSP_LED_Init();
    /* DMA/AOS FCG enable */
    FCG_Fcg0PeriphClockCmd((FCG0_PERIPH_DMA2 | FCG0_PERIPH_AOS), ENABLE);

    /* Register write protected for some required peripherals. */
    LL_PERIPH_WP(LL_PERIPH_GPIO | LL_PERIPH_FCG | LL_PERIPH_EFM | LL_PERIPH_SRAM);

    /* Config DMA */
    DmaInit();
    /* DMA interrupt config */
    DmaIntInit();

    /* DMA module enable */
    DMA_Cmd(DMA_UNIT, ENABLE);

    /* DMA channel enable */
    (void)DMA_ChCmd(DMA_UNIT, DMA_CH, ENABLE);

    /* 1st trigger for DMA */
    AOS_SW_Trigger();

    while (RESET == m_u8DmaTcEnd) {
        if (SET == DMA_GetTransCompleteStatus(DMA_UNIT, DMA_FLAG_BTC_CH3)) {
            DMA_ClearTransCompleteStatus(DMA_UNIT, DMA_FLAG_BTC_CH3);
            AOS_SW_Trigger();
        }
    }
    if (0 != memcmp(u32DestBuf, u32ExpectDestBufData, sizeof(u32DestBuf))) {
        /* LED red */
        BSP_LED_On(LED_RED);
    } else {
        /* LED blue, as expected */
        BSP_LED_On(LED_BLUE);
    }

    for (;;) {
        ;
    }
}

AOS_SW_Trigger(); 作用是 通过设置A0S中外设触发事件寄存器(INTSFTTRG)中b0为1,置1:产生一次软件触发事件。

while(...): 这个语句的作用是 传输之前判断相应的寄存器清0没有,否则无法传输。通过if()判断上一次是否传输完成(中断状态寄存器0(DMA_INTSTAT1)b3~b0)。

if (0 != memcmp(u32DestBuf, u32ExpectDestBufData, sizeof(u32DestBuf))) 用来判断是否按预期完成传输。

到此DMA数据传输实验代码分析完毕,如有疑问可以私信我~

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: hc32f460是一款高性能的32位微控制器,它支持串口DMA功能。串口DMA是一种通过直接内存访问(DMA)方式来传输数据的技术,可以大大提高串口通信的效率。 hc32f460的串口DMA功能通过将串口数据的传输交给DMA控制器来完成,减轻了CPU的负担。在使用串口DMA时,首先需要配置DMA控制器,包括设置DMA通道、传输数据的起始地址和长度等。然后,将数据写入串口发送缓冲区,并启动DMA传输。DMA控制器会自动根据配置的参数从内存中读取数据,并将数据直接发送到串口,无需CPU的干预。 串口DMA可以极大地提高数据传输的速度,尤其适用于大量数据的传输和高速通信的场景。相比于传统的CPU中断方式,串口DMA能够实现数据的无缝传输,提高了系统的响应速度和实时性。 hc32f460的串口DMA功能还具有灵活的配置选项,例如可以选择不同的DMA通道进行数据传输,还支持循环传输模式和多缓冲区传输,以满足不同的应用需求。 总之,hc32f460的串口DMA功能是一项强大且高效的数据传输技术,能够提升系统的性能和可靠性。通过 DMA 控制器和串口的协同工作,能够实现高速、实时的数据传输,广泛应用于各种通信和控制系统中。 ### 回答2: HC32F460是一款基于ARM Cortex-M4内核的高性能微控制器。它具有丰富的外设功能,包括多个串口接口和DMA控制器。串口DMA是指通过DMA控制器来管理串口数据的传输。 在HC32F460中,串口DMA的工作原理如下:首先,我们需要配置串口控制器的相关参数,包括波特率、数据位、停止位和校验位等。然后,我们通过编程的方式配置DMA控制器,以使其能够将串口数据的发送和接收与内存之间进行直接传输。 对于串口发送功能,当我们要发送一段数据时,首先将数据存储在内存中的发送缓冲区中,然后通过编程的方式触发DMA控制器开始传输。DMA控制器会自动从内存中读取数据,并通过串口控制器发送出去。在传输过程中,我们无需干预,可以继续进行其他的操作。 对于串口接收功能,当有数据到达时,串口控制器会将数据存储在接收缓冲区中。然后,我们再次通过编程的方式触发DMA控制器开始传输。DMA控制器会自动将数据从接收缓冲区读取到内存中,以供后续的处理使用。同样,在传输过程中我们无需干预。 通过使用串口DMA,我们可以实现高效的串口数据传输,提高系统的性能。它可以减少CPU的负载,降低数据传输的延迟。同时,由于采用了直接内存访问的方式,可以减少CPU与外设之间的数据拷贝,提高数据传输的速度。 总之,HC32F460串口DMA是一种高效的数据传输方式,通过使用DMA控制器来管理串口数据的传输,可以提高系统的性能和可靠性。 ### 回答3: HC32F460是一种高性能的32位MCU芯片,具有丰富的外设接口和强大的处理能力。其中,串口DMA是这款芯片上的一个功能模块,用于实现串口的数据传输。 串口DMA可以通过配置寄存器来进行初始化设置。首先需要配置串口的传输参数,例如波特率、数据位数、停止位等。然后设置DMA的初始化参数,包括数据的传输方向、传输大小、源地址和目的地址等。接下来,通过使能串口DMA功能,就可以开始进行数据传输。 串口DMA的工作原理是通过中断触发和DMA通道来实现数据的传输。当有数据到达串口时,串口DMA会产生一个中断请求,触发DMA通道进行数据的传输。DMA通道会自动从源地址读取数据,并将数据传输到目的地址。数据传输完成后,DMA通道会产生一个传输完成的中断,在此中断中可以进行相应的处理,例如发送一个完成信号给外部设备。 串口DMA的优点是能够大大提高数据传输的效率和可靠性。由于数据传输DMA通道完成,可以减轻CPU的负担,提高系统的响应速度。同时,采用DMA传输数据,可以避免由于CPU繁忙而导致的数据丢失或错误。因此,串口DMA在需要高效、稳定传输大量数据的应用中非常有用。 总之,HC32F460的串口DMA是一种可靠高效的数据传输方式,通过合理配置和使用,可以实现高速稳定的串口通信。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值