Compare commits
94 Commits
2.1-rigidb
...
2.0.9.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5312bdedf9 | ||
|
|
36d508c5a0 | ||
|
|
9f5aab1a61 | ||
|
|
62d29ade42 | ||
|
|
c801cc4830 | ||
|
|
bc91b1cdcd | ||
|
|
c847ef02a1 | ||
|
|
cdda90f56c | ||
|
|
ad4bc378b7 | ||
|
|
99710b94d2 | ||
|
|
78fc5acca9 | ||
|
|
e616542c89 | ||
|
|
a50bb96d2d | ||
|
|
653f0ab9dd | ||
|
|
c96ed8998b | ||
|
|
b025c18d5b | ||
|
|
b49da1d4ca | ||
|
|
90074e6260 | ||
|
|
e570c4cc2e | ||
|
|
543bbf02fc | ||
|
|
5ccdc9ced7 | ||
|
|
ddb0168e29 | ||
|
|
0caf234aa5 | ||
|
|
dddbc4d730 | ||
|
|
08e6e8b9be | ||
|
|
12ae80bcec | ||
|
|
9e530cd27b | ||
|
|
0ec1cb58c7 | ||
|
|
b548e21b65 | ||
|
|
e170460855 | ||
|
|
b7b2286e49 | ||
|
|
047d0264c5 | ||
|
|
c56fb1c182 | ||
|
|
d5a79c27fe | ||
|
|
1e3fe65b9d | ||
|
|
af4160af6f | ||
|
|
53b73bbd7f | ||
|
|
3b37e85949 | ||
|
|
a1881f70a8 | ||
|
|
6ad7f7ce98 | ||
|
|
9fe4d2cc6c | ||
|
|
5bd0541985 | ||
|
|
35d5393a3e | ||
|
|
1ffc4ba861 | ||
|
|
2bf6573098 | ||
|
|
5e0a39265a | ||
|
|
495002e158 | ||
|
|
adeca47292 | ||
|
|
686d1fbb51 | ||
|
|
8f84ce72e1 | ||
|
|
5bf02e39a9 | ||
|
|
a5b076dff7 | ||
|
|
b79231cc59 | ||
|
|
86e6f9e38e | ||
|
|
b3018da60c | ||
|
|
0d04aa960f | ||
|
|
0d34c2e287 | ||
|
|
1690f49656 | ||
|
|
dbdb39f60f | ||
|
|
843c04baa6 | ||
|
|
a7c58c1fd6 | ||
|
|
3af5c32ea2 | ||
|
|
4039075a1d | ||
|
|
ed796c8354 | ||
|
|
f3c64fd397 | ||
|
|
b220342b26 | ||
|
|
4dad587188 | ||
|
|
1efe48ef65 | ||
|
|
ae8365a4e5 | ||
|
|
dd68461bb1 | ||
|
|
010fbcccf7 | ||
|
|
185fe5696c | ||
|
|
7edd37bc5a | ||
|
|
0000427021 | ||
|
|
0d1d125bc6 | ||
|
|
22e82a13d9 | ||
|
|
70d72354e2 | ||
|
|
821f4983d0 | ||
|
|
15ca479708 | ||
|
|
2b8d115ebc | ||
|
|
ae78a8844a | ||
|
|
f26438ef28 | ||
|
|
ce6c8adcb1 | ||
|
|
d57cf9bd6b | ||
|
|
5408259f51 | ||
|
|
f31178f868 | ||
|
|
f976e56a19 | ||
|
|
571007e5c9 | ||
|
|
00527f38d5 | ||
|
|
1c7696838b | ||
|
|
ad786a7930 | ||
|
|
ce9c81dfa1 | ||
|
|
92910721d0 | ||
|
|
236251a2ce |
@ -35,7 +35,7 @@
|
||||
*
|
||||
* Advanced settings can be found in Configuration_adv.h
|
||||
*/
|
||||
#define CONFIGURATION_H_VERSION 02000904
|
||||
#define CONFIGURATION_H_VERSION 02000905
|
||||
|
||||
//===========================================================================
|
||||
//============================= Getting Started =============================
|
||||
@ -57,15 +57,6 @@
|
||||
* 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
|
||||
|
||||
// Author info of this build printed to the host during boot and M115
|
||||
@ -186,28 +177,27 @@
|
||||
//#define E7_DRIVER_TYPE A4988
|
||||
|
||||
/**
|
||||
* Axis codes for additional axes:
|
||||
* This defines the axis code that is used in G-code commands to
|
||||
* reference a specific axis.
|
||||
* 'A' for rotational axis parallel to X
|
||||
* 'B' for rotational axis parallel to Y
|
||||
* 'C' for rotational axis parallel to Z
|
||||
* 'U' for secondary linear axis parallel to X
|
||||
* 'V' for secondary linear axis parallel to Y
|
||||
* 'W' for secondary linear axis parallel to Z
|
||||
* Regardless of the settings, firmware-internal axis IDs are
|
||||
* I (AXIS4), J (AXIS5), K (AXIS6).
|
||||
* Additional Axis Settings
|
||||
*
|
||||
* AXISn_NAME defines the letter used to refer to the axis in (most) G-code commands.
|
||||
* By convention the names and roles are typically:
|
||||
* 'A' : Rotational axis parallel to X
|
||||
* 'B' : Rotational axis parallel to Y
|
||||
* 'C' : Rotational axis parallel to Z
|
||||
* 'U' : Secondary linear axis parallel to X
|
||||
* 'V' : Secondary linear axis parallel to Y
|
||||
* 'W' : Secondary linear axis parallel to Z
|
||||
*
|
||||
* Regardless of these settings the axes are internally named I, J, K.
|
||||
*/
|
||||
#ifdef I_DRIVER_TYPE
|
||||
#define AXIS4_NAME 'A' // :['A', 'B', 'C', 'U', 'V', 'W']
|
||||
#endif
|
||||
#ifdef J_DRIVER_TYPE
|
||||
#define AXIS5_NAME 'B' // :['B', 'C', 'U', 'V', 'W']
|
||||
#define AXIS5_ROTATES
|
||||
#endif
|
||||
#ifdef K_DRIVER_TYPE
|
||||
#define AXIS6_NAME 'C' // :['C', 'U', 'V', 'W']
|
||||
#define AXIS6_ROTATES
|
||||
#endif
|
||||
|
||||
// @section extruder
|
||||
@ -643,7 +633,7 @@
|
||||
*
|
||||
* 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
|
||||
* 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)
|
||||
//#define MPC_EDIT_MENU // Add MPC editing to the "Advanced Settings" menu. (~1300 bytes of flash)
|
||||
@ -845,6 +835,141 @@
|
||||
#define POLAR_SEGMENTS_PER_SECOND 5
|
||||
#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 ===========================
|
||||
//===========================================================================
|
||||
@ -1001,9 +1126,9 @@
|
||||
* M204 R Retract Acceleration
|
||||
* M204 T Travel Acceleration
|
||||
*/
|
||||
#define DEFAULT_ACCELERATION 3000 // X, Y, Z and E acceleration for printing moves
|
||||
#define DEFAULT_ACCELERATION 3000 // X, Y, Z ... and E acceleration for printing moves
|
||||
#define DEFAULT_RETRACT_ACCELERATION 3000 // E acceleration for retracts
|
||||
#define DEFAULT_TRAVEL_ACCELERATION 3000 // X, Y, Z acceleration for travel (non printing) moves
|
||||
#define DEFAULT_TRAVEL_ACCELERATION 3000 // X, Y, Z ... acceleration for travel (non printing) moves
|
||||
|
||||
/**
|
||||
* Default Jerk limits (mm/s)
|
||||
@ -1185,9 +1310,37 @@
|
||||
*/
|
||||
//#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 }
|
||||
@ -1738,7 +1891,7 @@
|
||||
//#define 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_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
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
*
|
||||
* Basic settings can be found in Configuration.h
|
||||
*/
|
||||
#define CONFIGURATION_ADV_H_VERSION 02000904
|
||||
#define CONFIGURATION_ADV_H_VERSION 02000905
|
||||
|
||||
//===========================================================================
|
||||
//============================= Thermal Settings ============================
|
||||
@ -54,87 +54,87 @@
|
||||
// Custom Thermistor 1000 parameters
|
||||
//
|
||||
#if TEMP_SENSOR_0 == 1000
|
||||
#define HOTEND0_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define HOTEND0_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define HOTEND0_BETA 3950 // Beta value
|
||||
#define HOTEND0_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define HOTEND0_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define HOTEND0_BETA 3950 // Beta value
|
||||
#endif
|
||||
|
||||
#if TEMP_SENSOR_1 == 1000
|
||||
#define HOTEND1_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define HOTEND1_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define HOTEND1_BETA 3950 // Beta value
|
||||
#define HOTEND1_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define HOTEND1_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define HOTEND1_BETA 3950 // Beta value
|
||||
#endif
|
||||
|
||||
#if TEMP_SENSOR_2 == 1000
|
||||
#define HOTEND2_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define HOTEND2_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define HOTEND2_BETA 3950 // Beta value
|
||||
#define HOTEND2_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define HOTEND2_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define HOTEND2_BETA 3950 // Beta value
|
||||
#endif
|
||||
|
||||
#if TEMP_SENSOR_3 == 1000
|
||||
#define HOTEND3_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define HOTEND3_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define HOTEND3_BETA 3950 // Beta value
|
||||
#define HOTEND3_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define HOTEND3_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define HOTEND3_BETA 3950 // Beta value
|
||||
#endif
|
||||
|
||||
#if TEMP_SENSOR_4 == 1000
|
||||
#define HOTEND4_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define HOTEND4_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define HOTEND4_BETA 3950 // Beta value
|
||||
#define HOTEND4_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define HOTEND4_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define HOTEND4_BETA 3950 // Beta value
|
||||
#endif
|
||||
|
||||
#if TEMP_SENSOR_5 == 1000
|
||||
#define HOTEND5_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define HOTEND5_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define HOTEND5_BETA 3950 // Beta value
|
||||
#define HOTEND5_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define HOTEND5_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define HOTEND5_BETA 3950 // Beta value
|
||||
#endif
|
||||
|
||||
#if TEMP_SENSOR_6 == 1000
|
||||
#define HOTEND6_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define HOTEND6_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define HOTEND6_BETA 3950 // Beta value
|
||||
#define HOTEND6_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define HOTEND6_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define HOTEND6_BETA 3950 // Beta value
|
||||
#endif
|
||||
|
||||
#if TEMP_SENSOR_7 == 1000
|
||||
#define HOTEND7_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define HOTEND7_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define HOTEND7_BETA 3950 // Beta value
|
||||
#define HOTEND7_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define HOTEND7_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define HOTEND7_BETA 3950 // Beta value
|
||||
#endif
|
||||
|
||||
#if TEMP_SENSOR_BED == 1000
|
||||
#define BED_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define BED_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define BED_BETA 3950 // Beta value
|
||||
#define BED_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define BED_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define BED_BETA 3950 // Beta value
|
||||
#endif
|
||||
|
||||
#if TEMP_SENSOR_CHAMBER == 1000
|
||||
#define CHAMBER_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define CHAMBER_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define CHAMBER_BETA 3950 // Beta value
|
||||
#define CHAMBER_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define CHAMBER_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define CHAMBER_BETA 3950 // Beta value
|
||||
#endif
|
||||
|
||||
#if TEMP_SENSOR_COOLER == 1000
|
||||
#define COOLER_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define COOLER_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define COOLER_BETA 3950 // Beta value
|
||||
#define COOLER_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define COOLER_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define COOLER_BETA 3950 // Beta value
|
||||
#endif
|
||||
|
||||
#if TEMP_SENSOR_PROBE == 1000
|
||||
#define PROBE_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define PROBE_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define PROBE_BETA 3950 // Beta value
|
||||
#define PROBE_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define PROBE_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define PROBE_BETA 3950 // Beta value
|
||||
#endif
|
||||
|
||||
#if TEMP_SENSOR_BOARD == 1000
|
||||
#define BOARD_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define BOARD_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define BOARD_BETA 3950 // Beta value
|
||||
#define BOARD_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define BOARD_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define BOARD_BETA 3950 // Beta value
|
||||
#endif
|
||||
|
||||
#if TEMP_SENSOR_REDUNDANT == 1000
|
||||
#define REDUNDANT_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define REDUNDANT_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define REDUNDANT_BETA 3950 // Beta value
|
||||
#define REDUNDANT_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
|
||||
#define REDUNDANT_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
|
||||
#define REDUNDANT_BETA 3950 // Beta value
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -2423,7 +2423,7 @@
|
||||
|
||||
/**
|
||||
* 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_T1 "G1 A10" // Extra G-code to run while executing tool-change command T1
|
||||
@ -3472,6 +3472,9 @@
|
||||
#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_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
|
||||
|
||||
//#define AIR_EVACUATION // Cutter Vacuum / Laser Blower motor control with G-codes M10-M11
|
||||
@ -3545,8 +3548,11 @@
|
||||
#endif
|
||||
|
||||
// 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_MAX 999 // Caution: Menu may not show more than 3 characters
|
||||
#define LASER_TEST_PULSE_MIN 1 // (ms) Used with Laser Control Menu
|
||||
#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
|
||||
@ -3559,79 +3565,38 @@
|
||||
#define LASER_SAFETY_TIMEOUT_MS 1000 // (ms)
|
||||
|
||||
/**
|
||||
* Enable inline laser power to be handled in the planner / stepper routines.
|
||||
* 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).
|
||||
* Any M3 or G1/2/3/5 command with the 'I' parameter enables continuous inline power mode.
|
||||
*
|
||||
* This allows the laser to keep in perfect sync with the planner and removes
|
||||
* the powerup/down delay since lasers require negligible time.
|
||||
* e.g., 'M3 I' enables continuous inline power which is processed by the planner.
|
||||
* 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)
|
||||
/**
|
||||
* Scale the laser's power in proportion to the movement rate.
|
||||
*
|
||||
* - 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.
|
||||
* - Due to the limited power resolution this is only approximate.
|
||||
*/
|
||||
#define LASER_POWER_INLINE_TRAPEZOID
|
||||
/**
|
||||
* Enable M3 commands for laser mode inline power planner syncing.
|
||||
* 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
|
||||
* for a planner syncronization
|
||||
*/
|
||||
//#define LASER_POWER_SYNC
|
||||
|
||||
/**
|
||||
* Continuously calculate the current power (nominal_power * current_rate / nominal_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.
|
||||
*
|
||||
* LASER_POWER_INLINE_TRAPEZOID_CONT_PER defines how many step cycles there are between power updates. If your
|
||||
* 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_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
|
||||
/**
|
||||
* Scale the laser's power in proportion to the movement rate.
|
||||
*
|
||||
* - 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.
|
||||
* - Due to the limited power resolution this is only approximate.
|
||||
*/
|
||||
//#define LASER_POWER_TRAP
|
||||
|
||||
//
|
||||
// Laser I2C Ammeter (High precision INA226 low/high side module)
|
||||
|
||||
123
Marlin/Makefile
123
Marlin/Makefile
@ -109,7 +109,7 @@ LIQUID_TWI2 ?= 0
|
||||
# This defines if Wire is needed
|
||||
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.
|
||||
TONE ?= 1
|
||||
|
||||
@ -317,123 +317,10 @@ else ifeq ($(HARDWARE_MOTHERBOARD),1159)
|
||||
else ifeq ($(HARDWARE_MOTHERBOARD),1160)
|
||||
# Longer LKx PRO / Alfawise Uxx Pro (PRO version)
|
||||
else ifeq ($(HARDWARE_MOTHERBOARD),1161)
|
||||
|
||||
|
||||
# 3Drag Controller
|
||||
else ifeq ($(HARDWARE_MOTHERBOARD),1100)
|
||||
# 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)
|
||||
# Zonestar zrib V5.3 (Chinese RAMPS replica)
|
||||
else ifeq ($(HARDWARE_MOTHERBOARD),1162)
|
||||
# Pxmalion Core I3
|
||||
else ifeq ($(HARDWARE_MOTHERBOARD),1163)
|
||||
|
||||
#
|
||||
# RAMBo and derivatives
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
/**
|
||||
* 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
|
||||
@ -41,7 +41,7 @@
|
||||
* here we define this default string as the date where the latest release
|
||||
* 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.
|
||||
|
||||
@ -19,6 +19,10 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* HAL for Arduino AVR
|
||||
*/
|
||||
|
||||
#include "../shared/Marduino.h"
|
||||
#include "../shared/HAL_SPI.h"
|
||||
#include "fastio.h"
|
||||
|
||||
@ -66,27 +66,26 @@ static volatile int8_t Channel[_Nbr_16timers]; // counter for the s
|
||||
|
||||
/************ static functions common to all instances ***********************/
|
||||
|
||||
static inline void handle_interrupts(timer16_Sequence_t timer, volatile uint16_t* TCNTn, volatile uint16_t* OCRnA) {
|
||||
if (Channel[timer] < 0)
|
||||
*TCNTn = 0; // channel set to -1 indicated that refresh interval completed so reset the timer
|
||||
else {
|
||||
if (SERVO_INDEX(timer, Channel[timer]) < ServoCount && SERVO(timer, Channel[timer]).Pin.isActive)
|
||||
extDigitalWrite(SERVO(timer, Channel[timer]).Pin.nbr, LOW); // pulse this channel low if activated
|
||||
}
|
||||
static inline void handle_interrupts(const timer16_Sequence_t timer, volatile uint16_t* TCNTn, volatile uint16_t* OCRnA) {
|
||||
int8_t cho = Channel[timer]; // Handle the prior Channel[timer] first
|
||||
if (cho < 0) // Channel -1 indicates the refresh interval completed...
|
||||
*TCNTn = 0; // ...so reset the timer
|
||||
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
|
||||
if (SERVO_INDEX(timer, Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) {
|
||||
*OCRnA = *TCNTn + SERVO(timer, Channel[timer]).ticks;
|
||||
if (SERVO(timer, Channel[timer]).Pin.isActive) // check if activated
|
||||
extDigitalWrite(SERVO(timer, Channel[timer]).Pin.nbr, HIGH); // it's an active channel so pulse it high
|
||||
Channel[timer] = ++cho; // Handle the next channel (or 0)
|
||||
if (cho < SERVOS_PER_TIMER && SERVO_INDEX(timer, cho) < ServoCount) {
|
||||
*OCRnA = *TCNTn + SERVO(timer, cho).ticks; // set compare to current ticks plus duration
|
||||
if (SERVO(timer, cho).Pin.isActive) // activated?
|
||||
extDigitalWrite(SERVO(timer, cho).Pin.nbr, HIGH); // yes: pulse HIGH
|
||||
}
|
||||
else {
|
||||
// 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
|
||||
*OCRnA = (unsigned int)usToTicks(REFRESH_INTERVAL);
|
||||
else
|
||||
*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
|
||||
const unsigned int cval = ((unsigned)*TCNTn) + 32 / (SERVO_TIMER_PRESCALER), // allow 32 cycles to ensure the next OCR1A not missed
|
||||
ival = (unsigned int)usToTicks(REFRESH_INTERVAL); // at least REFRESH_INTERVAL has elapsed
|
||||
*OCRnA = max(cval, ival);
|
||||
|
||||
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 ******************************/
|
||||
|
||||
void initISR(timer16_Sequence_t timer) {
|
||||
#ifdef _useTimer1
|
||||
if (timer == _timer1) {
|
||||
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
|
||||
void initISR(const timer16_Sequence_t timer_index) {
|
||||
switch (timer_index) {
|
||||
default: break;
|
||||
|
||||
#ifdef _useTimer3
|
||||
if (timer == _timer3) {
|
||||
TCCR3A = 0; // normal counting mode
|
||||
TCCR3B = _BV(CS31); // set prescaler of 8
|
||||
TCNT3 = 0; // clear the timer count
|
||||
#ifdef __AVR_ATmega128__
|
||||
SBI(TIFR, OCF3A); // clear any pending interrupts;
|
||||
SBI(ETIMSK, OCIE3A); // enable the output compare interrupt
|
||||
#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
|
||||
}
|
||||
#endif
|
||||
#ifdef _useTimer1
|
||||
case _timer1:
|
||||
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
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef _useTimer4
|
||||
if (timer == _timer4) {
|
||||
TCCR4A = 0; // normal counting mode
|
||||
TCCR4B = _BV(CS41); // set prescaler of 8
|
||||
TCNT4 = 0; // clear the timer count
|
||||
TIFR4 = _BV(OCF4A); // clear any pending interrupts;
|
||||
TIMSK4 = _BV(OCIE4A); // enable the output compare interrupt
|
||||
}
|
||||
#endif
|
||||
#ifdef _useTimer3
|
||||
case _timer3:
|
||||
TCCR3A = 0; // normal counting mode
|
||||
TCCR3B = _BV(CS31); // set prescaler of 8
|
||||
TCNT3 = 0; // clear the timer count
|
||||
#ifdef __AVR_ATmega128__
|
||||
SBI(TIFR, OCF3A); // clear any pending interrupts;
|
||||
SBI(ETIMSK, OCIE3A); // enable the output compare interrupt
|
||||
#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
|
||||
if (timer == _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
|
||||
}
|
||||
#endif
|
||||
#ifdef _useTimer4
|
||||
case _timer4:
|
||||
TCCR4A = 0; // normal counting mode
|
||||
TCCR4B = _BV(CS41); // set prescaler of 8
|
||||
TCNT4 = 0; // clear the timer count
|
||||
TIFR4 = _BV(OCF4A); // clear any pending interrupts;
|
||||
TIMSK4 = _BV(OCIE4A); // enable the output compare interrupt
|
||||
break;
|
||||
#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
|
||||
#ifdef WIRING
|
||||
if (timer == _timer1) {
|
||||
CBI(
|
||||
#if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__)
|
||||
TIMSK1
|
||||
#else
|
||||
TIMSK
|
||||
#endif
|
||||
, OCIE1A); // disable timer 1 output compare interrupt
|
||||
timerDetach(TIMER1OUTCOMPAREA_INT);
|
||||
}
|
||||
else if (timer == _timer3) {
|
||||
CBI(
|
||||
#if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__)
|
||||
TIMSK3
|
||||
#else
|
||||
ETIMSK
|
||||
#endif
|
||||
, OCIE3A); // disable the timer3 output compare A interrupt
|
||||
timerDetach(TIMER3OUTCOMPAREA_INT);
|
||||
switch (timer_index) {
|
||||
default: break;
|
||||
|
||||
case _timer1:
|
||||
CBI(
|
||||
#if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__)
|
||||
TIMSK1
|
||||
#else
|
||||
TIMSK
|
||||
#endif
|
||||
, OCIE1A // disable timer 1 output compare interrupt
|
||||
);
|
||||
timerDetach(TIMER1OUTCOMPAREA_INT);
|
||||
break;
|
||||
|
||||
case _timer3:
|
||||
CBI(
|
||||
#if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__)
|
||||
TIMSK3
|
||||
#else
|
||||
ETIMSK
|
||||
#endif
|
||||
, OCIE3A // disable the timer3 output compare A interrupt
|
||||
);
|
||||
timerDetach(TIMER3OUTCOMPAREA_INT);
|
||||
break;
|
||||
}
|
||||
#else // !WIRING
|
||||
// For arduino - in future: call here to a currently undefined function to reset the timer
|
||||
UNUSED(timer);
|
||||
UNUSED(timer_index);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -47,12 +47,12 @@
|
||||
#include "../shared/servo.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.
|
||||
// ------------------------
|
||||
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
|
||||
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); }
|
||||
#endif
|
||||
|
||||
void Servo_Handler(timer16_Sequence_t timer, Tc *tc, uint8_t channel) {
|
||||
// clear interrupt
|
||||
tc->TC_CHANNEL[channel].TC_SR;
|
||||
if (Channel[timer] < 0)
|
||||
tc->TC_CHANNEL[channel].TC_CCR |= TC_CCR_SWTRG; // channel set to -1 indicated that refresh interval completed so reset the timer
|
||||
else if (SERVO_INDEX(timer, Channel[timer]) < ServoCount && SERVO(timer, Channel[timer]).Pin.isActive)
|
||||
extDigitalWrite(SERVO(timer, Channel[timer]).Pin.nbr, LOW); // pulse this channel low if activated
|
||||
void Servo_Handler(const timer16_Sequence_t timer, Tc *tc, const uint8_t channel) {
|
||||
static int8_t Channel[_Nbr_16timers]; // Servo counters to pulse (or -1 for refresh interval)
|
||||
int8_t cho = Channel[timer]; // Handle the prior Channel[timer] first
|
||||
if (cho < 0) { // Channel -1 indicates the refresh interval completed...
|
||||
tc->TC_CHANNEL[channel].TC_CCR |= TC_CCR_SWTRG; // ...so reset the timer
|
||||
if (DisablePending[timer]) {
|
||||
// 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
|
||||
if (SERVO_INDEX(timer, Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) {
|
||||
tc->TC_CHANNEL[channel].TC_RA = tc->TC_CHANNEL[channel].TC_CV + SERVO(timer,Channel[timer]).ticks;
|
||||
if (SERVO(timer,Channel[timer]).Pin.isActive) // check if activated
|
||||
extDigitalWrite(SERVO(timer, Channel[timer]).Pin.nbr, HIGH); // its an active channel so pulse it high
|
||||
Channel[timer] = ++cho; // go to the next channel (or 0)
|
||||
if (cho < SERVOS_PER_TIMER && SERVO_INDEX(timer, cho) < ServoCount) {
|
||||
tc->TC_CHANNEL[channel].TC_RA = tc->TC_CHANNEL[channel].TC_CV + SERVO(timer, cho).ticks;
|
||||
if (SERVO(timer, cho).Pin.isActive) // activated?
|
||||
extDigitalWrite(SERVO(timer, cho).Pin.nbr, HIGH); // yes: pulse HIGH
|
||||
}
|
||||
else {
|
||||
// finished all channels so wait for the refresh period to expire before starting over
|
||||
tc->TC_CHANNEL[channel].TC_RA =
|
||||
tc->TC_CHANNEL[channel].TC_CV < usToTicks(REFRESH_INTERVAL) - 4
|
||||
? (unsigned int)usToTicks(REFRESH_INTERVAL) // allow a few ticks to ensure the next OCR1A not missed
|
||||
: 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
|
||||
const unsigned int cval = tc->TC_CHANNEL[channel].TC_CV + 128 / (SERVO_TIMER_PRESCALER), // allow 128 cycles to ensure the next CV not missed
|
||||
ival = (unsigned int)usToTicks(REFRESH_INTERVAL); // at least REFRESH_INTERVAL has elapsed
|
||||
tc->TC_CHANNEL[channel].TC_RA = max(cval, ival);
|
||||
|
||||
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) {
|
||||
pmc_enable_periph_clk(id);
|
||||
TC_Configure(tc, channel,
|
||||
TC_CMR_TCCLKS_TIMER_CLOCK3 | // MCK/32
|
||||
TC_CMR_WAVE | // Waveform mode
|
||||
TC_CMR_WAVSEL_UP_RC ); // Counter running up and reset when equals to RC
|
||||
TC_CMR_WAVE // Waveform mode
|
||||
| TC_CMR_WAVSEL_UP_RC // Counter running up and reset when equal 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 */
|
||||
TC_SetRA(tc, channel, 2625); // 1ms
|
||||
// Wait 1ms before the first ISR
|
||||
TC_SetRA(tc, channel, (F_CPU) / (SERVO_TIMER_PRESCALER) / 1000UL); // 1ms
|
||||
|
||||
/* Configure and enable interrupt */
|
||||
// Configure and enable interrupt
|
||||
NVIC_EnableIRQ(irqn);
|
||||
// TC_IER_CPAS: RA Compare
|
||||
tc->TC_CHANNEL[channel].TC_IER = TC_IER_CPAS;
|
||||
tc->TC_CHANNEL[channel].TC_IER = TC_IER_CPAS; // TC_IER_CPAS: RA Compare
|
||||
|
||||
// Enables the timer clock and performs a software reset to start the counting
|
||||
TC_Start(tc, channel);
|
||||
}
|
||||
|
||||
void initISR(timer16_Sequence_t timer) {
|
||||
#ifdef _useTimer1
|
||||
if (timer == _timer1)
|
||||
_initISR(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, ID_TC_FOR_TIMER1, IRQn_FOR_TIMER1);
|
||||
#endif
|
||||
#ifdef _useTimer2
|
||||
if (timer == _timer2)
|
||||
_initISR(TC_FOR_TIMER2, CHANNEL_FOR_TIMER2, ID_TC_FOR_TIMER2, IRQn_FOR_TIMER2);
|
||||
#endif
|
||||
#ifdef _useTimer3
|
||||
if (timer == _timer3)
|
||||
_initISR(TC_FOR_TIMER3, CHANNEL_FOR_TIMER3, ID_TC_FOR_TIMER3, IRQn_FOR_TIMER3);
|
||||
#endif
|
||||
#ifdef _useTimer4
|
||||
if (timer == _timer4)
|
||||
_initISR(TC_FOR_TIMER4, CHANNEL_FOR_TIMER4, ID_TC_FOR_TIMER4, IRQn_FOR_TIMER4);
|
||||
#endif
|
||||
#ifdef _useTimer5
|
||||
if (timer == _timer5)
|
||||
_initISR(TC_FOR_TIMER5, CHANNEL_FOR_TIMER5, ID_TC_FOR_TIMER5, IRQn_FOR_TIMER5);
|
||||
#endif
|
||||
void initISR(const timer16_Sequence_t timer_index) {
|
||||
CRITICAL_SECTION_START();
|
||||
const bool disable_soon = DisablePending[timer_index];
|
||||
DisablePending.clear(timer_index);
|
||||
CRITICAL_SECTION_END();
|
||||
|
||||
if (!disable_soon) switch (timer_index) {
|
||||
default: break;
|
||||
#ifdef _useTimer1
|
||||
case _timer1: return _initISR(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, ID_TC_FOR_TIMER1, IRQn_FOR_TIMER1);
|
||||
#endif
|
||||
#ifdef _useTimer2
|
||||
case _timer2: return _initISR(TC_FOR_TIMER2, CHANNEL_FOR_TIMER2, ID_TC_FOR_TIMER2, IRQn_FOR_TIMER2);
|
||||
#endif
|
||||
#ifdef _useTimer3
|
||||
case _timer3: return _initISR(TC_FOR_TIMER3, CHANNEL_FOR_TIMER3, ID_TC_FOR_TIMER3, IRQn_FOR_TIMER3);
|
||||
#endif
|
||||
#ifdef _useTimer4
|
||||
case _timer4: return _initISR(TC_FOR_TIMER4, CHANNEL_FOR_TIMER4, ID_TC_FOR_TIMER4, IRQn_FOR_TIMER4);
|
||||
#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) {
|
||||
#ifdef _useTimer1
|
||||
TC_Stop(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1);
|
||||
#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
|
||||
void finISR(const timer16_Sequence_t timer_index) {
|
||||
// Timer is disabled from the ISR, to ensure proper final pulse length.
|
||||
DisablePending.set(timer_index);
|
||||
}
|
||||
|
||||
#endif // HAS_SERVOS
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
#define _useTimer5
|
||||
|
||||
#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
|
||||
|
||||
@ -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);
|
||||
|
||||
// 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
|
||||
TC_SetRC(tc, channel, VARIANT_MCK / 2 / frequency);
|
||||
TC_SetRC(tc, channel, VARIANT_MCK / (HAL_TIMER_PRESCALER) / frequency);
|
||||
|
||||
// And start timer
|
||||
TC_Start(tc, channel);
|
||||
|
||||
@ -35,7 +35,8 @@
|
||||
typedef uint32_t hal_timer_t;
|
||||
#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
|
||||
#define MF_TIMER_STEP 2 // Timer Index for Stepper
|
||||
|
||||
@ -1059,7 +1059,7 @@ static inline void convert_64_bit_to_byte_array(uint64_t value, uint8_t *data)
|
||||
while (val_index < 8)
|
||||
{
|
||||
data[val_index++] = value & 0xFF;
|
||||
value = value >> 8;
|
||||
value >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -65,6 +65,7 @@ portMUX_TYPE MarlinHAL::spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
// ------------------------
|
||||
|
||||
uint16_t MarlinHAL::adc_result;
|
||||
pwm_pin_t MarlinHAL::pwm_pin_data[MAX_EXPANDER_BITS];
|
||||
|
||||
// ------------------------
|
||||
// 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*/) {
|
||||
const int8_t cid = get_pwm_channel(pin, PWM_FREQUENCY, PWM_RESOLUTION);
|
||||
if (cid >= 0) {
|
||||
uint32_t duty = map(invert ? v_size - v : v, 0, v_size, 0, _BV(PWM_RESOLUTION)-1);
|
||||
ledcWrite(cid, duty);
|
||||
}
|
||||
#if ENABLED(I2S_STEPPER_STREAM)
|
||||
if (pin > 127) {
|
||||
const uint8_t pinlo = pin & 0x7F;
|
||||
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) {
|
||||
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
|
||||
#if ENABLED(I2S_STEPPER_STREAM)
|
||||
if (pin > 127) {
|
||||
pwm_pin_data[pin & 0x7F].pwm_cycle_ticks = 1000000UL / f_desired / 4; // # of 4µs ticks per full PWM cycle
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
#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
|
||||
|
||||
@ -60,14 +60,17 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define CRITICAL_SECTION_START() portENTER_CRITICAL(&spinlock)
|
||||
#define CRITICAL_SECTION_END() portEXIT_CRITICAL(&spinlock)
|
||||
#define CRITICAL_SECTION_START() portENTER_CRITICAL(&hal.spinlock)
|
||||
#define CRITICAL_SECTION_END() portEXIT_CRITICAL(&hal.spinlock)
|
||||
|
||||
#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_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 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
|
||||
@ -76,6 +79,12 @@
|
||||
typedef double isr_float_t; // FPU ops are used for single-precision, so use double for ISRs.
|
||||
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;
|
||||
typedef Servo hal_servo_t;
|
||||
|
||||
@ -197,6 +206,8 @@ public:
|
||||
// Free SRAM
|
||||
static int freeMemory();
|
||||
|
||||
static pwm_pin_t pwm_pin_data[MAX_EXPANDER_BITS];
|
||||
|
||||
//
|
||||
// ADC Methods
|
||||
//
|
||||
|
||||
@ -337,6 +337,26 @@ uint8_t i2s_state(uint8_t pin) {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -20,3 +20,10 @@
|
||||
*
|
||||
*/
|
||||
#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
|
||||
|
||||
@ -48,3 +48,7 @@
|
||||
#if USING_PULLDOWNS
|
||||
#error "PULLDOWN pin mode is not available on ESP32 boards."
|
||||
#endif
|
||||
|
||||
#if BOTH(I2S_STEPPER_STREAM, LIN_ADVANCE)
|
||||
#error "I2S stream is currently incompatible with LIN_ADVANCE."
|
||||
#endif
|
||||
|
||||
@ -69,12 +69,12 @@ bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, ui
|
||||
std::size_t bytes_written = 0;
|
||||
|
||||
for (std::size_t i = 0; i < size; i++) {
|
||||
buffer[pos+i] = value[i];
|
||||
bytes_written ++;
|
||||
buffer[pos + i] = value[i];
|
||||
bytes_written++;
|
||||
}
|
||||
|
||||
crc16(crc, value, size);
|
||||
pos = pos + size;
|
||||
pos += size;
|
||||
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;
|
||||
if (writing) {
|
||||
for (std::size_t i = 0; i < size; i++) {
|
||||
value[i] = buffer[pos+i];
|
||||
bytes_read ++;
|
||||
value[i] = buffer[pos + i];
|
||||
bytes_read++;
|
||||
}
|
||||
crc16(crc, value, size);
|
||||
}
|
||||
else {
|
||||
uint8_t temp[size];
|
||||
for (std::size_t i = 0; i < size; i++) {
|
||||
temp[i] = buffer[pos+i];
|
||||
bytes_read ++;
|
||||
temp[i] = buffer[pos + i];
|
||||
bytes_read++;
|
||||
}
|
||||
crc16(crc, temp, size);
|
||||
}
|
||||
|
||||
pos = pos + size;
|
||||
pos += size;
|
||||
return bytes_read != size; // return true for any error
|
||||
}
|
||||
|
||||
|
||||
@ -26,8 +26,8 @@
|
||||
struct LowpassFilter {
|
||||
uint64_t data_delay = 0;
|
||||
uint16_t update(uint16_t value) {
|
||||
data_delay = data_delay - (data_delay >> 6) + value;
|
||||
return (uint16_t)(data_delay >> 6);
|
||||
data_delay += value - (data_delay >> 6);
|
||||
return uint16_t(data_delay >> 6);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -598,7 +598,7 @@ void MarlinHAL::dma_init() {
|
||||
void MarlinHAL::init() {
|
||||
TERN_(DMA_IS_REQUIRED, dma_init());
|
||||
#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);
|
||||
#endif
|
||||
OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up
|
||||
|
||||
@ -77,7 +77,8 @@ HAL_SERVO_TIMER_ISR() {
|
||||
;
|
||||
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 (currentServoIndex[timer ^ 1] >= 0) {
|
||||
// Wait for both channels
|
||||
@ -86,45 +87,37 @@ HAL_SERVO_TIMER_ISR() {
|
||||
return;
|
||||
}
|
||||
#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);
|
||||
}
|
||||
else if (SERVO_INDEX(timer, currentServoIndex[timer]) < ServoCount && SERVO(timer, currentServoIndex[timer]).Pin.isActive)
|
||||
digitalWrite(SERVO(timer, currentServoIndex[timer]).Pin.nbr, LOW); // pulse this channel low if activated
|
||||
else if (SERVO_INDEX(timer, cho) < ServoCount) // prior channel handled?
|
||||
digitalWrite(SERVO(timer, cho).Pin.nbr, LOW); // pulse the prior channel LOW
|
||||
|
||||
// Select the next servo controlled by this timer
|
||||
currentServoIndex[timer]++;
|
||||
currentServoIndex[timer] = ++cho; // go to the next channel (or 0)
|
||||
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) {
|
||||
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;
|
||||
tc->COUNT16.CC[tcChannel].reg = getTimerCount() - (uint16_t)SERVO(timer, cho).ticks;
|
||||
}
|
||||
else {
|
||||
// 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
|
||||
|
||||
const uint16_t tcCounterValue = getTimerCount();
|
||||
|
||||
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
|
||||
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
|
||||
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 (tcChannel == 0) {
|
||||
SYNC(tc->COUNT16.SYNCBUSY.bit.CC0);
|
||||
// Clear the interrupt
|
||||
tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC0;
|
||||
tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC0; // Clear the interrupt
|
||||
}
|
||||
else {
|
||||
SYNC(tc->COUNT16.SYNCBUSY.bit.CC1);
|
||||
// Clear the interrupt
|
||||
tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC1;
|
||||
tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC1; // Clear the interrupt
|
||||
}
|
||||
}
|
||||
|
||||
void initISR(timer16_Sequence_t timer) {
|
||||
void initISR(const timer16_Sequence_t timer) {
|
||||
Tc * const tc = timer_config[SERVO_TC].pTc;
|
||||
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;
|
||||
const uint8_t tcChannel = TIMER_TCCHANNEL(timer);
|
||||
const uint8_t tcChannel = TIMER_TCCHANNEL(timer_index);
|
||||
|
||||
// Disable the match channel interrupt request
|
||||
tc->COUNT16.INTENCLR.reg = (tcChannel == 0) ? TC_INTENCLR_MC0 : TC_INTENCLR_MC1;
|
||||
|
||||
@ -33,157 +33,43 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// use local drivers
|
||||
#if defined(STM32F103xE) || defined(STM32F103xG)
|
||||
#include <stm32f1xx.h>
|
||||
#include <stm32f1xx_hal_rcc_ex.h>
|
||||
#include <stm32f1xx_hal_sd.h>
|
||||
#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)
|
||||
#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)
|
||||
#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
|
||||
#error "SDIO only supported with STM32F103xE, STM32F103xG, STM32F4xx, STM32F7xx, or STM32H7xx."
|
||||
#error "SDIO is only supported with STM32F103xE, STM32F103xG, STM32F4xx, STM32F7xx, and STM32H7xx."
|
||||
#endif
|
||||
|
||||
// SDIO Max Clock (naming from STM Manual, don't change)
|
||||
#define SDIOCLK 48000000
|
||||
|
||||
// Target Clock, configurable. Default is 18MHz, from STM32F1
|
||||
#ifndef SDIO_CLOCK
|
||||
#define SDIO_CLOCK 18000000 // 18 MHz
|
||||
#endif
|
||||
|
||||
#define SD_TIMEOUT 1000 // ms
|
||||
|
||||
// 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
|
||||
}
|
||||
SD_HandleTypeDef hsd; // SDIO structure
|
||||
|
||||
static uint32_t clock_to_divider(uint32_t clk) {
|
||||
#if defined(STM32H7xx)
|
||||
#ifdef SDIO_FOR_STM32H7
|
||||
// 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);
|
||||
#else
|
||||
// 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
|
||||
}
|
||||
|
||||
bool SDIO_Init() {
|
||||
HAL_StatusTypeDef sd_state = HAL_OK;
|
||||
if (hsd.Instance == SDIO)
|
||||
HAL_SD_DeInit(&hsd);
|
||||
|
||||
/* HAL SD initialization */
|
||||
hsd.Instance = SDIO;
|
||||
hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
|
||||
hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
|
||||
hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
|
||||
hsd.Init.HardwareFlowControl = SDIO_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, SDIO_BUS_WIDE_4B);
|
||||
}
|
||||
// Start the SDIO clock
|
||||
void HAL_SD_MspInit(SD_HandleTypeDef *hsd) {
|
||||
UNUSED(hsd);
|
||||
#ifdef SDIO_FOR_STM32H7
|
||||
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 for 4-bit wide SDIO bus
|
||||
pinmap_pinout(PC_9, PinMap_SD);
|
||||
pinmap_pinout(PC_10, PinMap_SD);
|
||||
pinmap_pinout(PC_11, PinMap_SD);
|
||||
#endif
|
||||
__HAL_RCC_SDMMC1_CLK_ENABLE();
|
||||
HAL_NVIC_EnableIRQ(SDMMC1_IRQn);
|
||||
#else
|
||||
__HAL_RCC_SDIO_CLK_ENABLE();
|
||||
#endif
|
||||
|
||||
return (sd_state == HAL_OK) ? true : false;
|
||||
}
|
||||
|
||||
bool SDIO_ReadBlock(uint32_t block, uint8_t *dst) {
|
||||
uint32_t timeout = HAL_GetTick() + SD_TIMEOUT;
|
||||
#ifdef SDIO_FOR_STM32H7
|
||||
|
||||
while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER) {
|
||||
if (HAL_GetTick() >= timeout) return false;
|
||||
#define SD_TIMEOUT 1000 // ms
|
||||
|
||||
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;
|
||||
if (HAL_SD_ReadBlocks_DMA(&hsd, (uint8_t *)dst, block, 1) != HAL_OK)
|
||||
bool SDIO_Init() {
|
||||
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;
|
||||
|
||||
timeout = HAL_GetTick() + SD_TIMEOUT;
|
||||
while (waitingRxCplt)
|
||||
if (HAL_GetTick() >= timeout) return false;
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
uint32_t timeout = HAL_GetTick() + SD_TIMEOUT;
|
||||
#ifdef SDIO_FOR_STM32H7
|
||||
|
||||
while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER)
|
||||
if (HAL_GetTick() >= timeout) return false;
|
||||
uint32_t timeout = HAL_GetTick() + SD_TIMEOUT;
|
||||
|
||||
waitingTxCplt = 1;
|
||||
if (HAL_SD_WriteBlocks_DMA(&hsd, (uint8_t *)src, block, 1) != HAL_OK)
|
||||
while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER)
|
||||
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;
|
||||
|
||||
timeout = HAL_GetTick() + SD_TIMEOUT;
|
||||
while (waitingTxCplt)
|
||||
if (HAL_GetTick() >= timeout) return false;
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SDIO_IsReady() {
|
||||
|
||||
@ -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() {
|
||||
OUT_WRITE(GT911_RST_PIN, LOW);
|
||||
OUT_WRITE(GT911_INT_PIN, LOW);
|
||||
delay(20);
|
||||
delay(11);
|
||||
WRITE(GT911_INT_PIN, HIGH);
|
||||
delayMicroseconds(110);
|
||||
WRITE(GT911_RST_PIN, HIGH);
|
||||
delay(6);
|
||||
WRITE(GT911_INT_PIN, LOW);
|
||||
delay(55);
|
||||
SET_INPUT(GT911_INT_PIN);
|
||||
|
||||
sw_iic.init();
|
||||
|
||||
uint8_t clear_reg = 0x0000;
|
||||
write_reg(0x814E, 2, &clear_reg, 2); // Reset to 0 for start
|
||||
uint8_t clear_reg = 0x00;
|
||||
write_reg(0x814E, 2, &clear_reg, 1); // Reset to 0 for start
|
||||
}
|
||||
|
||||
bool GT911::getFirstTouchPoint(int16_t *x, int16_t *y) {
|
||||
read_reg(0x814E, 2, ®.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;
|
||||
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
|
||||
*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;
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
#include "../../../inc/MarlinConfig.h"
|
||||
|
||||
#define GT911_SLAVE_ADDRESS 0xBA
|
||||
#define GT911_SLAVE_ADDRESS 0x28
|
||||
|
||||
#if !PIN_EXISTS(GT911_RST)
|
||||
#error "GT911_RST_PIN is not defined."
|
||||
|
||||
@ -147,17 +147,17 @@ void libServo::move(const int32_t value) {
|
||||
uint16_t SR = timer_get_status(tdev);
|
||||
if (SR & TIMER_SR_CC1IF) { // channel 1 off
|
||||
#ifdef SERVO0_PWM_OD
|
||||
OUT_WRITE_OD(SERVO0_PIN, 1); // off
|
||||
OUT_WRITE_OD(SERVO0_PIN, HIGH); // off
|
||||
#else
|
||||
OUT_WRITE(SERVO0_PIN, 0);
|
||||
OUT_WRITE(SERVO0_PIN, LOW);
|
||||
#endif
|
||||
timer_reset_status_bit(tdev, TIMER_SR_CC1IF_BIT);
|
||||
}
|
||||
if (SR & TIMER_SR_CC2IF) { // channel 2 resume
|
||||
#ifdef SERVO0_PWM_OD
|
||||
OUT_WRITE_OD(SERVO0_PIN, 0); // on
|
||||
OUT_WRITE_OD(SERVO0_PIN, LOW); // on
|
||||
#else
|
||||
OUT_WRITE(SERVO0_PIN, 1);
|
||||
OUT_WRITE(SERVO0_PIN, HIGH);
|
||||
#endif
|
||||
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);
|
||||
if (!tdev) return false;
|
||||
#ifdef SERVO0_PWM_OD
|
||||
OUT_WRITE_OD(inPin, 1);
|
||||
OUT_WRITE_OD(inPin, HIGH);
|
||||
#else
|
||||
OUT_WRITE(inPin, 0);
|
||||
OUT_WRITE(inPin, LOW);
|
||||
#endif
|
||||
|
||||
timer_pause(tdev);
|
||||
@ -200,9 +200,9 @@ void libServo::move(const int32_t value) {
|
||||
timer_disable_irq(tdev, 1);
|
||||
timer_disable_irq(tdev, 2);
|
||||
#ifdef SERVO0_PWM_OD
|
||||
OUT_WRITE_OD(pin, 1); // off
|
||||
OUT_WRITE_OD(pin, HIGH); // off
|
||||
#else
|
||||
OUT_WRITE(pin, 0);
|
||||
OUT_WRITE(pin, LOW);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,11 +135,11 @@ static UnwResult UnwTabExecuteInstructions(const UnwindCallbacks *cb, UnwTabStat
|
||||
while ((instruction = UnwTabGetNextInstruction(cb, ucb)) != -1) {
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
else if ((instruction & 0xF0) == 0x80) {
|
||||
|
||||
@ -65,7 +65,7 @@ uint8_t ServoCount = 0; // the total number of attached
|
||||
|
||||
/************ 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
|
||||
LOOP_L_N(channel, SERVOS_PER_TIMER) {
|
||||
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;
|
||||
|
||||
// initialize the timer if it has not already been initialized
|
||||
timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex);
|
||||
if (!isTimerActive(timer)) initISR(timer);
|
||||
servo_info[servoIndex].Pin.isActive = true; // this must be set after the check for isTimerActive
|
||||
const timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex);
|
||||
if (!anyTimerChannelActive(timer)) initISR(timer);
|
||||
servo_info[servoIndex].Pin.isActive = true; // this must be set after the check for anyTimerChannelActive
|
||||
|
||||
return servoIndex;
|
||||
}
|
||||
|
||||
void Servo::detach() {
|
||||
servo_info[servoIndex].Pin.isActive = false;
|
||||
timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex);
|
||||
if (!isTimerActive(timer)) finISR(timer);
|
||||
const timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex);
|
||||
if (!anyTimerChannelActive(timer)) finISR(timer);
|
||||
//pinMode(servo_info[servoIndex].Pin.nbr, INPUT); // set servo pin to input
|
||||
}
|
||||
|
||||
void Servo::write(int value) {
|
||||
|
||||
@ -70,10 +70,10 @@
|
||||
#define ticksToUs(_ticks) (unsigned(_ticks) * (SERVO_TIMER_PRESCALER) / clockCyclesPerMicrosecond())
|
||||
|
||||
// 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_CHANNEL(_servo_nbr) (_servo_nbr % (SERVOS_PER_TIMER)) // returns 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(_timer,_channel) (servo_info[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel
|
||||
#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)) // the index of the servo on this timer
|
||||
#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)] // servo class by timer and channel
|
||||
|
||||
// Types
|
||||
|
||||
@ -94,5 +94,5 @@ extern ServoInfo_t servo_info[MAX_SERVOS];
|
||||
|
||||
// Public functions
|
||||
|
||||
extern void initISR(timer16_Sequence_t timer);
|
||||
extern void finISR(timer16_Sequence_t timer);
|
||||
void initISR(const timer16_Sequence_t timer_index);
|
||||
void finISR(const timer16_Sequence_t timer_index);
|
||||
|
||||
@ -782,7 +782,7 @@ void idle(bool no_stepper_sleep/*=false*/) {
|
||||
manage_inactivity(no_stepper_sleep);
|
||||
|
||||
// Manage Heaters (and Watchdog)
|
||||
thermalManager.manage_heater();
|
||||
thermalManager.task();
|
||||
|
||||
// Max7219 heartbeat, animation, etc
|
||||
TERN_(MAX7219_DEBUG, max7219.idle_tasks());
|
||||
|
||||
@ -238,6 +238,7 @@
|
||||
#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_4 2014 // BigTreeTech SKR v1.4
|
||||
#define BOARD_EMOTRONIC 2015 // eMotion-Tech eMotronic
|
||||
|
||||
//
|
||||
// LPC1769 ARM Cortex M3
|
||||
@ -343,29 +344,30 @@
|
||||
#define BOARD_CREALITY_V4 4040 // Creality v4.x (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_V427 4043 // Creality v4.2.7 (STM32F103RC / STM32F103RE)
|
||||
#define BOARD_CREALITY_V4210 4044 // Creality v4.2.10 (STM32F103RC / STM32F103RE) as found in the CR-30
|
||||
#define BOARD_CREALITY_V431 4045 // Creality v4.3.1 (STM32F103RC / STM32F103RE)
|
||||
#define BOARD_CREALITY_V431_A 4046 // Creality v4.3.1a (STM32F103RC / STM32F103RE)
|
||||
#define BOARD_CREALITY_V431_B 4047 // Creality v4.3.1b (STM32F103RC / STM32F103RE)
|
||||
#define BOARD_CREALITY_V431_C 4048 // Creality v4.3.1c (STM32F103RC / STM32F103RE)
|
||||
#define BOARD_CREALITY_V431_D 4049 // Creality v4.3.1d (STM32F103RC / STM32F103RE)
|
||||
#define BOARD_CREALITY_V452 4050 // Creality v4.5.2 (STM32F103RC / STM32F103RE)
|
||||
#define BOARD_CREALITY_V453 4051 // Creality v4.5.3 (STM32F103RC / STM32F103RE)
|
||||
#define BOARD_CREALITY_V24S1 4052 // Creality v2.4.S1 (STM32F103RC / STM32F103RE) v101 as found in the Ender-7
|
||||
#define BOARD_CREALITY_V24S1_301 4053 // Creality v2.4.S1_301 (STM32F103RC / STM32F103RE) v301 as found in the Ender-3 S1
|
||||
#define BOARD_CREALITY_V25S1 4054 // Creality v2.5.S1 (STM32F103RE) as found in the CR-10 Smart Pro
|
||||
#define BOARD_TRIGORILLA_PRO 4055 // Trigorilla Pro (STM32F103ZE)
|
||||
#define BOARD_FLY_MINI 4056 // FLYmaker FLY MINI (STM32F103RC)
|
||||
#define BOARD_FLSUN_HISPEED 4057 // FLSUN HiSpeedV1 (STM32F103VE)
|
||||
#define BOARD_BEAST 4058 // STM32F103RE Libmaple-based controller
|
||||
#define BOARD_MINGDA_MPX_ARM_MINI 4059 // STM32F103ZE Mingda MD-16
|
||||
#define BOARD_GTM32_PRO_VD 4060 // STM32F103VE controller
|
||||
#define BOARD_ZONESTAR_ZM3E2 4061 // Zonestar ZM3E2 (STM32F103RC)
|
||||
#define BOARD_ZONESTAR_ZM3E4 4062 // Zonestar ZM3E4 V1 (STM32F103VC)
|
||||
#define BOARD_ZONESTAR_ZM3E4V2 4063 // Zonestar ZM3E4 V2 (STM32F103VC)
|
||||
#define BOARD_ERYONE_ERY32_MINI 4064 // Eryone Ery32 mini (STM32F103VE)
|
||||
#define BOARD_PANDA_PI_V29 4065 // Panda Pi V2.9 - Standalone (STM32F103RC)
|
||||
#define BOARD_CREALITY_V425 4043 // Creality v4.2.5 (STM32F103RC / STM32F103RE)
|
||||
#define BOARD_CREALITY_V427 4044 // Creality v4.2.7 (STM32F103RC / STM32F103RE)
|
||||
#define BOARD_CREALITY_V4210 4045 // Creality v4.2.10 (STM32F103RC / STM32F103RE) as found in the CR-30
|
||||
#define BOARD_CREALITY_V431 4046 // Creality v4.3.1 (STM32F103RC / STM32F103RE)
|
||||
#define BOARD_CREALITY_V431_A 4047 // Creality v4.3.1a (STM32F103RC / STM32F103RE)
|
||||
#define BOARD_CREALITY_V431_B 4048 // Creality v4.3.1b (STM32F103RC / STM32F103RE)
|
||||
#define BOARD_CREALITY_V431_C 4049 // Creality v4.3.1c (STM32F103RC / STM32F103RE)
|
||||
#define BOARD_CREALITY_V431_D 4050 // Creality v4.3.1d (STM32F103RC / STM32F103RE)
|
||||
#define BOARD_CREALITY_V452 4051 // Creality v4.5.2 (STM32F103RC / STM32F103RE)
|
||||
#define BOARD_CREALITY_V453 4052 // Creality v4.5.3 (STM32F103RC / STM32F103RE)
|
||||
#define BOARD_CREALITY_V24S1 4053 // Creality v2.4.S1 (STM32F103RC / STM32F103RE) v101 as found in the Ender-7
|
||||
#define BOARD_CREALITY_V24S1_301 4054 // Creality v2.4.S1_301 (STM32F103RC / STM32F103RE) v301 as found in the Ender-3 S1
|
||||
#define BOARD_CREALITY_V25S1 4055 // Creality v2.5.S1 (STM32F103RE) as found in the CR-10 Smart Pro
|
||||
#define BOARD_TRIGORILLA_PRO 4056 // Trigorilla Pro (STM32F103ZE)
|
||||
#define BOARD_FLY_MINI 4057 // FLYmaker FLY MINI (STM32F103RC)
|
||||
#define BOARD_FLSUN_HISPEED 4058 // FLSUN HiSpeedV1 (STM32F103VE)
|
||||
#define BOARD_BEAST 4059 // STM32F103RE Libmaple-based controller
|
||||
#define BOARD_MINGDA_MPX_ARM_MINI 4060 // STM32F103ZE Mingda MD-16
|
||||
#define BOARD_GTM32_PRO_VD 4061 // STM32F103VE controller
|
||||
#define BOARD_ZONESTAR_ZM3E2 4062 // Zonestar ZM3E2 (STM32F103RC)
|
||||
#define BOARD_ZONESTAR_ZM3E4 4063 // Zonestar ZM3E4 V1 (STM32F103VC)
|
||||
#define BOARD_ZONESTAR_ZM3E4V2 4064 // Zonestar ZM3E4 V2 (STM32F103VC)
|
||||
#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
|
||||
@ -408,17 +410,18 @@
|
||||
#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_1 4229 // MKS Robin Nano V3.1 (STM32F407VE)
|
||||
#define BOARD_MKS_MONSTER8 4230 // MKS Monster8 (STM32F407VG)
|
||||
#define BOARD_ANET_ET4 4231 // ANET ET4 V1.x (STM32F407VG)
|
||||
#define BOARD_ANET_ET4P 4232 // ANET ET4P V1.x (STM32F407VG)
|
||||
#define BOARD_FYSETC_CHEETAH_V20 4233 // FYSETC Cheetah V2.0
|
||||
#define BOARD_TH3D_EZBOARD_V2 4234 // TH3D EZBoard v2.0
|
||||
#define BOARD_INDEX_REV03 4235 // Index PnP Controller REV03 (STM32F407VE/VG)
|
||||
#define BOARD_MKS_ROBIN_NANO_V1_3_F4 4236 // MKS Robin Nano V1.3 and MKS Robin Nano-S V1.3 (STM32F407VE)
|
||||
#define BOARD_MKS_EAGLE 4237 // MKS Eagle (STM32F407VE)
|
||||
#define BOARD_ARTILLERY_RUBY 4238 // Artillery Ruby (STM32F401RC)
|
||||
#define BOARD_FYSETC_SPIDER_V2_2 4239 // FYSETC Spider V2.2 (STM32F446VE)
|
||||
#define BOARD_CREALITY_V24S1_301F4 4240 // Creality v2.4.S1_301F4 (STM32F401RC) as found in the Ender-3 S1 F4
|
||||
#define BOARD_MKS_MONSTER8_V1 4230 // MKS Monster8 V1 (STM32F407VG)
|
||||
#define BOARD_MKS_MONSTER8_V2 4231 // MKS Monster8 V2 (STM32F407VG)
|
||||
#define BOARD_ANET_ET4 4232 // ANET ET4 V1.x (STM32F407VG)
|
||||
#define BOARD_ANET_ET4P 4233 // ANET ET4P V1.x (STM32F407VG)
|
||||
#define BOARD_FYSETC_CHEETAH_V20 4234 // FYSETC Cheetah V2.0
|
||||
#define BOARD_TH3D_EZBOARD_V2 4235 // TH3D EZBoard v2.0
|
||||
#define BOARD_OPULO_LUMEN_REV3 4236 // Opulo Lumen PnP Controller REV3 (STM32F407VE/VG)
|
||||
#define BOARD_MKS_ROBIN_NANO_V1_3_F4 4237 // MKS Robin Nano V1.3 and MKS Robin Nano-S V1.3 (STM32F407VE)
|
||||
#define BOARD_MKS_EAGLE 4238 // MKS Eagle (STM32F407VE)
|
||||
#define BOARD_ARTILLERY_RUBY 4239 // Artillery Ruby (STM32F401RC)
|
||||
#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
|
||||
@ -428,9 +431,10 @@
|
||||
#define BOARD_TEENSY41 5001 // Teensy 4.1
|
||||
#define BOARD_T41U5XBB 5002 // T41U5XBB Teensy 4.1 breakout 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_V3_0 5005 // BigTreeTech SKR V3.0 (STM32H743VG)
|
||||
#define BOARD_BTT_SKR_V3_0_EZ 5006 // BigTreeTech SKR V3.0 EZ (STM32H743VG)
|
||||
#define BOARD_BTT_SKR_SE_BX_V2 5004 // BigTreeTech SKR SE BX V2.0 (STM32H743II)
|
||||
#define BOARD_BTT_SKR_SE_BX_V3 5005 // BigTreeTech SKR SE BX V3.0 (STM32H743II)
|
||||
#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
|
||||
|
||||
@ -227,10 +227,6 @@
|
||||
#define STR_PID_DEBUG " PID_DEBUG "
|
||||
#define STR_PID_DEBUG_INPUT ": Input "
|
||||
#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_MPC_AUTOTUNE "MPC Autotune"
|
||||
#define STR_MPC_AUTOTUNE_START " start for " STR_E
|
||||
|
||||
@ -350,7 +350,7 @@
|
||||
|
||||
#define _LIST_N(N,V...) LIST_##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_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 PROBE() ~, 1 // Second item will be 1 if this is passed
|
||||
#define _NOT_0 PROBE()
|
||||
#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 NOT(x) IS_PROBE(_CAT(_NOT_, x)) // NOT('0') gets '1'. Anything else gets '0'.
|
||||
#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) _CAT(_IF_, TF)
|
||||
@ -647,7 +647,6 @@
|
||||
#define HAS_ARGS(V...) _BOOL(FIRST(_END_OF_ARGUMENTS_ V)())
|
||||
#define _END_OF_ARGUMENTS_() 0
|
||||
|
||||
|
||||
// Simple Inline IF Macros, friendly to use in other macro definitions
|
||||
#define IF(O, A, B) ((O) ? (A) : (B))
|
||||
#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(N,OP,V...) RREPEAT2_S(0,N,OP,V)
|
||||
|
||||
// See https://github.com/swansontec/map-macro
|
||||
#define MAP_OUT
|
||||
#define MAP_END(...)
|
||||
#define MAP_GET_END() 0, MAP_END
|
||||
#define MAP_NEXT0(test, next, ...) next MAP_OUT
|
||||
#define MAP_NEXT1(test, next) MAP_NEXT0 (test, next, 0)
|
||||
#define MAP_NEXT(test, next) MAP_NEXT1 (MAP_GET_END test, next)
|
||||
#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(f, ...) EVAL512 (MAP1 (f, __VA_ARGS__, (), 0))
|
||||
// Call OP(A) with each item as an argument
|
||||
#define _MAP(_MAP_OP,A,V...) \
|
||||
_MAP_OP(A) \
|
||||
IF_ELSE(HAS_ARGS(V)) \
|
||||
( DEFER2(__MAP)()(_MAP_OP,V) ) \
|
||||
( /* Do nothing */ )
|
||||
#define __MAP() _MAP
|
||||
|
||||
#define MAP(OP,V...) EVAL(_MAP(OP,V))
|
||||
|
||||
// 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))
|
||||
|
||||
@ -30,16 +30,15 @@
|
||||
uint8_t marlin_debug_flags = MARLIN_DEBUG_NONE;
|
||||
|
||||
// Commonly-used strings in serial output
|
||||
PGMSTR(NUL_STR, ""); PGMSTR(SP_P_STR, " P"); PGMSTR(SP_T_STR, " T");
|
||||
PGMSTR(X_STR, "X"); PGMSTR(Y_STR, "Y"); PGMSTR(Z_STR, "Z"); PGMSTR(E_STR, "E");
|
||||
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");
|
||||
PGMSTR(SP_X_STR, " X"); PGMSTR(SP_Y_STR, " Y"); PGMSTR(SP_Z_STR, " Z"); PGMSTR(SP_E_STR, " E");
|
||||
PGMSTR(SP_X_LBL, " X:"); PGMSTR(SP_Y_LBL, " Y:"); PGMSTR(SP_Z_LBL, " Z:"); PGMSTR(SP_E_LBL, " E:");
|
||||
PGMSTR(I_STR, STR_I); PGMSTR(J_STR, STR_J); PGMSTR(K_STR, STR_K);
|
||||
PGMSTR(I_LBL, STR_I ":"); PGMSTR(J_LBL, STR_J ":"); PGMSTR(K_LBL, STR_K ":");
|
||||
PGMSTR(SP_I_STR, " " STR_I); PGMSTR(SP_J_STR, " " STR_J); PGMSTR(SP_K_STR, " " STR_K);
|
||||
PGMSTR(SP_I_LBL, " " STR_I ":"); PGMSTR(SP_J_LBL, " " STR_J ":"); PGMSTR(SP_K_LBL, " " STR_K ":");
|
||||
PGMSTR(SP_A_STR, " A"); PGMSTR(SP_B_STR, " B"); PGMSTR(SP_C_STR, " C");
|
||||
PGMSTR(SP_P_STR, " P"); PGMSTR(SP_T_STR, " T"); PGMSTR(NUL_STR, "");
|
||||
|
||||
#define _N_STR(N) PGMSTR(N##_STR, STR_##N);
|
||||
#define _N_LBL(N) PGMSTR(N##_LBL, STR_##N ":");
|
||||
#define _SP_N_STR(N) PGMSTR(SP_##N##_STR, STR_##N ":");
|
||||
#define _SP_N_LBL(N) PGMSTR(SP_##N##_LBL, " " STR_##N ":");
|
||||
MAP(_N_STR, LOGICAL_AXIS_NAMES); MAP(_SP_N_STR, LOGICAL_AXIS_NAMES);
|
||||
MAP(_N_LBL, LOGICAL_AXIS_NAMES); MAP(_SP_N_LBL, LOGICAL_AXIS_NAMES);
|
||||
|
||||
// Hook Meatpack if it's enabled on the first leaf
|
||||
#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);
|
||||
}
|
||||
|
||||
void serial_echo_start() { static PGMSTR(echomagic, "echo:"); serial_print_P(echomagic); }
|
||||
void serial_error_start() { static PGMSTR(errormagic, "Error:"); serial_print_P(errormagic); }
|
||||
void serial_echo_start() { serial_print(F("echo:")); }
|
||||
void serial_error_start() { serial_print(F("Error:")); }
|
||||
|
||||
void serial_spaces(uint8_t count) { count *= (PROPORTIONAL_FONT_RATIO); while (count--) SERIAL_CHAR(' '); }
|
||||
|
||||
|
||||
@ -28,19 +28,6 @@
|
||||
#include "../feature/meatpack.h"
|
||||
#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
|
||||
//
|
||||
@ -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_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
|
||||
|
||||
@ -43,7 +43,9 @@ public:
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
@ -36,24 +36,42 @@ struct IF { typedef R type; };
|
||||
template <class L, class R>
|
||||
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_CODE(V...) CODE_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_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_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 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_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_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_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_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_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 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
|
||||
#define LIST_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 clear(const int n) { b &= ~(bits_t)_BV(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 int size() const { return sizeof(b); }
|
||||
int size() const { return sizeof(b); }
|
||||
};
|
||||
|
||||
// Specialization for a single bool flag
|
||||
@ -95,9 +113,9 @@ struct Flags<1> {
|
||||
void set(const int) { b = true; }
|
||||
void clear(const int) { b = false; }
|
||||
bool test(const int) const { return b; }
|
||||
bool operator[](const int) { return b; }
|
||||
const bool operator[](const int) const { return b; }
|
||||
const int size() const { return sizeof(b); }
|
||||
bool& operator[](const int) { return b; }
|
||||
bool operator[](const int) const { return b; }
|
||||
int size() const { return sizeof(b); }
|
||||
};
|
||||
|
||||
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 clear(const int n) { flags.clear(n); }
|
||||
bool test(const int n) const { return flags.test(n); }
|
||||
bool operator[](const int n) { return flags[n]; }
|
||||
const bool operator[](const int n) const { return flags[n]; }
|
||||
const int size() const { return sizeof(flags); }
|
||||
bool operator[](const int n) { return flags[n]; }
|
||||
bool operator[](const int n) const { return flags[n]; }
|
||||
int size() const { return sizeof(flags); }
|
||||
} axis_flags_t;
|
||||
|
||||
//
|
||||
@ -439,7 +457,7 @@ template<typename T>
|
||||
struct XYZval {
|
||||
union {
|
||||
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];
|
||||
};
|
||||
|
||||
@ -454,11 +472,11 @@ struct XYZval {
|
||||
FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; }
|
||||
#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(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
|
||||
#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(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
|
||||
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
|
||||
@ -585,7 +603,7 @@ template<typename T>
|
||||
struct XYZEval {
|
||||
union {
|
||||
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];
|
||||
};
|
||||
// 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 XYZval<T> pxyz) { set(LINEAR_AXIS_ELEM(pxyz)); }
|
||||
#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
|
||||
FI void set(const XYval<T> pxy, const T pz) { set(pxy); TERN_(HAS_Z_AXIS, z = pz); }
|
||||
#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 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
|
||||
|
||||
// Length reduced to one dimension
|
||||
|
||||
@ -29,10 +29,10 @@ void safe_delay(millis_t ms) {
|
||||
while (ms > 50) {
|
||||
ms -= 50;
|
||||
delay(50);
|
||||
thermalManager.manage_heater();
|
||||
thermalManager.task();
|
||||
}
|
||||
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
|
||||
@ -51,7 +51,7 @@ void safe_delay(millis_t ms) {
|
||||
|
||||
#include "../module/probe.h"
|
||||
#include "../module/motion.h"
|
||||
#include "../module/stepper.h"
|
||||
#include "../module/planner.h"
|
||||
#include "../libs/numtostr.h"
|
||||
#include "../feature/bedlevel/bedlevel.h"
|
||||
|
||||
@ -126,17 +126,16 @@ void safe_delay(millis_t ms) {
|
||||
#if ABL_PLANAR
|
||||
SERIAL_ECHOPGM("ABL Adjustment");
|
||||
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]);
|
||||
}
|
||||
#else
|
||||
#if ENABLED(AUTO_BED_LEVELING_UBL)
|
||||
SERIAL_ECHOPGM("UBL Adjustment Z");
|
||||
const float rz = bedlevel.get_z_correction(current_position);
|
||||
#elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
|
||||
SERIAL_ECHOPGM("ABL Adjustment Z");
|
||||
const float rz = bedlevel.get_z_correction(current_position);
|
||||
#endif
|
||||
const float rz = bedlevel.get_z_correction(current_position);
|
||||
SERIAL_ECHO(ftostr43sign(rz, '+'));
|
||||
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
|
||||
if (planner.z_fade_height) {
|
||||
@ -156,11 +155,13 @@ void safe_delay(millis_t ms) {
|
||||
SERIAL_ECHOPGM("Mesh Bed Leveling");
|
||||
if (planner.leveling_active) {
|
||||
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 (planner.z_fade_height) {
|
||||
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(')');
|
||||
}
|
||||
|
||||
@ -59,6 +59,11 @@ void safe_delay(millis_t ms); // Delay ensuring that temperatures are
|
||||
#define log_machine_info() NOOP
|
||||
#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>
|
||||
class restorer {
|
||||
T& ref_;
|
||||
@ -77,10 +82,14 @@ public:
|
||||
// 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; }
|
||||
|
||||
// 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);
|
||||
|
||||
#if LINEAR_AXES <= XYZ
|
||||
#define AXIS_CHAR(A) ((char)('X' + A))
|
||||
#define IAXIS_CHAR AXIS_CHAR
|
||||
#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 IAXIS_CHAR(A) iaxis_codes[A]
|
||||
#endif
|
||||
|
||||
@ -154,7 +154,7 @@ void reset_bed_level() {
|
||||
#endif
|
||||
LOOP_L_N(x, sx) {
|
||||
SERIAL_CHAR(' ');
|
||||
const float offset = values[x * sx + y];
|
||||
const float offset = values[x * sy + y];
|
||||
if (!isnan(offset)) {
|
||||
if (offset >= 0) SERIAL_CHAR('+');
|
||||
SERIAL_ECHO_F(offset, int(precision));
|
||||
|
||||
@ -31,7 +31,6 @@
|
||||
#include "../../../libs/hex_print.h"
|
||||
#include "../../../module/settings.h"
|
||||
#include "../../../lcd/marlinui.h"
|
||||
#include "../../../module/stepper.h"
|
||||
#include "../../../module/planner.h"
|
||||
#include "../../../module/motion.h"
|
||||
#include "../../../module/probe.h"
|
||||
|
||||
@ -26,7 +26,6 @@
|
||||
|
||||
#include "../bedlevel.h"
|
||||
#include "../../../module/planner.h"
|
||||
#include "../../../module/stepper.h"
|
||||
#include "../../../module/motion.h"
|
||||
|
||||
#if ENABLED(DELTA)
|
||||
@ -36,8 +35,18 @@
|
||||
#include "../../../MarlinCore.h"
|
||||
#include <math.h>
|
||||
|
||||
//#define DEBUG_UBL_MOTION
|
||||
#define DEBUG_OUT ENABLED(DEBUG_UBL_MOTION)
|
||||
#include "../../../core/debug_out.h"
|
||||
|
||||
#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) {
|
||||
/**
|
||||
* 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;
|
||||
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.
|
||||
@ -225,7 +236,9 @@
|
||||
dest.z += z0;
|
||||
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))
|
||||
|
||||
@ -45,7 +45,7 @@ void stop();
|
||||
|
||||
bool BLTouch::command(const BLTCommand cmd, const millis_t &ms) {
|
||||
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
|
||||
return triggered();
|
||||
}
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
#include "dac_dac084s085.h"
|
||||
|
||||
#include "../../MarlinCore.h"
|
||||
#include "../../module/stepper.h"
|
||||
#include "../../HAL/shared/Delay.h"
|
||||
|
||||
dac084s085::dac084s085() { }
|
||||
|
||||
@ -59,7 +59,7 @@ int StepperDAC::init() {
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
@ -84,13 +84,11 @@ void StepperDAC::print_values() {
|
||||
if (!dac_present) return;
|
||||
SERIAL_ECHO_MSG("Stepper current values in % (Amps):");
|
||||
SERIAL_ECHO_START();
|
||||
SERIAL_ECHOPGM_P(SP_X_LBL, dac_perc(X_AXIS), PSTR(" ("), dac_amps(X_AXIS), PSTR(")"));
|
||||
#if HAS_Y_AXIS
|
||||
SERIAL_ECHOPGM_P(SP_Y_LBL, dac_perc(Y_AXIS), PSTR(" ("), dac_amps(Y_AXIS), PSTR(")"));
|
||||
#endif
|
||||
#if HAS_Z_AXIS
|
||||
SERIAL_ECHOPGM_P(SP_Z_LBL, dac_perc(Z_AXIS), PSTR(" ("), dac_amps(Z_AXIS), PSTR(")"));
|
||||
#endif
|
||||
LOOP_LOGICAL_AXES(a) {
|
||||
SERIAL_CHAR(' ', IAXIS_CHAR(a), ':');
|
||||
SERIAL_ECHO(dac_perc(a));
|
||||
SERIAL_ECHOPGM_P(PSTR(" ("), dac_amps(AxisEnum(a)), PSTR(")"));
|
||||
}
|
||||
#if HAS_EXTRUDERS
|
||||
SERIAL_ECHOLNPGM_P(SP_E_LBL, dac_perc(E_AXIS), PSTR(" ("), dac_amps(E_AXIS), PSTR(")"));
|
||||
#endif
|
||||
|
||||
@ -34,7 +34,6 @@ FWRetract fwretract; // Single instance - this calls the constructor
|
||||
|
||||
#include "../module/motion.h"
|
||||
#include "../module/planner.h"
|
||||
#include "../module/stepper.h"
|
||||
|
||||
#include "../gcode/gcode.h"
|
||||
|
||||
|
||||
@ -44,7 +44,6 @@
|
||||
#include "max7219.h"
|
||||
|
||||
#include "../module/planner.h"
|
||||
#include "../module/stepper.h"
|
||||
#include "../MarlinCore.h"
|
||||
#include "../HAL/shared/Delay.h"
|
||||
|
||||
|
||||
@ -35,10 +35,13 @@
|
||||
#include "../gcode/gcode.h"
|
||||
#include "../module/motion.h"
|
||||
#include "../module/planner.h"
|
||||
#include "../module/stepper.h"
|
||||
#include "../module/printcounter.h"
|
||||
#include "../module/temperature.h"
|
||||
|
||||
#if HAS_EXTRUDERS
|
||||
#include "../module/stepper.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_UBL)
|
||||
#include "bedlevel/bedlevel.h"
|
||||
#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(DWIN_LCD_PROUI, DWIN_Print_Resume(), ui.reset_status());
|
||||
TERN_(HAS_MARLINUI_MENU, ui.return_to_status());
|
||||
TERN_(DWIN_LCD_PROUI, HMI_ReturnScreen());
|
||||
#if ENABLED(DWIN_LCD_PROUI)
|
||||
DWIN_Print_Resume();
|
||||
HMI_ReturnScreen();
|
||||
#else
|
||||
ui.reset_status();
|
||||
ui.return_to_status();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // ADVANCED_PAUSE_FEATURE
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
|
||||
#include "power.h"
|
||||
#include "../module/planner.h"
|
||||
#include "../module/stepper.h"
|
||||
#include "../module/stepper/indirection.h" // for restore_stepper_drivers
|
||||
#include "../module/temperature.h"
|
||||
#include "../MarlinCore.h"
|
||||
|
||||
@ -46,6 +46,7 @@ Power powerManager;
|
||||
bool Power::psu_on;
|
||||
|
||||
#if ENABLED(AUTO_POWER_CONTROL)
|
||||
#include "../module/stepper.h"
|
||||
#include "../module/temperature.h"
|
||||
|
||||
#if BOTH(USE_CONTROLLER_FAN, AUTO_POWER_CONTROLLERFAN)
|
||||
|
||||
@ -53,7 +53,7 @@ PowerMonitor power_monitor; // Single instance - this calls the constructor
|
||||
void PowerMonitor::draw_current() {
|
||||
const float amps = getAmps();
|
||||
lcd_put_u8str(amps < 100 ? ftostr31ns(amps) : ui16tostr4rj((uint16_t)amps));
|
||||
lcd_put_wchar('A');
|
||||
lcd_put_lchar('A');
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -61,7 +61,7 @@ PowerMonitor power_monitor; // Single instance - this calls the constructor
|
||||
void PowerMonitor::draw_voltage() {
|
||||
const float volts = getVolts();
|
||||
lcd_put_u8str(volts < 100 ? ftostr31ns(volts) : ui16tostr4rj((uint16_t)volts));
|
||||
lcd_put_wchar('V');
|
||||
lcd_put_lchar('V');
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -69,7 +69,7 @@ PowerMonitor power_monitor; // Single instance - this calls the constructor
|
||||
void PowerMonitor::draw_power() {
|
||||
const float power = getPower();
|
||||
lcd_put_u8str(power < 100 ? ftostr31ns(power) : ui16tostr4rj((uint16_t)power));
|
||||
lcd_put_wchar('W');
|
||||
lcd_put_lchar('W');
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@ -32,7 +32,7 @@ struct pm_lpf_t {
|
||||
uint32_t filter_buf;
|
||||
float value;
|
||||
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() {
|
||||
value = filter_buf * (SCALE * (1.0f / (1UL << (PM_K_VALUE + PM_K_SCALE))));
|
||||
|
||||
@ -39,18 +39,26 @@
|
||||
#endif
|
||||
|
||||
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
|
||||
#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)
|
||||
cutter_frequency_t SpindleLaser::frequency; // PWM frequency setting; range: 2K - 50K
|
||||
#if ENABLED(LASER_FEATURE)
|
||||
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
|
||||
|
||||
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)
|
||||
|
||||
/**
|
||||
@ -58,21 +66,21 @@ cutter_power_t SpindleLaser::menuPower, // Power s
|
||||
*/
|
||||
void SpindleLaser::init() {
|
||||
#if ENABLED(SPINDLE_SERVO)
|
||||
MOVE_SERVO(SPINDLE_SERVO_NR, SPINDLE_SERVO_MIN);
|
||||
servo[SPINDLE_SERVO_NR].move(SPINDLE_SERVO_MIN);
|
||||
#else
|
||||
OUT_WRITE(SPINDLE_LASER_ENA_PIN, !SPINDLE_LASER_ACTIVE_STATE); // Init spindle to off
|
||||
#endif
|
||||
#if ENABLED(SPINDLE_CHANGE_DIR)
|
||||
OUT_WRITE(SPINDLE_DIR_PIN, SPINDLE_INVERT_DIR); // Init rotation to clockwise (M3)
|
||||
#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)
|
||||
SET_PWM(SPINDLE_LASER_PWM_PIN);
|
||||
hal.set_pwm_duty(pin_t(SPINDLE_LASER_PWM_PIN), SPINDLE_LASER_PWM_OFF); // Set to lowest speed
|
||||
#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)
|
||||
OUT_WRITE(AIR_EVACUATION_PIN, !AIR_EVACUATION_ACTIVE); // Init Vacuum/Blower OFF
|
||||
#endif
|
||||
@ -90,7 +98,7 @@ void SpindleLaser::init() {
|
||||
*/
|
||||
void SpindleLaser::_set_ocr(const uint8_t ocr) {
|
||||
#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
|
||||
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
|
||||
|
||||
/**
|
||||
* Apply power for laser/spindle
|
||||
* Apply power for Laser or Spindle
|
||||
*
|
||||
* 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) {
|
||||
if (opwr == last_power_applied) return;
|
||||
last_power_applied = opwr;
|
||||
power = opwr;
|
||||
#if ENABLED(SPINDLE_LASER_USE_PWM)
|
||||
if (cutter.unitPower == 0 && CUTTER_UNIT_IS(RPM)) {
|
||||
ocr_off();
|
||||
isReady = false;
|
||||
}
|
||||
else if (ENABLED(CUTTER_POWER_RELATIVE) || enabled()) {
|
||||
set_ocr(power);
|
||||
isReady = true;
|
||||
}
|
||||
else {
|
||||
ocr_off();
|
||||
isReady = false;
|
||||
}
|
||||
#elif ENABLED(SPINDLE_SERVO)
|
||||
MOVE_SERVO(SPINDLE_SERVO_NR, power);
|
||||
#else
|
||||
WRITE(SPINDLE_LASER_ENA_PIN, enabled() ? SPINDLE_LASER_ACTIVE_STATE : !SPINDLE_LASER_ACTIVE_STATE);
|
||||
isReady = true;
|
||||
#endif
|
||||
if (enabled() || opwr == 0) { // 0 check allows us to disable where no ENA pin exists
|
||||
// Test and set the last power used to improve performance
|
||||
if (opwr == last_power_applied) return;
|
||||
last_power_applied = opwr;
|
||||
// Handle PWM driven or just simple on/off
|
||||
#if ENABLED(SPINDLE_LASER_USE_PWM)
|
||||
if (CUTTER_UNIT_IS(RPM) && unitPower == 0)
|
||||
ocr_off();
|
||||
else if (ENABLED(CUTTER_POWER_RELATIVE) || enabled() || opwr == 0) {
|
||||
set_ocr(opwr);
|
||||
isReadyForUI = true;
|
||||
}
|
||||
else
|
||||
ocr_off();
|
||||
#elif ENABLED(SPINDLE_SERVO)
|
||||
MOVE_SERVO(SPINDLE_SERVO_NR, power);
|
||||
#else
|
||||
WRITE(SPINDLE_LASER_ENA_PIN, enabled() ? SPINDLE_LASER_ACTIVE_STATE : !SPINDLE_LASER_ACTIVE_STATE);
|
||||
isReadyForUI = 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)
|
||||
|
||||
@ -34,87 +34,98 @@
|
||||
#include "../libs/buzzer.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(LASER_POWER_INLINE)
|
||||
#include "../module/planner.h"
|
||||
#endif
|
||||
// Inline laser power
|
||||
#include "../module/planner.h"
|
||||
|
||||
#define PCT_TO_PWM(X) ((X) * 255 / 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 {
|
||||
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)
|
||||
|
||||
// Convert configured power range to a percentage
|
||||
static const inline uint8_t cpwr_to_pct(const cutter_cpower_t cpwr) {
|
||||
constexpr cutter_cpower_t power_floor = TERN(CUTTER_POWER_RELATIVE, SPEED_POWER_MIN, 0),
|
||||
power_range = SPEED_POWER_MAX - power_floor;
|
||||
return cpwr ? round(100.0f * (cpwr - power_floor) / power_range) : 0;
|
||||
static 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) {
|
||||
return cpwr ? round(100.0f * (cpwr - power_floor) / (SPEED_POWER_MAX - power_floor)) : 0;
|
||||
}
|
||||
|
||||
// Convert a cpower (e.g., SPEED_POWER_STARTUP) to unit power (upwr, upower),
|
||||
// which can be PWM, Percent, Servo angle, or RPM (rel/abs).
|
||||
static const inline cutter_power_t cpwr_to_upwr(const cutter_cpower_t cpwr) { // STARTUP power to Unit power
|
||||
const cutter_power_t upwr = (
|
||||
// Convert config defines from RPM to %, angle or PWM when in Spindle mode
|
||||
// and convert from PERCENT to PWM when in Laser mode
|
||||
static constexpr cutter_power_t cpwr_to_upwr(const cutter_cpower_t cpwr) { // STARTUP power to Unit power
|
||||
return (
|
||||
#if ENABLED(SPINDLE_FEATURE)
|
||||
// Spindle configured values are in RPM
|
||||
// Spindle configured define values are in RPM
|
||||
#if CUTTER_UNIT_IS(RPM)
|
||||
cpwr // to RPM
|
||||
#elif CUTTER_UNIT_IS(PERCENT) // to PCT
|
||||
cpwr_to_pct(cpwr)
|
||||
#elif CUTTER_UNIT_IS(SERVO) // to SERVO angle
|
||||
PCT_TO_SERVO(cpwr_to_pct(cpwr))
|
||||
#else // to PWM
|
||||
PCT_TO_PWM(cpwr_to_pct(cpwr))
|
||||
cpwr // to same
|
||||
#elif CUTTER_UNIT_IS(PERCENT)
|
||||
cpwr_to_pct(cpwr) // to Percent
|
||||
#elif CUTTER_UNIT_IS(SERVO)
|
||||
PCT_TO_SERVO(cpwr_to_pct(cpwr)) // to SERVO angle
|
||||
#else
|
||||
PCT_TO_PWM(cpwr_to_pct(cpwr)) // to PWM
|
||||
#endif
|
||||
#else
|
||||
// Laser configured values are in PCT
|
||||
// Laser configured define values are in Percent
|
||||
#if CUTTER_UNIT_IS(PWM255)
|
||||
PCT_TO_PWM(cpwr)
|
||||
PCT_TO_PWM(cpwr) // to PWM
|
||||
#else
|
||||
cpwr // to RPM/PCT
|
||||
cpwr // to same
|
||||
#endif
|
||||
#endif
|
||||
);
|
||||
return upwr;
|
||||
}
|
||||
|
||||
static const 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_min() { return cpwr_to_upwr(SPEED_POWER_MIN); }
|
||||
static constexpr cutter_power_t mpower_max() { return cpwr_to_upwr(SPEED_POWER_MAX); }
|
||||
|
||||
#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
|
||||
|
||||
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,
|
||||
last_power_applied; // Basic power state tracking
|
||||
|
||||
#if ENABLED(MARLIN_DEV_MODE)
|
||||
static cutter_frequency_t frequency; // Set PWM frequency; range: 2K-50K
|
||||
#endif
|
||||
static cutter_frequency_t frequency; // Set PWM frequency; range: 2K-50K
|
||||
|
||||
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
|
||||
|
||||
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); }
|
||||
#endif
|
||||
|
||||
// Modifying this function should update everywhere
|
||||
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);
|
||||
|
||||
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)
|
||||
|
||||
@ -125,7 +136,6 @@ public:
|
||||
public:
|
||||
|
||||
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();
|
||||
|
||||
/**
|
||||
@ -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
|
||||
|
||||
/**
|
||||
* Enable/Disable spindle/laser
|
||||
* @param enable true = enable; false = disable
|
||||
* Correct power to configured range
|
||||
*/
|
||||
static void set_enabled(const bool enable) {
|
||||
uint8_t value = 0;
|
||||
if (enable) {
|
||||
#if ENABLED(SPINDLE_LASER_USE_PWM)
|
||||
if (power)
|
||||
value = power;
|
||||
else if (unitPower)
|
||||
value = upower_to_ocr(cpwr_to_upwr(SPEED_POWER_STARTUP));
|
||||
#else
|
||||
value = 255;
|
||||
#endif
|
||||
static cutter_power_t power_to_range(const cutter_power_t pwr, const uint8_t pwrUnit=_CUTTER_POWER(CUTTER_POWER_UNIT)) {
|
||||
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: { // PWM
|
||||
const uint8_t pmin = pct_to_ocr(min_pct), pmax = pct_to_ocr(max_pct);
|
||||
upwr = cutter_power_t(constrain(pwr, pmin, pmax));
|
||||
} 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) {
|
||||
#if DISABLED(LASER_POWER_INLINE)
|
||||
safe_delay(on ? SPINDLE_LASER_POWERUP_DELAY : SPINDLE_LASER_POWERDOWN_DELAY);
|
||||
static void set_enabled(const bool enable) {
|
||||
switch (cutter_mode) {
|
||||
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
|
||||
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)
|
||||
@ -226,47 +234,60 @@ public:
|
||||
#endif
|
||||
|
||||
#if ENABLED(AIR_EVACUATION)
|
||||
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_toggle(); // Toggle Cutter Vacuum or Laser Blower motor
|
||||
static bool air_evac_state() { // Get current state
|
||||
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_toggle(); // Toggle Cutter Vacuum or Laser Blower motor
|
||||
static bool air_evac_state() { // Get current state
|
||||
return (READ(AIR_EVACUATION_PIN) == AIR_EVACUATION_ACTIVE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLED(AIR_ASSIST)
|
||||
static void air_assist_enable(); // Turn on air assist
|
||||
static void air_assist_disable(); // Turn off air assist
|
||||
static void air_assist_toggle(); // Toggle air assist
|
||||
static bool air_assist_state() { // Get current state
|
||||
static void air_assist_enable(); // Turn on air assist
|
||||
static void air_assist_disable(); // Turn off air assist
|
||||
static void air_assist_toggle(); // Toggle air assist
|
||||
static bool air_assist_state() { // Get current state
|
||||
return (READ(AIR_ASSIST_PIN) == AIR_ASSIST_ACTIVE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HAS_MARLINUI_MENU
|
||||
static void enable_with_dir(const bool reverse) {
|
||||
isReady = true;
|
||||
const uint8_t ocr = TERN(SPINDLE_LASER_USE_PWM, upower_to_ocr(menuPower), 255);
|
||||
if (menuPower)
|
||||
power = ocr;
|
||||
else
|
||||
menuPower = cpwr_to_upwr(SPEED_POWER_STARTUP);
|
||||
unitPower = menuPower;
|
||||
set_reverse(reverse);
|
||||
set_enabled(true);
|
||||
}
|
||||
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()); }
|
||||
|
||||
#if ENABLED(SPINDLE_FEATURE)
|
||||
static void enable_with_dir(const bool reverse) {
|
||||
isReadyForUI = true;
|
||||
const uint8_t ocr = TERN(SPINDLE_LASER_USE_PWM, upower_to_ocr(menuPower), 255);
|
||||
if (menuPower)
|
||||
power = ocr;
|
||||
else
|
||||
menuPower = cpwr_to_upwr(SPEED_POWER_STARTUP);
|
||||
unitPower = menuPower;
|
||||
set_reverse(reverse);
|
||||
set_enabled(true);
|
||||
}
|
||||
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)
|
||||
static void update_from_mpower() {
|
||||
if (isReady) power = upower_to_ocr(menuPower);
|
||||
if (isReadyForUI) power = upower_to_ocr(menuPower);
|
||||
unitPower = menuPower;
|
||||
}
|
||||
#endif
|
||||
|
||||
#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
|
||||
* Also fires with any PWM power that was previous set
|
||||
@ -274,74 +295,36 @@ public:
|
||||
*/
|
||||
static void test_fire_pulse() {
|
||||
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.
|
||||
disable(); // Turn laser off
|
||||
laser_menu_toggle(false); // Laser Off
|
||||
}
|
||||
#endif
|
||||
#endif // LASER_FEATURE
|
||||
|
||||
#endif // HAS_MARLINUI_MENU
|
||||
|
||||
#if ENABLED(LASER_POWER_INLINE)
|
||||
/**
|
||||
* Inline power adds extra fields to the planner block
|
||||
* to handle laser power and scale to movement speed.
|
||||
*/
|
||||
#if ENABLED(LASER_FEATURE)
|
||||
|
||||
// Force disengage planner power control
|
||||
static void inline_disable() {
|
||||
isReady = false;
|
||||
unitPower = 0;
|
||||
planner.laser_inline.status.isPlanned = false;
|
||||
planner.laser_inline.status.isEnabled = false;
|
||||
planner.laser_inline.power = 0;
|
||||
// Dynamic mode rate calculation
|
||||
static uint8_t calc_dynamic_power() {
|
||||
if (feedrate_mm_m > 65535) return 255; // Too fast, go always on
|
||||
uint16_t rate = uint16_t(feedrate_mm_m); // 16 bits from the G-code parser float input
|
||||
rate >>= 8; // Take the G-code input e.g. F40000 and shift off the lower bits to get an OCR value from 1-255
|
||||
return uint8_t(rate);
|
||||
}
|
||||
|
||||
// Inline modes of all other functions; all enable planner inline power control
|
||||
static void set_inline_enabled(const bool 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);
|
||||
}
|
||||
}
|
||||
static void set_inline_enabled(const bool enable) { planner.laser_inline.status.isEnabled = enable;}
|
||||
|
||||
// Set the power for subsequent movement blocks
|
||||
static void inline_power(const cutter_power_t upwr) {
|
||||
unitPower = menuPower = upwr;
|
||||
#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_power(const cutter_power_t cpwr) {
|
||||
TERN(SPINDLE_LASER_USE_PWM, power = planner.laser_inline.power = cpwr, planner.laser_inline.power = cpwr > 0 ? 255 : 0);
|
||||
}
|
||||
|
||||
static void inline_direction(const bool) { /* never */ }
|
||||
#endif // LASER_FEATURE
|
||||
|
||||
#if ENABLED(SPINDLE_LASER_USE_PWM)
|
||||
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();
|
||||
}
|
||||
static void kill() { disable(); }
|
||||
};
|
||||
|
||||
extern SpindleLaser cutter;
|
||||
|
||||
@ -74,12 +74,10 @@ typedef IF<(SPEED_POWER_MAX > 255), uint16_t, uint8_t>::type cutter_cpower_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef uint16_t cutter_frequency_t;
|
||||
|
||||
#if ENABLED(LASER_FEATURE)
|
||||
typedef uint16_t cutter_test_pulse_t;
|
||||
#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
|
||||
#endif
|
||||
|
||||
@ -33,17 +33,12 @@
|
||||
#include "../gcode/gcode.h"
|
||||
|
||||
#if ENABLED(TMC_DEBUG)
|
||||
#include "../module/planner.h"
|
||||
#include "../libs/hex_print.h"
|
||||
#if ENABLED(MONITOR_DRIVER_STATUS)
|
||||
static uint16_t report_tmc_status_interval; // = 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if HAS_MARLINUI_MENU
|
||||
#include "../module/stepper.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Check for over temperature or short to ground error flags.
|
||||
* Report and log warning of overtemperature condition.
|
||||
|
||||
@ -107,7 +107,6 @@
|
||||
|
||||
#include "../../MarlinCore.h"
|
||||
#include "../../module/planner.h"
|
||||
#include "../../module/stepper.h"
|
||||
#include "../../module/motion.h"
|
||||
#include "../../module/tool_change.h"
|
||||
#include "../../module/temperature.h"
|
||||
@ -306,7 +305,7 @@ typedef struct {
|
||||
LIMIT(e.x, X_MIN_POS + 1, X_MAX_POS - 1);
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,7 +32,6 @@
|
||||
#include "../../../feature/bedlevel/bedlevel.h"
|
||||
#include "../../../module/motion.h"
|
||||
#include "../../../module/planner.h"
|
||||
#include "../../../module/stepper.h"
|
||||
#include "../../../module/probe.h"
|
||||
#include "../../queue.h"
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
#include "../../../libs/buzzer.h"
|
||||
#include "../../../lcd/marlinui.h"
|
||||
#include "../../../module/motion.h"
|
||||
#include "../../../module/stepper.h"
|
||||
#include "../../../module/planner.h"
|
||||
|
||||
#if ENABLED(EXTENSIBLE_UI)
|
||||
#include "../../../lcd/extui/ui_api.h"
|
||||
|
||||
@ -24,8 +24,9 @@
|
||||
|
||||
#include "../gcode.h"
|
||||
|
||||
#include "../../module/stepper.h"
|
||||
#include "../../module/endstops.h"
|
||||
#include "../../module/planner.h"
|
||||
#include "../../module/stepper.h" // for various
|
||||
|
||||
#if HAS_MULTI_HOTEND
|
||||
#include "../../module/tool_change.h"
|
||||
@ -59,7 +60,7 @@
|
||||
#include "../../libs/L64XX/L64XX_Marlin.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(LASER_MOVE_G28_OFF)
|
||||
#if ENABLED(LASER_FEATURE)
|
||||
#include "../../feature/spindle_laser.h"
|
||||
#endif
|
||||
|
||||
@ -169,7 +170,7 @@
|
||||
motion_state.jerk_state = planner.max_jerk;
|
||||
planner.max_jerk.set(0, 0 OPTARG(DELTA, 0));
|
||||
#endif
|
||||
planner.reset_acceleration_rates();
|
||||
planner.refresh_acceleration_rates();
|
||||
return motion_state;
|
||||
}
|
||||
|
||||
@ -178,7 +179,7 @@
|
||||
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_(HAS_CLASSIC_JERK, planner.max_jerk = motion_state.jerk_state);
|
||||
planner.reset_acceleration_rates();
|
||||
planner.refresh_acceleration_rates();
|
||||
}
|
||||
|
||||
#endif // IMPROVE_HOMING_RELIABILITY
|
||||
@ -205,7 +206,12 @@ void GcodeSuite::G28() {
|
||||
DEBUG_SECTION(log_G28, "G28", DEBUGGING(LEVELING));
|
||||
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)
|
||||
bool IDEX_saved_duplication_state = extruder_duplication_enabled;
|
||||
@ -460,9 +466,11 @@ void GcodeSuite::G28() {
|
||||
}
|
||||
#endif
|
||||
|
||||
TERN_(HAS_I_AXIS, if (doI) homeaxis(I_AXIS));
|
||||
TERN_(HAS_J_AXIS, if (doJ) homeaxis(J_AXIS));
|
||||
TERN_(HAS_K_AXIS, if (doK) homeaxis(K_AXIS));
|
||||
SECONDARY_AXIS_CODE(
|
||||
if (doI) homeaxis(I_AXIS),
|
||||
if (doJ) homeaxis(J_AXIS),
|
||||
if (doK) homeaxis(K_AXIS)
|
||||
);
|
||||
|
||||
sync_plan_position();
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
#include "../gcode.h"
|
||||
#include "../../module/delta.h"
|
||||
#include "../../module/motion.h"
|
||||
#include "../../module/stepper.h"
|
||||
#include "../../module/planner.h"
|
||||
#include "../../module/endstops.h"
|
||||
#include "../../lcd/marlinui.h"
|
||||
|
||||
|
||||
@ -26,9 +26,12 @@
|
||||
|
||||
#include "../gcode.h"
|
||||
#include "../../module/motion.h"
|
||||
#include "../../module/stepper.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
|
||||
#include "../../feature/bedlevel/bedlevel.h"
|
||||
#endif
|
||||
@ -79,7 +82,7 @@ void GcodeSuite::G34() {
|
||||
stepper.set_digipot_current(Z_AXIS, target_current);
|
||||
#elif HAS_MOTOR_CURRENT_PWM
|
||||
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);
|
||||
#elif HAS_MOTOR_CURRENT_DAC
|
||||
const float target_current = parser.floatval('S', GANTRY_CALIBRATION_CURRENT);
|
||||
|
||||
@ -88,7 +88,7 @@
|
||||
|
||||
enum side_t : uint8_t {
|
||||
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;
|
||||
|
||||
@ -47,23 +47,17 @@ void GcodeSuite::M425() {
|
||||
bool noArgs = true;
|
||||
|
||||
auto axis_can_calibrate = [](const uint8_t a) {
|
||||
#define _CAN_CASE(N) case N##_AXIS: return AXIS_CAN_CALIBRATE(N);
|
||||
switch (a) {
|
||||
default: return false;
|
||||
LINEAR_AXIS_CODE(
|
||||
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)
|
||||
);
|
||||
MAIN_AXIS_MAP(_CAN_CASE)
|
||||
}
|
||||
};
|
||||
|
||||
LOOP_LINEAR_AXES(a) {
|
||||
if (axis_can_calibrate(a) && parser.seen(AXIS_CHAR(a))) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -89,9 +83,7 @@ void GcodeSuite::M425() {
|
||||
SERIAL_ECHOLNPGM(" Correction Amount/Fade-out: F", backlash.get_correction(), " (F1.0 = full, F0.0 = none)");
|
||||
SERIAL_ECHOPGM(" Backlash Distance (mm): ");
|
||||
LOOP_LINEAR_AXES(a) if (axis_can_calibrate(a)) {
|
||||
SERIAL_CHAR(' ', AXIS_CHAR(a));
|
||||
SERIAL_ECHO(backlash.get_distance_mm(AxisEnum(a)));
|
||||
SERIAL_EOL();
|
||||
SERIAL_ECHOLNPGM_P((PGM_P)pgm_read_ptr(&SP_AXIS_STR[a]), backlash.get_distance_mm((AxisEnum)a));
|
||||
}
|
||||
|
||||
#ifdef BACKLASH_SMOOTHING_MM
|
||||
@ -102,8 +94,7 @@ void GcodeSuite::M425() {
|
||||
SERIAL_ECHOPGM(" Average measured backlash (mm):");
|
||||
if (backlash.has_any_measurement()) {
|
||||
LOOP_LINEAR_AXES(a) if (axis_can_calibrate(a) && backlash.has_measurement(AxisEnum(a))) {
|
||||
SERIAL_CHAR(' ', AXIS_CHAR(a));
|
||||
SERIAL_ECHO(backlash.get_measurement(AxisEnum(a)));
|
||||
SERIAL_ECHOPGM_P((PGM_P)pgm_read_ptr(&SP_AXIS_STR[a]), backlash.get_measurement((AxisEnum)a));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@ -86,13 +86,13 @@
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* S[segments-per-second] - Segments-per-second
|
||||
* S[segments] - Segments-per-second
|
||||
*
|
||||
* Without NO_WORKSPACE_OFFSETS:
|
||||
*
|
||||
* 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
|
||||
* Z[z-offset] - Z offset, added to Z
|
||||
* 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
|
||||
* Z[z-offset] - Z offset, added to Z
|
||||
*
|
||||
* A, P, and X are all aliases for the shoulder angle
|
||||
* B, T, and Y are all aliases for the elbow angle
|
||||
@ -152,18 +152,35 @@
|
||||
*
|
||||
* 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() {
|
||||
if (parser.seenval('S'))
|
||||
segments_per_second = parser.value_float();
|
||||
else
|
||||
M665_report();
|
||||
if (!parser.seen_any()) return M665_report();
|
||||
if (parser.seenval('S')) segments_per_second = parser.value_float();
|
||||
if (parser.seenval('L')) draw_area_min.x = parser.value_linear_units();
|
||||
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*/) {
|
||||
report_heading_etc(forReplay, F(STR_POLARGRAPH_SETTINGS " (" STR_S_SEG_PER_SEC ")"));
|
||||
SERIAL_ECHOLNPGM(" M665 S", segments_per_second);
|
||||
report_heading_etc(forReplay, F(STR_POLARGRAPH_SETTINGS));
|
||||
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
|
||||
|
||||
@ -45,7 +45,7 @@
|
||||
DEBUG_SECTION(log_M666, "M666", DEBUGGING(LEVELING));
|
||||
bool is_err = false, is_set = false;
|
||||
LOOP_LINEAR_AXES(i) {
|
||||
if (parser.seen(AXIS_CHAR(i))) {
|
||||
if (parser.seenval(AXIS_CHAR(i))) {
|
||||
is_set = true;
|
||||
const float v = parser.value_linear_units();
|
||||
if (v > 0)
|
||||
|
||||
@ -134,9 +134,9 @@ void GcodeSuite::M201() {
|
||||
#endif
|
||||
|
||||
LOOP_LOGICAL_AXES(i) {
|
||||
if (parser.seenval(axis_codes[i])) {
|
||||
const uint8_t a = TERN(HAS_EXTRUDERS, (i == E_AXIS ? uint8_t(E_AXIS_N(target_extruder)) : i), i);
|
||||
planner.set_max_acceleration(a, parser.value_axis_units((AxisEnum)a));
|
||||
if (parser.seenval(AXIS_CHAR(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(a));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -180,9 +180,9 @@ void GcodeSuite::M203() {
|
||||
if (target_extruder < 0) return;
|
||||
|
||||
LOOP_LOGICAL_AXES(i)
|
||||
if (parser.seenval(axis_codes[i])) {
|
||||
const uint8_t a = TERN(HAS_EXTRUDERS, (i == E_AXIS ? uint8_t(E_AXIS_N(target_extruder)) : i), i);
|
||||
planner.set_max_feedrate(a, parser.value_axis_units((AxisEnum)a));
|
||||
if (parser.seenval(AXIS_CHAR(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(a));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -174,14 +174,12 @@ void GcodeSuite::M217_report(const bool forReplay/*=true*/) {
|
||||
#if HAS_Y_AXIS
|
||||
, SP_Y_STR, LINEAR_UNIT(toolchange_settings.change_point.y)
|
||||
#endif
|
||||
#if HAS_I_AXIS
|
||||
, SP_I_STR, LINEAR_UNIT(toolchange_settings.change_point.i)
|
||||
#endif
|
||||
#if HAS_J_AXIS
|
||||
, SP_J_STR, LINEAR_UNIT(toolchange_settings.change_point.j)
|
||||
#endif
|
||||
#if HAS_K_AXIS
|
||||
, SP_K_STR, LINEAR_UNIT(toolchange_settings.change_point.k)
|
||||
#if SECONDARY_AXES >= 1
|
||||
, LIST_N(DOUBLE(SECONDARY_AXES),
|
||||
SP_I_STR, I_AXIS_UNIT(toolchange_settings.change_point.i),
|
||||
SP_J_STR, J_AXIS_UNIT(toolchange_settings.change_point.j),
|
||||
SP_K_STR, K_AXIS_UNIT(toolchange_settings.change_point.k)
|
||||
)
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
@ -47,8 +47,8 @@ void GcodeSuite::M281() {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (parser.seen('L')) servo_angles[servo_index][0] = parser.value_int();
|
||||
if (parser.seen('U')) servo_angles[servo_index][1] = parser.value_int();
|
||||
if (parser.seenval('L')) servo_angles[servo_index][0] = parser.value_int();
|
||||
if (parser.seenval('U')) servo_angles[servo_index][1] = parser.value_int();
|
||||
}
|
||||
else
|
||||
SERIAL_ERROR_MSG("Servo ", servo_index, " out of range");
|
||||
|
||||
@ -36,9 +36,9 @@
|
||||
*/
|
||||
void GcodeSuite::M304() {
|
||||
if (!parser.seen("PID")) return M304_report();
|
||||
if (parser.seen('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.seen('D')) thermalManager.temp_bed.pid.Kd = scalePID_d(parser.value_float());
|
||||
if (parser.seenval('P')) thermalManager.temp_bed.pid.Kp = parser.value_float();
|
||||
if (parser.seenval('I')) thermalManager.temp_bed.pid.Ki = scalePID_i(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*/) {
|
||||
|
||||
@ -52,19 +52,19 @@ void GcodeSuite::M305() {
|
||||
if (t_index >= (USER_THERMISTORS) || (do_set && t_index < 0))
|
||||
SERIAL_ECHO_MSG("!Invalid index. (0 <= P <= ", USER_THERMISTORS - 1, ")");
|
||||
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()))
|
||||
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()))
|
||||
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()))
|
||||
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()))
|
||||
SERIAL_ECHO_MSG("!Invalid Steinhart-Hart C coeff. (-0.01 < C < +0.01)");
|
||||
} // If not setting then report parameters
|
||||
|
||||
@ -198,10 +198,10 @@ inline void servo_probe_test() {
|
||||
uint8_t i = 0;
|
||||
SERIAL_ECHOLNPGM(". Deploy & stow 4 times");
|
||||
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);
|
||||
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);
|
||||
stow_state = READ(PROBE_TEST_PIN);
|
||||
} while (++i < 4);
|
||||
@ -226,7 +226,7 @@ inline void servo_probe_test() {
|
||||
}
|
||||
|
||||
// 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);
|
||||
SERIAL_ECHOLNPGM("** Please trigger probe within 30 sec **");
|
||||
uint16_t probe_counter = 0;
|
||||
@ -256,7 +256,7 @@ inline void servo_probe_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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
#if ENABLED(SD_ABORT_ON_ENDSTOP_HIT)
|
||||
|
||||
#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>)
|
||||
|
||||
@ -49,7 +49,7 @@ void GcodeSuite::M111() {
|
||||
LOOP_L_N(i, COUNT(debug_strings)) {
|
||||
if (TEST(marlin_debug_flags, i)) {
|
||||
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]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,6 +23,8 @@
|
||||
#include "../gcode.h"
|
||||
#include "../../MarlinCore.h" // for stepper_inactive_time, disable_e_steppers
|
||||
#include "../../lcd/marlinui.h"
|
||||
#include "../../module/motion.h" // for e_axis_mask
|
||||
#include "../../module/planner.h"
|
||||
#include "../../module/stepper.h"
|
||||
|
||||
#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));
|
||||
}
|
||||
else
|
||||
selected.bits = selected.e_bits();
|
||||
selected.bits = e_axis_mask;
|
||||
}
|
||||
#endif
|
||||
selected.bits |= LINEAR_AXIS_GANG(
|
||||
@ -125,14 +127,8 @@ void GcodeSuite::M17() {
|
||||
stepper.enable_e_steppers();
|
||||
}
|
||||
#endif
|
||||
LINEAR_AXIS_CODE(
|
||||
if (parser.seen_test('X')) stepper.enable_axis(X_AXIS),
|
||||
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)
|
||||
);
|
||||
LOOP_LINEAR_AXES(a)
|
||||
if (parser.seen_test(AXIS_CHAR(a))) stepper.enable_axis((AxisEnum)a);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -178,7 +174,7 @@ void try_to_disable(const stepper_flags_t to_disable) {
|
||||
|
||||
auto overlap_warning = [](const ena_mask_t axis_bits) {
|
||||
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
|
||||
#define _EN_STILLON(N) if (TEST(axis_bits, INDEX_OF_AXIS(E_AXIS, N))) SERIAL_CHAR(' ', 'E', '0' + N);
|
||||
REPEAT(EXTRUDERS, _EN_STILLON)
|
||||
@ -238,14 +234,8 @@ void GcodeSuite::M18_M84() {
|
||||
stepper.disable_e_steppers();
|
||||
}
|
||||
#endif
|
||||
LINEAR_AXIS_CODE(
|
||||
if (parser.seen_test('X')) stepper.disable_axis(X_AXIS),
|
||||
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)
|
||||
);
|
||||
LOOP_LINEAR_AXES(a)
|
||||
if (parser.seen_test(AXIS_CHAR(a))) stepper.disable_axis((AxisEnum)a);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
|
||||
#include "../gcode.h"
|
||||
#include "../../MarlinCore.h" // for pin_is_protected and idle()
|
||||
#include "../../module/stepper.h"
|
||||
#include "../../module/planner.h"
|
||||
|
||||
void protected_pin_err();
|
||||
|
||||
|
||||
@ -48,7 +48,7 @@ void GcodeSuite::M280() {
|
||||
const int anew = parser.value_int();
|
||||
if (anew >= 0) {
|
||||
#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 int aold = servo[servo_index].read();
|
||||
millis_t now = millis();
|
||||
@ -56,14 +56,14 @@ void GcodeSuite::M280() {
|
||||
while (PENDING(now, end)) {
|
||||
safe_delay(50);
|
||||
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
|
||||
MOVE_SERVO(servo_index, anew);
|
||||
servo[servo_index].move(anew);
|
||||
}
|
||||
else
|
||||
DETACH_SERVO(servo_index);
|
||||
servo[servo_index].detach();
|
||||
}
|
||||
else
|
||||
SERIAL_ECHO_MSG(" Servo ", servo_index, ": ", servo[servo_index].read());
|
||||
|
||||
@ -36,7 +36,7 @@ void GcodeSuite::M282() {
|
||||
|
||||
const int servo_index = parser.value_int();
|
||||
if (WITHIN(servo_index, 0, NUM_SERVOS - 1))
|
||||
DETACH_SERVO(servo_index);
|
||||
servo[servo_index].detach();
|
||||
else
|
||||
SERIAL_ECHO_MSG("Servo ", servo_index, " out of range");
|
||||
|
||||
|
||||
@ -26,22 +26,32 @@
|
||||
|
||||
#include "../gcode.h"
|
||||
#include "../../feature/spindle_laser.h"
|
||||
#include "../../module/stepper.h"
|
||||
#include "../../module/planner.h"
|
||||
|
||||
/**
|
||||
* Laser:
|
||||
* 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:
|
||||
* M3 - Spindle ON (Clockwise)
|
||||
* M4 - Spindle ON (Counter-clockwise)
|
||||
* M5 - Spindle OFF
|
||||
*
|
||||
* Parameters:
|
||||
* S<power> - Set power. S0 will turn the spindle/laser off, except in relative mode.
|
||||
* O<ocr> - Set power and OCR (oscillator count register)
|
||||
* S<power> - Set power. S0 will turn the spindle/laser off.
|
||||
*
|
||||
* 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.
|
||||
* 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.)
|
||||
#endif
|
||||
|
||||
#if EITHER(SPINDLE_LASER_USE_PWM, SPINDLE_SERVO)
|
||||
auto get_s_power = [] {
|
||||
if (parser.seenval('S')) {
|
||||
const float spwr = parser.value_float();
|
||||
#if ENABLED(SPINDLE_SERVO)
|
||||
cutter.unitPower = spwr;
|
||||
#else
|
||||
cutter.unitPower = TERN(SPINDLE_LASER_USE_PWM,
|
||||
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;
|
||||
};
|
||||
if (cutter.cutter_mode == CUTTER_MODE_STANDARD)
|
||||
planner.synchronize(); // Wait for previous movement commands (G0/G1/G2/G3) to complete before changing power
|
||||
|
||||
#if ENABLED(LASER_FEATURE)
|
||||
if (parser.seen_test('I')) {
|
||||
cutter.cutter_mode = is_M4 ? CUTTER_MODE_DYNAMIC : CUTTER_MODE_CONTINUOUS;
|
||||
cutter.inline_power(0);
|
||||
cutter.set_enabled(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLED(LASER_POWER_INLINE)
|
||||
if (parser.seen('I') == DISABLED(LASER_POWER_INLINE_INVERT)) {
|
||||
// Laser power in inline mode
|
||||
cutter.inline_direction(is_M4); // Should always be unused
|
||||
#if ENABLED(SPINDLE_LASER_USE_PWM)
|
||||
if (parser.seen('O')) {
|
||||
cutter.unitPower = cutter.power_to_range(parser.value_byte(), 0);
|
||||
cutter.inline_ocr_power(cutter.unitPower); // The OCR is a value from 0 to 255 (uint8_t)
|
||||
}
|
||||
else
|
||||
cutter.inline_power(cutter.upower_to_ocr(get_s_power()));
|
||||
auto get_s_power = [] {
|
||||
float u;
|
||||
if (parser.seenval('S')) {
|
||||
const float v = parser.value_float();
|
||||
u = TERN(LASER_POWER_TRAP, v, cutter.power_to_range(v));
|
||||
}
|
||||
else if (cutter.cutter_mode == CUTTER_MODE_STANDARD)
|
||||
u = cutter.cpwr_to_upwr(SPEED_POWER_STARTUP);
|
||||
|
||||
cutter.menuPower = cutter.unitPower = u;
|
||||
|
||||
// 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
|
||||
cutter.set_inline_enabled(true);
|
||||
planner.synchronize();
|
||||
cutter.inline_power(cutter.power);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
// Non-inline, standard case
|
||||
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
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
cutter.set_enabled(true);
|
||||
#endif
|
||||
cutter.menuPower = cutter.unitPower;
|
||||
get_s_power();
|
||||
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)
|
||||
*/
|
||||
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();
|
||||
cutter.set_enabled(false);
|
||||
cutter.menuPower = cutter.unitPower;
|
||||
cutter.power = 0;
|
||||
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
|
||||
|
||||
@ -33,9 +33,9 @@
|
||||
* Warning: Steps-per-unit remains unchanged.
|
||||
*/
|
||||
void GcodeSuite::M350() {
|
||||
if (parser.seen('S')) LOOP_LE_N(i, 4) stepper.microstep_mode(i, parser.value_byte());
|
||||
LOOP_LOGICAL_AXES(i) if (parser.seen(axis_codes[i])) stepper.microstep_mode(i, parser.value_byte());
|
||||
if (parser.seen('B')) stepper.microstep_mode(4, parser.value_byte());
|
||||
if (parser.seen('S')) LOOP_DISTINCT_AXES(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.seenval('B')) stepper.microstep_mode(E_AXIS + 1, parser.value_byte());
|
||||
stepper.microstep_readings();
|
||||
}
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
*/
|
||||
|
||||
#include "../gcode.h"
|
||||
#include "../../module/stepper.h"
|
||||
#include "../../module/planner.h"
|
||||
|
||||
/**
|
||||
* M400: Finish all moves
|
||||
|
||||
@ -28,7 +28,6 @@
|
||||
|
||||
#include "../gcode.h"
|
||||
#include "../../module/motion.h"
|
||||
#include "../../module/stepper.h"
|
||||
#include "../../module/tool_change.h"
|
||||
#include "../../module/planner.h"
|
||||
|
||||
@ -64,7 +63,7 @@
|
||||
void GcodeSuite::M605() {
|
||||
planner.synchronize();
|
||||
|
||||
if (parser.seen('S')) {
|
||||
if (parser.seenval('S')) {
|
||||
const DualXMode previous_mode = dual_x_carriage_mode;
|
||||
|
||||
dual_x_carriage_mode = (DualXMode)parser.value_byte();
|
||||
@ -78,8 +77,8 @@
|
||||
|
||||
case DXC_DUPLICATION_MODE:
|
||||
// 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.seen('R')) duplicate_extruder_temp_offset = parser.value_celsius_diff();
|
||||
if (parser.seenval('X')) duplicate_extruder_x_offset = _MAX(parser.value_linear_units(), (X2_MIN_POS) - (X1_MIN_POS));
|
||||
if (parser.seenval('R')) duplicate_extruder_temp_offset = parser.value_celsius_diff();
|
||||
// Always switch back to tool 0
|
||||
if (active_extruder != 0) tool_change(0);
|
||||
break;
|
||||
|
||||
@ -26,7 +26,6 @@
|
||||
|
||||
#include "../../gcode.h"
|
||||
#include "../../../module/planner.h"
|
||||
#include "../../../module/stepper.h"
|
||||
|
||||
#if ENABLED(EXTRA_LIN_ADVANCE_K)
|
||||
float other_extruder_advance_K[EXTRUDERS];
|
||||
|
||||
@ -44,14 +44,14 @@ void GcodeSuite::M486() {
|
||||
cancelable.object_count = parser.intval('T', 1);
|
||||
}
|
||||
|
||||
if (parser.seen('S'))
|
||||
if (parser.seenval('S'))
|
||||
cancelable.set_active_object(parser.value_int());
|
||||
|
||||
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
|
||||
|
||||
@ -45,9 +45,10 @@
|
||||
* X, Y, Z : Specify axes to move during cleaning. Default: ALL.
|
||||
*/
|
||||
void GcodeSuite::G12() {
|
||||
|
||||
// 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)))
|
||||
return;
|
||||
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);
|
||||
if (homing_needed_error(clean_axis_mask)) return;
|
||||
|
||||
#ifdef WIPE_SEQUENCE_COMMANDS
|
||||
if (!parser.seen_any()) {
|
||||
|
||||
@ -39,9 +39,11 @@
|
||||
#endif
|
||||
|
||||
/**
|
||||
* M907: Set digital trimpot motor current using axis codes X [Y] [Z] [E]
|
||||
* B<current> - Special case for 4th (E) axis
|
||||
* S<current> - Special case to set first 3 axes
|
||||
* M907: Set digital trimpot motor current using axis codes X [Y] [Z] [I] [J] [K] [E]
|
||||
* B<current> - Special case for E1 (Requires DIGIPOTSS_PIN or DIGIPOT_MCP4018 or DIGIPOT_MCP4451)
|
||||
* 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() {
|
||||
#if HAS_MOTOR_CURRENT_SPI
|
||||
@ -49,43 +51,64 @@ void GcodeSuite::M907() {
|
||||
if (!parser.seen("BS" LOGICAL_AXES_STRING))
|
||||
return M907_report();
|
||||
|
||||
LOOP_LOGICAL_AXES(i) if (parser.seenval(axis_codes[i])) stepper.set_digipot_current(i, parser.value_int());
|
||||
if (parser.seenval('B')) stepper.set_digipot_current(4, parser.value_int());
|
||||
if (parser.seenval('S')) LOOP_LE_N(i, 4) 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());
|
||||
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)
|
||||
// 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
|
||||
|
||||
if (!parser.seen(
|
||||
#if ANY_PIN(MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y, MOTOR_CURRENT_PWM_XY)
|
||||
"XY"
|
||||
#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)
|
||||
#define HAS_X_Y_XY_I_J_K 1
|
||||
#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
|
||||
#if PIN_EXISTS(MOTOR_CURRENT_PWM_Z)
|
||||
"Z"
|
||||
if (parser.seenval('Z')) stepper.set_digipot_current(1, parser.value_int());
|
||||
#endif
|
||||
#if PIN_EXISTS(MOTOR_CURRENT_PWM_E)
|
||||
"E"
|
||||
if (parser.seenval('E')) stepper.set_digipot_current(2, parser.value_int());
|
||||
#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 // HAS_MOTOR_CURRENT_PWM
|
||||
|
||||
#if HAS_MOTOR_CURRENT_I2C
|
||||
// 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());
|
||||
// Additional extruders use B,C,D for channels 4,5,6.
|
||||
// TODO: Change these parameters because 'E' is used. B<index>?
|
||||
#if HAS_EXTRUDERS
|
||||
for (uint8_t i = E_AXIS + 1; i < DIGIPOT_I2C_NUM_CHANNELS; i++)
|
||||
if (parser.seenval('S')) LOOP_L_N(q, DIGIPOT_I2C_NUM_CHANNELS) digipot_i2c.set_current(q, parser.value_float());
|
||||
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)
|
||||
// Additional extruders use B,C,D.
|
||||
// TODO: Change these parameters because 'E' is used and because 'D' should be reserved for debugging. B<index>?
|
||||
#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());
|
||||
#endif
|
||||
#endif
|
||||
@ -93,9 +116,9 @@ void GcodeSuite::M907() {
|
||||
#if HAS_MOTOR_CURRENT_DAC
|
||||
if (parser.seenval('S')) {
|
||||
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
|
||||
}
|
||||
|
||||
@ -104,19 +127,25 @@ void GcodeSuite::M907() {
|
||||
void GcodeSuite::M907_report(const bool forReplay/*=true*/) {
|
||||
report_heading_etc(forReplay, F(STR_STEPPER_MOTOR_CURRENTS));
|
||||
#if HAS_MOTOR_CURRENT_PWM
|
||||
SERIAL_ECHOLNPGM_P( // PWM-based has 3 values:
|
||||
PSTR(" M907 X"), stepper.motor_current_setting[0] // X and Y
|
||||
SERIAL_ECHOLNPGM_P( // PWM-based has 3 values:
|
||||
PSTR(" M907 X"), stepper.motor_current_setting[0] // X, Y, (I, J, K)
|
||||
, SP_Z_STR, stepper.motor_current_setting[1] // Z
|
||||
, SP_E_STR, stepper.motor_current_setting[2] // E
|
||||
);
|
||||
#elif HAS_MOTOR_CURRENT_SPI
|
||||
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)
|
||||
SERIAL_CHAR(' ', axis_codes[q]);
|
||||
SERIAL_CHAR(' ', IAXIS_CHAR(q));
|
||||
SERIAL_ECHO(stepper.motor_current_setting[q]);
|
||||
}
|
||||
SERIAL_CHAR(' ', 'B'); // B (maps to E1 by default)
|
||||
SERIAL_ECHOLN(stepper.motor_current_setting[4]);
|
||||
#if E_STEPPERS >= 2
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@ -45,10 +45,10 @@
|
||||
*/
|
||||
void GcodeSuite::M260() {
|
||||
// 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
|
||||
if (parser.seen('B')) i2c.addbyte(parser.value_byte());
|
||||
if (parser.seenval('B')) i2c.addbyte(parser.value_byte());
|
||||
|
||||
// Flush the buffer to the bus
|
||||
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>
|
||||
*/
|
||||
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
|
||||
style = parser.byteval('S'); // Serial output style (ASCII, HEX etc)
|
||||
|
||||
@ -51,7 +51,7 @@ void GcodeSuite::G60() {
|
||||
DEBUG_ECHOPGM(STR_SAVED_POS " S", slot, " :");
|
||||
const xyze_pos_t &pos = stored_position[slot];
|
||||
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
|
||||
, SP_E_LBL, pos.e
|
||||
#endif
|
||||
|
||||
@ -71,7 +71,7 @@ void GcodeSuite::G61() {
|
||||
if (parser.seen(LINEAR_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K))) {
|
||||
DEBUG_ECHOPGM(STR_RESTORING_POS " S", slot);
|
||||
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)
|
||||
: current_position[i];
|
||||
DEBUG_CHAR(' ', AXIS_CHAR(i));
|
||||
|
||||
@ -74,7 +74,9 @@ void GcodeSuite::M125() {
|
||||
);
|
||||
|
||||
// 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)
|
||||
park_point += hotend_offset[active_extruder];
|
||||
|
||||
@ -54,8 +54,11 @@
|
||||
*
|
||||
* E[distance] - Retract the filament this far
|
||||
* Z[distance] - Move the Z axis by this distance
|
||||
* X[position] - Move to this X position, with Y
|
||||
* Y[position] - Move to this Y position, with X
|
||||
* X[position] - Move to this X position (instead of NOZZLE_PARK_POINT.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)
|
||||
* L[distance] - Extrude distance for insertion (manual reload)
|
||||
* 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
|
||||
LINEAR_AXIS_CODE(
|
||||
if (parser.seenval('X')) park_point.x = parser.linearval('X'),
|
||||
if (parser.seenval('Y')) park_point.y = parser.linearval('Y'),
|
||||
if (parser.seenval('Z')) park_point.z = parser.linearval('Z'), // Lift Z axis
|
||||
if (parser.seenval(AXIS4_NAME)) park_point.i = parser.linearval(AXIS4_NAME),
|
||||
if (parser.seenval(AXIS5_NAME)) park_point.j = parser.linearval(AXIS5_NAME),
|
||||
if (parser.seenval(AXIS6_NAME)) park_point.k = parser.linearval(AXIS6_NAME)
|
||||
if (parser.seenval('X')) park_point.x = parser.value_linear_units(),
|
||||
if (parser.seenval('Y')) park_point.y = parser.value_linear_units(),
|
||||
if (parser.seenval('Z')) park_point.z = parser.value_linear_units(), // Lift Z axis
|
||||
if (parser.seenval('I')) park_point.i = parser.value_linear_units(),
|
||||
if (parser.seenval('J')) park_point.j = parser.value_linear_units(),
|
||||
if (parser.seenval('K')) park_point.k = parser.value_linear_units()
|
||||
);
|
||||
|
||||
#if HAS_HOTEND_OFFSET && NONE(DUAL_X_CARRIAGE, DELTA)
|
||||
park_point += hotend_offset[active_extruder];
|
||||
#endif
|
||||
|
||||
#if ENABLED(MMU2_MENUS)
|
||||
// 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;
|
||||
#else
|
||||
// Unload filament
|
||||
const float unload_length = -ABS(parser.axisunitsval('U', E_AXIS, fc_settings[active_extruder].unload_length));
|
||||
#endif
|
||||
// Unload filament
|
||||
// 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 int beep_count = parser.intval('B', -1
|
||||
#ifdef FILAMENT_CHANGE_ALERT_BEEPS
|
||||
|
||||
@ -48,7 +48,7 @@ void GcodeSuite::M603() {
|
||||
if (target_extruder < 0) return;
|
||||
|
||||
// Unload length
|
||||
if (parser.seen('U')) {
|
||||
if (parser.seenval('U')) {
|
||||
fc_settings[target_extruder].unload_length = ABS(parser.value_axis_units(E_AXIS));
|
||||
#if ENABLED(PREVENT_LENGTHY_EXTRUDE)
|
||||
NOMORE(fc_settings[target_extruder].unload_length, EXTRUDE_MAXLENGTH);
|
||||
@ -56,7 +56,7 @@ void GcodeSuite::M603() {
|
||||
}
|
||||
|
||||
// Load length
|
||||
if (parser.seen('L')) {
|
||||
if (parser.seenval('L')) {
|
||||
fc_settings[target_extruder].load_length = ABS(parser.value_axis_units(E_AXIS));
|
||||
#if ENABLED(PREVENT_LENGTHY_EXTRUDE)
|
||||
NOMORE(fc_settings[target_extruder].load_length, EXTRUDE_MAXLENGTH);
|
||||
|
||||
@ -106,8 +106,8 @@ void GcodeSuite::M701() {
|
||||
#else
|
||||
constexpr float purge_length = ADVANCED_PAUSE_PURGE_LENGTH,
|
||||
slow_load_length = FILAMENT_CHANGE_SLOW_LOAD_LENGTH;
|
||||
const float fast_load_length = ABS(parser.seen('L') ? parser.value_axis_units(E_AXIS)
|
||||
: fc_settings[active_extruder].load_length);
|
||||
const float fast_load_length = ABS(parser.seenval('L') ? parser.value_axis_units(E_AXIS)
|
||||
: fc_settings[active_extruder].load_length);
|
||||
load_filament(
|
||||
slow_load_length, fast_load_length, purge_length,
|
||||
FILAMENT_CHANGE_ALERT_BEEPS,
|
||||
|
||||
@ -48,7 +48,7 @@ void GcodeSuite::M412() {
|
||||
if (seenR || seenS) runout.reset();
|
||||
if (seenS) runout.enabled = parser.value_bool();
|
||||
#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
|
||||
}
|
||||
else {
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
|
||||
#include "../../gcode.h"
|
||||
#include "../../../feature/tmc_util.h"
|
||||
#include "../../../module/stepper/indirection.h"
|
||||
#include "../../../module/stepper/indirection.h" // for restore_stepper_drivers
|
||||
|
||||
/**
|
||||
* M122: Debug TMC drivers
|
||||
|
||||
@ -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(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 (TERN0( J_HAS_STEALTHCHOP, stepperJ.get_stored_stealthChop())) { say_M569(forReplay, FPSTR(SP_J_STR), true); }
|
||||
if (TERN0( K_HAS_STEALTHCHOP, stepperK.get_stored_stealthChop())) { say_M569(forReplay, FPSTR(SP_K_STR), true); }
|
||||
|
||||
#if HAS_I_AXIS
|
||||
if (TERN0(I_HAS_STEALTHCHOP, stepperI.get_stored_stealthChop())) { say_M569(forReplay, FPSTR(SP_I_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(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); }
|
||||
|
||||
@ -137,7 +137,7 @@
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* Examples:
|
||||
|
||||
@ -53,7 +53,7 @@ GcodeSuite gcode;
|
||||
#include "../feature/cancel_object.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(LASER_MOVE_POWER)
|
||||
#if ENABLED(LASER_FEATURE)
|
||||
#include "../feature/spindle_laser.h"
|
||||
#endif
|
||||
|
||||
@ -207,8 +207,11 @@ void GcodeSuite::get_destination_from_command() {
|
||||
recovery.save();
|
||||
#endif
|
||||
|
||||
if (parser.floatval('F') > 0)
|
||||
if (parser.floatval('F') > 0) {
|
||||
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 (!DEBUGGING(DRYRUN) && !skip_move)
|
||||
@ -220,15 +223,29 @@ void GcodeSuite::get_destination_from_command() {
|
||||
M165();
|
||||
#endif
|
||||
|
||||
#if ENABLED(LASER_MOVE_POWER)
|
||||
// Set the laser power in the planner to configure this move
|
||||
if (parser.seen('S')) {
|
||||
const float spwr = parser.value_float();
|
||||
cutter.inline_power(TERN(SPINDLE_LASER_USE_PWM, cutter.power_to_range(cutter_power_t(round(spwr))), spwr > 0 ? 255 : 0));
|
||||
#if ENABLED(LASER_FEATURE)
|
||||
if (cutter.cutter_mode == CUTTER_MODE_CONTINUOUS || cutter.cutter_mode == CUTTER_MODE_DYNAMIC) {
|
||||
// Set the cutter power in the planner to configure this move
|
||||
cutter.last_feedrate_mm_m = 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
|
||||
cutter.set_inline_enabled(false);
|
||||
#endif
|
||||
else if (parser.codenum == 0)
|
||||
cutter.apply_power(0);
|
||||
#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
|
||||
#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)
|
||||
case 425: M425(); break; // M425: Tune backlash compensation
|
||||
#endif
|
||||
@ -909,7 +930,7 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
|
||||
#endif
|
||||
|
||||
#if IS_KINEMATIC
|
||||
case 665: M665(); break; // M665: Set Delta/SCARA parameters
|
||||
case 665: M665(); break; // M665: Set Kinematics parameters
|
||||
#endif
|
||||
|
||||
#if ENABLED(DELTA) || HAS_EXTRA_ENDSTOPS
|
||||
|
||||
@ -262,6 +262,7 @@
|
||||
* 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)
|
||||
* 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)
|
||||
* 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)
|
||||
@ -885,7 +886,7 @@ private:
|
||||
static void M250_report(const bool forReplay=true);
|
||||
#endif
|
||||
|
||||
#if HAS_DISPLAY_SLEEP
|
||||
#if HAS_GCODE_M255
|
||||
static void M255();
|
||||
static void M255_report(const bool forReplay=true);
|
||||
#endif
|
||||
|
||||
@ -25,8 +25,6 @@
|
||||
|
||||
#if ENABLED(CNC_COORDINATE_SYSTEMS)
|
||||
|
||||
#include "../../module/stepper.h"
|
||||
|
||||
//#define DEBUG_M53
|
||||
|
||||
/**
|
||||
|
||||
@ -22,7 +22,6 @@
|
||||
|
||||
#include "../gcode.h"
|
||||
#include "../../module/motion.h"
|
||||
#include "../../module/stepper.h"
|
||||
|
||||
#if ENABLED(I2C_POSITION_ENCODERS)
|
||||
#include "../../feature/encoder_i2c.h"
|
||||
|
||||
@ -40,13 +40,12 @@
|
||||
void GcodeSuite::M206() {
|
||||
if (!parser.seen_any()) return M206_report();
|
||||
|
||||
LOOP_LINEAR_AXES(i)
|
||||
if (parser.seen(AXIS_CHAR(i)))
|
||||
set_home_offset((AxisEnum)i, parser.value_linear_units());
|
||||
LOOP_LINEAR_AXES(a)
|
||||
if (parser.seenval(AXIS_CHAR(a))) set_home_offset((AxisEnum)a, parser.value_axis_units((AxisEnum)a));
|
||||
|
||||
#if ENABLED(MORGAN_SCARA)
|
||||
if (parser.seen('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('T')) set_home_offset(A_AXIS, parser.value_float()); // Theta
|
||||
if (parser.seenval('P')) set_home_offset(B_AXIS, parser.value_float()); // Psi
|
||||
#endif
|
||||
|
||||
report_current_position();
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
void report_all_axis_pos(const xyze_pos_t &pos, const uint8_t n=XYZE, const uint8_t precision=3) {
|
||||
char str[12];
|
||||
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(' ');
|
||||
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) {
|
||||
char str[12];
|
||||
LOOP_LINEAR_AXES(a) {
|
||||
SERIAL_CHAR(' ', AXIS_CHAR(a), ':');
|
||||
SERIAL_ECHO(dtostrf(pos[a], 1, precision, str));
|
||||
}
|
||||
LOOP_LINEAR_AXES(a) SERIAL_ECHOPGM_P((PGM_P)pgm_read_ptr(&SP_AXIS_LBL[a]), dtostrf(pos[a], 1, precision, str));
|
||||
SERIAL_EOL();
|
||||
}
|
||||
|
||||
@ -163,8 +160,7 @@
|
||||
|
||||
SERIAL_ECHOPGM("Stepper:");
|
||||
LOOP_LOGICAL_AXES(i) {
|
||||
SERIAL_CHAR(' ', axis_codes[i], ':');
|
||||
SERIAL_ECHO(stepper.position((AxisEnum)i));
|
||||
SERIAL_ECHOPGM_P((PGM_P)pgm_read_ptr(&SP_AXIS_LBL[i]), stepper.position((AxisEnum)i));
|
||||
}
|
||||
SERIAL_EOL();
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user