Configuring and using the SPI bus on ZYNQ


ZYNQ contains two independent SPI controllers, and each controller can be routed to MIO pins or to the EMIO interface (the EMIO interface allows ZYNQs built-in peripherals to use pins normally reserved for the FPGA). Each controller can generate three independent SS signals and seven different interrupts, and each controller has its own set of control and status registers (shown in the table below).

Table 1. SPI Registers
Table 1. SPI Registers

ZYNQ’s SPI controllers include 128-byte managed FIFOs for both the transmitter and receiver (see the ZYNQ UART topic document for a discussion of managed FIFOs). Data placed in the transmit FIFO will be automatically serialized and sent out on the MOSI pin. Transmit data can be written into the FIFO much faster than it can be sent out, so if you write more than 128 bytes, you must manage the transmit FIFO by polling status bits or setting up interrupts. Data arriving in the receive FIFO can be read after checking status bits (to confirm new data is available) or in response to an interrupt. The tables below show the status bits that are available in the status register, and the available interrupt sources.

Table 2. SPI Status Register Bits
Table 2. SPI Status Register Bits
Table 3. Interrupt Functions
Table 3. Interrupt Functions

On the Blackboard, SPI0 is connected to an inertial module (the ST Micro LSM9DS1) that contains a gyroscope, an accelerometer, and a magnetometer (compass). SPI1 is connected to an on-board QSPI Flash ROM.

The SPI controller input clock is fixed at 166.666MHz. A mandatory programmable clock divider is applied to the input clock to divide it to a lower value. Bits 3-5 in the SPI Configuration Register define the clock divider value according to the formula: 166.666MHz / 2 ^ n +1, where n is the 3-bit number defined in the BAUD_RATE field (see table below). As an example, setting bits 3-5 to 100 will divide 166.666MHz by 32, resulting in an SCLK frequency of 5.2MHz.

Table 4. SPI Configuration Bits
Table 4. SPI Configuration Bits

Configuring the SPI controller

Before you configure the SPI module for use, you must reset it through the Zynq’s SLCR block (System Level Control Registers). There is a register which can assert and deassert reset to the SPI0 and SPI1 modules, but it cannot be written to unless write access to the SCLR block is ‘unlocked’. This can be accomplished by writting the specific value 0xDF0D to the unlock register (address 0xF8000008). The reset to the SPI can be asserted through the SLCR SPI reset register (address 0xF800021C); Set the lower 4 bits. After a small delay, you can clear the bits and the reset of the SPI modules will be complete. Now you should relock the SLCRs for security. Write the lock key 0x767B to the SLCR lock register at address 0xF8000004. the example code below has macros for these registers as well as a function that follows the above sequence.

//necessary SLCR addressesfor SPI reset
#define SLCR_LOCK		*( (uint32_t *) 0xF8000004)
#define SLCR_UNLOCK		*( (uint32_t *) 0xF8000008)
#define SLCR_SPI_RST 	*( (uint32_t *) 0xF800021C)

//SLCR lock and unlock keys
#define UNLOCK_KEY	0xDF0D
#define LOCK_KEY	0x767B

void reset_SPI(void)
	int i=0; //i for delay
	SLCR_SPI_RST = 0xF;		//assert SPI reset
	for(i=0;i<1000;i++);		//make sure Reset occurs
	SLCR_SPI_RST = 0;		//deassert
	SLCR_LOCK = LOCK_KEY;		//relock SLCRs
Chip selects

The chip/slave-select (CS/SS) lines are the mechanism SPI uses to choose which devices the bus master is communicating with. The Zynq’s SPI module has support for automatically driving chip selects during a bus transfer. This is controlled through bit 15 in the SPI control register (0:auto CS, 1:manual CS). If manual CS is enabled, the module will drive the configured CS even when no transaction is on the SPI bus (the CS lines will reflect the value in the control register).

The module also supports using an external decoder to support more than 3 CS lines. If decoder support is enabled more than 1 CS line can be driven at once, if the option is disabled only a single line can be driven at a time.

In auto CS mode, the chip-select defined by the control register’s bits 13:10 are driven. If the external decoder is enabled, the CS lines will reflect the state of bits 12-10, bit 13 must be set high. If the external decoder is disabled, the lowest CS bit set to zero is prioritized CS0 has the highest priorty, CS2 has the lowest. Setting bits 13:10 to 4b1xx0 will drive CS0, 4b1x01 will drive CS1, and 1011 will drive CS2 (x is don’t care).

Example Configuration

The configuration of the SPI module may need to be different for communication with different devices. The configuration covered below is recommended for communication with the inertial module on the Blackboard.

There are no other master devices connected on SPI0, therefore the SPI0 module must assume the master role. Set bit 0 in the control register to ‘1’

The Inertial Module Uses SPI Mode 3 for communication. That is, the clock pulses low for each bit (CPOL=1), as well as data being shifted out on leading clock edges and ‘clocked’ on trailing edges (CPHA=1). Additionally, the iNemo module has a max SPI clock speed of 10MHz, any clock speed below will work as well.

The baudrate divider for the SPI clock only divides powers of 2. The baudrate can be calculated from value of bits 3-5 in the SPI control register (baud_clk = 166.666MHz/2^(n+1). A divider value of 32 gives ~5.2MHz, which falls below the 10MHz requirement. So a working value you can put in the bitfield is 4

To configure the SPI module for communication with the inertial module, make sure the CPHA, CPOL, and clock divider bits in the Control register match the settings the inertial module needs.

The remaining fields in the control register control the chip-select lines as well as configure how SPI transactions are started.

On the blackboard, the Zynq’s SPI0 CS lines are only connected to the accelerometer and gyroscope chip selects of the inertial module. The accelerometer and gyroscope are selected via CS0 and the magnetometer is selected with CS1. These lines are not connected through a decoder, so the external decoder bit (CR, bit 9) should be clear (making the chip selects mutually exclusive). For convenience, the chip select mode can be set to automatic by clearing bit 1 in the CR; If auto-CS is enabled, the chip select will only drive when an SPI transaction is active.

Before you start a transaction, set the CS field in the control register (bits 13:10) to the appropriate value for the slave device you want. The Acc/Gyro is selected with CS0, so a value of 4b1110 can be used for an SPI transaction with it. The magnetometer is activated with CS1.

Summary of the example configuration

  • SPI in master mode
  • Configure for mode 3 (CPOL=1 and CPHA=1)
  • Divide clock to 5.2MHz (BAUD_RATE=4)
  • Set to no decoder (PERI_SEL=0)
  • Set to manual chip-select (MANUAL_CS=0)
  • Set to automatic start (MANUAL_START_EN=0)

Now writing data to the SPI TX FIFO will start an SPI bus transaction. Make sure you set the slave select value of the device you want in the control regsiter before you begin a transaction.

Starting SPI transfers

Transfers on the Zynq’s SPI can be started in 2 ways. If the manual start enable bit (bit 15) is set in the control register, transfers will begin after the manual start bit (bit 16) in the register is set.

If the manual start enable bit is clear, the module will automatically start transfers when there is at least one byte in the transmit FIFO

In both modes, the SPI controller on zynq will continue a transfer as long as there is data in the TX FIFO. Once the TX FIFO becomes empty, the bus transaction ends. On Zynq, if you wish to receive a number of bytes, you must put that many bytes in the transmit FIFO first.

Communicating with an SPI slave

The actual communication sequence via SPI can differ from device to device. The only way to know is to read the data sheet or reference manual for your specific device. It’s commonplace for device manufacturers to include multiple timing diagrams for different operations (single byte read/write, multibyte, etc).

An example of a device-specific protocol over SPI is the accelerometer portion of the inertial module. To read from an accelerometer/gyroscope register, the bus master provides an address in the first byte sent. The accelerometer will then send the data from the corresponding register over the next 8*n (for an n-byte read) SPI clock cycles. For a 1-byte read from the accelerometer, there would need to be 16 clock cycles in the SPI transaction (2 bytes); 8 cycles for the master sending the address (and indicating a read operation) and 8 cycles for the slave device, the accelerometer, sending the register’s contents. As stated above, the Zynq’s SPI module will extend a transaction as long as there is more data to transmit in the FIFO. To read one byte from the accelerometer, you need to place the address in the TX FIFO first, and then place an additional byte after it. This can be any value, as the inertial module will disregard. This, however, this is not the case with every device.

After the SPI transaction completes the data read from the slave device will be availible in the SPI module’s RX FIFO. Since 16 clock cycles occured on the bus, the RX FIFO will have 2 bytes in it. The first byte is the data read from the inertial module while the bus master was sending the address. The second byte will contain the actual data for the register requested. It is necessary to read the first byte, but it can be discarded.

See the iNemo’s background information and reference manual for complete details on communicating with the module.