2017-02-19 04:39 AM
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 #usart2017-02-19 09:21 AM
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.
2017-02-19 09:55 AM
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.
2017-02-19 11:53 AM
Yes, I'll process in foreground, but - is this the correct usage of the HAL API?
2017-02-19 02:13 PM
I believe so, but there are examples under the Cube install directory.
2017-02-19 02:30 PM
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.
2017-02-19 09:18 PM
' 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.
2017-02-20 04:27 AM
'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 :)
2017-02-20 04:50 AM
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;
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
2017-02-20 04:58 AM
Cool, I'll try it out.