Compare commits

...

108 Commits

Author SHA1 Message Date
a7eaf9cc97 Add BLTouch bed leveling 2022-08-04 07:33:35 -07:00
f16d92d39d Update PID values for hotend, bed
Also enable PID for bed
2022-08-03 17:30:52 -07:00
Danny Oh
aaf23d46af Reverts changes from 2b2db885088b61938bf476b9c10eafef9fe8d021 2022-07-28 12:47:49 -07:00
Danny Oh
2bc2307cdc Merge tag '2.0.9.5' into 2.0.9.5-rigidbot 2022-07-28 11:05:14 -07:00
Danny Oh
2b2db88508 Commit existing changes
- not sure if this is what is currently flashed
2022-07-28 10:35:42 -07:00
Scott Lahteine
5312bdedf9 🔖 Marlin 2.0.9.5 2022-07-27 22:20:42 -05:00
Ludy
36d508c5a0 🌐 Update German language (#24555) 2022-07-27 22:20:02 -05:00
Scott Lahteine
9f5aab1a61 🧑‍💻 Update planner/stepper includes 2022-07-27 22:20:02 -05:00
Scott Lahteine
62d29ade42 🩹 Fix lcd_preheat compile 2022-07-27 22:20:02 -05:00
Scott Lahteine
c801cc4830 🔨 Update build/CI scripts 2022-07-27 22:20:02 -05:00
Scott Lahteine
bc91b1cdcd 🎨 PIO scripts cleanup 2022-07-27 22:20:02 -05:00
Keith Bennett
c847ef02a1 📺 Fix TFT Classic UI non-Touchscreen 1024x600 (#24541) 2022-07-27 22:20:02 -05:00
Keith Bennett
cdda90f56c 📝 Update MPCTEMP G-Code M306 T (#24535)
M306 simply reports current values. M306 T starts autotune process.
2022-07-27 22:20:02 -05:00
Scott Lahteine
ad4bc378b7 📝 Update Driver Type comments 2022-07-27 22:20:02 -05:00
Scott Lahteine
99710b94d2 🎨 Clean up extra axes
Followup to #24120
2022-07-23 19:58:48 -05:00
Scott Lahteine
78fc5acca9 🔨 Add mftest --default flag 2022-07-23 19:57:43 -05:00
Arthur Masson
e616542c89 Polargraph M665 settings (#24401) 2022-07-23 19:57:43 -05:00
Scott Lahteine
a50bb96d2d 🔨 Fix Warnings.cpp force-recompile 2022-07-23 19:57:43 -05:00
Scott Lahteine
653f0ab9dd 🔨 Fix and update Makefile
Followup to 89fe5f6d
2022-07-23 19:57:43 -05:00
Jason Smith
c96ed8998b 🩹 Fix LCD_BACKLIGHT_TIMEOUT compile (#24463) 2022-07-23 19:57:43 -05:00
Mike La Spina
b025c18d5b ️ Fix and improve Inline Laser Power (#22690) 2022-07-23 19:57:43 -05:00
tombrazier
b49da1d4ca 💥 More M306 M => M306 H (#24258)
Followup to #24253
2022-07-23 19:57:43 -05:00
Keith Bennett
90074e6260 🎨 Fix/adjust warnings (#24225, #24404) 2022-07-23 19:57:43 -05:00
Scott Lahteine
e570c4cc2e 🧑‍💻 Forward-compatible axis strings 2022-07-23 19:57:43 -05:00
DerAndere
543bbf02fc 💥 Update Motor Current G-codes for extra axes (#23975) 2022-07-23 19:57:43 -05:00
Scott Lahteine
5ccdc9ced7 🏗️ Axis name arrays
Co-Authored-By: DerAndere <26200979+DerAndere1@users.noreply.github.com>
2022-07-23 19:57:43 -05:00
Scott Lahteine
ddb0168e29 ♻️ More updates for multi-axis 2022-07-23 19:57:43 -05:00
GHGiampy
0caf234aa5 🔨 Fix firmware upload (#24499) 2022-07-23 19:57:43 -05:00
Scott Lahteine
dddbc4d730 🔨 PlatformIO "--target upload" == "--target exec" 2022-07-23 19:57:43 -05:00
Scott Lahteine
08e6e8b9be ♻️ Encapsulate PID in class (#24389) 2022-07-23 19:57:43 -05:00
Victor Oliveira
12ae80bcec 🔨 Disable stack protector on macOS simulator (#24443) 2022-07-23 19:57:43 -05:00
Eduard Sukharev
9e530cd27b 🐛 Fix MKS TinyBee compile (#24454) 2022-07-23 19:57:43 -05:00
EvilGremlin
0ec1cb58c7 🔨 Fix OpenBLT encode; no-bootloader envs (#24446) 2022-07-23 19:57:43 -05:00
Scott Lahteine
b548e21b65 ♻️ reset_acceleration_rates => refresh_… 2022-07-23 19:57:43 -05:00
Scott Lahteine
e170460855 ♻️ Planner flags refactor 2022-07-23 19:57:43 -05:00
lujios
b7b2286e49 ️ 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-07-23 19:57:43 -05:00
elimisback
047d0264c5 🔨 BTT STM32G0B1RE xfer build (#24245) 2022-07-23 19:57:43 -05:00
Scott Lahteine
c56fb1c182 🎨 Minimize block->steps.set 2022-07-23 19:57:43 -05:00
DerAndere
d5a79c27fe ♻️ More updates for multi-axis
Based on #23112

Co-Authored-By: Scott Lahteine <thinkyhead@users.noreply.github.com>
2022-07-23 19:57:43 -05:00
Scott Lahteine
1e3fe65b9d 🚨 Fix some compiler warnings 2022-07-23 19:57:43 -05:00
Scott Lahteine
af4160af6f 🐛 Fix types.h macros and fields
Fixes #24419
2022-07-23 19:57:43 -05:00
Scott Lahteine
53b73bbd7f 🔧 Config parity with 2.1.x 2022-07-23 19:57:42 -05:00
Scott Lahteine
3b37e85949 🚸 Arrange EXP pins in common order (#24525) 2022-07-23 19:57:42 -05:00
Keith Bennett
a1881f70a8 MKS Monster8 V2 (#24483) 2022-07-23 19:57:42 -05:00
Christophe Huriaux
6ad7f7ce98 eMotion-Tech eMotronic (Micro-Delta rework) (#24488) 2022-07-23 19:57:42 -05:00
Victor Oliveira
9fe4d2cc6c Creality3D v4.2.5 / CR200B (#24491) 2022-07-23 19:57:42 -05:00
Keith Bennett
5bd0541985 BigTreeTech SKR SE BX V3.0 (#24449)
SKR SE BX V3.0 removes the Reverse Driver Protection feature.
2022-07-23 19:57:42 -05:00
Scott Lahteine
35d5393a3e 📝 Index Mobo Rev03 => Opulo Lumen Rev3 2022-07-23 19:57:42 -05:00
DerAndere
1ffc4ba861 🩹 Fix some parameters w/out values (#24051) 2022-07-23 19:57:42 -05:00
Scott Lahteine
2bf6573098 🐛 Fix SDIO for STM32 (#24470)
Followup to #24271
2022-07-23 19:57:42 -05:00
Scott Lahteine
5e0a39265a 🎨 Clean up extra axes
Followup to #24120
2022-07-23 19:15:22 -05:00
tombrazier
495002e158 🐛 Fix 2d mesh print (#24536) 2022-07-22 23:34:53 -05:00
Scott Lahteine
adeca47292 🔨 Fix Warnings.cpp force-recompile 2022-07-14 21:08:50 -05:00
Scott Lahteine
686d1fbb51 🎨 ANY => EITHER 2022-07-13 21:25:12 -05:00
Scott Lahteine
8f84ce72e1 Fix SDIO for STM32
Followup to #24271
2022-07-09 18:19:41 -05:00
Keith Bennett
5bf02e39a9 🚸 MPCTEMP: Home before cooling (#24434) 2022-07-04 00:29:45 -05:00
Keith Bennett
a5b076dff7 🩹 Fix MKS TinyBee ADC Vref (#24432) 2022-07-04 00:29:45 -05:00
Scott Lahteine
b79231cc59 🩹 Remove poison wchar_t macro 2022-07-04 00:29:45 -05:00
Scott Lahteine
86e6f9e38e 🩹 Remove obsolete split_move 2022-07-01 21:19:06 -05:00
Moonglow
b3018da60c 🐛 Fix M149 (#24430) 2022-07-01 08:01:03 -05:00
Scott Lahteine
0d04aa960f 🩹 Fix memset block warning 2022-07-01 08:01:03 -05:00
Keith Bennett
0d34c2e287 🐛 Fix Axis Homing (#24425)
Followup to 4520a51
2022-07-01 08:01:03 -05:00
John Lagonikas
1690f49656 🐛 Fix MAX31865 PT1000 normalization (#24407)
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
2022-07-01 08:01:03 -05:00
Scott Lahteine
dbdb39f60f 📝 Note about UBL bad splits 2022-07-01 08:01:03 -05:00
Scott Lahteine
843c04baa6 🎨 Misc. shorthand operators 2022-06-26 10:02:24 -05:00
Scott Lahteine
a7c58c1fd6 🐛 Fix Manual Move axis selection (#24404) 2022-06-26 06:50:24 -05:00
Shlee
3af5c32ea2 📝 Add STM32F4 example, Ruby (#24399) 2022-06-26 06:39:37 -05:00
Giuliano Zaro
4039075a1d 🌐 Update Italian language (#24398) 2022-06-26 06:39:37 -05:00
Roman Moravčík
ed796c8354 🌐 Update Slovak language (#24397) 2022-06-26 06:39:37 -05:00
sgparry
f3c64fd397 🩹 Fix LCD contrast with K8800 board 2022-06-26 06:39:37 -05:00
Scott Lahteine
b220342b26 🌐 Drop unused delta strings 2022-06-24 22:09:51 -05:00
InsanityAutomation
4dad587188 🐛 Resolve DUE Servo pulse issue (#24305)
Co-authored-by: sjasonsmith <20053467+sjasonsmith@users.noreply.github.com>
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
2022-06-24 18:02:21 -05:00
tombrazier
1efe48ef65 🐛 Fix G2/G3 Arcs stutter / JD speed (#24362) 2022-06-24 18:02:21 -05:00
Bob Kuhn
ae8365a4e5 🐛 Fix Lerdge build / encrypt (#24391)
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
2022-06-24 18:02:21 -05:00
Victor Oliveira
dd68461bb1 Classic UI BIQU BX (#24387) 2022-06-24 18:02:21 -05:00
ellensp
010fbcccf7 🩹 Fix DGUS (MKS) compile (#24378) 2022-06-24 18:02:21 -05:00
Victor Oliveira
185fe5696c 🚑️ Fix BIQU BX touch freeze (#24383) 2022-06-24 18:02:21 -05:00
ellensp
7edd37bc5a 🐛 Fix M423 invocation (#24360)
Followup to #23745
2022-06-24 18:02:21 -05:00
tombrazier
0000427021 🩹 LCD strings followup, fix warning (#24328) 2022-06-24 18:02:21 -05:00
ellensp
0d1d125bc6 🚑️ Fix SD mount bug (#24319)
Co-authored-by: Scott Lahteine <github@thinkyhead.com>
2022-06-24 18:01:32 -05:00
Scott Lahteine
22e82a13d9 🎨 Simplify move menus with substitution 2022-06-24 18:01:32 -05:00
Scott Lahteine
70d72354e2 🎨 Use MAP for home axis items 2022-06-24 18:01:32 -05:00
Scott Lahteine
821f4983d0 🧑‍💻 Fix STATIC_ITEM_N arg order 2022-06-24 18:01:32 -05:00
Scott Lahteine
15ca479708 🎨 Fix comments, formatting 2022-06-24 18:01:32 -05:00
John Robertson
2b8d115ebc ️ PWM for ESP32 I2S expander (#24193) 2022-06-24 18:01:32 -05:00
Scott Lahteine
ae78a8844a 🧑‍💻 MAP macro for axis lists, etc. (#24191) 2022-06-24 18:00:59 -05:00
Keith Bennett
f26438ef28 👷 Use Biqu BX for CI test (#24331) 2022-06-24 18:00:59 -05:00
ellensp
ce6c8adcb1 👷 CI test without src filter (emulate Arduino) (#24335) 2022-06-24 18:00:59 -05:00
luzpaz
d57cf9bd6b 🌐 Fix LCD string, typos (#24324) 2022-06-20 21:09:31 -05:00
Scott Lahteine
5408259f51 🧑‍💻 Apply F() to some LCD / TFT strings
Followup to #24228
2022-06-13 21:02:17 -05:00
ellensp
f31178f868 🩹 Fix missing ProUI cpp wrapper (#24313) 2022-06-13 21:02:17 -05:00
ellensp
f976e56a19 🐛 Fix JGAurora A5S A1 build (#24326) 2022-06-13 04:30:09 -05:00
Steven Haigh
571007e5c9 🩹 Fix ProUI compile (#24310)
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
2022-06-13 04:30:09 -05:00
Scott Lahteine
00527f38d5 🧑‍💻 Misc. servo code cleanup 2022-06-13 04:30:09 -05:00
Scott Lahteine
1c7696838b 🧑‍💻 Remove servo macros 2022-06-13 04:30:09 -05:00
tombrazier
ad786a7930 🩹 Fix Mesh Leveling + Debug compile (#24297) 2022-06-07 02:15:39 -05:00
ellensp
ce9c81dfa1 🩹 Media Change followup (#24302)
Followup to #24015
2022-06-07 02:02:11 -05:00
Scott Lahteine
92910721d0 👔 Fix and comment use_example_configs 2022-06-07 02:02:11 -05:00
Miguel Risco-Castillo
236251a2ce 🚸 ProUI G-code preview, PID plot (#24282) 2022-06-06 00:18:08 -05:00
40129a6605 Add TMC2209 configs 2020-08-11 17:21:51 -07:00
a8c32459cf Move extruder fan to pin 7 for auto fan with lower RPM 2020-08-09 10:37:39 -07:00
ab3c212f37 Reverse rotary controller direction 2020-08-06 16:52:38 -07:00
278f81be94 Add LCD controller 2020-08-06 15:55:15 -07:00
1cc42543fd Update steps, jerk, etc 2020-08-06 15:48:28 -07:00
19cb04b28e Fix stepper directions, adjust extruder steps per unit 2020-07-29 16:38:16 -07:00
42486dca57 Fix stepper motor directions 2020-07-29 03:12:42 -07:00
ed57425c08 Updated STEPS_PER_UNIT 2020-07-29 02:51:11 -07:00
af06b28e92 Update config for RigidBot and MKS Gen 1.4 2020-07-29 01:58:34 -07:00
422 changed files with 8412 additions and 6368 deletions

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
@ -96,7 +87,7 @@
// Choose the name from boards.h that matches your setup // Choose the name from boards.h that matches your setup
#ifndef MOTHERBOARD #ifndef MOTHERBOARD
#define MOTHERBOARD BOARD_RAMPS_14_EFB #define MOTHERBOARD BOARD_MKS_GEN_13
#endif #endif
/** /**
@ -120,7 +111,7 @@
* *
* :[2400, 9600, 19200, 38400, 57600, 115200, 250000, 500000, 1000000] * :[2400, 9600, 19200, 38400, 57600, 115200, 250000, 500000, 1000000]
*/ */
#define BAUDRATE 250000 #define BAUDRATE 115200
//#define BAUD_RATE_GCODE // Enable G-code M575 to set the baud rate //#define BAUD_RATE_GCODE // Enable G-code M575 to set the baud rate
/** /**
@ -165,18 +156,18 @@
* TMC5130, TMC5130_STANDALONE, TMC5160, TMC5160_STANDALONE * TMC5130, TMC5130_STANDALONE, TMC5160, TMC5160_STANDALONE
* :['A4988', 'A5984', 'DRV8825', 'LV8729', 'L6470', 'L6474', 'POWERSTEP01', 'TB6560', 'TB6600', 'TMC2100', 'TMC2130', 'TMC2130_STANDALONE', 'TMC2160', 'TMC2160_STANDALONE', 'TMC2208', 'TMC2208_STANDALONE', 'TMC2209', 'TMC2209_STANDALONE', 'TMC26X', 'TMC26X_STANDALONE', 'TMC2660', 'TMC2660_STANDALONE', 'TMC5130', 'TMC5130_STANDALONE', 'TMC5160', 'TMC5160_STANDALONE'] * :['A4988', 'A5984', 'DRV8825', 'LV8729', 'L6470', 'L6474', 'POWERSTEP01', 'TB6560', 'TB6600', 'TMC2100', 'TMC2130', 'TMC2130_STANDALONE', 'TMC2160', 'TMC2160_STANDALONE', 'TMC2208', 'TMC2208_STANDALONE', 'TMC2209', 'TMC2209_STANDALONE', 'TMC26X', 'TMC26X_STANDALONE', 'TMC2660', 'TMC2660_STANDALONE', 'TMC5130', 'TMC5130_STANDALONE', 'TMC5160', 'TMC5160_STANDALONE']
*/ */
#define X_DRIVER_TYPE A4988 #define X_DRIVER_TYPE TMC2209
#define Y_DRIVER_TYPE A4988 #define Y_DRIVER_TYPE TMC2209
#define Z_DRIVER_TYPE A4988 #define Z_DRIVER_TYPE DRV8825
//#define X2_DRIVER_TYPE A4988 //#define X2_DRIVER_TYPE A4988
//#define Y2_DRIVER_TYPE A4988 //#define Y2_DRIVER_TYPE A4988
//#define Z2_DRIVER_TYPE A4988 #define Z2_DRIVER_TYPE DRV8825
//#define Z3_DRIVER_TYPE A4988 //#define Z3_DRIVER_TYPE A4988
//#define Z4_DRIVER_TYPE A4988 //#define Z4_DRIVER_TYPE A4988
//#define I_DRIVER_TYPE A4988 //#define I_DRIVER_TYPE A4988
//#define J_DRIVER_TYPE A4988 //#define J_DRIVER_TYPE A4988
//#define K_DRIVER_TYPE A4988 //#define K_DRIVER_TYPE A4988
#define E0_DRIVER_TYPE A4988 #define E0_DRIVER_TYPE TMC2209
//#define E1_DRIVER_TYPE A4988 //#define E1_DRIVER_TYPE A4988
//#define E2_DRIVER_TYPE A4988 //#define E2_DRIVER_TYPE A4988
//#define E3_DRIVER_TYPE A4988 //#define E3_DRIVER_TYPE A4988
@ -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
@ -526,7 +516,7 @@
#define TEMP_SENSOR_5 0 #define TEMP_SENSOR_5 0
#define TEMP_SENSOR_6 0 #define TEMP_SENSOR_6 0
#define TEMP_SENSOR_7 0 #define TEMP_SENSOR_7 0
#define TEMP_SENSOR_BED 0 #define TEMP_SENSOR_BED 1
#define TEMP_SENSOR_PROBE 0 #define TEMP_SENSOR_PROBE 0
#define TEMP_SENSOR_CHAMBER 0 #define TEMP_SENSOR_CHAMBER 0
#define TEMP_SENSOR_COOLER 0 #define TEMP_SENSOR_COOLER 0
@ -632,9 +622,9 @@
#define DEFAULT_Ki_LIST { 1.08, 1.08 } #define DEFAULT_Ki_LIST { 1.08, 1.08 }
#define DEFAULT_Kd_LIST { 114.00, 114.00 } #define DEFAULT_Kd_LIST { 114.00, 114.00 }
#else #else
#define DEFAULT_Kp 22.20 #define DEFAULT_Kp 10.71
#define DEFAULT_Ki 1.08 #define DEFAULT_Ki 0.51
#define DEFAULT_Kd 114.00 #define DEFAULT_Kd 56.57
#endif #endif
#endif #endif
@ -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)
@ -697,7 +687,7 @@
* heater. If your configuration is significantly different than this and you don't understand * heater. If your configuration is significantly different than this and you don't understand
* the issues involved, don't use bed PID until someone else verifies that your hardware works. * the issues involved, don't use bed PID until someone else verifies that your hardware works.
*/ */
//#define PIDTEMPBED #define PIDTEMPBED
//#define BED_LIMIT_SWITCHING //#define BED_LIMIT_SWITCHING
@ -713,11 +703,22 @@
//#define MIN_BED_POWER 0 //#define MIN_BED_POWER 0
//#define PID_BED_DEBUG // Sends debug data to the serial port. //#define PID_BED_DEBUG // Sends debug data to the serial port.
// 120V 250W silicone heater into 4mm borosilicate (MendelMax 1.5+) //120V 250W silicone heater into 4mm borosilicate (MendelMax 1.5+)
// from FOPDT model - kp=.39 Tp=405 Tdead=66, Tc set to 79.2, aggressive factor of .15 (vs .1, 1, 10) //from FOPDT model - kp=.39 Tp=405 Tdead=66, Tc set to 79.2, aggressive factor of .15 (vs .1, 1, 10)
#define DEFAULT_bedKp 10.00 // #define DEFAULT_bedKp 10.00
#define DEFAULT_bedKi .023 // #define DEFAULT_bedKi .023
#define DEFAULT_bedKd 305.4 // #define DEFAULT_bedKd 305.4
//120V 250W silicone heater into 4mm borosilicate (MendelMax 1.5+)
//from pidautotune
//#define DEFAULT_bedKp 97.1
//#define DEFAULT_bedKi 1.41
//#define DEFAULT_bedKd 1675.16
// RigidBot
#define DEFAULT_bedKp 355
#define DEFAULT_bedKi 66.5
#define DEFAULT_bedKd 480
// FIND YOUR OWN: "M303 E-1 C8 S90" to run autotune on the bed at 90 degreesC for 8 cycles. // FIND YOUR OWN: "M303 E-1 C8 S90" to run autotune on the bed at 90 degreesC for 8 cycles.
#endif // PIDTEMPBED #endif // PIDTEMPBED
@ -845,6 +846,141 @@
#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
// Articulated robot (arm). Joints are directly mapped to axes with no kinematics.
//#define ARTICULATED_ROBOT_ARM
// For a hot wire cutter with parallel horizontal axes (X, I) where the heights of the two wire
// ends are controlled by parallel axes (Y, J). Joints are directly mapped to axes (no kinematics).
//#define FOAMCUTTER_XYUV
//=========================================================================== //===========================================================================
//============================== Endstop Settings =========================== //============================== Endstop Settings ===========================
//=========================================================================== //===========================================================================
@ -906,15 +1042,15 @@
#endif #endif
// Mechanical endstop with COM to ground and NC to Signal uses "false" here (most common setup). // Mechanical endstop with COM to ground and NC to Signal uses "false" here (most common setup).
#define X_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define X_MIN_ENDSTOP_INVERTING true // Set to true to invert the logic of the endstop.
#define Y_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define Y_MIN_ENDSTOP_INVERTING true // Set to true to invert the logic of the endstop.
#define Z_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define Z_MIN_ENDSTOP_INVERTING true // Set to true to invert the logic of the endstop.
#define I_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define I_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop.
#define J_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define J_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop.
#define K_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define K_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop.
#define X_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define X_MAX_ENDSTOP_INVERTING true // Set to true to invert the logic of the endstop.
#define Y_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define Y_MAX_ENDSTOP_INVERTING true // Set to true to invert the logic of the endstop.
#define Z_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define Z_MAX_ENDSTOP_INVERTING true // Set to true to invert the logic of the endstop.
#define I_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define I_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop.
#define J_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define J_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop.
#define K_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define K_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop.
@ -966,14 +1102,14 @@
* Override with M92 * Override with M92
* X, Y, Z [, I [, J [, K]]], E0 [, E1[, E2...]] * X, Y, Z [, I [, J [, K]]], E0 [, E1[, E2...]]
*/ */
#define DEFAULT_AXIS_STEPS_PER_UNIT { 80, 80, 400, 500 } #define DEFAULT_AXIS_STEPS_PER_UNIT { 80.8, 80, 3200, 114.3 } // 1/16 1/16 1/32 1/16 microsteps
/** /**
* Default Max Feed Rate (mm/s) * Default Max Feed Rate (mm/s)
* Override with M203 * Override with M203
* X, Y, Z [, I [, J [, K]]], E0 [, E1[, E2...]] * X, Y, Z [, I [, J [, K]]], E0 [, E1[, E2...]]
*/ */
#define DEFAULT_MAX_FEEDRATE { 300, 300, 5, 25 } #define DEFAULT_MAX_FEEDRATE { 500, 500, 4, 40 }
//#define LIMITED_MAX_FR_EDITING // Limit edit via M203 or LCD to DEFAULT_MAX_FEEDRATE * 2 //#define LIMITED_MAX_FR_EDITING // Limit edit via M203 or LCD to DEFAULT_MAX_FEEDRATE * 2
#if ENABLED(LIMITED_MAX_FR_EDITING) #if ENABLED(LIMITED_MAX_FR_EDITING)
@ -986,7 +1122,7 @@
* Override with M201 * Override with M201
* X, Y, Z [, I [, J [, K]]], E0 [, E1[, E2...]] * X, Y, Z [, I [, J [, K]]], E0 [, E1[, E2...]]
*/ */
#define DEFAULT_MAX_ACCELERATION { 3000, 3000, 100, 10000 } #define DEFAULT_MAX_ACCELERATION { 600, 600, 100, 10000 }
//#define LIMITED_MAX_ACCEL_EDITING // Limit edit via M201 or LCD to DEFAULT_MAX_ACCELERATION * 2 //#define LIMITED_MAX_ACCEL_EDITING // Limit edit via M201 or LCD to DEFAULT_MAX_ACCELERATION * 2
#if ENABLED(LIMITED_MAX_ACCEL_EDITING) #if ENABLED(LIMITED_MAX_ACCEL_EDITING)
@ -1001,8 +1137,8 @@
* 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 600 // X, Y, Z and E acceleration for printing moves
#define DEFAULT_RETRACT_ACCELERATION 3000 // E acceleration for retracts #define DEFAULT_RETRACT_ACCELERATION 1000 // 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
/** /**
@ -1013,14 +1149,11 @@
* When changing speed and direction, if the difference is less than the * When changing speed and direction, if the difference is less than the
* value set here, it may happen instantaneously. * value set here, it may happen instantaneously.
*/ */
//#define CLASSIC_JERK #define CLASSIC_JERK
#if ENABLED(CLASSIC_JERK) #if ENABLED(CLASSIC_JERK)
#define DEFAULT_XJERK 10.0 #define DEFAULT_YJERK 10
#define DEFAULT_YJERK 10.0 #define DEFAULT_XJERK 10
#define DEFAULT_ZJERK 0.3 #define DEFAULT_ZJERK 0.4
//#define DEFAULT_IJERK 0.3
//#define DEFAULT_JJERK 0.3
//#define DEFAULT_KJERK 0.3
//#define TRAVEL_EXTRA_XYJERK 0.0 // Additional jerk allowance for all travel moves //#define TRAVEL_EXTRA_XYJERK 0.0 // Additional jerk allowance for all travel moves
@ -1053,7 +1186,7 @@
* *
* See https://github.com/synthetos/TinyG/wiki/Jerk-Controlled-Motion-Explained * See https://github.com/synthetos/TinyG/wiki/Jerk-Controlled-Motion-Explained
*/ */
//#define S_CURVE_ACCELERATION #define S_CURVE_ACCELERATION
//=========================================================================== //===========================================================================
//============================= Z Probe Options ============================= //============================= Z Probe Options =============================
@ -1126,7 +1259,7 @@
/** /**
* The BLTouch probe uses a Hall effect sensor and emulates a servo. * The BLTouch probe uses a Hall effect sensor and emulates a servo.
*/ */
//#define BLTOUCH #define BLTOUCH
/** /**
* MagLev V4 probe by MDD * MagLev V4 probe by MDD
@ -1185,9 +1318,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 }
@ -1229,7 +1390,7 @@
* | [-] | * | [-] |
* O-- FRONT --+ * O-- FRONT --+
*/ */
#define NOZZLE_TO_PROBE_OFFSET { 10, 10, 0 } #define NOZZLE_TO_PROBE_OFFSET { -56.5, -7, 0 }
// Most probes should stay away from the edges of the bed, but // Most probes should stay away from the edges of the bed, but
// with NOZZLE_AS_PROBE this can be negative for a wider probing area. // with NOZZLE_AS_PROBE this can be negative for a wider probing area.
@ -1380,17 +1541,14 @@
// @section machine // @section machine
// Invert the stepper direction. Change (or reverse the motor connector) if an axis goes the wrong way. // Invert the stepper direction. Change (or reverse the motor connector) if an axis goes the wrong way.
#define INVERT_X_DIR false #define INVERT_X_DIR true
#define INVERT_Y_DIR true #define INVERT_Y_DIR false
#define INVERT_Z_DIR false #define INVERT_Z_DIR true
//#define INVERT_I_DIR false
//#define INVERT_J_DIR false
//#define INVERT_K_DIR false
// @section extruder // @section extruder
// For direct drive extruder v9 set to true, for geared extruder set to false. // For direct drive extruder v9 set to true, for geared extruder set to false.
#define INVERT_E0_DIR false #define INVERT_E0_DIR true
#define INVERT_E1_DIR false #define INVERT_E1_DIR false
#define INVERT_E2_DIR false #define INVERT_E2_DIR false
#define INVERT_E3_DIR false #define INVERT_E3_DIR false
@ -1427,23 +1585,19 @@
// @section machine // @section machine
// The size of the printable area // The size of the print bed
#define X_BED_SIZE 200 #define X_BED_SIZE 254
#define Y_BED_SIZE 200 #define Y_BED_SIZE 254
// Travel limits (mm) after homing, corresponding to endstop positions. // Travel limits (mm) after homing, corresponding to endstop positions.
#define X_MIN_POS 0 #define X_MIN_POS 0
#define Y_MIN_POS 0 #define Y_MIN_POS 0
// Travel limits after homing
#define Z_MIN_POS 0 #define Z_MIN_POS 0
#define X_MAX_POS X_BED_SIZE #define X_MAX_POS X_BED_SIZE
#define Y_MAX_POS Y_BED_SIZE #define Y_MAX_POS Y_BED_SIZE
#define Z_MAX_POS 200 #define Z_MAX_POS 254
//#define I_MIN_POS 0
//#define I_MAX_POS 50
//#define J_MIN_POS 0
//#define J_MAX_POS 50
//#define K_MIN_POS 0
//#define K_MAX_POS 50
/** /**
* Software Endstops * Software Endstops
@ -1595,7 +1749,7 @@
*/ */
//#define AUTO_BED_LEVELING_3POINT //#define AUTO_BED_LEVELING_3POINT
//#define AUTO_BED_LEVELING_LINEAR //#define AUTO_BED_LEVELING_LINEAR
//#define AUTO_BED_LEVELING_BILINEAR #define AUTO_BED_LEVELING_BILINEAR
//#define AUTO_BED_LEVELING_UBL //#define AUTO_BED_LEVELING_UBL
//#define MESH_BED_LEVELING //#define MESH_BED_LEVELING
@ -1604,7 +1758,7 @@
* these options to restore the prior leveling state or to always enable * these options to restore the prior leveling state or to always enable
* leveling immediately after G28. * leveling immediately after G28.
*/ */
//#define RESTORE_LEVELING_AFTER_G28 #define RESTORE_LEVELING_AFTER_G28
//#define ENABLE_LEVELING_AFTER_G28 //#define ENABLE_LEVELING_AFTER_G28
/** /**
@ -1646,7 +1800,7 @@
/** /**
* Enable the G26 Mesh Validation Pattern tool. * Enable the G26 Mesh Validation Pattern tool.
*/ */
//#define G26_MESH_VALIDATION #define G26_MESH_VALIDATION
#if ENABLED(G26_MESH_VALIDATION) #if ENABLED(G26_MESH_VALIDATION)
#define MESH_TEST_NOZZLE_SIZE 0.4 // (mm) Diameter of primary nozzle. #define MESH_TEST_NOZZLE_SIZE 0.4 // (mm) Diameter of primary nozzle.
#define MESH_TEST_LAYER_HEIGHT 0.2 // (mm) Default layer height for G26. #define MESH_TEST_LAYER_HEIGHT 0.2 // (mm) Default layer height for G26.
@ -1672,7 +1826,7 @@
// Beyond the probed grid, continue the implied tilt? // Beyond the probed grid, continue the implied tilt?
// Default is to maintain the height of the nearest edge. // Default is to maintain the height of the nearest edge.
//#define EXTRAPOLATE_BEYOND_GRID #define EXTRAPOLATE_BEYOND_GRID
// //
// Experimental Subdivision of the grid by Catmull-Rom method. // Experimental Subdivision of the grid by Catmull-Rom method.
@ -1726,7 +1880,7 @@
* Add a bed leveling sub-menu for ABL or MBL. * Add a bed leveling sub-menu for ABL or MBL.
* Include a guided procedure if manual probing is enabled. * Include a guided procedure if manual probing is enabled.
*/ */
//#define LCD_BED_LEVELING #define LCD_BED_LEVELING
#if ENABLED(LCD_BED_LEVELING) #if ENABLED(LCD_BED_LEVELING)
#define MESH_EDIT_Z_STEP 0.025 // (mm) Step size while manually probing Z axis. #define MESH_EDIT_Z_STEP 0.025 // (mm) Step size while manually probing Z axis.
@ -1738,7 +1892,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
@ -1881,8 +2035,8 @@
* M501 - Read settings from EEPROM. (i.e., Throw away unsaved changes) * M501 - Read settings from EEPROM. (i.e., Throw away unsaved changes)
* M502 - Revert settings to "factory" defaults. (Follow with M500 to init the EEPROM.) * M502 - Revert settings to "factory" defaults. (Follow with M500 to init the EEPROM.)
*/ */
//#define EEPROM_SETTINGS // Persistent storage with M500 and M501 #define EEPROM_SETTINGS // Persistent storage with M500 and M501
//#define DISABLE_M503 // Saves ~2700 bytes of flash. Disable for release! //#define DISABLE_M503 // Saves ~2700 bytes of PROGMEM. Disable for release!
#define EEPROM_CHITCHAT // Give feedback on EEPROM commands. Disable to save PROGMEM. #define EEPROM_CHITCHAT // Give feedback on EEPROM commands. Disable to save PROGMEM.
#define EEPROM_BOOT_SILENT // Keep M503 quiet and only give errors during first load #define EEPROM_BOOT_SILENT // Keep M503 quiet and only give errors during first load
#if ENABLED(EEPROM_SETTINGS) #if ENABLED(EEPROM_SETTINGS)
@ -2154,7 +2308,7 @@
* SD Card support is disabled by default. If your controller has an SD slot, * SD Card support is disabled by default. If your controller has an SD slot,
* you must uncomment the following option or it won't work. * you must uncomment the following option or it won't work.
*/ */
//#define SDSUPPORT #define SDSUPPORT
/** /**
* SD CARD: ENABLE CRC * SD CARD: ENABLE CRC
@ -2201,7 +2355,7 @@
// //
// Set this option if CLOCKWISE causes values to DECREASE // Set this option if CLOCKWISE causes values to DECREASE
// //
//#define REVERSE_ENCODER_DIRECTION #define REVERSE_ENCODER_DIRECTION
// //
// This option reverses the encoder direction for navigating LCD menus. // This option reverses the encoder direction for navigating LCD menus.
@ -2224,8 +2378,7 @@
// //
// Add individual axis homing items (Home X, Home Y, and Home Z) to the LCD menu. // Add individual axis homing items (Home X, Home Y, and Home Z) to the LCD menu.
// //
//#define INDIVIDUAL_AXIS_HOMING_MENU #define INDIVIDUAL_AXIS_HOMING_MENU
//#define INDIVIDUAL_AXIS_HOMING_SUBMENU
// //
// SPEAKER/BUZZER // SPEAKER/BUZZER
@ -2233,7 +2386,7 @@
// If you have a speaker that can produce tones, enable it here. // If you have a speaker that can produce tones, enable it here.
// By default Marlin assumes you have a buzzer with a fixed frequency. // By default Marlin assumes you have a buzzer with a fixed frequency.
// //
//#define SPEAKER #define SPEAKER
// //
// The duration and frequency for the UI feedback sound. // The duration and frequency for the UI feedback sound.
@ -2256,7 +2409,7 @@
// //
// Note: Usually sold with a white PCB. // Note: Usually sold with a white PCB.
// //
//#define REPRAP_DISCOUNT_SMART_CONTROLLER #define REPRAP_DISCOUNT_SMART_CONTROLLER
// //
// GT2560 (YHCB2004) LCD Display // GT2560 (YHCB2004) LCD Display

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
/** /**
@ -266,8 +266,8 @@
* THERMAL_PROTECTION_HYSTERESIS and/or THERMAL_PROTECTION_PERIOD * THERMAL_PROTECTION_HYSTERESIS and/or THERMAL_PROTECTION_PERIOD
*/ */
#if ENABLED(THERMAL_PROTECTION_HOTENDS) #if ENABLED(THERMAL_PROTECTION_HOTENDS)
#define THERMAL_PROTECTION_PERIOD 40 // Seconds #define THERMAL_PROTECTION_PERIOD 60 // Seconds
#define THERMAL_PROTECTION_HYSTERESIS 4 // Degrees Celsius #define THERMAL_PROTECTION_HYSTERESIS 10 // Degrees Celsius
//#define ADAPTIVE_FAN_SLOWING // Slow part cooling fan if temperature drops //#define ADAPTIVE_FAN_SLOWING // Slow part cooling fan if temperature drops
#if BOTH(ADAPTIVE_FAN_SLOWING, PIDTEMP) #if BOTH(ADAPTIVE_FAN_SLOWING, PIDTEMP)
@ -596,7 +596,7 @@
* Multiple extruders can be assigned to the same pin in which case * Multiple extruders can be assigned to the same pin in which case
* the fan will turn on when any selected extruder is above the threshold. * the fan will turn on when any selected extruder is above the threshold.
*/ */
#define E0_AUTO_FAN_PIN -1 #define E0_AUTO_FAN_PIN 7
#define E1_AUTO_FAN_PIN -1 #define E1_AUTO_FAN_PIN -1
#define E2_AUTO_FAN_PIN -1 #define E2_AUTO_FAN_PIN -1
#define E3_AUTO_FAN_PIN -1 #define E3_AUTO_FAN_PIN -1
@ -608,9 +608,9 @@
#define COOLER_AUTO_FAN_PIN -1 #define COOLER_AUTO_FAN_PIN -1
#define EXTRUDER_AUTO_FAN_TEMPERATURE 50 #define EXTRUDER_AUTO_FAN_TEMPERATURE 50
#define EXTRUDER_AUTO_FAN_SPEED 255 // 255 == full speed #define EXTRUDER_AUTO_FAN_SPEED 165 // 255 == full speed
#define CHAMBER_AUTO_FAN_TEMPERATURE 30 #define CHAMBER_AUTO_FAN_TEMPERATURE 30
#define CHAMBER_AUTO_FAN_SPEED 255 #define CHAMBER_AUTO_FAN_SPEED 165
#define COOLER_AUTO_FAN_TEMPERATURE 18 #define COOLER_AUTO_FAN_TEMPERATURE 18
#define COOLER_AUTO_FAN_SPEED 255 #define COOLER_AUTO_FAN_SPEED 255
@ -1954,7 +1954,7 @@
* *
* Warning: Does not respect endstops! * Warning: Does not respect endstops!
*/ */
//#define BABYSTEPPING #define BABYSTEPPING
#if ENABLED(BABYSTEPPING) #if ENABLED(BABYSTEPPING)
//#define INTEGRATED_BABYSTEPPING // EXPERIMENTAL integration of babystepping into the Stepper ISR //#define INTEGRATED_BABYSTEPPING // EXPERIMENTAL integration of babystepping into the Stepper ISR
//#define BABYSTEP_WITHOUT_HOMING //#define BABYSTEP_WITHOUT_HOMING
@ -1977,7 +1977,7 @@
//#define BABYSTEP_DISPLAY_TOTAL // Display total babysteps since last G28 //#define BABYSTEP_DISPLAY_TOTAL // Display total babysteps since last G28
//#define BABYSTEP_ZPROBE_OFFSET // Combine M851 Z and Babystepping #define BABYSTEP_ZPROBE_OFFSET // Combine M851 Z and Babystepping
#if ENABLED(BABYSTEP_ZPROBE_OFFSET) #if ENABLED(BABYSTEP_ZPROBE_OFFSET)
//#define BABYSTEP_HOTEND_Z_OFFSET // For multiple hotends, babystep relative Z offsets //#define BABYSTEP_HOTEND_Z_OFFSET // For multiple hotends, babystep relative Z offsets
//#define BABYSTEP_ZPROBE_GFX_OVERLAY // Enable graphical overlay on Z-offset editor //#define BABYSTEP_ZPROBE_GFX_OVERLAY // Enable graphical overlay on Z-offset editor
@ -2001,7 +2001,7 @@
* *
* See https://marlinfw.org/docs/features/lin_advance.html for full instructions. * See https://marlinfw.org/docs/features/lin_advance.html for full instructions.
*/ */
//#define LIN_ADVANCE // #define LIN_ADVANCE
#if ENABLED(LIN_ADVANCE) #if ENABLED(LIN_ADVANCE)
//#define EXTRA_LIN_ADVANCE_K // Enable for second linear advance constants //#define EXTRA_LIN_ADVANCE_K // Enable for second linear advance constants
#define LIN_ADVANCE_K 0.22 // Unit: mm compression per 1mm/s extruder speed #define LIN_ADVANCE_K 0.22 // Unit: mm compression per 1mm/s extruder speed
@ -2423,7 +2423,7 @@
/** /**
* Extra G-code to run while executing tool-change commands. Can be used to use an additional * Extra G-code to run while executing tool-change commands. Can be used to use an additional
* stepper motor (e.g., I axis in Configuration.h) to drive the tool-changer. * stepper motor (I axis, see option LINEAR_AXES in Configuration.h) to drive the tool-changer.
*/ */
//#define EVENT_GCODE_TOOLCHANGE_T0 "G28 A\nG1 A0" // Extra G-code to run while executing tool-change command T0 //#define EVENT_GCODE_TOOLCHANGE_T0 "G28 A\nG1 A0" // Extra G-code to run while executing tool-change command T0
//#define EVENT_GCODE_TOOLCHANGE_T1 "G1 A10" // Extra G-code to run while executing tool-change command T1 //#define EVENT_GCODE_TOOLCHANGE_T1 "G1 A10" // Extra G-code to run while executing tool-change command T1
@ -2565,7 +2565,7 @@
#if HAS_DRIVER(TMC26X) #if HAS_DRIVER(TMC26X)
#if AXIS_DRIVER_TYPE_X(TMC26X) #if AXIS_DRIVER_TYPE_X(TMC26X)
#define X_MAX_CURRENT 1000 // (mA) #define X_MAX_CURRENT 1330 // (mA)
#define X_SENSE_RESISTOR 91 // (mOhms) #define X_SENSE_RESISTOR 91 // (mOhms)
#define X_MICROSTEPS 16 // Number of microsteps #define X_MICROSTEPS 16 // Number of microsteps
#endif #endif
@ -2577,7 +2577,7 @@
#endif #endif
#if AXIS_DRIVER_TYPE_Y(TMC26X) #if AXIS_DRIVER_TYPE_Y(TMC26X)
#define Y_MAX_CURRENT 1000 #define Y_MAX_CURRENT 1680
#define Y_SENSE_RESISTOR 91 #define Y_SENSE_RESISTOR 91
#define Y_MICROSTEPS 16 #define Y_MICROSTEPS 16
#endif #endif
@ -2631,7 +2631,7 @@
#endif #endif
#if AXIS_DRIVER_TYPE_E0(TMC26X) #if AXIS_DRIVER_TYPE_E0(TMC26X)
#define E0_MAX_CURRENT 1000 #define E0_MAX_CURRENT 1330
#define E0_SENSE_RESISTOR 91 #define E0_SENSE_RESISTOR 91
#define E0_MICROSTEPS 16 #define E0_MICROSTEPS 16
#endif #endif
@ -2709,7 +2709,7 @@
#define INTERPOLATE true #define INTERPOLATE true
#if AXIS_IS_TMC(X) #if AXIS_IS_TMC(X)
#define X_CURRENT 800 // (mA) RMS current. Multiply by 1.414 for peak current. #define X_CURRENT 846 // (mA) RMS current. Multiply by 1.414 for peak current.
#define X_CURRENT_HOME X_CURRENT // (mA) RMS current for sensorless homing #define X_CURRENT_HOME X_CURRENT // (mA) RMS current for sensorless homing
#define X_MICROSTEPS 16 // 0..256 #define X_MICROSTEPS 16 // 0..256
#define X_RSENSE 0.11 #define X_RSENSE 0.11
@ -2729,7 +2729,7 @@
#endif #endif
#if AXIS_IS_TMC(Y) #if AXIS_IS_TMC(Y)
#define Y_CURRENT 800 #define Y_CURRENT 1069
#define Y_CURRENT_HOME Y_CURRENT #define Y_CURRENT_HOME Y_CURRENT
#define Y_MICROSTEPS 16 #define Y_MICROSTEPS 16
#define Y_RSENSE 0.11 #define Y_RSENSE 0.11
@ -2819,7 +2819,7 @@
#endif #endif
#if AXIS_IS_TMC(E0) #if AXIS_IS_TMC(E0)
#define E0_CURRENT 800 #define E0_CURRENT 846
#define E0_MICROSTEPS 16 #define E0_MICROSTEPS 16
#define E0_RSENSE 0.11 #define E0_RSENSE 0.11
#define E0_CHAIN_POS -1 #define E0_CHAIN_POS -1
@ -3023,7 +3023,7 @@
* M912 - Clear stepper driver overtemperature pre-warn condition flag. * M912 - Clear stepper driver overtemperature pre-warn condition flag.
* M122 - Report driver parameters (Requires TMC_DEBUG) * M122 - Report driver parameters (Requires TMC_DEBUG)
*/ */
//#define MONITOR_DRIVER_STATUS // #define MONITOR_DRIVER_STATUS
#if ENABLED(MONITOR_DRIVER_STATUS) #if ENABLED(MONITOR_DRIVER_STATUS)
#define CURRENT_STEP_DOWN 50 // [mA] #define CURRENT_STEP_DOWN 50 // [mA]
@ -3126,7 +3126,7 @@
* Enable M122 debugging command for TMC stepper drivers. * Enable M122 debugging command for TMC stepper drivers.
* M122 S0/1 will enable continuous reporting. * M122 S0/1 will enable continuous reporting.
*/ */
//#define TMC_DEBUG #define TMC_DEBUG
/** /**
* You can set your own advanced settings by filling in predefined functions. * You can set your own advanced settings by filling in predefined functions.
@ -3472,6 +3472,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 +3548,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 +3565,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 "2.0.9.5"
/** /**
* 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 "2022-07-27"
/** /**
* 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.

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

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

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

@ -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
@ -343,29 +344,30 @@
#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
@ -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 (STM32F407VG)
#define BOARD_ANET_ET4 4231 // ANET ET4 V1.x (STM32F407VG) #define BOARD_MKS_MONSTER8_V2 4231 // MKS Monster8 V2 (STM32F407VG)
#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
#define BOARD_INDEX_REV03 4235 // Index PnP Controller REV03 (STM32F407VE/VG) #define BOARD_TH3D_EZBOARD_V2 4235 // TH3D EZBoard v2.0
#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/VG)
#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(' '); }

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
// //
@ -356,3 +343,32 @@ inline void print_pos(const xyz_pos_t &xyz, FSTR_P const prefix=nullptr, FSTR_P
#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,24 +36,42 @@ 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 ALL_AXIS_NAMES X, X2, Y, Y2, Z, Z2, Z3, Z4, I, J, K, E0, E1, E2, E3, E4, E5, E6, E7
#define LINEAR_AXIS_GANG(V...) GANG_N(LINEAR_AXES, V) #define LINEAR_AXIS_GANG(V...) GANG_N(LINEAR_AXES, V)
#define LINEAR_AXIS_CODE(V...) CODE_N(LINEAR_AXES, V) #define LINEAR_AXIS_CODE(V...) CODE_N(LINEAR_AXES, V)
#define LINEAR_AXIS_LIST(V...) LIST_N(LINEAR_AXES, V) #define LINEAR_AXIS_LIST(V...) LIST_N(LINEAR_AXES, V)
#define LINEAR_AXIS_LIST_1(V) LIST_N_1(LINEAR_AXES, V)
#define LINEAR_AXIS_ARRAY(V...) { LINEAR_AXIS_LIST(V) } #define LINEAR_AXIS_ARRAY(V...) { LINEAR_AXIS_LIST(V) }
#define LINEAR_AXIS_ARRAY_1(V) { LINEAR_AXIS_LIST_1(V) }
#define LINEAR_AXIS_ARGS(T...) LINEAR_AXIS_LIST(T x, T y, T z, T i, T j, T k) #define LINEAR_AXIS_ARGS(T...) LINEAR_AXIS_LIST(T x, T y, T z, T i, T j, T k)
#define LINEAR_AXIS_ELEM(O) LINEAR_AXIS_LIST(O.x, O.y, O.z, O.i, O.j, O.k) #define LINEAR_AXIS_ELEM(O) LINEAR_AXIS_LIST(O.x, O.y, O.z, O.i, O.j, O.k)
#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 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 MAIN_AXIS_NAMES LINEAR_AXIS_LIST(X, Y, Z, I, J, K)
#define MAIN_AXIS_MAP(F) MAP(F, MAIN_AXIS_NAMES)
#define LOGICAL_AXIS_GANG(E,V...) LINEAR_AXIS_GANG(V) GANG_ITEM_E(E) #define LOGICAL_AXIS_GANG(E,V...) LINEAR_AXIS_GANG(V) GANG_ITEM_E(E)
#define LOGICAL_AXIS_CODE(E,V...) LINEAR_AXIS_CODE(V) CODE_ITEM_E(E) #define LOGICAL_AXIS_CODE(E,V...) LINEAR_AXIS_CODE(V) CODE_ITEM_E(E)
#define LOGICAL_AXIS_LIST(E,V...) LINEAR_AXIS_LIST(V) LIST_ITEM_E(E) #define LOGICAL_AXIS_LIST(E,V...) LINEAR_AXIS_LIST(V) LIST_ITEM_E(E)
#define LOGICAL_AXIS_LIST_1(V) LINEAR_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_AXIS_NAMES LOGICAL_AXIS_LIST(E, X, Y, Z, I, J, K)
#define LOGICAL_AXIS_MAP(F) MAP(F, LOGICAL_AXIS_NAMES)
#define LOGICAL_AXES_STRING LOGICAL_AXIS_GANG("E", "X", "Y", "Z", STR_I, STR_J, STR_K) #define LOGICAL_AXES_STRING 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
#define CODE_ITEM_E(N) ; N #define CODE_ITEM_E(N) ; N
@ -81,9 +99,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 +113,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 +132,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;
// //
@ -439,7 +457,7 @@ template<typename T>
struct XYZval { struct XYZval {
union { union {
struct { T LINEAR_AXIS_ARGS(); }; struct { T LINEAR_AXIS_ARGS(); };
struct { T LINEAR_AXIS_LIST(a, b, c, u, v, w); }; struct { T LINEAR_AXIS_LIST(a, b, c, _i, _j, _k); };
T pos[LINEAR_AXES]; T pos[LINEAR_AXES];
}; };
@ -454,11 +472,11 @@ struct XYZval {
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)[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(LINEAR_AXIS_ARGS(const T)) { LINEAR_AXIS_CODE(a = x, b = y, c = z, u = i, v = j, w = k ); } FI void set(LINEAR_AXIS_ARGS(const T)) { LINEAR_AXIS_CODE(a = x, b = y, c = z, _i = i, _j = j, _k = k); }
#endif #endif
#if LOGICAL_AXES > LINEAR_AXES #if LOGICAL_AXES > LINEAR_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]) { LINEAR_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)) { LINEAR_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]) { LINEAR_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5]); }
#endif #endif
@ -585,7 +603,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
@ -607,13 +625,13 @@ struct XYZEval {
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(LINEAR_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(LINEAR_AXIS_ARGS(const T)) { LINEAR_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 > LINEAR_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

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"
@ -126,17 +126,16 @@ void safe_delay(millis_t ms) {
#if ABL_PLANAR #if ABL_PLANAR
SERIAL_ECHOPGM("ABL Adjustment"); SERIAL_ECHOPGM("ABL Adjustment");
LOOP_LINEAR_AXES(a) { LOOP_LINEAR_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,14 @@ 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 LINEAR_AXES <= XYZ #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

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

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

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

@ -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
@ -711,9 +714,13 @@ void resume_print(const_float_t slow_load_length/*=0*/, const_float_t fast_load_
TERN_(HAS_FILAMENT_SENSOR, runout.reset()); TERN_(HAS_FILAMENT_SENSOR, runout.reset());
TERN(DWIN_LCD_PROUI, DWIN_Print_Resume(), ui.reset_status()); #if ENABLED(DWIN_LCD_PROUI)
TERN_(HAS_MARLINUI_MENU, ui.return_to_status()); DWIN_Print_Resume();
TERN_(DWIN_LCD_PROUI, HMI_ReturnScreen()); HMI_ReturnScreen();
#else
ui.reset_status();
ui.return_to_status();
#endif
} }
#endif // ADVANCED_PAUSE_FEATURE #endif // ADVANCED_PAUSE_FEATURE

View File

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

View File

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

View File

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

View File

@ -39,18 +39,26 @@
#endif #endif
SpindleLaser cutter; SpindleLaser cutter;
uint8_t SpindleLaser::power, bool SpindleLaser::enable_state; // Virtual enable state, controls enable pin if present and or apply power if > 0
uint8_t SpindleLaser::power, // Actual power output 0-255 ocr or "0 = off" > 0 = "on"
SpindleLaser::last_power_applied; // = 0 // Basic power state tracking SpindleLaser::last_power_applied; // = 0 // Basic power state tracking
#if ENABLED(LASER_FEATURE)
cutter_test_pulse_t SpindleLaser::testPulse = 50; // Test fire Pulse time ms value.
#endif
bool SpindleLaser::isReady; // Ready to apply power setting from the UI to OCR
cutter_power_t SpindleLaser::menuPower, // Power set via LCD menu in PWM, PERCENT, or RPM
SpindleLaser::unitPower; // LCD status power in PWM, PERCENT, or RPM
#if ENABLED(MARLIN_DEV_MODE) #if ENABLED(LASER_FEATURE)
cutter_frequency_t SpindleLaser::frequency; // PWM frequency setting; range: 2K - 50K cutter_test_pulse_t SpindleLaser::testPulse = 50; // (ms) Test fire pulse default duration
uint8_t SpindleLaser::last_block_power; // = 0 // Track power changes for dynamic inline power
feedRate_t SpindleLaser::feedrate_mm_m = 1500,
SpindleLaser::last_feedrate_mm_m; // = 0 // (mm/min) Track feedrate changes for dynamic power
#endif #endif
bool SpindleLaser::isReadyForUI = false; // Ready to apply power setting from the UI to OCR
CutterMode SpindleLaser::cutter_mode = CUTTER_MODE_STANDARD; // Default is standard mode
constexpr cutter_cpower_t SpindleLaser::power_floor;
cutter_power_t SpindleLaser::menuPower = 0, // Power value via LCD menu in PWM, PERCENT, or RPM based on configured format set by CUTTER_POWER_UNIT.
SpindleLaser::unitPower = 0; // Unit power is in PWM, PERCENT, or RPM based on CUTTER_POWER_UNIT.
cutter_frequency_t SpindleLaser::frequency; // PWM frequency setting; range: 2K - 50K
#define SPINDLE_LASER_PWM_OFF TERN(SPINDLE_LASER_PWM_INVERT, 255, 0) #define SPINDLE_LASER_PWM_OFF TERN(SPINDLE_LASER_PWM_INVERT, 255, 0)
/** /**
@ -58,21 +66,21 @@ cutter_power_t SpindleLaser::menuPower, // Power s
*/ */
void SpindleLaser::init() { void SpindleLaser::init() {
#if ENABLED(SPINDLE_SERVO) #if ENABLED(SPINDLE_SERVO)
MOVE_SERVO(SPINDLE_SERVO_NR, SPINDLE_SERVO_MIN); servo[SPINDLE_SERVO_NR].move(SPINDLE_SERVO_MIN);
#else #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,98 @@
#include "../libs/buzzer.h" #include "../libs/buzzer.h"
#endif #endif
#if ENABLED(LASER_POWER_INLINE) // Inline laser power
#include "../module/planner.h" #include "../module/planner.h"
#endif
#define PCT_TO_PWM(X) ((X) * 255 / 100) #define PCT_TO_PWM(X) ((X) * 255 / 100)
#define PCT_TO_SERVO(X) ((X) * 180 / 100) #define PCT_TO_SERVO(X) ((X) * 180 / 100)
// #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 +136,6 @@ public:
public: public:
static void set_ocr(const uint8_t ocr); static void set_ocr(const uint8_t ocr);
static void ocr_set_power(const uint8_t ocr) { power = ocr; set_ocr(ocr); }
static void ocr_off(); static void ocr_off();
/** /**
@ -143,78 +153,76 @@ public:
); );
} }
/**
* Correct power to configured range
*/
static cutter_power_t power_to_range(const cutter_power_t pwr) {
return power_to_range(pwr, _CUTTER_POWER(CUTTER_POWER_UNIT));
}
static cutter_power_t power_to_range(const cutter_power_t pwr, const uint8_t pwrUnit) {
static constexpr float
min_pct = TERN(CUTTER_POWER_RELATIVE, 0, TERN(SPINDLE_FEATURE, round(100.0f * (SPEED_POWER_MIN) / (SPEED_POWER_MAX)), SPEED_POWER_MIN)),
max_pct = TERN(SPINDLE_FEATURE, 100, SPEED_POWER_MAX);
if (pwr <= 0) return 0;
cutter_power_t upwr;
switch (pwrUnit) {
case _CUTTER_POWER_PWM255:
upwr = cutter_power_t(
(pwr < pct_to_ocr(min_pct)) ? pct_to_ocr(min_pct) // Use minimum if set below
: (pwr > pct_to_ocr(max_pct)) ? pct_to_ocr(max_pct) // Use maximum if set above
: pwr
);
break;
case _CUTTER_POWER_PERCENT:
upwr = cutter_power_t(
(pwr < min_pct) ? min_pct // Use minimum if set below
: (pwr > max_pct) ? max_pct // Use maximum if set above
: pwr // PCT
);
break;
case _CUTTER_POWER_RPM:
upwr = cutter_power_t(
(pwr < SPEED_POWER_MIN) ? SPEED_POWER_MIN // Use minimum if set below
: (pwr > SPEED_POWER_MAX) ? SPEED_POWER_MAX // Use maximum if set above
: pwr // Calculate OCR value
);
break;
default: break;
}
return upwr;
}
#endif // SPINDLE_LASER_USE_PWM #endif // SPINDLE_LASER_USE_PWM
/** /**
* Enable/Disable spindle/laser * Correct power to configured range
* @param enable true = enable; false = disable
*/ */
static void set_enabled(const bool enable) { static cutter_power_t power_to_range(const cutter_power_t pwr, const uint8_t pwrUnit=_CUTTER_POWER(CUTTER_POWER_UNIT)) {
uint8_t value = 0; static constexpr float
if (enable) { min_pct = TERN(CUTTER_POWER_RELATIVE, 0, TERN(SPINDLE_FEATURE, round(100.0f * (SPEED_POWER_MIN) / (SPEED_POWER_MAX)), SPEED_POWER_MIN)),
#if ENABLED(SPINDLE_LASER_USE_PWM) max_pct = TERN(SPINDLE_FEATURE, 100, SPEED_POWER_MAX);
if (power) if (pwr <= 0) return 0;
value = power; cutter_power_t upwr;
else if (unitPower) switch (pwrUnit) {
value = upower_to_ocr(cpwr_to_upwr(SPEED_POWER_STARTUP)); case _CUTTER_POWER_PWM255: { // PWM
#else const uint8_t pmin = pct_to_ocr(min_pct), pmax = pct_to_ocr(max_pct);
value = 255; upwr = cutter_power_t(constrain(pwr, pmin, pmax));
#endif } break;
case _CUTTER_POWER_PERCENT: // Percent
upwr = cutter_power_t(constrain(pwr, min_pct, max_pct));
break;
case _CUTTER_POWER_RPM: // Calculate OCR value
upwr = cutter_power_t(constrain(pwr, SPEED_POWER_MIN, SPEED_POWER_MAX));
break;
default: break;
} }
set_power(value); return upwr;
} }
static void disable() { isReady = false; set_enabled(false); }
/** /**
* Wait for spindle to spin up or spin down * Enable Laser or Spindle output.
* It's important to prevent changing the power output value during inline cutter operation.
* Inline power is adjusted in the planner to support LASER_TRAP_POWER and CUTTER_MODE_DYNAMIC mode.
* *
* @param on true = state to on; false = state to off. * This method accepts one of the following control states:
*
* - For CUTTER_MODE_STANDARD the cutter power is either full on/off or ocr-based and it will apply
* SPEED_POWER_STARTUP if no value is assigned.
*
* - For CUTTER_MODE_CONTINUOUS inline and power remains where last set and the cutter output enable flag is set.
*
* - CUTTER_MODE_DYNAMIC is also inline-based and it just sets the enable output flag.
*
* - For CUTTER_MODE_ERROR set the output enable_state flag directly and set power to 0 for any mode.
* This mode allows a global power shutdown action to occur.
*/ */
static void power_delay(const bool on) { static void set_enabled(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,47 +234,60 @@ 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
@ -274,74 +295,36 @@ public:
*/ */
static void test_fire_pulse() { static void test_fire_pulse() {
TERN_(HAS_BEEPER, buzzer.tone(30, 3000)); TERN_(HAS_BEEPER, buzzer.tone(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

@ -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
@ -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;
@ -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();

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"

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

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

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_LINEAR_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;
} }
} }
@ -89,9 +83,7 @@ void GcodeSuite::M425() {
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_LINEAR_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
@ -102,8 +94,7 @@ void GcodeSuite::M425() {
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_LINEAR_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

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

@ -45,7 +45,7 @@
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_LINEAR_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

@ -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));
} }
} }
} }
@ -180,9 +180,9 @@ void GcodeSuite::M203() {
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));
} }
} }

View File

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

@ -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,7 +45,7 @@ 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 |= LINEAR_AXIS_GANG(
@ -125,14 +127,8 @@ void GcodeSuite::M17() {
stepper.enable_e_steppers(); stepper.enable_e_steppers();
} }
#endif #endif
LINEAR_AXIS_CODE( LOOP_LINEAR_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 {
@ -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_LINEAR_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)
@ -238,14 +234,8 @@ void GcodeSuite::M18_M84() {
stepper.disable_e_steppers(); stepper.disable_e_steppers();
} }
#endif #endif
LINEAR_AXIS_CODE( LOOP_LINEAR_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

@ -33,9 +33,9 @@
* 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()); if (parser.seenval('B')) stepper.microstep_mode(E_AXIS + 1, parser.value_byte());
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;

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,9 +39,11 @@
#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
@ -49,43 +51,64 @@ void GcodeSuite::M907() {
if (!parser.seen("BS" LOGICAL_AXES_STRING)) if (!parser.seen("BS" LOGICAL_AXES_STRING))
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 (LINEAR_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 < _MAX(DIGIPOT_I2C_NUM_CHANNELS, (NUM_AXES + 3)); i++)
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
} }

View File

@ -45,10 +45,10 @@
*/ */
void GcodeSuite::M260() { void GcodeSuite::M260() {
// Set the target address // Set the target address
if (parser.seen('A')) i2c.address(parser.value_byte()); if (parser.seenval('A')) i2c.address(parser.value_byte());
// Add a new byte to the buffer // Add a new byte to the buffer
if (parser.seen('B')) i2c.addbyte(parser.value_byte()); if (parser.seenval('B')) i2c.addbyte(parser.value_byte());
// Flush the buffer to the bus // Flush the buffer to the bus
if (parser.seen('S')) i2c.send(); if (parser.seen('S')) i2c.send();
@ -63,7 +63,7 @@ void GcodeSuite::M260() {
* Usage: M261 A<slave device address base 10> B<number of bytes> S<style> * Usage: M261 A<slave device address base 10> B<number of bytes> S<style>
*/ */
void GcodeSuite::M261() { void GcodeSuite::M261() {
if (parser.seen('A')) i2c.address(parser.value_byte()); if (parser.seenval('A')) i2c.address(parser.value_byte());
const uint8_t bytes = parser.byteval('B', 1), // Bytes to request const uint8_t bytes = parser.byteval('B', 1), // Bytes to request
style = parser.byteval('S'); // Serial output style (ASCII, HEX etc) style = parser.byteval('S'); // Serial output style (ASCII, HEX etc)

View File

@ -51,7 +51,7 @@ void GcodeSuite::G60() {
DEBUG_ECHOPGM(STR_SAVED_POS " S", slot, " :"); DEBUG_ECHOPGM(STR_SAVED_POS " S", slot, " :");
const xyze_pos_t &pos = stored_position[slot]; const xyze_pos_t &pos = stored_position[slot];
DEBUG_ECHOLNPGM_P( DEBUG_ECHOLNPGM_P(
LIST_N(DOUBLE(LINEAR_AXES), PSTR(" : X"), pos.x, SP_Y_STR, pos.y, SP_Z_STR, pos.z, SP_I_STR, pos.i, SP_J_STR, pos.j, SP_K_STR, pos.k) LIST_N(DOUBLE(LINEAR_AXES), SP_X_STR, pos.x, SP_Y_STR, pos.y, SP_Z_STR, pos.z, SP_I_STR, pos.i, SP_J_STR, pos.j, SP_K_STR, pos.k)
#if HAS_EXTRUDERS #if HAS_EXTRUDERS
, SP_E_LBL, pos.e , SP_E_LBL, pos.e
#endif #endif

View File

@ -71,7 +71,7 @@ void GcodeSuite::G61() {
if (parser.seen(LINEAR_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K))) { if (parser.seen(LINEAR_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K))) {
DEBUG_ECHOPGM(STR_RESTORING_POS " S", slot); DEBUG_ECHOPGM(STR_RESTORING_POS " S", slot);
LOOP_LINEAR_AXES(i) { LOOP_LINEAR_AXES(i) {
destination[i] = parser.seen(AXIS_CHAR(i)) destination[i] = parser.seenval(AXIS_CHAR(i))
? stored_position[slot][i] + parser.value_axis_units((AxisEnum)i) ? stored_position[slot][i] + parser.value_axis_units((AxisEnum)i)
: current_position[i]; : current_position[i];
DEBUG_CHAR(' ', AXIS_CHAR(i)); DEBUG_CHAR(' ', AXIS_CHAR(i));

View File

@ -74,7 +74,9 @@ void GcodeSuite::M125() {
); );
// Lift Z axis // Lift Z axis
if (parser.seenval('Z')) park_point.z = parser.linearval('Z'); #if HAS_Z_AXIS
if (parser.seenval('Z')) park_point.z = parser.linearval('Z');
#endif
#if HAS_HOTEND_OFFSET && NONE(DUAL_X_CARRIAGE, DELTA) #if HAS_HOTEND_OFFSET && NONE(DUAL_X_CARRIAGE, DELTA)
park_point += hotend_offset[active_extruder]; park_point += hotend_offset[active_extruder];

View File

@ -54,8 +54,11 @@
* *
* E[distance] - Retract the filament this far * E[distance] - Retract the filament this far
* Z[distance] - Move the Z axis by this distance * Z[distance] - Move the Z axis by this distance
* X[position] - Move to this X position, with Y * X[position] - Move to this X position (instead of NOZZLE_PARK_POINT.x)
* Y[position] - Move to this Y position, with X * Y[position] - Move to this Y position (instead of NOZZLE_PARK_POINT.y)
* I[position] - Move to this I position (instead of NOZZLE_PARK_POINT.i)
* J[position] - Move to this J position (instead of NOZZLE_PARK_POINT.j)
* K[position] - Move to this K position (instead of NOZZLE_PARK_POINT.k)
* U[distance] - Retract distance for removal (manual reload) * U[distance] - Retract distance for removal (manual reload)
* L[distance] - Extrude distance for insertion (manual reload) * L[distance] - Extrude distance for insertion (manual reload)
* B[count] - Number of times to beep, -1 for indefinite (if equipped with a buzzer) * B[count] - Number of times to beep, -1 for indefinite (if equipped with a buzzer)
@ -118,25 +121,21 @@ void GcodeSuite::M600() {
// Move XY axes to filament change position or given position // Move XY axes to filament change position or given position
LINEAR_AXIS_CODE( LINEAR_AXIS_CODE(
if (parser.seenval('X')) park_point.x = parser.linearval('X'), if (parser.seenval('X')) park_point.x = parser.value_linear_units(),
if (parser.seenval('Y')) park_point.y = parser.linearval('Y'), if (parser.seenval('Y')) park_point.y = parser.value_linear_units(),
if (parser.seenval('Z')) park_point.z = parser.linearval('Z'), // Lift Z axis if (parser.seenval('Z')) park_point.z = parser.value_linear_units(), // Lift Z axis
if (parser.seenval(AXIS4_NAME)) park_point.i = parser.linearval(AXIS4_NAME), if (parser.seenval('I')) park_point.i = parser.value_linear_units(),
if (parser.seenval(AXIS5_NAME)) park_point.j = parser.linearval(AXIS5_NAME), if (parser.seenval('J')) park_point.j = parser.value_linear_units(),
if (parser.seenval(AXIS6_NAME)) park_point.k = parser.linearval(AXIS6_NAME) if (parser.seenval('K')) park_point.k = parser.value_linear_units()
); );
#if HAS_HOTEND_OFFSET && NONE(DUAL_X_CARRIAGE, DELTA) #if HAS_HOTEND_OFFSET && NONE(DUAL_X_CARRIAGE, DELTA)
park_point += hotend_offset[active_extruder]; park_point += hotend_offset[active_extruder];
#endif #endif
#if ENABLED(MMU2_MENUS) // Unload filament
// For MMU2, when enabled, reset retract value so it doesn't mess with MMU filament handling // For MMU2, when enabled, reset retract value so it doesn't mess with MMU filament handling
const float unload_length = standardM600 ? -ABS(parser.axisunitsval('U', E_AXIS, fc_settings[active_extruder].unload_length)) : 0.5f; const float unload_length = standardM600 ? -ABS(parser.axisunitsval('U', E_AXIS, fc_settings[active_extruder].unload_length)) : 0.5f;
#else
// Unload filament
const float unload_length = -ABS(parser.axisunitsval('U', E_AXIS, fc_settings[active_extruder].unload_length));
#endif
const int beep_count = parser.intval('B', -1 const int beep_count = parser.intval('B', -1
#ifdef FILAMENT_CHANGE_ALERT_BEEPS #ifdef FILAMENT_CHANGE_ALERT_BEEPS

View File

@ -48,7 +48,7 @@ void GcodeSuite::M603() {
if (target_extruder < 0) return; if (target_extruder < 0) return;
// Unload length // Unload length
if (parser.seen('U')) { if (parser.seenval('U')) {
fc_settings[target_extruder].unload_length = ABS(parser.value_axis_units(E_AXIS)); fc_settings[target_extruder].unload_length = ABS(parser.value_axis_units(E_AXIS));
#if ENABLED(PREVENT_LENGTHY_EXTRUDE) #if ENABLED(PREVENT_LENGTHY_EXTRUDE)
NOMORE(fc_settings[target_extruder].unload_length, EXTRUDE_MAXLENGTH); NOMORE(fc_settings[target_extruder].unload_length, EXTRUDE_MAXLENGTH);
@ -56,7 +56,7 @@ void GcodeSuite::M603() {
} }
// Load length // Load length
if (parser.seen('L')) { if (parser.seenval('L')) {
fc_settings[target_extruder].load_length = ABS(parser.value_axis_units(E_AXIS)); fc_settings[target_extruder].load_length = ABS(parser.value_axis_units(E_AXIS));
#if ENABLED(PREVENT_LENGTHY_EXTRUDE) #if ENABLED(PREVENT_LENGTHY_EXTRUDE)
NOMORE(fc_settings[target_extruder].load_length, EXTRUDE_MAXLENGTH); NOMORE(fc_settings[target_extruder].load_length, EXTRUDE_MAXLENGTH);

View File

@ -106,8 +106,8 @@ void GcodeSuite::M701() {
#else #else
constexpr float purge_length = ADVANCED_PAUSE_PURGE_LENGTH, constexpr float purge_length = ADVANCED_PAUSE_PURGE_LENGTH,
slow_load_length = FILAMENT_CHANGE_SLOW_LOAD_LENGTH; slow_load_length = FILAMENT_CHANGE_SLOW_LOAD_LENGTH;
const float fast_load_length = ABS(parser.seen('L') ? parser.value_axis_units(E_AXIS) const float fast_load_length = ABS(parser.seenval('L') ? parser.value_axis_units(E_AXIS)
: fc_settings[active_extruder].load_length); : fc_settings[active_extruder].load_length);
load_filament( load_filament(
slow_load_length, fast_load_length, purge_length, slow_load_length, fast_load_length, purge_length,
FILAMENT_CHANGE_ALERT_BEEPS, FILAMENT_CHANGE_ALERT_BEEPS,

View File

@ -48,7 +48,7 @@ void GcodeSuite::M412() {
if (seenR || seenS) runout.reset(); if (seenR || seenS) runout.reset();
if (seenS) runout.enabled = parser.value_bool(); if (seenS) runout.enabled = parser.value_bool();
#if HAS_FILAMENT_RUNOUT_DISTANCE #if HAS_FILAMENT_RUNOUT_DISTANCE
if (parser.seen('D')) runout.set_runout_distance(parser.value_linear_units()); if (parser.seenval('D')) runout.set_runout_distance(parser.value_linear_units());
#endif #endif
} }
else { else {

View File

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

View File

@ -187,10 +187,15 @@ void GcodeSuite::M569_report(const bool forReplay/*=true*/) {
if (TERN0(Z3_HAS_STEALTHCHOP, stepperZ3.get_stored_stealthChop())) { say_M569(forReplay, F("I2 Z"), true); } if (TERN0(Z3_HAS_STEALTHCHOP, stepperZ3.get_stored_stealthChop())) { say_M569(forReplay, F("I2 Z"), true); }
if (TERN0(Z4_HAS_STEALTHCHOP, stepperZ4.get_stored_stealthChop())) { say_M569(forReplay, F("I3 Z"), true); } if (TERN0(Z4_HAS_STEALTHCHOP, stepperZ4.get_stored_stealthChop())) { say_M569(forReplay, F("I3 Z"), true); }
if (TERN0( I_HAS_STEALTHCHOP, stepperI.get_stored_stealthChop())) { say_M569(forReplay, FPSTR(SP_I_STR), true); } #if HAS_I_AXIS
if (TERN0( J_HAS_STEALTHCHOP, stepperJ.get_stored_stealthChop())) { say_M569(forReplay, FPSTR(SP_J_STR), true); } if (TERN0(I_HAS_STEALTHCHOP, stepperI.get_stored_stealthChop())) { say_M569(forReplay, FPSTR(SP_I_STR), true); }
if (TERN0( K_HAS_STEALTHCHOP, stepperK.get_stored_stealthChop())) { say_M569(forReplay, FPSTR(SP_K_STR), true); } #endif
#if HAS_J_AXIS
if (TERN0(J_HAS_STEALTHCHOP, stepperJ.get_stored_stealthChop())) { say_M569(forReplay, FPSTR(SP_J_STR), true); }
#endif
#if HAS_K_AXIS
if (TERN0(K_HAS_STEALTHCHOP, stepperK.get_stored_stealthChop())) { say_M569(forReplay, FPSTR(SP_K_STR), true); }
#endif
if (TERN0(E0_HAS_STEALTHCHOP, stepperE0.get_stored_stealthChop())) { say_M569(forReplay, F("T0 E"), true); } if (TERN0(E0_HAS_STEALTHCHOP, stepperE0.get_stored_stealthChop())) { say_M569(forReplay, F("T0 E"), true); }
if (TERN0(E1_HAS_STEALTHCHOP, stepperE1.get_stored_stealthChop())) { say_M569(forReplay, F("T1 E"), true); } if (TERN0(E1_HAS_STEALTHCHOP, stepperE1.get_stored_stealthChop())) { say_M569(forReplay, F("T1 E"), true); }
if (TERN0(E2_HAS_STEALTHCHOP, stepperE2.get_stored_stealthChop())) { say_M569(forReplay, F("T2 E"), true); } if (TERN0(E2_HAS_STEALTHCHOP, stepperE2.get_stored_stealthChop())) { say_M569(forReplay, F("T2 E"), true); }

View File

@ -137,7 +137,7 @@
/** /**
* M912: Clear TMC stepper driver overtemperature pre-warn flag held by the library * M912: Clear TMC stepper driver overtemperature pre-warn flag held by the library
* Specify one or more axes with X, Y, Z, X1, Y1, Z1, X2, Y2, Z2, Z3, Z4 and E[index]. * Specify one or more axes with X, Y, Z, X1, Y1, Z1, X2, Y2, Z2, Z3, Z4, A, B, C, and E[index].
* If no axes are given, clear all. * If no axes are given, clear all.
* *
* Examples: * Examples:

View File

@ -53,7 +53,7 @@ GcodeSuite gcode;
#include "../feature/cancel_object.h" #include "../feature/cancel_object.h"
#endif #endif
#if ENABLED(LASER_MOVE_POWER) #if ENABLED(LASER_FEATURE)
#include "../feature/spindle_laser.h" #include "../feature/spindle_laser.h"
#endif #endif
@ -207,8 +207,11 @@ void GcodeSuite::get_destination_from_command() {
recovery.save(); recovery.save();
#endif #endif
if (parser.floatval('F') > 0) if (parser.floatval('F') > 0) {
feedrate_mm_s = parser.value_feedrate(); feedrate_mm_s = parser.value_feedrate();
// Update the cutter feed rate for use by M4 I set inline moves.
TERN_(LASER_FEATURE, cutter.feedrate_mm_m = MMS_TO_MMM(feedrate_mm_s));
}
#if BOTH(PRINTCOUNTER, HAS_EXTRUDERS) #if BOTH(PRINTCOUNTER, HAS_EXTRUDERS)
if (!DEBUGGING(DRYRUN) && !skip_move) if (!DEBUGGING(DRYRUN) && !skip_move)
@ -220,15 +223,29 @@ void GcodeSuite::get_destination_from_command() {
M165(); M165();
#endif #endif
#if ENABLED(LASER_MOVE_POWER) #if ENABLED(LASER_FEATURE)
// Set the laser power in the planner to configure this move if (cutter.cutter_mode == CUTTER_MODE_CONTINUOUS || cutter.cutter_mode == CUTTER_MODE_DYNAMIC) {
if (parser.seen('S')) { // Set the cutter power in the planner to configure this move
const float spwr = parser.value_float(); cutter.last_feedrate_mm_m = 0;
cutter.inline_power(TERN(SPINDLE_LASER_USE_PWM, cutter.power_to_range(cutter_power_t(round(spwr))), spwr > 0 ? 255 : 0)); if (WITHIN(parser.codenum, 1, TERN(ARC_SUPPORT, 3, 1)) || TERN0(BEZIER_CURVE_SUPPORT, parser.codenum == 5)) {
planner.laser_inline.status.isPowered = true;
if (parser.seen('I')) cutter.set_enabled(true); // This is set for backward LightBurn compatibility.
if (parser.seen('S')) {
const float v = parser.value_float(),
u = TERN(LASER_POWER_TRAP, v, cutter.power_to_range(v));
cutter.menuPower = cutter.unitPower = u;
cutter.inline_power(TERN(SPINDLE_LASER_USE_PWM, cutter.upower_to_ocr(u), u > 0 ? 255 : 0));
}
}
else if (parser.codenum == 0) {
// For dynamic mode we need to flag isPowered off, dynamic power is calculated in the stepper based on feedrate.
if (cutter.cutter_mode == CUTTER_MODE_DYNAMIC) planner.laser_inline.status.isPowered = false;
cutter.inline_power(0); // This is planner-based so only set power and do not disable inline control flags.
}
} }
else if (ENABLED(LASER_MOVE_G0_OFF) && parser.codenum == 0) // G0 else if (parser.codenum == 0)
cutter.set_inline_enabled(false); cutter.apply_power(0);
#endif #endif // LASER_FEATURE
} }
/** /**
@ -845,6 +862,10 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
case 421: M421(); break; // M421: Set a Mesh Bed Leveling Z coordinate case 421: M421(); break; // M421: Set a Mesh Bed Leveling Z coordinate
#endif #endif
#if ENABLED(X_AXIS_TWIST_COMPENSATION)
case 423: M423(); break; // M423: Reset, modify, or report X-Twist Compensation data
#endif
#if ENABLED(BACKLASH_GCODE) #if ENABLED(BACKLASH_GCODE)
case 425: M425(); break; // M425: Tune backlash compensation case 425: M425(); break; // M425: Tune backlash compensation
#endif #endif
@ -909,7 +930,7 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
#endif #endif
#if IS_KINEMATIC #if IS_KINEMATIC
case 665: M665(); break; // M665: Set Delta/SCARA parameters case 665: M665(); break; // M665: Set Kinematics parameters
#endif #endif
#if ENABLED(DELTA) || HAS_EXTRA_ENDSTOPS #if ENABLED(DELTA) || HAS_EXTRA_ENDSTOPS

View File

@ -262,6 +262,7 @@
* M605 - Set Dual X-Carriage movement mode: "M605 S<mode> [X<x_offset>] [R<temp_offset>]". (Requires DUAL_X_CARRIAGE) * M605 - Set Dual X-Carriage movement mode: "M605 S<mode> [X<x_offset>] [R<temp_offset>]". (Requires DUAL_X_CARRIAGE)
* M665 - Set delta configurations: "M665 H<delta height> L<diagonal rod> R<delta radius> S<segments/s> B<calibration radius> X<Alpha angle trim> Y<Beta angle trim> Z<Gamma angle trim> (Requires DELTA) * M665 - Set delta configurations: "M665 H<delta height> L<diagonal rod> R<delta radius> S<segments/s> B<calibration radius> X<Alpha angle trim> Y<Beta angle trim> Z<Gamma angle trim> (Requires DELTA)
* Set SCARA configurations: "M665 S<segments-per-second> P<theta-psi-offset> T<theta-offset> Z<z-offset> (Requires MORGAN_SCARA or MP_SCARA) * Set SCARA configurations: "M665 S<segments-per-second> P<theta-psi-offset> T<theta-offset> Z<z-offset> (Requires MORGAN_SCARA or MP_SCARA)
* Set Polargraph draw area and belt length: "M665 S<segments-per-second> L<draw-area-left> R<draw-area-right> T<draw-area-top> B<draw-area-bottom> H<max-belt-length>"
* M666 - Set/get offsets for delta (Requires DELTA) or dual endstops. (Requires [XYZ]_DUAL_ENDSTOPS) * M666 - Set/get offsets for delta (Requires DELTA) or dual endstops. (Requires [XYZ]_DUAL_ENDSTOPS)
* M672 - Set/Reset Duet Smart Effector's sensitivity. (Requires DUET_SMART_EFFECTOR and SMART_EFFECTOR_MOD_PIN) * M672 - Set/Reset Duet Smart Effector's sensitivity. (Requires DUET_SMART_EFFECTOR and SMART_EFFECTOR_MOD_PIN)
* M701 - Load filament (Requires FILAMENT_LOAD_UNLOAD_GCODES) * M701 - Load filament (Requires FILAMENT_LOAD_UNLOAD_GCODES)
@ -885,7 +886,7 @@ private:
static void M250_report(const bool forReplay=true); static void M250_report(const bool forReplay=true);
#endif #endif
#if HAS_DISPLAY_SLEEP #if HAS_GCODE_M255
static void M255(); static void M255();
static void M255_report(const bool forReplay=true); static void M255_report(const bool forReplay=true);
#endif #endif

View File

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

View File

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

View File

@ -40,13 +40,12 @@
void GcodeSuite::M206() { void GcodeSuite::M206() {
if (!parser.seen_any()) return M206_report(); if (!parser.seen_any()) return M206_report();
LOOP_LINEAR_AXES(i) LOOP_LINEAR_AXES(a)
if (parser.seen(AXIS_CHAR(i))) if (parser.seenval(AXIS_CHAR(a))) set_home_offset((AxisEnum)a, parser.value_axis_units((AxisEnum)a));
set_home_offset((AxisEnum)i, parser.value_linear_units());
#if ENABLED(MORGAN_SCARA) #if ENABLED(MORGAN_SCARA)
if (parser.seen('T')) set_home_offset(A_AXIS, parser.value_float()); // Theta if (parser.seenval('T')) set_home_offset(A_AXIS, parser.value_float()); // Theta
if (parser.seen('P')) set_home_offset(B_AXIS, parser.value_float()); // Psi if (parser.seenval('P')) set_home_offset(B_AXIS, parser.value_float()); // Psi
#endif #endif
report_current_position(); report_current_position();

View File

@ -37,7 +37,7 @@
void report_all_axis_pos(const xyze_pos_t &pos, const uint8_t n=XYZE, const uint8_t precision=3) { void report_all_axis_pos(const xyze_pos_t &pos, const uint8_t n=XYZE, const uint8_t precision=3) {
char str[12]; char str[12];
LOOP_L_N(a, n) { LOOP_L_N(a, n) {
SERIAL_CHAR(' ', axis_codes[a], ':'); SERIAL_ECHOPGM_P((PGM_P)pgm_read_ptr(&SP_AXIS_LBL[a]));
if (pos[a] >= 0) SERIAL_CHAR(' '); if (pos[a] >= 0) SERIAL_CHAR(' ');
SERIAL_ECHO(dtostrf(pos[a], 1, precision, str)); SERIAL_ECHO(dtostrf(pos[a], 1, precision, str));
} }
@ -47,10 +47,7 @@
void report_linear_axis_pos(const xyz_pos_t &pos, const uint8_t precision=3) { void report_linear_axis_pos(const xyz_pos_t &pos, const uint8_t precision=3) {
char str[12]; char str[12];
LOOP_LINEAR_AXES(a) { LOOP_LINEAR_AXES(a) SERIAL_ECHOPGM_P((PGM_P)pgm_read_ptr(&SP_AXIS_LBL[a]), dtostrf(pos[a], 1, precision, str));
SERIAL_CHAR(' ', AXIS_CHAR(a), ':');
SERIAL_ECHO(dtostrf(pos[a], 1, precision, str));
}
SERIAL_EOL(); SERIAL_EOL();
} }
@ -163,8 +160,7 @@
SERIAL_ECHOPGM("Stepper:"); SERIAL_ECHOPGM("Stepper:");
LOOP_LOGICAL_AXES(i) { LOOP_LOGICAL_AXES(i) {
SERIAL_CHAR(' ', axis_codes[i], ':'); SERIAL_ECHOPGM_P((PGM_P)pgm_read_ptr(&SP_AXIS_LBL[i]), stepper.position((AxisEnum)i));
SERIAL_ECHO(stepper.position((AxisEnum)i));
} }
SERIAL_EOL(); SERIAL_EOL();

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