Skip to main content
Louie88
Senior
March 1, 2022
Solved

How can I use UART manually, without HAL_UART_***() functions?

NUCLEO-H723ZG dev. kit.

I need take over the full control of the USARTx. I need a TX interrupt and the RX interrupt handled manually independently the HAL_UART_*** functions. The HAL_UART_Receive_IT() and the HAL_UART_Transmit_IT() is useless for me.

During initialization I need to enable the receiver. When one byte is received then I need an interrupt and I will store the received bytes in the RXBuffer. The main() loop periodically checks the received bytes. If it finds a complete message in the RXBuffer[] then it processes the message, then creates the answer into the TXBuffer[], enables the TX interrupt and sends back answer.

To do this I need a TX interrupt when the TX buffer becomes empty. I simply send the next byte. When I get the TX buffer empty interrupt and I have no more bytes to send I disable the TX interrupt, clear the RXBuffer and re-enable the RX interrupt. 

I am sure it is possible to do with STM32H723ZG MCU but I could not find such an example. How can I do this? Thanks for your help.

Louis

This topic has been closed for replies.
Tesla DeLorean
Tesla DeLoreanBest answer
Guru
March 1, 2022

At a register level the Reference Manual has the detail, the source to the libraries is also available.

For the L0 for example I have this

void USART2_IRQHandler(void)
{
 uint32_t isr = USART2->ISR;
 
 if (isr & USART_ISR_RXNE) // Received character?
 {
 uint16_t Data = USART2->RDR;
 
 Fifo_Insert(FifoIn2, 1, (void *)&Data);
 }
 
 if (isr & (USART_ISR_ORE | USART_ISR_NE | USART_ISR_FE)) // Pending Errors
 {
 if (isr & USART_ISR_ORE)
 USART2->ICR = USART_ICR_ORECF;
 
 if (isr & USART_ISR_NE)
 USART2->ICR = USART_ICR_NCF;
 
 if (isr & USART_ISR_FE)
 USART2->ICR = USART_ICR_FECF;
 }
 
 if (isr & USART_ISR_TXE) // Transmit empty
 {
 uint32_t Used = Fifo_Used(FifoOut2);
 
 if (Used)
 {
 uint16_t Data = 0;
 
 if (Fifo_Extract(FifoOut2, 1, (void *)&Data))
 USART2->TDR = Data;
 
 if (Used > 1)
 USART2->CR1 |= USART_CR1_TXEIE;
 else
 USART2->CR1 &= ~USART_CR1_TXEIE; // Disable as empty
 }
 else
 USART2->CR1 &= ~USART_CR1_TXEIE; // Disable as empty
 }
}

When pushing data into the output FIFO you enable the TXE interrupt, and it will fire immediately. You disable it so it doesn't saturate/loop with interrupts when there's not data available to push into the TDR

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..

2 replies

Tesla DeLorean
Tesla DeLoreanBest answer
Guru
March 1, 2022

At a register level the Reference Manual has the detail, the source to the libraries is also available.

For the L0 for example I have this

void USART2_IRQHandler(void)
{
 uint32_t isr = USART2->ISR;
 
 if (isr & USART_ISR_RXNE) // Received character?
 {
 uint16_t Data = USART2->RDR;
 
 Fifo_Insert(FifoIn2, 1, (void *)&Data);
 }
 
 if (isr & (USART_ISR_ORE | USART_ISR_NE | USART_ISR_FE)) // Pending Errors
 {
 if (isr & USART_ISR_ORE)
 USART2->ICR = USART_ICR_ORECF;
 
 if (isr & USART_ISR_NE)
 USART2->ICR = USART_ICR_NCF;
 
 if (isr & USART_ISR_FE)
 USART2->ICR = USART_ICR_FECF;
 }
 
 if (isr & USART_ISR_TXE) // Transmit empty
 {
 uint32_t Used = Fifo_Used(FifoOut2);
 
 if (Used)
 {
 uint16_t Data = 0;
 
 if (Fifo_Extract(FifoOut2, 1, (void *)&Data))
 USART2->TDR = Data;
 
 if (Used > 1)
 USART2->CR1 |= USART_CR1_TXEIE;
 else
 USART2->CR1 &= ~USART_CR1_TXEIE; // Disable as empty
 }
 else
 USART2->CR1 &= ~USART_CR1_TXEIE; // Disable as empty
 }
}

When pushing data into the output FIFO you enable the TXE interrupt, and it will fire immediately. You disable it so it doesn't saturate/loop with interrupts when there's not data available to push into the TDR

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
Louie88
Louie88Author
Senior
March 2, 2022

Dear Tesla DeLorean,

Excellent, thank you!

Best regards,

Louis