Version 1.2: spi_slave.vhd (8.1 KB)
Modified architecture slightly to make it synthesizable with more tools
Version 1.1: spi_slave_v1_1.vhd (8.0 KB)
Added an asynchronous active low reset
Version 1.0: spi_slave_v1_0.vhd (7.5 KB)
- User definable SPI mode
- User definable data width
- Status register with Transmit Ready, Receive Ready, and Receive Overrun Error bits
- Status register bits available to the master via SPI transaction and/or via individual pin interrupts
- Status register bits available to user logic
This details an SPI slave component for use in CPLDs and FPGAs, written in VHDL. The component was designed using Quartus II, version 11.1. Resource requirements depend on the implementation (i.e. the data width). Figure 1 illustrates a typical example of the SPI slave integrated into a system.
Figure 1. Example Application
An SPI communication scheme is a full-duplex data link, using four wires. 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 master transmits data via the Master Out, Slave In (MOSI) line and receives data via the Master In, Slave Out (MISO) line.
A master can communicates with multiple slaves via a variety of techniques. In the most common configuration, each slave has an independent SS line but shares the SCLK, MISO, and MOSI lines with the other slaves. Each slave ignores the shared lines when its SS line is not pulled low.
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 Timing Diagram
Table 3 describes the SPI slave’s ports. The mode that the slave operates in is defined by the GENERIC parameters cpol and cpha. The transmit and receive data bus widths are declared by the GENERIC parameter d_width.
Table 3. Port Descriptions
The slave component’s SPI mode is set by the user with the cpol and cpha GENERIC parameters in the VHDL entity.
Each transaction between this SPI slave component and the SPI master must consist of an 8-bit command, followed by a N-bit data transfer. The size N of the data transfer is determined by the GENERIC d_width parameter in the VHDL entity and is set by the user. Figure 3 illustrates a transaction with cpol = 0, cpha = 0, and d_width = 8.
Table 1 defines the 8-bit command sent over MOSI by the master. The master must send the command MSB first.
Table 1. 8-bit Command Format
The SPI slave component contains three registers: receive, transmit, and status. The wr_addr bit identifies which slave register the MOSI line writes to during the data transfer, and the rd_addr bit identifies which register the MISO line transmits back to the master. Table 2 shows the addresses of each register.
Table 2. Register Addresses.
The receive register is a buffer that holds data received from the master over the MOSI line. For the user logic to access the resulting data, the user must pulse the rx_req input when the component is not performing a transaction (i.e. when the busy output is low). The slave then outputs the receive register contents on the rx_data port.
The transmit register is a buffer that holds the data intended to be transmitted by the slave to the master over the MISO line. The user logic fills this register by presenting the data on the tx_load_data port and pulsing the tx_load_en input when the component is not performing a transaction (i.e. the busy output is low).
The SPI slave can operate without using the status register. This register provides the user with information regarding the state of the slave component but is not required to use the component.
The status register contains three status bits. The master can read, set, or clear these bits with transactions addressed to this register. During a transaction that reads or writes the status register, the first three data bits sent correspond to trdy, rrdy, and roe, respectively. The slave component ignores the remaining bits sent or received during the transaction. The user logic has access to these bits via the ports bearing their names. The user logic can also set or clear these bits by presenting the desired values on the st_load_trdy, st_load_rrdy, and st_load_roe inputs and pulsing the st_load_en input when the component is not performing a transaction (i.e. the busy output is low).
The trdy (transmit ready) bit indicates that the user logic has written new data to the transmit register after the last SPI transaction was performed, so the master has not yet read the data present. The component clears the trdy bit the next time the master reads the transmit register.
The rrdy (receive ready) bit indicates that the master has written new data to the receive register after the user logic has last read the receive register, so the user logic has not yet received the latest data. The component clears the rrdy bit once the user logic requests the data.
The roe (receive overrun error) bit indicates that the master has overwritten the last received data before the user logic ever read the data. The master can clear the roe bit by writing to the status register with an SPI transaction, or the user logic can clear the bit by writing to the status register over the st_load inputs as described above.
The trdy, rrdy, and roe ports also provide a means of interrupting the SPI master device or user logic by a change in the SPI slave status without requiring an SPI transaction. The user can attach these ports to the SPI master, to the user logic, to both, or to neither.
Figure 4 illustrates an example transaction (simulated in ModelSim Altera Starter Edition 10.0c). The slave is configured to operate in mode “00”. While the slave is not busy, the user logic pulses the tx_load_en input while presenting the data “10101010” on the tx_load_data bus. The trdy signal immediately goes high to indicate that new data exists to transmit. The master then initiates the transaction with the command “00000000”, instructing the slave to load the subsequent MOSI data into the receive register and output the transmit register’s contents to MISO. Once the last data bit is sent, the trdy signal goes low to indicate that the transmit register’s current value has been sent to the master. Likewise, when the slave reads the last data bit into the receive register, the rrdy signal asserts to indicate that new data has been received. The user logic then pulses the rx_req input, and the slave responds by outputting the received data “10110001” on the rx_data bus. The rrdy output then deasserts to indicate that the data contained in the receive register has already been read by the user logic.
Figure 4. Example Transaction
The reset_n input port must have a logic high for the SPI slave component to operate. A low signal on this port asynchronously resets the component. During reset, the miso output assumes a high impedance state, and the rx_data output port clears. The transmit, receive, transmit ready, receive ready, and receive overrun error registers all clear.
This VHDL SPI slave offers a user definable mode and data width. It includes status signals for transmit ready, receive ready, and receive overrun error.
SPI to I2C Bridge (VHDL) - This design uses the SPI Slave described on this page to implement an SPI to I2C Bridge.
Comments, feedback, and questions can be sent to email@example.com.