Version 1.17dev8
Fixed bugs related to grid bed compensation and M571 in 1.17dev7 version Software reset code storage/retrieval now works on Duet WiFi Removed max average printing acceleration parameter M571 now accepts F parameter to set the PWM frequency M106 now shows if fan is disabled
This commit is contained in:
parent
9799ffce73
commit
a7ea87d1e3
15 changed files with 360 additions and 278 deletions
Binary file not shown.
Binary file not shown.
|
@ -28,11 +28,11 @@ Licence: GPL
|
||||||
// Firmware name is now defined in the Pins file
|
// Firmware name is now defined in the Pins file
|
||||||
|
|
||||||
#ifndef VERSION
|
#ifndef VERSION
|
||||||
# define VERSION "1.17dev7"
|
# define VERSION "1.17dev8"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef DATE
|
#ifndef DATE
|
||||||
# define DATE "2016-12-07"
|
# define DATE "2016-12-09"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define AUTHORS "reprappro, dc42, zpl, t3p3, dnewman"
|
#define AUTHORS "reprappro, dc42, zpl, t3p3, dnewman"
|
||||||
|
@ -118,7 +118,7 @@ const unsigned int FirstRtdChannel = 200; // Temperature sensor channels 200..
|
||||||
const unsigned int SlowHeaterPwmFreq = 10; // slow PWM frequency for bed and chamber heaters, compatible with DC/AC SSRs
|
const unsigned int SlowHeaterPwmFreq = 10; // slow PWM frequency for bed and chamber heaters, compatible with DC/AC SSRs
|
||||||
const unsigned int NormalHeaterPwmFreq = 250; // normal PWM frequency used for hot ends
|
const unsigned int NormalHeaterPwmFreq = 250; // normal PWM frequency used for hot ends
|
||||||
const unsigned int DefaultFanPwmFreq = 250; // increase to 25kHz using M106 command to meet Intel 4-wire PWM fan specification
|
const unsigned int DefaultFanPwmFreq = 250; // increase to 25kHz using M106 command to meet Intel 4-wire PWM fan specification
|
||||||
const unsigned int DefaultPinWritePwmFreq = 500; // default PWM frequency for M42 pin writes
|
const unsigned int DefaultPinWritePwmFreq = 500; // default PWM frequency for M42 pin writes and extrusion ancilliary PWM
|
||||||
|
|
||||||
// Default Z probe values
|
// Default Z probe values
|
||||||
|
|
||||||
|
|
10
src/Fan.cpp
10
src/Fan.cpp
|
@ -132,4 +132,14 @@ void Fan::Check()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Fan::Disable()
|
||||||
|
{
|
||||||
|
if (pin != NoPin)
|
||||||
|
{
|
||||||
|
inverted = false;
|
||||||
|
SetHardwarePwm(0.0);
|
||||||
|
}
|
||||||
|
pin = NoPin;
|
||||||
|
}
|
||||||
|
|
||||||
// End
|
// End
|
||||||
|
|
|
@ -48,7 +48,7 @@ public:
|
||||||
void SetTriggerTemperature(float t) { triggerTemperature = t; }
|
void SetTriggerTemperature(float t) { triggerTemperature = t; }
|
||||||
void SetHeatersMonitored(uint16_t h);
|
void SetHeatersMonitored(uint16_t h);
|
||||||
void Check();
|
void Check();
|
||||||
void Disable() { pin = NoPin; }
|
void Disable();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* SRC_FAN_H_ */
|
#endif /* SRC_FAN_H_ */
|
||||||
|
|
|
@ -148,7 +148,7 @@ void GCodes::Reset()
|
||||||
simulationMode = 0;
|
simulationMode = 0;
|
||||||
simulationTime = 0.0;
|
simulationTime = 0.0;
|
||||||
isPaused = false;
|
isPaused = false;
|
||||||
filePos = moveBuffer.filePos = noFilePosition;
|
moveBuffer.filePos = noFilePosition;
|
||||||
lastEndstopStates = platform->GetAllEndstopStates();
|
lastEndstopStates = platform->GetAllEndstopStates();
|
||||||
firmwareUpdateModuleMap = 0;
|
firmwareUpdateModuleMap = 0;
|
||||||
|
|
||||||
|
@ -699,11 +699,6 @@ void GCodes::DoFilePrint(GCodeBuffer& gb, StringRef& reply)
|
||||||
char b;
|
char b;
|
||||||
if (fd.Read(b))
|
if (fd.Read(b))
|
||||||
{
|
{
|
||||||
if (gb.StartingNewCode() && &gb == fileGCode && gb.MachineState().previous == nullptr)
|
|
||||||
{
|
|
||||||
filePos = fd.GetPosition() - 1;
|
|
||||||
//debugPrintf("Set file pos %u\n", filePos);
|
|
||||||
}
|
|
||||||
if (gb.Put(b))
|
if (gb.Put(b))
|
||||||
{
|
{
|
||||||
gb.SetFinished(ActOnCode(gb, reply));
|
gb.SetFinished(ActOnCode(gb, reply));
|
||||||
|
@ -732,6 +727,7 @@ void GCodes::DoFilePrint(GCodeBuffer& gb, StringRef& reply)
|
||||||
if (gb.MachineState().previous == nullptr)
|
if (gb.MachineState().previous == nullptr)
|
||||||
{
|
{
|
||||||
// Finished printing SD card file
|
// Finished printing SD card file
|
||||||
|
UnlockAll(gb);
|
||||||
reprap.GetPrintMonitor()->StoppedPrint();
|
reprap.GetPrintMonitor()->StoppedPrint();
|
||||||
if (platform->Emulating() == marlin)
|
if (platform->Emulating() == marlin)
|
||||||
{
|
{
|
||||||
|
@ -947,7 +943,7 @@ void GCodes::Pop(GCodeBuffer& gb)
|
||||||
// Move expects all axis movements to be absolute, and all extruder drive moves to be relative. This function serves that.
|
// Move expects all axis movements to be absolute, and all extruder drive moves to be relative. This function serves that.
|
||||||
// 'moveType' is the S parameter in the G0 or G1 command, or -1 if we are doing G92.
|
// 'moveType' is the S parameter in the G0 or G1 command, or -1 if we are doing G92.
|
||||||
// For regular (type 0) moves, we apply limits and do X axis mapping.
|
// For regular (type 0) moves, we apply limits and do X axis mapping.
|
||||||
// Returns the number of segments if we have a legal move (or 1 if we are doing G92), or zero if this gcode should be discarded
|
// Returns the number of segments if we have a legal move, 1 if we are doing G92, or zero if this gcode should be discarded
|
||||||
unsigned int GCodes::LoadMoveBufferFromGCode(GCodeBuffer& gb, int moveType)
|
unsigned int GCodes::LoadMoveBufferFromGCode(GCodeBuffer& gb, int moveType)
|
||||||
{
|
{
|
||||||
// Zero every extruder drive as some drives may not be changed
|
// Zero every extruder drive as some drives may not be changed
|
||||||
|
@ -1214,7 +1210,7 @@ int GCodes::SetUpMove(GCodeBuffer& gb, StringRef& reply)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the last position and feed rate into moveBuffer
|
// Load the last position into moveBuffer
|
||||||
#if SUPPORT_ROLAND
|
#if SUPPORT_ROLAND
|
||||||
if (reprap.GetRoland()->Active())
|
if (reprap.GetRoland()->Active())
|
||||||
{
|
{
|
||||||
|
@ -1227,24 +1223,25 @@ int GCodes::SetUpMove(GCodeBuffer& gb, StringRef& reply)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the move buffer with either the absolute movement required or the relative movement required
|
// Load the move buffer with either the absolute movement required or the relative movement required
|
||||||
float oldCoords[MAX_AXES];
|
memcpy(moveBuffer.initialCoords, moveBuffer.coords, numAxes * sizeof(moveBuffer.initialCoords[0]));
|
||||||
memcpy(oldCoords, moveBuffer.coords, sizeof(oldCoords));
|
|
||||||
segmentsLeft = LoadMoveBufferFromGCode(gb, moveBuffer.moveType);
|
segmentsLeft = LoadMoveBufferFromGCode(gb, moveBuffer.moveType);
|
||||||
|
|
||||||
if (segmentsLeft != 0)
|
if (segmentsLeft != 0)
|
||||||
{
|
{
|
||||||
// Flag whether we should use pressure advance, if there is any extrusion in this move.
|
// Flag whether we should use pressure advance, if there is any extrusion in this move.
|
||||||
// We assume it is a normal printing move needing pressure advance if there is forward extrusion and XY movement.
|
// We assume it is a normal printing move needing pressure advance if there is forward extrusion and XYU.. movement.
|
||||||
// The movement code will only apply pressure advance if there is forward extrusion, so we only need to check for XY movement here.
|
// The movement code will only apply pressure advance if there is forward extrusion, so we only need to check for XYU.. movement here.
|
||||||
moveBuffer.usePressureAdvance = false;
|
moveBuffer.usePressureAdvance = false;
|
||||||
for (size_t axis = 0; axis < numAxes; ++axis)
|
for (size_t axis = 0; axis < numAxes; ++axis)
|
||||||
{
|
{
|
||||||
if (axis != Z_AXIS && moveBuffer.coords[axis] != oldCoords[axis])
|
if (axis != Z_AXIS && moveBuffer.coords[axis] != moveBuffer.initialCoords[axis])
|
||||||
{
|
{
|
||||||
moveBuffer.usePressureAdvance = true;
|
moveBuffer.usePressureAdvance = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
moveBuffer.filePos = (&gb == fileGCode) ? filePos : noFilePosition;
|
moveBuffer.filePos = (&gb == fileGCode) ? gb.MachineState().fileState.GetPosition() : noFilePosition;
|
||||||
|
moveBuffer.canPauseAfter = (moveBuffer.endStopsToCheck == 0);
|
||||||
//debugPrintf("Queue move pos %u\n", moveFilePos);
|
//debugPrintf("Queue move pos %u\n", moveFilePos);
|
||||||
}
|
}
|
||||||
return (moveBuffer.moveType != 0 || moveBuffer.endStopsToCheck != 0) ? 2 : 1;
|
return (moveBuffer.moveType != 0 || moveBuffer.endStopsToCheck != 0) ? 2 : 1;
|
||||||
|
@ -1266,7 +1263,9 @@ bool GCodes::ReadMove(RawMove& m)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// This move needs to be divided into 2 or more segments
|
// This move needs to be divided into 2 or more segments. We can only pause after the final segment.
|
||||||
|
m.canPauseAfter = false;
|
||||||
|
|
||||||
// Do the axes
|
// Do the axes
|
||||||
for (size_t drive = 0; drive < numAxes; ++drive)
|
for (size_t drive = 0; drive < numAxes; ++drive)
|
||||||
{
|
{
|
||||||
|
@ -1375,9 +1374,23 @@ bool GCodes::DoCannedCycleMove(GCodeBuffer& gb, EndstopChecks ce)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This handles G92
|
// This handles G92. Return true if completed, false if it needs to be called again.
|
||||||
bool GCodes::SetPositions(GCodeBuffer& gb)
|
bool GCodes::SetPositions(GCodeBuffer& gb)
|
||||||
{
|
{
|
||||||
|
if (gb.Seen('R') && gb.GetIValue() == 1)
|
||||||
|
{
|
||||||
|
// Babystepping command. All coordinates except Z are ignored.
|
||||||
|
if (gb.Seen('Z'))
|
||||||
|
{
|
||||||
|
const float babystepAmount = gb.GetFValue() * distanceScale;
|
||||||
|
if (fabs(babystepAmount) <= 1.0) // limit babystepping to 1mm
|
||||||
|
{
|
||||||
|
reprap.GetMove()->Babystep(babystepAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Don't pause the machine if only extruder drives are being reset (DC, 2015-09-06).
|
// Don't pause the machine if only extruder drives are being reset (DC, 2015-09-06).
|
||||||
// This avoids blobs and seams when the gcode uses absolute E coordinates and periodically includes G92 E0.
|
// This avoids blobs and seams when the gcode uses absolute E coordinates and periodically includes G92 E0.
|
||||||
bool includingAxes = false;
|
bool includingAxes = false;
|
||||||
|
@ -1392,7 +1405,7 @@ bool GCodes::SetPositions(GCodeBuffer& gb)
|
||||||
|
|
||||||
if (includingAxes)
|
if (includingAxes)
|
||||||
{
|
{
|
||||||
if (!LockMovementAndWaitForStandstill(gb))
|
if (!LockMovementAndWaitForStandstill(gb)) // lock movement and get current coordinates
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1402,8 +1415,7 @@ bool GCodes::SetPositions(GCodeBuffer& gb)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
reprap.GetMove()->GetCurrentUserPosition(moveBuffer.coords, 0, reprap.GetCurrentXAxes()); // make sure move buffer is up to date
|
const bool ok = LoadMoveBufferFromGCode(gb, -1);
|
||||||
bool ok = LoadMoveBufferFromGCode(gb, -1);
|
|
||||||
if (ok && includingAxes)
|
if (ok && includingAxes)
|
||||||
{
|
{
|
||||||
#if SUPPORT_ROLAND
|
#if SUPPORT_ROLAND
|
||||||
|
@ -1420,7 +1432,7 @@ bool GCodes::SetPositions(GCodeBuffer& gb)
|
||||||
#endif
|
#endif
|
||||||
SetPositions(moveBuffer.coords);
|
SetPositions(moveBuffer.coords);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2974,7 +2986,7 @@ void GCodes::StartToolChange(GCodeBuffer& gb, bool inM109)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retract or un-retract filament, returning true if movement has been queued, false if this needs to be called again
|
// Retract or un-retract filament, returning true if movement has been queued, false if this needs to be called again
|
||||||
bool GCodes::RetractFilament(bool retract)
|
bool GCodes::RetractFilament(GCodeBuffer& gb, bool retract)
|
||||||
{
|
{
|
||||||
if (retractLength != 0.0 || retractHop != 0.0 || (!retract && retractExtra != 0.0))
|
if (retractLength != 0.0 || retractHop != 0.0 || (!retract && retractExtra != 0.0))
|
||||||
{
|
{
|
||||||
|
@ -3008,7 +3020,8 @@ bool GCodes::RetractFilament(bool retract)
|
||||||
|
|
||||||
moveBuffer.isFirmwareRetraction = true;
|
moveBuffer.isFirmwareRetraction = true;
|
||||||
moveBuffer.usePressureAdvance = false;
|
moveBuffer.usePressureAdvance = false;
|
||||||
moveBuffer.filePos = filePos;
|
moveBuffer.filePos = (&gb == fileGCode) ? gb.MachineState().fileState.GetPosition() : noFilePosition;
|
||||||
|
moveBuffer.canPauseAfter = !retract; // don't pause after a retraction because that could cause too much retraction
|
||||||
moveBuffer.xAxes = reprap.GetCurrentXAxes();
|
moveBuffer.xAxes = reprap.GetCurrentXAxes();
|
||||||
segmentsLeft = 1;
|
segmentsLeft = 1;
|
||||||
}
|
}
|
|
@ -65,12 +65,13 @@ public:
|
||||||
float coords[DRIVES]; // new positions for the axes, amount of movement for the extruders
|
float coords[DRIVES]; // new positions for the axes, amount of movement for the extruders
|
||||||
float initialCoords[MAX_AXES]; // the initial positions of the axes
|
float initialCoords[MAX_AXES]; // the initial positions of the axes
|
||||||
float feedRate; // feed rate of this move
|
float feedRate; // feed rate of this move
|
||||||
FilePosition filePos; // offset in the file being printed that this move was read from
|
FilePosition filePos; // offset in the file being printed at the end of reading this move
|
||||||
uint32_t xAxes; // axes that X is mapped to
|
uint32_t xAxes; // axes that X is mapped to
|
||||||
EndstopChecks endStopsToCheck; // endstops to check
|
EndstopChecks endStopsToCheck; // endstops to check
|
||||||
uint8_t moveType; // the S parameter from the G0 or G1 command, 0 for a normal move
|
uint8_t moveType; // the S parameter from the G0 or G1 command, 0 for a normal move
|
||||||
bool isFirmwareRetraction; // true if this is a firmware retraction/un-retraction move
|
bool isFirmwareRetraction; // true if this is a firmware retraction/un-retraction move
|
||||||
bool usePressureAdvance; // true if we want to us extruder pressure advance, if there is any extrusion
|
bool usePressureAdvance; // true if we want to us extruder pressure advance, if there is any extrusion
|
||||||
|
bool canPauseAfter; // true if we can pause just after this move and successfully restart
|
||||||
};
|
};
|
||||||
|
|
||||||
GCodes(Platform* p, Webserver* w);
|
GCodes(Platform* p, Webserver* w);
|
||||||
|
@ -197,7 +198,7 @@ private:
|
||||||
void SetAllAxesNotHomed(); // Flag all axes as not homed
|
void SetAllAxesNotHomed(); // Flag all axes as not homed
|
||||||
void SetPositions(float positionNow[DRIVES]); // Set the current position to be this
|
void SetPositions(float positionNow[DRIVES]); // Set the current position to be this
|
||||||
const char *TranslateEndStopResult(EndStopHit es); // Translate end stop result to text
|
const char *TranslateEndStopResult(EndStopHit es); // Translate end stop result to text
|
||||||
bool RetractFilament(bool retract); // Retract or un-retract filaments
|
bool RetractFilament(GCodeBuffer& gb, bool retract); // Retract or un-retract filaments
|
||||||
bool ChangeMicrostepping(size_t drive, int microsteps, int mode) const; // Change microstepping on the specified drive
|
bool ChangeMicrostepping(size_t drive, int microsteps, int mode) const; // Change microstepping on the specified drive
|
||||||
void ListTriggers(StringRef reply, TriggerMask mask); // Append a list of trigger endstops to a message
|
void ListTriggers(StringRef reply, TriggerMask mask); // Append a list of trigger endstops to a message
|
||||||
void CheckTriggers(); // Check for and execute triggers
|
void CheckTriggers(); // Check for and execute triggers
|
||||||
|
@ -280,7 +281,6 @@ private:
|
||||||
|
|
||||||
float simulationTime; // Accumulated simulation time
|
float simulationTime; // Accumulated simulation time
|
||||||
uint8_t simulationMode; // 0 = not simulating, 1 = simulating, >1 are simulation modes for debugging
|
uint8_t simulationMode; // 0 = not simulating, 1 = simulating, >1 are simulation modes for debugging
|
||||||
FilePosition filePos; // The position we got up to in the file being printed
|
|
||||||
|
|
||||||
// Firmware retraction settings
|
// Firmware retraction settings
|
||||||
float retractLength, retractExtra; // retraction length and extra length to un-retract
|
float retractLength, retractExtra; // retraction length and extra length to un-retract
|
||||||
|
|
|
@ -133,7 +133,7 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, StringRef& reply)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
result = RetractFilament(true);
|
result = RetractFilament(gb, true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, StringRef& reply)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
result = RetractFilament(false);
|
result = RetractFilament(gb, false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 20: // Inches (which century are we living in, here?)
|
case 20: // Inches (which century are we living in, here?)
|
||||||
|
@ -913,9 +913,14 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool seen = false;
|
|
||||||
Fan& fan = platform->GetFan(fanNum);
|
Fan& fan = platform->GetFan(fanNum);
|
||||||
|
if (!fan.IsEnabled())
|
||||||
|
{
|
||||||
|
reply.printf("Fan number %d is disabled", fanNum);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool seen = false;
|
||||||
if (gb.Seen('I')) // Invert cooling
|
if (gb.Seen('I')) // Invert cooling
|
||||||
{
|
{
|
||||||
const int invert = gb.GetIValue();
|
const int invert = gb.GetIValue();
|
||||||
|
@ -1034,6 +1039,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 107: // Fan off - deprecated
|
case 107: // Fan off - deprecated
|
||||||
|
@ -1491,13 +1497,6 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gb.Seen('P'))
|
|
||||||
{
|
|
||||||
// Set max average printing acceleration
|
|
||||||
platform->SetMaxAverageAcceleration(gb.GetFValue() * distanceScale);
|
|
||||||
seen = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!seen)
|
if (!seen)
|
||||||
{
|
{
|
||||||
reply.printf("Accelerations: ");
|
reply.printf("Accelerations: ");
|
||||||
|
@ -1512,7 +1511,6 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
|
||||||
reply.catf("%c%.1f", sep, platform->Acceleration(extruder + numAxes) / distanceScale);
|
reply.catf("%c%.1f", sep, platform->Acceleration(extruder + numAxes) / distanceScale);
|
||||||
sep = ':';
|
sep = ':';
|
||||||
}
|
}
|
||||||
reply.catf(", avg. printing: %.1f", platform->GetMaxAverageAcceleration());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2591,6 +2589,10 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
|
||||||
}
|
}
|
||||||
seen = true;
|
seen = true;
|
||||||
}
|
}
|
||||||
|
if (gb.Seen('F'))
|
||||||
|
{
|
||||||
|
platform->SetExtrusionAncilliaryPwmFrequency(gb.GetFValue());
|
||||||
|
}
|
||||||
if (gb.Seen('S'))
|
if (gb.Seen('S'))
|
||||||
{
|
{
|
||||||
platform->SetExtrusionAncilliaryPwmValue(gb.GetFValue());
|
platform->SetExtrusionAncilliaryPwmValue(gb.GetFValue());
|
||||||
|
@ -2598,8 +2600,10 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
|
||||||
}
|
}
|
||||||
if (!seen)
|
if (!seen)
|
||||||
{
|
{
|
||||||
reply.printf("Extrusion ancillary PWM %.3f on pin %u",
|
reply.printf("Extrusion ancillary PWM %.3f at %.1fHz on pin %u",
|
||||||
platform->GetExtrusionAncilliaryPwmValue(), platform->GetExtrusionAncilliaryPwmPin());
|
platform->GetExtrusionAncilliaryPwmValue(),
|
||||||
|
platform->GetExtrusionAncilliaryPwmFrequency(),
|
||||||
|
platform->GetExtrusionAncilliaryPwmPin());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -240,6 +240,7 @@ bool DDA::Init(const GCodes::RawMove &nextMove, bool doMotorMapping)
|
||||||
|
|
||||||
// 3. Store some values
|
// 3. Store some values
|
||||||
endStopsToCheck = nextMove.endStopsToCheck;
|
endStopsToCheck = nextMove.endStopsToCheck;
|
||||||
|
canPauseAfter = nextMove.canPauseAfter;
|
||||||
filePos = nextMove.filePos;
|
filePos = nextMove.filePos;
|
||||||
usePressureAdvance = nextMove.usePressureAdvance;
|
usePressureAdvance = nextMove.usePressureAdvance;
|
||||||
hadLookaheadUnderrun = false;
|
hadLookaheadUnderrun = false;
|
||||||
|
@ -564,15 +565,14 @@ void DDA::RecalculateMove()
|
||||||
topSpeed = requestedSpeed;
|
topSpeed = requestedSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
canPause = (endStopsToCheck == 0);
|
if (canPauseAfter && endSpeed != 0.0)
|
||||||
if (canPause && endSpeed != 0.0)
|
|
||||||
{
|
{
|
||||||
const Platform * const p = reprap.GetPlatform();
|
const Platform * const p = reprap.GetPlatform();
|
||||||
for (size_t drive = 0; drive < DRIVES; ++drive)
|
for (size_t drive = 0; drive < DRIVES; ++drive)
|
||||||
{
|
{
|
||||||
if (ddm[drive].state == DMState::moving && endSpeed * fabsf(directionVector[drive]) > p->ActualInstantDv(drive))
|
if (ddm[drive].state == DMState::moving && endSpeed * fabsf(directionVector[drive]) > p->ActualInstantDv(drive))
|
||||||
{
|
{
|
||||||
canPause = false;
|
canPauseAfter = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -724,44 +724,6 @@ void DDA::Prepare()
|
||||||
float decelStartTime = accelStopTime + (params.decelStartDistance - accelDistance)/topSpeed;
|
float decelStartTime = accelStopTime + (params.decelStartDistance - accelDistance)/topSpeed;
|
||||||
float totalTime = decelStartTime + (topSpeed - endSpeed)/acceleration;
|
float totalTime = decelStartTime + (topSpeed - endSpeed)/acceleration;
|
||||||
|
|
||||||
// Enforce the maximum average acceleration
|
|
||||||
if (isPrintingMove && topSpeed > startSpeed && topSpeed > endSpeed)
|
|
||||||
{
|
|
||||||
const float maxAverageAcceleration = reprap.GetPlatform()->GetMaxAverageAcceleration();
|
|
||||||
if (2 * topSpeed - startSpeed - endSpeed > totalTime * maxAverageAcceleration)
|
|
||||||
{
|
|
||||||
// Reduce the top speed to comply with the maximum average acceleration
|
|
||||||
const float a2 = fsquare(acceleration);
|
|
||||||
const float am2 = fsquare(maxAverageAcceleration);
|
|
||||||
const float aam = acceleration * maxAverageAcceleration;
|
|
||||||
const float discriminant = (a2 + (2 * aam) - am2) * (fsquare(startSpeed) + fsquare(endSpeed))
|
|
||||||
+ (2 * a2 + 2 * am2 - 4 * aam) * startSpeed * endSpeed
|
|
||||||
+ (8 * a2 * maxAverageAcceleration - 4 * acceleration * am2) * totalDistance;
|
|
||||||
const float oldTopSpeed = topSpeed;
|
|
||||||
if (discriminant < 0.0)
|
|
||||||
{
|
|
||||||
topSpeed = max<float>(startSpeed, endSpeed);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const float temp = (sqrtf(discriminant) + (acceleration - maxAverageAcceleration) * (startSpeed + endSpeed))
|
|
||||||
/(4 * acceleration - 2 * maxAverageAcceleration);
|
|
||||||
topSpeed = max<float>(max<float>(temp, startSpeed), endSpeed);
|
|
||||||
}
|
|
||||||
|
|
||||||
//DEBUG
|
|
||||||
debugPrintf("ots %f nts %f ss %f es %f\n", oldTopSpeed, topSpeed, startSpeed, endSpeed);
|
|
||||||
|
|
||||||
// Recalculate parameters
|
|
||||||
accelDistance = (fsquare(topSpeed) - fsquare(startSpeed))/(2 * acceleration);
|
|
||||||
decelDistance = (fsquare(topSpeed) - fsquare(endSpeed))/(2 * acceleration);
|
|
||||||
params.decelStartDistance = totalDistance - decelDistance;
|
|
||||||
accelStopTime = (topSpeed - startSpeed)/acceleration;
|
|
||||||
decelStartTime = accelStopTime + (params.decelStartDistance - accelDistance)/topSpeed;
|
|
||||||
totalTime = decelStartTime + (topSpeed - endSpeed)/acceleration;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clocksNeeded = (uint32_t)(totalTime * stepClockRate);
|
clocksNeeded = (uint32_t)(totalTime * stepClockRate);
|
||||||
|
|
||||||
params.startSpeedTimesCdivA = (uint32_t)((startSpeed * stepClockRate)/acceleration);
|
params.startSpeedTimesCdivA = (uint32_t)((startSpeed * stepClockRate)/acceleration);
|
||||||
|
|
|
@ -47,7 +47,7 @@ public:
|
||||||
void Prepare(); // Calculate all the values and freeze this DDA
|
void Prepare(); // Calculate all the values and freeze this DDA
|
||||||
float CalcTime() const; // Calculate the time needed for this move (used for simulation)
|
float CalcTime() const; // Calculate the time needed for this move (used for simulation)
|
||||||
bool HasStepError() const;
|
bool HasStepError() const;
|
||||||
bool CanPause() const { return canPause; }
|
bool CanPauseAfter() const { return canPauseAfter; }
|
||||||
bool IsPrintingMove() const { return isPrintingMove; } // Return true if this involves both XY movement and extrusion
|
bool IsPrintingMove() const { return isPrintingMove; } // Return true if this involves both XY movement and extrusion
|
||||||
|
|
||||||
DDAState GetState() const { return state; }
|
DDAState GetState() const { return state; }
|
||||||
|
@ -117,7 +117,7 @@ private:
|
||||||
volatile DDAState state; // what state this DDA is in
|
volatile DDAState state; // what state this DDA is in
|
||||||
uint8_t endCoordinatesValid : 1; // True if endCoordinates can be relied on
|
uint8_t endCoordinatesValid : 1; // True if endCoordinates can be relied on
|
||||||
uint8_t isDeltaMovement : 1; // True if this is a delta printer movement
|
uint8_t isDeltaMovement : 1; // True if this is a delta printer movement
|
||||||
uint8_t canPause : 1; // True if we can pause at the end of this move
|
uint8_t canPauseAfter : 1; // True if we can pause at the end of this move
|
||||||
uint8_t goingSlow : 1; // True if we have reduced speed during homing
|
uint8_t goingSlow : 1; // True if we have reduced speed during homing
|
||||||
uint8_t isPrintingMove : 1; // True if this move includes XY movement and extrusion
|
uint8_t isPrintingMove : 1; // True if this move includes XY movement and extrusion
|
||||||
uint8_t usePressureAdvance : 1; // True if pressure advance should be applied to any forward extrusion
|
uint8_t usePressureAdvance : 1; // True if pressure advance should be applied to any forward extrusion
|
||||||
|
|
|
@ -46,6 +46,7 @@ void Move::Init()
|
||||||
|
|
||||||
currentDda = nullptr;
|
currentDda = nullptr;
|
||||||
addNoMoreMoves = false;
|
addNoMoreMoves = false;
|
||||||
|
babysteppingLeft = 0.0;
|
||||||
stepErrors = 0;
|
stepErrors = 0;
|
||||||
numLookaheadUnderruns = numPrepareUnderruns = 0;
|
numLookaheadUnderruns = numPrepareUnderruns = 0;
|
||||||
|
|
||||||
|
@ -311,11 +312,13 @@ FilePosition Move::PausePrint(float positions[DRIVES], float& pausedFeedRate, ui
|
||||||
const DDA *savedDdaRingAddPointer = ddaRingAddPointer;
|
const DDA *savedDdaRingAddPointer = ddaRingAddPointer;
|
||||||
cpu_irq_disable();
|
cpu_irq_disable();
|
||||||
DDA *dda = currentDda;
|
DDA *dda = currentDda;
|
||||||
|
FilePosition fPos = noFilePosition;
|
||||||
if (dda != nullptr)
|
if (dda != nullptr)
|
||||||
{
|
{
|
||||||
// A move is being executed. See if we can safely pause at the end of it.
|
// A move is being executed. See if we can safely pause at the end of it.
|
||||||
if (dda->CanPause())
|
if (dda->CanPauseAfter())
|
||||||
{
|
{
|
||||||
|
fPos = dda->GetFilePosition();
|
||||||
ddaRingAddPointer = dda->GetNext();
|
ddaRingAddPointer = dda->GetNext();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -325,8 +328,9 @@ FilePosition Move::PausePrint(float positions[DRIVES], float& pausedFeedRate, ui
|
||||||
dda = ddaRingGetPointer;
|
dda = ddaRingGetPointer;
|
||||||
while (dda != ddaRingAddPointer)
|
while (dda != ddaRingAddPointer)
|
||||||
{
|
{
|
||||||
if (dda->CanPause())
|
if (dda->CanPauseAfter())
|
||||||
{
|
{
|
||||||
|
fPos = dda->GetFilePosition();
|
||||||
ddaRingAddPointer = dda->GetNext();
|
ddaRingAddPointer = dda->GetNext();
|
||||||
if (ddaRingAddPointer->GetState() == DDA::frozen)
|
if (ddaRingAddPointer->GetState() == DDA::frozen)
|
||||||
{
|
{
|
||||||
|
@ -347,8 +351,6 @@ FilePosition Move::PausePrint(float positions[DRIVES], float& pausedFeedRate, ui
|
||||||
|
|
||||||
cpu_irq_enable();
|
cpu_irq_enable();
|
||||||
|
|
||||||
FilePosition fPos = noFilePosition;
|
|
||||||
|
|
||||||
if (ddaRingAddPointer != savedDdaRingAddPointer)
|
if (ddaRingAddPointer != savedDdaRingAddPointer)
|
||||||
{
|
{
|
||||||
const size_t numAxes = reprap.GetGCodes()->GetNumAxes();
|
const size_t numAxes = reprap.GetGCodes()->GetNumAxes();
|
||||||
|
@ -372,10 +374,6 @@ FilePosition Move::PausePrint(float positions[DRIVES], float& pausedFeedRate, ui
|
||||||
{
|
{
|
||||||
positions[drive] += dda->GetEndCoordinate(drive, true); // update the amount of extrusion we are going to skip
|
positions[drive] += dda->GetEndCoordinate(drive, true); // update the amount of extrusion we are going to skip
|
||||||
}
|
}
|
||||||
if (fPos == noFilePosition)
|
|
||||||
{
|
|
||||||
fPos = dda->GetFilePosition();
|
|
||||||
}
|
|
||||||
(void)dda->Free();
|
(void)dda->Free();
|
||||||
dda = dda->GetNext();
|
dda = dda->GetNext();
|
||||||
}
|
}
|
||||||
|
@ -389,6 +387,13 @@ FilePosition Move::PausePrint(float positions[DRIVES], float& pausedFeedRate, ui
|
||||||
return fPos;
|
return fPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Request babystepping
|
||||||
|
void Move::Babystep(float zMovement)
|
||||||
|
{
|
||||||
|
babysteppingLeft += zMovement;
|
||||||
|
// TODO use this value somewhere
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t maxReps = 0;
|
uint32_t maxReps = 0;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
|
@ -117,6 +117,7 @@ public:
|
||||||
|
|
||||||
void UseHeightMap(bool b) { useGridHeights = b; } // Start or stop using the height map
|
void UseHeightMap(bool b) { useGridHeights = b; } // Start or stop using the height map
|
||||||
bool UsingHeightMap() const { return useGridHeights; } // Are we doing grid bed compensation?
|
bool UsingHeightMap() const { return useGridHeights; } // Are we doing grid bed compensation?
|
||||||
|
void Babystep(float zMovement); // Request babystepping
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -192,6 +193,8 @@ private:
|
||||||
int coreXYMode; // 0 = Cartesian, 1 = CoreXY, 2 = CoreXZ, 3 = CoreYZ
|
int coreXYMode; // 0 = Cartesian, 1 = CoreXY, 2 = CoreXZ, 3 = CoreYZ
|
||||||
float axisFactors[MAX_AXES]; // How much further the motors need to move for each axis movement, on a CoreXY/CoreXZ/CoreYZ machine
|
float axisFactors[MAX_AXES]; // How much further the motors need to move for each axis movement, on a CoreXY/CoreXZ/CoreYZ machine
|
||||||
unsigned int stepErrors; // count of step errors, for diagnostics
|
unsigned int stepErrors; // count of step errors, for diagnostics
|
||||||
|
|
||||||
|
float babysteppingLeft; // the amount of Z babystepping left to do
|
||||||
};
|
};
|
||||||
|
|
||||||
//******************************************************************************************************
|
//******************************************************************************************************
|
||||||
|
|
126
src/Platform.cpp
126
src/Platform.cpp
|
@ -227,8 +227,6 @@ void Platform::Init()
|
||||||
stepperDacVoltageOffset = STEPPER_DAC_VOLTAGE_OFFSET;
|
stepperDacVoltageOffset = STEPPER_DAC_VOLTAGE_OFFSET;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
maxAverageAcceleration = 10000.0; // high enough to have no effect until it is changed
|
|
||||||
|
|
||||||
// Z PROBE
|
// Z PROBE
|
||||||
zProbePin = Z_PROBE_PIN;
|
zProbePin = Z_PROBE_PIN;
|
||||||
zProbeAdcChannel = PinToAdcChannel(zProbePin);
|
zProbeAdcChannel = PinToAdcChannel(zProbePin);
|
||||||
|
@ -326,12 +324,17 @@ void Platform::Init()
|
||||||
TMC2660::Init(ENABLE_PINS, numTMC2660Drivers);
|
TMC2660::Init(ENABLE_PINS, numTMC2660Drivers);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Allow extrusion ancilliary PWM to use FAN0 even if FAN0 has not been disabled, for backwards compatibility
|
||||||
extrusionAncilliaryPwmValue = 0.0;
|
extrusionAncilliaryPwmValue = 0.0;
|
||||||
extrusionAncilliaryPwmLogicalPin = -1;
|
extrusionAncilliaryPwmFrequency = DefaultPinWritePwmFreq;
|
||||||
extrusionAncilliaryPwmFirmwarePin = NoPin;
|
extrusionAncilliaryPwmLogicalPin = Fan0LogicalPin;
|
||||||
extrusionAncilliaryPwmInvert = false;
|
extrusionAncilliaryPwmFirmwarePin = COOLING_FAN_PINS[0];
|
||||||
SetExtrusionAncilliaryPwmPin(Fan0LogicalPin);
|
extrusionAncilliaryPwmInvert =
|
||||||
|
#if defined(DUET_NG) || defined(__RADDS__)
|
||||||
|
false;
|
||||||
|
#else
|
||||||
|
(board == BoardType::Duet_06 || board == BoardType::Duet_07);
|
||||||
|
#endif
|
||||||
ARRAY_INIT(tempSensePins, TEMP_SENSE_PINS);
|
ARRAY_INIT(tempSensePins, TEMP_SENSE_PINS);
|
||||||
ARRAY_INIT(heatOnPins, HEAT_ON_PINS);
|
ARRAY_INIT(heatOnPins, HEAT_ON_PINS);
|
||||||
ARRAY_INIT(spiTempSenseCsPins, SpiTempSensorCsPins);
|
ARRAY_INIT(spiTempSenseCsPins, SpiTempSensorCsPins);
|
||||||
|
@ -1243,14 +1246,41 @@ void Platform::SoftwareReset(uint16_t reason)
|
||||||
reason |= (uint16_t)reprap.GetSpinningModule();
|
reason |= (uint16_t)reprap.GetSpinningModule();
|
||||||
|
|
||||||
// Record the reason for the software reset
|
// Record the reason for the software reset
|
||||||
SoftwareResetData temp;
|
// First find a free slot (wear levelling)
|
||||||
temp.magic = SoftwareResetData::magicValue;
|
size_t slot = SoftwareResetData::numberOfSlots;
|
||||||
temp.version = SoftwareResetData::versionValue;
|
SoftwareResetData srdBuf[SoftwareResetData::numberOfSlots];
|
||||||
temp.resetReason = reason;
|
|
||||||
GetStackUsage(NULL, NULL, &temp.neverUsedRam);
|
|
||||||
|
|
||||||
// Save diagnostics data to Flash and reset the software
|
#ifdef DUET_NG
|
||||||
DueFlashStorage::write(SoftwareResetData::nvAddress, &temp, sizeof(SoftwareResetData));
|
if (flash_read_user_signature(reinterpret_cast<uint32_t*>(srdBuf), sizeof(srdBuf)/sizeof(uint32_t)) == FLASH_RC_OK)
|
||||||
|
#else
|
||||||
|
DueFlashStorage::read(SoftwareResetData::nvAddress, srdBuf, sizeof(srdBuf));
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
while (slot != 0 && srdBuf[slot - 1].isVacant())
|
||||||
|
{
|
||||||
|
--slot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slot == SoftwareResetData::numberOfSlots)
|
||||||
|
{
|
||||||
|
// No free slots, so erase the area
|
||||||
|
#ifdef DUET_NG
|
||||||
|
flash_erase_user_signature();
|
||||||
|
#endif
|
||||||
|
memset(srdBuf, 0xFF, sizeof(srdBuf));
|
||||||
|
slot = 0;
|
||||||
|
}
|
||||||
|
srdBuf[slot].magic = SoftwareResetData::magicValue;
|
||||||
|
srdBuf[slot].resetReason = reason;
|
||||||
|
GetStackUsage(NULL, NULL, &srdBuf[slot].neverUsedRam);
|
||||||
|
|
||||||
|
// Save diagnostics data to Flash
|
||||||
|
#ifdef DUET_NG
|
||||||
|
flash_write_user_signature(srdBuf, sizeof(srdBuf)/sizeof(uint32_t));
|
||||||
|
#else
|
||||||
|
DueFlashStorage::write(SoftwareResetData::nvAddress, srdBuf, sizeof(srdBuf));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
Reset();
|
Reset();
|
||||||
for(;;) {}
|
for(;;) {}
|
||||||
|
@ -1365,7 +1395,7 @@ void Platform::Diagnostics(MessageType mtype)
|
||||||
MessageF(mtype, "Program static ram used: %d\n", &_end - ramstart);
|
MessageF(mtype, "Program static ram used: %d\n", &_end - ramstart);
|
||||||
MessageF(mtype, "Dynamic ram used: %d\n", mi.uordblks);
|
MessageF(mtype, "Dynamic ram used: %d\n", mi.uordblks);
|
||||||
MessageF(mtype, "Recycled dynamic ram: %d\n", mi.fordblks);
|
MessageF(mtype, "Recycled dynamic ram: %d\n", mi.fordblks);
|
||||||
size_t currentStack, maxStack, neverUsed;
|
uint32_t currentStack, maxStack, neverUsed;
|
||||||
GetStackUsage(¤tStack, &maxStack, &neverUsed);
|
GetStackUsage(¤tStack, &maxStack, &neverUsed);
|
||||||
MessageF(mtype, "Current stack ram used: %d\n", currentStack);
|
MessageF(mtype, "Current stack ram used: %d\n", currentStack);
|
||||||
MessageF(mtype, "Maximum stack ram used: %d\n", maxStack);
|
MessageF(mtype, "Maximum stack ram used: %d\n", maxStack);
|
||||||
|
@ -1373,20 +1403,40 @@ void Platform::Diagnostics(MessageType mtype)
|
||||||
|
|
||||||
// Show the up time and reason for the last reset
|
// Show the up time and reason for the last reset
|
||||||
const uint32_t now = (uint32_t)Time(); // get up time in seconds
|
const uint32_t now = (uint32_t)Time(); // get up time in seconds
|
||||||
const char* resetReasons[8] = { "power up", "backup", "watchdog", "software", "external", "?", "?", "?" };
|
const char* resetReasons[8] = { "power up", "backup", "watchdog", "software", "reset button", "?", "?", "?" };
|
||||||
MessageF(mtype, "Last reset %02d:%02d:%02d ago, cause: %s\n",
|
MessageF(mtype, "Last reset %02d:%02d:%02d ago, cause: %s\n",
|
||||||
(unsigned int)(now/3600), (unsigned int)((now % 3600)/60), (unsigned int)(now % 60),
|
(unsigned int)(now/3600), (unsigned int)((now % 3600)/60), (unsigned int)(now % 60),
|
||||||
resetReasons[(REG_RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos]);
|
resetReasons[(REG_RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos]);
|
||||||
|
|
||||||
// Show the reset code stored at the last software reset
|
// Show the reset code stored at the last software reset
|
||||||
|
Message(mtype, "Last software reset code & available RAM: ");
|
||||||
{
|
{
|
||||||
SoftwareResetData temp;
|
SoftwareResetData srdBuf[SoftwareResetData::numberOfSlots];
|
||||||
temp.magic = 0;
|
memset(srdBuf, 0, sizeof(srdBuf));
|
||||||
DueFlashStorage::read(SoftwareResetData::nvAddress, &temp, sizeof(SoftwareResetData));
|
int slot = -1;
|
||||||
if (temp.magic == SoftwareResetData::magicValue && temp.version == SoftwareResetData::versionValue)
|
|
||||||
|
#ifdef DUET_NG
|
||||||
|
if (flash_read_user_signature(reinterpret_cast<uint32_t*>(srdBuf), sizeof(srdBuf)/sizeof(uint32_t)) == FLASH_RC_OK)
|
||||||
|
#else
|
||||||
|
DueFlashStorage::read(SoftwareResetData::nvAddress, srdBuf, sizeof(srdBuf));
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
MessageF(mtype, "Last software reset code & available RAM: 0x%04x, %u\n", temp.resetReason, temp.neverUsedRam);
|
// Find the last slot written
|
||||||
MessageF(mtype, "Spinning module during software reset: %s\n", moduleName[temp.resetReason & 0x0F]);
|
slot = SoftwareResetData::numberOfSlots - 1;
|
||||||
|
while (slot >= 0 && srdBuf[slot].magic == 0xFFFF)
|
||||||
|
{
|
||||||
|
--slot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slot >= 0 && srdBuf[slot].magic == SoftwareResetData::magicValue)
|
||||||
|
{
|
||||||
|
MessageF(mtype, "0x%04x, %u (slot %d)\n", srdBuf[slot].resetReason, srdBuf[slot].neverUsedRam, slot);
|
||||||
|
MessageF(mtype, "Spinning module during software reset: %s\n", moduleName[srdBuf[slot].resetReason & 0x0F]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Message(mtype, "not available\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1447,13 +1497,18 @@ void Platform::Diagnostics(MessageType mtype)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Show current RTC time
|
// Show current RTC time
|
||||||
|
Message(mtype, "Current date and time: ");
|
||||||
struct tm timeInfo;
|
struct tm timeInfo;
|
||||||
if (gmtime_r(&realTime, &timeInfo) != nullptr)
|
if (gmtime_r(&realTime, &timeInfo) != nullptr)
|
||||||
{
|
{
|
||||||
MessageF(mtype, "Current date and time: %04u-%02u-%02u %02u:%02u:%02u\n",
|
MessageF(mtype, "%04u-%02u-%02u %02u:%02u:%02u\n",
|
||||||
timeInfo.tm_year + 1900, timeInfo.tm_mon + 1, timeInfo.tm_mday,
|
timeInfo.tm_year + 1900, timeInfo.tm_mon + 1, timeInfo.tm_mday,
|
||||||
timeInfo.tm_hour, timeInfo.tm_min, timeInfo.tm_sec);
|
timeInfo.tm_hour, timeInfo.tm_min, timeInfo.tm_sec);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Message(mtype, "clock not set\n");
|
||||||
|
}
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
//MessageF(mtype, "TC_FMR = %08x, PWM_FPE = %08x, PWM_FSR = %08x\n", TC2->TC_FMR, PWM->PWM_FPE, PWM->PWM_FSR);
|
//MessageF(mtype, "TC_FMR = %08x, PWM_FPE = %08x, PWM_FSR = %08x\n", TC2->TC_FMR, PWM->PWM_FPE, PWM->PWM_FSR);
|
||||||
|
@ -1503,24 +1558,24 @@ void Platform::DiagnosticTest(int d)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the stack usage and amount of memory that has never been used, in bytes
|
// Return the stack usage and amount of memory that has never been used, in bytes
|
||||||
void Platform::GetStackUsage(size_t* currentStack, size_t* maxStack, size_t* neverUsed) const
|
void Platform::GetStackUsage(uint32_t* currentStack, uint32_t* maxStack, uint32_t* neverUsed) const
|
||||||
{
|
{
|
||||||
const char *ramend = (const char *)
|
const char * const ramend = (const char *)
|
||||||
#ifdef DUET_NG
|
#if SAM4E
|
||||||
0x20020000; // 0x20000000 + 128Kb
|
IRAM_ADDR + IRAM_SIZE;
|
||||||
#else
|
#else
|
||||||
0x20088000; // 0x20070000 + 96Kb
|
IRAM0_ADDR + IRAM_SIZE;
|
||||||
#endif
|
#endif
|
||||||
register const char * stack_ptr asm ("sp");
|
register const char * stack_ptr asm ("sp");
|
||||||
const char *heapend = sbrk(0);
|
const char * const heapend = sbrk(0);
|
||||||
const char* stack_lwm = heapend;
|
const char * stack_lwm = heapend;
|
||||||
while (stack_lwm < stack_ptr && *stack_lwm == memPattern)
|
while (stack_lwm < stack_ptr && *stack_lwm == memPattern)
|
||||||
{
|
{
|
||||||
++stack_lwm;
|
++stack_lwm;
|
||||||
}
|
}
|
||||||
if (currentStack) { *currentStack = ramend - stack_ptr; }
|
if (currentStack != nullptr) { *currentStack = ramend - stack_ptr; }
|
||||||
if (maxStack) { *maxStack = ramend - stack_lwm; }
|
if (maxStack != nullptr) { *maxStack = ramend - stack_lwm; }
|
||||||
if (neverUsed) { *neverUsed = stack_lwm - heapend; }
|
if (neverUsed != nullptr) { *neverUsed = stack_lwm - heapend; }
|
||||||
}
|
}
|
||||||
|
|
||||||
void Platform::ClassReport(float &lastTime)
|
void Platform::ClassReport(float &lastTime)
|
||||||
|
@ -2541,7 +2596,7 @@ void Platform::SetBoardType(BoardType bt)
|
||||||
#else
|
#else
|
||||||
// Determine whether this is a Duet 0.6 or a Duet 0.8.5 board.
|
// Determine whether this is a Duet 0.6 or a Duet 0.8.5 board.
|
||||||
// If it is a 0.85 board then DAC0 (AKA digital pin 67) is connected to ground via a diode and a 2.15K resistor.
|
// If it is a 0.85 board then DAC0 (AKA digital pin 67) is connected to ground via a diode and a 2.15K resistor.
|
||||||
// So we enable the pullup (value 150K-150K) on pin 67 and read it, expecting a LOW on a 0.8.5 board and a HIGH on a 0.6 board.
|
// So we enable the pullup (value 100K-150K) on pin 67 and read it, expecting a LOW on a 0.8.5 board and a HIGH on a 0.6 board.
|
||||||
// This may fail if anyone connects a load to the DAC0 pin on a Duet 0.6, hence we implement board selection in M115 as well.
|
// This may fail if anyone connects a load to the DAC0 pin on a Duet 0.6, hence we implement board selection in M115 as well.
|
||||||
pinMode(Dac0DigitalPin, INPUT_PULLUP);
|
pinMode(Dac0DigitalPin, INPUT_PULLUP);
|
||||||
board = (digitalRead(Dac0DigitalPin)) ? BoardType::Duet_06 : BoardType::Duet_085;
|
board = (digitalRead(Dac0DigitalPin)) ? BoardType::Duet_06 : BoardType::Duet_085;
|
||||||
|
@ -2628,6 +2683,9 @@ bool Platform::GetFirmwarePin(int logicalPin, PinAccess access, Pin& firmwarePin
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
firmwarePin = COOLING_FAN_PINS[logicalPin - Fan0LogicalPin];
|
firmwarePin = COOLING_FAN_PINS[logicalPin - Fan0LogicalPin];
|
||||||
|
#if !defined(DUET_NG) && !defined(__RADDS__)
|
||||||
|
invert = (board == BoardType::Duet_06 || board == BoardType::Duet_07);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (logicalPin >= EndstopXLogicalPin && logicalPin < EndstopXLogicalPin + (int)ARRAY_SIZE(endStopPins)) // pins 40-49 correspond to endstop pins
|
else if (logicalPin >= EndstopXLogicalPin && logicalPin < EndstopXLogicalPin + (int)ARRAY_SIZE(endStopPins)) // pins 40-49 correspond to endstop pins
|
||||||
|
|
|
@ -509,10 +509,6 @@ public:
|
||||||
float Acceleration(size_t drive) const;
|
float Acceleration(size_t drive) const;
|
||||||
const float* Accelerations() const;
|
const float* Accelerations() const;
|
||||||
void SetAcceleration(size_t drive, float value);
|
void SetAcceleration(size_t drive, float value);
|
||||||
const float GetMaxAverageAcceleration() const
|
|
||||||
{ return maxAverageAcceleration; }
|
|
||||||
void SetMaxAverageAcceleration(float f)
|
|
||||||
{ maxAverageAcceleration = f; }
|
|
||||||
float MaxFeedrate(size_t drive) const;
|
float MaxFeedrate(size_t drive) const;
|
||||||
const float* MaxFeedrates() const;
|
const float* MaxFeedrates() const;
|
||||||
void SetMaxFeedrate(size_t drive, float value);
|
void SetMaxFeedrate(size_t drive, float value);
|
||||||
|
@ -567,6 +563,8 @@ public:
|
||||||
|
|
||||||
void SetExtrusionAncilliaryPwmValue(float v);
|
void SetExtrusionAncilliaryPwmValue(float v);
|
||||||
float GetExtrusionAncilliaryPwmValue() const;
|
float GetExtrusionAncilliaryPwmValue() const;
|
||||||
|
void SetExtrusionAncilliaryPwmFrequency(float f);
|
||||||
|
float GetExtrusionAncilliaryPwmFrequency() const;
|
||||||
bool SetExtrusionAncilliaryPwmPin(int logicalPin);
|
bool SetExtrusionAncilliaryPwmPin(int logicalPin);
|
||||||
int GetExtrusionAncilliaryPwmPin() const { return extrusionAncilliaryPwmLogicalPin; }
|
int GetExtrusionAncilliaryPwmPin() const { return extrusionAncilliaryPwmLogicalPin; }
|
||||||
void ExtrudeOn();
|
void ExtrudeOn();
|
||||||
|
@ -681,31 +679,41 @@ private:
|
||||||
static float AdcReadingToPowerVoltage(uint16_t reading);
|
static float AdcReadingToPowerVoltage(uint16_t reading);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// These are the structures used to hold out non-volatile data.
|
// These are the structures used to hold our non-volatile data.
|
||||||
// The SAM3X doesn't have EEPROM so we save the data to flash. This unfortunately means that it gets cleared
|
// The SAM3X and SAM4E don't have EEPROM so we save the data to flash. This unfortunately means that it gets cleared
|
||||||
// every time we reprogram the firmware via bossa, but it can be retained when firmware updates are performed
|
// every time we reprogram the firmware via bossa, but it can be retained when firmware updates are performed
|
||||||
// via the web interface. That's why it's a good idea to implement versioning here - increase these values
|
// via the web interface. That's why it's a good idea to implement versioning here - increase these values
|
||||||
// whenever the fields of the following structs have changed.
|
// whenever the fields of the following structs have changed.
|
||||||
|
//
|
||||||
|
// The SAM4E has a large page erase size (8K). For this reason we store the software reset data in the 512-byte user signature area
|
||||||
|
// instead, which doesn't get cleared when the Erase button is pressed. The SoftareResetData struct must have at least one 32-bit
|
||||||
|
// field to guarantee that values of this type will be 32-bit aligned. It must have no virtual members because it is read/written
|
||||||
|
// directly form/to flash memory.
|
||||||
struct SoftwareResetData
|
struct SoftwareResetData
|
||||||
{
|
{
|
||||||
static const uint16_t magicValue = 0x7C5F; // value we use to recognise that all the flash data has been written
|
static const uint16_t versionValue = 2; // increment this whenever this struct changes
|
||||||
static const uint16_t versionValue = 1; // increment this whenever this struct changes
|
static const uint16_t magicValue = 0x7D00 | versionValue; // value we use to recognise that all the flash data has been written
|
||||||
static const uint32_t nvAddress = 0; // must be 4-byte aligned
|
static const uint32_t nvAddress = 0; // must be 4-byte aligned
|
||||||
|
static const size_t numberOfSlots = 8; // number of storage slots used to implement wear levelling
|
||||||
|
|
||||||
uint16_t magic;
|
uint16_t magic; // the magic number, including the version
|
||||||
uint16_t version;
|
|
||||||
|
|
||||||
uint16_t resetReason; // this records why we did a software reset, for diagnostic purposes
|
uint16_t resetReason; // this records why we did a software reset, for diagnostic purposes
|
||||||
uint16_t dummy; // padding to align the next field (should happen automatically I think)
|
uint32_t neverUsedRam; // the amount of never used RAM at the last abnormal software reset
|
||||||
size_t neverUsedRam; // the amount of never used RAM at the last abnormal software reset
|
|
||||||
|
bool isVacant() const // return true if this struct can be written without erasing it first
|
||||||
|
{
|
||||||
|
return magic == 0xFFFF && resetReason == 0xFFFF && neverUsedRam == 0xFFFFFFFF;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static_assert(SoftwareResetData::numberOfSlots * sizeof(SoftwareResetData) <= 512, "Can't fit software reset data in SAM4E user signature area");
|
||||||
|
|
||||||
|
// The following struct is due to be replaced by the config-override.g file.
|
||||||
struct FlashData
|
struct FlashData
|
||||||
{
|
{
|
||||||
static const uint16_t magicValue = 0xE6C4; // value we use to recognise that the flash data has been written
|
static const uint16_t magicValue = 0xE6C4; // value we use to recognise that the flash data has been written
|
||||||
static const uint16_t versionValue = 5; // increment this whenever this struct changes
|
static const uint16_t versionValue = 5; // increment this whenever this struct changes
|
||||||
static const uint32_t nvAddress = (SoftwareResetData::nvAddress + sizeof(SoftwareResetData) + 3) & (~3);
|
static const uint32_t nvAddress = SoftwareResetData::nvAddress + (SoftwareResetData::numberOfSlots * sizeof(SoftwareResetData));
|
||||||
|
|
||||||
uint16_t magic;
|
uint16_t magic;
|
||||||
uint16_t version;
|
uint16_t version;
|
||||||
|
@ -742,7 +750,7 @@ private:
|
||||||
uint32_t errorCodeBits;
|
uint32_t errorCodeBits;
|
||||||
|
|
||||||
void InitialiseInterrupts();
|
void InitialiseInterrupts();
|
||||||
void GetStackUsage(size_t* currentStack, size_t* maxStack, size_t* neverUsed) const;
|
void GetStackUsage(uint32_t* currentStack, uint32_t* maxStack, uint32_t* neverUsed) const;
|
||||||
|
|
||||||
// DRIVES
|
// DRIVES
|
||||||
|
|
||||||
|
@ -770,7 +778,6 @@ private:
|
||||||
uint32_t slowDriverStepPulseClocks; // minimum high and low step pulse widths, in processor clocks
|
uint32_t slowDriverStepPulseClocks; // minimum high and low step pulse widths, in processor clocks
|
||||||
uint32_t slowDrivers; // bitmap of driver port bits that need extended step pulse timing
|
uint32_t slowDrivers; // bitmap of driver port bits that need extended step pulse timing
|
||||||
float idleCurrentFactor;
|
float idleCurrentFactor;
|
||||||
float maxAverageAcceleration;
|
|
||||||
|
|
||||||
#if defined(DUET_NG)
|
#if defined(DUET_NG)
|
||||||
size_t numTMC2660Drivers; // the number of TMC2660 drivers we have, the remaining are simple enable/step/dir drivers
|
size_t numTMC2660Drivers; // the number of TMC2660 drivers we have, the remaining are simple enable/step/dir drivers
|
||||||
|
@ -793,6 +800,7 @@ private:
|
||||||
volatile ThermistorAveragingFilter thermistorFilters[HEATERS]; // bed and extruder thermistor readings
|
volatile ThermistorAveragingFilter thermistorFilters[HEATERS]; // bed and extruder thermistor readings
|
||||||
|
|
||||||
float extrusionAncilliaryPwmValue;
|
float extrusionAncilliaryPwmValue;
|
||||||
|
float extrusionAncilliaryPwmFrequency;
|
||||||
int extrusionAncilliaryPwmLogicalPin;
|
int extrusionAncilliaryPwmLogicalPin;
|
||||||
Pin extrusionAncilliaryPwmFirmwarePin;
|
Pin extrusionAncilliaryPwmFirmwarePin;
|
||||||
bool extrusionAncilliaryPwmInvert;
|
bool extrusionAncilliaryPwmInvert;
|
||||||
|
@ -1125,6 +1133,16 @@ inline float Platform::GetExtrusionAncilliaryPwmValue() const
|
||||||
return extrusionAncilliaryPwmValue;
|
return extrusionAncilliaryPwmValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void Platform::SetExtrusionAncilliaryPwmFrequency(float f)
|
||||||
|
{
|
||||||
|
extrusionAncilliaryPwmFrequency = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float Platform::GetExtrusionAncilliaryPwmFrequency() const
|
||||||
|
{
|
||||||
|
return extrusionAncilliaryPwmFrequency;
|
||||||
|
}
|
||||||
|
|
||||||
// For the Duet we use the fan output for this
|
// For the Duet we use the fan output for this
|
||||||
// DC 2015-03-21: To allow users to control the cooling fan via gcodes generated by slic3r etc.,
|
// DC 2015-03-21: To allow users to control the cooling fan via gcodes generated by slic3r etc.,
|
||||||
// only turn the fan on/off if the extruder ancilliary PWM has been set nonzero.
|
// only turn the fan on/off if the extruder ancilliary PWM has been set nonzero.
|
||||||
|
@ -1133,7 +1151,8 @@ inline void Platform::ExtrudeOn()
|
||||||
{
|
{
|
||||||
if (extrusionAncilliaryPwmValue > 0.0)
|
if (extrusionAncilliaryPwmValue > 0.0)
|
||||||
{
|
{
|
||||||
WriteAnalog(extrusionAncilliaryPwmFirmwarePin, extrusionAncilliaryPwmValue, DefaultPinWritePwmFreq);
|
WriteAnalog(extrusionAncilliaryPwmFirmwarePin,
|
||||||
|
(extrusionAncilliaryPwmInvert) ? 1.0 - extrusionAncilliaryPwmValue : extrusionAncilliaryPwmValue, extrusionAncilliaryPwmFrequency);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1144,7 +1163,8 @@ inline void Platform::ExtrudeOff()
|
||||||
{
|
{
|
||||||
if (extrusionAncilliaryPwmValue > 0.0)
|
if (extrusionAncilliaryPwmValue > 0.0)
|
||||||
{
|
{
|
||||||
WriteAnalog(extrusionAncilliaryPwmFirmwarePin, 0.0, DefaultPinWritePwmFreq);
|
WriteAnalog(extrusionAncilliaryPwmFirmwarePin,
|
||||||
|
(extrusionAncilliaryPwmInvert) ? 1.0 : 0.0, extrusionAncilliaryPwmFrequency);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -306,18 +306,25 @@ void Tool::SetVariables(const float* standby, const float* active)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const float temperatureLimit = reprap.GetHeat()->GetTemperatureLimit(heaters[heater]);
|
const float temperatureLimit = reprap.GetHeat()->GetTemperatureLimit(heaters[heater]);
|
||||||
|
const Tool * const currentTool = reprap.GetCurrentTool();
|
||||||
if (active[heater] < temperatureLimit)
|
if (active[heater] < temperatureLimit)
|
||||||
{
|
{
|
||||||
activeTemperatures[heater] = active[heater];
|
activeTemperatures[heater] = active[heater];
|
||||||
|
if (currentTool == nullptr || currentTool == this)
|
||||||
|
{
|
||||||
reprap.GetHeat()->SetActiveTemperature(heaters[heater], activeTemperatures[heater]);
|
reprap.GetHeat()->SetActiveTemperature(heaters[heater], activeTemperatures[heater]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (standby[heater] < temperatureLimit)
|
if (standby[heater] < temperatureLimit)
|
||||||
{
|
{
|
||||||
standbyTemperatures[heater] = standby[heater];
|
standbyTemperatures[heater] = standby[heater];
|
||||||
|
if (currentTool == nullptr || currentTool == this)
|
||||||
|
{
|
||||||
reprap.GetHeat()->SetStandbyTemperature(heaters[heater], standbyTemperatures[heater]);
|
reprap.GetHeat()->SetStandbyTemperature(heaters[heater], standbyTemperatures[heater]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tool::GetVariables(float* standby, float* active) const
|
void Tool::GetVariables(float* standby, float* active) const
|
||||||
|
|
Reference in a new issue