Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Crocker <dcrocker@eschertech.com>2017-10-26 00:36:48 +0300
committerDavid Crocker <dcrocker@eschertech.com>2017-10-26 00:37:05 +0300
commitad73549a01954de291cea135cde2527d1883596e (patch)
tree0fcd0f7b05c9e40e986851c5f6455c0f1f589108 /src/Platform.cpp
parentdff15aadac70efe87d3ec952af8b6a3d9acbcf66 (diff)
Version 1.20beta2
New features: On SCARA printera arm position limits are applied as well as XY size limits Heater 0 values are sent to to PanelDue even if there is no heated bed When logging is enabled, log entries are now written for when the date/time/date is set When logging is enabled, "Maximum open file count exceeded" messages are logged Loss of power is now handled much faster. The print is paused in the middle of a move if necessary. The M991 parameters are changed to facilitate this. When resuming a print after loss of power, the head is now moved, sideways and finally down when restoring position Following a power failure, M916 can now be used to resume the print instead of using M98 Presurrect.g The heater control now switches to fast PID parameters when the temperature is within 3C of target, instead of within 1C The TMC2660 Stallguard detection and Coolstep parameters may now be configured using M915. Currently, no action os performed when a stall is signalled. If a heater fault occurs, the print is paused instead of cancelled All error messages relating to incorrect use of a G- or M-code now include the G- or M-number of the command that caused them Increased ADC oversample bits to 2 Duet WiFi: M122 diagnostics now include the wifi module sleep mode and additional network diagnostics You can now disable monitorng of TMC2660 drivers rthat are not in use by using parameter R-1 in the corresponding M569 command The M585 (probe tool) command is now implemented (thanks chrrishamm) If axis lengths are adjusted by probing, a subsequent M500 command saves them in config-override.g If tool offsets are adjusted by probing, a subsequent M500 command saves them in config-override.g The layer counting mechanism has been modified to better handle GCode files that use a different layer height when printing support Debug messages sent to the USB port are truncated or thrown away if a software watchdog reset is imminent XY speed limiting is now done separate for each kinematics, in particular for CoreXY printers Support for Polar kinematics has been added but not tested (see M669 command) The TMC2660 drivers are configured to detect short-to-ground conditions faster The parameters in rr_ http commands are now all order-independent Bug fixes An error in computing the time taken to execute moves that were not yet frozen caused the first movement on a SCARA printer following homing to be jerky An extra space in the output from the M114 command confused Printerface, causing it to print exception messages When tuning a heater, any previous maximum PWM that was set is now ignored
Diffstat (limited to 'src/Platform.cpp')
-rw-r--r--src/Platform.cpp533
1 files changed, 376 insertions, 157 deletions
diff --git a/src/Platform.cpp b/src/Platform.cpp
index d1b72425..b9a79ad4 100644
--- a/src/Platform.cpp
+++ b/src/Platform.cpp
@@ -31,14 +31,18 @@
#include "Scanner.h"
#include "Version.h"
#include "SoftTimer.h"
+#include "Logger.h"
#include "Libraries/Math/Isqrt.h"
#include "sam/drivers/tc/tc.h"
#include "sam/drivers/hsmci/hsmci.h"
#include "sd_mmc.h"
-#ifdef DUET_NG
+#if HAS_SMART_DRIVERS
# include "TMC2660.h"
+#endif
+
+#ifdef DUET_NG
# include "FirmwareUpdater.h"
#endif
@@ -52,7 +56,7 @@ extern "C" char *sbrk(int i);
# error Missing feature definition
#endif
-#ifdef DUET_NG
+#if HAS_VOLTAGE_MONITOR
inline constexpr float AdcReadingToPowerVoltage(uint16_t adcVal)
{
@@ -254,10 +258,12 @@ bool ZProbeParameters::WriteParameters(FileStore *f, unsigned int probeType) con
//*************************************************************************************************
// Platform class
+uint8_t Platform::softwareResetDebugInfo = 0; // extra info for debugging
+
Platform::Platform() :
- logger(nullptr), lastLogFlushTime(0), board(DEFAULT_BOARD_TYPE), active(false), errorCodeBits(0), lastFanCheckTime(0),
+ logger(nullptr), board(DEFAULT_BOARD_TYPE), active(false), errorCodeBits(0), lastFanCheckTime(0),
auxGCodeReply(nullptr), fileStructureInitialised(false), tickState(0), debugCode(0)
-#ifdef DUET_NG
+#if HAS_SMART_DRIVERS
, lastWarningMillis(0), nextDriveToPoll(0),
onBoardDriversFanRunning(false), offBoardDriversFanRunning(false), onBoardDriversFanStartMillis(0), offBoardDriversFanStartMillis(0)
#endif
@@ -411,6 +417,7 @@ void Platform::Init()
// AXES
ARRAY_INIT(axisMaxima, AXIS_MAXIMA);
ARRAY_INIT(axisMinima, AXIS_MINIMA);
+ axisMaximaProbed = axisMinimaProbed = 0;
idleCurrentFactor = DefaultIdleCurrentFactor;
@@ -436,7 +443,7 @@ void Platform::Init()
for (size_t drive = 0; drive < DRIVES; drive++)
{
- enableValues[drive] = false; // assume active low enable signal
+ enableValues[drive] = 0; // assume active low enable signal
directions[drive] = true; // drive moves forwards by default
// Map axes and extruders straight through
@@ -501,22 +508,23 @@ void Platform::Init()
switch (expansionBoard)
{
case ExpansionBoardType::DueX2:
- numTMC2660Drivers = 7;
+ numSmartDrivers = 7;
break;
case ExpansionBoardType::DueX5:
- numTMC2660Drivers = 10;
+ numSmartDrivers = 10;
break;
case ExpansionBoardType::none:
case ExpansionBoardType::DueX0:
default:
- numTMC2660Drivers = 5; // assume that additional drivers are dumb enable/step/dir ones
+ numSmartDrivers = 5; // assume that any additional drivers are dumb enable/step/dir ones
break;
}
DuetExpansion::AdditionalOutputInit();
// Initialise TMC2660 driver module
driversPowered = false;
- TMC2660::Init(ENABLE_PINS, numTMC2660Drivers);
+ SmartDrivers::Init(ENABLE_PINS, numSmartDrivers);
+ pauseOnStallDrivers = rehomeOnStallDrivers = 0;
// Set up the VSSA sense pin. Older Duet WiFis don't have it connected, so we enable the pulldown resistor to keep it inactive.
{
@@ -559,7 +567,13 @@ void Platform::Init()
{
if (heatOnPins[heater] != NoPin)
{
- pinMode(heatOnPins[heater], (HEAT_ON) ? OUTPUT_LOW : OUTPUT_HIGH);
+ pinMode(heatOnPins[heater],
+#if ACTIVE_LOW_HEAT_ON
+ OUTPUT_LOW
+#else
+ OUTPUT_HIGH
+#endif
+ );
}
AnalogChannelNumber chan = PinToAdcChannel(tempSensePins[heater]); // translate the Arduino Due Analog pin number to the SAM ADC channel number
pinMode(tempSensePins[heater], AIN);
@@ -611,10 +625,10 @@ void Platform::Init()
AnalogInEnableChannel(temperatureAdcChannel, true);
highestMcuTemperature = 0; // the highest output we have seen from the ADC filter
lowestMcuTemperature = 4095 * ThermistorAverageReadings; // the lowest output we have seen from the ADC filter
-#endif
mcuTemperatureAdjust = 0.0;
+#endif
-#ifdef DUET_NG
+#if HAS_VOLTAGE_MONITOR
// Power monitoring
vInMonitorAdcChannel = PinToAdcChannel(PowerMonitorVinDetectPin);
pinMode(PowerMonitorVinDetectPin, AIN);
@@ -1329,7 +1343,7 @@ void Platform::Spin()
for (;;) {}
}
-#ifdef DUET_NG
+#if HAS_SMART_DRIVERS
// Check whether the TMC drivers need to be initialised.
// The tick ISR also looks for over-voltage events, but it just disables the driver without changing driversPowerd or numOverVoltageEvents
if (driversPowered)
@@ -1347,44 +1361,46 @@ void Platform::Spin()
else
{
// Poll one TMC2660 for temperature warning or temperature shutdown
- const uint32_t stat = TMC2660::GetStatus(nextDriveToPoll);
- const uint16_t mask = 1 << nextDriveToPoll;
- if (stat & TMC_RR_OT)
- {
- temperatureShutdownDrivers |= mask;
- temperatureWarningDrivers &= ~mask; // no point in setting warning as well as error
- }
- else
+ if (enableValues[nextDriveToPoll] >= 0) // don't poll driver if it is flagged "no poll"
{
- temperatureShutdownDrivers &= ~mask;
- if (stat & TMC_RR_OTPW)
+ const uint32_t stat = SmartDrivers::GetStatus(nextDriveToPoll);
+ const DriversBitmap mask = MakeBitmap<DriversBitmap>(nextDriveToPoll);
+ if (stat & TMC_RR_OT)
{
- temperatureWarningDrivers |= mask;
+ temperatureShutdownDrivers |= mask;
+ temperatureWarningDrivers &= ~mask; // no point in setting warning as well as error
}
else
{
- temperatureWarningDrivers &= ~mask;
+ temperatureShutdownDrivers &= ~mask;
+ if (stat & TMC_RR_OTPW)
+ {
+ temperatureWarningDrivers |= mask;
+ }
+ else
+ {
+ temperatureWarningDrivers &= ~mask;
+ }
+ }
+ if (stat & TMC_RR_S2G)
+ {
+ shortToGroundDrivers |= mask;
+ }
+ else
+ {
+ shortToGroundDrivers &= ~mask;
+ }
+ if ((stat & (TMC_RR_OLA | TMC_RR_OLB)) != 0 && (stat & TMC_RR_STST) == 0)
+ {
+ openLoadDrivers |= mask;
+ }
+ else
+ {
+ openLoadDrivers &= ~mask;
}
}
- if (stat & TMC_RR_S2G)
- {
- shortToGroundDrivers |= mask;
- }
- else
- {
- shortToGroundDrivers &= ~mask;
- }
- if ((stat & (TMC_RR_OLA | TMC_RR_OLB)) != 0 && (stat & TMC_RR_STST) == 0)
- {
- openLoadDrivers |= mask;
- }
- else
- {
- openLoadDrivers &= ~mask;
- }
-
++nextDriveToPoll;
- if (nextDriveToPoll > numTMC2660Drivers)
+ if (nextDriveToPoll > numSmartDrivers)
{
nextDriveToPoll = 0;
}
@@ -1394,7 +1410,7 @@ void Platform::Spin()
{
driversPowered = true;
}
- TMC2660::SetDriversPowered(driversPowered);
+ SmartDrivers::SetDriversPowered(driversPowered);
#endif
const uint32_t now = millis();
@@ -1418,7 +1434,7 @@ void Platform::Spin()
fans[fan].Check();
}
-#ifdef DUET_NG
+#if HAS_SMART_DRIVERS
// Check whether it is time to report any faults (do this after checking fans in case driver cooling fans are turned on)
if (now - lastWarningMillis > MinimumWarningInterval)
{
@@ -1457,7 +1473,7 @@ void Platform::Spin()
#endif
}
-#ifdef DUET_NG
+#if HAS_VOLTAGE_MONITOR
// Check for auto-pause, shutdown or resume
if (autoSaveEnabled)
{
@@ -1473,7 +1489,7 @@ void Platform::Spin()
case AutoSaveState::normal:
if (currentVin < autoPauseReading)
{
- if (reprap.GetGCodes().AutoPause())
+ if (reprap.GetGCodes().LowVoltagePause())
{
autoSaveState = AutoSaveState::autoPaused;
}
@@ -1481,26 +1497,9 @@ void Platform::Spin()
break;
case AutoSaveState::autoPaused:
- if (currentVin < autoShutdownReading)
- {
- if (reprap.GetGCodes().AutoShutdown())
- {
- autoSaveState = AutoSaveState::autoShutdown;
- }
- }
- else if (currentVin >= autoResumeReading)
- {
- if (reprap.GetGCodes().AutoResume())
- {
- autoSaveState = AutoSaveState::normal;
- }
- }
- break;
-
- case AutoSaveState::autoShutdown:
if (currentVin >= autoResumeReading)
{
- if (reprap.GetGCodes().AutoResumeAfterShutdown())
+ if (reprap.GetGCodes().LowVoltageResume())
{
autoSaveState = AutoSaveState::normal;
}
@@ -1516,21 +1515,17 @@ void Platform::Spin()
// Flush the log file it it is time. This may take some time, so do it last.
if (logger != nullptr)
{
- if (now - lastLogFlushTime >= LogFlushInterval)
- {
- logger->Flush();
- lastLogFlushTime = now;
- }
+ logger->Flush();
}
ClassReport(longWait);
}
-#ifdef DUET_NG
+#if HAS_SMART_DRIVERS
// Report driver status conditions that require attention.
// Sets 'reported' if we reported anything, else leaves 'reported' alone.
-void Platform::ReportDrivers(uint16_t whichDrivers, const char* text, bool& reported)
+void Platform::ReportDrivers(DriversBitmap whichDrivers, const char* text, bool& reported)
{
if (whichDrivers != 0)
{
@@ -1548,36 +1543,35 @@ void Platform::ReportDrivers(uint16_t whichDrivers, const char* text, bool& repo
}
}
-// Configure auto save on power fail
-bool Platform::ConfigureAutoSave(GCodeBuffer& gb, StringRef& reply)
+#endif
+
+#if HAS_VOLTAGE_MONITOR
+
+void Platform::DisableAutoSave()
{
- bool seen = false;
- float autoSaveVoltages[3];
- if (gb.TryGetFloatArray('S', 3, autoSaveVoltages, reply, seen))
- {
- return true;
- }
+ autoSaveEnabled = false;
+}
- if (seen)
- {
- autoSaveEnabled = (autoSaveVoltages[0] >= 5.0 && autoSaveVoltages[1] > autoSaveVoltages[0] && autoSaveVoltages[2] > autoSaveVoltages[1]);
- if (autoSaveEnabled)
- {
- autoShutdownReading = PowerVoltageToAdcReading(autoSaveVoltages[0]);
- autoPauseReading = PowerVoltageToAdcReading(autoSaveVoltages[1]);
- autoResumeReading = PowerVoltageToAdcReading(autoSaveVoltages[2]);
- }
- }
- else if (!autoSaveEnabled)
- {
- reply.copy("Auto save is disabled");
- }
- else
+bool Platform::IsPowerOk() const
+{
+ return currentVin > autoPauseReading;
+}
+
+void Platform::EnableAutoSave(float saveVoltage, float resumeVoltage)
+{
+ autoPauseReading = PowerVoltageToAdcReading(saveVoltage);
+ autoResumeReading = PowerVoltageToAdcReading(resumeVoltage);
+ autoSaveEnabled = true;
+}
+
+bool Platform::GetAutoSaveSettings(float& saveVoltage, float&resumeVoltage)
+{
+ if (autoSaveEnabled)
{
- reply.printf(" Auto shutdown at %.1fV, save/pause at %.1fV, resume at %.1fV",
- (double)AdcReadingToPowerVoltage(autoShutdownReading), (double)AdcReadingToPowerVoltage(autoPauseReading), (double)AdcReadingToPowerVoltage(autoResumeReading));
+ saveVoltage = AdcReadingToPowerVoltage(autoPauseReading);
+ resumeVoltage = AdcReadingToPowerVoltage(autoResumeReading);
}
- return false;
+ return autoSaveEnabled;
}
#endif
@@ -1593,16 +1587,22 @@ bool Platform::WriteFanSettings(FileStore *f) const
return ok;
}
+#if HAS_CPU_TEMP_SENSOR
+
float Platform::AdcReadingToCpuTemperature(uint32_t adcVal) const
{
- float voltage = (float)adcVal * (3.3/(float)(4096 * ThermistorAverageReadings));
-#if SAM4E
+ const float voltage = (float)adcVal * (3.3/(float)(4096 * ThermistorAverageReadings));
+#if SAM4E || SAM4S
return (voltage - 1.44) * (1000.0/4.7) + 27.0 + mcuTemperatureAdjust; // accuracy at 27C is +/-13C
#elif SAM3XA
return (voltage - 0.8) * (1000.0/2.65) + 27.0 + mcuTemperatureAdjust; // accuracy at 27C is +/-45C
+#else
+# error undefined CPU temp conversion
#endif
}
+#endif
+
// Perform a software reset. 'stk' points to the program counter on the stack if the cause is an exception, otherwise it is nullptr.
void Platform::SoftwareReset(uint16_t reason, const uint32_t *stk)
{
@@ -1635,17 +1635,20 @@ void Platform::SoftwareReset(uint16_t reason, const uint32_t *stk)
reason |= (uint16_t)SoftwareResetReason::inAuxOutput; // if we are resetting because we are stuck in a Spin function, record whether we are trying to send to aux
}
}
- reason |= (uint16_t)reprap.GetSpinningModule();
+ reason |= (uint8_t)reprap.GetSpinningModule();
+ reason |= (softwareResetDebugInfo & 0x07) << 5;
// Record the reason for the software reset
// First find a free slot (wear levelling)
size_t slot = SoftwareResetData::numberOfSlots;
SoftwareResetData srdBuf[SoftwareResetData::numberOfSlots];
-#if SAM4E
+#if SAM4E || SAM4S
if (flash_read_user_signature(reinterpret_cast<uint32_t*>(srdBuf), sizeof(srdBuf)/sizeof(uint32_t)) == FLASH_RC_OK)
-#else
+#elif SAM3XA
DueFlashStorage::read(SoftwareResetData::nvAddress, srdBuf, sizeof(srdBuf));
+#else
+# error
#endif
{
while (slot != 0 && srdBuf[slot - 1].isVacant())
@@ -1657,7 +1660,7 @@ void Platform::SoftwareReset(uint16_t reason, const uint32_t *stk)
if (slot == SoftwareResetData::numberOfSlots)
{
// No free slots, so erase the area
-#if SAM4E
+#if SAM4E || SAM4S
flash_erase_user_signature();
#endif
memset(srdBuf, 0xFF, sizeof(srdBuf));
@@ -1680,7 +1683,7 @@ void Platform::SoftwareReset(uint16_t reason, const uint32_t *stk)
}
// Save diagnostics data to Flash
-#if SAM4E
+#if SAM4E || SAM4S
flash_write_user_signature(srdBuf, sizeof(srdBuf)/sizeof(uint32_t));
#else
DueFlashStorage::write(SoftwareResetData::nvAddress, srdBuf, sizeof(srdBuf));
@@ -1696,11 +1699,13 @@ void Platform::SoftwareReset(uint16_t reason, const uint32_t *stk)
// Interrupts
#if HAS_LWIP_NETWORKING
+
void NETWORK_TC_HANDLER()
{
tc_get_status(NETWORK_TC, NETWORK_TC_CHAN);
reprap.GetNetwork().Interrupt();
}
+
#endif
static void FanInterrupt(void*)
@@ -1720,7 +1725,7 @@ void Platform::InitialiseInterrupts()
// Set the tick interrupt to the highest priority. We need to to monitor the heaters and kick the watchdog.
NVIC_SetPriority(SysTick_IRQn, NvicPrioritySystick); // set priority for tick interrupts
-#if SAM4E
+#if SAM4E || SAM4S
NVIC_SetPriority(UART0_IRQn, NvicPriorityUart); // set priority for UART interrupt - must be higher than step interrupt
#else
NVIC_SetPriority(UART_IRQn, NvicPriorityUart); // set priority for UART interrupt - must be higher than step interrupt
@@ -1763,11 +1768,12 @@ void Platform::InitialiseInterrupts()
NVIC_SetPriority(PIOE_IRQn, NvicPriorityPins);
#endif
-#if SAM3XA
- NVIC_SetPriority(UOTGHS_IRQn, NvicPriorityUSB);
-#endif
-#if SAM4E
+#if SAM4E || SAM4S
NVIC_SetPriority(UDP_IRQn, NvicPriorityUSB);
+#elif SAM3XA
+ NVIC_SetPriority(UOTGHS_IRQn, NvicPriorityUSB);
+#else
+# error
#endif
NVIC_SetPriority(TWI1_IRQn, NvicPriorityTwi);
@@ -1804,7 +1810,7 @@ void Platform::Diagnostics(MessageType mtype)
MessageF(mtype, "%s version %s running on %s", FIRMWARE_NAME, VERSION, GetElectronicsString());
#ifdef DUET_NG
- const char* expansionName = DuetExpansion::GetExpansionBoardName();
+ const char* const expansionName = DuetExpansion::GetExpansionBoardName();
if (expansionName != nullptr)
{
MessageF(mtype, " + %s", expansionName);
@@ -1813,7 +1819,7 @@ void Platform::Diagnostics(MessageType mtype)
Message(mtype, "\n");
-#ifdef DUET_NG
+#if SAM4E || SAM4S
// Print the unique ID
{
uint32_t idBuf[5];
@@ -1883,7 +1889,7 @@ void Platform::Diagnostics(MessageType mtype)
// Print memory stats and error codes to USB and copy them to the current webserver reply
const char *ramstart =
-#if SAM4E
+#if SAM4E || SAM4S
(char *) 0x20000000;
#elif SAM3XA
(char *) 0x20070000;
@@ -1902,7 +1908,7 @@ void Platform::Diagnostics(MessageType mtype)
// Show the up time and reason for the last reset
const uint32_t now = (uint32_t)(millis64()/1000u); // get up time in seconds
const char* resetReasons[8] = { "power up", "backup", "watchdog", "software",
-#if SAM4E
+#if SAM4E || SAM4S
// On the SAM4E a watchdog reset may be reported as a user reset because of the capacitor on the NRST pin
"reset button or watchdog",
#else
@@ -1919,7 +1925,7 @@ void Platform::Diagnostics(MessageType mtype)
memset(srdBuf, 0, sizeof(srdBuf));
int slot = -1;
-#if SAM4E
+#if SAM4E || SAM4S
// Work around bug in ASF flash library: flash_read_user_signature calls a RAMFUNC without disabling interrupts first.
// This caused a crash (watchdog timeout) sometimes if we run M122 while a print is in progress
const irqflags_t flags = cpu_irq_save();
@@ -2002,7 +2008,7 @@ void Platform::Diagnostics(MessageType mtype)
lowestMcuTemperature = highestMcuTemperature = currentMcuTemperature;
#endif
-#ifdef DUET_NG
+#if HAS_VOLTAGE_MONITOR
// Show the supply voltage
MessageF(mtype, "Supply voltage: min %.1f, current %.1f, max %.1f, under voltage events: %" PRIu32 ", over voltage events: %" PRIu32 "\n",
(double)AdcReadingToPowerVoltage(lowestVin), (double)AdcReadingToPowerVoltage(currentVin), (double)AdcReadingToPowerVoltage(highestVin),
@@ -2016,9 +2022,9 @@ void Platform::Diagnostics(MessageType mtype)
MessageF(mtype, "Expansion motor(s) stall indication: %s\n", (stalled) ? "yes" : "no");
}
- for (size_t drive = 0; drive < numTMC2660Drivers; ++drive)
+ for (size_t drive = 0; drive < numSmartDrivers; ++drive)
{
- const uint32_t stat = TMC2660::GetStatus(drive);
+ const uint32_t stat = SmartDrivers::GetStatus(drive);
MessageF(mtype, "Driver %d:%s%s%s%s%s%s\n", drive,
(stat & TMC_RR_SG) ? " stalled" : "",
(stat & TMC_RR_OT) ? " temperature-shutdown!"
@@ -2097,10 +2103,12 @@ void Platform::DiagnosticTest(int d)
case (int)DiagnosticTestType::BusFault:
// Read from the "Undefined (Abort)" area
-#ifdef DUET_NG
+#if SAM4E || SAM4S
(void)RepRap::ReadDword(reinterpret_cast<const char*>(0x20800000));
-#else
+#elif SAM3XA
(void)RepRap::ReadDword(reinterpret_cast<const char*>(0x20200000));
+#else
+# error
#endif
break;
@@ -2168,7 +2176,8 @@ void Platform::ClassReport(uint32_t &lastTime)
}
}
-#ifdef DUET_NG
+#if HAS_SMART_DRIVERS
+
// This is called when a fan that monitors driver temperatures is turned on when it was off
void Platform::DriverCoolingFansOn(uint32_t driverChannelsMonitored)
{
@@ -2183,6 +2192,7 @@ void Platform::DriverCoolingFansOn(uint32_t driverChannelsMonitored)
offBoardDriversFanRunning = true;
}
}
+
#endif
// Power is a fraction in [0,1]
@@ -2191,7 +2201,13 @@ void Platform::SetHeater(size_t heater, float power)
if (heatOnPins[heater] != NoPin)
{
const uint16_t freq = (reprap.GetHeat().UseSlowPwm(heater)) ? SlowHeaterPwmFreq : NormalHeaterPwmFreq;
- IoPort::WriteAnalog(heatOnPins[heater], (HEAT_ON) ? power : 1.0 - power, freq);
+ const float pwm =
+#if ACTIVE_LOW_HEAT_ON
+ 1.0 - power;
+#else
+ power;
+#endif
+ IoPort::WriteAnalog(heatOnPins[heater], pwm, freq);
}
}
@@ -2277,10 +2293,20 @@ EndStopHit Platform::GetZProbeResult() const
: EndStopHit::noStop;
}
-// Write the Z probe parameters to file
-bool Platform::WriteZProbeParameters(FileStore *f) const
+// Write the platform parameters to file
+bool Platform::WritePlatformParameters(FileStore *f) const
{
- bool ok = f->Write("; Z probe parameters\n");
+ bool ok = WriteAxisLimits(f, axisMinimaProbed, axisMinima, 1);
+ if (ok)
+ {
+ ok = WriteAxisLimits(f, axisMaximaProbed, axisMaxima, 0);
+ }
+
+#if 0 // From version 1.20 we no longer write the Z probe parameters, but keep the code for now in case too many users complain
+ if (ok)
+ {
+ ok = f->Write("; Z probe parameters\n");
+ }
if (ok)
{
ok = irZProbeParameters.WriteParameters(f, 1);
@@ -2293,9 +2319,27 @@ bool Platform::WriteZProbeParameters(FileStore *f) const
{
ok = switchZProbeParameters.WriteParameters(f, 4);
}
+#endif
+
return ok;
}
+bool Platform::WriteAxisLimits(FileStore *f, AxesBitmap axesProbed, const float limits[MaxAxes], int sParam)
+{
+ if (axesProbed == 0)
+ {
+ return true;
+ }
+
+ scratchString.printf("M208 S%d", sParam);
+ for (size_t axis = 0; axis < MaxAxes && IsBitSet(axesProbed, axis); ++axis)
+ {
+ scratchString.catf(" %c%.2f", GCodes::axisLetters[axis], (double)limits[axis]);
+ }
+ scratchString.cat('\n');
+ return f->Write(scratchString.Pointer());
+}
+
// This is called from the step ISR as well as other places, so keep it fast
// If drive >= DRIVES then we are setting an individual motor direction
void Platform::SetDirection(size_t drive, bool direction)
@@ -2326,16 +2370,16 @@ void Platform::EnableDriver(size_t driver)
driverState[driver] = DriverStatus::enabled;
UpdateMotorCurrent(driver); // the current may have been reduced by the idle timeout
-#if defined(DUET_NG)
- if (driver < numTMC2660Drivers)
+#if HAS_SMART_DRIVERS
+ if (driver < numSmartDrivers)
{
- TMC2660::EnableDrive(driver, true);
+ SmartDrivers::EnableDrive(driver, true);
}
else
{
#endif
- digitalWrite(ENABLE_PINS[driver], enableValues[driver]);
-#if defined(DUET_NG)
+ digitalWrite(ENABLE_PINS[driver], enableValues[driver] > 0);
+#if HAS_SMART_DRIVERS
}
#endif
}
@@ -2346,16 +2390,16 @@ void Platform::DisableDriver(size_t driver)
{
if (driver < DRIVES)
{
-#if defined(DUET_NG)
- if (driver < numTMC2660Drivers)
+#if HAS_SMART_DRIVERS
+ if (driver < numSmartDrivers)
{
- TMC2660::EnableDrive(driver, false);
+ SmartDrivers::EnableDrive(driver, false);
}
else
{
#endif
- digitalWrite(ENABLE_PINS[driver], !enableValues[driver]);
-#if defined(DUET_NG)
+ digitalWrite(ENABLE_PINS[driver], enableValues[driver] <= 0);
+#if HAS_SMART_DRIVERS
}
#endif
driverState[driver] = DriverStatus::disabled;
@@ -2470,13 +2514,13 @@ void Platform::UpdateMotorCurrent(size_t driver)
current *= motorCurrentFraction[driver];
}
-#if defined(DUET_NG)
- if (driver < numTMC2660Drivers)
+#if HAS_SMART_DRIVERS
+ if (driver < numSmartDrivers)
{
- TMC2660::SetCurrent(driver, current);
+ SmartDrivers::SetCurrent(driver, current);
}
#elif defined (DUET_06_085)
- unsigned short pot = (unsigned short)((0.256*current*8.0*senseResistor + maxStepperDigipotVoltage/2)/maxStepperDigipotVoltage);
+ const uint16_t pot = (unsigned short)((0.256*current*8.0*senseResistor + maxStepperDigipotVoltage/2)/maxStepperDigipotVoltage);
if (driver < 4)
{
mcpDuet.setNonVolatileWiper(potWipes[driver], pot);
@@ -2555,10 +2599,10 @@ bool Platform::SetDriverMicrostepping(size_t driver, int microsteps, int mode)
{
if (driver < DRIVES)
{
-#if defined(DUET_NG)
- if (driver < numTMC2660Drivers)
+#if HAS_SMART_DRIVERS
+ if (driver < numSmartDrivers)
{
- return TMC2660::SetMicrostepping(driver, microsteps, mode);
+ return SmartDrivers::SetMicrostepping(driver, microsteps, mode);
}
else
{
@@ -2599,10 +2643,10 @@ bool Platform::SetMicrostepping(size_t drive, int microsteps, int mode)
// Get the microstepping for a driver
unsigned int Platform::GetDriverMicrostepping(size_t driver, int mode, bool& interpolation) const
{
-#if defined(DUET_NG)
- if (driver < numTMC2660Drivers)
+#if HAS_SMART_DRIVERS
+ if (driver < numSmartDrivers)
{
- return TMC2660::GetMicrostepping(driver, mode, interpolation);
+ return SmartDrivers::GetMicrostepping(driver, mode, interpolation);
}
// On-board drivers only support x16 microstepping without interpolation
interpolation = false;
@@ -2635,6 +2679,23 @@ unsigned int Platform::GetMicrostepping(size_t drive, int mode, bool& interpolat
}
}
+void Platform::SetEnableValue(size_t driver, int8_t eVal)
+{
+ enableValues[driver] = eVal;
+ DisableDriver(driver); // disable the drive, because the enable polarity may have been wrong before
+#if HAS_SMART_DRIVERS
+ if (eVal == -1)
+ {
+ // User has asked to disable status monitoring for this driver, so clear its error bits
+ DriversBitmap mask = ~MakeBitmap<DriversBitmap>(driver);
+ temperatureShutdownDrivers &= mask;
+ temperatureWarningDrivers &= mask;
+ shortToGroundDrivers &= mask;
+ openLoadDrivers &= mask;
+ }
+#endif
+}
+
void Platform::SetAxisDriversConfig(size_t drive, const AxisDriversConfig& config)
{
axisDrivers[drive] = config;
@@ -2914,9 +2975,16 @@ void Platform::RawMessage(MessageType type, const char *message)
if ((type & BlockingUsbMessage) != 0)
{
- // Debug messages in blocking mode - potentially DANGEROUS, use with care!
- SERIAL_MAIN_DEVICE.write(message);
- SERIAL_MAIN_DEVICE.flush();
+ // Debug output sends messages in blocking mode. We now give up sending if we are close to software watchdog timeout.
+ const char *p = message;
+ size_t len = strlen(p);
+ while (SERIAL_MAIN_DEVICE && len != 0 && !reprap.SpinTimeoutImminent())
+ {
+ const size_t written = SERIAL_MAIN_DEVICE.write(p, len);
+ len -= written;
+ p += written;
+ }
+ // We no longer flush afterwards
}
else if ((type & UsbMessage) != 0)
{
@@ -3153,7 +3221,7 @@ bool Platform::ConfigureLogging(GCodeBuffer& gb, StringRef& reply)
return false;
}
-// This is called form EmergencyStop. It closes the log file and stops logging.
+// This is called from EmergencyStop. It closes the log file and stops logging.
void Platform::StopLogging()
{
if (logger != nullptr)
@@ -3352,7 +3420,11 @@ bool Platform::GetFirmwarePin(LogicalPin logicalPin, PinAccess access, Pin& firm
if (!reprap.GetHeat().IsHeaterEnabled(logicalPin - Heater0LogicalPin))
{
firmwarePin = heatOnPins[logicalPin - Heater0LogicalPin];
- invert = !HEAT_ON;
+#if ACTIVE_LOW_HEAT_ON
+ invert = true;
+#else
+ invert = false;
+#endif
}
}
else if (logicalPin >= Fan0LogicalPin && logicalPin < Fan0LogicalPin + (int)NUM_FANS) // pins 20- correspond to fan channels
@@ -3497,6 +3569,25 @@ Pin Platform::GetEndstopPin(int endstop) const
return (endstop >= 0 && endstop < (int)ARRAY_SIZE(endStopPins)) ? endStopPins[endstop] : NoPin;
}
+// Axis limits
+void Platform::SetAxisMaximum(size_t axis, float value, bool byProbing)
+{
+ axisMaxima[axis] = value;
+ if (byProbing)
+ {
+ SetBit(axisMaximaProbed, axis);
+ }
+}
+
+void Platform::SetAxisMinimum(size_t axis, float value, bool byProbing)
+{
+ axisMinima[axis] = value;
+ if (byProbing)
+ {
+ SetBit(axisMinimaProbed, axis);
+ }
+}
+
#if SUPPORT_INKJET
// Fire the inkjet (if any) in the given pattern
@@ -3552,7 +3643,7 @@ void Platform::GetMcuTemperatures(float& minT, float& currT, float& maxT) const
}
#endif
-#ifdef DUET_NG
+#if HAS_VOLTAGE_MONITOR
// Power in voltage
void Platform::GetPowerVoltages(float& minV, float& currV, float& maxV) const
@@ -3562,6 +3653,10 @@ void Platform::GetPowerVoltages(float& minV, float& currV, float& maxV) const
maxV = AdcReadingToPowerVoltage(highestVin);
}
+#endif
+
+#if HAS_SMART_DRIVERS
+
// TMC driver temperatures
float Platform::GetTmcDriversTemperature(unsigned int board) const
{
@@ -3571,6 +3666,127 @@ float Platform::GetTmcDriversTemperature(unsigned int board) const
: 0.0;
}
+// Configure the motor stall detection, returning true if an error was encountered
+bool Platform::ConfigureStallDetection(GCodeBuffer& gb, StringRef& reply)
+{
+ // Build a bitmap of all the drivers referenced
+ // First looks for explicit driver numbers
+ DriversBitmap drivers = 0;
+ if (gb.Seen('P'))
+ {
+ long int drives[DRIVES];
+ size_t dCount = DRIVES;
+ gb.GetLongArray(drives, dCount);
+ for (size_t i = 0; i < dCount; i++)
+ {
+ if (drives[i] < 0 || (size_t)drives[i] >= DRIVES)
+ {
+ reply.printf("Invalid drive number '%ld'", drives[i]);
+ return true;
+ }
+ SetBit(drivers, i);
+ }
+ }
+
+ // Now look for axes
+ for (size_t i = 0; i < reprap.GetGCodes().GetTotalAxes(); ++i)
+ {
+ if (gb.Seen(GCodes::axisLetters[i]))
+ {
+ for (size_t j = 0; j < axisDrivers[i].numDrivers; ++j)
+ {
+ SetBit(drivers, axisDrivers[i].driverNumbers[j]);
+ }
+ }
+ }
+
+ // Now check for values to change
+ bool seen = false;
+ if (gb.Seen('S'))
+ {
+ seen = true;
+ const int sgThreshold = gb.GetIValue();
+ for (size_t drive = 0; drive < numSmartDrivers; ++drive)
+ {
+ if (IsBitSet(drivers, drive))
+ {
+ SmartDrivers::SetStallThreshold(drive, sgThreshold);
+ }
+ }
+ }
+ if (gb.Seen('F'))
+ {
+ seen = true;
+ const int sgFilter = (gb.GetIValue() == 1);
+ for (size_t drive = 0; drive < numSmartDrivers; ++drive)
+ {
+ if (IsBitSet(drivers, drive))
+ {
+ SmartDrivers::SetStallFilter(drive, sgFilter);
+ }
+ }
+ }
+ if (gb.Seen('T'))
+ {
+ seen = true;
+ const uint16_t coolStepConfig = (uint16_t)gb.GetUIValue();
+ for (size_t drive = 0; drive < numSmartDrivers; ++drive)
+ {
+ if (IsBitSet(drivers, drive))
+ {
+ SmartDrivers::SetCoolStep(drive, coolStepConfig);
+ }
+ }
+ }
+ if (gb.Seen('R'))
+ {
+ seen = true;
+ const int action = gb.GetIValue();
+ switch (action)
+ {
+ case 0:
+ default:
+ pauseOnStallDrivers &= ~drivers;
+ rehomeOnStallDrivers &= ~drivers;
+ break;
+
+ case 1:
+ rehomeOnStallDrivers &= ~drivers;
+ pauseOnStallDrivers |= drivers;
+ break;
+
+ case 2:
+ pauseOnStallDrivers &= ~drivers;
+ rehomeOnStallDrivers |= drivers;
+ break;
+ }
+ }
+
+ if (!seen)
+ {
+ if (drivers == 0)
+ {
+ drivers = LowestNBits<DriversBitmap>(numSmartDrivers);
+ }
+ bool printed = false;
+ for (size_t drive = 0; drive < numSmartDrivers; ++drive)
+ {
+ if (IsBitSet(drivers, drive))
+ {
+ if (printed)
+ {
+ reply.cat('\n');
+ }
+ reply.catf("Driver %u: ", drive);
+ SmartDrivers::AppendStallConfig(drive, reply);
+ printed = true;
+ }
+ }
+
+ }
+ return false;
+}
+
#endif
// Real-time clock
@@ -3591,8 +3807,11 @@ bool Platform::SetDateTime(time_t time)
const bool ok = (gmtime_r(&time, &brokenDateTime) != nullptr);
if (ok)
{
- Message(LogMessage, "Time and date set\n");
- realTime = time;
+ realTime = time; // set the date and time
+
+ // Write a log message, giving the time since power up in same format as the logger does
+ const uint32_t timeSincePowerUp = (uint32_t)(millis64()/1000u);
+ MessageF(LogMessage, "Date and time set at power up + %02" PRIu32 ":%02" PRIu32 ":%02" PRIu32 "\n", timeSincePowerUp/3600u, (timeSincePowerUp % 3600u)/60u, timeSincePowerUp % 60u);
timeLastUpdatedMillis = millis();
}
return ok;
@@ -3628,7 +3847,7 @@ void STEP_TC_HANDLER()
{
const irqflags_t flags = cpu_irq_save();
const int32_t diff = (int32_t)(tim - GetInterruptClocks()); // see how long we have to go
- if (diff < (int32_t)DDA::minInterruptInterval) // if less than about 2us or already passed
+ if (diff < (int32_t)DDA::minInterruptInterval) // if less than about 6us or already passed
{
cpu_irq_restore(flags);
return true; // tell the caller to simulate an interrupt instead
@@ -3661,7 +3880,7 @@ void STEP_TC_HANDLER()
{
const irqflags_t flags = cpu_irq_save();
const int32_t diff = (int32_t)(tim - GetInterruptClocks()); // see how long we have to go
- if (diff < (int32_t)DDA::minInterruptInterval) // if less than about 2us or already passed
+ if (diff < (int32_t)DDA::minInterruptInterval) // if less than about 6us or already passed
{
cpu_irq_restore(flags);
return true; // tell the caller to simulate an interrupt instead
@@ -3700,7 +3919,7 @@ void Platform::Tick()
{
if (tickState != 0)
{
-#ifdef DUET_NG
+#if HAS_VOLTAGE_MONITOR
// Read the power input voltage
currentVin = AnalogInReadChannel(vInMonitorAdcChannel);
if (currentVin > highestVin)
@@ -3713,7 +3932,7 @@ void Platform::Tick()
}
if (driversPowered && currentVin > driverOverVoltageAdcReading)
{
- TMC2660::SetDriversPowered(false);
+ SmartDrivers::SetDriversPowered(false);
// We deliberately do not clear driversPowered here or increase the over voltage event count - we let the spin loop handle that
}
#endif