User Tools

Site Tools


spi

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
spi [2024/09/29 11:44] arisoturaspi [2025/04/17 15:44] (current) arisotura
Line 7: Line 7:
  
 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 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: The SPI controller has the following registers:
Line 15: Line 17:
 | 0xF000440C | FIFO status | | 0xF000440C | FIFO status |
 | 0xF0004410 | Data input/output | | 0xF0004410 | Data input/output |
-| 0xF0004414 | ?? |+| 0xF0004414 | SPI low-level control |
 | 0xF0004418 | IRQ enable | | 0xF0004418 | IRQ enable |
 | 0xF0004420 | Number of bytes to read | | 0xF0004420 | Number of bytes to read |
Line 26: Line 28:
  
 ^ Bits ^ Desc. ^ ^ Bits ^ Desc. ^
-| 0-2  | Clock multiplier |+| 0-2  | Clock source |
 | 3-10 | Clock divider | | 3-10 | Clock divider |
 +| 11-14 | ?? |
 | 15   | SPI enable (possibly just clock enable) | | 15   | SPI enable (possibly just clock enable) |
  
-The clock multiplier selects the base clock, and the clock divider divides that by a fixed value to produce the final SPI clock.+The clock source selects the base clock, and the clock divider divides that by a fixed value to produce the final SPI clock.
  
-The following clock multiplier values are available: +The clock source and divider values work the same way as in the [[General registers#Per-module clock settings|per-module clock setting registers]].
-^ Multiplier ^ Clock ^ +
-| 0          | 32MHz | +
-| 1          | 12MHz | +
-| 2          | ???   | +
-| 3          | ???   | +
-| 4          | ~857MHz | +
-| 5          | 3.38MHz | +
-| 6          | 15.9MHz | +
-| 7          | 3.38MHz | +
- +
-Not sure how these values are generated internally. I couldn't get settings 2 and 3 to produce any observable output even at the highest divider setting. Setting 4 only works at low enough divider settings, and suggests that some kind of PLL is used. Not sure if the input clock is dependent on the system clock+
- +
-The clock divider setting is a simple count-up divider. For example, setting it to 31 divides the clock by 32.+
  
 Observed settings in the stock firmware are the following: Observed settings in the stock firmware are the following:
-^ Register value ^ Destination ^ Clock speed ^ +^ Register value ^ Destination ^ Clock speed  
-| 0x808C         | FLASH       48MHz       | +| 0x808C         | FLASH       48 MHz       | 
-| 0x8018         | UIC         8MHz        | +| 0x8018         | UIC         8 MHz        | 
-| 0x835C         | UIC         8MHz        | +| 0x835C         | UIC         8 MHz        | 
-| 0x83F8         | UIC         250KHz      | +| 0x83F8         | UIC         250 KHz      | 
-| 0x8400         | UIC         248KHz      |+| 0x8400         | UIC         248 KHz      |
  
  
Line 79: Line 69:
  
 SPI IRQ flags. Writing a 1 to a flag clears it. 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. ^ ^ Bits ^ Desc. ^
Line 98: Line 90:
 | 0-4  | Free space in write FIFO (16 when empty) | | 0-4  | Free space in write FIFO (16 when empty) |
 | 8-12 | Occupied space in read FIFO (16 when full) | | 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.
  
  
Line 110: Line 104:
 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. 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.+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. It isn't known if there are IRQs for FIFO full/empty conditions, but there doesn't seem to be any.
- 
-Not yet known how SPI DMA works. 
  
  
 **0xF0004414** **0xF0004414**
  
-Unknown. Bits 0-1, 415 set by firmware code.+Controls low-level aspects of the SPI protocol. 
 + 
 +Bits ^ Desc. ^ 
 +   | CPHA Clock phase | 
 +   | CPOL - Clock polarity; 0=invert source clock1=use source clock as-is | 
 +   | ?? | 
 +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.
  
  
Line 157: Line 159:
  
 Setting both bits will result in both devices being selected at the same time. 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.1727610292.txt.gz · Last modified: 2024/09/29 11:44 by arisotura

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki