Initialization Sequence
Configuring the DW_apb_uart for data transmission and reception requires a specific sequence of register writes. The standard setup procedure is outlined below:
- Set up the Modem Control Register (MCR) to define operational modes such as SIR, automatic flow control, loopback, and modem output states.
- Enable divisor latch access by setting the LCR.DLAB bit to 1.
- Determine the required baud rate and compute the integer and fractional divisor values. Write these values to the Divisor Latch Low (DLL), Divisor Latch High (DLH), and Divisor Latch Fractional (DLF) registers.
- Disable divisor latch access by clearing the LCR.DLAB bit to 0.
- Configure the Line Control Register (LCR) to specify frame parameters like character length, stop bits, and parity.
- Adjust the FIFO Control Register (FCR) to set the trigger levels for both transmit and receive FIFOs.
- Enable desired interrupts via the Interrupt Enable Register (IER).
- For transmitting data, write the payload to the Transmit Holding Register (THR). Poll the Interrupt Identification Register (IIR) until it returns
0x02, indicating the TX FIFO is empty and ready for the next byte. For receiving data, poll IIR for the value0x04, which signals that data is available in the RX FIFO. The CPU can then retrieve the incoming byte from the Receive Buffer Register (RBR).
Register Definitions
Certain DW_apb_uart registers share the same memory offset but serve different purposes based on read/write operations or the state of the DLAB bit. Unions provide an effective mechanism to handle these overlapping address spaces.
/* Union for shared offset 0x00: RBR (read), DLL (write with DLAB=1), THR (write with DLAB=0) */
typedef union {
volatile const uart_rx_buffer_s rx_data; /* Receive Buffer Register */
volatile uart_div_low_s div_low; /* Divisor Latch Low */
volatile uart_tx_hold_s tx_data; /* Transmit Holding Register */
} uart_offset_0x00_u;
/* Union for shared offset 0x04: IER (read/write with DLAB=0), DLH (write with DLAB=1) */
typedef union {
volatile uart_div_high_s div_high; /* Divisor Latch High */
volatile uart_irq_enable_s irq_en; /* Interrupt Enable Register */
} uart_offset_0x04_u;
/* Union for shared offset 0x08: IIR (read), FCR (write) */
typedef union {
volatile uart_fifo_ctrl_s fifo_cfg; /* FIFO Control Register */
volatile const uart_irq_id_s irq_stat; /* Interrupt Identification Register */
} uart_offset_0x08_u;
The complete peripheral register map is structured as follows, incorporating the unions defined above:
typedef struct {
uart_offset_0x00_u base_0x00; /* 0x00: RBR/DLL/THR access */
uart_offset_0x04_u base_0x04; /* 0x04: DLH/IER access */
uart_offset_0x08_u base_0x08; /* 0x08: FCR/IIR access */
volatile uart_line_ctrl_s line_cfg; /* 0x0c: Line Control Register */
volatile uart_modem_ctrl_s modem_cfg; /* 0x10: Modem Control Register */
volatile const uart_line_stat_s line_stat; /* 0x14: Line Status Register */
volatile const uart_modem_stat_s modem_stat; /* 0x18: Modem Status Register */
volatile uart_scratch_s scratch_pad; /* 0x1c: Scratchpad Register */
volatile uart_lp_div_low_s lp_div_low; /* 0x20: Low Power Divisor Latch Low */
} dw_apb_uart_s;