单片机:STM32F407ZGT6 环境:标准库 使用USART3 在不使用 DMA 传输的情况下,USART3 的波特率可以设置为 921600 甚至更高;但是在添加了DMA 传输之后,波特率只能设置到 230400 了,在往上就会出现乱码了。 整个程序只运行了 USART1 USART3 和 TIM2 外设,没有其他的功能,其中只有 USART3 配置了DMA;请问是USART和DMA的存在问题,还是有其他的原因。 usart.h #ifndef __USART_H__ #define __USART_H__ #include "stm32f4xx.h" /******************************USART3******************************/ #define USART3_DMA_TxBufMaxSize 1024 #define USART3_DMA_RxBufMaxSize 1024 extern uint16_t USART3_RxLen; extern uint8_t USART3_DMA_RxBuf[USART3_DMA_RxBufMaxSize]; static void USART3_DMA_Tx_Init(void); static void USART3_DMA_Rx_Init(void); void USART3_Init(uint32_t bound); void USART3_DMA_SendDatas(uint8_t *data, uint16_t size); /*****************************************************************/ #endif usart.c /************************************************************** *函数:串口3初始化,带DMA传输 TXB10 RXB11 *参数: * @bound:串口波特率 *备注:!!!最高波特率230400 **************************************************************/ void USART3_Init(uint32_t bound) { GPIO_InitTypeDef GPIO_InitStructure; // GPIO配置结构体 USART_InitTypeDef USART_InitStructure; // 串口配置结构体 NVIC_InitTypeDef NVIC_InitStructure; // 中断向量控制器结构体 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE); // GPIOB时钟使能 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); // USART3时钟使能 /* 引脚复用配置 */ GPIO_PinAFConfig(GPIOB,GPIO_PinSource10,GPIO_AF_USART3); GPIO_PinAFConfig(GPIOB,GPIO_PinSource11,GPIO_AF_USART3); /* GPIO配置 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // 配置为复用模式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; // GPIO速率50MHz GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; // 开漏输出 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; // 禁用上下拉 GPIO_Init(GPIOB,&GPIO_InitStructure); // 初始化GPIO /* 串口配置 */ USART_InitStructure.USART_BaudRate = bound; // 波特率 USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 8位数据位 USART_InitStructure.USART_StopBits = USART_StopBits_1; // 1位停止位 USART_InitStructure.USART_Parity = USART_Parity_No; // 无校验位 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无硬件数据流控制 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 发送模式和接收模式 USART_Init(USART3, &USART_InitStructure); // 串口初始化 USART_ClearFlag(USART3, USART_FLAG_TC); USART_ITConfig(USART3, USART_IT_IDLE, ENABLE);// 使能串口空闲中断 /* NVIC配置 */ NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn; // USART1中断同道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2 ; // 抢占优先级 2 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; // 响应优先级 2 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 中断通道使能 NVIC_Init(&NVIC_InitStructure); // NVIC初始化 USART_Cmd(USART3, ENABLE); // 开启串口 USART3_DMA_Tx_Init(); USART3_DMA_Rx_Init(); } /* DMA 发送缓冲区 */ static uint8_t USART3_DMA_TxBuf[USART3_DMA_TxBufMaxSize] = {0}; /************************************************************** *函数:串口3 DMA 发送初始化 *参数:无 *备注:!!!最高波特率230400 **************************************************************/ static void USART3_DMA_Tx_Init(void) { DMA_InitTypeDef DMA_InitStructure; // DMA 初始化结构体 NVIC_InitTypeDef NVIC_InitStructure; // NVIC 初始化结构体,发送完成中断 /* 使能 DMA1 时钟 */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); /* */ DMA_DeInit(DMA1_Stream3); while (DMA_GetCmdStatus(DMA1_Stream3) != DISABLE); DMA_InitStructure.DMA_Channel = DMA_Channel_4; // DMA1 的通道4 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART3->DR; // 外设的地址 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)USART3_DMA_TxBuf; // 内存地址 DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; // 数据方向,内存到外设 DMA_InitStructure.DMA_BufferSize = USART3_DMA_TxBufMaxSize; // 发送缓冲区大小 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址不自增 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存地址自增 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 外设数据长度1字节 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 内存数据长度1字节 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // 正常模式 DMA_InitStructure.DMA_Priority = DMA_Priority_High; // 高优先级 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; // 不使能管道 DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull; // 管道大小 DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; // DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; // DMA_Init(DMA1_Stream3, &DMA_InitStructure); DMA_ITConfig(DMA1_Stream3, DMA_IT_TC, ENABLE); USART_DMACmd(USART3, USART_DMAReq_Tx, ENABLE); NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); while (DMA_GetCmdStatus(DMA1_Stream3) != DISABLE); DMA_Cmd(DMA1_Stream3, DISABLE); } uint8_t USART3_DMA_RxBuf[USART3_DMA_RxBufMaxSize] = {0}; static void USART3_DMA_Rx_Init(void) { DMA_InitTypeDef DMA_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); DMA_DeInit(DMA1_Stream1); while (DMA_GetCmdStatus(DMA1_Stream1) != DISABLE); DMA_InitStructure.DMA_Channel = DMA_Channel_4; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART3->DR; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)USART3_DMA_RxBuf; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = USART3_DMA_RxBufMaxSize; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA1_Stream1, &DMA_InitStructure); USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE); while (DMA_GetCmdStatus(DMA1_Stream1) != DISABLE); DMA_Cmd(DMA1_Stream1, ENABLE); } /************************************************************** *函数:串口3接收中断处理函数、接收中断,空闲中断 **************************************************************/ uint16_t USART3_RxLen = 0; void USART3_IRQHandler(void) { if(USART_GetITStatus(USART3, USART_IT_IDLE) == SET) { USART3->DR; USART3->SR; DMA_Cmd(DMA1_Stream1, DISABLE); USART3_RxLen = USART3_DMA_RxBufMaxSize - DMA_GetCurrDataCounter(DMA1_Stream1); DMA_ClearFlag(DMA1_Stream1, DMA_FLAG_TCIF1 | DMA_FLAG_FEIF1 | DMA_FLAG_DMEIF1 | DMA_FLAG_TEIF1 | DMA_FLAG_HTIF1); DMA_SetCurrDataCounter(DMA1_Stream1, USART3_DMA_RxBufMaxSize); DMA_Cmd(DMA1_Stream1, ENABLE); } if(USART_GetFlagStatus(USART3, USART_IT_TXE) == RESET) { USART_ITConfig(USART3, USART_IT_TC, DISABLE); } } void DMA1_Stream3_IRQHandler(void) { if(DMA_GetFlagStatus(DMA1_Stream3, DMA_FLAG_TCIF3) != RESET) { DMA_ClearFlag(DMA1_Stream3, DMA_FLAG_TCIF3); DMA_Cmd(DMA1_Stream3, DISABLE); USART_ITConfig(USART3, USART_IT_TC, ENABLE); } } void USART3_DMA_SendDatas(uint8_t *data, uint16_t size) { memcpy(USART3_DMA_TxBuf, data, size); while (DMA_GetCmdStatus(DMA1_Stream3) != DISABLE); DMA_SetCurrDataCounter(DMA1_Stream3, size); DMA_Cmd(DMA1_Stream3, ENABLE); } 主函数: int main() { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); led_init(); TIM2_delay_init(); USART1_Init(921600); USART3_Init(230400); while(1) { TIM2_delay_ms(300); led_ctrl(LED0, LED_OFF); USART3_DMA_SendDatas((uint8_t *)"DMA_Test\n", 9); TIM2_delay_ms(300); led_ctrl(LED0, LED_ON); if(USART3_RxLen > 0) { printf("USART3_DMA_Recv %d :%s\n", USART3_RxLen, USART3_DMA_RxBuf); memset(USART3_DMA_RxBuf, '\0', USART3_RxLen); USART3_RxLen = 0; } } } |
外部中断升降沿类型判断
STM32G0B1adc+dma采样数据错位
STM32H7打开DCache后,串口1DMA接受数据位空
定时器正交编码器功能
STM32F427串口接收和发送中断同时使能,出现接收中断丢数的现象。
为什么生成代码时一直卡在generating user source code 救救孩子吧。
STM32 SPI从机用DMA方式实现全双工,数据传输过程中出错。
easylogger打印失败
为什么ETH配置中没有Advanced Parameters?
使用STM32F103控制两步进电机同时进行不同的运动(软件指令驱动),与控制一个电机的不同之处在于哪里?
/* USER CODE END USART3_Init 1 */
huart3.Instance = USART3;
huart3.Init.BaudRate = 921600;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
我刚才模拟的应用场景做了验证测试,使用F407.
开启了TIM2的1ms中断,同时TICK的ms中断也在运行。
UART3的收发都采用DMA方式,测试是没问题的。
我觉得你的代码配置应该没啥问题,怀疑代码处理哪里有些问题,尤其当波特率较高时。具体原因还得你再找找。
我刚刚重新检查了一下代码,一开始是把USART3对应的GPIO配置成了开漏输出,将串口对应的GPIO配置成推挽输出后,波特率就可以支持到921600了。
DMA传输会影响到串口GPIO的驱动能力吗?
DMA应该是被冤枉了。它肯定影响不到GPIO的速率的。
但你UART的复用GPIO配置成PP合理合适,配置为OD比较反常。
这是从另外一块板子上移植的串口代码,之前哪个板子的串口3做rs485接口,外部有上拉,所以当时给配置了开漏,移植的时候忽略这问题了。😕