Compare commits

..

160 Commits

Author SHA1 Message Date
Scott Lahteine
815c9163ce 🩹 Fix LONG_FILENAME_WRITE_SUPPORT typo 2023-12-11 15:42:30 -06:00
Scott Lahteine
68dbe13f85 🔨 Specify versions in INI 2023-12-11 15:42:30 -06:00
Scott Lahteine
4caa32b6dd 🔖 Version 2.1.1.1 2023-12-11 15:42:26 -06:00
Scott Lahteine
dfa748cb96 🔨 PlatformIO 6 compatibility 2023-07-20 13:44:06 -05:00
Scott Lahteine
398cae7625 🔖 Version 2.1.1 2022-08-06 18:50:49 -05:00
Scott Lahteine
8192cc12d3 🎨 Misc. config cleanup 2022-08-06 18:50:49 -05:00
ExtNeon
7f2a836251 SD Endstop Abort G-Code (#24461) 2022-08-06 18:50:49 -05:00
Mark
b02c3258b5 Bed Distance Sensor (#24554) 2022-08-06 18:50:49 -05:00
Keith Bennett
a0462eb017 🩹 Fix AUTO_FAN_PIN sanity check (#24593) 2022-08-06 18:50:49 -05:00
Scott Lahteine
a1704c10b9 🩹 G0/G1 S seen => seenval 2022-08-06 18:50:49 -05:00
qwertymodo
7196f13125 M150 K – Keep unspecified components (#24315) 2022-08-06 18:50:49 -05:00
J.C. Nelson
e06340abd1 🔨 Trigorilla Pro disk based update (#24591) 2022-08-06 18:50:49 -05:00
Travis Ziegler
98095ddad6 🩹 Fix LPC176x USB Host Shield (#24588) 2022-08-06 18:50:49 -05:00
Scott Lahteine
2f4b121709 👔 Keep "Needs: More Data" open 2022-08-06 18:50:49 -05:00
Ruedi Steinmann
a0409289c8 🚸 Laser with only PWM pin (#24345) 2022-08-06 18:50:49 -05:00
Scott Lahteine
2ccdc4f9ed 🧑‍💻 MARLIN_TEST_BUILD – for future use (#24077) 2022-08-06 18:50:49 -05:00
Scott Lahteine
bbf2033211 🔧 Config INI, dump options (#24528) 2022-08-06 18:50:49 -05:00
Scott Lahteine
9a42d1e577 🩹 Fix Malyan M300 with S-Curve compile
Fixes #24548
2022-08-05 21:54:27 -05:00
ellensp
17794e18ae 🔧 Update 644p/1284p Serial 1 sanity check (#24575) 2022-08-01 01:59:37 -05:00
Scott Lahteine
3b30951e83 🔨 Simplify scripts with pathlib (#24574) 2022-08-01 01:59:37 -05:00
Mike La Spina
c3f2586445 🐛 Fix laser menu enable_state (#24557) 2022-08-01 01:59:37 -05:00
InsanityAutomation
c0cb7e35af Configurable Switching Nozzle dwell (#24304) 2022-08-01 01:59:37 -05:00
tombrazier
fd319928d2 Fix, improve Linear Advance (#24533) 2022-08-01 01:59:37 -05:00
tombrazier
5dad7e0d03 🩹 Use _MIN/_MAX macros for native compatibility (#24570) 2022-08-01 01:59:37 -05:00
DerAndere
9ee558afe1 🐛 Fix kinematic feedrate (#24568) 2022-08-01 01:59:37 -05:00
Keith Bennett
bbaccd342e Encoder Noise Filter (#24538) 2022-08-01 01:59:37 -05:00
lukasradek
6134d55360 📝 README Updates (#24564) 2022-08-01 01:59:37 -05:00
Scott Lahteine
868e76b965 🎨 Renum boards.h 2022-08-01 01:59:37 -05:00
Scott Lahteine
5f105e254d 🐛 Fix M125 for 9 Axis 2022-08-01 01:59:37 -05:00
Scott Lahteine
9534c6e903 🎨 Misc. 'else' cleanup 2022-08-01 01:59:37 -05:00
Ludy
ec9a2ee557 🌐 Update German language (#24555) 2022-08-01 01:59:37 -05:00
Scott Lahteine
d8db00e31f 🧑‍💻 Update planner/stepper includes 2022-08-01 01:59:37 -05:00
Scott Lahteine
e7c262dc30 🩹 Fix lcd_preheat compile 2022-08-01 01:59:37 -05:00
Scott Lahteine
cee9da6132 🔨 Update build/CI scripts 2022-08-01 01:59:37 -05:00
Scott Lahteine
a24b9e16ff 🎨 PIO scripts cleanup 2022-08-01 01:59:37 -05:00
Keith Bennett
1e9232723d 📺 Fix TFT Classic UI non-Touchscreen 1024x600 (#24541) 2022-08-01 01:59:37 -05:00
Keith Bennett
66369f8236 🩹 Fix JyersUI include (#24540) 2022-08-01 01:59:37 -05:00
Keith Bennett
0ca76bf9ed 📝 Update MPCTEMP G-Code M306 T (#24535)
M306 simply reports current values. M306 T starts autotune process.
2022-08-01 01:59:37 -05:00
Scott Lahteine
0f3c3c419e Reinstate JyersUI 2022-08-01 01:59:37 -05:00
Scott Lahteine
89e9ae0662 🧑‍💻 Give the simulator Stepper access 2022-08-01 01:59:37 -05:00
Scott Lahteine
5b8f7686cb 🧑‍💻 Fix and improve build_all_examples 2022-08-01 01:59:37 -05:00
Scott Lahteine
6e02f15dd6 🔨 Minor build script changes 2022-08-01 01:59:37 -05:00
Scott Lahteine
c9445cfc41 🩹 Fix TFT image PACKED conflict 2022-08-01 01:59:37 -05:00
Frederik Kemner
beacb73d93 🩹 Fix gcode.h include (#24527) 2022-08-01 01:59:37 -05:00
InsanityAutomation
53a57ff7bf 🐛 Fix Archim2 USB Hang (#24314) 2022-08-01 01:59:37 -05:00
Scott Lahteine
d726f641a5 EXP header pin numbers redux (#24525)
Followup to 504fec98
2022-08-01 01:59:37 -05:00
InsanityAutomation
feafa321d7 🚸 Use Tool 0 for G30 (#24511) 2022-08-01 01:59:37 -05:00
ellensp
f5b972bb10 📺 SKR_MINI_SCREEN_ADAPTER for BTT SKR Mini E3 V3 (#24521) 2022-08-01 01:59:37 -05:00
Eduard Sukharev
196795c0cc More ESP32 (MKS TinyBee) tests (#24493) 2022-08-01 01:59:36 -05:00
Keith Bennett
c3085d666f 📝 Update Contributing Guide (#24320) 2022-08-01 01:59:36 -05:00
InsanityAutomation
807f2ef969 🚸 Machine-relative Z_STEPPER_ALIGN_XY (#24261)
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
2022-08-01 01:59:36 -05:00
Scott Lahteine
f752fe75ee ♻️ Small sound / buzz refactor (#24520) 2022-08-01 01:59:36 -05:00
Scott Lahteine
97a73147fa 🩹 Fix manual move titles (#24518) 2022-08-01 01:59:36 -05:00
tombrazier
915203f545 🩹 Arc/Planner optimization followup (#24509) 2022-08-01 01:59:36 -05:00
Scott Lahteine
173eb3ff71 🚸 Renumber EXP pins to match schematics/RRF/Klipper 2022-08-01 01:59:36 -05:00
Nikolay-Po
96d3c66b64 Steinhart-Hart C Coeff for Custom Thermistor (#24428) 2022-08-01 01:59:36 -05:00
tombrazier
cc4fc28fe0 ️ Optimize Planner calculations (#24484) 2022-08-01 01:59:36 -05:00
Arthur Masson
0a164a88fe Polargraph M665 settings (#24401) 2022-08-01 01:59:36 -05:00
GHGiampy
c72fe1a2f9 🩹 Add'l ProUI fixes (#24500, #24508) 2022-08-01 01:59:17 -05:00
Christophe Huriaux
2add8ca4eb eMotion-Tech eMotronic (Micro-Delta rework) (#24488) 2022-08-01 01:58:45 -05:00
Scott Lahteine
779c24122d 🔨 Update mfprep comment 2022-08-01 01:58:45 -05:00
Scott Lahteine
6ac3f2738e 🔨 Add mftest --default flag 2022-08-01 01:57:17 -05:00
Scott Lahteine
77c6d9af20 🩹 Fix TFT tImage struct packing 2022-08-01 01:57:11 -05:00
GHGiampy
929e12bf49 🔨 Remove log2file monitor filter (#24502) 2022-08-01 01:57:01 -05:00
Keith Bennett
fd18ac5667 📝 Update board MCU comments (#24486) 2022-07-29 18:42:42 -05:00
Scott Lahteine
06c1409843 🩹 Fix MAX31865 approximations
Followup to #24407
2022-07-29 18:42:42 -05:00
Scott Lahteine
ec95e66ff0 🔧 Base NUM_AXES on defined DRIVER_TYPEs (#24106) 2022-07-29 18:42:42 -05:00
Scott Lahteine
53ee7fce5b 🐛 Fix SDIO for STM32 (#24470)
Followup to #24271
2022-07-29 18:42:42 -05:00
Scott Lahteine
10f5f878ce 🚑️ Fix XYZEval = N not setting E 2022-07-29 18:42:42 -05:00
tombrazier
733ca940c0 🐛 Fix 2d mesh print (#24536) 2022-07-22 23:33:30 -05:00
Scott Lahteine
c880c7ed45 🔨 Fix and update Makefile
Followup to 89fe5f6d
2022-07-15 18:48:15 -05:00
Keith Bennett
e5e4cf920d 📌 Pin ESP32SSDP to 1.1.1 (#24489) 2022-07-15 18:48:15 -05:00
Victor Oliveira
3315f6faa4 Creality3D v4.2.5 / CR200B (#24491) 2022-07-15 18:48:15 -05:00
GHGiampy
4a6ad1c98b 🩹 Fix ProUI LED compile (#24473) 2022-07-15 18:48:15 -05:00
Miguel Risco-Castillo
3c9789fda8 🚸 Fix and update ProUI (#24477) 2022-07-15 18:48:15 -05:00
toomuchwonder
3a19d34c75 🩹 Fix MKS UI extruder speed (#24476) 2022-07-15 18:48:15 -05:00
Bob Kuhn
6b19a58f03 🔥 Drop STM L64** drivers, STEVAL_3DP001V1 (#24427) 2022-07-15 18:48:15 -05:00
Scott Lahteine
9283859b1e 🎨 ANY => EITHER 2022-07-15 18:48:15 -05:00
GHGiampy
e840015cad 🔨 Abort firmware update on transfer error (#24472, #24499) 2022-07-15 18:48:15 -05:00
Scott Lahteine
efe04e1016 🧑‍💻 Update Mac Sim directions 2022-07-15 18:48:15 -05:00
Scott Lahteine
f543b3cb84 📌 Ask for PlatformIO 6.1.1 or newer (#24435) 2022-07-15 18:48:15 -05:00
Keith Bennett
6a86c5bad3 MKS Monster8 V2 (#24483) 2022-07-15 18:48:15 -05:00
Scott Lahteine
7207a32434 🧑‍💻 Add Sim debug with lldb 2022-07-15 18:48:15 -05:00
Keith Bennett
678474d55c 🔧 Assert Probe Temp Comp requirements (#24468) 2022-07-15 18:48:15 -05:00
Mike La Spina
24c211307d 🐛 Fix laser/fan sync (#24460)
Followup to #22690, 307dfb15
2022-07-15 18:48:15 -05:00
tombrazier
0c78a6f657 ️ Optimize G2-G3 Arcs (#24366) 2022-07-15 18:48:15 -05:00
Jason Smith
79a332b57e 🩹 Fix LCD_BACKLIGHT_TIMEOUT compile (#24463) 2022-07-15 18:48:15 -05:00
Pauli Jokela
d9ecbdcdbb 🩹 Fix safe homing sanity-check (#24462) 2022-07-15 18:48:15 -05:00
Farva42
527fe2496a MAG_MOUNTED_PROBE (#24420)
Co-Authored-By: Scott Lahteine <thinkyhead@users.noreply.github.com>
2022-07-15 18:48:14 -05:00
Scott Lahteine
6c2ffe9d34 🔥 Remove JyersUI (#24459) 2022-07-15 18:48:14 -05:00
Scott Lahteine
0fdedfa2fb 📝 Configurations 02010100 (#24458) 2022-07-15 18:48:14 -05:00
Meilleur Gars
e93a1dd2fa 🚸 JyersUI updates (#24451) 2022-07-15 18:48:14 -05:00
Christophe Huriaux
03760fd79e 🩹 Fix ST7565 LCD contrast init (#24457) 2022-07-15 18:48:14 -05:00
Bob Kuhn
d3aed23e18 🐛 Fix Sensorless Probing compile (#24455) 2022-07-15 18:48:14 -05:00
Eduard Sukharev
893707711e 🐛 Fix MKS TinyBee compile (#24454) 2022-07-15 18:48:14 -05:00
Mike La Spina
d965303a7a ️ Fix and improve Inline Laser Power (#22690) 2022-07-15 18:48:14 -05:00
Keith Bennett
5b6c46db29 BigTreeTech SKR SE BX V3.0 (#24449)
SKR SE BX V3.0 removes the Reverse Driver Protection feature.
2022-07-15 18:48:14 -05:00
EvilGremlin
8f40a2f257 🔨 Fix OpenBLT encode; no-bootloader envs (#24446) 2022-07-15 18:48:14 -05:00
Scott Lahteine
e4f85e8fbc ♻️ Encapsulate PID in class (#24389) 2022-07-15 18:48:14 -05:00
Victor Oliveira
678955949f 🔨 Disable stack protector on macOS simulator (#24443) 2022-07-15 18:48:14 -05:00
Scott Lahteine
923d34550a 🔨 PlatformIO "--target upload" == "--target exec" 2022-07-15 18:48:14 -05:00
Scott Lahteine
ed643e634f 🔨 Fix Warnings/settings force-recompile 2022-07-15 18:48:14 -05:00
Scott Lahteine
3f4c8c31c6 Fix SDIO for STM32
Followup to #24271
2022-07-09 18:19:47 -05:00
Keith Bennett
171ed66de0 🚸 MPCTEMP: Home before cooling (#24434) 2022-07-04 00:29:53 -05:00
Keith Bennett
5f2e4487e7 🩹 Fix MKS TinyBee ADC Vref (#24432) 2022-07-04 00:29:53 -05:00
Scott Lahteine
80c7abd727 🩹 Remove poison wchar_t macro 2022-07-04 00:29:53 -05:00
Scott Lahteine
814b53750f 🩹 Remove obsolete split_move 2022-07-01 22:05:44 -05:00
Moonglow
23e93c51fd 🐛 Fix M149 (#24430) 2022-07-01 07:54:53 -05:00
tombrazier
afbdcc8eee 🚸 Vertical Max7219::quantity in portrait orientation (#24415) 2022-07-01 07:54:53 -05:00
Scott Lahteine
4820947203 Update path to Ender-3 S1 configs 2022-07-01 07:54:53 -05:00
Scott Lahteine
d44aef8b6b 📝 Index Mobo Rev03 => Opulo Lumen Rev3 2022-06-30 22:10:31 -05:00
Scott Lahteine
c1c0496073 🩹 Fix memset block warning 2022-06-30 22:10:26 -05:00
Keith Bennett
a48831d600 🐛 Fix Axis Homing (#24425)
Followup to 4520a51
2022-06-30 22:10:26 -05:00
John Lagonikas
c076094fa9 🐛 Fix MAX31865 PT1000 normalization (#24407)
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
2022-06-30 22:10:26 -05:00
Scott Lahteine
57c137a60f ♻️ reset_acceleration_rates => refresh_… 2022-06-30 22:10:05 -05:00
Scott Lahteine
05bdc5640d ♻️ Planner flags refactor 2022-06-30 22:10:05 -05:00
Scott Lahteine
83784bd8b7 📝 Note about UBL bad splits 2022-06-30 22:10:05 -05:00
Scott Lahteine
23f19e9ce8 🎨 Misc. shorthand operators 2022-06-26 10:02:36 -05:00
Scott Lahteine
0435b2220a 🐛 Fix Manual Move axis selection (#24404) 2022-06-26 06:49:14 -05:00
Shlee
ab2fceda2c 📝 Add STM32F4 example, Ruby (#24399) 2022-06-26 06:39:00 -05:00
Giuliano Zaro
88dc360e9d 🌐 Update Italian language (#24398) 2022-06-26 06:39:00 -05:00
Roman Moravčík
f5bdb8b4d2 🌐 Update Slovak language (#24397) 2022-06-26 06:39:00 -05:00
sgparry
3e01e08989 🩹 Fix LCD contrast with K8800 board 2022-06-26 06:39:00 -05:00
tombrazier
4694a7fe74 MAX7219 idle profiler (#24375) 2022-06-26 06:39:00 -05:00
Scott Lahteine
537af0bb03 🌐 Drop unused delta strings 2022-06-24 22:09:59 -05:00
InsanityAutomation
0dc59311ec 🐛 Resolve DUE Servo pulse issue (#24305)
Co-authored-by: sjasonsmith <20053467+sjasonsmith@users.noreply.github.com>
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
2022-06-24 18:03:19 -05:00
tombrazier
0523874e9c 🐛 Fix G2/G3 Arcs stutter / JD speed (#24362) 2022-06-24 18:03:19 -05:00
Scott Lahteine
106537ff43 ✏️ 9-axis followup (sanity-check) 2022-06-24 18:03:19 -05:00
Bob Kuhn
ad96c36730 🐛 Fix Lerdge build / encrypt (#24391)
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
2022-06-24 18:03:19 -05:00
Victor Oliveira
a3629a7c28 Classic UI BIQU BX (#24387) 2022-06-24 18:03:19 -05:00
ellensp
b7e1b6b893 🩹 Fix DGUS (MKS) compile (#24378) 2022-06-24 18:03:19 -05:00
Victor Oliveira
253e35e066 🚑️ Fix BIQU BX touch freeze (#24383) 2022-06-24 18:03:19 -05:00
ellensp
831e1b5ecf 🐛 Fix M423 invocation (#24360)
Followup to #23745
2022-06-24 18:03:19 -05:00
tombrazier
c89ca2deb8 🩹 LCD strings followup, fix warning (#24328) 2022-06-24 18:03:19 -05:00
DerAndere
85e94038aa FOAMCUTTER_XYUV (for RAMPS) (#24325)
Co-authored-by: Scott Lahteine <github@thinkyhead.com>
2022-06-24 18:03:19 -05:00
ellensp
7c85f25042 🚑️ Fix SD mount bug (#24319)
Co-authored-by: Scott Lahteine <github@thinkyhead.com>
2022-06-24 18:03:19 -05:00
Scott Lahteine
eca5e46d17 🎨 Simplify move menus with substitution 2022-06-24 18:03:19 -05:00
Scott Lahteine
78b42ed387 🎨 Use MAP for home axis items 2022-06-24 18:03:19 -05:00
Scott Lahteine
95339c9561 🧑‍💻 Fix STATIC_ITEM_N arg order 2022-06-24 18:03:19 -05:00
Scott Lahteine
da6c16a9cd 🎨 Fix comments, formatting 2022-06-24 18:03:19 -05:00
ellensp
cc27cfb660 👷 CI test without src filter (emulate Arduino) (#24335) 2022-06-24 01:19:42 -05:00
Keith Bennett
25c0593c9b 👷 Use Biqu BX for CI test (#24331) 2022-06-24 01:19:36 -05:00
Scott Lahteine
5fff7bbef4 👔 Fix and comment use_example_configs 2022-06-24 01:11:07 -05:00
Scott Lahteine
3fd592e64b 👔 Update Marlin actions for 2.1.x 2022-06-24 01:11:07 -05:00
John Robertson
c34dd64469 ️ PWM for ESP32 I2S expander (#24193) 2022-06-24 01:11:07 -05:00
Scott Lahteine
7677368aaf 🔖 Moving to bugfix-2.1.x 2022-06-24 01:11:06 -05:00
Scott Lahteine
ece124fdea 🩹 M919 9-axis update 2022-06-20 21:09:20 -05:00
luzpaz
9aa499dbe9 🌐 Fix LCD string, typos (#24324) 2022-06-20 21:09:20 -05:00
Scott Lahteine
78a3ea0ed4 🧑‍💻 Apply F() to some LCD / TFT strings
Followup to #24228
2022-06-13 21:02:31 -05:00
ellensp
c605c1ebb5 🩹 Fix missing ProUI cpp wrapper (#24313) 2022-06-13 21:02:31 -05:00
ellensp
b2c4fb5f3a 🐛 Fix JGAurora A5S A1 build (#24326) 2022-06-13 04:32:49 -05:00
Steven Haigh
60cedf63f2 🩹 Fix ProUI compile (#24310)
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
2022-06-13 04:32:49 -05:00
Scott Lahteine
1156557a47 🧑‍💻 Misc. servo code cleanup 2022-06-13 04:32:49 -05:00
Scott Lahteine
ea22640d78 🧑‍💻 Remove servo macros 2022-06-13 04:32:49 -05:00
lujios
d886320799 🩹 Fix G33 Delta Sensorless Probing compile (#24291) 2022-06-13 04:32:30 -05:00
Scott Lahteine
a65189c637 👔 Fix and comment use_example_configs 2022-06-13 04:31:26 -05:00
tombrazier
dfc8acf376 🩹 Fix Mesh Leveling + Debug compile (#24297) 2022-06-07 02:15:48 -05:00
ellensp
48d03ca0a9 🩹 Media Change followup (#24302)
Followup to #24015
2022-06-07 02:00:38 -05:00
Miguel Risco-Castillo
85e8d1f9fa 🚸 ProUI G-code preview, PID plot (#24282) 2022-06-07 02:00:38 -05:00
Scott Lahteine
679f4608ab 👔 Update mfconfig import 2022-06-06 23:40:26 -05:00
446 changed files with 11865 additions and 13590 deletions

View File

@@ -34,8 +34,11 @@ This project and everyone participating in it is governed by the [Marlin Code of
We have a Message Board and a Facebook group where our knowledgable user community can provide helpful advice if you have questions. We have a Message Board and a Facebook group where our knowledgable user community can provide helpful advice if you have questions.
* [Marlin RepRap forum](https://reprap.org/forum/list.php?415) - [Marlin Documentation](https://marlinfw.org) - Official Marlin documentation
* [MarlinFirmware on Facebook](https://www.facebook.com/groups/1049718498464482/) - Facebook Group ["Marlin Firmware"](https://www.facebook.com/groups/1049718498464482/)
- RepRap.org [Marlin Forum](https://forums.reprap.org/list.php?415)
- Facebook Group ["Marlin Firmware for 3D Printers"](https://www.facebook.com/groups/3Dtechtalk/)
- [Marlin Configuration](https://www.youtube.com/results?search_query=marlin+configuration) on YouTube
If chat is more your speed, you can join the MarlinFirmware Discord server: If chat is more your speed, you can join the MarlinFirmware Discord server:
@@ -116,7 +119,7 @@ Unsure where to begin contributing to Marlin? You can start by looking through t
### Pull Requests ### Pull Requests
Pull Requests should always be targeted to working branches (e.g., `bugfix-2.0.x` and/or `bugfix-1.1.x`) and never to release branches (e.g., `2.0.x` and/or `1.1.x`). If this is your first Pull Request, please read our [Guide to Pull Requests](https://marlinfw.org/docs/development/getting_started_pull_requests.html) and Github's [Pull Request](https://help.github.com/articles/creating-a-pull-request/) documentation. Pull Requests should always be targeted to working branches (e.g., `bugfix-2.1.x` and/or `bugfix-1.1.x`) and never to release branches (e.g., `2.0.x` and/or `1.1.x`). If this is your first Pull Request, please read our [Guide to Pull Requests](https://marlinfw.org/docs/development/getting_started_pull_requests.html) and Github's [Pull Request](https://help.github.com/articles/creating-a-pull-request/) documentation.
* Fill in [the required template](pull_request_template.md). * Fill in [the required template](pull_request_template.md).
* Don't include issue numbers in the PR title. * Don't include issue numbers in the PR title.

View File

@@ -35,7 +35,7 @@
* *
* Advanced settings can be found in Configuration_adv.h * Advanced settings can be found in Configuration_adv.h
*/ */
#define CONFIGURATION_H_VERSION 02010000 #define CONFIGURATION_H_VERSION 02010100
//=========================================================================== //===========================================================================
//============================= Getting Started ============================= //============================= Getting Started =============================
@@ -57,15 +57,6 @@
* https://www.thingiverse.com/thing:1278865 * https://www.thingiverse.com/thing:1278865
*/ */
//===========================================================================
//========================== DELTA / SCARA / TPARA ==========================
//===========================================================================
//
// Download configurations from the link above and customize for your machine.
// Examples are located in config/examples/delta, .../SCARA, and .../TPARA.
//
//===========================================================================
// @section info // @section info
// Author info of this build printed to the host during boot and M115 // Author info of this build printed to the host during boot and M115
@@ -121,6 +112,7 @@
* :[2400, 9600, 19200, 38400, 57600, 115200, 250000, 500000, 1000000] * :[2400, 9600, 19200, 38400, 57600, 115200, 250000, 500000, 1000000]
*/ */
#define BAUDRATE 250000 #define BAUDRATE 250000
//#define BAUD_RATE_GCODE // Enable G-code M575 to set the baud rate //#define BAUD_RATE_GCODE // Enable G-code M575 to set the baud rate
/** /**
@@ -129,7 +121,7 @@
* :[-2, -1, 0, 1, 2, 3, 4, 5, 6, 7] * :[-2, -1, 0, 1, 2, 3, 4, 5, 6, 7]
*/ */
//#define SERIAL_PORT_2 -1 //#define SERIAL_PORT_2 -1
//#define BAUDRATE_2 250000 // Enable to override BAUDRATE //#define BAUDRATE_2 250000 // :[2400, 9600, 19200, 38400, 57600, 115200, 250000, 500000, 1000000] Enable to override BAUDRATE
/** /**
* Select a third serial port on the board to use for communication with the host. * Select a third serial port on the board to use for communication with the host.
@@ -137,7 +129,7 @@
* :[-1, 0, 1, 2, 3, 4, 5, 6, 7] * :[-1, 0, 1, 2, 3, 4, 5, 6, 7]
*/ */
//#define SERIAL_PORT_3 1 //#define SERIAL_PORT_3 1
//#define BAUDRATE_3 250000 // Enable to override BAUDRATE //#define BAUDRATE_3 250000 // :[2400, 9600, 19200, 38400, 57600, 115200, 250000, 500000, 1000000] Enable to override BAUDRATE
// Enable the Bluetooth serial interface on AT90USB devices // Enable the Bluetooth serial interface on AT90USB devices
//#define BLUETOOTH //#define BLUETOOTH
@@ -157,13 +149,12 @@
* *
* Use TMC2208/TMC2208_STANDALONE for TMC2225 drivers and TMC2209/TMC2209_STANDALONE for TMC2226 drivers. * Use TMC2208/TMC2208_STANDALONE for TMC2225 drivers and TMC2209/TMC2209_STANDALONE for TMC2226 drivers.
* *
* Options: A4988, A5984, DRV8825, LV8729, L6470, L6474, POWERSTEP01, * Options: A4988, A5984, DRV8825, LV8729, TB6560, TB6600, TMC2100,
* TB6560, TB6600, TMC2100,
* TMC2130, TMC2130_STANDALONE, TMC2160, TMC2160_STANDALONE, * TMC2130, TMC2130_STANDALONE, TMC2160, TMC2160_STANDALONE,
* TMC2208, TMC2208_STANDALONE, TMC2209, TMC2209_STANDALONE, * TMC2208, TMC2208_STANDALONE, TMC2209, TMC2209_STANDALONE,
* TMC26X, TMC26X_STANDALONE, TMC2660, TMC2660_STANDALONE, * TMC26X, TMC26X_STANDALONE, TMC2660, TMC2660_STANDALONE,
* TMC5130, TMC5130_STANDALONE, TMC5160, TMC5160_STANDALONE * TMC5130, TMC5130_STANDALONE, TMC5160, TMC5160_STANDALONE
* :['A4988', 'A5984', 'DRV8825', 'LV8729', 'L6470', 'L6474', 'POWERSTEP01', 'TB6560', 'TB6600', 'TMC2100', 'TMC2130', 'TMC2130_STANDALONE', 'TMC2160', 'TMC2160_STANDALONE', 'TMC2208', 'TMC2208_STANDALONE', 'TMC2209', 'TMC2209_STANDALONE', 'TMC26X', 'TMC26X_STANDALONE', 'TMC2660', 'TMC2660_STANDALONE', 'TMC5130', 'TMC5130_STANDALONE', 'TMC5160', 'TMC5160_STANDALONE'] * :['A4988', 'A5984', 'DRV8825', 'LV8729', 'TB6560', 'TB6600', 'TMC2100', 'TMC2130', 'TMC2130_STANDALONE', 'TMC2160', 'TMC2160_STANDALONE', 'TMC2208', 'TMC2208_STANDALONE', 'TMC2209', 'TMC2209_STANDALONE', 'TMC26X', 'TMC26X_STANDALONE', 'TMC2660', 'TMC2660_STANDALONE', 'TMC5130', 'TMC5130_STANDALONE', 'TMC5160', 'TMC5160_STANDALONE']
*/ */
#define X_DRIVER_TYPE A4988 #define X_DRIVER_TYPE A4988
#define Y_DRIVER_TYPE A4988 #define Y_DRIVER_TYPE A4988
@@ -280,6 +271,7 @@
#define SWITCHING_NOZZLE_SERVO_NR 0 #define SWITCHING_NOZZLE_SERVO_NR 0
//#define SWITCHING_NOZZLE_E1_SERVO_NR 1 // If two servos are used, the index of the second //#define SWITCHING_NOZZLE_E1_SERVO_NR 1 // If two servos are used, the index of the second
#define SWITCHING_NOZZLE_SERVO_ANGLES { 0, 90 } // Angles for E0, E1 (single servo) or lowered/raised (dual servo) #define SWITCHING_NOZZLE_SERVO_ANGLES { 0, 90 } // Angles for E0, E1 (single servo) or lowered/raised (dual servo)
#define SWITCHING_NOZZLE_SERVO_DWELL 2500 // Dwell time to wait for servo to make physical move
#endif #endif
/** /**
@@ -396,7 +388,7 @@
//#define HOTEND_OFFSET_Y { 0.0, 5.00 } // (mm) relative Y-offset for each nozzle //#define HOTEND_OFFSET_Y { 0.0, 5.00 } // (mm) relative Y-offset for each nozzle
//#define HOTEND_OFFSET_Z { 0.0, 0.00 } // (mm) relative Z-offset for each nozzle //#define HOTEND_OFFSET_Z { 0.0, 0.00 } // (mm) relative Z-offset for each nozzle
// @section machine // @section psu control
/** /**
* Power Supply Control * Power Supply Control
@@ -558,22 +550,32 @@
#define DUMMY_THERMISTOR_999_VALUE 100 #define DUMMY_THERMISTOR_999_VALUE 100
// Resistor values when using MAX31865 sensors (-5) on TEMP_SENSOR_0 / 1 // Resistor values when using MAX31865 sensors (-5) on TEMP_SENSOR_0 / 1
//#define MAX31865_SENSOR_OHMS_0 100 // (Ω) Typically 100 or 1000 (PT100 or PT1000) #if TEMP_SENSOR_IS_MAX_TC(0)
//#define MAX31865_CALIBRATION_OHMS_0 430 // (Ω) Typically 430 for Adafruit PT100; 4300 for Adafruit PT1000 #define MAX31865_SENSOR_OHMS_0 100 // (Ω) Typically 100 or 1000 (PT100 or PT1000)
//#define MAX31865_SENSOR_OHMS_1 100 #define MAX31865_CALIBRATION_OHMS_0 430 // (Ω) Typically 430 for Adafruit PT100; 4300 for Adafruit PT1000
//#define MAX31865_CALIBRATION_OHMS_1 430 #endif
#if TEMP_SENSOR_IS_MAX_TC(1)
#define MAX31865_SENSOR_OHMS_1 100
#define MAX31865_CALIBRATION_OHMS_1 430
#endif
#define TEMP_RESIDENCY_TIME 10 // (seconds) Time to wait for hotend to "settle" in M109 #if HAS_E_TEMP_SENSOR
#define TEMP_WINDOW 1 // (°C) Temperature proximity for the "temperature reached" timer #define TEMP_RESIDENCY_TIME 10 // (seconds) Time to wait for hotend to "settle" in M109
#define TEMP_HYSTERESIS 3 // (°C) Temperature proximity considered "close enough" to the target #define TEMP_WINDOW 1 // (°C) Temperature proximity for the "temperature reached" timer
#define TEMP_HYSTERESIS 3 // (°C) Temperature proximity considered "close enough" to the target
#endif
#define TEMP_BED_RESIDENCY_TIME 10 // (seconds) Time to wait for bed to "settle" in M190 #if TEMP_SENSOR_BED
#define TEMP_BED_WINDOW 1 // (°C) Temperature proximity for the "temperature reached" timer #define TEMP_BED_RESIDENCY_TIME 10 // (seconds) Time to wait for bed to "settle" in M190
#define TEMP_BED_HYSTERESIS 3 // (°C) Temperature proximity considered "close enough" to the target #define TEMP_BED_WINDOW 1 // (°C) Temperature proximity for the "temperature reached" timer
#define TEMP_BED_HYSTERESIS 3 // (°C) Temperature proximity considered "close enough" to the target
#endif
#define TEMP_CHAMBER_RESIDENCY_TIME 10 // (seconds) Time to wait for chamber to "settle" in M191 #if TEMP_SENSOR_CHAMBER
#define TEMP_CHAMBER_WINDOW 1 // (°C) Temperature proximity for the "temperature reached" timer #define TEMP_CHAMBER_RESIDENCY_TIME 10 // (seconds) Time to wait for chamber to "settle" in M191
#define TEMP_CHAMBER_HYSTERESIS 3 // (°C) Temperature proximity considered "close enough" to the target #define TEMP_CHAMBER_WINDOW 1 // (°C) Temperature proximity for the "temperature reached" timer
#define TEMP_CHAMBER_HYSTERESIS 3 // (°C) Temperature proximity considered "close enough" to the target
#endif
/** /**
* Redundant Temperature Sensor (TEMP_SENSOR_REDUNDANT) * Redundant Temperature Sensor (TEMP_SENSOR_REDUNDANT)
@@ -632,6 +634,8 @@
//============================= PID Settings ================================ //============================= PID Settings ================================
//=========================================================================== //===========================================================================
// @section hotend temp
// Enable PIDTEMP for PID control or MPCTEMP for Predictive Model. // Enable PIDTEMP for PID control or MPCTEMP for Predictive Model.
// temperature control. Disable both for bang-bang heating. // temperature control. Disable both for bang-bang heating.
#define PIDTEMP // See the PID Tuning Guide at https://reprap.org/wiki/PID_Tuning #define PIDTEMP // See the PID Tuning Guide at https://reprap.org/wiki/PID_Tuning
@@ -642,7 +646,8 @@
#define PID_K1 0.95 // Smoothing factor within any PID loop #define PID_K1 0.95 // Smoothing factor within any PID loop
#if ENABLED(PIDTEMP) #if ENABLED(PIDTEMP)
//#define PID_PARAMS_PER_HOTEND // Uses separate PID parameters for each extruder (useful for mismatched extruders) //#define PID_DEBUG // Print PID debug data to the serial port. Use 'M303 D' to toggle activation.
//#define PID_PARAMS_PER_HOTEND // Use separate PID parameters for each extruder (useful for mismatched extruders)
// Set/get with G-code: M301 E[extruder number, 0-2] // Set/get with G-code: M301 E[extruder number, 0-2]
#if ENABLED(PID_PARAMS_PER_HOTEND) #if ENABLED(PID_PARAMS_PER_HOTEND)
@@ -663,7 +668,8 @@
* *
* Use a physical model of the hotend to control temperature. When configured correctly * Use a physical model of the hotend to control temperature. When configured correctly
* this gives better responsiveness and stability than PID and it also removes the need * this gives better responsiveness and stability than PID and it also removes the need
* for PID_EXTRUSION_SCALING and PID_FAN_SCALING. Use M306 to autotune the model. * for PID_EXTRUSION_SCALING and PID_FAN_SCALING. Use M306 T to autotune the model.
* @section mpctemp
*/ */
#if ENABLED(MPCTEMP) #if ENABLED(MPCTEMP)
//#define MPC_EDIT_MENU // Add MPC editing to the "Advanced Settings" menu. (~1300 bytes of flash) //#define MPC_EDIT_MENU // Add MPC editing to the "Advanced Settings" menu. (~1300 bytes of flash)
@@ -716,6 +722,7 @@
* impact FET heating. This also works fine on a Fotek SSR-10DA Solid State Relay into a 250W * impact FET heating. This also works fine on a Fotek SSR-10DA Solid State Relay into a 250W
* heater. If your configuration is significantly different than this and you don't understand * heater. If your configuration is significantly different than this and you don't understand
* the issues involved, don't use bed PID until someone else verifies that your hardware works. * the issues involved, don't use bed PID until someone else verifies that your hardware works.
* @section bed temp
*/ */
//#define PIDTEMPBED //#define PIDTEMPBED
@@ -731,7 +738,7 @@
#if ENABLED(PIDTEMPBED) #if ENABLED(PIDTEMPBED)
//#define MIN_BED_POWER 0 //#define MIN_BED_POWER 0
//#define PID_BED_DEBUG // Sends debug data to the serial port. //#define PID_BED_DEBUG // Print Bed PID debug data to the serial port.
// 120V 250W silicone heater into 4mm borosilicate (MendelMax 1.5+) // 120V 250W silicone heater into 4mm borosilicate (MendelMax 1.5+)
// from FOPDT model - kp=.39 Tp=405 Tdead=66, Tc set to 79.2, aggressive factor of .15 (vs .1, 1, 10) // from FOPDT model - kp=.39 Tp=405 Tdead=66, Tc set to 79.2, aggressive factor of .15 (vs .1, 1, 10)
@@ -759,6 +766,7 @@
* impact FET heating. This also works fine on a Fotek SSR-10DA Solid State Relay into a 200W * impact FET heating. This also works fine on a Fotek SSR-10DA Solid State Relay into a 200W
* heater. If your configuration is significantly different than this and you don't understand * heater. If your configuration is significantly different than this and you don't understand
* the issues involved, don't use chamber PID until someone else verifies that your hardware works. * the issues involved, don't use chamber PID until someone else verifies that your hardware works.
* @section chamber temp
*/ */
//#define PIDTEMPCHAMBER //#define PIDTEMPCHAMBER
//#define CHAMBER_LIMIT_SWITCHING //#define CHAMBER_LIMIT_SWITCHING
@@ -773,7 +781,7 @@
#if ENABLED(PIDTEMPCHAMBER) #if ENABLED(PIDTEMPCHAMBER)
#define MIN_CHAMBER_POWER 0 #define MIN_CHAMBER_POWER 0
//#define PID_CHAMBER_DEBUG // Sends debug data to the serial port. //#define PID_CHAMBER_DEBUG // Print Chamber PID debug data to the serial port.
// Lasko "MyHeat Personal Heater" (200w) modified with a Fotek SSR-10DA to control only the heating element // Lasko "MyHeat Personal Heater" (200w) modified with a Fotek SSR-10DA to control only the heating element
// and placed inside the small Creality printer enclosure tent. // and placed inside the small Creality printer enclosure tent.
@@ -787,7 +795,6 @@
#endif // PIDTEMPCHAMBER #endif // PIDTEMPCHAMBER
#if ANY(PIDTEMP, PIDTEMPBED, PIDTEMPCHAMBER) #if ANY(PIDTEMP, PIDTEMPBED, PIDTEMPCHAMBER)
//#define PID_DEBUG // Sends debug data to the serial port. Use 'M303 D' to toggle activation.
//#define PID_OPENLOOP // Puts PID in open loop. M104/M140 sets the output power from 0 to PID_MAX //#define PID_OPENLOOP // Puts PID in open loop. M104/M140 sets the output power from 0 to PID_MAX
//#define SLOW_PWM_HEATERS // PWM with very low frequency (roughly 0.125Hz=8s) and minimum state time of approximately 1s useful for heaters driven by a relay //#define SLOW_PWM_HEATERS // PWM with very low frequency (roughly 0.125Hz=8s) and minimum state time of approximately 1s useful for heaters driven by a relay
#define PID_FUNCTIONAL_RANGE 10 // If the temperature difference between the target temperature and the actual temperature #define PID_FUNCTIONAL_RANGE 10 // If the temperature difference between the target temperature and the actual temperature
@@ -797,7 +804,7 @@
//#define PID_AUTOTUNE_MENU // Add PID auto-tuning to the "Advanced Settings" menu. (~250 bytes of flash) //#define PID_AUTOTUNE_MENU // Add PID auto-tuning to the "Advanced Settings" menu. (~250 bytes of flash)
#endif #endif
// @section extruder // @section safety
/** /**
* Prevent extrusion if the temperature is below EXTRUDE_MINTEMP. * Prevent extrusion if the temperature is below EXTRUDE_MINTEMP.
@@ -865,11 +872,154 @@
#define POLAR_SEGMENTS_PER_SECOND 5 #define POLAR_SEGMENTS_PER_SECOND 5
#endif #endif
// @section delta
// Enable for DELTA kinematics and configure below
//#define DELTA
#if ENABLED(DELTA)
// Make delta curves from many straight lines (linear interpolation).
// This is a trade-off between visible corners (not enough segments)
// and processor overload (too many expensive sqrt calls).
#define DELTA_SEGMENTS_PER_SECOND 200
// After homing move down to a height where XY movement is unconstrained
//#define DELTA_HOME_TO_SAFE_ZONE
// Delta calibration menu
// uncomment to add three points calibration menu option.
// See http://minow.blogspot.com/index.html#4918805519571907051
//#define DELTA_CALIBRATION_MENU
// uncomment to add G33 Delta Auto-Calibration (Enable EEPROM_SETTINGS to store results)
//#define DELTA_AUTO_CALIBRATION
// NOTE NB all values for DELTA_* values MUST be floating point, so always have a decimal point in them
#if ENABLED(DELTA_AUTO_CALIBRATION)
// set the default number of probe points : n*n (1 -> 7)
#define DELTA_CALIBRATION_DEFAULT_POINTS 4
#endif
#if EITHER(DELTA_AUTO_CALIBRATION, DELTA_CALIBRATION_MENU)
// Set the steprate for papertest probing
#define PROBE_MANUALLY_STEP 0.05 // (mm)
#endif
// Print surface diameter/2 minus unreachable space (avoid collisions with vertical towers).
#define DELTA_PRINTABLE_RADIUS 140.0 // (mm)
// Maximum reachable area
#define DELTA_MAX_RADIUS 140.0 // (mm)
// Center-to-center distance of the holes in the diagonal push rods.
#define DELTA_DIAGONAL_ROD 250.0 // (mm)
// Distance between bed and nozzle Z home position
#define DELTA_HEIGHT 250.00 // (mm) Get this value from G33 auto calibrate
#define DELTA_ENDSTOP_ADJ { 0.0, 0.0, 0.0 } // Get these values from G33 auto calibrate
// Horizontal distance bridged by diagonal push rods when effector is centered.
#define DELTA_RADIUS 124.0 // (mm) Get this value from G33 auto calibrate
// Trim adjustments for individual towers
// tower angle corrections for X and Y tower / rotate XYZ so Z tower angle = 0
// measured in degrees anticlockwise looking from above the printer
#define DELTA_TOWER_ANGLE_TRIM { 0.0, 0.0, 0.0 } // Get these values from G33 auto calibrate
// Delta radius and diagonal rod adjustments (mm)
//#define DELTA_RADIUS_TRIM_TOWER { 0.0, 0.0, 0.0 }
//#define DELTA_DIAGONAL_ROD_TRIM_TOWER { 0.0, 0.0, 0.0 }
#endif
// @section scara
/**
* MORGAN_SCARA was developed by QHARLEY in South Africa in 2012-2013.
* Implemented and slightly reworked by JCERNY in June, 2014.
*
* Mostly Printed SCARA is an open source design by Tyler Williams. See:
* https://www.thingiverse.com/thing:2487048
* https://www.thingiverse.com/thing:1241491
*/
//#define MORGAN_SCARA
//#define MP_SCARA
#if EITHER(MORGAN_SCARA, MP_SCARA)
// If movement is choppy try lowering this value
#define SCARA_SEGMENTS_PER_SECOND 200
// Length of inner and outer support arms. Measure arm lengths precisely.
#define SCARA_LINKAGE_1 150 // (mm)
#define SCARA_LINKAGE_2 150 // (mm)
// SCARA tower offset (position of Tower relative to bed zero position)
// This needs to be reasonably accurate as it defines the printbed position in the SCARA space.
#define SCARA_OFFSET_X 100 // (mm)
#define SCARA_OFFSET_Y -56 // (mm)
#if ENABLED(MORGAN_SCARA)
//#define DEBUG_SCARA_KINEMATICS
#define SCARA_FEEDRATE_SCALING // Convert XY feedrate from mm/s to degrees/s on the fly
// Radius around the center where the arm cannot reach
#define MIDDLE_DEAD_ZONE_R 0 // (mm)
#define THETA_HOMING_OFFSET 0 // Calculated from Calibration Guide and M360 / M114. See http://reprap.harleystudio.co.za/?page_id=1073
#define PSI_HOMING_OFFSET 0 // Calculated from Calibration Guide and M364 / M114. See http://reprap.harleystudio.co.za/?page_id=1073
#elif ENABLED(MP_SCARA)
#define SCARA_OFFSET_THETA1 12 // degrees
#define SCARA_OFFSET_THETA2 131 // degrees
#endif
#endif
// @section tpara
// Enable for TPARA kinematics and configure below
//#define AXEL_TPARA
#if ENABLED(AXEL_TPARA)
#define DEBUG_ROBOT_KINEMATICS
#define ROBOT_SEGMENTS_PER_SECOND 200
// Length of inner and outer support arms. Measure arm lengths precisely.
#define ROBOT_LINKAGE_1 120 // (mm)
#define ROBOT_LINKAGE_2 120 // (mm)
// SCARA tower offset (position of Tower relative to bed zero position)
// This needs to be reasonably accurate as it defines the printbed position in the SCARA space.
#define ROBOT_OFFSET_X 0 // (mm)
#define ROBOT_OFFSET_Y 0 // (mm)
#define ROBOT_OFFSET_Z 0 // (mm)
#define SCARA_FEEDRATE_SCALING // Convert XY feedrate from mm/s to degrees/s on the fly
// Radius around the center where the arm cannot reach
#define MIDDLE_DEAD_ZONE_R 0 // (mm)
// Calculated from Calibration Guide and M360 / M114. See http://reprap.harleystudio.co.za/?page_id=1073
#define THETA_HOMING_OFFSET 0
#define PSI_HOMING_OFFSET 0
#endif
// @section machine
// Articulated robot (arm). Joints are directly mapped to axes with no kinematics.
//#define ARTICULATED_ROBOT_ARM
// For a hot wire cutter with parallel horizontal axes (X, I) where the heights of the two wire
// ends are controlled by parallel axes (Y, J). Joints are directly mapped to axes (no kinematics).
//#define FOAMCUTTER_XYUV
//=========================================================================== //===========================================================================
//============================== Endstop Settings =========================== //============================== Endstop Settings ===========================
//=========================================================================== //===========================================================================
// @section homing // @section endstops
// Specify here all the endstop connectors that are connected to any endstop or probe. // Specify here all the endstop connectors that are connected to any endstop or probe.
// Almost all printers will be using one per axis. Probes will use one or more of the // Almost all printers will be using one per axis. Probes will use one or more of the
@@ -1217,6 +1367,27 @@
#define Z_PROBE_RETRACT_X X_MAX_POS #define Z_PROBE_RETRACT_X X_MAX_POS
#endif #endif
/**
* Magnetically Mounted Probe
* For probes such as Euclid, Klicky, Klackender, etc.
*/
//#define MAG_MOUNTED_PROBE
#if ENABLED(MAG_MOUNTED_PROBE)
#define PROBE_DEPLOY_FEEDRATE (133*60) // (mm/min) Probe deploy speed
#define PROBE_STOW_FEEDRATE (133*60) // (mm/min) Probe stow speed
#define MAG_MOUNTED_DEPLOY_1 { PROBE_DEPLOY_FEEDRATE, { 245, 114, 30 } } // Move to side Dock & Attach probe
#define MAG_MOUNTED_DEPLOY_2 { PROBE_DEPLOY_FEEDRATE, { 210, 114, 30 } } // Move probe off dock
#define MAG_MOUNTED_DEPLOY_3 { PROBE_DEPLOY_FEEDRATE, { 0, 0, 0 } } // Extra move if needed
#define MAG_MOUNTED_DEPLOY_4 { PROBE_DEPLOY_FEEDRATE, { 0, 0, 0 } } // Extra move if needed
#define MAG_MOUNTED_DEPLOY_5 { PROBE_DEPLOY_FEEDRATE, { 0, 0, 0 } } // Extra move if needed
#define MAG_MOUNTED_STOW_1 { PROBE_STOW_FEEDRATE, { 245, 114, 20 } } // Move to dock
#define MAG_MOUNTED_STOW_2 { PROBE_STOW_FEEDRATE, { 245, 114, 0 } } // Place probe beside remover
#define MAG_MOUNTED_STOW_3 { PROBE_STOW_FEEDRATE, { 230, 114, 0 } } // Side move to remove probe
#define MAG_MOUNTED_STOW_4 { PROBE_STOW_FEEDRATE, { 210, 114, 20 } } // Side move to remove probe
#define MAG_MOUNTED_STOW_5 { PROBE_STOW_FEEDRATE, { 0, 0, 0 } } // Extra move if needed
#endif
// Duet Smart Effector (for delta printers) - https://bit.ly/2ul5U7J // Duet Smart Effector (for delta printers) - https://bit.ly/2ul5U7J
// When the pin is defined you can use M672 to set/reset the probe sensitivity. // When the pin is defined you can use M672 to set/reset the probe sensitivity.
//#define DUET_SMART_EFFECTOR //#define DUET_SMART_EFFECTOR
@@ -1232,9 +1403,37 @@
*/ */
//#define SENSORLESS_PROBING //#define SENSORLESS_PROBING
// /**
// For Z_PROBE_ALLEN_KEY see the Delta example configurations. * Allen key retractable z-probe as seen on many Kossel delta printers - https://reprap.org/wiki/Kossel#Automatic_bed_leveling_probe
// * Deploys by touching z-axis belt. Retracts by pushing the probe down.
*/
//#define Z_PROBE_ALLEN_KEY
#if ENABLED(Z_PROBE_ALLEN_KEY)
// 2 or 3 sets of coordinates for deploying and retracting the spring loaded touch probe on G29,
// if servo actuated touch probe is not defined. Uncomment as appropriate for your printer/probe.
#define Z_PROBE_ALLEN_KEY_DEPLOY_1 { 30.0, DELTA_PRINTABLE_RADIUS, 100.0 }
#define Z_PROBE_ALLEN_KEY_DEPLOY_1_FEEDRATE XY_PROBE_FEEDRATE
#define Z_PROBE_ALLEN_KEY_DEPLOY_2 { 0.0, DELTA_PRINTABLE_RADIUS, 100.0 }
#define Z_PROBE_ALLEN_KEY_DEPLOY_2_FEEDRATE (XY_PROBE_FEEDRATE)/10
#define Z_PROBE_ALLEN_KEY_DEPLOY_3 { 0.0, (DELTA_PRINTABLE_RADIUS) * 0.75, 100.0 }
#define Z_PROBE_ALLEN_KEY_DEPLOY_3_FEEDRATE XY_PROBE_FEEDRATE
#define Z_PROBE_ALLEN_KEY_STOW_1 { -64.0, 56.0, 23.0 } // Move the probe into position
#define Z_PROBE_ALLEN_KEY_STOW_1_FEEDRATE XY_PROBE_FEEDRATE
#define Z_PROBE_ALLEN_KEY_STOW_2 { -64.0, 56.0, 3.0 } // Push it down
#define Z_PROBE_ALLEN_KEY_STOW_2_FEEDRATE (XY_PROBE_FEEDRATE)/10
#define Z_PROBE_ALLEN_KEY_STOW_3 { -64.0, 56.0, 50.0 } // Move it up to clear
#define Z_PROBE_ALLEN_KEY_STOW_3_FEEDRATE XY_PROBE_FEEDRATE
#define Z_PROBE_ALLEN_KEY_STOW_4 { 0.0, 0.0, 50.0 }
#define Z_PROBE_ALLEN_KEY_STOW_4_FEEDRATE XY_PROBE_FEEDRATE
#endif // Z_PROBE_ALLEN_KEY
/** /**
* Nozzle-to-Probe offsets { X, Y, Z } * Nozzle-to-Probe offsets { X, Y, Z }
@@ -1484,7 +1683,7 @@
//#define V_HOME_DIR -1 //#define V_HOME_DIR -1
//#define W_HOME_DIR -1 //#define W_HOME_DIR -1
// @section machine // @section geometry
// The size of the printable area // The size of the printable area
#define X_BED_SIZE 200 #define X_BED_SIZE 200
@@ -1687,6 +1886,15 @@
#define LEVELING_BED_TEMP 50 #define LEVELING_BED_TEMP 50
#endif #endif
/**
* Bed Distance Sensor
*
* Measures the distance from bed to nozzle with accuracy of 0.01mm.
* For information about this sensor https://github.com/markniu/Bed_Distance_sensor
* Uses I2C port, so it requires I2C library markyue/Panda_SoftMasterI2C.
*/
//#define BD_SENSOR
/** /**
* Enable detailed logging of G28, G29, M48, etc. * Enable detailed logging of G28, G29, M48, etc.
* Turn on with the command 'M111 S32'. * Turn on with the command 'M111 S32'.
@@ -1809,7 +2017,7 @@
//#define LCD_BED_TRAMMING //#define LCD_BED_TRAMMING
#if ENABLED(LCD_BED_TRAMMING) #if ENABLED(LCD_BED_TRAMMING)
#define BED_TRAMMING_INSET_LFRB { 30, 30, 30, 30 } // (mm) Left, Front, Right, Back insets #define BED_TRAMMING_INSET_LFRB { 30, 30, 30, 30 } // (mm) Left, Front, Right, Back insets
#define BED_TRAMMING_HEIGHT 0.0 // (mm) Z height of nozzle at leveling points #define BED_TRAMMING_HEIGHT 0.0 // (mm) Z height of nozzle at leveling points
#define BED_TRAMMING_Z_HOP 4.0 // (mm) Z height of nozzle between leveling points #define BED_TRAMMING_Z_HOP 4.0 // (mm) Z height of nozzle between leveling points
//#define BED_TRAMMING_INCLUDE_CENTER // Move to the center after the last corner //#define BED_TRAMMING_INCLUDE_CENTER // Move to the center after the last corner
@@ -1944,7 +2152,7 @@
//============================= Additional Features =========================== //============================= Additional Features ===========================
//============================================================================= //=============================================================================
// @section extras // @section eeprom
/** /**
* EEPROM * EEPROM
@@ -1964,6 +2172,8 @@
//#define EEPROM_INIT_NOW // Init EEPROM on first boot after a new build. //#define EEPROM_INIT_NOW // Init EEPROM on first boot after a new build.
#endif #endif
// @section host
// //
// Host Keepalive // Host Keepalive
// //
@@ -1974,6 +2184,8 @@
#define DEFAULT_KEEPALIVE_INTERVAL 2 // Number of seconds between "busy" messages. Set with M113. #define DEFAULT_KEEPALIVE_INTERVAL 2 // Number of seconds between "busy" messages. Set with M113.
#define BUSY_WHILE_HEATING // Some hosts require "busy" messages even during heating #define BUSY_WHILE_HEATING // Some hosts require "busy" messages even during heating
// @section units
// //
// G20/G21 Inch mode support // G20/G21 Inch mode support
// //
@@ -2001,6 +2213,8 @@
#define PREHEAT_2_TEMP_CHAMBER 35 #define PREHEAT_2_TEMP_CHAMBER 35
#define PREHEAT_2_FAN_SPEED 0 // Value from 0 to 255 #define PREHEAT_2_FAN_SPEED 0 // Value from 0 to 255
// @section motion
/** /**
* Nozzle Park * Nozzle Park
* *
@@ -2099,6 +2313,8 @@
#endif #endif
// @section host
/** /**
* Print Job Timer * Print Job Timer
* *
@@ -2125,6 +2341,8 @@
*/ */
#define PRINTJOB_TIMER_AUTOSTART #define PRINTJOB_TIMER_AUTOSTART
// @section stats
/** /**
* Print Counter * Print Counter
* *
@@ -2142,6 +2360,8 @@
#define PRINTCOUNTER_SAVE_INTERVAL 60 // (minutes) EEPROM save interval during print #define PRINTCOUNTER_SAVE_INTERVAL 60 // (minutes) EEPROM save interval during print
#endif #endif
// @section security
/** /**
* Password * Password
* *
@@ -2177,7 +2397,7 @@
//============================= LCD and SD support ============================ //============================= LCD and SD support ============================
//============================================================================= //=============================================================================
// @section lcd // @section interface
/** /**
* LCD LANGUAGE * LCD LANGUAGE
@@ -2293,6 +2513,16 @@
// //
//#define REVERSE_SELECT_DIRECTION //#define REVERSE_SELECT_DIRECTION
//
// Encoder EMI Noise Filter
//
// This option increases encoder samples to filter out phantom encoder clicks caused by EMI noise.
//
//#define ENCODER_NOISE_FILTER
#if ENABLED(ENCODER_NOISE_FILTER)
#define ENCODER_SAMPLES 10
#endif
// //
// Individual Axis Homing // Individual Axis Homing
// //
@@ -2323,6 +2553,7 @@
//======================== LCD / Controller Selection ========================= //======================== LCD / Controller Selection =========================
//======================== (Character-based LCDs) ========================= //======================== (Character-based LCDs) =========================
//============================================================================= //=============================================================================
// @section lcd
// //
// RepRapDiscount Smart Controller. // RepRapDiscount Smart Controller.
@@ -2624,6 +2855,12 @@
// //
//#define SILVER_GATE_GLCD_CONTROLLER //#define SILVER_GATE_GLCD_CONTROLLER
//
// eMotion Tech LCD with SD
// https://www.reprap-france.com/produit/1234568748-ecran-graphique-128-x-64-points-2-1
//
//#define EMOTION_TECH_LCD
//============================================================================= //=============================================================================
//============================== OLED Displays ============================== //============================== OLED Displays ==============================
//============================================================================= //=============================================================================
@@ -2951,7 +3188,7 @@
//=============================== Extra Features ============================== //=============================== Extra Features ==============================
//============================================================================= //=============================================================================
// @section extras // @section fans
// Set number of user-controlled fans. Disable to use all board-defined fans. // Set number of user-controlled fans. Disable to use all board-defined fans.
// :[1,2,3,4,5,6,7,8] // :[1,2,3,4,5,6,7,8]
@@ -2975,14 +3212,18 @@
// duty cycle is attained. // duty cycle is attained.
//#define SOFT_PWM_DITHER //#define SOFT_PWM_DITHER
// @section extras
// Support for the BariCUDA Paste Extruder
//#define BARICUDA
// @section lights
// Temperature status LEDs that display the hotend and bed temperature. // Temperature status LEDs that display the hotend and bed temperature.
// If all hotends, bed temperature, and target temperature are under 54C // If all hotends, bed temperature, and target temperature are under 54C
// then the BLUE led is on. Otherwise the RED led is on. (1C hysteresis) // then the BLUE led is on. Otherwise the RED led is on. (1C hysteresis)
//#define TEMP_STAT_LEDS //#define TEMP_STAT_LEDS
// Support for the BariCUDA Paste Extruder
//#define BARICUDA
// Support for BlinkM/CyzRgb // Support for BlinkM/CyzRgb
//#define BLINKM //#define BLINKM
@@ -3068,6 +3309,8 @@
#define PRINTER_EVENT_LEDS #define PRINTER_EVENT_LEDS
#endif #endif
// @section servos
/** /**
* Number of servos * Number of servos
* *

View File

@@ -30,7 +30,25 @@
* *
* Basic settings can be found in Configuration.h * Basic settings can be found in Configuration.h
*/ */
#define CONFIGURATION_ADV_H_VERSION 02010000 #define CONFIGURATION_ADV_H_VERSION 02010100
// @section develop
/**
* Configuration Export
*
* Export the configuration as part of the build. (See signature.py)
* Output files are saved with the build (e.g., .pio/build/mega2560).
*
* See `build_all_examples --ini` as an example of config.ini archiving.
*
* 1 = marlin_config.json - Dictionary containing the configuration.
* This file is also generated for CONFIGURATION_EMBEDDING.
* 2 = config.ini - File format for PlatformIO preprocessing.
* 3 = schema.json - The entire configuration schema. (13 = pattern groups)
* 4 = schema.yml - The entire configuration schema.
*/
//#define CONFIG_EXPORT // :[1:'JSON', 2:'config.ini', 3:'schema.json', 4:'schema.yml']
//=========================================================================== //===========================================================================
//============================= Thermal Settings ============================ //============================= Thermal Settings ============================
@@ -54,87 +72,101 @@
// Custom Thermistor 1000 parameters // Custom Thermistor 1000 parameters
// //
#if TEMP_SENSOR_0 == 1000 #if TEMP_SENSOR_0 == 1000
#define HOTEND0_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor #define HOTEND0_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
#define HOTEND0_RESISTANCE_25C_OHMS 100000 // Resistance at 25C #define HOTEND0_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
#define HOTEND0_BETA 3950 // Beta value #define HOTEND0_BETA 3950 // Beta value
#define HOTEND0_SH_C_COEFF 0 // Steinhart-Hart C coefficient
#endif #endif
#if TEMP_SENSOR_1 == 1000 #if TEMP_SENSOR_1 == 1000
#define HOTEND1_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor #define HOTEND1_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
#define HOTEND1_RESISTANCE_25C_OHMS 100000 // Resistance at 25C #define HOTEND1_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
#define HOTEND1_BETA 3950 // Beta value #define HOTEND1_BETA 3950 // Beta value
#define HOTEND1_SH_C_COEFF 0 // Steinhart-Hart C coefficient
#endif #endif
#if TEMP_SENSOR_2 == 1000 #if TEMP_SENSOR_2 == 1000
#define HOTEND2_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor #define HOTEND2_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
#define HOTEND2_RESISTANCE_25C_OHMS 100000 // Resistance at 25C #define HOTEND2_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
#define HOTEND2_BETA 3950 // Beta value #define HOTEND2_BETA 3950 // Beta value
#define HOTEND2_SH_C_COEFF 0 // Steinhart-Hart C coefficient
#endif #endif
#if TEMP_SENSOR_3 == 1000 #if TEMP_SENSOR_3 == 1000
#define HOTEND3_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor #define HOTEND3_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
#define HOTEND3_RESISTANCE_25C_OHMS 100000 // Resistance at 25C #define HOTEND3_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
#define HOTEND3_BETA 3950 // Beta value #define HOTEND3_BETA 3950 // Beta value
#define HOTEND3_SH_C_COEFF 0 // Steinhart-Hart C coefficient
#endif #endif
#if TEMP_SENSOR_4 == 1000 #if TEMP_SENSOR_4 == 1000
#define HOTEND4_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor #define HOTEND4_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
#define HOTEND4_RESISTANCE_25C_OHMS 100000 // Resistance at 25C #define HOTEND4_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
#define HOTEND4_BETA 3950 // Beta value #define HOTEND4_BETA 3950 // Beta value
#define HOTEND4_SH_C_COEFF 0 // Steinhart-Hart C coefficient
#endif #endif
#if TEMP_SENSOR_5 == 1000 #if TEMP_SENSOR_5 == 1000
#define HOTEND5_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor #define HOTEND5_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
#define HOTEND5_RESISTANCE_25C_OHMS 100000 // Resistance at 25C #define HOTEND5_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
#define HOTEND5_BETA 3950 // Beta value #define HOTEND5_BETA 3950 // Beta value
#define HOTEND5_SH_C_COEFF 0 // Steinhart-Hart C coefficient
#endif #endif
#if TEMP_SENSOR_6 == 1000 #if TEMP_SENSOR_6 == 1000
#define HOTEND6_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor #define HOTEND6_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
#define HOTEND6_RESISTANCE_25C_OHMS 100000 // Resistance at 25C #define HOTEND6_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
#define HOTEND6_BETA 3950 // Beta value #define HOTEND6_BETA 3950 // Beta value
#define HOTEND6_SH_C_COEFF 0 // Steinhart-Hart C coefficient
#endif #endif
#if TEMP_SENSOR_7 == 1000 #if TEMP_SENSOR_7 == 1000
#define HOTEND7_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor #define HOTEND7_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
#define HOTEND7_RESISTANCE_25C_OHMS 100000 // Resistance at 25C #define HOTEND7_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
#define HOTEND7_BETA 3950 // Beta value #define HOTEND7_BETA 3950 // Beta value
#define HOTEND7_SH_C_COEFF 0 // Steinhart-Hart C coefficient
#endif #endif
#if TEMP_SENSOR_BED == 1000 #if TEMP_SENSOR_BED == 1000
#define BED_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor #define BED_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
#define BED_RESISTANCE_25C_OHMS 100000 // Resistance at 25C #define BED_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
#define BED_BETA 3950 // Beta value #define BED_BETA 3950 // Beta value
#define BED_SH_C_COEFF 0 // Steinhart-Hart C coefficient
#endif #endif
#if TEMP_SENSOR_CHAMBER == 1000 #if TEMP_SENSOR_CHAMBER == 1000
#define CHAMBER_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor #define CHAMBER_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
#define CHAMBER_RESISTANCE_25C_OHMS 100000 // Resistance at 25C #define CHAMBER_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
#define CHAMBER_BETA 3950 // Beta value #define CHAMBER_BETA 3950 // Beta value
#define CHAMBER_SH_C_COEFF 0 // Steinhart-Hart C coefficient
#endif #endif
#if TEMP_SENSOR_COOLER == 1000 #if TEMP_SENSOR_COOLER == 1000
#define COOLER_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor #define COOLER_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
#define COOLER_RESISTANCE_25C_OHMS 100000 // Resistance at 25C #define COOLER_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
#define COOLER_BETA 3950 // Beta value #define COOLER_BETA 3950 // Beta value
#define COOLER_SH_C_COEFF 0 // Steinhart-Hart C coefficient
#endif #endif
#if TEMP_SENSOR_PROBE == 1000 #if TEMP_SENSOR_PROBE == 1000
#define PROBE_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor #define PROBE_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
#define PROBE_RESISTANCE_25C_OHMS 100000 // Resistance at 25C #define PROBE_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
#define PROBE_BETA 3950 // Beta value #define PROBE_BETA 3950 // Beta value
#define PROBE_SH_C_COEFF 0 // Steinhart-Hart C coefficient
#endif #endif
#if TEMP_SENSOR_BOARD == 1000 #if TEMP_SENSOR_BOARD == 1000
#define BOARD_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor #define BOARD_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
#define BOARD_RESISTANCE_25C_OHMS 100000 // Resistance at 25C #define BOARD_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
#define BOARD_BETA 3950 // Beta value #define BOARD_BETA 3950 // Beta value
#define BOARD_SH_C_COEFF 0 // Steinhart-Hart C coefficient
#endif #endif
#if TEMP_SENSOR_REDUNDANT == 1000 #if TEMP_SENSOR_REDUNDANT == 1000
#define REDUNDANT_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor #define REDUNDANT_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
#define REDUNDANT_RESISTANCE_25C_OHMS 100000 // Resistance at 25C #define REDUNDANT_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
#define REDUNDANT_BETA 3950 // Beta value #define REDUNDANT_BETA 3950 // Beta value
#define REDUNDANT_SH_C_COEFF 0 // Steinhart-Hart C coefficient
#endif #endif
/** /**
@@ -286,7 +318,7 @@
* and/or decrease WATCH_TEMP_INCREASE. WATCH_TEMP_INCREASE should not be set * and/or decrease WATCH_TEMP_INCREASE. WATCH_TEMP_INCREASE should not be set
* below 2. * below 2.
*/ */
#define WATCH_TEMP_PERIOD 20 // Seconds #define WATCH_TEMP_PERIOD 40 // Seconds
#define WATCH_TEMP_INCREASE 2 // Degrees Celsius #define WATCH_TEMP_INCREASE 2 // Degrees Celsius
#endif #endif
@@ -923,9 +955,12 @@
*/ */
//#define Z_STEPPER_AUTO_ALIGN //#define Z_STEPPER_AUTO_ALIGN
#if ENABLED(Z_STEPPER_AUTO_ALIGN) #if ENABLED(Z_STEPPER_AUTO_ALIGN)
// Define probe X and Y positions for Z1, Z2 [, Z3 [, Z4]] /**
// If not defined, probe limits will be used. * Define probe X and Y positions for Z1, Z2 [, Z3 [, Z4]]
// Override with 'M422 S<index> X<pos> Y<pos>' * These positions are machine-relative and do not shift with the M206 home offset!
* If not defined, probe limits will be used.
* Override with 'M422 S<index> X<pos> Y<pos>'.
*/
//#define Z_STEPPER_ALIGN_XY { { 10, 190 }, { 100, 10 }, { 190, 190 } } //#define Z_STEPPER_ALIGN_XY { { 10, 190 }, { 100, 10 }, { 190, 190 } }
/** /**
@@ -1319,6 +1354,9 @@
#define XATC_Y_POSITION Y_CENTER // (mm) Y position to probe #define XATC_Y_POSITION Y_CENTER // (mm) Y position to probe
#define XATC_Z_OFFSETS { 0, 0, 0 } // Z offsets for X axis sample points #define XATC_Z_OFFSETS { 0, 0, 0 } // Z offsets for X axis sample points
#endif #endif
// Show Deploy / Stow Probe options in the Motion menu.
#define PROBE_DEPLOY_STOW_MENU
#endif #endif
// Include a page of printer information in the LCD Main Menu // Include a page of printer information in the LCD Main Menu
@@ -1551,6 +1589,9 @@
* Endstops must be activated for this option to work. * Endstops must be activated for this option to work.
*/ */
//#define SD_ABORT_ON_ENDSTOP_HIT //#define SD_ABORT_ON_ENDSTOP_HIT
#if ENABLED(SD_ABORT_ON_ENDSTOP_HIT)
//#define SD_ABORT_ON_ENDSTOP_HIT_GCODE "G28XY" // G-code to run on endstop hit (e.g., "G28XY" or "G27")
#endif
//#define SD_REPRINT_LAST_SELECTED_FILE // On print completion open the LCD Menu and select the same file //#define SD_REPRINT_LAST_SELECTED_FILE // On print completion open the LCD Menu and select the same file
@@ -1585,6 +1626,8 @@
//#define USE_UHS2_USB //#define USE_UHS2_USB
//#define USE_UHS3_USB //#define USE_UHS3_USB
#define DISABLE_DUE_SD_MMC // Disable USB Host access to USB Drive to prevent hangs on block access for DUE platform
/** /**
* Native USB Host supported by some boards (USB OTG) * Native USB Host supported by some boards (USB OTG)
*/ */
@@ -2523,6 +2566,8 @@
#endif #endif
#endif // HAS_MULTI_EXTRUDER #endif // HAS_MULTI_EXTRUDER
// @section advanced pause
/** /**
* Advanced Pause for Filament Change * Advanced Pause for Filament Change
* - Adds the G-code M600 Filament Change to initiate a filament change. * - Adds the G-code M600 Filament Change to initiate a filament change.
@@ -2581,13 +2626,12 @@
//#define FILAMENT_UNLOAD_ALL_EXTRUDERS // Allow M702 to unload all extruders above a minimum target temp (as set by M302) //#define FILAMENT_UNLOAD_ALL_EXTRUDERS // Allow M702 to unload all extruders above a minimum target temp (as set by M302)
#endif #endif
// @section tmc
/** /**
* TMC26X Stepper Driver options * TMC26X Stepper Driver options
* *
* The TMC26XStepper library is required for this stepper driver. * The TMC26XStepper library is required for this stepper driver.
* https://github.com/trinamic/TMC26XStepper * https://github.com/trinamic/TMC26XStepper
* @section tmc/tmc26x
*/ */
#if HAS_DRIVER(TMC26X) #if HAS_DRIVER(TMC26X)
@@ -2725,8 +2769,6 @@
#endif // TMC26X #endif // TMC26X
// @section tmc_smart
/** /**
* To use TMC2130, TMC2160, TMC2660, TMC5130, TMC5160 stepper drivers in SPI mode * To use TMC2130, TMC2160, TMC2660, TMC5130, TMC5160 stepper drivers in SPI mode
* connect your SPI pins to the hardware SPI interface on your board and define * connect your SPI pins to the hardware SPI interface on your board and define
@@ -2742,6 +2784,7 @@
* *
* TMCStepper library is required to use TMC stepper drivers. * TMCStepper library is required to use TMC stepper drivers.
* https://github.com/teemuatlut/TMCStepper * https://github.com/teemuatlut/TMCStepper
* @section tmc/config
*/ */
#if HAS_TRINAMIC_CONFIG #if HAS_TRINAMIC_CONFIG
@@ -2965,6 +3008,8 @@
//#define E7_HOLD_MULTIPLIER 0.5 //#define E7_HOLD_MULTIPLIER 0.5
#endif #endif
// @section tmc/spi
/** /**
* Override default SPI pins for TMC2130, TMC2160, TMC2660, TMC5130 and TMC5160 drivers here. * Override default SPI pins for TMC2130, TMC2160, TMC2660, TMC5130 and TMC5160 drivers here.
* The default pins can be found in your board's pins file. * The default pins can be found in your board's pins file.
@@ -3002,6 +3047,8 @@
//#define TMC_SW_MISO -1 //#define TMC_SW_MISO -1
//#define TMC_SW_SCK -1 //#define TMC_SW_SCK -1
// @section tmc/serial
/** /**
* Four TMC2209 drivers can use the same HW/SW serial port with hardware configured addresses. * Four TMC2209 drivers can use the same HW/SW serial port with hardware configured addresses.
* Set the address using jumpers on pins MS1 and MS2. * Set the address using jumpers on pins MS1 and MS2.
@@ -3037,6 +3084,8 @@
//#define E6_SLAVE_ADDRESS 0 //#define E6_SLAVE_ADDRESS 0
//#define E7_SLAVE_ADDRESS 0 //#define E7_SLAVE_ADDRESS 0
// @section tmc/smart
/** /**
* Software enable * Software enable
* *
@@ -3045,6 +3094,8 @@
*/ */
//#define SOFTWARE_DRIVER_ENABLE //#define SOFTWARE_DRIVER_ENABLE
// @section tmc/stealthchop
/** /**
* TMC2130, TMC2160, TMC2208, TMC2209, TMC5130 and TMC5160 only * TMC2130, TMC2160, TMC2208, TMC2209, TMC5130 and TMC5160 only
* Use Trinamic's ultra quiet stepping mode. * Use Trinamic's ultra quiet stepping mode.
@@ -3099,6 +3150,8 @@
//#define CHOPPER_TIMING_E6 CHOPPER_TIMING_E //#define CHOPPER_TIMING_E6 CHOPPER_TIMING_E
//#define CHOPPER_TIMING_E7 CHOPPER_TIMING_E //#define CHOPPER_TIMING_E7 CHOPPER_TIMING_E
// @section tmc/status
/** /**
* Monitor Trinamic drivers * Monitor Trinamic drivers
* for error conditions like overtemperature and short to ground. * for error conditions like overtemperature and short to ground.
@@ -3118,6 +3171,8 @@
#define STOP_ON_ERROR #define STOP_ON_ERROR
#endif #endif
// @section tmc/hybrid
/** /**
* TMC2130, TMC2160, TMC2208, TMC2209, TMC5130 and TMC5160 only * TMC2130, TMC2160, TMC2208, TMC2209, TMC5130 and TMC5160 only
* The driver will switch to spreadCycle when stepper speed is over HYBRID_THRESHOLD. * The driver will switch to spreadCycle when stepper speed is over HYBRID_THRESHOLD.
@@ -3174,6 +3229,7 @@
* homing and adds a guard period for endstop triggering. * homing and adds a guard period for endstop triggering.
* *
* Comment *_STALL_SENSITIVITY to disable sensorless homing for that axis. * Comment *_STALL_SENSITIVITY to disable sensorless homing for that axis.
* @section tmc/stallguard
*/ */
//#define SENSORLESS_HOMING // StallGuard capable drivers only //#define SENSORLESS_HOMING // StallGuard capable drivers only
@@ -3197,6 +3253,8 @@
//#define IMPROVE_HOMING_RELIABILITY //#define IMPROVE_HOMING_RELIABILITY
#endif #endif
// @section tmc/config
/** /**
* TMC Homing stepper phase. * TMC Homing stepper phase.
* *
@@ -3236,254 +3294,6 @@
#endif // HAS_TRINAMIC_CONFIG #endif // HAS_TRINAMIC_CONFIG
// @section L64XX
/**
* L64XX Stepper Driver options
*
* Arduino-L6470 library (0.8.0 or higher) is required.
* https://github.com/ameyer/Arduino-L6470
*
* Requires the following to be defined in your pins_YOUR_BOARD file
* L6470_CHAIN_SCK_PIN
* L6470_CHAIN_MISO_PIN
* L6470_CHAIN_MOSI_PIN
* L6470_CHAIN_SS_PIN
* ENABLE_RESET_L64XX_CHIPS(Q) where Q is 1 to enable and 0 to reset
*/
#if HAS_L64XX
//#define L6470_CHITCHAT // Display additional status info
#if AXIS_IS_L64XX(X)
#define X_MICROSTEPS 128 // Number of microsteps (VALID: 1, 2, 4, 8, 16, 32, 128) - L6474 max is 16
#define X_OVERCURRENT 2000 // (mA) Current where the driver detects an over current
// L6470 & L6474 - VALID: 375 x (1 - 16) - 6A max - rounds down
// POWERSTEP01: VALID: 1000 x (1 - 32) - 32A max - rounds down
#define X_STALLCURRENT 1500 // (mA) Current where the driver detects a stall (VALID: 31.25 * (1-128) - 4A max - rounds down)
// L6470 & L6474 - VALID: 31.25 * (1-128) - 4A max - rounds down
// POWERSTEP01: VALID: 200 x (1 - 32) - 6.4A max - rounds down
// L6474 - STALLCURRENT setting is used to set the nominal (TVAL) current
#define X_MAX_VOLTAGE 127 // 0-255, Maximum effective voltage seen by stepper - not used by L6474
#define X_CHAIN_POS -1 // Position in SPI chain, 0=Not in chain, 1=Nearest MOSI
#define X_SLEW_RATE 1 // 0-3, Slew 0 is slowest, 3 is fastest
#endif
#if AXIS_IS_L64XX(X2)
#define X2_MICROSTEPS X_MICROSTEPS
#define X2_OVERCURRENT 2000
#define X2_STALLCURRENT 1500
#define X2_MAX_VOLTAGE 127
#define X2_CHAIN_POS -1
#define X2_SLEW_RATE 1
#endif
#if AXIS_IS_L64XX(Y)
#define Y_MICROSTEPS 128
#define Y_OVERCURRENT 2000
#define Y_STALLCURRENT 1500
#define Y_MAX_VOLTAGE 127
#define Y_CHAIN_POS -1
#define Y_SLEW_RATE 1
#endif
#if AXIS_IS_L64XX(Y2)
#define Y2_MICROSTEPS Y_MICROSTEPS
#define Y2_OVERCURRENT 2000
#define Y2_STALLCURRENT 1500
#define Y2_MAX_VOLTAGE 127
#define Y2_CHAIN_POS -1
#define Y2_SLEW_RATE 1
#endif
#if AXIS_IS_L64XX(Z)
#define Z_MICROSTEPS 128
#define Z_OVERCURRENT 2000
#define Z_STALLCURRENT 1500
#define Z_MAX_VOLTAGE 127
#define Z_CHAIN_POS -1
#define Z_SLEW_RATE 1
#endif
#if AXIS_IS_L64XX(Z2)
#define Z2_MICROSTEPS Z_MICROSTEPS
#define Z2_OVERCURRENT 2000
#define Z2_STALLCURRENT 1500
#define Z2_MAX_VOLTAGE 127
#define Z2_CHAIN_POS -1
#define Z2_SLEW_RATE 1
#endif
#if AXIS_IS_L64XX(Z3)
#define Z3_MICROSTEPS Z_MICROSTEPS
#define Z3_OVERCURRENT 2000
#define Z3_STALLCURRENT 1500
#define Z3_MAX_VOLTAGE 127
#define Z3_CHAIN_POS -1
#define Z3_SLEW_RATE 1
#endif
#if AXIS_IS_L64XX(Z4)
#define Z4_MICROSTEPS Z_MICROSTEPS
#define Z4_OVERCURRENT 2000
#define Z4_STALLCURRENT 1500
#define Z4_MAX_VOLTAGE 127
#define Z4_CHAIN_POS -1
#define Z4_SLEW_RATE 1
#endif
#if AXIS_IS_L64XX(I)
#define I_MICROSTEPS 128
#define I_OVERCURRENT 2000
#define I_STALLCURRENT 1500
#define I_MAX_VOLTAGE 127
#define I_CHAIN_POS -1
#define I_SLEW_RATE 1
#endif
#if AXIS_IS_L64XX(J)
#define J_MICROSTEPS 128
#define J_OVERCURRENT 2000
#define J_STALLCURRENT 1500
#define J_MAX_VOLTAGE 127
#define J_CHAIN_POS -1
#define J_SLEW_RATE 1
#endif
#if AXIS_IS_L64XX(K)
#define K_MICROSTEPS 128
#define K_OVERCURRENT 2000
#define K_STALLCURRENT 1500
#define K_MAX_VOLTAGE 127
#define K_CHAIN_POS -1
#define K_SLEW_RATE 1
#endif
#if AXIS_IS_L64XX(U)
#define U_MICROSTEPS 128
#define U_OVERCURRENT 2000
#define U_STALLCURRENT 1500
#define U_MAX_VOLTAGE 127
#define U_CHAIN_POS -1
#define U_SLEW_RATE 1
#endif
#if AXIS_IS_L64XX(V)
#define V_MICROSTEPS 128
#define V_OVERCURRENT 2000
#define V_STALLCURRENT 1500
#define V_MAX_VOLTAGE 127
#define V_CHAIN_POS -1
#define V_SLEW_RATE 1
#endif
#if AXIS_IS_L64XX(W)
#define W_MICROSTEPS 128
#define W_OVERCURRENT 2000
#define W_STALLCURRENT 1500
#define W_MAX_VOLTAGE 127
#define W_CHAIN_POS -1
#define W_SLEW_RATE 1
#endif
#if AXIS_IS_L64XX(E0)
#define E0_MICROSTEPS 128
#define E0_OVERCURRENT 2000
#define E0_STALLCURRENT 1500
#define E0_MAX_VOLTAGE 127
#define E0_CHAIN_POS -1
#define E0_SLEW_RATE 1
#endif
#if AXIS_IS_L64XX(E1)
#define E1_MICROSTEPS E0_MICROSTEPS
#define E1_OVERCURRENT 2000
#define E1_STALLCURRENT 1500
#define E1_MAX_VOLTAGE 127
#define E1_CHAIN_POS -1
#define E1_SLEW_RATE 1
#endif
#if AXIS_IS_L64XX(E2)
#define E2_MICROSTEPS E0_MICROSTEPS
#define E2_OVERCURRENT 2000
#define E2_STALLCURRENT 1500
#define E2_MAX_VOLTAGE 127
#define E2_CHAIN_POS -1
#define E2_SLEW_RATE 1
#endif
#if AXIS_IS_L64XX(E3)
#define E3_MICROSTEPS E0_MICROSTEPS
#define E3_OVERCURRENT 2000
#define E3_STALLCURRENT 1500
#define E3_MAX_VOLTAGE 127
#define E3_CHAIN_POS -1
#define E3_SLEW_RATE 1
#endif
#if AXIS_IS_L64XX(E4)
#define E4_MICROSTEPS E0_MICROSTEPS
#define E4_OVERCURRENT 2000
#define E4_STALLCURRENT 1500
#define E4_MAX_VOLTAGE 127
#define E4_CHAIN_POS -1
#define E4_SLEW_RATE 1
#endif
#if AXIS_IS_L64XX(E5)
#define E5_MICROSTEPS E0_MICROSTEPS
#define E5_OVERCURRENT 2000
#define E5_STALLCURRENT 1500
#define E5_MAX_VOLTAGE 127
#define E5_CHAIN_POS -1
#define E5_SLEW_RATE 1
#endif
#if AXIS_IS_L64XX(E6)
#define E6_MICROSTEPS E0_MICROSTEPS
#define E6_OVERCURRENT 2000
#define E6_STALLCURRENT 1500
#define E6_MAX_VOLTAGE 127
#define E6_CHAIN_POS -1
#define E6_SLEW_RATE 1
#endif
#if AXIS_IS_L64XX(E7)
#define E7_MICROSTEPS E0_MICROSTEPS
#define E7_OVERCURRENT 2000
#define E7_STALLCURRENT 1500
#define E7_MAX_VOLTAGE 127
#define E7_CHAIN_POS -1
#define E7_SLEW_RATE 1
#endif
/**
* Monitor L6470 drivers for error conditions like over temperature and over current.
* In the case of over temperature Marlin can decrease the drive until the error condition clears.
* Other detected conditions can be used to stop the current print.
* Relevant G-codes:
* M906 - I1/2/3/4/5 Set or get motor drive level using axis codes X, Y, Z, E. Report values if no axis codes given.
* I not present or I0 or I1 - X, Y, Z or E0
* I2 - X2, Y2, Z2 or E1
* I3 - Z3 or E3
* I4 - Z4 or E4
* I5 - E5
* M916 - Increase drive level until get thermal warning
* M917 - Find minimum current thresholds
* M918 - Increase speed until max or error
* M122 S0/1 - Report driver parameters
*/
//#define MONITOR_L6470_DRIVER_STATUS
#if ENABLED(MONITOR_L6470_DRIVER_STATUS)
#define KVAL_HOLD_STEP_DOWN 1
//#define L6470_STOP_ON_ERROR
#endif
#endif // HAS_L64XX
// @section i2cbus // @section i2cbus
// //
@@ -3525,7 +3335,7 @@
#define I2C_SLAVE_ADDRESS 0 // Set a value from 8 to 127 to act as a slave #define I2C_SLAVE_ADDRESS 0 // Set a value from 8 to 127 to act as a slave
#endif #endif
// @section extras // @section photo
/** /**
* Photo G-code * Photo G-code
@@ -3568,6 +3378,8 @@
#endif #endif
#endif #endif
// @section cnc
/** /**
* Spindle & Laser control * Spindle & Laser control
* *
@@ -3592,6 +3404,9 @@
#if ENABLED(SPINDLE_LASER_USE_PWM) #if ENABLED(SPINDLE_LASER_USE_PWM)
#define SPINDLE_LASER_PWM_INVERT false // Set to "true" if the speed/power goes up when you want it to go slower #define SPINDLE_LASER_PWM_INVERT false // Set to "true" if the speed/power goes up when you want it to go slower
#define SPINDLE_LASER_FREQUENCY 2500 // (Hz) Spindle/laser frequency (only on supported HALs: AVR, ESP32, and LPC) #define SPINDLE_LASER_FREQUENCY 2500 // (Hz) Spindle/laser frequency (only on supported HALs: AVR, ESP32, and LPC)
// ESP32: If SPINDLE_LASER_PWM_PIN is onboard then <=78125Hz. For I2S expander
// the frequency determines the PWM resolution. 2500Hz = 0-100, 977Hz = 0-255, ...
// (250000 / SPINDLE_LASER_FREQUENCY) = max value.
#endif #endif
//#define AIR_EVACUATION // Cutter Vacuum / Laser Blower motor control with G-codes M10-M11 //#define AIR_EVACUATION // Cutter Vacuum / Laser Blower motor control with G-codes M10-M11
@@ -3665,8 +3480,11 @@
#endif #endif
// Define the minimum and maximum test pulse time values for a laser test fire function // Define the minimum and maximum test pulse time values for a laser test fire function
#define LASER_TEST_PULSE_MIN 1 // Used with Laser Control Menu #define LASER_TEST_PULSE_MIN 1 // (ms) Used with Laser Control Menu
#define LASER_TEST_PULSE_MAX 999 // Caution: Menu may not show more than 3 characters #define LASER_TEST_PULSE_MAX 999 // (ms) Caution: Menu may not show more than 3 characters
#define SPINDLE_LASER_POWERUP_DELAY 50 // (ms) Delay to allow the spindle/laser to come up to speed/power
#define SPINDLE_LASER_POWERDOWN_DELAY 50 // (ms) Delay to allow the spindle to stop
/** /**
* Laser Safety Timeout * Laser Safety Timeout
@@ -3679,79 +3497,38 @@
#define LASER_SAFETY_TIMEOUT_MS 1000 // (ms) #define LASER_SAFETY_TIMEOUT_MS 1000 // (ms)
/** /**
* Enable inline laser power to be handled in the planner / stepper routines. * Any M3 or G1/2/3/5 command with the 'I' parameter enables continuous inline power mode.
* Inline power is specified by the I (inline) flag in an M3 command (e.g., M3 S20 I)
* or by the 'S' parameter in G0/G1/G2/G3 moves (see LASER_MOVE_POWER).
* *
* This allows the laser to keep in perfect sync with the planner and removes * e.g., 'M3 I' enables continuous inline power which is processed by the planner.
* the powerup/down delay since lasers require negligible time. * Power is stored in move blocks and applied when blocks are processed by the Stepper ISR.
*
* 'M4 I' sets dynamic mode which uses the current feedrate to calculate a laser power OCR value.
*
* Any move in dynamic mode will use the current feedrate to calculate the laser power.
* Feed rates are set by the F parameter of a move command e.g. G1 X0 Y10 F6000
* Laser power would be calculated by bit shifting off 8 LSB's. In binary this is div 256.
* The calculation gives us ocr values from 0 to 255, values over F65535 will be set as 255 .
* More refined power control such as compesation for accell/decell will be addressed in future releases.
*
* M5 I clears inline mode and set power to 0, M5 sets the power output to 0 but leaves inline mode on.
*/ */
//#define LASER_POWER_INLINE
#if ENABLED(LASER_POWER_INLINE) /**
/** * Enable M3 commands for laser mode inline power planner syncing.
* Scale the laser's power in proportion to the movement rate. * This feature enables any M3 S-value to be injected into the block buffers while in
* * CUTTER_MODE_CONTINUOUS. The option allows M3 laser power to be commited without waiting
* - Sets the entry power proportional to the entry speed over the nominal speed. * for a planner syncronization
* - Ramps the power up every N steps to approximate the speed trapezoid. */
* - Due to the limited power resolution this is only approximate. //#define LASER_POWER_SYNC
*/
#define LASER_POWER_INLINE_TRAPEZOID
/** /**
* Continuously calculate the current power (nominal_power * current_rate / nominal_rate). * Scale the laser's power in proportion to the movement rate.
* Required for accurate power with non-trapezoidal acceleration (e.g., S_CURVE_ACCELERATION). *
* This is a costly calculation so this option is discouraged on 8-bit AVR boards. * - Sets the entry power proportional to the entry speed over the nominal speed.
* * - Ramps the power up every N steps to approximate the speed trapezoid.
* LASER_POWER_INLINE_TRAPEZOID_CONT_PER defines how many step cycles there are between power updates. If your * - Due to the limited power resolution this is only approximate.
* board isn't able to generate steps fast enough (and you are using LASER_POWER_INLINE_TRAPEZOID_CONT), increase this. */
* Note that when this is zero it means it occurs every cycle; 1 means a delay wait one cycle then run, etc. //#define LASER_POWER_TRAP
*/
//#define LASER_POWER_INLINE_TRAPEZOID_CONT
/**
* Stepper iterations between power updates. Increase this value if the board
* can't keep up with the processing demands of LASER_POWER_INLINE_TRAPEZOID_CONT.
* Disable (or set to 0) to recalculate power on every stepper iteration.
*/
//#define LASER_POWER_INLINE_TRAPEZOID_CONT_PER 10
/**
* Include laser power in G0/G1/G2/G3/G5 commands with the 'S' parameter
*/
//#define LASER_MOVE_POWER
#if ENABLED(LASER_MOVE_POWER)
// Turn off the laser on G0 moves with no power parameter.
// If a power parameter is provided, use that instead.
//#define LASER_MOVE_G0_OFF
// Turn off the laser on G28 homing.
//#define LASER_MOVE_G28_OFF
#endif
/**
* Inline flag inverted
*
* WARNING: M5 will NOT turn off the laser unless another move
* is done (so G-code files must end with 'M5 I').
*/
//#define LASER_POWER_INLINE_INVERT
/**
* Continuously apply inline power. ('M3 S3' == 'G1 S3' == 'M3 S3 I')
*
* The laser might do some weird things, so only enable this
* feature if you understand the implications.
*/
//#define LASER_POWER_INLINE_CONTINUOUS
#else
#define SPINDLE_LASER_POWERUP_DELAY 50 // (ms) Delay to allow the spindle/laser to come up to speed/power
#define SPINDLE_LASER_POWERDOWN_DELAY 50 // (ms) Delay to allow the spindle to stop
#endif
// //
// Laser I2C Ammeter (High precision INA226 low/high side module) // Laser I2C Ammeter (High precision INA226 low/high side module)
@@ -3806,6 +3583,8 @@
#define COOLANT_FLOOD_INVERT false // Set "true" if the on/off function is reversed #define COOLANT_FLOOD_INVERT false // Set "true" if the on/off function is reversed
#endif #endif
// @section filament width
/** /**
* Filament Width Sensor * Filament Width Sensor
* *
@@ -3839,6 +3618,8 @@
//#define FILAMENT_LCD_DISPLAY //#define FILAMENT_LCD_DISPLAY
#endif #endif
// @section power
/** /**
* Power Monitor * Power Monitor
* Monitor voltage (V) and/or current (A), and -when possible- power (W) * Monitor voltage (V) and/or current (A), and -when possible- power (W)
@@ -3862,6 +3643,8 @@
#define POWER_MONITOR_VOLTAGE_OFFSET 0 // Offset (in volts) applied to the calculated voltage #define POWER_MONITOR_VOLTAGE_OFFSET 0 // Offset (in volts) applied to the calculated voltage
#endif #endif
// @section safety
/** /**
* Stepper Driver Anti-SNAFU Protection * Stepper Driver Anti-SNAFU Protection
* *
@@ -3871,6 +3654,8 @@
*/ */
//#define DISABLE_DRIVER_SAFE_POWER_PROTECT //#define DISABLE_DRIVER_SAFE_POWER_PROTECT
// @section cnc
/** /**
* CNC Coordinate Systems * CNC Coordinate Systems
* *
@@ -3879,6 +3664,8 @@
*/ */
//#define CNC_COORDINATE_SYSTEMS //#define CNC_COORDINATE_SYSTEMS
// @section reporting
/** /**
* Auto-report fan speed with M123 S<seconds> * Auto-report fan speed with M123 S<seconds>
* Requires fans with tachometer pins * Requires fans with tachometer pins
@@ -3906,6 +3693,8 @@
//#define M115_GEOMETRY_REPORT //#define M115_GEOMETRY_REPORT
#endif #endif
// @section security
/** /**
* Expected Printer Check * Expected Printer Check
* Add the M16 G-code to compare a string to the MACHINE_NAME. * Add the M16 G-code to compare a string to the MACHINE_NAME.
@@ -3913,6 +3702,8 @@
*/ */
//#define EXPECTED_PRINTER_CHECK //#define EXPECTED_PRINTER_CHECK
// @section volumetrics
/** /**
* Disable all Volumetric extrusion options * Disable all Volumetric extrusion options
*/ */
@@ -3941,14 +3732,7 @@
#endif #endif
#endif #endif
/** // @section reporting
* Enable this option for a leaner build of Marlin that removes all
* workspace offsets, simplifying coordinate transformations, leveling, etc.
*
* - M206 and M428 are disabled.
* - G92 will revert to its behavior from Marlin 1.0.
*/
//#define NO_WORKSPACE_OFFSETS
// Extra options for the M114 "Current Position" report // Extra options for the M114 "Current Position" report
//#define M114_DETAIL // Use 'M114` for details to check planner calculations //#define M114_DETAIL // Use 'M114` for details to check planner calculations
@@ -3957,6 +3741,8 @@
//#define REPORT_FAN_CHANGE // Report the new fan speed when changed by M106 (and others) //#define REPORT_FAN_CHANGE // Report the new fan speed when changed by M106 (and others)
// @section gcode
/** /**
* Spend 28 bytes of SRAM to optimize the G-code parser * Spend 28 bytes of SRAM to optimize the G-code parser
*/ */
@@ -3974,6 +3760,15 @@
//#define REPETIER_GCODE_M360 // Add commands originally from Repetier FW //#define REPETIER_GCODE_M360 // Add commands originally from Repetier FW
/**
* Enable this option for a leaner build of Marlin that removes all
* workspace offsets, simplifying coordinate transformations, leveling, etc.
*
* - M206 and M428 are disabled.
* - G92 will revert to its behavior from Marlin 1.0.
*/
//#define NO_WORKSPACE_OFFSETS
/** /**
* CNC G-code options * CNC G-code options
* Support CNC-style G-code dialects used by laser cutters, drawing machine cams, etc. * Support CNC-style G-code dialects used by laser cutters, drawing machine cams, etc.
@@ -3989,6 +3784,8 @@
//#define VARIABLE_G0_FEEDRATE // The G0 feedrate is set by F in G0 motion mode //#define VARIABLE_G0_FEEDRATE // The G0 feedrate is set by F in G0 motion mode
#endif #endif
// @section gcode
/** /**
* Startup commands * Startup commands
* *
@@ -4013,6 +3810,8 @@
* Up to 25 may be defined, but the actual number is LCD-dependent. * Up to 25 may be defined, but the actual number is LCD-dependent.
*/ */
// @section custom main menu
// Custom Menu: Main Menu // Custom Menu: Main Menu
//#define CUSTOM_MENU_MAIN //#define CUSTOM_MENU_MAIN
#if ENABLED(CUSTOM_MENU_MAIN) #if ENABLED(CUSTOM_MENU_MAIN)
@@ -4043,6 +3842,8 @@
//#define MAIN_MENU_ITEM_5_CONFIRM //#define MAIN_MENU_ITEM_5_CONFIRM
#endif #endif
// @section custom config menu
// Custom Menu: Configuration Menu // Custom Menu: Configuration Menu
//#define CUSTOM_MENU_CONFIG //#define CUSTOM_MENU_CONFIG
#if ENABLED(CUSTOM_MENU_CONFIG) #if ENABLED(CUSTOM_MENU_CONFIG)
@@ -4073,6 +3874,8 @@
//#define CONFIG_MENU_ITEM_5_CONFIRM //#define CONFIG_MENU_ITEM_5_CONFIRM
#endif #endif
// @section custom buttons
/** /**
* User-defined buttons to run custom G-code. * User-defined buttons to run custom G-code.
* Up to 25 may be defined. * Up to 25 may be defined.
@@ -4104,6 +3907,8 @@
#endif #endif
#endif #endif
// @section host
/** /**
* Host Action Commands * Host Action Commands
* *
@@ -4129,6 +3934,8 @@
//#define HOST_SHUTDOWN_MENU_ITEM // Add a menu item that tells the host to shut down //#define HOST_SHUTDOWN_MENU_ITEM // Add a menu item that tells the host to shut down
#endif #endif
// @section extras
/** /**
* Cancel Objects * Cancel Objects
* *
@@ -4150,6 +3957,7 @@
* Alternative Supplier: https://reliabuild3d.com/ * Alternative Supplier: https://reliabuild3d.com/
* *
* Reliabuild encoders have been modified to improve reliability. * Reliabuild encoders have been modified to improve reliability.
* @section i2c encoders
*/ */
//#define I2C_POSITION_ENCODERS //#define I2C_POSITION_ENCODERS
@@ -4221,6 +4029,7 @@
/** /**
* Analog Joystick(s) * Analog Joystick(s)
* @section joystick
*/ */
//#define JOYSTICK //#define JOYSTICK
#if ENABLED(JOYSTICK) #if ENABLED(JOYSTICK)
@@ -4245,6 +4054,7 @@
* Modern replacement for the Prusa TMC_Z_CALIBRATION. * Modern replacement for the Prusa TMC_Z_CALIBRATION.
* Adds capability to work with any adjustable current drivers. * Adds capability to work with any adjustable current drivers.
* Implemented as G34 because M915 is deprecated. * Implemented as G34 because M915 is deprecated.
* @section calibrate
*/ */
//#define MECHANICAL_GANTRY_CALIBRATION //#define MECHANICAL_GANTRY_CALIBRATION
#if ENABLED(MECHANICAL_GANTRY_CALIBRATION) #if ENABLED(MECHANICAL_GANTRY_CALIBRATION)
@@ -4262,6 +4072,7 @@
/** /**
* Instant freeze / unfreeze functionality * Instant freeze / unfreeze functionality
* Potentially useful for emergency stop that allows being resumed. * Potentially useful for emergency stop that allows being resumed.
* @section interface
*/ */
//#define FREEZE_FEATURE //#define FREEZE_FEATURE
#if ENABLED(FREEZE_FEATURE) #if ENABLED(FREEZE_FEATURE)
@@ -4274,6 +4085,7 @@
* *
* Add support for a low-cost 8x8 LED Matrix based on the Max7219 chip as a realtime status display. * Add support for a low-cost 8x8 LED Matrix based on the Max7219 chip as a realtime status display.
* Requires 3 signal wires. Some useful debug options are included to demonstrate its usage. * Requires 3 signal wires. Some useful debug options are included to demonstrate its usage.
* @section debug matrix
*/ */
//#define MAX7219_DEBUG //#define MAX7219_DEBUG
#if ENABLED(MAX7219_DEBUG) #if ENABLED(MAX7219_DEBUG)
@@ -4286,7 +4098,8 @@
#define MAX7219_NUMBER_UNITS 1 // Number of Max7219 units in chain. #define MAX7219_NUMBER_UNITS 1 // Number of Max7219 units in chain.
#define MAX7219_ROTATE 0 // Rotate the display clockwise (in multiples of +/- 90°) #define MAX7219_ROTATE 0 // Rotate the display clockwise (in multiples of +/- 90°)
// connector at: right=0 bottom=-90 top=90 left=180 // connector at: right=0 bottom=-90 top=90 left=180
//#define MAX7219_REVERSE_ORDER // The individual LED matrix units may be in reversed order //#define MAX7219_REVERSE_ORDER // The order of the LED matrix units may be reversed
//#define MAX7219_REVERSE_EACH // The LEDs in each matrix unit row may be reversed
//#define MAX7219_SIDE_BY_SIDE // Big chip+matrix boards can be chained side-by-side //#define MAX7219_SIDE_BY_SIDE // Big chip+matrix boards can be chained side-by-side
/** /**
@@ -4294,12 +4107,15 @@
* If you add more debug displays, be careful to avoid conflicts! * If you add more debug displays, be careful to avoid conflicts!
*/ */
#define MAX7219_DEBUG_PRINTER_ALIVE // Blink corner LED of 8x8 matrix to show that the firmware is functioning #define MAX7219_DEBUG_PRINTER_ALIVE // Blink corner LED of 8x8 matrix to show that the firmware is functioning
#define MAX7219_DEBUG_PLANNER_HEAD 3 // Show the planner queue head position on this and the next LED matrix row #define MAX7219_DEBUG_PLANNER_HEAD 2 // Show the planner queue head position on this and the next LED matrix row
#define MAX7219_DEBUG_PLANNER_TAIL 5 // Show the planner queue tail position on this and the next LED matrix row #define MAX7219_DEBUG_PLANNER_TAIL 4 // Show the planner queue tail position on this and the next LED matrix row
#define MAX7219_DEBUG_PLANNER_QUEUE 0 // Show the current planner queue depth on this and the next LED matrix row #define MAX7219_DEBUG_PLANNER_QUEUE 0 // Show the current planner queue depth on this and the next LED matrix row
// If you experience stuttering, reboots, etc. this option can reveal how // If you experience stuttering, reboots, etc. this option can reveal how
// tweaks made to the configuration are affecting the printer in real-time. // tweaks made to the configuration are affecting the printer in real-time.
#define MAX7219_DEBUG_PROFILE 6 // Display the fraction of CPU time spent in profiled code on this LED matrix
// row. By default idle() is profiled so this shows how "idle" the processor is.
// See class CodeProfiler.
#endif #endif
/** /**
@@ -4308,6 +4124,7 @@
* Support for Synchronized Z moves when used with NanoDLP. G0/G1 axis moves will * Support for Synchronized Z moves when used with NanoDLP. G0/G1 axis moves will
* output a "Z_move_comp" string to enable synchronization with DLP projector exposure. * output a "Z_move_comp" string to enable synchronization with DLP projector exposure.
* This feature allows you to use [[WaitForDoneMessage]] instead of M400 commands. * This feature allows you to use [[WaitForDoneMessage]] instead of M400 commands.
* @section nanodlp
*/ */
//#define NANODLP_Z_SYNC //#define NANODLP_Z_SYNC
#if ENABLED(NANODLP_Z_SYNC) #if ENABLED(NANODLP_Z_SYNC)
@@ -4316,6 +4133,7 @@
/** /**
* Ethernet. Use M552 to enable and set the IP address. * Ethernet. Use M552 to enable and set the IP address.
* @section network
*/ */
#if HAS_ETHERNET #if HAS_ETHERNET
#define MAC_ADDRESS { 0xDE, 0xAD, 0xBE, 0xEF, 0xF0, 0x0D } // A MAC address unique to your network #define MAC_ADDRESS { 0xDE, 0xAD, 0xBE, 0xEF, 0xF0, 0x0D } // A MAC address unique to your network
@@ -4343,6 +4161,8 @@
//#include "Configuration_Secure.h" // External file with WiFi SSID / Password //#include "Configuration_Secure.h" // External file with WiFi SSID / Password
#endif #endif
// @section multi-material
/** /**
* Průša Multi-Material Unit (MMU) * Průša Multi-Material Unit (MMU)
* Enable in Configuration.h * Enable in Configuration.h
@@ -4448,6 +4268,7 @@
/** /**
* Advanced Print Counter settings * Advanced Print Counter settings
* @section stats
*/ */
#if ENABLED(PRINTCOUNTER) #if ENABLED(PRINTCOUNTER)
#define SERVICE_WARNING_BUZZES 3 #define SERVICE_WARNING_BUZZES 3
@@ -4477,6 +4298,9 @@
// //
//#define PINS_DEBUGGING //#define PINS_DEBUGGING
// Enable Tests that will run at startup and produce a report
//#define MARLIN_TEST_BUILD
// Enable Marlin dev mode which adds some special commands // Enable Marlin dev mode which adds some special commands
//#define MARLIN_DEV_MODE //#define MARLIN_DEV_MODE

View File

@@ -109,7 +109,7 @@ LIQUID_TWI2 ?= 0
# This defines if Wire is needed # This defines if Wire is needed
WIRE ?= 0 WIRE ?= 0
# This defines if Tone is needed (i.e SPEAKER is defined in Configuration.h) # This defines if Tone is needed (i.e., SPEAKER is defined in Configuration.h)
# Disabling this (and SPEAKER) saves approximately 350 bytes of memory. # Disabling this (and SPEAKER) saves approximately 350 bytes of memory.
TONE ?= 1 TONE ?= 1
@@ -317,123 +317,10 @@ else ifeq ($(HARDWARE_MOTHERBOARD),1159)
else ifeq ($(HARDWARE_MOTHERBOARD),1160) else ifeq ($(HARDWARE_MOTHERBOARD),1160)
# Longer LKx PRO / Alfawise Uxx Pro (PRO version) # Longer LKx PRO / Alfawise Uxx Pro (PRO version)
else ifeq ($(HARDWARE_MOTHERBOARD),1161) else ifeq ($(HARDWARE_MOTHERBOARD),1161)
# Zonestar zrib V5.3 (Chinese RAMPS replica)
else ifeq ($(HARDWARE_MOTHERBOARD),1162)
# 3Drag Controller # Pxmalion Core I3
else ifeq ($(HARDWARE_MOTHERBOARD),1100) else ifeq ($(HARDWARE_MOTHERBOARD),1163)
# Velleman K8200 Controller (derived from 3Drag Controller)
else ifeq ($(HARDWARE_MOTHERBOARD),1101)
# Velleman K8400 Controller (derived from 3Drag Controller)
else ifeq ($(HARDWARE_MOTHERBOARD),1102)
# Velleman K8600 Controller (Vertex Nano)
else ifeq ($(HARDWARE_MOTHERBOARD),1103)
# Velleman K8800 Controller (Vertex Delta)
else ifeq ($(HARDWARE_MOTHERBOARD),1104)
# 2PrintBeta BAM&DICE with STK drivers
else ifeq ($(HARDWARE_MOTHERBOARD),1105)
# 2PrintBeta BAM&DICE Due with STK drivers
else ifeq ($(HARDWARE_MOTHERBOARD),1106)
# MKS BASE v1.0
else ifeq ($(HARDWARE_MOTHERBOARD),1107)
# MKS v1.4 with A4982 stepper drivers
else ifeq ($(HARDWARE_MOTHERBOARD),1108)
# MKS v1.5 with Allegro A4982 stepper drivers
else ifeq ($(HARDWARE_MOTHERBOARD),1109)
# MKS v1.6 with Allegro A4982 stepper drivers
else ifeq ($(HARDWARE_MOTHERBOARD),1110)
# MKS BASE 1.0 with Heroic HR4982 stepper drivers
else ifeq ($(HARDWARE_MOTHERBOARD),1111)
# MKS GEN v1.3 or 1.4
else ifeq ($(HARDWARE_MOTHERBOARD),1112)
# MKS GEN L
else ifeq ($(HARDWARE_MOTHERBOARD),1113)
# zrib V2.0 control board (Chinese RAMPS replica)
else ifeq ($(HARDWARE_MOTHERBOARD),1114)
# BigTreeTech or BIQU KFB2.0
else ifeq ($(HARDWARE_MOTHERBOARD),1115)
# Felix 2.0+ Electronics Board (RAMPS like)
else ifeq ($(HARDWARE_MOTHERBOARD),1116)
# Invent-A-Part RigidBoard
else ifeq ($(HARDWARE_MOTHERBOARD),1117)
# Invent-A-Part RigidBoard V2
else ifeq ($(HARDWARE_MOTHERBOARD),1118)
# Sainsmart 2-in-1 board
else ifeq ($(HARDWARE_MOTHERBOARD),1119)
# Ultimaker
else ifeq ($(HARDWARE_MOTHERBOARD),1120)
# Ultimaker (Older electronics. Pre 1.5.4. This is rare)
else ifeq ($(HARDWARE_MOTHERBOARD),1121)
MCU ?= atmega1280
PROG_MCU ?= m1280
# Azteeg X3
else ifeq ($(HARDWARE_MOTHERBOARD),1122)
# Azteeg X3 Pro
else ifeq ($(HARDWARE_MOTHERBOARD),1123)
# Ultimainboard 2.x (Uses TEMP_SENSOR 20)
else ifeq ($(HARDWARE_MOTHERBOARD),1124)
# Rumba
else ifeq ($(HARDWARE_MOTHERBOARD),1125)
# Raise3D Rumba
else ifeq ($(HARDWARE_MOTHERBOARD),1126)
# Rapide Lite RL200 Rumba
else ifeq ($(HARDWARE_MOTHERBOARD),1127)
# Formbot T-Rex 2 Plus
else ifeq ($(HARDWARE_MOTHERBOARD),1128)
# Formbot T-Rex 3
else ifeq ($(HARDWARE_MOTHERBOARD),1129)
# Formbot Raptor
else ifeq ($(HARDWARE_MOTHERBOARD),1130)
# Formbot Raptor 2
else ifeq ($(HARDWARE_MOTHERBOARD),1131)
# bq ZUM Mega 3D
else ifeq ($(HARDWARE_MOTHERBOARD),1132)
# MakeBoard Mini v2.1.2 is a control board sold by MicroMake
else ifeq ($(HARDWARE_MOTHERBOARD),1133)
# TriGorilla Anycubic version 1.3 based on RAMPS EFB
else ifeq ($(HARDWARE_MOTHERBOARD),1134)
# TriGorilla Anycubic version 1.4 based on RAMPS EFB
else ifeq ($(HARDWARE_MOTHERBOARD),1135)
# TriGorilla Anycubic version 1.4 Rev 1.1
else ifeq ($(HARDWARE_MOTHERBOARD),1136)
# Creality: Ender-4, CR-8
else ifeq ($(HARDWARE_MOTHERBOARD),1137)
# Creality: CR10S, CR20, CR-X
else ifeq ($(HARDWARE_MOTHERBOARD),1138)
# Dagoma F5
else ifeq ($(HARDWARE_MOTHERBOARD),1139)
# FYSETC F6 1.3
else ifeq ($(HARDWARE_MOTHERBOARD),1140)
# FYSETC F6 1.5
else ifeq ($(HARDWARE_MOTHERBOARD),1141)
# Duplicator i3 Plus
else ifeq ($(HARDWARE_MOTHERBOARD),1142)
# VORON
else ifeq ($(HARDWARE_MOTHERBOARD),1143)
# TRONXY V3 1.0
else ifeq ($(HARDWARE_MOTHERBOARD),1144)
# Z-Bolt X Series
else ifeq ($(HARDWARE_MOTHERBOARD),1145)
# TT OSCAR
else ifeq ($(HARDWARE_MOTHERBOARD),1146)
# Overlord/Overlord Pro
else ifeq ($(HARDWARE_MOTHERBOARD),1147)
# ADIMLab Gantry v1
else ifeq ($(HARDWARE_MOTHERBOARD),1148)
# ADIMLab Gantry v2
else ifeq ($(HARDWARE_MOTHERBOARD),1149)
# BIQU Tango V1
else ifeq ($(HARDWARE_MOTHERBOARD),1150)
# MKS GEN L V2
else ifeq ($(HARDWARE_MOTHERBOARD),1151)
# MKS GEN L V2.1
else ifeq ($(HARDWARE_MOTHERBOARD),1152)
# Copymaster 3D
else ifeq ($(HARDWARE_MOTHERBOARD),1153)
# Ortur 4
else ifeq ($(HARDWARE_MOTHERBOARD),1154)
# Tenlog D3 Hero
else ifeq ($(HARDWARE_MOTHERBOARD),1155)
# #
# RAMBo and derivatives # RAMBo and derivatives

View File

@@ -28,7 +28,7 @@
/** /**
* Marlin release version identifier * Marlin release version identifier
*/ */
//#define SHORT_BUILD_VERSION "2.1.0.2" //#define SHORT_BUILD_VERSION "2.1.1.2"
/** /**
* Verbose version identifier which should contain a reference to the location * Verbose version identifier which should contain a reference to the location

211
Marlin/config.ini Normal file
View File

@@ -0,0 +1,211 @@
#
# Marlin Firmware
# config.ini - Options to apply before the build
#
[config:base]
ini_use_config = none
# Load all config: sections in this file
;ini_use_config = all
# Load config file relative to Marlin/
;ini_use_config = another.ini
# Download configurations from GitHub
;ini_use_config = example/Creality/Ender-5 Plus @ bugfix-2.1.x
# Download configurations from your server
;ini_use_config = https://me.myserver.com/path/to/configs
# Evaluate config:base and do a config dump
;ini_use_config = base
;config_export = 2
[config:minimal]
motherboard = BOARD_RAMPS_14_EFB
serial_port = 0
baudrate = 250000
use_watchdog = on
thermal_protection_hotends = on
thermal_protection_hysteresis = 4
thermal_protection_period = 40
bufsize = 4
block_buffer_size = 16
max_cmd_size = 96
extruders = 1
temp_sensor_0 = 1
temp_hysteresis = 3
heater_0_mintemp = 5
heater_0_maxtemp = 275
preheat_1_temp_hotend = 180
bang_max = 255
pidtemp = on
pid_k1 = 0.95
pid_max = BANG_MAX
pid_functional_range = 10
default_kp = 22.20
default_ki = 1.08
default_kd = 114.00
x_driver_type = A4988
y_driver_type = A4988
z_driver_type = A4988
e0_driver_type = A4988
x_bed_size = 200
x_min_pos = 0
x_max_pos = X_BED_SIZE
y_bed_size = 200
y_min_pos = 0
y_max_pos = Y_BED_SIZE
z_min_pos = 0
z_max_pos = 200
x_home_dir = -1
y_home_dir = -1
z_home_dir = -1
use_xmin_plug = on
use_ymin_plug = on
use_zmin_plug = on
x_min_endstop_inverting = false
y_min_endstop_inverting = false
z_min_endstop_inverting = false
default_axis_steps_per_unit = { 80, 80, 400, 500 }
axis_relative_modes = { false, false, false, false }
default_max_feedrate = { 300, 300, 5, 25 }
default_max_acceleration = { 3000, 3000, 100, 10000 }
homing_feedrate_mm_m = { (50*60), (50*60), (4*60) }
homing_bump_divisor = { 2, 2, 4 }
x_enable_on = 0
y_enable_on = 0
z_enable_on = 0
e_enable_on = 0
invert_x_dir = false
invert_y_dir = true
invert_z_dir = false
invert_e0_dir = false
invert_e_step_pin = false
invert_x_step_pin = false
invert_y_step_pin = false
invert_z_step_pin = false
disable_x = false
disable_y = false
disable_z = false
disable_e = false
proportional_font_ratio = 1.0
default_nominal_filament_dia = 1.75
junction_deviation_mm = 0.013
default_acceleration = 3000
default_travel_acceleration = 3000
default_retract_acceleration = 3000
default_minimumfeedrate = 0.0
default_mintravelfeedrate = 0.0
minimum_planner_speed = 0.05
min_steps_per_segment = 6
default_minsegmenttime = 20000
[config:basic]
bed_overshoot = 10
busy_while_heating = on
default_ejerk = 5.0
default_keepalive_interval = 2
default_leveling_fade_height = 0.0
disable_inactive_extruder = on
display_charset_hd44780 = JAPANESE
eeprom_boot_silent = on
eeprom_chitchat = on
endstoppullups = on
extrude_maxlength = 200
extrude_mintemp = 170
host_keepalive_feature = on
hotend_overshoot = 15
jd_handle_small_segments = on
lcd_info_screen_style = 0
lcd_language = en
max_bed_power = 255
mesh_inset = 0
min_software_endstops = on
max_software_endstops = on
min_software_endstop_x = on
min_software_endstop_y = on
min_software_endstop_z = on
max_software_endstop_x = on
max_software_endstop_y = on
max_software_endstop_z = on
preheat_1_fan_speed = 0
preheat_1_label = "PLA"
preheat_1_temp_bed = 70
prevent_cold_extrusion = on
prevent_lengthy_extrude = on
printjob_timer_autostart = on
probing_margin = 10
show_bootscreen = on
soft_pwm_scale = 0
string_config_h_author = "(none, default config)"
temp_bed_hysteresis = 3
temp_bed_residency_time = 10
temp_bed_window = 1
temp_residency_time = 10
temp_window = 1
validate_homing_endstops = on
xy_probe_feedrate = (133*60)
z_clearance_between_probes = 5
z_clearance_deploy_probe = 10
z_clearance_multi_probe = 5
[config:advanced]
arc_support = on
auto_report_temperatures = on
autotemp = on
autotemp_oldweight = 0.98
bed_check_interval = 5000
default_stepper_deactive_time = 120
default_volumetric_extruder_limit = 0.00
disable_inactive_e = true
disable_inactive_x = true
disable_inactive_y = true
disable_inactive_z = true
e0_auto_fan_pin = -1
encoder_100x_steps_per_sec = 80
encoder_10x_steps_per_sec = 30
encoder_rate_multiplier = on
extended_capabilities_report = on
extruder_auto_fan_speed = 255
extruder_auto_fan_temperature = 50
fanmux0_pin = -1
fanmux1_pin = -1
fanmux2_pin = -1
faster_gcode_parser = on
homing_bump_mm = { 5, 5, 2 }
max_arc_segment_mm = 1.0
min_arc_segment_mm = 0.1
min_circle_segments = 72
n_arc_correction = 25
serial_overrun_protection = on
slowdown = on
slowdown_divisor = 2
temp_sensor_bed = 0
thermal_protection_bed_hysteresis = 2
thermocouple_max_errors = 15
tx_buffer_size = 0
watch_bed_temp_increase = 2
watch_bed_temp_period = 60
watch_temp_increase = 2
watch_temp_period = 20

View File

@@ -66,27 +66,26 @@ static volatile int8_t Channel[_Nbr_16timers]; // counter for the s
/************ static functions common to all instances ***********************/ /************ static functions common to all instances ***********************/
static inline void handle_interrupts(timer16_Sequence_t timer, volatile uint16_t* TCNTn, volatile uint16_t* OCRnA) { static inline void handle_interrupts(const timer16_Sequence_t timer, volatile uint16_t* TCNTn, volatile uint16_t* OCRnA) {
if (Channel[timer] < 0) int8_t cho = Channel[timer]; // Handle the prior Channel[timer] first
*TCNTn = 0; // channel set to -1 indicated that refresh interval completed so reset the timer if (cho < 0) // Channel -1 indicates the refresh interval completed...
else { *TCNTn = 0; // ...so reset the timer
if (SERVO_INDEX(timer, Channel[timer]) < ServoCount && SERVO(timer, Channel[timer]).Pin.isActive) else if (SERVO_INDEX(timer, cho) < ServoCount) // prior channel handled?
extDigitalWrite(SERVO(timer, Channel[timer]).Pin.nbr, LOW); // pulse this channel low if activated extDigitalWrite(SERVO(timer, cho).Pin.nbr, LOW); // pulse the prior channel LOW
}
Channel[timer]++; // increment to the next channel Channel[timer] = ++cho; // Handle the next channel (or 0)
if (SERVO_INDEX(timer, Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) { if (cho < SERVOS_PER_TIMER && SERVO_INDEX(timer, cho) < ServoCount) {
*OCRnA = *TCNTn + SERVO(timer, Channel[timer]).ticks; *OCRnA = *TCNTn + SERVO(timer, cho).ticks; // set compare to current ticks plus duration
if (SERVO(timer, Channel[timer]).Pin.isActive) // check if activated if (SERVO(timer, cho).Pin.isActive) // activated?
extDigitalWrite(SERVO(timer, Channel[timer]).Pin.nbr, HIGH); // it's an active channel so pulse it high extDigitalWrite(SERVO(timer, cho).Pin.nbr, HIGH); // yes: pulse HIGH
} }
else { else {
// finished all channels so wait for the refresh period to expire before starting over // finished all channels so wait for the refresh period to expire before starting over
if (((unsigned)*TCNTn) + 4 < usToTicks(REFRESH_INTERVAL)) // allow a few ticks to ensure the next OCR1A not missed const unsigned int cval = ((unsigned)*TCNTn) + 32 / (SERVO_TIMER_PRESCALER), // allow 32 cycles to ensure the next OCR1A not missed
*OCRnA = (unsigned int)usToTicks(REFRESH_INTERVAL); ival = (unsigned int)usToTicks(REFRESH_INTERVAL); // at least REFRESH_INTERVAL has elapsed
else *OCRnA = max(cval, ival);
*OCRnA = *TCNTn + 4; // at least REFRESH_INTERVAL has elapsed
Channel[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel Channel[timer] = -1; // reset the timer counter to 0 on the next call
} }
} }
@@ -123,91 +122,102 @@ static inline void handle_interrupts(timer16_Sequence_t timer, volatile uint16_t
/****************** end of static functions ******************************/ /****************** end of static functions ******************************/
void initISR(timer16_Sequence_t timer) { void initISR(const timer16_Sequence_t timer_index) {
#ifdef _useTimer1 switch (timer_index) {
if (timer == _timer1) { default: break;
TCCR1A = 0; // normal counting mode
TCCR1B = _BV(CS11); // set prescaler of 8
TCNT1 = 0; // clear the timer count
#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__)
SBI(TIFR, OCF1A); // clear any pending interrupts;
SBI(TIMSK, OCIE1A); // enable the output compare interrupt
#else
// here if not ATmega8 or ATmega128
SBI(TIFR1, OCF1A); // clear any pending interrupts;
SBI(TIMSK1, OCIE1A); // enable the output compare interrupt
#endif
#ifdef WIRING
timerAttach(TIMER1OUTCOMPAREA_INT, Timer1Service);
#endif
}
#endif
#ifdef _useTimer3 #ifdef _useTimer1
if (timer == _timer3) { case _timer1:
TCCR3A = 0; // normal counting mode TCCR1A = 0; // normal counting mode
TCCR3B = _BV(CS31); // set prescaler of 8 TCCR1B = _BV(CS11); // set prescaler of 8
TCNT3 = 0; // clear the timer count TCNT1 = 0; // clear the timer count
#ifdef __AVR_ATmega128__ #if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__)
SBI(TIFR, OCF3A); // clear any pending interrupts; SBI(TIFR, OCF1A); // clear any pending interrupts;
SBI(ETIMSK, OCIE3A); // enable the output compare interrupt SBI(TIMSK, OCIE1A); // enable the output compare interrupt
#else #else
SBI(TIFR3, OCF3A); // clear any pending interrupts; // here if not ATmega8 or ATmega128
SBI(TIMSK3, OCIE3A); // enable the output compare interrupt SBI(TIFR1, OCF1A); // clear any pending interrupts;
#endif SBI(TIMSK1, OCIE1A); // enable the output compare interrupt
#ifdef WIRING #endif
timerAttach(TIMER3OUTCOMPAREA_INT, Timer3Service); // for Wiring platform only #ifdef WIRING
#endif timerAttach(TIMER1OUTCOMPAREA_INT, Timer1Service);
} #endif
#endif break;
#endif
#ifdef _useTimer4 #ifdef _useTimer3
if (timer == _timer4) { case _timer3:
TCCR4A = 0; // normal counting mode TCCR3A = 0; // normal counting mode
TCCR4B = _BV(CS41); // set prescaler of 8 TCCR3B = _BV(CS31); // set prescaler of 8
TCNT4 = 0; // clear the timer count TCNT3 = 0; // clear the timer count
TIFR4 = _BV(OCF4A); // clear any pending interrupts; #ifdef __AVR_ATmega128__
TIMSK4 = _BV(OCIE4A); // enable the output compare interrupt SBI(TIFR, OCF3A); // clear any pending interrupts;
} SBI(ETIMSK, OCIE3A); // enable the output compare interrupt
#endif #else
SBI(TIFR3, OCF3A); // clear any pending interrupts;
SBI(TIMSK3, OCIE3A); // enable the output compare interrupt
#endif
#ifdef WIRING
timerAttach(TIMER3OUTCOMPAREA_INT, Timer3Service); // for Wiring platform only
#endif
break;
#endif
#ifdef _useTimer5 #ifdef _useTimer4
if (timer == _timer5) { case _timer4:
TCCR5A = 0; // normal counting mode TCCR4A = 0; // normal counting mode
TCCR5B = _BV(CS51); // set prescaler of 8 TCCR4B = _BV(CS41); // set prescaler of 8
TCNT5 = 0; // clear the timer count TCNT4 = 0; // clear the timer count
TIFR5 = _BV(OCF5A); // clear any pending interrupts; TIFR4 = _BV(OCF4A); // clear any pending interrupts;
TIMSK5 = _BV(OCIE5A); // enable the output compare interrupt TIMSK4 = _BV(OCIE4A); // enable the output compare interrupt
} break;
#endif #endif
#ifdef _useTimer5
case _timer5:
TCCR5A = 0; // normal counting mode
TCCR5B = _BV(CS51); // set prescaler of 8
TCNT5 = 0; // clear the timer count
TIFR5 = _BV(OCF5A); // clear any pending interrupts;
TIMSK5 = _BV(OCIE5A); // enable the output compare interrupt
break;
#endif
}
} }
void finISR(timer16_Sequence_t timer) { void finISR(const timer16_Sequence_t timer_index) {
// Disable use of the given timer // Disable use of the given timer
#ifdef WIRING #ifdef WIRING
if (timer == _timer1) { switch (timer_index) {
CBI( default: break;
#if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__)
TIMSK1 case _timer1:
#else CBI(
TIMSK #if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__)
#endif TIMSK1
, OCIE1A); // disable timer 1 output compare interrupt #else
timerDetach(TIMER1OUTCOMPAREA_INT); TIMSK
} #endif
else if (timer == _timer3) { , OCIE1A // disable timer 1 output compare interrupt
CBI( );
#if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__) timerDetach(TIMER1OUTCOMPAREA_INT);
TIMSK3 break;
#else
ETIMSK case _timer3:
#endif CBI(
, OCIE3A); // disable the timer3 output compare A interrupt #if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__)
timerDetach(TIMER3OUTCOMPAREA_INT); TIMSK3
#else
ETIMSK
#endif
, OCIE3A // disable the timer3 output compare A interrupt
);
timerDetach(TIMER3OUTCOMPAREA_INT);
break;
} }
#else // !WIRING #else // !WIRING
// For arduino - in future: call here to a currently undefined function to reset the timer // For arduino - in future: call here to a currently undefined function to reset the timer
UNUSED(timer); UNUSED(timer_index);
#endif #endif
} }

View File

@@ -35,11 +35,19 @@
|| X_STEP_PIN == N || Y_STEP_PIN == N || Z_STEP_PIN == N \ || X_STEP_PIN == N || Y_STEP_PIN == N || Z_STEP_PIN == N \
|| X_DIR_PIN == N || Y_DIR_PIN == N || Z_DIR_PIN == N \ || X_DIR_PIN == N || Y_DIR_PIN == N || Z_DIR_PIN == N \
|| X_ENA_PIN == N || Y_ENA_PIN == N || Z_ENA_PIN == N \ || X_ENA_PIN == N || Y_ENA_PIN == N || Z_ENA_PIN == N \
|| BTN_EN1 == N || BTN_EN2 == N \
) )
#if CONF_SERIAL_IS(0) // D0-D1. No known conflicts. #if CONF_SERIAL_IS(0)
// D0-D1. No known conflicts.
#endif #endif
#if CONF_SERIAL_IS(1) && (CHECK_SERIAL_PIN(18) || CHECK_SERIAL_PIN(19)) #if NOT_TARGET(__AVR_ATmega644P__, __AVR_ATmega1284P__)
#error "Serial Port 1 pin D18 and/or D19 conflicts with another pin on the board." #if CONF_SERIAL_IS(1) && (CHECK_SERIAL_PIN(18) || CHECK_SERIAL_PIN(19))
#error "Serial Port 1 pin D18 and/or D19 conflicts with another pin on the board."
#endif
#else
#if CONF_SERIAL_IS(1) && (CHECK_SERIAL_PIN(10) || CHECK_SERIAL_PIN(11))
#error "Serial Port 1 pin D10 and/or D11 conflicts with another pin on the board."
#endif
#endif #endif
#if CONF_SERIAL_IS(2) && (CHECK_SERIAL_PIN(16) || CHECK_SERIAL_PIN(17)) #if CONF_SERIAL_IS(2) && (CHECK_SERIAL_PIN(16) || CHECK_SERIAL_PIN(17))
#error "Serial Port 2 pin D16 and/or D17 conflicts with another pin on the board." #error "Serial Port 2 pin D16 and/or D17 conflicts with another pin on the board."

View File

@@ -47,12 +47,12 @@
#include "../shared/servo.h" #include "../shared/servo.h"
#include "../shared/servo_private.h" #include "../shared/servo_private.h"
static volatile int8_t Channel[_Nbr_16timers]; // counter for the servo being pulsed for each timer (or -1 if refresh interval) static Flags<_Nbr_16timers> DisablePending; // ISR should disable the timer at the next timer reset
// ------------------------ // ------------------------
/// Interrupt handler for the TC0 channel 1. /// Interrupt handler for the TC0 channel 1.
// ------------------------ // ------------------------
void Servo_Handler(timer16_Sequence_t timer, Tc *pTc, uint8_t channel); void Servo_Handler(const timer16_Sequence_t, Tc*, const uint8_t);
#ifdef _useTimer1 #ifdef _useTimer1
void HANDLER_FOR_TIMER1() { Servo_Handler(_timer1, TC_FOR_TIMER1, CHANNEL_FOR_TIMER1); } void HANDLER_FOR_TIMER1() { Servo_Handler(_timer1, TC_FOR_TIMER1, CHANNEL_FOR_TIMER1); }
@@ -70,88 +70,92 @@ void Servo_Handler(timer16_Sequence_t timer, Tc *pTc, uint8_t channel);
void HANDLER_FOR_TIMER5() { Servo_Handler(_timer5, TC_FOR_TIMER5, CHANNEL_FOR_TIMER5); } void HANDLER_FOR_TIMER5() { Servo_Handler(_timer5, TC_FOR_TIMER5, CHANNEL_FOR_TIMER5); }
#endif #endif
void Servo_Handler(timer16_Sequence_t timer, Tc *tc, uint8_t channel) { void Servo_Handler(const timer16_Sequence_t timer, Tc *tc, const uint8_t channel) {
// clear interrupt static int8_t Channel[_Nbr_16timers]; // Servo counters to pulse (or -1 for refresh interval)
tc->TC_CHANNEL[channel].TC_SR; int8_t cho = Channel[timer]; // Handle the prior Channel[timer] first
if (Channel[timer] < 0) if (cho < 0) { // Channel -1 indicates the refresh interval completed...
tc->TC_CHANNEL[channel].TC_CCR |= TC_CCR_SWTRG; // channel set to -1 indicated that refresh interval completed so reset the timer tc->TC_CHANNEL[channel].TC_CCR |= TC_CCR_SWTRG; // ...so reset the timer
else if (SERVO_INDEX(timer, Channel[timer]) < ServoCount && SERVO(timer, Channel[timer]).Pin.isActive) if (DisablePending[timer]) {
extDigitalWrite(SERVO(timer, Channel[timer]).Pin.nbr, LOW); // pulse this channel low if activated // Disabling only after the full servo period expires prevents
// pulses being too close together if immediately re-enabled.
DisablePending.clear(timer);
TC_Stop(tc, channel);
tc->TC_CHANNEL[channel].TC_SR; // clear interrupt
return;
}
}
else if (SERVO_INDEX(timer, cho) < ServoCount) // prior channel handled?
extDigitalWrite(SERVO(timer, cho).Pin.nbr, LOW); // pulse the prior channel LOW
Channel[timer]++; // increment to the next channel Channel[timer] = ++cho; // go to the next channel (or 0)
if (SERVO_INDEX(timer, Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) { if (cho < SERVOS_PER_TIMER && SERVO_INDEX(timer, cho) < ServoCount) {
tc->TC_CHANNEL[channel].TC_RA = tc->TC_CHANNEL[channel].TC_CV + SERVO(timer,Channel[timer]).ticks; tc->TC_CHANNEL[channel].TC_RA = tc->TC_CHANNEL[channel].TC_CV + SERVO(timer, cho).ticks;
if (SERVO(timer,Channel[timer]).Pin.isActive) // check if activated if (SERVO(timer, cho).Pin.isActive) // activated?
extDigitalWrite(SERVO(timer, Channel[timer]).Pin.nbr, HIGH); // its an active channel so pulse it high extDigitalWrite(SERVO(timer, cho).Pin.nbr, HIGH); // yes: pulse HIGH
} }
else { else {
// finished all channels so wait for the refresh period to expire before starting over // finished all channels so wait for the refresh period to expire before starting over
tc->TC_CHANNEL[channel].TC_RA = const unsigned int cval = tc->TC_CHANNEL[channel].TC_CV + 128 / (SERVO_TIMER_PRESCALER), // allow 128 cycles to ensure the next CV not missed
tc->TC_CHANNEL[channel].TC_CV < usToTicks(REFRESH_INTERVAL) - 4 ival = (unsigned int)usToTicks(REFRESH_INTERVAL); // at least REFRESH_INTERVAL has elapsed
? (unsigned int)usToTicks(REFRESH_INTERVAL) // allow a few ticks to ensure the next OCR1A not missed tc->TC_CHANNEL[channel].TC_RA = max(cval, ival);
: tc->TC_CHANNEL[channel].TC_CV + 4; // at least REFRESH_INTERVAL has elapsed
Channel[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel Channel[timer] = -1; // reset the timer CCR on the next call
} }
tc->TC_CHANNEL[channel].TC_SR; // clear interrupt
} }
static void _initISR(Tc *tc, uint32_t channel, uint32_t id, IRQn_Type irqn) { static void _initISR(Tc *tc, uint32_t channel, uint32_t id, IRQn_Type irqn) {
pmc_enable_periph_clk(id); pmc_enable_periph_clk(id);
TC_Configure(tc, channel, TC_Configure(tc, channel,
TC_CMR_TCCLKS_TIMER_CLOCK3 | // MCK/32 TC_CMR_WAVE // Waveform mode
TC_CMR_WAVE | // Waveform mode | TC_CMR_WAVSEL_UP_RC // Counter running up and reset when equal to RC
TC_CMR_WAVSEL_UP_RC ); // Counter running up and reset when equals to RC | (SERVO_TIMER_PRESCALER == 2 ? TC_CMR_TCCLKS_TIMER_CLOCK1 : 0) // MCK/2
| (SERVO_TIMER_PRESCALER == 8 ? TC_CMR_TCCLKS_TIMER_CLOCK2 : 0) // MCK/8
| (SERVO_TIMER_PRESCALER == 32 ? TC_CMR_TCCLKS_TIMER_CLOCK3 : 0) // MCK/32
| (SERVO_TIMER_PRESCALER == 128 ? TC_CMR_TCCLKS_TIMER_CLOCK4 : 0) // MCK/128
);
/* 84MHz, MCK/32, for 1.5ms: 3937 */ // Wait 1ms before the first ISR
TC_SetRA(tc, channel, 2625); // 1ms TC_SetRA(tc, channel, (F_CPU) / (SERVO_TIMER_PRESCALER) / 1000UL); // 1ms
/* Configure and enable interrupt */ // Configure and enable interrupt
NVIC_EnableIRQ(irqn); NVIC_EnableIRQ(irqn);
// TC_IER_CPAS: RA Compare tc->TC_CHANNEL[channel].TC_IER = TC_IER_CPAS; // TC_IER_CPAS: RA Compare
tc->TC_CHANNEL[channel].TC_IER = TC_IER_CPAS;
// Enables the timer clock and performs a software reset to start the counting // Enables the timer clock and performs a software reset to start the counting
TC_Start(tc, channel); TC_Start(tc, channel);
} }
void initISR(timer16_Sequence_t timer) { void initISR(const timer16_Sequence_t timer_index) {
#ifdef _useTimer1 CRITICAL_SECTION_START();
if (timer == _timer1) const bool disable_soon = DisablePending[timer_index];
_initISR(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, ID_TC_FOR_TIMER1, IRQn_FOR_TIMER1); DisablePending.clear(timer_index);
#endif CRITICAL_SECTION_END();
#ifdef _useTimer2
if (timer == _timer2) if (!disable_soon) switch (timer_index) {
_initISR(TC_FOR_TIMER2, CHANNEL_FOR_TIMER2, ID_TC_FOR_TIMER2, IRQn_FOR_TIMER2); default: break;
#endif #ifdef _useTimer1
#ifdef _useTimer3 case _timer1: return _initISR(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, ID_TC_FOR_TIMER1, IRQn_FOR_TIMER1);
if (timer == _timer3) #endif
_initISR(TC_FOR_TIMER3, CHANNEL_FOR_TIMER3, ID_TC_FOR_TIMER3, IRQn_FOR_TIMER3); #ifdef _useTimer2
#endif case _timer2: return _initISR(TC_FOR_TIMER2, CHANNEL_FOR_TIMER2, ID_TC_FOR_TIMER2, IRQn_FOR_TIMER2);
#ifdef _useTimer4 #endif
if (timer == _timer4) #ifdef _useTimer3
_initISR(TC_FOR_TIMER4, CHANNEL_FOR_TIMER4, ID_TC_FOR_TIMER4, IRQn_FOR_TIMER4); case _timer3: return _initISR(TC_FOR_TIMER3, CHANNEL_FOR_TIMER3, ID_TC_FOR_TIMER3, IRQn_FOR_TIMER3);
#endif #endif
#ifdef _useTimer5 #ifdef _useTimer4
if (timer == _timer5) case _timer4: return _initISR(TC_FOR_TIMER4, CHANNEL_FOR_TIMER4, ID_TC_FOR_TIMER4, IRQn_FOR_TIMER4);
_initISR(TC_FOR_TIMER5, CHANNEL_FOR_TIMER5, ID_TC_FOR_TIMER5, IRQn_FOR_TIMER5); #endif
#endif #ifdef _useTimer5
case _timer5: return _initISR(TC_FOR_TIMER5, CHANNEL_FOR_TIMER5, ID_TC_FOR_TIMER5, IRQn_FOR_TIMER5);
#endif
}
} }
void finISR(timer16_Sequence_t) { void finISR(const timer16_Sequence_t timer_index) {
#ifdef _useTimer1 // Timer is disabled from the ISR, to ensure proper final pulse length.
TC_Stop(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1); DisablePending.set(timer_index);
#endif
#ifdef _useTimer2
TC_Stop(TC_FOR_TIMER2, CHANNEL_FOR_TIMER2);
#endif
#ifdef _useTimer3
TC_Stop(TC_FOR_TIMER3, CHANNEL_FOR_TIMER3);
#endif
#ifdef _useTimer4
TC_Stop(TC_FOR_TIMER4, CHANNEL_FOR_TIMER4);
#endif
#ifdef _useTimer5
TC_Stop(TC_FOR_TIMER5, CHANNEL_FOR_TIMER5);
#endif
} }
#endif // HAS_SERVOS #endif // HAS_SERVOS

View File

@@ -37,7 +37,7 @@
#define _useTimer5 #define _useTimer5
#define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays #define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays
#define SERVO_TIMER_PRESCALER 32 // timer prescaler #define SERVO_TIMER_PRESCALER 2 // timer prescaler
/* /*
TC0, chan 0 => TC0_Handler TC0, chan 0 => TC0_Handler

View File

@@ -89,10 +89,17 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
NVIC_SetPriority(irq, timer_config[timer_num].priority); NVIC_SetPriority(irq, timer_config[timer_num].priority);
// wave mode, reset counter on match with RC, // wave mode, reset counter on match with RC,
TC_Configure(tc, channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK1); TC_Configure(tc, channel,
TC_CMR_WAVE
| TC_CMR_WAVSEL_UP_RC
| (HAL_TIMER_PRESCALER == 2 ? TC_CMR_TCCLKS_TIMER_CLOCK1 : 0)
| (HAL_TIMER_PRESCALER == 8 ? TC_CMR_TCCLKS_TIMER_CLOCK2 : 0)
| (HAL_TIMER_PRESCALER == 32 ? TC_CMR_TCCLKS_TIMER_CLOCK3 : 0)
| (HAL_TIMER_PRESCALER == 128 ? TC_CMR_TCCLKS_TIMER_CLOCK4 : 0)
);
// Set compare value // Set compare value
TC_SetRC(tc, channel, VARIANT_MCK / 2 / frequency); TC_SetRC(tc, channel, VARIANT_MCK / (HAL_TIMER_PRESCALER) / frequency);
// And start timer // And start timer
TC_Start(tc, channel); TC_Start(tc, channel);

View File

@@ -35,7 +35,8 @@
typedef uint32_t hal_timer_t; typedef uint32_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFF #define HAL_TIMER_TYPE_MAX 0xFFFFFFFF
#define HAL_TIMER_RATE ((F_CPU) / 2) // frequency of timers peripherals #define HAL_TIMER_PRESCALER 2
#define HAL_TIMER_RATE ((F_CPU) / (HAL_TIMER_PRESCALER)) // frequency of timers peripherals
#ifndef MF_TIMER_STEP #ifndef MF_TIMER_STEP
#define MF_TIMER_STEP 2 // Timer Index for Stepper #define MF_TIMER_STEP 2 // Timer Index for Stepper

View File

@@ -1059,7 +1059,7 @@ static inline void convert_64_bit_to_byte_array(uint64_t value, uint8_t *data)
while (val_index < 8) while (val_index < 8)
{ {
data[val_index++] = value & 0xFF; data[val_index++] = value & 0xFF;
value = value >> 8; value >>= 8;
} }
} }

View File

@@ -65,6 +65,7 @@ portMUX_TYPE MarlinHAL::spinlock = portMUX_INITIALIZER_UNLOCKED;
// ------------------------ // ------------------------
uint16_t MarlinHAL::adc_result; uint16_t MarlinHAL::adc_result;
pwm_pin_t MarlinHAL::pwm_pin_data[MAX_EXPANDER_BITS];
// ------------------------ // ------------------------
// Private Variables // Private Variables
@@ -330,21 +331,46 @@ int8_t get_pwm_channel(const pin_t pin, const uint32_t freq, const uint16_t res)
} }
void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=_BV(PWM_RESOLUTION)-1*/, const bool invert/*=false*/) { void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=_BV(PWM_RESOLUTION)-1*/, const bool invert/*=false*/) {
const int8_t cid = get_pwm_channel(pin, PWM_FREQUENCY, PWM_RESOLUTION); #if ENABLED(I2S_STEPPER_STREAM)
if (cid >= 0) { if (pin > 127) {
uint32_t duty = map(invert ? v_size - v : v, 0, v_size, 0, _BV(PWM_RESOLUTION)-1); const uint8_t pinlo = pin & 0x7F;
ledcWrite(cid, duty); pwm_pin_t &pindata = pwm_pin_data[pinlo];
} const uint32_t duty = map(invert ? v_size - v : v, 0, v_size, 0, pindata.pwm_cycle_ticks);
if (duty == 0 || duty == pindata.pwm_cycle_ticks) { // max or min (i.e., on/off)
pindata.pwm_duty_ticks = 0; // turn off PWM for this pin
duty ? SBI32(i2s_port_data, pinlo) : CBI32(i2s_port_data, pinlo); // set pin level
}
else
pindata.pwm_duty_ticks = duty; // PWM duty count = # of 4µs ticks per full PWM cycle
}
else
#endif
{
const int8_t cid = get_pwm_channel(pin, PWM_FREQUENCY, PWM_RESOLUTION);
if (cid >= 0) {
const uint32_t duty = map(invert ? v_size - v : v, 0, v_size, 0, _BV(PWM_RESOLUTION)-1);
ledcWrite(cid, duty);
}
}
} }
int8_t MarlinHAL::set_pwm_frequency(const pin_t pin, const uint32_t f_desired) { int8_t MarlinHAL::set_pwm_frequency(const pin_t pin, const uint32_t f_desired) {
const int8_t cid = channel_for_pin(pin); #if ENABLED(I2S_STEPPER_STREAM)
if (cid >= 0) { if (pin > 127) {
if (f_desired == ledcReadFreq(cid)) return cid; // no freq change pwm_pin_data[pin & 0x7F].pwm_cycle_ticks = 1000000UL / f_desired / 4; // # of 4µs ticks per full PWM cycle
ledcDetachPin(chan_pin[cid]); return 0;
chan_pin[cid] = 0; // remove old freq channel }
} else
return get_pwm_channel(pin, f_desired, PWM_RESOLUTION); // try for new one #endif
{
const int8_t cid = channel_for_pin(pin);
if (cid >= 0) {
if (f_desired == ledcReadFreq(cid)) return cid; // no freq change
ledcDetachPin(chan_pin[cid]);
chan_pin[cid] = 0; // remove old freq channel
}
return get_pwm_channel(pin, f_desired, PWM_RESOLUTION); // try for new one
}
} }
// use hardware PWM if avail, if not then ISR // use hardware PWM if avail, if not then ISR

View File

@@ -60,14 +60,17 @@
#endif #endif
#endif #endif
#define CRITICAL_SECTION_START() portENTER_CRITICAL(&spinlock) #define CRITICAL_SECTION_START() portENTER_CRITICAL(&hal.spinlock)
#define CRITICAL_SECTION_END() portEXIT_CRITICAL(&spinlock) #define CRITICAL_SECTION_END() portEXIT_CRITICAL(&hal.spinlock)
#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment #define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment
#define PWM_FREQUENCY 1000u // Default PWM frequency when set_pwm_duty() is called without set_pwm_frequency() #define PWM_FREQUENCY 1000u // Default PWM frequency when set_pwm_duty() is called without set_pwm_frequency()
#define PWM_RESOLUTION 10u // Default PWM bit resolution #define PWM_RESOLUTION 10u // Default PWM bit resolution
#define CHANNEL_MAX_NUM 15u // max PWM channel # to allocate (7 to only use low speed, 15 to use low & high) #define CHANNEL_MAX_NUM 15u // max PWM channel # to allocate (7 to only use low speed, 15 to use low & high)
#define MAX_PWM_IOPIN 33u // hardware pwm pins < 34 #define MAX_PWM_IOPIN 33u // hardware pwm pins < 34
#ifndef MAX_EXPANDER_BITS
#define MAX_EXPANDER_BITS 32 // I2S expander bit width (max 32)
#endif
// ------------------------ // ------------------------
// Types // Types
@@ -76,6 +79,12 @@
typedef double isr_float_t; // FPU ops are used for single-precision, so use double for ISRs. typedef double isr_float_t; // FPU ops are used for single-precision, so use double for ISRs.
typedef int16_t pin_t; typedef int16_t pin_t;
typedef struct pwm_pin {
uint32_t pwm_cycle_ticks = 1000000UL / (PWM_FREQUENCY) / 4; // # ticks per pwm cycle
uint32_t pwm_tick_count = 0; // current tick count
uint32_t pwm_duty_ticks = 0; // # of ticks for current duty cycle
} pwm_pin_t;
class Servo; class Servo;
typedef Servo hal_servo_t; typedef Servo hal_servo_t;
@@ -197,6 +206,8 @@ public:
// Free SRAM // Free SRAM
static int freeMemory(); static int freeMemory();
static pwm_pin_t pwm_pin_data[MAX_EXPANDER_BITS];
// //
// ADC Methods // ADC Methods
// //

View File

@@ -337,6 +337,26 @@ uint8_t i2s_state(uint8_t pin) {
} }
void i2s_push_sample() { void i2s_push_sample() {
// Every 4µs (when space in DMA buffer) toggle each expander PWM output using
// the current duty cycle/frequency so they sync with any steps (once
// through the DMA/FIFO buffers). PWM signal inversion handled by other functions
LOOP_L_N(p, MAX_EXPANDER_BITS) {
if (hal.pwm_pin_data[p].pwm_duty_ticks > 0) { // pin has active pwm?
if (hal.pwm_pin_data[p].pwm_tick_count == 0) {
if (TEST32(i2s_port_data, p)) { // hi->lo
CBI32(i2s_port_data, p);
hal.pwm_pin_data[p].pwm_tick_count = hal.pwm_pin_data[p].pwm_cycle_ticks - hal.pwm_pin_data[p].pwm_duty_ticks;
}
else { // lo->hi
SBI32(i2s_port_data, p);
hal.pwm_pin_data[p].pwm_tick_count = hal.pwm_pin_data[p].pwm_duty_ticks;
}
}
else
hal.pwm_pin_data[p].pwm_tick_count--;
}
}
dma.current[dma.rw_pos++] = i2s_port_data; dma.current[dma.rw_pos++] = i2s_port_data;
} }

View File

@@ -20,3 +20,10 @@
* *
*/ */
#pragma once #pragma once
//
// Board-specific options need to be defined before HAL.h
//
#if MB(MKS_TINYBEE)
#define MAX_EXPANDER_BITS 24 // TinyBee has 3 x HC595
#endif

View File

@@ -48,3 +48,7 @@
#if USING_PULLDOWNS #if USING_PULLDOWNS
#error "PULLDOWN pin mode is not available on ESP32 boards." #error "PULLDOWN pin mode is not available on ESP32 boards."
#endif #endif
#if BOTH(I2S_STEPPER_STREAM, LIN_ADVANCE)
#error "I2S stream is currently incompatible with LIN_ADVANCE."
#endif

View File

@@ -69,12 +69,12 @@ bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, ui
std::size_t bytes_written = 0; std::size_t bytes_written = 0;
for (std::size_t i = 0; i < size; i++) { for (std::size_t i = 0; i < size; i++) {
buffer[pos+i] = value[i]; buffer[pos + i] = value[i];
bytes_written ++; bytes_written++;
} }
crc16(crc, value, size); crc16(crc, value, size);
pos = pos + size; pos += size;
return (bytes_written != size); // return true for any error return (bytes_written != size); // return true for any error
} }
@@ -82,21 +82,21 @@ bool PersistentStore::read_data(int &pos, uint8_t *value, const size_t size, uin
std::size_t bytes_read = 0; std::size_t bytes_read = 0;
if (writing) { if (writing) {
for (std::size_t i = 0; i < size; i++) { for (std::size_t i = 0; i < size; i++) {
value[i] = buffer[pos+i]; value[i] = buffer[pos + i];
bytes_read ++; bytes_read++;
} }
crc16(crc, value, size); crc16(crc, value, size);
} }
else { else {
uint8_t temp[size]; uint8_t temp[size];
for (std::size_t i = 0; i < size; i++) { for (std::size_t i = 0; i < size; i++) {
temp[i] = buffer[pos+i]; temp[i] = buffer[pos + i];
bytes_read ++; bytes_read++;
} }
crc16(crc, temp, size); crc16(crc, temp, size);
} }
pos = pos + size; pos += size;
return bytes_read != size; // return true for any error return bytes_read != size; // return true for any error
} }

View File

@@ -26,8 +26,8 @@
struct LowpassFilter { struct LowpassFilter {
uint64_t data_delay = 0; uint64_t data_delay = 0;
uint16_t update(uint16_t value) { uint16_t update(uint16_t value) {
data_delay = data_delay - (data_delay >> 6) + value; data_delay += value - (data_delay >> 6);
return (uint16_t)(data_delay >> 6); return uint16_t(data_delay >> 6);
} }
}; };

View File

@@ -12,7 +12,7 @@ if pioutil.is_pio_build():
target_filename = "FIRMWARE.CUR" target_filename = "FIRMWARE.CUR"
target_drive = "REARM" target_drive = "REARM"
import os,getpass,platform import platform
current_OS = platform.system() current_OS = platform.system()
Import("env") Import("env")
@@ -26,7 +26,8 @@ if pioutil.is_pio_build():
def before_upload(source, target, env): def before_upload(source, target, env):
try: try:
# from pathlib import Path
#
# Find a disk for upload # Find a disk for upload
# #
upload_disk = 'Disk not found' upload_disk = 'Disk not found'
@@ -38,6 +39,7 @@ if pioutil.is_pio_build():
# Windows - doesn't care about the disk's name, only cares about the drive letter # Windows - doesn't care about the disk's name, only cares about the drive letter
import subprocess,string import subprocess,string
from ctypes import windll from ctypes import windll
from pathlib import PureWindowsPath
# getting list of drives # getting list of drives
# https://stackoverflow.com/questions/827371/is-there-a-way-to-list-all-the-available-drive-letters-in-python # https://stackoverflow.com/questions/827371/is-there-a-way-to-list-all-the-available-drive-letters-in-python
@@ -49,7 +51,7 @@ if pioutil.is_pio_build():
bitmask >>= 1 bitmask >>= 1
for drive in drives: for drive in drives:
final_drive_name = drive + ':\\' final_drive_name = drive + ':'
# print ('disc check: {}'.format(final_drive_name)) # print ('disc check: {}'.format(final_drive_name))
try: try:
volume_info = str(subprocess.check_output('cmd /C dir ' + final_drive_name, stderr=subprocess.STDOUT)) volume_info = str(subprocess.check_output('cmd /C dir ' + final_drive_name, stderr=subprocess.STDOUT))
@@ -59,29 +61,33 @@ if pioutil.is_pio_build():
else: else:
if target_drive in volume_info and not target_file_found: # set upload if not found target file yet if target_drive in volume_info and not target_file_found: # set upload if not found target file yet
target_drive_found = True target_drive_found = True
upload_disk = final_drive_name upload_disk = PureWindowsPath(final_drive_name)
if target_filename in volume_info: if target_filename in volume_info:
if not target_file_found: if not target_file_found:
upload_disk = final_drive_name upload_disk = PureWindowsPath(final_drive_name)
target_file_found = True target_file_found = True
elif current_OS == 'Linux': elif current_OS == 'Linux':
# #
# platformio.ini will accept this for a Linux upload port designation: 'upload_port = /media/media_name/drive' # platformio.ini will accept this for a Linux upload port designation: 'upload_port = /media/media_name/drive'
# #
drives = os.listdir(os.path.join(os.sep, 'media', getpass.getuser())) import getpass
user = getpass.getuser()
mpath = Path('media', user)
drives = [ x for x in mpath.iterdir() if x.is_dir() ]
if target_drive in drives: # If target drive is found, use it. if target_drive in drives: # If target drive is found, use it.
target_drive_found = True target_drive_found = True
upload_disk = os.path.join(os.sep, 'media', getpass.getuser(), target_drive) + os.sep upload_disk = mpath / target_drive
else: else:
for drive in drives: for drive in drives:
try: try:
files = os.listdir(os.path.join(os.sep, 'media', getpass.getuser(), drive)) fpath = mpath / drive
files = [ x for x in fpath.iterdir() if x.is_file() ]
except: except:
continue continue
else: else:
if target_filename in files: if target_filename in files:
upload_disk = os.path.join(os.sep, 'media', getpass.getuser(), drive) + os.sep upload_disk = mpath / drive
target_file_found = True target_file_found = True
break break
# #
@@ -97,26 +103,28 @@ if pioutil.is_pio_build():
# #
# platformio.ini will accept this for a OSX upload port designation: 'upload_port = /media/media_name/drive' # platformio.ini will accept this for a OSX upload port designation: 'upload_port = /media/media_name/drive'
# #
drives = os.listdir('/Volumes') # human readable names dpath = Path('/Volumes') # human readable names
drives = [ x for x in dpath.iterdir() ]
if target_drive in drives and not target_file_found: # set upload if not found target file yet if target_drive in drives and not target_file_found: # set upload if not found target file yet
target_drive_found = True target_drive_found = True
upload_disk = '/Volumes/' + target_drive + '/' upload_disk = dpath / target_drive
for drive in drives: for drive in drives:
try: try:
filenames = os.listdir('/Volumes/' + drive + '/') # will get an error if the drive is protected fpath = dpath / drive # will get an error if the drive is protected
files = [ x for x in fpath.iterdir() ]
except: except:
continue continue
else: else:
if target_filename in filenames: if target_filename in files:
if not target_file_found: if not target_file_found:
upload_disk = '/Volumes/' + drive + '/' upload_disk = dpath / drive
target_file_found = True target_file_found = True
# #
# Set upload_port to drive if found # Set upload_port to drive if found
# #
if target_file_found or target_drive_found: if target_file_found or target_drive_found:
env.Replace(UPLOAD_PORT=upload_disk) env.Replace(UPLOAD_PORT=str(upload_disk))
print('\nUpload disk: ', upload_disk, '\n') print('\nUpload disk: ', upload_disk, '\n')
else: else:
print_error('Autodetect Error') print_error('Autodetect Error')

View File

@@ -598,7 +598,7 @@ void MarlinHAL::dma_init() {
void MarlinHAL::init() { void MarlinHAL::init() {
TERN_(DMA_IS_REQUIRED, dma_init()); TERN_(DMA_IS_REQUIRED, dma_init());
#if ENABLED(SDSUPPORT) #if ENABLED(SDSUPPORT)
#if SD_CONNECTION_IS(ONBOARD) && PIN_EXISTS(SD_DETECT) #if HAS_SD_DETECT && SD_CONNECTION_IS(ONBOARD)
SET_INPUT_PULLUP(SD_DETECT_PIN); SET_INPUT_PULLUP(SD_DETECT_PIN);
#endif #endif
OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up

View File

@@ -77,7 +77,8 @@ HAL_SERVO_TIMER_ISR() {
; ;
const uint8_t tcChannel = TIMER_TCCHANNEL(timer); const uint8_t tcChannel = TIMER_TCCHANNEL(timer);
if (currentServoIndex[timer] < 0) { int8_t cho = currentServoIndex[timer]; // Handle the prior servo first
if (cho < 0) { // Servo -1 indicates the refresh interval completed...
#if defined(_useTimer1) && defined(_useTimer2) #if defined(_useTimer1) && defined(_useTimer2)
if (currentServoIndex[timer ^ 1] >= 0) { if (currentServoIndex[timer ^ 1] >= 0) {
// Wait for both channels // Wait for both channels
@@ -86,45 +87,37 @@ HAL_SERVO_TIMER_ISR() {
return; return;
} }
#endif #endif
tc->COUNT16.COUNT.reg = TC_COUNTER_START_VAL; tc->COUNT16.COUNT.reg = TC_COUNTER_START_VAL; // ...so reset the timer
SYNC(tc->COUNT16.SYNCBUSY.bit.COUNT); SYNC(tc->COUNT16.SYNCBUSY.bit.COUNT);
} }
else if (SERVO_INDEX(timer, currentServoIndex[timer]) < ServoCount && SERVO(timer, currentServoIndex[timer]).Pin.isActive) else if (SERVO_INDEX(timer, cho) < ServoCount) // prior channel handled?
digitalWrite(SERVO(timer, currentServoIndex[timer]).Pin.nbr, LOW); // pulse this channel low if activated digitalWrite(SERVO(timer, cho).Pin.nbr, LOW); // pulse the prior channel LOW
// Select the next servo controlled by this timer currentServoIndex[timer] = ++cho; // go to the next channel (or 0)
currentServoIndex[timer]++; if (cho < SERVOS_PER_TIMER && SERVO_INDEX(timer, cho) < ServoCount) {
if (SERVO(timer, cho).Pin.isActive) // activated?
digitalWrite(SERVO(timer, cho).Pin.nbr, HIGH); // yes: pulse HIGH
if (SERVO_INDEX(timer, currentServoIndex[timer]) < ServoCount && currentServoIndex[timer] < SERVOS_PER_TIMER) { tc->COUNT16.CC[tcChannel].reg = getTimerCount() - (uint16_t)SERVO(timer, cho).ticks;
if (SERVO(timer, currentServoIndex[timer]).Pin.isActive) // check if activated
digitalWrite(SERVO(timer, currentServoIndex[timer]).Pin.nbr, HIGH); // it's an active channel so pulse it high
tc->COUNT16.CC[tcChannel].reg = getTimerCount() - (uint16_t)SERVO(timer, currentServoIndex[timer]).ticks;
} }
else { else {
// finished all channels so wait for the refresh period to expire before starting over // finished all channels so wait for the refresh period to expire before starting over
currentServoIndex[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel currentServoIndex[timer] = -1; // reset the timer COUNT.reg on the next call
const uint16_t cval = getTimerCount() - 256 / (SERVO_TIMER_PRESCALER), // allow 256 cycles to ensure the next CV not missed
const uint16_t tcCounterValue = getTimerCount(); ival = (TC_COUNTER_START_VAL) - (uint16_t)usToTicks(REFRESH_INTERVAL); // at least REFRESH_INTERVAL has elapsed
tc->COUNT16.CC[tcChannel].reg = min(cval, ival);
if ((TC_COUNTER_START_VAL - tcCounterValue) + 4UL < usToTicks(REFRESH_INTERVAL)) // allow a few ticks to ensure the next OCR1A not missed
tc->COUNT16.CC[tcChannel].reg = TC_COUNTER_START_VAL - (uint16_t)usToTicks(REFRESH_INTERVAL);
else
tc->COUNT16.CC[tcChannel].reg = (uint16_t)(tcCounterValue - 4UL); // at least REFRESH_INTERVAL has elapsed
} }
if (tcChannel == 0) { if (tcChannel == 0) {
SYNC(tc->COUNT16.SYNCBUSY.bit.CC0); SYNC(tc->COUNT16.SYNCBUSY.bit.CC0);
// Clear the interrupt tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC0; // Clear the interrupt
tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC0;
} }
else { else {
SYNC(tc->COUNT16.SYNCBUSY.bit.CC1); SYNC(tc->COUNT16.SYNCBUSY.bit.CC1);
// Clear the interrupt tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC1; // Clear the interrupt
tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC1;
} }
} }
void initISR(timer16_Sequence_t timer) { void initISR(const timer16_Sequence_t timer) {
Tc * const tc = timer_config[SERVO_TC].pTc; Tc * const tc = timer_config[SERVO_TC].pTc;
const uint8_t tcChannel = TIMER_TCCHANNEL(timer); const uint8_t tcChannel = TIMER_TCCHANNEL(timer);
@@ -201,9 +194,9 @@ void initISR(timer16_Sequence_t timer) {
} }
} }
void finISR(timer16_Sequence_t timer) { void finISR(const timer16_Sequence_t timer_index) {
Tc * const tc = timer_config[SERVO_TC].pTc; Tc * const tc = timer_config[SERVO_TC].pTc;
const uint8_t tcChannel = TIMER_TCCHANNEL(timer); const uint8_t tcChannel = TIMER_TCCHANNEL(timer_index);
// Disable the match channel interrupt request // Disable the match channel interrupt request
tc->COUNT16.INTENCLR.reg = (tcChannel == 0) ? TC_INTENCLR_MC0 : TC_INTENCLR_MC1; tc->COUNT16.INTENCLR.reg = (tcChannel == 0) ? TC_INTENCLR_MC0 : TC_INTENCLR_MC1;

View File

@@ -33,157 +33,43 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
// use local drivers
#if defined(STM32F103xE) || defined(STM32F103xG) #if defined(STM32F103xE) || defined(STM32F103xG)
#include <stm32f1xx.h> #include <stm32f1xx_hal_rcc_ex.h>
#include <stm32f1xx_hal_sd.h>
#elif defined(STM32F4xx) #elif defined(STM32F4xx)
#include <stm32f4xx.h> #include <stm32f4xx_hal_rcc.h>
#include <stm32f4xx_hal_dma.h>
#include <stm32f4xx_hal_gpio.h>
#include <stm32f4xx_hal_sd.h>
#elif defined(STM32F7xx) #elif defined(STM32F7xx)
#include <stm32f7xx.h> #include <stm32f7xx_hal_rcc.h>
#include <stm32f7xx_hal_dma.h>
#include <stm32f7xx_hal_gpio.h>
#include <stm32f7xx_hal_sd.h>
#elif defined(STM32H7xx) #elif defined(STM32H7xx)
#include <stm32h7xx.h> #define SDIO_FOR_STM32H7
#include <stm32h7xx_hal_rcc.h>
#include <stm32h7xx_hal_dma.h>
#include <stm32h7xx_hal_gpio.h>
#include <stm32h7xx_hal_sd.h>
#else #else
#error "SDIO only supported with STM32F103xE, STM32F103xG, STM32F4xx, STM32F7xx, or STM32H7xx." #error "SDIO is only supported with STM32F103xE, STM32F103xG, STM32F4xx, STM32F7xx, and STM32H7xx."
#endif #endif
// SDIO Max Clock (naming from STM Manual, don't change)
#define SDIOCLK 48000000
// Target Clock, configurable. Default is 18MHz, from STM32F1 // Target Clock, configurable. Default is 18MHz, from STM32F1
#ifndef SDIO_CLOCK #ifndef SDIO_CLOCK
#define SDIO_CLOCK 18000000 // 18 MHz #define SDIO_CLOCK 18000000 // 18 MHz
#endif #endif
#define SD_TIMEOUT 1000 // ms SD_HandleTypeDef hsd; // SDIO structure
// SDIO Max Clock (naming from STM Manual, don't change)
#define SDIOCLK 48000000
#if defined(STM32F1xx)
DMA_HandleTypeDef hdma_sdio;
extern "C" void DMA2_Channel4_5_IRQHandler(void) {
HAL_DMA_IRQHandler(&hdma_sdio);
}
#elif defined(STM32F4xx)
DMA_HandleTypeDef hdma_sdio_rx;
DMA_HandleTypeDef hdma_sdio_tx;
extern "C" void DMA2_Stream3_IRQHandler(void) {
HAL_DMA_IRQHandler(&hdma_sdio_rx);
}
extern "C" void DMA2_Stream6_IRQHandler(void) {
HAL_DMA_IRQHandler(&hdma_sdio_tx);
}
#elif defined(STM32H7xx)
#define __HAL_RCC_SDIO_FORCE_RESET __HAL_RCC_SDMMC1_FORCE_RESET
#define __HAL_RCC_SDIO_RELEASE_RESET __HAL_RCC_SDMMC1_RELEASE_RESET
#define __HAL_RCC_SDIO_CLK_ENABLE __HAL_RCC_SDMMC1_CLK_ENABLE
#define SDIO SDMMC1
#define SDIO_IRQn SDMMC1_IRQn
#define SDIO_IRQHandler SDMMC1_IRQHandler
#define SDIO_CLOCK_EDGE_RISING SDMMC_CLOCK_EDGE_RISING
#define SDIO_CLOCK_POWER_SAVE_DISABLE SDMMC_CLOCK_POWER_SAVE_DISABLE
#define SDIO_BUS_WIDE_1B SDMMC_BUS_WIDE_1B
#define SDIO_BUS_WIDE_4B SDMMC_BUS_WIDE_4B
#define SDIO_HARDWARE_FLOW_CONTROL_DISABLE SDMMC_HARDWARE_FLOW_CONTROL_DISABLE
#endif
uint8_t waitingRxCplt = 0;
uint8_t waitingTxCplt = 0;
SD_HandleTypeDef hsd;
extern "C" void SDIO_IRQHandler(void) {
HAL_SD_IRQHandler(&hsd);
}
void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsdio) {
waitingTxCplt = 0;
}
void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsdio) {
waitingRxCplt = 0;
}
void HAL_SD_MspInit(SD_HandleTypeDef *hsd) {
pinmap_pinout(PC_12, PinMap_SD);
pinmap_pinout(PD_2, PinMap_SD);
pinmap_pinout(PC_8, PinMap_SD);
#if PINS_EXIST(SDIO_D1, SDIO_D2, SDIO_D3) // define D1-D3 only if have a four bit wide SDIO bus
// D1-D3
pinmap_pinout(PC_9, PinMap_SD);
pinmap_pinout(PC_10, PinMap_SD);
pinmap_pinout(PC_11, PinMap_SD);
#endif
__HAL_RCC_SDIO_CLK_ENABLE();
HAL_NVIC_EnableIRQ(SDIO_IRQn);
// DMA Config
#if defined(STM32F1xx)
__HAL_RCC_DMA2_CLK_ENABLE();
HAL_NVIC_EnableIRQ(DMA2_Channel4_5_IRQn);
hdma_sdio.Instance = DMA2_Channel4;
hdma_sdio.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_sdio.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_sdio.Init.MemInc = DMA_MINC_ENABLE;
hdma_sdio.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_sdio.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_sdio.Init.Mode = DMA_NORMAL;
hdma_sdio.Init.Priority = DMA_PRIORITY_LOW;
HAL_DMA_Init(&hdma_sdio);
__HAL_LINKDMA(hsd, hdmarx ,hdma_sdio);
__HAL_LINKDMA(hsd, hdmatx, hdma_sdio);
#elif defined(STM32F4xx)
__HAL_RCC_DMA2_CLK_ENABLE();
HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);
hdma_sdio_rx.Instance = DMA2_Stream3;
hdma_sdio_rx.Init.Channel = DMA_CHANNEL_4;
hdma_sdio_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_sdio_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_sdio_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_sdio_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_sdio_rx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_sdio_rx.Init.Mode = DMA_PFCTRL;
hdma_sdio_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_sdio_rx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
hdma_sdio_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_sdio_rx.Init.MemBurst = DMA_MBURST_INC4;
hdma_sdio_rx.Init.PeriphBurst = DMA_PBURST_INC4;
HAL_DMA_Init(&hdma_sdio_rx);
__HAL_LINKDMA(hsd,hdmarx,hdma_sdio_rx);
hdma_sdio_tx.Instance = DMA2_Stream6;
hdma_sdio_tx.Init.Channel = DMA_CHANNEL_4;
hdma_sdio_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_sdio_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_sdio_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_sdio_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_sdio_tx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_sdio_tx.Init.Mode = DMA_PFCTRL;
hdma_sdio_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_sdio_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
hdma_sdio_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_sdio_tx.Init.MemBurst = DMA_MBURST_INC4;
hdma_sdio_tx.Init.PeriphBurst = DMA_PBURST_INC4;
HAL_DMA_Init(&hdma_sdio_tx);
__HAL_LINKDMA(hsd,hdmatx,hdma_sdio_tx);
#endif
}
void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) {
#if !defined(STM32F1xx)
__HAL_RCC_SDIO_FORCE_RESET();
delay(10);
__HAL_RCC_SDIO_RELEASE_RESET();
delay(10);
#endif
}
static uint32_t clock_to_divider(uint32_t clk) { static uint32_t clock_to_divider(uint32_t clk) {
#if defined(STM32H7xx) #ifdef SDIO_FOR_STM32H7
// SDMMC_CK frequency = sdmmc_ker_ck / [2 * CLKDIV]. // SDMMC_CK frequency = sdmmc_ker_ck / [2 * CLKDIV].
uint32_t sdmmc_clk = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SDMMC); uint32_t sdmmc_clk = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SDMMC);
return sdmmc_clk / (2U * SDIO_CLOCK) + (sdmmc_clk % (2U * SDIO_CLOCK) != 0); return sdmmc_clk / (2U * SDIO_CLOCK) + (sdmmc_clk % (2U * SDIO_CLOCK) != 0);
#else #else
// limit the SDIO master clock to 8/3 of PCLK2. See STM32 Manuals // limit the SDIO master clock to 8/3 of PCLK2. See STM32 Manuals
@@ -198,62 +84,359 @@ static uint32_t clock_to_divider(uint32_t clk) {
#endif #endif
} }
bool SDIO_Init() { // Start the SDIO clock
HAL_StatusTypeDef sd_state = HAL_OK; void HAL_SD_MspInit(SD_HandleTypeDef *hsd) {
if (hsd.Instance == SDIO) UNUSED(hsd);
HAL_SD_DeInit(&hsd); #ifdef SDIO_FOR_STM32H7
pinmap_pinout(PC_12, PinMap_SD);
/* HAL SD initialization */ pinmap_pinout(PD_2, PinMap_SD);
hsd.Instance = SDIO; pinmap_pinout(PC_8, PinMap_SD);
hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; #if PINS_EXIST(SDIO_D1, SDIO_D2, SDIO_D3) // Define D1-D3 only for 4-bit wide SDIO bus
hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE; pinmap_pinout(PC_9, PinMap_SD);
hsd.Init.BusWide = SDIO_BUS_WIDE_1B; pinmap_pinout(PC_10, PinMap_SD);
hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; pinmap_pinout(PC_11, PinMap_SD);
hsd.Init.ClockDiv = clock_to_divider(SDIO_CLOCK); #endif
sd_state = HAL_SD_Init(&hsd); __HAL_RCC_SDMMC1_CLK_ENABLE();
HAL_NVIC_EnableIRQ(SDMMC1_IRQn);
#if PINS_EXIST(SDIO_D1, SDIO_D2, SDIO_D3) #else
if (sd_state == HAL_OK) { __HAL_RCC_SDIO_CLK_ENABLE();
sd_state = HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B);
}
#endif #endif
return (sd_state == HAL_OK) ? true : false;
} }
bool SDIO_ReadBlock(uint32_t block, uint8_t *dst) { #ifdef SDIO_FOR_STM32H7
uint32_t timeout = HAL_GetTick() + SD_TIMEOUT;
while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER) { #define SD_TIMEOUT 1000 // ms
if (HAL_GetTick() >= timeout) return false;
extern "C" void SDMMC1_IRQHandler(void) { HAL_SD_IRQHandler(&hsd); }
uint8_t waitingRxCplt = 0, waitingTxCplt = 0;
void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsdio) { waitingTxCplt = 0; }
void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsdio) { waitingRxCplt = 0; }
void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) {
__HAL_RCC_SDMMC1_FORCE_RESET(); delay(10);
__HAL_RCC_SDMMC1_RELEASE_RESET(); delay(10);
} }
waitingRxCplt = 1; bool SDIO_Init() {
if (HAL_SD_ReadBlocks_DMA(&hsd, (uint8_t *)dst, block, 1) != HAL_OK) HAL_StatusTypeDef sd_state = HAL_OK;
if (hsd.Instance == SDMMC1) HAL_SD_DeInit(&hsd);
// HAL SD initialization
hsd.Instance = SDMMC1;
hsd.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
hsd.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
hsd.Init.BusWide = SDMMC_BUS_WIDE_1B;
hsd.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
hsd.Init.ClockDiv = clock_to_divider(SDIO_CLOCK);
sd_state = HAL_SD_Init(&hsd);
#if PINS_EXIST(SDIO_D1, SDIO_D2, SDIO_D3)
if (sd_state == HAL_OK)
sd_state = HAL_SD_ConfigWideBusOperation(&hsd, SDMMC_BUS_WIDE_4B);
#endif
return (sd_state == HAL_OK);
}
#else // !SDIO_FOR_STM32H7
#define SD_TIMEOUT 500 // ms
// SDIO retries, configurable. Default is 3, from STM32F1
#ifndef SDIO_READ_RETRIES
#define SDIO_READ_RETRIES 3
#endif
// F4 supports one DMA for RX and another for TX, but Marlin will never
// do read and write at same time, so we use the same DMA for both.
DMA_HandleTypeDef hdma_sdio;
#ifdef STM32F1xx
#define DMA_IRQ_HANDLER DMA2_Channel4_5_IRQHandler
#elif defined(STM32F4xx)
#define DMA_IRQ_HANDLER DMA2_Stream3_IRQHandler
#else
#error "Unknown STM32 architecture."
#endif
extern "C" void SDIO_IRQHandler(void) { HAL_SD_IRQHandler(&hsd); }
extern "C" void DMA_IRQ_HANDLER(void) { HAL_DMA_IRQHandler(&hdma_sdio); }
/*
SDIO_INIT_CLK_DIV is 118
SDIO clock frequency is 48MHz / (TRANSFER_CLOCK_DIV + 2)
SDIO init clock frequency should not exceed 400kHz = 48MHz / (118 + 2)
Default TRANSFER_CLOCK_DIV is 2 (118 / 40)
Default SDIO clock frequency is 48MHz / (2 + 2) = 12 MHz
This might be too fast for stable SDIO operations
MKS Robin SDIO seems stable with BusWide 1bit and ClockDiv 8 (i.e., 4.8MHz SDIO clock frequency)
More testing is required as there are clearly some 4bit init problems.
*/
void go_to_transfer_speed() {
/* Default SDIO peripheral configuration for SD card initialization */
hsd.Init.ClockEdge = hsd.Init.ClockEdge;
hsd.Init.ClockBypass = hsd.Init.ClockBypass;
hsd.Init.ClockPowerSave = hsd.Init.ClockPowerSave;
hsd.Init.BusWide = hsd.Init.BusWide;
hsd.Init.HardwareFlowControl = hsd.Init.HardwareFlowControl;
hsd.Init.ClockDiv = clock_to_divider(SDIO_CLOCK);
/* Initialize SDIO peripheral interface with default configuration */
SDIO_Init(hsd.Instance, hsd.Init);
}
void SD_LowLevel_Init() {
uint32_t tempreg;
// Enable GPIO clocks
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = 1; // GPIO_NOPULL
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
#if DISABLED(STM32F1xx)
GPIO_InitStruct.Alternate = GPIO_AF12_SDIO;
#endif
GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_12; // D0 & SCK
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
#if PINS_EXIST(SDIO_D1, SDIO_D2, SDIO_D3) // define D1-D3 only if have a four bit wide SDIO bus
GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11; // D1-D3
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
#endif
// Configure PD.02 CMD line
GPIO_InitStruct.Pin = GPIO_PIN_2;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
// Setup DMA
#ifdef STM32F1xx
hdma_sdio.Init.Mode = DMA_NORMAL;
hdma_sdio.Instance = DMA2_Channel4;
HAL_NVIC_EnableIRQ(DMA2_Channel4_5_IRQn);
#elif defined(STM32F4xx)
hdma_sdio.Init.Mode = DMA_PFCTRL;
hdma_sdio.Instance = DMA2_Stream3;
hdma_sdio.Init.Channel = DMA_CHANNEL_4;
hdma_sdio.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
hdma_sdio.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_sdio.Init.MemBurst = DMA_MBURST_INC4;
hdma_sdio.Init.PeriphBurst = DMA_PBURST_INC4;
HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
#endif
HAL_NVIC_EnableIRQ(SDIO_IRQn);
hdma_sdio.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_sdio.Init.MemInc = DMA_MINC_ENABLE;
hdma_sdio.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_sdio.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_sdio.Init.Priority = DMA_PRIORITY_LOW;
__HAL_LINKDMA(&hsd, hdmarx, hdma_sdio);
__HAL_LINKDMA(&hsd, hdmatx, hdma_sdio);
#ifdef STM32F1xx
__HAL_RCC_SDIO_CLK_ENABLE();
__HAL_RCC_DMA2_CLK_ENABLE();
#else
__HAL_RCC_SDIO_FORCE_RESET(); delay(2);
__HAL_RCC_SDIO_RELEASE_RESET(); delay(2);
__HAL_RCC_SDIO_CLK_ENABLE();
__HAL_RCC_DMA2_FORCE_RESET(); delay(2);
__HAL_RCC_DMA2_RELEASE_RESET(); delay(2);
__HAL_RCC_DMA2_CLK_ENABLE();
#endif
// Initialize the SDIO (with initial <400Khz Clock)
tempreg = 0 // Reset value
| SDIO_CLKCR_CLKEN // Clock enabled
| SDIO_INIT_CLK_DIV; // Clock Divider. Clock = 48000 / (118 + 2) = 400Khz
// Keep the rest at 0 => HW_Flow Disabled, Rising Clock Edge, Disable CLK ByPass, Bus Width = 0, Power save Disable
SDIO->CLKCR = tempreg;
// Power up the SDIO
SDIO_PowerState_ON(SDIO);
hsd.Instance = SDIO;
}
bool SDIO_Init() {
uint8_t retryCnt = SDIO_READ_RETRIES;
bool status;
hsd.Instance = SDIO;
hsd.State = HAL_SD_STATE_RESET;
SD_LowLevel_Init();
uint8_t retry_Cnt = retryCnt;
for (;;) {
hal.watchdog_refresh();
status = (bool) HAL_SD_Init(&hsd);
if (!status) break;
if (!--retry_Cnt) return false; // return failing status if retries are exhausted
}
go_to_transfer_speed();
#if PINS_EXIST(SDIO_D1, SDIO_D2, SDIO_D3) // go to 4 bit wide mode if pins are defined
retry_Cnt = retryCnt;
for (;;) {
hal.watchdog_refresh();
if (!HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B)) break; // some cards are only 1 bit wide so a pass here is not required
if (!--retry_Cnt) break;
}
if (!retry_Cnt) { // wide bus failed, go back to one bit wide mode
hsd.State = (HAL_SD_StateTypeDef) 0; // HAL_SD_STATE_RESET
SD_LowLevel_Init();
retry_Cnt = retryCnt;
for (;;) {
hal.watchdog_refresh();
status = (bool) HAL_SD_Init(&hsd);
if (!status) break;
if (!--retry_Cnt) return false; // return failing status if retries are exhausted
}
go_to_transfer_speed();
}
#endif
return true;
}
/**
* @brief Read or Write a block
* @details Read or Write a block with SDIO
*
* @param block The block index
* @param src The data buffer source for a write
* @param dst The data buffer destination for a read
*
* @return true on success
*/
static bool SDIO_ReadWriteBlock_DMA(uint32_t block, const uint8_t *src, uint8_t *dst) {
if (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER) return false;
hal.watchdog_refresh();
HAL_StatusTypeDef ret;
if (src) {
hdma_sdio.Init.Direction = DMA_MEMORY_TO_PERIPH;
HAL_DMA_Init(&hdma_sdio);
ret = HAL_SD_WriteBlocks_DMA(&hsd, (uint8_t*)src, block, 1);
}
else {
hdma_sdio.Init.Direction = DMA_PERIPH_TO_MEMORY;
HAL_DMA_Init(&hdma_sdio);
ret = HAL_SD_ReadBlocks_DMA(&hsd, (uint8_t*)dst, block, 1);
}
if (ret != HAL_OK) {
HAL_DMA_Abort_IT(&hdma_sdio);
HAL_DMA_DeInit(&hdma_sdio);
return false;
}
millis_t timeout = millis() + SD_TIMEOUT;
// Wait the transfer
while (hsd.State != HAL_SD_STATE_READY) {
if (ELAPSED(millis(), timeout)) {
HAL_DMA_Abort_IT(&hdma_sdio);
HAL_DMA_DeInit(&hdma_sdio);
return false;
}
}
while (__HAL_DMA_GET_FLAG(&hdma_sdio, __HAL_DMA_GET_TC_FLAG_INDEX(&hdma_sdio)) != 0
|| __HAL_DMA_GET_FLAG(&hdma_sdio, __HAL_DMA_GET_TE_FLAG_INDEX(&hdma_sdio)) != 0) { /* nada */ }
HAL_DMA_Abort_IT(&hdma_sdio);
HAL_DMA_DeInit(&hdma_sdio);
timeout = millis() + SD_TIMEOUT;
while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER) if (ELAPSED(millis(), timeout)) return false;
return true;
}
#endif // !SDIO_FOR_STM32H7
/**
* @brief Read a block
* @details Read a block from media with SDIO
*
* @param block The block index
* @param src The block buffer
*
* @return true on success
*/
bool SDIO_ReadBlock(uint32_t block, uint8_t *dst) {
#ifdef SDIO_FOR_STM32H7
uint32_t timeout = HAL_GetTick() + SD_TIMEOUT;
while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER)
if (HAL_GetTick() >= timeout) return false;
waitingRxCplt = 1;
if (HAL_SD_ReadBlocks_DMA(&hsd, (uint8_t*)dst, block, 1) != HAL_OK)
return false;
timeout = HAL_GetTick() + SD_TIMEOUT;
while (waitingRxCplt)
if (HAL_GetTick() >= timeout) return false;
return true;
#else
uint8_t retries = SDIO_READ_RETRIES;
while (retries--) if (SDIO_ReadWriteBlock_DMA(block, nullptr, dst)) return true;
return false; return false;
timeout = HAL_GetTick() + SD_TIMEOUT; #endif
while (waitingRxCplt)
if (HAL_GetTick() >= timeout) return false;
return true;
} }
/**
* @brief Write a block
* @details Write a block to media with SDIO
*
* @param block The block index
* @param src The block data
*
* @return true on success
*/
bool SDIO_WriteBlock(uint32_t block, const uint8_t *src) { bool SDIO_WriteBlock(uint32_t block, const uint8_t *src) {
uint32_t timeout = HAL_GetTick() + SD_TIMEOUT; #ifdef SDIO_FOR_STM32H7
while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER) uint32_t timeout = HAL_GetTick() + SD_TIMEOUT;
if (HAL_GetTick() >= timeout) return false;
waitingTxCplt = 1; while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER)
if (HAL_SD_WriteBlocks_DMA(&hsd, (uint8_t *)src, block, 1) != HAL_OK) if (HAL_GetTick() >= timeout) return false;
waitingTxCplt = 1;
if (HAL_SD_WriteBlocks_DMA(&hsd, (uint8_t*)src, block, 1) != HAL_OK)
return false;
timeout = HAL_GetTick() + SD_TIMEOUT;
while (waitingTxCplt)
if (HAL_GetTick() >= timeout) return false;
return true;
#else
uint8_t retries = SDIO_READ_RETRIES;
while (retries--) if (SDIO_ReadWriteBlock_DMA(block, src, nullptr)) return true;
return false; return false;
timeout = HAL_GetTick() + SD_TIMEOUT; #endif
while (waitingTxCplt)
if (HAL_GetTick() >= timeout) return false;
return true;
} }
bool SDIO_IsReady() { bool SDIO_IsReady() {

View File

@@ -159,24 +159,28 @@ void GT911::read_reg(uint16_t reg, uint8_t reg_len, uint8_t* r_data, uint8_t r_l
void GT911::Init() { void GT911::Init() {
OUT_WRITE(GT911_RST_PIN, LOW); OUT_WRITE(GT911_RST_PIN, LOW);
OUT_WRITE(GT911_INT_PIN, LOW); OUT_WRITE(GT911_INT_PIN, LOW);
delay(20); delay(11);
WRITE(GT911_INT_PIN, HIGH);
delayMicroseconds(110);
WRITE(GT911_RST_PIN, HIGH); WRITE(GT911_RST_PIN, HIGH);
delay(6);
WRITE(GT911_INT_PIN, LOW);
delay(55);
SET_INPUT(GT911_INT_PIN); SET_INPUT(GT911_INT_PIN);
sw_iic.init(); sw_iic.init();
uint8_t clear_reg = 0x0000; uint8_t clear_reg = 0x00;
write_reg(0x814E, 2, &clear_reg, 2); // Reset to 0 for start write_reg(0x814E, 2, &clear_reg, 1); // Reset to 0 for start
} }
bool GT911::getFirstTouchPoint(int16_t *x, int16_t *y) { bool GT911::getFirstTouchPoint(int16_t *x, int16_t *y) {
read_reg(0x814E, 2, &reg.REG.status, 1); read_reg(0x814E, 2, &reg.REG.status, 1);
if (reg.REG.status & 0x80) { if (reg.REG.status >= 0x80 && reg.REG.status <= 0x85) {
read_reg(0x8150, 2, reg.map + 2, 38);
uint8_t clear_reg = 0x00; uint8_t clear_reg = 0x00;
write_reg(0x814E, 2, &clear_reg, 1); // Reset to 0 for start write_reg(0x814E, 2, &clear_reg, 1); // Reset to 0 for start
read_reg(0x8150, 2, reg.map + 2, 8 * (reg.REG.status & 0x0F));
// First touch point // First touch point
*x = ((reg.REG.point[0].xh & 0x0F) << 8) | reg.REG.point[0].xl; *x = ((reg.REG.point[0].xh & 0x0F) << 8) | reg.REG.point[0].xl;
*y = ((reg.REG.point[0].yh & 0x0F) << 8) | reg.REG.point[0].yl; *y = ((reg.REG.point[0].yh & 0x0F) << 8) | reg.REG.point[0].yl;

View File

@@ -23,7 +23,7 @@
#include "../../../inc/MarlinConfig.h" #include "../../../inc/MarlinConfig.h"
#define GT911_SLAVE_ADDRESS 0xBA #define GT911_SLAVE_ADDRESS 0x28
#if !PIN_EXISTS(GT911_RST) #if !PIN_EXISTS(GT911_RST)
#error "GT911_RST_PIN is not defined." #error "GT911_RST_PIN is not defined."

View File

@@ -372,9 +372,9 @@ void TFT_LTDC::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Cou
if (MemoryIncrease == DMA_PINC_ENABLE) { if (MemoryIncrease == DMA_PINC_ENABLE) {
DrawImage(x_min, y_cur, x_min + width, y_cur + height, Data); DrawImage(x_min, y_cur, x_min + width, y_cur + height, Data);
Data += width * height; Data += width * height;
} else {
DrawRect(x_min, y_cur, x_min + width, y_cur + height, *Data);
} }
else
DrawRect(x_min, y_cur, x_min + width, y_cur + height, *Data);
y_cur += height; y_cur += height;
} }

View File

@@ -147,17 +147,17 @@ void libServo::move(const int32_t value) {
uint16_t SR = timer_get_status(tdev); uint16_t SR = timer_get_status(tdev);
if (SR & TIMER_SR_CC1IF) { // channel 1 off if (SR & TIMER_SR_CC1IF) { // channel 1 off
#ifdef SERVO0_PWM_OD #ifdef SERVO0_PWM_OD
OUT_WRITE_OD(SERVO0_PIN, 1); // off OUT_WRITE_OD(SERVO0_PIN, HIGH); // off
#else #else
OUT_WRITE(SERVO0_PIN, 0); OUT_WRITE(SERVO0_PIN, LOW);
#endif #endif
timer_reset_status_bit(tdev, TIMER_SR_CC1IF_BIT); timer_reset_status_bit(tdev, TIMER_SR_CC1IF_BIT);
} }
if (SR & TIMER_SR_CC2IF) { // channel 2 resume if (SR & TIMER_SR_CC2IF) { // channel 2 resume
#ifdef SERVO0_PWM_OD #ifdef SERVO0_PWM_OD
OUT_WRITE_OD(SERVO0_PIN, 0); // on OUT_WRITE_OD(SERVO0_PIN, LOW); // on
#else #else
OUT_WRITE(SERVO0_PIN, 1); OUT_WRITE(SERVO0_PIN, HIGH);
#endif #endif
timer_reset_status_bit(tdev, TIMER_SR_CC2IF_BIT); timer_reset_status_bit(tdev, TIMER_SR_CC2IF_BIT);
} }
@@ -167,9 +167,9 @@ void libServo::move(const int32_t value) {
timer_dev *tdev = HAL_get_timer_dev(MF_TIMER_SERVO0); timer_dev *tdev = HAL_get_timer_dev(MF_TIMER_SERVO0);
if (!tdev) return false; if (!tdev) return false;
#ifdef SERVO0_PWM_OD #ifdef SERVO0_PWM_OD
OUT_WRITE_OD(inPin, 1); OUT_WRITE_OD(inPin, HIGH);
#else #else
OUT_WRITE(inPin, 0); OUT_WRITE(inPin, LOW);
#endif #endif
timer_pause(tdev); timer_pause(tdev);
@@ -200,9 +200,9 @@ void libServo::move(const int32_t value) {
timer_disable_irq(tdev, 1); timer_disable_irq(tdev, 1);
timer_disable_irq(tdev, 2); timer_disable_irq(tdev, 2);
#ifdef SERVO0_PWM_OD #ifdef SERVO0_PWM_OD
OUT_WRITE_OD(pin, 1); // off OUT_WRITE_OD(pin, HIGH); // off
#else #else
OUT_WRITE(pin, 0); OUT_WRITE(pin, LOW);
#endif #endif
} }
} }

View File

@@ -1,139 +0,0 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* Software L6470 SPI functions originally from Arduino Sd2Card Library
* Copyright (c) 2009 by William Greiman
*/
#include "../../inc/MarlinConfig.h"
#if HAS_L64XX
#include "Delay.h"
#include "../../core/serial.h"
#include "../../libs/L64XX/L64XX_Marlin.h"
// Make sure GCC optimizes this file.
// Note that this line triggers a bug in GCC which is fixed by casting.
// See the note below.
#pragma GCC optimize (3)
// run at ~4Mhz
inline uint8_t L6470_SpiTransfer_Mode_0(uint8_t b) { // using Mode 0
for (uint8_t bits = 8; bits--;) {
WRITE(L6470_CHAIN_MOSI_PIN, b & 0x80);
b <<= 1; // little setup time
WRITE(L6470_CHAIN_SCK_PIN, HIGH);
DELAY_NS(125); // 10 cycles @ 84mhz
b |= (READ(L6470_CHAIN_MISO_PIN) != 0);
WRITE(L6470_CHAIN_SCK_PIN, LOW);
DELAY_NS(125); // 10 cycles @ 84mhz
}
return b;
}
inline uint8_t L6470_SpiTransfer_Mode_3(uint8_t b) { // using Mode 3
for (uint8_t bits = 8; bits--;) {
WRITE(L6470_CHAIN_SCK_PIN, LOW);
WRITE(L6470_CHAIN_MOSI_PIN, b & 0x80);
DELAY_NS(125); // 10 cycles @ 84mhz
WRITE(L6470_CHAIN_SCK_PIN, HIGH);
DELAY_NS(125); // Need more delay for fast CPUs
b <<= 1; // little setup time
b |= (READ(L6470_CHAIN_MISO_PIN) != 0);
}
DELAY_NS(125); // 10 cycles @ 84mhz
return b;
}
/**
* L64XX methods for SPI init and transfer
*/
void L64XX_Marlin::spi_init() {
OUT_WRITE(L6470_CHAIN_SS_PIN, HIGH);
OUT_WRITE(L6470_CHAIN_SCK_PIN, HIGH);
OUT_WRITE(L6470_CHAIN_MOSI_PIN, HIGH);
SET_INPUT(L6470_CHAIN_MISO_PIN);
#if PIN_EXISTS(L6470_BUSY)
SET_INPUT(L6470_BUSY_PIN);
#endif
OUT_WRITE(L6470_CHAIN_MOSI_PIN, HIGH);
}
uint8_t L64XX_Marlin::transfer_single(uint8_t data, int16_t ss_pin) {
// First device in chain has data sent last
extDigitalWrite(ss_pin, LOW);
hal.isr_off(); // Disable interrupts during SPI transfer (can't allow partial command to chips)
const uint8_t data_out = L6470_SpiTransfer_Mode_3(data);
hal.isr_on(); // Enable interrupts
extDigitalWrite(ss_pin, HIGH);
return data_out;
}
uint8_t L64XX_Marlin::transfer_chain(uint8_t data, int16_t ss_pin, uint8_t chain_position) {
uint8_t data_out = 0;
// first device in chain has data sent last
extDigitalWrite(ss_pin, LOW);
for (uint8_t i = L64XX::chain[0]; !L64xxManager.spi_abort && i >= 1; i--) { // Send data unless aborted
hal.isr_off(); // Disable interrupts during SPI transfer (can't allow partial command to chips)
const uint8_t temp = L6470_SpiTransfer_Mode_3(uint8_t(i == chain_position ? data : dSPIN_NOP));
hal.isr_on(); // Enable interrupts
if (i == chain_position) data_out = temp;
}
extDigitalWrite(ss_pin, HIGH);
return data_out;
}
/**
* Platform-supplied L6470 buffer transfer method
*/
void L64XX_Marlin::transfer(uint8_t L6470_buf[], const uint8_t length) {
// First device in chain has its data sent last
if (spi_active) { // Interrupted SPI transfer so need to
WRITE(L6470_CHAIN_SS_PIN, HIGH); // guarantee min high of 650ns
DELAY_US(1);
}
WRITE(L6470_CHAIN_SS_PIN, LOW);
for (uint8_t i = length; i >= 1; i--)
L6470_SpiTransfer_Mode_3(uint8_t(L6470_buf[i]));
WRITE(L6470_CHAIN_SS_PIN, HIGH);
}
#pragma GCC reset_options
#endif // HAS_L64XX

View File

@@ -135,11 +135,11 @@ static UnwResult UnwTabExecuteInstructions(const UnwindCallbacks *cb, UnwTabStat
while ((instruction = UnwTabGetNextInstruction(cb, ucb)) != -1) { while ((instruction = UnwTabGetNextInstruction(cb, ucb)) != -1) {
if ((instruction & 0xC0) == 0x00) { // ARM_EXIDX_CMD_DATA_POP if ((instruction & 0xC0) == 0x00) { // ARM_EXIDX_CMD_DATA_POP
/* vsp = vsp + (xxxxxx << 2) + 4 */ /* vsp += (xxxxxx << 2) + 4 */
ucb->vrs[13] += ((instruction & 0x3F) << 2) + 4; ucb->vrs[13] += ((instruction & 0x3F) << 2) + 4;
} }
else if ((instruction & 0xC0) == 0x40) { // ARM_EXIDX_CMD_DATA_PUSH else if ((instruction & 0xC0) == 0x40) { // ARM_EXIDX_CMD_DATA_PUSH
/* vsp = vsp - (xxxxxx << 2) - 4 */ /* vsp -= (xxxxxx << 2) - 4 */
ucb->vrs[13] -= ((instruction & 0x3F) << 2) - 4; ucb->vrs[13] -= ((instruction & 0x3F) << 2) - 4;
} }
else if ((instruction & 0xF0) == 0x80) { else if ((instruction & 0xF0) == 0x80) {

View File

@@ -65,7 +65,7 @@ uint8_t ServoCount = 0; // the total number of attached
/************ static functions common to all instances ***********************/ /************ static functions common to all instances ***********************/
static boolean isTimerActive(timer16_Sequence_t timer) { static bool anyTimerChannelActive(const timer16_Sequence_t timer) {
// returns true if any servo is active on this timer // returns true if any servo is active on this timer
LOOP_L_N(channel, SERVOS_PER_TIMER) { LOOP_L_N(channel, SERVOS_PER_TIMER) {
if (SERVO(timer, channel).Pin.isActive) if (SERVO(timer, channel).Pin.isActive)
@@ -101,17 +101,18 @@ int8_t Servo::attach(const int inPin, const int inMin, const int inMax) {
max = (MAX_PULSE_WIDTH - inMax) / 4; max = (MAX_PULSE_WIDTH - inMax) / 4;
// initialize the timer if it has not already been initialized // initialize the timer if it has not already been initialized
timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex); const timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex);
if (!isTimerActive(timer)) initISR(timer); if (!anyTimerChannelActive(timer)) initISR(timer);
servo_info[servoIndex].Pin.isActive = true; // this must be set after the check for isTimerActive servo_info[servoIndex].Pin.isActive = true; // this must be set after the check for anyTimerChannelActive
return servoIndex; return servoIndex;
} }
void Servo::detach() { void Servo::detach() {
servo_info[servoIndex].Pin.isActive = false; servo_info[servoIndex].Pin.isActive = false;
timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex); const timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex);
if (!isTimerActive(timer)) finISR(timer); if (!anyTimerChannelActive(timer)) finISR(timer);
//pinMode(servo_info[servoIndex].Pin.nbr, INPUT); // set servo pin to input
} }
void Servo::write(int value) { void Servo::write(int value) {

View File

@@ -70,10 +70,10 @@
#define ticksToUs(_ticks) (unsigned(_ticks) * (SERVO_TIMER_PRESCALER) / clockCyclesPerMicrosecond()) #define ticksToUs(_ticks) (unsigned(_ticks) * (SERVO_TIMER_PRESCALER) / clockCyclesPerMicrosecond())
// convenience macros // convenience macros
#define SERVO_INDEX_TO_TIMER(_servo_nbr) ((timer16_Sequence_t)(_servo_nbr / (SERVOS_PER_TIMER))) // returns the timer controlling this servo #define SERVO_INDEX_TO_TIMER(_servo_nbr) timer16_Sequence_t(_servo_nbr / (SERVOS_PER_TIMER)) // the timer controlling this servo
#define SERVO_INDEX_TO_CHANNEL(_servo_nbr) (_servo_nbr % (SERVOS_PER_TIMER)) // returns the index of the servo on this timer #define SERVO_INDEX_TO_CHANNEL(_servo_nbr) (_servo_nbr % (SERVOS_PER_TIMER)) // the index of the servo on this timer
#define SERVO_INDEX(_timer,_channel) ((_timer*(SERVOS_PER_TIMER)) + _channel) // macro to access servo index by timer and channel #define SERVO_INDEX(_timer,_channel) ((_timer*(SERVOS_PER_TIMER)) + _channel) // servo index by timer and channel
#define SERVO(_timer,_channel) (servo_info[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel #define SERVO(_timer,_channel) servo_info[SERVO_INDEX(_timer,_channel)] // servo class by timer and channel
// Types // Types
@@ -94,5 +94,5 @@ extern ServoInfo_t servo_info[MAX_SERVOS];
// Public functions // Public functions
extern void initISR(timer16_Sequence_t timer); void initISR(const timer16_Sequence_t timer_index);
extern void finISR(timer16_Sequence_t timer); void finISR(const timer16_Sequence_t timer_index);

View File

@@ -39,17 +39,13 @@
#endif #endif
#include <math.h> #include <math.h>
#include "core/utility.h" #include "module/endstops.h"
#include "module/motion.h" #include "module/motion.h"
#include "module/planner.h" #include "module/planner.h"
#include "module/endstops.h"
#include "module/temperature.h"
#include "module/settings.h"
#include "module/printcounter.h" // PrintCounter or Stopwatch #include "module/printcounter.h" // PrintCounter or Stopwatch
#include "module/settings.h"
#include "module/stepper.h" #include "module/stepper.h"
#include "module/stepper/indirection.h" #include "module/temperature.h"
#include "gcode/gcode.h" #include "gcode/gcode.h"
#include "gcode/parser.h" #include "gcode/parser.h"
@@ -125,6 +121,10 @@
#include "feature/bltouch.h" #include "feature/bltouch.h"
#endif #endif
#if ENABLED(BD_SENSOR)
#include "feature/bedlevel/bdl/bdl.h"
#endif
#if ENABLED(POLL_JOG) #if ENABLED(POLL_JOG)
#include "feature/joystick.h" #include "feature/joystick.h"
#endif #endif
@@ -228,10 +228,6 @@
#include "feature/mmu/mmu2.h" #include "feature/mmu/mmu2.h"
#endif #endif
#if HAS_L64XX
#include "libs/L64XX/L64XX_Marlin.h"
#endif
#if ENABLED(PASSWORD_FEATURE) #if ENABLED(PASSWORD_FEATURE)
#include "feature/password/password.h" #include "feature/password/password.h"
#endif #endif
@@ -252,6 +248,10 @@
#include "feature/easythreed_ui.h" #include "feature/easythreed_ui.h"
#endif #endif
#if ENABLED(MARLIN_TEST_BUILD)
#include "tests/marlin_tests.h"
#endif
PGMSTR(M112_KILL_STR, "M112 Shutdown"); PGMSTR(M112_KILL_STR, "M112 Shutdown");
MarlinState marlin_state = MF_INITIALIZING; MarlinState marlin_state = MF_INITIALIZING;
@@ -434,7 +434,7 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) {
if (!has_blocks && !do_reset_timeout && gcode.stepper_inactive_timeout()) { if (!has_blocks && !do_reset_timeout && gcode.stepper_inactive_timeout()) {
if (!already_shutdown_steppers) { if (!already_shutdown_steppers) {
already_shutdown_steppers = true; // L6470 SPI will consume 99% of free time without this already_shutdown_steppers = true;
// Individual axes will be disabled if configured // Individual axes will be disabled if configured
TERN_(DISABLE_INACTIVE_X, stepper.disable_axis(X_AXIS)); TERN_(DISABLE_INACTIVE_X, stepper.disable_axis(X_AXIS));
@@ -733,8 +733,6 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) {
TERN_(MONITOR_DRIVER_STATUS, monitor_tmc_drivers()); TERN_(MONITOR_DRIVER_STATUS, monitor_tmc_drivers());
TERN_(MONITOR_L6470_DRIVER_STATUS, L64xxManager.monitor_driver());
// Limit check_axes_activity frequency to 10Hz // Limit check_axes_activity frequency to 10Hz
static millis_t next_check_axes_ms = 0; static millis_t next_check_axes_ms = 0;
if (ELAPSED(ms, next_check_axes_ms)) { if (ELAPSED(ms, next_check_axes_ms)) {
@@ -776,16 +774,23 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) {
* - Handle Joystick jogging * - Handle Joystick jogging
*/ */
void idle(bool no_stepper_sleep/*=false*/) { void idle(bool no_stepper_sleep/*=false*/) {
#ifdef MAX7219_DEBUG_PROFILE
CodeProfiler idle_profiler;
#endif
#if ENABLED(MARLIN_DEV_MODE) #if ENABLED(MARLIN_DEV_MODE)
static uint16_t idle_depth = 0; static uint16_t idle_depth = 0;
if (++idle_depth > 5) SERIAL_ECHOLNPGM("idle() call depth: ", idle_depth); if (++idle_depth > 5) SERIAL_ECHOLNPGM("idle() call depth: ", idle_depth);
#endif #endif
// Bed Distance Sensor task
TERN_(BD_SENSOR, bdl.process());
// Core Marlin activities // Core Marlin activities
manage_inactivity(no_stepper_sleep); manage_inactivity(no_stepper_sleep);
// Manage Heaters (and Watchdog) // Manage Heaters (and Watchdog)
thermalManager.manage_heater(); thermalManager.task();
// Max7219 heartbeat, animation, etc // Max7219 heartbeat, animation, etc
TERN_(MAX7219_DEBUG, max7219.idle_tasks()); TERN_(MAX7219_DEBUG, max7219.idle_tasks());
@@ -1060,7 +1065,6 @@ inline void tmc_standby_setup() {
* • TMC220x Stepper Drivers (Serial) * • TMC220x Stepper Drivers (Serial)
* • PSU control * • PSU control
* • Power-loss Recovery * • Power-loss Recovery
* • L64XX Stepper Drivers (SPI)
* • Stepper Driver Reset: DISABLE * • Stepper Driver Reset: DISABLE
* • TMC Stepper Drivers (SPI) * • TMC Stepper Drivers (SPI)
* • Run hal.init_board() for additional pins setup * • Run hal.init_board() for additional pins setup
@@ -1223,10 +1227,10 @@ void setup() {
SETUP_RUN(hal.init()); SETUP_RUN(hal.init());
// Init and disable SPI thermocouples; this is still needed // Init and disable SPI thermocouples; this is still needed
#if TEMP_SENSOR_0_IS_MAX_TC || (TEMP_SENSOR_REDUNDANT_IS_MAX_TC && REDUNDANT_TEMP_MATCH(SOURCE, E0)) #if TEMP_SENSOR_IS_MAX_TC(0) || (TEMP_SENSOR_IS_MAX_TC(REDUNDANT) && REDUNDANT_TEMP_MATCH(SOURCE, E0))
OUT_WRITE(TEMP_0_CS_PIN, HIGH); // Disable OUT_WRITE(TEMP_0_CS_PIN, HIGH); // Disable
#endif #endif
#if TEMP_SENSOR_1_IS_MAX_TC || (TEMP_SENSOR_REDUNDANT_IS_MAX_TC && REDUNDANT_TEMP_MATCH(SOURCE, E1)) #if TEMP_SENSOR_IS_MAX_TC(1) || (TEMP_SENSOR_IS_MAX_TC(REDUNDANT) && REDUNDANT_TEMP_MATCH(SOURCE, E1))
OUT_WRITE(TEMP_1_CS_PIN, HIGH); OUT_WRITE(TEMP_1_CS_PIN, HIGH);
#endif #endif
@@ -1249,10 +1253,6 @@ void setup() {
SETUP_RUN(tmc_init_cs_pins()); SETUP_RUN(tmc_init_cs_pins());
#endif #endif
#if HAS_L64XX
SETUP_RUN(L64xxManager.init()); // Set up SPI, init drivers
#endif
#if ENABLED(PSU_CONTROL) #if ENABLED(PSU_CONTROL)
SETUP_LOG("PSU_CONTROL"); SETUP_LOG("PSU_CONTROL");
powerManager.init(); powerManager.init();
@@ -1639,9 +1639,15 @@ void setup() {
SETUP_RUN(test_tmc_connection()); SETUP_RUN(test_tmc_connection());
#endif #endif
#if ENABLED(BD_SENSOR)
SETUP_RUN(bdl.init(I2C_BD_SDA_PIN, I2C_BD_SCL_PIN, I2C_BD_DELAY));
#endif
marlin_state = MF_RUNNING; marlin_state = MF_RUNNING;
SETUP_LOG("setup() completed."); SETUP_LOG("setup() completed.");
TERN_(MARLIN_TEST_BUILD, runStartupTests());
} }
/** /**
@@ -1676,5 +1682,7 @@ void loop() {
TERN_(HAS_TFT_LVGL_UI, printer_state_polling()); TERN_(HAS_TFT_LVGL_UI, printer_state_polling());
TERN_(MARLIN_TEST_BUILD, runPeriodicTests());
} while (ENABLED(__AVR__)); // Loop forever on slower (AVR) boards } while (ENABLED(__AVR__)); // Loop forever on slower (AVR) boards
} }

View File

@@ -238,6 +238,7 @@
#define BOARD_BTT_SKR_V1_1 2012 // BigTreeTech SKR v1.1 #define BOARD_BTT_SKR_V1_1 2012 // BigTreeTech SKR v1.1
#define BOARD_BTT_SKR_V1_3 2013 // BigTreeTech SKR v1.3 #define BOARD_BTT_SKR_V1_3 2013 // BigTreeTech SKR v1.3
#define BOARD_BTT_SKR_V1_4 2014 // BigTreeTech SKR v1.4 #define BOARD_BTT_SKR_V1_4 2014 // BigTreeTech SKR v1.4
#define BOARD_EMOTRONIC 2015 // eMotion-Tech eMotronic
// //
// LPC1769 ARM Cortex M3 // LPC1769 ARM Cortex M3
@@ -332,40 +333,41 @@
#define BOARD_BTT_SKR_E3_DIP 4029 // BigTreeTech SKR E3 DIP V1.0 (STM32F103RC / STM32F103RE) #define BOARD_BTT_SKR_E3_DIP 4029 // BigTreeTech SKR E3 DIP V1.0 (STM32F103RC / STM32F103RE)
#define BOARD_BTT_SKR_CR6 4030 // BigTreeTech SKR CR6 v1.0 (STM32F103RE) #define BOARD_BTT_SKR_CR6 4030 // BigTreeTech SKR CR6 v1.0 (STM32F103RE)
#define BOARD_JGAURORA_A5S_A1 4031 // JGAurora A5S A1 (STM32F103ZE) #define BOARD_JGAURORA_A5S_A1 4031 // JGAurora A5S A1 (STM32F103ZE)
#define BOARD_FYSETC_AIO_II 4032 // FYSETC AIO_II #define BOARD_FYSETC_AIO_II 4032 // FYSETC AIO_II (STM32F103RC)
#define BOARD_FYSETC_CHEETAH 4033 // FYSETC Cheetah #define BOARD_FYSETC_CHEETAH 4033 // FYSETC Cheetah (STM32F103RC)
#define BOARD_FYSETC_CHEETAH_V12 4034 // FYSETC Cheetah V1.2 #define BOARD_FYSETC_CHEETAH_V12 4034 // FYSETC Cheetah V1.2 (STM32F103RC)
#define BOARD_LONGER3D_LK 4035 // Alfawise U20/U20+/U30 (Longer3D LK1/2) / STM32F103VE #define BOARD_LONGER3D_LK 4035 // Longer3D LK1/2 - Alfawise U20/U20+/U30 (STM32F103VE)
#define BOARD_CCROBOT_MEEB_3DP 4036 // ccrobot-online.com MEEB_3DP (STM32F103RC) #define BOARD_CCROBOT_MEEB_3DP 4036 // ccrobot-online.com MEEB_3DP (STM32F103RC)
#define BOARD_CHITU3D_V5 4037 // Chitu3D TronXY X5SA V5 Board #define BOARD_CHITU3D_V5 4037 // Chitu3D TronXY X5SA V5 Board (STM32F103ZE)
#define BOARD_CHITU3D_V6 4038 // Chitu3D TronXY X5SA V6 Board #define BOARD_CHITU3D_V6 4038 // Chitu3D TronXY X5SA V6 Board (STM32F103ZE)
#define BOARD_CHITU3D_V9 4039 // Chitu3D TronXY X5SA V9 Board #define BOARD_CHITU3D_V9 4039 // Chitu3D TronXY X5SA V9 Board (STM32F103ZE)
#define BOARD_CREALITY_V4 4040 // Creality v4.x (STM32F103RC / STM32F103RE) #define BOARD_CREALITY_V4 4040 // Creality v4.x (STM32F103RC / STM32F103RE)
#define BOARD_CREALITY_V422 4041 // Creality v4.2.2 (STM32F103RC / STM32F103RE) #define BOARD_CREALITY_V422 4041 // Creality v4.2.2 (STM32F103RC / STM32F103RE)
#define BOARD_CREALITY_V423 4042 // Creality v4.2.3 (STM32F103RC / STM32F103RE) #define BOARD_CREALITY_V423 4042 // Creality v4.2.3 (STM32F103RC / STM32F103RE)
#define BOARD_CREALITY_V427 4043 // Creality v4.2.7 (STM32F103RC / STM32F103RE) #define BOARD_CREALITY_V425 4043 // Creality v4.2.5 (STM32F103RC / STM32F103RE)
#define BOARD_CREALITY_V4210 4044 // Creality v4.2.10 (STM32F103RC / STM32F103RE) as found in the CR-30 #define BOARD_CREALITY_V427 4044 // Creality v4.2.7 (STM32F103RC / STM32F103RE)
#define BOARD_CREALITY_V431 4045 // Creality v4.3.1 (STM32F103RC / STM32F103RE) #define BOARD_CREALITY_V4210 4045 // Creality v4.2.10 (STM32F103RC / STM32F103RE) as found in the CR-30
#define BOARD_CREALITY_V431_A 4046 // Creality v4.3.1a (STM32F103RC / STM32F103RE) #define BOARD_CREALITY_V431 4046 // Creality v4.3.1 (STM32F103RC / STM32F103RE)
#define BOARD_CREALITY_V431_B 4047 // Creality v4.3.1b (STM32F103RC / STM32F103RE) #define BOARD_CREALITY_V431_A 4047 // Creality v4.3.1a (STM32F103RC / STM32F103RE)
#define BOARD_CREALITY_V431_C 4048 // Creality v4.3.1c (STM32F103RC / STM32F103RE) #define BOARD_CREALITY_V431_B 4048 // Creality v4.3.1b (STM32F103RC / STM32F103RE)
#define BOARD_CREALITY_V431_D 4049 // Creality v4.3.1d (STM32F103RC / STM32F103RE) #define BOARD_CREALITY_V431_C 4049 // Creality v4.3.1c (STM32F103RC / STM32F103RE)
#define BOARD_CREALITY_V452 4050 // Creality v4.5.2 (STM32F103RC / STM32F103RE) #define BOARD_CREALITY_V431_D 4050 // Creality v4.3.1d (STM32F103RC / STM32F103RE)
#define BOARD_CREALITY_V453 4051 // Creality v4.5.3 (STM32F103RC / STM32F103RE) #define BOARD_CREALITY_V452 4051 // Creality v4.5.2 (STM32F103RC / STM32F103RE)
#define BOARD_CREALITY_V24S1 4052 // Creality v2.4.S1 (STM32F103RC / STM32F103RE) v101 as found in the Ender-7 #define BOARD_CREALITY_V453 4052 // Creality v4.5.3 (STM32F103RC / STM32F103RE)
#define BOARD_CREALITY_V24S1_301 4053 // Creality v2.4.S1_301 (STM32F103RC / STM32F103RE) v301 as found in the Ender-3 S1 #define BOARD_CREALITY_V24S1 4053 // Creality v2.4.S1 (STM32F103RC / STM32F103RE) v101 as found in the Ender-7
#define BOARD_CREALITY_V25S1 4054 // Creality v2.5.S1 (STM32F103RE) as found in the CR-10 Smart Pro #define BOARD_CREALITY_V24S1_301 4054 // Creality v2.4.S1_301 (STM32F103RC / STM32F103RE) v301 as found in the Ender-3 S1
#define BOARD_TRIGORILLA_PRO 4055 // Trigorilla Pro (STM32F103ZE) #define BOARD_CREALITY_V25S1 4055 // Creality v2.5.S1 (STM32F103RE) as found in the CR-10 Smart Pro
#define BOARD_FLY_MINI 4056 // FLYmaker FLY MINI (STM32F103RC) #define BOARD_TRIGORILLA_PRO 4056 // Trigorilla Pro (STM32F103ZE)
#define BOARD_FLSUN_HISPEED 4057 // FLSUN HiSpeedV1 (STM32F103VE) #define BOARD_FLY_MINI 4057 // FLYmaker FLY MINI (STM32F103RC)
#define BOARD_BEAST 4058 // STM32F103RE Libmaple-based controller #define BOARD_FLSUN_HISPEED 4058 // FLSUN HiSpeedV1 (STM32F103VE)
#define BOARD_MINGDA_MPX_ARM_MINI 4059 // STM32F103ZE Mingda MD-16 #define BOARD_BEAST 4059 // STM32F103RE Libmaple-based controller
#define BOARD_GTM32_PRO_VD 4060 // STM32F103VE controller #define BOARD_MINGDA_MPX_ARM_MINI 4060 // STM32F103ZE Mingda MD-16
#define BOARD_ZONESTAR_ZM3E2 4061 // Zonestar ZM3E2 (STM32F103RC) #define BOARD_GTM32_PRO_VD 4061 // STM32F103VE controller
#define BOARD_ZONESTAR_ZM3E4 4062 // Zonestar ZM3E4 V1 (STM32F103VC) #define BOARD_ZONESTAR_ZM3E2 4062 // Zonestar ZM3E2 (STM32F103RC)
#define BOARD_ZONESTAR_ZM3E4V2 4063 // Zonestar ZM3E4 V2 (STM32F103VC) #define BOARD_ZONESTAR_ZM3E4 4063 // Zonestar ZM3E4 V1 (STM32F103VC)
#define BOARD_ERYONE_ERY32_MINI 4064 // Eryone Ery32 mini (STM32F103VE) #define BOARD_ZONESTAR_ZM3E4V2 4064 // Zonestar ZM3E4 V2 (STM32F103VC)
#define BOARD_PANDA_PI_V29 4065 // Panda Pi V2.9 - Standalone (STM32F103RC) #define BOARD_ERYONE_ERY32_MINI 4065 // Eryone Ery32 mini (STM32F103VE)
#define BOARD_PANDA_PI_V29 4066 // Panda Pi V2.9 - Standalone (STM32F103RC)
// //
// ARM Cortex-M4F // ARM Cortex-M4F
@@ -385,35 +387,35 @@
#define BOARD_RUMBA32_BTT 4204 // RUMBA32 STM32F446VE based controller from BIGTREETECH #define BOARD_RUMBA32_BTT 4204 // RUMBA32 STM32F446VE based controller from BIGTREETECH
#define BOARD_BLACK_STM32F407VE 4205 // BLACK_STM32F407VE #define BOARD_BLACK_STM32F407VE 4205 // BLACK_STM32F407VE
#define BOARD_BLACK_STM32F407ZE 4206 // BLACK_STM32F407ZE #define BOARD_BLACK_STM32F407ZE 4206 // BLACK_STM32F407ZE
#define BOARD_STEVAL_3DP001V1 4207 // STEVAL-3DP001V1 3D PRINTER BOARD #define BOARD_BTT_SKR_PRO_V1_1 4207 // BigTreeTech SKR Pro v1.1 (STM32F407ZG)
#define BOARD_BTT_SKR_PRO_V1_1 4208 // BigTreeTech SKR Pro v1.1 (STM32F407ZG) #define BOARD_BTT_SKR_PRO_V1_2 4208 // BigTreeTech SKR Pro v1.2 (STM32F407ZG)
#define BOARD_BTT_SKR_PRO_V1_2 4209 // BigTreeTech SKR Pro v1.2 (STM32F407ZG) #define BOARD_BTT_BTT002_V1_0 4209 // BigTreeTech BTT002 v1.0 (STM32F407VG)
#define BOARD_BTT_BTT002_V1_0 4210 // BigTreeTech BTT002 v1.0 (STM32F407VG) #define BOARD_BTT_E3_RRF 4210 // BigTreeTech E3 RRF (STM32F407VG)
#define BOARD_BTT_E3_RRF 4211 // BigTreeTech E3 RRF (STM32F407VG) #define BOARD_BTT_SKR_V2_0_REV_A 4211 // BigTreeTech SKR v2.0 Rev A (STM32F407VG)
#define BOARD_BTT_SKR_V2_0_REV_A 4212 // BigTreeTech SKR v2.0 Rev A (STM32F407VG) #define BOARD_BTT_SKR_V2_0_REV_B 4212 // BigTreeTech SKR v2.0 Rev B (STM32F407VG/STM32F429VG)
#define BOARD_BTT_SKR_V2_0_REV_B 4213 // BigTreeTech SKR v2.0 Rev B (STM32F407VG/STM32F429VG) #define BOARD_BTT_GTR_V1_0 4213 // BigTreeTech GTR v1.0 (STM32F407IGT)
#define BOARD_BTT_GTR_V1_0 4214 // BigTreeTech GTR v1.0 (STM32F407IGT) #define BOARD_BTT_OCTOPUS_V1_0 4214 // BigTreeTech Octopus v1.0 (STM32F446ZE)
#define BOARD_BTT_OCTOPUS_V1_0 4215 // BigTreeTech Octopus v1.0 (STM32F446ZE) #define BOARD_BTT_OCTOPUS_V1_1 4215 // BigTreeTech Octopus v1.1 (STM32F446ZE)
#define BOARD_BTT_OCTOPUS_V1_1 4216 // BigTreeTech Octopus v1.1 (STM32F446ZE) #define BOARD_BTT_OCTOPUS_PRO_V1_0 4216 // BigTreeTech Octopus Pro v1.0 (STM32F446ZE / STM32F429ZG)
#define BOARD_BTT_OCTOPUS_PRO_V1_0 4217 // BigTreeTech Octopus Pro v1.0 (STM32F446ZE/STM32F429ZG) #define BOARD_LERDGE_K 4217 // Lerdge K (STM32F407ZG)
#define BOARD_LERDGE_K 4218 // Lerdge K (STM32F407ZG) #define BOARD_LERDGE_S 4218 // Lerdge S (STM32F407VE)
#define BOARD_LERDGE_S 4219 // Lerdge S (STM32F407VE) #define BOARD_LERDGE_X 4219 // Lerdge X (STM32F407VE)
#define BOARD_LERDGE_X 4220 // Lerdge X (STM32F407VE) #define BOARD_VAKE403D 4220 // VAkE 403D (STM32F446VE)
#define BOARD_VAKE403D 4221 // VAkE 403D (STM32F446VE) #define BOARD_FYSETC_S6 4221 // FYSETC S6 (STM32F446VE)
#define BOARD_FYSETC_S6 4222 // FYSETC S6 (STM32F446VE) #define BOARD_FYSETC_S6_V2_0 4222 // FYSETC S6 v2.0 (STM32F446VE)
#define BOARD_FYSETC_S6_V2_0 4223 // FYSETC S6 v2.0 (STM32F446VE) #define BOARD_FYSETC_SPIDER 4223 // FYSETC Spider (STM32F446VE)
#define BOARD_FYSETC_SPIDER 4224 // FYSETC Spider (STM32F446VE) #define BOARD_FLYF407ZG 4224 // FLYmaker FLYF407ZG (STM32F407ZG)
#define BOARD_FLYF407ZG 4225 // FLYmaker FLYF407ZG (STM32F407ZG) #define BOARD_MKS_ROBIN2 4225 // MKS_ROBIN2 (STM32F407ZE)
#define BOARD_MKS_ROBIN2 4226 // MKS_ROBIN2 (STM32F407ZE) #define BOARD_MKS_ROBIN_PRO_V2 4226 // MKS Robin Pro V2 (STM32F407VE)
#define BOARD_MKS_ROBIN_PRO_V2 4227 // MKS Robin Pro V2 (STM32F407VE) #define BOARD_MKS_ROBIN_NANO_V3 4227 // MKS Robin Nano V3 (STM32F407VG)
#define BOARD_MKS_ROBIN_NANO_V3 4228 // MKS Robin Nano V3 (STM32F407VG) #define BOARD_MKS_ROBIN_NANO_V3_1 4228 // MKS Robin Nano V3.1 (STM32F407VE)
#define BOARD_MKS_ROBIN_NANO_V3_1 4229 // MKS Robin Nano V3.1 (STM32F407VE) #define BOARD_MKS_MONSTER8_V1 4229 // MKS Monster8 V1 (STM32F407VE)
#define BOARD_MKS_MONSTER8 4230 // MKS Monster8 (STM32F407VG) #define BOARD_MKS_MONSTER8_V2 4230 // MKS Monster8 V2 (STM32F407VE)
#define BOARD_ANET_ET4 4231 // ANET ET4 V1.x (STM32F407VG) #define BOARD_ANET_ET4 4231 // ANET ET4 V1.x (STM32F407VG)
#define BOARD_ANET_ET4P 4232 // ANET ET4P V1.x (STM32F407VG) #define BOARD_ANET_ET4P 4232 // ANET ET4P V1.x (STM32F407VG)
#define BOARD_FYSETC_CHEETAH_V20 4233 // FYSETC Cheetah V2.0 #define BOARD_FYSETC_CHEETAH_V20 4233 // FYSETC Cheetah V2.0 (STM32F401RC)
#define BOARD_TH3D_EZBOARD_V2 4234 // TH3D EZBoard v2.0 #define BOARD_TH3D_EZBOARD_V2 4234 // TH3D EZBoard v2.0 (STM32F405RG)
#define BOARD_INDEX_REV03 4235 // Index PnP Controller REV03 (STM32F407VE/VG) #define BOARD_OPULO_LUMEN_REV3 4235 // Opulo Lumen PnP Controller REV3 (STM32F407VE / STM32F407VG)
#define BOARD_MKS_ROBIN_NANO_V1_3_F4 4236 // MKS Robin Nano V1.3 and MKS Robin Nano-S V1.3 (STM32F407VE) #define BOARD_MKS_ROBIN_NANO_V1_3_F4 4236 // MKS Robin Nano V1.3 and MKS Robin Nano-S V1.3 (STM32F407VE)
#define BOARD_MKS_EAGLE 4237 // MKS Eagle (STM32F407VE) #define BOARD_MKS_EAGLE 4237 // MKS Eagle (STM32F407VE)
#define BOARD_ARTILLERY_RUBY 4238 // Artillery Ruby (STM32F401RC) #define BOARD_ARTILLERY_RUBY 4238 // Artillery Ruby (STM32F401RC)
@@ -428,9 +430,10 @@
#define BOARD_TEENSY41 5001 // Teensy 4.1 #define BOARD_TEENSY41 5001 // Teensy 4.1
#define BOARD_T41U5XBB 5002 // T41U5XBB Teensy 4.1 breakout board #define BOARD_T41U5XBB 5002 // T41U5XBB Teensy 4.1 breakout board
#define BOARD_NUCLEO_F767ZI 5003 // ST NUCLEO-F767ZI Dev Board #define BOARD_NUCLEO_F767ZI 5003 // ST NUCLEO-F767ZI Dev Board
#define BOARD_BTT_SKR_SE_BX 5004 // BigTreeTech SKR SE BX (STM32H743II) #define BOARD_BTT_SKR_SE_BX_V2 5004 // BigTreeTech SKR SE BX V2.0 (STM32H743II)
#define BOARD_BTT_SKR_V3_0 5005 // BigTreeTech SKR V3.0 (STM32H743VG) #define BOARD_BTT_SKR_SE_BX_V3 5005 // BigTreeTech SKR SE BX V3.0 (STM32H743II)
#define BOARD_BTT_SKR_V3_0_EZ 5006 // BigTreeTech SKR V3.0 EZ (STM32H743VG) #define BOARD_BTT_SKR_V3_0 5006 // BigTreeTech SKR V3.0 (STM32H743VG)
#define BOARD_BTT_SKR_V3_0_EZ 5007 // BigTreeTech SKR V3.0 EZ (STM32H743VG)
// //
// Espressif ESP32 WiFi // Espressif ESP32 WiFi

View File

@@ -30,10 +30,6 @@
#define _A5984 0x5984 #define _A5984 0x5984
#define _DRV8825 0x8825 #define _DRV8825 0x8825
#define _LV8729 0x8729 #define _LV8729 0x8729
#define _L6470 0x6470
#define _L6474 0x6474
#define _L6480 0x6480
#define _POWERSTEP01 0xF00D
#define _TB6560 0x6560 #define _TB6560 0x6560
#define _TB6600 0x6600 #define _TB6600 0x6600
#define _TMC2100 0x2100 #define _TMC2100 0x2100
@@ -193,16 +189,3 @@
#if HAS_DRIVER(TMC26X) #if HAS_DRIVER(TMC26X)
#define HAS_TMC26X 1 #define HAS_TMC26X 1
#endif #endif
//
// L64XX Stepper Drivers
//
#if HAS_DRIVER(L6470) || HAS_DRIVER(L6474) || HAS_DRIVER(L6480) || HAS_DRIVER(POWERSTEP01)
#define HAS_L64XX 1
#endif
#if HAS_L64XX && !HAS_DRIVER(L6474)
#define HAS_L64XX_NOT_L6474 1
#endif
#define AXIS_IS_L64XX(A) (AXIS_DRIVER_TYPE_##A(L6470) || AXIS_DRIVER_TYPE_##A(L6474) || AXIS_DRIVER_TYPE_##A(L6480) || AXIS_DRIVER_TYPE_##A(POWERSTEP01))

View File

@@ -227,10 +227,6 @@
#define STR_PID_DEBUG " PID_DEBUG " #define STR_PID_DEBUG " PID_DEBUG "
#define STR_PID_DEBUG_INPUT ": Input " #define STR_PID_DEBUG_INPUT ": Input "
#define STR_PID_DEBUG_OUTPUT " Output " #define STR_PID_DEBUG_OUTPUT " Output "
#define STR_PID_DEBUG_PTERM " pTerm "
#define STR_PID_DEBUG_ITERM " iTerm "
#define STR_PID_DEBUG_DTERM " dTerm "
#define STR_PID_DEBUG_CTERM " cTerm "
#define STR_INVALID_EXTRUDER_NUM " - Invalid extruder number !" #define STR_INVALID_EXTRUDER_NUM " - Invalid extruder number !"
#define STR_MPC_AUTOTUNE "MPC Autotune" #define STR_MPC_AUTOTUNE "MPC Autotune"
#define STR_MPC_AUTOTUNE_START " start for " STR_E #define STR_MPC_AUTOTUNE_START " start for " STR_E

View File

@@ -644,8 +644,8 @@
#define IS_PROBE(V...) SECOND(V, 0) // Get the second item passed, or 0 #define IS_PROBE(V...) SECOND(V, 0) // Get the second item passed, or 0
#define PROBE() ~, 1 // Second item will be 1 if this is passed #define PROBE() ~, 1 // Second item will be 1 if this is passed
#define _NOT_0 PROBE() #define _NOT_0 PROBE()
#define NOT(x) IS_PROBE(_CAT(_NOT_, x)) // NOT('0') gets '1'. Anything else gets '0'. #define NOT(x) IS_PROBE(_CAT(_NOT_, x)) // NOT('0') gets '1'. Anything else gets '0'.
#define _BOOL(x) NOT(NOT(x)) // NOT('0') gets '0'. Anything else gets '1'. #define _BOOL(x) NOT(NOT(x)) // _BOOL('0') gets '0'. Anything else gets '1'.
#define IF_ELSE(TF) _IF_ELSE(_BOOL(TF)) #define IF_ELSE(TF) _IF_ELSE(_BOOL(TF))
#define _IF_ELSE(TF) _CAT(_IF_, TF) #define _IF_ELSE(TF) _CAT(_IF_, TF)
@@ -659,7 +659,6 @@
#define HAS_ARGS(V...) _BOOL(FIRST(_END_OF_ARGUMENTS_ V)()) #define HAS_ARGS(V...) _BOOL(FIRST(_END_OF_ARGUMENTS_ V)())
#define _END_OF_ARGUMENTS_() 0 #define _END_OF_ARGUMENTS_() 0
// Simple Inline IF Macros, friendly to use in other macro definitions // Simple Inline IF Macros, friendly to use in other macro definitions
#define IF(O, A, B) ((O) ? (A) : (B)) #define IF(O, A, B) ((O) ? (A) : (B))
#define IF_0(O, A) IF(O, A, 0) #define IF_0(O, A) IF(O, A, 0)
@@ -731,3 +730,8 @@
#define __MAPLIST() _MAPLIST #define __MAPLIST() _MAPLIST
#define MAPLIST(OP,V...) EVAL(_MAPLIST(OP,V)) #define MAPLIST(OP,V...) EVAL(_MAPLIST(OP,V))
// Temperature Sensor Config
#define _HAS_E_TEMP(N) || (TEMP_SENSOR_##N != 0)
#define HAS_E_TEMP_SENSOR (0 REPEAT(EXTRUDERS, _HAS_E_TEMP))
#define TEMP_SENSOR_IS_MAX_TC(T) (TEMP_SENSOR_##T == -5 || TEMP_SENSOR_##T == -3 || TEMP_SENSOR_##T == -2)

View File

@@ -72,8 +72,8 @@ void serial_print_P(PGM_P str) {
while (const char c = pgm_read_byte(str++)) SERIAL_CHAR(c); while (const char c = pgm_read_byte(str++)) SERIAL_CHAR(c);
} }
void serial_echo_start() { static PGMSTR(echomagic, "echo:"); serial_print_P(echomagic); } void serial_echo_start() { serial_print(F("echo:")); }
void serial_error_start() { static PGMSTR(errormagic, "Error:"); serial_print_P(errormagic); } void serial_error_start() { serial_print(F("Error:")); }
void serial_spaces(uint8_t count) { count *= (PROPORTIONAL_FONT_RATIO); while (count--) SERIAL_CHAR(' '); } void serial_spaces(uint8_t count) { count *= (PROPORTIONAL_FONT_RATIO); while (count--) SERIAL_CHAR(' '); }

View File

@@ -99,8 +99,8 @@ struct Flags {
void set(const int n) { b |= (bits_t)_BV(n); } void set(const int n) { b |= (bits_t)_BV(n); }
void clear(const int n) { b &= ~(bits_t)_BV(n); } void clear(const int n) { b &= ~(bits_t)_BV(n); }
bool test(const int n) const { return TEST(b, n); } bool test(const int n) const { return TEST(b, n); }
bool operator[](const int n) { return test(n); } const bool operator[](const int n) { return test(n); }
bool operator[](const int n) const { return test(n); } const bool operator[](const int n) const { return test(n); }
int size() const { return sizeof(b); } int size() const { return sizeof(b); }
}; };
@@ -113,8 +113,8 @@ struct Flags<1> {
void set(const int) { b = true; } void set(const int) { b = true; }
void clear(const int) { b = false; } void clear(const int) { b = false; }
bool test(const int) const { return b; } bool test(const int) const { return b; }
bool operator[](const int) { return b; } bool& operator[](const int) { return b; }
bool operator[](const int) const { return b; } bool operator[](const int) const { return b; }
int size() const { return sizeof(b); } int size() const { return sizeof(b); }
}; };
@@ -688,7 +688,7 @@ struct XYZEval {
FI const T& operator[](const int n) const { return pos[n]; } FI const T& operator[](const int n) const { return pos[n]; }
// Assignment operator overrides do the expected thing // Assignment operator overrides do the expected thing
FI XYZEval<T>& operator= (const T v) { set(LIST_N_1(NUM_AXES, v)); return *this; } FI XYZEval<T>& operator= (const T v) { set(LOGICAL_AXIS_LIST_1(v)); return *this; }
FI XYZEval<T>& operator= (const XYval<T> &rs) { set(rs.x, rs.y); return *this; } FI XYZEval<T>& operator= (const XYval<T> &rs) { set(rs.x, rs.y); return *this; }
FI XYZEval<T>& operator= (const XYZval<T> &rs) { set(NUM_AXIS_ELEM(rs)); return *this; } FI XYZEval<T>& operator= (const XYZval<T> &rs) { set(NUM_AXIS_ELEM(rs)); return *this; }

View File

@@ -29,10 +29,10 @@ void safe_delay(millis_t ms) {
while (ms > 50) { while (ms > 50) {
ms -= 50; ms -= 50;
delay(50); delay(50);
thermalManager.manage_heater(); thermalManager.task();
} }
delay(ms); delay(ms);
thermalManager.manage_heater(); // This keeps us safe if too many small safe_delay() calls are made thermalManager.task(); // This keeps us safe if too many small safe_delay() calls are made
} }
// A delay to provide brittle hosts time to receive bytes // A delay to provide brittle hosts time to receive bytes
@@ -51,7 +51,7 @@ void safe_delay(millis_t ms) {
#include "../module/probe.h" #include "../module/probe.h"
#include "../module/motion.h" #include "../module/motion.h"
#include "../module/stepper.h" #include "../module/planner.h"
#include "../libs/numtostr.h" #include "../libs/numtostr.h"
#include "../feature/bedlevel/bedlevel.h" #include "../feature/bedlevel/bedlevel.h"
@@ -70,6 +70,7 @@ void safe_delay(millis_t ms) {
TERN_(NOZZLE_AS_PROBE, "NOZZLE_AS_PROBE") TERN_(NOZZLE_AS_PROBE, "NOZZLE_AS_PROBE")
TERN_(FIX_MOUNTED_PROBE, "FIX_MOUNTED_PROBE") TERN_(FIX_MOUNTED_PROBE, "FIX_MOUNTED_PROBE")
TERN_(HAS_Z_SERVO_PROBE, TERN(BLTOUCH, "BLTOUCH", "SERVO PROBE")) TERN_(HAS_Z_SERVO_PROBE, TERN(BLTOUCH, "BLTOUCH", "SERVO PROBE"))
TERN_(BD_SENSOR, "BD_SENSOR")
TERN_(TOUCH_MI_PROBE, "TOUCH_MI_PROBE") TERN_(TOUCH_MI_PROBE, "TOUCH_MI_PROBE")
TERN_(Z_PROBE_SLED, "Z_PROBE_SLED") TERN_(Z_PROBE_SLED, "Z_PROBE_SLED")
TERN_(Z_PROBE_ALLEN_KEY, "Z_PROBE_ALLEN_KEY") TERN_(Z_PROBE_ALLEN_KEY, "Z_PROBE_ALLEN_KEY")
@@ -132,11 +133,10 @@ void safe_delay(millis_t ms) {
#else #else
#if ENABLED(AUTO_BED_LEVELING_UBL) #if ENABLED(AUTO_BED_LEVELING_UBL)
SERIAL_ECHOPGM("UBL Adjustment Z"); SERIAL_ECHOPGM("UBL Adjustment Z");
const float rz = bedlevel.get_z_correction(current_position);
#elif ENABLED(AUTO_BED_LEVELING_BILINEAR) #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
SERIAL_ECHOPGM("ABL Adjustment Z"); SERIAL_ECHOPGM("ABL Adjustment Z");
const float rz = bedlevel.get_z_correction(current_position);
#endif #endif
const float rz = bedlevel.get_z_correction(current_position);
SERIAL_ECHO(ftostr43sign(rz, '+')); SERIAL_ECHO(ftostr43sign(rz, '+'));
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
if (planner.z_fade_height) { if (planner.z_fade_height) {
@@ -156,11 +156,13 @@ void safe_delay(millis_t ms) {
SERIAL_ECHOPGM("Mesh Bed Leveling"); SERIAL_ECHOPGM("Mesh Bed Leveling");
if (planner.leveling_active) { if (planner.leveling_active) {
SERIAL_ECHOLNPGM(" (enabled)"); SERIAL_ECHOLNPGM(" (enabled)");
SERIAL_ECHOPGM("MBL Adjustment Z", ftostr43sign(bedlevel.get_z(current_position), '+')); const float z_offset = bedlevel.get_z_offset(),
z_correction = bedlevel.get_z_correction(current_position);
SERIAL_ECHOPGM("MBL Adjustment Z", ftostr43sign(z_offset + z_correction, '+'));
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
if (planner.z_fade_height) { if (planner.z_fade_height) {
SERIAL_ECHOPGM(" (", ftostr43sign( SERIAL_ECHOPGM(" (", ftostr43sign(
bedlevel.get_z(current_position, planner.fade_scaling_factor_for_z(current_position.z)), '+' z_offset + z_correction * planner.fade_scaling_factor_for_z(current_position.z), '+'
)); ));
SERIAL_CHAR(')'); SERIAL_CHAR(')');
} }

View File

@@ -59,6 +59,11 @@ void safe_delay(millis_t ms); // Delay ensuring that temperatures are
#define log_machine_info() NOOP #define log_machine_info() NOOP
#endif #endif
/**
* A restorer instance remembers a variable's value before setting a
* new value, then restores the old value when it goes out of scope.
* Put operator= on your type to get extended behavior on value change.
*/
template<typename T> template<typename T>
class restorer { class restorer {
T& ref_; T& ref_;

View File

@@ -54,6 +54,18 @@ void Babystep::add_mm(const AxisEnum axis, const_float_t mm) {
add_steps(axis, mm * planner.settings.axis_steps_per_mm[axis]); add_steps(axis, mm * planner.settings.axis_steps_per_mm[axis]);
} }
#if ENABLED(BD_SENSOR)
void Babystep::set_mm(const AxisEnum axis, const_float_t mm) {
//if (DISABLED(BABYSTEP_WITHOUT_HOMING) && axes_should_home(_BV(axis))) return;
const int16_t distance = mm * planner.settings.axis_steps_per_mm[axis];
accum = distance; // Count up babysteps for the UI
steps[BS_AXIS_IND(axis)] = distance;
TERN_(BABYSTEP_DISPLAY_TOTAL, axis_total[BS_TOTAL_IND(axis)] = distance);
TERN_(BABYSTEP_ALWAYS_AVAILABLE, gcode.reset_stepper_timeout());
TERN_(INTEGRATED_BABYSTEPPING, if (has_steps()) stepper.initiateBabystepping());
}
#endif
void Babystep::add_steps(const AxisEnum axis, const int16_t distance) { void Babystep::add_steps(const AxisEnum axis, const int16_t distance) {
if (DISABLED(BABYSTEP_WITHOUT_HOMING) && axes_should_home(_BV(axis))) return; if (DISABLED(BABYSTEP_WITHOUT_HOMING) && axes_should_home(_BV(axis))) return;

View File

@@ -63,6 +63,10 @@ public:
static void add_steps(const AxisEnum axis, const int16_t distance); static void add_steps(const AxisEnum axis, const int16_t distance);
static void add_mm(const AxisEnum axis, const_float_t mm); static void add_mm(const AxisEnum axis, const_float_t mm);
#if ENABLED(BD_SENSOR)
static void set_mm(const AxisEnum axis, const_float_t mm);
#endif
static bool has_steps() { static bool has_steps() {
return steps[BS_AXIS_IND(X_AXIS)] || steps[BS_AXIS_IND(Y_AXIS)] || steps[BS_AXIS_IND(Z_AXIS)]; return steps[BS_AXIS_IND(X_AXIS)] || steps[BS_AXIS_IND(Y_AXIS)] || steps[BS_AXIS_IND(Z_AXIS)];
} }

View File

@@ -0,0 +1,195 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "../../../inc/MarlinConfig.h"
#if ENABLED(BD_SENSOR)
#include "../../../MarlinCore.h"
#include "../../../gcode/gcode.h"
#include "../../../module/settings.h"
#include "../../../module/motion.h"
#include "../../../module/planner.h"
#include "../../../module/stepper.h"
#include "../../../module/probe.h"
#include "../../../module/temperature.h"
#include "../../../module/endstops.h"
#include "../../babystep.h"
// I2C software Master library for segment bed heating and bed distance sensor
#include <Panda_segmentBed_I2C.h>
#include "bdl.h"
BDS_Leveling bdl;
//#define DEBUG_OUT_BD
// M102 S-5 Read raw Calibrate data
// M102 S-6 Start Calibrate
// M102 S4 Set the adjustable Z height value (e.g., 'M102 S4' means it will do adjusting while the Z height <= 0.4mm , disable with 'M102 S0'.)
// M102 S-1 Read sensor information
#define MAX_BD_HEIGHT 4.0f
#define CMD_START_READ_CALIBRATE_DATA 1017
#define CMD_END_READ_CALIBRATE_DATA 1018
#define CMD_START_CALIBRATE 1019
#define CMD_END_CALIBRATE 1021
#define CMD_READ_VERSION 1016
I2C_SegmentBED BD_I2C_SENSOR;
#define BD_SENSOR_I2C_ADDR 0x3C
int8_t BDS_Leveling::config_state;
uint8_t BDS_Leveling::homing;
void BDS_Leveling::echo_name() { SERIAL_ECHOPGM("Bed Distance Leveling"); }
void BDS_Leveling::init(uint8_t _sda, uint8_t _scl, uint16_t delay_s) {
int ret = BD_I2C_SENSOR.i2c_init(_sda, _scl, BD_SENSOR_I2C_ADDR, delay_s);
if (ret != 1) SERIAL_ECHOLNPGM("BD_I2C_SENSOR Init Fail return code:", ret);
config_state = 0;
}
float BDS_Leveling::read() {
const uint16_t tmp = BD_I2C_SENSOR.BD_i2c_read();
float BD_z = NAN;
if (BD_I2C_SENSOR.BD_Check_OddEven(tmp) && (tmp & 0x3FF) < 1020)
BD_z = (tmp & 0x3FF) / 100.0f;
return BD_z;
}
void BDS_Leveling::process() {
//if (config_state == 0) return;
static millis_t next_check_ms = 0; // starting at T=0
static float z_pose = 0.0f;
const millis_t ms = millis();
if (ELAPSED(ms, next_check_ms)) { // timed out (or first run)
next_check_ms = ms + (config_state < 0 ? 1000 : 100); // check at 1Hz or 10Hz
unsigned short tmp = 0;
const float cur_z = planner.get_axis_position_mm(Z_AXIS); //current_position.z
static float old_cur_z = cur_z,
old_buf_z = current_position.z;
tmp = BD_I2C_SENSOR.BD_i2c_read();
if (BD_I2C_SENSOR.BD_Check_OddEven(tmp) && (tmp & 0x3FF) < 1020) {
const float z_sensor = (tmp & 0x3FF) / 100.0f;
if (cur_z < 0) config_state = 0;
//float abs_z = current_position.z > cur_z ? (current_position.z - cur_z) : (cur_z - current_position.z);
if ( cur_z < config_state * 0.1f
&& config_state > 0
&& old_cur_z == cur_z
&& old_buf_z == current_position.z
&& z_sensor < (MAX_BD_HEIGHT)
) {
babystep.set_mm(Z_AXIS, cur_z - z_sensor);
#if ENABLED(DEBUG_OUT_BD)
SERIAL_ECHOLNPGM("BD:", z_sensor, ", Z:", cur_z, "|", current_position.z);
#endif
}
else {
babystep.set_mm(Z_AXIS, 0);
//if (old_cur_z <= cur_z) Z_DIR_WRITE(!INVERT_Z_DIR);
stepper.set_directions();
}
old_cur_z = cur_z;
old_buf_z = current_position.z;
endstops.bdp_state_update(z_sensor <= 0.01f);
//endstops.update();
}
else
stepper.set_directions();
#if ENABLED(DEBUG_OUT_BD)
SERIAL_ECHOLNPGM("BD:", tmp & 0x3FF, ", Z:", cur_z, "|", current_position.z);
if (BD_I2C_SENSOR.BD_Check_OddEven(tmp) == 0) SERIAL_ECHOLNPGM("errorCRC");
#endif
if ((tmp & 0x3FF) > 1020) {
BD_I2C_SENSOR.BD_i2c_stop();
safe_delay(10);
}
// read raw calibrate data
if (config_state == -5) {
BD_I2C_SENSOR.BD_i2c_write(CMD_START_READ_CALIBRATE_DATA);
safe_delay(1000);
for (int i = 0; i < MAX_BD_HEIGHT * 10; i++) {
tmp = BD_I2C_SENSOR.BD_i2c_read();
SERIAL_ECHOLNPGM("Calibrate data:", i, ",", tmp & 0x3FF, ", check:", BD_I2C_SENSOR.BD_Check_OddEven(tmp));
safe_delay(500);
}
config_state = 0;
BD_I2C_SENSOR.BD_i2c_write(CMD_END_READ_CALIBRATE_DATA);
safe_delay(500);
}
else if (config_state <= -6) { // Start Calibrate
safe_delay(100);
if (config_state == -6) {
//BD_I2C_SENSOR.BD_i2c_write(1019); // begin calibrate
//delay(1000);
gcode.stepper_inactive_time = SEC_TO_MS(60 * 5);
gcode.process_subcommands_now(F("M17 Z"));
gcode.process_subcommands_now(F("G1 Z0.0"));
z_pose = 0;
safe_delay(1000);
BD_I2C_SENSOR.BD_i2c_write(CMD_START_CALIBRATE); // Begin calibrate
SERIAL_ECHOLNPGM("Begin calibrate");
safe_delay(2000);
config_state = -7;
}
else if (planner.get_axis_position_mm(Z_AXIS) < 10.0f) {
if (z_pose >= MAX_BD_HEIGHT) {
BD_I2C_SENSOR.BD_i2c_write(CMD_END_CALIBRATE); // End calibrate
SERIAL_ECHOLNPGM("End calibrate data");
z_pose = 7;
config_state = 0;
safe_delay(1000);
}
else {
float tmp_k = 0;
char tmp_1[30];
sprintf_P(tmp_1, PSTR("G1 Z%d.%d"), int(z_pose), int(int(z_pose * 10) % 10));
gcode.process_subcommands_now(tmp_1);
SERIAL_ECHO(tmp_1);
SERIAL_ECHOLNPGM(" ,Z:", current_position.z);
while (tmp_k < (z_pose - 0.1f)) {
tmp_k = planner.get_axis_position_mm(Z_AXIS);
safe_delay(1);
}
safe_delay(800);
tmp = (z_pose + 0.0001f) * 10;
BD_I2C_SENSOR.BD_i2c_write(tmp);
SERIAL_ECHOLNPGM("w:", tmp, ",Zpose:", z_pose);
z_pose += 0.1001f;
//queue.enqueue_now_P(PSTR("G90"));
}
}
}
}
}
#endif // BD_SENSOR

View File

@@ -0,0 +1,36 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <stdint.h>
class BDS_Leveling {
public:
static int8_t config_state;
static uint8_t homing;
static void echo_name();
static void init(uint8_t _sda, uint8_t _scl, uint16_t delay_s);
static void process();
static float read();
};
extern BDS_Leveling bdl;

View File

@@ -154,7 +154,7 @@ void reset_bed_level() {
#endif #endif
LOOP_L_N(x, sx) { LOOP_L_N(x, sx) {
SERIAL_CHAR(' '); SERIAL_CHAR(' ');
const float offset = values[x * sx + y]; const float offset = values[x * sy + y];
if (!isnan(offset)) { if (!isnan(offset)) {
if (offset >= 0) SERIAL_CHAR('+'); if (offset >= 0) SERIAL_CHAR('+');
SERIAL_ECHO_F(offset, int(precision)); SERIAL_ECHO_F(offset, int(precision));

View File

@@ -31,7 +31,6 @@
#include "../../../libs/hex_print.h" #include "../../../libs/hex_print.h"
#include "../../../module/settings.h" #include "../../../module/settings.h"
#include "../../../lcd/marlinui.h" #include "../../../lcd/marlinui.h"
#include "../../../module/stepper.h"
#include "../../../module/planner.h" #include "../../../module/planner.h"
#include "../../../module/motion.h" #include "../../../module/motion.h"
#include "../../../module/probe.h" #include "../../../module/probe.h"

View File

@@ -26,7 +26,6 @@
#include "../bedlevel.h" #include "../bedlevel.h"
#include "../../../module/planner.h" #include "../../../module/planner.h"
#include "../../../module/stepper.h"
#include "../../../module/motion.h" #include "../../../module/motion.h"
#if ENABLED(DELTA) #if ENABLED(DELTA)
@@ -36,8 +35,18 @@
#include "../../../MarlinCore.h" #include "../../../MarlinCore.h"
#include <math.h> #include <math.h>
//#define DEBUG_UBL_MOTION
#define DEBUG_OUT ENABLED(DEBUG_UBL_MOTION)
#include "../../../core/debug_out.h"
#if !UBL_SEGMENTED #if !UBL_SEGMENTED
// TODO: The first and last parts of a move might result in very short segment(s)
// after getting split on the cell boundary, so moves like that should not
// get split. This will be most common for moves that start/end near the
// corners of cells. To fix the issue, simply check if the start/end of the line
// is very close to a cell boundary in advance and don't split the line there.
void unified_bed_leveling::line_to_destination_cartesian(const_feedRate_t scaled_fr_mm_s, const uint8_t extruder) { void unified_bed_leveling::line_to_destination_cartesian(const_feedRate_t scaled_fr_mm_s, const uint8_t extruder) {
/** /**
* Much of the nozzle movement will be within the same cell. So we will do as little computation * Much of the nozzle movement will be within the same cell. So we will do as little computation
@@ -176,7 +185,9 @@
dest.z += z0; dest.z += z0;
planner.buffer_segment(dest, scaled_fr_mm_s, extruder); planner.buffer_segment(dest, scaled_fr_mm_s, extruder);
} //else printf("FIRST MOVE PRUNED "); }
else
DEBUG_ECHOLNPGM("[ubl] skip Y segment");
} }
// At the final destination? Usually not, but when on a Y Mesh Line it's completed. // At the final destination? Usually not, but when on a Y Mesh Line it's completed.
@@ -225,7 +236,9 @@
dest.z += z0; dest.z += z0;
if (!planner.buffer_segment(dest, scaled_fr_mm_s, extruder)) break; if (!planner.buffer_segment(dest, scaled_fr_mm_s, extruder)) break;
} //else printf("FIRST MOVE PRUNED "); }
else
DEBUG_ECHOLNPGM("[ubl] skip Y segment");
} }
if (xy_pos_t(current_position) != xy_pos_t(end)) if (xy_pos_t(current_position) != xy_pos_t(end))
@@ -360,11 +373,12 @@
#endif #endif
NOLESS(segments, 1U); // Must have at least one segment NOLESS(segments, 1U); // Must have at least one segment
const float inv_segments = 1.0f / segments, // Reciprocal to save calculation const float inv_segments = 1.0f / segments; // Reciprocal to save calculation
segment_xyz_mm = SQRT(cart_xy_mm_2 + sq(total.z)) * inv_segments; // Length of each segment
// Add hints to help optimize the move
PlannerHints hints(SQRT(cart_xy_mm_2 + sq(total.z)) * inv_segments); // Length of each segment
#if ENABLED(SCARA_FEEDRATE_SCALING) #if ENABLED(SCARA_FEEDRATE_SCALING)
const float inv_duration = scaled_fr_mm_s / segment_xyz_mm; hints.inv_duration = scaled_fr_mm_s / hints.millimeters;
#endif #endif
xyze_float_t diff = total * inv_segments; xyze_float_t diff = total * inv_segments;
@@ -378,13 +392,9 @@
if (!planner.leveling_active || !planner.leveling_active_at_z(destination.z)) { if (!planner.leveling_active || !planner.leveling_active_at_z(destination.z)) {
while (--segments) { while (--segments) {
raw += diff; raw += diff;
planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, segment_xyz_mm planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, hints);
OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)
);
} }
planner.buffer_line(destination, scaled_fr_mm_s, active_extruder, segment_xyz_mm planner.buffer_line(destination, scaled_fr_mm_s, active_extruder, hints);
OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)
);
return false; // Did not set current from destination return false; // Did not set current from destination
} }
@@ -453,7 +463,7 @@
TERN_(ENABLE_LEVELING_FADE_HEIGHT, * fade_scaling_factor); // apply fade factor to interpolated height TERN_(ENABLE_LEVELING_FADE_HEIGHT, * fade_scaling_factor); // apply fade factor to interpolated height
const float oldz = raw.z; raw.z += z_cxcy; const float oldz = raw.z; raw.z += z_cxcy;
planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, segment_xyz_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration) ); planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, hints);
raw.z = oldz; raw.z = oldz;
if (segments == 0) // done with last segment if (segments == 0) // done with last segment

View File

@@ -45,7 +45,7 @@ void stop();
bool BLTouch::command(const BLTCommand cmd, const millis_t &ms) { bool BLTouch::command(const BLTCommand cmd, const millis_t &ms) {
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("BLTouch Command :", cmd); if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("BLTouch Command :", cmd);
MOVE_SERVO(Z_PROBE_SERVO_NR, cmd); servo[Z_PROBE_SERVO_NR].move(cmd);
safe_delay(_MAX(ms, (uint32_t)BLTOUCH_DELAY)); // BLTOUCH_DELAY is also the *minimum* delay safe_delay(_MAX(ms, (uint32_t)BLTOUCH_DELAY)); // BLTOUCH_DELAY is also the *minimum* delay
return triggered(); return triggered();
} }

View File

@@ -11,7 +11,6 @@
#include "dac_dac084s085.h" #include "dac_dac084s085.h"
#include "../../MarlinCore.h" #include "../../MarlinCore.h"
#include "../../module/stepper.h"
#include "../../HAL/shared/Delay.h" #include "../../HAL/shared/Delay.h"
dac084s085::dac084s085() { } dac084s085::dac084s085() { }

View File

@@ -143,14 +143,16 @@ namespace DirectStepping {
// special case for 8-bit, check if rolled back to 0 // special case for 8-bit, check if rolled back to 0
if (Cfg::DIRECTIONAL || !write_page_size) { // full 256 bytes if (Cfg::DIRECTIONAL || !write_page_size) { // full 256 bytes
if (write_byte_idx) return true; if (write_byte_idx) return true;
} else {
if (write_byte_idx < write_page_size) return true;
} }
} else if (Cfg::DIRECTIONAL) { else if (write_byte_idx < write_page_size)
if (write_byte_idx != Cfg::PAGE_SIZE) return true; return true;
} else {
if (write_byte_idx < write_page_size) return true;
} }
else if (Cfg::DIRECTIONAL) {
if (write_byte_idx != Cfg::PAGE_SIZE)
return true;
}
else if (write_byte_idx < write_page_size)
return true;
state = State::CHECKSUM; state = State::CHECKSUM;
return true; return true;
@@ -161,11 +163,10 @@ namespace DirectStepping {
return true; return true;
} }
case State::UNFAIL: case State::UNFAIL:
if (c == 0) { if (c == 0)
set_page_state(write_page_idx, PageState::FREE); set_page_state(write_page_idx, PageState::FREE);
} else { else
fatal_error = true; fatal_error = true;
}
state = State::MONITOR; state = State::MONITOR;
return true; return true;
} }

View File

@@ -34,7 +34,6 @@ FWRetract fwretract; // Single instance - this calls the constructor
#include "../module/motion.h" #include "../module/motion.h"
#include "../module/planner.h" #include "../module/planner.h"
#include "../module/stepper.h"
#include "../gcode/gcode.h" #include "../gcode/gcode.h"

View File

@@ -172,8 +172,9 @@ Joystick joystick;
current_position += move_dist; current_position += move_dist;
apply_motion_limits(current_position); apply_motion_limits(current_position);
const float length = sqrt(hypot2); const float length = sqrt(hypot2);
PlannerHints hints(length);
injecting_now = true; injecting_now = true;
planner.buffer_line(current_position, length / seg_time, active_extruder, length); planner.buffer_line(current_position, length / seg_time, active_extruder, hints);
injecting_now = false; injecting_now = false;
} }
} }

View File

@@ -131,6 +131,13 @@ public:
// Accessors // Accessors
static uint16_t pixels() { return adaneo1.numPixels() * TERN1(NEOPIXEL2_INSERIES, 2); } static uint16_t pixels() { return adaneo1.numPixels() * TERN1(NEOPIXEL2_INSERIES, 2); }
static uint32_t pixel_color(const uint16_t n) {
#if ENABLED(NEOPIXEL2_INSERIES)
if (n >= NEOPIXEL_PIXELS) return adaneo2.getPixelColor(n - (NEOPIXEL_PIXELS));
#endif
return adaneo1.getPixelColor(n);
}
static uint8_t brightness() { return adaneo1.getBrightness(); } static uint8_t brightness() { return adaneo1.getBrightness(); }
static uint32_t Color(uint8_t r, uint8_t g, uint8_t b OPTARG(HAS_WHITE_LED, uint8_t w)) { static uint32_t Color(uint8_t r, uint8_t g, uint8_t b OPTARG(HAS_WHITE_LED, uint8_t w)) {
@@ -174,6 +181,7 @@ extern Marlin_NeoPixel neo;
// Accessors // Accessors
static uint16_t pixels() { return adaneo.numPixels();} static uint16_t pixels() { return adaneo.numPixels();}
static uint32_t pixel_color(const uint16_t n) { return adaneo.getPixelColor(n); }
static uint8_t brightness() { return adaneo.getBrightness(); } static uint8_t brightness() { return adaneo.getBrightness(); }
static uint32_t Color(uint8_t r, uint8_t g, uint8_t b OPTARG(HAS_WHITE_LED2, uint8_t w)) { static uint32_t Color(uint8_t r, uint8_t g, uint8_t b OPTARG(HAS_WHITE_LED2, uint8_t w)) {
return adaneo.Color(r, g, b OPTARG(HAS_WHITE_LED2, w)); return adaneo.Color(r, g, b OPTARG(HAS_WHITE_LED2, w));

View File

@@ -44,7 +44,6 @@
#include "max7219.h" #include "max7219.h"
#include "../module/planner.h" #include "../module/planner.h"
#include "../module/stepper.h"
#include "../MarlinCore.h" #include "../MarlinCore.h"
#include "../HAL/shared/Delay.h" #include "../HAL/shared/Delay.h"
@@ -52,6 +51,7 @@
#define HAS_SIDE_BY_SIDE 1 #define HAS_SIDE_BY_SIDE 1
#endif #endif
#define _ROT ((MAX7219_ROTATE + 360) % 360)
#if _ROT == 0 || _ROT == 180 #if _ROT == 0 || _ROT == 180
#define MAX7219_X_LEDS TERN(HAS_SIDE_BY_SIDE, 8, MAX7219_LINES) #define MAX7219_X_LEDS TERN(HAS_SIDE_BY_SIDE, 8, MAX7219_LINES)
#define MAX7219_Y_LEDS TERN(HAS_SIDE_BY_SIDE, MAX7219_LINES, 8) #define MAX7219_Y_LEDS TERN(HAS_SIDE_BY_SIDE, MAX7219_LINES, 8)
@@ -62,6 +62,15 @@
#error "MAX7219_ROTATE must be a multiple of +/- 90°." #error "MAX7219_ROTATE must be a multiple of +/- 90°."
#endif #endif
#ifdef MAX7219_DEBUG_PROFILE
CodeProfiler::Mode CodeProfiler::mode = ACCUMULATE_AVERAGE;
uint8_t CodeProfiler::instance_count = 0;
uint32_t CodeProfiler::last_calc_time = micros();
uint8_t CodeProfiler::time_fraction = 0;
uint32_t CodeProfiler::total_time = 0;
uint16_t CodeProfiler::call_count = 0;
#endif
Max7219 max7219; Max7219 max7219;
uint8_t Max7219::led_line[MAX7219_LINES]; // = { 0 }; uint8_t Max7219::led_line[MAX7219_LINES]; // = { 0 };
@@ -69,7 +78,7 @@ uint8_t Max7219::suspended; // = 0;
#define LINE_REG(Q) (max7219_reg_digit0 + ((Q) & 0x7)) #define LINE_REG(Q) (max7219_reg_digit0 + ((Q) & 0x7))
#if _ROT == 0 || _ROT == 270 #if (_ROT == 0 || _ROT == 270) == DISABLED(MAX7219_REVERSE_EACH)
#define _LED_BIT(Q) (7 - ((Q) & 0x7)) #define _LED_BIT(Q) (7 - ((Q) & 0x7))
#else #else
#define _LED_BIT(Q) ((Q) & 0x7) #define _LED_BIT(Q) ((Q) & 0x7)
@@ -266,26 +275,27 @@ void Max7219::set(const uint8_t line, const uint8_t bits) {
#endif // MAX7219_NUMERIC #endif // MAX7219_NUMERIC
// Modify a single LED bit and send the changed line // Modify a single LED bit and send the changed line
void Max7219::led_set(const uint8_t x, const uint8_t y, const bool on) { void Max7219::led_set(const uint8_t x, const uint8_t y, const bool on, uint8_t * const rcm/*=nullptr*/) {
if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(F("led_set"), x, y); if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(F("led_set"), x, y);
if (BIT_7219(x, y) == on) return; if (BIT_7219(x, y) == on) return;
XOR_7219(x, y); XOR_7219(x, y);
refresh_unit_line(LED_IND(x, y)); refresh_unit_line(LED_IND(x, y));
if (rcm != nullptr) *rcm |= _BV(LED_IND(x, y) & 0x07);
} }
void Max7219::led_on(const uint8_t x, const uint8_t y) { void Max7219::led_on(const uint8_t x, const uint8_t y, uint8_t * const rcm/*=nullptr*/) {
if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(F("led_on"), x, y); if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(F("led_on"), x, y);
led_set(x, y, true); led_set(x, y, true, rcm);
} }
void Max7219::led_off(const uint8_t x, const uint8_t y) { void Max7219::led_off(const uint8_t x, const uint8_t y, uint8_t * const rcm/*=nullptr*/) {
if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(F("led_off"), x, y); if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(F("led_off"), x, y);
led_set(x, y, false); led_set(x, y, false, rcm);
} }
void Max7219::led_toggle(const uint8_t x, const uint8_t y) { void Max7219::led_toggle(const uint8_t x, const uint8_t y, uint8_t * const rcm/*=nullptr*/) {
if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(F("led_toggle"), x, y); if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(F("led_toggle"), x, y);
led_set(x, y, !BIT_7219(x, y)); led_set(x, y, !BIT_7219(x, y), rcm);
} }
void Max7219::send_row(const uint8_t row) { void Max7219::send_row(const uint8_t row) {
@@ -448,7 +458,7 @@ void Max7219::register_setup() {
pulse_load(); // Tell the chips to load the clocked out data pulse_load(); // Tell the chips to load the clocked out data
} }
#ifdef MAX7219_INIT_TEST #if MAX7219_INIT_TEST
uint8_t test_mode = 0; uint8_t test_mode = 0;
millis_t next_patt_ms; millis_t next_patt_ms;
@@ -536,13 +546,9 @@ void Max7219::init() {
register_setup(); register_setup();
LOOP_LE_N(i, 7) { // Empty registers to turn all LEDs off clear();
led_line[i] = 0x00;
send(max7219_reg_digit0 + i, 0);
pulse_load(); // Tell the chips to load the clocked out data
}
#ifdef MAX7219_INIT_TEST #if MAX7219_INIT_TEST
start_test_pattern(); start_test_pattern();
#endif #endif
} }
@@ -554,41 +560,55 @@ void Max7219::init() {
*/ */
// Apply changes to update a marker // Apply changes to update a marker
void Max7219::mark16(const uint8_t pos, const uint8_t v1, const uint8_t v2) { void Max7219::mark16(const uint8_t pos, const uint8_t v1, const uint8_t v2, uint8_t * const rcm/*=nullptr*/) {
#if MAX7219_X_LEDS > 8 // At least 16 LEDs on the X-Axis. Use single line. #if MAX7219_X_LEDS > 8 // At least 16 LEDs on the X-Axis. Use single line.
led_off(v1 & 0xF, pos); led_off(v1 & 0xF, pos, rcm);
led_on(v2 & 0xF, pos); led_on(v2 & 0xF, pos, rcm);
#elif MAX7219_Y_LEDS > 8 // At least 16 LEDs on the Y-Axis. Use a single column. #elif MAX7219_Y_LEDS > 8 // At least 16 LEDs on the Y-Axis. Use a single column.
led_off(pos, v1 & 0xF); led_off(pos, v1 & 0xF, rcm);
led_on(pos, v2 & 0xF); led_on(pos, v2 & 0xF, rcm);
#else // Single 8x8 LED matrix. Use two lines to get 16 LEDs. #else // Single 8x8 LED matrix. Use two lines to get 16 LEDs.
led_off(v1 & 0x7, pos + (v1 >= 8)); led_off(v1 & 0x7, pos + (v1 >= 8), rcm);
led_on(v2 & 0x7, pos + (v2 >= 8)); led_on(v2 & 0x7, pos + (v2 >= 8), rcm);
#endif #endif
} }
// Apply changes to update a tail-to-head range // Apply changes to update a tail-to-head range
void Max7219::range16(const uint8_t y, const uint8_t ot, const uint8_t nt, const uint8_t oh, const uint8_t nh) { void Max7219::range16(const uint8_t y, const uint8_t ot, const uint8_t nt, const uint8_t oh,
const uint8_t nh, uint8_t * const rcm/*=nullptr*/) {
#if MAX7219_X_LEDS > 8 // At least 16 LEDs on the X-Axis. Use single line. #if MAX7219_X_LEDS > 8 // At least 16 LEDs on the X-Axis. Use single line.
if (ot != nt) for (uint8_t n = ot & 0xF; n != (nt & 0xF) && n != (nh & 0xF); n = (n + 1) & 0xF) if (ot != nt) for (uint8_t n = ot & 0xF; n != (nt & 0xF) && n != (nh & 0xF); n = (n + 1) & 0xF)
led_off(n & 0xF, y); led_off(n & 0xF, y, rcm);
if (oh != nh) for (uint8_t n = (oh + 1) & 0xF; n != ((nh + 1) & 0xF); n = (n + 1) & 0xF) if (oh != nh) for (uint8_t n = (oh + 1) & 0xF; n != ((nh + 1) & 0xF); n = (n + 1) & 0xF)
led_on(n & 0xF, y); led_on(n & 0xF, y, rcm);
#elif MAX7219_Y_LEDS > 8 // At least 16 LEDs on the Y-Axis. Use a single column. #elif MAX7219_Y_LEDS > 8 // At least 16 LEDs on the Y-Axis. Use a single column.
if (ot != nt) for (uint8_t n = ot & 0xF; n != (nt & 0xF) && n != (nh & 0xF); n = (n + 1) & 0xF) if (ot != nt) for (uint8_t n = ot & 0xF; n != (nt & 0xF) && n != (nh & 0xF); n = (n + 1) & 0xF)
led_off(y, n & 0xF); led_off(y, n & 0xF, rcm);
if (oh != nh) for (uint8_t n = (oh + 1) & 0xF; n != ((nh + 1) & 0xF); n = (n + 1) & 0xF) if (oh != nh) for (uint8_t n = (oh + 1) & 0xF; n != ((nh + 1) & 0xF); n = (n + 1) & 0xF)
led_on(y, n & 0xF); led_on(y, n & 0xF, rcm);
#else // Single 8x8 LED matrix. Use two lines to get 16 LEDs. #else // Single 8x8 LED matrix. Use two lines to get 16 LEDs.
if (ot != nt) for (uint8_t n = ot & 0xF; n != (nt & 0xF) && n != (nh & 0xF); n = (n + 1) & 0xF) if (ot != nt) for (uint8_t n = ot & 0xF; n != (nt & 0xF) && n != (nh & 0xF); n = (n + 1) & 0xF)
led_off(n & 0x7, y + (n >= 8)); led_off(n & 0x7, y + (n >= 8), rcm);
if (oh != nh) for (uint8_t n = (oh + 1) & 0xF; n != ((nh + 1) & 0xF); n = (n + 1) & 0xF) if (oh != nh) for (uint8_t n = (oh + 1) & 0xF; n != ((nh + 1) & 0xF); n = (n + 1) & 0xF)
led_on(n & 0x7, y + (n >= 8)); led_on(n & 0x7, y + (n >= 8), rcm);
#endif #endif
} }
// Apply changes to update a quantity // Apply changes to update a quantity
void Max7219::quantity16(const uint8_t pos, const uint8_t ov, const uint8_t nv) { void Max7219::quantity(const uint8_t pos, const uint8_t ov, const uint8_t nv, uint8_t * const rcm/*=nullptr*/) {
for (uint8_t i = _MIN(nv, ov); i < _MAX(nv, ov); i++)
led_set(
#if MAX7219_X_LEDS >= MAX7219_Y_LEDS
i, pos // Single matrix or multiple matrices in Landscape
#else
pos, i // Multiple matrices in Portrait
#endif
, nv >= ov
, rcm
);
}
void Max7219::quantity16(const uint8_t pos, const uint8_t ov, const uint8_t nv, uint8_t * const rcm/*=nullptr*/) {
for (uint8_t i = _MIN(nv, ov); i < _MAX(nv, ov); i++) for (uint8_t i = _MIN(nv, ov); i < _MAX(nv, ov); i++)
led_set( led_set(
#if MAX7219_X_LEDS > 8 // At least 16 LEDs on the X-Axis. Use single line. #if MAX7219_X_LEDS > 8 // At least 16 LEDs on the X-Axis. Use single line.
@@ -599,6 +619,7 @@ void Max7219::quantity16(const uint8_t pos, const uint8_t ov, const uint8_t nv)
i >> 1, pos + (i & 1) i >> 1, pos + (i & 1)
#endif #endif
, nv >= ov , nv >= ov
, rcm
); );
} }
@@ -636,16 +657,20 @@ void Max7219::idle_tasks() {
register_setup(); register_setup();
} }
#ifdef MAX7219_INIT_TEST #if MAX7219_INIT_TEST
if (test_mode) { if (test_mode) {
run_test_pattern(); run_test_pattern();
return; return;
} }
#endif #endif
// suspend updates and record which lines have changed for batching later
suspended++;
uint8_t row_change_mask = 0x00;
#if ENABLED(MAX7219_DEBUG_PRINTER_ALIVE) #if ENABLED(MAX7219_DEBUG_PRINTER_ALIVE)
if (do_blink) { if (do_blink) {
led_toggle(MAX7219_X_LEDS - 1, MAX7219_Y_LEDS - 1); led_toggle(MAX7219_X_LEDS - 1, MAX7219_Y_LEDS - 1, &row_change_mask);
next_blink = ms + 1000; next_blink = ms + 1000;
} }
#endif #endif
@@ -655,7 +680,7 @@ void Max7219::idle_tasks() {
static int16_t last_head_cnt = 0xF, last_tail_cnt = 0xF; static int16_t last_head_cnt = 0xF, last_tail_cnt = 0xF;
if (last_head_cnt != head || last_tail_cnt != tail) { if (last_head_cnt != head || last_tail_cnt != tail) {
range16(MAX7219_DEBUG_PLANNER_HEAD, last_tail_cnt, tail, last_head_cnt, head); range16(MAX7219_DEBUG_PLANNER_HEAD, last_tail_cnt, tail, last_head_cnt, head, &row_change_mask);
last_head_cnt = head; last_head_cnt = head;
last_tail_cnt = tail; last_tail_cnt = tail;
} }
@@ -665,7 +690,7 @@ void Max7219::idle_tasks() {
#ifdef MAX7219_DEBUG_PLANNER_HEAD #ifdef MAX7219_DEBUG_PLANNER_HEAD
static int16_t last_head_cnt = 0x1; static int16_t last_head_cnt = 0x1;
if (last_head_cnt != head) { if (last_head_cnt != head) {
mark16(MAX7219_DEBUG_PLANNER_HEAD, last_head_cnt, head); mark16(MAX7219_DEBUG_PLANNER_HEAD, last_head_cnt, head, &row_change_mask);
last_head_cnt = head; last_head_cnt = head;
} }
#endif #endif
@@ -673,7 +698,7 @@ void Max7219::idle_tasks() {
#ifdef MAX7219_DEBUG_PLANNER_TAIL #ifdef MAX7219_DEBUG_PLANNER_TAIL
static int16_t last_tail_cnt = 0x1; static int16_t last_tail_cnt = 0x1;
if (last_tail_cnt != tail) { if (last_tail_cnt != tail) {
mark16(MAX7219_DEBUG_PLANNER_TAIL, last_tail_cnt, tail); mark16(MAX7219_DEBUG_PLANNER_TAIL, last_tail_cnt, tail, &row_change_mask);
last_tail_cnt = tail; last_tail_cnt = tail;
} }
#endif #endif
@@ -684,11 +709,26 @@ void Max7219::idle_tasks() {
static int16_t last_depth = 0; static int16_t last_depth = 0;
const int16_t current_depth = (head - tail + BLOCK_BUFFER_SIZE) & (BLOCK_BUFFER_SIZE - 1) & 0xF; const int16_t current_depth = (head - tail + BLOCK_BUFFER_SIZE) & (BLOCK_BUFFER_SIZE - 1) & 0xF;
if (current_depth != last_depth) { if (current_depth != last_depth) {
quantity16(MAX7219_DEBUG_PLANNER_QUEUE, last_depth, current_depth); quantity16(MAX7219_DEBUG_PLANNER_QUEUE, last_depth, current_depth, &row_change_mask);
last_depth = current_depth; last_depth = current_depth;
} }
#endif #endif
#ifdef MAX7219_DEBUG_PROFILE
static uint8_t last_time_fraction = 0;
const uint8_t current_time_fraction = (uint16_t(CodeProfiler::get_time_fraction()) * MAX7219_NUMBER_UNITS + 8) / 16;
if (current_time_fraction != last_time_fraction) {
quantity(MAX7219_DEBUG_PROFILE, last_time_fraction, current_time_fraction, &row_change_mask);
last_time_fraction = current_time_fraction;
}
#endif
// batch line updates
suspended--;
if (!suspended)
LOOP_L_N(i, 8) if (row_change_mask & _BV(i))
refresh_line(i);
// After resume() automatically do a refresh() // After resume() automatically do a refresh()
if (suspended == 0x80) { if (suspended == 0x80) {
suspended = 0; suspended = 0;

View File

@@ -47,7 +47,6 @@
#ifndef MAX7219_ROTATE #ifndef MAX7219_ROTATE
#define MAX7219_ROTATE 0 #define MAX7219_ROTATE 0
#endif #endif
#define _ROT ((MAX7219_ROTATE + 360) % 360)
#ifndef MAX7219_NUMBER_UNITS #ifndef MAX7219_NUMBER_UNITS
#define MAX7219_NUMBER_UNITS 1 #define MAX7219_NUMBER_UNITS 1
@@ -73,6 +72,67 @@
#define max7219_reg_shutdown 0x0C #define max7219_reg_shutdown 0x0C
#define max7219_reg_displayTest 0x0F #define max7219_reg_displayTest 0x0F
#ifdef MAX7219_DEBUG_PROFILE
// This class sums up the amount of time for which its instances exist.
// By default there is one instantiated for the duration of the idle()
// function. But an instance can be created in any code block to measure
// the time spent from the point of instantiation until the CPU leaves
// block. Be careful about having multiple instances of CodeProfiler as
// it does not guard against double counting. In general mixing ISR and
// non-ISR use will require critical sections but note that mode setting
// is atomic so the total or average times can safely be read if you set
// mode to FREEZE first.
class CodeProfiler {
public:
enum Mode : uint8_t { ACCUMULATE_AVERAGE, ACCUMULATE_TOTAL, FREEZE };
private:
static Mode mode;
static uint8_t instance_count;
static uint32_t last_calc_time;
static uint32_t total_time;
static uint8_t time_fraction;
static uint16_t call_count;
uint32_t start_time;
public:
CodeProfiler() : start_time(micros()) { instance_count++; }
~CodeProfiler() {
instance_count--;
if (mode == FREEZE) return;
call_count++;
const uint32_t now = micros();
total_time += now - start_time;
if (mode == ACCUMULATE_TOTAL) return;
// update time_fraction every hundred milliseconds
if (instance_count == 0 && ELAPSED(now, last_calc_time + 100000)) {
time_fraction = total_time * 128 / (now - last_calc_time);
last_calc_time = now;
total_time = 0;
}
}
static void set_mode(Mode _mode) { mode = _mode; }
static void reset() {
time_fraction = 0;
last_calc_time = micros();
total_time = 0;
call_count = 0;
}
// returns fraction of total time which was measured, scaled from 0 to 128
static uint8_t get_time_fraction() { return time_fraction; }
// returns total time in microseconds
static uint32_t get_total_time() { return total_time; }
static uint16_t get_call_count() { return call_count; }
};
#endif
class Max7219 { class Max7219 {
public: public:
static uint8_t led_line[MAX7219_LINES]; static uint8_t led_line[MAX7219_LINES];
@@ -110,10 +170,10 @@ public:
#endif #endif
// Set a single LED by XY coordinate // Set a single LED by XY coordinate
static void led_set(const uint8_t x, const uint8_t y, const bool on); static void led_set(const uint8_t x, const uint8_t y, const bool on, uint8_t * const rcm=nullptr);
static void led_on(const uint8_t x, const uint8_t y); static void led_on(const uint8_t x, const uint8_t y, uint8_t * const rcm=nullptr);
static void led_off(const uint8_t x, const uint8_t y); static void led_off(const uint8_t x, const uint8_t y, uint8_t * const rcm=nullptr);
static void led_toggle(const uint8_t x, const uint8_t y); static void led_toggle(const uint8_t x, const uint8_t y, uint8_t * const rcm=nullptr);
// Set all LEDs in a single column // Set all LEDs in a single column
static void set_column(const uint8_t col, const uint32_t val); static void set_column(const uint8_t col, const uint32_t val);
@@ -147,11 +207,12 @@ private:
static void set(const uint8_t line, const uint8_t bits); static void set(const uint8_t line, const uint8_t bits);
static void send_row(const uint8_t row); static void send_row(const uint8_t row);
static void send_column(const uint8_t col); static void send_column(const uint8_t col);
static void mark16(const uint8_t y, const uint8_t v1, const uint8_t v2); static void mark16(const uint8_t y, const uint8_t v1, const uint8_t v2, uint8_t * const rcm=nullptr);
static void range16(const uint8_t y, const uint8_t ot, const uint8_t nt, const uint8_t oh, const uint8_t nh); static void range16(const uint8_t y, const uint8_t ot, const uint8_t nt, const uint8_t oh, const uint8_t nh, uint8_t * const rcm=nullptr);
static void quantity16(const uint8_t y, const uint8_t ov, const uint8_t nv); static void quantity(const uint8_t y, const uint8_t ov, const uint8_t nv, uint8_t * const rcm=nullptr);
static void quantity16(const uint8_t y, const uint8_t ov, const uint8_t nv, uint8_t * const rcm=nullptr);
#ifdef MAX7219_INIT_TEST #if MAX7219_INIT_TEST
static void test_pattern(); static void test_pattern();
static void run_test_pattern(); static void run_test_pattern();
static void start_test_pattern(); static void start_test_pattern();

View File

@@ -35,10 +35,13 @@
#include "../gcode/gcode.h" #include "../gcode/gcode.h"
#include "../module/motion.h" #include "../module/motion.h"
#include "../module/planner.h" #include "../module/planner.h"
#include "../module/stepper.h"
#include "../module/printcounter.h" #include "../module/printcounter.h"
#include "../module/temperature.h" #include "../module/temperature.h"
#if HAS_EXTRUDERS
#include "../module/stepper.h"
#endif
#if ENABLED(AUTO_BED_LEVELING_UBL) #if ENABLED(AUTO_BED_LEVELING_UBL)
#include "bedlevel/bedlevel.h" #include "bedlevel/bedlevel.h"
#endif #endif
@@ -63,7 +66,7 @@
#include "../lcd/marlinui.h" #include "../lcd/marlinui.h"
#if HAS_BUZZER #if HAS_SOUND
#include "../libs/buzzer.h" #include "../libs/buzzer.h"
#endif #endif
@@ -98,7 +101,7 @@ fil_change_settings_t fc_settings[EXTRUDERS];
#define _PMSG(L) L##_LCD #define _PMSG(L) L##_LCD
#endif #endif
#if HAS_BUZZER #if HAS_SOUND
static void impatient_beep(const int8_t max_beep_count, const bool restart=false) { static void impatient_beep(const int8_t max_beep_count, const bool restart=false) {
if (TERN0(HAS_MARLINUI_MENU, pause_mode == PAUSE_MODE_PAUSE_PRINT)) return; if (TERN0(HAS_MARLINUI_MENU, pause_mode == PAUSE_MODE_PAUSE_PRINT)) return;
@@ -711,9 +714,13 @@ void resume_print(const_float_t slow_load_length/*=0*/, const_float_t fast_load_
TERN_(HAS_FILAMENT_SENSOR, runout.reset()); TERN_(HAS_FILAMENT_SENSOR, runout.reset());
TERN(DWIN_LCD_PROUI, DWIN_Print_Resume(), ui.reset_status()); #if ENABLED(DWIN_LCD_PROUI)
TERN_(HAS_MARLINUI_MENU, ui.return_to_status()); DWIN_Print_Resume();
TERN_(DWIN_LCD_PROUI, HMI_ReturnScreen()); HMI_ReturnScreen();
#else
ui.reset_status();
ui.return_to_status();
#endif
} }
#endif // ADVANCED_PAUSE_FEATURE #endif // ADVANCED_PAUSE_FEATURE

View File

@@ -30,7 +30,7 @@
#include "power.h" #include "power.h"
#include "../module/planner.h" #include "../module/planner.h"
#include "../module/stepper.h" #include "../module/stepper/indirection.h" // for restore_stepper_drivers
#include "../module/temperature.h" #include "../module/temperature.h"
#include "../MarlinCore.h" #include "../MarlinCore.h"
@@ -46,6 +46,7 @@ Power powerManager;
bool Power::psu_on; bool Power::psu_on;
#if ENABLED(AUTO_POWER_CONTROL) #if ENABLED(AUTO_POWER_CONTROL)
#include "../module/stepper.h"
#include "../module/temperature.h" #include "../module/temperature.h"
#if BOTH(USE_CONTROLLER_FAN, AUTO_POWER_CONTROLLERFAN) #if BOTH(USE_CONTROLLER_FAN, AUTO_POWER_CONTROLLERFAN)

View File

@@ -53,7 +53,7 @@ PowerMonitor power_monitor; // Single instance - this calls the constructor
void PowerMonitor::draw_current() { void PowerMonitor::draw_current() {
const float amps = getAmps(); const float amps = getAmps();
lcd_put_u8str(amps < 100 ? ftostr31ns(amps) : ui16tostr4rj((uint16_t)amps)); lcd_put_u8str(amps < 100 ? ftostr31ns(amps) : ui16tostr4rj((uint16_t)amps));
lcd_put_wchar('A'); lcd_put_lchar('A');
} }
#endif #endif
@@ -61,7 +61,7 @@ PowerMonitor power_monitor; // Single instance - this calls the constructor
void PowerMonitor::draw_voltage() { void PowerMonitor::draw_voltage() {
const float volts = getVolts(); const float volts = getVolts();
lcd_put_u8str(volts < 100 ? ftostr31ns(volts) : ui16tostr4rj((uint16_t)volts)); lcd_put_u8str(volts < 100 ? ftostr31ns(volts) : ui16tostr4rj((uint16_t)volts));
lcd_put_wchar('V'); lcd_put_lchar('V');
} }
#endif #endif
@@ -69,7 +69,7 @@ PowerMonitor power_monitor; // Single instance - this calls the constructor
void PowerMonitor::draw_power() { void PowerMonitor::draw_power() {
const float power = getPower(); const float power = getPower();
lcd_put_u8str(power < 100 ? ftostr31ns(power) : ui16tostr4rj((uint16_t)power)); lcd_put_u8str(power < 100 ? ftostr31ns(power) : ui16tostr4rj((uint16_t)power));
lcd_put_wchar('W'); lcd_put_lchar('W');
} }
#endif #endif

View File

@@ -32,7 +32,7 @@ struct pm_lpf_t {
uint32_t filter_buf; uint32_t filter_buf;
float value; float value;
void add_sample(const uint16_t sample) { void add_sample(const uint16_t sample) {
filter_buf = filter_buf - (filter_buf >> K_VALUE) + (uint32_t(sample) << K_SCALE); filter_buf += (uint32_t(sample) << K_SCALE) - (filter_buf >> K_VALUE);
} }
void capture() { void capture() {
value = filter_buf * (SCALE * (1.0f / (1UL << (PM_K_VALUE + PM_K_SCALE)))); value = filter_buf * (SCALE * (1.0f / (1UL << (PM_K_VALUE + PM_K_SCALE))));

View File

@@ -39,18 +39,26 @@
#endif #endif
SpindleLaser cutter; SpindleLaser cutter;
uint8_t SpindleLaser::power, bool SpindleLaser::enable_state; // Virtual enable state, controls enable pin if present and or apply power if > 0
uint8_t SpindleLaser::power, // Actual power output 0-255 ocr or "0 = off" > 0 = "on"
SpindleLaser::last_power_applied; // = 0 // Basic power state tracking SpindleLaser::last_power_applied; // = 0 // Basic power state tracking
#if ENABLED(LASER_FEATURE)
cutter_test_pulse_t SpindleLaser::testPulse = 50; // Test fire Pulse time ms value.
#endif
bool SpindleLaser::isReady; // Ready to apply power setting from the UI to OCR
cutter_power_t SpindleLaser::menuPower, // Power set via LCD menu in PWM, PERCENT, or RPM
SpindleLaser::unitPower; // LCD status power in PWM, PERCENT, or RPM
#if ENABLED(MARLIN_DEV_MODE) #if ENABLED(LASER_FEATURE)
cutter_frequency_t SpindleLaser::frequency; // PWM frequency setting; range: 2K - 50K cutter_test_pulse_t SpindleLaser::testPulse = 50; // (ms) Test fire pulse default duration
uint8_t SpindleLaser::last_block_power; // = 0 // Track power changes for dynamic inline power
feedRate_t SpindleLaser::feedrate_mm_m = 1500,
SpindleLaser::last_feedrate_mm_m; // = 0 // (mm/min) Track feedrate changes for dynamic power
#endif #endif
bool SpindleLaser::isReadyForUI = false; // Ready to apply power setting from the UI to OCR
CutterMode SpindleLaser::cutter_mode = CUTTER_MODE_STANDARD; // Default is standard mode
constexpr cutter_cpower_t SpindleLaser::power_floor;
cutter_power_t SpindleLaser::menuPower = 0, // Power value via LCD menu in PWM, PERCENT, or RPM based on configured format set by CUTTER_POWER_UNIT.
SpindleLaser::unitPower = 0; // Unit power is in PWM, PERCENT, or RPM based on CUTTER_POWER_UNIT.
cutter_frequency_t SpindleLaser::frequency; // PWM frequency setting; range: 2K - 50K
#define SPINDLE_LASER_PWM_OFF TERN(SPINDLE_LASER_PWM_INVERT, 255, 0) #define SPINDLE_LASER_PWM_OFF TERN(SPINDLE_LASER_PWM_INVERT, 255, 0)
/** /**
@@ -58,21 +66,21 @@ cutter_power_t SpindleLaser::menuPower, // Power s
*/ */
void SpindleLaser::init() { void SpindleLaser::init() {
#if ENABLED(SPINDLE_SERVO) #if ENABLED(SPINDLE_SERVO)
MOVE_SERVO(SPINDLE_SERVO_NR, SPINDLE_SERVO_MIN); servo[SPINDLE_SERVO_NR].move(SPINDLE_SERVO_MIN);
#else #elif PIN_EXISTS(SPINDLE_LASER_ENA)
OUT_WRITE(SPINDLE_LASER_ENA_PIN, !SPINDLE_LASER_ACTIVE_STATE); // Init spindle to off OUT_WRITE(SPINDLE_LASER_ENA_PIN, !SPINDLE_LASER_ACTIVE_STATE); // Init spindle to off
#endif #endif
#if ENABLED(SPINDLE_CHANGE_DIR) #if ENABLED(SPINDLE_CHANGE_DIR)
OUT_WRITE(SPINDLE_DIR_PIN, SPINDLE_INVERT_DIR); // Init rotation to clockwise (M3) OUT_WRITE(SPINDLE_DIR_PIN, SPINDLE_INVERT_DIR); // Init rotation to clockwise (M3)
#endif #endif
#if ENABLED(HAL_CAN_SET_PWM_FREQ) && SPINDLE_LASER_FREQUENCY
frequency = SPINDLE_LASER_FREQUENCY;
hal.set_pwm_frequency(pin_t(SPINDLE_LASER_PWM_PIN), SPINDLE_LASER_FREQUENCY);
#endif
#if ENABLED(SPINDLE_LASER_USE_PWM) #if ENABLED(SPINDLE_LASER_USE_PWM)
SET_PWM(SPINDLE_LASER_PWM_PIN); SET_PWM(SPINDLE_LASER_PWM_PIN);
hal.set_pwm_duty(pin_t(SPINDLE_LASER_PWM_PIN), SPINDLE_LASER_PWM_OFF); // Set to lowest speed hal.set_pwm_duty(pin_t(SPINDLE_LASER_PWM_PIN), SPINDLE_LASER_PWM_OFF); // Set to lowest speed
#endif #endif
#if ENABLED(HAL_CAN_SET_PWM_FREQ) && SPINDLE_LASER_FREQUENCY
hal.set_pwm_frequency(pin_t(SPINDLE_LASER_PWM_PIN), SPINDLE_LASER_FREQUENCY);
TERN_(MARLIN_DEV_MODE, frequency = SPINDLE_LASER_FREQUENCY);
#endif
#if ENABLED(AIR_EVACUATION) #if ENABLED(AIR_EVACUATION)
OUT_WRITE(AIR_EVACUATION_PIN, !AIR_EVACUATION_ACTIVE); // Init Vacuum/Blower OFF OUT_WRITE(AIR_EVACUATION_PIN, !AIR_EVACUATION_ACTIVE); // Init Vacuum/Blower OFF
#endif #endif
@@ -90,52 +98,62 @@ void SpindleLaser::init() {
*/ */
void SpindleLaser::_set_ocr(const uint8_t ocr) { void SpindleLaser::_set_ocr(const uint8_t ocr) {
#if ENABLED(HAL_CAN_SET_PWM_FREQ) && SPINDLE_LASER_FREQUENCY #if ENABLED(HAL_CAN_SET_PWM_FREQ) && SPINDLE_LASER_FREQUENCY
hal.set_pwm_frequency(pin_t(SPINDLE_LASER_PWM_PIN), TERN(MARLIN_DEV_MODE, frequency, SPINDLE_LASER_FREQUENCY)); hal.set_pwm_frequency(pin_t(SPINDLE_LASER_PWM_PIN), frequency);
#endif #endif
hal.set_pwm_duty(pin_t(SPINDLE_LASER_PWM_PIN), ocr ^ SPINDLE_LASER_PWM_OFF); hal.set_pwm_duty(pin_t(SPINDLE_LASER_PWM_PIN), ocr ^ SPINDLE_LASER_PWM_OFF);
} }
void SpindleLaser::set_ocr(const uint8_t ocr) { void SpindleLaser::set_ocr(const uint8_t ocr) {
WRITE(SPINDLE_LASER_ENA_PIN, SPINDLE_LASER_ACTIVE_STATE); // Cutter ON #if PIN_EXISTS(SPINDLE_LASER_ENA)
WRITE(SPINDLE_LASER_ENA_PIN, SPINDLE_LASER_ACTIVE_STATE); // Cutter ON
#endif
_set_ocr(ocr); _set_ocr(ocr);
} }
void SpindleLaser::ocr_off() { void SpindleLaser::ocr_off() {
WRITE(SPINDLE_LASER_ENA_PIN, !SPINDLE_LASER_ACTIVE_STATE); // Cutter OFF #if PIN_EXISTS(SPINDLE_LASER_ENA)
WRITE(SPINDLE_LASER_ENA_PIN, !SPINDLE_LASER_ACTIVE_STATE); // Cutter OFF
#endif
_set_ocr(0); _set_ocr(0);
} }
#endif // SPINDLE_LASER_USE_PWM #endif // SPINDLE_LASER_USE_PWM
/** /**
* Apply power for laser/spindle * Apply power for Laser or Spindle
* *
* Apply cutter power value for PWM, Servo, and on/off pin. * Apply cutter power value for PWM, Servo, and on/off pin.
* *
* @param opwr Power value. Range 0 to MAX. When 0 disable spindle/laser. * @param opwr Power value. Range 0 to MAX.
*/ */
void SpindleLaser::apply_power(const uint8_t opwr) { void SpindleLaser::apply_power(const uint8_t opwr) {
if (opwr == last_power_applied) return; if (enabled() || opwr == 0) { // 0 check allows us to disable where no ENA pin exists
last_power_applied = opwr; // Test and set the last power used to improve performance
power = opwr; if (opwr == last_power_applied) return;
#if ENABLED(SPINDLE_LASER_USE_PWM) last_power_applied = opwr;
if (cutter.unitPower == 0 && CUTTER_UNIT_IS(RPM)) { // Handle PWM driven or just simple on/off
ocr_off(); #if ENABLED(SPINDLE_LASER_USE_PWM)
isReady = false; if (CUTTER_UNIT_IS(RPM) && unitPower == 0)
} ocr_off();
else if (ENABLED(CUTTER_POWER_RELATIVE) || enabled()) { else if (ENABLED(CUTTER_POWER_RELATIVE) || enabled() || opwr == 0) {
set_ocr(power); set_ocr(opwr);
isReady = true; isReadyForUI = true;
} }
else { else
ocr_off(); ocr_off();
isReady = false; #elif ENABLED(SPINDLE_SERVO)
} MOVE_SERVO(SPINDLE_SERVO_NR, power);
#elif ENABLED(SPINDLE_SERVO) #else
MOVE_SERVO(SPINDLE_SERVO_NR, power); WRITE(SPINDLE_LASER_ENA_PIN, enabled() ? SPINDLE_LASER_ACTIVE_STATE : !SPINDLE_LASER_ACTIVE_STATE);
#else isReadyForUI = true;
WRITE(SPINDLE_LASER_ENA_PIN, enabled() ? SPINDLE_LASER_ACTIVE_STATE : !SPINDLE_LASER_ACTIVE_STATE); #endif
isReady = true; }
#endif else {
#if PIN_EXISTS(SPINDLE_LASER_ENA)
WRITE(SPINDLE_LASER_ENA_PIN, !SPINDLE_LASER_ACTIVE_STATE);
#endif
isReadyForUI = false; // Only used for UI display updates.
TERN_(SPINDLE_LASER_USE_PWM, ocr_off());
}
} }
#if ENABLED(SPINDLE_CHANGE_DIR) #if ENABLED(SPINDLE_CHANGE_DIR)

View File

@@ -34,85 +34,98 @@
#include "../libs/buzzer.h" #include "../libs/buzzer.h"
#endif #endif
#if ENABLED(LASER_POWER_INLINE) // Inline laser power
#include "../module/planner.h" #include "../module/planner.h"
#endif
#define PCT_TO_PWM(X) ((X) * 255 / 100) #define PCT_TO_PWM(X) ((X) * 255 / 100)
#define PCT_TO_SERVO(X) ((X) * 180 / 100) #define PCT_TO_SERVO(X) ((X) * 180 / 100)
// Laser/Cutter operation mode
enum CutterMode : int8_t {
CUTTER_MODE_ERROR = -1,
CUTTER_MODE_STANDARD, // M3 power is applied directly and waits for planner moves to sync.
CUTTER_MODE_CONTINUOUS, // M3 or G1/2/3 move power is controlled within planner blocks, set with 'M3 I', cleared with 'M5 I'.
CUTTER_MODE_DYNAMIC // M4 laser power is proportional to the feed rate, set with 'M4 I', cleared with 'M5 I'.
};
class SpindleLaser { class SpindleLaser {
public: public:
static const inline uint8_t pct_to_ocr(const_float_t pct) { return uint8_t(PCT_TO_PWM(pct)); } static CutterMode cutter_mode;
static constexpr uint8_t pct_to_ocr(const_float_t pct) { return uint8_t(PCT_TO_PWM(pct)); }
// cpower = configured values (e.g., SPEED_POWER_MAX) // cpower = configured values (e.g., SPEED_POWER_MAX)
// Convert configured power range to a percentage // Convert configured power range to a percentage
static const inline uint8_t cpwr_to_pct(const cutter_cpower_t cpwr) { static constexpr cutter_cpower_t power_floor = TERN(CUTTER_POWER_RELATIVE, SPEED_POWER_MIN, 0);
constexpr cutter_cpower_t power_floor = TERN(CUTTER_POWER_RELATIVE, SPEED_POWER_MIN, 0), static constexpr uint8_t cpwr_to_pct(const cutter_cpower_t cpwr) {
power_range = SPEED_POWER_MAX - power_floor; return cpwr ? round(100.0f * (cpwr - power_floor) / (SPEED_POWER_MAX - power_floor)) : 0;
return cpwr ? round(100.0f * (cpwr - power_floor) / power_range) : 0;
} }
// Convert a cpower (e.g., SPEED_POWER_STARTUP) to unit power (upwr, upower), // Convert config defines from RPM to %, angle or PWM when in Spindle mode
// which can be PWM, Percent, Servo angle, or RPM (rel/abs). // and convert from PERCENT to PWM when in Laser mode
static const inline cutter_power_t cpwr_to_upwr(const cutter_cpower_t cpwr) { // STARTUP power to Unit power static constexpr cutter_power_t cpwr_to_upwr(const cutter_cpower_t cpwr) { // STARTUP power to Unit power
const cutter_power_t upwr = ( return (
#if ENABLED(SPINDLE_FEATURE) #if ENABLED(SPINDLE_FEATURE)
// Spindle configured values are in RPM // Spindle configured define values are in RPM
#if CUTTER_UNIT_IS(RPM) #if CUTTER_UNIT_IS(RPM)
cpwr // to RPM cpwr // to same
#elif CUTTER_UNIT_IS(PERCENT) // to PCT #elif CUTTER_UNIT_IS(PERCENT)
cpwr_to_pct(cpwr) cpwr_to_pct(cpwr) // to Percent
#elif CUTTER_UNIT_IS(SERVO) // to SERVO angle #elif CUTTER_UNIT_IS(SERVO)
PCT_TO_SERVO(cpwr_to_pct(cpwr)) PCT_TO_SERVO(cpwr_to_pct(cpwr)) // to SERVO angle
#else // to PWM #else
PCT_TO_PWM(cpwr_to_pct(cpwr)) PCT_TO_PWM(cpwr_to_pct(cpwr)) // to PWM
#endif #endif
#else #else
// Laser configured values are in PCT // Laser configured define values are in Percent
#if CUTTER_UNIT_IS(PWM255) #if CUTTER_UNIT_IS(PWM255)
PCT_TO_PWM(cpwr) PCT_TO_PWM(cpwr) // to PWM
#else #else
cpwr // to RPM/PCT cpwr // to same
#endif #endif
#endif #endif
); );
return upwr;
} }
static const cutter_power_t mpower_min() { return cpwr_to_upwr(SPEED_POWER_MIN); } static constexpr cutter_power_t mpower_min() { return cpwr_to_upwr(SPEED_POWER_MIN); }
static const cutter_power_t mpower_max() { return cpwr_to_upwr(SPEED_POWER_MAX); } static constexpr cutter_power_t mpower_max() { return cpwr_to_upwr(SPEED_POWER_MAX); }
#if ENABLED(LASER_FEATURE) #if ENABLED(LASER_FEATURE)
static cutter_test_pulse_t testPulse; // Test fire Pulse ms value static cutter_test_pulse_t testPulse; // (ms) Test fire pulse duration
static uint8_t last_block_power; // Track power changes for dynamic power
static feedRate_t feedrate_mm_m, last_feedrate_mm_m; // (mm/min) Track feedrate changes for dynamic power
static bool laser_feedrate_changed() {
const bool changed = last_feedrate_mm_m != feedrate_mm_m;
if (changed) last_feedrate_mm_m = feedrate_mm_m;
return changed;
}
#endif #endif
static bool isReady; // Ready to apply power setting from the UI to OCR static bool isReadyForUI; // Ready to apply power setting from the UI to OCR
static bool enable_state;
static uint8_t power, static uint8_t power,
last_power_applied; // Basic power state tracking last_power_applied; // Basic power state tracking
#if ENABLED(MARLIN_DEV_MODE) static cutter_frequency_t frequency; // Set PWM frequency; range: 2K-50K
static cutter_frequency_t frequency; // Set PWM frequency; range: 2K-50K
#endif
static cutter_power_t menuPower, // Power as set via LCD menu in PWM, Percentage or RPM static cutter_power_t menuPower, // Power as set via LCD menu in PWM, Percentage or RPM
unitPower; // Power as displayed status in PWM, Percentage or RPM unitPower; // Power as displayed status in PWM, Percentage or RPM
static void init(); static void init();
#if ENABLED(MARLIN_DEV_MODE) #if ENABLED(HAL_CAN_SET_PWM_FREQ) && SPINDLE_LASER_FREQUENCY
static void refresh_frequency() { hal.set_pwm_frequency(pin_t(SPINDLE_LASER_PWM_PIN), frequency); } static void refresh_frequency() { hal.set_pwm_frequency(pin_t(SPINDLE_LASER_PWM_PIN), frequency); }
#endif #endif
// Modifying this function should update everywhere // Modifying this function should update everywhere
static bool enabled(const cutter_power_t opwr) { return opwr > 0; } static bool enabled(const cutter_power_t opwr) { return opwr > 0; }
static bool enabled() { return enabled(power); } static bool enabled() { return enable_state; }
static void apply_power(const uint8_t inpow); static void apply_power(const uint8_t inpow);
FORCE_INLINE static void refresh() { apply_power(power); } FORCE_INLINE static void refresh() { apply_power(power); }
FORCE_INLINE static void set_power(const uint8_t upwr) { power = upwr; refresh(); }
#if ENABLED(SPINDLE_LASER_USE_PWM) #if ENABLED(SPINDLE_LASER_USE_PWM)
@@ -123,7 +136,6 @@ public:
public: public:
static void set_ocr(const uint8_t ocr); static void set_ocr(const uint8_t ocr);
static void ocr_set_power(const uint8_t ocr) { power = ocr; set_ocr(ocr); }
static void ocr_off(); static void ocr_off();
/** /**
@@ -141,78 +153,76 @@ public:
); );
} }
/**
* Correct power to configured range
*/
static cutter_power_t power_to_range(const cutter_power_t pwr) {
return power_to_range(pwr, _CUTTER_POWER(CUTTER_POWER_UNIT));
}
static cutter_power_t power_to_range(const cutter_power_t pwr, const uint8_t pwrUnit) {
static constexpr float
min_pct = TERN(CUTTER_POWER_RELATIVE, 0, TERN(SPINDLE_FEATURE, round(100.0f * (SPEED_POWER_MIN) / (SPEED_POWER_MAX)), SPEED_POWER_MIN)),
max_pct = TERN(SPINDLE_FEATURE, 100, SPEED_POWER_MAX);
if (pwr <= 0) return 0;
cutter_power_t upwr;
switch (pwrUnit) {
case _CUTTER_POWER_PWM255:
upwr = cutter_power_t(
(pwr < pct_to_ocr(min_pct)) ? pct_to_ocr(min_pct) // Use minimum if set below
: (pwr > pct_to_ocr(max_pct)) ? pct_to_ocr(max_pct) // Use maximum if set above
: pwr
);
break;
case _CUTTER_POWER_PERCENT:
upwr = cutter_power_t(
(pwr < min_pct) ? min_pct // Use minimum if set below
: (pwr > max_pct) ? max_pct // Use maximum if set above
: pwr // PCT
);
break;
case _CUTTER_POWER_RPM:
upwr = cutter_power_t(
(pwr < SPEED_POWER_MIN) ? SPEED_POWER_MIN // Use minimum if set below
: (pwr > SPEED_POWER_MAX) ? SPEED_POWER_MAX // Use maximum if set above
: pwr // Calculate OCR value
);
break;
default: break;
}
return upwr;
}
#endif // SPINDLE_LASER_USE_PWM #endif // SPINDLE_LASER_USE_PWM
/** /**
* Enable/Disable spindle/laser * Correct power to configured range
* @param enable true = enable; false = disable
*/ */
static void set_enabled(const bool enable) { static cutter_power_t power_to_range(const cutter_power_t pwr, const uint8_t pwrUnit=_CUTTER_POWER(CUTTER_POWER_UNIT)) {
uint8_t value = 0; static constexpr float
if (enable) { min_pct = TERN(CUTTER_POWER_RELATIVE, 0, TERN(SPINDLE_FEATURE, round(100.0f * (SPEED_POWER_MIN) / (SPEED_POWER_MAX)), SPEED_POWER_MIN)),
#if ENABLED(SPINDLE_LASER_USE_PWM) max_pct = TERN(SPINDLE_FEATURE, 100, SPEED_POWER_MAX);
if (power) if (pwr <= 0) return 0;
value = power; cutter_power_t upwr;
else if (unitPower) switch (pwrUnit) {
value = upower_to_ocr(cpwr_to_upwr(SPEED_POWER_STARTUP)); case _CUTTER_POWER_PWM255: { // PWM
#else const uint8_t pmin = pct_to_ocr(min_pct), pmax = pct_to_ocr(max_pct);
value = 255; upwr = cutter_power_t(constrain(pwr, pmin, pmax));
#endif } break;
case _CUTTER_POWER_PERCENT: // Percent
upwr = cutter_power_t(constrain(pwr, min_pct, max_pct));
break;
case _CUTTER_POWER_RPM: // Calculate OCR value
upwr = cutter_power_t(constrain(pwr, SPEED_POWER_MIN, SPEED_POWER_MAX));
break;
default: break;
} }
set_power(value); return upwr;
} }
static void disable() { isReady = false; set_enabled(false); }
/** /**
* Wait for spindle to spin up or spin down * Enable Laser or Spindle output.
* It's important to prevent changing the power output value during inline cutter operation.
* Inline power is adjusted in the planner to support LASER_TRAP_POWER and CUTTER_MODE_DYNAMIC mode.
* *
* @param on true = state to on; false = state to off. * This method accepts one of the following control states:
*
* - For CUTTER_MODE_STANDARD the cutter power is either full on/off or ocr-based and it will apply
* SPEED_POWER_STARTUP if no value is assigned.
*
* - For CUTTER_MODE_CONTINUOUS inline and power remains where last set and the cutter output enable flag is set.
*
* - CUTTER_MODE_DYNAMIC is also inline-based and it just sets the enable output flag.
*
* - For CUTTER_MODE_ERROR set the output enable_state flag directly and set power to 0 for any mode.
* This mode allows a global power shutdown action to occur.
*/ */
static void power_delay(const bool on) { static void set_enabled(bool enable) {
#if DISABLED(LASER_POWER_INLINE) switch (cutter_mode) {
safe_delay(on ? SPINDLE_LASER_POWERUP_DELAY : SPINDLE_LASER_POWERDOWN_DELAY); case CUTTER_MODE_STANDARD:
apply_power(enable ? TERN(SPINDLE_LASER_USE_PWM, (power ?: (unitPower ? upower_to_ocr(cpwr_to_upwr(SPEED_POWER_STARTUP)) : 0)), 255) : 0);
break;
case CUTTER_MODE_CONTINUOUS:
TERN_(LASER_FEATURE, set_inline_enabled(enable));
break;
case CUTTER_MODE_DYNAMIC:
TERN_(LASER_FEATURE, set_inline_enabled(enable));
break;
case CUTTER_MODE_ERROR: // Error mode, no enable and kill power.
enable = false;
apply_power(0);
}
#if SPINDLE_LASER_ENA_PIN
WRITE(SPINDLE_LASER_ENA_PIN, enable ? SPINDLE_LASER_ACTIVE_STATE : !SPINDLE_LASER_ACTIVE_STATE);
#endif #endif
enable_state = enable;
}
static void disable() { isReadyForUI = false; set_enabled(false); }
// Wait for spindle/laser to startup or shutdown
static void power_delay(const bool on) {
safe_delay(on ? SPINDLE_LASER_POWERUP_DELAY : SPINDLE_LASER_POWERDOWN_DELAY);
} }
#if ENABLED(SPINDLE_CHANGE_DIR) #if ENABLED(SPINDLE_CHANGE_DIR)
@@ -224,122 +234,98 @@ public:
#endif #endif
#if ENABLED(AIR_EVACUATION) #if ENABLED(AIR_EVACUATION)
static void air_evac_enable(); // Turn On Cutter Vacuum or Laser Blower motor static void air_evac_enable(); // Turn On Cutter Vacuum or Laser Blower motor
static void air_evac_disable(); // Turn Off Cutter Vacuum or Laser Blower motor static void air_evac_disable(); // Turn Off Cutter Vacuum or Laser Blower motor
static void air_evac_toggle(); // Toggle Cutter Vacuum or Laser Blower motor static void air_evac_toggle(); // Toggle Cutter Vacuum or Laser Blower motor
static bool air_evac_state() { // Get current state static bool air_evac_state() { // Get current state
return (READ(AIR_EVACUATION_PIN) == AIR_EVACUATION_ACTIVE); return (READ(AIR_EVACUATION_PIN) == AIR_EVACUATION_ACTIVE);
} }
#endif #endif
#if ENABLED(AIR_ASSIST) #if ENABLED(AIR_ASSIST)
static void air_assist_enable(); // Turn on air assist static void air_assist_enable(); // Turn on air assist
static void air_assist_disable(); // Turn off air assist static void air_assist_disable(); // Turn off air assist
static void air_assist_toggle(); // Toggle air assist static void air_assist_toggle(); // Toggle air assist
static bool air_assist_state() { // Get current state static bool air_assist_state() { // Get current state
return (READ(AIR_ASSIST_PIN) == AIR_ASSIST_ACTIVE); return (READ(AIR_ASSIST_PIN) == AIR_ASSIST_ACTIVE);
} }
#endif #endif
#if HAS_MARLINUI_MENU #if HAS_MARLINUI_MENU
static void enable_with_dir(const bool reverse) {
isReady = true; #if ENABLED(SPINDLE_FEATURE)
const uint8_t ocr = TERN(SPINDLE_LASER_USE_PWM, upower_to_ocr(menuPower), 255); static void enable_with_dir(const bool reverse) {
if (menuPower) isReadyForUI = true;
power = ocr; const uint8_t ocr = TERN(SPINDLE_LASER_USE_PWM, upower_to_ocr(menuPower), 255);
else if (menuPower)
menuPower = cpwr_to_upwr(SPEED_POWER_STARTUP); power = ocr;
unitPower = menuPower; else
set_reverse(reverse); menuPower = cpwr_to_upwr(SPEED_POWER_STARTUP);
set_enabled(true); unitPower = menuPower;
} set_reverse(reverse);
FORCE_INLINE static void enable_forward() { enable_with_dir(false); } set_enabled(true);
FORCE_INLINE static void enable_reverse() { enable_with_dir(true); } }
FORCE_INLINE static void enable_same_dir() { enable_with_dir(is_reverse()); } FORCE_INLINE static void enable_forward() { enable_with_dir(false); }
FORCE_INLINE static void enable_reverse() { enable_with_dir(true); }
FORCE_INLINE static void enable_same_dir() { enable_with_dir(is_reverse()); }
#endif // SPINDLE_FEATURE
#if ENABLED(SPINDLE_LASER_USE_PWM) #if ENABLED(SPINDLE_LASER_USE_PWM)
static void update_from_mpower() { static void update_from_mpower() {
if (isReady) power = upower_to_ocr(menuPower); if (isReadyForUI) power = upower_to_ocr(menuPower);
unitPower = menuPower; unitPower = menuPower;
} }
#endif #endif
#if ENABLED(LASER_FEATURE) #if ENABLED(LASER_FEATURE)
// Toggle the laser on/off with menuPower. Apply SPEED_POWER_STARTUP if it was 0 on entry.
static void menu_set_enabled(const bool state) {
set_enabled(state);
if (state) {
if (!menuPower) menuPower = cpwr_to_upwr(SPEED_POWER_STARTUP);
power = upower_to_ocr(menuPower);
apply_power(power);
} else
apply_power(0);
}
/** /**
* Test fire the laser using the testPulse ms duration * Test fire the laser using the testPulse ms duration
* Also fires with any PWM power that was previous set * Also fires with any PWM power that was previous set
* If not set defaults to 80% power * If not set defaults to 80% power
*/ */
static void test_fire_pulse() { static void test_fire_pulse() {
TERN_(HAS_BEEPER, buzzer.tone(30, 3000)); BUZZ(30, 3000);
enable_forward(); // Turn Laser on (Spindle speak but same funct) cutter_mode = CUTTER_MODE_STANDARD; // Menu needs standard mode.
delay(testPulse); // Delay for time set by user in pulse ms menu screen. menu_set_enabled(true); // Laser On
disable(); // Turn laser off delay(testPulse); // Delay for time set by user in pulse ms menu screen.
menu_set_enabled(false); // Laser Off
} }
#endif #endif // LASER_FEATURE
#endif // HAS_MARLINUI_MENU #endif // HAS_MARLINUI_MENU
#if ENABLED(LASER_POWER_INLINE) #if ENABLED(LASER_FEATURE)
/**
* Inline power adds extra fields to the planner block
* to handle laser power and scale to movement speed.
*/
// Force disengage planner power control // Dynamic mode rate calculation
static void inline_disable() { static uint8_t calc_dynamic_power() {
isReady = false; if (feedrate_mm_m > 65535) return 255; // Too fast, go always on
unitPower = 0; uint16_t rate = uint16_t(feedrate_mm_m); // 16 bits from the G-code parser float input
planner.laser_inline.status.isPlanned = false; rate >>= 8; // Take the G-code input e.g. F40000 and shift off the lower bits to get an OCR value from 1-255
planner.laser_inline.status.isEnabled = false; return uint8_t(rate);
planner.laser_inline.power = 0;
} }
// Inline modes of all other functions; all enable planner inline power control // Inline modes of all other functions; all enable planner inline power control
static void set_inline_enabled(const bool enable) { static void set_inline_enabled(const bool enable) { planner.laser_inline.status.isEnabled = enable; }
if (enable)
inline_power(255);
else {
isReady = false;
unitPower = menuPower = 0;
planner.laser_inline.status.isPlanned = false;
TERN(SPINDLE_LASER_USE_PWM, inline_ocr_power, inline_power)(0);
}
}
// Set the power for subsequent movement blocks // Set the power for subsequent movement blocks
static void inline_power(const cutter_power_t upwr) { static void inline_power(const cutter_power_t cpwr) {
unitPower = menuPower = upwr; TERN(SPINDLE_LASER_USE_PWM, power = planner.laser_inline.power = cpwr, planner.laser_inline.power = cpwr > 0 ? 255 : 0);
#if ENABLED(SPINDLE_LASER_USE_PWM)
#if ENABLED(SPEED_POWER_RELATIVE) && !CUTTER_UNIT_IS(RPM) // relative mode does not turn laser off at 0, except for RPM
planner.laser_inline.status.isEnabled = true;
planner.laser_inline.power = upower_to_ocr(upwr);
isReady = true;
#else
inline_ocr_power(upower_to_ocr(upwr));
#endif
#else
planner.laser_inline.status.isEnabled = enabled(upwr);
planner.laser_inline.power = upwr;
isReady = enabled(upwr);
#endif
} }
static void inline_direction(const bool) { /* never */ } #endif // LASER_FEATURE
#if ENABLED(SPINDLE_LASER_USE_PWM) static void kill() { disable(); }
static void inline_ocr_power(const uint8_t ocrpwr) {
isReady = ocrpwr > 0;
planner.laser_inline.status.isEnabled = ocrpwr > 0;
planner.laser_inline.power = ocrpwr;
}
#endif
#endif // LASER_POWER_INLINE
static void kill() {
TERN_(LASER_POWER_INLINE, inline_disable());
disable();
}
}; };
extern SpindleLaser cutter; extern SpindleLaser cutter;

View File

@@ -74,12 +74,10 @@ typedef IF<(SPEED_POWER_MAX > 255), uint16_t, uint8_t>::type cutter_cpower_t;
#endif #endif
#endif #endif
typedef uint16_t cutter_frequency_t;
#if ENABLED(LASER_FEATURE) #if ENABLED(LASER_FEATURE)
typedef uint16_t cutter_test_pulse_t; typedef uint16_t cutter_test_pulse_t;
#define CUTTER_MENU_PULSE_TYPE uint16_3 #define CUTTER_MENU_PULSE_TYPE uint16_3
#endif
#if ENABLED(MARLIN_DEV_MODE)
typedef uint16_t cutter_frequency_t;
#define CUTTER_MENU_FREQUENCY_TYPE uint16_5 #define CUTTER_MENU_FREQUENCY_TYPE uint16_5
#endif #endif

View File

@@ -33,17 +33,12 @@
#include "../gcode/gcode.h" #include "../gcode/gcode.h"
#if ENABLED(TMC_DEBUG) #if ENABLED(TMC_DEBUG)
#include "../module/planner.h"
#include "../libs/hex_print.h" #include "../libs/hex_print.h"
#if ENABLED(MONITOR_DRIVER_STATUS) #if ENABLED(MONITOR_DRIVER_STATUS)
static uint16_t report_tmc_status_interval; // = 0 static uint16_t report_tmc_status_interval; // = 0
#endif #endif
#endif #endif
#if HAS_MARLINUI_MENU
#include "../module/stepper.h"
#endif
/** /**
* Check for over temperature or short to ground error flags. * Check for over temperature or short to ground error flags.
* Report and log warning of overtemperature condition. * Report and log warning of overtemperature condition.

View File

@@ -107,7 +107,6 @@
#include "../../MarlinCore.h" #include "../../MarlinCore.h"
#include "../../module/planner.h" #include "../../module/planner.h"
#include "../../module/stepper.h"
#include "../../module/motion.h" #include "../../module/motion.h"
#include "../../module/tool_change.h" #include "../../module/tool_change.h"
#include "../../module/temperature.h" #include "../../module/temperature.h"
@@ -306,7 +305,7 @@ typedef struct {
LIMIT(e.x, X_MIN_POS + 1, X_MAX_POS - 1); LIMIT(e.x, X_MIN_POS + 1, X_MAX_POS - 1);
#endif #endif
if (position_is_reachable(s.x, s.y) && position_is_reachable(e.x, e.y)) if (position_is_reachable(s) && position_is_reachable(e))
print_line_from_here_to_there(s, e); print_line_from_here_to_there(s, e);
} }
} }

View File

@@ -32,7 +32,6 @@
#include "../../../feature/bedlevel/bedlevel.h" #include "../../../feature/bedlevel/bedlevel.h"
#include "../../../module/motion.h" #include "../../../module/motion.h"
#include "../../../module/planner.h" #include "../../../module/planner.h"
#include "../../../module/stepper.h"
#include "../../../module/probe.h" #include "../../../module/probe.h"
#include "../../queue.h" #include "../../queue.h"

View File

@@ -36,7 +36,7 @@
#include "../../../libs/buzzer.h" #include "../../../libs/buzzer.h"
#include "../../../lcd/marlinui.h" #include "../../../lcd/marlinui.h"
#include "../../../module/motion.h" #include "../../../module/motion.h"
#include "../../../module/stepper.h" #include "../../../module/planner.h"
#if ENABLED(EXTENSIBLE_UI) #if ENABLED(EXTENSIBLE_UI)
#include "../../../lcd/extui/ui_api.h" #include "../../../lcd/extui/ui_api.h"

View File

@@ -24,8 +24,9 @@
#include "../gcode.h" #include "../gcode.h"
#include "../../module/stepper.h"
#include "../../module/endstops.h" #include "../../module/endstops.h"
#include "../../module/planner.h"
#include "../../module/stepper.h" // for various
#if HAS_MULTI_HOTEND #if HAS_MULTI_HOTEND
#include "../../module/tool_change.h" #include "../../module/tool_change.h"
@@ -35,6 +36,10 @@
#include "../../feature/bedlevel/bedlevel.h" #include "../../feature/bedlevel/bedlevel.h"
#endif #endif
#if ENABLED(BD_SENSOR)
#include "../../feature/bedlevel/bdl/bdl.h"
#endif
#if ENABLED(SENSORLESS_HOMING) #if ENABLED(SENSORLESS_HOMING)
#include "../../feature/tmc_util.h" #include "../../feature/tmc_util.h"
#endif #endif
@@ -55,11 +60,7 @@
#include "../../lcd/e3v2/proui/dwin.h" #include "../../lcd/e3v2/proui/dwin.h"
#endif #endif
#if HAS_L64XX // set L6470 absolute position registers to counts #if ENABLED(LASER_FEATURE)
#include "../../libs/L64XX/L64XX_Marlin.h"
#endif
#if ENABLED(LASER_MOVE_G28_OFF)
#include "../../feature/spindle_laser.h" #include "../../feature/spindle_laser.h"
#endif #endif
@@ -169,7 +170,7 @@
motion_state.jerk_state = planner.max_jerk; motion_state.jerk_state = planner.max_jerk;
planner.max_jerk.set(0, 0 OPTARG(DELTA, 0)); planner.max_jerk.set(0, 0 OPTARG(DELTA, 0));
#endif #endif
planner.reset_acceleration_rates(); planner.refresh_acceleration_rates();
return motion_state; return motion_state;
} }
@@ -178,7 +179,7 @@
planner.settings.max_acceleration_mm_per_s2[Y_AXIS] = motion_state.acceleration.y; planner.settings.max_acceleration_mm_per_s2[Y_AXIS] = motion_state.acceleration.y;
TERN_(DELTA, planner.settings.max_acceleration_mm_per_s2[Z_AXIS] = motion_state.acceleration.z); TERN_(DELTA, planner.settings.max_acceleration_mm_per_s2[Z_AXIS] = motion_state.acceleration.z);
TERN_(HAS_CLASSIC_JERK, planner.max_jerk = motion_state.jerk_state); TERN_(HAS_CLASSIC_JERK, planner.max_jerk = motion_state.jerk_state);
planner.reset_acceleration_rates(); planner.refresh_acceleration_rates();
} }
#endif // IMPROVE_HOMING_RELIABILITY #endif // IMPROVE_HOMING_RELIABILITY
@@ -205,7 +206,14 @@ void GcodeSuite::G28() {
DEBUG_SECTION(log_G28, "G28", DEBUGGING(LEVELING)); DEBUG_SECTION(log_G28, "G28", DEBUGGING(LEVELING));
if (DEBUGGING(LEVELING)) log_machine_info(); if (DEBUGGING(LEVELING)) log_machine_info();
TERN_(LASER_MOVE_G28_OFF, cutter.set_inline_enabled(false)); // turn off laser TERN_(BD_SENSOR, bdl.config_state = 0);
/**
* Set the laser power to false to stop the planner from processing the current power setting.
*/
#if ENABLED(LASER_FEATURE)
planner.laser_inline.status.isPowered = false;
#endif
#if ENABLED(DUAL_X_CARRIAGE) #if ENABLED(DUAL_X_CARRIAGE)
bool IDEX_saved_duplication_state = extruder_duplication_enabled; bool IDEX_saved_duplication_state = extruder_duplication_enabled;
@@ -596,20 +604,4 @@ void GcodeSuite::G28() {
TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(old_grblstate)); TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(old_grblstate));
#if HAS_L64XX
// Set L6470 absolute position registers to counts
// constexpr *might* move this to PROGMEM.
// If not, this will need a PROGMEM directive and an accessor.
#define _EN_ITEM(N) , E_AXIS
static constexpr AxisEnum L64XX_axis_xref[MAX_L64XX] = {
NUM_AXIS_LIST(X_AXIS, Y_AXIS, Z_AXIS, I_AXIS, J_AXIS, K_AXIS, U_AXIS, V_AXIS, W_AXIS),
X_AXIS, Y_AXIS, Z_AXIS, Z_AXIS, Z_AXIS
REPEAT(E_STEPPERS, _EN_ITEM)
};
#undef _EN_ITEM
for (uint8_t j = 1; j <= L64XX::chain[0]; j++) {
const uint8_t cv = L64XX::chain[j];
L64xxManager.set_param((L64XX_axis_t)cv, L6470_ABS_POS, stepper.position(L64XX_axis_xref[cv]));
}
#endif
} }

View File

@@ -27,7 +27,7 @@
#include "../gcode.h" #include "../gcode.h"
#include "../../module/delta.h" #include "../../module/delta.h"
#include "../../module/motion.h" #include "../../module/motion.h"
#include "../../module/stepper.h" #include "../../module/planner.h"
#include "../../module/endstops.h" #include "../../module/endstops.h"
#include "../../lcd/marlinui.h" #include "../../lcd/marlinui.h"
@@ -437,7 +437,7 @@ void GcodeSuite::G33() {
const bool stow_after_each = parser.seen_test('E'); const bool stow_after_each = parser.seen_test('E');
#if HAS_DELTA_SENSORLESS_PROBING #if HAS_DELTA_SENSORLESS_PROBING
probe.test_sensitivity.set(!parser.seen_test('X'), !parser.seen_test('Y'), !parser.seen_test('Z')); probe.test_sensitivity = { !parser.seen_test('X'), !parser.seen_test('Y'), !parser.seen_test('Z') };
const bool do_save_offset_adj = parser.seen_test('S'); const bool do_save_offset_adj = parser.seen_test('S');
#endif #endif

View File

@@ -26,9 +26,12 @@
#include "../gcode.h" #include "../gcode.h"
#include "../../module/motion.h" #include "../../module/motion.h"
#include "../../module/stepper.h"
#include "../../module/endstops.h" #include "../../module/endstops.h"
#if ANY(HAS_MOTOR_CURRENT_SPI, HAS_MOTOR_CURRENT_PWM, HAS_TRINAMIC_CONFIG)
#include "../../module/stepper.h"
#endif
#if HAS_LEVELING #if HAS_LEVELING
#include "../../feature/bedlevel/bedlevel.h" #include "../../feature/bedlevel/bedlevel.h"
#endif #endif

View File

@@ -224,13 +224,15 @@ void GcodeSuite::G34() {
// Safe clearance even on an incline // Safe clearance even on an incline
if ((iteration == 0 || i > 0) && z_probe > current_position.z) do_blocking_move_to_z(z_probe); if ((iteration == 0 || i > 0) && z_probe > current_position.z) do_blocking_move_to_z(z_probe);
xy_pos_t &ppos = z_stepper_align.xy[iprobe];
if (DEBUGGING(LEVELING)) if (DEBUGGING(LEVELING))
DEBUG_ECHOLNPGM_P(PSTR("Probing X"), z_stepper_align.xy[iprobe].x, SP_Y_STR, z_stepper_align.xy[iprobe].y); DEBUG_ECHOLNPGM_P(PSTR("Probing X"), ppos.x, SP_Y_STR, ppos.y);
// Probe a Z height for each stepper. // Probe a Z height for each stepper.
// Probing sanity check is disabled, as it would trigger even in normal cases because // Probing sanity check is disabled, as it would trigger even in normal cases because
// current_position.z has been manually altered in the "dirty trick" above. // current_position.z has been manually altered in the "dirty trick" above.
const float z_probed_height = probe.probe_at_point(z_stepper_align.xy[iprobe], raise_after, 0, true, false); const float z_probed_height = probe.probe_at_point(DIFF_TERN(HAS_HOME_OFFSET, ppos, xy_pos_t(home_offset)), raise_after, 0, true, false);
if (isnan(z_probed_height)) { if (isnan(z_probed_height)) {
SERIAL_ECHOLNPGM("Probing failed"); SERIAL_ECHOLNPGM("Probing failed");
LCD_MESSAGE(MSG_LCD_PROBING_FAILED); LCD_MESSAGE(MSG_LCD_PROBING_FAILED);

View File

@@ -86,13 +86,13 @@
* *
* Parameters: * Parameters:
* *
* S[segments-per-second] - Segments-per-second * S[segments] - Segments-per-second
* *
* Without NO_WORKSPACE_OFFSETS: * Without NO_WORKSPACE_OFFSETS:
* *
* P[theta-psi-offset] - Theta-Psi offset, added to the shoulder (A/X) angle * P[theta-psi-offset] - Theta-Psi offset, added to the shoulder (A/X) angle
* T[theta-offset] - Theta offset, added to the elbow (B/Y) angle * T[theta-offset] - Theta offset, added to the elbow (B/Y) angle
* Z[z-offset] - Z offset, added to Z * Z[z-offset] - Z offset, added to Z
* *
* A, P, and X are all aliases for the shoulder angle * A, P, and X are all aliases for the shoulder angle
* B, T, and Y are all aliases for the elbow angle * B, T, and Y are all aliases for the elbow angle
@@ -152,18 +152,35 @@
* *
* Parameters: * Parameters:
* *
* S[segments-per-second] - Segments-per-second * S[segments] - Segments-per-second
* L[left] - Work area minimum X
* R[right] - Work area maximum X
* T[top] - Work area maximum Y
* B[bottom] - Work area minimum Y
* H[length] - Maximum belt length
*/ */
void GcodeSuite::M665() { void GcodeSuite::M665() {
if (parser.seenval('S')) if (!parser.seen_any()) return M665_report();
segments_per_second = parser.value_float(); if (parser.seenval('S')) segments_per_second = parser.value_float();
else if (parser.seenval('L')) draw_area_min.x = parser.value_linear_units();
M665_report(); if (parser.seenval('R')) draw_area_max.x = parser.value_linear_units();
if (parser.seenval('T')) draw_area_max.y = parser.value_linear_units();
if (parser.seenval('B')) draw_area_min.y = parser.value_linear_units();
if (parser.seenval('H')) polargraph_max_belt_len = parser.value_linear_units();
draw_area_size.x = draw_area_max.x - draw_area_min.x;
draw_area_size.y = draw_area_max.y - draw_area_min.y;
} }
void GcodeSuite::M665_report(const bool forReplay/*=true*/) { void GcodeSuite::M665_report(const bool forReplay/*=true*/) {
report_heading_etc(forReplay, F(STR_POLARGRAPH_SETTINGS " (" STR_S_SEG_PER_SEC ")")); report_heading_etc(forReplay, F(STR_POLARGRAPH_SETTINGS));
SERIAL_ECHOLNPGM(" M665 S", segments_per_second); SERIAL_ECHOLNPGM_P(
PSTR(" M665 S"), LINEAR_UNIT(segments_per_second),
PSTR(" L"), LINEAR_UNIT(draw_area_min.x),
PSTR(" R"), LINEAR_UNIT(draw_area_max.x),
SP_T_STR, LINEAR_UNIT(draw_area_max.y),
SP_B_STR, LINEAR_UNIT(draw_area_min.y),
PSTR(" H"), LINEAR_UNIT(polargraph_max_belt_len)
);
} }
#endif #endif

View File

@@ -198,10 +198,10 @@ inline void servo_probe_test() {
uint8_t i = 0; uint8_t i = 0;
SERIAL_ECHOLNPGM(". Deploy & stow 4 times"); SERIAL_ECHOLNPGM(". Deploy & stow 4 times");
do { do {
MOVE_SERVO(probe_index, servo_angles[Z_PROBE_SERVO_NR][0]); // Deploy servo[probe_index].move(servo_angles[Z_PROBE_SERVO_NR][0]); // Deploy
safe_delay(500); safe_delay(500);
deploy_state = READ(PROBE_TEST_PIN); deploy_state = READ(PROBE_TEST_PIN);
MOVE_SERVO(probe_index, servo_angles[Z_PROBE_SERVO_NR][1]); // Stow servo[probe_index].move(servo_angles[Z_PROBE_SERVO_NR][1]); // Stow
safe_delay(500); safe_delay(500);
stow_state = READ(PROBE_TEST_PIN); stow_state = READ(PROBE_TEST_PIN);
} while (++i < 4); } while (++i < 4);
@@ -226,7 +226,7 @@ inline void servo_probe_test() {
} }
// Ask the user for a trigger event and measure the pulse width. // Ask the user for a trigger event and measure the pulse width.
MOVE_SERVO(probe_index, servo_angles[Z_PROBE_SERVO_NR][0]); // Deploy servo[probe_index].move(servo_angles[Z_PROBE_SERVO_NR][0]); // Deploy
safe_delay(500); safe_delay(500);
SERIAL_ECHOLNPGM("** Please trigger probe within 30 sec **"); SERIAL_ECHOLNPGM("** Please trigger probe within 30 sec **");
uint16_t probe_counter = 0; uint16_t probe_counter = 0;
@@ -256,7 +256,7 @@ inline void servo_probe_test() {
} }
else SERIAL_ECHOLNPGM("FAIL: Noise detected - please re-run test"); else SERIAL_ECHOLNPGM("FAIL: Noise detected - please re-run test");
MOVE_SERVO(probe_index, servo_angles[Z_PROBE_SERVO_NR][1]); // Stow servo[probe_index].move(servo_angles[Z_PROBE_SERVO_NR][1]); // Stow
return; return;
} }
} }

View File

@@ -25,7 +25,7 @@
#if ENABLED(SD_ABORT_ON_ENDSTOP_HIT) #if ENABLED(SD_ABORT_ON_ENDSTOP_HIT)
#include "../gcode.h" #include "../gcode.h"
#include "../../module/stepper.h" #include "../../module/planner.h"
/** /**
* M540: Set whether SD card print should abort on endstop hit (M540 S<0|1>) * M540: Set whether SD card print should abort on endstop hit (M540 S<0|1>)

View File

@@ -24,6 +24,7 @@
#include "../../MarlinCore.h" // for stepper_inactive_time, disable_e_steppers #include "../../MarlinCore.h" // for stepper_inactive_time, disable_e_steppers
#include "../../lcd/marlinui.h" #include "../../lcd/marlinui.h"
#include "../../module/motion.h" // for e_axis_mask #include "../../module/motion.h" // for e_axis_mask
#include "../../module/planner.h"
#include "../../module/stepper.h" #include "../../module/stepper.h"
#if ENABLED(AUTO_BED_LEVELING_UBL) #if ENABLED(AUTO_BED_LEVELING_UBL)

View File

@@ -26,7 +26,7 @@
#include "../gcode.h" #include "../gcode.h"
#include "../../MarlinCore.h" // for pin_is_protected and idle() #include "../../MarlinCore.h" // for pin_is_protected and idle()
#include "../../module/stepper.h" #include "../../module/planner.h"
void protected_pin_err(); void protected_pin_err();

View File

@@ -56,14 +56,14 @@ void GcodeSuite::M280() {
while (PENDING(now, end)) { while (PENDING(now, end)) {
safe_delay(50); safe_delay(50);
now = _MIN(millis(), end); now = _MIN(millis(), end);
MOVE_SERVO(servo_index, LROUND(aold + (anew - aold) * (float(now - start) / t))); servo[servo_index].move(LROUND(aold + (anew - aold) * (float(now - start) / t)));
} }
} }
#endif // POLARGRAPH #endif // POLARGRAPH
MOVE_SERVO(servo_index, anew); servo[servo_index].move(anew);
} }
else else
DETACH_SERVO(servo_index); servo[servo_index].detach();
} }
else else
SERIAL_ECHO_MSG(" Servo ", servo_index, ": ", servo[servo_index].read()); SERIAL_ECHO_MSG(" Servo ", servo_index, ": ", servo[servo_index].read());

View File

@@ -36,7 +36,7 @@ void GcodeSuite::M282() {
const int servo_index = parser.value_int(); const int servo_index = parser.value_int();
if (WITHIN(servo_index, 0, NUM_SERVOS - 1)) if (WITHIN(servo_index, 0, NUM_SERVOS - 1))
DETACH_SERVO(servo_index); servo[servo_index].detach();
else else
SERIAL_ECHO_MSG("Servo ", servo_index, " out of range"); SERIAL_ECHO_MSG("Servo ", servo_index, " out of range");

View File

@@ -26,22 +26,32 @@
#include "../gcode.h" #include "../gcode.h"
#include "../../feature/spindle_laser.h" #include "../../feature/spindle_laser.h"
#include "../../module/stepper.h" #include "../../module/planner.h"
/** /**
* Laser: * Laser:
* M3 - Laser ON/Power (Ramped power) * M3 - Laser ON/Power (Ramped power)
* M4 - Laser ON/Power (Continuous power) * M4 - Laser ON/Power (Ramped power)
* M5 - Set power output to 0 (leaving inline mode unchanged).
*
* M3I - Enable continuous inline power to be processed by the planner, with power
* calculated and set in the planner blocks, processed inline during stepping.
* Within inline mode M3 S-Values will set the power for the next moves e.g. G1 X10 Y10 powers on with the last S-Value.
* M3I must be set before using planner-synced M3 inline S-Values (LASER_POWER_SYNC).
*
* M4I - Set dynamic mode which calculates laser power OCR based on the current feedrate.
*
* M5I - Clear inline mode and set power to 0.
* *
* Spindle: * Spindle:
* M3 - Spindle ON (Clockwise) * M3 - Spindle ON (Clockwise)
* M4 - Spindle ON (Counter-clockwise) * M4 - Spindle ON (Counter-clockwise)
* M5 - Spindle OFF
* *
* Parameters: * Parameters:
* S<power> - Set power. S0 will turn the spindle/laser off, except in relative mode. * S<power> - Set power. S0 will turn the spindle/laser off.
* O<ocr> - Set power and OCR (oscillator count register)
* *
* If no PWM pin is defined then M3/M4 just turns it on. * If no PWM pin is defined then M3/M4 just turns it on or off.
* *
* At least 12.8kHz (50Hz * 256) is needed for Spindle PWM. * At least 12.8kHz (50Hz * 256) is needed for Spindle PWM.
* Hardware PWM is required on AVR. ISRs are too slow. * Hardware PWM is required on AVR. ISRs are too slow.
@@ -70,77 +80,77 @@ void GcodeSuite::M3_M4(const bool is_M4) {
reset_stepper_timeout(); // Reset timeout to allow subsequent G-code to power the laser (imm.) reset_stepper_timeout(); // Reset timeout to allow subsequent G-code to power the laser (imm.)
#endif #endif
#if EITHER(SPINDLE_LASER_USE_PWM, SPINDLE_SERVO) if (cutter.cutter_mode == CUTTER_MODE_STANDARD)
auto get_s_power = [] { planner.synchronize(); // Wait for previous movement commands (G0/G1/G2/G3) to complete before changing power
if (parser.seenval('S')) {
const float spwr = parser.value_float(); #if ENABLED(LASER_FEATURE)
#if ENABLED(SPINDLE_SERVO) if (parser.seen_test('I')) {
cutter.unitPower = spwr; cutter.cutter_mode = is_M4 ? CUTTER_MODE_DYNAMIC : CUTTER_MODE_CONTINUOUS;
#else cutter.inline_power(0);
cutter.unitPower = TERN(SPINDLE_LASER_USE_PWM, cutter.set_enabled(true);
cutter.power_to_range(cutter_power_t(round(spwr))), }
spwr > 0 ? 255 : 0);
#endif
}
else
cutter.unitPower = cutter.cpwr_to_upwr(SPEED_POWER_STARTUP);
return cutter.unitPower;
};
#endif #endif
#if ENABLED(LASER_POWER_INLINE) auto get_s_power = [] {
if (parser.seen('I') == DISABLED(LASER_POWER_INLINE_INVERT)) { float u;
// Laser power in inline mode if (parser.seenval('S')) {
cutter.inline_direction(is_M4); // Should always be unused const float v = parser.value_float();
#if ENABLED(SPINDLE_LASER_USE_PWM) u = TERN(LASER_POWER_TRAP, v, cutter.power_to_range(v));
if (parser.seenval('O')) { }
cutter.unitPower = cutter.power_to_range(parser.value_byte(), 0); else if (cutter.cutter_mode == CUTTER_MODE_STANDARD)
cutter.inline_ocr_power(cutter.unitPower); // The OCR is a value from 0 to 255 (uint8_t) u = cutter.cpwr_to_upwr(SPEED_POWER_STARTUP);
}
else cutter.menuPower = cutter.unitPower = u;
cutter.inline_power(cutter.upower_to_ocr(get_s_power()));
// PWM not implied, power converted to OCR from unit definition and on/off if not PWM.
cutter.power = TERN(SPINDLE_LASER_USE_PWM, cutter.upower_to_ocr(u), u > 0 ? 255 : 0);
return u;
};
if (cutter.cutter_mode == CUTTER_MODE_CONTINUOUS || cutter.cutter_mode == CUTTER_MODE_DYNAMIC) { // Laser power in inline mode
#if ENABLED(LASER_FEATURE)
planner.laser_inline.status.isPowered = true; // M3 or M4 is powered either way
get_s_power(); // Update cutter.power if seen
#if ENABLED(LASER_POWER_SYNC)
// With power sync we only set power so it does not effect queued inline power sets
planner.buffer_sync_block(BLOCK_BIT_LASER_PWR); // Send the flag, queueing inline power
#else #else
cutter.set_inline_enabled(true); planner.synchronize();
cutter.inline_power(cutter.power);
#endif #endif
return; #endif
} }
// Non-inline, standard case else {
cutter.inline_disable(); // Prevent future blocks re-setting the power
#endif
planner.synchronize(); // Wait for previous movement commands (G0/G0/G2/G3) to complete before changing power
cutter.set_reverse(is_M4);
#if ENABLED(SPINDLE_LASER_USE_PWM)
if (parser.seenval('O')) {
cutter.unitPower = cutter.power_to_range(parser.value_byte(), 0);
cutter.ocr_set_power(cutter.unitPower); // The OCR is a value from 0 to 255 (uint8_t)
}
else
cutter.set_power(cutter.upower_to_ocr(get_s_power()));
#elif ENABLED(SPINDLE_SERVO)
cutter.set_power(get_s_power());
#else
cutter.set_enabled(true); cutter.set_enabled(true);
#endif get_s_power();
cutter.menuPower = cutter.unitPower; cutter.apply_power(
#if ENABLED(SPINDLE_SERVO)
cutter.unitPower
#elif ENABLED(SPINDLE_LASER_USE_PWM)
cutter.upower_to_ocr(cutter.unitPower)
#else
cutter.unitPower > 0 ? 255 : 0
#endif
);
TERN_(SPINDLE_CHANGE_DIR, cutter.set_reverse(is_M4));
}
} }
/** /**
* M5 - Cutter OFF (when moves are complete) * M5 - Cutter OFF (when moves are complete)
*/ */
void GcodeSuite::M5() { void GcodeSuite::M5() {
#if ENABLED(LASER_POWER_INLINE)
if (parser.seen('I') == DISABLED(LASER_POWER_INLINE_INVERT)) {
cutter.set_inline_enabled(false); // Laser power in inline mode
return;
}
// Non-inline, standard case
cutter.inline_disable(); // Prevent future blocks re-setting the power
#endif
planner.synchronize(); planner.synchronize();
cutter.set_enabled(false); cutter.power = 0;
cutter.menuPower = cutter.unitPower; cutter.apply_power(0); // M5 just kills power, leaving inline mode unchanged
if (cutter.cutter_mode != CUTTER_MODE_STANDARD) {
if (parser.seen_test('I')) {
TERN_(LASER_FEATURE, cutter.inline_power(cutter.power));
cutter.set_enabled(false); // Needs to happen while we are in inline mode to clear inline power.
cutter.cutter_mode = CUTTER_MODE_STANDARD; // Switch from inline to standard mode.
}
}
cutter.set_enabled(false); // Disable enable output setting
} }
#endif // HAS_CUTTER #endif // HAS_CUTTER

View File

@@ -21,7 +21,7 @@
*/ */
#include "../gcode.h" #include "../gcode.h"
#include "../../module/stepper.h" #include "../../module/planner.h"
/** /**
* M400: Finish all moves * M400: Finish all moves

View File

@@ -28,7 +28,6 @@
#include "../gcode.h" #include "../gcode.h"
#include "../../module/motion.h" #include "../../module/motion.h"
#include "../../module/stepper.h"
#include "../../module/tool_change.h" #include "../../module/tool_change.h"
#include "../../module/planner.h" #include "../../module/planner.h"

View File

@@ -1,151 +0,0 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "../../../inc/MarlinConfig.h"
#if HAS_L64XX
#include "../../gcode.h"
#include "../../../libs/L64XX/L64XX_Marlin.h"
#include "../../../module/stepper/indirection.h"
void echo_yes_no(const bool yes);
inline void L6470_say_status(const L64XX_axis_t axis) {
if (L64xxManager.spi_abort) return;
const L64XX_Marlin::L64XX_shadow_t &sh = L64xxManager.shadow;
L64xxManager.get_status(axis);
L64xxManager.say_axis(axis);
#if ENABLED(L6470_CHITCHAT)
char temp_buf[20];
sprintf_P(temp_buf, PSTR(" status: %4x "), sh.STATUS_AXIS_RAW);
SERIAL_ECHO(temp_buf);
print_bin(sh.STATUS_AXIS_RAW);
switch (sh.STATUS_AXIS_LAYOUT) {
case L6470_STATUS_LAYOUT: SERIAL_ECHOPGM(" L6470"); break;
case L6474_STATUS_LAYOUT: SERIAL_ECHOPGM(" L6474"); break;
case L6480_STATUS_LAYOUT: SERIAL_ECHOPGM(" L6480/powerSTEP01"); break;
}
#endif
SERIAL_ECHOPGM("\n...OUTPUT: ");
SERIAL_ECHOF(sh.STATUS_AXIS & STATUS_HIZ ? F("OFF") : F("ON "));
SERIAL_ECHOPGM(" BUSY: "); echo_yes_no((sh.STATUS_AXIS & STATUS_BUSY) == 0);
SERIAL_ECHOPGM(" DIR: ");
SERIAL_ECHOF((((sh.STATUS_AXIS & STATUS_DIR) >> 4) ^ L64xxManager.index_to_dir[axis]) ? F("FORWARD") : F("REVERSE"));
if (sh.STATUS_AXIS_LAYOUT == L6480_STATUS_LAYOUT) {
SERIAL_ECHOPGM(" Last Command: ");
if (sh.STATUS_AXIS & sh.STATUS_AXIS_WRONG_CMD) SERIAL_ECHOPGM("VALID");
else SERIAL_ECHOPGM("ERROR");
SERIAL_ECHOPGM("\n...THERMAL: ");
switch ((sh.STATUS_AXIS & (sh.STATUS_AXIS_TH_SD | sh.STATUS_AXIS_TH_WRN)) >> 11) {
case 0: SERIAL_ECHOPGM("DEVICE SHUTDOWN"); break;
case 1: SERIAL_ECHOPGM("BRIDGE SHUTDOWN"); break;
case 2: SERIAL_ECHOPGM("WARNING "); break;
case 3: SERIAL_ECHOPGM("OK "); break;
}
}
else {
SERIAL_ECHOPGM(" Last Command: ");
if (!(sh.STATUS_AXIS & sh.STATUS_AXIS_WRONG_CMD)) SERIAL_ECHOPGM("IN");
SERIAL_ECHOPGM("VALID ");
SERIAL_ECHOF(sh.STATUS_AXIS & sh.STATUS_AXIS_NOTPERF_CMD ? F("COMPLETED ") : F("Not PERFORMED"));
SERIAL_ECHOPGM("\n...THERMAL: ", !(sh.STATUS_AXIS & sh.STATUS_AXIS_TH_SD) ? "SHUTDOWN " : !(sh.STATUS_AXIS & sh.STATUS_AXIS_TH_WRN) ? "WARNING " : "OK ");
}
SERIAL_ECHOPGM(" OVERCURRENT:"); echo_yes_no((sh.STATUS_AXIS & sh.STATUS_AXIS_OCD) == 0);
if (sh.STATUS_AXIS_LAYOUT != L6474_STATUS_LAYOUT) {
SERIAL_ECHOPGM(" STALL:"); echo_yes_no((sh.STATUS_AXIS & sh.STATUS_AXIS_STEP_LOSS_A) == 0 || (sh.STATUS_AXIS & sh.STATUS_AXIS_STEP_LOSS_B) == 0);
SERIAL_ECHOPGM(" STEP-CLOCK MODE:"); echo_yes_no((sh.STATUS_AXIS & sh.STATUS_AXIS_SCK_MOD) != 0);
}
else {
SERIAL_ECHOPGM(" STALL: NA "
" STEP-CLOCK MODE: NA"
" UNDER VOLTAGE LOCKOUT: "); echo_yes_no((sh.STATUS_AXIS & sh.STATUS_AXIS_UVLO) == 0);
}
SERIAL_EOL();
}
/**
* M122: Debug L6470 drivers
*/
void GcodeSuite::M122() {
L64xxManager.pause_monitor(true); // Keep monitor_driver() from stealing status
L64xxManager.spi_active = true; // Tell set_directions() a series of SPI transfers is underway
//if (parser.seen('S'))
// tmc_set_report_interval(parser.value_bool());
//else
#if AXIS_IS_L64XX(X)
L6470_say_status(X);
#endif
#if AXIS_IS_L64XX(X2)
L6470_say_status(X2);
#endif
#if AXIS_IS_L64XX(Y)
L6470_say_status(Y);
#endif
#if AXIS_IS_L64XX(Y2)
L6470_say_status(Y2);
#endif
#if AXIS_IS_L64XX(Z)
L6470_say_status(Z);
#endif
#if AXIS_IS_L64XX(Z2)
L6470_say_status(Z2);
#endif
#if AXIS_IS_L64XX(Z3)
L6470_say_status(Z3);
#endif
#if AXIS_IS_L64XX(Z4)
L6470_say_status(Z4);
#endif
#if AXIS_IS_L64XX(E0)
L6470_say_status(E0);
#endif
#if AXIS_IS_L64XX(E1)
L6470_say_status(E1);
#endif
#if AXIS_IS_L64XX(E2)
L6470_say_status(E2);
#endif
#if AXIS_IS_L64XX(E3)
L6470_say_status(E3);
#endif
#if AXIS_IS_L64XX(E4)
L6470_say_status(E4);
#endif
#if AXIS_IS_L64XX(E5)
L6470_say_status(E5);
#endif
#if AXIS_IS_L64XX(E6)
L6470_say_status(E6);
#endif
#if AXIS_IS_L64XX(E7)
L6470_say_status(E7);
#endif
L64xxManager.spi_active = false; // done with all SPI transfers - clear handshake flags
L64xxManager.spi_abort = false;
L64xxManager.pause_monitor(false);
}
#endif // HAS_L64XX

View File

@@ -1,417 +0,0 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "../../../inc/MarlinConfig.h"
#if HAS_L64XX
#if AXIS_COLLISION('I')
#error "M906 parameter 'I' collision with axis name."
#endif
#include "../../gcode.h"
#include "../../../libs/L64XX/L64XX_Marlin.h"
#include "../../../module/stepper/indirection.h"
#include "../../../module/planner.h"
#define DEBUG_OUT ENABLED(L6470_CHITCHAT)
#include "../../../core/debug_out.h"
/**
* MACRO to fetch information on the items associated with current limiting
* and maximum voltage output.
*
* L6470 can be setup to shutdown if either current threshold is exceeded.
*
* L6470 output current can not be set directly. It is set indirectly by
* setting the maximum effective output voltage.
*
* Effective output voltage is set by PWM duty cycle.
*
* Maximum effective output voltage is affected by MANY variables. The main ones are:
* KVAL_HOLD
* KVAL_RUN
* KVAL_ACC
* KVAL_DEC
* Vs compensation (if enabled)
*/
void L64XX_report_current(L64XX &motor, const L64XX_axis_t axis) {
if (L64xxManager.spi_abort) return; // don't do anything if set_directions() has occurred
const L64XX_Marlin::L64XX_shadow_t &sh = L64xxManager.shadow;
const uint16_t status = L64xxManager.get_status(axis); //also populates shadow structure
const uint8_t OverCurrent_Threshold = uint8_t(motor.GetParam(L6470_OCD_TH));
auto say_axis_status = [](const L64XX_axis_t axis, const uint16_t status) {
L64xxManager.say_axis(axis);
#if ENABLED(L6470_CHITCHAT)
char tmp[10];
sprintf_P(tmp, PSTR("%4x "), status);
DEBUG_ECHOPGM(" status: ", tmp);
print_bin(status);
#else
UNUSED(status);
#endif
SERIAL_EOL();
};
char temp_buf[10];
switch (sh.STATUS_AXIS_LAYOUT) {
case L6470_STATUS_LAYOUT: // L6470
case L6480_STATUS_LAYOUT: { // L6480 & powerstep01
const uint16_t Stall_Threshold = (uint8_t)motor.GetParam(L6470_STALL_TH),
motor_status = (status & (STATUS_MOT_STATUS)) >> 5,
L6470_ADC_out = motor.GetParam(L6470_ADC_OUT),
L6470_ADC_out_limited = constrain(L6470_ADC_out, 8, 24);
const float comp_coef = 1600.0f / L6470_ADC_out_limited;
const uint16_t MicroSteps = _BV(motor.GetParam(L6470_STEP_MODE) & 0x07);
say_axis_status(axis, sh.STATUS_AXIS_RAW);
SERIAL_ECHOPGM("...OverCurrent Threshold: ");
sprintf_P(temp_buf, PSTR("%2d ("), OverCurrent_Threshold);
SERIAL_ECHO(temp_buf);
SERIAL_ECHO((OverCurrent_Threshold + 1) * motor.OCD_CURRENT_CONSTANT_INV);
SERIAL_ECHOPGM(" mA)");
SERIAL_ECHOPGM(" Stall Threshold: ");
sprintf_P(temp_buf, PSTR("%2d ("), Stall_Threshold);
SERIAL_ECHO(temp_buf);
SERIAL_ECHO((Stall_Threshold + 1) * motor.STALL_CURRENT_CONSTANT_INV);
SERIAL_ECHOPGM(" mA)");
SERIAL_ECHOPGM(" Motor Status: ");
switch (motor_status) {
case 0: SERIAL_ECHOPGM("stopped"); break;
case 1: SERIAL_ECHOPGM("accelerating"); break;
case 2: SERIAL_ECHOPGM("decelerating"); break;
case 3: SERIAL_ECHOPGM("at constant speed"); break;
}
SERIAL_EOL();
SERIAL_ECHOPGM("...MicroSteps: ", MicroSteps,
" ADC_OUT: ", L6470_ADC_out);
SERIAL_ECHOPGM(" Vs_compensation: ");
SERIAL_ECHOF((motor.GetParam(sh.L6470_AXIS_CONFIG) & CONFIG_EN_VSCOMP) ? F("ENABLED ") : F("DISABLED"));
SERIAL_ECHOLNPGM(" Compensation coefficient: ~", comp_coef * 0.01f);
SERIAL_ECHOPGM("...KVAL_HOLD: ", motor.GetParam(L6470_KVAL_HOLD),
" KVAL_RUN : ", motor.GetParam(L6470_KVAL_RUN),
" KVAL_ACC: ", motor.GetParam(L6470_KVAL_ACC),
" KVAL_DEC: ", motor.GetParam(L6470_KVAL_DEC),
" V motor max = ");
switch (motor_status) {
case 0: SERIAL_ECHO(motor.GetParam(L6470_KVAL_HOLD) * 100 / 256); SERIAL_ECHOPGM("% (KVAL_HOLD)"); break;
case 1: SERIAL_ECHO(motor.GetParam(L6470_KVAL_RUN) * 100 / 256); SERIAL_ECHOPGM("% (KVAL_RUN)"); break;
case 2: SERIAL_ECHO(motor.GetParam(L6470_KVAL_ACC) * 100 / 256); SERIAL_ECHOPGM("% (KVAL_ACC)"); break;
case 3: SERIAL_ECHO(motor.GetParam(L6470_KVAL_DEC) * 100 / 256); SERIAL_ECHOPGM("% (KVAL_HOLD)"); break;
}
SERIAL_EOL();
#if ENABLED(L6470_CHITCHAT)
DEBUG_ECHOPGM("...SLEW RATE: ");
switch (sh.STATUS_AXIS_LAYOUT) {
case L6470_STATUS_LAYOUT: {
switch ((motor.GetParam(sh.L6470_AXIS_CONFIG) & CONFIG_POW_SR) >> CONFIG_POW_SR_BIT) {
case 0: { DEBUG_ECHOLNPGM("320V/uS") ; break; }
case 1: { DEBUG_ECHOLNPGM("75V/uS") ; break; }
case 2: { DEBUG_ECHOLNPGM("110V/uS") ; break; }
case 3: { DEBUG_ECHOLNPGM("260V/uS") ; break; }
}
break;
}
case L6480_STATUS_LAYOUT: {
switch (motor.GetParam(L6470_GATECFG1) & CONFIG1_SR ) {
case CONFIG1_SR_220V_us: { DEBUG_ECHOLNPGM("220V/uS") ; break; }
case CONFIG1_SR_400V_us: { DEBUG_ECHOLNPGM("400V/uS") ; break; }
case CONFIG1_SR_520V_us: { DEBUG_ECHOLNPGM("520V/uS") ; break; }
case CONFIG1_SR_980V_us: { DEBUG_ECHOLNPGM("980V/uS") ; break; }
default: { DEBUG_ECHOLNPGM("unknown") ; break; }
}
}
}
#endif
SERIAL_EOL();
break;
}
case L6474_STATUS_LAYOUT: { // L6474
const uint16_t L6470_ADC_out = motor.GetParam(L6470_ADC_OUT) & 0x1F,
L6474_TVAL_val = motor.GetParam(L6474_TVAL) & 0x7F;
say_axis_status(axis, sh.STATUS_AXIS_RAW);
SERIAL_ECHOPGM("...OverCurrent Threshold: ");
sprintf_P(temp_buf, PSTR("%2d ("), OverCurrent_Threshold);
SERIAL_ECHO(temp_buf);
SERIAL_ECHO((OverCurrent_Threshold + 1) * motor.OCD_CURRENT_CONSTANT_INV);
SERIAL_ECHOPGM(" mA)");
SERIAL_ECHOPGM(" TVAL: ");
sprintf_P(temp_buf, PSTR("%2d ("), L6474_TVAL_val);
SERIAL_ECHO(temp_buf);
SERIAL_ECHO((L6474_TVAL_val + 1) * motor.STALL_CURRENT_CONSTANT_INV);
SERIAL_ECHOLNPGM(" mA) Motor Status: NA");
const uint16_t MicroSteps = _BV(motor.GetParam(L6470_STEP_MODE) & 0x07); //NOMORE(MicroSteps, 16);
SERIAL_ECHOPGM("...MicroSteps: ", MicroSteps,
" ADC_OUT: ", L6470_ADC_out);
SERIAL_ECHOLNPGM(" Vs_compensation: NA\n");
SERIAL_ECHOLNPGM("...KVAL_HOLD: NA"
" KVAL_RUN : NA"
" KVAL_ACC: NA"
" KVAL_DEC: NA"
" V motor max = NA");
#if ENABLED(L6470_CHITCHAT)
DEBUG_ECHOPGM("...SLEW RATE: ");
switch ((motor.GetParam(sh.L6470_AXIS_CONFIG) & CONFIG_POW_SR) >> CONFIG_POW_SR_BIT) {
case 0: DEBUG_ECHOLNPGM("320V/uS") ; break;
case 1: DEBUG_ECHOLNPGM("75V/uS") ; break;
case 2: DEBUG_ECHOLNPGM("110V/uS") ; break;
case 3: DEBUG_ECHOLNPGM("260V/uS") ; break;
default: DEBUG_ECHOLNPGM("slew rate: ", (motor.GetParam(sh.L6470_AXIS_CONFIG) & CONFIG_POW_SR) >> CONFIG_POW_SR_BIT); break;
}
#endif
SERIAL_EOL();
SERIAL_EOL();
break;
}
}
}
/**
* M906: report or set KVAL_HOLD which sets the maximum effective voltage provided by the
* PWMs to the steppers
*
* On L6474 this sets the TVAL register (same address).
*
* I - select which driver(s) to change on multi-driver axis
* (default) all drivers on the axis
* 0 - monitor only the first XYZ... driver
* 1 - monitor only X2, Y2, Z2
* 2 - monitor only Z3
* 3 - monitor only Z4
* Xxxx, Yxxx, Zxxx, Axxx, Bxxx, Cxxx, Uxxx, Vxxx, Wxxx, Exxx - axis to change (optional)
* L6474 - current in mA (4A max)
* All others - 0-255
*
* Sets KVAL_HOLD which affects the current being driven through the stepper.
*
* L6470 is used in the STEP-CLOCK mode. KVAL_HOLD is the only KVAL_xxx
* that affects the effective voltage seen by the stepper.
*/
void GcodeSuite::M906() {
L64xxManager.pause_monitor(true); // Keep monitor_driver() from stealing status
#define L6470_SET_KVAL_HOLD(Q) (AXIS_IS_L64XX(Q) ? stepper##Q.setTVALCurrent(value) : stepper##Q.SetParam(L6470_KVAL_HOLD, uint8_t(value)))
DEBUG_ECHOLNPGM("M906");
uint8_t report_current = true;
#if AXIS_IS_L64XX(X2) || AXIS_IS_L64XX(Y2) || AXIS_IS_L64XX(Z2) || AXIS_IS_L64XX(Z3) || AXIS_IS_L64XX(Z4)
const int8_t index = parser.byteval('I', -1);
#else
constexpr int8_t index = -1;
#endif
LOOP_LOGICAL_AXES(i) if (uint16_t value = parser.intval(AXIS_CHAR(i))) {
report_current = false;
if (planner.has_blocks_queued() || planner.cleaning_buffer_counter) {
SERIAL_ECHOLNPGM("Test aborted. Can't set KVAL_HOLD while steppers are moving.");
return;
}
switch (i) {
#if AXIS_IS_L64XX(X) || AXIS_IS_L64XX(X2)
case X_AXIS:
#if AXIS_IS_L64XX(X)
if (index < 0 || index == 0) L6470_SET_KVAL_HOLD(X);
#endif
#if AXIS_IS_L64XX(X2)
if (index < 0 || index == 1) L6470_SET_KVAL_HOLD(X2);
#endif
break;
#endif
#if AXIS_IS_L64XX(Y) || AXIS_IS_L64XX(Y2)
case Y_AXIS:
#if AXIS_IS_L64XX(Y)
if (index < 0 || index == 0) L6470_SET_KVAL_HOLD(Y);
#endif
#if AXIS_IS_L64XX(Y2)
if (index < 0 || index == 1) L6470_SET_KVAL_HOLD(Y2);
#endif
break;
#endif
#if AXIS_IS_L64XX(Z) || AXIS_IS_L64XX(Z2) || AXIS_IS_L64XX(Z3) || AXIS_IS_L64XX(Z4)
case Z_AXIS:
#if AXIS_IS_L64XX(Z)
if (index < 0 || index == 0) L6470_SET_KVAL_HOLD(Z);
#endif
#if AXIS_IS_L64XX(Z2)
if (index < 0 || index == 1) L6470_SET_KVAL_HOLD(Z2);
#endif
#if AXIS_IS_L64XX(Z3)
if (index < 0 || index == 2) L6470_SET_KVAL_HOLD(Z3);
#endif
#if AXIS_IS_L64XX(Z4)
if (index < 0 || index == 3) L6470_SET_KVAL_HOLD(Z4);
#endif
break;
#endif
#if AXIS_IS_L64XX(I)
case I_AXIS: L6470_SET_KVAL_HOLD(I); break;
#endif
#if AXIS_IS_L64XX(J)
case J_AXIS: L6470_SET_KVAL_HOLD(J); break;
#endif
#if AXIS_IS_L64XX(K)
case K_AXIS: L6470_SET_KVAL_HOLD(K); break;
#endif
#if AXIS_IS_L64XX(U)
case U_AXIS: L6470_SET_KVAL_HOLD(U); break;
#endif
#if AXIS_IS_L64XX(V)
case V_AXIS: L6470_SET_KVAL_HOLD(V); break;
#endif
#if AXIS_IS_L64XX(W)
case W_AXIS: L6470_SET_KVAL_HOLD(W); break;
#endif
#if AXIS_IS_L64XX(E0) || AXIS_IS_L64XX(E1) || AXIS_IS_L64XX(E2) || AXIS_IS_L64XX(E3) || AXIS_IS_L64XX(E4) || AXIS_IS_L64XX(E5) || AXIS_IS_L64XX(E6) || AXIS_IS_L64XX(E7)
case E_AXIS: {
const int8_t eindex = get_target_e_stepper_from_command(-2);
#if AXIS_IS_L64XX(E0)
if (eindex < 0 || eindex == 0) L6470_SET_KVAL_HOLD(E0);
#endif
#if AXIS_IS_L64XX(E1)
if (eindex < 0 || eindex == 1) L6470_SET_KVAL_HOLD(E1);
#endif
#if AXIS_IS_L64XX(E2)
if (eindex < 0 || eindex == 2) L6470_SET_KVAL_HOLD(E2);
#endif
#if AXIS_IS_L64XX(E3)
if (eindex < 0 || eindex == 3) L6470_SET_KVAL_HOLD(E3);
#endif
#if AXIS_IS_L64XX(E4)
if (eindex < 0 || eindex == 4) L6470_SET_KVAL_HOLD(E4);
#endif
#if AXIS_IS_L64XX(E5)
if (eindex < 0 || eindex == 5) L6470_SET_KVAL_HOLD(E5);
#endif
#if AXIS_IS_L64XX(E6)
if (eindex < 0 || eindex == 6) L6470_SET_KVAL_HOLD(E6);
#endif
#if AXIS_IS_L64XX(E7)
if (eindex < 0 || eindex == 7) L6470_SET_KVAL_HOLD(E7);
#endif
} break;
#endif
}
}
if (report_current) {
#define L64XX_REPORT_CURRENT(Q) L64XX_report_current(stepper##Q, Q)
L64xxManager.spi_active = true; // Tell set_directions() a series of SPI transfers is underway
#if AXIS_IS_L64XX(X)
L64XX_REPORT_CURRENT(X);
#endif
#if AXIS_IS_L64XX(X2)
L64XX_REPORT_CURRENT(X2);
#endif
#if AXIS_IS_L64XX(Y)
L64XX_REPORT_CURRENT(Y);
#endif
#if AXIS_IS_L64XX(Y2)
L64XX_REPORT_CURRENT(Y2);
#endif
#if AXIS_IS_L64XX(Z)
L64XX_REPORT_CURRENT(Z);
#endif
#if AXIS_IS_L64XX(Z2)
L64XX_REPORT_CURRENT(Z2);
#endif
#if AXIS_IS_L64XX(Z3)
L64XX_REPORT_CURRENT(Z3);
#endif
#if AXIS_IS_L64XX(Z4)
L64XX_REPORT_CURRENT(Z4);
#endif
#if AXIS_IS_L64XX(I)
L64XX_REPORT_CURRENT(I);
#endif
#if AXIS_IS_L64XX(J)
L64XX_REPORT_CURRENT(J);
#endif
#if AXIS_IS_L64XX(K)
L64XX_REPORT_CURRENT(K);
#endif
#if AXIS_IS_L64XX(U)
L64XX_REPORT_CURRENT(U);
#endif
#if AXIS_IS_L64XX(V)
L64XX_REPORT_CURRENT(V);
#endif
#if AXIS_IS_L64XX(W)
L64XX_REPORT_CURRENT(W);
#endif
#if AXIS_IS_L64XX(E0)
L64XX_REPORT_CURRENT(E0);
#endif
#if AXIS_IS_L64XX(E1)
L64XX_REPORT_CURRENT(E1);
#endif
#if AXIS_IS_L64XX(E2)
L64XX_REPORT_CURRENT(E2);
#endif
#if AXIS_IS_L64XX(E3)
L64XX_REPORT_CURRENT(E3);
#endif
#if AXIS_IS_L64XX(E4)
L64XX_REPORT_CURRENT(E4);
#endif
#if AXIS_IS_L64XX(E5)
L64XX_REPORT_CURRENT(E5);
#endif
#if AXIS_IS_L64XX(E6)
L64XX_REPORT_CURRENT(E6);
#endif
#if AXIS_IS_L64XX(E7)
L64XX_REPORT_CURRENT(E7);
#endif
L64xxManager.spi_active = false; // done with all SPI transfers - clear handshake flags
L64xxManager.spi_abort = false;
L64xxManager.pause_monitor(false);
}
}
#endif // HAS_L64XX

View File

@@ -1,650 +0,0 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
//
// NOTE: All tests assume each axis uses matching driver chips.
//
#include "../../../inc/MarlinConfig.h"
#if HAS_L64XX
#include "../../gcode.h"
#include "../../../module/stepper/indirection.h"
#include "../../../module/planner.h"
#include "../../../libs/L64XX/L64XX_Marlin.h"
#define DEBUG_OUT ENABLED(L6470_CHITCHAT)
#include "../../../core/debug_out.h"
/**
* M916: increase KVAL_HOLD until get thermal warning
* NOTE - on L6474 it is TVAL that is used
*
* J - select which driver(s) to monitor on multi-driver axis
* 0 - (default) monitor all drivers on the axis or E0
* 1 - monitor only X, Y, Z, E1
* 2 - monitor only X2, Y2, Z2, E2
* 3 - monitor only Z3, E3
* 4 - monitor only Z4, E4
*
* Xxxx, Yxxx, Zxxx, Exxx - axis to be monitored with displacement
* xxx (1-255) is distance moved on either side of current position
*
* F - feedrate
* optional - will use default max feedrate from configuration.h if not specified
*
* T - current (mA) setting for TVAL (0 - 4A in 31.25mA increments, rounds down) - L6474 only
* optional - will report current value from driver if not specified
*
* K - value for KVAL_HOLD (0 - 255) (ignored for L6474)
* optional - will report current value from driver if not specified
*
* D - time (in seconds) to run each setting of KVAL_HOLD/TVAL
* optional - defaults to zero (runs each setting once)
*/
/**
* This routine is also useful for determining the approximate KVAL_HOLD
* where the stepper stops losing steps. The sound will get noticeably quieter
* as it stops losing steps.
*/
void GcodeSuite::M916() {
DEBUG_ECHOLNPGM("M916");
L64xxManager.pause_monitor(true); // Keep monitor_driver() from stealing status
// Variables used by L64xxManager.get_user_input function - some may not be used
char axis_mon[3][3] = { {" "}, {" "}, {" "} }; // list of Axes to be monitored
L64XX_axis_t axis_index[3];
uint16_t axis_status[3];
uint8_t driver_count = 1;
float position_max;
float position_min;
float final_feedrate;
uint8_t kval_hold;
uint8_t OCD_TH_val = 0;
uint8_t STALL_TH_val = 0;
uint16_t over_current_threshold;
constexpr uint8_t over_current_flag = false; // M916 doesn't play with the overcurrent thresholds
#define DRIVER_TYPE_L6474(Q) AXIS_DRIVER_TYPE_##Q(L6474)
uint8_t j; // general purpose counter
if (L64xxManager.get_user_input(driver_count, axis_index, axis_mon, position_max, position_min, final_feedrate, kval_hold, over_current_flag, OCD_TH_val, STALL_TH_val, over_current_threshold))
return; // quit if invalid user input
DEBUG_ECHOLNPGM("feedrate = ", final_feedrate);
planner.synchronize(); // wait for all current movement commands to complete
const L64XX_Marlin::L64XX_shadow_t &sh = L64xxManager.shadow;
for (j = 0; j < driver_count; j++)
L64xxManager.get_status(axis_index[j]); // clear out any pre-existing error flags
char temp_axis_string[] = " ";
temp_axis_string[0] = axis_mon[0][0]; // need to have a string for use within sprintf format section
char gcode_string[80];
uint16_t status_composite = 0;
uint16_t M91x_counter = kval_hold;
uint16_t M91x_counter_max;
if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT) {
M91x_counter_max = 128; // TVAL is 7 bits
LIMIT(M91x_counter, 0U, 127U);
}
else
M91x_counter_max = 256; // KVAL_HOLD is 8 bits
uint8_t M91x_delay_s = parser.byteval('D'); // get delay in seconds
millis_t M91x_delay_ms = SEC_TO_MS(M91x_delay_s * 60);
millis_t M91x_delay_end;
DEBUG_ECHOLNPGM(".\n.");
do {
if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT)
DEBUG_ECHOLNPGM("TVAL current (mA) = ", (M91x_counter + 1) * sh.AXIS_STALL_CURRENT_CONSTANT_INV); // report TVAL current for this run
else
DEBUG_ECHOLNPGM("kval_hold = ", M91x_counter); // report KVAL_HOLD for this run
for (j = 0; j < driver_count; j++)
L64xxManager.set_param(axis_index[j], L6470_KVAL_HOLD, M91x_counter); //set KVAL_HOLD or TVAL (same register address)
M91x_delay_end = millis() + M91x_delay_ms;
do {
// turn the motor(s) both directions
sprintf_P(gcode_string, PSTR("G0 %s%03d F%03d"), temp_axis_string, uint16_t(position_min), uint16_t(final_feedrate));
process_subcommands_now(gcode_string);
sprintf_P(gcode_string, PSTR("G0 %s%03d F%03d"), temp_axis_string, uint16_t(position_max), uint16_t(final_feedrate));
process_subcommands_now(gcode_string);
// get the status after the motors have stopped
planner.synchronize();
status_composite = 0; // clear out the old bits
for (j = 0; j < driver_count; j++) {
axis_status[j] = (~L64xxManager.get_status(axis_index[j])) & sh.L6470_ERROR_MASK; // bits of interest are all active low
status_composite |= axis_status[j] ;
}
if (status_composite) break;
} while (millis() < M91x_delay_end);
if (status_composite) break;
M91x_counter++;
} while (!(status_composite & (sh.STATUS_AXIS_TH_WRN | sh.STATUS_AXIS_TH_SD)) && (M91x_counter < M91x_counter_max));
DEBUG_ECHOLNPGM(".");
#if ENABLED(L6470_CHITCHAT)
if (status_composite) {
L64xxManager.error_status_decode(status_composite, axis_index[0],
sh.STATUS_AXIS_TH_SD, sh.STATUS_AXIS_TH_WRN,
sh.STATUS_AXIS_STEP_LOSS_A, sh.STATUS_AXIS_STEP_LOSS_B,
sh.STATUS_AXIS_OCD, sh.STATUS_AXIS_LAYOUT);
DEBUG_ECHOLNPGM(".");
}
#endif
if ((status_composite & (sh.STATUS_AXIS_TH_WRN | sh.STATUS_AXIS_TH_SD)))
DEBUG_ECHOLNPGM(".\n.\nTest completed normally - Thermal warning/shutdown has occurred");
else if (status_composite)
DEBUG_ECHOLNPGM(".\n.\nTest completed abnormally - non-thermal error has occurred");
else
DEBUG_ECHOLNPGM(".\n.\nTest completed normally - Unable to get to thermal warning/shutdown");
L64xxManager.pause_monitor(false);
}
/**
* M917: Find minimum current thresholds
*
* Decrease OCD current until overcurrent error
* Increase OCD until overcurrent error goes away
* Decrease stall threshold until stall (not done on L6474)
* Increase stall until stall error goes away (not done on L6474)
*
* J - select which driver(s) to monitor on multi-driver axis
* 0 - (default) monitor all drivers on the axis or E0
* 1 - monitor only X, Y, Z, E1
* 2 - monitor only X2, Y2, Z2, E2
* Xxxx, Yxxx, Zxxx, Exxx - axis to be monitored with displacement
* xxx (1-255) is distance moved on either side of current position
*
* F - feedrate
* optional - will use default max feedrate from Configuration.h if not specified
*
* I - starting over-current threshold
* optional - will report current value from driver if not specified
* if there are multiple drivers on the axis then all will be set the same
*
* T - current (mA) setting for TVAL (0 - 4A in 31.25mA increments, rounds down) - L6474 only
* optional - will report current value from driver if not specified
*
* K - value for KVAL_HOLD (0 - 255) (ignored for L6474)
* optional - will report current value from driver if not specified
*/
void GcodeSuite::M917() {
DEBUG_ECHOLNPGM("M917");
L64xxManager.pause_monitor(true); // Keep monitor_driver() from stealing status
char axis_mon[3][3] = { {" "}, {" "}, {" "} }; // list of Axes to be monitored
L64XX_axis_t axis_index[3];
uint16_t axis_status[3];
uint8_t driver_count = 1;
float position_max;
float position_min;
float final_feedrate;
uint8_t kval_hold;
uint8_t OCD_TH_val = 0;
uint8_t STALL_TH_val = 0;
uint16_t over_current_threshold;
constexpr uint8_t over_current_flag = true;
uint8_t j; // general purpose counter
if (L64xxManager.get_user_input(driver_count, axis_index, axis_mon, position_max, position_min, final_feedrate, kval_hold, over_current_flag, OCD_TH_val, STALL_TH_val, over_current_threshold))
return; // quit if invalid user input
DEBUG_ECHOLNPGM("feedrate = ", final_feedrate);
planner.synchronize(); // wait for all current movement commands to complete
const L64XX_Marlin::L64XX_shadow_t &sh = L64xxManager.shadow;
for (j = 0; j < driver_count; j++)
L64xxManager.get_status(axis_index[j]); // clear error flags
char temp_axis_string[] = " ";
temp_axis_string[0] = axis_mon[0][0]; // need a sprintf format string
char gcode_string[80];
uint16_t status_composite = 0;
uint8_t test_phase = 0; // 0 - decreasing OCD - exit when OCD warning occurs (ignore STALL)
// 1 - increasing OCD - exit when OCD warning stops (ignore STALL)
// 2 - OCD finalized - decreasing STALL - exit when STALL warning happens
// 3 - OCD finalized - increasing STALL - exit when STALL warning stop
// 4 - all testing completed
DEBUG_ECHOPGM(".\n.\n.\nover_current threshold : ", (OCD_TH_val + 1) * 375); // first status display
DEBUG_ECHOPGM(" (OCD_TH: : ", OCD_TH_val);
if (sh.STATUS_AXIS_LAYOUT != L6474_STATUS_LAYOUT) {
DEBUG_ECHOPGM(") Stall threshold: ", (STALL_TH_val + 1) * 31.25);
DEBUG_ECHOPGM(" (STALL_TH: ", STALL_TH_val);
}
DEBUG_ECHOLNPGM(")");
do {
if (sh.STATUS_AXIS_LAYOUT != L6474_STATUS_LAYOUT) DEBUG_ECHOPGM("STALL threshold : ", (STALL_TH_val + 1) * 31.25);
DEBUG_ECHOLNPGM(" OCD threshold : ", (OCD_TH_val + 1) * 375);
sprintf_P(gcode_string, PSTR("G0 %s%03d F%03d"), temp_axis_string, uint16_t(position_min), uint16_t(final_feedrate));
process_subcommands_now(gcode_string);
sprintf_P(gcode_string, PSTR("G0 %s%03d F%03d"), temp_axis_string, uint16_t(position_max), uint16_t(final_feedrate));
process_subcommands_now(gcode_string);
planner.synchronize();
status_composite = 0; // clear out the old bits
for (j = 0; j < driver_count; j++) {
axis_status[j] = (~L64xxManager.get_status(axis_index[j])) & sh.L6470_ERROR_MASK; // bits of interest are all active low
status_composite |= axis_status[j];
}
if (status_composite && (status_composite & sh.STATUS_AXIS_UVLO)) {
DEBUG_ECHOLNPGM("Test aborted (Undervoltage lockout active)");
#if ENABLED(L6470_CHITCHAT)
for (j = 0; j < driver_count; j++) {
if (j) DEBUG_ECHOPGM("...");
L64xxManager.error_status_decode(axis_status[j], axis_index[j],
sh.STATUS_AXIS_TH_SD, sh.STATUS_AXIS_TH_WRN,
sh.STATUS_AXIS_STEP_LOSS_A, sh.STATUS_AXIS_STEP_LOSS_B,
sh.STATUS_AXIS_OCD, sh.STATUS_AXIS_LAYOUT);
}
#endif
return;
}
if (status_composite & (sh.STATUS_AXIS_TH_WRN | sh.STATUS_AXIS_TH_SD)) {
DEBUG_ECHOLNPGM("thermal problem - waiting for chip(s) to cool down ");
uint16_t status_composite_temp = 0;
uint8_t k = 0;
do {
k++;
if (!(k % 4)) {
kval_hold *= 0.95;
DEBUG_EOL();
DEBUG_ECHOLNPGM("Lowering KVAL_HOLD by about 5% to ", kval_hold);
for (j = 0; j < driver_count; j++)
L64xxManager.set_param(axis_index[j], L6470_KVAL_HOLD, kval_hold);
}
DEBUG_ECHOLNPGM(".");
reset_stepper_timeout(); // keep steppers powered
safe_delay(5000);
status_composite_temp = 0;
for (j = 0; j < driver_count; j++) {
axis_status[j] = (~L64xxManager.get_status(axis_index[j])) & sh.L6470_ERROR_MASK; // bits of interest are all active low
status_composite_temp |= axis_status[j];
}
}
while (status_composite_temp & (sh.STATUS_AXIS_TH_WRN | sh.STATUS_AXIS_TH_SD));
DEBUG_EOL();
}
if (status_composite & (sh.STATUS_AXIS_STEP_LOSS_A | sh.STATUS_AXIS_STEP_LOSS_B | sh.STATUS_AXIS_OCD)) {
switch (test_phase) {
case 0: {
if (status_composite & sh.STATUS_AXIS_OCD) {
// phase 0 with OCD warning - time to go to next phase
if (OCD_TH_val >= sh.AXIS_OCD_TH_MAX) {
OCD_TH_val = sh.AXIS_OCD_TH_MAX; // limit to max
test_phase = 2; // at highest value so skip phase 1
//DEBUG_ECHOLNPGM("LOGIC E0A OCD at highest - skip to 2");
DEBUG_ECHOLNPGM("OCD at highest - OCD finalized");
}
else {
OCD_TH_val++; // normal exit to next phase
test_phase = 1; // setup for first pass of phase 1
//DEBUG_ECHOLNPGM("LOGIC E0B - inc OCD & go to 1");
DEBUG_ECHOLNPGM("inc OCD");
}
}
else { // phase 0 without OCD warning - keep on decrementing if can
if (OCD_TH_val) {
OCD_TH_val--; // try lower value
//DEBUG_ECHOLNPGM("LOGIC E0C - dec OCD");
DEBUG_ECHOLNPGM("dec OCD");
}
else {
test_phase = 2; // at lowest value without warning so skip phase 1
//DEBUG_ECHOLNPGM("LOGIC E0D - OCD at latest - go to 2");
DEBUG_ECHOLNPGM("OCD finalized");
}
}
} break;
case 1: {
if (status_composite & sh.STATUS_AXIS_OCD) {
// phase 1 with OCD warning - increment if can
if (OCD_TH_val >= sh.AXIS_OCD_TH_MAX) {
OCD_TH_val = sh.AXIS_OCD_TH_MAX; // limit to max
test_phase = 2; // at highest value so go to next phase
//DEBUG_ECHOLNPGM("LOGIC E1A - OCD at max - go to 2");
DEBUG_ECHOLNPGM("OCD finalized");
}
else {
OCD_TH_val++; // try a higher value
//DEBUG_ECHOLNPGM("LOGIC E1B - inc OCD");
DEBUG_ECHOLNPGM("inc OCD");
}
}
else { // phase 1 without OCD warning - normal exit to phase 2
test_phase = 2;
//DEBUG_ECHOLNPGM("LOGIC E1C - no OCD warning - go to 1");
DEBUG_ECHOLNPGM("OCD finalized");
}
} break;
case 2: {
if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT) { // skip all STALL_TH steps if L6474
test_phase = 4;
break;
}
if (status_composite & (sh.STATUS_AXIS_STEP_LOSS_A | sh.STATUS_AXIS_STEP_LOSS_B)) {
// phase 2 with stall warning - time to go to next phase
if (STALL_TH_val >= 127) {
STALL_TH_val = 127; // limit to max
//DEBUG_ECHOLNPGM("LOGIC E2A - STALL warning, STALL at max, quit");
DEBUG_ECHOLNPGM("finished - STALL at maximum value but still have stall warning");
test_phase = 4;
}
else {
test_phase = 3; // normal exit to next phase (found failing value of STALL)
STALL_TH_val++; // setup for first pass of phase 3
//DEBUG_ECHOLNPGM("LOGIC E2B - INC - STALL warning, inc Stall, go to 3");
DEBUG_ECHOLNPGM("inc Stall");
}
}
else { // phase 2 without stall warning - decrement if can
if (STALL_TH_val) {
STALL_TH_val--; // try a lower value
//DEBUG_ECHOLNPGM("LOGIC E2C - no STALL, dec STALL");
DEBUG_ECHOLNPGM("dec STALL");
}
else {
DEBUG_ECHOLNPGM("finished - STALL at lowest value but still do NOT have stall warning");
test_phase = 4;
//DEBUG_ECHOLNPGM("LOGIC E2D - no STALL, at lowest so quit");
}
}
} break;
case 3: {
if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT) { // skip all STALL_TH steps if L6474
test_phase = 4;
break;
}
if (status_composite & (sh.STATUS_AXIS_STEP_LOSS_A | sh.STATUS_AXIS_STEP_LOSS_B)) {
// phase 3 with stall warning - increment if can
if (STALL_TH_val >= 127) {
STALL_TH_val = 127; // limit to max
DEBUG_ECHOLNPGM("finished - STALL at maximum value but still have stall warning");
test_phase = 4;
//DEBUG_ECHOLNPGM("LOGIC E3A - STALL, at max so quit");
}
else {
STALL_TH_val++; // still looking for passing value
//DEBUG_ECHOLNPGM("LOGIC E3B - STALL, inc stall");
DEBUG_ECHOLNPGM("inc stall");
}
}
else { //phase 3 without stall warning but have OCD warning
DEBUG_ECHOLNPGM("Hardware problem - OCD warning without STALL warning");
test_phase = 4;
//DEBUG_ECHOLNPGM("LOGIC E3C - not STALLED, hardware problem (quit)");
}
} break;
}
}
else {
switch (test_phase) {
case 0: { // phase 0 without OCD warning - keep on decrementing if can
if (OCD_TH_val) {
OCD_TH_val--; // try lower value
//DEBUG_ECHOLNPGM("LOGIC N0A - DEC OCD");
DEBUG_ECHOLNPGM("DEC OCD");
}
else {
test_phase = 2; // at lowest value without warning so skip phase 1
//DEBUG_ECHOLNPGM("LOGIC N0B - OCD at lowest (go to phase 2)");
DEBUG_ECHOLNPGM("OCD finalized");
}
} break;
case 1: //DEBUG_ECHOLNPGM("LOGIC N1 (go directly to 2)"); // phase 1 without OCD warning - drop directly to phase 2
DEBUG_ECHOLNPGM("OCD finalized");
case 2: { // phase 2 without stall warning - keep on decrementing if can
if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT) { // skip all STALL_TH steps if L6474
test_phase = 4;
break;
}
if (STALL_TH_val) {
STALL_TH_val--; // try a lower value (stay in phase 2)
//DEBUG_ECHOLNPGM("LOGIC N2B - dec STALL");
DEBUG_ECHOLNPGM("dec STALL");
}
else {
DEBUG_ECHOLNPGM("finished - STALL at lowest value but still no stall warning");
test_phase = 4;
//DEBUG_ECHOLNPGM("LOGIC N2C - STALL at lowest (quit)");
}
} break;
case 3: {
if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT) { // skip all STALL_TH steps if L6474
test_phase = 4;
break;
}
test_phase = 4;
//DEBUG_ECHOLNPGM("LOGIC N3 - finished!");
DEBUG_ECHOLNPGM("finished!");
} break; // phase 3 without any warnings - desired exit
} //
} // end of status checks
if (test_phase != 4) {
for (j = 0; j < driver_count; j++) { // update threshold(s)
L64xxManager.set_param(axis_index[j], L6470_OCD_TH, OCD_TH_val);
if (sh.STATUS_AXIS_LAYOUT != L6474_STATUS_LAYOUT) L64xxManager.set_param(axis_index[j], L6470_STALL_TH, STALL_TH_val);
if (L64xxManager.get_param(axis_index[j], L6470_OCD_TH) != OCD_TH_val) DEBUG_ECHOLNPGM("OCD mismatch");
if ((L64xxManager.get_param(axis_index[j], L6470_STALL_TH) != STALL_TH_val) && (sh.STATUS_AXIS_LAYOUT != L6474_STATUS_LAYOUT)) DEBUG_ECHOLNPGM("STALL mismatch");
}
}
} while (test_phase != 4);
DEBUG_ECHOLNPGM(".");
if (status_composite) {
#if ENABLED(L6470_CHITCHAT)
for (j = 0; j < driver_count; j++) {
if (j) DEBUG_ECHOPGM("...");
L64xxManager.error_status_decode(axis_status[j], axis_index[j],
sh.STATUS_AXIS_TH_SD, sh.STATUS_AXIS_TH_WRN,
sh.STATUS_AXIS_STEP_LOSS_A, sh.STATUS_AXIS_STEP_LOSS_B,
sh.STATUS_AXIS_OCD, sh.STATUS_AXIS_LAYOUT);
}
DEBUG_ECHOLNPGM(".");
#endif
DEBUG_ECHOLNPGM("Completed with errors");
}
else
DEBUG_ECHOLNPGM("Completed with no errors");
DEBUG_ECHOLNPGM(".");
L64xxManager.pause_monitor(false);
}
/**
* M918: increase speed until error or max feedrate achieved (as shown in configuration.h))
*
* J - select which driver(s) to monitor on multi-driver axis
* 0 - (default) monitor all drivers on the axis or E0
* 1 - monitor only X, Y, Z, E1
* 2 - monitor only X2, Y2, Z2, E2
* Xxxx, Yxxx, Zxxx, Exxx - axis to be monitored with displacement
* xxx (1-255) is distance moved on either side of current position
*
* I - over current threshold
* optional - will report current value from driver if not specified
*
* T - current (mA) setting for TVAL (0 - 4A in 31.25mA increments, rounds down) - L6474 only
* optional - will report current value from driver if not specified
*
* K - value for KVAL_HOLD (0 - 255) (ignored for L6474)
* optional - will report current value from driver if not specified
*
* M - value for microsteps (1 - 128) (optional)
* optional - will report current value from driver if not specified
*/
void GcodeSuite::M918() {
DEBUG_ECHOLNPGM("M918");
L64xxManager.pause_monitor(true); // Keep monitor_driver() from stealing status
char axis_mon[3][3] = { {" "}, {" "}, {" "} }; // list of Axes to be monitored
L64XX_axis_t axis_index[3];
uint16_t axis_status[3];
uint8_t driver_count = 1;
float position_max, position_min;
float final_feedrate;
uint8_t kval_hold;
uint8_t OCD_TH_val = 0;
uint8_t STALL_TH_val = 0;
uint16_t over_current_threshold;
constexpr uint8_t over_current_flag = true;
const L64XX_Marlin::L64XX_shadow_t &sh = L64xxManager.shadow;
uint8_t j; // general purpose counter
if (L64xxManager.get_user_input(driver_count, axis_index, axis_mon, position_max, position_min, final_feedrate, kval_hold, over_current_flag, OCD_TH_val, STALL_TH_val, over_current_threshold))
return; // quit if invalid user input
L64xxManager.get_status(axis_index[0]); // populate shadow array
uint8_t m_steps = parser.byteval('M');
if (m_steps != 0) {
LIMIT(m_steps, 1, sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT ? 16 : 128); // L6474
uint8_t stepVal;
for (stepVal = 0; stepVal < 8; stepVal++) { // convert to L64xx register value
if (m_steps == 1) break;
m_steps >>= 1;
}
if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT)
stepVal |= 0x98; // NO SYNC
else
stepVal |= (!SYNC_EN) | SYNC_SEL_1 | stepVal;
for (j = 0; j < driver_count; j++) {
L64xxManager.set_param(axis_index[j], dSPIN_HARD_HIZ, 0); // can't write STEP register if stepper being powered
// results in an extra NOOP being sent (data 00)
L64xxManager.set_param(axis_index[j], L6470_STEP_MODE, stepVal); // set microsteps
}
}
m_steps = L64xxManager.get_param(axis_index[0], L6470_STEP_MODE) & 0x07; // get microsteps
DEBUG_ECHOLNPGM("Microsteps = ", _BV(m_steps));
DEBUG_ECHOLNPGM("target (maximum) feedrate = ", final_feedrate);
const float feedrate_inc = final_feedrate / 10, // Start at 1/10 of max & go up by 1/10 per step
fr_limit = final_feedrate * 0.99f; // Rounding-safe comparison value
float current_feedrate = 0;
planner.synchronize(); // Wait for moves to complete
for (j = 0; j < driver_count; j++)
L64xxManager.get_status(axis_index[j]); // Clear error flags
char temp_axis_string[2] = " ";
temp_axis_string[0] = axis_mon[0][0]; // Need a sprintf format string
//temp_axis_string[1] = '\n';
char gcode_string[80];
uint16_t status_composite = 0;
DEBUG_ECHOLNPGM(".\n.\n."); // Make feedrate outputs easier to read
do {
current_feedrate += feedrate_inc;
DEBUG_ECHOLNPGM("...feedrate = ", current_feedrate);
sprintf_P(gcode_string, PSTR("G0 %s%03d F%03d"), temp_axis_string, uint16_t(position_min), uint16_t(current_feedrate));
process_subcommands_now(gcode_string);
sprintf_P(gcode_string, PSTR("G0 %s%03d F%03d"), temp_axis_string, uint16_t(position_max), uint16_t(current_feedrate));
process_subcommands_now(gcode_string);
planner.synchronize();
for (j = 0; j < driver_count; j++) {
axis_status[j] = (~L64xxManager.get_status(axis_index[j])) & 0x0800; // Bits of interest are all active LOW
status_composite |= axis_status[j];
}
if (status_composite) break; // Break on any error
} while (current_feedrate < fr_limit);
DEBUG_ECHOPGM("Completed with ");
if (status_composite) {
DEBUG_ECHOLNPGM("errors");
#if ENABLED(L6470_CHITCHAT)
for (j = 0; j < driver_count; j++) {
if (j) DEBUG_ECHOPGM("...");
L64xxManager.error_status_decode(axis_status[j], axis_index[j],
sh.STATUS_AXIS_TH_SD, sh.STATUS_AXIS_TH_WRN,
sh.STATUS_AXIS_STEP_LOSS_A, sh.STATUS_AXIS_STEP_LOSS_B,
sh.STATUS_AXIS_OCD, sh.STATUS_AXIS_LAYOUT);
}
#endif
}
else
DEBUG_ECHOLNPGM("no errors");
L64xxManager.pause_monitor(false);
}
#endif // HAS_L64XX

View File

@@ -26,7 +26,6 @@
#include "../../gcode.h" #include "../../gcode.h"
#include "../../../module/planner.h" #include "../../../module/planner.h"
#include "../../../module/stepper.h"
#if ENABLED(EXTRA_LIN_ADVANCE_K) #if ENABLED(EXTRA_LIN_ADVANCE_K)
float other_extruder_advance_K[EXTRUDERS]; float other_extruder_advance_K[EXTRUDERS];

View File

@@ -31,11 +31,13 @@
* M150: Set Status LED Color - Use R-U-B-W for R-G-B-W * M150: Set Status LED Color - Use R-U-B-W for R-G-B-W
* and Brightness - Use P (for NEOPIXEL only) * and Brightness - Use P (for NEOPIXEL only)
* *
* Always sets all 3 or 4 components. If a component is left out, set to 0. * Always sets all 3 or 4 components unless the K flag is specified.
* If brightness is left out, no value changed * If a component is left out, set to 0.
* If brightness is left out, no value changed.
* *
* With NEOPIXEL_LED: * With NEOPIXEL_LED:
* I<index> Set the NeoPixel index to affect. Default: All * I<index> Set the NeoPixel index to affect. Default: All
* K Keep all unspecified values unchanged instead of setting to 0.
* *
* With NEOPIXEL2_SEPARATE: * With NEOPIXEL2_SEPARATE:
* S<index> The NeoPixel strip to set. Default: All. * S<index> The NeoPixel strip to set. Default: All.
@@ -51,16 +53,19 @@
* M150 P ; Set LED full brightness * M150 P ; Set LED full brightness
* M150 I1 R ; Set NEOPIXEL index 1 to red * M150 I1 R ; Set NEOPIXEL index 1 to red
* M150 S1 I1 R ; Set SEPARATE index 1 to red * M150 S1 I1 R ; Set SEPARATE index 1 to red
* M150 K R127 ; Set LED red to 50% without changing blue or green
*/ */
void GcodeSuite::M150() { void GcodeSuite::M150() {
int32_t old_color = 0;
#if ENABLED(NEOPIXEL_LED) #if ENABLED(NEOPIXEL_LED)
const pixel_index_t index = parser.intval('I', -1); const pixel_index_t index = parser.intval('I', -1);
#if ENABLED(NEOPIXEL2_SEPARATE) #if ENABLED(NEOPIXEL2_SEPARATE)
int8_t brightness = neo.brightness(), unit = parser.intval('S', -1); int8_t brightness = neo.brightness(), unit = parser.intval('S', -1);
switch (unit) { switch (unit) {
case -1: neo2.neoindex = index; // fall-thru case -1: neo2.neoindex = index; // fall-thru
case 0: neo.neoindex = index; break; case 0: neo.neoindex = index; old_color = parser.seen('K') ? neo.pixel_color(index >= 0 ? index : 0) : 0; break;
case 1: neo2.neoindex = index; brightness = neo2.brightness(); break; case 1: neo2.neoindex = index; brightness = neo2.brightness(); old_color = parser.seen('K') ? neo2.pixel_color(index >= 0 ? index : 0) : 0; break;
} }
#else #else
const uint8_t brightness = neo.brightness(); const uint8_t brightness = neo.brightness();
@@ -69,10 +74,10 @@ void GcodeSuite::M150() {
#endif #endif
const LEDColor color = LEDColor( const LEDColor color = LEDColor(
parser.seen('R') ? (parser.has_value() ? parser.value_byte() : 255) : 0, parser.seen('R') ? (parser.has_value() ? parser.value_byte() : 255) : (old_color >> 16) & 0xFF,
parser.seen('U') ? (parser.has_value() ? parser.value_byte() : 255) : 0, parser.seen('U') ? (parser.has_value() ? parser.value_byte() : 255) : (old_color >> 8) & 0xFF,
parser.seen('B') ? (parser.has_value() ? parser.value_byte() : 255) : 0 parser.seen('B') ? (parser.has_value() ? parser.value_byte() : 255) : old_color & 0xFF
OPTARG(HAS_WHITE_LED, parser.seen('W') ? (parser.has_value() ? parser.value_byte() : 255) : 0) OPTARG(HAS_WHITE_LED, parser.seen('W') ? (parser.has_value() ? parser.value_byte() : 255) : (old_color >> 24) & 0xFF)
OPTARG(NEOPIXEL_LED, parser.seen('P') ? (parser.has_value() ? parser.value_byte() : 255) : brightness) OPTARG(NEOPIXEL_LED, parser.seen('P') ? (parser.has_value() ? parser.value_byte() : 255) : brightness)
); );

View File

@@ -71,12 +71,12 @@ void GcodeSuite::M125() {
if (parser.seenval('X')) park_point.x = RAW_X_POSITION(parser.linearval('X')), if (parser.seenval('X')) park_point.x = RAW_X_POSITION(parser.linearval('X')),
if (parser.seenval('Y')) park_point.y = RAW_Y_POSITION(parser.linearval('Y')), if (parser.seenval('Y')) park_point.y = RAW_Y_POSITION(parser.linearval('Y')),
NOOP, NOOP,
if (parser.seenval(AXIS4_NAME)) park_point.i = RAW_X_POSITION(parser.linearval(AXIS4_NAME)), if (parser.seenval(AXIS4_NAME)) park_point.i = RAW_I_POSITION(parser.linearval(AXIS4_NAME)),
if (parser.seenval(AXIS5_NAME)) park_point.j = RAW_X_POSITION(parser.linearval(AXIS5_NAME)), if (parser.seenval(AXIS5_NAME)) park_point.j = RAW_J_POSITION(parser.linearval(AXIS5_NAME)),
if (parser.seenval(AXIS6_NAME)) park_point.k = RAW_X_POSITION(parser.linearval(AXIS6_NAME)), if (parser.seenval(AXIS6_NAME)) park_point.k = RAW_K_POSITION(parser.linearval(AXIS6_NAME)),
if (parser.seenval(AXIS7_NAME)) park_point.u = RAW_X_POSITION(parser.linearval(AXIS7_NAME)), if (parser.seenval(AXIS7_NAME)) park_point.u = RAW_U_POSITION(parser.linearval(AXIS7_NAME)),
if (parser.seenval(AXIS8_NAME)) park_point.v = RAW_X_POSITION(parser.linearval(AXIS8_NAME)), if (parser.seenval(AXIS8_NAME)) park_point.v = RAW_V_POSITION(parser.linearval(AXIS8_NAME)),
if (parser.seenval(AXIS9_NAME)) park_point.w = RAW_X_POSITION(parser.linearval(AXIS9_NAME)) if (parser.seenval(AXIS9_NAME)) park_point.w = RAW_W_POSITION(parser.linearval(AXIS9_NAME))
); );
// Lift Z axis // Lift Z axis

View File

@@ -26,7 +26,7 @@
#include "../../gcode.h" #include "../../gcode.h"
#include "../../../feature/tmc_util.h" #include "../../../feature/tmc_util.h"
#include "../../../module/stepper/indirection.h" #include "../../../module/stepper/indirection.h" // for restore_stepper_drivers
/** /**
* M122: Debug TMC drivers * M122: Debug TMC drivers

View File

@@ -169,6 +169,15 @@ void GcodeSuite::M919() {
#if AXIS_IS_TMC(K) #if AXIS_IS_TMC(K)
case K_AXIS: TMC_SET_CHOPPER_TIME(K); break; case K_AXIS: TMC_SET_CHOPPER_TIME(K); break;
#endif #endif
#if AXIS_IS_TMC(U)
case U_AXIS: TMC_SET_CHOPPER_TIME(U); break;
#endif
#if AXIS_IS_TMC(V)
case V_AXIS: TMC_SET_CHOPPER_TIME(V); break;
#endif
#if AXIS_IS_TMC(W)
case W_AXIS: TMC_SET_CHOPPER_TIME(W); break;
#endif
#if HAS_E_CHOPPER #if HAS_E_CHOPPER
case E_AXIS: { case E_AXIS: {
@@ -236,6 +245,15 @@ void GcodeSuite::M919() {
#if AXIS_IS_TMC(K) #if AXIS_IS_TMC(K)
TMC_SAY_CHOPPER_TIME(K); TMC_SAY_CHOPPER_TIME(K);
#endif #endif
#if AXIS_IS_TMC(U)
TMC_SAY_CHOPPER_TIME(U);
#endif
#if AXIS_IS_TMC(V)
TMC_SAY_CHOPPER_TIME(V);
#endif
#if AXIS_IS_TMC(W)
TMC_SAY_CHOPPER_TIME(W);
#endif
#if AXIS_IS_TMC(E0) #if AXIS_IS_TMC(E0)
TMC_SAY_CHOPPER_TIME(E0); TMC_SAY_CHOPPER_TIME(E0);
#endif #endif

View File

@@ -53,7 +53,7 @@ GcodeSuite gcode;
#include "../feature/cancel_object.h" #include "../feature/cancel_object.h"
#endif #endif
#if ENABLED(LASER_MOVE_POWER) #if ENABLED(LASER_FEATURE)
#include "../feature/spindle_laser.h" #include "../feature/spindle_laser.h"
#endif #endif
@@ -210,8 +210,11 @@ void GcodeSuite::get_destination_from_command() {
recovery.save(); recovery.save();
#endif #endif
if (parser.floatval('F') > 0) if (parser.floatval('F') > 0) {
feedrate_mm_s = parser.value_feedrate(); feedrate_mm_s = parser.value_feedrate();
// Update the cutter feed rate for use by M4 I set inline moves.
TERN_(LASER_FEATURE, cutter.feedrate_mm_m = MMS_TO_MMM(feedrate_mm_s));
}
#if BOTH(PRINTCOUNTER, HAS_EXTRUDERS) #if BOTH(PRINTCOUNTER, HAS_EXTRUDERS)
if (!DEBUGGING(DRYRUN) && !skip_move) if (!DEBUGGING(DRYRUN) && !skip_move)
@@ -223,15 +226,29 @@ void GcodeSuite::get_destination_from_command() {
M165(); M165();
#endif #endif
#if ENABLED(LASER_MOVE_POWER) #if ENABLED(LASER_FEATURE)
// Set the laser power in the planner to configure this move if (cutter.cutter_mode == CUTTER_MODE_CONTINUOUS || cutter.cutter_mode == CUTTER_MODE_DYNAMIC) {
if (parser.seen('S')) { // Set the cutter power in the planner to configure this move
const float spwr = parser.value_float(); cutter.last_feedrate_mm_m = 0;
cutter.inline_power(TERN(SPINDLE_LASER_USE_PWM, cutter.power_to_range(cutter_power_t(round(spwr))), spwr > 0 ? 255 : 0)); if (WITHIN(parser.codenum, 1, TERN(ARC_SUPPORT, 3, 1)) || TERN0(BEZIER_CURVE_SUPPORT, parser.codenum == 5)) {
planner.laser_inline.status.isPowered = true;
if (parser.seen('I')) cutter.set_enabled(true); // This is set for backward LightBurn compatibility.
if (parser.seenval('S')) {
const float v = parser.value_float(),
u = TERN(LASER_POWER_TRAP, v, cutter.power_to_range(v));
cutter.menuPower = cutter.unitPower = u;
cutter.inline_power(TERN(SPINDLE_LASER_USE_PWM, cutter.upower_to_ocr(u), u > 0 ? 255 : 0));
}
}
else if (parser.codenum == 0) {
// For dynamic mode we need to flag isPowered off, dynamic power is calculated in the stepper based on feedrate.
if (cutter.cutter_mode == CUTTER_MODE_DYNAMIC) planner.laser_inline.status.isPowered = false;
cutter.inline_power(0); // This is planner-based so only set power and do not disable inline control flags.
}
} }
else if (ENABLED(LASER_MOVE_G0_OFF) && parser.codenum == 0) // G0 else if (parser.codenum == 0)
cutter.set_inline_enabled(false); cutter.apply_power(0);
#endif #endif // LASER_FEATURE
} }
/** /**
@@ -560,6 +577,10 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
case 100: M100(); break; // M100: Free Memory Report case 100: M100(); break; // M100: Free Memory Report
#endif #endif
#if ENABLED(BD_SENSOR)
case 102: M102(); break; // M102: Configure Bed Distance Sensor
#endif
#if HAS_EXTRUDERS #if HAS_EXTRUDERS
case 104: M104(); break; // M104: Set hot end temperature case 104: M104(); break; // M104: Set hot end temperature
case 109: M109(); break; // M109: Wait for hotend temperature to reach target case 109: M109(); break; // M109: Wait for hotend temperature to reach target
@@ -748,7 +769,7 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
case 290: M290(); break; // M290: Babystepping case 290: M290(); break; // M290: Babystepping
#endif #endif
#if HAS_BUZZER #if HAS_SOUND
case 300: M300(); break; // M300: Play beep tone case 300: M300(); break; // M300: Play beep tone
#endif #endif
@@ -848,6 +869,10 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
case 421: M421(); break; // M421: Set a Mesh Bed Leveling Z coordinate case 421: M421(); break; // M421: Set a Mesh Bed Leveling Z coordinate
#endif #endif
#if ENABLED(X_AXIS_TWIST_COMPENSATION)
case 423: M423(); break; // M423: Reset, modify, or report X-Twist Compensation data
#endif
#if ENABLED(BACKLASH_GCODE) #if ENABLED(BACKLASH_GCODE)
case 425: M425(); break; // M425: Tune backlash compensation case 425: M425(); break; // M425: Tune backlash compensation
#endif #endif
@@ -912,7 +937,7 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
#endif #endif
#if IS_KINEMATIC #if IS_KINEMATIC
case 665: M665(); break; // M665: Set Delta/SCARA parameters case 665: M665(); break; // M665: Set Kinematics parameters
#endif #endif
#if ENABLED(DELTA) || HAS_EXTRA_ENDSTOPS #if ENABLED(DELTA) || HAS_EXTRA_ENDSTOPS
@@ -984,14 +1009,6 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
case 919: M919(); break; // M919: Set stepper Chopper Times case 919: M919(); break; // M919: Set stepper Chopper Times
#endif #endif
#if HAS_L64XX
case 122: M122(); break; // M122: Report status
case 906: M906(); break; // M906: Set or get motor drive level
case 916: M916(); break; // M916: L6470 tuning: Increase drive level until thermal warning
case 917: M917(); break; // M917: L6470 tuning: Find minimum current thresholds
case 918: M918(); break; // M918: L6470 tuning: Increase speed until max or error
#endif
#if HAS_MICROSTEPS #if HAS_MICROSTEPS
case 350: M350(); break; // M350: Set microstepping mode. Warning: Steps per unit remains unchanged. S code sets stepping mode for all drivers. case 350: M350(); break; // M350: Set microstepping mode. Warning: Steps per unit remains unchanged. S code sets stepping mode for all drivers.
case 351: M351(); break; // M351: Toggle MS1 MS2 pins directly, S# determines MS1 or MS2, X# sets the pin high/low. case 351: M351(); break; // M351: Toggle MS1 MS2 pins directly, S# determines MS1 or MS2, X# sets the pin high/low.

View File

@@ -132,6 +132,8 @@
* *
* M100 - Watch Free Memory (for debugging) (Requires M100_FREE_MEMORY_WATCHER) * M100 - Watch Free Memory (for debugging) (Requires M100_FREE_MEMORY_WATCHER)
* *
* M102 - Configure Bed Distance Sensor. (Requires BD_SENSOR)
*
* M104 - Set extruder target temp. * M104 - Set extruder target temp.
* M105 - Report current temperatures. * M105 - Report current temperatures.
* M106 - Set print fan speed. * M106 - Set print fan speed.
@@ -155,7 +157,7 @@
* M120 - Enable endstops detection. * M120 - Enable endstops detection.
* M121 - Disable endstops detection. * M121 - Disable endstops detection.
* *
* M122 - Debug stepper (Requires at least one _DRIVER_TYPE defined as TMC2130/2160/5130/5160/2208/2209/2660 or L6470) * M122 - Debug stepper (Requires at least one _DRIVER_TYPE defined as TMC2130/2160/5130/5160/2208/2209/2660)
* M123 - Report fan tachometers. (Requires En_FAN_TACHO_PIN) Optionally set auto-report interval. (Requires AUTO_REPORT_FANS) * M123 - Report fan tachometers. (Requires En_FAN_TACHO_PIN) Optionally set auto-report interval. (Requires AUTO_REPORT_FANS)
* M125 - Save current position and move to filament change position. (Requires PARK_HEAD_ON_PAUSE) * M125 - Save current position and move to filament change position. (Requires PARK_HEAD_ON_PAUSE)
* *
@@ -262,6 +264,7 @@
* M605 - Set Dual X-Carriage movement mode: "M605 S<mode> [X<x_offset>] [R<temp_offset>]". (Requires DUAL_X_CARRIAGE) * M605 - Set Dual X-Carriage movement mode: "M605 S<mode> [X<x_offset>] [R<temp_offset>]". (Requires DUAL_X_CARRIAGE)
* M665 - Set delta configurations: "M665 H<delta height> L<diagonal rod> R<delta radius> S<segments/s> B<calibration radius> X<Alpha angle trim> Y<Beta angle trim> Z<Gamma angle trim> (Requires DELTA) * M665 - Set delta configurations: "M665 H<delta height> L<diagonal rod> R<delta radius> S<segments/s> B<calibration radius> X<Alpha angle trim> Y<Beta angle trim> Z<Gamma angle trim> (Requires DELTA)
* Set SCARA configurations: "M665 S<segments-per-second> P<theta-psi-offset> T<theta-offset> Z<z-offset> (Requires MORGAN_SCARA or MP_SCARA) * Set SCARA configurations: "M665 S<segments-per-second> P<theta-psi-offset> T<theta-offset> Z<z-offset> (Requires MORGAN_SCARA or MP_SCARA)
* Set Polargraph draw area and belt length: "M665 S<segments-per-second> L<draw-area-left> R<draw-area-right> T<draw-area-top> B<draw-area-bottom> H<max-belt-length>"
* M666 - Set/get offsets for delta (Requires DELTA) or dual endstops. (Requires [XYZ]_DUAL_ENDSTOPS) * M666 - Set/get offsets for delta (Requires DELTA) or dual endstops. (Requires [XYZ]_DUAL_ENDSTOPS)
* M672 - Set/Reset Duet Smart Effector's sensitivity. (Requires DUET_SMART_EFFECTOR and SMART_EFFECTOR_MOD_PIN) * M672 - Set/Reset Duet Smart Effector's sensitivity. (Requires DUET_SMART_EFFECTOR and SMART_EFFECTOR_MOD_PIN)
* M701 - Load filament (Requires FILAMENT_LOAD_UNLOAD_GCODES) * M701 - Load filament (Requires FILAMENT_LOAD_UNLOAD_GCODES)
@@ -286,7 +289,7 @@
* M871 - Print/reset/clear first layer temperature offset values. (Requires PTC_PROBE, PTC_BED, or PTC_HOTEND) * M871 - Print/reset/clear first layer temperature offset values. (Requires PTC_PROBE, PTC_BED, or PTC_HOTEND)
* M876 - Handle Prompt Response. (Requires HOST_PROMPT_SUPPORT and not EMERGENCY_PARSER) * M876 - Handle Prompt Response. (Requires HOST_PROMPT_SUPPORT and not EMERGENCY_PARSER)
* M900 - Get or Set Linear Advance K-factor. (Requires LIN_ADVANCE) * M900 - Get or Set Linear Advance K-factor. (Requires LIN_ADVANCE)
* M906 - Set or get motor current in milliamps using axis codes XYZE, etc. Report values if no axis codes given. (Requires at least one _DRIVER_TYPE defined as TMC2130/2160/5130/5160/2208/2209/2660 or L6470) * M906 - Set or get motor current in milliamps using axis codes XYZE, etc. Report values if no axis codes given. (Requires at least one _DRIVER_TYPE defined as TMC2130/2160/5130/5160/2208/2209/2660)
* M907 - Set digital trimpot motor current using axis codes. (Requires a board with digital trimpots) * M907 - Set digital trimpot motor current using axis codes. (Requires a board with digital trimpots)
* M908 - Control digital trimpot directly. (Requires HAS_MOTOR_CURRENT_DAC or DIGIPOTSS_PIN) * M908 - Control digital trimpot directly. (Requires HAS_MOTOR_CURRENT_DAC or DIGIPOTSS_PIN)
* M909 - Print digipot/DAC current value. (Requires HAS_MOTOR_CURRENT_DAC) * M909 - Print digipot/DAC current value. (Requires HAS_MOTOR_CURRENT_DAC)
@@ -295,9 +298,6 @@
* M912 - Clear stepper driver overtemperature pre-warn condition flag. (Requires at least one _DRIVER_TYPE defined as TMC2130/2160/5130/5160/2208/2209/2660) * M912 - Clear stepper driver overtemperature pre-warn condition flag. (Requires at least one _DRIVER_TYPE defined as TMC2130/2160/5130/5160/2208/2209/2660)
* M913 - Set HYBRID_THRESHOLD speed. (Requires HYBRID_THRESHOLD) * M913 - Set HYBRID_THRESHOLD speed. (Requires HYBRID_THRESHOLD)
* M914 - Set StallGuard sensitivity. (Requires SENSORLESS_HOMING or SENSORLESS_PROBING) * M914 - Set StallGuard sensitivity. (Requires SENSORLESS_HOMING or SENSORLESS_PROBING)
* M916 - L6470 tuning: Increase KVAL_HOLD until thermal warning. (Requires at least one _DRIVER_TYPE L6470)
* M917 - L6470 tuning: Find minimum current thresholds. (Requires at least one _DRIVER_TYPE L6470)
* M918 - L6470 tuning: Increase speed until max or error. (Requires at least one _DRIVER_TYPE L6470)
* M919 - Get or Set motor Chopper Times (time_off, hysteresis_end, hysteresis_start) using axis codes XYZE, etc. If no parameters are given, report. (Requires at least one _DRIVER_TYPE defined as TMC2130/2160/5130/5160/2208/2209/2660) * M919 - Get or Set motor Chopper Times (time_off, hysteresis_end, hysteresis_start) using axis codes XYZE, etc. If no parameters are given, report. (Requires at least one _DRIVER_TYPE defined as TMC2130/2160/5130/5160/2208/2209/2660)
* M951 - Set Magnetic Parking Extruder parameters. (Requires MAGNETIC_PARKING_EXTRUDER) * M951 - Set Magnetic Parking Extruder parameters. (Requires MAGNETIC_PARKING_EXTRUDER)
* M3426 - Read MCP3426 ADC over I2C. (Requires HAS_MCP3426_ADC) * M3426 - Read MCP3426 ADC over I2C. (Requires HAS_MCP3426_ADC)
@@ -707,6 +707,11 @@ private:
static void M100(); static void M100();
#endif #endif
#if ENABLED(BD_SENSOR)
static void M102();
static void M102_report(const bool forReplay=true);
#endif
#if HAS_EXTRUDERS #if HAS_EXTRUDERS
static void M104_M109(const bool isM109); static void M104_M109(const bool isM109);
FORCE_INLINE static void M104() { M104_M109(false); } FORCE_INLINE static void M104() { M104_M109(false); }
@@ -886,7 +891,7 @@ private:
static void M250_report(const bool forReplay=true); static void M250_report(const bool forReplay=true);
#endif #endif
#if HAS_DISPLAY_SLEEP #if HAS_GCODE_M255
static void M255(); static void M255();
static void M255_report(const bool forReplay=true); static void M255_report(const bool forReplay=true);
#endif #endif
@@ -916,7 +921,7 @@ private:
static void M290(); static void M290();
#endif #endif
#if HAS_BUZZER #if HAS_SOUND
static void M300(); static void M300();
#endif #endif
@@ -1163,14 +1168,6 @@ private:
static void M919(); static void M919();
#endif #endif
#if HAS_L64XX
static void M122();
static void M906();
static void M916();
static void M917();
static void M918();
#endif
#if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM || HAS_MOTOR_CURRENT_I2C || HAS_MOTOR_CURRENT_DAC #if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM || HAS_MOTOR_CURRENT_I2C || HAS_MOTOR_CURRENT_DAC
static void M907(); static void M907();
#if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM #if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM

View File

@@ -25,8 +25,6 @@
#if ENABLED(CNC_COORDINATE_SYSTEMS) #if ENABLED(CNC_COORDINATE_SYSTEMS)
#include "../../module/stepper.h"
//#define DEBUG_M53 //#define DEBUG_M53
/** /**

View File

@@ -22,7 +22,6 @@
#include "../gcode.h" #include "../gcode.h"
#include "../../module/motion.h" #include "../../module/motion.h"
#include "../../module/stepper.h"
#if ENABLED(I2C_POSITION_ENCODERS) #if ENABLED(I2C_POSITION_ENCODERS)
#include "../../feature/encoder_i2c.h" #include "../../feature/encoder_i2c.h"

View File

@@ -28,12 +28,6 @@
#if ENABLED(M114_DETAIL) #if ENABLED(M114_DETAIL)
#if HAS_L64XX
#include "../../libs/L64XX/L64XX_Marlin.h"
#define DEBUG_OUT ENABLED(L6470_CHITCHAT)
#include "../../core/debug_out.h"
#endif
void report_all_axis_pos(const xyze_pos_t &pos, const uint8_t n=LOGICAL_AXES, const uint8_t precision=3) { void report_all_axis_pos(const xyze_pos_t &pos, const uint8_t n=LOGICAL_AXES, const uint8_t precision=3) {
char str[12]; char str[12];
LOOP_L_N(a, n) { LOOP_L_N(a, n) {
@@ -84,89 +78,6 @@
planner.synchronize(); planner.synchronize();
#if HAS_L64XX
char temp_buf[80];
int32_t temp;
//#define ABS_POS_SIGN_MASK 0b1111 1111 1110 0000 0000 0000 0000 0000
#define ABS_POS_SIGN_MASK 0b11111111111000000000000000000000
#define REPORT_ABSOLUTE_POS(Q) do{ \
L64xxManager.say_axis(Q, false); \
temp = L6470_GETPARAM(L6470_ABS_POS,Q); \
if (temp & ABS_POS_SIGN_MASK) temp |= ABS_POS_SIGN_MASK; \
sprintf_P(temp_buf, PSTR(":%8ld "), temp); \
DEBUG_ECHO(temp_buf); \
}while(0)
DEBUG_ECHOPGM("\nL6470:");
#if AXIS_IS_L64XX(X)
REPORT_ABSOLUTE_POS(X);
#endif
#if AXIS_IS_L64XX(X2)
REPORT_ABSOLUTE_POS(X2);
#endif
#if AXIS_IS_L64XX(Y)
REPORT_ABSOLUTE_POS(Y);
#endif
#if AXIS_IS_L64XX(Y2)
REPORT_ABSOLUTE_POS(Y2);
#endif
#if AXIS_IS_L64XX(Z)
REPORT_ABSOLUTE_POS(Z);
#endif
#if AXIS_IS_L64XX(Z2)
REPORT_ABSOLUTE_POS(Z2);
#endif
#if AXIS_IS_L64XX(Z3)
REPORT_ABSOLUTE_POS(Z3);
#endif
#if AXIS_IS_L64XX(Z4)
REPORT_ABSOLUTE_POS(Z4);
#endif
#if AXIS_IS_L64XX(I)
REPORT_ABSOLUTE_POS(I);
#endif
#if AXIS_IS_L64XX(J)
REPORT_ABSOLUTE_POS(J);
#endif
#if AXIS_IS_L64XX(K)
REPORT_ABSOLUTE_POS(K);
#endif
#if AXIS_IS_L64XX(U)
REPORT_ABSOLUTE_POS(U);
#endif
#if AXIS_IS_L64XX(V)
REPORT_ABSOLUTE_POS(V);
#endif
#if AXIS_IS_L64XX(W)
REPORT_ABSOLUTE_POS(W);
#endif
#if AXIS_IS_L64XX(E0)
REPORT_ABSOLUTE_POS(E0);
#endif
#if AXIS_IS_L64XX(E1)
REPORT_ABSOLUTE_POS(E1);
#endif
#if AXIS_IS_L64XX(E2)
REPORT_ABSOLUTE_POS(E2);
#endif
#if AXIS_IS_L64XX(E3)
REPORT_ABSOLUTE_POS(E3);
#endif
#if AXIS_IS_L64XX(E4)
REPORT_ABSOLUTE_POS(E4);
#endif
#if AXIS_IS_L64XX(E5)
REPORT_ABSOLUTE_POS(E5);
#endif
#if AXIS_IS_L64XX(E6)
REPORT_ABSOLUTE_POS(E6);
#endif
#if AXIS_IS_L64XX(E7)
REPORT_ABSOLUTE_POS(E7);
#endif
SERIAL_EOL();
#endif // HAS_L64XX
SERIAL_ECHOPGM("Stepper:"); SERIAL_ECHOPGM("Stepper:");
LOOP_LOGICAL_AXES(i) { LOOP_LOGICAL_AXES(i) {
SERIAL_ECHOPGM_P((PGM_P)pgm_read_ptr(&SP_AXIS_LBL[i]), stepper.position((AxisEnum)i)); SERIAL_ECHOPGM_P((PGM_P)pgm_read_ptr(&SP_AXIS_LBL[i]), stepper.position((AxisEnum)i));

View File

@@ -36,7 +36,7 @@ void GcodeSuite::M255() {
const int m = parser.value_int(); const int m = parser.value_int();
ui.sleep_timeout_minutes = constrain(m, SLEEP_TIMEOUT_MIN, SLEEP_TIMEOUT_MAX); ui.sleep_timeout_minutes = constrain(m, SLEEP_TIMEOUT_MIN, SLEEP_TIMEOUT_MAX);
#else #else
const int s = parser.value_int() * 60; const unsigned int s = parser.value_ushort() * 60;
ui.lcd_backlight_timeout = constrain(s, LCD_BKL_TIMEOUT_MIN, LCD_BKL_TIMEOUT_MAX); ui.lcd_backlight_timeout = constrain(s, LCD_BKL_TIMEOUT_MIN, LCD_BKL_TIMEOUT_MAX);
#endif #endif
} }

View File

@@ -22,7 +22,7 @@
#include "../../inc/MarlinConfig.h" #include "../../inc/MarlinConfig.h"
#if HAS_BUZZER #if HAS_SOUND
#include "../gcode.h" #include "../gcode.h"
@@ -42,4 +42,4 @@ void GcodeSuite::M300() {
BUZZ(duration, frequency); BUZZ(duration, frequency);
} }
#endif // HAS_BUZZER #endif // HAS_SOUND

View File

@@ -32,7 +32,7 @@
#include "../../sd/cardreader.h" #include "../../sd/cardreader.h"
#if ENABLED(NANODLP_Z_SYNC) #if ENABLED(NANODLP_Z_SYNC)
#include "../../module/stepper.h" #include "../../module/planner.h"
#endif #endif
extern xyze_pos_t destination; extern xyze_pos_t destination;

View File

@@ -197,8 +197,8 @@ void plan_arc(
// Feedrate for the move, scaled by the feedrate multiplier // Feedrate for the move, scaled by the feedrate multiplier
const feedRate_t scaled_fr_mm_s = MMS_SCALED(feedrate_mm_s); const feedRate_t scaled_fr_mm_s = MMS_SCALED(feedrate_mm_s);
// Get the nominal segment length based on settings // Get the ideal segment length for the move based on settings
const float nominal_segment_mm = ( const float ideal_segment_mm = (
#if ARC_SEGMENTS_PER_SEC // Length based on segments per second and feedrate #if ARC_SEGMENTS_PER_SEC // Length based on segments per second and feedrate
constrain(scaled_fr_mm_s * RECIPROCAL(ARC_SEGMENTS_PER_SEC), MIN_ARC_SEGMENT_MM, MAX_ARC_SEGMENT_MM) constrain(scaled_fr_mm_s * RECIPROCAL(ARC_SEGMENTS_PER_SEC), MIN_ARC_SEGMENT_MM, MAX_ARC_SEGMENT_MM)
#else #else
@@ -206,19 +206,21 @@ void plan_arc(
#endif #endif
); );
// Number of whole segments based on the nominal segment length // Number of whole segments based on the ideal segment length
const float nominal_segments = _MAX(FLOOR(flat_mm / nominal_segment_mm), min_segments); const float nominal_segments = _MAX(FLOOR(flat_mm / ideal_segment_mm), min_segments),
nominal_segment_mm = flat_mm / nominal_segments;
// A new segment length based on the required minimum // The number of whole segments in the arc, with best attempt to honor MIN_ARC_SEGMENT_MM and MAX_ARC_SEGMENT_MM
const float segment_mm = constrain(flat_mm / nominal_segments, MIN_ARC_SEGMENT_MM, MAX_ARC_SEGMENT_MM); const uint16_t segments = nominal_segment_mm > (MAX_ARC_SEGMENT_MM) ? CEIL(flat_mm / (MAX_ARC_SEGMENT_MM)) :
nominal_segment_mm < (MIN_ARC_SEGMENT_MM) ? _MAX(1, FLOOR(flat_mm / (MIN_ARC_SEGMENT_MM))) :
nominal_segments;
const float segment_mm = flat_mm / segments;
// The number of whole segments in the arc, ignoring the remainder // Add hints to help optimize the move
uint16_t segments = FLOOR(flat_mm / segment_mm); PlannerHints hints;
#if ENABLED(SCARA_FEEDRATE_SCALING)
// Are the segments now too few to reach the destination? hints.inv_duration = (scaled_fr_mm_s / flat_mm) * segments;
const float segmented_length = segment_mm * segments; #endif
const bool tooshort = segmented_length < flat_mm - 0.0001f;
const float proportion = tooshort ? segmented_length / flat_mm : 1.0f;
/** /**
* Vector rotation by transformation matrix: r is the original vector, r_T is the rotated vector, * Vector rotation by transformation matrix: r is the original vector, r_T is the rotated vector,
@@ -246,108 +248,123 @@ void plan_arc(
* a correction, the planner should have caught up to the lag caused by the initial plan_arc overhead. * a correction, the planner should have caught up to the lag caused by the initial plan_arc overhead.
* This is important when there are successive arc motions. * This is important when there are successive arc motions.
*/ */
// Vector rotation matrix values
xyze_pos_t raw; xyze_pos_t raw;
const float theta_per_segment = proportion * angular_travel / segments,
sq_theta_per_segment = sq(theta_per_segment),
sin_T = theta_per_segment - sq_theta_per_segment * theta_per_segment / 6,
cos_T = 1 - 0.5f * sq_theta_per_segment; // Small angle approximation
#if DISABLED(AUTO_BED_LEVELING_UBL) // do not calculate rotation parameters for trivial single-segment arcs
ARC_LIJKUVW_CODE( if (segments > 1) {
const float per_segment_L = proportion * travel_L / segments, // Vector rotation matrix values
const float per_segment_I = proportion * travel_I / segments, const float theta_per_segment = angular_travel / segments,
const float per_segment_J = proportion * travel_J / segments, sq_theta_per_segment = sq(theta_per_segment),
const float per_segment_K = proportion * travel_K / segments, sin_T = theta_per_segment - sq_theta_per_segment * theta_per_segment / 6,
const float per_segment_U = proportion * travel_U / segments, cos_T = 1 - 0.5f * sq_theta_per_segment; // Small angle approximation
const float per_segment_V = proportion * travel_V / segments,
const float per_segment_W = proportion * travel_W / segments #if DISABLED(AUTO_BED_LEVELING_UBL)
ARC_LIJKUVW_CODE(
const float per_segment_L = travel_L / segments,
const float per_segment_I = travel_I / segments,
const float per_segment_J = travel_J / segments,
const float per_segment_K = travel_K / segments,
const float per_segment_U = travel_U / segments,
const float per_segment_V = travel_V / segments,
const float per_segment_W = travel_W / segments
);
#endif
CODE_ITEM_E(const float extruder_per_segment = travel_E / segments);
// Initialize all linear axes and E
ARC_LIJKUVWE_CODE(
raw[axis_l] = current_position[axis_l],
raw.i = current_position.i,
raw.j = current_position.j,
raw.k = current_position.k,
raw.u = current_position.u,
raw.v = current_position.v,
raw.w = current_position.w,
raw.e = current_position.e
); );
#endif
CODE_ITEM_E(const float extruder_per_segment = proportion * travel_E / segments); millis_t next_idle_ms = millis() + 200UL;
// For shortened segments, run all but the remainder in the loop
if (tooshort) segments++;
// Initialize all linear axes and E
ARC_LIJKUVWE_CODE(
raw[axis_l] = current_position[axis_l],
raw.i = current_position.i,
raw.j = current_position.j,
raw.k = current_position.k,
raw.u = current_position.u,
raw.v = current_position.v,
raw.w = current_position.w,
raw.e = current_position.e
);
#if ENABLED(SCARA_FEEDRATE_SCALING)
const float inv_duration = scaled_fr_mm_s / segment_mm;
#endif
millis_t next_idle_ms = millis() + 200UL;
#if N_ARC_CORRECTION > 1
int8_t arc_recalc_count = N_ARC_CORRECTION;
#endif
for (uint16_t i = 1; i < segments; i++) { // Iterate (segments-1) times
thermalManager.manage_heater();
const millis_t ms = millis();
if (ELAPSED(ms, next_idle_ms)) {
next_idle_ms = ms + 200UL;
idle();
}
#if N_ARC_CORRECTION > 1 #if N_ARC_CORRECTION > 1
if (--arc_recalc_count) { int8_t arc_recalc_count = N_ARC_CORRECTION;
// Apply vector rotation matrix to previous rvec.a / 1 #endif
const float r_new_Y = rvec.a * sin_T + rvec.b * cos_T;
rvec.a = rvec.a * cos_T - rvec.b * sin_T; // An arc can always complete within limits from a speed which...
rvec.b = r_new_Y; // a) is <= any configured maximum speed,
// b) does not require centripetal force greater than any configured maximum acceleration,
// c) is <= nominal speed,
// d) allows the print head to stop in the remining length of the curve within all configured maximum accelerations.
// The last has to be calculated every time through the loop.
const float limiting_accel = _MIN(planner.settings.max_acceleration_mm_per_s2[axis_p], planner.settings.max_acceleration_mm_per_s2[axis_q]),
limiting_speed = _MIN(planner.settings.max_feedrate_mm_s[axis_p], planner.settings.max_acceleration_mm_per_s2[axis_q]),
limiting_speed_sqr = _MIN(sq(limiting_speed), limiting_accel * radius, sq(scaled_fr_mm_s));
float arc_mm_remaining = flat_mm;
for (uint16_t i = 1; i < segments; i++) { // Iterate (segments-1) times
thermalManager.task();
const millis_t ms = millis();
if (ELAPSED(ms, next_idle_ms)) {
next_idle_ms = ms + 200UL;
idle();
} }
else
#endif
{
#if N_ARC_CORRECTION > 1 #if N_ARC_CORRECTION > 1
arc_recalc_count = N_ARC_CORRECTION; if (--arc_recalc_count) {
// Apply vector rotation matrix to previous rvec.a / 1
const float r_new_Y = rvec.a * sin_T + rvec.b * cos_T;
rvec.a = rvec.a * cos_T - rvec.b * sin_T;
rvec.b = r_new_Y;
}
else
#endif
{
#if N_ARC_CORRECTION > 1
arc_recalc_count = N_ARC_CORRECTION;
#endif
// Arc correction to radius vector. Computed only every N_ARC_CORRECTION increments.
// Compute exact location by applying transformation matrix from initial radius vector(=-offset).
// To reduce stuttering, the sin and cos could be computed at different times.
// For now, compute both at the same time.
const float Ti = i * theta_per_segment, cos_Ti = cos(Ti), sin_Ti = sin(Ti);
rvec.a = -offset[0] * cos_Ti + offset[1] * sin_Ti;
rvec.b = -offset[0] * sin_Ti - offset[1] * cos_Ti;
}
// Update raw location
raw[axis_p] = center_P + rvec.a;
raw[axis_q] = center_Q + rvec.b;
ARC_LIJKUVWE_CODE(
#if ENABLED(AUTO_BED_LEVELING_UBL)
raw[axis_l] = start_L,
raw.i = start_I, raw.j = start_J, raw.k = start_K,
raw.u = start_U, raw.v = start_V, raw.w = start_V
#else
raw[axis_l] += per_segment_L,
raw.i += per_segment_I, raw.j += per_segment_J, raw.k += per_segment_K,
raw.u += per_segment_U, raw.v += per_segment_V, raw.w += per_segment_W
#endif
, raw.e += extruder_per_segment
);
apply_motion_limits(raw);
#if HAS_LEVELING && !PLANNER_LEVELING
planner.apply_leveling(raw);
#endif #endif
// Arc correction to radius vector. Computed only every N_ARC_CORRECTION increments. // calculate safe speed for stopping by the end of the arc
// Compute exact location by applying transformation matrix from initial radius vector(=-offset). arc_mm_remaining -= segment_mm;
// To reduce stuttering, the sin and cos could be computed at different times. hints.safe_exit_speed_sqr = _MIN(limiting_speed_sqr, 2 * limiting_accel * arc_mm_remaining);
// For now, compute both at the same time.
const float cos_Ti = cos(i * theta_per_segment), sin_Ti = sin(i * theta_per_segment); if (!planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, hints))
rvec.a = -offset[0] * cos_Ti + offset[1] * sin_Ti; break;
rvec.b = -offset[0] * sin_Ti - offset[1] * cos_Ti;
hints.curve_radius = radius;
} }
// Update raw location
raw[axis_p] = center_P + rvec.a;
raw[axis_q] = center_Q + rvec.b;
ARC_LIJKUVWE_CODE(
#if ENABLED(AUTO_BED_LEVELING_UBL)
raw[axis_l] = start_L,
raw.i = start_I, raw.j = start_J, raw.k = start_K,
raw.u = start_U, raw.v = start_V, raw.w = start_V
#else
raw[axis_l] += per_segment_L,
raw.i += per_segment_I, raw.j += per_segment_J, raw.k += per_segment_K,
raw.u += per_segment_U, raw.v += per_segment_V, raw.w += per_segment_W
#endif
, raw.e += extruder_per_segment
);
apply_motion_limits(raw);
#if HAS_LEVELING && !PLANNER_LEVELING
planner.apply_leveling(raw);
#endif
if (!planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, 0 OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)))
break;
} }
// Ensure last segment arrives at target location. // Ensure last segment arrives at target location.
@@ -366,7 +383,9 @@ void plan_arc(
planner.apply_leveling(raw); planner.apply_leveling(raw);
#endif #endif
planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, 0 OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)); hints.curve_radius = 0;
hints.safe_exit_speed_sqr = 0.0f;
planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, hints);
#if ENABLED(AUTO_BED_LEVELING_UBL) #if ENABLED(AUTO_BED_LEVELING_UBL)
ARC_LIJKUVW_CODE( ARC_LIJKUVW_CODE(

View File

@@ -21,7 +21,7 @@
*/ */
#include "../gcode.h" #include "../gcode.h"
#include "../../module/stepper.h" #include "../../module/planner.h"
#include "../../lcd/marlinui.h" #include "../../lcd/marlinui.h"
/** /**

View File

@@ -50,7 +50,7 @@ void GcodeSuite::G6() {
// No speed is set, can't schedule the move // No speed is set, can't schedule the move
if (!planner.last_page_step_rate) return; if (!planner.last_page_step_rate) return;
const page_idx_t page_idx = (page_idx_t) parser.value_ulong(); const page_idx_t page_idx = (page_idx_t)parser.value_ulong();
uint16_t num_steps = DirectStepping::Config::TOTAL_STEPS; uint16_t num_steps = DirectStepping::Config::TOTAL_STEPS;
if (parser.seen('S')) num_steps = parser.value_ushort(); if (parser.seen('S')) num_steps = parser.value_ushort();

Some files were not shown because too many files have changed in this diff Show More