spi_to_i2c_bridge.vhd (8.6 KB)
spi_slave.vhd (8.1 KB)
spi_to_i2c.vhd (7.0 KB)
i2c_master.vhd (12.9 KB)
- VHDL source code of an SPI to I2C Bridge
- User definable system clock
- User definable SPI mode
- User definable I2C serial clock frequency
- Designed to write and/or read 8-bit I2C slave registers
- Notifies SPI master of any I2C slave acknowledge errors
- Meets the NXP UM10204 I2C-bus specification for single master buses
- Uses 7-bit slave addressing for I2C
- Compatible with clock-stretching by I2C slaves
- Not recommended for use with multi-master I2C buses (no arbitration or synchronization)
This details an SPI to I2C bridge component for use with single master I2C buses, written in VHDL for CPLDs and FPGAs. The bridge is designed to enable an SPI master to write and/or read 8-bit I2C slave registers. It was designed using Quartus II, version 11.1. Resource requirements depend on the implementation. Figure 1 illustrates a typical example of the SPI to I2C bridge integrated into a system.
Figure 1. Example SPI to I2C Bridge Implementation
The source code of the SPI to I2C bridge consists of the following four VHDL files:
Figure 2 illustrates the relationship between these files.
Figure 2. SPI to I2C Bridge Architecture
The spi_to_i2c_bridge.vhd file is the top level wrapper that instantiates and connects the other three files together.
The spi_slave.vhd file defines an SPI slave component that interfaces directly with the external SPI master. Detailed documentation for this SPI slave component (v1.2) is available here.
Likewise, the i2c_master.vhd defines an I2C master component that communicates directly with the I2C slave components. Detailed documentation for this I2C master component (v2.2) is available here.
The spi_to_i2c.vhd file controls the operation of the bridge and translates between the SPI slave and I2C master. The state diagram in Figure 3 depicts its operation. The bridge waits in a ready state, monitoring the SPI slave’s busy signal and its receive ready (rrdy) status register. The rrdy port asserts once the SPI slave has received a new data transmission from the SPI master. The busy signal indicates when the SPI slave is available. Once both conditions are met, the bridge requests the new SPI data from the slave and enters the spi_rx state. The new SPI data is then latched. If the data includes a command to conduct an I2C transaction (bit 25 is ‘1’), then it proceeds to the i2c state. If the command did not request an I2C transaction (bit 25 is ‘0’), the bridge returns to the ready state. Once in the i2c state, the bridge logic executes the transaction over the I2C bus using the I2C master component. This transaction requires several clock cycles. Its duration depends on the I2C serial bus speed, the system clock, and the existence of clock stretching by the slave. Once complete, the bridge proceeds to the spi_load_tx state. It waits until the SPI slave is not busy and then writes the result of the I2C transaction to the slave’s transmit register and returns to the ready state. The SPI slave’s transmit ready (trdy) status register asserts when the transmit register is thus loaded by the bridge, indicating that the I2C result is now available for retrieval by the SPI master and that the bridge is ready for another transaction. The SPI master can receive the trdy signal via a pin interrupt using the trdy port or by polling the SPI slave’s status registers over the SPI bus itself.
Figure 3. SPI to I2C State Machine
For simplicity, the reset functionality is not shown in the state diagram. If at any time the reset_n port is pulled low, the bridge re-initializes and the state machine returns to the ready state.
Table 1 describes the SPI to I2C bridge’s ports.
Table 1. Port Descriptions
The spi_to_i2c_bridge.vhd file is the top level VHDL wrapper file for the bridge component. There are four GENERIC parameters defined in its ENTITY that comprise the user definable aspects of the component.
The sys_clk_frq parameter must be set to the input system clock frequency in Hz. The default setting in the example code is 50 MHz (the frequency at which the component was simulated and tested).
The i2c_scl_frq parameter must be set to the desired frequency of the I2C serial clock scl. The default setting in the example code is 400 kHz, corresponding to the Fast-mode bit rate in the I2C specification.
The mode that the SPI interface operates in is defined by the parameters cpol and cpha. The SPI master and the SPI to I2C bridge must both operate in the same mode to communicate. The default values are ‘0’ for both parameters.
This bridge implementation enables an SPI master to write and/or read 8-bit I2C slave registers. Each transaction between the bridge’s SPI slave component and an SPI master must consist of an 8-bit command, followed by a 25-bit data transfer. Therefore, to execute a transaction, the SPI master sends a 33-bit command to the slave, outlined in Table 2. The command includes the 8-bit SPI slave command, an I2C enable bit, the 7-bit address of the I2C slave, a read/write bit, an 8-bit register address to access within the I2C slave, and the 8-bit data to write to the I2C slave. The command is transmitted MSB first. The SPI slave’s MISO line remains high impedance during the 8-bit SPI slave command, and then returns data during the remaining 25 bits. See the documentation on the SPI slave for complete timing details here.
Table 2. Command Format
Table 2 also lists the commands necessary to perform various actions. The first bit of the SPI slave command specifies which register inside the bridge’s SPI slave to write. ‘0’ indicates the SPI slave’s receive register, where the bridge receives the command and evaluates what to do. If the I2C enable bit is a ‘1’, the bridge conducts an I2C transaction. If ‘0’, the bridge ignores the rest of the bits and does nothing on the bus. This option allows the SPI master to read an I2C result or the bridge’s status register without issuing a new I2C transaction.
The second bit specifies which register inside the bridge’s SPI slave to return to the SPI master. ‘0’ indicates the SPI slave’s transmit register, which always holds the result of the last I2C transaction. ‘1’ indicates the SPI slave’s status register. The SPI master may read the status register to poll for the value of trdy, which is the first bit returned.
The final 24 bits specify the requested I2C transaction. The 8 data bits at the end are ignored if the transaction is a read.
Following each I2C transaction, the bridge loads a 25 bit result into the SPI slave’s transmit register, where it is available to the SPI master, as described above. Table 3 shows the I2C result’s format. The I2C acknowledge error bit indicates if any I2C slave acknowledge errors occurred during the transaction. (‘1’ indicates at least one error occurred, ‘0’ indicates no errors.) The bridge does not retry a transaction in the event of an acknowledge error, so the SPI master must reissue the command if it desires to retry the communication. The 7-bit I2C slave address, read/write bit, and 8-bit I2C slave register indicate what command had been sent. The 8 data bits return the data read if the command was a read, and they return the data written if the command was a write.
Table 3. I2C Result Format
Section 3.1.9 of the I2C specification defines an optional feature where a slave can hold scl low to essentially pause the transaction. Some slaves are designed to do this if, for instance, they need more time to store received data before continuing. This I2C master component is compatible with slaves that implement this feature. It requires no action by the user controlling the I2C master.
The reset_n input port must have a logic high for the SPI to I2C bridge component to operate. A low logic level on this port asynchronously resets the component. During reset, the miso, scl, and sda ports assume a high impedance state, and the trdy register clears.
This SPI to I2C bridge is a programmable logic component that allows SPI master devices to write and/or read 8-bit I2C slave registers. It offers user definable SPI mode, I2C bus frequency, and system clock frequency. It adheres to the NXP I2C specification in regard to single master buses and also incorporates the optional feature of clock stretching.
Comments, feedback, and questions can be sent to firstname.lastname@example.org.