diff options
author | David Crocker <dcrocker@eschertech.com> | 2018-12-15 14:47:19 +0300 |
---|---|---|
committer | David Crocker <dcrocker@eschertech.com> | 2018-12-15 14:47:19 +0300 |
commit | a25f8204d2fe36ad174b98dea673a114503cc457 (patch) | |
tree | 69c4bbd7abafb97a86a04705b80291875c62738a | |
parent | a15773859dabee6e88cce157f7c00d17e29171b4 (diff) |
Release 2.02RC62.02RC6
Fix for extruder movement less than 1 microstep
Fix for G30 on SCARA immediately after homing prox+distal arms
Fix babystepping move immediately after extruding move
Added nanoDLP compatibility option
Corrected PCCB pin assignments
G1 R moves never use machine coordinates
-rw-r--r-- | .cproject | 11 | ||||
-rw-r--r-- | src/Alligator/Microstepping.cpp | 8 | ||||
-rw-r--r-- | src/Alligator/Pins_Alligator.h | 24 | ||||
-rw-r--r-- | src/BugList.txt | 35 | ||||
-rw-r--r-- | src/Configuration.h | 8 | ||||
-rw-r--r-- | src/GCodes/GCodeMachineState.h | 2 | ||||
-rw-r--r-- | src/GCodes/GCodes.cpp | 233 | ||||
-rw-r--r-- | src/GCodes/GCodes.h | 17 | ||||
-rw-r--r-- | src/GCodes/GCodes2.cpp | 47 | ||||
-rw-r--r-- | src/GCodes/GCodes3.cpp | 44 | ||||
-rw-r--r-- | src/Movement/DDA.cpp | 67 | ||||
-rw-r--r-- | src/Movement/DDA.h | 5 | ||||
-rw-r--r-- | src/Movement/DriveMovement.cpp | 57 | ||||
-rw-r--r-- | src/Movement/DriveMovement.h | 2 | ||||
-rw-r--r-- | src/Movement/Kinematics/ScaraKinematics.cpp | 35 | ||||
-rw-r--r-- | src/Movement/Move.cpp | 48 | ||||
-rw-r--r-- | src/Movement/Move.h | 4 | ||||
-rw-r--r-- | src/Movement/StepTimer.cpp | 12 | ||||
-rw-r--r-- | src/Movement/StepTimer.h | 16 | ||||
-rw-r--r-- | src/ObjectModel/ObjectModel.cpp | 2 | ||||
-rw-r--r-- | src/Pccb/Pins_Pccb.h | 52 | ||||
-rw-r--r-- | src/Platform.cpp | 32 | ||||
-rw-r--r-- | src/Tasks.cpp | 2 | ||||
-rw-r--r-- | src/Version.h | 4 |
24 files changed, 424 insertions, 343 deletions
@@ -257,7 +257,7 @@ </extensions> </storageModule> <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <configuration artifactExtension="elf" artifactName="${ProjName}-Alligator" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.1745168887" name="Alligator" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin"> + <configuration artifactExtension="elf" artifactName="${ProjName}-Alligator" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.1745168887" name="Alligator" optionalBuildProperties="org.eclipse.cdt.docker.launcher.containerbuild.property.selectedvolumes=,org.eclipse.cdt.docker.launcher.containerbuild.property.volumes=" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin"> <folderInfo id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.1745168887." name="/" resourcePath=""> <toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.release.623324432" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.release"> <option id="cdt.managedbuild.option.gnu.cross.path.645044151" name="Path" superClass="cdt.managedbuild.option.gnu.cross.path" useByScannerDiscovery="false" value="${GccPath}" valueType="string"/> @@ -302,9 +302,11 @@ <option id="gnu.cpp.link.option.nostdlibs.760089516" name="No startup or default libs (-nostdlib)" superClass="gnu.cpp.link.option.nostdlibs" useByScannerDiscovery="false" value="false" valueType="boolean"/> <option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="gnu.cpp.link.option.paths.1593340130" name="Library search path (-L)" superClass="gnu.cpp.link.option.paths" useByScannerDiscovery="false" valueType="libPaths"> <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/Alligator/}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/RRFLibraries/SAM3X}""/> </option> <option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="gnu.cpp.link.option.libs.1260510068" name="Libraries (-l)" superClass="gnu.cpp.link.option.libs" useByScannerDiscovery="false" valueType="libs"> <listOptionValue builtIn="false" value="${CoreName}"/> + <listOptionValue builtIn="false" value="RRFLibraries"/> </option> <option id="gnu.cpp.link.option.flags.1376831701" name="Linker flags" superClass="gnu.cpp.link.option.flags" useByScannerDiscovery="false" value="-Os -Wl,--gc-sections -Wl,--fatal-warnings -mcpu=cortex-m3 -T"${workspace_loc:/${CoreName}/variants/alligator/linker_scripts/gcc/flash.ld" -Wl,-Map,"${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.map"" valueType="string"/> <inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1951368129" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input"> @@ -339,6 +341,7 @@ <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/src/Duet}""/> <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/src/Duet/Lwip}""/> <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/src/Duet/EMAC}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/RRFLibraries/src}""/> </option> <option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="gnu.cpp.compiler.option.preprocessor.def.890621467" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" useByScannerDiscovery="false" valueType="definedSymbols"> <listOptionValue builtIn="false" value="__SAM3X8E__"/> @@ -378,7 +381,7 @@ </extensions> </storageModule> <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <configuration artifactExtension="elf" artifactName="Duet2CombinedFirmware" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622" name="Duet2_RTOS" optionalBuildProperties="org.eclipse.cdt.docker.launcher.containerbuild.property.volumes=,org.eclipse.cdt.docker.launcher.containerbuild.property.selectedvolumes=" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin"> + <configuration artifactExtension="elf" artifactName="Duet2CombinedFirmware" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622" name="Duet2_RTOS" optionalBuildProperties="org.eclipse.cdt.docker.launcher.containerbuild.property.selectedvolumes=,org.eclipse.cdt.docker.launcher.containerbuild.property.volumes=" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin"> <folderInfo id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622." name="/" resourcePath=""> <toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.release.435431950" name="Cross GCC" nonInternalBuilderId="cdt.managedbuild.builder.gnu.cross" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.release"> <option id="cdt.managedbuild.option.gnu.cross.path.1881231799" name="Path" superClass="cdt.managedbuild.option.gnu.cross.path" useByScannerDiscovery="false" value="${GccPath}" valueType="string"/> @@ -763,7 +766,7 @@ </extensions> </storageModule> <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <configuration artifactExtension="elf" artifactName="PccbFirmware" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786.1798324396" name="PCCB" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin"> + <configuration artifactExtension="elf" artifactName="PccbFirmware" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786.1798324396" name="PCCB" optionalBuildProperties="" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin"> <folderInfo id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786.1798324396." name="/" resourcePath=""> <toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.release.1017317107" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.release"> <option id="cdt.managedbuild.option.gnu.cross.path.1932906636" name="Path" superClass="cdt.managedbuild.option.gnu.cross.path" useByScannerDiscovery="false" value="${GccPath}" valueType="string"/> @@ -885,7 +888,7 @@ </extensions> </storageModule> <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <configuration artifactExtension="elf" artifactName="PccbFirmware_X5" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786.1798324396.239853003" name="PCCB_X5" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin"> + <configuration artifactExtension="elf" artifactName="PccbFirmware_X5" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786.1798324396.239853003" name="PCCB_X5" optionalBuildProperties="" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin"> <folderInfo id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786.1798324396.239853003." name="/" resourcePath=""> <toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.release.2113529528" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.release"> <option id="cdt.managedbuild.option.gnu.cross.path.1216992967" name="Path" superClass="cdt.managedbuild.option.gnu.cross.path" useByScannerDiscovery="false" value="${GccPath}" valueType="string"/> diff --git a/src/Alligator/Microstepping.cpp b/src/Alligator/Microstepping.cpp index baf62efc..af83e759 100644 --- a/src/Alligator/Microstepping.cpp +++ b/src/Alligator/Microstepping.cpp @@ -11,7 +11,7 @@ //*************************************************************************************************** // Alligator Microstepping static class -uint8_t microsteppingPins[ DRIVES - MinAxes ]; +uint8_t microsteppingPins[ NumDirectDrivers - MinAxes ]; void Microstepping::Init() { @@ -19,7 +19,7 @@ void Microstepping::Init() { static_assert(sizeof(microsteppingPins) == sizeof(MICROSTEPPING_PINS), "Incompatible array types"); memcpy(microsteppingPins, MICROSTEPPING_PINS, sizeof(MICROSTEPPING_PINS)); - for(uint8_t pin=0; pin < (DRIVES-MinAxes); pin++ ) { + for(uint8_t pin=0; pin < (NumDirectDrivers - MinAxes); pin++ ) { pinMode( microsteppingPins[pin], OUTPUT_HIGH); } } @@ -27,7 +27,7 @@ void Microstepping::Init() { bool Microstepping::Set(uint8_t drive, uint8_t value) { // Do not exceed the maximum value - if ( drive >= (DRIVES - MinAxes) ) + if ( drive >= (NumDirectDrivers - MinAxes) ) { return false; } @@ -45,7 +45,7 @@ bool Microstepping::Set(uint8_t drive, uint8_t value) { uint8_t Microstepping::Read( uint8_t drive ) { // Do not exceed the maximum value - if ( drive < (DRIVES - MinAxes) ) + if ( drive < (NumDirectDrivers - MinAxes) ) { return ( digitalRead(microsteppingPins[drive]) == LOW ? 16 : 32 ); } diff --git a/src/Alligator/Pins_Alligator.h b/src/Alligator/Pins_Alligator.h index 6cdc61ce..859efd6b 100644 --- a/src/Alligator/Pins_Alligator.h +++ b/src/Alligator/Pins_Alligator.h @@ -27,11 +27,10 @@ const size_t NumFirmwareUpdateModules = 1; // The physical capabilities of the machine // Alligator + Piggy module max 7 stepper driver -const size_t DRIVES = 7; // The number of drives in the machine, including X, Y, and Z plus extruder drives -#define DRIVES_(a,b,c,d,e,f,g,h,i,j,k,l) { a,b,c,d,e,f,g } -const size_t MaxDriversPerAxis = 4; // The maximum number of stepper drivers assigned to one axis -// Initialization macro used in statements needing to initialize values in arrays of size MAX_AXES -#define AXES_(a,b,c,d,e,f,g,h,i) { a,b,c,d,e,f } +constexpr size_t NumDirectDrivers = 7; // The number of drives in the machine, including X, Y, and Z plus extruder drives +constexpr size_t MaxTotalDrivers = NumDirectDrivers; + +constexpr size_t MaxDriversPerAxis = 4; // The maximum number of stepper drivers assigned to one axis constexpr size_t NumEndstops = 6; // The number of inputs we have for endstops, filament sensors etc. // Alligator + Piggy module max 5 heaters @@ -42,21 +41,22 @@ constexpr size_t NumThermistorInputs = 5; constexpr size_t MaxAxes = 7; // The maximum number of movement axes in the machine, usually just X, Y and Z, <= DRIVES constexpr size_t MinAxes = 3; // The minimum and default number of axes -constexpr size_t MaxExtruders = DRIVES - MinAxes; // The maximum number of extruders +constexpr size_t MaxExtruders = NumDirectDrivers - MinAxes; // The maximum number of extruders constexpr size_t NUM_SERIAL_CHANNELS = 3; // The number of serial IO channels (USB and two auxiliary UARTs) #define SERIAL_MAIN_DEVICE SerialUSB #define SERIAL_AUX_DEVICE Serial #define SERIAL_AUX2_DEVICE Serial1 -// The numbers of entries in each array must correspond with the values of DRIVES, AXES, or HEATERS. Set values to NoPin to flag unavailability. -// DRIVES -const Pin ENABLE_PINS[DRIVES] = { 24, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin }; -const Pin STEP_PINS[DRIVES] = { X16, X14, X1, 5, 28, 11, X9 }; -const Pin DIRECTION_PINS[DRIVES] = { 2, 78, X13, 4, 27, 29, 12}; +constexpr Pin UsbVBusPin = NoPin; // Pin used to monitor VBUS on USB port. Not needed for SAM3X. + +// The numbers of entries in each array must correspond with the values of NumDirectDrivers, MaxAxes, or NumHeaters. Set values to NoPin to flag unavailability. +const Pin ENABLE_PINS[NumDirectDrivers] = { 24, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin }; +const Pin STEP_PINS[NumDirectDrivers] = { X16, X14, X1, 5, 28, 11, X9 }; +const Pin DIRECTION_PINS[NumDirectDrivers] = { 2, 78, X13, 4, 27, 29, 12}; // MICROSTEPPING Pins -const Pin MICROSTEPPING_PINS[DRIVES - MinAxes] = { X12, X10, 44, 45 }; +const Pin MICROSTEPPING_PINS[NumDirectDrivers - MinAxes] = { X12, X10, 44, 45 }; // Motor FAULT Pin const Pin MotorFaultDetectPin = 22; diff --git a/src/BugList.txt b/src/BugList.txt index 4d01c50d..5a6b2eaa 100644 --- a/src/BugList.txt +++ b/src/BugList.txt @@ -167,7 +167,7 @@ To be investigated for 2.02RC5 or release: - [probing speed was too high] Multiple G29 commands in succession, https://forum.duet3d.com/topic/7920/bed-compensation-g29-problems - [may be fixed by possible fix for for Z and U moving at different speeds] investigate slow movement, https://forum.duet3d.com/topic/6974/problem-with-3-independent-z-axis-motors-and-endstops/32 -To be fixed in 2.02RC5: +Fixed in 2.02RC5: - [done, ok] 12864 display of speed factor wrong, https://forum.duet3d.com/topic/7747/reprapfirmware-2-02rc4-released/10 - [done, ok] 12864 button menu handling wrong, https://forum.duet3d.com/topic/7747/reprapfirmware-2-02rc4-released/14 - [done, ok] 12864 items 510- display user position not machine position @@ -184,14 +184,41 @@ To be fixed in 2.02RC5: - [done, ok] M106 Pnn Svv always set full PWM if vv > 1 and there were additional parameters e.g. F, https://forum.duet3d.com/topic/7810/question-about-m106/6 - [done] Possible fix for Z and U moving at different speeds, https://forum.duet3d.com/topic/7755/drive-3-is-slower-as-drive-2-at-homing-in-z-solved/32 - [done, ok] For SimpleFilamentMonitor, include filament present/not present status in M591 report -- [done, ok] Heater turn on momentarily when Duet is reset +- [done, ok] Heaters turn on momentarily when Duet is reset - [done, ok] When G53 is in effect, don't apply tool offsets or axis mapping -- [done, ok] Don't alow both S0 and T0 in M291, it creates a message that can't be dismissed +- [done, ok] Don't allow both S0 and T0 in M291, it creates a message that can't be dismissed + +To be fixed in 2.02RC6: +- [done] When VIN power comes up (again), clear out open-load status bits to avoid spurious open load warnings +- [done, ok] Fix behaviour when extrusion per move is < 1 step, https://forum.duet3d.com/topic/7949/my-experience-with-relative-extrusion-problem-and-solution/13 +- [still can't reproduce] Investigate macro using M291 again, https://forum.duet3d.com/topic/7782/issues-with-macros-halting-the-printer/26 +- [done, ok] 12864 fallback: if 'menu' action is used with no parameter, use the F parameter +- [done, ok] Different U and Z homing speeds is back and worse, https://forum.duet3d.com/topic/7755/drive-3-is-slower-as-drive-2-at-homing-in-z-solved/30 +- [done, ok] A baby stepping move after an extruding move when the printer is idle replicates the same extrusion, https://forum.duet3d.com/topic/7940/firmware-2-02rc5-now-available +- [done, test] Suppress motor disconnected message if motor current is very low, https://forum.duet3d.com/topic/7994/possible-bug/4 +- [done, ok] When entering a subfolder on the 12864 display from a file list, the screen does not update until you rotate the encoder, https://forum.duet3d.com/topic/8014/12864-display-sd-print-subfolder-screen-update +- [done, ok] Add date/time if known to config-override.g +- [done, ok] Resume after pause doesn't use workplace coordinate offsets, https://forum.duet3d.com/topic/4557/cnc-coordinate-systems/29 and https://forum.duet3d.com/topic/7940/firmware-2-02rc5-now-available/16 +- [done, ok] Add nanoDLP to compatibility options, also add M650 and M651 support +- [done] Return a 503 http error when we run out of buffers while trying to compose a http reply +- [done] M206 now sets offsets for the current workplace, not workplace 0 +- [done] memory for 12864 display and menu system is not allocated until M918 is processed +- [done, test] scheduled vs. completed move count wrong, https://forum.duet3d.com/topic/8052/print-stopped-at-83-for-seemingly-no-reason/2 +- [done, ok] G2/G3 moves use a variable arg segment length +- [done, ok] Add sin + cosine calculation time +- [done, ok] New version of FatFS +- [done, ok] Allow M226 and M600 even when no file is being printed +- [done, test] Print progress based on requested extrusion *before* mixing, for ditto printing +- [done, ok] G30 after SCARA homing prox and distal sometimes failed due to rounding error in arm calculation, https://forum.duet3d.com/post/72199 Future: +- Run script if thermal error? https://forum.duet3d.com/topic/8038/suggestion-run-script-in-case-of-thermal-error +- Run script on filament error? +- In CNC mode, allow Fanuc-style X and/or Y coordinates without repeating the G0 or G1 command - Option for an endstop input to trigger an emergency pause +- Count steps until homing switch is triggered compared to original, https://forum.duet3d.com/topic/8017/request-check-for-lost-steps - In CNC or laser mode, don't segment G0 moves for mesh bed compensation, https://forum.duet3d.com/topic/7728/go-vs-g1-movement/11 -- Z homing switch offset in M208 or elswhere, https://forum.duet3d.com/topic/7767/z-offset-is-negated-in-homing-g-macro +- Z homing switch offset in M208 or elsewhere, https://forum.duet3d.com/topic/7767/z-offset-is-negated-in-homing-g-macro - After looking for G1 Z commands in gcode file analyser, check that there is extrusion after it - M260 allow bytes to be specified in hex, more generally allow hex anywhere? - Auto mount SD card when it is inserted diff --git a/src/Configuration.h b/src/Configuration.h index a0285afd..7dcde5b7 100644 --- a/src/Configuration.h +++ b/src/Configuration.h @@ -47,6 +47,11 @@ constexpr float DefaultXYInstantDv = 15.0; // mm/sec constexpr float DefaultZInstantDv = 0.2; constexpr float DefaultEInstantDv = 2.0; +constexpr float DefaultAxisMinimum = 0.0; +constexpr float DefaultAxisMaximum = 200.0; + +constexpr float MinimumOpenLoadMotorCurrent = 300; // minimum current in mA for the open load status to be taken seriously + // Timeouts constexpr uint32_t FanCheckInterval = 500; // Milliseconds constexpr uint32_t OpenLoadTimeout = 500; // Milliseconds @@ -205,7 +210,7 @@ constexpr int DefaultZProbeADValue = 500; // Default trigger threshold constexpr float TRIANGLE_ZERO = -0.001; // Millimetres constexpr float SILLY_Z_VALUE = -9999.0; // Millimetres -// String lengths. Try not to have too many different ones. +// String lengths. Try not to have too many different ones, because each one causes an instantiation of the String template constexpr size_t MaxMessageLength = 256; constexpr size_t MaxTitleLength = 61; @@ -221,6 +226,7 @@ constexpr size_t MaxHeaterNameLength = 20; // Maximum number of characters in constexpr size_t MaxFanNameLength = 20; // Maximum number of characters in a fan name constexpr size_t FormatStringLength = 256; +constexpr size_t GCodeReplyLength = 256; // Maximum number of characters in a GCode reply that doesn't use an OutputBuffer constexpr size_t MachineNameLength = 40; constexpr size_t RepRapPasswordLength = 20; constexpr size_t MediumStringLength = MaxFilenameLength; diff --git a/src/GCodes/GCodeMachineState.h b/src/GCodes/GCodeMachineState.h index 7e015aea..443a5e2f 100644 --- a/src/GCodes/GCodeMachineState.h +++ b/src/GCodes/GCodeMachineState.h @@ -120,7 +120,7 @@ public: post(!result.IsLive(); result.state == GCodeState::normal); // Return true if the G54 command is in effect - bool UsingG54() const { return useMachineCoordinates || useMachineCoordinatesSticky; } + bool UsingMachineCoordinates() const { return useMachineCoordinates || useMachineCoordinatesSticky; } // Copy values that may have been altered by config.g into this state record void CopyStateFrom(const GCodeMachineState& other) diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp index 38590f75..7857d44a 100644 --- a/src/GCodes/GCodes.cpp +++ b/src/GCodes/GCodes.cpp @@ -44,21 +44,6 @@ # include "Fans/DotStarLed.h" #endif -const size_t gcodeReplyLength = 2048; // long enough to pass back a reasonable number of files in response to M20 - -// Set up some default values for special moves, e.g. for Z probing and firmware retraction -void GCodes::RawMove::SetDefaults() -{ - moveType = 0; - isCoordinated = false; - usingStandardFeedrate = false; - usePressureAdvance = false; - endStopsToCheck = 0; - filePos = noFilePosition; - xAxes = DefaultXAxisMapping; - yAxes = DefaultYAxisMapping; -} - #if SUPPORT_OBJECT_MODEL // Object model table and functions @@ -146,11 +131,10 @@ void GCodes::Init() Reset(); distanceScale = 1.0; - arcSegmentLength = DefaultArcSegmentLength; virtualExtruderPosition = rawExtruderTotal = 0.0; - for (size_t extruder = 0; extruder < MaxExtruders; extruder++) + for (float& f : rawExtruderTotalByDrive) { - rawExtruderTotalByDrive[extruder] = 0.0; + f = 0.0; } runningConfigFile = false; @@ -160,9 +144,9 @@ void GCodes::Init() limitAxes = noMovesBeforeHoming = true; SetAllAxesNotHomed(); - for (size_t i = 0; i < NUM_FANS; ++i) + for (float& f : pausedFanSpeeds) { - pausedFanSpeeds[i] = 0.0; + f = 0.0; } lastDefaultFanSpeed = pausedDefaultFanSpeed = 0.0; @@ -237,9 +221,9 @@ void GCodes::Reset() currentCoordinateSystem = 0; #endif - for (size_t i = 0; i < MaxTotalDrivers; ++i) + for (float& f : moveBuffer.coords) { - moveBuffer.coords[i] = 0.0; // clear out all axis and extruder coordinates + f = 0.0; // clear out all axis and extruder coordinates } ClearMove(); @@ -287,17 +271,17 @@ void GCodes::Reset() codeQueue->Clear(); cancelWait = isWaiting = displayNoToolWarning = false; - for (size_t i = 0; i < NumResources; ++i) + for (const GCodeBuffer*& gbp : resourceOwners) { - resourceOwners[i] = nullptr; + gbp = nullptr; } } bool GCodes::DoingFileMacro() const { - for (const GCodeBuffer *gb : gcodeSources) + for (const GCodeBuffer *gbp : gcodeSources) { - if (gb != nullptr && gb->IsDoingFileMacro()) + if (gbp != nullptr && gbp->IsDoingFileMacro()) { return true; } @@ -408,7 +392,7 @@ void GCodes::Spin() GCodeBuffer& gb = *gbp; // Set up a buffer for the reply - String<gcodeReplyLength> reply; + String<GCodeReplyLength> reply; if (gb.GetState() == GCodeState::normal) { @@ -481,6 +465,11 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) } } } + + if (platform.Emulating() == Compatibility::nanoDLP && &gb == serialGCode && !DoingFileMacro()) + { + reply.copy("Z_move_comp"); + } gb.SetState(GCodeState::normal); } break; @@ -526,7 +515,8 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) // went (i.e. the difference between our start and end positions) and if we need to // incorporate any correction factors. That's why we only need to set the final tool // offset to this value in order to finish the tool probing. - currentTool->SetOffset(axis, (toolChangeRestorePoint.moveCoords[axis] - currentUserPosition[axis]) + gb.GetFValue(), true); + const float coord = toolChangeRestorePoint.moveCoords[axis] - currentUserPosition[axis] + gb.GetFValue(); + currentTool->SetOffset(axis, coord, true); break; } } @@ -542,7 +532,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) } else { - String<PASSWORD_LENGTH> nextHomingFileName; + String<RepRapPasswordLength> nextHomingFileName; AxesBitmap mustHomeFirst = reprap.GetMove().GetKinematics().GetHomingFileName(toBeHomed, axesHomed, numVisibleAxes, nextHomingFileName.GetRef()); if (mustHomeFirst != 0) { @@ -590,8 +580,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) case GCodeState::m109ToolChange0: // Run tfree for the old tool (if any) doingToolChange = true; SaveFanSpeeds(); - memcpy(toolChangeRestorePoint.moveCoords, currentUserPosition, MaxAxes * sizeof(currentUserPosition[0])); - toolChangeRestorePoint.feedRate = gb.MachineState().feedRate; + SavePosition(toolChangeRestorePoint, gb); gb.AdvanceState(); if ((gb.MachineState().toolChangeParam & TFreeBit) != 0) { @@ -725,16 +714,12 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) if (LockMovementAndWaitForStandstill(gb)) { float currentZ = moveBuffer.coords[Z_AXIS]; - for (size_t drive = 0; drive < numVisibleAxes; ++drive) + for (size_t axis = 0; axis < numVisibleAxes; ++axis) { - currentUserPosition[drive] = pauseRestorePoint.moveCoords[drive]; + currentUserPosition[axis] = pauseRestorePoint.moveCoords[axis]; } ToolOffsetTransform(currentUserPosition, moveBuffer.coords); - for (size_t drive = numTotalAxes; drive < MaxTotalDrivers; ++drive) - { - moveBuffer.coords[drive] = 0.0; - } - moveBuffer.SetDefaults(); + SetMoveBufferDefaults(); moveBuffer.feedRate = DefaultFeedRate * SecondsToMinutes; // ask for a good feed rate, we may have paused during a slow move if (gb.GetState() == GCodeState::resuming1 && currentZ > pauseRestorePoint.moveCoords[Z_AXIS]) { @@ -847,7 +832,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) { if (move.IsAccessibleProbePoint(x, y)) { - moveBuffer.SetDefaults(); + SetMoveBufferDefaults(); moveBuffer.coords[X_AXIS] = x - platform.GetCurrentZProbeParameters().xOffset; moveBuffer.coords[Y_AXIS] = y - platform.GetCurrentZProbeParameters().yOffset; moveBuffer.coords[Z_AXIS] = platform.GetZProbeStartingHeight(); @@ -924,7 +909,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) { zProbeTriggered = false; platform.SetProbing(true); - moveBuffer.SetDefaults(); + SetMoveBufferDefaults(); moveBuffer.endStopsToCheck = ZProbeActive; moveBuffer.coords[Z_AXIS] = -platform.GetZProbeDiveHeight(); moveBuffer.feedRate = platform.GetCurrentZProbeParameters().probeSpeed; @@ -973,7 +958,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) case GCodeState::gridProbing4a: // ready to lift the probe after probing the current grid probe point // Move back up to the dive height - moveBuffer.SetDefaults(); + SetMoveBufferDefaults(); moveBuffer.coords[Z_AXIS] = platform.GetZProbeStartingHeight(); moveBuffer.feedRate = platform.GetZProbeTravelSpeed(); NewMoveAvailable(1); @@ -1103,7 +1088,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) // States used for G30 probing case GCodeState::probingAtPoint0: // Initial state when executing G30 with a P parameter. Start by moving to the dive height at the current position. - moveBuffer.SetDefaults(); + SetMoveBufferDefaults(); moveBuffer.coords[Z_AXIS] = platform.GetZProbeStartingHeight(); moveBuffer.feedRate = platform.GetZProbeTravelSpeed(); NewMoveAvailable(1); @@ -1114,9 +1099,8 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) // The move to raise/lower the head to the correct dive height has been commanded. if (LockMovementAndWaitForStandstill(gb)) { - // Head is at the dive height but needs to be moved to the correct XY position. - // The XY coordinates have already been stored. - moveBuffer.SetDefaults(); + // Head is at the dive height but needs to be moved to the correct XY position. The XY coordinates have already been stored. + SetMoveBufferDefaults(); (void)reprap.GetMove().GetProbeCoordinates(g30ProbePointIndex, moveBuffer.coords[X_AXIS], moveBuffer.coords[Y_AXIS], true); moveBuffer.coords[Z_AXIS] = platform.GetZProbeStartingHeight(); moveBuffer.feedRate = platform.GetZProbeTravelSpeed(); @@ -1186,7 +1170,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) { zProbeTriggered = false; platform.SetProbing(true); - moveBuffer.SetDefaults(); + SetMoveBufferDefaults(); moveBuffer.endStopsToCheck = ZProbeActive; moveBuffer.coords[Z_AXIS] = (GetAxisIsHomed(Z_AXIS)) ? -platform.GetZProbeDiveHeight() // Z axis has been homed, so no point in going very far @@ -1267,7 +1251,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) case GCodeState::probingAtPoint4a: // Move back up to the dive height before we change anything, in particular before we adjust leadscrews - moveBuffer.SetDefaults(); + SetMoveBufferDefaults(); moveBuffer.coords[Z_AXIS] = platform.GetZProbeStartingHeight(); moveBuffer.feedRate = platform.GetZProbeTravelSpeed(); NewMoveAvailable(1); @@ -1387,12 +1371,8 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) const AxesBitmap xAxes = reprap.GetCurrentXAxes(); const AxesBitmap yAxes = reprap.GetCurrentYAxes(); reprap.GetMove().GetCurrentUserPosition(moveBuffer.coords, 0, xAxes, yAxes); + SetMoveBufferDefaults(); moveBuffer.coords[Z_AXIS] += retractHop; - for (size_t i = numTotalAxes; i < MaxTotalDrivers; ++i) - { - moveBuffer.coords[i] = 0.0; - } - moveBuffer.SetDefaults(); moveBuffer.feedRate = platform.MaxFeedrate(Z_AXIS); moveBuffer.filePos = (&gb == fileGCode) ? gb.GetFilePosition(fileInput->BytesCached()) : noFilePosition; moveBuffer.canPauseAfter = false; // don't pause after a retraction because that could cause too much retraction @@ -1412,15 +1392,11 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) const uint32_t xAxes = reprap.GetCurrentXAxes(); const uint32_t yAxes = reprap.GetCurrentYAxes(); reprap.GetMove().GetCurrentUserPosition(moveBuffer.coords, 0, xAxes, yAxes); - for (size_t i = numTotalAxes; i < MaxTotalDrivers; ++i) - { - moveBuffer.coords[i] = 0.0; - } + SetMoveBufferDefaults(); for (size_t i = 0; i < tool->DriveCount(); ++i) { moveBuffer.coords[numTotalAxes + tool->Drive(i)] = retractLength + retractExtra; } - moveBuffer.SetDefaults(); moveBuffer.feedRate = unRetractSpeed; moveBuffer.isFirmwareRetraction = true; moveBuffer.filePos = (&gb == fileGCode) ? gb.MachineState().fileState.GetPosition() - fileInput->BytesCached() : noFilePosition; @@ -1634,7 +1610,7 @@ void GCodes::EndSimulation(GCodeBuffer *gb) // Ending a simulation, so restore the position RestorePosition(simulationRestorePoint, gb); ToolOffsetTransform(currentUserPosition, moveBuffer.coords); - reprap.GetMove().SetNewPosition(simulationRestorePoint.moveCoords, true); + reprap.GetMove().SetNewPosition(moveBuffer.coords, true); axesHomed = axesHomedBeforeSimulation; } @@ -1775,7 +1751,7 @@ void GCodes::DoPause(GCodeBuffer& gb, PauseReason reason, const char *msg) #endif } - // Replace the paused machine coordinates by user coordinates, which we updated earlier + // Replace the paused machine coordinates by user coordinates, which we updated earlier if they were returned by Move::PausePrint for (size_t axis = 0; axis < numVisibleAxes; ++axis) { pauseRestorePoint.moveCoords[axis] = currentUserPosition[axis]; @@ -1901,6 +1877,10 @@ bool GCodes::DoEmergencyPause() // Save the resume info, stop movement immediately and run the low voltage pause script to lift the nozzle etc. GrabMovement(*autoPauseGCode); + // When we use RTOS there is a possible race condition in the following, because we might try to pause when a waiting move has just been added + // but before the gcode buffer has been re-initialised ready for the next command. So start a critical section. + TaskCriticalSectionLocker lock; + const bool movesSkipped = reprap.GetMove().LowPowerOrStallPause(pauseRestorePoint); if (movesSkipped) { @@ -1927,8 +1907,6 @@ bool GCodes::DoEmergencyPause() pauseRestorePoint.feedRate = fileGCode->MachineState().feedRate; pauseRestorePoint.virtualExtruderPosition = virtualExtruderPosition; - // TODO: when we use RTOS there is a possible race condition in the following, - // because we might try to pause when a waiting move has just been added but before the gcode buffer has been re-initialised ready for the next command pauseRestorePoint.filePos = fileGCode->GetFilePosition(fileInput->BytesCached()); pauseRestorePoint.proportionDone = 0.0; #if SUPPORT_LASER || SUPPORT_IOBITS @@ -1936,6 +1914,8 @@ bool GCodes::DoEmergencyPause() #endif } + codeQueue->PurgeEntries(); + // Replace the paused machine coordinates by user coordinates, which we updated earlier for (size_t axis = 0; axis < numVisibleAxes; ++axis) { @@ -2038,7 +2018,7 @@ bool GCodes::PauseOnStall(DriversBitmap stalledDrivers) return false; } - String<100> stallErrorString; + String<MediumStringLength> stallErrorString; stallErrorString.printf("Stall detected on driver(s)"); ListDrivers(stallErrorString.GetRef(), stalledDrivers); DoPause(*autoPauseGCode, PauseReason::stall, stallErrorString.c_str()); @@ -2331,6 +2311,13 @@ bool GCodes::LoadExtrusionAndFeedrateFromGCode(GCodeBuffer& gb) virtualExtruderPosition = moveArg; } + // rawExtruderTotal is used to calculate print progress, so it must be based on the requested extrusion before accounting for mixing, + // otherwise IDEX ditto printing and similar gives strange results + if (moveBuffer.moveType == 0 && !doingToolChange) + { + rawExtruderTotal += requestedExtrusionAmount; + } + for (size_t eDrive = 0; eDrive < eMoveCount; eDrive++) { const int drive = tool->Drive(eDrive); @@ -2344,10 +2331,6 @@ bool GCodes::LoadExtrusionAndFeedrateFromGCode(GCodeBuffer& gb) rawExtruderTotalByDrive[drive] += extrusionAmount; // Don't count extrusion done in filament loading or tool change macros towards total filament consumed, it distorts the print progress - if (moveBuffer.moveType == 0 && !doingToolChange) - { - rawExtruderTotal += extrusionAmount; - } moveBuffer.coords[drive + numTotalAxes] = extrusionAmount * extrusionFactors[drive]; #if HAS_SMART_DRIVERS if (moveBuffer.moveType == 1) @@ -2431,13 +2414,6 @@ const char* GCodes::DoStraightMove(GCodeBuffer& gb, bool isCoordinated) moveBuffer.yAxes = DefaultYAxisMapping; } } -#if SUPPORT_WORKPLACE_COORDINATES - else if (gb.MachineState().UsingG54()) - { - moveBuffer.xAxes = DefaultXAxisMapping; - moveBuffer.yAxes = DefaultYAxisMapping; - } -#endif // Check for 'R' parameter to move relative to a restore point const RestorePoint * rp = nullptr; @@ -2454,6 +2430,14 @@ const char* GCodes::DoStraightMove(GCodeBuffer& gb, bool isCoordinated) } } +#if SUPPORT_WORKPLACE_COORDINATES + if (moveBuffer.moveType == 0 && rp == nullptr && gb.MachineState().UsingMachineCoordinates()) + { + moveBuffer.xAxes = DefaultXAxisMapping; + moveBuffer.yAxes = DefaultYAxisMapping; + } +#endif + // Check for laser power setting or IOBITS #if SUPPORT_LASER || SUPPORT_IOBITS if (rp != nullptr) @@ -2493,7 +2477,7 @@ const char* GCodes::DoStraightMove(GCodeBuffer& gb, bool isCoordinated) #endif #endif - if (moveBuffer.moveType != 0 || gb.MachineState().UsingG54()) + if (moveBuffer.moveType != 0 || (rp == nullptr && gb.MachineState().UsingMachineCoordinates())) { // This may be a raw motor move, in which case we need the current raw motor positions in moveBuffer.coords. // If it isn't a raw motor move, it will still be applied without axis or bed transform applied, @@ -2520,7 +2504,7 @@ const char* GCodes::DoStraightMove(GCodeBuffer& gb, bool isCoordinated) SetBit(axesMentioned, axis); const float moveArg = gb.GetFValue() * distanceScale; - if (moveBuffer.moveType != 0 || gb.MachineState().UsingG54()) + if (moveBuffer.moveType != 0 || (rp == nullptr && gb.MachineState().UsingMachineCoordinates())) { if (gb.MachineState().axesRelative) { @@ -2586,7 +2570,7 @@ const char* GCodes::DoStraightMove(GCodeBuffer& gb, bool isCoordinated) } else { - if (gb.MachineState().UsingG54()) + if (rp == nullptr && gb.MachineState().UsingMachineCoordinates()) { gb.SetState(GCodeState::waitingForSpecialMoveToComplete); // we need to update the user coordinates after the move } @@ -2598,6 +2582,12 @@ const char* GCodes::DoStraightMove(GCodeBuffer& gb, bool isCoordinated) } ToolOffsetTransform(currentUserPosition, moveBuffer.coords, axesMentioned); // apply tool offset, axis mapping, baby stepping, Z hop and axis scaling + + // If we are emulating Marlin for nanoDLP then we need to set a special end state + if (platform.Emulating() == Compatibility::nanoDLP && &gb == serialGCode && !DoingFileMacro()) + { + gb.SetState(GCodeState::waitingForSpecialMoveToComplete); + } } AxesBitmap effectiveAxesHomed = axesHomed; @@ -2830,6 +2820,9 @@ const char* GCodes::DoArcMove(GCodeBuffer& gb, bool clockwise) } // Compute how many segments we need to move, but don't store it yet + // For the arc to deviate up to MaxArcDeviation from the ideal, the segment length should be sqrt(8 * arcRadius * MaxArcDeviation + fsquare(MaxArcDeviation)) + // We leave out the square term because it is very small + const float arcSegmentLength = constrain<float>(sqrt(8 * arcRadius * MaxArcDeviation), MinArcSegmentLength, MaxArcSegmentLength); totalSegments = max<unsigned int>((unsigned int)((arcRadius * totalArc)/arcSegmentLength + 0.8), 1u); arcAngleIncrement = totalArc/totalSegments; if (clockwise) @@ -3782,6 +3775,7 @@ void GCodes::HandleReply(GCodeBuffer& gb, GCodeResult rslt, const char* reply) } break; + case Compatibility::nanoDLP: // nanoDLP is like Marlin except that G0 and G1 commands return "Z_move_comp<LF>" before "ok<LF>" case Compatibility::marlin: // We don't need to handle M20 here because we always allocate an output buffer for that one if (gb.GetCommandLetter() == 'M' && gb.GetCommandNumber() == 28) @@ -3854,6 +3848,7 @@ void GCodes::HandleReply(GCodeBuffer& gb, OutputBuffer *reply) return; case Compatibility::marlin: + case Compatibility::nanoDLP: if (gb.GetCommandLetter() =='M' && gb.GetCommandNumber() == 20) { platform.Message(type, "Begin file list\n"); @@ -4171,11 +4166,7 @@ GCodeResult GCodes::RetractFilament(GCodeBuffer& gb, bool retract) const uint32_t xAxes = reprap.GetCurrentXAxes(); const uint32_t yAxes = reprap.GetCurrentYAxes(); reprap.GetMove().GetCurrentUserPosition(moveBuffer.coords, 0, xAxes, yAxes); - for (size_t i = numTotalAxes; i < MaxTotalDrivers; ++i) - { - moveBuffer.coords[i] = 0.0; - } - moveBuffer.SetDefaults(); + SetMoveBufferDefaults(); moveBuffer.isFirmwareRetraction = true; moveBuffer.filePos = (&gb == fileGCode) ? gb.GetFilePosition(fileInput->BytesCached()) : noFilePosition; moveBuffer.xAxes = xAxes; @@ -4421,7 +4412,7 @@ void GCodes::StopPrint(StopPrintReason reason) } } - if (platform.Emulating() == Compatibility::marlin) + if (platform.EmulatingMarlin()) { // Pronterface expects a "Done printing" message platform.Message(UsbMessage, "Done printing file\n"); @@ -4470,7 +4461,8 @@ void GCodes::UpdateCurrentUserPosition() ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition); } -// Save position to a restore point +// Save position to a restore point. +// Note that restore point coordinates are not affected by workplace coordinate offsets. This allows them to be use din resume.g. void GCodes::SavePosition(RestorePoint& rp, const GCodeBuffer& gb) const { for (size_t axis = 0; axis < numVisibleAxes; ++axis) @@ -4514,13 +4506,7 @@ void GCodes::ToolOffsetTransform(const float coordsIn[MaxAxes], float coordsOut[ { for (size_t axis = 0; axis < numVisibleAxes; ++axis) { - const float totalOffset = -#if SUPPORT_WORKPLACE_COORDINATES - workplaceCoordinates[currentCoordinateSystem][axis]; -#else - axisOffsets[axis]; -#endif - coordsOut[axis] = (coordsIn[axis] * axisScaleFactors[axis]) + totalOffset; + coordsOut[axis] = (coordsIn[axis] * axisScaleFactors[axis]) + GetWorkplaceOffset(axis); } } else @@ -4533,13 +4519,7 @@ void GCodes::ToolOffsetTransform(const float coordsIn[MaxAxes], float coordsOut[ && (axis != Y_AXIS || IsBitSet(yAxes, Y_AXIS)) ) { - const float totalOffset = -#if SUPPORT_WORKPLACE_COORDINATES - workplaceCoordinates[currentCoordinateSystem][axis] -#else - axisOffsets[axis] -#endif - - currentTool->GetOffset(axis); + const float totalOffset = GetWorkplaceOffset(axis) - currentTool->GetOffset(axis); const size_t inputAxis = (IsBitSet(explicitAxes, axis)) ? axis : (IsBitSet(xAxes, axis)) ? X_AXIS : (IsBitSet(yAxes, axis)) ? Y_AXIS @@ -4560,13 +4540,7 @@ void GCodes::ToolOffsetInverseTransform(const float coordsIn[MaxAxes], float coo { for (size_t axis = 0; axis < numVisibleAxes; ++axis) { - const float totalOffset = -#if SUPPORT_WORKPLACE_COORDINATES - workplaceCoordinates[currentCoordinateSystem][axis]; -#else - axisOffsets[axis]; -#endif - coordsOut[axis] = (coordsIn[axis] - totalOffset) / axisScaleFactors[axis]; + coordsOut[axis] = (coordsIn[axis] - GetWorkplaceOffset(axis)) / axisScaleFactors[axis]; } } else @@ -4577,13 +4551,7 @@ void GCodes::ToolOffsetInverseTransform(const float coordsIn[MaxAxes], float coo size_t numXAxes = 0, numYAxes = 0; for (size_t axis = 0; axis < numVisibleAxes; ++axis) { - const float totalOffset = -#if SUPPORT_WORKPLACE_COORDINATES - workplaceCoordinates[currentCoordinateSystem][axis] -#else - axisOffsets[axis] -#endif - - currentTool->GetOffset(axis); + const float totalOffset = GetWorkplaceOffset(axis) - currentTool->GetOffset(axis); coordsOut[axis] = coordsIn[axis]/axisScaleFactors[axis] - totalOffset; if (IsBitSet(xAxes, axis)) { @@ -4725,7 +4693,7 @@ GCodeResult GCodes::WriteConfigOverrideFile(GCodeBuffer& gb, const StringRef& re return GCodeResult::error; } - bool ok = f->Write("; This is a system-generated file - do not edit\n"); + bool ok = WriteConfigOverrideHeader(f); if (ok) { ok = reprap.GetMove().GetKinematics().WriteCalibrationParameters(f); @@ -4773,6 +4741,28 @@ GCodeResult GCodes::WriteConfigOverrideFile(GCodeBuffer& gb, const StringRef& re return GCodeResult::ok; } +// Write the config-override header returning true if success +// This is implemented as a separate function to avoid allocating a buffer on the stack and then calling functions that also allocate buffers on the stack +bool GCodes::WriteConfigOverrideHeader(FileStore *f) const +{ + String<MaxFilenameLength> buf; + buf.copy("; config-override.g file generated in response to M500"); + if (platform.IsDateTimeSet()) + { + time_t timeNow = platform.GetDateTime(); + const struct tm * const timeInfo = gmtime(&timeNow); + buf.catf(" at %04u-%02u-%02u %02u:%02u", + timeInfo->tm_year + 1900, timeInfo->tm_mon + 1, timeInfo->tm_mday, timeInfo->tm_hour, timeInfo->tm_min); + } + buf.cat('\n'); + bool ok = f->Write(buf.c_str()); + if (ok) + { + ok = f->Write("; This is a system-generated file - do not edit\n"); + } + return ok; +} + // Report the temperatures of one tool in M105 format void GCodes::ReportToolTemperatures(const StringRef& reply, const Tool *tool, bool includeNumber) const { @@ -4861,7 +4851,7 @@ void GCodes::CheckReportDue(GCodeBuffer& gb, const StringRef& reply) const { if (now - gb.whenTimerStarted >= 1000) { - if (platform.Emulating() == Compatibility::marlin && (&gb == serialGCode || &gb == telnetGCode)) + if (platform.EmulatingMarlin() && (&gb == serialGCode || &gb == telnetGCode)) { // In Marlin emulation mode we should return a standard temperature report every second GenerateTemperatureReport(reply); @@ -4920,6 +4910,23 @@ OutputBuffer *GCodes::GenerateJsonStatusResponse(int type, int seq, ResponseSour return statusResponse; } +// Set up some default values in the move buffer for special moves, e.g. for Z probing and firmware retraction +void GCodes::SetMoveBufferDefaults() +{ + moveBuffer.moveType = 0; + moveBuffer.isCoordinated = false; + moveBuffer.usingStandardFeedrate = false; + moveBuffer.usePressureAdvance = false; + moveBuffer.endStopsToCheck = 0; + moveBuffer.filePos = noFilePosition; + moveBuffer.xAxes = DefaultXAxisMapping; + moveBuffer.yAxes = DefaultYAxisMapping; + for (size_t drive = numTotalAxes; drive < MaxTotalDrivers; ++drive) + { + moveBuffer.coords[drive] = 0.0; // clear extrusion + } +} + // Resource locking/unlocking // Lock the resource, returning true if success. diff --git a/src/GCodes/GCodes.h b/src/GCodes/GCodes.h index 059cf400..ac096872 100644 --- a/src/GCodes/GCodes.h +++ b/src/GCodes/GCodes.h @@ -130,8 +130,6 @@ public: uint8_t hasExtrusion : 1; // true if the move includes extrusion - only valid if the move was set up by SetupMove uint8_t isCoordinated : 1; // true if this is a coordinates move uint8_t usingStandardFeedrate : 1; // true if this move uses the standard feed rate - - void SetDefaults(); // set up default values }; GCodes(Platform& p); @@ -367,6 +365,8 @@ private: GCodeResult ChangeSimulationMode(GCodeBuffer& gb, const StringRef &reply, uint32_t newSimulationMode); // Handle M37 to change the simulation mode GCodeResult WriteConfigOverrideFile(GCodeBuffer& gb, const StringRef& reply) const; // Write the config-override file + bool WriteConfigOverrideHeader(FileStore *f) const; // Write the config-override header + void CopyConfigFinalValues(GCodeBuffer& gb); // Copy the feed rate etc. from the daemon to the input channels void ClearBabyStepping() { currentBabyStepZOffset = 0.0; } @@ -386,11 +386,22 @@ private: void NewMoveAvailable(unsigned int sl); // Flag that a new move is available void NewMoveAvailable(); // Flag that a new move is available + void SetMoveBufferDefaults(); // Set up default values in the move buffer + #if SUPPORT_12864_LCD int GetHeaterNumber(unsigned int itemNumber) const; #endif Pwm_t ConvertLaserPwm(float reqVal) const; + inline float GetWorkplaceOffset(size_t axis) const + { +#if SUPPORT_WORKPLACE_COORDINATES + return workplaceCoordinates[currentCoordinateSystem][axis]; +#else + return axisOffsets[axis]; +#endif + } + #ifdef SERIAL_AUX_DEVICE static bool emergencyStopCommanded; static void CommandEmergencyStop(UARTClass *p); @@ -482,7 +493,6 @@ private: float rawExtruderTotalByDrive[MaxExtruders]; // Extrusion amount in the last G1 command with an E parameter when in absolute extrusion mode float rawExtruderTotal; // Total extrusion amount fed to Move class since starting print, before applying extrusion factor, summed over all drives float distanceScale; // MM or inches - float arcSegmentLength; // Length of segments that we split arc moves into #if SUPPORT_WORKPLACE_COORDINATES static const size_t NumCoordinateSystems = 9; @@ -599,6 +609,7 @@ private: static constexpr const char* RESUME_AFTER_POWER_FAIL_G = "resurrect.g"; static constexpr const char* RESUME_PROLOGUE_G = "resurrect-prologue.g"; static constexpr const char* FILAMENT_CHANGE_G = "filament-change.g"; + static constexpr const char* PEEL_MOVE_G = "peel-move.g"; #if HAS_SMART_DRIVERS static constexpr const char* REHOME_G = "rehome.g"; #endif diff --git a/src/GCodes/GCodes2.cpp b/src/GCodes/GCodes2.cpp index 1ef0c8d1..a62735ce 100644 --- a/src/GCodes/GCodes2.cpp +++ b/src/GCodes/GCodes2.cpp @@ -615,7 +615,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) outBuf->copy("GCode files:\n"); } - bool encapsulateList = ((&gb != serialGCode && &gb != telnetGCode) || platform.Emulating() != Compatibility::marlin); + bool encapsulateList = ((&gb != serialGCode && &gb != telnetGCode) || !platform.EmulatingMarlin()); FileInfo fileInfo; if (platform.GetMassStorage()->FindFirst(dir.c_str(), fileInfo)) { @@ -623,11 +623,11 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) do { if (encapsulateList) { - outBuf->catf("%c%s%c%c", FILE_LIST_BRACKET, fileInfo.fileName, FILE_LIST_BRACKET, FILE_LIST_SEPARATOR); + outBuf->catf("%c%s%c%c", FILE_LIST_BRACKET, fileInfo.fileName.c_str(), FILE_LIST_BRACKET, FILE_LIST_SEPARATOR); } else { - outBuf->catf("%s\n", fileInfo.fileName); + outBuf->catf("%s\n", fileInfo.fileName.c_str()); } } while (platform.GetMassStorage()->FindNext(fileInfo)); @@ -688,7 +688,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) if (QueueFileToPrint(filename.c_str(), reply)) { reprap.GetPrintMonitor().StartingPrint(filename.c_str()); - if (platform.Emulating() == Compatibility::marlin && (&gb == serialGCode || &gb == telnetGCode)) + if (platform.EmulatingMarlin() && (&gb == serialGCode || &gb == telnetGCode)) { reply.copy("File opened\nFile selected"); } @@ -779,8 +779,8 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) } break; - case 226: // Gcode Initiated Pause - if (&gb == fileGCode) // ignore M226 if it did't come from within a file being printed + case 226: // Synchronous pause, normally initiated from within the file being printed + if (!isPaused && !IsPausing()) { if (gb.IsDoingFileMacro()) { @@ -788,7 +788,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) } else { - if (!LockMovement(gb)) // lock movement before calling DoPause + if (!LockMovementAndWaitForStandstill(gb)) // lock movement before calling DoPause, also wait for movement to complete { return false; } @@ -797,8 +797,8 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) } break; - case 600: // Filament change pause - if (&gb == fileGCode) // ignore M600 if it did't come from within a file being printed + case 600: // Filament change pause, synchronous + if (!isPaused && !IsPausing()) { if (gb.IsDoingFileMacro()) { @@ -806,7 +806,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) } else { - if (!LockMovement(gb)) // lock movement before calling DoPause + if (!LockMovementAndWaitForStandstill(gb)) // lock movement before calling DoPause, also wait for movement to complete { return false; } @@ -1533,7 +1533,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) case 117: // Display message { - String<MaxFilenameLength> msg; + String<MediumStringLength> msg; gb.GetUnprecedentedString(msg.GetRef()); reprap.SetMessage(msg.c_str()); } @@ -2180,7 +2180,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) if (amountPushed != difference && segmentsLeft == 0 && reprap.GetMove().AllMovesAreFinished()) { // The pipeline is empty, so execute the babystepping move immediately - moveBuffer.SetDefaults(); + SetMoveBufferDefaults(); moveBuffer.feedRate = platform.MaxFeedrate(Z_AXIS); NewMoveAvailable(1); } @@ -2527,7 +2527,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) #if SUPPORT_OBJECT_MODEL case 1: { - String<MaxFilenameLength> filter; + String<MediumStringLength> filter; bool dummy; gb.TryGetQuotedString('F', filter.GetRef(), dummy); if (!OutputBuffer::Allocate(outBuf)) @@ -2755,7 +2755,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) case 550: // Set/report machine name { - String<MACHINE_NAME_LENGTH> name; + String<MachineNameLength> name; bool seen = false; gb.TryGetPossiblyQuotedString('P', name.GetRef(), seen); if (seen) @@ -2771,7 +2771,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) case 551: // Set password (no option to report it) { - String<PASSWORD_LENGTH> password; + String<RepRapPasswordLength> password; bool seen = false; gb.TryGetPossiblyQuotedString('P', password.GetRef(), seen); if (seen) @@ -2899,7 +2899,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) { case Compatibility::me: case Compatibility::reprapFirmware: - reply.cat("RepRap Firmware (i.e. in native mode)"); + reply.cat("RepRapFirmware (i.e. in native mode)"); break; case Compatibility::marlin: @@ -2918,6 +2918,10 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) reply.cat("Repetier"); break; + case Compatibility::nanoDLP: + reply.cat("nanoDLP"); + break; + default: reply.catf("Unknown: (%u)", (unsigned int)platform.Emulating()); } @@ -3534,6 +3538,17 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) // For case 600, see 226 + case 650: // Set peel move parameters - ignored + break; + + case 651: // Execute DLP peel move + if (!LockMovementAndWaitForStandstill(gb)) + { + return false; + } + DoFileMacro(gb, PEEL_MOVE_G, true); + break; + case 665: // Set delta configuration if (!LockMovementAndWaitForStandstill(gb)) { diff --git a/src/GCodes/GCodes3.cpp b/src/GCodes/GCodes3.cpp index 0eb7120b..428b2ab0 100644 --- a/src/GCodes/GCodes3.cpp +++ b/src/GCodes/GCodes3.cpp @@ -120,7 +120,7 @@ GCodeResult GCodes::SetPrintZProbe(GCodeBuffer& gb, const StringRef& reply) } // Deal with G60 -GCodeResult GCodes::SavePosition(GCodeBuffer& gb,const StringRef& reply) +GCodeResult GCodes::SavePosition(GCodeBuffer& gb, const StringRef& reply) { const uint32_t sParam = (gb.Seen('S')) ? gb.GetUIValue() : 0; if (sParam < ARRAY_SIZE(numberedRestorePoints)) @@ -201,7 +201,7 @@ GCodeResult GCodes::OffsetAxes(GCodeBuffer& gb, const StringRef& reply) if (gb.Seen(axisLetters[axis])) { #if SUPPORT_WORKPLACE_COORDINATES - workplaceCoordinates[0][axis] + workplaceCoordinates[currentCoordinateSystem][axis] #else axisOffsets[axis] #endif @@ -450,7 +450,7 @@ GCodeResult GCodes::SimulateFile(GCodeBuffer& gb, const StringRef &reply, const { axesHomedBeforeSimulation = axesHomed; axesHomed = LowestNBits<AxesBitmap>(numVisibleAxes); // pretend all axes are homed - reprap.GetMove().GetCurrentUserPosition(simulationRestorePoint.moveCoords, 0, reprap.GetCurrentXAxes(), reprap.GetCurrentYAxes()); + SavePosition(simulationRestorePoint, gb); simulationRestorePoint.feedRate = gb.MachineState().feedRate; } simulationTime = 0.0; @@ -488,8 +488,7 @@ GCodeResult GCodes::ChangeSimulationMode(GCodeBuffer& gb, const StringRef &reply // Starting a new simulation, so save the current position axesHomedBeforeSimulation = axesHomed; axesHomed = LowestNBits<AxesBitmap>(numVisibleAxes); // pretend all axes are homed - reprap.GetMove().GetCurrentUserPosition(simulationRestorePoint.moveCoords, 0, reprap.GetCurrentXAxes(), reprap.GetCurrentYAxes()); - simulationRestorePoint.feedRate = gb.MachineState().feedRate; + SavePosition(simulationRestorePoint, gb); } simulationTime = 0.0; } @@ -736,22 +735,20 @@ GCodeResult GCodes::DoDriveMapping(GCodeBuffer& gb, const StringRef& reply) { ++drive; } - if (drive < MaxAxes) + if (drive == numTotalAxes && drive < MaxAxes) { - if (drive == numTotalAxes) - { - axisLetters[drive] = c; // assign the drive to this drive letter - moveBuffer.coords[drive] = 0.0; // user has defined a new axis, so set its position - currentUserPosition[drive] = 0.0; // set its requested user position too in case it is visible - ++numTotalAxes; - numVisibleAxes = numTotalAxes; // assume any new axes are visible unless there is a P parameter - reprap.GetMove().SetNewPosition(moveBuffer.coords, true); // tell the Move system where the new axis is - } - platform.SetAxisDriversConfig(drive, config); - if (numTotalAxes + numExtruders > MaxTotalDrivers) - { - numExtruders = MaxTotalDrivers - numTotalAxes; // if we added axes, we may have fewer extruders now - } + axisLetters[drive] = c; // assign the drive to this drive letter + ++numTotalAxes; + numVisibleAxes = numTotalAxes; // assume any new axes are visible unless there is a P parameter + float initialCoords[MaxAxes]; + reprap.GetMove().GetKinematics().GetAssumedInitialPosition(drive + 1, initialCoords); + moveBuffer.coords[drive] = initialCoords[drive]; // user has defined a new axis, so set its position + ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition); + } + platform.SetAxisDriversConfig(drive, config); + if (numTotalAxes + numExtruders > MaxTotalDrivers) + { + numExtruders = MaxTotalDrivers - numTotalAxes; // if we added axes, we may have fewer extruders now } } ++lettersToTry; @@ -787,7 +784,10 @@ GCodeResult GCodes::DoDriveMapping(GCodeBuffer& gb, const StringRef& reply) if (seen) { - UpdateCurrentUserPosition(); // make sure that any new visible axes are up to date + // In the DDA ring, the axis positions for invisible non-moving axes are not always copied over from previous moves. + // So if we have more visible axes than before, then we need to update their positions to get them in sync. + // We could do this only when we increase the number of visible axes, but for simplicity we do it always. + reprap.GetMove().SetNewPosition(moveBuffer.coords, true); // tell the Move system where the axes are } else { @@ -844,7 +844,7 @@ GCodeResult GCodes::ProbeTool(GCodeBuffer& gb, const StringRef& reply) } // Save the current axis coordinates - memcpy(toolChangeRestorePoint.moveCoords, currentUserPosition, ARRAY_SIZE(currentUserPosition) * sizeof(currentUserPosition[0])); + SavePosition(toolChangeRestorePoint, gb); // Prepare another move similar to G1 .. S3 moveBuffer.moveType = 3; diff --git a/src/Movement/DDA.cpp b/src/Movement/DDA.cpp index 0278e53a..ae0a5bc6 100644 --- a/src/Movement/DDA.cpp +++ b/src/Movement/DDA.cpp @@ -290,17 +290,17 @@ bool DDA::Init(GCodes::RawMove &nextMove, bool doMotorMapping) for (size_t drive = 0; drive < MaxTotalDrivers; drive++) { accelerations[drive] = normalAccelerations[drive]; - if (drive >= numTotalAxes || (!doMotorMapping && drive < numVisibleAxes)) - { - endPoint[drive] = Move::MotorEndPointToMachine(drive, nextMove.coords[drive]); - } - endCoordinates[drive] = nextMove.coords[drive]; - int32_t delta; + int32_t delta; // this will be the net number of steps + if (drive < numTotalAxes) { + if (!doMotorMapping && drive < numVisibleAxes) + { + endPoint[drive] = Move::MotorMovementToSteps(drive, nextMove.coords[drive]); + } delta = endPoint[drive] - positionNow[drive]; - if (k.IsContinuousRotationAxis(drive) && nextMove.moveType != 1 && nextMove.moveType != 2) + if (k.IsContinuousRotationAxis(drive) && nextMove.moveType == 0) { const int32_t stepsPerRotation = lrintf(360.0 * reprap.GetPlatform().DriveStepsPerUnit(drive)); if (delta > stepsPerRotation/2) @@ -312,27 +312,34 @@ bool DDA::Init(GCodes::RawMove &nextMove, bool doMotorMapping) delta += stepsPerRotation; } } - } - else - { - delta = endPoint[drive]; - } - - if (drive < numTotalAxes && doMotorMapping) - { - const float positionDelta = nextMove.coords[drive] - prev->GetEndCoordinate(drive, false); - directionVector[drive] = positionDelta; - if (positionDelta != 0.0 && (IsBitSet(nextMove.yAxes, drive) || IsBitSet(nextMove.xAxes, drive))) + if (doMotorMapping) + { + const float positionDelta = nextMove.coords[drive] - prev->GetEndCoordinate(drive, false); + directionVector[drive] = positionDelta; + if (positionDelta != 0.0 && (IsBitSet(nextMove.yAxes, drive) || IsBitSet(nextMove.xAxes, drive))) + { + xyMoving = true; + } + } + else { - xyMoving = true; + directionVector[drive] = (float)delta/reprap.GetPlatform().DriveStepsPerUnit(drive); } } else { - directionVector[drive] = (float)delta/reprap.GetPlatform().DriveStepsPerUnit(drive); - if (drive >= numTotalAxes && nextMove.coords[drive] > 0.0) + // It's an extruder drive. We defer calculating the steps because they may be affected by nonlinear extrusion, which we can't calculate until we + // know the speed of the move, and because extruder movement is relative so we need to accumulate fractions of a whole step between moves. + const float movement = nextMove.coords[drive]; + directionVector[drive] = movement; + if (movement != 0.0) { - extruding = true; // flag this move as extruding even if the number of extruder microsteps is zero + extruding = true; + delta = (movement > 0.0) ? 1 : -1; // set 1 step for now, it will be recalculated later + } + else + { + delta = 0; } } @@ -347,8 +354,6 @@ bool DDA::Init(GCodes::RawMove &nextMove, bool doMotorMapping) if (drive >= numTotalAxes) { // It's an extruder movement - nextMove.coords[drive] -= directionVector[drive]; - // subtract the amount of extrusion we actually did to leave the residue outstanding if (xyMoving && nextMove.usePressureAdvance) { const float compensationTime = reprap.GetPlatform().GetPressureAdvance(drive - numTotalAxes); @@ -1044,7 +1049,7 @@ pre(disableDeltaMapping || drive < MaxAxes) { if (disableMotorMapping) { - return Move::MotorEndpointToPosition(endPoint[drive], drive); + return Move::MotorStepsToMovement(drive, endPoint[drive]); } else { @@ -1177,7 +1182,7 @@ inline void DDA::AdjustAcceleration() // Prepare this DDA for execution. // This must not be called with interrupts disabled, because it calls Platform::EnableDrive. -void DDA::Prepare(uint8_t simMode) +void DDA::Prepare(uint8_t simMode, float extrusionPending[]) { if ( xyMoving && reprap.GetMove().IsDRCenabled() @@ -1246,7 +1251,7 @@ void DDA::Prepare(uint8_t simMode) #endif // Handle all drivers - const size_t numAxes = reprap.GetGCodes().GetTotalAxes(); + const size_t numTotalAxes = reprap.GetGCodes().GetTotalAxes(); Platform& platform = reprap.GetPlatform(); for (size_t drive = 0; drive < NumDirectDrivers; ++drive) { @@ -1269,7 +1274,7 @@ void DDA::Prepare(uint8_t simMode) else { reprap.GetPlatform().EnableDrive(drive); - if (drive >= numAxes) + if (drive >= numTotalAxes) { // If there is any extruder jerk in this move, in theory that means we need to instantly extrude or retract some amount of filament. // Pass the speed change to PrepareExtruder @@ -1283,7 +1288,7 @@ void DDA::Prepare(uint8_t simMode) { speedChange = 0.0; } - pdm->PrepareExtruder(*this, params, speedChange, usePressureAdvance); + pdm->PrepareExtruder(*this, params, extrusionPending[drive - numTotalAxes], speedChange, usePressureAdvance); // Check for sensible values, print them if they look dubious if (reprap.Debug(moduleDda) @@ -1350,7 +1355,7 @@ void DDA::Prepare(uint8_t simMode) } else { - if (drive < numAxes) + if (drive < numTotalAxes) { const AxisDriversConfig& config = platform.GetAxisDriversConfig(drive); for (size_t i = 0; i < config.numDrivers; ++i) @@ -1364,7 +1369,7 @@ void DDA::Prepare(uint8_t simMode) } else { - const uint8_t driver = platform.GetExtruderDriver(drive - numAxes); + const uint8_t driver = platform.GetExtruderDriver(drive - numTotalAxes); if (driver >= NumDirectDrivers) { CanInterface::AddMovement(*this, params, driver - NumDirectDrivers, *pdm); diff --git a/src/Movement/DDA.h b/src/Movement/DDA.h index f506373e..452bcdd5 100644 --- a/src/Movement/DDA.h +++ b/src/Movement/DDA.h @@ -39,7 +39,8 @@ public: DDA(DDA* n); - bool Init(GCodes::RawMove &nextMove, bool doMotorMapping) __attribute__ ((hot)); // Set up a new move, returning true if it represents real movement + bool Init(GCodes::RawMove &nextMove, bool doMotorMapping) __attribute__ ((hot)); + // Set up a new move, returning true if it represents real movement bool Init(const float_t steps[MaxTotalDrivers]); // Set up a raw (unmapped) motor move void Init(); // Set up initial positions for machine startup bool Start(uint32_t tim) __attribute__ ((hot)); // Start executing the DDA, i.e. move the move. @@ -48,7 +49,7 @@ public: void SetPrevious(DDA *p) { prev = p; } void Complete() { state = completed; } bool Free(); - void Prepare(uint8_t simMode) __attribute__ ((hot)); // Calculate all the values and freeze this DDA + void Prepare(uint8_t simMode, float extrusionPending[]) __attribute__ ((hot)); // Calculate all the values and freeze this DDA bool HasStepError() const; bool CanPauseAfter() const { return canPauseAfter; } bool IsPrintingMove() const { return isPrintingMove; } // Return true if this involves both XY movement and extrusion diff --git a/src/Movement/DriveMovement.cpp b/src/Movement/DriveMovement.cpp index 54805798..02c9078d 100644 --- a/src/Movement/DriveMovement.cpp +++ b/src/Movement/DriveMovement.cpp @@ -171,35 +171,45 @@ void DriveMovement::PrepareDeltaAxis(const DDA& dda, const PrepParams& params) } // Prepare this DM for an extruder move -void DriveMovement::PrepareExtruder(const DDA& dda, const PrepParams& params, float speedChange, bool doCompensation) +void DriveMovement::PrepareExtruder(const DDA& dda, const PrepParams& params, float& extrusionPending, float speedChange, bool doCompensation) { - const float dv = dda.directionVector[drive]; - float stepsPerMm = reprap.GetPlatform().DriveStepsPerUnit(drive) * fabsf(dv); + // Calculate the requested extrusion amount and a few other things + float dv = dda.directionVector[drive]; + float extrusionRequired = dda.totalDistance * dv; const size_t extruder = drive - reprap.GetGCodes().GetTotalAxes(); #if SUPPORT_NONLINEAR_EXTRUSION + // Add the nonlinear extrusion correction to totalExtrusion if (dda.isPrintingMove) { float a, b, limit; if (reprap.GetPlatform().GetExtrusionCoefficients(extruder, a, b, limit)) { - const float averageExtrusionSpeed = (dda.totalDistance * dv * StepTimer::StepClockRate)/dda.clocksNeeded; + const float averageExtrusionSpeed = (extrusionRequired * StepTimer::StepClockRate)/dda.clocksNeeded; const float factor = 1.0 + min<float>((averageExtrusionSpeed * a) + (averageExtrusionSpeed * averageExtrusionSpeed * b), limit); - stepsPerMm *= factor; + extrusionRequired *= factor; } } #endif + // Add on any fractional extrusion pending from the previous move + extrusionRequired += extrusionPending; + dv = extrusionRequired/dda.totalDistance; + direction = (dv >= 0.0); + + const float rawStepsPerMm = reprap.GetPlatform().DriveStepsPerUnit(drive); + const float effectiveStepsPerMm = fabsf(dv) * rawStepsPerMm; + float compensationTime; float accelCompensationDistance; - int32_t netSteps; - if (doCompensation && dv > 0.0) + if (doCompensation && direction) { // Calculate the pressure advance parameters compensationTime = reprap.GetPlatform().GetPressureAdvance(extruder); - mp.cart.compensationClocks = roundU32(compensationTime * (float)StepTimer::StepClockRate); - mp.cart.accelCompensationClocks = roundU32(compensationTime * (float)StepTimer::StepClockRate * params.compFactor); + const float compensationClocks = compensationTime * (float)StepTimer::StepClockRate; + mp.cart.compensationClocks = roundU32(compensationClocks); + mp.cart.accelCompensationClocks = roundU32(compensationClocks * params.compFactor); #ifdef COMPENSATE_SPEED_CHANGES // If there is a speed change at the start of the move, theoretically we should instantly advance or retard the filament by the associated compensation amount. @@ -207,33 +217,40 @@ void DriveMovement::PrepareExtruder(const DDA& dda, const PrepParams& params, fl const float factor = 1.0 + (speedChange * compensationTime)/dda.totalDistance; stepsPerMm *= factor; #endif - // Recalculate the net total step count to allow for compensation. It may be negative. - const float compensationDistance = (dda.endSpeed - dda.startSpeed) * compensationTime; - netSteps = (int32_t)((dda.totalDistance + compensationDistance) * stepsPerMm); + // Calculate the net total extrusion to allow for compensation. It may be negative. + extrusionRequired += (dda.endSpeed - dda.startSpeed) * compensationTime * dv; // Calculate the acceleration phase parameters accelCompensationDistance = compensationTime * (dda.topSpeed - dda.startSpeed); - mp.cart.accelStopStep = (uint32_t)((dda.accelDistance + accelCompensationDistance) * stepsPerMm) + 1; + mp.cart.accelStopStep = (uint32_t)((dda.accelDistance + accelCompensationDistance) * effectiveStepsPerMm) + 1; } else { accelCompensationDistance = compensationTime = 0.0; mp.cart.compensationClocks = mp.cart.accelCompensationClocks = 0; - netSteps = (int32_t)(dda.totalDistance * stepsPerMm); // it may have changed from totalSteps if we are using nonlinear extrusion // Calculate the acceleration phase parameters - mp.cart.accelStopStep = (uint32_t)(dda.accelDistance * stepsPerMm) + 1; + mp.cart.accelStopStep = (uint32_t)(dda.accelDistance * effectiveStepsPerMm) + 1; } - mp.cart.twoCsquaredTimesMmPerStepDivA = roundU64((double)(StepTimer::StepClockRateSquared * 2)/((double)stepsPerMm * (double)dda.acceleration)); - mp.cart.twoCsquaredTimesMmPerStepDivD = roundU64((double)(StepTimer::StepClockRateSquared * 2)/((double)stepsPerMm * (double)dda.deceleration)); + int32_t netSteps = (int32_t)(extrusionRequired * rawStepsPerMm); + extrusionPending = extrusionRequired - (float)netSteps/rawStepsPerMm; + + if (!direction) + { + netSteps = -netSteps; + } + + // Note, netSteps may be negative at this point if we are applying pressure advance + mp.cart.twoCsquaredTimesMmPerStepDivA = roundU64((double)(StepTimer::StepClockRateSquared * 2)/((double)effectiveStepsPerMm * (double)dda.acceleration)); + mp.cart.twoCsquaredTimesMmPerStepDivD = roundU64((double)(StepTimer::StepClockRateSquared * 2)/((double)effectiveStepsPerMm * (double)dda.deceleration)); // Constant speed phase parameters - mp.cart.mmPerStepTimesCKdivtopSpeed = (uint32_t)((float)((uint64_t)StepTimer::StepClockRate * K1)/(stepsPerMm * dda.topSpeed)); + mp.cart.mmPerStepTimesCKdivtopSpeed = (uint32_t)((float)((uint64_t)StepTimer::StepClockRate * K1)/(effectiveStepsPerMm * dda.topSpeed)); // Calculate the deceleration and reverse phase parameters and update totalSteps // First check whether there is any deceleration at all, otherwise we may get strange results because of rounding errors - if (dda.decelDistance * stepsPerMm < 0.5) // if less than 1 deceleration step + if (dda.decelDistance * effectiveStepsPerMm < 0.5) // if less than 1 deceleration step { totalSteps = (uint32_t)max<int32_t>(netSteps, 0); mp.cart.decelStartStep = reverseStartStep = netSteps + 1; @@ -242,7 +259,7 @@ void DriveMovement::PrepareExtruder(const DDA& dda, const PrepParams& params, fl } else { - mp.cart.decelStartStep = (uint32_t)((params.decelStartDistance + accelCompensationDistance) * stepsPerMm) + 1; + mp.cart.decelStartStep = (uint32_t)((params.decelStartDistance + accelCompensationDistance) * effectiveStepsPerMm) + 1; const int32_t initialDecelSpeedTimesCdivD = (int32_t)params.topSpeedTimesCdivD - (int32_t)mp.cart.compensationClocks; // signed because it may be negative and we square it const uint64_t initialDecelSpeedTimesCdivDSquared = isquare64(initialDecelSpeedTimesCdivD); twoDistanceToStopTimesCsquaredDivD = diff --git a/src/Movement/DriveMovement.h b/src/Movement/DriveMovement.h index c0ed0cc6..7099feee 100644 --- a/src/Movement/DriveMovement.h +++ b/src/Movement/DriveMovement.h @@ -135,7 +135,7 @@ public: bool CalcNextStepTimeDelta(const DDA &dda, bool live) __attribute__ ((hot)); void PrepareCartesianAxis(const DDA& dda, const PrepParams& params) __attribute__ ((hot)); void PrepareDeltaAxis(const DDA& dda, const PrepParams& params) __attribute__ ((hot)); - void PrepareExtruder(const DDA& dda, const PrepParams& params, float speedChange, bool doCompensation) __attribute__ ((hot)); + void PrepareExtruder(const DDA& dda, const PrepParams& params, float& extrusionPending, float speedChange, bool doCompensation) __attribute__ ((hot)); void ReduceSpeed(const DDA& dda, uint32_t inverseSpeedFactor); void DebugPrint(char c, bool withDelta) const; int32_t GetNetStepsLeft() const; diff --git a/src/Movement/Kinematics/ScaraKinematics.cpp b/src/Movement/Kinematics/ScaraKinematics.cpp index 4ec47dc1..eec4e998 100644 --- a/src/Movement/Kinematics/ScaraKinematics.cpp +++ b/src/Movement/Kinematics/ScaraKinematics.cpp @@ -98,6 +98,12 @@ bool ScaraKinematics::CalculateThetaAndPsi(const float machinePos[], bool isCoor armMode = !armMode; } + // Save the original and transformed coordinates so that we don't need to calculate them again if we are commanded to move to this position + cachedX = machinePos[0]; + cachedY = machinePos[1]; + cachedTheta = theta; + cachedPsi = psi; + cachedArmMode = armMode; return true; } @@ -143,8 +149,12 @@ void ScaraKinematics::MotorStepsToCartesian(const int32_t motorPos[], const floa const float theta = ((float)motorPos[X_AXIS]/stepsPerMm[X_AXIS]); const float psi = ((float)motorPos[Y_AXIS]/stepsPerMm[Y_AXIS]) + (crosstalk[0] * theta); - machinePos[X_AXIS] = (cosf(theta * DegreesToRadians) * proximalArmLength + cosf((psi + theta) * DegreesToRadians) * distalArmLength) - xOffset; - machinePos[Y_AXIS] = (sinf(theta * DegreesToRadians) * proximalArmLength + sinf((psi + theta) * DegreesToRadians) * distalArmLength) - yOffset; + // Cache the current values so that a Z probe at this position won't fail due to rounding error when transforming the XY coordinates back + currentArmMode = cachedArmMode = (motorPos[Y_AXIS] >= 0); + cachedTheta = theta; + cachedPsi = psi; + cachedX = machinePos[X_AXIS] = (cosf(theta * DegreesToRadians) * proximalArmLength + cosf((psi + theta) * DegreesToRadians) * distalArmLength) - xOffset; + cachedY = machinePos[Y_AXIS] = (sinf(theta * DegreesToRadians) * proximalArmLength + sinf((psi + theta) * DegreesToRadians) * distalArmLength) - yOffset; // On some machines (e.g. Helios), the X and/or Y arm motors also affect the Z height machinePos[Z_AXIS] = ((float)motorPos[Z_AXIS]/stepsPerMm[Z_AXIS]) + (crosstalk[1] * theta) + (crosstalk[2] * psi); @@ -221,18 +231,7 @@ bool ScaraKinematics::IsReachable(float x, float y, bool isCoordinated) const // See if we can transform the position float theta, psi; bool armMode = currentArmMode; - const bool reachable = CalculateThetaAndPsi(coords, isCoordinated, theta, psi, armMode); - if (reachable) - { - // Save the original and transformed coordinates so that we don't need to calculate them again if we are commanded to move to this position - cachedX = x; - cachedY = y; - cachedTheta = theta; - cachedPsi = psi; - cachedArmMode = armMode; - } - - return reachable; + return CalculateThetaAndPsi(coords, isCoordinated, theta, psi, armMode); } // Limit the Cartesian position that the user wants to move to, returning true if any coordinates were changed @@ -245,12 +244,6 @@ bool ScaraKinematics::LimitPosition(float coords[], size_t numVisibleAxes, AxesB bool armMode = currentArmMode; if (CalculateThetaAndPsi(coords, isCoordinated, theta, psi, armMode)) { - // Save the original and transformed coordinates so that we don't need to calculate them again if we are commanded to move to this position - cachedX = coords[0]; - cachedY = coords[1]; - cachedTheta = theta; - cachedPsi = psi; - cachedArmMode = armMode; return m208Limited; } @@ -392,7 +385,7 @@ bool ScaraKinematics::QueryTerminateHomingMove(size_t axis) const } // This function is called from the step ISR when an endstop switch is triggered during homing after stopping just one motor or all motors. -// Take the action needed to define the current position, normally by calling dda.SetDriveCoordinate() and return false. +// Take the action needed to define the current position, normally by calling dda.SetDriveCoordinate(). void ScaraKinematics::OnHomingSwitchTriggered(size_t axis, bool highEnd, const float stepsPerMm[], DDA& dda) const { switch (axis) diff --git a/src/Movement/Move.cpp b/src/Movement/Move.cpp index bd81d352..b2a648f5 100644 --- a/src/Movement/Move.cpp +++ b/src/Movement/Move.cpp @@ -244,6 +244,7 @@ void Move::Spin() if (ddaRingAddPointer->Init(specialMoveCoords)) { ddaRingAddPointer = ddaRingAddPointer->GetNext(); + scheduledMoves++; if (moveState == MoveState::idle || moveState == MoveState::timing) { // We were previously idle, so we have a state change @@ -268,14 +269,6 @@ void Move::Spin() { if (simulationMode < 2) // in simulation mode 2 and higher, we don't process incoming moves beyond this point { -#if 0 // disabled this because it causes jerky movements on the SCARA printer - // Add on the extrusion left over from last time. - const size_t numAxes = reprap.GetGCodes().GetTotalAxes(); - for (size_t drive = numAxes; drive < DRIVES; ++drive) - { - nextMove.coords[drive] += extrusionPending[drive - numAxes]; - } -#endif if (nextMove.moveType == 0) { AxisAndBedTransform(nextMove.coords, nextMove.xAxes, nextMove.yAxes, true); @@ -284,8 +277,8 @@ void Move::Spin() if (ddaRingAddPointer->Init(nextMove, !IsRawMotorMove(nextMove.moveType))) { ddaRingAddPointer = ddaRingAddPointer->GetNext(); - idleCount = 0; scheduledMoves++; + idleCount = 0; if (moveState == MoveState::idle || moveState == MoveState::timing) { moveState = MoveState::collecting; @@ -298,14 +291,6 @@ void Move::Spin() lastStateChangeTime = now; } } - -#if 0 // see above - // Save the amount of extrusion not done - for (size_t drive = numAxes; drive < DRIVES; ++drive) - { - extrusionPending[drive - numAxes] = nextMove.coords[drive]; - } -#endif } } } @@ -338,7 +323,7 @@ void Move::Spin() #endif ) { - dda->Prepare(simulationMode); + dda->Prepare(simulationMode, extrusionPending); } if (dda->GetState() == DDA::frozen) { @@ -402,7 +387,7 @@ void Move::Spin() #endif ) { - cdda->Prepare(simulationMode); + cdda->Prepare(simulationMode, extrusionPending); } preparedTime += cdda->GetTimeLeft(); ++preparedCount; @@ -569,9 +554,16 @@ bool Move::LowPowerOrStallPause(RestorePoint& rp) { // We are executing a move that has a file address, so we can interrupt it StepTimer::DisableStepInterrupt(); +#if SUPPORT_LASER + if (reprap.GetGCodes().GetMachineType() == MachineType::laser) + { + reprap.GetPlatform().SetLaserPwm(0); + } +#endif dda->MoveAborted(); CurrentMoveCompleted(); // updates live endpoints, extrusion, ddaRingGetPointer, currentDda etc. --completedMoves; // this move wasn't really completed + --scheduledMoves; // ...but it is no longer scheduled either abortedMove = true; } else @@ -720,13 +712,13 @@ void Move::EndPointToMachine(const float coords[], int32_t ep[], size_t numDrive const size_t numAxes = reprap.GetGCodes().GetTotalAxes(); for (size_t drive = numAxes; drive < numDrives; ++drive) { - ep[drive] = MotorEndPointToMachine(drive, coords[drive]); + ep[drive] = MotorMovementToSteps(drive, coords[drive]); } } } // Convert distance to steps for a particular drive -int32_t Move::MotorEndPointToMachine(size_t drive, float coord) +int32_t Move::MotorMovementToSteps(size_t drive, float coord) { return lrintf(coord * reprap.GetPlatform().DriveStepsPerUnit(drive)); } @@ -744,16 +736,16 @@ bool Move::CartesianToMotorSteps(const float machinePos[MaxAxes], int32_t motorP { const bool b = kinematics->CartesianToMotorSteps(machinePos, reprap.GetPlatform().GetDriveStepsPerUnit(), reprap.GetGCodes().GetVisibleAxes(), reprap.GetGCodes().GetTotalAxes(), motorPos, isCoordinated); - if (reprap.Debug(moduleMove) && reprap.Debug(moduleDda)) + if (b) { - if (b) + if (reprap.Debug(moduleMove) && reprap.Debug(moduleDda)) { debugPrintf("Transformed %.2f %.2f %.2f to %" PRIu32 " %" PRIu32 " %" PRIu32 "\n", (double)machinePos[0], (double)machinePos[1], (double)machinePos[2], motorPos[0], motorPos[1], motorPos[2]); } - else - { - debugPrintf("Unable to transform %.2f %.2f %.2f\n", (double)machinePos[0], (double)machinePos[1], (double)machinePos[2]); - } + } + else if (reprap.Debug(moduleMove)) + { + debugPrintf("Unable to transform %.2f %.2f %.2f\n", (double)machinePos[0], (double)machinePos[1], (double)machinePos[2]); } return b; } @@ -1129,7 +1121,7 @@ void Move::GetCurrentMachinePosition(float m[MaxAxes], bool disableMotorMapping) } } -/*static*/ float Move::MotorEndpointToPosition(int32_t endpoint, size_t drive) +/*static*/ float Move::MotorStepsToMovement(size_t drive, int32_t endpoint) { return ((float)(endpoint))/reprap.GetPlatform().DriveStepsPerUnit(drive); } diff --git a/src/Movement/Move.h b/src/Movement/Move.h index 68f1984b..8792305e 100644 --- a/src/Movement/Move.h +++ b/src/Movement/Move.h @@ -150,8 +150,8 @@ public: uint32_t GetStepInterval(size_t axis, uint32_t microstepShift) const; // Get the current step interval for this axis or extruder #endif - static int32_t MotorEndPointToMachine(size_t drive, float coord); // Convert a single motor position to number of steps - static float MotorEndpointToPosition(int32_t endpoint, size_t drive); // Convert number of motor steps to motor position + static int32_t MotorMovementToSteps(size_t drive, float coord); // Convert a single motor position to number of steps + static float MotorStepsToMovement(size_t drive, int32_t endpoint); // Convert number of motor steps to motor position protected: DECLARE_OBJECT_MODEL diff --git a/src/Movement/StepTimer.cpp b/src/Movement/StepTimer.cpp index 8b275588..c09bccc7 100644 --- a/src/Movement/StepTimer.cpp +++ b/src/Movement/StepTimer.cpp @@ -16,8 +16,8 @@ #if SAM4S || SAME70 // Static data used by step ISR -volatile uint32_t stepTimerPendingStatus = 0; // for holding status bits that we have read (and therefore cleared) but haven't serviced yet -volatile uint32_t stepTimerHighWord = 0; // upper 16 bits of step timer +static volatile uint32_t stepTimerPendingStatus = 0; // for holding status bits that we have read (and therefore cleared) but haven't serviced yet +static volatile uint32_t stepTimerHighWord = 0; // upper 16 bits of step timer #endif namespace StepTimer @@ -85,6 +85,14 @@ namespace StepTimer return (lowWord & 0x0000FFFF) | highWord; } +#else + + // Get the interrupt clock count. Despite the name, on these processors we don't need to disable interrupts before calling this. + uint32_t GetInterruptClocksInterruptsDisabled() + { + return STEP_TC->TC_CHANNEL[STEP_TC_CHAN].TC_CV; + } + #endif // Schedule an interrupt at the specified clock count, or return true if that time is imminent or has passed already. diff --git a/src/Movement/StepTimer.h b/src/Movement/StepTimer.h index b82a11c1..3818f3b1 100644 --- a/src/Movement/StepTimer.h +++ b/src/Movement/StepTimer.h @@ -19,11 +19,13 @@ namespace StepTimer void Init(); -#if SAM4S || SAME70 // if the TCs are 16-bit - - // Function GetInterruptClocksInterruptsDisabled() is quite long for these processors, so it is moved to StepTimer.cpp and no longer inlined + // Function GetInterruptClocksInterruptsDisabled() is quite long for SAM4S and SAME70 processors, so it is moved to StepTimer.cpp and no longer inlined + // On other processor we have had trouble with the compiler moving instructions around too much when it is inlined. + // So we don't inline it any more. uint32_t GetInterruptClocksInterruptsDisabled() __attribute__ ((hot)); // Get the interrupt clock count, when we know already that interrupts are disabled +#if SAM4S || SAME70 // if the TCs are 16-bit + // Get the interrupt clock count static inline uint32_t GetInterruptClocks() { @@ -38,13 +40,7 @@ namespace StepTimer // Get the interrupt clock count static inline uint32_t GetInterruptClocks() { - return STEP_TC->TC_CHANNEL[STEP_TC_CHAN].TC_CV; - } - - // Get the interrupt clock count, when we know that interrupts are already disabled - static inline uint32_t GetInterruptClocksInterruptsDisabled() - { - return STEP_TC->TC_CHANNEL[STEP_TC_CHAN].TC_CV; + return GetInterruptClocksInterruptsDisabled(); // no need to disable interrupts on these processors } #endif diff --git a/src/ObjectModel/ObjectModel.cpp b/src/ObjectModel/ObjectModel.cpp index 44c579b1..d8ead242 100644 --- a/src/ObjectModel/ObjectModel.cpp +++ b/src/ObjectModel/ObjectModel.cpp @@ -117,7 +117,7 @@ void ObjectModelTableEntry::ReportItemAsJson(OutputBuffer *buf, const char *filt break; case TYPE_OF(const char*): - buf->EncodeString((const char*)nParam, strlen((const char*)nParam), true, true, false); + buf->EncodeString((const char*)nParam, true); break; case TYPE_OF(Bitmap32): diff --git a/src/Pccb/Pins_Pccb.h b/src/Pccb/Pins_Pccb.h index 23d3d5a7..362ae1c9 100644 --- a/src/Pccb/Pins_Pccb.h +++ b/src/Pccb/Pins_Pccb.h @@ -79,7 +79,7 @@ constexpr size_t NUM_SERIAL_CHANNELS = 1; // The number of serial IO channels #define SERIAL_MAIN_DEVICE SerialUSB // SerialUSB -constexpr Pin UsbVBusPin = 47; // Pin used to monitor VBUS on USB port +constexpr Pin UsbVBusPin = PortCPin(11); // Pin used to monitor VBUS on USB port #define I2C_IFACE Wire // First and only I2C interface #define I2C_IRQn WIRE_ISR_ID @@ -91,10 +91,10 @@ constexpr Pin GlobalTmc22xxEnablePin = 1; // The pin that drives ENN of all in #ifdef PCCB_X5 -constexpr Pin GlobalTmc2660EnablePin = 52; // The pin that drives ENN of all drivers on the DueX5 -constexpr Pin ENABLE_PINS[NumDirectDrivers] = { 61, 35, 41, 55, 0, 64 }; -constexpr Pin STEP_PINS[NumDirectDrivers] = { 60, 38, 58, 56, 46, 50 }; -constexpr Pin DIRECTION_PINS[NumDirectDrivers] = { 17, 57, 54, 34, 1, 53 }; +constexpr Pin GlobalTmc2660EnablePin = PortCPin(16); // The pin that drives ENN of all drivers on the DueX5 +constexpr Pin ENABLE_PINS[NumDirectDrivers] = { PortBPin(14), PortCPin(25), PortCPin( 5), PortCPin(19), PortAPin( 0), PortCPin(28) }; +constexpr Pin STEP_PINS[NumDirectDrivers] = { PortCPin(24), PortCPin( 2), PortCPin(22), PortCPin(20), PortCPin(10), PortCPin(14) }; +constexpr Pin DIRECTION_PINS[NumDirectDrivers] = { PortAPin(17), PortCPin(21), PortCPin(18), PortCPin(13), PortAPin( 1), PortCPin(17) }; Spi * const SPI_TMC2660 = SPI; constexpr uint32_t ID_TMC2660_SPI = ID_SPI; @@ -102,15 +102,15 @@ constexpr IRQn TMC2660_SPI_IRQn = SPI_IRQn; # define TMC2660_SPI_Handler SPI_Handler // Pin assignments, using USART1 in SPI mode -constexpr Pin TMC2660MosiPin = 13; // PA13 -constexpr Pin TMC2660MisoPin = 12; // PA12 -constexpr Pin TMC2660SclkPin = 14; // PA14 +constexpr Pin TMC2660MosiPin = PortAPin(13); +constexpr Pin TMC2660MisoPin = PortAPin(12); +constexpr Pin TMC2660SclkPin = PortAPin(14); #else -constexpr Pin ENABLE_PINS[NumDirectDrivers] = { NoPin, NoPin, 61, 35, 41, 55, 0, 64 }; -constexpr Pin STEP_PINS[NumDirectDrivers] = { 40, 43, 60, 38, 58, 56, 46, 50 }; -constexpr Pin DIRECTION_PINS[NumDirectDrivers] = { 8, 11, 17, 57, 54, 34, 1, 53 }; +constexpr Pin ENABLE_PINS[NumDirectDrivers] = { NoPin, NoPin, PortBPin(14), PortCPin(25), PortCPin( 5), PortCPin(19), PortAPin( 0), PortCPin(28) }; +constexpr Pin STEP_PINS[NumDirectDrivers] = { PortCPin( 4), PortCPin( 7), PortCPin(24), PortCPin( 2), PortCPin(22), PortCPin(20), PortCPin(10), PortCPin(14) }; +constexpr Pin DIRECTION_PINS[NumDirectDrivers] = { PortAPin( 8), PortAPin(11), PortAPin(17), PortCPin(21), PortCPin(18), PortCPin(13), PortAPin( 1), PortCPin(17) }; Uart * const TMC22xxUarts[MaxSmartDrivers] = { UART0, UART1 }; constexpr uint32_t TMC22xxUartIds[MaxSmartDrivers] = { ID_UART0, ID_UART1 }; @@ -135,13 +135,13 @@ const uint32_t TransferTimeout = 10; // any transfer should complete within // Endstops // RepRapFirmware only has a single endstop per axis. // Gcode defines if it is a max ("high end") or min ("low end") endstop and sets if it is active HIGH or LOW. -constexpr Pin END_STOP_PINS[NumEndstops] = { 25, 67, 24, 63 }; +constexpr Pin END_STOP_PINS[NumEndstops] = { PortAPin(24), PortAPin(25), PortCPin(31), PortCPin(27) }; // Heaters and thermistors -constexpr Pin HEAT_ON_PINS[NumHeaters] = { 36, 59 }; // these are actually the LED control pins -constexpr Pin TEMP_SENSE_PINS[NumThermistorInputs] = { 20, 49 }; // Thermistor pin numbers -constexpr Pin VssaSensePin = 19; -constexpr Pin VrefSensePin = 27; +constexpr Pin HEAT_ON_PINS[NumHeaters] = { PortCPin(0), PortCPin(23) }; // these are actually the LED control pins +constexpr Pin TEMP_SENSE_PINS[NumThermistorInputs] = { PortAPin(20), PortCPin(13) }; // thermistor pin numbers +constexpr Pin VssaSensePin = PortAPin(19); +constexpr Pin VrefSensePin = PortBPin(1); // Default thermistor parameters - on PCCB we default both thermistors to the same parameters constexpr float BED_R25 = 100000.0; @@ -158,14 +158,14 @@ constexpr float THERMISTOR_SERIES_RS = 2200.0; constexpr size_t MaxSpiTempSensors = 1; //TODO which SPI channels does PCCB route to the DueX? // Digital pins the 31855s have their select lines tied to -constexpr Pin SpiTempSensorCsPins[MaxSpiTempSensors] = { 63 }; // SPI0_CS6 if a DueX5 is connected +constexpr Pin SpiTempSensorCsPins[MaxSpiTempSensors] = { PortCPin(27) }; // SPI0_CS6 if a DueX5 is connected // Pin that controls the ATX power on/off constexpr Pin ATX_POWER_PIN = NoPin; // Analogue pin numbers constexpr Pin Z_PROBE_PIN = NoPin; // Z probe analog input -constexpr Pin PowerMonitorVinDetectPin = 48; // Vin monitor +constexpr Pin PowerMonitorVinDetectPin = PortCPin(12); // Vin monitor constexpr float PowerMonitorVoltageRange = 11.0 * 3.3; // We use an 11:1 voltage divider // Digital pin number to turn the IR LED on (high) or off (low), also controls the DIAG LED @@ -175,24 +175,24 @@ constexpr Pin DiagPin = NoPin; // Cooling fans constexpr size_t NUM_FANS = 4; constexpr size_t NumTachos = 2; -constexpr Pin COOLING_FAN_PINS[NUM_FANS] = { 16, 39, 15, 37 }; // PWML2, PWML3, TIOA1, PWML1 -constexpr Pin TachoPins[NumTachos] = { 26, 66 }; +constexpr Pin COOLING_FAN_PINS[NUM_FANS] = { PortAPin(16), PortCPin(3), PortAPin(15), PortCPin(1) }; // PWML2, PWML3, TIOA1, PWML1 +constexpr Pin TachoPins[NumTachos] = { PortBPin(0), PortCPin(30) }; // Main LED control constexpr size_t NumLeds = 2; // number of main LEDs -constexpr Pin LedOnPins[NumLeds] = { 36, 59 }; // LED control pins +constexpr Pin LedOnPins[NumLeds] = { PortCPin(0), PortCPin(23) }; // LED control pins // DotStar LED control (USART0 is SharedSPI, Usart * const DotStarUsart = USART1; constexpr uint32_t DotStarUsartId = ID_USART1; -constexpr Pin DotStarMosiPin = 22; -constexpr Pin DotStarSclkPin = 23; +constexpr Pin DotStarMosiPin = PortAPin(22); +constexpr Pin DotStarSclkPin = PortAPin(23); constexpr IRQn DotStarUsartIRQn = USART1_IRQn; const uint32_t DotStarSpiClockFrequency = 100000; // try sending at 100kHz // SD cards constexpr size_t NumSdCards = 1; -constexpr Pin SdCardDetectPins[NumSdCards] = { 44 }; +constexpr Pin SdCardDetectPins[NumSdCards] = { PortCPin(8) }; constexpr Pin SdWriteProtectPins[NumSdCards] = { NoPin }; constexpr Pin SdSpiCSPins[1] = { NoPin }; constexpr uint32_t ExpectedSdCardSpeed = 15000000; @@ -202,10 +202,10 @@ constexpr uint32_t ExpectedSdCardSpeed = 15000000; // This is the mapping from logical pins 60+ to firmware pin numbers constexpr Pin SpecialPinMap[] = { - 18, 21, 51, 59, 62, 65 // PA18/AD1, PA21/AD8, PC15/AD11, PC22, PC23, PC29 + PortAPin(18), PortAPin(21), PortCPin(15), PortCPin(29) // PA18/AD1, PA21/AD8, PC15/AD11, PC29 }; -constexpr int HighestLogicalPin = 65; // highest logical pin number on this electronics +constexpr int HighestLogicalPin = 63; // highest logical pin number on this electronics // SAM4S Flash locations (may be expanded in the future) constexpr uint32_t IAP_FLASH_START = 0x00470000; diff --git a/src/Platform.cpp b/src/Platform.cpp index 40cb2273..f149baf8 100644 --- a/src/Platform.cpp +++ b/src/Platform.cpp @@ -345,8 +345,8 @@ void Platform::Init() // AXES for (size_t axis = 0; axis < MaxAxes; ++axis) { - axisMinima[axis] = 0.0; - axisMaxima[axis] = 200.0; + axisMinima[axis] = DefaultAxisMinimum; + axisMaxima[axis] = DefaultAxisMaximum; } axisMaximaProbed = axisMinimaProbed = 0; @@ -400,7 +400,7 @@ void Platform::Init() } } - for (size_t endstop = 0; endstop < NumEndstops; ++endstop) + for (Pin p : endStopPins) { #if defined(DUET_NG) || defined(DUET_06_085) || defined(__RADDS__) || defined(__ALLIGATOR__) // Enable pullup resistors on endstop inputs here if necessary. @@ -411,9 +411,9 @@ void Platform::Init() // Note: if we don't have a DueX board connected, the pullups on endstop inputs 5-9 must always be enabled. // Also the pullups on endstop inputs 10-11 must always be enabled. // I don't know whether RADDS and Alligator have hardware pullup resistors or not. I'll assume they might not. - pinMode(endStopPins[endstop], INPUT_PULLUP); // enable pullup on endstop input + pinMode(p, INPUT_PULLUP); // enable pullup on endstop input #else - pinMode(endStopPins[endstop], INPUT); // don't enable pullup on endstop input + pinMode(p, INPUT); // don't enable pullup on endstop input #endif } @@ -521,15 +521,15 @@ void Platform::Init() // Enable pullups on all the SPI CS pins. This is required if we are using more than one device on the SPI bus. // Otherwise, when we try to initialise the first device, the other devices may respond as well because their CS lines are not high. - for (size_t i = 0; i < MaxSpiTempSensors; ++i) + for (Pin p : SpiTempSensorCsPins) { - setPullup(SpiTempSensorCsPins[i], true); + pinMode(p, INPUT_PULLUP); } - for (size_t heater = 0; heater < NumHeaters; heater++) + for (Pin p : HEAT_ON_PINS) { // pinMode is safe to call when the pin is NoPin, so we don't need to check it here - pinMode(HEAT_ON_PINS[heater], + pinMode(p, #if ACTIVE_LOW_HEAT_ON OUTPUT_HIGH #else @@ -1415,7 +1415,7 @@ void Platform::Spin() // The driver often produces a transient open-load error, especially in stealthchop mode, so we require the condition to persist before we report it. // Also, false open load indications persist when in standstill, if the phase has zero current in that position - if ((stat & TMC_RR_OLA) != 0) + if ((stat & TMC_RR_OLA) != 0 && motorCurrents[nextDriveToPoll] * motorCurrentFraction[nextDriveToPoll] >= MinimumOpenLoadMotorCurrent) { if (!openLoadATimer.IsRunning()) { @@ -1433,7 +1433,7 @@ void Platform::Spin() } } - if ((stat & TMC_RR_OLB) != 0) + if ((stat & TMC_RR_OLB) != 0 && motorCurrents[nextDriveToPoll] * motorCurrentFraction[nextDriveToPoll] >= MinimumOpenLoadMotorCurrent) { if (!openLoadBTimer.IsRunning()) { @@ -1906,9 +1906,9 @@ void Platform::SoftwareReset(uint16_t reason, const uint32_t *stk) if (stk != nullptr) { srdBuf[slot].sp = reinterpret_cast<uint32_t>(stk); - for (size_t i = 0; i < ARRAY_SIZE(srdBuf[slot].stack); ++i) + for (uint32_t& stval : srdBuf[slot].stack) { - srdBuf[slot].stack[i] = (stk < &_estack) ? *stk : 0xFFFFFFFF; + stval = (stk < &_estack) ? *stk : 0xFFFFFFFF; ++stk; } } @@ -2235,9 +2235,9 @@ void Platform::Diagnostics(MessageType mtype) { // We saved a stack dump, so print it scratchString.Clear(); - for (size_t i = 0; i < ARRAY_SIZE(srdBuf[slot].stack); ++i) + for (uint32_t stval : srdBuf[slot].stack) { - scratchString.catf(" %08" PRIx32, srdBuf[slot].stack[i]); + scratchString.catf(" %08" PRIx32, stval); } MessageF(mtype, "Stack:%s\n", scratchString.c_str()); } @@ -2285,7 +2285,7 @@ void Platform::Diagnostics(MessageType mtype) // Show the motor stall status for (size_t drive = 0; drive < numSmartDrivers; ++drive) { - String<100> driverStatus; + String<MediumStringLength> driverStatus; SmartDrivers::AppendDriverStatus(drive, driverStatus.GetRef()); MessageF(mtype, "Driver %u:%s\n", drive, driverStatus.c_str()); } diff --git a/src/Tasks.cpp b/src/Tasks.cpp index 2f739d59..675a7a4d 100644 --- a/src/Tasks.cpp +++ b/src/Tasks.cpp @@ -28,7 +28,7 @@ extern char _end; // The main task currently runs GCodes, so it needs to be large enough to hold the matrices used for auto calibration. // The timer and idle tasks currently never do I/O, so they can be much smaller. -constexpr unsigned int MainTaskStackWords = 2040; +constexpr unsigned int MainTaskStackWords = 1600; constexpr unsigned int IdleTaskStackWords = 60; static Task<IdleTaskStackWords> idleTask; diff --git a/src/Version.h b/src/Version.h index e22999ec..19c0d8ea 100644 --- a/src/Version.h +++ b/src/Version.h @@ -12,7 +12,7 @@ #ifndef VERSION #ifdef RTOS # define RTOSVER "(RTOS)" -# define MAIN_VERSION "2.02RC5" +# define MAIN_VERSION "2.02RC6" #else # define MAIN_VERSION "1.22" # define RTOSVER @@ -22,7 +22,7 @@ #endif #ifndef DATE -# define DATE "2018-11-28b1" +# define DATE "2018-12-15b2" #endif #define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman, printm3d" |