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
|
||||
|
||||
#ifndef VERSION
|
||||
# define VERSION "1.17dev7"
|
||||
# define VERSION "1.17dev8"
|
||||
#endif
|
||||
|
||||
#ifndef DATE
|
||||
# define DATE "2016-12-07"
|
||||
# define DATE "2016-12-09"
|
||||
#endif
|
||||
|
||||
#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 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 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
|
||||
|
||||
|
|
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
|
||||
|
|
|
@ -48,7 +48,7 @@ public:
|
|||
void SetTriggerTemperature(float t) { triggerTemperature = t; }
|
||||
void SetHeatersMonitored(uint16_t h);
|
||||
void Check();
|
||||
void Disable() { pin = NoPin; }
|
||||
void Disable();
|
||||
};
|
||||
|
||||
#endif /* SRC_FAN_H_ */
|
||||
|
|
|
@ -148,7 +148,7 @@ void GCodes::Reset()
|
|||
simulationMode = 0;
|
||||
simulationTime = 0.0;
|
||||
isPaused = false;
|
||||
filePos = moveBuffer.filePos = noFilePosition;
|
||||
moveBuffer.filePos = noFilePosition;
|
||||
lastEndstopStates = platform->GetAllEndstopStates();
|
||||
firmwareUpdateModuleMap = 0;
|
||||
|
||||
|
@ -699,11 +699,6 @@ void GCodes::DoFilePrint(GCodeBuffer& gb, StringRef& reply)
|
|||
char 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))
|
||||
{
|
||||
gb.SetFinished(ActOnCode(gb, reply));
|
||||
|
@ -732,6 +727,7 @@ void GCodes::DoFilePrint(GCodeBuffer& gb, StringRef& reply)
|
|||
if (gb.MachineState().previous == nullptr)
|
||||
{
|
||||
// Finished printing SD card file
|
||||
UnlockAll(gb);
|
||||
reprap.GetPrintMonitor()->StoppedPrint();
|
||||
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.
|
||||
// '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.
|
||||
// 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)
|
||||
{
|
||||
// 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 (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
|
||||
float oldCoords[MAX_AXES];
|
||||
memcpy(oldCoords, moveBuffer.coords, sizeof(oldCoords));
|
||||
memcpy(moveBuffer.initialCoords, moveBuffer.coords, numAxes * sizeof(moveBuffer.initialCoords[0]));
|
||||
segmentsLeft = LoadMoveBufferFromGCode(gb, moveBuffer.moveType);
|
||||
|
||||
if (segmentsLeft != 0)
|
||||
{
|
||||
// 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.
|
||||
// The movement code will only apply pressure advance if there is forward extrusion, so we only need to check for XY movement here.
|
||||
// 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 XYU.. movement here.
|
||||
moveBuffer.usePressureAdvance = false;
|
||||
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;
|
||||
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);
|
||||
}
|
||||
return (moveBuffer.moveType != 0 || moveBuffer.endStopsToCheck != 0) ? 2 : 1;
|
||||
|
@ -1266,7 +1263,9 @@ bool GCodes::ReadMove(RawMove& m)
|
|||
}
|
||||
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
|
||||
for (size_t drive = 0; drive < numAxes; ++drive)
|
||||
{
|
||||
|
@ -1375,52 +1374,65 @@ bool GCodes::DoCannedCycleMove(GCodeBuffer& gb, EndstopChecks ce)
|
|||
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)
|
||||
{
|
||||
// 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.
|
||||
bool includingAxes = false;
|
||||
for (size_t drive = 0; drive < numAxes; ++drive)
|
||||
if (gb.Seen('R') && gb.GetIValue() == 1)
|
||||
{
|
||||
if (gb.Seen(axisLetters[drive]))
|
||||
// Babystepping command. All coordinates except Z are ignored.
|
||||
if (gb.Seen('Z'))
|
||||
{
|
||||
includingAxes = true;
|
||||
break;
|
||||
const float babystepAmount = gb.GetFValue() * distanceScale;
|
||||
if (fabs(babystepAmount) <= 1.0) // limit babystepping to 1mm
|
||||
{
|
||||
reprap.GetMove()->Babystep(babystepAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (includingAxes)
|
||||
else
|
||||
{
|
||||
if (!LockMovementAndWaitForStandstill(gb))
|
||||
// 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.
|
||||
bool includingAxes = false;
|
||||
for (size_t drive = 0; drive < numAxes; ++drive)
|
||||
{
|
||||
if (gb.Seen(axisLetters[drive]))
|
||||
{
|
||||
includingAxes = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (includingAxes)
|
||||
{
|
||||
if (!LockMovementAndWaitForStandstill(gb)) // lock movement and get current coordinates
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (segmentsLeft != 0) // wait for previous move to be taken so that GetCurrentUserPosition returns the correct value
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (segmentsLeft != 0) // wait for previous move to be taken so that GetCurrentUserPosition returns the correct value
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
reprap.GetMove()->GetCurrentUserPosition(moveBuffer.coords, 0, reprap.GetCurrentXAxes()); // make sure move buffer is up to date
|
||||
bool ok = LoadMoveBufferFromGCode(gb, -1);
|
||||
if (ok && includingAxes)
|
||||
{
|
||||
#if SUPPORT_ROLAND
|
||||
if (reprap.GetRoland()->Active())
|
||||
const bool ok = LoadMoveBufferFromGCode(gb, -1);
|
||||
if (ok && includingAxes)
|
||||
{
|
||||
for(size_t axis = 0; axis < AXES; axis++)
|
||||
#if SUPPORT_ROLAND
|
||||
if (reprap.GetRoland()->Active())
|
||||
{
|
||||
if (!reprap.GetRoland()->ProcessG92(moveBuffer[axis], axis))
|
||||
for(size_t axis = 0; axis < AXES; axis++)
|
||||
{
|
||||
return false;
|
||||
if (!reprap.GetRoland()->ProcessG92(moveBuffer[axis], axis))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
SetPositions(moveBuffer.coords);
|
||||
SetPositions(moveBuffer.coords);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
bool GCodes::RetractFilament(bool retract)
|
||||
bool GCodes::RetractFilament(GCodeBuffer& gb, bool retract)
|
||||
{
|
||||
if (retractLength != 0.0 || retractHop != 0.0 || (!retract && retractExtra != 0.0))
|
||||
{
|
||||
|
@ -3008,7 +3020,8 @@ bool GCodes::RetractFilament(bool retract)
|
|||
|
||||
moveBuffer.isFirmwareRetraction = true;
|
||||
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();
|
||||
segmentsLeft = 1;
|
||||
}
|
|
@ -65,12 +65,13 @@ public:
|
|||
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 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
|
||||
EndstopChecks endStopsToCheck; // endstops to check
|
||||
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 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);
|
||||
|
@ -197,7 +198,7 @@ private:
|
|||
void SetAllAxesNotHomed(); // Flag all axes as not homed
|
||||
void SetPositions(float positionNow[DRIVES]); // Set the current position to be this
|
||||
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
|
||||
void ListTriggers(StringRef reply, TriggerMask mask); // Append a list of trigger endstops to a message
|
||||
void CheckTriggers(); // Check for and execute triggers
|
||||
|
@ -280,7 +281,6 @@ private:
|
|||
|
||||
float simulationTime; // Accumulated simulation time
|
||||
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
|
||||
float retractLength, retractExtra; // retraction length and extra length to un-retract
|
||||
|
|
|
@ -133,7 +133,7 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, StringRef& reply)
|
|||
{
|
||||
return false;
|
||||
}
|
||||
result = RetractFilament(true);
|
||||
result = RetractFilament(gb, true);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -142,7 +142,7 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, StringRef& reply)
|
|||
{
|
||||
return false;
|
||||
}
|
||||
result = RetractFilament(false);
|
||||
result = RetractFilament(gb, false);
|
||||
break;
|
||||
|
||||
case 20: // Inches (which century are we living in, here?)
|
||||
|
@ -913,121 +913,127 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
|
|||
}
|
||||
else
|
||||
{
|
||||
bool seen = false;
|
||||
Fan& fan = platform->GetFan(fanNum);
|
||||
|
||||
if (gb.Seen('I')) // Invert cooling
|
||||
if (!fan.IsEnabled())
|
||||
{
|
||||
const int invert = gb.GetIValue();
|
||||
if (invert < 0)
|
||||
reply.printf("Fan number %d is disabled", fanNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool seen = false;
|
||||
if (gb.Seen('I')) // Invert cooling
|
||||
{
|
||||
fan.Disable();
|
||||
}
|
||||
else
|
||||
{
|
||||
fan.SetInverted(invert > 0);
|
||||
}
|
||||
seen = true;
|
||||
}
|
||||
|
||||
if (gb.Seen('F')) // Set PWM frequency
|
||||
{
|
||||
fan.SetPwmFrequency(gb.GetFValue());
|
||||
seen = true;
|
||||
}
|
||||
|
||||
if (gb.Seen('T')) // Set thermostatic trigger temperature
|
||||
{
|
||||
seen = true;
|
||||
fan.SetTriggerTemperature(gb.GetFValue());
|
||||
}
|
||||
|
||||
if (gb.Seen('B')) // Set blip time
|
||||
{
|
||||
seen = true;
|
||||
fan.SetBlipTime(gb.GetFValue());
|
||||
}
|
||||
|
||||
if (gb.Seen('L')) // Set minimum speed
|
||||
{
|
||||
seen = true;
|
||||
fan.SetMinValue(gb.GetFValue());
|
||||
}
|
||||
|
||||
if (gb.Seen('H')) // Set thermostatically-controller heaters
|
||||
{
|
||||
seen = true;
|
||||
long heaters[HEATERS];
|
||||
size_t numH = HEATERS;
|
||||
gb.GetLongArray(heaters, numH);
|
||||
// Note that M106 H-1 disables thermostatic mode. The following code implements that automatically.
|
||||
uint16_t hh = 0;
|
||||
for (size_t h = 0; h < numH; ++h)
|
||||
{
|
||||
const int hnum = heaters[h];
|
||||
if (hnum >= 0 && hnum < HEATERS)
|
||||
const int invert = gb.GetIValue();
|
||||
if (invert < 0)
|
||||
{
|
||||
hh |= (1u << (unsigned int)hnum);
|
||||
fan.Disable();
|
||||
}
|
||||
else
|
||||
{
|
||||
fan.SetInverted(invert > 0);
|
||||
}
|
||||
seen = true;
|
||||
}
|
||||
|
||||
if (gb.Seen('F')) // Set PWM frequency
|
||||
{
|
||||
fan.SetPwmFrequency(gb.GetFValue());
|
||||
seen = true;
|
||||
}
|
||||
|
||||
if (gb.Seen('T')) // Set thermostatic trigger temperature
|
||||
{
|
||||
seen = true;
|
||||
fan.SetTriggerTemperature(gb.GetFValue());
|
||||
}
|
||||
|
||||
if (gb.Seen('B')) // Set blip time
|
||||
{
|
||||
seen = true;
|
||||
fan.SetBlipTime(gb.GetFValue());
|
||||
}
|
||||
|
||||
if (gb.Seen('L')) // Set minimum speed
|
||||
{
|
||||
seen = true;
|
||||
fan.SetMinValue(gb.GetFValue());
|
||||
}
|
||||
|
||||
if (gb.Seen('H')) // Set thermostatically-controller heaters
|
||||
{
|
||||
seen = true;
|
||||
long heaters[HEATERS];
|
||||
size_t numH = HEATERS;
|
||||
gb.GetLongArray(heaters, numH);
|
||||
// Note that M106 H-1 disables thermostatic mode. The following code implements that automatically.
|
||||
uint16_t hh = 0;
|
||||
for (size_t h = 0; h < numH; ++h)
|
||||
{
|
||||
const int hnum = heaters[h];
|
||||
if (hnum >= 0 && hnum < HEATERS)
|
||||
{
|
||||
hh |= (1u << (unsigned int)hnum);
|
||||
}
|
||||
}
|
||||
if (hh != 0)
|
||||
{
|
||||
platform->SetFanValue(fanNum, 1.0); // default the fan speed to full for safety
|
||||
}
|
||||
fan.SetHeatersMonitored(hh);
|
||||
}
|
||||
|
||||
if (gb.Seen('S')) // Set new fan value - process this after processing 'H' or it may not be acted on
|
||||
{
|
||||
const float f = constrain<float>(gb.GetFValue(), 0.0, 255.0);
|
||||
if (seen || seenFanNum)
|
||||
{
|
||||
platform->SetFanValue(fanNum, f);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are processing an M106 S### command with no other recognised parameters and we have a tool selected.
|
||||
// Apply the fan speed setting to the fans in the fan mapping for the current tool.
|
||||
lastDefaultFanSpeed = f;
|
||||
SetMappedFanSpeed();
|
||||
}
|
||||
}
|
||||
if (hh != 0)
|
||||
else if (gb.Seen('R'))
|
||||
{
|
||||
platform->SetFanValue(fanNum, 1.0); // default the fan speed to full for safety
|
||||
}
|
||||
fan.SetHeatersMonitored(hh);
|
||||
}
|
||||
|
||||
if (gb.Seen('S')) // Set new fan value - process this after processing 'H' or it may not be acted on
|
||||
{
|
||||
const float f = constrain<float>(gb.GetFValue(), 0.0, 255.0);
|
||||
if (seen || seenFanNum)
|
||||
{
|
||||
platform->SetFanValue(fanNum, f);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are processing an M106 S### command with no other recognised parameters and we have a tool selected.
|
||||
// Apply the fan speed setting to the fans in the fan mapping for the current tool.
|
||||
lastDefaultFanSpeed = f;
|
||||
SetMappedFanSpeed();
|
||||
}
|
||||
}
|
||||
else if (gb.Seen('R'))
|
||||
{
|
||||
const int i = gb.GetIValue();
|
||||
switch(i)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
// Restore fan speed to value when print was paused
|
||||
platform->SetFanValue(fanNum, pausedFanValues[fanNum]);
|
||||
break;
|
||||
case 2:
|
||||
// Set the speeds of mapped fans to the last known value. Fan number is ignored.
|
||||
SetMappedFanSpeed();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!seen)
|
||||
{
|
||||
reply.printf("Fan%i frequency: %dHz, speed: %d%%, min: %d%%, blip: %.2f, inverted: %s",
|
||||
fanNum,
|
||||
(int)(fan.GetPwmFrequency()),
|
||||
(int)(fan.GetValue() * 100.0),
|
||||
(int)(fan.GetMinValue() * 100.0),
|
||||
fan.GetBlipTime(),
|
||||
(fan.GetInverted()) ? "yes" : "no");
|
||||
uint16_t hh = fan.GetHeatersMonitored();
|
||||
if (hh != 0)
|
||||
{
|
||||
reply.catf(", trigger: %dC, heaters:", (int)fan.GetTriggerTemperature());
|
||||
for (unsigned int i = 0; i < HEATERS; ++i)
|
||||
const int i = gb.GetIValue();
|
||||
switch(i)
|
||||
{
|
||||
if ((hh & (1u << i)) != 0)
|
||||
case 0:
|
||||
case 1:
|
||||
// Restore fan speed to value when print was paused
|
||||
platform->SetFanValue(fanNum, pausedFanValues[fanNum]);
|
||||
break;
|
||||
case 2:
|
||||
// Set the speeds of mapped fans to the last known value. Fan number is ignored.
|
||||
SetMappedFanSpeed();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!seen)
|
||||
{
|
||||
reply.printf("Fan%i frequency: %dHz, speed: %d%%, min: %d%%, blip: %.2f, inverted: %s",
|
||||
fanNum,
|
||||
(int)(fan.GetPwmFrequency()),
|
||||
(int)(fan.GetValue() * 100.0),
|
||||
(int)(fan.GetMinValue() * 100.0),
|
||||
fan.GetBlipTime(),
|
||||
(fan.GetInverted()) ? "yes" : "no");
|
||||
uint16_t hh = fan.GetHeatersMonitored();
|
||||
if (hh != 0)
|
||||
{
|
||||
reply.catf(", trigger: %dC, heaters:", (int)fan.GetTriggerTemperature());
|
||||
for (unsigned int i = 0; i < HEATERS; ++i)
|
||||
{
|
||||
reply.catf(" %u", i);
|
||||
if ((hh & (1u << i)) != 0)
|
||||
{
|
||||
reply.catf(" %u", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
reply.printf("Accelerations: ");
|
||||
|
@ -1512,7 +1511,6 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
|
|||
reply.catf("%c%.1f", sep, platform->Acceleration(extruder + numAxes) / distanceScale);
|
||||
sep = ':';
|
||||
}
|
||||
reply.catf(", avg. printing: %.1f", platform->GetMaxAverageAcceleration());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -2591,6 +2589,10 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
|
|||
}
|
||||
seen = true;
|
||||
}
|
||||
if (gb.Seen('F'))
|
||||
{
|
||||
platform->SetExtrusionAncilliaryPwmFrequency(gb.GetFValue());
|
||||
}
|
||||
if (gb.Seen('S'))
|
||||
{
|
||||
platform->SetExtrusionAncilliaryPwmValue(gb.GetFValue());
|
||||
|
@ -2598,8 +2600,10 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
|
|||
}
|
||||
if (!seen)
|
||||
{
|
||||
reply.printf("Extrusion ancillary PWM %.3f on pin %u",
|
||||
platform->GetExtrusionAncilliaryPwmValue(), platform->GetExtrusionAncilliaryPwmPin());
|
||||
reply.printf("Extrusion ancillary PWM %.3f at %.1fHz on pin %u",
|
||||
platform->GetExtrusionAncilliaryPwmValue(),
|
||||
platform->GetExtrusionAncilliaryPwmFrequency(),
|
||||
platform->GetExtrusionAncilliaryPwmPin());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -240,6 +240,7 @@ bool DDA::Init(const GCodes::RawMove &nextMove, bool doMotorMapping)
|
|||
|
||||
// 3. Store some values
|
||||
endStopsToCheck = nextMove.endStopsToCheck;
|
||||
canPauseAfter = nextMove.canPauseAfter;
|
||||
filePos = nextMove.filePos;
|
||||
usePressureAdvance = nextMove.usePressureAdvance;
|
||||
hadLookaheadUnderrun = false;
|
||||
|
@ -564,15 +565,14 @@ void DDA::RecalculateMove()
|
|||
topSpeed = requestedSpeed;
|
||||
}
|
||||
|
||||
canPause = (endStopsToCheck == 0);
|
||||
if (canPause && endSpeed != 0.0)
|
||||
if (canPauseAfter && endSpeed != 0.0)
|
||||
{
|
||||
const Platform * const p = reprap.GetPlatform();
|
||||
for (size_t drive = 0; drive < DRIVES; ++drive)
|
||||
{
|
||||
if (ddm[drive].state == DMState::moving && endSpeed * fabsf(directionVector[drive]) > p->ActualInstantDv(drive))
|
||||
{
|
||||
canPause = false;
|
||||
canPauseAfter = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -724,44 +724,6 @@ void DDA::Prepare()
|
|||
float decelStartTime = accelStopTime + (params.decelStartDistance - accelDistance)/topSpeed;
|
||||
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);
|
||||
|
||||
params.startSpeedTimesCdivA = (uint32_t)((startSpeed * stepClockRate)/acceleration);
|
||||
|
|
|
@ -47,7 +47,7 @@ public:
|
|||
void Prepare(); // Calculate all the values and freeze this DDA
|
||||
float CalcTime() const; // Calculate the time needed for this move (used for simulation)
|
||||
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
|
||||
|
||||
DDAState GetState() const { return state; }
|
||||
|
@ -117,7 +117,7 @@ private:
|
|||
volatile DDAState state; // what state this DDA is in
|
||||
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 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 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
|
||||
|
|
|
@ -46,6 +46,7 @@ void Move::Init()
|
|||
|
||||
currentDda = nullptr;
|
||||
addNoMoreMoves = false;
|
||||
babysteppingLeft = 0.0;
|
||||
stepErrors = 0;
|
||||
numLookaheadUnderruns = numPrepareUnderruns = 0;
|
||||
|
||||
|
@ -311,11 +312,13 @@ FilePosition Move::PausePrint(float positions[DRIVES], float& pausedFeedRate, ui
|
|||
const DDA *savedDdaRingAddPointer = ddaRingAddPointer;
|
||||
cpu_irq_disable();
|
||||
DDA *dda = currentDda;
|
||||
FilePosition fPos = noFilePosition;
|
||||
if (dda != nullptr)
|
||||
{
|
||||
// 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();
|
||||
}
|
||||
else
|
||||
|
@ -325,8 +328,9 @@ FilePosition Move::PausePrint(float positions[DRIVES], float& pausedFeedRate, ui
|
|||
dda = ddaRingGetPointer;
|
||||
while (dda != ddaRingAddPointer)
|
||||
{
|
||||
if (dda->CanPause())
|
||||
if (dda->CanPauseAfter())
|
||||
{
|
||||
fPos = dda->GetFilePosition();
|
||||
ddaRingAddPointer = dda->GetNext();
|
||||
if (ddaRingAddPointer->GetState() == DDA::frozen)
|
||||
{
|
||||
|
@ -347,8 +351,6 @@ FilePosition Move::PausePrint(float positions[DRIVES], float& pausedFeedRate, ui
|
|||
|
||||
cpu_irq_enable();
|
||||
|
||||
FilePosition fPos = noFilePosition;
|
||||
|
||||
if (ddaRingAddPointer != savedDdaRingAddPointer)
|
||||
{
|
||||
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
|
||||
}
|
||||
if (fPos == noFilePosition)
|
||||
{
|
||||
fPos = dda->GetFilePosition();
|
||||
}
|
||||
(void)dda->Free();
|
||||
dda = dda->GetNext();
|
||||
}
|
||||
|
@ -389,6 +387,13 @@ FilePosition Move::PausePrint(float positions[DRIVES], float& pausedFeedRate, ui
|
|||
return fPos;
|
||||
}
|
||||
|
||||
// Request babystepping
|
||||
void Move::Babystep(float zMovement)
|
||||
{
|
||||
babysteppingLeft += zMovement;
|
||||
// TODO use this value somewhere
|
||||
}
|
||||
|
||||
uint32_t maxReps = 0;
|
||||
|
||||
#if 0
|
||||
|
@ -402,7 +407,7 @@ void Move::Diagnostics(MessageType mtype)
|
|||
Platform * const p = reprap.GetPlatform();
|
||||
p->Message(mtype, "=== Move ===\n");
|
||||
p->MessageF(mtype, "MaxReps: %u, StepErrors: %u, MaxWait: %ums, Underruns: %u, %u\n",
|
||||
maxReps, stepErrors, longestGcodeWaitInterval, numLookaheadUnderruns, numPrepareUnderruns);
|
||||
maxReps, stepErrors, longestGcodeWaitInterval, numLookaheadUnderruns, numPrepareUnderruns);
|
||||
maxReps = 0;
|
||||
numLookaheadUnderruns = numPrepareUnderruns = 0;
|
||||
longestGcodeWaitInterval = 0;
|
||||
|
|
|
@ -117,6 +117,7 @@ public:
|
|||
|
||||
void UseHeightMap(bool b) { useGridHeights = b; } // Start or stop using the height map
|
||||
bool UsingHeightMap() const { return useGridHeights; } // Are we doing grid bed compensation?
|
||||
void Babystep(float zMovement); // Request babystepping
|
||||
|
||||
private:
|
||||
|
||||
|
@ -192,6 +193,8 @@ private:
|
|||
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
|
||||
unsigned int stepErrors; // count of step errors, for diagnostics
|
||||
|
||||
float babysteppingLeft; // the amount of Z babystepping left to do
|
||||
};
|
||||
|
||||
//******************************************************************************************************
|
||||
|
|
128
src/Platform.cpp
128
src/Platform.cpp
|
@ -227,8 +227,6 @@ void Platform::Init()
|
|||
stepperDacVoltageOffset = STEPPER_DAC_VOLTAGE_OFFSET;
|
||||
#endif
|
||||
|
||||
maxAverageAcceleration = 10000.0; // high enough to have no effect until it is changed
|
||||
|
||||
// Z PROBE
|
||||
zProbePin = Z_PROBE_PIN;
|
||||
zProbeAdcChannel = PinToAdcChannel(zProbePin);
|
||||
|
@ -326,12 +324,17 @@ void Platform::Init()
|
|||
TMC2660::Init(ENABLE_PINS, numTMC2660Drivers);
|
||||
#endif
|
||||
|
||||
// Allow extrusion ancilliary PWM to use FAN0 even if FAN0 has not been disabled, for backwards compatibility
|
||||
extrusionAncilliaryPwmValue = 0.0;
|
||||
extrusionAncilliaryPwmLogicalPin = -1;
|
||||
extrusionAncilliaryPwmFirmwarePin = NoPin;
|
||||
extrusionAncilliaryPwmInvert = false;
|
||||
SetExtrusionAncilliaryPwmPin(Fan0LogicalPin);
|
||||
|
||||
extrusionAncilliaryPwmFrequency = DefaultPinWritePwmFreq;
|
||||
extrusionAncilliaryPwmLogicalPin = Fan0LogicalPin;
|
||||
extrusionAncilliaryPwmFirmwarePin = COOLING_FAN_PINS[0];
|
||||
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(heatOnPins, HEAT_ON_PINS);
|
||||
ARRAY_INIT(spiTempSenseCsPins, SpiTempSensorCsPins);
|
||||
|
@ -1243,14 +1246,41 @@ void Platform::SoftwareReset(uint16_t reason)
|
|||
reason |= (uint16_t)reprap.GetSpinningModule();
|
||||
|
||||
// Record the reason for the software reset
|
||||
SoftwareResetData temp;
|
||||
temp.magic = SoftwareResetData::magicValue;
|
||||
temp.version = SoftwareResetData::versionValue;
|
||||
temp.resetReason = reason;
|
||||
GetStackUsage(NULL, NULL, &temp.neverUsedRam);
|
||||
// First find a free slot (wear levelling)
|
||||
size_t slot = SoftwareResetData::numberOfSlots;
|
||||
SoftwareResetData srdBuf[SoftwareResetData::numberOfSlots];
|
||||
|
||||
// Save diagnostics data to Flash and reset the software
|
||||
DueFlashStorage::write(SoftwareResetData::nvAddress, &temp, sizeof(SoftwareResetData));
|
||||
#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
|
||||
{
|
||||
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();
|
||||
for(;;) {}
|
||||
|
@ -1365,7 +1395,7 @@ void Platform::Diagnostics(MessageType mtype)
|
|||
MessageF(mtype, "Program static ram used: %d\n", &_end - ramstart);
|
||||
MessageF(mtype, "Dynamic ram used: %d\n", mi.uordblks);
|
||||
MessageF(mtype, "Recycled dynamic ram: %d\n", mi.fordblks);
|
||||
size_t currentStack, maxStack, neverUsed;
|
||||
uint32_t currentStack, maxStack, neverUsed;
|
||||
GetStackUsage(¤tStack, &maxStack, &neverUsed);
|
||||
MessageF(mtype, "Current stack ram used: %d\n", currentStack);
|
||||
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
|
||||
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",
|
||||
(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]);
|
||||
|
||||
// Show the reset code stored at the last software reset
|
||||
Message(mtype, "Last software reset code & available RAM: ");
|
||||
{
|
||||
SoftwareResetData temp;
|
||||
temp.magic = 0;
|
||||
DueFlashStorage::read(SoftwareResetData::nvAddress, &temp, sizeof(SoftwareResetData));
|
||||
if (temp.magic == SoftwareResetData::magicValue && temp.version == SoftwareResetData::versionValue)
|
||||
SoftwareResetData srdBuf[SoftwareResetData::numberOfSlots];
|
||||
memset(srdBuf, 0, sizeof(srdBuf));
|
||||
int slot = -1;
|
||||
|
||||
#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);
|
||||
MessageF(mtype, "Spinning module during software reset: %s\n", moduleName[temp.resetReason & 0x0F]);
|
||||
// Find the last slot written
|
||||
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
|
||||
|
||||
// Show current RTC time
|
||||
Message(mtype, "Current date and time: ");
|
||||
struct tm timeInfo;
|
||||
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_hour, timeInfo.tm_min, timeInfo.tm_sec);
|
||||
}
|
||||
else
|
||||
{
|
||||
Message(mtype, "clock not set\n");
|
||||
}
|
||||
|
||||
// Debug
|
||||
//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
|
||||
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 *)
|
||||
#ifdef DUET_NG
|
||||
0x20020000; // 0x20000000 + 128Kb
|
||||
const char * const ramend = (const char *)
|
||||
#if SAM4E
|
||||
IRAM_ADDR + IRAM_SIZE;
|
||||
#else
|
||||
0x20088000; // 0x20070000 + 96Kb
|
||||
IRAM0_ADDR + IRAM_SIZE;
|
||||
#endif
|
||||
register const char * stack_ptr asm ("sp");
|
||||
const char *heapend = sbrk(0);
|
||||
const char* stack_lwm = heapend;
|
||||
const char * const heapend = sbrk(0);
|
||||
const char * stack_lwm = heapend;
|
||||
while (stack_lwm < stack_ptr && *stack_lwm == memPattern)
|
||||
{
|
||||
++stack_lwm;
|
||||
}
|
||||
if (currentStack) { *currentStack = ramend - stack_ptr; }
|
||||
if (maxStack) { *maxStack = ramend - stack_lwm; }
|
||||
if (neverUsed) { *neverUsed = stack_lwm - heapend; }
|
||||
if (currentStack != nullptr) { *currentStack = ramend - stack_ptr; }
|
||||
if (maxStack != nullptr) { *maxStack = ramend - stack_lwm; }
|
||||
if (neverUsed != nullptr) { *neverUsed = stack_lwm - heapend; }
|
||||
}
|
||||
|
||||
void Platform::ClassReport(float &lastTime)
|
||||
|
@ -2541,11 +2596,11 @@ void Platform::SetBoardType(BoardType bt)
|
|||
#else
|
||||
// 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.
|
||||
// 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.
|
||||
pinMode(Dac0DigitalPin, INPUT_PULLUP);
|
||||
board = (digitalRead(Dac0DigitalPin)) ? BoardType::Duet_06 : BoardType::Duet_085;
|
||||
pinMode(Dac0DigitalPin, INPUT); // turn pullup off
|
||||
pinMode(Dac0DigitalPin, INPUT); // turn pullup off
|
||||
#endif
|
||||
}
|
||||
else
|
||||
|
@ -2628,6 +2683,9 @@ bool Platform::GetFirmwarePin(int logicalPin, PinAccess access, Pin& firmwarePin
|
|||
)
|
||||
{
|
||||
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
|
||||
|
|
|
@ -509,10 +509,6 @@ public:
|
|||
float Acceleration(size_t drive) const;
|
||||
const float* Accelerations() const;
|
||||
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;
|
||||
const float* MaxFeedrates() const;
|
||||
void SetMaxFeedrate(size_t drive, float value);
|
||||
|
@ -567,6 +563,8 @@ public:
|
|||
|
||||
void SetExtrusionAncilliaryPwmValue(float v);
|
||||
float GetExtrusionAncilliaryPwmValue() const;
|
||||
void SetExtrusionAncilliaryPwmFrequency(float f);
|
||||
float GetExtrusionAncilliaryPwmFrequency() const;
|
||||
bool SetExtrusionAncilliaryPwmPin(int logicalPin);
|
||||
int GetExtrusionAncilliaryPwmPin() const { return extrusionAncilliaryPwmLogicalPin; }
|
||||
void ExtrudeOn();
|
||||
|
@ -681,31 +679,41 @@ private:
|
|||
static float AdcReadingToPowerVoltage(uint16_t reading);
|
||||
#endif
|
||||
|
||||
// These are the structures used to hold out non-volatile data.
|
||||
// The SAM3X doesn't have EEPROM so we save the data to flash. This unfortunately means that it gets cleared
|
||||
// These are the structures used to hold our non-volatile data.
|
||||
// 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
|
||||
// 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.
|
||||
|
||||
//
|
||||
// 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
|
||||
{
|
||||
static const uint16_t magicValue = 0x7C5F; // value we use to recognise that all the flash data has been written
|
||||
static const uint16_t versionValue = 1; // increment this whenever this struct changes
|
||||
static const uint16_t versionValue = 2; // 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 size_t numberOfSlots = 8; // number of storage slots used to implement wear levelling
|
||||
|
||||
uint16_t magic;
|
||||
uint16_t version;
|
||||
|
||||
uint16_t magic; // the magic number, including the version
|
||||
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)
|
||||
size_t neverUsedRam; // the amount of never used RAM at the last abnormal software reset
|
||||
uint32_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
|
||||
{
|
||||
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 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 version;
|
||||
|
@ -742,7 +750,7 @@ private:
|
|||
uint32_t errorCodeBits;
|
||||
|
||||
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
|
||||
|
||||
|
@ -770,7 +778,6 @@ private:
|
|||
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
|
||||
float idleCurrentFactor;
|
||||
float maxAverageAcceleration;
|
||||
|
||||
#if defined(DUET_NG)
|
||||
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
|
||||
|
||||
float extrusionAncilliaryPwmValue;
|
||||
float extrusionAncilliaryPwmFrequency;
|
||||
int extrusionAncilliaryPwmLogicalPin;
|
||||
Pin extrusionAncilliaryPwmFirmwarePin;
|
||||
bool extrusionAncilliaryPwmInvert;
|
||||
|
@ -1125,6 +1133,16 @@ inline float Platform::GetExtrusionAncilliaryPwmValue() const
|
|||
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
|
||||
// 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.
|
||||
|
@ -1133,7 +1151,8 @@ inline void Platform::ExtrudeOn()
|
|||
{
|
||||
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)
|
||||
{
|
||||
WriteAnalog(extrusionAncilliaryPwmFirmwarePin, 0.0, DefaultPinWritePwmFreq);
|
||||
WriteAnalog(extrusionAncilliaryPwmFirmwarePin,
|
||||
(extrusionAncilliaryPwmInvert) ? 1.0 : 0.0, extrusionAncilliaryPwmFrequency);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
11
src/Tool.cpp
11
src/Tool.cpp
|
@ -306,15 +306,22 @@ void Tool::SetVariables(const float* standby, const float* active)
|
|||
else
|
||||
{
|
||||
const float temperatureLimit = reprap.GetHeat()->GetTemperatureLimit(heaters[heater]);
|
||||
const Tool * const currentTool = reprap.GetCurrentTool();
|
||||
if (active[heater] < temperatureLimit)
|
||||
{
|
||||
activeTemperatures[heater] = active[heater];
|
||||
reprap.GetHeat()->SetActiveTemperature(heaters[heater], activeTemperatures[heater]);
|
||||
if (currentTool == nullptr || currentTool == this)
|
||||
{
|
||||
reprap.GetHeat()->SetActiveTemperature(heaters[heater], activeTemperatures[heater]);
|
||||
}
|
||||
}
|
||||
if (standby[heater] < temperatureLimit)
|
||||
{
|
||||
standbyTemperatures[heater] = standby[heater];
|
||||
reprap.GetHeat()->SetStandbyTemperature(heaters[heater], standbyTemperatures[heater]);
|
||||
if (currentTool == nullptr || currentTool == this)
|
||||
{
|
||||
reprap.GetHeat()->SetStandbyTemperature(heaters[heater], standbyTemperatures[heater]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Reference in a new issue