|
Using SpinAPI in C/C++ for
PulseBlaster Programming
Sections
- Legal
- List of
Boards Compatible with this Manual
- Introduction
- 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
- Triggering
from WAIT, RESET, and STOP states
- About
SpinAPI
- Using C
Functions to Program the PulseBlaster
- Sample
Pulse Generation Instructions
- Example 1
- 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
|