This manual acts as a reference for the M.2- / mPCIe-AIO Family's Application Programming Interface, “AIOAIO.dll”, which provides convenient, high-level functions for using the Analog Inputs and Outputs of these cards from any programming language or environment.
Three primary types of functions are provided: Board-level functions that operate on the card as a whole, such as "BRD_GetName()", ADC-specific functions, such as "ADC_GetImmediate()", and DAC-specific functions, such as "DAC_Output()"
In addition to these a fourth group of functions is provided to support very low-level operation of the device, in a manner similar to our AIOWDM.dll-provided API. These functions include register transactions, buffer/register transactions, and IRQ-handling functions.
API Overview
The AIOAIO API (application programming interface) is designed to be convenient to use. There are no required initialization steps, no device handles, no de-init code to run. Functions are provided in a variety of forms specific to each programming language, allowing the API to match the expectations of programmers, regardless of language. We've also provided various "overloaded" versions for many functions, allowing you to switch between 16-bit count values and voltage values, for example, just by changing your variable types from integers to floating-point. Or control multiple DACs simultaneously by passing an array of values instead of a single variable — in either counts or volts.
Important Terms
- Board Index
Instead of presenting you with using device files, handles, or other low-level hardware-control mechanisms AIOAIO maintains an internal list of all detected devices, exposed via the BoardIndexTBoardIndex parameter, iBoard. The first detected device will be zero (0), and additional detected cards are assigned sequential indices.
- Sequencer Index
The two onboard ADC circuits run completely independently and are referred to as "ADC Sequencer" and selected via the SequencerIndexTSequencerIndex parameter, iSequencer. Each sequencer is configured independently for speed, channels to acquire, etc.
- Range Code
Each of the ADC channels can be acquired at any of 8 bipolar ranges, and each DAC channel can be configured for any of four bipolar and four unipolar ranges. AIOAIO uses the RangeCodeTRangeCode to represent the available ranges, both as "FourCC" values, like "B±10" (0x3031E142) for the bipolar 10V range (-10 to +10V), and by register-level code specific to the chips involved.
We highly recommend using the mnemonic, hardware-independent, "FourCC" values for all development. To support this we provide constants like Range.Bipolar10TRange.Bipolar10 for your use.
However, because RangeCodeTRangeCode supports both ADC and DAC ranges, and is consistent with other hardwares' APIs, you will find more FourCC constants in our API than your ADC or DAC can use. Refer to the ADC_SetRange() and DAC_SetRange() functions for the constant available to each function.
- Channel Index
Channel Index is an alias for "Channel Number" or just "Channel", starting from zero (0) and incrementing consecutively. Each ADC Sequencer has its own Channels, starting at zero (0) and incrementing through seven (7). The DAC provides Channels zero (0) through three (3).
-
Analog Inputs (ADC)
Using the Analog Inputs can be as simple as calling ADC_GetImmediate() in a loop. You should be able to achieve tens or even hundreds of kilohertz sampling rate using this technique.
On the other hand, the card is quite powerful, capable of running two, up-to 1MHz, acquisition streams simultaneously, one per ADC. Handling this much data could be complex, but AIOAIO provides a variety of acqusition methods to satisfy all application types:
- ADC Immediate mode
As mentioned, this is a very simple way to take data, but not capable of the fastest speeds and doesn't support simultaneous acquisition from both ADC Sequencers without your application implementing relatively complex multi-threading.
- ADC Polling mode
ADC Polling requires your application to occasionally call ADC_PollData() and ADC_GetData() to collect the samples that have accumulated in the onboard FIFOs. Top speed is limited by your application's worst-case polling interval.
- ADC Callback mode
In ADC Callback mode you accept data from the card via our driver suite calling your function every once in a while. Configure the callback using ADC_SetCallback(). We offer two primary callback function signatures, one that provides the data as an array of double-precision floating point Voltages, and one that provides the low-level "counts" straight from the ADC chip. Both callbacks include an optional array of "status" information, one status per conversion datapoint.
In Polling and Callback modes you can choose how often you want data / callbacks, expressed as either "number of samples per callback" or "number of callbacks per second". AIOAIO calls these "Chunking Types", as in "what type of chunks do you want the data sent in, buffer length or duration?". Select the Chunking Type using ADC_ConfigureAcquire().
Analog Outputs (DAC)
The (optional) onboard DAC provides four voltage output channels. You can output data as either double-precision volts or 16-bit counts (two's-complement in bipolar ranges; straight binary in unipolar ranges).
To output data to a single DAC channel call DAC_Output(). By using the ciAll sentinel value you can also use DAC_Output() to write the same value to all DACs
To output data to multiple DAC channels simultaneously use the DAC_OutputAll() function.
AIOAIO Defined Types
We recommend copying these type-aliases into your source files, as C# doesn't support the concept between modules.
using TWinErrCode = UInt32;
using TBoardIndex = UInt64;
using TChannelIndex = UInt32;
Specific bit-width types
These types alias existing simple types with language-agnostic explicit-precision names. Convenient "pointer-to" types are provided for each.
TUInt8 = Byte ; TPUInt8 = ^TUInt8 ;
TUInt16 = Word ; TPUInt16 = ^TUInt16 ;
TUInt32 = LongWord ; TPUInt32 = ^TUInt32 ;
TUInt64 = Int64 ; TPUInt64 = ^TUInt64 ;
TUNative = Cardinal ; TPUNative = ^TUNative ;
TSingle = Single ; TPSingle = ^TSingle ;
TDouble = Double ; TPDouble = ^TDouble ;
TAnsiChar = AnsiChar ; TPAnsiChar = ^TAnsiChar;
TWideChar = WideChar ; TPWideChar = ^TWideChar;
Python doesn't use "types".
AIOAIO.py makes use of the enum module's IntEnum class and uses the ctypes module internally.
Enum base types
TWinErrCode = TUInt32 ; TPWinErrCode = ^TWinErrCode; // Standard Win32 error codes
TRangeCode = TUInt32 ; TPRangeCode = ^TRangeCode;
TSerialNumber = TUInt64 ; TPSerialNumber = ^TSerialNumber;
TBoardIndex = TUInt64; // iBoard: which card to control. Cards are numbered consecutively from 0
TSequencerIndex = TUInt32; // iSequencer: which ADC Sequencer to read/control
TChannelIndex = TUInt32; // Channels are numbered consecutively from 0
TIRQIndex = TUint32; // reserved, use iiOnly (0)
TChunkingType = TUInt32; // chunk data by amount or by duration
TCallbackType = TUInt32;
AIOAIO Defined Enums / Constants
ctRaw = TCallbackType($00776152); // FourCC('Raw'#0);
ctCounts = TCallbackType($6E756F43); // FourCC('Coun');
ctV = TCallbackType($746C6F56); // FourCC('Volt');
ctNone = TCallbackType($FFFFFFFF);
ctAuto = TChunkingType(0);
ctSize = TChunkingType(1);
ctRate = TChunkingType(2);
siFirst = TSequencerIndex(0);
siSecond = TSequencerIndex(1);
siBoth = TSequenceryIndex(-1);
rcNoChange = TRangeCode(-1);
rcUnipolar10 = TRangeCode($30313055); // FourCC('U010');
rcUnipolar5 = TRangeCode($35303055); // FourCC('U005');
rcBipolar10 = TRangeCode($3031E142); // FourCC('B±10');
rcBipolar5 = TRangeCode($3530E142); // FourCC('B±05');
rcBipolar2_5 = TRangeCode($BD32E142); // FourCC('B±2½');
rcCurrent420 = TRangeCode($30323449); // FourCC('I420'); mA current
rcRangeCode0 = TRangeCode(0);
rcRangeCode1 = TRangeCode(1);
rcRangeCode2 = TRangeCode(2);
rcRangeCode3 = TRangeCode(3);
rcRangeCode4 = TRangeCode(4);
ciAll = TChannelIndex(-1);
biAuto = TBoardIndex(0);
biNone = TBoardIndex(-1);
iiOnly = TIRQIndex(0);
[[[ tbd ]]]
public const TWinErrCode ERROR_SUCCESS = 0;
public const TBoardIndex biAuto = 0;
public const TBoardIndex biNone = 0xFFFFFFFF_FFFFFFFF;
public const TChannelIndex ciAll = 0xFFFF_FFFF;
public enum Range : UInt32
{
NoChange = 0xFFFFFFFF,
Unipolar10 = 0x30313055, // FourCC("U010");
Unipolar5 = 0x35303055, // FourCC("U005");
Bipolar10 = 0x3031E142, // FourCC("B±10");
Bipolar5 = 0x3530E142, // FourCC("B±05");
Bipolar2_5 = 0xBD32E142, // FourCC("B±2½");
Current420 = 0x30323449, // FourCC("I420"); // 4-20mA
Code0 = 0,
Code1 = 1,
Code2 = 2,
Code3 = 3,
Code4 = 4,
Code5 = 5,
Code6 = 6,
Code7 = 7,
}
public enum Sequencer : UInt32 { First = 0, Second = 1 }
public enum IRQIndex : UInt32 { Only = 0 }
public enum ChunkingType : UInt32 { Auto = 0, Size = 1, Rate = 1}
public enum CallbackType : UInt32 { Raw = 0, Volts = 1, Current = 2}
ERROR_SUCCESS = 0
biAuto = 0 # board index
biNone = -1 # board index
ciAll = 0xFFFF_FFFF # channel index
class Range(IntEnum):
NoChange = 0xFFFFFFFF,
Unipolar10 = 0x30313055, # FourCC("U010")
Unipolar5 = 0x35303055, # FourCC("U005")
Bipolar10 = 0x3031E142, # FourCC("B±10")
Bipolar5 = 0x3530E142, # FourCC("B±05")
Bipolar2_5 = 0xBD32E142, # FourCC("B±2½")
Current420 = 0x30323449, # FourCC("I420") # 4-20mA
Code0 = 0
Code1 = 1
Code2 = 2
Code3 = 3
Code4 = 4
Code5 = 5
Code6 = 6
Code7 = 7
class Sequencer(IntEnum):
Both = -1
First = 0
Second = 1
class IRQIndex(IntEnum):
Only = 0
class ChunkingType(IntEnum):
Auto = 0
Size = 1
Rate = 1
class CallbackType(IntEnum):
Raw = 0x00776152 # FourCC('Raw'#0)
Volts = 746C6F56 # FourCC('Volt')
Counts = 0x6E756F43 # FourCC('Coun')
None = 0xFFFFFFFF
Use these enums as "Sequencer.First" or "CallbackType.Volts"
Error/Status Return Values
Unless otherwise documented all return values are Microsoft defined “Win32” error codes (see BRD_GetHighestBoardIndex() for the exception to this rule).
A return of “ERROR_SUCCESS” (equal to 0) means no error occurred.
Unless otherwise documented all functions return a tuple containing an error/status value in the first position. This status is a Microsoft defined “Win32” error code (see BRD_GetHighestBoardIndex() for the exception to this rule).
A return of “ERROR_SUCCESS” (equal to 0) means no error occurred.
The set of error codes AIOAIO.dll can produce is the combined set called out in our AIOAIO.dll source code (provided) plus anything the OS's lower-level code decides to throw our way.
Refer to each function description for an explanation of the other values returned in the tuple.