- Modify the class to specify ConstructOnLoad=true as described here - perhaps this is enough
- Use parallel.pool.Constant to construct ADXL372 instances directly on the worker
Using public class methods and libraries in parfeval()
20 views (last 30 days)
Show older comments
Hello everyone,
I've been googling the entire day, but nobody seems to have quite the same problem as myself at the moment.
I've programmed a matlab-class to communicate to a USB-SPI Interface Chip via the provided drivers. No Problem here. I can execute everything and read and write Data properly and quickly.
My Problem starts, as soon as I start to put this Code into a parallel pool. Since it's some very active Code (i.e. polling of IO-Pins and such) I need it to run separately from everything else.
My Code:
Firstly, I open the (properly working outside of a parallel pool) Class:
% Open ACCELEROMETER Class
ACC = ADXL372;
% Configure both Channels, as per documentation
[P1,C1]=ACC.ADXL_Config(1);
[P2,C2]=ACC.ADXL_Config(2);
My constructor looks as follows:
function ADXL = ADXL372()
if ~libisloaded( ADXL.Libname )
loadlibrary( ADXL.Libname, 'libMPSSE_spi_matlabFriendly.h');
end
if ~libisloaded( ADXL.Libname2 )
loadlibrary( ADXL.Libname2);
end
clc
% Get the number of SPI channels available.
calllib(ADXL.Libname,'SPI_GetNumChannels',ADXL.pNumchannels);
disp(['Channels Found: ', num2str(get(ADXL.pNumchannels,'value'))]);
% Connect to SPI channel 0. Valid numbers are 0:(Numchannels-1).
E = calllib(ADXL.Libname,'SPI_OpenChannel',0,ADXL.pChannelHandle);
disp(['Channel Opened with Errorcode: ', num2str(E)]);
% Set GPIO for Receiving Interrupt
E=calllib(ADXL.Libname,'FT_WriteGPIO',ADXL.pChannelHandle,0,0);
disp(['GPIO Set with Errorcode: ',num2str(E)]);
% Set Latency Timer to 1ms
E=calllib(ADXL.Libname2,'FT_SetLatencyTimer',ADXL.pChannelHandle,1);
disp(['LatencyTimer Set with Errorcode: ',num2str(E)]);
% Define the channel configuration struct, and initialize the channel.
ChConfig.ClockRate = uint32(10e6); % Clock speed, Hz
ChConfig.LatencyTimer = uint32(1); % Users guide section 3.4, suggested value is 2-255 for all devices
ChConfig.configOptions = uint32(0b100000); % Bit 1 is CPOL, bit 0 is CPHA. Higher order bits configure the chip select.
ChConfig.Pin = uint32(0x00000000);
E = calllib(ADXL.Libname,'SPI_InitChannel',ADXL.pChannelHandle,ChConfig);
disp(['SPI configured with Errorcode: ',num2str(E)]);
end
I've found solutions to make my main file know, that the function exists. Now at least I'm not getting the "Unknown Function ..." Error.
F = parfeval(gcp(),@(varargin) ACC.ReadFIFO(varargin{:}),4,Dauer,10);
with ReadFIFO being:
function [MessungA,MessungB,TVectorA,TVectorB] = ReadFIFO(ADXL,Time,Means)
% Some code that's irrelevant to this question
end
The Problem:
I need to run ReadFIFO in a separate pool for the rest of my program to work properly. First I got errors, that the function was unkown. Now I'm getting Errors that say "Library was not found", as if the pool doesn't receive the loaded libraries.
I can provide more code, but it essentially all looks like this example:
calllib(ADXL.Libname,'SPI_ChangeCS',ADXL.pChannelHandle, uint32(0b100000));
0 Comments
Accepted Answer
Edric Ellis
on 7 Jun 2022
I suspect the problem here is that when you transfer instances of your ADXL372 class to the workers, they are not getting set up correctly. The data transfer mechanism from client to worker when you invoke parfeval is equivalent to saving your objects to disk, and then loading them on the worker (it all happens in memory though). The problem is almost certainly that your loadlibrary calls are not being invoked on the workers.
By default, MATLAB classes do not call the constructor during load (or when they're received by a worker for a parfeval call). See this page in the doc for more details. I think you have two options here:
Here's an example of what I mean for the 2nd point:
% This causes the ADXL372 constructor to be invoked on every worker
adxlConst = parallel.pool.Constant(@ADXL372)
% Pass the Constant to the workers, extract the ".Value" and use that
F = parfeval(gcp(),@(c, varargin) ReadFIFO(c.Value, varargin{:}),4, adxlConst, Dauer, 10);
5 Comments
Edric Ellis
on 8 Jun 2022
The statement
app.adxlConst = parallel.pool.Constant(@ADXL372);
builds an instance of ADXL372 on each worker. I thought that SPISetup needed to be called by each process to set up state there - but it sounds like that is not the case?
If you want to update a UI on completion of a Future, you might want to use afterEach - this is designed for that sort of situation.
More Answers (0)
See Also
Categories
Find more on Asynchronous Parallel Programming in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!