Home
Applications Contact Us Purchasing Info About Us Software Downloads
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Using SpinAPI in C/C++ for PulseBlaster ProgrammingSections
LegalCopyright (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 ManualThe 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 IntroductionThis 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 ArchitectureMachine-Word DefinitionThe 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.
Figure 1: Bit definitions of the
80 bit instruction/memory word.
Breakdown of 80-bit Instruction WordThe 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 WordPlease refer to Table 2
for output pattern and control bit assignments of the
24-bit output/control word.
Table 2: Output Pattern and Control Word Bits. Data Field and Op CodePlease 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)
Table 3: Op Code and Data Field
Description.
Delay CountThe 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. TriggeringTriggering from WAITWhen 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 RESETWhen the board is in the reset state, the board takes 8 clock cycles after a hardware trigger to start running.Triggering from STOPWhen 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 SpinAPISpinAPI 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 PulseBlasterA 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.
Sample Pulse Generation InstructionsA simple program to
generate a square pulse will have two intervals as
shown below:
Back to Topstart= 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. 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 200ms // 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 5 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 150ms 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 150ms 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 .5 * 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 | Contact Us | Purchasing Info | About Us | Software Downloads
© 2024 SpinCore Technologies, Inc.