-
GD32F303 串口DMA发送问题
[i=s] 本帖最后由 jsrdczy 于 2021-11-22 15:55 编辑 [/i] 兄弟萌,有一个关于gd32的串口dma发送问题:场景描述:串口DMA发送数据,一般的做法是开DMA发送完成中断,然后在中断里切换发送状态或者进行下一次传输。 思路描述:如果是485传输,如果用DMA发送完成中断的话,在中断里发送改为接收状态时,可能会丢1个字节。所以沿用之前stm32的做法,打开串口的发送完成中断,利用tc中断在串口中断服务程序中切换状态或者进行下一帧发送。 问题:之前stm32的工程就是用串口tc发送完成中断来标识发送完成的,但是同样的做法在gd32上,虽然能够进行入tc中断,但是发送出来的数据完全不对。解决办法:dma通道使能后delay 3个ms 就可以发送正确发送了,和开dma或者串口tc中断没有关系。 贴一部分代码: DMA配置: static void gd32_dma_config(struct rt_serial_device *serial, rt_ubase_t flag) { struct dma_config *dma_config; struct gd32_uart *uart; dma_parameter_struct dma_init_struct; RT_ASSERT(serial != RT_NULL); uart = (struct gd32_uart *)serial->parent.user_data; if (RT_DEVICE_FLAG_DMA_TX == flag) { dma_config = uart->dma_tx; } else if(RT_DEVICE_FLAG_DMA_RX == flag) { return ; // no support temporarily } //enable dma clock rcu_periph_clock_enable(dma_config->dma_rcu); //initillize DMA channel dma_deinit(dma_config->dma_periph, dma_config->channel); dma_struct_para_init(&dma_init_struct); dma_channel_disable(uart->dma_tx->dma_periph,uart->dma_tx->channel); dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL; dma_init_struct.memory_addr = RT_NULL; dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT; dma_init_struct.number = 0; dma_init_struct.periph_addr = (uint32_t)&USART_DATA(uart->uart_periph); 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(dma_config->dma_periph, dma_config->channel, &dma_init_struct); dma_circulation_disable(dma_config->dma_periph, dma_config->channel); dma_memory_to_memory_disable(dma_config->dma_periph, dma_config->channel); if (RT_DEVICE_FLAG_DMA_TX == flag) { usart_flag_clear(uart->uart_periph, USART_FLAG_TC); //clear flag dma_interrupt_flag_clear(uart->dma_tx->dma_periph, uart->dma_tx->channel,DMA_FLAG_G); /* enable rx irq */ NVIC_EnableIRQ(uart->irqn); /* enable interrupt */ usart_interrupt_enable(uart->uart_periph, USART_INT_TC); //uart tc send complete interrupt usart_dma_transmit_config(uart->uart_periph, USART_DENT_ENABLE); } #endif } DMA发送 static rt_size_t gd32_dma_transmit(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction) { struct gd32_uart *uart; RT_ASSERT(serial != RT_NULL); RT_ASSERT(buf != RT_NULL); uart = (struct gd32_uart *)serial->parent.user_data; struct rt_serial_tx_dma *tx_dma; tx_dma = (struct rt_serial_tx_dma*)(serial->serial_tx); if (size == 0) { return 0; } if (RT_SERIAL_DMA_TX == direction) { dma_channel_disable(uart->dma_tx->dma_periph,uart->dma_tx->channel); dma_interrupt_flag_clear(uart->dma_tx->dma_periph, uart->dma_tx->channel,DMA_FLAG_G); usart_flag_clear(uart->uart_periph, USART_FLAG_TC); //clear flag dma_memory_address_config(uart->dma_tx->dma_periph,uart->dma_tx->channel,(uint32_t)buf); dma_transfer_number_config(uart->dma_tx->dma_periph,uart->dma_tx->channel,size); dma_channel_enable(uart->dma_tx->dma_periph,uart->dma_tx->channel); [color=#ff0000]//rt_thread_mdelay(3); 这里delay就能发送[/color] return size; } return 0; } 串口发送完成中断(tc)处理: static void uart_isr(struct rt_serial_device *serial) { struct gd32_uart *uart = (struct gd32_uart *) serial->parent.user_data; rt_base_t level; rt_size_t trans_total_index; RT_ASSERT(uart != RT_NULL); /* UART in mode Receiver -------------------------------------------------*/ if ((usart_interrupt_flag_get(uart->uart_periph, USART_INT_FLAG_RBNE) != RESET) && (usart_flag_get(uart->uart_periph, USART_FLAG_RBNE) != RESET)) { rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND); /* Clear RXNE interrupt flag */ usart_flag_clear(uart->uart_periph, USART_FLAG_RBNE); } /* UART in mode Transmiter -------------------------------------------------*/ if ((usart_interrupt_flag_get(uart->uart_periph, USART_INT_FLAG_TC) != RESET) && (usart_flag_get(uart->uart_periph, USART_FLAG_TC) != RESET)) { if(dma_flag_get(uart->dma_tx->dma_periph, uart->dma_tx->channel,DMA_FLAG_FTF) == SET) { rt_hw_serial_isr(serial, RT_SERIAL_EVENT_TX_DMADONE); dma_interrupt_flag_clear(uart->dma_tx->dma_periph, uart->dma_tx->channel,DMA_FLAG_G); } /* Clear TC interrupt flag */ usart_flag_clear(uart->uart_periph, USART_FLAG_TC); } } 目前的现象就是tc中断可以进,发出来的字节数也对,但是内容除了头2个字节,其余的字节全都不对。换成DMA发送完成中断也是杨的现象 那位用gd32的大佬使用过,一起探讨下,看是否是我哪里配置有啥问题
2319浏览量 1回复量 关注量