This is an old revision of the document!
−Table of Contents
UART
The gamepad features 3 UART controllers.
Base address | Desc. |
---|---|
0xF0004C00 | UART0 |
0xF0004C40 | UART1 |
0xF0004C80 | UART2 |
The entire UART region is mirrored every 256 bytes over 0xF0004C00..0xF0004FFF.
Related IRQs:
IRQ | Desc. |
---|---|
0x03 | UART0 |
0x04 | UART1 |
0x05 | UART2 |
UART0 appears to be unused. UART1 is connected to the test points under the battery connector, and is used as a debug console by the diagnostics firmware. UART2 is used for IR comm.
Registers
Offset | Desc. |
---|---|
0x00 | Data output |
0x04 | Data input |
0x08 | IRQ enable |
0x0C | IRQ status |
0x10 | ?? |
0x14 | Serial settings |
0x18 | ?? |
0x1C | Status register |
0x20 | ?? |
0x24 | Clock divider 1 |
0x28 | Clock multiplier |
0x2C | Clock divider 2 |
0x30 | Control register |
0x34 | RX FIFO level |
0x38 | TX FIFO level |
0x3C | ?? |
Base+0x00
Data output.
Data received can be read out from this register.
Base+0x04
Data input.
Data written to this register is queued in the transmit FIFO. If the FIFO is already full, the data is discarded (TODO: does it raise an error condition?).
Base+0x08
Bits | Desc. |
---|---|
0 | Enable RX IRQ (4) |
1 | Enable TX IRQ (2) |
2 | Enable RX fail IRQ (6) |
Base+0x0C
Bit 0-3 are the current IRQ status.
Value | Desc. |
---|---|
0 | ?? |
1 | No pending IRQ |
2 | Ready to send |
4 | Data received |
6 | RX error |
12 | ?? |
IRQ 2 is fired when the TX FIFO becomes empty. It is also fired when starting the UART. To acknowledge it, reading this register is enough.
IRQ 4 is fired when a byte of data is received. To acknowledge it, read the data from the data output port.
IRQ 6 is fired when data reception fails. For example this happens if the RX line is pulled low (when polarity set to active high). The only known way to acknowledge this IRQ is to reset the UART entirely.
Base+0x14
Serial settings.
Bits | Desc. |
---|---|
0-1 | Data bits; 0=5 bits, 1=6 bits, 2=7 bits, 3=8 bits |
2 | Stop bits; 0=1 bit, 1=2 bits |
3 | Enable parity bit |
4 | Parity; 0=odd, 1=even |
5 | ??? (no effect observed) |
6 | ??? (causes TX line to be held low) |
Base+0x1C
Status register.
Bits | Desc. |
---|---|
0 | RX FIFO not empty |
1 | RX FIFO overflow (received data while FIFO already full) |
4 | RX line error (ie. line held low) |
5 | 1 when ready to send, 0 when sending |
6 | 1 when ready to send, 0 when sending |
7 | RX error |
There doesn't seem to be error bits for TX FIFO overflow.
Base+0x24
Clock divider. This register is 9 bits wide.
Base+0x28
Clock multiplier. This register is 16 bits wide.
Base+0x2C
Clock divider. This register is 16 bits wide.
Base+0x30
Control register.
Bits | Desc. |
---|---|
0 | Enable UART |
1 | Bit order; 0=LSb first, 1=MSb first |
2 | Line polarity; 0=active high, 1=active low |
When bit 0 is cleared, most of the UART registers are disabled (read-only, zero).
Base+0x34
RX FIFO level.
Bits | Desc. |
---|---|
0-2 | RX state |
8-12 | RX FIFO level (occupied space, 0..16) |
RX state goes through the following values when receiving a data byte:
- 1 = receiving start bit
- 6 = waiting for start bit to end?
- 2 = receiving data bit
- 7 = waiting for next data bit?
- 4 = receiving stop bit
- 10 = storing byte into FIFO
- 0 = idle
Base+0x38
TX FIFO level.
Bits | Desc. |
---|---|
0-2 | TX state |
8-12 | TX FIFO level (occupied space, 0..16) |
TX state goes through the following values when sending a data byte:
- 5 = fetching byte from FIFO
- 1 = sending start bit
- 2 = sending data bits
- 4 = sending stop bit
- 0 = idle
Base+0x3C
Unknown, RX related.
Bits | Desc. |
---|---|
0-4 | ??? |
8-14 | ??? |
Default value 0x102.
Bit 0 seems to break clocking/timing logic? When it is set, data is still clocked out, but in a very fast and broken way (and completely ignores all clock settings).
Baud rate calculation
Three registers are used to determine the serial baud rate.
The formula is as follows:
baudrate = (inputclock / 16) * multiplier / divider1 / divider2
The input clock can be configured in the clock registers. Each UART gets its own clock register: 0xF0000040 for UART0, 0xF0000044 for UART1, and 0xF0000048 for UART2.
The diagnostics firmware contains code (at 0xAC0EE) to calculate the multiplier/divider register parameters for a given baud rate based on the current UART input clock. However, that function produces incorrect results for certain baud rates.
The diagnostics firmware uses a baud rate of 115200, for which the aforementioned function produces correct results.
The following C code can be used. It is based on the diagnostics firmware's code, but with the aforementioned bug fixed.
void calc_baud_rate(u32 clk, u32 baudrate, u32* mul, u32* div) { baudrate <<= 4; u32 multiplier = baudrate; u32 divider = clk; for (;;) { multiplier = multiplier % divider; if (multiplier != 0) { // baudrate is not a multiple of the input clock divider = divider % multiplier; if (divider != 0) continue; // input clock not a multiple of baudrate divider = clk / multiplier; multiplier = baudrate / multiplier; break; } else { // baudrate is a multiple of the input clock multiplier = baudrate / divider; divider = clk / divider; break; } } // adjust parameters to fit within 16-bit range while ((multiplier > 0xFFFF) || (divider > 0xFFFF)) { multiplier >>= 1; divider >>= 1; } *mul = multiplier; *div = divider; }
Output mul
and div
parameters can be applied to the multiplier and divider 2 registers, respectively. Divider 1 will be set to 1.