Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adi:Generic: Add a generic driver #13

Merged
merged 2 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
266 changes: 266 additions & 0 deletions +adi/+Generic/Rx.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
classdef Rx < adi.common.Rx & matlabshared.libiio.base & ...
adi.common.Attribute & adi.common.DeviceAttribute & adi.common.Channel
% Generic Precision ADC Class
% adi.Generic.Rx Receives data from the connected ADC
% The adi.Generic.Rx System object is a signal source that can receive
% data from any generic ADI precision ADC.
%
% rx = adi.Generic.Rx('adxxxx', 'ip:analog.local');

properties
ribdp marked this conversation as resolved.
Show resolved Hide resolved
% DeviceAttributeNames Device Attribute Names
% Array of device IIO attribute names as defined in the
% driver/firmware, and queried from the hardware
% at initialization time
DeviceAttributeNames

% ChannelAttributeNames Channel Attribute Names
% Array of channel IIO attribute names as defined in the
% driver/firmware, and queried from the hardware
% at initialization time
ChannelAttributeNames
end

properties (Nontunable)
mphalke marked this conversation as resolved.
Show resolved Hide resolved
% SamplesPerFrame Samples Per Frame
% Number of samples per frame, specified as an even positive
% integer.
SamplesPerFrame = 1024
end

properties (Nontunable, Hidden)
ribdp marked this conversation as resolved.
Show resolved Hide resolved
% channel_names Channel Names
channel_names = {'voltage0'}

% Timeout Timeout for the IIO client
Timeout = Inf

% kernelBuffersCount Kernel Buffers Count
% For Tinyiiod firmware, set the value to 1.
% For Linux platforms, value can be greater than 1 aa well
kernelBuffersCount = 1

% dataTypeStr Data Type String
% Data type to store the samples
dataTypeStr = 'int32'

% phyDevName Physical Device Name
% Set this to match the IIO device name
phyDevName = 'adxxxx'

% devName Device Name
% Set this to match the IIO device name
devName = 'adxxxx'
end

properties (Nontunable, Hidden, Constant)
Type = 'Rx'
ComplexData = false
end

properties (Hidden, Nontunable, Access = protected)
isOutput = false
end

properties(Hidden, Access = protected)
% cachedAttrWrites Cached Attribute Writes
% Stores the attr write values locally until hardware is
% connected.
cachedAttrWrites = {}
end

methods

%% Constructor
function obj = Rx(Args)
arguments
Args.devName
Args.phyDevName
Args.uri
end

obj = [email protected]();
obj.enableExplicitPolling = false;
obj.EnabledChannels = 1;
obj.BufferTypeConversionEnable = true;
mphalke marked this conversation as resolved.
Show resolved Hide resolved

% Set device name, phyDevName, uri from input arguments
try
obj.devName = Args.devName;
obj.phyDevName = Args.phyDevName;
obj.uri = Args.uri;
catch
e = MException('MATLAB:notEnoughInputs',['Not enough input ' ...
'arguments. Specify devName, phyDevName and uri']);
throw(e)
end

% Determine datatype using trial and error
possibleDataTypeStr = {'int8', 'int16', 'int32', 'int64'};
for k = 1:length(possibleDataTypeStr)
try
obj.dataTypeStr = possibleDataTypeStr{k};
obj.setup();
break;
catch
end
end
assert(obj.ConnectedToDevice == 1, "Connection could not be established with the specified device")

% Check is the platform is running ADI Kuiper Linux.
% Presence of 'local,kernel' context attribute would
% indicate usage of Linux platform
isLinuxPLatform = false;
try
obj.iio_context_get_attr_value(obj.iioCtx, 'local,kernel');
isLinuxPLatform = true;
catch
end

release(obj);

% If platform is running ADI Kuiper Linux, kernelBuffersCount
% can be increased
if isLinuxPLatform
obj.kernelBuffersCount = 4;
mphalke marked this conversation as resolved.
Show resolved Hide resolved
disp("Detected ADI Kuiper Linux platform. Changing buffer count to 4..")
end

end

function flush(obj)
% Flush the buffer contents
flushBuffers(obj);
end

function SetDeviceAttrValue(obj, attr, val)
% Apply the device attribute value when device is
% connected
% rx.SetDeviceAttrValue('sampling_frequency', '1000000')
obj.cachedAttrWrites{end+1} = {attr, val};
end


function val = GetDeviceAttrValue(obj, attr)
% Fetch the device attribute value if device is
% connected.
% rx.GetDeviceAttrValue('sampling_frequency')
if obj.ConnectedToDevice
val = obj.getDeviceAttributeRAW(attr, 128);
end
end

function SetChannelAttrValue(obj, chnID, attr, val)
% Apply the channel attribute value when device is
% connected. To write to the first channel attribute use
% rx.SetChannelAttrValue('voltage0', 'scale', '2') or
% rx.SetChannelAttrValue(1, 'scale', '2')
if isnumeric(chnID)
chnID = obj.channel_names(chanID);
end
obj.cachedAttrWrites{end+1} = {chnID, attr, val};
end

function val = GetChannelAttrValue(obj, chnID, attr)
% Fetch the channel attribute value if device is
% connected. To get the first channel attribute value, use
% rx.GetChannelAttrValue('voltage0', 'scale') or
% rx.GetChannelAttrValue(1, 'scale')
if obj.ConnectedToDevice
if isnumeric(chnID)
chnID = obj.channel_names(chanID);
end
val = obj.getAttributeRAW(attr, chnID, obj.isOutput);
end
end

end

%% API Functions
methods (Hidden, Access = protected)

function setupInit(obj)

% Write all attributes to device once connected through set
ribdp marked this conversation as resolved.
Show resolved Hide resolved
% methods
% Do writes directly to hardware without using set methods.
% This is required since Simulink support doesn't support
% modification to nontunable variables at SetupImpl

%Fetch all the attributes and channel names
if ~isempty(obj.channel_names)
obj.fetch_channel_names();
end

if isempty(obj.DeviceAttributeNames)
obj.fetch_device_attributes();
end

if isempty(obj.ChannelAttributeNames)
obj.fetch_channel_attributes();
end

% Apply attribute settings in hardware
if ~isempty(obj.cachedAttrWrites)
for i = 1:length(obj.cachedAttrWrites)
if length(obj.cachedAttrWrites{i}) == 2
% Apply device attribute
attr = obj.cachedAttrWrites{i}{1};
val = obj.cachedAttrWrites{i}{2};
obj.setDeviceAttributeRAW(attr, val);
elseif length(obj.cachedAttrWrites{i}) == 3
% Apply channel attribute
chan = obj.cachedAttrWrites{i}{1};
attr = obj.cachedAttrWrites{i}{2};
val = obj.cachedAttrWrites{i}{3};
obj.setAttributeRAW(chan, attr, val, obj.isOutput);
end
end
end

obj.cachedAttrWrites = {};

end

function fetch_channel_names(obj)
% Update the channel names
obj.channel_names = {};
phydev = getDev(obj, obj.devName);
chanCount = obj.iio_device_get_channels_count(phydev);
for c = 1:chanCount
chanPtr = obj.iio_device_get_channel(phydev, c - 1);
obj.channel_names{end + 1} = obj.iio_channel_get_name(chanPtr);
end
end

function fetch_device_attributes(obj)
% Store the attribute names
devPtr = obj.getDev(obj.phyDevName);
devAttrCnt = obj.iio_device_get_attrs_count(devPtr);
for i=1:devAttrCnt
obj.DeviceAttributeNames{end+1} = obj.iio_device_get_attr(devPtr, i-1);
end
end

function fetch_channel_attributes(obj)
% Store channel attribute names, if there's channels present
devPtr = obj.getDev(obj.phyDevName);

if ~isempty(obj.channel_names)
% Fetch first channel
chanPtr = calllib(obj.libName, 'iio_device_get_channel', devPtr, 0);

% Fetch count of channel attributes
chanAttrCnt = obj.iio_channel_get_attrs_count(chanPtr);

% Fetch each attribute for the channel
for j=1:chanAttrCnt
obj.ChannelAttributeNames{j} = obj.iio_channel_get_attr(chanPtr, j-1);
end
end

end


end
end
37 changes: 37 additions & 0 deletions examples/Generic_DataCapture.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
%% Script for capturing buffers of data from a connected IIO device

% Instantiate the Generic Rx system object, and specify the device name, uri
% and phyDevName in the manner shown below
rx = adi.Generic.Rx("devName", 'ad4630-24', 'phyDevName', 'ad4630-24',...
'uri', 'ip:analog.local');

% Specify number of samples to fetch using buffered capture
rx.SamplesPerFrame = 4096;

% Enable channels for data capture
rx.EnabledChannels = [1];

% Uncomment to display device and channel attribute names
%rx.DeviceAttributeNames
%rx.ChannelAttributeNames

% Read and write attribute values
% For example, with ad4630-24
% rx.GetDeviceAttrValue('sampling_frequency')
% rx.SetDeviceAttrValue('sampling_frequency', '2000000');
% rx.SetChannelAttrValue('differential0', 'hardwaregain', '2');

% Capture data
data = rx();

% Plot samples
enabledChannels = size(data, 2);
figure(1);
for i = 1:enabledChannels
subplot(enabledChannels, 1, i);
plot(data(1:rx.SamplesPerFrame, i));
mphalke marked this conversation as resolved.
Show resolved Hide resolved
title("Channel " + num2str(rx.EnabledChannels(i)));
end

% Delete the system object
release(rx);
Loading