Analog I/O Demo 3 – Acquiring data on the analog to digital converter

Note

You can only use ADC/DAC with the full version of a device; the lite version does not have ADC/DAC capabilities.

This demo generates data on the DAC0 and 1, which is then read continuously on ADC 0/1 using an internal loop-back. As in Demo 1, we must set up the ADC schedule with the right terms. This time, since we are continuously buffering the values, the 4th argument is set to zero.

Datapixx('SetAdcSchedule', 0, adcRate, 0, [0 1], adcBuffBaseAddr, nAdcBuffFrames);

The first zero is the schedule start delay, the adcRate was defined before as 10000 Hz, the second zero here means this schedule will run until we stop it by hand: Datapixx('StopAdcSchedule');, [0 1] means we are looking at ADC 0/1, adcBuffBaseAddr is where the data will be in the ram and nAdcBuffFrames is how much memory is allocated to buffer data. In this case, nAdcBuffFrames is defined to be 100*adcRate, therefore it will be able to contain 100 seconds of data.

We can then read the buffer and its time tags at regular intervals using

Datapixx('ReadAdcBuffer', nReadFrames, -1);

nReadFrames is the number of data available, and can be obtained using

status = Datapixx('GetAdcStatus'); nReadFrames = status.newBufferFrames;

The -1 signifies we use the same buffer defined in the previous SetAdcSchedule call (a buffer starting at adcBuffBaseAddr).

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
function DatapixxAdcStreamDemo()
% DatapixxAdcStreamDemo()
%
% Demonstrates how to continuously acquire streaming ADC data from the DATAPixx.
% For demonstration purposes we use the DAC0/1 outputs to generate waveforms,
% which we then acquire on ADC0/1 using internal loopback between DACs and ADCs.
% We'll also plot the last 100 ms of acquired data.
%
% Also see: DatapixxAdcBasicDemo, DatapixxAdcAcquireDemo
%
% History:
%
% Oct 1, 2009  paa     Written
% Oct 29, 2014 dml     Revised 

AssertOpenGL;   % We use PTB-3

Datapixx('Open');
Datapixx('StopAllSchedules');
Datapixx('RegWrRd');    % Synchronize DATAPixx registers to local register cache

% Fill up a DAC buffer with 2 channels of 1000 samples of sin/cos functions.
% We'll generate a single period of the waveforms, and play them repeatedly.
nDacSamples = 1000;
dacData = [sin([0:nDacSamples-1]/nDacSamples*2*pi) ; cos([0:nDacSamples-1]/nDacSamples*2*pi)];
Datapixx('WriteDacBuffer', dacData);

% Play the downloaded DAC waveform buffers continuously at 100 kSPS,
% resulting in 100 Hz sin/cos waves being output onto DAC0/1.
dacRate = 1e5;
dacBuffBaseAddr = 0;
Datapixx('SetDacSchedule', 0, dacRate, 0, [0 1], dacBuffBaseAddr, nDacSamples);
Datapixx('StartDacSchedule');
Datapixx('RegWrRd');

% Start acquiring ADC data.
% This streaming demo stores collected ADC data in a 1 second circular buffer within the DATAPixx.
% This circular buffer is then uploaded to a large local matrix at regular intervals.
adcRate = 10000;                            % Acquire ADC data at 10 kSPS
nAdcLocalBuffFrames = adcRate*100;          % Preallocate a local buffer for 100 seconds of data
adcDataset = zeros(2, nAdcLocalBuffFrames); % We'll acquire 2 ADC channels into 2 matrix rows
nAdcBuffFrames = adcRate;                   % Streaming will use 1 second circular buffer in DATAPixx
adcBuffBaseAddr = 4e6;                      % DATAPixx internal buffer address
minStreamFrames = floor(adcRate / 100);     % Limit streaming reads to 100 times per second
Datapixx('SetAdcSchedule', 0, adcRate, 0, [0 1], adcBuffBaseAddr, nAdcBuffFrames);
Datapixx('EnableDacAdcLoopback');           % Replace this with DisableDacAdcLoopback to collect real data
Datapixx('DisableAdcFreeRunning');          % For microsecond-precise sample windows
Datapixx('StartAdcSchedule');
Datapixx('RegWrRd');                        % This will cause the acquisition to start

% Continuously acquire ADC data until we've filled our local buffer,
% or until a key is pressed.
fprintf('\nADC acquisition started, press any key to stop.\n');
if (exist('OCTAVE_VERSION'))
    fflush(stdout);
end
nAcquiredFrames = 0;
while (nAcquiredFrames < nAdcLocalBuffFrames)
    if (KbCheck)    % A keypress will immediately abort the acquisition
        break;
    end

    % How much data is available to read?
    Datapixx('RegWrRd');                    % Update registers for GetAdcStatus
    status = Datapixx('GetAdcStatus');
    nReadFrames = status.newBufferFrames;   % How many frames can we read?

    % It's not really necessary to limit the dataset to its preallocated size,
    % but we'll do it anyways, just for elegance.
    if (nReadFrames > nAdcLocalBuffFrames - nAcquiredFrames)
        nReadFrames = nAdcLocalBuffFrames - nAcquiredFrames;
        
    % Do not waste CPU time doing millions of tiny buffer reads    
    elseif (nReadFrames < minStreamFrames)
        continue;
    end
    
    % Upload the acquired ADC data
    adcDataset(:, nAcquiredFrames+1: nAcquiredFrames+nReadFrames) = Datapixx('ReadAdcBuffer', nReadFrames, -1);
    nAcquiredFrames = nAcquiredFrames + nReadFrames;
end

% Stop the DAC and ADC schedules, and show ADC status
Datapixx('StopAllSchedules');
Datapixx('RegWrRd');
fprintf('\nStatus information for ADC scheduler:\n');
disp(Datapixx('GetAdcStatus'));

% OK, the dog caught the car.  Now what do we do with it?
% We'll plot the last 100 milliseconds of data.
fprintf('\nAcquired %d data\nPlotting last 100ms of data\n', nAcquiredFrames);
startPlotFrame = nAcquiredFrames - floor(adcRate/10);
if (startPlotFrame < 1)
    startPlotFrame = 1;
end
plot(startPlotFrame:nAcquiredFrames, adcDataset(:,startPlotFrame:nAcquiredFrames)');

% Job done
Datapixx('Close');
fprintf('\nDemo completed\n\n');