Hi Sarra,
thank you for bearing with me. I was curious, so I wanted to repeat it, but this time all was running fine.
I must have been blind for some stupid mistake. I didn't keep that code so I had to redo it, and then didn't seem to hit any problems. I must be getting old a bit.
Nevertheless, enabling the uart interrupt appears to be a best practice anyway, if would it only to clear error flags, like framing errors which easily occur when connecting and disconnecting the lines.
I thought I would share some straight forward examples for other (co)developers to play with.
During the blocking HAL_Delay, characters are fetched using DMA on UART RX.
We can either use the UART RTO interrupt (Receive TimeOut in number of bits) to detect an end of the data reception (perhaps when receiving Modbus, 35 bits is a 3.5 character timout), or pol for received data, or recognize some specific received data.
Note, blocking calls should be avoided at all times, I believe. This is just a simple demo example.
Also as much as possible should be done using the hardware, so using DMA as much as possible is mostly a good thing. The MCU can then perform other tasks in the mean time.
First: Mode = DMA_CIRCULAR, start once (I think the best solution, as no characters will be missed)
Second: DMA_NORMAL or DMA_CIRCULAR, start/stop
/* Mode = DMA_CIRCULAR, start once */
/* Interrupt Enable */
HAL_NVIC_EnableIRQ(USART1_IRQn);
uint8_t DataRX[256];
if (HAL_UART_Receive_DMA(&huart1, DataRX, sizeof(DataRX)) != HAL_OK)
{
/* Error */
char Error[] = "Error HAL_UART_Receive_DMA\n";
HAL_UART_Transmit(&huart2, (uint8_t*)Error, strlen(Error), 100); /* To USB serial port */
}
uint16_t First_Byte_Index = 0;
uint16_t Last_Byte_Index_Previous = 0;
while (1)
{
/* Show what's in the DataRX */
uint16_t Last_Byte_Index = (uint16_t)(sizeof(DataRX) - __HAL_DMA_GET_COUNTER(huart1.hdmarx));
uint16_t DataRX_Length = Last_Byte_Index - Last_Byte_Index_Previous;
First_Byte_Index = Last_Byte_Index - DataRX_Length;
/* If the new Index is greater than Index_old, we received something */
if (DataRX_Length)
{
char Received[] = "Received: ";
HAL_UART_Transmit(&huart2, (uint8_t*)Received, strlen(Received), 100); /* To USB serial port */
for (uint16_t i = 0; i < DataRX_Length; i++)
{
uint16_t DataRX_Index = i + First_Byte_Index;
/* Roll over DataRX_index if necessary */
if (DataRX_Index > sizeof(DataRX))
{
DataRX_Index -= sizeof(DataRX);
}
HAL_UART_Transmit(&huart2, &DataRX[DataRX_Index], 1, 100); /* To USB serial port */
}
char CR[] = "\n";
HAL_UART_Transmit(&huart2, (uint8_t*)CR, strlen(CR), 100); /* To USB serial port */
/* Reset Index_old to latest Index */
Last_Byte_Index_Previous = Last_Byte_Index;
}
HAL_UART_Transmit(&huart2, (uint8_t*)Test, strlen(Test), 100); /* To USB serial port */
HAL_Delay(1000);
HAL_IWDG_Refresh(&hiwdg); /* Don't forget to take good care of your watch-dog, feed it! */
}
/* Mode = DMA_NORMAL or DMA_CIRCULAR, start/stop */
/* Interrupt Enable */
HAL_NVIC_EnableIRQ(USART1_IRQn);
uint8_t DataRX[256];
while (1)
{
if (HAL_UART_Receive_DMA(&huart1, DataRX, sizeof(DataRX)) != HAL_OK)
{
/* Error */
char Error[] = "Error HAL_UART_Receive_DMA\n";
HAL_UART_Transmit(&huart2, (uint8_t*)Error, strlen(Error), 100); /* To USB serial port */
}
HAL_Delay(1000);
/*Checking length and print buffer (on a different UART) */
uint16_t Last_Byte_Index = (uint16_t)(sizeof(DataRX) - __HAL_DMA_GET_COUNTER(huart1.hdmarx));
/* printing the buffer on another UART */
if (Last_Byte_Index)
{
char Received[] = "Received: ";
HAL_UART_Transmit(&huart2, (uint8_t*)Received, strlen(Received), 100); /* To USB serial port */
for (uint16_t i = 0; i < Last_Byte_Index; i++)
{
HAL_UART_Transmit(&huart2, &DataRX[i], 1, 100); /* To USB serial port */
}
char CR[] = "\n";
HAL_UART_Transmit(&huart2, (uint8_t*)CR, strlen(CR), 100); /* To USB serial port */
}
if (HAL_UART_DMAStop(&huart1) != HAL_OK)
{
/* Error */
char Error[] = "Error HAL_UART_DMAStop\n";
HAL_UART_Transmit(&huart2, (uint8_t*)Error, strlen(Error), 100); /* To USB serial port */
}
HAL_IWDG_Refresh(&hiwdg); /* Don't forget to take good care of your watch-dog, feed it! */
}
In stm32g4xx_it.c we clear some error flags, would they occur. We could just clear them without checking, but maybe someone would maintain framing and parity error counters.
/**
* @brief This function handles USART1 global interrupt / USART1 wake-up interrupt through EXTI line 25.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* Noise immunity feature enabled for RS (Modbus-RTU) interfaces */
/* Clear the errors if they occurred */
/* UART parity error detected */
if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_PE) == SET)
{
__HAL_UART_CLEAR_PEFLAG(&huart1);
}
/* UART frame error detected or break character is detected */
if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_FE) == SET)
{
__HAL_UART_CLEAR_FEFLAG(&huart1);
}
/* UART noise error detected */
if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_NE) == SET)
{
__HAL_UART_CLEAR_NEFLAG(&huart1);
}
/* UART overrun error detected */
if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_ORE) == SET)
{
__HAL_UART_CLEAR_OREFLAG(&huart1);
}
/* UART idle flag */
if((__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
Hope this is useful.
Any feedback is always welcome.
Warm regards to all of you!