From 88a98fda641dbee2ed0fdd1702dd0596bea460cd Mon Sep 17 00:00:00 2001 From: Travis Collins Date: Thu, 23 May 2019 15:43:49 -0400 Subject: [PATCH 1/2] Update streaming interfaces to distinguish between complex data devices and non-complex Signed-off-by: Travis Collins --- +adi/+AD9361/Base.m | 1 + +adi/+AD9371/Base.m | 1 + +adi/+AD9680/Base.m | 1 + +adi/+ADRV9009/Base.m | 1 + +adi/+common/Rx.m | 46 ++++++++++++++++++++++++++++++++----------- 5 files changed, 39 insertions(+), 11 deletions(-) diff --git a/+adi/+AD9361/Base.m b/+adi/+AD9361/Base.m index 450f417..2f890d0 100644 --- a/+adi/+AD9361/Base.m +++ b/+adi/+AD9361/Base.m @@ -51,6 +51,7 @@ dataTypeStr = 'int16'; phyDevName = 'ad9361-phy'; iioDevPHY + ComplexData = true; end diff --git a/+adi/+AD9371/Base.m b/+adi/+AD9371/Base.m index 716978f..1aa2ccb 100644 --- a/+adi/+AD9371/Base.m +++ b/+adi/+AD9371/Base.m @@ -48,6 +48,7 @@ dataTypeStr = 'int16'; phyDevName = 'ad9371-phy'; iioDevPHY + ComplexData = true; end diff --git a/+adi/+AD9680/Base.m b/+adi/+AD9680/Base.m index ad94c74..391db4f 100644 --- a/+adi/+AD9680/Base.m +++ b/+adi/+AD9680/Base.m @@ -18,6 +18,7 @@ Timeout = Inf; kernelBuffersCount = 2; dataTypeStr = 'int16'; + ComplexData = false; end properties (Abstract, Hidden, Constant) diff --git a/+adi/+ADRV9009/Base.m b/+adi/+ADRV9009/Base.m index 74a33d2..5bfb88c 100644 --- a/+adi/+ADRV9009/Base.m +++ b/+adi/+ADRV9009/Base.m @@ -48,6 +48,7 @@ dataTypeStr = 'int16'; phyDevName = 'adrv9009-phy'; iioDevPHY + ComplexData = true; end diff --git a/+adi/+common/Rx.m b/+adi/+common/Rx.m index c61a69d..5ed6bfc 100644 --- a/+adi/+common/Rx.m +++ b/+adi/+common/Rx.m @@ -3,24 +3,48 @@ properties(Constant, Hidden, Logical) EnableCyclicBuffers = false; end + + properties (Abstract, Hidden, Logical) + ComplexData + end + methods (Hidden, Access = protected) function varargout = stepImpl(obj) % Get the data - c = obj.channelCount/2; - if c > 0 - [dataRAW, valid] = getData(obj); - index = 1; - varargout = cell(c+1,1); - for k = 1:c - varargout{k} = complex(dataRAW(index,:),dataRAW(index+1,:)).'; - index = index+2; + + if obj.ComplexData + c = obj.channelCount/2; + % Complex output + if c > 0 + [dataRAW, valid] = getData(obj); + index = 1; + data = coder.nullcopy(complex(zeros(obj.SamplesPerFrame,c,'int16'))); + for k = 1:c + data(:,k) = complex(dataRAW(index,:),dataRAW(index+1,:)).'; + index = index+2; + end + varargout = cell(2,1); + varargout{1} = data; + varargout{2} = valid; + else + varargout = cell(1,1); + varargout{1} = true; end - varargout{end} = valid; else - varargout = cell(1,1); - varargout{1} = true; + c = obj.channelCount; + if c > 0 + [dataRAW, valid] = getData(obj); + varargout = cell(2,1); + varargout{1} = dataRAW.'; + varargout{2} = valid; + else + varargout = cell(1,1); + varargout{1} = true; + end end + + end end From 0623e594ad8de81482fe57fbc238644b3c3d89e3 Mon Sep 17 00:00:00 2001 From: Travis Collins Date: Thu, 23 May 2019 15:47:35 -0400 Subject: [PATCH 2/2] Add streaming interfaces for AD9467 with tests. A shared class was also added for common ADC features provided in many of the IIO drivers Signed-off-by: Travis Collins --- +adi/+AD9467/Base.m | 77 ++++++++++++++++ +adi/+AD9467/Rx.m | 210 ++++++++++++++++++++++++++++++++++++++++++++ +adi/+common/ADC.m | 49 +++++++++++ test/AD9467Tests.m | 30 +++++++ 4 files changed, 366 insertions(+) create mode 100644 +adi/+AD9467/Base.m create mode 100644 +adi/+AD9467/Rx.m create mode 100644 +adi/+common/ADC.m create mode 100644 test/AD9467Tests.m diff --git a/+adi/+AD9467/Base.m b/+adi/+AD9467/Base.m new file mode 100644 index 0000000..72a6709 --- /dev/null +++ b/+adi/+AD9467/Base.m @@ -0,0 +1,77 @@ +classdef (Abstract) Base < adi.common.Attribute & ... + matlabshared.libiio.base & ... + matlab.system.mixin.CustomIcon + %AD9467 Base Class + + properties (Nontunable) + %SamplesPerFrame Samples Per Frame + % Number of samples per frame, specified as an even positive + % integer from 2 to 16,777,216. Using values less than 3660 can + % yield poor performance. + SamplesPerFrame = 2^15; + end + + properties(Nontunable, Hidden) + Timeout = Inf; + kernelBuffersCount = 2; + dataTypeStr = 'int16'; + channelCount = 1; + ComplexData = false; + phyDevName = 'cf-ad9467-core-lpc'; + end + + properties (Abstract, Hidden, Constant) + Type + end + + methods + %% Constructor + function obj = Base(varargin) + % Returns the matlabshared.libiio.base object + coder.allowpcode('plain'); + obj = obj@matlabshared.libiio.base(varargin{:}); + end + % Check SamplesPerFrame + function set.SamplesPerFrame(obj, value) + validateattributes( value, { 'double','single' }, ... + { 'real', 'positive','scalar', 'finite', 'nonnan', 'nonempty','integer','>',0,'<',2^20+1}, ... + '', 'SamplesPerFrame'); + obj.SamplesPerFrame = value; + end + % Check channelCount + function set.channelCount(obj, value) + validateattributes( value, { 'double','single' }, ... + { 'real', 'positive','scalar', 'finite', 'nonnan', 'nonempty','integer','>=',1,'<=',1}, ... + '', 'channelCount'); + obj.channelCount = value; + end + end + + %% API Functions + methods (Hidden, Access = protected) + + function icon = getIconImpl(obj) + icon = sprintf(['AD9467 ',obj.Type]); + end + + end + + %% External Dependency Methods + methods (Hidden, Static) + + function tf = isSupportedContext(bldCfg) + tf = matlabshared.libiio.ExternalDependency.isSupportedContext(bldCfg); + end + + function updateBuildInfo(buildInfo, bldCfg) + % Call the matlabshared.libiio.method first + matlabshared.libiio.ExternalDependency.updateBuildInfo(buildInfo, bldCfg); + end + + function bName = getDescriptiveName(~) + bName = 'AD9467'; + end + + end +end + diff --git a/+adi/+AD9467/Rx.m b/+adi/+AD9467/Rx.m new file mode 100644 index 0000000..cd461ca --- /dev/null +++ b/+adi/+AD9467/Rx.m @@ -0,0 +1,210 @@ +classdef Rx < adi.AD9467.Base & adi.common.Rx & adi.common.ADC + % adi.AD9467.Rx Receive data from the AD9467 high speed ADC + % The adi.AD9467.Rx System object is a signal source that can receive + % complex data from the AD9467. + % + % rx = adi.AD9467.Rx; + % rx = adi.AD9467.Rx('uri','192.168.2.1'); + % + % AD9467 Datasheet + + properties (Dependent) + %SamplingRate Sampling Rate + % Baseband sampling rate in Hz, specified as a scalar + % in samples per second. This value read from the hardware after + % the object is setup. + SamplingRate + end + + properties + %TestMode Test Mode + % Select ADC test mode. Options are: + % 'off' + % 'midscale_short' + % 'pos_fullscale' + % 'neg_fullscale' + % 'checkerboard' + % 'pn_long' + % 'pn_short' + % 'one_zero_toggle' + TestMode = 'off'; + %FilterHighPass3dbFrequency Filter High Pass 3db Frequency + % FilterHighPass3dbFrequency + FilterHighPass3dbFrequency = 0; + %Scale Scale + % Scale received data. Possible options are: + % 0.030517 0.032043 0.033569 0.035095 0.036621 0.038146 + Scale = 0.038146; + end + + properties(Constant, Hidden) + TestModeSet = matlab.system.StringSet({ ... + 'off','midscale_short', 'pos_fullscale', 'neg_fullscale',... + 'checkerboard', 'pn_long', 'pn_short', 'one_zero_toggle'}); + end + + properties (Hidden, Nontunable, Access = protected) + isOutput = false; + end + + properties(Nontunable, Hidden, Constant) + Type = 'Rx'; + channel_names = {'voltage0'}; + end + + properties (Nontunable, Hidden) + devName = 'cf-ad9467-core-lpc'; + end + + methods + %% Constructor + function obj = Rx(varargin) + % Returns the matlabshared.libiio.base object + coder.allowpcode('plain'); + obj = obj@adi.AD9467.Base(varargin{:}); + end + % Check TestMode + function set.TestMode(obj, value) + obj.TestMode = value; + if obj.ConnectedToDevice + id = 'voltage0'; + obj.setAttributeRAW(id,'test_mode',value,false); + end + end + % Check FilterHighPass3dbFrequency + function set.FilterHighPass3dbFrequency(obj, value) + obj.FilterHighPass3dbFrequency = value; + if obj.ConnectedToDevice + id = 'voltage0'; + obj.setAttributeLongLong(id,'filter_high_pass_3db_frequency',value,false); + end + end + % Check Scale + function set.Scale(obj, value) + options = [0.030517 0.032043 0.033569 0.035095 0.036621 0.038146]; + if ~any(value==options) + error(['Scale must be one of ',num2str(options)]); + end + obj.Scale = value; + if obj.ConnectedToDevice + id = 'voltage0'; + obj.setAttributeRAW(id,'scale',num2str(value),false); + end + end + function value = get.SamplingRate(obj) + if obj.ConnectedToDevice + id = 'voltage0'; + value = obj.getAttributeLongLong(id,'sampling_frequency',false); + else + value = 0; + end + end + + end + + %% API Functions + methods (Hidden, Access = protected) + + function numOut = getNumOutputsImpl(obj) + numOut = ceil(obj.channelCount) + 1; % +1 for valid + end + + function setupInit(obj) + % Write all attributes to device once connected through set + % methods + id = 'voltage0'; + + obj.setAttributeRAW(id,'test_mode',obj.TestMode,false); + obj.setAttributeLongLong(id,'filter_high_pass_3db_frequency',... + obj.FilterHighPass3dbFrequency,false); + obj.setAttributeRAW(id,'scale',num2str(obj.Scale),false); + + obj.setAttributeLongLong(id,'calibbias',obj.CalibrationBias,... + false); + obj.setAttributeRAW(id,'calibphase',... + num2str(obj.CalibrationPhase),false); + obj.setAttributeRAW(id,'calibscale',... + num2str(obj.CalibrationScale),false); + + + end + + % Hide unused parameters when in specific modes + function flag = isInactivePropertyImpl(obj, prop) + % Call the superclass method + flag = isInactivePropertyImpl@adi.common.RxTx(obj,prop); + end + end + + methods (Access=protected) + + function varargout = getOutputNamesImpl(obj) + % Return output port names for System block + numOut = ceil(obj.channelCount) + 1; % +1 for valid + varargout = cell(1,numOut); + for k=1:numOut-1 + varargout{k} = ['chan',num2str(k)]; + end + varargout{numOut} = 'valid'; + end + + function varargout = getOutputSizeImpl(obj) + % Return size for each output port + numOut = ceil(obj.channelCount) + 1; % +1 for valid + varargout = cell(1,numOut); + for k=1:numOut-1 + varargout{k} = [obj.SamplesPerFrame,1]; + end + varargout{numOut} = [1,1]; + end + + function varargout = getOutputDataTypeImpl(obj) + % Return data type for each output port + numOut = ceil(obj.channelCount) + 1; % +1 for valid + varargout = cell(1,numOut); + for k=1:numOut-1 + varargout{k} = "int16"; + end + varargout{numOut} = "logical"; + end + + function varargout = isOutputComplexImpl(obj) + % Return true for each output port with complex data + numOut = ceil(obj.channelCount) + 1; % +1 for valid + varargout = cell(1,numOut); + for k=1:numOut-1 + varargout{k} = true; + end + varargout{numOut} = false; + end + + function varargout = isOutputFixedSizeImpl(obj) + % Return true for each output port with fixed size + numOut = ceil(obj.channelCount) + 1; % +1 for valid + varargout = cell(1,numOut); + for k=1:numOut + varargout{k} = true; + end + end + end + + + %% External Dependency Methods + methods (Hidden, Static) + + function tf = isSupportedContext(bldCfg) + tf = matlabshared.libiio.ExternalDependency.isSupportedContext(bldCfg); + end + + function updateBuildInfo(buildInfo, bldCfg) + % Call the matlabshared.libiio.method first + matlabshared.libiio.ExternalDependency.updateBuildInfo(buildInfo, bldCfg); + end + + function bName = getDescriptiveName(~) + bName = 'AD9467'; + end + + end +end + diff --git a/+adi/+common/ADC.m b/+adi/+common/ADC.m new file mode 100644 index 0000000..147ed62 --- /dev/null +++ b/+adi/+common/ADC.m @@ -0,0 +1,49 @@ +classdef (Abstract) ADC < matlab.System + % ADC: Common shared attributes across ADC designs + properties + %CalibrationBias Calibration Bias + CalibrationBias = 0; + %CalibrationPhase Calibration Phase + CalibrationPhase = 0; + %CalibrationScale Calibration Scale + CalibrationScale = 1; + end + + methods + % Check CalibrationBias + function set.CalibrationBias(obj, value) + validateattributes( value, { 'double','single' }, ... + { 'real', 'scalar', 'finite', 'nonnan', 'nonempty'}, ... + '', 'CalibrationBias'); + obj.CalibrationBias = value; + if obj.ConnectedToDevice + id = 'voltage0'; + obj.setAttributeLongLong(id,'calibbias',value,false); + end + end + % Check CalibrationPhase + function set.CalibrationPhase(obj, value) + validateattributes( value, { 'double','single' }, ... + { 'real', 'scalar', 'finite', 'nonnan', 'nonempty'}, ... + '', 'CalibrationPhase'); + obj.CalibrationPhase = value; + if obj.ConnectedToDevice + id = 'voltage0'; + obj.setAttributeRAW(id,'calibphase',num2str(value),false); + end + end + % Check CalibrationScale + function set.CalibrationScale(obj, value) + validateattributes( value, { 'double','single' }, ... + { 'real', 'scalar', 'finite', 'nonnan', 'nonempty'}, ... + '', 'CalibrationScale'); + obj.CalibrationScale = value; + if obj.ConnectedToDevice + id = 'voltage0'; + obj.setAttributeRAW(id,'calibscale',num2str(value),false); + end + end + end + +end + diff --git a/test/AD9467Tests.m b/test/AD9467Tests.m new file mode 100644 index 0000000..6e177c5 --- /dev/null +++ b/test/AD9467Tests.m @@ -0,0 +1,30 @@ +classdef AD9467Tests < HardwareTests + + properties + uri = 'ip:192.168.3.2'; + author = 'ADI'; + end + + methods(TestClassSetup) + % Check hardware connected + function CheckForHardware(testCase) + Device = @()adi.AD9467.Rx; + testCase.CheckDevice('ip',Device,testCase.uri(4:end),false); + end + end + + methods (Test) + + function testAD9467Rx(testCase) + % Test Rx DMA data output + rx = adi.AD9467.Rx('uri',testCase.uri); + [out, valid] = rx(); + rx.release(); + testCase.verifyTrue(valid); + testCase.verifyGreaterThan(sum(abs(double(out))),0); + end + + end + +end +