Monday, March 23, 2015

SPI Host Controller and Device Programming

This page describes how to write a program to drive SPI host controller to communicate a SPI device (e.g., flash part) via SPI protocol. We know SPI has 4 wires, and SPI host controller has 2 FIFO, RX FIFO and TX FIFO. How does host controller work with both FIFOs and 4 wires SPI. I consider the Read-Id (EFh) command of the flash part W25Q80DV is an simplest example to describe the mechanism.

Please refer my previous page to understand Data Transmission via SPI.

The following block diagram uses a simple model to describe the hardware mechanism of SPI Host Controller with RX/TX FIFO, registers accessed by a program, and 4 SPI wires connected to a SPI device. This diagram skips the shift register in SPI Host Controller. It also skips the details hardware components of the SPI device.





SPI 4 Wires.

SPI has 4 wires, CS, CLK, MOSI, and MISO. Please refer the wiki page, SPI Bus.

Two FIFOs.

TX FIFO transmits data to a SPI device (e.g., flash part) via MOSI. When data are transmitted, CLK is also enabled. Therefore RX FIFO might receive dummy data via MISO at the same time.

Registers of SPI Host Controller

CS register selects a SPI device to begin to communicate via SPI.

Data register is a window to write data into TX FIFO and read data from RX FIFO.

TXL (TX Level) register reports the number of elements in TX FIFO.

RXL (RX Level) register reports the number of elements in RX FIFO.

SPI Programming.

The routine SpiTransfer() transmits Request with RequestSize bytes to a SPI device and receives Response with ResponseSize bytes from the SPI device.

SpiTransfer (
  IN UINT8 *Request
  IN UINTN RequestSize
  OUT UINT8 *Response
  IN UINTN ResponseSize
  )
{
  Dev = GetHcDevice ();

  // Select a SPI device.

  Dev->Hc->CsReg = 0;

  // Transmit the request to the SPI device via MOSI.

  for (i = 0; i < RequestSize; i++) {
    Dev->Hc->DataReg = Request [i]; // put a byte in TX FIFO.
    Delay (...); // wait for transmitting the byte.
    Dummy = Dev->Hc->DataReg; // clean a received dummy in RX FIFO.
  }

  // Clean dummy data in RX FIFO.

  while (Dev->Hc->RxlReg) { // if RX FIFO has dummy data,
    Dummy = Dev->Hc->DataReg; // clean the received dummy in RX FIFO.
  }

  // Receive a response from the SPI device via MISO.

  for (i = 0; i < ResponseSize; i++) {

    // put a dummy in TX FIFO to trigger CLK so that RX FIFO 
    // will receive data from the SPI device via MISO.
    Dev->Hc->DataReg = Dummy;     

    Delay (...); // wait for the dummy is transmitted. 
    Response [i] = Dev->Hc->DataReg; // Receive data in RX FIFO.
  }

  // Free the SPI device.

  Dev->HC->CsReg = 1;

}

-Count





No comments:

Post a Comment