- VHDL source code of a Serial Peripheral Interface (SPI) 3-wire master component
- Configurable number of slaves
- Configurable command width
- Configurable data width
- Selectable polarity and phase
- Selectable speed
This details an SPI 3-wire master component for use in CPLDs and FPGAs, written in VHDL. The component was designed using Quartus II, version 12.1. Resource requirements depend on the implementation (i.e. the desired number of slaves and data width). Figure 1 illustrates a typical example of the SPI 3-wire master integrated into a system. An SPI 4-wire master component is available here, and an SPI 4-wire slave component is available here.
Figure 1. Example Application
An SPI 3-wire communication scheme is a half-duplex data link. The master initiates the transaction by pulling the Slave Select (SS) wire low. A Serial Clock (SCLK) line, driven by the master, provides a synchronous clock source. The Serial Data In/Out line is a bidirectional data line over which the master transmits and receives data. In a typical scenario, the master transmits a command of a specified length over the SDIO line. If it is a write command, the master then transmits fixed-length data on the line. If it is a read command, the slave transmits and the master receives a fixed-length data response.
A master can communicate with multiple slaves via a variety of techniques. In the most common configuration, each slave has an independent SS line but shares the SCLK and SDIO lines with the other slaves. Each slave ignores the shared lines when its SS line is not pulled low. This topology is shown in Figure 1 above.
SPI has four modes of operation, based on two parameters: clock polarity (CPOL) and clock phase (CPHA). Master and slave must use the same mode to communicate articulately. If CPOL is zero, then SCLK is normally low, and the first clock edge is a rising edge. If CPOL is one, SCLK is normally high, and the first clock edge is a falling edge. CPHA defines the data alignment. If CPHA is zero, then the first data bit is written on the SS falling edge and read on the first SCLK edge. If CPHA is one, data is written on the first SCLK edge and read on the second SCLK edge. The timing diagram in Figure 2 depicts the four SPI modes.
Figure 2. SPI 3-Wire Timing Diagram
Table 1 describes the SPI master’s ports. The number of slaves is declared in the ENTITY by the GENERIC parameter slaves. The command bus width is declared by the GENERIC parameter cmd_width. The transmit and receive data bus widths are declared by the GENERIC parameter d_width.
Table 1. Port Descriptions
|clock||1||in||standard logic||user logic||System clock.|
|reset_n||1||in||standard logic||user logic||Asynchronous active low reset.|
|enable||1||in||standard logic||user logic||H: latches in settings, address, rw, command, and data to initiate a transaction, L: no transaction is initiated.|
|cpol||1||in||standard logic||user logic||SPI clock polarity setting.|
|cpha||1||in||standard logic||user logic||SPI clock phase setting.|
|user logic||Speed setting. The integer input is the number of system clocks per 1/2 period of sclk.|
|addr||32||in||integer||user logic||Address of target slave. The slaves are assigned addresses starting with 0.|
|rw||1||in||standard logic||user logic||H: the transaction is a write, L: the transaction is a read.|
|tx_cmd||K+||in||standard logic vector||user logic||Command to transmit.|
|tx_data||M*||in||standard logic vector||user logic||Data to transmit.|
|sclk||1||buffer||standard logic||slave devices||SPI clock.|
|ss_n||N^||buffer||standard logic vector||slave devices||Slave select signals.|
|sdio||1||inout||standard logic||slave devices||Serial data signal.|
|busy||1||out||standard logic||user logic||Busy / data ready signal.|
|rx_data||M*||out||standard logic vector||user logic||Data received from target slave.|
+ K is the specified command width, set by the cmd_width generic
* M is the specified data width, set by the d_width generic
^ N is the specified number of slaves, set by the slaves generic
The clock and clk_div inputs define the frequency of SCLK (i.e. the SPI data rate). clock is the system clock used to operate the synchronous logic inside the component. The clk_div integer input allows the user to set the relative speed at which the current transaction occurs. clk_div is the number of clock periods between SCLK transitions, as described by Equation 1.
When the clk_div port is set to 1, the SCLK frequency is half the clock frequency and is set at the maximum achievable data rate. The enable pin latches the value of clk_div into the component to begin each transaction, so it is possible to adjust the data rate for individual slaves.
Setting the clk_div port to a constant value permanently sets the data rate. If clk_div is set to 0, the component assumes a value of 1. Therefore, tying the clk_div port low configures the component to always operate at maximum speed.
Polarity and Phase
The enable pin latches in the standard logic values of cpol and cpha at the start of each transaction. This allows communication with individual slaves using independent SPI modes. If all slaves require the same mode, cpol and cpha can simply be tied to the corresponding logic levels.
Command and Data Widths
The cmd_width GENERIC parameter in the ENTITY specifies the length of the command portion of a transaction. Likewise, the d_width GENERIC parameter specifies the length of the data portion of a transaction. Figures 3 and 4 show signal timing diagrams for write and read transactions, respectively, given CPOL = 0 and CPHA = 0. In these timing diagrams, K = cmd_width and M = d_width. As shown, both commands and data are sent MSB first.
Figure 3. Timing Diagram for a Write Transaction (CPOL = 0, CPHA = 0)
Figure 4. Timing Diagram for a Read Transaction (CPOL = 0, CPHA = 0)
A low logic level on the busy output port indicates that the component is ready to accept a command. The component latches the settings, address, rw, command, and data for a transaction on the first rising edge of clock where the enable input is asserted. On the following clock, the component asserts the busy signal and begins performing the transaction. Once complete, the component outputs the received data on the rx_data port if the transaction was a read. This data remains on the port until the component receives new data from a subsequent read transaction. The component sets busy low to notify the user when the transaction is complete and received data is available. The component is then immediately ready for another instruction.
Figure 3 shows the timing diagram for a typical transaction. This SPI 3-wire master is configured with one slave, an 8 bit command width, and an 8 bit data width. The enable pulse latches in the settings CPOL = 1, CPHA = 1, clk_div = 0 (a maximum speed of fsclk = fclock/2), a slave address of 0, rw = 0 (indicating a read transaction), and the command “10011001.” The tx_data port does not matter, since this is a read transaction. The SPI 3-wire master then transmits the command and receives the response from the slave. Once the transaction is completed, it sets the busy output low and asserts the received data “01010101” on the rx_data port.
Figure 5. Timing Diagram for a Typical Transaction
The reset_n input port must have a logic high for the SPI 3-wire master component to operate. A low signal on this port asynchronously resets the component. During reset, the component holds the busy port and all ss_n outputs high. The sdio port assumes a high impedance state, and the rx_data output port clears. Once released from reset, the busy port deasserts on the following clock, indicating the SPI master’s readiness to communicate.
The SPI 3-wire master is a flexible programmable logic component that accommodates communication with a variety of slaves via a single parallel interface. It allows communication with a user specified number of slaves, which may require independent SPI modes and serial clock speeds. It also allows the user to configure the desired command and data sizes.
Comments, feedback, and questions can be sent to email@example.com.