NanoBoard SPI Communications - Accessing the Common SPI Bus from an FPGA Design

Frozen Content

Related articles: NanoBoard SPI Communications - Interface Wiring, Using SPI Flash Memory as Embedded Memory

From an FPGA design perspective, the NanoBoard's SPI Controller provides an SPI path from the target FPGA device to each of the common-bus SPI slave resources resident in the system.

Signals SPI_DIN, SPI_DOUT, SPI_CLK, SPI_SEL and SPI_MODE provide this connectivity.
 

In the schematics for a NanoBoard, these signals may appear with slightly different naming. For example on the NanoBoard NB2, they are DAU_SPI_DIN, DAU_SPI_DOUT, DAU_SPI_CLK, DAU_SPI_SEL and DAU_SPI_MODE.

 


Handling of SPI-related signals from the FPGA design.


In the preceeding image, DIN and DOUT on the SPI Bus side refer to direction from the slave device perspective.

 
During operation, the FPGA design communicates with the NanoBoard's SPI Controller to establish a path between the design and a specific motherboard/peripheral board common-bus SPI device. Communications with the target device is a two-stage process:

  • Firstly, the address of the target SPI device must be written to an address register within the SPI Controller and bus ownership must be requested.
  • Secondly, once ownership of the SPI bus is granted, the SPI lines from the target FPGA must be routed to the external SPI bus itself, and the select line for the required slave device made active.

In terms of communication with the SPI Controller, the FPGA design has two modes of access – either accessing and writing to the Controller itself, or communicating directly with a selected target device over the routed SPI bus. The following sections look more closely at how the target FPGA can switch between these two modes, obtain ownership of the common SPI bus, select a device for communications, and release the bus after it has finished with the slave device.

Mode of Access

A design running in the target FPGA can either access the SPI Controller itself, or the SPI bus directly. These two modes of access are determined by the level of the SPI_MODE signal:

  • SPI_MODE = High – communicate with the SPI Controller and, more specifically, an 8-bit SPI device address register therein.
  • SPI_MODE = Low – communicate directly with a slave device over the SPI bus.

Getting Ownership of the Bus

Only one of the three bus masters – Altium Designer, firmware, or target FPGA – can access a common-bus SPI device at any one time. Therefore the SPI Controller in the NanoBoard firmware provides simple multiplexed access to the common SPI bus. Arbitration of the masters – who has control of the bus at any given time – is achieved by employing the notion of 'bus ownership'.

Each of the three masters may request ownership of the bus. The job of bus arbitration for the SPI Controller therefore becomes two-fold:

  • Monitor bus requests from each master and grant ownership to one
  • Route the internal SPI lines, from the master that is granted ownership, to the common SPI bus.


Bus ownership will only be granted provided the common SPI bus is currently not being used. This allows any current transmission on the bus to terminate naturally without any errors.

 
If multiple requests for the bus are present, the following order of ownership hierarchy is adhered to:

  • Altium Designer – highest priority
  • Target FPGA
  • Firmware (TSK3000A)

From the design in the target FPGA, requesting ownership of the common SPI bus is performed through the SPI Controller's internal SPI device address register. To access this register you must ensure that the SPI_MODE line is High.

In order to request ownership of the common SPI bus, bit 7 of the register must be set ('1'). The register must also be loaded with the address of the device to which you wish to communicate. This address must be stored in bits 4..0 of the register. For device addresses, see Selecting a Slave SPI Device.

Data transfer on the SPI bus is always MSB first. The 8-bit value you intend to load into the address register is shifted into the register from the SPI_DOUT line, one bit at a time (from the right), on each rising edge of the SPI_CLK signal. For example, if you are using a NanoBoard NB2, and wish to request bus ownership in order to talk to the Touch Screen Digitizer, with address 00101, you must send out the 8 bit value 1xx00101 on the SPI_DOUT line.

Checking Whether Bus Ownership has been Granted

Putting in a request for the common SPI bus does not necessarily mean you will be granted access to it immediately. The bus may be already in use by one of the other masters in the system (Altium Designer or the firmware).

To check that bus ownership has been granted, before committing to the actual transmission of data to the target slave device, an SPI send-wait-receive routine is used. After sending out the value to be loaded into the address register on the SPI_DOUT line, the value received on the SPI_DIN line is checked against zero. If it is zero, the target FPGA has been granted ownership. Direct communications with the SPI device can then proceed, by taking the SPI_MODE and SPI_SEL lines Low.

The following software routine illustrates opening up an SPI channel for communications with a target SPI device:

bool nanoboard_spi_open(unsigned int base, unsigned char device)

 {

      device |= 0x80; //Enable bus request bit in address register
      spi_control_write (base,SPI_CTRL_ENABLE);
      spi_divider_write (base,spi_divisor());
      spi_mode_hi (base); //Access SPI address register
      spi_send_wait_receive(base,0x80 | device);
      if (spi_send_wait_receive(base,0x80 | device) == 0)
   {

          spi_mode_lo (base);
          spi_cs_lo (base);
          return true;
   }

      else
   {

          return false;
   }

 }

In the embedded software, the call to this routine could be in the form of a while loop, whereby the routine would be repeated (request bit set, target address loaded) until it returns True, meaning that Altium Designer or the firmware have released the SPI bus. For example:

.
.
.
while (!nanoboard_spi_open(Base_SPI, Device_Address));
.
.
.

The following wave diagrams illustrate the difference between a failed bus ownership request and a successful request, when trying to open communications with the Touch Screen Digitizer on the NanoBoard NB2. In the latter case, once the target FPGA has been given control of the common SPI bus, the SPI_MODE and SPI_SEL lines are taken Low, switching access mode to direct bus communications and enabling the addressed device's chip select line. Communications with that device can then proceed, in accordance with the SPI bus data exchange protocol.


Failed request to own the bus. The SPI_DIN line is still High after writing to the SPI address register, meaning the
bus is not available.

 

Successful request to own the bus. The SPI_DIN line is Low after writing to the SPI address register, meaning the
bus is available. The SPI_MODE and SPI_SEL lines are then taken Low, to enable communications with the addressed
device.

Selecting a Slave SPI Device

Depending on the type of NanoBoard you are using, the SPI Controller (inside the NanoBoard's Host Controller FPGA) provides multiplexed access to some or all slave SPI devices resident in the system. For such slave devices, the SCLK and DIN lines are common. For the majority of these devices, and specifically those which can be accessed from a design running on the target FPGA device, the DOUT lines are also common. The multiplexing process then simply becomes a job of toggling the required chip select line for the device you wish to communicate with.
 

On the NanoBoard NB2, all SPI devices are accessed over a common SPI bus. On a 3000-series NanoBoard, some SPI devices are accessed over a common SPI bus, whereas others – those only for use by a design programmed into the User FPGA – are accessed over direct, dedicated SPI links.

 
The state of the individual chip select lines for the common-bus SPI devices is controlled using the SEL and ADDR[4..0] lines. The SEL line is simply the SPI_SEL line routed through from the target FPGA once ownership of the common SPI bus has been granted. The ADDR[4..0] bus carries the address of the required device, and is the address loaded into bits 4..0 of the SPI Controller's internal 8-bit address register.

Only one common-bus SPI device can be selected for communications at any one time. The corresponding chip select line is taken Low (enabling communication with the device) provided that:

  • The SPI_SEL line from the target FPGA is taken Low and
  • The address of the target device is apparent on the ADDR[4..0] line.

Selecting a Common-bus SPI Device on the NanoBoard NB2

Related article: NB2DSK01 SPI System Overview

For common-bus SPI devices that can be accessed from a design programmed into the daughter board FPGA attached to your NanoBoard NB2, the unique device addresses and associated chip select signals are summarized in Table 1.

Table 1. Common-bus SPI device addresses and chip select signals when using the NanoBoard NB2.
Target Device
Address (Binary)
Address (Hexadecimal)
Associated Chip Select Signal

Flash Memory (Embedded/FPGA Boot)

00001
0x01
FLASH1_CS_N

Flash Memory (Embedded)

00010
0x02
FLASH2_CS_N

Board Clock

00100
0x04
CLKGEN_CS_N

Touch Screen Digitizer

00101
0x05
TFT_SPI_CS_N

Real Time Clock (RTC)

00110
0x06
RTC_CS_N

Peripheral Board A (Device 1)

00111
0x07
EXTSPI_CSA_N0

Peripheral Board A (Device 2)

01000
0x08
EXTSPI_CSA_N1

Peripheral Board B (Device 1)

01001
0x09
EXTSPI_CSB_N0

Peripheral Board B (Device 2)

01010
0x0A
EXTSPI_CSB_N1

Peripheral Board C (Device 1)

01011
0x0B
EXTSPI_CSC_N0

Peripheral Board C (Device 2)

01100
0x0C
EXTSPI_CSC_N1

Selecting a Common-bus SPI Device on the NanoBoard 3000

Related article: NanoBoard 3000 SPI System Overview

For common-bus SPI devices that can be accessed from a design programmed into the User FPGA on your 3000-series NanoBoard, the unique device addresses and associated chip select signals are summarized in Table 2.

Table 2. Common-bus SPI device addresses and chip select signals when using the NanoBoard 3000.
Target Device
Address (Binary)
Address (Hexadecimal)
Associated Chip Select Signal

User Flash Memory (Embedded/FPGA Boot)

00001
0x01
USERFLASH1_CS_N

User Flash Memory (Embedded)

00010
0x02
USERFLASH2_CS_N

Board Clock

00100
0x04
CLKGEN_CS_N

Real Time Clock

00110
0x06
RTC_CS_N

Peripheral Board (Device 1)

00111
0x07
EXTSPI_CSA_N0

Peripheral Board (Device 2)

01000
0x08
EXTSPI_CSA_N1

Releasing the Bus

Once you have finished communications with the intended slave SPI device, you must release the common SPI bus. This is achieved by taking the SPI_MODE line High, switching from direct SPI bus access to access of the SPI Controller's internal address register. Once accessed, you need to flush the register – writing it with all zeroes. As bit 7 of the register is no longer set, request of the SPI bus is cancelled and the SPI Controller will place the SPI bus back into the 'idle' (no ownership) state.

In addition, you should also take the SPI_SEL line High.

The following code routine shows how the release process can be implemented:

void nanoboard_spi_close(unsigned int base)

 {

    spi_mode_hi (base );
    spi_send_wait_receive(base,0);
    spi_cs_hi (base );
 }

You are reporting an issue with the following selected text and/or image within the active document: