【GD32】GD32F303串口设置DMA发生中断无法进入中断函数

文章讲述了在GD32F303开发中遇到的串口DMA中断问题,涉及到DMA初始化、中断设置和中断函数调用的顺序,强调了DMA中断函数(如DMA0_Channel3_IRQHandler)的特殊性以及正确配置中断的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述在GD32F303官方提供的串口例程中,有一个DMA发生和接收中断例程,在模仿着写的过程中,能够正常发送数据,但是无法进入中断函数。在这里插入图片描述DMA0_Channel3_IRQHandler函数时官方定义的弱函数,需要自己重新实现。如果开启了DMA0通道3相关的中断,在发生中断的时候就会进入该函数。DMA的中断主要有以下3个,每一个通道都有自己的3个中断。
在这里插入图片描述
例程的代码主要:

int main(void)
{
    dma_parameter_struct dma_init_struct;
    /* enable DMA0 */
    rcu_periph_clock_enable(RCU_DMA0);
    /* initialize USART */
    gd_eval_com_init(EVAL_COM0);
    /*configure DMA0 interrupt*/
    nvic_config();
    
    /* deinitialize DMA channel3(USART0 tx) */
    dma_deinit(DMA0, DMA_CH3);
    dma_struct_para_init(&dma_init_struct);

    dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_addr = (uint32_t)txbuffer;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = ARRAYNUM(txbuffer);
    dma_init_struct.periph_addr = USART0_DATA_ADDRESS;
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA0, DMA_CH3, &dma_init_struct);

    /* deinitialize DMA channel4 (USART0 rx) */
    dma_deinit(DMA0, DMA_CH4);
    dma_struct_para_init(&dma_init_struct);

    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_addr = (uint32_t)rxbuffer;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = 10;
    dma_init_struct.periph_addr = USART0_DATA_ADDRESS;
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA0, DMA_CH4, &dma_init_struct);

    /* configure DMA mode */
    dma_circulation_disable(DMA0, DMA_CH3);
    dma_memory_to_memory_disable(DMA0, DMA_CH3);
    dma_circulation_disable(DMA0, DMA_CH4);
    dma_memory_to_memory_disable(DMA0, DMA_CH4);
    
    /* enable USART DMA for reception */
    usart_dma_receive_config(USART0, USART_RECEIVE_DMA_ENABLE);
    /* enable DMA0 channel4 transfer complete interrupt */
    dma_interrupt_enable(DMA0, DMA_CH4, DMA_INT_FTF);
    /* enable DMA0 channel4 */
    dma_channel_enable(DMA0, DMA_CH4);
    /* enable USART DMA for transmission */
    usart_dma_transmit_config(USART0, USART_TRANSMIT_DMA_ENABLE);
    /* enable DMA0 channel3 transfer complete interrupt */
    dma_interrupt_enable(DMA0, DMA_CH3, DMA_INT_FTF);
    /* enable DMA0 channel3 */
    dma_channel_enable(DMA0, DMA_CH3);
    
    /* waiting for the transfer to complete*/
    while(RESET == g_transfer_complete){
    }
    
    g_transfer_complete = RESET;

    /* waiting for the transfer to complete*/
    while(RESET == g_transfer_complete){
    }

    printf("\n\r%s\n\r", rxbuffer);

    while(1){
    }
}

/*!
    \brief      configure DMA interrupt
    \param[in]  none
    \param[out] none
    \retval     none
*/
void nvic_config(void)
{
    nvic_irq_enable(DMA0_Channel3_IRQn, 0, 0);
    nvic_irq_enable(DMA0_Channel4_IRQn, 0, 1);
}

这里要特别注意是dma_interrupt_enable(DMA0, DMA_CH3, DMA_INT_FTF);,必须要在dma_deinit(DMA0, DMA_CH3);这个函数的后面。如果他们两个顺序反了,就会无法成功开启中断。

dma_deinit(DMA0, DMA_CH3);该函数主要是将DMA0的通道3去初始化,后面会接着dma_init函数。该函数主要将各种寄存器数值重置为0,有点类似于计算器的归0。
在这里插入图片描述
在这里插入图片描述
在函数内部会将0赋值给CHCTL寄存器,这个寄存器很重要。看数据手册,CHCTL是通道控制寄存器,bit0是CHEN通道使能位,bit1时FTFIE通道传输完成中断使能为,bit2是HTFIE通道半传输完成中断使能,bit3是ERRIE通道错误中断使能位。所以中断使能函数操作的就是该寄存器的某个位。
在这里插入图片描述
在这里插入图片描述
dma_interrupt_enable(DMA0, DMA_CH3, DMA_INT_FTF);该函数主要是开启DMA通道的中断,DMA_INT_FTF开启的是通道传输完成中断。如下所示,主要是CHCTL寄存器赋值,也就是将CHCTL的bit1置1。
在这里插入图片描述
到这里,我就看出来了。我在配置DMA通道中断的过程中,将dma_interrupt_enable(DMA0, DMA_CH3, DMA_INT_FTF);提前了,想着和nvic_irq_enable函数凑在一起,都是使能中断,看起来顺眼,没想到不能提前开启中断。
在这里插入图片描述
与上述函数类似不能放在前面的还有dma_channel_enable函数。
在这里插入图片描述
仅此记录。

<think>好的,用户的问题是关于如何在GD32微控制器上实现串口DMA发送和接收中断的功能,需要示例代码和参考文档。首先,我需要回顾一下GD32和STM32的相似性,因为用户提供的引用内容提到了STM32DMA配置问题,而GD32可能与STM32有类似的架构,但可能存在一些差异。 首先,用户提到的引用[1]是关于RT-Thread在GD32F4xx上的USART驱动DMA接收,里面提到了修改drv_usart.c驱动,增加DMA通道和相关函数。这可能涉及到配置DMA通道、初始化顺序以及中断处理的问题。引用[2]讨论了STM32DMA配置问题,比如参数配置不正确、中断处理不当、初始化顺序错误等,这些点同样适用于GD32,需要注意。而引用[3]提到STM32的CAN控制器不支持DMA,但用户的问题是关于串口的,所以这个引用可能不太相关,但需要确认GD32串口是否支持DMA。 接下来,我需要整理实现步骤。根据引用内容,配置DMA发送和接收通常包括以下几个步骤:初始化串口、配置DMA通道、设置中断服务函数、启用DMA传输。同时,需要注意初始化顺序,比如DMA是否需要在串口初始化之前配置,避免冲突。另外,中断处理中不能有延时操作,否则会导致数据丢失,这点引用[2]提到过。 在代码示例方面,用户可能需要参考GD32的标准库函数,比如gd32f4xx_usart.c和gd32f4xx_dma.c。需要确认DMA通道与串口的对应关系,例如USART0的发送和接收对应的DMA通道是什么,这可能需要查阅GD32的数据手册或用户手册。例如,USART0_TX可能使用DMA0通道x,USART0_RX使用DMA0通道y。 此外,接收中断的实现可能涉及到使能串口空闲中断,在中断服务函数中处理接收完成的数据,并重新配置DMA缓冲区。引用[1]中提到在应用测试中遇到的问题,比如FinSH控制台初始化失败和数据错误,这可能与DMA缓冲区的配置或中断处理有关,需要确保DMA缓冲区的大小足够,并且数据指针正确。 用户可能需要示例代码展示如何初始化USARTDMA,配置中断,以及处理发送和接收。例如,初始化函数中配置USART参数,使能DMA发送和接收,配置DMA的源地址、目标地址、传输方向、数据宽度等。然后,在中断服务函数中,检查传输完成标志,处理数据,并重新启动DMA接收以持续监听。 参考文档方面,用户提供的引用[1]和[2]已经涉及GD32和STM32DMA配置,可能需要补充GD32官方提供的资料,比如GD32F4xx的用户手册、DMAUSART章节,以及RT-Thread的相关驱动文档。此外,GD32的标准外设库示例代码可能提供DMAUSART的配置范例,这也是重要的参考资料。 最后,需要确保生成的代码符合GD32的具体型号,比如GD32F4xx,因为不同型号的DMA通道分配可能不同。同时,注意在DMA发送和接收过程中,缓冲区的管理,避免数据覆盖或溢出,特别是在接收中断中,可能需要使用双缓冲区或循环模式来确保数据的连续性。 总结步骤: 1. 初始化USART,配置波特率、数据位等参数。 2. 配置DMA发送和接收通道,设置正确的源/目标地址,传输长度,方向等。 3. 使能USARTDMA发送和接收请求。 4. 配置中断服务函数,处理DMA传输完成和USART空闲中断。 5. 在接收中断中,处理数据并重新启动DMA接收。 6. 测试时注意初始化顺序,避免外设依赖问题。</think>### GD32串口DMA发送及接收中断实现方法 #### 一、硬件配置要点 1. **DMA通道分配**:需查阅芯片手册确认USART对应DMA通道,例如GD32F4xx中USART0_TX使用DMA0通道3,USART0_RX使用DMA0通道2[^1] 2. **中断优先级**:接收中断需配置NVIC优先级,确保实时性 #### 二、实现步骤 **1. 初始化USART外设** ```c void usart_config(void) { /* 配置USART参数 */ usart_deinit(USART0); usart_baudrate_set(USART0, 115200U); usart_word_length_set(USART0, USART_WL_8BIT); usart_stop_bit_set(USART0, USART_STB_1BIT); usart_parity_config(USART0, USART_PM_NONE); usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE); usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE); usart_receive_config(USART0, USART_RECEIVE_ENABLE); usart_transmit_config(USART0, USART_TRANSMIT_ENABLE); usart_enable(USART0); } ``` **2. 配置DMA发送** ```c void dma_tx_config(uint8_t *buffer, uint32_t length) { dma_parameter_struct dma_init_struct; dma_deinit(DMA0, DMA_CH3); dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL; dma_init_struct.memory_addr = (uint32_t)buffer; dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT; dma_init_struct.number = length; dma_init_struct.periph_addr = (uint32_t)&USART_DATA(USART0); dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; dma_init_struct.priority = DMA_PRIORITY_HIGH; dma_init(DMA0, DMA_CH3, &dma_init_struct); usart_dma_transmit_config(USART0, USART_DENT_ENABLE); dma_channel_enable(DMA0, DMA_CH3); } ``` **3. 配置DMA接收中断** ```c // DMA接收配置 void dma_rx_config(uint8_t *buffer, uint32_t length) { dma_parameter_struct dma_init_struct; dma_deinit(DMA0, DMA_CH2); dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY; dma_init_struct.memory_addr = (uint32_t)buffer; dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT; dma_init_struct.number = length; dma_init_struct.periph_addr = (uint32_t)&USART_DATA(USART0); dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH; dma_init(DMA0, DMA_CH2, &dma_init_struct); usart_dma_receive_config(USART0, USART_DENR_ENABLE); dma_interrupt_enable(DMA0, DMA_CH2, DMA_INT_FTF); // 配置NVIC nvic_irq_enable(DMA0_Channel2_IRQn, 1, 0); dma_channel_enable(DMA0, DMA_CH2); } // 中断服务函数 void DMA0_Channel2_IRQHandler(void) { if(dma_interrupt_flag_get(DMA0, DMA_CH2, DMA_INT_FLAG_FTF)) { dma_interrupt_flag_clear(DMA0, DMA_CH2, DMA_INT_FLAG_FTF); // 处理接收完成数据 process_rx_data(); // 重新配置DMA接收 dma_channel_disable(DMA0, DMA_CH2); dma_flag_clear(DMA0, DMA_CH2, DMA_FLAG_FTF); dma_channel_enable(DMA0, DMA_CH2); } } ``` #### 三、关键注意事项 1. **初始化顺序**:先初始化DMA再初始化USART外设,避免配置冲突[^2] 2. **缓冲区管理**:接收缓冲区建议使用双缓冲机制防止数据覆盖 3. **空闲中断检测**:可结合USART空闲中断判断帧结束: ```c usart_interrupt_enable(USART0, USART_INT_IDLE); ``` #### 四、参考文档 1. GD32F4xx用户手册DMA控制器章节 2. RT-Thread GD32F4xx USART驱动实现说明[^1] 3. GD32标准外设库示例代码`GD32F4xx_Firmware_Library_V2.1.2\Examples\DMA\USART_DMA`
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值