diff options
32 files changed, 1310 insertions, 342 deletions
@@ -840,6 +840,127 @@ </storageModule> <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> </cconfiguration> + <cconfiguration id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786.1798324396.239853003"> + <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786.1798324396.239853003" moduleId="org.eclipse.cdt.core.settings" name="PCCB_X5"> + <macros> + <stringMacro name="LinkFlags2" type="VALUE_TEXT" value="-Wl,--end-group -lm"/> + <stringMacro name="LinkFlags1" type="VALUE_TEXT" value="-mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group"/> + <stringMacro name="CoreName" type="VALUE_TEXT" value="CoreNG"/> + <stringMacro name="GccPath" type="VALUE_TEXT" value="C:\Program Files (x86)\GNU Tools ARM Embedded\7 2018-q2-update\bin"/> + </macros> + <externalSettings/> + <extensions> + <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/> + <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + </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"> + <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"/> + <option id="cdt.managedbuild.option.gnu.cross.prefix.2115296403" name="Prefix" superClass="cdt.managedbuild.option.gnu.cross.prefix" useByScannerDiscovery="false" value="arm-none-eabi-" valueType="string"/> + <targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.targetPlatform.gnu.cross.650998352" isAbstract="false" osList="all" superClass="cdt.managedbuild.targetPlatform.gnu.cross"/> + <builder buildPath="${workspace_loc:/RepRapFirmware}/Release" id="cdt.managedbuild.builder.gnu.cross.2109049020" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" parallelBuildOn="true" parallelizationNumber="optimal" superClass="cdt.managedbuild.builder.gnu.cross"/> + <tool id="cdt.managedbuild.tool.gnu.cross.assembler.1562151564" name="Cross GCC Assembler" superClass="cdt.managedbuild.tool.gnu.cross.assembler"> + <inputType id="cdt.managedbuild.tool.gnu.assembler.input.421833380" superClass="cdt.managedbuild.tool.gnu.assembler.input"/> + </tool> + <tool commandLinePattern="${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}" id="cdt.managedbuild.tool.gnu.cross.c.compiler.907968158" name="Cross GCC Compiler" superClass="cdt.managedbuild.tool.gnu.cross.c.compiler"> + <option defaultValue="gnu.c.optimization.level.most" id="gnu.c.compiler.option.optimization.level.1879548421" name="Optimization Level" superClass="gnu.c.compiler.option.optimization.level" useByScannerDiscovery="false" value="gnu.c.optimization.level.more" valueType="enumerated"/> + <option id="gnu.c.compiler.option.debugging.level.1798838148" name="Debug Level" superClass="gnu.c.compiler.option.debugging.level" useByScannerDiscovery="false" value="gnu.c.debugging.level.none" valueType="enumerated"/> + <option id="gnu.c.compiler.option.misc.verbose.1017329274" name="Verbose (-v)" superClass="gnu.c.compiler.option.misc.verbose" useByScannerDiscovery="false" value="false" valueType="boolean"/> + <option id="gnu.c.compiler.option.misc.other.1392314364" name="Other flags" superClass="gnu.c.compiler.option.misc.other" useByScannerDiscovery="false" value="-c -std=gnu99 -mcpu=cortex-m4 -mthumb -ffunction-sections -fdata-sections -nostdlib -Wdouble-promotion -fsingle-precision-constant "-Wa,-ahl=$*.s"" valueType="string"/> + <option id="gnu.c.compiler.option.include.paths.712616825" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath"> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/cores/arduino}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/libraries/Storage}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/asf}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/asf/common/utils}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/asf/common/services/ioport}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/asf/sam/drivers}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/asf/sam/utils}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/asf/sam/utils/cmsis/sam4s/include}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/asf/sam/utils/header_files}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/asf/sam/utils/preprocessor}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/asf/thirdparty/CMSIS/Include}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/variants/sam4s}""/> + </option> + <option id="gnu.c.compiler.option.preprocessor.def.symbols.1475180073" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" useByScannerDiscovery="false" valueType="definedSymbols"> + <listOptionValue builtIn="false" value="__SAM4S8C__"/> + <listOptionValue builtIn="false" value="RTOS"/> + <listOptionValue builtIn="false" value="PCCB"/> + <listOptionValue builtIn="false" value="PCCB_X5"/> + </option> + <inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1120814753" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/> + </tool> + <tool id="cdt.managedbuild.tool.gnu.cross.c.linker.1936542357" name="Cross GCC Linker" superClass="cdt.managedbuild.tool.gnu.cross.c.linker"/> + <tool id="cdt.managedbuild.tool.gnu.cross.archiver.1577761657" name="Cross GCC Archiver" superClass="cdt.managedbuild.tool.gnu.cross.archiver"/> + <tool command="gcc" commandLinePattern="${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${LinkFlags1} "${workspace_loc}/${CoreName}/SAM4S_RTOS/cores/arduino/syscalls.o" ${INPUTS} ${LinkFlags2}" id="cdt.managedbuild.tool.gnu.cross.cpp.linker.523461887" name="Cross G++ Linker" superClass="cdt.managedbuild.tool.gnu.cross.cpp.linker"> + <option id="gnu.cpp.link.option.nostdlibs.1674515330" name="No startup or default libs (-nostdlib)" superClass="gnu.cpp.link.option.nostdlibs" useByScannerDiscovery="false" value="false" valueType="boolean"/> + <option id="gnu.cpp.link.option.paths.144825348" name="Library search path (-L)" superClass="gnu.cpp.link.option.paths" useByScannerDiscovery="false" valueType="libPaths"> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/SAM4S_RTOS_PCCB/}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/FreeRTOS/SAM4S}""/> + </option> + <option id="gnu.cpp.link.option.libs.1538113275" name="Libraries (-l)" superClass="gnu.cpp.link.option.libs" useByScannerDiscovery="false" valueType="libs"> + <listOptionValue builtIn="false" value="${CoreName}"/> + <listOptionValue builtIn="false" value="FreeRTOS"/> + </option> + <option id="gnu.cpp.link.option.flags.1106600671" name="Linker flags" superClass="gnu.cpp.link.option.flags" useByScannerDiscovery="false" value="-Os --specs=nano.specs -Wl,--gc-sections -Wl,--fatal-warnings -mcpu=cortex-m4 -T${workspace_loc:/${CoreName}/variants/sam4s/linker_scripts/gcc/flash.ld} -Wl,-Map,${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.map" valueType="string"/> + <inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.180173717" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input"> + <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/> + <additionalInput kind="additionalinput" paths="$(LIBS)"/> + </inputType> + </tool> + <tool command="g++" id="cdt.managedbuild.tool.gnu.cross.cpp.compiler.265237939" name="Cross G++ Compiler" superClass="cdt.managedbuild.tool.gnu.cross.cpp.compiler"> + <option id="gnu.cpp.compiler.option.optimization.level.1022715653" name="Optimization Level" superClass="gnu.cpp.compiler.option.optimization.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.optimization.level.more" valueType="enumerated"/> + <option id="gnu.cpp.compiler.option.debugging.level.746816525" name="Debug Level" superClass="gnu.cpp.compiler.option.debugging.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/> + <option id="gnu.cpp.compiler.option.other.verbose.628173646" name="Verbose (-v)" superClass="gnu.cpp.compiler.option.other.verbose" useByScannerDiscovery="false" value="false" valueType="boolean"/> + <option id="gnu.cpp.compiler.option.other.other.195351069" name="Other flags" superClass="gnu.cpp.compiler.option.other.other" useByScannerDiscovery="false" value="-c -std=gnu++14 -mcpu=cortex-m4 -mthumb -ffunction-sections -fdata-sections -fno-threadsafe-statics -fno-rtti -fno-exceptions -nostdlib -Wdouble-promotion -fsingle-precision-constant "-Wa,-ahl=$*.s"" valueType="string"/> + <option id="gnu.cpp.compiler.option.include.paths.1437187820" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath"> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/cores/arduino}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/libraries/Flash}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/libraries/SharedSpi}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/libraries/Storage}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/libraries/Wire}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/asf}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/asf/common/utils}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/asf/common/services/clock}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/asf/common/services/ioport}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/asf/sam/drivers}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/asf/sam/services/flash_efc}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/asf/sam/utils}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/asf/sam/utils/cmsis/sam4s/include}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/asf/sam/utils/header_files}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/asf/sam/utils/preprocessor}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/asf/thirdparty/CMSIS/Include}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${CoreName}/variants/sam4s}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/src}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/src/Pccb}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/DuetWiFiSocketServer/src/include}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/FreeRTOS/src/include}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/FreeRTOS/src/portable/GCC/ARM_CM3}""/> + </option> + <option id="gnu.cpp.compiler.option.preprocessor.def.900153856" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" useByScannerDiscovery="false" valueType="definedSymbols"> + <listOptionValue builtIn="false" value="__SAM4S8C__"/> + <listOptionValue builtIn="false" value="RTOS"/> + <listOptionValue builtIn="false" value="PCCB"/> + <listOptionValue builtIn="false" value="PCCB_X5"/> + <listOptionValue builtIn="false" value="_XOPEN_SOURCE"/> + </option> + <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.940275677" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/> + </tool> + </toolChain> + </folderInfo> + <sourceEntries> + <entry excluding="src/DuetM|src/Display|src/Networking|src/Alligator|src/SAME70_TEST|src/Duet|src/Networking/ESP8266WiFi|src/Networking/LwipEthernet|src/DuetNG|src/RADDS" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/> + </sourceEntries> + </configuration> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> + </cconfiguration> </storageModule> <storageModule moduleId="cdtBuildSystem" version="4.0.0"> <project id="RepRapFirmware.cdt.managedbuild.target.gnu.cross.exe.1494358155" name="Executable" projectType="cdt.managedbuild.target.gnu.cross.exe"/> diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml index 93f91cfc..4f109f3e 100644 --- a/.settings/language.settings.xml +++ b/.settings/language.settings.xml @@ -5,7 +5,7 @@ <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/> <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/> <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/> - <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-102132239664010639" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true"> + <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-284248688145585500" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true"> <language-scope id="org.eclipse.cdt.core.gcc"/> <language-scope id="org.eclipse.cdt.core.g++"/> </provider> @@ -16,7 +16,7 @@ <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/> <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/> <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/> - <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-102132239664010639" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true"> + <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-284248688145585500" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true"> <language-scope id="org.eclipse.cdt.core.gcc"/> <language-scope id="org.eclipse.cdt.core.g++"/> </provider> @@ -27,7 +27,7 @@ <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/> <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/> <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/> - <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-102132239664010639" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true"> + <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-284248688145585500" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true"> <language-scope id="org.eclipse.cdt.core.gcc"/> <language-scope id="org.eclipse.cdt.core.g++"/> </provider> @@ -38,7 +38,7 @@ <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/> <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/> <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/> - <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-102132239664010639" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true"> + <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-284248688145585500" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true"> <language-scope id="org.eclipse.cdt.core.gcc"/> <language-scope id="org.eclipse.cdt.core.g++"/> </provider> @@ -49,7 +49,7 @@ <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/> <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/> <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/> - <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-102132239664010639" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true"> + <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-284248688145585500" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true"> <language-scope id="org.eclipse.cdt.core.gcc"/> <language-scope id="org.eclipse.cdt.core.g++"/> </provider> @@ -60,7 +60,7 @@ <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/> <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/> <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/> - <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-102132239664010639" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true"> + <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-284248688145585500" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true"> <language-scope id="org.eclipse.cdt.core.gcc"/> <language-scope id="org.eclipse.cdt.core.g++"/> </provider> @@ -71,7 +71,18 @@ <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/> <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/> <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/> - <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-102132239664010639" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true"> + <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-284248688145585500" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true"> + <language-scope id="org.eclipse.cdt.core.gcc"/> + <language-scope id="org.eclipse.cdt.core.g++"/> + </provider> + </extension> + </configuration> + <configuration id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786.1798324396.239853003" name="PCCB_X5"> + <extension point="org.eclipse.cdt.core.LanguageSettingsProvider"> + <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/> + <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/> + <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/> + <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-284248688145585500" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true"> <language-scope id="org.eclipse.cdt.core.gcc"/> <language-scope id="org.eclipse.cdt.core.g++"/> </provider> diff --git a/src/BugList.txt b/src/BugList.txt index 8d62eb94..8bbbc24b 100644 --- a/src/BugList.txt +++ b/src/BugList.txt @@ -258,6 +258,7 @@ Bug fixes/investigations for 2.02beta3: Other: Planned for 2.02: +- Still doesn't always find the DueX5, see https://forum.duet3d.com/topic/6239/unstable-after-firmware-upgrade/3. Is the Heat task affecting the timing? Need new I2C driver? - @wilriker PR for M106 PWM limit - WiFi continuous auto reconnect in client mode, or extra M552 parameter? See https://forum.duet3d.com/topic/5765/wifi-module-auto-reconnect - Better dead time measurement during auto tuning. Measure both turn-on and turn-off? diff --git a/src/DuetM/Pins_DuetM.h b/src/DuetM/Pins_DuetM.h index f59ec75c..bc489001 100644 --- a/src/DuetM/Pins_DuetM.h +++ b/src/DuetM/Pins_DuetM.h @@ -63,18 +63,17 @@ constexpr size_t NUM_SERIAL_CHANNELS = 2; // The number of serial IO channels // The numbers of entries in each array must correspond with the values of DRIVES, AXES, or HEATERS. Set values to NoPin to flag unavailability. // Drivers -constexpr Pin GlobalTmcEnablePin = 1; // The pin that drives ENN of all drivers +constexpr Pin GlobalTmc22xxEnablePin = 1; // The pin that drives ENN of all drivers constexpr Pin ENABLE_PINS[DRIVES] = { NoPin, NoPin, NoPin, NoPin, NoPin, 63, 61 }; constexpr Pin STEP_PINS[DRIVES] = { 56, 38, 64, 40, 41, 67, 57 }; constexpr Pin DIRECTION_PINS[DRIVES] = { 54, 8, 30, 33, 42, 18, 60 }; // UART interface to stepper drivers -Uart * const UART_TMC_DRV = UART0; -const IRQn UART_TMC_DRV_IRQn = UART0_IRQn; -const uint32_t ID_UART_TMC_DRV = ID_UART0; -const uint8_t UART_TMC_DRV_PINS = APINS_UART0; - -#define UART_TMC_DRV_Handler UART0_Handler +Uart * const UART_TMC22xx = UART0; +const IRQn TMC22xx_UART_IRQn = UART0_IRQn; +const uint32_t ID_TMC22xx_UART = ID_UART0; +const uint8_t TMC22xx_UART_PINS = APINS_UART0; +#define TMC22xx_UART_Handler UART0_Handler // Define the baud rate used to send/receive data to/from the drivers. // If we assume a worst case clock frequency of 8MHz then the maximum baud rate is 8MHz/16 = 500kbaud. @@ -85,7 +84,7 @@ const uint8_t UART_TMC_DRV_PINS = APINS_UART0; const uint32_t DriversBaudRate = 200000; const uint32_t TransferTimeout = 10; // any transfer should complete within 10 ticks @ 1ms/tick -constexpr Pin DriverMuxPins[3] = { 50, 52, 53 }; // Pins that control the UART multiplexer, LSB first +constexpr Pin TMC22xxMuxPins[3] = { 50, 52, 53 }; // Pins that control the UART multiplexer, LSB first // Endstops // RepRapFirmware only has a single endstop per axis. diff --git a/src/DuetNG/Pins_DuetNG.h b/src/DuetNG/Pins_DuetNG.h index 8d4f7334..358c8301 100644 --- a/src/DuetNG/Pins_DuetNG.h +++ b/src/DuetNG/Pins_DuetNG.h @@ -17,6 +17,7 @@ constexpr size_t NumFirmwareUpdateModules = 4; // 3 modules, plus one for manua #define HAS_CPU_TEMP_SENSOR 1 #define HAS_HIGH_SPEED_SD 1 #define SUPPORT_TMC2660 1 +#define TMC2660_USES_USART 1 #define HAS_VOLTAGE_MONITOR 1 #define HAS_VREF_MONITOR 0 #define ACTIVE_LOW_HEAT_ON 1 @@ -61,11 +62,21 @@ constexpr Pin AdditionalIoExpansionStart = 220; // Pin numbers 220-235 are on t // 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 -constexpr Pin GlobalTmcEnablePin = 38; // The pin that drives ENN of all TMC2660 drivers on production boards (on pre-production boards they are grounded) +constexpr Pin GlobalTmc2660EnablePin = 38; // The pin that drives ENN of all TMC2660 drivers on production boards (on pre-production boards they are grounded) constexpr Pin ENABLE_PINS[DRIVES] = { 78, 41, 42, 49, 57, 87, 88, 89, 90, 31, 82, 60 }; constexpr Pin STEP_PINS[DRIVES] = { 70, 71, 72, 69, 68, 66, 65, 64, 67, 91, 84, 85 }; constexpr Pin DIRECTION_PINS[DRIVES] = { 75, 76, 77, 01, 73, 92, 86, 80, 81, 32, 83, 25 }; +// Pin assignments etc. using USART1 in SPI mode +Usart * const USART_TMC2660 = USART1; +constexpr uint32_t ID_TMC2660_SPI = ID_USART1; +constexpr IRQn TMC2660_SPI_IRQn = USART1_IRQn; +# define TMC2660_SPI_Handler USART1_Handler + +constexpr Pin TMC2660MosiPin = 22; // PA13 +constexpr Pin TMC2660MisoPin = 21; // PA22 +constexpr Pin TMC2660SclkPin = 23; // PA23 + constexpr Pin DueX_SG = 96; // DueX stallguard detect pin = PE0 (was E2_STOP) constexpr Pin DueX_INT = 17; // DueX interrupt pin = PA17 (was E6_STOP) diff --git a/src/Fans/DotStarLed.h b/src/Fans/DotStarLed.h index 838a33c6..902918ec 100644 --- a/src/Fans/DotStarLed.h +++ b/src/Fans/DotStarLed.h @@ -8,7 +8,7 @@ #ifndef SRC_FANS_DOTSTARLED_H_ #define SRC_FANS_DOTSTARLED_H_ -#include "ReprapFirmware.h" +#include "RepRapFirmware.h" #include "GCodes/GCodeResult.h" class GCodeBuffer; diff --git a/src/GCodes/GCodes2.cpp b/src/GCodes/GCodes2.cpp index 52825318..d2a685cc 100644 --- a/src/GCodes/GCodes2.cpp +++ b/src/GCodes/GCodes2.cpp @@ -1919,28 +1919,31 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) case 204: // Set max travel and printing accelerations { + Move& move = reprap.GetMove(); bool seen = false; if (gb.Seen('S')) { // For backwards compatibility with old versions of Marlin (e.g. for Cura and the Prusa fork of slic3r), set both accelerations const float acc = gb.GetFValue(); - platform.SetMaxPrintingAcceleration(acc); - platform.SetMaxTravelAcceleration(acc); + move.SetMaxPrintingAcceleration(acc); + move.SetMaxTravelAcceleration(acc); seen = true; } if (gb.Seen('P')) { - platform.SetMaxPrintingAcceleration(gb.GetFValue()); + move.SetMaxPrintingAcceleration(gb.GetFValue()); seen = true; } if (gb.Seen('T')) { - platform.SetMaxTravelAcceleration(gb.GetFValue()); + move.SetMaxTravelAcceleration(gb.GetFValue()); seen = true; } if (!seen) { - reply.printf("Maximum printing acceleration %.1f, maximum travel acceleration %.1f", (double)platform.GetMaxPrintingAcceleration(), (double)platform.GetMaxTravelAcceleration()); + reply.printf("Maximum printing acceleration %.1f, maximum travel acceleration %.1f%s", + (double)move.GetMaxPrintingAcceleration(), (double)move.GetMaxTravelAcceleration(), + (move.IsDRCenabled()) ? " (both currently ignored because DRC is enabled)" : ""); } } break; @@ -3618,8 +3621,19 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) break; #endif - case 593: // Configure filament properties - // TODO: We may need this code later to restrict specific filaments to certain tools or to reset filament counters. + case 593: // Configure dynamic ringing cancellation + if (gb.Seen('F')) + { + reprap.GetMove().SetDRCfreq(gb.GetFValue()); + } + else if (reprap.GetMove().IsDRCenabled()) + { + reply.printf("Dynamic ringing cancellation at %.1fHz", (double)reprap.GetMove().GetDRCfreq()); + } + else + { + reply.copy("Dynamic ringing cancellation is disabled"); + } break; case 665: // Set delta configuration diff --git a/src/Movement/BedProbing/Grid.cpp b/src/Movement/BedProbing/Grid.cpp index 379a4a60..3f598706 100644 --- a/src/Movement/BedProbing/Grid.cpp +++ b/src/Movement/BedProbing/Grid.cpp @@ -247,10 +247,10 @@ void HeightMap::SetGridHeight(size_t xIndex, size_t yIndex, float height) // Note that deltaX and deltaY may be negative unsigned int HeightMap::GetMinimumSegments(float deltaX, float deltaY) const { - const float xDistance = fabs(deltaX); + const float xDistance = fabsf(deltaX); unsigned int xSegments = (xDistance > 0.0) ? (unsigned int)(xDistance * def.recipXspacing + 0.4) : 1; - const float yDistance = fabs(deltaY); + const float yDistance = fabsf(deltaY); unsigned int ySegments = (yDistance > 0.0) ? (unsigned int)(yDistance * def.recipYspacing + 0.4) : 1; return max<unsigned int>(xSegments, ySegments); diff --git a/src/Movement/DDA.cpp b/src/Movement/DDA.cpp index d26d60fe..8ea28469 100644 --- a/src/Movement/DDA.cpp +++ b/src/Movement/DDA.cpp @@ -195,13 +195,13 @@ void DDA::DebugPrint() const DebugPrintVector(" end", endCoordinates, numAxes); } - debugPrintf(" d=%f", (double)totalDistance); + debugPrintf(" s=%f", (double)totalDistance); DebugPrintVector(" vec", directionVector, 5); debugPrintf("\n" - "a=%f reqv=%f startv=%f topv=%f endv=%f daccel=%f ddecel=%f\n" - "cks=%" PRIu32 " sstcda=%" PRIu32 " tstcdapdsc=%" PRIu32 " exac=%" PRIi32 "\n", - (double)acceleration, (double)requestedSpeed, (double)startSpeed, (double)topSpeed, (double)endSpeed, (double)accelDistance, (double)decelDistance, - clocksNeeded, startSpeedTimesCdivA, topSpeedTimesCdivAPlusDecelStartClocks, extraAccelerationClocks); + "a=%f d=%f reqv=%f startv=%f topv=%f endv=%f sa=%f sd=%f\n" + "cks=%" PRIu32 " sstcda=%" PRIu32 " tstcddpdsc=%" PRIu32 " exac=%" PRIi32 "\n", + (double)acceleration, (double)deceleration, (double)requestedSpeed, (double)startSpeed, (double)topSpeed, (double)endSpeed, (double)accelDistance, (double)decelDistance, + clocksNeeded, startSpeedTimesCdivA, topSpeedTimesCdivDPlusDecelStartClocks, extraAccelerationClocks); } // Print the DDA and active DMs @@ -439,7 +439,7 @@ bool DDA::Init(GCodes::RawMove &nextMove, bool doMotorMapping) totalDistance = 0.0; for (size_t d = 0; d < DRIVES; d++) { - totalDistance += fabs(directionVector[d]); + totalDistance += fabsf(directionVector[d]); } if (totalDistance > 0.0) // should always be true { @@ -451,11 +451,12 @@ bool DDA::Init(GCodes::RawMove &nextMove, bool doMotorMapping) float normalisedDirectionVector[DRIVES]; // Used to hold a unit-length vector in the direction of motion memcpy(normalisedDirectionVector, directionVector, sizeof(normalisedDirectionVector)); Absolute(normalisedDirectionVector, DRIVES); - acceleration = VectorBoxIntersection(normalisedDirectionVector, accelerations, DRIVES); - if (xyMoving) + acceleration = maxAcceleration = VectorBoxIntersection(normalisedDirectionVector, accelerations, DRIVES); + if (xyMoving && !move.IsDRCenabled()) // apply M204 acceleration limits to XY moves { - acceleration = min<float>(acceleration, (isPrintingMove) ? reprap.GetPlatform().GetMaxPrintingAcceleration() : reprap.GetPlatform().GetMaxTravelAcceleration()); + acceleration = min<float>(acceleration, (isPrintingMove) ? move.GetMaxPrintingAcceleration() : move.GetMaxTravelAcceleration()); } + deceleration = acceleration; // 6. Set the speed to the smaller of the requested and maximum speed. // Also enforce a minimum speed of 0.5mm/sec. We need a minimum speed to avoid overflow in the movement calculations. @@ -484,7 +485,7 @@ bool DDA::Init(GCodes::RawMove &nextMove, bool doMotorMapping) requestedSpeed = min<float>(max<float>(reqSpeed, MinimumMovementSpeed), VectorBoxIntersection(normalisedDirectionVector, reprap.GetPlatform().MaxFeedrates(), DRIVES)); // On a Cartesian printer, it is OK to limit the X and Y speeds and accelerations independently, and in consequence to allow greater values - // for diagonal moves. On a delta, this is not OK and any movement in the XY plane should be limited to the X/Y axis values, which we assume to be equal. + // for diagonal moves. On other architectures, this is not OK and any movement in the XY plane should be limited to the X/Y axis values, which we assume to be equal. if (doMotorMapping) { k.LimitSpeedAndAcceleration(*this, normalisedDirectionVector); // give the kinematics the chance to further restrict the speed and acceleration @@ -502,7 +503,7 @@ bool DDA::Init(GCodes::RawMove &nextMove, bool doMotorMapping) { // Try to meld this move to the previous move to avoid stop/start // Assuming that this move ends with zero speed, calculate the maximum possible starting speed: u^2 = v^2 - 2as - prev->targetNextSpeed = min<float>(sqrtf(acceleration * totalDistance * 2.0), requestedSpeed); + prev->targetNextSpeed = min<float>(sqrtf(deceleration * totalDistance * 2.0), requestedSpeed); DoLookahead(prev); startSpeed = prev->endSpeed; } @@ -579,7 +580,7 @@ bool DDA::Init(const float_t adjustments[DRIVES]) float normalisedDirectionVector[DRIVES]; // Used to hold a unit-length vector in the direction of motion memcpy(normalisedDirectionVector, directionVector, sizeof(normalisedDirectionVector)); Absolute(normalisedDirectionVector, DRIVES); - acceleration = VectorBoxIntersection(normalisedDirectionVector, accelerations, DRIVES); + acceleration = deceleration = VectorBoxIntersection(normalisedDirectionVector, accelerations, DRIVES); // 6. Set the speed to the smaller of the requested and maximum speed. requestedSpeed = VectorBoxIntersection(normalisedDirectionVector, maxSpeeds, DRIVES); @@ -594,14 +595,22 @@ bool DDA::Init(const float_t adjustments[DRIVES]) // Return true if this move is or might have been intended to be a deceleration-only move // A move planned as a deceleration-only move may have a short acceleration segment at the start because of rounding error -// We declare this inline because it is only used once, in DDA::DoLookahead inline bool DDA::IsDecelerationMove() const { return decelDistance == totalDistance // the simple case - is a deceleration-only move || (topSpeed < requestedSpeed // can't have been intended as deceleration-only if it reaches the requested speed && decelDistance > 0.98 * totalDistance // rounding error can only go so far - && prev->state == DDA::provisional // if we can't adjust the previous move then we don't care (and its figures may not be reliable if it has been recycled already) - && prev->decelDistance > 0.0); // if the previous move has no deceleration phase then no point in adjus6ting it + ); +} + +// Return true if this move is or might have been intended to be a deceleration-only move +// A move planned as a deceleration-only move may have a short acceleration segment at the start because of rounding error +inline bool DDA::IsAccelerationMove() const +{ + return accelDistance == totalDistance // the simple case - is an acceleration-only move + || (topSpeed < requestedSpeed // can't have been intended as deceleration-only if it reaches the requested speed + && accelDistance > 0.98 * totalDistance // rounding error can only go so far + ); } // Return true if there is no reason to delay preparing this move @@ -637,21 +646,24 @@ pre(state == provisional) // We have been asked to adjust the end speed of this move to match the next move starting at targetNextSpeed if (laDDA->targetNextSpeed > laDDA->requestedSpeed) { - laDDA->targetNextSpeed = laDDA->requestedSpeed; // don't try for an end speed higher than our requested speed + laDDA->targetNextSpeed = laDDA->requestedSpeed; // don't try for an end speed higher than our requested speed } if (laDDA->topSpeed >= laDDA->requestedSpeed) { // This move already reaches its top speed, so we just need to adjust the deceleration part - laDDA->MatchSpeeds(); // adjust it if necessary + laDDA->MatchSpeeds(); // adjust it if necessary goingUp = false; } - else if (laDDA->IsDecelerationMove()) + else if ( laDDA->IsDecelerationMove() + && laDDA->prev->state == DDA::provisional // if we can't adjust the previous move then we don't care (and its figures may not be reliable if it has been recycled already) + && laDDA->prev->decelDistance > 0.0 // if the previous move has no deceleration phase then no point in adjus6ting it + ) { // This is a deceleration-only move, so we may have to adjust the previous move as well to get optimum behaviour if (laDDA->prev->state == provisional && laDDA->prev->isPrintingMove == laDDA->isPrintingMove && laDDA->prev->xyMoving == laDDA->xyMoving) { laDDA->MatchSpeeds(); - const float maxStartSpeed = sqrtf(fsquare(laDDA->targetNextSpeed) + (2 * laDDA->acceleration * laDDA->totalDistance)); + const float maxStartSpeed = sqrtf(fsquare(laDDA->targetNextSpeed) + (2 * laDDA->deceleration * laDDA->totalDistance)); laDDA->prev->targetNextSpeed = min<float>(maxStartSpeed, laDDA->requestedSpeed); // leave 'recurse' true } @@ -659,7 +671,7 @@ pre(state == provisional) { // This move is a deceleration-only move but we can't adjust the previous one laDDA->hadLookaheadUnderrun = true; - const float maxReachableSpeed = sqrtf(fsquare(laDDA->startSpeed) + (2 * laDDA->acceleration * laDDA->totalDistance)); + const float maxReachableSpeed = sqrtf(fsquare(laDDA->startSpeed) + (2 * laDDA->deceleration * laDDA->totalDistance)); if (laDDA->targetNextSpeed > maxReachableSpeed) { laDDA->targetNextSpeed = maxReachableSpeed; @@ -843,62 +855,71 @@ float DDA::AdvanceBabyStepping(float amount) // This may cause a move that we intended to be a deceleration-only move to have a tiny acceleration segment at the start void DDA::RecalculateMove() { - const float accelDiff = fsquare(requestedSpeed) - fsquare(startSpeed); - const float decelDiff = fsquare(requestedSpeed) - fsquare(endSpeed); - if (accelDiff + decelDiff >= acceleration * totalDistance * 2) + const float twoA = 2 * acceleration; + const float twoD = 2 * deceleration; + accelDistance = (fsquare(requestedSpeed) - fsquare(startSpeed))/twoA; + decelDistance = (fsquare(requestedSpeed) - fsquare(endSpeed))/twoD; + if (accelDistance + decelDistance < totalDistance) + { + // This move reaches its top speed + topSpeed = requestedSpeed; + } + else { // This move has no steady-speed phase, so it's accelerate-decelerate or accelerate-only or decelerate-only move. - // If V is the peak speed, then (V^2 - u^2)/2a + (V^2 - v^2)/2a = distance. - // So (2V^2 - u^2 - v^2) = 2a * distance - // So V^2 = a * distance + 0.5(u^2 + v^2) - const float vsquared = (acceleration * totalDistance) + 0.5 * (fsquare(startSpeed) + fsquare(endSpeed)); + // If V is the peak speed, then (V^2 - u^2)/2a + (V^2 - v^2)/2d = dist + // So V^2(2a + 2d) = 2a.2d.dist + 2a.v^2 + 2d.u^2 + // So V^2 = (2a.2d.dist + 2a.v^2 + 2d.u^2)/(2a + 2d) + const float vsquared = ((twoA * twoD * totalDistance) + (twoA * fsquare(endSpeed)) + twoD * fsquare(startSpeed))/(twoA + twoD); if (vsquared > fsquare(startSpeed) && vsquared > fsquare(endSpeed)) { // It's an accelerate-decelerate move. Calculate accelerate distance from: V^2 = u^2 + 2as. - accelDistance = (vsquared - fsquare(startSpeed))/(2 * acceleration); - decelDistance = totalDistance - accelDistance; + accelDistance = (vsquared - fsquare(startSpeed))/twoA; + decelDistance = (vsquared - fsquare(endSpeed))/twoD; topSpeed = sqrtf(vsquared); } else { // It's an accelerate-only or decelerate-only move. - // Due to rounding errors and babystepping adjustments, we may have to adjust the acceleration slightly. - float newAcceleration; + // Due to rounding errors and babystepping adjustments, we may have to adjust the acceleration or deceleration slightly. if (startSpeed < endSpeed) { accelDistance = totalDistance; decelDistance = 0.0; topSpeed = endSpeed; - newAcceleration = (fsquare(endSpeed) - fsquare(startSpeed))/(2 * totalDistance); + const float newAcceleration = (fsquare(endSpeed) - fsquare(startSpeed))/(2 * totalDistance); + if (newAcceleration > 1.02 * acceleration) + { + // The acceleration increase is greater than we expect from rounding error, so record an error + reprap.GetMove().RecordLookaheadError(); + if (reprap.Debug(moduleMove)) + { + debugPrintf("DDA.cpp(%d) na=%.3f", __LINE__, (double)newAcceleration); + DebugPrint(); + } + } + acceleration = newAcceleration; } else { accelDistance = 0.0; decelDistance = totalDistance; topSpeed = startSpeed; - newAcceleration = (fsquare(startSpeed) - fsquare(endSpeed))/(2 * totalDistance); - } - - if (newAcceleration > 1.02 * acceleration) - { - // The acceleration increase is greater than we expect from rounding error, so record an error - reprap.GetMove().RecordLookaheadError(); - if (reprap.Debug(moduleMove)) + const float newDeceleration = (fsquare(startSpeed) - fsquare(endSpeed))/(2 * totalDistance); + if (newDeceleration > 1.02 * deceleration) { - debugPrintf("DDA.cpp(%d) na=%.3f", __LINE__, (double)newAcceleration); - DebugPrint(); + // The deceleration increase is greater than we expect from rounding error, so record an error + reprap.GetMove().RecordLookaheadError(); + if (reprap.Debug(moduleMove)) + { + debugPrintf("DDA.cpp(%d) nd=%.3f", __LINE__, (double)newDeceleration); + DebugPrint(); + } } + deceleration = newDeceleration; } - acceleration = newAcceleration; } } - else - { - // This move reaches its top speed - topSpeed = requestedSpeed; - accelDistance = accelDiff/(2 * acceleration); - decelDistance = decelDiff/(2 * acceleration); - } if (canPauseAfter && endSpeed != 0.0) { @@ -914,7 +935,7 @@ void DDA::RecalculateMove() } // We need to set the number of clocks needed here because we use it before the move has been frozen - const float totalTime = (2 * topSpeed - startSpeed - endSpeed)/acceleration + (totalDistance - accelDistance - decelDistance)/topSpeed; + const float totalTime = (topSpeed - startSpeed)/acceleration + (topSpeed - endSpeed)/deceleration + (totalDistance - accelDistance - decelDistance)/topSpeed; clocksNeeded = (uint32_t)(totalTime * StepClockRate); } @@ -1018,10 +1039,85 @@ pre(disableDeltaMapping || drive < MaxAxes) } } +// Adjust the acceleration and deceleration to reduce ringing +// This is only called once, so inlined for speed +inline void DDA::AdjustAcceleration() +{ + // Try to reduce the acceleration/deceleration of the move to cancel ringing + const float idealPeriod = reprap.GetMove().GetDRCperiod(); + + const float accTime = (topSpeed - startSpeed)/acceleration; + const bool adjustAcceleration = + (accTime < idealPeriod && accTime > 0.2 * idealPeriod && ((prev->state != DDAState::frozen && prev->state != DDAState::executing) || !prev->IsAccelerationMove())); + if (adjustAcceleration) + { + acceleration = (topSpeed - startSpeed)/idealPeriod; + accelDistance = (fsquare(topSpeed) - fsquare(startSpeed))/(2 *acceleration); + } + + const float decelTime = (topSpeed - endSpeed)/deceleration; + const float adjustDeceleration = + (decelTime < idealPeriod && decelTime > 0.2 * idealPeriod && (next->state != DDAState::provisional || !next->IsDecelerationMove())); + if (adjustDeceleration) + { + deceleration = (topSpeed - endSpeed)/idealPeriod; + decelDistance = (fsquare(topSpeed) - fsquare(endSpeed))/(2 * deceleration); + } + + if (adjustAcceleration || adjustDeceleration) + { + if (accelDistance + decelDistance > totalDistance) + { + // We can't keep this as a trapezoidal move + const float twiceTotalDistance = 2 * totalDistance; + if (adjustAcceleration && adjustDeceleration && (startSpeed + endSpeed) * idealPeriod < totalDistance) + { + // Change it into an accelerate-decelerate move with equal acceleration and deceleration times + acceleration = (twiceTotalDistance - (3 * startSpeed + endSpeed) * idealPeriod)/(2 * fsquare(idealPeriod)); + deceleration = (twiceTotalDistance - (startSpeed + 3 * endSpeed) * idealPeriod)/(2 * fsquare(idealPeriod)); + topSpeed = (totalDistance/idealPeriod) - (startSpeed + endSpeed)/2; + accelDistance = startSpeed * idealPeriod + (acceleration * fsquare(idealPeriod))/2; + decelDistance = endSpeed * idealPeriod + (deceleration * fsquare(idealPeriod))/2; + } + else if (startSpeed < endSpeed) + { + // Change it into an accelerate-only move, accelerating as slowly as we can + acceleration = (fsquare(endSpeed) - fsquare(startSpeed))/twiceTotalDistance; + topSpeed = endSpeed; + accelDistance = totalDistance; + decelDistance = 0.0; + } + else + { + // Change it into a decelerate-only move, decelerating as slowly as we can + deceleration = (fsquare(startSpeed) - fsquare(endSpeed))/twiceTotalDistance; + topSpeed = startSpeed; + accelDistance = 0.0; + decelDistance = totalDistance; + } + } + const float totalTime = (topSpeed - startSpeed)/acceleration + (topSpeed - endSpeed)/deceleration + (totalDistance - accelDistance - decelDistance)/topSpeed; + clocksNeeded = (uint32_t)(totalTime * StepClockRate); + if (reprap.Debug(moduleMove)) + { + debugPrintf("New a=%f d=%f\n", (double)acceleration, (double)deceleration); + } + } +} + // Prepare this DDA for execution. // This must not be called with interrupts disabled, because it calls Platform::EnableDrive. void DDA::Prepare(uint8_t simMode) { + if ( xyMoving + && reprap.GetMove().IsDRCenabled() + && topSpeed > startSpeed && topSpeed > endSpeed + && (fabsf(directionVector[X_AXIS]) > 0.5 || fabsf(directionVector[Y_AXIS]) > 0.5) + ) + { + AdjustAcceleration(); + } + PrepParams params; params.decelStartDistance = totalDistance - decelDistance; @@ -1046,8 +1142,8 @@ void DDA::Prepare(uint8_t simMode) const float decelStartTime = accelStopTime + (params.decelStartDistance - accelDistance)/topSpeed; startSpeedTimesCdivA = (uint32_t)roundU32((startSpeed * StepClockRate)/acceleration); - params.topSpeedTimesCdivA = (uint32_t)roundU32((topSpeed * StepClockRate)/acceleration); - topSpeedTimesCdivAPlusDecelStartClocks = params.topSpeedTimesCdivA + (uint32_t)roundU32(decelStartTime * StepClockRate); + params.topSpeedTimesCdivD = (uint32_t)roundU32((topSpeed * StepClockRate)/deceleration); + topSpeedTimesCdivDPlusDecelStartClocks = params.topSpeedTimesCdivD + (uint32_t)roundU32(decelStartTime * StepClockRate); extraAccelerationClocks = roundS32((accelStopTime - (accelDistance/topSpeed)) * StepClockRate); params.compFactor = (topSpeed - startSpeed)/topSpeed; @@ -1094,7 +1190,7 @@ void DDA::Prepare(uint8_t simMode) && ( pdm->totalSteps > 1000000 || pdm->reverseStartStep < pdm->mp.cart.decelStartStep || (pdm->reverseStartStep <= pdm->totalSteps - && pdm->mp.cart.fourMaxStepDistanceMinusTwoDistanceToStopTimesCsquaredDivA > (int64_t)(pdm->mp.cart.twoCsquaredTimesMmPerStepDivA * pdm->reverseStartStep)) + && pdm->mp.cart.fourMaxStepDistanceMinusTwoDistanceToStopTimesCsquaredDivD > (int64_t)(pdm->mp.cart.twoCsquaredTimesMmPerStepDivD * pdm->reverseStartStep)) ) ) { @@ -1735,6 +1831,10 @@ void DDA::LimitSpeedAndAcceleration(float maxSpeed, float maxAcceleration) { acceleration = maxAcceleration; } + if (deceleration > maxAcceleration) + { + deceleration = maxAcceleration; + } } // End diff --git a/src/Movement/DDA.h b/src/Movement/DDA.h index 4747d430..b0cc4cc1 100644 --- a/src/Movement/DDA.h +++ b/src/Movement/DDA.h @@ -140,9 +140,11 @@ private: void RemoveDM(size_t drive); void ReleaseDMs(); bool IsDecelerationMove() const; // return true if this move is or have been might have been intended to be a deceleration-only move + bool IsAccelerationMove() const; // return true if this move is or have been might have been intended to be an acceleration-only move void DebugPrintVector(const char *name, const float *vec, size_t len) const; void CheckEndstops(Platform& platform); float NormaliseXYZ(); // Make the direction vector unit-normal in XYZ + void AdjustAcceleration(); // Adjust the acceleration and deceleration to reduce ringing static void DoLookahead(DDA *laDDA) __attribute__ ((hot)); // Try to smooth out moves in the queue static float Normalise(float v[], size_t dim1, size_t dim2); // Normalise a vector of dim1 dimensions to unit length in the first dim1 dimensions @@ -175,6 +177,10 @@ private: uint16_t flags; // so that we can print all the flags at once for debugging }; +#if SUPPORT_IOBITS + IoBits_t ioBits; // port state required during this move (here because it is currently 16 bits) +#endif + EndstopChecks endStopsToCheck; // Which endstops we are checking on this move AxesBitmap xAxes; // Which axes are behaving as X axes AxesBitmap yAxes; // Which axes are behaving as Y axes @@ -186,12 +192,10 @@ private: float directionVector[DRIVES]; // The normalised direction vector - first 3 are XYZ Cartesian coordinates even on a delta float totalDistance; // How long is the move in hypercuboid space float acceleration; // The acceleration to use + float deceleration; // The deceleration to use float requestedSpeed; // The speed that the user asked for float virtualExtruderPosition; // the virtual extruder position at the end of this move, used for pause/resume - // These are used only in delta calculations - int32_t cKc; // The Z movement fraction multiplied by Kc and converted to integer - // These vary depending on how we connect the move with its predecessor and successor, but remain constant while the move is being executed float startSpeed; float endSpeed; @@ -199,21 +203,31 @@ private: float accelDistance; float decelDistance; - // This is a temporary, used to keep track of the lookahead to avoid making recursive calls - float targetNextSpeed; // The speed that the next move would like to start at - - // These are calculated from the above and used in the ISR, so they are set up by Prepare() - uint32_t clocksNeeded; // in clocks - uint32_t moveStartTime; // clock count at which the move was started - uint32_t startSpeedTimesCdivA; // the number of clocks it would have taken to reach the start speed from rest - uint32_t topSpeedTimesCdivAPlusDecelStartClocks; - int32_t extraAccelerationClocks; // the additional number of clocks needed because we started the move at less than topSpeed. Negative after ReduceHomingSpeed has been called. - float proportionLeft; // what proportion of the extrusion in the G1 or G0 move of which this is a part remains to be done after this segment is complete + uint32_t clocksNeeded; -#if SUPPORT_IOBITS - IoBits_t ioBits; // port state required during this move -#endif + union + { + // Values that are needed only before Prepare is called + struct + { + float targetNextSpeed; // The speed that the next move would like to start at, used to keep track of the lookahead without making recursive calls + float maxAcceleration; // the maximum allowed acceleration for this move according to the limits set by M201 + }; + + // Values that are not set or accessed before Prepare is called + struct + { + // These are calculated from the above and used in the ISR, so they are set up by Prepare() + uint32_t moveStartTime; // clock count at which the move was started + uint32_t startSpeedTimesCdivA; // the number of clocks it would have taken to reach the start speed from rest + uint32_t topSpeedTimesCdivDPlusDecelStartClocks; + int32_t extraAccelerationClocks; // the additional number of clocks needed because we started the move at less than topSpeed. Negative after ReduceHomingSpeed has been called. + + // These are used only in delta calculations + int32_t cKc; // The Z movement fraction multiplied by Kc and converted to integer + }; + }; #if DDA_LOG_PROBE_CHANGES static bool probeTriggered; diff --git a/src/Movement/DriveMovement.cpp b/src/Movement/DriveMovement.cpp index f510d0a2..7ebbc6c5 100644 --- a/src/Movement/DriveMovement.cpp +++ b/src/Movement/DriveMovement.cpp @@ -59,6 +59,7 @@ void DriveMovement::PrepareCartesianAxis(const DDA& dda, const PrepParams& param { const float stepsPerMm = (float)totalSteps/dda.totalDistance; mp.cart.twoCsquaredTimesMmPerStepDivA = roundU64((double)(StepClockRateSquared * 2)/((double)stepsPerMm * (double)dda.acceleration)); + mp.cart.twoCsquaredTimesMmPerStepDivD = roundU64((double)(StepClockRateSquared * 2)/((double)stepsPerMm * (double)dda.deceleration)); // Acceleration phase parameters mp.cart.accelStopStep = (uint32_t)(dda.accelDistance * stepsPerMm) + 1; @@ -72,18 +73,18 @@ void DriveMovement::PrepareCartesianAxis(const DDA& dda, const PrepParams& param if (dda.decelDistance * stepsPerMm < 0.5) { mp.cart.decelStartStep = totalSteps + 1; - twoDistanceToStopTimesCsquaredDivA = 0; + twoDistanceToStopTimesCsquaredDivD = 0; } else { mp.cart.decelStartStep = (uint32_t)(params.decelStartDistance * stepsPerMm) + 1; - const uint64_t initialDecelSpeedTimesCdivASquared = isquare64(params.topSpeedTimesCdivA); - twoDistanceToStopTimesCsquaredDivA = initialDecelSpeedTimesCdivASquared + roundU64((params.decelStartDistance * (StepClockRateSquared * 2))/dda.acceleration); + const uint64_t initialDecelSpeedTimesCdivDSquared = isquare64(params.topSpeedTimesCdivD); + twoDistanceToStopTimesCsquaredDivD = initialDecelSpeedTimesCdivDSquared + roundU64((params.decelStartDistance * (StepClockRateSquared * 2))/dda.deceleration); } // No reverse phase reverseStartStep = totalSteps + 1; - mp.cart.fourMaxStepDistanceMinusTwoDistanceToStopTimesCsquaredDivA = 0; + mp.cart.fourMaxStepDistanceMinusTwoDistanceToStopTimesCsquaredDivD = 0; } // Prepare this DM for a Delta axis move @@ -99,6 +100,7 @@ void DriveMovement::PrepareDeltaAxis(const DDA& dda, const PrepParams& params) mp.delta.minusAaPlusBbTimesKs = -roundS32(aAplusbB * stepsPerMm * DriveMovement::K2); mp.delta.dSquaredMinusAsquaredMinusBsquaredTimesKsquaredSsquared = roundS64(dSquaredMinusAsquaredMinusBsquared * fsquare(stepsPerMm * DriveMovement::K2)); mp.delta.twoCsquaredTimesMmPerStepDivA = roundU64((double)(2 * StepClockRateSquared)/((double)stepsPerMm * (double)dda.acceleration)); + mp.delta.twoCsquaredTimesMmPerStepDivD = roundU64((double)(2 * StepClockRateSquared)/((double)stepsPerMm * (double)dda.deceleration)); // Calculate the distance at which we need to reverse direction. if (params.a2plusb2 <= 0.0) @@ -159,12 +161,12 @@ void DriveMovement::PrepareDeltaAxis(const DDA& dda, const PrepParams& params) if (dda.decelDistance * stepsPerMm < 0.5) { mp.delta.decelStartDsK = 0xFFFFFFFF; - twoDistanceToStopTimesCsquaredDivA = 0; + twoDistanceToStopTimesCsquaredDivD = 0; } else { mp.delta.decelStartDsK = roundU32(params.decelStartDistance * stepsPerMm * K2); - twoDistanceToStopTimesCsquaredDivA = isquare64(params.topSpeedTimesCdivA) + roundU64((params.decelStartDistance * (StepClockRateSquared * 2))/dda.acceleration); + twoDistanceToStopTimesCsquaredDivD = isquare64(params.topSpeedTimesCdivD) + roundU64((params.decelStartDistance * (StepClockRateSquared * 2))/dda.deceleration); } } @@ -224,6 +226,7 @@ void DriveMovement::PrepareExtruder(const DDA& dda, const PrepParams& params, fl } mp.cart.twoCsquaredTimesMmPerStepDivA = roundU64((double)(StepClockRateSquared * 2)/((double)stepsPerMm * (double)dda.acceleration)); + mp.cart.twoCsquaredTimesMmPerStepDivD = roundU64((double)(StepClockRateSquared * 2)/((double)stepsPerMm * (double)dda.deceleration)); // Constant speed phase parameters mp.cart.mmPerStepTimesCKdivtopSpeed = (uint32_t)((float)((uint64_t)StepClockRate * K1)/(stepsPerMm * dda.topSpeed)); @@ -234,28 +237,28 @@ void DriveMovement::PrepareExtruder(const DDA& dda, const PrepParams& params, fl { totalSteps = (uint32_t)max<int32_t>(netSteps, 0); mp.cart.decelStartStep = reverseStartStep = netSteps + 1; - mp.cart.fourMaxStepDistanceMinusTwoDistanceToStopTimesCsquaredDivA = 0; - twoDistanceToStopTimesCsquaredDivA = 0; + mp.cart.fourMaxStepDistanceMinusTwoDistanceToStopTimesCsquaredDivD = 0; + twoDistanceToStopTimesCsquaredDivD = 0; } else { mp.cart.decelStartStep = (uint32_t)((params.decelStartDistance + accelCompensationDistance) * stepsPerMm) + 1; - const int32_t initialDecelSpeedTimesCdivA = (int32_t)params.topSpeedTimesCdivA - (int32_t)mp.cart.compensationClocks; // signed because it may be negative and we square it - const uint64_t initialDecelSpeedTimesCdivASquared = isquare64(initialDecelSpeedTimesCdivA); - twoDistanceToStopTimesCsquaredDivA = - initialDecelSpeedTimesCdivASquared + roundU64(((params.decelStartDistance + accelCompensationDistance) * (float)(StepClockRateSquared * 2))/dda.acceleration); + 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 = + initialDecelSpeedTimesCdivDSquared + roundU64(((params.decelStartDistance + accelCompensationDistance) * (float)(StepClockRateSquared * 2))/dda.deceleration); // See whether there is a reverse phase - const float compensationSpeedChange = dda.acceleration * compensationTime; + const float compensationSpeedChange = dda.deceleration * compensationTime; const uint32_t stepsBeforeReverse = (compensationSpeedChange > dda.topSpeed) ? mp.cart.decelStartStep - 1 - : twoDistanceToStopTimesCsquaredDivA/mp.cart.twoCsquaredTimesMmPerStepDivA; + : twoDistanceToStopTimesCsquaredDivD/mp.cart.twoCsquaredTimesMmPerStepDivD; if (dda.endSpeed < compensationSpeedChange && (int32_t)stepsBeforeReverse > netSteps) { reverseStartStep = stepsBeforeReverse + 1; totalSteps = (uint32_t)((int32_t)(2 * stepsBeforeReverse) - netSteps); - mp.cart.fourMaxStepDistanceMinusTwoDistanceToStopTimesCsquaredDivA = - (int64_t)((2 * stepsBeforeReverse) * mp.cart.twoCsquaredTimesMmPerStepDivA) - (int64_t)twoDistanceToStopTimesCsquaredDivA; + mp.cart.fourMaxStepDistanceMinusTwoDistanceToStopTimesCsquaredDivD = + (int64_t)((2 * stepsBeforeReverse) * mp.cart.twoCsquaredTimesMmPerStepDivD) - (int64_t)twoDistanceToStopTimesCsquaredDivD; } else { @@ -266,7 +269,7 @@ void DriveMovement::PrepareExtruder(const DDA& dda, const PrepParams& params, fl } reverseStartStep = netSteps + 1; totalSteps = (uint32_t)max<int32_t>(netSteps, 0); - mp.cart.fourMaxStepDistanceMinusTwoDistanceToStopTimesCsquaredDivA = 0; + mp.cart.fourMaxStepDistanceMinusTwoDistanceToStopTimesCsquaredDivD = 0; } } } @@ -278,22 +281,22 @@ void DriveMovement::DebugPrint(char c, bool isDeltaMovement) const debugPrintf("DM%c%s dir=%c steps=%" PRIu32 " next=%" PRIu32 " rev=%" PRIu32 " interval=%" PRIu32 " 2dtstc2diva=%" PRIu64 "\n", c, (state == DMState::stepError) ? " ERR:" : ":", (direction) ? 'F' : 'B', totalSteps, nextStep, reverseStartStep, stepInterval, - twoDistanceToStopTimesCsquaredDivA); + twoDistanceToStopTimesCsquaredDivD); if (isDeltaMovement) { debugPrintf("hmz0sK=%" PRIi32 " minusAaPlusBbTimesKs=%" PRIi32 " dSquaredMinusAsquaredMinusBsquared=%" PRId64 "\n" - "2c2mmsda=%" PRIu64 " asdsk=%" PRIu32 " dsdsk=%" PRIu32 " mmstcdts=%" PRIu32 "\n", + "2c2mmsda=%" PRIu64 "2c2mmsdd=%" PRIu64 " asdsk=%" PRIu32 " dsdsk=%" PRIu32 " mmstcdts=%" PRIu32 "\n", mp.delta.hmz0sK, mp.delta.minusAaPlusBbTimesKs, mp.delta.dSquaredMinusAsquaredMinusBsquaredTimesKsquaredSsquared, - mp.delta.twoCsquaredTimesMmPerStepDivA, mp.delta.accelStopDsK, mp.delta.decelStartDsK, mp.delta.mmPerStepTimesCKdivtopSpeed + mp.delta.twoCsquaredTimesMmPerStepDivA, mp.delta.twoCsquaredTimesMmPerStepDivD, mp.delta.accelStopDsK, mp.delta.decelStartDsK, mp.delta.mmPerStepTimesCKdivtopSpeed ); } else { - debugPrintf("accelStopStep=%" PRIu32 " decelStartStep=%" PRIu32 " 2CsqtMmPerStepDivA=%" PRIu64 "\n" + debugPrintf("accelStopStep=%" PRIu32 " decelStartStep=%" PRIu32 " 2c2mmsda=%" PRIu64 " 2c2mmsdd=%" PRIu64 "\n" "mmPerStepTimesCdivtopSpeed=%" PRIu32 " fmsdmtstdca2=%" PRId64 " cc=%" PRIu32 " acc=%" PRIu32 "\n", - mp.cart.accelStopStep, mp.cart.decelStartStep, mp.cart.twoCsquaredTimesMmPerStepDivA, - mp.cart.mmPerStepTimesCKdivtopSpeed, mp.cart.fourMaxStepDistanceMinusTwoDistanceToStopTimesCsquaredDivA, mp.cart.compensationClocks, mp.cart.accelCompensationClocks + mp.cart.accelStopStep, mp.cart.decelStartStep, mp.cart.twoCsquaredTimesMmPerStepDivA, mp.cart.twoCsquaredTimesMmPerStepDivD, + mp.cart.mmPerStepTimesCKdivtopSpeed, mp.cart.fourMaxStepDistanceMinusTwoDistanceToStopTimesCsquaredDivD, mp.cart.compensationClocks, mp.cart.accelCompensationClocks ); } } @@ -353,12 +356,12 @@ pre(nextStep < totalSteps; stepsTillRecalc == 0) else if (nextCalcStep < reverseStartStep) { // deceleration phase, not reversed yet - const uint64_t temp = mp.cart.twoCsquaredTimesMmPerStepDivA * nextCalcStep; - const uint32_t adjustedTopSpeedTimesCdivAPlusDecelStartClocks = dda.topSpeedTimesCdivAPlusDecelStartClocks - mp.cart.compensationClocks; + const uint64_t temp = mp.cart.twoCsquaredTimesMmPerStepDivD * nextCalcStep; + const uint32_t adjustedTopSpeedTimesCdivDPlusDecelStartClocks = dda.topSpeedTimesCdivDPlusDecelStartClocks - mp.cart.compensationClocks; // Allow for possible rounding error when the end speed is zero or very small - nextCalcStepTime = (temp < twoDistanceToStopTimesCsquaredDivA) - ? adjustedTopSpeedTimesCdivAPlusDecelStartClocks - isqrt64(twoDistanceToStopTimesCsquaredDivA - temp) - : adjustedTopSpeedTimesCdivAPlusDecelStartClocks; + nextCalcStepTime = (temp < twoDistanceToStopTimesCsquaredDivD) + ? adjustedTopSpeedTimesCdivDPlusDecelStartClocks - isqrt64(twoDistanceToStopTimesCsquaredDivD - temp) + : adjustedTopSpeedTimesCdivDPlusDecelStartClocks; } else { @@ -371,9 +374,9 @@ pre(nextStep < totalSteps; stepsTillRecalc == 0) reprap.GetPlatform().SetDirection(drive, direction); } } - const uint32_t adjustedTopSpeedTimesCdivAPlusDecelStartClocks = dda.topSpeedTimesCdivAPlusDecelStartClocks - mp.cart.compensationClocks; - nextCalcStepTime = adjustedTopSpeedTimesCdivAPlusDecelStartClocks - + isqrt64((int64_t)(mp.cart.twoCsquaredTimesMmPerStepDivA * nextCalcStep) - mp.cart.fourMaxStepDistanceMinusTwoDistanceToStopTimesCsquaredDivA); + const uint32_t adjustedTopSpeedTimesCdivDPlusDecelStartClocks = dda.topSpeedTimesCdivDPlusDecelStartClocks - mp.cart.compensationClocks; + nextCalcStepTime = adjustedTopSpeedTimesCdivDPlusDecelStartClocks + + isqrt64((int64_t)(mp.cart.twoCsquaredTimesMmPerStepDivD * nextCalcStep) - mp.cart.fourMaxStepDistanceMinusTwoDistanceToStopTimesCsquaredDivD); } // When crossing between movement phases with high microstepping, due to rounding errors the next step may appear to be due before the last one @@ -491,11 +494,11 @@ pre(nextStep < totalSteps; stepsTillRecalc == 0) } else { - const uint64_t temp = (mp.delta.twoCsquaredTimesMmPerStepDivA * (uint32_t)dsK)/K2; + const uint64_t temp = (mp.delta.twoCsquaredTimesMmPerStepDivD * (uint32_t)dsK)/K2; // Because of possible rounding error when the end speed is zero or very small, we need to check that the square root will work OK - nextCalcStepTime = (temp < twoDistanceToStopTimesCsquaredDivA) - ? dda.topSpeedTimesCdivAPlusDecelStartClocks - isqrt64(twoDistanceToStopTimesCsquaredDivA - temp) - : dda.topSpeedTimesCdivAPlusDecelStartClocks; + nextCalcStepTime = (temp < twoDistanceToStopTimesCsquaredDivD) + ? dda.topSpeedTimesCdivDPlusDecelStartClocks - isqrt64(twoDistanceToStopTimesCsquaredDivD - temp) + : dda.topSpeedTimesCdivDPlusDecelStartClocks; } // When crossing between movement phases with high microstepping, due to rounding errors the next step may appear to be due before the last one. diff --git a/src/Movement/DriveMovement.h b/src/Movement/DriveMovement.h index 8deb5b14..d5df4602 100644 --- a/src/Movement/DriveMovement.h +++ b/src/Movement/DriveMovement.h @@ -93,7 +93,7 @@ struct PrepParams { // Parameters used for all types of motion float decelStartDistance; - uint32_t topSpeedTimesCdivA; + uint32_t topSpeedTimesCdivD; // Parameters used only for extruders float compFactor; @@ -171,18 +171,19 @@ private: uint32_t stepInterval; // how many clocks between steps // The following only needs to be stored per-drive if we are supporting pressure advance - uint64_t twoDistanceToStopTimesCsquaredDivA; + uint64_t twoDistanceToStopTimesCsquaredDivD; // Parameters unique to a style of move (Cartesian, delta or extruder). Currently, extruders and Cartesian moves use the same parameters. union MoveParams { struct CartesianParameters // Parameters for Cartesian and extruder movement, including extruder pressure advance { - // The following don't depend on how the move is executed, so they could be set up in Init() + // The following don't depend on how the move is executed, so they could be set up in Init() if we use fixed acceleration/deceleration uint64_t twoCsquaredTimesMmPerStepDivA; // 2 * clock^2 * mmPerStepInHyperCuboidSpace / acceleration + uint64_t twoCsquaredTimesMmPerStepDivD; // 2 * clock^2 * mmPerStepInHyperCuboidSpace / deceleration // The following depend on how the move is executed, so they must be set up in Prepare() - int64_t fourMaxStepDistanceMinusTwoDistanceToStopTimesCsquaredDivA; // this one can be negative + int64_t fourMaxStepDistanceMinusTwoDistanceToStopTimesCsquaredDivD; // this one can be negative uint32_t accelStopStep; // the first step number at which we are no longer accelerating uint32_t decelStartStep; // the first step number at which we are decelerating uint32_t mmPerStepTimesCKdivtopSpeed; // mmPerStepInHyperCuboidSpace * clock / topSpeed @@ -192,8 +193,9 @@ private: struct DeltaParameters // Parameters for delta movement { - // The following don't depend on how the move is executed, so they can be set up in Init + // The following don't depend on how the move is executed, so they could be set up in Init() if we use fixed acceleration/deceleration uint64_t twoCsquaredTimesMmPerStepDivA; // this could be stored in the DDA if all towers use the same steps/mm + uint64_t twoCsquaredTimesMmPerStepDivD; // 2 * clock^2 * mmPerStepInHyperCuboidSpace / deceleration int64_t dSquaredMinusAsquaredMinusBsquaredTimesKsquaredSsquared; int32_t hmz0sK; // the starting step position less the starting Z height, multiplied by the Z movement fraction and K (can go negative) int32_t minusAaPlusBbTimesKs; diff --git a/src/Movement/Kinematics/CoreXYKinematics.cpp b/src/Movement/Kinematics/CoreXYKinematics.cpp index 86d32a33..09a5f24d 100644 --- a/src/Movement/Kinematics/CoreXYKinematics.cpp +++ b/src/Movement/Kinematics/CoreXYKinematics.cpp @@ -62,7 +62,7 @@ void CoreXYKinematics::LimitSpeedAndAcceleration(DDA& dda, const float *normalis { const float vecX = normalisedDirectionVector[0]; const float vecY = normalisedDirectionVector[1]; - const float vecMax = max<float>(fabs(vecX + vecY), fabs(vecX - vecY)); // pick the case for the motor that is working hardest + const float vecMax = max<float>(fabsf(vecX + vecY), fabsf(vecX - vecY)); // pick the case for the motor that is working hardest if (vecMax > 0.01) // avoid division by zero or near-zero { const Platform& platform = reprap.GetPlatform(); @@ -70,8 +70,8 @@ void CoreXYKinematics::LimitSpeedAndAcceleration(DDA& dda, const float *normalis const float aY = platform.Acceleration(1); const float vX = platform.MaxFeedrate(0); const float vY = platform.MaxFeedrate(1); - const float aMax = (fabs(vecX) + fabs(vecY)) * aX * aY/(vecMax * (fabs(vecX) * aY + fabs(vecY) * aX)); - const float vMax = (fabs(vecX) + fabs(vecY)) * vX * vY/(vecMax * (fabs(vecX) * vY + fabs(vecY) * vX)); + const float aMax = (fabsf(vecX) + fabsf(vecY)) * aX * aY/(vecMax * (fabsf(vecX) * aY + fabsf(vecY) * aX)); + const float vMax = (fabsf(vecX) + fabsf(vecY)) * vX * vY/(vecMax * (fabsf(vecX) * vY + fabsf(vecY) * vX)); dda.LimitSpeedAndAcceleration(vMax, aMax); } } diff --git a/src/Movement/Kinematics/CoreXYUKinematics.cpp b/src/Movement/Kinematics/CoreXYUKinematics.cpp index 0b2f3981..3f2db5cb 100644 --- a/src/Movement/Kinematics/CoreXYUKinematics.cpp +++ b/src/Movement/Kinematics/CoreXYUKinematics.cpp @@ -106,7 +106,7 @@ void CoreXYUKinematics::LimitSpeedAndAcceleration(DDA& dda, const float *normali const float vecY = normalisedDirectionVector[1]; // Limit the XY motor accelerations - const float vecMaxXY = max<float>(fabs(vecX + vecY), fabs(vecX - vecY)); // pick the case for the motor that is working hardest + const float vecMaxXY = max<float>(fabsf(vecX + vecY), fabsf(vecX - vecY)); // pick the case for the motor that is working hardest if (vecMaxXY > 0.01) // avoid division by zero or near-zero { const Platform& platform = reprap.GetPlatform(); @@ -114,14 +114,14 @@ void CoreXYUKinematics::LimitSpeedAndAcceleration(DDA& dda, const float *normali const float aY = platform.Acceleration(1); const float vX = platform.MaxFeedrate(0); const float vY = platform.MaxFeedrate(1); - const float aMax = (fabs(vecX) + fabs(vecY)) * aX * aY/(vecMaxXY * (fabs(vecX) * aY + fabs(vecY) * aX)); - const float vMax = (fabs(vecX) + fabs(vecY)) * vX * vY/(vecMaxXY * (fabs(vecX) * vY + fabs(vecY) * vX)); + const float aMax = (fabsf(vecX) + fabsf(vecY)) * aX * aY/(vecMaxXY * (fabsf(vecX) * aY + fabsf(vecY) * aX)); + const float vMax = (fabsf(vecX) + fabsf(vecY)) * vX * vY/(vecMaxXY * (fabsf(vecX) * vY + fabsf(vecY) * vX)); dda.LimitSpeedAndAcceleration(vMax, aMax); } // Limit the UV motor accelerations const float vecU = normalisedDirectionVector[3]; - const float vecMaxUV = max<float>(fabs(vecU + vecY), fabs(vecU - vecY)); // pick the case for the motor that is working hardest + const float vecMaxUV = max<float>(fabsf(vecU + vecY), fabsf(vecU - vecY)); // pick the case for the motor that is working hardest if (vecMaxUV > 0.01) // avoid division by zero or near-zero { const Platform& platform = reprap.GetPlatform(); @@ -129,8 +129,8 @@ void CoreXYUKinematics::LimitSpeedAndAcceleration(DDA& dda, const float *normali const float aY = platform.Acceleration(1); const float vU = platform.MaxFeedrate(3); const float vY = platform.MaxFeedrate(1); - const float aMax = (fabs(vecU) + fabs(vecY)) * aU * aY/(vecMaxUV * (fabs(vecU) * aY + fabs(vecY) * aU)); - const float vMax = (fabs(vecU) + fabs(vecY)) * vU * vY/(vecMaxUV * (fabs(vecU) * vY + fabs(vecY) * vU)); + const float aMax = (fabsf(vecU) + fabsf(vecY)) * aU * aY/(vecMaxUV * (fabsf(vecU) * aY + fabsf(vecY) * aU)); + const float vMax = (fabsf(vecU) + fabsf(vecY)) * vU * vY/(vecMaxUV * (fabsf(vecU) * vY + fabsf(vecY) * vU)); dda.LimitSpeedAndAcceleration(vMax, aMax); } } diff --git a/src/Movement/Kinematics/CoreXYUVKinematics.cpp b/src/Movement/Kinematics/CoreXYUVKinematics.cpp index 6d2ea68c..69c24311 100644 --- a/src/Movement/Kinematics/CoreXYUVKinematics.cpp +++ b/src/Movement/Kinematics/CoreXYUVKinematics.cpp @@ -105,7 +105,7 @@ void CoreXYUVKinematics::LimitSpeedAndAcceleration(DDA& dda, const float *normal const float vecY = normalisedDirectionVector[1]; // Limit the XY motor accelerations - const float vecMaxXY = max<float>(fabs(vecX + vecY), fabs(vecX - vecY)); // pick the case for the motor that is working hardest + const float vecMaxXY = max<float>(fabsf(vecX + vecY), fabsf(vecX - vecY)); // pick the case for the motor that is working hardest if (vecMaxXY > 0.01) // avoid division by zero or near-zero { const Platform& platform = reprap.GetPlatform(); @@ -113,15 +113,15 @@ void CoreXYUVKinematics::LimitSpeedAndAcceleration(DDA& dda, const float *normal const float aY = platform.Acceleration(1); const float vX = platform.MaxFeedrate(0); const float vY = platform.MaxFeedrate(1); - const float aMax = (fabs(vecX) + fabs(vecY)) * aX * aY/(vecMaxXY * (fabs(vecX) * aY + fabs(vecY) * aX)); - const float vMax = (fabs(vecX) + fabs(vecY)) * vX * vY/(vecMaxXY * (fabs(vecX) * vY + fabs(vecY) * vX)); + const float aMax = (fabsf(vecX) + fabsf(vecY)) * aX * aY/(vecMaxXY * (fabsf(vecX) * aY + fabsf(vecY) * aX)); + const float vMax = (fabsf(vecX) + fabsf(vecY)) * vX * vY/(vecMaxXY * (fabsf(vecX) * vY + fabsf(vecY) * vX)); dda.LimitSpeedAndAcceleration(vMax, aMax); } // Limit the UV motor accelerations const float vecU = normalisedDirectionVector[3]; const float vecV = normalisedDirectionVector[4]; - const float vecMaxUV = max<float>(fabs(vecU + vecV), fabs(vecU - vecV)); // pick the case for the motor that is working hardest + const float vecMaxUV = max<float>(fabsf(vecU + vecV), fabsf(vecU - vecV)); // pick the case for the motor that is working hardest if (vecMaxUV > 0.01) // avoid division by zero or near-zero { const Platform& platform = reprap.GetPlatform(); @@ -129,8 +129,8 @@ void CoreXYUVKinematics::LimitSpeedAndAcceleration(DDA& dda, const float *normal const float aV = platform.Acceleration(4); const float vU = platform.MaxFeedrate(3); const float vV = platform.MaxFeedrate(4); - const float aMax = (fabs(vecU) + fabs(vecV)) * aU * aV/(vecMaxUV * (fabs(vecU) * aV + fabs(vecV) * aU)); - const float vMax = (fabs(vecU) + fabs(vecV)) * vU * vV/(vecMaxUV * (fabs(vecU) * vV + fabs(vecV) * vU)); + const float aMax = (fabsf(vecU) + fabsf(vecV)) * aU * aV/(vecMaxUV * (fabsf(vecU) * aV + fabsf(vecV) * aU)); + const float vMax = (fabsf(vecU) + fabsf(vecV)) * vU * vV/(vecMaxUV * (fabsf(vecU) * vV + fabsf(vecV) * vU)); dda.LimitSpeedAndAcceleration(vMax, aMax); } } diff --git a/src/Movement/Kinematics/Kinematics.cpp b/src/Movement/Kinematics/Kinematics.cpp index 51c4d1fe..145c466a 100644 --- a/src/Movement/Kinematics/Kinematics.cpp +++ b/src/Movement/Kinematics/Kinematics.cpp @@ -15,6 +15,7 @@ #include "HangprinterKinematics.h" #include "PolarKinematics.h" #include "CoreXYUVKinematics.h" +#include "RotaryDeltaKinematics.h" #include "RepRap.h" #include "Platform.h" #include "GCodes/GCodeBuffer.h" @@ -142,8 +143,10 @@ const char* Kinematics::GetHomingFileName(AxesBitmap toBeHomed, AxesBitmap alrea { switch (k) { + case KinematicsType::linearDeltaPlusZ: // not implemented yet default: return nullptr; + case KinematicsType::cartesian: return new CartesianKinematics(); case KinematicsType::linearDelta: @@ -162,6 +165,8 @@ const char* Kinematics::GetHomingFileName(AxesBitmap toBeHomed, AxesBitmap alrea return new PolarKinematics(); case KinematicsType::coreXYUV: return new CoreXYUVKinematics(); + case KinematicsType::rotaryDelta: + return new RotaryDeltaKinematics(); } } diff --git a/src/Movement/Kinematics/Kinematics.h b/src/Movement/Kinematics/Kinematics.h index f9ebe5d9..2275788b 100644 --- a/src/Movement/Kinematics/Kinematics.h +++ b/src/Movement/Kinematics/Kinematics.h @@ -29,8 +29,8 @@ enum class KinematicsType : uint8_t hangprinter, polar, coreXYUV, -// linearDeltaPlusZ, // reserved for @sga, see https://forum.duet3d.com/topic/5775/aditional-carterian-z-axis-on-delta-printer -// rotaryDelta, // not yet implemented + linearDeltaPlusZ, // reserved for @sga, see https://forum.duet3d.com/topic/5775/aditional-carterian-z-axis-on-delta-printer + rotaryDelta, // not yet implemented unknown // this one must be last! }; diff --git a/src/Movement/Kinematics/LinearDeltaKinematics.cpp b/src/Movement/Kinematics/LinearDeltaKinematics.cpp index e2eedfb4..c5c69b26 100644 --- a/src/Movement/Kinematics/LinearDeltaKinematics.cpp +++ b/src/Movement/Kinematics/LinearDeltaKinematics.cpp @@ -26,11 +26,11 @@ const char *LinearDeltaKinematics::GetName(bool forStatusReport) const void LinearDeltaKinematics::Init() { - diagonal = defaultDiagonal; - radius = defaultDeltaRadius; + diagonal = DefaultDiagonal; + radius = DefaultDeltaRadius; xTilt = yTilt = 0.0; - printRadius = defaultPrintRadius; - homedHeight = defaultDeltaHomedHeight; + printRadius = DefaultPrintRadius; + homedHeight = DefaultDeltaHomedHeight; doneAutoCalibration = false; for (size_t axis = 0; axis < DELTA_AXES; ++axis) @@ -68,7 +68,7 @@ void LinearDeltaKinematics::Recalc() // Calculate the base carriage height when the printer is homed, i.e. the carriages are at the endstops less the corrections const float tempHeight = diagonal; // any sensible height will do here float machinePos[DELTA_AXES]; - InverseTransform(tempHeight, tempHeight, tempHeight, machinePos); + ForwardTransform(tempHeight, tempHeight, tempHeight, machinePos); homedCarriageHeight = homedHeight + tempHeight - machinePos[Z_AXIS]; printRadiusSquared = fsquare(printRadius); } @@ -87,7 +87,6 @@ void LinearDeltaKinematics::NormaliseEndstopAdjustments() // Calculate the motor position for a single tower from a Cartesian coordinate. float LinearDeltaKinematics::Transform(const float machinePos[], size_t axis) const { - //TODO find a way of returning error if we can't transform the position if (axis < DELTA_AXES) { return sqrtf(D2 - fsquare(machinePos[X_AXIS] - towerX[axis]) - fsquare(machinePos[Y_AXIS] - towerY[axis])) @@ -102,7 +101,7 @@ float LinearDeltaKinematics::Transform(const float machinePos[], size_t axis) co } // Calculate the Cartesian coordinates from the motor coordinates -void LinearDeltaKinematics::InverseTransform(float Ha, float Hb, float Hc, float machinePos[DELTA_AXES]) const +void LinearDeltaKinematics::ForwardTransform(float Ha, float Hb, float Hc, float machinePos[DELTA_AXES]) const { const float Fa = coreFa + fsquare(Ha); const float Fb = coreFb + fsquare(Hb); @@ -129,10 +128,18 @@ void LinearDeltaKinematics::InverseTransform(float Ha, float Hb, float Hc, float // Convert Cartesian coordinates to motor steps bool LinearDeltaKinematics::CartesianToMotorSteps(const float machinePos[], const float stepsPerMm[], size_t numVisibleAxes, size_t numTotalAxes, int32_t motorPos[], bool isCoordinated) const { - //TODO return false if we can't transform the position + bool ok = true; for (size_t axis = 0; axis < min<size_t>(numVisibleAxes, DELTA_AXES); ++axis) { - motorPos[axis] = lrintf(Transform(machinePos, axis) * stepsPerMm[axis]); + const float pos = Transform(machinePos, axis); + if (isnan(pos) || isinf(pos)) + { + ok = false; + } + else + { + motorPos[axis] = lrintf(pos * stepsPerMm[axis]); + } } // Transform any additional axes linearly @@ -140,13 +147,13 @@ bool LinearDeltaKinematics::CartesianToMotorSteps(const float machinePos[], cons { motorPos[axis] = lrintf(machinePos[axis] * stepsPerMm[axis]); } - return true; + return ok; } // Convert motor coordinates to machine coordinates. Used after homing and after individual motor moves. void LinearDeltaKinematics::MotorStepsToCartesian(const int32_t motorPos[], const float stepsPerMm[], size_t numVisibleAxes, size_t numTotalAxes, float machinePos[]) const { - InverseTransform(motorPos[DELTA_A_AXIS]/stepsPerMm[DELTA_A_AXIS], motorPos[DELTA_B_AXIS]/stepsPerMm[DELTA_B_AXIS], motorPos[DELTA_C_AXIS]/stepsPerMm[DELTA_C_AXIS], machinePos); + ForwardTransform(motorPos[DELTA_A_AXIS]/stepsPerMm[DELTA_A_AXIS], motorPos[DELTA_B_AXIS]/stepsPerMm[DELTA_B_AXIS], motorPos[DELTA_C_AXIS]/stepsPerMm[DELTA_C_AXIS], machinePos); // Convert any additional axes linearly for (size_t drive = DELTA_AXES; drive < numVisibleAxes; ++drive) @@ -357,7 +364,7 @@ bool LinearDeltaKinematics::DoAutoCalibration(size_t numFactors, const RandomPro probeMotorPositions(i, axis) += solution[axis]; } float newPosition[DELTA_AXES]; - InverseTransform(probeMotorPositions(i, DELTA_A_AXIS), probeMotorPositions(i, DELTA_B_AXIS), probeMotorPositions(i, DELTA_C_AXIS), newPosition); + ForwardTransform(probeMotorPositions(i, DELTA_A_AXIS), probeMotorPositions(i, DELTA_B_AXIS), probeMotorPositions(i, DELTA_C_AXIS), newPosition); corrections[i] = newPosition[Z_AXIS]; expectedResiduals[i] = probePoints.GetZHeight(i) + newPosition[Z_AXIS]; sumOfSquares += fcsquare(expectedResiduals[i]); @@ -458,7 +465,7 @@ floatc_t LinearDeltaKinematics::ComputeDerivative(unsigned int deriv, float ha, } float newPos[DELTA_AXES]; - hiParams.InverseTransform((deriv == 0) ? ha + perturb : ha, (deriv == 1) ? hb + perturb : hb, (deriv == 2) ? hc + perturb : hc, newPos); + hiParams.ForwardTransform((deriv == 0) ? ha + perturb : ha, (deriv == 1) ? hb + perturb : hb, (deriv == 2) ? hc + perturb : hc, newPos); if (deriv == 7) { return -newPos[X_AXIS]/printRadius; @@ -469,7 +476,7 @@ floatc_t LinearDeltaKinematics::ComputeDerivative(unsigned int deriv, float ha, } const float zHi = newPos[Z_AXIS]; - loParams.InverseTransform((deriv == 0) ? ha - perturb : ha, (deriv == 1) ? hb - perturb : hb, (deriv == 2) ? hc - perturb : hc, newPos); + loParams.ForwardTransform((deriv == 0) ? ha - perturb : ha, (deriv == 1) ? hb - perturb : hb, (deriv == 2) ? hc - perturb : hc, newPos); const float zLo = newPos[Z_AXIS]; return ((floatc_t)zHi - (floatc_t)zLo)/(floatc_t)(2 * perturb); @@ -583,16 +590,9 @@ bool LinearDeltaKinematics::Configure(unsigned int mCode, GCodeBuffer& gb, const case 665: { bool seen = false; - if (gb.Seen('L')) - { - diagonal = gb.GetFValue(); - seen = true; - } - if (gb.Seen('R')) - { - radius = gb.GetFValue(); - seen = true; - } + gb.TryGetFValue('L', diagonal, seen); + gb.TryGetFValue('R', radius, seen); + if (gb.Seen('B')) { printRadius = gb.GetFValue(); @@ -604,24 +604,9 @@ bool LinearDeltaKinematics::Configure(unsigned int mCode, GCodeBuffer& gb, const p.SetAxisMaximum(Y_AXIS, printRadius, false); seen = true; } - if (gb.Seen('X')) - { - // X tower position correction - angleCorrections[DELTA_A_AXIS] = gb.GetFValue(); - seen = true; - } - if (gb.Seen('Y')) - { - // Y tower position correction - angleCorrections[DELTA_B_AXIS] = gb.GetFValue(); - seen = true; - } - if (gb.Seen('Z')) - { - // Z tower position correction - angleCorrections[DELTA_C_AXIS] = gb.GetFValue(); - seen = true; - } + gb.TryGetFValue('X', angleCorrections[DELTA_A_AXIS], seen); + gb.TryGetFValue('Y', angleCorrections[DELTA_B_AXIS], seen); + gb.TryGetFValue('Z', angleCorrections[DELTA_C_AXIS], seen); if (gb.Seen('H')) { @@ -649,21 +634,10 @@ bool LinearDeltaKinematics::Configure(unsigned int mCode, GCodeBuffer& gb, const case 666: { bool seen = false; - if (gb.Seen('X')) - { - endstopAdjustments[X_AXIS] = gb.GetFValue(); - seen = true; - } - if (gb.Seen('Y')) - { - endstopAdjustments[Y_AXIS] = gb.GetFValue(); - seen = true; - } - if (gb.Seen('Z')) - { - endstopAdjustments[Z_AXIS] = gb.GetFValue(); - seen = true; - } + gb.TryGetFValue('X', endstopAdjustments[DELTA_A_AXIS], seen); + gb.TryGetFValue('Y', endstopAdjustments[DELTA_B_AXIS], seen); + gb.TryGetFValue('Z', endstopAdjustments[DELTA_C_AXIS], seen); + if (gb.Seen('A')) { xTilt = gb.GetFValue() * 0.01; diff --git a/src/Movement/Kinematics/LinearDeltaKinematics.h b/src/Movement/Kinematics/LinearDeltaKinematics.h index c183587a..a17ee520 100644 --- a/src/Movement/Kinematics/LinearDeltaKinematics.h +++ b/src/Movement/Kinematics/LinearDeltaKinematics.h @@ -12,9 +12,6 @@ #include "Kinematics.h" constexpr size_t DELTA_AXES = 3; -constexpr size_t DELTA_A_AXIS = 0; -constexpr size_t DELTA_B_AXIS = 1; -constexpr size_t DELTA_C_AXIS = 2; // Class to hold the parameter for a delta machine. class LinearDeltaKinematics : public Kinematics @@ -60,37 +57,42 @@ private: void Recalc(); void NormaliseEndstopAdjustments(); // Make the average of the endstop adjustments zero float Transform(const float headPos[], size_t axis) const; // Calculate the motor position for a single tower from a Cartesian coordinate - void InverseTransform(float Ha, float Hb, float Hc, float headPos[]) const; // Calculate the Cartesian position from the motor positions + void ForwardTransform(float Ha, float Hb, float Hc, float headPos[]) const; // Calculate the Cartesian position from the motor positions floatc_t ComputeDerivative(unsigned int deriv, float ha, float hb, float hc) const; // Compute the derivative of height with respect to a parameter at a set of motor endpoints void Adjust(size_t numFactors, const floatc_t v[]); // Perform 3-, 4-, 6- or 7-factor adjustment void PrintParameters(const StringRef& reply) const; // Print all the parameters for debugging - // Delta parameter defaults - const float defaultDiagonal = 215.0; - const float defaultDeltaRadius = 105.6; - const float defaultPrintRadius = 80.0; // mm - const float defaultDeltaHomedHeight = 240.0; // mm + // Axis names used internally + static constexpr size_t DELTA_A_AXIS = 0; + static constexpr size_t DELTA_B_AXIS = 1; + static constexpr size_t DELTA_C_AXIS = 2; + + // Delta parameter defaults in mm + static constexpr float DefaultDiagonal = 215.0; + static constexpr float DefaultDeltaRadius = 105.6; + static constexpr float DefaultPrintRadius = 80.0; + static constexpr float DefaultDeltaHomedHeight = 240.0; // Core parameters - float diagonal; // The diagonal rod length, all 3 are assumed to be the same length - float radius; // The nominal delta radius, before any fine tuning of tower positions - float angleCorrections[DELTA_AXES]; // Tower position corrections - float endstopAdjustments[DELTA_AXES]; // How much above or below the ideal position each endstop is - float printRadius; - float homedHeight; - float xTilt, yTilt; // How much we need to raise Z for each unit of movement in the +X and +Y directions + float diagonal; // The diagonal rod length, all 3 are assumed to be the same length + float radius; // The nominal delta radius, before any fine tuning of tower positions + float angleCorrections[DELTA_AXES]; // Tower position corrections + float endstopAdjustments[DELTA_AXES]; // How much above or below the ideal position each endstop is + float printRadius; + float homedHeight; + float xTilt, yTilt; // How much we need to raise Z for each unit of movement in the +X and +Y directions - // Derived values - float towerX[DELTA_AXES]; // The X coordinate of each tower - float towerY[DELTA_AXES]; // The Y coordinate of each tower - float printRadiusSquared; - float homedCarriageHeight; + // Derived values + float towerX[DELTA_AXES]; // The X coordinate of each tower + float towerY[DELTA_AXES]; // The Y coordinate of each tower + float printRadiusSquared; + float homedCarriageHeight; float Xbc, Xca, Xab, Ybc, Yca, Yab; float coreFa, coreFb, coreFc; - float Q, Q2, D2; + float Q, Q2, D2; - bool doneAutoCalibration; // True if we have done auto calibration + bool doneAutoCalibration; // True if we have done auto calibration }; #endif /* LINEARDELTAKINEMATICS_H_ */ diff --git a/src/Movement/Kinematics/RotaryDeltaKinematics.cpp b/src/Movement/Kinematics/RotaryDeltaKinematics.cpp new file mode 100644 index 00000000..3b59d215 --- /dev/null +++ b/src/Movement/Kinematics/RotaryDeltaKinematics.cpp @@ -0,0 +1,507 @@ +/* + * RotaryDeltaKinematics.cpp + * + * Created on: 1 Aug 2018 + * Author: David + */ + +#include "RotaryDeltaKinematics.h" +#include "RepRap.h" +#include "Platform.h" +#include "Movement/DDA.h" +#include "GCodes/GCodeBuffer.h" + +const float RotaryDeltaKinematics::NormalTowerAngles[DELTA_AXES] = { -150.0, -30.0, 90.0 }; + +// Constructor +RotaryDeltaKinematics::RotaryDeltaKinematics() : Kinematics(KinematicsType::rotaryDelta, DefaultSegmentsPerSecond, DefaultMinSegmentSize, false) +{ + Init(); +} + +// Initialise parameters to defaults +void RotaryDeltaKinematics::Init() +{ + radius = DefaultDeltaRadius; + printRadius = DefaultPrintRadius; + minArmAngle = DefaultMinArmAngle; + maxArmAngle = DefaultMaxArmAngle; + + for (size_t axis = 0; axis < DELTA_AXES; ++axis) + { + armLengths[axis] = DefaultArmLength; + rodLengths[axis] = DefaultRodLength; + bearingHeights[axis] = DefaultBearingHeight; + angleCorrections[axis] = 0.0; + endstopAdjustments[axis] = 0.0; + } + + Recalc(); +} + +// Compute the derived parameters from the primary parameters +void RotaryDeltaKinematics::Recalc() +{ + printRadiusSquared = fsquare(printRadius); + for (size_t axis = 0; axis < DELTA_AXES; ++axis) + { + const float angle = (NormalTowerAngles[axis] + angleCorrections[axis]) * DegreesToRadians; + armAngleSines[axis] = sinf(angle); + armAngleCosines[axis] = cosf(angle); + twiceU[axis] = armLengths[axis] * 2; + rodSquared[axis] = fsquare(rodLengths[axis]); + rodSquaredMinusArmSquared[axis] = rodSquared[axis] - fsquare(armLengths[axis]); + } +} + +// Return the name of the current kinematics. +// If 'forStatusReport' is true then the string must be the one for that kinematics expected by DuetWebControl and PanelDue. +// Otherwise it should be in a format suitable for printing. +const char *RotaryDeltaKinematics::GetName(bool forStatusReport) const +{ + return "Rotary delta"; +} + +// Set or report the parameters from a M665, M666 or M669 command +// If 'mCode' is an M-code used to set parameters for the current kinematics (which should only ever be 665, 666, 667 or 669) +// then search for parameters used to configure the current kinematics. If any are found, perform appropriate actions, +// and return true if the changes affect the geometry. +// If errors were discovered while processing parameters, put an appropriate error message in 'reply' and set 'error' to true. +// If no relevant parameters are found, print the existing ones to 'reply' and return false. +// If 'mCode' does not apply to this kinematics, call the base class version of this function, which will print a suitable error message. +bool RotaryDeltaKinematics::Configure(unsigned int mCode, GCodeBuffer& gb, const StringRef& reply, bool& error) +{ + switch(mCode) + { + case 669: + { + bool seen = false; + size_t numValues = 3; + if (gb.TryGetFloatArray('L', numValues, armLengths, reply, seen, true)) + { + error = true; + return true; + } + + numValues = 3; + if (gb.TryGetFloatArray('R', numValues, rodLengths, reply, seen, true)) + { + error = true; + return true; + } + + numValues = 3; + if (gb.TryGetFloatArray('H', numValues, bearingHeights, reply, seen, true)) + { + error = true; + return true; + } + + numValues = 2; + if (gb.TryGetFloatArray('A', numValues, minMaxArmAngles, reply, seen, false)) + { + error = true; + return true; + } + + gb.TryGetFValue('R', radius, seen); + if (gb.Seen('B')) + { + printRadius = gb.GetFValue(); + // Set the axis limits so that DWC reports them correctly (they are not otherwise used for deltas, except Z min) + Platform& p = reprap.GetPlatform(); + p.SetAxisMinimum(X_AXIS, -printRadius, false); + p.SetAxisMinimum(Y_AXIS, -printRadius, false); + p.SetAxisMaximum(X_AXIS, printRadius, false); + p.SetAxisMaximum(Y_AXIS, printRadius, false); + seen = true; + } + + gb.TryGetFValue('X', angleCorrections[DELTA_A_AXIS], seen); + gb.TryGetFValue('Y', angleCorrections[DELTA_B_AXIS], seen); + gb.TryGetFValue('Z', angleCorrections[DELTA_C_AXIS], seen); + + if (seen) + { + Recalc(); + } + else + { + reply.printf("Arms (%.3f,%.2f,%.3f)mm, rods (%.3f,%.3f,%.3f)mm, bearingHeights (%.3f,%.2f,%.3f)mm" + ", arm movement %.1f to %.1f" DEGREE_SYMBOL + ", delta radius %.3f, bed radius %.1f" + ", angle corrections (%.3f,%.3f,%.3f)" DEGREE_SYMBOL , + (double)armLengths[DELTA_A_AXIS], (double)armLengths[DELTA_B_AXIS], (double)armLengths[DELTA_C_AXIS], + (double)rodLengths[DELTA_A_AXIS], (double)rodLengths[DELTA_B_AXIS], (double)rodLengths[DELTA_C_AXIS], + (double)bearingHeights[DELTA_A_AXIS], (double)bearingHeights[DELTA_B_AXIS], (double)bearingHeights[DELTA_C_AXIS], + (double)minArmAngle, (double)maxArmAngle, + (double)radius, (double)printRadius, + (double)angleCorrections[DELTA_A_AXIS], (double)angleCorrections[DELTA_B_AXIS], (double)angleCorrections[DELTA_C_AXIS]); + } + return seen; + } + + case 666: + { + bool seen = false; + gb.TryGetFValue('X', endstopAdjustments[DELTA_A_AXIS], seen); + gb.TryGetFValue('Y', endstopAdjustments[DELTA_B_AXIS], seen); + gb.TryGetFValue('Z', endstopAdjustments[DELTA_C_AXIS], seen); + + if (!seen) + { + reply.printf("Endstop adjustments X%.2f Y%.2f Z%.2f" DEGREE_SYMBOL, + (double)endstopAdjustments[X_AXIS], (double)endstopAdjustments[Y_AXIS], (double)endstopAdjustments[Z_AXIS]); + } + return seen; + } + + default: + return Kinematics::Configure(mCode, gb, reply, error); + } +} + +// Convert Cartesian coordinates to motor positions measured in steps from reference position +// 'machinePos' is a set of axis and extruder positions to convert +// 'stepsPerMm' is as configured in M92. On a Scara or polar machine this would actually be steps per degree. +// 'numAxes' is the number of machine axes to convert, which will always be at least 3 +// 'motorPos' is the output vector of motor positions +// Return true if successful, false if we were unable to convert +bool RotaryDeltaKinematics::CartesianToMotorSteps(const float machinePos[], const float stepsPerMm[], size_t numVisibleAxes, size_t numTotalAxes, int32_t motorPos[], bool isCoordinated) const +{ + bool ok = true; + for (size_t axis = 0; axis < min<size_t>(numVisibleAxes, DELTA_AXES); ++axis) + { + const float pos = Transform(machinePos, axis); + if (isnan(pos) || isinf(pos)) + { + ok = false; + } + else + { + motorPos[axis] = lrintf(pos * stepsPerMm[axis]); + } + } + + // TEMP DEBUG + if (reprap.Debug(moduleMove)) + { + debugPrintf("Transformed %.2f,%.2f,%.2f mm to %" PRIi32 ",%" PRIi32 ",%" PRIi32 "steps\n", + (double)machinePos[0], (double)machinePos[1], (double)machinePos[2], + motorPos[0], motorPos[1], motorPos[2]); + } + + // Transform any additional axes linearly + for (size_t axis = DELTA_AXES; axis < numVisibleAxes; ++axis) + { + motorPos[axis] = lrintf(machinePos[axis] * stepsPerMm[axis]); + } + return ok; +} + +// Convert motor positions (measured in steps from reference position) to Cartesian coordinates +// 'motorPos' is the input vector of motor positions +// 'stepsPerMm' is as configured in M92. On a Scara or polar machine this would actually be steps per degree. +// 'numDrives' is the number of machine drives to convert, which will always be at least 3 +// 'machinePos' is the output set of converted axis and extruder positions +void RotaryDeltaKinematics::MotorStepsToCartesian(const int32_t motorPos[], const float stepsPerMm[], size_t numVisibleAxes, size_t numTotalAxes, float machinePos[]) const +{ + ForwardTransform(motorPos[DELTA_A_AXIS]/stepsPerMm[DELTA_A_AXIS], motorPos[DELTA_B_AXIS]/stepsPerMm[DELTA_B_AXIS], motorPos[DELTA_C_AXIS]/stepsPerMm[DELTA_C_AXIS], machinePos); + + // Convert any additional axes linearly + for (size_t drive = DELTA_AXES; drive < numVisibleAxes; ++drive) + { + machinePos[drive] = motorPos[drive]/stepsPerMm[drive]; + } +} + +// Perform auto calibration. Caller already owns the movement lock. +// Return true if an error occurred. +bool RotaryDeltaKinematics::DoAutoCalibration(size_t numFactors, const RandomProbePointSet& probePoints, const StringRef& reply) +{ + return true; // auto calibration not implemented yet +} + +// Write the parameters that are set by auto calibration to a file, returning true if success +bool RotaryDeltaKinematics::WriteCalibrationParameters(FileStore *f) const +{ + return true; // auto calibration not implemented yet +} + +// Return true if the specified XY position is reachable by the print head reference point. +bool RotaryDeltaKinematics::IsReachable(float x, float y, bool isCoordinated) const +{ + return fsquare(x) + fsquare(y) < printRadiusSquared; +} + +// Limit the Cartesian position that the user wants to move to returning true if we adjusted the position +bool RotaryDeltaKinematics::LimitPosition(float coords[], size_t numVisibleAxes, AxesBitmap axesHomed, bool isCoordinated) const +{ + const AxesBitmap allAxes = MakeBitmap<AxesBitmap>(X_AXIS) | MakeBitmap<AxesBitmap>(Y_AXIS) | MakeBitmap<AxesBitmap>(Z_AXIS); + bool limited = false; + if ((axesHomed & allAxes) == allAxes) + { + // If axes have been homed on a delta printer and this isn't a homing move, check for movements outside limits. + // Skip this check if axes have not been homed, so that extruder-only moves are allowed before homing + // Constrain the move to be within the build radius + const float diagonalSquared = fsquare(coords[X_AXIS]) + fsquare(coords[Y_AXIS]); + if (diagonalSquared > printRadiusSquared) + { + const float factor = sqrtf(printRadiusSquared / diagonalSquared); + coords[X_AXIS] *= factor; + coords[Y_AXIS] *= factor; + limited = true; + } + + if (coords[Z_AXIS] < reprap.GetPlatform().AxisMinimum(Z_AXIS)) + { + coords[Z_AXIS] = reprap.GetPlatform().AxisMinimum(Z_AXIS); + limited = true; + } + else if (coords[Z_AXIS] > reprap.GetPlatform().AxisMaximum(Z_AXIS)) + { + coords[Z_AXIS] = reprap.GetPlatform().AxisMaximum(Z_AXIS); + limited = true; + } + } + + // Limit any additional axes according to the M208 limits + if (LimitPositionFromAxis(coords, Z_AXIS + 1, numVisibleAxes, axesHomed)) + { + limited = true; + } + + return limited; +} + +// Return the initial Cartesian coordinates we assume after switching to this kinematics +void RotaryDeltaKinematics::GetAssumedInitialPosition(size_t numAxes, float positions[]) const +{ + ForwardTransform(0.0, 0.0, 0.0, positions); // assume that the arms are horizontal + for (size_t i = DELTA_AXES; i < numAxes; ++i) + { + positions[i] = 0.0; // set additional axes to zero + } +} + +// Return the axes that we can assume are homed after executing a G92 command to set the specified axis coordinates +AxesBitmap RotaryDeltaKinematics::AxesAssumedHomed(AxesBitmap g92Axes) const +{ + // If all of X, Y and Z have been specified then we know the positions of all 3 tower motors, otherwise we don't + constexpr AxesBitmap xyzAxes = MakeBitmap<AxesBitmap>(X_AXIS) | MakeBitmap<AxesBitmap>(Y_AXIS) | MakeBitmap<AxesBitmap>(Z_AXIS); + if ((g92Axes & xyzAxes) != xyzAxes) + { + g92Axes &= ~xyzAxes; + } + return g92Axes; +} + +// Return the set of axes that must be homed prior to regular movement of the specified axes +AxesBitmap RotaryDeltaKinematics::MustBeHomedAxes(AxesBitmap axesMoving, bool disallowMovesBeforeHoming) const +{ + constexpr AxesBitmap xyzAxes = MakeBitmap<AxesBitmap>(X_AXIS) | MakeBitmap<AxesBitmap>(Y_AXIS) | MakeBitmap<AxesBitmap>(Z_AXIS); + if ((axesMoving & xyzAxes) != 0) + { + axesMoving |= xyzAxes; + } + return axesMoving; +} + +// This function is called when a request is made to home the axes in 'toBeHomed' and the axes in 'alreadyHomed' have already been homed. +// If we can proceed with homing some axes, return the name of the homing file to be called. +// If we can't proceed because other axes need to be homed first, return nullptr and pass those axes back in 'mustBeHomedFirst'. +const char* RotaryDeltaKinematics::GetHomingFileName(AxesBitmap toBeHomed, AxesBitmap alreadyHomed, size_t numVisibleAxes, AxesBitmap& mustHomeFirst) const +{ + // If homing X, Y or Z we must home all the towers + if ((toBeHomed & LowestNBits<AxesBitmap>(DELTA_AXES)) != 0) + { + return "homedelta.g"; + } + + // Return the homing file for the lowest axis that we have been asked to home + for (size_t axis = DELTA_AXES; axis < numVisibleAxes; ++axis) + { + if (IsBitSet(toBeHomed, axis)) + { + return StandardHomingFileNames[axis]; + } + } + + mustHomeFirst = 0; + return nullptr; +} + +// This function is called from the step ISR when an endstop switch is triggered during homing. +// Return true if the entire homing move should be terminated, false if only the motor associated with the endstop switch should be stopped. +bool RotaryDeltaKinematics::QueryTerminateHomingMove(size_t axis) const +{ + return false; +} + +// 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. +void RotaryDeltaKinematics::OnHomingSwitchTriggered(size_t axis, bool highEnd, const float stepsPerMm[], DDA& dda) const +{ + if (axis < DELTA_AXES) + { + if (highEnd) + { + const float hitPoint = maxArmAngle + endstopAdjustments[axis]; + dda.SetDriveCoordinate(lrintf(hitPoint * stepsPerMm[axis]), axis); + } + } + else + { + // Assume that any additional axes are linear + const float hitPoint = (highEnd) ? reprap.GetPlatform().AxisMaximum(axis) : reprap.GetPlatform().AxisMinimum(axis); + dda.SetDriveCoordinate(lrintf(hitPoint * stepsPerMm[axis]), axis); + } +} + +// Write any calibration data that we need to resume a print after power fail, returning true if successful +bool RotaryDeltaKinematics::WriteResumeSettings(FileStore *f) const +{ +// return !doneAutoCalibration || WriteCalibrationParameters(f); + return true; // auto calibration not implemented yet +} + +// Limit the speed and acceleration of a move to values that the mechanics can handle. +// The speeds in Cartesian space have already been limited. +void RotaryDeltaKinematics::LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector) const +{ + // Limit the speed in the XY plane to the lower of the X and Y maximum speeds, and similarly for the acceleration + const float xyFactor = sqrtf(fsquare(normalisedDirectionVector[X_AXIS]) + fsquare(normalisedDirectionVector[Y_AXIS])); + if (xyFactor > 0.01) + { + const Platform& platform = reprap.GetPlatform(); + const float maxSpeed = min<float>(platform.MaxFeedrate(X_AXIS), platform.MaxFeedrate(Y_AXIS)); + const float maxAcceleration = min<float>(platform.Acceleration(X_AXIS), platform.Acceleration(Y_AXIS)); + dda.LimitSpeedAndAcceleration(maxSpeed/xyFactor, maxAcceleration/xyFactor); + } +} + +// Calculate the motor position for a single tower from a Cartesian coordinate. +// If we first transform the XY coordinates so that +X is along the direction of the arm, then we need to solve this equation: +// L^2 = (U cos(theta) + (R - x))^2 + y^2 + (U sin(theta) + (H - z))^2 +// Expanding this and using cos^2(theta) + sin^2(theta) = 1 we get: +// L^2 = U^2 + (H - z)^2 + (R - x)^2 + y^2 + 2U(R - x)cos(theta) + 2U(H - z)sin(theta) +// This is of the form: +// a cos(theta) + b sin(theta) = c +// where: +// a = 2U(r - x), b = 2U(H - z), c = L^2 - U^2 - (H - z)^2 - (R - x)^2 - y^2 +// We can rearrange, square and use sin^2 + cos^2 = 1 again to get this: +// (a^2 + b^2)sin^2(theta) - 2bc sin(theta) + (c^2 - a^2) = 0 +// which has solutions: +// sin(theta) = (bc +/- a sqrt(a^2 + b^2 - c^2))/(a^2 + b^2) +float RotaryDeltaKinematics::Transform(const float machinePos[], size_t axis) const +{ + if (axis < DELTA_AXES) + { + // 1. Transform the X and Y coordinates so that +X is along the arm and +Y is 90deg anticlockwise from +X + const float x = machinePos[X_AXIS] * armAngleCosines[axis] + machinePos[Y_AXIS] * armAngleSines[axis]; + const float y = machinePos[Y_AXIS] * armAngleCosines[axis] - machinePos[X_AXIS] * armAngleSines[axis]; + + // 2. Calculate a, b and c + const float rMinusX = radius - x; + const float hMinusZ = bearingHeights[axis] - machinePos[Z_AXIS]; + const float a = twiceU[axis] * rMinusX; + const float b = twiceU[axis] * hMinusZ; + const float c = rodSquaredMinusArmSquared[axis] - (fsquare(hMinusZ) + fsquare(rMinusX) + fsquare(y)); + + // 3. Solve the quadratic equation, taking the lower root + const float sinTheta = (b * c - a * sqrtf(fsquare(a) + fsquare(b) - fsquare(c)))/(fsquare(a) + fsquare(b)); + + // 4. Take the arc sine and convert to degrees + return asinf(sinTheta) * RadiansToDegrees; + } + else + { + return machinePos[axis]; // any additional axes must be linear + } +} + +// Calculate the Cartesian coordinates from the motor coordinates. We do this by trilateration. +void RotaryDeltaKinematics::ForwardTransform(float Ha, float Hb, float Hc, float machinePos[DELTA_AXES]) const +{ + // Calculate the Cartesian coordinates of the joints at the moving ends of the arms + const float angleA = Ha * DegreesToRadians; + const float posAX = (radius + (armLengths[DELTA_A_AXIS] * cosf(angleA))) * armAngleCosines[DELTA_A_AXIS]; + const float posAY = (radius + (armLengths[DELTA_A_AXIS] * cosf(angleA))) * armAngleSines[DELTA_A_AXIS]; + const float posAZ = bearingHeights[DELTA_A_AXIS] + sinf(angleA); + + const float angleB = Hb * DegreesToRadians; + const float posBX = (radius + (armLengths[DELTA_B_AXIS] * cosf(angleB))) * armAngleCosines[DELTA_B_AXIS]; + const float posBY = (radius + (armLengths[DELTA_B_AXIS] * cosf(angleB))) * armAngleSines[DELTA_B_AXIS]; + const float posBZ = bearingHeights[DELTA_B_AXIS] + sinf(angleB); + + const float angleC = Hc * DegreesToRadians; + const float posCX = (radius + (armLengths[DELTA_C_AXIS] * cosf(angleC))) * armAngleCosines[DELTA_C_AXIS]; + const float posCY = (radius + (armLengths[DELTA_C_AXIS] * cosf(angleC))) * armAngleSines[DELTA_C_AXIS]; + const float posCZ = bearingHeights[DELTA_C_AXIS] + sinf(angleC); + + // Calculate some intermediate values that we will use more than once + const float Da2 = fsquare(posAX) + fsquare(posAY) + fsquare(posAZ); + const float Db2 = fsquare(posBX) + fsquare(posBY) + fsquare(posBZ); + const float Dc2 = fsquare(posCX) + fsquare(posCY) + fsquare(posCZ); + + const float Xab = posAX - posBX; + const float Xbc = posBX - posCX; + const float Xca = posCX - posAX; + + const float Yab = posAY - posBY; + const float Ybc = posBY - posCY; + const float Yca = posCY - posAY; + + const float Zca = posCZ - posAZ; + + // Calculate PQRST such that x = (Qz + S)/P, y = (Rz + T)/P. + const float P = ( posBX * Yca + - posAX * posCY + + posAY * posCX + - posBY * Xca + ) * 2; + + const float Q = ( posBY * Zca + - posAY * posCZ + + posAZ * posCY + - posBZ * Yca + ) * 2; + + const float R = - ( posBX * Zca + + posAX * posCZ + + posAZ * posCX + - posBZ * Xca + ) * 2; + + const float P2 = fsquare(P); + const float U = (posAZ * P2) + (posAX * Q * P) + (posAY * R * P); + const float A = (P2 + fsquare(Q) + fsquare(R)) * 2; + + const float S = - Yab * (rodSquared[DELTA_C_AXIS] - Dc2) + - Yca * (rodSquared[DELTA_B_AXIS] - Db2) + - Ybc * (rodSquared[DELTA_A_AXIS] - Da2); + const float T = - Xab * (rodSquared[DELTA_C_AXIS] - Dc2) + + Xca * (rodSquared[DELTA_B_AXIS] - Db2) + + Xbc * (rodSquared[DELTA_A_AXIS] - Da2); + + // Calculate quadratic equation coefficients + const float halfB = (S * Q) - (R * T) - U; + const float C = fsquare(S) + fsquare(T) + (posAY * T - posAX * S) * P * 2 + (Da2 - rodSquared[DELTA_A_AXIS]) * P2; + + // Solve the quadratic equation for z + const float z = (- halfB - sqrtf(fsquare(halfB) - A * C))/A; + + // Substitute back for X and Y + machinePos[X_AXIS] = (Q * z + S)/P; + machinePos[Y_AXIS] = (R * z + T)/P; + machinePos[Z_AXIS] = z; + + if (reprap.Debug(moduleMove)) + { + debugPrintf("Trilaterated (%.2f, %.2f, %.2f)" DEGREE_SYMBOL " to X=%.2f Y=%.2f Z=%.2f\n", + (double)Ha, (double)Hb, (double)Hc, + (double)machinePos[X_AXIS], (double)machinePos[Y_AXIS], (double)machinePos[Z_AXIS]); + } +} + +// End diff --git a/src/Movement/Kinematics/RotaryDeltaKinematics.h b/src/Movement/Kinematics/RotaryDeltaKinematics.h new file mode 100644 index 00000000..0630e9f2 --- /dev/null +++ b/src/Movement/Kinematics/RotaryDeltaKinematics.h @@ -0,0 +1,88 @@ +/* + * RotaryDeltaKinematics.h + * + * Created on: 1 Aug 2018 + * Author: David + */ + +#ifndef SRC_MOVEMENT_KINEMATICS_ROTARYDELTAKINEMATICS_H_ +#define SRC_MOVEMENT_KINEMATICS_ROTARYDELTAKINEMATICS_H_ + +#include "Kinematics.h" + +class RotaryDeltaKinematics : public Kinematics +{ +public: + // Constructors + RotaryDeltaKinematics(); + + // Overridden base class functions. See Kinematics.h for descriptions. + const char *GetName(bool forStatusReport) const override; + bool Configure(unsigned int mCode, GCodeBuffer& gb, const StringRef& reply, bool& error) override; + bool CartesianToMotorSteps(const float machinePos[], const float stepsPerMm[], size_t numVisibleAxes, size_t numTotalAxes, int32_t motorPos[], bool isCoordinated) const override; + void MotorStepsToCartesian(const int32_t motorPos[], const float stepsPerMm[], size_t numVisibleAxes, size_t numTotalAxes, float machinePos[]) const override; + bool SupportsAutoCalibration() const override { return false; } // TODO support autocalibration + bool DoAutoCalibration(size_t numFactors, const RandomProbePointSet& probePoints, const StringRef& reply) override; + void SetCalibrationDefaults() override { Init(); } + bool WriteCalibrationParameters(FileStore *f) const override; + bool IsReachable(float x, float y, bool isCoordinated) const override; + bool LimitPosition(float coords[], size_t numVisibleAxes, AxesBitmap axesHomed, bool isCoordinated) const override; + void GetAssumedInitialPosition(size_t numAxes, float positions[]) const override; + AxesBitmap AxesToHomeBeforeProbing() const override { return MakeBitmap<AxesBitmap>(X_AXIS) | MakeBitmap<AxesBitmap>(Y_AXIS) | MakeBitmap<AxesBitmap>(Z_AXIS); } + size_t NumHomingButtons(size_t numVisibleAxes) const override { return 0; } + HomingMode GetHomingMode() const override { return homeIndividualMotors; } + AxesBitmap AxesAssumedHomed(AxesBitmap g92Axes) const override; + AxesBitmap MustBeHomedAxes(AxesBitmap axesMoving, bool disallowMovesBeforeHoming) const override; + const char* GetHomingFileName(AxesBitmap toBeHomed, AxesBitmap alreadyHomed, size_t numVisibleAxes, AxesBitmap& mustHomeFirst) const override; + bool QueryTerminateHomingMove(size_t axis) const override; + void OnHomingSwitchTriggered(size_t axis, bool highEnd, const float stepsPerMm[], DDA& dda) const override; + bool WriteResumeSettings(FileStore *f) const override; + void LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector) const override; + +private: + void Init(); + void Recalc(); + float Transform(const float headPos[], size_t axis) const; // Calculate the motor position for a single tower from a Cartesian coordinate + void ForwardTransform(float Ha, float Hb, float Hc, float headPos[]) const; // Calculate the Cartesian position from the motor positions + + // Axis names used internally + static constexpr size_t DELTA_AXES = 3; + static constexpr size_t DELTA_A_AXIS = 0; + static constexpr size_t DELTA_B_AXIS = 1; + static constexpr size_t DELTA_C_AXIS = 2; + + // Delta mechanism parameter defaults + static constexpr float DefaultSegmentsPerSecond = 100.0; + static constexpr float DefaultMinSegmentSize = 0.2; + static constexpr float DefaultArmLength = 100.0; + static constexpr float DefaultRodLength = 200.0; + static constexpr float DefaultDeltaRadius = 50.0; + static constexpr float DefaultPrintRadius = 80.0; + static constexpr float DefaultBearingHeight = 250.0; + static constexpr float DefaultMinArmAngle = -45.0; + static constexpr float DefaultMaxArmAngle = 45.0; + + static const float NormalTowerAngles[DELTA_AXES]; + + // Core parameters + float radius; // The nominal delta radius, before any fine tuning of tower positions + float bearingHeights[DELTA_AXES]; + float armLengths[DELTA_AXES]; + float rodLengths[DELTA_AXES]; + float angleCorrections[DELTA_AXES]; // Tower position corrections + float endstopAdjustments[DELTA_AXES]; // How much above or below the ideal position each endstop is + float minMaxArmAngles[2]; + float& minArmAngle = minMaxArmAngles[0]; + float& maxArmAngle = minMaxArmAngles[1]; + float printRadius; + + // Derived values + float armAngleCosines[DELTA_AXES]; + float armAngleSines[DELTA_AXES]; + float twiceU[DELTA_AXES]; + float rodSquared[DELTA_AXES]; + float rodSquaredMinusArmSquared[DELTA_AXES]; + float printRadiusSquared; +}; + +#endif /* SRC_MOVEMENT_KINEMATICS_ROTARYDELTAKINEMATICS_H_ */ diff --git a/src/Movement/Kinematics/ScaraKinematics.cpp b/src/Movement/Kinematics/ScaraKinematics.cpp index 8b99645d..ff85c5e2 100644 --- a/src/Movement/Kinematics/ScaraKinematics.cpp +++ b/src/Movement/Kinematics/ScaraKinematics.cpp @@ -469,7 +469,7 @@ void ScaraKinematics::Recalc() } else { - const float minAngle = min<float>(fabs(psiLimits[0]), fabs(psiLimits[1])) * DegreesToRadians; + const float minAngle = min<float>(fabsf(psiLimits[0]), fabsf(psiLimits[1])) * DegreesToRadians; maxRadius = sqrtf(proximalArmLengthSquared + distalArmLengthSquared + (twoPd * cosf(minAngle))); } maxRadius *= 0.995; diff --git a/src/Movement/Kinematics/ZLeadscrewKinematics.h b/src/Movement/Kinematics/ZLeadscrewKinematics.h index 21e82041..78f1147a 100644 --- a/src/Movement/Kinematics/ZLeadscrewKinematics.h +++ b/src/Movement/Kinematics/ZLeadscrewKinematics.h @@ -26,7 +26,7 @@ public: private: void AppendCorrections(const floatc_t corrections[], const StringRef& reply) const; - static const unsigned int MaxLeadscrews = 4; + static const unsigned int MaxLeadscrews = 8; // some Folgertech FT5 printers have 8 bed adjusting screws unsigned int numLeadscrews; float leadscrewX[MaxLeadscrews], leadscrewY[MaxLeadscrews]; diff --git a/src/Movement/Move.cpp b/src/Movement/Move.cpp index 89b4ef81..f3d9807b 100644 --- a/src/Movement/Move.cpp +++ b/src/Movement/Move.cpp @@ -73,6 +73,8 @@ void Move::Init() currentDda = nullptr; stepErrors = 0; numLookaheadUnderruns = numPrepareUnderruns = numLookaheadErrors = 0; + maxPrintingAcceleration = maxTravelAcceleration = 10000.0; + drcEnabled = false; // disable dynamic ringing cancellation // Clear the transforms SetIdentityTransform(); @@ -1284,6 +1286,20 @@ bool Move::WriteResumeSettings(FileStore *f) const return kinematics->WriteResumeSettings(f) && (!usingMesh || f->Write("G29 S1\n")); } +// Set the DRC frequency or disable DRC +void Move::SetDRCfreq(float f) +{ + if (f >= 4.0 && f <= 10000.0) + { + drcPeriod = 1.0/f; + drcEnabled = true; + } + else + { + drcEnabled = false; + } +} + // For debugging void Move::PrintCurrentDda() const { diff --git a/src/Movement/Move.h b/src/Movement/Move.h index 2fefc201..e8a6bb32 100644 --- a/src/Movement/Move.h +++ b/src/Movement/Move.h @@ -71,6 +71,15 @@ public: unsigned int GetNumProbePoints() const; // Return the number of currently used probe points float PushBabyStepping(float amount); // Try to push some babystepping through the lookahead queue + float GetMaxPrintingAcceleration() const { return maxPrintingAcceleration; } + void SetMaxPrintingAcceleration(float acc) { maxPrintingAcceleration = acc; } + float GetMaxTravelAcceleration() const { return maxTravelAcceleration; } + void SetMaxTravelAcceleration(float acc) { maxTravelAcceleration = acc; } + float GetDRCfreq() const { return 1.0/drcPeriod; } + float GetDRCperiod() const { return drcPeriod; } + float IsDRCenabled() const { return drcEnabled; } + void SetDRCfreq(float f); + void Diagnostics(MessageType mtype); // Report useful stuff void RecordLookaheadError() { ++numLookaheadErrors; } // Record a lookahead error @@ -165,6 +174,11 @@ private: bool active; // Are we live and running? uint8_t simulationMode; // Are we simulating, or really printing? MoveState moveState; // whether the idle timer is active + bool drcEnabled; + + float maxPrintingAcceleration; + float maxTravelAcceleration; + float drcPeriod; // the period of ringing that we don't want to excite unsigned int numLookaheadUnderruns; // How many times we have run out of moves to adjust during lookahead unsigned int numPrepareUnderruns; // How many times we wanted a new move but there were only un-prepared moves in the queue diff --git a/src/Pccb/Pins_Pccb.h b/src/Pccb/Pins_Pccb.h index c361156b..db2ce2b4 100644 --- a/src/Pccb/Pins_Pccb.h +++ b/src/Pccb/Pins_Pccb.h @@ -8,7 +8,12 @@ #ifndef SRC_DUETM_PINS_DUETM_H_ #define SRC_DUETM_PINS_DUETM_H_ -#define FIRMWARE_NAME "RepRapFirmware for PCCB" +#ifdef PCCB_X5 +# define FIRMWARE_NAME "RepRapFirmware for PCCB+DueX5" +#else +# define FIRMWARE_NAME "RepRapFirmware for PCCB" +#endif + #define DEFAULT_BOARD_TYPE BoardType::PCCB_10 constexpr size_t NumFirmwareUpdateModules = 1; // 1 module #define IAP_FIRMWARE_FILE "PccbFirmware.bin" @@ -21,8 +26,15 @@ constexpr size_t NumFirmwareUpdateModules = 1; // 1 module #define HAS_CPU_TEMP_SENSOR 1 #define HAS_HIGH_SPEED_SD 1 // SD card socket is optional -#define SUPPORT_TMC22xx 1 -#define TMC22xx_HAS_MUX 0 + +#ifdef PCCB_X5 +# define SUPPORT_TMC2660 1 +# define TMC2660_USES_USART 0 +#else +# define SUPPORT_TMC22xx 1 +# define TMC22xx_HAS_MUX 0 +#endif + #define HAS_VOLTAGE_MONITOR 1 #define HAS_VREF_MONITOR 1 #define ACTIVE_LOW_HEAT_ON 1 // although we have no heaters, this matters because we treat the LEDs as heaters @@ -38,9 +50,19 @@ constexpr size_t NumFirmwareUpdateModules = 1; // 1 module // The physical capabilities of the machine +#ifdef PCCB_X5 + +constexpr size_t DRIVES = 6; // The maximum number of drives supported by the electronics +constexpr size_t MaxSmartDrivers = 5; // The maximum number of smart drivers +# define DRIVES_(a,b,c,d,e,f,g,h,i,j,k,l) { a,b,c,d,e,f } + +#else + constexpr size_t DRIVES = 8; // The maximum number of drives supported by the electronics constexpr size_t MaxSmartDrivers = 2; // The maximum number of smart drivers -#define DRIVES_(a,b,c,d,e,f,g,h,i,j,k,l) { a,b,c,d,e,f,g,h } +# define DRIVES_(a,b,c,d,e,f,g,h,i,j,k,l) { a,b,c,d,e,f,g,h } + +#endif constexpr size_t Heaters = 2; // The number of heaters in the machine. PCCB has no heaters, but we pretend that the LED pins are heaters. constexpr size_t NumExtraHeaterProtections = 4; // The number of extra heater protection instances @@ -63,15 +85,37 @@ constexpr size_t NUM_SERIAL_CHANNELS = 1; // The number of serial IO channels // The numbers of entries in each array must correspond with the values of DRIVES, AXES, or HEATERS. Set values to NoPin to flag unavailability. // Drivers -constexpr Pin GlobalTmcEnablePin = 1; // The pin that drives ENN of all drivers +constexpr Pin GlobalTmc22xxEnablePin = 1; // The pin that drives ENN of all internal drivers + +#ifdef PCCB_X5 + +constexpr Pin GlobalTmc2660EnablePin = 52; // The pin that drives ENN of all drivers on the DueX5 +constexpr Pin ENABLE_PINS[DRIVES] = { 61, 35, 41, 55, 0, 64 }; +constexpr Pin STEP_PINS[DRIVES] = { 60, 38, 58, 56, 46, 50 }; +constexpr Pin DIRECTION_PINS[DRIVES] = { 17, 57, 54, 34, 1, 53 }; + +Spi * const SPI_TMC2660 = SPI; +constexpr uint32_t ID_TMC2660_SPI = ID_SPI; +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 + +#else + constexpr Pin ENABLE_PINS[DRIVES] = { NoPin, NoPin, 61, 35, 41, 55, 0, 64 }; constexpr Pin STEP_PINS[DRIVES] = { 40, 43, 60, 38, 58, 56, 46, 50 }; constexpr Pin DIRECTION_PINS[DRIVES] = { 8, 11, 17, 57, 54, 34, 1, 53 }; -Uart * const DriverUarts[MaxSmartDrivers] = { UART0, UART1 }; -constexpr uint32_t DriverUartIds[MaxSmartDrivers] = { ID_UART0, ID_UART1 }; -constexpr IRQn DriverUartIRQns[MaxSmartDrivers] = { UART0_IRQn, UART1_IRQn }; -constexpr Pin DriverUartPins[MaxSmartDrivers] = { APINS_UART0, APINS_UART1 }; +Uart * const TMC22xxUarts[MaxSmartDrivers] = { UART0, UART1 }; +constexpr uint32_t TMC22xxUartIds[MaxSmartDrivers] = { ID_UART0, ID_UART1 }; +constexpr IRQn TMC22xxUartIRQns[MaxSmartDrivers] = { UART0_IRQn, UART1_IRQn }; +constexpr Pin TMC22xxUartPins[MaxSmartDrivers] = { APINS_UART0, APINS_UART1 }; + +#endif // Define the baud rate used to send/receive data to/from the drivers. // If we assume a worst case clock frequency of 8MHz then the maximum baud rate is 8MHz/16 = 500kbaud. @@ -89,7 +133,11 @@ 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. +#ifdef PCCB_X5 +constexpr Pin END_STOP_PINS[DRIVES] = { 24, 25, 67, 63, NoPin, NoPin }; +#else constexpr Pin END_STOP_PINS[DRIVES] = { 24, 25, 67, 63, NoPin, NoPin, NoPin, NoPin }; +#endif // Heaters and thermistors constexpr Pin HEAT_ON_PINS[Heaters] = { 36, 59 }; // these are actually the LED control pins diff --git a/src/Platform.cpp b/src/Platform.cpp index db9d8166..44f60c37 100644 --- a/src/Platform.cpp +++ b/src/Platform.cpp @@ -199,6 +199,9 @@ void Platform::Init() SetBoardType(BoardType::Auto); #ifdef PCCB + // Make sure the on-board TMC22xx drivers are disabled + pinMode(GlobalTmc22xxEnablePin, OUTPUT_HIGH); + // Ensure that the main LEDs are turned off. // The main LED output is active, just like a heater on the Duet 2 series. // The secondary LED control dims the LED via the external controller when the output is high. So both outputs must be initialised high. @@ -324,7 +327,6 @@ void Platform::Init() ARRAY_INIT(accelerations, ACCELERATIONS); ARRAY_INIT(driveStepsPerUnit, DRIVE_STEPS_PER_UNIT); ARRAY_INIT(instantDvs, INSTANT_DVS); - maxPrintingAcceleration = maxTravelAcceleration = 10000.0; // Z PROBE zProbeType = ZProbeType::none; // default is to use no Z probe @@ -1880,23 +1882,29 @@ void Platform::InitialiseInterrupts() NVIC_SetPriority(SysTick_IRQn, NvicPrioritySystick); // set priority for tick interrupts #endif - // Set UART interrupt priorities -#ifdef PCCB - NVIC_SetPriority(DriverUartIRQns[0], NvicPriorityDriversSerialTMC); - NVIC_SetPriority(DriverUartIRQns[1], NvicPriorityDriversSerialTMC); -#else -# if SAM4E || SAME70 - NVIC_SetPriority(UART0_IRQn, NvicPriorityPanelDueUart); // set priority for UART interrupt + // Set PanelDue UART interrupt priority +#ifdef SERIAL_AUX_DEVICE + SERIAL_AUX_DEVICE.setInterruptPriority(NvicPriorityPanelDueUart); +#endif +#ifdef SERIAL_AUX2_DEVICE + SERIAL_AUX2_DEVICE.setInterruptPriority(NvicPriorityPanelDueUart); +#endif + +#if HAS_WIFI_NETWORKING NVIC_SetPriority(UART1_IRQn, NvicPriorityWiFiUart); // set priority for WiFi UART interrupt -# elif SAM4S - NVIC_SetPriority(UART1_IRQn, NvicPriorityPanelDueUart); // set priority for UART interrupt +#endif + +#if SUPPORT_TMC22xx +# if TMC22xx_HAS_MUX + NVIC_SetPriority(TMC22xx_UART_IRQn, NvicPriorityDriversSerialTMC); // set priority for TMC2660 SPI interrupt # else - NVIC_SetPriority(UART_IRQn, NvicPriorityPanelDueUart); // set priority for UART interrupt + NVIC_SetPriority(TMC22xxUartIRQns[0], NvicPriorityDriversSerialTMC); + NVIC_SetPriority(TMC22xxUartIRQns[1], NvicPriorityDriversSerialTMC); # endif +#endif -# if HAS_SMART_DRIVERS - NVIC_SetPriority(UART_TMC_DRV_IRQn, NvicPriorityDriversSerialTMC); -# endif +#if SUPPORT_TMC2660 + NVIC_SetPriority(TMC2660_SPI_IRQn, NvicPriorityDriversSerialTMC); // set priority for TMC2660 SPI interrupt #endif // Timer interrupt for stepper motors diff --git a/src/Platform.h b/src/Platform.h index 08ef818b..779215e6 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -426,14 +426,6 @@ public: float Acceleration(size_t axisOrExtruder) const; const float* Accelerations() const; void SetAcceleration(size_t axisOrExtruder, float value); - float GetMaxPrintingAcceleration() const - { return maxPrintingAcceleration; } - void SetMaxPrintingAcceleration(float acc) - { maxPrintingAcceleration = acc; } - float GetMaxTravelAcceleration() const - { return maxTravelAcceleration; } - void SetMaxTravelAcceleration(float acc) - { maxTravelAcceleration = acc; } float MaxFeedrate(size_t axisOrExtruder) const; const float* MaxFeedrates() const; void SetMaxFeedrate(size_t axisOrExtruder, float value); @@ -738,8 +730,6 @@ private: Pin endStopPins[DRIVES]; float maxFeedrates[DRIVES]; float accelerations[DRIVES]; - float maxPrintingAcceleration; - float maxTravelAcceleration; float driveStepsPerUnit[DRIVES]; float instantDvs[DRIVES]; float pressureAdvance[MaxExtruders]; diff --git a/src/StepperDrivers/TMC22xx/TMC22xx.cpp b/src/StepperDrivers/TMC22xx/TMC22xx.cpp index 97b2b06c..7cc0e9c7 100644 --- a/src/StepperDrivers/TMC22xx/TMC22xx.cpp +++ b/src/StepperDrivers/TMC22xx/TMC22xx.cpp @@ -5,7 +5,7 @@ * Author: David */ -#include "ReprapFirmware.h" +#include "RepRapFirmware.h" #if SUPPORT_TMC22xx @@ -346,7 +346,7 @@ private: // Static data members of class TmcDriverState #if TMC22xx_HAS_MUX -Uart * const TmcDriverState::uart = UART_TMC_DRV; +Uart * const TmcDriverState::uart = UART_TMC22xx; #endif TmcDriverState * volatile TmcDriverState::currentDriver = nullptr; // volatile because the ISR changes it @@ -471,7 +471,7 @@ pre(!driversPowered) } #if !TMC22xx_HAS_MUX - uart = DriverUarts[p_driverNumber]; + uart = TMC22xxUarts[p_driverNumber]; #endif enabled = false; @@ -715,27 +715,27 @@ inline void TmcDriverState::SetUartMux() { if ((driverNumber & 0x01) != 0) { - fastDigitalWriteHigh(DriverMuxPins[0]); + fastDigitalWriteHigh(TMC22xxMuxPins[0]); } else { - fastDigitalWriteLow(DriverMuxPins[0]); + fastDigitalWriteLow(TMC22xxMuxPins[0]); } if ((driverNumber & 0x02) != 0) { - fastDigitalWriteHigh(DriverMuxPins[1]); + fastDigitalWriteHigh(TMC22xxMuxPins[1]); } else { - fastDigitalWriteLow(DriverMuxPins[1]); + fastDigitalWriteLow(TMC22xxMuxPins[1]); } if ((driverNumber & 0x04) != 0) { - fastDigitalWriteHigh(DriverMuxPins[2]); + fastDigitalWriteHigh(TMC22xxMuxPins[2]); } else { - fastDigitalWriteLow(DriverMuxPins[2]); + fastDigitalWriteLow(TMC22xxMuxPins[2]); } } @@ -816,11 +816,16 @@ inline void TmcDriverState::UartTmcHandler() #if TMC22xx_HAS_MUX +#ifndef TMC22xx_UART_Handler +# error TMC handler name not defined +#endif + // ISR for the single UART -extern "C" void UART_TMC_DRV_Handler() __attribute__ ((hot)); -void UART_TMC_DRV_Handler() +extern "C" void TMC22xx_UART_Handler() __attribute__ ((hot)); + +void TMC22xx_UART_Handler() { - UART_TMC_DRV->UART_IDR = UART_IDR_ENDRX; // disable the interrupt + UART_TMC22xx->UART_IDR = UART_IDR_ENDRX; // disable the interrupt TmcDriverState *driver = TmcDriverState::currentDriver; // capture volatile variable if (driver != nullptr) { @@ -856,27 +861,27 @@ namespace SmartDrivers numTmc22xxDrivers = min<size_t>(numTmcDrivers, MaxSmartDrivers); // Make sure the ENN pins are high - pinMode(GlobalTmcEnablePin, OUTPUT_HIGH); + pinMode(GlobalTmc22xxEnablePin, OUTPUT_HIGH); #if TMC22xx_HAS_MUX // Set up- the single UART that communicates with all TMC22xx drivers - ConfigurePin(GetPinDescription(UART_TMC_DRV_PINS)); // the pins are already set up for UART use in the pins table + ConfigurePin(GetPinDescription(TMC22xx_UART_PINS)); // the pins are already set up for UART use in the pins table // Enable the clock to the UART - pmc_enable_periph_clk(ID_UART_TMC_DRV); + pmc_enable_periph_clk(ID_TMC22xx_UART); // Set the UART baud rate, 8 bits, 2 stop bits, no parity - UART_TMC_DRV->UART_IDR = ~0u; - UART_TMC_DRV->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS; - UART_TMC_DRV->UART_MR = UART_MR_CHMODE_NORMAL | UART_MR_PAR_NO; - UART_TMC_DRV->UART_BRGR = VARIANT_MCK/(16 * DriversBaudRate); // set baud rate - UART_TMC_DRV->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS | UART_CR_RSTSTA; - NVIC_EnableIRQ(UART_TMC_DRV_IRQn); + UART_TMC22xx->UART_IDR = ~0u; + UART_TMC22xx->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS; + UART_TMC22xx->UART_MR = UART_MR_CHMODE_NORMAL | UART_MR_PAR_NO; + UART_TMC22xx->UART_BRGR = VARIANT_MCK/(16 * DriversBaudRate); // set baud rate + UART_TMC22xx->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS | UART_CR_RSTSTA; + NVIC_EnableIRQ(TMC22xx_UART_IRQn); // Set up the multiplexer control pins as outputs - pinMode(DriverMuxPins[0], OUTPUT_LOW); - pinMode(DriverMuxPins[1], OUTPUT_LOW); - pinMode(DriverMuxPins[2], OUTPUT_LOW); + pinMode(TMC22xxMuxPins[0], OUTPUT_LOW); + pinMode(TMC22xxMuxPins[1], OUTPUT_LOW); + pinMode(TMC22xxMuxPins[2], OUTPUT_LOW); #endif driversState = DriversState::noPower; @@ -885,19 +890,19 @@ namespace SmartDrivers #if !TMC22xx_HAS_MUX // Initialise the UART that controls this driver // The pins are already set up for UART use in the pins table - ConfigurePin(GetPinDescription(DriverUartPins[drive])); + ConfigurePin(GetPinDescription(TMC22xxUartPins[drive])); // Enable the clock to the UART - pmc_enable_periph_clk(DriverUartIds[drive]); + pmc_enable_periph_clk(TMC22xxUartIds[drive]); // Set the UART baud rate, 8 bits, 2 stop bits, no parity - Uart * const uart = DriverUarts[drive]; + Uart * const uart = TMC22xxUarts[drive]; uart->UART_IDR = ~0u; uart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS; uart->UART_MR = UART_MR_CHMODE_NORMAL | UART_MR_PAR_NO; uart->UART_BRGR = VARIANT_MCK/(16 * DriversBaudRate); // set baud rate uart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS | UART_CR_RSTSTA; - NVIC_EnableIRQ(DriverUartIRQns[drive]); + NVIC_EnableIRQ(TMC22xxUartIRQns[drive]); #endif driverStates[drive].Init(drive, driverSelectPins[drive]); // axes are mapped straight through to drivers initially } @@ -1045,7 +1050,7 @@ namespace SmartDrivers if (allInitialised) { - digitalWrite(GlobalTmcEnablePin, LOW); + digitalWrite(GlobalTmc22xxEnablePin, LOW); driversState = DriversState::ready; } } @@ -1053,7 +1058,7 @@ namespace SmartDrivers else { // We had power but we lost it - digitalWrite(GlobalTmcEnablePin, HIGH); // disable the drivers + digitalWrite(GlobalTmc22xxEnablePin, HIGH); // disable the drivers if (TmcDriverState::currentDriver == nullptr) { TmcDriverState::currentDriver->AbortTransfer(); diff --git a/src/StepperDrivers/TMC2660/TMC2660.cpp b/src/StepperDrivers/TMC2660/TMC2660.cpp index f99961ea..5390d56f 100644 --- a/src/StepperDrivers/TMC2660/TMC2660.cpp +++ b/src/StepperDrivers/TMC2660/TMC2660.cpp @@ -5,7 +5,7 @@ * Author: David */ -#include "ReprapFirmware.h" +#include "RepRapFirmware.h" #if SUPPORT_TMC2660 @@ -26,12 +26,6 @@ static size_t numTmc2660Drivers; static bool driversPowered = false; -// Pin assignments, using USART1 in SPI mode -const Pin DriversClockPin = 15; // PB15/TIOA1 -const Pin DriversMosiPin = 22; // PA13 -const Pin DriversMisoPin = 21; // PA22 -const Pin DriversSclkPin = 23; // PA23 - const int ChopperControlRegisterMode = 999; // mode passed to get/set microstepping to indicate we want the chopper control register // The SPI clock speed is a compromise: @@ -228,8 +222,13 @@ private: // State structures for all drivers static TmcDriverState driverStates[MaxSmartDrivers]; -// PDC address for the USART -static Pdc * const usartPdc = usart_get_pdc_base(USART_TMC_DRV); +// PDC address +static Pdc * const spiPdc = +#if TMC2660_USES_USART + usart_get_pdc_base(USART_TMC2660); +#else + spi_get_pdc_base(SPI_TMC2660); +#endif // Words to send and receive driver SPI data from/to volatile static uint32_t spiDataOut = 0; // volatile because we care about when it is written @@ -242,18 +241,18 @@ static TmcDriverState * volatile currentDriver = nullptr; // volatile because th /*static*/ inline void TmcDriverState::SetupDMA(uint32_t outVal) { // Faster code, not using the ASF - usartPdc->PERIPH_PTCR = (PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS); // disable the PDC + spiPdc->PERIPH_PTCR = (PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS); // disable the PDC // SPI sends data MSB first, but the firmware uses little-endian mode, so we need to reverse the byte order spiDataOut = cpu_to_be32(outVal << 8); - usartPdc->PERIPH_TPR = reinterpret_cast<uint32_t>(&spiDataOut); - usartPdc->PERIPH_TCR = 3; + spiPdc->PERIPH_TPR = reinterpret_cast<uint32_t>(&spiDataOut); + spiPdc->PERIPH_TCR = 3; - usartPdc->PERIPH_RPR = reinterpret_cast<uint32_t>(&spiDataIn); - usartPdc->PERIPH_RCR = 3; + spiPdc->PERIPH_RPR = reinterpret_cast<uint32_t>(&spiDataIn); + spiPdc->PERIPH_RCR = 3; - usartPdc->PERIPH_PTCR = (PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN); // enable the PDC + spiPdc->PERIPH_PTCR = (PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN); // enable the PDC } // Initialise the state of the driver and its CS pin @@ -561,18 +560,37 @@ inline void TmcDriverState::StartTransfer() // Kick off a transfer for that register const irqflags_t flags = cpu_irq_save(); // avoid race condition - USART_TMC_DRV->US_CR = US_CR_RSTRX | US_CR_RSTTX; // reset transmitter and receiver + +#if TMC2660_USES_USART + USART_TMC2660->US_CR = US_CR_RSTRX | US_CR_RSTTX; // reset transmitter and receiver +#else + SPI_TMC2660->SPI_CR = SPI_CR_SPIDIS; // disable the SPI + (void)SPI_TMC2660->SPI_RDR; // clear the receive buffer +#endif + fastDigitalWriteLow(pin); // set CS low SetupDMA(regVal); // set up the PDC - USART_TMC_DRV->US_IER = US_IER_ENDRX; // enable end-of-transfer interrupt - USART_TMC_DRV->US_CR = US_CR_RXEN | US_CR_TXEN; // enable transmitter and receiver + +#if TMC2660_USES_USART + USART_TMC2660->US_IER = US_IER_ENDRX; // enable end-of-transfer interrupt + USART_TMC2660->US_CR = US_CR_RXEN | US_CR_TXEN; // enable transmitter and receiver +#else + SPI_TMC2660->SPI_IER = SPI_IER_ENDRX; // enable end-of-transfer interrupt + SPI_TMC2660->SPI_CR = SPI_CR_SPIEN; // enable SPI +#endif + cpu_irq_restore(flags); } // ISR for the USART -extern "C" void USART_TMC_DRV_Handler(void) __attribute__ ((hot)); -void USART_TMC_DRV_Handler(void) +#ifndef TMC2660_SPI_Handler +# error TMC handler name not defined +#endif + +extern "C" void TMC2660_SPI_Handler(void) __attribute__ ((hot)); + +void TMC2660_SPI_Handler(void) { TmcDriverState *driver = currentDriver; // capture volatile variable if (driver != nullptr) @@ -592,7 +610,13 @@ void USART_TMC_DRV_Handler(void) } // Driver power is down or there is no current driver, so stop polling - USART_TMC_DRV->US_IDR = US_IDR_ENDRX; + +#if TMC2660_USES_USART + USART_TMC2660->US_IDR = US_IDR_ENDRX; +#else + SPI_TMC2660->SPI_IDR = SPI_IDR_ENDRX; +#endif + currentDriver = nullptr; // signal that we are not waiting for an interrupt } @@ -607,32 +631,49 @@ namespace SmartDrivers numTmc2660Drivers = min<size_t>(numTmcDrivers, MaxSmartDrivers); // Make sure the ENN pins are high - pinMode(GlobalTmcEnablePin, OUTPUT_HIGH); + pinMode(GlobalTmc2660EnablePin, OUTPUT_HIGH); // The pins are already set up for SPI in the pins table - ConfigurePin(GetPinDescription(DriversMosiPin)); - ConfigurePin(GetPinDescription(DriversMisoPin)); - ConfigurePin(GetPinDescription(DriversSclkPin)); + ConfigurePin(GetPinDescription(TMC2660MosiPin)); + ConfigurePin(GetPinDescription(TMC2660MisoPin)); + ConfigurePin(GetPinDescription(TMC2660SclkPin)); - // Enable the clock to the USART - pmc_enable_periph_clk(ID_USART_TMC_DRV); + // Enable the clock to the USART or SPI + pmc_enable_periph_clk(ID_TMC2660_SPI); +#if TMC2660_USES_USART // Set USART_EXT_DRV in SPI mode, with data changing on the falling edge of the clock and captured on the rising edge - USART_TMC_DRV->US_IDR = ~0u; - USART_TMC_DRV->US_CR = US_CR_RSTRX | US_CR_RSTTX | US_CR_RXDIS | US_CR_TXDIS; - USART_TMC_DRV->US_MR = US_MR_USART_MODE_SPI_MASTER + USART_TMC2660->US_IDR = ~0u; + USART_TMC2660->US_CR = US_CR_RSTRX | US_CR_RSTTX | US_CR_RXDIS | US_CR_TXDIS; + USART_TMC2660->US_MR = US_MR_USART_MODE_SPI_MASTER | US_MR_USCLKS_MCK | US_MR_CHRL_8_BIT | US_MR_CHMODE_NORMAL | US_MR_CPOL | US_MR_CLKO; - USART_TMC_DRV->US_BRGR = VARIANT_MCK/DriversSpiClockFrequency; // set SPI clock frequency - USART_TMC_DRV->US_CR = US_CR_RSTRX | US_CR_RSTTX | US_CR_RXDIS | US_CR_TXDIS | US_CR_RSTSTA; + USART_TMC2660->US_BRGR = VARIANT_MCK/DriversSpiClockFrequency; // set SPI clock frequency + USART_TMC2660->US_CR = US_CR_RSTRX | US_CR_RSTTX | US_CR_RXDIS | US_CR_TXDIS | US_CR_RSTSTA; // We need a few microseconds of delay here for the USART to sort itself out before we send any data, // otherwise the processor generates two short reset pulses on its own NRST pin, and resets itself. // 2016-07-07: removed this delay, because we no longer send commands to the TMC2660 drivers immediately. //delay(10); +#else + // Set up the SPI interface with data changing on the falling edge of the clock and captured on the rising edge + spi_reset(SPI_TMC2660); // this clears the transmit and receive registers and puts the SPI into slave mode + SPI_TMC2660->SPI_MR = SPI_MR_MSTR // master mode + | SPI_MR_MODFDIS // disable fault detection + | SPI_MR_PCS(0); // fixed peripheral select + + // Set SPI mode, clock frequency, CS active after transfer, delay between transfers + const uint16_t baud_div = (uint16_t)spi_calc_baudrate_div(DriversSpiClockFrequency, SystemCoreClock); + const uint32_t csr = SPI_CSR_SCBR(baud_div) // Baud rate + | SPI_CSR_BITS_8_BIT // Transfer bit width + | SPI_CSR_DLYBCT(0) // Transfer delay + | SPI_CSR_CSAAT // Keep CS low after transfer in case we are slow in writing the next byte + | SPI_CSR_CPOL; // clock high between transfers + SPI_TMC2660->SPI_CSR[0] = csr; +#endif driversPowered = false; for (size_t driver = 0; driver < numTmc2660Drivers; ++driver) @@ -739,7 +780,7 @@ namespace SmartDrivers if (!wasPowered) { // Power to the drivers has been provided or restored, so we need to enable and re-initialise them - digitalWrite(GlobalTmcEnablePin, LOW); + digitalWrite(GlobalTmc2660EnablePin, LOW); delayMicroseconds(10); for (size_t driver = 0; driver < numTmc2660Drivers; ++driver) @@ -750,20 +791,20 @@ namespace SmartDrivers if (currentDriver == nullptr && numTmc2660Drivers != 0) { // Kick off the first transfer - NVIC_EnableIRQ(UART_TMC_DRV_IRQn); + NVIC_EnableIRQ(TMC2660_SPI_IRQn); driverStates[0].StartTransfer(); } } else if (wasPowered) { - digitalWrite(GlobalTmcEnablePin, HIGH); // disable the drivers + digitalWrite(GlobalTmc2660EnablePin, HIGH); // disable the drivers } } // This is called from the tick ISR, possibly while Spin (with powered either true or false) is being executed void TurnDriversOff() { - digitalWrite(GlobalTmcEnablePin, HIGH); // disable the drivers + digitalWrite(GlobalTmc2660EnablePin, HIGH); // disable the drivers driversPowered = false; } diff --git a/src/StepperDrivers/TMC2660/TMC2660.h b/src/StepperDrivers/TMC2660/TMC2660.h index ceed9734..37721e0d 100644 --- a/src/StepperDrivers/TMC2660/TMC2660.h +++ b/src/StepperDrivers/TMC2660/TMC2660.h @@ -16,12 +16,6 @@ #include "MessageType.h" #include "Libraries/General/StringRef.h" -// The Platform class needs to know which USART we are using when assigning interrupt priorities -#define USART_TMC_DRV USART1 -#define UART_TMC_DRV_IRQn USART1_IRQn -#define ID_USART_TMC_DRV ID_USART1 -#define USART_TMC_DRV_Handler USART1_Handler - // TMC2660 Read response. The microstep counter can also be read, but we don't include that here. const uint32_t TMC_RR_SG = 1 << 0; // stall detected const uint32_t TMC_RR_OT = 1 << 1; // over temperature shutdown diff --git a/src/Version.h b/src/Version.h index b529899b..57dc01e5 100644 --- a/src/Version.h +++ b/src/Version.h @@ -12,7 +12,7 @@ #ifndef VERSION #ifdef RTOS # define RTOSVER "(RTOS)" -# define MAIN_VERSION "2.01" +# define MAIN_VERSION "2.02alpha1" #else # define MAIN_VERSION "1.22" # define RTOSVER @@ -22,7 +22,7 @@ #endif #ifndef DATE -# define DATE "2018-07-26b2" +# define DATE "2018-08-02b1" #endif #define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman" |