NanoBoard SPI Communications - Accessing the Common SPI Bus from an FPGA Design
Contents
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
.
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.
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.
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.
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 );
}