cancel
Showing results for 
Search instead for 
Did you mean: 

USART - reading 1 byte at a time

Rami Rosenbaum (old)
Associate II
Posted on February 19, 2017 at 13:39

Hi,

I need to parse incoming data from UART, with unknown length.

The packet length is sent within the packet, so I need to parse the packet as it arrives.

So - I need to read 1 byte at a time, and parse the packet while receiving.

I'm using CubeMX generated code and HAL libraries, and will probably work with interrupts.

Should I be calling HAL_UART_Receive_IT(&huart1, &nextByte, 1) within my HAL_UART_TxCpltCallback() method, and move the received byte to the foreground thread' for parse?

#hal #usart
10 REPLIES 10
Posted on February 19, 2017 at 18:21

Depends on how burdensome your parsing is. If you can process with a state-machine, or similar, within one byte time you could do in the interrupt. For more complex stuff you could buffer, and process in foreground or worker task.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
S.Ma
Principal
Posted on February 19, 2017 at 18:55

Use interrupt scheme in RX mode and do the 'start/end' detection of the packet of bytes for treatment.

Use a DMA Memory to Memory to push the slice out and get the interrupt ready for the next batch. For Transmit, usually the message is constructed byte by byte, sometime, if it is text, it would be generated from a form of printf. As one char is pushed to USART, the printf char by char processing can be done in the dead time, and for RS232, there is no 'urgency' as it is typically asynchroneous. 

Posted on February 19, 2017 at 19:53

Yes, I'll process in foreground, but - is this the correct usage of the HAL API?

Posted on February 19, 2017 at 22:13

I believe so, but there are examples under the Cube install directory. 

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
T J
Lead
Posted on February 19, 2017 at 23:30

set the Uart receive DMA circular buffer to two bytes length

then the halfcallback and full callback will interrupt you for each individual byte

I have done this exactly, it works extremely well at 460800 baud.

Posted on February 20, 2017 at 05:18

' Should I be calling HAL_UART_Receive_IT(&huart1, &nextByte, 1) within my HAL_UART_TxCpltCallback() method,'

no, I think that method carries way too much overhead.

definitely use the DMA circular buffer of 2 bytes,

under the half and full callbacks; store into a buffer and check the buffer in the foreground.

Posted on February 20, 2017 at 12:27

'way too much overhead' - that's exactly what I thought.

The 2-byte circular buffer looks like what I need.

I won't find it imposing, if you attach a demo-code... feel free, on my behalf 🙂

Posted on February 20, 2017 at 12:50

void MX_USART1_UART_Init(void){
 huart1.Instance = USART1; huart1.Init.BaudRate = 460800; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); }
}
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle){
 GPIO_InitTypeDef GPIO_InitStruct; if(uartHandle->Instance==USART1) { /* USER CODE BEGIN USART1_MspInit 0 */
 /* USER CODE END USART1_MspInit 0 */ /* Peripheral clock enable */ __HAL_RCC_USART1_CLK_ENABLE(); /**USART1 GPIO Configuration PA9 ------> USART1_TX PA10 ------> USART1_RX */ GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Alternate = GPIO_AF1_USART1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 /* Peripheral DMA init*/ hdma_usart1_tx.Instance = DMA1_Channel7; hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart1_tx.Init.Mode = DMA_NORMAL; hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW; if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK) { Error_Handler(); }
 __HAL_DMA1_REMAP(HAL_DMA1_CH7_USART1_TX);
 __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx);
 hdma_usart1_rx.Instance = DMA1_Channel6; hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart1_rx.Init.Mode = DMA_CIRCULAR; hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW; if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK) { Error_Handler(); }
 __HAL_DMA1_REMAP(HAL_DMA1_CH6_USART1_RX);
 __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx);
 /* Peripheral interrupt init */ HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(USART1_IRQn); /* USER CODE BEGIN USART1_MspInit 1 */
 //hdma_usart1_tx.Init.BufferSize = ARRAYSIZE;
 /* USER CODE END USART1_MspInit 1 */ }}

void initUart1RxDMABuffer(void){ //##-3- Put UART peripheral in reception process ###########################
 if (HAL_UART_Receive_DMA(&huart1,(uint8_t *)Usart1RxDMABuffer, 2 != HAL_OK) { // Transfer error in reception process Error_Handler(); }}

extern 'C' void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
 HAL_UART_RxCpltFlag = true;
 uint8_t Rxbyte; // save the char, update the buffer flags Rxbyte = Usart1RxDMABuffer[1]; // tricky, no counters needed... Usart1RxBuffer [ U1RxBufferPtrIN ++] = Rxbyte; if (U1RxBufferPtrIN >= 1024) U1RxBufferPtrIN =0; } extern 'C' void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart){
 HAL_UART_RxHalfCpltFlag = true;
 uint8_t Rxbyte; Rxbyte = Usart1RxDMABuffer[0]; // tricky, no counters needed... Usart1RxBuffer [ U1RxBufferPtrIN ++] = Rxbyte; if (U1RxBufferPtrIN >= 1024) U1RxBufferPtrIN =0;
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Posted on February 20, 2017 at 12:58

Cool, I'll try it out.