2023-11-11 07:45 AM
Hello everyone!
After many hours of grinding through forums & discussing with ChatGPT (really, ChatGPT is like my best friend now), I still fail to understand what must be a simple notion with an easy solution. This is why I'm posting this in forums.
I have a device which is transmitting data constantly (with about 4-5 Mbits/sec rates). I use HAL_UART_Transmit_DMA method for it. This part works correctly.
I also need to receive some commands from the PC to configure or signal the device. The frequency of this command reception is very low (about 1-2 commands per 10 seconds, usually). I try using HAL_UART_Receive_IT method for it (because from what I understand, it is best practice for such a requirement).
I want the UART interrupt to trigger only on actual data reception (like RXNE - Receive Data Register Not Empty). I have a buffer of 1 byte long and I try filling it via the following command ->
uint8_t rxBuffer[1];
__HAL_USART_ENABLE_IT(&husart3, USART_IT_RXNE);
HAL_USART_Receive_IT(&husart3, (uint8_t*)rxBuffer, 1);
I need the callback function to fire only when I get data in the buffer. Instead, I discover in debugging that it fires repeatedly, messing up with the data transmission DMA. This is my callback function:
void HAL_USART_RxCpltCallback(USART_HandleTypeDef *husart)
{
commandRecieved = 1;
command = rxBuffer[0];
memset(rxBuffer, 0, sizeof(rxBuffer));
HAL_USART_Receive_IT(&husart3, (uint8_t*)rxBuffer, 1);
}
(my plan was to use the commandRecieved flag and command in the main while(1) function, then clear them after handling the command)
What am I missing here? What can I do so that callback function only fires when the buffer is full (i.e. I received a command from PC) instead of firing all the time?
Regards
Solved! Go to Solution.
2023-11-11 01:10 PM
Ok, for some weird reason, I created a brand new project, wrote the exact same code and it somehow worked this time. Right now a circular HAL_UART_Receive_DMA callback only fires when the rxBuffer is full, which was my intention all along.
In debugging, for some weird reason, I discovered (in my first failed project), the uint8 rxBuffer (populated via HAL_UART_Receive_DMA or IT) was somehow getting filled with the number "127" continuously (01111111) - I (or chatGPT) haven't got the slightest idea as to why, or why it resolved itself when I opened a brand new project (which happened entirely by chance, by the way).
In any case, thank you everyone for your help :) I don't think this was engineering at its finest, but in any case, I resolved it somehow...
2023-11-11 08:00 AM - edited 2023-11-11 08:02 AM
For your scenario the best is a custom interrupt handler (no HAL, especially no HAL_USART_Receive_IT). Just enable the RXNE interrupt and keep it enabled. Another option is a continuous circular DMA with RX timeout detection, since you already use the DMA.
Note that H7 UARTs have a FIFO, it can be helpful. But IIRC the FIFO is not compatible with the disable overrun option (at least in older H7's such as 743/753/750).
2023-11-11 08:11 AM
i use (on H743) almost same : HAL_USART_Receive_IT(&husart3, (uint8_t*)rxBuffer, 1);
to receive data at 115k ; works without problems (most time...so i include error callback also)
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
// *** egal...
HAL_UART_Receive_IT(&huart7, &ESP_RX[ESP_RX_COUNT], 1); // set receive buf to 120 char. max
}
so check with a scope, whats real on rx pin of cpu.
2023-11-11 10:37 AM
So you are recommending to use no HAL method such as HAL_USART_Receive_IT if I use the custom interrupt handler approach, did I get this right? If possible, can you tell me where can I learn how to create a custom interrupt handler?
2023-11-11 11:53 AM - edited 2023-11-11 11:55 AM
Correct. There are many UART projects on github, and even chatgpt (or MS Bing/Copilot) these day can quickly offer an example.
Assume UART3 is used,then
void handle_RX_byte(uint8_t b)
{ .... }
void USART3_IRQHandler(void)
{
USART_TypeDef *U = USART3;
uint32_t isrflags = U->ISR; // status
if (isrflags & USART_ISR_ORE) {
U->ICR = UART_CLEAR_OREF;
}
if (isrflags & USART_ISR_RXNE_RXFNE) {
uint8_t recvd_byte = U->RDR;
handle_RX_byte(recvd_byte);
}
}
int main(void)
{
//..... initialize HAL, clocks...........
//..... initialize UARTs...........
// Enable USART receive interrupt
USART3->CR1 |= USART_CR1_RXNEIE;
while (1) {
// Your main application logic here
}
}
2023-11-11 01:10 PM
Ok, for some weird reason, I created a brand new project, wrote the exact same code and it somehow worked this time. Right now a circular HAL_UART_Receive_DMA callback only fires when the rxBuffer is full, which was my intention all along.
In debugging, for some weird reason, I discovered (in my first failed project), the uint8 rxBuffer (populated via HAL_UART_Receive_DMA or IT) was somehow getting filled with the number "127" continuously (01111111) - I (or chatGPT) haven't got the slightest idea as to why, or why it resolved itself when I opened a brand new project (which happened entirely by chance, by the way).
In any case, thank you everyone for your help :) I don't think this was engineering at its finest, but in any case, I resolved it somehow...