I created 4 threads for each of the 4 stepper motors separately, where an infinite loop will spin with the given Dir and Step and with delays depending on the current speed for each motor. Each call to Out32 will be in a critical section.
In procedure TLPTEngine.ApplyHardware, RotDir[i], RotateStep[i] and speed (delay) TimeOut[i] will be set for each engine. The code below should start spinning the motors when the program starts, but it doesn't. When calling the OutToLptThread[i].Execute procedure in the TLPTEngine.InitializeHardware procedure, an error occurs:
"Exception EAccessViolation in module MyProgram.exe at 001CE279. Access violation at address 005CE279 in module MyProgram.exe'. Read of address 00000000."
and the program is terminated.
uses
SysUtils, Math, TraceLog, MDriveEngines, SyncObjs;
const
numOfEngines = 4;
type
// Class of threads that control motors
TOutToLptThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
public
LPTEngineNum: integer; // Number of engine and thread
end;
// Class of stepper motors
TLPTEngine = class(TEngine)
public
procedure InitializeHardware; override;
procedure FinalizeHardware; override;
procedure ApplyHardware; override;
end;
var
RotateStep: array [1 .. numOfEngines] of Integer; // Stepper motor rotation pulse via LPT-port
RotDir: array [1 .. numOfEngines] of Integer; // Direction of rotation of stepper motor via LPT-port
Time_out: array [1 .. numOfEngines] of Integer; // Delays in the supply of pulses to the stepper motor through the LPT-port - for different motor speeds
FSynchronizer: TCriticalSection;
OutToLptThread: array[1..numOfEngines] of TOutToLptThread; // Array of threads that control numOfEngines engines
OutToLPTData: Byte; // Common byte with all Dir and Step for tumOfEngines engines, issued to the LPT port
procedure TOutToLptThread.Execute;
procedure Delay_mcs(time_out: double); // Delay in microseconds
var
iCounterPerSec: TLargeInteger;
T1, T2: TLargeInteger; // Values of counter before and after operation
begin
QueryPerformanceFrequency(iCounterPerSec);
// We defines a frequency of counter
QueryPerformanceCounter(T1); // Recorded the start time of the operation
T2 := T1;
while (T2 - T1) * 1000000 / iCounterPerSec < time_out do
QueryPerformanceCounter(T2); // Recorded the end time of the operation
end;
var
PortAdr: word;
begin
PortAdr := $EEFC; // Address of LPT-port
while true do
begin
OutToLPTData := RotDir[1] * 2 + RotDir[2] * 8 + RotDir[3] * 32 + RotDir[4] * 128; // Data that output to LPT-port
FSynchronizer.Enter; // = Acquire;
try
Out32(PortAdr, OutToLPTData);
finally
FSynchronizer.Leave; // = Release
end;
Delay_mcs(Time_out[LPTEngineNum]);
OutToLPTData := RotateStep[1] + RotateStep[2] * 4 + RotateStep[3] * 16 +
RotateStep[4] * 64 +
RotDir[1] * 2 + RotDir[2] * 8 + RotDir[3] * 32 +
RotDir[4] * 128; // Data that output to LPT-port
FSynchronizer.Enter; // = Acquire;
try
Out32(PortAdr, OutToLPTData);
finally
FSynchronizer.Leave; // = Release
end;
Delay_mcs(Time_out[LPTEngineNum]);
end;
end;
procedure TLPTEngine.InitializeHardware; // Called at the start of program execution
var
i: integer;
begin
IsSoftwareControlEngine := true;
for i := 1 to numOfEngines do
begin
RotateStep[i] := 1; // Initial pulses of rotation of the stepper motor
RotDir[i] := 0; // Initial direction of rotation of motors
Time_out[i] := 500; // Delay in microseconds for each stepper motor
OutToLptThread[i] := TOutToLptThread.Create(False);
OutToLptThread[i].LPTEngineNum := i; // The thread number corresponds to the engine number, used in the assignment Time_out[LPTEngineNum]
OutToLptThread[i].Priority := tpNormal;
// OutToLptThread[i].Execute; // This command causes a message "Exception EAccessViolation in module MyProgram.exe at 001CE279. Access violation at address 005CE279 in module MyProgram.exe'. Read of address 00000000."
end;
inherited;
end;
procedure TLPTEngine.ApplyHardware; // Called when the value of Velocity changes.
var
i: Integer;
begin
i := AxisNum; // Number of engine
if Velocity > 0 then // Direction of Rotation
begin
RotDir[i] := 0;
RotateStep[i] := 1
end
else if Velocity < 0 then // Another direction of Rotation
begin
RotDir[i] := 1;
RotateStep[i] := 1
end
else
begin
RotDir[i] := 0;
RotateStep[i] := 0
end;
end;