Code covered by the BSD License  

Highlights from
PicoScope® 3000 Series - MATLAB® Generic Instrument Driver

image thumbnail

PicoScope® 3000 Series - MATLAB® Generic Instrument Driver

by

 

07 Nov 2012 (Updated )

MATLAB Instrument Driver for use with PicoScope 3000A/B oscilloscopes

PS3000a_IC_Generic_Driver_1buffer_RapidBlock.m
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Filename:    PS3000A_IC_Generic_Driver_1buffer_RapidBlock
%
% Copyright:   Pico Technology Limited 2012 - 2014
%
% Author:      HSM
%
% Description:
%   This is a MATLAB script that demonstrates how to use the
%   PicoScope 3000a series Instrument Control Toobox driver to collect a 
%   rapid block of samples immediately with 1 data buffer on 1 channel.
%
%	To run this application:
%		Ensure that the following files are located either in the same 
%       directory or define the path:
%       
%       - ps3000a.mdd
%       - PS3000a.dll & ps3000aWrap.dll 
%       - PS3000aMFile & ps3000aWrapMFile
%       - PicoStatus.m
%       - ps3000aChangePowerSource.m  
%       - adc2mv.m & mv2adc.m (located in the Functions directory)
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Clear MATLAB Env

clc;
clear;

%% Set Path

% Edit as required
%addpath('C:\Pico SDK\PS3000asdk_r10_5_0_32');
addpath('..\');
addpath('..\Functions');

%% Load in PicoStatus values

PicoStatus;

%% Declare variables

global data;

data.BUFFER_SIZE = 1024;

data.timebase = 64;         % ~1 MS/s (320XA/B)
%data.timebase = 127        % 1 MS/s (340XA/B)
data.oversample = 1;

data.scaleVoltages = PicoConstants.TRUE;

plotData = PicoConstants.TRUE;

%% Device Connection

% Create device
ps3000a_obj = icdevice('PS3000a_IC_drv', ''); % Specify serial number as 2nd argument if required.

% Connect device
connect(ps3000a_obj);

% Provide access to enumerations and structures
[methodinfo, structs, enuminfo, ThunkLibName] = PS3000aMFile;

%% Show unit information

info_status = invoke(ps3000a_obj, 'GetUnitInfo')

%% Obtain Maximum & Minimum values 

max_val_status = invoke(ps3000a_obj, 'ps3000aMaximumValue')

disp('Max ADC value:');
ps3000a_obj.maxValue

min_val_status= invoke(ps3000a_obj, 'ps3000aMinimumValue')

disp('Min ADC value:');
ps3000a_obj.minValue

%% Channel settings

channelA        = enuminfo.enPS3000AChannel.PS3000A_CHANNEL_A;
channelA_range  = enuminfo.enPS3000ARange.PS3000A_1V;

channelB        = enuminfo.enPS3000AChannel.PS3000A_CHANNEL_B;
channelB_range  = enuminfo.enPS3000ARange.PS3000A_1V;

analogueOffset  = 0;

% Channel settings - create a struct

% Channel A
channelSettings(1).enabled      = PicoConstants.TRUE;
channelSettings(1).DCCoupled    = PicoConstants.TRUE;
channelSettings(1).range        = channelA_range;

% Channel B
channelSettings(2).enabled      = PicoConstants.FALSE;
channelSettings(2).DCCoupled    = PicoConstants.TRUE;
channelSettings(2).range        = channelB_range;

if(ps3000a_obj.channelCount == 4)

    channelC        = enuminfo.enPS3000AChannel.PS3000A_CHANNEL_C;
    channelC_range  = enuminfo.enPS3000ARange.PS3000A_1V;
    
    channelD        = enuminfo.enPS3000AChannel.PS3000A_CHANNEL_D;
    channelD_range  = enuminfo.enPS3000ARange.PS3000A_1V;
    
    % Channel C
    channelSettings(3).enabled      = PicoConstants.FALSE;
    channelSettings(3).DCCoupled    = PicoConstants.TRUE;
    channelSettings(3).range        = channelC_range;

    % Channel D
    channelSettings(4).enabled      = PicoConstants.FALSE;
    channelSettings(4).DCCoupled    = PicoConstants.TRUE;
    channelSettings(4).range        = channelD_range;

end

set_ch_a_status = invoke(ps3000a_obj, 'ps3000aSetChannel', channelA, ...
    channelSettings(1).enabled, channelSettings(1).DCCoupled, ...
    channelSettings(1).range, analogueOffset);

set_ch_b_status = invoke(ps3000a_obj, 'ps3000aSetChannel', channelB, ...
    channelSettings(2).enabled, channelSettings(2).DCCoupled, ...
    channelSettings(2).range, analogueOffset);

%% Set Simple Trigger

enable = PicoConstants.TRUE;
source = enuminfo.enPS3000AChannel.PS3000A_CHANNEL_A;
threshold = mv2adc(500, PicoConstants.SCOPE_INPUT_RANGES(channelA_range + 1), ps3000a_obj.maxValue);
direction = enuminfo.enPS3000AThresholdDirection.PS3000A_RISING;
delay = 0;              
autoTrigger_ms = 10000; % 10 seconds

trigger_status = invoke(ps3000a_obj, 'ps3000aSetSimpleTrigger', ...
    enable, source, threshold, direction, delay, autoTrigger_ms)

%% Get Timebase

timeIndisposed = 0;
maxSamples = data.BUFFER_SIZE;
timeIntNs = 0;
segmentIndex = 0;

[get_timebase_status, timeIntNs1, maxSamples1] = invoke(ps3000a_obj, 'ps3000aGetTimebase', ...
        data.timebase, data.BUFFER_SIZE, ...
        timeIntNs, data.oversample, maxSamples, segmentIndex);

%% Setup Number of Captures and Memory Segments

nCaptures = 10;

% Segment the memory
[mem_segments_status, maxSamples] = invoke(ps3000a_obj, 'ps3000aMemorySegments', ...
    nCaptures);

% Set the number of captures
num_captures_status = invoke(ps3000a_obj, 'ps3000aSetNoOfCaptures', nCaptures);

%% Run Block

preTriggerSamples = 0;
postTriggerSamples = data.BUFFER_SIZE - preTriggerSamples;
segmentIndex = 0;

% Prompt to press a key to begin capture
input_str = input('Press ENTER to begin data collection.', 's');

% Run block and retry if power source not set correctly
retry = 1;

while retry == 1
    
    [run_block_status, timeIndisposedMs] = invoke(ps3000a_obj, 'ps3000aRunBlock', ...
        preTriggerSamples, postTriggerSamples, data.timebase, ...
        data.oversample, segmentIndex)

    % Check power status
    if run_block_status ~= PicoStatus.PICO_OK

        if (run_block_status == PicoStatus.PICO_POWER_SUPPLY_CONNECTED || ...
                run_block_status == PicoStatus.PICO_POWER_SUPPLY_NOT_CONNECTED || ...
                run_block_status == PicoStatus.PICO_POWER_SUPPLY_UNDERVOLTAGE)

            %change_power_src_status = invoke(ps3000a_obj, 'ChangePowerSource', run_block_status)
            change_power_src_status = ps3000aChangePowerSource(ps3000a_obj, run_block_status)

        else

            % Display error code in Hexadecimal
            fprintf('ps3000aRunBlock status: 0x%X', run_block_status);

        end

    else

        retry = 0;

    end
    
end

% Confirm if device is ready
[status, ready] = invoke(ps3000a_obj, 'ps3000aIsReady')

while ready == 0
   
    [status, ready] = invoke(ps3000a_obj, 'ps3000aIsReady');
    pause(1);
end

fprintf('Ready: %d\n', ready);
disp('Capture complete.');

%% Stop the device

stop_status = invoke(ps3000a_obj, 'ps3000aStop');

%% Get Number of Captures

[num_captures_status, nCompleteCaptures] = invoke(ps3000a_obj, 'ps3000aGetNoOfCaptures');

% Only show blocks that were captured

nCaptures = nCompleteCaptures;

%% Set Data Buffers

channelA_range      = enuminfo.enPS3000AChannel.PS3000A_CHANNEL_A;
buffer_length       = preTriggerSamples + postTriggerSamples;
buffer_ratio_mode   = enuminfo.enPS3000ARatioMode.PS3000A_RATIO_MODE_NONE;
channel_count       = ps3000a_obj.channelCount;

% 2-D matrix of lib pointers corresponding to channels x segments
pBuffer(channel_count, nCaptures) = libpointer;

% Obtain data values for each capture, setting the data buffer in turn.
for segment = 1 : nCaptures
    
    for ch = 1:channel_count
    
        if(channelSettings(ch).enabled == PicoConstants.TRUE)
    
            p_buffer(ch, segment) = libpointer('int16Ptr', zeros(buffer_length, 1));
    
            status_set_db = invoke(ps3000a_obj, 'ps3000aSetDataBuffer', ... 
                                (ch - 1), p_buffer(ch, segment), ...
                                buffer_length, (segment - 1), buffer_ratio_mode);
            
            if(status_set_db ~= PicoStatus.PICO_OK)

                error('Error: Set Data Buffer for Channel %d Segment % error code %d', ...
                    (ch - 1), (segment - 1), status_set_db);

            end
                            
        end
    
    end
end

%% Retrieve Values and Convert to milliVolts

fromSegmentIndex    = 0;
toSegmentIndex      = nCaptures - 1;
downSampleRatio     = 1;
downSampleRatioMode = enuminfo.enPS3000ARatioMode.PS3000A_RATIO_MODE_NONE;
overflow            = zeros(nCaptures, 1);

% Get Values through one function call

[get_values_bulk_status, numSamples, overflow] = invoke(ps3000a_obj, ...
    'ps3000aGetValuesBulk', buffer_length, fromSegmentIndex, toSegmentIndex, ...
    downSampleRatio, downSampleRatioMode, overflow)
    
if(get_values_bulk_status ~= PicoStatus.PICO_OK)

    % Check if Power Status issue
    if(get_values_bulk_status == PicoStatus.PICO_POWER_SUPPLY_CONNECTED || ...
        get_values_bulk_status == PicoStatus.PICO_POWER_SUPPLY_NOT_CONNECTED || ...
            get_values_bulk_status == PicoStatus.PICO_POWER_SUPPLY_UNDERVOLTAGE)

        if(get_values_bulk_status == PicoStatus.PICO_POWER_SUPPLY_UNDERVOLTAGE)

            pwr_status = ps3000aChangePowerSource(ps3000a_obj, get_values_bulk_status)

        else

            fprintf('Power Source Changed. Data collection aborted.\n');
            plotData = PicoConstants.FALSE;

        end

    else

        fprintf('ps3000aGetValues status: 0x%X', get_values_bulk_status);
        plotData = PicoConstants.FALSE;

    end

else

    % Null matrices for channels
    
    channelAValues = [];
    channelBValues = [];
    
    if(ps3000a_obj.channelCount == 4)
        
        channelCValues = [];
        channelDValues = [];
        
    end
    
    % Retrieve data values for enabled channels
    for ch = 1:channel_count

        if(channelSettings(ch).enabled == PicoConstants.TRUE)

            scope_input_index = channelSettings(ch).range + 1;
            voltage_range = PicoConstants.SCOPE_INPUT_RANGES(scope_input_index);

            % Obtain a cell array representing the waveforms for 
            % the channel

            buffer_cell = get(p_buffer(ch, :), 'Value');

            % Combine the cell contents into a total_samples x
            % numCaptures array

            buffer_matrix = [];

            if(nCaptures > 1)

                buffer_matrix = horzcat(buffer_cell{1:end});

            else

                buffer_matrix = buffer_cell;

            end

            buffer_values = adc2mv(buffer_matrix, voltage_range, ps3000a_obj.maxValue);

            switch(ch - 1)

                case enuminfo.enPS3000AChannel.PS3000A_CHANNEL_A

                    channelAValues = buffer_values;

                case enuminfo.enPS3000AChannel.PS3000A_CHANNEL_B

                    channelBValues = buffer_values;

                case enuminfo.enPS3000AChannel.PS3000A_CHANNEL_C

                    channelCValues = buffer_values;

                case enuminfo.enPS3000AChannel.PS3000A_CHANNEL_D

                    channelDValues = buffer_values;

                otherwise

            end
            
        end
            
    end

end


%% Plot data
% This plots the 10 waveforms on a 5 x 2 grid - if nCaptures is set to 
% another value this may require adjustment such as separating graphs onto
% other figures.
disp('Plotting data...')
figure;

% Time axis
t_ns = double(timeIntNs1) * double([0: downSampleRatio : numSamples - 1]);
t = t_ns / 1000000;

% Number of columns in plot
numColumns = 2;

% Calculate number of rows for the grid
if(mod(nCaptures, numColumns) == 0)
    
    numRows = double(nCaptures / numColumns);
    
else 
    
    numRows = double((nCaptures + 1) / numColumns);
    
end

for i = 1 : nCaptures
        
    plot_a_axes = subplot(numRows, numColumns, double(i)); 
    
    plot(t, channelAValues(:, i));
    title(strcat(['Channel A - Waveform ', num2str(i)]));
    xlabel('Time (ms)');
    ylabel(plot_a_axes, 'Voltage (mV)');
 
    % plot_b_axes = subplot(2,1,2); 
    % plot(t, buffer_b_mv(:, i));
    % title('Channel B');
    % xlabel('Time (ms)');
    % ylabel(plot_b_axes, 'Voltage (mV)');

end

%% Disconnect device

disconnect(ps3000a_obj);

Contact us