最近使用stm32f743VIT6 DMA通过空闲中断接收不定长度的字节。有个现象很奇怪,我接收GPS下发的数据的时候,使用的串口2的DMA的空闲中断来接收,(一般情况下GPS发出来的数据都是每秒钟一帧,美帧数据大约几百个字节),要么接收到1个字节就空闲中断了,要么就根本接收不到。 然后我换成用PC机模拟GPS通过USB转TTL 的线下发数据到串口2,这个时候能完整无误的接收到数据,无论下发的数据字节有多少都能 完整无误的接收到。 我把我的串口的配置和中断处理贴出来,希望有知道原因的大牛指点指点。谢谢 说明一下, 以上我做实验都是通过串口2接收的数据,然后用串口3转发接收的数据到PC机上来观察的。 以下是 串口1 和串口2和串口3 的初始化配置: void HAL_UART_MspInit(UART_HandleTypeDef *huart) { static DMA_HandleTypeDef U1hdma_tx; static DMA_HandleTypeDef U1hdma_rx; static DMA_HandleTypeDef U2hdma_tx; static DMA_HandleTypeDef U2hdma_rx; static DMA_HandleTypeDef U3hdma_tx; static DMA_HandleTypeDef U3hdma_rx; GPIO_InitTypeDef GPIO_InitStruct; RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit; if(huart->Instance==USART1) { USARTx_TX_GPIO_CLK_ENABLE(); RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART16; RCC_PeriphClkInit.Usart16ClockSelection = RCC_USART16CLKSOURCE_D2PCLK2; HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit); USARTx_CLK_ENABLE(); DMAx_CLK_ENABLE(); GPIO_InitStruct.Pin = USARTx_TX_PIN; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = USARTx_TX_AF; HAL_GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStruct); GPIO_InitStruct.Pin = USARTx_RX_PIN; GPIO_InitStruct.Alternate = USARTx_RX_AF; HAL_GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStruct); U1hdma_tx.Instance = USARTx_TX_DMA_STREAM; U1hdma_tx.Init.Request = USARTx_TX_DMA_CHANNEL; U1hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; U1hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE; U1hdma_tx.Init.MemInc = DMA_MINC_ENABLE; U1hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; U1hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; U1hdma_tx.Init.Mode = DMA_NORMAL; U1hdma_tx.Init.Priority = DMA_PRIORITY_LOW; U1hdma_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; U1hdma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; U1hdma_tx.Init.MemBurst = DMA_MBURST_INC4; U1hdma_tx.Init.PeriphBurst = DMA_PBURST_INC4; HAL_DMA_Init(&U1hdma_tx); __HAL_LINKDMA(huart, hdmatx, U1hdma_tx); HAL_NVIC_SetPriority(USARTx_DMA_TX_IRQn, 3, 1); HAL_NVIC_EnableIRQ(USARTx_DMA_TX_IRQn); HAL_NVIC_SetPriority(USARTx_IRQn, 3, 1); HAL_NVIC_EnableIRQ(USARTx_IRQn); } if(huart->Instance==USART2) { UsartG_RX_GPIO_CLK_ENABLE(); RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2; RCC_PeriphClkInit.Usart234578ClockSelection = RCC_USART2CLKSOURCE_D2PCLK1; HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit); __HAL_RCC_USART2_CLK_ENABLE(); __HAL_RCC_DMA1_CLK_ENABLE(); GPIO_InitStruct.Pin = UsartG_TX_PIN; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Alternate = UsartG_TX_AF; HAL_GPIO_Init(UsartG_TX_GPIO_PORT, &GPIO_InitStruct); GPIO_InitStruct.Pin = UsartG_RX_PIN; GPIO_InitStruct.Alternate = UsartG_RX_AF; HAL_GPIO_Init(UsartG_RX_GPIO_PORT, &GPIO_InitStruct); U2hdma_rx.Instance = UsartG_RX_DMA_STREAM; U2hdma_rx.Init.Request = UsartG_RX_DMA_CHANNEL; U2hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; U2hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE; U2hdma_rx.Init.MemInc = DMA_MINC_ENABLE; U2hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; U2hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; U2hdma_rx.Init.Mode = DMA_NORMAL; U2hdma_rx.Init.Priority = DMA_PRIORITY_HIGH; U2hdma_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; U2hdma_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; U2hdma_rx.Init.MemBurst = DMA_MBURST_INC4; U2hdma_rx.Init.PeriphBurst = DMA_PBURST_INC4; HAL_DMA_Init(&U2hdma_rx); __HAL_LINKDMA(huart, hdmarx, U2hdma_rx); HAL_NVIC_SetPriority(UsartG_DMA_RX_IRQn, 0, 0); HAL_NVIC_EnableIRQ(UsartG_DMA_RX_IRQn); HAL_NVIC_SetPriority(UsartG_IRQn, 0, 0); HAL_NVIC_EnableIRQ(UsartG_IRQn); } if(huart->Instance==USART3) { UsartX_TX_GPIO_CLK_ENABLE(); RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART3; RCC_PeriphClkInit.Usart234578ClockSelection = RCC_USART3CLKSOURCE_D2PCLK1; HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit); UsartX_CLK_ENABLE(); DMAX_CLK_ENABLE(); GPIO_InitStruct.Pin = UsartX_TX_PIN; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Alternate = UsartX_TX_AF; HAL_GPIO_Init(UsartX_TX_GPIO_PORT, &GPIO_InitStruct); U3hdma_tx.Instance = UsartX_TX_DMA_STREAM; U3hdma_tx.Init.Request = UsartX_TX_DMA_CHANNEL; U3hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; U3hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE; U3hdma_tx.Init.MemInc = DMA_MINC_ENABLE; U3hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; U3hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; U3hdma_tx.Init.Mode = DMA_NORMAL; U3hdma_tx.Init.Priority = DMA_PRIORITY_LOW; U3hdma_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; U3hdma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; U3hdma_tx.Init.MemBurst = DMA_MBURST_INC4; U3hdma_tx.Init.PeriphBurst = DMA_PBURST_INC4; HAL_DMA_Init(&U3hdma_tx); __HAL_LINKDMA(huart, hdmatx, U3hdma_tx); HAL_NVIC_SetPriority(UsartX_DMA_TX_IRQn, 1, 1); HAL_NVIC_EnableIRQ(UsartX_DMA_TX_IRQn); HAL_NVIC_SetPriority(UsartX_IRQn, 1, 1); HAL_NVIC_EnableIRQ(UsartX_IRQn); } } 以下是串口2的中断处理: 注: GPS_UartHandle 是处理处理GPS 接收数据的一个Handle ,也就是串口2 void Usart2_IRQHandler(void) { uint32_t tmp_flag = 0; uint32_t temp; //HAL_UART_IRQHandler(&GPS_UartHandle); tmp_flag = __HAL_UART_GET_FLAG(&GPS_UartHandle,UART_FLAG_IDLE); // 这里是获取空闲标志 if((tmp_flag ==SET)) { __HAL_UART_CLEAR_IDLEFLAG(&GPS_UartHandle); // 清除空闲标志 temp=__HAL_DMA_GET_COUNTER(GPS_UartHandle.hdmarx); // 获取接收缓存的剩余字节数 HAL_UART_DMAStop(&GPS_UartHandle); /// 停止 串口2的DMA接收 rx_len = (RXBUFFERSIZE - temp); // 计算 接收到的数据长度 recv_end_flag = 1; // 置位接收完成标志,在main中提示处理接收到的数据 temp =0; } __HAL_UART_CLEAR_IT(&GPS_UartHandle,UART_CLEAR_PEF // 清除 其他的中断标志 等 |UART_CLEAR_FEF |UART_CLEAR_NEF |UART_CLEAR_OREF //|UART_CLEAR_IDLEF |UART_CLEAR_TCF |UART_CLEAR_LBDF |UART_CLEAR_CTSF |UART_CLEAR_RTOF |UART_CLEAR_WUF |UART_CLEAR_CMF |UART_CLEAR_TXFECF); } 恳请 知道原因的大牛指点一二,谢谢 |
还有一个,你在串口中断处理函数里只有停止DMA的操作,怎么没有再次打开DMA的操作呢?不再次打开怎么能够接收新数据呢?
评分
查看全部评分
说了多少次不要用空闲中断+DMA方式
能这么用的必须保证发送方也是DMA方式发送,且DMA优先级最高。否则一旦发送被打断,你接收端就认为空闲中断了,于是错了。
能用空闲+DMA的应用场景在于大数据传输之前,先通过简单串口协议交互,把数据信息准备好,然后启用DMA定长传输数据,传输完成后切换到普通模式,亦或者两个串口,一个走命令一个走大数据
评分
查看全部评分
串口中断接收数据放入fifo,再找合适的时机处理即可。
DMA的两个中断 TC及HT都要用上
这三个中断只应用作, 告诉你buf里有新来的数据, 而不能以IDLE中断来代替数据包的解析
评分
查看全部评分
GPS是标准的串口输出,我看了两个字节是连贯的,另外我开DMA的操作是在 main里面对数据处理了以后再开的
接收不定长度的是字节不用DMA+空闲还有其他方式吗,主要是我通过USB转TTL 的线在PC上模拟下发数据的时候也是正常的,如果是DMA被中断了的话那么说这种方式应该是不正常或者不能够接收到完整的数据。
你的意思是说我再空闲中断的处理函数中判断 DMA 通道的TC 中断标志是不是置位,如果置位才表示一帧数据接收完毕了对了?还要判断HT 这个中断标志,这个标志是半传输完成标志,?这个怎么操作,您有合适的例子吗,能给我发一个吗? 4094359@qq.com
谢谢, 中断接收放入FIFO 这个不错我可以试试。
空闲+DMA被打断也没有什么问题吧
评分
查看全部评分
可以到是可以,这样子就要把接收字节数设置到最大,远远大于GPS下发一帧数据的最大字节数,也使用DMA来接收,这样子就是处理的效率不高,可能FIFO中存储的是不完整的两帧数据。
现在主要的问题是用一块单片机模拟GPS发送数据,另外一块板子都可以接收到,换成电脑模拟GPS发送数据也能接收到,但是就是换成GPS就是接收不到, (GPS通过USB转串口线发送到电脑上的数据也是正常的,说明GPS也木有问题),可能这个是硬件哪里的问题,。一时不明白
评分
查看全部评分
看你的描述,有点像硬件哪里出了问题,你看看有没有共地啊,给GPS供电后的电压,能不能支持GPS的最小功耗啊之类的,接上去之后,在用逻辑分析仪抓GPS发送到板子里的数据,是不是正确的。。然后在慢慢排除吧。
谢谢,确实是硬件问题。