0
0
Power-electronicsHow-ToBeginner · 4 min read

How to Implement UART Receive Interrupt in Embedded C

To implement a UART receive interrupt in Embedded C, first enable the UART receive interrupt in the UART control register and configure the interrupt vector to call your interrupt service routine (ISR). Inside the ISR, read the received data from the UART data register to clear the interrupt flag and process the data as needed.
📐

Syntax

The basic steps to implement UART receive interrupt are:

  • Enable UART receive interrupt in the UART control register.
  • Write an Interrupt Service Routine (ISR) to handle the interrupt.
  • Inside the ISR, read the UART data register to clear the interrupt flag.
  • Process the received data as needed.
c
void UART_Init(void) {
    // Enable UART receiver and its interrupt
    UART_CTRL_REG |= (1 << RX_ENABLE_BIT) | (1 << RX_INT_ENABLE_BIT);
    // Enable global interrupts
    ENABLE_GLOBAL_INTERRUPTS();
}

// UART Receive Interrupt Service Routine
void UART_RX_ISR(void) {
    char received_char = UART_DATA_REG; // Read received data
    // Process received_char as needed
}
💻

Example

This example shows how to initialize UART with receive interrupt and handle incoming data by storing it in a buffer.

c
#include <stdint.h>
#include <stdbool.h>

#define UART_CTRL_REG (*(volatile uint8_t*)0x4000)
#define UART_DATA_REG (*(volatile uint8_t*)0x4001)
#define UART_STATUS_REG (*(volatile uint8_t*)0x4002)
#define RX_ENABLE_BIT 0
#define RX_INT_ENABLE_BIT 1
#define RX_READY_BIT 0

volatile char rx_buffer[64];
volatile uint8_t rx_index = 0;

void ENABLE_GLOBAL_INTERRUPTS(void) {
    // Platform specific code to enable global interrupts
}

void UART_Init(void) {
    UART_CTRL_REG |= (1 << RX_ENABLE_BIT) | (1 << RX_INT_ENABLE_BIT);
    ENABLE_GLOBAL_INTERRUPTS();
}

// UART Receive Interrupt Service Routine
void UART_RX_ISR(void) {
    if (UART_STATUS_REG & (1 << RX_READY_BIT)) {
        char received_char = UART_DATA_REG; // Read clears interrupt flag
        if (rx_index < sizeof(rx_buffer)) {
            rx_buffer[rx_index++] = received_char;
        }
    }
}

int main(void) {
    UART_Init();
    while (true) {
        // Main loop can process rx_buffer or sleep
    }
    return 0;
}
Output
No direct output; UART receive interrupt stores incoming characters in rx_buffer.
⚠️

Common Pitfalls

  • Not enabling global interrupts after enabling UART receive interrupt.
  • Failing to read the UART data register inside the ISR, which prevents clearing the interrupt flag and causes repeated interrupts.
  • Accessing shared data (like buffers) without proper synchronization if used outside ISR.
  • Not configuring the interrupt vector or ISR correctly, so the interrupt never triggers.
c
/* Wrong: Not reading UART_DATA_REG inside ISR, interrupt flag not cleared */
void UART_RX_ISR(void) {
    // Missing read of UART_DATA_REG
    // Interrupt flag remains set, causing repeated interrupts
}

/* Correct: Read UART_DATA_REG to clear interrupt flag */
void UART_RX_ISR(void) {
    char received_char = UART_DATA_REG; // Clears interrupt flag
    // Process received_char
}
📊

Quick Reference

StepDescription
Enable UART RX interruptSet RX interrupt enable bit in UART control register
Enable global interruptsAllow CPU to respond to interrupts
Write ISRRead UART data register to clear interrupt flag and handle data
Process dataUse received data as needed in main program or ISR
Avoid pitfallsAlways clear interrupt flag and synchronize shared data

Key Takeaways

Always enable UART receive interrupt and global interrupts to allow ISR execution.
Inside the ISR, read the UART data register to clear the interrupt flag and get received data.
Configure the interrupt vector properly so the ISR is called on UART receive events.
Avoid missing the data register read inside ISR to prevent repeated interrupts.
Use buffers carefully and synchronize access if shared between ISR and main code.