2019-10-23 11:05 AM
I have a uart setup that performs large transfers. I have seen that it blocks receive for most of the time this transmit happens. The IRQ is shared for both transmit and receive (by chip architecture). So how do I deal with this ?
Is the usart really full duplex ?
How does NVIC nesting play into this?
Solved! Go to Solution.
2019-10-23 01:53 PM
You don't need them to nest mutually, just make them as simple as possible.
void USART1_IRQHandler(void) {
uint32_t isr, cr1;
uint_least8_t b;
isr = USART1->ISR;
if (isr AND USART_ISR_ORE) {
// set any flag you want to indicate main() that overflow happened
USART1->ICR = USART_ICR_ORECF;
}
if (isr AND USART_ISR_RXNE) {
b = USART1->RDR;
// here, store b into a Rx buffer, for main() to process
}
cr1 = USART1->CR1;
if (cr1 AND USART_CR1_TXEIE) {
if (isr AND USART_ISR_TXE) {
// look into the buffer into which main() stored data to be transmitted
if (there_are_bytes_to_Tx) {
USART1->TDR = byte_to_Tx;
} else {
USART1->CR1 = cr1 AND ~USART_CR1_TXEIE; // disable further Tx
}
}
}
}
When you want to Tx in main(), store data to Tx buffer and enable Tx in USARTx_CR1.
In main(), check if there are received data in the Rx buffer, and if yes, process them.
JW
2019-10-23 11:13 AM
The underlying hardware really is full duplex, but the HAL software implementation doesn't really support TX and RX being used independently. You can play some games with it, like setting huart->gState = HAL_UART_STATE_READY after starting a transfer (instead of letting it be HAL_UART_STATE_BUSY_TX). Or you can roll your own software implementation for the UART.
There's no problem with them sharing an IRQ. The flags will indicate which event you need to handle. This is done well in the default HAL IRQ handler.
2019-10-23 11:16 AM
Is there any example implimentation or application note for this that you can point me to?
If the IRQ is the same, how will nesting work? They are equal priority and may not nest.
2019-10-23 01:53 PM
You don't need them to nest mutually, just make them as simple as possible.
void USART1_IRQHandler(void) {
uint32_t isr, cr1;
uint_least8_t b;
isr = USART1->ISR;
if (isr AND USART_ISR_ORE) {
// set any flag you want to indicate main() that overflow happened
USART1->ICR = USART_ICR_ORECF;
}
if (isr AND USART_ISR_RXNE) {
b = USART1->RDR;
// here, store b into a Rx buffer, for main() to process
}
cr1 = USART1->CR1;
if (cr1 AND USART_CR1_TXEIE) {
if (isr AND USART_ISR_TXE) {
// look into the buffer into which main() stored data to be transmitted
if (there_are_bytes_to_Tx) {
USART1->TDR = byte_to_Tx;
} else {
USART1->CR1 = cr1 AND ~USART_CR1_TXEIE; // disable further Tx
}
}
}
}
When you want to Tx in main(), store data to Tx buffer and enable Tx in USARTx_CR1.
In main(), check if there are received data in the Rx buffer, and if yes, process them.
JW
2019-10-23 02:05 PM
They don't nest, or preempt, if you don't service all the pending interrupts the processor/NVIC will simply tail-chain and call your IRQHandler again.
Each interrupting source is flagged separately, you simply test for each and deal with it. It is not profoundly different from interrupts in other micro-controller architectures.
You don't want to be faffing about in the IRQHandler, service the pending interrupts and leave. Try to avoid the urge to use printf(), callbacks, message processing and blocking functions. Assume you have less than one byte time to play with.
Might I suggest one of Joseph Yiu's Essential Cortex-Mx series that covers interrupts and NVIC operation are the core level.