GD32F4xx关于DMA串口收发
F4xx手册描述8个串口都支持DMA传输,但是实际使用过程中,当1和7都用的话,始终有一个有异常。无法发送,接收正常。不知道大家有遇到过没。本帖最后由 suifengkm 于 2024-4-2 15:15 编辑
这是初始化代码
//串口1初始化
void usart1_init(u32 bound)
{
dma_single_data_parameter_struct dma_init_struct;
/* enable USART clock */
rcu_periph_clock_enable(RCU_USART1);
/* configure the USART1Tx pin and USART1 Rx pin */
gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_2);
gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_3);
/* configure USART1 Tx as alternate function push-pull */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_2|GPIO_PIN_3);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_2|GPIO_PIN_3);
/* USART configure */
usart_deinit(USART1);
usart_baudrate_set(USART1, bound);
usart_receive_config(USART1, USART_RECEIVE_ENABLE);
usart_transmit_config(USART1, USART_TRANSMIT_ENABLE);
usart_enable(USART1);
/* enable DMA0 */
rcu_periph_clock_enable(RCU_DMA0);
/* deinitialize DMA channel6(USART1 tx) */
dma_deinit(DMA0, DMA_CH6); //dma寄存器初始化
dma_init_struct.direction = DMA_MEMORY_TO_PERIPH; //传输模式,存储到外设(发送)
dma_init_struct.memory0_addr = (uint32_t)gUsart1.txBuff1; //dma内存地址
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; //内存地址增量模式
dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT; //dma外设宽度8位
dma_init_struct.number = USART_LEN_TX_1; //长度
dma_init_struct.periph_addr = (uint32_t)&USART_DATA(USART1); //外设基地址
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; //外设地址增量禁用
dma_init_struct.priority = DMA_PRIORITY_HIGH; //优先级高
dma_single_data_mode_init(DMA0, DMA_CH6, &dma_init_struct);
/* configure DMA mode */
dma_circulation_disable(DMA0, DMA_CH6); //循环模式禁用
dma_channel_subperipheral_select(DMA0, DMA_CH6, DMA_SUBPERI4); //通道6外设4USART1_TX
dma_interrupt_enable(DMA0, DMA_CH6, DMA_CHXCTL_FTFIE); //传输完成中断
nvic_irq_enable(DMA0_Channel6_IRQn, 5, 0); //5 抢占优先级,(组4只有抢占优先级)
usart_dma_transmit_config(USART1, USART_TRANSMIT_DMA_ENABLE);
/* deinitialize DMA0 channel5 (USART1 rx) */
dma_deinit(DMA0, DMA_CH5);
dma_init_struct.direction = DMA_PERIPH_TO_MEMORY; //传输模式,外设到存储(接收)
dma_init_struct.memory0_addr = (uint32_t)gUsart1.rxBuff1;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.number = USART_LEN_RX_1;
dma_init_struct.periph_addr = (uint32_t)&USART_DATA(USART1);
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_single_data_mode_init(DMA0, DMA_CH5, &dma_init_struct);
/* configure DMA mode */
dma_circulation_disable(DMA0, DMA_CH5);
dma_channel_subperipheral_select(DMA0, DMA_CH5, DMA_SUBPERI4);
usart_interrupt_enable(USART1, USART_INT_IDLE);
/* USART interrupt configuration */
nvic_irq_enable(USART1_IRQn, 4, 0);
/* enable DMA1 channel5 */
dma_channel_enable(DMA0, DMA_CH5);
usart_dma_receive_config(USART1, USART_RECEIVE_DMA_ENABLE);
}
//串口1 DMA接收,只触发空闲中断
void USART1_IRQHandler(void){
if(RESET != usart_flag_get(USART1, USART_FLAG_IDLE))
{
USART_STAT0(USART1);
usart_data_receive(USART1); //清除串口中断
gUsart1.RevLen1 = USART_LEN_RX_1 - dma_transfer_number_get(DMA0, DMA_CH5);
dma_channel_disable(DMA0, DMA_CH5);
dma_transfer_number_config(DMA0, DMA_CH5, USART_LEN_RX_1);
dma_flag_clear(DMA0,DMA_CH5,DMA_INTF_FTFIF); //清除dma中断
dma_channel_enable(DMA0, DMA_CH5);
//测试代码
// printf("Usart1:%d %s\r\n",gUsart1.RevLen1,gUsart1.rxBuff1);
// memcpy((u8 *)gUsart1.txBuff1,(u8 *)gUsart1.rxBuff1,gUsart1.RevLen1);
// usartSend(1,gUsart1.RevLen1);
if(!gEppFlag.isUsart1)
{
gEppFlag.isUsart1 = TRUE;
gRevLen1 = gUsart1.RevLen1;
memset((u8 *)gRevBuf1,0, USART_LEN_RX_1);
memcpy((u8 *)gRevBuf1,(u8 *)gUsart1.rxBuff1,gRevLen1);
memset((u8 *)gUsart1.rxBuff1,0, USART_LEN_RX_1);
}
}
}
//dma中断 串口1 发送完成
void DMA0_Channel6_IRQHandler(void)
{
if(dma_interrupt_flag_get(DMA0, DMA_CH6, DMA_INT_FLAG_FTF))
{
dma_interrupt_flag_clear(DMA0, DMA_CH6, DMA_INT_FLAG_FTF);
dma_flag_clear(DMA0,DMA_CH6,DMA_INTF_FTFIF);
}
gEppFlag.isTxUsart1 = FALSE;
}
//串口7初始化
void usart7_init(u32 bound)
{
dma_single_data_parameter_struct dma_init_struct;
/* enable USART clock */
rcu_periph_clock_enable(RCU_UART7);
/* configure the UART7 Tx pin and USART7 Rx pin */
gpio_af_set(GPIOE, GPIO_AF_8, GPIO_PIN_1);
gpio_af_set(GPIOE, GPIO_AF_8, GPIO_PIN_0);
/* configure USART5 Tx as alternate function push-pull */
gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_0|GPIO_PIN_1);
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_0|GPIO_PIN_1);
/* USART configure */
usart_deinit(UART7);
usart_baudrate_set(UART7, bound);
usart_receive_config(UART7, USART_RECEIVE_ENABLE);
usart_transmit_config(UART7, USART_TRANSMIT_ENABLE);
usart_enable(UART7);
/* enable DMA0 */
rcu_periph_clock_enable(RCU_DMA0);
/* deinitialize DMA channel0(UART7 tx) */
dma_deinit(DMA0, DMA_CH0); //dma寄存器初始化
dma_init_struct.direction = DMA_MEMORY_TO_PERIPH; //传输模式,存储到外设(发送)
dma_init_struct.memory0_addr = (uint32_t)gUsart7.txBuff7; //dma内存地址
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; //内存地址增量模式
dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT; //dma外设宽度8位
dma_init_struct.number = USART_LEN_TX_7; //长度
dma_init_struct.periph_addr = (uint32_t)&USART_DATA(UART7); //外设基地址
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; //外设地址增量禁用
dma_init_struct.priority = DMA_PRIORITY_HIGH; //优先级高
dma_single_data_mode_init(DMA0, DMA_CH0, &dma_init_struct);
/* configure DMA mode */
dma_circulation_disable(DMA0, DMA_CH0); //循环模式禁用
dma_channel_subperipheral_select(DMA0, DMA_CH0, DMA_SUBPERI5); //通道0外设5UART7_TX
dma_interrupt_enable(DMA0, DMA_CH0, DMA_CHXCTL_FTFIE); //传输完成中断
nvic_irq_enable(DMA0_Channel0_IRQn, 11, 0); //5 抢占优先级,(组4只有抢占优先级)
usart_dma_transmit_config(UART7, USART_TRANSMIT_DMA_ENABLE);
/* deinitialize DMA0 channel6 (UART7 rx) */
dma_deinit(DMA0, DMA_CH6);
dma_init_struct.direction = DMA_PERIPH_TO_MEMORY; //传输模式,外设到存储(接收)
dma_init_struct.memory0_addr = (uint32_t)gUsart7.rxBuff7;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.number = USART_LEN_RX_7;
dma_init_struct.periph_addr = (uint32_t)&USART_DATA(UART7);
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_single_data_mode_init(DMA0, DMA_CH6, &dma_init_struct);
/* configure DMA mode */
dma_circulation_disable(DMA0, DMA_CH6);
dma_channel_subperipheral_select(DMA0, DMA_CH6, DMA_SUBPERI5);
usart_interrupt_enable(UART7, USART_INT_IDLE);
/* USART interrupt configuration */
nvic_irq_enable(UART7_IRQn, 10, 0);
/* enable DMA0 channel1 */
dma_channel_enable(DMA0, DMA_CH6);
usart_dma_receive_config(UART7, USART_RECEIVE_DMA_ENABLE);
}
//串口7 DMA接收,只触发空闲中断
void UART7_IRQHandler(void){
if(RESET != usart_flag_get(UART7, USART_FLAG_IDLE))
{
USART_STAT0(UART7);
usart_data_receive(UART7); //清除串口中断
gUsart7.RevLen7 = USART_LEN_RX_7 - dma_transfer_number_get(DMA0, DMA_CH6);
dma_channel_disable(DMA0, DMA_CH6);
dma_transfer_number_config(DMA0, DMA_CH6, USART_LEN_RX_7);
dma_flag_clear(DMA0,DMA_CH6,DMA_INTF_FTFIF); //清除dma中断
dma_channel_enable(DMA0, DMA_CH6);
printf("Usart7:%d %s\r\n",gUsart7.RevLen7,gUsart7.rxBuff7);
memcpy((u8 *)gUsart7.txBuff7,(u8 *)gUsart7.rxBuff7,gUsart7.RevLen7);
usartSend(7,gUsart7.RevLen7);
if(!gEppFlag.isUsart7)
{
gEppFlag.isUsart7 = TRUE;
gRevLen7 = gUsart7.RevLen7;
memset((u8 *)gRevBuf7,0, USART_LEN_RX_7);
memcpy((u8 *)gRevBuf7,(u8 *)gUsart7.rxBuff7,gRevLen7);
memset((u8 *)gUsart7.rxBuff7,0, USART_LEN_RX_7);
}
}
}
//dma中断 串口7 发送完成
void DMA0_Channel0_IRQHandler(void)
{
if(dma_interrupt_flag_get(DMA0, DMA_CH0, DMA_INT_FLAG_FTF))
{
dma_interrupt_flag_clear(DMA0, DMA_CH0, DMA_INT_FLAG_FTF);
dma_flag_clear(DMA0,DMA_CH0,DMA_INTF_FTFIF);
}
gEppFlag.isTxUsart7 = FALSE;
}
//串口发送数据
void usartSend(u8 usaetId, u16 sendLen)
{
if(sendLen != 0) //不管哪个串口,不能发送空操作。
{
switch(usaetId)
{
case 1:
{
gEppFlag.isTxUsart1 = TRUE; //置端口使用状态,在发送完成中断清零 PC
dma_transfer_number_config(DMA0, DMA_CH6,sendLen); //设置发送长度
dma_channel_enable(DMA0, DMA_CH6); //开启发送
break;
}
case 7:
{
gEppFlag.isTxUsart7 = TRUE; //置端口使用状态,在发送完成中断清零 高压板
dma_transfer_number_config(DMA0, DMA_CH0,sendLen); //设置发送长度
dma_channel_enable(DMA0, DMA_CH0); //开启发送
break;
}
default:
break;
}
}
}
结贴:左边的列是用于区分哪个外设的,同个通道同时只有一个外设有效。即右边画圈的串口。不能同时使用。需要分时。
在 STM32F4 系列中,不同的 USART 通道使用不同的 DMA 流。检查是否正确配置了每个 USART 的 DMA 流和通道。 如果某个 DMA 通道被禁用或没有正确配置,可能会导致数据传输失败。 suifengkm 发表于 2024-4-3 14:19
结贴:左边的列是用于区分哪个外设的,同个通道同时只有一个外设有效。即右边画圈的串口。不能同时使用。需 ...
你好我想问一下,这个分时该如何分时使用? 林白给 发表于 2024-8-2 11:26
你好我想问一下,这个分时该如何分时使用?
我现在GDF470的八个串口都使用了,然后有些串口的dma接收和发送通道是共用一个通道,导致通道中断也是共用的,我想问一下如何分时使用 本帖最后由 林白给 于 2024-8-2 11:33 编辑
C:\Users\linhy\Desktop 林白给 发表于 2024-8-2 11:30
我现在GDF470的八个串口都使用了,然后有些串口的dma接收和发送通道是共用一个通道,导致通道中断也是共 ...
分时只是厂商忽悠人的。最终应用的时候基本上无法使用。比如你A口再用的时候。B口接收数据是无效的。最终还是只能用一个。目前我们使用的方法是六个串口dma。2个数据量小的。使用中断收发。
页:
[1]