2
votes

I got a problem when using STM32f427 UART with DMA(using stm cube HAL library).

I would like make a console echo function, so I reply received data immediately in uart idle interrupt handler function.

But sometimes, the highest bit of received data will be 1, when I input any key in keyboard. such as following

0x31 -> 0xB1
0x32 -> 0xB2
0x40 -> 0xC0

Does someone have any idea? the code segment as following.

Thank you very much.

My uart configuration as following

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;

My PIN and DMA channels configuration as following

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);

/* Associate the initialized DMA handle to the UART handle */

__HAL_LINKDMA(huart, hdmatx, hdma_tx);

/* Configure the DMA handler for reception process */

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;

And use uart idle interrupt to receive data.

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);
}

Thank you.

I traced the function of UART_Receive_IT and added debug code. and insert break point for int a = *(huart->pRxBuffPtr - 1);

I found huart->Instance->DR is 0x31 but int a is 0xB1.

I tried to disable other interrupt but it still cannot be solved.

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);
      }

========================================================================

I found the problem point

RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 /*| RCC_CLOCKTYPE_PCLK2*/);

If I comment RCC_CLOCKTYPE_PCLK2, this problem could be solved. But I don't know why, it is official sample code. I think it should be right.

2
You could make sure that your computer's UART is set up correctly (start bit, stop bit, parity). I can't imagine that the problem could be the clocks, but you could seeing if all the clocks are set up correctly. If that still doesn't work, then I would use STM32CubeMX to generate the code again, and see how it differs with what you have.Hein Wessels
Hi thank for your response , about UART configure , I think it is correct, because it work well if set to 9600, but it has problem when set to 115200. under baudrate 115200 the incorrect output as below. I press down "1" on keyboard and send to my board by uart "111±11111111111111111111111111111111111111±11" most of output is correct, but sometime it will be ± And my development target is not official develop board, it maybe is a hardware design issue on my side only, I am checking it. But in actually, if I comment RCC_CLOCKTYPE_PCLK2 in my code, uart is work well.user7743152

2 Answers

0
votes

Okay, then it does sound like a clock issue.

  • Do you have an oscilloscope? Instead of doing an echo test you could just send a known byte from the STM32. I usually send 0xAA or 0x55. Then you can measure the timing of your STM32's UART and verify if it is correct.
  • Sometimes at higher clock speeds the accuracy of the peripheral's clock will decrease. You could also try to increase the speed of your system clock.

Thought: Looking at your code again I think I might have found the problem. In your UART config change

uart_handler.Init.OverSampling = UART_OVERSAMPLING_8;

to

uart_handler.Init.OverSampling = UART_OVERSAMPLING_16;

This will force the STM32 to look more finely at the incoming bytes and could resolve your problem. In my understanding 16x oversampling is the typical configuration used, even at lower UART speeds.

0
votes

Finally, I got the root cause for this question. I use official sample code for my board but those sample code is for official development board the board is with embedded stlink/v2 circuit and it will pass 8M hz to the STM32F4 chip for HSE clock.

But my board does not have the circuit , so I have to use external stlink/v2 module to develop my board.

So, I need to do below change.

WAS: RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;

IS: RCC_OscInitStruct.HSEState = RCC_LSE_ON;

After change, my problem is be solved.

And thanks Hein Wessels for watching and help :).