−Table of Contents
SPI
The SPI bus connects the gamepad storage (Flash memory) and the UIC to the CPU.
SPI controller
The gamepad uses a pretty simple SPI controller with 16-byte FIFOs for reading and writing. Due to the way this is designed, one has to be mindful to avoid FIFO overflows/underflows during a SPI transfer.
The SPI controller doesn't support full-duplex communication, ie. when sending out a data byte on MOSI, it isn't possible to receive a data byte on MISO at the same time.
The SPI controller has the following registers:
Address | Desc. |
---|---|
0xF0004400 | SPI control/speed |
0xF0004404 | SPI transfer control |
0xF0004408 | IRQ flags |
0xF000440C | FIFO status |
0xF0004410 | Data input/output |
0xF0004414 | SPI low-level control |
0xF0004418 | IRQ enable |
0xF0004420 | Number of bytes to read |
0xF0004424 | Device select |
0xF0004400
Controls SPI clock speed.
Bits | Desc. |
---|---|
0-2 | Clock source |
3-10 | Clock divider |
11-14 | ?? |
15 | SPI enable (possibly just clock enable) |
The clock source selects the base clock, and the clock divider divides that by a fixed value to produce the final SPI clock.
The clock source and divider values work the same way as in the per-module clock setting registers.
Observed settings in the stock firmware are the following:
Register value | Destination | Clock speed |
---|---|---|
0x808C | FLASH | 48 MHz |
0x8018 | UIC | 8 MHz |
0x835C | UIC | 8 MHz |
0x83F8 | UIC | 250 KHz |
0x8400 | UIC | 248 KHz |
0xF0004404
Controls various aspects of the SPI transfer.
Bits | Desc. |
---|---|
0 | ?? |
1 | Transfer direction; 0=write, 1=read |
2 | ?? |
6 | ?? toggled during UIC reads, not sure what the effect is |
8 | Chipselect mode; 0=automatic, 1=manual |
9 | Manual chipselect; 0=select, 1=release |
10 | ?? FIFO related? |
Setting bit8 to 0 causes the chipselect line to be automatically activated only during a transfer. This means that during a write-then-read transfer, the chipselect line will get deactivated and activated again between the write and the read.
Setting bit8 to 1 causes the chipselect line to be directly controlled by bit9. In this mode, no transfer will be initiated until the chipselect line is activated.
Note: it is also possible to leave bit8 at 0 and manually toggle the chipselect lines via the GPIO registers. Firmware code seems to do this for UIC comm.
0xF0004408
SPI IRQ flags. Writing a 1 to a flag clears it.
The flags only get set when the corresponding IRQ is enabled in register 0xF0004418.
Bits | Desc. |
---|---|
6 | Read IRQ (read operation finished) |
7 | Write IRQ (write operation finished) |
The write IRQ triggers after the contents of the write FIFO have been entirely transferred.
The read IRQ triggers after the amount specified in register 0xF0004420 has been transferred.
Both IRQ conditions trigger IRQ 0x06. Not known yet which conditions would trigger IRQ 0x07.
0xF000440C
FIFO status. The read and write FIFOs can hold up to 16 bytes each.
Bits | Desc. |
---|---|
0-4 | Free space in write FIFO (16 when empty) |
8-12 | Occupied space in read FIFO (16 when full) |
When writing data, transfer completion should be checked for by waiting for a write IRQ rather than relying on the write FIFO level. Even when the write FIFO is empty, there may still be data being transferred.
0xF0004410
Data input/output.
During a write transfer, data written to this register is queued up in the write FIFO.
During a read transfer, the desired amount of bytes is written to 0xF0004420, then received data is queued up in the read FIFO and can be retrieved by reading 0xF0004410.
WARNING: if the write FIFO is already full, writes to this register are discarded. There seems to be no error signal in this case, so you have to be mindful of this.
In a similar vein, a read transfer will halt if the read FIFO is full (and resume when it is no longer full).
Using DMA takes care of this automatically, avoiding many potential problems.
It isn't known if there are IRQs for FIFO full/empty conditions, but there doesn't seem to be any.
0xF0004414
Controls low-level aspects of the SPI protocol.
Bits | Desc. |
---|---|
0 | CPHA - Clock phase |
1 | CPOL - Clock polarity; 0=invert source clock, 1=use source clock as-is |
4 | ?? |
15 | ?? |
Clearing bit 15 has weird effects: seems to force CPOL to 1? This causes the transmitted data to be offset by one bit unless CPHA is 1.
0xF0004418
SPI IRQ enable.
Bits | Desc. |
---|---|
0 | ??? |
1 | Unknown, causes lock-up during write transfer |
2 | ??? |
3 | Unknown, causes lock-up during write transfer |
4 | ??? |
5 | ??? |
6 | Enable read IRQ |
7 | Enable write IRQ |
8 | ??? |
9 | ??? |
0xF0004420
Number of bytes to read.
When the transfer mode is set to read, writing to this register will initiate a transfer.
This register does not change after a transfer.
0xF0004424
Specifies which device will be selected during SPI transfers.
Bits | Desc. |
---|---|
0 | Select Flash |
1 | Select UIC |
Setting both bits will result in both devices being selected at the same time.
Unknown if there are more devices? The diagnostics firmware accesses a third device named 'Userial' by toggling GPIO 0xF0005104. It also does not use register 0xF0004424 at all, instead manually toggling the chipselect GPIOs.
On a retail gamepad, register 0xF0004424 only has two bits.
Using with DMA
The SPI controller can be used conjointly with DMA channels 0 or 1. Due to the simplistic design of the FIFO system, using DMA is more straightforward as it will take care of keeping the FIFOs happy for you.
To write using DMA, you simply start a DMA transfer instead of writing to 0xF0004410. You should rely on the SPI write IRQ to detect transfer completion.
To read using DMA, you set 0xF0004420 to the desired read length, then start a DMA transfer instead of reading from 0xF0004410. You should rely on the DMA IRQ to detect transfer completion.
SPI commands
For Flash commands, see the Flash datasheet.
For UIC commands, see the UIC page.