SBUS

From embeddedTS Manuals
Revision as of 22:37, 23 July 2011 by Mark (talk | contribs) (Created page with "{{Infobox |title = SBUS |image = 400px |titlestyle = |headerstyle = background:#ccf; |labelstyle = width:33% |datastyle = |label...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
SBUS
File:Sbus-diagram.png
sbus.c
sbus.h

Overview

While many CPUs contain some type of parallel interface that we can use for FPGA communication, the Cavium CNS2132 only has an SPI interface. It functions quite well, however some programming considerations must be made with this processor. Since SPI cannot be shared, we have implemented the SBUS which is a locking mechanism to communicate to the 128k of registers in the FPGA. We use this on all of our applications that communicate with the FPGA which includes sdctl, nandctl, xuartctl, daqctl, spiflashctl, dioctl, and ts7500ctl.

If you use the ctl applications as libraries, they will abstract this.

Code Example

This example shows accessing DIO directly without dioctl.

#include "sbus.h"
#include <assert.h>
#include <string.h>
#include <stdio.h>

#define DIO_Z 2

/*******************************************************************************
* Main: accept input from the command line and act accordingly.
*******************************************************************************/
int main(int argc, char **argv)
{
   int pin;
   int val;
   int returnedValue;
         
   // Check for invalid command line arguments
   if ((argc > 4) | (argc < 3))
   {
       printf("Usage: %s <get|set> <pin#> <set_value (0|1|2)>\n", argv[0]);
       return 1;
   }
   
   // We only want to get val if there are more than 3 command line arguments
   if (argc == 3)
      pin = strtoul(argv[2], NULL, 0);
   else
   {
      pin = strtoul(argv[2], NULL, 0);
      val = strtoul(argv[3], NULL, 0);
   }
   
   // If anything other than pins 5 through 40, fail program
   assert(pin <= 40 && pin >= 5);

   // Parse through the command line arguments, check for valid inputs, and exec
   if (!(strcmp(argv[1], "get")) && (argc == 3))
   {
      sbuslock();
      returnedValue = getdiopin(pin);
      sbusunlock();
      
      printf("pin#%d = %d \n", pin, returnedValue);
   }
   else if(!(strcmp(argv[1], "set")) && (argc == 4) && (val <= 2))
   {
      sbuslock();
      setdiopin(pin, val);
      sbusunlock();
      
      printf("pin#%d set to %d\n", pin, val);
   }   
   else
   {
      printf("Usage: %s <get|set> <pin#> <set_value (0|1|2)>\n", argv[0]);
      return 1;
   }
   return 0;
}

SBUS to FPGA Protocol

For the most part, the application and kernel level programmer will not be interested in the following sections as the below information is completely abstracted away from the user by the SBUS C API and the various TS-specific utilities. Even the FPGA programmer is abstracted from the details of this protocol by the spi_sbus.v Verilog module which turns the SBUS SPI traffic into WISHBONE bus cycles.

The SBUS protocol allows for 16 specific 16 bit registers (32-bytes of register space) to be read or written and has provision for the FPGA internal WISHBONE bus cycles to take any amount of time to be ack'ed through the mechanism of SBUS retries. SPI bandwidth efficient burst register reads/writes are also possible when writing/reading continuously to the same address.

The general protocol consists of a 24-bit SPI transaction framed by the SPI CS#. Bits are clocked in on the rising edge and the first MOSI (input) bit signifies whether the bus cycle is a read or write. This is followed by the 4 address bits MSB first. The remaining 19 bits depend on whether the cycle is a read or write. For reads, the WISHBONE bus cycle is started as soon as the last address bit is clocked in.

The 24-bit SPI SBUS data format - bit 23 (WE) is first on wire:

  16-bit WISHBONE READ operation
     23|22|21|20|19|18|17|16|15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
     --|--|--|--|--|--|--|--|--|--------------------------------------------|
  SI: 0|A3|A2|A1|A0|  |  |  | B|<------------should be zero---------------->|
  SO:              |X2|X1|X0|MSB<----------returned READ data----------->LSB|
  
  16-bit WISHBONE WRITE operation:
     23|22|21|20|19|18|17|16|15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
     --|--|--|--|--|-----------------------------------------------|--|--|--|
  SI: 1|A3|A2|A1|A0|MSB<-----------WRITE data------------------>LSB|N2|N1|N0|
  SO:                                                              |Y2|Y1|Y0|
  
  * A3-A0: Address bits (sent by CPU)
  
  * X2-X0: ack bits for reads (sent by FPGA). If any are 1, the following
    data is valid.  If they are all 0, the WISHBONE cycle did not complete in 
    time and must be immediately retried.
  
  * Y2-Y0: ack bits for write (sent by FPGA). If any are 1, the write
    cycle was completed.  If all are 0, the WISHBONE write did not complete
    and must be immediately retried.
  
  * B: Burst read.  Setting this to 1 starts another WISHBONE read cycle for
    the same address.  See "SBUS Burst mode" below.
  
  * N2-N0: For burst writes, this represents bits 15-13 of the next burst 
    write data, otherwise these bits are Dont-Cares.  See "SBUS Burst mode"
    below.