21ic问答首页 - GD32F303 串口DMA发送问题
GD32F303 串口DMA发送问题
jsrdczy2021-11-22
本帖最后由 jsrdczy 于 2021-11-22 15:55 编辑
兄弟萌,有一个关于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);
//rt_thread_mdelay(3); 这里delay就能发送
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的大佬使用过,一起探讨下,看是否是我哪里配置有啥问题
兄弟萌,有一个关于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);
//rt_thread_mdelay(3); 这里delay就能发送
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的大佬使用过,一起探讨下,看是否是我哪里配置有啥问题
赞0
评论
2021-11-23
您需要登录后才可以回复 登录 | 注册