**STM32f427 UART with DMA** 从控制台接收数据时最高位有时为1
**STM32f427 UART with DMA** The highest bit sometimes is 1 when receive data from console
我在使用带 DMA 的 STM32f427 UART(使用 stm cube HAL 库)时遇到问题。
我想做一个控制台回显功能,所以我在uart空闲中断处理函数中立即回复接收到的数据。
但有时,当我在键盘上输入任何键时,接收到的数据的最高位将是1。
比如关注
0x31 -> 0xB1
0x32 -> 0xB2
0x40 -> 0xC0
有人知道吗?代码段如下。
非常感谢。
我的串口配置如下
uart_handler.Instance = USARTx;
uart_handler.Init.BaudRate = baudrate;
uart_handler.Init.WordLength = UART_WORDLENGTH_8B;
uart_handler.Init.StopBits = UART_STOPBITS_1;
uart_handler.Init.Parity = UART_PARITY_NONE;
uart_handler.Init.HwFlowCtl = UART_HWCONTROL_NONE;
uart_handler.Init.Mode = UART_MODE_TX_RX;
uart_handler.Init.OverSampling = UART_OVERSAMPLING_8;
我的PIN和DMA通道配置如下
GPIO_InitStruct.Pin = USARTx_TX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = USARTx_TX_AF;
HAL_GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = USARTx_RX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Alternate = USARTx_RX_AF;
HAL_GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStruct);
hdma_tx.Instance = USARTx_TX_DMA_STREAM;
hdma_tx.Init.Channel = USARTx_TX_DMA_CHANNEL;
hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_tx.Init.Mode = DMA_NORMAL;
hdma_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_tx.Init.MemBurst = DMA_MBURST_INC16;
hdma_tx.Init.PeriphBurst = DMA_MBURST_INC16;
HAL_DMA_Init(&hdma_tx);
/* 将初始化的DMA句柄关联到UART句柄*/
__HAL_LINKDMA(huart, hdmatx, hdma_tx);
/* 为接收进程配置 DMA 处理程序 */
hdma_rx.Instance = USARTx_RX_DMA_STREAM;
hdma_rx.Init.Channel = USARTx_RX_DMA_CHANNEL;
hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_rx.Init.Mode = DMA_NORMAL;
hdma_rx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_rx.Init.MemBurst = DMA_MBURST_INC16;
hdma_rx.Init.PeriphBurst = DMA_MBURST_INC16;
并使用串口空闲中断接收数据
uint32_t temp;
if((__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE) != RESET))
{
__HAL_UART_CLEAR_IDLEFLAG(huart);
HAL_UART_DMAStop(&uart_handler);
temp = uart_handler.hdmarx->Instance->NDTR;
g_usart_info.rx_len = USART_DMA_RECV_LEN - temp;
g_usart_info.receive_flag = 1;
g_usart_info.usart_dma_tx_buff = g_usart_info.usart_dma_rx_buff[0] ;
memset(g_usart_info.usart_dma_rx_buff, 0,
sizeof(g_usart_info.usart_dma_rx_buff));
__HAL_UART_CLEAR_FLAG(&uart_handler, UART_FLAG_RXNE);
g_usart_info.usart_dma_rx_buff[0] = 0;
HAL_UART_Receive_DMA(&uart_handler, g_usart_info.usart_dma_rx_buff,
USART_DMA_RECV_LEN);
}
谢谢。
我跟踪了UART_Receive_IT的功能并添加了调试代码。
并为 int a = *(huart->pRxBuffPtr - 1);
插入断点
我发现 huart->Instance->DR 是 0x31 但 int a 是 0xB1。
我试过禁用其他中断还是无法解决
if(huart->Init.Parity == UART_PARITY_NONE)
{
*huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
if(*(huart->pRxBuffPtr - 1) != 0x31)
{
int a = *(huart->pRxBuffPtr - 1);
a = a;
}
}
else
{
*huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
}
============================================= ===========================
找到问题点了
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 /*| RCC_CLOCKTYPE_PCLK2*/);
如果我评论RCC_CLOCKTYPE_PCLK2
,这个问题就可以解决了。
但是不知道为什么,是官方的示例代码。我觉得应该是对的。
好的,那么听起来确实像是时钟问题。
- 你有示波器吗?您可以从 STM32 发送一个已知字节,而不是进行回声测试。我通常发送
0xAA
或 0x55
。然后你可以测量你的STM32的UART的时序并验证它是否正确。
- 有时在较高的时钟速度下,外设时钟的精度会降低。您也可以尝试提高系统时钟的速度。
思考:再看看你的代码我想我可能已经找到了问题所在。在您的 UART 配置中更改
uart_handler.Init.OverSampling = UART_OVERSAMPLING_8;
到
uart_handler.Init.OverSampling = UART_OVERSAMPLING_16;
这将迫使 STM32 更仔细地查看传入的字节,可以解决您的问题。据我了解,16x
过采样是使用的典型配置,即使在较低的 UART 速度下也是如此。
终于找到了这个问题的根源。
我为我的开发板使用官方示例代码,但这些示例代码适用于官方开发板,该开发板带有嵌入式 stlink/v2 电路,它将通过 8M hz 到 STM32F4 芯片以获得 HSE 时钟。
但是我的板子没有电路,所以我必须使用外部stlink/v2模块来开发我的板子。
所以,我需要做以下改变。
是:
RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
是:
RCC_OscInitStruct.HSEState = RCC_LSE_ON;
修改后,我的问题解决了。
感谢 Hein Wessels 的观看和帮助:)。
我在使用带 DMA 的 STM32f427 UART(使用 stm cube HAL 库)时遇到问题。
我想做一个控制台回显功能,所以我在uart空闲中断处理函数中立即回复接收到的数据。
但有时,当我在键盘上输入任何键时,接收到的数据的最高位将是1。 比如关注
0x31 -> 0xB1
0x32 -> 0xB2
0x40 -> 0xC0
有人知道吗?代码段如下。
非常感谢。
我的串口配置如下
uart_handler.Instance = USARTx;
uart_handler.Init.BaudRate = baudrate;
uart_handler.Init.WordLength = UART_WORDLENGTH_8B;
uart_handler.Init.StopBits = UART_STOPBITS_1;
uart_handler.Init.Parity = UART_PARITY_NONE;
uart_handler.Init.HwFlowCtl = UART_HWCONTROL_NONE;
uart_handler.Init.Mode = UART_MODE_TX_RX;
uart_handler.Init.OverSampling = UART_OVERSAMPLING_8;
我的PIN和DMA通道配置如下
GPIO_InitStruct.Pin = USARTx_TX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = USARTx_TX_AF;
HAL_GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = USARTx_RX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Alternate = USARTx_RX_AF;
HAL_GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStruct);
hdma_tx.Instance = USARTx_TX_DMA_STREAM;
hdma_tx.Init.Channel = USARTx_TX_DMA_CHANNEL;
hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_tx.Init.Mode = DMA_NORMAL;
hdma_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_tx.Init.MemBurst = DMA_MBURST_INC16;
hdma_tx.Init.PeriphBurst = DMA_MBURST_INC16;
HAL_DMA_Init(&hdma_tx);
/* 将初始化的DMA句柄关联到UART句柄*/
__HAL_LINKDMA(huart, hdmatx, hdma_tx);
/* 为接收进程配置 DMA 处理程序 */
hdma_rx.Instance = USARTx_RX_DMA_STREAM;
hdma_rx.Init.Channel = USARTx_RX_DMA_CHANNEL;
hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_rx.Init.Mode = DMA_NORMAL;
hdma_rx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_rx.Init.MemBurst = DMA_MBURST_INC16;
hdma_rx.Init.PeriphBurst = DMA_MBURST_INC16;
并使用串口空闲中断接收数据
uint32_t temp;
if((__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE) != RESET))
{
__HAL_UART_CLEAR_IDLEFLAG(huart);
HAL_UART_DMAStop(&uart_handler);
temp = uart_handler.hdmarx->Instance->NDTR;
g_usart_info.rx_len = USART_DMA_RECV_LEN - temp;
g_usart_info.receive_flag = 1;
g_usart_info.usart_dma_tx_buff = g_usart_info.usart_dma_rx_buff[0] ;
memset(g_usart_info.usart_dma_rx_buff, 0,
sizeof(g_usart_info.usart_dma_rx_buff));
__HAL_UART_CLEAR_FLAG(&uart_handler, UART_FLAG_RXNE);
g_usart_info.usart_dma_rx_buff[0] = 0;
HAL_UART_Receive_DMA(&uart_handler, g_usart_info.usart_dma_rx_buff,
USART_DMA_RECV_LEN);
}
谢谢。
我跟踪了UART_Receive_IT的功能并添加了调试代码。 并为 int a = *(huart->pRxBuffPtr - 1);
插入断点我发现 huart->Instance->DR 是 0x31 但 int a 是 0xB1。
我试过禁用其他中断还是无法解决
if(huart->Init.Parity == UART_PARITY_NONE)
{
*huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
if(*(huart->pRxBuffPtr - 1) != 0x31)
{
int a = *(huart->pRxBuffPtr - 1);
a = a;
}
}
else
{
*huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
}
============================================= ===========================
找到问题点了
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 /*| RCC_CLOCKTYPE_PCLK2*/);
如果我评论RCC_CLOCKTYPE_PCLK2
,这个问题就可以解决了。
但是不知道为什么,是官方的示例代码。我觉得应该是对的。
好的,那么听起来确实像是时钟问题。
- 你有示波器吗?您可以从 STM32 发送一个已知字节,而不是进行回声测试。我通常发送
0xAA
或0x55
。然后你可以测量你的STM32的UART的时序并验证它是否正确。 - 有时在较高的时钟速度下,外设时钟的精度会降低。您也可以尝试提高系统时钟的速度。
思考:再看看你的代码我想我可能已经找到了问题所在。在您的 UART 配置中更改
uart_handler.Init.OverSampling = UART_OVERSAMPLING_8;
到
uart_handler.Init.OverSampling = UART_OVERSAMPLING_16;
这将迫使 STM32 更仔细地查看传入的字节,可以解决您的问题。据我了解,16x
过采样是使用的典型配置,即使在较低的 UART 速度下也是如此。
终于找到了这个问题的根源。 我为我的开发板使用官方示例代码,但这些示例代码适用于官方开发板,该开发板带有嵌入式 stlink/v2 电路,它将通过 8M hz 到 STM32F4 芯片以获得 HSE 时钟。
但是我的板子没有电路,所以我必须使用外部stlink/v2模块来开发我的板子。
所以,我需要做以下改变。
是: RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
是: RCC_OscInitStruct.HSEState = RCC_LSE_ON;
修改后,我的问题解决了。
感谢 Hein Wessels 的观看和帮助:)。