Interrupt-based input/output

The examples in this section are based on polling the status of UART by continuously checking the flags of UART_SR. The write operation contains a busy loop that can spin for several milliseconds, depending on the length of the string. Even worse, the read function presented earlier spins within a busy loop until there is data to read from the peripheral, which means that the whole system is hanging until new data is received. In a single-thread embedded system, returning to the main loop with the shortest latency possible is important to keep the system responsive.

The correct way to perform UART communication without blocking is by using the interrupt line associated with UART to trigger actions based on the event received. UART can be configured to raise the interrupt signal upon multiple types of events. As we have seen in the previous examples, to regulate input and output operations, we are interested in particular in two specific events, namely:

  • TX FIFO empty event, allowing for more data to be transmitted
  • RX FIFO not-empty event, signaling the presence of new received data

The interrupt for these two events can be enabled by setting the corresponding bits in UART_CR1. We define two helper functions with the purpose of turning interrupts on and off, independently:

#define UART_CR1_TXEIE (1 << 7)
#define UART_CR1_RXNEIE (1 << 5)

static void uart3_tx_interrupt_onoff(int enable)
{
if (enable)
UART3_CR1 |= UART_CR1_TXEIE;
else
UART3_CR1 &= ~UART_CR1_TXEIE;
}

static void uart3_rx_interrupt_onoff(int enable)
{
if (enable)
UART3_CR1 |= UART_CR1_RXNEIE;
else
UART3_CR1 &= ~UART_CR1_RXNEIE;
}

A service routine can be associated with the interrupt events, then check the flags in UART_SR to identify the cause of the interrupt:

void isr_uart3(void)
{
volatile uint32_t reg;
reg = UART3_SR;
if (reg & UART_SR_RX_NOTEMPTY) {
/* Receive a new byte */
}

if ((reg & UART_SR_TX_EMPTY)
{
/* resume pending transmission */
}
}

The implementation of the interrupt routine depends on the specific system design. An RTOS may decide to multiplex access to the serial port to multiple threads, and wake up threads waiting to access the resource. In a single-thread application, it is possible to add intermediate system buffers to provide non-blocking calls, which return immediately after copying the data from the receiving buffer, or to the transmitting one. The interrupt service routine fills the receiving buffer with new data from the bus, and transmits the data from the pending buffer. Using appropriate structures, such as circular buffers to implement system input and output queues, ensures that the use of the memory assigned is optimized.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset