Compare commits

...

138 Commits

Author SHA1 Message Date
thinkyhead
70c5bca8c2 [cron] Bump distribution date (2023-04-16) 2023-04-16 06:07:32 +00:00
Scott Lahteine
bb4a01c4f9 🔨 Newer PlatformIO support 2023-04-15 22:27:40 -05:00
Scott Lahteine
06a6708220 🧑‍💻 Update Python indentation 2023-04-15 22:27:40 -05:00
ellensp
e3d1bd6d97 🩹 Add missing FORCE_SOFT_SPI (#24940) 2023-04-15 22:27:40 -05:00
thinkyhead
031bc6adb9 [cron] Bump distribution date (2023-04-08) 2023-04-08 00:18:54 +00:00
ellensp
a6cc7a4f35 🩹 Add missing FORCE_SOFT_SPI (#24940) 2022-11-13 22:42:36 -06:00
Scott Lahteine
4f9fbcee2b 🐛 Fix recalculate_max_e_jerk 2022-11-09 20:55:20 -06:00
Moonglow
d1211b9f90 🩹 Fix M907 "extra axis" limit (#24559) 2022-07-29 19:37:42 -05:00
Scott Lahteine
d5699dd5c0 🚑️ Fix XYZEval = N not setting E 2022-07-29 18:41:23 -05:00
Scott Lahteine
79bd1a68c7 🧑‍💻 Further script updates 2022-07-29 08:33:08 -05:00
Scott Lahteine
0922702504 🧑‍💻 Axis macros parity with 2.1.x 2022-07-29 08:33:08 -05:00
Miguel Risco-Castillo
2bf631c6cc 🚸 Fix, update ProUI (#24251, #24473, #24500) 2022-07-29 08:16:20 -05:00
Scott Lahteine
9a0d0e7ef1 ♻️ Small sound / buzz refactor (#24520) 2022-07-29 07:10:59 -05:00
Keith Bennett
3fab4898e4 👷 CI for bugfix-2.0.x, updates (#24560) 2022-07-29 06:12:38 -05:00
tombrazier
eee8f11849 ️ Optimize Planner calculations (#24484, #24509) 2022-07-29 05:54:17 -05:00
tombrazier
096bea208e ️ Optimize G2-G3 Arcs (#24366) 2022-07-29 05:40:40 -05:00
Scott Lahteine
daa7ee6c6a 🩹 Revert extra axis changes 2022-07-29 05:40:40 -05:00
Scott Lahteine
09cc5473b5 🧑‍💻 Fix and improve build_all_examples 2022-07-29 05:06:58 -05:00
Scott Lahteine
5ccaf1d233 🧑‍💻 Add Sim debug with lldb 2022-07-29 04:56:28 -05:00
ellensp
78789ee11d 📺 SKR_MINI_SCREEN_ADAPTER for BTT SKR Mini E3 V3 (#24521) 2022-07-29 04:52:14 -05:00
Keith Bennett
39f6ae0e3c 📝 Update board MCU comments (#24486) 2022-07-29 04:24:11 -05:00
InsanityAutomation
3441e917bc 🚸 Machine-relative Z_STEPPER_ALIGN_XY (#24261)
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
2022-07-29 04:24:11 -05:00
Scott Lahteine
9ba4c58595 🧑‍💻 Fix MAP macro use
Followup to #24191
2022-07-29 04:24:11 -05:00
ellensp
a720b1a335 🩹 Fix G60/G61 debug code (#24231) 2022-07-29 04:24:11 -05:00
lujios
799b8fccaf 🩹 Fix G33 Delta Sensorless Probing compile (#24291) 2022-07-29 04:24:11 -05:00
Scott Lahteine
69a1c539fb 🩹 Apply linearval in M600 2022-07-29 04:24:11 -05:00
Keith Bennett
6904e31e54 🔧 Assert Probe Temp Comp requirements (#24468) 2022-07-29 04:24:11 -05:00
ellensp
407c32563b 🐛 Fix BACKLASH_COMPENSATION compile (#24072)
Followup to #23826
2022-07-29 04:24:11 -05:00
Scott Lahteine
0281459093 🎨 Misc. 6-axis cleanup 2022-07-29 04:24:11 -05:00
Scott Lahteine
0ef496df2b 📝 Note about UBL bad splits 2022-07-29 04:24:11 -05:00
Pauli Jokela
9c2d0f47fb 🩹 Fix safe homing sanity-check (#24462) 2022-07-29 04:24:11 -05:00
Scott Lahteine
cd9a23c4d0 🎨 Fix comments, formatting 2022-07-29 04:24:11 -05:00
Christophe Huriaux
ab346f24ca 🩹 Fix ST7565 LCD contrast init (#24457) 2022-07-29 04:24:11 -05:00
Mike La Spina
5ee7e3ffa4 🐛 Fix laser/fan sync (#24460)
Followup to #22690, 307dfb15
2022-07-29 04:24:11 -05:00
Scott Lahteine
32765c600a 🩹 Fix TFT image packing 2022-07-29 04:24:11 -05:00
DerAndere
602e14704b 🚸 Better M350, M114 with more axes (#23986)
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
2022-07-29 04:24:11 -05:00
toomuchwonder
0ad83e0af5 🩹 Fix MKS UI extruder speed (#24476) 2022-07-29 04:24:10 -05:00
Miguel Risco-Castillo
9bd39749d7 🚸 Fix and update ProUI (#24477) 2022-07-29 04:24:10 -05:00
InsanityAutomation
ce5497218a 🐛 Fix Archim2 USB Hang (#24314) 2022-07-29 04:24:10 -05:00
Scott Lahteine
ca06ec9abb 🎨 Misc. 'else' cleanup 2022-07-29 04:24:10 -05:00
Scott Lahteine
cf1e4df51b 🩹 Fix MAX31865 approximations
Followup to #24407
2022-07-29 04:24:10 -05:00
Scott Lahteine
38391eb116 🩹 Fix manual move titles (#24518) 2022-07-29 04:24:10 -05:00
Scott Lahteine
03b50354cb 🏗️ Extend AXIS_CHAR to include E
Co-Authored-By: DerAndere <26200979+DerAndere1@users.noreply.github.com>
2022-07-29 04:24:10 -05:00
kisslorand
ceeb6c646b Fix axis string 'N' (#24259)
Followup to 167672d
2022-07-29 02:40:12 -05:00
Ludy
20f79e290f 🌐 Update German language (#24555) 2022-07-27 22:11:49 -05:00
Scott Lahteine
5ecf3f876c 🧑‍💻 Update planner/stepper includes 2022-07-27 22:10:00 -05:00
Scott Lahteine
dee41990cc 🩹 Fix lcd_preheat compile 2022-07-27 22:09:41 -05:00
Scott Lahteine
94a8b70ce3 🔨 Update build/CI scripts 2022-07-27 22:08:38 -05:00
Scott Lahteine
b2101b9928 🎨 PIO scripts cleanup 2022-07-27 22:05:52 -05:00
Keith Bennett
976ac28be5 📺 Fix TFT Classic UI non-Touchscreen 1024x600 (#24541) 2022-07-27 22:04:58 -05:00
Keith Bennett
b0b340aab9 📝 Update MPCTEMP G-Code M306 T (#24535)
M306 simply reports current values. M306 T starts autotune process.
2022-07-27 21:49:09 -05:00
Scott Lahteine
1ceac4a9fe 📝 Update Driver Type comments 2022-07-23 19:43:50 -05:00
Scott Lahteine
a8046d2a95 🎨 Clean up extra axes
Followup to #24120
2022-07-23 19:14:57 -05:00
Scott Lahteine
c6f2be637c EXP header pin numbers redux (#24525)
Followup to 504fec98
2022-07-23 18:53:47 -05:00
tombrazier
30da489f1c 🐛 Fix 2d mesh print (#24536) 2022-07-22 23:34:16 -05:00
Scott Lahteine
a540c58a2d 🔧 Config parity with 2.1.x 2022-07-17 22:25:51 -05:00
Scott Lahteine
e52298db35 🔨 Add mftest --default flag 2022-07-16 23:55:25 -05:00
Arthur Masson
31c350d55e Polargraph M665 settings (#24401) 2022-07-16 23:55:25 -05:00
Scott Lahteine
d50a3129e2 🚸 Renumber EXP pins to match schematics/RRF/Klipper 2022-07-16 23:55:25 -05:00
Scott Lahteine
614f54622a 🔖 Configuration version 02000905 2022-07-16 23:55:25 -05:00
Christophe Huriaux
f89bb65220 eMotion-Tech eMotronic (Micro-Delta rework) (#24488) 2022-07-16 23:30:52 -05:00
Scott Lahteine
284b35d120 🔨 Fix and update Makefile
Followup to 89fe5f6d
2022-07-16 23:30:52 -05:00
Victor Oliveira
fe5e941d92 Creality3D v4.2.5 / CR200B (#24491) 2022-07-16 23:30:52 -05:00
Keith Bennett
80cc5f0413 MKS Monster8 V2 (#24483) 2022-07-16 23:30:52 -05:00
Scott Lahteine
0595a55700 🐛 Fix SDIO for STM32 (#24470)
Followup to #24271
2022-07-16 23:30:52 -05:00
Jason Smith
2535ce2a26 🩹 Fix LCD_BACKLIGHT_TIMEOUT compile (#24463) 2022-07-16 23:30:52 -05:00
Mike La Spina
777af4b6c4 ️ Fix and improve Inline Laser Power (#22690) 2022-07-16 23:30:52 -05:00
Keith Bennett
b1162d97eb BigTreeTech SKR SE BX V3.0 (#24449)
SKR SE BX V3.0 removes the Reverse Driver Protection feature.
2022-07-16 23:30:52 -05:00
tombrazier
e70c350b3d 💥 More M306 M => M306 H (#24258)
Followup to #24253
2022-07-16 23:30:52 -05:00
Keith Bennett
ff516e257b 🎨 Fix/adjust warnings (#24225, #24404) 2022-07-16 23:30:52 -05:00
Scott Lahteine
41269e9c2b 🧑‍💻 Forward-compatible axis strings 2022-07-16 23:30:52 -05:00
DerAndere
091b0f9664 💥 Update Motor Current G-codes for extra axes (#23975) 2022-07-16 23:30:52 -05:00
DerAndere
dc04f61adc 🩹 Fix some parameters w/out values (#24051) 2022-07-16 22:37:40 -05:00
Scott Lahteine
eb25530ba8 🏗️ Axis name arrays
Co-Authored-By: DerAndere <26200979+DerAndere1@users.noreply.github.com>
2022-07-16 22:37:40 -05:00
Scott Lahteine
6133ca2d68 ♻️ More updates for multi-axis 2022-07-16 22:37:40 -05:00
GHGiampy
5a46b900d8 🔨 Fix firmware upload (#24499) 2022-07-16 17:22:10 -05:00
Scott Lahteine
b09997d137 🔨 PlatformIO "--target upload" == "--target exec" 2022-07-16 17:22:10 -05:00
Scott Lahteine
7dc3cfa1a6 ♻️ Encapsulate PID in class (#24389) 2022-07-16 17:22:10 -05:00
Victor Oliveira
93144f1e7d 🔨 Disable stack protector on macOS simulator (#24443) 2022-07-16 17:22:10 -05:00
Eduard Sukharev
5e215fa3c4 🐛 Fix MKS TinyBee compile (#24454) 2022-07-16 17:22:10 -05:00
EvilGremlin
2bdc5a78ad 🔨 Fix OpenBLT encode; no-bootloader envs (#24446) 2022-07-16 17:22:10 -05:00
Scott Lahteine
cd06d5f34f 🔨 Fix Warnings.cpp force-recompile 2022-07-16 17:22:10 -05:00
Scott Lahteine
72f341b4bc 🎨 ANY => EITHER 2022-07-13 21:24:30 -05:00
Keith Bennett
9a4cfe4940 🚸 MPCTEMP: Home before cooling (#24434) 2022-07-04 00:30:02 -05:00
Keith Bennett
4a9ecdd70b 🩹 Fix MKS TinyBee ADC Vref (#24432) 2022-07-04 00:30:02 -05:00
Scott Lahteine
160762742a 🩹 Remove poison wchar_t macro 2022-07-04 00:30:02 -05:00
Scott Lahteine
95b0ee2fbf 🩹 Remove obsolete split_move 2022-07-01 21:17:21 -05:00
Moonglow
505ae61b8d 🐛 Fix M149 (#24430) 2022-06-30 22:00:52 -05:00
Scott Lahteine
5660c3b189 📝 Index Mobo Rev03 => Opulo Lumen Rev3 2022-06-30 22:00:52 -05:00
Scott Lahteine
470512dd50 🩹 Fix memset block warning 2022-06-30 22:00:52 -05:00
Keith Bennett
310a76444d 🐛 Fix Axis Homing (#24425)
Followup to 4520a51
2022-06-30 22:00:52 -05:00
John Lagonikas
ea630bbed7 🐛 Fix MAX31865 PT1000 normalization (#24407)
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
2022-06-30 22:00:52 -05:00
Scott Lahteine
15915ede53 ♻️ reset_acceleration_rates => refresh_… 2022-06-30 22:00:52 -05:00
Scott Lahteine
a68aa255bc ♻️ Planner flags refactor 2022-06-30 22:00:52 -05:00
lujios
b3fe059f6c ️ Improve Sensorless homing/probing accuracy for G28, G33, M48 (#24220)
Co-Authored-By: Robby Candra <robbycandra.mail@gmail.com>
Co-Authored-By: ellensp <530024+ellensp@users.noreply.github.com>
2022-06-30 22:00:52 -05:00
elimisback
b938d99b32 🔨 BTT STM32G0B1RE xfer build (#24245) 2022-06-30 22:00:52 -05:00
Scott Lahteine
b01caf0afe 🎨 Minimize block->steps.set 2022-06-30 22:00:52 -05:00
DerAndere
088fa84b7f ♻️ More updates for multi-axis
Based on #23112

Co-Authored-By: Scott Lahteine <thinkyhead@users.noreply.github.com>
2022-06-30 22:00:52 -05:00
Scott Lahteine
74339bfefc 🚨 Fix some compiler warnings 2022-06-30 22:00:52 -05:00
Scott Lahteine
40fa85b92e 🐛 Fix types.h macros and fields
Fixes #24419
2022-06-29 13:05:16 -05:00
Scott Lahteine
1c3d5827e6 🎨 Misc. shorthand operators 2022-06-26 10:02:15 -05:00
Scott Lahteine
0567d613ba 🐛 Fix Manual Move axis selection (#24404) 2022-06-26 06:45:47 -05:00
Shlee
3bf100301a 📝 Add STM32F4 example, Ruby (#24399) 2022-06-26 06:43:49 -05:00
Giuliano Zaro
f1483e76a1 🌐 Update Italian language (#24398) 2022-06-26 06:43:49 -05:00
Roman Moravčík
9efccbf23e 🌐 Update Slovak language (#24397) 2022-06-26 06:43:49 -05:00
sgparry
fe86ff2d53 🩹 Fix LCD contrast with K8800 board 2022-06-26 06:43:49 -05:00
Scott Lahteine
f6e248df6e 🌐 Drop unused delta strings 2022-06-24 22:09:42 -05:00
Scott Lahteine
6d1ce46dd1 🧑‍💻 Fix STATIC_ITEM_N arg order 2022-06-24 01:39:40 -05:00
Scott Lahteine
341bf27d1d ✏️ 9-axis followup fixing G2-G3 arcs 2022-06-24 01:39:40 -05:00
tombrazier
0698fcb005 🩹 Fix Mesh Leveling + Debug compile (#24297) 2022-06-24 01:39:40 -05:00
John Robertson
d725998340 ️ PWM for ESP32 I2S expander (#24193) 2022-06-24 01:25:17 -05:00
Bob Kuhn
2f814079d8 🐛 Fix Lerdge build / encrypt (#24391)
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
2022-06-24 00:07:38 -05:00
Victor Oliveira
a3876c5896 Classic UI BIQU BX (#24387) 2022-06-24 00:07:24 -05:00
ellensp
7497890f04 🩹 Fix DGUS (MKS) compile (#24378) 2022-06-24 00:07:04 -05:00
Victor Oliveira
b16a32e7ce 🚑️ Fix BIQU BX touch freeze (#24383) 2022-06-24 00:06:35 -05:00
ellensp
052a64052b 🐛 Fix M423 invocation (#24360)
Followup to #23745
2022-06-24 00:06:20 -05:00
tombrazier
4648ade0e6 🩹 LCD strings followup, fix warning (#24328) 2022-06-24 00:06:06 -05:00
InsanityAutomation
a67dd76db4 🐛 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 00:04:01 -05:00
ellensp
47b8671836 🚑️ Fix SD mount bug (#24319)
Co-authored-by: Scott Lahteine <github@thinkyhead.com>
2022-06-24 00:01:36 -05:00
Scott Lahteine
f04efa85cd 🎨 Simplify move menus with substitution 2022-06-22 05:55:38 -05:00
Scott Lahteine
5b2b08d048 🎨 Use MAP for home axis items 2022-06-22 05:55:38 -05:00
Scott Lahteine
3f9869a6c1 🧑‍💻 Fix STATIC_ITEM_N arg order 2022-06-22 05:55:38 -05:00
Scott Lahteine
65490f27c4 🎨 Fix comments, formatting 2022-06-22 05:37:38 -05:00
luzpaz
1afb80d45d 🌐 Fix LCD string, typos (#24324) 2022-06-22 05:37:38 -05:00
tombrazier
6a20b1271d 🐛 Fix G2/G3 Arcs stutter / JD speed (#24362) 2022-06-22 05:37:38 -05:00
ellensp
733e5f3957 👷 CI test without src filter (emulate Arduino) (#24335) 2022-06-22 05:37:38 -05:00
Keith Bennett
031633cde6 👷 Use Biqu BX for CI test (#24331) 2022-06-22 05:37:38 -05:00
Scott Lahteine
5149eed13c 🧑‍💻 MAP macro for axis lists, etc. (#24191) 2022-06-22 05:37:38 -05:00
Scott Lahteine
2ecaebeab2 🧑‍💻 Apply F() to some LCD / TFT strings
Followup to #24228
2022-06-13 21:01:55 -05:00
ellensp
047ecc5995 🩹 Fix missing ProUI cpp wrapper (#24313) 2022-06-13 21:01:55 -05:00
ellensp
2268e1417b 🐛 Fix JGAurora A5S A1 build (#24326) 2022-06-13 04:30:00 -05:00
Steven Haigh
3fa767f533 🩹 Fix ProUI compile (#24310)
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
2022-06-13 04:29:40 -05:00
Scott Lahteine
9860580bed 🧑‍💻 Misc. servo code cleanup 2022-06-13 04:29:24 -05:00
Scott Lahteine
6df193a5d1 🧑‍💻 Remove servo macros 2022-06-13 04:29:04 -05:00
ellensp
e5fb6ace4c 🩹 Media Change followup (#24302)
Followup to #24015
2022-06-07 01:59:58 -05:00
Scott Lahteine
b659bb2a52 👔 Fix and comment use_example_configs 2022-06-06 19:13:26 -05:00
Miguel Risco-Castillo
7e27f06364 🚸 ProUI G-code preview, PID plot (#24282) 2022-06-06 00:01:26 -05:00
Scott Lahteine
72346e80fa 🔖 Repurpose as bugfix for 2.0.9.4 2022-06-05 23:56:18 -05:00
526 changed files with 12789 additions and 9239 deletions

View File

@@ -14,6 +14,10 @@ end_of_line = lf
indent_style = space indent_style = space
indent_size = 2 indent_size = 2
[{*.py,*.conf,*.sublime-project}] [{*.py}]
indent_style = space
indent_size = 4
[{*.conf,*.sublime-project}]
indent_style = tab indent_style = tab
indent_size = 4 indent_size = 4

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:

147
.github/workflows/test-builds.yml vendored Normal file
View File

@@ -0,0 +1,147 @@
#
# test-builds.yml
# Do test builds to catch compile errors
#
name: CI - bugfix-2.0.x
on:
pull_request:
branches:
- bugfix-2.0.x
paths-ignore:
- config/**
- data/**
- docs/**
- '**/*.md'
push:
branches:
- bugfix-2.0.x
paths-ignore:
- config/**
- data/**
- docs/**
- '**/*.md'
jobs:
test_builds:
name: Run All Tests
if: github.repository == 'MarlinFirmware/Marlin'
runs-on: ubuntu-latest
strategy:
matrix:
test-platform:
# Base Environments
- DUE
- DUE_archim
- esp32
- linux_native
- mega2560
- at90usb1286_dfu
- teensy31
- teensy35
- teensy41
- SAMD51_grandcentral_m4
# Extended AVR Environments
- FYSETC_F6
- mega1280
- rambo
- sanguino1284p
- sanguino644p
# STM32F1 (Maple) Environments
#- STM32F103RC_btt_maple
- STM32F103RC_btt_USB_maple
- STM32F103RC_fysetc_maple
- STM32F103RC_meeb_maple
- jgaurora_a5s_a1_maple
- STM32F103VE_longer_maple
#- mks_robin_maple
- mks_robin_lite_maple
- mks_robin_pro_maple
#- mks_robin_nano35_maple
#- STM32F103RE_creality_maple
- STM32F103VE_ZM3E4V2_USB_maple
# STM32 (ST) Environments
- STM32F103RC_btt
#- STM32F103RC_btt_USB
- STM32F103RE_btt
- STM32F103RE_btt_USB
- STM32F103RE_creality
- STM32F401RC_creality
- STM32F103VE_longer
- STM32F407VE_black
- STM32F401VE_STEVAL
- BIGTREE_BTT002
- BIGTREE_SKR_PRO
- BIGTREE_GTR_V1_0
- mks_robin
- ARMED
- FYSETC_S6
- STM32F070CB_malyan
- STM32F070RB_malyan
- malyan_M300
- FLYF407ZG
- rumba32
- LERDGEX
- LERDGEK
- mks_robin_nano35
- NUCLEO_F767ZI
- REMRAM_V1
- BTT_SKR_SE_BX
- chitu_f103
- Opulo_Lumen_REV3
# Put lengthy tests last
- LPC1768
- LPC1769
# Non-working environment tests
#- at90usb1286_cdc
#- STM32F103CB_malyan
#- STM32F103RE
#- mks_robin_mini
steps:
- name: Check out the PR
uses: actions/checkout@v3
- name: Cache pip
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Cache PlatformIO
uses: actions/cache@v3
with:
path: ~/.platformio
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
- name: Select Python 3.7
uses: actions/setup-python@v3
with:
python-version: '3.7' # Version range or exact version of a Python version to use, using semvers version range syntax.
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
- name: Install PlatformIO
run: |
pip install -U platformio
pio upgrade --dev
pio pkg update --global
- name: Run ${{ matrix.test-platform }} Tests
run: |
make tests-single-ci TEST_TARGET=${{ matrix.test-platform }}

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 02000904 #define CONFIGURATION_H_VERSION 02000905
//=========================================================================== //===========================================================================
//============================= 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
@@ -186,28 +177,27 @@
//#define E7_DRIVER_TYPE A4988 //#define E7_DRIVER_TYPE A4988
/** /**
* Axis codes for additional axes: * Additional Axis Settings
* This defines the axis code that is used in G-code commands to *
* reference a specific axis. * AXISn_NAME defines the letter used to refer to the axis in (most) G-code commands.
* 'A' for rotational axis parallel to X * By convention the names and roles are typically:
* 'B' for rotational axis parallel to Y * 'A' : Rotational axis parallel to X
* 'C' for rotational axis parallel to Z * 'B' : Rotational axis parallel to Y
* 'U' for secondary linear axis parallel to X * 'C' : Rotational axis parallel to Z
* 'V' for secondary linear axis parallel to Y * 'U' : Secondary linear axis parallel to X
* 'W' for secondary linear axis parallel to Z * 'V' : Secondary linear axis parallel to Y
* Regardless of the settings, firmware-internal axis IDs are * 'W' : Secondary linear axis parallel to Z
* I (AXIS4), J (AXIS5), K (AXIS6). *
* Regardless of these settings the axes are internally named I, J, K.
*/ */
#ifdef I_DRIVER_TYPE #ifdef I_DRIVER_TYPE
#define AXIS4_NAME 'A' // :['A', 'B', 'C', 'U', 'V', 'W'] #define AXIS4_NAME 'A' // :['A', 'B', 'C', 'U', 'V', 'W']
#endif #endif
#ifdef J_DRIVER_TYPE #ifdef J_DRIVER_TYPE
#define AXIS5_NAME 'B' // :['B', 'C', 'U', 'V', 'W'] #define AXIS5_NAME 'B' // :['B', 'C', 'U', 'V', 'W']
#define AXIS5_ROTATES
#endif #endif
#ifdef K_DRIVER_TYPE #ifdef K_DRIVER_TYPE
#define AXIS6_NAME 'C' // :['C', 'U', 'V', 'W'] #define AXIS6_NAME 'C' // :['C', 'U', 'V', 'W']
#define AXIS6_ROTATES
#endif #endif
// @section extruder // @section extruder
@@ -643,7 +633,7 @@
* *
* 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.
*/ */
#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)
@@ -845,6 +835,134 @@
#define POLAR_SEGMENTS_PER_SECOND 5 #define POLAR_SEGMENTS_PER_SECOND 5
#endif #endif
// 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
/**
* 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
// 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
//=========================================================================== //===========================================================================
//============================== Endstop Settings =========================== //============================== Endstop Settings ===========================
//=========================================================================== //===========================================================================
@@ -1001,9 +1119,9 @@
* M204 R Retract Acceleration * M204 R Retract Acceleration
* M204 T Travel Acceleration * M204 T Travel Acceleration
*/ */
#define DEFAULT_ACCELERATION 3000 // X, Y, Z and E acceleration for printing moves #define DEFAULT_ACCELERATION 3000 // X, Y, Z ... and E acceleration for printing moves
#define DEFAULT_RETRACT_ACCELERATION 3000 // E acceleration for retracts #define DEFAULT_RETRACT_ACCELERATION 3000 // E acceleration for retracts
#define DEFAULT_TRAVEL_ACCELERATION 3000 // X, Y, Z acceleration for travel (non printing) moves #define DEFAULT_TRAVEL_ACCELERATION 3000 // X, Y, Z ... acceleration for travel (non printing) moves
/** /**
* Default Jerk limits (mm/s) * Default Jerk limits (mm/s)
@@ -1185,9 +1303,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 }
@@ -1738,7 +1884,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

View File

@@ -30,7 +30,7 @@
* *
* Basic settings can be found in Configuration.h * Basic settings can be found in Configuration.h
*/ */
#define CONFIGURATION_ADV_H_VERSION 02000904 #define CONFIGURATION_ADV_H_VERSION 02000905
//=========================================================================== //===========================================================================
//============================= Thermal Settings ============================ //============================= Thermal Settings ============================
@@ -54,87 +54,87 @@
// 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
#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
#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
#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
#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
#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
#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
#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
#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
#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
#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
#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
#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
#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
#endif #endif
/** /**
@@ -923,9 +923,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 } }
/** /**
@@ -3472,6 +3475,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
@@ -3545,8 +3551,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
@@ -3559,79 +3568,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)

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.0.9.4" //#define SHORT_BUILD_VERSION "bugfix-2.0.x"
/** /**
* Verbose version identifier which should contain a reference to the location * Verbose version identifier which should contain a reference to the location
@@ -41,7 +41,7 @@
* here we define this default string as the date where the latest release * here we define this default string as the date where the latest release
* version was tagged. * version was tagged.
*/ */
//#define STRING_DISTRIBUTION_DATE "2022-06-04" //#define STRING_DISTRIBUTION_DATE "2023-04-16"
/** /**
* Defines a generic printer name to be output to the LCD after booting Marlin. * Defines a generic printer name to be output to the LCD after booting Marlin.

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

@@ -19,6 +19,10 @@
*/ */
#pragma once #pragma once
/**
* HAL for Arduino AVR
*/
#include "../shared/Marduino.h" #include "../shared/Marduino.h"
#include "../shared/HAL_SPI.h" #include "../shared/HAL_SPI.h"
#include "fastio.h" #include "fastio.h"

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

@@ -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

@@ -6,14 +6,14 @@
# #
import pioutil import pioutil
if pioutil.is_pio_build(): if pioutil.is_pio_build():
import platform import platform
current_OS = platform.system() current_OS = platform.system()
if current_OS == 'Windows': if current_OS == 'Windows':
Import("env") Import("env")
# Use bossac.exe on Windows # Use bossac.exe on Windows
env.Replace( env.Replace(
UPLOADCMD="bossac --info --unlock --write --verify --reset --erase -U false --boot $SOURCE" UPLOADCMD="bossac --info --unlock --write --verify --reset --erase -U false --boot $SOURCE"
) )

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

@@ -9,119 +9,127 @@ from __future__ import print_function
import pioutil import pioutil
if pioutil.is_pio_build(): 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")
def print_error(e): def print_error(e):
print('\nUnable to find destination disk (%s)\n' \ print('\nUnable to find destination disk (%s)\n' \
'Please select it in platformio.ini using the upload_port keyword ' \ 'Please select it in platformio.ini using the upload_port keyword ' \
'(https://docs.platformio.org/en/latest/projectconf/section_env_upload.html) ' \ '(https://docs.platformio.org/en/latest/projectconf/section_env_upload.html) ' \
'or copy the firmware (.pio/build/%s/firmware.bin) manually to the appropriate disk\n' \ 'or copy the firmware (.pio/build/%s/firmware.bin) manually to the appropriate disk\n' \
%(e, env.get('PIOENV'))) %(e, env.get('PIOENV')))
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' #
target_file_found = False upload_disk = 'Disk not found'
target_drive_found = False target_file_found = False
if current_OS == 'Windows': target_drive_found = False
# if current_OS == 'Windows':
# platformio.ini will accept this for a Windows upload port designation: 'upload_port = L:' #
# Windows - doesn't care about the disk's name, only cares about the drive letter # platformio.ini will accept this for a Windows upload port designation: 'upload_port = L:'
import subprocess,string # Windows - doesn't care about the disk's name, only cares about the drive letter
from ctypes import windll import subprocess,string
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
drives = [] drives = []
bitmask = windll.kernel32.GetLogicalDrives() bitmask = windll.kernel32.GetLogicalDrives()
for letter in string.ascii_uppercase: for letter in string.ascii_uppercase:
if bitmask & 1: if bitmask & 1:
drives.append(letter) drives.append(letter)
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))
except Exception as e: except Exception as e:
print ('error:{}'.format(e)) print ('error:{}'.format(e))
continue continue
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
if target_drive in drives: # If target drive is found, use it. user = getpass.getuser()
target_drive_found = True mpath = Path('/media', user)
upload_disk = os.path.join(os.sep, 'media', getpass.getuser(), target_drive) + os.sep drives = [ x for x in mpath.iterdir() if x.is_dir() ]
else: if target_drive in drives: # If target drive is found, use it.
for drive in drives: target_drive_found = True
try: upload_disk = mpath / target_drive
files = os.listdir(os.path.join(os.sep, 'media', getpass.getuser(), drive)) else:
except: for drive in drives:
continue try:
else: fpath = mpath / drive
if target_filename in files: filenames = [ x.name for x in fpath.iterdir() if x.is_file() ]
upload_disk = os.path.join(os.sep, 'media', getpass.getuser(), drive) + os.sep except:
target_file_found = True continue
break else:
# if target_filename in filenames:
# set upload_port to drive if found upload_disk = mpath / drive
# target_file_found = True
break
#
# 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( env.Replace(
UPLOAD_FLAGS="-P$UPLOAD_PORT" UPLOAD_FLAGS="-P$UPLOAD_PORT"
) )
elif current_OS == 'Darwin': # MAC elif current_OS == 'Darwin': # MAC
# #
# 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
if target_drive in drives and not target_file_found: # set upload if not found target file yet drives = [ x for x in dpath.iterdir() if x.is_dir() ]
target_drive_found = True if target_drive in drives and not target_file_found: # set upload if not found target file yet
upload_disk = '/Volumes/' + target_drive + '/' target_drive_found = True
for drive in drives: upload_disk = dpath / target_drive
try: for drive in drives:
filenames = os.listdir('/Volumes/' + drive + '/') # will get an error if the drive is protected try:
except: fpath = dpath / drive # will get an error if the drive is protected
continue filenames = [ x.name for x in fpath.iterdir() if x.is_file() ]
else: except:
if target_filename in filenames: continue
if not target_file_found: else:
upload_disk = '/Volumes/' + drive + '/' if target_filename in filenames:
target_file_found = True upload_disk = dpath / drive
target_file_found = True
break
# #
# 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')
except Exception as e: except Exception as e:
print_error(str(e)) print_error(str(e))
env.AddPreAction("upload", before_upload) env.AddPreAction("upload", before_upload)

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

@@ -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

@@ -782,7 +782,7 @@ void idle(bool no_stepper_sleep/*=false*/) {
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());

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
@@ -395,7 +397,7 @@
#define BOARD_BTT_GTR_V1_0 4214 // BigTreeTech GTR v1.0 (STM32F407IGT) #define BOARD_BTT_GTR_V1_0 4214 // BigTreeTech GTR v1.0 (STM32F407IGT)
#define BOARD_BTT_OCTOPUS_V1_0 4215 // BigTreeTech Octopus v1.0 (STM32F446ZE) #define BOARD_BTT_OCTOPUS_V1_0 4215 // BigTreeTech Octopus v1.0 (STM32F446ZE)
#define BOARD_BTT_OCTOPUS_V1_1 4216 // BigTreeTech Octopus v1.1 (STM32F446ZE) #define BOARD_BTT_OCTOPUS_V1_1 4216 // BigTreeTech Octopus v1.1 (STM32F446ZE)
#define BOARD_BTT_OCTOPUS_PRO_V1_0 4217 // 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 4218 // Lerdge K (STM32F407ZG) #define BOARD_LERDGE_K 4218 // Lerdge K (STM32F407ZG)
#define BOARD_LERDGE_S 4219 // Lerdge S (STM32F407VE) #define BOARD_LERDGE_S 4219 // Lerdge S (STM32F407VE)
#define BOARD_LERDGE_X 4220 // Lerdge X (STM32F407VE) #define BOARD_LERDGE_X 4220 // Lerdge X (STM32F407VE)
@@ -408,17 +410,18 @@
#define BOARD_MKS_ROBIN_PRO_V2 4227 // MKS Robin Pro V2 (STM32F407VE) #define BOARD_MKS_ROBIN_PRO_V2 4227 // MKS Robin Pro V2 (STM32F407VE)
#define BOARD_MKS_ROBIN_NANO_V3 4228 // MKS Robin Nano V3 (STM32F407VG) #define BOARD_MKS_ROBIN_NANO_V3 4228 // MKS Robin Nano V3 (STM32F407VG)
#define BOARD_MKS_ROBIN_NANO_V3_1 4229 // MKS Robin Nano V3.1 (STM32F407VE) #define BOARD_MKS_ROBIN_NANO_V3_1 4229 // MKS Robin Nano V3.1 (STM32F407VE)
#define BOARD_MKS_MONSTER8 4230 // MKS Monster8 (STM32F407VG) #define BOARD_MKS_MONSTER8_V1 4230 // MKS Monster8 V1 (STM32F407VE)
#define BOARD_ANET_ET4 4231 // ANET ET4 V1.x (STM32F407VG) #define BOARD_MKS_MONSTER8_V2 4231 // MKS Monster8 V2 (STM32F407VE)
#define BOARD_ANET_ET4P 4232 // ANET ET4P V1.x (STM32F407VG) #define BOARD_ANET_ET4 4232 // ANET ET4 V1.x (STM32F407VG)
#define BOARD_FYSETC_CHEETAH_V20 4233 // FYSETC Cheetah V2.0 #define BOARD_ANET_ET4P 4233 // ANET ET4P V1.x (STM32F407VG)
#define BOARD_TH3D_EZBOARD_V2 4234 // TH3D EZBoard v2.0 #define BOARD_FYSETC_CHEETAH_V20 4234 // FYSETC Cheetah V2.0 (STM32F401RC)
#define BOARD_INDEX_REV03 4235 // Index PnP Controller REV03 (STM32F407VE/VG) #define BOARD_TH3D_EZBOARD_V2 4235 // TH3D EZBoard v2.0 (STM32F405RG)
#define BOARD_MKS_ROBIN_NANO_V1_3_F4 4236 // MKS Robin Nano V1.3 and MKS Robin Nano-S V1.3 (STM32F407VE) #define BOARD_OPULO_LUMEN_REV3 4236 // Opulo Lumen PnP Controller REV3 (STM32F407VE / STM32F407VG)
#define BOARD_MKS_EAGLE 4237 // MKS Eagle (STM32F407VE) #define BOARD_MKS_ROBIN_NANO_V1_3_F4 4237 // MKS Robin Nano V1.3 and MKS Robin Nano-S V1.3 (STM32F407VE)
#define BOARD_ARTILLERY_RUBY 4238 // Artillery Ruby (STM32F401RC) #define BOARD_MKS_EAGLE 4238 // MKS Eagle (STM32F407VE)
#define BOARD_FYSETC_SPIDER_V2_2 4239 // FYSETC Spider V2.2 (STM32F446VE) #define BOARD_ARTILLERY_RUBY 4239 // Artillery Ruby (STM32F401RC)
#define BOARD_CREALITY_V24S1_301F4 4240 // Creality v2.4.S1_301F4 (STM32F401RC) as found in the Ender-3 S1 F4 #define BOARD_FYSETC_SPIDER_V2_2 4240 // FYSETC Spider V2.2 (STM32F446VE)
#define BOARD_CREALITY_V24S1_301F4 4241 // Creality v2.4.S1_301F4 (STM32F401RC) as found in the Ender-3 S1 F4
// //
// ARM Cortex M7 // ARM Cortex M7
@@ -428,9 +431,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

@@ -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

@@ -350,7 +350,7 @@
#define _LIST_N(N,V...) LIST_##N(V) #define _LIST_N(N,V...) LIST_##N(V)
#define LIST_N(N,V...) _LIST_N(N,V) #define LIST_N(N,V...) _LIST_N(N,V)
#define LIST_N_1(N,K) _LIST_N(N,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K) #define LIST_N_1(N,K) _LIST_N(N,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K)
#define ARRAY_N(N,V...) { _LIST_N(N,V) } #define ARRAY_N(N,V...) { _LIST_N(N,V) }
#define ARRAY_N_1(N,K) { LIST_N_1(N,K) } #define ARRAY_N_1(N,K) { LIST_N_1(N,K) }
@@ -632,8 +632,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)
@@ -647,7 +647,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)
@@ -700,13 +699,22 @@
#define RREPEAT2_S(S,N,OP,V...) EVAL1024(_RREPEAT2(S,SUB##S(N),OP,V)) #define RREPEAT2_S(S,N,OP,V...) EVAL1024(_RREPEAT2(S,SUB##S(N),OP,V))
#define RREPEAT2(N,OP,V...) RREPEAT2_S(0,N,OP,V) #define RREPEAT2(N,OP,V...) RREPEAT2_S(0,N,OP,V)
// See https://github.com/swansontec/map-macro // Call OP(A) with each item as an argument
#define MAP_OUT #define _MAP(_MAP_OP,A,V...) \
#define MAP_END(...) _MAP_OP(A) \
#define MAP_GET_END() 0, MAP_END IF_ELSE(HAS_ARGS(V)) \
#define MAP_NEXT0(test, next, ...) next MAP_OUT ( DEFER2(__MAP)()(_MAP_OP,V) ) \
#define MAP_NEXT1(test, next) MAP_NEXT0 (test, next, 0) ( /* Do nothing */ )
#define MAP_NEXT(test, next) MAP_NEXT1 (MAP_GET_END test, next) #define __MAP() _MAP
#define MAP0(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP1) (f, peek, __VA_ARGS__)
#define MAP1(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP0) (f, peek, __VA_ARGS__) #define MAP(OP,V...) EVAL(_MAP(OP,V))
#define MAP(f, ...) EVAL512 (MAP1 (f, __VA_ARGS__, (), 0))
// Emit a list of OP(A) with the given items
#define _MAPLIST(_MAP_OP,A,V...) \
_MAP_OP(A) \
IF_ELSE(HAS_ARGS(V)) \
( , DEFER2(__MAPLIST)()(_MAP_OP,V) ) \
( /* Do nothing */ )
#define __MAPLIST() _MAPLIST
#define MAPLIST(OP,V...) EVAL(_MAPLIST(OP,V))

View File

@@ -30,16 +30,15 @@
uint8_t marlin_debug_flags = MARLIN_DEBUG_NONE; uint8_t marlin_debug_flags = MARLIN_DEBUG_NONE;
// Commonly-used strings in serial output // Commonly-used strings in serial output
PGMSTR(NUL_STR, ""); PGMSTR(SP_P_STR, " P"); PGMSTR(SP_T_STR, " T"); PGMSTR(SP_A_STR, " A"); PGMSTR(SP_B_STR, " B"); PGMSTR(SP_C_STR, " C");
PGMSTR(X_STR, "X"); PGMSTR(Y_STR, "Y"); PGMSTR(Z_STR, "Z"); PGMSTR(E_STR, "E"); PGMSTR(SP_P_STR, " P"); PGMSTR(SP_T_STR, " T"); PGMSTR(NUL_STR, "");
PGMSTR(X_LBL, "X:"); PGMSTR(Y_LBL, "Y:"); PGMSTR(Z_LBL, "Z:"); PGMSTR(E_LBL, "E:");
PGMSTR(SP_A_STR, " A"); PGMSTR(SP_B_STR, " B"); PGMSTR(SP_C_STR, " C"); #define _N_STR(N) PGMSTR(N##_STR, STR_##N);
PGMSTR(SP_X_STR, " X"); PGMSTR(SP_Y_STR, " Y"); PGMSTR(SP_Z_STR, " Z"); PGMSTR(SP_E_STR, " E"); #define _N_LBL(N) PGMSTR(N##_LBL, STR_##N ":");
PGMSTR(SP_X_LBL, " X:"); PGMSTR(SP_Y_LBL, " Y:"); PGMSTR(SP_Z_LBL, " Z:"); PGMSTR(SP_E_LBL, " E:"); #define _SP_N_STR(N) PGMSTR(SP_##N##_STR, " " STR_##N);
PGMSTR(I_STR, STR_I); PGMSTR(J_STR, STR_J); PGMSTR(K_STR, STR_K); #define _SP_N_LBL(N) PGMSTR(SP_##N##_LBL, " " STR_##N ":");
PGMSTR(I_LBL, STR_I ":"); PGMSTR(J_LBL, STR_J ":"); PGMSTR(K_LBL, STR_K ":"); MAP(_N_STR, LOGICAL_AXIS_NAMES); MAP(_SP_N_STR, LOGICAL_AXIS_NAMES);
PGMSTR(SP_I_STR, " " STR_I); PGMSTR(SP_J_STR, " " STR_J); PGMSTR(SP_K_STR, " " STR_K); MAP(_N_LBL, LOGICAL_AXIS_NAMES); MAP(_SP_N_LBL, LOGICAL_AXIS_NAMES);
PGMSTR(SP_I_LBL, " " STR_I ":"); PGMSTR(SP_J_LBL, " " STR_J ":"); PGMSTR(SP_K_LBL, " " STR_K ":");
// Hook Meatpack if it's enabled on the first leaf // Hook Meatpack if it's enabled on the first leaf
#if ENABLED(MEATPACK_ON_SERIAL_PORT_1) #if ENABLED(MEATPACK_ON_SERIAL_PORT_1)
@@ -73,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(' '); }
@@ -102,10 +101,10 @@ void print_bin(uint16_t val) {
} }
} }
void print_pos(LINEAR_AXIS_ARGS(const_float_t), FSTR_P const prefix/*=nullptr*/, FSTR_P const suffix/*=nullptr*/) { void print_pos(NUM_AXIS_ARGS(const_float_t), FSTR_P const prefix/*=nullptr*/, FSTR_P const suffix/*=nullptr*/) {
if (prefix) serial_print(prefix); if (prefix) serial_print(prefix);
SERIAL_ECHOPGM_P( SERIAL_ECHOPGM_P(
LIST_N(DOUBLE(LINEAR_AXES), SP_X_STR, x, SP_Y_STR, y, SP_Z_STR, z, SP_I_STR, i, SP_J_STR, j, SP_K_STR, k) LIST_N(DOUBLE(NUM_AXES), SP_X_STR, x, SP_Y_STR, y, SP_Z_STR, z, SP_I_STR, i, SP_J_STR, j, SP_K_STR, k)
); );
if (suffix) serial_print(suffix); else SERIAL_EOL(); if (suffix) serial_print(suffix); else SERIAL_EOL();
} }

View File

@@ -28,19 +28,6 @@
#include "../feature/meatpack.h" #include "../feature/meatpack.h"
#endif #endif
// Commonly-used strings in serial output
extern const char NUL_STR[],
SP_X_STR[], SP_Y_STR[], SP_Z_STR[],
SP_A_STR[], SP_B_STR[], SP_C_STR[], SP_E_STR[],
SP_X_LBL[], SP_Y_LBL[], SP_Z_LBL[], SP_E_LBL[],
SP_I_STR[], SP_J_STR[], SP_K_STR[],
SP_I_LBL[], SP_J_LBL[], SP_K_LBL[],
SP_P_STR[], SP_T_STR[],
X_STR[], Y_STR[], Z_STR[], E_STR[],
I_STR[], J_STR[], K_STR[],
X_LBL[], Y_LBL[], Z_LBL[], E_LBL[],
I_LBL[], J_LBL[], K_LBL[];
// //
// Debugging flags for use by M111 // Debugging flags for use by M111
// //
@@ -348,11 +335,40 @@ void serial_spaces(uint8_t count);
void serial_offset(const_float_t v, const uint8_t sp=0); // For v==0 draw space (sp==1) or plus (sp==2) void serial_offset(const_float_t v, const uint8_t sp=0); // For v==0 draw space (sp==1) or plus (sp==2)
void print_bin(const uint16_t val); void print_bin(const uint16_t val);
void print_pos(LINEAR_AXIS_ARGS(const_float_t), FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr); void print_pos(NUM_AXIS_ARGS(const_float_t), FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr);
inline void print_pos(const xyz_pos_t &xyz, FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr) { inline void print_pos(const xyz_pos_t &xyz, FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr) {
print_pos(LINEAR_AXIS_ELEM(xyz), prefix, suffix); print_pos(NUM_AXIS_ELEM(xyz), prefix, suffix);
} }
#define SERIAL_POS(SUFFIX,VAR) do { print_pos(VAR, F(" " STRINGIFY(VAR) "="), F(" : " SUFFIX "\n")); }while(0) #define SERIAL_POS(SUFFIX,VAR) do { print_pos(VAR, F(" " STRINGIFY(VAR) "="), F(" : " SUFFIX "\n")); }while(0)
#define SERIAL_XYZ(PREFIX,V...) do { print_pos(V, F(PREFIX)); }while(0) #define SERIAL_XYZ(PREFIX,V...) do { print_pos(V, F(PREFIX)); }while(0)
//
// Commonly-used strings in serial output
//
#define _N_STR(N) N##_STR
#define _N_LBL(N) N##_LBL
#define _N_STR_A(N) _N_STR(N)[]
#define _N_LBL_A(N) _N_LBL(N)[]
#define _SP_N_STR(N) SP_##N##_STR
#define _SP_N_LBL(N) SP_##N##_LBL
#define _SP_N_STR_A(N) _SP_N_STR(N)[]
#define _SP_N_LBL_A(N) _SP_N_LBL(N)[]
extern const char SP_A_STR[], SP_B_STR[], SP_C_STR[], SP_P_STR[], SP_T_STR[], NUL_STR[],
MAPLIST(_N_STR_A, LOGICAL_AXIS_NAMES), MAPLIST(_SP_N_STR_A, LOGICAL_AXIS_NAMES),
MAPLIST(_N_LBL_A, LOGICAL_AXIS_NAMES), MAPLIST(_SP_N_LBL_A, LOGICAL_AXIS_NAMES);
PGM_P const SP_AXIS_LBL[] PROGMEM = { MAPLIST(_SP_N_LBL, LOGICAL_AXIS_NAMES) };
PGM_P const SP_AXIS_STR[] PROGMEM = { MAPLIST(_SP_N_STR, LOGICAL_AXIS_NAMES) };
#undef _N_STR
#undef _N_LBL
#undef _N_STR_A
#undef _N_LBL_A
#undef _SP_N_STR
#undef _SP_N_LBL
#undef _SP_N_STR_A
#undef _SP_N_LBL_A

View File

@@ -43,7 +43,9 @@ public:
} }
constexpr SerialMask(const uint8_t mask) : mask(mask) {} constexpr SerialMask(const uint8_t mask) : mask(mask) {}
constexpr SerialMask(const SerialMask & other) : mask(other.mask) {} // Can't use = default here since not all framework support this constexpr SerialMask(const SerialMask &rs) : mask(rs.mask) {} // Can't use = default here since not all frameworks support this
SerialMask& operator=(const SerialMask &rs) { mask = rs.mask; return *this; }
static constexpr uint8_t All = 0xFF; static constexpr uint8_t All = 0xFF;
}; };

View File

@@ -36,23 +36,40 @@ struct IF { typedef R type; };
template <class L, class R> template <class L, class R>
struct IF<true, L, R> { typedef L type; }; struct IF<true, L, R> { typedef L type; };
#define LINEAR_AXIS_GANG(V...) GANG_N(LINEAR_AXES, V) #define NUM_AXIS_GANG(V...) GANG_N(NUM_AXES, V)
#define LINEAR_AXIS_CODE(V...) CODE_N(LINEAR_AXES, V) #define NUM_AXIS_CODE(V...) CODE_N(NUM_AXES, V)
#define LINEAR_AXIS_LIST(V...) LIST_N(LINEAR_AXES, V) #define NUM_AXIS_LIST(V...) LIST_N(NUM_AXES, V)
#define LINEAR_AXIS_ARRAY(V...) { LINEAR_AXIS_LIST(V) } #define NUM_AXIS_LIST_1(V) LIST_N_1(NUM_AXES, V)
#define LINEAR_AXIS_ARGS(T...) LINEAR_AXIS_LIST(T x, T y, T z, T i, T j, T k) #define NUM_AXIS_ARRAY(V...) { NUM_AXIS_LIST(V) }
#define LINEAR_AXIS_ELEM(O) LINEAR_AXIS_LIST(O.x, O.y, O.z, O.i, O.j, O.k) #define NUM_AXIS_ARRAY_1(V) { NUM_AXIS_LIST_1(V) }
#define LINEAR_AXIS_DEFS(T,V) LINEAR_AXIS_LIST(T x=V, T y=V, T z=V, T i=V, T j=V, T k=V) #define NUM_AXIS_ARGS(T...) NUM_AXIS_LIST(T x, T y, T z, T i, T j, T k)
#define NUM_AXIS_ELEM(O) NUM_AXIS_LIST(O.x, O.y, O.z, O.i, O.j, O.k)
#define NUM_AXIS_DEFS(T,V) NUM_AXIS_LIST(T x=V, T y=V, T z=V, T i=V, T j=V, T k=V)
#define LOGICAL_AXIS_GANG(E,V...) LINEAR_AXIS_GANG(V) GANG_ITEM_E(E) #define MAIN_AXIS_NAMES NUM_AXIS_LIST(X, Y, Z, I, J, K)
#define LOGICAL_AXIS_CODE(E,V...) LINEAR_AXIS_CODE(V) CODE_ITEM_E(E) #define MAIN_AXIS_MAP(F) MAP(F, MAIN_AXIS_NAMES)
#define LOGICAL_AXIS_LIST(E,V...) LINEAR_AXIS_LIST(V) LIST_ITEM_E(E) #define STR_AXES_MAIN NUM_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K)
#define LOGICAL_AXIS_GANG(E,V...) NUM_AXIS_GANG(V) GANG_ITEM_E(E)
#define LOGICAL_AXIS_CODE(E,V...) NUM_AXIS_CODE(V) CODE_ITEM_E(E)
#define LOGICAL_AXIS_LIST(E,V...) NUM_AXIS_LIST(V) LIST_ITEM_E(E)
#define LOGICAL_AXIS_LIST_1(V) NUM_AXIS_LIST_1(V) LIST_ITEM_E(V)
#define LOGICAL_AXIS_ARRAY(E,V...) { LOGICAL_AXIS_LIST(E,V) } #define LOGICAL_AXIS_ARRAY(E,V...) { LOGICAL_AXIS_LIST(E,V) }
#define LOGICAL_AXIS_ARRAY_1(V) { LOGICAL_AXIS_LIST_1(V) }
#define LOGICAL_AXIS_ARGS(T...) LOGICAL_AXIS_LIST(T e, T x, T y, T z, T i, T j, T k) #define LOGICAL_AXIS_ARGS(T...) LOGICAL_AXIS_LIST(T e, T x, T y, T z, T i, T j, T k)
#define LOGICAL_AXIS_ELEM(O) LOGICAL_AXIS_LIST(O.e, O.x, O.y, O.z, O.i, O.j, O.k) #define LOGICAL_AXIS_ELEM(O) LOGICAL_AXIS_LIST(O.e, O.x, O.y, O.z, O.i, O.j, O.k)
#define LOGICAL_AXIS_DECL(T,V) LOGICAL_AXIS_LIST(T e=V, T x=V, T y=V, T z=V, T i=V, T j=V, T k=V) #define LOGICAL_AXIS_DECL(T,V) LOGICAL_AXIS_LIST(T e=V, T x=V, T y=V, T z=V, T i=V, T j=V, T k=V)
#define LOGICAL_AXES_STRING LOGICAL_AXIS_GANG("E", "X", "Y", "Z", STR_I, STR_J, STR_K) #define LOGICAL_AXIS_NAMES LOGICAL_AXIS_LIST(E, X, Y, Z, I, J, K)
#define LOGICAL_AXIS_MAP(F) MAP(F, LOGICAL_AXIS_NAMES)
#define STR_AXES_LOGICAL LOGICAL_AXIS_GANG("E", "X", "Y", "Z", STR_I, STR_J, STR_K)
#define XYZ_GANG(V...) GANG_N(PRIMARY_LINEAR_AXES, V)
#define XYZ_CODE(V...) CODE_N(PRIMARY_LINEAR_AXES, V)
#define SECONDARY_AXIS_GANG(V...) GANG_N(SECONDARY_AXES, V)
#define SECONDARY_AXIS_CODE(V...) CODE_N(SECONDARY_AXES, V)
#if HAS_EXTRUDERS #if HAS_EXTRUDERS
#define LIST_ITEM_E(N) , N #define LIST_ITEM_E(N) , N
@@ -81,9 +98,9 @@ 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); }
const bool operator[](const int n) const { return test(n); } const bool operator[](const int n) const { return test(n); }
const int size() const { return sizeof(b); } int size() const { return sizeof(b); }
}; };
// Specialization for a single bool flag // Specialization for a single bool flag
@@ -95,9 +112,9 @@ 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; }
const bool operator[](const int) const { return b; } bool operator[](const int) const { return b; }
const int size() const { return sizeof(b); } int size() const { return sizeof(b); }
}; };
typedef Flags<8> flags_8_t; typedef Flags<8> flags_8_t;
@@ -114,9 +131,9 @@ typedef struct AxisFlags {
void set(const int n, const bool onoff) { flags.set(n, onoff); } void set(const int n, const bool onoff) { flags.set(n, onoff); }
void clear(const int n) { flags.clear(n); } void clear(const int n) { flags.clear(n); }
bool test(const int n) const { return flags.test(n); } bool test(const int n) const { return flags.test(n); }
bool operator[](const int n) { return flags[n]; } bool operator[](const int n) { return flags[n]; }
const bool operator[](const int n) const { return flags[n]; } bool operator[](const int n) const { return flags[n]; }
const int size() const { return sizeof(flags); } int size() const { return sizeof(flags); }
} axis_flags_t; } axis_flags_t;
// //
@@ -129,7 +146,7 @@ typedef struct AxisFlags {
enum AxisEnum : uint8_t { enum AxisEnum : uint8_t {
// Linear axes may be controlled directly or indirectly // Linear axes may be controlled directly or indirectly
LINEAR_AXIS_LIST(X_AXIS, Y_AXIS, Z_AXIS, I_AXIS, J_AXIS, K_AXIS) NUM_AXIS_LIST(X_AXIS, Y_AXIS, Z_AXIS, I_AXIS, J_AXIS, K_AXIS)
// Extruder axes may be considered distinctly // Extruder axes may be considered distinctly
#define _EN_ITEM(N) , E##N##_AXIS #define _EN_ITEM(N) , E##N##_AXIS
@@ -168,7 +185,7 @@ typedef IF<(NUM_AXIS_ENUMS > 8), uint16_t, uint8_t>::type axis_bits_t;
// Loop over axes // Loop over axes
// //
#define LOOP_ABC(VAR) LOOP_S_LE_N(VAR, A_AXIS, C_AXIS) #define LOOP_ABC(VAR) LOOP_S_LE_N(VAR, A_AXIS, C_AXIS)
#define LOOP_LINEAR_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, LINEAR_AXES) #define LOOP_NUM_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, NUM_AXES)
#define LOOP_LOGICAL_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, LOGICAL_AXES) #define LOOP_LOGICAL_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, LOGICAL_AXES)
#define LOOP_DISTINCT_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, DISTINCT_AXES) #define LOOP_DISTINCT_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, DISTINCT_AXES)
#define LOOP_DISTINCT_E(VAR) LOOP_L_N(VAR, DISTINCT_E) #define LOOP_DISTINCT_E(VAR) LOOP_L_N(VAR, DISTINCT_E)
@@ -313,10 +330,10 @@ struct XYval {
FI void set(const T px, const T py) { x = px; y = py; } FI void set(const T px, const T py) { x = px; y = py; }
FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; } FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; }
#endif #endif
#if LINEAR_AXES > XY #if NUM_AXES > XY
FI void set(const T (&arr)[LINEAR_AXES]) { x = arr[0]; y = arr[1]; } FI void set(const T (&arr)[NUM_AXES]) { x = arr[0]; y = arr[1]; }
#endif #endif
#if LOGICAL_AXES > LINEAR_AXES #if LOGICAL_AXES > NUM_AXES
FI void set(const T (&arr)[LOGICAL_AXES]) { x = arr[0]; y = arr[1]; } FI void set(const T (&arr)[LOGICAL_AXES]) { x = arr[0]; y = arr[1]; }
#if DISTINCT_AXES > LOGICAL_AXES #if DISTINCT_AXES > LOGICAL_AXES
FI void set(const T (&arr)[DISTINCT_AXES]) { x = arr[0]; y = arr[1]; } FI void set(const T (&arr)[DISTINCT_AXES]) { x = arr[0]; y = arr[1]; }
@@ -438,29 +455,29 @@ struct XYval {
template<typename T> template<typename T>
struct XYZval { struct XYZval {
union { union {
struct { T LINEAR_AXIS_ARGS(); }; struct { T NUM_AXIS_ARGS(); };
struct { T LINEAR_AXIS_LIST(a, b, c, u, v, w); }; struct { T NUM_AXIS_LIST(a, b, c, _i, _j, _k); };
T pos[LINEAR_AXES]; T pos[NUM_AXES];
}; };
// Set all to 0 // Set all to 0
FI void reset() { LINEAR_AXIS_GANG(x =, y =, z =, i =, j =, k =) 0; } FI void reset() { NUM_AXIS_GANG(x =, y =, z =, i =, j =, k =) 0; }
// Setters taking struct types and arrays // Setters taking struct types and arrays
FI void set(const T px) { x = px; } FI void set(const T px) { x = px; }
FI void set(const T px, const T py) { x = px; y = py; } FI void set(const T px, const T py) { x = px; y = py; }
FI void set(const XYval<T> pxy) { x = pxy.x; y = pxy.y; } FI void set(const XYval<T> pxy) { x = pxy.x; y = pxy.y; }
FI void set(const XYval<T> pxy, const T pz) { LINEAR_AXIS_CODE(x = pxy.x, y = pxy.y, z = pz, NOOP, NOOP, NOOP); } FI void set(const XYval<T> pxy, const T pz) { NUM_AXIS_CODE(x = pxy.x, y = pxy.y, z = pz, NOOP, NOOP, NOOP); }
FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; } FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; }
#if HAS_Z_AXIS #if HAS_Z_AXIS
FI void set(const T (&arr)[LINEAR_AXES]) { LINEAR_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5]); } FI void set(const T (&arr)[NUM_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5]); }
FI void set(LINEAR_AXIS_ARGS(const T)) { LINEAR_AXIS_CODE(a = x, b = y, c = z, u = i, v = j, w = k ); } FI void set(NUM_AXIS_ARGS(const T)) { NUM_AXIS_CODE(a = x, b = y, c = z, _i = i, _j = j, _k = k); }
#endif #endif
#if LOGICAL_AXES > LINEAR_AXES #if LOGICAL_AXES > NUM_AXES
FI void set(const T (&arr)[LOGICAL_AXES]) { LINEAR_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5]); } FI void set(const T (&arr)[LOGICAL_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5]); }
FI void set(LOGICAL_AXIS_ARGS(const T)) { LINEAR_AXIS_CODE(a = x, b = y, c = z, u = i, v = j, w = k ); } FI void set(LOGICAL_AXIS_ARGS(const T)) { NUM_AXIS_CODE(a = x, b = y, c = z, _i = i, _j = j, _k = k); }
#if DISTINCT_AXES > LOGICAL_AXES #if DISTINCT_AXES > LOGICAL_AXES
FI void set(const T (&arr)[DISTINCT_AXES]) { LINEAR_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5]); } FI void set(const T (&arr)[DISTINCT_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5]); }
#endif #endif
#endif #endif
#if HAS_I_AXIS #if HAS_I_AXIS
@@ -474,24 +491,24 @@ struct XYZval {
#endif #endif
// Length reduced to one dimension // Length reduced to one dimension
FI T magnitude() const { return (T)sqrtf(LINEAR_AXIS_GANG(x*x, + y*y, + z*z, + i*i, + j*j, + k*k)); } FI T magnitude() const { return (T)sqrtf(NUM_AXIS_GANG(x*x, + y*y, + z*z, + i*i, + j*j, + k*k)); }
// Pointer to the data as a simple array // Pointer to the data as a simple array
FI operator T* () { return pos; } FI operator T* () { return pos; }
// If any element is true then it's true // If any element is true then it's true
FI operator bool() { return LINEAR_AXIS_GANG(x, || y, || z, || i, || j, || k); } FI operator bool() { return NUM_AXIS_GANG(x, || y, || z, || i, || j, || k); }
// Explicit copy and copies with conversion // Explicit copy and copies with conversion
FI XYZval<T> copy() const { XYZval<T> o = *this; return o; } FI XYZval<T> copy() const { XYZval<T> o = *this; return o; }
FI XYZval<T> ABS() const { return LINEAR_AXIS_ARRAY(T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(i)), T(_ABS(j)), T(_ABS(k))); } FI XYZval<T> ABS() const { return NUM_AXIS_ARRAY(T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(i)), T(_ABS(j)), T(_ABS(k))); }
FI XYZval<int16_t> asInt() { return LINEAR_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k)); } FI XYZval<int16_t> asInt() { return NUM_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k)); }
FI XYZval<int16_t> asInt() const { return LINEAR_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k)); } FI XYZval<int16_t> asInt() const { return NUM_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k)); }
FI XYZval<int32_t> asLong() { return LINEAR_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k)); } FI XYZval<int32_t> asLong() { return NUM_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k)); }
FI XYZval<int32_t> asLong() const { return LINEAR_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k)); } FI XYZval<int32_t> asLong() const { return NUM_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k)); }
FI XYZval<int32_t> ROUNDL() { return LINEAR_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k))); } FI XYZval<int32_t> ROUNDL() { return NUM_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k))); }
FI XYZval<int32_t> ROUNDL() const { return LINEAR_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k))); } FI XYZval<int32_t> ROUNDL() const { return NUM_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k))); }
FI XYZval<float> asFloat() { return LINEAR_AXIS_ARRAY(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(i), static_cast<float>(j), static_cast<float>(k)); } FI XYZval<float> asFloat() { return NUM_AXIS_ARRAY(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(i), static_cast<float>(j), static_cast<float>(k)); }
FI XYZval<float> asFloat() const { return LINEAR_AXIS_ARRAY(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(i), static_cast<float>(j), static_cast<float>(k)); } FI XYZval<float> asFloat() const { return NUM_AXIS_ARRAY(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(i), static_cast<float>(j), static_cast<float>(k)); }
FI XYZval<float> reciprocal() const { return LINEAR_AXIS_ARRAY(_RECIP(x), _RECIP(y), _RECIP(z), _RECIP(i), _RECIP(j), _RECIP(k)); } FI XYZval<float> reciprocal() const { return NUM_AXIS_ARRAY(_RECIP(x), _RECIP(y), _RECIP(z), _RECIP(i), _RECIP(j), _RECIP(k)); }
// Marlin workspace shifting is done with G92 and M206 // Marlin workspace shifting is done with G92 and M206
FI XYZval<float> asLogical() const { XYZval<float> o = asFloat(); toLogical(o); return o; } FI XYZval<float> asLogical() const { XYZval<float> o = asFloat(); toLogical(o); return o; }
@@ -502,78 +519,78 @@ struct XYZval {
FI operator const XYval<T>&() const { return *(const XYval<T>*)this; } FI operator const XYval<T>&() const { return *(const XYval<T>*)this; }
// Cast to a type with more fields by making a new object // Cast to a type with more fields by making a new object
FI operator XYZEval<T>() const { return LINEAR_AXIS_ARRAY(x, y, z, i, j, k); } FI operator XYZEval<T>() const { return NUM_AXIS_ARRAY(x, y, z, i, j, k); }
// Accessor via an AxisEnum (or any integer) [index] // Accessor via an AxisEnum (or any integer) [index]
FI T& operator[](const int n) { return pos[n]; } FI T& operator[](const int n) { return pos[n]; }
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 XYZval<T>& operator= (const T v) { set(ARRAY_N_1(LINEAR_AXES, v)); return *this; } FI XYZval<T>& operator= (const T v) { set(ARRAY_N_1(NUM_AXES, v)); return *this; }
FI XYZval<T>& operator= (const XYval<T> &rs) { set(rs.x, rs.y ); return *this; } FI XYZval<T>& operator= (const XYval<T> &rs) { set(rs.x, rs.y ); return *this; }
FI XYZval<T>& operator= (const XYZEval<T> &rs) { set(LINEAR_AXIS_ELEM(rs)); return *this; } FI XYZval<T>& operator= (const XYZEval<T> &rs) { set(NUM_AXIS_ELEM(rs)); return *this; }
// Override other operators to get intuitive behaviors // Override other operators to get intuitive behaviors
FI XYZval<T> operator+ (const XYval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } FI XYZval<T> operator+ (const XYval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; }
FI XYZval<T> operator+ (const XYval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } FI XYZval<T> operator+ (const XYval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; }
FI XYZval<T> operator- (const XYval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } FI XYZval<T> operator- (const XYval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; }
FI XYZval<T> operator- (const XYval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } FI XYZval<T> operator- (const XYval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; }
FI XYZval<T> operator* (const XYval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } FI XYZval<T> operator* (const XYval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; }
FI XYZval<T> operator* (const XYval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } FI XYZval<T> operator* (const XYval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; }
FI XYZval<T> operator/ (const XYval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } FI XYZval<T> operator/ (const XYval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; }
FI XYZval<T> operator/ (const XYval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } FI XYZval<T> operator/ (const XYval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; }
FI XYZval<T> operator+ (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } FI XYZval<T> operator+ (const XYZval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; }
FI XYZval<T> operator+ (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } FI XYZval<T> operator+ (const XYZval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; }
FI XYZval<T> operator- (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } FI XYZval<T> operator- (const XYZval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; }
FI XYZval<T> operator- (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } FI XYZval<T> operator- (const XYZval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; }
FI XYZval<T> operator* (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } FI XYZval<T> operator* (const XYZval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; }
FI XYZval<T> operator* (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } FI XYZval<T> operator* (const XYZval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; }
FI XYZval<T> operator/ (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } FI XYZval<T> operator/ (const XYZval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; }
FI XYZval<T> operator/ (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } FI XYZval<T> operator/ (const XYZval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; }
FI XYZval<T> operator+ (const XYZEval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } FI XYZval<T> operator+ (const XYZEval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; }
FI XYZval<T> operator+ (const XYZEval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } FI XYZval<T> operator+ (const XYZEval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; }
FI XYZval<T> operator- (const XYZEval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } FI XYZval<T> operator- (const XYZEval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; }
FI XYZval<T> operator- (const XYZEval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } FI XYZval<T> operator- (const XYZEval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; }
FI XYZval<T> operator* (const XYZEval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } FI XYZval<T> operator* (const XYZEval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; }
FI XYZval<T> operator* (const XYZEval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } FI XYZval<T> operator* (const XYZEval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; }
FI XYZval<T> operator/ (const XYZEval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } FI XYZval<T> operator/ (const XYZEval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; }
FI XYZval<T> operator/ (const XYZEval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } FI XYZval<T> operator/ (const XYZEval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; }
FI XYZval<T> operator* (const float &v) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; } FI XYZval<T> operator* (const float &v) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; }
FI XYZval<T> operator* (const float &v) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; } FI XYZval<T> operator* (const float &v) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; }
FI XYZval<T> operator* (const int &v) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; } FI XYZval<T> operator* (const int &v) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; }
FI XYZval<T> operator* (const int &v) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; } FI XYZval<T> operator* (const int &v) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; }
FI XYZval<T> operator/ (const float &v) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; } FI XYZval<T> operator/ (const float &v) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; }
FI XYZval<T> operator/ (const float &v) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; } FI XYZval<T> operator/ (const float &v) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; }
FI XYZval<T> operator/ (const int &v) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; } FI XYZval<T> operator/ (const int &v) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; }
FI XYZval<T> operator/ (const int &v) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; } FI XYZval<T> operator/ (const int &v) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; }
FI XYZval<T> operator>>(const int &v) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(_RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k) ); return ls; } FI XYZval<T> operator>>(const int &v) const { XYZval<T> ls = *this; NUM_AXIS_CODE(_RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k) ); return ls; }
FI XYZval<T> operator>>(const int &v) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(_RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k) ); return ls; } FI XYZval<T> operator>>(const int &v) { XYZval<T> ls = *this; NUM_AXIS_CODE(_RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k) ); return ls; }
FI XYZval<T> operator<<(const int &v) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(_LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k) ); return ls; } FI XYZval<T> operator<<(const int &v) const { XYZval<T> ls = *this; NUM_AXIS_CODE(_LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k) ); return ls; }
FI XYZval<T> operator<<(const int &v) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(_LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k) ); return ls; } FI XYZval<T> operator<<(const int &v) { XYZval<T> ls = *this; NUM_AXIS_CODE(_LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k) ); return ls; }
FI const XYZval<T> operator-() const { XYZval<T> o = *this; LINEAR_AXIS_CODE(o.x = -x, o.y = -y, o.z = -z, o.i = -i, o.j = -j, o.k = -k); return o; } FI const XYZval<T> operator-() const { XYZval<T> o = *this; NUM_AXIS_CODE(o.x = -x, o.y = -y, o.z = -z, o.i = -i, o.j = -j, o.k = -k); return o; }
FI XYZval<T> operator-() { XYZval<T> o = *this; LINEAR_AXIS_CODE(o.x = -x, o.y = -y, o.z = -z, o.i = -i, o.j = -j, o.k = -k); return o; } FI XYZval<T> operator-() { XYZval<T> o = *this; NUM_AXIS_CODE(o.x = -x, o.y = -y, o.z = -z, o.i = -i, o.j = -j, o.k = -k); return o; }
// Modifier operators // Modifier operators
FI XYZval<T>& operator+=(const XYval<T> &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, NOOP, NOOP, NOOP, NOOP ); return *this; } FI XYZval<T>& operator+=(const XYval<T> &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, NOOP, NOOP, NOOP, NOOP ); return *this; }
FI XYZval<T>& operator-=(const XYval<T> &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, NOOP, NOOP, NOOP, NOOP ); return *this; } FI XYZval<T>& operator-=(const XYval<T> &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, NOOP, NOOP, NOOP, NOOP ); return *this; }
FI XYZval<T>& operator*=(const XYval<T> &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, NOOP, NOOP, NOOP, NOOP ); return *this; } FI XYZval<T>& operator*=(const XYval<T> &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, NOOP, NOOP, NOOP, NOOP ); return *this; }
FI XYZval<T>& operator/=(const XYval<T> &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, NOOP, NOOP, NOOP, NOOP ); return *this; } FI XYZval<T>& operator/=(const XYval<T> &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, NOOP, NOOP, NOOP, NOOP ); return *this; }
FI XYZval<T>& operator+=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k); return *this; } FI XYZval<T>& operator+=(const XYZval<T> &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k); return *this; }
FI XYZval<T>& operator-=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k); return *this; } FI XYZval<T>& operator-=(const XYZval<T> &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k); return *this; }
FI XYZval<T>& operator*=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k); return *this; } FI XYZval<T>& operator*=(const XYZval<T> &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k); return *this; }
FI XYZval<T>& operator/=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k); return *this; } FI XYZval<T>& operator/=(const XYZval<T> &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k); return *this; }
FI XYZval<T>& operator+=(const XYZEval<T> &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k); return *this; } FI XYZval<T>& operator+=(const XYZEval<T> &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k); return *this; }
FI XYZval<T>& operator-=(const XYZEval<T> &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k); return *this; } FI XYZval<T>& operator-=(const XYZEval<T> &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k); return *this; }
FI XYZval<T>& operator*=(const XYZEval<T> &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k); return *this; } FI XYZval<T>& operator*=(const XYZEval<T> &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k); return *this; }
FI XYZval<T>& operator/=(const XYZEval<T> &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k); return *this; } FI XYZval<T>& operator/=(const XYZEval<T> &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k); return *this; }
FI XYZval<T>& operator*=(const float &v) { LINEAR_AXIS_CODE(x *= v, y *= v, z *= v, i *= v, j *= v, k *= v); return *this; } FI XYZval<T>& operator*=(const float &v) { NUM_AXIS_CODE(x *= v, y *= v, z *= v, i *= v, j *= v, k *= v); return *this; }
FI XYZval<T>& operator*=(const int &v) { LINEAR_AXIS_CODE(x *= v, y *= v, z *= v, i *= v, j *= v, k *= v); return *this; } FI XYZval<T>& operator*=(const int &v) { NUM_AXIS_CODE(x *= v, y *= v, z *= v, i *= v, j *= v, k *= v); return *this; }
FI XYZval<T>& operator>>=(const int &v) { LINEAR_AXIS_CODE(_RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k)); return *this; } FI XYZval<T>& operator>>=(const int &v) { NUM_AXIS_CODE(_RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k)); return *this; }
FI XYZval<T>& operator<<=(const int &v) { LINEAR_AXIS_CODE(_LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k)); return *this; } FI XYZval<T>& operator<<=(const int &v) { NUM_AXIS_CODE(_LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k)); return *this; }
// Exact comparisons. For floats a "NEAR" operation may be better. // Exact comparisons. For floats a "NEAR" operation may be better.
FI bool operator==(const XYZEval<T> &rs) { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k); } FI bool operator==(const XYZEval<T> &rs) { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k); }
FI bool operator==(const XYZEval<T> &rs) const { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k); } FI bool operator==(const XYZEval<T> &rs) const { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k); }
FI bool operator!=(const XYZEval<T> &rs) { return !operator==(rs); } FI bool operator!=(const XYZEval<T> &rs) { return !operator==(rs); }
FI bool operator!=(const XYZEval<T> &rs) const { return !operator==(rs); } FI bool operator!=(const XYZEval<T> &rs) const { return !operator==(rs); }
}; };
@@ -585,7 +602,7 @@ template<typename T>
struct XYZEval { struct XYZEval {
union { union {
struct { T LOGICAL_AXIS_ARGS(); }; struct { T LOGICAL_AXIS_ARGS(); };
struct { T LOGICAL_AXIS_LIST(_e, a, b, c, u, v, w); }; struct { T LOGICAL_AXIS_LIST(_e, a, b, c, _i, _j, _k); };
T pos[LOGICAL_AXES]; T pos[LOGICAL_AXES];
}; };
// Reset all to 0 // Reset all to 0
@@ -605,15 +622,15 @@ struct XYZEval {
#endif #endif
// Setters taking struct types and arrays // Setters taking struct types and arrays
FI void set(const XYval<T> pxy) { x = pxy.x; y = pxy.y; } FI void set(const XYval<T> pxy) { x = pxy.x; y = pxy.y; }
FI void set(const XYZval<T> pxyz) { set(LINEAR_AXIS_ELEM(pxyz)); } FI void set(const XYZval<T> pxyz) { set(NUM_AXIS_ELEM(pxyz)); }
#if HAS_Z_AXIS #if HAS_Z_AXIS
FI void set(LINEAR_AXIS_ARGS(const T)) { LINEAR_AXIS_CODE(a = x, b = y, c = z, u = i, v = j, w = k); } FI void set(NUM_AXIS_ARGS(const T)) { NUM_AXIS_CODE(a = x, b = y, c = z, _i = i, _j = j, _k = k); }
#endif #endif
FI void set(const XYval<T> pxy, const T pz) { set(pxy); TERN_(HAS_Z_AXIS, z = pz); } FI void set(const XYval<T> pxy, const T pz) { set(pxy); TERN_(HAS_Z_AXIS, z = pz); }
#if LOGICAL_AXES > LINEAR_AXES #if LOGICAL_AXES > NUM_AXES
FI void set(const XYval<T> pxy, const T pz, const T pe) { set(pxy, pz); e = pe; } FI void set(const XYval<T> pxy, const T pz, const T pe) { set(pxy, pz); e = pe; }
FI void set(const XYZval<T> pxyz, const T pe) { set(pxyz); e = pe; } FI void set(const XYZval<T> pxyz, const T pe) { set(pxyz); e = pe; }
FI void set(LOGICAL_AXIS_ARGS(const T)) { LOGICAL_AXIS_CODE(_e = e, a = x, b = y, c = z, u = i, v = j, w = k); } FI void set(LOGICAL_AXIS_ARGS(const T)) { LOGICAL_AXIS_CODE(_e = e, a = x, b = y, c = z, _i = i, _j = j, _k = k); }
#endif #endif
// Length reduced to one dimension // Length reduced to one dimension
@@ -651,9 +668,9 @@ 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(LINEAR_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(LINEAR_AXIS_ELEM(rs)); return *this; } FI XYZEval<T>& operator= (const XYZval<T> &rs) { set(NUM_AXIS_ELEM(rs)); return *this; }
// Override other operators to get intuitive behaviors // Override other operators to get intuitive behaviors
FI XYZEval<T> operator+ (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } FI XYZEval<T> operator+ (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
@@ -664,14 +681,14 @@ struct XYZEval {
FI XYZEval<T> operator* (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } FI XYZEval<T> operator* (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
FI XYZEval<T> operator/ (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } FI XYZEval<T> operator/ (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
FI XYZEval<T> operator/ (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } FI XYZEval<T> operator/ (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
FI XYZEval<T> operator+ (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } FI XYZEval<T> operator+ (const XYZval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; }
FI XYZEval<T> operator+ (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } FI XYZEval<T> operator+ (const XYZval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; }
FI XYZEval<T> operator- (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } FI XYZEval<T> operator- (const XYZval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; }
FI XYZEval<T> operator- (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } FI XYZEval<T> operator- (const XYZval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; }
FI XYZEval<T> operator* (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } FI XYZEval<T> operator* (const XYZval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; }
FI XYZEval<T> operator* (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } FI XYZEval<T> operator* (const XYZval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; }
FI XYZEval<T> operator/ (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } FI XYZEval<T> operator/ (const XYZval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; }
FI XYZEval<T> operator/ (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } FI XYZEval<T> operator/ (const XYZval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; }
FI XYZEval<T> operator+ (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e += rs.e, ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } FI XYZEval<T> operator+ (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e += rs.e, ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; }
FI XYZEval<T> operator+ (const XYZEval<T> &rs) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e += rs.e, ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } FI XYZEval<T> operator+ (const XYZEval<T> &rs) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e += rs.e, ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; }
FI XYZEval<T> operator- (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e -= rs.e, ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } FI XYZEval<T> operator- (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e -= rs.e, ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; }
@@ -700,10 +717,10 @@ struct XYZEval {
FI XYZEval<T>& operator-=(const XYval<T> &rs) { x -= rs.x; y -= rs.y; return *this; } FI XYZEval<T>& operator-=(const XYval<T> &rs) { x -= rs.x; y -= rs.y; return *this; }
FI XYZEval<T>& operator*=(const XYval<T> &rs) { x *= rs.x; y *= rs.y; return *this; } FI XYZEval<T>& operator*=(const XYval<T> &rs) { x *= rs.x; y *= rs.y; return *this; }
FI XYZEval<T>& operator/=(const XYval<T> &rs) { x /= rs.x; y /= rs.y; return *this; } FI XYZEval<T>& operator/=(const XYval<T> &rs) { x /= rs.x; y /= rs.y; return *this; }
FI XYZEval<T>& operator+=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k); return *this; } FI XYZEval<T>& operator+=(const XYZval<T> &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k); return *this; }
FI XYZEval<T>& operator-=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k); return *this; } FI XYZEval<T>& operator-=(const XYZval<T> &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k); return *this; }
FI XYZEval<T>& operator*=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k); return *this; } FI XYZEval<T>& operator*=(const XYZval<T> &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k); return *this; }
FI XYZEval<T>& operator/=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k); return *this; } FI XYZEval<T>& operator/=(const XYZval<T> &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k); return *this; }
FI XYZEval<T>& operator+=(const XYZEval<T> &rs) { LOGICAL_AXIS_CODE(e += rs.e, x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k); return *this; } FI XYZEval<T>& operator+=(const XYZEval<T> &rs) { LOGICAL_AXIS_CODE(e += rs.e, x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k); return *this; }
FI XYZEval<T>& operator-=(const XYZEval<T> &rs) { LOGICAL_AXIS_CODE(e -= rs.e, x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k); return *this; } FI XYZEval<T>& operator-=(const XYZEval<T> &rs) { LOGICAL_AXIS_CODE(e -= rs.e, x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k); return *this; }
FI XYZEval<T>& operator*=(const XYZEval<T> &rs) { LOGICAL_AXIS_CODE(e *= rs.e, x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k); return *this; } FI XYZEval<T>& operator*=(const XYZEval<T> &rs) { LOGICAL_AXIS_CODE(e *= rs.e, x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k); return *this; }
@@ -713,8 +730,8 @@ struct XYZEval {
FI XYZEval<T>& operator<<=(const int &v) { LOGICAL_AXIS_CODE(_LS(e), _LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k)); return *this; } FI XYZEval<T>& operator<<=(const int &v) { LOGICAL_AXIS_CODE(_LS(e), _LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k)); return *this; }
// Exact comparisons. For floats a "NEAR" operation may be better. // Exact comparisons. For floats a "NEAR" operation may be better.
FI bool operator==(const XYZval<T> &rs) { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k); } FI bool operator==(const XYZval<T> &rs) { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k); }
FI bool operator==(const XYZval<T> &rs) const { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k); } FI bool operator==(const XYZval<T> &rs) const { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k); }
FI bool operator!=(const XYZval<T> &rs) { return !operator==(rs); } FI bool operator!=(const XYZval<T> &rs) { return !operator==(rs); }
FI bool operator!=(const XYZval<T> &rs) const { return !operator==(rs); } FI bool operator!=(const XYZval<T> &rs) const { return !operator==(rs); }
}; };

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"
@@ -125,18 +125,17 @@ void safe_delay(millis_t ms) {
#endif #endif
#if ABL_PLANAR #if ABL_PLANAR
SERIAL_ECHOPGM("ABL Adjustment"); SERIAL_ECHOPGM("ABL Adjustment");
LOOP_LINEAR_AXES(a) { LOOP_NUM_AXES(a) {
SERIAL_CHAR(' ', AXIS_CHAR(a)); SERIAL_ECHOPGM_P((PGM_P)pgm_read_ptr(&SP_AXIS_STR[a]));
serial_offset(planner.get_axis_position_mm(AxisEnum(a)) - current_position[a]); serial_offset(planner.get_axis_position_mm(AxisEnum(a)) - current_position[a]);
} }
#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 +155,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_;
@@ -77,10 +82,13 @@ public:
// in the range 0-100 while avoiding rounding artifacts // in the range 0-100 while avoiding rounding artifacts
constexpr uint8_t ui8_to_percent(const uint8_t i) { return (int(i) * 100 + 127) / 255; } constexpr uint8_t ui8_to_percent(const uint8_t i) { return (int(i) * 100 + 127) / 255; }
// Axis names for G-code parsing, reports, etc.
const xyze_char_t axis_codes LOGICAL_AXIS_ARRAY('E', 'X', 'Y', 'Z', AXIS4_NAME, AXIS5_NAME, AXIS6_NAME); const xyze_char_t axis_codes LOGICAL_AXIS_ARRAY('E', 'X', 'Y', 'Z', AXIS4_NAME, AXIS5_NAME, AXIS6_NAME);
#if NUM_AXES <= XYZ && !HAS_EXTRUDERS
#if LINEAR_AXES <= XYZ
#define AXIS_CHAR(A) ((char)('X' + A)) #define AXIS_CHAR(A) ((char)('X' + A))
#define IAXIS_CHAR AXIS_CHAR
#else #else
const xyze_char_t iaxis_codes LOGICAL_AXIS_ARRAY('E', 'X', 'Y', 'Z', 'I', 'J', 'K');
#define AXIS_CHAR(A) axis_codes[A] #define AXIS_CHAR(A) axis_codes[A]
#define IAXIS_CHAR(A) iaxis_codes[A]
#endif #endif

View File

@@ -97,7 +97,7 @@ void Backlash::add_correction_steps(const int32_t &da, const int32_t &db, const
const float f_corr = float(correction) / all_on; const float f_corr = float(correction) / all_on;
LOOP_LINEAR_AXES(axis) { LOOP_NUM_AXES(axis) {
if (distance_mm[axis]) { if (distance_mm[axis]) {
const bool reverse = TEST(dm, axis); const bool reverse = TEST(dm, axis);
@@ -145,7 +145,7 @@ void Backlash::add_correction_steps(const int32_t &da, const int32_t &db, const
} }
int32_t Backlash::get_applied_steps(const AxisEnum axis) { int32_t Backlash::get_applied_steps(const AxisEnum axis) {
if (axis >= LINEAR_AXES) return 0; if (axis >= NUM_AXES) return 0;
const bool reverse = TEST(last_direction_bits, axis); const bool reverse = TEST(last_direction_bits, axis);
@@ -162,32 +162,37 @@ int32_t Backlash::get_applied_steps(const AxisEnum axis) {
} }
class Backlash::StepAdjuster { class Backlash::StepAdjuster {
xyz_long_t applied_steps; private:
public: xyz_long_t applied_steps;
StepAdjuster() { public:
LOOP_LINEAR_AXES(axis) applied_steps[axis] = backlash.get_applied_steps((AxisEnum)axis); StepAdjuster() {
} LOOP_NUM_AXES(axis) applied_steps[axis] = backlash.get_applied_steps((AxisEnum)axis);
~StepAdjuster() { }
// after backlash compensation parameter changes, ensure applied step count does not change ~StepAdjuster() {
LOOP_LINEAR_AXES(axis) residual_error[axis] += backlash.get_applied_steps((AxisEnum)axis) - applied_steps[axis]; // after backlash compensation parameter changes, ensure applied step count does not change
} LOOP_NUM_AXES(axis) residual_error[axis] += backlash.get_applied_steps((AxisEnum)axis) - applied_steps[axis];
}
}; };
void Backlash::set_correction_uint8(const uint8_t v) { #if ENABLED(BACKLASH_GCODE)
StepAdjuster adjuster;
correction = v;
}
void Backlash::set_distance_mm(const AxisEnum axis, const float v) { void Backlash::set_correction_uint8(const uint8_t v) {
StepAdjuster adjuster;
distance_mm[axis] = v;
}
#ifdef BACKLASH_SMOOTHING_MM
void Backlash::set_smoothing_mm(const float v) {
StepAdjuster adjuster; StepAdjuster adjuster;
smoothing_mm = v; correction = v;
} }
void Backlash::set_distance_mm(const AxisEnum axis, const float v) {
StepAdjuster adjuster;
distance_mm[axis] = v;
}
#ifdef BACKLASH_SMOOTHING_MM
void Backlash::set_smoothing_mm(const float v) {
StepAdjuster adjuster;
smoothing_mm = v;
}
#endif
#endif #endif
#if ENABLED(MEASURE_BACKLASH_WHEN_PROBING) #if ENABLED(MEASURE_BACKLASH_WHEN_PROBING)

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

@@ -59,7 +59,7 @@ int StepperDAC::init() {
} }
void StepperDAC::set_current_value(const uint8_t channel, uint16_t val) { void StepperDAC::set_current_value(const uint8_t channel, uint16_t val) {
if (!dac_present) return; if (!(dac_present && channel < LOGICAL_AXES)) return;
NOMORE(val, uint16_t(DAC_STEPPER_MAX)); NOMORE(val, uint16_t(DAC_STEPPER_MAX));
@@ -84,13 +84,11 @@ void StepperDAC::print_values() {
if (!dac_present) return; if (!dac_present) return;
SERIAL_ECHO_MSG("Stepper current values in % (Amps):"); SERIAL_ECHO_MSG("Stepper current values in % (Amps):");
SERIAL_ECHO_START(); SERIAL_ECHO_START();
SERIAL_ECHOPGM_P(SP_X_LBL, dac_perc(X_AXIS), PSTR(" ("), dac_amps(X_AXIS), PSTR(")")); LOOP_LOGICAL_AXES(a) {
#if HAS_Y_AXIS SERIAL_CHAR(' ', IAXIS_CHAR(a), ':');
SERIAL_ECHOPGM_P(SP_Y_LBL, dac_perc(Y_AXIS), PSTR(" ("), dac_amps(Y_AXIS), PSTR(")")); SERIAL_ECHO(dac_perc(a));
#endif SERIAL_ECHOPGM_P(PSTR(" ("), dac_amps(AxisEnum(a)), PSTR(")"));
#if HAS_Z_AXIS }
SERIAL_ECHOPGM_P(SP_Z_LBL, dac_perc(Z_AXIS), PSTR(" ("), dac_amps(Z_AXIS), PSTR(")"));
#endif
#if HAS_EXTRUDERS #if HAS_EXTRUDERS
SERIAL_ECHOLNPGM_P(SP_E_LBL, dac_perc(E_AXIS), PSTR(" ("), dac_amps(E_AXIS), PSTR(")")); SERIAL_ECHOLNPGM_P(SP_E_LBL, dac_perc(E_AXIS), PSTR(" ("), dac_amps(E_AXIS), PSTR(")"));
#endif #endif

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

@@ -49,7 +49,7 @@ void I2CPositionEncoder::init(const uint8_t address, const AxisEnum axis) {
initialized = true; initialized = true;
SERIAL_ECHOLNPGM("Setting up encoder on ", AS_CHAR(axis_codes[encoderAxis]), " axis, addr = ", address); SERIAL_ECHOLNPGM("Setting up encoder on ", AS_CHAR(AXIS_CHAR(encoderAxis)), " axis, addr = ", address);
position = get_position(); position = get_position();
} }
@@ -67,7 +67,7 @@ void I2CPositionEncoder::update() {
/* /*
if (trusted) { //commented out as part of the note below if (trusted) { //commented out as part of the note below
trusted = false; trusted = false;
SERIAL_ECHOLNPGM("Fault detected on ", AS_CHAR(axis_codes[encoderAxis]), " axis encoder. Disengaging error correction until module is trusted again."); SERIAL_ECHOLNPGM("Fault detected on ", AS_CHAR(AXIS_CHAR(encoderAxis)), " axis encoder. Disengaging error correction until module is trusted again.");
} }
*/ */
return; return;
@@ -92,7 +92,7 @@ void I2CPositionEncoder::update() {
if (millis() - lastErrorTime > I2CPE_TIME_TRUSTED) { if (millis() - lastErrorTime > I2CPE_TIME_TRUSTED) {
trusted = true; trusted = true;
SERIAL_ECHOLNPGM("Untrusted encoder module on ", AS_CHAR(axis_codes[encoderAxis]), " axis has been fault-free for set duration, reinstating error correction."); SERIAL_ECHOLNPGM("Untrusted encoder module on ", AS_CHAR(AXIS_CHAR(encoderAxis)), " axis has been fault-free for set duration, reinstating error correction.");
//the encoder likely lost its place when the error occurred, so we'll reset and use the printer's //the encoder likely lost its place when the error occurred, so we'll reset and use the printer's
//idea of where it the axis is to re-initialize //idea of where it the axis is to re-initialize
@@ -172,7 +172,7 @@ void I2CPositionEncoder::update() {
float sumP = 0; float sumP = 0;
LOOP_L_N(i, I2CPE_ERR_PRST_ARRAY_SIZE) sumP += errPrst[i]; LOOP_L_N(i, I2CPE_ERR_PRST_ARRAY_SIZE) sumP += errPrst[i];
const int32_t errorP = int32_t(sumP * RECIPROCAL(I2CPE_ERR_PRST_ARRAY_SIZE)); const int32_t errorP = int32_t(sumP * RECIPROCAL(I2CPE_ERR_PRST_ARRAY_SIZE));
SERIAL_CHAR(axis_codes[encoderAxis]); SERIAL_CHAR(AXIS_CHAR(encoderAxis));
SERIAL_ECHOLNPGM(" : CORRECT ERR ", errorP * planner.mm_per_step[encoderAxis], "mm"); SERIAL_ECHOLNPGM(" : CORRECT ERR ", errorP * planner.mm_per_step[encoderAxis], "mm");
babystep.add_steps(encoderAxis, -LROUND(errorP)); babystep.add_steps(encoderAxis, -LROUND(errorP));
errPrstIdx = 0; errPrstIdx = 0;
@@ -192,7 +192,7 @@ void I2CPositionEncoder::update() {
if (ABS(error) > I2CPE_ERR_CNT_THRESH * planner.settings.axis_steps_per_mm[encoderAxis]) { if (ABS(error) > I2CPE_ERR_CNT_THRESH * planner.settings.axis_steps_per_mm[encoderAxis]) {
const millis_t ms = millis(); const millis_t ms = millis();
if (ELAPSED(ms, nextErrorCountTime)) { if (ELAPSED(ms, nextErrorCountTime)) {
SERIAL_CHAR(axis_codes[encoderAxis]); SERIAL_CHAR(AXIS_CHAR(encoderAxis));
SERIAL_ECHOLNPGM(" : LARGE ERR ", error, "; diffSum=", diffSum); SERIAL_ECHOLNPGM(" : LARGE ERR ", error, "; diffSum=", diffSum);
errorCount++; errorCount++;
nextErrorCountTime = ms + I2CPE_ERR_CNT_DEBOUNCE_MS; nextErrorCountTime = ms + I2CPE_ERR_CNT_DEBOUNCE_MS;
@@ -212,7 +212,7 @@ void I2CPositionEncoder::set_homed() {
homed = trusted = true; homed = trusted = true;
#ifdef I2CPE_DEBUG #ifdef I2CPE_DEBUG
SERIAL_CHAR(axis_codes[encoderAxis]); SERIAL_CHAR(AXIS_CHAR(encoderAxis));
SERIAL_ECHOLNPGM(" axis encoder homed, offset of ", zeroOffset, " ticks."); SERIAL_ECHOLNPGM(" axis encoder homed, offset of ", zeroOffset, " ticks.");
#endif #endif
} }
@@ -223,7 +223,7 @@ void I2CPositionEncoder::set_unhomed() {
homed = trusted = false; homed = trusted = false;
#ifdef I2CPE_DEBUG #ifdef I2CPE_DEBUG
SERIAL_CHAR(axis_codes[encoderAxis]); SERIAL_CHAR(AXIS_CHAR(encoderAxis));
SERIAL_ECHOLNPGM(" axis encoder unhomed."); SERIAL_ECHOLNPGM(" axis encoder unhomed.");
#endif #endif
} }
@@ -231,7 +231,7 @@ void I2CPositionEncoder::set_unhomed() {
bool I2CPositionEncoder::passes_test(const bool report) { bool I2CPositionEncoder::passes_test(const bool report) {
if (report) { if (report) {
if (H != I2CPE_MAG_SIG_GOOD) SERIAL_ECHOPGM("Warning. "); if (H != I2CPE_MAG_SIG_GOOD) SERIAL_ECHOPGM("Warning. ");
SERIAL_CHAR(axis_codes[encoderAxis]); SERIAL_CHAR(AXIS_CHAR(encoderAxis));
serial_ternary(H == I2CPE_MAG_SIG_BAD, F(" axis "), F("magnetic strip "), F("encoder ")); serial_ternary(H == I2CPE_MAG_SIG_BAD, F(" axis "), F("magnetic strip "), F("encoder "));
switch (H) { switch (H) {
case I2CPE_MAG_SIG_GOOD: case I2CPE_MAG_SIG_GOOD:
@@ -252,7 +252,7 @@ float I2CPositionEncoder::get_axis_error_mm(const bool report) {
error = ABS(diff) > 10000 ? 0 : diff; // Huge error is a bad reading error = ABS(diff) > 10000 ? 0 : diff; // Huge error is a bad reading
if (report) { if (report) {
SERIAL_CHAR(axis_codes[encoderAxis]); SERIAL_CHAR(AXIS_CHAR(encoderAxis));
SERIAL_ECHOLNPGM(" axis target=", target, "mm; actual=", actual, "mm; err=", error, "mm"); SERIAL_ECHOLNPGM(" axis target=", target, "mm; actual=", actual, "mm; err=", error, "mm");
} }
@@ -262,7 +262,7 @@ float I2CPositionEncoder::get_axis_error_mm(const bool report) {
int32_t I2CPositionEncoder::get_axis_error_steps(const bool report) { int32_t I2CPositionEncoder::get_axis_error_steps(const bool report) {
if (!active) { if (!active) {
if (report) { if (report) {
SERIAL_CHAR(axis_codes[encoderAxis]); SERIAL_CHAR(AXIS_CHAR(encoderAxis));
SERIAL_ECHOLNPGM(" axis encoder not active!"); SERIAL_ECHOLNPGM(" axis encoder not active!");
} }
return 0; return 0;
@@ -287,7 +287,7 @@ int32_t I2CPositionEncoder::get_axis_error_steps(const bool report) {
errorPrev = error; errorPrev = error;
if (report) { if (report) {
SERIAL_CHAR(axis_codes[encoderAxis]); SERIAL_CHAR(AXIS_CHAR(encoderAxis));
SERIAL_ECHOLNPGM(" axis target=", target, "; actual=", encoderCountInStepperTicksScaled, "; err=", error); SERIAL_ECHOLNPGM(" axis target=", target, "; actual=", encoderCountInStepperTicksScaled, "; err=", error);
} }
@@ -337,7 +337,7 @@ bool I2CPositionEncoder::test_axis() {
ec = false; ec = false;
xyze_pos_t startCoord, endCoord; xyze_pos_t startCoord, endCoord;
LOOP_LINEAR_AXES(a) { LOOP_NUM_AXES(a) {
startCoord[a] = planner.get_axis_position_mm((AxisEnum)a); startCoord[a] = planner.get_axis_position_mm((AxisEnum)a);
endCoord[a] = planner.get_axis_position_mm((AxisEnum)a); endCoord[a] = planner.get_axis_position_mm((AxisEnum)a);
} }
@@ -395,7 +395,7 @@ void I2CPositionEncoder::calibrate_steps_mm(const uint8_t iter) {
travelDistance = endDistance - startDistance; travelDistance = endDistance - startDistance;
xyze_pos_t startCoord, endCoord; xyze_pos_t startCoord, endCoord;
LOOP_LINEAR_AXES(a) { LOOP_NUM_AXES(a) {
startCoord[a] = planner.get_axis_position_mm((AxisEnum)a); startCoord[a] = planner.get_axis_position_mm((AxisEnum)a);
endCoord[a] = planner.get_axis_position_mm((AxisEnum)a); endCoord[a] = planner.get_axis_position_mm((AxisEnum)a);
} }
@@ -657,7 +657,7 @@ void I2CPositionEncodersMgr::report_position(const int8_t idx, const bool units,
else { else {
if (noOffset) { if (noOffset) {
const int32_t raw_count = encoders[idx].get_raw_count(); const int32_t raw_count = encoders[idx].get_raw_count();
SERIAL_CHAR(axis_codes[encoders[idx].get_axis()], ' '); SERIAL_CHAR(AXIS_CHAR(encoders[idx).get_axis()], ' ');
for (uint8_t j = 31; j > 0; j--) for (uint8_t j = 31; j > 0; j--)
SERIAL_ECHO((bool)(0x00000001 & (raw_count >> j))); SERIAL_ECHO((bool)(0x00000001 & (raw_count >> j)));
@@ -712,7 +712,7 @@ void I2CPositionEncodersMgr::change_module_address(const uint8_t oldaddr, const
// and enable it (it will likely have failed initialization on power-up, before the address change). // and enable it (it will likely have failed initialization on power-up, before the address change).
const int8_t idx = idx_from_addr(newaddr); const int8_t idx = idx_from_addr(newaddr);
if (idx >= 0 && !encoders[idx].get_active()) { if (idx >= 0 && !encoders[idx].get_active()) {
SERIAL_CHAR(axis_codes[encoders[idx].get_axis()]); SERIAL_CHAR(AXIS_CHAR(encoders[idx).get_axis()]);
SERIAL_ECHOLNPGM(" axis encoder was not detected on printer startup. Trying again."); SERIAL_ECHOLNPGM(" axis encoder was not detected on printer startup. Trying again.");
encoders[idx].set_active(encoders[idx].passes_test(true)); encoders[idx].set_active(encoders[idx].passes_test(true));
} }
@@ -814,7 +814,7 @@ void I2CPositionEncodersMgr::M860() {
if (I2CPE_idx == 0xFF) { if (I2CPE_idx == 0xFF) {
LOOP_LOGICAL_AXES(i) { LOOP_LOGICAL_AXES(i) {
if (!I2CPE_anyaxis || parser.seen_test(axis_codes[i])) { if (!I2CPE_anyaxis || parser.seen_test(AXIS_CHAR(i))) {
const uint8_t idx = idx_from_axis(AxisEnum(i)); const uint8_t idx = idx_from_axis(AxisEnum(i));
if ((int8_t)idx >= 0) report_position(idx, hasU, hasO); if ((int8_t)idx >= 0) report_position(idx, hasU, hasO);
} }
@@ -841,7 +841,7 @@ void I2CPositionEncodersMgr::M861() {
if (I2CPE_idx == 0xFF) { if (I2CPE_idx == 0xFF) {
LOOP_LOGICAL_AXES(i) { LOOP_LOGICAL_AXES(i) {
if (!I2CPE_anyaxis || parser.seen(axis_codes[i])) { if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) {
const uint8_t idx = idx_from_axis(AxisEnum(i)); const uint8_t idx = idx_from_axis(AxisEnum(i));
if ((int8_t)idx >= 0) report_status(idx); if ((int8_t)idx >= 0) report_status(idx);
} }
@@ -869,7 +869,7 @@ void I2CPositionEncodersMgr::M862() {
if (I2CPE_idx == 0xFF) { if (I2CPE_idx == 0xFF) {
LOOP_LOGICAL_AXES(i) { LOOP_LOGICAL_AXES(i) {
if (!I2CPE_anyaxis || parser.seen(axis_codes[i])) { if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) {
const uint8_t idx = idx_from_axis(AxisEnum(i)); const uint8_t idx = idx_from_axis(AxisEnum(i));
if ((int8_t)idx >= 0) test_axis(idx); if ((int8_t)idx >= 0) test_axis(idx);
} }
@@ -900,7 +900,7 @@ void I2CPositionEncodersMgr::M863() {
if (I2CPE_idx == 0xFF) { if (I2CPE_idx == 0xFF) {
LOOP_LOGICAL_AXES(i) { LOOP_LOGICAL_AXES(i) {
if (!I2CPE_anyaxis || parser.seen(axis_codes[i])) { if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) {
const uint8_t idx = idx_from_axis(AxisEnum(i)); const uint8_t idx = idx_from_axis(AxisEnum(i));
if ((int8_t)idx >= 0) calibrate_steps_mm(idx, iterations); if ((int8_t)idx >= 0) calibrate_steps_mm(idx, iterations);
} }
@@ -976,7 +976,7 @@ void I2CPositionEncodersMgr::M865() {
if (!I2CPE_addr) { if (!I2CPE_addr) {
LOOP_LOGICAL_AXES(i) { LOOP_LOGICAL_AXES(i) {
if (!I2CPE_anyaxis || parser.seen(axis_codes[i])) { if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) {
const uint8_t idx = idx_from_axis(AxisEnum(i)); const uint8_t idx = idx_from_axis(AxisEnum(i));
if ((int8_t)idx >= 0) report_module_firmware(encoders[idx].get_address()); if ((int8_t)idx >= 0) report_module_firmware(encoders[idx].get_address());
} }
@@ -1007,7 +1007,7 @@ void I2CPositionEncodersMgr::M866() {
if (I2CPE_idx == 0xFF) { if (I2CPE_idx == 0xFF) {
LOOP_LOGICAL_AXES(i) { LOOP_LOGICAL_AXES(i) {
if (!I2CPE_anyaxis || parser.seen(axis_codes[i])) { if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) {
const uint8_t idx = idx_from_axis(AxisEnum(i)); const uint8_t idx = idx_from_axis(AxisEnum(i));
if ((int8_t)idx >= 0) { if ((int8_t)idx >= 0) {
if (hasR) if (hasR)
@@ -1045,7 +1045,7 @@ void I2CPositionEncodersMgr::M867() {
if (I2CPE_idx == 0xFF) { if (I2CPE_idx == 0xFF) {
LOOP_LOGICAL_AXES(i) { LOOP_LOGICAL_AXES(i) {
if (!I2CPE_anyaxis || parser.seen(axis_codes[i])) { if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) {
const uint8_t idx = idx_from_axis(AxisEnum(i)); const uint8_t idx = idx_from_axis(AxisEnum(i));
if ((int8_t)idx >= 0) { if ((int8_t)idx >= 0) {
const bool ena = onoff == -1 ? !encoders[I2CPE_idx].get_ec_enabled() : !!onoff; const bool ena = onoff == -1 ? !encoders[I2CPE_idx].get_ec_enabled() : !!onoff;
@@ -1081,7 +1081,7 @@ void I2CPositionEncodersMgr::M868() {
if (I2CPE_idx == 0xFF) { if (I2CPE_idx == 0xFF) {
LOOP_LOGICAL_AXES(i) { LOOP_LOGICAL_AXES(i) {
if (!I2CPE_anyaxis || parser.seen(axis_codes[i])) { if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) {
const uint8_t idx = idx_from_axis(AxisEnum(i)); const uint8_t idx = idx_from_axis(AxisEnum(i));
if ((int8_t)idx >= 0) { if ((int8_t)idx >= 0) {
if (newThreshold != -9999) if (newThreshold != -9999)
@@ -1115,7 +1115,7 @@ void I2CPositionEncodersMgr::M869() {
if (I2CPE_idx == 0xFF) { if (I2CPE_idx == 0xFF) {
LOOP_LOGICAL_AXES(i) { LOOP_LOGICAL_AXES(i) {
if (!I2CPE_anyaxis || parser.seen(axis_codes[i])) { if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) {
const uint8_t idx = idx_from_axis(AxisEnum(i)); const uint8_t idx = idx_from_axis(AxisEnum(i));
if ((int8_t)idx >= 0) report_error(idx); if ((int8_t)idx >= 0) report_error(idx);
} }

View File

@@ -261,32 +261,32 @@ class I2CPositionEncodersMgr {
static void report_error_count(const int8_t idx, const AxisEnum axis) { static void report_error_count(const int8_t idx, const AxisEnum axis) {
CHECK_IDX(); CHECK_IDX();
SERIAL_ECHOLNPGM("Error count on ", AS_CHAR(axis_codes[axis]), " axis is ", encoders[idx].get_error_count()); SERIAL_ECHOLNPGM("Error count on ", AS_CHAR(AXIS_CHAR(axis)), " axis is ", encoders[idx].get_error_count());
} }
static void reset_error_count(const int8_t idx, const AxisEnum axis) { static void reset_error_count(const int8_t idx, const AxisEnum axis) {
CHECK_IDX(); CHECK_IDX();
encoders[idx].set_error_count(0); encoders[idx].set_error_count(0);
SERIAL_ECHOLNPGM("Error count on ", AS_CHAR(axis_codes[axis]), " axis has been reset."); SERIAL_ECHOLNPGM("Error count on ", AS_CHAR(AXIS_CHAR(axis)), " axis has been reset.");
} }
static void enable_ec(const int8_t idx, const bool enabled, const AxisEnum axis) { static void enable_ec(const int8_t idx, const bool enabled, const AxisEnum axis) {
CHECK_IDX(); CHECK_IDX();
encoders[idx].set_ec_enabled(enabled); encoders[idx].set_ec_enabled(enabled);
SERIAL_ECHOPGM("Error correction on ", AS_CHAR(axis_codes[axis])); SERIAL_ECHOPGM("Error correction on ", AS_CHAR(AXIS_CHAR(axis)));
SERIAL_ECHO_TERNARY(encoders[idx].get_ec_enabled(), " axis is ", "en", "dis", "abled.\n"); SERIAL_ECHO_TERNARY(encoders[idx].get_ec_enabled(), " axis is ", "en", "dis", "abled.\n");
} }
static void set_ec_threshold(const int8_t idx, const float newThreshold, const AxisEnum axis) { static void set_ec_threshold(const int8_t idx, const float newThreshold, const AxisEnum axis) {
CHECK_IDX(); CHECK_IDX();
encoders[idx].set_ec_threshold(newThreshold); encoders[idx].set_ec_threshold(newThreshold);
SERIAL_ECHOLNPGM("Error correct threshold for ", AS_CHAR(axis_codes[axis]), " axis set to ", newThreshold, "mm."); SERIAL_ECHOLNPGM("Error correct threshold for ", AS_CHAR(AXIS_CHAR(axis)), " axis set to ", newThreshold, "mm.");
} }
static void get_ec_threshold(const int8_t idx, const AxisEnum axis) { static void get_ec_threshold(const int8_t idx, const AxisEnum axis) {
CHECK_IDX(); CHECK_IDX();
const float threshold = encoders[idx].get_ec_threshold(); const float threshold = encoders[idx].get_ec_threshold();
SERIAL_ECHOLNPGM("Error correct threshold for ", AS_CHAR(axis_codes[axis]), " axis is ", threshold, "mm."); SERIAL_ECHOLNPGM("Error correct threshold for ", AS_CHAR(AXIS_CHAR(axis)), " axis is ", threshold, "mm.");
} }
static int8_t idx_from_axis(const AxisEnum axis) { static int8_t idx_from_axis(const AxisEnum axis) {

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

@@ -163,7 +163,7 @@ Joystick joystick;
// norm_jog values of [-1 .. 1] maps linearly to [-feedrate .. feedrate] // norm_jog values of [-1 .. 1] maps linearly to [-feedrate .. feedrate]
xyz_float_t move_dist{0}; xyz_float_t move_dist{0};
float hypot2 = 0; float hypot2 = 0;
LOOP_LINEAR_AXES(i) if (norm_jog[i]) { LOOP_NUM_AXES(i) if (norm_jog[i]) {
move_dist[i] = seg_time * norm_jog[i] * TERN(EXTENSIBLE_UI, manual_feedrate_mm_s, planner.settings.max_feedrate_mm_s)[i]; move_dist[i] = seg_time * norm_jog[i] * TERN(EXTENSIBLE_UI, manual_feedrate_mm_s, planner.settings.max_feedrate_mm_s)[i];
hypot2 += sq(move_dist[i]); hypot2 += sq(move_dist[i]);
} }
@@ -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

@@ -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"

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

@@ -567,7 +567,7 @@ void PrintJobRecovery::resume() {
TERN_(HAS_HOME_OFFSET, home_offset = info.home_offset); TERN_(HAS_HOME_OFFSET, home_offset = info.home_offset);
TERN_(HAS_POSITION_SHIFT, position_shift = info.position_shift); TERN_(HAS_POSITION_SHIFT, position_shift = info.position_shift);
#if HAS_HOME_OFFSET || HAS_POSITION_SHIFT #if HAS_HOME_OFFSET || HAS_POSITION_SHIFT
LOOP_LINEAR_AXES(i) update_workspace_offset((AxisEnum)i); LOOP_NUM_AXES(i) update_workspace_offset((AxisEnum)i);
#endif #endif
// Relative axis modes // Relative axis modes
@@ -617,7 +617,7 @@ void PrintJobRecovery::resume() {
#if HAS_HOME_OFFSET #if HAS_HOME_OFFSET
DEBUG_ECHOPGM("home_offset: "); DEBUG_ECHOPGM("home_offset: ");
LOOP_LINEAR_AXES(i) { LOOP_NUM_AXES(i) {
if (i) DEBUG_CHAR(','); if (i) DEBUG_CHAR(',');
DEBUG_DECIMAL(info.home_offset[i]); DEBUG_DECIMAL(info.home_offset[i]);
} }
@@ -626,7 +626,7 @@ void PrintJobRecovery::resume() {
#if HAS_POSITION_SHIFT #if HAS_POSITION_SHIFT
DEBUG_ECHOPGM("position_shift: "); DEBUG_ECHOPGM("position_shift: ");
LOOP_LINEAR_AXES(i) { LOOP_NUM_AXES(i) {
if (i) DEBUG_CHAR(','); if (i) DEBUG_CHAR(',');
DEBUG_DECIMAL(info.position_shift[i]); DEBUG_DECIMAL(info.position_shift[i]);
} }

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 #else
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,7 +98,7 @@ 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);
} }
@@ -107,35 +115,41 @@ void SpindleLaser::init() {
#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,87 +34,97 @@
#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)
// #define _MAP(N,S1,S2,D1,D2) ((N)*_MAX((D2)-(D1),0)/_MAX((S2)-(S1),1)+(D1)) // 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)
@@ -125,7 +135,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();
/** /**
@@ -143,78 +152,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(const 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_state = 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)
@@ -226,122 +233,97 @@ 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 laser_menu_toggle(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);
}
}
/** /**
* 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.
laser_menu_toggle(true); // Laser On
delay(testPulse); // Delay for time set by user in pulse ms menu screen. delay(testPulse); // Delay for time set by user in pulse ms menu screen.
disable(); // Turn laser off laser_menu_toggle(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

@@ -348,7 +348,7 @@ void test_tmc_connection(LOGICAL_AXIS_DECL(const bool, true));
#if USE_SENSORLESS #if USE_SENSORLESS
// Track enabled status of stealthChop and only re-enable where applicable // Track enabled status of stealthChop and only re-enable where applicable
struct sensorless_t { bool LINEAR_AXIS_ARGS(), x2, y2, z2, z3, z4; }; struct sensorless_t { bool NUM_AXIS_ARGS(), x2, y2, z2, z3, z4; };
#if ENABLED(IMPROVE_HOMING_RELIABILITY) #if ENABLED(IMPROVE_HOMING_RELIABILITY)
extern millis_t sg_guard_period; extern millis_t sg_guard_period;

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"
@@ -59,7 +60,7 @@
#include "../../libs/L64XX/L64XX_Marlin.h" #include "../../libs/L64XX/L64XX_Marlin.h"
#endif #endif
#if ENABLED(LASER_MOVE_G28_OFF) #if ENABLED(LASER_FEATURE)
#include "../../feature/spindle_laser.h" #include "../../feature/spindle_laser.h"
#endif #endif
@@ -82,7 +83,7 @@
#if ENABLED(SENSORLESS_HOMING) #if ENABLED(SENSORLESS_HOMING)
sensorless_t stealth_states { sensorless_t stealth_states {
LINEAR_AXIS_LIST( NUM_AXIS_LIST(
TERN0(X_SENSORLESS, tmc_enable_stallguard(stepperX)), TERN0(X_SENSORLESS, tmc_enable_stallguard(stepperX)),
TERN0(Y_SENSORLESS, tmc_enable_stallguard(stepperY)), TERN0(Y_SENSORLESS, tmc_enable_stallguard(stepperY)),
false, false, false, false false, false, false, false
@@ -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,12 @@ 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 /*
* 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;
@@ -214,7 +220,7 @@ void GcodeSuite::G28() {
#if ENABLED(MARLIN_DEV_MODE) #if ENABLED(MARLIN_DEV_MODE)
if (parser.seen_test('S')) { if (parser.seen_test('S')) {
LOOP_LINEAR_AXES(a) set_axis_is_at_home((AxisEnum)a); LOOP_NUM_AXES(a) set_axis_is_at_home((AxisEnum)a);
sync_plan_position(); sync_plan_position();
SERIAL_ECHOLNPGM("Simulated Homing"); SERIAL_ECHOLNPGM("Simulated Homing");
report_current_position(); report_current_position();
@@ -367,21 +373,21 @@ void GcodeSuite::G28() {
#define _UNSAFE(A) (homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(A##_AXIS)))) #define _UNSAFE(A) (homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(A##_AXIS))))
const bool homeZ = TERN0(HAS_Z_AXIS, parser.seen_test('Z')), const bool homeZ = TERN0(HAS_Z_AXIS, parser.seen_test('Z')),
LINEAR_AXIS_LIST( // Other axes should be homed before Z safe-homing NUM_AXIS_LIST( // Other axes should be homed before Z safe-homing
needX = _UNSAFE(X), needY = _UNSAFE(Y), needZ = false, // UNUSED needX = _UNSAFE(X), needY = _UNSAFE(Y), needZ = false, // UNUSED
needI = _UNSAFE(I), needJ = _UNSAFE(J), needK = _UNSAFE(K) needI = _UNSAFE(I), needJ = _UNSAFE(J), needK = _UNSAFE(K)
), ),
LINEAR_AXIS_LIST( // Home each axis if needed or flagged NUM_AXIS_LIST( // Home each axis if needed or flagged
homeX = needX || parser.seen_test('X'), homeX = needX || parser.seen_test('X'),
homeY = needY || parser.seen_test('Y'), homeY = needY || parser.seen_test('Y'),
homeZZ = homeZ, homeZZ = homeZ,
homeI = needI || parser.seen_test(AXIS4_NAME), homeJ = needJ || parser.seen_test(AXIS5_NAME), homeK = needK || parser.seen_test(AXIS6_NAME) homeI = needI || parser.seen_test(AXIS4_NAME), homeJ = needJ || parser.seen_test(AXIS5_NAME), homeK = needK || parser.seen_test(AXIS6_NAME)
), ),
home_all = LINEAR_AXIS_GANG( // Home-all if all or none are flagged home_all = NUM_AXIS_GANG( // Home-all if all or none are flagged
homeX == homeX, && homeY == homeX, && homeZ == homeX, homeX == homeX, && homeY == homeX, && homeZ == homeX,
&& homeI == homeX, && homeJ == homeX, && homeK == homeX && homeI == homeX, && homeJ == homeX, && homeK == homeX
), ),
LINEAR_AXIS_LIST( NUM_AXIS_LIST(
doX = home_all || homeX, doY = home_all || homeY, doZ = home_all || homeZ, doX = home_all || homeX, doY = home_all || homeY, doZ = home_all || homeZ,
doI = home_all || homeI, doJ = home_all || homeJ, doK = home_all || homeK doI = home_all || homeI, doJ = home_all || homeJ, doK = home_all || homeK
); );
@@ -397,7 +403,7 @@ void GcodeSuite::G28() {
const bool seenR = parser.seenval('R'); const bool seenR = parser.seenval('R');
const float z_homing_height = seenR ? parser.value_linear_units() : Z_HOMING_HEIGHT; const float z_homing_height = seenR ? parser.value_linear_units() : Z_HOMING_HEIGHT;
if (z_homing_height && (seenR || LINEAR_AXIS_GANG(doX, || doY, || TERN0(Z_SAFE_HOMING, doZ), || doI, || doJ, || doK))) { if (z_homing_height && (seenR || NUM_AXIS_GANG(doX, || doY, || TERN0(Z_SAFE_HOMING, doZ), || doI, || doJ, || doK))) {
// Raise Z before homing any other axes and z is not already high enough (never lower z) // Raise Z before homing any other axes and z is not already high enough (never lower z)
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Raise Z (before homing) by ", z_homing_height); if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Raise Z (before homing) by ", z_homing_height);
do_z_clearance(z_homing_height); do_z_clearance(z_homing_height);
@@ -460,9 +466,11 @@ void GcodeSuite::G28() {
} }
#endif #endif
TERN_(HAS_I_AXIS, if (doI) homeaxis(I_AXIS)); SECONDARY_AXIS_CODE(
TERN_(HAS_J_AXIS, if (doJ) homeaxis(J_AXIS)); if (doI) homeaxis(I_AXIS),
TERN_(HAS_K_AXIS, if (doK) homeaxis(K_AXIS)); if (doJ) homeaxis(J_AXIS),
if (doK) homeaxis(K_AXIS)
);
sync_plan_position(); sync_plan_position();
@@ -568,7 +576,7 @@ void GcodeSuite::G28() {
// If not, this will need a PROGMEM directive and an accessor. // If not, this will need a PROGMEM directive and an accessor.
#define _EN_ITEM(N) , E_AXIS #define _EN_ITEM(N) , E_AXIS
static constexpr AxisEnum L64XX_axis_xref[MAX_L64XX] = { static constexpr AxisEnum L64XX_axis_xref[MAX_L64XX] = {
LINEAR_AXIS_LIST(X_AXIS, Y_AXIS, Z_AXIS, I_AXIS, J_AXIS, K_AXIS), NUM_AXIS_LIST(X_AXIS, Y_AXIS, Z_AXIS, I_AXIS, J_AXIS, K_AXIS),
X_AXIS, Y_AXIS, Z_AXIS, Z_AXIS, Z_AXIS X_AXIS, Y_AXIS, Z_AXIS, Z_AXIS, Z_AXIS
REPEAT(E_STEPPERS, _EN_ITEM) REPEAT(E_STEPPERS, _EN_ITEM)
}; };

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"
@@ -343,7 +343,7 @@ static float auto_tune_a(const float dcr) {
abc_float_t delta_e = { 0.0f }, delta_t = { 0.0f }; abc_float_t delta_e = { 0.0f }, delta_t = { 0.0f };
delta_t.reset(); delta_t.reset();
LOOP_LINEAR_AXES(axis) { LOOP_NUM_AXES(axis) {
delta_t[axis] = diff; delta_t[axis] = diff;
calc_kinematics_diff_probe_points(z_pt, dcr, delta_e, delta_r, delta_t); calc_kinematics_diff_probe_points(z_pt, dcr, delta_e, delta_r, delta_t);
delta_t[axis] = 0; delta_t[axis] = 0;
@@ -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
@@ -557,7 +557,7 @@ void GcodeSuite::G33() {
case 1: case 1:
test_precision = 0.0f; // forced end test_precision = 0.0f; // forced end
LOOP_LINEAR_AXES(axis) e_delta[axis] = +Z4(CEN); LOOP_NUM_AXES(axis) e_delta[axis] = +Z4(CEN);
break; break;
case 2: case 2:
@@ -605,14 +605,14 @@ void GcodeSuite::G33() {
// Normalize angles to least-squares // Normalize angles to least-squares
if (_angle_results) { if (_angle_results) {
float a_sum = 0.0f; float a_sum = 0.0f;
LOOP_LINEAR_AXES(axis) a_sum += delta_tower_angle_trim[axis]; LOOP_NUM_AXES(axis) a_sum += delta_tower_angle_trim[axis];
LOOP_LINEAR_AXES(axis) delta_tower_angle_trim[axis] -= a_sum / 3.0f; LOOP_NUM_AXES(axis) delta_tower_angle_trim[axis] -= a_sum / 3.0f;
} }
// adjust delta_height and endstops by the max amount // adjust delta_height and endstops by the max amount
const float z_temp = _MAX(delta_endstop_adj.a, delta_endstop_adj.b, delta_endstop_adj.c); const float z_temp = _MAX(delta_endstop_adj.a, delta_endstop_adj.b, delta_endstop_adj.c);
delta_height -= z_temp; delta_height -= z_temp;
LOOP_LINEAR_AXES(axis) delta_endstop_adj[axis] -= z_temp; LOOP_NUM_AXES(axis) delta_endstop_adj[axis] -= z_temp;
} }
recalc_delta_settings(); recalc_delta_settings();
NOMORE(zero_std_dev_min, zero_std_dev); NOMORE(zero_std_dev_min, zero_std_dev);

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
@@ -79,7 +82,7 @@ void GcodeSuite::G34() {
stepper.set_digipot_current(Z_AXIS, target_current); stepper.set_digipot_current(Z_AXIS, target_current);
#elif HAS_MOTOR_CURRENT_PWM #elif HAS_MOTOR_CURRENT_PWM
const uint16_t target_current = parser.intval('S', GANTRY_CALIBRATION_CURRENT); const uint16_t target_current = parser.intval('S', GANTRY_CALIBRATION_CURRENT);
const uint32_t previous_current = stepper.motor_current_setting[Z_AXIS]; const uint32_t previous_current = stepper.motor_current_setting[1]; // Z
stepper.set_digipot_current(1, target_current); stepper.set_digipot_current(1, target_current);
#elif HAS_MOTOR_CURRENT_DAC #elif HAS_MOTOR_CURRENT_DAC
const float target_current = parser.floatval('S', GANTRY_CALIBRATION_CURRENT); const float target_current = parser.floatval('S', GANTRY_CALIBRATION_CURRENT);

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

@@ -88,7 +88,7 @@
enum side_t : uint8_t { enum side_t : uint8_t {
TOP, RIGHT, FRONT, LEFT, BACK, NUM_SIDES, TOP, RIGHT, FRONT, LEFT, BACK, NUM_SIDES,
LIST_N(DOUBLE(SUB3(LINEAR_AXES)), IMINIMUM, IMAXIMUM, JMINIMUM, JMAXIMUM, KMINIMUM, KMAXIMUM) LIST_N(DOUBLE(SECONDARY_AXES), IMINIMUM, IMAXIMUM, JMINIMUM, JMAXIMUM, KMINIMUM, KMAXIMUM)
}; };
static constexpr xyz_pos_t true_center CALIBRATION_OBJECT_CENTER; static constexpr xyz_pos_t true_center CALIBRATION_OBJECT_CENTER;
@@ -352,7 +352,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
// The difference between the known and the measured location // The difference between the known and the measured location
// of the calibration object is the positional error // of the calibration object is the positional error
LINEAR_AXIS_CODE( NUM_AXIS_CODE(
m.pos_error.x = TERN0(HAS_X_CENTER, true_center.x - m.obj_center.x), m.pos_error.x = TERN0(HAS_X_CENTER, true_center.x - m.obj_center.x),
m.pos_error.y = TERN0(HAS_Y_CENTER, true_center.y - m.obj_center.y), m.pos_error.y = TERN0(HAS_Y_CENTER, true_center.y - m.obj_center.y),
m.pos_error.z = true_center.z - m.obj_center.z, m.pos_error.z = true_center.z - m.obj_center.z,
@@ -597,7 +597,7 @@ inline void calibrate_backlash(measurements_t &m, const float uncertainty) {
// New scope for TEMPORARY_BACKLASH_CORRECTION // New scope for TEMPORARY_BACKLASH_CORRECTION
TEMPORARY_BACKLASH_CORRECTION(backlash.all_on); TEMPORARY_BACKLASH_CORRECTION(backlash.all_on);
TEMPORARY_BACKLASH_SMOOTHING(0.0f); TEMPORARY_BACKLASH_SMOOTHING(0.0f);
const xyz_float_t move = LINEAR_AXIS_ARRAY( const xyz_float_t move = NUM_AXIS_ARRAY(
AXIS_CAN_CALIBRATE(X) * 3, AXIS_CAN_CALIBRATE(Y) * 3, AXIS_CAN_CALIBRATE(Z) * 3, AXIS_CAN_CALIBRATE(X) * 3, AXIS_CAN_CALIBRATE(Y) * 3, AXIS_CAN_CALIBRATE(Z) * 3,
AXIS_CAN_CALIBRATE(I) * 3, AXIS_CAN_CALIBRATE(J) * 3, AXIS_CAN_CALIBRATE(K) * 3 AXIS_CAN_CALIBRATE(I) * 3, AXIS_CAN_CALIBRATE(J) * 3, AXIS_CAN_CALIBRATE(K) * 3
); );

View File

@@ -47,23 +47,17 @@ void GcodeSuite::M425() {
bool noArgs = true; bool noArgs = true;
auto axis_can_calibrate = [](const uint8_t a) { auto axis_can_calibrate = [](const uint8_t a) {
#define _CAN_CASE(N) case N##_AXIS: return AXIS_CAN_CALIBRATE(N);
switch (a) { switch (a) {
default: return false; default: return false;
LINEAR_AXIS_CODE( MAIN_AXIS_MAP(_CAN_CASE)
case X_AXIS: return AXIS_CAN_CALIBRATE(X),
case Y_AXIS: return AXIS_CAN_CALIBRATE(Y),
case Z_AXIS: return AXIS_CAN_CALIBRATE(Z),
case I_AXIS: return AXIS_CAN_CALIBRATE(I),
case J_AXIS: return AXIS_CAN_CALIBRATE(J),
case K_AXIS: return AXIS_CAN_CALIBRATE(K)
);
} }
}; };
LOOP_LINEAR_AXES(a) { LOOP_NUM_AXES(a) {
if (axis_can_calibrate(a) && parser.seen(AXIS_CHAR(a))) { if (axis_can_calibrate(a) && parser.seen(AXIS_CHAR(a))) {
planner.synchronize(); planner.synchronize();
backlash.set_distance_mm(AxisEnum(a), parser.has_value() ? parser.value_linear_units() : backlash.get_measurement(AxisEnum(a))); backlash.set_distance_mm((AxisEnum)a, parser.has_value() ? parser.value_axis_units((AxisEnum)a) : backlash.get_measurement((AxisEnum)a));
noArgs = false; noArgs = false;
} }
} }
@@ -88,10 +82,8 @@ void GcodeSuite::M425() {
SERIAL_ECHOLNPGM("active:"); SERIAL_ECHOLNPGM("active:");
SERIAL_ECHOLNPGM(" Correction Amount/Fade-out: F", backlash.get_correction(), " (F1.0 = full, F0.0 = none)"); SERIAL_ECHOLNPGM(" Correction Amount/Fade-out: F", backlash.get_correction(), " (F1.0 = full, F0.0 = none)");
SERIAL_ECHOPGM(" Backlash Distance (mm): "); SERIAL_ECHOPGM(" Backlash Distance (mm): ");
LOOP_LINEAR_AXES(a) if (axis_can_calibrate(a)) { LOOP_NUM_AXES(a) if (axis_can_calibrate(a)) {
SERIAL_CHAR(' ', AXIS_CHAR(a)); SERIAL_ECHOLNPGM_P((PGM_P)pgm_read_ptr(&SP_AXIS_STR[a]), backlash.get_distance_mm((AxisEnum)a));
SERIAL_ECHO(backlash.get_distance_mm(AxisEnum(a)));
SERIAL_EOL();
} }
#ifdef BACKLASH_SMOOTHING_MM #ifdef BACKLASH_SMOOTHING_MM
@@ -101,9 +93,8 @@ void GcodeSuite::M425() {
#if ENABLED(MEASURE_BACKLASH_WHEN_PROBING) #if ENABLED(MEASURE_BACKLASH_WHEN_PROBING)
SERIAL_ECHOPGM(" Average measured backlash (mm):"); SERIAL_ECHOPGM(" Average measured backlash (mm):");
if (backlash.has_any_measurement()) { if (backlash.has_any_measurement()) {
LOOP_LINEAR_AXES(a) if (axis_can_calibrate(a) && backlash.has_measurement(AxisEnum(a))) { LOOP_NUM_AXES(a) if (axis_can_calibrate(a) && backlash.has_measurement(AxisEnum(a))) {
SERIAL_CHAR(' ', AXIS_CHAR(a)); SERIAL_ECHOPGM_P((PGM_P)pgm_read_ptr(&SP_AXIS_STR[a]), backlash.get_measurement((AxisEnum)a));
SERIAL_ECHO(backlash.get_measurement(AxisEnum(a)));
} }
} }
else else
@@ -120,7 +111,7 @@ void GcodeSuite::M425_report(const bool forReplay/*=true*/) {
#ifdef BACKLASH_SMOOTHING_MM #ifdef BACKLASH_SMOOTHING_MM
, PSTR(" S"), LINEAR_UNIT(backlash.get_smoothing_mm()) , PSTR(" S"), LINEAR_UNIT(backlash.get_smoothing_mm())
#endif #endif
, LIST_N(DOUBLE(LINEAR_AXES), , LIST_N(DOUBLE(NUM_AXES),
SP_X_STR, LINEAR_UNIT(backlash.get_distance_mm(X_AXIS)), SP_X_STR, LINEAR_UNIT(backlash.get_distance_mm(X_AXIS)),
SP_Y_STR, LINEAR_UNIT(backlash.get_distance_mm(Y_AXIS)), SP_Y_STR, LINEAR_UNIT(backlash.get_distance_mm(Y_AXIS)),
SP_Z_STR, LINEAR_UNIT(backlash.get_distance_mm(Z_AXIS)), SP_Z_STR, LINEAR_UNIT(backlash.get_distance_mm(Z_AXIS)),

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

@@ -44,8 +44,8 @@
void GcodeSuite::M666() { void GcodeSuite::M666() {
DEBUG_SECTION(log_M666, "M666", DEBUGGING(LEVELING)); DEBUG_SECTION(log_M666, "M666", DEBUGGING(LEVELING));
bool is_err = false, is_set = false; bool is_err = false, is_set = false;
LOOP_LINEAR_AXES(i) { LOOP_NUM_AXES(i) {
if (parser.seen(AXIS_CHAR(i))) { if (parser.seenval(AXIS_CHAR(i))) {
is_set = true; is_set = true;
const float v = parser.value_linear_units(); const float v = parser.value_linear_units();
if (v > 0) if (v > 0)

View File

@@ -122,7 +122,7 @@
* S<percent> : Speed factor percentage. * S<percent> : Speed factor percentage.
*/ */
void GcodeSuite::M201() { void GcodeSuite::M201() {
if (!parser.seen("T" LOGICAL_AXES_STRING TERN_(XY_FREQUENCY_LIMIT, "FS"))) if (!parser.seen("T" STR_AXES_LOGICAL TERN_(XY_FREQUENCY_LIMIT, "FS")))
return M201_report(); return M201_report();
const int8_t target_extruder = get_target_extruder_from_command(); const int8_t target_extruder = get_target_extruder_from_command();
@@ -134,9 +134,9 @@ void GcodeSuite::M201() {
#endif #endif
LOOP_LOGICAL_AXES(i) { LOOP_LOGICAL_AXES(i) {
if (parser.seenval(axis_codes[i])) { if (parser.seenval(AXIS_CHAR(i))) {
const uint8_t a = TERN(HAS_EXTRUDERS, (i == E_AXIS ? uint8_t(E_AXIS_N(target_extruder)) : i), i); const AxisEnum a = TERN(HAS_EXTRUDERS, (i == E_AXIS ? E_AXIS_N(target_extruder) : (AxisEnum)i), (AxisEnum)i);
planner.set_max_acceleration(a, parser.value_axis_units((AxisEnum)a)); planner.set_max_acceleration(a, parser.value_axis_units(a));
} }
} }
} }
@@ -144,7 +144,7 @@ void GcodeSuite::M201() {
void GcodeSuite::M201_report(const bool forReplay/*=true*/) { void GcodeSuite::M201_report(const bool forReplay/*=true*/) {
report_heading_etc(forReplay, F(STR_MAX_ACCELERATION)); report_heading_etc(forReplay, F(STR_MAX_ACCELERATION));
SERIAL_ECHOLNPGM_P( SERIAL_ECHOLNPGM_P(
LIST_N(DOUBLE(LINEAR_AXES), LIST_N(DOUBLE(NUM_AXES),
PSTR(" M201 X"), LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[X_AXIS]), PSTR(" M201 X"), LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[X_AXIS]),
SP_Y_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Y_AXIS]), SP_Y_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Y_AXIS]),
SP_Z_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Z_AXIS]), SP_Z_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Z_AXIS]),
@@ -173,23 +173,23 @@ void GcodeSuite::M201_report(const bool forReplay/*=true*/) {
* With multiple extruders use T to specify which one. * With multiple extruders use T to specify which one.
*/ */
void GcodeSuite::M203() { void GcodeSuite::M203() {
if (!parser.seen("T" LOGICAL_AXES_STRING)) if (!parser.seen("T" STR_AXES_LOGICAL))
return M203_report(); return M203_report();
const int8_t target_extruder = get_target_extruder_from_command(); const int8_t target_extruder = get_target_extruder_from_command();
if (target_extruder < 0) return; if (target_extruder < 0) return;
LOOP_LOGICAL_AXES(i) LOOP_LOGICAL_AXES(i)
if (parser.seenval(axis_codes[i])) { if (parser.seenval(AXIS_CHAR(i))) {
const uint8_t a = TERN(HAS_EXTRUDERS, (i == E_AXIS ? uint8_t(E_AXIS_N(target_extruder)) : i), i); const AxisEnum a = TERN(HAS_EXTRUDERS, (i == E_AXIS ? E_AXIS_N(target_extruder) : (AxisEnum)i), (AxisEnum)i);
planner.set_max_feedrate(a, parser.value_axis_units((AxisEnum)a)); planner.set_max_feedrate(a, parser.value_axis_units(a));
} }
} }
void GcodeSuite::M203_report(const bool forReplay/*=true*/) { void GcodeSuite::M203_report(const bool forReplay/*=true*/) {
report_heading_etc(forReplay, F(STR_MAX_FEEDRATES)); report_heading_etc(forReplay, F(STR_MAX_FEEDRATES));
SERIAL_ECHOLNPGM_P( SERIAL_ECHOLNPGM_P(
LIST_N(DOUBLE(LINEAR_AXES), LIST_N(DOUBLE(NUM_AXES),
PSTR(" M203 X"), LINEAR_UNIT(planner.settings.max_feedrate_mm_s[X_AXIS]), PSTR(" M203 X"), LINEAR_UNIT(planner.settings.max_feedrate_mm_s[X_AXIS]),
SP_Y_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Y_AXIS]), SP_Y_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Y_AXIS]),
SP_Z_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Z_AXIS]), SP_Z_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Z_AXIS]),
@@ -298,7 +298,7 @@ void GcodeSuite::M205_report(const bool forReplay/*=true*/) {
"Advanced (B<min_segment_time_us> S<min_feedrate> T<min_travel_feedrate>" "Advanced (B<min_segment_time_us> S<min_feedrate> T<min_travel_feedrate>"
TERN_(HAS_JUNCTION_DEVIATION, " J<junc_dev>") TERN_(HAS_JUNCTION_DEVIATION, " J<junc_dev>")
#if HAS_CLASSIC_JERK #if HAS_CLASSIC_JERK
LINEAR_AXIS_GANG( NUM_AXIS_GANG(
" X<max_jerk>", " Y<max_jerk>", " Z<max_jerk>", " X<max_jerk>", " Y<max_jerk>", " Z<max_jerk>",
" " STR_I "<max_jerk>", " " STR_J "<max_jerk>", " " STR_K "<max_jerk>" " " STR_I "<max_jerk>", " " STR_J "<max_jerk>", " " STR_K "<max_jerk>"
) )
@@ -314,7 +314,7 @@ void GcodeSuite::M205_report(const bool forReplay/*=true*/) {
, PSTR(" J"), LINEAR_UNIT(planner.junction_deviation_mm) , PSTR(" J"), LINEAR_UNIT(planner.junction_deviation_mm)
#endif #endif
#if HAS_CLASSIC_JERK #if HAS_CLASSIC_JERK
, LIST_N(DOUBLE(LINEAR_AXES), , LIST_N(DOUBLE(NUM_AXES),
SP_X_STR, LINEAR_UNIT(planner.max_jerk.x), SP_X_STR, LINEAR_UNIT(planner.max_jerk.x),
SP_Y_STR, LINEAR_UNIT(planner.max_jerk.y), SP_Y_STR, LINEAR_UNIT(planner.max_jerk.y),
SP_Z_STR, LINEAR_UNIT(planner.max_jerk.z), SP_Z_STR, LINEAR_UNIT(planner.max_jerk.z),

View File

@@ -50,9 +50,9 @@
* W[linear] 0/1 Enable park & Z Raise * W[linear] 0/1 Enable park & Z Raise
* X[linear] Park X (Requires TOOLCHANGE_PARK) * X[linear] Park X (Requires TOOLCHANGE_PARK)
* Y[linear] Park Y (Requires TOOLCHANGE_PARK) * Y[linear] Park Y (Requires TOOLCHANGE_PARK)
* I[linear] Park I (Requires TOOLCHANGE_PARK and LINEAR_AXES >= 4) * I[linear] Park I (Requires TOOLCHANGE_PARK and NUM_AXES >= 4)
* J[linear] Park J (Requires TOOLCHANGE_PARK and LINEAR_AXES >= 5) * J[linear] Park J (Requires TOOLCHANGE_PARK and NUM_AXES >= 5)
* K[linear] Park K (Requires TOOLCHANGE_PARK and LINEAR_AXES >= 6) * K[linear] Park K (Requires TOOLCHANGE_PARK and NUM_AXES >= 6)
* Z[linear] Z Raise * Z[linear] Z Raise
* F[speed] Fan Speed 0-255 * F[speed] Fan Speed 0-255
* D[seconds] Fan time * D[seconds] Fan time
@@ -174,14 +174,12 @@ void GcodeSuite::M217_report(const bool forReplay/*=true*/) {
#if HAS_Y_AXIS #if HAS_Y_AXIS
, SP_Y_STR, LINEAR_UNIT(toolchange_settings.change_point.y) , SP_Y_STR, LINEAR_UNIT(toolchange_settings.change_point.y)
#endif #endif
#if HAS_I_AXIS #if SECONDARY_AXES >= 1
, SP_I_STR, LINEAR_UNIT(toolchange_settings.change_point.i) , LIST_N(DOUBLE(SECONDARY_AXES),
#endif SP_I_STR, I_AXIS_UNIT(toolchange_settings.change_point.i),
#if HAS_J_AXIS SP_J_STR, J_AXIS_UNIT(toolchange_settings.change_point.j),
, SP_J_STR, LINEAR_UNIT(toolchange_settings.change_point.j) SP_K_STR, K_AXIS_UNIT(toolchange_settings.change_point.k)
#endif )
#if HAS_K_AXIS
, SP_K_STR, LINEAR_UNIT(toolchange_settings.change_point.k)
#endif #endif
); );
} }

View File

@@ -47,8 +47,8 @@ void GcodeSuite::M281() {
return; return;
} }
#endif #endif
if (parser.seen('L')) servo_angles[servo_index][0] = parser.value_int(); if (parser.seenval('L')) servo_angles[servo_index][0] = parser.value_int();
if (parser.seen('U')) servo_angles[servo_index][1] = parser.value_int(); if (parser.seenval('U')) servo_angles[servo_index][1] = parser.value_int();
} }
else else
SERIAL_ERROR_MSG("Servo ", servo_index, " out of range"); SERIAL_ERROR_MSG("Servo ", servo_index, " out of range");

View File

@@ -36,9 +36,9 @@
*/ */
void GcodeSuite::M304() { void GcodeSuite::M304() {
if (!parser.seen("PID")) return M304_report(); if (!parser.seen("PID")) return M304_report();
if (parser.seen('P')) thermalManager.temp_bed.pid.Kp = parser.value_float(); if (parser.seenval('P')) thermalManager.temp_bed.pid.Kp = parser.value_float();
if (parser.seen('I')) thermalManager.temp_bed.pid.Ki = scalePID_i(parser.value_float()); if (parser.seenval('I')) thermalManager.temp_bed.pid.Ki = scalePID_i(parser.value_float());
if (parser.seen('D')) thermalManager.temp_bed.pid.Kd = scalePID_d(parser.value_float()); if (parser.seenval('D')) thermalManager.temp_bed.pid.Kd = scalePID_d(parser.value_float());
} }
void GcodeSuite::M304_report(const bool forReplay/*=true*/) { void GcodeSuite::M304_report(const bool forReplay/*=true*/) {

View File

@@ -52,19 +52,19 @@ void GcodeSuite::M305() {
if (t_index >= (USER_THERMISTORS) || (do_set && t_index < 0)) if (t_index >= (USER_THERMISTORS) || (do_set && t_index < 0))
SERIAL_ECHO_MSG("!Invalid index. (0 <= P <= ", USER_THERMISTORS - 1, ")"); SERIAL_ECHO_MSG("!Invalid index. (0 <= P <= ", USER_THERMISTORS - 1, ")");
else if (do_set) { else if (do_set) {
if (parser.seen('R')) // Pullup resistor value if (parser.seenval('R')) // Pullup resistor value
if (!thermalManager.set_pull_up_res(t_index, parser.value_float())) if (!thermalManager.set_pull_up_res(t_index, parser.value_float()))
SERIAL_ECHO_MSG("!Invalid series resistance. (0 < R < 1000000)"); SERIAL_ECHO_MSG("!Invalid series resistance. (0 < R < 1000000)");
if (parser.seen('T')) // Resistance at 25C if (parser.seenval('T')) // Resistance at 25C
if (!thermalManager.set_res25(t_index, parser.value_float())) if (!thermalManager.set_res25(t_index, parser.value_float()))
SERIAL_ECHO_MSG("!Invalid 25C resistance. (0 < T < 10000000)"); SERIAL_ECHO_MSG("!Invalid 25C resistance. (0 < T < 10000000)");
if (parser.seen('B')) // Beta value if (parser.seenval('B')) // Beta value
if (!thermalManager.set_beta(t_index, parser.value_float())) if (!thermalManager.set_beta(t_index, parser.value_float()))
SERIAL_ECHO_MSG("!Invalid beta. (0 < B < 1000000)"); SERIAL_ECHO_MSG("!Invalid beta. (0 < B < 1000000)");
if (parser.seen('C')) // Steinhart-Hart C coefficient if (parser.seenval('C')) // Steinhart-Hart C coefficient
if (!thermalManager.set_sh_coeff(t_index, parser.value_float())) if (!thermalManager.set_sh_coeff(t_index, parser.value_float()))
SERIAL_ECHO_MSG("!Invalid Steinhart-Hart C coeff. (-0.01 < C < +0.01)"); SERIAL_ECHO_MSG("!Invalid Steinhart-Hart C coeff. (-0.01 < C < +0.01)");
} // If not setting then report parameters } // If not setting then report parameters

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

@@ -43,11 +43,11 @@ void GcodeSuite::M92() {
if (target_extruder < 0) return; if (target_extruder < 0) return;
// No arguments? Show M92 report. // No arguments? Show M92 report.
if (!parser.seen(LOGICAL_AXES_STRING TERN_(MAGIC_NUMBERS_GCODE, "HL"))) if (!parser.seen(STR_AXES_LOGICAL TERN_(MAGIC_NUMBERS_GCODE, "HL")))
return M92_report(true, target_extruder); return M92_report(true, target_extruder);
LOOP_LOGICAL_AXES(i) { LOOP_LOGICAL_AXES(i) {
if (parser.seenval(axis_codes[i])) { if (parser.seenval(AXIS_CHAR(i))) {
if (TERN1(HAS_EXTRUDERS, i != E_AXIS)) if (TERN1(HAS_EXTRUDERS, i != E_AXIS))
planner.settings.axis_steps_per_mm[i] = parser.value_per_axis_units((AxisEnum)i); planner.settings.axis_steps_per_mm[i] = parser.value_per_axis_units((AxisEnum)i);
else { else {
@@ -92,7 +92,7 @@ void GcodeSuite::M92() {
void GcodeSuite::M92_report(const bool forReplay/*=true*/, const int8_t e/*=-1*/) { void GcodeSuite::M92_report(const bool forReplay/*=true*/, const int8_t e/*=-1*/) {
report_heading_etc(forReplay, F(STR_STEPS_PER_UNIT)); report_heading_etc(forReplay, F(STR_STEPS_PER_UNIT));
SERIAL_ECHOPGM_P(LIST_N(DOUBLE(LINEAR_AXES), SERIAL_ECHOPGM_P(LIST_N(DOUBLE(NUM_AXES),
PSTR(" M92 X"), LINEAR_UNIT(planner.settings.axis_steps_per_mm[X_AXIS]), PSTR(" M92 X"), LINEAR_UNIT(planner.settings.axis_steps_per_mm[X_AXIS]),
SP_Y_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Y_AXIS]), SP_Y_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Y_AXIS]),
SP_Z_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Z_AXIS]), SP_Z_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Z_AXIS]),

View File

@@ -49,7 +49,7 @@ void GcodeSuite::M111() {
LOOP_L_N(i, COUNT(debug_strings)) { LOOP_L_N(i, COUNT(debug_strings)) {
if (TEST(marlin_debug_flags, i)) { if (TEST(marlin_debug_flags, i)) {
if (comma++) SERIAL_CHAR(','); if (comma++) SERIAL_CHAR(',');
SERIAL_ECHOPGM_P((char*)pgm_read_ptr(&debug_strings[i])); SERIAL_ECHOPGM_P((PGM_P)pgm_read_ptr(&debug_strings[i]));
} }
} }
} }

View File

@@ -23,6 +23,8 @@
#include "../gcode.h" #include "../gcode.h"
#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/planner.h"
#include "../../module/stepper.h" #include "../../module/stepper.h"
#if ENABLED(AUTO_BED_LEVELING_UBL) #if ENABLED(AUTO_BED_LEVELING_UBL)
@@ -43,10 +45,10 @@ inline stepper_flags_t selected_axis_bits() {
selected.bits = _BV(INDEX_OF_AXIS(E_AXIS, e)); selected.bits = _BV(INDEX_OF_AXIS(E_AXIS, e));
} }
else else
selected.bits = selected.e_bits(); selected.bits = e_axis_mask;
} }
#endif #endif
selected.bits |= LINEAR_AXIS_GANG( selected.bits |= NUM_AXIS_GANG(
(parser.seen_test('X') << X_AXIS), (parser.seen_test('X') << X_AXIS),
| (parser.seen_test('Y') << Y_AXIS), | (parser.seen_test('Y') << Y_AXIS),
| (parser.seen_test('Z') << Z_AXIS), | (parser.seen_test('Z') << Z_AXIS),
@@ -69,10 +71,10 @@ void do_enable(const stepper_flags_t to_enable) {
ena_mask_t also_enabled = 0; // Track steppers enabled due to overlap ena_mask_t also_enabled = 0; // Track steppers enabled due to overlap
// Enable all flagged axes // Enable all flagged axes
LOOP_LINEAR_AXES(a) { LOOP_NUM_AXES(a) {
if (TEST(shall_enable, a)) { if (TEST(shall_enable, a)) {
stepper.enable_axis(AxisEnum(a)); // Mark and enable the requested axis stepper.enable_axis(AxisEnum(a)); // Mark and enable the requested axis
DEBUG_ECHOLNPGM("Enabled ", axis_codes[a], " (", a, ") with overlap ", hex_word(enable_overlap[a]), " ... Enabled: ", hex_word(stepper.axis_enabled.bits)); DEBUG_ECHOLNPGM("Enabled ", AXIS_CHAR(a), " (", a, ") with overlap ", hex_word(enable_overlap[a]), " ... Enabled: ", hex_word(stepper.axis_enabled.bits));
also_enabled |= enable_overlap[a]; also_enabled |= enable_overlap[a];
} }
} }
@@ -89,7 +91,7 @@ void do_enable(const stepper_flags_t to_enable) {
if ((also_enabled &= ~(shall_enable | was_enabled))) { if ((also_enabled &= ~(shall_enable | was_enabled))) {
SERIAL_CHAR('('); SERIAL_CHAR('(');
LOOP_LINEAR_AXES(a) if (TEST(also_enabled, a)) SERIAL_CHAR(axis_codes[a], ' '); LOOP_NUM_AXES(a) if (TEST(also_enabled, a)) SERIAL_CHAR(AXIS_CHAR(a), ' ');
#if HAS_EXTRUDERS #if HAS_EXTRUDERS
#define _EN_ALSO(N) if (TEST(also_enabled, INDEX_OF_AXIS(E_AXIS, N))) SERIAL_CHAR('E', '0' + N, ' '); #define _EN_ALSO(N) if (TEST(also_enabled, INDEX_OF_AXIS(E_AXIS, N))) SERIAL_CHAR('E', '0' + N, ' ');
REPEAT(EXTRUDERS, _EN_ALSO) REPEAT(EXTRUDERS, _EN_ALSO)
@@ -125,14 +127,8 @@ void GcodeSuite::M17() {
stepper.enable_e_steppers(); stepper.enable_e_steppers();
} }
#endif #endif
LINEAR_AXIS_CODE( LOOP_NUM_AXES(a)
if (parser.seen_test('X')) stepper.enable_axis(X_AXIS), if (parser.seen_test(AXIS_CHAR(a))) stepper.enable_axis((AxisEnum)a);
if (parser.seen_test('Y')) stepper.enable_axis(Y_AXIS),
if (parser.seen_test('Z')) stepper.enable_axis(Z_AXIS),
if (parser.seen_test(AXIS4_NAME)) stepper.enable_axis(I_AXIS),
if (parser.seen_test(AXIS5_NAME)) stepper.enable_axis(J_AXIS),
if (parser.seen_test(AXIS6_NAME)) stepper.enable_axis(K_AXIS)
);
} }
} }
else { else {
@@ -149,9 +145,9 @@ void try_to_disable(const stepper_flags_t to_disable) {
if (!still_enabled) return; if (!still_enabled) return;
// Attempt to disable all flagged axes // Attempt to disable all flagged axes
LOOP_LINEAR_AXES(a) LOOP_NUM_AXES(a)
if (TEST(to_disable.bits, a)) { if (TEST(to_disable.bits, a)) {
DEBUG_ECHOPGM("Try to disable ", axis_codes[a], " (", a, ") with overlap ", hex_word(enable_overlap[a]), " ... "); DEBUG_ECHOPGM("Try to disable ", AXIS_CHAR(a), " (", a, ") with overlap ", hex_word(enable_overlap[a]), " ... ");
if (stepper.disable_axis(AxisEnum(a))) { // Mark the requested axis and request to disable if (stepper.disable_axis(AxisEnum(a))) { // Mark the requested axis and request to disable
DEBUG_ECHOPGM("OK"); DEBUG_ECHOPGM("OK");
still_enabled &= ~(_BV(a) | enable_overlap[a]); // If actually disabled, clear one or more tracked bits still_enabled &= ~(_BV(a) | enable_overlap[a]); // If actually disabled, clear one or more tracked bits
@@ -178,7 +174,7 @@ void try_to_disable(const stepper_flags_t to_disable) {
auto overlap_warning = [](const ena_mask_t axis_bits) { auto overlap_warning = [](const ena_mask_t axis_bits) {
SERIAL_ECHOPGM(" not disabled. Shared with"); SERIAL_ECHOPGM(" not disabled. Shared with");
LOOP_LINEAR_AXES(a) if (TEST(axis_bits, a)) SERIAL_CHAR(' ', axis_codes[a]); LOOP_NUM_AXES(a) if (TEST(axis_bits, a)) SERIAL_ECHOPGM_P((PGM_P)pgm_read_ptr(&SP_AXIS_STR[a]));
#if HAS_EXTRUDERS #if HAS_EXTRUDERS
#define _EN_STILLON(N) if (TEST(axis_bits, INDEX_OF_AXIS(E_AXIS, N))) SERIAL_CHAR(' ', 'E', '0' + N); #define _EN_STILLON(N) if (TEST(axis_bits, INDEX_OF_AXIS(E_AXIS, N))) SERIAL_CHAR(' ', 'E', '0' + N);
REPEAT(EXTRUDERS, _EN_STILLON) REPEAT(EXTRUDERS, _EN_STILLON)
@@ -187,9 +183,9 @@ void try_to_disable(const stepper_flags_t to_disable) {
}; };
// If any of the requested axes are still enabled, give a warning // If any of the requested axes are still enabled, give a warning
LOOP_LINEAR_AXES(a) { LOOP_NUM_AXES(a) {
if (TEST(still_enabled, a)) { if (TEST(still_enabled, a)) {
SERIAL_CHAR(axis_codes[a]); SERIAL_CHAR(AXIS_CHAR(a));
overlap_warning(stepper.axis_enabled.bits & enable_overlap[a]); overlap_warning(stepper.axis_enabled.bits & enable_overlap[a]);
} }
} }
@@ -238,14 +234,8 @@ void GcodeSuite::M18_M84() {
stepper.disable_e_steppers(); stepper.disable_e_steppers();
} }
#endif #endif
LINEAR_AXIS_CODE( LOOP_NUM_AXES(a)
if (parser.seen_test('X')) stepper.disable_axis(X_AXIS), if (parser.seen_test(AXIS_CHAR(a))) stepper.disable_axis((AxisEnum)a);
if (parser.seen_test('Y')) stepper.disable_axis(Y_AXIS),
if (parser.seen_test('Z')) stepper.disable_axis(Z_AXIS),
if (parser.seen_test(AXIS4_NAME)) stepper.disable_axis(I_AXIS),
if (parser.seen_test(AXIS5_NAME)) stepper.disable_axis(J_AXIS),
if (parser.seen_test(AXIS6_NAME)) stepper.disable_axis(K_AXIS)
);
} }
} }
else else

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

@@ -48,7 +48,7 @@ void GcodeSuite::M280() {
const int anew = parser.value_int(); const int anew = parser.value_int();
if (anew >= 0) { if (anew >= 0) {
#if ENABLED(POLARGRAPH) #if ENABLED(POLARGRAPH)
if (parser.seen('T')) { // (ms) Total duration of servo move if (parser.seenval('T')) { // (ms) Total duration of servo move
const int16_t t = constrain(parser.value_int(), 0, 10000); const int16_t t = constrain(parser.value_int(), 0, 10000);
const int aold = servo[servo_index].read(); const int aold = servo[servo_index].read();
millis_t now = millis(); millis_t now = millis();
@@ -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.seen('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

@@ -27,35 +27,45 @@
#include "../gcode.h" #include "../gcode.h"
#include "../../module/stepper.h" #include "../../module/stepper.h"
#if NUM_AXES == XYZ && EXTRUDERS >= 1
#define HAS_M350_B_PARAM 1 // "5th axis" (after E0) for an original XYZEB setup.
#if AXIS_COLLISION('B')
#error "M350 parameter 'B' collision with axis name."
#endif
#endif
/** /**
* M350: Set axis microstepping modes. S sets mode for all drivers. * M350: Set axis microstepping modes. S sets mode for all drivers.
* *
* Warning: Steps-per-unit remains unchanged. * Warning: Steps-per-unit remains unchanged.
*/ */
void GcodeSuite::M350() { void GcodeSuite::M350() {
if (parser.seen('S')) LOOP_LE_N(i, 4) stepper.microstep_mode(i, parser.value_byte()); if (parser.seen('S')) LOOP_DISTINCT_AXES(i) stepper.microstep_mode(i, parser.value_byte());
LOOP_LOGICAL_AXES(i) if (parser.seen(axis_codes[i])) stepper.microstep_mode(i, parser.value_byte()); LOOP_LOGICAL_AXES(i) if (parser.seenval(AXIS_CHAR(i))) stepper.microstep_mode(i, parser.value_byte());
if (parser.seen('B')) stepper.microstep_mode(4, parser.value_byte()); TERN_(HAS_M350_B_PARAM, if (parser.seenval('B')) stepper.microstep_mode(E_AXIS + 1, parser.value_byte()));
stepper.microstep_readings(); stepper.microstep_readings();
} }
/** /**
* M351: Toggle MS1 MS2 pins directly with axis codes X Y Z E B * M351: Toggle MS1 MS2 pins directly with axis codes X Y Z . . . E [B]
* S# determines MS1, MS2 or MS3, X# sets the pin high/low. * S# determines MS1, MS2 or MS3, X# sets the pin high/low.
*
* Parameter 'B' sets "5th axis" (after E0) only for an original XYZEB setup.
*/ */
void GcodeSuite::M351() { void GcodeSuite::M351() {
const int8_t bval = TERN(HAS_M350_B_PARAM, parser.byteval('B', -1), -1); UNUSED(bval);
if (parser.seenval('S')) switch (parser.value_byte()) { if (parser.seenval('S')) switch (parser.value_byte()) {
case 1: case 1:
LOOP_LOGICAL_AXES(i) if (parser.seenval(axis_codes[i])) stepper.microstep_ms(i, parser.value_byte(), -1, -1); LOOP_LOGICAL_AXES(i) if (parser.seenval(AXIS_CHAR(i))) stepper.microstep_ms(i, parser.value_byte(), -1, -1);
if (parser.seenval('B')) stepper.microstep_ms(4, parser.value_byte(), -1, -1); TERN_(HAS_M350_B_PARAM, if (bval >= 0) stepper.microstep_ms(E_AXIS + 1, bval != 0, -1, -1));
break; break;
case 2: case 2:
LOOP_LOGICAL_AXES(i) if (parser.seenval(axis_codes[i])) stepper.microstep_ms(i, -1, parser.value_byte(), -1); LOOP_LOGICAL_AXES(i) if (parser.seenval(AXIS_CHAR(i))) stepper.microstep_ms(i, -1, parser.value_byte(), -1);
if (parser.seenval('B')) stepper.microstep_ms(4, -1, parser.value_byte(), -1); TERN_(HAS_M350_B_PARAM, if (bval >= 0) stepper.microstep_ms(E_AXIS + 1, -1, bval != 0, -1));
break; break;
case 3: case 3:
LOOP_LOGICAL_AXES(i) if (parser.seenval(axis_codes[i])) stepper.microstep_ms(i, -1, -1, parser.value_byte()); LOOP_LOGICAL_AXES(i) if (parser.seenval(AXIS_CHAR(i))) stepper.microstep_ms(i, -1, -1, parser.value_byte());
if (parser.seenval('B')) stepper.microstep_ms(4, -1, -1, parser.value_byte()); TERN_(HAS_M350_B_PARAM, if (bval >= 0) stepper.microstep_ms(E_AXIS + 1, -1, -1, bval != 0));
break; break;
} }
stepper.microstep_readings(); stepper.microstep_readings();

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"
@@ -64,7 +63,7 @@
void GcodeSuite::M605() { void GcodeSuite::M605() {
planner.synchronize(); planner.synchronize();
if (parser.seen('S')) { if (parser.seenval('S')) {
const DualXMode previous_mode = dual_x_carriage_mode; const DualXMode previous_mode = dual_x_carriage_mode;
dual_x_carriage_mode = (DualXMode)parser.value_byte(); dual_x_carriage_mode = (DualXMode)parser.value_byte();
@@ -78,8 +77,8 @@
case DXC_DUPLICATION_MODE: case DXC_DUPLICATION_MODE:
// Set the X offset, but no less than the safety gap // Set the X offset, but no less than the safety gap
if (parser.seen('X')) duplicate_extruder_x_offset = _MAX(parser.value_linear_units(), (X2_MIN_POS) - (X1_MIN_POS)); if (parser.seenval('X')) duplicate_extruder_x_offset = _MAX(parser.value_linear_units(), (X2_MIN_POS) - (X1_MIN_POS));
if (parser.seen('R')) duplicate_extruder_temp_offset = parser.value_celsius_diff(); if (parser.seenval('R')) duplicate_extruder_temp_offset = parser.value_celsius_diff();
// Always switch back to tool 0 // Always switch back to tool 0
if (active_extruder != 0) tool_change(0); if (active_extruder != 0) tool_change(0);
break; break;
@@ -146,7 +145,7 @@
HOTEND_LOOP() { HOTEND_LOOP() {
DEBUG_ECHOPGM_P(SP_T_STR, e); DEBUG_ECHOPGM_P(SP_T_STR, e);
LOOP_LINEAR_AXES(a) DEBUG_ECHOPGM(" hotend_offset[", e, "].", AS_CHAR(AXIS_CHAR(a) | 0x20), "=", hotend_offset[e][a]); LOOP_NUM_AXES(a) DEBUG_ECHOPGM(" hotend_offset[", e, "].", AS_CHAR(AXIS_CHAR(a) | 0x20), "=", hotend_offset[e][a]);
DEBUG_EOL(); DEBUG_EOL();
} }
DEBUG_EOL(); DEBUG_EOL();

View File

@@ -25,7 +25,7 @@
#if HAS_L64XX #if HAS_L64XX
#if AXIS_COLLISION('I') #if AXIS_COLLISION('I')
#error "M906 parameter collision with axis name." #error "M906 parameter 'I' collision with axis name."
#endif #endif
#include "../../gcode.h" #include "../../gcode.h"
@@ -211,7 +211,7 @@ void L64XX_report_current(L64XX &motor, const L64XX_axis_t axis) {
* 1 - monitor only X2, Y2, Z2 * 1 - monitor only X2, Y2, Z2
* 2 - monitor only Z3 * 2 - monitor only Z3
* 3 - monitor only Z4 * 3 - monitor only Z4
* Xxxx, Yxxx, Zxxx, Exxx - axis to change (optional) * Xxxx, Yxxx, Zxxx, Axxx, Bxxx, Cxxx, Exxx - axis to change (optional)
* L6474 - current in mA (4A max) * L6474 - current in mA (4A max)
* All others - 0-255 * All others - 0-255
* *
@@ -236,7 +236,7 @@ void GcodeSuite::M906() {
constexpr int8_t index = -1; constexpr int8_t index = -1;
#endif #endif
LOOP_LOGICAL_AXES(i) if (uint16_t value = parser.intval(axis_codes[i])) { LOOP_LOGICAL_AXES(i) if (uint16_t value = parser.intval(AXIS_CHAR(i))) {
report_current = false; report_current = false;

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

@@ -44,14 +44,14 @@ void GcodeSuite::M486() {
cancelable.object_count = parser.intval('T', 1); cancelable.object_count = parser.intval('T', 1);
} }
if (parser.seen('S')) if (parser.seenval('S'))
cancelable.set_active_object(parser.value_int()); cancelable.set_active_object(parser.value_int());
if (parser.seen('C')) cancelable.cancel_active_object(); if (parser.seen('C')) cancelable.cancel_active_object();
if (parser.seen('P')) cancelable.cancel_object(parser.value_int()); if (parser.seenval('P')) cancelable.cancel_object(parser.value_int());
if (parser.seen('U')) cancelable.uncancel_object(parser.value_int()); if (parser.seenval('U')) cancelable.uncancel_object(parser.value_int());
} }
#endif // CANCEL_OBJECTS #endif // CANCEL_OBJECTS

View File

@@ -45,9 +45,10 @@
* X, Y, Z : Specify axes to move during cleaning. Default: ALL. * X, Y, Z : Specify axes to move during cleaning. Default: ALL.
*/ */
void GcodeSuite::G12() { void GcodeSuite::G12() {
// Don't allow nozzle cleaning without homing first // Don't allow nozzle cleaning without homing first
if (homing_needed_error(linear_bits & ~TERN0(NOZZLE_CLEAN_NO_Z, Z_AXIS) & ~TERN0(NOZZLE_CLEAN_NO_Y, Y_AXIS))) constexpr main_axes_bits_t clean_axis_mask = main_axes_mask & ~TERN0(NOZZLE_CLEAN_NO_Z, Z_AXIS) & ~TERN0(NOZZLE_CLEAN_NO_Y, Y_AXIS);
return; if (homing_needed_error(clean_axis_mask)) return;
#ifdef WIPE_SEQUENCE_COMMANDS #ifdef WIPE_SEQUENCE_COMMANDS
if (!parser.seen_any()) { if (!parser.seen_any()) {

View File

@@ -39,53 +39,76 @@
#endif #endif
/** /**
* M907: Set digital trimpot motor current using axis codes X [Y] [Z] [E] * M907: Set digital trimpot motor current using axis codes X [Y] [Z] [I] [J] [K] [E]
* B<current> - Special case for 4th (E) axis * B<current> - Special case for E1 (Requires DIGIPOTSS_PIN or DIGIPOT_MCP4018 or DIGIPOT_MCP4451)
* S<current> - Special case to set first 3 axes * C<current> - Special case for E2 (Requires DIGIPOTSS_PIN or DIGIPOT_MCP4018 or DIGIPOT_MCP4451)
* S<current> - Set current in mA for all axes (Requires DIGIPOTSS_PIN or DIGIPOT_MCP4018 or DIGIPOT_MCP4451), or
* Set percentage of max current for all axes (Requires HAS_DIGIPOT_DAC)
*/ */
void GcodeSuite::M907() { void GcodeSuite::M907() {
#if HAS_MOTOR_CURRENT_SPI #if HAS_MOTOR_CURRENT_SPI
if (!parser.seen("BS" LOGICAL_AXES_STRING)) if (!parser.seen("BS" STR_AXES_LOGICAL))
return M907_report(); return M907_report();
LOOP_LOGICAL_AXES(i) if (parser.seenval(axis_codes[i])) stepper.set_digipot_current(i, parser.value_int()); if (parser.seenval('S')) LOOP_L_N(i, MOTOR_CURRENT_COUNT) stepper.set_digipot_current(i, parser.value_int());
if (parser.seenval('B')) stepper.set_digipot_current(4, parser.value_int()); LOOP_LOGICAL_AXES(i) if (parser.seenval(IAXIS_CHAR(i))) stepper.set_digipot_current(i, parser.value_int()); // X Y Z (I J K) E (map to drivers according to DIGIPOT_CHANNELS. Default with NUM_AXES 3: map X Y Z E to X Y Z E0)
if (parser.seenval('S')) LOOP_LE_N(i, 4) stepper.set_digipot_current(i, parser.value_int()); // Additional extruders use B,C.
// TODO: Change these parameters because 'E' is used and D should be reserved for debugging. B<index>?
#if E_STEPPERS >= 2
if (parser.seenval('B')) stepper.set_digipot_current(E_AXIS + 1, parser.value_int());
#if E_STEPPERS >= 3
if (parser.seenval('C')) stepper.set_digipot_current(E_AXIS + 2, parser.value_int());
#endif
#endif
#elif HAS_MOTOR_CURRENT_PWM #elif HAS_MOTOR_CURRENT_PWM
if (!parser.seen( #if ANY_PIN(MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y, MOTOR_CURRENT_PWM_XY, MOTOR_CURRENT_PWM_I, MOTOR_CURRENT_PWM_J, MOTOR_CURRENT_PWM_K)
#if ANY_PIN(MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y, MOTOR_CURRENT_PWM_XY) #define HAS_X_Y_XY_I_J_K 1
"XY" #endif
#if HAS_X_Y_XY_I_J_K || ANY_PIN(MOTOR_CURRENT_PWM_E, MOTOR_CURRENT_PWM_Z)
if (!parser.seen("S"
#if HAS_X_Y_XY_I_J_K
"XY" SECONDARY_AXIS_GANG("I", "J", "K")
#endif
#if PIN_EXISTS(MOTOR_CURRENT_PWM_Z)
"Z"
#endif
#if PIN_EXISTS(MOTOR_CURRENT_PWM_E)
"E"
#endif
)) return M907_report();
if (parser.seenval('S')) LOOP_L_N(a, MOTOR_CURRENT_COUNT) stepper.set_digipot_current(a, parser.value_int());
#if HAS_X_Y_XY_I_J_K
if (NUM_AXIS_GANG(
parser.seenval('X'), || parser.seenval('Y'), || false,
|| parser.seenval('I'), || parser.seenval('J'), || parser.seenval('K')
)) stepper.set_digipot_current(0, parser.value_int());
#endif #endif
#if PIN_EXISTS(MOTOR_CURRENT_PWM_Z) #if PIN_EXISTS(MOTOR_CURRENT_PWM_Z)
"Z" if (parser.seenval('Z')) stepper.set_digipot_current(1, parser.value_int());
#endif #endif
#if PIN_EXISTS(MOTOR_CURRENT_PWM_E) #if PIN_EXISTS(MOTOR_CURRENT_PWM_E)
"E" if (parser.seenval('E')) stepper.set_digipot_current(2, parser.value_int());
#endif #endif
)) return M907_report();
#if ANY_PIN(MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y, MOTOR_CURRENT_PWM_XY)
if (parser.seenval('X') || parser.seenval('Y')) stepper.set_digipot_current(0, parser.value_int());
#endif
#if PIN_EXISTS(MOTOR_CURRENT_PWM_Z)
if (parser.seenval('Z')) stepper.set_digipot_current(1, parser.value_int());
#endif
#if PIN_EXISTS(MOTOR_CURRENT_PWM_E)
if (parser.seenval('E')) stepper.set_digipot_current(2, parser.value_int());
#endif #endif
#endif // HAS_MOTOR_CURRENT_PWM #endif // HAS_MOTOR_CURRENT_PWM
#if HAS_MOTOR_CURRENT_I2C #if HAS_MOTOR_CURRENT_I2C
// this one uses actual amps in floating point // this one uses actual amps in floating point
LOOP_LOGICAL_AXES(i) if (parser.seenval(axis_codes[i])) digipot_i2c.set_current(i, parser.value_float()); if (parser.seenval('S')) LOOP_L_N(q, DIGIPOT_I2C_NUM_CHANNELS) digipot_i2c.set_current(q, parser.value_float());
// Additional extruders use B,C,D for channels 4,5,6. LOOP_LOGICAL_AXES(i) if (parser.seenval(IAXIS_CHAR(i))) digipot_i2c.set_current(i, parser.value_float()); // X Y Z (I J K) E (map to drivers according to pots adresses. Default with NUM_AXES 3 X Y Z E: map to X Y Z E0)
// TODO: Change these parameters because 'E' is used. B<index>? // Additional extruders use B,C,D.
#if HAS_EXTRUDERS // TODO: Change these parameters because 'E' is used and because 'D' should be reserved for debugging. B<index>?
for (uint8_t i = E_AXIS + 1; i < DIGIPOT_I2C_NUM_CHANNELS; i++) #if E_STEPPERS >= 2
for (uint8_t i = E_AXIS + 1; i <= _MIN(DIGIPOT_I2C_NUM_CHANNELS - 1, E_AXIS + 3); i++) // Up to B=E1 C=E2 D=E3
if (parser.seenval('B' + i - (E_AXIS + 1))) digipot_i2c.set_current(i, parser.value_float()); if (parser.seenval('B' + i - (E_AXIS + 1))) digipot_i2c.set_current(i, parser.value_float());
#endif #endif
#endif #endif
@@ -93,9 +116,9 @@ void GcodeSuite::M907() {
#if HAS_MOTOR_CURRENT_DAC #if HAS_MOTOR_CURRENT_DAC
if (parser.seenval('S')) { if (parser.seenval('S')) {
const float dac_percent = parser.value_float(); const float dac_percent = parser.value_float();
LOOP_LE_N(i, 4) stepper_dac.set_current_percent(i, dac_percent); LOOP_LOGICAL_AXES(i) stepper_dac.set_current_percent(i, dac_percent);
} }
LOOP_LOGICAL_AXES(i) if (parser.seenval(axis_codes[i])) stepper_dac.set_current_percent(i, parser.value_float()); LOOP_LOGICAL_AXES(i) if (parser.seenval(IAXIS_CHAR(i))) stepper_dac.set_current_percent(i, parser.value_float()); // X Y Z (I J K) E (map to drivers according to DAC_STEPPER_ORDER. Default with NUM_AXES 3: X Y Z E map to X Y Z E0)
#endif #endif
} }
@@ -104,19 +127,25 @@ void GcodeSuite::M907() {
void GcodeSuite::M907_report(const bool forReplay/*=true*/) { void GcodeSuite::M907_report(const bool forReplay/*=true*/) {
report_heading_etc(forReplay, F(STR_STEPPER_MOTOR_CURRENTS)); report_heading_etc(forReplay, F(STR_STEPPER_MOTOR_CURRENTS));
#if HAS_MOTOR_CURRENT_PWM #if HAS_MOTOR_CURRENT_PWM
SERIAL_ECHOLNPGM_P( // PWM-based has 3 values: SERIAL_ECHOLNPGM_P( // PWM-based has 3 values:
PSTR(" M907 X"), stepper.motor_current_setting[0] // X and Y PSTR(" M907 X"), stepper.motor_current_setting[0] // X, Y, (I, J, K)
, SP_Z_STR, stepper.motor_current_setting[1] // Z , SP_Z_STR, stepper.motor_current_setting[1] // Z
, SP_E_STR, stepper.motor_current_setting[2] // E , SP_E_STR, stepper.motor_current_setting[2] // E
); );
#elif HAS_MOTOR_CURRENT_SPI #elif HAS_MOTOR_CURRENT_SPI
SERIAL_ECHOPGM(" M907"); // SPI-based has 5 values: SERIAL_ECHOPGM(" M907"); // SPI-based has 5 values:
LOOP_LOGICAL_AXES(q) { // X Y Z (I J K) E (map to X Y Z (I J K) E0 by default) LOOP_LOGICAL_AXES(q) { // X Y Z (I J K) E (map to X Y Z (I J K) E0 by default)
SERIAL_CHAR(' ', axis_codes[q]); SERIAL_CHAR(' ', IAXIS_CHAR(q));
SERIAL_ECHO(stepper.motor_current_setting[q]); SERIAL_ECHO(stepper.motor_current_setting[q]);
} }
SERIAL_CHAR(' ', 'B'); // B (maps to E1 by default) #if E_STEPPERS >= 2
SERIAL_ECHOLN(stepper.motor_current_setting[4]); SERIAL_ECHOPGM_P(PSTR(" B"), stepper.motor_current_setting[E_AXIS + 1] // B (maps to E1 with NUM_AXES 3 according to DIGIPOT_CHANNELS)
#if E_STEPPERS >= 3
, PSTR(" C"), stepper.motor_current_setting[E_AXIS + 2] // C (mapping to E2 must be defined by DIGIPOT_CHANNELS)
#endif
);
#endif
SERIAL_EOL();
#endif #endif
} }

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