SpinCore Logo Home
Contact Us
About Us
Applications
Purchasing Info
Software Downloads

banner_left.jpg banner_right.jpg

Using SpinAPI in C/C++ for PulseBlaster Programming

Sections

  1. Legal
  2. List of Boards Compatible with this Manual
  3. Introduction
  4. Instruction Set Architecture
    • Machine-Word Definition
    • Break-Down of 80-Bit Instruction Word
      • Output Pattern and Control Word
      • Data Field and Op Code
      • Delay Count
      • The WAIT OpCode
      • The STOP OpCode
  5. Triggering from WAIT, RESET, and STOP states
  6. About SpinAPI
  7. Using C Functions to Program the PulseBlaster
  8. Sample Pulse Generation Instructions
  9. Example 1
  10. Example 2

Legal

Copyright (c) 2009 SpinCore Technologies, Inc.

This software is provided 'as-is', without any expressed or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.

Permission is granted to anyone to use this software for any purpose, including commercial applications.

Back to Top

List of Boards Compatible with this Manual

The information provided in this manual is nearly universal to SpinCore's lines of boards.  More complex boards such as the PulseBlasterESR, PulseBlaster-DDS, and RadioProcessor lines of boards still rely on the same PulseBlaster core for TTL programming and so these basic example programs listed here will be able to produce the same results on any of them.  The exception is the PulseBlaster-DDS-II board which uses a 96-Bit instruction word instead of an 80-Bit instruction word and is currently not compatible with PulseBlaster methods of programming the board.

Back to Top

Introduction

This section provides detailed descriptions of the instruction set for the PulseBlaster board and the C functions in SpinAPI that utilize them. The information on the instruction set is very in depth and knowledge of this is not required to be able to operate the board, but details are provided so the user can understand the functionality of the PulseBlaster.  It is highly recommended that you read the instruction set information, however if you would like to get started programming the board immediately in C, start with the section About SpinAPI.

Back to Top

Instruction Set Architecture

Machine-Word Definition

The PulseBlaster pulse timing and control processor implements an 80-bit wide Very Long Instruction Word (VLIW) architecture. The VLIW memory words have specific bits/fields dedicated to specific purposes, and every word should be viewed as a single instruction of the micro-controller. The maximum number of instructions that can be loaded to on-chip memory is 512 (Model PB24-512, also called the “Internal Memory Model”); the maximum number of instructions that can be loaded to the on-board memory is 32k (Model PB24-32k, also called the “External Memory Model).  The execution time of instructions can be varied and is under (self) control by one of the fields of the instruction word – the shortest being five clock cycles for the “Internal Memory Model” and nine clock cycles for the “External Memory Model.”  All instructions have the same format and bit length, and all bit fields have to be filled.  Figure 1 shows the fields and bit definitions of the 80-bit instruction word. 

Output/Control Word
Data Field
OP Code
Delay Count
(24 Bits)
(20 Bits)
(4 Bits)
(32 Bits)

Figure 1: Bit definitions of the 80 bit instruction/memory word.

Breakdown of 80-bit Instruction Word

  The 80-bit VLIW is broken up into 4 sections as shown above.  These sections are:

  1. Output Pattern and Control Word - 24 bits
  2. Data Field - 20 bits
  3. OP Code - 4 bits
  4. Delay Count - 32 bits.

  Output Pattern and Control Word

Please refer to Table 2 for output pattern and control bit assignments of the 24-bit output/control word.


Bit #
Output Connector Label
Bit # Output Connector Label
23
Flag16..23 Out pin 15
11
Flag0..15 Out pin 5
22
Flag16..23 Out pin 13 10
Flag0..15 Out pin 18
21
Flag16..23 Out pin 11 9
Flag0..15 Out pin 19
20
Flag16..23 Out pin 9
8
Flag0..15 Out pin 7
19
Flag16..23 Out pin 7
7
Flag0..15 Out pin 8
18
Flag16..23 Out pin 5 6
Flag0..15 Out pin 21
17
Flag16..23 Out pin 3
5
Flag0..15 Out pin 22
16
Flag16..23 Out pin 1
4
Flag0..15 Out pin 10
15
Flag0..15 Out pin 2
3
Flag0..15 Out pin 11
14
Flag0..15 Out pin 15
2
Flag0..15 Out pin 24
13
Flag0..15 Out pin 16
1
Flag0..15 Out pin 25
12
Flag0..15 Out pin 4
0
Flag0..15 Out pin 13

Table 2: Output Pattern and Control Word Bits.

  Data Field and Op Code 

Please refer to Table 3 for information on the available operational codes (OpCode) and the associated data field functions (the data field's function is dependent on the OpCode)


Op Code #
Inst
Inst_data
Function
0
CONTINUE
Ignored
Program execution continues to next instruction.
1
STOP
Ignored
Stop execution of program (*Note all TTL values remain from previous instruction, and analog outputs turn. However, on DDS boards all digital TTL outputs and analog outputs turn off.)
2
LOOP
Number of desired loops. This value must be greater than or equal to 1.
Specify beginning of a loop. Execution continues to next instruction.  Data used to specify number of loops.
3
END_LOOP
Address of beginning of loop
Specify end of loop.  Execution returns to beginning of loop and decrements loops counter.
4
JSR
Address of first subroutine instruction
Program execution jumps to beginning of  a subroutine.
5
RTS
Ignored
Program execution returns to instruction after JSR was called.
6
BRANCH
Address of next instruction
Program execution continues at specified instruction.
7
LONG_DELAY
Number of desired loops. This value must be greater than or equal to 3.
For long interval instructions.  Data field specifies a multiplier of the delay field.  Execution continues to next instruction..
8
WAIT
Ignored
Program execution stops and waits for software or hardware trigger.  Execution continues to next instruction after receipt of trigger. A WAIT instruction must be preceded by an instruction lasting longer than the minimum instruction time. 

Table 3: Op Code and Data Field Description.

Delay Count

The value of the Delay Count field (a 32-bit value) determines how long the current instruction should be executed.  The allowed minimum value of this field is 0x00000002 for PB24-512 and 0x00000006 for PB24-32K and the allowed maximum is 0xFFFFFFFF.  The timing controller has a fixed delay of three clock cycles and the value that one enters into the Delay Count field should account for this inherent delay. (NOTE: the pb_inst() family of functions in SpinAPI and the PulseBlaster Interpreter automatically account for this delay.)

The WAIT OpCode

When using the WAIT opcode you do not want to call pb_stop() or pb_reset() inappropriately. Calling pb_stop() or pb_reset() will reset the entire pulse program to the beginning, therefore the next trigger you issue will start the program from the beginning instead of the next instruction you want executed.

While the board is ‘WAITING’ you must only call pb_start() to trigger the board which will then leave the wait state and continue on with the next instruction. You may also use a hardware trigger.

To clarify, the WAIT opcode is suitable if you have multiple patterns or loops you want to run sequentially.

Please see dds2_wait_test.c for an example of the WAIT instruction and software triggering.

The STOP OpCode

Using the STOP opcode will halt your pulse program. After issuing a STOP instruction you must issue pb_reset() before calling pb_start(). You may also use a hardware reset and trigger. Otherwise the board remains in a ‘STOPPED’ state and triggering will have no effect. Calling pb_reset() will reset the pulse program to the beginning and the next trigger will start the program from the beginning.

To clarify, the STOP opcode is suitable if you have one program that runs ‘all at once’ so when you want to re-trigger it the whole thing runs again from the beginning.

Triggering

Triggering from WAIT

When the board is in the wait state (after a wait instruction has been reached) the board takes a variable number of clock cycles to start running again depending on the delay counter for the instruction. If the user programs a wait statement with 5 clock cycles as the delay, the board will take 8 clock cycles to start running again. If the user programs more than that, it will take 3 more clock cycles than programmed delay to start running again. If the user programs less than a 5 clock cycle delay, then pb_inst() will return an error and the instruction will not be programmed.

Triggering from RESET

When the board is in the reset state, the board takes 8 clock cycles after a hardware trigger to start running.

Triggering from STOP

When the board is in the stopped state, the board cannot be triggered using the hardware trigger. You need to first reset the board with either pb_reset() or a hardware reset.

Back to Top

About SpinAPI

SpinAPI is a control library which allows programs to be written to communicate with the PulseBlaster board. The most straightforward way to interface with this library is with a C/C++ program, and the API definitions are described in this context. However, virtually all programming languages and software environments (including software such as LabView and Matlab) provide mechanisms for accessing the functionality of standard libraries such as SpinAPI.

Please see the example programs for an an explanation of how to use SpinAPI. A reference document for all SpinAPI functions is available online at:

http://www.spincore.com/CD/spinapi/spinapi_reference/

For a pre-configured compiler for writing and modifying pulse programs download Dev-C++ with MinGW from our website here.

With this compiler, making changes to a sample program and recreating the executable file is as easy as clicking "Rebuild All" as shown in figure 4 below:



Figure 4

Back to Top

Using C Functions to Program the PulseBlaster

A series of functions have been written to control the board and facilitate the construction of pulse program instructions.

In order to use these functions, the DLL (spinapi.dll), the library file (libspinapi.a for mingw, spinapi.lib for msvc), the header file (spinapi.h), must be in the working directory of your C compiler.

int pb_init();

Initializes PulseBlaster board.  Needs to be called before calling any functions using the PulseBlaster.  Returns a negative number on an error or 0 on success.

int pb_close();

Releases PulseBlaster board.  Needs to be called as last command in pulse program.  Returns a negative number on an error or 0 on success.

void pb_core_clock(double clock_freq);

Used to inform SpinAPI of the clock frequency of the board.  The variable clock_frequency is specified in MHz when no units are entered.  Valid units are MHz, kHz, and Hz.  The default clock value is 50MHz.  You only need to call this function if you are not using a –50 board.

int pb_start_programming(int device);

Used to initialize the system to receive programming information.  It accepts a parameter referencing the target for the instructions.  The only valid value for device is PULSE_PROGRAM, It returns a 0 on success or a negative number on an error.

int pb_inst(int flags, int inst, int inst_data, double length);

Used to send one instruction of the pulse program.  Should only be called after start_programming(PULSE_PROGRAM) has been called.  It returns a negative number on an error, or the instruction number upon success.  If the function returns –99, an invalid parameter was passed to the function.  Instructions are numbered starting at 0.

int flags – determines state of each TTL output bit.  Valid values are 0x0 to 0xFFFFFF. For example, 0x010 would correspond to bit 7 being on, and all other bits being off.

int inst – determines which type of instruction is to be executed. Please see Table 2 for details.

int inst_data – data to be used with the previous inst field.  Please see Table 2 for details.

int length – duration of this pulse program instruction, specified in ns.

int pb_stop_programming();

Used to tell that programming the board is complete.  Board execution cannot start until this command is received.  It returns a 0 on success or a negative number on an error.

int pb_start();

Once board has been programmed, this instruction will start execution of pulse program.  It returns a 0 on success or a negative number on an error.

int pb_stop();

Stops output of board.  Analog output will return to ground, and TTL outputs will remain in the state they were in when stop command was received.  It returns a 0 on success or a negative number on an error.

int pb_read_status();

Read status from the board. Each bit of the returned integer indicates whether the board is in that state. Bit 0 is the least significant bit.

Bit 0 – Stopped
Bit 1 - Reset (this bit will always be '1' unless the board is being reset)
Bit 2 – Running
Bit 3 – Waiting
Bit 4 - Scanning (RadioProcessor boards only)

Bits 5-31 are reserved for future use. It should not be assumed that these will be set to 0.

char* pb_get_version();

Returns the version of SpinAPI in the form YYYYMMDD, i.e. 20090209.  This function should be used to make sure you are using an up to date version of SpinAPI.

int pb_select_board(int board_num);

If multiple boards from SpinCore Technologies are present in your system, this function allows you to select which board to communicate with. Once this function is called, all subsequent commands (such as pb_init(), pb_set_clock(), etc.) will be sent to the selected board. You may change which board is selected at any time. If you have only one board, it is not necessary to call this function.  All PCI slot boards are numbered before any USB boards, starting with the number 0.  This function returns a 0 upon success, and a negative number upon failure.
 
Back to Top

Sample Pulse Generation Instructions

A simple program to generate a square pulse will have two intervals as shown below:

start= pb_inst(0xFFFFFF, CONTINUE, 0, 200.0*ms); 
pb_inst(0x000000, BRANCH, start, 200.0*ms);

The first line of the code above corresponds to the logical "one” on all output bits.  The second line
corresponds to the logical "zero," after which the program branches (jumps) back to the beginning, thus
resulting in a continuous generation of a square wave on all outputs.

A complete C program will have, in addition to the two lines above, the initialization section, the
closing section, and, optionally, the (software) trigger to start the execution immediately upon launch
of the program.  For more detailed information on programming the board consult the section above for all SpinAPI C functions or the examples below for complete usable programs.

Back to Top

Example 1

/*
 * PulseBlaster example 1
 * This program will cause the outputs to turn on and off with a period
 * of 400ms
 */

#include <stdio.h>
#define PB24
#include "spinapi.h"

int main(){

    int start, status;
   
    printf ("Using spinapi library version %s\n", pb_get_version());
       
    if(pb_init() != 0) {
               printf ("Error initializing board: %s\n", pb_get_error());   
            return -1;
        }

      // Tell the driver what clock frequency the board has (in MHz)
        pb_core_clock(100.0);

        pb_start_programming(PULSE_PROGRAM);
   
    // Instruction 0 - Continue to instruction 1 in 100ms
    // Flags = 0xFFFFFF, OPCODE = CONTINUE
    start = pb_inst(0xFFFFFF, CONTINUE, 0, 200.0*ms);

        // Instruction 1 - Continue to instruction 2 in 100ms
        // Flags = 0x0, OPCODE = CONTINUE
        pb_inst(0x0, CONTINUE, 0, 100.0*ms);

        // Instruction 2 - Branch to "start" (Instruction 0) in 100ms
        // 0x0, OPCODE = BRANCH, Target = start
        pb_inst(0x0, BRANCH, start, 100.0*ms);

    pb_stop_programming();

        // Trigger the pulse program
    pb_start();

    //Read the status register
    status = pb_read_status();
    printf("status: %d", status);

    pb_close();

    return 0;
}

Back to Top

Example 2

  //*
 * PulseBlaster example 2
 * This example makes use of all instructions (except WAIT).
 */
#include <stdio.h>
#define PB24
#include <spinapi.h>

int main(int argc, char **argv){
    int start, loop, sub;
    int status;

        printf ("Using spinapi library version %s\n", pb_get_version());
        if(pb_init() != 0) {
          printf ("Error initializing board: %s\n", pb_get_error());   
            return -1;
        }

      // Tell the driver what clock frequency the board has (in MHz)
        pb_core_clock(100.0);

        pb_start_programming(PULSE_PROGRAM);

        // Since we are going to jump forward in our program, we need to
      // define this variable by hand.  Instructions start at 0 and count up
    sub = 5;

        // Instruction format
        // int pb_inst(int flags, int inst, int inst_data, int length)

        // Instruction 0 - Jump to Subroutine at Instruction 4 in 1s
        start =    pb_inst(0xFFFFFF,JSR, sub, 1000.0 * ms);

        // Loop. Instructions 1 and 2 will be repeated 3 times
        // Instruction 1 - Beginning of Loop (Loop 3 times).  Continue to next     // instruction in 1s
        loop =    pb_inst(0x0,LOOP,3,150.0 * ms);
   
    // Instruction 2 - End of Loop.  Return to beginning of loop or    
    // continue to next instruction in .5 s
        pb_inst(0xFFFFFF,END_LOOP,loop,150.0 * ms);

        // Instruction 3 - Stay here for (5*100ms) then continue to Instruction
    // 4
        pb_inst(0x0,LONG_DELAY,5, 100.0 * ms);

        // Instruction 4 - Branch to "start" (Instruction 0) in 1 s
        pb_inst(0x0,BRANCH,start,1000.0*ms);

    // Subroutine
        // Instruction 5 - Continue to next instruction in 1 * s
        pb_inst(0x0,CONTINUE,0,500.0*ms);
   
    // Instruction 6 - Return from Subroutine to Instruction 1 in .5*s
        pb_inst(0xF0F0F0,RTS,0,500.0*ms);

        // End of pulse program
        pb_stop_programming();

        // Trigger the pulse program
    pb_start();

        //Read the status register
        status = pb_read_status();
        printf("status = %d", status);

        pb_close();
       
    return 0;
}

Back to Top



Home | Products | Applications | Purchasing Info | Company Info | Contact Us | Software Downloads

© 2009 SpinCore Technologies, Inc.