diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..221568f2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# Compiled binaries +Marlin.ino.with_bootloader.mega.hex +Marlin.ino.mega.hex diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 053c856f..48ddcf50 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -35,7 +35,7 @@ * * Advanced settings can be found in Configuration_adv.h */ -#define CONFIGURATION_H_VERSION 02000903 +#define CONFIGURATION_H_VERSION 02010205 //=========================================================================== //============================= Getting Started ============================= @@ -46,26 +46,18 @@ * * Example Configs: https://github.com/MarlinFirmware/Configurations/branches/all * - * Průša Calculator: https://blog.prusaprinters.org/calculator_3416/ + * Průša Calculator: https://blog.prusa3d.com/calculator_3416/ * * Calibration Guides: https://reprap.org/wiki/Calibration * https://reprap.org/wiki/Triffid_Hunter%27s_Calibration_Guide - * https://sites.google.com/site/repraplogphase/calibration-of-your-reprap + * https://web.archive.org/web/20220907014303/sites.google.com/site/repraplogphase/calibration-of-your-reprap * https://youtu.be/wAL9d7FgInk + * https://teachingtechyt.github.io/calibration.html * * Calibration Objects: https://www.thingiverse.com/thing:5573 * 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 @@ -99,6 +91,8 @@ #define MOTHERBOARD BOARD_RAMPS_14_EFB #endif +// @section serial + /** * Select the serial port on the board to use for communication with the host. * This allows the connection of wireless adapters (for instance) to non-default port pins. @@ -121,6 +115,7 @@ * :[2400, 9600, 19200, 38400, 57600, 115200, 250000, 500000, 1000000] */ #define BAUDRATE 250000 + //#define BAUD_RATE_GCODE // Enable G-code M575 to set the baud rate /** @@ -129,7 +124,7 @@ * :[-2, -1, 0, 1, 2, 3, 4, 5, 6, 7] */ //#define SERIAL_PORT_2 -1 -//#define BAUDRATE_2 250000 // Enable to override BAUDRATE +//#define BAUDRATE_2 250000 // :[2400, 9600, 19200, 38400, 57600, 115200, 250000, 500000, 1000000] Enable to override BAUDRATE /** * Select a third serial port on the board to use for communication with the host. @@ -137,7 +132,7 @@ * :[-1, 0, 1, 2, 3, 4, 5, 6, 7] */ //#define SERIAL_PORT_3 1 -//#define BAUDRATE_3 250000 // Enable to override BAUDRATE +//#define BAUDRATE_3 250000 // :[2400, 9600, 19200, 38400, 57600, 115200, 250000, 500000, 1000000] Enable to override BAUDRATE // Enable the Bluetooth serial interface on AT90USB devices //#define BLUETOOTH @@ -149,43 +144,86 @@ // Choose your own or use a service like https://www.uuidgenerator.net/version4 //#define MACHINE_UUID "00000000-0000-0000-0000-000000000000" +// @section stepper drivers + /** - * Define the number of coordinated linear axes. - * See https://github.com/DerAndere1/Marlin/wiki - * Each linear axis gets its own stepper control and endstop: + * Stepper Drivers + * + * These settings allow Marlin to tune stepper driver timing and enable advanced options for + * stepper drivers that support them. You may also override timing options in Configuration_adv.h. * - * Steppers: *_STEP_PIN, *_ENABLE_PIN, *_DIR_PIN, *_ENABLE_ON - * Endstops: *_STOP_PIN, USE_*MIN_PLUG, USE_*MAX_PLUG - * Axes: *_MIN_POS, *_MAX_POS, INVERT_*_DIR - * Planner: DEFAULT_AXIS_STEPS_PER_UNIT, DEFAULT_MAX_FEEDRATE - * DEFAULT_MAX_ACCELERATION, AXIS_RELATIVE_MODES, - * MICROSTEP_MODES, MANUAL_FEEDRATE + * Use TMC2208/TMC2208_STANDALONE for TMC2225 drivers and TMC2209/TMC2209_STANDALONE for TMC2226 drivers. * - * :[3, 4, 5, 6] + * Options: A4988, A5984, DRV8825, LV8729, TB6560, TB6600, TMC2100, + * TMC2130, TMC2130_STANDALONE, TMC2160, TMC2160_STANDALONE, + * TMC2208, TMC2208_STANDALONE, TMC2209, TMC2209_STANDALONE, + * TMC26X, TMC26X_STANDALONE, TMC2660, TMC2660_STANDALONE, + * TMC5130, TMC5130_STANDALONE, TMC5160, TMC5160_STANDALONE + * :['A4988', 'A5984', 'DRV8825', 'LV8729', 'TB6560', 'TB6600', 'TMC2100', 'TMC2130', 'TMC2130_STANDALONE', 'TMC2160', 'TMC2160_STANDALONE', 'TMC2208', 'TMC2208_STANDALONE', 'TMC2209', 'TMC2209_STANDALONE', 'TMC26X', 'TMC26X_STANDALONE', 'TMC2660', 'TMC2660_STANDALONE', 'TMC5130', 'TMC5130_STANDALONE', 'TMC5160', 'TMC5160_STANDALONE'] */ -//#define LINEAR_AXES 3 +#define X_DRIVER_TYPE A4988 +#define Y_DRIVER_TYPE A4988 +#define Z_DRIVER_TYPE A4988 +//#define X2_DRIVER_TYPE A4988 +//#define Y2_DRIVER_TYPE A4988 +//#define Z2_DRIVER_TYPE A4988 +//#define Z3_DRIVER_TYPE A4988 +//#define Z4_DRIVER_TYPE A4988 +//#define I_DRIVER_TYPE A4988 +//#define J_DRIVER_TYPE A4988 +//#define K_DRIVER_TYPE A4988 +//#define U_DRIVER_TYPE A4988 +//#define V_DRIVER_TYPE A4988 +//#define W_DRIVER_TYPE A4988 +#define E0_DRIVER_TYPE DRV8825 +//#define E1_DRIVER_TYPE A4988 +//#define E2_DRIVER_TYPE A4988 +//#define E3_DRIVER_TYPE A4988 +//#define E4_DRIVER_TYPE A4988 +//#define E5_DRIVER_TYPE A4988 +//#define E6_DRIVER_TYPE A4988 +//#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 + * + * Define AXISn_ROTATES for all axes that rotate or pivot. + * Rotational axis coordinates are expressed in degrees. + * + * 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, U, V, W. */ -#if LINEAR_AXES >= 4 +#ifdef I_DRIVER_TYPE #define AXIS4_NAME 'A' // :['A', 'B', 'C', 'U', 'V', 'W'] + #define AXIS4_ROTATES +#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 +#ifdef U_DRIVER_TYPE + #define AXIS7_NAME 'U' // :['U', 'V', 'W'] + //#define AXIS7_ROTATES #endif -#if LINEAR_AXES >= 5 - #define AXIS5_NAME 'B' // :['A', 'B', 'C', 'U', 'V', 'W'] +#ifdef V_DRIVER_TYPE + #define AXIS8_NAME 'V' // :['V', 'W'] + //#define AXIS8_ROTATES #endif -#if LINEAR_AXES >= 6 - #define AXIS6_NAME 'C' // :['A', 'B', 'C', 'U', 'V', 'W'] +#ifdef W_DRIVER_TYPE + #define AXIS9_NAME 'W' // :['W'] + //#define AXIS9_ROTATES #endif // @section extruder @@ -207,21 +245,6 @@ //#define SINGLENOZZLE_STANDBY_FAN #endif -/** - * Multi-Material Unit - * Set to one of these predefined models: - * - * PRUSA_MMU1 : Průša MMU1 (The "multiplexer" version) - * PRUSA_MMU2 : Průša MMU2 - * PRUSA_MMU2S : Průša MMU2S (Requires MK3S extruder with motion sensor, EXTRUDERS = 5) - * EXTENDABLE_EMU_MMU2 : MMU with configurable number of filaments (ERCF, SMuFF or similar with Průša MMU2 compatible firmware) - * EXTENDABLE_EMU_MMU2S : MMUS with configurable number of filaments (ERCF, SMuFF or similar with Průša MMU2 compatible firmware) - * - * Requires NOZZLE_PARK_FEATURE to park print head in case MMU unit fails. - * See additional options in Configuration_adv.h. - */ -//#define MMU_MODEL PRUSA_MMU2 - // A dual extruder that uses a single stepper motor //#define SWITCHING_EXTRUDER #if ENABLED(SWITCHING_EXTRUDER) @@ -237,7 +260,9 @@ #if ENABLED(SWITCHING_NOZZLE) #define SWITCHING_NOZZLE_SERVO_NR 0 //#define SWITCHING_NOZZLE_E1_SERVO_NR 1 // If two servos are used, the index of the second - #define SWITCHING_NOZZLE_SERVO_ANGLES { 0, 90 } // Angles for E0, E1 (single servo) or lowered/raised (dual servo) + #define SWITCHING_NOZZLE_SERVO_ANGLES { 0, 90 } // A pair of angles for { E0, E1 }. + // For Dual Servo use two pairs: { { lower, raise }, { lower, raise } } + #define SWITCHING_NOZZLE_SERVO_DWELL 2500 // Dwell time to wait for servo to make physical move #endif /** @@ -354,7 +379,25 @@ //#define HOTEND_OFFSET_Y { 0.0, 5.00 } // (mm) relative Y-offset for each nozzle //#define HOTEND_OFFSET_Z { 0.0, 0.00 } // (mm) relative Z-offset for each nozzle -// @section machine +// @section multi-material + +/** + * Multi-Material Unit + * Set to one of these predefined models: + * + * PRUSA_MMU1 : Průša MMU1 (The "multiplexer" version) + * PRUSA_MMU2 : Průša MMU2 + * PRUSA_MMU2S : Průša MMU2S (Requires MK3S extruder with motion sensor, EXTRUDERS = 5) + * EXTENDABLE_EMU_MMU2 : MMU with configurable number of filaments (ERCF, SMuFF or similar with Průša MMU2 compatible firmware) + * EXTENDABLE_EMU_MMU2S : MMUS with configurable number of filaments (ERCF, SMuFF or similar with Průša MMU2 compatible firmware) + * + * Requires NOZZLE_PARK_FEATURE to park print head in case MMU unit fails. + * See additional options in Configuration_adv.h. + * :["PRUSA_MMU1", "PRUSA_MMU2", "PRUSA_MMU2S", "EXTENDABLE_EMU_MMU2", "EXTENDABLE_EMU_MMU2S"] + */ +//#define MMU_MODEL PRUSA_MMU2 + +// @section psu control /** * Power Supply Control @@ -371,25 +414,31 @@ //#define PS_OFF_SOUND // Beep 1s when power off #define PSU_ACTIVE_STATE LOW // Set 'LOW' for ATX, 'HIGH' for X-Box - //#define PSU_DEFAULT_OFF // Keep power off until enabled directly with M80 - //#define PSU_POWERUP_DELAY 250 // (ms) Delay for the PSU to warm up to full power + //#define PSU_DEFAULT_OFF // Keep power off until enabled directly with M80 + //#define PSU_POWERUP_DELAY 250 // (ms) Delay for the PSU to warm up to full power + //#define LED_POWEROFF_TIMEOUT 10000 // (ms) Turn off LEDs after power-off, with this amount of delay + + //#define POWER_OFF_TIMER // Enable M81 D to power off after a delay + //#define POWER_OFF_WAIT_FOR_COOLDOWN // Enable M81 S to power off only after cooldown //#define PSU_POWERUP_GCODE "M355 S1" // G-code to run after power-on (e.g., case light on) //#define PSU_POWEROFF_GCODE "M355 S0" // G-code to run before power-off (e.g., case light off) //#define AUTO_POWER_CONTROL // Enable automatic control of the PS_ON pin #if ENABLED(AUTO_POWER_CONTROL) - #define AUTO_POWER_FANS // Turn on PSU if fans need power - #define AUTO_POWER_E_FANS - #define AUTO_POWER_CONTROLLERFAN - #define AUTO_POWER_CHAMBER_FAN - #define AUTO_POWER_COOLER_FAN - //#define AUTO_POWER_E_TEMP 50 // (°C) Turn on PSU if any extruder is over this temperature - //#define AUTO_POWER_CHAMBER_TEMP 30 // (°C) Turn on PSU if the chamber is over this temperature - //#define AUTO_POWER_COOLER_TEMP 26 // (°C) Turn on PSU if the cooler is over this temperature + #define AUTO_POWER_FANS // Turn on PSU for fans + #define AUTO_POWER_E_FANS // Turn on PSU for E Fans + #define AUTO_POWER_CONTROLLERFAN // Turn on PSU for Controller Fan + #define AUTO_POWER_CHAMBER_FAN // Turn on PSU for Chamber Fan + #define AUTO_POWER_COOLER_FAN // Turn on PSU for Cooler Fan #define POWER_TIMEOUT 30 // (s) Turn off power if the machine is idle for this duration //#define POWER_OFF_DELAY 60 // (s) Delay of poweroff after M81 command. Useful to let fans run for extra time. #endif + #if EITHER(AUTO_POWER_CONTROL, POWER_OFF_WAIT_FOR_COOLDOWN) + //#define AUTO_POWER_E_TEMP 50 // (°C) PSU on if any extruder is over this temperature + //#define AUTO_POWER_CHAMBER_TEMP 30 // (°C) PSU on if the chamber is over this temperature + //#define AUTO_POWER_COOLER_TEMP 26 // (°C) PSU on if the cooler is over this temperature + #endif #endif //=========================================================================== @@ -398,77 +447,74 @@ // @section temperature /** - * --NORMAL IS 4.7kΩ PULLUP!-- 1kΩ pullup can be used on hotend sensor, using correct resistor and table - * - * Temperature sensors available: - * - * SPI RTD/Thermocouple Boards - IMPORTANT: Read the NOTE below! - * ------- - * -5 : MAX31865 with Pt100/Pt1000, 2, 3, or 4-wire (only for sensors 0-1) - * NOTE: You must uncomment/set the MAX31865_*_OHMS_n defines below. - * -3 : MAX31855 with Thermocouple, -200°C to +700°C (only for sensors 0-1) - * -2 : MAX6675 with Thermocouple, 0°C to +700°C (only for sensors 0-1) + * Temperature Sensors: * - * NOTE: Ensure TEMP_n_CS_PIN is set in your pins file for each TEMP_SENSOR_n using an SPI Thermocouple. By default, - * Hardware SPI on the default serial bus is used. If you have also set TEMP_n_SCK_PIN and TEMP_n_MISO_PIN, - * Software SPI will be used on those ports instead. You can force Hardware SPI on the default bus in the - * Configuration_adv.h file. At this time, separate Hardware SPI buses for sensors are not supported. - * - * Analog Themocouple Boards - * ------- - * -4 : AD8495 with Thermocouple - * -1 : AD595 with Thermocouple + * NORMAL IS 4.7kΩ PULLUP! Hotend sensors can use 1kΩ pullup with correct resistor and table. * + * ================================================================ * Analog Thermistors - 4.7kΩ pullup - Normal - * ------- - * 1 : 100kΩ EPCOS - Best choice for EPCOS thermistors - * 331 : 100kΩ Same as #1, but 3.3V scaled for MEGA - * 332 : 100kΩ Same as #1, but 3.3V scaled for DUE - * 2 : 200kΩ ATC Semitec 204GT-2 - * 202 : 200kΩ Copymaster 3D - * 3 : ???Ω Mendel-parts thermistor - * 4 : 10kΩ Generic Thermistor !! DO NOT use for a hotend - it gives bad resolution at high temp. !! - * 5 : 100kΩ ATC Semitec 104GT-2/104NT-4-R025H42G - Used in ParCan, J-Head, and E3D, SliceEngineering 300°C - * 501 : 100kΩ Zonestar - Tronxy X3A - * 502 : 100kΩ Zonestar - used by hot bed in Zonestar Průša P802M - * 512 : 100kΩ RPW-Ultra hotend - * 6 : 100kΩ EPCOS - Not as accurate as table #1 (created using a fluke thermocouple) - * 7 : 100kΩ Honeywell 135-104LAG-J01 - * 71 : 100kΩ Honeywell 135-104LAF-J01 - * 8 : 100kΩ Vishay 0603 SMD NTCS0603E3104FXT - * 9 : 100kΩ GE Sensing AL03006-58.2K-97-G1 - * 10 : 100kΩ RS PRO 198-961 - * 11 : 100kΩ Keenovo AC silicone mats, most Wanhao i3 machines - beta 3950, 1% - * 12 : 100kΩ Vishay 0603 SMD NTCS0603E3104FXT (#8) - calibrated for Makibox hot bed - * 13 : 100kΩ Hisens up to 300°C - for "Simple ONE" & "All In ONE" hotend - beta 3950, 1% - * 15 : 100kΩ Calibrated for JGAurora A5 hotend - * 18 : 200kΩ ATC Semitec 204GT-2 Dagoma.Fr - MKS_Base_DKU001327 - * 22 : 100kΩ GTM32 Pro vB - hotend - 4.7kΩ pullup to 3.3V and 220Ω to analog input - * 23 : 100kΩ GTM32 Pro vB - bed - 4.7kΩ pullup to 3.3v and 220Ω to analog input - * 30 : 100kΩ Kis3d Silicone heating mat 200W/300W with 6mm precision cast plate (EN AW 5083) NTC100K - beta 3950 - * 60 : 100kΩ Maker's Tool Works Kapton Bed Thermistor - beta 3950 - * 61 : 100kΩ Formbot/Vivedino 350°C Thermistor - beta 3950 - * 66 : 4.7MΩ Dyze Design High Temperature Thermistor - * 67 : 500kΩ SliceEngineering 450°C Thermistor - * 70 : 100kΩ bq Hephestos 2 - * 75 : 100kΩ Generic Silicon Heat Pad with NTC100K MGB18-104F39050L32 - * 2000 : 100kΩ Ultimachine Rambo TDK NTCG104LH104KT1 NTC100K motherboard Thermistor - * - * Analog Thermistors - 1kΩ pullup - Atypical, and requires changing out the 4.7kΩ pullup for 1kΩ. - * ------- (but gives greater accuracy and more stable PID) - * 51 : 100kΩ EPCOS (1kΩ pullup) - * 52 : 200kΩ ATC Semitec 204GT-2 (1kΩ pullup) - * 55 : 100kΩ ATC Semitec 104GT-2 - Used in ParCan & J-Head (1kΩ pullup) - * + * ================================================================ + * 1 : 100kΩ EPCOS - Best choice for EPCOS thermistors + * 331 : 100kΩ Same as #1, but 3.3V scaled for MEGA + * 332 : 100kΩ Same as #1, but 3.3V scaled for DUE + * 2 : 200kΩ ATC Semitec 204GT-2 + * 202 : 200kΩ Copymaster 3D + * 3 : ???Ω Mendel-parts thermistor + * 4 : 10kΩ Generic Thermistor !! DO NOT use for a hotend - it gives bad resolution at high temp. !! + * 5 : 100kΩ ATC Semitec 104GT-2/104NT-4-R025H42G - Used in ParCan, J-Head, and E3D, SliceEngineering 300°C + * 501 : 100kΩ Zonestar - Tronxy X3A + * 502 : 100kΩ Zonestar - used by hot bed in Zonestar Průša P802M + * 503 : 100kΩ Zonestar (Z8XM2) Heated Bed thermistor + * 504 : 100kΩ Zonestar P802QR2 (Part# QWG-104F-B3950) Hotend Thermistor + * 505 : 100kΩ Zonestar P802QR2 (Part# QWG-104F-3950) Bed Thermistor + * 512 : 100kΩ RPW-Ultra hotend + * 6 : 100kΩ EPCOS - Not as accurate as table #1 (created using a fluke thermocouple) + * 7 : 100kΩ Honeywell 135-104LAG-J01 + * 71 : 100kΩ Honeywell 135-104LAF-J01 + * 8 : 100kΩ Vishay 0603 SMD NTCS0603E3104FXT + * 9 : 100kΩ GE Sensing AL03006-58.2K-97-G1 + * 10 : 100kΩ RS PRO 198-961 + * 11 : 100kΩ Keenovo AC silicone mats, most Wanhao i3 machines - beta 3950, 1% + * 12 : 100kΩ Vishay 0603 SMD NTCS0603E3104FXT (#8) - calibrated for Makibox hot bed + * 13 : 100kΩ Hisens up to 300°C - for "Simple ONE" & "All In ONE" hotend - beta 3950, 1% + * 14 : 100kΩ (R25), 4092K (beta25), 4.7kΩ pull-up, bed thermistor as used in Ender-5 S1 + * 15 : 100kΩ Calibrated for JGAurora A5 hotend + * 17 : 100kΩ Dagoma NTC white thermistor + * 18 : 200kΩ ATC Semitec 204GT-2 Dagoma.Fr - MKS_Base_DKU001327 + * 22 : 100kΩ GTM32 Pro vB - hotend - 4.7kΩ pullup to 3.3V and 220Ω to analog input + * 23 : 100kΩ GTM32 Pro vB - bed - 4.7kΩ pullup to 3.3v and 220Ω to analog input + * 30 : 100kΩ Kis3d Silicone heating mat 200W/300W with 6mm precision cast plate (EN AW 5083) NTC100K - beta 3950 + * 60 : 100kΩ Maker's Tool Works Kapton Bed Thermistor - beta 3950 + * 61 : 100kΩ Formbot/Vivedino 350°C Thermistor - beta 3950 + * 66 : 4.7MΩ Dyze Design / Trianglelab T-D500 500°C High Temperature Thermistor + * 67 : 500kΩ SliceEngineering 450°C Thermistor + * 68 : PT100 Smplifier board from Dyze Design + * 70 : 100kΩ bq Hephestos 2 + * 75 : 100kΩ Generic Silicon Heat Pad with NTC100K MGB18-104F39050L32 + * 666 : 200kΩ Einstart S custom thermistor with 10k pullup. + * 2000 : 100kΩ Ultimachine Rambo TDK NTCG104LH104KT1 NTC100K motherboard Thermistor + * + * ================================================================ + * Analog Thermistors - 1kΩ pullup + * Atypical, and requires changing out the 4.7kΩ pullup for 1kΩ. + * (but gives greater accuracy and more stable PID) + * ================================================================ + * 51 : 100kΩ EPCOS (1kΩ pullup) + * 52 : 200kΩ ATC Semitec 204GT-2 (1kΩ pullup) + * 55 : 100kΩ ATC Semitec 104GT-2 - Used in ParCan & J-Head (1kΩ pullup) + * + * ================================================================ * Analog Thermistors - 10kΩ pullup - Atypical - * ------- - * 99 : 100kΩ Found on some Wanhao i3 machines with a 10kΩ pull-up resistor + * ================================================================ + * 99 : 100kΩ Found on some Wanhao i3 machines with a 10kΩ pull-up resistor * + * ================================================================ * Analog RTDs (Pt100/Pt1000) - * ------- + * ================================================================ * 110 : Pt100 with 1kΩ pullup (atypical) * 147 : Pt100 with 4.7kΩ pullup * 1010 : Pt1000 with 1kΩ pullup (atypical) + * 1022 : Pt1000 with 2.2kΩ pullup * 1047 : Pt1000 with 4.7kΩ pullup (E3D) * 20 : Pt100 with circuit in the Ultimainboard V2.x with mainboard ADC reference voltage = INA826 amplifier-board supply voltage. * NOTE: (1) Must use an ADC input with no pullup. (2) Some INA826 amplifiers are unreliable at 3.3V so consider using sensor 147, 110, or 21. @@ -476,15 +522,34 @@ * NOTE: ADC pins are not 5V tolerant. Not recommended because it's possible to damage the CPU by going over 500°C. * 201 : Pt100 with circuit in Overlord, similar to Ultimainboard V2.x * + * ================================================================ + * SPI RTD/Thermocouple Boards + * ================================================================ + * -5 : MAX31865 with Pt100/Pt1000, 2, 3, or 4-wire (only for sensors 0-2 and bed) + * NOTE: You must uncomment/set the MAX31865_*_OHMS_n defines below. + * -3 : MAX31855 with Thermocouple, -200°C to +700°C (only for sensors 0-2 and bed) + * -2 : MAX6675 with Thermocouple, 0°C to +700°C (only for sensors 0-2 and bed) + * + * NOTE: Ensure TEMP_n_CS_PIN is set in your pins file for each TEMP_SENSOR_n using an SPI Thermocouple. By default, + * Hardware SPI on the default serial bus is used. If you have also set TEMP_n_SCK_PIN and TEMP_n_MISO_PIN, + * Software SPI will be used on those ports instead. You can force Hardware SPI on the default bus in the + * Configuration_adv.h file. At this time, separate Hardware SPI buses for sensors are not supported. + * + * ================================================================ + * Analog Thermocouple Boards + * ================================================================ + * -4 : AD8495 with Thermocouple + * -1 : AD595 with Thermocouple + * + * ================================================================ * Custom/Dummy/Other Thermal Sensors - * ------ + * ================================================================ * 0 : not used * 1000 : Custom - Specify parameters in Configuration_adv.h * * !!! Use these for Testing or Development purposes. NEVER for production machine. !!! * 998 : Dummy Table that ALWAYS reads 25°C or the temperature defined below. * 999 : Dummy Table that ALWAYS reads 100°C or the temperature defined below. - * */ #define TEMP_SENSOR_0 1 #define TEMP_SENSOR_1 0 @@ -506,22 +571,36 @@ #define DUMMY_THERMISTOR_999_VALUE 100 // Resistor values when using MAX31865 sensors (-5) on TEMP_SENSOR_0 / 1 -//#define MAX31865_SENSOR_OHMS_0 100 // (Ω) Typically 100 or 1000 (PT100 or PT1000) -//#define MAX31865_CALIBRATION_OHMS_0 430 // (Ω) Typically 430 for Adafruit PT100; 4300 for Adafruit PT1000 -//#define MAX31865_SENSOR_OHMS_1 100 -//#define MAX31865_CALIBRATION_OHMS_1 430 +#if TEMP_SENSOR_IS_MAX_TC(0) + #define MAX31865_SENSOR_OHMS_0 100 // (Ω) Typically 100 or 1000 (PT100 or PT1000) + #define MAX31865_CALIBRATION_OHMS_0 430 // (Ω) Typically 430 for Adafruit PT100; 4300 for Adafruit PT1000 +#endif +#if TEMP_SENSOR_IS_MAX_TC(1) + #define MAX31865_SENSOR_OHMS_1 100 + #define MAX31865_CALIBRATION_OHMS_1 430 +#endif +#if TEMP_SENSOR_IS_MAX_TC(2) + #define MAX31865_SENSOR_OHMS_2 100 + #define MAX31865_CALIBRATION_OHMS_2 430 +#endif -#define TEMP_RESIDENCY_TIME 10 // (seconds) Time to wait for hotend to "settle" in M109 -#define TEMP_WINDOW 1 // (°C) Temperature proximity for the "temperature reached" timer -#define TEMP_HYSTERESIS 3 // (°C) Temperature proximity considered "close enough" to the target +#if HAS_E_TEMP_SENSOR + #define TEMP_RESIDENCY_TIME 10 // (seconds) Time to wait for hotend to "settle" in M109 + #define TEMP_WINDOW 1 // (°C) Temperature proximity for the "temperature reached" timer + #define TEMP_HYSTERESIS 3 // (°C) Temperature proximity considered "close enough" to the target +#endif -#define TEMP_BED_RESIDENCY_TIME 10 // (seconds) Time to wait for bed to "settle" in M190 -#define TEMP_BED_WINDOW 1 // (°C) Temperature proximity for the "temperature reached" timer -#define TEMP_BED_HYSTERESIS 3 // (°C) Temperature proximity considered "close enough" to the target +#if TEMP_SENSOR_BED + #define TEMP_BED_RESIDENCY_TIME 10 // (seconds) Time to wait for bed to "settle" in M190 + #define TEMP_BED_WINDOW 1 // (°C) Temperature proximity for the "temperature reached" timer + #define TEMP_BED_HYSTERESIS 3 // (°C) Temperature proximity considered "close enough" to the target +#endif -#define TEMP_CHAMBER_RESIDENCY_TIME 10 // (seconds) Time to wait for chamber to "settle" in M191 -#define TEMP_CHAMBER_WINDOW 2 // (°C) Temperature proximity for the "temperature reached" timer -#define TEMP_CHAMBER_HYSTERESIS 6 // (°C) Temperature proximity considered "close enough" to the target +#if TEMP_SENSOR_CHAMBER + #define TEMP_CHAMBER_RESIDENCY_TIME 10 // (seconds) Time to wait for chamber to "settle" in M191 + #define TEMP_CHAMBER_WINDOW 1 // (°C) Temperature proximity for the "temperature reached" timer + #define TEMP_CHAMBER_HYSTERESIS 3 // (°C) Temperature proximity considered "close enough" to the target +#endif /** * Redundant Temperature Sensor (TEMP_SENSOR_REDUNDANT) @@ -563,7 +642,7 @@ #define HEATER_5_MAXTEMP 275 #define HEATER_6_MAXTEMP 275 #define HEATER_7_MAXTEMP 275 -#define BED_MAXTEMP 90 +#define BED_MAXTEMP 150 #define CHAMBER_MAXTEMP 60 /** @@ -579,19 +658,26 @@ //=========================================================================== //============================= PID Settings ================================ //=========================================================================== -// PID Tuning Guide here: https://reprap.org/wiki/PID_Tuning -// Comment the following line to disable PID and enable bang-bang. -#define PIDTEMP -#define BANG_MAX 255 // Limits current to nozzle while in bang-bang mode; 255=full current -#define PID_MAX BANG_MAX // Limits current to nozzle while PID is active (see PID_FUNCTIONAL_RANGE below); 255=full current -#define PID_K1 0.95 // Smoothing factor within any PID loop +// @section hotend temp + +/** + * Temperature Control + * + * (NONE) : Bang-bang heating + * PIDTEMP : PID temperature control (~4.1K) + * MPCTEMP : Predictive Model temperature control. (~1.8K without auto-tune) + */ +#define PIDTEMP // See the PID Tuning Guide at https://reprap.org/wiki/PID_Tuning +//#define MPCTEMP // See https://marlinfw.org/docs/features/model_predictive_control.html + +#define PID_MAX 255 // Limit hotend current while PID is active (see PID_FUNCTIONAL_RANGE below); 255=full current +#define PID_K1 0.95 // Smoothing factor within any PID loop #if ENABLED(PIDTEMP) - //#define PID_EDIT_MENU // Add PID editing to the "Advanced Settings" menu. (~700 bytes of PROGMEM) - //#define PID_AUTOTUNE_MENU // Add PID auto-tuning to the "Advanced Settings" menu. (~250 bytes of PROGMEM) - //#define PID_PARAMS_PER_HOTEND // Uses separate PID parameters for each extruder (useful for mismatched extruders) - // Set/get with gcode: M301 E[extruder number, 0-2] + //#define PID_DEBUG // Print PID debug data to the serial port. Use 'M303 D' to toggle activation. + //#define PID_PARAMS_PER_HOTEND // Use separate PID parameters for each extruder (useful for mismatched extruders) + // Set/get with G-code: M301 E[extruder number, 0-2] #if ENABLED(PID_PARAMS_PER_HOTEND) // Specify up to one value per hotend here, according to your setup. @@ -604,40 +690,88 @@ #define DEFAULT_Ki 1.08 #define DEFAULT_Kd 114.00 #endif -#endif // PIDTEMP +#else + #define BANG_MAX 255 // Limit hotend current while in bang-bang mode; 255=full current +#endif + +/** + * Model Predictive Control for hotend + * + * Use a physical model of the hotend to control temperature. When configured correctly this gives + * better responsiveness and stability than PID and removes the need for PID_EXTRUSION_SCALING + * and PID_FAN_SCALING. Use M306 T to autotune the model. + * @section mpctemp + */ +#if ENABLED(MPCTEMP) + //#define MPC_EDIT_MENU // Add MPC editing to the "Advanced Settings" menu. (~1.3K bytes of flash) + //#define MPC_AUTOTUNE_MENU // Add MPC auto-tuning to the "Advanced Settings" menu. (~350 bytes of flash) + + #define MPC_MAX 255 // (0..255) Current to nozzle while MPC is active. + #define MPC_HEATER_POWER { 40.0f } // (W) Heat cartridge powers. + + #define MPC_INCLUDE_FAN // Model the fan speed? + + // Measured physical constants from M306 + #define MPC_BLOCK_HEAT_CAPACITY { 16.7f } // (J/K) Heat block heat capacities. + #define MPC_SENSOR_RESPONSIVENESS { 0.22f } // (K/s per ∆K) Rate of change of sensor temperature from heat block. + #define MPC_AMBIENT_XFER_COEFF { 0.068f } // (W/K) Heat transfer coefficients from heat block to room air with fan off. + #if ENABLED(MPC_INCLUDE_FAN) + #define MPC_AMBIENT_XFER_COEFF_FAN255 { 0.097f } // (W/K) Heat transfer coefficients from heat block to room air with fan on full. + #endif + + // For one fan and multiple hotends MPC needs to know how to apply the fan cooling effect. + #if ENABLED(MPC_INCLUDE_FAN) + //#define MPC_FAN_0_ALL_HOTENDS + //#define MPC_FAN_0_ACTIVE_HOTEND + #endif + + // Filament Heat Capacity (joules/kelvin/mm) + // Set at runtime with M306 H + #define FILAMENT_HEAT_CAPACITY_PERMM { 5.6e-3f } // 0.0056 J/K/mm for 1.75mm PLA (0.0149 J/K/mm for 2.85mm PLA). + // 0.0036 J/K/mm for 1.75mm PETG (0.0094 J/K/mm for 2.85mm PETG). + // 0.00515 J/K/mm for 1.75mm ABS (0.0137 J/K/mm for 2.85mm ABS). + // 0.00522 J/K/mm for 1.75mm Nylon (0.0138 J/K/mm for 2.85mm Nylon). + + // Advanced options + #define MPC_SMOOTHING_FACTOR 0.5f // (0.0...1.0) Noisy temperature sensors may need a lower value for stabilization. + #define MPC_MIN_AMBIENT_CHANGE 1.0f // (K/s) Modeled ambient temperature rate of change, when correcting model inaccuracies. + #define MPC_STEADYSTATE 0.5f // (K/s) Temperature change rate for steady state logic to be enforced. + + #define MPC_TUNING_POS { X_CENTER, Y_CENTER, 1.0f } // (mm) M306 Autotuning position, ideally bed center at first layer height. + #define MPC_TUNING_END_Z 10.0f // (mm) M306 Autotuning final Z position. +#endif //=========================================================================== //====================== PID > Bed Temperature Control ====================== //=========================================================================== +// @section bed temp + +/** + * Max Bed Power + * Applies to all forms of bed control (PID, bang-bang, and bang-bang with hysteresis). + * When set to any value below 255, enables a form of PWM to the bed that acts like a divider + * so don't use it unless you are OK with PWM on your bed. (See the comment on enabling PIDTEMPBED) + */ +#define MAX_BED_POWER 255 // limits duty cycle to bed; 255=full current + /** * PID Bed Heating * - * If this option is enabled set PID constants below. - * If this option is disabled, bang-bang will be used and BED_LIMIT_SWITCHING will enable hysteresis. - * * The PID frequency will be the same as the extruder PWM. * If PID_dT is the default, and correct for the hardware/configuration, that means 7.689Hz, * which is fine for driving a square wave into a resistive load and does not significantly * impact FET heating. This also works fine on a Fotek SSR-10DA Solid State Relay into a 250W * heater. If your configuration is significantly different than this and you don't understand * the issues involved, don't use bed PID until someone else verifies that your hardware works. + * + * With this option disabled, bang-bang will be used. BED_LIMIT_SWITCHING enables hysteresis. */ //#define PIDTEMPBED -//#define BED_LIMIT_SWITCHING - -/** - * Max Bed Power - * Applies to all forms of bed control (PID, bang-bang, and bang-bang with hysteresis). - * When set to any value below 255, enables a form of PWM to the bed that acts like a divider - * so don't use it unless you are OK with PWM on your bed. (See the comment on enabling PIDTEMPBED) - */ -#define MAX_BED_POWER 255 // limits duty cycle to bed; 255=full current - #if ENABLED(PIDTEMPBED) //#define MIN_BED_POWER 0 - //#define PID_BED_DEBUG // Sends debug data to the serial port. + //#define PID_BED_DEBUG // Print Bed PID debug data to the serial port. // 120V 250W silicone heater into 4mm borosilicate (MendelMax 1.5+) // from FOPDT model - kp=.39 Tp=405 Tdead=66, Tc set to 79.2, aggressive factor of .15 (vs .1, 1, 10) @@ -646,7 +780,9 @@ #define DEFAULT_bedKd 305.4 // FIND YOUR OWN: "M303 E-1 C8 S90" to run autotune on the bed at 90 degreesC for 8 cycles. -#endif // PIDTEMPBED +#else + //#define BED_LIMIT_SWITCHING // Keep the bed temperature within BED_HYSTERESIS of the target +#endif //=========================================================================== //==================== PID > Chamber Temperature Control ==================== @@ -665,6 +801,7 @@ * impact FET heating. This also works fine on a Fotek SSR-10DA Solid State Relay into a 200W * heater. If your configuration is significantly different than this and you don't understand * the issues involved, don't use chamber PID until someone else verifies that your hardware works. + * @section chamber temp */ //#define PIDTEMPCHAMBER //#define CHAMBER_LIMIT_SWITCHING @@ -679,28 +816,32 @@ #if ENABLED(PIDTEMPCHAMBER) #define MIN_CHAMBER_POWER 0 - //#define PID_CHAMBER_DEBUG // Sends debug data to the serial port. + //#define PID_CHAMBER_DEBUG // Print Chamber PID debug data to the serial port. // Lasko "MyHeat Personal Heater" (200w) modified with a Fotek SSR-10DA to control only the heating element // and placed inside the small Creality printer enclosure tent. // - #define DEFAULT_chamberKp 37.04 - #define DEFAULT_chamberKi 1.40 + #define DEFAULT_chamberKp 37.04 + #define DEFAULT_chamberKi 1.40 #define DEFAULT_chamberKd 655.17 // M309 P37.04 I1.04 D655.17 // FIND YOUR OWN: "M303 E-2 C8 S50" to run autotune on the chamber at 50 degreesC for 8 cycles. #endif // PIDTEMPCHAMBER +// @section pid temp + #if ANY(PIDTEMP, PIDTEMPBED, PIDTEMPCHAMBER) - //#define PID_DEBUG // Sends debug data to the serial port. Use 'M303 D' to toggle activation. //#define PID_OPENLOOP // Puts PID in open loop. M104/M140 sets the output power from 0 to PID_MAX //#define SLOW_PWM_HEATERS // PWM with very low frequency (roughly 0.125Hz=8s) and minimum state time of approximately 1s useful for heaters driven by a relay #define PID_FUNCTIONAL_RANGE 10 // If the temperature difference between the target temperature and the actual temperature // is more than PID_FUNCTIONAL_RANGE then the PID will be shut off and the heater will be set to min/max. + + //#define PID_EDIT_MENU // Add PID editing to the "Advanced Settings" menu. (~700 bytes of flash) + //#define PID_AUTOTUNE_MENU // Add PID auto-tuning to the "Advanced Settings" menu. (~250 bytes of flash) #endif -// @section extruder +// @section safety /** * Prevent extrusion if the temperature is below EXTRUDE_MINTEMP. @@ -717,7 +858,7 @@ * Note: For Bowden Extruders make this large enough to allow load/unload. */ #define PREVENT_LENGTHY_EXTRUDE -#define EXTRUDE_MAXLENGTH 300 +#define EXTRUDE_MAXLENGTH 200 //=========================================================================== //======================== Thermal Runaway Protection ======================= @@ -745,7 +886,7 @@ //============================= Mechanical Settings ========================= //=========================================================================== -// @section machine +// @section kinematics // Enable one of the options below for CoreXY, CoreXZ, or CoreYZ kinematics, // either in the usual order or reversed @@ -755,7 +896,12 @@ //#define COREYX //#define COREZX //#define COREZY -//#define MARKFORGED_XY // MarkForged. See https://reprap.org/forum/read.php?152,504042 + +// +// MarkForged Kinematics +// See https://reprap.org/forum/read.php?152,504042 +// +//#define MARKFORGED_XY //#define MARKFORGED_YX // Enable for a belt style printer with endless "Z" motion @@ -764,15 +910,152 @@ // Enable for Polargraph Kinematics //#define POLARGRAPH #if ENABLED(POLARGRAPH) - #define POLARGRAPH_MAX_BELT_LEN 1035.0 - #define POLAR_SEGMENTS_PER_SECOND 5 + #define POLARGRAPH_MAX_BELT_LEN 1035.0 // (mm) Belt length at full extension. Override with M665 H. + #define DEFAULT_SEGMENTS_PER_SECOND 5 // Move segmentation based on duration +#endif + +// @section delta + +// Enable for DELTA kinematics and configure below +//#define DELTA +#if ENABLED(DELTA) + + // Make delta curves from many straight lines (linear interpolation). + // This is a trade-off between visible corners (not enough segments) + // and processor overload (too many expensive sqrt calls). + #define DEFAULT_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 + // Add three-point calibration to the MarlinUI menu. + // See http://minow.blogspot.com/index.html#4918805519571907051 + //#define DELTA_CALIBRATION_MENU + + // G33 Delta Auto-Calibration. Enable EEPROM_SETTINGS to store results. + //#define DELTA_AUTO_CALIBRATION + + #if ENABLED(DELTA_AUTO_CALIBRATION) + // Default number of probe points : n*n (1 -> 7) + #define DELTA_CALIBRATION_DEFAULT_POINTS 4 + #endif + + #if EITHER(DELTA_AUTO_CALIBRATION, DELTA_CALIBRATION_MENU) + // Step size for paper-test 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 } // (mm) 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 } // (mm) Get these values from G33 auto calibrate + + // Delta radius and diagonal rod adjustments + //#define DELTA_RADIUS_TRIM_TOWER { 0.0, 0.0, 0.0 } // (mm) + //#define DELTA_DIAGONAL_ROD_TRIM_TOWER { 0.0, 0.0, 0.0 } // (mm) +#endif + +// @section scara + +/** + * MORGAN_SCARA was developed by QHARLEY in South Africa in 2012-2013. + * Implemented and slightly reworked by JCERNY in June, 2014. + * + * Mostly Printed SCARA is an open source design by Tyler Williams. See: + * https://www.thingiverse.com/thing:2487048 + * https://www.thingiverse.com/thing:1241491 + */ +//#define MORGAN_SCARA +//#define MP_SCARA +#if EITHER(MORGAN_SCARA, MP_SCARA) + // If movement is choppy try lowering this value + #define DEFAULT_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 https://www.morgan3dp.com/morgan-calibration-guide/ + #define PSI_HOMING_OFFSET 0 // Calculated from Calibration Guide and M364 / M114. See https://www.morgan3dp.com/morgan-calibration-guide/ + + #elif ENABLED(MP_SCARA) + + #define SCARA_OFFSET_THETA1 12 // degrees + #define SCARA_OFFSET_THETA2 131 // degrees + + #endif + #endif +// @section tpara + +// Enable for TPARA kinematics and configure below +//#define AXEL_TPARA +#if ENABLED(AXEL_TPARA) + #define DEBUG_TPARA_KINEMATICS + #define DEFAULT_SEGMENTS_PER_SECOND 200 + + // Length of inner and outer support arms. Measure arm lengths precisely. + #define TPARA_LINKAGE_1 120 // (mm) + #define TPARA_LINKAGE_2 120 // (mm) + + // TPARA tower offset (position of Tower relative to bed zero position) + // This needs to be reasonably accurate as it defines the printbed position in the TPARA space. + #define TPARA_OFFSET_X 0 // (mm) + #define TPARA_OFFSET_Y 0 // (mm) + #define TPARA_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) +#endif + +// @section machine + +// Articulated robot (arm). Joints are directly mapped to axes with no kinematics. +//#define ARTICULATED_ROBOT_ARM + +// For a hot wire cutter with parallel horizontal axes (X, I) where the heights of the two wire +// ends are controlled by parallel axes (Y, J). Joints are directly mapped to axes (no kinematics). +//#define FOAMCUTTER_XYUV + //=========================================================================== //============================== Endstop Settings =========================== //=========================================================================== -// @section homing +// @section endstops // Specify here all the endstop connectors that are connected to any endstop or probe. // Almost all printers will be using one per axis. Probes will use one or more of the @@ -783,12 +1066,18 @@ //#define USE_IMIN_PLUG //#define USE_JMIN_PLUG //#define USE_KMIN_PLUG +//#define USE_UMIN_PLUG +//#define USE_VMIN_PLUG +//#define USE_WMIN_PLUG //#define USE_XMAX_PLUG //#define USE_YMAX_PLUG -#define USE_ZMAX_PLUG +//#define USE_ZMAX_PLUG //#define USE_IMAX_PLUG //#define USE_JMAX_PLUG //#define USE_KMAX_PLUG +//#define USE_UMAX_PLUG +//#define USE_VMAX_PLUG +//#define USE_WMAX_PLUG // Enable pullup for all endstops to prevent a floating state #define ENDSTOPPULLUPS @@ -800,12 +1089,18 @@ //#define ENDSTOPPULLUP_IMIN //#define ENDSTOPPULLUP_JMIN //#define ENDSTOPPULLUP_KMIN + //#define ENDSTOPPULLUP_UMIN + //#define ENDSTOPPULLUP_VMIN + //#define ENDSTOPPULLUP_WMIN //#define ENDSTOPPULLUP_XMAX //#define ENDSTOPPULLUP_YMAX //#define ENDSTOPPULLUP_ZMAX //#define ENDSTOPPULLUP_IMAX //#define ENDSTOPPULLUP_JMAX //#define ENDSTOPPULLUP_KMAX + //#define ENDSTOPPULLUP_UMAX + //#define ENDSTOPPULLUP_VMAX + //#define ENDSTOPPULLUP_WMAX //#define ENDSTOPPULLUP_ZMIN_PROBE #endif @@ -819,12 +1114,18 @@ //#define ENDSTOPPULLDOWN_IMIN //#define ENDSTOPPULLDOWN_JMIN //#define ENDSTOPPULLDOWN_KMIN + //#define ENDSTOPPULLDOWN_UMIN + //#define ENDSTOPPULLDOWN_VMIN + //#define ENDSTOPPULLDOWN_WMIN //#define ENDSTOPPULLDOWN_XMAX //#define ENDSTOPPULLDOWN_YMAX //#define ENDSTOPPULLDOWN_ZMAX //#define ENDSTOPPULLDOWN_IMAX //#define ENDSTOPPULLDOWN_JMAX //#define ENDSTOPPULLDOWN_KMAX + //#define ENDSTOPPULLDOWN_UMAX + //#define ENDSTOPPULLDOWN_VMAX + //#define ENDSTOPPULLDOWN_WMAX //#define ENDSTOPPULLDOWN_ZMIN_PROBE #endif @@ -835,52 +1136,20 @@ #define I_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define J_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define K_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. +#define U_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. +#define V_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. +#define W_MIN_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define X_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define Y_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. -#define Z_MAX_ENDSTOP_INVERTING true // Set to true to invert the logic of the endstop. +#define Z_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define I_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define J_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define K_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. +#define U_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. +#define V_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. +#define W_MAX_ENDSTOP_INVERTING false // Set to true to invert the logic of the endstop. #define Z_MIN_PROBE_ENDSTOP_INVERTING true // Set to true to invert the logic of the probe. -/** - * Stepper Drivers - * - * These settings allow Marlin to tune stepper driver timing and enable advanced options for - * stepper drivers that support them. You may also override timing options in Configuration_adv.h. - * - * A4988 is assumed for unspecified drivers. - * - * Use TMC2208/TMC2208_STANDALONE for TMC2225 drivers and TMC2209/TMC2209_STANDALONE for TMC2226 drivers. - * - * Options: A4988, A5984, DRV8825, LV8729, L6470, L6474, POWERSTEP01, - * TB6560, TB6600, TMC2100, - * TMC2130, TMC2130_STANDALONE, TMC2160, TMC2160_STANDALONE, - * TMC2208, TMC2208_STANDALONE, TMC2209, TMC2209_STANDALONE, - * TMC26X, TMC26X_STANDALONE, TMC2660, TMC2660_STANDALONE, - * TMC5130, TMC5130_STANDALONE, TMC5160, TMC5160_STANDALONE - * :['A4988', 'A5984', 'DRV8825', 'LV8729', 'L6470', 'L6474', 'POWERSTEP01', 'TB6560', 'TB6600', 'TMC2100', 'TMC2130', 'TMC2130_STANDALONE', 'TMC2160', 'TMC2160_STANDALONE', 'TMC2208', 'TMC2208_STANDALONE', 'TMC2209', 'TMC2209_STANDALONE', 'TMC26X', 'TMC26X_STANDALONE', 'TMC2660', 'TMC2660_STANDALONE', 'TMC5130', 'TMC5130_STANDALONE', 'TMC5160', 'TMC5160_STANDALONE'] - */ -#define X_DRIVER_TYPE A4988 -#define Y_DRIVER_TYPE A4988 -#define Z_DRIVER_TYPE A4988 -//#define X2_DRIVER_TYPE A4988 -//#define Y2_DRIVER_TYPE A4988 -//#define Z2_DRIVER_TYPE A4988 -//#define Z3_DRIVER_TYPE A4988 -//#define Z4_DRIVER_TYPE A4988 -//#define I_DRIVER_TYPE A4988 -//#define J_DRIVER_TYPE A4988 -//#define K_DRIVER_TYPE A4988 -#define E0_DRIVER_TYPE DRV8825 -//#define E1_DRIVER_TYPE A4988 -//#define E2_DRIVER_TYPE A4988 -//#define E3_DRIVER_TYPE A4988 -//#define E4_DRIVER_TYPE A4988 -//#define E5_DRIVER_TYPE A4988 -//#define E6_DRIVER_TYPE A4988 -//#define E7_DRIVER_TYPE A4988 - // Enable this feature if all enabled endstop pins are interrupt-capable. // This will remove the need to poll the interrupt pins, saving many CPU cycles. //#define ENDSTOP_INTERRUPTS_FEATURE @@ -923,18 +1192,18 @@ //#define DISTINCT_E_FACTORS /** - * Default Axis Steps Per Unit (steps/mm) + * Default Axis Steps Per Unit (linear=steps/mm, rotational=steps/°) * Override with M92 - * X, Y, Z [, I [, J [, K]]], E0 [, E1[, E2...]] + * X, Y, Z [, I [, J [, K...]]], E0 [, E1[, E2...]] */ #define DEFAULT_AXIS_STEPS_PER_UNIT { 400, 400, 400, 98 } /** - * Default Max Feed Rate (mm/s) + * Default Max Feed Rate (linear=mm/s, rotational=°/s) * Override with M203 - * X, Y, Z [, I [, J [, K]]], E0 [, E1[, E2...]] + * X, Y, Z [, I [, J [, K...]]], E0 [, E1[, E2...]] */ -#define DEFAULT_MAX_FEEDRATE { 2000, 2000, 400, 150 } +#define DEFAULT_MAX_FEEDRATE { 300, 300, 5, 25 } //#define LIMITED_MAX_FR_EDITING // Limit edit via M203 or LCD to DEFAULT_MAX_FEEDRATE * 2 #if ENABLED(LIMITED_MAX_FR_EDITING) @@ -942,12 +1211,12 @@ #endif /** - * Default Max Acceleration (change/s) change = mm/s + * Default Max Acceleration (speed change with time) (linear=mm/(s^2), rotational=°/(s^2)) * (Maximum start speed for accelerated moves) * Override with M201 - * X, Y, Z [, I [, J [, K]]], E0 [, E1[, E2...]] + * X, Y, Z [, I [, J [, K...]]], E0 [, E1[, E2...]] */ -#define DEFAULT_MAX_ACCELERATION { 100, 100, 50, 10000 } +#define DEFAULT_MAX_ACCELERATION { 100, 50, 25, 10000 } //#define LIMITED_MAX_ACCEL_EDITING // Limit edit via M201 or LCD to DEFAULT_MAX_ACCELERATION * 2 #if ENABLED(LIMITED_MAX_ACCEL_EDITING) @@ -955,20 +1224,20 @@ #endif /** - * Default Acceleration (change/s) change = mm/s + * Default Acceleration (speed change with time) (linear=mm/(s^2), rotational=°/(s^2)) * Override with M204 * * M204 P Acceleration * M204 R Retract Acceleration * M204 T Travel Acceleration */ -#define DEFAULT_ACCELERATION 300 // X, Y, Z and E acceleration for printing moves +#define DEFAULT_ACCELERATION 50 // X, Y, Z and E acceleration for printing moves #define DEFAULT_RETRACT_ACCELERATION 3000 // E acceleration for retracts -#define DEFAULT_TRAVEL_ACCELERATION 400 // X, Y, Z acceleration for travel (non printing) moves +#define DEFAULT_TRAVEL_ACCELERATION 50 // X, Y, Z acceleration for travel (non printing) moves /** * Default Jerk limits (mm/s) - * Override with M205 X Y Z E + * Override with M205 X Y Z . . . E * * "Jerk" specifies the minimum speed change that requires acceleration. * When changing speed and direction, if the difference is less than the @@ -976,12 +1245,15 @@ */ //#define CLASSIC_JERK #if ENABLED(CLASSIC_JERK) - #define DEFAULT_XJERK 1.5 - #define DEFAULT_YJERK 1.5 + #define DEFAULT_XJERK 10.0 + #define DEFAULT_YJERK 10.0 #define DEFAULT_ZJERK 0.3 //#define DEFAULT_IJERK 0.3 //#define DEFAULT_JJERK 0.3 //#define DEFAULT_KJERK 0.3 + //#define DEFAULT_UJERK 0.3 + //#define DEFAULT_VJERK 0.3 + //#define DEFAULT_WJERK 0.3 //#define TRAVEL_EXTRA_XYJERK 0.0 // Additional jerk allowance for all travel moves @@ -991,7 +1263,7 @@ #endif #endif -#define DEFAULT_EJERK 2.5 // May be used by Linear Advance +#define DEFAULT_EJERK 5.0 // May be used by Linear Advance /** * Junction Deviation Factor @@ -1038,19 +1310,17 @@ /** * Z_MIN_PROBE_PIN * - * Define this pin if the probe is not connected to Z_MIN_PIN. - * If not defined the default pin for the selected MOTHERBOARD - * will be used. Most of the time the default is what you want. + * Override this pin only if the probe cannot be connected to + * the default Z_MIN_PROBE_PIN for the selected MOTHERBOARD. * * - The simplest option is to use a free endstop connector. * - Use 5V for powered (usually inductive) sensors. * - * - RAMPS 1.3/1.4 boards may use the 5V, GND, and Aux4->D32 pin: - * - For simple switches connect... - * - normally-closed switches to GND and D32. - * - normally-open switches to 5V and D32. + * - For simple switches... + * - Normally-closed (NC) also connect to GND. + * - Normally-open (NO) also connect to 5V. */ -//#define Z_MIN_PROBE_PIN 32 // Pin 32 is the RAMPS default +//#define Z_MIN_PROBE_PIN -1 /** * Probe Type @@ -1081,14 +1351,27 @@ /** * Z Servo Probe, such as an endstop switch on a rotating arm. */ -//#define Z_PROBE_SERVO_NR 0 // Defaults to SERVO 0 connector. -//#define Z_SERVO_ANGLES { 70, 0 } // Z Servo Deploy and Stow angles +//#define Z_PROBE_SERVO_NR 0 +#ifdef Z_PROBE_SERVO_NR + //#define Z_SERVO_ANGLES { 70, 0 } // Z Servo Deploy and Stow angles +#endif /** * The BLTouch probe uses a Hall effect sensor and emulates a servo. */ //#define BLTOUCH +/** + * MagLev V4 probe by MDD + * + * This probe is deployed and activated by powering a built-in electromagnet. + */ +//#define MAGLEV4 +#if ENABLED(MAGLEV4) + //#define MAGLEV_TRIGGER_PIN 11 // Set to the connected digital output + #define MAGLEV_TRIGGER_DELAY 15 // Changing this risks overheating the coil +#endif + /** * Touch-MI Probe by hotends.fr * @@ -1120,7 +1403,28 @@ #define Z_PROBE_RETRACT_X X_MAX_POS #endif -// Duet Smart Effector (for delta printers) - https://bit.ly/2ul5U7J +/** + * Magnetically Mounted Probe + * For probes such as Euclid, Klicky, Klackender, etc. + */ +//#define MAG_MOUNTED_PROBE +#if ENABLED(MAG_MOUNTED_PROBE) + #define PROBE_DEPLOY_FEEDRATE (133*60) // (mm/min) Probe deploy speed + #define PROBE_STOW_FEEDRATE (133*60) // (mm/min) Probe stow speed + + #define MAG_MOUNTED_DEPLOY_1 { PROBE_DEPLOY_FEEDRATE, { 245, 114, 30 } } // Move to side Dock & Attach probe + #define MAG_MOUNTED_DEPLOY_2 { PROBE_DEPLOY_FEEDRATE, { 210, 114, 30 } } // Move probe off dock + #define MAG_MOUNTED_DEPLOY_3 { PROBE_DEPLOY_FEEDRATE, { 0, 0, 0 } } // Extra move if needed + #define MAG_MOUNTED_DEPLOY_4 { PROBE_DEPLOY_FEEDRATE, { 0, 0, 0 } } // Extra move if needed + #define MAG_MOUNTED_DEPLOY_5 { PROBE_DEPLOY_FEEDRATE, { 0, 0, 0 } } // Extra move if needed + #define MAG_MOUNTED_STOW_1 { PROBE_STOW_FEEDRATE, { 245, 114, 20 } } // Move to dock + #define MAG_MOUNTED_STOW_2 { PROBE_STOW_FEEDRATE, { 245, 114, 0 } } // Place probe beside remover + #define MAG_MOUNTED_STOW_3 { PROBE_STOW_FEEDRATE, { 230, 114, 0 } } // Side move to remove probe + #define MAG_MOUNTED_STOW_4 { PROBE_STOW_FEEDRATE, { 210, 114, 20 } } // Side move to remove probe + #define MAG_MOUNTED_STOW_5 { PROBE_STOW_FEEDRATE, { 0, 0, 0 } } // Extra move if needed +#endif + +// Duet Smart Effector (for delta printers) - https://docs.duet3d.com/en/Duet3D_hardware/Accessories/Smart_Effector // When the pin is defined you can use M672 to set/reset the probe sensitivity. //#define DUET_SMART_EFFECTOR #if ENABLED(DUET_SMART_EFFECTOR) @@ -1135,9 +1439,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#Autolevel_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 } @@ -1155,7 +1487,7 @@ * * Tune and Adjust * - Probe Offsets can be tuned at runtime with 'M851', LCD menus, babystepping, etc. - * - PROBE_OFFSET_WIZARD (configuration_adv.h) can be used for setting the Z offset. + * - PROBE_OFFSET_WIZARD (Configuration_adv.h) can be used for setting the Z offset. * * Assuming the typical work area orientation: * - Probe to RIGHT of the Nozzle has a Positive X offset @@ -1189,7 +1521,7 @@ #define XY_PROBE_FEEDRATE (18*60) // Feedrate (mm/min) for the first approach when double-probing (MULTIPLE_PROBING == 2) -#define Z_PROBE_FEEDRATE_FAST (6*60) +#define Z_PROBE_FEEDRATE_FAST (4*60) // Feedrate (mm/min) for the "accurate" probe of each point #define Z_PROBE_FEEDRATE_SLOW (Z_PROBE_FEEDRATE_FAST / 2) @@ -1253,13 +1585,13 @@ * probe Z Offset set with NOZZLE_TO_PROBE_OFFSET, M851, or the LCD. * Only integer values >= 1 are valid here. * - * Example: `M851 Z-5` with a CLEARANCE of 4 => 9mm from bed to nozzle. - * But: `M851 Z+1` with a CLEARANCE of 2 => 2mm from bed to nozzle. + * Example: 'M851 Z-5' with a CLEARANCE of 4 => 9mm from bed to nozzle. + * But: 'M851 Z+1' with a CLEARANCE of 2 => 2mm from bed to nozzle. */ -#define Z_CLEARANCE_DEPLOY_PROBE 10 // Z Clearance for Deploy/Stow -#define Z_CLEARANCE_BETWEEN_PROBES 5 // Z Clearance between probe points -#define Z_CLEARANCE_MULTI_PROBE 5 // Z Clearance between multiple probes -//#define Z_AFTER_PROBING 5 // Z position after probing is done +#define Z_CLEARANCE_DEPLOY_PROBE 10 // (mm) Z Clearance for Deploy/Stow +#define Z_CLEARANCE_BETWEEN_PROBES 5 // (mm) Z Clearance between probe points +#define Z_CLEARANCE_MULTI_PROBE 5 // (mm) Z Clearance between multiple probes +//#define Z_AFTER_PROBING 5 // (mm) Z position after probing is done #define Z_PROBE_LOW_POINT -4 // Farthest distance below the trigger-point to go before stopping @@ -1300,6 +1632,8 @@ #define PROBING_BED_TEMP 50 #endif +// @section stepper drivers + // For Inverting Stepper Enable Pins (Active Low) use 0, Non Inverting (Active High) use 1 // :{ 0:'Low', 1:'High' } #define X_ENABLE_ON 0 @@ -1309,25 +1643,31 @@ //#define I_ENABLE_ON 0 //#define J_ENABLE_ON 0 //#define K_ENABLE_ON 0 +//#define U_ENABLE_ON 0 +//#define V_ENABLE_ON 0 +//#define W_ENABLE_ON 0 // Disable axis steppers immediately when they're not being stepped. // WARNING: When motors turn off there is a chance of losing position accuracy! -#define DISABLE_X false -#define DISABLE_Y false -#define DISABLE_Z false -//#define DISABLE_I false -//#define DISABLE_J false -//#define DISABLE_K false +//#define DISABLE_X +//#define DISABLE_Y +//#define DISABLE_Z +//#define DISABLE_I +//#define DISABLE_J +//#define DISABLE_K +//#define DISABLE_U +//#define DISABLE_V +//#define DISABLE_W // Turn off the display blinking that warns about possible accuracy reduction //#define DISABLE_REDUCED_ACCURACY_WARNING // @section extruder -#define DISABLE_E false // Disable the extruder when not stepping -#define DISABLE_INACTIVE_EXTRUDER // Keep only the active extruder enabled +//#define DISABLE_E // Disable the extruder when not stepping +#define DISABLE_OTHER_EXTRUDERS // Keep only the active extruder enabled -// @section machine +// @section motion // Invert the stepper direction. Change (or reverse the motor connector) if an axis goes the wrong way. #define INVERT_X_DIR false @@ -1336,6 +1676,9 @@ //#define INVERT_I_DIR false //#define INVERT_J_DIR false //#define INVERT_K_DIR false +//#define INVERT_U_DIR false +//#define INVERT_V_DIR false +//#define INVERT_W_DIR false // @section extruder @@ -1374,14 +1717,17 @@ //#define I_HOME_DIR -1 //#define J_HOME_DIR -1 //#define K_HOME_DIR -1 +//#define U_HOME_DIR -1 +//#define V_HOME_DIR -1 +//#define W_HOME_DIR -1 -// @section machine +// @section geometry // The size of the printable area #define X_BED_SIZE 230 #define Y_BED_SIZE 230 -// Travel limits (mm) after homing, corresponding to endstop positions. +// Travel limits (linear=mm, rotational=°) after homing, corresponding to endstop positions. #define X_MIN_POS 0 #define Y_MIN_POS 0 #define Z_MIN_POS 0 @@ -1394,6 +1740,12 @@ //#define J_MAX_POS 50 //#define K_MIN_POS 0 //#define K_MAX_POS 50 +//#define U_MIN_POS 0 +//#define U_MAX_POS 50 +//#define V_MIN_POS 0 +//#define V_MAX_POS 50 +//#define W_MIN_POS 0 +//#define W_MAX_POS 50 /** * Software Endstops @@ -1413,6 +1765,9 @@ #define MIN_SOFTWARE_ENDSTOP_I #define MIN_SOFTWARE_ENDSTOP_J #define MIN_SOFTWARE_ENDSTOP_K + #define MIN_SOFTWARE_ENDSTOP_U + #define MIN_SOFTWARE_ENDSTOP_V + #define MIN_SOFTWARE_ENDSTOP_W #endif // Max software endstops constrain movement within maximum coordinate bounds @@ -1424,6 +1779,9 @@ #define MAX_SOFTWARE_ENDSTOP_I #define MAX_SOFTWARE_ENDSTOP_J #define MAX_SOFTWARE_ENDSTOP_K + #define MAX_SOFTWARE_ENDSTOP_U + #define MAX_SOFTWARE_ENDSTOP_V + #define MAX_SOFTWARE_ENDSTOP_W #endif #if EITHER(MIN_SOFTWARE_ENDSTOPS, MAX_SOFTWARE_ENDSTOPS) @@ -1431,6 +1789,8 @@ #endif /** + * @section filament runout sensors + * * Filament Runout Sensors * Mechanical or opto endstops are used to check for the presence of filament. * @@ -1549,6 +1909,12 @@ //#define AUTO_BED_LEVELING_UBL //#define MESH_BED_LEVELING +/** + * Commands to execute at the end of G29 probing. + * Useful to retract or move the Z probe out of the way. + */ +//#define Z_PROBE_END_SCRIPT "G1 Z10 F12000\nG1 X15 Y330\nG1 Z0.5\nG1 Z10" + /** * Normally G28 leaves leveling disabled on completion. Enable one of * these options to restore the prior leveling state or to always enable @@ -1566,10 +1932,19 @@ #define LEVELING_BED_TEMP 50 #endif +/** + * Bed Distance Sensor + * + * Measures the distance from bed to nozzle with accuracy of 0.01mm. + * For information about this sensor https://github.com/markniu/Bed_Distance_sensor + * Uses I2C port, so it requires I2C library markyue/Panda_SoftMasterI2C. + */ +//#define BD_SENSOR + /** * Enable detailed logging of G28, G29, M48, etc. * Turn on with the command 'M111 S32'. - * NOTE: Requires a lot of PROGMEM! + * NOTE: Requires a lot of flash! */ //#define DEBUG_LEVELING_FEATURE @@ -1579,17 +1954,21 @@ #endif #if ANY(MESH_BED_LEVELING, AUTO_BED_LEVELING_BILINEAR, AUTO_BED_LEVELING_UBL) - // Gradually reduce leveling correction until a set height is reached, - // at which point movement will be level to the machine's XY plane. - // The height can be set with M420 Z + /** + * Gradually reduce leveling correction until a set height is reached, + * at which point movement will be level to the machine's XY plane. + * The height can be set with M420 Z + */ #define ENABLE_LEVELING_FADE_HEIGHT #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) #define DEFAULT_LEVELING_FADE_HEIGHT 10.0 // (mm) Default fade height. #endif - // For Cartesian machines, instead of dividing moves on mesh boundaries, - // split up moves into short segments like a Delta. This follows the - // contours of the bed more closely than edge-to-edge straight moves. + /** + * For Cartesian machines, instead of dividing moves on mesh boundaries, + * split up moves into short segments like a Delta. This follows the + * contours of the bed more closely than edge-to-edge straight moves. + */ #define SEGMENT_LEVELED_MOVES #define LEVELED_SEGMENT_LENGTH 5.0 // (mm) Length of all segments (except the last one) @@ -1603,7 +1982,7 @@ #define MESH_TEST_HOTEND_TEMP 205 // (°C) Default nozzle temperature for G26. #define MESH_TEST_BED_TEMP 60 // (°C) Default bed temperature for G26. #define G26_XY_FEEDRATE 20 // (mm/s) Feedrate for G26 XY moves. - #define G26_XY_FEEDRATE_TRAVEL 30 // (mm/s) Feedrate for G26 XY travel moves. + #define G26_XY_FEEDRATE_TRAVEL 100 // (mm/s) Feedrate for G26 XY travel moves. #define G26_RETRACT_MULTIPLIER 1.0 // G26 Q (retraction) used by default between mesh test elements. #endif @@ -1625,7 +2004,7 @@ //#define EXTRAPOLATE_BEYOND_GRID // - // Experimental Subdivision of the grid by Catmull-Rom method. + // Subdivision of the grid by Catmull-Rom method. // Synthesizes intermediate points to produce a more detailed mesh. // //#define ABL_BILINEAR_SUBDIVISION @@ -1685,18 +2064,18 @@ #endif // Add a menu item to move between bed corners for manual bed adjustment -//#define LEVEL_BED_CORNERS - -#if ENABLED(LEVEL_BED_CORNERS) - #define LEVEL_CORNERS_INSET_LFRB { 30, 30, 30, 30 } // (mm) Left, Front, Right, Back insets - #define LEVEL_CORNERS_HEIGHT 0.0 // (mm) Z height of nozzle at leveling points - #define LEVEL_CORNERS_Z_HOP 4.0 // (mm) Z height of nozzle between leveling points - //#define LEVEL_CENTER_TOO // Move to the center after the last corner - //#define LEVEL_CORNERS_USE_PROBE - #if ENABLED(LEVEL_CORNERS_USE_PROBE) - #define LEVEL_CORNERS_PROBE_TOLERANCE 0.1 - #define LEVEL_CORNERS_VERIFY_RAISED // After adjustment triggers the probe, re-probe to verify - //#define LEVEL_CORNERS_AUDIO_FEEDBACK +//#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_HEIGHT 0.0 // (mm) Z height of nozzle at tramming points + #define BED_TRAMMING_Z_HOP 4.0 // (mm) Z raise between tramming points + //#define BED_TRAMMING_INCLUDE_CENTER // Move to the center after the last corner + //#define BED_TRAMMING_USE_PROBE + #if ENABLED(BED_TRAMMING_USE_PROBE) + #define BED_TRAMMING_PROBE_TOLERANCE 0.1 // (mm) + #define BED_TRAMMING_VERIFY_RAISED // After adjustment triggers the probe, re-probe to verify + //#define BED_TRAMMING_AUDIO_FEEDBACK #endif /** @@ -1716,15 +2095,9 @@ * | 1 2 | | 1 4 | | 1 2 | | 2 | * LF --------- RF LF --------- RF LF --------- RF LF --------- RF */ - #define LEVEL_CORNERS_LEVELING_ORDER { LF, RF, RB, LB } + #define BED_TRAMMING_LEVELING_ORDER { LF, RF, RB, LB } #endif -/** - * Commands to execute at the end of G29 probing. - * Useful to retract or move the Z probe out of the way. - */ -//#define Z_PROBE_END_SCRIPT "G1 Z10 F12000\nG1 X15 Y330\nG1 Z0.5\nG1 Z10" - // @section homing // The center of the bed is at (X=0, Y=0) @@ -1738,6 +2111,9 @@ //#define MANUAL_I_HOME_POS 0 //#define MANUAL_J_HOME_POS 0 //#define MANUAL_K_HOME_POS 0 +//#define MANUAL_U_HOME_POS 0 +//#define MANUAL_V_HOME_POS 0 +//#define MANUAL_W_HOME_POS 0 /** * Use "Z Safe Homing" to avoid homing with a Z probe outside the bed area. @@ -1749,12 +2125,12 @@ #define Z_SAFE_HOMING #if ENABLED(Z_SAFE_HOMING) - #define Z_SAFE_HOMING_X_POINT ((X_BED_SIZE) / 2) // X point for Z homing - #define Z_SAFE_HOMING_Y_POINT ((Y_BED_SIZE) / 2) // Y point for Z homing + #define Z_SAFE_HOMING_X_POINT X_CENTER // (mm) X point for Z homing + #define Z_SAFE_HOMING_Y_POINT Y_CENTER // (mm) Y point for Z homing #endif -// Homing speeds (mm/min) -#define HOMING_FEEDRATE_MM_M { (15*60), (15*60), (5*60) } +// Homing speeds (linear=mm/min, rotational=°/min) +#define HOMING_FEEDRATE_MM_M { (15*60), (15*60), (4*60) } // Validate that endstops are triggered on homing moves #define VALIDATE_HOMING_ENDSTOPS @@ -1797,9 +2173,8 @@ #define XY_DIAG_BD 282.8427124746 #define XY_SIDE_AD 200 - // Or, set the default skew factors directly here - // to override the above measurements: - #define XY_SKEW_FACTOR 0.0 + // Or, set the XY skew factor directly: + //#define XY_SKEW_FACTOR 0.0 //#define SKEW_CORRECTION_FOR_Z #if ENABLED(SKEW_CORRECTION_FOR_Z) @@ -1808,8 +2183,10 @@ #define YZ_DIAG_AC 282.8427124746 #define YZ_DIAG_BD 282.8427124746 #define YZ_SIDE_AD 200 - #define XZ_SKEW_FACTOR 0.0 - #define YZ_SKEW_FACTOR 0.0 + + // Or, set the Z skew factors directly: + //#define XZ_SKEW_FACTOR 0.0 + //#define YZ_SKEW_FACTOR 0.0 #endif // Enable this option for M852 to set skew at runtime @@ -1820,7 +2197,7 @@ //============================= Additional Features =========================== //============================================================================= -// @section extras +// @section eeprom /** * EEPROM @@ -1832,14 +2209,16 @@ * M502 - Revert settings to "factory" defaults. (Follow with M500 to init the EEPROM.) */ #define EEPROM_SETTINGS // Persistent storage with M500 and M501 -//#define DISABLE_M503 // Saves ~2700 bytes of PROGMEM. Disable for release! -#define EEPROM_CHITCHAT // Give feedback on EEPROM commands. Disable to save PROGMEM. +//#define DISABLE_M503 // Saves ~2700 bytes of flash. Disable for release! +#define EEPROM_CHITCHAT // Give feedback on EEPROM commands. Disable to save flash. #define EEPROM_BOOT_SILENT // Keep M503 quiet and only give errors during first load #if ENABLED(EEPROM_SETTINGS) //#define EEPROM_AUTO_INIT // Init EEPROM automatically on any errors. //#define EEPROM_INIT_NOW // Init EEPROM on first boot after a new build. #endif +// @section host + // // Host Keepalive // @@ -1850,6 +2229,8 @@ #define DEFAULT_KEEPALIVE_INTERVAL 2 // Number of seconds between "busy" messages. Set with M113. #define BUSY_WHILE_HEATING // Some hosts require "busy" messages even during heating +// @section units + // // G20/G21 Inch mode support // @@ -1863,7 +2244,7 @@ // @section temperature // -// Preheat Constants - Up to 5 are supported without changes +// Preheat Constants - Up to 10 are supported without changes // #define PREHEAT_1_LABEL "PLA" #define PREHEAT_1_TEMP_HOTEND 180 @@ -1872,12 +2253,14 @@ #define PREHEAT_1_FAN_SPEED 0 // Value from 0 to 255 #define PREHEAT_2_LABEL "ABS" -#define PREHEAT_2_TEMP_HOTEND 220 -#define PREHEAT_2_TEMP_BED 70 +#define PREHEAT_2_TEMP_HOTEND 240 +#define PREHEAT_2_TEMP_BED 110 #define PREHEAT_2_TEMP_CHAMBER 35 #define PREHEAT_2_FAN_SPEED 0 // Value from 0 to 255 /** + * @section nozzle park + * * Nozzle Park * * Park the nozzle at the given XYZ position on idle or G27. @@ -1893,15 +2276,16 @@ #if ENABLED(NOZZLE_PARK_FEATURE) // Specify a park position as { X, Y, Z_raise } #define NOZZLE_PARK_POINT { (X_MIN_POS + 10), (Y_MAX_POS - 10), 20 } - //#define NOZZLE_PARK_X_ONLY // X move only is required to park - //#define NOZZLE_PARK_Y_ONLY // Y move only is required to park + #define NOZZLE_PARK_MOVE 0 // Park motion: 0 = XY Move, 1 = X Only, 2 = Y Only, 3 = X before Y, 4 = Y before X #define NOZZLE_PARK_Z_RAISE_MIN 2 // (mm) Always raise Z by at least this distance #define NOZZLE_PARK_XY_FEEDRATE 100 // (mm/s) X and Y axes feedrate (also used for delta Z axis) #define NOZZLE_PARK_Z_FEEDRATE 5 // (mm/s) Z axis feedrate (not used for delta printers) #endif /** - * Clean Nozzle Feature -- EXPERIMENTAL + * @section nozzle clean + * + * Clean Nozzle Feature * * Adds the G12 command to perform a nozzle cleaning process. * @@ -1935,7 +2319,6 @@ * Before starting, the nozzle moves to NOZZLE_CLEAN_START_POINT. * * Caveats: The ending Z should be the same as starting Z. - * Attention: EXPERIMENTAL. G-code arguments may change. */ //#define NOZZLE_CLEAN_FEATURE @@ -1976,6 +2359,8 @@ #endif +// @section host + /** * Print Job Timer * @@ -2002,6 +2387,8 @@ */ #define PRINTJOB_TIMER_AUTOSTART +// @section stats + /** * Print Counter * @@ -2016,9 +2403,11 @@ */ //#define PRINTCOUNTER #if ENABLED(PRINTCOUNTER) - #define PRINTCOUNTER_SAVE_INTERVAL 60 // (minutes) EEPROM save interval during print + #define PRINTCOUNTER_SAVE_INTERVAL 60 // (minutes) EEPROM save interval during print. A value of 0 will save stats at end of print. #endif +// @section security + /** * Password * @@ -2044,7 +2433,7 @@ #define PASSWORD_ON_STARTUP #define PASSWORD_UNLOCK_GCODE // Unlock with the M511 P command. Disable to prevent brute-force attack. #define PASSWORD_CHANGE_GCODE // Change the password with M512 P S. - //#define PASSWORD_ON_SD_PRINT_MENU // This does not prevent gcodes from running + //#define PASSWORD_ON_SD_PRINT_MENU // This does not prevent G-codes from running //#define PASSWORD_AFTER_SD_PRINT_END //#define PASSWORD_AFTER_SD_PRINT_ABORT //#include "Configuration_Secure.h" // External file with PASSWORD_DEFAULT_VALUE @@ -2054,7 +2443,7 @@ //============================= LCD and SD support ============================ //============================================================================= -// @section lcd +// @section interface /** * LCD LANGUAGE @@ -2170,6 +2559,16 @@ // //#define REVERSE_SELECT_DIRECTION +// +// Encoder EMI Noise Filter +// +// This option increases encoder samples to filter out phantom encoder clicks caused by EMI noise. +// +//#define ENCODER_NOISE_FILTER +#if ENABLED(ENCODER_NOISE_FILTER) + #define ENCODER_SAMPLES 10 +#endif + // // Individual Axis Homing // @@ -2200,6 +2599,7 @@ //======================== LCD / Controller Selection ========================= //======================== (Character-based LCDs) ========================= //============================================================================= +// @section lcd // // RepRapDiscount Smart Controller. @@ -2219,7 +2619,7 @@ // // Original RADDS LCD Display+Encoder+SDCardReader -// http://doku.radds.org/dokumentation/lcd-display/ +// https://web.archive.org/web/20200719145306/doku.radds.org/dokumentation/lcd-display/ // //#define RADDS_DISPLAY @@ -2249,7 +2649,6 @@ // // RigidBot Panel V1.0 -// http://www.inventapart.com/ // //#define RIGIDBOT_PANEL @@ -2286,15 +2685,16 @@ // // Elefu RA Board Control Panel -// http://www.elefu.com/index.php?route=product/product&product_id=53 +// https://web.archive.org/web/20140823033947/www.elefu.com/index.php?route=product/product&product_id=53 // //#define RA_CONTROL_PANEL // // Sainsmart (YwRobot) LCD Displays // -// These require F.Malpartida's LiquidCrystal_I2C library -// https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home +// These require LiquidCrystal_I2C library: +// https://github.com/MarlinFirmware/New-LiquidCrystal +// https://github.com/fmalpartida/New-LiquidCrystal/wiki // //#define LCD_SAINSMART_I2C_1602 //#define LCD_SAINSMART_I2C_2004 @@ -2327,7 +2727,7 @@ // // -// 2-wire Non-latching LCD SR from https://goo.gl/aJJ4sH +// 2-wire Non-latching LCD SR from https://github.com/fmalpartida/New-LiquidCrystal/wiki/schematics#user-content-ShiftRegister_connection // LCD configuration: https://reprap.org/wiki/SAV_3D_LCD // //#define SAV_3DLCD @@ -2374,7 +2774,7 @@ // // ReprapWorld Graphical LCD -// https://reprapworld.com/?products_details&products_id/1218 +// https://reprapworld.com/electronics/3d-printer-modules/autonomous-printing/graphical-lcd-screen-v1-0/ // //#define REPRAPWORLD_GRAPHICAL_LCD @@ -2399,7 +2799,7 @@ // // MaKr3d Makr-Panel with graphic controller and SD support. -// https://reprap.org/wiki/MaKr3d_MaKrPanel +// https://reprap.org/wiki/MaKrPanel // //#define MAKRPANEL @@ -2417,7 +2817,7 @@ // // Cartesio UI -// http://mauk.cc/webshop/cartesio-shop/electronics/user-interface +// https://web.archive.org/web/20180605050442/mauk.cc/webshop/cartesio-shop/electronics/user-interface // //#define CARTESIO_UI @@ -2461,16 +2861,16 @@ //#define FYSETC_GENERIC_12864_1_1 // Larger display with basic ON/OFF backlight. // -// BigTreeTech Mini 12864 V1.0 is an alias for FYSETC_MINI_12864_2_1. Type A/B. NeoPixel RGB Backlight. +// BigTreeTech Mini 12864 V1.0 / V2.0 is an alias for FYSETC_MINI_12864_2_1. Type A/B. NeoPixel RGB Backlight. +// https://github.com/bigtreetech/MINI-12864 // -//#define BTT_MINI_12864_V1 +//#define BTT_MINI_12864 // -// Factory display for Creality CR-10 -// https://www.aliexpress.com/item/32833148327.html +// Factory display for Creality CR-10 / CR-7 / Ender-3 +// https://marlinfw.org/docs/hardware/controllers.html#cr10_stockdisplay // -// This is RAMPS-compatible using a single 10-pin connector. -// (For CR-10 owners who want to replace the Melzi Creality board but retain the display) +// Connect to EXP1 on RAMPS and compatible boards. // //#define CR10_STOCKDISPLAY @@ -2501,6 +2901,12 @@ // //#define SILVER_GATE_GLCD_CONTROLLER +// +// eMotion Tech LCD with SD +// https://www.reprap-france.com/produit/1234568748-ecran-graphique-128-x-64-points-2-1 +// +//#define EMOTION_TECH_LCD + //============================================================================= //============================== OLED Displays ============================== //============================================================================= @@ -2564,38 +2970,47 @@ //========================== Extensible UI Displays =========================== //============================================================================= -// -// DGUS Touch Display with DWIN OS. (Choose one.) -// ORIGIN : https://www.aliexpress.com/item/32993409517.html -// FYSETC : https://www.aliexpress.com/item/32961471929.html -// MKS : https://www.aliexpress.com/item/1005002008179262.html -// -// Flash display with DGUS Displays for Marlin: -// - Format the SD card to FAT32 with an allocation size of 4kb. -// - Download files as specified for your type of display. -// - Plug the microSD card into the back of the display. -// - Boot the display and wait for the update to complete. -// -// ORIGIN (Marlin DWIN_SET) -// - Download https://github.com/coldtobi/Marlin_DGUS_Resources -// - Copy the downloaded DWIN_SET folder to the SD card. -// -// FYSETC (Supplier default) -// - Download https://github.com/FYSETC/FYSTLCD-2.0 -// - Copy the downloaded SCREEN folder to the SD card. -// -// HIPRECY (Supplier default) -// - Download https://github.com/HiPrecy/Touch-Lcd-LEO -// - Copy the downloaded DWIN_SET folder to the SD card. -// -// MKS (MKS-H43) (Supplier default) -// - Download https://github.com/makerbase-mks/MKS-H43 -// - Copy the downloaded DWIN_SET folder to the SD card. -// -// RELOADED (T5UID1) -// - Download https://github.com/Desuuuu/DGUS-reloaded/releases -// - Copy the downloaded DWIN_SET folder to the SD card. -// +/** + * DGUS Touch Display with DWIN OS. (Choose one.) + * ORIGIN : https://www.aliexpress.com/item/32993409517.html + * FYSETC : https://www.aliexpress.com/item/32961471929.html + * MKS : https://www.aliexpress.com/item/1005002008179262.html + * + * Flash display with DGUS Displays for Marlin: + * - Format the SD card to FAT32 with an allocation size of 4kb. + * - Download files as specified for your type of display. + * - Plug the microSD card into the back of the display. + * - Boot the display and wait for the update to complete. + * + * ORIGIN (Marlin DWIN_SET) + * - Download https://github.com/coldtobi/Marlin_DGUS_Resources + * - Copy the downloaded DWIN_SET folder to the SD card. + * - Product: https://www.aliexpress.com/item/32993409517.html + * + * FYSETC (Supplier default) + * - Download https://github.com/FYSETC/FYSTLCD-2.0 + * - Copy the downloaded SCREEN folder to the SD card. + * - Product: https://www.aliexpress.com/item/32961471929.html + * + * HIPRECY (Supplier default) + * - Download https://github.com/HiPrecy/Touch-Lcd-LEO + * - Copy the downloaded DWIN_SET folder to the SD card. + * + * MKS (MKS-H43) (Supplier default) + * - Download https://github.com/makerbase-mks/MKS-H43 + * - Copy the downloaded DWIN_SET folder to the SD card. + * - Product: https://www.aliexpress.com/item/1005002008179262.html + * + * RELOADED (T5UID1) + * - Download https://github.com/Neo2003/DGUS-reloaded/releases + * - Copy the downloaded DWIN_SET folder to the SD card. + * + * Flash display with DGUS Displays for Marlin: + * - Format the SD card to FAT32 with an allocation size of 4kb. + * - Download files as specified for your type of display. + * - Plug the microSD card into the back of the display. + * - Boot the display and wait for the update to complete. + */ //#define DGUS_LCD_UI_ORIGIN //#define DGUS_LCD_UI_FYSETC //#define DGUS_LCD_UI_HIPRECY @@ -2609,9 +3024,6 @@ // Touch-screen LCD for Malyan M200/M300 printers // //#define MALYAN_LCD -#if ENABLED(MALYAN_LCD) - #define LCD_SERIAL_PORT 1 // Default is 1 for Malyan M200 -#endif // // Touch UI for FTDI EVE (FT800/FT810) displays @@ -2625,17 +3037,14 @@ //#define ANYCUBIC_LCD_I3MEGA //#define ANYCUBIC_LCD_CHIRON #if EITHER(ANYCUBIC_LCD_I3MEGA, ANYCUBIC_LCD_CHIRON) - #define LCD_SERIAL_PORT 3 // Default is 3 for Anycubic //#define ANYCUBIC_LCD_DEBUG + //#define ANYCUBIC_LCD_GCODE_EXT // Add ".gcode" to menu entries for DGUS clone compatibility #endif // // 320x240 Nextion 2.8" serial TFT Resistive Touch Screen NX3224T028 // //#define NEXTION_TFT -#if ENABLED(NEXTION_TFT) - #define LCD_SERIAL_PORT 1 // Default is 1 for Nextion -#endif // // Third-party or vendor-customized controller interfaces. @@ -2659,6 +3068,7 @@ // // 480x320, 3.5", SPI Display with Rotary Encoder from MKS // Usually paired with MKS Robin Nano V2 & V3 +// https://github.com/makerbase-mks/MKS-TFT-Hardware/tree/master/MKS%20TS35 // //#define MKS_TS35_V2_0 @@ -2698,7 +3108,7 @@ //#define MKS_ROBIN_TFT_V1_1R // -// 480x320, 3.5", FSMC Stock Display from TronxXY +// 480x320, 3.5", FSMC Stock Display from Tronxy // //#define TFT_TRONXY_X5SA @@ -2723,12 +3133,14 @@ //#define ANET_ET5_TFT35 // -// 1024x600, 7", RGB Stock Display with Rotary Encoder from BIQU-BX +// 1024x600, 7", RGB Stock Display with Rotary Encoder from BIQU BX +// https://github.com/bigtreetech/BIQU-BX/tree/master/Hardware // //#define BIQU_BX_TFT70 // // 480x320, 3.5", SPI Stock Display with Rotary Encoder from BIQU B1 SE Series +// https://github.com/bigtreetech/TFT35-SPI/tree/master/v1 // //#define BTT_TFT35_SPI_V1_0 @@ -2765,8 +3177,12 @@ //#define TFT_COLOR_UI //#define TFT_LVGL_UI +#if ENABLED(TFT_COLOR_UI) + //#define TFT_SHARED_IO // SPI is shared between TFT display and other devices. Disable async data transfer +#endif + #if ENABLED(TFT_LVGL_UI) - //#define MKS_WIFI_MODULE // MKS WiFi module + //#define MKS_WIFI_MODULE // MKS WiFi module #endif /** @@ -2787,7 +3203,7 @@ // Ender-3 v2 OEM display. A DWIN display with Rotary Encoder. // //#define DWIN_CREALITY_LCD // Creality UI -//#define DWIN_CREALITY_LCD_ENHANCED // Enhanced UI +//#define DWIN_LCD_PROUI // Pro UI by MRiscoC //#define DWIN_CREALITY_LCD_JYERSUI // Jyers UI by Jacob Myers //#define DWIN_MARLINUI_PORTRAIT // MarlinUI (portrait orientation) //#define DWIN_MARLINUI_LANDSCAPE // MarlinUI (landscape orientation) @@ -2797,10 +3213,11 @@ // //#define TOUCH_SCREEN #if ENABLED(TOUCH_SCREEN) - #define BUTTON_DELAY_EDIT 50 // (ms) Button repeat delay for edit screens - #define BUTTON_DELAY_MENU 250 // (ms) Button repeat delay for menus + #define BUTTON_DELAY_EDIT 50 // (ms) Button repeat delay for edit screens + #define BUTTON_DELAY_MENU 250 // (ms) Button repeat delay for menus - //#define TOUCH_IDLE_SLEEP 300 // (secs) Turn off the TFT backlight if set (5mn) + //#define DISABLE_ENCODER // Disable the click encoder, if any + //#define TOUCH_IDLE_SLEEP_MINS 5 // (minutes) Display Sleep after a period of inactivity. Set with M255 S. #define TOUCH_SCREEN_CALIBRATION @@ -2835,7 +3252,7 @@ //=============================== Extra Features ============================== //============================================================================= -// @section extras +// @section fans // Set number of user-controlled fans. Disable to use all board-defined fans. // :[1,2,3,4,5,6,7,8] @@ -2859,14 +3276,18 @@ // duty cycle is attained. //#define SOFT_PWM_DITHER +// @section extras + +// Support for the BariCUDA Paste Extruder +//#define BARICUDA + +// @section lights + // Temperature status LEDs that display the hotend and bed temperature. // If all hotends, bed temperature, and target temperature are under 54C // then the BLUE led is on. Otherwise the RED led is on. (1C hysteresis) //#define TEMP_STAT_LEDS -// Support for the BariCUDA Paste Extruder -//#define BARICUDA - // Support for BlinkM/CyzRgb //#define BLINKM @@ -2887,16 +3308,19 @@ * luminance values can be set from 0 to 255. * For NeoPixel LED an overall brightness parameter is also available. * - * *** CAUTION *** + * === CAUTION === * LED Strips require a MOSFET Chip between PWM lines and LEDs, * as the Arduino cannot handle the current the LEDs will require. * Failure to follow this precaution can destroy your Arduino! + * * NOTE: A separate 5V power supply is required! The NeoPixel LED needs * more current than the Arduino 5V linear regulator can produce. - * *** CAUTION *** * - * LED Type. Enable only one of the following two options. + * Requires PWM frequency between 50 <> 100Hz (Check HAL or variant) + * Use FAST_PWM_FAN, if possible, to reduce fan noise. */ + +// LED Type. Enable only one of the following two options: //#define RGB_LED //#define RGBW_LED @@ -2907,33 +3331,42 @@ //#define RGB_LED_W_PIN -1 #endif +#if ANY(RGB_LED, RGBW_LED, PCA9632) + //#define RGB_STARTUP_TEST // For PWM pins, fade between all colors + #if ENABLED(RGB_STARTUP_TEST) + #define RGB_STARTUP_TEST_INNER_MS 10 // (ms) Reduce or increase fading speed + #endif +#endif + // Support for Adafruit NeoPixel LED driver //#define NEOPIXEL_LED #if ENABLED(NEOPIXEL_LED) - #define NEOPIXEL_TYPE NEO_GRBW // NEO_GRBW / NEO_GRB - four/three channel driver type (defined in Adafruit_NeoPixel.h) - //#define NEOPIXEL_PIN 4 // LED driving pin - //#define NEOPIXEL2_TYPE NEOPIXEL_TYPE - //#define NEOPIXEL2_PIN 5 - #define NEOPIXEL_PIXELS 30 // Number of LEDs in the strip. (Longest strip when NEOPIXEL2_SEPARATE is disabled.) - #define NEOPIXEL_IS_SEQUENTIAL // Sequential display for temperature change - LED by LED. Disable to change all LEDs at once. - #define NEOPIXEL_BRIGHTNESS 127 // Initial brightness (0-255) - //#define NEOPIXEL_STARTUP_TEST // Cycle through colors at startup + #define NEOPIXEL_TYPE NEO_GRBW // NEO_GRBW, NEO_RGBW, NEO_GRB, NEO_RBG, etc. + // See https://github.com/adafruit/Adafruit_NeoPixel/blob/master/Adafruit_NeoPixel.h + //#define NEOPIXEL_PIN 4 // LED driving pin + //#define NEOPIXEL2_TYPE NEOPIXEL_TYPE + //#define NEOPIXEL2_PIN 5 + #define NEOPIXEL_PIXELS 30 // Number of LEDs in the strip. (Longest strip when NEOPIXEL2_SEPARATE is disabled.) + #define NEOPIXEL_IS_SEQUENTIAL // Sequential display for temperature change - LED by LED. Disable to change all LEDs at once. + #define NEOPIXEL_BRIGHTNESS 127 // Initial brightness (0-255) + //#define NEOPIXEL_STARTUP_TEST // Cycle through colors at startup // Support for second Adafruit NeoPixel LED driver controlled with M150 S1 ... //#define NEOPIXEL2_SEPARATE #if ENABLED(NEOPIXEL2_SEPARATE) - #define NEOPIXEL2_PIXELS 15 // Number of LEDs in the second strip - #define NEOPIXEL2_BRIGHTNESS 127 // Initial brightness (0-255) - #define NEOPIXEL2_STARTUP_TEST // Cycle through colors at startup + #define NEOPIXEL2_PIXELS 15 // Number of LEDs in the second strip + #define NEOPIXEL2_BRIGHTNESS 127 // Initial brightness (0-255) + #define NEOPIXEL2_STARTUP_TEST // Cycle through colors at startup + #define NEOPIXEL_M150_DEFAULT -1 // Default strip for M150 without 'S'. Use -1 to set all by default. #else - //#define NEOPIXEL2_INSERIES // Default behavior is NeoPixel 2 in parallel + //#define NEOPIXEL2_INSERIES // Default behavior is NeoPixel 2 in parallel #endif // Use some of the NeoPixel LEDs for static (background) lighting - //#define NEOPIXEL_BKGD_INDEX_FIRST 0 // Index of the first background LED - //#define NEOPIXEL_BKGD_INDEX_LAST 5 // Index of the last background LED - //#define NEOPIXEL_BKGD_COLOR { 255, 255, 255, 0 } // R, G, B, W - //#define NEOPIXEL_BKGD_ALWAYS_ON // Keep the backlight on when other NeoPixels are off + //#define NEOPIXEL_BKGD_INDEX_FIRST 0 // Index of the first background LED + //#define NEOPIXEL_BKGD_INDEX_LAST 5 // Index of the last background LED + //#define NEOPIXEL_BKGD_COLOR { 255, 255, 255, 0 } // R, G, B, W + //#define NEOPIXEL_BKGD_ALWAYS_ON // Keep the backlight on when other NeoPixels are off #endif /** @@ -2951,6 +3384,8 @@ #define PRINTER_EVENT_LEDS #endif +// @section servos + /** * Number of servos * diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 5d6dc5bd..6557ad81 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -30,7 +30,25 @@ * * Basic settings can be found in Configuration.h */ -#define CONFIGURATION_ADV_H_VERSION 02000903 +#define CONFIGURATION_ADV_H_VERSION 02010205 + +// @section develop + +/** + * Configuration Export + * + * Export the configuration as part of the build. (See signature.py) + * Output files are saved with the build (e.g., .pio/build/mega2560). + * + * See `build_all_examples --ini` as an example of config.ini archiving. + * + * 1 = marlin_config.json - Dictionary containing the configuration. + * This file is also generated for CONFIGURATION_EMBEDDING. + * 2 = config.ini - File format for PlatformIO preprocessing. + * 3 = schema.json - The entire configuration schema. (13 = pattern groups) + * 4 = schema.yml - The entire configuration schema. + */ +//#define CONFIG_EXPORT 2 // :[1:'JSON', 2:'config.ini', 3:'schema.json', 4:'schema.yml'] //=========================================================================== //============================= Thermal Settings ============================ @@ -54,117 +72,128 @@ // 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 + #define HOTEND0_SH_C_COEFF 0 // Steinhart-Hart C coefficient #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 + #define HOTEND1_SH_C_COEFF 0 // Steinhart-Hart C coefficient #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 + #define HOTEND2_SH_C_COEFF 0 // Steinhart-Hart C coefficient #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 + #define HOTEND3_SH_C_COEFF 0 // Steinhart-Hart C coefficient #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 + #define HOTEND4_SH_C_COEFF 0 // Steinhart-Hart C coefficient #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 + #define HOTEND5_SH_C_COEFF 0 // Steinhart-Hart C coefficient #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 + #define HOTEND6_SH_C_COEFF 0 // Steinhart-Hart C coefficient #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 + #define HOTEND7_SH_C_COEFF 0 // Steinhart-Hart C coefficient #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 + #define BED_SH_C_COEFF 0 // Steinhart-Hart C coefficient #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 + #define CHAMBER_SH_C_COEFF 0 // Steinhart-Hart C coefficient #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 + #define COOLER_SH_C_COEFF 0 // Steinhart-Hart C coefficient #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 + #define PROBE_SH_C_COEFF 0 // Steinhart-Hart C coefficient #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 + #define BOARD_SH_C_COEFF 0 // Steinhart-Hart C coefficient #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 + #define REDUNDANT_SH_C_COEFF 0 // Steinhart-Hart C coefficient #endif /** - * Configuration options for MAX Thermocouples (-2, -3, -5). - * FORCE_HW_SPI: Ignore SCK/MOSI/MISO pins and just use the CS pin & default SPI bus. - * MAX31865_WIRES: Set the number of wires for the probe connected to a MAX31865 board, 2-4. Default: 2 - * MAX31865_50HZ: Enable 50Hz filter instead of the default 60Hz. - * MAX31865_USE_READ_ERROR_DETECTION: Detects random read errors from value spikes (a 20°C difference in less than 1sec) - * MAX31865_USE_AUTO_MODE: Faster and more frequent reads than 1-shot, but bias voltage always on, slightly affecting RTD temperature. - * MAX31865_MIN_SAMPLING_TIME_MSEC: in 1-shot mode, the minimum time between subsequent reads. This reduces the effect of bias voltage by leaving the sensor unpowered for longer intervals. - * MAX31865_WIRE_OHMS: In 2-wire configurations, manually set the wire resistance for more accurate readings + * Thermocouple Options — for MAX6675 (-2), MAX31855 (-3), and MAX31865 (-5). */ -//#define TEMP_SENSOR_FORCE_HW_SPI -//#define MAX31865_SENSOR_WIRES_0 2 +//#define TEMP_SENSOR_FORCE_HW_SPI // Ignore SCK/MOSI/MISO pins; use CS and the default SPI bus. +//#define MAX31865_SENSOR_WIRES_0 2 // (2-4) Number of wires for the probe connected to a MAX31865 board. //#define MAX31865_SENSOR_WIRES_1 2 -//#define MAX31865_50HZ_FILTER -//#define MAX31865_USE_READ_ERROR_DETECTION -//#define MAX31865_USE_AUTO_MODE -//#define MAX31865_MIN_SAMPLING_TIME_MSEC 100 -//#define MAX31865_WIRE_OHMS_0 0.0f -//#define MAX31865_WIRE_OHMS_1 0.0f +//#define MAX31865_SENSOR_WIRES_2 2 + +//#define MAX31865_50HZ_FILTER // Use a 50Hz filter instead of the default 60Hz. +//#define MAX31865_USE_READ_ERROR_DETECTION // Treat value spikes (20°C delta in under 1s) as read errors. + +//#define MAX31865_USE_AUTO_MODE // Read faster and more often than 1-shot; bias voltage always on; slight effect on RTD temperature. +//#define MAX31865_MIN_SAMPLING_TIME_MSEC 100 // (ms) 1-shot: minimum read interval. Reduces bias voltage effects by leaving sensor unpowered for longer intervals. +//#define MAX31865_IGNORE_INITIAL_FAULTY_READS 10 // Ignore some read faults (keeping the temperature reading) to work around a possible issue (#23439). + +//#define MAX31865_WIRE_OHMS_0 0.95f // For 2-wire, set the wire resistances for more accurate readings. +//#define MAX31865_WIRE_OHMS_1 0.0f +//#define MAX31865_WIRE_OHMS_2 0.0f /** * Hephestos 2 24V heated bed upgrade kit. - * https://store.bq.com/en/heated-bed-kit-hephestos2 + * https://www.en3dstudios.com/product/bq-hephestos-2-heated-bed-kit/ */ //#define HEPHESTOS2_HEATED_BED_KIT #if ENABLED(HEPHESTOS2_HEATED_BED_KIT) - #undef TEMP_SENSOR_BED - #define TEMP_SENSOR_BED 70 #define HEATER_BED_INVERTING true #endif @@ -247,23 +276,7 @@ #define THERMAL_PROTECTION_BOARD // Halt the printer if the board sensor leaves the temp range below. #define BOARD_MINTEMP 8 // (°C) #define BOARD_MAXTEMP 70 // (°C) - #ifndef TEMP_BOARD_PIN - //#define TEMP_BOARD_PIN -1 // Board temp sensor pin, if not set in pins file. - #endif -#endif - -// -// Laser Coolant Flow Meter -// -//#define LASER_COOLANT_FLOW_METER -#if ENABLED(LASER_COOLANT_FLOW_METER) - #define FLOWMETER_PIN 20 // Requires an external interrupt-enabled pin (e.g., RAMPS 2,3,18,19,20,21) - #define FLOWMETER_PPL 5880 // (pulses/liter) Flow meter pulses-per-liter on the input pin - #define FLOWMETER_INTERVAL 1000 // (ms) Flow rate calculation interval in milliseconds - #define FLOWMETER_SAFETY // Prevent running the laser without the minimum flow rate set below - #if ENABLED(FLOWMETER_SAFETY) - #define FLOWMETER_MIN_LITERS_PER_MINUTE 1.5 // (liters/min) Minimum flow required when enabled - #endif + //#define TEMP_BOARD_PIN -1 // Board temp sensor pin override. #endif /** @@ -283,8 +296,8 @@ * THERMAL_PROTECTION_HYSTERESIS and/or THERMAL_PROTECTION_PERIOD */ #if ENABLED(THERMAL_PROTECTION_HOTENDS) - #define THERMAL_PROTECTION_PERIOD 40 // Seconds - #define THERMAL_PROTECTION_HYSTERESIS 4 // Degrees Celsius + #define THERMAL_PROTECTION_PERIOD 40 // (seconds) + #define THERMAL_PROTECTION_HYSTERESIS 4 // (°C) //#define ADAPTIVE_FAN_SLOWING // Slow part cooling fan if temperature drops #if BOTH(ADAPTIVE_FAN_SLOWING, PIDTEMP) @@ -303,54 +316,62 @@ * and/or decrease WATCH_TEMP_INCREASE. WATCH_TEMP_INCREASE should not be set * below 2. */ - #define WATCH_TEMP_PERIOD 20 // Seconds - #define WATCH_TEMP_INCREASE 2 // Degrees Celsius + #define WATCH_TEMP_PERIOD 40 // (seconds) + #define WATCH_TEMP_INCREASE 2 // (°C) #endif /** * Thermal Protection parameters for the bed are just as above for hotends. */ #if ENABLED(THERMAL_PROTECTION_BED) - #define THERMAL_PROTECTION_BED_PERIOD 20 // Seconds - #define THERMAL_PROTECTION_BED_HYSTERESIS 2 // Degrees Celsius + #define THERMAL_PROTECTION_BED_PERIOD 20 // (seconds) + #define THERMAL_PROTECTION_BED_HYSTERESIS 2 // (°C) /** * As described above, except for the bed (M140/M190/M303). */ - #define WATCH_BED_TEMP_PERIOD 60 // Seconds - #define WATCH_BED_TEMP_INCREASE 2 // Degrees Celsius + #define WATCH_BED_TEMP_PERIOD 60 // (seconds) + #define WATCH_BED_TEMP_INCREASE 2 // (°C) #endif /** * Thermal Protection parameters for the heated chamber. */ #if ENABLED(THERMAL_PROTECTION_CHAMBER) - #define THERMAL_PROTECTION_CHAMBER_PERIOD 20 // Seconds - #define THERMAL_PROTECTION_CHAMBER_HYSTERESIS 2 // Degrees Celsius + #define THERMAL_PROTECTION_CHAMBER_PERIOD 20 // (seconds) + #define THERMAL_PROTECTION_CHAMBER_HYSTERESIS 2 // (°C) /** * Heated chamber watch settings (M141/M191). */ - #define WATCH_CHAMBER_TEMP_PERIOD 60 // Seconds - #define WATCH_CHAMBER_TEMP_INCREASE 2 // Degrees Celsius + #define WATCH_CHAMBER_TEMP_PERIOD 60 // (seconds) + #define WATCH_CHAMBER_TEMP_INCREASE 2 // (°C) #endif /** * Thermal Protection parameters for the laser cooler. */ #if ENABLED(THERMAL_PROTECTION_COOLER) - #define THERMAL_PROTECTION_COOLER_PERIOD 10 // Seconds - #define THERMAL_PROTECTION_COOLER_HYSTERESIS 3 // Degrees Celsius + #define THERMAL_PROTECTION_COOLER_PERIOD 10 // (seconds) + #define THERMAL_PROTECTION_COOLER_HYSTERESIS 3 // (°C) /** * Laser cooling watch settings (M143/M193). */ - #define WATCH_COOLER_TEMP_PERIOD 60 // Seconds - #define WATCH_COOLER_TEMP_INCREASE 3 // Degrees Celsius + #define WATCH_COOLER_TEMP_PERIOD 60 // (seconds) + #define WATCH_COOLER_TEMP_INCREASE 3 // (°C) +#endif + +#if ANY(THERMAL_PROTECTION_HOTENDS, THERMAL_PROTECTION_BED, THERMAL_PROTECTION_CHAMBER, THERMAL_PROTECTION_COOLER) + /** + * Thermal Protection Variance Monitor - EXPERIMENTAL. + * Kill the machine on a stuck temperature sensor. Disable if you get false positives. + */ + //#define THERMAL_PROTECTION_VARIANCE_MONITOR // Detect a sensor malfunction preventing temperature updates #endif #if ENABLED(PIDTEMP) - // Add an experimental additional term to the heater power, proportional to the extrusion speed. + // Add an additional term to the heater power, proportional to the extrusion speed. // A well-chosen Kc value should add just enough power to melt the increased material volume. //#define PID_EXTRUSION_SCALING #if ENABLED(PID_EXTRUSION_SCALING) @@ -359,12 +380,12 @@ #endif /** - * Add an experimental additional term to the heater power, proportional to the fan speed. + * Add an additional term to the heater power, proportional to the fan speed. * A well-chosen Kf value should add just enough power to compensate for power-loss from the cooling fan. * You can either just add a constant compensation with the DEFAULT_Kf value * or follow the instruction below to get speed-dependent compensation. * - * Constant compensation (use only with fanspeeds of 0% and 100%) + * Constant compensation (use only with fan speeds of 0% and 100%) * --------------------------------------------------------------------- * A good starting point for the Kf-value comes from the calculation: * kf = (power_fan * eff_fan) / power_heater * 255 @@ -391,7 +412,7 @@ //#define PID_FAN_SCALING_ALTERNATIVE_DEFINITION #if ENABLED(PID_FAN_SCALING_ALTERNATIVE_DEFINITION) // The alternative definition is used for an easier configuration. - // Just figure out Kf at fullspeed (255) and PID_FAN_SCALING_MIN_SPEED. + // Just figure out Kf at full speed (255) and PID_FAN_SCALING_MIN_SPEED. // DEFAULT_Kf and PID_FAN_SCALING_LIN_FACTOR are calculated accordingly. #define PID_FAN_SCALING_AT_FULL_SPEED 13.0 //=PID_FAN_SCALING_LIN_FACTOR*255+DEFAULT_Kf @@ -402,7 +423,7 @@ #define PID_FAN_SCALING_LIN_FACTOR (PID_FAN_SCALING_AT_FULL_SPEED-DEFAULT_Kf)/255.0 #else - #define PID_FAN_SCALING_LIN_FACTOR (0) // Power loss due to cooling = Kf * (fan_speed) + #define PID_FAN_SCALING_LIN_FACTOR (0) // Power-loss due to cooling = Kf * (fan_speed) #define DEFAULT_Kf 10 // A constant value added to the PID-tuner #define PID_FAN_SCALING_MIN_SPEED 10 // Minimum fan speed at which to enable PID_FAN_SCALING #endif @@ -444,10 +465,10 @@ * Thermistors able to support high temperature tend to have a hard time getting * good readings at room and lower temperatures. This means TEMP_SENSOR_X_RAW_LO_TEMP * will probably be caught when the heating element first turns on during the - * preheating process, which will trigger a min_temp_error as a safety measure + * preheating process, which will trigger a MINTEMP error as a safety measure * and force stop everything. * To circumvent this limitation, we allow for a preheat time (during which, - * min_temp_error won't be triggered) and add a min_temp buffer to handle + * MINTEMP error won't be triggered) and add a min_temp buffer to handle * aberrant readings. * * If you want to enable this feature for your hotend thermistor(s) @@ -455,21 +476,25 @@ */ // The number of consecutive low temperature errors that can occur -// before a min_temp_error is triggered. (Shouldn't be more than 10.) +// before a MINTEMP error is triggered. (Shouldn't be more than 10.) //#define MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED 0 -// The number of milliseconds a hotend will preheat before starting to check -// the temperature. This value should NOT be set to the time it takes the -// hot end to reach the target temperature, but the time it takes to reach -// the minimum temperature your thermistor can read. The lower the better/safer. -// This shouldn't need to be more than 30 seconds (30000) +/** + * The number of milliseconds a hotend will preheat before starting to check + * the temperature. This value should NOT be set to the time it takes the + * hot end to reach the target temperature, but the time it takes to reach + * the minimum temperature your thermistor can read. The lower the better/safer. + * This shouldn't need to be more than 30 seconds (30000) + */ //#define MILLISECONDS_PREHEAT_TIME 0 // @section extruder -// Extruder runout prevention. -// If the machine is idle and the temperature over MINTEMP -// then extrude some filament every couple of SECONDS. +/** + * Extruder runout prevention. + * If the machine is idle and the temperature over MINTEMP + * then extrude some filament every couple of SECONDS. + */ //#define EXTRUDER_RUNOUT_PREVENT #if ENABLED(EXTRUDER_RUNOUT_PREVENT) #define EXTRUDER_RUNOUT_MINTEMP 190 @@ -499,6 +524,8 @@ #define TEMP_SENSOR_AD8495_OFFSET 0.0 #define TEMP_SENSOR_AD8495_GAIN 1.0 +// @section fans + /** * Controller Fan * To cool down the stepper drivers and MOSFETs. @@ -509,6 +536,7 @@ //#define USE_CONTROLLER_FAN #if ENABLED(USE_CONTROLLER_FAN) //#define CONTROLLER_FAN_PIN -1 // Set a custom pin for the controller fan + //#define CONTROLLER_FAN2_PIN -1 // Set a custom pin for second controller fan //#define CONTROLLER_FAN_USE_Z_ONLY // With this option only the Z axis is considered //#define CONTROLLER_FAN_IGNORE_Z // Ignore Z stepper. Useful when stepper timeout is disabled. #define CONTROLLERFAN_SPEED_MIN 0 // (0-255) Minimum speed. (If set below this value the fan is turned off.) @@ -525,10 +553,14 @@ #endif #endif -// When first starting the main fan, run it at full speed for the -// given number of milliseconds. This gets the fan spinning reliably -// before setting a PWM value. (Does not work with software PWM for fan on Sanguinololu) -//#define FAN_KICKSTART_TIME 100 +/** + * Fan Kickstart + * When part cooling or controller fans first start, run at a speed that + * gets it spinning reliably for a short time before setting the requested speed. + * (Does not work on Sanguinololu with FAN_SOFT_PWM.) + */ +//#define FAN_KICKSTART_TIME 100 // (ms) +//#define FAN_KICKSTART_POWER 180 // 64-255 // Some coolers may require a non-zero "off" state. //#define FAN_OFF_PWM 1 @@ -557,7 +589,7 @@ * FAST_PWM_FAN_FREQUENCY * Set this to your desired frequency. * For AVR, if left undefined this defaults to F = F_CPU/(2*255*1) - * i.e., F = 31.4kHz on 16MHz microcontrollers or F = 39.2kHz on 20MHz microcontrollers. + * i.e., F = 31.4kHz on 16MHz micro-controllers or F = 39.2kHz on 20MHz micro-controllers. * For non AVR, if left undefined this defaults to F = 1Khz. * This F value is only to protect the hardware from an absence of configuration * and not to complete it when users are not aware that the frequency must be specifically set to support the target board. @@ -567,8 +599,8 @@ * * USE_OCR2A_AS_TOP [undefined by default] * Boards that use TIMER2 for PWM have limitations resulting in only a few possible frequencies on TIMER2: - * 16MHz MCUs: [62.5KHz, 31.4KHz (default), 7.8KHz, 3.92KHz, 1.95KHz, 977Hz, 488Hz, 244Hz, 60Hz, 122Hz, 30Hz] - * 20MHz MCUs: [78.1KHz, 39.2KHz (default), 9.77KHz, 4.9KHz, 2.44KHz, 1.22KHz, 610Hz, 305Hz, 153Hz, 76Hz, 38Hz] + * 16MHz MCUs: [62.5kHz, 31.4kHz (default), 7.8kHz, 3.92kHz, 1.95kHz, 977Hz, 488Hz, 244Hz, 60Hz, 122Hz, 30Hz] + * 20MHz MCUs: [78.1kHz, 39.2kHz (default), 9.77kHz, 4.9kHz, 2.44kHz, 1.22kHz, 610Hz, 305Hz, 153Hz, 76Hz, 38Hz] * A greater range can be achieved by enabling USE_OCR2A_AS_TOP. But note that this option blocks the use of * PWM on pin OC2A. Only use this option if you don't need PWM on 0C2A. (Check your schematic.) * USE_OCR2A_AS_TOP sacrifices duty cycle control resolution to achieve this broader range of frequencies. @@ -589,9 +621,7 @@ /** * Use one of the PWM fans as a redundant part-cooling fan */ -//#define REDUNDANT_PART_COOLING_FAN 2 // Index of the fan to sync with FAN 0. - -// @section extruder +//#define REDUNDANT_PART_COOLING_FAN 1 // Index of the fan to sync with FAN 0. /** * Extruder cooling fans @@ -615,7 +645,6 @@ #define E7_AUTO_FAN_PIN -1 #define CHAMBER_AUTO_FAN_PIN -1 #define COOLER_AUTO_FAN_PIN -1 -#define COOLER_FAN_PIN -1 #define EXTRUDER_AUTO_FAN_TEMPERATURE 50 #define EXTRUDER_AUTO_FAN_SPEED 255 // 255 == full speed @@ -670,6 +699,7 @@ #define FANMUX2_PIN -1 /** + * @section caselight * M355 Case Light on-off / brightness */ //#define CASE_LIGHT_ENABLE @@ -692,7 +722,7 @@ #endif #endif -// @section homing +// @section endstops // If you want endstops to stay on (by default) even when not homing // enable this option. Override at any time with M120, M121. @@ -709,72 +739,7 @@ //#define CLOSED_LOOP_MOVE_COMPLETE_PIN -1 #endif -/** - * Dual Steppers / Dual Endstops - * - * This section will allow you to use extra E drivers to drive a second motor for X, Y, or Z axes. - * - * For example, set X_DUAL_STEPPER_DRIVERS setting to use a second motor. If the motors need to - * spin in opposite directions set INVERT_X2_VS_X_DIR. If the second motor needs its own endstop - * set X_DUAL_ENDSTOPS. This can adjust for "racking." Use X2_USE_ENDSTOP to set the endstop plug - * that should be used for the second endstop. Extra endstops will appear in the output of 'M119'. - * - * Use X_DUAL_ENDSTOP_ADJUSTMENT to adjust for mechanical imperfection. After homing both motors - * this offset is applied to the X2 motor. To find the offset home the X axis, and measure the error - * in X2. Dual endstop offsets can be set at runtime with 'M666 X Y Z'. - */ - -//#define X_DUAL_STEPPER_DRIVERS -#if ENABLED(X_DUAL_STEPPER_DRIVERS) - //#define INVERT_X2_VS_X_DIR // Enable if X2 direction signal is opposite to X - //#define X_DUAL_ENDSTOPS - #if ENABLED(X_DUAL_ENDSTOPS) - #define X2_USE_ENDSTOP _XMAX_ - #define X2_ENDSTOP_ADJUSTMENT 0 - #endif -#endif - -//#define Y_DUAL_STEPPER_DRIVERS -#if ENABLED(Y_DUAL_STEPPER_DRIVERS) - //#define INVERT_Y2_VS_Y_DIR // Enable if Y2 direction signal is opposite to Y - //#define Y_DUAL_ENDSTOPS - #if ENABLED(Y_DUAL_ENDSTOPS) - #define Y2_USE_ENDSTOP _YMAX_ - #define Y2_ENDSTOP_ADJUSTMENT 0 - #endif -#endif - -// -// For Z set the number of stepper drivers -// -#define NUM_Z_STEPPER_DRIVERS 1 // (1-4) Z options change based on how many - -#if NUM_Z_STEPPER_DRIVERS > 1 - // Enable if Z motor direction signals are the opposite of Z1 - //#define INVERT_Z2_VS_Z_DIR - //#define INVERT_Z3_VS_Z_DIR - //#define INVERT_Z4_VS_Z_DIR - - //#define Z_MULTI_ENDSTOPS - #if ENABLED(Z_MULTI_ENDSTOPS) - #define Z2_USE_ENDSTOP _XMAX_ - #define Z2_ENDSTOP_ADJUSTMENT 0 - #if NUM_Z_STEPPER_DRIVERS >= 3 - #define Z3_USE_ENDSTOP _YMAX_ - #define Z3_ENDSTOP_ADJUSTMENT 0 - #endif - #if NUM_Z_STEPPER_DRIVERS >= 4 - #define Z4_USE_ENDSTOP _ZMAX_ - #define Z4_ENDSTOP_ADJUSTMENT 0 - #endif - #endif -#endif - -// Drive the E axis with two synchronized steppers -//#define E_DUAL_STEPPER_DRIVERS -#if ENABLED(E_DUAL_STEPPER_DRIVERS) - //#define INVERT_E1_VS_E0_DIR // Enable if the E motors need opposite DIR states -#endif +// @section idex /** * Dual X Carriage @@ -806,18 +771,16 @@ */ //#define DUAL_X_CARRIAGE #if ENABLED(DUAL_X_CARRIAGE) - #define X1_MIN_POS X_MIN_POS // Set to X_MIN_POS - #define X1_MAX_POS X_BED_SIZE // Set a maximum so the first X-carriage can't hit the parked second X-carriage - #define X2_MIN_POS 80 // Set a minimum to ensure the second X-carriage can't hit the parked first X-carriage - #define X2_MAX_POS 353 // Set this to the distance between toolheads when both heads are homed - #define X2_HOME_DIR 1 // Set to 1. The second X-carriage always homes to the maximum endstop position - #define X2_HOME_POS X2_MAX_POS // Default X2 home position. Set to X2_MAX_POS. - // However: In this mode the HOTEND_OFFSET_X value for the second extruder provides a software - // override for X2_HOME_POS. This also allow recalibration of the distance between the two endstops - // without modifying the firmware (through the "M218 T1 X???" command). - // Remember: you should set the second extruder x-offset to 0 in your slicer. - - // This is the default power-up mode which can be later using M605. + #define X1_MIN_POS X_MIN_POS // Set to X_MIN_POS + #define X1_MAX_POS X_BED_SIZE // A max coordinate so the X1 carriage can't hit the parked X2 carriage + #define X2_MIN_POS 80 // A min coordinate so the X2 carriage can't hit the parked X1 carriage + #define X2_MAX_POS 353 // The max position of the X2 carriage, typically also the home position + #define X2_HOME_POS X2_MAX_POS // Default X2 home position. Set to X2_MAX_POS. + // NOTE: For Dual X Carriage use M218 T1 Xn to override the X2_HOME_POS. + // This allows recalibration of endstops distance without a rebuild. + // Remember to set the second extruder's X-offset to 0 in your slicer. + + // This is the default power-up mode which can be changed later using M605 S. #define DEFAULT_DUAL_X_CARRIAGE_MODE DXC_AUTO_PARK_MODE // Default x offset in duplication mode (typically set to half print bed width) @@ -827,6 +790,81 @@ //#define EVENT_GCODE_IDEX_AFTER_MODECHANGE "G28X" #endif +// @section multi stepper + +/** + * Multi-Stepper / Multi-Endstop + * + * When X2_DRIVER_TYPE is defined, this indicates that the X and X2 motors work in tandem. + * The following explanations for X also apply to Y and Z multi-stepper setups. + * Endstop offsets may be changed by 'M666 X Y Z' and stored to EEPROM. + * + * - Enable INVERT_X2_VS_X_DIR if the X2 motor requires an opposite DIR signal from X. + * + * - Enable X_DUAL_ENDSTOPS if the second motor has its own endstop, with adjustable offset. + * + * - Extra endstops are included in the output of 'M119'. + * + * - Set X_DUAL_ENDSTOP_ADJUSTMENT to the known error in the X2 endstop. + * Applied to the X2 motor on 'G28' / 'G28 X'. + * Get the offset by homing X and measuring the error. + * Also set with 'M666 X' and stored to EEPROM with 'M500'. + * + * - Use X2_USE_ENDSTOP to set the endstop plug by name. (_XMIN_, _XMAX_, _YMIN_, _YMAX_, _ZMIN_, _ZMAX_) + */ +#if HAS_X2_STEPPER && DISABLED(DUAL_X_CARRIAGE) + //#define INVERT_X2_VS_X_DIR // X2 direction signal is the opposite of X + //#define X_DUAL_ENDSTOPS // X2 has its own endstop + #if ENABLED(X_DUAL_ENDSTOPS) + #define X2_USE_ENDSTOP _XMAX_ // X2 endstop board plug. Don't forget to enable USE_*_PLUG. + #define X2_ENDSTOP_ADJUSTMENT 0 // X2 offset relative to X endstop + #endif +#endif + +#if HAS_DUAL_Y_STEPPERS + //#define INVERT_Y2_VS_Y_DIR // Y2 direction signal is the opposite of Y + //#define Y_DUAL_ENDSTOPS // Y2 has its own endstop + #if ENABLED(Y_DUAL_ENDSTOPS) + #define Y2_USE_ENDSTOP _YMAX_ // Y2 endstop board plug. Don't forget to enable USE_*_PLUG. + #define Y2_ENDSTOP_ADJUSTMENT 0 // Y2 offset relative to Y endstop + #endif +#endif + +// +// Multi-Z steppers +// +#ifdef Z2_DRIVER_TYPE + //#define INVERT_Z2_VS_Z_DIR // Z2 direction signal is the opposite of Z + + //#define Z_MULTI_ENDSTOPS // Other Z axes have their own endstops + #if ENABLED(Z_MULTI_ENDSTOPS) + #define Z2_USE_ENDSTOP _XMAX_ // Z2 endstop board plug. Don't forget to enable USE_*_PLUG. + #define Z2_ENDSTOP_ADJUSTMENT 0 // Z2 offset relative to Z endstop + #endif + #ifdef Z3_DRIVER_TYPE + //#define INVERT_Z3_VS_Z_DIR // Z3 direction signal is the opposite of Z + #if ENABLED(Z_MULTI_ENDSTOPS) + #define Z3_USE_ENDSTOP _YMAX_ // Z3 endstop board plug. Don't forget to enable USE_*_PLUG. + #define Z3_ENDSTOP_ADJUSTMENT 0 // Z3 offset relative to Z endstop + #endif + #endif + #ifdef Z4_DRIVER_TYPE + //#define INVERT_Z4_VS_Z_DIR // Z4 direction signal is the opposite of Z + #if ENABLED(Z_MULTI_ENDSTOPS) + #define Z4_USE_ENDSTOP _ZMAX_ // Z4 endstop board plug. Don't forget to enable USE_*_PLUG. + #define Z4_ENDSTOP_ADJUSTMENT 0 // Z4 offset relative to Z endstop + #endif + #endif +#endif + +// Drive the E axis with two synchronized steppers +//#define E_DUAL_STEPPER_DRIVERS +#if ENABLED(E_DUAL_STEPPER_DRIVERS) + //#define INVERT_E1_VS_E0_DIR // E direction signals are opposites +#endif + +// @section extruder + // Activate a solenoid on the active extruder with M380. Disable all with M381. // Define SOL0_PIN, SOL1_PIN, etc., for each extruder that has a solenoid. //#define EXT_SOLENOID @@ -839,16 +877,17 @@ * the position of the toolhead relative to the workspace. */ -//#define SENSORLESS_BACKOFF_MM { 2, 2, 0 } // (mm) Backoff from endstops before sensorless homing +//#define SENSORLESS_BACKOFF_MM { 2, 2, 0 } // (linear=mm, rotational=°) Backoff from endstops before sensorless homing -#define HOMING_BUMP_MM { 5, 5, 2 } // (mm) Backoff from endstops after first bump +#define HOMING_BUMP_MM { 5, 5, 2 } // (linear=mm, rotational=°) Backoff from endstops after first bump #define HOMING_BUMP_DIVISOR { 2, 2, 4 } // Re-Bump Speed Divisor (Divides the Homing Feedrate) -//#define HOMING_BACKOFF_POST_MM { 2, 2, 2 } // (mm) Backoff from endstops after homing +//#define HOMING_BACKOFF_POST_MM { 2, 2, 2 } // (linear=mm, rotational=°) Backoff from endstops after homing +//#define XY_COUNTERPART_BACKOFF_MM 0 // (mm) Backoff X after homing Y, and vice-versa //#define QUICK_HOME // If G28 contains XY do a diagonal move first //#define HOME_Y_BEFORE_X // If G28 contains XY home Y before X -//#define HOME_Z_FIRST // Home Z first. Requires a Z-MIN endstop (not a probe). +//#define HOME_Z_FIRST // Home Z first. Requires a real endstop (not a probe). //#define CODEPENDENT_XY_HOMING // If X/Y can't home without homing Y/X first // @section bltouch @@ -893,12 +932,15 @@ * Danger: Don't activate 5V mode unless attached to a 5V-tolerant controller! * V3.0 or 3.1: Set default mode to 5V mode at Marlin startup. * If disabled, OD mode is the hard-coded default on 3.0 - * On startup, Marlin will compare its eeprom to this value. If the selected mode - * differs, a mode set eeprom write will be completed at initialization. - * Use the option below to force an eeprom write to a V3.1 probe regardless. + * On startup, Marlin will compare its EEPROM to this value. If the selected mode + * differs, a mode set EEPROM write will be completed at initialization. + * Use the option below to force an EEPROM write to a V3.1 probe regardless. */ //#define BLTOUCH_SET_5V_MODE + // Safety: Enable voltage mode settings in the LCD menu. + //#define BLTOUCH_LCD_VOLTAGE_MENU + /** * Safety: Activate if connecting a probe with an unknown voltage mode. * V3.0: Set a probe into mode selected above at Marlin startup. Required for 5V mode on 3.0 @@ -917,12 +959,9 @@ */ //#define BLTOUCH_HS_MODE true - // Safety: Enable voltage mode settings in the LCD menu. - //#define BLTOUCH_LCD_VOLTAGE_MENU - #endif // BLTOUCH -// @section extras +// @section calibration /** * Z Steppers Auto-Alignment @@ -930,9 +969,12 @@ */ //#define Z_STEPPER_AUTO_ALIGN #if ENABLED(Z_STEPPER_AUTO_ALIGN) - // Define probe X and Y positions for Z1, Z2 [, Z3 [, Z4]] - // If not defined, probe limits will be used. - // Override with 'M422 S X Y' + /** + * Define probe X and Y positions for Z1, Z2 [, Z3 [, Z4]] + * These positions are machine-relative and do not shift with the M206 home offset! + * If not defined, probe limits will be used. + * Override with 'M422 S X Y'. + */ //#define Z_STEPPER_ALIGN_XY { { 10, 190 }, { 100, 10 }, { 190, 190 } } /** @@ -958,15 +1000,17 @@ //#define Z_STEPPERS_ORIENTATION 0 #endif - // Provide Z stepper positions for more rapid convergence in bed alignment. - // Requires triple stepper drivers (i.e., set NUM_Z_STEPPER_DRIVERS to 3) - //#define Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS - #if ENABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS) - // Define Stepper XY positions for Z1, Z2, Z3 corresponding to - // the Z screw positions in the bed carriage. - // Define one position per Z stepper in stepper driver order. - #define Z_STEPPER_ALIGN_STEPPER_XY { { 210.7, 102.5 }, { 152.6, 220.0 }, { 94.5, 102.5 } } - #else + /** + * Z Stepper positions for more rapid convergence in bed alignment. + * Requires 3 or 4 Z steppers. + * + * Define Stepper XY positions for Z1, Z2, Z3... corresponding to the screw + * positions in the bed carriage, with one position per Z stepper in stepper + * driver order. + */ + //#define Z_STEPPER_ALIGN_STEPPER_XY { { 210.7, 102.5 }, { 152.6, 220.0 }, { 94.5, 102.5 } } + + #ifndef Z_STEPPER_ALIGN_STEPPER_XY // Amplification factor. Used to scale the correction step up or down in case // the stepper (spindle) position is farther out than the test point. #define Z_STEPPER_ALIGN_AMP 1.0 // Use a value > 1.0 NOTE: This may cause instability! @@ -988,7 +1032,7 @@ //#define ASSISTED_TRAMMING #if ENABLED(ASSISTED_TRAMMING) - // Define positions for probe points. + // Define from 3 to 9 points to probe. #define TRAMMING_POINT_XY { { 20, 20 }, { 180, 20 }, { 180, 180 }, { 20, 180 } } // Define position names for probe points. @@ -1014,6 +1058,45 @@ #endif +// @section motion control + +/** + * Input Shaping -- EXPERIMENTAL + * + * Zero Vibration (ZV) Input Shaping for X and/or Y movements. + * + * This option uses a lot of SRAM for the step buffer. The buffer size is + * calculated automatically from SHAPING_FREQ_[XY], DEFAULT_AXIS_STEPS_PER_UNIT, + * DEFAULT_MAX_FEEDRATE and ADAPTIVE_STEP_SMOOTHING. The default calculation can + * be overridden by setting SHAPING_MIN_FREQ and/or SHAPING_MAX_FEEDRATE. + * The higher the frequency and the lower the feedrate, the smaller the buffer. + * If the buffer is too small at runtime, input shaping will have reduced + * effectiveness during high speed movements. + * + * Tune with M593 D F: + * + * D Set the zeta/damping factor. If axes (X, Y, etc.) are not specified, set for all axes. + * F Set the frequency. If axes (X, Y, etc.) are not specified, set for all axes. + * T[map] Input Shaping type, 0:ZV, 1:EI, 2:2H EI (not implemented yet) + * X<1> Set the given parameters only for the X axis. + * Y<1> Set the given parameters only for the Y axis. + */ +//#define INPUT_SHAPING_X +//#define INPUT_SHAPING_Y +#if EITHER(INPUT_SHAPING_X, INPUT_SHAPING_Y) + #if ENABLED(INPUT_SHAPING_X) + #define SHAPING_FREQ_X 40.0 // (Hz) The default dominant resonant frequency on the X axis. + #define SHAPING_ZETA_X 0.15 // Damping ratio of the X axis (range: 0.0 = no damping to 1.0 = critical damping). + #endif + #if ENABLED(INPUT_SHAPING_Y) + #define SHAPING_FREQ_Y 40.0 // (Hz) The default dominant resonant frequency on the Y axis. + #define SHAPING_ZETA_Y 0.15 // Damping ratio of the Y axis (range: 0.0 = no damping to 1.0 = critical damping). + #endif + //#define SHAPING_MIN_FREQ 20.0 // (Hz) By default the minimum of the shaping frequencies. Override to affect SRAM usage. + //#define SHAPING_MAX_STEPRATE 10000 // By default the maximum total step rate of the shaped axes. Override to affect SRAM usage. + //#define SHAPING_MENU // Add a menu to the LCD to set shaping parameters. +#endif + // @section motion #define AXIS_RELATIVE_MODES { false, false, false, false } @@ -1028,21 +1111,27 @@ #define INVERT_I_STEP_PIN false #define INVERT_J_STEP_PIN false #define INVERT_K_STEP_PIN false +#define INVERT_U_STEP_PIN false +#define INVERT_V_STEP_PIN false +#define INVERT_W_STEP_PIN false #define INVERT_E_STEP_PIN false /** * Idle Stepper Shutdown - * Set DISABLE_INACTIVE_? 'true' to shut down axis steppers after an idle period. - * The Deactive Time can be overridden with M18 and M84. Set to 0 for No Timeout. + * Enable DISABLE_IDLE_* to shut down axis steppers after an idle period. + * The default timeout duration can be overridden with M18 and M84. Set to 0 for No Timeout. */ -#define DEFAULT_STEPPER_DEACTIVE_TIME 120 -#define DISABLE_INACTIVE_X true -#define DISABLE_INACTIVE_Y true -#define DISABLE_INACTIVE_Z true // Set 'false' if the nozzle could fall onto your printed part! -#define DISABLE_INACTIVE_I true -#define DISABLE_INACTIVE_J true -#define DISABLE_INACTIVE_K true -#define DISABLE_INACTIVE_E true +#define DEFAULT_STEPPER_TIMEOUT_SEC 120 +#define DISABLE_IDLE_X +#define DISABLE_IDLE_Y +#define DISABLE_IDLE_Z // Disable if the nozzle could fall onto your printed part! +//#define DISABLE_IDLE_I +//#define DISABLE_IDLE_J +//#define DISABLE_IDLE_K +//#define DISABLE_IDLE_U +//#define DISABLE_IDLE_V +//#define DISABLE_IDLE_W +#define DISABLE_IDLE_E // Shut down all idle extruders // Default Minimum Feedrates for printing and travel moves #define DEFAULT_MINIMUMFEEDRATE 0.0 // (mm/s) Minimum feedrate. Set with M205 S. @@ -1062,11 +1151,11 @@ * XY Frequency limit * Reduce resonance by limiting the frequency of small zigzag infill moves. * See https://hydraraptor.blogspot.com/2010/12/frequency-limit.html - * Use M201 F G to change limits at runtime. + * Use M201 F S to change limits at runtime. */ //#define XY_FREQUENCY_LIMIT 10 // (Hz) Maximum frequency of small zigzag infill moves. Set with M201 F. #ifdef XY_FREQUENCY_LIMIT - #define XY_FREQUENCY_MIN_PERCENT 5 // (percent) Minimum FR percentage to apply. Set with M201 G. + #define XY_FREQUENCY_MIN_PERCENT 5 // (%) Minimum FR percentage to apply. Set with M201 S. #endif // Minimum planner junction speed. Sets the default minimum speed the planner plans for at the end @@ -1082,7 +1171,7 @@ #if ENABLED(BACKLASH_COMPENSATION) // Define values for backlash distance and correction. // If BACKLASH_GCODE is enabled these values are the defaults. - #define BACKLASH_DISTANCE_MM { 0, 0, 0 } // (mm) One value for each linear axis + #define BACKLASH_DISTANCE_MM { 0, 0, 0 } // (linear=mm, rotational=°) One value for each linear axis #define BACKLASH_CORRECTION 0.0 // 0.0 = no correction; 1.0 = full correction // Add steps for motor direction changes on CORE kinematics @@ -1111,7 +1200,7 @@ #endif /** - * Automatic backlash, position and hotend offset calibration + * Automatic backlash, position, and hotend offset calibration * * Enable G425 to run automatic calibration using an electrically- * conductive cube, bolt, or washer mounted on the bed. @@ -1139,7 +1228,7 @@ #define CALIBRATION_NOZZLE_TIP_HEIGHT 1.0 // mm #define CALIBRATION_NOZZLE_OUTER_DIAMETER 2.0 // mm - // Uncomment to enable reporting (required for "G425 V", but consumes PROGMEM). + // Uncomment to enable reporting (required for "G425 V", but consumes flash). //#define CALIBRATION_REPORTING // The true location and dimension the cube/bolt/washer on the bed. @@ -1159,9 +1248,15 @@ //#define CALIBRATION_MEASURE_JMAX //#define CALIBRATION_MEASURE_KMIN //#define CALIBRATION_MEASURE_KMAX + //#define CALIBRATION_MEASURE_UMIN + //#define CALIBRATION_MEASURE_UMAX + //#define CALIBRATION_MEASURE_VMIN + //#define CALIBRATION_MEASURE_VMAX + //#define CALIBRATION_MEASURE_WMIN + //#define CALIBRATION_MEASURE_WMAX // Probing at the exact top center only works if the center is flat. If - // probing on a screwhead or hollow washer, probe near the edges. + // probing on a screw head or hollow washer, probe near the edges. //#define CALIBRATION_MEASURE_AT_TOP_EDGES // Define the pin to read during calibration @@ -1253,7 +1348,7 @@ // @section lcd -#if ANY(HAS_LCD_MENU, EXTENSIBLE_UI, HAS_DWIN_E3V2) +#if HAS_MANUAL_MOVE_MENU #define MANUAL_FEEDRATE { 50*60, 50*60, 4*60, 2*60 } // (mm/min) Feedrates for manual moves along X, Y, Z, E from panel #define FINE_MANUAL_MOVE 0.025 // (mm) Smallest manual move (< 0.1mm) applying to Z on most machines #if IS_ULTIPANEL @@ -1276,38 +1371,47 @@ #define FEEDRATE_CHANGE_BEEP_FREQUENCY 440 #endif -#if HAS_LCD_MENU +// +// LCD Backlight Timeout +// +//#define LCD_BACKLIGHT_TIMEOUT_MINS 1 // (minutes) Timeout before turning off the backlight + +#if HAS_BED_PROBE && EITHER(HAS_MARLINUI_MENU, HAS_TFT_LVGL_UI) + //#define PROBE_OFFSET_WIZARD // Add a Probe Z Offset calibration option to the LCD menu + #if ENABLED(PROBE_OFFSET_WIZARD) + /** + * Enable to init the Probe Z-Offset when starting the Wizard. + * Use a height slightly above the estimated nozzle-to-probe Z offset. + * For example, with an offset of -5, consider a starting height of -4. + */ + //#define PROBE_OFFSET_WIZARD_START_Z -4.0 + + // Set a convenient position to do the calibration (probing point and nozzle/bed-distance) + //#define PROBE_OFFSET_WIZARD_XY_POS { X_CENTER, Y_CENTER } + #endif +#endif + +#if HAS_MARLINUI_MENU - // Add Probe Z Offset calibration to the Z Probe Offsets menu #if HAS_BED_PROBE - //#define PROBE_OFFSET_WIZARD - #if ENABLED(PROBE_OFFSET_WIZARD) - // - // Enable to init the Probe Z-Offset when starting the Wizard. - // Use a height slightly above the estimated nozzle-to-probe Z offset. - // For example, with an offset of -5, consider a starting height of -4. - // - //#define PROBE_OFFSET_WIZARD_START_Z -4.0 - - // Set a convenient position to do the calibration (probing point and nozzle/bed-distance) - //#define PROBE_OFFSET_WIZARD_XY_POS { X_CENTER, Y_CENTER } - #endif - #if ENABLED(AUTO_BED_LEVELING_BILINEAR) - // Add a calibration procedure in the Probe Offsets menu - // to compensate for twist in the X-axis. - //#define X_AXIS_TWIST_COMPENSATION - #if ENABLED(X_AXIS_TWIST_COMPENSATION) - /** - * Enable to init the Probe Z-Offset when starting the Wizard. - * Use a height slightly above the estimated nozzle-to-probe Z offset. - * For example, with an offset of -5, consider a starting height of -4. - */ - #define XATC_START_Z 0.0 - #define XATC_MAX_POINTS 3 // Number of points to probe in the wizard - #define XATC_Y_POSITION Y_CENTER // (mm) Y position to probe - #endif + // Show Deploy / Stow Probe options in the Motion menu. + #define PROBE_DEPLOY_STOW_MENU + + // Add calibration in the Probe Offsets menu to compensate for X-axis twist. + //#define X_AXIS_TWIST_COMPENSATION + #if ENABLED(X_AXIS_TWIST_COMPENSATION) + /** + * Enable to init the Probe Z-Offset when starting the Wizard. + * Use a height slightly above the estimated nozzle-to-probe Z offset. + * For example, with an offset of -5, consider a starting height of -4. + */ + #define XATC_START_Z 0.0 + #define XATC_MAX_POINTS 3 // Number of points to probe in the wizard + #define XATC_Y_POSITION Y_CENTER // (mm) Y position to probe + #define XATC_Z_OFFSETS { 0, 0, 0 } // Z offsets for X axis sample points #endif + #endif // Include a page of printer information in the LCD Main Menu @@ -1319,85 +1423,95 @@ // BACK menu items keep the highlight at the top //#define TURBO_BACK_MENU_ITEM - /** - * LED Control Menu - * Add LED Control to the LCD menu - */ - //#define LED_CONTROL_MENU - #if ENABLED(LED_CONTROL_MENU) - #define LED_COLOR_PRESETS // Enable the Preset Color menu option - //#define NEO2_COLOR_PRESETS // Enable a second NeoPixel Preset Color menu option - #if ENABLED(LED_COLOR_PRESETS) - #define LED_USER_PRESET_RED 255 // User defined RED value - #define LED_USER_PRESET_GREEN 128 // User defined GREEN value - #define LED_USER_PRESET_BLUE 0 // User defined BLUE value - #define LED_USER_PRESET_WHITE 255 // User defined WHITE value - #define LED_USER_PRESET_BRIGHTNESS 255 // User defined intensity - //#define LED_USER_PRESET_STARTUP // Have the printer display the user preset color on startup - #endif - #if ENABLED(NEO2_COLOR_PRESETS) - #define NEO2_USER_PRESET_RED 255 // User defined RED value - #define NEO2_USER_PRESET_GREEN 128 // User defined GREEN value - #define NEO2_USER_PRESET_BLUE 0 // User defined BLUE value - #define NEO2_USER_PRESET_WHITE 255 // User defined WHITE value - #define NEO2_USER_PRESET_BRIGHTNESS 255 // User defined intensity - //#define NEO2_USER_PRESET_STARTUP // Have the printer display the user preset color on startup for the second strip - #endif - #endif - // Insert a menu for preheating at the top level to allow for quick access //#define PREHEAT_SHORTCUT_MENU_ITEM -#endif // HAS_LCD_MENU +#endif // HAS_MARLINUI_MENU -#if ANY(HAS_DISPLAY, DWIN_CREALITY_LCD_ENHANCED, DWIN_CREALITY_LCD_JYERSUI) +#if ANY(HAS_DISPLAY, DWIN_LCD_PROUI, DWIN_CREALITY_LCD_JYERSUI) //#define SOUND_MENU_ITEM // Add a mute option to the LCD menu + #define SOUND_ON_DEFAULT // Buzzer/speaker default enabled state #endif -#if EITHER(HAS_DISPLAY, DWIN_CREALITY_LCD_ENHANCED) - // The timeout (in ms) to return to the status screen from sub-menus - //#define LCD_TIMEOUT_TO_STATUS 15000 +#if EITHER(HAS_DISPLAY, DWIN_LCD_PROUI) + // The timeout to return to the status screen from sub-menus + #define LCD_TIMEOUT_TO_STATUS 60000 // (ms) #if ENABLED(SHOW_BOOTSCREEN) - #define BOOTSCREEN_TIMEOUT 4000 // (ms) Total Duration to display the boot screen(s) + #define BOOTSCREEN_TIMEOUT 3000 // (ms) Total Duration to display the boot screen(s) #if EITHER(HAS_MARLINUI_U8GLIB, TFT_COLOR_UI) - #define BOOT_MARLIN_LOGO_SMALL // Show a smaller Marlin logo on the Boot Screen (saving lots of flash) + #define BOOT_MARLIN_LOGO_SMALL // Show a smaller Marlin logo on the Boot Screen (saving lots of flash) #endif #endif // Scroll a longer status message into view //#define STATUS_MESSAGE_SCROLLING + // Apply a timeout to low-priority status messages + //#define STATUS_MESSAGE_TIMEOUT_SEC 30 // (seconds) + // On the Info Screen, display XY with one decimal place when possible //#define LCD_DECIMAL_SMALL_XY - // Add an 'M73' G-code to set the current percentage - //#define LCD_SET_PROGRESS_MANUALLY - // Show the E position (filament used) during printing //#define LCD_SHOW_E_TOTAL -#endif -// LCD Print Progress options -#if EITHER(SDSUPPORT, LCD_SET_PROGRESS_MANUALLY) - #if CAN_SHOW_REMAINING_TIME - //#define SHOW_REMAINING_TIME // Display estimated time to completion - #if ENABLED(SHOW_REMAINING_TIME) - //#define USE_M73_REMAINING_TIME // Use remaining time from M73 command instead of estimation - //#define ROTATE_PROGRESS_DISPLAY // Display (P)rogress, (E)lapsed, and (R)emaining time + /** + * LED Control Menu + * Add LED Control to the LCD menu + */ + //#define LED_CONTROL_MENU + #if ENABLED(LED_CONTROL_MENU) + #define LED_COLOR_PRESETS // Enable the Preset Color menu option + //#define NEO2_COLOR_PRESETS // Enable a second NeoPixel Preset Color menu option + #if ENABLED(LED_COLOR_PRESETS) + #define LED_USER_PRESET_RED 255 // User defined RED value + #define LED_USER_PRESET_GREEN 128 // User defined GREEN value + #define LED_USER_PRESET_BLUE 0 // User defined BLUE value + #define LED_USER_PRESET_WHITE 255 // User defined WHITE value + #define LED_USER_PRESET_BRIGHTNESS 255 // User defined intensity + //#define LED_USER_PRESET_STARTUP // Have the printer display the user preset color on startup + #endif + #if ENABLED(NEO2_COLOR_PRESETS) + #define NEO2_USER_PRESET_RED 255 // User defined RED value + #define NEO2_USER_PRESET_GREEN 128 // User defined GREEN value + #define NEO2_USER_PRESET_BLUE 0 // User defined BLUE value + #define NEO2_USER_PRESET_WHITE 255 // User defined WHITE value + #define NEO2_USER_PRESET_BRIGHTNESS 255 // User defined intensity + //#define NEO2_USER_PRESET_STARTUP // Have the printer display the user preset color on startup for the second strip #endif #endif - #if EITHER(HAS_MARLINUI_U8GLIB, EXTENSIBLE_UI) - //#define PRINT_PROGRESS_SHOW_DECIMALS // Show progress with decimal digits +#endif // HAS_DISPLAY || DWIN_LCD_PROUI + +// Add 'M73' to set print job progress, overrides Marlin's built-in estimate +//#define SET_PROGRESS_MANUALLY +#if ENABLED(SET_PROGRESS_MANUALLY) + #define SET_PROGRESS_PERCENT // Add 'P' parameter to set percentage done + #define SET_REMAINING_TIME // Add 'R' parameter to set remaining time + //#define SET_INTERACTION_TIME // Add 'C' parameter to set time until next filament change or other user interaction + //#define M73_REPORT // Report M73 values to host + #if BOTH(M73_REPORT, SDSUPPORT) + #define M73_REPORT_SD_ONLY // Report only when printing from SD + #endif +#endif + +// LCD Print Progress options. Multiple times may be displayed in turn. +#if HAS_DISPLAY && EITHER(SDSUPPORT, SET_PROGRESS_MANUALLY) + #define SHOW_PROGRESS_PERCENT // Show print progress percentage (doesn't affect progress bar) + #define SHOW_ELAPSED_TIME // Display elapsed printing time (prefix 'E') + //#define SHOW_REMAINING_TIME // Display estimated time to completion (prefix 'R') + #if ENABLED(SET_INTERACTION_TIME) + #define SHOW_INTERACTION_TIME // Display time until next user interaction ('C' = filament change) #endif + //#define PRINT_PROGRESS_SHOW_DECIMALS // Show/report progress with decimal digits, not all UIs support this #if EITHER(HAS_MARLINUI_HD44780, IS_TFTGLCD_PANEL) //#define LCD_PROGRESS_BAR // Show a progress bar on HD44780 LCDs for SD printing #if ENABLED(LCD_PROGRESS_BAR) #define PROGRESS_BAR_BAR_TIME 2000 // (ms) Amount of time to show the bar #define PROGRESS_BAR_MSG_TIME 3000 // (ms) Amount of time to show the status message - #define PROGRESS_MSG_EXPIRE 0 // (ms) Amount of time to retain the status message (0=forever) + #define PROGRESS_MSG_EXPIRE 0 // (ms) Amount of time to retain the status message (0=forever) //#define PROGRESS_MSG_ONCE // Show the message for MSG_TIME then clear it //#define LCD_PROGRESS_BAR_TEST // Add a menu item to test the progress bar #endif @@ -1508,8 +1622,8 @@ // SD Card Sorting options #if ENABLED(SDCARD_SORT_ALPHA) #define SDSORT_LIMIT 40 // Maximum number of sorted items (10-256). Costs 27 bytes each. - #define FOLDER_SORTING -1 // -1=above 0=none 1=below - #define SDSORT_GCODE false // Allow turning sorting on/off with LCD and M34 G-code. + #define SDSORT_FOLDERS -1 // -1=above 0=none 1=below + #define SDSORT_GCODE false // Enable G-code M34 to set sorting behaviors: M34 S<-1|0|1> F<-1|0|1> #define SDSORT_USES_RAM false // Pre-allocate a static array for faster pre-sorting. #define SDSORT_USES_STACK false // Prefer the stack for pre-sorting to give back some SRAM. (Negated by next 2 options.) #define SDSORT_CACHE_NAMES false // Keep sorted items in RAM longer for speedy performance. Most expensive option. @@ -1522,33 +1636,27 @@ // LCD's font must contain the characters. Check your selected LCD language. //#define UTF_FILENAME_SUPPORT - // This allows hosts to request long names for files and folders with M33 - //#define LONG_FILENAME_HOST_SUPPORT + //#define LONG_FILENAME_HOST_SUPPORT // Get the long filename of a file/folder with 'M33 ' and list long filenames with 'M20 L' + //#define LONG_FILENAME_WRITE_SUPPORT // Create / delete files with long filenames via M28, M30, and Binary Transfer Protocol + //#define M20_TIMESTAMP_SUPPORT // Include timestamps by adding the 'T' flag to M20 commands - // Enable this option to scroll long filenames in the SD card menu - //#define SCROLL_LONG_FILENAMES + //#define SCROLL_LONG_FILENAMES // Scroll long filenames in the SD card menu - // Leave the heaters on after Stop Print (not recommended!) - //#define SD_ABORT_NO_COOLDOWN + //#define SD_ABORT_NO_COOLDOWN // Leave the heaters on after Stop Print (not recommended!) /** - * This option allows you to abort SD printing when any endstop is triggered. - * This feature must be enabled with "M540 S1" or from the LCD menu. - * To have any effect, endstops must be enabled during SD printing. + * Abort SD printing when any endstop is triggered. + * This feature is enabled with 'M540 S1' or from the LCD menu. + * Endstops must be activated for this option to work. */ //#define SD_ABORT_ON_ENDSTOP_HIT + #if ENABLED(SD_ABORT_ON_ENDSTOP_HIT) + //#define SD_ABORT_ON_ENDSTOP_HIT_GCODE "G28XY" // G-code to run on endstop hit (e.g., "G28XY" or "G27") + #endif - /** - * This option makes it easier to print the same SD Card file again. - * On print completion the LCD Menu will open with the file selected. - * You can just click to start the print, or navigate elsewhere. - */ - //#define SD_REPRINT_LAST_SELECTED_FILE + //#define SD_REPRINT_LAST_SELECTED_FILE // On print completion open the LCD Menu and select the same file - /** - * Auto-report SdCard status with M27 S - */ - //#define AUTO_REPORT_SD_STATUS + //#define AUTO_REPORT_SD_STATUS // Auto-report media status with 'M27 S' /** * Support for USB thumb drives using an Arduino USB Host Shield or @@ -1579,6 +1687,8 @@ //#define USE_UHS2_USB //#define USE_UHS3_USB + #define DISABLE_DUE_SD_MMC // Disable USB Host access to USB Drive to prevent hangs on block access for DUE platform + /** * Native USB Host supported by some boards (USB OTG) */ @@ -1617,6 +1727,11 @@ // Add an optimized binary file transfer mode, initiated with 'M28 B1' //#define BINARY_FILE_TRANSFER + #if ENABLED(BINARY_FILE_TRANSFER) + // Include extra facilities (e.g., 'M20 F') supporting firmware upload via BINARY_FILE_TRANSFER + //#define CUSTOM_FIRMWARE_UPLOAD + #endif + /** * Set this option to one of the following (or the board's defaults apply): * @@ -1631,7 +1746,10 @@ // Enable if SD detect is rendered useless (e.g., by using an SD extender) //#define NO_SD_DETECT - // Multiple volume support - EXPERIMENTAL. + /** + * Multiple volume support - EXPERIMENTAL. + * Adds 'M21 Pm' / 'M21 S' / 'M21 U' to mount SD Card / USB Drive. + */ //#define MULTI_VOLUME #if ENABLED(MULTI_VOLUME) #define VOLUME_SD_ONBOARD @@ -1665,14 +1783,25 @@ //#define XYZ_NO_FRAME #define XYZ_HOLLOW_FRAME - // A bigger font is available for edit items. Costs 3120 bytes of PROGMEM. + // A bigger font is available for edit items. Costs 3120 bytes of flash. // Western only. Not available for Cyrillic, Kana, Turkish, Greek, or Chinese. //#define USE_BIG_EDIT_FONT - // A smaller font may be used on the Info Screen. Costs 2434 bytes of PROGMEM. + // A smaller font may be used on the Info Screen. Costs 2434 bytes of flash. // Western only. Not available for Cyrillic, Kana, Turkish, Greek, or Chinese. //#define USE_SMALL_INFOFONT + /** + * Graphical Display Sleep + * + * The U8G library provides sleep / wake functions for SH1106, SSD1306, + * SSD1309, and some other DOGM displays. + * Enable this option to save energy and prevent OLED pixel burn-in. + * Adds the menu item Configuration > LCD Timeout (m) to set a wait period + * from 0 (disabled) to 99 minutes. + */ + //#define DISPLAY_SLEEP_MINUTES 2 // (minutes) Timeout before turning off the screen. Set with M255 S. + /** * ST7920-based LCDs can emulate a 16 x 4 character display using * the ST7920 character-generator for very fast screen updates. @@ -1697,7 +1826,7 @@ #endif /** - * Status (Info) Screen customizations + * Status (Info) Screen customization * These options may affect code size and screen render time. * Custom status screens can forcibly override these settings. */ @@ -1714,7 +1843,7 @@ //#define STATUS_ALT_FAN_BITMAP // Use the alternative fan bitmap //#define STATUS_FAN_FRAMES 3 // :[0,1,2,3,4] Number of fan animation frames //#define STATUS_HEAT_PERCENT // Show heating in a progress bar - //#define BOOT_MARLIN_LOGO_ANIMATED // Animated Marlin logo. Costs ~3260 (or ~940) bytes of PROGMEM. + //#define BOOT_MARLIN_LOGO_ANIMATED // Animated Marlin logo. Costs ~3260 (or ~940) bytes of flash. // Frivolous Game Options //#define MARLIN_BRICKOUT @@ -1725,21 +1854,14 @@ #endif // HAS_MARLINUI_U8GLIB #if HAS_MARLINUI_U8GLIB || IS_DWIN_MARLINUI - // Show SD percentage next to the progress bar - //#define SHOW_SD_PERCENT - - // Enable to save many cycles by drawing a hollow frame on Menu Screens - #define MENU_HOLLOW_FRAME - - // Swap the CW/CCW indicators in the graphics overlay - //#define OVERLAY_GFX_REVERSE + #define MENU_HOLLOW_FRAME // Enable to save many cycles by drawing a hollow frame on Menu Screens + //#define OVERLAY_GFX_REVERSE // Swap the CW/CCW indicators in the graphics overlay #endif // // Additional options for DGUS / DWIN displays // #if HAS_DGUS_LCD - #define LCD_SERIAL_PORT 3 #define LCD_BAUDRATE 115200 #define DGUS_RX_BUFFER_SIZE 128 @@ -1946,7 +2068,7 @@ #if ENABLED(BABYSTEPPING) //#define INTEGRATED_BABYSTEPPING // EXPERIMENTAL integration of babystepping into the Stepper ISR //#define BABYSTEP_WITHOUT_HOMING - //#define BABYSTEP_ALWAYS_AVAILABLE // Allow babystepping at all times (not just during movement). + //#define BABYSTEP_ALWAYS_AVAILABLE // Allow babystepping at all times (not just during movement) //#define BABYSTEP_XY // Also enable X/Y Babystepping. Not supported on DELTA! #define BABYSTEP_INVERT_Z false // Change if Z babysteps should go the other way //#define BABYSTEP_MILLIMETER_UNITS // Specify BABYSTEP_MULTIPLICATOR_(XY|Z) in mm instead of micro-steps @@ -1957,7 +2079,7 @@ #if ENABLED(DOUBLECLICK_FOR_Z_BABYSTEPPING) #define DOUBLECLICK_MAX_INTERVAL 1250 // Maximum interval between clicks, in milliseconds. // Note: Extra time may be added to mitigate controller latency. - //#define MOVE_Z_WHEN_IDLE // Jump to the move Z menu on doubleclick when printer is idle. + //#define MOVE_Z_WHEN_IDLE // Jump to the move Z menu on double-click when printer is idle. #if ENABLED(MOVE_Z_WHEN_IDLE) #define MOVE_Z_IDLE_MULTIPLICATOR 1 // Multiply 1mm by this factor for the move step size. #endif @@ -1991,15 +2113,34 @@ */ //#define LIN_ADVANCE #if ENABLED(LIN_ADVANCE) - //#define EXTRA_LIN_ADVANCE_K // Enable for second linear advance constants - #define LIN_ADVANCE_K 0.22 // Unit: mm compression per 1mm/s extruder speed - //#define LA_DEBUG // If enabled, this will generate debug information output over USB. - //#define EXPERIMENTAL_SCURVE // Enable this option to permit S-Curve Acceleration - //#define ALLOW_LOW_EJERK // Allow a DEFAULT_EJERK value of <10. Recommended for direct drive hotends. + #if ENABLED(DISTINCT_E_FACTORS) + #define ADVANCE_K { 0.22 } // (mm) Compression length per 1mm/s extruder speed, per extruder + #else + #define ADVANCE_K 0.22 // (mm) Compression length applying to all extruders + #endif + //#define ADVANCE_K_EXTRA // Add a second linear advance constant, configurable with M900 L. + //#define LA_DEBUG // Print debug information to serial during operation. Disable for production use. + //#define ALLOW_LOW_EJERK // Allow a DEFAULT_EJERK value of <10. Recommended for direct drive hotends. + //#define EXPERIMENTAL_I2S_LA // Allow I2S_STEPPER_STREAM to be used with LA. Performance degrades as the LA step rate reaches ~20kHz. #endif // @section leveling +/** + * Use Safe Bed Leveling coordinates to move axes to a useful position before bed probing. + * For example, after homing a rotational axis the Z probe might not be perpendicular to the bed. + * Choose values the orient the bed horizontally and the Z-probe vertically. + */ +//#define SAFE_BED_LEVELING_START_X 0.0 +//#define SAFE_BED_LEVELING_START_Y 0.0 +//#define SAFE_BED_LEVELING_START_Z 0.0 +//#define SAFE_BED_LEVELING_START_I 0.0 +//#define SAFE_BED_LEVELING_START_J 0.0 +//#define SAFE_BED_LEVELING_START_K 0.0 +//#define SAFE_BED_LEVELING_START_U 0.0 +//#define SAFE_BED_LEVELING_START_V 0.0 +//#define SAFE_BED_LEVELING_START_W 0.0 + /** * Points to probe for all 3-point Leveling procedures. * Override if the automatically selected points are inadequate. @@ -2069,6 +2210,8 @@ #endif +// @section probes + /** * Thermal Probe Compensation * @@ -2131,7 +2274,7 @@ // Height above Z=0.0 to raise the nozzle. Lowering this can help the probe to heat faster. // Note: The Z=0.0 offset is determined by the probe Z offset (e.g., as set with M851 Z). - #define PTC_PROBE_HEATING_OFFSET 0.5 + #define PTC_PROBE_HEATING_OFFSET 0.5 // (mm) #endif #endif // PTC_PROBE || PTC_BED || PTC_HOTEND @@ -2186,6 +2329,8 @@ #define G38_MINIMUM_MOVE 0.0275 // (mm) Minimum distance that will produce a move. #endif +// @section motion + // Moves (or segments) with fewer steps than this will be joined with the next move #define MIN_STEPS_PER_SEGMENT 6 @@ -2241,7 +2386,7 @@ //================================= Buffers ================================= //=========================================================================== -// @section motion +// @section gcode // The number of linear moves that can be in the planner at once. // The value of BLOCK_BUFFER_SIZE must be a power of 2 (e.g., 8, 16, 32) @@ -2260,7 +2405,7 @@ #define BUFSIZE 4 // Transmission to Host Buffer Size -// To save 386 bytes of PROGMEM (and TX_BUFFER_SIZE+3 bytes of RAM) set to 0. +// To save 386 bytes of flash (and TX_BUFFER_SIZE+3 bytes of RAM) set to 0. // To buffer a simple "ok" you need 4 bytes. // For ADVANCED_OK (M105) you need 32 bytes. // For debug-echo: 128 bytes for the optimal speed. @@ -2326,11 +2471,13 @@ //#define FULL_REPORT_TO_HOST_FEATURE // Auto-report the machine status like Grbl CNC #endif -// Bad Serial-connections can miss a received command by sending an 'ok' -// Therefore some clients abort after 30 seconds in a timeout. -// Some other clients start sending commands while receiving a 'wait'. -// This "wait" is only sent when the buffer is empty. 1 second is a good value here. -//#define NO_TIMEOUTS 1000 // Milliseconds +/** + * Bad Serial-connections can miss a received command by sending an 'ok' + * Therefore some clients abort after 30 seconds in a timeout. + * Some other clients start sending commands while receiving a 'wait'. + * This "wait" is only sent when the buffer is empty. 1 second is a good value here. + */ +//#define NO_TIMEOUTS 1000 // (ms) // Some clients will have this feature soon. This could make the NO_TIMEOUTS unnecessary. //#define ADVANCED_OK @@ -2342,6 +2489,15 @@ // For serial echo, the number of digits after the decimal point //#define SERIAL_FLOAT_PRECISION 4 +/** + * Set the number of proportional font spaces required to fill up a typical character space. + * This can help to better align the output of commands like 'G29 O' Mesh Output. + * + * For clients that use a fixed-width font (like OctoPrint), leave this set to 1.0. + * Otherwise, adjust according to your client and font. + */ +#define PROPORTIONAL_FONT_RATIO 1.0 + // @section extras /** @@ -2353,6 +2509,8 @@ */ //#define EXTRA_FAN_SPEED +// @section gcode + /** * Firmware-based and LCD-controlled retract * @@ -2387,6 +2545,8 @@ #endif #endif +// @section tool change + /** * Universal tool change settings. * Applies to all types of extruders except where explicitly noted. @@ -2402,11 +2562,11 @@ /** * Extra G-code to run while executing tool-change commands. Can be used to use an additional - * stepper motor (I axis, see option LINEAR_AXES in Configuration.h) to drive the tool-changer. + * stepper motor (e.g., I axis 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 - //#define EVENT_GCODE_TOOLCHANGE_ALWAYS_RUN // Always execute above G-code sequences. Use with caution! + //#define EVENT_GCODE_TOOLCHANGE_T0 "G28 A\nG1 A0" // Extra G-code to run while executing tool-change command T0 + //#define EVENT_GCODE_TOOLCHANGE_T1 "G1 A10" // Extra G-code to run while executing tool-change command T1 + //#define EVENT_GCODE_TOOLCHANGE_ALWAYS_RUN // Always execute above G-code sequences. Use with caution! /** * Tool Sensors detect when tools have been picked up or dropped. @@ -2422,26 +2582,30 @@ #if ENABLED(TOOLCHANGE_FILAMENT_SWAP) // Load / Unload #define TOOLCHANGE_FS_LENGTH 12 // (mm) Load / Unload length - #define TOOLCHANGE_FS_EXTRA_RESUME_LENGTH 0 // (mm) Extra length for better restart, fine tune by LCD/Gcode) + #define TOOLCHANGE_FS_EXTRA_RESUME_LENGTH 0 // (mm) Extra length for better restart. Adjust with LCD or M217 B. #define TOOLCHANGE_FS_RETRACT_SPEED (50*60) // (mm/min) (Unloading) #define TOOLCHANGE_FS_UNRETRACT_SPEED (25*60) // (mm/min) (On SINGLENOZZLE or Bowden loading must be slowed down) // Longer prime to clean out a SINGLENOZZLE #define TOOLCHANGE_FS_EXTRA_PRIME 0 // (mm) Extra priming length #define TOOLCHANGE_FS_PRIME_SPEED (4.6*60) // (mm/min) Extra priming feedrate - #define TOOLCHANGE_FS_WIPE_RETRACT 0 // (mm) Retract before cooling for less stringing, better wipe, etc. + #define TOOLCHANGE_FS_WIPE_RETRACT 0 // (mm) Cutting retraction out of park, for less stringing, better wipe, etc. Adjust with LCD or M217 G. // Cool after prime to reduce stringing #define TOOLCHANGE_FS_FAN -1 // Fan index or -1 to skip #define TOOLCHANGE_FS_FAN_SPEED 255 // 0-255 #define TOOLCHANGE_FS_FAN_TIME 10 // (seconds) - // Swap uninitialized extruder with TOOLCHANGE_FS_PRIME_SPEED for all lengths (recover + prime) - // (May break filament if not retracted beforehand.) - //#define TOOLCHANGE_FS_INIT_BEFORE_SWAP + // Use TOOLCHANGE_FS_PRIME_SPEED feedrate the first time each extruder is primed + //#define TOOLCHANGE_FS_SLOW_FIRST_PRIME - // Prime on the first T0 (If other, TOOLCHANGE_FS_INIT_BEFORE_SWAP applied) - // Enable it (M217 V[0/1]) before printing, to avoid unwanted priming on host connect + /** + * Prime T0 the first time T0 is sent to the printer: + * [ Power-On -> T0 { Activate & Prime T0 } -> T1 { Retract T0, Activate & Prime T1 } ] + * If disabled, no priming on T0 until switching back to T0 from another extruder: + * [ Power-On -> T0 { T0 Activated } -> T1 { Activate & Prime T1 } -> T0 { Retract T1, Activate & Prime T0 } ] + * Enable with M217 V1 before printing to avoid unwanted priming on host connect. + */ //#define TOOLCHANGE_FS_PRIME_FIRST_USED /** @@ -2471,6 +2635,8 @@ #endif #endif // HAS_MULTI_EXTRUDER +// @section advanced pause + /** * Advanced Pause for Filament Change * - Adds the G-code M600 Filament Change to initiate a filament change. @@ -2529,151 +2695,33 @@ //#define FILAMENT_UNLOAD_ALL_EXTRUDERS // Allow M702 to unload all extruders above a minimum target temp (as set by M302) #endif -// @section tmc - -/** - * TMC26X Stepper Driver options - * - * The TMC26XStepper library is required for this stepper driver. - * https://github.com/trinamic/TMC26XStepper - */ -#if HAS_DRIVER(TMC26X) - - #if AXIS_DRIVER_TYPE_X(TMC26X) - #define X_MAX_CURRENT 1000 // (mA) - #define X_SENSE_RESISTOR 91 // (mOhms) - #define X_MICROSTEPS 16 // Number of microsteps - #endif - - #if AXIS_DRIVER_TYPE_X2(TMC26X) - #define X2_MAX_CURRENT 1000 - #define X2_SENSE_RESISTOR 91 - #define X2_MICROSTEPS X_MICROSTEPS - #endif - - #if AXIS_DRIVER_TYPE_Y(TMC26X) - #define Y_MAX_CURRENT 1000 - #define Y_SENSE_RESISTOR 91 - #define Y_MICROSTEPS 16 - #endif - - #if AXIS_DRIVER_TYPE_Y2(TMC26X) - #define Y2_MAX_CURRENT 1000 - #define Y2_SENSE_RESISTOR 91 - #define Y2_MICROSTEPS Y_MICROSTEPS - #endif - - #if AXIS_DRIVER_TYPE_Z(TMC26X) - #define Z_MAX_CURRENT 1000 - #define Z_SENSE_RESISTOR 91 - #define Z_MICROSTEPS 16 - #endif - - #if AXIS_DRIVER_TYPE_Z2(TMC26X) - #define Z2_MAX_CURRENT 1000 - #define Z2_SENSE_RESISTOR 91 - #define Z2_MICROSTEPS Z_MICROSTEPS - #endif - - #if AXIS_DRIVER_TYPE_Z3(TMC26X) - #define Z3_MAX_CURRENT 1000 - #define Z3_SENSE_RESISTOR 91 - #define Z3_MICROSTEPS Z_MICROSTEPS - #endif - - #if AXIS_DRIVER_TYPE_Z4(TMC26X) - #define Z4_MAX_CURRENT 1000 - #define Z4_SENSE_RESISTOR 91 - #define Z4_MICROSTEPS Z_MICROSTEPS - #endif - - #if AXIS_DRIVER_TYPE_I(TMC26X) - #define I_MAX_CURRENT 1000 - #define I_SENSE_RESISTOR 91 - #define I_MICROSTEPS 16 - #endif - - #if AXIS_DRIVER_TYPE_J(TMC26X) - #define J_MAX_CURRENT 1000 - #define J_SENSE_RESISTOR 91 - #define J_MICROSTEPS 16 - #endif - - #if AXIS_DRIVER_TYPE_K(TMC26X) - #define K_MAX_CURRENT 1000 - #define K_SENSE_RESISTOR 91 - #define K_MICROSTEPS 16 - #endif - - #if AXIS_DRIVER_TYPE_E0(TMC26X) - #define E0_MAX_CURRENT 1000 - #define E0_SENSE_RESISTOR 91 - #define E0_MICROSTEPS 16 - #endif - - #if AXIS_DRIVER_TYPE_E1(TMC26X) - #define E1_MAX_CURRENT 1000 - #define E1_SENSE_RESISTOR 91 - #define E1_MICROSTEPS E0_MICROSTEPS - #endif - - #if AXIS_DRIVER_TYPE_E2(TMC26X) - #define E2_MAX_CURRENT 1000 - #define E2_SENSE_RESISTOR 91 - #define E2_MICROSTEPS E0_MICROSTEPS - #endif - - #if AXIS_DRIVER_TYPE_E3(TMC26X) - #define E3_MAX_CURRENT 1000 - #define E3_SENSE_RESISTOR 91 - #define E3_MICROSTEPS E0_MICROSTEPS - #endif - - #if AXIS_DRIVER_TYPE_E4(TMC26X) - #define E4_MAX_CURRENT 1000 - #define E4_SENSE_RESISTOR 91 - #define E4_MICROSTEPS E0_MICROSTEPS - #endif - - #if AXIS_DRIVER_TYPE_E5(TMC26X) - #define E5_MAX_CURRENT 1000 - #define E5_SENSE_RESISTOR 91 - #define E5_MICROSTEPS E0_MICROSTEPS - #endif - - #if AXIS_DRIVER_TYPE_E6(TMC26X) - #define E6_MAX_CURRENT 1000 - #define E6_SENSE_RESISTOR 91 - #define E6_MICROSTEPS E0_MICROSTEPS - #endif - - #if AXIS_DRIVER_TYPE_E7(TMC26X) - #define E7_MAX_CURRENT 1000 - #define E7_SENSE_RESISTOR 91 - #define E7_MICROSTEPS E0_MICROSTEPS - #endif - -#endif // TMC26X - // @section tmc_smart /** - * To use TMC2130, TMC2160, TMC2660, TMC5130, TMC5160 stepper drivers in SPI mode - * connect your SPI pins to the hardware SPI interface on your board and define - * the required CS pins in your `pins_MYBOARD.h` file. (e.g., RAMPS 1.4 uses AUX3 - * pins `X_CS_PIN 53`, `Y_CS_PIN 49`, etc.). - * You may also use software SPI if you wish to use general purpose IO pins. + * Trinamic Smart Drivers * - * To use TMC2208 stepper UART-configurable stepper drivers connect #_SERIAL_TX_PIN - * to the driver side PDN_UART pin with a 1K resistor. - * To use the reading capabilities, also connect #_SERIAL_RX_PIN to PDN_UART without - * a resistor. - * The drivers can also be used with hardware serial. + * To use TMC2130, TMC2160, TMC2660, TMC5130, TMC5160 stepper drivers in SPI mode: + * - Connect your SPI pins to the Hardware SPI interface on the board. + * Some boards have simple jumper connections! See your board's documentation. + * - Define the required Stepper CS pins in your `pins_MYBOARD.h` file. + * (See the RAMPS pins, for example.) + * - You can also use Software SPI with GPIO pins instead of Hardware SPI. * - * TMCStepper library is required to use TMC stepper drivers. - * https://github.com/teemuatlut/TMCStepper + * To use TMC220x stepper drivers with Serial UART: + * - Connect PDN_UART to the #_SERIAL_TX_PIN through a 1K resistor. + * For reading capabilities also connect PDN_UART to #_SERIAL_RX_PIN with no resistor. + * Some boards have simple jumper connections! See your board's documentation. + * - These drivers can also be used with Hardware Serial. + * + * The TMC26XStepper library is required for TMC26X stepper drivers. + * https://github.com/MarlinFirmware/TMC26XStepper + * + * The TMCStepper library is required for other TMC stepper drivers. + * https://github.com/teemuatlut/TMCStepper + * + * @section tmc/config */ -#if HAS_TRINAMIC_CONFIG +#if HAS_TRINAMIC_CONFIG || HAS_TMC26X #define HOLD_MULTIPLIER 0.5 // Scales down the holding current from run current @@ -2683,27 +2731,27 @@ */ #define INTERPOLATE true - #if AXIS_IS_TMC(X) + #if AXIS_IS_TMC_CONFIG(X) #define X_CURRENT 800 // (mA) RMS current. Multiply by 1.414 for peak current. - #define X_CURRENT_HOME X_CURRENT // (mA) RMS current for sensorless homing + #define X_CURRENT_HOME X_CURRENT // (mA) RMS current for homing. (Typically lower than *_CURRENT.) #define X_MICROSTEPS 16 // 0..256 - #define X_RSENSE 0.11 + #define X_RSENSE 0.11 // Multiplied x1000 for TMC26X #define X_CHAIN_POS -1 // -1..0: Not chained. 1: MCU MOSI connected. 2: Next in chain, ... //#define X_INTERPOLATE true // Enable to override 'INTERPOLATE' for the X axis //#define X_HOLD_MULTIPLIER 0.5 // Enable to override 'HOLD_MULTIPLIER' for the X axis #endif - #if AXIS_IS_TMC(X2) - #define X2_CURRENT 800 - #define X2_CURRENT_HOME X2_CURRENT - #define X2_MICROSTEPS X_MICROSTEPS - #define X2_RSENSE 0.11 + #if AXIS_IS_TMC_CONFIG(X2) + #define X2_CURRENT X_CURRENT + #define X2_CURRENT_HOME X_CURRENT_HOME + #define X2_MICROSTEPS X_MICROSTEPS + #define X2_RSENSE X_RSENSE #define X2_CHAIN_POS -1 //#define X2_INTERPOLATE true //#define X2_HOLD_MULTIPLIER 0.5 #endif - #if AXIS_IS_TMC(Y) + #if AXIS_IS_TMC_CONFIG(Y) #define Y_CURRENT 800 #define Y_CURRENT_HOME Y_CURRENT #define Y_MICROSTEPS 16 @@ -2713,17 +2761,17 @@ //#define Y_HOLD_MULTIPLIER 0.5 #endif - #if AXIS_IS_TMC(Y2) - #define Y2_CURRENT 800 - #define Y2_CURRENT_HOME Y2_CURRENT - #define Y2_MICROSTEPS Y_MICROSTEPS - #define Y2_RSENSE 0.11 + #if AXIS_IS_TMC_CONFIG(Y2) + #define Y2_CURRENT Y_CURRENT + #define Y2_CURRENT_HOME Y_CURRENT_HOME + #define Y2_MICROSTEPS Y_MICROSTEPS + #define Y2_RSENSE Y_RSENSE #define Y2_CHAIN_POS -1 //#define Y2_INTERPOLATE true //#define Y2_HOLD_MULTIPLIER 0.5 #endif - #if AXIS_IS_TMC(Z) + #if AXIS_IS_TMC_CONFIG(Z) #define Z_CURRENT 800 #define Z_CURRENT_HOME Z_CURRENT #define Z_MICROSTEPS 16 @@ -2733,37 +2781,37 @@ //#define Z_HOLD_MULTIPLIER 0.5 #endif - #if AXIS_IS_TMC(Z2) - #define Z2_CURRENT 800 - #define Z2_CURRENT_HOME Z2_CURRENT - #define Z2_MICROSTEPS Z_MICROSTEPS - #define Z2_RSENSE 0.11 + #if AXIS_IS_TMC_CONFIG(Z2) + #define Z2_CURRENT Z_CURRENT + #define Z2_CURRENT_HOME Z_CURRENT_HOME + #define Z2_MICROSTEPS Z_MICROSTEPS + #define Z2_RSENSE Z_RSENSE #define Z2_CHAIN_POS -1 //#define Z2_INTERPOLATE true //#define Z2_HOLD_MULTIPLIER 0.5 #endif - #if AXIS_IS_TMC(Z3) - #define Z3_CURRENT 800 - #define Z3_CURRENT_HOME Z3_CURRENT - #define Z3_MICROSTEPS Z_MICROSTEPS - #define Z3_RSENSE 0.11 + #if AXIS_IS_TMC_CONFIG(Z3) + #define Z3_CURRENT Z_CURRENT + #define Z3_CURRENT_HOME Z_CURRENT_HOME + #define Z3_MICROSTEPS Z_MICROSTEPS + #define Z3_RSENSE Z_RSENSE #define Z3_CHAIN_POS -1 //#define Z3_INTERPOLATE true //#define Z3_HOLD_MULTIPLIER 0.5 #endif - #if AXIS_IS_TMC(Z4) - #define Z4_CURRENT 800 - #define Z4_CURRENT_HOME Z4_CURRENT - #define Z4_MICROSTEPS Z_MICROSTEPS - #define Z4_RSENSE 0.11 + #if AXIS_IS_TMC_CONFIG(Z4) + #define Z4_CURRENT Z_CURRENT + #define Z4_CURRENT_HOME Z_CURRENT_HOME + #define Z4_MICROSTEPS Z_MICROSTEPS + #define Z4_RSENSE Z_RSENSE #define Z4_CHAIN_POS -1 //#define Z4_INTERPOLATE true //#define Z4_HOLD_MULTIPLIER 0.5 #endif - #if AXIS_IS_TMC(I) + #if AXIS_IS_TMC_CONFIG(I) #define I_CURRENT 800 #define I_CURRENT_HOME I_CURRENT #define I_MICROSTEPS 16 @@ -2773,7 +2821,7 @@ //#define I_HOLD_MULTIPLIER 0.5 #endif - #if AXIS_IS_TMC(J) + #if AXIS_IS_TMC_CONFIG(J) #define J_CURRENT 800 #define J_CURRENT_HOME J_CURRENT #define J_MICROSTEPS 16 @@ -2783,7 +2831,7 @@ //#define J_HOLD_MULTIPLIER 0.5 #endif - #if AXIS_IS_TMC(K) + #if AXIS_IS_TMC_CONFIG(K) #define K_CURRENT 800 #define K_CURRENT_HOME K_CURRENT #define K_MICROSTEPS 16 @@ -2793,7 +2841,37 @@ //#define K_HOLD_MULTIPLIER 0.5 #endif - #if AXIS_IS_TMC(E0) + #if AXIS_IS_TMC_CONFIG(U) + #define U_CURRENT 800 + #define U_CURRENT_HOME U_CURRENT + #define U_MICROSTEPS 8 + #define U_RSENSE 0.11 + #define U_CHAIN_POS -1 + //#define U_INTERPOLATE true + //#define U_HOLD_MULTIPLIER 0.5 + #endif + + #if AXIS_IS_TMC_CONFIG(V) + #define V_CURRENT 800 + #define V_CURRENT_HOME V_CURRENT + #define V_MICROSTEPS 8 + #define V_RSENSE 0.11 + #define V_CHAIN_POS -1 + //#define V_INTERPOLATE true + //#define V_HOLD_MULTIPLIER 0.5 + #endif + + #if AXIS_IS_TMC_CONFIG(W) + #define W_CURRENT 800 + #define W_CURRENT_HOME W_CURRENT + #define W_MICROSTEPS 8 + #define W_RSENSE 0.11 + #define W_CHAIN_POS -1 + //#define W_INTERPOLATE true + //#define W_HOLD_MULTIPLIER 0.5 + #endif + + #if AXIS_IS_TMC_CONFIG(E0) #define E0_CURRENT 800 #define E0_MICROSTEPS 16 #define E0_RSENSE 0.11 @@ -2802,92 +2880,97 @@ //#define E0_HOLD_MULTIPLIER 0.5 #endif - #if AXIS_IS_TMC(E1) - #define E1_CURRENT 800 + #if AXIS_IS_TMC_CONFIG(E1) + #define E1_CURRENT E0_CURRENT #define E1_MICROSTEPS E0_MICROSTEPS - #define E1_RSENSE 0.11 + #define E1_RSENSE E0_RSENSE #define E1_CHAIN_POS -1 //#define E1_INTERPOLATE true //#define E1_HOLD_MULTIPLIER 0.5 #endif - #if AXIS_IS_TMC(E2) - #define E2_CURRENT 800 + #if AXIS_IS_TMC_CONFIG(E2) + #define E2_CURRENT E0_CURRENT #define E2_MICROSTEPS E0_MICROSTEPS - #define E2_RSENSE 0.11 + #define E2_RSENSE E0_RSENSE #define E2_CHAIN_POS -1 //#define E2_INTERPOLATE true //#define E2_HOLD_MULTIPLIER 0.5 #endif - #if AXIS_IS_TMC(E3) - #define E3_CURRENT 800 + #if AXIS_IS_TMC_CONFIG(E3) + #define E3_CURRENT E0_CURRENT #define E3_MICROSTEPS E0_MICROSTEPS - #define E3_RSENSE 0.11 + #define E3_RSENSE E0_RSENSE #define E3_CHAIN_POS -1 //#define E3_INTERPOLATE true //#define E3_HOLD_MULTIPLIER 0.5 #endif - #if AXIS_IS_TMC(E4) - #define E4_CURRENT 800 + #if AXIS_IS_TMC_CONFIG(E4) + #define E4_CURRENT E0_CURRENT #define E4_MICROSTEPS E0_MICROSTEPS - #define E4_RSENSE 0.11 + #define E4_RSENSE E0_RSENSE #define E4_CHAIN_POS -1 //#define E4_INTERPOLATE true //#define E4_HOLD_MULTIPLIER 0.5 #endif - #if AXIS_IS_TMC(E5) - #define E5_CURRENT 800 + #if AXIS_IS_TMC_CONFIG(E5) + #define E5_CURRENT E0_CURRENT #define E5_MICROSTEPS E0_MICROSTEPS - #define E5_RSENSE 0.11 + #define E5_RSENSE E0_RSENSE #define E5_CHAIN_POS -1 //#define E5_INTERPOLATE true //#define E5_HOLD_MULTIPLIER 0.5 #endif - #if AXIS_IS_TMC(E6) - #define E6_CURRENT 800 + #if AXIS_IS_TMC_CONFIG(E6) + #define E6_CURRENT E0_CURRENT #define E6_MICROSTEPS E0_MICROSTEPS - #define E6_RSENSE 0.11 + #define E6_RSENSE E0_RSENSE #define E6_CHAIN_POS -1 //#define E6_INTERPOLATE true //#define E6_HOLD_MULTIPLIER 0.5 #endif - #if AXIS_IS_TMC(E7) - #define E7_CURRENT 800 + #if AXIS_IS_TMC_CONFIG(E7) + #define E7_CURRENT E0_CURRENT #define E7_MICROSTEPS E0_MICROSTEPS - #define E7_RSENSE 0.11 + #define E7_RSENSE E0_RSENSE #define E7_CHAIN_POS -1 //#define E7_INTERPOLATE true //#define E7_HOLD_MULTIPLIER 0.5 #endif + // @section tmc/spi + /** * Override default SPI pins for TMC2130, TMC2160, TMC2660, TMC5130 and TMC5160 drivers here. * The default pins can be found in your board's pins file. */ - //#define X_CS_PIN -1 - //#define Y_CS_PIN -1 - //#define Z_CS_PIN -1 - //#define X2_CS_PIN -1 - //#define Y2_CS_PIN -1 - //#define Z2_CS_PIN -1 - //#define Z3_CS_PIN -1 - //#define Z4_CS_PIN -1 - //#define I_CS_PIN -1 - //#define J_CS_PIN -1 - //#define K_CS_PIN -1 - //#define E0_CS_PIN -1 - //#define E1_CS_PIN -1 - //#define E2_CS_PIN -1 - //#define E3_CS_PIN -1 - //#define E4_CS_PIN -1 - //#define E5_CS_PIN -1 - //#define E6_CS_PIN -1 - //#define E7_CS_PIN -1 + //#define X_CS_PIN -1 + //#define Y_CS_PIN -1 + //#define Z_CS_PIN -1 + //#define X2_CS_PIN -1 + //#define Y2_CS_PIN -1 + //#define Z2_CS_PIN -1 + //#define Z3_CS_PIN -1 + //#define Z4_CS_PIN -1 + //#define I_CS_PIN -1 + //#define J_CS_PIN -1 + //#define K_CS_PIN -1 + //#define U_CS_PIN -1 + //#define V_CS_PIN -1 + //#define W_CS_PIN -1 + //#define E0_CS_PIN -1 + //#define E1_CS_PIN -1 + //#define E2_CS_PIN -1 + //#define E3_CS_PIN -1 + //#define E4_CS_PIN -1 + //#define E5_CS_PIN -1 + //#define E6_CS_PIN -1 + //#define E7_CS_PIN -1 /** * Software option for SPI driven drivers (TMC2130, TMC2160, TMC2660, TMC5130 and TMC5160). @@ -2895,9 +2978,11 @@ * but you can override or define them here. */ //#define TMC_USE_SW_SPI - //#define TMC_SW_MOSI -1 - //#define TMC_SW_MISO -1 - //#define TMC_SW_SCK -1 + //#define TMC_SPI_MOSI -1 + //#define TMC_SPI_MISO -1 + //#define TMC_SPI_SCK -1 + + // @section tmc/serial /** * Four TMC2209 drivers can use the same HW/SW serial port with hardware configured addresses. @@ -2922,6 +3007,9 @@ //#define I_SLAVE_ADDRESS 0 //#define J_SLAVE_ADDRESS 0 //#define K_SLAVE_ADDRESS 0 + //#define U_SLAVE_ADDRESS 0 + //#define V_SLAVE_ADDRESS 0 + //#define W_SLAVE_ADDRESS 0 //#define E0_SLAVE_ADDRESS 0 //#define E1_SLAVE_ADDRESS 0 //#define E2_SLAVE_ADDRESS 0 @@ -2931,6 +3019,8 @@ //#define E6_SLAVE_ADDRESS 0 //#define E7_SLAVE_ADDRESS 0 + // @section tmc/smart + /** * Software enable * @@ -2939,17 +3029,24 @@ */ //#define SOFTWARE_DRIVER_ENABLE + // @section tmc/stealthchop + /** * TMC2130, TMC2160, TMC2208, TMC2209, TMC5130 and TMC5160 only * Use Trinamic's ultra quiet stepping mode. * When disabled, Marlin will use spreadCycle stepping mode. */ - #define STEALTHCHOP_XY - #define STEALTHCHOP_Z - #define STEALTHCHOP_I - #define STEALTHCHOP_J - #define STEALTHCHOP_K - #define STEALTHCHOP_E + #if HAS_STEALTHCHOP + #define STEALTHCHOP_XY + #define STEALTHCHOP_Z + #define STEALTHCHOP_I + #define STEALTHCHOP_J + #define STEALTHCHOP_K + #define STEALTHCHOP_U + #define STEALTHCHOP_V + #define STEALTHCHOP_W + #define STEALTHCHOP_E + #endif /** * Optimize spreadCycle chopper parameters by using predefined parameter sets @@ -2975,6 +3072,12 @@ //#define CHOPPER_TIMING_Z2 CHOPPER_TIMING_Z //#define CHOPPER_TIMING_Z3 CHOPPER_TIMING_Z //#define CHOPPER_TIMING_Z4 CHOPPER_TIMING_Z + //#define CHOPPER_TIMING_I CHOPPER_TIMING // For I Axis + //#define CHOPPER_TIMING_J CHOPPER_TIMING // For J Axis + //#define CHOPPER_TIMING_K CHOPPER_TIMING // For K Axis + //#define CHOPPER_TIMING_U CHOPPER_TIMING // For U Axis + //#define CHOPPER_TIMING_V CHOPPER_TIMING // For V Axis + //#define CHOPPER_TIMING_W CHOPPER_TIMING // For W Axis //#define CHOPPER_TIMING_E CHOPPER_TIMING // For Extruders (override below) //#define CHOPPER_TIMING_E1 CHOPPER_TIMING_E //#define CHOPPER_TIMING_E2 CHOPPER_TIMING_E @@ -2984,6 +3087,8 @@ //#define CHOPPER_TIMING_E6 CHOPPER_TIMING_E //#define CHOPPER_TIMING_E7 CHOPPER_TIMING_E + // @section tmc/status + /** * Monitor Trinamic drivers * for error conditions like overtemperature and short to ground. @@ -3003,6 +3108,8 @@ #define STOP_ON_ERROR #endif + // @section tmc/hybrid + /** * TMC2130, TMC2160, TMC2208, TMC2209, TMC5130 and TMC5160 only * The driver will switch to spreadCycle when stepper speed is over HYBRID_THRESHOLD. @@ -3020,9 +3127,12 @@ #define Z2_HYBRID_THRESHOLD 3 #define Z3_HYBRID_THRESHOLD 3 #define Z4_HYBRID_THRESHOLD 3 - #define I_HYBRID_THRESHOLD 3 - #define J_HYBRID_THRESHOLD 3 - #define K_HYBRID_THRESHOLD 3 + #define I_HYBRID_THRESHOLD 3 // [linear=mm/s, rotational=°/s] + #define J_HYBRID_THRESHOLD 3 // [linear=mm/s, rotational=°/s] + #define K_HYBRID_THRESHOLD 3 // [linear=mm/s, rotational=°/s] + #define U_HYBRID_THRESHOLD 3 // [mm/s] + #define V_HYBRID_THRESHOLD 3 + #define W_HYBRID_THRESHOLD 3 #define E0_HYBRID_THRESHOLD 30 #define E1_HYBRID_THRESHOLD 30 #define E2_HYBRID_THRESHOLD 30 @@ -3048,7 +3158,7 @@ * * It is recommended to set HOMING_BUMP_MM to { 0, 0, 0 }. * - * SPI_ENDSTOPS *** Beta feature! *** TMC2130/TMC5160 Only *** + * SPI_ENDSTOPS *** TMC2130/TMC5160 Only *** * Poll the driver through SPI to determine load when homing. * Removes the need for a wire from DIAG1 to an endstop pin. * @@ -3056,6 +3166,7 @@ * homing and adds a guard period for endstop triggering. * * Comment *_STALL_SENSITIVITY to disable sensorless homing for that axis. + * @section tmc/stallguard */ //#define SENSORLESS_HOMING // StallGuard capable drivers only @@ -3072,10 +3183,15 @@ //#define I_STALL_SENSITIVITY 8 //#define J_STALL_SENSITIVITY 8 //#define K_STALL_SENSITIVITY 8 - //#define SPI_ENDSTOPS // TMC2130 only + //#define U_STALL_SENSITIVITY 8 + //#define V_STALL_SENSITIVITY 8 + //#define W_STALL_SENSITIVITY 8 + //#define SPI_ENDSTOPS // TMC2130/TMC5160 only //#define IMPROVE_HOMING_RELIABILITY #endif + // @section tmc/config + /** * TMC Homing stepper phase. * @@ -3089,8 +3205,7 @@ //#define TMC_HOME_PHASE { 896, 896, 896 } /** - * Beta feature! - * Create a 50/50 square wave step pulse optimal for stepper drivers. + * Step on both rising and falling edge signals (as with a square wave). */ //#define SQUARE_WAVE_STEPPING @@ -3113,228 +3228,7 @@ */ #define TMC_ADV() { } -#endif // HAS_TRINAMIC_CONFIG - -// @section L64XX - -/** - * L64XX Stepper Driver options - * - * Arduino-L6470 library (0.8.0 or higher) is required. - * https://github.com/ameyer/Arduino-L6470 - * - * Requires the following to be defined in your pins_YOUR_BOARD file - * L6470_CHAIN_SCK_PIN - * L6470_CHAIN_MISO_PIN - * L6470_CHAIN_MOSI_PIN - * L6470_CHAIN_SS_PIN - * ENABLE_RESET_L64XX_CHIPS(Q) where Q is 1 to enable and 0 to reset - */ - -#if HAS_L64XX - - //#define L6470_CHITCHAT // Display additional status info - - #if AXIS_IS_L64XX(X) - #define X_MICROSTEPS 128 // Number of microsteps (VALID: 1, 2, 4, 8, 16, 32, 128) - L6474 max is 16 - #define X_OVERCURRENT 2000 // (mA) Current where the driver detects an over current - // L6470 & L6474 - VALID: 375 x (1 - 16) - 6A max - rounds down - // POWERSTEP01: VALID: 1000 x (1 - 32) - 32A max - rounds down - #define X_STALLCURRENT 1500 // (mA) Current where the driver detects a stall (VALID: 31.25 * (1-128) - 4A max - rounds down) - // L6470 & L6474 - VALID: 31.25 * (1-128) - 4A max - rounds down - // POWERSTEP01: VALID: 200 x (1 - 32) - 6.4A max - rounds down - // L6474 - STALLCURRENT setting is used to set the nominal (TVAL) current - #define X_MAX_VOLTAGE 127 // 0-255, Maximum effective voltage seen by stepper - not used by L6474 - #define X_CHAIN_POS -1 // Position in SPI chain, 0=Not in chain, 1=Nearest MOSI - #define X_SLEW_RATE 1 // 0-3, Slew 0 is slowest, 3 is fastest - #endif - - #if AXIS_IS_L64XX(X2) - #define X2_MICROSTEPS X_MICROSTEPS - #define X2_OVERCURRENT 2000 - #define X2_STALLCURRENT 1500 - #define X2_MAX_VOLTAGE 127 - #define X2_CHAIN_POS -1 - #define X2_SLEW_RATE 1 - #endif - - #if AXIS_IS_L64XX(Y) - #define Y_MICROSTEPS 128 - #define Y_OVERCURRENT 2000 - #define Y_STALLCURRENT 1500 - #define Y_MAX_VOLTAGE 127 - #define Y_CHAIN_POS -1 - #define Y_SLEW_RATE 1 - #endif - - #if AXIS_IS_L64XX(Y2) - #define Y2_MICROSTEPS Y_MICROSTEPS - #define Y2_OVERCURRENT 2000 - #define Y2_STALLCURRENT 1500 - #define Y2_MAX_VOLTAGE 127 - #define Y2_CHAIN_POS -1 - #define Y2_SLEW_RATE 1 - #endif - - #if AXIS_IS_L64XX(Z) - #define Z_MICROSTEPS 128 - #define Z_OVERCURRENT 2000 - #define Z_STALLCURRENT 1500 - #define Z_MAX_VOLTAGE 127 - #define Z_CHAIN_POS -1 - #define Z_SLEW_RATE 1 - #endif - - #if AXIS_IS_L64XX(Z2) - #define Z2_MICROSTEPS Z_MICROSTEPS - #define Z2_OVERCURRENT 2000 - #define Z2_STALLCURRENT 1500 - #define Z2_MAX_VOLTAGE 127 - #define Z2_CHAIN_POS -1 - #define Z2_SLEW_RATE 1 - #endif - - #if AXIS_IS_L64XX(Z3) - #define Z3_MICROSTEPS Z_MICROSTEPS - #define Z3_OVERCURRENT 2000 - #define Z3_STALLCURRENT 1500 - #define Z3_MAX_VOLTAGE 127 - #define Z3_CHAIN_POS -1 - #define Z3_SLEW_RATE 1 - #endif - - #if AXIS_IS_L64XX(Z4) - #define Z4_MICROSTEPS Z_MICROSTEPS - #define Z4_OVERCURRENT 2000 - #define Z4_STALLCURRENT 1500 - #define Z4_MAX_VOLTAGE 127 - #define Z4_CHAIN_POS -1 - #define Z4_SLEW_RATE 1 - #endif - - #if AXIS_DRIVER_TYPE_I(L6470) - #define I_MICROSTEPS 128 - #define I_OVERCURRENT 2000 - #define I_STALLCURRENT 1500 - #define I_MAX_VOLTAGE 127 - #define I_CHAIN_POS -1 - #define I_SLEW_RATE 1 - #endif - - #if AXIS_DRIVER_TYPE_J(L6470) - #define J_MICROSTEPS 128 - #define J_OVERCURRENT 2000 - #define J_STALLCURRENT 1500 - #define J_MAX_VOLTAGE 127 - #define J_CHAIN_POS -1 - #define J_SLEW_RATE 1 - #endif - - #if AXIS_DRIVER_TYPE_K(L6470) - #define K_MICROSTEPS 128 - #define K_OVERCURRENT 2000 - #define K_STALLCURRENT 1500 - #define K_MAX_VOLTAGE 127 - #define K_CHAIN_POS -1 - #define K_SLEW_RATE 1 - #endif - - #if AXIS_IS_L64XX(E0) - #define E0_MICROSTEPS 128 - #define E0_OVERCURRENT 2000 - #define E0_STALLCURRENT 1500 - #define E0_MAX_VOLTAGE 127 - #define E0_CHAIN_POS -1 - #define E0_SLEW_RATE 1 - #endif - - #if AXIS_IS_L64XX(E1) - #define E1_MICROSTEPS E0_MICROSTEPS - #define E1_OVERCURRENT 2000 - #define E1_STALLCURRENT 1500 - #define E1_MAX_VOLTAGE 127 - #define E1_CHAIN_POS -1 - #define E1_SLEW_RATE 1 - #endif - - #if AXIS_IS_L64XX(E2) - #define E2_MICROSTEPS E0_MICROSTEPS - #define E2_OVERCURRENT 2000 - #define E2_STALLCURRENT 1500 - #define E2_MAX_VOLTAGE 127 - #define E2_CHAIN_POS -1 - #define E2_SLEW_RATE 1 - #endif - - #if AXIS_IS_L64XX(E3) - #define E3_MICROSTEPS E0_MICROSTEPS - #define E3_OVERCURRENT 2000 - #define E3_STALLCURRENT 1500 - #define E3_MAX_VOLTAGE 127 - #define E3_CHAIN_POS -1 - #define E3_SLEW_RATE 1 - #endif - - #if AXIS_IS_L64XX(E4) - #define E4_MICROSTEPS E0_MICROSTEPS - #define E4_OVERCURRENT 2000 - #define E4_STALLCURRENT 1500 - #define E4_MAX_VOLTAGE 127 - #define E4_CHAIN_POS -1 - #define E4_SLEW_RATE 1 - #endif - - #if AXIS_IS_L64XX(E5) - #define E5_MICROSTEPS E0_MICROSTEPS - #define E5_OVERCURRENT 2000 - #define E5_STALLCURRENT 1500 - #define E5_MAX_VOLTAGE 127 - #define E5_CHAIN_POS -1 - #define E5_SLEW_RATE 1 - #endif - - #if AXIS_IS_L64XX(E6) - #define E6_MICROSTEPS E0_MICROSTEPS - #define E6_OVERCURRENT 2000 - #define E6_STALLCURRENT 1500 - #define E6_MAX_VOLTAGE 127 - #define E6_CHAIN_POS -1 - #define E6_SLEW_RATE 1 - #endif - - #if AXIS_IS_L64XX(E7) - #define E7_MICROSTEPS E0_MICROSTEPS - #define E7_OVERCURRENT 2000 - #define E7_STALLCURRENT 1500 - #define E7_MAX_VOLTAGE 127 - #define E7_CHAIN_POS -1 - #define E7_SLEW_RATE 1 - #endif - - /** - * Monitor L6470 drivers for error conditions like over temperature and over current. - * In the case of over temperature Marlin can decrease the drive until the error condition clears. - * Other detected conditions can be used to stop the current print. - * Relevant G-codes: - * M906 - I1/2/3/4/5 Set or get motor drive level using axis codes X, Y, Z, E. Report values if no axis codes given. - * I not present or I0 or I1 - X, Y, Z or E0 - * I2 - X2, Y2, Z2 or E1 - * I3 - Z3 or E3 - * I4 - Z4 or E4 - * I5 - E5 - * M916 - Increase drive level until get thermal warning - * M917 - Find minimum current thresholds - * M918 - Increase speed until max or error - * M122 S0/1 - Report driver parameters - */ - //#define MONITOR_L6470_DRIVER_STATUS - - #if ENABLED(MONITOR_L6470_DRIVER_STATUS) - #define KVAL_HOLD_STEP_DOWN 1 - //#define L6470_STOP_ON_ERROR - #endif - -#endif // HAS_L64XX +#endif // HAS_TRINAMIC_CONFIG || HAS_TMC26X // @section i2cbus @@ -3347,9 +3241,8 @@ /** * TWI/I2C BUS * - * This feature is an EXPERIMENTAL feature so it shall not be used on production - * machines. Enabling this will allow you to send and receive I2C data from slave - * devices on the bus. + * This feature is EXPERIMENTAL but may be useful for custom I2C peripherals. + * Enable this to send and receive I2C data from slave devices on the bus. * * ; Example #1 * ; This macro send the string "Marlin" to the slave device with address 0x63 (99) @@ -3377,7 +3270,7 @@ #define I2C_SLAVE_ADDRESS 0 // Set a value from 8 to 127 to act as a slave #endif -// @section extras +// @section photo /** * Photo G-code @@ -3396,7 +3289,7 @@ //#define PHOTOGRAPH_PIN 23 // Canon Hack Development Kit - // https://captain-slow.dk/2014/03/09/3d-printing-timelapses/ + // https://web.archive.org/web/20200920094805/captain-slow.dk/2014/03/09/3d-printing-timelapses/ //#define CHDK_PIN 4 // Optional second move with delay to trigger the camera shutter @@ -3420,20 +3313,22 @@ #endif #endif +// @section cnc + /** * Spindle & Laser control * * Add the M3, M4, and M5 commands to turn the spindle/laser on and off, and * to set spindle speed, spindle direction, and laser power. * - * SuperPid is a router/spindle speed controller used in the CNC milling community. + * SuperPID is a router/spindle speed controller used in the CNC milling community. * Marlin can be used to turn the spindle on and off. It can also be used to set * the spindle speed from 5,000 to 30,000 RPM. * * You'll need to select a pin for the ON/OFF function and optionally choose a 0-5V * hardware PWM pin for the speed control and a pin for the rotation direction. * - * See https://marlinfw.org/docs/configuration/laser_spindle.html for more config details. + * See https://marlinfw.org/docs/configuration/2.0.9/laser_spindle.html for more config details. */ //#define SPINDLE_FEATURE //#define LASER_FEATURE @@ -3443,7 +3338,10 @@ #define SPINDLE_LASER_USE_PWM // Enable if your controller supports setting the speed/power #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 and LPC) + #define SPINDLE_LASER_FREQUENCY 2500 // (Hz) Spindle/laser frequency (only on supported HALs: AVR, ESP32, and LPC) + // ESP32: If SPINDLE_LASER_PWM_PIN is onboard then <=78125Hz. For I2S expander + // the frequency determines the PWM resolution. 2500Hz = 0-100, 977Hz = 0-255, ... + // (250000 / SPINDLE_LASER_FREQUENCY) = max value. #endif //#define AIR_EVACUATION // Cutter Vacuum / Laser Blower motor control with G-codes M10-M11 @@ -3517,83 +3415,55 @@ #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 + * + * The laser should be turned off when there is no movement for a period of time. + * Consider material flammability, cut rate, and G-code order when setting this + * value. Too low and it could turn off during a very slow move; too high and + * the material could ignite. + */ + #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. + * + * 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. * - * This allows the laser to keep in perfect sync with the planner and removes - * the powerup/down delay since lasers require negligible time. + * '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 compensation for accel/decel 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 - - /** - * 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 + /** + * 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 committed without waiting + * for a planner synchronization + */ + //#define LASER_POWER_SYNC - #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) @@ -3604,6 +3474,20 @@ #define I2C_AMMETER_SHUNT_RESISTOR 0.1 // (Ohms) Calibration shunt resistor value #endif + // + // Laser Coolant Flow Meter + // + //#define LASER_COOLANT_FLOW_METER + #if ENABLED(LASER_COOLANT_FLOW_METER) + #define FLOWMETER_PIN 20 // Requires an external interrupt-enabled pin (e.g., RAMPS 2,3,18,19,20,21) + #define FLOWMETER_PPL 5880 // (pulses/liter) Flow meter pulses-per-liter on the input pin + #define FLOWMETER_INTERVAL 1000 // (ms) Flow rate calculation interval in milliseconds + #define FLOWMETER_SAFETY // Prevent running the laser without the minimum flow rate set below + #if ENABLED(FLOWMETER_SAFETY) + #define FLOWMETER_MIN_LITERS_PER_MINUTE 1.5 // (liters/min) Minimum flow required when enabled + #endif + #endif + #endif #endif // SPINDLE_FEATURE || LASER_FEATURE @@ -3634,6 +3518,8 @@ #define COOLANT_FLOOD_INVERT false // Set "true" if the on/off function is reversed #endif +// @section filament width + /** * Filament Width Sensor * @@ -3667,6 +3553,8 @@ //#define FILAMENT_LCD_DISPLAY #endif +// @section power + /** * Power Monitor * Monitor voltage (V) and/or current (A), and -when possible- power (W) @@ -3690,6 +3578,8 @@ #define POWER_MONITOR_VOLTAGE_OFFSET 0 // Offset (in volts) applied to the calculated voltage #endif +// @section safety + /** * Stepper Driver Anti-SNAFU Protection * @@ -3699,6 +3589,8 @@ */ //#define DISABLE_DRIVER_SAFE_POWER_PROTECT +// @section cnc + /** * CNC Coordinate Systems * @@ -3707,6 +3599,8 @@ */ //#define CNC_COORDINATE_SYSTEMS +// @section reporting + /** * Auto-report fan speed with M123 S * Requires fans with tachometer pins @@ -3717,6 +3611,9 @@ * Auto-report temperatures with M155 S */ #define AUTO_REPORT_TEMPERATURES +#if ENABLED(AUTO_REPORT_TEMPERATURES) && TEMP_SENSOR_REDUNDANT + //#define AUTO_REPORT_REDUNDANT // Include the "R" sensor in the auto-report +#endif /** * Auto-report position with M154 S @@ -3731,6 +3628,8 @@ //#define M115_GEOMETRY_REPORT #endif +// @section security + /** * Expected Printer Check * Add the M16 G-code to compare a string to the MACHINE_NAME. @@ -3738,6 +3637,8 @@ */ //#define EXPECTED_PRINTER_CHECK +// @section volumetrics + /** * Disable all Volumetric extrusion options */ @@ -3762,34 +3663,22 @@ * Use 'M200 [T] L' to override and 'M502' to reset. * A non-zero value activates Volume-based Extrusion Limiting. */ - #define DEFAULT_VOLUMETRIC_EXTRUDER_LIMIT 0.00 // (mm^3/sec) + #define DEFAULT_VOLUMETRIC_EXTRUDER_LIMIT 0.00 // (mm^3/sec) #endif #endif +// @section reporting + /** - * Enable this option for a leaner build of Marlin that removes all - * workspace offsets, simplifying coordinate transformations, leveling, etc. - * - * - M206 and M428 are disabled. - * - G92 will revert to its behavior from Marlin 1.0. + * Extra options for the M114 "Current Position" report */ -//#define NO_WORKSPACE_OFFSETS - -// Extra options for the M114 "Current Position" report //#define M114_DETAIL // Use 'M114` for details to check planner calculations //#define M114_REALTIME // Real current position based on forward kinematics //#define M114_LEGACY // M114 used to synchronize on every call. Enable if needed. //#define REPORT_FAN_CHANGE // Report the new fan speed when changed by M106 (and others) -/** - * Set the number of proportional font spaces required to fill up a typical character space. - * This can help to better align the output of commands like `G29 O` Mesh Output. - * - * For clients that use a fixed-width font (like OctoPrint), leave this set to 1.0. - * Otherwise, adjust according to your client and font. - */ -#define PROPORTIONAL_FONT_RATIO 1.0 +// @section gcode /** * Spend 28 bytes of SRAM to optimize the G-code parser @@ -3800,7 +3689,9 @@ //#define GCODE_QUOTED_STRINGS // Support for quoted string parameters #endif -// Support for MeatPack G-code compression (https://github.com/scottmudge/OctoPrint-MeatPack) +/** + * Support for MeatPack G-code compression (https://github.com/scottmudge/OctoPrint-MeatPack) + */ //#define MEATPACK_ON_SERIAL_PORT_1 //#define MEATPACK_ON_SERIAL_PORT_2 @@ -3808,6 +3699,15 @@ //#define REPETIER_GCODE_M360 // Add commands originally from Repetier FW +/** + * Enable this option for a leaner build of Marlin that removes all + * workspace offsets, simplifying coordinate transformations, leveling, etc. + * + * - M206 and M428 are disabled. + * - G92 will revert to its behavior from Marlin 1.0. + */ +//#define NO_WORKSPACE_OFFSETS + /** * CNC G-code options * Support CNC-style G-code dialects used by laser cutters, drawing machine cams, etc. @@ -3847,6 +3747,8 @@ * Up to 25 may be defined, but the actual number is LCD-dependent. */ +// @section custom main menu + // Custom Menu: Main Menu //#define CUSTOM_MENU_MAIN #if ENABLED(CUSTOM_MENU_MAIN) @@ -3877,6 +3779,8 @@ //#define MAIN_MENU_ITEM_5_CONFIRM #endif +// @section custom config menu + // Custom Menu: Configuration Menu //#define CUSTOM_MENU_CONFIG #if ENABLED(CUSTOM_MENU_CONFIG) @@ -3907,6 +3811,8 @@ //#define CONFIG_MENU_ITEM_5_CONFIRM #endif +// @section custom buttons + /** * User-defined buttons to run custom G-code. * Up to 25 may be defined. @@ -3938,6 +3844,8 @@ #endif #endif +// @section host + /** * Host Action Commands * @@ -3952,14 +3860,19 @@ * Host Prompt Support enables Marlin to use the host for user prompts so * filament runout and other processes can be managed from the host side. */ -#define HOST_ACTION_COMMANDS +//#define HOST_ACTION_COMMANDS #if ENABLED(HOST_ACTION_COMMANDS) - //#define HOST_PAUSE_M76 - //#define HOST_PROMPT_SUPPORT - //#define HOST_START_MENU_ITEM // Add a menu item that tells the host to start - //#define HOST_SHUTDOWN_MENU_ITEM // Add a menu item that tells the host to shut down + //#define HOST_PAUSE_M76 // Tell the host to pause in response to M76 + //#define HOST_PROMPT_SUPPORT // Initiate host prompts to get user feedback + #if ENABLED(HOST_PROMPT_SUPPORT) + //#define HOST_STATUS_NOTIFICATIONS // Send some status messages to the host as notifications + #endif + //#define HOST_START_MENU_ITEM // Add a menu item that tells the host to start + //#define HOST_SHUTDOWN_MENU_ITEM // Add a menu item that tells the host to shut down #endif +// @section extras + /** * Cancel Objects * @@ -3977,10 +3890,11 @@ * Wiki: https://wiki.aus3d.com.au/Magnetic_Encoder * Github: https://github.com/Aus3D/MagneticEncoder * - * Supplier: https://aus3d.com.au/magnetic-encoder-module + * Supplier: https://aus3d.com.au/products/magnetic-encoder-module * Alternative Supplier: https://reliabuild3d.com/ * * Reliabuild encoders have been modified to improve reliability. + * @section i2c encoders */ //#define I2C_POSITION_ENCODERS @@ -4052,6 +3966,7 @@ /** * Analog Joystick(s) + * @section joystick */ //#define JOYSTICK #if ENABLED(JOYSTICK) @@ -4073,9 +3988,10 @@ /** * Mechanical Gantry Calibration - * Modern replacement for the Prusa TMC_Z_CALIBRATION. + * Modern replacement for the Průša TMC_Z_CALIBRATION. * Adds capability to work with any adjustable current drivers. * Implemented as G34 because M915 is deprecated. + * @section calibrate */ //#define MECHANICAL_GANTRY_CALIBRATION #if ENABLED(MECHANICAL_GANTRY_CALIBRATION) @@ -4092,12 +4008,14 @@ /** * Instant freeze / unfreeze functionality - * Specified pin has pullup and connecting to ground will instantly pause motion. - * Potentially useful for emergency stop that allows being resumed. + * Potentially useful for rapid stop that allows being resumed. Halts stepper movement. + * Note this does NOT pause spindles, lasers, fans, heaters or any other auxiliary device. + * @section interface */ //#define FREEZE_FEATURE #if ENABLED(FREEZE_FEATURE) //#define FREEZE_PIN 41 // Override the default (KILL) pin here + #define FREEZE_STATE LOW // State of pin indicating freeze #endif /** @@ -4105,6 +4023,7 @@ * * Add support for a low-cost 8x8 LED Matrix based on the Max7219 chip as a realtime status display. * Requires 3 signal wires. Some useful debug options are included to demonstrate its usage. + * @section debug matrix */ //#define MAX7219_DEBUG #if ENABLED(MAX7219_DEBUG) @@ -4117,7 +4036,8 @@ #define MAX7219_NUMBER_UNITS 1 // Number of Max7219 units in chain. #define MAX7219_ROTATE 0 // Rotate the display clockwise (in multiples of +/- 90°) // connector at: right=0 bottom=-90 top=90 left=180 - //#define MAX7219_REVERSE_ORDER // The individual LED matrix units may be in reversed order + //#define MAX7219_REVERSE_ORDER // The order of the LED matrix units may be reversed + //#define MAX7219_REVERSE_EACH // The LEDs in each matrix unit row may be reversed //#define MAX7219_SIDE_BY_SIDE // Big chip+matrix boards can be chained side-by-side /** @@ -4125,12 +4045,15 @@ * If you add more debug displays, be careful to avoid conflicts! */ #define MAX7219_DEBUG_PRINTER_ALIVE // Blink corner LED of 8x8 matrix to show that the firmware is functioning - #define MAX7219_DEBUG_PLANNER_HEAD 3 // Show the planner queue head position on this and the next LED matrix row - #define MAX7219_DEBUG_PLANNER_TAIL 5 // Show the planner queue tail position on this and the next LED matrix row + #define MAX7219_DEBUG_PLANNER_HEAD 2 // Show the planner queue head position on this and the next LED matrix row + #define MAX7219_DEBUG_PLANNER_TAIL 4 // Show the planner queue tail position on this and the next LED matrix row #define MAX7219_DEBUG_PLANNER_QUEUE 0 // Show the current planner queue depth on this and the next LED matrix row // If you experience stuttering, reboots, etc. this option can reveal how // tweaks made to the configuration are affecting the printer in real-time. + #define MAX7219_DEBUG_PROFILE 6 // Display the fraction of CPU time spent in profiled code on this LED matrix + // row. By default idle() is profiled so this shows how "idle" the processor is. + // See class CodeProfiler. #endif /** @@ -4139,6 +4062,7 @@ * Support for Synchronized Z moves when used with NanoDLP. G0/G1 axis moves will * output a "Z_move_comp" string to enable synchronization with DLP projector exposure. * This feature allows you to use [[WaitForDoneMessage]] instead of M400 commands. + * @section nanodlp */ //#define NANODLP_Z_SYNC #if ENABLED(NANODLP_Z_SYNC) @@ -4147,19 +4071,24 @@ /** * Ethernet. Use M552 to enable and set the IP address. + * @section network */ #if HAS_ETHERNET #define MAC_ADDRESS { 0xDE, 0xAD, 0xBE, 0xEF, 0xF0, 0x0D } // A MAC address unique to your network #endif /** - * WiFi Support (Espressif ESP32 WiFi) + * Native ESP32 board with WiFi or add-on ESP32 WiFi-101 module */ -//#define WIFISUPPORT // Marlin embedded WiFi managenent +//#define WIFISUPPORT // Marlin embedded WiFi management. Not needed for simple WiFi serial port. //#define ESP3D_WIFISUPPORT // ESP3D Library WiFi management (https://github.com/luc-github/ESP3DLib) -#if EITHER(WIFISUPPORT, ESP3D_WIFISUPPORT) - //#define WEBSUPPORT // Start a webserver (which may include auto-discovery) +/** + * Extras for an ESP32-based motherboard with WIFISUPPORT + * These options don't apply to add-on WiFi modules based on ESP32 WiFi101. + */ +#if ANY(WIFISUPPORT, ESP3D_WIFISUPPORT) + //#define WEBSUPPORT // Start a webserver (which may include auto-discovery) using SPIFFS //#define OTASUPPORT // Support over-the-air firmware updates //#define WIFI_CUSTOM_COMMAND // Accept feature config commands (e.g., WiFi ESP3D) from the host @@ -4174,6 +4103,8 @@ //#include "Configuration_Secure.h" // External file with WiFi SSID / Password #endif +// @section multi-material + /** * Průša Multi-Material Unit (MMU) * Enable in Configuration.h @@ -4207,35 +4138,34 @@ // Add an LCD menu for MMU2 //#define MMU2_MENUS - #if EITHER(MMU2_MENUS, HAS_PRUSA_MMU2S) - // Settings for filament load / unload from the LCD menu. - // This is for Průša MK3-style extruders. Customize for your hardware. - #define MMU2_FILAMENTCHANGE_EJECT_FEED 80.0 - #define MMU2_LOAD_TO_NOZZLE_SEQUENCE \ - { 7.2, 1145 }, \ - { 14.4, 871 }, \ - { 36.0, 1393 }, \ - { 14.4, 871 }, \ - { 50.0, 198 } - - #define MMU2_RAMMING_SEQUENCE \ - { 1.0, 1000 }, \ - { 1.0, 1500 }, \ - { 2.0, 2000 }, \ - { 1.5, 3000 }, \ - { 2.5, 4000 }, \ - { -15.0, 5000 }, \ - { -14.0, 1200 }, \ - { -6.0, 600 }, \ - { 10.0, 700 }, \ - { -10.0, 400 }, \ - { -50.0, 2000 } - #endif + + // Settings for filament load / unload from the LCD menu. + // This is for Průša MK3-style extruders. Customize for your hardware. + #define MMU2_FILAMENTCHANGE_EJECT_FEED 80.0 + #define MMU2_LOAD_TO_NOZZLE_SEQUENCE \ + { 7.2, 1145 }, \ + { 14.4, 871 }, \ + { 36.0, 1393 }, \ + { 14.4, 871 }, \ + { 50.0, 198 } + + #define MMU2_RAMMING_SEQUENCE \ + { 1.0, 1000 }, \ + { 1.0, 1500 }, \ + { 2.0, 2000 }, \ + { 1.5, 3000 }, \ + { 2.5, 4000 }, \ + { -15.0, 5000 }, \ + { -14.0, 1200 }, \ + { -6.0, 600 }, \ + { 10.0, 700 }, \ + { -10.0, 400 }, \ + { -50.0, 2000 } /** * Using a sensor like the MMU2S * This mode requires a MK3S extruder with a sensor at the extruder idler, like the MMU2S. - * See https://help.prusa3d.com/en/guide/3b-mk3s-mk2-5s-extruder-upgrade_41560, step 11 + * See https://help.prusa3d.com/guide/3b-mk3s-mk2-5s-extruder-upgrade_41560#42048, step 11 */ #if HAS_PRUSA_MMU2S #define MMU2_C0_RETRY 5 // Number of retries (total time = timeout*retries) @@ -4279,6 +4209,7 @@ /** * Advanced Print Counter settings + * @section stats */ #if ENABLED(PRINTCOUNTER) #define SERVICE_WARNING_BUZZES 3 @@ -4308,6 +4239,9 @@ // //#define PINS_DEBUGGING +// Enable Tests that will run at startup and produce a report +//#define MARLIN_TEST_BUILD + // Enable Marlin dev mode which adds some special commands //#define MARLIN_DEV_MODE diff --git a/Marlin/Makefile b/Marlin/Makefile index eee1403b..e5ba9cb3 100644 --- a/Marlin/Makefile +++ b/Marlin/Makefile @@ -63,8 +63,8 @@ HARDWARE_MOTHERBOARD ?= 1020 ifeq ($(OS),Windows_NT) # Windows - ARDUINO_INSTALL_DIR ?= ${HOME}/Arduino - ARDUINO_USER_DIR ?= ${HOME}/Arduino + ARDUINO_INSTALL_DIR ?= ${HOME}/AppData/Local/Arduino + ARDUINO_USER_DIR ?= ${HOME}/Documents/Arduino else UNAME_S := $(shell uname -s) ifeq ($(UNAME_S),Linux) @@ -82,11 +82,11 @@ endif # Arduino source install directory, and version number # On most linuxes this will be /usr/share/arduino -ARDUINO_INSTALL_DIR ?= ${HOME}/Arduino -ARDUINO_VERSION ?= 106 +ARDUINO_INSTALL_DIR ?= ${HOME}/AppData/Local/Arduino # C:/Users/${USERNAME}/AppData/Local/Arduino +ARDUINO_VERSION ?= 10819 # The installed Libraries are in the User folder -ARDUINO_USER_DIR ?= ${HOME}/Arduino +ARDUINO_USER_DIR ?= ${HOME}/Documents/Arduino # You can optionally set a path to the avr-gcc tools. # Requires a trailing slash. For example, /usr/local/avr-gcc/bin/ @@ -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 @@ -132,7 +132,7 @@ CC_MIN:=$(shell $(CC) -dM -E - < /dev/null | grep __GNUC_MINOR__ | cut -f3 -d\ ) CC_PATCHLEVEL:=$(shell $(CC) -dM -E - < /dev/null | grep __GNUC_PATCHLEVEL__ | cut -f3 -d\ ) CC_VER:=$(shell echo $$(( $(CC_MAJ) * 10000 + $(CC_MIN) * 100 + $(CC_PATCHLEVEL) ))) ifeq ($(shell test $(CC_VER) -lt 40901 && echo 1),1) - @echo This version of GCC is likely broken. Enabling relocation workaround. + $(warning This GCC version $(CC_VER) is likely broken. Enabling relocation workaround.) RELOC_WORKAROUND = 1 endif @@ -307,133 +307,22 @@ else ifeq ($(HARDWARE_MOTHERBOARD),1154) else ifeq ($(HARDWARE_MOTHERBOARD),1155) # Tenlog D3 Hero IDEX printer else ifeq ($(HARDWARE_MOTHERBOARD),1156) -# Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Fan, Bed) +# Tenlog D3,5,6 Pro IDEX printers else ifeq ($(HARDWARE_MOTHERBOARD),1157) -# Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Hotend2, Bed) +# Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Fan, Bed) else ifeq ($(HARDWARE_MOTHERBOARD),1158) -# Ramps S 1.2 by Sakul.cz (Power outputs: Hotend, Fan0, Fan1, Bed) +# Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Hotend2, Bed) else ifeq ($(HARDWARE_MOTHERBOARD),1159) -# Longer LK1 PRO / Alfawise U20 Pro (PRO version) +# Ramps S 1.2 by Sakul.cz (Power outputs: Hotend, Fan0, Fan1, Bed) else ifeq ($(HARDWARE_MOTHERBOARD),1160) -# Longer LKx PRO / Alfawise Uxx Pro (PRO version) +# Longer LK1 PRO / Alfawise U20 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) +# Longer LKx PRO / Alfawise Uxx Pro (PRO version) +else ifeq ($(HARDWARE_MOTHERBOARD),1162) +# Zonestar zrib V5.3 (Chinese RAMPS replica) +else ifeq ($(HARDWARE_MOTHERBOARD),1163) +# Pxmalion Core I3 +else ifeq ($(HARDWARE_MOTHERBOARD),1164) # # RAMBo and derivatives @@ -512,7 +401,7 @@ else ifeq ($(HARDWARE_MOTHERBOARD),1324) else ifeq ($(HARDWARE_MOTHERBOARD),1325) # Intamsys 4.0 (Funmat HT) else ifeq ($(HARDWARE_MOTHERBOARD),1326) -# Malyan M180 Mainboard Version 2 (no display function, direct gcode only) +# Malyan M180 Mainboard Version 2 (no display function, direct G-code only) else ifeq ($(HARDWARE_MOTHERBOARD),1327) # Geeetech GT2560 Rev B for A20(M/T/D) else ifeq ($(HARDWARE_MOTHERBOARD),1328) @@ -767,18 +656,18 @@ ifeq ($(HARDWARE_VARIANT), $(filter $(HARDWARE_VARIANT),arduino Teensy Sanguino) # Old libraries (avr-core 1.6.21 < / Arduino < 1.6.8) VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/libraries/SPI # New libraries (avr-core >= 1.6.21 / Arduino >= 1.6.8) - VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/libraries/SPI/src + VPATH += $(ARDUINO_INSTALL_DIR)/packages/arduino/hardware/arduino/avr/1.8.6/libraries/SPI/src endif ifeq ($(IS_MCU),1) - VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/cores/arduino + VPATH += $(ARDUINO_INSTALL_DIR)/packages/arduino/hardware/arduino/avr/1.8.6/cores/arduino # Old libraries (avr-core 1.6.21 < / Arduino < 1.6.8) VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/libraries/SPI VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/libraries/SoftwareSerial # New libraries (avr-core >= 1.6.21 / Arduino >= 1.6.8) - VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/libraries/SPI/src - VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/libraries/SoftwareSerial/src + VPATH += $(ARDUINO_INSTALL_DIR)/packages/arduino/hardware/arduino/avr/1.8.6/libraries/SPI/src + VPATH += $(ARDUINO_INSTALL_DIR)/packages/arduino/hardware/arduino/avr/1.8.6/libraries/SoftwareSerial/src endif VPATH += $(ARDUINO_INSTALL_DIR)/libraries/LiquidCrystal/src @@ -792,17 +681,17 @@ ifeq ($(WIRE), 1) VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/libraries/Wire VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/libraries/Wire/utility # New libraries (avr-core >= 1.6.21 / Arduino >= 1.6.8) - VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/libraries/Wire/src - VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/libraries/Wire/src/utility + VPATH += $(ARDUINO_INSTALL_DIR)/packages/arduino/hardware/avr/1.8.6/libraries/Wire/src + VPATH += $(ARDUINO_INSTALL_DIR)/packages/arduino/hardware/avr/1.8.6/libraries/Wire/src/utility endif ifeq ($(NEOPIXEL), 1) VPATH += $(ARDUINO_INSTALL_DIR)/libraries/Adafruit_NeoPixel endif ifeq ($(U8GLIB), 1) -VPATH += $(ARDUINO_INSTALL_DIR)/libraries/U8glib -VPATH += $(ARDUINO_INSTALL_DIR)/libraries/U8glib/csrc -VPATH += $(ARDUINO_INSTALL_DIR)/libraries/U8glib/cppsrc -VPATH += $(ARDUINO_INSTALL_DIR)/libraries/U8glib/fntsrc +VPATH += $(ARDUINO_INSTALL_DIR)/libraries/U8glib-HAL +VPATH += $(ARDUINO_INSTALL_DIR)/libraries/U8glib-HAL/src +# VPATH += $(ARDUINO_INSTALL_DIR)/libraries/U8glib +# VPATH += $(ARDUINO_INSTALL_DIR)/libraries/U8glib/src endif ifeq ($(TMC), 1) VPATH += $(ARDUINO_INSTALL_DIR)/libraries/TMCStepper/src @@ -811,9 +700,9 @@ endif ifeq ($(HARDWARE_VARIANT), arduino) HARDWARE_SUB_VARIANT ?= mega - VPATH += $(ARDUINO_INSTALL_DIR)/hardware/arduino/avr/variants/$(HARDWARE_SUB_VARIANT) + VPATH += $(ARDUINO_INSTALL_DIR)/packages/arduino/hardware/avr/1.8.6/variants/$(HARDWARE_SUB_VARIANT) else ifeq ($(HARDWARE_VARIANT), Sanguino) - VPATH += $(ARDUINO_INSTALL_DIR)/hardware/marlin/avr/variants/sanguino + VPATH += $(ARDUINO_INSTALL_DIR)/packages/arduino/hardware/avr/1.8.6/variants/sanguino else ifeq ($(HARDWARE_VARIANT), archim) VPATH += $(ARDUINO_INSTALL_DIR)/packages/ultimachine/hardware/sam/1.6.9-b/system/libsam VPATH += $(ARDUINO_INSTALL_DIR)/packages/ultimachine/hardware/sam/1.6.9-b/system/CMSIS/CMSIS/Include/ @@ -829,7 +718,7 @@ else ifeq ($(HARDWARE_VARIANT), archim) LDLIBS = $(ARDUINO_INSTALL_DIR)/packages/ultimachine/hardware/sam/1.6.9-b/variants/archim/libsam_sam3x8e_gcc_rel.a else HARDWARE_SUB_VARIANT ?= standard - VPATH += $(ARDUINO_INSTALL_DIR)/hardware/$(HARDWARE_VARIANT)/variants/$(HARDWARE_SUB_VARIANT) + VPATH += $(ARDUINO_INSTALL_DIR)/packages/arduino/hardware/avr/1.8.6/variants/$(HARDWARE_SUB_VARIANT) endif LIB_SRC = wiring.c \ @@ -844,7 +733,7 @@ endif ifeq ($(HARDWARE_VARIANT), Teensy) LIB_SRC = wiring.c - VPATH += $(ARDUINO_INSTALL_DIR)/hardware/teensy/cores/teensy + VPATH += $(ARDUINO_INSTALL_DIR)/packages/arduino/hardware/teensy/cores/teensy endif LIB_CXXSRC = WMath.cpp WString.cpp Print.cpp SPI.cpp @@ -991,7 +880,7 @@ AVRDUDE_WRITE_FLASH = -Uflash:w:$(BUILD_DIR)/$(TARGET).hex:i ifeq ($(shell uname -s), Linux) AVRDUDE_CONF = /etc/avrdude/avrdude.conf else - AVRDUDE_CONF = $(ARDUINO_INSTALL_DIR)/hardware/tools/avr/etc/avrdude.conf + AVRDUDE_CONF = $(ARDUINO_INSTALL_DIR)/packages/arduino/tools/avrdude/6.3.0-arduino17/etc/avrdude.conf endif AVRDUDE_FLAGS = -D -C$(AVRDUDE_CONF) \ -p$(PROG_MCU) -P$(AVRDUDE_PORT) -c$(AVRDUDE_PROGRAMMER) \ diff --git a/Marlin/Marlin.ino b/Marlin/Marlin.ino index 57c82544..066cc171 100644 --- a/Marlin/Marlin.ino +++ b/Marlin/Marlin.ino @@ -2,7 +2,7 @@ Marlin Firmware - (c) 2011-2020 MarlinFirmware + (c) 2011-2024 MarlinFirmware Portions of Marlin are (c) by their respective authors. All code complies with GPLv2 and/or GPLv3 @@ -27,7 +27,7 @@ Configuration - https://github.com/MarlinFirmware/Configurations Example configurations for several printer models. - - https://www.youtube.com/watch?v=3gwWVFtdg-4 + - https://youtu.be/3gwWVFtdg-4 A good 20-minute overview of Marlin configuration by Tom Sanladerer. (Applies to Marlin 1.0.x, so Jerk and Acceleration should be halved.) Also... https://www.google.com/search?tbs=vid%3A1&q=configure+marlin diff --git a/Marlin/Version.h b/Marlin/Version.h index 4f96db29..b9b2885c 100644 --- a/Marlin/Version.h +++ b/Marlin/Version.h @@ -28,7 +28,7 @@ /** * Marlin release version identifier */ -//#define SHORT_BUILD_VERSION "2.0.9.3" +//#define SHORT_BUILD_VERSION "2.1.2.5" /** * Verbose version identifier which should contain a reference to the location @@ -41,7 +41,14 @@ * here we define this default string as the date where the latest release * version was tagged. */ -//#define STRING_DISTRIBUTION_DATE "2021-12-25" +//#define STRING_DISTRIBUTION_DATE "2024-11-18" + +/** + * The protocol for communication to the host. Protocol indicates communication + * standards such as the use of ASCII, "echo:" and "error:" line prefixes, etc. + * (Other behaviors are given by the firmware version and capabilities report.) + */ +//#define PROTOCOL_VERSION "1.0" /** * Defines a generic printer name to be output to the LCD after booting Marlin. @@ -54,7 +61,7 @@ * has a distinct Github fork— the Source Code URL should just be the main * Marlin repository. */ -//#define SOURCE_CODE_URL "https://github.com/cumal/krotos3d" +//#define SOURCE_CODE_URL "github.com/MarlinFirmware/Marlin" /** * Default generic printer UUID. @@ -68,8 +75,8 @@ //#define WEBSITE_URL "marlinfw.org" /** - * Set the vendor info the serial USB interface, if changable - * Currently only supported by DUE platform + * Set the vendor info the serial USB interface, if changeable. + * Currently only supported by DUE platform. */ //#define USB_DEVICE_VENDOR_ID 0x0000 //#define USB_DEVICE_PRODUCT_ID 0x0000 diff --git a/Marlin/config.ini b/Marlin/config.ini new file mode 100644 index 00000000..85b05d18 --- /dev/null +++ b/Marlin/config.ini @@ -0,0 +1,251 @@ +# +# Marlin Firmware +# config.ini - Options to apply before the build +# +[config:base] +# +# ini_use_config - A comma-separated list of actions to apply to the Configuration files. +# The actions will be applied in the listed order. +# - none +# Ignore this file and don't apply any configuration options +# +# - base +# Just apply the options in config:base to the configuration +# +# - minimal +# Just apply the options in config:minimal to the configuration +# +# - all +# Apply all 'config:*' sections in this file to the configuration +# +# - another.ini +# Load another INI file with a path relative to this config.ini file (i.e., within Marlin/) +# +# - https://me.myserver.com/path/to/configs +# Fetch configurations from any URL. +# +# - example/Creality/Ender-5 Plus @ bugfix-2.1.x +# Fetch example configuration files from the MarlinFirmware/Configurations repository +# https://raw.githubusercontent.com/MarlinFirmware/Configurations/bugfix-2.1.x/config/examples/Creality/Ender-5%20Plus/ +# +# - example/default @ release-2.0.9.7 +# Fetch default configuration files from the MarlinFirmware/Configurations repository +# https://raw.githubusercontent.com/MarlinFirmware/Configurations/release-2.0.9.7/config/default/ +# +# - [disable] +# Comment out all #defines in both Configuration.h and Configuration_adv.h. This is useful +# to start with a clean slate before applying any config: options, so only the options explicitly +# set in config.ini will be enabled in the configuration. +# +# - [flatten] (Not yet implemented) +# Produce a flattened set of Configuration.h and Configuration_adv.h files with only the enabled +# #defines and no comments. A clean look, but context-free. +# +ini_use_config = none + +# Load all config: sections in this file +;ini_use_config = all +# Disable everything and apply subsequent config:base options +;ini_use_config = [disable], base +# Load config file relative to Marlin/ +;ini_use_config = another.ini +# Download configurations from GitHub +;ini_use_config = example/Creality/Ender-5 Plus @ bugfix-2.1.x +# Download configurations from your server +;ini_use_config = https://me.myserver.com/path/to/configs +# Evaluate config:base and do a config dump +;ini_use_config = base +;config_export = 2 + +[config:minimal] +motherboard = BOARD_RAMPS_14_EFB +serial_port = 0 +baudrate = 250000 + +use_watchdog = on +thermal_protection_hotends = on +thermal_protection_hysteresis = 4 +thermal_protection_period = 40 + +bufsize = 4 +block_buffer_size = 16 +max_cmd_size = 96 + +extruders = 1 +temp_sensor_0 = 1 + +temp_hysteresis = 3 +heater_0_mintemp = 5 +heater_0_maxtemp = 275 +preheat_1_temp_hotend = 180 + +bang_max = 255 +pidtemp = on +pid_k1 = 0.95 +pid_max = 255 +pid_functional_range = 10 + +default_kp = 22.20 +default_ki = 1.08 +default_kd = 114.00 + +x_driver_type = A4988 +y_driver_type = A4988 +z_driver_type = A4988 +e0_driver_type = A4988 + +x_bed_size = 200 +x_min_pos = 0 +x_max_pos = X_BED_SIZE + +y_bed_size = 200 +y_min_pos = 0 +y_max_pos = Y_BED_SIZE + +z_min_pos = 0 +z_max_pos = 200 + +x_home_dir = -1 +y_home_dir = -1 +z_home_dir = -1 + +use_xmin_plug = on +use_ymin_plug = on +use_zmin_plug = on + +x_min_endstop_inverting = false +y_min_endstop_inverting = false +z_min_endstop_inverting = false + +default_axis_steps_per_unit = { 80, 80, 400, 500 } +axis_relative_modes = { false, false, false, false } +default_max_feedrate = { 300, 300, 5, 25 } +default_max_acceleration = { 3000, 3000, 100, 10000 } + +homing_feedrate_mm_m = { (50*60), (50*60), (4*60) } +homing_bump_divisor = { 2, 2, 4 } + +x_enable_on = 0 +y_enable_on = 0 +z_enable_on = 0 +e_enable_on = 0 + +invert_x_dir = false +invert_y_dir = true +invert_z_dir = false +invert_e0_dir = false + +invert_e_step_pin = false +invert_x_step_pin = false +invert_y_step_pin = false +invert_z_step_pin = false + +disable_x = off +disable_y = off +disable_z = off +disable_e = off + +proportional_font_ratio = 1.0 +default_nominal_filament_dia = 1.75 + +junction_deviation_mm = 0.013 + +default_acceleration = 3000 +default_travel_acceleration = 3000 +default_retract_acceleration = 3000 + +default_minimumfeedrate = 0.0 +default_mintravelfeedrate = 0.0 + +minimum_planner_speed = 0.05 +min_steps_per_segment = 6 +default_minsegmenttime = 20000 + +[config:basic] +bed_overshoot = 10 +busy_while_heating = on +default_ejerk = 5.0 +default_keepalive_interval = 2 +default_leveling_fade_height = 0.0 +disable_other_extruders = on +display_charset_hd44780 = JAPANESE +eeprom_boot_silent = on +eeprom_chitchat = on +endstoppullups = on +extrude_maxlength = 200 +extrude_mintemp = 170 +host_keepalive_feature = on +hotend_overshoot = 15 +jd_handle_small_segments = on +lcd_info_screen_style = 0 +lcd_language = en +max_bed_power = 255 +mesh_inset = 0 +min_software_endstops = on +max_software_endstops = on +min_software_endstop_x = on +min_software_endstop_y = on +min_software_endstop_z = on +max_software_endstop_x = on +max_software_endstop_y = on +max_software_endstop_z = on +preheat_1_fan_speed = 0 +preheat_1_label = "PLA" +preheat_1_temp_bed = 70 +prevent_cold_extrusion = on +prevent_lengthy_extrude = on +printjob_timer_autostart = on +probing_margin = 10 +show_bootscreen = on +soft_pwm_scale = 0 +string_config_h_author = "(none, default config)" +temp_bed_hysteresis = 3 +temp_bed_residency_time = 10 +temp_bed_window = 1 +temp_residency_time = 10 +temp_window = 1 +validate_homing_endstops = on +xy_probe_feedrate = (133*60) +z_clearance_between_probes = 5 +z_clearance_deploy_probe = 10 +z_clearance_multi_probe = 5 + +[config:advanced] +arc_support = on +auto_report_temperatures = on +autotemp = on +autotemp_oldweight = 0.98 +bed_check_interval = 5000 +default_stepper_timeout_sec = 120 +default_volumetric_extruder_limit = 0.00 +disable_idle_x = on +disable_idle_y = on +disable_idle_z = on +disable_idle_e = on +e0_auto_fan_pin = -1 +encoder_100x_steps_per_sec = 80 +encoder_10x_steps_per_sec = 30 +encoder_rate_multiplier = on +extended_capabilities_report = on +extruder_auto_fan_speed = 255 +extruder_auto_fan_temperature = 50 +fanmux0_pin = -1 +fanmux1_pin = -1 +fanmux2_pin = -1 +faster_gcode_parser = on +homing_bump_mm = { 5, 5, 2 } +max_arc_segment_mm = 1.0 +min_arc_segment_mm = 0.1 +min_circle_segments = 72 +n_arc_correction = 25 +serial_overrun_protection = on +slowdown = on +slowdown_divisor = 2 +temp_sensor_bed = 0 +thermal_protection_bed_hysteresis = 2 +thermocouple_max_errors = 15 +tx_buffer_size = 0 +watch_bed_temp_increase = 2 +watch_bed_temp_period = 60 +watch_temp_increase = 2 +watch_temp_period = 20 diff --git a/Marlin/src/HAL/AVR/HAL.cpp b/Marlin/src/HAL/AVR/HAL.cpp index d7bf2a6f..3dadfafe 100644 --- a/Marlin/src/HAL/AVR/HAL.cpp +++ b/Marlin/src/HAL/AVR/HAL.cpp @@ -23,6 +23,7 @@ #include "../../inc/MarlinConfig.h" #include "HAL.h" +#include #ifdef USBCON DefaultSerial1 MSerial0(false, Serial); @@ -36,7 +37,7 @@ // ------------------------ // Don't initialize/override variable (which would happen in .init4) -uint8_t reset_reason __attribute__((section(".noinit"))); +uint8_t MarlinHAL::reset_reason __attribute__((section(".noinit"))); // ------------------------ // Public functions @@ -45,39 +46,46 @@ uint8_t reset_reason __attribute__((section(".noinit"))); __attribute__((naked)) // Don't output function pro- and epilogue __attribute__((used)) // Output the function, even if "not used" __attribute__((section(".init3"))) // Put in an early user definable section -void HAL_save_reset_reason() { +void save_reset_reason() { #if ENABLED(OPTIBOOT_RESET_REASON) __asm__ __volatile__( A("STS %0, r2") - : "=m"(reset_reason) + : "=m"(hal.reset_reason) ); #else - reset_reason = MCUSR; + hal.reset_reason = MCUSR; #endif // Clear within 16ms since WDRF bit enables a 16ms watchdog timer -> Boot loop - MCUSR = 0; + hal.clear_reset_source(); wdt_disable(); } -void HAL_init() { +void MarlinHAL::init() { // Init Servo Pins - #define INIT_SERVO(N) OUT_WRITE(SERVO##N##_PIN, LOW) #if HAS_SERVO_0 - INIT_SERVO(0); + OUT_WRITE(SERVO0_PIN, LOW); #endif #if HAS_SERVO_1 - INIT_SERVO(1); + OUT_WRITE(SERVO1_PIN, LOW); #endif #if HAS_SERVO_2 - INIT_SERVO(2); + OUT_WRITE(SERVO2_PIN, LOW); #endif #if HAS_SERVO_3 - INIT_SERVO(3); + OUT_WRITE(SERVO3_PIN, LOW); #endif + #if HAS_SERVO_4 + OUT_WRITE(SERVO4_PIN, LOW); + #endif + #if HAS_SERVO_5 + OUT_WRITE(SERVO5_PIN, LOW); + #endif + + init_pwm_timers(); // Init user timers to default frequency - 1000HZ } -void HAL_reboot() { +void MarlinHAL::reboot() { #if ENABLED(USE_WATCHDOG) while (1) { /* run out the watchdog */ } #else @@ -86,28 +94,84 @@ void HAL_reboot() { #endif } -#if ENABLED(SDSUPPORT) +// ------------------------ +// Watchdog Timer +// ------------------------ - #include "../../sd/SdFatUtil.h" - int freeMemory() { return SdFatUtil::FreeRam(); } +#if ENABLED(USE_WATCHDOG) + + #include + #include "../../MarlinCore.h" + + // Initialize watchdog with 8s timeout, if possible. Otherwise, make it 4s. + void MarlinHAL::watchdog_init() { + #if ENABLED(WATCHDOG_DURATION_8S) && defined(WDTO_8S) + #define WDTO_NS WDTO_8S + #else + #define WDTO_NS WDTO_4S + #endif + #if ENABLED(WATCHDOG_RESET_MANUAL) + // Enable the watchdog timer, but only for the interrupt. + // Take care, as this requires the correct order of operation, with interrupts disabled. + // See the datasheet of any AVR chip for details. + wdt_reset(); + cli(); + _WD_CONTROL_REG = _BV(_WD_CHANGE_BIT) | _BV(WDE); + _WD_CONTROL_REG = _BV(WDIE) | (WDTO_NS & 0x07) | ((WDTO_NS & 0x08) << 2); // WDTO_NS directly does not work. bit 0-2 are consecutive in the register but the highest value bit is at bit 5 + // So worked for up to WDTO_2S + sei(); + wdt_reset(); + #else + wdt_enable(WDTO_NS); // The function handles the upper bit correct. + #endif + //delay(10000); // test it! + } + + //=========================================================================== + //=================================== ISR =================================== + //=========================================================================== + + // Watchdog timer interrupt, called if main program blocks >4sec and manual reset is enabled. + #if ENABLED(WATCHDOG_RESET_MANUAL) + ISR(WDT_vect) { + sei(); // With the interrupt driven serial we need to allow interrupts. + SERIAL_ERROR_MSG(STR_WATCHDOG_FIRED); + minkill(); // interrupt-safe final kill and infinite loop + } + #endif + + // Reset watchdog. MUST be called at least every 4 seconds after the + // first watchdog_init or AVR will go into emergency procedures. + void MarlinHAL::watchdog_refresh() { wdt_reset(); } + +#endif // USE_WATCHDOG -#else // !SDSUPPORT +// ------------------------ +// Free Memory Accessor +// ------------------------ -extern "C" { - extern char __bss_end; - extern char __heap_start; - extern void* __brkval; +#if HAS_MEDIA - int freeMemory() { - int free_memory; - if ((int)__brkval == 0) - free_memory = ((int)&free_memory) - ((int)&__bss_end); - else - free_memory = ((int)&free_memory) - ((int)__brkval); - return free_memory; + #include "../../sd/SdFatUtil.h" + int freeMemory() { return SdFatUtil::FreeRam(); } + +#else // !HAS_MEDIA + + extern "C" { + extern char __bss_end; + extern char __heap_start; + extern void* __brkval; + + int freeMemory() { + int free_memory; + if ((int)__brkval == 0) + free_memory = ((int)&free_memory) - ((int)&__bss_end); + else + free_memory = ((int)&free_memory) - ((int)__brkval); + return free_memory; + } } -} -#endif // !SDSUPPORT +#endif // !HAS_MEDIA #endif // __AVR__ diff --git a/Marlin/src/HAL/AVR/HAL.h b/Marlin/src/HAL/AVR/HAL.h index 2217f239..0f882525 100644 --- a/Marlin/src/HAL/AVR/HAL.h +++ b/Marlin/src/HAL/AVR/HAL.h @@ -1,7 +1,9 @@ /** * Marlin 3D Printer Firmware * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,17 +21,20 @@ */ #pragma once +/** + * HAL for Arduino AVR + */ + #include "../shared/Marduino.h" #include "../shared/HAL_SPI.h" #include "fastio.h" -#include "watchdog.h" #include "math.h" #ifdef USBCON #include #else - #define HardwareSerial_h // Hack to prevent HardwareSerial.h header inclusion #include "MarlinSerial.h" + #define BOARD_NO_NATIVE_USB #endif #include @@ -74,9 +79,9 @@ #define CRITICAL_SECTION_START() unsigned char _sreg = SREG; cli() #define CRITICAL_SECTION_END() SREG = _sreg #endif -#define ISRS_ENABLED() TEST(SREG, SREG_I) -#define ENABLE_ISRS() sei() -#define DISABLE_ISRS() cli() + +#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment +#define PWM_FREQUENCY 1000 // Default PWM frequency when set_pwm_duty() is called without set_pwm_frequency() // ------------------------ // Types @@ -84,16 +89,15 @@ typedef int8_t pin_t; -#define SHARED_SERVOS HAS_SERVOS -#define HAL_SERVO_LIB Servo +#define SHARED_SERVOS HAS_SERVOS // Use shared/servos.cpp + +class Servo; +typedef Servo hal_servo_t; // ------------------------ -// Public Variables +// Serial ports // ------------------------ -extern uint8_t reset_reason; - -// Serial ports #ifdef USBCON #include "../../core/serial_hook.h" typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1; @@ -105,57 +109,68 @@ extern uint8_t reset_reason; #define MYSERIAL1 TERN(BLUETOOTH, btSerial, MSerial0) #else - #if !WITHIN(SERIAL_PORT, -1, 3) - #error "SERIAL_PORT must be from 0 to 3, or -1 for USB Serial." + #if !WITHIN(SERIAL_PORT, 0, 3) + #error "SERIAL_PORT must be from 0 to 3." #endif #define MYSERIAL1 customizedSerial1 #ifdef SERIAL_PORT_2 - #if !WITHIN(SERIAL_PORT_2, -1, 3) - #error "SERIAL_PORT_2 must be from 0 to 3, or -1 for USB Serial." + #if !WITHIN(SERIAL_PORT_2, 0, 3) + #error "SERIAL_PORT_2 must be from 0 to 3." #endif #define MYSERIAL2 customizedSerial2 #endif #ifdef SERIAL_PORT_3 - #if !WITHIN(SERIAL_PORT_3, -1, 3) - #error "SERIAL_PORT_3 must be from 0 to 3, or -1 for USB Serial." + #if !WITHIN(SERIAL_PORT_3, 0, 3) + #error "SERIAL_PORT_3 must be from 0 to 3." #endif #define MYSERIAL3 customizedSerial3 #endif #endif #ifdef MMU2_SERIAL_PORT - #if !WITHIN(MMU2_SERIAL_PORT, -1, 3) - #error "MMU2_SERIAL_PORT must be from 0 to 3, or -1 for USB Serial." + #if !WITHIN(MMU2_SERIAL_PORT, 0, 3) + #error "MMU2_SERIAL_PORT must be from 0 to 3" #endif #define MMU2_SERIAL mmuSerial #endif #ifdef LCD_SERIAL_PORT - #if !WITHIN(LCD_SERIAL_PORT, -1, 3) - #error "LCD_SERIAL_PORT must be from 0 to 3, or -1 for USB Serial." + #if !WITHIN(LCD_SERIAL_PORT, 0, 3) + #error "LCD_SERIAL_PORT must be from 0 to 3." #endif #define LCD_SERIAL lcdSerial #if HAS_DGUS_LCD - #define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.get_tx_buffer_free() + #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.get_tx_buffer_free() #endif #endif -// ------------------------ -// Public functions -// ------------------------ +// +// ADC +// +#define HAL_ADC_VREF_MV 5000 +#define HAL_ADC_RESOLUTION 10 -void HAL_init(); +// +// Pin Mapping for M42, M43, M226 +// +#define GET_PIN_MAP_PIN(index) index +#define GET_PIN_MAP_INDEX(pin) pin +#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval) -//void cli(); +#define HAL_SENSITIVE_PINS 0, 1, -//void _delay_ms(const int delay); +#ifdef __AVR_AT90USB1286__ + #define JTAG_DISABLE() do{ MCUCR = 0x80; MCUCR = 0x80; }while(0) +#endif -inline void HAL_clear_reset_source() { } -inline uint8_t HAL_get_reset_source() { return reset_reason; } +// AVR compatibility +#define strtof strtod -void HAL_reboot(); +// ------------------------ +// Free Memory Accessor +// ------------------------ #pragma GCC diagnostic push #if GCC_VERSION <= 50000 @@ -166,63 +181,100 @@ extern "C" int freeMemory(); #pragma GCC diagnostic pop -// ADC -#ifdef DIDR2 - #define HAL_ANALOG_SELECT(ind) do{ if (ind < 8) SBI(DIDR0, ind); else SBI(DIDR2, ind & 0x07); }while(0) -#else - #define HAL_ANALOG_SELECT(ind) SBI(DIDR0, ind); -#endif +// ------------------------ +// MarlinHAL Class +// ------------------------ -inline void HAL_adc_init() { - ADCSRA = _BV(ADEN) | _BV(ADSC) | _BV(ADIF) | 0x07; - DIDR0 = 0; - #ifdef DIDR2 - DIDR2 = 0; - #endif -} +class MarlinHAL { +public: -#define SET_ADMUX_ADCSRA(ch) ADMUX = _BV(REFS0) | (ch & 0x07); SBI(ADCSRA, ADSC) -#ifdef MUX5 - #define HAL_START_ADC(ch) if (ch > 7) ADCSRB = _BV(MUX5); else ADCSRB = 0; SET_ADMUX_ADCSRA(ch) -#else - #define HAL_START_ADC(ch) ADCSRB = 0; SET_ADMUX_ADCSRA(ch) -#endif + // Earliest possible init, before setup() + MarlinHAL() {} -#define HAL_ADC_VREF 5.0 -#define HAL_ADC_RESOLUTION 10 -#define HAL_READ_ADC() ADC -#define HAL_ADC_READY() !TEST(ADCSRA, ADSC) + // Watchdog + static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {}); + static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {}); -#define GET_PIN_MAP_PIN(index) index -#define GET_PIN_MAP_INDEX(pin) pin -#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval) + static void init(); // Called early in setup() + static void init_board() {} // Called less early in setup() + static void reboot(); // Restart the firmware from 0x0 -#define HAL_SENSITIVE_PINS 0, 1, + // Interrupts + static bool isr_state() { return TEST(SREG, SREG_I); } + static void isr_on() { sei(); } + static void isr_off() { cli(); } -#ifdef __AVR_AT90USB1286__ - #define JTAG_DISABLE() do{ MCUCR = 0x80; MCUCR = 0x80; }while(0) -#endif + static void delay_ms(const int ms) { _delay_ms(ms); } -// AVR compatibility -#define strtof strtod + // Tasks, called from idle() + static void idletask() {} -#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment + // Reset + static uint8_t reset_reason; + static uint8_t get_reset_source() { return reset_reason; } + static void clear_reset_source() { MCUSR = 0; } -/** - * set_pwm_frequency - * Sets the frequency of the timer corresponding to the provided pin - * as close as possible to the provided desired frequency. Internally - * calculates the required waveform generation mode, prescaler and - * resolution values required and sets the timer registers accordingly. - * NOTE that the frequency is applied to all pins on the timer (Ex OC3A, OC3B and OC3B) - * NOTE that there are limitations, particularly if using TIMER2. (see Configuration_adv.h -> FAST FAN PWM Settings) - */ -void set_pwm_frequency(const pin_t pin, int f_desired); + // Free SRAM + static int freeMemory() { return ::freeMemory(); } -/** - * set_pwm_duty - * Set the PWM duty cycle of the provided pin to the provided value - * Optionally allows inverting the duty cycle [default = false] - * Optionally allows changing the maximum size of the provided value to enable finer PWM duty control [default = 255] - */ -void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false); + // + // ADC Methods + // + + // Called by Temperature::init once at startup + static void adc_init() { + ADCSRA = _BV(ADEN) | _BV(ADSC) | _BV(ADIF) | 0x07; + DIDR0 = 0; + #ifdef DIDR2 + DIDR2 = 0; + #endif + } + + // Called by Temperature::init for each sensor at startup + static void adc_enable(const uint8_t ch) { + #ifdef DIDR2 + if (ch > 7) { SBI(DIDR2, ch & 0x07); return; } + #endif + SBI(DIDR0, ch); + } + + // Begin ADC sampling on the given channel. Called from Temperature::isr! + static void adc_start(const uint8_t ch) { + #ifdef MUX5 + ADCSRB = ch > 7 ? _BV(MUX5) : 0; + #else + ADCSRB = 0; + #endif + ADMUX = _BV(REFS0) | (ch & 0x07); + SBI(ADCSRA, ADSC); + } + + // Is the ADC ready for reading? + static bool adc_ready() { return !TEST(ADCSRA, ADSC); } + + // The current value of the ADC register + static __typeof__(ADC) adc_value() { return ADC; } + + /** + * init_pwm_timers + * Set the default frequency for timers 2-5 to 1000HZ + */ + static void init_pwm_timers(); + + /** + * Set the PWM duty cycle for the pin to the given value. + * Optionally invert the duty cycle [default = false] + * Optionally change the scale of the provided value to enable finer PWM duty control [default = 255] + */ + static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false); + + /** + * Set the frequency of the timer for the given pin as close as + * possible to the provided desired frequency. Internally calculate + * the required waveform generation mode, prescaler, and resolution + * values and set timer registers accordingly. + * NOTE that the frequency is applied to all pins on the timer (Ex OC3A, OC3B and OC3B) + * NOTE that there are limitations, particularly if using TIMER2. (see Configuration_adv.h -> FAST_PWM_FAN Settings) + */ + static void set_pwm_frequency(const pin_t pin, const uint16_t f_desired); +}; diff --git a/Marlin/src/HAL/AVR/HAL_SPI.cpp b/Marlin/src/HAL/AVR/HAL_SPI.cpp index 8784bb07..db6a1273 100644 --- a/Marlin/src/HAL/AVR/HAL_SPI.cpp +++ b/Marlin/src/HAL/AVR/HAL_SPI.cpp @@ -35,22 +35,20 @@ void spiBegin() { #if PIN_EXISTS(SD_SS) - OUT_WRITE(SD_SS_PIN, HIGH); + // Do not init HIGH for boards with pin 4 used as Fans or Heaters or otherwise, not likely to have multiple SPI devices anyway. + #if defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega1284P__) + // SS must be in output mode even it is not chip select + SET_OUTPUT(SD_SS_PIN); + #else + // set SS high - may be chip select for another SPI device + OUT_WRITE(SD_SS_PIN, HIGH); + #endif #endif SET_OUTPUT(SD_SCK_PIN); SET_INPUT(SD_MISO_PIN); SET_OUTPUT(SD_MOSI_PIN); - #if DISABLED(SOFTWARE_SPI) - // SS must be in output mode even it is not chip select - //SET_OUTPUT(SD_SS_PIN); - // set SS high - may be chip select for another SPI device - //#if SET_SPI_SS_HIGH - //WRITE(SD_SS_PIN, HIGH); - //#endif - // set a default rate - spiInit(1); - #endif + IF_DISABLED(SOFTWARE_SPI, spiInit(SPI_HALF_SPEED)); } #if NONE(SOFTWARE_SPI, FORCE_SOFT_SPI) @@ -121,7 +119,6 @@ void spiBegin() { while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ } } - /** begin spi transaction */ void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) { // Based on Arduino SPI library @@ -177,7 +174,6 @@ void spiBegin() { SPSR = clockDiv | 0x01; } - #else // SOFTWARE_SPI || FORCE_SOFT_SPI // ------------------------ @@ -200,7 +196,7 @@ void spiBegin() { // output pin high - like sending 0xFF WRITE(SD_MOSI_PIN, HIGH); - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { WRITE(SD_SCK_PIN, HIGH); nop; // adjust so SCK is nice @@ -227,7 +223,7 @@ void spiBegin() { void spiSend(uint8_t data) { // no interrupts during byte send - about 8µs cli(); - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { WRITE(SD_SCK_PIN, LOW); WRITE(SD_MOSI_PIN, data & 0x80); data <<= 1; diff --git a/Marlin/src/HAL/AVR/MarlinSerial.cpp b/Marlin/src/HAL/AVR/MarlinSerial.cpp index cd8bf5e6..98646243 100644 --- a/Marlin/src/HAL/AVR/MarlinSerial.cpp +++ b/Marlin/src/HAL/AVR/MarlinSerial.cpp @@ -486,7 +486,7 @@ void MarlinSerial::write(const uint8_t c) { const uint8_t i = (tx_buffer.head + 1) & (Cfg::TX_SIZE - 1); // If global interrupts are disabled (as the result of being called from an ISR)... - if (!ISRS_ENABLED()) { + if (!hal.isr_state()) { // Make room by polling if it is possible to transmit, and do so! while (i == tx_buffer.tail) { @@ -534,7 +534,7 @@ void MarlinSerial::flushTX() { if (!_written) return; // If global interrupts are disabled (as the result of being called from an ISR)... - if (!ISRS_ENABLED()) { + if (!hal.isr_state()) { // Wait until everything was transmitted - We must do polling, as interrupts are disabled while (tx_buffer.head != tx_buffer.tail || !B_TXC) { diff --git a/Marlin/src/HAL/AVR/MarlinSerial.h b/Marlin/src/HAL/AVR/MarlinSerial.h index 0565c7b9..a40730e0 100644 --- a/Marlin/src/HAL/AVR/MarlinSerial.h +++ b/Marlin/src/HAL/AVR/MarlinSerial.h @@ -34,12 +34,9 @@ #include #include "../../inc/MarlinConfigPre.h" +#include "../../core/types.h" #include "../../core/serial_hook.h" -#ifndef SERIAL_PORT - #define SERIAL_PORT 0 -#endif - #ifndef USBCON // The presence of the UBRRH register is used to detect a UART. @@ -138,10 +135,6 @@ #define BYTE 0 - // Templated type selector - template struct TypeSelector { typedef T type;} ; - template struct TypeSelector { typedef F type; }; - template class MarlinSerial { protected: @@ -164,7 +157,7 @@ static constexpr B_U2Xx B_U2X = 0; // Base size of type on buffer size - typedef typename TypeSelector<(Cfg::RX_SIZE>256), uint16_t, uint8_t>::type ring_buffer_pos_t; + typedef uvalue_t(Cfg::RX_SIZE - 1) ring_buffer_pos_t; struct ring_buffer_r { volatile ring_buffer_pos_t head, tail; @@ -191,13 +184,13 @@ rx_framing_errors; static ring_buffer_pos_t rx_max_enqueued; - static FORCE_INLINE ring_buffer_pos_t atomic_read_rx_head(); + FORCE_INLINE static ring_buffer_pos_t atomic_read_rx_head(); static volatile bool rx_tail_value_not_stable; static volatile uint16_t rx_tail_value_backup; - static FORCE_INLINE void atomic_set_rx_tail(ring_buffer_pos_t value); - static FORCE_INLINE ring_buffer_pos_t atomic_read_rx_tail(); + FORCE_INLINE static void atomic_set_rx_tail(ring_buffer_pos_t value); + FORCE_INLINE static ring_buffer_pos_t atomic_read_rx_tail(); public: FORCE_INLINE static void store_rxd_char(); @@ -217,7 +210,7 @@ #endif enum { HasEmergencyParser = Cfg::EMERGENCYPARSER }; - static inline bool emergency_parser_enabled() { return Cfg::EMERGENCYPARSER; } + static bool emergency_parser_enabled() { return Cfg::EMERGENCYPARSER; } FORCE_INLINE static uint8_t dropped() { return Cfg::DROPPED_RX ? rx_dropped_bytes : 0; } FORCE_INLINE static uint8_t buffer_overruns() { return Cfg::RX_OVERRUNS ? rx_buffer_overruns : 0; } @@ -283,7 +276,7 @@ static constexpr bool DROPPED_RX = false; static constexpr bool RX_FRAMING_ERRORS = false; static constexpr bool MAX_RX_QUEUED = false; - static constexpr bool RX_OVERRUNS = BOTH(HAS_DGUS_LCD, SERIAL_STATS_RX_BUFFER_OVERRUNS); + static constexpr bool RX_OVERRUNS = ALL(HAS_DGUS_LCD, SERIAL_STATS_RX_BUFFER_OVERRUNS); }; typedef Serial1Class< MarlinSerial< LCDSerialCfg > > MSerialLCD; diff --git a/Marlin/src/HAL/AVR/Servo.cpp b/Marlin/src/HAL/AVR/Servo.cpp index 526352b7..8ce9bc11 100644 --- a/Marlin/src/HAL/AVR/Servo.cpp +++ b/Marlin/src/HAL/AVR/Servo.cpp @@ -63,30 +63,28 @@ static volatile int8_t Channel[_Nbr_16timers]; // counter for the servo being pulsed for each timer (or -1 if refresh interval) - /************ 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 - } - - 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 +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] = ++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 +121,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 - - #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 _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 _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 -} - -void finISR(timer16_Sequence_t timer) { - // Disable use of the given timer - #ifdef WIRING - if (timer == _timer1) { - CBI( - #if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__) - TIMSK1 +void initISR(const timer16_Sequence_t timer_index) { + switch (timer_index) { + default: break; + + #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 - TIMSK + // here if not ATmega8 or ATmega128 + SBI(TIFR1, OCF1A); // clear any pending interrupts; + SBI(TIMSK1, OCIE1A); // enable the output compare interrupt #endif - , OCIE1A); // disable timer 1 output compare interrupt - timerDetach(TIMER1OUTCOMPAREA_INT); - } - else if (timer == _timer3) { - CBI( - #if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__) - TIMSK3 + #ifdef WIRING + timerAttach(TIMER1OUTCOMPAREA_INT, Timer1Service); + #endif + break; + #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 - ETIMSK + SBI(TIFR3, OCF3A); // clear any pending interrupts; + SBI(TIMSK3, OCIE3A); // enable the output compare interrupt #endif - , OCIE3A); // disable the timer3 output compare A interrupt - timerDetach(TIMER3OUTCOMPAREA_INT); + #ifdef WIRING + timerAttach(TIMER3OUTCOMPAREA_INT, Timer3Service); // for Wiring platform only + #endif + break; + #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(const timer16_Sequence_t timer_index) { + // Disable use of the given timer + #ifdef WIRING + 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 } diff --git a/Marlin/src/HAL/AVR/eeprom.cpp b/Marlin/src/HAL/AVR/eeprom.cpp index 8d084dec..6465e470 100644 --- a/Marlin/src/HAL/AVR/eeprom.cpp +++ b/Marlin/src/HAL/AVR/eeprom.cpp @@ -23,7 +23,7 @@ #include "../../inc/MarlinConfig.h" -#if EITHER(EEPROM_SETTINGS, SD_FIRMWARE_UPDATE) +#if ANY(EEPROM_SETTINGS, SD_FIRMWARE_UPDATE) /** * PersistentStore for Arduino-style EEPROM interface diff --git a/Marlin/src/HAL/AVR/endstop_interrupts.h b/Marlin/src/HAL/AVR/endstop_interrupts.h index 50f29c33..52b3ad98 100644 --- a/Marlin/src/HAL/AVR/endstop_interrupts.h +++ b/Marlin/src/HAL/AVR/endstop_interrupts.h @@ -91,7 +91,6 @@ void endstop_ISR() { endstops.update(); } #endif - // Install Pin change interrupt for a pin. Can be called multiple times. void pciSetup(const int8_t pin) { if (digitalPinHasPCICR(pin)) { @@ -120,7 +119,7 @@ void pciSetup(const int8_t pin) { void setup_endstop_interrupts() { #define _ATTACH(P) attachInterrupt(digitalPinToInterrupt(P), endstop_ISR, CHANGE) - #if HAS_X_MAX + #if USE_X_MAX #if (digitalPinToInterrupt(X_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(X_MAX_PIN); #else @@ -128,7 +127,7 @@ void setup_endstop_interrupts() { pciSetup(X_MAX_PIN); #endif #endif - #if HAS_X_MIN + #if USE_X_MIN #if (digitalPinToInterrupt(X_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(X_MIN_PIN); #else @@ -136,7 +135,7 @@ void setup_endstop_interrupts() { pciSetup(X_MIN_PIN); #endif #endif - #if HAS_Y_MAX + #if USE_Y_MAX #if (digitalPinToInterrupt(Y_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(Y_MAX_PIN); #else @@ -144,7 +143,7 @@ void setup_endstop_interrupts() { pciSetup(Y_MAX_PIN); #endif #endif - #if HAS_Y_MIN + #if USE_Y_MIN #if (digitalPinToInterrupt(Y_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(Y_MIN_PIN); #else @@ -152,7 +151,7 @@ void setup_endstop_interrupts() { pciSetup(Y_MIN_PIN); #endif #endif - #if HAS_Z_MAX + #if USE_Z_MAX #if (digitalPinToInterrupt(Z_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(Z_MAX_PIN); #else @@ -160,7 +159,7 @@ void setup_endstop_interrupts() { pciSetup(Z_MAX_PIN); #endif #endif - #if HAS_Z_MIN + #if USE_Z_MIN #if (digitalPinToInterrupt(Z_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(Z_MIN_PIN); #else @@ -168,52 +167,97 @@ void setup_endstop_interrupts() { pciSetup(Z_MIN_PIN); #endif #endif - #if HAS_I_MAX + #if USE_I_MAX #if (digitalPinToInterrupt(I_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(I_MAX_PIN); #else - static_assert(digitalPinHasPCICR(I_MAX_PIN), "I_MAX_PIN is not interrupt-capable"); + static_assert(digitalPinHasPCICR(I_MAX_PIN), "I_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); pciSetup(I_MAX_PIN); #endif - #elif HAS_I_MIN + #elif USE_I_MIN #if (digitalPinToInterrupt(I_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(I_MIN_PIN); #else - static_assert(digitalPinHasPCICR(I_MIN_PIN), "I_MIN_PIN is not interrupt-capable"); + static_assert(digitalPinHasPCICR(I_MIN_PIN), "I_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); pciSetup(I_MIN_PIN); #endif #endif - #if HAS_J_MAX + #if USE_J_MAX #if (digitalPinToInterrupt(J_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(J_MAX_PIN); #else - static_assert(digitalPinHasPCICR(J_MAX_PIN), "J_MAX_PIN is not interrupt-capable"); + static_assert(digitalPinHasPCICR(J_MAX_PIN), "J_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); pciSetup(J_MAX_PIN); #endif - #elif HAS_J_MIN + #elif USE_J_MIN #if (digitalPinToInterrupt(J_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(J_MIN_PIN); #else - static_assert(digitalPinHasPCICR(J_MIN_PIN), "J_MIN_PIN is not interrupt-capable"); + static_assert(digitalPinHasPCICR(J_MIN_PIN), "J_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); pciSetup(J_MIN_PIN); #endif #endif - #if HAS_K_MAX + #if USE_K_MAX #if (digitalPinToInterrupt(K_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(K_MAX_PIN); #else - static_assert(digitalPinHasPCICR(K_MAX_PIN), "K_MAX_PIN is not interrupt-capable"); + static_assert(digitalPinHasPCICR(K_MAX_PIN), "K_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); pciSetup(K_MAX_PIN); #endif - #elif HAS_K_MIN + #elif USE_K_MIN #if (digitalPinToInterrupt(K_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(K_MIN_PIN); #else - static_assert(digitalPinHasPCICR(K_MIN_PIN), "K_MIN_PIN is not interrupt-capable"); + static_assert(digitalPinHasPCICR(K_MIN_PIN), "K_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); pciSetup(K_MIN_PIN); #endif #endif - #if HAS_X2_MAX + #if USE_U_MAX + #if (digitalPinToInterrupt(U_MAX_PIN) != NOT_AN_INTERRUPT) + _ATTACH(U_MAX_PIN); + #else + static_assert(digitalPinHasPCICR(U_MAX_PIN), "U_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); + pciSetup(U_MAX_PIN); + #endif + #elif USE_U_MIN + #if (digitalPinToInterrupt(U_MIN_PIN) != NOT_AN_INTERRUPT) + _ATTACH(U_MIN_PIN); + #else + static_assert(digitalPinHasPCICR(U_MIN_PIN), "U_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); + pciSetup(U_MIN_PIN); + #endif + #endif + #if USE_V_MAX + #if (digitalPinToInterrupt(V_MAX_PIN) != NOT_AN_INTERRUPT) + _ATTACH(V_MAX_PIN); + #else + static_assert(digitalPinHasPCICR(V_MAX_PIN), "V_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); + pciSetup(V_MAX_PIN); + #endif + #elif USE_V_MIN + #if (digitalPinToInterrupt(V_MIN_PIN) != NOT_AN_INTERRUPT) + _ATTACH(V_MIN_PIN); + #else + static_assert(digitalPinHasPCICR(V_MIN_PIN), "V_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); + pciSetup(V_MIN_PIN); + #endif + #endif + #if USE_W_MAX + #if (digitalPinToInterrupt(W_MAX_PIN) != NOT_AN_INTERRUPT) + _ATTACH(W_MAX_PIN); + #else + static_assert(digitalPinHasPCICR(W_MAX_PIN), "W_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); + pciSetup(W_MAX_PIN); + #endif + #elif USE_W_MIN + #if (digitalPinToInterrupt(W_MIN_PIN) != NOT_AN_INTERRUPT) + _ATTACH(W_MIN_PIN); + #else + static_assert(digitalPinHasPCICR(W_MIN_PIN), "W_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."); + pciSetup(W_MIN_PIN); + #endif + #endif + #if USE_X2_MAX #if (digitalPinToInterrupt(X2_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(X2_MAX_PIN); #else @@ -221,7 +265,7 @@ void setup_endstop_interrupts() { pciSetup(X2_MAX_PIN); #endif #endif - #if HAS_X2_MIN + #if USE_X2_MIN #if (digitalPinToInterrupt(X2_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(X2_MIN_PIN); #else @@ -229,7 +273,7 @@ void setup_endstop_interrupts() { pciSetup(X2_MIN_PIN); #endif #endif - #if HAS_Y2_MAX + #if USE_Y2_MAX #if (digitalPinToInterrupt(Y2_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(Y2_MAX_PIN); #else @@ -237,7 +281,7 @@ void setup_endstop_interrupts() { pciSetup(Y2_MAX_PIN); #endif #endif - #if HAS_Y2_MIN + #if USE_Y2_MIN #if (digitalPinToInterrupt(Y2_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(Y2_MIN_PIN); #else @@ -245,7 +289,7 @@ void setup_endstop_interrupts() { pciSetup(Y2_MIN_PIN); #endif #endif - #if HAS_Z2_MAX + #if USE_Z2_MAX #if (digitalPinToInterrupt(Z2_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(Z2_MAX_PIN); #else @@ -253,7 +297,7 @@ void setup_endstop_interrupts() { pciSetup(Z2_MAX_PIN); #endif #endif - #if HAS_Z2_MIN + #if USE_Z2_MIN #if (digitalPinToInterrupt(Z2_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(Z2_MIN_PIN); #else @@ -261,7 +305,7 @@ void setup_endstop_interrupts() { pciSetup(Z2_MIN_PIN); #endif #endif - #if HAS_Z3_MAX + #if USE_Z3_MAX #if (digitalPinToInterrupt(Z3_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(Z3_MAX_PIN); #else @@ -269,7 +313,7 @@ void setup_endstop_interrupts() { pciSetup(Z3_MAX_PIN); #endif #endif - #if HAS_Z3_MIN + #if USE_Z3_MIN #if (digitalPinToInterrupt(Z3_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(Z3_MIN_PIN); #else @@ -277,7 +321,7 @@ void setup_endstop_interrupts() { pciSetup(Z3_MIN_PIN); #endif #endif - #if HAS_Z4_MAX + #if USE_Z4_MAX #if (digitalPinToInterrupt(Z4_MAX_PIN) != NOT_AN_INTERRUPT) _ATTACH(Z4_MAX_PIN); #else @@ -285,7 +329,7 @@ void setup_endstop_interrupts() { pciSetup(Z4_MAX_PIN); #endif #endif - #if HAS_Z4_MIN + #if USE_Z4_MIN #if (digitalPinToInterrupt(Z4_MIN_PIN) != NOT_AN_INTERRUPT) _ATTACH(Z4_MIN_PIN); #else @@ -301,5 +345,6 @@ void setup_endstop_interrupts() { pciSetup(Z_MIN_PROBE_PIN); #endif #endif + // If we arrive here without raising an assertion, each pin has either an EXT-interrupt or a PCI. } diff --git a/Marlin/src/HAL/AVR/fast_pwm.cpp b/Marlin/src/HAL/AVR/fast_pwm.cpp index 804e5fad..936f9e56 100644 --- a/Marlin/src/HAL/AVR/fast_pwm.cpp +++ b/Marlin/src/HAL/AVR/fast_pwm.cpp @@ -21,10 +21,11 @@ */ #ifdef __AVR__ -#include "../../inc/MarlinConfigPre.h" -#include "HAL.h" +#include "../../inc/MarlinConfig.h" -#if NEEDS_HARDWARE_PWM // Specific meta-flag for features that mandate PWM +//#define DEBUG_AVR_FAST_PWM +#define DEBUG_OUT ENABLED(DEBUG_AVR_FAST_PWM) +#include "../../core/debug_out.h" struct Timer { volatile uint8_t* TCCRnQ[3]; // max 3 TCCR registers per timer @@ -32,229 +33,207 @@ struct Timer { volatile uint16_t* ICRn; // max 1 ICR register per timer uint8_t n; // the timer number [0->5] uint8_t q; // the timer output [0->2] (A->C) + bool isPWM; // True if pin is a "hardware timer" + bool isProtected; // True if timer is protected }; +// Macros for the Timer structure +#define _SET_WGMnQ(T, V) do{ \ + *(T.TCCRnQ)[0] = (*(T.TCCRnQ)[0] & ~(0x3 << 0)) | (( int(V) & 0x3) << 0); \ + *(T.TCCRnQ)[1] = (*(T.TCCRnQ)[1] & ~(0x3 << 3)) | (((int(V) >> 2) & 0x3) << 3); \ + }while(0) + +// Set TCCR CS bits +#define _SET_CSn(T, V) (*(T.TCCRnQ)[1] = (*(T.TCCRnQ[1]) & ~(0x7 << 0)) | ((int(V) & 0x7) << 0)) + +// Set TCCR COM bits +#define _SET_COMnQ(T, Q, V) (*(T.TCCRnQ)[0] = (*(T.TCCRnQ)[0] & ~(0x3 << (6-2*(Q)))) | (int(V) << (6-2*(Q)))) + +// Set OCRnQ register +#define _SET_OCRnQ(T, Q, V) (*(T.OCRnQ)[Q] = int(V) & 0xFFFF) + +// Set ICRn register (one per timer) +#define _SET_ICRn(T, V) (*(T.ICRn) = int(V) & 0xFFFF) + /** - * get_pwm_timer - * Get the timer information and register of the provided pin. - * Return a Timer struct containing this information. - * Used by set_pwm_frequency, set_pwm_duty + * Return a Timer struct describing a pin's timer. */ -Timer get_pwm_timer(const pin_t pin) { +const Timer get_pwm_timer(const pin_t pin) { + uint8_t q = 0; + switch (digitalPinToTimer(pin)) { - // Protect reserved timers (TIMER0 & TIMER1) #ifdef TCCR0A - #if !AVR_AT90USB1286_FAMILY - case TIMER0A: - #endif - case TIMER0B: + IF_DISABLED(AVR_AT90USB1286_FAMILY, case TIMER0A:) #endif #ifdef TCCR1A case TIMER1A: case TIMER1B: #endif - break; - #if HAS_TCCR2 || defined(TCCR2A) - #if HAS_TCCR2 - case TIMER2: { - Timer timer = { - /*TCCRnQ*/ { &TCCR2, nullptr, nullptr }, - /*OCRnQ*/ { (uint16_t*)&OCR2, nullptr, nullptr }, - /*ICRn*/ nullptr, - /*n, q*/ 2, 0 - }; - } - #elif defined(TCCR2A) - #if ENABLED(USE_OCR2A_AS_TOP) - case TIMER2A: break; // protect TIMER2A - case TIMER2B: { - Timer timer = { - /*TCCRnQ*/ { &TCCR2A, &TCCR2B, nullptr }, - /*OCRnQ*/ { (uint16_t*)&OCR2A, (uint16_t*)&OCR2B, nullptr }, - /*ICRn*/ nullptr, - /*n, q*/ 2, 1 - }; - return timer; - } - #else - case TIMER2B: ++q; - case TIMER2A: { - Timer timer = { - /*TCCRnQ*/ { &TCCR2A, &TCCR2B, nullptr }, - /*OCRnQ*/ { (uint16_t*)&OCR2A, (uint16_t*)&OCR2B, nullptr }, - /*ICRn*/ nullptr, - 2, q - }; - return timer; - } - #endif - #endif + + break; // Protect reserved timers (TIMER0 & TIMER1) + + #ifdef TCCR0A + case TIMER0B: // Protected timer, but allow setting the duty cycle on OCR0B for pin D4 only + return Timer({ { &TCCR0A, nullptr, nullptr }, { (uint16_t*)&OCR0A, (uint16_t*)&OCR0B, nullptr }, nullptr, 0, 1, true, true }); #endif + + #if HAS_TCCR2 + case TIMER2: + return Timer({ { &TCCR2, nullptr, nullptr }, { (uint16_t*)&OCR2, nullptr, nullptr }, nullptr, 2, 0, true, false }); + #elif ENABLED(USE_OCR2A_AS_TOP) + case TIMER2A: break; // Protect TIMER2A since its OCR is used by TIMER2B + case TIMER2B: + return Timer({ { &TCCR2A, &TCCR2B, nullptr }, { (uint16_t*)&OCR2A, (uint16_t*)&OCR2B, nullptr }, nullptr, 2, 1, true, false }); + #elif defined(TCCR2A) + case TIMER2B: ++q; case TIMER2A: + return Timer({ { &TCCR2A, &TCCR2B, nullptr }, { (uint16_t*)&OCR2A, (uint16_t*)&OCR2B, nullptr }, nullptr, 2, q, true, false }); + #endif + #ifdef OCR3C - case TIMER3C: ++q; - case TIMER3B: ++q; - case TIMER3A: { - Timer timer = { - /*TCCRnQ*/ { &TCCR3A, &TCCR3B, &TCCR3C }, - /*OCRnQ*/ { &OCR3A, &OCR3B, &OCR3C }, - /*ICRn*/ &ICR3, - /*n, q*/ 3, q - }; - return timer; - } + case TIMER3C: ++q; case TIMER3B: ++q; case TIMER3A: + return Timer({ { &TCCR3A, &TCCR3B, &TCCR3C }, { &OCR3A, &OCR3B, &OCR3C }, &ICR3, 3, q, true, false }); #elif defined(OCR3B) - case TIMER3B: ++q; - case TIMER3A: { - Timer timer = { - /*TCCRnQ*/ { &TCCR3A, &TCCR3B, nullptr }, - /*OCRnQ*/ { &OCR3A, &OCR3B, nullptr }, - /*ICRn*/ &ICR3, - /*n, q*/ 3, q - }; - return timer; - } + case TIMER3B: ++q; case TIMER3A: + return Timer({ { &TCCR3A, &TCCR3B, nullptr }, { &OCR3A, &OCR3B, nullptr }, &ICR3, 3, q, true, false }); #endif + #ifdef TCCR4A - case TIMER4C: ++q; - case TIMER4B: ++q; - case TIMER4A: { - Timer timer = { - /*TCCRnQ*/ { &TCCR4A, &TCCR4B, &TCCR4C }, - /*OCRnQ*/ { &OCR4A, &OCR4B, &OCR4C }, - /*ICRn*/ &ICR4, - /*n, q*/ 4, q - }; - return timer; - } + case TIMER4C: ++q; case TIMER4B: ++q; case TIMER4A: + return Timer({ { &TCCR4A, &TCCR4B, &TCCR4C }, { &OCR4A, &OCR4B, &OCR4C }, &ICR4, 4, q, true, false }); #endif + #ifdef TCCR5A - case TIMER5C: ++q; - case TIMER5B: ++q; - case TIMER5A: { - Timer timer = { - /*TCCRnQ*/ { &TCCR5A, &TCCR5B, &TCCR5C }, - /*OCRnQ*/ { &OCR5A, &OCR5B, &OCR5C }, - /*ICRn*/ &ICR5, - /*n, q*/ 5, q - }; - return timer; - } + case TIMER5C: ++q; case TIMER5B: ++q; case TIMER5A: + return Timer({ { &TCCR5A, &TCCR5B, &TCCR5C }, { &OCR5A, &OCR5B, &OCR5C }, &ICR5, 5, q, true, false }); #endif } - Timer timer = { - /*TCCRnQ*/ { nullptr, nullptr, nullptr }, - /*OCRnQ*/ { nullptr, nullptr, nullptr }, - /*ICRn*/ nullptr, - 0, 0 - }; - return timer; + + return Timer(); } -void set_pwm_frequency(const pin_t pin, int f_desired) { - Timer timer = get_pwm_timer(pin); - if (timer.n == 0) return; // Don't proceed if protected timer or not recognized - uint16_t size; - if (timer.n == 2) size = 255; else size = 65535; +void MarlinHAL::set_pwm_frequency(const pin_t pin, const uint16_t f_desired) { + DEBUG_ECHOLNPGM("set_pwm_frequency(pin=", pin, ", freq=", f_desired, ")"); + const Timer timer = get_pwm_timer(pin); + if (timer.isProtected || !timer.isPWM) return; // Don't proceed if protected timer or not recognized + + const bool is_timer2 = timer.n == 2; + const uint16_t maxtop = is_timer2 ? 0xFF : 0xFFFF; + + DEBUG_ECHOLNPGM("maxtop=", maxtop); - uint16_t res = 255; // resolution (TOP value) - uint8_t j = 0; // prescaler index - uint8_t wgm = 1; // waveform generation mode + uint16_t res = 0xFF; // resolution (TOP value) + uint8_t j = CS_NONE; // prescaler index + uint8_t wgm = WGM_PWM_PC_8; // waveform generation mode // Calculating the prescaler and resolution to use to achieve closest frequency if (f_desired != 0) { - int f = (F_CPU) / (2 * 1024 * size) + 1; // Initialize frequency as lowest (non-zero) achievable - uint16_t prescaler[] = { 0, 1, 8, /*TIMER2 ONLY*/32, 64, /*TIMER2 ONLY*/128, 256, 1024 }; - - // loop over prescaler values - LOOP_S_L_N(i, 1, 8) { - uint16_t res_temp_fast = 255, res_temp_phase_correct = 255; - if (timer.n == 2) { - // No resolution calculation for TIMER2 unless enabled USE_OCR2A_AS_TOP - #if ENABLED(USE_OCR2A_AS_TOP) - const uint16_t rtf = (F_CPU) / (prescaler[i] * f_desired); - res_temp_fast = rtf - 1; - res_temp_phase_correct = rtf / 2; + constexpr uint16_t prescaler[] = { 1, 8, (32), 64, (128), 256, 1024 }; // (*) are Timer 2 only + uint16_t f = (F_CPU) / (uint32_t(maxtop) << 11) + 1; // Start with the lowest non-zero frequency achievable (for 16MHz, 1 or 31) + + DEBUG_ECHOLNPGM("f=", f); + DEBUG_ECHOLNPGM("(prescaler loop)"); + for (uint8_t i = 0; i < COUNT(prescaler); ++i) { // Loop through all prescaler values + const uint32_t p = prescaler[i]; // Extend to 32 bits for calculations + DEBUG_ECHOLNPGM("prescaler[", i, "]=", p); + uint16_t res_fast_temp, res_pc_temp; + if (is_timer2) { + #if ENABLED(USE_OCR2A_AS_TOP) // No resolution calculation for TIMER2 unless enabled USE_OCR2A_AS_TOP + const uint16_t rft = (F_CPU) / (p * f_desired); + res_fast_temp = rft - 1; + res_pc_temp = rft / 2; + DEBUG_ECHOLNPGM("(Timer2) res_fast_temp=", res_fast_temp, " res_pc_temp=", res_pc_temp); + #else + res_fast_temp = res_pc_temp = maxtop; + DEBUG_ECHOLNPGM("(Timer2) res_fast_temp=", maxtop, " res_pc_temp=", maxtop); #endif } else { - // Skip TIMER2 specific prescalers when not TIMER2 - if (i == 3 || i == 5) continue; - const uint16_t rtf = (F_CPU) / (prescaler[i] * f_desired); - res_temp_fast = rtf - 1; - res_temp_phase_correct = rtf / 2; + if (p == 32 || p == 128) continue; // Skip TIMER2 specific prescalers when not TIMER2 + const uint16_t rft = (F_CPU) / (p * f_desired); + DEBUG_ECHOLNPGM("(Not Timer 2) F_CPU=", STRINGIFY(F_CPU), " prescaler=", p, " f_desired=", f_desired); + res_fast_temp = rft - 1; + res_pc_temp = rft / 2; } - LIMIT(res_temp_fast, 1U, size); - LIMIT(res_temp_phase_correct, 1U, size); + LIMIT(res_fast_temp, 1U, maxtop); + LIMIT(res_pc_temp, 1U, maxtop); + // Calculate frequencies of test prescaler and resolution values - const int f_temp_fast = (F_CPU) / (prescaler[i] * (1 + res_temp_fast)), - f_temp_phase_correct = (F_CPU) / (2 * prescaler[i] * res_temp_phase_correct), - f_diff = ABS(f - f_desired), - f_fast_diff = ABS(f_temp_fast - f_desired), - f_phase_diff = ABS(f_temp_phase_correct - f_desired); - - // If FAST values are closest to desired f - if (f_fast_diff < f_diff && f_fast_diff <= f_phase_diff) { - // Remember this combination - f = f_temp_fast; - res = res_temp_fast; - j = i; + const uint16_t f_fast_temp = (F_CPU) / (p * (1 + res_fast_temp)), + f_pc_temp = (F_CPU) / ((p * res_pc_temp) << 1), + f_diff = _MAX(f, f_desired) - _MIN(f, f_desired), + f_fast_diff = _MAX(f_fast_temp, f_desired) - _MIN(f_fast_temp, f_desired), + f_pc_diff = _MAX(f_pc_temp, f_desired) - _MIN(f_pc_temp, f_desired); + + DEBUG_ECHOLNPGM("f_fast_temp=", f_fast_temp, " f_pc_temp=", f_pc_temp, " f_diff=", f_diff, " f_fast_diff=", f_fast_diff, " f_pc_diff=", f_pc_diff); + + if (f_fast_diff < f_diff && f_fast_diff <= f_pc_diff) { // FAST values are closest to desired f // Set the Wave Generation Mode to FAST PWM - if (timer.n == 2) - wgm = TERN(USE_OCR2A_AS_TOP, WGM2_FAST_PWM_OCR2A, WGM2_FAST_PWM); - else - wgm = WGM_FAST_PWM_ICRn; + wgm = is_timer2 ? uint8_t(TERN(USE_OCR2A_AS_TOP, WGM2_FAST_PWM_OCR2A, WGM2_FAST_PWM)) : uint8_t(WGM_FAST_PWM_ICRn); + // Remember this combination + f = f_fast_temp; res = res_fast_temp; j = i + 1; + DEBUG_ECHOLNPGM("(FAST) updated f=", f); } - // If PHASE CORRECT values are closes to desired f - else if (f_phase_diff < f_diff) { - f = f_temp_phase_correct; - res = res_temp_phase_correct; - j = i; + else if (f_pc_diff < f_diff) { // PHASE CORRECT values are closes to desired f // Set the Wave Generation Mode to PWM PHASE CORRECT - if (timer.n == 2) - wgm = TERN(USE_OCR2A_AS_TOP, WGM2_PWM_PC_OCR2A, WGM2_FAST_PWM); - else - wgm = WGM_PWM_PC_ICRn; + wgm = is_timer2 ? uint8_t(TERN(USE_OCR2A_AS_TOP, WGM2_PWM_PC_OCR2A, WGM2_PWM_PC)) : uint8_t(WGM_PWM_PC_ICRn); + f = f_pc_temp; res = res_pc_temp; j = i + 1; + DEBUG_ECHOLNPGM("(PHASE) updated f=", f); } - } + } // prescaler loop } - _SET_WGMnQ(timer.TCCRnQ, wgm); - _SET_CSn(timer.TCCRnQ, j); - if (timer.n == 2) { - TERN_(USE_OCR2A_AS_TOP, _SET_OCRnQ(timer.OCRnQ, 0, res)); // Set OCR2A value (TOP) = res + _SET_WGMnQ(timer, wgm); + _SET_CSn(timer, j); + + if (is_timer2) { + TERN_(USE_OCR2A_AS_TOP, _SET_OCRnQ(timer, 0, res)); // Set OCR2A value (TOP) = res } else - _SET_ICRn(timer.ICRn, res); // Set ICRn value (TOP) = res + _SET_ICRn(timer, res); // Set ICRn value (TOP) = res } -#endif // NEEDS_HARDWARE_PWM - -void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) { - #if NEEDS_HARDWARE_PWM - - // If v is 0 or v_size (max), digitalWrite to LOW or HIGH. - // Note that digitalWrite also disables pwm output for us (sets COM bit to 0) - if (v == 0) - digitalWrite(pin, invert); - else if (v == v_size) - digitalWrite(pin, !invert); - else { - Timer timer = get_pwm_timer(pin); - if (timer.n == 0) return; // Don't proceed if protected timer or not recognized - // Set compare output mode to CLEAR -> SET or SET -> CLEAR (if inverted) - _SET_COMnQ(timer.TCCRnQ, timer.q TERN_(HAS_TCCR2, + (timer.q == 2)), COM_CLEAR_SET + invert); // COM20 is on bit 4 of TCCR2, so +1 for q==2 - const uint16_t top = timer.n == 2 ? TERN(USE_OCR2A_AS_TOP, *timer.OCRnQ[0], 255) : *timer.ICRn; - _SET_OCRnQ(timer.OCRnQ, timer.q, uint16_t(uint32_t(v) * top / v_size)); // Scale 8/16-bit v to top value +void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) { + // If v is 0 or v_size (max), digitalWrite to LOW or HIGH. + // Note that digitalWrite also disables PWM output for us (sets COM bit to 0) + if (v == 0) + digitalWrite(pin, invert); + else if (v == v_size) + digitalWrite(pin, !invert); + else { + const Timer timer = get_pwm_timer(pin); + if (timer.isPWM) { + if (timer.n == 0) { + _SET_COMnQ(timer, timer.q, COM_CLEAR_SET); // Only allow a TIMER0B select... + _SET_OCRnQ(timer, timer.q, v); // ...and OCR0B duty update. For output pin D4 no frequency changes are permitted. + } + else if (!timer.isProtected) { + const uint16_t top = timer.n == 2 ? TERN(USE_OCR2A_AS_TOP, *timer.OCRnQ[0], 255) : *timer.ICRn; + _SET_COMnQ(timer, SUM_TERN(HAS_TCCR2, timer.q, timer.q == 2), COM_CLEAR_SET + invert); // COM20 is on bit 4 of TCCR2, so +1 for q==2 + _SET_OCRnQ(timer, timer.q, uint16_t(uint32_t(v) * top / v_size)); // Scale 8/16-bit v to top value + } } + else + digitalWrite(pin, v < v_size / 2 ? LOW : HIGH); + } +} - #else - - analogWrite(pin, v); - UNUSED(v_size); - UNUSED(invert); +void MarlinHAL::init_pwm_timers() { + // Init some timer frequencies to a default 1KHz + const pin_t pwm_pin[] = { + #ifdef __AVR_ATmega2560__ + 10, 5, 6, 46 + #elif defined(__AVR_ATmega1280__) + 12, 31 + #elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega1284__) + 15, 6 + #elif defined(__AVR_AT90USB1286__) || defined(__AVR_mega64) || defined(__AVR_mega128) + 16, 24 + #endif + }; - #endif + for (uint8_t i = 0; i < COUNT(pwm_pin); ++i) + set_pwm_frequency(pwm_pin[i], 1000); } #endif // __AVR__ diff --git a/Marlin/src/HAL/AVR/fastio.cpp b/Marlin/src/HAL/AVR/fastio.cpp index 8af3ef80..5c6ef189 100644 --- a/Marlin/src/HAL/AVR/fastio.cpp +++ b/Marlin/src/HAL/AVR/fastio.cpp @@ -245,7 +245,7 @@ uint16_t set_pwm_frequency_hz(const_float_t hz, const float dca, const float dcb float count = 0; if (hz > 0 && (dca || dcb || dcc)) { count = float(F_CPU) / hz; // 1x prescaler, TOP for 16MHz base freq. - uint16_t prescaler; // Range of 30.5Hz (65535) 64.5KHz (>31) + uint16_t prescaler; // Range of 30.5Hz (65535) 64.5kHz (>31) if (count >= 255. * 256.) { prescaler = 1024; SET_CS(5, PRESCALER_1024); } else if (count >= 255. * 64.) { prescaler = 256; SET_CS(5, PRESCALER_256); } @@ -257,7 +257,7 @@ uint16_t set_pwm_frequency_hz(const_float_t hz, const float dca, const float dcb const float pwm_top = round(count); // Get the rounded count ICR5 = (uint16_t)pwm_top - 1; // Subtract 1 for TOP - OCR5A = pwm_top * ABS(dca); // Update and scale DCs + OCR5A = pwm_top * ABS(dca); // Update and scale DCs OCR5B = pwm_top * ABS(dcb); OCR5C = pwm_top * ABS(dcc); _SET_COM(5, A, dca ? (dca < 0 ? COM_SET_CLEAR : COM_CLEAR_SET) : COM_NORMAL); // Set compare modes @@ -277,7 +277,7 @@ uint16_t set_pwm_frequency_hz(const_float_t hz, const float dca, const float dcb // Restore the default for Timer 5 SET_WGM(5, PWM_PC_8); // PWM 8-bit (Phase Correct) SET_COMS(5, NORMAL, NORMAL, NORMAL); // Do nothing - SET_CS(5, PRESCALER_64); // 16MHz / 64 = 250KHz + SET_CS(5, PRESCALER_64); // 16MHz / 64 = 250kHz OCR5A = OCR5B = OCR5C = 0; } return round(count); diff --git a/Marlin/src/HAL/AVR/fastio.h b/Marlin/src/HAL/AVR/fastio.h index db6e598b..4516d9cd 100644 --- a/Marlin/src/HAL/AVR/fastio.h +++ b/Marlin/src/HAL/AVR/fastio.h @@ -118,7 +118,7 @@ */ // Waveform Generation Modes -enum WaveGenMode : char { +enum WaveGenMode : uint8_t { WGM_NORMAL, // 0 WGM_PWM_PC_8, // 1 WGM_PWM_PC_9, // 2 @@ -138,19 +138,19 @@ enum WaveGenMode : char { }; // Wavefore Generation Modes (Timer 2 only) -enum WaveGenMode2 : char { - WGM2_NORMAL, // 0 - WGM2_PWM_PC, // 1 - WGM2_CTC_OCR2A, // 2 - WGM2_FAST_PWM, // 3 - WGM2_reserved_1, // 4 - WGM2_PWM_PC_OCR2A, // 5 - WGM2_reserved_2, // 6 - WGM2_FAST_PWM_OCR2A, // 7 +enum WaveGenMode2 : uint8_t { + WGM2_NORMAL, // 0 + WGM2_PWM_PC, // 1 + WGM2_CTC_OCR2A, // 2 + WGM2_FAST_PWM, // 3 + WGM2_reserved_1, // 4 + WGM2_PWM_PC_OCR2A, // 5 + WGM2_reserved_2, // 6 + WGM2_FAST_PWM_OCR2A, // 7 }; // Compare Modes -enum CompareMode : char { +enum CompareMode : uint8_t { COM_NORMAL, // 0 COM_TOGGLE, // 1 Non-PWM: OCnx ... Both PWM (WGM 9,11,14,15): OCnA only ... else NORMAL COM_CLEAR_SET, // 2 Non-PWM: OCnx ... Fast PWM: OCnx/Bottom ... PF-FC: OCnx Up/Down @@ -158,7 +158,7 @@ enum CompareMode : char { }; // Clock Sources -enum ClockSource : char { +enum ClockSource : uint8_t { CS_NONE, // 0 CS_PRESCALER_1, // 1 CS_PRESCALER_8, // 2 @@ -170,7 +170,7 @@ enum ClockSource : char { }; // Clock Sources (Timer 2 only) -enum ClockSource2 : char { +enum ClockSource2 : uint8_t { CS2_NONE, // 0 CS2_PRESCALER_1, // 1 CS2_PRESCALER_8, // 2 @@ -203,11 +203,6 @@ enum ClockSource2 : char { TCCR##T##B = (TCCR##T##B & ~(0x3 << WGM##T##2)) | (((int(V) >> 2) & 0x3) << WGM##T##2); \ }while(0) #define SET_WGM(T,V) _SET_WGM(T,WGM_##V) -// Runtime (see set_pwm_frequency): -#define _SET_WGMnQ(TCCRnQ, V) do{ \ - *(TCCRnQ)[0] = (*(TCCRnQ)[0] & ~(0x3 << 0)) | (( int(V) & 0x3) << 0); \ - *(TCCRnQ)[1] = (*(TCCRnQ)[1] & ~(0x3 << 3)) | (((int(V) >> 2) & 0x3) << 3); \ - }while(0) // Set Clock Select bits // Ex: SET_CS3(PRESCALER_64); @@ -235,8 +230,6 @@ enum ClockSource2 : char { #define SET_CS4(V) _SET_CS4(CS_##V) #define SET_CS5(V) _SET_CS5(CS_##V) #define SET_CS(T,V) SET_CS##T(V) -// Runtime (see set_pwm_frequency) -#define _SET_CSn(TCCRnQ, V) (*(TCCRnQ)[1] = (*(TCCRnQ[1]) & ~(0x7 << 0)) | ((int(V) & 0x7) << 0)) // Set Compare Mode bits // Ex: SET_COMS(4,CLEAR_SET,CLEAR_SET,CLEAR_SET); @@ -246,16 +239,6 @@ enum ClockSource2 : char { #define SET_COMB(T,V) SET_COM(T,B,V) #define SET_COMC(T,V) SET_COM(T,C,V) #define SET_COMS(T,V1,V2,V3) do{ SET_COMA(T,V1); SET_COMB(T,V2); SET_COMC(T,V3); }while(0) -// Runtime (see set_pwm_duty) -#define _SET_COMnQ(TCCRnQ, Q, V) (*(TCCRnQ)[0] = (*(TCCRnQ)[0] & ~(0x3 << (6-2*(Q)))) | (int(V) << (6-2*(Q)))) - -// Set OCRnQ register -// Runtime (see set_pwm_duty): -#define _SET_OCRnQ(OCRnQ, Q, V) (*(OCRnQ)[Q] = int(V) & 0xFFFF) - -// Set ICRn register (one per timer) -// Runtime (see set_pwm_frequency) -#define _SET_ICRn(ICRn, V) (*(ICRn) = int(V) & 0xFFFF) // Set Noise Canceler bit // Ex: SET_ICNC(2,1) @@ -272,84 +255,6 @@ enum ClockSource2 : char { #define SET_FOCB(T,V) SET_FOC(T,B,V) #define SET_FOCC(T,V) SET_FOC(T,C,V) -#if 0 - -/** - * PWM availability macros - */ - -// Determine which hardware PWMs are already in use -#define _PWM_CHK_FAN_B(P) (P == E0_AUTO_FAN_PIN || P == E1_AUTO_FAN_PIN || P == E2_AUTO_FAN_PIN || P == E3_AUTO_FAN_PIN || P == E4_AUTO_FAN_PIN || P == E5_AUTO_FAN_PIN || P == E6_AUTO_FAN_PIN || P == E7_AUTO_FAN_PIN || P == CHAMBER_AUTO_FAN_PIN || P == COOLER_AUTO_FAN_PIN) -#if PIN_EXISTS(CONTROLLER_FAN) - #define PWM_CHK_FAN_B(P) (_PWM_CHK_FAN_B(P) || P == CONTROLLER_FAN_PIN) -#else - #define PWM_CHK_FAN_B(P) _PWM_CHK_FAN_B(P) -#endif - -#if ANY_PIN(FAN, FAN1, FAN2, FAN3, FAN4, FAN5, FAN6, FAN7) - #if PIN_EXISTS(FAN7) - #define PWM_CHK_FAN_A(P) (P == FAN0_PIN || P == FAN1_PIN || P == FAN2_PIN || P == FAN3_PIN || P == FAN4_PIN || P == FAN5_PIN || P == FAN6_PIN || P == FAN7_PIN) - #elif PIN_EXISTS(FAN6) - #define PWM_CHK_FAN_A(P) (P == FAN0_PIN || P == FAN1_PIN || P == FAN2_PIN || P == FAN3_PIN || P == FAN4_PIN || P == FAN5_PIN || P == FAN6_PIN) - #elif PIN_EXISTS(FAN5) - #define PWM_CHK_FAN_A(P) (P == FAN0_PIN || P == FAN1_PIN || P == FAN2_PIN || P == FAN3_PIN || P == FAN4_PIN || P == FAN5_PIN) - #elif PIN_EXISTS(FAN4) - #define PWM_CHK_FAN_A(P) (P == FAN0_PIN || P == FAN1_PIN || P == FAN2_PIN || P == FAN3_PIN || P == FAN4_PIN) - #elif PIN_EXISTS(FAN3) - #define PWM_CHK_FAN_A(P) (P == FAN0_PIN || P == FAN1_PIN || P == FAN2_PIN || P == FAN3_PIN) - #elif PIN_EXISTS(FAN2) - #define PWM_CHK_FAN_A(P) (P == FAN0_PIN || P == FAN1_PIN || P == FAN2_PIN) - #elif PIN_EXISTS(FAN1) - #define PWM_CHK_FAN_A(P) (P == FAN0_PIN || P == FAN1_PIN) - #else - #define PWM_CHK_FAN_A(P) (P == FAN0_PIN) - #endif -#else - #define PWM_CHK_FAN_A(P) false -#endif - -#if HAS_MOTOR_CURRENT_PWM - #if PIN_EXISTS(MOTOR_CURRENT_PWM_XY) - #define PWM_CHK_MOTOR_CURRENT(P) (P == MOTOR_CURRENT_PWM_E || P == MOTOR_CURRENT_PWM_Z || P == MOTOR_CURRENT_PWM_XY) - #elif PIN_EXISTS(MOTOR_CURRENT_PWM_Z) - #define PWM_CHK_MOTOR_CURRENT(P) (P == MOTOR_CURRENT_PWM_E || P == MOTOR_CURRENT_PWM_Z) - #else - #define PWM_CHK_MOTOR_CURRENT(P) (P == MOTOR_CURRENT_PWM_E) - #endif -#else - #define PWM_CHK_MOTOR_CURRENT(P) false -#endif - -#ifdef NUM_SERVOS - #if AVR_ATmega2560_FAMILY - #define PWM_CHK_SERVO(P) (P == 5 || (NUM_SERVOS > 12 && P == 6) || (NUM_SERVOS > 24 && P == 46)) // PWMS 3A, 4A & 5A - #elif AVR_ATmega2561_FAMILY - #define PWM_CHK_SERVO(P) (P == 5) // PWM3A - #elif AVR_ATmega1284_FAMILY - #define PWM_CHK_SERVO(P) false - #elif AVR_AT90USB1286_FAMILY - #define PWM_CHK_SERVO(P) (P == 16) // PWM3A - #elif AVR_ATmega328_FAMILY - #define PWM_CHK_SERVO(P) false - #endif -#else - #define PWM_CHK_SERVO(P) false -#endif - -#if ENABLED(BARICUDA) - #if HAS_HEATER_1 && HAS_HEATER_2 - #define PWM_CHK_HEATER(P) (P == HEATER_1_PIN || P == HEATER_2_PIN) - #elif HAS_HEATER_1 - #define PWM_CHK_HEATER(P) (P == HEATER_1_PIN) - #endif -#else - #define PWM_CHK_HEATER(P) false -#endif - -#define PWM_CHK(P) (PWM_CHK_HEATER(P) || PWM_CHK_SERVO(P) || PWM_CHK_MOTOR_CURRENT(P) || PWM_CHK_FAN_A(P) || PWM_CHK_FAN_B(P)) - -#endif // PWM_CHK is not used in Marlin - // define which hardware PWMs are available for the current CPU // all timer 1 PWMS deleted from this list because they are never available #if AVR_ATmega2560_FAMILY diff --git a/Marlin/src/HAL/AVR/fastio/fastio_1280.h b/Marlin/src/HAL/AVR/fastio/fastio_1280.h index f482f823..57d6181d 100644 --- a/Marlin/src/HAL/AVR/fastio/fastio_1280.h +++ b/Marlin/src/HAL/AVR/fastio/fastio_1280.h @@ -27,43 +27,41 @@ * Hardware Pin : 02 03 06 07 01 05 15 16 17 18 23 24 25 26 64 63 13 12 46 45 44 43 78 77 76 75 74 73 72 71 60 59 58 57 56 55 54 53 50 70 52 51 42 41 40 39 38 37 36 35 22 21 20 19 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 | 04 08 09 10 11 14 27 28 29 30 31 32 33 34 47 48 49 61 62 65 66 67 68 69 79 80 81 98 99 100 * Port : E0 E1 E4 E5 G5 E3 H3 H4 H5 H6 B4 B5 B6 B7 J1 J0 H1 H0 D3 D2 D1 D0 A0 A1 A2 A3 A4 A5 A6 A7 C7 C6 C5 C4 C3 C2 C1 C0 D7 G2 G1 G0 L7 L6 L5 L4 L3 L2 L1 L0 B3 B2 B1 B0 F0 F1 F2 F3 F4 F5 F6 F7 K0 K1 K2 K3 K4 K5 K6 K7 | E2 E6 E7 xx xx H2 H7 G3 G4 xx xx xx xx xx D4 D5 D6 xx xx J2 J3 J4 J5 J6 J7 xx xx xx xx xx * Logical Pin : 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | 78 79 80 xx xx 84 85 71 70 xx xx xx xx xx 81 82 83 xx xx 72 73 75 76 77 74 xx xx xx xx xx + * Analog Input : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ #include "../fastio.h" -// change for your board -#define DEBUG_LED DIO21 - // UART -#define RXD DIO0 -#define TXD DIO1 +#define RXD 0 +#define TXD 1 // SPI -#define SCK DIO52 -#define MISO DIO50 -#define MOSI DIO51 -#define SS DIO53 +#define MISO 50 +#define MOSI 51 +#define SCK 52 +#define SS 53 // TWI (I2C) -#define SCL DIO21 -#define SDA DIO20 +#define SCL 21 +#define SDA 20 // Timers and PWM -#define OC0A DIO13 -#define OC0B DIO4 -#define OC1A DIO11 -#define OC1B DIO12 -#define OC2A DIO10 -#define OC2B DIO9 -#define OC3A DIO5 -#define OC3B DIO2 -#define OC3C DIO3 -#define OC4A DIO6 -#define OC4B DIO7 -#define OC4C DIO8 -#define OC5A DIO46 -#define OC5B DIO45 -#define OC5C DIO44 +#define OC0A 13 +#define OC0B 4 +#define OC1A 11 +#define OC1B 12 +#define OC2A 10 +#define OC2B 9 +#define OC3A 5 +#define OC3B 2 +#define OC3C 3 +#define OC4A 6 +#define OC4B 7 +#define OC4C 8 +#define OC5A 46 +#define OC5B 45 +#define OC5C 44 // Digital I/O diff --git a/Marlin/src/HAL/AVR/fastio/fastio_1281.h b/Marlin/src/HAL/AVR/fastio/fastio_1281.h index e0bc5e29..fdff219e 100644 --- a/Marlin/src/HAL/AVR/fastio/fastio_1281.h +++ b/Marlin/src/HAL/AVR/fastio/fastio_1281.h @@ -30,32 +30,29 @@ #include "../fastio.h" -// change for your board -#define DEBUG_LED DIO46 - // UART -#define RXD DIO0 -#define TXD DIO1 +#define RXD 0 +#define TXD 1 // SPI -#define SCK DIO10 -#define MISO DIO12 -#define MOSI DIO11 -#define SS DIO16 +#define SCK 10 +#define MISO 12 +#define MOSI 11 +#define SS 16 // TWI (I2C) -#define SCL DIO17 -#define SDA DIO18 +#define SCL 17 +#define SDA 18 // Timers and PWM -#define OC0A DIO9 -#define OC0B DIO4 -#define OC1A DIO7 -#define OC1B DIO8 -#define OC2A DIO6 -#define OC3A DIO5 -#define OC3B DIO2 -#define OC3C DIO3 +#define OC0A 9 +#define OC0B 4 +#define OC1A 7 +#define OC1B 8 +#define OC2A 6 +#define OC3A 5 +#define OC3B 2 +#define OC3C 3 // Digital I/O diff --git a/Marlin/src/HAL/AVR/fastio/fastio_168.h b/Marlin/src/HAL/AVR/fastio/fastio_168.h index 8cfdd1e8..36dc5523 100644 --- a/Marlin/src/HAL/AVR/fastio/fastio_168.h +++ b/Marlin/src/HAL/AVR/fastio/fastio_168.h @@ -30,29 +30,27 @@ #include "../fastio.h" -#define DEBUG_LED AIO5 - // UART -#define RXD DIO0 -#define TXD DIO1 +#define RXD 0 +#define TXD 1 // SPI -#define SCK DIO13 -#define MISO DIO12 -#define MOSI DIO11 -#define SS DIO10 +#define SS 10 +#define MOSI 11 +#define MISO 12 +#define SCK 13 // TWI (I2C) #define SCL AIO5 #define SDA AIO4 // Timers and PWM -#define OC0A DIO6 -#define OC0B DIO5 -#define OC1A DIO9 -#define OC1B DIO10 -#define OC2A DIO11 -#define OC2B DIO3 +#define OC0A 6 +#define OC0B 5 +#define OC1A 9 +#define OC1B 10 +#define OC2A 11 +#define OC2B 3 // Digital I/O diff --git a/Marlin/src/HAL/AVR/fastio/fastio_644.h b/Marlin/src/HAL/AVR/fastio/fastio_644.h index f4a9427e..e20a3d34 100644 --- a/Marlin/src/HAL/AVR/fastio/fastio_644.h +++ b/Marlin/src/HAL/AVR/fastio/fastio_644.h @@ -56,34 +56,32 @@ #include "../fastio.h" -#define DEBUG_LED DIO0 - // UART -#define RXD DIO8 -#define TXD DIO9 -#define RXD0 DIO8 -#define TXD0 DIO9 +#define RXD 8 +#define TXD 9 +#define RXD0 8 +#define TXD0 9 -#define RXD1 DIO10 -#define TXD1 DIO11 +#define RXD1 10 +#define TXD1 11 // SPI -#define SCK DIO7 -#define MISO DIO6 -#define MOSI DIO5 -#define SS DIO4 +#define SS 4 +#define MOSI 5 +#define MISO 6 +#define SCK 7 // TWI (I2C) -#define SCL DIO16 -#define SDA DIO17 +#define SCL 16 +#define SDA 17 // Timers and PWM -#define OC0A DIO3 -#define OC0B DIO4 -#define OC1A DIO13 -#define OC1B DIO12 -#define OC2A DIO15 -#define OC2B DIO14 +#define OC0A 3 +#define OC0B 4 +#define OC1A 13 +#define OC1B 12 +#define OC2A 15 +#define OC2B 14 // Digital I/O diff --git a/Marlin/src/HAL/AVR/fastio/fastio_AT90USB.h b/Marlin/src/HAL/AVR/fastio/fastio_AT90USB.h index 51d400b7..2119d168 100644 --- a/Marlin/src/HAL/AVR/fastio/fastio_AT90USB.h +++ b/Marlin/src/HAL/AVR/fastio/fastio_AT90USB.h @@ -26,19 +26,16 @@ * * Logical Pin: 28 29 30 31 32 33 34 35 20 21 22 23 24 25 26 27 10 11 12 13 14 15 16 17 00 01 02 03 04 05 06 07 08 09(46*47)36 37 18 19 38 39 40 41 42 43 44 45 * Port: A0 A1 A2 A3 A4 A5 A6 A7 B0 B1 B2 B3 B4 B5 B6 B7 C0 C1 C2 C3 C4 C5 C6 C7 D0 D1 D2 D3 D4 D5 D6 D7 E0 E1 E2 E3 E4 E5 E6 E7 F0 F1 F2 F3 F4 F5 F6 F7 - * The logical pins 46 and 47 are not supported by Teensyduino, but are supported below as E2 and E3 + * Logical pins 46-47 aren't supported by Teensyduino, but are supported below as E2 and E3 */ #include "../fastio.h" -// change for your board -#define DEBUG_LED DIO31 /* led D5 red */ - // SPI -#define SCK DIO21 // 9 -#define MISO DIO23 // 11 -#define MOSI DIO22 // 10 -#define SS DIO20 // 8 +#define SS 20 // 8 +#define SCK 21 // 9 +#define MOSI 22 // 10 +#define MISO 23 // 11 // Digital I/O @@ -679,7 +676,6 @@ #define PF7_PWM 0 #define PF7_DDR DDRF - /** * Some of the pin mapping functions of the Teensduino extension to the Arduino IDE * do not function the same as the other Arduino extensions. diff --git a/Marlin/src/HAL/AVR/inc/Conditionals_LCD.h b/Marlin/src/HAL/AVR/inc/Conditionals_LCD.h index a611ccd7..65b019b2 100644 --- a/Marlin/src/HAL/AVR/inc/Conditionals_LCD.h +++ b/Marlin/src/HAL/AVR/inc/Conditionals_LCD.h @@ -21,6 +21,6 @@ */ #pragma once -#if HAS_SPI_TFT || HAS_FSMC_TFT - #error "Sorry! TFT displays are not available for HAL/AVR." +#ifndef SERIAL_PORT + #define SERIAL_PORT 0 #endif diff --git a/Marlin/src/HAL/AVR/inc/SanityCheck.h b/Marlin/src/HAL/AVR/inc/SanityCheck.h index 2f80d1fe..85ee6836 100644 --- a/Marlin/src/HAL/AVR/inc/SanityCheck.h +++ b/Marlin/src/HAL/AVR/inc/SanityCheck.h @@ -25,11 +25,57 @@ * Test AVR-specific configuration values for errors at compile-time. */ +#if HAS_SPI_TFT || HAS_FSMC_TFT + #error "Sorry! TFT displays are not available for HAL/AVR." +#endif + +/** + * Check for common serial pin conflicts + */ +#define CHECK_SERIAL_PIN(N) ( \ + X_STOP_PIN == N || Y_STOP_PIN == N || Z_STOP_PIN == N \ + || X_MIN_PIN == N || Y_MIN_PIN == N || Z_MIN_PIN == N \ + || X_MAX_PIN == N || Y_MAX_PIN == N || Z_MAX_PIN == N \ + || X_STEP_PIN == N || Y_STEP_PIN == N || Z_STEP_PIN == N \ + || X_DIR_PIN == N || Y_DIR_PIN == N || Z_DIR_PIN == N \ + || X_ENA_PIN == N || Y_ENA_PIN == N || Z_ENA_PIN == N \ + || BTN_EN1 == N || BTN_EN2 == N || LCD_PINS_EN == N \ +) +#if SERIAL_IN_USE(0) + // D0-D1. No known conflicts. +#endif +#if SERIAL_IN_USE(1) + #if NOT_TARGET(__AVR_ATmega644P__, __AVR_ATmega1284P__) + #if CHECK_SERIAL_PIN(18) || CHECK_SERIAL_PIN(19) + #error "Serial Port 1 pin D18 and/or D19 conflicts with another pin on the board." + #endif + #else + #if CHECK_SERIAL_PIN(10) || CHECK_SERIAL_PIN(11) + #error "Serial Port 1 pin D10 and/or D11 conflicts with another pin on the board." + #endif + #endif +#endif +#if SERIAL_IN_USE(2) && (CHECK_SERIAL_PIN(16) || CHECK_SERIAL_PIN(17)) + #error "Serial Port 2 pin D16 and/or D17 conflicts with another pin on the board." +#endif +#if SERIAL_IN_USE(3) && (CHECK_SERIAL_PIN(14) || CHECK_SERIAL_PIN(15)) + #error "Serial Port 3 pin D14 and/or D15 conflicts with another pin on the board." +#endif +#undef CHECK_SERIAL_PIN + /** * Checks for FAST PWM */ #if ALL(FAST_PWM_FAN, USE_OCR2A_AS_TOP, HAS_TCCR2) - #error "USE_OCR2A_AS_TOP does not apply to devices with a single output TIMER2" + #error "USE_OCR2A_AS_TOP does not apply to devices with a single output TIMER2." +#endif + +/** + * Checks for SOFT PWM + */ +#if HAS_FAN0 && FAN0_PIN == 9 && DISABLED(FAN_SOFT_PWM) && ENABLED(SPEAKER) + #error "FAN0_PIN 9 Hardware PWM uses Timer 2 which conflicts with Arduino AVR Tone Timer (for SPEAKER)." + #error "Disable SPEAKER or enable FAN_SOFT_PWM." #endif /** @@ -42,18 +88,18 @@ #elif NUM_SERVOS > 0 && defined(_useTimer3) && (WITHIN(SPINDLE_LASER_PWM_PIN, 2, 3) || SPINDLE_LASER_PWM_PIN == 5) #error "Counter/Timer for SPINDLE_LASER_PWM_PIN is used by the servo system." #endif -#elif defined(SPINDLE_LASER_FREQUENCY) +#elif SPINDLE_LASER_FREQUENCY #error "SPINDLE_LASER_FREQUENCY requires SPINDLE_LASER_USE_PWM." #endif /** * The Trinamic library includes SoftwareSerial.h, leading to a compile error. */ -#if BOTH(HAS_TRINAMIC_CONFIG, ENDSTOP_INTERRUPTS_FEATURE) +#if ALL(HAS_TRINAMIC_CONFIG, ENDSTOP_INTERRUPTS_FEATURE) #error "TMCStepper includes SoftwareSerial.h which is incompatible with ENDSTOP_INTERRUPTS_FEATURE. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif -#if BOTH(HAS_TMC_SW_SERIAL, MONITOR_DRIVER_STATUS) +#if ALL(HAS_TMC_SW_SERIAL, MONITOR_DRIVER_STATUS) #error "MONITOR_DRIVER_STATUS causes performance issues when used with SoftwareSerial-connected drivers. Disable MONITOR_DRIVER_STATUS or use hardware serial to continue." #endif @@ -63,3 +109,7 @@ #if ENABLED(POSTMORTEM_DEBUGGING) #error "POSTMORTEM_DEBUGGING is not supported on AVR boards." #endif + +#if USING_PULLDOWNS + #error "PULLDOWN pin mode is not available on AVR boards." +#endif diff --git a/Marlin/src/HAL/AVR/math.h b/Marlin/src/HAL/AVR/math.h index 7ede4acc..34f859fb 100644 --- a/Marlin/src/HAL/AVR/math.h +++ b/Marlin/src/HAL/AVR/math.h @@ -27,15 +27,16 @@ // intRes = longIn1 * longIn2 >> 24 // uses: -// A[tmp] to store 0 -// B[tmp] to store bits 16-23 of the 48bit result. The top bit is used to round the two byte result. -// note that the lower two bytes and the upper byte of the 48bit result are not calculated. -// this can cause the result to be out by one as the lower bytes may cause carries into the upper ones. -// B A are bits 24-39 and are the returned value -// C B A is longIn1 -// D C B A is longIn2 +// r1, r0 for the result of mul. +// [tmp1] to store 0. +// [tmp2] to store bits 16-23 of the 56 bit result. The top bit of [tmp2] is used for rounding. +// Note that the lower two bytes and the upper two bytes of the 56 bit result are not calculated. +// This can cause the result to be out by one as the lower bytes may cause carries into the upper ones. +// [intRes] (A B) is bits 24-39 and is the returned value. +// [longIn1] (C B A) is a 24 bit parameter. +// [longIn2] (D C B A) is a 32 bit parameter. // -static FORCE_INLINE uint16_t MultiU24X32toH16(uint32_t longIn1, uint32_t longIn2) { +FORCE_INLINE static uint16_t MultiU24X32toH16(uint32_t longIn1, uint32_t longIn2) { uint8_t tmp1; uint8_t tmp2; uint16_t intRes; @@ -66,11 +67,9 @@ static FORCE_INLINE uint16_t MultiU24X32toH16(uint32_t longIn1, uint32_t longIn2 A("add %[tmp2], r1") A("adc %A[intRes], %[tmp1]") A("adc %B[intRes], %[tmp1]") - A("lsr %[tmp2]") - A("adc %A[intRes], %[tmp1]") - A("adc %B[intRes], %[tmp1]") A("mul %D[longIn2], %A[longIn1]") - A("add %A[intRes], r0") + A("lsl %[tmp2]") + A("adc %A[intRes], r0") A("adc %B[intRes], r1") A("mul %D[longIn2], %B[longIn1]") A("add %B[intRes], r0") @@ -85,11 +84,16 @@ static FORCE_INLINE uint16_t MultiU24X32toH16(uint32_t longIn1, uint32_t longIn2 return intRes; } -// intRes = intIn1 * intIn2 >> 16 +// intRes = intIn1 * intIn2 >> 8 // uses: -// r26 to store 0 -// r27 to store the byte 1 of the 24 bit result -static FORCE_INLINE uint16_t MultiU16X8toH16(uint8_t charIn1, uint16_t intIn2) { +// r1, r0 for the result of mul. After the second mul, r0 holds bits 0-7 of the 24 bit result and +// the top bit of r0 is used for rounding. +// [tmp] to store 0. +// [intRes] (A B) is bits 8-15 and is the returned value. +// [charIn1] is an 8 bit parameter. +// [intIn2] (B A) is a 16 bit parameter. +// +FORCE_INLINE static uint16_t MultiU8X16toH16(uint8_t charIn1, uint16_t intIn2) { uint8_t tmp; uint16_t intRes; __asm__ __volatile__ ( @@ -97,10 +101,8 @@ static FORCE_INLINE uint16_t MultiU16X8toH16(uint8_t charIn1, uint16_t intIn2) { A("mul %[charIn1], %B[intIn2]") A("movw %A[intRes], r0") A("mul %[charIn1], %A[intIn2]") - A("add %A[intRes], r1") - A("adc %B[intRes], %[tmp]") - A("lsr r0") - A("adc %A[intRes], %[tmp]") + A("lsl r0") + A("adc %A[intRes], r1") A("adc %B[intRes], %[tmp]") A("clr r1") : [intRes] "=&r" (intRes), diff --git a/Marlin/src/HAL/AVR/pinsDebug.h b/Marlin/src/HAL/AVR/pinsDebug.h index 0f564df9..e9bc09a4 100644 --- a/Marlin/src/HAL/AVR/pinsDebug.h +++ b/Marlin/src/HAL/AVR/pinsDebug.h @@ -22,7 +22,23 @@ #pragma once /** - * PWM print routines for Atmel 8 bit AVR CPUs + * Pins Debugging for Atmel 8 bit AVR CPUs + * + * - NUMBER_PINS_TOTAL + * - MULTI_NAME_PAD + * - getPinByIndex(index) + * - printPinNameByIndex(index) + * - getPinIsDigitalByIndex(index) + * - digitalPinToAnalogIndex(pin) + * - getValidPinMode(pin) + * - isValidPin(pin) + * - isAnalogPin(pin) + * - digitalRead_mod(pin) + * - pwm_status(pin) + * - printPinPWM(pin) + * - printPinPort(pin) + * - printPinNumber(pin) + * - printPinAnalog(pin) */ #include "../../inc/MarlinConfig.h" @@ -39,55 +55,56 @@ #include "pinsDebug_Teensyduino.h" // Can't use the "digitalPinToPort" function from the Teensyduino type IDEs // portModeRegister takes a different argument - #define digitalPinToTimer_DEBUG(p) digitalPinToTimer(p) - #define digitalPinToBitMask_DEBUG(p) digitalPinToBitMask(p) - #define digitalPinToPort_DEBUG(p) digitalPinToPort(p) - #define GET_PINMODE(pin) (*portModeRegister(pin) & digitalPinToBitMask_DEBUG(pin)) + #define digitalPinToTimer_DEBUG(P) digitalPinToTimer(P) + #define digitalPinToBitMask_DEBUG(P) digitalPinToBitMask(P) + #define digitalPinToPort_DEBUG(P) digitalPinToPort(P) + #define getValidPinMode(P) (*portModeRegister(P) & digitalPinToBitMask_DEBUG(P)) #elif AVR_ATmega2560_FAMILY_PLUS_70 // So we can access/display all the pins on boards using more than 70 #include "pinsDebug_plus_70.h" - #define digitalPinToTimer_DEBUG(p) digitalPinToTimer_plus_70(p) - #define digitalPinToBitMask_DEBUG(p) digitalPinToBitMask_plus_70(p) - #define digitalPinToPort_DEBUG(p) digitalPinToPort_plus_70(p) - bool GET_PINMODE(int8_t pin) {return *portModeRegister(digitalPinToPort_DEBUG(pin)) & digitalPinToBitMask_DEBUG(pin); } + #define digitalPinToTimer_DEBUG(P) digitalPinToTimer_plus_70(P) + #define digitalPinToBitMask_DEBUG(P) digitalPinToBitMask_plus_70(P) + #define digitalPinToPort_DEBUG(P) digitalPinToPort_plus_70(P) + bool getValidPinMode(pin_t pin) {return *portModeRegister(digitalPinToPort_DEBUG(pin)) & digitalPinToBitMask_DEBUG(pin); } #else - #define digitalPinToTimer_DEBUG(p) digitalPinToTimer(p) - #define digitalPinToBitMask_DEBUG(p) digitalPinToBitMask(p) - #define digitalPinToPort_DEBUG(p) digitalPinToPort(p) - bool GET_PINMODE(int8_t pin) {return *portModeRegister(digitalPinToPort_DEBUG(pin)) & digitalPinToBitMask_DEBUG(pin); } - #define GET_ARRAY_PIN(p) pgm_read_byte(&pin_array[p].pin) + #define digitalPinToTimer_DEBUG(P) digitalPinToTimer(P) + #define digitalPinToBitMask_DEBUG(P) digitalPinToBitMask(P) + #define digitalPinToPort_DEBUG(P) digitalPinToPort(P) + bool getValidPinMode(pin_t pin) {return *portModeRegister(digitalPinToPort_DEBUG(pin)) & digitalPinToBitMask_DEBUG(pin); } + #define getPinByIndex(x) pgm_read_byte(&pin_array[x].pin) #endif -#define VALID_PIN(pin) (pin >= 0 && pin < NUM_DIGITAL_PINS ? 1 : 0) +#define isValidPin(P) (P >= 0 && P < NUMBER_PINS_TOTAL) #if AVR_ATmega1284_FAMILY - #define DIGITAL_PIN_TO_ANALOG_PIN(P) int(analogInputToDigitalPin(0) - (P)) - #define IS_ANALOG(P) ((P) >= analogInputToDigitalPin(7) && (P) <= analogInputToDigitalPin(0)) + #define isAnalogPin(P) WITHIN(P, analogInputToDigitalPin(7), analogInputToDigitalPin(0)) + #define digitalPinToAnalogIndex(P) int(isAnalogPin(P) ? (P) - analogInputToDigitalPin(7) : -1) #else - #define DIGITAL_PIN_TO_ANALOG_PIN(P) int((P) - analogInputToDigitalPin(0)) - #define IS_ANALOG(P) ((P) >= analogInputToDigitalPin(0) && ((P) <= analogInputToDigitalPin(15) || (P) <= analogInputToDigitalPin(7))) + #define _ANALOG1(P) WITHIN(P, analogInputToDigitalPin(0), analogInputToDigitalPin(7)) + #define _ANALOG2(P) WITHIN(P, analogInputToDigitalPin(8), analogInputToDigitalPin(15)) + #define isAnalogPin(P) (_ANALOG1(P) || _ANALOG2(P)) + #define digitalPinToAnalogIndex(P) int(_ANALOG1(P) ? (P) - analogInputToDigitalPin(0) : _ANALOG2(P) ? (P) - analogInputToDigitalPin(8) + 8 : -1) #endif -#define GET_ARRAY_PIN(p) pgm_read_byte(&pin_array[p].pin) +#define getPinByIndex(x) pgm_read_byte(&pin_array[x].pin) #define MULTI_NAME_PAD 26 // space needed to be pretty if not first name assigned to a pin -void PRINT_ARRAY_NAME(uint8_t x) { - char *name_mem_pointer = (char*)pgm_read_ptr(&pin_array[x].name); - LOOP_L_N(y, MAX_NAME_LENGTH) { +void printPinNameByIndex(const uint8_t index) { + PGM_P const name_mem_pointer = (PGM_P)pgm_read_ptr(&pin_array[index].name); + for (uint8_t y = 0; y < MAX_NAME_LENGTH; ++y) { char temp_char = pgm_read_byte(name_mem_pointer + y); if (temp_char != 0) SERIAL_CHAR(temp_char); else { - LOOP_L_N(i, MAX_NAME_LENGTH - y) SERIAL_CHAR(' '); + for (uint8_t i = 0; i < MAX_NAME_LENGTH - y; ++i) SERIAL_CHAR(' '); break; } } } -#define GET_ARRAY_IS_DIGITAL(x) pgm_read_byte(&pin_array[x].is_digital) - +#define getPinIsDigitalByIndex(x) pgm_read_byte(&pin_array[x].is_digital) #if defined(__AVR_ATmega1284P__) // 1284 IDE extensions set this to the number of #undef NUM_DIGITAL_PINS // digital only pins while all other CPUs have it @@ -108,7 +125,7 @@ void PRINT_ARRAY_NAME(uint8_t x) { * Print a pin's PWM status. * Return true if it's currently a PWM pin. */ -static bool pwm_status(uint8_t pin) { +bool pwm_status(const uint8_t pin) { char buffer[20]; // for the sprintf statements switch (digitalPinToTimer_DEBUG(pin)) { @@ -162,7 +179,6 @@ static bool pwm_status(uint8_t pin) { SERIAL_ECHO_SP(2); } // pwm_status - const volatile uint8_t* const PWM_other[][3] PROGMEM = { { &TCCR0A, &TCCR0B, &TIMSK0 }, { &TCCR1A, &TCCR1B, &TIMSK1 }, @@ -180,7 +196,6 @@ const volatile uint8_t* const PWM_other[][3] PROGMEM = { #endif }; - const volatile uint8_t* const PWM_OCR[][3] PROGMEM = { #ifdef TIMER0A @@ -216,7 +231,6 @@ const volatile uint8_t* const PWM_OCR[][3] PROGMEM = { #endif }; - #define TCCR_A(T) pgm_read_word(&PWM_other[T][0]) #define TCCR_B(T) pgm_read_word(&PWM_other[T][1]) #define TIMSK(T) pgm_read_word(&PWM_other[T][2]) @@ -231,12 +245,12 @@ const volatile uint8_t* const PWM_OCR[][3] PROGMEM = { #define OCR_VAL(T, L) pgm_read_word(&PWM_OCR[T][L]) -static void err_is_counter() { SERIAL_ECHOPGM(" non-standard PWM mode"); } -static void err_is_interrupt() { SERIAL_ECHOPGM(" compare interrupt enabled"); } -static void err_prob_interrupt() { SERIAL_ECHOPGM(" overflow interrupt enabled"); } -static void print_is_also_tied() { SERIAL_ECHOPGM(" is also tied to this pin"); SERIAL_ECHO_SP(14); } +void err_is_counter() { SERIAL_ECHOPGM(" non-standard PWM mode"); } +void err_is_interrupt() { SERIAL_ECHOPGM(" compare interrupt enabled"); } +void err_prob_interrupt() { SERIAL_ECHOPGM(" overflow interrupt enabled"); } +void print_is_also_tied() { SERIAL_ECHOPGM(" is also tied to this pin"); SERIAL_ECHO_SP(14); } -inline void com_print(const uint8_t N, const uint8_t Z) { +void com_print(const uint8_t N, const uint8_t Z) { const uint8_t *TCCRA = (uint8_t*)TCCR_A(N); SERIAL_ECHOPGM(" COM", AS_DIGIT(N)); SERIAL_CHAR(Z); @@ -278,7 +292,7 @@ void timer_prefix(uint8_t T, char L, uint8_t N) { // T - timer L - pwm N - if (TEST(*TMSK, TOIE)) err_prob_interrupt(); } -static void pwm_details(uint8_t pin) { +void printPinPWM(const uint8_t pin) { switch (digitalPinToTimer_DEBUG(pin)) { #if ABTEST(0) @@ -349,52 +363,46 @@ static void pwm_details(uint8_t pin) { #else UNUSED(print_is_also_tied); #endif -} // pwm_details +} // printPinPWM #ifndef digitalRead_mod // Use Teensyduino's version of digitalRead - it doesn't disable the PWMs - int digitalRead_mod(const int8_t pin) { // same as digitalRead except the PWM stop section has been removed + int digitalRead_mod(const pin_t pin) { // same as digitalRead except the PWM stop section has been removed const uint8_t port = digitalPinToPort_DEBUG(pin); return (port != NOT_A_PIN) && (*portInputRegister(port) & digitalPinToBitMask_DEBUG(pin)) ? HIGH : LOW; } #endif -#ifndef PRINT_PORT - - void print_port(int8_t pin) { // print port number - #ifdef digitalPinToPort_DEBUG - uint8_t x; - SERIAL_ECHOPGM(" Port: "); - #if AVR_AT90USB1286_FAMILY - x = (pin == 46 || pin == 47) ? 'E' : digitalPinToPort_DEBUG(pin) + 64; - #else - x = digitalPinToPort_DEBUG(pin) + 64; - #endif - SERIAL_CHAR(x); - - #if AVR_AT90USB1286_FAMILY - if (pin == 46) - x = '2'; - else if (pin == 47) - x = '3'; - else { - uint8_t temp = digitalPinToBitMask_DEBUG(pin); - for (x = '0'; x < '9' && temp != 1; x++) temp >>= 1; - } - #else +void printPinPort(const pin_t pin) { // print port number + #ifdef digitalPinToPort_DEBUG + uint8_t x; + SERIAL_ECHOPGM(" Port: "); + #if AVR_AT90USB1286_FAMILY + x = (pin == 46 || pin == 47) ? 'E' : digitalPinToPort_DEBUG(pin) + 64; + #else + x = digitalPinToPort_DEBUG(pin) + 64; + #endif + SERIAL_CHAR(x); + + #if AVR_AT90USB1286_FAMILY + if (pin == 46) + x = '2'; + else if (pin == 47) + x = '3'; + else { uint8_t temp = digitalPinToBitMask_DEBUG(pin); for (x = '0'; x < '9' && temp != 1; x++) temp >>= 1; - #endif - SERIAL_CHAR(x); + } #else - SERIAL_ECHO_SP(10); + uint8_t temp = digitalPinToBitMask_DEBUG(pin); + for (x = '0'; x < '9' && temp != 1; x++) temp >>= 1; #endif - } - - #define PRINT_PORT(p) print_port(p) - -#endif + SERIAL_CHAR(x); + #else + SERIAL_ECHO_SP(10); + #endif +} -#define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%3d "), p); SERIAL_ECHO(buffer); }while(0) -#define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0) +#define printPinNumber(P) do{ sprintf_P(buffer, PSTR("%3d "), P); SERIAL_ECHO(buffer); }while(0) +#define printPinAnalog(P) do{ sprintf_P(buffer, PSTR(" (A%2d) "), digitalPinToAnalogIndex(P)); SERIAL_ECHO(buffer); }while(0) #undef ABTEST diff --git a/Marlin/src/HAL/AVR/pinsDebug_Teensyduino.h b/Marlin/src/HAL/AVR/pinsDebug_Teensyduino.h index 582ae79b..463a77ec 100644 --- a/Marlin/src/HAL/AVR/pinsDebug_Teensyduino.h +++ b/Marlin/src/HAL/AVR/pinsDebug_Teensyduino.h @@ -22,11 +22,10 @@ #pragma once // -// some of the pin mapping functions of the Teensduino extension to the Arduino IDE -// do not function the same as the other Arduino extensions +// Some of the pin mapping functions of the Arduino IDE Teensduino extension +// function differently from other Arduino extensions. // - #define TEENSYDUINO_IDE //digitalPinToTimer(pin) function works like Arduino but Timers are not defined @@ -48,8 +47,6 @@ #define PE 5 #define PF 6 -#undef digitalPinToPort - const uint8_t PROGMEM digital_pin_to_port_PGM[] = { PD, // 0 - PD0 - INT0 - PWM PD, // 1 - PD1 - INT1 - PWM @@ -101,11 +98,11 @@ const uint8_t PROGMEM digital_pin_to_port_PGM[] = { PE, // 47 - PE3 (not defined in teensyduino) }; -#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) ) +#define digitalPinToPort(P) pgm_read_byte(digital_pin_to_port_PGM[P]) // digitalPinToBitMask(pin) is OK -#define digitalRead_mod(p) extDigitalRead(p) // Teensyduino's version of digitalRead doesn't +#define digitalRead_mod(P) extDigitalRead(P) // Teensyduino's version of digitalRead doesn't // disable the PWMs so we can use it as is // portModeRegister(pin) is OK diff --git a/Marlin/src/HAL/AVR/pinsDebug_plus_70.h b/Marlin/src/HAL/AVR/pinsDebug_plus_70.h index d9aa44c3..fa479cfe 100644 --- a/Marlin/src/HAL/AVR/pinsDebug_plus_70.h +++ b/Marlin/src/HAL/AVR/pinsDebug_plus_70.h @@ -231,7 +231,6 @@ const uint8_t PROGMEM digital_pin_to_bit_mask_PGM_plus_70[] = { #define digitalPinToBitMask_plus_70(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM_plus_70 + (P) ) ) - const uint8_t PROGMEM digital_pin_to_timer_PGM_plus_70[] = { // TIMERS // ------------------------ diff --git a/Marlin/src/HAL/AVR/timers.h b/Marlin/src/HAL/AVR/timers.h index 36b04eae..94b17f31 100644 --- a/Marlin/src/HAL/AVR/timers.h +++ b/Marlin/src/HAL/AVR/timers.h @@ -1,7 +1,9 @@ /** * Marlin 3D Printer Firmware * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -44,23 +46,23 @@ typedef uint16_t hal_timer_t; #define MF_TIMER_TEMP 0 #endif -#define TEMP_TIMER_FREQUENCY ((F_CPU) / 64.0 / 256.0) +#define TEMP_TIMER_FREQUENCY (((F_CPU) + 0x2000) / 0x4000) #define STEPPER_TIMER_RATE HAL_TIMER_RATE #define STEPPER_TIMER_PRESCALE 8 -#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // Cannot be of type double +#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) -#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // frequency of pulse timer -#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE +#define PULSE_TIMER_RATE STEPPER_TIMER_RATE +#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE #define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US #define ENABLE_STEPPER_DRIVER_INTERRUPT() SBI(TIMSK1, OCIE1A) #define DISABLE_STEPPER_DRIVER_INTERRUPT() CBI(TIMSK1, OCIE1A) #define STEPPER_ISR_ENABLED() TEST(TIMSK1, OCIE1A) -#define ENABLE_TEMPERATURE_INTERRUPT() SBI(TIMSK0, OCIE0B) -#define DISABLE_TEMPERATURE_INTERRUPT() CBI(TIMSK0, OCIE0B) -#define TEMPERATURE_ISR_ENABLED() TEST(TIMSK0, OCIE0B) +#define ENABLE_TEMPERATURE_INTERRUPT() SBI(TIMSK0, OCIE0A) +#define DISABLE_TEMPERATURE_INTERRUPT() CBI(TIMSK0, OCIE0A) +#define TEMPERATURE_ISR_ENABLED() TEST(TIMSK0, OCIE0A) FORCE_INLINE void HAL_timer_start(const uint8_t timer_num, const uint32_t) { switch (timer_num) { @@ -87,7 +89,7 @@ FORCE_INLINE void HAL_timer_start(const uint8_t timer_num, const uint32_t) { case MF_TIMER_TEMP: // Use timer0 for temperature measurement // Interleave temperature interrupt with millies interrupt - OCR0B = 128; + OCR0A = 128; break; } } @@ -109,12 +111,12 @@ FORCE_INLINE void HAL_timer_start(const uint8_t timer_num, const uint32_t) { * (otherwise, characters will be lost due to UART overflow). * Then: Stepper, Endstops, Temperature, and -finally- all others. */ -#define HAL_timer_isr_prologue(T) -#define HAL_timer_isr_epilogue(T) +#define HAL_timer_isr_prologue(T) NOOP +#define HAL_timer_isr_epilogue(T) NOOP -/* 18 cycles maximum latency */ #ifndef HAL_STEP_TIMER_ISR +/* 18 cycles maximum latency */ #define HAL_STEP_TIMER_ISR() \ extern "C" void TIMER1_COMPA_vect() __attribute__ ((signal, naked, used, externally_visible)); \ extern "C" void TIMER1_COMPA_vect_bottom() asm ("TIMER1_COMPA_vect_bottom") __attribute__ ((used, externally_visible, noinline)); \ @@ -180,7 +182,7 @@ void TIMER1_COMPA_vect() { \ : \ : [timsk0] "i" ((uint16_t)&TIMSK0), \ [timsk1] "i" ((uint16_t)&TIMSK1), \ - [msk0] "M" ((uint8_t)(1<. - * - */ -#ifdef __AVR__ - -#include "../../inc/MarlinConfig.h" - -#if ENABLED(USE_WATCHDOG) - -#include "watchdog.h" - -#include "../../MarlinCore.h" - -// Initialize watchdog with 8s timeout, if possible. Otherwise, make it 4s. -void watchdog_init() { - #if ENABLED(WATCHDOG_DURATION_8S) && defined(WDTO_8S) - #define WDTO_NS WDTO_8S - #else - #define WDTO_NS WDTO_4S - #endif - #if ENABLED(WATCHDOG_RESET_MANUAL) - // Enable the watchdog timer, but only for the interrupt. - // Take care, as this requires the correct order of operation, with interrupts disabled. - // See the datasheet of any AVR chip for details. - wdt_reset(); - cli(); - _WD_CONTROL_REG = _BV(_WD_CHANGE_BIT) | _BV(WDE); - _WD_CONTROL_REG = _BV(WDIE) | (WDTO_NS & 0x07) | ((WDTO_NS & 0x08) << 2); // WDTO_NS directly does not work. bit 0-2 are consecutive in the register but the highest value bit is at bit 5 - // So worked for up to WDTO_2S - sei(); - wdt_reset(); - #else - wdt_enable(WDTO_NS); // The function handles the upper bit correct. - #endif - //delay(10000); // test it! -} - -//=========================================================================== -//=================================== ISR =================================== -//=========================================================================== - -// Watchdog timer interrupt, called if main program blocks >4sec and manual reset is enabled. -#if ENABLED(WATCHDOG_RESET_MANUAL) - ISR(WDT_vect) { - sei(); // With the interrupt driven serial we need to allow interrupts. - SERIAL_ERROR_MSG(STR_WATCHDOG_FIRED); - minkill(); // interrupt-safe final kill and infinite loop - } -#endif - -#endif // USE_WATCHDOG -#endif // __AVR__ diff --git a/Marlin/src/HAL/DUE/HAL.cpp b/Marlin/src/HAL/DUE/HAL.cpp index a3985652..763091cb 100644 --- a/Marlin/src/HAL/DUE/HAL.cpp +++ b/Marlin/src/HAL/DUE/HAL.cpp @@ -1,7 +1,9 @@ /** * Marlin 3D Printer Firmware * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,7 +27,7 @@ #ifdef ARDUINO_ARCH_SAM #include "../../inc/MarlinConfig.h" -#include "HAL.h" +#include "../../MarlinCore.h" #include #include "usb/usb_task.h" @@ -34,39 +36,33 @@ // Public Variables // ------------------------ -uint16_t HAL_adc_result; +uint16_t MarlinHAL::adc_result; // ------------------------ // Public functions // ------------------------ -TERN_(POSTMORTEM_DEBUGGING, extern void install_min_serial()); +#if ENABLED(POSTMORTEM_DEBUGGING) + extern void install_min_serial(); +#endif -// HAL initialization task -void HAL_init() { - // Initialize the USB stack - #if ENABLED(SDSUPPORT) +void MarlinHAL::init() { + #if HAS_MEDIA OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up #endif - usb_task_init(); + usb_task_init(); // Initialize the USB stack TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); // Install the min serial handler } -// HAL idle task -void HAL_idletask() { - // Perform USB stack housekeeping - usb_task_idle(); +void MarlinHAL::init_board() { + #ifdef BOARD_INIT + BOARD_INIT(); + #endif } -// Disable interrupts -void cli() { noInterrupts(); } - -// Enable interrupts -void sei() { interrupts(); } - -void HAL_clear_reset_source() { } +void MarlinHAL::idletask() { usb_task_idle(); } // Perform USB stack housekeeping -uint8_t HAL_get_reset_source() { +uint8_t MarlinHAL::get_reset_source() { switch ((RSTC->RSTC_SR >> 8) & 0x07) { case 0: return RST_POWER_ON; case 1: return RST_BACKUP; @@ -77,13 +73,105 @@ uint8_t HAL_get_reset_source() { } } -void HAL_reboot() { rstc_start_software_reset(RSTC); } +void MarlinHAL::reboot() { rstc_start_software_reset(RSTC); } + +// ------------------------ +// Watchdog Timer +// ------------------------ + +#if ENABLED(USE_WATCHDOG) + + // Initialize watchdog - On SAM3X, Watchdog was already configured + // and enabled or disabled at startup, so no need to reconfigure it + // here. + void MarlinHAL::watchdog_init() { WDT_Restart(WDT); } // Reset watchdog to start clean + + // Reset watchdog. MUST be called at least every 4 seconds after the + // first watchdog_init or AVR will go into emergency procedures. + void MarlinHAL::watchdog_refresh() { watchdogReset(); } + +#endif + +// Override Arduino runtime to either config or disable the watchdog +// +// We need to configure the watchdog as soon as possible in the boot +// process, because watchdog initialization at hardware reset on SAM3X8E +// is unreliable, and there is risk of unintended resets if we delay +// that initialization to a later time. +void watchdogSetup() { + + #if ENABLED(USE_WATCHDOG) + + // 4 seconds timeout + uint32_t timeout = TERN(WATCHDOG_DURATION_8S, 8000, 4000); + + // Calculate timeout value in WDT counter ticks: This assumes + // the slow clock is running at 32.768 kHz watchdog + // frequency is therefore 32768 / 128 = 256 Hz + timeout = (timeout << 8) / 1000; + if (timeout == 0) + timeout = 1; + else if (timeout > 0xFFF) + timeout = 0xFFF; + + // We want to enable the watchdog with the specified timeout + uint32_t value = + WDT_MR_WDV(timeout) | // With the specified timeout + WDT_MR_WDD(timeout) | // and no invalid write window + #if !(SAMV70 || SAMV71 || SAME70 || SAMS70) + WDT_MR_WDRPROC | // WDT fault resets processor only - We want + // to keep PIO controller state + #endif + WDT_MR_WDDBGHLT | // WDT stops in debug state. + WDT_MR_WDIDLEHLT; // WDT stops in idle state. + + #if ENABLED(WATCHDOG_RESET_MANUAL) + // We enable the watchdog timer, but only for the interrupt. + + // Configure WDT to only trigger an interrupt + value |= WDT_MR_WDFIEN; // Enable WDT fault interrupt. -void _delay_ms(const int delay_ms) { - // Todo: port for Due? - delay(delay_ms); + // Disable WDT interrupt (just in case, to avoid triggering it!) + NVIC_DisableIRQ(WDT_IRQn); + + // We NEED memory barriers to ensure Interrupts are actually disabled! + // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the ) + __DSB(); + __ISB(); + + // Initialize WDT with the given parameters + WDT_Enable(WDT, value); + + // Configure and enable WDT interrupt. + NVIC_ClearPendingIRQ(WDT_IRQn); + NVIC_SetPriority(WDT_IRQn, 0); // Use highest priority, so we detect all kinds of lockups + NVIC_EnableIRQ(WDT_IRQn); + + #else + + // a WDT fault triggers a reset + value |= WDT_MR_WDRSTEN; + + // Initialize WDT with the given parameters + WDT_Enable(WDT, value); + + #endif + + // Reset the watchdog + WDT_Restart(WDT); + + #else + + // Make sure to completely disable the Watchdog + WDT_Disable(WDT); + + #endif } +// ------------------------ +// Free Memory Accessor +// ------------------------ + extern "C" { extern unsigned int _ebss; // end of bss section } @@ -95,18 +183,9 @@ int freeMemory() { } // ------------------------ -// ADC +// Serial Ports // ------------------------ -void HAL_adc_start_conversion(const uint8_t ch) { - HAL_adc_result = analogRead(ch); -} - -uint16_t HAL_adc_get_result() { - // nop - return HAL_adc_result; -} - // Forward the default serial ports #if USING_HW_SERIAL0 DefaultSerial1 MSerial0(false, Serial); diff --git a/Marlin/src/HAL/DUE/HAL.h b/Marlin/src/HAL/DUE/HAL.h index 96ab5d98..fde235ed 100644 --- a/Marlin/src/HAL/DUE/HAL.h +++ b/Marlin/src/HAL/DUE/HAL.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,12 +32,15 @@ #include "../shared/math_32bit.h" #include "../shared/HAL_SPI.h" #include "fastio.h" -#include "watchdog.h" #include #include "../../core/serial_hook.h" +// ------------------------ +// Serial ports +// ------------------------ + typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1; typedef ForwardSerial1Class< decltype(Serial1) > DefaultSerial2; typedef ForwardSerial1Class< decltype(Serial2) > DefaultSerial3; @@ -97,60 +100,38 @@ extern DefaultSerial4 MSerial3; #include "MarlinSerial.h" #include "MarlinSerialUSB.h" -// On AVR this is in math.h? -#define square(x) ((x)*(x)) +// ------------------------ +// Types +// ------------------------ typedef int8_t pin_t; -#define SHARED_SERVOS HAS_SERVOS -#define HAL_SERVO_LIB Servo +#define SHARED_SERVOS HAS_SERVOS // Use shared/servos.cpp + +class Servo; +typedef Servo hal_servo_t; // // Interrupts // -#define CRITICAL_SECTION_START() uint32_t primask = __get_PRIMASK(); __disable_irq() -#define CRITICAL_SECTION_END() if (!primask) __enable_irq() -#define ISRS_ENABLED() (!__get_PRIMASK()) -#define ENABLE_ISRS() __enable_irq() -#define DISABLE_ISRS() __disable_irq() - -void cli(); // Disable interrupts -void sei(); // Enable interrupts - -void HAL_clear_reset_source(); // clear reset reason -uint8_t HAL_get_reset_source(); // get reset reason +#define sei() interrupts() +#define cli() noInterrupts() -void HAL_reboot(); +#define CRITICAL_SECTION_START() const bool _irqon = hal.isr_state(); hal.isr_off() +#define CRITICAL_SECTION_END() if (_irqon) hal.isr_on() // // ADC // -extern uint16_t HAL_adc_result; // result of last ADC conversion +#define HAL_ADC_VREF_MV 3300 +#define HAL_ADC_RESOLUTION 10 #ifndef analogInputToDigitalPin - #define analogInputToDigitalPin(p) ((p < 12U) ? (p) + 54U : -1) + #define analogInputToDigitalPin(p) pin_t((p < 12U) ? (p) + 54U : -1) #endif -#define HAL_ANALOG_SELECT(ch) - -inline void HAL_adc_init() {}//todo - -#define HAL_ADC_VREF 3.3 -#define HAL_ADC_RESOLUTION 10 -#define HAL_START_ADC(ch) HAL_adc_start_conversion(ch) -#define HAL_READ_ADC() HAL_adc_result -#define HAL_ADC_READY() true - -void HAL_adc_start_conversion(const uint8_t ch); -uint16_t HAL_adc_get_result(); - -// -// PWM // -inline void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { analogWrite(pin, v); } - -// -// Pin Map +// Pin Mapping for M42, M43, M226 // #define GET_PIN_MAP_PIN(index) index #define GET_PIN_MAP_INDEX(pin) pin @@ -159,27 +140,18 @@ inline void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, // // Tone // -void toneInit(); void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration=0); void noTone(const pin_t _pin); -// Enable hooks into idle and setup for HAL -#define HAL_IDLETASK 1 -void HAL_idletask(); -void HAL_init(); - -// -// Utility functions -// -void _delay_ms(const int delay); +// ------------------------ +// Class Utilities +// ------------------------ #pragma GCC diagnostic push #if GCC_VERSION <= 50000 #pragma GCC diagnostic ignored "-Wunused-function" #endif -int freeMemory(); - #pragma GCC diagnostic pop #ifdef __cplusplus @@ -189,3 +161,73 @@ char *dtostrf(double __val, signed char __width, unsigned char __prec, char *__s #ifdef __cplusplus } #endif + +// Return free RAM between end of heap (or end bss) and whatever is current +int freeMemory(); + +// ------------------------ +// MarlinHAL Class +// ------------------------ + +class MarlinHAL { +public: + + // Earliest possible init, before setup() + MarlinHAL() {} + + // Watchdog + static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {}); + static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {}); + + static void init(); // Called early in setup() + static void init_board(); // Called less early in setup() + static void reboot(); // Restart the firmware + + // Interrupts + static bool isr_state() { return !__get_PRIMASK(); } + static void isr_on() { __enable_irq(); } + static void isr_off() { __disable_irq(); } + + static void delay_ms(const int ms) { delay(ms); } + + // Tasks, called from idle() + static void idletask(); + + // Reset + static uint8_t get_reset_source(); + static void clear_reset_source() {} + + // Free SRAM + static int freeMemory() { return ::freeMemory(); } + + // + // ADC Methods + // + + static uint16_t adc_result; + + // Called by Temperature::init once at startup + static void adc_init() {} + + // Called by Temperature::init for each sensor at startup + static void adc_enable(const uint8_t /*ch*/) {} + + // Begin ADC sampling on the given channel. Called from Temperature::isr! + static void adc_start(const uint8_t ch) { adc_result = analogRead(ch); } + + // Is the ADC ready for reading? + static bool adc_ready() { return true; } + + // The current value of the ADC register + static uint16_t adc_value() { return adc_result; } + + /** + * Set the PWM duty cycle for the pin to the given value. + * No inverting the duty cycle in this HAL. + * No changing the maximum size of the provided value to enable finer PWM duty control in this HAL. + */ + static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { + analogWrite(pin, v); + } + +}; diff --git a/Marlin/src/HAL/DUE/HAL_SPI.cpp b/Marlin/src/HAL/DUE/HAL_SPI.cpp index c5e8f243..63ebf164 100644 --- a/Marlin/src/HAL/DUE/HAL_SPI.cpp +++ b/Marlin/src/HAL/DUE/HAL_SPI.cpp @@ -31,8 +31,6 @@ /** * HAL for Arduino Due and compatible (SAM3X8E) - * - * For ARDUINO_ARCH_SAM */ #ifdef ARDUINO_ARCH_SAM @@ -44,7 +42,7 @@ // Public functions // ------------------------ -#if EITHER(DUE_SOFTWARE_SPI, FORCE_SOFT_SPI) +#if ANY(DUE_SOFTWARE_SPI, FORCE_SOFT_SPI) // ------------------------ // Software SPI @@ -249,12 +247,12 @@ b <<= 1; // little setup time WRITE(SD_SCK_PIN, HIGH); - DELAY_NS(spiDelayNS); + DELAY_NS_VAR(spiDelayNS); b |= (READ(SD_MISO_PIN) != 0); WRITE(SD_SCK_PIN, LOW); - DELAY_NS(spiDelayNS); + DELAY_NS_VAR(spiDelayNS); } while (--bits); return b; } diff --git a/Marlin/src/HAL/DUE/InterruptVectors.cpp b/Marlin/src/HAL/DUE/InterruptVectors.cpp index e4e0ce99..70795d1c 100644 --- a/Marlin/src/HAL/DUE/InterruptVectors.cpp +++ b/Marlin/src/HAL/DUE/InterruptVectors.cpp @@ -41,7 +41,7 @@ practice, we need alignment to 256 bytes to make this work in all cases */ __attribute__ ((aligned(256))) -static DeviceVectors ram_tab = { nullptr }; +static DeviceVectors ram_tab[61] = { nullptr }; /** * This function checks if the exception/interrupt table is already in SRAM or not. diff --git a/Marlin/src/HAL/DUE/MarlinSerial.cpp b/Marlin/src/HAL/DUE/MarlinSerial.cpp index fe62ff56..90efe55f 100644 --- a/Marlin/src/HAL/DUE/MarlinSerial.cpp +++ b/Marlin/src/HAL/DUE/MarlinSerial.cpp @@ -406,7 +406,7 @@ size_t MarlinSerial::write(const uint8_t c) { const uint8_t i = (tx_buffer.head + 1) & (Cfg::TX_SIZE - 1); // If global interrupts are disabled (as the result of being called from an ISR)... - if (!ISRS_ENABLED()) { + if (!hal.isr_state()) { // Make room by polling if it is possible to transmit, and do so! while (i == tx_buffer.tail) { @@ -454,7 +454,7 @@ void MarlinSerial::flushTX() { if (!_written) return; // If global interrupts are disabled (as the result of being called from an ISR)... - if (!ISRS_ENABLED()) { + if (!hal.isr_state()) { // Wait until everything was transmitted - We must do polling, as interrupts are disabled while (tx_buffer.head != tx_buffer.tail || !(HWUART->UART_SR & UART_SR_TXEMPTY)) { @@ -474,7 +474,6 @@ void MarlinSerial::flushTX() { } } - // If not using the USB port as serial port #if defined(SERIAL_PORT) && SERIAL_PORT >= 0 template class MarlinSerial< MarlinSerialCfg >; diff --git a/Marlin/src/HAL/DUE/MarlinSerial.h b/Marlin/src/HAL/DUE/MarlinSerial.h index 4a62e283..b80ae218 100644 --- a/Marlin/src/HAL/DUE/MarlinSerial.h +++ b/Marlin/src/HAL/DUE/MarlinSerial.h @@ -30,6 +30,7 @@ #include #include "../../inc/MarlinConfigPre.h" +#include "../../core/types.h" #include "../../core/serial_hook.h" // Define constants and variables for buffering incoming serial data. We're @@ -52,10 +53,6 @@ // #error "TX_BUFFER_SIZE must be 0, a power of 2 greater than 1, and no greater than 256." //#endif -// Templated type selector -template struct TypeSelector { typedef T type;} ; -template struct TypeSelector { typedef F type; }; - // Templated structure wrapper template struct StructWrapper { constexpr StructWrapper(int) {} @@ -76,7 +73,7 @@ class MarlinSerial { static constexpr int HWUART_IRQ_ID = IRQ_IDS[Cfg::PORT]; // Base size of type on buffer size - typedef typename TypeSelector<(Cfg::RX_SIZE>256), uint16_t, uint8_t>::type ring_buffer_pos_t; + typedef uvalue_t(Cfg::RX_SIZE - 1) ring_buffer_pos_t; struct ring_buffer_r { volatile ring_buffer_pos_t head, tail; @@ -118,7 +115,7 @@ class MarlinSerial { static size_t write(const uint8_t c); static void flushTX(); - static inline bool emergency_parser_enabled() { return Cfg::EMERGENCYPARSER; } + static bool emergency_parser_enabled() { return Cfg::EMERGENCYPARSER; } FORCE_INLINE static uint8_t dropped() { return Cfg::DROPPED_RX ? rx_dropped_bytes : 0; } FORCE_INLINE static uint8_t buffer_overruns() { return Cfg::RX_OVERRUNS ? rx_buffer_overruns : 0; } diff --git a/Marlin/src/HAL/DUE/MarlinSerialUSB.cpp b/Marlin/src/HAL/DUE/MarlinSerialUSB.cpp index 67c597da..8de2dc79 100644 --- a/Marlin/src/HAL/DUE/MarlinSerialUSB.cpp +++ b/Marlin/src/HAL/DUE/MarlinSerialUSB.cpp @@ -41,7 +41,7 @@ extern "C" { int udi_cdc_getc(); bool udi_cdc_is_tx_ready(); int udi_cdc_putc(int value); -}; +} // Pending character static int pending_char = -1; diff --git a/Marlin/src/HAL/DUE/HAL_MinSerial.cpp b/Marlin/src/HAL/DUE/MinSerial.cpp similarity index 81% rename from Marlin/src/HAL/DUE/HAL_MinSerial.cpp rename to Marlin/src/HAL/DUE/MinSerial.cpp index 93c4ed67..505a712a 100644 --- a/Marlin/src/HAL/DUE/HAL_MinSerial.cpp +++ b/Marlin/src/HAL/DUE/MinSerial.cpp @@ -25,7 +25,7 @@ #if ENABLED(POSTMORTEM_DEBUGGING) -#include "../shared/HAL_MinSerial.h" +#include "../shared/MinSerial.h" #include @@ -73,18 +73,18 @@ void install_min_serial() { } #if DISABLED(DYNAMIC_VECTORTABLE) -extern "C" { - __attribute__((naked)) void JumpHandler_ASM() { - __asm__ __volatile__ ( - "b CommonHandler_ASM\n" - ); + extern "C" { + __attribute__((naked)) void JumpHandler_ASM() { + __asm__ __volatile__ ( + "b CommonHandler_ASM\n" + ); + } + void __attribute__((naked, alias("JumpHandler_ASM"))) HardFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"))) BusFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"))) UsageFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"))) MemManage_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"))) NMI_Handler(); } - void __attribute__((naked, alias("JumpHandler_ASM"))) HardFault_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"))) BusFault_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"))) UsageFault_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"))) MemManage_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"))) NMI_Handler(); -} #endif #endif // POSTMORTEM_DEBUGGING diff --git a/Marlin/src/HAL/DUE/Servo.cpp b/Marlin/src/HAL/DUE/Servo.cpp index 5524aa9c..2f72d66b 100644 --- a/Marlin/src/HAL/DUE/Servo.cpp +++ b/Marlin/src/HAL/DUE/Servo.cpp @@ -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. +// 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 - - 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 +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] = ++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 - - /* 84MHz, MCK/32, for 1.5ms: 3937 */ - TC_SetRA(tc, channel, 2625); // 1ms - - /* Configure and enable interrupt */ + 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 + ); + + // Wait 1ms before the first ISR + TC_SetRA(tc, channel, (F_CPU) / (SERVO_TIMER_PRESCALER) / 1000UL); // 1ms + + // 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 diff --git a/Marlin/src/HAL/DUE/ServoTimers.h b/Marlin/src/HAL/DUE/ServoTimers.h index c32c9382..95bd404c 100644 --- a/Marlin/src/HAL/DUE/ServoTimers.h +++ b/Marlin/src/HAL/DUE/ServoTimers.h @@ -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 diff --git a/Marlin/src/HAL/DUE/Tone.cpp b/Marlin/src/HAL/DUE/Tone.cpp index 1ac81faa..4bc8142a 100644 --- a/Marlin/src/HAL/DUE/Tone.cpp +++ b/Marlin/src/HAL/DUE/Tone.cpp @@ -35,7 +35,7 @@ static pin_t tone_pin; volatile static int32_t toggles; -void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration) { +void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration/*=0*/) { tone_pin = _pin; toggles = 2 * frequency * duration / 1000; HAL_timer_start(MF_TIMER_TONE, 2 * frequency); diff --git a/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_sw_spi_shared.cpp b/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_sw_spi_shared.cpp index 90492479..86c8a484 100644 --- a/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_sw_spi_shared.cpp +++ b/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_sw_spi_shared.cpp @@ -81,7 +81,7 @@ Pio *SCK_pPio, *MOSI_pPio; uint32_t SCK_dwMask, MOSI_dwMask; void u8g_spiSend_sw_DUE_mode_0(uint8_t val) { // 3MHz - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { if (val & 0x80) MOSI_pPio->PIO_SODR = MOSI_dwMask; else @@ -95,7 +95,7 @@ void u8g_spiSend_sw_DUE_mode_0(uint8_t val) { // 3MHz } void u8g_spiSend_sw_DUE_mode_3(uint8_t val) { // 3.5MHz - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { SCK_pPio->PIO_CODR = SCK_dwMask; DELAY_NS(50); if (val & 0x80) diff --git a/Marlin/src/HAL/DUE/eeprom_flash.cpp b/Marlin/src/HAL/DUE/eeprom_flash.cpp index 7ce4a84d..915a699e 100644 --- a/Marlin/src/HAL/DUE/eeprom_flash.cpp +++ b/Marlin/src/HAL/DUE/eeprom_flash.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2016 Victor Perez victor_pv@hotmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -199,8 +198,7 @@ static bool ee_PageWrite(uint16_t page, const void *data) { for (i = 0; i > 2; i++) pageContents[i] = (((uint32_t*)data)[i]) | (~(pageContents[i] ^ ((uint32_t*)data)[i])); - DEBUG_ECHO_START(); - DEBUG_ECHOLNPGM("EEPROM PageWrite ", page); + DEBUG_ECHO_MSG("EEPROM PageWrite ", page); DEBUG_ECHOLNPGM(" in FLASH address ", (uint32_t)addrflash); DEBUG_ECHOLNPGM(" base address ", (uint32_t)getFlashStorage(0)); DEBUG_FLUSH(); @@ -245,8 +243,7 @@ static bool ee_PageWrite(uint16_t page, const void *data) { // Reenable interrupts __enable_irq(); - DEBUG_ECHO_START(); - DEBUG_ECHOLNPGM("EEPROM Unlock failure for page ", page); + DEBUG_ECHO_MSG("EEPROM Unlock failure for page ", page); return false; } @@ -270,8 +267,7 @@ static bool ee_PageWrite(uint16_t page, const void *data) { // Reenable interrupts __enable_irq(); - DEBUG_ECHO_START(); - DEBUG_ECHOLNPGM("EEPROM Write failure for page ", page); + DEBUG_ECHO_MSG("EEPROM Write failure for page ", page); return false; } @@ -286,8 +282,7 @@ static bool ee_PageWrite(uint16_t page, const void *data) { if (memcmp(getFlashStorage(page),data,PageSize)) { #ifdef EE_EMU_DEBUG - DEBUG_ECHO_START(); - DEBUG_ECHOLNPGM("EEPROM Verify Write failure for page ", page); + DEBUG_ECHO_MSG("EEPROM Verify Write failure for page ", page); ee_Dump( page, (uint32_t *)addrflash); ee_Dump(-page, data); @@ -296,7 +291,7 @@ static bool ee_PageWrite(uint16_t page, const void *data) { uint32_t *p1 = (uint32_t*)addrflash; uint32_t *p2 = (uint32_t*)data; int count = 0; - for (i =0; i> 2; i++) { + for (i = 0; i < PageSize >> 2; i++) { if (p1[i] != p2[i]) { uint32_t delta = p1[i] ^ p2[i]; while (delta) { @@ -325,8 +320,7 @@ static bool ee_PageErase(uint16_t page) { uint16_t i; uint32_t addrflash = uint32_t(getFlashStorage(page)); - DEBUG_ECHO_START(); - DEBUG_ECHOLNPGM("EEPROM PageErase ", page); + DEBUG_ECHO_MSG("EEPROM PageErase ", page); DEBUG_ECHOLNPGM(" in FLASH address ", (uint32_t)addrflash); DEBUG_ECHOLNPGM(" base address ", (uint32_t)getFlashStorage(0)); DEBUG_FLUSH(); @@ -370,8 +364,7 @@ static bool ee_PageErase(uint16_t page) { // Reenable interrupts __enable_irq(); - DEBUG_ECHO_START(); - DEBUG_ECHOLNPGM("EEPROM Unlock failure for page ",page); + DEBUG_ECHO_MSG("EEPROM Unlock failure for page ",page); return false; } @@ -394,8 +387,7 @@ static bool ee_PageErase(uint16_t page) { // Reenable interrupts __enable_irq(); - DEBUG_ECHO_START(); - DEBUG_ECHOLNPGM("EEPROM Erase failure for page ",page); + DEBUG_ECHO_MSG("EEPROM Erase failure for page ",page); return false; } @@ -410,8 +402,7 @@ static bool ee_PageErase(uint16_t page) { uint32_t * aligned_src = (uint32_t *) addrflash; for (i = 0; i < PageSize >> 2; i++) { if (*aligned_src++ != 0xFFFFFFFF) { - DEBUG_ECHO_START(); - DEBUG_ECHOLNPGM("EEPROM Verify Erase failure for page ",page); + DEBUG_ECHO_MSG("EEPROM Verify Erase failure for page ",page); ee_Dump(page, (uint32_t *)addrflash); return false; } @@ -921,8 +912,7 @@ static void ee_Init() { // If all groups seem to be used, default to first group if (curGroup >= GroupCount) curGroup = 0; - DEBUG_ECHO_START(); - DEBUG_ECHOLNPGM("EEPROM Current Group: ",curGroup); + DEBUG_ECHO_MSG("EEPROM Current Group: ",curGroup); DEBUG_FLUSH(); // Now, validate that all the other group pages are empty @@ -931,8 +921,7 @@ static void ee_Init() { for (int page = 0; page < PagesPerGroup; page++) { if (!ee_IsPageClean(grp * PagesPerGroup + page)) { - DEBUG_ECHO_START(); - DEBUG_ECHOLNPGM("EEPROM Page ", page, " not clean on group ", grp); + DEBUG_ECHO_MSG("EEPROM Page ", page, " not clean on group ", grp); DEBUG_FLUSH(); ee_PageErase(grp * PagesPerGroup + page); } @@ -948,15 +937,13 @@ static void ee_Init() { } } - DEBUG_ECHO_START(); - DEBUG_ECHOLNPGM("EEPROM Active page: ", curPage); + DEBUG_ECHO_MSG("EEPROM Active page: ", curPage); DEBUG_FLUSH(); // Make sure the pages following the first clean one are also clean for (int page = curPage + 1; page < PagesPerGroup; page++) { if (!ee_IsPageClean(curGroup * PagesPerGroup + page)) { - DEBUG_ECHO_START(); - DEBUG_ECHOLNPGM("EEPROM Page ", page, " not clean on active group ", curGroup); + DEBUG_ECHO_MSG("EEPROM Page ", page, " not clean on active group ", curGroup); DEBUG_FLUSH(); ee_Dump(curGroup * PagesPerGroup + page, getFlashStorage(curGroup * PagesPerGroup + page)); ee_PageErase(curGroup * PagesPerGroup + page); diff --git a/Marlin/src/HAL/DUE/eeprom_wired.cpp b/Marlin/src/HAL/DUE/eeprom_wired.cpp index 557a2f2c..24f8c06d 100644 --- a/Marlin/src/HAL/DUE/eeprom_wired.cpp +++ b/Marlin/src/HAL/DUE/eeprom_wired.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2016 Victor Perez victor_pv@hotmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Marlin/src/HAL/DUE/endstop_interrupts.h b/Marlin/src/HAL/DUE/endstop_interrupts.h index 9c7e2104..08ffc256 100644 --- a/Marlin/src/HAL/DUE/endstop_interrupts.h +++ b/Marlin/src/HAL/DUE/endstop_interrupts.h @@ -47,27 +47,33 @@ void endstop_ISR() { endstops.update(); } void setup_endstop_interrupts() { #define _ATTACH(P) attachInterrupt(digitalPinToInterrupt(P), endstop_ISR, CHANGE) - TERN_(HAS_X_MAX, _ATTACH(X_MAX_PIN)); - TERN_(HAS_X_MIN, _ATTACH(X_MIN_PIN)); - TERN_(HAS_Y_MAX, _ATTACH(Y_MAX_PIN)); - TERN_(HAS_Y_MIN, _ATTACH(Y_MIN_PIN)); - TERN_(HAS_Z_MAX, _ATTACH(Z_MAX_PIN)); - TERN_(HAS_Z_MIN, _ATTACH(Z_MIN_PIN)); - TERN_(HAS_X2_MAX, _ATTACH(X2_MAX_PIN)); - TERN_(HAS_X2_MIN, _ATTACH(X2_MIN_PIN)); - TERN_(HAS_Y2_MAX, _ATTACH(Y2_MAX_PIN)); - TERN_(HAS_Y2_MIN, _ATTACH(Y2_MIN_PIN)); - TERN_(HAS_Z2_MAX, _ATTACH(Z2_MAX_PIN)); - TERN_(HAS_Z2_MIN, _ATTACH(Z2_MIN_PIN)); - TERN_(HAS_Z3_MAX, _ATTACH(Z3_MAX_PIN)); - TERN_(HAS_Z3_MIN, _ATTACH(Z3_MIN_PIN)); - TERN_(HAS_Z4_MAX, _ATTACH(Z4_MAX_PIN)); - TERN_(HAS_Z4_MIN, _ATTACH(Z4_MIN_PIN)); + TERN_(USE_X_MAX, _ATTACH(X_MAX_PIN)); + TERN_(USE_X_MIN, _ATTACH(X_MIN_PIN)); + TERN_(USE_Y_MAX, _ATTACH(Y_MAX_PIN)); + TERN_(USE_Y_MIN, _ATTACH(Y_MIN_PIN)); + TERN_(USE_Z_MAX, _ATTACH(Z_MAX_PIN)); + TERN_(USE_Z_MIN, _ATTACH(Z_MIN_PIN)); + TERN_(USE_X2_MAX, _ATTACH(X2_MAX_PIN)); + TERN_(USE_X2_MIN, _ATTACH(X2_MIN_PIN)); + TERN_(USE_Y2_MAX, _ATTACH(Y2_MAX_PIN)); + TERN_(USE_Y2_MIN, _ATTACH(Y2_MIN_PIN)); + TERN_(USE_Z2_MAX, _ATTACH(Z2_MAX_PIN)); + TERN_(USE_Z2_MIN, _ATTACH(Z2_MIN_PIN)); + TERN_(USE_Z3_MAX, _ATTACH(Z3_MAX_PIN)); + TERN_(USE_Z3_MIN, _ATTACH(Z3_MIN_PIN)); + TERN_(USE_Z4_MAX, _ATTACH(Z4_MAX_PIN)); + TERN_(USE_Z4_MIN, _ATTACH(Z4_MIN_PIN)); TERN_(HAS_Z_MIN_PROBE_PIN, _ATTACH(Z_MIN_PROBE_PIN)); - TERN_(HAS_I_MAX, _ATTACH(I_MAX_PIN)); - TERN_(HAS_I_MIN, _ATTACH(I_MIN_PIN)); - TERN_(HAS_J_MAX, _ATTACH(J_MAX_PIN)); - TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN)); - TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN)); - TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_I_MAX, _ATTACH(I_MAX_PIN)); + TERN_(USE_I_MIN, _ATTACH(I_MIN_PIN)); + TERN_(USE_J_MAX, _ATTACH(J_MAX_PIN)); + TERN_(USE_J_MIN, _ATTACH(J_MIN_PIN)); + TERN_(USE_K_MAX, _ATTACH(K_MAX_PIN)); + TERN_(USE_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(USE_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(USE_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(USE_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(USE_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(USE_W_MIN, _ATTACH(W_MIN_PIN)); } diff --git a/Marlin/src/HAL/DUE/fastio.h b/Marlin/src/HAL/DUE/fastio.h index a609210d..77bc1911 100644 --- a/Marlin/src/HAL/DUE/fastio.h +++ b/Marlin/src/HAL/DUE/fastio.h @@ -189,12 +189,12 @@ */ // UART -#define RXD DIO0 -#define TXD DIO1 +#define RXD 0 +#define TXD 1 // TWI (I2C) -#define SCL DIO21 -#define SDA DIO20 +#define SCL 21 +#define SDA 20 /** * pins diff --git a/Marlin/src/HAL/DUE/fastio/G2_PWM.cpp b/Marlin/src/HAL/DUE/fastio/G2_PWM.cpp index d9fbabce..800915ff 100644 --- a/Marlin/src/HAL/DUE/fastio/G2_PWM.cpp +++ b/Marlin/src/HAL/DUE/fastio/G2_PWM.cpp @@ -25,7 +25,7 @@ * is NOT used to directly toggle pins. The ISR writes to the pin assigned to * that interrupt. * - * All PWMs use the same repetition rate. The G2 needs about 10KHz min in order to + * All PWMs use the same repetition rate. The G2 needs about 10kHz min in order to * not have obvious ripple on the Vref signals. * * The data structures are setup to minimize the computation done by the ISR which diff --git a/Marlin/src/HAL/DUE/fastio/G2_PWM.h b/Marlin/src/HAL/DUE/fastio/G2_PWM.h index dc4edfff..054eb2cf 100644 --- a/Marlin/src/HAL/DUE/fastio/G2_PWM.h +++ b/Marlin/src/HAL/DUE/fastio/G2_PWM.h @@ -49,7 +49,6 @@ extern volatile uint32_t *SODR_A, *SODR_B, *CODR_A, *CODR_B; #define PWM_MAP_INIT_ROW(IO,ZZ) { ZZ == 'A' ? SODR_A : SODR_B, ZZ == 'A' ? CODR_A : CODR_B, 1 << _PIN(IO) } - #define PWM_MAP_INIT { PWM_MAP_INIT_ROW(MOTOR_CURRENT_PWM_X_PIN, 'B'), \ PWM_MAP_INIT_ROW(MOTOR_CURRENT_PWM_Y_PIN, 'B'), \ PWM_MAP_INIT_ROW(MOTOR_CURRENT_PWM_Z_PIN, 'B'), \ @@ -63,7 +62,7 @@ extern PWM_map ISR_table[NUM_PWMS]; extern uint32_t motor_current_setting[3]; #define IR_BIT(p) (WITHIN(p, 0, 3) ? (p) : (p) + 4) -#define COPY_ACTIVE_TABLE() do{ LOOP_L_N(i, 6) work_table[i] = active_table[i]; }while(0) +#define COPY_ACTIVE_TABLE() do{ for (uint8_t i = 0; i < 6; ++i) work_table[i] = active_table[i]; }while(0) #define PWM_MR0 19999 // base repetition rate minus one count - 20mS #define PWM_PR 24 // prescaler value - prescaler divide by 24 + 1 - 1 MHz output diff --git a/Marlin/src/HAL/DUE/fastio/G2_pins.h b/Marlin/src/HAL/DUE/fastio/G2_pins.h index 80c87bd3..38fcc5e5 100644 --- a/Marlin/src/HAL/DUE/fastio/G2_pins.h +++ b/Marlin/src/HAL/DUE/fastio/G2_pins.h @@ -168,7 +168,6 @@ const G2_PinDescription G2_g_APinDescription[] = { { PIOB, PIO_PB21, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 52 { PIOB, PIO_PB14, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 53 - // 54 .. 65 - Analog pins // ---------------------- { PIOA, PIO_PA16X1_AD7, ID_PIOA, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC0, ADC7, NOT_ON_PWM, NOT_ON_TIMER }, // AD0 diff --git a/Marlin/src/HAL/DUE/inc/Conditionals_LCD.h b/Marlin/src/HAL/DUE/inc/Conditionals_LCD.h index 58674144..5f1c4b16 100644 --- a/Marlin/src/HAL/DUE/inc/Conditionals_LCD.h +++ b/Marlin/src/HAL/DUE/inc/Conditionals_LCD.h @@ -20,7 +20,3 @@ * */ #pragma once - -#if HAS_SPI_TFT || HAS_FSMC_TFT - #error "Sorry! TFT displays are not available for HAL/DUE." -#endif diff --git a/Marlin/src/HAL/DUE/inc/Conditionals_post.h b/Marlin/src/HAL/DUE/inc/Conditionals_post.h index ce6d3fdd..295596b7 100644 --- a/Marlin/src/HAL/DUE/inc/Conditionals_post.h +++ b/Marlin/src/HAL/DUE/inc/Conditionals_post.h @@ -23,6 +23,6 @@ #if USE_FALLBACK_EEPROM #define FLASH_EEPROM_EMULATION -#elif EITHER(I2C_EEPROM, SPI_EEPROM) +#elif ANY(I2C_EEPROM, SPI_EEPROM) #define USE_SHARED_EEPROM 1 #endif diff --git a/Marlin/src/HAL/DUE/inc/SanityCheck.h b/Marlin/src/HAL/DUE/inc/SanityCheck.h index 87b09cf2..4d0a3f4a 100644 --- a/Marlin/src/HAL/DUE/inc/SanityCheck.h +++ b/Marlin/src/HAL/DUE/inc/SanityCheck.h @@ -25,6 +25,34 @@ * Test Arduino Due specific configuration values for errors at compile-time. */ +#if HAS_SPI_TFT || HAS_FSMC_TFT + #error "Sorry! TFT displays are not available for HAL/DUE." +#endif + +/** + * Check for common serial pin conflicts + */ +#define CHECK_SERIAL_PIN(N) ( \ + X_STOP_PIN == N || Y_STOP_PIN == N || Z_STOP_PIN == N \ + || X_MIN_PIN == N || Y_MIN_PIN == N || Z_MIN_PIN == N \ + || X_MAX_PIN == N || Y_MAX_PIN == N || Z_MAX_PIN == N \ + || X_STEP_PIN == N || Y_STEP_PIN == N || Z_STEP_PIN == N \ + || X_DIR_PIN == N || Y_DIR_PIN == N || Z_DIR_PIN == N \ + || X_ENA_PIN == N || Y_ENA_PIN == N || Z_ENA_PIN == N \ +) +#if SERIAL_IN_USE(0) // D0-D1. No known conflicts. +#endif +#if SERIAL_IN_USE(1) && (CHECK_SERIAL_PIN(18) || CHECK_SERIAL_PIN(19)) + #error "Serial Port 1 pin D18 and/or D19 conflicts with another pin on the board." +#endif +#if SERIAL_IN_USE(2) && (CHECK_SERIAL_PIN(16) || CHECK_SERIAL_PIN(17)) + #error "Serial Port 2 pin D16 and/or D17 conflicts with another pin on the board." +#endif +#if SERIAL_IN_USE(3) && (CHECK_SERIAL_PIN(14) || CHECK_SERIAL_PIN(15)) + #error "Serial Port 3 pin D14 and/or D15 conflicts with another pin on the board." +#endif +#undef CHECK_SERIAL_PIN + /** * HARDWARE VS. SOFTWARE SPI COMPATIBILITY * @@ -40,22 +68,25 @@ * Usually the hardware SPI pins are only available to the LCD. This makes the DUE hard SPI used at the same time * as the TMC2130 soft SPI the most common setup. */ -#define _IS_HW_SPI(P) (defined(TMC_SW_##P) && (TMC_SW_##P == SD_MOSI_PIN || TMC_SW_##P == SD_MISO_PIN || TMC_SW_##P == SD_SCK_PIN)) - -#if ENABLED(SDSUPPORT) && HAS_DRIVER(TMC2130) - #if ENABLED(TMC_USE_SW_SPI) - #if DISABLED(DUE_SOFTWARE_SPI) && (_IS_HW_SPI(MOSI) || _IS_HW_SPI(MISO) || _IS_HW_SPI(SCK)) - #error "DUE hardware SPI is required but is incompatible with TMC2130 software SPI. Either disable TMC_USE_SW_SPI or use separate pins for the two SPIs." - #endif - #elif ENABLED(DUE_SOFTWARE_SPI) +#if HAS_MEDIA && HAS_DRIVER(TMC2130) + #define _IS_HW_SPI(P) (defined(TMC_SPI_##P) && (TMC_SPI_##P == SD_MOSI_PIN || TMC_SPI_##P == SD_MISO_PIN || TMC_SPI_##P == SD_SCK_PIN)) + #if DISABLED(DUE_SOFTWARE_SPI) && ENABLED(TMC_USE_SW_SPI) && (_IS_HW_SPI(MOSI) || _IS_HW_SPI(MISO) || _IS_HW_SPI(SCK)) + #error "DUE hardware SPI is required but is incompatible with TMC2130 software SPI. Either disable TMC_USE_SW_SPI or use separate pins for the two SPIs." + #endif + #if ENABLED(DUE_SOFTWARE_SPI) && DISABLED(TMC_USE_SW_SPI) #error "DUE software SPI is required but is incompatible with TMC2130 hardware SPI. Enable TMC_USE_SW_SPI to fix." #endif + #undef _IS_HW_SPI #endif #if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY - #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported on DUE." + #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported for HAL/DUE." #endif #if HAS_TMC_SW_SERIAL #error "TMC220x Software Serial is not supported on the DUE platform." #endif + +#if USING_PULLDOWNS + #error "PULLDOWN pin mode is not available on DUE boards." +#endif diff --git a/Marlin/src/HAL/DUE/pinsDebug.h b/Marlin/src/HAL/DUE/pinsDebug.h index f01c53c8..e9e364dc 100644 --- a/Marlin/src/HAL/DUE/pinsDebug.h +++ b/Marlin/src/HAL/DUE/pinsDebug.h @@ -19,13 +19,26 @@ * along with this program. If not, see . * */ +#pragma once /** - * Support routines for Due - */ - -/** - * Translation of routines & variables used by pinsDebug.h + * Pins Debugging for DUE + * + * - NUMBER_PINS_TOTAL + * - MULTI_NAME_PAD + * - getPinByIndex(index) + * - printPinNameByIndex(index) + * - getPinIsDigitalByIndex(index) + * - digitalPinToAnalogIndex(pin) + * - getValidPinMode(pin) + * - isValidPin(pin) + * - isAnalogPin(pin) + * - digitalRead_mod(pin) + * - pwm_status(pin) + * - printPinPWM(pin) + * - printPinPort(pin) + * - printPinNumber(pin) + * - printPinAnalog(pin) */ #include "../shared/Marduino.h" @@ -53,7 +66,7 @@ * The net result is that both the g_pinStatus[pin] array and the PIO_OSR register * needs to be looked at when determining if a pin is an input or an output. * - * b) Due has only pins 6, 7, 8 & 9 enabled for PWMs. FYI - they run at 1KHz + * b) Due has only pins 6, 7, 8 & 9 enabled for PWMs. FYI - they run at 1kHz * * c) NUM_DIGITAL_PINS does not include the analog pins * @@ -63,21 +76,20 @@ #define NUMBER_PINS_TOTAL PINS_COUNT -#define digitalRead_mod(p) extDigitalRead(p) // AVR digitalRead disabled PWM before it read the pin -#define PRINT_PORT(p) -#define PRINT_ARRAY_NAME(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) -#define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%02d"), p); SERIAL_ECHO(buffer); }while(0) -#define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0) -#define GET_ARRAY_PIN(p) pin_array[p].pin -#define GET_ARRAY_IS_DIGITAL(p) pin_array[p].is_digital -#define VALID_PIN(pin) (pin >= 0 && pin < (int8_t)NUMBER_PINS_TOTAL ? 1 : 0) -#define DIGITAL_PIN_TO_ANALOG_PIN(p) int(p - analogInputToDigitalPin(0)) -#define IS_ANALOG(P) WITHIN(P, char(analogInputToDigitalPin(0)), char(analogInputToDigitalPin(NUM_ANALOG_INPUTS - 1))) -#define pwm_status(pin) (((g_pinStatus[pin] & 0xF) == PIN_STATUS_PWM) && \ - ((g_APinDescription[pin].ulPinAttribute & PIN_ATTR_PWM) == PIN_ATTR_PWM)) +#define digitalRead_mod(P) extDigitalRead(P) // AVR digitalRead disabled PWM before it read the pin +#define printPinNameByIndex(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) +#define printPinNumber(P) do{ sprintf_P(buffer, PSTR("%02d"), P); SERIAL_ECHO(buffer); }while(0) +#define printPinAnalog(P) do{ sprintf_P(buffer, PSTR(" (A%2d) "), digitalPinToAnalogIndex(P)); SERIAL_ECHO(buffer); }while(0) +#define getPinByIndex(x) pin_array[x].pin +#define getPinIsDigitalByIndex(x) pin_array[x].is_digital +#define isValidPin(P) (P >= 0 && P < pin_t(NUMBER_PINS_TOTAL)) +#define digitalPinToAnalogIndex(P) int(P - analogInputToDigitalPin(0)) +#define isAnalogPin(P) WITHIN(P, pin_t(analogInputToDigitalPin(0)), pin_t(analogInputToDigitalPin(NUM_ANALOG_INPUTS - 1))) +#define pwm_status(P) (((g_pinStatus[P] & 0xF) == PIN_STATUS_PWM) && \ + ((g_APinDescription[P].ulPinAttribute & PIN_ATTR_PWM) == PIN_ATTR_PWM)) #define MULTI_NAME_PAD 14 // space needed to be pretty if not first name assigned to a pin -bool GET_PINMODE(int8_t pin) { // 1: output, 0: input +bool getValidPinMode(const pin_t pin) { // 1: output, 0: input volatile Pio* port = g_APinDescription[pin].pPort; uint32_t mask = g_APinDescription[pin].ulPin; uint8_t pin_status = g_pinStatus[pin] & 0xF; @@ -86,14 +98,15 @@ bool GET_PINMODE(int8_t pin) { // 1: output, 0: input || pwm_status(pin)); } - -void pwm_details(int32_t pin) { +void printPinPWM(const int32_t pin) { if (pwm_status(pin)) { uint32_t chan = g_APinDescription[pin].ulPWMChannel; SERIAL_ECHOPGM("PWM = ", PWM_INTERFACE->PWM_CH_NUM[chan].PWM_CDTY); } } +void printPinPort(const pin_t) {} + /** * DUE Board pin | PORT | Label * ----------------+--------+------- diff --git a/Marlin/src/HAL/DUE/spi_pins.h b/Marlin/src/HAL/DUE/spi_pins.h index cec22c2c..efb93bc6 100644 --- a/Marlin/src/HAL/DUE/spi_pins.h +++ b/Marlin/src/HAL/DUE/spi_pins.h @@ -24,7 +24,7 @@ /** * Define SPI Pins: SCK, MISO, MOSI, SS * - * Available chip select pins for HW SPI are 4 10 52 77 + * Available chip select pins for HW SPI are 4 10 52 77 87 */ #if SDSS == 4 || SDSS == 10 || SDSS == 52 || SDSS == 77 || SDSS == 87 #if SDSS == 4 diff --git a/Marlin/src/HAL/DUE/timers.cpp b/Marlin/src/HAL/DUE/timers.cpp index a7bf7fbd..e388255c 100644 --- a/Marlin/src/HAL/DUE/timers.cpp +++ b/Marlin/src/HAL/DUE/timers.cpp @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -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); diff --git a/Marlin/src/HAL/DUE/timers.h b/Marlin/src/HAL/DUE/timers.h index e2932ff3..db5d83a0 100644 --- a/Marlin/src/HAL/DUE/timers.h +++ b/Marlin/src/HAL/DUE/timers.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,7 +36,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 @@ -125,4 +127,4 @@ FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) { pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_SR; } -#define HAL_timer_isr_epilogue(T) +#define HAL_timer_isr_epilogue(T) NOOP diff --git a/Marlin/src/HAL/DUE/upload_extra_script.py b/Marlin/src/HAL/DUE/upload_extra_script.py index 4f7a4945..729b1d67 100644 --- a/Marlin/src/HAL/DUE/upload_extra_script.py +++ b/Marlin/src/HAL/DUE/upload_extra_script.py @@ -6,14 +6,14 @@ # import pioutil if pioutil.is_pio_build(): - import platform - current_OS = platform.system() + import platform + current_OS = platform.system() - if current_OS == 'Windows': + if current_OS == 'Windows': - Import("env") + env = pioutil.env - # Use bossac.exe on Windows - env.Replace( - UPLOADCMD="bossac --info --unlock --write --verify --reset --erase -U false --boot $SOURCE" - ) + # Use bossac.exe on Windows + env.Replace( + UPLOADCMD="bossac --info --unlock --write --verify --reset --erase -U false --boot $SOURCE" + ) diff --git a/Marlin/src/HAL/DUE/usb/README.md b/Marlin/src/HAL/DUE/usb/README.md new file mode 100644 index 00000000..2548135a --- /dev/null +++ b/Marlin/src/HAL/DUE/usb/README.md @@ -0,0 +1,29 @@ +# USB Files Source Documentation + +## Source + +We sourced the USB files in Marlin from the Atmel ASF (Advanced Software Framework). The framework provides a variety of examples which were utilized in this project. + +Atmel doesn't provide these files in a source repository but they can be extracted from ASF, which can be downloaded from Atmel. + +[Advanced Software Framework](https://www.microchip.com/en-us/tools-resources/develop/libraries/advanced-software-framework) + +## Modifications + +The files are mostly unmodified except for minor cosmetic changes but some more significant changes were needed. + +The changes that prompted the addition of this README file are listed below. Other changes may have been made prior to this. + +1. Modified `uotghs_device_due.c` to resolve race conditions that could leave interrupts asserted when freezing the peripheral clock, resulting in hangs and watchdog resets due to the ensuing interrupt storm. + +## Version Information + +We don't know the exact version of ASF used as the source. However, the copyright information in the files indicates they are from 2015. + +## Upgrade Considerations + +We looked at the ASF 3.52.0 files released in 2022 but saw no immediate benefits to justify an upgrade. It's important to note that the files in Marlin don't follow the same folder structure as the files in ASF, which complicates the process of comparing and applying updated files. + +When these files are updated it's important to carefully compare them to Marlin's versions so any improvements in the Marlin sources are brought forward. + +It would be best to make Marlin's directory structure align with ASF or at least document the source of each file to ease future updates. diff --git a/Marlin/src/HAL/DUE/usb/compiler.h b/Marlin/src/HAL/DUE/usb/compiler.h index f89e554c..27c554cd 100644 --- a/Marlin/src/HAL/DUE/usb/compiler.h +++ b/Marlin/src/HAL/DUE/usb/compiler.h @@ -142,7 +142,6 @@ */ #define COMPILER_PACK_RESET() COMPILER_PRAGMA(pack()) - /** * \brief Set aligned boundary. */ @@ -283,7 +282,6 @@ typedef double F64; //!< 64-bit floating-point number. typedef uint32_t iram_size_t; //! @} - /*! \name Status Types */ //! @{ @@ -291,7 +289,6 @@ typedef bool Status_bool_t; //!< Boolean status. typedef U8 Status_t; //!< 8-bit-coded status. //! @} - /*! \name Aliasing Aggregate Types */ //! @{ @@ -462,7 +459,6 @@ typedef struct #endif //! @} - #ifndef __ASSEMBLY__ // not for assembling. //! \name Optimization Control @@ -581,7 +577,6 @@ typedef struct //! @} - /*! \name Zero-Bit Counting * * Under GCC, __builtin_clz and __builtin_ctz behave like macros when @@ -692,7 +687,6 @@ typedef struct //! @} - /*! \name Bit Reversing */ //! @{ @@ -732,7 +726,6 @@ typedef struct //! @} - /*! \name Alignment */ //! @{ @@ -798,7 +791,6 @@ typedef struct */ #define Long_call(addr) ((*(void (*)(void))(addr))()) - /*! \name MCU Endianism Handling * ARM is MCU little endianism. */ @@ -868,7 +860,6 @@ typedef struct #define CPU_TO_BE32(x) swap32(x) //! @} - /*! \name Endianism Conversion * * The same considerations as for clz and ctz apply here but GCC's @@ -955,7 +946,6 @@ typedef struct //! @} - /*! \name Target Abstraction */ //! @{ @@ -997,7 +987,6 @@ typedef U8 Byte; //!< 8-bit unsigned integer. #endif // #ifndef __ASSEMBLY__ - #ifdef __ICCARM__ #define SHORTENUM __packed #elif defined(__GNUC__) @@ -1059,7 +1048,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; } } diff --git a/Marlin/src/HAL/DUE/usb/conf_access.h b/Marlin/src/HAL/DUE/usb/conf_access.h index f4016852..0ea5fe22 100644 --- a/Marlin/src/HAL/DUE/usb/conf_access.h +++ b/Marlin/src/HAL/DUE/usb/conf_access.h @@ -81,7 +81,6 @@ #define LUN_0_NAME "\"SD/MMC Card\"" //! @} - /*! \name Actions Associated with Memory Accesses * * Write here the action to associate with each memory access. @@ -112,5 +111,4 @@ #define GLOBAL_WR_PROTECT false //!< Management of a global write protection. //! @} - #endif // _CONF_ACCESS_H_ diff --git a/Marlin/src/HAL/DUE/usb/conf_clock.h b/Marlin/src/HAL/DUE/usb/conf_clock.h index 97e70e99..0c7815ee 100644 --- a/Marlin/src/HAL/DUE/usb/conf_clock.h +++ b/Marlin/src/HAL/DUE/usb/conf_clock.h @@ -96,5 +96,4 @@ // - UPLL frequency: 480MHz // - USB clock: 480 / 1 = 480MHz - #endif /* CONF_CLOCK_H_INCLUDED */ diff --git a/Marlin/src/HAL/DUE/usb/conf_usb.h b/Marlin/src/HAL/DUE/usb/conf_usb.h index 4de9e347..fb4ef342 100644 --- a/Marlin/src/HAL/DUE/usb/conf_usb.h +++ b/Marlin/src/HAL/DUE/usb/conf_usb.h @@ -88,7 +88,6 @@ #endif //@} - /** * USB Device Callbacks definitions (Optional) * @{ @@ -101,7 +100,7 @@ #define USB_DEVICE_SPECIFIC_REQUEST() usb_task_other_requests() //@} -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA /** * USB Device low level configuration * When only one interface is used, these configurations are defined by the class module. @@ -150,7 +149,6 @@ //@} - /** * USB Interface Configuration * @{ @@ -185,7 +183,7 @@ //! Enable id string of interface to add an extra USB string #define UDI_CDC_IAD_STRING_ID 4 -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA /** * USB CDC low level configuration * In standalone these configurations are defined by the CDC module. @@ -210,7 +208,6 @@ //@} //@} - /** * Configuration of MSC interface * @{ @@ -245,7 +242,6 @@ //@} - /** * Description of Composite Device * @{ diff --git a/Marlin/src/HAL/DUE/usb/ctrl_access.c b/Marlin/src/HAL/DUE/usb/ctrl_access.c index 99f97f62..b766ed12 100644 --- a/Marlin/src/HAL/DUE/usb/ctrl_access.c +++ b/Marlin/src/HAL/DUE/usb/ctrl_access.c @@ -68,7 +68,6 @@ #endif #include "ctrl_access.h" - //_____ D E F I N I T I O N S ______________________________________________ #ifdef FREERTOS_USED @@ -112,7 +111,6 @@ static xSemaphoreHandle ctrl_access_semphr = NULL; #endif // FREERTOS_USED - #if MAX_LUN /*! \brief Initializes an entry of the LUN descriptor table. @@ -242,17 +240,14 @@ static const struct #endif - #if GLOBAL_WR_PROTECT == true bool g_wr_protect; #endif - /*! \name Control Interface */ //! @{ - #ifdef FREERTOS_USED bool ctrl_access_init(void) @@ -270,7 +265,6 @@ bool ctrl_access_init(void) return true; } - /*! \brief Locks accesses to LUNs. * * \return \c true if the access was successfully locked, else \c false. @@ -288,7 +282,6 @@ static bool ctrl_access_lock(void) #endif // FREERTOS_USED - U8 get_nb_lun(void) { #if MEM_USB == ENABLE @@ -309,13 +302,11 @@ U8 get_nb_lun(void) #endif } - U8 get_cur_lun(void) { return LUN_ID_0; } - Ctrl_status mem_test_unit_ready(U8 lun) { Ctrl_status status; @@ -337,7 +328,6 @@ Ctrl_status mem_test_unit_ready(U8 lun) return status; } - Ctrl_status mem_read_capacity(U8 lun, U32 *u32_nb_sector) { Ctrl_status status; @@ -359,7 +349,6 @@ Ctrl_status mem_read_capacity(U8 lun, U32 *u32_nb_sector) return status; } - U8 mem_sector_size(U8 lun) { U8 sector_size; @@ -381,7 +370,6 @@ U8 mem_sector_size(U8 lun) return sector_size; } - bool mem_unload(U8 lun, bool unload) { bool unloaded; @@ -433,7 +421,6 @@ bool mem_wr_protect(U8 lun) return wr_protect; } - bool mem_removal(U8 lun) { bool removal; @@ -458,7 +445,6 @@ bool mem_removal(U8 lun) return removal; } - const char *mem_name(U8 lun) { #if MAX_LUN==0 @@ -475,17 +461,14 @@ const char *mem_name(U8 lun) #endif } - //! @} - #if ACCESS_USB == true /*! \name MEM <-> USB Interface */ //! @{ - Ctrl_status memory_2_usb(U8 lun, U32 addr, U16 nb_sector) { Ctrl_status status; @@ -505,7 +488,6 @@ Ctrl_status memory_2_usb(U8 lun, U32 addr, U16 nb_sector) return status; } - Ctrl_status usb_2_memory(U8 lun, U32 addr, U16 nb_sector) { Ctrl_status status; @@ -525,19 +507,16 @@ Ctrl_status usb_2_memory(U8 lun, U32 addr, U16 nb_sector) return status; } - //! @} #endif // ACCESS_USB == true - #if ACCESS_MEM_TO_RAM == true /*! \name MEM <-> RAM Interface */ //! @{ - Ctrl_status memory_2_ram(U8 lun, U32 addr, void *ram) { Ctrl_status status; @@ -564,7 +543,6 @@ Ctrl_status memory_2_ram(U8 lun, U32 addr, void *ram) return status; } - Ctrl_status ram_2_memory(U8 lun, U32 addr, const void *ram) { Ctrl_status status; @@ -591,19 +569,16 @@ Ctrl_status ram_2_memory(U8 lun, U32 addr, const void *ram) return status; } - //! @} #endif // ACCESS_MEM_TO_RAM == true - #if ACCESS_STREAM == true /*! \name Streaming MEM <-> MEM Interface */ //! @{ - #if ACCESS_MEM_TO_MEM == true #include "fat.h" @@ -625,21 +600,18 @@ Ctrl_status stream_mem_to_mem(U8 src_lun, U32 src_addr, U8 dest_lun, U32 dest_ad #endif // ACCESS_MEM_TO_MEM == true - Ctrl_status stream_state(U8 id) { UNUSED(id); return CTRL_GOOD; } - U16 stream_stop(U8 id) { UNUSED(id); return 0; } - //! @} #endif // ACCESS_STREAM diff --git a/Marlin/src/HAL/DUE/usb/ctrl_access.h b/Marlin/src/HAL/DUE/usb/ctrl_access.h index b3383907..d9cb05da 100644 --- a/Marlin/src/HAL/DUE/usb/ctrl_access.h +++ b/Marlin/src/HAL/DUE/usb/ctrl_access.h @@ -56,7 +56,6 @@ * Support and FAQ: visit Atmel Support */ - #ifndef _CTRL_ACCESS_H_ #define _CTRL_ACCESS_H_ @@ -89,7 +88,6 @@ typedef enum CTRL_BUSY = FAIL + 2 //!< Memory not initialized or changed. } Ctrl_status; - // FYI: Each Logical Unit Number (LUN) corresponds to a memory. // Check LUN defines. @@ -136,7 +134,6 @@ typedef enum #define LUN_ID_USB (MAX_LUN) //!< First dynamic LUN (USB host mass storage). //! @} - // Include LUN header files. #if LUN_0 == ENABLE #include LUN_0_INCLUDE @@ -166,13 +163,11 @@ typedef enum #include LUN_USB_INCLUDE #endif - // Check the configuration of write protection in conf_access.h. #ifndef GLOBAL_WR_PROTECT #error GLOBAL_WR_PROTECT must be defined as true or false in conf_access.h #endif - #if GLOBAL_WR_PROTECT == true //! Write protect. @@ -180,7 +175,6 @@ extern bool g_wr_protect; #endif - /*! \name Control Interface */ //! @{ @@ -279,7 +273,6 @@ extern const char *mem_name(U8 lun); //! @} - #if ACCESS_USB == true /*! \name MEM <-> USB Interface @@ -310,7 +303,6 @@ extern Ctrl_status usb_2_memory(U8 lun, U32 addr, U16 nb_sector); #endif // ACCESS_USB == true - #if ACCESS_MEM_TO_RAM == true /*! \name MEM <-> RAM Interface @@ -341,7 +333,6 @@ extern Ctrl_status ram_2_memory(U8 lun, U32 addr, const void *ram); #endif // ACCESS_MEM_TO_RAM == true - #if ACCESS_STREAM == true /*! \name Streaming MEM <-> MEM Interface diff --git a/Marlin/src/HAL/DUE/usb/genclk.h b/Marlin/src/HAL/DUE/usb/genclk.h index cde03bc0..45eba587 100644 --- a/Marlin/src/HAL/DUE/usb/genclk.h +++ b/Marlin/src/HAL/DUE/usb/genclk.h @@ -74,17 +74,17 @@ extern "C" { //@{ enum genclk_source { - GENCLK_PCK_SRC_SLCK_RC = 0, //!< Internal 32kHz RC oscillator as PCK source clock - GENCLK_PCK_SRC_SLCK_XTAL = 1, //!< External 32kHz crystal oscillator as PCK source clock - GENCLK_PCK_SRC_SLCK_BYPASS = 2, //!< External 32kHz bypass oscillator as PCK source clock - GENCLK_PCK_SRC_MAINCK_4M_RC = 3, //!< Internal 4MHz RC oscillator as PCK source clock - GENCLK_PCK_SRC_MAINCK_8M_RC = 4, //!< Internal 8MHz RC oscillator as PCK source clock - GENCLK_PCK_SRC_MAINCK_12M_RC = 5, //!< Internal 12MHz RC oscillator as PCK source clock - GENCLK_PCK_SRC_MAINCK_XTAL = 6, //!< External crystal oscillator as PCK source clock - GENCLK_PCK_SRC_MAINCK_BYPASS = 7, //!< External bypass oscillator as PCK source clock - GENCLK_PCK_SRC_PLLACK = 8, //!< Use PLLACK as PCK source clock - GENCLK_PCK_SRC_PLLBCK = 9, //!< Use PLLBCK as PCK source clock - GENCLK_PCK_SRC_MCK = 10, //!< Use Master Clk as PCK source clock + GENCLK_PCK_SRC_SLCK_RC = 0, //!< Internal 32kHz RC oscillator as PCK source clock + GENCLK_PCK_SRC_SLCK_XTAL = 1, //!< External 32kHz crystal oscillator as PCK source clock + GENCLK_PCK_SRC_SLCK_BYPASS = 2, //!< External 32kHz bypass oscillator as PCK source clock + GENCLK_PCK_SRC_MAINCK_4M_RC = 3, //!< Internal 4MHz RC oscillator as PCK source clock + GENCLK_PCK_SRC_MAINCK_8M_RC = 4, //!< Internal 8MHz RC oscillator as PCK source clock + GENCLK_PCK_SRC_MAINCK_12M_RC = 5, //!< Internal 12MHz RC oscillator as PCK source clock + GENCLK_PCK_SRC_MAINCK_XTAL = 6, //!< External crystal oscillator as PCK source clock + GENCLK_PCK_SRC_MAINCK_BYPASS = 7, //!< External bypass oscillator as PCK source clock + GENCLK_PCK_SRC_PLLACK = 8, //!< Use PLLACK as PCK source clock + GENCLK_PCK_SRC_PLLBCK = 9, //!< Use PLLBCK as PCK source clock + GENCLK_PCK_SRC_MCK = 10, //!< Use Master Clk as PCK source clock }; //@} @@ -93,176 +93,162 @@ enum genclk_source { //@{ enum genclk_divider { - GENCLK_PCK_PRES_1 = PMC_PCK_PRES_CLK_1, //!< Set PCK clock prescaler to 1 - GENCLK_PCK_PRES_2 = PMC_PCK_PRES_CLK_2, //!< Set PCK clock prescaler to 2 - GENCLK_PCK_PRES_4 = PMC_PCK_PRES_CLK_4, //!< Set PCK clock prescaler to 4 - GENCLK_PCK_PRES_8 = PMC_PCK_PRES_CLK_8, //!< Set PCK clock prescaler to 8 - GENCLK_PCK_PRES_16 = PMC_PCK_PRES_CLK_16, //!< Set PCK clock prescaler to 16 - GENCLK_PCK_PRES_32 = PMC_PCK_PRES_CLK_32, //!< Set PCK clock prescaler to 32 - GENCLK_PCK_PRES_64 = PMC_PCK_PRES_CLK_64, //!< Set PCK clock prescaler to 64 + GENCLK_PCK_PRES_1 = PMC_PCK_PRES_CLK_1, //!< Set PCK clock prescaler to 1 + GENCLK_PCK_PRES_2 = PMC_PCK_PRES_CLK_2, //!< Set PCK clock prescaler to 2 + GENCLK_PCK_PRES_4 = PMC_PCK_PRES_CLK_4, //!< Set PCK clock prescaler to 4 + GENCLK_PCK_PRES_8 = PMC_PCK_PRES_CLK_8, //!< Set PCK clock prescaler to 8 + GENCLK_PCK_PRES_16 = PMC_PCK_PRES_CLK_16, //!< Set PCK clock prescaler to 16 + GENCLK_PCK_PRES_32 = PMC_PCK_PRES_CLK_32, //!< Set PCK clock prescaler to 32 + GENCLK_PCK_PRES_64 = PMC_PCK_PRES_CLK_64, //!< Set PCK clock prescaler to 64 }; //@} struct genclk_config { - uint32_t ctrl; + uint32_t ctrl; }; -static inline void genclk_config_defaults(struct genclk_config *p_cfg, - uint32_t ul_id) -{ - ul_id = ul_id; - p_cfg->ctrl = 0; +static inline void genclk_config_defaults(struct genclk_config *p_cfg, uint32_t ul_id) { + ul_id = ul_id; + p_cfg->ctrl = 0; } -static inline void genclk_config_read(struct genclk_config *p_cfg, - uint32_t ul_id) -{ - p_cfg->ctrl = PMC->PMC_PCK[ul_id]; +static inline void genclk_config_read(struct genclk_config *p_cfg, uint32_t ul_id) { + p_cfg->ctrl = PMC->PMC_PCK[ul_id]; } -static inline void genclk_config_write(const struct genclk_config *p_cfg, - uint32_t ul_id) -{ - PMC->PMC_PCK[ul_id] = p_cfg->ctrl; +static inline void genclk_config_write(const struct genclk_config *p_cfg, uint32_t ul_id) { + PMC->PMC_PCK[ul_id] = p_cfg->ctrl; } //! \name Programmable Clock Source and Prescaler configuration //@{ -static inline void genclk_config_set_source(struct genclk_config *p_cfg, - enum genclk_source e_src) -{ - p_cfg->ctrl &= (~PMC_PCK_CSS_Msk); - - switch (e_src) { - case GENCLK_PCK_SRC_SLCK_RC: - case GENCLK_PCK_SRC_SLCK_XTAL: - case GENCLK_PCK_SRC_SLCK_BYPASS: - p_cfg->ctrl |= (PMC_PCK_CSS_SLOW_CLK); - break; - - case GENCLK_PCK_SRC_MAINCK_4M_RC: - case GENCLK_PCK_SRC_MAINCK_8M_RC: - case GENCLK_PCK_SRC_MAINCK_12M_RC: - case GENCLK_PCK_SRC_MAINCK_XTAL: - case GENCLK_PCK_SRC_MAINCK_BYPASS: - p_cfg->ctrl |= (PMC_PCK_CSS_MAIN_CLK); - break; - - case GENCLK_PCK_SRC_PLLACK: - p_cfg->ctrl |= (PMC_PCK_CSS_PLLA_CLK); - break; - - case GENCLK_PCK_SRC_PLLBCK: - p_cfg->ctrl |= (PMC_PCK_CSS_UPLL_CLK); - break; - - case GENCLK_PCK_SRC_MCK: - p_cfg->ctrl |= (PMC_PCK_CSS_MCK); - break; - } +static inline void genclk_config_set_source(struct genclk_config *p_cfg, enum genclk_source e_src) { + p_cfg->ctrl &= (~PMC_PCK_CSS_Msk); + + switch (e_src) { + case GENCLK_PCK_SRC_SLCK_RC: + case GENCLK_PCK_SRC_SLCK_XTAL: + case GENCLK_PCK_SRC_SLCK_BYPASS: + p_cfg->ctrl |= (PMC_PCK_CSS_SLOW_CLK); + break; + + case GENCLK_PCK_SRC_MAINCK_4M_RC: + case GENCLK_PCK_SRC_MAINCK_8M_RC: + case GENCLK_PCK_SRC_MAINCK_12M_RC: + case GENCLK_PCK_SRC_MAINCK_XTAL: + case GENCLK_PCK_SRC_MAINCK_BYPASS: + p_cfg->ctrl |= (PMC_PCK_CSS_MAIN_CLK); + break; + + case GENCLK_PCK_SRC_PLLACK: + p_cfg->ctrl |= (PMC_PCK_CSS_PLLA_CLK); + break; + + case GENCLK_PCK_SRC_PLLBCK: + p_cfg->ctrl |= (PMC_PCK_CSS_UPLL_CLK); + break; + + case GENCLK_PCK_SRC_MCK: + p_cfg->ctrl |= (PMC_PCK_CSS_MCK); + break; + } } -static inline void genclk_config_set_divider(struct genclk_config *p_cfg, - uint32_t e_divider) -{ - p_cfg->ctrl &= ~PMC_PCK_PRES_Msk; - p_cfg->ctrl |= e_divider; +static inline void genclk_config_set_divider(struct genclk_config *p_cfg, uint32_t e_divider) { + p_cfg->ctrl &= ~PMC_PCK_PRES_Msk; + p_cfg->ctrl |= e_divider; } //@} -static inline void genclk_enable(const struct genclk_config *p_cfg, - uint32_t ul_id) -{ - PMC->PMC_PCK[ul_id] = p_cfg->ctrl; - pmc_enable_pck(ul_id); +static inline void genclk_enable(const struct genclk_config *p_cfg, uint32_t ul_id) { + PMC->PMC_PCK[ul_id] = p_cfg->ctrl; + pmc_enable_pck(ul_id); } -static inline void genclk_disable(uint32_t ul_id) -{ - pmc_disable_pck(ul_id); +static inline void genclk_disable(uint32_t ul_id) { + pmc_disable_pck(ul_id); } -static inline void genclk_enable_source(enum genclk_source e_src) -{ - switch (e_src) { - case GENCLK_PCK_SRC_SLCK_RC: - if (!osc_is_ready(OSC_SLCK_32K_RC)) { - osc_enable(OSC_SLCK_32K_RC); - osc_wait_ready(OSC_SLCK_32K_RC); - } - break; - - case GENCLK_PCK_SRC_SLCK_XTAL: - if (!osc_is_ready(OSC_SLCK_32K_XTAL)) { - osc_enable(OSC_SLCK_32K_XTAL); - osc_wait_ready(OSC_SLCK_32K_XTAL); - } - break; - - case GENCLK_PCK_SRC_SLCK_BYPASS: - if (!osc_is_ready(OSC_SLCK_32K_BYPASS)) { - osc_enable(OSC_SLCK_32K_BYPASS); - osc_wait_ready(OSC_SLCK_32K_BYPASS); - } - break; - - case GENCLK_PCK_SRC_MAINCK_4M_RC: - if (!osc_is_ready(OSC_MAINCK_4M_RC)) { - osc_enable(OSC_MAINCK_4M_RC); - osc_wait_ready(OSC_MAINCK_4M_RC); - } - break; - - case GENCLK_PCK_SRC_MAINCK_8M_RC: - if (!osc_is_ready(OSC_MAINCK_8M_RC)) { - osc_enable(OSC_MAINCK_8M_RC); - osc_wait_ready(OSC_MAINCK_8M_RC); - } - break; - - case GENCLK_PCK_SRC_MAINCK_12M_RC: - if (!osc_is_ready(OSC_MAINCK_12M_RC)) { - osc_enable(OSC_MAINCK_12M_RC); - osc_wait_ready(OSC_MAINCK_12M_RC); - } - break; - - case GENCLK_PCK_SRC_MAINCK_XTAL: - if (!osc_is_ready(OSC_MAINCK_XTAL)) { - osc_enable(OSC_MAINCK_XTAL); - osc_wait_ready(OSC_MAINCK_XTAL); - } - break; - - case GENCLK_PCK_SRC_MAINCK_BYPASS: - if (!osc_is_ready(OSC_MAINCK_BYPASS)) { - osc_enable(OSC_MAINCK_BYPASS); - osc_wait_ready(OSC_MAINCK_BYPASS); - } - break; - -#ifdef CONFIG_PLL0_SOURCE - case GENCLK_PCK_SRC_PLLACK: - pll_enable_config_defaults(0); - break; -#endif - -#ifdef CONFIG_PLL1_SOURCE - case GENCLK_PCK_SRC_PLLBCK: - pll_enable_config_defaults(1); - break; -#endif - - case GENCLK_PCK_SRC_MCK: - break; - - default: - Assert(false); - break; - } +static inline void genclk_enable_source(enum genclk_source e_src) { + switch (e_src) { + case GENCLK_PCK_SRC_SLCK_RC: + if (!osc_is_ready(OSC_SLCK_32K_RC)) { + osc_enable(OSC_SLCK_32K_RC); + osc_wait_ready(OSC_SLCK_32K_RC); + } + break; + + case GENCLK_PCK_SRC_SLCK_XTAL: + if (!osc_is_ready(OSC_SLCK_32K_XTAL)) { + osc_enable(OSC_SLCK_32K_XTAL); + osc_wait_ready(OSC_SLCK_32K_XTAL); + } + break; + + case GENCLK_PCK_SRC_SLCK_BYPASS: + if (!osc_is_ready(OSC_SLCK_32K_BYPASS)) { + osc_enable(OSC_SLCK_32K_BYPASS); + osc_wait_ready(OSC_SLCK_32K_BYPASS); + } + break; + + case GENCLK_PCK_SRC_MAINCK_4M_RC: + if (!osc_is_ready(OSC_MAINCK_4M_RC)) { + osc_enable(OSC_MAINCK_4M_RC); + osc_wait_ready(OSC_MAINCK_4M_RC); + } + break; + + case GENCLK_PCK_SRC_MAINCK_8M_RC: + if (!osc_is_ready(OSC_MAINCK_8M_RC)) { + osc_enable(OSC_MAINCK_8M_RC); + osc_wait_ready(OSC_MAINCK_8M_RC); + } + break; + + case GENCLK_PCK_SRC_MAINCK_12M_RC: + if (!osc_is_ready(OSC_MAINCK_12M_RC)) { + osc_enable(OSC_MAINCK_12M_RC); + osc_wait_ready(OSC_MAINCK_12M_RC); + } + break; + + case GENCLK_PCK_SRC_MAINCK_XTAL: + if (!osc_is_ready(OSC_MAINCK_XTAL)) { + osc_enable(OSC_MAINCK_XTAL); + osc_wait_ready(OSC_MAINCK_XTAL); + } + break; + + case GENCLK_PCK_SRC_MAINCK_BYPASS: + if (!osc_is_ready(OSC_MAINCK_BYPASS)) { + osc_enable(OSC_MAINCK_BYPASS); + osc_wait_ready(OSC_MAINCK_BYPASS); + } + break; + + #ifdef CONFIG_PLL0_SOURCE + case GENCLK_PCK_SRC_PLLACK: + pll_enable_config_defaults(0); + break; + #endif + + #ifdef CONFIG_PLL1_SOURCE + case GENCLK_PCK_SRC_PLLBCK: + pll_enable_config_defaults(1); + break; + #endif + + case GENCLK_PCK_SRC_MCK: + break; + + default: + Assert(false); + break; + } } //! @} diff --git a/Marlin/src/HAL/DUE/usb/mrepeat.h b/Marlin/src/HAL/DUE/usb/mrepeat.h index 8363d9cd..10a82375 100644 --- a/Marlin/src/HAL/DUE/usb/mrepeat.h +++ b/Marlin/src/HAL/DUE/usb/mrepeat.h @@ -57,7 +57,6 @@ #include "preprocessor.h" - //! Maximal number of repetitions supported by MREPEAT. #define MREPEAT_LIMIT 256 diff --git a/Marlin/src/HAL/DUE/usb/osc.h b/Marlin/src/HAL/DUE/usb/osc.h index 953bcbbe..1585018e 100644 --- a/Marlin/src/HAL/DUE/usb/osc.h +++ b/Marlin/src/HAL/DUE/usb/osc.h @@ -62,28 +62,28 @@ extern "C" { * should be defined by the board code, otherwise default value are used. */ #ifndef BOARD_FREQ_SLCK_XTAL -# warning The board slow clock xtal frequency has not been defined. -# define BOARD_FREQ_SLCK_XTAL (32768UL) + #warning The board slow clock xtal frequency has not been defined. + #define BOARD_FREQ_SLCK_XTAL (32768UL) #endif #ifndef BOARD_FREQ_SLCK_BYPASS -# warning The board slow clock bypass frequency has not been defined. -# define BOARD_FREQ_SLCK_BYPASS (32768UL) + #warning The board slow clock bypass frequency has not been defined. + #define BOARD_FREQ_SLCK_BYPASS (32768UL) #endif #ifndef BOARD_FREQ_MAINCK_XTAL -# warning The board main clock xtal frequency has not been defined. -# define BOARD_FREQ_MAINCK_XTAL (12000000UL) + #warning The board main clock xtal frequency has not been defined. + #define BOARD_FREQ_MAINCK_XTAL (12000000UL) #endif #ifndef BOARD_FREQ_MAINCK_BYPASS -# warning The board main clock bypass frequency has not been defined. -# define BOARD_FREQ_MAINCK_BYPASS (12000000UL) + #warning The board main clock bypass frequency has not been defined. + #define BOARD_FREQ_MAINCK_BYPASS (12000000UL) #endif #ifndef BOARD_OSC_STARTUP_US -# warning The board main clock xtal startup time has not been defined. -# define BOARD_OSC_STARTUP_US (15625UL) + #warning The board main clock xtal startup time has not been defined. + #define BOARD_OSC_STARTUP_US (15625UL) #endif /** @@ -115,122 +115,116 @@ extern "C" { #define OSC_MAINCK_BYPASS_HZ BOARD_FREQ_MAINCK_BYPASS //!< External bypass oscillator. //@} -static inline void osc_enable(uint32_t ul_id) -{ - switch (ul_id) { - case OSC_SLCK_32K_RC: - break; - - case OSC_SLCK_32K_XTAL: - pmc_switch_sclk_to_32kxtal(PMC_OSC_XTAL); - break; - - case OSC_SLCK_32K_BYPASS: - pmc_switch_sclk_to_32kxtal(PMC_OSC_BYPASS); - break; - - - case OSC_MAINCK_4M_RC: - pmc_switch_mainck_to_fastrc(CKGR_MOR_MOSCRCF_4_MHz); - break; - - case OSC_MAINCK_8M_RC: - pmc_switch_mainck_to_fastrc(CKGR_MOR_MOSCRCF_8_MHz); - break; +static inline void osc_enable(uint32_t ul_id) { + switch (ul_id) { + case OSC_SLCK_32K_RC: + break; + + case OSC_SLCK_32K_XTAL: + pmc_switch_sclk_to_32kxtal(PMC_OSC_XTAL); + break; + + case OSC_SLCK_32K_BYPASS: + pmc_switch_sclk_to_32kxtal(PMC_OSC_BYPASS); + break; + + case OSC_MAINCK_4M_RC: + pmc_switch_mainck_to_fastrc(CKGR_MOR_MOSCRCF_4_MHz); + break; + + case OSC_MAINCK_8M_RC: + pmc_switch_mainck_to_fastrc(CKGR_MOR_MOSCRCF_8_MHz); + break; + + case OSC_MAINCK_12M_RC: + pmc_switch_mainck_to_fastrc(CKGR_MOR_MOSCRCF_12_MHz); + break; + + case OSC_MAINCK_XTAL: + pmc_switch_mainck_to_xtal(PMC_OSC_XTAL/*, + pmc_us_to_moscxtst(BOARD_OSC_STARTUP_US, + OSC_SLCK_32K_RC_HZ)*/); + break; + + case OSC_MAINCK_BYPASS: + pmc_switch_mainck_to_xtal(PMC_OSC_BYPASS/*, + pmc_us_to_moscxtst(BOARD_OSC_STARTUP_US, + OSC_SLCK_32K_RC_HZ)*/); + break; + } +} - case OSC_MAINCK_12M_RC: - pmc_switch_mainck_to_fastrc(CKGR_MOR_MOSCRCF_12_MHz); - break; +static inline void osc_disable(uint32_t ul_id) { + switch (ul_id) { + case OSC_SLCK_32K_RC: + case OSC_SLCK_32K_XTAL: + case OSC_SLCK_32K_BYPASS: + break; + + case OSC_MAINCK_4M_RC: + case OSC_MAINCK_8M_RC: + case OSC_MAINCK_12M_RC: + pmc_osc_disable_fastrc(); + break; + + case OSC_MAINCK_XTAL: + pmc_osc_disable_xtal(PMC_OSC_XTAL); + break; + + case OSC_MAINCK_BYPASS: + pmc_osc_disable_xtal(PMC_OSC_BYPASS); + break; + } +} +static inline bool osc_is_ready(uint32_t ul_id) { + switch (ul_id) { + case OSC_SLCK_32K_RC: + return 1; - case OSC_MAINCK_XTAL: - pmc_switch_mainck_to_xtal(PMC_OSC_XTAL/*, - pmc_us_to_moscxtst(BOARD_OSC_STARTUP_US, - OSC_SLCK_32K_RC_HZ)*/); - break; + case OSC_SLCK_32K_XTAL: + case OSC_SLCK_32K_BYPASS: + return pmc_osc_is_ready_32kxtal(); - case OSC_MAINCK_BYPASS: - pmc_switch_mainck_to_xtal(PMC_OSC_BYPASS/*, - pmc_us_to_moscxtst(BOARD_OSC_STARTUP_US, - OSC_SLCK_32K_RC_HZ)*/); - break; - } -} - -static inline void osc_disable(uint32_t ul_id) -{ - switch (ul_id) { - case OSC_SLCK_32K_RC: - case OSC_SLCK_32K_XTAL: - case OSC_SLCK_32K_BYPASS: - break; - - case OSC_MAINCK_4M_RC: - case OSC_MAINCK_8M_RC: - case OSC_MAINCK_12M_RC: - pmc_osc_disable_fastrc(); - break; - - case OSC_MAINCK_XTAL: - pmc_osc_disable_xtal(PMC_OSC_XTAL); - break; - - case OSC_MAINCK_BYPASS: - pmc_osc_disable_xtal(PMC_OSC_BYPASS); - break; - } -} + case OSC_MAINCK_4M_RC: + case OSC_MAINCK_8M_RC: + case OSC_MAINCK_12M_RC: + case OSC_MAINCK_XTAL: + case OSC_MAINCK_BYPASS: + return pmc_osc_is_ready_mainck(); + } -static inline bool osc_is_ready(uint32_t ul_id) -{ - switch (ul_id) { - case OSC_SLCK_32K_RC: - return 1; - - case OSC_SLCK_32K_XTAL: - case OSC_SLCK_32K_BYPASS: - return pmc_osc_is_ready_32kxtal(); - - case OSC_MAINCK_4M_RC: - case OSC_MAINCK_8M_RC: - case OSC_MAINCK_12M_RC: - case OSC_MAINCK_XTAL: - case OSC_MAINCK_BYPASS: - return pmc_osc_is_ready_mainck(); - } - - return 0; + return 0; } -static inline uint32_t osc_get_rate(uint32_t ul_id) -{ - switch (ul_id) { - case OSC_SLCK_32K_RC: - return OSC_SLCK_32K_RC_HZ; +static inline uint32_t osc_get_rate(uint32_t ul_id) { + switch (ul_id) { + case OSC_SLCK_32K_RC: + return OSC_SLCK_32K_RC_HZ; - case OSC_SLCK_32K_XTAL: - return BOARD_FREQ_SLCK_XTAL; + case OSC_SLCK_32K_XTAL: + return BOARD_FREQ_SLCK_XTAL; - case OSC_SLCK_32K_BYPASS: - return BOARD_FREQ_SLCK_BYPASS; + case OSC_SLCK_32K_BYPASS: + return BOARD_FREQ_SLCK_BYPASS; - case OSC_MAINCK_4M_RC: - return OSC_MAINCK_4M_RC_HZ; + case OSC_MAINCK_4M_RC: + return OSC_MAINCK_4M_RC_HZ; - case OSC_MAINCK_8M_RC: - return OSC_MAINCK_8M_RC_HZ; + case OSC_MAINCK_8M_RC: + return OSC_MAINCK_8M_RC_HZ; - case OSC_MAINCK_12M_RC: - return OSC_MAINCK_12M_RC_HZ; + case OSC_MAINCK_12M_RC: + return OSC_MAINCK_12M_RC_HZ; - case OSC_MAINCK_XTAL: - return BOARD_FREQ_MAINCK_XTAL; + case OSC_MAINCK_XTAL: + return BOARD_FREQ_MAINCK_XTAL; - case OSC_MAINCK_BYPASS: - return BOARD_FREQ_MAINCK_BYPASS; - } + case OSC_MAINCK_BYPASS: + return BOARD_FREQ_MAINCK_BYPASS; + } - return 0; + return 0; } /** @@ -241,11 +235,10 @@ static inline uint32_t osc_get_rate(uint32_t ul_id) * * \param id A number identifying the oscillator to wait for. */ -static inline void osc_wait_ready(uint8_t id) -{ - while (!osc_is_ready(id)) { - /* Do nothing */ - } +static inline void osc_wait_ready(uint8_t id) { + while (!osc_is_ready(id)) { + /* Do nothing */ + } } //! @} diff --git a/Marlin/src/HAL/DUE/usb/pll.h b/Marlin/src/HAL/DUE/usb/pll.h index 8eaf2767..d25a1f65 100644 --- a/Marlin/src/HAL/DUE/usb/pll.h +++ b/Marlin/src/HAL/DUE/usb/pll.h @@ -77,22 +77,22 @@ extern "C" { #define PLL_COUNT 0x3FU enum pll_source { - PLL_SRC_MAINCK_4M_RC = OSC_MAINCK_4M_RC, //!< Internal 4MHz RC oscillator. - PLL_SRC_MAINCK_8M_RC = OSC_MAINCK_8M_RC, //!< Internal 8MHz RC oscillator. - PLL_SRC_MAINCK_12M_RC = OSC_MAINCK_12M_RC, //!< Internal 12MHz RC oscillator. - PLL_SRC_MAINCK_XTAL = OSC_MAINCK_XTAL, //!< External crystal oscillator. - PLL_SRC_MAINCK_BYPASS = OSC_MAINCK_BYPASS, //!< External bypass oscillator. - PLL_NR_SOURCES, //!< Number of PLL sources. + PLL_SRC_MAINCK_4M_RC = OSC_MAINCK_4M_RC, //!< Internal 4MHz RC oscillator. + PLL_SRC_MAINCK_8M_RC = OSC_MAINCK_8M_RC, //!< Internal 8MHz RC oscillator. + PLL_SRC_MAINCK_12M_RC = OSC_MAINCK_12M_RC, //!< Internal 12MHz RC oscillator. + PLL_SRC_MAINCK_XTAL = OSC_MAINCK_XTAL, //!< External crystal oscillator. + PLL_SRC_MAINCK_BYPASS = OSC_MAINCK_BYPASS, //!< External bypass oscillator. + PLL_NR_SOURCES, //!< Number of PLL sources. }; struct pll_config { - uint32_t ctrl; + uint32_t ctrl; }; #define pll_get_default_rate(pll_id) \ - ((osc_get_rate(CONFIG_PLL##pll_id##_SOURCE) \ - * CONFIG_PLL##pll_id##_MUL) \ - / CONFIG_PLL##pll_id##_DIV) + ((osc_get_rate(CONFIG_PLL##pll_id##_SOURCE) \ + * CONFIG_PLL##pll_id##_MUL) \ + / CONFIG_PLL##pll_id##_DIV) /* Force UTMI PLL parameters (Hardware defined) */ #ifdef CONFIG_PLL1_SOURCE @@ -113,145 +113,130 @@ struct pll_config { * is hidden in this implementation. Use mul as mul effective value. */ static inline void pll_config_init(struct pll_config *p_cfg, - enum pll_source e_src, uint32_t ul_div, uint32_t ul_mul) -{ - uint32_t vco_hz; - - Assert(e_src < PLL_NR_SOURCES); - - if (ul_div == 0 && ul_mul == 0) { /* Must only be true for UTMI PLL */ - p_cfg->ctrl = CKGR_UCKR_UPLLCOUNT(PLL_COUNT); - } else { /* PLLA */ - /* Calculate internal VCO frequency */ - vco_hz = osc_get_rate(e_src) / ul_div; - Assert(vco_hz >= PLL_INPUT_MIN_HZ); - Assert(vco_hz <= PLL_INPUT_MAX_HZ); - - vco_hz *= ul_mul; - Assert(vco_hz >= PLL_OUTPUT_MIN_HZ); - Assert(vco_hz <= PLL_OUTPUT_MAX_HZ); - - /* PMC hardware will automatically make it mul+1 */ - p_cfg->ctrl = CKGR_PLLAR_MULA(ul_mul - 1) | CKGR_PLLAR_DIVA(ul_div) | CKGR_PLLAR_PLLACOUNT(PLL_COUNT); - } + enum pll_source e_src, uint32_t ul_div, uint32_t ul_mul) { + uint32_t vco_hz; + + Assert(e_src < PLL_NR_SOURCES); + + if (ul_div == 0 && ul_mul == 0) { /* Must only be true for UTMI PLL */ + p_cfg->ctrl = CKGR_UCKR_UPLLCOUNT(PLL_COUNT); + } + else { /* PLLA */ + /* Calculate internal VCO frequency */ + vco_hz = osc_get_rate(e_src) / ul_div; + Assert(vco_hz >= PLL_INPUT_MIN_HZ); + Assert(vco_hz <= PLL_INPUT_MAX_HZ); + + vco_hz *= ul_mul; + Assert(vco_hz >= PLL_OUTPUT_MIN_HZ); + Assert(vco_hz <= PLL_OUTPUT_MAX_HZ); + + /* PMC hardware will automatically make it mul+1 */ + p_cfg->ctrl = CKGR_PLLAR_MULA(ul_mul - 1) | CKGR_PLLAR_DIVA(ul_div) | CKGR_PLLAR_PLLACOUNT(PLL_COUNT); + } } -#define pll_config_defaults(cfg, pll_id) \ - pll_config_init(cfg, \ - CONFIG_PLL##pll_id##_SOURCE, \ - CONFIG_PLL##pll_id##_DIV, \ - CONFIG_PLL##pll_id##_MUL) - -static inline void pll_config_read(struct pll_config *p_cfg, uint32_t ul_pll_id) -{ - Assert(ul_pll_id < NR_PLLS); - - if (ul_pll_id == PLLA_ID) { - p_cfg->ctrl = PMC->CKGR_PLLAR; - } else { - p_cfg->ctrl = PMC->CKGR_UCKR; - } +#define pll_config_defaults(cfg, pll_id) \ + pll_config_init(cfg, \ + CONFIG_PLL##pll_id##_SOURCE, \ + CONFIG_PLL##pll_id##_DIV, \ + CONFIG_PLL##pll_id##_MUL) + +static inline void pll_config_read(struct pll_config *p_cfg, uint32_t ul_pll_id) { + Assert(ul_pll_id < NR_PLLS); + p_cfg->ctrl = ul_pll_id == PLLA_ID ? PMC->CKGR_PLLAR : PMC->CKGR_UCKR; } -static inline void pll_config_write(const struct pll_config *p_cfg, uint32_t ul_pll_id) -{ - Assert(ul_pll_id < NR_PLLS); +static inline void pll_config_write(const struct pll_config *p_cfg, uint32_t ul_pll_id) { + Assert(ul_pll_id < NR_PLLS); - if (ul_pll_id == PLLA_ID) { - pmc_disable_pllack(); // Always stop PLL first! - PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | p_cfg->ctrl; - } else { - PMC->CKGR_UCKR = p_cfg->ctrl; - } + if (ul_pll_id == PLLA_ID) { + pmc_disable_pllack(); // Always stop PLL first! + PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | p_cfg->ctrl; + } + else + PMC->CKGR_UCKR = p_cfg->ctrl; } -static inline void pll_enable(const struct pll_config *p_cfg, uint32_t ul_pll_id) -{ - Assert(ul_pll_id < NR_PLLS); +static inline void pll_enable(const struct pll_config *p_cfg, uint32_t ul_pll_id) { + Assert(ul_pll_id < NR_PLLS); - if (ul_pll_id == PLLA_ID) { - pmc_disable_pllack(); // Always stop PLL first! - PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | p_cfg->ctrl; - } else { - PMC->CKGR_UCKR = p_cfg->ctrl | CKGR_UCKR_UPLLEN; - } + if (ul_pll_id == PLLA_ID) { + pmc_disable_pllack(); // Always stop PLL first! + PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | p_cfg->ctrl; + } + else + PMC->CKGR_UCKR = p_cfg->ctrl | CKGR_UCKR_UPLLEN; } /** * \note This will only disable the selected PLL, not the underlying oscillator (mainck). */ -static inline void pll_disable(uint32_t ul_pll_id) -{ - Assert(ul_pll_id < NR_PLLS); - - if (ul_pll_id == PLLA_ID) { - pmc_disable_pllack(); - } else { - PMC->CKGR_UCKR &= ~CKGR_UCKR_UPLLEN; - } +static inline void pll_disable(uint32_t ul_pll_id) { + Assert(ul_pll_id < NR_PLLS); + + if (ul_pll_id == PLLA_ID) + pmc_disable_pllack(); + else + PMC->CKGR_UCKR &= ~CKGR_UCKR_UPLLEN; } -static inline uint32_t pll_is_locked(uint32_t ul_pll_id) -{ - Assert(ul_pll_id < NR_PLLS); +static inline uint32_t pll_is_locked(uint32_t ul_pll_id) { + Assert(ul_pll_id < NR_PLLS); - if (ul_pll_id == PLLA_ID) { - return pmc_is_locked_pllack(); - } else { - return pmc_is_locked_upll(); - } + if (ul_pll_id == PLLA_ID) + return pmc_is_locked_pllack(); + else + return pmc_is_locked_upll(); } -static inline void pll_enable_source(enum pll_source e_src) -{ - switch (e_src) { - case PLL_SRC_MAINCK_4M_RC: - case PLL_SRC_MAINCK_8M_RC: - case PLL_SRC_MAINCK_12M_RC: - case PLL_SRC_MAINCK_XTAL: - case PLL_SRC_MAINCK_BYPASS: - osc_enable(e_src); - osc_wait_ready(e_src); - break; - - default: - Assert(false); - break; - } +static inline void pll_enable_source(enum pll_source e_src) { + switch (e_src) { + case PLL_SRC_MAINCK_4M_RC: + case PLL_SRC_MAINCK_8M_RC: + case PLL_SRC_MAINCK_12M_RC: + case PLL_SRC_MAINCK_XTAL: + case PLL_SRC_MAINCK_BYPASS: + osc_enable(e_src); + osc_wait_ready(e_src); + break; + + default: + Assert(false); + break; + } } -static inline void pll_enable_config_defaults(unsigned int ul_pll_id) -{ - struct pll_config pllcfg; - - if (pll_is_locked(ul_pll_id)) { - return; // Pll already running - } - switch (ul_pll_id) { -#ifdef CONFIG_PLL0_SOURCE - case 0: - pll_enable_source(CONFIG_PLL0_SOURCE); - pll_config_init(&pllcfg, - CONFIG_PLL0_SOURCE, - CONFIG_PLL0_DIV, - CONFIG_PLL0_MUL); - break; -#endif -#ifdef CONFIG_PLL1_SOURCE - case 1: - pll_enable_source(CONFIG_PLL1_SOURCE); - pll_config_init(&pllcfg, - CONFIG_PLL1_SOURCE, - CONFIG_PLL1_DIV, - CONFIG_PLL1_MUL); - break; -#endif - default: - Assert(false); - break; - } - pll_enable(&pllcfg, ul_pll_id); - while (!pll_is_locked(ul_pll_id)); +static inline void pll_enable_config_defaults(unsigned int ul_pll_id) { + struct pll_config pllcfg; + + if (pll_is_locked(ul_pll_id)) return; // Pll already running + + switch (ul_pll_id) { + #ifdef CONFIG_PLL0_SOURCE + case 0: + pll_enable_source(CONFIG_PLL0_SOURCE); + pll_config_init(&pllcfg, + CONFIG_PLL0_SOURCE, + CONFIG_PLL0_DIV, + CONFIG_PLL0_MUL); + break; + #endif + #ifdef CONFIG_PLL1_SOURCE + case 1: + pll_enable_source(CONFIG_PLL1_SOURCE); + pll_config_init(&pllcfg, + CONFIG_PLL1_SOURCE, + CONFIG_PLL1_DIV, + CONFIG_PLL1_MUL); + break; + #endif + default: + Assert(false); + break; + } + pll_enable(&pllcfg, ul_pll_id); + while (!pll_is_locked(ul_pll_id)); } /** @@ -264,15 +249,12 @@ static inline void pll_enable_config_defaults(unsigned int ul_pll_id) * \retval STATUS_OK The PLL is now locked. * \retval ERR_TIMEOUT Timed out waiting for PLL to become locked. */ -static inline int pll_wait_for_lock(unsigned int pll_id) -{ - Assert(pll_id < NR_PLLS); +static inline int pll_wait_for_lock(unsigned int pll_id) { + Assert(pll_id < NR_PLLS); - while (!pll_is_locked(pll_id)) { - /* Do nothing */ - } + while (!pll_is_locked(pll_id)) { /* Do nothing */ } - return 0; + return 0; } //! @} diff --git a/Marlin/src/HAL/DUE/usb/preprocessor.h b/Marlin/src/HAL/DUE/usb/preprocessor.h index c12d01cb..fe796c4f 100644 --- a/Marlin/src/HAL/DUE/usb/preprocessor.h +++ b/Marlin/src/HAL/DUE/usb/preprocessor.h @@ -51,5 +51,4 @@ #include "stringz.h" #include "mrepeat.h" - #endif // _PREPROCESSOR_H_ diff --git a/Marlin/src/HAL/DUE/usb/sbc_protocol.h b/Marlin/src/HAL/DUE/usb/sbc_protocol.h index ab845739..cdd4caa3 100644 --- a/Marlin/src/HAL/DUE/usb/sbc_protocol.h +++ b/Marlin/src/HAL/DUE/usb/sbc_protocol.h @@ -57,7 +57,6 @@ #ifndef _SBC_PROTOCOL_H_ #define _SBC_PROTOCOL_H_ - /** * \ingroup usb_msc_protocol * \defgroup usb_sbc_protocol SCSI Block Commands protocol definitions @@ -81,82 +80,81 @@ //@{ enum scsi_sbc_mode { - SCSI_MS_MODE_RW_ERR_RECOV = 0x01, //!< Read-Write Error Recovery mode page - SCSI_MS_MODE_FORMAT_DEVICE = 0x03, //!< Format Device mode page - SCSI_MS_MODE_FLEXIBLE_DISK = 0x05, //!< Flexible Disk mode page - SCSI_MS_MODE_CACHING = 0x08, //!< Caching mode page + SCSI_MS_MODE_RW_ERR_RECOV = 0x01, //!< Read-Write Error Recovery mode page + SCSI_MS_MODE_FORMAT_DEVICE = 0x03, //!< Format Device mode page + SCSI_MS_MODE_FLEXIBLE_DISK = 0x05, //!< Flexible Disk mode page + SCSI_MS_MODE_CACHING = 0x08, //!< Caching mode page }; - //! \name SBC-2 Device-Specific Parameter //@{ -#define SCSI_MS_SBC_WP 0x80 //!< Write Protected -#define SCSI_MS_SBC_DPOFUA 0x10 //!< DPO and FUA supported +#define SCSI_MS_SBC_WP 0x80 //!< Write Protected +#define SCSI_MS_SBC_DPOFUA 0x10 //!< DPO and FUA supported //@} /** * \brief SBC-2 Short LBA mode parameter block descriptor */ struct sbc_slba_block_desc { - be32_t nr_blocks; //!< Number of Blocks - be32_t block_len; //!< Block Length -#define SBC_SLBA_BLOCK_LEN_MASK 0x00FFFFFFU //!< Mask reserved bits + be32_t nr_blocks; //!< Number of Blocks + be32_t block_len; //!< Block Length +#define SBC_SLBA_BLOCK_LEN_MASK 0x00FFFFFFU //!< Mask reserved bits }; /** * \brief SBC-2 Caching mode page */ struct sbc_caching_mode_page { - uint8_t page_code; - uint8_t page_length; - uint8_t flags2; -#define SBC_MP_CACHE_IC (1 << 7) //!< Initiator Control -#define SBC_MP_CACHE_ABPF (1 << 6) //!< Abort Pre-Fetch -#define SBC_MP_CACHE_CAP (1 << 5) //!< Catching Analysis Permitted -#define SBC_MP_CACHE_DISC (1 << 4) //!< Discontinuity -#define SBC_MP_CACHE_SIZE (1 << 3) //!< Size enable -#define SBC_MP_CACHE_WCE (1 << 2) //!< Write back Cache Enable -#define SBC_MP_CACHE_MF (1 << 1) //!< Multiplication Factor -#define SBC_MP_CACHE_RCD (1 << 0) //!< Read Cache Disable - uint8_t retention; - be16_t dis_pf_transfer_len; - be16_t min_prefetch; - be16_t max_prefetch; - be16_t max_prefetch_ceil; - uint8_t flags12; -#define SBC_MP_CACHE_FSW (1 << 7) //!< Force Sequential Write -#define SBC_MP_CACHE_LBCSS (1 << 6) //!< Logical Blk Cache Seg Sz -#define SBC_MP_CACHE_DRA (1 << 5) //!< Disable Read-Ahead -#define SBC_MP_CACHE_NV_DIS (1 << 0) //!< Non-Volatile Cache Disable - uint8_t nr_cache_segments; - be16_t cache_segment_size; - uint8_t reserved[4]; + uint8_t page_code; + uint8_t page_length; + uint8_t flags2; +#define SBC_MP_CACHE_IC (1 << 7) //!< Initiator Control +#define SBC_MP_CACHE_ABPF (1 << 6) //!< Abort Pre-Fetch +#define SBC_MP_CACHE_CAP (1 << 5) //!< Catching Analysis Permitted +#define SBC_MP_CACHE_DISC (1 << 4) //!< Discontinuity +#define SBC_MP_CACHE_SIZE (1 << 3) //!< Size enable +#define SBC_MP_CACHE_WCE (1 << 2) //!< Write back Cache Enable +#define SBC_MP_CACHE_MF (1 << 1) //!< Multiplication Factor +#define SBC_MP_CACHE_RCD (1 << 0) //!< Read Cache Disable + uint8_t retention; + be16_t dis_pf_transfer_len; + be16_t min_prefetch; + be16_t max_prefetch; + be16_t max_prefetch_ceil; + uint8_t flags12; +#define SBC_MP_CACHE_FSW (1 << 7) //!< Force Sequential Write +#define SBC_MP_CACHE_LBCSS (1 << 6) //!< Logical Blk Cache Seg Sz +#define SBC_MP_CACHE_DRA (1 << 5) //!< Disable Read-Ahead +#define SBC_MP_CACHE_NV_DIS (1 << 0) //!< Non-Volatile Cache Disable + uint8_t nr_cache_segments; + be16_t cache_segment_size; + uint8_t reserved[4]; }; /** * \brief SBC-2 Read-Write Error Recovery mode page */ struct sbc_rdwr_error_recovery_mode_page { - uint8_t page_code; - uint8_t page_length; -#define SPC_MP_RW_ERR_RECOV_PAGE_LENGTH 0x0A - uint8_t flags1; -#define SBC_MP_RW_ERR_RECOV_AWRE (1 << 7) -#define SBC_MP_RW_ERR_RECOV_ARRE (1 << 6) -#define SBC_MP_RW_ERR_RECOV_TB (1 << 5) -#define SBC_MP_RW_ERR_RECOV_RC (1 << 4) -#define SBC_MP_RW_ERR_RECOV_ERR (1 << 3) -#define SBC_MP_RW_ERR_RECOV_PER (1 << 2) -#define SBC_MP_RW_ERR_RECOV_DTE (1 << 1) -#define SBC_MP_RW_ERR_RECOV_DCR (1 << 0) - uint8_t read_retry_count; - uint8_t correction_span; - uint8_t head_offset_count; - uint8_t data_strobe_offset_count; - uint8_t flags2; - uint8_t write_retry_count; - uint8_t flags3; - be16_t recovery_time_limit; + uint8_t page_code; + uint8_t page_length; + #define SPC_MP_RW_ERR_RECOV_PAGE_LENGTH 0x0A + uint8_t flags1; + #define SBC_MP_RW_ERR_RECOV_AWRE (1 << 7) + #define SBC_MP_RW_ERR_RECOV_ARRE (1 << 6) + #define SBC_MP_RW_ERR_RECOV_TB (1 << 5) + #define SBC_MP_RW_ERR_RECOV_RC (1 << 4) + #define SBC_MP_RW_ERR_RECOV_ERR (1 << 3) + #define SBC_MP_RW_ERR_RECOV_PER (1 << 2) + #define SBC_MP_RW_ERR_RECOV_DTE (1 << 1) + #define SBC_MP_RW_ERR_RECOV_DCR (1 << 0) + uint8_t read_retry_count; + uint8_t correction_span; + uint8_t head_offset_count; + uint8_t data_strobe_offset_count; + uint8_t flags2; + uint8_t write_retry_count; + uint8_t flags3; + be16_t recovery_time_limit; }; //@} @@ -164,8 +162,8 @@ struct sbc_rdwr_error_recovery_mode_page { * \brief SBC-2 READ CAPACITY (10) parameter data */ struct sbc_read_capacity10_data { - be32_t max_lba; //!< LBA of last logical block - be32_t block_len; //!< Number of bytes in the last logical block + be32_t max_lba; //!< LBA of last logical block + be32_t block_len; //!< Number of bytes in the last logical block }; //@} diff --git a/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp b/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp index 3dcbbaec..8421ff34 100644 --- a/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp +++ b/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp @@ -6,11 +6,11 @@ #include "../../../inc/MarlinConfig.h" -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA #include "../../../sd/cardreader.h" extern "C" { -#include "sd_mmc_spi_mem.h" + #include "sd_mmc_spi_mem.h" } #define SD_MMC_BLOCK_SIZE 512 @@ -18,32 +18,32 @@ extern "C" { void sd_mmc_spi_mem_init() { } +inline bool media_ready() { + return IS_SD_INSERTED() && !IS_SD_PRINTING() && !IS_SD_FILE_OPEN() && card.isMounted(); +} + +bool sd_mmc_spi_unload(bool) { return true; } + +bool sd_mmc_spi_wr_protect() { return false; } + +bool sd_mmc_spi_removal() { return !media_ready(); } + Ctrl_status sd_mmc_spi_test_unit_ready() { #ifdef DISABLE_DUE_SD_MMC return CTRL_NO_PRESENT; #endif - if (!IS_SD_INSERTED() || IS_SD_PRINTING() || IS_SD_FILE_OPEN() || !card.isMounted()) - return CTRL_NO_PRESENT; + if (sd_mmc_spi_removal()) return CTRL_NO_PRESENT; return CTRL_GOOD; } // NOTE: This function is defined as returning the address of the last block // in the card, which is cardSize() - 1 Ctrl_status sd_mmc_spi_read_capacity(uint32_t *nb_sector) { - if (!IS_SD_INSERTED() || IS_SD_PRINTING() || IS_SD_FILE_OPEN() || !card.isMounted()) - return CTRL_NO_PRESENT; + if (sd_mmc_spi_removal()) return CTRL_NO_PRESENT; *nb_sector = card.diskIODriver()->cardSize() - 1; return CTRL_GOOD; } -bool sd_mmc_spi_unload(bool) { return true; } - -bool sd_mmc_spi_wr_protect() { return false; } - -bool sd_mmc_spi_removal() { - return (!IS_SD_INSERTED() || IS_SD_PRINTING() || IS_SD_FILE_OPEN() || !card.isMounted()); -} - #if ACCESS_USB == true /** * \name MEM <-> USB Interface @@ -61,8 +61,7 @@ Ctrl_status sd_mmc_spi_usb_read_10(uint32_t addr, uint16_t nb_sector) { #ifdef DISABLE_DUE_SD_MMC return CTRL_NO_PRESENT; #endif - if (!IS_SD_INSERTED() || IS_SD_PRINTING() || IS_SD_FILE_OPEN() || !card.isMounted()) - return CTRL_NO_PRESENT; + if (sd_mmc_spi_removal()) return CTRL_NO_PRESENT; #ifdef DEBUG_MMC { @@ -101,8 +100,7 @@ Ctrl_status sd_mmc_spi_usb_write_10(uint32_t addr, uint16_t nb_sector) { #ifdef DISABLE_DUE_SD_MMC return CTRL_NO_PRESENT; #endif - if (!IS_SD_INSERTED() || IS_SD_PRINTING() || IS_SD_FILE_OPEN() || !card.isMounted()) - return CTRL_NO_PRESENT; + if (sd_mmc_spi_removal()) return CTRL_NO_PRESENT; #ifdef DEBUG_MMC { @@ -138,5 +136,5 @@ Ctrl_status sd_mmc_spi_usb_write_10(uint32_t addr, uint16_t nb_sector) { #endif // ACCESS_USB == true -#endif // SDSUPPORT +#endif // HAS_MEDIA #endif // ARDUINO_ARCH_SAM diff --git a/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.h b/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.h index 553fd3c2..464d106e 100644 --- a/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.h +++ b/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.h @@ -45,7 +45,6 @@ * Support and FAQ: visit Atmel Support */ - #ifndef _SD_MMC_SPI_MEM_H_ #define _SD_MMC_SPI_MEM_H_ @@ -63,22 +62,19 @@ #error sd_mmc_spi_mem.h is #included although SD_MMC_SPI_MEM is disabled #endif - #include "ctrl_access.h" - //_____ D E F I N I T I O N S ______________________________________________ #define SD_MMC_REMOVED 0 #define SD_MMC_INSERTED 1 #define SD_MMC_REMOVING 2 - //---- CONTROL FUNCTIONS ---- //! //! @brief This function initializes the hw/sw resources required to drive the SD_MMC_SPI. //!/ -extern void sd_mmc_spi_mem_init(void); +void sd_mmc_spi_mem_init(); //! //! @brief This function tests the state of the SD_MMC memory and sends it to the Host. @@ -91,7 +87,7 @@ extern void sd_mmc_spi_mem_init(void); //! Media not present -> CTRL_NO_PRESENT //! Media has changed -> CTRL_BUSY //!/ -extern Ctrl_status sd_mmc_spi_test_unit_ready(void); +Ctrl_status sd_mmc_spi_test_unit_ready(); //! //! @brief This function gives the address of the last valid sector. @@ -102,7 +98,7 @@ extern Ctrl_status sd_mmc_spi_test_unit_ready(void); //! Media ready -> CTRL_GOOD //! Media not present -> CTRL_NO_PRESENT //!/ -extern Ctrl_status sd_mmc_spi_read_capacity(uint32_t *nb_sector); +Ctrl_status sd_mmc_spi_read_capacity(uint32_t *nb_sector); /*! \brief Unload/Load the SD/MMC card selected * @@ -113,7 +109,7 @@ extern Ctrl_status sd_mmc_spi_read_capacity(uint32_t *nb_sector); * * \return \c true if unload/load done success. */ -extern bool sd_mmc_spi_unload(bool unload); +bool sd_mmc_spi_unload(bool unload); //! //! @brief This function returns the write protected status of the memory. @@ -124,15 +120,14 @@ extern bool sd_mmc_spi_unload(bool unload); //! //! @return false -> the memory is not write-protected (always) //!/ -extern bool sd_mmc_spi_wr_protect(void); +bool sd_mmc_spi_wr_protect(); //! //! @brief This function tells if the memory has been removed or not. //! //! @return false -> The memory isn't removed //! -extern bool sd_mmc_spi_removal(void); - +bool sd_mmc_spi_removal(); //---- ACCESS DATA FUNCTIONS ---- @@ -152,7 +147,7 @@ extern bool sd_mmc_spi_removal(void); //! It is ready -> CTRL_GOOD //! A error occur -> CTRL_FAIL //! -extern Ctrl_status sd_mmc_spi_usb_read_10(uint32_t addr, uint16_t nb_sector); +Ctrl_status sd_mmc_spi_usb_read_10(uint32_t addr, uint16_t nb_sector); //! This function initializes the SD/MMC memory for a write operation //! @@ -166,7 +161,7 @@ extern Ctrl_status sd_mmc_spi_usb_read_10(uint32_t addr, uint16_t nb_sector); //! It is ready -> CTRL_GOOD //! An error occurs -> CTRL_FAIL //! -extern Ctrl_status sd_mmc_spi_usb_write_10(uint32_t addr, uint16_t nb_sector); +Ctrl_status sd_mmc_spi_usb_write_10(uint32_t addr, uint16_t nb_sector); #endif // #if ACCESS_USB == true diff --git a/Marlin/src/HAL/DUE/usb/spc_protocol.h b/Marlin/src/HAL/DUE/usb/spc_protocol.h index d67cc5c7..808c388f 100644 --- a/Marlin/src/HAL/DUE/usb/spc_protocol.h +++ b/Marlin/src/HAL/DUE/usb/spc_protocol.h @@ -59,23 +59,23 @@ //! \name SCSI commands defined by SPC-2 //@{ -#define SPC_TEST_UNIT_READY 0x00 -#define SPC_REQUEST_SENSE 0x03 -#define SPC_INQUIRY 0x12 -#define SPC_MODE_SELECT6 0x15 -#define SPC_MODE_SENSE6 0x1A -#define SPC_SEND_DIAGNOSTIC 0x1D -#define SPC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E -#define SPC_MODE_SENSE10 0x5A -#define SPC_REPORT_LUNS 0xA0 +#define SPC_TEST_UNIT_READY 0x00 +#define SPC_REQUEST_SENSE 0x03 +#define SPC_INQUIRY 0x12 +#define SPC_MODE_SELECT6 0x15 +#define SPC_MODE_SENSE6 0x1A +#define SPC_SEND_DIAGNOSTIC 0x1D +#define SPC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E +#define SPC_MODE_SENSE10 0x5A +#define SPC_REPORT_LUNS 0xA0 //@} //! \brief May be set in byte 0 of the INQUIRY CDB //@{ //! Enable Vital Product Data -#define SCSI_INQ_REQ_EVPD 0x01 +#define SCSI_INQ_REQ_EVPD 0x01 //! Command Support Data specified by the PAGE OR OPERATION CODE field -#define SCSI_INQ_REQ_CMDT 0x02 +#define SCSI_INQ_REQ_CMDT 0x02 //@} COMPILER_PACK_SET(1) @@ -84,110 +84,110 @@ COMPILER_PACK_SET(1) * \brief SCSI Standard Inquiry data structure */ struct scsi_inquiry_data { - uint8_t pq_pdt; //!< Peripheral Qual / Peripheral Dev Type -#define SCSI_INQ_PQ_CONNECTED 0x00 //!< Peripheral connected -#define SCSI_INQ_PQ_NOT_CONN 0x20 //!< Peripheral not connected -#define SCSI_INQ_PQ_NOT_SUPP 0x60 //!< Peripheral not supported -#define SCSI_INQ_DT_DIR_ACCESS 0x00 //!< Direct Access (SBC) -#define SCSI_INQ_DT_SEQ_ACCESS 0x01 //!< Sequential Access -#define SCSI_INQ_DT_PRINTER 0x02 //!< Printer -#define SCSI_INQ_DT_PROCESSOR 0x03 //!< Processor device -#define SCSI_INQ_DT_WRITE_ONCE 0x04 //!< Write-once device -#define SCSI_INQ_DT_CD_DVD 0x05 //!< CD/DVD device -#define SCSI_INQ_DT_OPTICAL 0x07 //!< Optical Memory -#define SCSI_INQ_DT_MC 0x08 //!< Medium Changer -#define SCSI_INQ_DT_ARRAY 0x0C //!< Storage Array Controller -#define SCSI_INQ_DT_ENCLOSURE 0x0D //!< Enclosure Services -#define SCSI_INQ_DT_RBC 0x0E //!< Simplified Direct Access -#define SCSI_INQ_DT_OCRW 0x0F //!< Optical card reader/writer -#define SCSI_INQ_DT_BCC 0x10 //!< Bridge Controller Commands -#define SCSI_INQ_DT_OSD 0x11 //!< Object-based Storage -#define SCSI_INQ_DT_NONE 0x1F //!< No Peripheral - uint8_t flags1; //!< Flags (byte 1) -#define SCSI_INQ_RMB 0x80 //!< Removable Medium - uint8_t version; //!< Version -#define SCSI_INQ_VER_NONE 0x00 //!< No standards conformance -#define SCSI_INQ_VER_SPC 0x03 //!< SCSI Primary Commands (link to SBC) -#define SCSI_INQ_VER_SPC2 0x04 //!< SCSI Primary Commands - 2 (link to SBC-2) -#define SCSI_INQ_VER_SPC3 0x05 //!< SCSI Primary Commands - 3 (link to SBC-2) -#define SCSI_INQ_VER_SPC4 0x06 //!< SCSI Primary Commands - 4 (link to SBC-3) - uint8_t flags3; //!< Flags (byte 3) -#define SCSI_INQ_NORMACA 0x20 //!< Normal ACA Supported -#define SCSI_INQ_HISUP 0x10 //!< Hierarchal LUN addressing -#define SCSI_INQ_RSP_SPC2 0x02 //!< SPC-2 / SPC-3 response format - uint8_t addl_len; //!< Additional Length (n-4) -#define SCSI_INQ_ADDL_LEN(tot) ((tot)-5) //!< Total length is \a tot - uint8_t flags5; //!< Flags (byte 5) -#define SCSI_INQ_SCCS 0x80 - uint8_t flags6; //!< Flags (byte 6) -#define SCSI_INQ_BQUE 0x80 -#define SCSI_INQ_ENCSERV 0x40 -#define SCSI_INQ_MULTIP 0x10 -#define SCSI_INQ_MCHGR 0x08 -#define SCSI_INQ_ADDR16 0x01 - uint8_t flags7; //!< Flags (byte 7) -#define SCSI_INQ_WBUS16 0x20 -#define SCSI_INQ_SYNC 0x10 -#define SCSI_INQ_LINKED 0x08 -#define SCSI_INQ_CMDQUE 0x02 - uint8_t vendor_id[8]; //!< T10 Vendor Identification - uint8_t product_id[16]; //!< Product Identification - uint8_t product_rev[4]; //!< Product Revision Level + uint8_t pq_pdt; //!< Peripheral Qual / Peripheral Dev Type + #define SCSI_INQ_PQ_CONNECTED 0x00 //!< Peripheral connected + #define SCSI_INQ_PQ_NOT_CONN 0x20 //!< Peripheral not connected + #define SCSI_INQ_PQ_NOT_SUPP 0x60 //!< Peripheral not supported + #define SCSI_INQ_DT_DIR_ACCESS 0x00 //!< Direct Access (SBC) + #define SCSI_INQ_DT_SEQ_ACCESS 0x01 //!< Sequential Access + #define SCSI_INQ_DT_PRINTER 0x02 //!< Printer + #define SCSI_INQ_DT_PROCESSOR 0x03 //!< Processor device + #define SCSI_INQ_DT_WRITE_ONCE 0x04 //!< Write-once device + #define SCSI_INQ_DT_CD_DVD 0x05 //!< CD/DVD device + #define SCSI_INQ_DT_OPTICAL 0x07 //!< Optical Memory + #define SCSI_INQ_DT_MC 0x08 //!< Medium Changer + #define SCSI_INQ_DT_ARRAY 0x0C //!< Storage Array Controller + #define SCSI_INQ_DT_ENCLOSURE 0x0D //!< Enclosure Services + #define SCSI_INQ_DT_RBC 0x0E //!< Simplified Direct Access + #define SCSI_INQ_DT_OCRW 0x0F //!< Optical card reader/writer + #define SCSI_INQ_DT_BCC 0x10 //!< Bridge Controller Commands + #define SCSI_INQ_DT_OSD 0x11 //!< Object-based Storage + #define SCSI_INQ_DT_NONE 0x1F //!< No Peripheral + uint8_t flags1; //!< Flags (byte 1) + #define SCSI_INQ_RMB 0x80 //!< Removable Medium + uint8_t version; //!< Version + #define SCSI_INQ_VER_NONE 0x00 //!< No standards conformance + #define SCSI_INQ_VER_SPC 0x03 //!< SCSI Primary Commands (link to SBC) + #define SCSI_INQ_VER_SPC2 0x04 //!< SCSI Primary Commands - 2 (link to SBC-2) + #define SCSI_INQ_VER_SPC3 0x05 //!< SCSI Primary Commands - 3 (link to SBC-2) + #define SCSI_INQ_VER_SPC4 0x06 //!< SCSI Primary Commands - 4 (link to SBC-3) + uint8_t flags3; //!< Flags (byte 3) + #define SCSI_INQ_NORMACA 0x20 //!< Normal ACA Supported + #define SCSI_INQ_HISUP 0x10 //!< Hierarchal LUN addressing + #define SCSI_INQ_RSP_SPC2 0x02 //!< SPC-2 / SPC-3 response format + uint8_t addl_len; //!< Additional Length (n-4) + #define SCSI_INQ_ADDL_LEN(tot) ((tot)-5) //!< Total length is \a tot + uint8_t flags5; //!< Flags (byte 5) + #define SCSI_INQ_SCCS 0x80 + uint8_t flags6; //!< Flags (byte 6) + #define SCSI_INQ_BQUE 0x80 + #define SCSI_INQ_ENCSERV 0x40 + #define SCSI_INQ_MULTIP 0x10 + #define SCSI_INQ_MCHGR 0x08 + #define SCSI_INQ_ADDR16 0x01 + uint8_t flags7; //!< Flags (byte 7) + #define SCSI_INQ_WBUS16 0x20 + #define SCSI_INQ_SYNC 0x10 + #define SCSI_INQ_LINKED 0x08 + #define SCSI_INQ_CMDQUE 0x02 + uint8_t vendor_id[8]; //!< T10 Vendor Identification + uint8_t product_id[16]; //!< Product Identification + uint8_t product_rev[4]; //!< Product Revision Level }; /** * \brief SCSI Standard Request sense data structure */ struct scsi_request_sense_data { - /* 1st byte: REQUEST SENSE response flags*/ - uint8_t valid_reponse_code; -#define SCSI_SENSE_VALID 0x80 //!< Indicates the INFORMATION field contains valid information -#define SCSI_SENSE_RESPONSE_CODE_MASK 0x7F -#define SCSI_SENSE_CURRENT 0x70 //!< Response code 70h (current errors) -#define SCSI_SENSE_DEFERRED 0x71 - - /* 2nd byte */ - uint8_t obsolete; - - /* 3rd byte */ - uint8_t sense_flag_key; -#define SCSI_SENSE_FILEMARK 0x80 //!< Indicates that the current command has read a filemark or setmark. -#define SCSI_SENSE_EOM 0x40 //!< Indicates that an end-of-medium condition exists. -#define SCSI_SENSE_ILI 0x20 //!< Indicates that the requested logical block length did not match the logical block length of the data on the medium. -#define SCSI_SENSE_RESERVED 0x10 //!< Reserved -#define SCSI_SENSE_KEY(x) (x&0x0F) //!< Sense Key - - /* 4th to 7th bytes - INFORMATION field */ - uint8_t information[4]; - - /* 8th byte - ADDITIONAL SENSE LENGTH field */ - uint8_t AddSenseLen; -#define SCSI_SENSE_ADDL_LEN(total_len) ((total_len) - 8) - - /* 9th to 12th byte - COMMAND-SPECIFIC INFORMATION field */ - uint8_t CmdSpecINFO[4]; - - /* 13th byte - ADDITIONAL SENSE CODE field */ - uint8_t AddSenseCode; - - /* 14th byte - ADDITIONAL SENSE CODE QUALIFIER field */ - uint8_t AddSnsCodeQlfr; - - /* 15th byte - FIELD REPLACEABLE UNIT CODE field */ - uint8_t FldReplUnitCode; - - /* 16th byte */ - uint8_t SenseKeySpec[3]; -#define SCSI_SENSE_SKSV 0x80 //!< Indicates the SENSE-KEY SPECIFIC field contains valid information + /* 1st byte: REQUEST SENSE response flags*/ + uint8_t valid_reponse_code; + #define SCSI_SENSE_VALID 0x80 //!< Indicates the INFORMATION field contains valid information + #define SCSI_SENSE_RESPONSE_CODE_MASK 0x7F + #define SCSI_SENSE_CURRENT 0x70 //!< Response code 70h (current errors) + #define SCSI_SENSE_DEFERRED 0x71 + + /* 2nd byte */ + uint8_t obsolete; + + /* 3rd byte */ + uint8_t sense_flag_key; + #define SCSI_SENSE_FILEMARK 0x80 //!< Indicates that the current command has read a filemark or setmark. + #define SCSI_SENSE_EOM 0x40 //!< Indicates that an end-of-medium condition exists. + #define SCSI_SENSE_ILI 0x20 //!< Indicates that the requested logical block length did not match the logical block length of the data on the medium. + #define SCSI_SENSE_RESERVED 0x10 //!< Reserved + #define SCSI_SENSE_KEY(x) (x&0x0F) //!< Sense Key + + /* 4th to 7th bytes - INFORMATION field */ + uint8_t information[4]; + + /* 8th byte - ADDITIONAL SENSE LENGTH field */ + uint8_t AddSenseLen; + #define SCSI_SENSE_ADDL_LEN(total_len) ((total_len) - 8) + + /* 9th to 12th byte - COMMAND-SPECIFIC INFORMATION field */ + uint8_t CmdSpecINFO[4]; + + /* 13th byte - ADDITIONAL SENSE CODE field */ + uint8_t AddSenseCode; + + /* 14th byte - ADDITIONAL SENSE CODE QUALIFIER field */ + uint8_t AddSnsCodeQlfr; + + /* 15th byte - FIELD REPLACEABLE UNIT CODE field */ + uint8_t FldReplUnitCode; + + /* 16th byte */ + uint8_t SenseKeySpec[3]; + #define SCSI_SENSE_SKSV 0x80 //!< Indicates the SENSE-KEY SPECIFIC field contains valid information }; COMPILER_PACK_RESET() /* Vital Product Data page codes */ enum scsi_vpd_page_code { - SCSI_VPD_SUPPORTED_PAGES = 0x00, - SCSI_VPD_UNIT_SERIAL_NUMBER = 0x80, - SCSI_VPD_DEVICE_IDENTIFICATION = 0x83, + SCSI_VPD_SUPPORTED_PAGES = 0x00, + SCSI_VPD_UNIT_SERIAL_NUMBER = 0x80, + SCSI_VPD_DEVICE_IDENTIFICATION = 0x83, }; #define SCSI_VPD_HEADER_SIZE 4 @@ -200,37 +200,36 @@ enum scsi_vpd_page_code { #define SCSI_VPD_ID_TYPE_T10 1 - /* Sense keys */ enum scsi_sense_key { - SCSI_SK_NO_SENSE = 0x0, - SCSI_SK_RECOVERED_ERROR = 0x1, - SCSI_SK_NOT_READY = 0x2, - SCSI_SK_MEDIUM_ERROR = 0x3, - SCSI_SK_HARDWARE_ERROR = 0x4, - SCSI_SK_ILLEGAL_REQUEST = 0x5, - SCSI_SK_UNIT_ATTENTION = 0x6, - SCSI_SK_DATA_PROTECT = 0x7, - SCSI_SK_BLANK_CHECK = 0x8, - SCSI_SK_VENDOR_SPECIFIC = 0x9, - SCSI_SK_COPY_ABORTED = 0xA, - SCSI_SK_ABORTED_COMMAND = 0xB, - SCSI_SK_VOLUME_OVERFLOW = 0xD, - SCSI_SK_MISCOMPARE = 0xE, + SCSI_SK_NO_SENSE = 0x0, + SCSI_SK_RECOVERED_ERROR = 0x1, + SCSI_SK_NOT_READY = 0x2, + SCSI_SK_MEDIUM_ERROR = 0x3, + SCSI_SK_HARDWARE_ERROR = 0x4, + SCSI_SK_ILLEGAL_REQUEST = 0x5, + SCSI_SK_UNIT_ATTENTION = 0x6, + SCSI_SK_DATA_PROTECT = 0x7, + SCSI_SK_BLANK_CHECK = 0x8, + SCSI_SK_VENDOR_SPECIFIC = 0x9, + SCSI_SK_COPY_ABORTED = 0xA, + SCSI_SK_ABORTED_COMMAND = 0xB, + SCSI_SK_VOLUME_OVERFLOW = 0xD, + SCSI_SK_MISCOMPARE = 0xE, }; /* Additional Sense Code / Additional Sense Code Qualifier pairs */ enum scsi_asc_ascq { - SCSI_ASC_NO_ADDITIONAL_SENSE_INFO = 0x0000, - SCSI_ASC_LU_NOT_READY_REBUILD_IN_PROGRESS = 0x0405, - SCSI_ASC_WRITE_ERROR = 0x0C00, - SCSI_ASC_UNRECOVERED_READ_ERROR = 0x1100, - SCSI_ASC_INVALID_COMMAND_OPERATION_CODE = 0x2000, - SCSI_ASC_INVALID_FIELD_IN_CDB = 0x2400, - SCSI_ASC_WRITE_PROTECTED = 0x2700, - SCSI_ASC_NOT_READY_TO_READY_CHANGE = 0x2800, - SCSI_ASC_MEDIUM_NOT_PRESENT = 0x3A00, - SCSI_ASC_INTERNAL_TARGET_FAILURE = 0x4400, + SCSI_ASC_NO_ADDITIONAL_SENSE_INFO = 0x0000, + SCSI_ASC_LU_NOT_READY_REBUILD_IN_PROGRESS = 0x0405, + SCSI_ASC_WRITE_ERROR = 0x0C00, + SCSI_ASC_UNRECOVERED_READ_ERROR = 0x1100, + SCSI_ASC_INVALID_COMMAND_OPERATION_CODE = 0x2000, + SCSI_ASC_INVALID_FIELD_IN_CDB = 0x2400, + SCSI_ASC_WRITE_PROTECTED = 0x2700, + SCSI_ASC_NOT_READY_TO_READY_CHANGE = 0x2800, + SCSI_ASC_MEDIUM_NOT_PRESENT = 0x3A00, + SCSI_ASC_INTERNAL_TARGET_FAILURE = 0x4400, }; /** @@ -240,9 +239,9 @@ enum scsi_asc_ascq { * that are applicable to all SCSI devices. */ enum scsi_spc_mode { - SCSI_MS_MODE_VENDOR_SPEC = 0x00, - SCSI_MS_MODE_INFEXP = 0x1C, // Informational exceptions control page - SCSI_MS_MODE_ALL = 0x3F, + SCSI_MS_MODE_VENDOR_SPEC = 0x00, + SCSI_MS_MODE_INFEXP = 0x1C, // Informational exceptions control page + SCSI_MS_MODE_ALL = 0x3F, }; /** @@ -250,51 +249,45 @@ enum scsi_spc_mode { * See chapter 8.3.8 */ struct spc_control_page_info_execpt { - uint8_t page_code; - uint8_t page_length; -#define SPC_MP_INFEXP_PAGE_LENGTH 0x0A - uint8_t flags1; -#define SPC_MP_INFEXP_PERF (1<<7) //!< Initiator Control -#define SPC_MP_INFEXP_EBF (1<<5) //!< Caching Analysis Permitted -#define SPC_MP_INFEXP_EWASC (1<<4) //!< Discontinuity -#define SPC_MP_INFEXP_DEXCPT (1<<3) //!< Size enable -#define SPC_MP_INFEXP_TEST (1<<2) //!< Writeback Cache Enable -#define SPC_MP_INFEXP_LOGERR (1<<0) //!< Log errors bit - uint8_t mrie; -#define SPC_MP_INFEXP_MRIE_NO_REPORT 0x00 -#define SPC_MP_INFEXP_MRIE_ASYNC_EVENT 0x01 -#define SPC_MP_INFEXP_MRIE_GEN_UNIT 0x02 -#define SPC_MP_INFEXP_MRIE_COND_RECOV_ERROR 0x03 -#define SPC_MP_INFEXP_MRIE_UNCOND_RECOV_ERROR 0x04 -#define SPC_MP_INFEXP_MRIE_NO_SENSE 0x05 -#define SPC_MP_INFEXP_MRIE_ONLY_REPORT 0x06 - be32_t interval_timer; - be32_t report_count; + uint8_t page_code; + uint8_t page_length; + #define SPC_MP_INFEXP_PAGE_LENGTH 0x0A + uint8_t flags1; + #define SPC_MP_INFEXP_PERF (1<<7) //!< Initiator Control + #define SPC_MP_INFEXP_EBF (1<<5) //!< Caching Analysis Permitted + #define SPC_MP_INFEXP_EWASC (1<<4) //!< Discontinuity + #define SPC_MP_INFEXP_DEXCPT (1<<3) //!< Size enable + #define SPC_MP_INFEXP_TEST (1<<2) //!< Writeback Cache Enable + #define SPC_MP_INFEXP_LOGERR (1<<0) //!< Log errors bit + uint8_t mrie; + #define SPC_MP_INFEXP_MRIE_NO_REPORT 0x00 + #define SPC_MP_INFEXP_MRIE_ASYNC_EVENT 0x01 + #define SPC_MP_INFEXP_MRIE_GEN_UNIT 0x02 + #define SPC_MP_INFEXP_MRIE_COND_RECOV_ERROR 0x03 + #define SPC_MP_INFEXP_MRIE_UNCOND_RECOV_ERROR 0x04 + #define SPC_MP_INFEXP_MRIE_NO_SENSE 0x05 + #define SPC_MP_INFEXP_MRIE_ONLY_REPORT 0x06 + be32_t interval_timer; + be32_t report_count; }; - enum scsi_spc_mode_sense_pc { - SCSI_MS_SENSE_PC_CURRENT = 0, - SCSI_MS_SENSE_PC_CHANGEABLE = 1, - SCSI_MS_SENSE_PC_DEFAULT = 2, - SCSI_MS_SENSE_PC_SAVED = 3, + SCSI_MS_SENSE_PC_CURRENT = 0, + SCSI_MS_SENSE_PC_CHANGEABLE = 1, + SCSI_MS_SENSE_PC_DEFAULT = 2, + SCSI_MS_SENSE_PC_SAVED = 3, }; - - -static inline bool scsi_mode_sense_dbd_is_set(const uint8_t * cdb) -{ - return (cdb[1] >> 3) & 1; +static inline bool scsi_mode_sense_dbd_is_set(const uint8_t * cdb) { + return (cdb[1] >> 3) & 1; } -static inline uint8_t scsi_mode_sense_get_page_code(const uint8_t * cdb) -{ - return cdb[2] & 0x3F; +static inline uint8_t scsi_mode_sense_get_page_code(const uint8_t * cdb) { + return cdb[2] & 0x3F; } -static inline uint8_t scsi_mode_sense_get_pc(const uint8_t * cdb) -{ - return cdb[2] >> 6; +static inline uint8_t scsi_mode_sense_get_pc(const uint8_t * cdb) { + return cdb[2] >> 6; } /** @@ -302,10 +295,10 @@ static inline uint8_t scsi_mode_sense_get_pc(const uint8_t * cdb) * SENSE(6) */ struct scsi_mode_param_header6 { - uint8_t mode_data_length; //!< Number of bytes after this - uint8_t medium_type; //!< Medium Type - uint8_t device_specific_parameter; //!< Defined by command set - uint8_t block_descriptor_length; //!< Length of block descriptors + uint8_t mode_data_length; //!< Number of bytes after this + uint8_t medium_type; //!< Medium Type + uint8_t device_specific_parameter; //!< Defined by command set + uint8_t block_descriptor_length; //!< Length of block descriptors }; /** @@ -313,23 +306,23 @@ struct scsi_mode_param_header6 { * SENSE(10) */ struct scsi_mode_param_header10 { - be16_t mode_data_length; //!< Number of bytes after this - uint8_t medium_type; //!< Medium Type - uint8_t device_specific_parameter; //!< Defined by command set - uint8_t flags4; //!< LONGLBA in bit 0 - uint8_t reserved; - be16_t block_descriptor_length; //!< Length of block descriptors + be16_t mode_data_length; //!< Number of bytes after this + uint8_t medium_type; //!< Medium Type + uint8_t device_specific_parameter; //!< Defined by command set + uint8_t flags4; //!< LONGLBA in bit 0 + uint8_t reserved; + be16_t block_descriptor_length; //!< Length of block descriptors }; /** * \brief SCSI Page_0 Mode Page header (SPF not set) */ struct scsi_mode_page_0_header { - uint8_t page_code; -#define SCSI_PAGE_CODE_PS (1 << 7) //!< Parameters Saveable -#define SCSI_PAGE_CODE_SPF (1 << 6) //!< SubPage Format - uint8_t page_length; //!< Number of bytes after this -#define SCSI_MS_PAGE_LEN(total) ((total) - 2) + uint8_t page_code; +#define SCSI_PAGE_CODE_PS (1 << 7) //!< Parameters Saveable +#define SCSI_PAGE_CODE_SPF (1 << 6) //!< SubPage Format + uint8_t page_length; //!< Number of bytes after this +#define SCSI_MS_PAGE_LEN(total) ((total) - 2) }; //@} diff --git a/Marlin/src/HAL/DUE/usb/sysclk.h b/Marlin/src/HAL/DUE/usb/sysclk.h index 16db8c86..40013668 100644 --- a/Marlin/src/HAL/DUE/usb/sysclk.h +++ b/Marlin/src/HAL/DUE/usb/sysclk.h @@ -71,7 +71,7 @@ * \subsection sysclk_quickstart_use_case_1_setup_steps Initialization code * Add to the application initialization code: * \code - sysclk_init(); + sysclk_init(); \endcode * * \subsection sysclk_quickstart_use_case_1_setup_steps_workflow Workflow @@ -82,15 +82,15 @@ * Add or uncomment the following in your conf_clock.h header file, commenting out all other * definitions of the same symbol(s): * \code - #define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_PLLACK + #define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_PLLACK - // Fpll0 = (Fclk * PLL_mul) / PLL_div - #define CONFIG_PLL0_SOURCE PLL_SRC_MAINCK_XTAL - #define CONFIG_PLL0_MUL (84000000UL / BOARD_FREQ_MAINCK_XTAL) - #define CONFIG_PLL0_DIV 1 + // Fpll0 = (Fclk * PLL_mul) / PLL_div + #define CONFIG_PLL0_SOURCE PLL_SRC_MAINCK_XTAL + #define CONFIG_PLL0_MUL (84000000UL / BOARD_FREQ_MAINCK_XTAL) + #define CONFIG_PLL0_DIV 1 - // Fbus = Fsys / BUS_div - #define CONFIG_SYSCLK_PRES SYSCLK_PRES_1 + // Fbus = Fsys / BUS_div + #define CONFIG_SYSCLK_PRES SYSCLK_PRES_1 \endcode * * \subsection sysclk_quickstart_use_case_1_example_workflow Workflow @@ -100,14 +100,14 @@ * \code #define CONFIG_PLL0_SOURCE PLL_SRC_MAINCK_XTAL \endcode * -# Configure the PLL module to multiply the external fast crystal oscillator frequency up to 84MHz: * \code - #define CONFIG_PLL0_MUL (84000000UL / BOARD_FREQ_MAINCK_XTAL) - #define CONFIG_PLL0_DIV 1 + #define CONFIG_PLL0_MUL (84000000UL / BOARD_FREQ_MAINCK_XTAL) + #define CONFIG_PLL0_DIV 1 \endcode * \note For user boards, \c BOARD_FREQ_MAINCK_XTAL should be defined in the board \c conf_board.h configuration * file as the frequency of the fast crystal attached to the microcontroller. * -# Configure the main clock to run at the full 84MHz, disable scaling of the main system clock speed: * \code - #define CONFIG_SYSCLK_PRES SYSCLK_PRES_1 + #define CONFIG_SYSCLK_PRES SYSCLK_PRES_1 \endcode * \note Some dividers are powers of two, while others are integer division factors. Refer to the * formulas in the conf_clock.h template commented above each division define. @@ -136,7 +136,7 @@ extern "C" { * initialization. */ #ifndef CONFIG_SYSCLK_SOURCE -# define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_MAINCK_4M_RC + #define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_MAINCK_4M_RC #endif /** * \def CONFIG_SYSCLK_PRES @@ -149,7 +149,7 @@ extern "C" { * after initialization. */ #ifndef CONFIG_SYSCLK_PRES -# define CONFIG_SYSCLK_PRES 0 + #define CONFIG_SYSCLK_PRES 0 #endif //@} @@ -197,7 +197,7 @@ extern "C" { * USB is not required. */ #ifdef __DOXYGEN__ -# define CONFIG_USBCLK_SOURCE + #define CONFIG_USBCLK_SOURCE #endif /** @@ -209,10 +209,9 @@ extern "C" { * defined. */ #ifdef __DOXYGEN__ -# define CONFIG_USBCLK_DIV + #define CONFIG_USBCLK_DIV #endif - extern void sysclk_enable_usb(void); extern void sysclk_disable_usb(void); diff --git a/Marlin/src/HAL/DUE/usb/udc.c b/Marlin/src/HAL/DUE/usb/udc.c index 60bf0cff..f6a4243d 100644 --- a/Marlin/src/HAL/DUE/usb/udc.c +++ b/Marlin/src/HAL/DUE/usb/udc.c @@ -83,7 +83,6 @@ static usb_iface_desc_t UDC_DESC_STORAGE *udc_ptr_iface; //! @} - //! \name Internal structure to store the USB device main strings //! @{ diff --git a/Marlin/src/HAL/DUE/usb/udc.h b/Marlin/src/HAL/DUE/usb/udc.h index 8d92eb5c..aba08d95 100644 --- a/Marlin/src/HAL/DUE/usb/udc.h +++ b/Marlin/src/HAL/DUE/usb/udc.h @@ -144,15 +144,15 @@ extern "C" { * \code #define USB_DEVICE_ATTACH_AUTO_DISABLE \endcode * User C file contains: * \code - // Authorize VBUS monitoring - if (!udc_include_vbus_monitoring()) { - // Implement custom VBUS monitoring via GPIO or other - } - Event_VBUS_present() // VBUS interrupt or GPIO interrupt or other - { - // Attach USB Device - udc_attach(); - } + // Authorize VBUS monitoring + if (!udc_include_vbus_monitoring()) { + // Implement custom VBUS monitoring via GPIO or other + } + Event_VBUS_present() // VBUS interrupt or GPIO interrupt or other + { + // Attach USB Device + udc_attach(); + } \endcode * * - Case of battery charging. conf_usb.h file contains define @@ -160,21 +160,20 @@ extern "C" { * \code #define USB_DEVICE_ATTACH_AUTO_DISABLE \endcode * User C file contains: * \code - Event VBUS present() // VBUS interrupt or GPIO interrupt or .. - { - // Authorize battery charging, but wait key press to start USB. - } - Event Key press() - { - // Stop batteries charging - // Start USB - udc_attach(); - } + Event VBUS present() // VBUS interrupt or GPIO interrupt or .. + { + // Authorize battery charging, but wait key press to start USB. + } + Event Key press() + { + // Stop batteries charging + // Start USB + udc_attach(); + } \endcode */ -static inline bool udc_include_vbus_monitoring(void) -{ - return udd_include_vbus_monitoring(); +static inline bool udc_include_vbus_monitoring(void) { + return udd_include_vbus_monitoring(); } /*! \brief Start the USB Device stack @@ -192,32 +191,26 @@ void udc_stop(void); * then it will attach device when an acceptable Vbus * level from the host is detected. */ -static inline void udc_attach(void) -{ - udd_attach(); +static inline void udc_attach(void) { + udd_attach(); } - /** * \brief Detaches the device from the bus * * The driver must remove pull-up on USB line D- or D+. */ -static inline void udc_detach(void) -{ - udd_detach(); +static inline void udc_detach(void) { + udd_detach(); } - /*! \brief The USB driver sends a resume signal called \e "Upstream Resume" * This is authorized only when the remote wakeup feature is enabled by host. */ -static inline void udc_remotewakeup(void) -{ - udd_send_remotewakeup(); +static inline void udc_remotewakeup(void) { + udd_send_remotewakeup(); } - /** * \brief Returns a pointer on the current interface descriptor * @@ -296,23 +289,23 @@ usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); * * for AVR and SAM3/4 devices, add to the initialization code: * \code - sysclk_init(); - irq_initialize_vectors(); - cpu_irq_enable(); - board_init(); - sleepmgr_init(); // Optional + sysclk_init(); + irq_initialize_vectors(); + cpu_irq_enable(); + board_init(); + sleepmgr_init(); // Optional \endcode * * For SAMD devices, add to the initialization code: * \code - system_init(); - irq_initialize_vectors(); - cpu_irq_enable(); - sleepmgr_init(); // Optional + system_init(); + irq_initialize_vectors(); + cpu_irq_enable(); + sleepmgr_init(); // Optional \endcode * Add to the main IDLE loop: * \code - sleepmgr_enter_sleep(); // Optional + sleepmgr_enter_sleep(); // Optional \endcode * */ @@ -324,20 +317,20 @@ usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); * * Content of conf_usb.h: * \code - #define USB_DEVICE_VENDOR_ID 0x03EB - #define USB_DEVICE_PRODUCT_ID 0xXXXX - #define USB_DEVICE_MAJOR_VERSION 1 - #define USB_DEVICE_MINOR_VERSION 0 - #define USB_DEVICE_POWER 100 - #define USB_DEVICE_ATTR USB_CONFIG_ATTR_BUS_POWERED + #define USB_DEVICE_VENDOR_ID 0x03EB + #define USB_DEVICE_PRODUCT_ID 0xXXXX + #define USB_DEVICE_MAJOR_VERSION 1 + #define USB_DEVICE_MINOR_VERSION 0 + #define USB_DEVICE_POWER 100 + #define USB_DEVICE_ATTR USB_CONFIG_ATTR_BUS_POWERED \endcode * * Add to application C-file: * \code - void usb_init(void) - { - udc_start(); - } + void usb_init(void) + { + udc_start(); + } \endcode */ @@ -349,17 +342,17 @@ usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); * -# Ensure that conf_usb.h is available and contains the following configuration * which is the main USB device configuration: * - \code // Vendor ID provided by USB org (ATMEL 0x03EB) - #define USB_DEVICE_VENDOR_ID 0x03EB // Type Word - // Product ID (Atmel PID referenced in usb_atmel.h) - #define USB_DEVICE_PRODUCT_ID 0xXXXX // Type Word - // Major version of the device - #define USB_DEVICE_MAJOR_VERSION 1 // Type Byte - // Minor version of the device - #define USB_DEVICE_MINOR_VERSION 0 // Type Byte - // Maximum device power (mA) - #define USB_DEVICE_POWER 100 // Type 9-bits - // USB attributes to enable features - #define USB_DEVICE_ATTR USB_CONFIG_ATTR_BUS_POWERED // Flags \endcode + #define USB_DEVICE_VENDOR_ID 0x03EB // Type Word + // Product ID (Atmel PID referenced in usb_atmel.h) + #define USB_DEVICE_PRODUCT_ID 0xXXXX // Type Word + // Major version of the device + #define USB_DEVICE_MAJOR_VERSION 1 // Type Byte + // Minor version of the device + #define USB_DEVICE_MINOR_VERSION 0 // Type Byte + // Maximum device power (mA) + #define USB_DEVICE_POWER 100 // Type 9-bits + // USB attributes to enable features + #define USB_DEVICE_ATTR USB_CONFIG_ATTR_BUS_POWERED // Flags \endcode * -# Call the USB device stack start function to enable stack and start USB: * - \code udc_start(); \endcode * \note In case of USB dual roles (Device and Host) managed through USB OTG connector @@ -372,90 +365,90 @@ usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); * * Content of XMEGA conf_clock.h: * \code - // Configuration based on internal RC: - // USB clock need of 48Mhz - #define CONFIG_USBCLK_SOURCE USBCLK_SRC_RCOSC - #define CONFIG_OSC_RC32_CAL 48000000UL - #define CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC OSC_ID_USBSOF - // CPU clock need of clock > 12MHz to run with USB (Here 24MHz) - #define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_RC32MHZ - #define CONFIG_SYSCLK_PSADIV SYSCLK_PSADIV_2 - #define CONFIG_SYSCLK_PSBCDIV SYSCLK_PSBCDIV_1_1 + // Configuration based on internal RC: + // USB clock need of 48Mhz + #define CONFIG_USBCLK_SOURCE USBCLK_SRC_RCOSC + #define CONFIG_OSC_RC32_CAL 48000000UL + #define CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC OSC_ID_USBSOF + // CPU clock need of clock > 12MHz to run with USB (Here 24MHz) + #define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_RC32MHZ + #define CONFIG_SYSCLK_PSADIV SYSCLK_PSADIV_2 + #define CONFIG_SYSCLK_PSBCDIV SYSCLK_PSBCDIV_1_1 \endcode * * Content of conf_clock.h for AT32UC3A0, AT32UC3A1, AT32UC3B devices (USBB): * \code - // Configuration based on 12MHz external OSC: - #define CONFIG_PLL1_SOURCE PLL_SRC_OSC0 - #define CONFIG_PLL1_MUL 8 - #define CONFIG_PLL1_DIV 2 - #define CONFIG_USBCLK_SOURCE USBCLK_SRC_PLL1 - #define CONFIG_USBCLK_DIV 1 // Fusb = Fsys/(2 ^ USB_div) + // Configuration based on 12MHz external OSC: + #define CONFIG_PLL1_SOURCE PLL_SRC_OSC0 + #define CONFIG_PLL1_MUL 8 + #define CONFIG_PLL1_DIV 2 + #define CONFIG_USBCLK_SOURCE USBCLK_SRC_PLL1 + #define CONFIG_USBCLK_DIV 1 // Fusb = Fsys/(2 ^ USB_div) \endcode * * Content of conf_clock.h for AT32UC3A3, AT32UC3A4 devices (USBB with high speed support): * \code - // Configuration based on 12MHz external OSC: - #define CONFIG_USBCLK_SOURCE USBCLK_SRC_OSC0 - #define CONFIG_USBCLK_DIV 1 // Fusb = Fsys/(2 ^ USB_div) + // Configuration based on 12MHz external OSC: + #define CONFIG_USBCLK_SOURCE USBCLK_SRC_OSC0 + #define CONFIG_USBCLK_DIV 1 // Fusb = Fsys/(2 ^ USB_div) \endcode * * Content of conf_clock.h for AT32UC3C, ATUCXXD, ATUCXXL3U, ATUCXXL4U devices (USBC): * \code - // Configuration based on 12MHz external OSC: - #define CONFIG_PLL1_SOURCE PLL_SRC_OSC0 - #define CONFIG_PLL1_MUL 8 - #define CONFIG_PLL1_DIV 2 - #define CONFIG_USBCLK_SOURCE USBCLK_SRC_PLL1 - #define CONFIG_USBCLK_DIV 1 // Fusb = Fsys/(2 ^ USB_div) - // CPU clock need of clock > 25MHz to run with USBC - #define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_PLL1 + // Configuration based on 12MHz external OSC: + #define CONFIG_PLL1_SOURCE PLL_SRC_OSC0 + #define CONFIG_PLL1_MUL 8 + #define CONFIG_PLL1_DIV 2 + #define CONFIG_USBCLK_SOURCE USBCLK_SRC_PLL1 + #define CONFIG_USBCLK_DIV 1 // Fusb = Fsys/(2 ^ USB_div) + // CPU clock need of clock > 25MHz to run with USBC + #define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_PLL1 \endcode * * Content of conf_clock.h for SAM3S, SAM3SD, SAM4S devices (UPD: USB Peripheral Device): * \code - // PLL1 (B) Options (Fpll = (Fclk * PLL_mul) / PLL_div) - #define CONFIG_PLL1_SOURCE PLL_SRC_MAINCK_XTAL - #define CONFIG_PLL1_MUL 16 - #define CONFIG_PLL1_DIV 2 - // USB Clock Source Options (Fusb = FpllX / USB_div) - #define CONFIG_USBCLK_SOURCE USBCLK_SRC_PLL1 - #define CONFIG_USBCLK_DIV 2 + // PLL1 (B) Options (Fpll = (Fclk * PLL_mul) / PLL_div) + #define CONFIG_PLL1_SOURCE PLL_SRC_MAINCK_XTAL + #define CONFIG_PLL1_MUL 16 + #define CONFIG_PLL1_DIV 2 + // USB Clock Source Options (Fusb = FpllX / USB_div) + #define CONFIG_USBCLK_SOURCE USBCLK_SRC_PLL1 + #define CONFIG_USBCLK_DIV 2 \endcode * * Content of conf_clock.h for SAM3U device (UPDHS: USB Peripheral Device High Speed): * \code - // USB Clock Source fixed at UPLL. + // USB Clock Source fixed at UPLL. \endcode * * Content of conf_clock.h for SAM3X, SAM3A devices (UOTGHS: USB OTG High Speed): * \code - // USB Clock Source fixed at UPLL. - #define CONFIG_USBCLK_SOURCE USBCLK_SRC_UPLL - #define CONFIG_USBCLK_DIV 1 + // USB Clock Source fixed at UPLL. + #define CONFIG_USBCLK_SOURCE USBCLK_SRC_UPLL + #define CONFIG_USBCLK_DIV 1 \endcode * * Content of conf_clocks.h for SAMD devices (USB): * \code - // System clock bus configuration - # define CONF_CLOCK_FLASH_WAIT_STATES 2 - - // USB Clock Source fixed at DFLL. - // SYSTEM_CLOCK_SOURCE_DFLL configuration - Digital Frequency Locked Loop - # define CONF_CLOCK_DFLL_ENABLE true - # define CONF_CLOCK_DFLL_LOOP_MODE SYSTEM_CLOCK_DFLL_LOOP_MODE_USB_RECOVERY - # define CONF_CLOCK_DFLL_ON_DEMAND true - - // Set this to true to configure the GCLK when running clocks_init. - // If set to false, none of the GCLK generators will be configured in clocks_init(). - # define CONF_CLOCK_CONFIGURE_GCLK true - - // Configure GCLK generator 0 (Main Clock) - # define CONF_CLOCK_GCLK_0_ENABLE true - # define CONF_CLOCK_GCLK_0_RUN_IN_STANDBY true - # define CONF_CLOCK_GCLK_0_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_DFLL - # define CONF_CLOCK_GCLK_0_PRESCALER 1 - # define CONF_CLOCK_GCLK_0_OUTPUT_ENABLE false + // System clock bus configuration + # define CONF_CLOCK_FLASH_WAIT_STATES 2 + + // USB Clock Source fixed at DFLL. + // SYSTEM_CLOCK_SOURCE_DFLL configuration - Digital Frequency Locked Loop + # define CONF_CLOCK_DFLL_ENABLE true + # define CONF_CLOCK_DFLL_LOOP_MODE SYSTEM_CLOCK_DFLL_LOOP_MODE_USB_RECOVERY + # define CONF_CLOCK_DFLL_ON_DEMAND true + + // Set this to true to configure the GCLK when running clocks_init. + // If set to false, none of the GCLK generators will be configured in clocks_init(). + # define CONF_CLOCK_CONFIGURE_GCLK true + + // Configure GCLK generator 0 (Main Clock) + # define CONF_CLOCK_GCLK_0_ENABLE true + # define CONF_CLOCK_GCLK_0_RUN_IN_STANDBY true + # define CONF_CLOCK_GCLK_0_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_DFLL + # define CONF_CLOCK_GCLK_0_PRESCALER 1 + # define CONF_CLOCK_GCLK_0_OUTPUT_ENABLE false \endcode */ @@ -474,34 +467,34 @@ usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); * \subsection udc_use_case_1_usage_code Example code * Content of conf_usb.h: * \code - #if // Low speed - #define USB_DEVICE_LOW_SPEED - // #define USB_DEVICE_HS_SUPPORT + #if // Low speed + #define USB_DEVICE_LOW_SPEED + // #define USB_DEVICE_HS_SUPPORT - #elif // Full speed - // #define USB_DEVICE_LOW_SPEED - // #define USB_DEVICE_HS_SUPPORT + #elif // Full speed + // #define USB_DEVICE_LOW_SPEED + // #define USB_DEVICE_HS_SUPPORT - #elif // High speed - // #define USB_DEVICE_LOW_SPEED - #define USB_DEVICE_HS_SUPPORT + #elif // High speed + // #define USB_DEVICE_LOW_SPEED + #define USB_DEVICE_HS_SUPPORT - #endif + #endif \endcode * * \subsection udc_use_case_1_usage_flow Workflow * -# Ensure that conf_usb.h is available and contains the following parameters * required for a USB device low speed (1.5Mbit/s): * - \code #define USB_DEVICE_LOW_SPEED - //#define USB_DEVICE_HS_SUPPORT \endcode + //#define USB_DEVICE_HS_SUPPORT \endcode * -# Ensure that conf_usb.h contains the following parameters * required for a USB device full speed (12Mbit/s): * - \code //#define USB_DEVICE_LOW_SPEED - //#define USB_DEVICE_HS_SUPPORT \endcode + //#define USB_DEVICE_HS_SUPPORT \endcode * -# Ensure that conf_usb.h contains the following parameters * required for a USB device high speed (480Mbit/s): * - \code //#define USB_DEVICE_LOW_SPEED - #define USB_DEVICE_HS_SUPPORT \endcode + #define USB_DEVICE_HS_SUPPORT \endcode */ /** @@ -518,20 +511,20 @@ usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); * \subsection udc_use_case_2_usage_code Example code * Content of conf_usb.h: * \code - #define USB_DEVICE_MANUFACTURE_NAME "Manufacture name" - #define USB_DEVICE_PRODUCT_NAME "Product name" - #define USB_DEVICE_SERIAL_NAME "12...EF" + #define USB_DEVICE_MANUFACTURE_NAME "Manufacture name" + #define USB_DEVICE_PRODUCT_NAME "Product name" + #define USB_DEVICE_SERIAL_NAME "12...EF" \endcode * * \subsection udc_use_case_2_usage_flow Workflow * -# Ensure that conf_usb.h is available and contains the following parameters * required to enable different USB strings: * - \code // Static ASCII name for the manufacture - #define USB_DEVICE_MANUFACTURE_NAME "Manufacture name" \endcode + #define USB_DEVICE_MANUFACTURE_NAME "Manufacture name" \endcode * - \code // Static ASCII name for the product - #define USB_DEVICE_PRODUCT_NAME "Product name" \endcode + #define USB_DEVICE_PRODUCT_NAME "Product name" \endcode * - \code // Static ASCII name to enable and set a serial number - #define USB_DEVICE_SERIAL_NAME "12...EF" \endcode + #define USB_DEVICE_SERIAL_NAME "12...EF" \endcode */ /** @@ -548,42 +541,42 @@ usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); * \subsection udc_use_case_3_usage_code Example code * Content of conf_usb.h: * \code - #define USB_DEVICE_ATTR \ - (USB_CONFIG_ATTR_REMOTE_WAKEUP | USB_CONFIG_ATTR_..._POWERED) - #define UDC_REMOTEWAKEUP_ENABLE() my_callback_remotewakeup_enable() - extern void my_callback_remotewakeup_enable(void); - #define UDC_REMOTEWAKEUP_DISABLE() my_callback_remotewakeup_disable() - extern void my_callback_remotewakeup_disable(void); + #define USB_DEVICE_ATTR \ + (USB_CONFIG_ATTR_REMOTE_WAKEUP | USB_CONFIG_ATTR_..._POWERED) + #define UDC_REMOTEWAKEUP_ENABLE() my_callback_remotewakeup_enable() + extern void my_callback_remotewakeup_enable(void); + #define UDC_REMOTEWAKEUP_DISABLE() my_callback_remotewakeup_disable() + extern void my_callback_remotewakeup_disable(void); \endcode * * Add to application C-file: * \code - void my_callback_remotewakeup_enable(void) - { - // Enable application wakeup events (e.g. enable GPIO interrupt) - } - void my_callback_remotewakeup_disable(void) - { - // Disable application wakeup events (e.g. disable GPIO interrupt) - } - - void my_interrupt_event(void) - { - udc_remotewakeup(); - } + void my_callback_remotewakeup_enable(void) + { + // Enable application wakeup events (e.g. enable GPIO interrupt) + } + void my_callback_remotewakeup_disable(void) + { + // Disable application wakeup events (e.g. disable GPIO interrupt) + } + + void my_interrupt_event(void) + { + udc_remotewakeup(); + } \endcode * * \subsection udc_use_case_3_usage_flow Workflow * -# Ensure that conf_usb.h is available and contains the following parameters * required to enable remote wakeup feature: * - \code // Authorizes the remote wakeup feature - #define USB_DEVICE_ATTR (USB_CONFIG_ATTR_REMOTE_WAKEUP | USB_CONFIG_ATTR_..._POWERED) \endcode + #define USB_DEVICE_ATTR (USB_CONFIG_ATTR_REMOTE_WAKEUP | USB_CONFIG_ATTR_..._POWERED) \endcode * - \code // Define callback called when the host enables the remotewakeup feature - #define UDC_REMOTEWAKEUP_ENABLE() my_callback_remotewakeup_enable() - extern void my_callback_remotewakeup_enable(void); \endcode + #define UDC_REMOTEWAKEUP_ENABLE() my_callback_remotewakeup_enable() + extern void my_callback_remotewakeup_enable(void); \endcode * - \code // Define callback called when the host disables the remotewakeup feature - #define UDC_REMOTEWAKEUP_DISABLE() my_callback_remotewakeup_disable() - extern void my_callback_remotewakeup_disable(void); \endcode + #define UDC_REMOTEWAKEUP_DISABLE() my_callback_remotewakeup_disable() + extern void my_callback_remotewakeup_disable(void); \endcode * -# Send a remote wakeup (USB upstream): * - \code udc_remotewakeup(); \endcode */ @@ -603,40 +596,40 @@ usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); * \subsection udc_use_case_5_usage_code Example code * Content of conf_usb.h: * \code - #define USB_DEVICE_ATTR (USB_CONFIG_ATTR_BUS_POWERED) - #define UDC_SUSPEND_EVENT() user_callback_suspend_action() - extern void user_callback_suspend_action(void) - #define UDC_RESUME_EVENT() user_callback_resume_action() - extern void user_callback_resume_action(void) + #define USB_DEVICE_ATTR (USB_CONFIG_ATTR_BUS_POWERED) + #define UDC_SUSPEND_EVENT() user_callback_suspend_action() + extern void user_callback_suspend_action(void) + #define UDC_RESUME_EVENT() user_callback_resume_action() + extern void user_callback_resume_action(void) \endcode * * Add to application C-file: * \code - void user_callback_suspend_action(void) - { - // Disable hardware component to reduce power consumption - } - void user_callback_resume_action(void) - { - // Re-enable hardware component - } + void user_callback_suspend_action(void) + { + // Disable hardware component to reduce power consumption + } + void user_callback_resume_action(void) + { + // Re-enable hardware component + } \endcode * * \subsection udc_use_case_5_usage_flow Workflow * -# Ensure that conf_usb.h is available and contains the following parameters: * - \code // Authorizes the BUS power feature - #define USB_DEVICE_ATTR (USB_CONFIG_ATTR_BUS_POWERED) \endcode + #define USB_DEVICE_ATTR (USB_CONFIG_ATTR_BUS_POWERED) \endcode * - \code // Define callback called when the host suspend the USB line - #define UDC_SUSPEND_EVENT() user_callback_suspend_action() - extern void user_callback_suspend_action(void); \endcode + #define UDC_SUSPEND_EVENT() user_callback_suspend_action() + extern void user_callback_suspend_action(void); \endcode * - \code // Define callback called when the host or device resume the USB line - #define UDC_RESUME_EVENT() user_callback_resume_action() - extern void user_callback_resume_action(void); \endcode + #define UDC_RESUME_EVENT() user_callback_resume_action() + extern void user_callback_resume_action(void); \endcode * -# Reduce power consumption in suspend mode (max. 2.5mA on Vbus): * - \code void user_callback_suspend_action(void) - { - turn_off_components(); - } \endcode + { + turn_off_components(); + } \endcode */ /** @@ -654,44 +647,42 @@ usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); * \subsection udc_use_case_6_usage_code Example code * Content of conf_usb.h: * \code - #define USB_DEVICE_SERIAL_NAME - #define USB_DEVICE_GET_SERIAL_NAME_POINTER serial_number - #define USB_DEVICE_GET_SERIAL_NAME_LENGTH 12 - extern uint8_t serial_number[]; + #define USB_DEVICE_SERIAL_NAME + #define USB_DEVICE_GET_SERIAL_NAME_POINTER serial_number + #define USB_DEVICE_GET_SERIAL_NAME_LENGTH 12 + extern uint8_t serial_number[]; \endcode * * Add to application C-file: * \code - uint8_t serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH]; + uint8_t serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH]; - void init_build_usb_serial_number(void) - { - serial_number[0] = 'A'; - serial_number[1] = 'B'; - ... - serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH-1] = 'C'; - } \endcode + void init_build_usb_serial_number(void) + { + serial_number[0] = 'A'; + serial_number[1] = 'B'; + ... + serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH-1] = 'C'; + } \endcode * * \subsection udc_use_case_6_usage_flow Workflow * -# Ensure that conf_usb.h is available and contains the following parameters * required to enable a USB serial number strings dynamically: * - \code #define USB_DEVICE_SERIAL_NAME // Define this empty - #define USB_DEVICE_GET_SERIAL_NAME_POINTER serial_number // Give serial array pointer - #define USB_DEVICE_GET_SERIAL_NAME_LENGTH 12 // Give size of serial array - extern uint8_t serial_number[]; // Declare external serial array \endcode + #define USB_DEVICE_GET_SERIAL_NAME_POINTER serial_number // Give serial array pointer + #define USB_DEVICE_GET_SERIAL_NAME_LENGTH 12 // Give size of serial array + extern uint8_t serial_number[]; // Declare external serial array \endcode * -# Before start USB stack, initialize the serial array * - \code - uint8_t serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH]; - - void init_build_usb_serial_number(void) - { - serial_number[0] = 'A'; - serial_number[1] = 'B'; - ... - serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH-1] = 'C'; - } \endcode + uint8_t serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH]; + + void init_build_usb_serial_number(void) + { + serial_number[0] = 'A'; + serial_number[1] = 'B'; + ... + serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH-1] = 'C'; + } \endcode */ - - #endif // _UDC_H_ diff --git a/Marlin/src/HAL/DUE/usb/udc_desc.h b/Marlin/src/HAL/DUE/usb/udc_desc.h index 052ca08e..f1f328d0 100644 --- a/Marlin/src/HAL/DUE/usb/udc_desc.h +++ b/Marlin/src/HAL/DUE/usb/udc_desc.h @@ -78,50 +78,47 @@ extern "C" { * For Mega application used "code". */ #define UDC_DESC_STORAGE - // Descriptor storage in internal RAM + // Descriptor storage in internal RAM #if (defined UDC_DATA_USE_HRAM_SUPPORT) -# if defined(__GNUC__) -# define UDC_DATA(x) COMPILER_WORD_ALIGNED __attribute__((__section__(".data_hram0"))) -# define UDC_BSS(x) COMPILER_ALIGNED(x) __attribute__((__section__(".bss_hram0"))) -# elif defined(__ICCAVR32__) -# define UDC_DATA(x) COMPILER_ALIGNED(x) __data32 -# define UDC_BSS(x) COMPILER_ALIGNED(x) __data32 -# endif + #if defined(__GNUC__) + #define UDC_DATA(x) COMPILER_WORD_ALIGNED __attribute__((__section__(".data_hram0"))) + #define UDC_BSS(x) COMPILER_ALIGNED(x) __attribute__((__section__(".bss_hram0"))) +#elif defined(__ICCAVR32__) + #define UDC_DATA(x) COMPILER_ALIGNED(x) __data32 + #define UDC_BSS(x) COMPILER_ALIGNED(x) __data32 +#endif #else -# define UDC_DATA(x) COMPILER_ALIGNED(x) -# define UDC_BSS(x) COMPILER_ALIGNED(x) + #define UDC_DATA(x) COMPILER_ALIGNED(x) + #define UDC_BSS(x) COMPILER_ALIGNED(x) #endif - - /** * \brief Configuration descriptor and UDI link for one USB speed */ typedef struct { - //! USB configuration descriptor - usb_conf_desc_t UDC_DESC_STORAGE *desc; - //! Array of UDI API pointer - udi_api_t UDC_DESC_STORAGE *UDC_DESC_STORAGE * udi_apis; + //! USB configuration descriptor + usb_conf_desc_t UDC_DESC_STORAGE *desc; + //! Array of UDI API pointer + udi_api_t UDC_DESC_STORAGE *UDC_DESC_STORAGE * udi_apis; } udc_config_speed_t; - /** * \brief All information about the USB Device */ typedef struct { - //! USB device descriptor for low or full speed - usb_dev_desc_t UDC_DESC_STORAGE *confdev_lsfs; - //! USB configuration descriptor and UDI API pointers for low or full speed - udc_config_speed_t UDC_DESC_STORAGE *conf_lsfs; -#ifdef USB_DEVICE_HS_SUPPORT - //! USB device descriptor for high speed - usb_dev_desc_t UDC_DESC_STORAGE *confdev_hs; - //! USB device qualifier, only use in high speed mode - usb_dev_qual_desc_t UDC_DESC_STORAGE *qualifier; - //! USB configuration descriptor and UDI API pointers for high speed - udc_config_speed_t UDC_DESC_STORAGE *conf_hs; -#endif - usb_dev_bos_desc_t UDC_DESC_STORAGE *conf_bos; + //! USB device descriptor for low or full speed + usb_dev_desc_t UDC_DESC_STORAGE *confdev_lsfs; + //! USB configuration descriptor and UDI API pointers for low or full speed + udc_config_speed_t UDC_DESC_STORAGE *conf_lsfs; + #ifdef USB_DEVICE_HS_SUPPORT + //! USB device descriptor for high speed + usb_dev_desc_t UDC_DESC_STORAGE *confdev_hs; + //! USB device qualifier, only use in high speed mode + usb_dev_qual_desc_t UDC_DESC_STORAGE *qualifier; + //! USB configuration descriptor and UDI API pointers for high speed + udc_config_speed_t UDC_DESC_STORAGE *conf_hs; + #endif + usb_dev_bos_desc_t UDC_DESC_STORAGE *conf_bos; } udc_config_t; //! Global variables of USB Device Descriptor and UDI links diff --git a/Marlin/src/HAL/DUE/usb/udd.h b/Marlin/src/HAL/DUE/usb/udd.h index 319d8842..4e482784 100644 --- a/Marlin/src/HAL/DUE/usb/udd.h +++ b/Marlin/src/HAL/DUE/usb/udd.h @@ -71,8 +71,8 @@ typedef uint8_t udd_ep_id_t; //! \brief Endpoint transfer status //! Returned in parameters of callback register via udd_ep_run routine. typedef enum { - UDD_EP_TRANSFER_OK = 0, - UDD_EP_TRANSFER_ABORT = 1, + UDD_EP_TRANSFER_OK = 0, + UDD_EP_TRANSFER_ABORT = 1, } udd_ep_status_t; /** @@ -82,41 +82,37 @@ typedef enum { * It can be updated by udc_process_setup() from UDC or *setup() from UDIs. */ typedef struct { - //! Data received in USB SETUP packet - //! Note: The swap of "req.wValues" from uin16_t to le16_t is done by UDD. - usb_setup_req_t req; + //! Data received in USB SETUP packet + //! Note: The swap of "req.wValues" from uin16_t to le16_t is done by UDD. + usb_setup_req_t req; - //! Point to buffer to send or fill with data following SETUP packet - //! This buffer must be word align for DATA IN phase (use prefix COMPILER_WORD_ALIGNED for buffer) - uint8_t *payload; + //! Point to buffer to send or fill with data following SETUP packet + //! This buffer must be word align for DATA IN phase (use prefix COMPILER_WORD_ALIGNED for buffer) + uint8_t *payload; - //! Size of buffer to send or fill, and content the number of byte transferred - uint16_t payload_size; + //! Size of buffer to send or fill, and content the number of byte transferred + uint16_t payload_size; - //! Callback called after reception of ZLP from setup request - void (*callback)(void); + //! Callback called after reception of ZLP from setup request + void (*callback)(void); - //! Callback called when the buffer given (.payload) is full or empty. - //! This one return false to abort data transfer, or true with a new buffer in .payload. - bool (*over_under_run)(void); + //! Callback called when the buffer given (.payload) is full or empty. + //! This one return false to abort data transfer, or true with a new buffer in .payload. + bool (*over_under_run)(void); } udd_ctrl_request_t; extern udd_ctrl_request_t udd_g_ctrlreq; //! Return true if the setup request \a udd_g_ctrlreq indicates IN data transfer -#define Udd_setup_is_in() \ - (USB_REQ_DIR_IN == (udd_g_ctrlreq.req.bmRequestType & USB_REQ_DIR_MASK)) +#define Udd_setup_is_in() (USB_REQ_DIR_IN == (udd_g_ctrlreq.req.bmRequestType & USB_REQ_DIR_MASK)) //! Return true if the setup request \a udd_g_ctrlreq indicates OUT data transfer -#define Udd_setup_is_out() \ - (USB_REQ_DIR_OUT == (udd_g_ctrlreq.req.bmRequestType & USB_REQ_DIR_MASK)) +#define Udd_setup_is_out() (USB_REQ_DIR_OUT == (udd_g_ctrlreq.req.bmRequestType & USB_REQ_DIR_MASK)) //! Return the type of the SETUP request \a udd_g_ctrlreq. \see usb_reqtype. -#define Udd_setup_type() \ - (udd_g_ctrlreq.req.bmRequestType & USB_REQ_TYPE_MASK) +#define Udd_setup_type() (udd_g_ctrlreq.req.bmRequestType & USB_REQ_TYPE_MASK) //! Return the recipient of the SETUP request \a udd_g_ctrlreq. \see usb_recipient -#define Udd_setup_recipient() \ - (udd_g_ctrlreq.req.bmRequestType & USB_REQ_RECIP_MASK) +#define Udd_setup_recipient() (udd_g_ctrlreq.req.bmRequestType & USB_REQ_RECIP_MASK) /** * \brief End of halt callback function type. @@ -134,8 +130,7 @@ typedef void (*udd_callback_halt_cleared_t)(void); * \param status UDD_EP_TRANSFER_ABORT, if transfer is aborted * \param n number of data transferred */ -typedef void (*udd_callback_trans_t) (udd_ep_status_t status, - iram_size_t nb_transferred, udd_ep_id_t ep); +typedef void (*udd_callback_trans_t) (udd_ep_status_t status, iram_size_t nb_transferred, udd_ep_id_t ep); /** * \brief Authorizes the VBUS event @@ -218,7 +213,6 @@ void udd_send_remotewakeup(void); */ void udd_set_setup_payload( uint8_t *payload, uint16_t payload_size ); - /** * \name Endpoint Management * @@ -239,8 +233,7 @@ void udd_set_setup_payload( uint8_t *payload, uint16_t payload_size ); * * \return \c 1 if the endpoint is enabled, otherwise \c 0. */ -bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes, - uint16_t MaxEndpointSize); +bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes, uint16_t MaxEndpointSize); /** * \brief Disables an endpoint @@ -294,8 +287,7 @@ bool udd_ep_clear_halt(udd_ep_id_t ep); * * \return \c 1 if the register is accepted, otherwise \c 0. */ -bool udd_ep_wait_stall_clear(udd_ep_id_t ep, - udd_callback_halt_cleared_t callback); +bool udd_ep_wait_stall_clear(udd_ep_id_t ep, udd_callback_halt_cleared_t callback); /** * \brief Allows to receive or send data on an endpoint @@ -321,9 +313,8 @@ bool udd_ep_wait_stall_clear(udd_ep_id_t ep, * * \return \c 1 if function was successfully done, otherwise \c 0. */ -bool udd_ep_run(udd_ep_id_t ep, bool b_shortpacket, - uint8_t * buf, iram_size_t buf_size, - udd_callback_trans_t callback); +bool udd_ep_run(udd_ep_id_t ep, bool b_shortpacket, uint8_t * buf, iram_size_t buf_size, udd_callback_trans_t callback); + /** * \brief Aborts transfer on going on endpoint * @@ -339,7 +330,6 @@ void udd_ep_abort(udd_ep_id_t ep); //@} - /** * \name High speed test mode management * @@ -352,7 +342,6 @@ void udd_test_mode_se0_nak(void); void udd_test_mode_packet(void); //@} - /** * \name UDC callbacks to provide for UDD * diff --git a/Marlin/src/HAL/DUE/usb/udi.h b/Marlin/src/HAL/DUE/usb/udi.h index febf03b7..bc5de086 100644 --- a/Marlin/src/HAL/DUE/usb/udi.h +++ b/Marlin/src/HAL/DUE/usb/udi.h @@ -72,57 +72,57 @@ extern "C" { * selected by UDC. */ typedef struct { - /** - * \brief Enable the interface. - * - * This function is called when the host selects a configuration - * to which this interface belongs through a Set Configuration - * request, and when the host selects an alternate setting of - * this interface through a Set Interface request. - * - * \return \c 1 if function was successfully done, otherwise \c 0. - */ - bool (*enable)(void); + /** + * \brief Enable the interface. + * + * This function is called when the host selects a configuration + * to which this interface belongs through a Set Configuration + * request, and when the host selects an alternate setting of + * this interface through a Set Interface request. + * + * \return \c 1 if function was successfully done, otherwise \c 0. + */ + bool (*enable)(void); - /** - * \brief Disable the interface. - * - * This function is called when this interface is currently - * active, and - * - the host selects any configuration through a Set - * Configuration request, or - * - the host issues a USB reset, or - * - the device is detached from the host (i.e. Vbus is no - * longer present) - */ - void (*disable)(void); + /** + * \brief Disable the interface. + * + * This function is called when this interface is currently + * active, and + * - the host selects any configuration through a Set + * Configuration request, or + * - the host issues a USB reset, or + * - the device is detached from the host (i.e. Vbus is no + * longer present) + */ + void (*disable)(void); - /** - * \brief Handle a control request directed at an interface. - * - * This function is called when this interface is currently - * active and the host sends a SETUP request - * with this interface as the recipient. - * - * Use udd_g_ctrlreq to decode and response to SETUP request. - * - * \return \c 1 if this interface supports the SETUP request, otherwise \c 0. - */ - bool (*setup)(void); + /** + * \brief Handle a control request directed at an interface. + * + * This function is called when this interface is currently + * active and the host sends a SETUP request + * with this interface as the recipient. + * + * Use udd_g_ctrlreq to decode and response to SETUP request. + * + * \return \c 1 if this interface supports the SETUP request, otherwise \c 0. + */ + bool (*setup)(void); - /** - * \brief Returns the current setting of the selected interface. - * - * This function is called when UDC when know alternate setting of selected interface. - * - * \return alternate setting of selected interface - */ - uint8_t (*getsetting)(void); + /** + * \brief Returns the current setting of the selected interface. + * + * This function is called when UDC when know alternate setting of selected interface. + * + * \return alternate setting of selected interface + */ + uint8_t (*getsetting)(void); - /** - * \brief To signal that a SOF is occurred - */ - void (*sof_notify)(void); + /** + * \brief To signal that a SOF is occurred + */ + void (*sof_notify)(void); } udi_api_t; //@} diff --git a/Marlin/src/HAL/DUE/usb/udi_cdc.c b/Marlin/src/HAL/DUE/usb/udi_cdc.c index 89debe57..26788570 100644 --- a/Marlin/src/HAL/DUE/usb/udi_cdc.c +++ b/Marlin/src/HAL/DUE/usb/udi_cdc.c @@ -457,7 +457,6 @@ void udi_cdc_data_sof_notify(void) #endif } - // ------------------------ //------- Internal routines to control serial line @@ -520,7 +519,6 @@ static void udi_cdc_ctrl_state_change(uint8_t port, bool b_set, le16_t bit_mask) udi_cdc_ctrl_state_notify(port, ep_comm); } - static void udi_cdc_ctrl_state_notify(uint8_t port, udd_ep_id_t ep) { #if UDI_CDC_PORT_NB == 1 // To optimize code @@ -542,7 +540,6 @@ static void udi_cdc_ctrl_state_notify(uint8_t port, udd_ep_id_t ep) } } - static void udi_cdc_serial_state_msg_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep) { uint8_t port; @@ -578,11 +575,9 @@ static void udi_cdc_serial_state_msg_sent(udd_ep_status_t status, iram_size_t n, udi_cdc_ctrl_state_notify(port, ep); } - // ------------------------ //------- Internal routines to process data transfer - static bool udi_cdc_rx_start(uint8_t port) { irqflags_t flags; @@ -632,7 +627,6 @@ static bool udi_cdc_rx_start(uint8_t port) udi_cdc_data_received); } - static void udi_cdc_data_received(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep) { uint8_t buf_sel_trans; @@ -668,7 +662,6 @@ static void udi_cdc_data_received(udd_ep_status_t status, iram_size_t n, udd_ep_ udi_cdc_rx_start(port); } - static void udi_cdc_data_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep) { uint8_t port; @@ -700,7 +693,6 @@ static void udi_cdc_data_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t udi_cdc_tx_send(port); } - static void udi_cdc_tx_send(uint8_t port) { irqflags_t flags; @@ -780,11 +772,9 @@ static void udi_cdc_tx_send(uint8_t port) udi_cdc_data_sent); } - // ------------------------ //------- Application interface - //------- Application interface void udi_cdc_ctrl_signal_dcd(bool b_set) diff --git a/Marlin/src/HAL/DUE/usb/udi_cdc.h b/Marlin/src/HAL/DUE/usb/udi_cdc.h index b6184501..e9c6abbb 100644 --- a/Marlin/src/HAL/DUE/usb/udi_cdc.h +++ b/Marlin/src/HAL/DUE/usb/udi_cdc.h @@ -92,21 +92,20 @@ extern UDC_DESC_STORAGE udi_api_t udi_api_cdc_data; * descriptors for the CDC Communication Class interface. */ typedef struct { - //! Standard interface descriptor - usb_iface_desc_t iface; - //! CDC Header functional descriptor - usb_cdc_hdr_desc_t header; - //! CDC Abstract Control Model functional descriptor - usb_cdc_acm_desc_t acm; - //! CDC Union functional descriptor - usb_cdc_union_desc_t union_desc; - //! CDC Call Management functional descriptor - usb_cdc_call_mgmt_desc_t call_mgmt; - //! Notification endpoint descriptor - usb_ep_desc_t ep_notify; + //! Standard interface descriptor + usb_iface_desc_t iface; + //! CDC Header functional descriptor + usb_cdc_hdr_desc_t header; + //! CDC Abstract Control Model functional descriptor + usb_cdc_acm_desc_t acm; + //! CDC Union functional descriptor + usb_cdc_union_desc_t union_desc; + //! CDC Call Management functional descriptor + usb_cdc_call_mgmt_desc_t call_mgmt; + //! Notification endpoint descriptor + usb_ep_desc_t ep_notify; } udi_cdc_comm_desc_t; - /** * \brief Data Class interface descriptor * @@ -114,14 +113,13 @@ typedef struct { * CDC Data Class interface. */ typedef struct { - //! Standard interface descriptor - usb_iface_desc_t iface; - //! Data IN/OUT endpoint descriptors - usb_ep_desc_t ep_in; - usb_ep_desc_t ep_out; + //! Standard interface descriptor + usb_iface_desc_t iface; + //! Data IN/OUT endpoint descriptors + usb_ep_desc_t ep_in; + usb_ep_desc_t ep_out; } udi_cdc_data_desc_t; - //! CDC communication endpoints size for all speeds #define UDI_CDC_COMM_EP_SIZE 64 //! CDC data endpoints size for FS speed (8B, 16B, 32B, 64B) @@ -136,13 +134,13 @@ typedef struct { //@{ //! By default no string associated to these interfaces #ifndef UDI_CDC_IAD_STRING_ID_0 -#define UDI_CDC_IAD_STRING_ID_0 0 + #define UDI_CDC_IAD_STRING_ID_0 0 #endif #ifndef UDI_CDC_COMM_STRING_ID_0 -#define UDI_CDC_COMM_STRING_ID_0 0 + #define UDI_CDC_COMM_STRING_ID_0 0 #endif #ifndef UDI_CDC_DATA_STRING_ID_0 -#define UDI_CDC_DATA_STRING_ID_0 0 + #define UDI_CDC_DATA_STRING_ID_0 0 #endif #define UDI_CDC_IAD_DESC_0 UDI_CDC_IAD_DESC(0) #define UDI_CDC_COMM_DESC_0 UDI_CDC_COMM_DESC(0) @@ -151,13 +149,13 @@ typedef struct { //! By default no string associated to these interfaces #ifndef UDI_CDC_IAD_STRING_ID_1 -#define UDI_CDC_IAD_STRING_ID_1 0 + #define UDI_CDC_IAD_STRING_ID_1 0 #endif #ifndef UDI_CDC_COMM_STRING_ID_1 -#define UDI_CDC_COMM_STRING_ID_1 0 + #define UDI_CDC_COMM_STRING_ID_1 0 #endif #ifndef UDI_CDC_DATA_STRING_ID_1 -#define UDI_CDC_DATA_STRING_ID_1 0 + #define UDI_CDC_DATA_STRING_ID_1 0 #endif #define UDI_CDC_IAD_DESC_1 UDI_CDC_IAD_DESC(1) #define UDI_CDC_COMM_DESC_1 UDI_CDC_COMM_DESC(1) @@ -166,13 +164,13 @@ typedef struct { //! By default no string associated to these interfaces #ifndef UDI_CDC_IAD_STRING_ID_2 -#define UDI_CDC_IAD_STRING_ID_2 0 + #define UDI_CDC_IAD_STRING_ID_2 0 #endif #ifndef UDI_CDC_COMM_STRING_ID_2 -#define UDI_CDC_COMM_STRING_ID_2 0 + #define UDI_CDC_COMM_STRING_ID_2 0 #endif #ifndef UDI_CDC_DATA_STRING_ID_2 -#define UDI_CDC_DATA_STRING_ID_2 0 + #define UDI_CDC_DATA_STRING_ID_2 0 #endif #define UDI_CDC_IAD_DESC_2 UDI_CDC_IAD_DESC(2) #define UDI_CDC_COMM_DESC_2 UDI_CDC_COMM_DESC(2) @@ -181,13 +179,13 @@ typedef struct { //! By default no string associated to these interfaces #ifndef UDI_CDC_IAD_STRING_ID_3 -#define UDI_CDC_IAD_STRING_ID_3 0 + #define UDI_CDC_IAD_STRING_ID_3 0 #endif #ifndef UDI_CDC_COMM_STRING_ID_3 -#define UDI_CDC_COMM_STRING_ID_3 0 + #define UDI_CDC_COMM_STRING_ID_3 0 #endif #ifndef UDI_CDC_DATA_STRING_ID_3 -#define UDI_CDC_DATA_STRING_ID_3 0 + #define UDI_CDC_DATA_STRING_ID_3 0 #endif #define UDI_CDC_IAD_DESC_3 UDI_CDC_IAD_DESC(3) #define UDI_CDC_COMM_DESC_3 UDI_CDC_COMM_DESC(3) @@ -196,13 +194,13 @@ typedef struct { //! By default no string associated to these interfaces #ifndef UDI_CDC_IAD_STRING_ID_4 -#define UDI_CDC_IAD_STRING_ID_4 0 + #define UDI_CDC_IAD_STRING_ID_4 0 #endif #ifndef UDI_CDC_COMM_STRING_ID_4 -#define UDI_CDC_COMM_STRING_ID_4 0 + #define UDI_CDC_COMM_STRING_ID_4 0 #endif #ifndef UDI_CDC_DATA_STRING_ID_4 -#define UDI_CDC_DATA_STRING_ID_4 0 + #define UDI_CDC_DATA_STRING_ID_4 0 #endif #define UDI_CDC_IAD_DESC_4 UDI_CDC_IAD_DESC(4) #define UDI_CDC_COMM_DESC_4 UDI_CDC_COMM_DESC(4) @@ -211,13 +209,13 @@ typedef struct { //! By default no string associated to these interfaces #ifndef UDI_CDC_IAD_STRING_ID_5 -#define UDI_CDC_IAD_STRING_ID_5 0 + #define UDI_CDC_IAD_STRING_ID_5 0 #endif #ifndef UDI_CDC_COMM_STRING_ID_5 -#define UDI_CDC_COMM_STRING_ID_5 0 + #define UDI_CDC_COMM_STRING_ID_5 0 #endif #ifndef UDI_CDC_DATA_STRING_ID_5 -#define UDI_CDC_DATA_STRING_ID_5 0 + #define UDI_CDC_DATA_STRING_ID_5 0 #endif #define UDI_CDC_IAD_DESC_5 UDI_CDC_IAD_DESC(5) #define UDI_CDC_COMM_DESC_5 UDI_CDC_COMM_DESC(5) @@ -226,13 +224,13 @@ typedef struct { //! By default no string associated to these interfaces #ifndef UDI_CDC_IAD_STRING_ID_6 -#define UDI_CDC_IAD_STRING_ID_6 0 + #define UDI_CDC_IAD_STRING_ID_6 0 #endif #ifndef UDI_CDC_COMM_STRING_ID_6 -#define UDI_CDC_COMM_STRING_ID_6 0 + #define UDI_CDC_COMM_STRING_ID_6 0 #endif #ifndef UDI_CDC_DATA_STRING_ID_6 -#define UDI_CDC_DATA_STRING_ID_6 0 + #define UDI_CDC_DATA_STRING_ID_6 0 #endif #define UDI_CDC_IAD_DESC_6 UDI_CDC_IAD_DESC(6) #define UDI_CDC_COMM_DESC_6 UDI_CDC_COMM_DESC(6) @@ -240,7 +238,6 @@ typedef struct { #define UDI_CDC_DATA_DESC_6_HS UDI_CDC_DATA_DESC_HS(6) //@} - //! Content of CDC IAD interface descriptor for all speeds #define UDI_CDC_IAD_DESC(port) { \ .bLength = sizeof(usb_iad_desc_t),\ @@ -270,7 +267,7 @@ typedef struct { .call_mgmt.bDescriptorType = CDC_CS_INTERFACE,\ .call_mgmt.bDescriptorSubtype = CDC_SCS_CALL_MGMT,\ .call_mgmt.bmCapabilities = \ - CDC_CALL_MGMT_SUPPORTED | CDC_CALL_MGMT_OVER_DCI,\ + CDC_CALL_MGMT_SUPPORTED | CDC_CALL_MGMT_OVER_DCI,\ .acm.bFunctionLength = sizeof(usb_cdc_acm_desc_t),\ .acm.bDescriptorType = CDC_CS_INTERFACE,\ .acm.bDescriptorSubtype = CDC_SCS_ACM,\ @@ -610,40 +607,37 @@ iram_size_t udi_cdc_multi_write_buf(uint8_t port, const void* buf, iram_size_t s * \subsection udi_cdc_basic_use_case_usage_code Example code * Content of conf_usb.h: * \code - #define UDI_CDC_ENABLE_EXT(port) my_callback_cdc_enable() - extern bool my_callback_cdc_enable(void); - #define UDI_CDC_DISABLE_EXT(port) my_callback_cdc_disable() - extern void my_callback_cdc_disable(void); - #define UDI_CDC_LOW_RATE - - #define UDI_CDC_DEFAULT_RATE 115200 - #define UDI_CDC_DEFAULT_STOPBITS CDC_STOP_BITS_1 - #define UDI_CDC_DEFAULT_PARITY CDC_PAR_NONE - #define UDI_CDC_DEFAULT_DATABITS 8 - - #include "udi_cdc_conf.h" // At the end of conf_usb.h file + #define UDI_CDC_ENABLE_EXT(port) my_callback_cdc_enable() + extern bool my_callback_cdc_enable(void); + #define UDI_CDC_DISABLE_EXT(port) my_callback_cdc_disable() + extern void my_callback_cdc_disable(void); + #define UDI_CDC_LOW_RATE + + #define UDI_CDC_DEFAULT_RATE 115200 + #define UDI_CDC_DEFAULT_STOPBITS CDC_STOP_BITS_1 + #define UDI_CDC_DEFAULT_PARITY CDC_PAR_NONE + #define UDI_CDC_DEFAULT_DATABITS 8 + + #include "udi_cdc_conf.h" // At the end of conf_usb.h file \endcode * * Add to application C-file: * \code - static bool my_flag_autorize_cdc_transfert = false; - bool my_callback_cdc_enable(void) - { - my_flag_autorize_cdc_transfert = true; - return true; - } - void my_callback_cdc_disable(void) - { - my_flag_autorize_cdc_transfert = false; - } - - void task(void) - { - if (my_flag_autorize_cdc_transfert) { - udi_cdc_putc('A'); - udi_cdc_getc(); - } - } + static bool my_flag_autorize_cdc_transfert = false; + bool my_callback_cdc_enable(void) { + my_flag_autorize_cdc_transfert = true; + return true; + } + void my_callback_cdc_disable(void) { + my_flag_autorize_cdc_transfert = false; + } + + void task(void) { + if (my_flag_autorize_cdc_transfert) { + udi_cdc_putc('A'); + udi_cdc_getc(); + } + } \endcode * * \subsection udi_cdc_basic_use_case_setup_flow Workflow @@ -652,14 +646,14 @@ iram_size_t udi_cdc_multi_write_buf(uint8_t port, const void* buf, iram_size_t s * - \code #define USB_DEVICE_SERIAL_NAME "12...EF" // Disk SN for CDC \endcode * \note The USB serial number is mandatory when a CDC interface is used. * - \code #define UDI_CDC_ENABLE_EXT(port) my_callback_cdc_enable() - extern bool my_callback_cdc_enable(void); \endcode + extern bool my_callback_cdc_enable(void); \endcode * \note After the device enumeration (detecting and identifying USB devices), * the USB host starts the device configuration. When the USB CDC interface * from the device is accepted by the host, the USB host enables this interface and the * UDI_CDC_ENABLE_EXT() callback function is called and return true. * Thus, when this event is received, the data transfer on CDC interface are authorized. * - \code #define UDI_CDC_DISABLE_EXT(port) my_callback_cdc_disable() - extern void my_callback_cdc_disable(void); \endcode + extern void my_callback_cdc_disable(void); \endcode * \note When the USB device is unplugged or is reset by the USB host, the USB * interface is disabled and the UDI_CDC_DISABLE_EXT() callback function * is called. Thus, the data transfer must be stopped on CDC interface. @@ -667,19 +661,19 @@ iram_size_t udi_cdc_multi_write_buf(uint8_t port, const void* buf, iram_size_t s * \note Define it when the transfer CDC Device to Host is a low rate * (<512000 bauds) to reduce CDC buffers size. * - \code #define UDI_CDC_DEFAULT_RATE 115200 - #define UDI_CDC_DEFAULT_STOPBITS CDC_STOP_BITS_1 - #define UDI_CDC_DEFAULT_PARITY CDC_PAR_NONE - #define UDI_CDC_DEFAULT_DATABITS 8 \endcode + #define UDI_CDC_DEFAULT_STOPBITS CDC_STOP_BITS_1 + #define UDI_CDC_DEFAULT_PARITY CDC_PAR_NONE + #define UDI_CDC_DEFAULT_DATABITS 8 \endcode * \note Default configuration of communication port at startup. * -# Send or wait data on CDC line: * - \code // Waits and gets a value on CDC line - int udi_cdc_getc(void); - // Reads a RAM buffer on CDC line - iram_size_t udi_cdc_read_buf(int *buf, iram_size_t size); - // Puts a byte on CDC line - int udi_cdc_putc(int value); - // Writes a RAM buffer on CDC line - iram_size_t udi_cdc_write_buf(const int *buf, iram_size_t size); \endcode + int udi_cdc_getc(void); + // Reads a RAM buffer on CDC line + iram_size_t udi_cdc_read_buf(int *buf, iram_size_t size); + // Puts a byte on CDC line + int udi_cdc_putc(int value); + // Writes a RAM buffer on CDC line + iram_size_t udi_cdc_write_buf(const int *buf, iram_size_t size); \endcode * * \section udi_cdc_use_cases Advanced use cases * For more advanced use of the UDI CDC module, see the following use cases: @@ -713,90 +707,90 @@ iram_size_t udi_cdc_multi_write_buf(uint8_t port, const void* buf, iram_size_t s * \subsection udi_cdc_use_case_composite_usage_code Example code * Content of conf_usb.h: * \code - #define USB_DEVICE_EP_CTRL_SIZE 64 - #define USB_DEVICE_NB_INTERFACE (X+2) - #define USB_DEVICE_MAX_EP (X+3) - - #define UDI_CDC_DATA_EP_IN_0 (1 | USB_EP_DIR_IN) // TX - #define UDI_CDC_DATA_EP_OUT_0 (2 | USB_EP_DIR_OUT) // RX - #define UDI_CDC_COMM_EP_0 (3 | USB_EP_DIR_IN) // Notify endpoint - #define UDI_CDC_COMM_IFACE_NUMBER_0 X+0 - #define UDI_CDC_DATA_IFACE_NUMBER_0 X+1 - - #define UDI_COMPOSITE_DESC_T \ - usb_iad_desc_t udi_cdc_iad; \ - udi_cdc_comm_desc_t udi_cdc_comm; \ - udi_cdc_data_desc_t udi_cdc_data; \ - ... - #define UDI_COMPOSITE_DESC_FS \ - .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ - .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ - .udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \ - ... - #define UDI_COMPOSITE_DESC_HS \ - .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ - .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ - .udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \ - ... - #define UDI_COMPOSITE_API \ - &udi_api_cdc_comm, \ - &udi_api_cdc_data, \ - ... + #define USB_DEVICE_EP_CTRL_SIZE 64 + #define USB_DEVICE_NB_INTERFACE (X+2) + #define USB_DEVICE_MAX_EP (X+3) + + #define UDI_CDC_DATA_EP_IN_0 (1 | USB_EP_DIR_IN) // TX + #define UDI_CDC_DATA_EP_OUT_0 (2 | USB_EP_DIR_OUT) // RX + #define UDI_CDC_COMM_EP_0 (3 | USB_EP_DIR_IN) // Notify endpoint + #define UDI_CDC_COMM_IFACE_NUMBER_0 X+0 + #define UDI_CDC_DATA_IFACE_NUMBER_0 X+1 + + #define UDI_COMPOSITE_DESC_T \ + usb_iad_desc_t udi_cdc_iad; \ + udi_cdc_comm_desc_t udi_cdc_comm; \ + udi_cdc_data_desc_t udi_cdc_data; \ + ... + #define UDI_COMPOSITE_DESC_FS \ + .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ + .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ + .udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \ + ... + #define UDI_COMPOSITE_DESC_HS \ + .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ + .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ + .udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \ + ... + #define UDI_COMPOSITE_API \ + &udi_api_cdc_comm, \ + &udi_api_cdc_data, \ + ... \endcode * * \subsection udi_cdc_use_case_composite_usage_flow Workflow * -# Ensure that conf_usb.h is available and contains the following parameters * required for a USB composite device configuration: * - \code // Endpoint control size, This must be: - // - 8, 16, 32 or 64 for full speed device (8 is recommended to save RAM) - // - 64 for a high speed device - #define USB_DEVICE_EP_CTRL_SIZE 64 - // Total Number of interfaces on this USB device. - // Add 2 for CDC. - #define USB_DEVICE_NB_INTERFACE (X+2) - // Total number of endpoints on this USB device. - // This must include each endpoint for each interface. - // Add 3 for CDC. - #define USB_DEVICE_MAX_EP (X+3) \endcode + // - 8, 16, 32 or 64 for full speed device (8 is recommended to save RAM) + // - 64 for a high speed device + #define USB_DEVICE_EP_CTRL_SIZE 64 + // Total Number of interfaces on this USB device. + // Add 2 for CDC. + #define USB_DEVICE_NB_INTERFACE (X+2) + // Total number of endpoints on this USB device. + // This must include each endpoint for each interface. + // Add 3 for CDC. + #define USB_DEVICE_MAX_EP (X+3) \endcode * -# Ensure that conf_usb.h contains the description of * composite device: * - \code // The endpoint numbers chosen by you for the CDC. - // The endpoint numbers starting from 1. - #define UDI_CDC_DATA_EP_IN_0 (1 | USB_EP_DIR_IN) // TX - #define UDI_CDC_DATA_EP_OUT_0 (2 | USB_EP_DIR_OUT) // RX - #define UDI_CDC_COMM_EP_0 (3 | USB_EP_DIR_IN) // Notify endpoint - // The interface index of an interface starting from 0 - #define UDI_CDC_COMM_IFACE_NUMBER_0 X+0 - #define UDI_CDC_DATA_IFACE_NUMBER_0 X+1 \endcode + // The endpoint numbers starting from 1. + #define UDI_CDC_DATA_EP_IN_0 (1 | USB_EP_DIR_IN) // TX + #define UDI_CDC_DATA_EP_OUT_0 (2 | USB_EP_DIR_OUT) // RX + #define UDI_CDC_COMM_EP_0 (3 | USB_EP_DIR_IN) // Notify endpoint + // The interface index of an interface starting from 0 + #define UDI_CDC_COMM_IFACE_NUMBER_0 X+0 + #define UDI_CDC_DATA_IFACE_NUMBER_0 X+1 \endcode * -# Ensure that conf_usb.h contains the following parameters * required for a USB composite device configuration: * - \code // USB Interfaces descriptor structure - #define UDI_COMPOSITE_DESC_T \ - ... - usb_iad_desc_t udi_cdc_iad; \ - udi_cdc_comm_desc_t udi_cdc_comm; \ - udi_cdc_data_desc_t udi_cdc_data; \ - ... - // USB Interfaces descriptor value for Full Speed - #define UDI_COMPOSITE_DESC_FS \ - ... - .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ - .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ - .udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \ - ... - // USB Interfaces descriptor value for High Speed - #define UDI_COMPOSITE_DESC_HS \ - ... - .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ - .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ - .udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \ - ... - // USB Interface APIs - #define UDI_COMPOSITE_API \ - ... - &udi_api_cdc_comm, \ - &udi_api_cdc_data, \ - ... \endcode + #define UDI_COMPOSITE_DESC_T \ + ... + usb_iad_desc_t udi_cdc_iad; \ + udi_cdc_comm_desc_t udi_cdc_comm; \ + udi_cdc_data_desc_t udi_cdc_data; \ + ... + // USB Interfaces descriptor value for Full Speed + #define UDI_COMPOSITE_DESC_FS \ + ... + .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ + .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ + .udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \ + ... + // USB Interfaces descriptor value for High Speed + #define UDI_COMPOSITE_DESC_HS \ + ... + .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \ + .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \ + .udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \ + ... + // USB Interface APIs + #define UDI_COMPOSITE_API \ + ... + &udi_api_cdc_comm, \ + &udi_api_cdc_data, \ + ... \endcode * - \note The descriptors order given in the four lists above must be the * same as the order defined by all interface indexes. The interface index * orders are defined through UDI_X_IFACE_NUMBER defines.\n diff --git a/Marlin/src/HAL/DUE/usb/udi_cdc_desc.c b/Marlin/src/HAL/DUE/usb/udi_cdc_desc.c index 97c334e2..bcae362c 100644 --- a/Marlin/src/HAL/DUE/usb/udi_cdc_desc.c +++ b/Marlin/src/HAL/DUE/usb/udi_cdc_desc.c @@ -51,7 +51,7 @@ #include "udc_desc.h" #include "udi_cdc.h" -#if DISABLED(SDSUPPORT) +#if !HAS_MEDIA /** * \defgroup udi_cdc_group_single_desc USB device descriptors for a single interface @@ -109,7 +109,6 @@ UDC_DESC_STORAGE usb_dev_desc_t udc_device_desc = { .bNumConfigurations = 1 }; - #ifdef USB_DEVICE_HS_SUPPORT //! USB Device Qualifier Descriptor for HS COMPILER_WORD_ALIGNED @@ -256,6 +255,6 @@ UDC_DESC_STORAGE udc_config_t udc_config = { //@} //@} -#endif // SDSUPPORT +#endif // HAS_MEDIA #endif // ARDUINO_ARCH_SAM diff --git a/Marlin/src/HAL/DUE/usb/udi_composite_desc.c b/Marlin/src/HAL/DUE/usb/udi_composite_desc.c index da74fbe6..8fa5acbb 100644 --- a/Marlin/src/HAL/DUE/usb/udi_composite_desc.c +++ b/Marlin/src/HAL/DUE/usb/udi_composite_desc.c @@ -50,7 +50,7 @@ #include "udd.h" #include "udc_desc.h" -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA /** * \defgroup udi_group_desc Descriptors for a USB Device @@ -93,7 +93,6 @@ UDC_DESC_STORAGE usb_dev_desc_t udc_device_desc = { .bNumConfigurations = 1 }; - #ifdef USB_DEVICE_HS_SUPPORT //! USB Device Qualifier Descriptor for HS COMPILER_WORD_ALIGNED @@ -147,7 +146,6 @@ UDC_DESC_STORAGE udc_desc_t udc_desc_hs = { }; #endif - /** * \name UDC structures which contains all USB Device definitions */ @@ -189,4 +187,4 @@ UDC_DESC_STORAGE udc_config_t udc_config = { #endif // ARDUINO_ARCH_SAM -#endif // SDSUPPORT +#endif // HAS_MEDIA diff --git a/Marlin/src/HAL/DUE/usb/udi_msc.c b/Marlin/src/HAL/DUE/usb/udi_msc.c index dd340487..56664f4b 100644 --- a/Marlin/src/HAL/DUE/usb/udi_msc.c +++ b/Marlin/src/HAL/DUE/usb/udi_msc.c @@ -57,7 +57,7 @@ #include "ctrl_access.h" #include -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA #ifndef UDI_MSC_NOTIFY_TRANS_EXT # define UDI_MSC_NOTIFY_TRANS_EXT() @@ -86,7 +86,6 @@ UDC_DESC_STORAGE udi_api_t udi_api_msc = { }; //@} - /** * \ingroup udi_msc_group * \defgroup udi_msc_group_internal Implementation of UDI MSC @@ -137,7 +136,6 @@ volatile bool udi_msc_b_reset_trans = true; //@} - /** * \name Internal routines */ @@ -190,7 +188,6 @@ static void udi_msc_cbw_received(udd_ep_status_t status, static bool udi_msc_cbw_validate(uint32_t alloc_len, uint8_t dir_flag); //@} - /** * \name Routines to process small data packet */ @@ -217,7 +214,6 @@ static void udi_msc_data_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep); //@} - /** * \name Routines to process CSW packet */ @@ -250,7 +246,6 @@ static void udi_msc_csw_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep); //@} - /** * \name Routines manage sense data */ @@ -307,7 +302,6 @@ static void udi_msc_sense_fail_cdb_invalid(void); static void udi_msc_sense_command_invalid(void); //@} - /** * \name Routines manage SCSI Commands */ @@ -372,9 +366,7 @@ static void udi_msc_sbc_trans(bool b_read); //@} - -bool udi_msc_enable(void) -{ +bool udi_msc_enable(void) { uint8_t lun; udi_msc_b_trans_req = false; udi_msc_b_cbw_invalid = false; @@ -397,18 +389,14 @@ bool udi_msc_enable(void) return true; } - -void udi_msc_disable(void) -{ +void udi_msc_disable(void) { udi_msc_b_trans_req = false; udi_msc_b_ack_trans = true; udi_msc_b_reset_trans = true; UDI_MSC_DISABLE_EXT(); } - -bool udi_msc_setup(void) -{ +bool udi_msc_setup(void) { if (Udd_setup_is_in()) { // Requests Interface GET if (Udd_setup_type() == USB_REQ_TYPE_CLASS) { @@ -451,17 +439,14 @@ bool udi_msc_setup(void) return false; // Not supported request } -uint8_t udi_msc_getsetting(void) -{ +uint8_t udi_msc_getsetting(void) { return 0; // MSC don't have multiple alternate setting } - // ------------------------ //------- Routines to process CBW packet -static void udi_msc_cbw_invalid(void) -{ +static void udi_msc_cbw_invalid(void) { if (!udi_msc_b_cbw_invalid) return; // Don't re-stall endpoint if error reset by setup udd_ep_set_halt(UDI_MSC_EP_OUT); @@ -469,8 +454,7 @@ static void udi_msc_cbw_invalid(void) udd_ep_wait_stall_clear(UDI_MSC_EP_OUT, udi_msc_cbw_invalid); } -static void udi_msc_csw_invalid(void) -{ +static void udi_msc_csw_invalid(void) { if (!udi_msc_b_cbw_invalid) return; // Don't re-stall endpoint if error reset by setup udd_ep_set_halt(UDI_MSC_EP_IN); @@ -478,8 +462,7 @@ static void udi_msc_csw_invalid(void) udd_ep_wait_stall_clear(UDI_MSC_EP_IN, udi_msc_csw_invalid); } -static void udi_msc_cbw_wait(void) -{ +static void udi_msc_cbw_wait(void) { // Register buffer and callback on OUT endpoint if (!udd_ep_run(UDI_MSC_EP_OUT, true, (uint8_t *) & udi_msc_cbw, @@ -490,10 +473,8 @@ static void udi_msc_cbw_wait(void) } } - static void udi_msc_cbw_received(udd_ep_status_t status, - iram_size_t nb_received, udd_ep_id_t ep) -{ + iram_size_t nb_received, udd_ep_id_t ep) { UNUSED(ep); // Check status of transfer if (UDD_EP_TRANSFER_OK != status) { @@ -582,9 +563,7 @@ static void udi_msc_cbw_received(udd_ep_status_t status, } } - -static bool udi_msc_cbw_validate(uint32_t alloc_len, uint8_t dir_flag) -{ +static bool udi_msc_cbw_validate(uint32_t alloc_len, uint8_t dir_flag) { /* * The following cases should result in a phase error: * - Case 2: Hn < Di @@ -612,12 +591,10 @@ static bool udi_msc_cbw_validate(uint32_t alloc_len, uint8_t dir_flag) return true; } - // ------------------------ //------- Routines to process small data packet -static void udi_msc_data_send(uint8_t * buffer, uint8_t buf_size) -{ +static void udi_msc_data_send(uint8_t * buffer, uint8_t buf_size) { // Sends data on IN endpoint if (!udd_ep_run(UDI_MSC_EP_IN, true, buffer, buf_size, udi_msc_data_sent)) { @@ -627,10 +604,8 @@ static void udi_msc_data_send(uint8_t * buffer, uint8_t buf_size) } } - static void udi_msc_data_sent(udd_ep_status_t status, iram_size_t nb_sent, - udd_ep_id_t ep) -{ + udd_ep_id_t ep) { UNUSED(ep); if (UDD_EP_TRANSFER_OK != status) { // Error protocol @@ -644,12 +619,10 @@ static void udi_msc_data_sent(udd_ep_status_t status, iram_size_t nb_sent, udi_msc_csw_process(); } - // ------------------------ //------- Routines to process CSW packet -static void udi_msc_csw_process(void) -{ +static void udi_msc_csw_process(void) { if (0 != udi_msc_csw.dCSWDataResidue) { // Residue not NULL // then STALL next request from USB host on corresponding endpoint @@ -664,9 +637,7 @@ static void udi_msc_csw_process(void) udi_msc_csw_send(); } - -void udi_msc_csw_send(void) -{ +void udi_msc_csw_send(void) { // Sends CSW on IN endpoint if (!udd_ep_run(UDI_MSC_EP_IN, false, (uint8_t *) & udi_msc_csw, @@ -678,10 +649,8 @@ void udi_msc_csw_send(void) } } - static void udi_msc_csw_sent(udd_ep_status_t status, iram_size_t nb_sent, - udd_ep_id_t ep) -{ + udd_ep_id_t ep) { UNUSED(ep); UNUSED(status); UNUSED(nb_sent); @@ -690,20 +659,17 @@ static void udi_msc_csw_sent(udd_ep_status_t status, iram_size_t nb_sent, udi_msc_cbw_wait(); } - // ------------------------ //------- Routines manage sense data -static void udi_msc_clear_sense(void) -{ +static void udi_msc_clear_sense(void) { memset((uint8_t*)&udi_msc_sense, 0, sizeof(struct scsi_request_sense_data)); udi_msc_sense.valid_reponse_code = SCSI_SENSE_VALID | SCSI_SENSE_CURRENT; udi_msc_sense.AddSenseLen = SCSI_SENSE_ADDL_LEN(sizeof(udi_msc_sense)); } static void udi_msc_sense_fail(uint8_t sense_key, uint16_t add_sense, - uint32_t lba) -{ + uint32_t lba) { udi_msc_clear_sense(); udi_msc_csw.bCSWStatus = USB_CSW_STATUS_FAIL; udi_msc_sense.sense_flag_key = sense_key; @@ -715,53 +681,39 @@ static void udi_msc_sense_fail(uint8_t sense_key, uint16_t add_sense, udi_msc_sense.AddSnsCodeQlfr = add_sense; } -static void udi_msc_sense_pass(void) -{ +static void udi_msc_sense_pass(void) { udi_msc_clear_sense(); udi_msc_csw.bCSWStatus = USB_CSW_STATUS_PASS; } - -static void udi_msc_sense_fail_not_present(void) -{ +static void udi_msc_sense_fail_not_present(void) { udi_msc_sense_fail(SCSI_SK_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT, 0); } -static void udi_msc_sense_fail_busy_or_change(void) -{ - udi_msc_sense_fail(SCSI_SK_UNIT_ATTENTION, - SCSI_ASC_NOT_READY_TO_READY_CHANGE, 0); +static void udi_msc_sense_fail_busy_or_change(void) { + udi_msc_sense_fail(SCSI_SK_UNIT_ATTENTION, SCSI_ASC_NOT_READY_TO_READY_CHANGE, 0); } -static void udi_msc_sense_fail_hardware(void) -{ - udi_msc_sense_fail(SCSI_SK_HARDWARE_ERROR, - SCSI_ASC_NO_ADDITIONAL_SENSE_INFO, 0); +static void udi_msc_sense_fail_hardware(void) { + udi_msc_sense_fail(SCSI_SK_HARDWARE_ERROR, SCSI_ASC_NO_ADDITIONAL_SENSE_INFO, 0); } -static void udi_msc_sense_fail_protected(void) -{ +static void udi_msc_sense_fail_protected(void) { udi_msc_sense_fail(SCSI_SK_DATA_PROTECT, SCSI_ASC_WRITE_PROTECTED, 0); } -static void udi_msc_sense_fail_cdb_invalid(void) -{ - udi_msc_sense_fail(SCSI_SK_ILLEGAL_REQUEST, - SCSI_ASC_INVALID_FIELD_IN_CDB, 0); +static void udi_msc_sense_fail_cdb_invalid(void) { + udi_msc_sense_fail(SCSI_SK_ILLEGAL_REQUEST, SCSI_ASC_INVALID_FIELD_IN_CDB, 0); } -static void udi_msc_sense_command_invalid(void) -{ - udi_msc_sense_fail(SCSI_SK_ILLEGAL_REQUEST, - SCSI_ASC_INVALID_COMMAND_OPERATION_CODE, 0); +static void udi_msc_sense_command_invalid(void) { + udi_msc_sense_fail(SCSI_SK_ILLEGAL_REQUEST, SCSI_ASC_INVALID_COMMAND_OPERATION_CODE, 0); } - // ------------------------ //------- Routines manage SCSI Commands -static void udi_msc_spc_requestsense(void) -{ +static void udi_msc_spc_requestsense(void) { uint8_t length = udi_msc_cbw.CDB[4]; // Can't send more than sense data length @@ -774,9 +726,7 @@ static void udi_msc_spc_requestsense(void) udi_msc_data_send((uint8_t*)&udi_msc_sense, length); } - -static void udi_msc_spc_inquiry(void) -{ +static void udi_msc_spc_inquiry(void) { uint8_t length, i; UDC_DATA(4) // Constant inquiry data for all LUNs @@ -835,9 +785,7 @@ static void udi_msc_spc_inquiry(void) udi_msc_data_send((uint8_t *) & udi_msc_inquiry_data, length); } - -static bool udi_msc_spc_testunitready_global(void) -{ +static bool udi_msc_spc_testunitready_global(void) { switch (mem_test_unit_ready(udi_msc_cbw.bCBWLUN)) { case CTRL_GOOD: return true; // Don't change sense data @@ -855,9 +803,7 @@ static bool udi_msc_spc_testunitready_global(void) return false; } - -static void udi_msc_spc_testunitready(void) -{ +static void udi_msc_spc_testunitready(void) { if (udi_msc_spc_testunitready_global()) { // LUN ready, then update sense data with status pass udi_msc_sense_pass(); @@ -866,9 +812,7 @@ static void udi_msc_spc_testunitready(void) udi_msc_csw_process(); } - -static void udi_msc_spc_mode_sense(bool b_sense10) -{ +static void udi_msc_spc_mode_sense(bool b_sense10) { // Union of all mode sense structures union sense_6_10 { struct { @@ -943,9 +887,7 @@ static void udi_msc_spc_mode_sense(bool b_sense10) udi_msc_data_send((uint8_t *) & sense, request_lgt); } - -static void udi_msc_spc_prevent_allow_medium_removal(void) -{ +static void udi_msc_spc_prevent_allow_medium_removal(void) { uint8_t prevent = udi_msc_cbw.CDB[4]; if (0 == prevent) { udi_msc_sense_pass(); @@ -955,9 +897,7 @@ static void udi_msc_spc_prevent_allow_medium_removal(void) udi_msc_csw_process(); } - -static void udi_msc_sbc_start_stop(void) -{ +static void udi_msc_sbc_start_stop(void) { bool start = 0x1 & udi_msc_cbw.CDB[4]; bool loej = 0x2 & udi_msc_cbw.CDB[4]; if (loej) { @@ -967,9 +907,7 @@ static void udi_msc_sbc_start_stop(void) udi_msc_csw_process(); } - -static void udi_msc_sbc_read_capacity(void) -{ +static void udi_msc_sbc_read_capacity(void) { UDC_BSS(4) static struct sbc_read_capacity10_data udi_msc_capacity; if (!udi_msc_cbw_validate(sizeof(udi_msc_capacity), @@ -1003,9 +941,7 @@ static void udi_msc_sbc_read_capacity(void) sizeof(udi_msc_capacity)); } - -static void udi_msc_sbc_trans(bool b_read) -{ +static void udi_msc_sbc_trans(bool b_read) { uint32_t trans_size; if (!b_read) { @@ -1038,9 +974,7 @@ static void udi_msc_sbc_trans(bool b_read) UDI_MSC_NOTIFY_TRANS_EXT(); } - -bool udi_msc_process_trans(void) -{ +bool udi_msc_process_trans(void) { Ctrl_status status; if (!udi_msc_b_trans_req) @@ -1084,10 +1018,8 @@ bool udi_msc_process_trans(void) return true; } - static void udi_msc_trans_ack(udd_ep_status_t status, iram_size_t n, - udd_ep_id_t ep) -{ + udd_ep_id_t ep) { UNUSED(ep); UNUSED(n); // Update variable to signal the end of transfer @@ -1095,10 +1027,8 @@ static void udi_msc_trans_ack(udd_ep_status_t status, iram_size_t n, udi_msc_b_ack_trans = true; } - bool udi_msc_trans_block(bool b_read, uint8_t * block, iram_size_t block_size, - void (*callback) (udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep)) -{ + void (*callback) (udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep)) { if (!udi_msc_b_ack_trans) return false; // No possible, transfer on going @@ -1127,6 +1057,6 @@ bool udi_msc_trans_block(bool b_read, uint8_t * block, iram_size_t block_size, //@} -#endif // SDSUPPORT +#endif // HAS_MEDIA #endif // ARDUINO_ARCH_SAM diff --git a/Marlin/src/HAL/DUE/usb/udi_msc.h b/Marlin/src/HAL/DUE/usb/udi_msc.h index 730dbc8e..0ede4d6a 100644 --- a/Marlin/src/HAL/DUE/usb/udi_msc.h +++ b/Marlin/src/HAL/DUE/usb/udi_msc.h @@ -77,9 +77,9 @@ extern UDC_DESC_STORAGE udi_api_t udi_api_msc; //! Interface descriptor structure for MSC typedef struct { - usb_iface_desc_t iface; - usb_ep_desc_t ep_in; - usb_ep_desc_t ep_out; + usb_iface_desc_t iface; + usb_ep_desc_t ep_in; + usb_ep_desc_t ep_out; } udi_msc_desc_t; //! By default no string associated to this interface @@ -94,32 +94,32 @@ typedef struct { //! Content of MSC interface descriptor for all speeds #define UDI_MSC_DESC \ - .iface.bLength = sizeof(usb_iface_desc_t),\ - .iface.bDescriptorType = USB_DT_INTERFACE,\ - .iface.bInterfaceNumber = UDI_MSC_IFACE_NUMBER,\ - .iface.bAlternateSetting = 0,\ - .iface.bNumEndpoints = 2,\ - .iface.bInterfaceClass = MSC_CLASS,\ - .iface.bInterfaceSubClass = MSC_SUBCLASS_TRANSPARENT,\ - .iface.bInterfaceProtocol = MSC_PROTOCOL_BULK,\ - .iface.iInterface = UDI_MSC_STRING_ID,\ - .ep_in.bLength = sizeof(usb_ep_desc_t),\ - .ep_in.bDescriptorType = USB_DT_ENDPOINT,\ - .ep_in.bEndpointAddress = UDI_MSC_EP_IN,\ - .ep_in.bmAttributes = USB_EP_TYPE_BULK,\ - .ep_in.bInterval = 0,\ - .ep_out.bLength = sizeof(usb_ep_desc_t),\ - .ep_out.bDescriptorType = USB_DT_ENDPOINT,\ - .ep_out.bEndpointAddress = UDI_MSC_EP_OUT,\ - .ep_out.bmAttributes = USB_EP_TYPE_BULK,\ - .ep_out.bInterval = 0, + .iface.bLength = sizeof(usb_iface_desc_t),\ + .iface.bDescriptorType = USB_DT_INTERFACE,\ + .iface.bInterfaceNumber = UDI_MSC_IFACE_NUMBER,\ + .iface.bAlternateSetting = 0,\ + .iface.bNumEndpoints = 2,\ + .iface.bInterfaceClass = MSC_CLASS,\ + .iface.bInterfaceSubClass = MSC_SUBCLASS_TRANSPARENT,\ + .iface.bInterfaceProtocol = MSC_PROTOCOL_BULK,\ + .iface.iInterface = UDI_MSC_STRING_ID,\ + .ep_in.bLength = sizeof(usb_ep_desc_t),\ + .ep_in.bDescriptorType = USB_DT_ENDPOINT,\ + .ep_in.bEndpointAddress = UDI_MSC_EP_IN,\ + .ep_in.bmAttributes = USB_EP_TYPE_BULK,\ + .ep_in.bInterval = 0,\ + .ep_out.bLength = sizeof(usb_ep_desc_t),\ + .ep_out.bDescriptorType = USB_DT_ENDPOINT,\ + .ep_out.bEndpointAddress = UDI_MSC_EP_OUT,\ + .ep_out.bmAttributes = USB_EP_TYPE_BULK,\ + .ep_out.bInterval = 0, //! Content of MSC interface descriptor for full speed only #define UDI_MSC_DESC_FS {\ - UDI_MSC_DESC \ - .ep_in.wMaxPacketSize = LE16(UDI_MSC_EPS_SIZE_FS),\ - .ep_out.wMaxPacketSize = LE16(UDI_MSC_EPS_SIZE_FS),\ - } + UDI_MSC_DESC \ + .ep_in.wMaxPacketSize = LE16(UDI_MSC_EPS_SIZE_FS),\ + .ep_out.wMaxPacketSize = LE16(UDI_MSC_EPS_SIZE_FS),\ + } //! Content of MSC interface descriptor for high speed only #define UDI_MSC_DESC_HS {\ @@ -129,7 +129,6 @@ typedef struct { } //@} - /** * \ingroup udi_group * \defgroup udi_msc_group USB Device Interface (UDI) for Mass Storage Class (MSC) @@ -163,14 +162,13 @@ bool udi_msc_process_trans(void); * \return \c 1 if function was successfully done, otherwise \c 0. */ bool udi_msc_trans_block(bool b_read, uint8_t * block, iram_size_t block_size, - void (*callback) (udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep)); + void (*callback) (udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep)); //@} #ifdef __cplusplus } #endif - /** * \page udi_msc_quickstart Quick start guide for USB device Mass Storage module (UDI MSC) * @@ -200,35 +198,32 @@ bool udi_msc_trans_block(bool b_read, uint8_t * block, iram_size_t block_size, * \subsection udi_msc_basic_use_case_usage_code Example code * Content of conf_usb.h: * \code - #define USB_DEVICE_SERIAL_NAME "12...EF" // Disk SN for MSC - #define UDI_MSC_GLOBAL_VENDOR_ID \ - 'A', 'T', 'M', 'E', 'L', ' ', ' ', ' ' - #define UDI_MSC_GLOBAL_PRODUCT_VERSION \ - '1', '.', '0', '0' - #define UDI_MSC_ENABLE_EXT() my_callback_msc_enable() - extern bool my_callback_msc_enable(void); - #define UDI_MSC_DISABLE_EXT() my_callback_msc_disable() - extern void my_callback_msc_disable(void); - #include "udi_msc_conf.h" // At the end of conf_usb.h file + #define USB_DEVICE_SERIAL_NAME "12...EF" // Disk SN for MSC + #define UDI_MSC_GLOBAL_VENDOR_ID \ + 'A', 'T', 'M', 'E', 'L', ' ', ' ', ' ' + #define UDI_MSC_GLOBAL_PRODUCT_VERSION \ + '1', '.', '0', '0' + #define UDI_MSC_ENABLE_EXT() my_callback_msc_enable() + extern bool my_callback_msc_enable(void); + #define UDI_MSC_DISABLE_EXT() my_callback_msc_disable() + extern void my_callback_msc_disable(void); + #include "udi_msc_conf.h" // At the end of conf_usb.h file \endcode * * Add to application C-file: * \code - static bool my_flag_autorize_msc_transfert = false; - bool my_callback_msc_enable(void) - { - my_flag_autorize_msc_transfert = true; - return true; - } - void my_callback_msc_disable(void) - { - my_flag_autorize_msc_transfert = false; - } + static bool my_flag_autorize_msc_transfert = false; + bool my_callback_msc_enable(void) { + my_flag_autorize_msc_transfert = true; + return true; + } + void my_callback_msc_disable(void) { + my_flag_autorize_msc_transfert = false; + } - void task(void) - { - udi_msc_process_trans(); - } + void task(void) { + udi_msc_process_trans(); + } \endcode * * \subsection udi_msc_basic_use_case_setup_flow Workflow @@ -237,14 +232,14 @@ bool udi_msc_trans_block(bool b_read, uint8_t * block, iram_size_t block_size, * - \code #define USB_DEVICE_SERIAL_NAME "12...EF" // Disk SN for MSC \endcode * \note The USB serial number is mandatory when a MSC interface is used. * - \code //! Vendor name and Product version of MSC interface - #define UDI_MSC_GLOBAL_VENDOR_ID \ - 'A', 'T', 'M', 'E', 'L', ' ', ' ', ' ' - #define UDI_MSC_GLOBAL_PRODUCT_VERSION \ - '1', '.', '0', '0' \endcode + #define UDI_MSC_GLOBAL_VENDOR_ID \ + 'A', 'T', 'M', 'E', 'L', ' ', ' ', ' ' + #define UDI_MSC_GLOBAL_PRODUCT_VERSION \ + '1', '.', '0', '0' \endcode * \note The USB MSC interface requires a vendor ID (8 ASCII characters) * and a product version (4 ASCII characters). * - \code #define UDI_MSC_ENABLE_EXT() my_callback_msc_enable() - extern bool my_callback_msc_enable(void); \endcode + extern bool my_callback_msc_enable(void); \endcode * \note After the device enumeration (detecting and identifying USB devices), * the USB host starts the device configuration. When the USB MSC interface * from the device is accepted by the host, the USB host enables this interface and the @@ -252,7 +247,7 @@ bool udi_msc_trans_block(bool b_read, uint8_t * block, iram_size_t block_size, * Thus, when this event is received, the tasks which call * udi_msc_process_trans() must be enabled. * - \code #define UDI_MSC_DISABLE_EXT() my_callback_msc_disable() - extern void my_callback_msc_disable(void); \endcode + extern void my_callback_msc_disable(void); \endcode * \note When the USB device is unplugged or is reset by the USB host, the USB * interface is disabled and the UDI_MSC_DISABLE_EXT() callback function * is called. Thus, it is recommended to disable the task which is called udi_msc_process_trans(). @@ -261,15 +256,15 @@ bool udi_msc_trans_block(bool b_read, uint8_t * block, iram_size_t block_size, * must be done outside USB interrupt routine. This is done in the MSC process * ("udi_msc_process_trans()") called by main loop: * - \code * void task(void) { - udi_msc_process_trans(); - } \endcode + udi_msc_process_trans(); + } \endcode * -# The MSC speed depends on task periodicity. To get the best speed * the notification callback "UDI_MSC_NOTIFY_TRANS_EXT" can be used to wakeup * this task (Example, through a mutex): * - \code #define UDI_MSC_NOTIFY_TRANS_EXT() msc_notify_trans() - void msc_notify_trans(void) { - wakeup_my_task(); - } \endcode + void msc_notify_trans(void) { + wakeup_my_task(); + } \endcode * * \section udi_msc_use_cases Advanced use cases * For more advanced use of the UDI MSC module, see the following use cases: @@ -302,72 +297,72 @@ bool udi_msc_trans_block(bool b_read, uint8_t * block, iram_size_t block_size, * \subsection udi_msc_use_case_composite_usage_code Example code * Content of conf_usb.h: * \code - #define USB_DEVICE_EP_CTRL_SIZE 64 - #define USB_DEVICE_NB_INTERFACE (X+1) - #define USB_DEVICE_MAX_EP (X+2) + #define USB_DEVICE_EP_CTRL_SIZE 64 + #define USB_DEVICE_NB_INTERFACE (X+1) + #define USB_DEVICE_MAX_EP (X+2) - #define UDI_MSC_EP_IN (X | USB_EP_DIR_IN) - #define UDI_MSC_EP_OUT (Y | USB_EP_DIR_OUT) - #define UDI_MSC_IFACE_NUMBER X + #define UDI_MSC_EP_IN (X | USB_EP_DIR_IN) + #define UDI_MSC_EP_OUT (Y | USB_EP_DIR_OUT) + #define UDI_MSC_IFACE_NUMBER X - #define UDI_COMPOSITE_DESC_T \ - udi_msc_desc_t udi_msc; \ - ... - #define UDI_COMPOSITE_DESC_FS \ - .udi_msc = UDI_MSC_DESC, \ - ... - #define UDI_COMPOSITE_DESC_HS \ - .udi_msc = UDI_MSC_DESC, \ - ... - #define UDI_COMPOSITE_API \ - &udi_api_msc, \ - ... + #define UDI_COMPOSITE_DESC_T \ + udi_msc_desc_t udi_msc; \ + ... + #define UDI_COMPOSITE_DESC_FS \ + .udi_msc = UDI_MSC_DESC, \ + ... + #define UDI_COMPOSITE_DESC_HS \ + .udi_msc = UDI_MSC_DESC, \ + ... + #define UDI_COMPOSITE_API \ + &udi_api_msc, \ + ... \endcode * * \subsection udi_msc_use_case_composite_usage_flow Workflow * -# Ensure that conf_usb.h is available and contains the following parameters * required for a USB composite device configuration: * - \code // Endpoint control size, This must be: - // - 8, 16, 32 or 64 for full speed device (8 is recommended to save RAM) - // - 64 for a high speed device - #define USB_DEVICE_EP_CTRL_SIZE 64 - // Total Number of interfaces on this USB device. - // Add 1 for MSC. - #define USB_DEVICE_NB_INTERFACE (X+1) - // Total number of endpoints on this USB device. - // This must include each endpoint for each interface. - // Add 2 for MSC. - #define USB_DEVICE_MAX_EP (X+2) \endcode + // - 8, 16, 32 or 64 for full speed device (8 is recommended to save RAM) + // - 64 for a high speed device + #define USB_DEVICE_EP_CTRL_SIZE 64 + // Total Number of interfaces on this USB device. + // Add 1 for MSC. + #define USB_DEVICE_NB_INTERFACE (X+1) + // Total number of endpoints on this USB device. + // This must include each endpoint for each interface. + // Add 2 for MSC. + #define USB_DEVICE_MAX_EP (X+2) \endcode * -# Ensure that conf_usb.h contains the description of * composite device: * - \code // The endpoint numbers chosen by you for the MSC. - // The endpoint numbers starting from 1. - #define UDI_MSC_EP_IN (X | USB_EP_DIR_IN) - #define UDI_MSC_EP_OUT (Y | USB_EP_DIR_OUT) - // The interface index of an interface starting from 0 - #define UDI_MSC_IFACE_NUMBER X \endcode + // The endpoint numbers starting from 1. + #define UDI_MSC_EP_IN (X | USB_EP_DIR_IN) + #define UDI_MSC_EP_OUT (Y | USB_EP_DIR_OUT) + // The interface index of an interface starting from 0 + #define UDI_MSC_IFACE_NUMBER X \endcode * -# Ensure that conf_usb.h contains the following parameters * required for a USB composite device configuration: * - \code // USB Interfaces descriptor structure - #define UDI_COMPOSITE_DESC_T \ - ... - udi_msc_desc_t udi_msc; \ - ... - // USB Interfaces descriptor value for Full Speed - #define UDI_COMPOSITE_DESC_FS \ - ... - .udi_msc = UDI_MSC_DESC_FS, \ - ... - // USB Interfaces descriptor value for High Speed - #define UDI_COMPOSITE_DESC_HS \ - ... - .udi_msc = UDI_MSC_DESC_HS, \ - ... - // USB Interface APIs - #define UDI_COMPOSITE_API \ - ... - &udi_api_msc, \ - ... \endcode + #define UDI_COMPOSITE_DESC_T \ + ... + udi_msc_desc_t udi_msc; \ + ... + // USB Interfaces descriptor value for Full Speed + #define UDI_COMPOSITE_DESC_FS \ + ... + .udi_msc = UDI_MSC_DESC_FS, \ + ... + // USB Interfaces descriptor value for High Speed + #define UDI_COMPOSITE_DESC_HS \ + ... + .udi_msc = UDI_MSC_DESC_HS, \ + ... + // USB Interface APIs + #define UDI_COMPOSITE_API \ + ... + &udi_api_msc, \ + ... \endcode * - \note The descriptors order given in the four lists above must be the * same as the order defined by all interface indexes. The interface index * orders are defined through UDI_X_IFACE_NUMBER defines. diff --git a/Marlin/src/HAL/DUE/usb/uotghs_device_due.c b/Marlin/src/HAL/DUE/usb/uotghs_device_due.c index c7e8f8d9..01dda7e7 100644 --- a/Marlin/src/HAL/DUE/usb/uotghs_device_due.c +++ b/Marlin/src/HAL/DUE/usb/uotghs_device_due.c @@ -116,6 +116,23 @@ //#define dbg_print printf #define dbg_print(...) +// Marlin modification: Redefine the otg_freeze_clock and otg_unfreeze_clock macros +// to add memory barriers to ensure that any accesses to USB registers aren't re-ordered +// to occur while the clock is frozen. +#undef otg_freeze_clock +#undef otg_unfreeze_clock + +#define otg_freeze_clock() do { \ + __DSB(); \ + Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_FRZCLK); \ +} while (0) + +#define otg_unfreeze_clock() \ +do { \ + Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_FRZCLK); \ + __DSB(); \ +} while (0) + /** * \ingroup udd_group * \defgroup udd_udphs_group USB On-The-Go High-Speed Port for device mode (UOTGHS) @@ -276,7 +293,6 @@ # endif #endif - /** * \name Power management routine. */ @@ -293,7 +309,6 @@ static bool udd_b_idle; //! State of sleep manager static bool udd_b_sleep_initialized = false; - /*! \brief Authorize or not the CPU powerdown mode * * \param b_enable true to authorize idle mode @@ -321,7 +336,6 @@ static void udd_sleep_mode(bool b_idle) //@} - /** * \name Control endpoint low level management routine. * @@ -393,7 +407,6 @@ static void udd_ctrl_send_zlp_out(void); //! \brief Call callback associated to setup request static void udd_ctrl_endofrequest(void); - /** * \brief Main interrupt routine for control endpoint * @@ -405,7 +418,6 @@ static bool udd_ctrl_interrupt(void); //@} - /** * \name Management of bulk/interrupt/isochronous endpoints * @@ -443,7 +455,6 @@ typedef struct { uint8_t stall_requested:1; } udd_ep_job_t; - //! Array to register a job on bulk/interrupt/isochronous endpoint static udd_ep_job_t udd_ep_job[USB_DEVICE_MAX_EP]; @@ -505,7 +516,6 @@ static bool udd_ep_interrupt(void); #endif // (0!=USB_DEVICE_MAX_EP) //@} - // ------------------------ //--- INTERNAL ROUTINES TO MANAGED GLOBAL EVENTS @@ -611,6 +621,18 @@ ISR(UDD_USB_INT_FUN) // The wakeup interrupt is automatic acked when a suspend occur udd_disable_wake_up_interrupt(); udd_enable_suspend_interrupt(); + + // Marlin modification: The RESET, SOF, and MSOF interrupts were previously + // enabled in udd_attach, which caused a race condition where they could + // be raised and unclearable with the clock is frozen. They are now + // enabled here, after the clock has been unfrozen in response to the wake + // interrupt. + udd_enable_reset_interrupt(); + udd_enable_sof_interrupt(); +#ifdef USB_DEVICE_HS_SUPPORT + udd_enable_msof_interrupt(); +#endif + udd_sleep_mode(true); // Enter in IDLE mode #ifdef UDC_RESUME_EVENT UDC_RESUME_EVENT(); @@ -642,13 +664,11 @@ ISR(UDD_USB_INT_FUN) return; } - bool udd_include_vbus_monitoring(void) { return true; } - void udd_enable(void) { irqflags_t flags; @@ -735,7 +755,6 @@ void udd_enable(void) cpu_irq_restore(flags); } - void udd_disable(void) { irqflags_t flags; @@ -776,6 +795,27 @@ void udd_disable(void) cpu_irq_restore(flags); } +// Marlin modification: The original implementation did not use a memory +// barrier between disabling and clearing interrupts. This sometimes +// allowed interrupts to remain raised and unclearable after the clock +// was frozen. This helper was added to ensure that memory barriers +// are used consistently from all places where interrupts are disabled. +static void disable_and_ack_sync_interrupts() +{ + // Disable USB line events + udd_disable_reset_interrupt(); + udd_disable_sof_interrupt(); +#ifdef USB_DEVICE_HS_SUPPORT + udd_disable_msof_interrupt(); +#endif + __DSB(); + udd_ack_reset(); + udd_ack_sof(); +#ifdef USB_DEVICE_HS_SUPPORT + udd_ack_msof(); +#endif + __DSB(); +} void udd_attach(void) { @@ -796,17 +836,16 @@ void udd_attach(void) udd_attach_device(); // Enable USB line events - udd_enable_reset_interrupt(); udd_enable_suspend_interrupt(); udd_enable_wake_up_interrupt(); - udd_enable_sof_interrupt(); -#ifdef USB_DEVICE_HS_SUPPORT - udd_enable_msof_interrupt(); -#endif - // Reset following interrupts flag - udd_ack_reset(); - udd_ack_sof(); - udd_ack_msof(); + + // Marlin modification: The RESET, SOF, and MSOF interrupts were previously + // enabled here, which caused a race condition where they could be raised + // and unclearable with the clock is frozen. They are now enabled in the + // wake interrupt handler, after the clock has been unfrozen. They are now + // explicitly disabled here to ensure that they cannot be raised before + // the clock is frozen. + disable_and_ack_sync_interrupts(); // The first suspend interrupt must be forced // The first suspend interrupt is not detected else raise it @@ -817,18 +856,22 @@ void udd_attach(void) cpu_irq_restore(flags); } - void udd_detach(void) { otg_unfreeze_clock(); // Detach device from the bus udd_detach_device(); + + // Marlin modification: Added the explicit disabling of the RESET, SOF, and + // MSOF interrupts here, to ensure that they cannot be raised after the + // clock is frozen. + disable_and_ack_sync_interrupts(); + otg_freeze_clock(); udd_sleep_mode(false); } - bool udd_is_high_speed(void) { #ifdef USB_DEVICE_HS_SUPPORT @@ -838,7 +881,6 @@ bool udd_is_high_speed(void) #endif } - void udd_set_address(uint8_t address) { udd_disable_address(); @@ -846,13 +888,11 @@ void udd_set_address(uint8_t address) udd_enable_address(); } - uint8_t udd_getaddress(void) { return udd_get_configured_address(); } - uint16_t udd_get_frame_number(void) { return udd_frame_number(); @@ -875,14 +915,12 @@ void udd_send_remotewakeup(void) } } - void udd_set_setup_payload(uint8_t *payload, uint16_t payload_size) { udd_g_ctrlreq.payload = payload; udd_g_ctrlreq.payload_size = payload_size; } - #if (0 != USB_DEVICE_MAX_EP) bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes, uint16_t MaxEndpointSize) @@ -1006,7 +1044,6 @@ bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes, return true; } - void udd_ep_free(udd_ep_id_t ep) { uint8_t ep_index = ep & USB_EP_ADDR_MASK; @@ -1019,14 +1056,12 @@ void udd_ep_free(udd_ep_id_t ep) udd_ep_job[ep_index - 1].stall_requested = false; } - bool udd_ep_is_halted(udd_ep_id_t ep) { uint8_t ep_index = ep & USB_EP_ADDR_MASK; return Is_udd_endpoint_stall_requested(ep_index); } - bool udd_ep_set_halt(udd_ep_id_t ep) { uint8_t ep_index = ep & USB_EP_ADDR_MASK; @@ -1067,7 +1102,6 @@ bool udd_ep_set_halt(udd_ep_id_t ep) return true; } - bool udd_ep_clear_halt(udd_ep_id_t ep) { uint8_t ep_index = ep & USB_EP_ADDR_MASK; @@ -1108,7 +1142,6 @@ bool udd_ep_clear_halt(udd_ep_id_t ep) return true; } - bool udd_ep_run(udd_ep_id_t ep, bool b_shortpacket, uint8_t * buf, iram_size_t buf_size, udd_callback_trans_t callback) @@ -1175,7 +1208,6 @@ bool udd_ep_run(udd_ep_id_t ep, bool b_shortpacket, #endif } - void udd_ep_abort(udd_ep_id_t ep) { uint8_t ep_index = ep & USB_EP_ADDR_MASK; @@ -1204,7 +1236,6 @@ void udd_ep_abort(udd_ep_id_t ep) udd_ep_abort_job(ep); } - bool udd_ep_wait_stall_clear(udd_ep_id_t ep, udd_callback_halt_cleared_t callback) { @@ -1239,7 +1270,6 @@ bool udd_ep_wait_stall_clear(udd_ep_id_t ep, } #endif // (0 != USB_DEVICE_MAX_EP) - #ifdef USB_DEVICE_HS_SUPPORT void udd_test_mode_j(void) @@ -1248,20 +1278,17 @@ void udd_test_mode_j(void) udd_enable_hs_test_mode_j(); } - void udd_test_mode_k(void) { udd_enable_hs_test_mode(); udd_enable_hs_test_mode_k(); } - void udd_test_mode_se0_nak(void) { udd_enable_hs_test_mode(); } - void udd_test_mode_packet(void) { uint8_t i; @@ -1305,8 +1332,6 @@ void udd_test_mode_packet(void) } #endif // USB_DEVICE_HS_SUPPORT - - // ------------------------ //--- INTERNAL ROUTINES TO MANAGED THE CONTROL ENDPOINT @@ -1356,7 +1381,6 @@ static void udd_ctrl_init(void) udd_ep_control_state = UDD_EPCTRL_SETUP; } - static void udd_ctrl_setup_received(void) { irqflags_t flags; @@ -1418,7 +1442,6 @@ static void udd_ctrl_setup_received(void) } } - static void udd_ctrl_in_sent(void) { static bool b_shortpacket = false; @@ -1502,7 +1525,6 @@ static void udd_ctrl_in_sent(void) cpu_irq_restore(flags); } - static void udd_ctrl_out_received(void) { irqflags_t flags; @@ -1593,7 +1615,6 @@ static void udd_ctrl_out_received(void) cpu_irq_restore(flags); } - static void udd_ctrl_underflow(void) { if (Is_udd_out_received(0)) @@ -1610,7 +1631,6 @@ static void udd_ctrl_underflow(void) } } - static void udd_ctrl_overflow(void) { if (Is_udd_in_send(0)) @@ -1626,7 +1646,6 @@ static void udd_ctrl_overflow(void) } } - static void udd_ctrl_stall_data(void) { // Stall all packets on IN & OUT control endpoint @@ -1634,7 +1653,6 @@ static void udd_ctrl_stall_data(void) udd_enable_stall_handshake(0); } - static void udd_ctrl_send_zlp_in(void) { irqflags_t flags; @@ -1652,7 +1670,6 @@ static void udd_ctrl_send_zlp_in(void) cpu_irq_restore(flags); } - static void udd_ctrl_send_zlp_out(void) { irqflags_t flags; @@ -1668,7 +1685,6 @@ static void udd_ctrl_send_zlp_out(void) cpu_irq_restore(flags); } - static void udd_ctrl_endofrequest(void) { // If a callback is registered then call it @@ -1677,7 +1693,6 @@ static void udd_ctrl_endofrequest(void) } } - static bool udd_ctrl_interrupt(void) { @@ -1728,7 +1743,6 @@ static bool udd_ctrl_interrupt(void) return false; } - // ------------------------ //--- INTERNAL ROUTINES TO MANAGED THE BULK/INTERRUPT/ISOCHRONOUS ENDPOINTS @@ -1743,7 +1757,6 @@ static void udd_ep_job_table_reset(void) } } - static void udd_ep_job_table_kill(void) { uint8_t i; @@ -1754,7 +1767,6 @@ static void udd_ep_job_table_kill(void) } } - static void udd_ep_abort_job(udd_ep_id_t ep) { ep &= USB_EP_ADDR_MASK; @@ -1763,7 +1775,6 @@ static void udd_ep_abort_job(udd_ep_id_t ep) udd_ep_finish_job(&udd_ep_job[ep - 1], true, ep); } - static void udd_ep_finish_job(udd_ep_job_t * ptr_job, bool b_abort, uint8_t ep_num) { if (ptr_job->busy == false) { @@ -1834,7 +1845,6 @@ static void udd_ep_trans_done(udd_ep_id_t ep) udd_dma_ctrl |= UOTGHS_DEVDMACONTROL_END_BUFFIT | UOTGHS_DEVDMACONTROL_CHANN_ENB; - // Disable IRQs to have a short sequence // between read of EOT_STA and DMA enable flags = cpu_irq_save(); @@ -2043,6 +2053,12 @@ static bool udd_ep_interrupt(void) dbg_print("I "); udd_disable_in_send_interrupt(ep); // One bank is free then send a ZLP + + // Marlin modification: Add a barrier to ensure in_send is disabled + // before it is cleared. This was not an observed problem, but + // other interrupts were seen to misbehave without this barrier. + __DSB(); + udd_ack_in_send(ep); udd_ack_fifocon(ep); udd_ep_finish_job(ptr_job, false, ep); diff --git a/Marlin/src/HAL/DUE/usb/uotghs_device_due.h b/Marlin/src/HAL/DUE/usb/uotghs_device_due.h index 6df26d63..99ad492c 100644 --- a/Marlin/src/HAL/DUE/usb/uotghs_device_due.h +++ b/Marlin/src/HAL/DUE/usb/uotghs_device_due.h @@ -129,7 +129,6 @@ extern "C" { #define Is_udd_vbus_transition() (Tst_bits(UOTGHS->UOTGHS_SR, UOTGHS_SR_VBUSTI)) //! @} - //! @name UOTGHS device attach control //! These macros manage the UOTGHS Device attach. //! @{ @@ -141,7 +140,6 @@ extern "C" { #define Is_udd_detached() (Tst_bits(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_DETACH)) //! @} - //! @name UOTGHS device bus events control //! These macros manage the UOTGHS Device bus events. //! @{ @@ -246,7 +244,6 @@ extern "C" { #define udd_get_configured_address() (Rd_bitfield(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_UADD_Msk)) //! @} - //! @name UOTGHS Device endpoint drivers //! These macros manage the common features of the endpoints. //! @{ @@ -330,7 +327,6 @@ extern "C" { #define udd_data_toggle(ep) (Rd_bitfield(UOTGHS_ARRAY(UOTGHS_DEVEPTISR[0], ep), UOTGHS_DEVEPTISR_DTSEQ_Msk)) //! @} - //! @name UOTGHS Device control endpoint //! These macros control the endpoints. //! @{ @@ -530,7 +526,6 @@ extern "C" { //! Tests if IN sending interrupt is enabled #define Is_udd_in_send_interrupt_enabled(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTIMR[0], ep), UOTGHS_DEVEPTIMR_TXINE)) - //! Get 64-, 32-, 16- or 8-bit access to FIFO data register of selected endpoint. //! @param ep Endpoint of which to access FIFO data register //! @param scale Data scale in bits: 64, 32, 16 or 8 @@ -652,7 +647,6 @@ typedef struct { //! @} //! @} - /// @cond 0 /**INDENT-OFF**/ #ifdef __cplusplus diff --git a/Marlin/src/HAL/DUE/usb/uotghs_otg.h b/Marlin/src/HAL/DUE/usb/uotghs_otg.h index eca5e938..8c12a3e2 100644 --- a/Marlin/src/HAL/DUE/usb/uotghs_otg.h +++ b/Marlin/src/HAL/DUE/usb/uotghs_otg.h @@ -53,7 +53,6 @@ extern "C" { #endif - //! \ingroup usb_group //! \defgroup otg_group UOTGHS OTG Driver //! UOTGHS low-level driver for OTG features @@ -74,7 +73,6 @@ bool otg_dual_enable(void); */ void otg_dual_disable(void); - //! @name UOTGHS OTG ID pin management //! The ID pin come from the USB OTG connector (A and B receptable) and //! allows to select the USB mode host or device. @@ -127,13 +125,13 @@ void otg_dual_disable(void); //! These macros allows to enable/disable pad and UOTGHS hardware //! @{ //! Reset USB macro -#define otg_reset() \ - do { \ - UOTGHS->UOTGHS_CTRL = 0; \ - while( UOTGHS->UOTGHS_SR & 0x3FFF) {\ - UOTGHS->UOTGHS_SCR = 0xFFFFFFFF;\ - } \ - } while (0) +#define otg_reset() \ + do { \ + UOTGHS->UOTGHS_CTRL = 0; \ + while( UOTGHS->UOTGHS_SR & 0x3FFF) { \ + UOTGHS->UOTGHS_SCR = 0xFFFFFFFF; \ + } \ + } while (0) //! Enable USB macro #define otg_enable() (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_USBE)) //! Disable USB macro @@ -157,15 +155,14 @@ void otg_dual_disable(void); //! Configure time-out of specified OTG timer #define otg_configure_timeout(timer, timeout) (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UNLOCK),\ - Wr_bitfield(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_TIMPAGE_Msk, timer),\ - Wr_bitfield(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_TIMVALUE_Msk, timeout),\ - Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UNLOCK)) + Wr_bitfield(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_TIMPAGE_Msk, timer),\ + Wr_bitfield(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_TIMVALUE_Msk, timeout),\ + Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UNLOCK)) //! Get configured time-out of specified OTG timer #define otg_get_timeout(timer) (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UNLOCK),\ - Wr_bitfield(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_TIMPAGE_Msk, timer),\ - Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UNLOCK),\ - Rd_bitfield(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_TIMVALUE_Msk)) - + Wr_bitfield(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_TIMPAGE_Msk, timer),\ + Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UNLOCK),\ + Rd_bitfield(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_TIMVALUE_Msk)) //! Get the dual-role device state of the internal USB finite state machine of the UOTGHS controller #define otg_get_fsm_drd_state() (Rd_bitfield(UOTGHS->UOTGHS_FSM, UOTGHS_FSM_DRDSTATE_Msk)) diff --git a/Marlin/src/HAL/DUE/usb/usb_protocol.h b/Marlin/src/HAL/DUE/usb/usb_protocol.h index ea51a868..9bf0a1ba 100644 --- a/Marlin/src/HAL/DUE/usb/usb_protocol.h +++ b/Marlin/src/HAL/DUE/usb/usb_protocol.h @@ -108,17 +108,17 @@ * \brief Standard USB requests (bRequest) */ enum usb_reqid { - USB_REQ_GET_STATUS = 0, - USB_REQ_CLEAR_FEATURE = 1, - USB_REQ_SET_FEATURE = 3, - USB_REQ_SET_ADDRESS = 5, - USB_REQ_GET_DESCRIPTOR = 6, - USB_REQ_SET_DESCRIPTOR = 7, - USB_REQ_GET_CONFIGURATION = 8, - USB_REQ_SET_CONFIGURATION = 9, - USB_REQ_GET_INTERFACE = 10, - USB_REQ_SET_INTERFACE = 11, - USB_REQ_SYNCH_FRAME = 12, + USB_REQ_GET_STATUS = 0, + USB_REQ_CLEAR_FEATURE = 1, + USB_REQ_SET_FEATURE = 3, + USB_REQ_SET_ADDRESS = 5, + USB_REQ_GET_DESCRIPTOR = 6, + USB_REQ_SET_DESCRIPTOR = 7, + USB_REQ_GET_CONFIGURATION = 8, + USB_REQ_SET_CONFIGURATION = 9, + USB_REQ_GET_INTERFACE = 10, + USB_REQ_SET_INTERFACE = 11, + USB_REQ_SYNCH_FRAME = 12, }; /** @@ -126,9 +126,9 @@ enum usb_reqid { * */ enum usb_device_status { - USB_DEV_STATUS_BUS_POWERED = 0, - USB_DEV_STATUS_SELF_POWERED = 1, - USB_DEV_STATUS_REMOTEWAKEUP = 2 + USB_DEV_STATUS_BUS_POWERED = 0, + USB_DEV_STATUS_SELF_POWERED = 1, + USB_DEV_STATUS_REMOTEWAKEUP = 2 }; /** @@ -136,7 +136,7 @@ enum usb_device_status { * */ enum usb_interface_status { - USB_IFACE_STATUS_RESERVED = 0 + USB_IFACE_STATUS_RESERVED = 0 }; /** @@ -144,7 +144,7 @@ enum usb_interface_status { * */ enum usb_endpoint_status { - USB_EP_STATUS_HALTED = 1, + USB_EP_STATUS_HALTED = 1, }; /** @@ -153,11 +153,11 @@ enum usb_endpoint_status { * \note valid for SetFeature request. */ enum usb_device_feature { - USB_DEV_FEATURE_REMOTE_WAKEUP = 1, //!< Remote wakeup enabled - USB_DEV_FEATURE_TEST_MODE = 2, //!< USB test mode - USB_DEV_FEATURE_OTG_B_HNP_ENABLE = 3, - USB_DEV_FEATURE_OTG_A_HNP_SUPPORT = 4, - USB_DEV_FEATURE_OTG_A_ALT_HNP_SUPPORT = 5 + USB_DEV_FEATURE_REMOTE_WAKEUP = 1, //!< Remote wakeup enabled + USB_DEV_FEATURE_TEST_MODE = 2, //!< USB test mode + USB_DEV_FEATURE_OTG_B_HNP_ENABLE = 3, + USB_DEV_FEATURE_OTG_A_HNP_SUPPORT = 4, + USB_DEV_FEATURE_OTG_A_ALT_HNP_SUPPORT = 5 }; /** @@ -166,54 +166,54 @@ enum usb_device_feature { * \note valid for USB_DEV_FEATURE_TEST_MODE request. */ enum usb_device_hs_test_mode { - USB_DEV_TEST_MODE_J = 1, - USB_DEV_TEST_MODE_K = 2, - USB_DEV_TEST_MODE_SE0_NAK = 3, - USB_DEV_TEST_MODE_PACKET = 4, - USB_DEV_TEST_MODE_FORCE_ENABLE = 5, + USB_DEV_TEST_MODE_J = 1, + USB_DEV_TEST_MODE_K = 2, + USB_DEV_TEST_MODE_SE0_NAK = 3, + USB_DEV_TEST_MODE_PACKET = 4, + USB_DEV_TEST_MODE_FORCE_ENABLE = 5, }; /** * \brief Standard USB endpoint feature/status flags */ enum usb_endpoint_feature { - USB_EP_FEATURE_HALT = 0, + USB_EP_FEATURE_HALT = 0, }; /** * \brief Standard USB Test Mode Selectors */ enum usb_test_mode_selector { - USB_TEST_J = 0x01, - USB_TEST_K = 0x02, - USB_TEST_SE0_NAK = 0x03, - USB_TEST_PACKET = 0x04, - USB_TEST_FORCE_ENABLE = 0x05, + USB_TEST_J = 0x01, + USB_TEST_K = 0x02, + USB_TEST_SE0_NAK = 0x03, + USB_TEST_PACKET = 0x04, + USB_TEST_FORCE_ENABLE = 0x05, }; /** * \brief Standard USB descriptor types */ enum usb_descriptor_type { - USB_DT_DEVICE = 1, - USB_DT_CONFIGURATION = 2, - USB_DT_STRING = 3, - USB_DT_INTERFACE = 4, - USB_DT_ENDPOINT = 5, - USB_DT_DEVICE_QUALIFIER = 6, - USB_DT_OTHER_SPEED_CONFIGURATION = 7, - USB_DT_INTERFACE_POWER = 8, - USB_DT_OTG = 9, - USB_DT_IAD = 0x0B, - USB_DT_BOS = 0x0F, - USB_DT_DEVICE_CAPABILITY = 0x10, + USB_DT_DEVICE = 1, + USB_DT_CONFIGURATION = 2, + USB_DT_STRING = 3, + USB_DT_INTERFACE = 4, + USB_DT_ENDPOINT = 5, + USB_DT_DEVICE_QUALIFIER = 6, + USB_DT_OTHER_SPEED_CONFIGURATION = 7, + USB_DT_INTERFACE_POWER = 8, + USB_DT_OTG = 9, + USB_DT_IAD = 0x0B, + USB_DT_BOS = 0x0F, + USB_DT_DEVICE_CAPABILITY = 0x10, }; /** * \brief USB Device Capability types */ enum usb_capability_type { - USB_DC_USB20_EXTENSION = 0x02, + USB_DC_USB20_EXTENSION = 0x02, }; /** @@ -221,7 +221,7 @@ enum usb_capability_type { * To fill bmAttributes field of usb_capa_ext_desc_t structure. */ enum usb_capability_extension_attr { - USB_DC_EXT_LPM = 0x00000002, + USB_DC_EXT_LPM = 0x00000002, }; #define HIRD_50_US 0 @@ -254,18 +254,18 @@ enum usb_capability_extension_attr { * \brief Standard USB endpoint transfer types */ enum usb_ep_type { - USB_EP_TYPE_CONTROL = 0x00, - USB_EP_TYPE_ISOCHRONOUS = 0x01, - USB_EP_TYPE_BULK = 0x02, - USB_EP_TYPE_INTERRUPT = 0x03, - USB_EP_TYPE_MASK = 0x03, + USB_EP_TYPE_CONTROL = 0x00, + USB_EP_TYPE_ISOCHRONOUS = 0x01, + USB_EP_TYPE_BULK = 0x02, + USB_EP_TYPE_INTERRUPT = 0x03, + USB_EP_TYPE_MASK = 0x03, }; /** * \brief Standard USB language IDs for string descriptors */ enum usb_langid { - USB_LANGID_EN_US = 0x0409, //!< English (United States) + USB_LANGID_EN_US = 0x0409, //!< English (United States) }; /** @@ -308,31 +308,31 @@ COMPILER_PACK_SET(1) * The data payload of SETUP packets always follows this structure. */ typedef struct { - uint8_t bmRequestType; - uint8_t bRequest; - le16_t wValue; - le16_t wIndex; - le16_t wLength; + uint8_t bmRequestType; + uint8_t bRequest; + le16_t wValue; + le16_t wIndex; + le16_t wLength; } usb_setup_req_t; /** * \brief Standard USB device descriptor structure */ typedef struct { - uint8_t bLength; - uint8_t bDescriptorType; - le16_t bcdUSB; - uint8_t bDeviceClass; - uint8_t bDeviceSubClass; - uint8_t bDeviceProtocol; - uint8_t bMaxPacketSize0; - le16_t idVendor; - le16_t idProduct; - le16_t bcdDevice; - uint8_t iManufacturer; - uint8_t iProduct; - uint8_t iSerialNumber; - uint8_t bNumConfigurations; + uint8_t bLength; + uint8_t bDescriptorType; + le16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + le16_t idVendor; + le16_t idProduct; + le16_t bcdDevice; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; + uint8_t bNumConfigurations; } usb_dev_desc_t; /** @@ -344,15 +344,15 @@ typedef struct { * the device was operating at full speed.) */ typedef struct { - uint8_t bLength; - uint8_t bDescriptorType; - le16_t bcdUSB; - uint8_t bDeviceClass; - uint8_t bDeviceSubClass; - uint8_t bDeviceProtocol; - uint8_t bMaxPacketSize0; - uint8_t bNumConfigurations; - uint8_t bReserved; + uint8_t bLength; + uint8_t bDescriptorType; + le16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint8_t bNumConfigurations; + uint8_t bReserved; } usb_dev_qual_desc_t; /** @@ -368,23 +368,22 @@ typedef struct { * The descriptor type in the GetDescriptor() request is set to BOS. */ typedef struct { - uint8_t bLength; - uint8_t bDescriptorType; - le16_t wTotalLength; - uint8_t bNumDeviceCaps; + uint8_t bLength; + uint8_t bDescriptorType; + le16_t wTotalLength; + uint8_t bNumDeviceCaps; } usb_dev_bos_desc_t; - /** * \brief USB Device Capabilities - USB 2.0 Extension Descriptor structure * * Defines the set of USB 1.1-specific device level capabilities. */ typedef struct { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDevCapabilityType; - le32_t bmAttributes; + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + le32_t bmAttributes; } usb_dev_capa_ext_desc_t; /** @@ -393,40 +392,38 @@ typedef struct { * The BOS descriptor and capabilities descriptors for LPM. */ typedef struct { - usb_dev_bos_desc_t bos; - usb_dev_capa_ext_desc_t capa_ext; + usb_dev_bos_desc_t bos; + usb_dev_capa_ext_desc_t capa_ext; } usb_dev_lpm_desc_t; /** * \brief Standard USB Interface Association Descriptor structure */ typedef struct { - uint8_t bLength; //!< size of this descriptor in bytes - uint8_t bDescriptorType; //!< INTERFACE descriptor type - uint8_t bFirstInterface; //!< Number of interface - uint8_t bInterfaceCount; //!< value to select alternate setting - uint8_t bFunctionClass; //!< Class code assigned by the USB - uint8_t bFunctionSubClass;//!< Sub-class code assigned by the USB - uint8_t bFunctionProtocol;//!< Protocol code assigned by the USB - uint8_t iFunction; //!< Index of string descriptor + uint8_t bLength; //!< size of this descriptor in bytes + uint8_t bDescriptorType; //!< INTERFACE descriptor type + uint8_t bFirstInterface; //!< Number of interface + uint8_t bInterfaceCount; //!< value to select alternate setting + uint8_t bFunctionClass; //!< Class code assigned by the USB + uint8_t bFunctionSubClass;//!< Sub-class code assigned by the USB + uint8_t bFunctionProtocol;//!< Protocol code assigned by the USB + uint8_t iFunction; //!< Index of string descriptor } usb_association_desc_t; - /** * \brief Standard USB configuration descriptor structure */ typedef struct { - uint8_t bLength; - uint8_t bDescriptorType; - le16_t wTotalLength; - uint8_t bNumInterfaces; - uint8_t bConfigurationValue; - uint8_t iConfiguration; - uint8_t bmAttributes; - uint8_t bMaxPower; + uint8_t bLength; + uint8_t bDescriptorType; + le16_t wTotalLength; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t bMaxPower; } usb_conf_desc_t; - #define USB_CONFIG_ATTR_MUST_SET (1 << 7) //!< Must always be set #define USB_CONFIG_ATTR_BUS_POWERED (0 << 6) //!< Bus-powered #define USB_CONFIG_ATTR_SELF_POWERED (1 << 6) //!< Self-powered @@ -438,55 +435,54 @@ typedef struct { * \brief Standard USB association descriptor structure */ typedef struct { - uint8_t bLength; //!< Size of this descriptor in bytes - uint8_t bDescriptorType; //!< Interface descriptor type - uint8_t bFirstInterface; //!< Number of interface - uint8_t bInterfaceCount; //!< value to select alternate setting - uint8_t bFunctionClass; //!< Class code assigned by the USB - uint8_t bFunctionSubClass; //!< Sub-class code assigned by the USB - uint8_t bFunctionProtocol; //!< Protocol code assigned by the USB - uint8_t iFunction; //!< Index of string descriptor + uint8_t bLength; //!< Size of this descriptor in bytes + uint8_t bDescriptorType; //!< Interface descriptor type + uint8_t bFirstInterface; //!< Number of interface + uint8_t bInterfaceCount; //!< value to select alternate setting + uint8_t bFunctionClass; //!< Class code assigned by the USB + uint8_t bFunctionSubClass; //!< Sub-class code assigned by the USB + uint8_t bFunctionProtocol; //!< Protocol code assigned by the USB + uint8_t iFunction; //!< Index of string descriptor } usb_iad_desc_t; /** * \brief Standard USB interface descriptor structure */ typedef struct { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bInterfaceNumber; - uint8_t bAlternateSetting; - uint8_t bNumEndpoints; - uint8_t bInterfaceClass; - uint8_t bInterfaceSubClass; - uint8_t bInterfaceProtocol; - uint8_t iInterface; + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; } usb_iface_desc_t; /** * \brief Standard USB endpoint descriptor structure */ typedef struct { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bEndpointAddress; - uint8_t bmAttributes; - le16_t wMaxPacketSize; - uint8_t bInterval; + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + le16_t wMaxPacketSize; + uint8_t bInterval; } usb_ep_desc_t; - /** * \brief A standard USB string descriptor structure */ typedef struct { - uint8_t bLength; - uint8_t bDescriptorType; + uint8_t bLength; + uint8_t bDescriptorType; } usb_str_desc_t; typedef struct { - usb_str_desc_t desc; - le16_t string[1]; + usb_str_desc_t desc; + le16_t string[1]; } usb_str_lgid_desc_t; COMPILER_PACK_RESET() diff --git a/Marlin/src/HAL/DUE/usb/usb_protocol_cdc.h b/Marlin/src/HAL/DUE/usb/usb_protocol_cdc.h index d594db52..769e7589 100644 --- a/Marlin/src/HAL/DUE/usb/usb_protocol_cdc.h +++ b/Marlin/src/HAL/DUE/usb/usb_protocol_cdc.h @@ -58,42 +58,42 @@ * \name Possible values of class */ //@{ -#define CDC_CLASS_DEVICE 0x02 //!< USB Communication Device Class -#define CDC_CLASS_COMM 0x02 //!< CDC Communication Class Interface -#define CDC_CLASS_DATA 0x0A //!< CDC Data Class Interface +#define CDC_CLASS_DEVICE 0x02 //!< USB Communication Device Class +#define CDC_CLASS_COMM 0x02 //!< CDC Communication Class Interface +#define CDC_CLASS_DATA 0x0A //!< CDC Data Class Interface #define CDC_CLASS_MULTI 0xEF //!< CDC Multi-interface Function //@} //! \name USB CDC Subclass IDs //@{ -#define CDC_SUBCLASS_DLCM 0x01 //!< Direct Line Control Model -#define CDC_SUBCLASS_ACM 0x02 //!< Abstract Control Model -#define CDC_SUBCLASS_TCM 0x03 //!< Telephone Control Model -#define CDC_SUBCLASS_MCCM 0x04 //!< Multi-Channel Control Model -#define CDC_SUBCLASS_CCM 0x05 //!< CAPI Control Model -#define CDC_SUBCLASS_ETH 0x06 //!< Ethernet Networking Control Model -#define CDC_SUBCLASS_ATM 0x07 //!< ATM Networking Control Model +#define CDC_SUBCLASS_DLCM 0x01 //!< Direct Line Control Model +#define CDC_SUBCLASS_ACM 0x02 //!< Abstract Control Model +#define CDC_SUBCLASS_TCM 0x03 //!< Telephone Control Model +#define CDC_SUBCLASS_MCCM 0x04 //!< Multi-Channel Control Model +#define CDC_SUBCLASS_CCM 0x05 //!< CAPI Control Model +#define CDC_SUBCLASS_ETH 0x06 //!< Ethernet Networking Control Model +#define CDC_SUBCLASS_ATM 0x07 //!< ATM Networking Control Model //@} //! \name USB CDC Communication Interface Protocol IDs //@{ -#define CDC_PROTOCOL_V25TER 0x01 //!< Common AT commands +#define CDC_PROTOCOL_V25TER 0x01 //!< Common AT commands //@} //! \name USB CDC Data Interface Protocol IDs //@{ -#define CDC_PROTOCOL_I430 0x30 //!< ISDN BRI -#define CDC_PROTOCOL_HDLC 0x31 //!< HDLC -#define CDC_PROTOCOL_TRANS 0x32 //!< Transparent -#define CDC_PROTOCOL_Q921M 0x50 //!< Q.921 management protocol -#define CDC_PROTOCOL_Q921 0x51 //!< Q.931 [sic] Data link protocol -#define CDC_PROTOCOL_Q921TM 0x52 //!< Q.921 TEI-multiplexor -#define CDC_PROTOCOL_V42BIS 0x90 //!< Data compression procedures -#define CDC_PROTOCOL_Q931 0x91 //!< Euro-ISDN protocol control -#define CDC_PROTOCOL_V120 0x92 //!< V.24 rate adaption to ISDN -#define CDC_PROTOCOL_CAPI20 0x93 //!< CAPI Commands -#define CDC_PROTOCOL_HOST 0xFD //!< Host based driver +#define CDC_PROTOCOL_I430 0x30 //!< ISDN BRI +#define CDC_PROTOCOL_HDLC 0x31 //!< HDLC +#define CDC_PROTOCOL_TRANS 0x32 //!< Transparent +#define CDC_PROTOCOL_Q921M 0x50 //!< Q.921 management protocol +#define CDC_PROTOCOL_Q921 0x51 //!< Q.931 [sic] Data link protocol +#define CDC_PROTOCOL_Q921TM 0x52 //!< Q.921 TEI-multiplexor +#define CDC_PROTOCOL_V42BIS 0x90 //!< Data compression procedures +#define CDC_PROTOCOL_Q931 0x91 //!< Euro-ISDN protocol control +#define CDC_PROTOCOL_V120 0x92 //!< V.24 rate adaption to ISDN +#define CDC_PROTOCOL_CAPI20 0x93 //!< CAPI Commands +#define CDC_PROTOCOL_HOST 0xFD //!< Host based driver /** * \brief Describes the Protocol Unit Functional Descriptors [sic] * on Communication Class Interface @@ -103,16 +103,16 @@ //! \name USB CDC Functional Descriptor Types //@{ -#define CDC_CS_INTERFACE 0x24 //!< Interface Functional Descriptor -#define CDC_CS_ENDPOINT 0x25 //!< Endpoint Functional Descriptor +#define CDC_CS_INTERFACE 0x24 //!< Interface Functional Descriptor +#define CDC_CS_ENDPOINT 0x25 //!< Endpoint Functional Descriptor //@} //! \name USB CDC Functional Descriptor Subtypes //@{ -#define CDC_SCS_HEADER 0x00 //!< Header Functional Descriptor -#define CDC_SCS_CALL_MGMT 0x01 //!< Call Management -#define CDC_SCS_ACM 0x02 //!< Abstract Control Management -#define CDC_SCS_UNION 0x06 //!< Union Functional Descriptor +#define CDC_SCS_HEADER 0x00 //!< Header Functional Descriptor +#define CDC_SCS_CALL_MGMT 0x01 //!< Call Management +#define CDC_SCS_ACM 0x02 //!< Abstract Control Management +#define CDC_SCS_UNION 0x06 //!< Union Functional Descriptor //@} //! \name USB CDC Request IDs @@ -168,42 +168,40 @@ COMPILER_PACK_SET(1) //! \name USB CDC Descriptors //@{ - //! CDC Header Functional Descriptor typedef struct { - uint8_t bFunctionLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubtype; - le16_t bcdCDC; + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + le16_t bcdCDC; } usb_cdc_hdr_desc_t; //! CDC Call Management Functional Descriptor typedef struct { - uint8_t bFunctionLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubtype; - uint8_t bmCapabilities; - uint8_t bDataInterface; + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bmCapabilities; + uint8_t bDataInterface; } usb_cdc_call_mgmt_desc_t; //! CDC ACM Functional Descriptor typedef struct { - uint8_t bFunctionLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubtype; - uint8_t bmCapabilities; + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bmCapabilities; } usb_cdc_acm_desc_t; //! CDC Union Functional Descriptor typedef struct { - uint8_t bFunctionLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubtype; - uint8_t bMasterInterface; - uint8_t bSlaveInterface0; + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bMasterInterface; + uint8_t bSlaveInterface0; } usb_cdc_union_desc_t; - //! \name USB CDC Call Management Capabilities //@{ //! Device handles call management itself @@ -235,24 +233,24 @@ typedef struct { //@{ //! Line Coding structure typedef struct { - le32_t dwDTERate; - uint8_t bCharFormat; - uint8_t bParityType; - uint8_t bDataBits; + le32_t dwDTERate; + uint8_t bCharFormat; + uint8_t bParityType; + uint8_t bDataBits; } usb_cdc_line_coding_t; //! Possible values of bCharFormat enum cdc_char_format { - CDC_STOP_BITS_1 = 0, //!< 1 stop bit - CDC_STOP_BITS_1_5 = 1, //!< 1.5 stop bits - CDC_STOP_BITS_2 = 2, //!< 2 stop bits + CDC_STOP_BITS_1 = 0, //!< 1 stop bit + CDC_STOP_BITS_1_5 = 1, //!< 1.5 stop bits + CDC_STOP_BITS_2 = 2, //!< 2 stop bits }; //! Possible values of bParityType enum cdc_parity { - CDC_PAR_NONE = 0, //!< No parity - CDC_PAR_ODD = 1, //!< Odd parity - CDC_PAR_EVEN = 2, //!< Even parity - CDC_PAR_MARK = 3, //!< Parity forced to 0 (space) - CDC_PAR_SPACE = 4, //!< Parity forced to 1 (mark) + CDC_PAR_NONE = 0, //!< No parity + CDC_PAR_ODD = 1, //!< Odd parity + CDC_PAR_EVEN = 2, //!< Even parity + CDC_PAR_MARK = 3, //!< Parity forced to 0 (space) + CDC_PAR_SPACE = 4, //!< Parity forced to 1 (mark) }; //@} @@ -262,7 +260,7 @@ enum cdc_parity { //! Control signal structure typedef struct { - uint16_t value; + uint16_t value; } usb_cdc_control_signal_t; //! \name Possible values in usb_cdc_control_signal_t @@ -278,16 +276,15 @@ typedef struct { //@} //@} - //! \name USB CDC notification message //@{ typedef struct { - uint8_t bmRequestType; - uint8_t bNotification; - le16_t wValue; - le16_t wIndex; - le16_t wLength; + uint8_t bmRequestType; + uint8_t bNotification; + le16_t wValue; + le16_t wIndex; + le16_t wLength; } usb_cdc_notify_msg_t; //! \name USB CDC serial state @@ -295,8 +292,8 @@ typedef struct { //! Hardware handshake support (cdc spec 1.1 chapter 6.3.5) typedef struct { - usb_cdc_notify_msg_t header; - le16_t value; + usb_cdc_notify_msg_t header; + le16_t value; } usb_cdc_notify_serial_state_t; //! \name Possible values in usb_cdc_notify_serial_state_t diff --git a/Marlin/src/HAL/DUE/usb/usb_protocol_msc.h b/Marlin/src/HAL/DUE/usb/usb_protocol_msc.h index e1e59237..227a13dc 100644 --- a/Marlin/src/HAL/DUE/usb/usb_protocol_msc.h +++ b/Marlin/src/HAL/DUE/usb/usb_protocol_msc.h @@ -47,7 +47,6 @@ #ifndef _USB_PROTOCOL_MSC_H_ #define _USB_PROTOCOL_MSC_H_ - /** * \ingroup usb_protocol_group * \defgroup usb_msc_protocol USB Mass Storage Class (MSC) protocol definitions @@ -59,7 +58,7 @@ * \name Possible Class value */ //@{ -#define MSC_CLASS 0x08 +#define MSC_CLASS 0x08 //@} /** @@ -71,12 +70,12 @@ * operating systems like Windows XP. */ //@{ -#define MSC_SUBCLASS_RBC 0x01 //!< Reduced Block Commands -#define MSC_SUBCLASS_ATAPI 0x02 //!< CD/DVD devices -#define MSC_SUBCLASS_QIC_157 0x03 //!< Tape devices -#define MSC_SUBCLASS_UFI 0x04 //!< Floppy disk drives -#define MSC_SUBCLASS_SFF_8070I 0x05 //!< Floppy disk drives -#define MSC_SUBCLASS_TRANSPARENT 0x06 //!< Determined by INQUIRY +#define MSC_SUBCLASS_RBC 0x01 //!< Reduced Block Commands +#define MSC_SUBCLASS_ATAPI 0x02 //!< CD/DVD devices +#define MSC_SUBCLASS_QIC_157 0x03 //!< Tape devices +#define MSC_SUBCLASS_UFI 0x04 //!< Floppy disk drives +#define MSC_SUBCLASS_SFF_8070I 0x05 //!< Floppy disk drives +#define MSC_SUBCLASS_TRANSPARENT 0x06 //!< Determined by INQUIRY //@} /** @@ -84,21 +83,19 @@ * \note Only the BULK protocol should be used in new designs. */ //@{ -#define MSC_PROTOCOL_CBI 0x00 //!< Command/Bulk/Interrupt -#define MSC_PROTOCOL_CBI_ALT 0x01 //!< W/o command completion -#define MSC_PROTOCOL_BULK 0x50 //!< Bulk-only +#define MSC_PROTOCOL_CBI 0x00 //!< Command/Bulk/Interrupt +#define MSC_PROTOCOL_CBI_ALT 0x01 //!< W/o command completion +#define MSC_PROTOCOL_BULK 0x50 //!< Bulk-only //@} - /** * \brief MSC USB requests (bRequest) */ enum usb_reqid_msc { - USB_REQ_MSC_BULK_RESET = 0xFF, //!< Mass Storage Reset - USB_REQ_MSC_GET_MAX_LUN = 0xFE //!< Get Max LUN + USB_REQ_MSC_BULK_RESET = 0xFF, //!< Mass Storage Reset + USB_REQ_MSC_GET_MAX_LUN = 0xFE //!< Get Max LUN }; - COMPILER_PACK_SET(1) /** @@ -106,38 +103,37 @@ COMPILER_PACK_SET(1) */ //@{ struct usb_msc_cbw { - le32_t dCBWSignature; //!< Must contain 'USBC' - le32_t dCBWTag; //!< Unique command ID - le32_t dCBWDataTransferLength; //!< Number of bytes to transfer - uint8_t bmCBWFlags; //!< Direction in bit 7 - uint8_t bCBWLUN; //!< Logical Unit Number - uint8_t bCBWCBLength; //!< Number of valid CDB bytes - uint8_t CDB[16]; //!< SCSI Command Descriptor Block + le32_t dCBWSignature; //!< Must contain 'USBC' + le32_t dCBWTag; //!< Unique command ID + le32_t dCBWDataTransferLength; //!< Number of bytes to transfer + uint8_t bmCBWFlags; //!< Direction in bit 7 + uint8_t bCBWLUN; //!< Logical Unit Number + uint8_t bCBWCBLength; //!< Number of valid CDB bytes + uint8_t CDB[16]; //!< SCSI Command Descriptor Block }; -#define USB_CBW_SIGNATURE 0x55534243 //!< dCBWSignature value -#define USB_CBW_DIRECTION_IN (1<<7) //!< Data from device to host -#define USB_CBW_DIRECTION_OUT (0<<7) //!< Data from host to device -#define USB_CBW_LUN_MASK 0x0F //!< Valid bits in bCBWLUN -#define USB_CBW_LEN_MASK 0x1F //!< Valid bits in bCBWCBLength +#define USB_CBW_SIGNATURE 0x55534243 //!< dCBWSignature value +#define USB_CBW_DIRECTION_IN (1<<7) //!< Data from device to host +#define USB_CBW_DIRECTION_OUT (0<<7) //!< Data from host to device +#define USB_CBW_LUN_MASK 0x0F //!< Valid bits in bCBWLUN +#define USB_CBW_LEN_MASK 0x1F //!< Valid bits in bCBWCBLength //@} - /** * \name A Command Status Wrapper (CSW). */ //@{ struct usb_msc_csw { - le32_t dCSWSignature; //!< Must contain 'USBS' - le32_t dCSWTag; //!< Same as dCBWTag - le32_t dCSWDataResidue; //!< Number of bytes not transferred - uint8_t bCSWStatus; //!< Status code + le32_t dCSWSignature; //!< Must contain 'USBS' + le32_t dCSWTag; //!< Same as dCBWTag + le32_t dCSWDataResidue; //!< Number of bytes not transferred + uint8_t bCSWStatus; //!< Status code }; -#define USB_CSW_SIGNATURE 0x55534253 //!< dCSWSignature value -#define USB_CSW_STATUS_PASS 0x00 //!< Command Passed -#define USB_CSW_STATUS_FAIL 0x01 //!< Command Failed -#define USB_CSW_STATUS_PE 0x02 //!< Phase Error +#define USB_CSW_SIGNATURE 0x55534253 //!< dCSWSignature value +#define USB_CSW_STATUS_PASS 0x00 //!< Command Passed +#define USB_CSW_STATUS_FAIL 0x01 //!< Command Failed +#define USB_CSW_STATUS_PE 0x02 //!< Phase Error //@} COMPILER_PACK_RESET() diff --git a/Marlin/src/HAL/DUE/usb/usb_task.c b/Marlin/src/HAL/DUE/usb/usb_task.c index 54a808d7..6f027f83 100644 --- a/Marlin/src/HAL/DUE/usb/usb_task.c +++ b/Marlin/src/HAL/DUE/usb/usb_task.c @@ -51,18 +51,18 @@ #include "conf_usb.h" #include "udc.h" -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA static volatile bool main_b_msc_enable = false; #endif static volatile bool main_b_cdc_enable = false; static volatile bool main_b_dtr_active = false; void usb_task_idle(void) { - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA // Attend SD card access from the USB MSD -- Prioritize access to improve speed int delay = 2; while (main_b_msc_enable && --delay > 0) { - if (udi_msc_process_trans()) delay = 10000; + if (udi_msc_process_trans()) delay = 20; // Reset the watchdog, just to be sure REG_WDT_CR = WDT_CR_WDRSTT | WDT_CR_KEY(0xA5); @@ -70,7 +70,7 @@ void usb_task_idle(void) { #endif } -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA bool usb_task_msc_enable(void) { return ((main_b_msc_enable = true)); } void usb_task_msc_disable(void) { main_b_msc_enable = false; } bool usb_task_msc_isenabled(void) { return main_b_msc_enable; } @@ -206,13 +206,13 @@ static USB_MicrosoftExtendedPropertiesDescriptor microsoft_extended_properties_d bool usb_task_extra_string(void) { static uint8_t udi_msft_magic[] = "MSFT100\xEE"; static uint8_t udi_cdc_name[] = "CDC interface"; - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA static uint8_t udi_msc_name[] = "MSC interface"; #endif struct extra_strings_desc_t { usb_str_desc_t header; - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA le16_t string[Max(Max(sizeof(udi_cdc_name) - 1, sizeof(udi_msc_name) - 1), sizeof(udi_msft_magic) - 1)]; #else le16_t string[Max(sizeof(udi_cdc_name) - 1, sizeof(udi_msft_magic) - 1)]; @@ -231,7 +231,7 @@ bool usb_task_extra_string(void) { str_lgt = sizeof(udi_cdc_name) - 1; str = udi_cdc_name; break; - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA case UDI_MSC_STRING_ID: str_lgt = sizeof(udi_msc_name) - 1; str = udi_msc_name; diff --git a/Marlin/src/HAL/DUE/watchdog.cpp b/Marlin/src/HAL/DUE/watchdog.cpp deleted file mode 100644 index e144db82..00000000 --- a/Marlin/src/HAL/DUE/watchdog.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * - * Based on Sprinter and grbl. - * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -#ifdef ARDUINO_ARCH_SAM - -#include "../../inc/MarlinConfig.h" -#include "../../MarlinCore.h" -#include "watchdog.h" - -// Override Arduino runtime to either config or disable the watchdog -// -// We need to configure the watchdog as soon as possible in the boot -// process, because watchdog initialization at hardware reset on SAM3X8E -// is unreliable, and there is risk of unintended resets if we delay -// that initialization to a later time. -void watchdogSetup() { - - #if ENABLED(USE_WATCHDOG) - - // 4 seconds timeout - uint32_t timeout = TERN(WATCHDOG_DURATION_8S, 8000, 4000); - - // Calculate timeout value in WDT counter ticks: This assumes - // the slow clock is running at 32.768 kHz watchdog - // frequency is therefore 32768 / 128 = 256 Hz - timeout = (timeout << 8) / 1000; - if (timeout == 0) - timeout = 1; - else if (timeout > 0xFFF) - timeout = 0xFFF; - - // We want to enable the watchdog with the specified timeout - uint32_t value = - WDT_MR_WDV(timeout) | // With the specified timeout - WDT_MR_WDD(timeout) | // and no invalid write window - #if !(SAMV70 || SAMV71 || SAME70 || SAMS70) - WDT_MR_WDRPROC | // WDT fault resets processor only - We want - // to keep PIO controller state - #endif - WDT_MR_WDDBGHLT | // WDT stops in debug state. - WDT_MR_WDIDLEHLT; // WDT stops in idle state. - - #if ENABLED(WATCHDOG_RESET_MANUAL) - // We enable the watchdog timer, but only for the interrupt. - - // Configure WDT to only trigger an interrupt - value |= WDT_MR_WDFIEN; // Enable WDT fault interrupt. - - // Disable WDT interrupt (just in case, to avoid triggering it!) - NVIC_DisableIRQ(WDT_IRQn); - - // We NEED memory barriers to ensure Interrupts are actually disabled! - // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the ) - __DSB(); - __ISB(); - - // Initialize WDT with the given parameters - WDT_Enable(WDT, value); - - // Configure and enable WDT interrupt. - NVIC_ClearPendingIRQ(WDT_IRQn); - NVIC_SetPriority(WDT_IRQn, 0); // Use highest priority, so we detect all kinds of lockups - NVIC_EnableIRQ(WDT_IRQn); - - #else - - // a WDT fault triggers a reset - value |= WDT_MR_WDRSTEN; - - // Initialize WDT with the given parameters - WDT_Enable(WDT, value); - - #endif - - // Reset the watchdog - WDT_Restart(WDT); - - #else - - // Make sure to completely disable the Watchdog - WDT_Disable(WDT); - - #endif -} - -#if ENABLED(USE_WATCHDOG) - // Initialize watchdog - On SAM3X, Watchdog was already configured - // and enabled or disabled at startup, so no need to reconfigure it - // here. - void watchdog_init() { - // Reset watchdog to start clean - WDT_Restart(WDT); - } -#endif // USE_WATCHDOG - -#endif diff --git a/Marlin/src/HAL/ESP32/HAL.cpp b/Marlin/src/HAL/ESP32/HAL.cpp index 810e3868..4890972b 100644 --- a/Marlin/src/HAL/ESP32/HAL.cpp +++ b/Marlin/src/HAL/ESP32/HAL.cpp @@ -52,7 +52,7 @@ // Externs // ------------------------ -portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; +portMUX_TYPE MarlinHAL::spinlock = portMUX_INITIALIZER_UNLOCKED; // ------------------------ // Local defines @@ -64,7 +64,8 @@ portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; // Public Variables // ------------------------ -uint16_t HAL_adc_result; +uint16_t MarlinHAL::adc_result; +pwm_pin_t MarlinHAL::pwm_pin_data[MAX_EXPANDER_BITS]; // ------------------------ // Private Variables @@ -73,9 +74,16 @@ uint16_t HAL_adc_result; esp_adc_cal_characteristics_t characteristics[ADC_ATTEN_MAX]; adc_atten_t attenuations[ADC1_CHANNEL_MAX] = {}; uint32_t thresholds[ADC_ATTEN_MAX]; -volatile int numPWMUsed = 0, - pwmPins[MAX_PWM_PINS], - pwmValues[MAX_PWM_PINS]; + +volatile int numPWMUsed = 0; +volatile struct { pin_t pin; int value; } pwmState[MAX_PWM_PINS]; + +pin_t chan_pin[CHANNEL_MAX_NUM + 1] = { 0 }; // PWM capable IOpins - not 0 or >33 on ESP32 + +struct { + uint32_t freq; // ledcReadFreq doesn't work if a duty hasn't been set yet! + uint16_t res; +} pwmInfo[(CHANNEL_MAX_NUM + 1) / 2]; // ------------------------ // Public functions @@ -95,20 +103,22 @@ volatile int numPWMUsed = 0, #endif #if ENABLED(USE_ESP32_EXIO) + HardwareSerial YSerial2(2); void Write_EXIO(uint8_t IO, uint8_t v) { - if (ISRS_ENABLED()) { - DISABLE_ISRS(); + if (hal.isr_state()) { + hal.isr_off(); YSerial2.write(0x80 | (((char)v) << 5) | (IO - 100)); - ENABLE_ISRS(); + hal.isr_on(); } else YSerial2.write(0x80 | (((char)v) << 5) | (IO - 100)); } + #endif -void HAL_init_board() { +void MarlinHAL::init_board() { #if ENABLED(USE_ESP32_TASK_WDT) esp_task_wdt_init(10, true); #endif @@ -154,27 +164,51 @@ void HAL_init_board() { #endif } -void HAL_idletask() { - #if BOTH(WIFISUPPORT, OTASUPPORT) +void MarlinHAL::idletask() { + #if ALL(WIFISUPPORT, OTASUPPORT) OTA_handle(); #endif TERN_(ESP3D_WIFISUPPORT, esp3dlib.idletask()); } -void HAL_clear_reset_source() { } - -uint8_t HAL_get_reset_source() { return rtc_get_reset_reason(1); } +uint8_t MarlinHAL::get_reset_source() { return rtc_get_reset_reason(1); } -void HAL_reboot() { ESP.restart(); } +void MarlinHAL::reboot() { ESP.restart(); } -void _delay_ms(int delay_ms) { delay(delay_ms); } +void _delay_ms(const int ms) { delay(ms); } // return free memory between end of heap (or end bss) and whatever is current -int freeMemory() { return ESP.getFreeHeap(); } +int MarlinHAL::freeMemory() { return ESP.getFreeHeap(); } + +// ------------------------ +// Watchdog Timer +// ------------------------ + +#if ENABLED(USE_WATCHDOG) + + #define WDT_TIMEOUT_US TERN(WATCHDOG_DURATION_8S, 8000000, 4000000) // 4 or 8 second timeout + + extern "C" { + esp_err_t esp_task_wdt_reset(); + } + + void watchdogSetup() { + // do whatever. don't remove this function. + } + + void MarlinHAL::watchdog_init() { + // TODO + } + + // Reset watchdog. + void MarlinHAL::watchdog_refresh() { esp_task_wdt_reset(); } + +#endif // ------------------------ // ADC // ------------------------ + #define ADC1_CHANNEL(pin) ADC1_GPIO ## pin ## _CHANNEL adc1_channel_t get_channel(int pin) { @@ -196,22 +230,24 @@ void adc1_set_attenuation(adc1_channel_t chan, adc_atten_t atten) { } } -void HAL_adc_init() { +void MarlinHAL::adc_init() { // Configure ADC adc1_config_width(ADC_WIDTH_12Bit); // Configure channels only if used as (re-)configuring a pin for ADC that is used elsewhere might have adverse effects - TERN_(HAS_TEMP_ADC_0, adc1_set_attenuation(get_channel(TEMP_0_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_ADC_1, adc1_set_attenuation(get_channel(TEMP_1_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_ADC_2, adc1_set_attenuation(get_channel(TEMP_2_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_ADC_3, adc1_set_attenuation(get_channel(TEMP_3_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_ADC_4, adc1_set_attenuation(get_channel(TEMP_4_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_ADC_5, adc1_set_attenuation(get_channel(TEMP_5_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_ADC_6, adc2_set_attenuation(get_channel(TEMP_6_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_ADC_7, adc3_set_attenuation(get_channel(TEMP_7_PIN), ADC_ATTEN_11db)); - TERN_(HAS_HEATED_BED, adc1_set_attenuation(get_channel(TEMP_BED_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_CHAMBER, adc1_set_attenuation(get_channel(TEMP_CHAMBER_PIN), ADC_ATTEN_11db)); - TERN_(HAS_TEMP_COOLER, adc1_set_attenuation(get_channel(TEMP_COOLER_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_ADC_0, adc1_set_attenuation(get_channel(TEMP_0_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_ADC_1, adc1_set_attenuation(get_channel(TEMP_1_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_ADC_2, adc1_set_attenuation(get_channel(TEMP_2_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_ADC_3, adc1_set_attenuation(get_channel(TEMP_3_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_ADC_4, adc1_set_attenuation(get_channel(TEMP_4_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_ADC_5, adc1_set_attenuation(get_channel(TEMP_5_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_ADC_6, adc2_set_attenuation(get_channel(TEMP_6_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_ADC_7, adc3_set_attenuation(get_channel(TEMP_7_PIN), ADC_ATTEN_11db)); + TERN_(HAS_HEATED_BED, adc1_set_attenuation(get_channel(TEMP_BED_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_CHAMBER, adc1_set_attenuation(get_channel(TEMP_CHAMBER_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_PROBE, adc1_set_attenuation(get_channel(TEMP_PROBE_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_COOLER, adc1_set_attenuation(get_channel(TEMP_COOLER_PIN), ADC_ATTEN_11db)); + TERN_(HAS_TEMP_BOARD, adc1_set_attenuation(get_channel(TEMP_BOARD_PIN), ADC_ATTEN_11db)); TERN_(FILAMENT_WIDTH_SENSOR, adc1_set_attenuation(get_channel(FILWIDTH_PIN), ADC_ATTEN_11db)); // Note that adc2 is shared with the WiFi module, which has higher priority, so the conversion may fail. @@ -226,11 +262,16 @@ void HAL_adc_init() { } } -void HAL_adc_start_conversion(const uint8_t adc_pin) { - const adc1_channel_t chan = get_channel(adc_pin); +#ifndef ADC_REFERENCE_VOLTAGE + #define ADC_REFERENCE_VOLTAGE 3.3 +#endif + +void MarlinHAL::adc_start(const pin_t pin) { + const adc1_channel_t chan = get_channel(pin); uint32_t mv; esp_adc_cal_get_voltage((adc_channel_t)chan, &characteristics[attenuations[chan]], &mv); - HAL_adc_result = mv * 1023.0 / 3300.0; + + adc_result = mv * isr_float_t(1023) / isr_float_t(ADC_REFERENCE_VOLTAGE) / isr_float_t(1000); // Change the attenuation level based on the new reading adc_atten_t atten; @@ -247,25 +288,104 @@ void HAL_adc_start_conversion(const uint8_t adc_pin) { adc1_set_attenuation(chan, atten); } -void analogWrite(pin_t pin, int value) { - // Use ledc hardware for internal pins - if (pin < 34) { - static int cnt_channel = 1, pin_to_channel[40] = { 0 }; - if (pin_to_channel[pin] == 0) { - ledcAttachPin(pin, cnt_channel); - ledcSetup(cnt_channel, 490, 8); - ledcWrite(cnt_channel, value); - pin_to_channel[pin] = cnt_channel++; +// ------------------------ +// PWM +// ------------------------ + +int8_t channel_for_pin(const uint8_t pin) { + for (int i = 0; i <= CHANNEL_MAX_NUM; i++) + if (chan_pin[i] == pin) return i; + return -1; +} + +// get PWM channel for pin - if none then attach a new one +// return -1 if fail or invalid pin#, channel # (0-15) if success +int8_t get_pwm_channel(const pin_t pin, const uint32_t freq, const uint16_t res) { + if (!WITHIN(pin, 1, MAX_PWM_IOPIN)) return -1; // Not a hardware PWM pin! + int8_t cid = channel_for_pin(pin); + if (cid >= 0) return cid; + + // Find an empty adjacent channel (same timer & freq/res) + for (int i = 0; i <= CHANNEL_MAX_NUM; i++) { + if (chan_pin[i] == 0) { + if (chan_pin[i ^ 0x1] != 0) { + if (pwmInfo[i / 2].freq == freq && pwmInfo[i / 2].res == res) { + chan_pin[i] = pin; // Allocate PWM to this channel + ledcAttachPin(pin, i); + return i; + } + } + else if (cid == -1) // Pair of empty channels? + cid = i & 0xFE; // Save lower channel number } - ledcWrite(pin_to_channel[pin], value); + } + // not attached, is an empty timer slot avail? + if (cid >= 0) { + chan_pin[cid] = pin; + pwmInfo[cid / 2].freq = freq; + pwmInfo[cid / 2].res = res; + ledcSetup(cid, freq, res); + ledcAttachPin(pin, cid); + } + return cid; // -1 if no channel avail +} + +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*/) { + #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 + + return; + } + #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) { + #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; + } + #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 +void analogWrite(const pin_t pin, const uint16_t value, const uint32_t freq/*=PWM_FREQUENCY*/, const uint16_t res/*=8*/) { // always 8 bit resolution! + // Use ledc hardware for internal pins + const int8_t cid = get_pwm_channel(pin, freq, res); + if (cid >= 0) { + ledcWrite(cid, value); // set duty value return; } + // not a hardware PWM pin OR no PWM channels available int idx = -1; // Search Pin for (int i = 0; i < numPWMUsed; ++i) - if (pwmPins[i] == pin) { idx = i; break; } + if (pwmState[i].pin == pin) { idx = i; break; } // not found ? if (idx < 0) { @@ -274,7 +394,7 @@ void analogWrite(pin_t pin, int value) { // Take new slot for pin idx = numPWMUsed; - pwmPins[idx] = pin; + pwmState[idx].pin = pin; // Start timer on first use if (idx == 0) HAL_timer_start(MF_TIMER_PWM, PWM_TIMER_FREQUENCY); @@ -282,7 +402,7 @@ void analogWrite(pin_t pin, int value) { } // Use 7bit internal value - add 1 to have 100% high at 255 - pwmValues[idx] = (value + 1) / 2; + pwmState[idx].value = (value + 1) / 2; } // Handle PWM timer interrupt @@ -293,9 +413,9 @@ HAL_PWM_TIMER_ISR() { for (int i = 0; i < numPWMUsed; ++i) { if (count == 0) // Start of interval - WRITE(pwmPins[i], pwmValues[i] ? HIGH : LOW); - else if (pwmValues[i] == count) // End of duration - WRITE(pwmPins[i], LOW); + digitalWrite(pwmState[i].pin, pwmState[i].value ? HIGH : LOW); + else if (pwmState[i].value == count) // End of duration + digitalWrite(pwmState[i].pin, LOW); } // 128 for 7 Bit resolution diff --git a/Marlin/src/HAL/ESP32/HAL.h b/Marlin/src/HAL/ESP32/HAL.h index 8473e3c4..0acb3676 100644 --- a/Marlin/src/HAL/ESP32/HAL.h +++ b/Marlin/src/HAL/ESP32/HAL.h @@ -1,7 +1,9 @@ /** * Marlin 3D Printer Firmware * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,7 +34,6 @@ #include "../shared/HAL_SPI.h" #include "fastio.h" -#include "watchdog.h" #include "i2s.h" #if ENABLED(WIFISUPPORT) @@ -49,40 +50,43 @@ // Defines // ------------------------ -extern portMUX_TYPE spinlock; - #define MYSERIAL1 flushableSerial -#if EITHER(WIFISUPPORT, ESP3D_WIFISUPPORT) - #if ENABLED(ESP3D_WIFISUPPORT) - typedef ForwardSerial1Class< decltype(Serial2Socket) > DefaultSerial1; - extern DefaultSerial1 MSerial0; - #define MYSERIAL2 MSerial0 - #else - #define MYSERIAL2 webSocketSerial - #endif +#if ENABLED(ESP3D_WIFISUPPORT) + typedef ForwardSerial1Class< decltype(Serial2Socket) > DefaultSerial1; + extern DefaultSerial1 MSerial0; + #define MYSERIAL2 MSerial0 +#elif ENABLED(WIFISUPPORT) + #define MYSERIAL2 webSocketSerial #endif -#define CRITICAL_SECTION_START() portENTER_CRITICAL(&spinlock) -#define CRITICAL_SECTION_END() portEXIT_CRITICAL(&spinlock) -#define ISRS_ENABLED() (spinlock.owner == portMUX_FREE_VAL) -#define ENABLE_ISRS() if (spinlock.owner != portMUX_FREE_VAL) portEXIT_CRITICAL(&spinlock) -#define DISABLE_ISRS() portENTER_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 // ------------------------ +typedef double isr_float_t; // FPU ops are used for single-precision, so use double for ISRs. typedef int16_t pin_t; -#define HAL_SERVO_LIB Servo +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; -// ------------------------ -// Public Variables -// ------------------------ - -/** result of last ADC conversion */ -extern uint16_t HAL_adc_result; +class Servo; +typedef Servo hal_servo_t; // ------------------------ // Public functions @@ -91,59 +95,18 @@ extern uint16_t HAL_adc_result; // // Tone // -void toneInit(); void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration=0); void noTone(const pin_t _pin); +int8_t get_pwm_channel(const pin_t pin, const uint32_t freq, const uint16_t res); +void analogWrite(const pin_t pin, const uint16_t value, const uint32_t freq=PWM_FREQUENCY, const uint16_t res=8); -// clear reset reason -void HAL_clear_reset_source(); - -// reset reason -uint8_t HAL_get_reset_source(); - -void HAL_reboot(); - -void _delay_ms(int delay); - -#pragma GCC diagnostic push -#if GCC_VERSION <= 50000 - #pragma GCC diagnostic ignored "-Wunused-function" -#endif - -int freeMemory(); - -#pragma GCC diagnostic pop - -void analogWrite(pin_t pin, int value); - -// ADC -#define HAL_ANALOG_SELECT(pin) - -void HAL_adc_init(); - -#define HAL_ADC_VREF 3.3 -#define HAL_ADC_RESOLUTION 10 -#define HAL_START_ADC(pin) HAL_adc_start_conversion(pin) -#define HAL_READ_ADC() HAL_adc_result -#define HAL_ADC_READY() true - -void HAL_adc_start_conversion(const uint8_t adc_pin); - -// PWM -inline void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { analogWrite(pin, v); } - -// Pin Map +// +// Pin Mapping for M42, M43, M226 +// #define GET_PIN_MAP_PIN(index) index #define GET_PIN_MAP_INDEX(pin) pin #define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval) -// Enable hooks into idle and setup for HAL -#define HAL_IDLETASK 1 -#define BOARD_INIT() HAL_init_board(); -void HAL_idletask(); -inline void HAL_init() {} -void HAL_init_board(); - #if ENABLED(USE_ESP32_EXIO) void Write_EXIO(uint8_t IO, uint8_t v); #endif @@ -188,3 +151,96 @@ FORCE_INLINE static void DELAY_CYCLES(uint32_t x) { } } + +// ------------------------ +// Class Utilities +// ------------------------ + +#pragma GCC diagnostic push +#if GCC_VERSION <= 50000 + #pragma GCC diagnostic ignored "-Wunused-function" +#endif + +int freeMemory(); + +#pragma GCC diagnostic pop + +void _delay_ms(const int ms); + +// ------------------------ +// MarlinHAL Class +// ------------------------ + +#define HAL_ADC_VREF_MV 3300 +#define HAL_ADC_RESOLUTION 10 + +class MarlinHAL { +public: + + // Earliest possible init, before setup() + MarlinHAL() {} + + // Watchdog + static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {}); + static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {}); + + static void init() {} // Called early in setup() + static void init_board(); // Called less early in setup() + static void reboot(); // Restart the firmware + + // Interrupts + static portMUX_TYPE spinlock; + static bool isr_state() { return spinlock.owner == portMUX_FREE_VAL; } + static void isr_on() { if (spinlock.owner != portMUX_FREE_VAL) portEXIT_CRITICAL(&spinlock); } + static void isr_off() { portENTER_CRITICAL(&spinlock); } + + static void delay_ms(const int ms) { _delay_ms(ms); } + + // Tasks, called from idle() + static void idletask(); + + // Reset + static uint8_t get_reset_source(); + static void clear_reset_source() {} + + // Free SRAM + static int freeMemory(); + + static pwm_pin_t pwm_pin_data[MAX_EXPANDER_BITS]; + + // + // ADC Methods + // + + static uint16_t adc_result; + + // Called by Temperature::init once at startup + static void adc_init(); + + // Called by Temperature::init for each sensor at startup + static void adc_enable(const pin_t pin) {} + + // Begin ADC sampling on the given pin. Called from Temperature::isr! + static void adc_start(const pin_t pin); + + // Is the ADC ready for reading? + static bool adc_ready() { return true; } + + // The current value of the ADC register + static uint16_t adc_value() { return adc_result; } + + /** + * If not already allocated, allocate a hardware PWM channel + * to the pin and set the duty cycle.. + * Optionally invert the duty cycle [default = false] + * Optionally change the scale of the provided value to enable finer PWM duty control [default = 255] + */ + static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false); + + /** + * Allocate and set the frequency of a hardware PWM pin + * Returns -1 if no pin available. + */ + static int8_t set_pwm_frequency(const pin_t pin, const uint32_t f_desired); + +}; diff --git a/Marlin/src/HAL/ESP32/HAL_SPI.cpp b/Marlin/src/HAL/ESP32/HAL_SPI.cpp index 868ab1b6..e5302bb9 100644 --- a/Marlin/src/HAL/ESP32/HAL_SPI.cpp +++ b/Marlin/src/HAL/ESP32/HAL_SPI.cpp @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -53,7 +52,7 @@ static SPISettings spiConfig; // ------------------------ void spiBegin() { - #if ENABLED(SDSUPPORT) && PIN_EXISTS(SD_SS) + #if HAS_MEDIA && PIN_EXISTS(SD_SS) OUT_WRITE(SD_SS_PIN, HIGH); #endif } diff --git a/Marlin/src/HAL/ESP32/Servo.cpp b/Marlin/src/HAL/ESP32/Servo.cpp index fcf58485..ca3950d0 100644 --- a/Marlin/src/HAL/ESP32/Servo.cpp +++ b/Marlin/src/HAL/ESP32/Servo.cpp @@ -31,20 +31,18 @@ // so we only allocate servo channels up high to avoid side effects with regards to analogWrite (fans, leds, laser pwm etc.) int Servo::channel_next_free = 12; -Servo::Servo() { - channel = channel_next_free++; -} +Servo::Servo() {} int8_t Servo::attach(const int inPin) { - if (channel >= CHANNEL_MAX_NUM) return -1; if (inPin > 0) pin = inPin; - - ledcSetup(channel, 50, 16); // channel X, 50 Hz, 16-bit depth - ledcAttachPin(pin, channel); - return true; + channel = get_pwm_channel(pin, 50u, 16u); + return channel; // -1 if no PWM avail. } -void Servo::detach() { ledcDetachPin(pin); } +// leave channel connected to servo - set duty to zero +void Servo::detach() { + if (channel >= 0) ledcWrite(channel, 0); +} int Servo::read() { return degrees; } @@ -52,7 +50,7 @@ void Servo::write(int inDegrees) { degrees = constrain(inDegrees, MIN_ANGLE, MAX_ANGLE); int us = map(degrees, MIN_ANGLE, MAX_ANGLE, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH); int duty = map(us, 0, TAU_USEC, 0, MAX_COMPARE); - ledcWrite(channel, duty); + if (channel >= 0) ledcWrite(channel, duty); // don't save duty for servos! } void Servo::move(const int value) { diff --git a/Marlin/src/HAL/ESP32/Servo.h b/Marlin/src/HAL/ESP32/Servo.h index 8542092d..1dbb416a 100644 --- a/Marlin/src/HAL/ESP32/Servo.h +++ b/Marlin/src/HAL/ESP32/Servo.h @@ -30,8 +30,7 @@ class Servo { MAX_PULSE_WIDTH = 2400, // Longest pulse sent to a servo TAU_MSEC = 20, TAU_USEC = (TAU_MSEC * 1000), - MAX_COMPARE = _BV(16) - 1, // 65535 - CHANNEL_MAX_NUM = 16; + MAX_COMPARE = _BV(16) - 1; // 65535 public: Servo(); diff --git a/Marlin/src/HAL/ESP32/Tone.cpp b/Marlin/src/HAL/ESP32/Tone.cpp index 9c16cdde..839c612b 100644 --- a/Marlin/src/HAL/ESP32/Tone.cpp +++ b/Marlin/src/HAL/ESP32/Tone.cpp @@ -35,7 +35,7 @@ static pin_t tone_pin; volatile static int32_t toggles; -void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration) { +void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration/*=0*/) { tone_pin = _pin; toggles = 2 * frequency * duration / 1000; HAL_timer_start(MF_TIMER_TONE, 2 * frequency); diff --git a/Marlin/src/HAL/ESP32/endstop_interrupts.h b/Marlin/src/HAL/ESP32/endstop_interrupts.h index 4725df92..f2637d32 100644 --- a/Marlin/src/HAL/ESP32/endstop_interrupts.h +++ b/Marlin/src/HAL/ESP32/endstop_interrupts.h @@ -42,27 +42,33 @@ void ICACHE_RAM_ATTR endstop_ISR() { endstops.update(); } void setup_endstop_interrupts() { #define _ATTACH(P) attachInterrupt(digitalPinToInterrupt(P), endstop_ISR, CHANGE) - TERN_(HAS_X_MAX, _ATTACH(X_MAX_PIN)); - TERN_(HAS_X_MIN, _ATTACH(X_MIN_PIN)); - TERN_(HAS_Y_MAX, _ATTACH(Y_MAX_PIN)); - TERN_(HAS_Y_MIN, _ATTACH(Y_MIN_PIN)); - TERN_(HAS_Z_MAX, _ATTACH(Z_MAX_PIN)); - TERN_(HAS_Z_MIN, _ATTACH(Z_MIN_PIN)); - TERN_(HAS_X2_MAX, _ATTACH(X2_MAX_PIN)); - TERN_(HAS_X2_MIN, _ATTACH(X2_MIN_PIN)); - TERN_(HAS_Y2_MAX, _ATTACH(Y2_MAX_PIN)); - TERN_(HAS_Y2_MIN, _ATTACH(Y2_MIN_PIN)); - TERN_(HAS_Z2_MAX, _ATTACH(Z2_MAX_PIN)); - TERN_(HAS_Z2_MIN, _ATTACH(Z2_MIN_PIN)); - TERN_(HAS_Z3_MAX, _ATTACH(Z3_MAX_PIN)); - TERN_(HAS_Z3_MIN, _ATTACH(Z3_MIN_PIN)); - TERN_(HAS_Z4_MAX, _ATTACH(Z4_MAX_PIN)); - TERN_(HAS_Z4_MIN, _ATTACH(Z4_MIN_PIN)); + TERN_(USE_X_MAX, _ATTACH(X_MAX_PIN)); + TERN_(USE_X_MIN, _ATTACH(X_MIN_PIN)); + TERN_(USE_Y_MAX, _ATTACH(Y_MAX_PIN)); + TERN_(USE_Y_MIN, _ATTACH(Y_MIN_PIN)); + TERN_(USE_Z_MAX, _ATTACH(Z_MAX_PIN)); + TERN_(USE_Z_MIN, _ATTACH(Z_MIN_PIN)); + TERN_(USE_X2_MAX, _ATTACH(X2_MAX_PIN)); + TERN_(USE_X2_MIN, _ATTACH(X2_MIN_PIN)); + TERN_(USE_Y2_MAX, _ATTACH(Y2_MAX_PIN)); + TERN_(USE_Y2_MIN, _ATTACH(Y2_MIN_PIN)); + TERN_(USE_Z2_MAX, _ATTACH(Z2_MAX_PIN)); + TERN_(USE_Z2_MIN, _ATTACH(Z2_MIN_PIN)); + TERN_(USE_Z3_MAX, _ATTACH(Z3_MAX_PIN)); + TERN_(USE_Z3_MIN, _ATTACH(Z3_MIN_PIN)); + TERN_(USE_Z4_MAX, _ATTACH(Z4_MAX_PIN)); + TERN_(USE_Z4_MIN, _ATTACH(Z4_MIN_PIN)); TERN_(HAS_Z_MIN_PROBE_PIN, _ATTACH(Z_MIN_PROBE_PIN)); - TERN_(HAS_I_MAX, _ATTACH(I_MAX_PIN)); - TERN_(HAS_I_MIN, _ATTACH(I_MIN_PIN)); - TERN_(HAS_J_MAX, _ATTACH(J_MAX_PIN)); - TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN)); - TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN)); - TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_I_MAX, _ATTACH(I_MAX_PIN)); + TERN_(USE_I_MIN, _ATTACH(I_MIN_PIN)); + TERN_(USE_J_MAX, _ATTACH(J_MAX_PIN)); + TERN_(USE_J_MIN, _ATTACH(J_MIN_PIN)); + TERN_(USE_K_MAX, _ATTACH(K_MAX_PIN)); + TERN_(USE_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(USE_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(USE_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(USE_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(USE_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(USE_W_MIN, _ATTACH(W_MIN_PIN)); } diff --git a/Marlin/src/HAL/ESP32/i2s.cpp b/Marlin/src/HAL/ESP32/i2s.cpp index 3e77b658..507414d9 100644 --- a/Marlin/src/HAL/ESP32/i2s.cpp +++ b/Marlin/src/HAL/ESP32/i2s.cpp @@ -134,27 +134,43 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg) { if (high_priority_task_awoken == pdTRUE) portYIELD_FROM_ISR(); - // clear interrupt - I2S0.int_clr.val = I2S0.int_st.val; //clear pending interrupt + // Clear pending interrupt + I2S0.int_clr.val = I2S0.int_st.val; } void stepperTask(void *parameter) { - uint32_t remaining = 0; + uint32_t nextMainISR = 0; + #if ENABLED(LIN_ADVANCE) + uint32_t nextAdvanceISR = Stepper::LA_ADV_NEVER; + #endif - while (1) { + for (;;) { xQueueReceive(dma.queue, &dma.current, portMAX_DELAY); dma.rw_pos = 0; while (dma.rw_pos < DMA_SAMPLE_COUNT) { - // Fill with the port data post pulse_phase until the next step - if (remaining) { - i2s_push_sample(); - remaining--; - } - else { + if (!nextMainISR) { Stepper::pulse_phase_isr(); - remaining = Stepper::block_phase_isr(); + nextMainISR = Stepper::block_phase_isr(); } + #if ENABLED(LIN_ADVANCE) + else if (!nextAdvanceISR) { + Stepper::advance_isr(); + nextAdvanceISR = Stepper::la_interval; + } + #endif + else + i2s_push_sample(); + + nextMainISR--; + + #if ENABLED(LIN_ADVANCE) + if (nextAdvanceISR == Stepper::LA_ADV_NEVER) + nextAdvanceISR = Stepper::la_interval; + + if (nextAdvanceISR && nextAdvanceISR != Stepper::LA_ADV_NEVER) + nextAdvanceISR--; + #endif } } } @@ -337,6 +353,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 + for (uint8_t p = 0; p < MAX_EXPANDER_BITS; ++p) { + 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; } diff --git a/Marlin/src/HAL/ESP32/inc/Conditionals_LCD.h b/Marlin/src/HAL/ESP32/inc/Conditionals_LCD.h index 4da60017..5f1c4b16 100644 --- a/Marlin/src/HAL/ESP32/inc/Conditionals_LCD.h +++ b/Marlin/src/HAL/ESP32/inc/Conditionals_LCD.h @@ -20,7 +20,3 @@ * */ #pragma once - -#if HAS_SPI_TFT || HAS_FSMC_TFT - #error "Sorry! TFT displays are not available for HAL/ESP32." -#endif diff --git a/Marlin/src/HAL/ESP32/inc/Conditionals_adv.h b/Marlin/src/HAL/ESP32/inc/Conditionals_adv.h index 5f1c4b16..3ca80689 100644 --- a/Marlin/src/HAL/ESP32/inc/Conditionals_adv.h +++ b/Marlin/src/HAL/ESP32/inc/Conditionals_adv.h @@ -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 diff --git a/Marlin/src/HAL/ESP32/inc/SanityCheck.h b/Marlin/src/HAL/ESP32/inc/SanityCheck.h index 8bbc68d8..e6c364a6 100644 --- a/Marlin/src/HAL/ESP32/inc/SanityCheck.h +++ b/Marlin/src/HAL/ESP32/inc/SanityCheck.h @@ -21,22 +21,49 @@ */ #pragma once +#if HAS_SPI_TFT || HAS_FSMC_TFT + #error "Sorry! TFT displays are not available for HAL/ESP32." +#endif + #if ENABLED(EMERGENCY_PARSER) #error "EMERGENCY_PARSER is not yet implemented for ESP32. Disable EMERGENCY_PARSER to continue." #endif -#if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY - #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported on ESP32." +#if ENABLED(SPINDLE_LASER_USE_PWM) && SPINDLE_LASER_FREQUENCY > 78125 + #error "SPINDLE_LASER_FREQUENCY maximum value is 78125Hz for ESP32." +#endif +#if ENABLED(FAST_PWM_FAN) && FAST_PWM_FAN_FREQUENCY > 78125 + #error "FAST_PWM_FREQUENCY maximum value is 78125Hz for ESP32." #endif #if HAS_TMC_SW_SERIAL #error "TMC220x Software Serial is not supported on ESP32." #endif -#if BOTH(WIFISUPPORT, ESP3D_WIFISUPPORT) +#if ALL(WIFISUPPORT, ESP3D_WIFISUPPORT) #error "Only enable one WiFi option, either WIFISUPPORT or ESP3D_WIFISUPPORT." #endif #if ENABLED(POSTMORTEM_DEBUGGING) #error "POSTMORTEM_DEBUGGING is not yet supported on ESP32." #endif + +#if MB(MKS_TINYBEE) && ENABLED(FAST_PWM_FAN) + #error "FAST_PWM_FAN is not available on TinyBee." +#endif + +#if ALL(I2S_STEPPER_STREAM, BABYSTEPPING) && DISABLED(INTEGRATED_BABYSTEPPING) + #error "BABYSTEPPING on I2S stream requires INTEGRATED_BABYSTEPPING." +#endif + +#if USING_PULLDOWNS + #error "PULLDOWN pin mode is not available on ESP32 boards." +#endif + +#if ALL(I2S_STEPPER_STREAM, LIN_ADVANCE) && DISABLED(EXPERIMENTAL_I2S_LA) + #error "I2S stream is currently incompatible with LIN_ADVANCE." +#endif + +#if ALL(I2S_STEPPER_STREAM, PRINTCOUNTER) && PRINTCOUNTER_SAVE_INTERVAL > 0 && DISABLED(PRINTCOUNTER_SYNC) + #error "PRINTCOUNTER_SAVE_INTERVAL may cause issues on ESP32 with an I2S expander. Define PRINTCOUNTER_SYNC in Configuration.h for an imperfect solution." +#endif diff --git a/Marlin/src/HAL/ESP32/ota.cpp b/Marlin/src/HAL/ESP32/ota.cpp index 69a3e25e..01f59248 100644 --- a/Marlin/src/HAL/ESP32/ota.cpp +++ b/Marlin/src/HAL/ESP32/ota.cpp @@ -1,7 +1,9 @@ /** * Marlin 3D Printer Firmware * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,7 +24,7 @@ #include "../../inc/MarlinConfigPre.h" -#if BOTH(WIFISUPPORT, OTASUPPORT) +#if ALL(WIFISUPPORT, OTASUPPORT) #include #include @@ -50,7 +52,7 @@ void OTA_init() { }) .onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); - char *str; + const char *str = "unknown"; switch (error) { case OTA_AUTH_ERROR: str = "Auth Failed"; break; case OTA_BEGIN_ERROR: str = "Begin Failed"; break; diff --git a/Marlin/src/HAL/ESP32/ota.h b/Marlin/src/HAL/ESP32/ota.h index 546ace82..a91d04db 100644 --- a/Marlin/src/HAL/ESP32/ota.h +++ b/Marlin/src/HAL/ESP32/ota.h @@ -1,7 +1,9 @@ /** * Marlin 3D Printer Firmware * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Marlin/src/HAL/ESP32/pinsDebug.h b/Marlin/src/HAL/ESP32/pinsDebug.h new file mode 100644 index 00000000..42304b2a --- /dev/null +++ b/Marlin/src/HAL/ESP32/pinsDebug.h @@ -0,0 +1,71 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2024 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#error "PINS_DEBUGGING is not yet supported for ESP32!" + +/** + * Pins Debugging for ESP32 + * + * - NUMBER_PINS_TOTAL + * - MULTI_NAME_PAD + * - getPinByIndex(index) + * - printPinNameByIndex(index) + * - getPinIsDigitalByIndex(index) + * - digitalPinToAnalogIndex(pin) + * - getValidPinMode(pin) + * - isValidPin(pin) + * - isAnalogPin(pin) + * - digitalRead_mod(pin) + * - pwm_status(pin) + * - printPinPWM(pin) + * - printPinPort(pin) + * - printPinNumber(pin) + * - printPinAnalog(pin) + */ + +#define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS +#define MULTI_NAME_PAD 16 // space needed to be pretty if not first name assigned to a pin + +#define digitalRead_mod(P) extDigitalRead(P) +#define printPinNameByIndex(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) +#define printPinNumber(P) do{ sprintf_P(buffer, PSTR("%02d"), P); SERIAL_ECHO(buffer); }while(0) +#define printPinAnalog(P) do{ sprintf_P(buffer, PSTR(" (A%2d) "), digitalPinToAnalogIndex(P)); SERIAL_ECHO(buffer); }while(0) +#define getPinByIndex(x) pin_array[x].pin +#define getPinIsDigitalByIndex(x) pin_array[x].is_digital +#define isValidPin(P) (P >= 0 && P < pin_t(NUMBER_PINS_TOTAL)) +#define digitalPinToAnalogIndex(P) int(P - analogInputToDigitalPin(0)) +#define isAnalogPin(P) WITHIN(P, pin_t(analogInputToDigitalPin(0)), pin_t(analogInputToDigitalPin(NUM_ANALOG_INPUTS - 1))) +bool pwm_status(const pin_t) { return false; } + +void printPinPort(const pin_t) {} + +static bool getValidPinMode(const pin_t pin) { + return isValidPin(pin) && !IS_INPUT(pin); +} + +void printPinPWM(const int32_t pin) { + if (pwm_status(pin)) { + //uint32_t chan = g_APinDescription[pin].ulPWMChannel TODO when fast pwm is operative; + //SERIAL_ECHOPGM("PWM = ", duty); + } +} diff --git a/Marlin/src/HAL/ESP32/spiffs.cpp b/Marlin/src/HAL/ESP32/spiffs.cpp index a0e713bf..043ad784 100644 --- a/Marlin/src/HAL/ESP32/spiffs.cpp +++ b/Marlin/src/HAL/ESP32/spiffs.cpp @@ -23,7 +23,7 @@ #include "../../inc/MarlinConfigPre.h" -#if BOTH(WIFISUPPORT, WEBSUPPORT) +#if ALL(WIFISUPPORT, WEBSUPPORT) #include "../../core/serial.h" diff --git a/Marlin/src/HAL/ESP32/timers.cpp b/Marlin/src/HAL/ESP32/timers.cpp index df0065f4..a6893150 100644 --- a/Marlin/src/HAL/ESP32/timers.cpp +++ b/Marlin/src/HAL/ESP32/timers.cpp @@ -81,7 +81,7 @@ void IRAM_ATTR timer_isr(void *para) { * @param timer_num timer number to initialize * @param frequency frequency of the timer */ -void HAL_timer_start(const uint8_t timer_num, uint32_t frequency) { +void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) { const tTimerConfig timer = timer_config[timer_num]; timer_config_t config; @@ -111,12 +111,12 @@ void HAL_timer_start(const uint8_t timer_num, uint32_t frequency) { /** * Set the upper value of the timer, when the timer reaches this upper value the * interrupt should be triggered and the counter reset - * @param timer_num timer number to set the count to - * @param count threshold at which the interrupt is triggered + * @param timer_num timer number to set the compare value to + * @param compare threshold at which the interrupt is triggered */ -void HAL_timer_set_compare(const uint8_t timer_num, hal_timer_t count) { +void HAL_timer_set_compare(const uint8_t timer_num, const hal_timer_t compare) { const tTimerConfig timer = timer_config[timer_num]; - timer_set_alarm_value(timer.group, timer.idx, count); + timer_set_alarm_value(timer.group, timer.idx, compare); } /** diff --git a/Marlin/src/HAL/ESP32/timers.h b/Marlin/src/HAL/ESP32/timers.h index 26616984..aa4e1551 100644 --- a/Marlin/src/HAL/ESP32/timers.h +++ b/Marlin/src/HAL/ESP32/timers.h @@ -127,7 +127,7 @@ extern const tTimerConfig timer_config[]; // Public functions // ------------------------ -void HAL_timer_start (const uint8_t timer_num, uint32_t frequency); +void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency); void HAL_timer_set_compare(const uint8_t timer_num, const hal_timer_t count); hal_timer_t HAL_timer_get_compare(const uint8_t timer_num); hal_timer_t HAL_timer_get_count(const uint8_t timer_num); @@ -136,5 +136,5 @@ void HAL_timer_enable_interrupt(const uint8_t timer_num); void HAL_timer_disable_interrupt(const uint8_t timer_num); bool HAL_timer_interrupt_enabled(const uint8_t timer_num); -#define HAL_timer_isr_prologue(T) -#define HAL_timer_isr_epilogue(T) +#define HAL_timer_isr_prologue(T) NOOP +#define HAL_timer_isr_epilogue(T) NOOP diff --git a/Marlin/src/HAL/ESP32/u8g_esp32_spi.cpp b/Marlin/src/HAL/ESP32/u8g_esp32_spi.cpp new file mode 100644 index 00000000..d2645557 --- /dev/null +++ b/Marlin/src/HAL/ESP32/u8g_esp32_spi.cpp @@ -0,0 +1,105 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * Copypaste of SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#ifdef ARDUINO_ARCH_ESP32 + +#include "../../inc/MarlinConfig.h" + +#if ANY(MKS_MINI_12864, FYSETC_MINI_12864_2_1) + +#include +#include "../shared/HAL_SPI.h" +#include "HAL.h" +#include "SPI.h" + +#if HAS_MEDIA + #include "../../sd/cardreader.h" + #if ENABLED(ESP3D_WIFISUPPORT) + #include "sd_ESP32.h" + #endif +#endif + +static SPISettings spiConfig; + +#ifndef LCD_SPI_SPEED + #ifdef SD_SPI_SPEED + #define LCD_SPI_SPEED SD_SPI_SPEED // Assume SPI speed shared with SD + #else + #define LCD_SPI_SPEED SPI_FULL_SPEED // Use full speed if SD speed is not supplied + #endif +#endif + +uint8_t u8g_eps_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) { + static uint8_t msgInitCount = 2; // Ignore all messages until 2nd U8G_COM_MSG_INIT + + #if ENABLED(PAUSE_LCD_FOR_BUSY_SD) + if (card.flag.saving || card.flag.logging || TERN0(ESP3D_WIFISUPPORT, sd_busy_lock == true)) return 0; + #endif + + if (msgInitCount) { + if (msg == U8G_COM_MSG_INIT) msgInitCount--; + if (msgInitCount) return -1; + } + + switch (msg) { + case U8G_COM_MSG_STOP: break; + + case U8G_COM_MSG_INIT: + OUT_WRITE(DOGLCD_CS, HIGH); + OUT_WRITE(DOGLCD_A0, HIGH); + OUT_WRITE(LCD_RESET_PIN, HIGH); + u8g_Delay(5); + spiBegin(); + spiInit(LCD_SPI_SPEED); + break; + + case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */ + WRITE(DOGLCD_A0, arg_val ? HIGH : LOW); + break; + + case U8G_COM_MSG_CHIP_SELECT: /* arg_val == 0 means HIGH level of U8G_PI_CS */ + WRITE(DOGLCD_CS, arg_val ? LOW : HIGH); + break; + + case U8G_COM_MSG_RESET: + WRITE(LCD_RESET_PIN, arg_val); + break; + + case U8G_COM_MSG_WRITE_BYTE: + spiSend((uint8_t)arg_val); + break; + + case U8G_COM_MSG_WRITE_SEQ: + uint8_t *ptr = (uint8_t*) arg_ptr; + while (arg_val > 0) { + spiSend(*ptr++); + arg_val--; + } + break; + } + return 1; +} + +#endif // MKS_MINI_12864 || FYSETC_MINI_12864_2_1 + +#endif // ARDUINO_ARCH_ESP32 diff --git a/Marlin/src/HAL/ESP32/web.cpp b/Marlin/src/HAL/ESP32/web.cpp index 7a27707a..63a10159 100644 --- a/Marlin/src/HAL/ESP32/web.cpp +++ b/Marlin/src/HAL/ESP32/web.cpp @@ -23,7 +23,7 @@ #include "../../inc/MarlinConfigPre.h" -#if BOTH(WIFISUPPORT, WEBSUPPORT) +#if ALL(WIFISUPPORT, WEBSUPPORT) #include "../../inc/MarlinConfig.h" diff --git a/Marlin/src/HAL/HAL.h b/Marlin/src/HAL/HAL.h index 0cd836af..f3e16cfd 100644 --- a/Marlin/src/HAL/HAL.h +++ b/Marlin/src/HAL/HAL.h @@ -27,7 +27,8 @@ #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #endif -#include HAL_PATH(.,HAL.h) +#include HAL_PATH(..,HAL.h) +extern MarlinHAL hal; #define HAL_ADC_RANGE _BV(HAL_ADC_RESOLUTION) @@ -44,7 +45,3 @@ #ifndef PGMSTR #define PGMSTR(NAM,STR) const char NAM[] = STR #endif - -inline void watchdog_refresh() { - TERN_(USE_WATCHDOG, HAL_watchdog_refresh()); -} diff --git a/Marlin/src/HAL/HC32/pinsDebug.h b/Marlin/src/HAL/HC32/pinsDebug.h new file mode 100644 index 00000000..e80b5a08 --- /dev/null +++ b/Marlin/src/HAL/HC32/pinsDebug.h @@ -0,0 +1,180 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * Pins Debugging for HC32 + * + * - NUMBER_PINS_TOTAL + * - MULTI_NAME_PAD + * - getPinByIndex(index) + * - printPinNameByIndex(index) + * - getPinIsDigitalByIndex(index) + * - digitalPinToAnalogIndex(pin) + * - getValidPinMode(pin) + * - isValidPin(pin) + * - isAnalogPin(pin) + * - digitalRead_mod(pin) + * - pwm_status(pin) + * - printPinPWM(pin) + * - printPinPort(pin) + * - printPinNumber(pin) + * - printPinAnalog(pin) + */ + +#include "../../inc/MarlinConfig.h" +#include "fastio.h" +#include + +#ifndef BOARD_NR_GPIO_PINS + #error "Expected BOARD_NR_GPIO_PINS not found." +#endif + +#define NUM_DIGITAL_PINS BOARD_NR_GPIO_PINS +#define NUMBER_PINS_TOTAL BOARD_NR_GPIO_PINS +#define isValidPin(P) IS_GPIO_PIN(P) + +// Note: pin_array is defined in `Marlin/src/pins/pinsDebug.h`, and since this file is included +// after it, it is available in this file as well. +#define getPinByIndex(x) pin_t(pin_array[x].pin) +#define digitalRead_mod(P) extDigitalRead(P) + +#define printPinNumber(P) do{ sprintf_P(buffer, PSTR("%3hd "), int16_t(P)); SERIAL_ECHO(buffer); }while(0) +#define printPinAnalog(P) do{ sprintf_P(buffer, PSTR(" (A%2d) "), digitalPinToAnalogIndex(P)); SERIAL_ECHO(buffer); }while(0) + +#define printPinNameByIndex(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) + +#define MULTI_NAME_PAD 21 // Space needed to be pretty if not first name assigned to a pin + +// +// Pins that will cause a hang / reset / disconnect in M43 Toggle and Watch utils +// +#ifndef M43_NEVER_TOUCH + // Don't touch any of the following pins: + // - Host serial pins, and + // - Pins that could be connected to oscillators (see datasheet, Table 2.1): + // - XTAL = PH0, PH1 + // - XTAL32 = PC14, PC15 + #define IS_HOST_USART_PIN(Q) (Q == BOARD_USART2_TX_PIN || Q == BOARD_USART2_RX_PIN) + #define IS_OSC_PIN(Q) (Q == PH0 || Q == PH1 || Q == PC14 || Q == PC15) + + #define M43_NEVER_TOUCH(Q) (IS_HOST_USART_PIN(Q) || IS_OSC_PIN(Q)) +#endif + +int8_t digitalPinToAnalogIndex(const pin_t pin) { + if (!isValidPin(pin)) return -1; + const int8_t adc_channel = int8_t(PIN_MAP[pin].adc_info.channel); + return pin_t(adc_channel); +} + +bool isAnalogPin(pin_t pin) { + if (!isValidPin(pin)) return false; + + if (PIN_MAP[pin].adc_info.channel != ADC_PIN_INVALID) + return _GET_MODE(pin) == INPUT_ANALOG && !M43_NEVER_TOUCH(pin); + + return false; +} + +bool getValidPinMode(const pin_t pin) { + return isValidPin(pin) && !IS_INPUT(pin); +} + +bool getPinIsDigitalByIndex(const int16_t index) { + const pin_t pin = getPinByIndex(index); + return (!isAnalogPin(pin)); +} + +/** + * @brief print pin PWM status + * @return true if pin is currently a PWM pin, false otherwise + */ +bool pwm_status(const pin_t pin) { + // Get timer assignment for pin + timera_config_t *unit; + en_timera_channel_t channel; + en_port_func_t port_function; + if (!timera_get_assignment(pin, unit, channel, port_function) || unit == nullptr) { + // No pwm pin or no unit assigned + return false; + } + + // A pin that is PWM output is: + // - Assigned to a timerA unit (tested above) + // - Unit is initialized + // - Channel is active + // - PinMode is OUTPUT_PWM + return timera_is_unit_initialized(unit) && timera_is_channel_active(unit, channel) && getPinMode(pin) == OUTPUT_PWM; +} + +void printPinPWM(const pin_t pin) { + // Get timer assignment for pin + timera_config_t *unit; + en_timera_channel_t channel; + en_port_func_t port_function; + if (!timera_get_assignment(pin, unit, channel, port_function) || unit == nullptr) + return; // No pwm pin or no unit assigned + + // Print timer assignment of pin, eg. "TimerA1Ch2 Func4" + SERIAL_ECHOPGM("TimerA", TIMERA_REG_TO_X(unit->peripheral.register_base), + "Ch", TIMERA_CHANNEL_TO_X(channel), + " Func", int(port_function)); + SERIAL_ECHO_SP(3); // 3 spaces + + // Print timer unit state, eg. "1/16 PERAR=1234" OR "N/A" + if (timera_is_unit_initialized(unit)) { + // Unit initialized, print + // - Timer clock divider + // - Timer period value (PERAR) + const uint8_t clock_divider = timera_clk_div_to_n(unit->state.base_init->enClkDiv); + const uint16_t period = TIMERA_GetPeriodValue(unit->peripheral.register_base); + SERIAL_ECHOPGM("1/", clock_divider, " PERAR=", period); + } + else { + // Unit not initialized + SERIAL_ECHOPGM("N/A"); + return; + } + + SERIAL_ECHO_SP(3); // 3 spaces + + // Print timer channel state, e.g. "CMPAR=1234" OR "N/A" + if (timera_is_channel_active(unit, channel)) { + // Channel active, print + // - Channel compare value + const uint16_t compare = TIMERA_GetCompareValue(unit->peripheral.register_base, channel); + SERIAL_ECHOPGM("CMPAR=", compare); + } + else { + // Channel inactive + SERIAL_ECHOPGM("N/A"); + } +} + +void printPinPort(pin_t pin) { + const char port = 'A' + char(pin >> 4); // Pin div 16 + const int16_t gbit = PIN_MAP[pin].bit_pos; + char buffer[8]; + sprintf_P(buffer, PSTR("P%c%hd "), port, gbit); + if (gbit < 10) { + SERIAL_CHAR(' '); + } + + SERIAL_ECHO(buffer); +} diff --git a/Marlin/src/HAL/LINUX/HAL.cpp b/Marlin/src/HAL/LINUX/HAL.cpp index 0b679170..9f5009d0 100644 --- a/Marlin/src/HAL/LINUX/HAL.cpp +++ b/Marlin/src/HAL/LINUX/HAL.cpp @@ -19,11 +19,16 @@ * along with this program. If not, see . * */ + #ifdef __PLAT_LINUX__ #include "../../inc/MarlinConfig.h" #include "../shared/Delay.h" +// ------------------------ +// Serial ports +// ------------------------ + MSerialT usb_serial(TERN0(EMERGENCY_PARSER, true)); // U8glib required functions @@ -37,42 +42,20 @@ extern "C" { //************************// // return free heap space -int freeMemory() { - return 0; -} +int freeMemory() { return 0; } // ------------------------ // ADC // ------------------------ -void HAL_adc_init() { +uint8_t MarlinHAL::active_ch = 0; -} - -void HAL_adc_enable_channel(const uint8_t ch) { - -} - -uint8_t active_ch = 0; -void HAL_adc_start_conversion(const uint8_t ch) { - active_ch = ch; -} - -bool HAL_adc_finished() { - return true; -} - -uint16_t HAL_adc_get_result() { - pin_t pin = analogInputToDigitalPin(active_ch); +uint16_t MarlinHAL::adc_value() { + const pin_t pin = analogInputToDigitalPin(active_ch); if (!VALID_PIN(pin)) return 0; - uint16_t data = ((Gpio::get(pin) >> 2) & 0x3FF); - return data; // return 10bit value as Marlin expects -} - -void HAL_pwm_init() { - + return uint16_t((Gpio::get(pin) >> 2) & 0x3FF); // return 10bit value as Marlin expects } -void HAL_reboot() { /* Reset the application state and GPIO */ } +void MarlinHAL::reboot() { /* Reset the application state and GPIO */ } #endif // __PLAT_LINUX__ diff --git a/Marlin/src/HAL/LINUX/HAL.h b/Marlin/src/HAL/LINUX/HAL.h index d7d3a92b..e84516d4 100644 --- a/Marlin/src/HAL/LINUX/HAL.h +++ b/Marlin/src/HAL/LINUX/HAL.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,25 +21,42 @@ */ #pragma once -#define CPU_32_BIT +#include "../../inc/MarlinConfigPre.h" -#define F_CPU 100000000UL -#define SystemCoreClock F_CPU #include #include #include - #undef min #undef max - #include -void _printf (const char *format, ...); +#include "hardware/Clock.h" +#include "../shared/Marduino.h" +#include "../shared/math_32bit.h" +#include "../shared/HAL_SPI.h" +#include "fastio.h" +#include "serial.h" + +// ------------------------ +// Defines +// ------------------------ + +#define CPU_32_BIT +#define SHARED_SERVOS HAS_SERVOS // Use shared/servos.cpp + +#define F_CPU 100000000UL +#define SystemCoreClock F_CPU + +#define DELAY_CYCLES(x) Clock::delayCycles(x) + +#define CPU_ST7920_DELAY_1 600 +#define CPU_ST7920_DELAY_2 750 +#define CPU_ST7920_DELAY_3 750 + +void _printf(const char *format, ...); void _putc(uint8_t c); uint8_t _getc(); -//extern "C" volatile uint32_t _millis; - //arduino: Print.h #define DEC 10 #define HEX 16 @@ -49,36 +66,27 @@ uint8_t _getc(); #define B01 1 #define B10 2 -#include "hardware/Clock.h" - -#include "../shared/Marduino.h" -#include "../shared/math_32bit.h" -#include "../shared/HAL_SPI.h" -#include "fastio.h" -#include "watchdog.h" -#include "serial.h" - -#define SHARED_SERVOS HAS_SERVOS +// ------------------------ +// Serial ports +// ------------------------ extern MSerialT usb_serial; #define MYSERIAL1 usb_serial -#define CPU_ST7920_DELAY_1 600 -#define CPU_ST7920_DELAY_2 750 -#define CPU_ST7920_DELAY_3 750 - // // Interrupts // #define CRITICAL_SECTION_START() #define CRITICAL_SECTION_END() -#define ISRS_ENABLED() -#define ENABLE_ISRS() -#define DISABLE_ISRS() -inline void HAL_init() {} +// ADC +#define HAL_ADC_VREF_MV 5000 +#define HAL_ADC_RESOLUTION 10 + +// ------------------------ +// Class Utilities +// ------------------------ -// Utility functions #pragma GCC diagnostic push #if GCC_VERSION <= 50000 #pragma GCC diagnostic ignored "-Wunused-function" @@ -88,29 +96,70 @@ int freeMemory(); #pragma GCC diagnostic pop -// ADC -#define HAL_ADC_VREF 5.0 -#define HAL_ADC_RESOLUTION 10 -#define HAL_ANALOG_SELECT(ch) HAL_adc_enable_channel(ch) -#define HAL_START_ADC(ch) HAL_adc_start_conversion(ch) -#define HAL_READ_ADC() HAL_adc_get_result() -#define HAL_ADC_READY() true - -void HAL_adc_init(); -void HAL_adc_enable_channel(const uint8_t ch); -void HAL_adc_start_conversion(const uint8_t ch); -uint16_t HAL_adc_get_result(); - -// PWM -inline void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { analogWrite(pin, v); } - -// Reset source -inline void HAL_clear_reset_source(void) {} -inline uint8_t HAL_get_reset_source(void) { return RST_POWER_ON; } - -void HAL_reboot(); // Reset the application state and GPIO - -/* ---------------- Delay in cycles */ -FORCE_INLINE static void DELAY_CYCLES(uint64_t x) { - Clock::delayCycles(x); -} +// ------------------------ +// MarlinHAL Class +// ------------------------ + +class MarlinHAL { +public: + + // Earliest possible init, before setup() + MarlinHAL() {} + + // Watchdog + static void watchdog_init() {} + static void watchdog_refresh() {} + + static void init() {} // Called early in setup() + static void init_board() {} // Called less early in setup() + static void reboot(); // Reset the application state and GPIO + + // Interrupts + static bool isr_state() { return true; } + static void isr_on() {} + static void isr_off() {} + + static void delay_ms(const int ms) { _delay_ms(ms); } + + // Tasks, called from idle() + static void idletask() {} + + // Reset + static constexpr uint8_t reset_reason = RST_POWER_ON; + static uint8_t get_reset_source() { return reset_reason; } + static void clear_reset_source() {} + + // Free SRAM + static int freeMemory() { return ::freeMemory(); } + + // + // ADC Methods + // + + static uint8_t active_ch; + + // Called by Temperature::init once at startup + static void adc_init() {} + + // Called by Temperature::init for each sensor at startup + static void adc_enable(const uint8_t) {} + + // Begin ADC sampling on the given channel + static void adc_start(const uint8_t ch) { active_ch = ch; } + + // Is the ADC ready for reading? + static bool adc_ready() { return true; } + + // The current value of the ADC register + static uint16_t adc_value(); + + /** + * Set the PWM duty cycle for the pin to the given value. + * No option to change the resolution or invert the duty cycle. + */ + static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { + analogWrite(pin, v); + } + + static void set_pwm_frequency(const pin_t, int) {} +}; diff --git a/Marlin/src/HAL/LINUX/arduino.cpp b/Marlin/src/HAL/LINUX/arduino.cpp index 4b56d02a..075b4ccd 100644 --- a/Marlin/src/HAL/LINUX/arduino.cpp +++ b/Marlin/src/HAL/LINUX/arduino.cpp @@ -31,9 +31,7 @@ void cli() { } // Disable void sei() { } // Enable // Time functions -void _delay_ms(const int delay_ms) { - delay(delay_ms); -} +void _delay_ms(const int ms) { delay(ms); } uint32_t millis() { return (uint32_t)Clock::millis(); diff --git a/Marlin/src/HAL/LINUX/eeprom.cpp b/Marlin/src/HAL/LINUX/eeprom.cpp index 532f323c..f878bba6 100644 --- a/Marlin/src/HAL/LINUX/eeprom.cpp +++ b/Marlin/src/HAL/LINUX/eeprom.cpp @@ -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 } diff --git a/Marlin/src/HAL/LINUX/hardware/Heater.h b/Marlin/src/HAL/LINUX/hardware/Heater.h index b17078d0..6d590ce6 100644 --- a/Marlin/src/HAL/LINUX/hardware/Heater.h +++ b/Marlin/src/HAL/LINUX/hardware/Heater.h @@ -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); } }; diff --git a/Marlin/src/HAL/LINUX/hardware/Timer.cpp b/Marlin/src/HAL/LINUX/hardware/Timer.cpp index 9f0d6a8f..013690a4 100644 --- a/Marlin/src/HAL/LINUX/hardware/Timer.cpp +++ b/Marlin/src/HAL/LINUX/hardware/Timer.cpp @@ -37,7 +37,10 @@ Timer::Timer() { } Timer::~Timer() { - timer_delete(timerid); + if (timerid != 0) { + timer_delete(timerid); + timerid = 0; + } } void Timer::init(uint32_t sig_id, uint32_t sim_freq, callback_fn* fn) { diff --git a/Marlin/src/HAL/LINUX/inc/Conditionals_LCD.h b/Marlin/src/HAL/LINUX/inc/Conditionals_LCD.h index 99a6fc27..5f1c4b16 100644 --- a/Marlin/src/HAL/LINUX/inc/Conditionals_LCD.h +++ b/Marlin/src/HAL/LINUX/inc/Conditionals_LCD.h @@ -20,7 +20,3 @@ * */ #pragma once - -#if HAS_SPI_TFT || HAS_FSMC_TFT - #error "Sorry! TFT displays are not available for HAL/LINUX." -#endif diff --git a/Marlin/src/HAL/LINUX/inc/SanityCheck.h b/Marlin/src/HAL/LINUX/inc/SanityCheck.h index 36d3190a..861bade1 100644 --- a/Marlin/src/HAL/LINUX/inc/SanityCheck.h +++ b/Marlin/src/HAL/LINUX/inc/SanityCheck.h @@ -31,13 +31,17 @@ #endif #if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY - #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported on LINUX." + #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported for HAL/LINUX." +#endif + +#if HAS_SPI_TFT || HAS_FSMC_TFT + #error "Sorry! TFT displays are not available for HAL/LINUX." #endif #if HAS_TMC_SW_SERIAL - #error "TMC220x Software Serial is not supported on LINUX." + #error "TMC220x Software Serial is not supported for HAL/LINUX." #endif #if ENABLED(POSTMORTEM_DEBUGGING) - #error "POSTMORTEM_DEBUGGING is not yet supported on LINUX." + #error "POSTMORTEM_DEBUGGING is not yet supported for HAL/LINUX." #endif diff --git a/Marlin/src/HAL/LINUX/include/Arduino.h b/Marlin/src/HAL/LINUX/include/Arduino.h index d4086e25..6e9c80ee 100644 --- a/Marlin/src/HAL/LINUX/include/Arduino.h +++ b/Marlin/src/HAL/LINUX/include/Arduino.h @@ -28,6 +28,9 @@ #include +#define strlcpy(A, B, C) strncpy(A, B, (C) - 1) +#define strlcpy_P(A, B, C) strncpy_P(A, B, (C) - 1) + #define HIGH 0x01 #define LOW 0x00 @@ -59,10 +62,9 @@ typedef uint8_t byte; #endif #define sq(v) ((v) * (v)) -#define square(v) sq(v) #define constrain(value, arg_min, arg_max) ((value) < (arg_min) ? (arg_min) :((value) > (arg_max) ? (arg_max) : (value))) -//Interrupts +// Interrupts void cli(); // Disable void sei(); // Enable void attachInterrupt(uint32_t pin, void (*callback)(), uint32_t mode); @@ -74,8 +76,8 @@ extern "C" { } // Time functions -extern "C" void delay(const int milis); -void _delay_ms(const int delay); +extern "C" void delay(const int ms); +void _delay_ms(const int ms); void delayMicroseconds(unsigned long); uint32_t millis(); diff --git a/Marlin/src/HAL/LINUX/include/pinmapping.h b/Marlin/src/HAL/LINUX/include/pinmapping.h index cfac5e3b..9147ef82 100644 --- a/Marlin/src/HAL/LINUX/include/pinmapping.h +++ b/Marlin/src/HAL/LINUX/include/pinmapping.h @@ -37,29 +37,29 @@ constexpr uint8_t NUM_ANALOG_INPUTS = 16; constexpr uint8_t analog_offset = NUM_DIGITAL_PINS - NUM_ANALOG_INPUTS; // Get the digital pin for an analog index -constexpr pin_t analogInputToDigitalPin(const int8_t p) { - return (WITHIN(p, 0, NUM_ANALOG_INPUTS) ? analog_offset + p : P_NC); +constexpr pin_t analogInputToDigitalPin(const int8_t a) { + return (WITHIN(a, 0, NUM_ANALOG_INPUTS - 1) ? analog_offset + a : P_NC); } // Get the analog index for a digital pin -constexpr int8_t DIGITAL_PIN_TO_ANALOG_PIN(const pin_t p) { - return (WITHIN(p, analog_offset, NUM_DIGITAL_PINS) ? p - analog_offset : P_NC); +constexpr int8_t digitalPinToAnalogIndex(const pin_t pin) { + return (WITHIN(pin, analog_offset, NUM_DIGITAL_PINS - 1) ? pin - analog_offset : P_NC); } // Return the index of a pin number constexpr int16_t GET_PIN_MAP_INDEX(const pin_t pin) { return pin; } // Test whether the pin is valid -constexpr bool VALID_PIN(const pin_t p) { return WITHIN(p, 0, NUM_DIGITAL_PINS); } +constexpr bool isValidPin(const pin_t pin) { return WITHIN(pin, 0, NUM_DIGITAL_PINS - 1); } // Test whether the pin is PWM -constexpr bool PWM_PIN(const pin_t p) { return false; } +constexpr bool PWM_PIN(const pin_t) { return false; } // Test whether the pin is interruptible -constexpr bool INTERRUPT_PIN(const pin_t p) { return false; } +constexpr bool INTERRUPT_PIN(const pin_t) { return false; } // Get the pin number at the given index -constexpr pin_t GET_PIN_MAP_PIN(const int16_t ind) { return ind; } +constexpr pin_t GET_PIN_MAP_PIN(const int16_t index) { return pin_t(index); } // Parse a G-code word into a pin index int16_t PARSED_PIN_INDEX(const char code, const int16_t dval); diff --git a/Marlin/src/HAL/LINUX/pinsDebug.h b/Marlin/src/HAL/LINUX/pinsDebug.h index 7bfd97d0..aacb6261 100644 --- a/Marlin/src/HAL/LINUX/pinsDebug.h +++ b/Marlin/src/HAL/LINUX/pinsDebug.h @@ -19,45 +19,62 @@ * along with this program. If not, see . * */ +#pragma once /** - * Support routines for X86_64 + * Pins Debugging for Linux Native + * + * - NUMBER_PINS_TOTAL + * - MULTI_NAME_PAD + * - getPinByIndex(index) + * - printPinNameByIndex(index) + * - getPinIsDigitalByIndex(index) + * - digitalPinToAnalogIndex(pin) + * - getValidPinMode(pin) + * - isValidPin(pin) + * - isAnalogPin(pin) + * - digitalRead_mod(pin) + * - pwm_status(pin) + * - printPinPWM(pin) + * - printPinPort(pin) + * - printPinNumber(pin) + * - printPinAnalog(pin) */ -/** - * Translation of routines & variables used by pinsDebug.h - */ +#define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS +#define MULTI_NAME_PAD 16 // space needed to be pretty if not first name assigned to a pin -#define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS -#define pwm_details(pin) NOOP // (do nothing) -#define pwm_status(pin) false // Print a pin's PWM status. Return true if it's currently a PWM pin. -#define IS_ANALOG(P) (DIGITAL_PIN_TO_ANALOG_PIN(P) >= 0 ? 1 : 0) -#define digitalRead_mod(p) digitalRead(p) -#define PRINT_PORT(p) -#define GET_ARRAY_PIN(p) pin_array[p].pin -#define PRINT_ARRAY_NAME(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) -#define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%3d "), p); SERIAL_ECHO(buffer); }while(0) -#define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0) -#define MULTI_NAME_PAD 16 // space needed to be pretty if not first name assigned to a pin +#define getPinByIndex(x) pin_array[x].pin + +#define printPinNameByIndex(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) // active ADC function/mode/code values for PINSEL registers -constexpr int8_t ADC_pin_mode(pin_t pin) { - return (-1); -} +constexpr int8_t ADC_pin_mode(const pin_t) { return -1; } -int8_t get_pin_mode(pin_t pin) { - if (!VALID_PIN(pin)) return -1; - return 0; +// The pin and index are the same on this platform +bool getPinIsDigitalByIndex(const pin_t pin) { + return (!isAnalogPin(pin) || get_pin_mode(pin) != ADC_pin_mode(pin)); } -bool GET_PINMODE(pin_t pin) { - int8_t pin_mode = get_pin_mode(pin); - if (pin_mode == -1 || pin_mode == ADC_pin_mode(pin)) // found an invalid pin or active analog pin +#define isAnalogPin(P) (digitalPinToAnalogIndex(P) >= 0) + +#define digitalRead_mod(P) digitalRead(P) + +int8_t get_pin_mode(const pin_t pin) { return isValidPin(pin) ? 0 : -1; } + +bool getValidPinMode(const pin_t pin) { + const int8_t pin_mode = get_pin_mode(pin); + if (pin_mode == -1 || pin_mode == ADC_pin_mode(pin)) // Invalid pin or active analog pin return false; - return (Gpio::getMode(pin) != 0); //input/output state + return (Gpio::getMode(pin) != 0); // Input/output state } -bool GET_ARRAY_IS_DIGITAL(pin_t pin) { - return (!IS_ANALOG(pin) || get_pin_mode(pin) != ADC_pin_mode(pin)); -} +void printPinPWM(const pin_t) {} +bool pwm_status(const pin_t) { return false; } + +void printPinPort(const pin_t) {} + +#define printPinNumber(P) do{ sprintf_P(buffer, PSTR("%3d "), P); SERIAL_ECHO(buffer); }while(0) + +#define printPinAnalog(P) do{ sprintf_P(buffer, PSTR(" (A%2d) "), digitalPinToAnalogIndex(P)); SERIAL_ECHO(buffer); }while(0) diff --git a/Marlin/src/HAL/LINUX/servo_private.h b/Marlin/src/HAL/LINUX/servo_private.h index bcc8d203..11e1c2b9 100644 --- a/Marlin/src/HAL/LINUX/servo_private.h +++ b/Marlin/src/HAL/LINUX/servo_private.h @@ -60,7 +60,6 @@ #define INVALID_SERVO 255 // flag indicating an invalid servo index - // Types typedef struct { diff --git a/Marlin/src/HAL/LINUX/spi_pins.h b/Marlin/src/HAL/LINUX/spi_pins.h index 33136ac9..37e47a59 100644 --- a/Marlin/src/HAL/LINUX/spi_pins.h +++ b/Marlin/src/HAL/LINUX/spi_pins.h @@ -24,19 +24,13 @@ #include "../../core/macros.h" #include "../../inc/MarlinConfigPre.h" -#if BOTH(HAS_MARLINUI_U8GLIB, SDSUPPORT) && (LCD_PINS_D4 == SD_SCK_PIN || LCD_PINS_ENABLE == SD_MOSI_PIN || DOGLCD_SCK == SD_SCK_PIN || DOGLCD_MOSI == SD_MOSI_PIN) - #define LPC_SOFTWARE_SPI // If the SD card and LCD adapter share the same SPI pins, then software SPI is currently - // needed due to the speed and mode required for communicating with each device being different. - // This requirement can be removed if the SPI access to these devices is updated to use - // spiBeginTransaction. +#if ALL(HAS_MARLINUI_U8GLIB, HAS_MEDIA) && (LCD_PINS_D4 == SD_SCK_PIN || LCD_PINS_EN == SD_MOSI_PIN || DOGLCD_SCK == SD_SCK_PIN || DOGLCD_MOSI == SD_MOSI_PIN) + #define SOFTWARE_SPI // If the SD card and LCD adapter share the same SPI pins, then software SPI is currently + // needed due to the speed and mode required for communicating with each device being different. + // This requirement can be removed if the SPI access to these devices is updated to use + // spiBeginTransaction. #endif -// Onboard SD -//#define SD_SCK_PIN P0_07 -//#define SD_MISO_PIN P0_08 -//#define SD_MOSI_PIN P0_09 -//#define SD_SS_PIN P0_06 - // External SD #ifndef SD_SCK_PIN #define SD_SCK_PIN 50 diff --git a/Marlin/src/HAL/LINUX/timers.cpp b/Marlin/src/HAL/LINUX/timers.cpp index 66d80f25..a8ab4031 100644 --- a/Marlin/src/HAL/LINUX/timers.cpp +++ b/Marlin/src/HAL/LINUX/timers.cpp @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Marlin/src/HAL/LINUX/timers.h b/Marlin/src/HAL/LINUX/timers.h index a98ceb6f..2b29edce 100644 --- a/Marlin/src/HAL/LINUX/timers.h +++ b/Marlin/src/HAL/LINUX/timers.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -92,5 +93,5 @@ void HAL_timer_enable_interrupt(const uint8_t timer_num); void HAL_timer_disable_interrupt(const uint8_t timer_num); bool HAL_timer_interrupt_enabled(const uint8_t timer_num); -#define HAL_timer_isr_prologue(T) -#define HAL_timer_isr_epilogue(T) +#define HAL_timer_isr_prologue(T) NOOP +#define HAL_timer_isr_epilogue(T) NOOP diff --git a/Marlin/src/HAL/LINUX/watchdog.cpp b/Marlin/src/HAL/LINUX/watchdog.cpp deleted file mode 100644 index 84202e48..00000000 --- a/Marlin/src/HAL/LINUX/watchdog.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * - * Based on Sprinter and grbl. - * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -#ifdef __PLAT_LINUX__ - -#include "../../inc/MarlinConfig.h" - -#if ENABLED(USE_WATCHDOG) - -#include "watchdog.h" - -#define WDT_TIMEOUT_US TERN(WATCHDOG_DURATION_8S, 8000000, 4000000) // 4 or 8 second timeout - -void watchdog_init() {} -void HAL_watchdog_refresh() {} - -#endif - -#endif // __PLAT_LINUX__ diff --git a/Marlin/src/HAL/LPC1768/HAL.cpp b/Marlin/src/HAL/LPC1768/HAL.cpp index cee9cfc5..db9881cd 100644 --- a/Marlin/src/HAL/LPC1768/HAL.cpp +++ b/Marlin/src/HAL/LPC1768/HAL.cpp @@ -23,15 +23,22 @@ #include "../../inc/MarlinConfig.h" #include "../shared/Delay.h" -#include "../../../gcode/parser.h" +#include "../../core/millis_t.h" -#if ENABLED(USE_WATCHDOG) - #include "watchdog.h" -#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include DefaultSerial1 USBSerial(false, UsbSerial); -uint32_t HAL_adc_reading = 0; +uint32_t MarlinHAL::adc_result = 0; +pin_t MarlinHAL::adc_pin = 0; // U8glib required functions extern "C" { @@ -41,8 +48,6 @@ extern "C" { void u8g_Delay(uint16_t val) { delay(val); } } -//************************// - // return free heap space int freeMemory() { char stack_end; @@ -54,33 +59,211 @@ int freeMemory() { return result; } -// scan command line for code -// return index into pin map array if found and the pin is valid. -// return dval if not found or not a valid pin. -int16_t PARSED_PIN_INDEX(const char code, const int16_t dval) { - const uint16_t val = (uint16_t)parser.intval(code, -1), port = val / 100, pin = val % 100; - const int16_t ind = (port < ((NUM_DIGITAL_PINS) >> 5) && pin < 32) ? ((port << 5) | pin) : -2; - return ind > -1 ? ind : dval; +extern "C" { + #include + int isLPC1769(); + void disk_timerproc(); } -void flashFirmware(const int16_t) { - delay(500); // Give OS time to disconnect - USB_Connect(false); // USB clear connection - delay(1000); // Give OS time to notice - HAL_reboot(); +extern uint32_t MSC_SD_Init(uint8_t pdrv); + +void SysTick_Callback() { disk_timerproc(); } + +TERN_(POSTMORTEM_DEBUGGING, extern void install_min_serial()); + +void MarlinHAL::init() { + + // Init LEDs + #if PIN_EXISTS(LED) + SET_DIR_OUTPUT(LED_PIN); + WRITE_PIN_CLR(LED_PIN); + #if PIN_EXISTS(LED2) + SET_DIR_OUTPUT(LED2_PIN); + WRITE_PIN_CLR(LED2_PIN); + #if PIN_EXISTS(LED3) + SET_DIR_OUTPUT(LED3_PIN); + WRITE_PIN_CLR(LED3_PIN); + #if PIN_EXISTS(LED4) + SET_DIR_OUTPUT(LED4_PIN); + WRITE_PIN_CLR(LED4_PIN); + #endif + #endif + #endif + + // Flash status LED 3 times to indicate Marlin has started booting + for (uint8_t i = 0; i < 6; ++i) { + TOGGLE(LED_PIN); + delay(100); + } + #endif + + // Init Servo Pins + #define INIT_SERVO(N) OUT_WRITE(SERVO##N##_PIN, LOW) + #if HAS_SERVO_0 + INIT_SERVO(0); + #endif + #if HAS_SERVO_1 + INIT_SERVO(1); + #endif + #if HAS_SERVO_2 + INIT_SERVO(2); + #endif + #if HAS_SERVO_3 + INIT_SERVO(3); + #endif + #if HAS_SERVO_4 + INIT_SERVO(4); + #endif + #if HAS_SERVO_5 + INIT_SERVO(5); + #endif + + //debug_frmwrk_init(); + //_DBG("\n\nDebug running\n"); + // Initialize the SD card chip select pins as soon as possible + #if PIN_EXISTS(SD_SS) + OUT_WRITE(SD_SS_PIN, HIGH); + #endif + + #if PIN_EXISTS(ONBOARD_SD_CS) && ONBOARD_SD_CS_PIN != SD_SS_PIN + OUT_WRITE(ONBOARD_SD_CS_PIN, HIGH); + #endif + + #ifdef LPC1768_ENABLE_CLKOUT_12M + /** + * CLKOUTCFG register + * bit 8 (CLKOUT_EN) = enables CLKOUT signal. Disabled for now to prevent glitch when enabling GPIO. + * bits 7:4 (CLKOUTDIV) = set to 0 for divider setting of /1 + * bits 3:0 (CLKOUTSEL) = set to 1 to select main crystal oscillator as CLKOUT source + */ + LPC_SC->CLKOUTCFG = (0<<8)|(0<<4)|(1<<0); + // set P1.27 pin to function 01 (CLKOUT) + PINSEL_CFG_Type PinCfg; + PinCfg.Portnum = 1; + PinCfg.Pinnum = 27; + PinCfg.Funcnum = 1; // function 01 (CLKOUT) + PinCfg.OpenDrain = 0; // not open drain + PinCfg.Pinmode = 2; // no pull-up/pull-down + PINSEL_ConfigPin(&PinCfg); + // now set CLKOUT_EN bit + SBI(LPC_SC->CLKOUTCFG, 8); + #endif + + USB_Init(); // USB Initialization + USB_Connect(false); // USB clear connection + delay(1000); // Give OS time to notice + USB_Connect(true); + + TERN_(HAS_SD_HOST_DRIVE, MSC_SD_Init(0)); // Enable USB SD card access + + const millis_t usb_timeout = millis() + 2000; + while (!USB_Configuration && PENDING(millis(), usb_timeout)) { + delay(50); + idletask(); + #if PIN_EXISTS(LED) + TOGGLE(LED_PIN); // Flash quickly during USB initialization + #endif + } + + HAL_timer_init(); + + TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); // Install the min serial handler } -void HAL_clear_reset_source(void) { - TERN_(USE_WATCHDOG, watchdog_clear_timeout_flag()); +#include "../../sd/cardreader.h" + +// HAL idle task +void MarlinHAL::idletask() { + #if HAS_SHARED_MEDIA + // If Marlin is using the SD card we need to lock it to prevent access from + // a PC via USB. + // Other HALs use IS_SD_PRINTING() and IS_SD_FILE_OPEN() to check for access but + // this will not reliably detect delete operations. To be safe we will lock + // the disk if Marlin has it mounted. Unfortunately there is currently no way + // to unmount the disk from the LCD menu. + // if (IS_SD_PRINTING() || IS_SD_FILE_OPEN()) + if (card.isMounted()) + MSC_Aquire_Lock(); + else + MSC_Release_Lock(); + #endif + // Perform USB stack housekeeping + MSC_RunDeferredCommands(); } -uint8_t HAL_get_reset_source(void) { +void MarlinHAL::reboot() { NVIC_SystemReset(); } + +uint8_t MarlinHAL::get_reset_source() { #if ENABLED(USE_WATCHDOG) if (watchdog_timed_out()) return RST_WATCHDOG; #endif return RST_POWER_ON; } -void HAL_reboot() { NVIC_SystemReset(); } +void MarlinHAL::clear_reset_source() { watchdog_clear_timeout_flag(); } + +void flashFirmware(const int16_t) { + delay(500); // Give OS time to disconnect + USB_Connect(false); // USB clear connection + delay(1000); // Give OS time to notice + hal.reboot(); +} + +#if ENABLED(USE_WATCHDOG) + + #include + + #define WDT_TIMEOUT_US TERN(WATCHDOG_DURATION_8S, 8000000, 4000000) // 4 or 8 second timeout + + void MarlinHAL::watchdog_init() { + #if ENABLED(WATCHDOG_RESET_MANUAL) + // We enable the watchdog timer, but only for the interrupt. + + // Configure WDT to only trigger an interrupt + // Disable WDT interrupt (just in case, to avoid triggering it!) + NVIC_DisableIRQ(WDT_IRQn); + + // We NEED memory barriers to ensure Interrupts are actually disabled! + // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the ) + __DSB(); + __ISB(); + + // Configure WDT to only trigger an interrupt + // Initialize WDT with the given parameters + WDT_Init(WDT_CLKSRC_IRC, WDT_MODE_INT_ONLY); + + // Configure and enable WDT interrupt. + NVIC_ClearPendingIRQ(WDT_IRQn); + NVIC_SetPriority(WDT_IRQn, 0); // Use highest priority, so we detect all kinds of lockups + NVIC_EnableIRQ(WDT_IRQn); + #else + WDT_Init(WDT_CLKSRC_IRC, WDT_MODE_RESET); + #endif + WDT_Start(WDT_TIMEOUT_US); + } + + void MarlinHAL::watchdog_refresh() { + WDT_Feed(); + #if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED) + TOGGLE(LED_PIN); // heartbeat indicator + #endif + } + + // Timeout state + bool MarlinHAL::watchdog_timed_out() { return TEST(WDT_ReadTimeOutFlag(), 0); } + void MarlinHAL::watchdog_clear_timeout_flag() { WDT_ClrTimeOutFlag(); } + +#endif // USE_WATCHDOG + +#include "../../../gcode/parser.h" + +// For M42/M43, scan command line for pin code +// return index into pin map array if found and the pin is valid. +// return dval if not found or not a valid pin. +int16_t PARSED_PIN_INDEX(const char code, const int16_t dval) { + const uint16_t val = (uint16_t)parser.intval(code, -1), port = val / 100, pin = val % 100; + const int16_t ind = (port < ((NUM_DIGITAL_PINS) >> 5) && pin < 32) ? ((port << 5) | pin) : -2; + return ind > -1 ? ind : dval; +} #endif // TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC1768/HAL.h b/Marlin/src/HAL/LPC1768/HAL.h index 348ea6b2..ab28e06e 100644 --- a/Marlin/src/HAL/LPC1768/HAL.h +++ b/Marlin/src/HAL/LPC1768/HAL.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,8 +28,6 @@ #define CPU_32_BIT -void HAL_init(); - #include #include #include @@ -40,19 +38,15 @@ extern "C" volatile uint32_t _millis; #include "../shared/math_32bit.h" #include "../shared/HAL_SPI.h" #include "fastio.h" -#include "watchdog.h" #include "MarlinSerial.h" #include #include #include -// -// Default graphical display delays -// -#define CPU_ST7920_DELAY_1 600 -#define CPU_ST7920_DELAY_2 750 -#define CPU_ST7920_DELAY_3 750 +// ------------------------ +// Serial ports +// ------------------------ typedef ForwardSerial1Class< decltype(UsbSerial) > DefaultSerial1; extern DefaultSerial1 USBSerial; @@ -107,33 +101,19 @@ extern DefaultSerial1 USBSerial; #error "LCD_SERIAL_PORT must be from 0 to 3. You can also use -1 if the board supports Native USB." #endif #if HAS_DGUS_LCD - #define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.available() + #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.available() #endif #endif // // Interrupts // -#define CRITICAL_SECTION_START() uint32_t primask = __get_PRIMASK(); __disable_irq() -#define CRITICAL_SECTION_END() if (!primask) __enable_irq() -#define ISRS_ENABLED() (!__get_PRIMASK()) -#define ENABLE_ISRS() __enable_irq() -#define DISABLE_ISRS() __disable_irq() - -// -// Utility functions -// -#pragma GCC diagnostic push -#if GCC_VERSION <= 50000 - #pragma GCC diagnostic ignored "-Wunused-function" -#endif - -int freeMemory(); -#pragma GCC diagnostic pop +#define CRITICAL_SECTION_START() const bool irqon = !__get_PRIMASK(); __disable_irq() +#define CRITICAL_SECTION_END() if (irqon) __enable_irq() // -// ADC API +// ADC // #define ADC_MEDIAN_FILTER_SIZE (23) // Higher values increase step delay (phase shift), @@ -147,25 +127,14 @@ int freeMemory(); // K = 6, 565 samples, 500Hz sample rate, 1.13s convergence on full range step // Memory usage per ADC channel (bytes): 4 (32 Bytes for 8 channels) -#define HAL_ADC_VREF 3.3 // ADC voltage reference +#define HAL_ADC_VREF_MV 3300 // ADC voltage reference #define HAL_ADC_RESOLUTION 12 // 15 bit maximum, raw temperature is stored as int16_t #define HAL_ADC_FILTERED // Disable oversampling done in Marlin as ADC values already filtered in HAL -using FilteredADC = LPC176x::ADC; -extern uint32_t HAL_adc_reading; -[[gnu::always_inline]] inline void HAL_adc_start_conversion(const pin_t pin) { - HAL_adc_reading = FilteredADC::read(pin) >> (16 - HAL_ADC_RESOLUTION); // returns 16bit value, reduce to required bits -} -[[gnu::always_inline]] inline uint16_t HAL_adc_get_result() { - return HAL_adc_reading; -} - -#define HAL_adc_init() -#define HAL_ANALOG_SELECT(pin) FilteredADC::enable_channel(pin) -#define HAL_START_ADC(pin) HAL_adc_start_conversion(pin) -#define HAL_READ_ADC() HAL_adc_get_result() -#define HAL_ADC_READY() (true) +// +// Pin Mapping for M42, M43, M226 +// // Test whether the pin is valid constexpr bool VALID_PIN(const pin_t pin) { @@ -192,32 +161,112 @@ int16_t PARSED_PIN_INDEX(const char code, const int16_t dval); // P0.6 thru P0.9 are for the onboard SD card #define HAL_SENSITIVE_PINS P0_06, P0_07, P0_08, P0_09, -#define HAL_IDLETASK 1 -void HAL_idletask(); +// ------------------------ +// Defines +// ------------------------ -#define PLATFORM_M997_SUPPORT +#ifndef PLATFORM_M997_SUPPORT + #define PLATFORM_M997_SUPPORT +#endif void flashFirmware(const int16_t); #define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment -/** - * set_pwm_frequency - * Set the frequency of the timer corresponding to the provided pin - * All Hardware PWM pins run at the same frequency and all - * Software PWM pins run at the same frequency - */ -void set_pwm_frequency(const pin_t pin, int f_desired); +// Default graphical display delays +#define CPU_ST7920_DELAY_1 600 +#define CPU_ST7920_DELAY_2 750 +#define CPU_ST7920_DELAY_3 750 -/** - * set_pwm_duty - * Set the PWM duty cycle of the provided pin to the provided value - * Optionally allows inverting the duty cycle [default = false] - * Optionally allows changing the maximum size of the provided value to enable finer PWM duty control [default = 255] - */ -void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false); +// ------------------------ +// Free Memory Accessor +// ------------------------ + +#pragma GCC diagnostic push +#if GCC_VERSION <= 50000 + #pragma GCC diagnostic ignored "-Wunused-function" +#endif + +int freeMemory(); + +#pragma GCC diagnostic pop + +// ------------------------ +// MarlinHAL Class +// ------------------------ + +class MarlinHAL { +public: + + // Earliest possible init, before setup() + MarlinHAL() {} + + static void init(); // Called early in setup() + static void init_board() {} // Called less early in setup() + static void reboot(); // Restart the firmware from 0x0 + + // Interrupts + static bool isr_state() { return !__get_PRIMASK(); } + static void isr_on() { __enable_irq(); } + static void isr_off() { __disable_irq(); } + + static void delay_ms(const int ms) { _delay_ms(ms); } + + // Watchdog + static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {}); + static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {}); + static bool watchdog_timed_out() IF_DISABLED(USE_WATCHDOG, { return false; }); + static void watchdog_clear_timeout_flag() IF_DISABLED(USE_WATCHDOG, {}); + + // Tasks, called from idle() + static void idletask(); + + // Reset + static uint8_t get_reset_source(); + static void clear_reset_source(); + + // Free SRAM + static int freeMemory() { return ::freeMemory(); } + + // + // ADC Methods + // + + using FilteredADC = LPC176x::ADC; + + // Called by Temperature::init once at startup + static void adc_init() {} + + // Called by Temperature::init for each sensor at startup + static void adc_enable(const pin_t pin) { + FilteredADC::enable_channel(pin); + } + + // Begin ADC sampling on the given pin. Called from Temperature::isr! + static uint32_t adc_result; + static pin_t adc_pin; + + static void adc_start(const pin_t pin) { adc_pin = pin; } + + // Is the ADC ready for reading? + static bool adc_ready() { return LPC176x::adc_hardware.done(LPC176x::pin_get_adc_channel(adc_pin)); } + + // The current value of the ADC register + static uint16_t adc_value() { + adc_result = FilteredADC::read(adc_pin) >> (16 - HAL_ADC_RESOLUTION); // returns 16bit value, reduce to required bits + return uint16_t(adc_result); + } -// Reset source -void HAL_clear_reset_source(void); -uint8_t HAL_get_reset_source(void); + /** + * Set the PWM duty cycle for the pin to the given value. + * Optionally invert the duty cycle [default = false] + * Optionally change the scale of the provided value to enable finer PWM duty control [default = 255] + */ + static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false); -void HAL_reboot(); + /** + * Set the frequency of the timer corresponding to the provided pin + * All Hardware PWM pins will run at the same frequency and + * All Software PWM pins will run at the same frequency + */ + static void set_pwm_frequency(const pin_t pin, const uint16_t f_desired); +}; diff --git a/Marlin/src/HAL/LPC1768/HAL_SPI.cpp b/Marlin/src/HAL/LPC1768/HAL_SPI.cpp index 29f9b43a..6ce7f755 100644 --- a/Marlin/src/HAL/LPC1768/HAL_SPI.cpp +++ b/Marlin/src/HAL/LPC1768/HAL_SPI.cpp @@ -60,7 +60,7 @@ // ------------------------ // Public functions // ------------------------ -#if ENABLED(LPC_SOFTWARE_SPI) +#if ENABLED(SOFTWARE_SPI) // Software SPI @@ -161,7 +161,7 @@ // TODO: Implement this method } -#endif // LPC_SOFTWARE_SPI +#endif // SOFTWARE_SPI /** * @brief Wait until TXE (tx empty) flag is set and BSY (busy) flag unset. @@ -318,8 +318,16 @@ void SPIClass::dmaSend(void *buf, uint16_t length, bool minc) { // Enable DMA GPDMA_ChannelCmd(0, ENABLE); + /** + * Observed behaviour on normal data transfer completion (SKR 1.3 board / LPC1768 MCU) + * GPDMA_STAT_INTTC flag is SET + * GPDMA_STAT_INTERR flag is NOT SET + * GPDMA_STAT_RAWINTTC flag is NOT SET + * GPDMA_STAT_RAWINTERR flag is SET + */ + // Wait for data transfer - while (!GPDMA_IntGetStatus(GPDMA_STAT_RAWINTTC, 0) && !GPDMA_IntGetStatus(GPDMA_STAT_RAWINTERR, 0)) { } + while (!GPDMA_IntGetStatus(GPDMA_STAT_INTTC, 0) && !GPDMA_IntGetStatus(GPDMA_STAT_INTERR, 0)) {} // Clear err and int GPDMA_ClearIntPending (GPDMA_STATCLR_INTTC, 0); @@ -333,6 +341,43 @@ void SPIClass::dmaSend(void *buf, uint16_t length, bool minc) { SSP_DMACmd(_currentSetting->spi_d, SSP_DMA_TX, DISABLE); } +void SPIClass::dmaSendAsync(void *buf, uint16_t length, bool minc) { + //TODO: LPC dma can only write 0xFFF bytes at once. + GPDMA_Channel_CFG_Type GPDMACfg; + + /* Configure GPDMA channel 0 -------------------------------------------------------------*/ + /* DMA Channel 0 */ + GPDMACfg.ChannelNum = 0; + // Source memory + GPDMACfg.SrcMemAddr = (uint32_t)buf; + // Destination memory - Not used + GPDMACfg.DstMemAddr = 0; + // Transfer size + GPDMACfg.TransferSize = length; + // Transfer width + GPDMACfg.TransferWidth = (_currentSetting->dataSize == DATA_SIZE_16BIT) ? GPDMA_WIDTH_HALFWORD : GPDMA_WIDTH_BYTE; + // Transfer type + GPDMACfg.TransferType = GPDMA_TRANSFERTYPE_M2P; + // Source connection - unused + GPDMACfg.SrcConn = 0; + // Destination connection + GPDMACfg.DstConn = (_currentSetting->spi_d == LPC_SSP0) ? GPDMA_CONN_SSP0_Tx : GPDMA_CONN_SSP1_Tx; + + GPDMACfg.DMALLI = 0; + + // Enable dma on SPI + SSP_DMACmd(_currentSetting->spi_d, SSP_DMA_TX, ENABLE); + + // Only increase memory if minc is true + GPDMACfg.MemoryIncrease = (minc ? GPDMA_DMACCxControl_SI : 0); + + // Setup channel with given parameter + GPDMA_Setup(&GPDMACfg); + + // Enable DMA + GPDMA_ChannelCmd(0, ENABLE); +} + uint16_t SPIClass::read() { return SSP_ReceiveData(_currentSetting->spi_d); } diff --git a/Marlin/src/HAL/LPC1768/MarlinSerial.h b/Marlin/src/HAL/LPC1768/MarlinSerial.h index 3e6848a1..2fadd820 100644 --- a/Marlin/src/HAL/LPC1768/MarlinSerial.h +++ b/Marlin/src/HAL/LPC1768/MarlinSerial.h @@ -30,16 +30,6 @@ #endif #include "../../core/serial_hook.h" -#ifndef SERIAL_PORT - #define SERIAL_PORT 0 -#endif -#ifndef RX_BUFFER_SIZE - #define RX_BUFFER_SIZE 128 -#endif -#ifndef TX_BUFFER_SIZE - #define TX_BUFFER_SIZE 32 -#endif - class MarlinSerial : public HardwareSerial { public: MarlinSerial(LPC_UART_TypeDef *UARTx) : HardwareSerial(UARTx) { } diff --git a/Marlin/src/HAL/LPC1768/HAL_MinSerial.cpp b/Marlin/src/HAL/LPC1768/MinSerial.cpp similarity index 68% rename from Marlin/src/HAL/LPC1768/HAL_MinSerial.cpp rename to Marlin/src/HAL/LPC1768/MinSerial.cpp index 57065c49..368bcb52 100644 --- a/Marlin/src/HAL/LPC1768/HAL_MinSerial.cpp +++ b/Marlin/src/HAL/LPC1768/MinSerial.cpp @@ -26,25 +26,25 @@ #if ENABLED(POSTMORTEM_DEBUGGING) -#include "../shared/HAL_MinSerial.h" +#include "../shared/MinSerial.h" #include static void TX(char c) { _DBC(c); } void install_min_serial() { HAL_min_serial_out = &TX; } #if DISABLED(DYNAMIC_VECTORTABLE) -extern "C" { - __attribute__((naked)) void JumpHandler_ASM() { - __asm__ __volatile__ ( - "b CommonHandler_ASM\n" - ); + extern "C" { + __attribute__((naked)) void JumpHandler_ASM() { + __asm__ __volatile__ ( + "b CommonHandler_ASM\n" + ); + } + void __attribute__((naked, alias("JumpHandler_ASM"))) HardFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"))) BusFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"))) UsageFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"))) MemManage_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"))) NMI_Handler(); } - void __attribute__((naked, alias("JumpHandler_ASM"))) HardFault_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"))) BusFault_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"))) UsageFault_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"))) MemManage_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"))) NMI_Handler(); -} #endif #endif // POSTMORTEM_DEBUGGING diff --git a/Marlin/src/HAL/LPC1768/Servo.h b/Marlin/src/HAL/LPC1768/Servo.h index eb12fd20..221001c9 100644 --- a/Marlin/src/HAL/LPC1768/Servo.h +++ b/Marlin/src/HAL/LPC1768/Servo.h @@ -39,7 +39,6 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#pragma once /** * Based on "servo.h - Interrupt driven Servo library for Arduino using 16 bit timers - @@ -65,4 +64,5 @@ class libServo: public Servo { } }; -#define HAL_SERVO_LIB libServo +class libServo; +typedef libServo hal_servo_t; diff --git a/Marlin/src/HAL/LPC1768/eeprom_wired.cpp b/Marlin/src/HAL/LPC1768/eeprom_wired.cpp index f9286a74..1bbc39d4 100644 --- a/Marlin/src/HAL/LPC1768/eeprom_wired.cpp +++ b/Marlin/src/HAL/LPC1768/eeprom_wired.cpp @@ -34,7 +34,7 @@ #include "../shared/eeprom_api.h" #ifndef MARLIN_EEPROM_SIZE - #define MARLIN_EEPROM_SIZE 0x8000 // 32KB‬ + #define MARLIN_EEPROM_SIZE 0x8000 // 32K #endif size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE; } diff --git a/Marlin/src/HAL/LPC1768/endstop_interrupts.h b/Marlin/src/HAL/LPC1768/endstop_interrupts.h index 23bd0cc9..924025a6 100644 --- a/Marlin/src/HAL/LPC1768/endstop_interrupts.h +++ b/Marlin/src/HAL/LPC1768/endstop_interrupts.h @@ -44,73 +44,97 @@ void setup_endstop_interrupts() { #define _ATTACH(P) attachInterrupt(digitalPinToInterrupt(P), endstop_ISR, CHANGE) #define LPC1768_PIN_INTERRUPT_M(pin) ((pin >> 0x5 & 0x7) == 0 || (pin >> 0x5 & 0x7) == 2) - #if HAS_X_MAX + #if USE_X_MAX #if !LPC1768_PIN_INTERRUPT_M(X_MAX_PIN) #error "X_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(X_MAX_PIN); #endif - #if HAS_X_MIN + #if USE_X_MIN #if !LPC1768_PIN_INTERRUPT_M(X_MIN_PIN) #error "X_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(X_MIN_PIN); #endif - #if HAS_Y_MAX + #if USE_Y_MAX #if !LPC1768_PIN_INTERRUPT_M(Y_MAX_PIN) #error "Y_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Y_MAX_PIN); #endif - #if HAS_Y_MIN + #if USE_Y_MIN #if !LPC1768_PIN_INTERRUPT_M(Y_MIN_PIN) #error "Y_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Y_MIN_PIN); #endif - #if HAS_Z_MAX + #if USE_Z_MAX #if !LPC1768_PIN_INTERRUPT_M(Z_MAX_PIN) #error "Z_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z_MAX_PIN); #endif - #if HAS_Z_MIN + #if USE_Z_MIN #if !LPC1768_PIN_INTERRUPT_M(Z_MIN_PIN) #error "Z_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z_MIN_PIN); #endif - #if HAS_Z2_MAX + #if USE_X2_MAX + #if !LPC1768_PIN_INTERRUPT_M(X2_MAX_PIN) + #error "X2_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(X2_MAX_PIN); + #endif + #if USE_X2_MIN + #if !LPC1768_PIN_INTERRUPT_M(X2_MIN_PIN) + #error "X2_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(X2_MIN_PIN); + #endif + #if USE_Y2_MAX + #if !LPC1768_PIN_INTERRUPT_M(Y2_MAX_PIN) + #error "Y2_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Y2_MAX_PIN); + #endif + #if USE_Y2_MIN + #if !LPC1768_PIN_INTERRUPT_M(Y2_MIN_PIN) + #error "Y2_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Y2_MIN_PIN); + #endif + #if USE_Z2_MAX #if !LPC1768_PIN_INTERRUPT_M(Z2_MAX_PIN) #error "Z2_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z2_MAX_PIN); #endif - #if HAS_Z2_MIN + #if USE_Z2_MIN #if !LPC1768_PIN_INTERRUPT_M(Z2_MIN_PIN) #error "Z2_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z2_MIN_PIN); #endif - #if HAS_Z3_MAX + #if USE_Z3_MAX #if !LPC1768_PIN_INTERRUPT_M(Z3_MAX_PIN) #error "Z3_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z3_MAX_PIN); #endif - #if HAS_Z3_MIN + #if USE_Z3_MIN #if !LPC1768_PIN_INTERRUPT_M(Z3_MIN_PIN) #error "Z3_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z3_MIN_PIN); #endif - #if HAS_Z4_MAX + #if USE_Z4_MAX #if !LPC1768_PIN_INTERRUPT_M(Z4_MAX_PIN) #error "Z4_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z4_MAX_PIN); #endif - #if HAS_Z4_MIN + #if USE_Z4_MIN #if !LPC1768_PIN_INTERRUPT_M(Z4_MIN_PIN) #error "Z4_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif @@ -122,37 +146,70 @@ void setup_endstop_interrupts() { #endif _ATTACH(Z_MIN_PROBE_PIN); #endif - #if HAS_I_MAX + #if USE_I_MAX #if !LPC1768_PIN_INTERRUPT_M(I_MAX_PIN) - #error "I_MAX_PIN is not INTERRUPT-capable." + #error "I_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(I_MAX_PIN); - #elif HAS_I_MIN + #elif USE_I_MIN #if !LPC1768_PIN_INTERRUPT_M(I_MIN_PIN) - #error "I_MIN_PIN is not INTERRUPT-capable." + #error "I_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(I_MIN_PIN); #endif - #if HAS_J_MAX + #if USE_J_MAX #if !LPC1768_PIN_INTERRUPT_M(J_MAX_PIN) - #error "J_MAX_PIN is not INTERRUPT-capable." + #error "J_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(J_MAX_PIN); - #elif HAS_J_MIN + #elif USE_J_MIN #if !LPC1768_PIN_INTERRUPT_M(J_MIN_PIN) - #error "J_MIN_PIN is not INTERRUPT-capable." + #error "J_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(J_MIN_PIN); #endif - #if HAS_K_MAX + #if USE_K_MAX #if !LPC1768_PIN_INTERRUPT_M(K_MAX_PIN) - #error "K_MAX_PIN is not INTERRUPT-capable." + #error "K_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(K_MAX_PIN); - #elif HAS_K_MIN + #elif USE_K_MIN #if !LPC1768_PIN_INTERRUPT_M(K_MIN_PIN) - #error "K_MIN_PIN is not INTERRUPT-capable." + #error "K_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(K_MIN_PIN); #endif + #if USE_U_MAX + #if !LPC1768_PIN_INTERRUPT_M(U_MAX_PIN) + #error "U_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(U_MAX_PIN); + #elif USE_U_MIN + #if !LPC1768_PIN_INTERRUPT_M(U_MIN_PIN) + #error "U_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(U_MIN_PIN); + #endif + #if USE_V_MAX + #if !LPC1768_PIN_INTERRUPT_M(V_MAX_PIN) + #error "V_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(V_MAX_PIN); + #elif USE_V_MIN + #if !LPC1768_PIN_INTERRUPT_M(V_MIN_PIN) + #error "V_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(V_MIN_PIN); + #endif + #if USE_W_MAX + #if !LPC1768_PIN_INTERRUPT_M(W_MAX_PIN) + #error "W_MAX_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(W_MAX_PIN); + #elif USE_W_MIN + #if !LPC1768_PIN_INTERRUPT_M(W_MIN_PIN) + #error "W_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(W_MIN_PIN); + #endif } diff --git a/Marlin/src/HAL/LPC1768/fast_pwm.cpp b/Marlin/src/HAL/LPC1768/fast_pwm.cpp index eae0e36b..6d2b1a90 100644 --- a/Marlin/src/HAL/LPC1768/fast_pwm.cpp +++ b/Marlin/src/HAL/LPC1768/fast_pwm.cpp @@ -21,21 +21,17 @@ */ #ifdef TARGET_LPC1768 -#include "../../inc/MarlinConfigPre.h" +#include "../../inc/MarlinConfig.h" #include -void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) { +void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) { if (!LPC176x::pin_is_valid(pin)) return; if (LPC176x::pwm_attach_pin(pin)) LPC176x::pwm_write_ratio(pin, invert ? 1.0f - (float)v / v_size : (float)v / v_size); // map 1-254 onto PWM range } -#if NEEDS_HARDWARE_PWM // Specific meta-flag for features that mandate PWM - - void set_pwm_frequency(const pin_t pin, int f_desired) { - LPC176x::pwm_set_frequency(pin, f_desired); - } - -#endif +void MarlinHAL::set_pwm_frequency(const pin_t pin, const uint16_t f_desired) { + LPC176x::pwm_set_frequency(pin, f_desired); +} #endif // TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC1768/fastio.h b/Marlin/src/HAL/LPC1768/fastio.h index c553ffb1..48583340 100644 --- a/Marlin/src/HAL/LPC1768/fastio.h +++ b/Marlin/src/HAL/LPC1768/fastio.h @@ -66,7 +66,7 @@ #define _WRITE(IO,V) WRITE_PIN(IO,V) /// toggle a pin -#define _TOGGLE(IO) _WRITE(IO, !READ(IO)) +#define _TOGGLE(IO) LPC176x::gpio_toggle(IO) /// set pin as input #define _SET_INPUT(IO) SET_DIR_INPUT(IO) diff --git a/Marlin/src/HAL/LPC1768/inc/Conditionals_LCD.h b/Marlin/src/HAL/LPC1768/inc/Conditionals_LCD.h index 32ef908d..65b019b2 100644 --- a/Marlin/src/HAL/LPC1768/inc/Conditionals_LCD.h +++ b/Marlin/src/HAL/LPC1768/inc/Conditionals_LCD.h @@ -21,6 +21,6 @@ */ #pragma once -#if HAS_FSMC_TFT - #error "Sorry! FSMC TFT displays are not current available for HAL/LPC1768." +#ifndef SERIAL_PORT + #define SERIAL_PORT 0 #endif diff --git a/Marlin/src/HAL/LPC1768/inc/Conditionals_adv.h b/Marlin/src/HAL/LPC1768/inc/Conditionals_adv.h index 8e7cab18..9d04c4f7 100644 --- a/Marlin/src/HAL/LPC1768/inc/Conditionals_adv.h +++ b/Marlin/src/HAL/LPC1768/inc/Conditionals_adv.h @@ -24,3 +24,10 @@ #if DISABLED(NO_SD_HOST_DRIVE) #define HAS_SD_HOST_DRIVE 1 #endif + +#ifndef RX_BUFFER_SIZE + #define RX_BUFFER_SIZE 128 +#endif +#ifndef TX_BUFFER_SIZE + #define TX_BUFFER_SIZE 32 +#endif diff --git a/Marlin/src/HAL/LPC1768/inc/Conditionals_post.h b/Marlin/src/HAL/LPC1768/inc/Conditionals_post.h index be574a96..0b03cb2a 100644 --- a/Marlin/src/HAL/LPC1768/inc/Conditionals_post.h +++ b/Marlin/src/HAL/LPC1768/inc/Conditionals_post.h @@ -23,12 +23,12 @@ #if USE_FALLBACK_EEPROM #define FLASH_EEPROM_EMULATION -#elif EITHER(I2C_EEPROM, SPI_EEPROM) +#elif ANY(I2C_EEPROM, SPI_EEPROM) #define USE_SHARED_EEPROM 1 #endif // LPC1768 boards seem to lose steps when saving to EEPROM during print (issue #20785) // TODO: Which other boards are incompatible? -#if defined(MCU_LPC1768) && PRINTCOUNTER_SAVE_INTERVAL > 0 - #define PRINTCOUNTER_SYNC 1 +#if defined(MCU_LPC1768) && ENABLED(FLASH_EEPROM_EMULATION) && PRINTCOUNTER_SAVE_INTERVAL > 0 + #define PRINTCOUNTER_SYNC #endif diff --git a/Marlin/src/HAL/LPC1768/inc/SanityCheck.h b/Marlin/src/HAL/LPC1768/inc/SanityCheck.h index 3ea05458..f49bc34c 100644 --- a/Marlin/src/HAL/LPC1768/inc/SanityCheck.h +++ b/Marlin/src/HAL/LPC1768/inc/SanityCheck.h @@ -77,6 +77,10 @@ static_assert(!(NUM_SERVOS && ENABLED(FAST_PWM_FAN)), "BLTOUCH and Servos are in #endif #endif +#if HAS_FSMC_TFT + #error "Sorry! FSMC TFT displays are not current available for HAL/LPC1768." +#endif + static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported on LPC176x."); /** @@ -95,7 +99,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o #if USING_HW_SERIAL0 #define IS_TX0(P) (P == P0_02) #define IS_RX0(P) (P == P0_03) - #if IS_TX0(TMC_SW_MISO) || IS_RX0(TMC_SW_MOSI) + #if IS_TX0(TMC_SPI_MISO) || IS_RX0(TMC_SPI_MOSI) #error "Serial port pins (0) conflict with Trinamic SPI pins!" #elif HAS_PRUSA_MMU1 && (IS_TX0(E_MUX1_PIN) || IS_RX0(E_MUX0_PIN)) #error "Serial port pins (0) conflict with Multi-Material-Unit multiplexer pins!" @@ -111,9 +115,9 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o #define IS_RX1(P) (P == P0_16) #define _IS_TX1_1 IS_TX1 #define _IS_RX1_1 IS_RX1 - #if IS_TX1(TMC_SW_SCK) + #if IS_TX1(TMC_SPI_SCK) #error "Serial port pins (1) conflict with other pins!" - #elif HAS_WIRED_LCD + #elif HAS_ROTARY_ENCODER #if IS_TX1(BTN_EN2) || IS_RX1(BTN_EN1) #error "Serial port pins (1) conflict with Encoder Buttons!" #elif ANY_TX(1, SD_SCK_PIN, LCD_PINS_D4, DOGLCD_SCK, LCD_RESET_PIN, LCD_PINS_RS, SHIFT_CLK_PIN) \ @@ -197,7 +201,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o #if USEDI2CDEV_M == 0 // P0_27 [D57] (AUX-1) .......... P0_28 [D58] (AUX-1) #define PIN_IS_SDA0(P) (P##_PIN == P0_27) #define IS_SCL0(P) (P == P0_28) - #if ENABLED(SDSUPPORT) && PIN_IS_SDA0(SD_DETECT) + #if HAS_MEDIA && PIN_IS_SDA0(SD_DETECT) #error "SDA0 overlaps with SD_DETECT_PIN!" #elif PIN_IS_SDA0(E0_AUTO_FAN) #error "SDA0 overlaps with E0_AUTO_FAN_PIN!" diff --git a/Marlin/src/HAL/LPC1768/include/SPI.h b/Marlin/src/HAL/LPC1768/include/SPI.h index ecd91f6a..03d34bec 100644 --- a/Marlin/src/HAL/LPC1768/include/SPI.h +++ b/Marlin/src/HAL/LPC1768/include/SPI.h @@ -77,7 +77,7 @@ class SPISettings { //uint32_t spiRate() const { return spi_speed; } - static inline uint32_t spiRate2Clock(uint32_t spiRate) { + static uint32_t spiRate2Clock(uint32_t spiRate) { uint32_t Marlin_speed[7]; // CPSR is always 2 Marlin_speed[0] = 8333333; //(SCR: 2) desired: 8,000,000 actual: 8,333,333 +4.2% SPI_FULL_SPEED Marlin_speed[1] = 4166667; //(SCR: 5) desired: 4,000,000 actual: 4,166,667 +4.2% SPI_HALF_SPEED @@ -155,6 +155,7 @@ class SPIClass { void read(uint8_t *buf, uint32_t len); void dmaSend(void *buf, uint16_t length, bool minc); + void dmaSendAsync(void *buf, uint16_t length, bool minc); /** * @brief Sets the number of the SPI peripheral to be used by diff --git a/Marlin/src/HAL/LPC1768/include/digipot_mcp4451_I2C_routines.c b/Marlin/src/HAL/LPC1768/include/digipot_mcp4451_I2C_routines.c index f442ab71..c489c16e 100644 --- a/Marlin/src/HAL/LPC1768/include/digipot_mcp4451_I2C_routines.c +++ b/Marlin/src/HAL/LPC1768/include/digipot_mcp4451_I2C_routines.c @@ -29,7 +29,7 @@ #include "../../../inc/MarlinConfigPre.h" -#if MB(MKS_SBASE) +#if ENABLED(DIGIPOT_MCP4451) && MB(MKS_SBASE) #ifdef __cplusplus extern "C" { @@ -37,35 +37,6 @@ #include "digipot_mcp4451_I2C_routines.h" -// These two routines are exact copies of the lpc17xx_i2c.c routines. Couldn't link to -// to the lpc17xx_i2c.c routines so had to copy them into this file & rename them. - -static uint32_t _I2C_Start(LPC_I2C_TypeDef *I2Cx) { - // Reset STA, STO, SI - I2Cx->I2CONCLR = I2C_I2CONCLR_SIC|I2C_I2CONCLR_STOC|I2C_I2CONCLR_STAC; - - // Enter to Master Transmitter mode - I2Cx->I2CONSET = I2C_I2CONSET_STA; - - // Wait for complete - while (!(I2Cx->I2CONSET & I2C_I2CONSET_SI)); - I2Cx->I2CONCLR = I2C_I2CONCLR_STAC; - return (I2Cx->I2STAT & I2C_STAT_CODE_BITMASK); -} - -static void _I2C_Stop(LPC_I2C_TypeDef *I2Cx) { - // Make sure start bit is not active - if (I2Cx->I2CONSET & I2C_I2CONSET_STA) - I2Cx->I2CONCLR = I2C_I2CONCLR_STAC; - - I2Cx->I2CONSET = I2C_I2CONSET_STO|I2C_I2CONSET_AA; - I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; -} - -I2C_M_SETUP_Type transferMCfg; - -#define I2C_status (LPC_I2C1->I2STAT & I2C_STAT_CODE_BITMASK) - uint8_t digipot_mcp4451_start(uint8_t sla) { // send slave address and write bit // Sometimes TX data ACK or NAK status is returned. That mean the start state didn't // happen which means only the value of the slave address was send. Keep looping until @@ -102,5 +73,5 @@ uint8_t digipot_mcp4451_send_byte(uint8_t data) { } #endif -#endif // MB(MKS_SBASE) +#endif // DIGIPOT_MCP4451 && MKS_SBASE #endif // TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC1768/include/i2c_util.c b/Marlin/src/HAL/LPC1768/include/i2c_util.c index e52fb7c4..4e24f232 100644 --- a/Marlin/src/HAL/LPC1768/include/i2c_util.c +++ b/Marlin/src/HAL/LPC1768/include/i2c_util.c @@ -63,6 +63,32 @@ void configure_i2c(const uint8_t clock_option) { I2C_Cmd(I2CDEV_M, I2C_MASTER_MODE, ENABLE); } +////////////////////////////////////////////////////////////////////////////////////// +// These two routines are exact copies of the lpc17xx_i2c.c routines. Couldn't link to +// to the lpc17xx_i2c.c routines so had to copy them into this file & rename them. + +uint32_t _I2C_Start(LPC_I2C_TypeDef *I2Cx) { + // Reset STA, STO, SI + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC|I2C_I2CONCLR_STOC|I2C_I2CONCLR_STAC; + + // Enter to Master Transmitter mode + I2Cx->I2CONSET = I2C_I2CONSET_STA; + + // Wait for complete + while (!(I2Cx->I2CONSET & I2C_I2CONSET_SI)); + I2Cx->I2CONCLR = I2C_I2CONCLR_STAC; + return (I2Cx->I2STAT & I2C_STAT_CODE_BITMASK); +} + +void _I2C_Stop(LPC_I2C_TypeDef *I2Cx) { + /* Make sure start bit is not active */ + if (I2Cx->I2CONSET & I2C_I2CONSET_STA) + I2Cx->I2CONCLR = I2C_I2CONCLR_STAC; + + I2Cx->I2CONSET = I2C_I2CONSET_STO|I2C_I2CONSET_AA; + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; +} + #ifdef __cplusplus } #endif diff --git a/Marlin/src/HAL/LPC1768/include/i2c_util.h b/Marlin/src/HAL/LPC1768/include/i2c_util.h index a57f68a4..1f1c19f2 100644 --- a/Marlin/src/HAL/LPC1768/include/i2c_util.h +++ b/Marlin/src/HAL/LPC1768/include/i2c_util.h @@ -51,6 +51,11 @@ void configure_i2c(const uint8_t clock_option); +uint32_t _I2C_Start(LPC_I2C_TypeDef *I2Cx); +void _I2C_Stop(LPC_I2C_TypeDef *I2Cx); + +#define I2C_status (LPC_I2C1->I2STAT & I2C_STAT_CODE_BITMASK) + #ifdef __cplusplus } #endif diff --git a/Marlin/src/HAL/LPC1768/main.cpp b/Marlin/src/HAL/LPC1768/main.cpp deleted file mode 100644 index ef0dc42c..00000000 --- a/Marlin/src/HAL/LPC1768/main.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * - * Based on Sprinter and grbl. - * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -#ifdef TARGET_LPC1768 - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../inc/MarlinConfig.h" -#include "../../core/millis_t.h" - -#include "../../sd/cardreader.h" - -extern uint32_t MSC_SD_Init(uint8_t pdrv); - -extern "C" { - #include - extern "C" int isLPC1769(); - extern "C" void disk_timerproc(); -} - -void SysTick_Callback() { disk_timerproc(); } - -TERN_(POSTMORTEM_DEBUGGING, extern void install_min_serial()); - -void HAL_init() { - - // Init LEDs - #if PIN_EXISTS(LED) - SET_DIR_OUTPUT(LED_PIN); - WRITE_PIN_CLR(LED_PIN); - #if PIN_EXISTS(LED2) - SET_DIR_OUTPUT(LED2_PIN); - WRITE_PIN_CLR(LED2_PIN); - #if PIN_EXISTS(LED3) - SET_DIR_OUTPUT(LED3_PIN); - WRITE_PIN_CLR(LED3_PIN); - #if PIN_EXISTS(LED4) - SET_DIR_OUTPUT(LED4_PIN); - WRITE_PIN_CLR(LED4_PIN); - #endif - #endif - #endif - - // Flash status LED 3 times to indicate Marlin has started booting - LOOP_L_N(i, 6) { - TOGGLE(LED_PIN); - delay(100); - } - #endif - - // Init Servo Pins - #define INIT_SERVO(N) OUT_WRITE(SERVO##N##_PIN, LOW) - #if HAS_SERVO_0 - INIT_SERVO(0); - #endif - #if HAS_SERVO_1 - INIT_SERVO(1); - #endif - #if HAS_SERVO_2 - INIT_SERVO(2); - #endif - #if HAS_SERVO_3 - INIT_SERVO(3); - #endif - - //debug_frmwrk_init(); - //_DBG("\n\nDebug running\n"); - // Initialize the SD card chip select pins as soon as possible - #if PIN_EXISTS(SD_SS) - OUT_WRITE(SD_SS_PIN, HIGH); - #endif - - #if PIN_EXISTS(ONBOARD_SD_CS) && ONBOARD_SD_CS_PIN != SD_SS_PIN - OUT_WRITE(ONBOARD_SD_CS_PIN, HIGH); - #endif - - #ifdef LPC1768_ENABLE_CLKOUT_12M - /** - * CLKOUTCFG register - * bit 8 (CLKOUT_EN) = enables CLKOUT signal. Disabled for now to prevent glitch when enabling GPIO. - * bits 7:4 (CLKOUTDIV) = set to 0 for divider setting of /1 - * bits 3:0 (CLKOUTSEL) = set to 1 to select main crystal oscillator as CLKOUT source - */ - LPC_SC->CLKOUTCFG = (0<<8)|(0<<4)|(1<<0); - // set P1.27 pin to function 01 (CLKOUT) - PINSEL_CFG_Type PinCfg; - PinCfg.Portnum = 1; - PinCfg.Pinnum = 27; - PinCfg.Funcnum = 1; // function 01 (CLKOUT) - PinCfg.OpenDrain = 0; // not open drain - PinCfg.Pinmode = 2; // no pull-up/pull-down - PINSEL_ConfigPin(&PinCfg); - // now set CLKOUT_EN bit - SBI(LPC_SC->CLKOUTCFG, 8); - #endif - - USB_Init(); // USB Initialization - USB_Connect(false); // USB clear connection - delay(1000); // Give OS time to notice - USB_Connect(true); - - TERN_(HAS_SD_HOST_DRIVE, MSC_SD_Init(0)); // Enable USB SD card access - - const millis_t usb_timeout = millis() + 2000; - while (!USB_Configuration && PENDING(millis(), usb_timeout)) { - delay(50); - HAL_idletask(); - #if PIN_EXISTS(LED) - TOGGLE(LED_PIN); // Flash quickly during USB initialization - #endif - } - - HAL_timer_init(); - - TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); // Install the min serial handler -} - -// HAL idle task -void HAL_idletask() { - #if HAS_SHARED_MEDIA - // If Marlin is using the SD card we need to lock it to prevent access from - // a PC via USB. - // Other HALs use IS_SD_PRINTING() and IS_SD_FILE_OPEN() to check for access but - // this will not reliably detect delete operations. To be safe we will lock - // the disk if Marlin has it mounted. Unfortunately there is currently no way - // to unmount the disk from the LCD menu. - // if (IS_SD_PRINTING() || IS_SD_FILE_OPEN()) - if (card.isMounted()) - MSC_Aquire_Lock(); - else - MSC_Release_Lock(); - #endif - // Perform USB stack housekeeping - MSC_RunDeferredCommands(); -} - -#endif // TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC1768/pinsDebug.h b/Marlin/src/HAL/LPC1768/pinsDebug.h index a2f5c123..5baeadd0 100644 --- a/Marlin/src/HAL/LPC1768/pinsDebug.h +++ b/Marlin/src/HAL/LPC1768/pinsDebug.h @@ -19,25 +19,35 @@ * along with this program. If not, see . * */ +#pragma once /** - * Support routines for LPC1768 - */ - -/** - * Translation of routines & variables used by pinsDebug.h + * Pins Debugging for LPC1768/9 + * + * - NUMBER_PINS_TOTAL + * - MULTI_NAME_PAD + * - getPinByIndex(index) + * - printPinNameByIndex(index) + * - getPinIsDigitalByIndex(index) + * - digitalPinToAnalogIndex(pin) + * - getValidPinMode(pin) + * - isValidPin(pin) + * - isAnalogPin(pin) + * - digitalRead_mod(pin) + * - pwm_status(pin) + * - printPinPWM(pin) + * - printPinPort(pin) + * - printPinNumber(pin) + * - printPinAnalog(pin) */ #define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS -#define pwm_details(pin) pin = pin // do nothing // print PWM details -#define pwm_status(pin) false //Print a pin's PWM status. Return true if it's currently a PWM pin. -#define IS_ANALOG(P) (DIGITAL_PIN_TO_ANALOG_PIN(P) >= 0 ? 1 : 0) -#define digitalRead_mod(p) extDigitalRead(p) -#define PRINT_PORT(p) -#define GET_ARRAY_PIN(p) pin_array[p].pin -#define PRINT_ARRAY_NAME(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) -#define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("P%d_%02d"), LPC176x::pin_port(p), LPC176x::pin_bit(p)); SERIAL_ECHO(buffer); }while(0) -#define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR("_A%d "), LPC176x::pin_get_adc_channel(pin)); SERIAL_ECHO(buffer); }while(0) +#define isAnalogPin(P) (digitalPinToAnalogIndex(P) >= 0) +#define digitalRead_mod(P) extDigitalRead(P) +#define getPinByIndex(x) pin_array[x].pin +#define printPinNameByIndex(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) +#define printPinNumber(P) do{ sprintf_P(buffer, PSTR("P%d_%02d"), LPC176x::pin_port(P), LPC176x::pin_bit(P)); SERIAL_ECHO(buffer); }while(0) +#define printPinAnalog(P) do{ sprintf_P(buffer, PSTR("_A%d "), LPC176x::pin_get_adc_channel(P)); SERIAL_ECHO(buffer); }while(0) #define MULTI_NAME_PAD 17 // space needed to be pretty if not first name assigned to a pin // pins that will cause hang/reset/disconnect in M43 Toggle and Watch utilities @@ -45,11 +55,15 @@ #define M43_NEVER_TOUCH(Q) ((Q) == P0_29 || (Q) == P0_30 || (Q) == P2_09) // USB pins #endif -bool GET_PINMODE(const pin_t pin) { - if (!LPC176x::pin_is_valid(pin) || LPC176x::pin_adc_enabled(pin)) // found an invalid pin or active analog pin +bool getValidPinMode(const pin_t pin) { + if (!LPC176x::pin_is_valid(pin) || LPC176x::pin_adc_enabled(pin)) // Invalid pin or active analog pin return false; return LPC176x::gpio_direction(pin); } -#define GET_ARRAY_IS_DIGITAL(x) ((bool) pin_array[x].is_digital) +#define getPinIsDigitalByIndex(x) ((bool) pin_array[x].is_digital) + +void printPinPort(const pin_t) {} +void printPinPWM(const pin_t) {} +bool pwm_status(const pin_t) { return false; } diff --git a/Marlin/src/HAL/LPC1768/spi_pins.h b/Marlin/src/HAL/LPC1768/spi_pins.h index e7d77474..ec638d86 100644 --- a/Marlin/src/HAL/LPC1768/spi_pins.h +++ b/Marlin/src/HAL/LPC1768/spi_pins.h @@ -23,19 +23,20 @@ #include "../../core/macros.h" -#if BOTH(SDSUPPORT, HAS_MARLINUI_U8GLIB) && (LCD_PINS_D4 == SD_SCK_PIN || LCD_PINS_ENABLE == SD_MOSI_PIN || DOGLCD_SCK == SD_SCK_PIN || DOGLCD_MOSI == SD_MOSI_PIN) - #define LPC_SOFTWARE_SPI // If the SD card and LCD adapter share the same SPI pins, then software SPI is currently - // needed due to the speed and mode required for communicating with each device being different. - // This requirement can be removed if the SPI access to these devices is updated to use - // spiBeginTransaction. +#if ALL(HAS_MARLINUI_U8GLIB, HAS_MEDIA) && (LCD_PINS_D4 == SD_SCK_PIN || LCD_PINS_EN == SD_MOSI_PIN || DOGLCD_SCK == SD_SCK_PIN || DOGLCD_MOSI == SD_MOSI_PIN) + #define SOFTWARE_SPI // If the SD card and LCD adapter share the same SPI pins, then software SPI is currently + // needed due to the speed and mode required for communicating with each device being different. + // This requirement can be removed if the SPI access to these devices is updated to use + // spiBeginTransaction. #endif -/** onboard SD card */ -//#define SD_SCK_PIN P0_07 -//#define SD_MISO_PIN P0_08 -//#define SD_MOSI_PIN P0_09 -//#define SD_SS_PIN P0_06 -/** external */ +// Onboard SD +//#define SD_SCK_PIN P0_07 +//#define SD_MISO_PIN P0_08 +//#define SD_MOSI_PIN P0_09 +//#define SD_SS_PIN P0_06 + +// External SD #ifndef SD_SCK_PIN #define SD_SCK_PIN P0_15 #endif diff --git a/Marlin/src/HAL/LPC1768/tft/tft_spi.cpp b/Marlin/src/HAL/LPC1768/tft/tft_spi.cpp index a9847b2d..c1486177 100644 --- a/Marlin/src/HAL/LPC1768/tft/tft_spi.cpp +++ b/Marlin/src/HAL/LPC1768/tft/tft_spi.cpp @@ -20,13 +20,15 @@ * */ +#ifdef TARGET_LPC1768 + #include "../../../inc/MarlinConfig.h" #if HAS_SPI_TFT #include "tft_spi.h" -SPIClass TFT_SPI::SPIx(1); +SPIClass TFT_SPI::SPIx(TFT_SPI_DEVICE); void TFT_SPI::Init() { #if PIN_EXISTS(TFT_RESET) @@ -38,40 +40,10 @@ void TFT_SPI::Init() { OUT_WRITE(TFT_BACKLIGHT_PIN, HIGH); #endif - SET_OUTPUT(TFT_DC_PIN); - SET_OUTPUT(TFT_CS_PIN); - WRITE(TFT_DC_PIN, HIGH); - WRITE(TFT_CS_PIN, HIGH); - - /** - * STM32F1 APB2 = 72MHz, APB1 = 36MHz, max SPI speed of this MCU if 18Mhz - * STM32F1 has 3 SPI ports, SPI1 in APB2, SPI2/SPI3 in APB1 - * so the minimum prescale of SPI1 is DIV4, SPI2/SPI3 is DIV2 - */ - #if 0 - #if SPI_DEVICE == 1 - #define SPI_CLOCK_MAX SPI_CLOCK_DIV4 - #else - #define SPI_CLOCK_MAX SPI_CLOCK_DIV2 - #endif - uint8_t clock; - uint8_t spiRate = SPI_FULL_SPEED; - switch (spiRate) { - case SPI_FULL_SPEED: clock = SPI_CLOCK_MAX ; break; - case SPI_HALF_SPEED: clock = SPI_CLOCK_DIV4 ; break; - case SPI_QUARTER_SPEED: clock = SPI_CLOCK_DIV8 ; break; - case SPI_EIGHTH_SPEED: clock = SPI_CLOCK_DIV16; break; - case SPI_SPEED_5: clock = SPI_CLOCK_DIV32; break; - case SPI_SPEED_6: clock = SPI_CLOCK_DIV64; break; - default: clock = SPI_CLOCK_DIV2; // Default from the SPI library - } - #endif + OUT_WRITE(TFT_DC_PIN, HIGH); + OUT_WRITE(TFT_CS_PIN, HIGH); - #if TFT_MISO_PIN == BOARD_SPI1_MISO_PIN - SPIx.setModule(1); - #elif TFT_MISO_PIN == BOARD_SPI2_MISO_PIN - SPIx.setModule(2); - #endif + SPIx.setModule(TFT_SPI_DEVICE); SPIx.setClock(SPI_CLOCK_MAX_TFT); SPIx.setBitOrder(MSBFIRST); SPIx.setDataMode(SPI_MODE0); @@ -102,7 +74,7 @@ uint32_t TFT_SPI::ReadID(uint16_t Reg) { WRITE(TFT_CS_PIN, LOW); WriteReg(Reg); - LOOP_L_N(i, 4) { + for (uint8_t i = 0; i < 4; ++i) { SPIx.read((uint8_t*)&d, 1); data = (data << 8) | d; } @@ -114,17 +86,63 @@ uint32_t TFT_SPI::ReadID(uint16_t Reg) { return data >> 7; } -bool TFT_SPI::isBusy() { return false; } +bool TFT_SPI::isBusy() { + #define __IS_DMA_CONFIGURED(__HANDLE__) ((__HANDLE__)->DMACCSrcAddr != 0) + + // DMA Channel 0 is hardcoded in dmaSendAsync() and dmaSend() + if (!__IS_DMA_CONFIGURED(LPC_GPDMACH0)) return false; + + if (GPDMA_IntGetStatus(GPDMA_STAT_INTERR, 0)) { + // You should not be here - DMA transfer error flag is set + // Abort DMA transfer and release SPI + } + else { + // Check if DMA transfer completed flag is set + if (!GPDMA_IntGetStatus(GPDMA_STAT_INTTC, 0)) return true; + // Check if SPI TX butter is empty and SPI is idle + if ((SSP_GetStatus(LPC_SSPx, SSP_STAT_TXFIFO_EMPTY) == RESET) || (SSP_GetStatus(LPC_SSPx, SSP_STAT_BUSY) == SET)) return true; + } + + Abort(); + return false; +} + +void TFT_SPI::Abort() { + // DMA Channel 0 is hardcoded in dmaSendAsync() and dmaSend() + + // Disable DMA + GPDMA_ChannelCmd(0, DISABLE); + + // Clear ERR and TC + GPDMA_ClearIntPending(GPDMA_STATCLR_INTTC, 0); + GPDMA_ClearIntPending(GPDMA_STATCLR_INTERR, 0); -void TFT_SPI::Abort() { DataTransferEnd(); } + // Disable DMA on SPI + SSP_DMACmd(LPC_SSPx, SSP_DMA_TX, DISABLE); + + // Deconfigure DMA Channel 0 + LPC_GPDMACH0->DMACCControl = 0U; + LPC_GPDMACH0->DMACCConfig = 0U; + LPC_GPDMACH0->DMACCSrcAddr = 0U; + LPC_GPDMACH0->DMACCDestAddr = 0U; + + DataTransferEnd(); +} void TFT_SPI::Transmit(uint16_t Data) { SPIx.transfer(Data); } -void TFT_SPI::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) { +void TFT_SPI::Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) { DataTransferBegin(DATASIZE_16BIT); - WRITE(TFT_DC_PIN, HIGH); SPIx.dmaSend(Data, Count, MemoryIncrease); - DataTransferEnd(); + Abort(); +} + +void TFT_SPI::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) { + DataTransferBegin(DATASIZE_16BIT); + SPIx.dmaSendAsync(Data, Count, MemoryIncrease); + + TERN_(TFT_SHARED_IO, while (isBusy())); } #endif // HAS_SPI_TFT +#endif // TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC1768/tft/tft_spi.h b/Marlin/src/HAL/LPC1768/tft/tft_spi.h index 4753fdba..54b72248 100644 --- a/Marlin/src/HAL/LPC1768/tft/tft_spi.h +++ b/Marlin/src/HAL/LPC1768/tft/tft_spi.h @@ -27,6 +27,18 @@ #include // #include +#define IS_SPI(N) (BOARD_NR_SPI >= N && (TFT_SCK_PIN == BOARD_SPI##N##_SCK_PIN) && (TFT_MOSI_PIN == BOARD_SPI##N##_MOSI_PIN) && (TFT_MISO_PIN == BOARD_SPI##N##_MISO_PIN)) +#if IS_SPI(1) + #define TFT_SPI_DEVICE 1 + #define LPC_SSPx LPC_SSP0 +#elif IS_SPI(2) + #define TFT_SPI_DEVICE 2 + #define LPC_SSPx LPC_SSP1 +#else + #error "Invalid TFT SPI configuration." +#endif +#undef IS_SPI + #ifndef LCD_READ_ID #define LCD_READ_ID 0x04 // Read display identification information (0xD3 on ILI9341) #endif @@ -34,17 +46,19 @@ #define LCD_READ_ID4 0xD3 // Read display identification information (0xD3 on ILI9341) #endif -#define DATASIZE_8BIT SSP_DATABIT_8 -#define DATASIZE_16BIT SSP_DATABIT_16 -#define TFT_IO_DRIVER TFT_SPI +#define DATASIZE_8BIT SSP_DATABIT_8 +#define DATASIZE_16BIT SSP_DATABIT_16 +#define TFT_IO_DRIVER TFT_SPI +#define DMA_MAX_WORDS 0xFFF -#define DMA_MINC_ENABLE 1 -#define DMA_MINC_DISABLE 0 +#define DMA_MINC_ENABLE 1 +#define DMA_MINC_DISABLE 0 class TFT_SPI { private: static uint32_t ReadID(uint16_t Reg); static void Transmit(uint16_t Data); + static void Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count); static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count); public: @@ -56,22 +70,20 @@ class TFT_SPI { static void Abort(); static void DataTransferBegin(uint16_t DataWidth = DATASIZE_16BIT); - static void DataTransferEnd() { OUT_WRITE(TFT_CS_PIN, HIGH); SPIx.end(); }; + static void DataTransferEnd() { WRITE(TFT_CS_PIN, HIGH); SSP_Cmd(LPC_SSPx, DISABLE); }; static void DataTransferAbort(); static void WriteData(uint16_t Data) { Transmit(Data); } - static void WriteReg(uint16_t Reg) { OUT_WRITE(TFT_A0_PIN, LOW); Transmit(Reg); OUT_WRITE(TFT_A0_PIN, HIGH); } + static void WriteReg(uint16_t Reg) { WRITE(TFT_DC_PIN, LOW); Transmit(Reg); WRITE(TFT_DC_PIN, HIGH); } + + static void WriteSequence_DMA(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_MINC_ENABLE, Data, Count); } + static void WriteMultiple_DMA(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_MINC_DISABLE, &Data, Count); } - static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_MINC_ENABLE, Data, Count); } - // static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_MINC_DISABLE, &Data, Count); } + static void WriteSequence(uint16_t *Data, uint16_t Count) { Transmit(DMA_MINC_ENABLE, Data, Count); } static void WriteMultiple(uint16_t Color, uint32_t Count) { - static uint16_t Data; Data = Color; - //LPC dma can only write 0xFFF bytes at once. - #define MAX_DMA_SIZE (0xFFF - 1) while (Count > 0) { - TransmitDMA(DMA_MINC_DISABLE, &Data, Count > MAX_DMA_SIZE ? MAX_DMA_SIZE : Count); - Count = Count > MAX_DMA_SIZE ? Count - MAX_DMA_SIZE : 0; + Transmit(DMA_MINC_DISABLE, &Color, Count > DMA_MAX_WORDS ? DMA_MAX_WORDS : Count); + Count = Count > DMA_MAX_WORDS ? Count - DMA_MAX_WORDS : 0; } - #undef MAX_DMA_SIZE } }; diff --git a/Marlin/src/HAL/LPC1768/tft/xpt2046.cpp b/Marlin/src/HAL/LPC1768/tft/xpt2046.cpp index 9c1e1589..91051161 100644 --- a/Marlin/src/HAL/LPC1768/tft/xpt2046.cpp +++ b/Marlin/src/HAL/LPC1768/tft/xpt2046.cpp @@ -20,6 +20,8 @@ * */ +#ifdef TARGET_LPC1768 + #include "../../../inc/MarlinConfig.h" #if HAS_TFT_XPT2046 || HAS_RES_TOUCH_BUTTONS @@ -44,9 +46,11 @@ uint16_t delta(uint16_t a, uint16_t b) { return a > b ? a - b : b - a; } #endif void XPT2046::Init() { - SET_INPUT(TOUCH_MISO_PIN); - SET_OUTPUT(TOUCH_MOSI_PIN); - SET_OUTPUT(TOUCH_SCK_PIN); + #if DISABLED(TOUCH_BUTTONS_HW_SPI) + SET_INPUT(TOUCH_MISO_PIN); + SET_OUTPUT(TOUCH_MOSI_PIN); + SET_OUTPUT(TOUCH_SCK_PIN); + #endif OUT_WRITE(TOUCH_CS_PIN, HIGH); #if PIN_EXISTS(TOUCH_INT) @@ -128,4 +132,5 @@ uint16_t XPT2046::SoftwareIO(uint16_t data) { return result; } -#endif // HAS_TFT_XPT2046 +#endif // HAS_TFT_XPT2046 || HAS_RES_TOUCH_BUTTONS +#endif // TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC1768/tft/xpt2046.h b/Marlin/src/HAL/LPC1768/tft/xpt2046.h index aba0799e..7c456cf0 100644 --- a/Marlin/src/HAL/LPC1768/tft/xpt2046.h +++ b/Marlin/src/HAL/LPC1768/tft/xpt2046.h @@ -65,8 +65,8 @@ class XPT2046 { static uint16_t getRawData(const XPTCoordinate coordinate); static bool isTouched(); - static inline void DataTransferBegin() { WRITE(TOUCH_CS_PIN, LOW); }; - static inline void DataTransferEnd() { WRITE(TOUCH_CS_PIN, HIGH); }; + static void DataTransferBegin() { WRITE(TOUCH_CS_PIN, LOW); }; + static void DataTransferEnd() { WRITE(TOUCH_CS_PIN, HIGH); }; #if ENABLED(TOUCH_BUTTONS_HW_SPI) static uint16_t HardwareIO(uint16_t data); #endif diff --git a/Marlin/src/HAL/LPC1768/timers.cpp b/Marlin/src/HAL/LPC1768/timers.cpp index bbb13f81..b541ab6e 100644 --- a/Marlin/src/HAL/LPC1768/timers.cpp +++ b/Marlin/src/HAL/LPC1768/timers.cpp @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Marlin/src/HAL/LPC1768/timers.h b/Marlin/src/HAL/LPC1768/timers.h index 78e856db..bae01703 100644 --- a/Marlin/src/HAL/LPC1768/timers.h +++ b/Marlin/src/HAL/LPC1768/timers.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -170,4 +171,4 @@ FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) { } } -#define HAL_timer_isr_epilogue(T) +#define HAL_timer_isr_epilogue(T) NOOP diff --git a/Marlin/src/HAL/LPC1768/u8g/LCD_I2C_routines.cpp b/Marlin/src/HAL/LPC1768/u8g/LCD_I2C_routines.cpp index a48a820d..e714c3c1 100644 --- a/Marlin/src/HAL/LPC1768/u8g/LCD_I2C_routines.cpp +++ b/Marlin/src/HAL/LPC1768/u8g/LCD_I2C_routines.cpp @@ -36,40 +36,7 @@ extern int millis(); ////////////////////////////////////////////////////////////////////////////////////// -// These two routines are exact copies of the lpc17xx_i2c.c routines. Couldn't link to -// to the lpc17xx_i2c.c routines so had to copy them into this file & rename them. - -static uint32_t _I2C_Start(LPC_I2C_TypeDef *I2Cx) { - // Reset STA, STO, SI - I2Cx->I2CONCLR = I2C_I2CONCLR_SIC|I2C_I2CONCLR_STOC|I2C_I2CONCLR_STAC; - - // Enter to Master Transmitter mode - I2Cx->I2CONSET = I2C_I2CONSET_STA; - - // Wait for complete - while (!(I2Cx->I2CONSET & I2C_I2CONSET_SI)); - I2Cx->I2CONCLR = I2C_I2CONCLR_STAC; - return (I2Cx->I2STAT & I2C_STAT_CODE_BITMASK); -} - -static void _I2C_Stop (LPC_I2C_TypeDef *I2Cx) { - /* Make sure start bit is not active */ - if (I2Cx->I2CONSET & I2C_I2CONSET_STA) - I2Cx->I2CONCLR = I2C_I2CONCLR_STAC; - - I2Cx->I2CONSET = I2C_I2CONSET_STO|I2C_I2CONSET_AA; - I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; -} - -////////////////////////////////////////////////////////////////////////////////////// - -#define I2CDEV_S_ADDR 0x78 // from SSD1306 //actual address is 0x3C - shift left 1 with LSB set to 0 to indicate write - -#define BUFFER_SIZE 0x1 // only do single byte transfers with LCDs - -I2C_M_SETUP_Type transferMCfg; - -#define I2C_status (LPC_I2C1->I2STAT & I2C_STAT_CODE_BITMASK) +#define I2CDEV_S_ADDR 0x78 // From SSD1306 (actual address is 0x3C - shift left 1 with LSB set to 0 to indicate write) // Send slave address and write bit uint8_t u8g_i2c_start(const uint8_t sla) { @@ -115,7 +82,6 @@ uint8_t u8g_i2c_send_byte(uint8_t data) { void u8g_i2c_stop() { } - #ifdef __cplusplus } #endif diff --git a/Marlin/src/HAL/LPC1768/u8g/LCD_defines.h b/Marlin/src/HAL/LPC1768/u8g/LCD_defines.h index d2260037..fb7fdcb8 100644 --- a/Marlin/src/HAL/LPC1768/u8g/LCD_defines.h +++ b/Marlin/src/HAL/LPC1768/u8g/LCD_defines.h @@ -34,7 +34,6 @@ uint8_t u8g_com_HAL_LPC1768_ST7920_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t ar uint8_t u8g_com_HAL_LPC1768_ST7920_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); uint8_t u8g_com_HAL_LPC1768_ssd_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); - // connect U8g com generic com names to the desired driver #define U8G_COM_HW_SPI u8g_com_HAL_LPC1768_hw_spi_fn // use LPC1768 specific hardware SPI routine #define U8G_COM_SW_SPI u8g_com_HAL_LPC1768_sw_spi_fn // use LPC1768 specific software SPI routine diff --git a/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_hw_spi.cpp b/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_hw_spi.cpp index 0118f928..406fc484 100644 --- a/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_hw_spi.cpp +++ b/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_hw_spi.cpp @@ -125,5 +125,4 @@ uint8_t u8g_com_HAL_LPC1768_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, } #endif // HAS_MARLINUI_U8GLIB - #endif // TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_ssd_hw_i2c.cpp b/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_ssd_hw_i2c.cpp index bf76eaf0..3dea365a 100644 --- a/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_ssd_hw_i2c.cpp +++ b/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_ssd_hw_i2c.cpp @@ -194,5 +194,4 @@ uint8_t u8g_com_HAL_LPC1768_ssd_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_v } #endif // HAS_MARLINUI_U8GLIB - #endif // TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_st7920_hw_spi.cpp b/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_st7920_hw_spi.cpp index ce7b3380..c029dc06 100644 --- a/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_st7920_hw_spi.cpp +++ b/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_st7920_hw_spi.cpp @@ -134,5 +134,4 @@ uint8_t u8g_com_HAL_LPC1768_ST7920_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t ar } #endif // HAS_MARLINUI_U8GLIB - #endif // TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_sw_spi.cpp b/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_sw_spi.cpp index f116a9b8..f6ed7b0e 100644 --- a/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_sw_spi.cpp +++ b/Marlin/src/HAL/LPC1768/u8g/u8g_com_HAL_LPC1768_sw_spi.cpp @@ -75,7 +75,7 @@ uint8_t swSpiTransfer_mode_0(uint8_t b, const uint8_t spi_speed, const pin_t sck_pin, const pin_t miso_pin, const pin_t mosi_pin ) { - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { if (spi_speed == 0) { LPC176x::gpio_set(mosi_pin, !!(b & 0x80)); LPC176x::gpio_set(sck_pin, HIGH); @@ -85,16 +85,16 @@ uint8_t swSpiTransfer_mode_0(uint8_t b, const uint8_t spi_speed, const pin_t sck } else { const uint8_t state = (b & 0x80) ? HIGH : LOW; - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) LPC176x::gpio_set(mosi_pin, state); - LOOP_L_N(j, spi_speed + (miso_pin >= 0 ? 0 : 1)) + for (uint8_t j = 0; j < spi_speed + (miso_pin >= 0 ? 0 : 1); ++j) LPC176x::gpio_set(sck_pin, HIGH); b <<= 1; if (miso_pin >= 0 && LPC176x::gpio_get(miso_pin)) b |= 1; - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) LPC176x::gpio_set(sck_pin, LOW); } } @@ -104,7 +104,7 @@ uint8_t swSpiTransfer_mode_0(uint8_t b, const uint8_t spi_speed, const pin_t sck uint8_t swSpiTransfer_mode_3(uint8_t b, const uint8_t spi_speed, const pin_t sck_pin, const pin_t miso_pin, const pin_t mosi_pin ) { - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { const uint8_t state = (b & 0x80) ? HIGH : LOW; if (spi_speed == 0) { LPC176x::gpio_set(sck_pin, LOW); @@ -113,13 +113,13 @@ uint8_t swSpiTransfer_mode_3(uint8_t b, const uint8_t spi_speed, const pin_t sck LPC176x::gpio_set(sck_pin, HIGH); } else { - LOOP_L_N(j, spi_speed + (miso_pin >= 0 ? 0 : 1)) + for (uint8_t j = 0; j < spi_speed + (miso_pin >= 0 ? 0 : 1); ++j) LPC176x::gpio_set(sck_pin, LOW); - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) LPC176x::gpio_set(mosi_pin, state); - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) LPC176x::gpio_set(sck_pin, HIGH); } b <<= 1; @@ -132,7 +132,7 @@ uint8_t swSpiTransfer_mode_3(uint8_t b, const uint8_t spi_speed, const pin_t sck static uint8_t SPI_speed = 0; static void u8g_sw_spi_HAL_LPC1768_shift_out(uint8_t dataPin, uint8_t clockPin, uint8_t val) { - #if EITHER(FYSETC_MINI_12864, MKS_MINI_12864) + #if ANY(FYSETC_MINI_12864, MKS_MINI_12864) swSpiTransfer_mode_3(val, SPI_speed, clockPin, -1, dataPin); #else swSpiTransfer_mode_0(val, SPI_speed, clockPin, -1, dataPin); @@ -160,10 +160,10 @@ uint8_t u8g_com_HAL_LPC1768_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, break; case U8G_COM_MSG_CHIP_SELECT: - #if EITHER(FYSETC_MINI_12864, MKS_MINI_12864) // LCD SPI is running mode 3 while SD card is running mode 0 - if (arg_val) { // SCK idle state needs to be set to the proper idle state before - // the next chip select goes active - u8g_SetPILevel(u8g, U8G_PI_SCK, 1); // Set SCK to mode 3 idle state before CS goes active + #if ANY(FYSETC_MINI_12864, MKS_MINI_12864) // LCD SPI is running mode 3 while SD card is running mode 0 + if (arg_val) { // SCK idle state needs to be set to the proper idle state before + // the next chip select goes active + u8g_SetPILevel(u8g, U8G_PI_SCK, 1); // Set SCK to mode 3 idle state before CS goes active u8g_SetPILevel(u8g, U8G_PI_CS, LOW); } else { diff --git a/Marlin/src/HAL/LPC1768/upload_extra_script.py b/Marlin/src/HAL/LPC1768/upload_extra_script.py index 7975f151..efd46fdd 100644 --- a/Marlin/src/HAL/LPC1768/upload_extra_script.py +++ b/Marlin/src/HAL/LPC1768/upload_extra_script.py @@ -9,119 +9,127 @@ import pioutil if pioutil.is_pio_build(): - target_filename = "FIRMWARE.CUR" - target_drive = "REARM" + target_filename = "FIRMWARE.CUR" + target_drive = "REARM" - import os,getpass,platform + import platform - current_OS = platform.system() - Import("env") + current_OS = platform.system() + Import("env") - def print_error(e): - print('\nUnable to find destination disk (%s)\n' \ - 'Please select it in platformio.ini using the upload_port keyword ' \ - '(https://docs.platformio.org/en/latest/projectconf/section_env_upload.html) ' \ - 'or copy the firmware (.pio/build/%s/firmware.bin) manually to the appropriate disk\n' \ - %(e, env.get('PIOENV'))) + def print_error(e): + print('\nUnable to find destination disk (%s)\n' \ + 'Please select it in platformio.ini using the upload_port keyword ' \ + '(https://docs.platformio.org/en/latest/projectconf/section_env_upload.html) ' \ + 'or copy the firmware (.pio/build/%s/firmware.bin) manually to the appropriate disk\n' \ + %(e, env.get('PIOENV'))) - def before_upload(source, target, env): - try: - # - # Find a disk for upload - # - upload_disk = 'Disk not found' - target_file_found = False - target_drive_found = False - if current_OS == 'Windows': - # - # platformio.ini will accept this for a Windows upload port designation: 'upload_port = L:' - # Windows - doesn't care about the disk's name, only cares about the drive letter - import subprocess,string - from ctypes import windll + def before_upload(source, target, env): + try: + from pathlib import Path + # + # Find a disk for upload + # + upload_disk = 'Disk not found' + target_file_found = False + target_drive_found = False + if current_OS == 'Windows': + # + # platformio.ini will accept this for a Windows upload port designation: 'upload_port = L:' + # Windows - doesn't care about the disk's name, only cares about the drive letter + import subprocess,string + from ctypes import windll + from pathlib import PureWindowsPath - # getting list of drives - # https://stackoverflow.com/questions/827371/is-there-a-way-to-list-all-the-available-drive-letters-in-python - drives = [] - bitmask = windll.kernel32.GetLogicalDrives() - for letter in string.ascii_uppercase: - if bitmask & 1: - drives.append(letter) - bitmask >>= 1 + # getting list of drives + # https://stackoverflow.com/questions/827371/is-there-a-way-to-list-all-the-available-drive-letters-in-python + drives = [] + bitmask = windll.kernel32.GetLogicalDrives() + for letter in string.ascii_uppercase: + if bitmask & 1: + drives.append(letter) + bitmask >>= 1 - for drive in drives: - final_drive_name = drive + ':\\' - # print ('disc check: {}'.format(final_drive_name)) - try: - volume_info = str(subprocess.check_output('cmd /C dir ' + final_drive_name, stderr=subprocess.STDOUT)) - except Exception as e: - print ('error:{}'.format(e)) - continue - else: - if target_drive in volume_info and not target_file_found: # set upload if not found target file yet - target_drive_found = True - upload_disk = final_drive_name - if target_filename in volume_info: - if not target_file_found: - upload_disk = final_drive_name - target_file_found = True + for drive in drives: + final_drive_name = drive + ':' + # print ('disc check: {}'.format(final_drive_name)) + try: + volume_info = str(subprocess.check_output('cmd /C dir ' + final_drive_name, stderr=subprocess.STDOUT)) + except Exception as e: + print ('error:{}'.format(e)) + continue + else: + if target_drive in volume_info and not target_file_found: # set upload if not found target file yet + target_drive_found = True + upload_disk = PureWindowsPath(final_drive_name) + if target_filename in volume_info: + if not target_file_found: + upload_disk = PureWindowsPath(final_drive_name) + target_file_found = True - elif current_OS == 'Linux': - # - # platformio.ini will accept this for a Linux upload port designation: 'upload_port = /media/media_name/drive' - # - drives = os.listdir(os.path.join(os.sep, 'media', getpass.getuser())) - if target_drive in drives: # If target drive is found, use it. - target_drive_found = True - upload_disk = os.path.join(os.sep, 'media', getpass.getuser(), target_drive) + os.sep - else: - for drive in drives: - try: - files = os.listdir(os.path.join(os.sep, 'media', getpass.getuser(), drive)) - except: - continue - else: - if target_filename in files: - upload_disk = os.path.join(os.sep, 'media', getpass.getuser(), drive) + os.sep - target_file_found = True - break - # - # set upload_port to drive if found - # + elif current_OS == 'Linux': + # + # platformio.ini will accept this for a Linux upload port designation: 'upload_port = /media/media_name/drive' + # + import getpass + user = getpass.getuser() + mpath = Path('/media', user) + drives = [ x for x in mpath.iterdir() if x.is_dir() ] + if target_drive in drives: # If target drive is found, use it. + target_drive_found = True + upload_disk = mpath / target_drive + else: + for drive in drives: + try: + fpath = mpath / drive + filenames = [ x.name for x in fpath.iterdir() if x.is_file() ] + except: + continue + else: + if target_filename in filenames: + upload_disk = mpath / drive + target_file_found = True + break + # + # set upload_port to drive if found + # - if target_file_found or target_drive_found: - env.Replace( - UPLOAD_FLAGS="-P$UPLOAD_PORT" - ) + if target_file_found or target_drive_found: + env.Replace( + UPLOAD_FLAGS="-P$UPLOAD_PORT" + ) - elif current_OS == 'Darwin': # MAC - # - # platformio.ini will accept this for a OSX upload port designation: 'upload_port = /media/media_name/drive' - # - drives = os.listdir('/Volumes') # human readable names - if target_drive in drives and not target_file_found: # set upload if not found target file yet - target_drive_found = True - upload_disk = '/Volumes/' + target_drive + '/' - for drive in drives: - try: - filenames = os.listdir('/Volumes/' + drive + '/') # will get an error if the drive is protected - except: - continue - else: - if target_filename in filenames: - if not target_file_found: - upload_disk = '/Volumes/' + drive + '/' - target_file_found = True + elif current_OS == 'Darwin': # MAC + # + # platformio.ini will accept this for a OSX upload port designation: 'upload_port = /media/media_name/drive' + # + dpath = Path('/Volumes') # human readable names + drives = [ x for x in dpath.iterdir() if x.is_dir() ] + if target_drive in drives and not target_file_found: # set upload if not found target file yet + target_drive_found = True + upload_disk = dpath / target_drive + for drive in drives: + try: + fpath = dpath / drive # will get an error if the drive is protected + filenames = [ x.name for x in fpath.iterdir() if x.is_file() ] + except: + continue + else: + if target_filename in filenames: + upload_disk = dpath / drive + target_file_found = True + break - # - # Set upload_port to drive if found - # - if target_file_found or target_drive_found: - env.Replace(UPLOAD_PORT=upload_disk) - print('\nUpload disk: ', upload_disk, '\n') - else: - print_error('Autodetect Error') + # + # Set upload_port to drive if found + # + if target_file_found or target_drive_found: + env.Replace(UPLOAD_PORT=str(upload_disk)) + print('\nUpload disk: ', upload_disk, '\n') + else: + print_error('Autodetect Error') - except Exception as e: - print_error(str(e)) + except Exception as e: + print_error(str(e)) - env.AddPreAction("upload", before_upload) + env.AddPreAction("upload", before_upload) diff --git a/Marlin/src/HAL/LPC1768/watchdog.cpp b/Marlin/src/HAL/LPC1768/watchdog.cpp deleted file mode 100644 index f23ccf5b..00000000 --- a/Marlin/src/HAL/LPC1768/watchdog.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * - * Based on Sprinter and grbl. - * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -#ifdef TARGET_LPC1768 - -#include "../../inc/MarlinConfig.h" - -#if ENABLED(USE_WATCHDOG) - -#include -#include "watchdog.h" - -#define WDT_TIMEOUT_US TERN(WATCHDOG_DURATION_8S, 8000000, 4000000) // 4 or 8 second timeout - -void watchdog_init() { - #if ENABLED(WATCHDOG_RESET_MANUAL) - // We enable the watchdog timer, but only for the interrupt. - - // Configure WDT to only trigger an interrupt - // Disable WDT interrupt (just in case, to avoid triggering it!) - NVIC_DisableIRQ(WDT_IRQn); - - // We NEED memory barriers to ensure Interrupts are actually disabled! - // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the ) - __DSB(); - __ISB(); - - // Configure WDT to only trigger an interrupt - // Initialize WDT with the given parameters - WDT_Init(WDT_CLKSRC_IRC, WDT_MODE_INT_ONLY); - - // Configure and enable WDT interrupt. - NVIC_ClearPendingIRQ(WDT_IRQn); - NVIC_SetPriority(WDT_IRQn, 0); // Use highest priority, so we detect all kinds of lockups - NVIC_EnableIRQ(WDT_IRQn); - #else - WDT_Init(WDT_CLKSRC_IRC, WDT_MODE_RESET); - #endif - WDT_Start(WDT_TIMEOUT_US); -} - -void HAL_watchdog_refresh() { - WDT_Feed(); - #if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED) - TOGGLE(LED_PIN); // heartbeat indicator - #endif -} - -// Timeout state -bool watchdog_timed_out() { return TEST(WDT_ReadTimeOutFlag(), 0); } -void watchdog_clear_timeout_flag() { WDT_ClrTimeOutFlag(); } - -#endif // USE_WATCHDOG -#endif // TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC1768/win_usb_driver/lpc176x_usb_driver.inf b/Marlin/src/HAL/LPC1768/win_usb_driver/lpc176x_usb_driver.inf index 4732eb85..37d9a617 100644 --- a/Marlin/src/HAL/LPC1768/win_usb_driver/lpc176x_usb_driver.inf +++ b/Marlin/src/HAL/LPC1768/win_usb_driver/lpc176x_usb_driver.inf @@ -8,14 +8,12 @@ DriverVer =04/14/2008, 5.1.2600.5512 [Manufacturer] %PROVIDER%=DeviceList,ntamd64 - [DeviceList] %DESCRIPTION%=LPC1768USB, USB\VID_1D50&PID_6029&MI_00 [DeviceList.ntamd64] %DESCRIPTION%=LPC1768USB, USB\VID_1D50&PID_6029&MI_00 - [LPC1768USB] include=mdmcpq.inf CopyFiles=FakeModemCopyFileSection @@ -28,9 +26,8 @@ AddService=usbser, 0x00000002, LowerFilter_Service_Inst [SerialPropPageAddReg] HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider" - [Strings] PROVIDER = "marlinfw.org" DRIVER.SVC = "Marlin USB Driver" DESCRIPTION= "Marlin USB Serial" -COMPOSITE = "Marlin USB VCOM" \ No newline at end of file +COMPOSITE = "Marlin USB VCOM" diff --git a/Marlin/src/HAL/NATIVE_SIM/HAL.h b/Marlin/src/HAL/NATIVE_SIM/HAL.h index 436b4b4d..8e88e502 100644 --- a/Marlin/src/HAL/NATIVE_SIM/HAL.h +++ b/Marlin/src/HAL/NATIVE_SIM/HAL.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,18 +21,10 @@ */ #pragma once -#define CPU_32_BIT -#define HAL_IDLETASK -void HAL_idletask(); - -#define F_CPU 100000000 -#define SystemCoreClock F_CPU #include #include - #undef min #undef max - #include #include "pinmapping.h" @@ -40,8 +32,6 @@ void _printf (const char *format, ...); void _putc(uint8_t c); uint8_t _getc(); -//extern "C" volatile uint32_t _millis; - //arduino: Print.h #define DEC 10 #define HEX 16 @@ -55,10 +45,25 @@ uint8_t _getc(); #include "../shared/math_32bit.h" #include "../shared/HAL_SPI.h" #include "fastio.h" -#include "watchdog.h" #include "serial.h" -#define SHARED_SERVOS HAS_SERVOS +// ------------------------ +// Defines +// ------------------------ + +#define CPU_32_BIT +#define SHARED_SERVOS HAS_SERVOS // Use shared/servos.cpp + +#define F_CPU 100000000 +#define SystemCoreClock F_CPU + +#define CPU_ST7920_DELAY_1 600 +#define CPU_ST7920_DELAY_2 750 +#define CPU_ST7920_DELAY_3 750 + +// ------------------------ +// Serial ports +// ------------------------ extern MSerialT serial_stream_0; extern MSerialT serial_stream_1; @@ -98,49 +103,19 @@ extern MSerialT serial_stream_3; #endif #endif - -#define CPU_ST7920_DELAY_1 600 -#define CPU_ST7920_DELAY_2 750 -#define CPU_ST7920_DELAY_3 750 - -// +// ------------------------ // Interrupts -// +// ------------------------ + #define CRITICAL_SECTION_START() #define CRITICAL_SECTION_END() -#define ISRS_ENABLED() -#define ENABLE_ISRS() -#define DISABLE_ISRS() - -inline void HAL_init() {} - -// Utility functions -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" -int freeMemory(); -#pragma GCC diagnostic pop +// ------------------------ // ADC -#define HAL_ADC_VREF 5.0 -#define HAL_ADC_RESOLUTION 10 -#define HAL_ANALOG_SELECT(ch) HAL_adc_enable_channel(ch) -#define HAL_START_ADC(ch) HAL_adc_start_conversion(ch) -#define HAL_READ_ADC() HAL_adc_get_result() -#define HAL_ADC_READY() true - -void HAL_adc_init(); -void HAL_adc_enable_channel(const uint8_t ch); -void HAL_adc_start_conversion(const uint8_t ch); -uint16_t HAL_adc_get_result(); - -// PWM -inline void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { analogWrite(pin, v); } - -// Reset source -inline void HAL_clear_reset_source(void) {} -inline uint8_t HAL_get_reset_source(void) { return RST_POWER_ON; } +// ------------------------ -void HAL_reboot(); +#define HAL_ADC_VREF_MV 5000 +#define HAL_ADC_RESOLUTION 10 /* ---------------- Delay in cycles */ @@ -159,29 +134,22 @@ constexpr inline std::size_t strlen_constexpr(const char* str) { // https://github.com/gcc-mirror/gcc/blob/5c7634a0e5f202935aa6c11b6ea953b8bf80a00a/libstdc%2B%2B-v3/include/bits/char_traits.h#L329 if (str != nullptr) { std::size_t i = 0; - while (str[i] != '\0') { - ++i; - } - + while (str[i] != '\0') ++i; return i; } - return 0; } constexpr inline int strncmp_constexpr(const char* lhs, const char* rhs, std::size_t count) { // https://github.com/gcc-mirror/gcc/blob/13b9cbfc32fe3ac4c81c4dd9c42d141c8fb95db4/libstdc%2B%2B-v3/include/bits/char_traits.h#L655 - if (lhs == nullptr || rhs == nullptr) { + if (lhs == nullptr || rhs == nullptr) return rhs != nullptr ? -1 : 1; - } - for (std::size_t i = 0; i < count; ++i) { - if (lhs[i] != rhs[i]) { + for (std::size_t i = 0; i < count; ++i) + if (lhs[i] != rhs[i]) return lhs[i] < rhs[i] ? -1 : 1; - } else if (lhs[i] == '\0') { + else if (lhs[i] == '\0') return 0; - } - } return 0; } @@ -193,14 +161,11 @@ constexpr inline const char* strstr_constexpr(const char* str, const char* targe do { char sc = {}; do { - if ((sc = *str++) == '\0') { - return nullptr; - } + if ((sc = *str++) == '\0') return nullptr; } while (sc != c); } while (strncmp_constexpr(str, target, len) != 0); --str; } - return str; } @@ -211,12 +176,91 @@ constexpr inline char* strstr_constexpr(char* str, const char* target) { do { char sc = {}; do { - if ((sc = *str++) == '\0') { - return nullptr; - } + if ((sc = *str++) == '\0') return nullptr; } while (sc != c); } while (strncmp_constexpr(str, target, len) != 0); --str; } return str; } + +// ------------------------ +// Free Memory Accessor +// ------------------------ + +#pragma GCC diagnostic push +#if GCC_VERSION <= 50000 + #pragma GCC diagnostic ignored "-Wunused-function" +#endif + +int freeMemory(); + +#pragma GCC diagnostic pop + +// ------------------------ +// MarlinHAL Class +// ------------------------ + +class MarlinHAL { +public: + + // Earliest possible init, before setup() + MarlinHAL() {} + + // Watchdog + static void watchdog_init(); + static void watchdog_refresh(); + + static void init() {} // Called early in setup() + static void init_board() {} // Called less early in setup() + static void reboot(); // Restart the firmware from 0x0 + + // Interrupts + static bool isr_state() { return true; } + static void isr_on() {} + static void isr_off() {} + + static void delay_ms(const int ms) { _delay_ms(ms); } + + // Tasks, called from idle() + static void idletask(); + + // Reset + static constexpr uint8_t reset_reason = RST_POWER_ON; + static uint8_t get_reset_source() { return reset_reason; } + static void clear_reset_source() {} + + // Free SRAM + static int freeMemory() { return ::freeMemory(); } + + // + // ADC Methods + // + + static uint8_t active_ch; + + // Called by Temperature::init once at startup + static void adc_init(); + + // Called by Temperature::init for each sensor at startup + static void adc_enable(const uint8_t ch); + + // Begin ADC sampling on the given channel. Called from Temperature::isr! + static void adc_start(const uint8_t ch); + + // Is the ADC ready for reading? + static bool adc_ready(); + + // The current value of the ADC register + static uint16_t adc_value(); + + /** + * Set the PWM duty cycle for the pin to the given value. + * No option to invert the duty cycle [default = false] + * No option to change the scale of the provided value to enable finer PWM duty control [default = 255] + */ + static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { + analogWrite(pin, v); + } + +}; diff --git a/Marlin/src/HAL/NATIVE_SIM/MarlinSPI.h b/Marlin/src/HAL/NATIVE_SIM/MarlinSPI.h index b5cc6f02..0c447ba4 100644 --- a/Marlin/src/HAL/NATIVE_SIM/MarlinSPI.h +++ b/Marlin/src/HAL/NATIVE_SIM/MarlinSPI.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Marlin/src/HAL/NATIVE_SIM/fastio.h b/Marlin/src/HAL/NATIVE_SIM/fastio.h index de8013b1..f501afdb 100644 --- a/Marlin/src/HAL/NATIVE_SIM/fastio.h +++ b/Marlin/src/HAL/NATIVE_SIM/fastio.h @@ -44,7 +44,7 @@ * * Now you can simply SET_OUTPUT(STEP); WRITE(STEP, HIGH); WRITE(STEP, LOW); * - * Why double up on these macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html + * Why double up on these macros? see https://gcc.gnu.org/onlinedocs/cpp/Stringification.html */ /// Read a pin diff --git a/Marlin/src/HAL/NATIVE_SIM/inc/Conditionals_post.h b/Marlin/src/HAL/NATIVE_SIM/inc/Conditionals_post.h index 1ac02f11..fc20373d 100644 --- a/Marlin/src/HAL/NATIVE_SIM/inc/Conditionals_post.h +++ b/Marlin/src/HAL/NATIVE_SIM/inc/Conditionals_post.h @@ -20,3 +20,24 @@ * */ #pragma once + +// Newer simulator needs these +#define X_MIN_ENDSTOP_HIT_STATE DISABLED(X_MIN_ENDSTOP_INVERTING) +#define Y_MIN_ENDSTOP_HIT_STATE DISABLED(Y_MIN_ENDSTOP_INVERTING) +#define Z_MIN_ENDSTOP_HIT_STATE DISABLED(Z_MIN_ENDSTOP_INVERTING) +#define I_MIN_ENDSTOP_HIT_STATE DISABLED(I_MIN_ENDSTOP_INVERTING) +#define J_MIN_ENDSTOP_HIT_STATE DISABLED(J_MIN_ENDSTOP_INVERTING) +#define K_MIN_ENDSTOP_HIT_STATE DISABLED(K_MIN_ENDSTOP_INVERTING) +#define U_MIN_ENDSTOP_HIT_STATE DISABLED(U_MIN_ENDSTOP_INVERTING) +#define V_MIN_ENDSTOP_HIT_STATE DISABLED(V_MIN_ENDSTOP_INVERTING) +#define W_MIN_ENDSTOP_HIT_STATE DISABLED(W_MIN_ENDSTOP_INVERTING) +#define X_MAX_ENDSTOP_HIT_STATE DISABLED(X_MAX_ENDSTOP_INVERTING) +#define Y_MAX_ENDSTOP_HIT_STATE DISABLED(Y_MAX_ENDSTOP_INVERTING) +#define Z_MAX_ENDSTOP_HIT_STATE DISABLED(Z_MAX_ENDSTOP_INVERTING) +#define I_MAX_ENDSTOP_HIT_STATE DISABLED(I_MAX_ENDSTOP_INVERTING) +#define J_MAX_ENDSTOP_HIT_STATE DISABLED(J_MAX_ENDSTOP_INVERTING) +#define K_MAX_ENDSTOP_HIT_STATE DISABLED(K_MAX_ENDSTOP_INVERTING) +#define U_MAX_ENDSTOP_HIT_STATE DISABLED(U_MAX_ENDSTOP_INVERTING) +#define V_MAX_ENDSTOP_HIT_STATE DISABLED(V_MAX_ENDSTOP_INVERTING) +#define W_MAX_ENDSTOP_HIT_STATE DISABLED(W_MAX_ENDSTOP_INVERTING) +#define Z_MIN_PROBE_ENDSTOP_HIT_STATE DISABLED(Z_MIN_PROBE_ENDSTOP_INVERTING) diff --git a/Marlin/src/HAL/NATIVE_SIM/inc/SanityCheck.h b/Marlin/src/HAL/NATIVE_SIM/inc/SanityCheck.h index 2d7bef23..615e5254 100644 --- a/Marlin/src/HAL/NATIVE_SIM/inc/SanityCheck.h +++ b/Marlin/src/HAL/NATIVE_SIM/inc/SanityCheck.h @@ -31,7 +31,7 @@ #endif #if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY - #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported on LINUX." + #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported for HAL/LINUX." #endif #if HAS_TMC_SW_SERIAL diff --git a/Marlin/src/HAL/NATIVE_SIM/pinsDebug.cpp b/Marlin/src/HAL/NATIVE_SIM/pinsDebug.cpp new file mode 100644 index 00000000..1354c79b --- /dev/null +++ b/Marlin/src/HAL/NATIVE_SIM/pinsDebug.cpp @@ -0,0 +1,49 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifdef __PLAT_NATIVE_SIM__ + +#include "../../inc/MarlinConfig.h" +#include "pinsDebug.h" + +int8_t ADC_pin_mode(const pin_t) { return -1; } + +int8_t get_pin_mode(const pin_t pin) { return isValidPin(pin) ? 0 : -1; } + +bool getValidPinMode(const pin_t pin) { + const int8_t pin_mode = get_pin_mode(pin); + if (pin_mode == -1 || pin_mode == ADC_pin_mode(pin)) // Invalid pin or active analog pin + return false; + + return (Gpio::getMode(pin) != 0); // Input/output state +} + +// The pin and index are the same on this platform +bool getPinIsDigitalByIndex(const pin_t pin) { + return !isAnalogPin(pin) || get_pin_mode(pin) != ADC_pin_mode(pin); +} + +void printPinPort(const pin_t) {} +void printPinPWM(const pin_t) {} +bool pwm_status(const pin_t) { return false; } + +#endif diff --git a/Marlin/src/HAL/NATIVE_SIM/pinsDebug.h b/Marlin/src/HAL/NATIVE_SIM/pinsDebug.h index aa90eb39..752802d4 100644 --- a/Marlin/src/HAL/NATIVE_SIM/pinsDebug.h +++ b/Marlin/src/HAL/NATIVE_SIM/pinsDebug.h @@ -2,6 +2,9 @@ * Marlin 3D Printer Firmware * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -16,46 +19,43 @@ * along with this program. If not, see . * */ - -/** - * Support routines for X86_64 - */ #pragma once /** - * Translation of routines & variables used by pinsDebug.h + * Pins Debugging for x86_64 + * + * - NUMBER_PINS_TOTAL + * - MULTI_NAME_PAD + * - getPinByIndex(index) + * - printPinNameByIndex(index) + * - getPinIsDigitalByIndex(index) + * - digitalPinToAnalogIndex(pin) + * - getValidPinMode(pin) + * - isValidPin(pin) + * - isAnalogPin(pin) + * - digitalRead_mod(pin) + * - pwm_status(pin) + * - printPinPWM(pin) + * - printPinPort(pin) + * - printPinNumber(pin) + * - printPinAnalog(pin) */ #define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS -#define pwm_details(pin) pin = pin // do nothing // print PWM details -#define pwm_status(pin) false //Print a pin's PWM status. Return true if it's currently a PWM pin. -#define IS_ANALOG(P) (DIGITAL_PIN_TO_ANALOG_PIN(P) >= 0 ? 1 : 0) -#define digitalRead_mod(p) digitalRead(p) -#define PRINT_PORT(p) -#define GET_ARRAY_PIN(p) pin_array[p].pin -#define PRINT_ARRAY_NAME(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) -#define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%3d "), p); SERIAL_ECHO(buffer); }while(0) -#define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0) +#define isValidPin(P) (P >= 0 && P < pin_t(NUMBER_PINS_TOTAL)) +#define isAnalogPin(P) (digitalPinToAnalogIndex(P) >= 0) +#define digitalRead_mod(P) digitalRead(P) +#define getPinByIndex(x) pin_array[x].pin +#define printPinNameByIndex(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) +#define printPinNumber(P) do{ sprintf_P(buffer, PSTR("%3d "), P); SERIAL_ECHO(buffer); }while(0) +#define printPinAnalog(P) do{ sprintf_P(buffer, PSTR(" (A%2d) "), digitalPinToAnalogIndex(P)); SERIAL_ECHO(buffer); }while(0) #define MULTI_NAME_PAD 16 // space needed to be pretty if not first name assigned to a pin -// active ADC function/mode/code values for PINSEL registers -inline constexpr int8_t ADC_pin_mode(pin_t pin) { - return (-1); -} - -inline int8_t get_pin_mode(pin_t pin) { - if (!VALID_PIN(pin)) return -1; - return 0; -} - -inline bool GET_PINMODE(pin_t pin) { - int8_t pin_mode = get_pin_mode(pin); - if (pin_mode == -1 || pin_mode == ADC_pin_mode(pin)) // found an invalid pin or active analog pin - return false; - - return (Gpio::getMode(pin) != 0); //input/output state -} - -inline bool GET_ARRAY_IS_DIGITAL(pin_t pin) { - return (!IS_ANALOG(pin) || get_pin_mode(pin) != ADC_pin_mode(pin)); -} +// Active ADC function/mode/code values for PINSEL registers +int8_t ADC_pin_mode(const pin_t); +int8_t get_pin_mode(const pin_t); +bool getValidPinMode(const pin_t); +bool getPinIsDigitalByIndex(const pin_t); +void printPinPort(const pin_t); +void printPinPWM(const pin_t); +bool pwm_status(const pin_t); diff --git a/Marlin/src/HAL/NATIVE_SIM/servo_private.h b/Marlin/src/HAL/NATIVE_SIM/servo_private.h index 06be1893..e0eb30ab 100644 --- a/Marlin/src/HAL/NATIVE_SIM/servo_private.h +++ b/Marlin/src/HAL/NATIVE_SIM/servo_private.h @@ -61,7 +61,6 @@ #define INVALID_SERVO 255 // flag indicating an invalid servo index - // Types typedef struct { diff --git a/Marlin/src/HAL/NATIVE_SIM/spi_pins.h b/Marlin/src/HAL/NATIVE_SIM/spi_pins.h index a5138e0c..9b1bae9a 100644 --- a/Marlin/src/HAL/NATIVE_SIM/spi_pins.h +++ b/Marlin/src/HAL/NATIVE_SIM/spi_pins.h @@ -24,8 +24,8 @@ #include "../../core/macros.h" #include "../../inc/MarlinConfigPre.h" -#if BOTH(HAS_MARLINUI_U8GLIB, SDSUPPORT) && (LCD_PINS_D4 == SD_SCK_PIN || LCD_PINS_ENABLE == SD_MOSI_PIN || DOGLCD_SCK == SD_SCK_PIN || DOGLCD_MOSI == SD_MOSI_PIN) - #define LPC_SOFTWARE_SPI // If the SD card and LCD adapter share the same SPI pins, then software SPI is currently +#if ALL(HAS_MARLINUI_U8GLIB, HAS_MEDIA) && (LCD_PINS_D4 == SD_SCK_PIN || LCD_PINS_EN == SD_MOSI_PIN || DOGLCD_SCK == SD_SCK_PIN || DOGLCD_MOSI == SD_MOSI_PIN) + #define SOFTWARE_SPI // If the SD card and LCD adapter share the same SPI pins, then software SPI is currently // needed due to the speed and mode required for communicating with each device being different. // This requirement can be removed if the SPI access to these devices is updated to use // spiBeginTransaction. diff --git a/Marlin/src/HAL/NATIVE_SIM/tft/tft_spi.h b/Marlin/src/HAL/NATIVE_SIM/tft/tft_spi.h index b3e622f1..1e0bc209 100644 --- a/Marlin/src/HAL/NATIVE_SIM/tft/tft_spi.h +++ b/Marlin/src/HAL/NATIVE_SIM/tft/tft_spi.h @@ -31,10 +31,11 @@ #endif #define DATASIZE_8BIT 8 -#define DATASIZE_16BIT 16 -#define TFT_IO_DRIVER TFT_SPI +#define DATASIZE_16BIT 16 +#define TFT_IO_DRIVER TFT_SPI +#define DMA_MAX_WORDS 0xFFFF -#define DMA_MINC_ENABLE 1 +#define DMA_MINC_ENABLE 1 #define DMA_MINC_DISABLE 0 class TFT_SPI { diff --git a/Marlin/src/HAL/NATIVE_SIM/tft/xpt2046.h b/Marlin/src/HAL/NATIVE_SIM/tft/xpt2046.h index 9ef1816c..8bf059f5 100644 --- a/Marlin/src/HAL/NATIVE_SIM/tft/xpt2046.h +++ b/Marlin/src/HAL/NATIVE_SIM/tft/xpt2046.h @@ -2,6 +2,9 @@ * Marlin 3D Printer Firmware * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -51,7 +54,7 @@ enum XPTCoordinate : uint8_t { XPT2046_Z2 = 0x40 | XPT2046_CONTROL | XPT2046_DFR_MODE, }; -#if !defined(XPT2046_Z1_THRESHOLD) +#ifndef XPT2046_Z1_THRESHOLD #define XPT2046_Z1_THRESHOLD 10 #endif @@ -62,8 +65,8 @@ class XPT2046 { static uint16_t getRawData(const XPTCoordinate coordinate); static bool isTouched(); - static inline void DataTransferBegin(); - static inline void DataTransferEnd(); + static void DataTransferBegin(); + static void DataTransferEnd(); #if ENABLED(TOUCH_BUTTONS_HW_SPI) static uint16_t HardwareIO(uint16_t data); #endif diff --git a/Marlin/src/HAL/NATIVE_SIM/timers.h b/Marlin/src/HAL/NATIVE_SIM/timers.h index cedfdb62..d46e8e7b 100644 --- a/Marlin/src/HAL/NATIVE_SIM/timers.h +++ b/Marlin/src/HAL/NATIVE_SIM/timers.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -87,5 +88,5 @@ void HAL_timer_enable_interrupt(const uint8_t timer_num); void HAL_timer_disable_interrupt(const uint8_t timer_num); bool HAL_timer_interrupt_enabled(const uint8_t timer_num); -#define HAL_timer_isr_prologue(T) -#define HAL_timer_isr_epilogue(T) +#define HAL_timer_isr_prologue(T) NOOP +#define HAL_timer_isr_epilogue(T) NOOP diff --git a/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_I2C_routines.h b/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_I2C_routines.h index 6d5f91d3..ec263b6d 100644 --- a/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_I2C_routines.h +++ b/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_I2C_routines.h @@ -34,4 +34,3 @@ void u8g_i2c_stop(); #ifdef __cplusplus } #endif - diff --git a/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_defines.h b/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_defines.h index 44ffbfeb..05d5526b 100644 --- a/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_defines.h +++ b/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_defines.h @@ -21,6 +21,10 @@ */ #pragma once +/** + * Native/Simulator LCD-specific defines + */ + void usleep(uint64_t microsec); // The following are optional depending on the platform. @@ -40,5 +44,3 @@ uint8_t u8g_com_ST7920_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void #define U8G_COM_T6963 u8g_com_null_fn #define U8G_COM_FAST_PARALLEL u8g_com_null_fn #define U8G_COM_UC_I2C u8g_com_null_fn - - diff --git a/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_pin_routines.cpp b/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_pin_routines.cpp index 3b5acc16..91b7e0f6 100644 --- a/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_pin_routines.cpp +++ b/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_pin_routines.cpp @@ -38,13 +38,13 @@ #ifdef __cplusplus extern "C" { #endif -void u8g_SetPinOutput(uint8_t internal_pin_number){SET_DIR_OUTPUT(internal_pin_number);} -void u8g_SetPinInput(uint8_t internal_pin_number){SET_DIR_INPUT(internal_pin_number);} -void u8g_SetPinLevel(uint8_t pin, uint8_t pin_status){WRITE_PIN(pin, pin_status);} -uint8_t u8g_GetPinLevel(uint8_t pin){return READ_PIN(pin);} -void usleep(uint64_t microsec){ -assert(false); // why we here? -} + +void u8g_SetPinOutput(uint8_t internal_pin_number) { SET_DIR_OUTPUT(internal_pin_number); } +void u8g_SetPinInput(uint8_t internal_pin_number) { SET_DIR_INPUT(internal_pin_number); } +void u8g_SetPinLevel(uint8_t pin, uint8_t pin_status) { WRITE_PIN(pin, pin_status); } +uint8_t u8g_GetPinLevel(uint8_t pin) { return READ_PIN(pin); } +void usleep(uint64_t microsec) { assert(false); /* why we here? */ } + #ifdef __cplusplus } #endif diff --git a/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_pin_routines.h b/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_pin_routines.h index c27c84e8..39af4d7e 100644 --- a/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_pin_routines.h +++ b/Marlin/src/HAL/NATIVE_SIM/u8g/LCD_pin_routines.h @@ -31,7 +31,6 @@ * resulted in using about about 25% of the CPU's time. */ - #ifdef __cplusplus extern "C" { #endif diff --git a/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_st7920_sw_spi.cpp b/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_st7920_sw_spi.cpp index c384cdd7..46f2798a 100644 --- a/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_st7920_sw_spi.cpp +++ b/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_st7920_sw_spi.cpp @@ -100,6 +100,7 @@ static void u8g_com_st7920_write_byte_sw_spi(uint8_t rs, uint8_t val) { swSpiTransfer(val & 0x0F0, SPI_speed, SCK_pin_ST7920_HAL, -1, MOSI_pin_ST7920_HAL_HAL); swSpiTransfer(val << 4, SPI_speed, SCK_pin_ST7920_HAL, -1, MOSI_pin_ST7920_HAL_HAL); } + #ifdef __cplusplus extern "C" { #endif @@ -128,7 +129,7 @@ uint8_t u8g_com_ST7920_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void break; case U8G_COM_MSG_RESET: - if (U8G_PIN_NONE != u8g->pin_list[U8G_PI_RESET]) u8g_SetPILevel(u8g, U8G_PI_RESET, arg_val); + if (U8G_PIN_NONE != u8g->pin_list[U8G_PI_RESET]) u8g_SetPILevel(u8g, U8G_PI_RESET, arg_val); break; case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */ @@ -163,9 +164,10 @@ uint8_t u8g_com_ST7920_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void } return 1; } + #ifdef __cplusplus } #endif #endif // IS_U8GLIB_ST7920 -#endif // TARGET_LPC1768 +#endif // __PLAT_NATIVE_SIM__ diff --git a/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_sw_spi.cpp b/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_sw_spi.cpp index 7be84580..9184e2f6 100644 --- a/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_sw_spi.cpp +++ b/Marlin/src/HAL/NATIVE_SIM/u8g/u8g_com_sw_spi.cpp @@ -70,7 +70,7 @@ #endif uint8_t swSpiTransfer_mode_0(uint8_t b, const uint8_t spi_speed, const pin_t sck_pin, const pin_t miso_pin, const pin_t mosi_pin ) { - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { if (spi_speed == 0) { WRITE_PIN(mosi_pin, !!(b & 0x80)); WRITE_PIN(sck_pin, HIGH); @@ -80,16 +80,16 @@ uint8_t swSpiTransfer_mode_0(uint8_t b, const uint8_t spi_speed, const pin_t sck } else { const uint8_t state = (b & 0x80) ? HIGH : LOW; - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) WRITE_PIN(mosi_pin, state); - LOOP_L_N(j, spi_speed + (miso_pin >= 0 ? 0 : 1)) + for (uint8_t j = 0; j < spi_speed + (miso_pin >= 0 ? 0 : 1); ++j) WRITE_PIN(sck_pin, HIGH); b <<= 1; if (miso_pin >= 0 && READ_PIN(miso_pin)) b |= 1; - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) WRITE_PIN(sck_pin, LOW); } } @@ -99,7 +99,7 @@ uint8_t swSpiTransfer_mode_0(uint8_t b, const uint8_t spi_speed, const pin_t sck uint8_t swSpiTransfer_mode_3(uint8_t b, const uint8_t spi_speed, const pin_t sck_pin, const pin_t miso_pin, const pin_t mosi_pin ) { - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { const uint8_t state = (b & 0x80) ? HIGH : LOW; if (spi_speed == 0) { WRITE_PIN(sck_pin, LOW); @@ -108,13 +108,13 @@ uint8_t swSpiTransfer_mode_3(uint8_t b, const uint8_t spi_speed, const pin_t sck WRITE_PIN(sck_pin, HIGH); } else { - LOOP_L_N(j, spi_speed + (miso_pin >= 0 ? 0 : 1)) + for (uint8_t j = 0; j < spi_speed + (miso_pin >= 0 ? 0 : 1); ++j) WRITE_PIN(sck_pin, LOW); - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) WRITE_PIN(mosi_pin, state); - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) WRITE_PIN(sck_pin, HIGH); } b <<= 1; @@ -131,7 +131,7 @@ static uint8_t swSpiInit(const uint8_t spi_speed, const uint8_t clk_pin, const u } static void u8g_sw_spi_shift_out(uint8_t dataPin, uint8_t clockPin, uint8_t val) { - #if EITHER(FYSETC_MINI_12864, MKS_MINI_12864) + #if ANY(FYSETC_MINI_12864, MKS_MINI_12864) swSpiTransfer_mode_3(val, SPI_speed, clockPin, -1, dataPin); #else swSpiTransfer_mode_0(val, SPI_speed, clockPin, -1, dataPin); @@ -159,10 +159,10 @@ uint8_t u8g_com_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_pt break; case U8G_COM_MSG_CHIP_SELECT: - #if EITHER(FYSETC_MINI_12864, MKS_MINI_12864) // LCD SPI is running mode 3 while SD card is running mode 0 - if (arg_val) { // SCK idle state needs to be set to the proper idle state before - // the next chip select goes active - u8g_SetPILevel(u8g, U8G_PI_SCK, 1); // Set SCK to mode 3 idle state before CS goes active + #if ANY(FYSETC_MINI_12864, MKS_MINI_12864) // LCD SPI is running mode 3 while SD card is running mode 0 + if (arg_val) { // SCK idle state needs to be set to the proper idle state before + // the next chip select goes active + u8g_SetPILevel(u8g, U8G_PI_SCK, 1); // Set SCK to mode 3 idle state before CS goes active u8g_SetPILevel(u8g, U8G_PI_CS, LOW); } else { diff --git a/Marlin/src/HAL/SAMD21/HAL.cpp b/Marlin/src/HAL/SAMD21/HAL.cpp new file mode 100644 index 00000000..3656d971 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/HAL.cpp @@ -0,0 +1,209 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#ifdef __SAMD21__ + +#include "../../inc/MarlinConfig.h" + +#include + +#if USING_HW_SERIALUSB + DefaultSerial1 MSerialUSB(false, SerialUSB); +#endif +#if USING_HW_SERIAL0 + DefaultSerial2 MSerial1(false, Serial1); +#endif +#if USING_HW_SERIAL1 + DefaultSerial3 MSerial2(false, Serial2); +#endif + +#define WDT_CONFIG_PER_7_Val 0x9u +#define WDT_CONFIG_PER_Pos 0 +#define WDT_CONFIG_PER_7 (WDT_CONFIG_PER_7_Val << WDT_CONFIG_PER_Pos) + +#if ENABLED(USE_WATCHDOG) + + #define WDT_TIMEOUT_REG TERN(WATCHDOG_DURATION_8S, WDT_CONFIG_PER_CYC8192, WDT_CONFIG_PER_CYC4096) // 4 or 8 second timeout + + void MarlinHAL::watchdog_init() { + // Set up the generic clock (GCLK2) used to clock the watchdog timer at 1.024kHz + GCLK->GENDIV.reg = GCLK_GENDIV_DIV(4) | // Divide the 32.768kHz clock source by divisor 32, where 2^(4 + 1): 32.768kHz/32=1.024kHz + GCLK_GENDIV_ID(2); // Select Generic Clock (GCLK) 2 + while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization + + REG_GCLK_GENCTRL = GCLK_GENCTRL_DIVSEL | // Set to divide by 2^(GCLK_GENDIV_DIV(4) + 1) + GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW + GCLK_GENCTRL_GENEN | // Enable GCLK2 + GCLK_GENCTRL_SRC_OSCULP32K | // Set the clock source to the ultra low power oscillator (OSCULP32K) + GCLK_GENCTRL_ID(2); // Select GCLK2 + while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization + + // Feed GCLK2 to WDT (Watchdog Timer) + REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | // Enable GCLK2 to the WDT + GCLK_CLKCTRL_GEN_GCLK2 | // Select GCLK2 + GCLK_CLKCTRL_ID_WDT; // Feed the GCLK2 to the WDT + while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization + + WDT->CONFIG.bit.PER = WDT_CONFIG_PER_7; // Set the WDT reset timeout to 4 seconds + while (WDT->STATUS.bit.SYNCBUSY); // Wait for synchronization + REG_WDT_CTRL = WDT_CTRL_ENABLE; // Enable the WDT in normal mode + while (WDT->STATUS.bit.SYNCBUSY); // Wait for synchronization + } + + // Reset watchdog. MUST be called at least every 4 seconds after the + // first watchdog_init or SAMD will go into emergency procedures. + void MarlinHAL::watchdog_refresh() { + WDT->CLEAR.reg = WDT_CLEAR_CLEAR_KEY; + while (WDT->STATUS.bit.SYNCBUSY); + } + +#endif + +// ------------------------ +// Types +// ------------------------ + +// ------------------------ +// Private Variables +// ------------------------ + +// ------------------------ +// Private functions +// ------------------------ + +void MarlinHAL::dma_init() {} + +// ------------------------ +// Public functions +// ------------------------ + +// HAL initialization task +void MarlinHAL::init() { + TERN_(DMA_IS_REQUIRED, dma_init()); + #if HAS_MEDIA + #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 + #endif +} + +#pragma push_macro("WDT") +#undef WDT // Required to be able to use '.bit.WDT'. Compiler wrongly replace struct field with WDT define +uint8_t MarlinHAL::get_reset_source() { + + return 0; +} +#pragma pop_macro("WDT") + +void MarlinHAL::reboot() { NVIC_SystemReset(); } + +extern "C" { + void * _sbrk(int incr); + extern unsigned int __bss_end__; // end of bss section +} + +// Return free memory between end of heap (or end bss) and whatever is current +int freeMemory() { + int free_memory, heap_end = (int)_sbrk(0); + return (int)&free_memory - (heap_end ?: (int)&__bss_end__); +} + +// ------------------------ +// ADC +// ------------------------ + +uint16_t MarlinHAL::adc_result; + +void MarlinHAL::adc_init() { + /* thanks to https://www.eevblog.com/forum/microcontrollers/samd21g18-adc-with-resrdy-interrupts-only-reads-once-or-twice/ */ + + ADC->CTRLA.bit.ENABLE = false; + while(ADC->STATUS.bit.SYNCBUSY); + + // load chip corrections + uint32_t bias = (*((uint32_t *) ADC_FUSES_BIASCAL_ADDR) & ADC_FUSES_BIASCAL_Msk) >> ADC_FUSES_BIASCAL_Pos; + uint32_t linearity = (*((uint32_t *) ADC_FUSES_LINEARITY_0_ADDR) & ADC_FUSES_LINEARITY_0_Msk) >> ADC_FUSES_LINEARITY_0_Pos; + linearity |= ((*((uint32_t *) ADC_FUSES_LINEARITY_1_ADDR) & ADC_FUSES_LINEARITY_1_Msk) >> ADC_FUSES_LINEARITY_1_Pos) << 5; + + /* Wait for bus synchronization. */ + while (ADC->STATUS.bit.SYNCBUSY) {}; + + ADC->CALIB.reg = ADC_CALIB_BIAS_CAL(bias) | ADC_CALIB_LINEARITY_CAL(linearity); + + /* Wait for bus synchronization. */ + while (ADC->STATUS.bit.SYNCBUSY) {}; + + ADC->CTRLA.bit.SWRST = true; + while(ADC->STATUS.bit.SYNCBUSY); + + ADC->REFCTRL.reg = ADC_REFCTRL_REFSEL_INTVCC1; + ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_32| ADC_AVGCTRL_ADJRES(4);; + + ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV128 | + ADC_CTRLB_RESSEL_16BIT | + ADC_CTRLB_FREERUN; + while(ADC->STATUS.bit.SYNCBUSY); + + ADC->SAMPCTRL.bit.SAMPLEN = 0x00; + while(ADC->STATUS.bit.SYNCBUSY); + + ADC->INPUTCTRL.reg = ADC_INPUTCTRL_INPUTSCAN(HAL_ADC_AIN_LEN) // scan (INPUTSCAN + NUM_EXTUDERS - 1) pins + | ADC_INPUTCTRL_GAIN_DIV2 |ADC_INPUTCTRL_MUXNEG_GND| HAL_ADC_AIN_START ; /* set to first AIN */ + + while(ADC->STATUS.bit.SYNCBUSY); + + ADC->INTENSET.reg |= ADC_INTENSET_RESRDY; // enable Result Ready ADC interrupts + while (ADC->STATUS.bit.SYNCBUSY); + + NVIC_EnableIRQ(ADC_IRQn); // enable ADC interrupts + + NVIC_SetPriority(ADC_IRQn, 3); + + ADC->CTRLA.bit.ENABLE = true; +} + +volatile uint32_t adc_results[HAL_ADC_AIN_NUM_SENSORS]; + +void ADC_Handler() { + while(ADC->STATUS.bit.SYNCBUSY == 1); + int pos = ADC->INPUTCTRL.bit.INPUTOFFSET; + + adc_results[pos] = ADC->RESULT.reg; /* Read the value. */ + ADC->INTFLAG.reg = ADC_INTENSET_RESRDY; /* Clear the data ready flag. */ +} + +void MarlinHAL::adc_start(const pin_t pin) { + /* due to the way INPUTOFFSET works, the last sensor is the first position in the array + and we want the ADC_handler interrupt to be as simple possible, so we do the calculation here. + */ + unsigned int pos = PIN_TO_INPUTCTRL(pin) - HAL_ADC_AIN_START + 1; + if (pos == HAL_ADC_AIN_NUM_SENSORS) pos = 0; + adc_result = adc_results[pos]; // 16-bit resolution + //adc_result = 0xFFFF; +} + +#endif // __SAMD21__ diff --git a/Marlin/src/HAL/SAMD21/HAL.h b/Marlin/src/HAL/SAMD21/HAL.h new file mode 100644 index 00000000..95f391fa --- /dev/null +++ b/Marlin/src/HAL/SAMD21/HAL.h @@ -0,0 +1,222 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +#define CPU_32_BIT + +#include "../shared/Marduino.h" +#include "../shared/math_32bit.h" +#include "../shared/HAL_SPI.h" +#include "fastio.h" + +// ------------------------ +// Serial ports +// ------------------------ +#include "../../core/serial_hook.h" +typedef ForwardSerial1Class< decltype(SerialUSB) > DefaultSerial1; +extern DefaultSerial1 MSerialUSB; + +// Serial ports +typedef ForwardSerial1Class< decltype(Serial1) > DefaultSerial2; +typedef ForwardSerial1Class< decltype(Serial2) > DefaultSerial3; + +extern DefaultSerial2 MSerial0; +extern DefaultSerial3 MSerial1; + +#define __MSERIAL(X) MSerial##X +#define _MSERIAL(X) __MSERIAL(X) +#define MSERIAL(X) _MSERIAL(INCREMENT(X)) + +#if WITHIN(SERIAL_PORT, 0, 1) + #define MYSERIAL1 MSERIAL(SERIAL_PORT) +#elif SERIAL_PORT == -1 + #define MYSERIAL1 MSerialUSB +#else + #error "SERIAL_PORT must be -1 (Native USB only)." +#endif + +#ifdef SERIAL_PORT_2 + #if WITHIN(SERIAL_PORT_2, 0, 1) + #define MYSERIAL2 MSERIAL(SERIAL_PORT) + #elif SERIAL_PORT_2 == -1 + #define MYSERIAL2 MSerialUSB + #else + #error "SERIAL_PORT_2 must be -1 (Native USB only)." + #endif +#endif + +#ifdef MMU2_SERIAL_PORT + #if WITHIN(MMU2_SERIAL_PORT, 0, 1) + #define MMU2_SERIAL MSERIAL(SERIAL_PORT) + #elif MMU2_SERIAL_PORT == -1 + #define MMU2_SERIAL MSerialUSB + #else + #error "MMU2_SERIAL_PORT must be -1 (Native USB only)." + #endif +#endif + +#ifdef LCD_SERIAL_PORT + #if WITHIN(LCD_SERIAL_PORT, 0, 1) + #define LCD_SERIAL MSERIAL(SERIAL_PORT) + #elif LCD_SERIAL_PORT == -1 + #define LCD_SERIAL MSerialUSB + #else + #error "LCD_SERIAL_PORT must be -1 (Native USB only)." + #endif +#endif + +typedef int8_t pin_t; + +#define SHARED_SERVOS HAS_SERVOS // Use shared/servos.cpp + +class Servo; +typedef Servo hal_servo_t; + +// +// Interrupts +// +#define CRITICAL_SECTION_START() const bool irqon = !__get_PRIMASK(); __disable_irq() +#define CRITICAL_SECTION_END() if (irqon) __enable_irq() + +#define cli() __disable_irq() // Disable interrupts +#define sei() __enable_irq() // Enable interrupts + +// +// ADC +// + +#define HAL_ADC_FILTERED 1 // Disable Marlin's oversampling. The HAL filters ADC values. +#define HAL_ADC_VREF_MV 3300 +#define HAL_ADC_RESOLUTION 12 +#define HAL_ADC_AIN_START ADC_INPUTCTRL_MUXPOS_PIN3 +#define HAL_ADC_AIN_NUM_SENSORS 3 +#define HAL_ADC_AIN_LEN HAL_ADC_AIN_NUM_SENSORS-1 + +// +// Pin Mapping for M42, M43, M226 +// +#define GET_PIN_MAP_PIN(index) index +#define GET_PIN_MAP_INDEX(pin) pin +#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval) + +// +// Tone +// +void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration=0); +void noTone(const pin_t _pin); + +// ------------------------ +// Class Utilities +// ------------------------ + +#pragma GCC diagnostic push +#if GCC_VERSION <= 50000 + #pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +char *dtostrf(double __val, signed char __width, unsigned char __prec, char *__s); + +extern "C" int freeMemory(); + +#ifdef __cplusplus + } +#endif + +#pragma GCC diagnostic pop + +// ------------------------ +// MarlinHAL Class +// ------------------------ + +class MarlinHAL { +public: + + // Earliest possible init, before setup() + MarlinHAL() {} + + // Watchdog + static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {}); + static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {}); + + static void init(); // Called early in setup() + static void init_board() {} // Called less early in setup() + static void reboot(); // Restart the firmware from 0x0 + + // Interrupts + static bool isr_state() { return !__get_PRIMASK(); } + static void isr_on() { sei(); } + static void isr_off() { cli(); } + + static void delay_ms(const int ms) { delay(ms); } + + // Tasks, called from idle() + static void idletask() {} + + // Reset + static uint8_t get_reset_source(); + static void clear_reset_source() {} + + // Free SRAM + static int freeMemory() { return ::freeMemory(); } + + // + // ADC Methods + // + + static uint16_t adc_result; + + // Called by Temperature::init once at startup + static void adc_init(); + + // Called by Temperature::init for each sensor at startup + static void adc_enable(const uint8_t ch) {} + + // Begin ADC sampling on the given pin. Called from Temperature::isr! + static void adc_start(const pin_t pin); + + // Is the ADC ready for reading? + static bool adc_ready() { return true; } + + // The current value of the ADC register + static uint16_t adc_value() { return adc_result; } + + /** + * Set the PWM duty cycle for the pin to the given value. + * No option to invert the duty cycle [default = false] + * No option to change the scale of the provided value to enable finer PWM duty control [default = 255] + */ + static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { + analogWrite(pin, v); + } + +private: + static void dma_init(); +}; diff --git a/Marlin/src/HAL/SAMD21/HAL_SPI.cpp b/Marlin/src/HAL/SAMD21/HAL_SPI.cpp new file mode 100644 index 00000000..e01f540c --- /dev/null +++ b/Marlin/src/HAL/SAMD21/HAL_SPI.cpp @@ -0,0 +1,148 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +/** + * Hardware and software SPI implementations are included in this file. + * + * Control of the slave select pin(s) is handled by the calling routines and + * SAMD21 let hardware SPI handling to remove SS from its logic. + */ + +#ifdef __SAMD21__ + +// -------------------------------------------------------------------------- +// Includes +// -------------------------------------------------------------------------- + +#include "../../inc/MarlinConfig.h" +#include + +// -------------------------------------------------------------------------- +// Public functions +// -------------------------------------------------------------------------- + +#if ANY(SOFTWARE_SPI, FORCE_SOFT_SPI) + + // ------------------------ + // Software SPI + // ------------------------ + #error "Software SPI not supported for SAMD21. Use Hardware SPI." + +#else // !SOFTWARE_SPI + + static SPISettings spiConfig; + + // ------------------------ + // Hardware SPI + // ------------------------ + void spiBegin() { + spiInit(SPI_HALF_SPEED); + } + + void spiInit(uint8_t spiRate) { + // Use Marlin datarates + uint32_t clock; + switch (spiRate) { + case SPI_FULL_SPEED: clock = 8000000; break; + case SPI_HALF_SPEED: clock = 4000000; break; + case SPI_QUARTER_SPEED: clock = 2000000; break; + case SPI_EIGHTH_SPEED: clock = 1000000; break; + case SPI_SIXTEENTH_SPEED: clock = 500000; break; + case SPI_SPEED_5: clock = 250000; break; + case SPI_SPEED_6: clock = 125000; break; + default: clock = 4000000; break; // Default from the SPI library + } + spiConfig = SPISettings(clock, MSBFIRST, SPI_MODE0); + SPI.begin(); + } + + /** + * @brief Receives a single byte from the SPI port. + * + * @return Byte received + * + * @details + */ + uint8_t spiRec() { + SPI.beginTransaction(spiConfig); + uint8_t returnByte = SPI.transfer(0xFF); + SPI.endTransaction(); + return returnByte; + } + + /** + * @brief Receives a number of bytes from the SPI port to a buffer + * + * @param buf Pointer to starting address of buffer to write to. + * @param nbyte Number of bytes to receive. + * @return Nothing + */ + void spiRead(uint8_t *buf, uint16_t nbyte) { + if (nbyte == 0) return; + memset(buf, 0xFF, nbyte); + + SPI.beginTransaction(spiConfig); + SPI.transfer(buf, nbyte); + SPI.endTransaction(); + + } + + /** + * @brief Sends a single byte on SPI port + * + * @param b Byte to send + * + * @details + */ + void spiSend(uint8_t b) { + SPI.beginTransaction(spiConfig); + SPI.transfer(b); + SPI.endTransaction(); + } + + /** + * @brief Write token and then write from 512 byte buffer to SPI (for SD card) + * + * @param buf Pointer with buffer start address + * @return Nothing + * + * @details Uses DMA + */ + void spiSendBlock(uint8_t token, const uint8_t *buf) { + SPI.beginTransaction(spiConfig); + SPI.transfer(token); + SPI.transfer((uint8_t*)buf, 512); + SPI.endTransaction(); + } + + void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) { + spiConfig = SPISettings(spiClock, (BitOrder)bitOrder, dataMode); + SPI.beginTransaction(spiConfig); + } +#endif // !SOFTWARE_SPI + +#endif // __SAMD21__ diff --git a/Marlin/src/HAL/TEENSY35_36/watchdog.h b/Marlin/src/HAL/SAMD21/MarlinSPI.h similarity index 78% rename from Marlin/src/HAL/TEENSY35_36/watchdog.h rename to Marlin/src/HAL/SAMD21/MarlinSPI.h index 981b1f0b..7b539279 100644 --- a/Marlin/src/HAL/TEENSY35_36/watchdog.h +++ b/Marlin/src/HAL/SAMD21/MarlinSPI.h @@ -1,6 +1,6 @@ /** * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm @@ -19,12 +19,13 @@ * along with this program. If not, see . * */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ #pragma once -void watchdog_init(); +#include -inline void HAL_watchdog_refresh() { - // Watchdog refresh sequence - WDOG_REFRESH = 0xA602; - WDOG_REFRESH = 0xB480; -} +using MarlinSPI = SPIClass; diff --git a/Marlin/src/HAL/SAMD21/QSPIFlash.cpp b/Marlin/src/HAL/SAMD21/QSPIFlash.cpp new file mode 100644 index 00000000..fa54c620 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/QSPIFlash.cpp @@ -0,0 +1,82 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#include "../../inc/MarlinConfig.h" + +#if ENABLED(QSPI_EEPROM) + +#include "QSPIFlash.h" + +#define INVALID_ADDR 0xFFFFFFFF +#define SECTOR_OF(a) (a & ~(SFLASH_SECTOR_SIZE - 1)) +#define OFFSET_OF(a) (a & (SFLASH_SECTOR_SIZE - 1)) + +Adafruit_SPIFlashBase * QSPIFlash::_flashBase = nullptr; +uint8_t QSPIFlash::_buf[SFLASH_SECTOR_SIZE]; +uint32_t QSPIFlash::_addr = INVALID_ADDR; + +void QSPIFlash::begin() { + if (_flashBase) return; + + _flashBase = new Adafruit_SPIFlashBase(new Adafruit_FlashTransport_QSPI()); + _flashBase->begin(nullptr); +} + +size_t QSPIFlash::size() { + return _flashBase->size(); +} + +uint8_t QSPIFlash::readByte(const uint32_t address) { + if (SECTOR_OF(address) == _addr) return _buf[OFFSET_OF(address)]; + + return _flashBase->read8(address); +} + +void QSPIFlash::writeByte(const uint32_t address, const uint8_t value) { + uint32_t const sector_addr = SECTOR_OF(address); + + // Page changes, flush old and update new cache + if (sector_addr != _addr) { + flush(); + _addr = sector_addr; + + // read a whole page from flash + _flashBase->readBuffer(sector_addr, _buf, SFLASH_SECTOR_SIZE); + } + + _buf[OFFSET_OF(address)] = value; +} + +void QSPIFlash::flush() { + if (_addr == INVALID_ADDR) return; + + _flashBase->eraseSector(_addr / SFLASH_SECTOR_SIZE); + _flashBase->writeBuffer(_addr, _buf, SFLASH_SECTOR_SIZE); + + _addr = INVALID_ADDR; +} + +#endif // QSPI_EEPROM diff --git a/Marlin/src/HAL/SAMD21/QSPIFlash.h b/Marlin/src/HAL/SAMD21/QSPIFlash.h new file mode 100644 index 00000000..58822fe0 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/QSPIFlash.h @@ -0,0 +1,49 @@ +/** + * @file QSPIFlash.h + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach and Dean Miller for Adafruit Industries LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Derived from Adafruit_SPIFlash class with no SdFat references + */ +#pragma once + +#include + +// This class extends Adafruit_SPIFlashBase by adding caching support. +// +// This class will use 4096 Bytes of RAM as a block cache. +class QSPIFlash { + public: + static void begin(); + static size_t size(); + static uint8_t readByte(const uint32_t address); + static void writeByte(const uint32_t address, const uint8_t v); + static void flush(); + + private: + static Adafruit_SPIFlashBase * _flashBase; + static uint8_t _buf[SFLASH_SECTOR_SIZE]; + static uint32_t _addr; +}; + +extern QSPIFlash qspi; diff --git a/Marlin/src/HAL/SAMD21/SAMD21.h b/Marlin/src/HAL/SAMD21/SAMD21.h new file mode 100644 index 00000000..b64c5ce7 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/SAMD21.h @@ -0,0 +1,64 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +#define SYNC(sc) while (sc) { \ + asm(""); \ + } + +// Get SAMD port/pin from specified arduino pin +#define GET_SAMD_PORT(P) _GET_SAMD_PORT(PIN_TO_SAMD_PIN(P)) +#define GET_SAMD_PIN(P) _GET_SAMD_PIN(PIN_TO_SAMD_PIN(P)) + +// Get external interrupt line associated to specified arduino pin +#define PIN_TO_EILINE(P) _SAMDPORTPIN_TO_EILINE(GET_SAMD_PORT(P), GET_SAMD_PIN(P)) + +// Get adc/ain associated to specified arduino pin +#define PIN_TO_ADC(P) (ANAPIN_TO_ADCAIN(P) >> 8) + +// Private defines +#define PIN_TO_SAMD_PIN(P) DIO##P##_PIN + +#define _GET_SAMD_PORT(P) ((P) >> 5) +#define _GET_SAMD_PIN(P) ((P) & 0x1F) + +// Get external interrupt line +#define _SAMDPORTPIN_TO_EILINE(P,B) ((P == 0 && WITHIN(B, 0, 31) && B != 26 && B != 28 && B != 29) ? (B) & 0xF \ + : (P == 1 && (WITHIN(B, 0, 25) || WITHIN(B, 30, 31))) ? (B) & 0xF \ + : (P == 1 && WITHIN(B, 26, 29)) ? 12 + (B) - 26 \ + : (P == 2 && (WITHIN(B, 0, 6) || WITHIN(B, 10, 31)) && B != 29) ? (B) & 0xF \ + : (P == 2 && B == 7) ? 9 \ + : (P == 3 && WITHIN(B, 0, 1)) ? (B) \ + : (P == 3 && WITHIN(B, 8, 12)) ? 3 + (B) - 8 \ + : (P == 3 && WITHIN(B, 20, 21)) ? 10 + (B) - 20 \ + : -1) + +#define A2_AIN 3 +#define A3_AIN 4 +#define A4_AIN 5 +#define PIN_TO_AIN(P) A##P##_AIN +#define AIN_TO_RESULT(P) ( (P - HAL_ADC_AIN_START == HAL_ADC_AIN_NUM_SENSORS-1) ? 0 : (P - HAL_ADC_AIN_START + 1) ) diff --git a/Marlin/src/HAL/SAMD21/Servo.cpp b/Marlin/src/HAL/SAMD21/Servo.cpp new file mode 100644 index 00000000..704d0a29 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/Servo.cpp @@ -0,0 +1,219 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +/** + * This comes from Arduino library which at the moment is buggy and uncompilable + */ + +#ifdef __SAMD21__ + +#include "../../inc/MarlinConfig.h" + +#if HAS_SERVOS + +#include "../shared/servo.h" +#include "../shared/servo_private.h" +#include "SAMD21.h" + +#define __TC_GCLK_ID(t) TC##t##_GCLK_ID +#define _TC_GCLK_ID(t) __TC_GCLK_ID(t) +#define TC_GCLK_ID _TC_GCLK_ID(SERVO_TC) + +#define _TC_PRESCALER(d) TC_CTRLA_PRESCALER_DIV##d##_Val +#define TC_PRESCALER(d) _TC_PRESCALER(d) + +#define __SERVO_IRQn(t) TC##t##_IRQn +#define _SERVO_IRQn(t) __SERVO_IRQn(t) +#define SERVO_IRQn _SERVO_IRQn(SERVO_TC) + +#define HAL_SERVO_TIMER_ISR() TC_HANDLER(SERVO_TC) + +#define TIMER_TCCHANNEL(t) ((t) & 1) +#define TC_COUNTER_START_VAL 0xFFFF + +static volatile int8_t currentServoIndex[_Nbr_16timers]; // index for the servo being pulsed for each timer (or -1 if refresh interval) + +FORCE_INLINE static uint16_t getTimerCount() { + Tcc * const tc = timer_config[SERVO_TC].pTcc; + + tc->CTRLBSET.reg = TCC_CTRLBCLR_CMD_READSYNC; + SYNC(tc->STATUS.reg & TC_STATUS_SYNCBUSY); + + return tc->COUNT.bit.COUNT; +} + +// ---------------------------- +// Interrupt handler for the TC +// ---------------------------- +HAL_SERVO_TIMER_ISR() { + Tcc * const tc = timer_config[SERVO_TC].pTcc; + const timer16_Sequence_t timer = + #ifndef _useTimer1 + _timer2 + #elif !defined(_useTimer2) + _timer1 + #else + (tc->INTFLAG.reg & tc->INTENSET.reg & TC_INTFLAG_MC0) ? _timer1 : _timer2 + #endif + ; + const uint8_t tcChannel = TIMER_TCCHANNEL(timer); + + 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 + // Clear the interrupt + tc->INTFLAG.reg = (tcChannel == 0) ? TC_INTFLAG_MC0 : TC_INTFLAG_MC1; + return; + } + #endif + tc->COUNT.reg = TC_COUNTER_START_VAL; // ...so reset the timer + SYNC(tc->STATUS.reg & TC_STATUS_SYNCBUSY); + } + else if (SERVO_INDEX(timer, cho) < ServoCount) // prior channel handled? + digitalWrite(SERVO(timer, cho).Pin.nbr, LOW); // pulse the prior channel LOW + + 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 + + tc->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; // 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->CC[tcChannel].reg = min(cval, ival); + } + if (tcChannel == 0) { + SYNC(tc->SYNCBUSY.bit.CC0); + tc->INTFLAG.reg = TC_INTFLAG_MC0; // Clear the interrupt + } + else { + SYNC(tc->SYNCBUSY.bit.CC1); + tc->INTFLAG.reg = TC_INTFLAG_MC1; // Clear the interrupt + } +} + +void initISR(const timer16_Sequence_t timer) { + Tcc * const tc = timer_config[SERVO_TC].pTcc; + const uint8_t tcChannel = TIMER_TCCHANNEL(timer); + + static bool initialized = false; // Servo TC has been initialized + if (!initialized) { + NVIC_DisableIRQ(SERVO_IRQn); + + // Disable the timer + tc->CTRLA.bit.ENABLE = false; + SYNC(tc->STATUS.reg & TC_STATUS_SYNCBUSY); + + // Select GCLK0 as timer/counter input clock source + GCLK->CLKCTRL.reg =(GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(TCC0_GCLK_ID)); + SYNC (GCLK->STATUS.bit.SYNCBUSY); + + // Reset the timer + tc->CTRLA.bit.SWRST = true; + SYNC(tc->CTRLA.bit.SWRST); + + // Set timer counter mode to 16 bits + tc->CTRLA.reg = TC_CTRLA_MODE_COUNT16; + + // Set timer counter mode as normal PWM + tc->WAVE.bit.WAVEGEN = TCC_WAVE_WAVEGEN_NPWM_Val; + + // Set the prescaler factor + tc->CTRLA.bit.PRESCALER = TC_PRESCALER(SERVO_TIMER_PRESCALER); + + // Count down + tc->CTRLBSET.reg = TCC_CTRLBCLR_DIR; + SYNC(tc->SYNCBUSY.bit.CTRLB); + + // Reset all servo indexes + memset((void *)currentServoIndex, 0xFF, sizeof(currentServoIndex)); + + // Configure interrupt request + NVIC_ClearPendingIRQ(SERVO_IRQn); + NVIC_SetPriority(SERVO_IRQn, 5); + NVIC_EnableIRQ(SERVO_IRQn); + + initialized = true; + } + + if (!tc->CTRLA.bit.ENABLE) { + // Reset the timer counter + tc->COUNT.reg = TC_COUNTER_START_VAL; + SYNC(tc->STATUS.reg & TC_STATUS_SYNCBUSY); + + // Enable the timer and start it + tc->CTRLA.bit.ENABLE = true; + SYNC(tc->STATUS.reg & TC_STATUS_SYNCBUSY); + } + // First interrupt request after 1 ms + tc->CC[tcChannel].reg = getTimerCount() - (uint16_t)usToTicks(1000UL); + + if (tcChannel == 0 ) { + SYNC(tc->SYNCBUSY.bit.CC0); + + // Clear pending match interrupt + tc->INTFLAG.reg = TC_INTENSET_MC0; + // Enable the match channel interrupt request + tc->INTENSET.reg = TC_INTENSET_MC0; + } + else { + SYNC(tc->SYNCBUSY.bit.CC1); + + // Clear pending match interrupt + tc->INTFLAG.reg = TC_INTENSET_MC1; + // Enable the match channel interrupt request + tc->INTENSET.reg = TC_INTENSET_MC1; + } +} + +void finISR(const timer16_Sequence_t timer_index) { + Tcc * const tc = timer_config[SERVO_TC].pTcc; + const uint8_t tcChannel = TIMER_TCCHANNEL(timer_index); + + // Disable the match channel interrupt request + tc->INTENCLR.reg = (tcChannel == 0) ? TC_INTENCLR_MC0 : TC_INTENCLR_MC1; + + if (true + #if defined(_useTimer1) && defined(_useTimer2) + && (tc->INTENCLR.reg & (TC_INTENCLR_MC0|TC_INTENCLR_MC1)) == 0 + #endif + ) { + // Disable the timer if not used + tc->CTRLA.bit.ENABLE = false; + SYNC(tc->STATUS.reg & TC_STATUS_SYNCBUSY); + } +} + +#endif // HAS_SERVOS + +#endif // __SAMD21__ diff --git a/Marlin/src/HAL/DUE/watchdog.h b/Marlin/src/HAL/SAMD21/ServoTimers.h similarity index 56% rename from Marlin/src/HAL/DUE/watchdog.h rename to Marlin/src/HAL/SAMD21/ServoTimers.h index 5725a100..89805476 100644 --- a/Marlin/src/HAL/DUE/watchdog.h +++ b/Marlin/src/HAL/SAMD21/ServoTimers.h @@ -1,6 +1,6 @@ /** * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm @@ -21,13 +21,25 @@ */ #pragma once -// Arduino Due core now has watchdog support +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +#define _useTimer1 +#define _useTimer2 -#include "HAL.h" +#define TRIM_DURATION 5 // compensation ticks to trim adjust for digitalWrite delays +#define SERVO_TIMER_PRESCALER 64 // timer prescaler factor to 64 (avoid overflowing 16-bit clock counter, at 120MHz this is 1831 ticks per millisecond -// Initialize watchdog with a 4 second interrupt time -void watchdog_init(); +#define SERVO_TC 3 -// Reset watchdog. MUST be called at least every 4 seconds after the -// first watchdog_init or AVR will go into emergency procedures. -inline void HAL_watchdog_refresh() { watchdogReset(); } +typedef enum { + #ifdef _useTimer1 + _timer1, + #endif + #ifdef _useTimer2 + _timer2, + #endif + _Nbr_16timers +} timer16_Sequence_t; diff --git a/Marlin/src/HAL/SAMD21/eeprom_flash.cpp b/Marlin/src/HAL/SAMD21/eeprom_flash.cpp new file mode 100644 index 00000000..5364cd67 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/eeprom_flash.cpp @@ -0,0 +1,144 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#ifdef __SAMD21__ + +#include "../../inc/MarlinConfig.h" + +#if ENABLED(FLASH_EEPROM_EMULATION) + +#define TOTAL_FLASH_SIZE (MARLIN_EEPROM_SIZE+255)/256*256 + +/* reserve flash memory */ +static const uint8_t flashdata[TOTAL_FLASH_SIZE] __attribute__((__aligned__(256))) { }; \ + +#include "../shared/eeprom_api.h" + +size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE; } + +/* + const uint8_t psz = NVMCTRL->SEESTAT.bit.PSZ, + sblk = NVMCTRL->SEESTAT.bit.SBLK; + + return ( + (!psz && !sblk) ? 0 + : (psz <= 2) ? (0x200 << psz) + : (sblk == 1 || psz == 3) ? 4096 + : (sblk == 2 || psz == 4) ? 8192 + : (sblk <= 4 || psz == 5) ? 16384 + : (sblk >= 9 && psz == 7) ? 65536 + : 32768 + ) - eeprom_exclude_size; +} +*/ + +uint32_t PAGE_SIZE; +uint32_t ROW_SIZE; +bool hasWritten = false; +uint8_t * buffer; + +void _erase(const volatile void *flash_ptr) { + NVMCTRL->ADDR.reg = ((uint32_t)flash_ptr) / 2; + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER; + while (!NVMCTRL->INTFLAG.bit.READY) { } + +} + +void erase(const volatile void *flash_ptr, uint32_t size) { + const uint8_t *ptr = (const uint8_t *)flash_ptr; + while (size > ROW_SIZE) { + _erase(ptr); + ptr += ROW_SIZE; + size -= ROW_SIZE; + } + _erase(ptr); +} + +bool PersistentStore::access_start() { + /* clear page buffer*/ + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC; + while (NVMCTRL->INTFLAG.bit.READY == 0) { } + + PAGE_SIZE = pow(2,3 + NVMCTRL->PARAM.bit.PSZ); + ROW_SIZE= PAGE_SIZE * 4; + /*NVMCTRL->SEECFG.reg = NVMCTRL_SEECFG_WMODE_BUFFERED; // Buffered mode and segment reallocation active + if (NVMCTRL->SEESTAT.bit.RLOCK) + NVMCTRL_CMD(NVMCTRL_CTRLB_CMD_USEE); */ // Unlock E2P data write access + // erase(&flashdata[0], TOTAL_FLASH_SIZE); + return true; +} + +bool PersistentStore::access_finish() { + if (hasWritten) { + erase(&flashdata[0], TOTAL_FLASH_SIZE); + + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC; + while (NVMCTRL->INTFLAG.bit.READY == 0) { } + + NVMCTRL->CTRLB.bit.MANW = 0; + + volatile uint32_t *dst_addr = (volatile uint32_t *) &flashdata; + + uint32_t *pointer = (uint32_t *) buffer; + for (uint32_t i = 0; i < TOTAL_FLASH_SIZE; i += 4) { + *dst_addr = (uint32_t) *pointer; + pointer++; + dst_addr ++; + } + + // Execute "WP" Write Page + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP; + while (NVMCTRL->INTFLAG.bit.READY == 0) { } + + free(buffer); + hasWritten = false; + } + return true; +} + +bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) { + if (!hasWritten) { + // init temp buffer + buffer = (uint8_t *) malloc(MARLIN_EEPROM_SIZE); + hasWritten = true; + } + + memcpy(buffer+pos,value,size); + pos += size; + return false; +} + +bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) { + volatile uint8_t *dst_addr = (volatile uint8_t *) &flashdata; + dst_addr += pos; + + memcpy(value, (const void *)dst_addr, size); + pos += size; + return false; +} + +#endif // FLASH_EEPROM_EMULATION +#endif // __SAMD21__ diff --git a/Marlin/src/HAL/SAMD21/eeprom_qspi.cpp b/Marlin/src/HAL/SAMD21/eeprom_qspi.cpp new file mode 100644 index 00000000..587dcb0b --- /dev/null +++ b/Marlin/src/HAL/SAMD21/eeprom_qspi.cpp @@ -0,0 +1,79 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#ifdef __SAMD21__ + +#include "../../inc/MarlinConfig.h" + +#if ENABLED(QSPI_EEPROM) + +#error "QSPI_EEPROM emulation Not implemented on SAMD21" + +#include "../shared/eeprom_api.h" + +#include "QSPIFlash.h" + +static bool initialized; + +size_t PersistentStore::capacity() { return qspi.size(); } + +bool PersistentStore::access_start() { + if (!initialized) { + qspi.begin(); + initialized = true; + } + return true; +} + +bool PersistentStore::access_finish() { + qspi.flush(); + return true; +} + +bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) { + while (size--) { + const uint8_t v = *value; + qspi.writeByte(pos, v); + crc16(crc, &v, 1); + pos++; + value++; + } + return false; +} + +bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) { + while (size--) { + uint8_t c = qspi.readByte(pos); + if (writing) *value = c; + crc16(crc, &c, 1); + pos++; + value++; + } + return false; +} + +#endif // QSPI_EEPROM +#endif // __SAMD21__ diff --git a/Marlin/src/HAL/SAMD21/eeprom_wired.cpp b/Marlin/src/HAL/SAMD21/eeprom_wired.cpp new file mode 100644 index 00000000..ab71e616 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/eeprom_wired.cpp @@ -0,0 +1,82 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#ifdef __SAMD21__ + +#include "../../inc/MarlinConfig.h" + +#if USE_WIRED_EEPROM + +#error "USE_WIRED_EEPROM emulation Not implemented on SAMD21" +/** + * PersistentStore for Arduino-style EEPROM interface + * with simple implementations supplied by Marlin. + */ + +#include "../shared/eeprom_if.h" +#include "../shared/eeprom_api.h" + +#ifndef MARLIN_EEPROM_SIZE + #error "MARLIN_EEPROM_SIZE is required for I2C / SPI EEPROM." +#endif +size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE; } + +bool PersistentStore::access_start() { eeprom_init(); return true; } +bool PersistentStore::access_finish() { return true; } + +bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) { + uint16_t written = 0; + while (size--) { + const uint8_t v = *value; + uint8_t * const p = (uint8_t * const)pos; + if (v != eeprom_read_byte(p)) { // EEPROM has only ~100,000 write cycles, so only write bytes that have changed! + eeprom_write_byte(p, v); + if (++written & 0x7F) delay(2); else safe_delay(2); // Avoid triggering watchdog during long EEPROM writes + if (eeprom_read_byte(p) != v) { + SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE); + return true; + } + } + crc16(crc, &v, 1); + pos++; + value++; + } + return false; +} + +bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) { + while (size--) { + uint8_t c = eeprom_read_byte((uint8_t*)pos); + if (writing) *value = c; + crc16(crc, &c, 1); + pos++; + value++; + } + return false; +} + +#endif // USE_WIRED_EEPROM +#endif // __SAMD21__ diff --git a/Marlin/src/HAL/SAMD21/endstop_interrupts.h b/Marlin/src/HAL/SAMD21/endstop_interrupts.h new file mode 100644 index 00000000..1459ae9e --- /dev/null +++ b/Marlin/src/HAL/SAMD21/endstop_interrupts.h @@ -0,0 +1,283 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +/** + * Endstop interrupts for ATMEL SAMD21 based targets. + * + * On SAMD21, all pins support external interrupt capability. + * Any pin can be used for external interrupts, but there are some restrictions. + * At most 16 different external interrupts can be used at one time. + * Further, you can’t just pick any 16 pins to use. This is because every pin on the SAMD21 + * connects to what is called an EXTINT line, and only one pin per EXTINT line can be used for external + * interrupts at a time + */ + +/** + * Endstop Interrupts + * + * Without endstop interrupts the endstop pins must be polled continually in + * the temperature-ISR via endstops.update(), most of the time finding no change. + * With this feature endstops.update() is called only when we know that at + * least one endstop has changed state, saving valuable CPU cycles. + * + * This feature only works when all used endstop pins can generate an 'external interrupt'. + * + * Test whether pins issue interrupts on your board by flashing 'pin_interrupt_test.ino'. + * (Located in Marlin/buildroot/share/pin_interrupt_test/pin_interrupt_test.ino) + */ + +#include "../../module/endstops.h" + +#define MATCH_EILINE(P1,P2) (P1 != P2 && PIN_TO_EILINE(P1) == PIN_TO_EILINE(P2)) +#define MATCH_X_MAX_EILINE(P) TERN0(USE_X_MAX, DEFER4(MATCH_EILINE)(P, X_MAX_PIN)) +#define MATCH_X_MIN_EILINE(P) TERN0(USE_X_MIN, DEFER4(MATCH_EILINE)(P, X_MIN_PIN)) +#define MATCH_Y_MAX_EILINE(P) TERN0(USE_Y_MAX, DEFER4(MATCH_EILINE)(P, Y_MAX_PIN)) +#define MATCH_Y_MIN_EILINE(P) TERN0(USE_Y_MIN, DEFER4(MATCH_EILINE)(P, Y_MIN_PIN)) +#define MATCH_Z_MAX_EILINE(P) TERN0(USE_Z_MAX, DEFER4(MATCH_EILINE)(P, Z_MAX_PIN)) +#define MATCH_Z_MIN_EILINE(P) TERN0(USE_Z_MIN, DEFER4(MATCH_EILINE)(P, Z_MIN_PIN)) +#define MATCH_I_MAX_EILINE(P) TERN0(USE_I_MAX, DEFER4(MATCH_EILINE)(P, I_MAX_PIN)) +#define MATCH_I_MIN_EILINE(P) TERN0(USE_I_MIN, DEFER4(MATCH_EILINE)(P, I_MIN_PIN)) +#define MATCH_J_MAX_EILINE(P) TERN0(USE_J_MAX, DEFER4(MATCH_EILINE)(P, J_MAX_PIN)) +#define MATCH_J_MIN_EILINE(P) TERN0(USE_J_MIN, DEFER4(MATCH_EILINE)(P, J_MIN_PIN)) +#define MATCH_K_MAX_EILINE(P) TERN0(USE_K_MAX, DEFER4(MATCH_EILINE)(P, K_MAX_PIN)) +#define MATCH_K_MIN_EILINE(P) TERN0(USE_K_MIN, DEFER4(MATCH_EILINE)(P, K_MIN_PIN)) +#define MATCH_U_MAX_EILINE(P) TERN0(USE_U_MAX, DEFER4(MATCH_EILINE)(P, U_MAX_PIN)) +#define MATCH_U_MIN_EILINE(P) TERN0(USE_U_MIN, DEFER4(MATCH_EILINE)(P, U_MIN_PIN)) +#define MATCH_V_MAX_EILINE(P) TERN0(USE_V_MAX, DEFER4(MATCH_EILINE)(P, V_MAX_PIN)) +#define MATCH_V_MIN_EILINE(P) TERN0(USE_V_MIN, DEFER4(MATCH_EILINE)(P, V_MIN_PIN)) +#define MATCH_W_MAX_EILINE(P) TERN0(USE_W_MAX, DEFER4(MATCH_EILINE)(P, W_MAX_PIN)) +#define MATCH_W_MIN_EILINE(P) TERN0(USE_W_MIN, DEFER4(MATCH_EILINE)(P, W_MIN_PIN)) +#define MATCH_X2_MAX_EILINE(P) TERN0(USE_X2_MAX, DEFER4(MATCH_EILINE)(P, X2_MAX_PIN)) +#define MATCH_X2_MIN_EILINE(P) TERN0(USE_X2_MIN, DEFER4(MATCH_EILINE)(P, X2_MIN_PIN)) +#define MATCH_Y2_MAX_EILINE(P) TERN0(USE_Y2_MAX, DEFER4(MATCH_EILINE)(P, Y2_MAX_PIN)) +#define MATCH_Y2_MIN_EILINE(P) TERN0(USE_Y2_MIN, DEFER4(MATCH_EILINE)(P, Y2_MIN_PIN)) +#define MATCH_Z2_MAX_EILINE(P) TERN0(USE_Z2_MAX, DEFER4(MATCH_EILINE)(P, Z2_MAX_PIN)) +#define MATCH_Z2_MIN_EILINE(P) TERN0(USE_Z2_MIN, DEFER4(MATCH_EILINE)(P, Z2_MIN_PIN)) +#define MATCH_Z3_MAX_EILINE(P) TERN0(USE_Z3_MAX, DEFER4(MATCH_EILINE)(P, Z3_MAX_PIN)) +#define MATCH_Z3_MIN_EILINE(P) TERN0(USE_Z3_MIN, DEFER4(MATCH_EILINE)(P, Z3_MIN_PIN)) +#define MATCH_Z4_MAX_EILINE(P) TERN0(USE_Z4_MAX, DEFER4(MATCH_EILINE)(P, Z4_MAX_PIN)) +#define MATCH_Z4_MIN_EILINE(P) TERN0(USE_Z4_MIN, DEFER4(MATCH_EILINE)(P, Z4_MIN_PIN)) +#define MATCH_Z_MIN_PROBE_EILINE(P) TERN0(HAS_Z_MIN_PROBE_PIN, DEFER4(MATCH_EILINE)(P, Z_MIN_PROBE_PIN)) + +#define AVAILABLE_EILINE(P) ( PIN_TO_EILINE(P) != -1 \ + && !MATCH_X_MAX_EILINE(P) && !MATCH_X_MIN_EILINE(P) \ + && !MATCH_Y_MAX_EILINE(P) && !MATCH_Y_MIN_EILINE(P) \ + && !MATCH_Z_MAX_EILINE(P) && !MATCH_Z_MIN_EILINE(P) \ + && !MATCH_I_MAX_EILINE(P) && !MATCH_I_MIN_EILINE(P) \ + && !MATCH_J_MAX_EILINE(P) && !MATCH_J_MIN_EILINE(P) \ + && !MATCH_K_MAX_EILINE(P) && !MATCH_K_MIN_EILINE(P) \ + && !MATCH_U_MAX_EILINE(P) && !MATCH_U_MIN_EILINE(P) \ + && !MATCH_V_MAX_EILINE(P) && !MATCH_V_MIN_EILINE(P) \ + && !MATCH_W_MAX_EILINE(P) && !MATCH_W_MIN_EILINE(P) \ + && !MATCH_X2_MAX_EILINE(P) && !MATCH_X2_MIN_EILINE(P) \ + && !MATCH_Y2_MAX_EILINE(P) && !MATCH_Y2_MIN_EILINE(P) \ + && !MATCH_Z2_MAX_EILINE(P) && !MATCH_Z2_MIN_EILINE(P) \ + && !MATCH_Z3_MAX_EILINE(P) && !MATCH_Z3_MIN_EILINE(P) \ + && !MATCH_Z4_MAX_EILINE(P) && !MATCH_Z4_MIN_EILINE(P) \ + && !MATCH_Z_MIN_PROBE_EILINE(P) ) + +// One ISR for all EXT-Interrupts +void endstop_ISR() { endstops.update(); } + +void setup_endstop_interrupts() { + #define _ATTACH(P) attachInterrupt(P, endstop_ISR, CHANGE) + #if USE_X_MAX + #if !AVAILABLE_EILINE(X_MAX_PIN) + #error "X_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(X_MAX_PIN); + #endif + #if USE_X_MIN + #if !AVAILABLE_EILINE(X_MIN_PIN) + #error "X_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(X_MIN_PIN); + #endif + #if USE_Y_MAX + #if !AVAILABLE_EILINE(Y_MAX_PIN) + #error "Y_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Y_MAX_PIN); + #endif + #if USE_Y_MIN + #if !AVAILABLE_EILINE(Y_MIN_PIN) + #error "Y_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Y_MIN_PIN); + #endif + #if USE_Z_MAX + #if !AVAILABLE_EILINE(Z_MAX_PIN) + #error "Z_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Z_MAX_PIN); + #endif + #if USE_Z_MIN + #if !AVAILABLE_EILINE(Z_MIN_PIN) + #error "Z_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Z_MIN_PIN); + #endif + #if USE_X2_MAX + #if !AVAILABLE_EILINE(X2_MAX_PIN) + #error "X2_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(X2_MAX_PIN); + #endif + #if USE_X2_MIN + #if !AVAILABLE_EILINE(X2_MIN_PIN) + #error "X2_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(X2_MIN_PIN); + #endif + #if USE_Y2_MAX + #if !AVAILABLE_EILINE(Y2_MAX_PIN) + #error "Y2_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Y2_MAX_PIN); + #endif + #if USE_Y2_MIN + #if !AVAILABLE_EILINE(Y2_MIN_PIN) + #error "Y2_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Y2_MIN_PIN); + #endif + #if USE_Z2_MAX + #if !AVAILABLE_EILINE(Z2_MAX_PIN) + #error "Z2_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Z2_MAX_PIN); + #endif + #if USE_Z2_MIN + #if !AVAILABLE_EILINE(Z2_MIN_PIN) + #error "Z2_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Z2_MIN_PIN); + #endif + #if USE_Z3_MAX + #if !AVAILABLE_EILINE(Z3_MAX_PIN) + #error "Z3_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Z3_MAX_PIN); + #endif + #if USE_Z3_MIN + #if !AVAILABLE_EILINE(Z3_MIN_PIN) + #error "Z3_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Z3_MIN_PIN); + #endif + #if USE_Z4_MAX + #if !AVAILABLE_EILINE(Z4_MAX_PIN) + #error "Z4_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Z4_MAX_PIN); + #endif + #if USE_Z4_MIN + #if !AVAILABLE_EILINE(Z4_MIN_PIN) + #error "Z4_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Z4_MIN_PIN); + #endif + #if HAS_Z_MIN_PROBE_PIN + #if !AVAILABLE_EILINE(Z_MIN_PROBE_PIN) + #error "Z_MIN_PROBE_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Z_MIN_PROBE_PIN); + #endif + #if USE_I_MAX + #if !AVAILABLE_EILINE(I_MAX_PIN) + #error "I_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(I_MAX_PIN, endstop_ISR, CHANGE); + #endif + #if USE_I_MIN + #if !AVAILABLE_EILINE(I_MIN_PIN) + #error "I_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(I_MIN_PIN, endstop_ISR, CHANGE); + #endif + #if USE_J_MAX + #if !AVAILABLE_EILINE(J_MAX_PIN) + #error "J_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(J_MAX_PIN, endstop_ISR, CHANGE); + #endif + #if USE_J_MIN + #if !AVAILABLE_EILINE(J_MIN_PIN) + #error "J_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(J_MIN_PIN, endstop_ISR, CHANGE); + #endif + #if USE_K_MAX + #if !AVAILABLE_EILINE(K_MAX_PIN) + #error "K_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(K_MAX_PIN, endstop_ISR, CHANGE); + #endif + #if USE_K_MIN + #if !AVAILABLE_EILINE(K_MIN_PIN) + #error "K_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(K_MIN_PIN, endstop_ISR, CHANGE); + #endif + #if USE_U_MAX + #if !AVAILABLE_EILINE(U_MAX_PIN) + #error "U_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(U_MAX_PIN, endstop_ISR, CHANGE); + #endif + #if USE_U_MIN + #if !AVAILABLE_EILINE(U_MIN_PIN) + #error "U_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(U_MIN_PIN, endstop_ISR, CHANGE); + #endif + #if USE_V_MAX + #if !AVAILABLE_EILINE(V_MAX_PIN) + #error "V_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(V_MAX_PIN, endstop_ISR, CHANGE); + #endif + #if USE_V_MIN + #if !AVAILABLE_EILINE(V_MIN_PIN) + #error "V_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(V_MIN_PIN, endstop_ISR, CHANGE); + #endif + #if USE_W_MAX + #if !AVAILABLE_EILINE(W_MAX_PIN) + #error "W_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(W_MAX_PIN, endstop_ISR, CHANGE); + #endif + #if USE_W_MIN + #if !AVAILABLE_EILINE(W_MIN_PIN) + #error "W_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(W_MIN_PIN, endstop_ISR, CHANGE); + #endif +} diff --git a/Marlin/src/HAL/SAMD21/fastio.h b/Marlin/src/HAL/SAMD21/fastio.h new file mode 100644 index 00000000..32cc5575 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/fastio.h @@ -0,0 +1,215 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +/** + * Fast IO functions for SAMD21 + */ + +#include "SAMD21.h" + +/** + * Utility functions + */ + +#ifndef MASK + #define MASK(PIN) _BV(PIN) +#endif + +/** + * Magic I/O routines + * + * Now you can simply SET_OUTPUT(IO); WRITE(IO, HIGH); WRITE(IO, LOW); + */ + +// Read a pin +#define READ(IO) ((PORT->Group[(EPortType)GET_SAMD_PORT(IO)].IN.reg & MASK(GET_SAMD_PIN(IO))) != 0) + +// Write to a pin +#define WRITE(IO,V) do{ \ + const EPortType port = (EPortType)GET_SAMD_PORT(IO); \ + const uint32_t mask = MASK(GET_SAMD_PIN(IO)); \ + \ + if (V) PORT->Group[port].OUTSET.reg = mask; \ + else PORT->Group[port].OUTCLR.reg = mask; \ + }while(0) + +// Toggle a pin +#define TOGGLE(IO) PORT->Group[(EPortType)GET_SAMD_PORT(IO)].OUTTGL.reg = MASK(GET_SAMD_PIN(IO)); + +// Set pin as input +#define SET_INPUT(IO) do{ \ + const EPortType port = (EPortType)GET_SAMD_PORT(IO); \ + const uint32_t pin = GET_SAMD_PIN(IO); \ + \ + PORT->Group[port].PINCFG[pin].reg = (uint8_t)(PORT_PINCFG_INEN); \ + PORT->Group[port].DIRCLR.reg = MASK(pin); \ + }while(0) +// Set pin as input with pullup +#define SET_INPUT_PULLUP(IO) do{ \ + const EPortType port = (EPortType)GET_SAMD_PORT(IO); \ + const uint32_t pin = GET_SAMD_PIN(IO); \ + const uint32_t mask = MASK(pin); \ + \ + PORT->Group[port].PINCFG[pin].reg = (uint8_t)(PORT_PINCFG_INEN | PORT_PINCFG_PULLEN); \ + PORT->Group[port].DIRCLR.reg = mask; \ + PORT->Group[port].OUTSET.reg = mask; \ + }while(0) +// Set pin as input with pulldown +#define SET_INPUT_PULLDOWN(IO) do{ \ + const EPortType port = (EPortType)GET_SAMD_PORT(IO); \ + const uint32_t pin = GET_SAMD_PIN(IO); \ + const uint32_t mask = MASK(pin); \ + \ + PORT->Group[port].PINCFG[pin].reg = (uint8_t)(PORT_PINCFG_INEN | PORT_PINCFG_PULLEN); \ + PORT->Group[port].DIRCLR.reg = mask; \ + PORT->Group[port].OUTCLR.reg = mask; \ + }while(0) +// Set pin as output (push pull) +#define SET_OUTPUT(IO) do{ \ + const EPortType port = (EPortType)GET_SAMD_PORT(IO); \ + const uint32_t pin = GET_SAMD_PIN(IO); \ + \ + PORT->Group[port].DIRSET.reg = MASK(pin); \ + PORT->Group[port].PINCFG[pin].reg = 0; \ + }while(0) +// Set pin as output (open drain) +#define SET_OUTPUT_OD(IO) do{ \ + const EPortType port = (EPortType)GET_SAMD_PORT(IO); \ + const uint32_t pin = GET_SAMD_PIN(IO); \ + \ + PORT->Group[port].PINCFG[pin].reg = (uint8_t)(PORT_PINCFG_PULLEN); \ + PORT->Group[port].DIRCLR.reg = MASK(pin); \ + }while(0) +// Set pin as PWM (push pull) +#define SET_PWM SET_OUTPUT +// Set pin as PWM (open drain) +#define SET_PWM_OD SET_OUTPUT_OD + +// check if pin is an output +#define IS_OUTPUT(IO) ((PORT->Group[(EPortType)GET_SAMD_PORT(IO)].DIR.reg & MASK(GET_SAMD_PIN(IO))) \ + || (PORT->Group[(EPortType)GET_SAMD_PORT(IO)].PINCFG[GET_SAMD_PIN(IO)].reg & (PORT_PINCFG_INEN | PORT_PINCFG_PULLEN)) == PORT_PINCFG_PULLEN) +// check if pin is an input +#define IS_INPUT(IO) !IS_OUTPUT(IO) + +// Shorthand +#define OUT_WRITE(IO,V) do{ SET_OUTPUT(IO); WRITE(IO,V); }while(0) +#define OUT_WRITE_OD(IO,V) do{ SET_OUTPUT_OD(IO); WRITE(IO,V); }while(0) + +// digitalRead/Write wrappers +#define extDigitalRead(IO) digitalRead(IO) +#define extDigitalWrite(IO,V) digitalWrite(IO,V) + +/** + * Ports and functions + * Added as necessary or if I feel like it- not a comprehensive list! + */ + +/** + * Some of these share the same source and so can't be used in the same time + */ +#define PWM_PIN(P) (WITHIN(P, 2, 13) || WITHIN(P, 22, 23) || WITHIN(P, 44, 45) || P == 48) + +// Return fulfilled ADCx->INPUTCTRL.reg +#define PIN_TO_INPUTCTRL(P) ( (P == 0) ? ADC_INPUTCTRL_MUXPOS_PIN0 \ + : ((P) == 1) ? ADC_INPUTCTRL_MUXPOS_PIN1 \ + : ((P) == 2) ? ADC_INPUTCTRL_MUXPOS_PIN3 \ + : ((P) == 3) ? ADC_INPUTCTRL_MUXPOS_PIN4 \ + : ((P) == 4) ? ADC_INPUTCTRL_MUXPOS_PIN5 \ + : ((P) == 5) ? ADC_INPUTCTRL_MUXPOS_PIN5 \ + : ((P) == 6) ? ADC_INPUTCTRL_MUXPOS_PIN6 \ + : ((P) == 7) ? ADC_INPUTCTRL_MUXPOS_PIN7 \ + : ((P) == 8) ? ADC_INPUTCTRL_MUXPOS_PIN8 \ + : ((P) == 9) ? ADC_INPUTCTRL_MUXPOS_PIN9 \ + : ((P) == 10) ? ADC_INPUTCTRL_MUXPOS_PIN10 \ + : ((P) == 11) ? ADC_INPUTCTRL_MUXPOS_PIN11 \ + : ((P) == 12) ? ADC_INPUTCTRL_MUXPOS_PIN12 \ + : ((P) == 13) ? ADC_INPUTCTRL_MUXPOS_PIN13 \ + : ((P) == 14) ? ADC_INPUTCTRL_MUXPOS_PIN14 \ + : ADC_INPUTCTRL_MUXPOS_PIN15) + +#define digitalPinToAnalogIndex(P) (WITHIN(P, 67, 74) ? (P) - 67 : WITHIN(P, 54, 61) ? 8 + (P) - 54 : WITHIN(P, 12, 13) ? 16 + (P) - 12 : P == 9 ? 18 : -1) + +/** + * pins + */ + +// PORTA +#define DIO28_PIN PIN_PA02 // A0 +#define DIO56_PIN PIN_PA03 // A13 +#define DIO31_PIN PIN_PA04 // A13 +#define DIO32_PIN PIN_PA05 // A1 +#define DIO8_PIN PIN_PA06 // A14 +#define DIO9_PIN PIN_PA07 // A15 +#define DIO4_PIN PIN_PA08 // A15 +#define DIO3_PIN PIN_PA09 // A15 +#define DIO1_PIN PIN_PA10 +#define DIO0_PIN PIN_PA11 +#define DIO18_PIN PIN_PA12 +#define DIO52_PIN PIN_PA13 +#define DIO2_PIN PIN_PA14 +#define DIO5_PIN PIN_PA15 +#define DIO11_PIN PIN_PA16 +#define DIO13_PIN PIN_PA17 +#define DIO10_PIN PIN_PA18 +#define DIO12_PIN PIN_PA19 +#define DIO6_PIN PIN_PA20 +#define DIO07_PIN PIN_PA21 +#define DIO34_PIN PIN_PA22 +#define DIO35_PIN PIN_PA23 +#define DIO42_PIN PIN_PA24 +#define DIO43_PIN PIN_PA25 + +#define DIO40_PIN PIN_PA27 + +#define DIO26_PIN PIN_PB00 +#define DIO27_PIN PIN_PB01 // A0 +#define DIO33_PIN PIN_PB02 +#define DIO39_PIN PIN_PB03 +#define DIO14_PIN PIN_PB04 +#define DIO15_PIN PIN_PB05 +#define DIO16_PIN PIN_PB06 +#define DIO17_PIN PIN_PB07 +#define DIO29_PIN PIN_PB08 +#define DIO30_PIN PIN_PB09 +#define DIO37_PIN PIN_PB10 +#define DIO38_PIN PIN_PB11 +#define DIO36_PIN PIN_PB12 +#define DIO19_PIN PIN_PB13 +#define DIO20_PIN PIN_PB14 +#define DIO21_PIN PIN_PB15 +#define DIO22_PIN PIN_PB16 +#define DIO23_PIN PIN_PB17 + +#define DIO44_PIN PIN_PB22 +#define DIO45_PIN PIN_PB23 +#define DIO24_PIN PIN_PB30 +#define DIO25_PIN PIN_PB31 + +#define DIO53_PIN PIN_PA21 +#define DIO54_PIN PIN_PA06 +#define DIO55_PIN PIN_PA07 diff --git a/Marlin/src/HAL/STM32/watchdog.h b/Marlin/src/HAL/SAMD21/inc/Conditionals_LCD.h similarity index 87% rename from Marlin/src/HAL/STM32/watchdog.h rename to Marlin/src/HAL/SAMD21/inc/Conditionals_LCD.h index 49a0d9c6..570baf7e 100644 --- a/Marlin/src/HAL/STM32/watchdog.h +++ b/Marlin/src/HAL/SAMD21/inc/Conditionals_LCD.h @@ -1,6 +1,6 @@ /** * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm @@ -20,6 +20,3 @@ * */ #pragma once - -void watchdog_init(); -void HAL_watchdog_refresh(); diff --git a/Marlin/src/HAL/SAMD21/inc/Conditionals_adv.h b/Marlin/src/HAL/SAMD21/inc/Conditionals_adv.h new file mode 100644 index 00000000..d6a3c4fe --- /dev/null +++ b/Marlin/src/HAL/SAMD21/inc/Conditionals_adv.h @@ -0,0 +1,27 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#pragma once diff --git a/Marlin/src/HAL/SAMD21/inc/Conditionals_post.h b/Marlin/src/HAL/SAMD21/inc/Conditionals_post.h new file mode 100644 index 00000000..87d3350c --- /dev/null +++ b/Marlin/src/HAL/SAMD21/inc/Conditionals_post.h @@ -0,0 +1,33 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#pragma once + +#if USE_FALLBACK_EEPROM + #define FLASH_EEPROM_EMULATION +#elif ANY(I2C_EEPROM, SPI_EEPROM) + #define USE_SHARED_EEPROM 1 +#endif diff --git a/Marlin/src/HAL/SAMD21/inc/SanityCheck.h b/Marlin/src/HAL/SAMD21/inc/SanityCheck.h new file mode 100644 index 00000000..83fafc96 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/inc/SanityCheck.h @@ -0,0 +1,54 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +/** + * Test SAMD21 specific configuration values for errors at compile-time. + */ + +#if HAS_SPI_TFT || HAS_FSMC_TFT + #error "Sorry! TFT displays are not available for HAL/SAMD21." +#endif + +#if SERVO_TC == MF_TIMER_RTC + #error "Servos can't use RTC timer" +#endif + +#if ENABLED(EMERGENCY_PARSER) + #error "EMERGENCY_PARSER is not yet implemented for SAMD21. Disable EMERGENCY_PARSER to continue." +#endif + +#if ENABLED(ONBOARD_SDIO) + #error "ONBOARD_SDIO is not supported on SAMD21." +#endif + +#if ENABLED(FAST_PWM_FAN) + #error "Features requiring Hardware PWM (FAST_PWM_FAN) are not yet supported for HAL/SAMD21." +#endif + +#if ENABLED(POSTMORTEM_DEBUGGING) + #error "POSTMORTEM_DEBUGGING is not yet supported on SAMD21." +#endif diff --git a/Marlin/src/HAL/SAMD21/pinsDebug.h b/Marlin/src/HAL/SAMD21/pinsDebug.h new file mode 100644 index 00000000..387516aa --- /dev/null +++ b/Marlin/src/HAL/SAMD21/pinsDebug.h @@ -0,0 +1,175 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * Pins Debugging for SAMD21 + * + * - NUMBER_PINS_TOTAL + * - MULTI_NAME_PAD + * - getPinByIndex(index) + * - printPinNameByIndex(index) + * - getPinIsDigitalByIndex(index) + * - digitalPinToAnalogIndex(pin) + * - getValidPinMode(pin) + * - isValidPin(pin) + * - isAnalogPin(pin) + * - digitalRead_mod(pin) + * - pwm_status(pin) + * - printPinPWM(pin) + * - printPinPort(pin) + * - printPinNumber(pin) + * - printPinAnalog(pin) + */ + +#define NUMBER_PINS_TOTAL PINS_COUNT + +#define digitalRead_mod(P) extDigitalRead(P) +#define printPinNameByIndex(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) +#define printPinNumber(P) do{ sprintf_P(buffer, PSTR("%3d "), P); SERIAL_ECHO(buffer); }while(0) +#define printPinAnalog(P) do{ sprintf_P(buffer, PSTR(" (A%2d) "), digitalPinToAnalogIndex(P)); SERIAL_ECHO(buffer); }while(0) +#define getPinByIndex(x) pin_array[x].pin +#define getPinIsDigitalByIndex(x) pin_array[x].is_digital +#define isValidPin(P) (P >= 0 && P < pin_t(NUMBER_PINS_TOTAL)) +#define isAnalogPin(P) (digitalPinToAnalogIndex(P) != -1) +#define pwm_status(P) digitalPinHasPWM(P) +#define MULTI_NAME_PAD 27 // space needed to be pretty if not first name assigned to a pin + +// pins that will cause hang/reset/disconnect in M43 Toggle and Watch utilities +// uses pin index +#define M43_NEVER_TOUCH(Q) ((Q) >= 75) + +bool getValidPinMode(const int8_t pin) { // 1: output, 0: input + const EPortType samdport = g_APinDescription[pin].ulPort; + const uint32_t samdpin = g_APinDescription[pin].ulPin; + return PORT->Group[samdport].DIR.reg & MASK(samdpin) || (PORT->Group[samdport].PINCFG[samdpin].reg & (PORT_PINCFG_INEN | PORT_PINCFG_PULLEN)) == PORT_PINCFG_PULLEN; +} + +void printPinPWM(const int32_t pin) { + if (pwm_status(pin)) { + //uint32_t chan = g_APinDescription[pin].ulPWMChannel TODO when fast pwm is operative; + //SERIAL_ECHOPGM("PWM = ", duty); + } +} + +void printPinPort(const pin_t) {} + +/** + * SAMD21 Board pin| PORT | Label + * ----------------+--------+------- + * 0 | PB25 | "RX0" + * 1 | PB24 | "TX0" + * 2 | PC18 | + * 3 | PC19 | + * 4 | PC20 | + * 5 | PC21 | + * 6 | PD20 | + * 7 | PD21 | + * 8 | PB18 | + * 9 | PB2 | + * 10 | PB22 | + * 11 | PB23 | + * 12 | PB0 | "A16" + * 13 | PB1 | LED AMBER "L" / "A17" + * 14 | PB16 | "TX3" + * 15 | PB17 | "RX3" + * 16 | PC22 | "TX2" + * 17 | PC23 | "RX2" + * 18 | PB12 | "TX1" / "A18" + * 19 | PB13 | "RX1" + * 20 | PB20 | "SDA" + * 21 | PB21 | "SCL" + * 22 | PD12 | + * 23 | PA15 | + * 24 | PC17 | + * 25 | PC16 | + * 26 | PA12 | + * 27 | PA13 | + * 28 | PA14 | + * 29 | PB19 | + * 30 | PA23 | + * 31 | PA22 | + * 32 | PA21 | + * 33 | PA20 | + * 34 | PA19 | + * 35 | PA18 | + * 36 | PA17 | + * 37 | PA16 | + * 38 | PB15 | + * 39 | PB14 | + * 40 | PC13 | + * 41 | PC12 | + * 42 | PC15 | + * 43 | PC14 | + * 44 | PC11 | + * 45 | PC10 | + * 46 | PC6 | + * 47 | PC7 | + * 48 | PC4 | + * 49 | PC5 | + * 50 | PD11 | + * 51 | PD8 | + * 52 | PD9 | + * 53 | PD10 | + * 54 | PB5 | "A8" + * 55 | PB6 | "A9" + * 56 | PB7 | "A10" + * 57 | PB8 | "A11" + * 58 | PB9 | "A12" + * 69 | PA4 | "A13" + * 60 | PA6 | "A14" + * 61 | PA7 | "A15" + * 62 | PB17 | + * 63 | PB20 | + * 64 | PD11 | + * 65 | PD8 | + * 66 | PD9 | + * 67 | PA2 | "A0" / "DAC0" + * 68 | PA5 | "A1" / "DAC1" + * 69 | PB3 | "A2" + * 70 | PC0 | "A3" + * 71 | PC1 | "A4" + * 72 | PC2 | "A5" + * 73 | PC3 | "A6" + * 74 | PB4 | "A7" + * 75 | PC31 | LED GREEN "RX" + * 76 | PC30 | LED GREEN "TX" + * 77 | PA27 | USB: Host enable + * 78 | PA24 | USB: D- + * 79 | PA25 | USB: D+ + * 80 | PB29 | SD: MISO + * 81 | PB27 | SD: SCK + * 82 | PB26 | SD: MOSI + * 83 | PB28 | SD: CS + * 84 | PA3 | AREF + * 85 | PA2 | DAC0 (Duplicate) + * 86 | PA5 | DAC1 (Duplicate) + * 87 | PB1 | LED AMBER "L" (Duplicate) + * 88 | PC24 | NeoPixel + * 89 | PB10 | QSPI: SCK + * 90 | PB11 | QSPI: CS + * 91 | PA8 | QSPI: IO0 + * 92 | PA9 | QSPI: IO1 + * 93 | PA10 | QSPI: IO2 + * 94 | PA11 | QSPI: IO3 + * 95 | PB31 | SD: DETECT + */ diff --git a/Marlin/src/HAL/SAMD21/spi_pins.h b/Marlin/src/HAL/SAMD21/spi_pins.h new file mode 100644 index 00000000..8c25b84d --- /dev/null +++ b/Marlin/src/HAL/SAMD21/spi_pins.h @@ -0,0 +1,54 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +/** + * SAMD21 Default SPI Pins + * + * SS SCK MISO MOSI + * +-------------------------+ + * SPI | 53 52 50 51 | + * SPI1 | 83 81 80 82 | + * +-------------------------+ + * Any pin can be used for Chip Select (SD_SS_PIN) + */ +#ifndef SD_SCK_PIN + #define SD_SCK_PIN 38 +#endif +#ifndef SD_MISO_PIN + #define SD_MISO_PIN 36 +#endif +#ifndef SD_MOSI_PIN + #define SD_MOSI_PIN 37 +#endif +#ifndef SDSS + #define SDSS 18 +#endif + +#ifndef SD_SS_PIN + #define SD_SS_PIN SDSS +#endif diff --git a/Marlin/src/HAL/SAMD21/timers.cpp b/Marlin/src/HAL/SAMD21/timers.cpp new file mode 100644 index 00000000..b5f1d4f7 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/timers.cpp @@ -0,0 +1,217 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#ifdef __SAMD21__ + +// -------------------------------------------------------------------------- +// Includes +// -------------------------------------------------------------------------- + +#include "../../inc/MarlinConfig.h" +#include "ServoTimers.h" // for SERVO_TC + +// -------------------------------------------------------------------------- +// Local defines +// -------------------------------------------------------------------------- + +#define NUM_HARDWARE_TIMERS 9 + +// -------------------------------------------------------------------------- +// Private Variables +// -------------------------------------------------------------------------- + +const tTimerConfig timer_config[NUM_HARDWARE_TIMERS] = { + { {.pTcc=TCC0}, TimerType::tcc, TCC0_IRQn, TC_PRIORITY(0) }, // 0 - stepper (assigned priority 2) + { {.pTcc=TCC1}, TimerType::tcc, TCC1_IRQn, TC_PRIORITY(1) }, // 1 - stepper (needed by 32 bit timers) + { {.pTcc=TCC2}, TimerType::tcc, TCC2_IRQn, 5 }, // 2 - tone (reserved by framework and fixed assigned priority 5) + { {.pTc=TC3}, TimerType::tc, TC3_IRQn, TC_PRIORITY(3) }, // 3 - servo (assigned priority 1) + { {.pTc=TC4}, TimerType::tc, TC4_IRQn, TC_PRIORITY(4) }, // 4 - software serial (no interrupts used) + { {.pTc=TC5}, TimerType::tc, TC5_IRQn, TC_PRIORITY(5) }, + { {.pTc=TC6}, TimerType::tc, TC6_IRQn, TC_PRIORITY(6) }, + { {.pTc=TC7}, TimerType::tc, TC7_IRQn, TC_PRIORITY(7) }, + { {.pRtc=RTC}, TimerType::rtc, RTC_IRQn, TC_PRIORITY(8) } // 8 - temperature (assigned priority 6) +}; + +// -------------------------------------------------------------------------- +// Private functions +// -------------------------------------------------------------------------- + +FORCE_INLINE void Disable_Irq(IRQn_Type irq) { + NVIC_DisableIRQ(irq); + + // We NEED memory barriers to ensure Interrupts are actually disabled! + // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the ) + __DSB(); + __ISB(); +} + +static bool tcIsSyncing(Tc * tc) { + return tc->COUNT32.STATUS.reg & TC_STATUS_SYNCBUSY; +} + +static void tcReset( Tc * tc) { + tc->COUNT32.CTRLA.reg = TC_CTRLA_SWRST; + while (tcIsSyncing(tc)) {} + while (tc->COUNT32.CTRLA.bit.SWRST) {} +} + +// -------------------------------------------------------------------------- +// Public functions +// -------------------------------------------------------------------------- + +void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) { + IRQn_Type irq = timer_config[timer_num].IRQ_Id; + + // Disable interrupt, just in case it was already enabled + NVIC_DisableIRQ(irq); + NVIC_ClearPendingIRQ(irq); + + if (timer_num == MF_TIMER_RTC) { + + // https://github.com/arduino-libraries/RTCZero + Rtc * const rtc = timer_config[timer_num].pRtc; + PM->APBAMASK.reg |= PM_APBAMASK_RTC; + + GCLK->CLKCTRL.reg = (uint32_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK4 | (RTC_GCLK_ID << GCLK_CLKCTRL_ID_Pos))); + while (GCLK->STATUS.bit.SYNCBUSY) {} + + GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID(4) | GCLK_GENCTRL_DIVSEL ); + while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} + + GCLK->GENDIV.reg = GCLK_GENDIV_ID(4); + GCLK->GENDIV.bit.DIV=4; + while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} + + // Disable timer interrupt + rtc->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP0; + SYNC(rtc->MODE0.STATUS.bit.SYNCBUSY); + + while(rtc->MODE0.STATUS.bit.SYNCBUSY) {} + + // Stop timer, just in case, to be able to reconfigure it + rtc->MODE0.CTRL.reg = + RTC_MODE0_CTRL_MODE_COUNT32 | // Mode 0 = 32-bits counter + RTC_MODE0_CTRL_PRESCALER_DIV1024; // Divisor = 1024 + + while(rtc->MODE0.STATUS.bit.SYNCBUSY) {} + + // Mode, reset counter on match + rtc->MODE0.CTRL.reg = RTC_MODE0_CTRL_MODE_COUNT32 | RTC_MODE0_CTRL_MATCHCLR; + + // Set compare value + rtc->MODE0.COMP[0].reg = (32768 + frequency / 2) / frequency; + SYNC(rtc->MODE0.STATUS.bit.SYNCBUSY); + + // Enable interrupt on compare + rtc->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0; // reset pending interrupt + rtc->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP0; // enable compare 0 interrupt + + // And start timer + rtc->MODE0.CTRL.bit.ENABLE = true; + SYNC(rtc->MODE0.STATUS.bit.SYNCBUSY); + + } + else if (timer_config[timer_num].type==TimerType::tcc) { + + Tcc * const tc = timer_config[timer_num].pTcc; + + PM->APBCMASK.reg |= PM_APBCMASK_TCC0; + GCLK->CLKCTRL.reg =(GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(TCC0_GCLK_ID)); + SYNC (GCLK->STATUS.bit.SYNCBUSY); + + tc->CTRLA.reg = TCC_CTRLA_SWRST; + SYNC (tc->SYNCBUSY.reg & TCC_SYNCBUSY_SWRST) {} + + SYNC (tc->CTRLA.bit.SWRST); + + tc->CTRLA.reg &= ~(TCC_CTRLA_ENABLE); // disable TC module + + tc->CTRLA.reg |= TCC_WAVE_WAVEGEN_MFRQ; + tc->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV2; + tc->CC[0].reg = (HAL_TIMER_RATE) / frequency; + tc->INTENSET.reg = TCC_INTFLAG_MC0; + tc->CTRLA.reg |= TCC_CTRLA_ENABLE; + tc->INTFLAG.reg = 0xFF; + SYNC ( tc->STATUS.reg & TC_STATUS_SYNCBUSY); + + } + else { + Tc * const tc = timer_config[timer_num].pTc; + + // Disable timer interrupt + tc->COUNT32.INTENCLR.reg = TC_INTENCLR_OVF; // disable overflow interrupt + + // TCn clock setup + GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TC4_TC5)) ; + SYNC (GCLK->STATUS.bit.SYNCBUSY); + + tcReset(tc); // reset TC + + // Set Timer counter 5 Mode to 16 bits, it will become a 16bit counter ('mode1' in the datasheet) + tc->COUNT32.CTRLA.reg |= TC_CTRLA_MODE_COUNT32; + // Set TC waveform generation mode to 'match frequency' + tc->COUNT32.CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ; + //set prescaler + //the clock normally counts at the GCLK_TC frequency, but we can set it to divide that frequency to slow it down + //you can use different prescaler divisons here like TC_CTRLA_PRESCALER_DIV1 to get a different range + tc->COUNT32.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1 | TC_CTRLA_ENABLE; //it will divide GCLK_TC frequency by 1024 + //set the compare-capture register. + //The counter will count up to this value (it's a 16bit counter so we use uint16_t) + //this is how we fine-tune the frequency, make it count to a lower or higher value + //system clock should be 1MHz (8MHz/8) at Reset by default + tc->COUNT32.CC[0].reg = (uint16_t) (HAL_TIMER_RATE / frequency); + while (tcIsSyncing(tc)) {} + + // Enable the TC interrupt request + tc->COUNT32.INTENSET.bit.MC0 = 1; + while (tcIsSyncing(tc)) {} + } + + NVIC_SetPriority(irq, timer_config[timer_num].priority); + NVIC_EnableIRQ(irq); +} + +void HAL_timer_enable_interrupt(const uint8_t timer_num) { + const IRQn_Type irq = timer_config[timer_num].IRQ_Id; + NVIC_EnableIRQ(irq); +} + +void HAL_timer_disable_interrupt(const uint8_t timer_num) { + const IRQn_Type irq = timer_config[timer_num].IRQ_Id; + Disable_Irq(irq); +} + +// missing from CMSIS: Check if interrupt is enabled or not +static bool NVIC_GetEnabledIRQ(IRQn_Type IRQn) { + return TEST(NVIC->ISER[uint32_t(IRQn) >> 5], uint32_t(IRQn) & 0x1F); +} + +bool HAL_timer_interrupt_enabled(const uint8_t timer_num) { + const IRQn_Type irq = timer_config[timer_num].IRQ_Id; + return NVIC_GetEnabledIRQ(irq); +} + +#endif // __SAMD21__ diff --git a/Marlin/src/HAL/SAMD21/timers.h b/Marlin/src/HAL/SAMD21/timers.h new file mode 100644 index 00000000..303ccbdc --- /dev/null +++ b/Marlin/src/HAL/SAMD21/timers.h @@ -0,0 +1,160 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +#include + +// -------------------------------------------------------------------------- +// Defines +// -------------------------------------------------------------------------- + +typedef uint32_t hal_timer_t; +#define HAL_TIMER_TYPE_MAX 0xFFFFFFFF + +#define HAL_TIMER_RATE F_CPU // frequency of timers peripherals + +#define MF_TIMER_RTC 8 // This is not a TC but a RTC + +#ifndef MF_TIMER_STEP + #define MF_TIMER_STEP 4 // Timer Index for Stepper +#endif +#ifndef MF_TIMER_PULSE + #define MF_TIMER_PULSE MF_TIMER_STEP +#endif +#ifndef MF_TIMER_TEMP + #define MF_TIMER_TEMP MF_TIMER_RTC // Timer Index for Temperature +#endif + +#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency + +#define STEPPER_TIMER_RATE HAL_TIMER_RATE // frequency of stepper timer (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE) +#define STEPPER_TIMER_TICKS_PER_US (STEPPER_TIMER_RATE / 1000000) // stepper timer ticks per µs +#define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US) + +#define PULSE_TIMER_RATE STEPPER_TIMER_RATE +#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE +#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US + +#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP) +#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP) +#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP) + +#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP) +#define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_TEMP) + +#define TC_PRIORITY(t) ( t == SERVO_TC ? 1 \ + : (t == MF_TIMER_STEP || t == MF_TIMER_PULSE) ? 2 \ + : (t == MF_TIMER_TEMP) ? 6 : 7 ) + +#define _TC_HANDLER(t) void TC##t##_Handler() +#define TC_HANDLER(t) _TC_HANDLER(t) +#ifndef HAL_STEP_TIMER_ISR + #define HAL_STEP_TIMER_ISR() TC_HANDLER(MF_TIMER_STEP) +#endif +#if MF_TIMER_STEP != MF_TIMER_PULSE + #define HAL_PULSE_TIMER_ISR() TC_HANDLER(MF_TIMER_PULSE) +#endif +#if MF_TIMER_TEMP == MF_TIMER_RTC + #define HAL_TEMP_TIMER_ISR() void RTC_Handler() +#else + #define HAL_TEMP_TIMER_ISR() TC_HANDLER(MF_TIMER_TEMP) +#endif + +// -------------------------------------------------------------------------- +// Types +// -------------------------------------------------------------------------- +typedef enum { tcc, tc, rtc } TimerType; + +typedef struct { + union { + Tc *pTc; + Tcc *pTcc; + Rtc *pRtc; + }; + TimerType type; + IRQn_Type IRQ_Id; + uint8_t priority; +} tTimerConfig; + +// -------------------------------------------------------------------------- +// Public Variables +// -------------------------------------------------------------------------- + +extern const tTimerConfig timer_config[]; + +// -------------------------------------------------------------------------- +// Public functions +// -------------------------------------------------------------------------- + +void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency); + +FORCE_INLINE static void HAL_timer_set_compare(const uint8_t timer_num, const hal_timer_t compare) { + // Should never be called with timer MF_TIMER_RTC + Tc * const tc = timer_config[timer_num].pTc; + tc->COUNT32.CC[0].reg = compare; +} + +FORCE_INLINE static hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) { + // Should never be called with timer MF_TIMER_RTC + Tc * const tc = timer_config[timer_num].pTc; + return (hal_timer_t)tc->COUNT32.CC[0].reg; +} + +FORCE_INLINE static hal_timer_t HAL_timer_get_count(const uint8_t timer_num) { + // Should never be called with timer MF_TIMER_RTC + Tc * const tc = timer_config[timer_num].pTc; + tc->COUNT32.READREQ.reg = TC_READREQ_RREQ; + // Request a read synchronization + SYNC (tc->COUNT32.STATUS.bit.SYNCBUSY); + //SYNC(tc->COUNT32.STATUS.bit.SYNCBUSY ); + return tc->COUNT32.COUNT.reg; +} + +void HAL_timer_enable_interrupt(const uint8_t timer_num); +void HAL_timer_disable_interrupt(const uint8_t timer_num); +bool HAL_timer_interrupt_enabled(const uint8_t timer_num); + +FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) { + if (timer_num == MF_TIMER_RTC) { + Rtc * const rtc = timer_config[timer_num].pRtc; + // Clear interrupt flag + rtc->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0| RTC_MODE0_INTFLAG_OVF; + + } + else if (timer_config[timer_num].type == TimerType::tcc){ + Tcc * const tc = timer_config[timer_num].pTcc; + // Clear interrupt flag + tc->INTFLAG.reg = TCC_INTFLAG_OVF; + } + else { + Tc * const tc = timer_config[timer_num].pTc; + // Clear interrupt flag + tc->COUNT32.INTFLAG.bit.MC0 = 1; + } +} + +#define HAL_timer_isr_epilogue(timer_num) diff --git a/Marlin/src/HAL/AVR/watchdog.h b/Marlin/src/HAL/SAMD21/u8g/LCD_I2C_routines.cpp similarity index 68% rename from Marlin/src/HAL/AVR/watchdog.h rename to Marlin/src/HAL/SAMD21/u8g/LCD_I2C_routines.cpp index a16c88b3..41da7c10 100644 --- a/Marlin/src/HAL/AVR/watchdog.h +++ b/Marlin/src/HAL/SAMD21/u8g/LCD_I2C_routines.cpp @@ -1,6 +1,6 @@ /** * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm @@ -19,13 +19,14 @@ * along with this program. If not, see . * */ -#pragma once -#include +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +// adapted from I2C/master/master.c example +// https://www-users.cs.york.ac.uk/~pcc/MCP/HAPR-Course-web/CMSIS/examples/html/master_8c_source.html -// Initialize watchdog with a 4 second interrupt time -void watchdog_init(); +#ifdef __SAMD21__ -// Reset watchdog. MUST be called at least every 4 seconds after the -// first watchdog_init or AVR will go into emergency procedures. -inline void HAL_watchdog_refresh() { wdt_reset(); } +#endif // __SAMD21__ diff --git a/Marlin/src/HAL/SAMD21/u8g/LCD_I2C_routines.h b/Marlin/src/HAL/SAMD21/u8g/LCD_I2C_routines.h new file mode 100644 index 00000000..d6a3c4fe --- /dev/null +++ b/Marlin/src/HAL/SAMD21/u8g/LCD_I2C_routines.h @@ -0,0 +1,27 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#pragma once diff --git a/Marlin/src/HAL/SAMD21/u8g/LCD_defines.h b/Marlin/src/HAL/SAMD21/u8g/LCD_defines.h new file mode 100644 index 00000000..fa98725d --- /dev/null +++ b/Marlin/src/HAL/SAMD21/u8g/LCD_defines.h @@ -0,0 +1,41 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#pragma once + +/** + * SAMD21 LCD-specific defines + */ + +// The following are optional depending on the platform. + +// definitions of HAL specific com and device drivers. +uint8_t u8g_com_samd21_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); +uint8_t u8g_com_samd21_st7920_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); + +// connect U8g com generic com names to the desired driver +#define U8G_COM_HW_SPI u8g_com_samd21_st7920_hw_spi_fn // use SAMD21 specific hardware SPI routine +#define U8G_COM_ST7920_HW_SPI u8g_com_samd21_st7920_hw_spi_fn diff --git a/Marlin/src/HAL/ESP32/watchdog.cpp b/Marlin/src/HAL/SAMD21/u8g/LCD_pin_routines.c similarity index 56% rename from Marlin/src/HAL/ESP32/watchdog.cpp rename to Marlin/src/HAL/SAMD21/u8g/LCD_pin_routines.c index 5ec03c46..f9f77825 100644 --- a/Marlin/src/HAL/ESP32/watchdog.cpp +++ b/Marlin/src/HAL/SAMD21/u8g/LCD_pin_routines.c @@ -1,6 +1,6 @@ /** * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm @@ -19,24 +19,24 @@ * along with this program. If not, see . * */ -#ifdef ARDUINO_ARCH_ESP32 -#include "../../inc/MarlinConfig.h" - -#if ENABLED(USE_WATCHDOG) - -#define WDT_TIMEOUT_US TERN(WATCHDOG_DURATION_8S, 8000000, 4000000) // 4 or 8 second timeout - -#include "watchdog.h" +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ -void watchdogSetup() { - // do whatever. don't remove this function. -} +/** + * Low level pin manipulation routines - used by all the drivers. + * + * These are based on the SAMD51 pinMode, digitalRead & digitalWrite routines. + * + * Couldn't just call exact copies because the overhead killed the LCD update speed + * With an intermediate level the softspi was running in the 10-20kHz range which + * resulted in using about about 25% of the CPU's time. + */ -void watchdog_init() { - // TODO -} +#ifdef __SAMD21__ -#endif // USE_WATCHDOG +#include -#endif // ARDUINO_ARCH_ESP32 +#endif // __SAMD21__ diff --git a/Marlin/src/HAL/SAMD21/u8g/LCD_pin_routines.h b/Marlin/src/HAL/SAMD21/u8g/LCD_pin_routines.h new file mode 100644 index 00000000..92626552 --- /dev/null +++ b/Marlin/src/HAL/SAMD21/u8g/LCD_pin_routines.h @@ -0,0 +1,42 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ +#pragma once + +/** + * Low level pin manipulation routines - used by all the drivers. + * + * These are based on the SAMD51 pinMode, digitalRead & digitalWrite routines. + * + * Couldn't just call exact copies because the overhead killed the LCD update speed + * With an intermediate level the softspi was running in the 10-20kHz range which + * resulted in using about about 25% of the CPU's time. + */ + +void u8g_SetPinOutput(uint8_t internal_pin_number); +void u8g_SetPinInput(uint8_t internal_pin_number); +void u8g_SetPinLevel(uint8_t pin, uint8_t pin_status); +uint8_t u8g_GetPinLevel(uint8_t pin); diff --git a/Marlin/src/HAL/SAMD21/u8g/u8g_com_HAL_samd21_shared_hw_spi.cpp b/Marlin/src/HAL/SAMD21/u8g/u8g_com_HAL_samd21_shared_hw_spi.cpp new file mode 100644 index 00000000..2e2b0d8f --- /dev/null +++ b/Marlin/src/HAL/SAMD21/u8g/u8g_com_HAL_samd21_shared_hw_spi.cpp @@ -0,0 +1,157 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * SAMD21 HAL developed by Bart Meijer (brupje) + * Based on SAMD51 HAL by Giuliano Zaro (AKA GMagician) + */ + +/** + * Based on u8g_com_msp430_hw_spi.c + * + * Universal 8bit Graphics Library + * + * Copyright (c) 2012, olikraus@gmail.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef __SAMD21__ + +#include "../../../inc/MarlinConfigPre.h" + +#if HAS_MARLINUI_U8GLIB + +#include +#include "SPI.h" + +#include "../../shared/HAL_SPI.h" + +#ifndef LCD_SPI_SPEED + #define LCD_SPI_SPEED SPI_HALF_SPEED +#endif + +void u8g_SetPIOutput(u8g_t *u8g, uint8_t pin_index) { + if (u8g->pin_list[pin_index]!= U8G_PIN_NONE) + pinMode(u8g->pin_list[pin_index],OUTPUT); +} + +void u8g_SetPILevel(u8g_t *u8g, uint8_t pin_index, uint8_t level) { + if (u8g->pin_list[pin_index]!= U8G_PIN_NONE) + digitalWrite(u8g->pin_list[pin_index],level); +} + +uint8_t u8g_com_samd21_st7920_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) { + + switch (msg) { + case U8G_COM_MSG_STOP: + break; + + case U8G_COM_MSG_INIT: + u8g_SetPIOutput(u8g, U8G_PI_CS); + u8g_SetPIOutput(u8g, U8G_PI_A0); + u8g_SetPIOutput(u8g, U8G_PI_RESET); + + u8g_SetPILevel(u8g, U8G_PI_CS, LOW); + + spiBegin(); + u8g->pin_list[U8G_PI_A0_STATE] = 0; + break; + + case U8G_COM_MSG_ADDRESS: // define cmd (arg_val = 0) or data mode (arg_val = 1) + u8g_SetPILevel(u8g, U8G_PI_A0, arg_val); + u8g->pin_list[U8G_PI_A0_STATE] = arg_val; + break; + + case U8G_COM_MSG_CHIP_SELECT: // arg_val == 1 means chip selected, but ST7920 is active high, so needs inverting + u8g_SetPILevel(u8g, U8G_PI_CS, arg_val ? HIGH : LOW); + break; + + case U8G_COM_MSG_RESET: + u8g_SetPILevel(u8g, U8G_PI_RESET, arg_val); + break; + + case U8G_COM_MSG_WRITE_BYTE: + spiBeginTransaction(LCD_SPI_SPEED, MSBFIRST, SPI_MODE0); + + if (u8g->pin_list[U8G_PI_A0_STATE] == 0) { // command + SPI.transfer(0x0f8); u8g->pin_list[U8G_PI_A0_STATE] = 2; + } + else if (u8g->pin_list[U8G_PI_A0_STATE] == 1) { // data + SPI.transfer(0x0fa); u8g->pin_list[U8G_PI_A0_STATE] = 2; + } + + SPI.transfer(arg_val & 0x0f0); + SPI.transfer(arg_val << 4); + SPI.endTransaction(); + break; + + case U8G_COM_MSG_WRITE_SEQ: + spiBeginTransaction(LCD_SPI_SPEED, MSBFIRST, SPI_MODE0); + + if (u8g->pin_list[U8G_PI_A0_STATE] == 0 ) { // command + SPI.transfer(0x0f8); u8g->pin_list[U8G_PI_A0_STATE] = 2; + } + else if (u8g->pin_list[U8G_PI_A0_STATE] == 1) { // data + SPI.transfer(0x0fa); u8g->pin_list[U8G_PI_A0_STATE] = 2; + } + + uint8_t *ptr = (uint8_t*)arg_ptr; + while (arg_val > 0) { + SPI.transfer((*ptr) & 0x0f0); + SPI.transfer((*ptr) << 4); + ptr++; + arg_val--; + } + + SPI.endTransaction(); + break; + } + return 1; +} + +#endif // HAS_MARLINUI_U8GLIB + +#endif // __SAMD21__ diff --git a/Marlin/src/HAL/SAMD51/HAL.cpp b/Marlin/src/HAL/SAMD51/HAL.cpp index 8baad31b..308b45eb 100644 --- a/Marlin/src/HAL/SAMD51/HAL.cpp +++ b/Marlin/src/HAL/SAMD51/HAL.cpp @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,6 +19,10 @@ * along with this program. If not, see . * */ + +/** + * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + */ #ifdef __SAMD51__ #include "../../inc/MarlinConfig.h" @@ -42,34 +47,40 @@ #endif #endif -// ------------------------ -// Local defines -// ------------------------ - -#define GET_TEMP_0_ADC() TERN(HAS_TEMP_ADC_0, PIN_TO_ADC(TEMP_0_PIN), -1) -#define GET_TEMP_1_ADC() TERN(HAS_TEMP_ADC_1, PIN_TO_ADC(TEMP_1_PIN), -1) -#define GET_TEMP_2_ADC() TERN(HAS_TEMP_ADC_2, PIN_TO_ADC(TEMP_2_PIN), -1) -#define GET_TEMP_3_ADC() TERN(HAS_TEMP_ADC_3, PIN_TO_ADC(TEMP_3_PIN), -1) -#define GET_TEMP_4_ADC() TERN(HAS_TEMP_ADC_4, PIN_TO_ADC(TEMP_4_PIN), -1) -#define GET_TEMP_5_ADC() TERN(HAS_TEMP_ADC_5, PIN_TO_ADC(TEMP_5_PIN), -1) -#define GET_TEMP_6_ADC() TERN(HAS_TEMP_ADC_6, PIN_TO_ADC(TEMP_6_PIN), -1) -#define GET_TEMP_7_ADC() TERN(HAS_TEMP_ADC_7, PIN_TO_ADC(TEMP_7_PIN), -1) -#define GET_PROBE_ADC() TERN(HAS_TEMP_PROBE, PIN_TO_ADC(TEMP_PROBE_PIN), -1) -#define GET_BED_ADC() TERN(HAS_TEMP_ADC_BED, PIN_TO_ADC(TEMP_BED_PIN), -1) -#define GET_CHAMBER_ADC() TERN(HAS_TEMP_ADC_CHAMBER, PIN_TO_ADC(TEMP_CHAMBER_PIN), -1) -#define GET_COOLER_ADC() TERN(HAS_TEMP_ADC_COOLER, PIN_TO_ADC(TEMP_COOLER_PIN), -1) -#define GET_FILAMENT_WIDTH_ADC() TERN(FILAMENT_WIDTH_SENSOR, PIN_TO_ADC(FILWIDTH_PIN), -1) -#define GET_BUTTONS_ADC() TERN(HAS_ADC_BUTTONS, PIN_TO_ADC(ADC_KEYPAD_PIN), -1) +#define GET_TEMP_0_ADC() TERN(HAS_TEMP_ADC_0, PIN_TO_ADC(TEMP_0_PIN), -1) +#define GET_TEMP_1_ADC() TERN(HAS_TEMP_ADC_1, PIN_TO_ADC(TEMP_1_PIN), -1) +#define GET_TEMP_2_ADC() TERN(HAS_TEMP_ADC_2, PIN_TO_ADC(TEMP_2_PIN), -1) +#define GET_TEMP_3_ADC() TERN(HAS_TEMP_ADC_3, PIN_TO_ADC(TEMP_3_PIN), -1) +#define GET_TEMP_4_ADC() TERN(HAS_TEMP_ADC_4, PIN_TO_ADC(TEMP_4_PIN), -1) +#define GET_TEMP_5_ADC() TERN(HAS_TEMP_ADC_5, PIN_TO_ADC(TEMP_5_PIN), -1) +#define GET_TEMP_6_ADC() TERN(HAS_TEMP_ADC_6, PIN_TO_ADC(TEMP_6_PIN), -1) +#define GET_TEMP_7_ADC() TERN(HAS_TEMP_ADC_7, PIN_TO_ADC(TEMP_7_PIN), -1) +#define GET_BED_ADC() TERN(HAS_TEMP_ADC_BED, PIN_TO_ADC(TEMP_BED_PIN), -1) +#define GET_CHAMBER_ADC() TERN(HAS_TEMP_ADC_CHAMBER, PIN_TO_ADC(TEMP_CHAMBER_PIN), -1) +#define GET_PROBE_ADC() TERN(HAS_TEMP_ADC_PROBE, PIN_TO_ADC(TEMP_PROBE_PIN), -1) +#define GET_COOLER_ADC() TERN(HAS_TEMP_ADC_COOLER, PIN_TO_ADC(TEMP_COOLER_PIN), -1) +#define GET_BOARD_ADC() TERN(HAS_TEMP_ADC_BOARD, PIN_TO_ADC(TEMP_BOARD_PIN), -1) +#define GET_SOC_ADC() TERN(HAS_TEMP_ADC_BOARD, PIN_TO_ADC(TEMP_BOARD_PIN), -1) +#define GET_FILAMENT_WIDTH_ADC() TERN(FILAMENT_WIDTH_SENSOR, PIN_TO_ADC(FILWIDTH_PIN), -1) +#define GET_BUTTONS_ADC() TERN(HAS_ADC_BUTTONS, PIN_TO_ADC(ADC_KEYPAD_PIN), -1) +#define GET_JOY_ADC_X() TERN(HAS_JOY_ADC_X, PIN_TO_ADC(JOY_X_PIN), -1) +#define GET_JOY_ADC_Y() TERN(HAS_JOY_ADC_Y, PIN_TO_ADC(JOY_Y_PIN), -1) +#define GET_JOY_ADC_Z() TERN(HAS_JOY_ADC_Z, PIN_TO_ADC(JOY_Z_PIN), -1) +#define GET_POWERMON_ADC_CURRENT() TERN(POWER_MONITOR_CURRENT, PIN_TO_ADC(POWER_MONITOR_CURRENT_PIN), -1) +#define GET_POWERMON_ADC_VOLTS() TERN(POWER_MONITOR_VOLTAGE, PIN_TO_ADC(POWER_MONITOR_VOLTAGE_PIN), -1) #define IS_ADC_REQUIRED(n) ( \ GET_TEMP_0_ADC() == n || GET_TEMP_1_ADC() == n || GET_TEMP_2_ADC() == n || GET_TEMP_3_ADC() == n \ || GET_TEMP_4_ADC() == n || GET_TEMP_5_ADC() == n || GET_TEMP_6_ADC() == n || GET_TEMP_7_ADC() == n \ - || GET_PROBE_ADC() == n \ - || GET_BED_ADC() == n \ - || GET_CHAMBER_ADC() == n \ - || GET_COOLER_ADC() == n \ + || GET_BED_ADC() == n \ + || GET_CHAMBER_ADC() == n \ + || GET_PROBE_ADC() == n \ + || GET_COOLER_ADC() == n \ + || GET_BOARD_ADC() == n \ || GET_FILAMENT_WIDTH_ADC() == n \ - || GET_BUTTONS_ADC() == n \ + || GET_BUTTONS_ADC() == n \ + || GET_JOY_ADC_X() == n || GET_JOY_ADC_Y() == n || GET_JOY_ADC_Z() == n \ + || GET_POWERMON_ADC_CURRENT() == n || GET_POWERMON_ADC_VOLTS() == n \ ) #if IS_ADC_REQUIRED(0) @@ -89,6 +100,167 @@ #define DMA_IS_REQUIRED 1 #endif +enum ADCIndex { + #if GET_TEMP_0_ADC() == 0 + TEMP_0, + #endif + #if GET_TEMP_1_ADC() == 0 + TEMP_1, + #endif + #if GET_TEMP_2_ADC() == 0 + TEMP_2, + #endif + #if GET_TEMP_3_ADC() == 0 + TEMP_3, + #endif + #if GET_TEMP_4_ADC() == 0 + TEMP_4, + #endif + #if GET_TEMP_5_ADC() == 0 + TEMP_5, + #endif + #if GET_TEMP_6_ADC() == 0 + TEMP_6, + #endif + #if GET_TEMP_7_ADC() == 0 + TEMP_7, + #endif + #if GET_BED_ADC() == 0 + TEMP_BED, + #endif + #if GET_CHAMBER_ADC() == 0 + TEMP_CHAMBER, + #endif + #if GET_PROBE_ADC() == 0 + TEMP_PROBE, + #endif + #if GET_COOLER_ADC() == 0 + TEMP_COOLER, + #endif + #if GET_BOARD_ADC() == 0 + TEMP_BOARD, + #endif + #if GET_FILAMENT_WIDTH_ADC() == 0 + FILWIDTH, + #endif + #if GET_BUTTONS_ADC() == 0 + ADC_KEY, + #endif + #if GET_JOY_ADC_X() == 0 + JOY_X, + #endif + #if GET_JOY_ADC_Y() == 0 + JOY_Y, + #endif + #if GET_JOY_ADC_Z() == 0 + JOY_Z, + #endif + #if GET_POWERMON_ADC_CURRENT() == 0 + POWERMON_CURRENT, + #endif + #if GET_POWERMON_ADC_VOLTS() == 0 + POWERMON_VOLTAGE, + #endif + + // Indexes for ADC1 after those for ADC0 + + #if GET_TEMP_0_ADC() == 1 + TEMP_0, + #endif + #if GET_TEMP_1_ADC() == 1 + TEMP_1, + #endif + #if GET_TEMP_2_ADC() == 1 + TEMP_2, + #endif + #if GET_TEMP_3_ADC() == 1 + TEMP_3, + #endif + #if GET_TEMP_4_ADC() == 1 + TEMP_4, + #endif + #if GET_TEMP_5_ADC() == 1 + TEMP_5, + #endif + #if GET_TEMP_6_ADC() == 1 + TEMP_6, + #endif + #if GET_TEMP_7_ADC() == 1 + TEMP_7, + #endif + #if GET_BED_ADC() == 1 + TEMP_BED, + #endif + #if GET_CHAMBER_ADC() == 1 + TEMP_CHAMBER, + #endif + #if GET_PROBE_ADC() == 1 + TEMP_PROBE, + #endif + #if GET_COOLER_ADC() == 1 + TEMP_COOLER, + #endif + #if GET_BOARD_ADC() == 1 + TEMP_BOARD, + #endif + #if GET_FILAMENT_WIDTH_ADC() == 1 + FILWIDTH, + #endif + #if GET_BUTTONS_ADC() == 1 + ADC_KEY, + #endif + #if GET_JOY_ADC_X() == 1 + JOY_X, + #endif + #if GET_JOY_ADC_Y() == 1 + JOY_Y, + #endif + #if GET_JOY_ADC_Z() == 1 + JOY_Z, + #endif + #if GET_POWERMON_ADC_CURRENT() == 1 + POWERMON_CURRENT, + #endif + #if GET_POWERMON_ADC_VOLTS() == 1 + POWERMON_VOLTAGE, + #endif + ADC_COUNT +}; + +#if ENABLED(USE_WATCHDOG) + + #define WDT_TIMEOUT_REG TERN(WATCHDOG_DURATION_8S, WDT_CONFIG_PER_CYC8192, WDT_CONFIG_PER_CYC4096) // 4 or 8 second timeout + + void MarlinHAL::watchdog_init() { + // The low-power oscillator used by the WDT runs at 32,768 Hz with + // a 1:32 prescale, thus 1024 Hz, though probably not super precise. + + // Setup WDT clocks + MCLK->APBAMASK.bit.OSC32KCTRL_ = true; + MCLK->APBAMASK.bit.WDT_ = true; + OSC32KCTRL->OSCULP32K.bit.EN1K = true; // Enable out 1K (this is what WDT uses) + + WDT->CTRLA.bit.ENABLE = false; // Disable watchdog for config + SYNC(WDT->SYNCBUSY.bit.ENABLE); + + WDT->INTENCLR.reg = WDT_INTENCLR_EW; // Disable early warning interrupt + WDT->CONFIG.reg = WDT_TIMEOUT_REG; // Set a 4s or 8s period for chip reset + + hal.watchdog_refresh(); + + WDT->CTRLA.reg = WDT_CTRLA_ENABLE; // Start watchdog now in normal mode + SYNC(WDT->SYNCBUSY.bit.ENABLE); + } + + // Reset watchdog. MUST be called at least every 4 seconds after the + // first watchdog_init or SAMD will go into emergency procedures. + void MarlinHAL::watchdog_refresh() { + SYNC(WDT->SYNCBUSY.bit.CLEAR); // Test first if previous is 'ongoing' to save time waiting for command execution + WDT->CLEAR.reg = WDT_CLEAR_CLEAR_KEY; + } + +#endif + // ------------------------ // Types // ------------------------ @@ -106,12 +278,10 @@ // Private Variables // ------------------------ -uint16_t HAL_adc_result; - #if ADC_IS_REQUIRED // Pins used by ADC inputs. Order must be ADC0 inputs first then ADC1 - const uint8_t adc_pins[] = { + static constexpr uint8_t adc_pins[ADC_COUNT] = { // ADC0 pins #if GET_TEMP_0_ADC() == 0 TEMP_0_PIN, @@ -137,25 +307,45 @@ uint16_t HAL_adc_result; #if GET_TEMP_7_ADC() == 0 TEMP_7_PIN, #endif - #if GET_PROBE_ADC() == 0 - TEMP_PROBE_PIN, - #endif #if GET_BED_ADC() == 0 TEMP_BED_PIN, #endif #if GET_CHAMBER_ADC() == 0 TEMP_CHAMBER_PIN, #endif + #if GET_PROBE_ADC() == 0 + TEMP_PROBE_PIN, + #endif #if GET_COOLER_ADC() == 0 TEMP_COOLER_PIN, #endif + #if GET_BOARD_ADC() == 0 + TEMP_BOARD_PIN, + #endif #if GET_FILAMENT_WIDTH_ADC() == 0 FILWIDTH_PIN, #endif #if GET_BUTTONS_ADC() == 0 ADC_KEYPAD_PIN, #endif - // ADC1 pins + #if GET_JOY_ADC_X() == 0 + JOY_X_PIN, + #endif + #if GET_JOY_ADC_Y() == 0 + JOY_Y_PIN, + #endif + #if GET_JOY_ADC_Z() == 0 + JOY_Z_PIN, + #endif + #if GET_POWERMON_ADC_CURRENT() == 0 + POWER_MONITOR_CURRENT_PIN, + #endif + #if GET_POWERMON_ADC_VOLTS() == 0 + POWER_MONITOR_VOLTAGE_PIN, + #endif + + // Pins for ADC1 after ADC0 + #if GET_TEMP_0_ADC() == 1 TEMP_0_PIN, #endif @@ -180,33 +370,50 @@ uint16_t HAL_adc_result; #if GET_TEMP_7_ADC() == 1 TEMP_7_PIN, #endif - #if GET_PROBE_ADC() == 1 - TEMP_PROBE_PIN, - #endif #if GET_BED_ADC() == 1 TEMP_BED_PIN, #endif #if GET_CHAMBER_ADC() == 1 TEMP_CHAMBER_PIN, #endif + #if GET_PROBE_ADC() == 1 + TEMP_PROBE_PIN, + #endif #if GET_COOLER_ADC() == 1 TEMP_COOLER_PIN, #endif + #if GET_BOARD_ADC() == 1 + TEMP_BOARD_PIN, + #endif #if GET_FILAMENT_WIDTH_ADC() == 1 FILWIDTH_PIN, #endif #if GET_BUTTONS_ADC() == 1 ADC_KEYPAD_PIN, #endif + #if GET_JOY_ADC_X() == 1 + JOY_X_PIN, + #endif + #if GET_JOY_ADC_Y() == 1 + JOY_Y_PIN, + #endif + #if GET_JOY_ADC_Z() == 1 + JOY_Z_PIN, + #endif + #if GET_POWERMON_ADC_CURRENT() == 1 + POWER_MONITOR_CURRENT_PIN, + #endif + #if GET_POWERMON_ADC_VOLTS() == 1 + POWER_MONITOR_VOLTAGE_PIN, + #endif }; - uint16_t HAL_adc_results[COUNT(adc_pins)]; + static uint16_t adc_results[ADC_COUNT]; #if ADC0_IS_REQUIRED - Adafruit_ZeroDMA adc0DMAProgram, - adc0DMARead; + Adafruit_ZeroDMA adc0DMAProgram, adc0DMARead; - const HAL_DMA_DAC_Registers adc0_dma_regs_list[] = { + static constexpr HAL_DMA_DAC_Registers adc0_dma_regs_list[ADC_COUNT] = { #if GET_TEMP_0_ADC() == 0 { PIN_TO_INPUTCTRL(TEMP_0_PIN) }, #endif @@ -231,34 +438,51 @@ uint16_t HAL_adc_result; #if GET_TEMP_7_ADC() == 0 { PIN_TO_INPUTCTRL(TEMP_7_PIN) }, #endif - #if GET_PROBE_ADC() == 0 - { PIN_TO_INPUTCTRL(TEMP_PROBE_PIN) }, - #endif #if GET_BED_ADC() == 0 { PIN_TO_INPUTCTRL(TEMP_BED_PIN) }, #endif #if GET_CHAMBER_ADC() == 0 { PIN_TO_INPUTCTRL(TEMP_CHAMBER_PIN) }, #endif + #if GET_PROBE_ADC() == 0 + { PIN_TO_INPUTCTRL(TEMP_PROBE_PIN) }, + #endif #if GET_COOLER_ADC() == 0 { PIN_TO_INPUTCTRL(TEMP_COOLER_PIN) }, #endif + #if GET_BOARD_ADC() == 0 + { PIN_TO_INPUTCTRL(TEMP_BOARD_PIN) }, + #endif #if GET_FILAMENT_WIDTH_ADC() == 0 { PIN_TO_INPUTCTRL(FILWIDTH_PIN) }, #endif #if GET_BUTTONS_ADC() == 0 { PIN_TO_INPUTCTRL(ADC_KEYPAD_PIN) }, #endif + #if GET_JOY_ADC_X() == 0 + { PIN_TO_INPUTCTRL(JOY_X_PIN) }, + #endif + #if GET_JOY_ADC_Y() == 0 + { PIN_TO_INPUTCTRL(JOY_Y_PIN) }, + #endif + #if GET_JOY_ADC_Z() == 0 + { PIN_TO_INPUTCTRL(JOY_Z_PIN) }, + #endif + #if GET_POWERMON_ADC_CURRENT() == 0 + { PIN_TO_INPUTCTRL(POWER_MONITOR_CURRENT_PIN) }, + #endif + #if GET_POWERMON_ADC_VOLTS() == 0 + { PIN_TO_INPUTCTRL(POWER_MONITOR_VOLTAGE_PIN) }, + #endif }; #define ADC0_AINCOUNT COUNT(adc0_dma_regs_list) #endif // ADC0_IS_REQUIRED #if ADC1_IS_REQUIRED - Adafruit_ZeroDMA adc1DMAProgram, - adc1DMARead; + Adafruit_ZeroDMA adc1DMAProgram, adc1DMARead; - const HAL_DMA_DAC_Registers adc1_dma_regs_list[] = { + static constexpr HAL_DMA_DAC_Registers adc1_dma_regs_list[ADC_COUNT] = { #if GET_TEMP_0_ADC() == 1 { PIN_TO_INPUTCTRL(TEMP_0_PIN) }, #endif @@ -283,24 +507,42 @@ uint16_t HAL_adc_result; #if GET_TEMP_7_ADC() == 1 { PIN_TO_INPUTCTRL(TEMP_7_PIN) }, #endif - #if GET_PROBE_ADC() == 1 - { PIN_TO_INPUTCTRL(TEMP_PROBE_PIN) }, - #endif #if GET_BED_ADC() == 1 { PIN_TO_INPUTCTRL(TEMP_BED_PIN) }, #endif #if GET_CHAMBER_ADC() == 1 { PIN_TO_INPUTCTRL(TEMP_CHAMBER_PIN) }, #endif + #if GET_PROBE_ADC() == 1 + { PIN_TO_INPUTCTRL(TEMP_PROBE_PIN) }, + #endif #if GET_COOLER_ADC() == 1 { PIN_TO_INPUTCTRL(TEMP_COOLER_PIN) }, #endif + #if GET_BOARD_ADC() == 1 + { PIN_TO_INPUTCTRL(TEMP_BOARD_PIN) }, + #endif #if GET_FILAMENT_WIDTH_ADC() == 1 { PIN_TO_INPUTCTRL(FILWIDTH_PIN) }, #endif #if GET_BUTTONS_ADC() == 1 { PIN_TO_INPUTCTRL(ADC_KEYPAD_PIN) }, #endif + #if GET_JOY_ADC_X() == 1 + { PIN_TO_INPUTCTRL(JOY_X_PIN) }, + #endif + #if GET_JOY_ADC_Y() == 1 + { PIN_TO_INPUTCTRL(JOY_Y_PIN) }, + #endif + #if GET_JOY_ADC_Z() == 1 + { PIN_TO_INPUTCTRL(JOY_Z_PIN) }, + #endif + #if GET_POWERMON_ADC_CURRENT() == 1 + { PIN_TO_INPUTCTRL(POWER_MONITOR_CURRENT_PIN) }, + #endif + #if GET_POWERMON_ADC_VOLTS() == 1 + { PIN_TO_INPUTCTRL(POWER_MONITOR_VOLTAGE_PIN) }, + #endif }; #define ADC1_AINCOUNT COUNT(adc1_dma_regs_list) @@ -312,9 +554,10 @@ uint16_t HAL_adc_result; // Private functions // ------------------------ -#if DMA_IS_REQUIRED +void MarlinHAL::dma_init() { + + #if DMA_IS_REQUIRED - void dma_init() { DmacDescriptor *descriptor; #if ADC0_IS_REQUIRED @@ -343,7 +586,7 @@ uint16_t HAL_adc_result; if (adc0DMARead.allocate() == DMA_STATUS_OK) { adc0DMARead.addDescriptor( (void *)&ADC0->RESULT.reg, // SRC - &HAL_adc_results, // DEST + &adc_results, // DEST ADC0_AINCOUNT, // CNT DMA_BEAT_SIZE_HWORD, false, // SRCINC @@ -380,7 +623,7 @@ uint16_t HAL_adc_result; if (adc1DMARead.allocate() == DMA_STATUS_OK) { adc1DMARead.addDescriptor( (void *)&ADC1->RESULT.reg, // SRC - &HAL_adc_results[ADC0_AINCOUNT], // DEST + &adc_results[ADC0_AINCOUNT], // DEST ADC1_AINCOUNT, // CNT DMA_BEAT_SIZE_HWORD, false, // SRCINC @@ -393,36 +636,28 @@ uint16_t HAL_adc_result; #endif DMAC->PRICTRL0.bit.RRLVLEN0 = true; // Activate round robin for DMA channels required by ADCs - } -#endif // DMA_IS_REQUIRED + #endif // DMA_IS_REQUIRED +} // ------------------------ // Public functions // ------------------------ // HAL initialization task -void HAL_init() { +void MarlinHAL::init() { TERN_(DMA_IS_REQUIRED, dma_init()); - #if ENABLED(SDSUPPORT) - #if SD_CONNECTION_IS(ONBOARD) && PIN_EXISTS(SD_DETECT) + #if HAS_MEDIA + #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 #endif } -// HAL idle task -/* -void HAL_idletask() { -} -*/ - -void HAL_clear_reset_source() { } - #pragma push_macro("WDT") #undef WDT // Required to be able to use '.bit.WDT'. Compiler wrongly replace struct field with WDT define -uint8_t HAL_get_reset_source() { +uint8_t MarlinHAL::get_reset_source() { RSTC_RCAUSE_Type resetCause; resetCause.reg = REG_RSTC_RCAUSE; @@ -436,7 +671,7 @@ uint8_t HAL_get_reset_source() { } #pragma pop_macro("WDT") -void HAL_reboot() { NVIC_SystemReset(); } +void MarlinHAL::reboot() { NVIC_SystemReset(); } extern "C" { void * _sbrk(int incr); @@ -454,14 +689,16 @@ int freeMemory() { // ADC // ------------------------ -void HAL_adc_init() { +uint16_t MarlinHAL::adc_result; + +void MarlinHAL::adc_init() { #if ADC_IS_REQUIRED - memset(HAL_adc_results, 0xFF, sizeof(HAL_adc_results)); // Fill result with invalid values + memset(adc_results, 0xFF, sizeof(adc_results)); // Fill result with invalid values - LOOP_L_N(pi, COUNT(adc_pins)) + for (uint8_t pi = 0; pi < COUNT(adc_pins); ++pi) pinPeripheral(adc_pins[pi], PIO_ANALOG); - LOOP_S_LE_N(ai, FIRST_ADC, LAST_ADC) { + for (uint8_t ai = FIRST_ADC; ai <= LAST_ADC; ++ai) { Adc* adc = ((Adc*[])ADC_INSTS)[ai]; // ADC clock setup @@ -491,17 +728,13 @@ void HAL_adc_init() { #endif // ADC_IS_REQUIRED } -void HAL_adc_start_conversion(const uint8_t adc_pin) { +void MarlinHAL::adc_start(const pin_t pin) { #if ADC_IS_REQUIRED - LOOP_L_N(pi, COUNT(adc_pins)) { - if (adc_pin == adc_pins[pi]) { - HAL_adc_result = HAL_adc_results[pi]; - return; - } - } + for (uint8_t pi = 0; pi < COUNT(adc_pins); ++pi) + if (pin == adc_pins[pi]) { adc_result = adc_results[pi]; return; } #endif - HAL_adc_result = 0xFFFF; + adc_result = 0xFFFF; } #endif // __SAMD51__ diff --git a/Marlin/src/HAL/SAMD51/HAL.h b/Marlin/src/HAL/SAMD51/HAL.h index c262752a..c96401fd 100644 --- a/Marlin/src/HAL/SAMD51/HAL.h +++ b/Marlin/src/HAL/SAMD51/HAL.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,13 +21,16 @@ */ #pragma once +/** + * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + */ + #define CPU_32_BIT #include "../shared/Marduino.h" #include "../shared/math_32bit.h" #include "../shared/HAL_SPI.h" #include "fastio.h" -#include "watchdog.h" #ifdef ADAFRUIT_GRAND_CENTRAL_M4 #include "MarlinSerial_AGCM4.h" @@ -89,51 +93,30 @@ typedef int8_t pin_t; -#define SHARED_SERVOS HAS_SERVOS -#define HAL_SERVO_LIB Servo +#define SHARED_SERVOS HAS_SERVOS // Use shared/servos.cpp + +class Servo; +typedef Servo hal_servo_t; // // Interrupts // -#define CRITICAL_SECTION_START() uint32_t primask = __get_PRIMASK(); __disable_irq() -#define CRITICAL_SECTION_END() if (!primask) __enable_irq() -#define ISRS_ENABLED() (!__get_PRIMASK()) -#define ENABLE_ISRS() __enable_irq() -#define DISABLE_ISRS() __disable_irq() - -#define cli() __disable_irq() // Disable interrupts -#define sei() __enable_irq() // Enable interrupts +#define CRITICAL_SECTION_START() const bool irqon = !__get_PRIMASK(); __disable_irq() +#define CRITICAL_SECTION_END() if (irqon) __enable_irq() -void HAL_clear_reset_source(); // clear reset reason -uint8_t HAL_get_reset_source(); // get reset reason - -void HAL_reboot(); +#define cli() __disable_irq() // Disable interrupts +#define sei() __enable_irq() // Enable interrupts // // ADC // -extern uint16_t HAL_adc_result; // Most recent ADC conversion - -#define HAL_ANALOG_SELECT(pin) - -void HAL_adc_init(); //#define HAL_ADC_FILTERED // Disable Marlin's oversampling. The HAL filters ADC values. -#define HAL_ADC_VREF 3.3 +#define HAL_ADC_VREF_MV 3300 #define HAL_ADC_RESOLUTION 10 // ... 12 -#define HAL_START_ADC(pin) HAL_adc_start_conversion(pin) -#define HAL_READ_ADC() HAL_adc_result -#define HAL_ADC_READY() true - -void HAL_adc_start_conversion(const uint8_t adc_pin); - -// -// PWM -// -inline void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { analogWrite(pin, v); } // -// Pin Map +// Pin Mapping for M42, M43, M226 // #define GET_PIN_MAP_PIN(index) index #define GET_PIN_MAP_INDEX(pin) pin @@ -142,35 +125,97 @@ inline void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, // // Tone // -void toneInit(); void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration=0); void noTone(const pin_t _pin); -// Enable hooks into idle and setup for HAL -void HAL_init(); -/* -#define HAL_IDLETASK 1 -void HAL_idletask(); -*/ - -// -// Utility functions -// -FORCE_INLINE void _delay_ms(const int delay_ms) { delay(delay_ms); } +// ------------------------ +// Class Utilities +// ------------------------ #pragma GCC diagnostic push #if GCC_VERSION <= 50000 #pragma GCC diagnostic ignored "-Wunused-function" #endif -int freeMemory(); - -#pragma GCC diagnostic pop - #ifdef __cplusplus extern "C" { #endif + char *dtostrf(double __val, signed char __width, unsigned char __prec, char *__s); + +extern "C" int freeMemory(); + #ifdef __cplusplus } #endif + +#pragma GCC diagnostic pop + +// ------------------------ +// MarlinHAL Class +// ------------------------ + +class MarlinHAL { +public: + + // Earliest possible init, before setup() + MarlinHAL() {} + + // Watchdog + static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {}); + static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {}); + + static void init(); // Called early in setup() + static void init_board() {} // Called less early in setup() + static void reboot(); // Restart the firmware from 0x0 + + // Interrupts + static bool isr_state() { return !__get_PRIMASK(); } + static void isr_on() { sei(); } + static void isr_off() { cli(); } + + static void delay_ms(const int ms) { delay(ms); } + + // Tasks, called from idle() + static void idletask() {} + + // Reset + static uint8_t get_reset_source(); + static void clear_reset_source() {} + + // Free SRAM + static int freeMemory() { return ::freeMemory(); } + + // + // ADC Methods + // + + static uint16_t adc_result; + + // Called by Temperature::init once at startup + static void adc_init(); + + // Called by Temperature::init for each sensor at startup + static void adc_enable(const uint8_t ch) {} + + // Begin ADC sampling on the given pin. Called from Temperature::isr! + static void adc_start(const pin_t pin); + + // Is the ADC ready for reading? + static bool adc_ready() { return true; } + + // The current value of the ADC register + static uint16_t adc_value() { return adc_result; } + + /** + * Set the PWM duty cycle for the pin to the given value. + * No option to invert the duty cycle [default = false] + * No option to change the scale of the provided value to enable finer PWM duty control [default = 255] + */ + static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { + analogWrite(pin, v); + } + +private: + static void dma_init(); +}; diff --git a/Marlin/src/HAL/SAMD51/HAL_SPI.cpp b/Marlin/src/HAL/SAMD51/HAL_SPI.cpp index 77f4d5ec..63d39719 100644 --- a/Marlin/src/HAL/SAMD51/HAL_SPI.cpp +++ b/Marlin/src/HAL/SAMD51/HAL_SPI.cpp @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +20,10 @@ * */ +/** + * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + */ + /** * Hardware and software SPI implementations are included in this file. * @@ -39,7 +44,7 @@ // Public functions // -------------------------------------------------------------------------- -#if EITHER(SOFTWARE_SPI, FORCE_SOFT_SPI) +#if ANY(SOFTWARE_SPI, FORCE_SOFT_SPI) // ------------------------ // Software SPI diff --git a/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.cpp b/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.cpp index a16ea2f7..baa7a385 100644 --- a/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.cpp +++ b/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.cpp @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,6 +19,10 @@ * along with this program. If not, see . * */ + +/** + * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + */ #ifdef ADAFRUIT_GRAND_CENTRAL_M4 /** diff --git a/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h b/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h index ac5a3793..1044d9fc 100644 --- a/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h +++ b/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +21,10 @@ */ #pragma once +/** + * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + */ + #include "../../core/serial_hook.h" typedef Serial1Class UartT; diff --git a/Marlin/src/HAL/SAMD51/SAMD51.h b/Marlin/src/HAL/SAMD51/SAMD51.h index 78395614..8cc19d71 100644 --- a/Marlin/src/HAL/SAMD51/SAMD51.h +++ b/Marlin/src/HAL/SAMD51/SAMD51.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +21,10 @@ */ #pragma once +/** + * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + */ + #define SYNC(sc) while (sc) { \ asm(""); \ } diff --git a/Marlin/src/HAL/SAMD51/Servo.cpp b/Marlin/src/HAL/SAMD51/Servo.cpp index 23ab21c6..059955e1 100644 --- a/Marlin/src/HAL/SAMD51/Servo.cpp +++ b/Marlin/src/HAL/SAMD51/Servo.cpp @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +20,10 @@ * */ +/** + * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + */ + /** * This comes from Arduino library which at the moment is buggy and uncompilable */ @@ -49,7 +54,6 @@ #define TIMER_TCCHANNEL(t) ((t) & 1) #define TC_COUNTER_START_VAL 0xFFFF - static volatile int8_t currentServoIndex[_Nbr_16timers]; // index for the servo being pulsed for each timer (or -1 if refresh interval) FORCE_INLINE static uint16_t getTimerCount() { @@ -77,7 +81,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 +91,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 - - // Select the next servo controlled by this timer - currentServoIndex[timer]++; + else if (SERVO_INDEX(timer, cho) < ServoCount) // prior channel handled? + digitalWrite(SERVO(timer, cho).Pin.nbr, LOW); // pulse the prior channel LOW - 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 + 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 - 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 +198,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; diff --git a/Marlin/src/HAL/SAMD51/ServoTimers.h b/Marlin/src/HAL/SAMD51/ServoTimers.h index 948d5153..47e0a190 100644 --- a/Marlin/src/HAL/SAMD51/ServoTimers.h +++ b/Marlin/src/HAL/SAMD51/ServoTimers.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +21,10 @@ */ #pragma once +/** + * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + */ + #define _useTimer1 #define _useTimer2 diff --git a/Marlin/src/HAL/SAMD51/eeprom_flash.cpp b/Marlin/src/HAL/SAMD51/eeprom_flash.cpp index 871bf22b..7d551895 100644 --- a/Marlin/src/HAL/SAMD51/eeprom_flash.cpp +++ b/Marlin/src/HAL/SAMD51/eeprom_flash.cpp @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,6 +19,10 @@ * along with this program. If not, see . * */ + +/** + * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + */ #ifdef __SAMD51__ #include "../../inc/MarlinConfig.h" diff --git a/Marlin/src/HAL/SAMD51/eeprom_qspi.cpp b/Marlin/src/HAL/SAMD51/eeprom_qspi.cpp index faa76371..1c82ede0 100644 --- a/Marlin/src/HAL/SAMD51/eeprom_qspi.cpp +++ b/Marlin/src/HAL/SAMD51/eeprom_qspi.cpp @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,6 +19,10 @@ * along with this program. If not, see . * */ + +/** + * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + */ #ifdef __SAMD51__ #include "../../inc/MarlinConfig.h" diff --git a/Marlin/src/HAL/SAMD51/eeprom_wired.cpp b/Marlin/src/HAL/SAMD51/eeprom_wired.cpp index 3481fe53..7a03d4ea 100644 --- a/Marlin/src/HAL/SAMD51/eeprom_wired.cpp +++ b/Marlin/src/HAL/SAMD51/eeprom_wired.cpp @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,6 +19,10 @@ * along with this program. If not, see . * */ + +/** + * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + */ #ifdef __SAMD51__ #include "../../inc/MarlinConfig.h" diff --git a/Marlin/src/HAL/SAMD51/endstop_interrupts.h b/Marlin/src/HAL/SAMD51/endstop_interrupts.h index 61a06c0d..62a49e5f 100644 --- a/Marlin/src/HAL/SAMD51/endstop_interrupts.h +++ b/Marlin/src/HAL/SAMD51/endstop_interrupts.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +21,10 @@ */ #pragma once +/** + * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + */ + /** * Endstop interrupts for ATMEL SAMD51 based targets. * @@ -48,25 +53,35 @@ #include "../../module/endstops.h" #define MATCH_EILINE(P1,P2) (P1 != P2 && PIN_TO_EILINE(P1) == PIN_TO_EILINE(P2)) -#define MATCH_X_MAX_EILINE(P) TERN0(HAS_X_MAX, DEFER4(MATCH_EILINE)(P, X_MAX_PIN)) -#define MATCH_X_MIN_EILINE(P) TERN0(HAS_X_MIN, DEFER4(MATCH_EILINE)(P, X_MIN_PIN)) -#define MATCH_Y_MAX_EILINE(P) TERN0(HAS_Y_MAX, DEFER4(MATCH_EILINE)(P, Y_MAX_PIN)) -#define MATCH_Y_MIN_EILINE(P) TERN0(HAS_Y_MIN, DEFER4(MATCH_EILINE)(P, Y_MIN_PIN)) -#define MATCH_Z_MAX_EILINE(P) TERN0(HAS_Z_MAX, DEFER4(MATCH_EILINE)(P, Z_MAX_PIN)) -#define MATCH_Z_MIN_EILINE(P) TERN0(HAS_Z_MIN, DEFER4(MATCH_EILINE)(P, Z_MIN_PIN)) -#define MATCH_I_MAX_EILINE(P) TERN0(HAS_I_MAX, DEFER4(MATCH_EILINE)(P, I_MAX_PIN)) -#define MATCH_I_MIN_EILINE(P) TERN0(HAS_I_MIN, DEFER4(MATCH_EILINE)(P, I_MIN_PIN)) -#define MATCH_J_MAX_EILINE(P) TERN0(HAS_J_MAX, DEFER4(MATCH_EILINE)(P, J_MAX_PIN)) -#define MATCH_J_MIN_EILINE(P) TERN0(HAS_J_MIN, DEFER4(MATCH_EILINE)(P, J_MIN_PIN)) -#define MATCH_K_MAX_EILINE(P) TERN0(HAS_K_MAX, DEFER4(MATCH_EILINE)(P, K_MAX_PIN)) -#define MATCH_K_MIN_EILINE(P) TERN0(HAS_K_MIN, DEFER4(MATCH_EILINE)(P, K_MIN_PIN)) -#define MATCH_Z2_MAX_EILINE(P) TERN0(HAS_Z2_MAX, DEFER4(MATCH_EILINE)(P, Z2_MAX_PIN)) -#define MATCH_Z2_MIN_EILINE(P) TERN0(HAS_Z2_MIN, DEFER4(MATCH_EILINE)(P, Z2_MIN_PIN)) -#define MATCH_Z3_MAX_EILINE(P) TERN0(HAS_Z3_MAX, DEFER4(MATCH_EILINE)(P, Z3_MAX_PIN)) -#define MATCH_Z3_MIN_EILINE(P) TERN0(HAS_Z3_MIN, DEFER4(MATCH_EILINE)(P, Z3_MIN_PIN)) -#define MATCH_Z4_MAX_EILINE(P) TERN0(HAS_Z4_MAX, DEFER4(MATCH_EILINE)(P, Z4_MAX_PIN)) -#define MATCH_Z4_MIN_EILINE(P) TERN0(HAS_Z4_MIN, DEFER4(MATCH_EILINE)(P, Z4_MIN_PIN)) -#define MATCH_Z_MIN_PROBE_EILINE(P) TERN0(HAS_Z_MIN_PROBE_PIN, DEFER4(MATCH_EILINE)(P, Z_MIN_PROBE_PIN)) +#define MATCH_X_MAX_EILINE(P) TERN0(USE_X_MAX, DEFER4(MATCH_EILINE)(P, X_MAX_PIN)) +#define MATCH_X_MIN_EILINE(P) TERN0(USE_X_MIN, DEFER4(MATCH_EILINE)(P, X_MIN_PIN)) +#define MATCH_Y_MAX_EILINE(P) TERN0(USE_Y_MAX, DEFER4(MATCH_EILINE)(P, Y_MAX_PIN)) +#define MATCH_Y_MIN_EILINE(P) TERN0(USE_Y_MIN, DEFER4(MATCH_EILINE)(P, Y_MIN_PIN)) +#define MATCH_Z_MAX_EILINE(P) TERN0(USE_Z_MAX, DEFER4(MATCH_EILINE)(P, Z_MAX_PIN)) +#define MATCH_Z_MIN_EILINE(P) TERN0(USE_Z_MIN, DEFER4(MATCH_EILINE)(P, Z_MIN_PIN)) +#define MATCH_I_MAX_EILINE(P) TERN0(USE_I_MAX, DEFER4(MATCH_EILINE)(P, I_MAX_PIN)) +#define MATCH_I_MIN_EILINE(P) TERN0(USE_I_MIN, DEFER4(MATCH_EILINE)(P, I_MIN_PIN)) +#define MATCH_J_MAX_EILINE(P) TERN0(USE_J_MAX, DEFER4(MATCH_EILINE)(P, J_MAX_PIN)) +#define MATCH_J_MIN_EILINE(P) TERN0(USE_J_MIN, DEFER4(MATCH_EILINE)(P, J_MIN_PIN)) +#define MATCH_K_MAX_EILINE(P) TERN0(USE_K_MAX, DEFER4(MATCH_EILINE)(P, K_MAX_PIN)) +#define MATCH_K_MIN_EILINE(P) TERN0(USE_K_MIN, DEFER4(MATCH_EILINE)(P, K_MIN_PIN)) +#define MATCH_U_MAX_EILINE(P) TERN0(USE_U_MAX, DEFER4(MATCH_EILINE)(P, U_MAX_PIN)) +#define MATCH_U_MIN_EILINE(P) TERN0(USE_U_MIN, DEFER4(MATCH_EILINE)(P, U_MIN_PIN)) +#define MATCH_V_MAX_EILINE(P) TERN0(USE_V_MAX, DEFER4(MATCH_EILINE)(P, V_MAX_PIN)) +#define MATCH_V_MIN_EILINE(P) TERN0(USE_V_MIN, DEFER4(MATCH_EILINE)(P, V_MIN_PIN)) +#define MATCH_W_MAX_EILINE(P) TERN0(USE_W_MAX, DEFER4(MATCH_EILINE)(P, W_MAX_PIN)) +#define MATCH_W_MIN_EILINE(P) TERN0(USE_W_MIN, DEFER4(MATCH_EILINE)(P, W_MIN_PIN)) +#define MATCH_X2_MAX_EILINE(P) TERN0(USE_X2_MAX, DEFER4(MATCH_EILINE)(P, X2_MAX_PIN)) +#define MATCH_X2_MIN_EILINE(P) TERN0(USE_X2_MIN, DEFER4(MATCH_EILINE)(P, X2_MIN_PIN)) +#define MATCH_Y2_MAX_EILINE(P) TERN0(USE_Y2_MAX, DEFER4(MATCH_EILINE)(P, Y2_MAX_PIN)) +#define MATCH_Y2_MIN_EILINE(P) TERN0(USE_Y2_MIN, DEFER4(MATCH_EILINE)(P, Y2_MIN_PIN)) +#define MATCH_Z2_MAX_EILINE(P) TERN0(USE_Z2_MAX, DEFER4(MATCH_EILINE)(P, Z2_MAX_PIN)) +#define MATCH_Z2_MIN_EILINE(P) TERN0(USE_Z2_MIN, DEFER4(MATCH_EILINE)(P, Z2_MIN_PIN)) +#define MATCH_Z3_MAX_EILINE(P) TERN0(USE_Z3_MAX, DEFER4(MATCH_EILINE)(P, Z3_MAX_PIN)) +#define MATCH_Z3_MIN_EILINE(P) TERN0(USE_Z3_MIN, DEFER4(MATCH_EILINE)(P, Z3_MIN_PIN)) +#define MATCH_Z4_MAX_EILINE(P) TERN0(USE_Z4_MAX, DEFER4(MATCH_EILINE)(P, Z4_MAX_PIN)) +#define MATCH_Z4_MIN_EILINE(P) TERN0(USE_Z4_MIN, DEFER4(MATCH_EILINE)(P, Z4_MIN_PIN)) +#define MATCH_Z_MIN_PROBE_EILINE(P) TERN0(HAS_Z_MIN_PROBE+PIN, DEFER4(MATCH_EILINE)(P, Z_MIN_PROBE_PIN)) #define AVAILABLE_EILINE(P) ( PIN_TO_EILINE(P) != -1 \ && !MATCH_X_MAX_EILINE(P) && !MATCH_X_MIN_EILINE(P) \ @@ -75,6 +90,11 @@ && !MATCH_I_MAX_EILINE(P) && !MATCH_I_MIN_EILINE(P) \ && !MATCH_J_MAX_EILINE(P) && !MATCH_J_MIN_EILINE(P) \ && !MATCH_K_MAX_EILINE(P) && !MATCH_K_MIN_EILINE(P) \ + && !MATCH_U_MAX_EILINE(P) && !MATCH_U_MIN_EILINE(P) \ + && !MATCH_V_MAX_EILINE(P) && !MATCH_V_MIN_EILINE(P) \ + && !MATCH_W_MAX_EILINE(P) && !MATCH_W_MIN_EILINE(P) \ + && !MATCH_X2_MAX_EILINE(P) && !MATCH_X2_MIN_EILINE(P) \ + && !MATCH_Y2_MAX_EILINE(P) && !MATCH_Y2_MIN_EILINE(P) \ && !MATCH_Z2_MAX_EILINE(P) && !MATCH_Z2_MIN_EILINE(P) \ && !MATCH_Z3_MAX_EILINE(P) && !MATCH_Z3_MIN_EILINE(P) \ && !MATCH_Z4_MAX_EILINE(P) && !MATCH_Z4_MIN_EILINE(P) \ @@ -85,118 +105,154 @@ void endstop_ISR() { endstops.update(); } void setup_endstop_interrupts() { #define _ATTACH(P) attachInterrupt(P, endstop_ISR, CHANGE) - #if HAS_X_MAX + #if USE_X_MAX #if !AVAILABLE_EILINE(X_MAX_PIN) - #error "X_MAX_PIN has no EXTINT line available." + #error "X_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(X_MAX_PIN); #endif - #if HAS_X_MIN + #if USE_X_MIN #if !AVAILABLE_EILINE(X_MIN_PIN) - #error "X_MIN_PIN has no EXTINT line available." + #error "X_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(X_MIN_PIN); #endif - #if HAS_Y_MAX + #if USE_Y_MAX #if !AVAILABLE_EILINE(Y_MAX_PIN) - #error "Y_MAX_PIN has no EXTINT line available." + #error "Y_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Y_MAX_PIN); #endif - #if HAS_Y_MIN + #if USE_Y_MIN #if !AVAILABLE_EILINE(Y_MIN_PIN) - #error "Y_MIN_PIN has no EXTINT line available." + #error "Y_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Y_MIN_PIN); #endif - #if HAS_Z_MAX + #if USE_Z_MAX #if !AVAILABLE_EILINE(Z_MAX_PIN) - #error "Z_MAX_PIN has no EXTINT line available." + #error "Z_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z_MAX_PIN); #endif - #if HAS_Z_MIN + #if USE_Z_MIN #if !AVAILABLE_EILINE(Z_MIN_PIN) - #error "Z_MIN_PIN has no EXTINT line available." + #error "Z_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z_MIN_PIN); #endif - #if HAS_Z2_MAX + #if USE_Z2_MAX #if !AVAILABLE_EILINE(Z2_MAX_PIN) - #error "Z2_MAX_PIN has no EXTINT line available." + #error "Z2_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z2_MAX_PIN); #endif - #if HAS_Z2_MIN + #if USE_Z2_MIN #if !AVAILABLE_EILINE(Z2_MIN_PIN) - #error "Z2_MIN_PIN has no EXTINT line available." + #error "Z2_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z2_MIN_PIN); #endif - #if HAS_Z3_MAX + #if USE_Z3_MAX #if !AVAILABLE_EILINE(Z3_MAX_PIN) - #error "Z3_MAX_PIN has no EXTINT line available." + #error "Z3_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z3_MAX_PIN); #endif - #if HAS_Z3_MIN + #if USE_Z3_MIN #if !AVAILABLE_EILINE(Z3_MIN_PIN) - #error "Z3_MIN_PIN has no EXTINT line available." + #error "Z3_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z3_MIN_PIN); #endif - #if HAS_Z4_MAX + #if USE_Z4_MAX #if !AVAILABLE_EILINE(Z4_MAX_PIN) - #error "Z4_MAX_PIN has no EXTINT line available." + #error "Z4_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z4_MAX_PIN); #endif - #if HAS_Z4_MIN + #if USE_Z4_MIN #if !AVAILABLE_EILINE(Z4_MIN_PIN) - #error "Z4_MIN_PIN has no EXTINT line available." + #error "Z4_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z4_MIN_PIN); #endif #if HAS_Z_MIN_PROBE_PIN #if !AVAILABLE_EILINE(Z_MIN_PROBE_PIN) - #error "Z_MIN_PROBE_PIN has no EXTINT line available." + #error "Z_MIN_PROBE_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif _ATTACH(Z_MIN_PROBE_PIN); #endif - #if HAS_I_MAX + #if USE_I_MAX #if !AVAILABLE_EILINE(I_MAX_PIN) - #error "I_MAX_PIN has no EXTINT line available." + #error "I_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif attachInterrupt(I_MAX_PIN, endstop_ISR, CHANGE); #endif - #if HAS_I_MIN + #if USE_I_MIN #if !AVAILABLE_EILINE(I_MIN_PIN) - #error "I_MIN_PIN has no EXTINT line available." + #error "I_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif attachInterrupt(I_MIN_PIN, endstop_ISR, CHANGE); #endif - #if HAS_J_MAX + #if USE_J_MAX #if !AVAILABLE_EILINE(J_MAX_PIN) - #error "J_MAX_PIN has no EXTINT line available." + #error "J_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif attachInterrupt(J_MAX_PIN, endstop_ISR, CHANGE); #endif - #if HAS_J_MIN + #if USE_J_MIN #if !AVAILABLE_EILINE(J_MIN_PIN) - #error "J_MIN_PIN has no EXTINT line available." + #error "J_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif attachInterrupt(J_MIN_PIN, endstop_ISR, CHANGE); #endif - #if HAS_K_MAX + #if USE_K_MAX #if !AVAILABLE_EILINE(K_MAX_PIN) - #error "K_MAX_PIN has no EXTINT line available." + #error "K_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif attachInterrupt(K_MAX_PIN, endstop_ISR, CHANGE); #endif - #if HAS_K_MIN + #if USE_K_MIN #if !AVAILABLE_EILINE(K_MIN_PIN) - #error "K_MIN_PIN has no EXTINT line available." + #error "K_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." #endif attachInterrupt(K_MIN_PIN, endstop_ISR, CHANGE); #endif + #if USE_U_MAX + #if !AVAILABLE_EILINE(U_MAX_PIN) + #error "U_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(U_MAX_PIN, endstop_ISR, CHANGE); + #endif + #if USE_U_MIN + #if !AVAILABLE_EILINE(U_MIN_PIN) + #error "U_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(U_MIN_PIN, endstop_ISR, CHANGE); + #endif + #if USE_V_MAX + #if !AVAILABLE_EILINE(V_MAX_PIN) + #error "V_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(V_MAX_PIN, endstop_ISR, CHANGE); + #endif + #if USE_V_MIN + #if !AVAILABLE_EILINE(V_MIN_PIN) + #error "V_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(V_MIN_PIN, endstop_ISR, CHANGE); + #endif + #if USE_W_MAX + #if !AVAILABLE_EILINE(W_MAX_PIN) + #error "W_MAX_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(W_MAX_PIN, endstop_ISR, CHANGE); + #endif + #if USE_W_MIN + #if !AVAILABLE_EILINE(W_MIN_PIN) + #error "W_MIN_PIN has no EXTINT line available. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + attachInterrupt(W_MIN_PIN, endstop_ISR, CHANGE); + #endif } diff --git a/Marlin/src/HAL/SAMD51/fastio.h b/Marlin/src/HAL/SAMD51/fastio.h index 79aede57..1a67b6ce 100644 --- a/Marlin/src/HAL/SAMD51/fastio.h +++ b/Marlin/src/HAL/SAMD51/fastio.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +21,10 @@ */ #pragma once +/** + * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + */ + /** * Fast IO functions for SAMD51 */ @@ -125,7 +130,7 @@ #ifdef ADAFRUIT_GRAND_CENTRAL_M4 - /* + /** * Adafruit Grand Central M4 has a lot of PWMs the availables are listed here. * Some of these share the same source and so can't be used in the same time */ @@ -169,9 +174,9 @@ : (P == 17) ? PIN_TO_SAMD_PIN(13) \ : PIN_TO_SAMD_PIN(9)) - #define digitalPinToAnalogInput(P) (WITHIN(P, 67, 74) ? (P) - 67 : WITHIN(P, 54, 61) ? 8 + (P) - 54 : WITHIN(P, 12, 13) ? 16 + (P) - 12 : P == 9 ? 18 : -1) + #define digitalPinToAnalogIndex(P) (WITHIN(P, 67, 74) ? (P) - 67 : WITHIN(P, 54, 61) ? 8 + (P) - 54 : WITHIN(P, 12, 13) ? 16 + (P) - 12 : P == 9 ? 18 : -1) - /* + /** * pins */ diff --git a/Marlin/src/HAL/SAMD51/inc/Conditionals_LCD.h b/Marlin/src/HAL/SAMD51/inc/Conditionals_LCD.h index 932348c5..5f1c4b16 100644 --- a/Marlin/src/HAL/SAMD51/inc/Conditionals_LCD.h +++ b/Marlin/src/HAL/SAMD51/inc/Conditionals_LCD.h @@ -20,7 +20,3 @@ * */ #pragma once - -#if HAS_SPI_TFT || HAS_FSMC_TFT - #error "Sorry! TFT displays are not available for HAL/SAMD51." -#endif diff --git a/Marlin/src/HAL/SAMD51/inc/Conditionals_post.h b/Marlin/src/HAL/SAMD51/inc/Conditionals_post.h index ce6d3fdd..295596b7 100644 --- a/Marlin/src/HAL/SAMD51/inc/Conditionals_post.h +++ b/Marlin/src/HAL/SAMD51/inc/Conditionals_post.h @@ -23,6 +23,6 @@ #if USE_FALLBACK_EEPROM #define FLASH_EEPROM_EMULATION -#elif EITHER(I2C_EEPROM, SPI_EEPROM) +#elif ANY(I2C_EEPROM, SPI_EEPROM) #define USE_SHARED_EEPROM 1 #endif diff --git a/Marlin/src/HAL/SAMD51/inc/SanityCheck.h b/Marlin/src/HAL/SAMD51/inc/SanityCheck.h index 1b876c94..4719ac6e 100644 --- a/Marlin/src/HAL/SAMD51/inc/SanityCheck.h +++ b/Marlin/src/HAL/SAMD51/inc/SanityCheck.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,11 +19,20 @@ * along with this program. If not, see . * */ +#pragma once + +/** + * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + */ /** * Test SAMD51 specific configuration values for errors at compile-time. */ +#if HAS_SPI_TFT || HAS_FSMC_TFT + #error "Sorry! TFT displays are not available for HAL/SAMD51." +#endif + #if ENABLED(FLASH_EEPROM_EMULATION) #warning "Did you activate the SmartEEPROM? See https://github.com/GMagician/SAMD51-SmartEEprom-Manager/releases" #endif @@ -44,12 +54,12 @@ #error "EMERGENCY_PARSER is not yet implemented for SAMD51. Disable EMERGENCY_PARSER to continue." #endif -#if ENABLED(SDIO_SUPPORT) - #error "SDIO_SUPPORT is not supported on SAMD51." +#if ENABLED(ONBOARD_SDIO) + #error "ONBOARD_SDIO is not supported on SAMD51." #endif #if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY - #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported on SAMD51." + #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported for HAL/SAMD51." #endif #if ENABLED(POSTMORTEM_DEBUGGING) diff --git a/Marlin/src/HAL/SAMD51/pinsDebug.h b/Marlin/src/HAL/SAMD51/pinsDebug.h index f0a46fd7..1518c615 100644 --- a/Marlin/src/HAL/SAMD51/pinsDebug.h +++ b/Marlin/src/HAL/SAMD51/pinsDebug.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,38 +21,58 @@ */ #pragma once +/** + * Pins Debugging for SAMD51 + * + * - NUMBER_PINS_TOTAL + * - MULTI_NAME_PAD + * - getPinByIndex(index) + * - printPinNameByIndex(index) + * - getPinIsDigitalByIndex(index) + * - digitalPinToAnalogIndex(pin) + * - getValidPinMode(pin) + * - isValidPin(pin) + * - isAnalogPin(pin) + * - digitalRead_mod(pin) + * - pwm_status(pin) + * - printPinPWM(pin) + * - printPinPort(pin) + * - printPinNumber(pin) + * - printPinAnalog(pin) + */ + #define NUMBER_PINS_TOTAL PINS_COUNT -#define digitalRead_mod(p) extDigitalRead(p) -#define PRINT_PORT(p) do{ SERIAL_ECHOPGM(" Port: "); sprintf_P(buffer, PSTR("%c%02ld"), 'A' + g_APinDescription[p].ulPort, g_APinDescription[p].ulPin); SERIAL_ECHO(buffer); }while (0) -#define PRINT_ARRAY_NAME(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) -#define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%3d "), p); SERIAL_ECHO(buffer); }while(0) -#define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0) -#define GET_ARRAY_PIN(p) pin_array[p].pin -#define GET_ARRAY_IS_DIGITAL(p) pin_array[p].is_digital -#define VALID_PIN(pin) (pin >= 0 && pin < (int8_t)NUMBER_PINS_TOTAL) -#define DIGITAL_PIN_TO_ANALOG_PIN(p) digitalPinToAnalogInput(p) -#define IS_ANALOG(P) (DIGITAL_PIN_TO_ANALOG_PIN(P)!=-1) -#define pwm_status(pin) digitalPinHasPWM(pin) +#define digitalRead_mod(P) extDigitalRead(P) +#define printPinNameByIndex(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) +#define printPinNumber(P) do{ sprintf_P(buffer, PSTR("%3d "), P); SERIAL_ECHO(buffer); }while(0) +#define printPinAnalog(P) do{ sprintf_P(buffer, PSTR(" (A%2d) "), digitalPinToAnalogIndex(P)); SERIAL_ECHO(buffer); }while(0) +#define getPinByIndex(x) pin_array[x].pin +#define getPinIsDigitalByIndex(x) pin_array[x].is_digital +#define isValidPin(P) (P >= 0 && P < pin_t(NUMBER_PINS_TOTAL)) +#define isAnalogPin(P) (digitalPinToAnalogIndex(P) != -1) +#define pwm_status(P) digitalPinHasPWM(P) #define MULTI_NAME_PAD 27 // space needed to be pretty if not first name assigned to a pin // pins that will cause hang/reset/disconnect in M43 Toggle and Watch utilities // uses pin index #define M43_NEVER_TOUCH(Q) ((Q) >= 75) -bool GET_PINMODE(int8_t pin) { // 1: output, 0: input +bool getValidPinMode(const int8_t pin) { // 1: output, 0: input const EPortType samdport = g_APinDescription[pin].ulPort; const uint32_t samdpin = g_APinDescription[pin].ulPin; return PORT->Group[samdport].DIR.reg & MASK(samdpin) || (PORT->Group[samdport].PINCFG[samdpin].reg & (PORT_PINCFG_INEN | PORT_PINCFG_PULLEN)) == PORT_PINCFG_PULLEN; } -void pwm_details(int32_t pin) { +void printPinPWM(const int32_t pin) { if (pwm_status(pin)) { //uint32_t chan = g_APinDescription[pin].ulPWMChannel TODO when fast pwm is operative; //SERIAL_ECHOPGM("PWM = ", duty); } } +void printPinPort(const pin_t) {} + /** * AGCM4 Board pin | PORT | Label * ----------------+--------+------- diff --git a/Marlin/src/HAL/SAMD51/spi_pins.h b/Marlin/src/HAL/SAMD51/spi_pins.h index 2a667bca..2c7cbeb9 100644 --- a/Marlin/src/HAL/SAMD51/spi_pins.h +++ b/Marlin/src/HAL/SAMD51/spi_pins.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,9 +21,13 @@ */ #pragma once +/** + * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + */ + #ifdef ADAFRUIT_GRAND_CENTRAL_M4 - /* + /** * AGCM4 Default SPI Pins * * SS SCK MISO MOSI diff --git a/Marlin/src/HAL/SAMD51/timers.cpp b/Marlin/src/HAL/SAMD51/timers.cpp index ce13dd23..7a211eb3 100644 --- a/Marlin/src/HAL/SAMD51/timers.cpp +++ b/Marlin/src/HAL/SAMD51/timers.cpp @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,6 +19,10 @@ * along with this program. If not, see . * */ + +/** + * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + */ #ifdef __SAMD51__ // -------------------------------------------------------------------------- @@ -79,7 +84,7 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) { rtc->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP0; // RTC clock setup - OSC32KCTRL->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL_XOSC32K; // External 32.768KHz oscillator + OSC32KCTRL->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL_XOSC32K; // External 32.768kHz oscillator // Stop timer, just in case, to be able to reconfigure it rtc->MODE0.CTRLA.bit.ENABLE = false; diff --git a/Marlin/src/HAL/SAMD51/timers.h b/Marlin/src/HAL/SAMD51/timers.h index 86e980c5..86c32418 100644 --- a/Marlin/src/HAL/SAMD51/timers.h +++ b/Marlin/src/HAL/SAMD51/timers.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +21,10 @@ */ #pragma once +/** + * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) + */ + #include // -------------------------------------------------------------------------- diff --git a/Marlin/src/HAL/SAMD51/watchdog.cpp b/Marlin/src/HAL/SAMD51/watchdog.cpp deleted file mode 100644 index 9de45183..00000000 --- a/Marlin/src/HAL/SAMD51/watchdog.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -#ifdef __SAMD51__ - -#include "../../inc/MarlinConfig.h" - -#if ENABLED(USE_WATCHDOG) - -#include "watchdog.h" - -#define WDT_TIMEOUT_REG TERN(WATCHDOG_DURATION_8S, WDT_CONFIG_PER_CYC8192, WDT_CONFIG_PER_CYC4096) // 4 or 8 second timeout - -void watchdog_init() { - // The low-power oscillator used by the WDT runs at 32,768 Hz with - // a 1:32 prescale, thus 1024 Hz, though probably not super precise. - - // Setup WDT clocks - MCLK->APBAMASK.bit.OSC32KCTRL_ = true; - MCLK->APBAMASK.bit.WDT_ = true; - OSC32KCTRL->OSCULP32K.bit.EN1K = true; // Enable out 1K (this is what WDT uses) - - WDT->CTRLA.bit.ENABLE = false; // Disable watchdog for config - SYNC(WDT->SYNCBUSY.bit.ENABLE); - - WDT->INTENCLR.reg = WDT_INTENCLR_EW; // Disable early warning interrupt - WDT->CONFIG.reg = WDT_TIMEOUT_REG; // Set a 4s or 8s period for chip reset - - HAL_watchdog_refresh(); - - WDT->CTRLA.reg = WDT_CTRLA_ENABLE; // Start watchdog now in normal mode - SYNC(WDT->SYNCBUSY.bit.ENABLE); -} - -#endif // USE_WATCHDOG - -#endif // __SAMD51__ diff --git a/Marlin/src/HAL/SAMD51/watchdog.h b/Marlin/src/HAL/SAMD51/watchdog.h deleted file mode 100644 index 2cd47882..00000000 --- a/Marlin/src/HAL/SAMD51/watchdog.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -#pragma once - -// Initialize watchdog with a 4 second interrupt time -void watchdog_init(); - -// Reset watchdog. MUST be called at least every 4 seconds after the -// first watchdog_init or SAMD will go into emergency procedures. -inline void HAL_watchdog_refresh() { - SYNC(WDT->SYNCBUSY.bit.CLEAR); // Test first if previous is 'ongoing' to save time waiting for command execution - WDT->CLEAR.reg = WDT_CLEAR_CLEAR_KEY; -} diff --git a/Marlin/src/HAL/STM32/HAL.cpp b/Marlin/src/HAL/STM32/HAL.cpp index 0920a72e..610bd0b2 100644 --- a/Marlin/src/HAL/STM32/HAL.cpp +++ b/Marlin/src/HAL/STM32/HAL.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2017 Victor Perez + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,14 +23,13 @@ #ifdef HAL_STM32 -#include "HAL.h" -#include "usb_serial.h" - #include "../../inc/MarlinConfig.h" #include "../shared/Delay.h" +#include "usb_serial.h" + #ifdef USBCON - DefaultSerial1 MSerial0(false, SerialUSB); + DefaultSerial1 MSerialUSB(false, SerialUSB); #endif #if ENABLED(SRAM_EEPROM_EMULATION) @@ -53,23 +51,25 @@ // Public Variables // ------------------------ -uint16_t HAL_adc_result; +uint16_t MarlinHAL::adc_result; // ------------------------ // Public functions // ------------------------ -TERN_(POSTMORTEM_DEBUGGING, extern void install_min_serial()); +#if ENABLED(POSTMORTEM_DEBUGGING) + extern void install_min_serial(); +#endif // HAL initialization task -void HAL_init() { +void MarlinHAL::init() { // Ensure F_CPU is a constant expression. // If the compiler breaks here, it means that delay code that should compute at compile time will not work. // So better safe than sorry here. constexpr int cpuFreq = F_CPU; UNUSED(cpuFreq); - #if ENABLED(SDSUPPORT) && DISABLED(SDIO_SUPPORT) && (defined(SDSS) && SDSS != -1) + #if HAS_MEDIA && DISABLED(ONBOARD_SDIO) && (defined(SDSS) && SDSS != -1) OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up #endif @@ -87,7 +87,7 @@ void HAL_init() { SetTimerInterruptPriorities(); - #if ENABLED(EMERGENCY_PARSER) && USBD_USE_CDC + #if ENABLED(EMERGENCY_PARSER) && (USBD_USE_CDC || USBD_USE_CDC_MSC) USB_Hook_init(); #endif @@ -103,7 +103,7 @@ void HAL_init() { } // HAL idle task -void HAL_idletask() { +void MarlinHAL::idletask() { #if HAS_SHARED_MEDIA // Stm32duino currently doesn't have a "loop/idle" method CDC_resume_receive(); @@ -111,9 +111,9 @@ void HAL_idletask() { #endif } -void HAL_clear_reset_source() { __HAL_RCC_CLEAR_RESET_FLAGS(); } +void MarlinHAL::reboot() { NVIC_SystemReset(); } -uint8_t HAL_get_reset_source() { +uint8_t MarlinHAL::get_reset_source() { return #ifdef RCC_FLAG_IWDGRST // Some sources may not exist... RESET != __HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST) ? RST_WATCHDOG : @@ -137,24 +137,37 @@ uint8_t HAL_get_reset_source() { ; } -void HAL_reboot() { NVIC_SystemReset(); } +void MarlinHAL::clear_reset_source() { __HAL_RCC_CLEAR_RESET_FLAGS(); } + +// ------------------------ +// Watchdog Timer +// ------------------------ + +#if ENABLED(USE_WATCHDOG) -void _delay_ms(const int delay_ms) { delay(delay_ms); } + #define WDT_TIMEOUT_US TERN(WATCHDOG_DURATION_8S, 8000000, 4000000) // 4 or 8 second timeout + + #include + + void MarlinHAL::watchdog_init() { + IF_DISABLED(DISABLE_WATCHDOG_INIT, IWatchdog.begin(WDT_TIMEOUT_US)); + } + + void MarlinHAL::watchdog_refresh() { + IWatchdog.reload(); + #if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED) + TOGGLE(LED_PIN); // heartbeat indicator + #endif + } + +#endif extern "C" { extern unsigned int _ebss; // end of bss section } -// ------------------------ -// ADC -// ------------------------ - -// TODO: Make sure this doesn't cause any delay -void HAL_adc_start_conversion(const uint8_t adc_pin) { HAL_adc_result = analogRead(adc_pin); } -uint16_t HAL_adc_get_result() { return HAL_adc_result; } - // Reset the system to initiate a firmware flash -WEAK void flashFirmware(const int16_t) { HAL_reboot(); } +WEAK void flashFirmware(const int16_t) { hal.reboot(); } // Maple Compatibility volatile uint32_t systick_uptime_millis = 0; diff --git a/Marlin/src/HAL/STM32/HAL.h b/Marlin/src/HAL/STM32/HAL.h index adaf1422..d6e9bc9a 100644 --- a/Marlin/src/HAL/STM32/HAL.h +++ b/Marlin/src/HAL/STM32/HAL.h @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2017 Victor Perez + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +29,6 @@ #include "../shared/HAL_SPI.h" #include "fastio.h" #include "Servo.h" -#include "watchdog.h" #include "MarlinSerial.h" #include "../../inc/MarlinConfigPre.h" @@ -44,67 +42,77 @@ #define CPU_ST7920_DELAY_2 40 #define CPU_ST7920_DELAY_3 340 -// -// Serial Ports -// +// ------------------------ +// Serial ports +// ------------------------ #ifdef USBCON #include #include "../../core/serial_hook.h" typedef ForwardSerial1Class< decltype(SerialUSB) > DefaultSerial1; - extern DefaultSerial1 MSerial0; + extern DefaultSerial1 MSerialUSB; #endif #define _MSERIAL(X) MSerial##X #define MSERIAL(X) _MSERIAL(X) -#if SERIAL_PORT == -1 - #define MYSERIAL1 MSerial0 -#elif WITHIN(SERIAL_PORT, 1, 6) +#if WITHIN(SERIAL_PORT, 1, 9) #define MYSERIAL1 MSERIAL(SERIAL_PORT) +#elif !defined(USBCON) + #error "SERIAL_PORT must be from 1 to 9." +#elif SERIAL_PORT == -1 + #define MYSERIAL1 MSerialUSB #else - #error "SERIAL_PORT must be from 1 to 6. You can also use -1 if the board supports Native USB." + #error "SERIAL_PORT must be from 1 to 9, or -1 for Native USB." #endif #ifdef SERIAL_PORT_2 - #if SERIAL_PORT_2 == -1 - #define MYSERIAL2 MSerial0 - #elif WITHIN(SERIAL_PORT_2, 1, 6) + #if WITHIN(SERIAL_PORT_2, 1, 9) #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) + #elif !defined(USBCON) + #error "SERIAL_PORT_2 must be from 1 to 9." + #elif SERIAL_PORT_2 == -1 + #define MYSERIAL2 MSerialUSB #else - #error "SERIAL_PORT_2 must be from 1 to 6. You can also use -1 if the board supports Native USB." + #error "SERIAL_PORT_2 must be from 1 to 9, or -1 for Native USB." #endif #endif #ifdef SERIAL_PORT_3 - #if SERIAL_PORT_3 == -1 - #define MYSERIAL3 MSerial0 - #elif WITHIN(SERIAL_PORT_3, 1, 6) + #if WITHIN(SERIAL_PORT_3, 1, 9) #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) + #elif !defined(USBCON) + #error "SERIAL_PORT_3 must be from 1 to 9." + #elif SERIAL_PORT_3 == -1 + #define MYSERIAL3 MSerialUSB #else - #error "SERIAL_PORT_3 must be from 1 to 6. You can also use -1 if the board supports Native USB." + #error "SERIAL_PORT_3 must be from 1 to 9, or -1 for Native USB." #endif #endif #ifdef MMU2_SERIAL_PORT - #if MMU2_SERIAL_PORT == -1 - #define MMU2_SERIAL MSerial0 - #elif WITHIN(MMU2_SERIAL_PORT, 1, 6) + #if WITHIN(MMU2_SERIAL_PORT, 1, 9) #define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT) + #elif !defined(USBCON) + #error "MMU2_SERIAL_PORT must be from 1 to 9." + #elif MMU2_SERIAL_PORT == -1 + #define MMU2_SERIAL MSerialUSB #else - #error "MMU2_SERIAL_PORT must be from 1 to 6. You can also use -1 if the board supports Native USB." + #error "MMU2_SERIAL_PORT must be from 1 to 9, or -1 for Native USB." #endif #endif #ifdef LCD_SERIAL_PORT - #if LCD_SERIAL_PORT == -1 - #define LCD_SERIAL MSerial0 - #elif WITHIN(LCD_SERIAL_PORT, 1, 6) + #if WITHIN(LCD_SERIAL_PORT, 1, 9) #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) + #elif !defined(USBCON) + #error "LCD_SERIAL_PORT must be from 1 to 9." + #elif LCD_SERIAL_PORT == -1 + #define LCD_SERIAL MSerialUSB #else - #error "LCD_SERIAL_PORT must be from 1 to 6. You can also use -1 if the board supports Native USB." + #error "LCD_SERIAL_PORT must be from 1 to 9, or -1 for Native USB." #endif #if HAS_DGUS_LCD - #define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() + #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() #endif #endif @@ -112,67 +120,82 @@ * TODO: review this to return 1 for pins that are not analog input */ #ifndef analogInputToDigitalPin - #define analogInputToDigitalPin(p) (p) + #define analogInputToDigitalPin(p) pin_t(p) #endif -#define CRITICAL_SECTION_START() uint32_t primask = __get_PRIMASK(); __disable_irq() -#define CRITICAL_SECTION_END() if (!primask) __enable_irq() -#define ISRS_ENABLED() (!__get_PRIMASK()) -#define ENABLE_ISRS() __enable_irq() -#define DISABLE_ISRS() __disable_irq() +// +// Interrupts +// +#define CRITICAL_SECTION_START() const bool irqon = !__get_PRIMASK(); __disable_irq() +#define CRITICAL_SECTION_END() if (irqon) __enable_irq() #define cli() __disable_irq() #define sei() __enable_irq() -// On AVR this is in math.h? -#define square(x) ((x)*(x)) - // ------------------------ // Types // ------------------------ -#ifdef STM32G0B1xx - typedef int32_t pin_t; -#else - typedef int16_t pin_t; -#endif +typedef double isr_float_t; // FPU ops are used for single-precision, so use double for ISRs. -#define HAL_SERVO_LIB libServo +typedef int32_t pin_t; // Parity with platform/ststm32 + +class libServo; +typedef libServo hal_servo_t; #define PAUSE_SERVO_OUTPUT() libServo::pause_all_servos() #define RESUME_SERVO_OUTPUT() libServo::resume_all_servos() // ------------------------ -// Public Variables +// ADC // ------------------------ -// result of last ADC conversion -extern uint16_t HAL_adc_result; +#ifdef ADC_RESOLUTION + #define HAL_ADC_RESOLUTION ADC_RESOLUTION +#else + #define HAL_ADC_RESOLUTION 12 +#endif -// ------------------------ -// Public functions -// ------------------------ +#define HAL_ADC_VREF_MV 3300 -// Memory related -#define __bss_end __bss_end__ +// +// Pin Mapping for M42, M43, M226 +// +#define GET_PIN_MAP_PIN(index) index +#define GET_PIN_MAP_INDEX(pin) pin +#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval) -// Enable hooks into setup for HAL -void HAL_init(); -#define HAL_IDLETASK 1 -void HAL_idletask(); +#ifdef STM32F1xx + #define JTAG_DISABLE() AFIO_DBGAFR_CONFIG(AFIO_MAPR_SWJ_CFG_JTAGDISABLE) + #define JTAGSWD_DISABLE() AFIO_DBGAFR_CONFIG(AFIO_MAPR_SWJ_CFG_DISABLE) + #define JTAGSWD_RESET() AFIO_DBGAFR_CONFIG(AFIO_MAPR_SWJ_CFG_RESET); // Reset: FULL SWD+JTAG +#endif -// Clear reset reason -void HAL_clear_reset_source(); +#ifndef PLATFORM_M997_SUPPORT + #define PLATFORM_M997_SUPPORT +#endif +void flashFirmware(const int16_t); -// Reset reason -uint8_t HAL_get_reset_source(); +// Maple Compatibility +typedef void (*systickCallback_t)(void); +void systick_attach_callback(systickCallback_t cb); +void HAL_SYSTICK_Callback(); -void HAL_reboot(); +extern volatile uint32_t systick_uptime_millis; -void _delay_ms(const int delay); +#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment + +// ------------------------ +// Class Utilities +// ------------------------ + +// Memory related +#define __bss_end __bss_end__ extern "C" char* _sbrk(int incr); #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" +#if GCC_VERSION <= 50000 + #pragma GCC diagnostic ignored "-Wunused-function" +#endif static inline int freeMemory() { volatile char top; @@ -181,62 +204,75 @@ static inline int freeMemory() { #pragma GCC diagnostic pop -// -// ADC -// +// ------------------------ +// MarlinHAL Class +// ------------------------ -#define HAL_ANALOG_SELECT(pin) pinMode(pin, INPUT) +class MarlinHAL { +public: -#ifdef ADC_RESOLUTION - #define HAL_ADC_RESOLUTION ADC_RESOLUTION -#else - #define HAL_ADC_RESOLUTION 12 -#endif + // Earliest possible init, before setup() + MarlinHAL() {} -#define HAL_ADC_VREF 3.3 -#define HAL_START_ADC(pin) HAL_adc_start_conversion(pin) -#define HAL_READ_ADC() HAL_adc_result -#define HAL_ADC_READY() true + // Watchdog + static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {}); + static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {}); -inline void HAL_adc_init() { analogReadResolution(HAL_ADC_RESOLUTION); } + static void init(); // Called early in setup() + static void init_board() {} // Called less early in setup() + static void reboot(); // Restart the firmware from 0x0 -void HAL_adc_start_conversion(const uint8_t adc_pin); + // Interrupts + static bool isr_state() { return !__get_PRIMASK(); } + static void isr_on() { sei(); } + static void isr_off() { cli(); } -uint16_t HAL_adc_get_result(); + static void delay_ms(const int ms) { delay(ms); } -#define GET_PIN_MAP_PIN(index) index -#define GET_PIN_MAP_INDEX(pin) pin -#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval) + // Tasks, called from idle() + static void idletask(); -#ifdef STM32F1xx - #define JTAG_DISABLE() AFIO_DBGAFR_CONFIG(AFIO_MAPR_SWJ_CFG_JTAGDISABLE) - #define JTAGSWD_DISABLE() AFIO_DBGAFR_CONFIG(AFIO_MAPR_SWJ_CFG_DISABLE) - #define JTAGSWD_RESET() AFIO_DBGAFR_CONFIG(AFIO_MAPR_SWJ_CFG_RESET); // Reset: FULL SWD+JTAG -#endif + // Reset + static uint8_t get_reset_source(); + static void clear_reset_source(); -#define PLATFORM_M997_SUPPORT -void flashFirmware(const int16_t); + // Free SRAM + static int freeMemory() { return ::freeMemory(); } -// Maple Compatibility -typedef void (*systickCallback_t)(void); -void systick_attach_callback(systickCallback_t cb); -void HAL_SYSTICK_Callback(); + // + // ADC Methods + // -extern volatile uint32_t systick_uptime_millis; + static uint16_t adc_result; -#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment + // Called by Temperature::init once at startup + static void adc_init() { + analogReadResolution(HAL_ADC_RESOLUTION); + } -/** - * set_pwm_frequency - * Set the frequency of the timer corresponding to the provided pin - * All Timer PWM pins run at the same frequency - */ -void set_pwm_frequency(const pin_t pin, int f_desired); + // Called by Temperature::init for each sensor at startup + static void adc_enable(const pin_t pin) { pinMode(pin, INPUT); } -/** - * set_pwm_duty - * Set the PWM duty cycle of the provided pin to the provided value - * Optionally allows inverting the duty cycle [default = false] - * Optionally allows changing the maximum size of the provided value to enable finer PWM duty control [default = 255] - */ -void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false); + // Begin ADC sampling on the given pin. Called from Temperature::isr! + static void adc_start(const pin_t pin) { adc_result = analogRead(pin); } + + // Is the ADC ready for reading? + static bool adc_ready() { return true; } + + // The current value of the ADC register + static uint16_t adc_value() { return adc_result; } + + /** + * Set the PWM duty cycle for the pin to the given value. + * Optionally invert the duty cycle [default = false] + * Optionally change the maximum size of the provided value to enable finer PWM duty control [default = 255] + */ + static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false); + + /** + * Set the frequency of the timer for the given pin. + * All Timer PWM pins run at the same frequency. + */ + static void set_pwm_frequency(const pin_t pin, const uint16_t f_desired); + +}; diff --git a/Marlin/src/HAL/STM32/HAL_SPI.cpp b/Marlin/src/HAL/STM32/HAL_SPI.cpp index 8ee47616..cc035ecf 100644 --- a/Marlin/src/HAL/STM32/HAL_SPI.cpp +++ b/Marlin/src/HAL/STM32/HAL_SPI.cpp @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -78,7 +77,6 @@ static SPISettings spiConfig; case SPI_SPEED_6: delaySPIFunc = &delaySPI_2000; break; // desired: 250,000 actual: ~210K default: delaySPIFunc = &delaySPI_4000; break; // desired: 125,000 actual: ~123K } - SPI.begin(); } // Begin SPI transaction, set clock, bit order, data mode @@ -102,9 +100,9 @@ static SPISettings spiConfig; // Soft SPI receive byte uint8_t spiRec() { - DISABLE_ISRS(); // No interrupts during byte receive + hal.isr_off(); // No interrupts during byte receive const uint8_t data = HAL_SPI_STM32_SpiTransfer_Mode_3(0xFF); - ENABLE_ISRS(); // Enable interrupts + hal.isr_on(); // Enable interrupts return data; } @@ -116,9 +114,9 @@ static SPISettings spiConfig; // Soft SPI send byte void spiSend(uint8_t data) { - DISABLE_ISRS(); // No interrupts during byte send + hal.isr_off(); // No interrupts during byte send HAL_SPI_STM32_SpiTransfer_Mode_3(data); // Don't care what is received - ENABLE_ISRS(); // Enable interrupts + hal.isr_on(); // Enable interrupts } // Soft SPI send block diff --git a/Marlin/src/HAL/STM32/MarlinSerial.cpp b/Marlin/src/HAL/STM32/MarlinSerial.cpp index 37a8f40f..9f0b003a 100644 --- a/Marlin/src/HAL/STM32/MarlinSerial.cpp +++ b/Marlin/src/HAL/STM32/MarlinSerial.cpp @@ -37,6 +37,15 @@ #ifndef USART5 #define USART5 UART5 #endif +#ifndef USART7 + #define USART7 UART7 +#endif +#ifndef USART8 + #define USART8 UART8 +#endif +#ifndef USART9 + #define USART9 UART9 +#endif #define DECLARE_SERIAL_PORT(ser_num) \ void _rx_complete_irq_ ## ser_num (serial_t * obj); \ diff --git a/Marlin/src/HAL/STM32/HAL_MinSerial.cpp b/Marlin/src/HAL/STM32/MinSerial.cpp similarity index 85% rename from Marlin/src/HAL/STM32/HAL_MinSerial.cpp rename to Marlin/src/HAL/STM32/MinSerial.cpp index b6e86b72..a27bc35a 100644 --- a/Marlin/src/HAL/STM32/HAL_MinSerial.cpp +++ b/Marlin/src/HAL/STM32/MinSerial.cpp @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,8 +27,7 @@ #if ENABLED(POSTMORTEM_DEBUGGING) -#include "../shared/HAL_MinSerial.h" -#include "watchdog.h" +#include "../shared/MinSerial.h" /* Instruction Synchronization Barrier */ #define isb() __asm__ __volatile__ ("isb" : : : "memory") @@ -46,7 +44,7 @@ struct USARTMin { volatile uint32_t CR2; }; -#if WITHIN(SERIAL_PORT, 1, 6) +#if WITHIN(SERIAL_PORT, 1, 9) // Depending on the CPU, the serial port is different for USART1 static const uintptr_t regsAddr[] = { TERN(STM32F1xx, 0x40013800, 0x40011000), // USART1 @@ -54,7 +52,10 @@ struct USARTMin { 0x40004800, // USART3 0x40004C00, // UART4_BASE 0x40005000, // UART5_BASE - 0x40011400 // USART6 + 0x40011400, // USART6 + 0x40007800, // UART7_BASE + 0x40007C00, // UART8_BASE + 0x40011800 // UART9_BASE }; static USARTMin * regs = (USARTMin*)regsAddr[SERIAL_PORT - 1]; #endif @@ -117,10 +118,10 @@ static void TXBegin() { // A SW memory barrier, to ensure GCC does not overoptimize loops #define sw_barrier() __asm__ volatile("": : :"memory"); static void TX(char c) { - #if WITHIN(SERIAL_PORT, 1, 6) + #if WITHIN(SERIAL_PORT, 1, 9) constexpr uint32_t usart_sr_txe = _BV(7); while (!(regs->SR & usart_sr_txe)) { - TERN_(USE_WATCHDOG, HAL_watchdog_refresh()); + hal.watchdog_refresh(); sw_barrier(); } regs->DR = c; @@ -136,18 +137,18 @@ void install_min_serial() { } #if NONE(DYNAMIC_VECTORTABLE, STM32F0xx, STM32G0xx) // Cortex M0 can't jump to a symbol that's too far from the current function, so we work around this in exception_arm.cpp -extern "C" { - __attribute__((naked)) void JumpHandler_ASM() { - __asm__ __volatile__ ( - "b CommonHandler_ASM\n" - ); + extern "C" { + __attribute__((naked)) void JumpHandler_ASM() { + __asm__ __volatile__ ( + "b CommonHandler_ASM\n" + ); + } + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) HardFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) BusFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) UsageFault_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) MemManage_Handler(); + void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) NMI_Handler(); } - void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) HardFault_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) BusFault_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) UsageFault_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) MemManage_Handler(); - void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) NMI_Handler(); -} #endif #endif // POSTMORTEM_DEBUGGING diff --git a/Marlin/src/HAL/STM32/Sd2Card_sdio_stm32duino.cpp b/Marlin/src/HAL/STM32/Sd2Card_sdio_stm32duino.cpp deleted file mode 100644 index 54e1820c..00000000 --- a/Marlin/src/HAL/STM32/Sd2Card_sdio_stm32duino.cpp +++ /dev/null @@ -1,326 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * - * Based on Sprinter and grbl. - * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -#include "../platforms.h" - -#ifdef HAL_STM32 - -#include "../../inc/MarlinConfig.h" - -#if ENABLED(SDIO_SUPPORT) - -#include -#include - -// use local drivers -#if defined(STM32F103xE) || defined(STM32F103xG) - #include - #include -#elif defined(STM32F4xx) - #include - #include - #include - #include -#elif defined(STM32F7xx) - #include - #include - #include - #include -#else - #error "SDIO only supported with STM32F103xE, STM32F103xG, STM32F4xx, or STM32F7xx." -#endif - -// Fixed -#define SDIO_D0_PIN PC8 -#define SDIO_D1_PIN PC9 -#define SDIO_D2_PIN PC10 -#define SDIO_D3_PIN PC11 -#define SDIO_CK_PIN PC12 -#define SDIO_CMD_PIN PD2 - -SD_HandleTypeDef hsd; // create SDIO structure -// 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; - -/* - 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 board seems to have stable SDIO with BusWide 1bit and ClockDiv 8 i.e. 4.8MHz SDIO clock frequency - Additional testing is required as there are clearly some 4bit initialization problems -*/ - -#ifndef USBD_OK - #define USBD_OK 0 -#endif - -// Target Clock, configurable. Default is 18MHz, from STM32F1 -#ifndef SDIO_CLOCK - #define SDIO_CLOCK 18000000 // 18 MHz -#endif - -// SDIO retries, configurable. Default is 3, from STM32F1 -#ifndef SDIO_READ_RETRIES - #define SDIO_READ_RETRIES 3 -#endif - -// SDIO Max Clock (naming from STM Manual, don't change) -#define SDIOCLK 48000000 - -static uint32_t clock_to_divider(uint32_t clk) { - // limit the SDIO master clock to 8/3 of PCLK2. See STM32 Manuals - // Also limited to no more than 48Mhz (SDIOCLK). - const uint32_t pclk2 = HAL_RCC_GetPCLK2Freq(); - clk = min(clk, (uint32_t)(pclk2 * 8 / 3)); - clk = min(clk, (uint32_t)SDIOCLK); - // Round up divider, so we don't run the card over the speed supported, - // and subtract by 2, because STM32 will add 2, as written in the manual: - // SDIO_CK frequency = SDIOCLK / [CLKDIV + 2] - return pclk2 / clk + (pclk2 % clk != 0) - 2; -} - -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(void) { - uint32_t tempreg; - - __HAL_RCC_GPIOC_CLK_ENABLE(); //enable GPIO clocks - __HAL_RCC_GPIOD_CLK_ENABLE(); //enable GPIO clocks - - 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 - #if defined(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); - - #if defined(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 - tempreg |= SDIO_CLKCR_CLKEN; // Clock enabled - tempreg |= 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; -} - -void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { // application specific init - UNUSED(hsd); // Prevent unused argument(s) compilation warning - __HAL_RCC_SDIO_CLK_ENABLE(); // turn on SDIO clock -} - -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 (;;) { - TERN_(USE_WATCHDOG, 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 (;;) { - TERN_(USE_WATCHDOG, 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 (;;) { - TERN_(USE_WATCHDOG, 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; -} - -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; - - TERN_(USE_WATCHDOG, 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() + 500; - // 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() + 500; - while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER) if (ELAPSED(millis(), timeout)) return false; - - return true; -} - -bool SDIO_ReadBlock(uint32_t block, uint8_t *dst) { - uint8_t retries = SDIO_READ_RETRIES; - while (retries--) if (SDIO_ReadWriteBlock_DMA(block, nullptr, dst)) return true; - return false; -} - -bool SDIO_WriteBlock(uint32_t block, const uint8_t *src) { - uint8_t retries = SDIO_READ_RETRIES; - while (retries--) if (SDIO_ReadWriteBlock_DMA(block, src, nullptr)) return true; - return false; -} - -bool SDIO_IsReady() { - return hsd.State == HAL_SD_STATE_READY; -} - -uint32_t SDIO_GetCardSize() { - return (uint32_t)(hsd.SdCard.BlockNbr) * (hsd.SdCard.BlockSize); -} - -#if defined(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); } - -#endif // SDIO_SUPPORT -#endif // HAL_STM32 diff --git a/Marlin/src/HAL/STM32/Servo.cpp b/Marlin/src/HAL/STM32/Servo.cpp index a00186e0..4f026ffc 100644 --- a/Marlin/src/HAL/STM32/Servo.cpp +++ b/Marlin/src/HAL/STM32/Servo.cpp @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Marlin/src/HAL/STM32/Servo.h b/Marlin/src/HAL/STM32/Servo.h index 1527e753..95ecb5d9 100644 --- a/Marlin/src/HAL/STM32/Servo.h +++ b/Marlin/src/HAL/STM32/Servo.h @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Marlin/src/HAL/STM32/eeprom_flash.cpp b/Marlin/src/HAL/STM32/eeprom_flash.cpp index 252b0573..69511c6d 100644 --- a/Marlin/src/HAL/STM32/eeprom_flash.cpp +++ b/Marlin/src/HAL/STM32/eeprom_flash.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2016 Victor Perez victor_pv@hotmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -95,7 +94,7 @@ static_assert(IS_FLASH_SECTOR(FLASH_SECTOR), "FLASH_SECTOR is invalid"); static_assert(IS_POWER_OF_2(FLASH_UNIT_SIZE), "FLASH_UNIT_SIZE should be a power of 2, please check your chip's spec sheet"); -#endif +#endif // FLASH_EEPROM_LEVELING static bool eeprom_data_written = false; @@ -174,9 +173,9 @@ bool PersistentStore::access_finish() { UNLOCK_FLASH(); TERN_(HAS_PAUSE_SERVO_OUTPUT, PAUSE_SERVO_OUTPUT()); - DISABLE_ISRS(); + hal.isr_off(); status = HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError); - ENABLE_ISRS(); + hal.isr_on(); TERN_(HAS_PAUSE_SERVO_OUTPUT, RESUME_SERVO_OUTPUT()); if (status != HAL_OK) { DEBUG_ECHOLNPGM("HAL_FLASHEx_Erase=", status); @@ -189,15 +188,15 @@ bool PersistentStore::access_finish() { UNLOCK_FLASH(); - uint32_t offset = 0; - uint32_t address = SLOT_ADDRESS(current_slot); - uint32_t address_end = address + MARLIN_EEPROM_SIZE; - uint32_t data = 0; + uint32_t offset = 0, + address = SLOT_ADDRESS(current_slot), + address_end = address + MARLIN_EEPROM_SIZE, + data = 0; bool success = true; while (address < address_end) { - memcpy(&data, ram_eeprom + offset, sizeof(uint32_t)); + memcpy(&data, ram_eeprom + offset, sizeof(data)); status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, data); if (status == HAL_OK) { address += sizeof(uint32_t); @@ -221,7 +220,8 @@ bool PersistentStore::access_finish() { return success; - #else + #else // !FLASH_EEPROM_LEVELING + // The following was written for the STM32F4 but may work with other MCUs as well. // Most STM32F4 flash does not allow reading from flash during erase operations. // This takes about a second on a STM32F407 with a 128kB sector used as EEPROM. @@ -229,13 +229,14 @@ bool PersistentStore::access_finish() { // output. Servo output still glitches with interrupts disabled, but recovers after the // erase. TERN_(HAS_PAUSE_SERVO_OUTPUT, PAUSE_SERVO_OUTPUT()); - DISABLE_ISRS(); + hal.isr_off(); eeprom_buffer_flush(); - ENABLE_ISRS(); + hal.isr_on(); TERN_(HAS_PAUSE_SERVO_OUTPUT, RESUME_SERVO_OUTPUT()); eeprom_data_written = false; - #endif + + #endif // !FLASH_EEPROM_LEVELING } return true; diff --git a/Marlin/src/HAL/STM32/eeprom_sdcard.cpp b/Marlin/src/HAL/STM32/eeprom_sdcard.cpp index 473b656f..1b5c0ae5 100644 --- a/Marlin/src/HAL/STM32/eeprom_sdcard.cpp +++ b/Marlin/src/HAL/STM32/eeprom_sdcard.cpp @@ -48,7 +48,7 @@ static char _ALIGN(4) HAL_eeprom_data[MARLIN_EEPROM_SIZE]; bool PersistentStore::access_start() { if (!card.isMounted()) return false; - SdFile file, root = card.getroot(); + MediaFile file, root = card.getroot(); if (!file.open(&root, EEPROM_FILENAME, O_RDONLY)) return true; @@ -63,7 +63,7 @@ bool PersistentStore::access_start() { bool PersistentStore::access_finish() { if (!card.isMounted()) return false; - SdFile file, root = card.getroot(); + MediaFile file, root = card.getroot(); int bytes_written = 0; if (file.open(&root, EEPROM_FILENAME, O_CREAT | O_WRITE | O_TRUNC)) { bytes_written = file.write(HAL_eeprom_data, MARLIN_EEPROM_SIZE); diff --git a/Marlin/src/HAL/STM32/eeprom_sram.cpp b/Marlin/src/HAL/STM32/eeprom_sram.cpp index 687e7f55..9bd84ff4 100644 --- a/Marlin/src/HAL/STM32/eeprom_sram.cpp +++ b/Marlin/src/HAL/STM32/eeprom_sram.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2016 Victor Perez victor_pv@hotmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Marlin/src/HAL/STM32/eeprom_wired.cpp b/Marlin/src/HAL/STM32/eeprom_wired.cpp index cf046815..6fb9d9b5 100644 --- a/Marlin/src/HAL/STM32/eeprom_wired.cpp +++ b/Marlin/src/HAL/STM32/eeprom_wired.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2016 Victor Perez victor_pv@hotmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Marlin/src/HAL/STM32/endstop_interrupts.h b/Marlin/src/HAL/STM32/endstop_interrupts.h index 90870881..c7414f95 100644 --- a/Marlin/src/HAL/STM32/endstop_interrupts.h +++ b/Marlin/src/HAL/STM32/endstop_interrupts.h @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,27 +28,33 @@ void endstop_ISR() { endstops.update(); } void setup_endstop_interrupts() { #define _ATTACH(P) attachInterrupt(P, endstop_ISR, CHANGE) - TERN_(HAS_X_MAX, _ATTACH(X_MAX_PIN)); - TERN_(HAS_X_MIN, _ATTACH(X_MIN_PIN)); - TERN_(HAS_Y_MAX, _ATTACH(Y_MAX_PIN)); - TERN_(HAS_Y_MIN, _ATTACH(Y_MIN_PIN)); - TERN_(HAS_Z_MAX, _ATTACH(Z_MAX_PIN)); - TERN_(HAS_Z_MIN, _ATTACH(Z_MIN_PIN)); - TERN_(HAS_X2_MAX, _ATTACH(X2_MAX_PIN)); - TERN_(HAS_X2_MIN, _ATTACH(X2_MIN_PIN)); - TERN_(HAS_Y2_MAX, _ATTACH(Y2_MAX_PIN)); - TERN_(HAS_Y2_MIN, _ATTACH(Y2_MIN_PIN)); - TERN_(HAS_Z2_MAX, _ATTACH(Z2_MAX_PIN)); - TERN_(HAS_Z2_MIN, _ATTACH(Z2_MIN_PIN)); - TERN_(HAS_Z3_MAX, _ATTACH(Z3_MAX_PIN)); - TERN_(HAS_Z3_MIN, _ATTACH(Z3_MIN_PIN)); - TERN_(HAS_Z4_MAX, _ATTACH(Z4_MAX_PIN)); - TERN_(HAS_Z4_MIN, _ATTACH(Z4_MIN_PIN)); + TERN_(USE_X_MAX, _ATTACH(X_MAX_PIN)); + TERN_(USE_X_MIN, _ATTACH(X_MIN_PIN)); + TERN_(USE_Y_MAX, _ATTACH(Y_MAX_PIN)); + TERN_(USE_Y_MIN, _ATTACH(Y_MIN_PIN)); + TERN_(USE_Z_MAX, _ATTACH(Z_MAX_PIN)); + TERN_(USE_Z_MIN, _ATTACH(Z_MIN_PIN)); + TERN_(USE_X2_MAX, _ATTACH(X2_MAX_PIN)); + TERN_(USE_X2_MIN, _ATTACH(X2_MIN_PIN)); + TERN_(USE_Y2_MAX, _ATTACH(Y2_MAX_PIN)); + TERN_(USE_Y2_MIN, _ATTACH(Y2_MIN_PIN)); + TERN_(USE_Z2_MAX, _ATTACH(Z2_MAX_PIN)); + TERN_(USE_Z2_MIN, _ATTACH(Z2_MIN_PIN)); + TERN_(USE_Z3_MAX, _ATTACH(Z3_MAX_PIN)); + TERN_(USE_Z3_MIN, _ATTACH(Z3_MIN_PIN)); + TERN_(USE_Z4_MAX, _ATTACH(Z4_MAX_PIN)); + TERN_(USE_Z4_MIN, _ATTACH(Z4_MIN_PIN)); TERN_(HAS_Z_MIN_PROBE_PIN, _ATTACH(Z_MIN_PROBE_PIN)); - TERN_(HAS_I_MAX, _ATTACH(I_MAX_PIN)); - TERN_(HAS_I_MIN, _ATTACH(I_MIN_PIN)); - TERN_(HAS_J_MAX, _ATTACH(J_MAX_PIN)); - TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN)); - TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN)); - TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_I_MAX, _ATTACH(I_MAX_PIN)); + TERN_(USE_I_MIN, _ATTACH(I_MIN_PIN)); + TERN_(USE_J_MAX, _ATTACH(J_MAX_PIN)); + TERN_(USE_J_MIN, _ATTACH(J_MIN_PIN)); + TERN_(USE_K_MAX, _ATTACH(K_MAX_PIN)); + TERN_(USE_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(USE_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(USE_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(USE_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(USE_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(USE_W_MIN, _ATTACH(W_MIN_PIN)); } diff --git a/Marlin/src/HAL/STM32/fast_pwm.cpp b/Marlin/src/HAL/STM32/fast_pwm.cpp index b1bea5ce..a0d8ecc6 100644 --- a/Marlin/src/HAL/STM32/fast_pwm.cpp +++ b/Marlin/src/HAL/STM32/fast_pwm.cpp @@ -29,34 +29,39 @@ // Array to support sticky frequency sets per timer static uint16_t timer_freq[TIMER_NUM]; -void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) { - if (!PWM_PIN(pin)) return; // Don't proceed if no hardware timer - const PinName pin_name = digitalPinToPinName(pin); - TIM_TypeDef * const Instance = (TIM_TypeDef *)pinmap_peripheral(pin_name, PinMap_PWM); +void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) { + const uint16_t duty = invert ? v_size - v : v; + if (PWM_PIN(pin)) { + const PinName pin_name = digitalPinToPinName(pin); + TIM_TypeDef * const Instance = (TIM_TypeDef *)pinmap_peripheral(pin_name, PinMap_PWM); - const timer_index_t index = get_timer_index(Instance); - const bool needs_freq = (HardwareTimer_Handle[index] == nullptr); - if (needs_freq) // A new instance must be set to the default frequency of PWM_FREQUENCY - HardwareTimer_Handle[index]->__this = new HardwareTimer((TIM_TypeDef *)pinmap_peripheral(pin_name, PinMap_PWM)); + const timer_index_t index = get_timer_index(Instance); + const bool needs_freq = (HardwareTimer_Handle[index] == nullptr); + if (needs_freq) // A new instance must be set to the default frequency of PWM_FREQUENCY + HardwareTimer_Handle[index]->__this = new HardwareTimer((TIM_TypeDef *)pinmap_peripheral(pin_name, PinMap_PWM)); - HardwareTimer * const HT = (HardwareTimer *)(HardwareTimer_Handle[index]->__this); - const uint32_t channel = STM_PIN_CHANNEL(pinmap_function(pin_name, PinMap_PWM)); - const TimerModes_t previousMode = HT->getMode(channel); - if (previousMode != TIMER_OUTPUT_COMPARE_PWM1) - HT->setMode(channel, TIMER_OUTPUT_COMPARE_PWM1, pin); + HardwareTimer * const HT = (HardwareTimer *)(HardwareTimer_Handle[index]->__this); + const uint32_t channel = STM_PIN_CHANNEL(pinmap_function(pin_name, PinMap_PWM)); + const TimerModes_t previousMode = HT->getMode(channel); + if (previousMode != TIMER_OUTPUT_COMPARE_PWM1) + HT->setMode(channel, TIMER_OUTPUT_COMPARE_PWM1, pin); - if (needs_freq && timer_freq[index] == 0) // If the timer is unconfigured and no freq is set then default PWM_FREQUENCY - set_pwm_frequency(pin_name, PWM_FREQUENCY); // Set the frequency and save the value to the assigned index no. + if (needs_freq && timer_freq[index] == 0) // If the timer is unconfigured and no freq is set then default PWM_FREQUENCY + set_pwm_frequency(pin_name, PWM_FREQUENCY); // Set the frequency and save the value to the assigned index no. - // Note the resolution is sticky here, the input can be upto 16 bits and that would require RESOLUTION_16B_COMPARE_FORMAT (16) - // If such a need were to manifest then we would need to calc the resolution based on the v_size parameter and add code for it. - const uint16_t value = invert ? v_size - v : v; - HT->setCaptureCompare(channel, value, RESOLUTION_8B_COMPARE_FORMAT); // Sets the duty, the calc is done in the library :) - pinmap_pinout(pin_name, PinMap_PWM); // Make sure the pin output state is set. - if (previousMode != TIMER_OUTPUT_COMPARE_PWM1) HT->resume(); + // Note the resolution is sticky here, the input can be upto 16 bits and that would require RESOLUTION_16B_COMPARE_FORMAT (16) + // If such a need were to manifest then we would need to calc the resolution based on the v_size parameter and add code for it. + HT->setCaptureCompare(channel, duty, RESOLUTION_8B_COMPARE_FORMAT); // Set the duty, the calc is done in the library :) + pinmap_pinout(pin_name, PinMap_PWM); // Make sure the pin output state is set. + if (previousMode != TIMER_OUTPUT_COMPARE_PWM1) HT->resume(); + } + else { + pinMode(pin, OUTPUT); + digitalWrite(pin, duty < v_size / 2 ? LOW : HIGH); + } } -void set_pwm_frequency(const pin_t pin, int f_desired) { +void MarlinHAL::set_pwm_frequency(const pin_t pin, const uint16_t f_desired) { if (!PWM_PIN(pin)) return; // Don't proceed if no hardware timer const PinName pin_name = digitalPinToPinName(pin); TIM_TypeDef * const Instance = (TIM_TypeDef *)pinmap_peripheral(pin_name, PinMap_PWM); // Get HAL timer instance diff --git a/Marlin/src/HAL/STM32/fastio.cpp b/Marlin/src/HAL/STM32/fastio.cpp index b34555b8..f8501545 100644 --- a/Marlin/src/HAL/STM32/fastio.cpp +++ b/Marlin/src/HAL/STM32/fastio.cpp @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,7 +28,7 @@ GPIO_TypeDef* FastIOPortMap[LastPort + 1] = { 0 }; void FastIO_init() { - LOOP_L_N(i, NUM_DIGITAL_PINS) + for (uint8_t i = 0; i < NUM_DIGITAL_PINS; ++i) FastIOPortMap[STM_PORT(digitalPin[i])] = get_GPIO_Port(STM_PORT(digitalPin[i])); } diff --git a/Marlin/src/HAL/STM32/fastio.h b/Marlin/src/HAL/STM32/fastio.h index 4a489544..af2941c4 100644 --- a/Marlin/src/HAL/STM32/fastio.h +++ b/Marlin/src/HAL/STM32/fastio.h @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Marlin/src/HAL/STM32/inc/Conditionals_adv.h b/Marlin/src/HAL/STM32/inc/Conditionals_adv.h index 451c94f2..032716a2 100644 --- a/Marlin/src/HAL/STM32/inc/Conditionals_adv.h +++ b/Marlin/src/HAL/STM32/inc/Conditionals_adv.h @@ -21,7 +21,7 @@ */ #pragma once -#if BOTH(SDSUPPORT, USBD_USE_CDC_MSC) && DISABLED(NO_SD_HOST_DRIVE) +#if ALL(HAS_MEDIA, USBD_USE_CDC_MSC) && DISABLED(NO_SD_HOST_DRIVE) #define HAS_SD_HOST_DRIVE 1 #endif diff --git a/Marlin/src/HAL/STM32/inc/Conditionals_post.h b/Marlin/src/HAL/STM32/inc/Conditionals_post.h index 18826e11..6c97a635 100644 --- a/Marlin/src/HAL/STM32/inc/Conditionals_post.h +++ b/Marlin/src/HAL/STM32/inc/Conditionals_post.h @@ -24,6 +24,11 @@ // If no real or emulated EEPROM selected, fall back to SD emulation #if USE_FALLBACK_EEPROM #define SDCARD_EEPROM_EMULATION -#elif EITHER(I2C_EEPROM, SPI_EEPROM) +#elif ANY(I2C_EEPROM, SPI_EEPROM) #define USE_SHARED_EEPROM 1 #endif + +// Some STM32F4 boards may lose steps when saving to EEPROM during print (PR #17946) +#if defined(STM32F4xx) && ENABLED(FLASH_EEPROM_EMULATION) && PRINTCOUNTER_SAVE_INTERVAL > 0 + #define PRINTCOUNTER_SYNC +#endif diff --git a/Marlin/src/HAL/STM32/inc/SanityCheck.h b/Marlin/src/HAL/STM32/inc/SanityCheck.h index 0f1a2aca..deb16ef7 100644 --- a/Marlin/src/HAL/STM32/inc/SanityCheck.h +++ b/Marlin/src/HAL/STM32/inc/SanityCheck.h @@ -28,8 +28,7 @@ // #error "SPINDLE_LASER_PWM_PIN must use SERVO0, SERVO1 or SERVO3 connector" //#endif - -#if ENABLED(SDCARD_EEPROM_EMULATION) && DISABLED(SDSUPPORT) +#if ENABLED(SDCARD_EEPROM_EMULATION) && !HAS_MEDIA #undef SDCARD_EEPROM_EMULATION // Avoid additional error noise #if USE_FALLBACK_EEPROM #warning "EEPROM type not specified. Fallback is SDCARD_EEPROM_EMULATION." @@ -37,11 +36,6 @@ #error "SDCARD_EEPROM_EMULATION requires SDSUPPORT. Enable SDSUPPORT or choose another EEPROM emulation." #endif -#if defined(STM32F4xx) && BOTH(PRINTCOUNTER, FLASH_EEPROM_EMULATION) - #warning "FLASH_EEPROM_EMULATION may cause long delays when writing and should not be used while printing." - #error "Disable PRINTCOUNTER or choose another EEPROM emulation." -#endif - #if !defined(STM32F4xx) && ENABLED(FLASH_EEPROM_LEVELING) #error "FLASH_EEPROM_LEVELING is currently only supported on STM32F4 hardware." #endif @@ -55,3 +49,62 @@ #if ANY(TFT_COLOR_UI, TFT_LVGL_UI, TFT_CLASSIC_UI) && NOT_TARGET(STM32H7xx, STM32F4xx, STM32F1xx) #error "TFT_COLOR_UI, TFT_LVGL_UI and TFT_CLASSIC_UI are currently only supported on STM32H7, STM32F4 and STM32F1 hardware." #endif + +/** + * Check for common serial pin conflicts + */ +#define _CHECK_SERIAL_PIN(N) (( \ + BTN_EN1 == N || DOGLCD_CS == N || HEATER_BED_PIN == N || FAN0_PIN == N || \ + SDIO_D2_PIN == N || SDIO_D3_PIN == N || SDIO_CK_PIN == N || SDIO_CMD_PIN == N \ + )) +#define CHECK_SERIAL_PIN(T,N) defined(UART##N##_##T##_PIN) && _CHECK_SERIAL_PIN(UART##N##_##T##_PIN) +#if SERIAL_IN_USE(1) + #if CHECK_SERIAL_PIN(TX,1) + #error "Serial Port 1 TX IO pins conflict with another pin on the board." + #endif + #if CHECK_SERIAL_PIN(RX,1) + #error "Serial Port 1 RX IO pins conflict with another pin on the board." + #endif +#endif +#if SERIAL_IN_USE(2) + #if CHECK_SERIAL_PIN(TX,2) + #error "Serial Port 2 TX IO pins conflict with another pin on the board." + #endif + #if CHECK_SERIAL_PIN(RX,2) + #error "Serial Port 2 RX IO pins conflict with another pin on the board." + #endif +#endif +#if SERIAL_IN_USE(3) + #if CHECK_SERIAL_PIN(TX,3) + #error "Serial Port 3 TX IO pins conflict with another pin on the board." + #endif + #if CHECK_SERIAL_PIN(RX,3) + #error "Serial Port 3 RX IO pins conflict with another pin on the board." + #endif +#endif +#if SERIAL_IN_USE(4) + #if CHECK_SERIAL_PIN(TX,4) + #error "Serial Port 4 TX IO pins conflict with another pin on the board." + #endif + #if CHECK_SERIAL_PIN(RX,4) + #error "Serial Port 4 RX IO pins conflict with another pin on the board." + #endif +#endif +#if SERIAL_IN_USE(5) + #if CHECK_SERIAL_PIN(TX,5) + #error "Serial Port 5 TX IO pins conflict with another pin on the board." + #endif + #if CHECK_SERIAL_PIN(RX,5) + #error "Serial Port 5 RX IO pins conflict with another pin on the board." + #endif +#endif +#if SERIAL_IN_USE(6) + #if CHECK_SERIAL_PIN(TX,6) + #error "Serial Port 6 TX IO pins conflict with another pin on the board." + #endif + #if CHECK_SERIAL_PIN(RX,6) + #error "Serial Port 6 RX IO pins conflict with another pin on the board." + #endif +#endif +#undef CHECK_SERIAL_PIN +#undef _CHECK_SERIAL_PIN diff --git a/Marlin/src/HAL/STM32/msc_sd.cpp b/Marlin/src/HAL/STM32/msc_sd.cpp index 4f85af0d..5c8bee9c 100644 --- a/Marlin/src/HAL/STM32/msc_sd.cpp +++ b/Marlin/src/HAL/STM32/msc_sd.cpp @@ -1,14 +1,21 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * Copyright (c) 2019 BigTreeTech [https://github.com/bigtreetech] * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * @@ -33,6 +40,12 @@ #define BLOCK_SIZE 512 #define PRODUCT_ID 0x29 +#ifndef SD_MULTIBLOCK_RETRY_CNT + #define SD_MULTIBLOCK_RETRY_CNT 1 +#elif SD_MULTIBLOCK_RETRY_CNT < 1 + #error "SD_MULTIBLOCK_RETRY_CNT must be greater than or equal to 1." +#endif + class Sd2CardUSBMscHandler : public USBMscHandler { public: DiskIODriver* diskIODriver() { @@ -57,45 +70,63 @@ class Sd2CardUSBMscHandler : public USBMscHandler { auto sd2card = diskIODriver(); // single block if (blkLen == 1) { - watchdog_refresh(); - sd2card->writeBlock(blkAddr, pBuf); - return true; + hal.watchdog_refresh(); + return sd2card->writeBlock(blkAddr, pBuf); } // multi block optimization - sd2card->writeStart(blkAddr, blkLen); - while (blkLen--) { - watchdog_refresh(); - sd2card->writeData(pBuf); - pBuf += BLOCK_SIZE; + bool done = false; + for (uint16_t rcount = SD_MULTIBLOCK_RETRY_CNT; !done && rcount--;) { + uint8_t *cBuf = pBuf; + sd2card->writeStart(blkAddr, blkLen); + bool okay = true; // Assume success + for (uint32_t i = blkLen; i--;) { + hal.watchdog_refresh(); + if (!sd2card->writeData(cBuf)) { // Write. Did it fail? + sd2card->writeStop(); // writeStop for new writeStart + okay = false; // Failed, so retry + break; // Go to while... below + } + cBuf += BLOCK_SIZE; + } + done = okay; // Done if no error occurred } - sd2card->writeStop(); - return true; + + if (done) sd2card->writeStop(); + return done; } bool Read(uint8_t *pBuf, uint32_t blkAddr, uint16_t blkLen) { auto sd2card = diskIODriver(); // single block if (blkLen == 1) { - watchdog_refresh(); - sd2card->readBlock(blkAddr, pBuf); - return true; + hal.watchdog_refresh(); + return sd2card->readBlock(blkAddr, pBuf); } // multi block optimization - sd2card->readStart(blkAddr); - while (blkLen--) { - watchdog_refresh(); - sd2card->readData(pBuf); - pBuf += BLOCK_SIZE; + bool done = false; + for (uint16_t rcount = SD_MULTIBLOCK_RETRY_CNT; !done && rcount--;) { + uint8_t *cBuf = pBuf; + sd2card->readStart(blkAddr); + bool okay = true; // Assume success + for (uint32_t i = blkLen; i--;) { + hal.watchdog_refresh(); + if (!sd2card->readData(cBuf)) { // Read. Did it fail? + sd2card->readStop(); // readStop for new readStart + okay = false; // Failed, so retry + break; // Go to while... below + } + cBuf += BLOCK_SIZE; + } + done = okay; // Done if no error occurred } - sd2card->readStop(); - return true; - } - bool IsReady() { - return diskIODriver()->isReady(); + if (done) sd2card->readStop(); + return done; } + + bool IsReady() { return diskIODriver()->isReady(); } }; Sd2CardUSBMscHandler usbMscHandler; diff --git a/Marlin/src/HAL/STM32/msc_sd.h b/Marlin/src/HAL/STM32/msc_sd.h index a8e5349f..20e73822 100644 --- a/Marlin/src/HAL/STM32/msc_sd.h +++ b/Marlin/src/HAL/STM32/msc_sd.h @@ -1,14 +1,21 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * Copyright (c) 2019 BigTreeTech [https://github.com/bigtreetech] * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * diff --git a/Marlin/src/HAL/STM32/pinsDebug.h b/Marlin/src/HAL/STM32/pinsDebug.h index 73d850fc..21cd2de3 100644 --- a/Marlin/src/HAL/STM32/pinsDebug.h +++ b/Marlin/src/HAL/STM32/pinsDebug.h @@ -21,6 +21,26 @@ */ #pragma once +/** + * Pins Debugging for STM32 + * + * - NUMBER_PINS_TOTAL + * - MULTI_NAME_PAD + * - getPinByIndex(index) + * - printPinNameByIndex(index) + * - getPinIsDigitalByIndex(index) + * - digitalPinToAnalogIndex(pin) + * - getValidPinMode(pin) + * - isValidPin(pin) + * - isAnalogPin(pin) + * - digitalRead_mod(pin) + * - pwm_status(pin) + * - printPinPWM(pin) + * - printPinPort(pin) + * - printPinNumber(pin) + * - printPinAnalog(pin) + */ + #include #ifndef NUM_DIGITAL_PINS @@ -34,11 +54,11 @@ * that a CPU has. * * VARIABLES: - * Ard_num - Arduino pin number - defined by the platform. It is used by digitalRead and - * digitalWrite commands and by M42. - * - does not contain port/pin info - * - is not in port/pin order - * - typically a variant will only assign Ard_num to port/pins that are actually used + * A - Arduino pin number - defined by the platform. It is used by digitalRead and + * digitalWrite commands and by M42. + * - does not contain port/pin info + * - is not in port/pin order + * - typically a variant will only assign Ard_num to port/pins that are actually used * Index - M43 counter - only used to get Ard_num * x - a parameter/argument used to search the pin_array to try to find a signal name * associated with a Ard_num @@ -79,7 +99,6 @@ // make a list of the Arduino pin numbers in the Port/Pin order // -#define _PIN_ADD_2(NAME_ALPHA, ARDUINO_NUM) { {NAME_ALPHA}, ARDUINO_NUM }, #define _PIN_ADD(NAME_ALPHA, ARDUINO_NUM) { NAME_ALPHA, ARDUINO_NUM }, #define PIN_ADD(NAME) _PIN_ADD(#NAME, NAME) @@ -99,49 +118,55 @@ const XrefInfo pin_xref[] PROGMEM = { #define MODE_PIN_ALT 2 // Alternate function mode #define MODE_PIN_ANALOG 3 // Analog mode -#define PIN_NUM(P) (P & 0x000F) -#define PIN_NUM_ALPHA_LEFT(P) (((P & 0x000F) < 10) ? ('0' + (P & 0x000F)) : '1') -#define PIN_NUM_ALPHA_RIGHT(P) (((P & 0x000F) > 9) ? ('0' + (P & 0x000F) - 10) : 0 ) -#define PORT_NUM(P) ((P >> 4) & 0x0007) -#define PORT_ALPHA(P) ('A' + (P >> 4)) +#define PIN_NUM(P) ((P) & 0x000F) +#define PIN_NUM_ALPHA_LEFT(P) ((((P) & 0x000F) < 10) ? ('0' + ((P) & 0x000F)) : '1') +#define PIN_NUM_ALPHA_RIGHT(P) ((((P) & 0x000F) > 9) ? ('0' + ((P) & 0x000F) - 10) : 0 ) +#define PORT_NUM(P) (((P) >> 4) & 0x0007) +#define PORT_ALPHA(P) ('A' + ((P) >> 4)) -/** - * Translation of routines & variables used by pinsDebug.h - */ -#define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS -#define VALID_PIN(ANUM) ((ANUM) >= 0 && (ANUM) < NUMBER_PINS_TOTAL) -#define digitalRead_mod(Ard_num) extDigitalRead(Ard_num) // must use Arduino pin numbers when doing reads -#define PRINT_PIN(Q) -#define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0) -#define PRINT_PORT(ANUM) port_print(ANUM) -#define DIGITAL_PIN_TO_ANALOG_PIN(ANUM) -1 // will report analog pin number in the print port routine -#define GET_PIN_MAP_PIN_M43(Index) pin_xref[Index].Ard_num +#if NUM_ANALOG_FIRST >= NUM_DIGITAL_PINS + #define HAS_HIGH_ANALOG_PINS 1 +#endif +#ifndef NUM_ANALOG_LAST + #define NUM_ANALOG_LAST ((NUM_ANALOG_FIRST) + (NUM_ANALOG_INPUTS) - 1) +#endif +#define NUMBER_PINS_TOTAL ((NUM_DIGITAL_PINS) + TERN0(HAS_HIGH_ANALOG_PINS, NUM_ANALOG_INPUTS)) +#define isValidPin(P) (WITHIN(P, 0, (NUM_DIGITAL_PINS) - 1) || TERN0(HAS_HIGH_ANALOG_PINS, WITHIN(P, NUM_ANALOG_FIRST, NUM_ANALOG_LAST))) +#define digitalRead_mod(A) extDigitalRead(A) // must use Arduino pin numbers when doing reads +#define printPinNumber(Q) +#define printPinAnalog(P) do{ sprintf_P(buffer, PSTR(" (A%2d) "), digitalPinToAnalogIndex(P)); SERIAL_ECHO(buffer); }while(0) +#define digitalPinToAnalogIndex(P) -1 // will report analog pin number in the print port routine // x is a variable used to search pin_array -#define GET_ARRAY_IS_DIGITAL(x) ((bool) pin_array[x].is_digital) -#define GET_ARRAY_PIN(x) ((pin_t) pin_array[x].pin) -#define PRINT_ARRAY_NAME(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) +#define getPinIsDigitalByIndex(x) ((bool) pin_array[x].is_digital) +#define getPinByIndex(x) ((pin_t) pin_array[x].pin) +#define printPinNameByIndex(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) #define MULTI_NAME_PAD 33 // space needed to be pretty if not first name assigned to a pin +// +// Pin Mapping for M43 +// +#define GET_PIN_MAP_PIN_M43(x) pin_xref[x].Ard_num + #ifndef M43_NEVER_TOUCH - #define _M43_NEVER_TOUCH(Index) (Index >= 9 && Index <= 12) // SERIAL/USB pins: PA9(TX) PA10(RX) PA11(USB_DM) PA12(USB_DP) + #define _M43_NEVER_TOUCH(x) WITHIN(x, 9, 12) // SERIAL/USB pins: PA9(TX) PA10(RX) PA11(USB_DM) PA12(USB_DP) #ifdef KILL_PIN - #define M43_NEVER_TOUCH(Index) m43_never_touch(Index) + #define M43_NEVER_TOUCH(x) m43_never_touch(x) - bool m43_never_touch(const pin_t Index) { + bool m43_never_touch(const pin_t index) { static pin_t M43_kill_index = -1; if (M43_kill_index < 0) for (M43_kill_index = 0; M43_kill_index < NUMBER_PINS_TOTAL; M43_kill_index++) if (KILL_PIN == GET_PIN_MAP_PIN_M43(M43_kill_index)) break; - return _M43_NEVER_TOUCH(Index) || Index == M43_kill_index; // KILL_PIN and SERIAL/USB + return _M43_NEVER_TOUCH(index) || index == M43_kill_index; // KILL_PIN and SERIAL/USB } #else - #define M43_NEVER_TOUCH(Index) _M43_NEVER_TOUCH(Index) + #define M43_NEVER_TOUCH(index) _M43_NEVER_TOUCH(index) #endif #endif -uint8_t get_pin_mode(const pin_t Ard_num) { - const PinName dp = digitalPinToPinName(Ard_num); +uint8_t get_pin_mode(const pin_t pin) { + const PinName dp = digitalPinToPinName(pin); uint32_t ll_pin = STM_LL_GPIO_PIN(dp); GPIO_TypeDef *port = get_GPIO_Port(STM_PORT(dp)); uint32_t mode = LL_GPIO_GetPinMode(port, ll_pin); @@ -155,38 +180,41 @@ uint8_t get_pin_mode(const pin_t Ard_num) { } } -bool GET_PINMODE(const pin_t Ard_num) { - const uint8_t pin_mode = get_pin_mode(Ard_num); +bool getValidPinMode(const pin_t pin) { + const uint8_t pin_mode = get_pin_mode(pin); return pin_mode == MODE_PIN_OUTPUT || pin_mode == MODE_PIN_ALT; // assume all alt definitions are PWM } -int8_t digital_pin_to_analog_pin(pin_t Ard_num) { - Ard_num -= NUM_ANALOG_FIRST; - return (Ard_num >= 0 && Ard_num < NUM_ANALOG_INPUTS) ? Ard_num : -1; +int8_t digital_pin_to_analog_pin(const pin_t pin) { + if (WITHIN(pin, NUM_ANALOG_FIRST, NUM_ANALOG_LAST)) + return pin - NUM_ANALOG_FIRST; + + const int8_t ind = digitalPinToAnalogIndex(pin); + return (ind < NUM_ANALOG_INPUTS) ? ind : -1; } -bool IS_ANALOG(const pin_t Ard_num) { - return get_pin_mode(Ard_num) == MODE_PIN_ANALOG; +bool isAnalogPin(const pin_t pin) { + return get_pin_mode(pin) == MODE_PIN_ANALOG; } -bool is_digital(const pin_t x) { - const uint8_t pin_mode = get_pin_mode(pin_array[x].pin); +bool is_digital(const pin_t pin) { + const uint8_t pin_mode = get_pin_mode(pin_array[pin].pin); return pin_mode == MODE_PIN_INPUT || pin_mode == MODE_PIN_OUTPUT; } -void port_print(const pin_t Ard_num) { +void printPinPort(const pin_t pin) { char buffer[16]; - pin_t Index; - for (Index = 0; Index < NUMBER_PINS_TOTAL; Index++) - if (Ard_num == GET_PIN_MAP_PIN_M43(Index)) break; + pin_t index; + for (index = 0; index < NUMBER_PINS_TOTAL; index++) + if (pin == GET_PIN_MAP_PIN_M43(index)) break; - const char * ppa = pin_xref[Index].Port_pin_alpha; + const char * ppa = pin_xref[index].Port_pin_alpha; sprintf_P(buffer, PSTR("%s"), ppa); SERIAL_ECHO(buffer); if (ppa[3] == '\0') SERIAL_CHAR(' '); // print analog pin number - const int8_t Port_pin = digital_pin_to_analog_pin(Ard_num); + const int8_t Port_pin = digital_pin_to_analog_pin(pin); if (Port_pin >= 0) { sprintf_P(buffer, PSTR(" (A%d) "), Port_pin); SERIAL_ECHO(buffer); @@ -196,21 +224,29 @@ void port_print(const pin_t Ard_num) { SERIAL_ECHO_SP(7); // Print number to be used with M42 - sprintf_P(buffer, PSTR(" M42 P%d "), Ard_num); - SERIAL_ECHO(buffer); - if (Ard_num < 10) SERIAL_CHAR(' '); - if (Ard_num < 100) SERIAL_CHAR(' '); + int calc_p = pin; + if (pin > NUM_DIGITAL_PINS) { + calc_p -= NUM_ANALOG_FIRST; + if (calc_p > 7) calc_p += 8; + } + SERIAL_ECHOPGM(" M42 P", calc_p); + SERIAL_CHAR(' '); + if (calc_p < 100) { + SERIAL_CHAR(' '); + if (calc_p < 10) + SERIAL_CHAR(' '); + } } -bool pwm_status(const pin_t Ard_num) { - return get_pin_mode(Ard_num) == MODE_PIN_ALT; +bool pwm_status(const pin_t pin) { + return get_pin_mode(pin) == MODE_PIN_ALT; } -void pwm_details(const pin_t Ard_num) { +void printPinPWM(const pin_t pin) { #ifndef STM32F1xx - if (pwm_status(Ard_num)) { + if (pwm_status(pin)) { uint32_t alt_all = 0; - const PinName dp = digitalPinToPinName(Ard_num); + const PinName dp = digitalPinToPinName(pin); pin_t pin_number = uint8_t(PIN_NUM(dp)); const bool over_7 = pin_number >= 8; const uint8_t ind = over_7 ? 1 : 0; @@ -221,19 +257,19 @@ void pwm_details(const pin_t Ard_num) { case 'D' : alt_all = GPIOD->AFR[ind]; break; #ifdef PE_0 case 'E' : alt_all = GPIOE->AFR[ind]; break; - #elif defined (PF_0) + #elif defined(PF_0) case 'F' : alt_all = GPIOF->AFR[ind]; break; - #elif defined (PG_0) + #elif defined(PG_0) case 'G' : alt_all = GPIOG->AFR[ind]; break; - #elif defined (PH_0) + #elif defined(PH_0) case 'H' : alt_all = GPIOH->AFR[ind]; break; - #elif defined (PI_0) + #elif defined(PI_0) case 'I' : alt_all = GPIOI->AFR[ind]; break; - #elif defined (PJ_0) + #elif defined(PJ_0) case 'J' : alt_all = GPIOJ->AFR[ind]; break; - #elif defined (PK_0) + #elif defined(PK_0) case 'K' : alt_all = GPIOK->AFR[ind]; break; - #elif defined (PL_0) + #elif defined(PL_0) case 'L' : alt_all = GPIOL->AFR[ind]; break; #endif } @@ -265,4 +301,4 @@ void pwm_details(const pin_t Ard_num) { #else // TODO: F1 doesn't support changing pins function, so we need to check the function of the PIN and if it's enabled #endif -} // pwm_details +} // printPinPWM diff --git a/Marlin/src/HAL/STM32/sdio.cpp b/Marlin/src/HAL/STM32/sdio.cpp new file mode 100644 index 00000000..de388b8e --- /dev/null +++ b/Marlin/src/HAL/STM32/sdio.cpp @@ -0,0 +1,457 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "../platforms.h" + +#ifdef HAL_STM32 + +#include "../../inc/MarlinConfig.h" + +#if ENABLED(ONBOARD_SDIO) + +#include "sdio.h" + +#include +#include + +#if defined(STM32F103xE) || defined(STM32F103xG) + #include + #include +#elif defined(STM32F4xx) + #include + #include + #include + #include +#elif defined(STM32F7xx) + #include + #include + #include + #include +#elif defined(STM32H7xx) + #define SDIO_FOR_STM32H7 + #include + #include + #include + #include +#else + #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 + +SD_HandleTypeDef hsd; // SDIO structure + +static uint32_t clock_to_divider(uint32_t clk) { + #ifdef SDIO_FOR_STM32H7 + // SDMMC_CK frequency = sdmmc_ker_ck / [2 * CLKDIV]. + 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 + // Also limited to no more than 48Mhz (SDIOCLK). + const uint32_t pclk2 = HAL_RCC_GetPCLK2Freq(); + clk = min(clk, (uint32_t)(pclk2 * 8 / 3)); + clk = min(clk, (uint32_t)SDIOCLK); + // Round up divider, so we don't run the card over the speed supported, + // and subtract by 2, because STM32 will add 2, as written in the manual: + // SDIO_CK frequency = SDIOCLK / [CLKDIV + 2] + return pclk2 / clk + (pclk2 % clk != 0) - 2; + #endif +} + +// 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 +} + +#ifdef SDIO_FOR_STM32H7 + + #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); + } + + 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(); + + hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_ENABLE; + hsd.Init.ClockDiv = 8; + + #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; + + #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) { + #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; + + 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; + delay(10); + } + return false; + + #endif +} + +bool SDIO_IsReady() { + return hsd.State == HAL_SD_STATE_READY; +} + +uint32_t SDIO_GetCardSize() { + return (uint32_t)(hsd.SdCard.BlockNbr) * (hsd.SdCard.BlockSize); +} + +#endif // ONBOARD_SDIO +#endif // HAL_STM32 diff --git a/Marlin/src/HAL/NATIVE_SIM/watchdog.h b/Marlin/src/HAL/STM32/sdio.h similarity index 84% rename from Marlin/src/HAL/NATIVE_SIM/watchdog.h rename to Marlin/src/HAL/STM32/sdio.h index 4e404c38..cf5539c3 100644 --- a/Marlin/src/HAL/NATIVE_SIM/watchdog.h +++ b/Marlin/src/HAL/STM32/sdio.h @@ -21,7 +21,9 @@ */ #pragma once -#define WDT_TIMEOUT 4000000 // 4 second timeout - -void watchdog_init(); -void HAL_watchdog_refresh(); +#define SDIO_D0_PIN PC8 +#define SDIO_D1_PIN PC9 +#define SDIO_D2_PIN PC10 +#define SDIO_D3_PIN PC11 +#define SDIO_CK_PIN PC12 +#define SDIO_CMD_PIN PD2 diff --git a/Marlin/src/HAL/STM32/tft/gt911.cpp b/Marlin/src/HAL/STM32/tft/gt911.cpp index 92e14edb..6809f662 100644 --- a/Marlin/src/HAL/STM32/tft/gt911.cpp +++ b/Marlin/src/HAL/STM32/tft/gt911.cpp @@ -90,7 +90,7 @@ bool SW_IIC::read_ack() { } void SW_IIC::send_byte(uint8_t txd) { - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { write_sda(txd & 0x80); // write data bit txd <<= 1; iic_delay(1); @@ -107,7 +107,7 @@ uint8_t SW_IIC::read_byte(bool ack) { uint8_t data = 0; set_sda_in(); - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { write_scl(HIGH); // SCL = 1 iic_delay(1); data <<= 1; @@ -128,12 +128,12 @@ SW_IIC GT911::sw_iic = SW_IIC(GT911_SW_I2C_SDA_PIN, GT911_SW_I2C_SCL_PIN); void GT911::write_reg(uint16_t reg, uint8_t reg_len, uint8_t* w_data, uint8_t w_len) { sw_iic.start(); sw_iic.send_byte(gt911_slave_address); // Set IIC Slave address - LOOP_L_N(i, reg_len) { // Set reg address + for (uint8_t i = 0; i < reg_len; ++i) { // Set reg address uint8_t r = (reg >> (8 * (reg_len - 1 - i))) & 0xFF; sw_iic.send_byte(r); } - LOOP_L_N(i, w_len) { // Write data to reg + for (uint8_t i = 0; i < w_len; ++i) { // Write data to reg sw_iic.send_byte(w_data[i]); } sw_iic.stop(); @@ -142,7 +142,7 @@ void GT911::write_reg(uint16_t reg, uint8_t reg_len, uint8_t* w_data, uint8_t w_ void GT911::read_reg(uint16_t reg, uint8_t reg_len, uint8_t* r_data, uint8_t r_len) { sw_iic.start(); sw_iic.send_byte(gt911_slave_address); // Set IIC Slave address - LOOP_L_N(i, reg_len) { // Set reg address + for (uint8_t i = 0; i < reg_len; ++i) { // Set reg address uint8_t r = (reg >> (8 * (reg_len - 1 - i))) & 0xFF; sw_iic.send_byte(r); } @@ -150,33 +150,37 @@ void GT911::read_reg(uint16_t reg, uint8_t reg_len, uint8_t* r_data, uint8_t r_l sw_iic.start(); sw_iic.send_byte(gt911_slave_address + 1); // Set read mode - LOOP_L_N(i, r_len) { + for (uint8_t i = 0; i < r_len; ++i) r_data[i] = sw_iic.read_byte(1); // Read data from reg - } + sw_iic.stop(); } 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; diff --git a/Marlin/src/HAL/STM32/tft/gt911.h b/Marlin/src/HAL/STM32/tft/gt911.h index 752a554d..260c195e 100644 --- a/Marlin/src/HAL/STM32/tft/gt911.h +++ b/Marlin/src/HAL/STM32/tft/gt911.h @@ -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." @@ -39,42 +39,18 @@ class SW_IIC { private: uint16_t scl_pin; uint16_t sda_pin; - void write_scl(bool level) - { - WRITE(scl_pin, level); - } - void write_sda(bool level) - { - WRITE(sda_pin, level); - } - bool read_sda() - { - return READ(sda_pin); - } - void set_sda_out() - { - SET_OUTPUT(sda_pin); - } - void set_sda_in() - { - SET_INPUT_PULLUP(sda_pin); - } - static void iic_delay(uint8_t t) - { - delayMicroseconds(t); - } + void write_scl(bool level) { WRITE(scl_pin, level); } + void write_sda(bool level) { WRITE(sda_pin, level); } + bool read_sda() { return READ(sda_pin); } + void set_sda_out() { SET_OUTPUT(sda_pin); } + void set_sda_in() { SET_INPUT_PULLUP(sda_pin); } + static void iic_delay(uint8_t t) { delayMicroseconds(t); } public: SW_IIC(uint16_t sda, uint16_t scl); // setSCL/SDA have to be called before begin() - void setSCL(uint16_t scl) - { - scl_pin = scl; - }; - void setSDA(uint16_t sda) - { - sda_pin = sda; - }; + void setSCL(uint16_t scl) { scl_pin = scl; } + void setSDA(uint16_t sda) { sda_pin = sda; } void init(); // Initialize the IO port of IIC void start(); // Send IIC start signal void stop(); // Send IIC stop signal diff --git a/Marlin/src/HAL/STM32/tft/tft_fsmc.cpp b/Marlin/src/HAL/STM32/tft/tft_fsmc.cpp index e68b3c12..cf9e5693 100644 --- a/Marlin/src/HAL/STM32/tft/tft_fsmc.cpp +++ b/Marlin/src/HAL/STM32/tft/tft_fsmc.cpp @@ -147,21 +147,36 @@ uint32_t TFT_FSMC::ReadID(tft_data_t Reg) { } bool TFT_FSMC::isBusy() { - #if defined(STM32F1xx) - volatile bool dmaEnabled = (DMAtx.Instance->CCR & DMA_CCR_EN) != RESET; + #ifdef STM32F1xx + #define __IS_DMA_ENABLED(__HANDLE__) ((__HANDLE__)->Instance->CCR & DMA_CCR_EN) + #define __IS_DMA_CONFIGURED(__HANDLE__) ((__HANDLE__)->Instance->CPAR != 0) #elif defined(STM32F4xx) - volatile bool dmaEnabled = DMAtx.Instance->CR & DMA_SxCR_EN; + #define __IS_DMA_ENABLED(__HANDLE__) ((__HANDLE__)->Instance->CR & DMA_SxCR_EN) + #define __IS_DMA_CONFIGURED(__HANDLE__) ((__HANDLE__)->Instance->PAR != 0) #endif - if (dmaEnabled) { - if (__HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TC_FLAG_INDEX(&DMAtx)) != 0 || __HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TE_FLAG_INDEX(&DMAtx)) != 0) - Abort(); - } - else - Abort(); - return dmaEnabled; + + if (!__IS_DMA_CONFIGURED(&DMAtx)) return false; + + // Check if DMA transfer error or transfer complete flags are set + if ((__HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TE_FLAG_INDEX(&DMAtx)) == 0) && (__HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TC_FLAG_INDEX(&DMAtx)) == 0)) return true; + + __DSB(); + Abort(); + return false; +} + +void TFT_FSMC::Abort() { + HAL_DMA_Abort(&DMAtx); // Abort DMA transfer if any + HAL_DMA_DeInit(&DMAtx); // Deconfigure DMA } void TFT_FSMC::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) { + DMAtx.Init.PeriphInc = MemoryIncrease; + HAL_DMA_Init(&DMAtx); + HAL_DMA_Start(&DMAtx, (uint32_t)Data, (uint32_t)&(LCD->RAM), Count); +} + +void TFT_FSMC::Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) { DMAtx.Init.PeriphInc = MemoryIncrease; HAL_DMA_Init(&DMAtx); DataTransferBegin(); diff --git a/Marlin/src/HAL/STM32/tft/tft_fsmc.h b/Marlin/src/HAL/STM32/tft/tft_fsmc.h index 2200abaa..6189fed2 100644 --- a/Marlin/src/HAL/STM32/tft/tft_fsmc.h +++ b/Marlin/src/HAL/STM32/tft/tft_fsmc.h @@ -41,6 +41,7 @@ #define DATASIZE_8BIT SPI_DATASIZE_8BIT #define DATASIZE_16BIT SPI_DATASIZE_16BIT #define TFT_IO_DRIVER TFT_FSMC +#define DMA_MAX_WORDS 0xFFFF #define TFT_DATASIZE TERN(TFT_INTERFACE_FSMC_8BIT, DATASIZE_8BIT, DATASIZE_16BIT) typedef TERN(TFT_INTERFACE_FSMC_8BIT, uint8_t, uint16_t) tft_data_t; @@ -59,13 +60,14 @@ class TFT_FSMC { static uint32_t ReadID(tft_data_t Reg); static void Transmit(tft_data_t Data) { LCD->RAM = Data; __DSB(); } + static void Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count); static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count); public: static void Init(); static uint32_t GetID(); static bool isBusy(); - static void Abort() { __HAL_DMA_DISABLE(&DMAtx); } + static void Abort(); static void DataTransferBegin(uint16_t DataWidth = TFT_DATASIZE) {} static void DataTransferEnd() {}; @@ -73,13 +75,14 @@ class TFT_FSMC { static void WriteData(uint16_t Data) { Transmit(tft_data_t(Data)); } static void WriteReg(uint16_t Reg) { LCD->REG = tft_data_t(Reg); __DSB(); } - static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_PINC_ENABLE, Data, Count); } - static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_PINC_DISABLE, &Data, Count); } + static void WriteSequence_DMA(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_PINC_ENABLE, Data, Count); } + static void WriteMultiple_DMA(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_PINC_DISABLE, &Data, Count); } + + static void WriteSequence(uint16_t *Data, uint16_t Count) { Transmit(DMA_PINC_ENABLE, Data, Count); } static void WriteMultiple(uint16_t Color, uint32_t Count) { - static uint16_t Data; Data = Color; while (Count > 0) { - TransmitDMA(DMA_MINC_DISABLE, &Data, Count > 0xFFFF ? 0xFFFF : Count); - Count = Count > 0xFFFF ? Count - 0xFFFF : 0; + Transmit(DMA_MINC_DISABLE, &Color, Count > DMA_MAX_WORDS ? DMA_MAX_WORDS : Count); + Count = Count > DMA_MAX_WORDS ? Count - DMA_MAX_WORDS : 0; } } }; diff --git a/Marlin/src/HAL/STM32/tft/tft_ltdc.cpp b/Marlin/src/HAL/STM32/tft/tft_ltdc.cpp index 66cfd659..2be90061 100644 --- a/Marlin/src/HAL/STM32/tft/tft_ltdc.cpp +++ b/Marlin/src/HAL/STM32/tft/tft_ltdc.cpp @@ -356,7 +356,7 @@ void TFT_LTDC::WriteReg(uint16_t Reg) { reg = Reg; } -void TFT_LTDC::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) { +void TFT_LTDC::Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) { while (x_cur != x_min && Count) { Transmit(*Data); @@ -372,9 +372,9 @@ void TFT_LTDC::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Cou if (MemoryIncrease == DMA_PINC_ENABLE) { DrawImage(x_min, y_cur, x_min + width, y_cur + height, Data); Data += width * height; - } else { - DrawRect(x_min, y_cur, x_min + width, y_cur + height, *Data); } + else + DrawRect(x_min, y_cur, x_min + width, y_cur + height, *Data); y_cur += height; } diff --git a/Marlin/src/HAL/STM32/tft/tft_ltdc.h b/Marlin/src/HAL/STM32/tft/tft_ltdc.h index 7b63d692..c60b33fe 100644 --- a/Marlin/src/HAL/STM32/tft/tft_ltdc.h +++ b/Marlin/src/HAL/STM32/tft/tft_ltdc.h @@ -32,6 +32,7 @@ #define DATASIZE_8BIT SPI_DATASIZE_8BIT #define DATASIZE_16BIT SPI_DATASIZE_16BIT #define TFT_IO_DRIVER TFT_LTDC +#define DMA_MAX_WORDS 0xFFFF #define TFT_DATASIZE DATASIZE_16BIT typedef uint16_t tft_data_t; @@ -49,7 +50,7 @@ class TFT_LTDC { static void DrawRect(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t color); static void DrawImage(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *colors); static void Transmit(tft_data_t Data); - static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count); + static void Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count); public: static void Init(); @@ -63,13 +64,15 @@ class TFT_LTDC { static void WriteData(uint16_t Data); static void WriteReg(uint16_t Reg); - static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_PINC_ENABLE, Data, Count); } - static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_PINC_DISABLE, &Data, Count); } + // Non-blocking DMA data transfer is not implemented for LTDC interface + inline static void WriteSequence_DMA(uint16_t *Data, uint16_t Count) { WriteSequence(Data, Count); } + inline static void WriteMultiple_DMA(uint16_t Color, uint16_t Count) { WriteMultiple(Color, Count); } + + static void WriteSequence(uint16_t *Data, uint16_t Count) { Transmit(DMA_PINC_ENABLE, Data, Count); } static void WriteMultiple(uint16_t Color, uint32_t Count) { - static uint16_t Data; Data = Color; while (Count > 0) { - TransmitDMA(DMA_MINC_DISABLE, &Data, Count > 0xFFFF ? 0xFFFF : Count); - Count = Count > 0xFFFF ? Count - 0xFFFF : 0; + Transmit(DMA_PINC_DISABLE, &Color, Count > DMA_MAX_WORDS ? DMA_MAX_WORDS : Count); + Count = Count > DMA_MAX_WORDS ? Count - DMA_MAX_WORDS : 0; } } }; diff --git a/Marlin/src/HAL/STM32/tft/tft_spi.cpp b/Marlin/src/HAL/STM32/tft/tft_spi.cpp index 4ad35cee..26472875 100644 --- a/Marlin/src/HAL/STM32/tft/tft_spi.cpp +++ b/Marlin/src/HAL/STM32/tft/tft_spi.cpp @@ -160,16 +160,13 @@ uint32_t TFT_SPI::ReadID(uint16_t Reg) { for (i = 0; i < 4; i++) { #if TFT_MISO_PIN != TFT_MOSI_PIN - //if (hspi->Init.Direction == SPI_DIRECTION_2LINES) { - while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_TXE)) {} - SPIx.Instance->DR = 0; - //} + while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_TXE)) {} + SPIx.Instance->DR = 0; #endif while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_RXNE)) {} Data = (Data << 8) | SPIx.Instance->DR; } - __HAL_SPI_DISABLE(&SPIx); DataTransferEnd(); SPIx.Init.BaudRatePrescaler = BaudRatePrescaler; @@ -179,36 +176,44 @@ uint32_t TFT_SPI::ReadID(uint16_t Reg) { } bool TFT_SPI::isBusy() { - #if defined(STM32F1xx) - volatile bool dmaEnabled = (DMAtx.Instance->CCR & DMA_CCR_EN) != RESET; + #ifdef STM32F1xx + #define __IS_DMA_ENABLED(__HANDLE__) ((__HANDLE__)->Instance->CCR & DMA_CCR_EN) + #define __IS_DMA_CONFIGURED(__HANDLE__) ((__HANDLE__)->Instance->CPAR != 0) #elif defined(STM32F4xx) - volatile bool dmaEnabled = DMAtx.Instance->CR & DMA_SxCR_EN; + #define __IS_DMA_ENABLED(__HANDLE__) ((__HANDLE__)->Instance->CR & DMA_SxCR_EN) + #define __IS_DMA_CONFIGURED(__HANDLE__) ((__HANDLE__)->Instance->PAR != 0) #endif - if (dmaEnabled) { - if (__HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TC_FLAG_INDEX(&DMAtx)) != 0 || __HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TE_FLAG_INDEX(&DMAtx)) != 0) - Abort(); + + if (!__IS_DMA_CONFIGURED(&DMAtx)) return false; + + if (__HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TE_FLAG_INDEX(&DMAtx))) { + // You should not be here - DMA transfer error flag is set + // Abort DMA transfer and release SPI + } + else { + // Check if DMA transfer completed flag is set + if (__HAL_DMA_GET_FLAG(&DMAtx, __HAL_DMA_GET_TC_FLAG_INDEX(&DMAtx)) == 0) return true; + // Check if SPI transmit butter is empty and SPI is idle + if ((!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_TXE)) || (__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_BSY))) return true; } - else - Abort(); - return dmaEnabled; + + Abort(); + return false; } void TFT_SPI::Abort() { - // Wait for any running spi - while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_TXE)) {} - while ( __HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_BSY)) {} - // First, abort any running dma - HAL_DMA_Abort(&DMAtx); - // DeInit objects + HAL_DMA_Abort(&DMAtx); // Abort DMA transfer if any HAL_DMA_DeInit(&DMAtx); - HAL_SPI_DeInit(&SPIx); - // Deselect CS - DataTransferEnd(); + + CLEAR_BIT(SPIx.Instance->CR2, SPI_CR2_TXDMAEN); + + DataTransferEnd(); // Stop SPI and deselect CS } void TFT_SPI::Transmit(uint16_t Data) { - if (TFT_MISO_PIN == TFT_MOSI_PIN) + #if TFT_MISO_PIN == TFT_MOSI_PIN SPI_1LINE_TX(&SPIx); + #endif __HAL_SPI_ENABLE(&SPIx); @@ -217,14 +222,30 @@ void TFT_SPI::Transmit(uint16_t Data) { while (!__HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_TXE)) {} while ( __HAL_SPI_GET_FLAG(&SPIx, SPI_FLAG_BSY)) {} - if (TFT_MISO_PIN != TFT_MOSI_PIN) - __HAL_SPI_CLEAR_OVRFLAG(&SPIx); // Clear overrun flag in 2 Lines communication mode because received is not read + #if TFT_MISO_PIN != TFT_MOSI_PIN + __HAL_SPI_CLEAR_OVRFLAG(&SPIx); // Clear overrun flag in 2 Lines communication mode because received data is not read + #endif } void TFT_SPI::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) { - // Wait last dma finish, to start another - while (isBusy()) { /* nada */ } + DMAtx.Init.MemInc = MemoryIncrease; + HAL_DMA_Init(&DMAtx); + + #if TFT_MISO_PIN == TFT_MOSI_PIN + SPI_1LINE_TX(&SPIx); + #endif + + DataTransferBegin(); + HAL_DMA_Start(&DMAtx, (uint32_t)Data, (uint32_t)&(SPIx.Instance->DR), Count); + __HAL_SPI_ENABLE(&SPIx); + + SET_BIT(SPIx.Instance->CR2, SPI_CR2_TXDMAEN); // Enable Tx DMA Request + + TERN_(TFT_SHARED_IO, while (isBusy())); +} + +void TFT_SPI::Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) { DMAtx.Init.MemInc = MemoryIncrease; HAL_DMA_Init(&DMAtx); @@ -242,5 +263,27 @@ void TFT_SPI::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Coun Abort(); } +#if ENABLED(USE_SPI_DMA_TC) + void TFT_SPI::TransmitDMA_IT(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) { + + DMAtx.Init.MemInc = MemoryIncrease; + HAL_DMA_Init(&DMAtx); + + if (TFT_MISO_PIN == TFT_MOSI_PIN) + SPI_1LINE_TX(&SPIx); + + DataTransferBegin(); + + HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn); + HAL_DMA_Start_IT(&DMAtx, (uint32_t)Data, (uint32_t)&(SPIx.Instance->DR), Count); + __HAL_SPI_ENABLE(&SPIx); + + SET_BIT(SPIx.Instance->CR2, SPI_CR2_TXDMAEN); // Enable Tx DMA Request + } + + extern "C" void DMA2_Stream3_IRQHandler(void) { TFT_SPI::DMA_IRQHandler(); } +#endif + #endif // HAS_SPI_TFT #endif // HAL_STM32 diff --git a/Marlin/src/HAL/STM32/tft/tft_spi.h b/Marlin/src/HAL/STM32/tft/tft_spi.h index 667b5f36..9ec3b88f 100644 --- a/Marlin/src/HAL/STM32/tft/tft_spi.h +++ b/Marlin/src/HAL/STM32/tft/tft_spi.h @@ -36,9 +36,11 @@ #define LCD_READ_ID4 0xD3 // Read display identification information (0xD3 on ILI9341) #endif -#define DATASIZE_8BIT SPI_DATASIZE_8BIT -#define DATASIZE_16BIT SPI_DATASIZE_16BIT -#define TFT_IO_DRIVER TFT_SPI +#define DATASIZE_8BIT SPI_DATASIZE_8BIT +#define DATASIZE_16BIT SPI_DATASIZE_16BIT +#define DATASIZE_32BIT SPI_DATASIZE_32BIT +#define TFT_IO_DRIVER TFT_SPI +#define DMA_MAX_WORDS 0xFFFF class TFT_SPI { private: @@ -47,7 +49,11 @@ class TFT_SPI { static uint32_t ReadID(uint16_t Reg); static void Transmit(uint16_t Data); + static void Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count); static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count); + #if ENABLED(USE_SPI_DMA_TC) + static void TransmitDMA_IT(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count); + #endif public: static void Init(); @@ -56,19 +62,25 @@ class TFT_SPI { static void Abort(); static void DataTransferBegin(uint16_t DataWidth = DATASIZE_16BIT); - static void DataTransferEnd() { WRITE(TFT_CS_PIN, HIGH); }; + static void DataTransferEnd() { WRITE(TFT_CS_PIN, HIGH); __HAL_SPI_DISABLE(&SPIx); }; static void DataTransferAbort(); static void WriteData(uint16_t Data) { Transmit(Data); } static void WriteReg(uint16_t Reg) { WRITE(TFT_A0_PIN, LOW); Transmit(Reg); WRITE(TFT_A0_PIN, HIGH); } - static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_MINC_ENABLE, Data, Count); } - static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_MINC_DISABLE, &Data, Count); } + static void WriteSequence_DMA(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_MINC_ENABLE, Data, Count); } + static void WriteMultiple_DMA(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_MINC_DISABLE, &Data, Count); } + + #if ENABLED(USE_SPI_DMA_TC) + static void WriteSequenceIT(uint16_t *Data, uint16_t Count) { TransmitDMA_IT(DMA_MINC_ENABLE, Data, Count); } + inline static void DMA_IRQHandler() { HAL_DMA_IRQHandler(&TFT_SPI::DMAtx); } + #endif + + static void WriteSequence(uint16_t *Data, uint16_t Count) { Transmit(DMA_MINC_ENABLE, Data, Count); } static void WriteMultiple(uint16_t Color, uint32_t Count) { - static uint16_t Data; Data = Color; while (Count > 0) { - TransmitDMA(DMA_MINC_DISABLE, &Data, Count > 0xFFFF ? 0xFFFF : Count); - Count = Count > 0xFFFF ? Count - 0xFFFF : 0; + Transmit(DMA_MINC_DISABLE, &Color, Count > DMA_MAX_WORDS ? DMA_MAX_WORDS : Count); + Count = Count > DMA_MAX_WORDS ? Count - DMA_MAX_WORDS : 0; } } }; diff --git a/Marlin/src/HAL/STM32/tft/xpt2046.h b/Marlin/src/HAL/STM32/tft/xpt2046.h index 2cff3e29..71de6b00 100644 --- a/Marlin/src/HAL/STM32/tft/xpt2046.h +++ b/Marlin/src/HAL/STM32/tft/xpt2046.h @@ -69,8 +69,8 @@ class XPT2046 { static uint16_t getRawData(const XPTCoordinate coordinate); static bool isTouched(); - static inline void DataTransferBegin() { if (SPIx.Instance) { HAL_SPI_Init(&SPIx); } WRITE(TOUCH_CS_PIN, LOW); }; - static inline void DataTransferEnd() { WRITE(TOUCH_CS_PIN, HIGH); }; + static void DataTransferBegin() { if (SPIx.Instance) { HAL_SPI_Init(&SPIx); } WRITE(TOUCH_CS_PIN, LOW); }; + static void DataTransferEnd() { WRITE(TOUCH_CS_PIN, HIGH); }; static uint16_t HardwareIO(uint16_t data); static uint16_t SoftwareIO(uint16_t data); static uint16_t IO(uint16_t data = 0) { return SPIx.Instance ? HardwareIO(data) : SoftwareIO(data); } diff --git a/Marlin/src/HAL/STM32/timers.cpp b/Marlin/src/HAL/STM32/timers.cpp index fe27ca10..10e0dc43 100644 --- a/Marlin/src/HAL/STM32/timers.cpp +++ b/Marlin/src/HAL/STM32/timers.cpp @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -74,10 +74,10 @@ #define MCU_STEP_TIMER 4 #define MCU_TEMP_TIMER 2 #elif defined(STM32F401xC) || defined(STM32F401xE) - #define MCU_STEP_TIMER 9 + #define MCU_STEP_TIMER 9 // STM32F401 has no TIM6, TIM7, or TIM8 #define MCU_TEMP_TIMER 10 #elif defined(STM32F4xx) || defined(STM32F7xx) || defined(STM32H7xx) - #define MCU_STEP_TIMER 6 // STM32F401 has no TIM6, TIM7, or TIM8 + #define MCU_STEP_TIMER 6 #define MCU_TEMP_TIMER 14 // TIM7 is consumed by Software Serial if used. #endif @@ -292,9 +292,9 @@ static constexpr int get_timer_num_from_base_address(uintptr_t base_address) { // constexpr doesn't like using the base address pointers that timers evaluate to. // We can get away with casting them to uintptr_t, if we do so inside an array. // GCC will not currently do it directly to a uintptr_t. -IF_ENABLED(HAS_TMC_SW_SERIAL, static constexpr uintptr_t timer_serial[] = {uintptr_t(TIMER_SERIAL)}); -IF_ENABLED(SPEAKER, static constexpr uintptr_t timer_tone[] = {uintptr_t(TIMER_TONE)}); -IF_ENABLED(HAS_SERVOS, static constexpr uintptr_t timer_servo[] = {uintptr_t(TIMER_SERVO)}); +TERN_(HAS_TMC_SW_SERIAL, static constexpr uintptr_t timer_serial[] = {uintptr_t(TIMER_SERIAL)}); +TERN_(SPEAKER, static constexpr uintptr_t timer_tone[] = {uintptr_t(TIMER_TONE)}); +TERN_(HAS_SERVOS, static constexpr uintptr_t timer_servo[] = {uintptr_t(TIMER_SERVO)}); enum TimerPurpose { TP_SERIAL, TP_TONE, TP_SERVO, TP_STEP, TP_TEMP }; @@ -303,21 +303,21 @@ enum TimerPurpose { TP_SERIAL, TP_TONE, TP_SERVO, TP_STEP, TP_TEMP }; // This cannot yet account for timers used for PWM output, such as for fans. static constexpr struct { TimerPurpose p; int t; } timers_in_use[] = { #if HAS_TMC_SW_SERIAL - {TP_SERIAL, get_timer_num_from_base_address(timer_serial[0])}, // Set in variant.h, or as a define in platformio.h if not present in variant.h + { TP_SERIAL, get_timer_num_from_base_address(timer_serial[0]) }, // Set in variant.h, or as a define in platformio.h if not present in variant.h #endif #if ENABLED(SPEAKER) - {TP_TONE, get_timer_num_from_base_address(timer_tone[0])}, // Set in variant.h, or as a define in platformio.h if not present in variant.h + { TP_TONE, get_timer_num_from_base_address(timer_tone[0]) }, // Set in variant.h, or as a define in platformio.h if not present in variant.h #endif #if HAS_SERVOS - {TP_SERVO, get_timer_num_from_base_address(timer_servo[0])}, // Set in variant.h, or as a define in platformio.h if not present in variant.h + { TP_SERVO, get_timer_num_from_base_address(timer_servo[0]) }, // Set in variant.h, or as a define in platformio.h if not present in variant.h #endif - {TP_STEP, STEP_TIMER}, - {TP_TEMP, TEMP_TIMER}, + { TP_STEP, STEP_TIMER }, + { TP_TEMP, TEMP_TIMER }, }; static constexpr bool verify_no_timer_conflicts() { - LOOP_L_N(i, COUNT(timers_in_use)) - LOOP_S_L_N(j, i + 1, COUNT(timers_in_use)) + for (uint8_t i = 0; i < COUNT(timers_in_use); ++i) + for (uint8_t j = i + 1; j < COUNT(timers_in_use); ++j) if (timers_in_use[i].t == timers_in_use[j].t) return false; return true; } diff --git a/Marlin/src/HAL/STM32/timers.h b/Marlin/src/HAL/STM32/timers.h index aad54322..180e2403 100644 --- a/Marlin/src/HAL/STM32/timers.h +++ b/Marlin/src/HAL/STM32/timers.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2017 Victor Perez + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -116,5 +116,5 @@ FORCE_INLINE static void HAL_timer_set_compare(const uint8_t timer_num, const ha } } -#define HAL_timer_isr_prologue(T) -#define HAL_timer_isr_epilogue(T) +#define HAL_timer_isr_prologue(T) NOOP +#define HAL_timer_isr_epilogue(T) NOOP diff --git a/Marlin/src/HAL/STM32/usb_host.cpp b/Marlin/src/HAL/STM32/usb_host.cpp index d77f0b28..afafe1d4 100644 --- a/Marlin/src/HAL/STM32/usb_host.cpp +++ b/Marlin/src/HAL/STM32/usb_host.cpp @@ -26,7 +26,7 @@ #include "../../inc/MarlinConfig.h" -#if BOTH(USE_OTG_USB_HOST, USBHOST) +#if ALL(USE_OTG_USB_HOST, USBHOST) #include "usb_host.h" #include "../shared/Marduino.h" @@ -44,7 +44,7 @@ static void USBH_UserProcess(USBH_HandleTypeDef *phost, uint8_t id) { break; case HOST_USER_DISCONNECTION: //SERIAL_ECHOLNPGM("APPLICATION_DISCONNECT"); - //usb.setUsbTaskState(USB_STATE_RUNNING); + usb.setUsbTaskState(USB_STATE_INIT); break; case HOST_USER_CLASS_ACTIVE: //SERIAL_ECHOLNPGM("APPLICATION_READY"); diff --git a/Marlin/src/HAL/STM32/usb_serial.cpp b/Marlin/src/HAL/STM32/usb_serial.cpp index b607275d..0b2372f3 100644 --- a/Marlin/src/HAL/STM32/usb_serial.cpp +++ b/Marlin/src/HAL/STM32/usb_serial.cpp @@ -26,7 +26,7 @@ #include "../../inc/MarlinConfigPre.h" -#if ENABLED(EMERGENCY_PARSER) && USBD_USE_CDC +#if ENABLED(EMERGENCY_PARSER) && (USBD_USE_CDC || USBD_USE_CDC_MSC) #include "usb_serial.h" #include "../../feature/e_parser.h" diff --git a/Marlin/src/HAL/STM32F1/HAL.cpp b/Marlin/src/HAL/STM32F1/HAL.cpp index f29b3053..be2c9334 100644 --- a/Marlin/src/HAL/STM32F1/HAL.cpp +++ b/Marlin/src/HAL/STM32F1/HAL.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2017 Victor Perez + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -79,10 +78,11 @@ #define SCB_AIRCR_PRIGROUP_Msk (7UL << SCB_AIRCR_PRIGROUP_Pos) /*!< SCB AIRCR: PRIGROUP Mask */ // ------------------------ -// Public Variables +// Serial ports // ------------------------ #if defined(SERIAL_USB) && !HAS_SD_HOST_DRIVE + USBSerial SerialUSB; DefaultSerial1 MSerial0(true, SerialUSB); @@ -112,148 +112,78 @@ #endif #endif -uint16_t HAL_adc_result; +// ------------------------ +// Watchdog Timer +// ------------------------ + +#if ENABLED(USE_WATCHDOG) + + #include + + void watchdogSetup() { + // do whatever. don't remove this function. + } + + /** + * The watchdog clock is 40Khz. So for a 4s or 8s interval use a /256 preescaler and 625 or 1250 reload value (counts down to 0). + */ + #define STM32F1_WD_RELOAD TERN(WATCHDOG_DURATION_8S, 1250, 625) // 4 or 8 second timeout + + /** + * @brief Initialize the independent hardware watchdog. + * + * @return No return + * + * @details The watchdog clock is 40Khz. So for a 4s or 8s interval use a /256 preescaler and 625 or 1250 reload value (counts down to 0). + */ + void MarlinHAL::watchdog_init() { + #if DISABLED(DISABLE_WATCHDOG_INIT) + iwdg_init(IWDG_PRE_256, STM32F1_WD_RELOAD); + #endif + } + + // Reset watchdog. MUST be called every 4 or 8 seconds after the + // first watchdog_init or the STM32F1 will reset. + void MarlinHAL::watchdog_refresh() { + #if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED) + TOGGLE(LED_PIN); // heartbeat indicator + #endif + iwdg_feed(); + } + +#endif // USE_WATCHDOG // ------------------------ -// Private Variables +// ADC // ------------------------ -STM32ADC adc(ADC1); -const uint8_t adc_pins[] = { - #if HAS_TEMP_ADC_0 - TEMP_0_PIN, - #endif - #if HAS_TEMP_ADC_PROBE - TEMP_PROBE_PIN, - #endif - #if HAS_HEATED_BED - TEMP_BED_PIN, - #endif - #if HAS_TEMP_CHAMBER - TEMP_CHAMBER_PIN, - #endif - #if HAS_TEMP_COOLER - TEMP_COOLER_PIN, - #endif - #if HAS_TEMP_ADC_1 - TEMP_1_PIN, - #endif - #if HAS_TEMP_ADC_2 - TEMP_2_PIN, - #endif - #if HAS_TEMP_ADC_3 - TEMP_3_PIN, - #endif - #if HAS_TEMP_ADC_4 - TEMP_4_PIN, - #endif - #if HAS_TEMP_ADC_5 - TEMP_5_PIN, - #endif - #if HAS_TEMP_ADC_6 - TEMP_6_PIN, - #endif - #if HAS_TEMP_ADC_7 - TEMP_7_PIN, - #endif - #if ENABLED(FILAMENT_WIDTH_SENSOR) - FILWIDTH_PIN, - #endif - #if HAS_ADC_BUTTONS - ADC_KEYPAD_PIN, - #endif - #if HAS_JOY_ADC_X - JOY_X_PIN, - #endif - #if HAS_JOY_ADC_Y - JOY_Y_PIN, - #endif - #if HAS_JOY_ADC_Z - JOY_Z_PIN, - #endif - #if ENABLED(POWER_MONITOR_CURRENT) - POWER_MONITOR_CURRENT_PIN, - #endif - #if ENABLED(POWER_MONITOR_VOLTAGE) - POWER_MONITOR_VOLTAGE_PIN, - #endif -}; +// Watch out for recursion here! Our pin_t is signed, so pass through to Arduino -> analogRead(uint8_t) -enum TempPinIndex : char { - #if HAS_TEMP_ADC_0 - TEMP_0, - #endif - #if HAS_TEMP_ADC_PROBE - TEMP_PROBE, - #endif - #if HAS_HEATED_BED - TEMP_BED, - #endif - #if HAS_TEMP_CHAMBER - TEMP_CHAMBER, - #endif - #if HAS_TEMP_COOLER - TEMP_COOLER_PIN, - #endif - #if HAS_TEMP_ADC_1 - TEMP_1, - #endif - #if HAS_TEMP_ADC_2 - TEMP_2, - #endif - #if HAS_TEMP_ADC_3 - TEMP_3, - #endif - #if HAS_TEMP_ADC_4 - TEMP_4, - #endif - #if HAS_TEMP_ADC_5 - TEMP_5, - #endif - #if HAS_TEMP_ADC_6 - TEMP_6, - #endif - #if HAS_TEMP_ADC_7 - TEMP_7, - #endif - #if ENABLED(FILAMENT_WIDTH_SENSOR) - FILWIDTH, - #endif - #if HAS_ADC_BUTTONS - ADC_KEY, - #endif - #if HAS_JOY_ADC_X - JOY_X, - #endif - #if HAS_JOY_ADC_Y - JOY_Y, - #endif - #if HAS_JOY_ADC_Z - JOY_Z, - #endif - #if ENABLED(POWER_MONITOR_CURRENT) - POWERMON_CURRENT, - #endif - #if ENABLED(POWER_MONITOR_VOLTAGE) - POWERMON_VOLTS, - #endif - ADC_PIN_COUNT -}; +uint16_t analogRead(const pin_t pin) { + const bool is_analog = _GET_MODE(pin) == GPIO_INPUT_ANALOG; + return is_analog ? analogRead(uint8_t(pin)) : 0; +} + +// Wrapper to maple unprotected analogWrite +void analogWrite(const pin_t pin, int pwm_val8) { + if (PWM_PIN(pin)) analogWrite(uint8_t(pin), pwm_val8); +} -uint16_t HAL_adc_results[ADC_PIN_COUNT]; +uint16_t MarlinHAL::adc_result; // ------------------------ // Private functions // ------------------------ + static void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) { uint32_t reg_value; - uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07); /* only values 0..7 are used */ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07); // only values 0..7 are used - reg_value = SCB->AIRCR; /* read old register configuration */ - reg_value &= ~(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk); /* clear bits to change */ + reg_value = SCB->AIRCR; // read old register configuration + reg_value &= ~(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk); // clear bits to change reg_value = (reg_value | ((uint32_t)0x5FA << SCB_AIRCR_VECTKEY_Pos) | - (PriorityGroupTmp << 8)); /* Insert write key & priority group */ + (PriorityGroupTmp << 8)); // Insert write key & priority group SCB->AIRCR = reg_value; } @@ -261,6 +191,8 @@ static void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) { // Public functions // ------------------------ +void flashFirmware(const int16_t) { hal.reboot(); } + // // Leave PA11/PA12 intact if USBSerial is not used // @@ -280,14 +212,18 @@ static void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) { TERN_(POSTMORTEM_DEBUGGING, extern void install_min_serial()); -void HAL_init() { +// ------------------------ +// MarlinHAL class +// ------------------------ + +void MarlinHAL::init() { NVIC_SetPriorityGrouping(0x3); #if PIN_EXISTS(LED) OUT_WRITE(LED_PIN, LOW); #endif #if HAS_SD_HOST_DRIVE MSC_SD_init(); - #elif BOTH(SERIAL_USB, EMERGENCY_PARSER) + #elif ALL(SERIAL_USB, EMERGENCY_PARSER) usb_cdcacm_set_hooks(USB_CDCACM_HOOK_RX, my_rx_callback); #endif #if PIN_EXISTS(USB_CONNECT) @@ -299,7 +235,7 @@ void HAL_init() { } // HAL idle task -void HAL_idletask() { +void MarlinHAL::idletask() { #if HAS_SHARED_MEDIA // If Marlin is using the SD card we need to lock it to prevent access from // a PC via USB. @@ -314,14 +250,11 @@ void HAL_idletask() { #endif } -void HAL_clear_reset_source() { } +void MarlinHAL::reboot() { nvic_sys_reset(); } -/** - * TODO: Check this and change or remove. - */ -uint8_t HAL_get_reset_source() { return RST_POWER_ON; } - -void _delay_ms(const int delay_ms) { delay(delay_ms); } +// ------------------------ +// Free Memory Accessor +// ------------------------ extern "C" { extern unsigned int _ebss; // end of bss section @@ -358,102 +291,96 @@ extern "C" { // ------------------------ // ADC // ------------------------ + +enum ADCIndex : uint8_t { + OPTITEM(HAS_TEMP_ADC_0, TEMP_0) + OPTITEM(HAS_TEMP_ADC_1, TEMP_1) + OPTITEM(HAS_TEMP_ADC_2, TEMP_2) + OPTITEM(HAS_TEMP_ADC_3, TEMP_3) + OPTITEM(HAS_TEMP_ADC_4, TEMP_4) + OPTITEM(HAS_TEMP_ADC_5, TEMP_5) + OPTITEM(HAS_TEMP_ADC_6, TEMP_6) + OPTITEM(HAS_TEMP_ADC_7, TEMP_7) + OPTITEM(HAS_HEATED_BED, TEMP_BED) + OPTITEM(HAS_TEMP_CHAMBER, TEMP_CHAMBER) + OPTITEM(HAS_TEMP_ADC_PROBE, TEMP_PROBE) + OPTITEM(HAS_TEMP_COOLER, TEMP_COOLER) + OPTITEM(HAS_TEMP_BOARD, TEMP_BOARD) + OPTITEM(FILAMENT_WIDTH_SENSOR, FILWIDTH) + OPTITEM(HAS_ADC_BUTTONS, ADC_KEY) + OPTITEM(HAS_JOY_ADC_X, JOY_X) + OPTITEM(HAS_JOY_ADC_Y, JOY_Y) + OPTITEM(HAS_JOY_ADC_Z, JOY_Z) + OPTITEM(POWER_MONITOR_CURRENT, POWERMON_CURRENT) + OPTITEM(POWER_MONITOR_VOLTAGE, POWERMON_VOLTS) + ADC_COUNT +}; + +static uint16_t adc_results[ADC_COUNT]; + // Init the AD in continuous capture mode -void HAL_adc_init() { +void MarlinHAL::adc_init() { + static const uint8_t adc_pins[] = { + OPTITEM(HAS_TEMP_ADC_0, TEMP_0_PIN) + OPTITEM(HAS_TEMP_ADC_1, TEMP_1_PIN) + OPTITEM(HAS_TEMP_ADC_2, TEMP_2_PIN) + OPTITEM(HAS_TEMP_ADC_3, TEMP_3_PIN) + OPTITEM(HAS_TEMP_ADC_4, TEMP_4_PIN) + OPTITEM(HAS_TEMP_ADC_5, TEMP_5_PIN) + OPTITEM(HAS_TEMP_ADC_6, TEMP_6_PIN) + OPTITEM(HAS_TEMP_ADC_7, TEMP_7_PIN) + OPTITEM(HAS_HEATED_BED, TEMP_BED_PIN) + OPTITEM(HAS_TEMP_CHAMBER, TEMP_CHAMBER_PIN) + OPTITEM(HAS_TEMP_ADC_PROBE, TEMP_PROBE_PIN) + OPTITEM(HAS_TEMP_COOLER, TEMP_COOLER_PIN) + OPTITEM(HAS_TEMP_BOARD, TEMP_BOARD_PIN) + OPTITEM(FILAMENT_WIDTH_SENSOR, FILWIDTH_PIN) + OPTITEM(HAS_ADC_BUTTONS, ADC_KEYPAD_PIN) + OPTITEM(HAS_JOY_ADC_X, JOY_X_PIN) + OPTITEM(HAS_JOY_ADC_Y, JOY_Y_PIN) + OPTITEM(HAS_JOY_ADC_Z, JOY_Z_PIN) + OPTITEM(POWER_MONITOR_CURRENT, POWER_MONITOR_CURRENT_PIN) + OPTITEM(POWER_MONITOR_VOLTAGE, POWER_MONITOR_VOLTAGE_PIN) + }; + static STM32ADC adc(ADC1); // configure the ADC adc.calibrate(); - #if F_CPU > 72000000 - adc.setSampleRate(ADC_SMPR_71_5); // 71.5 ADC cycles - #else - adc.setSampleRate(ADC_SMPR_41_5); // 41.5 ADC cycles - #endif - adc.setPins((uint8_t *)adc_pins, ADC_PIN_COUNT); - adc.setDMA(HAL_adc_results, (uint16_t)ADC_PIN_COUNT, (uint32_t)(DMA_MINC_MODE | DMA_CIRC_MODE), nullptr); + adc.setSampleRate((F_CPU > 72000000) ? ADC_SMPR_71_5 : ADC_SMPR_41_5); // 71.5 or 41.5 ADC cycles + adc.setPins((uint8_t *)adc_pins, ADC_COUNT); + adc.setDMA(adc_results, uint16_t(ADC_COUNT), uint32_t(DMA_MINC_MODE | DMA_CIRC_MODE), nullptr); adc.setScanMode(); adc.setContinuous(); adc.startConversion(); } -void HAL_adc_start_conversion(const uint8_t adc_pin) { - //TEMP_PINS pin_index; - TempPinIndex pin_index; - switch (adc_pin) { +void MarlinHAL::adc_start(const pin_t pin) { + #define __TCASE(N,I) case N: pin_index = I; break; + #define _TCASE(C,N,I) TERN_(C, __TCASE(N, I)) + ADCIndex pin_index; + switch (pin) { default: return; - #if HAS_TEMP_ADC_0 - case TEMP_0_PIN: pin_index = TEMP_0; break; - #endif - #if HAS_TEMP_ADC_PROBE - case TEMP_PROBE_PIN: pin_index = TEMP_PROBE; break; - #endif - #if HAS_HEATED_BED - case TEMP_BED_PIN: pin_index = TEMP_BED; break; - #endif - #if HAS_TEMP_CHAMBER - case TEMP_CHAMBER_PIN: pin_index = TEMP_CHAMBER; break; - #endif - #if HAS_TEMP_COOLER - case TEMP_COOLER_PIN: pin_index = TEMP_COOLER; break; - #endif - #if HAS_TEMP_ADC_1 - case TEMP_1_PIN: pin_index = TEMP_1; break; - #endif - #if HAS_TEMP_ADC_2 - case TEMP_2_PIN: pin_index = TEMP_2; break; - #endif - #if HAS_TEMP_ADC_3 - case TEMP_3_PIN: pin_index = TEMP_3; break; - #endif - #if HAS_TEMP_ADC_4 - case TEMP_4_PIN: pin_index = TEMP_4; break; - #endif - #if HAS_TEMP_ADC_5 - case TEMP_5_PIN: pin_index = TEMP_5; break; - #endif - #if HAS_TEMP_ADC_6 - case TEMP_6_PIN: pin_index = TEMP_6; break; - #endif - #if HAS_TEMP_ADC_7 - case TEMP_7_PIN: pin_index = TEMP_7; break; - #endif - #if HAS_JOY_ADC_X - case JOY_X_PIN: pin_index = JOY_X; break; - #endif - #if HAS_JOY_ADC_Y - case JOY_Y_PIN: pin_index = JOY_Y; break; - #endif - #if HAS_JOY_ADC_Z - case JOY_Z_PIN: pin_index = JOY_Z; break; - #endif - #if ENABLED(FILAMENT_WIDTH_SENSOR) - case FILWIDTH_PIN: pin_index = FILWIDTH; break; - #endif - #if HAS_ADC_BUTTONS - case ADC_KEYPAD_PIN: pin_index = ADC_KEY; break; - #endif - #if ENABLED(POWER_MONITOR_CURRENT) - case POWER_MONITOR_CURRENT_PIN: pin_index = POWERMON_CURRENT; break; - #endif - #if ENABLED(POWER_MONITOR_VOLTAGE) - case POWER_MONITOR_VOLTAGE_PIN: pin_index = POWERMON_VOLTS; break; - #endif + _TCASE(HAS_TEMP_ADC_0, TEMP_0_PIN, TEMP_0) + _TCASE(HAS_TEMP_ADC_1, TEMP_1_PIN, TEMP_1) + _TCASE(HAS_TEMP_ADC_2, TEMP_2_PIN, TEMP_2) + _TCASE(HAS_TEMP_ADC_3, TEMP_3_PIN, TEMP_3) + _TCASE(HAS_TEMP_ADC_4, TEMP_4_PIN, TEMP_4) + _TCASE(HAS_TEMP_ADC_5, TEMP_5_PIN, TEMP_5) + _TCASE(HAS_TEMP_ADC_6, TEMP_6_PIN, TEMP_6) + _TCASE(HAS_TEMP_ADC_7, TEMP_7_PIN, TEMP_7) + _TCASE(HAS_HEATED_BED, TEMP_BED_PIN, TEMP_BED) + _TCASE(HAS_TEMP_CHAMBER, TEMP_CHAMBER_PIN, TEMP_CHAMBER) + _TCASE(HAS_TEMP_ADC_PROBE, TEMP_PROBE_PIN, TEMP_PROBE) + _TCASE(HAS_TEMP_COOLER, TEMP_COOLER_PIN, TEMP_COOLER) + _TCASE(HAS_TEMP_BOARD, TEMP_BOARD_PIN, TEMP_BOARD) + _TCASE(HAS_JOY_ADC_X, JOY_X_PIN, JOY_X) + _TCASE(HAS_JOY_ADC_Y, JOY_Y_PIN, JOY_Y) + _TCASE(HAS_JOY_ADC_Z, JOY_Z_PIN, JOY_Z) + _TCASE(FILAMENT_WIDTH_SENSOR, FILWIDTH_PIN, FILWIDTH) + _TCASE(HAS_ADC_BUTTONS, ADC_KEYPAD_PIN, ADC_KEY) + _TCASE(POWER_MONITOR_CURRENT, POWER_MONITOR_CURRENT_PIN, POWERMON_CURRENT) + _TCASE(POWER_MONITOR_VOLTAGE, POWER_MONITOR_VOLTAGE_PIN, POWERMON_VOLTS) } - HAL_adc_result = HAL_adc_results[(int)pin_index] >> (12 - HAL_ADC_RESOLUTION); // shift out unused bits -} - -uint16_t HAL_adc_get_result() { return HAL_adc_result; } - -uint16_t analogRead(pin_t pin) { - const bool is_analog = _GET_MODE(pin) == GPIO_INPUT_ANALOG; - return is_analog ? analogRead(uint8_t(pin)) : 0; + adc_result = (adc_results[(int)pin_index] & 0xFFF) >> (12 - HAL_ADC_RESOLUTION); // shift out unused bits } -// Wrapper to maple unprotected analogWrite -void analogWrite(pin_t pin, int pwm_val8) { - if (PWM_PIN(pin)) analogWrite(uint8_t(pin), pwm_val8); -} - -void HAL_reboot() { nvic_sys_reset(); } - -void flashFirmware(const int16_t) { HAL_reboot(); } - #endif // __STM32F1__ diff --git a/Marlin/src/HAL/STM32F1/HAL.h b/Marlin/src/HAL/STM32F1/HAL.h index 153cfe8a..1319af9c 100644 --- a/Marlin/src/HAL/STM32F1/HAL.h +++ b/Marlin/src/HAL/STM32F1/HAL.h @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2017 Victor Perez + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,7 +33,6 @@ #include "../shared/HAL_SPI.h" #include "fastio.h" -#include "watchdog.h" #include #include @@ -66,6 +64,10 @@ #endif #endif +// ------------------------ +// Serial ports +// ------------------------ + #ifdef SERIAL_USB typedef ForwardSerial1Class< USBSerial > DefaultSerial1; extern DefaultSerial1 MSerial0; @@ -79,7 +81,7 @@ #define _MSERIAL(X) MSerial##X #define MSERIAL(X) _MSERIAL(X) -#if EITHER(STM32_HIGH_DENSITY, STM32_XL_DENSITY) +#if ANY(STM32_HIGH_DENSITY, STM32_XL_DENSITY) #define NUM_UARTS 5 #else #define NUM_UARTS 3 @@ -137,20 +139,15 @@ static_assert(false, "LCD_SERIAL_PORT must be from 1 to " STRINGIFY(NUM_UARTS) ". You can also use -1 if the board supports Native USB.") #endif #if HAS_DGUS_LCD - #define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() + #define LCD_SERIAL_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() #endif #endif -// Set interrupt grouping for this MCU -void HAL_init(); -#define HAL_IDLETASK 1 -void HAL_idletask(); - /** * TODO: review this to return 1 for pins that are not analog input */ #ifndef analogInputToDigitalPin - #define analogInputToDigitalPin(p) (p) + #define analogInputToDigitalPin(p) pin_t(p) #endif #ifndef digitalPinHasPWM @@ -158,15 +155,7 @@ void HAL_idletask(); #define NO_COMPILE_TIME_PWM #endif -#define CRITICAL_SECTION_START() uint32_t primask = __get_primask(); (void)__iCliRetVal() -#define CRITICAL_SECTION_END() if (!primask) (void)__iSeiRetVal() -#define ISRS_ENABLED() (!__get_primask()) -#define ENABLE_ISRS() ((void)__iSeiRetVal()) -#define DISABLE_ISRS() ((void)__iCliRetVal()) - -// On AVR this is in math.h? -#define square(x) ((x)*(x)) - +// Reset Reason #define RST_POWER_ON 1 #define RST_EXTERNAL 2 #define RST_BROWN_OUT 4 @@ -182,46 +171,63 @@ void HAL_idletask(); typedef int8_t pin_t; // ------------------------ -// Public Variables +// Interrupts // ------------------------ -// Result of last ADC conversion -extern uint16_t HAL_adc_result; +#define CRITICAL_SECTION_START() const bool irqon = !__get_primask(); (void)__iCliRetVal() +#define CRITICAL_SECTION_END() if (!irqon) (void)__iSeiRetVal() +#define cli() noInterrupts() +#define sei() interrupts() // ------------------------ -// Public functions +// ADC // ------------------------ -// Disable interrupts -#define cli() noInterrupts() +#ifdef ADC_RESOLUTION + #define HAL_ADC_RESOLUTION ADC_RESOLUTION +#else + #define HAL_ADC_RESOLUTION 12 +#endif -// Enable interrupts -#define sei() interrupts() +#define HAL_ADC_VREF_MV 3300 -// Memory related -#define __bss_end __bss_end__ +uint16_t analogRead(const pin_t pin); // need hal.adc_enable() first +void analogWrite(const pin_t pin, int pwm_val8); // PWM only! mul by 257 in maple!? -// Clear reset reason -void HAL_clear_reset_source(); +// +// Pin Mapping for M42, M43, M226 +// +#define GET_PIN_MAP_PIN(index) index +#define GET_PIN_MAP_INDEX(pin) pin +#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval) -// Reset reason -uint8_t HAL_get_reset_source(); +#define JTAG_DISABLE() afio_cfg_debug_ports(AFIO_DEBUG_SW_ONLY) +#define JTAGSWD_DISABLE() afio_cfg_debug_ports(AFIO_DEBUG_NONE) -void HAL_reboot(); +#ifndef PLATFORM_M997_SUPPORT + #define PLATFORM_M997_SUPPORT +#endif +void flashFirmware(const int16_t); -void _delay_ms(const int delay); +#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment +#ifndef PWM_FREQUENCY + #define PWM_FREQUENCY 1000 // Default PWM Frequency +#endif -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" +// ------------------------ +// Class Utilities +// ------------------------ -/* -extern "C" { - int freeMemory(); -} -*/ +// Memory related +#define __bss_end __bss_end__ extern "C" char* _sbrk(int incr); +#pragma GCC diagnostic push +#if GCC_VERSION <= 50000 + #pragma GCC diagnostic ignored "-Wunused-function" +#endif + static inline int freeMemory() { volatile char top; return &top - _sbrk(0); @@ -229,58 +235,74 @@ static inline int freeMemory() { #pragma GCC diagnostic pop -// -// ADC -// +// ------------------------ +// MarlinHAL Class +// ------------------------ -#define HAL_ANALOG_SELECT(pin) pinMode(pin, INPUT_ANALOG); +class MarlinHAL { +public: -void HAL_adc_init(); + // Earliest possible init, before setup() + MarlinHAL() {} -#ifdef ADC_RESOLUTION - #define HAL_ADC_RESOLUTION ADC_RESOLUTION -#else - #define HAL_ADC_RESOLUTION 12 -#endif + // Watchdog + static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {}); + static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {}); -#define HAL_ADC_VREF 3.3 -#define HAL_START_ADC(pin) HAL_adc_start_conversion(pin) -#define HAL_READ_ADC() HAL_adc_result -#define HAL_ADC_READY() true + static void init(); // Called early in setup() + static void init_board() {} // Called less early in setup() + static void reboot(); // Restart the firmware from 0x0 -void HAL_adc_start_conversion(const uint8_t adc_pin); -uint16_t HAL_adc_get_result(); + // Interrupts + static bool isr_state() { return !__get_primask(); } + static void isr_on() { ((void)__iSeiRetVal()); } + static void isr_off() { ((void)__iCliRetVal()); } -uint16_t analogRead(pin_t pin); // need HAL_ANALOG_SELECT() first -void analogWrite(pin_t pin, int pwm_val8); // PWM only! mul by 257 in maple!? + static void delay_ms(const int ms) { delay(ms); } -#define GET_PIN_MAP_PIN(index) index -#define GET_PIN_MAP_INDEX(pin) pin -#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval) + // Tasks, called from idle() + static void idletask(); -#define JTAG_DISABLE() afio_cfg_debug_ports(AFIO_DEBUG_SW_ONLY) -#define JTAGSWD_DISABLE() afio_cfg_debug_ports(AFIO_DEBUG_NONE) + // Reset + static uint8_t get_reset_source() { return RST_POWER_ON; } + static void clear_reset_source() {} -#define PLATFORM_M997_SUPPORT -void flashFirmware(const int16_t); + // Free SRAM + static int freeMemory() { return ::freeMemory(); } -#ifndef PWM_FREQUENCY - #define PWM_FREQUENCY 1000 // Default PWM Frequency -#endif -#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment + // + // ADC Methods + // -/** - * set_pwm_frequency - * Set the frequency of the timer corresponding to the provided pin - * All Timer PWM pins run at the same frequency - */ -void set_pwm_frequency(const pin_t pin, int f_desired); + static uint16_t adc_result; -/** - * set_pwm_duty - * Set the PWM duty cycle of the provided pin to the provided value - * Optionally allows inverting the duty cycle [default = false] - * Optionally allows changing the maximum size of the provided value to enable finer PWM duty control [default = 255] - * The timer must be pre-configured with set_pwm_frequency() if the default frequency is not desired. - */ -void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false); + // Called by Temperature::init once at startup + static void adc_init(); + + // Called by Temperature::init for each sensor at startup + static void adc_enable(const pin_t pin) { pinMode(pin, INPUT_ANALOG); } + + // Begin ADC sampling on the given pin. Called from Temperature::isr! + static void adc_start(const pin_t pin); + + // Is the ADC ready for reading? + static bool adc_ready() { return true; } + + // The current value of the ADC register + static uint16_t adc_value() { return adc_result; } + + /** + * Set the PWM duty cycle for the pin to the given value. + * Optionally invert the duty cycle [default = false] + * Optionally change the maximum size of the provided value to enable finer PWM duty control [default = 255] + * The timer must be pre-configured with set_pwm_frequency() if the default frequency is not desired. + */ + static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false); + + /** + * Set the frequency of the timer for the given pin. + * All Timer PWM pins run at the same frequency. + */ + static void set_pwm_frequency(const pin_t pin, const uint16_t f_desired); + +}; diff --git a/Marlin/src/HAL/STM32F1/HAL_SPI.cpp b/Marlin/src/HAL/STM32F1/HAL_SPI.cpp index abb348d7..b5b57536 100644 --- a/Marlin/src/HAL/STM32F1/HAL_SPI.cpp +++ b/Marlin/src/HAL/STM32F1/HAL_SPI.cpp @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Marlin/src/HAL/STM32F1/MarlinSerial.cpp b/Marlin/src/HAL/STM32F1/MarlinSerial.cpp index 6dabcde5..3b26b630 100644 --- a/Marlin/src/HAL/STM32F1/MarlinSerial.cpp +++ b/Marlin/src/HAL/STM32F1/MarlinSerial.cpp @@ -28,7 +28,7 @@ // Copied from ~/.platformio/packages/framework-arduinoststm32-maple/STM32F1/system/libmaple/usart_private.h // Changed to handle Emergency Parser -static inline __always_inline void my_usart_irq(ring_buffer *rb, ring_buffer *wb, usart_reg_map *regs, MSerialT &serial) { +FORCE_INLINE void my_usart_irq(ring_buffer *rb, ring_buffer *wb, usart_reg_map *regs, MSerialT &serial) { /* Handle RXNEIE and TXEIE interrupts. * RXNE signifies availability of a byte in DR. * @@ -75,9 +75,9 @@ static inline __always_inline void my_usart_irq(ring_buffer *rb, ring_buffer *wb } // Not every MarlinSerial port should handle emergency parsing. -// It would not make sense to parse GCode from TMC responses, for example. +// It would not make sense to parse G-Code from TMC responses, for example. constexpr bool serial_handles_emergency(int port) { - return false + return (false #ifdef SERIAL_PORT || (SERIAL_PORT) == port #endif @@ -87,7 +87,7 @@ constexpr bool serial_handles_emergency(int port) { #ifdef LCD_SERIAL_PORT || (LCD_SERIAL_PORT) == port #endif - ; + ); } #define DEFINE_HWSERIAL_MARLIN(name, n) \ @@ -116,7 +116,7 @@ constexpr bool serial_handles_emergency(int port) { #endif DEFINE_HWSERIAL_MARLIN(MSerial2, 2); DEFINE_HWSERIAL_MARLIN(MSerial3, 3); -#if EITHER(STM32_HIGH_DENSITY, STM32_XL_DENSITY) +#if ANY(STM32_HIGH_DENSITY, STM32_XL_DENSITY) DEFINE_HWSERIAL_UART_MARLIN(MSerial4, 4); DEFINE_HWSERIAL_UART_MARLIN(MSerial5, 5); #endif diff --git a/Marlin/src/HAL/STM32F1/MarlinSerial.h b/Marlin/src/HAL/STM32F1/MarlinSerial.h index dda32fe7..53bcd484 100644 --- a/Marlin/src/HAL/STM32F1/MarlinSerial.h +++ b/Marlin/src/HAL/STM32F1/MarlinSerial.h @@ -52,7 +52,7 @@ typedef Serial1Class MSerialT; extern MSerialT MSerial1; extern MSerialT MSerial2; extern MSerialT MSerial3; -#if EITHER(STM32_HIGH_DENSITY, STM32_XL_DENSITY) +#if ANY(STM32_HIGH_DENSITY, STM32_XL_DENSITY) extern MSerialT MSerial4; extern MSerialT MSerial5; #endif diff --git a/Marlin/src/HAL/STM32F1/HAL_MinSerial.cpp b/Marlin/src/HAL/STM32F1/MinSerial.cpp similarity index 96% rename from Marlin/src/HAL/STM32F1/HAL_MinSerial.cpp rename to Marlin/src/HAL/STM32F1/MinSerial.cpp index 0fc3d014..8fb91332 100644 --- a/Marlin/src/HAL/STM32F1/HAL_MinSerial.cpp +++ b/Marlin/src/HAL/STM32F1/MinSerial.cpp @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,8 +25,7 @@ #if ENABLED(POSTMORTEM_DEBUGGING) -#include "../shared/HAL_MinSerial.h" -#include "watchdog.h" +#include "../shared/MinSerial.h" #include #include @@ -82,7 +80,7 @@ static void TX(char c) { #if WITHIN(SERIAL_PORT, 1, 6) struct usart_dev* dev = MYSERIAL1.c_dev(); while (!(dev->regs->SR & USART_SR_TXE)) { - TERN_(USE_WATCHDOG, HAL_watchdog_refresh()); + hal.watchdog_refresh(); sw_barrier(); } dev->regs->DR = c; diff --git a/Marlin/src/HAL/STM32F1/SPI.cpp b/Marlin/src/HAL/STM32F1/SPI.cpp index 8bfa3d23..ab111ddb 100644 --- a/Marlin/src/HAL/STM32F1/SPI.cpp +++ b/Marlin/src/HAL/STM32F1/SPI.cpp @@ -91,6 +91,14 @@ static const spi_pins board_spi_pins[] __FLASH__ = { static void *_spi3_this; #endif +/** + * @brief Wait until TXE (tx empty) flag is set and BSY (busy) flag unset. + */ +static inline void waitSpiTxEnd(spi_dev *spi_d) { + while (spi_is_tx_empty(spi_d) == 0) { /* nada */ } // wait until TXE=1 + while (spi_is_busy(spi_d) != 0) { /* nada */ } // wait until BSY=0 +} + /** * Constructor */ @@ -509,7 +517,6 @@ uint8_t SPIClass::dmaSendAsync(const void * transmitBuf, uint16_t length, bool m return b; } - /** * New functions added to manage callbacks. * Victor Perez 2017 @@ -518,23 +525,22 @@ void SPIClass::onReceive(void(*callback)()) { _currentSetting->receiveCallback = callback; if (callback) { switch (_currentSetting->spi_d->clk_id) { - #if BOARD_NR_SPI >= 1 - case RCC_SPI1: - dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi1EventCallback); - break; - #endif - #if BOARD_NR_SPI >= 2 - case RCC_SPI2: - dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi2EventCallback); - break; - #endif - #if BOARD_NR_SPI >= 3 - case RCC_SPI3: - dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi3EventCallback); - break; - #endif - default: - ASSERT(0); + #if BOARD_NR_SPI >= 1 + case RCC_SPI1: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi1EventCallback); + break; + #endif + #if BOARD_NR_SPI >= 2 + case RCC_SPI2: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi2EventCallback); + break; + #endif + #if BOARD_NR_SPI >= 3 + case RCC_SPI3: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi3EventCallback); + break; + #endif + default: ASSERT(0); } } else { @@ -546,23 +552,22 @@ void SPIClass::onTransmit(void(*callback)()) { _currentSetting->transmitCallback = callback; if (callback) { switch (_currentSetting->spi_d->clk_id) { - #if BOARD_NR_SPI >= 1 - case RCC_SPI1: - dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi1EventCallback); - break; - #endif - #if BOARD_NR_SPI >= 2 - case RCC_SPI2: - dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi2EventCallback); - break; - #endif - #if BOARD_NR_SPI >= 3 - case RCC_SPI3: - dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi3EventCallback); - break; - #endif - default: - ASSERT(0); + #if BOARD_NR_SPI >= 1 + case RCC_SPI1: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi1EventCallback); + break; + #endif + #if BOARD_NR_SPI >= 2 + case RCC_SPI2: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi2EventCallback); + break; + #endif + #if BOARD_NR_SPI >= 3 + case RCC_SPI3: + dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi3EventCallback); + break; + #endif + default: ASSERT(0); } } else { diff --git a/Marlin/src/HAL/STM32F1/SPI.h b/Marlin/src/HAL/STM32F1/SPI.h index 2467432e..27bf6843 100644 --- a/Marlin/src/HAL/STM32F1/SPI.h +++ b/Marlin/src/HAL/STM32F1/SPI.h @@ -33,6 +33,15 @@ #include #include +// Number of SPI ports +#ifdef BOARD_SPI3_SCK_PIN + #define BOARD_NR_SPI 3 +#elif defined(BOARD_SPI2_SCK_PIN) + #define BOARD_NR_SPI 2 +#elif defined(BOARD_SPI1_SCK_PIN) + #define BOARD_NR_SPI 1 +#endif + // SPI_HAS_TRANSACTION means SPI has // - beginTransaction() // - endTransaction() @@ -49,7 +58,7 @@ #define SPI_CLOCK_DIV128 SPI_BAUD_PCLK_DIV_128 #define SPI_CLOCK_DIV256 SPI_BAUD_PCLK_DIV_256 -/* +/** * Roger Clark. 20150106 * Commented out redundant AVR defined * @@ -144,7 +153,7 @@ class SPISettings { friend class SPIClass; }; -/* +/** * Kept for compat. */ static const uint8_t ff = 0xFF; @@ -224,7 +233,7 @@ class SPIClass { void onReceive(void(*)()); void onTransmit(void(*)()); - /* + /** * I/O */ @@ -305,7 +314,7 @@ class SPIClass { uint8_t dmaSendRepeat(uint16_t length); uint8_t dmaSendAsync(const void * transmitBuf, uint16_t length, bool minc = 1); - /* + /** * Pin accessors */ @@ -389,7 +398,7 @@ class SPIClass { void updateSettings(); - /* + /** * Functions added for DMA transfers with Callback. * Experimental. */ @@ -414,12 +423,4 @@ class SPIClass { */ }; -/** - * @brief Wait until TXE (tx empty) flag is set and BSY (busy) flag unset. - */ -static inline void waitSpiTxEnd(spi_dev *spi_d) { - while (spi_is_tx_empty(spi_d) == 0) { /* nada */ } // wait until TXE=1 - while (spi_is_busy(spi_d) != 0) { /* nada */ } // wait until BSY=0 -} - extern SPIClass SPI; diff --git a/Marlin/src/HAL/STM32F1/Servo.cpp b/Marlin/src/HAL/STM32F1/Servo.cpp index 8dc1ef7b..7aa8fe3d 100644 --- a/Marlin/src/HAL/STM32F1/Servo.cpp +++ b/Marlin/src/HAL/STM32F1/Servo.cpp @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -147,17 +146,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 +166,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 +199,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 } } diff --git a/Marlin/src/HAL/STM32F1/Servo.h b/Marlin/src/HAL/STM32F1/Servo.h index b6143de8..ffafc238 100644 --- a/Marlin/src/HAL/STM32F1/Servo.h +++ b/Marlin/src/HAL/STM32F1/Servo.h @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,7 +34,8 @@ #define SERVO_DEFAULT_MIN_ANGLE 0 #define SERVO_DEFAULT_MAX_ANGLE 180 -#define HAL_SERVO_LIB libServo +class libServo; +typedef libServo hal_servo_t; class libServo { public: diff --git a/Marlin/src/HAL/STM32F1/dogm/u8g_com_stm32duino_swspi.cpp b/Marlin/src/HAL/STM32F1/dogm/u8g_com_stm32duino_swspi.cpp index 26ea1ea1..c57350aa 100644 --- a/Marlin/src/HAL/STM32F1/dogm/u8g_com_stm32duino_swspi.cpp +++ b/Marlin/src/HAL/STM32F1/dogm/u8g_com_stm32duino_swspi.cpp @@ -24,7 +24,7 @@ #include "../../../inc/MarlinConfig.h" -#if BOTH(HAS_MARLINUI_U8GLIB, FORCE_SOFT_SPI) +#if ALL(HAS_MARLINUI_U8GLIB, FORCE_SOFT_SPI) #include #include "../../shared/HAL_SPI.h" @@ -37,7 +37,7 @@ static uint8_t SPI_speed = LCD_SPI_SPEED; static inline uint8_t swSpiTransfer_mode_0(uint8_t b, const uint8_t spi_speed, const pin_t miso_pin=-1) { - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { if (spi_speed == 0) { WRITE(DOGLCD_MOSI, !!(b & 0x80)); WRITE(DOGLCD_SCK, HIGH); @@ -47,16 +47,16 @@ static inline uint8_t swSpiTransfer_mode_0(uint8_t b, const uint8_t spi_speed, c } else { const uint8_t state = (b & 0x80) ? HIGH : LOW; - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) WRITE(DOGLCD_MOSI, state); - LOOP_L_N(j, spi_speed + (miso_pin >= 0 ? 0 : 1)) + for (uint8_t j = 0; j < spi_speed + (miso_pin >= 0 ? 0 : 1); ++j) WRITE(DOGLCD_SCK, HIGH); b <<= 1; if (miso_pin >= 0 && READ(miso_pin)) b |= 1; - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) WRITE(DOGLCD_SCK, LOW); } } @@ -64,7 +64,7 @@ static inline uint8_t swSpiTransfer_mode_0(uint8_t b, const uint8_t spi_speed, c } static inline uint8_t swSpiTransfer_mode_3(uint8_t b, const uint8_t spi_speed, const pin_t miso_pin=-1) { - LOOP_L_N(i, 8) { + for (uint8_t i = 0; i < 8; ++i) { const uint8_t state = (b & 0x80) ? HIGH : LOW; if (spi_speed == 0) { WRITE(DOGLCD_SCK, LOW); @@ -73,13 +73,13 @@ static inline uint8_t swSpiTransfer_mode_3(uint8_t b, const uint8_t spi_speed, c WRITE(DOGLCD_SCK, HIGH); } else { - LOOP_L_N(j, spi_speed + (miso_pin >= 0 ? 0 : 1)) + for (uint8_t j = 0; j < spi_speed + (miso_pin >= 0 ? 0 : 1); ++j) WRITE(DOGLCD_SCK, LOW); - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) WRITE(DOGLCD_MOSI, state); - LOOP_L_N(j, spi_speed) + for (uint8_t j = 0; j < spi_speed; ++j) WRITE(DOGLCD_SCK, HIGH); } b <<= 1; diff --git a/Marlin/src/HAL/STM32F1/eeprom_flash.cpp b/Marlin/src/HAL/STM32F1/eeprom_flash.cpp index e7d9dd29..48fb2d28 100644 --- a/Marlin/src/HAL/STM32F1/eeprom_flash.cpp +++ b/Marlin/src/HAL/STM32F1/eeprom_flash.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2016 Victor Perez victor_pv@hotmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Marlin/src/HAL/STM32F1/eeprom_sdcard.cpp b/Marlin/src/HAL/STM32F1/eeprom_sdcard.cpp index d608ccee..9cfa97c1 100644 --- a/Marlin/src/HAL/STM32F1/eeprom_sdcard.cpp +++ b/Marlin/src/HAL/STM32F1/eeprom_sdcard.cpp @@ -47,7 +47,7 @@ static char _ALIGN(4) HAL_eeprom_data[MARLIN_EEPROM_SIZE]; bool PersistentStore::access_start() { if (!card.isMounted()) return false; - SdFile file, root = card.getroot(); + MediaFile file, root = card.getroot(); if (!file.open(&root, EEPROM_FILENAME, O_RDONLY)) return true; // false aborts the save @@ -62,7 +62,7 @@ bool PersistentStore::access_start() { bool PersistentStore::access_finish() { if (!card.isMounted()) return false; - SdFile file, root = card.getroot(); + MediaFile file, root = card.getroot(); int bytes_written = 0; if (file.open(&root, EEPROM_FILENAME, O_CREAT | O_WRITE | O_TRUNC)) { bytes_written = file.write(HAL_eeprom_data, MARLIN_EEPROM_SIZE); diff --git a/Marlin/src/HAL/STM32F1/endstop_interrupts.h b/Marlin/src/HAL/STM32F1/endstop_interrupts.h index 4d7edb94..56600bcd 100644 --- a/Marlin/src/HAL/STM32F1/endstop_interrupts.h +++ b/Marlin/src/HAL/STM32F1/endstop_interrupts.h @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -54,27 +53,33 @@ void endstop_ISR() { endstops.update(); } void setup_endstop_interrupts() { #define _ATTACH(P) attachInterrupt(P, endstop_ISR, CHANGE) - TERN_(HAS_X_MAX, _ATTACH(X_MAX_PIN)); - TERN_(HAS_X_MIN, _ATTACH(X_MIN_PIN)); - TERN_(HAS_Y_MAX, _ATTACH(Y_MAX_PIN)); - TERN_(HAS_Y_MIN, _ATTACH(Y_MIN_PIN)); - TERN_(HAS_Z_MAX, _ATTACH(Z_MAX_PIN)); - TERN_(HAS_Z_MIN, _ATTACH(Z_MIN_PIN)); - TERN_(HAS_X2_MAX, _ATTACH(X2_MAX_PIN)); - TERN_(HAS_X2_MIN, _ATTACH(X2_MIN_PIN)); - TERN_(HAS_Y2_MAX, _ATTACH(Y2_MAX_PIN)); - TERN_(HAS_Y2_MIN, _ATTACH(Y2_MIN_PIN)); - TERN_(HAS_Z2_MAX, _ATTACH(Z2_MAX_PIN)); - TERN_(HAS_Z2_MIN, _ATTACH(Z2_MIN_PIN)); - TERN_(HAS_Z3_MAX, _ATTACH(Z3_MAX_PIN)); - TERN_(HAS_Z3_MIN, _ATTACH(Z3_MIN_PIN)); - TERN_(HAS_Z4_MAX, _ATTACH(Z4_MAX_PIN)); - TERN_(HAS_Z4_MIN, _ATTACH(Z4_MIN_PIN)); + TERN_(USE_X_MAX, _ATTACH(X_MAX_PIN)); + TERN_(USE_X_MIN, _ATTACH(X_MIN_PIN)); + TERN_(USE_Y_MAX, _ATTACH(Y_MAX_PIN)); + TERN_(USE_Y_MIN, _ATTACH(Y_MIN_PIN)); + TERN_(USE_Z_MAX, _ATTACH(Z_MAX_PIN)); + TERN_(USE_Z_MIN, _ATTACH(Z_MIN_PIN)); + TERN_(USE_X2_MAX, _ATTACH(X2_MAX_PIN)); + TERN_(USE_X2_MIN, _ATTACH(X2_MIN_PIN)); + TERN_(USE_Y2_MAX, _ATTACH(Y2_MAX_PIN)); + TERN_(USE_Y2_MIN, _ATTACH(Y2_MIN_PIN)); + TERN_(USE_Z2_MAX, _ATTACH(Z2_MAX_PIN)); + TERN_(USE_Z2_MIN, _ATTACH(Z2_MIN_PIN)); + TERN_(USE_Z3_MAX, _ATTACH(Z3_MAX_PIN)); + TERN_(USE_Z3_MIN, _ATTACH(Z3_MIN_PIN)); + TERN_(USE_Z4_MAX, _ATTACH(Z4_MAX_PIN)); + TERN_(USE_Z4_MIN, _ATTACH(Z4_MIN_PIN)); TERN_(HAS_Z_MIN_PROBE_PIN, _ATTACH(Z_MIN_PROBE_PIN)); - TERN_(HAS_I_MAX, _ATTACH(I_MAX_PIN)); - TERN_(HAS_I_MIN, _ATTACH(I_MIN_PIN)); - TERN_(HAS_J_MAX, _ATTACH(J_MAX_PIN)); - TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN)); - TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN)); - TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_I_MAX, _ATTACH(I_MAX_PIN)); + TERN_(USE_I_MIN, _ATTACH(I_MIN_PIN)); + TERN_(USE_J_MAX, _ATTACH(J_MAX_PIN)); + TERN_(USE_J_MIN, _ATTACH(J_MIN_PIN)); + TERN_(USE_K_MAX, _ATTACH(K_MAX_PIN)); + TERN_(USE_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(USE_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(USE_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(USE_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(USE_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(USE_W_MIN, _ATTACH(W_MIN_PIN)); } diff --git a/Marlin/src/HAL/STM32F1/fast_pwm.cpp b/Marlin/src/HAL/STM32F1/fast_pwm.cpp index 98d56bc5..c3f96f0f 100644 --- a/Marlin/src/HAL/STM32F1/fast_pwm.cpp +++ b/Marlin/src/HAL/STM32F1/fast_pwm.cpp @@ -21,11 +21,9 @@ */ #ifdef __STM32F1__ -#include "../../inc/MarlinConfigPre.h" +#include "../../inc/MarlinConfig.h" #include -#include "HAL.h" -#include "timers.h" #define NR_TIMERS TERN(STM32_XL_DENSITY, 14, 8) // Maple timers, 14 for STM32_XL_DENSITY (F/G chips), 8 for HIGH density (C D E) @@ -38,23 +36,26 @@ inline uint8_t timer_and_index_for_pin(const pin_t pin, timer_dev **timer_ptr) { return 0; } -void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) { - if (!PWM_PIN(pin)) return; - - timer_dev *timer; UNUSED(timer); - if (timer_freq[timer_and_index_for_pin(pin, &timer)] == 0) - set_pwm_frequency(pin, PWM_FREQUENCY); - - const uint8_t channel = PIN_MAP[pin].timer_channel; +void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) { const uint16_t duty = invert ? v_size - v : v; - timer_set_compare(timer, channel, duty); - timer_set_mode(timer, channel, TIMER_PWM); // PWM Output Mode + if (PWM_PIN(pin)) { + timer_dev *timer; + if (timer_freq[timer_and_index_for_pin(pin, &timer)] == 0) + set_pwm_frequency(pin, PWM_FREQUENCY); + const uint8_t channel = PIN_MAP[pin].timer_channel; + timer_set_compare(timer, channel, duty); + timer_set_mode(timer, channel, TIMER_PWM); // PWM Output Mode + } + else { + pinMode(pin, OUTPUT); + digitalWrite(pin, duty < v_size / 2 ? LOW : HIGH); + } } -void set_pwm_frequency(const pin_t pin, int f_desired) { +void MarlinHAL::set_pwm_frequency(const pin_t pin, const uint16_t f_desired) { if (!PWM_PIN(pin)) return; // Don't proceed if no hardware timer - timer_dev *timer; UNUSED(timer); + timer_dev *timer; timer_freq[timer_and_index_for_pin(pin, &timer)] = f_desired; // Protect used timers diff --git a/Marlin/src/HAL/STM32F1/fastio.h b/Marlin/src/HAL/STM32F1/fastio.h index e75254d6..5b3ebaa5 100644 --- a/Marlin/src/HAL/STM32F1/fastio.h +++ b/Marlin/src/HAL/STM32F1/fastio.h @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Marlin/src/HAL/STM32F1/inc/Conditionals_post.h b/Marlin/src/HAL/STM32F1/inc/Conditionals_post.h index 656fbe1c..f130f5ca 100644 --- a/Marlin/src/HAL/STM32F1/inc/Conditionals_post.h +++ b/Marlin/src/HAL/STM32F1/inc/Conditionals_post.h @@ -24,11 +24,11 @@ // If no real EEPROM, Flash emulation, or SRAM emulation is available fall back to SD emulation #if USE_FALLBACK_EEPROM #define SDCARD_EEPROM_EMULATION -#elif EITHER(I2C_EEPROM, SPI_EEPROM) +#elif ANY(I2C_EEPROM, SPI_EEPROM) #define USE_SHARED_EEPROM 1 #endif -// Allow SDSUPPORT to be disabled -#if DISABLED(SDSUPPORT) - #undef SDIO_SUPPORT +// Allow for no media drives +#if !HAS_MEDIA + #undef ONBOARD_SDIO #endif diff --git a/Marlin/src/HAL/STM32F1/inc/SanityCheck.h b/Marlin/src/HAL/STM32F1/inc/SanityCheck.h index fe8f6e0e..1da42dcc 100644 --- a/Marlin/src/HAL/STM32F1/inc/SanityCheck.h +++ b/Marlin/src/HAL/STM32F1/inc/SanityCheck.h @@ -25,7 +25,7 @@ * Test STM32F1-specific configuration values for errors at compile-time. */ -#if ENABLED(SDCARD_EEPROM_EMULATION) && DISABLED(SDSUPPORT) +#if ENABLED(SDCARD_EEPROM_EMULATION) && !HAS_MEDIA #undef SDCARD_EEPROM_EMULATION // Avoid additional error noise #if USE_FALLBACK_EEPROM #warning "EEPROM type not specified. Fallback is SDCARD_EEPROM_EMULATION." diff --git a/Marlin/src/HAL/STM32F1/maple_win_usb_driver/maple_serial.inf b/Marlin/src/HAL/STM32F1/maple_win_usb_driver/maple_serial.inf index c39f4ce0..0df30d2c 100644 --- a/Marlin/src/HAL/STM32F1/maple_win_usb_driver/maple_serial.inf +++ b/Marlin/src/HAL/STM32F1/maple_win_usb_driver/maple_serial.inf @@ -48,7 +48,6 @@ ServiceBinary=%12%\usbser.sys ; String Definitions ;------------------------------------------------------------------------------ - [Strings] STM = "LeafLabs" MFGNAME = "LeafLabs" diff --git a/Marlin/src/HAL/STM32F1/msc_sd.cpp b/Marlin/src/HAL/STM32F1/msc_sd.cpp index f490c83e..067b46eb 100644 --- a/Marlin/src/HAL/STM32F1/msc_sd.cpp +++ b/Marlin/src/HAL/STM32F1/msc_sd.cpp @@ -1,14 +1,21 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * Copyright (c) 2019 BigTreeTech [https://github.com/bigtreetech] * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * diff --git a/Marlin/src/HAL/STM32F1/msc_sd.h b/Marlin/src/HAL/STM32F1/msc_sd.h index f4636bdf..371211ef 100644 --- a/Marlin/src/HAL/STM32F1/msc_sd.h +++ b/Marlin/src/HAL/STM32F1/msc_sd.h @@ -1,14 +1,21 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * Copyright (c) 2019 BigTreeTech [https://github.com/bigtreetech] * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * diff --git a/Marlin/src/HAL/STM32F1/onboard_sd.cpp b/Marlin/src/HAL/STM32F1/onboard_sd.cpp index 582ee385..a3d8dcb2 100644 --- a/Marlin/src/HAL/STM32F1/onboard_sd.cpp +++ b/Marlin/src/HAL/STM32F1/onboard_sd.cpp @@ -38,8 +38,13 @@ #define SPI_CLOCK_MAX SPI_BAUD_PCLK_DIV_2 #endif -#define CS_LOW() WRITE(ONBOARD_SD_CS_PIN, LOW) // Set OnboardSPI cs low -#define CS_HIGH() WRITE(ONBOARD_SD_CS_PIN, HIGH) // Set OnboardSPI cs high +#if PIN_EXISTS(ONBOARD_SD_CS) && ONBOARD_SD_CS_PIN != SD_SS_PIN + #define CS_LOW() WRITE(ONBOARD_SD_CS_PIN, LOW) // Set OnboardSPI cs low + #define CS_HIGH() WRITE(ONBOARD_SD_CS_PIN, HIGH) // Set OnboardSPI cs high +#else + #define CS_LOW() + #define CS_HIGH() +#endif #define FCLK_FAST() ONBOARD_SD_SPI.setClockDivider(SPI_CLOCK_MAX) #define FCLK_SLOW() ONBOARD_SD_SPI.setClockDivider(SPI_BAUD_PCLK_DIV_256) diff --git a/Marlin/src/HAL/STM32F1/onboard_sd.h b/Marlin/src/HAL/STM32F1/onboard_sd.h index f228d068..be1d1d0a 100644 --- a/Marlin/src/HAL/STM32F1/onboard_sd.h +++ b/Marlin/src/HAL/STM32F1/onboard_sd.h @@ -1,11 +1,31 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + /*----------------------------------------------------------------------- -/ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] / * Copyright (c) 2019 BigTreeTech [https://github.com/bigtreetech] -/ * Low level disk interface module include file (C)ChaN, 2015 +/ * Low level disk interface module include file (c) ChaN, 2015 /-----------------------------------------------------------------------*/ -#pragma once - #define _DISKIO_WRITE 1 /* 1: Enable disk_write function */ #define _DISKIO_IOCTL 1 /* 1: Enable disk_ioctl function */ #define _DISKIO_ISDIO 0 /* 1: Enable iSDIO control function */ @@ -27,7 +47,6 @@ typedef enum { RES_PARERR /* 4: Invalid Parameter */ } DRESULT; - #if _DISKIO_ISDIO /* Command structure for iSDIO ioctl command */ typedef struct { diff --git a/Marlin/src/HAL/STM32F1/pinsDebug.h b/Marlin/src/HAL/STM32F1/pinsDebug.h index 27f4b673..91916145 100644 --- a/Marlin/src/HAL/STM32F1/pinsDebug.h +++ b/Marlin/src/HAL/STM32F1/pinsDebug.h @@ -22,11 +22,23 @@ #pragma once /** - * Support routines for MAPLE_STM32F1 - */ - -/** - * Translation of routines & variables used by pinsDebug.h + * Pins Debugging for Maple STM32F1 + * + * - NUMBER_PINS_TOTAL + * - MULTI_NAME_PAD + * - getPinByIndex(index) + * - printPinNameByIndex(index) + * - getPinIsDigitalByIndex(index) + * - digitalPinToAnalogIndex(pin) + * - getValidPinMode(pin) + * - isValidPin(pin) + * - isAnalogPin(pin) + * - digitalRead_mod(pin) + * - pwm_status(pin) + * - printPinPWM(pin) + * - printPinPort(pin) + * - printPinNumber(pin) + * - printPinAnalog(pin) */ #ifndef BOARD_NR_GPIO_PINS // Only in MAPLE_STM32F1 @@ -39,14 +51,12 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS]; #define NUM_DIGITAL_PINS BOARD_NR_GPIO_PINS #define NUMBER_PINS_TOTAL BOARD_NR_GPIO_PINS -#define VALID_PIN(pin) (pin >= 0 && pin < BOARD_NR_GPIO_PINS) -#define GET_ARRAY_PIN(p) pin_t(pin_array[p].pin) -#define pwm_status(pin) PWM_PIN(pin) -#define digitalRead_mod(p) extDigitalRead(p) -#define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%3hd "), int16_t(p)); SERIAL_ECHO(buffer); }while(0) -#define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0) -#define PRINT_PORT(p) print_port(p) -#define PRINT_ARRAY_NAME(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) +#define isValidPin(P) (P >= 0 && P < BOARD_NR_GPIO_PINS) +#define getPinByIndex(x) pin_t(pin_array[x].pin) +#define digitalRead_mod(P) extDigitalRead(P) +#define printPinNumber(P) do{ sprintf_P(buffer, PSTR("%3hd "), int16_t(P)); SERIAL_ECHO(buffer); }while(0) +#define printPinAnalog(P) do{ sprintf_P(buffer, PSTR(" (A%2d) "), digitalPinToAnalogIndex(P)); SERIAL_ECHO(buffer); }while(0) +#define printPinNameByIndex(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) #define MULTI_NAME_PAD 21 // space needed to be pretty if not first name assigned to a pin // pins that will cause hang/reset/disconnect in M43 Toggle and Watch utilities @@ -54,21 +64,19 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS]; #define M43_NEVER_TOUCH(Q) (Q >= 9 && Q <= 12) // SERIAL/USB pins PA9(TX) PA10(RX) #endif -static inline int8_t get_pin_mode(pin_t pin) { - return VALID_PIN(pin) ? _GET_MODE(pin) : -1; -} +int8_t get_pin_mode(const pin_t pin) { return isValidPin(pin) ? _GET_MODE(pin) : -1; } -static inline pin_t DIGITAL_PIN_TO_ANALOG_PIN(pin_t pin) { - if (!VALID_PIN(pin)) return -1; - int8_t adc_channel = int8_t(PIN_MAP[pin].adc_channel); +int8_t digitalPinToAnalogIndex(const pin_t pin) { + if (!isValidPin(pin)) return -1; + pin_t adc_channel = pin_t(PIN_MAP[pin].adc_channel); #ifdef NUM_ANALOG_INPUTS - if (adc_channel >= NUM_ANALOG_INPUTS) adc_channel = ADCx; + if (adc_channel >= NUM_ANALOG_INPUTS) adc_channel = (pin_t)ADCx; #endif - return pin_t(adc_channel); + return adc_channel; } -static inline bool IS_ANALOG(pin_t pin) { - if (!VALID_PIN(pin)) return false; +bool isAnalogPin(const pin_t pin) { + if (!isValidPin(pin)) return false; if (PIN_MAP[pin].adc_channel != ADCx) { #ifdef NUM_ANALOG_INPUTS if (PIN_MAP[pin].adc_channel >= NUM_ANALOG_INPUTS) return false; @@ -78,13 +86,13 @@ static inline bool IS_ANALOG(pin_t pin) { return false; } -static inline bool GET_PINMODE(const pin_t pin) { - return VALID_PIN(pin) && !IS_INPUT(pin); +bool getValidPinMode(const pin_t pin) { + return isValidPin(pin) && !IS_INPUT(pin); } -static inline bool GET_ARRAY_IS_DIGITAL(const int16_t array_pin) { - const pin_t pin = GET_ARRAY_PIN(array_pin); - return (!IS_ANALOG(pin) +bool getPinIsDigitalByIndex(const int16_t index) { + const pin_t pin = getPinByIndex(index); + return (!isAnalogPin(pin) #ifdef NUM_ANALOG_INPUTS || PIN_MAP[pin].adc_channel >= NUM_ANALOG_INPUTS #endif @@ -93,12 +101,12 @@ static inline bool GET_ARRAY_IS_DIGITAL(const int16_t array_pin) { #include "../../inc/MarlinConfig.h" // Allow pins/pins.h to set density -static inline void pwm_details(const pin_t pin) { +void printPinPWM(const pin_t pin) { if (PWM_PIN(pin)) { timer_dev * const tdev = PIN_MAP[pin].timer_device; const uint8_t channel = PIN_MAP[pin].timer_channel; const char num = ( - #if EITHER(STM32_HIGH_DENSITY, STM32_XL_DENSITY) + #if ANY(STM32_HIGH_DENSITY, STM32_XL_DENSITY) tdev == &timer8 ? '8' : tdev == &timer5 ? '5' : #endif @@ -113,7 +121,9 @@ static inline void pwm_details(const pin_t pin) { } } -static inline void print_port(pin_t pin) { +bool pwm_status(const pin_t pin) { return PWM_PIN(pin); } + +void printPinPort(const pin_t pin) { const char port = 'A' + char(pin >> 4); // pin div 16 const int16_t gbit = PIN_MAP[pin].gpio_bit; char buffer[8]; diff --git a/Marlin/src/HAL/STM32F1/sdio.cpp b/Marlin/src/HAL/STM32F1/sdio.cpp index 6e41d2cb..23f984ef 100644 --- a/Marlin/src/HAL/STM32F1/sdio.cpp +++ b/Marlin/src/HAL/STM32F1/sdio.cpp @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,7 +25,7 @@ #include "../../inc/MarlinConfig.h" // Allow pins/pins.h to set density -#if EITHER(STM32_HIGH_DENSITY, STM32_XL_DENSITY) +#if ANY(STM32_HIGH_DENSITY, STM32_XL_DENSITY) #include "sdio.h" @@ -136,8 +135,13 @@ bool SDIO_ReadBlock_DMA(uint32_t blockAddress, uint8_t *data) { } bool SDIO_ReadBlock(uint32_t blockAddress, uint8_t *data) { - uint32_t retries = SDIO_READ_RETRIES; - while (retries--) if (SDIO_ReadBlock_DMA(blockAddress, data)) return true; + uint8_t retries = SDIO_READ_RETRIES; + while (retries--) { + if (SDIO_ReadBlock_DMA(blockAddress, data)) return true; + #if SD_RETRY_DELAY_MS + delay(SD_RETRY_DELAY_MS); + #endif + } return false; } diff --git a/Marlin/src/HAL/STM32F1/sdio.h b/Marlin/src/HAL/STM32F1/sdio.h index 8777299f..08c88466 100644 --- a/Marlin/src/HAL/STM32F1/sdio.h +++ b/Marlin/src/HAL/STM32F1/sdio.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2017 Victor Perez + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -60,7 +60,6 @@ #define ACMD41_SD_APP_OP_COND (uint16_t)(SDMMC_ACMD_SD_APP_OP_COND | SDIO_CMD_WAIT_SHORT_RESP) #define ACMD42_SD_APP_SET_CLR_CARD_DETECT (uint16_t)(SDMMC_ACMD_SD_APP_SET_CLR_CARD_DETECT | SDIO_CMD_WAIT_SHORT_RESP) - #define SDMMC_ALLZERO 0x00000000U #define SDMMC_OCR_ERRORBITS 0xFDFFE008U diff --git a/Marlin/src/HAL/STM32F1/tft/tft_fsmc.cpp b/Marlin/src/HAL/STM32F1/tft/tft_fsmc.cpp index 5b52fb41..175576c2 100644 --- a/Marlin/src/HAL/STM32F1/tft/tft_fsmc.cpp +++ b/Marlin/src/HAL/STM32F1/tft/tft_fsmc.cpp @@ -20,6 +20,8 @@ * */ +#ifdef __STM32F1__ + #include "../../../inc/MarlinConfig.h" #if HAS_FSMC_TFT @@ -215,23 +217,50 @@ uint32_t TFT_FSMC::GetID() { } bool TFT_FSMC::isBusy() { + #define __IS_DMA_CONFIGURED(__DMAx__, __CHx__) (dma_channel_regs(__DMAx__, __CHx__)->CPAR != 0) + + if (!__IS_DMA_CONFIGURED(FSMC_DMA_DEV, FSMC_DMA_CHANNEL)) return false; + + // Check if DMA transfer error or transfer complete flags are set + if ((dma_get_isr_bits(FSMC_DMA_DEV, FSMC_DMA_CHANNEL) & (DMA_ISR_TCIF | DMA_ISR_TEIF)) == 0) return true; + + __DSB(); + Abort(); return false; } void TFT_FSMC::Abort() { + dma_channel_reg_map *channel_regs = dma_channel_regs(FSMC_DMA_DEV, FSMC_DMA_CHANNEL); + dma_disable(FSMC_DMA_DEV, FSMC_DMA_CHANNEL); // Abort DMA transfer if any + + // Deconfigure DMA + channel_regs->CCR = 0U; + channel_regs->CNDTR = 0U; + channel_regs->CMAR = 0U; + channel_regs->CPAR = 0U; } void TFT_FSMC::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) { + // TODO: HAL STM32 uses DMA2_Channel1 for FSMC on STM32F1 + dma_setup_transfer(FSMC_DMA_DEV, FSMC_DMA_CHANNEL, Data, DMA_SIZE_16BITS, &LCD->RAM, DMA_SIZE_16BITS, DMA_MEM_2_MEM | MemoryIncrease); + dma_set_num_transfers(FSMC_DMA_DEV, FSMC_DMA_CHANNEL, Count); + dma_clear_isr_bits(FSMC_DMA_DEV, FSMC_DMA_CHANNEL); + dma_enable(FSMC_DMA_DEV, FSMC_DMA_CHANNEL); +} + +void TFT_FSMC::Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) { #if defined(FSMC_DMA_DEV) && defined(FSMC_DMA_CHANNEL) dma_setup_transfer(FSMC_DMA_DEV, FSMC_DMA_CHANNEL, Data, DMA_SIZE_16BITS, &LCD->RAM, DMA_SIZE_16BITS, DMA_MEM_2_MEM | MemoryIncrease); dma_set_num_transfers(FSMC_DMA_DEV, FSMC_DMA_CHANNEL, Count); dma_clear_isr_bits(FSMC_DMA_DEV, FSMC_DMA_CHANNEL); dma_enable(FSMC_DMA_DEV, FSMC_DMA_CHANNEL); - while ((dma_get_isr_bits(FSMC_DMA_DEV, FSMC_DMA_CHANNEL) & 0x0A) == 0) {}; - dma_disable(FSMC_DMA_DEV, FSMC_DMA_CHANNEL); + while ((dma_get_isr_bits(FSMC_DMA_DEV, FSMC_DMA_CHANNEL) & (DMA_CCR_TEIE | DMA_CCR_TCIE)) == 0) {} + Abort(); #endif } #endif // HAS_FSMC_TFT + +#endif // __STM32F1__ diff --git a/Marlin/src/HAL/STM32F1/tft/tft_fsmc.h b/Marlin/src/HAL/STM32F1/tft/tft_fsmc.h index d9ee1f4c..720af8db 100644 --- a/Marlin/src/HAL/STM32F1/tft/tft_fsmc.h +++ b/Marlin/src/HAL/STM32F1/tft/tft_fsmc.h @@ -33,6 +33,10 @@ #define DATASIZE_8BIT DMA_SIZE_8BITS #define DATASIZE_16BIT DMA_SIZE_16BITS #define TFT_IO_DRIVER TFT_FSMC +#define DMA_MAX_WORDS 0xFFFF + +#define DMA_PINC_ENABLE DMA_PINC_MODE +#define DMA_PINC_DISABLE 0 typedef struct { __IO uint16_t REG; @@ -45,6 +49,7 @@ class TFT_FSMC { static uint32_t ReadID(uint16_t Reg); static void Transmit(uint16_t Data); + static void Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count); static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count); public: @@ -59,13 +64,14 @@ class TFT_FSMC { static void WriteData(uint16_t Data) { Transmit(Data); } static void WriteReg(uint16_t Reg); - static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_PINC_MODE, Data, Count); } - static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_CIRC_MODE, &Data, Count); } + static void WriteSequence_DMA(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_PINC_ENABLE, Data, Count); } + static void WriteMultiple_DMA(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_PINC_DISABLE, &Data, Count); } + + static void WriteSequence(uint16_t *Data, uint16_t Count) { Transmit(DMA_PINC_ENABLE, Data, Count); } static void WriteMultiple(uint16_t Color, uint32_t Count) { - static uint16_t Data; Data = Color; while (Count > 0) { - TransmitDMA(DMA_CIRC_MODE, &Data, Count > 0xFFFF ? 0xFFFF : Count); - Count = Count > 0xFFFF ? Count - 0xFFFF : 0; + Transmit(DMA_PINC_DISABLE, &Color, Count > DMA_MAX_WORDS ? DMA_MAX_WORDS : Count); + Count = Count > DMA_MAX_WORDS ? Count - DMA_MAX_WORDS : 0; } } }; diff --git a/Marlin/src/HAL/STM32F1/tft/tft_spi.cpp b/Marlin/src/HAL/STM32F1/tft/tft_spi.cpp index 9bf6bbb3..d0772e27 100644 --- a/Marlin/src/HAL/STM32F1/tft/tft_spi.cpp +++ b/Marlin/src/HAL/STM32F1/tft/tft_spi.cpp @@ -20,17 +20,19 @@ * */ +#ifdef __STM32F1__ + #include "../../../inc/MarlinConfig.h" #if HAS_SPI_TFT #include "tft_spi.h" -SPIClass TFT_SPI::SPIx(1); +SPIClass TFT_SPI::SPIx(TFT_SPI_DEVICE); void TFT_SPI::Init() { #if PIN_EXISTS(TFT_RESET) - OUT_WRITE(TFT_RST_PIN, HIGH); + OUT_WRITE(TFT_RESET_PIN, HIGH); delay(100); #endif @@ -46,7 +48,7 @@ void TFT_SPI::Init() { * STM32F1 has 3 SPI ports, SPI1 in APB2, SPI2/SPI3 in APB1 * so the minimum prescale of SPI1 is DIV4, SPI2/SPI3 is DIV2 */ - #if SPI_DEVICE == 1 + #if TFT_SPI_DEVICE == 1 #define SPI_CLOCK_MAX SPI_CLOCK_DIV4 #else #define SPI_CLOCK_MAX SPI_CLOCK_DIV2 @@ -62,7 +64,7 @@ void TFT_SPI::Init() { case SPI_SPEED_6: clock = SPI_CLOCK_DIV64; break; default: clock = SPI_CLOCK_DIV2; // Default from the SPI library } - SPIx.setModule(1); + SPIx.setModule(TFT_SPI_DEVICE); SPIx.setClockDivider(clock); SPIx.setBitOrder(MSBFIRST); SPIx.setDataMode(SPI_MODE0); @@ -71,7 +73,7 @@ void TFT_SPI::Init() { void TFT_SPI::DataTransferBegin(uint16_t DataSize) { SPIx.setDataSize(DataSize); SPIx.begin(); - OUT_WRITE(TFT_CS_PIN, LOW); + WRITE(TFT_CS_PIN, LOW); } #ifdef TFT_DEFAULT_DRIVER @@ -101,7 +103,7 @@ uint32_t TFT_SPI::ReadID(uint16_t Reg) { DataTransferBegin(DATASIZE_8BIT); WriteReg(Reg); - LOOP_L_N(i, 4) { + for (uint8_t i = 0; i < 4; ++i) { SPIx.read((uint8_t*)&d, 1); data = (data << 8) | d; } @@ -113,17 +115,57 @@ uint32_t TFT_SPI::ReadID(uint16_t Reg) { #endif } -bool TFT_SPI::isBusy() { return false; } +bool TFT_SPI::isBusy() { + #define __IS_DMA_CONFIGURED(__DMAx__, __CHx__) (dma_channel_regs(__DMAx__, __CHx__)->CPAR != 0) + + if (!__IS_DMA_CONFIGURED(DMAx, DMA_CHx)) return false; + + if (dma_get_isr_bits(DMAx, DMA_CHx) & DMA_ISR_TEIF) { + // You should not be here - DMA transfer error flag is set + // Abort DMA transfer and release SPI + } + else { + // Check if DMA transfer completed flag is set + if (!(dma_get_isr_bits(DMAx, DMA_CHx) & DMA_ISR_TCIF)) return true; + // Check if SPI TX butter is empty and SPI is idle + if (!(SPIdev->regs->SR & SPI_SR_TXE) || (SPIdev->regs->SR & SPI_SR_BSY)) return true; + } + + Abort(); + return false; +} + +void TFT_SPI::Abort() { + dma_channel_reg_map *channel_regs = dma_channel_regs(DMAx, DMA_CHx); + + dma_disable(DMAx, DMA_CHx); // Abort DMA transfer if any + spi_tx_dma_disable(SPIdev); -void TFT_SPI::Abort() { DataTransferEnd(); } + // Deconfigure DMA + channel_regs->CCR = 0U; + channel_regs->CNDTR = 0U; + channel_regs->CMAR = 0U; + channel_regs->CPAR = 0U; + + DataTransferEnd(); +} void TFT_SPI::Transmit(uint16_t Data) { SPIx.send(Data); } void TFT_SPI::TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) { DataTransferBegin(); - OUT_WRITE(TFT_DC_PIN, HIGH); + SPIx.dmaSendAsync(Data, Count, MemoryIncrease == DMA_MINC_ENABLE); + + TERN_(TFT_SHARED_IO, while (isBusy())); +} + +void TFT_SPI::Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count) { + WRITE(TFT_DC_PIN, HIGH); + DataTransferBegin(); SPIx.dmaSend(Data, Count, MemoryIncrease == DMA_MINC_ENABLE); DataTransferEnd(); } #endif // HAS_SPI_TFT + +#endif // __STM32F1__ diff --git a/Marlin/src/HAL/STM32F1/tft/tft_spi.h b/Marlin/src/HAL/STM32F1/tft/tft_spi.h index da9a8e0c..3416f88f 100644 --- a/Marlin/src/HAL/STM32F1/tft/tft_spi.h +++ b/Marlin/src/HAL/STM32F1/tft/tft_spi.h @@ -25,6 +25,27 @@ #include +#define IS_SPI(N) (BOARD_NR_SPI >= N && (TFT_SCK_PIN == BOARD_SPI##N##_SCK_PIN) && (TFT_MOSI_PIN == BOARD_SPI##N##_MOSI_PIN) && (TFT_MISO_PIN == BOARD_SPI##N##_MISO_PIN)) +#if IS_SPI(1) + #define TFT_SPI_DEVICE 1 + #define SPIdev SPI1 + #define DMAx DMA1 + #define DMA_CHx DMA_CH3 +#elif IS_SPI(2) + #define TFT_SPI_DEVICE 2 + #define SPIdev SPI2 + #define DMAx DMA1 + #define DMA_CHx DMA_CH5 +#elif IS_SPI(3) + #define TFT_SPI_DEVICE 3 + #define SPIdev SPI3 + #define DMAx DMA2 + #define DMA_CHx DMA_CH2 +#else + #error "Invalid TFT SPI configuration." +#endif +#undef IS_SPI + #ifndef LCD_READ_ID #define LCD_READ_ID 0x04 // Read display identification information (0xD3 on ILI9341) #endif @@ -32,17 +53,19 @@ #define LCD_READ_ID4 0xD3 // Read display identification information (0xD3 on ILI9341) #endif -#define DATASIZE_8BIT DATA_SIZE_8BIT -#define DATASIZE_16BIT DATA_SIZE_16BIT -#define TFT_IO_DRIVER TFT_SPI +#define DATASIZE_8BIT DATA_SIZE_8BIT +#define DATASIZE_16BIT DATA_SIZE_16BIT +#define TFT_IO_DRIVER TFT_SPI +#define DMA_MAX_WORDS 0xFFFF -#define DMA_MINC_ENABLE 1 -#define DMA_MINC_DISABLE 0 +#define DMA_MINC_ENABLE DMA_MINC_MODE +#define DMA_MINC_DISABLE 0 class TFT_SPI { private: static uint32_t ReadID(uint16_t Reg); static void Transmit(uint16_t Data); + static void Transmit(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count); static void TransmitDMA(uint32_t MemoryIncrease, uint16_t *Data, uint16_t Count); public: @@ -58,15 +81,16 @@ class TFT_SPI { static void DataTransferAbort(); static void WriteData(uint16_t Data) { Transmit(Data); } - static void WriteReg(uint16_t Reg) { WRITE(TFT_A0_PIN, LOW); Transmit(Reg); WRITE(TFT_A0_PIN, HIGH); } + static void WriteReg(uint16_t Reg) { WRITE(TFT_DC_PIN, LOW); Transmit(Reg); WRITE(TFT_DC_PIN, HIGH); } + + static void WriteSequence_DMA(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_MINC_ENABLE, Data, Count); } + static void WriteMultiple_DMA(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_MINC_DISABLE, &Data, Count); } - static void WriteSequence(uint16_t *Data, uint16_t Count) { TransmitDMA(DMA_MINC_ENABLE, Data, Count); } - static void WriteMultiple(uint16_t Color, uint16_t Count) { static uint16_t Data; Data = Color; TransmitDMA(DMA_MINC_DISABLE, &Data, Count); } + static void WriteSequence(uint16_t *Data, uint16_t Count) { Transmit(DMA_MINC_ENABLE, Data, Count); } static void WriteMultiple(uint16_t Color, uint32_t Count) { - static uint16_t Data; Data = Color; while (Count > 0) { - TransmitDMA(DMA_MINC_DISABLE, &Data, Count > 0xFFFF ? 0xFFFF : Count); - Count = Count > 0xFFFF ? Count - 0xFFFF : 0; + Transmit(DMA_MINC_DISABLE, &Color, Count > DMA_MAX_WORDS ? DMA_MAX_WORDS : Count); + Count = Count > DMA_MAX_WORDS ? Count - DMA_MAX_WORDS : 0; } } }; diff --git a/Marlin/src/HAL/STM32F1/tft/xpt2046.cpp b/Marlin/src/HAL/STM32F1/tft/xpt2046.cpp index ac9ad072..bf57ba00 100644 --- a/Marlin/src/HAL/STM32F1/tft/xpt2046.cpp +++ b/Marlin/src/HAL/STM32F1/tft/xpt2046.cpp @@ -20,6 +20,8 @@ * */ +#ifdef __STM32F1__ + #include "../../../inc/MarlinConfig.h" #if HAS_TFT_XPT2046 || HAS_RES_TOUCH_BUTTONS @@ -141,4 +143,6 @@ uint16_t XPT2046::SoftwareIO(uint16_t data) { return result; } -#endif // HAS_TFT_XPT2046 +#endif // HAS_TFT_XPT2046 || HAS_RES_TOUCH_BUTTONS + +#endif // __STM32F1__ diff --git a/Marlin/src/HAL/STM32F1/tft/xpt2046.h b/Marlin/src/HAL/STM32F1/tft/xpt2046.h index aba0799e..7c456cf0 100644 --- a/Marlin/src/HAL/STM32F1/tft/xpt2046.h +++ b/Marlin/src/HAL/STM32F1/tft/xpt2046.h @@ -65,8 +65,8 @@ class XPT2046 { static uint16_t getRawData(const XPTCoordinate coordinate); static bool isTouched(); - static inline void DataTransferBegin() { WRITE(TOUCH_CS_PIN, LOW); }; - static inline void DataTransferEnd() { WRITE(TOUCH_CS_PIN, HIGH); }; + static void DataTransferBegin() { WRITE(TOUCH_CS_PIN, LOW); }; + static void DataTransferEnd() { WRITE(TOUCH_CS_PIN, HIGH); }; #if ENABLED(TOUCH_BUTTONS_HW_SPI) static uint16_t HardwareIO(uint16_t data); #endif diff --git a/Marlin/src/HAL/STM32F1/timers.cpp b/Marlin/src/HAL/STM32F1/timers.cpp index 112c730b..12477a45 100644 --- a/Marlin/src/HAL/STM32F1/timers.cpp +++ b/Marlin/src/HAL/STM32F1/timers.cpp @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Marlin/src/HAL/STM32F1/timers.h b/Marlin/src/HAL/STM32F1/timers.h index f9ab6d13..f92c32c2 100644 --- a/Marlin/src/HAL/STM32F1/timers.h +++ b/Marlin/src/HAL/STM32F1/timers.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2017 Victor Perez + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -81,7 +81,7 @@ typedef uint16_t hal_timer_t; #endif #if MB(BTT_SKR_MINI_E3_V1_0, BTT_SKR_E3_DIP, BTT_SKR_MINI_E3_V1_2, MKS_ROBIN_LITE, MKS_ROBIN_E3D, MKS_ROBIN_E3) - // SKR Mini E3 boards use PA8 as FAN_PIN, so TIMER 1 is used for Fan PWM. + // SKR Mini E3 boards use PA8 as FAN0_PIN, so TIMER 1 is used for Fan PWM. #ifdef STM32_HIGH_DENSITY #define MF_TIMER_SERVO0 8 // tone.cpp uses Timer 4 #else @@ -188,7 +188,7 @@ FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) { } } -#define HAL_timer_isr_epilogue(T) +#define HAL_timer_isr_epilogue(T) NOOP // No command is available in framework to turn off ARPE bit, which is turned on by default in libmaple. // Needed here to reset ARPE=0 for stepper timer diff --git a/Marlin/src/HAL/STM32F1/watchdog.cpp b/Marlin/src/HAL/STM32F1/watchdog.cpp deleted file mode 100644 index b812a4fa..00000000 --- a/Marlin/src/HAL/STM32F1/watchdog.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * - * Based on Sprinter and grbl. - * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -/** - * HAL for stm32duino.com based on Libmaple and compatible (STM32F1) - */ - -#ifdef __STM32F1__ - -#include "../../inc/MarlinConfig.h" - -#if ENABLED(USE_WATCHDOG) - -#include -#include "watchdog.h" - -/** - * The watchdog clock is 40Khz. So for a 4s or 8s interval use a /256 preescaler and 625 or 1250 reload value (counts down to 0). - */ -#define STM32F1_WD_RELOAD TERN(WATCHDOG_DURATION_8S, 1250, 625) // 4 or 8 second timeout - -void HAL_watchdog_refresh() { - #if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED) - TOGGLE(LED_PIN); // heartbeat indicator - #endif - iwdg_feed(); -} - -void watchdogSetup() { - // do whatever. don't remove this function. -} - -/** - * @brief Initialized the independent hardware watchdog. - * - * @return No return - * - * @details The watchdog clock is 40Khz. So for a 4s or 8s interval use a /256 preescaler and 625 or 1250 reload value (counts down to 0). - */ -void watchdog_init() { - #if DISABLED(DISABLE_WATCHDOG_INIT) - iwdg_init(IWDG_PRE_256, STM32F1_WD_RELOAD); - #endif -} - -#endif // USE_WATCHDOG -#endif // __STM32F1__ diff --git a/Marlin/src/HAL/TEENSY31_32/HAL.cpp b/Marlin/src/HAL/TEENSY31_32/HAL.cpp index f08cf799..28923689 100644 --- a/Marlin/src/HAL/TEENSY31_32/HAL.cpp +++ b/Marlin/src/HAL/TEENSY31_32/HAL.cpp @@ -31,6 +31,10 @@ #include +// ------------------------ +// Serial ports +// ------------------------ + #define _IMPLEMENT_SERIAL(X) DefaultSerial##X MSerial##X(false, Serial##X) #define IMPLEMENT_SERIAL(X) _IMPLEMENT_SERIAL(X) #if WITHIN(SERIAL_PORT, 0, 3) @@ -40,33 +44,13 @@ #endif USBSerialType USBSerial(false, SerialUSB); -uint16_t HAL_adc_result; - -static const uint8_t pin2sc1a[] = { - 5, 14, 8, 9, 13, 12, 6, 7, 15, 4, 0, 19, 3, 31, // 0-13, we treat them as A0-A13 - 5, 14, 8, 9, 13, 12, 6, 7, 15, 4, // 14-23 (A0-A9) - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, // 24-33 - 0+64, 19+64, 3+64, 31+64, // 34-37 (A10-A13) - 26, 22, 23, 27, 29, 30 // 38-43: temp. sensor, VREF_OUT, A14, bandgap, VREFH, VREFL. A14 isn't connected to anything in Teensy 3.0. -}; - -/* - // disable interrupts - void cli() { noInterrupts(); } - - // enable interrupts - void sei() { interrupts(); } -*/ +// ------------------------ +// MarlinHAL Class +// ------------------------ -void HAL_adc_init() { - analog_init(); - while (ADC0_SC3 & ADC_SC3_CAL) {}; // Wait for calibration to finish - NVIC_ENABLE_IRQ(IRQ_FTM1); -} +void MarlinHAL::reboot() { _reboot_Teensyduino_(); } -void HAL_clear_reset_source() { } - -uint8_t HAL_get_reset_source() { +uint8_t MarlinHAL::get_reset_source() { switch (RCM_SRS0) { case 128: return RST_POWER_ON; break; case 64: return RST_EXTERNAL; break; @@ -78,7 +62,54 @@ uint8_t HAL_get_reset_source() { return 0; } -void HAL_reboot() { _reboot_Teensyduino_(); } +// ------------------------ +// Watchdog Timer +// ------------------------ + +#if ENABLED(USE_WATCHDOG) + + #define WDT_TIMEOUT_MS TERN(WATCHDOG_DURATION_8S, 8000, 4000) // 4 or 8 second timeout + + void MarlinHAL::watchdog_init() { + WDOG_TOVALH = 0; + WDOG_TOVALL = WDT_TIMEOUT_MS; + WDOG_STCTRLH = WDOG_STCTRLH_WDOGEN; + } + + void MarlinHAL::watchdog_refresh() { + // Watchdog refresh sequence + WDOG_REFRESH = 0xA602; + WDOG_REFRESH = 0xB480; + } + +#endif + +// ------------------------ +// ADC +// ------------------------ + +void MarlinHAL::adc_init() { + analog_init(); + while (ADC0_SC3 & ADC_SC3_CAL) {}; // Wait for calibration to finish + NVIC_ENABLE_IRQ(IRQ_FTM1); +} + +void MarlinHAL::adc_start(const pin_t pin) { + static const uint8_t pin2sc1a[] = { + 5, 14, 8, 9, 13, 12, 6, 7, 15, 4, 0, 19, 3, 31, // 0-13, we treat them as A0-A13 + 5, 14, 8, 9, 13, 12, 6, 7, 15, 4, // 14-23 (A0-A9) + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, // 24-33 + 0+64, 19+64, 3+64, 31+64, // 34-37 (A10-A13) + 26, 22, 23, 27, 29, 30 // 38-43: temp. sensor, VREF_OUT, A14, bandgap, VREFH, VREFL. A14 isn't connected to anything in Teensy 3.0. + }; + ADC0_SC1A = pin2sc1a[pin]; +} + +uint16_t MarlinHAL::adc_value() { return ADC0_RA; } + +// ------------------------ +// Free Memory Accessor +// ------------------------ extern "C" { extern char __bss_end; @@ -95,8 +126,4 @@ extern "C" { } } -void HAL_adc_start_conversion(const uint8_t adc_pin) { ADC0_SC1A = pin2sc1a[adc_pin]; } - -uint16_t HAL_adc_get_result() { return ADC0_RA; } - #endif // __MK20DX256__ diff --git a/Marlin/src/HAL/TEENSY31_32/HAL.h b/Marlin/src/HAL/TEENSY31_32/HAL.h index 61d8b346..659fcb72 100644 --- a/Marlin/src/HAL/TEENSY31_32/HAL.h +++ b/Marlin/src/HAL/TEENSY31_32/HAL.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,16 +32,12 @@ #include "../shared/HAL_SPI.h" #include "fastio.h" -#include "watchdog.h" #include -#define CPU_ST7920_DELAY_1 600 -#define CPU_ST7920_DELAY_2 750 -#define CPU_ST7920_DELAY_3 750 - -//#undef MOTHERBOARD -//#define MOTHERBOARD BOARD_TEENSY31_32 +// ------------------------ +// Defines +// ------------------------ #define IS_32BIT_TEENSY 1 #define IS_TEENSY_31_32 1 @@ -49,6 +45,14 @@ #define IS_TEENSY32 1 #endif +#define CPU_ST7920_DELAY_1 600 +#define CPU_ST7920_DELAY_2 750 +#define CPU_ST7920_DELAY_3 750 + +// ------------------------ +// Serial ports +// ------------------------ + #include "../../core/serial_hook.h" #define Serial0 Serial @@ -72,31 +76,44 @@ extern USBSerialType USBSerial; #error "The required SERIAL_PORT must be from 0 to 3, or -1 for Native USB." #endif -#define HAL_SERVO_LIB libServo +// ------------------------ +// Types +// ------------------------ + +class libServo; +typedef libServo hal_servo_t; typedef int8_t pin_t; -#ifndef analogInputToDigitalPin - #define analogInputToDigitalPin(p) ((p < 12U) ? (p) + 54U : -1) -#endif +// ------------------------ +// Interrupts +// ------------------------ -#define CRITICAL_SECTION_START() uint32_t primask = __get_PRIMASK(); __disable_irq() -#define CRITICAL_SECTION_END() if (!primask) __enable_irq() -#define ISRS_ENABLED() (!__get_PRIMASK()) -#define ENABLE_ISRS() __enable_irq() -#define DISABLE_ISRS() __disable_irq() +uint32_t __get_PRIMASK(void); // CMSIS +#define CRITICAL_SECTION_START() const bool irqon = !__get_PRIMASK(); __disable_irq() +#define CRITICAL_SECTION_END() if (irqon) __enable_irq() -inline void HAL_init() {} +// ------------------------ +// ADC +// ------------------------ -// Clear the reset reason -void HAL_clear_reset_source(); +#ifndef analogInputToDigitalPin + #define analogInputToDigitalPin(p) pin_t((p < 12U) ? (p) + 54U : -1) +#endif -// Get the reason for the reset -uint8_t HAL_get_reset_source(); +#define HAL_ADC_VREF_MV 3300 +#define HAL_ADC_RESOLUTION 10 -void HAL_reboot(); +// +// Pin Mapping for M42, M43, M226 +// +#define GET_PIN_MAP_PIN(index) index +#define GET_PIN_MAP_INDEX(pin) pin +#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval) -FORCE_INLINE void _delay_ms(const int delay_ms) { delay(delay_ms); } +// ------------------------ +// Class Utilities +// ------------------------ #pragma GCC diagnostic push #if GCC_VERSION <= 50000 @@ -107,27 +124,67 @@ extern "C" int freeMemory(); #pragma GCC diagnostic pop -// ADC +// ------------------------ +// MarlinHAL Class +// ------------------------ -void HAL_adc_init(); +class MarlinHAL { +public: -#define HAL_ADC_VREF 3.3 -#define HAL_ADC_RESOLUTION 10 -#define HAL_START_ADC(pin) HAL_adc_start_conversion(pin) -#define HAL_READ_ADC() HAL_adc_get_result() -#define HAL_ADC_READY() true + // Earliest possible init, before setup() + MarlinHAL() {} -#define HAL_ANALOG_SELECT(pin) + // Watchdog + static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {}); + static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {}); -void HAL_adc_start_conversion(const uint8_t adc_pin); -uint16_t HAL_adc_get_result(); + static void init() {} // Called early in setup() + static void init_board() {} // Called less early in setup() + static void reboot(); // Restart the firmware from 0x0 -// PWM + // Interrupts + static bool isr_state() { return !__get_PRIMASK(); } + static void isr_on() { __enable_irq(); } + static void isr_off() { __disable_irq(); } -inline void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { analogWrite(pin, v); } + static void delay_ms(const int ms) { delay(ms); } -// Pin Map + // Tasks, called from idle() + static void idletask() {} -#define GET_PIN_MAP_PIN(index) index -#define GET_PIN_MAP_INDEX(pin) pin -#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval) + // Reset + static uint8_t get_reset_source(); + static void clear_reset_source() {} + + // Free SRAM + static int freeMemory() { return ::freeMemory(); } + + // + // ADC Methods + // + + // Called by Temperature::init once at startup + static void adc_init(); + + // Called by Temperature::init for each sensor at startup + static void adc_enable(const pin_t ch) {} + + // Begin ADC sampling on the given channel. Called from Temperature::isr! + static void adc_start(const pin_t ch); + + // Is the ADC ready for reading? + static bool adc_ready() { return true; } + + // The current value of the ADC register + static uint16_t adc_value(); + + /** + * Set the PWM duty cycle for the pin to the given value. + * No option to invert the duty cycle [default = false] + * No option to change the scale of the provided value to enable finer PWM duty control [default = 255] + */ + static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { + analogWrite(pin, v); + } + +}; diff --git a/Marlin/src/HAL/TEENSY31_32/HAL_SPI.cpp b/Marlin/src/HAL/TEENSY31_32/HAL_SPI.cpp index 415c6922..cda7e7d1 100644 --- a/Marlin/src/HAL/TEENSY31_32/HAL_SPI.cpp +++ b/Marlin/src/HAL/TEENSY31_32/HAL_SPI.cpp @@ -120,7 +120,6 @@ void spiSendBlock(uint8_t token, const uint8_t *buf) { SPI.endTransaction(); } - // Begin SPI transaction, set clock, bit order, data mode void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) { spiConfig = SPISettings(spiClock, bitOrder, dataMode); diff --git a/Marlin/src/HAL/TEENSY31_32/endstop_interrupts.h b/Marlin/src/HAL/TEENSY31_32/endstop_interrupts.h index 9c7e2104..08ffc256 100644 --- a/Marlin/src/HAL/TEENSY31_32/endstop_interrupts.h +++ b/Marlin/src/HAL/TEENSY31_32/endstop_interrupts.h @@ -47,27 +47,33 @@ void endstop_ISR() { endstops.update(); } void setup_endstop_interrupts() { #define _ATTACH(P) attachInterrupt(digitalPinToInterrupt(P), endstop_ISR, CHANGE) - TERN_(HAS_X_MAX, _ATTACH(X_MAX_PIN)); - TERN_(HAS_X_MIN, _ATTACH(X_MIN_PIN)); - TERN_(HAS_Y_MAX, _ATTACH(Y_MAX_PIN)); - TERN_(HAS_Y_MIN, _ATTACH(Y_MIN_PIN)); - TERN_(HAS_Z_MAX, _ATTACH(Z_MAX_PIN)); - TERN_(HAS_Z_MIN, _ATTACH(Z_MIN_PIN)); - TERN_(HAS_X2_MAX, _ATTACH(X2_MAX_PIN)); - TERN_(HAS_X2_MIN, _ATTACH(X2_MIN_PIN)); - TERN_(HAS_Y2_MAX, _ATTACH(Y2_MAX_PIN)); - TERN_(HAS_Y2_MIN, _ATTACH(Y2_MIN_PIN)); - TERN_(HAS_Z2_MAX, _ATTACH(Z2_MAX_PIN)); - TERN_(HAS_Z2_MIN, _ATTACH(Z2_MIN_PIN)); - TERN_(HAS_Z3_MAX, _ATTACH(Z3_MAX_PIN)); - TERN_(HAS_Z3_MIN, _ATTACH(Z3_MIN_PIN)); - TERN_(HAS_Z4_MAX, _ATTACH(Z4_MAX_PIN)); - TERN_(HAS_Z4_MIN, _ATTACH(Z4_MIN_PIN)); + TERN_(USE_X_MAX, _ATTACH(X_MAX_PIN)); + TERN_(USE_X_MIN, _ATTACH(X_MIN_PIN)); + TERN_(USE_Y_MAX, _ATTACH(Y_MAX_PIN)); + TERN_(USE_Y_MIN, _ATTACH(Y_MIN_PIN)); + TERN_(USE_Z_MAX, _ATTACH(Z_MAX_PIN)); + TERN_(USE_Z_MIN, _ATTACH(Z_MIN_PIN)); + TERN_(USE_X2_MAX, _ATTACH(X2_MAX_PIN)); + TERN_(USE_X2_MIN, _ATTACH(X2_MIN_PIN)); + TERN_(USE_Y2_MAX, _ATTACH(Y2_MAX_PIN)); + TERN_(USE_Y2_MIN, _ATTACH(Y2_MIN_PIN)); + TERN_(USE_Z2_MAX, _ATTACH(Z2_MAX_PIN)); + TERN_(USE_Z2_MIN, _ATTACH(Z2_MIN_PIN)); + TERN_(USE_Z3_MAX, _ATTACH(Z3_MAX_PIN)); + TERN_(USE_Z3_MIN, _ATTACH(Z3_MIN_PIN)); + TERN_(USE_Z4_MAX, _ATTACH(Z4_MAX_PIN)); + TERN_(USE_Z4_MIN, _ATTACH(Z4_MIN_PIN)); TERN_(HAS_Z_MIN_PROBE_PIN, _ATTACH(Z_MIN_PROBE_PIN)); - TERN_(HAS_I_MAX, _ATTACH(I_MAX_PIN)); - TERN_(HAS_I_MIN, _ATTACH(I_MIN_PIN)); - TERN_(HAS_J_MAX, _ATTACH(J_MAX_PIN)); - TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN)); - TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN)); - TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_I_MAX, _ATTACH(I_MAX_PIN)); + TERN_(USE_I_MIN, _ATTACH(I_MIN_PIN)); + TERN_(USE_J_MAX, _ATTACH(J_MAX_PIN)); + TERN_(USE_J_MIN, _ATTACH(J_MIN_PIN)); + TERN_(USE_K_MAX, _ATTACH(K_MAX_PIN)); + TERN_(USE_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(USE_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(USE_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(USE_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(USE_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(USE_W_MIN, _ATTACH(W_MIN_PIN)); } diff --git a/Marlin/src/HAL/TEENSY31_32/inc/Conditionals_LCD.h b/Marlin/src/HAL/TEENSY31_32/inc/Conditionals_LCD.h index 54ec1666..5f1c4b16 100644 --- a/Marlin/src/HAL/TEENSY31_32/inc/Conditionals_LCD.h +++ b/Marlin/src/HAL/TEENSY31_32/inc/Conditionals_LCD.h @@ -20,7 +20,3 @@ * */ #pragma once - -#if HAS_SPI_TFT || HAS_FSMC_TFT - #error "Sorry! TFT displays are not available for HAL/TEENSY31_32." -#endif diff --git a/Marlin/src/HAL/TEENSY31_32/inc/SanityCheck.h b/Marlin/src/HAL/TEENSY31_32/inc/SanityCheck.h index 1efa76b1..c5b25f2c 100644 --- a/Marlin/src/HAL/TEENSY31_32/inc/SanityCheck.h +++ b/Marlin/src/HAL/TEENSY31_32/inc/SanityCheck.h @@ -25,18 +25,26 @@ * Test TEENSY35_36 specific configuration values for errors at compile-time. */ +#if HAS_SPI_TFT || HAS_FSMC_TFT + #error "Sorry! TFT displays are not available for Teensy 3.1/3.2." +#endif + #if ENABLED(EMERGENCY_PARSER) #error "EMERGENCY_PARSER is not yet implemented for Teensy 3.1/3.2. Disable EMERGENCY_PARSER to continue." #endif #if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY - #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported on Teensy 3.1/3.2." + #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported for Teensy 3.1/3.2." #endif #if HAS_TMC_SW_SERIAL - #error "TMC220x Software Serial is not supported on Teensy 3.1/3.2." + #error "TMC220x Software Serial is not supported for Teensy 3.1/3.2." #endif #if ENABLED(POSTMORTEM_DEBUGGING) - #error "POSTMORTEM_DEBUGGING is not yet supported on Teensy 3.1/3.2." + #error "POSTMORTEM_DEBUGGING is not yet supported for Teensy 3.1/3.2." +#endif + +#if USING_PULLDOWNS + #error "PULLDOWN pin mode is not available for Teensy 3.1/3.2." #endif diff --git a/Marlin/src/HAL/TEENSY31_32/pinsDebug.h b/Marlin/src/HAL/TEENSY31_32/pinsDebug.h index d4a91ce8..741909bf 100644 --- a/Marlin/src/HAL/TEENSY31_32/pinsDebug.h +++ b/Marlin/src/HAL/TEENSY31_32/pinsDebug.h @@ -1 +1,71 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + #error "PINS_DEBUGGING is not yet supported for Teensy 3.1 / 3.2!" + +/** + * Pins Debugging for ESP32 + * + * - NUMBER_PINS_TOTAL + * - MULTI_NAME_PAD + * - getPinByIndex(index) + * - printPinNameByIndex(index) + * - getPinIsDigitalByIndex(index) + * - digitalPinToAnalogIndex(pin) + * - getValidPinMode(pin) + * - isValidPin(pin) + * - isAnalogPin(pin) + * - digitalRead_mod(pin) + * - pwm_status(pin) + * - printPinPWM(pin) + * - printPinPort(pin) + * - printPinNumber(pin) + * - printPinAnalog(pin) + */ + +#define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS +#define MULTI_NAME_PAD 16 // space needed to be pretty if not first name assigned to a pin + +#define digitalRead_mod(P) extDigitalRead(P) +#define printPinNameByIndex(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) +#define printPinNumber(P) do{ sprintf_P(buffer, PSTR("%02d"), P); SERIAL_ECHO(buffer); }while(0) +#define printPinAnalog(P) do{ sprintf_P(buffer, PSTR(" (A%2d) "), digitalPinToAnalogIndex(P)); SERIAL_ECHO(buffer); }while(0) +#define getPinByIndex(x) pin_array[x].pin +#define getPinIsDigitalByIndex(x) pin_array[x].is_digital +#define isValidPin(P) (P >= 0 && P < pin_t(NUMBER_PINS_TOTAL)) +#define digitalPinToAnalogIndex(P) int(P - analogInputToDigitalPin(0)) +#define isAnalogPin(P) WITHIN(P, pin_t(analogInputToDigitalPin(0)), pin_t(analogInputToDigitalPin(NUM_ANALOG_INPUTS - 1))) +bool pwm_status(const pin_t) { return false; } + +void printPinPort(const pin_t) {} + +static bool getValidPinMode(const pin_t pin) { + return isValidPin(pin) /* && !IS_INPUT(pin) */ ; +} + +void printPinPWM(const int32_t pin) { + if (pwm_status(pin)) { + //uint32_t chan = g_APinDescription[pin].ulPWMChannel TODO when fast pwm is operative; + //SERIAL_ECHOPGM("PWM = ", duty); + } +} diff --git a/Marlin/src/HAL/TEENSY31_32/timers.h b/Marlin/src/HAL/TEENSY31_32/timers.h index 3b073d63..3bbc2421 100644 --- a/Marlin/src/HAL/TEENSY31_32/timers.h +++ b/Marlin/src/HAL/TEENSY31_32/timers.h @@ -41,7 +41,7 @@ typedef uint32_t hal_timer_t; #define FTM0_TIMER_PRESCALE_BITS 0b011 #define FTM1_TIMER_PRESCALE_BITS 0b010 -#define FTM0_TIMER_RATE (F_BUS / (FTM0_TIMER_PRESCALE)) // 60MHz / 8 = 7500kHz +#define FTM0_TIMER_RATE (F_BUS / (FTM0_TIMER_PRESCALE)) // 60MHz / 8 = 7.5MHz #define FTM1_TIMER_RATE (F_BUS / (FTM1_TIMER_PRESCALE)) // 60MHz / 4 = 15MHz #define HAL_TIMER_RATE (FTM0_TIMER_RATE) @@ -110,4 +110,4 @@ void HAL_timer_disable_interrupt(const uint8_t timer_num); bool HAL_timer_interrupt_enabled(const uint8_t timer_num); void HAL_timer_isr_prologue(const uint8_t timer_num); -#define HAL_timer_isr_epilogue(T) +#define HAL_timer_isr_epilogue(T) NOOP diff --git a/Marlin/src/HAL/TEENSY31_32/watchdog.cpp b/Marlin/src/HAL/TEENSY31_32/watchdog.cpp deleted file mode 100644 index 5e212361..00000000 --- a/Marlin/src/HAL/TEENSY31_32/watchdog.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * - * Based on Sprinter and grbl. - * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -#ifdef __MK20DX256__ - -#include "../../inc/MarlinConfig.h" - -#if ENABLED(USE_WATCHDOG) - -#include "watchdog.h" - -#define WDT_TIMEOUT_MS TERN(WATCHDOG_DURATION_8S, 8000, 4000) // 4 or 8 second timeout - -void watchdog_init() { - WDOG_TOVALH = 0; - WDOG_TOVALL = WDT_TIMEOUT_MS; - WDOG_STCTRLH = WDOG_STCTRLH_WDOGEN; -} - -#endif // USE_WATCHDOG - -#endif // __MK20DX256__ diff --git a/Marlin/src/HAL/TEENSY35_36/HAL.cpp b/Marlin/src/HAL/TEENSY35_36/HAL.cpp index 046c00b5..bc02ac1c 100644 --- a/Marlin/src/HAL/TEENSY35_36/HAL.cpp +++ b/Marlin/src/HAL/TEENSY35_36/HAL.cpp @@ -31,6 +31,10 @@ #include +// ------------------------ +// Serial ports +// ------------------------ + #define _IMPLEMENT_SERIAL(X) DefaultSerial##X MSerial##X(false, Serial##X) #define IMPLEMENT_SERIAL(X) _IMPLEMENT_SERIAL(X) #if WITHIN(SERIAL_PORT, 0, 3) @@ -39,42 +43,13 @@ USBSerialType USBSerial(false, SerialUSB); -uint16_t HAL_adc_result, HAL_adc_select; - -static const uint8_t pin2sc1a[] = { - 5, 14, 8, 9, 13, 12, 6, 7, 15, 4, 3, 19+128, 14+128, 15+128, // 0-13 -> A0-A13 - 5, 14, 8, 9, 13, 12, 6, 7, 15, 4, // 14-23 are A0-A9 - 255, 255, 255, 255, 255, 255, 255, // 24-30 are digital only - 14+128, 15+128, 17, 18, 4+128, 5+128, 6+128, 7+128, 17+128, // 31-39 are A12-A20 - 255, 255, 255, 255, 255, 255, 255, 255, 255, // 40-48 are digital only - 10+128, 11+128, // 49-50 are A23-A24 - 255, 255, 255, 255, 255, 255, 255, // 51-57 are digital only - 255, 255, 255, 255, 255, 255, // 58-63 (sd card pins) are digital only - 3, 19+128, // 64-65 are A10-A11 - 23, 23+128,// 66-67 are A21-A22 (DAC pins) - 1, 1+128, // 68-69 are A25-A26 (unused USB host port on Teensy 3.5) - 26, // 70 is Temperature Sensor - 18+128 // 71 is Vref -}; - -/* - // disable interrupts - void cli() { noInterrupts(); } - - // enable interrupts - void sei() { interrupts(); } -*/ - -void HAL_adc_init() { - analog_init(); - while (ADC0_SC3 & ADC_SC3_CAL) {}; // Wait for calibration to finish - while (ADC1_SC3 & ADC_SC3_CAL) {}; // Wait for calibration to finish - NVIC_ENABLE_IRQ(IRQ_FTM1); -} +// ------------------------ +// MarlinHAL Class +// ------------------------ -void HAL_clear_reset_source() { } +void MarlinHAL::reboot() { _reboot_Teensyduino_(); } -uint8_t HAL_get_reset_source() { +uint8_t MarlinHAL::get_reset_source() { switch (RCM_SRS0) { case 128: return RST_POWER_ON; break; case 64: return RST_EXTERNAL; break; @@ -86,45 +61,96 @@ uint8_t HAL_get_reset_source() { return 0; } -void HAL_reboot() { _reboot_Teensyduino_(); } +// ------------------------ +// Watchdog Timer +// ------------------------ -extern "C" { - extern char __bss_end; - extern char __heap_start; - extern void* __brkval; +#if ENABLED(USE_WATCHDOG) - int freeMemory() { - int free_memory; - if ((int)__brkval == 0) - free_memory = ((int)&free_memory) - ((int)&__bss_end); - else - free_memory = ((int)&free_memory) - ((int)__brkval); - return free_memory; + #define WDT_TIMEOUT_MS TERN(WATCHDOG_DURATION_8S, 8000, 4000) // 4 or 8 second timeout + + void MarlinHAL::watchdog_init() { + WDOG_TOVALH = 0; + WDOG_TOVALL = WDT_TIMEOUT_MS; + WDOG_STCTRLH = WDOG_STCTRLH_WDOGEN; } + + void MarlinHAL::watchdog_refresh() { + // Watchdog refresh sequence + WDOG_REFRESH = 0xA602; + WDOG_REFRESH = 0xB480; + } + +#endif + +// ------------------------ +// ADC +// ------------------------ + +int8_t MarlinHAL::adc_select; + +void MarlinHAL::adc_init() { + analog_init(); + while (ADC0_SC3 & ADC_SC3_CAL) { /* Wait for calibration to finish */ } + while (ADC1_SC3 & ADC_SC3_CAL) { /* Wait for calibration to finish */ } + NVIC_ENABLE_IRQ(IRQ_FTM1); } -void HAL_adc_start_conversion(const uint8_t adc_pin) { +void MarlinHAL::adc_start(const pin_t adc_pin) { + static const uint8_t pin2sc1a[] = { + 5, 14, 8, 9, 13, 12, 6, 7, 15, 4, 3, 19+128, 14+128, 15+128, // 0-13 -> A0-A13 + 5, 14, 8, 9, 13, 12, 6, 7, 15, 4, // 14-23 are A0-A9 + 255, 255, 255, 255, 255, 255, 255, // 24-30 are digital only + 14+128, 15+128, 17, 18, 4+128, 5+128, 6+128, 7+128, 17+128, // 31-39 are A12-A20 + 255, 255, 255, 255, 255, 255, 255, 255, 255, // 40-48 are digital only + 10+128, 11+128, // 49-50 are A23-A24 + 255, 255, 255, 255, 255, 255, 255, // 51-57 are digital only + 255, 255, 255, 255, 255, 255, // 58-63 (sd card pins) are digital only + 3, 19+128, // 64-65 are A10-A11 + 23, 23+128,// 66-67 are A21-A22 (DAC pins) + 1, 1+128, // 68-69 are A25-A26 (unused USB host port on Teensy 3.5) + 26, // 70 is Temperature Sensor + 18+128 // 71 is Vref + }; const uint16_t pin = pin2sc1a[adc_pin]; if (pin == 0xFF) { - // Digital only - HAL_adc_select = -1; + adc_select = -1; // Digital only } else if (pin & 0x80) { - HAL_adc_select = 1; + adc_select = 1; ADC1_SC1A = pin & 0x7F; } else { - HAL_adc_select = 0; + adc_select = 0; ADC0_SC1A = pin; } } -uint16_t HAL_adc_get_result() { - switch (HAL_adc_select) { +uint16_t MarlinHAL::adc_value() { + switch (adc_select) { case 0: return ADC0_RA; case 1: return ADC1_RA; } return 0; } +// ------------------------ +// Free Memory Accessor +// ------------------------ + +extern "C" { + extern char __bss_end; + extern char __heap_start; + extern void* __brkval; + + int freeMemory() { + int free_memory; + if ((int)__brkval == 0) + free_memory = ((int)&free_memory) - ((int)&__bss_end); + else + free_memory = ((int)&free_memory) - ((int)__brkval); + return free_memory; + } +} + #endif // __MK64FX512__ || __MK66FX1M0__ diff --git a/Marlin/src/HAL/TEENSY35_36/HAL.h b/Marlin/src/HAL/TEENSY35_36/HAL.h index 892eb2d3..44eafe5e 100644 --- a/Marlin/src/HAL/TEENSY35_36/HAL.h +++ b/Marlin/src/HAL/TEENSY35_36/HAL.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,15 +32,10 @@ #include "../shared/HAL_SPI.h" #include "fastio.h" -#include "watchdog.h" #include #include -#define CPU_ST7920_DELAY_1 600 -#define CPU_ST7920_DELAY_2 750 -#define CPU_ST7920_DELAY_3 750 - // ------------------------ // Defines // ------------------------ @@ -53,6 +48,17 @@ #define IS_TEENSY35 1 #endif +#define CPU_ST7920_DELAY_1 600 +#define CPU_ST7920_DELAY_2 750 +#define CPU_ST7920_DELAY_3 750 + +#undef sq +#define sq(x) ((x)*(x)) + +// ------------------------ +// Serial ports +// ------------------------ + #include "../../core/serial_hook.h" #define Serial0 Serial @@ -76,34 +82,43 @@ extern USBSerialType USBSerial; #error "SERIAL_PORT must be from 0 to 3, or -1 for Native USB." #endif -#define HAL_SERVO_LIB libServo +// ------------------------ +// Types +// ------------------------ -typedef int8_t pin_t; +class libServo; +typedef libServo hal_servo_t; -#ifndef analogInputToDigitalPin - #define analogInputToDigitalPin(p) ((p < 12U) ? (p) + 54U : -1) -#endif +typedef int8_t pin_t; -#define CRITICAL_SECTION_START() uint32_t primask = __get_primask(); __disable_irq() -#define CRITICAL_SECTION_END() if (!primask) __enable_irq() -#define ISRS_ENABLED() (!__get_primask()) -#define ENABLE_ISRS() __enable_irq() -#define DISABLE_ISRS() __disable_irq() +// ------------------------ +// Interrupts +// ------------------------ -#undef sq -#define sq(x) ((x)*(x)) +#define CRITICAL_SECTION_START() const bool irqon = !__get_primask(); __disable_irq() +#define CRITICAL_SECTION_END() if (irqon) __enable_irq() -inline void HAL_init() {} +// ------------------------ +// ADC +// ------------------------ -// Clear reset reason -void HAL_clear_reset_source(); +#ifndef analogInputToDigitalPin + #define analogInputToDigitalPin(p) pin_t((p < 12U) ? (p) + 54U : -1) +#endif -// Reset reason -uint8_t HAL_get_reset_source(); +#define HAL_ADC_VREF_MV 3300 +#define HAL_ADC_RESOLUTION 10 -void HAL_reboot(); +// +// Pin Mapping for M42, M43, M226 +// +#define GET_PIN_MAP_PIN(index) index +#define GET_PIN_MAP_INDEX(pin) pin +#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval) -FORCE_INLINE void _delay_ms(const int delay_ms) { delay(delay_ms); } +// ------------------------ +// Free Memory Accessor +// ------------------------ #pragma GCC diagnostic push #if GCC_VERSION <= 50000 @@ -114,27 +129,69 @@ extern "C" int freeMemory(); #pragma GCC diagnostic pop -// ADC +// ------------------------ +// MarlinHAL Class +// ------------------------ -void HAL_adc_init(); +class MarlinHAL { +public: -#define HAL_ADC_VREF 3.3 -#define HAL_ADC_RESOLUTION 10 -#define HAL_START_ADC(pin) HAL_adc_start_conversion(pin) -#define HAL_READ_ADC() HAL_adc_get_result() -#define HAL_ADC_READY() true + // Earliest possible init, before setup() + MarlinHAL() {} -#define HAL_ANALOG_SELECT(pin) + // Watchdog + static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {}); + static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {}); -void HAL_adc_start_conversion(const uint8_t adc_pin); -uint16_t HAL_adc_get_result(); + static void init() {} // Called early in setup() + static void init_board() {} // Called less early in setup() + static void reboot(); // Restart the firmware from 0x0 -// PWM + // Interrupts + static bool isr_state() { return true; } + static void isr_on() { __enable_irq(); } + static void isr_off() { __disable_irq(); } -inline void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { analogWrite(pin, v); } + static void delay_ms(const int ms) { delay(ms); } -// Pin Map + // Tasks, called from idle() + static void idletask() {} -#define GET_PIN_MAP_PIN(index) index -#define GET_PIN_MAP_INDEX(pin) pin -#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval) + // Reset + static uint8_t get_reset_source(); + static void clear_reset_source() {} + + // Free SRAM + static int freeMemory() { return ::freeMemory(); } + + // + // ADC Methods + // + + static int8_t adc_select; + + // Called by Temperature::init once at startup + static void adc_init(); + + // Called by Temperature::init for each sensor at startup + static void adc_enable(const pin_t) {} + + // Begin ADC sampling on the given pin. Called from Temperature::isr! + static void adc_start(const pin_t pin); + + // Is the ADC ready for reading? + static bool adc_ready() { return true; } + + // The current value of the ADC register + static uint16_t adc_value(); + + /** + * Set the PWM duty cycle for the pin to the given value. + * No option to invert the duty cycle [default = false] + * No option to change the scale of the provided value to enable finer PWM duty control [default = 255] + */ + static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { + analogWrite(pin, v); + } + +}; diff --git a/Marlin/src/HAL/TEENSY35_36/eeprom.cpp b/Marlin/src/HAL/TEENSY35_36/eeprom.cpp index b80e93b5..a2afa453 100644 --- a/Marlin/src/HAL/TEENSY35_36/eeprom.cpp +++ b/Marlin/src/HAL/TEENSY35_36/eeprom.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2016 Victor Perez victor_pv@hotmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Marlin/src/HAL/TEENSY35_36/endstop_interrupts.h b/Marlin/src/HAL/TEENSY35_36/endstop_interrupts.h index a3002488..6ba7d7fc 100644 --- a/Marlin/src/HAL/TEENSY35_36/endstop_interrupts.h +++ b/Marlin/src/HAL/TEENSY35_36/endstop_interrupts.h @@ -46,27 +46,33 @@ void endstop_ISR() { endstops.update(); } */ void setup_endstop_interrupts() { #define _ATTACH(P) attachInterrupt(digitalPinToInterrupt(P), endstop_ISR, CHANGE) - TERN_(HAS_X_MAX, _ATTACH(X_MAX_PIN)); - TERN_(HAS_X_MIN, _ATTACH(X_MIN_PIN)); - TERN_(HAS_Y_MAX, _ATTACH(Y_MAX_PIN)); - TERN_(HAS_Y_MIN, _ATTACH(Y_MIN_PIN)); - TERN_(HAS_Z_MAX, _ATTACH(Z_MAX_PIN)); - TERN_(HAS_Z_MIN, _ATTACH(Z_MIN_PIN)); - TERN_(HAS_X2_MAX, _ATTACH(X2_MAX_PIN)); - TERN_(HAS_X2_MIN, _ATTACH(X2_MIN_PIN)); - TERN_(HAS_Y2_MAX, _ATTACH(Y2_MAX_PIN)); - TERN_(HAS_Y2_MIN, _ATTACH(Y2_MIN_PIN)); - TERN_(HAS_Z2_MAX, _ATTACH(Z2_MAX_PIN)); - TERN_(HAS_Z2_MIN, _ATTACH(Z2_MIN_PIN)); - TERN_(HAS_Z3_MAX, _ATTACH(Z3_MAX_PIN)); - TERN_(HAS_Z3_MIN, _ATTACH(Z3_MIN_PIN)); - TERN_(HAS_Z4_MAX, _ATTACH(Z4_MAX_PIN)); - TERN_(HAS_Z4_MIN, _ATTACH(Z4_MIN_PIN)); + TERN_(USE_X_MAX, _ATTACH(X_MAX_PIN)); + TERN_(USE_X_MIN, _ATTACH(X_MIN_PIN)); + TERN_(USE_Y_MAX, _ATTACH(Y_MAX_PIN)); + TERN_(USE_Y_MIN, _ATTACH(Y_MIN_PIN)); + TERN_(USE_Z_MAX, _ATTACH(Z_MAX_PIN)); + TERN_(USE_Z_MIN, _ATTACH(Z_MIN_PIN)); + TERN_(USE_X2_MAX, _ATTACH(X2_MAX_PIN)); + TERN_(USE_X2_MIN, _ATTACH(X2_MIN_PIN)); + TERN_(USE_Y2_MAX, _ATTACH(Y2_MAX_PIN)); + TERN_(USE_Y2_MIN, _ATTACH(Y2_MIN_PIN)); + TERN_(USE_Z2_MAX, _ATTACH(Z2_MAX_PIN)); + TERN_(USE_Z2_MIN, _ATTACH(Z2_MIN_PIN)); + TERN_(USE_Z3_MAX, _ATTACH(Z3_MAX_PIN)); + TERN_(USE_Z3_MIN, _ATTACH(Z3_MIN_PIN)); + TERN_(USE_Z4_MAX, _ATTACH(Z4_MAX_PIN)); + TERN_(USE_Z4_MIN, _ATTACH(Z4_MIN_PIN)); TERN_(HAS_Z_MIN_PROBE_PIN, _ATTACH(Z_MIN_PROBE_PIN)); - TERN_(HAS_I_MAX, _ATTACH(I_MAX_PIN)); - TERN_(HAS_I_MIN, _ATTACH(I_MIN_PIN)); - TERN_(HAS_J_MAX, _ATTACH(J_MAX_PIN)); - TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN)); - TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN)); - TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_I_MAX, _ATTACH(I_MAX_PIN)); + TERN_(USE_I_MIN, _ATTACH(I_MIN_PIN)); + TERN_(USE_J_MAX, _ATTACH(J_MAX_PIN)); + TERN_(USE_J_MIN, _ATTACH(J_MIN_PIN)); + TERN_(USE_K_MAX, _ATTACH(K_MAX_PIN)); + TERN_(USE_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(USE_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(USE_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(USE_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(USE_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(USE_W_MIN, _ATTACH(W_MIN_PIN)); } diff --git a/Marlin/src/HAL/TEENSY35_36/inc/Conditionals_LCD.h b/Marlin/src/HAL/TEENSY35_36/inc/Conditionals_LCD.h index 632ee533..5f1c4b16 100644 --- a/Marlin/src/HAL/TEENSY35_36/inc/Conditionals_LCD.h +++ b/Marlin/src/HAL/TEENSY35_36/inc/Conditionals_LCD.h @@ -20,7 +20,3 @@ * */ #pragma once - -#if HAS_SPI_TFT || HAS_FSMC_TFT - #error "Sorry! TFT displays are not available for HAL/TEENSY35_36." -#endif diff --git a/Marlin/src/HAL/TEENSY35_36/inc/SanityCheck.h b/Marlin/src/HAL/TEENSY35_36/inc/SanityCheck.h index eef28505..843905a8 100644 --- a/Marlin/src/HAL/TEENSY35_36/inc/SanityCheck.h +++ b/Marlin/src/HAL/TEENSY35_36/inc/SanityCheck.h @@ -25,18 +25,26 @@ * Test TEENSY35_36 specific configuration values for errors at compile-time. */ +#if HAS_SPI_TFT || HAS_FSMC_TFT + #error "Sorry! TFT displays are not available for Teensy 3.5/3.6." +#endif + #if ENABLED(EMERGENCY_PARSER) #error "EMERGENCY_PARSER is not yet implemented for Teensy 3.5/3.6. Disable EMERGENCY_PARSER to continue." #endif #if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY - #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported on Teensy 3.5/3.6." + #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported for Teensy 3.5/3.6." #endif #if HAS_TMC_SW_SERIAL - #error "TMC220x Software Serial is not supported on Teensy 3.5/3.6." + #error "TMC220x Software Serial is not supported for Teensy 3.5/3.6." #endif #if ENABLED(POSTMORTEM_DEBUGGING) - #error "POSTMORTEM_DEBUGGING is not yet supported on Teensy 3.5/3.6." + #error "POSTMORTEM_DEBUGGING is not yet supported for Teensy 3.5/3.6." +#endif + +#if USING_PULLDOWNS + #error "PULLDOWN pin mode is not available for Teensy 3.5/3.6." #endif diff --git a/Marlin/src/HAL/TEENSY35_36/pinsDebug.h b/Marlin/src/HAL/TEENSY35_36/pinsDebug.h index 7a2e1d6e..f0f61b8b 100644 --- a/Marlin/src/HAL/TEENSY35_36/pinsDebug.h +++ b/Marlin/src/HAL/TEENSY35_36/pinsDebug.h @@ -22,7 +22,23 @@ #pragma once /** - * HAL Pins Debugging for Teensy 3.5 (MK64FX512) and Teensy 3.6 (MK66FX1M0) + * Pins Debugging for Teensy 3.5 (MK64FX512) and Teensy 3.6 (MK66FX1M0) + * + * - NUMBER_PINS_TOTAL + * - MULTI_NAME_PAD + * - getPinByIndex(index) + * - printPinNameByIndex(index) + * - getPinIsDigitalByIndex(index) + * - digitalPinToAnalogIndex(pin) + * - getValidPinMode(pin) + * - isValidPin(pin) + * - isAnalogPin(pin) + * - digitalRead_mod(pin) + * - pwm_status(pin) + * - printPinPWM(pin) + * - printPinPort(pin) + * - printPinNumber(pin) + * - printPinAnalog(pin) */ #define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS @@ -53,14 +69,23 @@ #define TPM1_CH1_PIN 17 #endif -#define IS_ANALOG(P) ((P) >= analogInputToDigitalPin(0) && (P) <= analogInputToDigitalPin(9)) || ((P) >= analogInputToDigitalPin(12) && (P) <= analogInputToDigitalPin(20)) +#define getPinByIndex(x) pin_array[x].pin +#define printPinNameByIndex(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) +#define getPinIsDigitalByIndex(x) pin_array[x].is_digital +#define digitalPinToAnalogIndex(P) int(P - analogInputToDigitalPin(0)) +#define getValidPinMode(P) (isValidPin(P) && IS_OUTPUT(P)) +#define isValidPin(P) (P >= 0 && P < pin_t(NUMBER_PINS_TOTAL)) +#define printPinNumber(P) do{ sprintf_P(buffer, PSTR("%02d"), P); SERIAL_ECHO(buffer); }while(0) +#define printPinAnalog(P) do{ sprintf_P(buffer, PSTR(" (A%2d) "), digitalPinToAnalogIndex(P)); SERIAL_ECHO(buffer); }while(0) + +#define isAnalogPin(P) ((P) >= analogInputToDigitalPin(0) && (P) <= analogInputToDigitalPin(9)) || ((P) >= analogInputToDigitalPin(12) && (P) <= analogInputToDigitalPin(20)) -void HAL_print_analog_pin(char buffer[], int8_t pin) { +void printAnalogPin(char buffer[], int8_t pin) { if (pin <= 23) sprintf_P(buffer, PSTR("(A%2d) "), int(pin - 14)); else if (pin <= 39) sprintf_P(buffer, PSTR("(A%2d) "), int(pin - 19)); } -void HAL_analog_pin_state(char buffer[], int8_t pin) { +void analog_pin_state(char buffer[], int8_t pin) { if (pin <= 23) sprintf_P(buffer, PSTR("Analog in =% 5d"), analogRead(pin - 14)); else if (pin <= 39) sprintf_P(buffer, PSTR("Analog in =% 5d"), analogRead(pin - 19)); } @@ -77,7 +102,7 @@ void HAL_analog_pin_state(char buffer[], int8_t pin) { * Print a pin's PWM status. * Return true if it's currently a PWM pin. */ -bool HAL_pwm_status(int8_t pin) { +bool pwm_status(const int8_t pin) { char buffer[20]; // for the sprintf statements switch (pin) { FTM_CASE(0,0); @@ -108,4 +133,6 @@ bool HAL_pwm_status(int8_t pin) { SERIAL_ECHOPGM(" "); } -static void HAL_pwm_details(uint8_t pin) { /* TODO */ } +void printPinPWM(const pin_t) { /* TODO */ } + +void printPinPort(const pin_t) {} diff --git a/Marlin/src/HAL/TEENSY35_36/timers.h b/Marlin/src/HAL/TEENSY35_36/timers.h index 6c342bbe..3536b622 100644 --- a/Marlin/src/HAL/TEENSY35_36/timers.h +++ b/Marlin/src/HAL/TEENSY35_36/timers.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -109,4 +110,4 @@ void HAL_timer_disable_interrupt(const uint8_t timer_num); bool HAL_timer_interrupt_enabled(const uint8_t timer_num); void HAL_timer_isr_prologue(const uint8_t timer_num); -#define HAL_timer_isr_epilogue(T) +#define HAL_timer_isr_epilogue(T) NOOP diff --git a/Marlin/src/HAL/TEENSY35_36/watchdog.cpp b/Marlin/src/HAL/TEENSY35_36/watchdog.cpp deleted file mode 100644 index 3825e279..00000000 --- a/Marlin/src/HAL/TEENSY35_36/watchdog.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * - * Based on Sprinter and grbl. - * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -#if defined(__MK64FX512__) || defined(__MK66FX1M0__) - -#include "../../inc/MarlinConfig.h" - -#if ENABLED(USE_WATCHDOG) - -#include "watchdog.h" - -#define WDT_TIMEOUT_MS TERN(WATCHDOG_DURATION_8S, 8000, 4000) // 4 or 8 second timeout - -void watchdog_init() { - WDOG_TOVALH = 0; - WDOG_TOVALL = WDT_TIMEOUT_MS; - WDOG_STCTRLH = WDOG_STCTRLH_WDOGEN; -} - -#endif // USE_WATCHDOG - -#endif // __MK64FX512__ || __MK66FX1M0__ diff --git a/Marlin/src/HAL/TEENSY40_41/HAL.cpp b/Marlin/src/HAL/TEENSY40_41/HAL.cpp index 270bee0d..4dd5c367 100644 --- a/Marlin/src/HAL/TEENSY40_41/HAL.cpp +++ b/Marlin/src/HAL/TEENSY40_41/HAL.cpp @@ -33,82 +33,44 @@ #include "timers.h" #include +// ------------------------ +// Serial ports +// ------------------------ + #define _IMPLEMENT_SERIAL(X) DefaultSerial##X MSerial##X(false, Serial##X) #define IMPLEMENT_SERIAL(X) _IMPLEMENT_SERIAL(X) -#if WITHIN(SERIAL_PORT, 0, 3) +#if WITHIN(SERIAL_PORT, 0, 8) IMPLEMENT_SERIAL(SERIAL_PORT); #endif -USBSerialType USBSerial(false, SerialUSB); - -uint16_t HAL_adc_result, HAL_adc_select; - -static const uint8_t pin2sc1a[] = { - 0x07, // 0/A0 AD_B1_02 - 0x08, // 1/A1 AD_B1_03 - 0x0C, // 2/A2 AD_B1_07 - 0x0B, // 3/A3 AD_B1_06 - 0x06, // 4/A4 AD_B1_01 - 0x05, // 5/A5 AD_B1_00 - 0x0F, // 6/A6 AD_B1_10 - 0x00, // 7/A7 AD_B1_11 - 0x0D, // 8/A8 AD_B1_08 - 0x0E, // 9/A9 AD_B1_09 - 0x01, // 24/A10 AD_B0_12 - 0x02, // 25/A11 AD_B0_13 - 0x83, // 26/A12 AD_B1_14 - only on ADC2, 3 - 0x84, // 27/A13 AD_B1_15 - only on ADC2, 4 - 0x07, // 14/A0 AD_B1_02 - 0x08, // 15/A1 AD_B1_03 - 0x0C, // 16/A2 AD_B1_07 - 0x0B, // 17/A3 AD_B1_06 - 0x06, // 18/A4 AD_B1_01 - 0x05, // 19/A5 AD_B1_00 - 0x0F, // 20/A6 AD_B1_10 - 0x00, // 21/A7 AD_B1_11 - 0x0D, // 22/A8 AD_B1_08 - 0x0E, // 23/A9 AD_B1_09 - 0x01, // 24/A10 AD_B0_12 - 0x02, // 25/A11 AD_B0_13 - 0x83, // 26/A12 AD_B1_14 - only on ADC2, 3 - 0x84, // 27/A13 AD_B1_15 - only on ADC2, 4 - #ifdef ARDUINO_TEENSY41 - 0xFF, // 28 - 0xFF, // 29 - 0xFF, // 30 - 0xFF, // 31 - 0xFF, // 32 - 0xFF, // 33 - 0xFF, // 34 - 0xFF, // 35 - 0xFF, // 36 - 0xFF, // 37 - 0x81, // 38/A14 AD_B1_12 - only on ADC2, 1 - 0x82, // 39/A15 AD_B1_13 - only on ADC2, 2 - 0x09, // 40/A16 AD_B1_04 - 0x0A, // 41/A17 AD_B1_05 +#ifdef SERIAL_PORT_2 + #if WITHIN(SERIAL_PORT_2, 0, 8) + IMPLEMENT_SERIAL(SERIAL_PORT_2); #endif -}; - -/* -// disable interrupts -void cli() { noInterrupts(); } +#endif +#ifdef SERIAL_PORT_3 + #if WITHIN(SERIAL_PORT_3, 0, 8) + IMPLEMENT_SERIAL(SERIAL_PORT_3); + #endif +#endif +USBSerialType USBSerial(false, SerialUSB); -// enable interrupts -void sei() { interrupts(); } -*/ +// ------------------------ +// FastIO +// ------------------------ -void HAL_adc_init() { - analog_init(); - while (ADC1_GC & ADC_GC_CAL) ; - while (ADC2_GC & ADC_GC_CAL) ; +bool is_output(pin_t pin) { + const struct digital_pin_bitband_and_config_table_struct *p; + p = digital_pin_to_info_PGM + pin; + return (*(p->reg + 1) & p->mask); } -void HAL_clear_reset_source() { - uint32_t reset_source = SRC_SRSR; - SRC_SRSR = reset_source; -} +// ------------------------ +// MarlinHAL Class +// ------------------------ -uint8_t HAL_get_reset_source() { +void MarlinHAL::reboot() { _reboot_Teensyduino_(); } + +uint8_t MarlinHAL::get_reset_source() { switch (SRC_SRSR & 0xFF) { case 1: return RST_POWER_ON; break; case 2: return RST_SOFTWARE; break; @@ -121,57 +83,138 @@ uint8_t HAL_get_reset_source() { return 0; } -void HAL_reboot() { _reboot_Teensyduino_(); } +void MarlinHAL::clear_reset_source() { + uint32_t reset_source = SRC_SRSR; + SRC_SRSR = reset_source; +} -#define __bss_end _ebss +// ------------------------ +// Watchdog Timer +// ------------------------ -extern "C" { - extern char __bss_end; - extern char __heap_start; - extern void* __brkval; +#if ENABLED(USE_WATCHDOG) - // Doesn't work on Teensy 4.x - uint32_t freeMemory() { - uint32_t free_memory; - if ((uint32_t)__brkval == 0) - free_memory = ((uint32_t)&free_memory) - ((uint32_t)&__bss_end); - else - free_memory = ((uint32_t)&free_memory) - ((uint32_t)__brkval); - return free_memory; + #define WDT_TIMEOUT TERN(WATCHDOG_DURATION_8S, 8, 4) // 4 or 8 second timeout + + constexpr uint8_t timeoutval = (WDT_TIMEOUT - 0.5f) / 0.5f; + + void MarlinHAL::watchdog_init() { + CCM_CCGR3 |= CCM_CCGR3_WDOG1(3); // enable WDOG1 clocks + WDOG1_WMCR = 0; // disable power down PDE + WDOG1_WCR |= WDOG_WCR_SRS | WDOG_WCR_WT(timeoutval); + WDOG1_WCR |= WDOG_WCR_WDE | WDOG_WCR_WDT | WDOG_WCR_SRE; } + + void MarlinHAL::watchdog_refresh() { + // Watchdog refresh sequence + WDOG1_WSR = 0x5555; + WDOG1_WSR = 0xAAAA; + } + +#endif + +// ------------------------ +// ADC +// ------------------------ + +int8_t MarlinHAL::adc_select; + +void MarlinHAL::adc_init() { + analog_init(); + while (ADC1_GC & ADC_GC_CAL) { /* wait */ } + while (ADC2_GC & ADC_GC_CAL) { /* wait */ } } -void HAL_adc_start_conversion(const uint8_t adc_pin) { +void MarlinHAL::adc_start(const pin_t adc_pin) { + static const uint8_t pin2sc1a[] = { + 0x07, // 0/A0 AD_B1_02 + 0x08, // 1/A1 AD_B1_03 + 0x0C, // 2/A2 AD_B1_07 + 0x0B, // 3/A3 AD_B1_06 + 0x06, // 4/A4 AD_B1_01 + 0x05, // 5/A5 AD_B1_00 + 0x0F, // 6/A6 AD_B1_10 + 0x00, // 7/A7 AD_B1_11 + 0x0D, // 8/A8 AD_B1_08 + 0x0E, // 9/A9 AD_B1_09 + 0x01, // 24/A10 AD_B0_12 + 0x02, // 25/A11 AD_B0_13 + 0x83, // 26/A12 AD_B1_14 - only on ADC2, 3 + 0x84, // 27/A13 AD_B1_15 - only on ADC2, 4 + 0x07, // 14/A0 AD_B1_02 + 0x08, // 15/A1 AD_B1_03 + 0x0C, // 16/A2 AD_B1_07 + 0x0B, // 17/A3 AD_B1_06 + 0x06, // 18/A4 AD_B1_01 + 0x05, // 19/A5 AD_B1_00 + 0x0F, // 20/A6 AD_B1_10 + 0x00, // 21/A7 AD_B1_11 + 0x0D, // 22/A8 AD_B1_08 + 0x0E, // 23/A9 AD_B1_09 + 0x01, // 24/A10 AD_B0_12 + 0x02, // 25/A11 AD_B0_13 + 0x83, // 26/A12 AD_B1_14 - only on ADC2, 3 + 0x84, // 27/A13 AD_B1_15 - only on ADC2, 4 + #ifdef ARDUINO_TEENSY41 + 0xFF, // 28 + 0xFF, // 29 + 0xFF, // 30 + 0xFF, // 31 + 0xFF, // 32 + 0xFF, // 33 + 0xFF, // 34 + 0xFF, // 35 + 0xFF, // 36 + 0xFF, // 37 + 0x81, // 38/A14 AD_B1_12 - only on ADC2, 1 + 0x82, // 39/A15 AD_B1_13 - only on ADC2, 2 + 0x09, // 40/A16 AD_B1_04 + 0x0A, // 41/A17 AD_B1_05 + #endif + }; const uint16_t pin = pin2sc1a[adc_pin]; if (pin == 0xFF) { - HAL_adc_select = -1; // Digital only + adc_select = -1; // Digital only } else if (pin & 0x80) { - HAL_adc_select = 1; + adc_select = 1; ADC2_HC0 = pin & 0x7F; } else { - HAL_adc_select = 0; + adc_select = 0; ADC1_HC0 = pin; } } -uint16_t HAL_adc_get_result() { - switch (HAL_adc_select) { +uint16_t MarlinHAL::adc_value() { + switch (adc_select) { case 0: - while (!(ADC1_HS & ADC_HS_COCO0)) ; // wait + while (!(ADC1_HS & ADC_HS_COCO0)) { /* wait */ } return ADC1_R0; case 1: - while (!(ADC2_HS & ADC_HS_COCO0)) ; // wait + while (!(ADC2_HS & ADC_HS_COCO0)) { /* wait */ } return ADC2_R0; } return 0; } -bool is_output(pin_t pin) { - const struct digital_pin_bitband_and_config_table_struct *p; - p = digital_pin_to_info_PGM + pin; - return (*(p->reg + 1) & p->mask); +// ------------------------ +// Free Memory Accessor +// ------------------------ + +#define __bss_end _ebss + +extern "C" { + extern char __bss_end; + extern char __heap_start; + extern void* __brkval; + + // Doesn't work on Teensy 4.x + uint32_t freeMemory() { + uint32_t free_memory; + free_memory = ((uint32_t)&free_memory) - (((uint32_t)__brkval) ?: ((uint32_t)&__bss_end)); + return free_memory; + } } #endif // __IMXRT1062__ diff --git a/Marlin/src/HAL/TEENSY40_41/HAL.h b/Marlin/src/HAL/TEENSY40_41/HAL.h index 2b730768..355d1d75 100644 --- a/Marlin/src/HAL/TEENSY40_41/HAL.h +++ b/Marlin/src/HAL/TEENSY40_41/HAL.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,7 +32,6 @@ #include "../shared/HAL_SPI.h" #include "fastio.h" -#include "watchdog.h" #include #include @@ -41,10 +40,6 @@ #include "../../feature/ethernet.h" #endif -#define CPU_ST7920_DELAY_1 600 -#define CPU_ST7920_DELAY_2 750 -#define CPU_ST7920_DELAY_3 750 - // ------------------------ // Defines // ------------------------ @@ -55,7 +50,23 @@ #define IS_TEENSY41 1 #endif +#define CPU_ST7920_DELAY_1 600 +#define CPU_ST7920_DELAY_2 750 +#define CPU_ST7920_DELAY_3 750 + +#undef sq +#define sq(x) ((x)*(x)) + +// Don't place string constants in PROGMEM +#undef PSTR +#define PSTR(str) ({static const char *data = (str); &data[0];}) + +// ------------------------ +// Serial ports +// ------------------------ + #include "../../core/serial_hook.h" + #define Serial0 Serial #define _DECLARE_SERIAL(X) \ typedef ForwardSerial1Class DefaultSerial##X; \ @@ -69,7 +80,7 @@ extern USBSerialType USBSerial; #define MSERIAL(X) _MSERIAL(X) #if SERIAL_PORT == -1 - #define MYSERIAL1 SerialUSB + #define MYSERIAL1 USBSerial #elif WITHIN(SERIAL_PORT, 0, 8) DECLARE_SERIAL(SERIAL_PORT); #define MYSERIAL1 MSERIAL(SERIAL_PORT) @@ -79,51 +90,69 @@ extern USBSerialType USBSerial; #ifdef SERIAL_PORT_2 #if SERIAL_PORT_2 == -1 - #define MYSERIAL2 usbSerial + #define MYSERIAL2 USBSerial #elif SERIAL_PORT_2 == -2 #define MYSERIAL2 ethernet.telnetClient #elif WITHIN(SERIAL_PORT_2, 0, 8) + DECLARE_SERIAL(SERIAL_PORT_2); #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) #else #error "SERIAL_PORT_2 must be from 0 to 8, or -1 for Native USB, or -2 for Ethernet." #endif #endif -#define HAL_SERVO_LIB libServo +#ifdef SERIAL_PORT_3 + #if SERIAL_PORT_3 == -1 + #define MYSERIAL3 USBSerial + #elif WITHIN(SERIAL_PORT_3, 0, 8) + DECLARE_SERIAL(SERIAL_PORT_3); + #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) + #else + #error "SERIAL_PORT_3 must be from 0 to 8, or -1 for Native USB." + #endif +#endif -typedef int8_t pin_t; +// ------------------------ +// Types +// ------------------------ -#ifndef analogInputToDigitalPin - #define analogInputToDigitalPin(p) ((p < 12U) ? (p) + 54U : -1) -#endif +class libServo; +typedef libServo hal_servo_t; -#define CRITICAL_SECTION_START() uint32_t primask = __get_primask(); __disable_irq() -#define CRITICAL_SECTION_END() if (!primask) __enable_irq() -#define ISRS_ENABLED() (!__get_primask()) -#define ENABLE_ISRS() __enable_irq() -#define DISABLE_ISRS() __disable_irq() +typedef int8_t pin_t; -#undef sq -#define sq(x) ((x)*(x)) +// ------------------------ +// Interrupts +// ------------------------ -// Don't place string constants in PROGMEM -#undef PSTR -#define PSTR(str) ({static const char *data = (str); &data[0];}) +#define CRITICAL_SECTION_START() const bool irqon = !__get_primask(); __disable_irq() +#define CRITICAL_SECTION_END() if (irqon) __enable_irq() -// Enable hooks into idle and setup for HAL -#define HAL_IDLETASK 1 -FORCE_INLINE void HAL_idletask() {} -FORCE_INLINE void HAL_init() {} +// ------------------------ +// ADC +// ------------------------ -// Clear reset reason -void HAL_clear_reset_source(); +#ifndef analogInputToDigitalPin + #define analogInputToDigitalPin(p) pin_t((p < 12U) ? (p) + 54U : -1) +#endif -// Reset reason -uint8_t HAL_get_reset_source(); +#define HAL_ADC_VREF_MV 3300 +#define HAL_ADC_RESOLUTION 10 +#define HAL_ADC_FILTERED // turn off ADC oversampling -void HAL_reboot(); +// +// Pin Mapping for M42, M43, M226 +// +#define GET_PIN_MAP_PIN(index) index +#define GET_PIN_MAP_INDEX(pin) pin +#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval) + +// FastIO +bool is_output(pin_t pin); -FORCE_INLINE void _delay_ms(const int delay_ms) { delay(delay_ms); } +// ------------------------ +// Free Memory Accessor +// ------------------------ #pragma GCC diagnostic push #if GCC_VERSION <= 50000 @@ -134,30 +163,69 @@ extern "C" uint32_t freeMemory(); #pragma GCC diagnostic pop -// ADC +// ------------------------ +// MarlinHAL Class +// ------------------------ -void HAL_adc_init(); +class MarlinHAL { +public: -#define HAL_ADC_VREF 3.3 -#define HAL_ADC_RESOLUTION 10 -#define HAL_ADC_FILTERED // turn off ADC oversampling -#define HAL_START_ADC(pin) HAL_adc_start_conversion(pin) -#define HAL_READ_ADC() HAL_adc_get_result() -#define HAL_ADC_READY() true + // Earliest possible init, before setup() + MarlinHAL() {} -#define HAL_ANALOG_SELECT(pin) + // Watchdog + static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {}); + static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {}); -void HAL_adc_start_conversion(const uint8_t adc_pin); -uint16_t HAL_adc_get_result(); + static void init() {} // Called early in setup() + static void init_board() {} // Called less early in setup() + static void reboot(); // Restart the firmware from 0x0 -// PWM + // Interrupts + static bool isr_state() { return !__get_primask(); } + static void isr_on() { __enable_irq(); } + static void isr_off() { __disable_irq(); } -inline void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { analogWrite(pin, v); } + static void delay_ms(const int ms) { delay(ms); } -// Pin Map + // Tasks, called from idle() + static void idletask() {} -#define GET_PIN_MAP_PIN(index) index -#define GET_PIN_MAP_INDEX(pin) pin -#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval) + // Reset + static uint8_t get_reset_source(); + static void clear_reset_source(); -bool is_output(pin_t pin); + // Free SRAM + static int freeMemory() { return ::freeMemory(); } + + // + // ADC Methods + // + + static int8_t adc_select; + + // Called by Temperature::init once at startup + static void adc_init(); + + // Called by Temperature::init for each sensor at startup + static void adc_enable(const pin_t pin) {} + + // Begin ADC sampling on the given pin. Called from Temperature::isr! + static void adc_start(const pin_t pin); + + // Is the ADC ready for reading? + static bool adc_ready() { return true; } + + // The current value of the ADC register + static uint16_t adc_value(); + + /** + * Set the PWM duty cycle for the pin to the given value. + * No option to invert the duty cycle [default = false] + * No option to change the scale of the provided value to enable finer PWM duty control [default = 255] + */ + static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { + analogWrite(pin, v); + } + +}; diff --git a/Marlin/src/HAL/TEENSY40_41/eeprom.cpp b/Marlin/src/HAL/TEENSY40_41/eeprom.cpp index 3cd376ed..87f7dd3c 100644 --- a/Marlin/src/HAL/TEENSY40_41/eeprom.cpp +++ b/Marlin/src/HAL/TEENSY40_41/eeprom.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2016 Victor Perez victor_pv@hotmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Marlin/src/HAL/TEENSY40_41/endstop_interrupts.h b/Marlin/src/HAL/TEENSY40_41/endstop_interrupts.h index 4c3ddec9..c646b6be 100644 --- a/Marlin/src/HAL/TEENSY40_41/endstop_interrupts.h +++ b/Marlin/src/HAL/TEENSY40_41/endstop_interrupts.h @@ -46,27 +46,33 @@ void endstop_ISR() { endstops.update(); } */ void setup_endstop_interrupts() { #define _ATTACH(P) attachInterrupt(digitalPinToInterrupt(P), endstop_ISR, CHANGE) - TERN_(HAS_X_MAX, _ATTACH(X_MAX_PIN)); - TERN_(HAS_X_MIN, _ATTACH(X_MIN_PIN)); - TERN_(HAS_Y_MAX, _ATTACH(Y_MAX_PIN)); - TERN_(HAS_Y_MIN, _ATTACH(Y_MIN_PIN)); - TERN_(HAS_Z_MAX, _ATTACH(Z_MAX_PIN)); - TERN_(HAS_Z_MIN, _ATTACH(Z_MIN_PIN)); - TERN_(HAS_X2_MAX, _ATTACH(X2_MAX_PIN)); - TERN_(HAS_X2_MIN, _ATTACH(X2_MIN_PIN)); - TERN_(HAS_Y2_MAX, _ATTACH(Y2_MAX_PIN)); - TERN_(HAS_Y2_MIN, _ATTACH(Y2_MIN_PIN)); - TERN_(HAS_Z2_MAX, _ATTACH(Z2_MAX_PIN)); - TERN_(HAS_Z2_MIN, _ATTACH(Z2_MIN_PIN)); - TERN_(HAS_Z3_MAX, _ATTACH(Z3_MAX_PIN)); - TERN_(HAS_Z3_MIN, _ATTACH(Z3_MIN_PIN)); - TERN_(HAS_Z4_MAX, _ATTACH(Z4_MAX_PIN)); - TERN_(HAS_Z4_MIN, _ATTACH(Z4_MIN_PIN)); + TERN_(USE_X_MIN, _ATTACH(X_MIN_PIN)); + TERN_(USE_Y_MAX, _ATTACH(Y_MAX_PIN)); + TERN_(USE_Y_MIN, _ATTACH(Y_MIN_PIN)); + TERN_(USE_Z_MAX, _ATTACH(Z_MAX_PIN)); + TERN_(USE_Z_MIN, _ATTACH(Z_MIN_PIN)); + TERN_(USE_X2_MAX, _ATTACH(X2_MAX_PIN)); + TERN_(USE_X2_MIN, _ATTACH(X2_MIN_PIN)); + TERN_(USE_Y2_MAX, _ATTACH(Y2_MAX_PIN)); + TERN_(USE_Y2_MIN, _ATTACH(Y2_MIN_PIN)); + TERN_(USE_Z2_MAX, _ATTACH(Z2_MAX_PIN)); + TERN_(USE_Z2_MIN, _ATTACH(Z2_MIN_PIN)); + TERN_(USE_Z3_MAX, _ATTACH(Z3_MAX_PIN)); + TERN_(USE_Z3_MIN, _ATTACH(Z3_MIN_PIN)); + TERN_(USE_Z4_MAX, _ATTACH(Z4_MAX_PIN)); + TERN_(USE_Z4_MIN, _ATTACH(Z4_MIN_PIN)); TERN_(HAS_Z_MIN_PROBE_PIN, _ATTACH(Z_MIN_PROBE_PIN)); - TERN_(HAS_I_MAX, _ATTACH(I_MAX_PIN)); - TERN_(HAS_I_MIN, _ATTACH(I_MIN_PIN)); - TERN_(HAS_J_MAX, _ATTACH(J_MAX_PIN)); - TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN)); - TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN)); - TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_I_MAX, _ATTACH(I_MAX_PIN)); + TERN_(USE_I_MIN, _ATTACH(I_MIN_PIN)); + TERN_(USE_J_MAX, _ATTACH(J_MAX_PIN)); + TERN_(USE_J_MIN, _ATTACH(J_MIN_PIN)); + TERN_(USE_K_MAX, _ATTACH(K_MAX_PIN)); + TERN_(USE_K_MIN, _ATTACH(K_MIN_PIN)); + TERN_(USE_U_MAX, _ATTACH(U_MAX_PIN)); + TERN_(USE_U_MIN, _ATTACH(U_MIN_PIN)); + TERN_(USE_V_MAX, _ATTACH(V_MAX_PIN)); + TERN_(USE_V_MIN, _ATTACH(V_MIN_PIN)); + TERN_(USE_W_MAX, _ATTACH(W_MAX_PIN)); + TERN_(USE_W_MIN, _ATTACH(W_MIN_PIN)); + TERN_(USE_X_MAX, _ATTACH(X_MAX_PIN)); } diff --git a/Marlin/src/HAL/TEENSY40_41/fastio.h b/Marlin/src/HAL/TEENSY40_41/fastio.h index 52f991df..179f044c 100644 --- a/Marlin/src/HAL/TEENSY40_41/fastio.h +++ b/Marlin/src/HAL/TEENSY40_41/fastio.h @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2017 Victor Perez * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Marlin/src/HAL/TEENSY40_41/inc/Conditionals_LCD.h b/Marlin/src/HAL/TEENSY40_41/inc/Conditionals_LCD.h index 6a854092..5f1c4b16 100644 --- a/Marlin/src/HAL/TEENSY40_41/inc/Conditionals_LCD.h +++ b/Marlin/src/HAL/TEENSY40_41/inc/Conditionals_LCD.h @@ -20,7 +20,3 @@ * */ #pragma once - -#if HAS_SPI_TFT || HAS_FSMC_TFT - #error "Sorry! TFT displays are not available for HAL/TEENSY40_41." -#endif diff --git a/Marlin/src/HAL/TEENSY40_41/inc/SanityCheck.h b/Marlin/src/HAL/TEENSY40_41/inc/SanityCheck.h index 3d2668d7..731658b4 100644 --- a/Marlin/src/HAL/TEENSY40_41/inc/SanityCheck.h +++ b/Marlin/src/HAL/TEENSY40_41/inc/SanityCheck.h @@ -25,18 +25,22 @@ * Test TEENSY41 specific configuration values for errors at compile-time. */ +#if HAS_SPI_TFT || HAS_FSMC_TFT + #error "Sorry! TFT displays are not available for Teensy 4.0/4.1." +#endif + #if ENABLED(EMERGENCY_PARSER) #error "EMERGENCY_PARSER is not yet implemented for Teensy 4.0/4.1. Disable EMERGENCY_PARSER to continue." #endif #if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY - #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported on Teensy 4.0/4.1." + #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported for Teensy 4.0/4.1." #endif #if HAS_TMC_SW_SERIAL - #error "TMC220x Software Serial is not supported on Teensy 4.0/4.1." + #error "TMC220x Software Serial is not supported for Teensy 4.0/4.1." #endif #if ENABLED(POSTMORTEM_DEBUGGING) - #error "POSTMORTEM_DEBUGGING is not yet supported on Teensy 4.0/4.1." + #error "POSTMORTEM_DEBUGGING is not yet supported for Teensy 4.0/4.1." #endif diff --git a/Marlin/src/HAL/TEENSY40_41/pinsDebug.h b/Marlin/src/HAL/TEENSY40_41/pinsDebug.h index 94b85ea5..3307b3f7 100644 --- a/Marlin/src/HAL/TEENSY40_41/pinsDebug.h +++ b/Marlin/src/HAL/TEENSY40_41/pinsDebug.h @@ -22,25 +22,39 @@ #pragma once /** - * HAL Pins Debugging for Teensy 4.0 (IMXRT1062DVL6A) / 4.1 (IMXRT1062DVJ6A) + * Pins Debugging for Teensy 4.0 (IMXRT1062DVL6A) / 4.1 (IMXRT1062DVJ6A) + * + * - NUMBER_PINS_TOTAL + * - MULTI_NAME_PAD + * - getPinByIndex(index) + * - printPinNameByIndex(index) + * - getPinIsDigitalByIndex(index) + * - digitalPinToAnalogIndex(pin) + * - getValidPinMode(pin) + * - isValidPin(pin) + * - isAnalogPin(pin) + * - digitalRead_mod(pin) + * - pwm_status(pin) + * - printPinPWM(pin) + * - printPinPort(pin) + * - printPinNumber(pin) + * - printPinAnalog(pin) */ #warning "PINS_DEBUGGING is not fully supported for Teensy 4.0 / 4.1 so 'M43' may cause hangs." #define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS -#define digitalRead_mod(p) extDigitalRead(p) // AVR digitalRead disabled PWM before it read the pin -#define PRINT_PORT(p) -#define PRINT_ARRAY_NAME(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) -#define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%02d"), p); SERIAL_ECHO(buffer); }while(0) -#define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0) -#define GET_ARRAY_PIN(p) pin_array[p].pin -#define GET_ARRAY_IS_DIGITAL(p) pin_array[p].is_digital -#define VALID_PIN(pin) (pin >= 0 && pin < (int8_t)NUMBER_PINS_TOTAL ? 1 : 0) -#define DIGITAL_PIN_TO_ANALOG_PIN(p) int(p - analogInputToDigitalPin(0)) -#define IS_ANALOG(P) ((P) >= analogInputToDigitalPin(0) && (P) <= analogInputToDigitalPin(13)) || ((P) >= analogInputToDigitalPin(14) && (P) <= analogInputToDigitalPin(17)) -#define pwm_status(pin) HAL_pwm_status(pin) -#define GET_PINMODE(PIN) (VALID_PIN(pin) && IS_OUTPUT(pin)) +#define getPinByIndex(x) pin_array[x].pin +#define printPinNameByIndex(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0) +#define getPinIsDigitalByIndex(x) pin_array[x].is_digital +#define digitalPinToAnalogIndex(P) int(P - analogInputToDigitalPin(0)) +#define getValidPinMode(P) (isValidPin(P) && IS_OUTPUT(P)) +#define isValidPin(P) (P >= 0 && P < pin_t(NUMBER_PINS_TOTAL)) +#define isAnalogPin(P) (pin_t(P) >= analogInputToDigitalPin(0) && pin_t(P) <= analogInputToDigitalPin(13)) || (pin_t(P) >= analogInputToDigitalPin(14) && pin_t(P) <= analogInputToDigitalPin(17)) +#define digitalRead_mod(P) extDigitalRead(P) // AVR digitalRead disabled PWM before it read the pin +#define printPinNumber(P) do{ sprintf_P(buffer, PSTR("%02d"), P); SERIAL_ECHO(buffer); }while(0) +#define printPinAnalog(P) do{ sprintf_P(buffer, PSTR(" (A%2d) "), digitalPinToAnalogIndex(P)); SERIAL_ECHO(buffer); }while(0) #define MULTI_NAME_PAD 16 // space needed to be pretty if not first name assigned to a pin struct pwm_pin_info_struct { @@ -120,12 +134,12 @@ const struct pwm_pin_info_struct pwm_pin_info[] = { #endif }; -void HAL_print_analog_pin(char buffer[], int8_t pin) { +void printAnalogPin(char buffer[], const pin_t pin) { if (pin <= 23) sprintf_P(buffer, PSTR("(A%2d) "), int(pin - 14)); else if (pin <= 41) sprintf_P(buffer, PSTR("(A%2d) "), int(pin - 24)); } -void HAL_analog_pin_state(char buffer[], int8_t pin) { +void analog_pin_state(char buffer[], const pin_t pin) { if (pin <= 23) sprintf_P(buffer, PSTR("Analog in =% 5d"), analogRead(pin - 14)); else if (pin <= 41) sprintf_P(buffer, PSTR("Analog in =% 5d"), analogRead(pin - 24)); } @@ -136,14 +150,14 @@ void HAL_analog_pin_state(char buffer[], int8_t pin) { * Print a pin's PWM status. * Return true if it's currently a PWM pin. */ -bool HAL_pwm_status(int8_t pin) { +bool pwm_status(const pin_t pin) { char buffer[20]; // for the sprintf statements const struct pwm_pin_info_struct *info; - if (pin >= CORE_NUM_DIGITAL) return 0; - info = pwm_pin_info + pin; + if (pin >= CORE_NUM_DIGITAL) return false; - if (info->type == 0) return 0; + info = pwm_pin_info + pin; + if (info->type == 0) return false; /* TODO decode pwm value from timers */ // for now just indicate if output is set as pwm @@ -151,4 +165,6 @@ bool HAL_pwm_status(int8_t pin) { return (*(portConfigRegister(pin)) == info->muxval); } -static void pwm_details(uint8_t pin) { /* TODO */ } +void printPinPWM(const pin_t) { /* TODO */ } + +void printPinPort(const pin_t) {} diff --git a/Marlin/src/HAL/TEENSY40_41/timers.h b/Marlin/src/HAL/TEENSY40_41/timers.h index 81cf67f7..fc160ab8 100644 --- a/Marlin/src/HAL/TEENSY40_41/timers.h +++ b/Marlin/src/HAL/TEENSY40_41/timers.h @@ -1,8 +1,9 @@ /** * Marlin 3D Printer Firmware * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,13 +36,13 @@ typedef uint32_t hal_timer_t; #define HAL_TIMER_TYPE_MAX 0xFFFFFFFE -#define GPT_TIMER_RATE F_BUS_ACTUAL // 150MHz +#define GPT_TIMER_RATE (F_CPU / 4) // 150MHz (Can't use F_BUS_ACTUAL because it's extern volatile) #define GPT1_TIMER_PRESCALE 2 #define GPT2_TIMER_PRESCALE 10 -#define GPT1_TIMER_RATE (GPT_TIMER_RATE / GPT1_TIMER_PRESCALE) // 75MHz -#define GPT2_TIMER_RATE (GPT_TIMER_RATE / GPT2_TIMER_PRESCALE) // 15MHz +#define GPT1_TIMER_RATE (GPT_TIMER_RATE / GPT1_TIMER_PRESCALE) // 150MHz / 2 = 75MHz +#define GPT2_TIMER_RATE (GPT_TIMER_RATE / GPT2_TIMER_PRESCALE) // 150MHz / 10 = 15MHz #ifndef MF_TIMER_STEP #define MF_TIMER_STEP 0 // Timer Index for Stepper @@ -56,7 +57,8 @@ typedef uint32_t hal_timer_t; #define TEMP_TIMER_RATE 1000000 #define TEMP_TIMER_FREQUENCY 1000 -#define STEPPER_TIMER_RATE GPT1_TIMER_RATE +#define HAL_TIMER_RATE GPT1_TIMER_RATE +#define STEPPER_TIMER_RATE HAL_TIMER_RATE #define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) #define STEPPER_TIMER_PRESCALE ((GPT_TIMER_RATE / 1000000) / STEPPER_TIMER_TICKS_PER_US) @@ -114,4 +116,4 @@ bool HAL_timer_interrupt_enabled(const uint8_t timer_num); void HAL_timer_isr_prologue(const uint8_t timer_num); //void HAL_timer_isr_epilogue(const uint8_t timer_num) {} -#define HAL_timer_isr_epilogue(T) +#define HAL_timer_isr_epilogue(T) NOOP diff --git a/Marlin/src/HAL/TEENSY40_41/watchdog.cpp b/Marlin/src/HAL/TEENSY40_41/watchdog.cpp deleted file mode 100644 index dd7c0aa9..00000000 --- a/Marlin/src/HAL/TEENSY40_41/watchdog.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * - * Based on Sprinter and grbl. - * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -#ifdef __IMXRT1062__ - -/** - * HAL Watchdog for Teensy 4.0 (IMXRT1062DVL6A) / 4.1 (IMXRT1062DVJ6A) - */ - -#include "../../inc/MarlinConfig.h" - -#if ENABLED(USE_WATCHDOG) - -#include "watchdog.h" - -#define WDT_TIMEOUT TERN(WATCHDOG_DURATION_8S, 8, 4) // 4 or 8 second timeout - -constexpr uint8_t timeoutval = (WDT_TIMEOUT - 0.5f) / 0.5f; - -void watchdog_init() { - CCM_CCGR3 |= CCM_CCGR3_WDOG1(3); // enable WDOG1 clocks - WDOG1_WMCR = 0; // disable power down PDE - WDOG1_WCR |= WDOG_WCR_SRS | WDOG_WCR_WT(timeoutval); - WDOG1_WCR |= WDOG_WCR_WDE | WDOG_WCR_WDT | WDOG_WCR_SRE; -} - -void HAL_watchdog_refresh() { - // Watchdog refresh sequence - WDOG1_WSR = 0x5555; - WDOG1_WSR = 0xAAAA; -} - -#endif // USE_WATCHDOG -#endif // __IMXRT1062__ diff --git a/Marlin/src/HAL/platforms.h b/Marlin/src/HAL/platforms.h index 28fe28e1..84ba7087 100644 --- a/Marlin/src/HAL/platforms.h +++ b/Marlin/src/HAL/platforms.h @@ -24,32 +24,34 @@ #define XSTR(V...) #V #ifdef __AVR__ - #define HAL_PATH(PATH, NAME) XSTR(PATH/AVR/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/AVR/NAME) #elif defined(ARDUINO_ARCH_SAM) - #define HAL_PATH(PATH, NAME) XSTR(PATH/DUE/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/DUE/NAME) #elif defined(__MK20DX256__) - #define HAL_PATH(PATH, NAME) XSTR(PATH/TEENSY31_32/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/TEENSY31_32/NAME) #elif defined(__MK64FX512__) || defined(__MK66FX1M0__) - #define HAL_PATH(PATH, NAME) XSTR(PATH/TEENSY35_36/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/TEENSY35_36/NAME) #elif defined(__IMXRT1062__) - #define HAL_PATH(PATH, NAME) XSTR(PATH/TEENSY40_41/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/TEENSY40_41/NAME) #elif defined(TARGET_LPC1768) - #define HAL_PATH(PATH, NAME) XSTR(PATH/LPC1768/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/LPC1768/NAME) #elif defined(__STM32F1__) || defined(TARGET_STM32F1) - #define HAL_PATH(PATH, NAME) XSTR(PATH/STM32F1/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/STM32F1/NAME) #elif defined(ARDUINO_ARCH_STM32) #ifndef HAL_STM32 #define HAL_STM32 #endif - #define HAL_PATH(PATH, NAME) XSTR(PATH/STM32/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/STM32/NAME) #elif defined(ARDUINO_ARCH_ESP32) - #define HAL_PATH(PATH, NAME) XSTR(PATH/ESP32/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/ESP32/NAME) #elif defined(__PLAT_LINUX__) - #define HAL_PATH(PATH, NAME) XSTR(PATH/LINUX/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/LINUX/NAME) #elif defined(__PLAT_NATIVE_SIM__) - #define HAL_PATH(PATH, NAME) XSTR(PATH/NATIVE_SIM/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/NATIVE_SIM/NAME) #elif defined(__SAMD51__) - #define HAL_PATH(PATH, NAME) XSTR(PATH/SAMD51/NAME) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/SAMD51/NAME) +#elif defined(__SAMD21__) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/SAMD21/NAME) #else #error "Unsupported Platform!" #endif diff --git a/Marlin/src/HAL/shared/Delay.cpp b/Marlin/src/HAL/shared/Delay.cpp index c64376d2..8856fe13 100644 --- a/Marlin/src/HAL/shared/Delay.cpp +++ b/Marlin/src/HAL/shared/Delay.cpp @@ -167,7 +167,6 @@ } #endif // MARLIN_DEV_MODE - #else void calibrate_delay_loop() {} diff --git a/Marlin/src/HAL/shared/Delay.h b/Marlin/src/HAL/shared/Delay.h index df07881f..a6795a78 100644 --- a/Marlin/src/HAL/shared/Delay.h +++ b/Marlin/src/HAL/shared/Delay.h @@ -166,6 +166,8 @@ void calibrate_delay_loop(); // Delay in microseconds #define DELAY_US(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL)) + #define DELAY_CYCLES_VAR DELAY_CYCLES + #elif defined(ESP32) || defined(__PLAT_LINUX__) || defined(__PLAT_NATIVE_SIM__) // DELAY_CYCLES specified inside platform diff --git a/Marlin/src/HAL/shared/HAL.cpp b/Marlin/src/HAL/shared/HAL.cpp new file mode 100644 index 00000000..4d92aedd --- /dev/null +++ b/Marlin/src/HAL/shared/HAL.cpp @@ -0,0 +1,36 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * HAL/shared/HAL.cpp + */ + +#include "../../inc/MarlinConfig.h" + +MarlinHAL hal; + +#if ENABLED(SOFT_RESET_VIA_SERIAL) + + // Global for use by e_parser.h + void HAL_reboot() { hal.reboot(); } + +#endif diff --git a/Marlin/src/HAL/shared/HAL_ST7920.h b/Marlin/src/HAL/shared/HAL_ST7920.h index 4e362f96..305736c3 100644 --- a/Marlin/src/HAL/shared/HAL_ST7920.h +++ b/Marlin/src/HAL/shared/HAL_ST7920.h @@ -27,7 +27,7 @@ * (bypassing U8G), it will allow the LIGHTWEIGHT_UI to operate. */ -#if BOTH(HAS_MARLINUI_U8GLIB, LIGHTWEIGHT_UI) +#if ALL(HAS_MARLINUI_U8GLIB, LIGHTWEIGHT_UI) void ST7920_cs(); void ST7920_ncs(); void ST7920_set_cmd(); diff --git a/Marlin/src/HAL/shared/HAL_spi_L6470.cpp b/Marlin/src/HAL/shared/HAL_spi_L6470.cpp deleted file mode 100644 index bd85dbe7..00000000 --- a/Marlin/src/HAL/shared/HAL_spi_L6470.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * - * Based on Sprinter and grbl. - * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -/** - * Software L6470 SPI functions originally from Arduino Sd2Card Library - * Copyright (c) 2009 by William Greiman - */ - -#include "../../inc/MarlinConfig.h" - -#if HAS_L64XX - -#include "Delay.h" - -#include "../../core/serial.h" -#include "../../libs/L64XX/L64XX_Marlin.h" - -// Make sure GCC optimizes this file. -// Note that this line triggers a bug in GCC which is fixed by casting. -// See the note below. -#pragma GCC optimize (3) - -// run at ~4Mhz -inline uint8_t L6470_SpiTransfer_Mode_0(uint8_t b) { // using Mode 0 - for (uint8_t bits = 8; bits--;) { - WRITE(L6470_CHAIN_MOSI_PIN, b & 0x80); - b <<= 1; // little setup time - - WRITE(L6470_CHAIN_SCK_PIN, HIGH); - DELAY_NS(125); // 10 cycles @ 84mhz - - b |= (READ(L6470_CHAIN_MISO_PIN) != 0); - - WRITE(L6470_CHAIN_SCK_PIN, LOW); - DELAY_NS(125); // 10 cycles @ 84mhz - } - return b; -} - -inline uint8_t L6470_SpiTransfer_Mode_3(uint8_t b) { // using Mode 3 - for (uint8_t bits = 8; bits--;) { - WRITE(L6470_CHAIN_SCK_PIN, LOW); - WRITE(L6470_CHAIN_MOSI_PIN, b & 0x80); - - DELAY_NS(125); // 10 cycles @ 84mhz - WRITE(L6470_CHAIN_SCK_PIN, HIGH); - DELAY_NS(125); // Need more delay for fast CPUs - - b <<= 1; // little setup time - b |= (READ(L6470_CHAIN_MISO_PIN) != 0); - } - DELAY_NS(125); // 10 cycles @ 84mhz - return b; -} - -/** - * L64XX methods for SPI init and transfer - */ -void L64XX_Marlin::spi_init() { - OUT_WRITE(L6470_CHAIN_SS_PIN, HIGH); - OUT_WRITE(L6470_CHAIN_SCK_PIN, HIGH); - OUT_WRITE(L6470_CHAIN_MOSI_PIN, HIGH); - SET_INPUT(L6470_CHAIN_MISO_PIN); - - #if PIN_EXISTS(L6470_BUSY) - SET_INPUT(L6470_BUSY_PIN); - #endif - - OUT_WRITE(L6470_CHAIN_MOSI_PIN, HIGH); -} - -uint8_t L64XX_Marlin::transfer_single(uint8_t data, int16_t ss_pin) { - // First device in chain has data sent last - extDigitalWrite(ss_pin, LOW); - - DISABLE_ISRS(); // Disable interrupts during SPI transfer (can't allow partial command to chips) - const uint8_t data_out = L6470_SpiTransfer_Mode_3(data); - ENABLE_ISRS(); // Enable interrupts - - extDigitalWrite(ss_pin, HIGH); - return data_out; -} - -uint8_t L64XX_Marlin::transfer_chain(uint8_t data, int16_t ss_pin, uint8_t chain_position) { - uint8_t data_out = 0; - - // first device in chain has data sent last - extDigitalWrite(ss_pin, LOW); - - for (uint8_t i = L64XX::chain[0]; !L64xxManager.spi_abort && i >= 1; i--) { // Send data unless aborted - DISABLE_ISRS(); // Disable interrupts during SPI transfer (can't allow partial command to chips) - const uint8_t temp = L6470_SpiTransfer_Mode_3(uint8_t(i == chain_position ? data : dSPIN_NOP)); - ENABLE_ISRS(); // Enable interrupts - if (i == chain_position) data_out = temp; - } - - extDigitalWrite(ss_pin, HIGH); - return data_out; -} - -/** - * Platform-supplied L6470 buffer transfer method - */ -void L64XX_Marlin::transfer(uint8_t L6470_buf[], const uint8_t length) { - // First device in chain has its data sent last - - if (spi_active) { // Interrupted SPI transfer so need to - WRITE(L6470_CHAIN_SS_PIN, HIGH); // guarantee min high of 650ns - DELAY_US(1); - } - - WRITE(L6470_CHAIN_SS_PIN, LOW); - for (uint8_t i = length; i >= 1; i--) - L6470_SpiTransfer_Mode_3(uint8_t(L6470_buf[i])); - WRITE(L6470_CHAIN_SS_PIN, HIGH); -} - -#pragma GCC reset_options - -#endif // HAS_L64XX diff --git a/Marlin/src/HAL/shared/HAL_MinSerial.cpp b/Marlin/src/HAL/shared/MinSerial.cpp similarity index 97% rename from Marlin/src/HAL/shared/HAL_MinSerial.cpp rename to Marlin/src/HAL/shared/MinSerial.cpp index 9dda5fdf..2e718d83 100644 --- a/Marlin/src/HAL/shared/HAL_MinSerial.cpp +++ b/Marlin/src/HAL/shared/MinSerial.cpp @@ -19,7 +19,7 @@ * along with this program. If not, see . * */ -#include "HAL_MinSerial.h" +#include "MinSerial.h" #if ENABLED(POSTMORTEM_DEBUGGING) diff --git a/Marlin/src/HAL/shared/HAL_MinSerial.h b/Marlin/src/HAL/shared/MinSerial.h similarity index 100% rename from Marlin/src/HAL/shared/HAL_MinSerial.h rename to Marlin/src/HAL/shared/MinSerial.h diff --git a/Marlin/src/HAL/shared/backtrace/backtrace.cpp b/Marlin/src/HAL/shared/backtrace/backtrace.cpp index ad88de83..33e8e651 100644 --- a/Marlin/src/HAL/shared/backtrace/backtrace.cpp +++ b/Marlin/src/HAL/shared/backtrace/backtrace.cpp @@ -25,7 +25,7 @@ #include "unwinder.h" #include "unwmemaccess.h" -#include "../HAL_MinSerial.h" +#include "../MinSerial.h" #include // Dump a backtrace entry diff --git a/Marlin/src/HAL/shared/backtrace/unwarm.cpp b/Marlin/src/HAL/shared/backtrace/unwarm.cpp index adbcca69..823f54c1 100644 --- a/Marlin/src/HAL/shared/backtrace/unwarm.cpp +++ b/Marlin/src/HAL/shared/backtrace/unwarm.cpp @@ -33,8 +33,9 @@ void UnwPrintf(const char *format, ...) { va_list args; - va_start( args, format ); - vprintf(format, args ); + va_start(args, format); + vprintf(format, args); + va_end(args); } #endif @@ -49,7 +50,6 @@ void UnwInvalidateRegisterFile(RegData *regFile) { } while (t < 13); } - /** * Initialize the data used for unwinding. */ @@ -128,7 +128,6 @@ bool UnwReportRetAddr(UnwState * const state, uint32_t addr) { return state->cb->report((void *)state->reportData, &entry); } - /** * Write some register to memory. * This will store some register and meta data onto the virtual stack. diff --git a/Marlin/src/HAL/shared/backtrace/unwarm.h b/Marlin/src/HAL/shared/backtrace/unwarm.h index edae9065..72ea0b06 100644 --- a/Marlin/src/HAL/shared/backtrace/unwarm.h +++ b/Marlin/src/HAL/shared/backtrace/unwarm.h @@ -41,7 +41,6 @@ typedef enum { REG_VAL_ARITHMETIC = 0x80 } RegValOrigin; - /** Type for tracking information about a register. * This stores the register value, as well as other data that helps unwinding. */ @@ -56,7 +55,6 @@ typedef struct { int o; /* (RegValOrigin) */ } RegData; - /** Structure used to track reads and writes to memory. * This structure is used as a hash to store a small number of writes * to memory. @@ -81,7 +79,6 @@ typedef struct { uint8_t tracked[(MEM_HASH_SIZE + 7) / 8]; } MemData; - /** Structure that is used to keep track of unwinding meta-data. * This data is passed between all the unwinding functions. */ diff --git a/Marlin/src/HAL/shared/backtrace/unwarmbytab.cpp b/Marlin/src/HAL/shared/backtrace/unwarmbytab.cpp index f1ee81ed..bd87b673 100644 --- a/Marlin/src/HAL/shared/backtrace/unwarmbytab.cpp +++ b/Marlin/src/HAL/shared/backtrace/unwarmbytab.cpp @@ -55,7 +55,12 @@ static const char *UnwTabGetFunctionName(const UnwindCallbacks *cb, uint32_t add return nullptr; if ((flag_word & 0xFF000000) == 0xFF000000) { - return (const char *)(address - 4 - (flag_word & 0x00FFFFFF)); + const uint32_t fn_name_addr = address - 4 - (flag_word & 0x00FFFFFF); + + // Ensure the address is readable to avoid returning a bogus pointer + uint8_t dummy = 0; + if (cb->readB(fn_name_addr, &dummy)) + return (const char *)fn_name_addr; } return nullptr; } @@ -135,11 +140,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) { diff --git a/Marlin/src/HAL/shared/backtrace/unwmemaccess.cpp b/Marlin/src/HAL/shared/backtrace/unwmemaccess.cpp index a4151b38..da1cff4f 100644 --- a/Marlin/src/HAL/shared/backtrace/unwmemaccess.cpp +++ b/Marlin/src/HAL/shared/backtrace/unwmemaccess.cpp @@ -135,7 +135,7 @@ // Generic ARM code, that's testing if an access to the given address would cause a fault or not // It can't guarantee an address is in RAM or Flash only, but we usually don't care - #define NVIC_FAULT_STAT 0xE000ED28 // Configurable Fault Status Reg. + #define NVIC_FAULT_STAT 0xE000ED28 // Configurable Fault Status reg. #define NVIC_CFG_CTRL 0xE000ED14 // Configuration Control Register #define NVIC_FAULT_STAT_BFARV 0x00008000 // BFAR is valid #define NVIC_CFG_CTRL_BFHFNMIGN 0x00000100 // Ignore bus fault in NMI/fault diff --git a/Marlin/src/HAL/shared/cpu_exception/exception_arm.cpp b/Marlin/src/HAL/shared/cpu_exception/exception_arm.cpp index a106ed2b..f4435c73 100644 --- a/Marlin/src/HAL/shared/cpu_exception/exception_arm.cpp +++ b/Marlin/src/HAL/shared/cpu_exception/exception_arm.cpp @@ -4,7 +4,6 @@ * * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * Copyright (c) 2020 Cyril Russo * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,7 +26,6 @@ #if defined(__arm__) || defined(__thumb__) - /* On ARM CPUs exception handling is quite powerful. @@ -54,7 +52,7 @@ #include "exception_hook.h" #include "../backtrace/backtrace.h" -#include "../HAL_MinSerial.h" +#include "../MinSerial.h" #define HW_REG(X) (*((volatile unsigned long *)(X))) @@ -221,7 +219,7 @@ bool resume_from_fault() { // So we'll just need to refresh the watchdog for a while and then stop for the system to reboot uint32_t last = start; while (PENDING(last, end)) { - watchdog_refresh(); + hal.watchdog_refresh(); while (millis() == last) { /* nada */ } last = millis(); MinSerial::TX('.'); @@ -279,8 +277,6 @@ void CommonHandler_C(ContextStateFrame * frame, unsigned long lr, unsigned long if (!faulted_from_exception) { // Not sure about the non_usage_fault, we want to try anyway, don't we ? && !non_usage_fault_occurred) // Try to resume to our handler here CFSR |= CFSR; // The ARM programmer manual says you must write to 1 all fault bits to clear them so this instruction is correct - // The frame will not be valid when returning anymore, let's clean it - savedFrame.CFSR = 0; frame->pc = (uint32_t)resume_from_fault; // Patch where to return to frame->lr = 0xDEADBEEF; // If our handler returns (it shouldn't), let's make it trigger an exception immediately diff --git a/Marlin/src/HAL/shared/eeprom_api.cpp b/Marlin/src/HAL/shared/eeprom_api.cpp index 47cfa5a2..62a8f2af 100644 --- a/Marlin/src/HAL/shared/eeprom_api.cpp +++ b/Marlin/src/HAL/shared/eeprom_api.cpp @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2016 Victor Perez victor_pv@hotmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,7 +21,7 @@ */ #include "../../inc/MarlinConfigPre.h" -#if EITHER(EEPROM_SETTINGS, SD_FIRMWARE_UPDATE) +#if ANY(EEPROM_SETTINGS, SD_FIRMWARE_UPDATE) #include "eeprom_api.h" PersistentStore persistentStore; diff --git a/Marlin/src/HAL/shared/eeprom_api.h b/Marlin/src/HAL/shared/eeprom_api.h index 1f386399..7be1e72f 100644 --- a/Marlin/src/HAL/shared/eeprom_api.h +++ b/Marlin/src/HAL/shared/eeprom_api.h @@ -1,10 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com - * Copyright (c) 2016 Victor Perez victor_pv@hotmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -49,7 +48,7 @@ class PersistentStore { // Write one or more bytes of data // Return 'true' on write error - static inline bool write_data(const int pos, const uint8_t *value, const size_t size=sizeof(uint8_t)) { + static bool write_data(const int pos, const uint8_t *value, const size_t size=sizeof(uint8_t)) { int data_pos = pos; uint16_t crc = 0; return write_data(data_pos, value, size, &crc); @@ -57,11 +56,11 @@ class PersistentStore { // Write a single byte of data // Return 'true' on write error - static inline bool write_data(const int pos, const uint8_t value) { return write_data(pos, &value); } + static bool write_data(const int pos, const uint8_t value) { return write_data(pos, &value); } // Read one or more bytes of data // Return 'true' on read error - static inline bool read_data(const int pos, uint8_t *value, const size_t size=1) { + static bool read_data(const int pos, uint8_t *value, const size_t size=1) { int data_pos = pos; uint16_t crc = 0; return read_data(data_pos, value, size, &crc); diff --git a/Marlin/src/HAL/shared/eeprom_if.h b/Marlin/src/HAL/shared/eeprom_if.h index e496de2a..8b9791e1 100644 --- a/Marlin/src/HAL/shared/eeprom_if.h +++ b/Marlin/src/HAL/shared/eeprom_if.h @@ -1,9 +1,9 @@ /** * Marlin 3D Printer Firmware - * * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com - * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Marlin/src/HAL/shared/eeprom_if_i2c.cpp b/Marlin/src/HAL/shared/eeprom_if_i2c.cpp index 6b559e23..bba9c626 100644 --- a/Marlin/src/HAL/shared/eeprom_if_i2c.cpp +++ b/Marlin/src/HAL/shared/eeprom_if_i2c.cpp @@ -33,13 +33,14 @@ #if ENABLED(SOFT_I2C_EEPROM) #include - SlowSoftWire Wire = SlowSoftWire(I2C_SDA_PIN, I2C_SCL_PIN, true); + SlowSoftWire eWire = SlowSoftWire(I2C_SDA_PIN, I2C_SCL_PIN, true); #else #include + #define eWire Wire #endif void eeprom_init() { - Wire.begin( + eWire.begin( #if PINS_EXIST(I2C_SCL, I2C_SDA) && DISABLED(SOFT_I2C_EEPROM) uint8_t(I2C_SDA_PIN), uint8_t(I2C_SCL_PIN) #endif @@ -75,16 +76,16 @@ static uint8_t _eeprom_calc_device_address(uint8_t * const pos) { static void _eeprom_begin(uint8_t * const pos) { const unsigned eeprom_address = (unsigned)pos; - Wire.beginTransmission(_eeprom_calc_device_address(pos)); + eWire.beginTransmission(_eeprom_calc_device_address(pos)); if (!SMALL_EEPROM) - Wire.write(uint8_t((eeprom_address >> 8) & 0xFF)); // Address High, if needed - Wire.write(uint8_t(eeprom_address & 0xFF)); // Address Low + eWire.write(uint8_t((eeprom_address >> 8) & 0xFF)); // Address High, if needed + eWire.write(uint8_t(eeprom_address & 0xFF)); // Address Low } void eeprom_write_byte(uint8_t *pos, uint8_t value) { _eeprom_begin(pos); - Wire.write(value); - Wire.endTransmission(); + eWire.write(value); + eWire.endTransmission(); // wait for write cycle to complete // this could be done more efficiently with "acknowledge polling" @@ -93,9 +94,9 @@ void eeprom_write_byte(uint8_t *pos, uint8_t value) { uint8_t eeprom_read_byte(uint8_t *pos) { _eeprom_begin(pos); - Wire.endTransmission(); - Wire.requestFrom(_eeprom_calc_device_address(pos), (byte)1); - return Wire.available() ? Wire.read() : 0xFF; + eWire.endTransmission(); + eWire.requestFrom(_eeprom_calc_device_address(pos), (byte)1); + return eWire.available() ? eWire.read() : 0xFF; } #endif // USE_SHARED_EEPROM diff --git a/Marlin/src/HAL/shared/esp_wifi.cpp b/Marlin/src/HAL/shared/esp_wifi.cpp index a55f5ca3..8a6ac2df 100644 --- a/Marlin/src/HAL/shared/esp_wifi.cpp +++ b/Marlin/src/HAL/shared/esp_wifi.cpp @@ -21,6 +21,9 @@ */ #include "../../inc/MarlinConfig.h" + +#if ENABLED(WIFISUPPORT) + #include "Delay.h" void esp_wifi_init(void) { // init ESP01 WIFI module pins @@ -41,3 +44,5 @@ void esp_wifi_init(void) { // init ESP01 WIFI module pi OUT_WRITE(ESP_WIFI_MODULE_ENABLE_PIN, HIGH); #endif } + +#endif // WIFISUPPORT diff --git a/Marlin/src/HAL/shared/fauxpins.h b/Marlin/src/HAL/shared/fauxpins.h new file mode 100644 index 00000000..924bfba0 --- /dev/null +++ b/Marlin/src/HAL/shared/fauxpins.h @@ -0,0 +1,367 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +// +// Faux pins for Dependency Check +// + +// +// STM32 Pin Names +// +#define PA0 0x10 +#define PA1 0x11 +#define PA2 0x12 +#define PA3 0x13 +#define PA4 0x14 +#define PA5 0x15 +#define PA6 0x16 +#define PA7 0x17 +#define PA8 0x18 +#define PA9 0x19 +#define PA10 0x1A +#define PA11 0x1B +#define PA12 0x1C +#define PA13 0x1D +#define PA14 0x1E +#define PA15 0x1F + +#define PB0 0x20 +#define PB1 0x21 +#define PB2 0x22 +#define PB3 0x23 +#define PB4 0x24 +#define PB5 0x25 +#define PB6 0x26 +#define PB7 0x27 +#define PB8 0x28 +#define PB9 0x29 +#define PB10 0x2A +#define PB11 0x2B +#define PB12 0x2C +#define PB13 0x2D +#define PB14 0x2E +#define PB15 0x2F + +#define PC0 0x30 +#define PC1 0x31 +#define PC2 0x32 +#define PC3 0x33 +#define PC4 0x34 +#define PC5 0x35 +#define PC6 0x36 +#define PC7 0x37 +#define PC8 0x38 +#define PC9 0x39 +#define PC10 0x3A +#define PC11 0x3B +#define PC12 0x3C +#define PC13 0x3D +#define PC14 0x3E +#define PC15 0x3F + +#define PD0 0x40 +#define PD1 0x41 +#define PD2 0x42 +#define PD3 0x43 +#define PD4 0x44 +#define PD5 0x45 +#define PD6 0x46 +#define PD7 0x47 +#define PD8 0x48 +#define PD9 0x49 +#define PD10 0x4A +#define PD11 0x4B +#define PD12 0x4C +#define PD13 0x4D +#define PD14 0x4E +#define PD15 0x4F + +#define PE0 0x50 +#define PE1 0x51 +#define PE2 0x52 +#define PE3 0x53 +#define PE4 0x54 +#define PE5 0x55 +#define PE6 0x56 +#define PE7 0x57 +#define PE8 0x58 +#define PE9 0x59 +#define PE10 0x5A +#define PE11 0x5B +#define PE12 0x5C +#define PE13 0x5D +#define PE14 0x5E +#define PE15 0x5F + +#define PF0 0x60 +#define PF1 0x61 +#define PF2 0x62 +#define PF3 0x63 +#define PF4 0x64 +#define PF5 0x65 +#define PF6 0x66 +#define PF7 0x67 +#define PF8 0x68 +#define PF9 0x69 +#define PF10 0x6A +#define PF11 0x6B +#define PF12 0x6C +#define PF13 0x6D +#define PF14 0x6E +#define PF15 0x6F + +#define PG0 0x70 +#define PG1 0x71 +#define PG2 0x72 +#define PG3 0x73 +#define PG4 0x74 +#define PG5 0x75 +#define PG6 0x76 +#define PG7 0x77 +#define PG8 0x78 +#define PG9 0x79 +#define PG10 0x7A +#define PG11 0x7B +#define PG12 0x7C +#define PG13 0x7D +#define PG14 0x7E +#define PG15 0x7F + +#define PH0 0x80 +#define PH1 0x81 +#define PH2 0x82 +#define PH3 0x83 +#define PH4 0x84 +#define PH5 0x85 +#define PH6 0x86 +#define PH7 0x87 +#define PH8 0x88 +#define PH9 0x89 +#define PH10 0x8A +#define PH11 0x8B +#define PH12 0x8C +#define PH13 0x8D +#define PH14 0x8E +#define PH15 0x8F + +#define PI0 0x90 +#define PI1 0x91 +#define PI2 0x92 +#define PI3 0x93 +#define PI4 0x94 +#define PI5 0x95 +#define PI6 0x96 +#define PI7 0x97 +#define PI8 0x98 +#define PI9 0x99 +#define PI10 0x9A +#define PI11 0x9B +#define PI12 0x9C +#define PI13 0x9D +#define PI14 0x9E +#define PI15 0x9F + +#define PJ0 0xA0 +#define PJ1 0xA1 +#define PJ2 0xA2 +#define PJ3 0xA3 +#define PJ4 0xA4 +#define PJ5 0xA5 +#define PJ6 0xA6 +#define PJ7 0xA7 +#define PJ8 0xA8 +#define PJ9 0xA9 +#define PJ10 0xAA +#define PJ11 0xAB +#define PJ12 0xAC +#define PJ13 0xAD +#define PJ14 0xAE +#define PJ15 0xAF + +// +// LPC Pin Names +// +#define P0_00 100 +#define P0_01 101 +#define P0_02 102 +#define P0_03 103 +#define P0_04 104 +#define P0_05 105 +#define P0_06 106 +#define P0_07 107 +#define P0_08 108 +#define P0_09 109 +#define P0_10 110 +#define P0_11 111 +#define P0_12 112 +#define P0_13 113 +#define P0_14 114 +#define P0_15 115 +#define P0_16 116 +#define P0_17 117 +#define P0_18 118 +#define P0_19 119 +#define P0_20 120 +#define P0_21 121 +#define P0_22 122 +#define P0_23 123 +#define P0_24 124 +#define P0_25 125 +#define P0_26 126 +#define P0_27 127 +#define P0_28 128 +#define P0_29 129 +#define P0_30 130 +#define P0_31 131 + +#define P1_00 200 +#define P1_01 201 +#define P1_02 202 +#define P1_03 203 +#define P1_04 204 +#define P1_05 205 +#define P1_06 206 +#define P1_07 207 +#define P1_08 208 +#define P1_09 209 +#define P1_10 210 +#define P1_11 211 +#define P1_12 212 +#define P1_13 213 +#define P1_14 214 +#define P1_15 215 +#define P1_16 216 +#define P1_17 217 +#define P1_18 218 +#define P1_19 219 +#define P1_20 220 +#define P1_21 221 +#define P1_22 222 +#define P1_23 223 +#define P1_24 224 +#define P1_25 225 +#define P1_26 226 +#define P1_27 227 +#define P1_28 228 +#define P1_29 229 +#define P1_30 230 +#define P1_31 231 + +#define P2_00 300 +#define P2_01 301 +#define P2_02 302 +#define P2_03 303 +#define P2_04 304 +#define P2_05 305 +#define P2_06 306 +#define P2_07 307 +#define P2_08 308 +#define P2_09 309 +#define P2_10 310 +#define P2_11 311 +#define P2_12 312 +#define P2_13 313 +#define P2_14 314 +#define P2_15 315 +#define P2_16 316 +#define P2_17 317 +#define P2_18 318 +#define P2_19 319 +#define P2_20 320 +#define P2_21 321 +#define P2_22 322 +#define P2_23 323 +#define P2_24 324 +#define P2_25 325 +#define P2_26 326 +#define P2_27 327 +#define P2_28 328 +#define P2_29 329 +#define P2_30 330 +#define P2_31 331 + +#define P3_00 400 +#define P3_01 401 +#define P3_02 402 +#define P3_03 403 +#define P3_04 404 +#define P3_05 405 +#define P3_06 406 +#define P3_07 407 +#define P3_08 408 +#define P3_09 409 +#define P3_10 410 +#define P3_11 411 +#define P3_12 412 +#define P3_13 413 +#define P3_14 414 +#define P3_15 415 +#define P3_16 416 +#define P3_17 417 +#define P3_18 418 +#define P3_19 419 +#define P3_20 420 +#define P3_21 421 +#define P3_22 422 +#define P3_23 423 +#define P3_24 424 +#define P3_25 425 +#define P3_26 426 +#define P3_27 427 +#define P3_28 428 +#define P3_29 429 +#define P3_30 430 +#define P3_31 431 + +#define P4_00 500 +#define P4_01 501 +#define P4_02 502 +#define P4_03 503 +#define P4_04 504 +#define P4_05 505 +#define P4_06 506 +#define P4_07 507 +#define P4_08 508 +#define P4_09 509 +#define P4_10 510 +#define P4_11 511 +#define P4_12 512 +#define P4_13 513 +#define P4_14 514 +#define P4_15 515 +#define P4_16 516 +#define P4_17 517 +#define P4_18 518 +#define P4_19 519 +#define P4_20 520 +#define P4_21 521 +#define P4_22 522 +#define P4_23 523 +#define P4_24 524 +#define P4_25 525 +#define P4_26 526 +#define P4_27 527 +#define P4_28 528 +#define P4_29 529 +#define P4_30 530 +#define P4_31 531 diff --git a/Marlin/src/HAL/shared/math_32bit.h b/Marlin/src/HAL/shared/math_32bit.h index 87e9e640..1fb233e3 100644 --- a/Marlin/src/HAL/shared/math_32bit.h +++ b/Marlin/src/HAL/shared/math_32bit.h @@ -26,6 +26,6 @@ /** * Math helper functions for 32 bit CPUs */ -static FORCE_INLINE uint32_t MultiU32X24toH32(uint32_t longIn1, uint32_t longIn2) { +FORCE_INLINE static uint32_t MultiU32X24toH32(uint32_t longIn1, uint32_t longIn2) { return ((uint64_t)longIn1 * longIn2 + 0x00800000) >> 24; } diff --git a/Marlin/src/HAL/shared/servo.cpp b/Marlin/src/HAL/shared/servo.cpp index cfec6f30..543bc8e8 100644 --- a/Marlin/src/HAL/shared/servo.cpp +++ b/Marlin/src/HAL/shared/servo.cpp @@ -60,14 +60,14 @@ ServoInfo_t servo_info[MAX_SERVOS]; // static array of servo info structures uint8_t ServoCount = 0; // the total number of attached servos -#define SERVO_MIN(v) (MIN_PULSE_WIDTH - (v) * 4) // minimum value in uS for this servo -#define SERVO_MAX(v) (MAX_PULSE_WIDTH - (v) * 4) // maximum value in uS for this servo +#define SERVO_MIN_US(v) (MIN_PULSE_WIDTH - (v) * 4) // minimum value in uS for this servo +#define SERVO_MAX_US(v) (MAX_PULSE_WIDTH - (v) * 4) // maximum value in uS for this servo /************ 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) { + for (uint8_t channel = 0; channel < SERVOS_PER_TIMER; ++channel) { if (SERVO(timer, channel).Pin.isActive) return true; } @@ -101,22 +101,23 @@ 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) { if (value < MIN_PULSE_WIDTH) // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds) - value = map(constrain(value, 0, 180), 0, 180, SERVO_MIN(min), SERVO_MAX(max)); + value = map(constrain(value, 0, 180), 0, 180, SERVO_MIN_US(min), SERVO_MAX_US(max)); writeMicroseconds(value); } @@ -125,8 +126,8 @@ void Servo::writeMicroseconds(int value) { byte channel = servoIndex; if (channel < MAX_SERVOS) { // ensure channel is valid // ensure pulse width is valid - value = constrain(value, SERVO_MIN(min), SERVO_MAX(max)) - (TRIM_DURATION); - value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009 + LIMIT(value, SERVO_MIN_US(min), SERVO_MAX_US(max)); + value = usToTicks(value - (TRIM_DURATION)); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009 CRITICAL_SECTION_START(); servo_info[channel].ticks = value; @@ -135,7 +136,7 @@ void Servo::writeMicroseconds(int value) { } // return the value as degrees -int Servo::read() { return map(readMicroseconds() + 1, SERVO_MIN(min), SERVO_MAX(max), 0, 180); } +int Servo::read() { return map(readMicroseconds() + 1, SERVO_MIN_US(min), SERVO_MAX_US(max), 0, 180); } int Servo::readMicroseconds() { return (servoIndex == INVALID_SERVO) ? 0 : ticksToUs(servo_info[servoIndex].ticks) + (TRIM_DURATION); diff --git a/Marlin/src/HAL/shared/servo.h b/Marlin/src/HAL/shared/servo.h index c2560a85..15153ca5 100644 --- a/Marlin/src/HAL/shared/servo.h +++ b/Marlin/src/HAL/shared/servo.h @@ -83,10 +83,10 @@ #else #include - #if defined(__AVR__) || defined(ARDUINO_ARCH_SAM) || defined(__SAMD51__) + #if defined(__AVR__) || defined(ARDUINO_ARCH_SAM) || defined(__SAMD51__) || defined(__SAMD21__) // we're good to go #else - #error "This library only supports boards with an AVR, SAM3X or SAMD51 processor." + #error "This library only supports boards with an AVR, SAM3X, SAMD21 or SAMD51 processor." #endif #define Servo_VERSION 2 // software version of this library diff --git a/Marlin/src/HAL/shared/servo_private.h b/Marlin/src/HAL/shared/servo_private.h index d85d8da8..8fd5ab2d 100644 --- a/Marlin/src/HAL/shared/servo_private.h +++ b/Marlin/src/HAL/shared/servo_private.h @@ -49,8 +49,10 @@ #include "../DUE/ServoTimers.h" #elif defined(__SAMD51__) #include "../SAMD51/ServoTimers.h" +#elif defined(__SAMD21__) + #include "../SAMD21/ServoTimers.h" #else - #error "This library only supports boards with an AVR, SAM3X or SAMD51 processor." + #error "This library only supports boards with an AVR, SAM3X, SAMD21 or SAMD51 processor." #endif // Macros @@ -70,10 +72,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 +96,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); diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index 5132d07e..8fddd125 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -34,22 +34,22 @@ #include "HAL/shared/esp_wifi.h" #include "HAL/shared/cpu_exception/exception_hook.h" +#if ENABLED(WIFISUPPORT) + #include "HAL/shared/esp_wifi.h" +#endif + #ifdef ARDUINO #include #endif #include -#include "core/utility.h" - +#include "module/endstops.h" #include "module/motion.h" #include "module/planner.h" -#include "module/endstops.h" -#include "module/temperature.h" -#include "module/settings.h" #include "module/printcounter.h" // PrintCounter or Stopwatch - +#include "module/settings.h" #include "module/stepper.h" -#include "module/stepper/indirection.h" +#include "module/temperature.h" #include "gcode/gcode.h" #include "gcode/parser.h" @@ -74,8 +74,8 @@ #include "lcd/e3v2/common/encoder.h" #if ENABLED(DWIN_CREALITY_LCD) #include "lcd/e3v2/creality/dwin.h" - #elif ENABLED(DWIN_CREALITY_LCD_ENHANCED) - #include "lcd/e3v2/enhanced/dwin.h" + #elif ENABLED(DWIN_LCD_PROUI) + #include "lcd/e3v2/proui/dwin.h" #elif ENABLED(DWIN_CREALITY_LCD_JYERSUI) #include "lcd/e3v2/jyersui/dwin.h" #endif @@ -97,7 +97,7 @@ #include "feature/host_actions.h" #endif -#if USE_BEEPER +#if HAS_BEEPER #include "libs/buzzer.h" #endif @@ -125,6 +125,10 @@ #include "feature/bltouch.h" #endif +#if ENABLED(BD_SENSOR) + #include "feature/bedlevel/bdl/bdl.h" +#endif + #if ENABLED(POLL_JOG) #include "feature/joystick.h" #endif @@ -145,7 +149,7 @@ #include "feature/encoder_i2c.h" #endif -#if HAS_TRINAMIC_CONFIG && DISABLED(PSU_DEFAULT_OFF) +#if (HAS_TRINAMIC_CONFIG || HAS_TMC_SPI) && DISABLED(PSU_DEFAULT_OFF) #include "feature/tmc_util.h" #endif @@ -153,7 +157,7 @@ #include "feature/spindle_laser.h" #endif -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA CardReader card; #endif @@ -190,7 +194,7 @@ #include "feature/runout.h" #endif -#if EITHER(PROBE_TARE, HAS_Z_SERVO_PROBE) +#if ANY(PROBE_TARE, HAS_Z_SERVO_PROBE) #include "module/probe.h" #endif @@ -228,10 +232,6 @@ #include "feature/mmu/mmu2.h" #endif -#if HAS_L64XX - #include "libs/L64XX/L64XX_Marlin.h" -#endif - #if ENABLED(PASSWORD_FEATURE) #include "feature/password/password.h" #endif @@ -252,6 +252,10 @@ #include "feature/easythreed_ui.h" #endif +#if ENABLED(MARLIN_TEST_BUILD) + #include "tests/marlin_tests.h" +#endif + PGMSTR(M112_KILL_STR, "M112 Shutdown"); MarlinState marlin_state = MF_INITIALIZING; @@ -271,6 +275,7 @@ bool wait_for_heatup = true; while (wait_for_user && !(ms && ELAPSED(millis(), ms))) idle(TERN_(ADVANCED_PAUSE_FEATURE, no_sleep)); wait_for_user = false; + while (ui.button_pressed()) safe_delay(50); } #endif @@ -311,7 +316,7 @@ bool pin_is_protected(const pin_t pin) { static constexpr size_t pincount = OnlyPins::size; static const pin_t (&sensitive_pins)[pincount] PROGMEM = OnlyPins::table; #endif - LOOP_L_N(i, pincount) { + for (uint8_t i = 0; i < pincount; ++i) { const pin_t * const pptr = &sensitive_pins[i]; if (pin == (sizeof(pin_t) == 2 ? (pin_t)pgm_read_word(pptr) : (pin_t)pgm_read_byte(pptr))) return true; } @@ -320,6 +325,10 @@ bool pin_is_protected(const pin_t pin) { #pragma GCC diagnostic pop +bool printer_busy() { + return planner.movesplanned() || printingIsActive(); +} + /** * A Print Job exists when the timer is running or SD is printing */ @@ -342,14 +351,12 @@ void startOrResumeJob() { TERN_(GCODE_REPEAT_MARKERS, repeat.reset()); TERN_(CANCEL_OBJECTS, cancelable.reset()); TERN_(LCD_SHOW_E_TOTAL, e_move_accumulator = 0); - #if BOTH(LCD_SET_PROGRESS_MANUALLY, USE_M73_REMAINING_TIME) - ui.reset_remaining_time(); - #endif + TERN_(SET_REMAINING_TIME, ui.reset_remaining_time()); } print_job_timer.start(); } -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA inline void abortSDPrinting() { IF_DISABLED(NO_SD_AUTOSTART, card.autofile_cancel()); @@ -383,7 +390,7 @@ void startOrResumeJob() { } } -#endif // SDSUPPORT +#endif // HAS_MEDIA /** * Minimal management of Marlin's core activities: @@ -412,38 +419,44 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { if (do_reset_timeout) gcode.reset_stepper_timeout(ms); if (gcode.stepper_max_timed_out(ms)) { - SERIAL_ERROR_MSG(STR_KILL_INACTIVE_TIME, parser.command_ptr); + SERIAL_ERROR_START(); + SERIAL_ECHOPGM(STR_KILL_PRE); + SERIAL_ECHOLNPGM(STR_KILL_INACTIVE_TIME, parser.command_ptr); kill(); } - // M18 / M84 : Handle steppers inactive time timeout - if (gcode.stepper_inactive_time) { + const bool has_blocks = planner.has_blocks_queued(); // Any moves in the planner? + if (has_blocks) gcode.reset_stepper_timeout(ms); // Reset timeout for M18/M84, M85 max 'kill', and laser. - static bool already_shutdown_steppers; // = false - - // Any moves in the planner? Resets both the M18/M84 - // activity timeout and the M85 max 'kill' timeout - if (planner.has_blocks_queued()) - gcode.reset_stepper_timeout(ms); - else if (!do_reset_timeout && gcode.stepper_inactive_timeout()) { - if (!already_shutdown_steppers) { - already_shutdown_steppers = true; // L6470 SPI will consume 99% of free time without this - - // Individual axes will be disabled if configured - TERN_(DISABLE_INACTIVE_X, stepper.disable_axis(X_AXIS)); - TERN_(DISABLE_INACTIVE_Y, stepper.disable_axis(Y_AXIS)); - TERN_(DISABLE_INACTIVE_Z, stepper.disable_axis(Z_AXIS)); - TERN_(DISABLE_INACTIVE_I, stepper.disable_axis(I_AXIS)); - TERN_(DISABLE_INACTIVE_J, stepper.disable_axis(J_AXIS)); - TERN_(DISABLE_INACTIVE_K, stepper.disable_axis(K_AXIS)); - TERN_(DISABLE_INACTIVE_E, stepper.disable_e_steppers()); - - TERN_(AUTO_BED_LEVELING_UBL, ubl.steppers_were_disabled()); + // M18 / M84 : Handle steppers inactive time timeout + #if HAS_DISABLE_IDLE_AXES + if (gcode.stepper_inactive_time) { + + static bool already_shutdown_steppers; // = false + + if (!has_blocks && !do_reset_timeout && gcode.stepper_inactive_timeout()) { + if (!already_shutdown_steppers) { + already_shutdown_steppers = true; + + // Individual axes will be disabled if configured + TERN_(DISABLE_IDLE_X, stepper.disable_axis(X_AXIS)); + TERN_(DISABLE_IDLE_Y, stepper.disable_axis(Y_AXIS)); + TERN_(DISABLE_IDLE_Z, stepper.disable_axis(Z_AXIS)); + TERN_(DISABLE_IDLE_I, stepper.disable_axis(I_AXIS)); + TERN_(DISABLE_IDLE_J, stepper.disable_axis(J_AXIS)); + TERN_(DISABLE_IDLE_K, stepper.disable_axis(K_AXIS)); + TERN_(DISABLE_IDLE_U, stepper.disable_axis(U_AXIS)); + TERN_(DISABLE_IDLE_V, stepper.disable_axis(V_AXIS)); + TERN_(DISABLE_IDLE_W, stepper.disable_axis(W_AXIS)); + TERN_(DISABLE_IDLE_E, stepper.disable_e_steppers()); + + TERN_(AUTO_BED_LEVELING_UBL, bedlevel.steppers_were_disabled()); + } } + else + already_shutdown_steppers = false; } - else - already_shutdown_steppers = false; - } + #endif #if ENABLED(PHOTO_GCODE) && PIN_EXISTS(CHDK) // Check if CHDK should be set to LOW (after M240 set it HIGH) @@ -470,13 +483,15 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { // KILL the machine // ---------------------------------------------------------------- if (killCount >= KILL_DELAY) { - SERIAL_ERROR_MSG(STR_KILL_BUTTON); + SERIAL_ERROR_START(); + SERIAL_ECHOPGM(STR_KILL_PRE); + SERIAL_ECHOLNPGM(STR_KILL_BUTTON); kill(); } #endif - #if HAS_FREEZE_PIN - Stepper::frozen = !READ(FREEZE_PIN); + #if ENABLED(FREEZE_FEATURE) + stepper.frozen = READ(FREEZE_PIN) == FREEZE_STATE; #endif #if HAS_HOME @@ -505,8 +520,8 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { if (ELAPSED(ms, next_cub_ms_##N)) { \ next_cub_ms_##N = ms + CUB_DEBOUNCE_DELAY_##N; \ CODE; \ - queue.inject(F(BUTTON##N##_GCODE)); \ - TERN_(HAS_LCD_MENU, ui.quick_feedback()); \ + queue.inject(F(BUTTON##N##_GCODE)); \ + TERN_(HAS_MARLINUI_MENU, ui.quick_feedback()); \ } \ } \ }while(0) @@ -720,8 +735,6 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { TERN_(MONITOR_DRIVER_STATUS, monitor_tmc_drivers()); - TERN_(MONITOR_L6470_DRIVER_STATUS, L64xxManager.monitor_driver()); - // Limit check_axes_activity frequency to 10Hz static millis_t next_check_axes_ms = 0; if (ELAPSED(ms, next_check_axes_ms)) { @@ -762,17 +775,24 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { * - Update the Průša MMU2 * - Handle Joystick jogging */ -void idle(bool no_stepper_sleep/*=false*/) { +void idle(const bool no_stepper_sleep/*=false*/) { + #ifdef MAX7219_DEBUG_PROFILE + CodeProfiler idle_profiler; + #endif + #if ENABLED(MARLIN_DEV_MODE) static uint16_t idle_depth = 0; if (++idle_depth > 5) SERIAL_ECHOLNPGM("idle() call depth: ", idle_depth); #endif + // Bed Distance Sensor task + TERN_(BD_SENSOR, bdl.process()); + // Core Marlin activities manage_inactivity(no_stepper_sleep); // Manage Heaters (and Watchdog) - thermalManager.manage_heater(); + thermalManager.task(); // Max7219 heartbeat, animation, etc TERN_(MAX7219_DEBUG, max7219.idle_tasks()); @@ -790,7 +810,7 @@ void idle(bool no_stepper_sleep/*=false*/) { #endif // Run HAL idle tasks - TERN_(HAL_IDLETASK, HAL_idletask()); + hal.idletask(); // Check network connection TERN_(HAS_ETHERNET, ethernet.check()); @@ -803,11 +823,11 @@ void idle(bool no_stepper_sleep/*=false*/) { // Run StallGuard endstop checks #if ENABLED(SPI_ENDSTOPS) if (endstops.tmc_spi_homing.any && TERN1(IMPROVE_HOMING_RELIABILITY, ELAPSED(millis(), sg_guard_period))) - LOOP_L_N(i, 4) if (endstops.tmc_spi_homing_check()) break; // Read SGT 4 times per idle loop + for (uint8_t i = 0; i < 4; ++i) if (endstops.tmc_spi_homing_check()) break; // Read SGT 4 times per idle loop #endif // Handle SD Card insert / remove - TERN_(SDSUPPORT, card.manage_media()); + TERN_(HAS_MEDIA, card.manage_media()); // Handle USB Flash Drive insert / remove TERN_(USB_FLASH_DRIVE_SUPPORT, card.diskIODriver()->idle()); @@ -819,10 +839,10 @@ void idle(bool no_stepper_sleep/*=false*/) { TERN_(PRINTCOUNTER, print_job_timer.tick()); // Update the Beeper queue - TERN_(USE_BEEPER, buzzer.tick()); + TERN_(HAS_BEEPER, buzzer.tick()); // Handle UI input / draw events - TERN(HAS_DWIN_E3V2_BASIC, DWIN_Update(), ui.update()); + TERN(DWIN_CREALITY_LCD, DWIN_Update(), ui.update()); // Run i2c Position Encoders #if ENABLED(I2C_POSITION_ENCODERS) @@ -878,7 +898,7 @@ void kill(FSTR_P const lcd_error/*=nullptr*/, FSTR_P const lcd_component/*=nullp // Echo the LCD message to serial for extra context if (lcd_error) { SERIAL_ECHO_START(); SERIAL_ECHOLNF(lcd_error); } - #if EITHER(HAS_DISPLAY, DWIN_CREALITY_LCD_ENHANCED) + #if HAS_DISPLAY ui.kill_screen(lcd_error ?: GET_TEXT_F(MSG_KILLED), lcd_component ?: FPSTR(NUL_STR)); #else UNUSED(lcd_error); UNUSED(lcd_component); @@ -918,22 +938,22 @@ void minkill(const bool steppers_off/*=false*/) { TERN_(HAS_SUICIDE, suicide()); - #if EITHER(HAS_KILL, SOFT_RESET_ON_KILL) + #if ANY(HAS_KILL, SOFT_RESET_ON_KILL) // Wait for both KILL and ENC to be released while (TERN0(HAS_KILL, kill_state()) || TERN0(SOFT_RESET_ON_KILL, ui.button_pressed())) - watchdog_refresh(); + hal.watchdog_refresh(); // Wait for either KILL or ENC to be pressed again while (TERN1(HAS_KILL, !kill_state()) && TERN1(SOFT_RESET_ON_KILL, !ui.button_pressed())) - watchdog_refresh(); + hal.watchdog_refresh(); // Reboot the board - HAL_reboot(); + hal.reboot(); #else - for (;;) watchdog_refresh(); // Wait for RESET button or power-cycle + for (;;) hal.watchdog_refresh(); // Wait for RESET button or power-cycle #endif } @@ -947,7 +967,7 @@ void stop() { print_job_timer.stop(); - #if EITHER(PROBING_FANS_OFF, ADVANCED_PAUSE_FANS_PAUSE) + #if ANY(PROBING_FANS_OFF, ADVANCED_PAUSE_FANS_PAUSE) thermalManager.set_fans_paused(false); // Un-pause fans for safety #endif @@ -993,6 +1013,15 @@ inline void tmc_standby_setup() { #if PIN_EXISTS(K_STDBY) SET_INPUT_PULLDOWN(K_STDBY_PIN); #endif + #if PIN_EXISTS(U_STDBY) + SET_INPUT_PULLDOWN(U_STDBY_PIN); + #endif + #if PIN_EXISTS(V_STDBY) + SET_INPUT_PULLDOWN(V_STDBY_PIN); + #endif + #if PIN_EXISTS(W_STDBY) + SET_INPUT_PULLDOWN(W_STDBY_PIN); + #endif #if PIN_EXISTS(E0_STDBY) SET_INPUT_PULLDOWN(E0_STDBY_PIN); #endif @@ -1038,10 +1067,9 @@ inline void tmc_standby_setup() { * • TMC220x Stepper Drivers (Serial) * • PSU control * • Power-loss Recovery - * • L64XX Stepper Drivers (SPI) * • Stepper Driver Reset: DISABLE * • TMC Stepper Drivers (SPI) - * • Run BOARD_INIT if defined + * • Run hal.init_board() for additional pins setup * • ESP WiFi * - Get the Reset Reason and report it * - Print startup messages and diagnostics @@ -1049,7 +1077,7 @@ inline void tmc_standby_setup() { * - Init the buzzer, possibly a custom timer * - Init more optional hardware: * • Color LED illumination - * • Neopixel illumination + * • NeoPixel illumination * • Controller Fan * • Creality DWIN LCD (show boot image) * • Tare the Probe if possible @@ -1119,8 +1147,8 @@ void setup() { tmc_standby_setup(); // TMC Low Power Standby pins must be set early or they're not usable // Check startup - does nothing if bootloader sets MCUSR to 0 - const byte mcu = HAL_get_reset_source(); - HAL_clear_reset_source(); + const byte mcu = hal.get_reset_source(); + hal.clear_reset_source(); #if ENABLED(MARLIN_DEV_MODE) auto log_current_ms = [&](PGM_P const msg) { @@ -1166,9 +1194,13 @@ void setup() { #endif #endif - #if HAS_FREEZE_PIN + #if ENABLED(FREEZE_FEATURE) SETUP_LOG("FREEZE_PIN"); - SET_INPUT_PULLUP(FREEZE_PIN); + #if FREEZE_STATE + SET_INPUT_PULLDOWN(FREEZE_PIN); + #else + SET_INPUT_PULLUP(FREEZE_PIN); + #endif #endif #if HAS_SUICIDE @@ -1181,29 +1213,26 @@ void setup() { JTAGSWD_RESET(); #endif - #if EITHER(DISABLE_DEBUG, DISABLE_JTAG) + // Disable any hardware debug to free up pins for IO + #if ENABLED(DISABLE_DEBUG) && defined(JTAGSWD_DISABLE) delay(10); - // Disable any hardware debug to free up pins for IO - #if ENABLED(DISABLE_DEBUG) && defined(JTAGSWD_DISABLE) - SETUP_LOG("JTAGSWD_DISABLE"); - JTAGSWD_DISABLE(); - #elif defined(JTAG_DISABLE) - SETUP_LOG("JTAG_DISABLE"); - JTAG_DISABLE(); - #else - #error "DISABLE_(DEBUG|JTAG) is not supported for the selected MCU/Board." - #endif + SETUP_LOG("JTAGSWD_DISABLE"); + JTAGSWD_DISABLE(); + #elif ENABLED(DISABLE_JTAG) && defined(JTAG_DISABLE) + delay(10); + SETUP_LOG("JTAG_DISABLE"); + JTAG_DISABLE(); #endif TERN_(DYNAMIC_VECTORTABLE, hook_cpu_exceptions()); // If supported, install Marlin exception handlers at runtime - SETUP_RUN(HAL_init()); + SETUP_RUN(hal.init()); // Init and disable SPI thermocouples; this is still needed - #if TEMP_SENSOR_0_IS_MAX_TC || (TEMP_SENSOR_REDUNDANT_IS_MAX_TC && REDUNDANT_TEMP_MATCH(SOURCE, E0)) + #if TEMP_SENSOR_IS_MAX_TC(0) || (TEMP_SENSOR_IS_MAX_TC(REDUNDANT) && REDUNDANT_TEMP_MATCH(SOURCE, E0)) OUT_WRITE(TEMP_0_CS_PIN, HIGH); // Disable #endif - #if TEMP_SENSOR_1_IS_MAX_TC || (TEMP_SENSOR_REDUNDANT_IS_MAX_TC && REDUNDANT_TEMP_MATCH(SOURCE, E1)) + #if TEMP_SENSOR_IS_MAX_TC(1) || (TEMP_SENSOR_IS_MAX_TC(REDUNDANT) && REDUNDANT_TEMP_MATCH(SOURCE, E1)) OUT_WRITE(TEMP_1_CS_PIN, HIGH); #endif @@ -1219,6 +1248,13 @@ void setup() { SETUP_RUN(tmc_serial_begin()); #endif + #if HAS_TMC_SPI + #if DISABLED(TMC_USE_SW_SPI) + SETUP_RUN(SPI.begin()); + #endif + SETUP_RUN(tmc_init_cs_pins()); + #endif + #if ENABLED(PSU_CONTROL) SETUP_LOG("PSU_CONTROL"); powerManager.init(); @@ -1228,34 +1264,22 @@ void setup() { SETUP_RUN(recovery.setup()); #endif - #if HAS_L64XX - SETUP_RUN(L64xxManager.init()); // Set up SPI, init drivers - #endif - #if HAS_STEPPER_RESET SETUP_RUN(disableStepperDrivers()); #endif - #if HAS_TMC_SPI - #if DISABLED(TMC_USE_SW_SPI) - SETUP_RUN(SPI.begin()); - #endif - SETUP_RUN(tmc_init_cs_pins()); - #endif + SETUP_RUN(hal.init_board()); - #ifdef BOARD_INIT - SETUP_LOG("BOARD_INIT"); - BOARD_INIT(); + #if ENABLED(WIFISUPPORT) + SETUP_RUN(esp_wifi_init()); #endif - SETUP_RUN(esp_wifi_init()); - // Report Reset Reason - if (mcu & RST_POWER_ON) SERIAL_ECHOLNPGM(STR_POWERUP); - if (mcu & RST_EXTERNAL) SERIAL_ECHOLNPGM(STR_EXTERNAL_RESET); + if (mcu & RST_POWER_ON) SERIAL_ECHOLNPGM(STR_POWERUP); + if (mcu & RST_EXTERNAL) SERIAL_ECHOLNPGM(STR_EXTERNAL_RESET); if (mcu & RST_BROWN_OUT) SERIAL_ECHOLNPGM(STR_BROWNOUT_RESET); - if (mcu & RST_WATCHDOG) SERIAL_ECHOLNPGM(STR_WATCHDOG_RESET); - if (mcu & RST_SOFTWARE) SERIAL_ECHOLNPGM(STR_SOFTWARE_RESET); + if (mcu & RST_WATCHDOG) SERIAL_ECHOLNPGM(STR_WATCHDOG_RESET); + if (mcu & RST_SOFTWARE) SERIAL_ECHOLNPGM(STR_SOFTWARE_RESET); // Identify myself as Marlin x.x.x SERIAL_ECHOLNPGM("Marlin " SHORT_BUILD_VERSION); @@ -1266,13 +1290,13 @@ void setup() { ); #endif SERIAL_ECHO_MSG(" Compiled: " __DATE__); - SERIAL_ECHO_MSG(STR_FREE_MEMORY, freeMemory(), STR_PLANNER_BUFFER_BYTES, sizeof(block_t) * (BLOCK_BUFFER_SIZE)); + SERIAL_ECHO_MSG(STR_FREE_MEMORY, hal.freeMemory(), STR_PLANNER_BUFFER_BYTES, sizeof(block_t) * (BLOCK_BUFFER_SIZE)); // Some HAL need precise delay adjustment calibrate_delay_loop(); // Init buzzer pin(s) - #if USE_BEEPER + #if HAS_BEEPER SETUP_RUN(buzzer.init()); #endif @@ -1294,16 +1318,7 @@ void setup() { // UI must be initialized before EEPROM // (because EEPROM code calls the UI). - #if HAS_DWIN_E3V2_BASIC - SETUP_RUN(DWIN_Startup()); - #else - SETUP_RUN(ui.init()); - #if BOTH(HAS_WIRED_LCD, SHOW_BOOTSCREEN) - SETUP_RUN(ui.show_bootscreen()); - const millis_t bootscreen_ms = millis(); - #endif - SETUP_RUN(ui.reset_status()); // Load welcome message early. (Retained if no errors exist.) - #endif + SETUP_RUN(ui.init()); #if PIN_EXISTS(SAFE_POWER) #if HAS_DRIVER_SAFE_POWER_PROTECT @@ -1314,17 +1329,22 @@ void setup() { #endif #endif - #if ENABLED(PROBE_TARE) - SETUP_RUN(probe.tare_init()); - #endif - - #if BOTH(SDSUPPORT, SDCARD_EEPROM_EMULATION) + #if HAS_MEDIA && ANY(SDCARD_EEPROM_EMULATION, POWER_LOSS_RECOVERY) SETUP_RUN(card.mount()); // Mount media with settings before first_load #endif SETUP_RUN(settings.first_load()); // Load data from EEPROM if available (or use defaults) // This also updates variables in the planner, elsewhere + #if ALL(HAS_WIRED_LCD, SHOW_BOOTSCREEN) + SETUP_RUN(ui.show_bootscreen()); + const millis_t bootscreen_ms = millis(); + #endif + + #if ENABLED(PROBE_TARE) + SETUP_RUN(probe.tare_init()); + #endif + #if HAS_ETHERNET SETUP_RUN(ethernet.init()); #endif @@ -1343,6 +1363,10 @@ void setup() { SETUP_RUN(endstops.init()); // Init endstops and pullups + #if ENABLED(DELTA) && !HAS_SOFTWARE_ENDSTOPS + SETUP_RUN(refresh_delta_clip_start_height()); // Init safe delta height without soft endstops + #endif + SETUP_RUN(stepper.init()); // Init stepper. This enables interrupts! #if HAS_SERVOS @@ -1387,7 +1411,7 @@ void setup() { SETUP_RUN(stepper_dac.init()); #endif - #if EITHER(Z_PROBE_SLED, SOLENOID_PROBE) && HAS_SOLENOID_1 + #if ANY(Z_PROBE_SLED, SOLENOID_PROBE) && HAS_SOLENOID_1 OUT_WRITE(SOL1_PIN, LOW); // OFF #endif @@ -1502,6 +1526,10 @@ void setup() { SETUP_RUN(bltouch.init(/*set_voltage=*/true)); #endif + #if ENABLED(MAGLEV4) + OUT_WRITE(MAGLEV_TRIGGER_PIN, LOW); + #endif + #if ENABLED(I2C_POSITION_ENCODERS) SETUP_RUN(I2CPEM.init()); #endif @@ -1538,7 +1566,7 @@ void setup() { #endif #if ENABLED(USE_WATCHDOG) - SETUP_RUN(watchdog_init()); // Reinit watchdog after HAL_get_reset_source call + SETUP_RUN(hal.watchdog_init()); // Reinit watchdog after hal.get_reset_source call #endif #if ENABLED(EXTERNAL_CLOSED_LOOP_CONTROLLER) @@ -1554,10 +1582,6 @@ void setup() { SETUP_RUN(hostui.prompt_end()); #endif - #if HAS_TRINAMIC_CONFIG && DISABLED(PSU_DEFAULT_OFF) - SETUP_RUN(test_tmc_connection()); - #endif - #if HAS_DRIVER_SAFE_POWER_PROTECT SETUP_RUN(stepper_driver_backward_report()); #endif @@ -1573,11 +1597,7 @@ void setup() { #endif #if HAS_DWIN_E3V2_BASIC - SETUP_LOG("E3V2 Init"); - Encoder_Configuration(); - HMI_Init(); - HMI_SetLanguageCache(); - HMI_StartFrame(true); + SETUP_RUN(DWIN_InitScreen()); #endif #if HAS_SERVICE_INTERVALS && !HAS_DWIN_E3V2_BASIC @@ -1593,13 +1613,13 @@ void setup() { #endif #if HAS_TFT_LVGL_UI - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA if (!card.isMounted()) SETUP_RUN(card.mount()); // Mount SD to load graphics and fonts #endif SETUP_RUN(tft_lvgl_init()); #endif - #if BOTH(HAS_WIRED_LCD, SHOW_BOOTSCREEN) + #if ALL(HAS_WIRED_LCD, SHOW_BOOTSCREEN) const millis_t elapsed = millis() - bootscreen_ms; #if ENABLED(MARLIN_DEV_MODE) SERIAL_ECHOLNPGM("elapsed=", elapsed); @@ -1611,7 +1631,7 @@ void setup() { SETUP_RUN(password.lock_machine()); // Will not proceed until correct password provided #endif - #if BOTH(HAS_LCD_MENU, TOUCH_SCREEN_CALIBRATION) && EITHER(TFT_CLASSIC_UI, TFT_COLOR_UI) + #if ALL(HAS_MARLINUI_MENU, TOUCH_SCREEN_CALIBRATION) && ANY(TFT_CLASSIC_UI, TFT_COLOR_UI) SETUP_RUN(ui.check_touch_calibration()); #endif @@ -1619,9 +1639,19 @@ void setup() { SETUP_RUN(easythreed_ui.init()); #endif + #if HAS_TRINAMIC_CONFIG && DISABLED(PSU_DEFAULT_OFF) + SETUP_RUN(test_tmc_connection()); + #endif + + #if ENABLED(BD_SENSOR) + SETUP_RUN(bdl.init(I2C_BD_SDA_PIN, I2C_BD_SCL_PIN, I2C_BD_DELAY)); + #endif + marlin_state = MF_RUNNING; SETUP_LOG("setup() completed."); + + TERN_(MARLIN_TEST_BUILD, runStartupTests()); } /** @@ -1641,16 +1671,22 @@ void loop() { do { idle(); - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA if (card.flag.abort_sd_printing) abortSDPrinting(); if (marlin_state == MF_SD_COMPLETE) finishSDPrinting(); #endif queue.advance(); + #if ANY(POWER_OFF_TIMER, POWER_OFF_WAIT_FOR_COOLDOWN) + powerManager.checkAutoPowerOff(); + #endif + endstops.event_handler(); TERN_(HAS_TFT_LVGL_UI, printer_state_polling()); + TERN_(MARLIN_TEST_BUILD, runPeriodicTests()); + } while (ENABLED(__AVR__)); // Loop forever on slower (AVR) boards } diff --git a/Marlin/src/MarlinCore.h b/Marlin/src/MarlinCore.h index 7063c7e2..e9c63bb3 100644 --- a/Marlin/src/MarlinCore.h +++ b/Marlin/src/MarlinCore.h @@ -30,7 +30,7 @@ void stop(); // Pass true to keep steppers from timing out -void idle(bool no_stepper_sleep=false); +void idle(const bool no_stepper_sleep=false); inline void idle_no_sleep() { idle(true); } #if ENABLED(G38_PROBE_TARGET) @@ -61,6 +61,8 @@ bool printJobOngoing(); bool printingIsPaused(); void startOrResumeJob(); +bool printer_busy(); + extern bool wait_for_heatup; #if HAS_RESUME_CONTINUE diff --git a/Marlin/src/core/boards.h b/Marlin/src/core/boards.h index aee9b3c4..a459f232 100644 --- a/Marlin/src/core/boards.h +++ b/Marlin/src/core/boards.h @@ -21,6 +21,11 @@ */ #pragma once +/** + * Whenever changes are made to this file, please update Marlin/Makefile + * and _data/boards.yml in the MarlinDocumentation repo. + */ + #include "macros.h" #define BOARD_UNKNOWN -1 @@ -110,11 +115,14 @@ #define BOARD_COPYMASTER_3D 1154 // Copymaster 3D #define BOARD_ORTUR_4 1155 // Ortur 4 #define BOARD_TENLOG_D3_HERO 1156 // Tenlog D3 Hero IDEX printer -#define BOARD_RAMPS_S_12_EEFB 1157 // Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Fan, Bed) -#define BOARD_RAMPS_S_12_EEEB 1158 // Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Hotend2, Bed) -#define BOARD_RAMPS_S_12_EFFB 1159 // Ramps S 1.2 by Sakul.cz (Power outputs: Hotend, Fan0, Fan1, Bed) -#define BOARD_LONGER3D_LK1_PRO 1160 // Longer LK1 PRO / Alfawise U20 Pro (PRO version) -#define BOARD_LONGER3D_LKx_PRO 1161 // Longer LKx PRO / Alfawise Uxx Pro (PRO version) +#define BOARD_TENLOG_MB1_V23 1157 // Tenlog D3, D5, D6 IDEX Printer +#define BOARD_RAMPS_S_12_EEFB 1158 // Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Fan, Bed) +#define BOARD_RAMPS_S_12_EEEB 1159 // Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Hotend2, Bed) +#define BOARD_RAMPS_S_12_EFFB 1160 // Ramps S 1.2 by Sakul.cz (Power outputs: Hotend, Fan0, Fan1, Bed) +#define BOARD_LONGER3D_LK1_PRO 1161 // Longer LK1 PRO / Alfawise U20 Pro (PRO version) +#define BOARD_LONGER3D_LKx_PRO 1162 // Longer LKx PRO / Alfawise Uxx Pro (PRO version) +#define BOARD_ZRIB_V53 1163 // Zonestar zrib V5.3 (Chinese RAMPS replica) +#define BOARD_PXMALION_CORE_I3 1164 // Pxmalion Core I3 // // RAMBo and derivatives @@ -159,9 +167,10 @@ #define BOARD_PICA_REVB 1324 // PICA Shield (original version) #define BOARD_PICA 1325 // PICA Shield (rev C or later) #define BOARD_INTAMSYS40 1326 // Intamsys 4.0 (Funmat HT) -#define BOARD_MALYAN_M180 1327 // Malyan M180 Mainboard Version 2 (no display function, direct gcode only) +#define BOARD_MALYAN_M180 1327 // Malyan M180 Mainboard Version 2 (no display function, direct G-code only) #define BOARD_GT2560_V4_A20 1328 // Geeetech GT2560 Rev B for A20(M/T/D) #define BOARD_PROTONEER_CNC_SHIELD_V3 1329 // Mega controller & Protoneer CNC Shield V3.00 +#define BOARD_WEEDO_62A 1330 // WEEDO 62A board (TINA2, Monoprice Cadet, etc.) // // ATmega1281, ATmega2561 @@ -217,7 +226,7 @@ #define BOARD_5DPRINT 1707 // 5DPrint D8 Driver Board // -// LPC1768 ARM Cortex M3 +// LPC1768 ARM Cortex-M3 // #define BOARD_RAMPS_14_RE_ARM_EFB 2000 // Re-ARM with RAMPS 1.4 (Power outputs: Hotend, Fan, Bed) @@ -225,36 +234,37 @@ #define BOARD_RAMPS_14_RE_ARM_EFF 2002 // Re-ARM with RAMPS 1.4 (Power outputs: Hotend, Fan0, Fan1) #define BOARD_RAMPS_14_RE_ARM_EEF 2003 // Re-ARM with RAMPS 1.4 (Power outputs: Hotend0, Hotend1, Fan) #define BOARD_RAMPS_14_RE_ARM_SF 2004 // Re-ARM with RAMPS 1.4 (Power outputs: Spindle, Controller Fan) -#define BOARD_MKS_SBASE 2005 // MKS-Sbase (Power outputs: Hotend0, Hotend1, Bed, Fan) +#define BOARD_MKS_SBASE 2005 // MKS-Sbase #define BOARD_AZSMZ_MINI 2006 // AZSMZ Mini -#define BOARD_BIQU_BQ111_A4 2007 // BIQU BQ111-A4 (Power outputs: Hotend, Fan, Bed) -#define BOARD_SELENA_COMPACT 2008 // Selena Compact (Power outputs: Hotend0, Hotend1, Bed0, Bed1, Fan0, Fan1) -#define BOARD_BIQU_B300_V1_0 2009 // BIQU B300_V1.0 (Power outputs: Hotend0, Fan, Bed, SPI Driver) -#define BOARD_MKS_SGEN_L 2010 // MKS-SGen-L (Power outputs: Hotend0, Hotend1, Bed, Fan) +#define BOARD_BIQU_BQ111_A4 2007 // BIQU BQ111-A4 +#define BOARD_SELENA_COMPACT 2008 // Selena Compact +#define BOARD_BIQU_B300_V1_0 2009 // BIQU B300_V1.0 +#define BOARD_MKS_SGEN_L 2010 // MKS-SGen-L #define BOARD_GMARSH_X6_REV1 2011 // GMARSH X6, revision 1 prototype -#define BOARD_BTT_SKR_V1_1 2012 // BigTreeTech SKR v1.1 (Power outputs: Hotend0, Hotend1, Fan, Bed) -#define BOARD_BTT_SKR_V1_3 2013 // BigTreeTech SKR v1.3 (Power outputs: Hotend0, Hotend1, Fan, Bed) -#define BOARD_BTT_SKR_V1_4 2014 // BigTreeTech SKR v1.4 (Power outputs: Hotend0, Hotend1, Fan, Bed) +#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 +// LPC1769 ARM Cortex-M3 // -#define BOARD_MKS_SGEN 2500 // MKS-SGen (Power outputs: Hotend0, Hotend1, Bed, Fan) -#define BOARD_AZTEEG_X5_GT 2501 // Azteeg X5 GT (Power outputs: Hotend0, Hotend1, Bed, Fan) -#define BOARD_AZTEEG_X5_MINI 2502 // Azteeg X5 Mini (Power outputs: Hotend0, Bed, Fan) -#define BOARD_AZTEEG_X5_MINI_WIFI 2503 // Azteeg X5 Mini Wifi (Power outputs: Hotend0, Bed, Fan) +#define BOARD_MKS_SGEN 2500 // MKS-SGen +#define BOARD_AZTEEG_X5_GT 2501 // Azteeg X5 GT +#define BOARD_AZTEEG_X5_MINI 2502 // Azteeg X5 Mini +#define BOARD_AZTEEG_X5_MINI_WIFI 2503 // Azteeg X5 Mini Wifi #define BOARD_COHESION3D_REMIX 2504 // Cohesion3D ReMix #define BOARD_COHESION3D_MINI 2505 // Cohesion3D Mini #define BOARD_SMOOTHIEBOARD 2506 // Smoothieboard #define BOARD_TH3D_EZBOARD 2507 // TH3D EZBoard v1.0 -#define BOARD_BTT_SKR_V1_4_TURBO 2508 // BigTreeTech SKR v1.4 TURBO (Power outputs: Hotend0, Hotend1, Fan, Bed) -#define BOARD_MKS_SGEN_L_V2 2509 // MKS SGEN_L V2 (Power outputs: Hotend0, Hotend1, Bed, Fan) -#define BOARD_BTT_SKR_E3_TURBO 2510 // BigTreeTech SKR E3 Turbo (Power outputs: Hotend0, Hotend1, Bed, Fan0, Fan1) -#define BOARD_FLY_CDY 2511 // FLYmaker FLY CDY (Power outputs: Hotend0, Hotend1, Hotend2, Bed, Fan0, Fan1, Fan2) +#define BOARD_BTT_SKR_V1_4_TURBO 2508 // BigTreeTech SKR v1.4 TURBO +#define BOARD_MKS_SGEN_L_V2 2509 // MKS SGEN_L V2 +#define BOARD_BTT_SKR_E3_TURBO 2510 // BigTreeTech SKR E3 Turbo +#define BOARD_FLY_CDY 2511 // FLYmaker FLY CDY // -// SAM3X8E ARM Cortex M3 +// SAM3X8E ARM Cortex-M3 // #define BOARD_DUE3DOM 3000 // DUE3DOM for Arduino DUE @@ -277,8 +287,8 @@ #define BOARD_RAMPS4DUE_EFF 3017 // RAMPS4DUE (Power outputs: Hotend, Fan0, Fan1) #define BOARD_RAMPS4DUE_EEF 3018 // RAMPS4DUE (Power outputs: Hotend0, Hotend1, Fan) #define BOARD_RAMPS4DUE_SF 3019 // RAMPS4DUE (Power outputs: Spindle, Controller Fan) -#define BOARD_RURAMPS4D_11 3020 // RuRAMPS4Duo v1.1 (Power outputs: Hotend0, Hotend1, Hotend2, Fan0, Fan1, Bed) -#define BOARD_RURAMPS4D_13 3021 // RuRAMPS4Duo v1.3 (Power outputs: Hotend0, Hotend1, Hotend2, Fan0, Fan1, Bed) +#define BOARD_RURAMPS4D_11 3020 // RuRAMPS4Duo v1.1 +#define BOARD_RURAMPS4D_13 3021 // RuRAMPS4Duo v1.3 #define BOARD_ULTRATRONICS_PRO 3022 // ReprapWorld Ultratronics Pro V1.0 #define BOARD_ARCHIM1 3023 // UltiMachine Archim1 (with DRV8825 drivers) #define BOARD_ARCHIM2 3024 // UltiMachine Archim2 (with TMC2130 drivers) @@ -287,159 +297,196 @@ #define BOARD_KRATOS32 3027 // K.3D Kratos32 (Arduino Due Shield) // -// SAM3X8C ARM Cortex M3 +// SAM3X8C ARM Cortex-M3 // -#define BOARD_PRINTRBOARD_G2 3100 // PRINTRBOARD G2 +#define BOARD_PRINTRBOARD_G2 3100 // Printrboard G2 #define BOARD_ADSK 3101 // Arduino DUE Shield Kit (ADSK) +// +// STM32 ARM Cortex-M0+ +// + +#define BOARD_BTT_EBB42_V1_1 4000 // BigTreeTech EBB42 V1.1 (STM32G0B1CB) +#define BOARD_BTT_SKR_MINI_E3_V3_0 4001 // BigTreeTech SKR Mini E3 V3.0 (STM32G0B0RE / STM32G0B1RE) +#define BOARD_BTT_MANTA_E3_EZ_V1_0 4002 // BigTreeTech Manta E3 EZ V1.0 (STM32G0B1RE) +#define BOARD_BTT_MANTA_M4P_V2_1 4003 // BigTreeTech Manta M4P V2.1 (STM32G0B0RE) +#define BOARD_BTT_MANTA_M5P_V1_0 4004 // BigTreeTech Manta M5P V1.0 (STM32G0B1RE) +#define BOARD_BTT_MANTA_M8P_V1_0 4005 // BigTreeTech Manta M8P V1.0 (STM32G0B1VE) +#define BOARD_BTT_MANTA_M8P_V1_1 4006 // BigTreeTech Manta M8P V1.1 (STM32G0B1VE) + // // STM32 ARM Cortex-M3 // -#define BOARD_MALYAN_M200_V2 4000 // STM32F070CB controller -#define BOARD_MALYAN_M300 4001 // STM32F070-based delta -#define BOARD_STM32F103RE 4002 // STM32F103RE Libmaple-based STM32F1 controller -#define BOARD_MALYAN_M200 4003 // STM32C8T6 Libmaple-based STM32F1 controller -#define BOARD_STM3R_MINI 4004 // STM32F103RE Libmaple-based STM32F1 controller -#define BOARD_GTM32_PRO_VB 4005 // STM32F103VET6 controller -#define BOARD_GTM32_MINI 4006 // STM32F103VET6 controller -#define BOARD_GTM32_MINI_A30 4007 // STM32F103VET6 controller -#define BOARD_GTM32_REV_B 4008 // STM32F103VET6 controller -#define BOARD_MORPHEUS 4009 // STM32F103C8 / STM32F103CB Libmaple-based STM32F1 controller -#define BOARD_CHITU3D 4010 // Chitu3D (STM32F103RET6) -#define BOARD_MKS_ROBIN 4011 // MKS Robin (STM32F103ZET6) -#define BOARD_MKS_ROBIN_MINI 4012 // MKS Robin Mini (STM32F103VET6) -#define BOARD_MKS_ROBIN_NANO 4013 // MKS Robin Nano (STM32F103VET6) -#define BOARD_MKS_ROBIN_NANO_V2 4014 // MKS Robin Nano V2 (STM32F103VET6) -#define BOARD_MKS_ROBIN_LITE 4015 // MKS Robin Lite/Lite2 (STM32F103RCT6) -#define BOARD_MKS_ROBIN_LITE3 4016 // MKS Robin Lite3 (STM32F103RCT6) -#define BOARD_MKS_ROBIN_PRO 4017 // MKS Robin Pro (STM32F103ZET6) -#define BOARD_MKS_ROBIN_E3 4018 // MKS Robin E3 (STM32F103RCT6) -#define BOARD_MKS_ROBIN_E3_V1_1 4019 // MKS Robin E3 V1.1 (STM32F103RCT6) -#define BOARD_MKS_ROBIN_E3D 4020 // MKS Robin E3D (STM32F103RCT6) -#define BOARD_MKS_ROBIN_E3D_V1_1 4021 // MKS Robin E3D V1.1 (STM32F103RCT6) -#define BOARD_MKS_ROBIN_E3P 4022 // MKS Robin E3p (STM32F103VET6) -#define BOARD_BTT_SKR_MINI_V1_1 4023 // BigTreeTech SKR Mini v1.1 (STM32F103RC) -#define BOARD_BTT_SKR_MINI_E3_V1_0 4024 // BigTreeTech SKR Mini E3 (STM32F103RC) -#define BOARD_BTT_SKR_MINI_E3_V1_2 4025 // BigTreeTech SKR Mini E3 V1.2 (STM32F103RC) -#define BOARD_BTT_SKR_MINI_E3_V2_0 4026 // BigTreeTech SKR Mini E3 V2.0 (STM32F103RC / STM32F103RE) -#define BOARD_BTT_SKR_MINI_E3_V3_0 4027 // BigTreeTech SKR Mini E3 V3.0 (STM32G0B1RE) -#define BOARD_BTT_SKR_MINI_MZ_V1_0 4028 // BigTreeTech SKR Mini MZ V1.0 (STM32F103RC) -#define BOARD_BTT_SKR_E3_DIP 4029 // BigTreeTech SKR E3 DIP V1.0 (STM32F103RC / STM32F103RE) -#define BOARD_BTT_SKR_CR6 4030 // BigTreeTech SKR CR6 v1.0 (STM32F103RE) -#define BOARD_JGAURORA_A5S_A1 4031 // JGAurora A5S A1 (STM32F103ZET6) -#define BOARD_FYSETC_AIO_II 4032 // FYSETC AIO_II -#define BOARD_FYSETC_CHEETAH 4033 // FYSETC Cheetah -#define BOARD_FYSETC_CHEETAH_V12 4034 // FYSETC Cheetah V1.2 -#define BOARD_LONGER3D_LK 4035 // Alfawise U20/U20+/U30 (Longer3D LK1/2) / STM32F103VET6 -#define BOARD_CCROBOT_MEEB_3DP 4036 // ccrobot-online.com MEEB_3DP (STM32F103RC) -#define BOARD_CHITU3D_V5 4037 // Chitu3D TronXY X5SA V5 Board -#define BOARD_CHITU3D_V6 4038 // Chitu3D TronXY X5SA V6 Board -#define BOARD_CHITU3D_V9 4039 // Chitu3D TronXY X5SA V9 Board -#define BOARD_CREALITY_V4 4040 // Creality v4.x (STM32F103RE) -#define BOARD_CREALITY_V423 4041 // Creality v4.2.3 (STM32F103RE) -#define BOARD_CREALITY_V427 4042 // Creality v4.2.7 (STM32F103RE) -#define BOARD_CREALITY_V4210 4043 // Creality v4.2.10 (STM32F103RE) as found in the CR-30 -#define BOARD_CREALITY_V431 4044 // Creality v4.3.1 (STM32F103RE) -#define BOARD_CREALITY_V431_A 4045 // Creality v4.3.1a (STM32F103RE) -#define BOARD_CREALITY_V431_B 4046 // Creality v4.3.1b (STM32F103RE) -#define BOARD_CREALITY_V431_C 4047 // Creality v4.3.1c (STM32F103RE) -#define BOARD_CREALITY_V431_D 4048 // Creality v4.3.1d (STM32F103RE) -#define BOARD_CREALITY_V452 4049 // Creality v4.5.2 (STM32F103RE) -#define BOARD_CREALITY_V453 4050 // Creality v4.5.3 (STM32F103RE) -#define BOARD_CREALITY_V24S1 4051 // Creality v2.4.S1 (STM32F103RE) v101 as found in the Ender 7 -#define BOARD_TRIGORILLA_PRO 4052 // Trigorilla Pro (STM32F103ZET6) -#define BOARD_FLY_MINI 4053 // FLYmaker FLY MINI (STM32F103RCT6) -#define BOARD_FLSUN_HISPEED 4054 // FLSUN HiSpeedV1 (STM32F103VET6) -#define BOARD_BEAST 4055 // STM32F103RET6 Libmaple-based controller -#define BOARD_MINGDA_MPX_ARM_MINI 4056 // STM32F103ZET6 Mingda MD-16 -#define BOARD_GTM32_PRO_VD 4057 // STM32F103VET6 controller -#define BOARD_ZONESTAR_ZM3E2 4058 // Zonestar ZM3E2 (STM32F103RCT6) -#define BOARD_ZONESTAR_ZM3E4 4059 // Zonestar ZM3E4 V1 (STM32F103VCT6) -#define BOARD_ZONESTAR_ZM3E4V2 4060 // Zonestar ZM3E4 V2 (STM32F103VCT6) -#define BOARD_ERYONE_ERY32_MINI 4061 // Eryone Ery32 mini (STM32F103VET6) +#define BOARD_MALYAN_M200_V2 5000 // STM32F070CB controller +#define BOARD_MALYAN_M300 5001 // STM32F070-based delta +#define BOARD_STM32F103RE 5002 // STM32F103RE Libmaple-based STM32F1 controller +#define BOARD_MALYAN_M200 5003 // STM32C8 Libmaple-based STM32F1 controller +#define BOARD_STM3R_MINI 5004 // STM32F103RE Libmaple-based STM32F1 controller +#define BOARD_GTM32_PRO_VB 5005 // STM32F103VE controller +#define BOARD_GTM32_MINI 5006 // STM32F103VE controller +#define BOARD_GTM32_MINI_A30 5007 // STM32F103VE controller +#define BOARD_GTM32_REV_B 5008 // STM32F103VE controller +#define BOARD_MORPHEUS 5009 // STM32F103C8 / STM32F103CB Libmaple-based STM32F1 controller +#define BOARD_CHITU3D 5010 // Chitu3D (STM32F103RE) +#define BOARD_MKS_ROBIN 5011 // MKS Robin (STM32F103ZE) +#define BOARD_MKS_ROBIN_MINI 5012 // MKS Robin Mini (STM32F103VE) +#define BOARD_MKS_ROBIN_NANO 5013 // MKS Robin Nano (STM32F103VE) +#define BOARD_MKS_ROBIN_NANO_V2 5014 // MKS Robin Nano V2 (STM32F103VE) +#define BOARD_MKS_ROBIN_LITE 5015 // MKS Robin Lite/Lite2 (STM32F103RC) +#define BOARD_MKS_ROBIN_LITE3 5016 // MKS Robin Lite3 (STM32F103RC) +#define BOARD_MKS_ROBIN_PRO 5017 // MKS Robin Pro (STM32F103ZE) +#define BOARD_MKS_ROBIN_E3 5018 // MKS Robin E3 (STM32F103RC) +#define BOARD_MKS_ROBIN_E3_V1_1 5019 // MKS Robin E3 V1.1 (STM32F103RC) +#define BOARD_MKS_ROBIN_E3D 5020 // MKS Robin E3D (STM32F103RC) +#define BOARD_MKS_ROBIN_E3D_V1_1 5021 // MKS Robin E3D V1.1 (STM32F103RC) +#define BOARD_MKS_ROBIN_E3P 5022 // MKS Robin E3P (STM32F103VE) +#define BOARD_BTT_SKR_MINI_V1_1 5023 // BigTreeTech SKR Mini v1.1 (STM32F103RC) +#define BOARD_BTT_SKR_MINI_E3_V1_0 5024 // BigTreeTech SKR Mini E3 (STM32F103RC) +#define BOARD_BTT_SKR_MINI_E3_V1_2 5025 // BigTreeTech SKR Mini E3 V1.2 (STM32F103RC) +#define BOARD_BTT_SKR_MINI_E3_V2_0 5026 // BigTreeTech SKR Mini E3 V2.0 (STM32F103RC / STM32F103RE) +#define BOARD_BTT_SKR_MINI_MZ_V1_0 5027 // BigTreeTech SKR Mini MZ V1.0 (STM32F103RC) +#define BOARD_BTT_SKR_E3_DIP 5028 // BigTreeTech SKR E3 DIP V1.0 (STM32F103RC / STM32F103RE) +#define BOARD_BTT_SKR_CR6 5029 // BigTreeTech SKR CR6 v1.0 (STM32F103RE) +#define BOARD_JGAURORA_A5S_A1 5030 // JGAurora A5S A1 (STM32F103ZE) +#define BOARD_FYSETC_AIO_II 5031 // FYSETC AIO_II (STM32F103RC) +#define BOARD_FYSETC_CHEETAH 5032 // FYSETC Cheetah (STM32F103RC) +#define BOARD_FYSETC_CHEETAH_V12 5033 // FYSETC Cheetah V1.2 (STM32F103RC) +#define BOARD_LONGER3D_LK 5034 // Longer3D LK1/2 - Alfawise U20/U20+/U30 (STM32F103VE) +#define BOARD_CCROBOT_MEEB_3DP 5035 // ccrobot-online.com MEEB_3DP (STM32F103RC) +#define BOARD_CHITU3D_V5 5036 // Chitu3D TronXY X5SA V5 Board (STM32F103ZE) +#define BOARD_CHITU3D_V6 5037 // Chitu3D TronXY X5SA V6 Board (STM32F103ZE) +#define BOARD_CHITU3D_V9 5038 // Chitu3D TronXY X5SA V9 Board (STM32F103ZE) +#define BOARD_CREALITY_V4 5039 // Creality v4.x (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V422 5040 // Creality v4.2.2 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V423 5041 // Creality v4.2.3 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V425 5042 // Creality v4.2.5 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V427 5043 // Creality v4.2.7 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V4210 5044 // Creality v4.2.10 (STM32F103RC / STM32F103RE) as found in the CR-30 +#define BOARD_CREALITY_V431 5045 // Creality v4.3.1 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V431_A 5046 // Creality v4.3.1a (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V431_B 5047 // Creality v4.3.1b (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V431_C 5048 // Creality v4.3.1c (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V431_D 5049 // Creality v4.3.1d (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V452 5050 // Creality v4.5.2 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V453 5051 // Creality v4.5.3 (STM32F103RC / STM32F103RE) +#define BOARD_CREALITY_V521 5052 // Creality v5.2.1 (STM32F103VE) as found in the SV04 +#define BOARD_CREALITY_V24S1 5053 // Creality v2.4.S1 (STM32F103RC / STM32F103RE) v101 as found in the Ender-7 +#define BOARD_CREALITY_V24S1_301 5054 // Creality v2.4.S1_301 (STM32F103RC / STM32F103RE) v301 as found in the Ender-3 S1 +#define BOARD_CREALITY_V25S1 5055 // Creality v2.5.S1 (STM32F103RE) as found in the CR-10 Smart Pro +#define BOARD_TRIGORILLA_PRO 5056 // Trigorilla Pro (STM32F103ZE) +#define BOARD_FLY_MINI 5057 // FLYmaker FLY MINI (STM32F103RC) +#define BOARD_FLSUN_HISPEED 5058 // FLSUN HiSpeedV1 (STM32F103VE) +#define BOARD_BEAST 5059 // STM32F103RE Libmaple-based controller +#define BOARD_MINGDA_MPX_ARM_MINI 5060 // STM32F103ZE Mingda MD-16 +#define BOARD_GTM32_PRO_VD 5061 // STM32F103VE controller +#define BOARD_ZONESTAR_ZM3E2 5062 // Zonestar ZM3E2 (STM32F103RC) +#define BOARD_ZONESTAR_ZM3E4 5063 // Zonestar ZM3E4 V1 (STM32F103VC) +#define BOARD_ZONESTAR_ZM3E4V2 5064 // Zonestar ZM3E4 V2 (STM32F103VC) +#define BOARD_ERYONE_ERY32_MINI 5065 // Eryone Ery32 mini (STM32F103VE) +#define BOARD_PANDA_PI_V29 5066 // Panda Pi V2.9 - Standalone (STM32F103RC) +#define BOARD_SOVOL_V131 5067 // Sovol V1.3.1 (GD32F103RE) // // ARM Cortex-M4F // -#define BOARD_TEENSY31_32 4100 // Teensy3.1 and Teensy3.2 -#define BOARD_TEENSY35_36 4101 // Teensy3.5 and Teensy3.6 +#define BOARD_TEENSY31_32 5100 // Teensy3.1 and Teensy3.2 +#define BOARD_TEENSY35_36 5101 // Teensy3.5 and Teensy3.6 // // STM32 ARM Cortex-M4F // -#define BOARD_ARMED 4200 // Arm'ed STM32F4-based controller -#define BOARD_RUMBA32_V1_0 4201 // RUMBA32 STM32F446VET6 based controller from Aus3D -#define BOARD_RUMBA32_V1_1 4202 // RUMBA32 STM32F446VET6 based controller from Aus3D -#define BOARD_RUMBA32_MKS 4203 // RUMBA32 STM32F446VET6 based controller from Makerbase -#define BOARD_RUMBA32_BTT 4204 // RUMBA32 STM32F446VET6 based controller from BIGTREETECH -#define BOARD_BLACK_STM32F407VE 4205 // BLACK_STM32F407VE -#define BOARD_BLACK_STM32F407ZE 4206 // BLACK_STM32F407ZE -#define BOARD_STEVAL_3DP001V1 4207 // STEVAL-3DP001V1 3D PRINTER BOARD -#define BOARD_BTT_SKR_PRO_V1_1 4208 // BigTreeTech SKR Pro v1.1 (STM32F407ZGT6) -#define BOARD_BTT_SKR_PRO_V1_2 4209 // BigTreeTech SKR Pro v1.2 (STM32F407ZGT6) -#define BOARD_BTT_BTT002_V1_0 4210 // BigTreeTech BTT002 v1.0 (STM32F407VGT6) -#define BOARD_BTT_E3_RRF 4211 // BigTreeTech E3 RRF (STM32F407VGT6) -#define BOARD_BTT_SKR_V2_0_REV_A 4212 // BigTreeTech SKR v2.0 Rev A (STM32F407VGT6) -#define BOARD_BTT_SKR_V2_0_REV_B 4213 // BigTreeTech SKR v2.0 Rev B (STM32F407VGT6/STM32F429VGT6) -#define BOARD_BTT_GTR_V1_0 4214 // BigTreeTech GTR v1.0 (STM32F407IGT) -#define BOARD_BTT_OCTOPUS_V1_0 4215 // BigTreeTech Octopus v1.0 (STM32F446ZET6) -#define BOARD_BTT_OCTOPUS_V1_1 4216 // BigTreeTech Octopus v1.1 (STM32F446ZET6) -#define BOARD_BTT_OCTOPUS_PRO_V1_0 4217 // BigTreeTech Octopus Pro v1.0 (STM32F446ZET6/STM32F429ZGT6) -#define BOARD_LERDGE_K 4218 // Lerdge K (STM32F407ZG) -#define BOARD_LERDGE_S 4219 // Lerdge S (STM32F407VE) -#define BOARD_LERDGE_X 4220 // Lerdge X (STM32F407VE) -#define BOARD_VAKE403D 4221 // VAkE 403D (STM32F446VET6) -#define BOARD_FYSETC_S6 4222 // FYSETC S6 (STM32F446VET6) -#define BOARD_FYSETC_S6_V2_0 4223 // FYSETC S6 v2.0 (STM32F446VET6) -#define BOARD_FYSETC_SPIDER 4224 // FYSETC Spider (STM32F446VET6) -#define BOARD_FLYF407ZG 4225 // FLYmaker FLYF407ZG (STM32F407ZG) -#define BOARD_MKS_ROBIN2 4226 // MKS_ROBIN2 (STM32F407ZE) -#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_MONSTER8 4229 // MKS Monster8 (STM32F407VGT6) -#define BOARD_ANET_ET4 4230 // ANET ET4 V1.x (STM32F407VGT6) -#define BOARD_ANET_ET4P 4231 // ANET ET4P V1.x (STM32F407VGT6) -#define BOARD_FYSETC_CHEETAH_V20 4232 // FYSETC Cheetah V2.0 -#define BOARD_TH3D_EZBOARD_V2 4233 // TH3D EZBoard v2.0 -#define BOARD_INDEX_REV03 4234 // Index PnP Controller REV03 (STM32F407VET6/VGT6) -#define BOARD_MKS_ROBIN_NANO_V1_3_F4 4235 // MKS Robin Nano V1.3 and MKS Robin Nano-S V1.3 (STM32F407VET6) -#define BOARD_MKS_EAGLE 4236 // MKS Eagle (STM32F407VET6) -#define BOARD_ARTILLERY_RUBY 4237 // Artillery Ruby (STM32F401RCT6) -#define BOARD_FYSETC_SPIDER_V2_2 4238 // FYSETC Spider V2.2 (STM32F446VET6) - -// -// ARM Cortex M7 -// - -#define BOARD_REMRAM_V1 5000 // RemRam v1 -#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_ARMED 5200 // Arm'ed STM32F4-based controller +#define BOARD_RUMBA32_V1_0 5201 // RUMBA32 STM32F446VE based controller from Aus3D +#define BOARD_RUMBA32_V1_1 5202 // RUMBA32 STM32F446VE based controller from Aus3D +#define BOARD_RUMBA32_MKS 5203 // RUMBA32 STM32F446VE based controller from Makerbase +#define BOARD_RUMBA32_BTT 5204 // RUMBA32 STM32F446VE based controller from BIGTREETECH +#define BOARD_BLACK_STM32F407VE 5205 // BLACK_STM32F407VE +#define BOARD_BLACK_STM32F407ZE 5206 // BLACK_STM32F407ZE +#define BOARD_BTT_SKR_MINI_E3_V3_0_1 5207 // BigTreeTech SKR Mini E3 V3.0.1 (STM32F401RC) +#define BOARD_BTT_SKR_PRO_V1_1 5208 // BigTreeTech SKR Pro v1.1 (STM32F407ZG) +#define BOARD_BTT_SKR_PRO_V1_2 5209 // BigTreeTech SKR Pro v1.2 (STM32F407ZG) +#define BOARD_BTT_BTT002_V1_0 5210 // BigTreeTech BTT002 v1.0 (STM32F407VG) +#define BOARD_BTT_E3_RRF 5211 // BigTreeTech E3 RRF (STM32F407VG) +#define BOARD_BTT_SKR_V2_0_REV_A 5212 // BigTreeTech SKR v2.0 Rev A (STM32F407VG) +#define BOARD_BTT_SKR_V2_0_REV_B 5213 // BigTreeTech SKR v2.0 Rev B (STM32F407VG/STM32F429VG) +#define BOARD_BTT_GTR_V1_0 5214 // BigTreeTech GTR v1.0 (STM32F407IGT) +#define BOARD_BTT_OCTOPUS_V1_0 5215 // BigTreeTech Octopus v1.0 (STM32F446ZE) +#define BOARD_BTT_OCTOPUS_V1_1 5216 // BigTreeTech Octopus v1.1 (STM32F446ZE) +#define BOARD_BTT_OCTOPUS_PRO_V1_0 5217 // BigTreeTech Octopus Pro v1.0 (STM32F446ZE / STM32F429ZG) +#define BOARD_LERDGE_K 5218 // Lerdge K (STM32F407ZG) +#define BOARD_LERDGE_S 5219 // Lerdge S (STM32F407VE) +#define BOARD_LERDGE_X 5220 // Lerdge X (STM32F407VE) +#define BOARD_FYSETC_S6 5221 // FYSETC S6 (STM32F446VE) +#define BOARD_FYSETC_S6_V2_0 5222 // FYSETC S6 v2.0 (STM32F446VE) +#define BOARD_FYSETC_SPIDER 5223 // FYSETC Spider (STM32F446VE) +#define BOARD_FLYF407ZG 5224 // FLYmaker FLYF407ZG (STM32F407ZG) +#define BOARD_MKS_ROBIN2 5225 // MKS Robin2 V1.0 (STM32F407ZE) +#define BOARD_MKS_ROBIN_PRO_V2 5226 // MKS Robin Pro V2 (STM32F407VE) +#define BOARD_MKS_ROBIN_NANO_V3 5227 // MKS Robin Nano V3 (STM32F407VG) +#define BOARD_MKS_ROBIN_NANO_V3_1 5228 // MKS Robin Nano V3.1 (STM32F407VE) +#define BOARD_MKS_MONSTER8_V1 5229 // MKS Monster8 V1 (STM32F407VE) +#define BOARD_MKS_MONSTER8_V2 5230 // MKS Monster8 V2 (STM32F407VE) +#define BOARD_ANET_ET4 5231 // ANET ET4 V1.x (STM32F407VG) +#define BOARD_ANET_ET4P 5232 // ANET ET4P V1.x (STM32F407VG) +#define BOARD_FYSETC_CHEETAH_V20 5233 // FYSETC Cheetah V2.0 (STM32F401RC) +#define BOARD_TH3D_EZBOARD_V2 5234 // TH3D EZBoard v2.0 (STM32F405RG) +#define BOARD_OPULO_LUMEN_REV3 5235 // Opulo Lumen PnP Controller REV3 (STM32F407VE / STM32F407VG) +#define BOARD_MKS_ROBIN_NANO_V1_3_F4 5236 // MKS Robin Nano V1.3 and MKS Robin Nano-S V1.3 (STM32F407VE) +#define BOARD_MKS_EAGLE 5237 // MKS Eagle (STM32F407VE) +#define BOARD_ARTILLERY_RUBY 5238 // Artillery Ruby (STM32F401RC) +#define BOARD_FYSETC_SPIDER_V2_2 5239 // FYSETC Spider V2.2 (STM32F446VE) +#define BOARD_CREALITY_V24S1_301F4 5240 // Creality v2.4.S1_301F4 (STM32F401RC) as found in the Ender-3 S1 F4 +#define BOARD_OPULO_LUMEN_REV4 5241 // Opulo Lumen PnP Controller REV4 (STM32F407VE / STM32F407VG) +#define BOARD_FYSETC_SPIDER_KING407 5242 // FYSETC Spider King407 (STM32F407ZG) +#define BOARD_MKS_SKIPR_V1 5243 // MKS SKIPR v1.0 all-in-one board (STM32F407VE) +#define BOARD_TRONXY_CXY_446_V10 5244 // TRONXY CXY-446-V10-220413/CXY-V6-191121 (STM32F446ZE) + +// +// ARM Cortex-M7 +// + +#define BOARD_REMRAM_V1 6000 // RemRam v1 +#define BOARD_TEENSY41 6001 // Teensy 4.1 +#define BOARD_T41U5XBB 6002 // T41U5XBB Teensy 4.1 breakout board +#define BOARD_NUCLEO_F767ZI 6003 // ST NUCLEO-F767ZI Dev Board +#define BOARD_BTT_SKR_SE_BX_V2 6004 // BigTreeTech SKR SE BX V2.0 (STM32H743II) +#define BOARD_BTT_SKR_SE_BX_V3 6005 // BigTreeTech SKR SE BX V3.0 (STM32H743II) +#define BOARD_BTT_SKR_V3_0 6006 // BigTreeTech SKR V3.0 (STM32H743VI / STM32H723VG) +#define BOARD_BTT_SKR_V3_0_EZ 6007 // BigTreeTech SKR V3.0 EZ (STM32H743VI / STM32H723VG) +#define BOARD_BTT_OCTOPUS_MAX_EZ_V1_0 6008 // BigTreeTech Octopus Max EZ V1.0 (STM32H723ZE) // // Espressif ESP32 WiFi // -#define BOARD_ESPRESSIF_ESP32 6000 // Generic ESP32 -#define BOARD_MRR_ESPA 6001 // MRR ESPA based on ESP32 (native pins only) -#define BOARD_MRR_ESPE 6002 // MRR ESPE based on ESP32 (with I2S stepper stream) -#define BOARD_E4D_BOX 6003 // E4d@BOX -#define BOARD_RESP32_CUSTOM 6004 // Rutilea ESP32 custom board -#define BOARD_FYSETC_E4 6005 // FYSETC E4 -#define BOARD_PANDA_ZHU 6006 // Panda_ZHU -#define BOARD_PANDA_M4 6007 // Panda_M4 -#define BOARD_MKS_TINYBEE 6008 // MKS TinyBee based on ESP32 (with I2S stepper stream) +#define BOARD_ESPRESSIF_ESP32 7000 // Generic ESP32 +#define BOARD_MRR_ESPA 7001 // MRR ESPA based on ESP32 (native pins only) +#define BOARD_MRR_ESPE 7002 // MRR ESPE based on ESP32 (with I2S stepper stream) +#define BOARD_E4D_BOX 7003 // E4d@BOX +#define BOARD_RESP32_CUSTOM 7004 // Rutilea ESP32 custom board +#define BOARD_FYSETC_E4 7005 // FYSETC E4 +#define BOARD_PANDA_ZHU 7006 // Panda_ZHU +#define BOARD_PANDA_M4 7007 // Panda_M4 +#define BOARD_MKS_TINYBEE 7008 // MKS TinyBee based on ESP32 (with I2S stepper stream) +#define BOARD_ENWI_ESPNP 7009 // enwi ESPNP based on ESP32 (with I2S stepper stream) + +// +// SAMD51 ARM Cortex-M4 +// + +#define BOARD_AGCM4_RAMPS_144 7100 // RAMPS 1.4.4 +#define BOARD_BRICOLEMON_V1_0 7101 // Bricolemon +#define BOARD_BRICOLEMON_LITE_V1_0 7102 // Bricolemon Lite // -// SAMD51 ARM Cortex M4 +// SAMD21 ARM Cortex-M4 // -#define BOARD_AGCM4_RAMPS_144 6100 // RAMPS 1.4.4 +#define BOARD_MINITRONICS20 7103 // Minitronics v2.0 // // Custom board @@ -451,7 +498,7 @@ // Simulations // -#define BOARD_LINUX_RAMPS 9999 +#define BOARD_SIMULATED 9999 #define _MB_1(B) (defined(BOARD_##B) && MOTHERBOARD==BOARD_##B) #define MB(V...) DO(MB,||,V) diff --git a/Marlin/src/core/drivers.h b/Marlin/src/core/drivers.h index 0a764102..2f589b3e 100644 --- a/Marlin/src/core/drivers.h +++ b/Marlin/src/core/drivers.h @@ -30,10 +30,6 @@ #define _A5984 0x5984 #define _DRV8825 0x8825 #define _LV8729 0x8729 -#define _L6470 0x6470 -#define _L6474 0x6474 -#define _L6480 0x6480 -#define _POWERSTEP01 0xF00D #define _TB6560 0x6560 #define _TB6600 0x6600 #define _TMC2100 0x2100 @@ -63,12 +59,15 @@ #define AXIS_DRIVER_TYPE_I(T) _AXIS_DRIVER_TYPE(I,T) #define AXIS_DRIVER_TYPE_J(T) _AXIS_DRIVER_TYPE(J,T) #define AXIS_DRIVER_TYPE_K(T) _AXIS_DRIVER_TYPE(K,T) +#define AXIS_DRIVER_TYPE_U(T) _AXIS_DRIVER_TYPE(U,T) +#define AXIS_DRIVER_TYPE_V(T) _AXIS_DRIVER_TYPE(V,T) +#define AXIS_DRIVER_TYPE_W(T) _AXIS_DRIVER_TYPE(W,T) -#define AXIS_DRIVER_TYPE_X2(T) (EITHER(X_DUAL_STEPPER_DRIVERS, DUAL_X_CARRIAGE) && _AXIS_DRIVER_TYPE(X2,T)) -#define AXIS_DRIVER_TYPE_Y2(T) (ENABLED(Y_DUAL_STEPPER_DRIVERS) && _AXIS_DRIVER_TYPE(Y2,T)) -#define AXIS_DRIVER_TYPE_Z2(T) (NUM_Z_STEPPER_DRIVERS >= 2 && _AXIS_DRIVER_TYPE(Z2,T)) -#define AXIS_DRIVER_TYPE_Z3(T) (NUM_Z_STEPPER_DRIVERS >= 3 && _AXIS_DRIVER_TYPE(Z3,T)) -#define AXIS_DRIVER_TYPE_Z4(T) (NUM_Z_STEPPER_DRIVERS >= 4 && _AXIS_DRIVER_TYPE(Z4,T)) +#define AXIS_DRIVER_TYPE_X2(T) (HAS_X2_STEPPER && _AXIS_DRIVER_TYPE(X2,T)) +#define AXIS_DRIVER_TYPE_Y2(T) (HAS_DUAL_Y_STEPPERS && _AXIS_DRIVER_TYPE(Y2,T)) +#define AXIS_DRIVER_TYPE_Z2(T) (NUM_Z_STEPPERS >= 2 && _AXIS_DRIVER_TYPE(Z2,T)) +#define AXIS_DRIVER_TYPE_Z3(T) (NUM_Z_STEPPERS >= 3 && _AXIS_DRIVER_TYPE(Z3,T)) +#define AXIS_DRIVER_TYPE_Z4(T) (NUM_Z_STEPPERS >= 4 && _AXIS_DRIVER_TYPE(Z4,T)) #define AXIS_DRIVER_TYPE_E(N,T) (E_STEPPERS > N && _AXIS_DRIVER_TYPE(E##N,T)) #define AXIS_DRIVER_TYPE_E0(T) AXIS_DRIVER_TYPE_E(0,T) @@ -87,6 +86,7 @@ #define HAS_DRIVER(T) ( AXIS_DRIVER_TYPE_X(T) || AXIS_DRIVER_TYPE_Y(T) || AXIS_DRIVER_TYPE_Z(T) \ || AXIS_DRIVER_TYPE_I(T) || AXIS_DRIVER_TYPE_J(T) || AXIS_DRIVER_TYPE_K(T) \ + || AXIS_DRIVER_TYPE_U(T) || AXIS_DRIVER_TYPE_V(T) || AXIS_DRIVER_TYPE_W(T) \ || AXIS_DRIVER_TYPE_X2(T) || AXIS_DRIVER_TYPE_Y2(T) || AXIS_DRIVER_TYPE_Z2(T) \ || AXIS_DRIVER_TYPE_Z3(T) || AXIS_DRIVER_TYPE_Z4(T) || HAS_E_DRIVER(T) ) @@ -120,15 +120,21 @@ #define HAS_TMC220x 1 #endif +#if HAS_DRIVER(TMC26X) + #define HAS_TMC26X 1 +#endif + #define AXIS_IS_TMC(A) ( AXIS_DRIVER_TYPE(A,TMC2130) || AXIS_DRIVER_TYPE(A,TMC2160) \ || AXIS_DRIVER_TYPE(A,TMC2208) || AXIS_DRIVER_TYPE(A,TMC2209) \ || AXIS_DRIVER_TYPE(A,TMC2660) \ || AXIS_DRIVER_TYPE(A,TMC5130) || AXIS_DRIVER_TYPE(A,TMC5160) ) +#define AXIS_IS_TMC_CONFIG(A) ( AXIS_IS_TMC(A) || AXIS_DRIVER_TYPE(A,TMC26X) ) + // Test for a driver that uses SPI - this allows checking whether a _CS_ pin // is considered sensitive #define AXIS_HAS_SPI(A) ( AXIS_DRIVER_TYPE(A,TMC2130) || AXIS_DRIVER_TYPE(A,TMC2160) \ - || AXIS_DRIVER_TYPE(A,TMC2660) \ + || AXIS_DRIVER_TYPE(A,TMC26X) || AXIS_DRIVER_TYPE(A,TMC2660) \ || AXIS_DRIVER_TYPE(A,TMC5130) || AXIS_DRIVER_TYPE(A,TMC5160) ) #define AXIS_HAS_UART(A) ( AXIS_DRIVER_TYPE(A,TMC2208) || AXIS_DRIVER_TYPE(A,TMC2209) ) @@ -161,6 +167,7 @@ || AXIS_HAS_##T(Y) || AXIS_HAS_##T(Y2) \ || AXIS_HAS_##T(Z) || AXIS_HAS_##T(Z2) || AXIS_HAS_##T(Z3) || AXIS_HAS_##T(Z4) \ || AXIS_HAS_##T(I) || AXIS_HAS_##T(J) || AXIS_HAS_##T(K) \ + || AXIS_HAS_##T(U) || AXIS_HAS_##T(V) || AXIS_HAS_##T(W) \ || E_AXIS_HAS(T) ) #if ANY_AXIS_HAS(STEALTHCHOP) @@ -181,23 +188,3 @@ #if ANY_AXIS_HAS(SPI) #define HAS_TMC_SPI 1 #endif - -// -// TMC26XX Stepper Drivers -// -#if HAS_DRIVER(TMC26X) - #define HAS_TMC26X 1 -#endif - -// -// L64XX Stepper Drivers -// - -#if HAS_DRIVER(L6470) || HAS_DRIVER(L6474) || HAS_DRIVER(L6480) || HAS_DRIVER(POWERSTEP01) - #define HAS_L64XX 1 -#endif -#if HAS_L64XX && !HAS_DRIVER(L6474) - #define HAS_L64XX_NOT_L6474 1 -#endif - -#define AXIS_IS_L64XX(A) (AXIS_DRIVER_TYPE_##A(L6470) || AXIS_DRIVER_TYPE_##A(L6474) || AXIS_DRIVER_TYPE_##A(L6480) || AXIS_DRIVER_TYPE_##A(POWERSTEP01)) diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h index 0a6870af..ccebb87d 100644 --- a/Marlin/src/core/language.h +++ b/Marlin/src/core/language.h @@ -88,10 +88,6 @@ #define MACHINE_NAME DEFAULT_MACHINE_NAME #endif -#ifndef MACHINE_UUID - #define MACHINE_UUID DEFAULT_MACHINE_UUID -#endif - #define MARLIN_WEBSITE_URL "marlinfw.org" //#if !defined(STRING_SPLASH_LINE3) && defined(WEBSITE_URL) @@ -105,6 +101,7 @@ #define STR_ENQUEUEING "enqueueing \"" #define STR_POWERUP "PowerUp" +#define STR_POWEROFF "PowerOff" #define STR_EXTERNAL_RESET " External Reset" #define STR_BROWNOUT_RESET " Brown out Reset" #define STR_WATCHDOG_RESET " Watchdog Reset" @@ -152,7 +149,7 @@ #define STR_ERR_ARC_ARGS "G2/G3 bad parameters" #define STR_ERR_PROTECTED_PIN "Protected Pin" #define STR_ERR_M420_FAILED "Failed to enable Bed Leveling" -#define STR_ERR_M428_TOO_FAR "Too far from reference point" +#define STR_ERR_M428_TOO_FAR "Too far from MIN/MAX" #define STR_ERR_M303_DISABLED "PIDTEMP disabled" #define STR_M119_REPORT "Reporting endstop status" #define STR_ON "ON" @@ -173,6 +170,7 @@ #define STR_SD_VOL_INIT_FAIL "volume.init failed" #define STR_SD_OPENROOT_FAIL "openRoot failed" #define STR_SD_CARD_OK "SD card ok" +#define STR_SD_CARD_RELEASED "SD card released" #define STR_SD_WORKDIR_FAIL "workDir open failed" #define STR_SD_OPEN_FILE_FAIL "open failed, File: " #define STR_SD_FILE_OPENED "File opened: " @@ -190,6 +188,7 @@ #define STR_ERR_LONG_EXTRUDE_STOP " too long extrusion prevented" #define STR_ERR_HOTEND_TOO_COLD "Hotend too cold" #define STR_ERR_EEPROM_WRITE "Error writing to EEPROM!" +#define STR_ERR_EEPROM_CORRUPT "EEPROM Corrupt" #define STR_FILAMENT_CHANGE_HEAT_LCD "Press button to heat nozzle" #define STR_FILAMENT_CHANGE_INSERT_LCD "Insert filament and press button" @@ -198,16 +197,20 @@ #define STR_FILAMENT_CHANGE_INSERT_M108 "Insert filament and send M108" #define STR_FILAMENT_CHANGE_WAIT_M108 "Send M108 to resume" -#define STR_STOP_BLTOUCH "!! STOP called because of BLTouch error - restart with M999" -#define STR_STOP_UNHOMED "!! STOP called because of unhomed error - restart with M999" -#define STR_KILL_INACTIVE_TIME "!! KILL caused by too much inactive time - current command: " -#define STR_KILL_BUTTON "!! KILL caused by KILL button/pin" +#define STR_STOP_PRE "!! STOP called because of " +#define STR_STOP_POST " error - restart with M999" +#define STR_STOP_BLTOUCH "BLTouch" +#define STR_STOP_UNHOMED "unhomed" +#define STR_KILL_PRE "!! KILL caused by " +#define STR_KILL_INACTIVE_TIME "too much inactive time - current command: " +#define STR_KILL_BUTTON "KILL button/pin" // temperature.cpp strings -#define STR_PID_AUTOTUNE_START "PID Autotune start" -#define STR_PID_BAD_HEATER_ID "PID Autotune failed! Bad heater id" -#define STR_PID_TEMP_TOO_HIGH "PID Autotune failed! Temperature too high" -#define STR_PID_TIMEOUT "PID Autotune failed! timeout" +#define STR_PID_AUTOTUNE "PID Autotune" +#define STR_PID_AUTOTUNE_START " start" +#define STR_PID_BAD_HEATER_ID " failed! Bad heater id" +#define STR_PID_TEMP_TOO_HIGH " failed! Temperature too high" +#define STR_PID_TIMEOUT " failed! timeout" #define STR_BIAS " bias: " #define STR_D_COLON " d: " #define STR_T_MIN " min: " @@ -218,15 +221,19 @@ #define STR_KP " Kp: " #define STR_KI " Ki: " #define STR_KD " Kd: " -#define STR_PID_AUTOTUNE_FINISHED "PID Autotune finished! Put the last Kp, Ki and Kd constants from below into Configuration.h" +#define STR_PID_AUTOTUNE_FINISHED " finished! Put the last Kp, Ki and Kd constants from below into Configuration.h" #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 +#define STR_MPC_AUTOTUNE_INTERRUPTED " interrupted!" +#define STR_MPC_AUTOTUNE_FINISHED " finished! Put the constants below into Configuration.h" +#define STR_MPC_COOLING_TO_AMBIENT "Cooling to ambient" +#define STR_MPC_HEATING_PAST_200 "Heating to over 200C" +#define STR_MPC_MEASURING_AMBIENT "Measuring ambient heatloss at " +#define STR_MPC_TEMPERATURE_ERROR "Temperature error" #define STR_HEATER_BED "bed" #define STR_HEATER_CHAMBER "chamber" @@ -240,6 +247,7 @@ #define STR_REDUNDANCY "Heater switched off. Temperature difference between temp sensors is too high !" #define STR_T_HEATING_FAILED "Heating failed" #define STR_T_THERMAL_RUNAWAY "Thermal Runaway" +#define STR_T_MALFUNCTION "Thermal Malfunction" #define STR_T_MAXTEMP "MAXTEMP triggered" #define STR_T_MINTEMP "MINTEMP triggered" #define STR_ERR_PROBING_FAILED "Probing Failed" @@ -253,7 +261,7 @@ #define STR_DEBUG_ERRORS "ERRORS" #define STR_DEBUG_DRYRUN "DRYRUN" #define STR_DEBUG_COMMUNICATION "COMMUNICATION" -#define STR_DEBUG_LEVELING "LEVELING" +#define STR_DEBUG_DETAIL "DETAIL" #define STR_PRINTER_LOCKED "Printer locked! (Unlock with M511 or LCD)" #define STR_WRONG_PASSWORD "Incorrect Password" @@ -301,18 +309,22 @@ #define STR_MATERIAL_HEATUP "Material heatup parameters" #define STR_LCD_CONTRAST "LCD Contrast" #define STR_LCD_BRIGHTNESS "LCD Brightness" +#define STR_DISPLAY_SLEEP "Display Sleep" #define STR_UI_LANGUAGE "UI Language" #define STR_Z_PROBE_OFFSET "Z-Probe Offset" #define STR_TEMPERATURE_UNITS "Temperature Units" #define STR_USER_THERMISTORS "User thermistors" +#define STR_DELAYED_POWEROFF "Delayed poweroff" // // Endstop Names used by Endstops::report_states // -#define STR_X_MIN "x_min" -#define STR_X_MAX "x_max" -#define STR_X2_MIN "x2_min" -#define STR_X2_MAX "x2_max" +#if HAS_X_AXIS + #define STR_X_MIN "x_min" + #define STR_X_MAX "x_max" + #define STR_X2_MIN "x2_min" + #define STR_X2_MAX "x2_max" +#endif #if HAS_Y_AXIS #define STR_Y_MIN "y_min" @@ -340,9 +352,6 @@ #define STR_X "X" #define STR_Y "Y" #define STR_Z "Z" -#define STR_I AXIS4_STR -#define STR_J AXIS5_STR -#define STR_K AXIS6_STR #define STR_E "E" #if IS_KINEMATIC #define STR_A "A" @@ -359,118 +368,140 @@ #define STR_Z3 "Z3" #define STR_Z4 "Z4" -#define LCD_STR_A STR_A -#define LCD_STR_B STR_B -#define LCD_STR_C STR_C -#define LCD_STR_I STR_I -#define LCD_STR_J STR_J -#define LCD_STR_K STR_K -#define LCD_STR_E STR_E - // Extra Axis and Endstop Names -#if LINEAR_AXES >= 4 +#if HAS_I_AXIS #if AXIS4_NAME == 'A' - #define AXIS4_STR "A" + #define STR_I "A" #define STR_I_MIN "a_min" #define STR_I_MAX "a_max" #elif AXIS4_NAME == 'B' - #define AXIS4_STR "B" + #define STR_I "B" #define STR_I_MIN "b_min" #define STR_I_MAX "b_max" #elif AXIS4_NAME == 'C' - #define AXIS4_STR "C" + #define STR_I "C" #define STR_I_MIN "c_min" #define STR_I_MAX "c_max" #elif AXIS4_NAME == 'U' - #define AXIS4_STR "U" + #define STR_I "U" #define STR_I_MIN "u_min" #define STR_I_MAX "u_max" #elif AXIS4_NAME == 'V' - #define AXIS4_STR "V" + #define STR_I "V" #define STR_I_MIN "v_min" #define STR_I_MAX "v_max" #elif AXIS4_NAME == 'W' - #define AXIS4_STR "W" + #define STR_I "W" #define STR_I_MIN "w_min" #define STR_I_MAX "w_max" #else - #define AXIS4_STR "A" - #define STR_I_MIN "a_min" - #define STR_I_MAX "a_max" + #error "AXIS4_NAME can only be one of 'A', 'B', 'C', 'U', 'V', or 'W'." #endif #else - #define AXIS4_STR "" + #define STR_I "" #endif -#if LINEAR_AXES >= 5 - #if AXIS5_NAME == 'A' - #define AXIS5_STR "A" - #define STR_J_MIN "a_min" - #define STR_J_MAX "a_max" - #elif AXIS5_NAME == 'B' - #define AXIS5_STR "B" +#if HAS_J_AXIS + #if AXIS5_NAME == 'B' + #define STR_J "B" #define STR_J_MIN "b_min" #define STR_J_MAX "b_max" #elif AXIS5_NAME == 'C' - #define AXIS5_STR "C" + #define STR_J "C" #define STR_J_MIN "c_min" #define STR_J_MAX "c_max" #elif AXIS5_NAME == 'U' - #define AXIS5_STR "U" + #define STR_J "U" #define STR_J_MIN "u_min" #define STR_J_MAX "u_max" #elif AXIS5_NAME == 'V' - #define AXIS5_STR "V" + #define STR_J "V" #define STR_J_MIN "v_min" #define STR_J_MAX "v_max" #elif AXIS5_NAME == 'W' - #define AXIS5_STR "W" + #define STR_J "W" #define STR_J_MIN "w_min" #define STR_J_MAX "w_max" #else - #define AXIS5_STR "B" - #define STR_J_MIN "b_min" - #define STR_J_MAX "b_max" + #error "AXIS5_NAME can only be one of 'B', 'C', 'U', 'V', or 'W'." #endif #else - #define AXIS5_STR "" + #define STR_J "" #endif -#if LINEAR_AXES >= 6 - #if AXIS6_NAME == 'A' - #define AXIS6_STR "A" - #define STR_K_MIN "a_min" - #define STR_K_MAX "a_max" - #elif AXIS6_NAME == 'B' - #define AXIS6_STR "B" - #define STR_K_MIN "b_min" - #define STR_K_MAX "b_max" - #elif AXIS6_NAME == 'C' - #define AXIS6_STR "C" +#if HAS_K_AXIS + #if AXIS6_NAME == 'C' + #define STR_K "C" #define STR_K_MIN "c_min" #define STR_K_MAX "c_max" #elif AXIS6_NAME == 'U' - #define AXIS6_STR "U" + #define STR_K "U" #define STR_K_MIN "u_min" #define STR_K_MAX "u_max" #elif AXIS6_NAME == 'V' - #define AXIS6_STR "V" + #define STR_K "V" #define STR_K_MIN "v_min" #define STR_K_MAX "v_max" #elif AXIS6_NAME == 'W' - #define AXIS6_STR "W" + #define STR_K "W" #define STR_K_MIN "w_min" #define STR_K_MAX "w_max" #else - #define AXIS6_STR "C" - #define STR_K_MIN "c_min" - #define STR_K_MAX "c_max" + #error "AXIS6_NAME can only be one of 'C', 'U', 'V', or 'W'." + #endif +#else + #define STR_K "" +#endif + +#if HAS_U_AXIS + #if AXIS7_NAME == 'U' + #define STR_U "U" + #define STR_U_MIN "u_min" + #define STR_U_MAX "u_max" + #elif AXIS7_NAME == 'V' + #define STR_U "V" + #define STR_U_MIN "v_min" + #define STR_U_MAX "v_max" + #elif AXIS7_NAME == 'W' + #define STR_U "W" + #define STR_U_MIN "w_min" + #define STR_U_MAX "w_max" + #else + #error "AXIS7_NAME can only be one of 'U', 'V', or 'W'." + #endif +#else + #define STR_U "" +#endif + +#if HAS_V_AXIS + #if AXIS8_NAME == 'V' + #define STR_V "V" + #define STR_V_MIN "v_min" + #define STR_V_MAX "v_max" + #elif AXIS8_NAME == 'W' + #define STR_V "W" + #define STR_V_MIN "w_min" + #define STR_V_MAX "w_max" + #else + #error "AXIS8_NAME can only be one of 'V', or 'W'." + #endif +#else + #define STR_V "" +#endif + +#if HAS_W_AXIS + #if AXIS9_NAME == 'W' + #define STR_W "W" + #define STR_W_MIN "w_min" + #define STR_W_MAX "w_max" + #else + #error "AXIS9_NAME can only be 'W'." #endif #else - #define AXIS6_STR "" + #define STR_W "" #endif -#if EITHER(HAS_MARLINUI_HD44780, IS_TFTGLCD_PANEL) +#if ANY(HAS_MARLINUI_HD44780, IS_TFTGLCD_PANEL) // Custom characters defined in the first 8 characters of the LCD #define LCD_STR_BEDTEMP "\x00" // Print only as a char. This will have 'unexpected' results when used in a string! @@ -518,34 +549,34 @@ */ #if ENABLED(NUMBER_TOOLS_FROM_0) #define LCD_FIRST_TOOL 0 - #define LCD_STR_N0 "0" - #define LCD_STR_N1 "1" - #define LCD_STR_N2 "2" - #define LCD_STR_N3 "3" - #define LCD_STR_N4 "4" - #define LCD_STR_N5 "5" - #define LCD_STR_N6 "6" - #define LCD_STR_N7 "7" + #define STR_N0 "0" + #define STR_N1 "1" + #define STR_N2 "2" + #define STR_N3 "3" + #define STR_N4 "4" + #define STR_N5 "5" + #define STR_N6 "6" + #define STR_N7 "7" #else #define LCD_FIRST_TOOL 1 - #define LCD_STR_N0 "1" - #define LCD_STR_N1 "2" - #define LCD_STR_N2 "3" - #define LCD_STR_N3 "4" - #define LCD_STR_N4 "5" - #define LCD_STR_N5 "6" - #define LCD_STR_N6 "7" - #define LCD_STR_N7 "8" + #define STR_N0 "1" + #define STR_N1 "2" + #define STR_N2 "3" + #define STR_N3 "4" + #define STR_N4 "5" + #define STR_N5 "6" + #define STR_N6 "7" + #define STR_N7 "8" #endif -#define LCD_STR_E0 "E" LCD_STR_N0 -#define LCD_STR_E1 "E" LCD_STR_N1 -#define LCD_STR_E2 "E" LCD_STR_N2 -#define LCD_STR_E3 "E" LCD_STR_N3 -#define LCD_STR_E4 "E" LCD_STR_N4 -#define LCD_STR_E5 "E" LCD_STR_N5 -#define LCD_STR_E6 "E" LCD_STR_N6 -#define LCD_STR_E7 "E" LCD_STR_N7 +#define STR_E0 STR_E STR_N0 +#define STR_E1 STR_E STR_N1 +#define STR_E2 STR_E STR_N2 +#define STR_E3 STR_E STR_N3 +#define STR_E4 STR_E STR_N4 +#define STR_E5 STR_E STR_N5 +#define STR_E6 STR_E STR_N6 +#define STR_E7 STR_E STR_N7 // Include localized LCD Menu Messages diff --git a/Marlin/src/core/macros.h b/Marlin/src/core/macros.h index 62675d13..65fabf3f 100644 --- a/Marlin/src/core/macros.h +++ b/Marlin/src/core/macros.h @@ -21,7 +21,7 @@ */ #pragma once -#if !defined(__has_include) +#ifndef __has_include #define __has_include(...) 1 #endif @@ -39,24 +39,36 @@ #define _ISTOP_ 0x04 #define _JSTOP_ 0x05 #define _KSTOP_ 0x06 +#define _USTOP_ 0x07 +#define _VSTOP_ 0x08 +#define _WSTOP_ 0x09 #define _XMIN_ 0x11 #define _YMIN_ 0x12 #define _ZMIN_ 0x13 #define _IMIN_ 0x14 #define _JMIN_ 0x15 #define _KMIN_ 0x16 +#define _UMIN_ 0x17 +#define _VMIN_ 0x18 +#define _WMIN_ 0x19 #define _XMAX_ 0x21 #define _YMAX_ 0x22 #define _ZMAX_ 0x23 #define _IMAX_ 0x24 #define _JMAX_ 0x25 #define _KMAX_ 0x26 +#define _UMAX_ 0x27 +#define _VMAX_ 0x28 +#define _WMAX_ 0x29 #define _XDIAG_ 0x31 #define _YDIAG_ 0x32 #define _ZDIAG_ 0x33 #define _IDIAG_ 0x34 #define _JDIAG_ 0x35 #define _KDIAG_ 0x36 +#define _UDIAG_ 0x37 +#define _VDIAG_ 0x38 +#define _WDIAG_ 0x39 #define _E0DIAG_ 0xE0 #define _E1DIAG_ 0xE1 #define _E2DIAG_ 0xE2 @@ -70,11 +82,12 @@ #define FORCE_INLINE __attribute__((always_inline)) inline #define NO_INLINE __attribute__((noinline)) #define _UNUSED __attribute__((unused)) -#define _O0 __attribute__((optimize("O0"))) -#define _Os __attribute__((optimize("Os"))) -#define _O1 __attribute__((optimize("O1"))) -#define _O2 __attribute__((optimize("O2"))) -#define _O3 __attribute__((optimize("O3"))) +#define __O0 __attribute__((optimize("O0"))) // No optimization and less debug info +#define __Og __attribute__((optimize("Og"))) // Optimize the debugging experience +#define __Os __attribute__((optimize("Os"))) // Optimize for size +#define __O1 __attribute__((optimize("O1"))) // Try to reduce size and cycles; nothing that takes a lot of time to compile +#define __O2 __attribute__((optimize("O2"))) // Optimize even more +#define __O3 __attribute__((optimize("O3"))) // Optimize yet more #define IS_CONSTEXPR(...) __builtin_constant_p(__VA_ARGS__) // Only valid solution with C++14. Should use std::is_constant_evaluated() in C++20 instead @@ -99,7 +112,7 @@ // Macros for bit masks #undef _BV -#define _BV(n) (1<<(n)) +#define _BV(b) (1 << (b)) #define TEST(n,b) (!!((n)&_BV(b))) #define SET_BIT_TO(N,B,TF) do{ if (TF) SBI(N,B); else CBI(N,B); }while(0) #ifndef SBI @@ -121,7 +134,8 @@ #define HYPOT2(x,y) (sq(x)+sq(y)) #define NORMSQ(x,y,z) (sq(x)+sq(y)+sq(z)) -#define CIRCLE_AREA(R) (float(M_PI) * sq(float(R))) +#define FLOAT_SQ(I) sq(float(I)) +#define CIRCLE_AREA(R) (float(M_PI) * FLOAT_SQ(R)) #define CIRCLE_CIRC(R) (2 * float(M_PI) * float(R)) #define SIGN(a) ({__typeof__(a) _a = (a); (_a>0)-(_a<0);}) @@ -131,13 +145,13 @@ #ifdef __cplusplus // C++11 solution that is standards compliant. - template static inline constexpr void NOLESS(V& v, const N n) { + template static constexpr void NOLESS(V& v, const N n) { if (n > v) v = n; } - template static inline constexpr void NOMORE(V& v, const N n) { + template static constexpr void NOMORE(V& v, const N n) { if (n < v) v = n; } - template static inline constexpr void LIMIT(V& v, const N1 n1, const N2 n2) { + template static constexpr void LIMIT(V& v, const N1 n1, const N2 n2) { if (n1 > v) v = n1; else if (n2 < v) v = n2; } @@ -211,22 +225,29 @@ #define _DO_N(W,C,N,V...) __DO_N(W,C,N,V) #define DO(W,C,V...) (_DO_N(W,C,NUM_ARGS(V),V)) -// Macros to support option testing +// Concatenate symbol names, without or with pre-expansion #define _CAT(a,V...) a##V #define CAT(a,V...) _CAT(a,V) +// Recognize "true" values: blank, 1, 0x1, true #define _ISENA_ ~,1 #define _ISENA_1 ~,1 #define _ISENA_0x1 ~,1 #define _ISENA_true ~,1 #define _ISENA(V...) IS_PROBE(V) +// Macros to evaluate simple option switches #define _ENA_1(O) _ISENA(CAT(_IS,CAT(ENA_, O))) #define _DIS_1(O) NOT(_ENA_1(O)) #define ENABLED(V...) DO(ENA,&&,V) #define DISABLED(V...) DO(DIS,&&,V) +#define ANY(V...) !DISABLED(V) +#define ALL(V...) ENABLED(V) +#define NONE(V...) DISABLED(V) #define COUNT_ENABLED(V...) DO(ENA,+,V) +#define MANY(V...) (COUNT_ENABLED(V) > 1) +// Ternary pre-compiler macros conceal non-emitted content from the compiler #define TERN(O,A,B) _TERN(_ENA_1(O),B,A) // OPTION ? 'A' : 'B' #define TERN0(O,A) _TERN(_ENA_1(O),0,A) // OPTION ? 'A' : '0' #define TERN1(O,A) _TERN(_ENA_1(O),1,A) // OPTION ? 'A' : '1' @@ -234,28 +255,29 @@ #define _TERN(E,V...) __TERN(_CAT(T_,E),V) // Prepend 'T_' to get 'T_0' or 'T_1' #define __TERN(T,V...) ___TERN(_CAT(_NO,T),V) // Prepend '_NO' to get '_NOT_0' or '_NOT_1' #define ___TERN(P,V...) THIRD(P,V) // If first argument has a comma, A. Else B. +#define IF_DISABLED(O,A) TERN(O,,A) +// Macros to conditionally emit array items and function arguments +#define _OPTITEM(A...) A, +#define OPTITEM(O,A...) TERN_(O,DEFER4(_OPTITEM)(A)) #define _OPTARG(A...) , A #define OPTARG(O,A...) TERN_(O,DEFER4(_OPTARG)(A)) #define _OPTCODE(A) A; #define OPTCODE(O,A) TERN_(O,DEFER4(_OPTCODE)(A)) -// Macros to avoid 'f + 0.0' which is not always optimized away. Minus included for symmetry. +// Macros to avoid operations that aren't always optimized away (e.g., 'f + 0.0' and 'f * 1.0'). // Compiler flags -fno-signed-zeros -ffinite-math-only also cover 'f * 1.0', 'f - f', etc. #define PLUS_TERN0(O,A) _TERN(_ENA_1(O),,+ (A)) // OPTION ? '+ (A)' : '' #define MINUS_TERN0(O,A) _TERN(_ENA_1(O),,- (A)) // OPTION ? '- (A)' : '' +#define MUL_TERN1(O,A) _TERN(_ENA_1(O),,* (A)) // OPTION ? '* (A)' : '' +#define DIV_TERN1(O,A) _TERN(_ENA_1(O),,/ (A)) // OPTION ? '/ (A)' : '' #define SUM_TERN(O,B,A) ((B) PLUS_TERN0(O,A)) // ((B) (OPTION ? '+ (A)' : '')) #define DIFF_TERN(O,B,A) ((B) MINUS_TERN0(O,A)) // ((B) (OPTION ? '- (A)' : '')) +#define MUL_TERN(O,B,A) ((B) MUL_TERN1(O,A)) // ((B) (OPTION ? '* (A)' : '')) +#define DIV_TERN(O,B,A) ((B) DIV_TERN1(O,A)) // ((B) (OPTION ? '/ (A)' : '')) -#define IF_ENABLED TERN_ -#define IF_DISABLED(O,A) TERN(O,,A) - -#define ANY(V...) !DISABLED(V) -#define NONE(V...) DISABLED(V) -#define ALL(V...) ENABLED(V) #define BOTH(V1,V2) ALL(V1,V2) #define EITHER(V1,V2) ANY(V1,V2) -#define MANY(V...) (COUNT_ENABLED(V) > 1) // Macros to support pins/buttons exist testing #define PIN_EXISTS(PN) (defined(PN##_PIN) && PN##_PIN >= 0) @@ -268,6 +290,7 @@ #define BUTTONS_EXIST(V...) DO(BTNEX,&&,V) #define ANY_BUTTON(V...) DO(BTNEX,||,V) +// Value helper macros #define WITHIN(N,L,H) ((N) >= (L) && (N) <= (H)) #define ISEOL(C) ((C) == '\n' || (C) == '\r') #define NUMERIC(a) WITHIN(a, '0', '9') @@ -275,13 +298,16 @@ #define HEXCHR(a) (NUMERIC(a) ? (a) - '0' : WITHIN(a, 'a', 'f') ? ((a) - 'a' + 10) : WITHIN(a, 'A', 'F') ? ((a) - 'A' + 10) : -1) #define NUMERIC_SIGNED(a) (NUMERIC(a) || (a) == '-' || (a) == '+') #define DECIMAL_SIGNED(a) (DECIMAL(a) || (a) == '-' || (a) == '+') + +// Array shorthand #define COUNT(a) (sizeof(a)/sizeof(*a)) -#define ZERO(a) memset(a,0,sizeof(a)) +#define ZERO(a) memset((void*)a,0,sizeof(a)) #define COPY(a,b) do{ \ static_assert(sizeof(a[0]) == sizeof(b[0]), "COPY: '" STRINGIFY(a) "' and '" STRINGIFY(b) "' types (sizes) don't match!"); \ memcpy(&a[0],&b[0],_MIN(sizeof(a),sizeof(b))); \ }while(0) +// Expansion of some code #define CODE_16( A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,...) A; B; C; D; E; F; G; H; I; J; K; L; M; N; O; P #define CODE_15( A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,...) A; B; C; D; E; F; G; H; I; J; K; L; M; N; O #define CODE_14( A,B,C,D,E,F,G,H,I,J,K,L,M,N,...) A; B; C; D; E; F; G; H; I; J; K; L; M; N @@ -302,6 +328,7 @@ #define _CODE_N(N,V...) CODE_##N(V) #define CODE_N(N,V...) _CODE_N(N,V) +// Expansion of some non-delimited content #define GANG_16(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,...) A B C D E F G H I J K L M N O P #define GANG_15(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,...) A B C D E F G H I J K L M N O #define GANG_14(A,B,C,D,E,F,G,H,I,J,K,L,M,N,...) A B C D E F G H I J K L M N @@ -323,7 +350,13 @@ #define GANG_N(N,V...) _GANG_N(N,V) #define GANG_N_1(N,K) _GANG_N(N,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K) -// Macros for initializing arrays +// Expansion of some list items +#define LIST_26(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z +#define LIST_25(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y +#define LIST_24(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X +#define LIST_23(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W +#define LIST_22(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V +#define LIST_21(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U #define LIST_20(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T #define LIST_19(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S #define LIST_18(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R @@ -348,25 +381,20 @@ #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) } #define _JOIN_1(O) (O) #define JOIN_N(N,C,V...) (DO(JOIN,C,LIST_N(N,V))) -#define LOOP_S_LE_N(VAR, S, N) for (uint8_t VAR=(S); VAR<=(N); VAR++) -#define LOOP_S_L_N(VAR, S, N) for (uint8_t VAR=(S); VAR<(N); VAR++) -#define LOOP_LE_N(VAR, N) LOOP_S_LE_N(VAR, 0, N) -#define LOOP_L_N(VAR, N) LOOP_S_L_N(VAR, 0, N) - #define NOOP (void(0)) #define CEILING(x,y) (((x) + (y) - 1) / (y)) #undef ABS #ifdef __cplusplus - template static inline constexpr const T ABS(const T v) { return v >= 0 ? v : -v; } + template static constexpr const T ABS(const T v) { return v >= 0 ? v : -v; } #else #define ABS(a) ({__typeof__(a) _a = (a); _a >= 0 ? _a : -_a;}) #endif @@ -409,14 +437,16 @@ extern "C++" { // C++11 solution that is standards compliant. Return type is deduced automatically - template static inline constexpr auto _MIN(const L lhs, const R rhs) -> decltype(lhs + rhs) { + template static constexpr N _MIN(const N val) { return val; } + template static constexpr N _MAX(const N val) { return val; } + template static constexpr auto _MIN(const L lhs, const R rhs) -> decltype(lhs + rhs) { return lhs < rhs ? lhs : rhs; } - template static inline constexpr auto _MAX(const L lhs, const R rhs) -> decltype(lhs + rhs) { + template static constexpr auto _MAX(const L lhs, const R rhs) -> decltype(lhs + rhs) { return lhs > rhs ? lhs : rhs; } - template static inline constexpr const T _MIN(T V, Ts... Vs) { return _MIN(V, _MIN(Vs...)); } - template static inline constexpr const T _MAX(T V, Ts... Vs) { return _MAX(V, _MAX(Vs...)); } + template static constexpr const T _MIN(T V, Ts... Vs) { return _MIN(V, _MIN(Vs...)); } + template static constexpr const T _MAX(T V, Ts... Vs) { return _MAX(V, _MAX(Vs...)); } } @@ -428,9 +458,9 @@ FORCE_INLINE constexpr T operator|(T x, T y) { return static_cast(static_cast(x) | static_cast(y)); } \ FORCE_INLINE constexpr T operator^(T x, T y) { return static_cast(static_cast(x) ^ static_cast(y)); } \ FORCE_INLINE constexpr T operator~(T x) { return static_cast(~static_cast(x)); } \ - FORCE_INLINE T & operator&=(T &x, T y) { return x &= y; } \ - FORCE_INLINE T & operator|=(T &x, T y) { return x |= y; } \ - FORCE_INLINE T & operator^=(T &x, T y) { return x ^= y; } + FORCE_INLINE T & operator&=(T &x, T y) { x = x & y; return x; } \ + FORCE_INLINE T & operator|=(T &x, T y) { x = x | y; return x; } \ + FORCE_INLINE T & operator^=(T &x, T y) { x = x ^ y; return x; } // C++11 solution that is standard compliant. is not available on all platform namespace Private { @@ -442,7 +472,41 @@ template struct first_type_of { typedef T type; }; template struct first_type_of { typedef T type; }; + + // remove const/volatile type qualifiers + template struct remove_const { typedef T type; }; + template struct remove_const { typedef T type; }; + + template struct remove_volatile { typedef T type; }; + template struct remove_volatile { typedef T type; }; + + template struct remove_cv { typedef typename remove_const::type>::type type; }; + + // test if type is integral + template struct _is_integral { enum { value = false }; }; + template<> struct _is_integral { enum { value = true }; }; + template<> struct _is_integral { enum { value = true }; }; + template<> struct _is_integral { enum { value = true }; }; + template<> struct _is_integral { enum { value = true }; }; + template<> struct _is_integral { enum { value = true }; }; + template<> struct _is_integral { enum { value = true }; }; + template<> struct _is_integral { enum { value = true }; }; + template<> struct _is_integral { enum { value = true }; }; + template<> struct _is_integral { enum { value = true }; }; + template<> struct _is_integral { enum { value = true }; }; + template struct is_integral : public _is_integral::type> {}; } + + // enum type check and regression to its underlying integral. + namespace Private { + template struct is_enum { enum { value = __is_enum(T) }; }; + + template::value> struct _underlying_type { using type = __underlying_type(T); }; + template struct _underlying_type { }; + + template struct underlying_type : public _underlying_type { }; + } + // C++11 solution using SFINAE to detect the existence of a member in a class at compile time. // It creates a HasMember structure containing 'value' set to true if the member exists #define HAS_MEMBER_IMPL(Member) \ @@ -615,6 +679,8 @@ // Force define expansion #define EVAL(V...) EVAL16(V) +#define EVAL4096(V...) EVAL2048(EVAL2048(V)) +#define EVAL2048(V...) EVAL1024(EVAL1024(V)) #define EVAL1024(V...) EVAL512(EVAL512(V)) #define EVAL512(V...) EVAL256(EVAL256(V)) #define EVAL256(V...) EVAL128(EVAL128(V)) @@ -630,8 +696,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) @@ -645,7 +711,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) @@ -693,18 +758,47 @@ ( DEFER2(__RREPEAT2)()(ADD1(_RPT_I),SUB1(_RPT_N),_RPT_OP,V) ) \ ( /* Do nothing */ ) #define __RREPEAT2() _RREPEAT2 -#define RREPEAT_S(S,N,OP) EVAL1024(_RREPEAT(S,SUB##S(N),OP)) -#define RREPEAT(N,OP) RREPEAT_S(0,N,OP) -#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)) +#define RREPEAT_S(S,N,OP) EVAL1024(_RREPEAT(S,SUB##S(N),OP)) +#define RREPEAT(N,OP) RREPEAT_S(0,N,OP) +#define RREPEAT_1(N,OP) RREPEAT_S(1,INCREMENT(N),OP) +#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) + +// Emit a list of N OP(I) items with ascending counter. +#define _REPLIST(_RPT_I,_RPT_N,_RPT_OP) \ + _RPT_OP(_RPT_I) \ + IF_ELSE(SUB1(_RPT_N)) \ + ( , DEFER2(__REPLIST)()(ADD1(_RPT_I),SUB1(_RPT_N),_RPT_OP) ) \ + ( /* Do nothing */ ) +#define __REPLIST() _REPLIST + +// Repeat a macro, comma-separated, passing S...N-1. +#define REPLIST_S(S,N,OP) EVAL(_REPLIST(S,SUB##S(N),OP)) +#define REPLIST(N,OP) REPLIST_S(0,N,OP) +#define REPLIST_1(N,OP) REPLIST_S(1,INCREMENT(N),OP) + +// 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)) + +// Temperature Sensor Config +#define TEMP_SENSOR(N) TEMP_SENSOR_##N +#define _HAS_E_TEMP(N) || TEMP_SENSOR(N) +#define HAS_E_TEMP_SENSOR (0 REPEAT(EXTRUDERS, _HAS_E_TEMP)) +#define TEMP_SENSOR_IS_MAX_TC(T) (TEMP_SENSOR(T) == -5 || TEMP_SENSOR(T) == -3 || TEMP_SENSOR(T) == -2) diff --git a/Marlin/src/core/multi_language.h b/Marlin/src/core/multi_language.h index 2106f946..81a1754d 100644 --- a/Marlin/src/core/multi_language.h +++ b/Marlin/src/core/multi_language.h @@ -45,6 +45,7 @@ typedef const char Language_Str[]; // Set unused languages equal to each other so the // compiler can optimize away the conditionals. +#define LCD_LANGUAGE_1 LCD_LANGUAGE #ifndef LCD_LANGUAGE_2 #define LCD_LANGUAGE_2 LCD_LANGUAGE #endif @@ -63,6 +64,9 @@ typedef const char Language_Str[]; #if NUM_LANGUAGES > 1 #define HAS_MULTI_LANGUAGE 1 + #if HAS_MARLINUI_MENU + #define HAS_MENU_MULTI_LANGUAGE 1 + #endif #define GET_TEXT(MSG) ( \ ui.language == 4 ? GET_LANG(LCD_LANGUAGE_5)::MSG : \ ui.language == 3 ? GET_LANG(LCD_LANGUAGE_4)::MSG : \ @@ -80,10 +84,14 @@ typedef const char Language_Str[]; #endif #define GET_TEXT_F(MSG) FPSTR(GET_TEXT(MSG)) +#define GET_EN_TEXT(MSG) GET_LANG(en)::MSG +#define GET_EN_TEXT_F(MSG) FPSTR(GET_EN_TEXT(MSG)) + #define GET_LANGUAGE_NAME(INDEX) GET_LANG(LCD_LANGUAGE_##INDEX)::LANGUAGE #define LANG_CHARSIZE GET_TEXT(CHARSIZE) #define USE_WIDE_GLYPH (LANG_CHARSIZE > 2) +// The final "\0" is added invisibly by the compiler #define MSG_1_LINE(A) A "\0" "\0" #define MSG_2_LINE(A,B) A "\0" B "\0" #define MSG_3_LINE(A,B,C) A "\0" B "\0" C diff --git a/Marlin/src/core/serial.cpp b/Marlin/src/core/serial.cpp index 9cd862df..2ff3fd4c 100644 --- a/Marlin/src/core/serial.cpp +++ b/Marlin/src/core/serial.cpp @@ -27,19 +27,19 @@ #include "../feature/ethernet.h" #endif -uint8_t marlin_debug_flags = MARLIN_DEBUG_NONE; +// Echo commands to the terminal by default in dev mode +uint8_t marlin_debug_flags = TERN(MARLIN_DEV_MODE, MARLIN_DEBUG_ECHO, 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, AXIS4_STR); PGMSTR(J_STR, AXIS5_STR); PGMSTR(K_STR, AXIS6_STR); -PGMSTR(I_LBL, AXIS4_STR ":"); PGMSTR(J_LBL, AXIS5_STR ":"); PGMSTR(K_LBL, AXIS6_STR ":"); -PGMSTR(SP_I_STR, " " AXIS4_STR); PGMSTR(SP_J_STR, " " AXIS5_STR); PGMSTR(SP_K_STR, " " AXIS6_STR); -PGMSTR(SP_I_LBL, " " AXIS4_STR ":"); PGMSTR(SP_J_LBL, " " AXIS5_STR ":"); PGMSTR(SP_K_LBL, " " AXIS6_STR ":"); +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,16 +73,19 @@ 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(' '); } -void serial_ternary(const bool onoff, FSTR_P const pre, FSTR_P const on, FSTR_P const off, FSTR_P const post/*=nullptr*/) { - if (pre) serial_print(pre); - serial_print(onoff ? on : off); - if (post) serial_print(post); +void serial_offset(const_float_t v, const uint8_t sp/*=0*/) { + if (v == 0 && sp == 1) + SERIAL_CHAR(' '); + else if (v > 0 || (v == 0 && sp == 2)) + SERIAL_CHAR('+'); + SERIAL_DECIMAL(v); } + void serialprint_onoff(const bool onoff) { serial_print(onoff ? F(STR_ON) : F(STR_OFF)); } void serialprintln_onoff(const bool onoff) { serialprint_onoff(onoff); SERIAL_EOL(); } void serialprint_truefalse(const bool tf) { serial_print(tf ? F("true") : F("false")); } @@ -94,10 +97,10 @@ void print_bin(uint16_t val) { } } -void print_pos(LINEAR_AXIS_ARGS(const_float_t), FSTR_P const prefix/*=nullptr*/, FSTR_P const suffix/*=nullptr*/) { +void print_pos(NUM_AXIS_ARGS_LC(const_float_t), FSTR_P const prefix/*=nullptr*/, FSTR_P const suffix/*=nullptr*/) { if (prefix) serial_print(prefix); SERIAL_ECHOPGM_P( - LIST_N(DOUBLE(LINEAR_AXES), SP_X_STR, x, SP_Y_STR, y, SP_Z_STR, z, SP_I_STR, i, SP_J_STR, j, SP_K_STR, k) + LIST_N(DOUBLE(NUM_AXES), SP_X_STR, x, SP_Y_STR, y, SP_Z_STR, z, SP_I_STR, i, SP_J_STR, j, SP_K_STR, k, SP_U_STR, u, SP_V_STR, v, SP_W_STR, w) ); if (suffix) serial_print(suffix); else SERIAL_EOL(); } diff --git a/Marlin/src/core/serial.h b/Marlin/src/core/serial.h index aee4d4d4..15c83f77 100644 --- a/Marlin/src/core/serial.h +++ b/Marlin/src/core/serial.h @@ -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 // @@ -138,8 +125,6 @@ extern uint8_t marlin_debug_flags; #define SERIAL_IMPL SERIAL_LEAF_1 #endif -#define SERIAL_OUT(WHAT, V...) (void)SERIAL_IMPL.WHAT(V) - #define PORT_REDIRECT(p) _PORT_REDIRECT(1,p) #define PORT_RESTORE() _PORT_RESTORE(1) #define SERIAL_PORTMASK(P) SerialMask::from(P) @@ -162,10 +147,8 @@ template void SERIAL_ECHO(T x) { SERIAL_IMPL.print(x); } // Wrapper for ECHO commands to interpret a char -typedef struct SerialChar { char c; SerialChar(char n) : c(n) { } } serial_char_t; inline void SERIAL_ECHO(serial_char_t x) { SERIAL_IMPL.write(x.c); } -#define AS_CHAR(C) serial_char_t(C) -#define AS_DIGIT(C) AS_CHAR('0' + (C)) +#define AS_DIGIT(n) C('0' + (n)) template void SERIAL_ECHOLN(T x) { SERIAL_IMPL.println(x); } @@ -340,18 +323,53 @@ inline void serial_echolnpair(FSTR_P const fstr, T v) { serial_echolnpair_P(FTOP void serial_echo_start(); void serial_error_start(); -void serial_ternary(const bool onoff, FSTR_P const pre, FSTR_P const on, FSTR_P const off, FSTR_P const post=nullptr); +inline void serial_ternary(const bool onoff, FSTR_P const pre, FSTR_P const on, FSTR_P const off, FSTR_P const post=nullptr) { + if (pre) serial_print(pre); + if (onoff && on) serial_print(on); + if (!onoff && off) serial_print(off); + if (post) serial_print(post); +} void serialprint_onoff(const bool onoff); void serialprintln_onoff(const bool onoff); void serialprint_truefalse(const bool tf); void serial_spaces(uint8_t count); +void serial_offset(const_float_t v, const uint8_t sp=0); // For v==0 draw space (sp==1) or plus (sp==2) void print_bin(const uint16_t val); -void print_pos(LINEAR_AXIS_ARGS(const_float_t), FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr); +void print_pos(NUM_AXIS_ARGS_LC(const_float_t), FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr); -inline void print_pos(const xyz_pos_t &xyz, FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr) { - print_pos(LINEAR_AXIS_ELEM(xyz), prefix, suffix); +inline void print_pos(const xyze_pos_t &xyze, FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr) { + print_pos(NUM_AXIS_ELEM(xyze), prefix, suffix); } #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 diff --git a/Marlin/src/core/serial_base.h b/Marlin/src/core/serial_base.h index a5abd67d..a2f49417 100644 --- a/Marlin/src/core/serial_base.h +++ b/Marlin/src/core/serial_base.h @@ -23,6 +23,8 @@ #include "../inc/MarlinConfigPre.h" +#include // for size_t + #if ENABLED(EMERGENCY_PARSER) #include "../feature/e_parser.h" #endif @@ -77,7 +79,7 @@ struct EnsureDouble { operator double() { return a; } // If the compiler breaks on ambiguity here, it's likely because print(X, base) is called with X not a double/float, and // a base that's not a PrintBase value. This code is made to detect the error. You MUST set a base explicitly like this: - // SERIAL_PRINT(v, PrintBase::Hex) + //SERIAL_PRINT(v, PrintBase::Hex) EnsureDouble(double a) : a(a) {} EnsureDouble(float a) : a(a) {} }; @@ -167,7 +169,6 @@ struct SerialBase { FORCE_INLINE void print(unsigned int c, PrintBase base) { printNumber_unsigned(c, base); } FORCE_INLINE void print(unsigned long c, PrintBase base) { printNumber_unsigned(c, base); } - void print(EnsureDouble c, int digits) { printFloat(c, digits); } // Forward the call to the former's method @@ -178,7 +179,7 @@ struct SerialBase { void print(T c) { print(c, PrintBase::Dec); } void print(float c) { print(c, 2); } - void print(double c) { print(c, 2); } + void print(double c) { print(c, 2); } void println(char *s) { print(s); println(); } void println(const char *s) { print(s); println(); } @@ -232,7 +233,7 @@ struct SerialBase { // Round correctly so that print(1.999, 2) prints as "2.00" double rounding = 0.5; - LOOP_L_N(i, digits) rounding *= 0.1; + for (uint8_t i = 0; i < digits; ++i) rounding *= 0.1; number += rounding; // Extract the integer part of the number and print it diff --git a/Marlin/src/core/serial_hook.h b/Marlin/src/core/serial_hook.h index 2019b389..06efce1d 100644 --- a/Marlin/src/core/serial_hook.h +++ b/Marlin/src/core/serial_hook.h @@ -37,13 +37,15 @@ class SerialMask { inline constexpr bool enabled(const SerialMask PortMask) const { return mask & PortMask.mask; } inline constexpr SerialMask combine(const SerialMask other) const { return SerialMask(mask | other.mask); } inline constexpr SerialMask operator<< (const int offset) const { return SerialMask(mask << offset); } - static inline SerialMask from(const serial_index_t index) { + static SerialMask from(const serial_index_t index) { if (index.valid()) return SerialMask(_BV(index.index)); return SerialMask(0); // A invalid index mean no output } 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; }; @@ -177,7 +179,7 @@ struct RuntimeSerial : public SerialBase< RuntimeSerial >, public Seria // Append Hookable for this class SerialFeature features(serial_index_t index) const { return SerialFeature::Hookable | CALL_IF_EXISTS(SerialFeature, static_cast(this), features, index); } - void setHook(WriteHook writeHook = 0, EndOfMessageHook eofHook = 0, void * userPointer = 0) { + void setHook(WriteHook writeHook=0, EndOfMessageHook eofHook=0, void * userPointer=0) { // Order is important here as serial code can be called inside interrupts // When setting a hook, the user pointer must be set first so if writeHook is called as soon as it's set, it'll be valid if (userPointer) this->userPointer = userPointer; @@ -290,7 +292,7 @@ struct MultiSerial : public SerialBase< MultiSerial< REPEAT(NUM_SERIAL, _S_NAME) #define _S_REFS(N) Serial##N##T & serial##N, #define _S_INIT(N) ,serial##N (serial##N) - MultiSerial(REPEAT(NUM_SERIAL, _S_REFS) const SerialMask mask = ALL, const bool e = false) + MultiSerial(REPEAT(NUM_SERIAL, _S_REFS) const SerialMask mask=ALL, const bool e=false) : BaseClassT(e), portMask(mask) REPEAT(NUM_SERIAL, _S_INIT) {} }; @@ -298,7 +300,7 @@ struct MultiSerial : public SerialBase< MultiSerial< REPEAT(NUM_SERIAL, _S_NAME) // Build the actual serial object depending on current configuration #define Serial1Class TERN(SERIAL_RUNTIME_HOOK, RuntimeSerial, BaseSerial) #define ForwardSerial1Class TERN(SERIAL_RUNTIME_HOOK, RuntimeSerial, ForwardSerial) -#ifdef HAS_MULTI_SERIAL +#if HAS_MULTI_SERIAL #define Serial2Class ConditionalSerial #if NUM_SERIAL >= 3 #define Serial3Class ConditionalSerial diff --git a/Marlin/src/core/types.h b/Marlin/src/core/types.h index 9a5b64c2..f973b81f 100644 --- a/Marlin/src/core/types.h +++ b/Marlin/src/core/types.h @@ -31,32 +31,132 @@ // // typename IF<(MYOPT==12), int, float>::type myvar; // -template -struct IF { typedef R type; }; -template -struct IF { typedef L type; }; - -#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_ARRAY(V...) { LINEAR_AXIS_LIST(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 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_ARRAY(E,V...) { LOGICAL_AXIS_LIST(E,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_AXES_STRING LOGICAL_AXIS_GANG("E", "X", "Y", "Z", AXIS4_STR, AXIS5_STR, AXIS6_STR) +template struct IF { typedef R type; }; +template struct IF { typedef L type; }; + +#define ALL_AXIS_NAMES X, X2, Y, Y2, Z, Z2, Z3, Z4, I, J, K, U, V, W, E0, E1, E2, E3, E4, E5, E6, E7 + +#define NUM_AXIS_GANG(V...) GANG_N(NUM_AXES, V) +#define NUM_AXIS_CODE(V...) CODE_N(NUM_AXES, V) +#define NUM_AXIS_LIST(V...) LIST_N(NUM_AXES, V) +#define NUM_AXIS_LIST_1(V) LIST_N_1(NUM_AXES, V) +#define NUM_AXIS_ARRAY(V...) { NUM_AXIS_LIST(V) } +#define NUM_AXIS_ARRAY_1(V) { NUM_AXIS_LIST_1(V) } +#define NUM_AXIS_ARGS(T) NUM_AXIS_LIST(T X, T Y, T Z, T I, T J, T K, T U, T V, T W) +#define NUM_AXIS_ARGS_LC(T) NUM_AXIS_LIST(T x, T y, T z, T i, T j, T k, T u, T v, T w) +#define NUM_AXIS_ELEM(O) NUM_AXIS_LIST(O.X, O.Y, O.Z, O.I, O.J, O.K, O.U, O.V, O.W) +#define NUM_AXIS_ELEM_LC(O) NUM_AXIS_LIST(O.x, O.y, O.z, O.i, O.j, O.k, O.u, O.v, O.w) +#define NUM_AXIS_DECL(T,V) NUM_AXIS_LIST(T X=V, T Y=V, T Z=V, T I=V, T J=V, T K=V, T U=V, T V=V, T W=V) +#define NUM_AXIS_DECL_LC(T,V) NUM_AXIS_LIST(T x=V, T y=V, T z=V, T i=V, T j=V, T k=V, T u=V, T v=V, T w=V) +#define MAIN_AXIS_NAMES NUM_AXIS_LIST(X, Y, Z, I, J, K, U, V, W) +#define MAIN_AXIS_NAMES_LC NUM_AXIS_LIST(x, y, z, i, j, k, u, v, w) +#define STR_AXES_MAIN NUM_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K, STR_U, STR_V, STR_W) + +#define LOGICAL_AXIS_GANG(N,V...) NUM_AXIS_GANG(V) GANG_ITEM_E(N) +#define LOGICAL_AXIS_CODE(N,V...) NUM_AXIS_CODE(V) CODE_ITEM_E(N) +#define LOGICAL_AXIS_LIST(N,V...) NUM_AXIS_LIST(V) LIST_ITEM_E(N) +#define LOGICAL_AXIS_LIST_1(V) NUM_AXIS_LIST_1(V) LIST_ITEM_E(V) +#define LOGICAL_AXIS_ARRAY(N,V...) { LOGICAL_AXIS_LIST(N,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, T U, T V, T W) +#define LOGICAL_AXIS_ARGS_LC(T) LOGICAL_AXIS_LIST(T e, T x, T y, T z, T i, T j, T k, T u, T v, T w) +#define LOGICAL_AXIS_ELEM(O) LOGICAL_AXIS_LIST(O.E, O.X, O.Y, O.Z, O.I, O.J, O.K, O.U, O.V, O.W) +#define LOGICAL_AXIS_ELEM_LC(O) LOGICAL_AXIS_LIST(O.e, O.x, O.y, O.z, O.i, O.j, O.k, O.u, O.v, O.w) +#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, T U=V, T V=V, T W=V) +#define LOGICAL_AXIS_DECL_LC(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, T u=V, T v=V, T w=V) +#define LOGICAL_AXIS_NAMES LOGICAL_AXIS_LIST(E, X, Y, Z, I, J, K, U, V, W) +#define LOGICAL_AXIS_NAMES_LC LOGICAL_AXIS_LIST(e, x, y, z, i, j, k, u, v, w) +#define LOGICAL_AXIS_MAP(F) MAP(F, LOGICAL_AXIS_NAMES) +#define LOGICAL_AXIS_MAP_LC(F) MAP(F, LOGICAL_AXIS_NAMES_LC) +#define STR_AXES_LOGICAL LOGICAL_AXIS_GANG("E", "X", "Y", "Z", STR_I, STR_J, STR_K, STR_U, STR_V, STR_W) + +#if NUM_AXES + #define NUM_AXES_SEP , + #define MAIN_AXIS_MAP(F) MAP(F, MAIN_AXIS_NAMES) + #define MAIN_AXIS_MAP_LC(F) MAP(F, MAIN_AXIS_NAMES_LC) + #define OPTARGS_NUM(T) , NUM_AXIS_ARGS_LC(T) + #define OPTARGS_LOGICAL(T) , LOGICAL_AXIS_ARGS_LC(T) +#else + #define NUM_AXES_SEP + #define MAIN_AXIS_MAP(F) + #define MAIN_AXIS_MAP_LC(F) + #define OPTARGS_NUM(T) + #define OPTARGS_LOGICAL(T) +#endif + +#define NUM_AXIS_GANG_(V...) NUM_AXIS_GANG(V) NUM_AXES_SEP +#define NUM_AXIS_LIST_(V...) NUM_AXIS_LIST(V) NUM_AXES_SEP +#define NUM_AXIS_LIST_1_(V...) NUM_AXIS_LIST_1(V) NUM_AXES_SEP +#define NUM_AXIS_ARGS_(T) NUM_AXIS_ARGS_LC(T) NUM_AXES_SEP +#define NUM_AXIS_ELEM_(T) NUM_AXIS_ELEM_LC(T) NUM_AXES_SEP +#define MAIN_AXIS_NAMES_ MAIN_AXIS_NAMES NUM_AXES_SEP +#define MAIN_AXIS_NAMES_LC_ MAIN_AXIS_NAMES_LC NUM_AXES_SEP + +#if LOGICAL_AXES + #define LOGICAL_AXES_SEP , +#else + #define LOGICAL_AXES_SEP +#endif + +#define LOGICAL_AXIS_GANG_(V...) LOGICAL_AXIS_GANG(V) LOGICAL_AXES_SEP +#define LOGICAL_AXIS_LIST_(V...) LOGICAL_AXIS_LIST(V) LOGICAL_AXES_SEP +#define LOGICAL_AXIS_LIST_1_(V...) LOGICAL_AXIS_LIST_1(V) LOGICAL_AXES_SEP +#define LOGICAL_AXIS_ARGS_(T) LOGICAL_AXIS_ARGS_LC(T) LOGICAL_AXES_SEP +#define LOGICAL_AXIS_ELEM_(T) LOGICAL_AXIS_ELEM(T) LOGICAL_AXES_SEP +#define LOGICAL_AXIS_ELEM_LC_(T) LOGICAL_AXIS_ELEM_LC(T) LOGICAL_AXES_SEP +#define LOGICAL_AXIS_NAMES_ LOGICAL_AXIS_NAMES LOGICAL_AXES_SEP +#define LOGICAL_AXIS_NAMES_LC_ LOGICAL_AXIS_NAMES_LC LOGICAL_AXES_SEP + +#define SECONDARY_AXIS_GANG(V...) GANG_N(SECONDARY_AXES, V) +#define SECONDARY_AXIS_CODE(V...) CODE_N(SECONDARY_AXES, V) +#define SECONDARY_AXIS_LIST(V...) LIST_N(SECONDARY_AXES, V) +#if SECONDARY_AXES + #define SECONDARY_AXIS_NAMES SECONDARY_AXIS_LIST(I, J, K, U, V, W) + #define SECONDARY_AXIS_NAMES_LC SECONDARY_AXIS_LIST(i, j, k, u, v, w) + #define SECONDARY_AXIS_ARGS(T) SECONDARY_AXIS_LIST(T I, T J, T K, T U, T V, T W) + #define SECONDARY_AXIS_ARGS_LC(T) SECONDARY_AXIS_LIST(T i, T j, T k, T u, T v, T w) + #define SECONDARY_AXIS_MAP(F) MAP(F, SECONDARY_AXIS_NAMES) + #define SECONDARY_AXIS_MAP_LC(F) MAP(F, SECONDARY_AXIS_NAMES_LC) +#else + #define SECONDARY_AXIS_MAP(F) + #define SECONDARY_AXIS_MAP_LC(F) +#endif + +// Just the XY or XYZ elements +#if HAS_Z_AXIS + #define XYZ_COUNT 3 + #define XY_COUNT 2 +#elif HAS_Y_AXIS + #define XY_COUNT 2 +#elif HAS_X_AXIS + #define XY_COUNT 1 +#else + #define XY_COUNT 0 +#endif +#ifndef XYZ_COUNT + #define XYZ_COUNT XY_COUNT +#endif +#define XY_LIST(V...) LIST_N(XY_COUNT, V) +#define XY_ARRAY(V...) ARRAY_N(XY_COUNT, V) +#define XY_CODE(V...) CODE_N(XY_COUNT, V) +#define XY_GANG(V...) GANG_N(XY_COUNT, V) +#define XYZ_LIST(V...) LIST_N(XYZ_COUNT, V) +#define XYZ_ARRAY(V...) ARRAY_N(XYZ_COUNT, V) +#define XYZ_CODE(V...) CODE_N(XYZ_COUNT, V) +#define XYZ_GANG(V...) GANG_N(XYZ_COUNT, V) + +#if HAS_ROTATIONAL_AXES + #define ROTATIONAL_AXIS_GANG(V...) GANG_N(ROTATIONAL_AXES, V) +#endif #if HAS_EXTRUDERS - #define LIST_ITEM_E(N) , N - #define CODE_ITEM_E(N) ; N + #if NUM_AXES + #define LIST_ITEM_E(N) , N + #define CODE_ITEM_E(N) ; N + #else + #define LIST_ITEM_E(N) N + #define CODE_ITEM_E(N) N + #endif #define GANG_ITEM_E(N) N #else #define LIST_ITEM_E(N) @@ -64,58 +164,188 @@ struct IF { typedef L type; }; #define GANG_ITEM_E(N) #endif +#define AXIS_COLLISION(L) (AXIS4_NAME == L || AXIS5_NAME == L || AXIS6_NAME == L || AXIS7_NAME == L || AXIS8_NAME == L || AXIS9_NAME == L) + +// Helpers +#define _RECIP(N) ((N) ? 1.0f / static_cast(N) : 0.0f) +#define _ABS(N) ((N) < 0 ? -(N) : (N)) +#define _LS(N) T(uint32_t(N) << p) +#define _RS(N) T(uint32_t(N) >> p) +#define _LSE(N) N = T(uint32_t(N) << p) +#define _RSE(N) N = T(uint32_t(N) >> p) +#define FI FORCE_INLINE + +// Define types based on largest bit width stored value required +#define bits_t(W) typename IF<((W)> 32), uint64_t, typename IF<((W)> 16), uint32_t, typename IF<((W)>8), uint16_t, uint8_t>::type>::type>::type +#define uvalue_t(V) typename IF<((V)>65535), uint32_t, typename IF<((V)>255), uint16_t, uint8_t>::type>::type +#define value_t(V) typename IF<((V)>32767), int32_t, typename IF<((V)>127), int16_t, int8_t>::type>::type + +// Define a template for a bit field of N bits, using the smallest type that can hold N bits +template 64)> +struct Flags; + +// Flag bits for <= 64 states +template +struct Flags { + typedef bits_t(N) flagbits_t; + flagbits_t b; + + class BitProxy { + public: + BitProxy(flagbits_t& data, int bit) : data_(data), bit_(bit) {} + + BitProxy& operator=(const bool value) { + if (value) + data_ |= (flagbits_t(1) << bit_); + else + data_ &= ~(flagbits_t(1) << bit_); + return *this; + } + + operator bool() const { return bool(data_ & (flagbits_t(1) << bit_)); } + + private: + flagbits_t& data_; + uint8_t bit_; + }; + + FI void reset() { b = 0; } + FI void set(const int n, const bool onoff) { onoff ? set(n) : clear(n); } + FI void set(const int n) { b |= (flagbits_t(1) << n); } + FI void clear(const int n) { b &= ~(flagbits_t(1) << n); } + FI bool test(const int n) const { return bool(b & (flagbits_t(1) << n)); } + FI BitProxy operator[](const int n) { return BitProxy(b, n); } + FI bool operator[](const int n) const { return test(n); } + FI int size() const { return sizeof(b); } + FI operator bool() const { return b != 0; } +}; + +// Flag bits for more than 64 states +template +struct Flags { + uint8_t bitmask[(N+7)>>3]; + // Proxy class for handling bit assignment + class BitProxy { + public: + BitProxy(uint8_t data[], int n) : data_(data[n >> 3]), bit_(n & 7) {} + + // Assignment operator + BitProxy& operator=(const bool value) { + if (value) + data_ |= _BV(bit_); + else + data_ &= ~_BV(bit_); + return *this; + } + + // Conversion operator to bool + operator bool() const { return TEST(data_, bit_); } + + private: + uint8_t& data_; + uint8_t bit_; + }; + + FI void reset() { for (uint8_t b = 0; b < sizeof(bitmask); ++b) bitmask[b] = 0; } + FI void set(const int n, const bool onoff) { onoff ? set(n) : clear(n); } + FI void set(const int n) { bitmask[n >> 3] |= _BV(n & 7); } + FI void clear(const int n) { bitmask[n >> 3] &= ~_BV(n & 7); } + FI bool test(const int n) const { return TEST(bitmask[n >> 3], n & 7); } + FI BitProxy operator[](const int n) { return BitProxy(bitmask, n); } + FI bool operator[](const int n) const { return test(n); } + FI int size() const { return sizeof(bitmask); } + FI operator bool() const { for (uint8_t b : bitmask) if (b) return true; return false; } +}; + +// Specialization for a single bool flag +template<> +struct Flags<1, false> { + bool b; + FI void reset() { b = false; } + FI void set(const int n, const bool onoff) { onoff ? set(n) : clear(n); } + FI void set(const int) { b = true; } + FI void clear(const int) { b = false; } + FI bool test(const int) const { return b; } + FI bool& operator[](const int) { return b; } + FI bool operator[](const int) const { return b; } + FI int size() const { return sizeof(b); } + FI operator bool() const { return b; } +}; + +typedef Flags<8> flags_8_t; +typedef Flags<16> flags_16_t; + +// Flags for some axis states, with per-axis aliases xyzijkuvwe +typedef struct { + union { + struct Flags flags; + struct { bool LOGICAL_AXIS_LIST(e:1, x:1, y:1, z:1, i:1, j:1, k:1, u:1, v:1, w:1); }; + }; + FI void reset() { flags.reset(); } + FI void set(const int n) { flags.set(n); } + FI void set(const int n, const bool onoff) { flags.set(n, onoff); } + FI void clear(const int n) { flags.clear(n); } + FI bool test(const int n) const { return flags.test(n); } + FI bool operator[](const int n) { return flags[n]; } + FI bool operator[](const int n) const { return flags[n]; } + FI int size() const { return sizeof(flags); } + FI operator bool() const { return (bool)flags; } +} AxisFlags; + // // Enumerated axis indices // // - X_AXIS, Y_AXIS, and Z_AXIS should be used for axes in Cartesian space // - A_AXIS, B_AXIS, and C_AXIS should be used for Steppers, corresponding to XYZ on Cartesians -// - X_HEAD, Y_HEAD, and Z_HEAD should be used for Steppers on Core kinematics +// - X_HEAD, Y_HEAD, and Z_HEAD should be used for axes on Core kinematics // enum AxisEnum : uint8_t { // Linear axes may be controlled directly or indirectly - LINEAR_AXIS_LIST(X_AXIS, Y_AXIS, Z_AXIS, I_AXIS, J_AXIS, K_AXIS) + NUM_AXIS_LIST_(X_AXIS, Y_AXIS, Z_AXIS, I_AXIS, J_AXIS, K_AXIS, U_AXIS, V_AXIS, W_AXIS) - // Extruder axes may be considered distinctly - #define _EN_ITEM(N) , E##N##_AXIS + #define _EN_ITEM(N) E##N##_AXIS, REPEAT(EXTRUDERS, _EN_ITEM) #undef _EN_ITEM // Core also keeps toolhead directions #if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX) - , X_HEAD, Y_HEAD, Z_HEAD + X_HEAD, Y_HEAD, Z_HEAD, #endif // Distinct axes, including all E and Core - , NUM_AXIS_ENUMS + NUM_AXIS_HEADS, // Most of the time we refer only to the single E_AXIS #if HAS_EXTRUDERS - , E_AXIS = E0_AXIS + E_AXIS = E0_AXIS, #endif // A, B, and C are for DELTA, SCARA, etc. - , A_AXIS = X_AXIS - #if LINEAR_AXES >= 2 - , B_AXIS = Y_AXIS + #if HAS_X_AXIS + A_AXIS = X_AXIS, #endif - #if LINEAR_AXES >= 3 - , C_AXIS = Z_AXIS + #if HAS_Y_AXIS + B_AXIS = Y_AXIS, + #endif + #if HAS_Z_AXIS + C_AXIS = Z_AXIS, #endif // To refer to all or none - , ALL_AXES_ENUM = 0xFE, NO_AXIS_ENUM = 0xFF + ALL_AXES_ENUM = 0xFE, NO_AXIS_ENUM = 0xFF }; -typedef IF<(NUM_AXIS_ENUMS > 8), uint16_t, uint8_t>::type axis_bits_t; +typedef IF<(NUM_AXIS_HEADS > 8), uint16_t, uint8_t>::type axis_bits_t; // // Loop over axes // -#define LOOP_ABC(VAR) LOOP_S_LE_N(VAR, A_AXIS, C_AXIS) -#define LOOP_LINEAR_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, LINEAR_AXES) -#define LOOP_LOGICAL_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, LOGICAL_AXES) -#define LOOP_DISTINCT_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, DISTINCT_AXES) +#define LOOP_ABC(VAR) for (uint8_t VAR = A_AXIS; VAR <= C_AXIS; ++VAR) +#define LOOP_NUM_AXES(VAR) for (uint8_t VAR = 0; VAR < NUM_AXES; ++VAR) +#define LOOP_LOGICAL_AXES(VAR) for (uint8_t VAR = 0; VAR < LOGICAL_AXES; ++VAR) +#define LOOP_DISTINCT_AXES(VAR) for (uint8_t VAR = 0; VAR < DISTINCT_AXES; ++VAR) +#define LOOP_DISTINCT_E(VAR) for (uint8_t VAR = 0; VAR < DISTINCT_E; ++VAR) // // feedRate_t is just a humble float @@ -126,6 +356,7 @@ typedef float feedRate_t; // celsius_t is the native unit of temperature. Signed to handle a disconnected thermistor value (-14). // For more resolition (e.g., for a chocolate printer) this may later be changed to Celsius x 100 // +typedef uint16_t raw_adc_t; typedef int16_t celsius_t; typedef float celsius_float_t; @@ -140,21 +371,47 @@ typedef float celsius_float_t; typedef const_float_t const_feedRate_t; typedef const_float_t const_celsius_float_t; +// Type large enough to count leveling grid points +typedef IF 255)), uint16_t, uint8_t>::type grid_count_t; + // Conversion macros #define MMM_TO_MMS(MM_M) feedRate_t(static_cast(MM_M) / 60.0f) #define MMS_TO_MMM(MM_S) (static_cast(MM_S) * 60.0f) +// Packaged character for C macro and other usage +typedef struct SerialChar { char c; SerialChar(char n) : c(n) { } } serial_char_t; +#define C(c) serial_char_t(c) + +// Packaged types: float with precision and/or width; a repeated space/character +typedef struct WFloat { float value; char width; char prec; + WFloat(float v, char w, char p) : value(v), width(w), prec(p) {} + } w_float_t; +typedef struct PFloat { float value; char prec; + PFloat(float v, char p) : value(v), prec(p) {} + } p_float_t; +typedef struct RepChr { char asc; int8_t count; + RepChr(char a, uint8_t c) : asc(a), count(c) {} + } repchr_t; +typedef struct Spaces { int8_t count; + Spaces(uint8_t c) : count(c) {} + } spaces_t; + +#ifdef __AVR__ + typedef w_float_t w_double_t; + typedef p_float_t p_double_t; +#else + typedef struct WDouble { double value; char width; char prec; + WDouble(double v, char w, char p) : value(v), width(w), prec(p) {} + } w_double_t; + typedef struct PDouble { double value; char prec; + PDouble(double v, char p) : value(v), prec(p) {} + } p_double_t; +#endif + // // Coordinates structures for XY, XYZ, XYZE... // -// Helpers -#define _RECIP(N) ((N) ? 1.0f / static_cast(N) : 0.0f) -#define _ABS(N) ((N) < 0 ? -(N) : (N)) -#define _LS(N) (N = (T)(uint32_t(N) << v)) -#define _RS(N) (N = (T)(uint32_t(N) >> v)) -#define FI FORCE_INLINE - // Forward declarations template struct XYval; template struct XYZval; @@ -232,354 +489,370 @@ typedef abce_float_t abce_pos_t; void toLogical(xy_pos_t &raw); void toLogical(xyz_pos_t &raw); void toLogical(xyze_pos_t &raw); -void toNative(xy_pos_t &raw); -void toNative(xyz_pos_t &raw); -void toNative(xyze_pos_t &raw); +void toNative(xy_pos_t &lpos); +void toNative(xyz_pos_t &lpos); +void toNative(xyze_pos_t &lpos); // // Paired XY coordinates, counters, flags, etc. +// Always has XY elements regardless of the number of configured axes. // template struct XYval { union { struct { T x, y; }; + struct { T X, Y; }; struct { T a, b; }; + struct { T A, B; }; T pos[2]; }; // Set all to 0 - FI void reset() { x = y = 0; } + FI void reset() { x = y = 0; } // Setters taking struct types and arrays - FI void set(const T px) { x = px; } + #if HAS_X_AXIS + FI void set(const T px) { x = px; } + #endif #if HAS_Y_AXIS - FI void set(const T px, const T py) { x = px; y = py; } - FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; } + FI void set(const T px, const T py) { x = px; y = py; } + FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; } #endif - #if LINEAR_AXES > XY - FI void set(const T (&arr)[LINEAR_AXES]) { x = arr[0]; y = arr[1]; } + #if NUM_AXES > XY + FI void set(const T (&arr)[NUM_AXES]) { x = arr[0]; y = arr[1]; } #endif - #if LOGICAL_AXES > LINEAR_AXES - FI void set(const T (&arr)[LOGICAL_AXES]) { x = arr[0]; y = arr[1]; } + #if LOGICAL_AXES > NUM_AXES + FI void set(const T (&arr)[LOGICAL_AXES]) { x = arr[0]; y = arr[1]; } #if DISTINCT_AXES > LOGICAL_AXES - FI void set(const T (&arr)[DISTINCT_AXES]) { x = arr[0]; y = arr[1]; } + FI void set(const T (&arr)[DISTINCT_AXES]) { x = arr[0]; y = arr[1]; } #endif #endif // Length reduced to one dimension - FI T magnitude() const { return (T)sqrtf(x*x + y*y); } + FI constexpr T magnitude() const { return (T)sqrtf(x*x + y*y); } // Pointer to the data as a simple array - FI operator T* () { return pos; } + explicit FI operator T* () { return pos; } // If any element is true then it's true - FI operator bool() { return x || y; } + FI constexpr operator bool() const { return x || y; } + // Smallest element + FI constexpr T small() const { return _MIN(x, y); } + // Largest element + FI constexpr T large() const { return _MAX(x, y); } // Explicit copy and copies with conversion - FI XYval copy() const { return *this; } - FI XYval ABS() const { return { T(_ABS(x)), T(_ABS(y)) }; } - FI XYval asInt() { return { int16_t(x), int16_t(y) }; } - FI XYval asInt() const { return { int16_t(x), int16_t(y) }; } - FI XYval asLong() { return { int32_t(x), int32_t(y) }; } - FI XYval asLong() const { return { int32_t(x), int32_t(y) }; } - FI XYval ROUNDL() { return { int32_t(LROUND(x)), int32_t(LROUND(y)) }; } - FI XYval ROUNDL() const { return { int32_t(LROUND(x)), int32_t(LROUND(y)) }; } - FI XYval asFloat() { return { static_cast(x), static_cast(y) }; } - FI XYval asFloat() const { return { static_cast(x), static_cast(y) }; } - FI XYval reciprocal() const { return { _RECIP(x), _RECIP(y) }; } + FI constexpr XYval copy() const { return *this; } + FI constexpr XYval ABS() const { return { T(_ABS(x)), T(_ABS(y)) }; } + FI constexpr XYval asInt() const { return { int16_t(x), int16_t(y) }; } + FI constexpr XYval asLong() const { return { int32_t(x), int32_t(y) }; } + FI constexpr XYval ROUNDL() const { return { int32_t(LROUND(x)), int32_t(LROUND(y)) }; } + FI constexpr XYval asFloat() const { return { static_cast(x), static_cast(y) }; } + FI constexpr XYval reciprocal() const { return { _RECIP(x), _RECIP(y) }; } // Marlin workspace shifting is done with G92 and M206 - FI XYval asLogical() const { XYval o = asFloat(); toLogical(o); return o; } - FI XYval asNative() const { XYval o = asFloat(); toNative(o); return o; } + FI XYval asLogical() const { XYval o = asFloat(); toLogical(o); return o; } + FI XYval asNative() const { XYval o = asFloat(); toNative(o); return o; } // Cast to a type with more fields by making a new object - FI operator XYZval() { return { x, y }; } - FI operator XYZval() const { return { x, y }; } - FI operator XYZEval() { return { x, y }; } - FI operator XYZEval() const { return { x, y }; } + FI constexpr operator XYZval() const { return { x, y }; } + FI constexpr operator XYZEval() const { return { x, y }; } // Accessor via an AxisEnum (or any integer) [index] - FI T& operator[](const int n) { return pos[n]; } - FI const T& operator[](const int n) const { return pos[n]; } + FI T& operator[](const int n) { return pos[n]; } + FI const T& operator[](const int n) const { return pos[n]; } // Assignment operator overrides do the expected thing - FI XYval& operator= (const T v) { set(v, v ); return *this; } - FI XYval& operator= (const XYZval &rs) { set(rs.x, rs.y); return *this; } - FI XYval& operator= (const XYZEval &rs) { set(rs.x, rs.y); return *this; } + FI XYval& operator= (const T v) { set(v, v); return *this; } + FI XYval& operator= (const XYZval &rs) { set(XY_LIST(rs.x, rs.y)); return *this; } + FI XYval& operator= (const XYZEval &rs) { set(XY_LIST(rs.x, rs.y)); return *this; } // Override other operators to get intuitive behaviors - FI XYval operator+ (const XYval &rs) const { XYval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } - FI XYval operator+ (const XYval &rs) { XYval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } - FI XYval operator- (const XYval &rs) const { XYval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } - FI XYval operator- (const XYval &rs) { XYval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } - FI XYval operator* (const XYval &rs) const { XYval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } - FI XYval operator* (const XYval &rs) { XYval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } - FI XYval operator/ (const XYval &rs) const { XYval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } - FI XYval operator/ (const XYval &rs) { XYval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } - FI XYval operator+ (const XYZval &rs) const { XYval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } - FI XYval operator+ (const XYZval &rs) { XYval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } - FI XYval operator- (const XYZval &rs) const { XYval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } - FI XYval operator- (const XYZval &rs) { XYval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } - FI XYval operator* (const XYZval &rs) const { XYval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } - FI XYval operator* (const XYZval &rs) { XYval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } - FI XYval operator/ (const XYZval &rs) const { XYval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } - FI XYval operator/ (const XYZval &rs) { XYval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } - FI XYval operator+ (const XYZEval &rs) const { XYval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } - FI XYval operator+ (const XYZEval &rs) { XYval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } - FI XYval operator- (const XYZEval &rs) const { XYval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } - FI XYval operator- (const XYZEval &rs) { XYval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } - FI XYval operator* (const XYZEval &rs) const { XYval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } - FI XYval operator* (const XYZEval &rs) { XYval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } - FI XYval operator/ (const XYZEval &rs) const { XYval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } - FI XYval operator/ (const XYZEval &rs) { XYval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } - FI XYval operator* (const float &v) const { XYval ls = *this; ls.x *= v; ls.y *= v; return ls; } - FI XYval operator* (const float &v) { XYval ls = *this; ls.x *= v; ls.y *= v; return ls; } - FI XYval operator* (const int &v) const { XYval ls = *this; ls.x *= v; ls.y *= v; return ls; } - FI XYval operator* (const int &v) { XYval ls = *this; ls.x *= v; ls.y *= v; return ls; } - FI XYval operator/ (const float &v) const { XYval ls = *this; ls.x /= v; ls.y /= v; return ls; } - FI XYval operator/ (const float &v) { XYval ls = *this; ls.x /= v; ls.y /= v; return ls; } - FI XYval operator/ (const int &v) const { XYval ls = *this; ls.x /= v; ls.y /= v; return ls; } - FI XYval operator/ (const int &v) { XYval ls = *this; ls.x /= v; ls.y /= v; return ls; } - FI XYval operator>>(const int &v) const { XYval ls = *this; _RS(ls.x); _RS(ls.y); return ls; } - FI XYval operator>>(const int &v) { XYval ls = *this; _RS(ls.x); _RS(ls.y); return ls; } - FI XYval operator<<(const int &v) const { XYval ls = *this; _LS(ls.x); _LS(ls.y); return ls; } - FI XYval operator<<(const int &v) { XYval ls = *this; _LS(ls.x); _LS(ls.y); return ls; } - FI const XYval operator-() const { XYval o = *this; o.x = -x; o.y = -y; return o; } - FI XYval operator-() { XYval o = *this; o.x = -x; o.y = -y; return o; } + #define XY_OP(OP) { x TERN_(HAS_X_AXIS, OP rs.x), y TERN_(HAS_Y_AXIS, OP rs.y) } + FI constexpr XYval operator+ (const XYval &rs) const { return { x + rs.x, y + rs.y }; } + FI constexpr XYval operator- (const XYval &rs) const { return { x - rs.x, y - rs.y }; } + FI constexpr XYval operator* (const XYval &rs) const { return { x * rs.x, y * rs.y }; } + FI constexpr XYval operator/ (const XYval &rs) const { return { x / rs.x, y / rs.y }; } + FI constexpr XYval operator+ (const XYZval &rs) const { return { XY_OP(+) }; } + FI constexpr XYval operator- (const XYZval &rs) const { return { XY_OP(-) }; } + FI constexpr XYval operator* (const XYZval &rs) const { return { XY_OP(*) }; } + FI constexpr XYval operator/ (const XYZval &rs) const { return { XY_OP(/) }; } + FI constexpr XYval operator+ (const XYZEval &rs) const { return { XY_OP(+) }; } + FI constexpr XYval operator- (const XYZEval &rs) const { return { XY_OP(-) }; } + FI constexpr XYval operator* (const XYZEval &rs) const { return { XY_OP(*) }; } + FI constexpr XYval operator/ (const XYZEval &rs) const { return { XY_OP(/) }; } + FI constexpr XYval operator* (const float &p) const { return { (T)(x * p), (T)(y * p) }; } + FI constexpr XYval operator* (const int &p) const { return { x * p, y * p }; } + FI constexpr XYval operator/ (const float &p) const { return { (T)(x / p), (T)(y / p) }; } + FI constexpr XYval operator/ (const int &p) const { return { x / p, y / p }; } + FI constexpr XYval operator>>(const int &p) const { return { _RS(x), _RS(y) }; } + FI constexpr XYval operator<<(const int &p) const { return { _LS(x), _LS(y) }; } + FI constexpr XYval operator-() const { return { -x, -y }; } + #undef XY_OP // Modifier operators - FI XYval& operator+=(const XYval &rs) { x += rs.x; y += rs.y; return *this; } - FI XYval& operator-=(const XYval &rs) { x -= rs.x; y -= rs.y; return *this; } - FI XYval& operator*=(const XYval &rs) { x *= rs.x; y *= rs.y; return *this; } - FI XYval& operator+=(const XYZval &rs) { x += rs.x; y += rs.y; return *this; } - FI XYval& operator-=(const XYZval &rs) { x -= rs.x; y -= rs.y; return *this; } - FI XYval& operator*=(const XYZval &rs) { x *= rs.x; y *= rs.y; return *this; } - FI XYval& operator+=(const XYZEval &rs) { x += rs.x; y += rs.y; return *this; } - FI XYval& operator-=(const XYZEval &rs) { x -= rs.x; y -= rs.y; return *this; } - FI XYval& operator*=(const XYZEval &rs) { x *= rs.x; y *= rs.y; return *this; } - FI XYval& operator*=(const float &v) { x *= v; y *= v; return *this; } - FI XYval& operator*=(const int &v) { x *= v; y *= v; return *this; } - FI XYval& operator>>=(const int &v) { _RS(x); _RS(y); return *this; } - FI XYval& operator<<=(const int &v) { _LS(x); _LS(y); return *this; } + FI XYval& operator+=(const XYval &rs) { x += rs.x; y += rs.y; return *this; } + FI XYval& operator-=(const XYval &rs) { x -= rs.x; y -= rs.y; return *this; } + FI XYval& operator*=(const XYval &rs) { x *= rs.x; y *= rs.y; return *this; } + FI XYval& operator/=(const XYval &rs) { x /= rs.x; y /= rs.y; return *this; } + FI XYval& operator+=(const XYZval &rs) { XY_CODE(x += rs.x, y += rs.y); return *this; } + FI XYval& operator-=(const XYZval &rs) { XY_CODE(x -= rs.x, y -= rs.y); return *this; } + FI XYval& operator*=(const XYZval &rs) { XY_CODE(x *= rs.x, y *= rs.y); return *this; } + FI XYval& operator/=(const XYZval &rs) { XY_CODE(x /= rs.x, y /= rs.y); return *this; } + FI XYval& operator+=(const XYZEval &rs) { XY_CODE(x += rs.x, y += rs.y); return *this; } + FI XYval& operator-=(const XYZEval &rs) { XY_CODE(x -= rs.x, y -= rs.y); return *this; } + FI XYval& operator*=(const XYZEval &rs) { XY_CODE(x *= rs.x, y *= rs.y); return *this; } + FI XYval& operator/=(const XYZEval &rs) { XY_CODE(x /= rs.x, y /= rs.y); return *this; } + FI XYval& operator*=(const float &p) { x *= p; y *= p; return *this; } + FI XYval& operator*=(const int &p) { x *= p; y *= p; return *this; } + FI XYval& operator>>=(const int &p) { _RSE(x); _RSE(y); return *this; } + FI XYval& operator<<=(const int &p) { _LSE(x); _LSE(y); return *this; } + + // Absolute difference between two objects + FI constexpr XYval diff(const XYZEval &rs) const { return { TERN(HAS_X_AXIS, T(_ABS(x - rs.x)), x), TERN(HAS_Y_AXIS, T(_ABS(y - rs.y)), y) }; } + FI constexpr XYval diff(const XYZval &rs) const { return { TERN(HAS_X_AXIS, T(_ABS(x - rs.x)), x), TERN(HAS_Y_AXIS, T(_ABS(y - rs.y)), y) }; } + FI constexpr XYval diff(const XYval &rs) const { return { T(_ABS(x - rs.x)), T(_ABS(y - rs.y)) }; } // Exact comparisons. For floats a "NEAR" operation may be better. - FI bool operator==(const XYval &rs) { return x == rs.x && y == rs.y; } - FI bool operator==(const XYZval &rs) { return x == rs.x && y == rs.y; } - FI bool operator==(const XYZEval &rs) { return x == rs.x && y == rs.y; } - FI bool operator==(const XYval &rs) const { return x == rs.x && y == rs.y; } - FI bool operator==(const XYZval &rs) const { return x == rs.x && y == rs.y; } - FI bool operator==(const XYZEval &rs) const { return x == rs.x && y == rs.y; } - FI bool operator!=(const XYval &rs) { return !operator==(rs); } - FI bool operator!=(const XYZval &rs) { return !operator==(rs); } - FI bool operator!=(const XYZEval &rs) { return !operator==(rs); } - FI bool operator!=(const XYval &rs) const { return !operator==(rs); } - FI bool operator!=(const XYZval &rs) const { return !operator==(rs); } - FI bool operator!=(const XYZEval &rs) const { return !operator==(rs); } + FI bool operator==(const XYval &rs) const { return x == rs.x && y == rs.y; } + FI bool operator==(const XYZval &rs) const { return ENABLED(HAS_X_AXIS) XY_GANG(&& x == rs.x, && y == rs.y); } + FI bool operator==(const XYZEval &rs) const { return ENABLED(HAS_X_AXIS) XY_GANG(&& x == rs.x, && y == rs.y); } + FI bool operator!=(const XYval &rs) const { return !operator==(rs); } + FI bool operator!=(const XYZval &rs) const { return !operator==(rs); } + FI bool operator!=(const XYZEval &rs) const { return !operator==(rs); } }; // // Linear Axes coordinates, counters, flags, etc. +// May have any number of axes according to configuration, including zero axes. // template struct XYZval { union { - struct { T LINEAR_AXIS_ARGS(); }; - struct { T LINEAR_AXIS_LIST(a, b, c, u, v, w); }; - T pos[LINEAR_AXES]; + #if NUM_AXES + struct { NUM_AXIS_CODE(T x, T y, T z, T i, T j, T k, T u, T v, T w); }; + struct { NUM_AXIS_CODE(T X, T Y, T Z, T I, T J, T K, T U, T V, T W); }; + struct { NUM_AXIS_CODE(T a, T b, T c, T _i, T _j, T _k, T _u, T _v, T _w); }; + struct { NUM_AXIS_CODE(T A, T B, T C, T II, T JJ, T KK, T UU, T VV, T WW); }; + #endif + T pos[NUM_AXES]; }; // Set all to 0 - FI void reset() { LINEAR_AXIS_GANG(x =, y =, z =, i =, j =, k =) 0; } + FI void reset() { NUM_AXIS_CODE(x = 0, y = 0, z = 0, i = 0, j = 0, k = 0, u = 0, v = 0, w = 0); } // Setters taking struct types and arrays - FI void set(const T px) { x = px; } - FI void set(const T px, const T py) { x = px; y = py; } - FI void set(const XYval pxy) { x = pxy.x; y = pxy.y; } - FI void set(const XYval pxy, const T pz) { LINEAR_AXIS_CODE(x = pxy.x, y = pxy.y, z = pz, NOOP, NOOP, NOOP); } - FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; } - #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 ); } - #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(const XYval pxy) { XY_CODE(x = pxy.x, y = pxy.y); } + FI void set(const XYval pxy, const T pz) { XYZ_CODE(x = pxy.x, y = pxy.y, z = pz); } + FI void set(const T (&arr)[NUM_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } + #if LOGICAL_AXES > NUM_AXES + FI void set(const T (&arr)[LOGICAL_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } + FI void set(LOGICAL_AXIS_ARGS_LC(const T)) { NUM_AXIS_CODE(a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w); } #if DISTINCT_AXES > LOGICAL_AXES - FI void set(const T (&arr)[DISTINCT_AXES]) { LINEAR_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5]); } + FI void set(const T (&arr)[DISTINCT_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } #endif #endif - #if LINEAR_AXES >= 4 - FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; } + + // Setter for all individual args + FI void set(NUM_AXIS_ARGS_LC(const T)) { NUM_AXIS_CODE(a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w); } + + // Setters with fewer elements leave the rest untouched + #if HAS_Y_AXIS + FI void set(const T px) { x = px; } + #endif + #if HAS_Z_AXIS + FI void set(const T px, const T py) { x = px; y = py; } #endif - #if LINEAR_AXES >= 5 - FI void set(const T px, const T py, const T pz, const T pi) { x = px; y = py; z = pz; i = pi; } + #if HAS_I_AXIS + FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; } #endif - #if LINEAR_AXES >= 6 + #if HAS_J_AXIS + FI void set(const T px, const T py, const T pz, const T pi) { x = px; y = py; z = pz; i = pi; } + #endif + #if HAS_K_AXIS FI void set(const T px, const T py, const T pz, const T pi, const T pj) { x = px; y = py; z = pz; i = pi; j = pj; } #endif + #if HAS_U_AXIS + FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; } + #endif + #if HAS_V_AXIS + FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; u = pu; } + #endif + #if HAS_W_AXIS + FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu, const T pv) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; u = pu; v = pv; } + #endif // Length reduced to one dimension - FI T magnitude() const { return (T)sqrtf(LINEAR_AXIS_GANG(x*x, + y*y, + z*z, + i*i, + j*j, + k*k)); } + FI constexpr T magnitude() const { return (T)TERN(HAS_X_AXIS, sqrtf(NUM_AXIS_GANG(x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)), 0); } // Pointer to the data as a simple array - FI operator T* () { return pos; } + explicit FI operator T* () { return pos; } // If any element is true then it's true - FI operator bool() { return LINEAR_AXIS_GANG(x, || y, || z, || i, || j, || k); } + FI constexpr operator bool() const { return 0 NUM_AXIS_GANG(|| x, || y, || z, || i, || j, || k, || u, || v, || w); } + // Smallest element + FI constexpr T small() const { return TERN0(HAS_X_AXIS, _MIN(NUM_AXIS_LIST(x, y, z, i, j, k, u, v, w))); } + // Largest element + FI constexpr T large() const { return TERN0(HAS_X_AXIS, _MAX(NUM_AXIS_LIST(x, y, z, i, j, k, u, v, w))); } // Explicit copy and copies with conversion - FI XYZval copy() const { XYZval o = *this; return o; } - FI XYZval ABS() const { return LINEAR_AXIS_ARRAY(T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(i)), T(_ABS(j)), T(_ABS(k))); } - FI XYZval asInt() { return LINEAR_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k)); } - FI XYZval asInt() const { return LINEAR_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k)); } - FI XYZval asLong() { return LINEAR_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k)); } - FI XYZval asLong() const { return LINEAR_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k)); } - FI XYZval ROUNDL() { return LINEAR_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k))); } - FI XYZval ROUNDL() const { return LINEAR_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k))); } - FI XYZval asFloat() { return LINEAR_AXIS_ARRAY(static_cast(x), static_cast(y), static_cast(z), static_cast(i), static_cast(j), static_cast(k)); } - FI XYZval asFloat() const { return LINEAR_AXIS_ARRAY(static_cast(x), static_cast(y), static_cast(z), static_cast(i), static_cast(j), static_cast(k)); } - FI XYZval reciprocal() const { return LINEAR_AXIS_ARRAY(_RECIP(x), _RECIP(y), _RECIP(z), _RECIP(i), _RECIP(j), _RECIP(k)); } + FI constexpr XYZval copy() const { XYZval o = *this; return o; } + FI constexpr XYZval ABS() const { return NUM_AXIS_ARRAY(T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(i)), T(_ABS(j)), T(_ABS(k)), T(_ABS(u)), T(_ABS(v)), T(_ABS(w))); } + FI constexpr XYZval asInt() const { return NUM_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k), int16_t(u), int16_t(v), int16_t(w)); } + FI constexpr XYZval asLong() const { return NUM_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k), int32_t(u), int32_t(v), int32_t(w)); } + FI constexpr XYZval ROUNDL() const { return NUM_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k)), int32_t(LROUND(u)), int32_t(LROUND(v)), int32_t(LROUND(w))); } + FI constexpr XYZval asFloat() const { return NUM_AXIS_ARRAY(static_cast(x), static_cast(y), static_cast(z), static_cast(i), static_cast(j), static_cast(k), static_cast(u), static_cast(v), static_cast(w)); } + FI constexpr XYZval reciprocal() const { return NUM_AXIS_ARRAY(_RECIP(x), _RECIP(y), _RECIP(z), _RECIP(i), _RECIP(j), _RECIP(k), _RECIP(u), _RECIP(v), _RECIP(w)); } // Marlin workspace shifting is done with G92 and M206 - FI XYZval asLogical() const { XYZval o = asFloat(); toLogical(o); return o; } - FI XYZval asNative() const { XYZval o = asFloat(); toNative(o); return o; } + FI XYZval asLogical() const { XYZval o = asFloat(); toLogical(o); return o; } + FI XYZval asNative() const { XYZval o = asFloat(); toNative(o); return o; } // In-place cast to types having fewer fields - FI operator XYval&() { return *(XYval*)this; } - FI operator const XYval&() const { return *(const XYval*)this; } + FI operator XYval&() { return *(XYval*)this; } + FI operator const XYval&() const { return *(const XYval*)this; } // Cast to a type with more fields by making a new object - FI operator XYZEval() const { return LINEAR_AXIS_ARRAY(x, y, z, i, j, k); } + FI constexpr operator XYZEval() const { return NUM_AXIS_ARRAY(x, y, z, i, j, k, u, v, w); } // Accessor via an AxisEnum (or any integer) [index] - FI T& operator[](const int n) { return pos[n]; } - FI const T& operator[](const int n) const { return pos[n]; } + FI T& operator[](const int n) { return pos[n]; } + FI const T& operator[](const int n) const { return pos[n]; } // Assignment operator overrides do the expected thing - FI XYZval& operator= (const T v) { set(ARRAY_N_1(LINEAR_AXES, v)); return *this; } - FI XYZval& operator= (const XYval &rs) { set(rs.x, rs.y ); return *this; } - FI XYZval& operator= (const XYZEval &rs) { set(LINEAR_AXIS_ELEM(rs)); return *this; } + FI XYZval& operator= (const T v) { set(ARRAY_N_1(NUM_AXES, v)); return *this; } + FI XYZval& operator= (const XYval &rs) { set(rs.x, rs.y); return *this; } + FI XYZval& operator= (const XYZEval &rs) { set(NUM_AXIS_ELEM_LC(rs)); return *this; } // Override other operators to get intuitive behaviors - FI XYZval operator+ (const XYval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator+ (const XYval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator- (const XYval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator- (const XYval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator* (const XYval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator* (const XYval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator/ (const XYval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator/ (const XYval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; } - FI XYZval operator+ (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } - FI XYZval operator+ (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } - FI XYZval operator- (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } - FI XYZval operator- (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } - FI XYZval operator* (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } - FI XYZval operator* (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } - FI XYZval operator/ (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } - FI XYZval operator/ (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } - FI XYZval operator+ (const XYZEval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } - FI XYZval operator+ (const XYZEval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } - FI XYZval operator- (const XYZEval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } - FI XYZval operator- (const XYZEval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } - FI XYZval operator* (const XYZEval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } - FI XYZval operator* (const XYZEval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } - FI XYZval operator/ (const XYZEval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } - FI XYZval operator/ (const XYZEval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } - FI XYZval operator* (const float &v) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; } - FI XYZval operator* (const float &v) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; } - FI XYZval operator* (const int &v) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; } - FI XYZval operator* (const int &v) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; } - FI XYZval operator/ (const float &v) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; } - FI XYZval operator/ (const float &v) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; } - FI XYZval operator/ (const int &v) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; } - FI XYZval operator/ (const int &v) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; } - FI XYZval operator>>(const int &v) const { XYZval ls = *this; LINEAR_AXIS_CODE(_RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k) ); return ls; } - FI XYZval operator>>(const int &v) { XYZval ls = *this; LINEAR_AXIS_CODE(_RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k) ); return ls; } - FI XYZval operator<<(const int &v) const { XYZval ls = *this; LINEAR_AXIS_CODE(_LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k) ); return ls; } - FI XYZval operator<<(const int &v) { XYZval ls = *this; LINEAR_AXIS_CODE(_LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k) ); return ls; } - FI const XYZval operator-() const { XYZval o = *this; LINEAR_AXIS_CODE(o.x = -x, o.y = -y, o.z = -z, o.i = -i, o.j = -j, o.k = -k); return o; } - FI XYZval operator-() { XYZval o = *this; LINEAR_AXIS_CODE(o.x = -x, o.y = -y, o.z = -z, o.i = -i, o.j = -j, o.k = -k); return o; } + FI constexpr XYZval operator+ (const XYval &rs) const { return NUM_AXIS_ARRAY(x + rs.x, y + rs.y, z, i, j, k, u, v, w ); } + FI constexpr XYZval operator- (const XYval &rs) const { return NUM_AXIS_ARRAY(x - rs.x, y - rs.y, z, i, j, k, u, v, w ); } + FI constexpr XYZval operator* (const XYval &rs) const { return NUM_AXIS_ARRAY(x * rs.x, y * rs.y, z, i, j, k, u, v, w ); } + FI constexpr XYZval operator/ (const XYval &rs) const { return NUM_AXIS_ARRAY(x / rs.x, y / rs.y, z, i, j, k, u, v, w ); } + FI constexpr XYZval operator+ (const XYZval &rs) const { return NUM_AXIS_ARRAY(x + rs.x, y + rs.y, z + rs.z, i + rs.i, j + rs.j, k + rs.k, u + rs.u, v + rs.v, w + rs.w ); } + FI constexpr XYZval operator- (const XYZval &rs) const { return NUM_AXIS_ARRAY(x - rs.x, y - rs.y, z - rs.z, i - rs.i, j - rs.j, k - rs.k, u - rs.u, v - rs.v, w - rs.w ); } + FI constexpr XYZval operator* (const XYZval &rs) const { return NUM_AXIS_ARRAY(x * rs.x, y * rs.y, z * rs.z, i * rs.i, j * rs.j, k * rs.k, u * rs.u, v * rs.v, w * rs.w ); } + FI constexpr XYZval operator/ (const XYZval &rs) const { return NUM_AXIS_ARRAY(x / rs.x, y / rs.y, z / rs.z, i / rs.i, j / rs.j, k / rs.k, u / rs.u, v / rs.v, w / rs.w ); } + FI constexpr XYZval operator+ (const XYZEval &rs) const { return NUM_AXIS_ARRAY(x + rs.x, y + rs.y, z + rs.z, i + rs.i, j + rs.j, k + rs.k, u + rs.u, v + rs.v, w + rs.w ); } + FI constexpr XYZval operator- (const XYZEval &rs) const { return NUM_AXIS_ARRAY(x - rs.x, y - rs.y, z - rs.z, i - rs.i, j - rs.j, k - rs.k, u - rs.u, v - rs.v, w - rs.w ); } + FI constexpr XYZval operator* (const XYZEval &rs) const { return NUM_AXIS_ARRAY(x * rs.x, y * rs.y, z * rs.z, i * rs.i, j * rs.j, k * rs.k, u * rs.u, v * rs.v, w * rs.w ); } + FI constexpr XYZval operator/ (const XYZEval &rs) const { return NUM_AXIS_ARRAY(x / rs.x, y / rs.y, z / rs.z, i / rs.i, j / rs.j, k / rs.k, u / rs.u, v / rs.v, w / rs.w ); } + FI constexpr XYZval operator* (const float &p) const { return NUM_AXIS_ARRAY((T)(x * p), (T)(y * p), (T)(z * p), (T)(i * p), (T)(j * p), (T)(k * p), (T)(u * p), (T)(v * p), (T)(w * p)); } + FI constexpr XYZval operator* (const int &p) const { return NUM_AXIS_ARRAY(x * p, y * p, z * p, i * p, j * p, k * p, u * p, v * p, w * p); } + FI constexpr XYZval operator/ (const float &p) const { return NUM_AXIS_ARRAY((T)(x / p), (T)(y / p), (T)(z / p), (T)(i / p), (T)(j / p), (T)(k / p), (T)(u / p), (T)(v / p), (T)(w / p)); } + FI constexpr XYZval operator/ (const int &p) const { return NUM_AXIS_ARRAY(x / p, y / p, z / p, i / p, j / p, k / p, u / p, v / p, w / p); } + FI constexpr XYZval operator>>(const int &p) const { return NUM_AXIS_ARRAY(_RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k), _RS(u), _RS(v), _RS(w)); } + FI constexpr XYZval operator<<(const int &p) const { return NUM_AXIS_ARRAY(_LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k), _LS(u), _LS(v), _LS(w)); } + FI constexpr XYZval operator-() const { return NUM_AXIS_ARRAY(-x, -y, -z, -i, -j, -k, -u, -v, -w); } + + // Absolute difference between two objects + FI constexpr XYZval diff(const XYZEval &rs) const { return NUM_AXIS_ARRAY(T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), T(_ABS(z - rs.z)), T(_ABS(i - rs.i)), T(_ABS(j - rs.j)), T(_ABS(k - rs.k)), T(_ABS(u - rs.u)), T(_ABS(v - rs.v)), T(_ABS(w - rs.w)) ); } + FI constexpr XYZval diff(const XYZval &rs) const { return NUM_AXIS_ARRAY(T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), T(_ABS(z - rs.z)), T(_ABS(i - rs.i)), T(_ABS(j - rs.j)), T(_ABS(k - rs.k)), T(_ABS(u - rs.u)), T(_ABS(v - rs.v)), T(_ABS(w - rs.w)) ); } + FI constexpr XYZval diff(const XYval &rs) const { return NUM_AXIS_ARRAY(T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), z, i, j, k, u, v, w ); } // Modifier operators - FI XYZval& operator+=(const XYval &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, NOOP, NOOP, NOOP, NOOP ); return *this; } - FI XYZval& operator-=(const XYval &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, NOOP, NOOP, NOOP, NOOP ); return *this; } - FI XYZval& operator*=(const XYval &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, NOOP, NOOP, NOOP, NOOP ); return *this; } - FI XYZval& operator/=(const XYval &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, NOOP, NOOP, NOOP, NOOP ); return *this; } - FI XYZval& operator+=(const XYZval &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k); return *this; } - FI XYZval& operator-=(const XYZval &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k); return *this; } - FI XYZval& operator*=(const XYZval &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k); return *this; } - FI XYZval& operator/=(const XYZval &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k); return *this; } - FI XYZval& operator+=(const XYZEval &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k); return *this; } - FI XYZval& operator-=(const XYZEval &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k); return *this; } - FI XYZval& operator*=(const XYZEval &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k); return *this; } - FI XYZval& operator/=(const XYZEval &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k); return *this; } - FI XYZval& operator*=(const float &v) { LINEAR_AXIS_CODE(x *= v, y *= v, z *= v, i *= v, j *= v, k *= v); return *this; } - FI XYZval& operator*=(const int &v) { LINEAR_AXIS_CODE(x *= v, y *= v, z *= v, i *= v, j *= v, k *= v); return *this; } - FI XYZval& operator>>=(const int &v) { LINEAR_AXIS_CODE(_RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k)); return *this; } - FI XYZval& operator<<=(const int &v) { LINEAR_AXIS_CODE(_LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k)); return *this; } + FI XYZval& operator+=(const XYval &rs) { XY_CODE(x += rs.x, y += rs.y); return *this; } + FI XYZval& operator-=(const XYval &rs) { XY_CODE(x -= rs.x, y -= rs.y); return *this; } + FI XYZval& operator*=(const XYval &rs) { XY_CODE(x *= rs.x, y *= rs.y); return *this; } + FI XYZval& operator/=(const XYval &rs) { XY_CODE(x /= rs.x, y /= rs.y); return *this; } + FI XYZval& operator+=(const XYZval &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k, u += rs.u, v += rs.v, w += rs.w); return *this; } + FI XYZval& operator-=(const XYZval &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k, u -= rs.u, v -= rs.v, w -= rs.w); return *this; } + FI XYZval& operator*=(const XYZval &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k, u *= rs.u, v *= rs.v, w *= rs.w); return *this; } + FI XYZval& operator/=(const XYZval &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k, u /= rs.u, v /= rs.v, w /= rs.w); return *this; } + FI XYZval& operator+=(const XYZEval &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k, u += rs.u, v += rs.v, w += rs.w); return *this; } + FI XYZval& operator-=(const XYZEval &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k, u -= rs.u, v -= rs.v, w -= rs.w); return *this; } + FI XYZval& operator*=(const XYZEval &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k, u *= rs.u, v *= rs.v, w *= rs.w); return *this; } + FI XYZval& operator/=(const XYZEval &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k, u /= rs.u, v /= rs.v, w /= rs.w); return *this; } + FI XYZval& operator*=(const float &p) { NUM_AXIS_CODE(x *= p, y *= p, z *= p, i *= p, j *= p, k *= p, u *= p, v *= p, w *= p); return *this; } + FI XYZval& operator*=(const int &p) { NUM_AXIS_CODE(x *= p, y *= p, z *= p, i *= p, j *= p, k *= p, u *= p, v *= p, w *= p); return *this; } + FI XYZval& operator>>=(const int &p) { NUM_AXIS_CODE(_RSE(x), _RSE(y), _RSE(z), _RSE(i), _RSE(j), _RSE(k), _RSE(u), _RSE(v), _RSE(w)); return *this; } + FI XYZval& operator<<=(const int &p) { NUM_AXIS_CODE(_LSE(x), _LSE(y), _LSE(z), _LSE(i), _LSE(j), _LSE(k), _LSE(u), _LSE(v), _LSE(w)); return *this; } // Exact comparisons. For floats a "NEAR" operation may be better. - FI bool operator==(const XYZEval &rs) { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k); } - FI bool operator==(const XYZEval &rs) const { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k); } - FI bool operator!=(const XYZEval &rs) { return !operator==(rs); } - FI bool operator!=(const XYZEval &rs) const { return !operator==(rs); } + FI bool operator==(const XYZEval &rs) const { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); } + FI bool operator!=(const XYZEval &rs) const { return !operator==(rs); } }; // // Logical Axes coordinates, counters, etc. +// May have any number of axes according to configuration, including zero axes. +// When there is no extruder, essentially identical to XYZval. // template struct XYZEval { union { + struct { T LOGICAL_AXIS_ARGS_LC(); }; 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, _u, _v, _w); }; + struct { T LOGICAL_AXIS_LIST(EE, A, B, C, II, JJ, KK, UU, VV, WW); }; T pos[LOGICAL_AXES]; }; // Reset all to 0 - FI void reset() { LOGICAL_AXIS_GANG(e =, x =, y =, z =, i =, j =, k =) 0; } + FI void reset() { LOGICAL_AXIS_GANG(e =, x =, y =, z =, i =, j =, k =, u =, v =, w =) 0; } // Setters taking struct types and arrays - FI void set(const T px) { x = px; } - FI void set(const T px, const T py) { x = px; y = py; } - FI void set(const XYval pxy) { x = pxy.x; y = pxy.y; } - FI void set(const XYZval pxyz) { set(LINEAR_AXIS_ELEM(pxyz)); } + FI void set(const XYval pxy) { XY_CODE(x = pxy.x, y = pxy.y); } + FI void set(const XYval pxy, const T pz) { XYZ_CODE(x = pxy.x, y = pxy.y, z = pz); } + FI void set(const XYZval pxyz) { set(NUM_AXIS_ELEM_LC(pxyz)); } + FI void set(const T (&arr)[NUM_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } + #if LOGICAL_AXES > NUM_AXES + FI void set(const T (&arr)[LOGICAL_AXES]) { LOGICAL_AXIS_CODE(e = arr[LOGICAL_AXES-1], x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } + FI void set(const XYval pxy, const T pz, const T pe) { set(pxy, pz); e = pe; } + FI void set(const XYZval pxyz, const T pe) { set(pxyz); e = pe; } + FI void set(LOGICAL_AXIS_ARGS_LC(const T)) { LOGICAL_AXIS_CODE(_e = e, a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w); } + #if DISTINCT_AXES > LOGICAL_AXES + FI void set(const T (&arr)[DISTINCT_AXES]) { LOGICAL_AXIS_CODE(e = arr[LOGICAL_AXES-1], x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); } + #endif + #endif + + // Setter for all individual args + FI void set(NUM_AXIS_ARGS_LC(const T)) { NUM_AXIS_CODE(a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w); } + + // Setters with fewer elements leave the rest untouched + #if HAS_Y_AXIS + FI void set(const T px) { x = px; } + #endif #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(const T px, const T py) { x = px; y = py; } #endif - #if LOGICAL_AXES > LINEAR_AXES - FI void set(const XYval pxy, const T pe) { set(pxy); e = pe; } - FI void set(const XYZval 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); } + #if HAS_I_AXIS + FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; } #endif - #if LINEAR_AXES >= 4 - FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; } + #if HAS_J_AXIS + FI void set(const T px, const T py, const T pz, const T pi) { x = px; y = py; z = pz; i = pi; } #endif - #if LINEAR_AXES >= 5 - FI void set(const T px, const T py, const T pz, const T pi) { x = px; y = py; z = pz; i = pi; } + #if HAS_K_AXIS + FI void set(const T px, const T py, const T pz, const T pi, const T pj) { x = px; y = py; z = pz; i = pi; j = pj; } #endif - #if LINEAR_AXES >= 6 - FI void set(const T px, const T py, const T pz, const T pi, const T pj) { x = px; y = py; z = pz; i = pi; j = pj; } + #if HAS_U_AXIS + FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; } + #endif + #if HAS_V_AXIS + FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; u = pu; } + #endif + #if HAS_W_AXIS + FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu, const T pv) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; u = pu; v = pv; } #endif // Length reduced to one dimension - FI T magnitude() const { return (T)sqrtf(LOGICAL_AXIS_GANG(+ e*e, + x*x, + y*y, + z*z, + i*i, + j*j, + k*k)); } + FI constexpr T magnitude() const { return (T)sqrtf(LOGICAL_AXIS_GANG(+ e*e, + x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)); } // Pointer to the data as a simple array - FI operator T* () { return pos; } + explicit FI operator T* () { return pos; } // If any element is true then it's true - FI operator bool() { return 0 LOGICAL_AXIS_GANG(|| e, || x, || y, || z, || i, || j, || k); } + FI constexpr operator bool() const { return 0 LOGICAL_AXIS_GANG(|| e, || x, || y, || z, || i, || j, || k, || u, || v, || w); } + // Smallest element + FI constexpr T small() const { return _MIN(LOGICAL_AXIS_LIST(e, x, y, z, i, j, k, u, v, w)); } + // Largest element + FI constexpr T large() const { return _MAX(LOGICAL_AXIS_LIST(e, x, y, z, i, j, k, u, v, w)); } // Explicit copy and copies with conversion - FI XYZEval copy() const { XYZEval o = *this; return o; } - FI XYZEval ABS() const { return LOGICAL_AXIS_ARRAY(T(_ABS(e)), T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(i)), T(_ABS(j)), T(_ABS(k))); } - FI XYZEval asInt() { return LOGICAL_AXIS_ARRAY(int16_t(e), int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k)); } - FI XYZEval asInt() const { return LOGICAL_AXIS_ARRAY(int16_t(e), int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k)); } - FI XYZEval asLong() { return LOGICAL_AXIS_ARRAY(int32_t(e), int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k)); } - FI XYZEval asLong() const { return LOGICAL_AXIS_ARRAY(int32_t(e), int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k)); } - FI XYZEval ROUNDL() { return LOGICAL_AXIS_ARRAY(int32_t(LROUND(e)), int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k))); } - FI XYZEval ROUNDL() const { return LOGICAL_AXIS_ARRAY(int32_t(LROUND(e)), int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k))); } - FI XYZEval asFloat() { return LOGICAL_AXIS_ARRAY(static_cast(e), static_cast(x), static_cast(y), static_cast(z), static_cast(i), static_cast(j), static_cast(k)); } - FI XYZEval asFloat() const { return LOGICAL_AXIS_ARRAY(static_cast(e), static_cast(x), static_cast(y), static_cast(z), static_cast(i), static_cast(j), static_cast(k)); } - FI XYZEval reciprocal() const { return LOGICAL_AXIS_ARRAY(_RECIP(e), _RECIP(x), _RECIP(y), _RECIP(z), _RECIP(i), _RECIP(j), _RECIP(k)); } + FI constexpr XYZEval copy() const { XYZEval v = *this; return v; } + FI constexpr XYZEval ABS() const { return LOGICAL_AXIS_ARRAY(T(_ABS(e)), T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(i)), T(_ABS(j)), T(_ABS(k)), T(_ABS(u)), T(_ABS(v)), T(_ABS(w))); } + FI constexpr XYZEval asInt() const { return LOGICAL_AXIS_ARRAY(int16_t(e), int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k), int16_t(u), int16_t(v), int16_t(w)); } + FI constexpr XYZEval asLong() const { return LOGICAL_AXIS_ARRAY(int32_t(e), int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k), int32_t(u), int32_t(v), int32_t(w)); } + FI constexpr XYZEval ROUNDL() const { return LOGICAL_AXIS_ARRAY(int32_t(LROUND(e)), int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k)), int32_t(LROUND(u)), int32_t(LROUND(v)), int32_t(LROUND(w))); } + FI constexpr XYZEval asFloat() const { return LOGICAL_AXIS_ARRAY(static_cast(e), static_cast(x), static_cast(y), static_cast(z), static_cast(i), static_cast(j), static_cast(k), static_cast(u), static_cast(v), static_cast(w)); } + FI constexpr XYZEval reciprocal() const { return LOGICAL_AXIS_ARRAY(_RECIP(e), _RECIP(x), _RECIP(y), _RECIP(z), _RECIP(i), _RECIP(j), _RECIP(k), _RECIP(u), _RECIP(v), _RECIP(w)); } // Marlin workspace shifting is done with G92 and M206 - FI XYZEval asLogical() const { XYZEval o = asFloat(); toLogical(o); return o; } - FI XYZEval asNative() const { XYZEval o = asFloat(); toNative(o); return o; } + FI XYZEval asLogical() const { XYZEval o = asFloat(); toLogical(o); return o; } + FI XYZEval asNative() const { XYZEval o = asFloat(); toNative(o); return o; } // In-place cast to types having fewer fields FI operator XYval&() { return *(XYval*)this; } @@ -588,80 +861,375 @@ struct XYZEval { FI operator const XYZval&() const { return *(const XYZval*)this; } // Accessor via an AxisEnum (or any integer) [index] - FI T& operator[](const int n) { return pos[n]; } - FI const T& operator[](const int n) const { return pos[n]; } + FI T& operator[](const int n) { return pos[n]; } + FI const T& operator[](const int n) const { return pos[n]; } // Assignment operator overrides do the expected thing - FI XYZEval& operator= (const T v) { set(LIST_N_1(LINEAR_AXES, v)); return *this; } - FI XYZEval& operator= (const XYval &rs) { set(rs.x, rs.y); return *this; } - FI XYZEval& operator= (const XYZval &rs) { set(LINEAR_AXIS_ELEM(rs)); return *this; } + FI XYZEval& operator= (const T v) { set(LOGICAL_AXIS_LIST_1(v)); return *this; } + FI XYZEval& operator= (const XYval &rs) { set(rs.x, rs.y); return *this; } + FI XYZEval& operator= (const XYZval &rs) { set(NUM_AXIS_ELEM_LC(rs)); return *this; } // Override other operators to get intuitive behaviors - FI XYZEval operator+ (const XYval &rs) const { XYZEval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } - FI XYZEval operator+ (const XYval &rs) { XYZEval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } - FI XYZEval operator- (const XYval &rs) const { XYZEval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } - FI XYZEval operator- (const XYval &rs) { XYZEval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } - FI XYZEval operator* (const XYval &rs) const { XYZEval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } - FI XYZEval operator* (const XYval &rs) { XYZEval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } - FI XYZEval operator/ (const XYval &rs) const { XYZEval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } - FI XYZEval operator/ (const XYval &rs) { XYZEval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } - FI XYZEval operator+ (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } - FI XYZEval operator+ (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } - FI XYZEval operator- (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } - FI XYZEval operator- (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } - FI XYZEval operator* (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } - FI XYZEval operator* (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } - FI XYZEval operator/ (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } - FI XYZEval operator/ (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } - FI XYZEval operator+ (const XYZEval &rs) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e += rs.e, ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } - FI XYZEval operator+ (const XYZEval &rs) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e += rs.e, ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; } - FI XYZEval operator- (const XYZEval &rs) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e -= rs.e, ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } - FI XYZEval operator- (const XYZEval &rs) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e -= rs.e, ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; } - FI XYZEval operator* (const XYZEval &rs) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= rs.e, ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } - FI XYZEval operator* (const XYZEval &rs) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= rs.e, ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; } - FI XYZEval operator/ (const XYZEval &rs) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= rs.e, ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } - FI XYZEval operator/ (const XYZEval &rs) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= rs.e, ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; } - FI XYZEval operator* (const float &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; } - FI XYZEval operator* (const float &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; } - FI XYZEval operator* (const int &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; } - FI XYZEval operator* (const int &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; } - FI XYZEval operator/ (const float &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; } - FI XYZEval operator/ (const float &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; } - FI XYZEval operator/ (const int &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; } - FI XYZEval operator/ (const int &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; } - FI XYZEval operator>>(const int &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(_RS(ls.e), _RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k) ); return ls; } - FI XYZEval operator>>(const int &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(_RS(ls.e), _RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k) ); return ls; } - FI XYZEval operator<<(const int &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(_LS(ls.e), _LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k) ); return ls; } - FI XYZEval operator<<(const int &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(_LS(ls.e), _LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k) ); return ls; } - FI const XYZEval operator-() const { return LOGICAL_AXIS_ARRAY(-e, -x, -y, -z, -i, -j, -k); } - FI XYZEval operator-() { return LOGICAL_AXIS_ARRAY(-e, -x, -y, -z, -i, -j, -k); } + FI constexpr XYZEval operator+ (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, x + rs.x, y + rs.y, z, i, j, k, u, v, w); } + FI constexpr XYZEval operator- (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, x - rs.x, y - rs.y, z, i, j, k, u, v, w); } + FI constexpr XYZEval operator* (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, x * rs.x, y * rs.y, z, i, j, k, u, v, w); } + FI constexpr XYZEval operator/ (const XYval &rs) const { return LOGICAL_AXIS_ARRAY(e, x / rs.x, y / rs.y, z, i, j, k, u, v, w); } + FI constexpr XYZEval operator+ (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(e, x + rs.x, y + rs.y, z + rs.z, i + rs.i, j + rs.j, k + rs.k, u + rs.u, v + rs.v, w + rs.w); } + FI constexpr XYZEval operator- (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(e, x - rs.x, y - rs.y, z - rs.z, i - rs.i, j - rs.j, k - rs.k, u - rs.u, v - rs.v, w - rs.w); } + FI constexpr XYZEval operator* (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(e, x * rs.x, y * rs.y, z * rs.z, i * rs.i, j * rs.j, k * rs.k, u * rs.u, v * rs.v, w * rs.w); } + FI constexpr XYZEval operator/ (const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(e, x / rs.x, y / rs.y, z / rs.z, i / rs.i, j / rs.j, k / rs.k, u / rs.u, v / rs.v, w / rs.w); } + FI constexpr XYZEval operator+ (const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(e + rs.e, x + rs.x, y + rs.y, z + rs.z, i + rs.i, j + rs.j, k + rs.k, u + rs.u, v + rs.v, w + rs.w); } + FI constexpr XYZEval operator- (const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(e - rs.e, x - rs.x, y - rs.y, z - rs.z, i - rs.i, j - rs.j, k - rs.k, u - rs.u, v - rs.v, w - rs.w); } + FI constexpr XYZEval operator* (const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(e * rs.e, x * rs.x, y * rs.y, z * rs.z, i * rs.i, j * rs.j, k * rs.k, u * rs.u, v * rs.v, w * rs.w); } + FI constexpr XYZEval operator/ (const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(e / rs.e, x / rs.x, y / rs.y, z / rs.z, i / rs.i, j / rs.j, k / rs.k, u / rs.u, v / rs.v, w / rs.w); } + FI constexpr XYZEval operator* (const float &p) const { return LOGICAL_AXIS_ARRAY((T)(e * p), (T)(x * p), (T)(y * p), (T)(z * p), (T)(i * p), (T)(j * p), (T)(k * p), (T)(u * p), (T)(v * p), (T)(w * p)); } + FI constexpr XYZEval operator* (const int &p) const { return LOGICAL_AXIS_ARRAY(e * p, x * p, y * p, z * p, i * p, j * p, k * p, u * p, v * p, w * p); } + FI constexpr XYZEval operator/ (const float &p) const { return LOGICAL_AXIS_ARRAY((T)(e / p), (T)(x / p), (T)(y / p), (T)(z / p), (T)(i / p), (T)(j / p), (T)(k / p), (T)(u / p), (T)(v / p), (T)(w / p)); } + FI constexpr XYZEval operator/ (const int &p) const { return LOGICAL_AXIS_ARRAY(e / p, x / p, y / p, z / p, i / p, j / p, k / p, u / p, v / p, w / p); } + FI constexpr XYZEval operator>>(const int &p) const { return LOGICAL_AXIS_ARRAY(_RS(e), _RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k), _RS(u), _RS(v), _RS(w)); } + FI constexpr XYZEval operator<<(const int &p) const { return LOGICAL_AXIS_ARRAY(_LS(e), _LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k), _LS(u), _LS(v), _LS(w)); } + FI constexpr XYZEval operator-() const { return LOGICAL_AXIS_ARRAY(-e, -x, -y, -z, -i, -j, -k, -u, -v, -w); } + + // Absolute difference between two objects + FI constexpr XYZEval diff(const XYZEval &rs) const { return LOGICAL_AXIS_ARRAY(T(_ABS(e - rs.e)), T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), T(_ABS(z - rs.z)), T(_ABS(i - rs.i)), T(_ABS(j - rs.j)), T(_ABS(k - rs.k)), T(_ABS(u - rs.u)), T(_ABS(v - rs.v)), T(_ABS(w - rs.w)) ); } + FI constexpr XYZEval diff(const XYZval &rs) const { return LOGICAL_AXIS_ARRAY(0 , T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), T(_ABS(z - rs.z)), T(_ABS(i - rs.i)), T(_ABS(j - rs.j)), T(_ABS(k - rs.k)), T(_ABS(u - rs.u)), T(_ABS(v - rs.v)), T(_ABS(w - rs.w)) ); } + FI constexpr XYZEval diff(const XYval &rs) const { return LOGICAL_AXIS_ARRAY(0 , T(_ABS(x - rs.x)), T(_ABS(y - rs.y)), z, i, j, k, u, v, w ); } // Modifier operators - FI XYZEval& operator+=(const XYval &rs) { x += rs.x; y += rs.y; return *this; } - FI XYZEval& operator-=(const XYval &rs) { x -= rs.x; y -= rs.y; return *this; } - FI XYZEval& operator*=(const XYval &rs) { x *= rs.x; y *= rs.y; return *this; } - FI XYZEval& operator/=(const XYval &rs) { x /= rs.x; y /= rs.y; return *this; } - FI XYZEval& operator+=(const XYZval &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k); return *this; } - FI XYZEval& operator-=(const XYZval &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k); return *this; } - FI XYZEval& operator*=(const XYZval &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k); return *this; } - FI XYZEval& operator/=(const XYZval &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k); return *this; } - FI XYZEval& operator+=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e += rs.e, x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k); return *this; } - FI XYZEval& operator-=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e -= rs.e, x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k); return *this; } - FI XYZEval& operator*=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e *= rs.e, x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k); return *this; } - FI XYZEval& operator/=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e /= rs.e, x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k); return *this; } - FI XYZEval& operator*=(const T &v) { LOGICAL_AXIS_CODE(e *= v, x *= v, y *= v, z *= v, i *= v, j *= v, k *= v); return *this; } - FI XYZEval& operator>>=(const int &v) { LOGICAL_AXIS_CODE(_RS(e), _RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k)); return *this; } - FI XYZEval& operator<<=(const int &v) { LOGICAL_AXIS_CODE(_LS(e), _LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k)); return *this; } + FI XYZEval& operator+=(const XYval &rs) { XY_CODE(x += rs.x, y += rs.y); return *this; } + FI XYZEval& operator-=(const XYval &rs) { XY_CODE(x -= rs.x, y -= rs.y); return *this; } + FI XYZEval& operator*=(const XYval &rs) { XY_CODE(x *= rs.x, y *= rs.y); return *this; } + FI XYZEval& operator/=(const XYval &rs) { XY_CODE(x /= rs.x, y /= rs.y); return *this; } + FI XYZEval& operator+=(const XYZval &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k, u += rs.u, v += rs.v, w += rs.w); return *this; } + FI XYZEval& operator-=(const XYZval &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k, u -= rs.u, v -= rs.v, w -= rs.w); return *this; } + FI XYZEval& operator*=(const XYZval &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k, u *= rs.u, v *= rs.v, w *= rs.w); return *this; } + FI XYZEval& operator/=(const XYZval &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k, u /= rs.u, v /= rs.v, w /= rs.w); return *this; } + FI XYZEval& operator+=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e += rs.e, x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k, u += rs.u, v += rs.v, w += rs.w); return *this; } + FI XYZEval& operator-=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e -= rs.e, x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k, u -= rs.u, v -= rs.v, w -= rs.w); return *this; } + FI XYZEval& operator*=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e *= rs.e, x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k, u *= rs.u, v *= rs.v, w *= rs.w); return *this; } + FI XYZEval& operator/=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e /= rs.e, x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k, u /= rs.u, v /= rs.v, w /= rs.w); return *this; } + FI XYZEval& operator*=(const T &p) { LOGICAL_AXIS_CODE(e *= p, x *= p, y *= p, z *= p, i *= p, j *= p, k *= p, u *= p, v *= p, w *= p); return *this; } + FI XYZEval& operator>>=(const int &p) { LOGICAL_AXIS_CODE(_RSE(e), _RSE(x), _RSE(y), _RSE(z), _RSE(i), _RSE(j), _RSE(k), _RSE(u), _RSE(v), _RSE(w)); return *this; } + FI XYZEval& operator<<=(const int &p) { LOGICAL_AXIS_CODE(_LSE(e), _LSE(x), _LSE(y), _LSE(z), _LSE(i), _LSE(j), _LSE(k), _LSE(u), _LSE(v), _LSE(w)); return *this; } // Exact comparisons. For floats a "NEAR" operation may be better. - FI bool operator==(const XYZval &rs) { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k); } - FI bool operator==(const XYZval &rs) const { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k); } - FI bool operator!=(const XYZval &rs) { return !operator==(rs); } - FI bool operator!=(const XYZval &rs) const { return !operator==(rs); } + FI bool operator==(const XYZval &rs) const { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); } + FI bool operator==(const XYZEval &rs) const { return true LOGICAL_AXIS_GANG(&& e == rs.e, && x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); } + FI bool operator!=(const XYZval &rs) const { return !operator==(rs); } + FI bool operator!=(const XYZEval &rs) const { return !operator==(rs); } +}; + +#include // for memset + +template +struct XYZarray { + typedef T el[SIZE]; + union { + el data[LOGICAL_AXES]; + struct { NUM_AXIS_CODE(T x, T y, T z, T i, T j, T k, T u, T v, T w); }; + struct { NUM_AXIS_CODE(T X, T Y, T Z, T I, T J, T K, T U, T V, T W); }; + struct { NUM_AXIS_CODE(T a, T b, T c, T _i, T _j, T _k, T _u, T _v, T _w); }; + struct { NUM_AXIS_CODE(T A, T B, T C, T II, T JJ, T KK, T UU, T VV, T WW); }; + }; + FI void reset() { ZERO(data); } + + FI void set(const int n, const XYval p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y,,,,,,,); } + FI void set(const int n, const XYZval p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } + FI void set(const int n, const XYZEval p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } + + // Setter for all individual args + FI void set(const int n OPTARGS_NUM(const T)) { NUM_AXIS_CODE(a[n] = x, b[n] = y, c[n] = z, _i[n] = i, _j[n] = j, _k[n] = k, _u[n] = u, _v[n] = v, _w[n] = w); } + + // Setters with fewer elements leave the rest untouched + #if HAS_Y_AXIS + FI void set(const int n, const T px) { x[n] = px; } + #endif + #if HAS_Z_AXIS + FI void set(const int n, const T px, const T py) { x[n] = px; y[n] = py; } + #endif + #if HAS_I_AXIS + FI void set(const int n, const T px, const T py, const T pz) { x[n] = px; y[n] = py; z[n] = pz; } + #endif + #if HAS_J_AXIS + FI void set(const int n, const T px, const T py, const T pz, const T pi) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; } + #endif + #if HAS_K_AXIS + FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; j[n] = pj; } + #endif + #if HAS_U_AXIS + FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj, const T pk) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; j[n] = pj; k[n] = pk; } + #endif + #if HAS_V_AXIS + FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; j[n] = pj; k[n] = pk; u[n] = pu; } + #endif + #if HAS_W_AXIS + FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu, const T pv) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; j[n] = pj; k[n] = pk; u[n] = pu; v[n] = pv; } + #endif + + FI XYZval operator[](const int n) const { return XYZval(NUM_AXIS_ARRAY(x[n], y[n], z[n], i[n], j[n], k[n], u[n], v[n], w[n])); } +}; + +template +struct XYZEarray { + typedef T el[SIZE]; + union { + el data[LOGICAL_AXES]; + struct { el LOGICAL_AXIS_ARGS(); }; + struct { el LOGICAL_AXIS_ARGS_LC(); }; + struct { el LOGICAL_AXIS_LIST(EE, A, B, C, II, JJ, KK, UU, VV, WW); }; + struct { el LOGICAL_AXIS_LIST(_e, a, b, c, _i, _j, _k, _u, _v, _w); }; + }; + FI void reset() { ZERO(data); } + + FI void set(const int n, const XYval p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y,,,,,,,); } + FI void set(const int n, const XYZval p) { NUM_AXIS_CODE(x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } + FI void set(const int n, const XYZEval p) { LOGICAL_AXIS_CODE(e[n]=p.e, x[n]=p.x, y[n]=p.y, z[n]=p.z, i[n]=p.i, j[n]=p.j, k[n]=p.k, u[n]=p.u, v[n]=p.v, w[n]=p.w ); } + + // Setter for all individual args + FI void set(const int n OPTARGS_NUM(const T)) { NUM_AXIS_CODE(a[n] = x, b[n] = y, c[n] = z, _i[n] = i, _j[n] = j, _k[n] = k, _u[n] = u, _v[n] = v, _w[n] = w); } + #if LOGICAL_AXES > NUM_AXES + FI void set(const int n, LOGICAL_AXIS_ARGS_LC(const T)) { LOGICAL_AXIS_CODE(_e[n] = e, a[n] = x, b[n] = y, c[n] = z, _i[n] = i, _j[n] = j, _k[n] = k, _u[n] = u, _v[n] = v, _w[n] = w); } + #endif + + // Setters with fewer elements leave the rest untouched + #if HAS_Y_AXIS + FI void set(const int n, const T px) { x[n] = px; } + #endif + #if HAS_Z_AXIS + FI void set(const int n, const T px, const T py) { x[n] = px; y[n] = py; } + #endif + #if HAS_I_AXIS + FI void set(const int n, const T px, const T py, const T pz) { x[n] = px; y[n] = py; z[n] = pz; } + #endif + #if HAS_J_AXIS + FI void set(const int n, const T px, const T py, const T pz, const T pi) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; } + #endif + #if HAS_K_AXIS + FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; j[n] = pj; } + #endif + #if HAS_U_AXIS + FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj, const T pk) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; j[n] = pj; k[n] = pk; } + #endif + #if HAS_V_AXIS + FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; j[n] = pj; k[n] = pk; u[n] = pu; } + #endif + #if HAS_W_AXIS + FI void set(const int n, const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pu, const T pv) { x[n] = px; y[n] = py; z[n] = pz; i[n] = pi; j[n] = pj; k[n] = pk; u[n] = pu; v[n] = pv; } + #endif + + FI XYZEval operator[](const int n) const { return XYZval(LOGICAL_AXIS_ARRAY(e[n], x[n], y[n], z[n], i[n], j[n], k[n], u[n], v[n], w[n])); } +}; + +class AxisBits; + +class AxisBits { +public: + typedef bits_t(NUM_AXIS_HEADS) el; + union { + el bits; + // Axes x, y, z ... e0, e1, e2 ... hx, hy, hz + struct { + #if NUM_AXES + bool NUM_AXIS_LIST(x:1, y:1, z:1, i:1, j:1, k:1, u:1, v:1, w:1); + #endif + #define _EN_ITEM(N) bool e##N:1; + REPEAT(EXTRUDERS,_EN_ITEM) + #undef _EN_ITEM + #if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX) + bool hx:1, hy:1, hz:1; + #endif + }; + // Axes X, Y, Z ... E0, E1, E2 ... HX, HY, HZ + struct { + #if NUM_AXES + bool NUM_AXIS_LIST(X:1, Y:1, Z:1, I:1, J:1, K:1, U:1, V:1, W:1); + #endif + #define _EN_ITEM(N) bool E##N:1; + REPEAT(EXTRUDERS,_EN_ITEM) + #undef _EN_ITEM + #if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX) + bool HX:1, HY:1, HZ:1; + #endif + }; + // a, b, c, e ... ha, hb, hc + struct { + bool LOGICAL_AXIS_LIST(e:1, a:1, b:1, c:1, ii:1, jj:1, kk:1, uu:1, vv:1, ww:1); + #if EXTRUDERS > 1 + #define _EN_ITEM(N) bool _e##N:1; + REPEAT_S(1,EXTRUDERS,_EN_ITEM) + #undef _EN_ITEM + #endif + #if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX) + bool ha:1, hb:1, hc:1; + #endif + }; + // A, B, C, E ... HA, HB, HC + struct { + bool LOGICAL_AXIS_LIST(E:1, A:1, B:1, C:1, II:1, JJ:1, KK:1, UU:1, VV:1, WW:1); + #if EXTRUDERS > 1 + #define _EN_ITEM(N) bool _E##N:1; + REPEAT_S(1,EXTRUDERS,_EN_ITEM) + #undef _EN_ITEM + #endif + #if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX) + bool HA:1, HB:1, HC:1; + #endif + }; + }; + + class BitProxy { + public: + BitProxy(el& data, int bit) : data_(data), bit_(bit) {} + + BitProxy& operator=(const bool value) { + if (value) + data_ |= (el(1) << bit_); + else + data_ &= ~(el(1) << bit_); + return *this; + } + + operator bool() const { return bool(data_ & (el(1) << bit_)); } + + private: + el& data_; + uint8_t bit_; + }; + + AxisBits() { reset(); } + + // Constructor, setter, and operator= for bit mask + AxisBits(const el p) { set(p); } + FI void set(const el p) { bits = el(p); } + FI AxisBits& operator=(const el p) { set(p); return *this; } + + FI void reset() { set(0); } + FI void fill() { set(_BV(NUM_AXIS_HEADS) - 1); } + + #define MSET(pE,pX,pY,pZ,pI,pJ,pK,pU,pV,pW) LOGICAL_AXIS_CODE(e=pE, x=pX, y=pY, z=pZ, i=pI, j=pJ, k=pK, u=pU, v=pV, w=pW) + + // Constructor, setter, and operator= for XYZE type + AxisBits(const xyze_bool_t &p) { set(p); } + FI void set(const xyze_bool_t &p) { + MSET(p.e, p.x, p.y, p.z, p.i, p.j, p.k, p.u, p.v, p.w); + } + FI AxisBits& operator=(const xyze_bool_t &p) { set(p); return *this; } + + // Constructor, setter, and operator= for bool array + AxisBits(const bool (&p)[LOGICAL_AXES]) { set(p); } + FI void set(const bool (&p)[LOGICAL_AXES]) { + MSET(p[E_AXIS], p[X_AXIS], p[Y_AXIS], p[Z_AXIS], + p[I_AXIS], p[J_AXIS], p[K_AXIS], + p[U_AXIS], p[V_AXIS], p[W_AXIS]); + } + FI AxisBits& operator=(const bool (&p)[LOGICAL_AXES]) { set(p); return *this; } + + // Constructor, setter, and operator= for undersized bool arrays + #if LOGICAL_AXES > 1 + AxisBits(const bool (&p)[1]) { set(p); } + FI void set(const bool (&p)[1]) { + MSET(0, p[X_AXIS], 0, 0, 0, 0, 0, 0, 0, 0); + } + FI AxisBits& operator=(const bool (&p)[1]) { set(p); return *this; } + #endif + #if LOGICAL_AXES > 2 + AxisBits(const bool (&p)[2]) { set(p); } + FI void set(const bool (&p)[2]) { + MSET(0, p[X_AXIS], p[Y_AXIS], 0, 0, 0, 0, 0, 0, 0); + } + FI AxisBits& operator=(const bool (&p)[2]) { set(p); return *this; } + #endif + #if LOGICAL_AXES > 3 + AxisBits(const bool (&p)[3]) { set(p); } + FI void set(const bool (&p)[3]) { + MSET(0, p[X_AXIS], p[Y_AXIS], p[Z_AXIS], 0, 0, 0, 0, 0, 0); + } + FI AxisBits& operator=(const bool (&p)[3]) { set(p); return *this; } + #endif + #if LOGICAL_AXES > 4 + AxisBits(const bool (&p)[4]) { set(p); } + FI void set(const bool (&p)[4]) { + MSET(0, p[X_AXIS], p[Y_AXIS], p[Z_AXIS], p[I_AXIS], 0, 0, 0, 0, 0); + } + FI AxisBits& operator=(const bool (&p)[4]) { set(p); return *this; } + #endif + #if LOGICAL_AXES > 5 + AxisBits(const bool (&p)[5]) { set(p); } + FI void set(const bool (&p)[5]) { + MSET(0, p[X_AXIS], p[Y_AXIS], p[Z_AXIS], p[I_AXIS], p[J_AXIS], 0, 0, 0, 0); + } + FI AxisBits& operator=(const bool (&p)[5]) { set(p); return *this; } + #endif + #if LOGICAL_AXES > 6 + AxisBits(const bool (&p)[6]) { set(p); } + FI void set(const bool (&p)[6]) { + MSET(0, p[X_AXIS], p[Y_AXIS], p[Z_AXIS], p[I_AXIS], p[J_AXIS], p[K_AXIS], 0, 0, 0); + } + FI AxisBits& operator=(const bool (&p)[6]) { set(p); return *this; } + #endif + #if LOGICAL_AXES > 7 + AxisBits(const bool (&p)[7]) { set(p); } + FI void set(const bool (&p)[7]) { + MSET(0, p[X_AXIS], p[Y_AXIS], p[Z_AXIS], p[I_AXIS], p[J_AXIS], p[K_AXIS], p[U_AXIS], 0, 0); + } + FI AxisBits& operator=(const bool (&p)[7]) { set(p); return *this; } + #endif + #if LOGICAL_AXES > 8 + AxisBits(const bool (&p)[8]) { set(p); } + FI void set(const bool (&p)[8]) { + MSET(0, p[X_AXIS], p[Y_AXIS], p[Z_AXIS], p[I_AXIS], p[J_AXIS], p[K_AXIS], p[U_AXIS], p[V_AXIS], 0); + } + FI AxisBits& operator=(const bool (&p)[8]) { set(p); return *this; } + #endif + #if LOGICAL_AXES > 9 + AxisBits(const bool (&p)[9]) { set(p); } + FI void set(const bool (&p)[9]) { + MSET(0, p[X_AXIS], p[Y_AXIS], p[Z_AXIS], p[I_AXIS], p[J_AXIS], p[K_AXIS], p[U_AXIS], p[V_AXIS], p[W_AXIS]); + } + FI AxisBits& operator=(const bool (&p)[9]) { set(p); return *this; } + #endif + #undef MSET + + FI bool toggle(const AxisEnum n) { TBI(bits, n); return TEST(bits, n); } + FI void bset(const AxisEnum n) { SBI(bits, n); } + FI void bclr(const AxisEnum n) { CBI(bits, n); } + FI void bset(const AxisEnum n, const bool b) { if (b) bset(n); else bclr(n); } + + // Accessor via an AxisEnum (or any integer) [index] + FI BitProxy operator[](const int n) { return BitProxy(bits, n); } + FI BitProxy operator[](const AxisEnum n) { return BitProxy(bits, n); } + FI bool operator[](const int n) const { return TEST(bits, n); } + FI bool operator[](const AxisEnum n) const { return TEST(bits, n); } + + FI AxisBits& operator|=(const el &p) { bits |= el(p); return *this; } + FI AxisBits& operator&=(const el &p) { bits &= el(p); return *this; } + FI AxisBits& operator^=(const el &p) { bits ^= el(p); return *this; } + + FI AxisBits& operator|=(const AxisBits &p) { bits |= p.bits; return *this; } + FI AxisBits& operator&=(const AxisBits &p) { bits &= p.bits; return *this; } + FI AxisBits& operator^=(const AxisBits &p) { bits ^= p.bits; return *this; } + + FI bool operator==(const AxisBits &p) const { return p.bits == bits; } + FI bool operator!=(const AxisBits &p) const { return p.bits != bits; } + + FI el operator|(const el &p) const { return bits | el(p); } + FI el operator&(const el &p) const { return bits & el(p); } + FI el operator^(const el &p) const { return bits ^ el(p); } + + FI AxisBits operator|(const AxisBits &p) const { return AxisBits(bits | p.bits); } + FI AxisBits operator&(const AxisBits &p) const { return AxisBits(bits & p.bits); } + FI AxisBits operator^(const AxisBits &p) const { return AxisBits(bits ^ p.bits); } + + FI operator bool() const { return !!bits; } + FI operator uint16_t() const { return uint16_t(bits & 0xFFFF); } + FI operator uint32_t() const { return uint32_t(bits); } + }; #undef _RECIP #undef _ABS #undef _LS #undef _RS +#undef _LSE +#undef _RSE #undef FI diff --git a/Marlin/src/core/utility.cpp b/Marlin/src/core/utility.cpp index cc3b1ace..f1e84135 100644 --- a/Marlin/src/core/utility.cpp +++ b/Marlin/src/core/utility.cpp @@ -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,30 +51,40 @@ 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" void log_machine_info() { - SERIAL_ECHOLNPGM("Machine Type: " - TERN_(DELTA, "Delta") - TERN_(IS_SCARA, "SCARA") - TERN_(IS_CORE, "Core") - TERN_(MARKFORGED_XY, "MarkForgedXY") - TERN_(MARKFORGED_YX, "MarkForgedYX") - TERN_(IS_CARTESIAN, "Cartesian") + SERIAL_ECHOLNPGM("Machine Type:" + TERN_(DELTA, " Delta") + TERN_(IS_SCARA, " SCARA") + TERN_(AXEL_TPARA, " TPARA") + TERN_(IS_CORE, " Core") + TERN_(BELTPRINTER, " Belt Printer") + TERN_(MARKFORGED_XY, " MarkForgedXY") + TERN_(MARKFORGED_YX, " MarkForgedYX") + TERN_(POLARGRAPH, " Polargraph") + TERN_(ARTICULATED_ROBOT_ARM, " Robot Arm") + TERN_(FOAMCUTTER_XYUV, " Foam Cutter") + TERN_(IS_CARTESIAN, " Cartesian") ); SERIAL_ECHOLNPGM("Probe: " - TERN_(PROBE_MANUALLY, "PROBE_MANUALLY") - TERN_(NOZZLE_AS_PROBE, "NOZZLE_AS_PROBE") - TERN_(FIX_MOUNTED_PROBE, "FIX_MOUNTED_PROBE") - TERN_(HAS_Z_SERVO_PROBE, TERN(BLTOUCH, "BLTOUCH", "SERVO PROBE")) - TERN_(TOUCH_MI_PROBE, "TOUCH_MI_PROBE") - TERN_(Z_PROBE_SLED, "Z_PROBE_SLED") - TERN_(Z_PROBE_ALLEN_KEY, "Z_PROBE_ALLEN_KEY") - TERN_(SOLENOID_PROBE, "SOLENOID_PROBE") - TERN(PROBE_SELECTED, "", "NONE") + TERN_(PROBE_MANUALLY, "PROBE_MANUALLY") + TERN_(NOZZLE_AS_PROBE, "NOZZLE_AS_PROBE") + TERN_(FIX_MOUNTED_PROBE, "FIX_MOUNTED_PROBE") + TERN_(HAS_Z_SERVO_PROBE, TERN(BLTOUCH, "BLTOUCH", "SERVO PROBE")) + TERN_(BD_SENSOR, "BD_SENSOR") + TERN_(TOUCH_MI_PROBE, "TOUCH_MI_PROBE") + TERN_(Z_PROBE_ALLEN_KEY, "Z_PROBE_ALLEN_KEY") + TERN_(Z_PROBE_SLED, "Z_PROBE_SLED") + TERN_(RACK_AND_PINION_PROBE, "RACK_AND_PINION_PROBE") + TERN_(SOLENOID_PROBE, "SOLENOID_PROBE") + TERN_(SENSORLESS_PROBING, "SENSORLESS_PROBING") + TERN_(MAGLEV4, "MAGLEV4") + TERN_(MAG_MOUNTED_PROBE, "MAG_MOUNTED_PROBE") + IF_DISABLED(PROBE_SELECTED, "NONE") ); #if HAS_BED_PROBE @@ -124,20 +134,17 @@ void safe_delay(millis_t ms) { #endif #if ABL_PLANAR SERIAL_ECHOPGM("ABL Adjustment"); - LOOP_LINEAR_AXES(a) { - const float v = planner.get_axis_position_mm(AxisEnum(a)) - current_position[a]; - SERIAL_CHAR(' ', AXIS_CHAR(a)); - if (v > 0) SERIAL_CHAR('+'); - SERIAL_DECIMAL(v); + LOOP_NUM_AXES(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 = ubl.get_z_correction(current_position); #elif ENABLED(AUTO_BED_LEVELING_BILINEAR) SERIAL_ECHOPGM("ABL Adjustment Z"); - const float rz = bilinear_z_offset(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) { @@ -157,11 +164,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(mbl.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( - mbl.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(')'); } diff --git a/Marlin/src/core/utility.h b/Marlin/src/core/utility.h index d248091c..0d8416ac 100644 --- a/Marlin/src/core/utility.h +++ b/Marlin/src/core/utility.h @@ -33,17 +33,17 @@ void safe_delay(millis_t ms); // Delay ensuring that temperatures are inline void serial_delay(const millis_t) {} #endif -#if (GRID_MAX_POINTS_X) && (GRID_MAX_POINTS_Y) +#if GRID_MAX_POINTS // 16x16 bit arrays template struct FlagBits { - typename IF<(W>8), uint16_t, uint8_t>::type bits[H]; - void fill() { memset(bits, 0xFF, sizeof(bits)); } - void reset() { memset(bits, 0x00, sizeof(bits)); } - void unmark(const uint8_t x, const uint8_t y) { CBI(bits[y], x); } - void mark(const uint8_t x, const uint8_t y) { SBI(bits[y], x); } - bool marked(const uint8_t x, const uint8_t y) { return TEST(bits[y], x); } + bits_t(W) flags[H]; + void fill() { memset(flags, 0xFF, sizeof(flags)); } + void reset() { memset(flags, 0x00, sizeof(flags)); } + void unmark(const uint8_t x, const uint8_t y) { CBI(flags[y], x); } + void mark(const uint8_t x, const uint8_t y) { SBI(flags[y], x); } + bool marked(const uint8_t x, const uint8_t y) { return TEST(flags[y], x); } inline void unmark(const xy_int8_t &xy) { unmark(xy.x, xy.y); } inline void mark(const xy_int8_t &xy) { mark(xy.x, xy.y); } inline bool marked(const xy_int8_t &xy) { return marked(xy.x, xy.y); } @@ -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 class restorer { T& ref_; @@ -77,10 +82,13 @@ class restorer { // 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; } -const xyze_char_t axis_codes LOGICAL_AXIS_ARRAY('E', 'X', 'Y', 'Z', AXIS4_NAME, AXIS5_NAME, AXIS6_NAME); - -#if LINEAR_AXES <= XYZ +// 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, AXIS7_NAME, AXIS8_NAME, AXIS9_NAME); +#if NUM_AXES <= XYZ && !HAS_EXTRUDERS #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', 'U', 'V', 'W'); #define AXIS_CHAR(A) axis_codes[A] + #define IAXIS_CHAR(A) iaxis_codes[A] #endif diff --git a/Marlin/src/feature/adc/adc_mcp3426.cpp b/Marlin/src/feature/adc/adc_mcp3426.cpp index aaddf468..49bb67ef 100644 --- a/Marlin/src/feature/adc/adc_mcp3426.cpp +++ b/Marlin/src/feature/adc/adc_mcp3426.cpp @@ -34,7 +34,7 @@ #include "adc_mcp3426.h" // Read the ADC value from MCP342X on a specific channel -int16_t MCP3426::ReadValue(uint8_t channel, uint8_t gain) { +int16_t MCP3426::ReadValue(uint8_t channel, uint8_t gain, uint8_t address) { Error = false; #if PINS_EXIST(I2C_SCL, I2C_SDA) && DISABLED(SOFT_I2C_EEPROM) @@ -44,7 +44,7 @@ int16_t MCP3426::ReadValue(uint8_t channel, uint8_t gain) { Wire.begin(); // No address joins the BUS as the master - Wire.beginTransmission(I2C_ADDRESS(MCP342X_ADC_I2C_ADDRESS)); + Wire.beginTransmission(I2C_ADDRESS(address)); // Continuous Conversion Mode, 16 bit, Channel 1, Gain x4 // 26 = 0b00011000 @@ -75,7 +75,7 @@ int16_t MCP3426::ReadValue(uint8_t channel, uint8_t gain) { uint8_t buffer[len] = {}; do { - Wire.requestFrom(I2C_ADDRESS(MCP342X_ADC_I2C_ADDRESS), len); + Wire.requestFrom(I2C_ADDRESS(address), len); if (Wire.available() != len) { Error = true; return 0; diff --git a/Marlin/src/feature/adc/adc_mcp3426.h b/Marlin/src/feature/adc/adc_mcp3426.h index 35458716..af485933 100644 --- a/Marlin/src/feature/adc/adc_mcp3426.h +++ b/Marlin/src/feature/adc/adc_mcp3426.h @@ -29,12 +29,9 @@ #include #include -// Address of MCP342X chip -#define MCP342X_ADC_I2C_ADDRESS 104 - class MCP3426 { public: - int16_t ReadValue(uint8_t channel, uint8_t gain); + int16_t ReadValue(uint8_t channel, uint8_t gain, uint8_t address); bool Error; }; diff --git a/Marlin/src/feature/babystep.cpp b/Marlin/src/feature/babystep.cpp index 54ad9588..2e3d6a9f 100644 --- a/Marlin/src/feature/babystep.cpp +++ b/Marlin/src/feature/babystep.cpp @@ -54,6 +54,18 @@ void Babystep::add_mm(const AxisEnum axis, const_float_t mm) { add_steps(axis, mm * planner.settings.axis_steps_per_mm[axis]); } +#if ENABLED(BD_SENSOR) + void Babystep::set_mm(const AxisEnum axis, const_float_t mm) { + //if (DISABLED(BABYSTEP_WITHOUT_HOMING) && axes_should_home(_BV(axis))) return; + const int16_t distance = mm * planner.settings.axis_steps_per_mm[axis]; + accum = distance; // Count up babysteps for the UI + steps[BS_AXIS_IND(axis)] = distance; + TERN_(BABYSTEP_DISPLAY_TOTAL, axis_total[BS_TOTAL_IND(axis)] = distance); + TERN_(BABYSTEP_ALWAYS_AVAILABLE, gcode.reset_stepper_timeout()); + TERN_(INTEGRATED_BABYSTEPPING, if (has_steps()) stepper.initiateBabystepping()); + } +#endif + void Babystep::add_steps(const AxisEnum axis, const int16_t distance) { if (DISABLED(BABYSTEP_WITHOUT_HOMING) && axes_should_home(_BV(axis))) return; diff --git a/Marlin/src/feature/babystep.h b/Marlin/src/feature/babystep.h index f8037678..32e13755 100644 --- a/Marlin/src/feature/babystep.h +++ b/Marlin/src/feature/babystep.h @@ -31,7 +31,7 @@ #define BABYSTEP_TICKS ((TEMP_TIMER_RATE) / (BABYSTEPS_PER_SEC)) #endif -#if IS_CORE || EITHER(BABYSTEP_XY, I2C_POSITION_ENCODERS) +#if ANY(IS_CORE, BABYSTEP_XY, I2C_POSITION_ENCODERS) #define BS_AXIS_IND(A) A #define BS_AXIS(I) AxisEnum(I) #else @@ -54,7 +54,7 @@ class Babystep { #if ENABLED(BABYSTEP_DISPLAY_TOTAL) static int16_t axis_total[BS_TOTAL_IND(Z_AXIS) + 1]; // Total babysteps since G28 - static inline void reset_total(const AxisEnum axis) { + static void reset_total(const AxisEnum axis) { if (TERN1(BABYSTEP_XY, axis == Z_AXIS)) axis_total[BS_TOTAL_IND(axis)] = 0; } @@ -63,7 +63,11 @@ class Babystep { static void add_steps(const AxisEnum axis, const int16_t distance); static void add_mm(const AxisEnum axis, const_float_t mm); - static inline bool has_steps() { + #if ENABLED(BD_SENSOR) + static void set_mm(const AxisEnum axis, const_float_t mm); + #endif + + static bool has_steps() { return steps[BS_AXIS_IND(X_AXIS)] || steps[BS_AXIS_IND(Y_AXIS)] || steps[BS_AXIS_IND(Z_AXIS)]; } @@ -71,8 +75,8 @@ class Babystep { // Called by the Temperature or Stepper ISR to // apply accumulated babysteps to the axes. // - static inline void task() { - LOOP_LE_N(i, BS_AXIS_IND(Z_AXIS)) step_axis(BS_AXIS(i)); + static void task() { + for (uint8_t i = 0; i <= BS_AXIS_IND(Z_AXIS); ++i) step_axis(BS_AXIS(i)); } private: diff --git a/Marlin/src/feature/backlash.cpp b/Marlin/src/feature/backlash.cpp index 24c0f2ca..2aa78e6c 100644 --- a/Marlin/src/feature/backlash.cpp +++ b/Marlin/src/feature/backlash.cpp @@ -29,6 +29,9 @@ #include "../module/motion.h" #include "../module/planner.h" +axis_bits_t Backlash::last_direction_bits; +xyz_long_t Backlash::residual_error{0}; + #ifdef BACKLASH_DISTANCE_MM #if ENABLED(BACKLASH_GCODE) xyz_float_t Backlash::distance_mm = BACKLASH_DISTANCE_MM; @@ -38,7 +41,7 @@ #endif #if ENABLED(BACKLASH_GCODE) - uint8_t Backlash::correction = (BACKLASH_CORRECTION) * 0xFF; + uint8_t Backlash::correction = (BACKLASH_CORRECTION) * all_on; #ifdef BACKLASH_SMOOTHING_MM float Backlash::smoothing_mm = BACKLASH_SMOOTHING_MM; #endif @@ -61,10 +64,9 @@ Backlash backlash; */ void Backlash::add_correction_steps(const int32_t &da, const int32_t &db, const int32_t &dc, const axis_bits_t dm, block_t * const block) { - static axis_bits_t last_direction_bits; axis_bits_t changed_dir = last_direction_bits ^ dm; // Ignore direction change unless steps are taken in that direction - #if DISABLED(CORE_BACKLASH) || EITHER(MARKFORGED_XY, MARKFORGED_YX) + #if DISABLED(CORE_BACKLASH) || ANY(MARKFORGED_XY, MARKFORGED_YX) if (!da) CBI(changed_dir, X_AXIS); if (!db) CBI(changed_dir, Y_AXIS); if (!dc) CBI(changed_dir, Z_AXIS); @@ -83,7 +85,7 @@ void Backlash::add_correction_steps(const int32_t &da, const int32_t &db, const #endif last_direction_bits ^= changed_dir; - if (correction == 0) return; + if (!correction && !residual_error) return; #ifdef BACKLASH_SMOOTHING_MM // The segment proportion is a value greater than 0.0 indicating how much residual_error @@ -91,39 +93,28 @@ void Backlash::add_correction_steps(const int32_t &da, const int32_t &db, const // smoothing distance. Since the computation of this proportion involves a floating point // division, defer computation until needed. float segment_proportion = 0; - - // Residual error carried forward across multiple segments, so correction can be applied - // to segments where there is no direction change. - static xyz_long_t residual_error{0}; - #else - // No direction change, no correction. - if (!changed_dir) return; - // No leftover residual error from segment to segment - xyz_long_t residual_error{0}; #endif - const float f_corr = float(correction) / 255.0f; + const float f_corr = float(correction) / all_on; - LOOP_LINEAR_AXES(axis) { + LOOP_NUM_AXES(axis) { if (distance_mm[axis]) { - const bool reversing = TEST(dm,axis); + const bool reverse = TEST(dm, axis); // When an axis changes direction, add axis backlash to the residual error if (TEST(changed_dir, axis)) - residual_error[axis] += (reversing ? -f_corr : f_corr) * distance_mm[axis] * planner.settings.axis_steps_per_mm[axis]; + residual_error[axis] += (reverse ? -f_corr : f_corr) * distance_mm[axis] * planner.settings.axis_steps_per_mm[axis]; // Decide how much of the residual error to correct in this segment int32_t error_correction = residual_error[axis]; + if (reverse != (error_correction < 0)) + error_correction = 0; // Don't take up any backlash in this segment, as it would subtract steps + #ifdef BACKLASH_SMOOTHING_MM if (error_correction && smoothing_mm != 0) { - // Take up a portion of the residual_error in this segment, but only when - // the current segment travels in the same direction as the correction - if (reversing == (error_correction < 0)) { - if (segment_proportion == 0) segment_proportion = _MIN(1.0f, block->millimeters / smoothing_mm); - error_correction = CEIL(segment_proportion * error_correction); - } - else - error_correction = 0; // Don't take up any backlash in this segment, as it would subtract steps + // Take up a portion of the residual_error in this segment + if (segment_proportion == 0) segment_proportion = _MIN(1.0f, block->millimeters / smoothing_mm); + error_correction = CEIL(segment_proportion * error_correction); } #endif @@ -153,6 +144,57 @@ void Backlash::add_correction_steps(const int32_t &da, const int32_t &db, const } } +int32_t Backlash::get_applied_steps(const AxisEnum axis) { + if (axis >= NUM_AXES) return 0; + + const bool reverse = TEST(last_direction_bits, axis); + + const int32_t residual_error_axis = residual_error[axis]; + + // At startup it is assumed the last move was forwards. So the applied + // steps will always be a non-positive number. + + if (!reverse) return -residual_error_axis; + + const float f_corr = float(correction) / all_on; + const int32_t full_error_axis = -f_corr * distance_mm[axis] * planner.settings.axis_steps_per_mm[axis]; + return full_error_axis - residual_error_axis; +} + +class Backlash::StepAdjuster { + private: + xyz_long_t applied_steps; + public: + StepAdjuster() { + LOOP_NUM_AXES(axis) applied_steps[axis] = backlash.get_applied_steps((AxisEnum)axis); + } + ~StepAdjuster() { + // after backlash compensation parameter changes, ensure applied step count does not change + LOOP_NUM_AXES(axis) residual_error[axis] += backlash.get_applied_steps((AxisEnum)axis) - applied_steps[axis]; + } +}; + +#if ENABLED(BACKLASH_GCODE) + + void Backlash::set_correction_uint8(const uint8_t v) { + StepAdjuster adjuster; + correction = v; + } + + void Backlash::set_distance_mm(const AxisEnum axis, const float v) { + StepAdjuster adjuster; + distance_mm[axis] = v; + } + + #ifdef BACKLASH_SMOOTHING_MM + void Backlash::set_smoothing_mm(const float v) { + StepAdjuster adjuster; + smoothing_mm = v; + } + #endif + +#endif + #if ENABLED(MEASURE_BACKLASH_WHEN_PROBING) #include "../module/probe.h" diff --git a/Marlin/src/feature/backlash.h b/Marlin/src/feature/backlash.h index 4d4e2940..0bace526 100644 --- a/Marlin/src/feature/backlash.h +++ b/Marlin/src/feature/backlash.h @@ -24,21 +24,22 @@ #include "../inc/MarlinConfigPre.h" #include "../module/planner.h" -constexpr uint8_t all_on = 0xFF, all_off = 0x00; - class Backlash { public: + static constexpr uint8_t all_on = 0xFF, all_off = 0x00; + +private: + static axis_bits_t last_direction_bits; + static xyz_long_t residual_error; + #if ENABLED(BACKLASH_GCODE) - static xyz_float_t distance_mm; static uint8_t correction; + static xyz_float_t distance_mm; #ifdef BACKLASH_SMOOTHING_MM static float smoothing_mm; #endif - - static inline void set_correction(const_float_t v) { correction = _MAX(0, _MIN(1.0, v)) * all_on; } - static inline float get_correction() { return float(ui8_to_percent(correction)) / 100.0f; } #else - static constexpr uint8_t correction = (BACKLASH_CORRECTION) * 0xFF; + static constexpr uint8_t correction = (BACKLASH_CORRECTION) * all_on; static const xyz_float_t distance_mm; #ifdef BACKLASH_SMOOTHING_MM static constexpr float smoothing_mm = BACKLASH_SMOOTHING_MM; @@ -46,14 +47,14 @@ class Backlash { #endif #if ENABLED(MEASURE_BACKLASH_WHEN_PROBING) - private: - static xyz_float_t measured_mm; - static xyz_uint8_t measured_count; - public: - static void measure_with_probe(); + static xyz_float_t measured_mm; + static xyz_uint8_t measured_count; #endif - static inline float get_measurement(const AxisEnum a) { + class StepAdjuster; + +public: + static float get_measurement(const AxisEnum a) { UNUSED(a); // Return the measurement averaged over all readings return TERN(MEASURE_BACKLASH_WHEN_PROBING @@ -62,16 +63,34 @@ class Backlash { ); } - static inline bool has_measurement(const AxisEnum a) { + static bool has_measurement(const AxisEnum a) { UNUSED(a); return TERN0(MEASURE_BACKLASH_WHEN_PROBING, measured_count[a] > 0); } - static inline bool has_any_measurement() { + static bool has_any_measurement() { return has_measurement(X_AXIS) || has_measurement(Y_AXIS) || has_measurement(Z_AXIS); } - void add_correction_steps(const int32_t &da, const int32_t &db, const int32_t &dc, const axis_bits_t dm, block_t * const block); + static void add_correction_steps(const int32_t &da, const int32_t &db, const int32_t &dc, const axis_bits_t dm, block_t * const block); + static int32_t get_applied_steps(const AxisEnum axis); + + #if ENABLED(BACKLASH_GCODE) + static void set_correction_uint8(const uint8_t v); + static uint8_t get_correction_uint8() { return correction; } + static void set_correction(const float v) { set_correction_uint8(_MAX(0, _MIN(1.0, v)) * all_on + 0.5f); } + static float get_correction() { return float(get_correction_uint8()) / all_on; } + static void set_distance_mm(const AxisEnum axis, const float v); + static float get_distance_mm(const AxisEnum axis) {return distance_mm[axis];} + #ifdef BACKLASH_SMOOTHING_MM + static void set_smoothing_mm(const float v); + static float get_smoothing_mm() {return smoothing_mm;} + #endif + #endif + + #if ENABLED(MEASURE_BACKLASH_WHEN_PROBING) + static void measure_with_probe(); + #endif }; extern Backlash backlash; diff --git a/Marlin/src/feature/bedlevel/abl/abl.h b/Marlin/src/feature/bedlevel/abl/abl.h deleted file mode 100644 index 3d54c556..00000000 --- a/Marlin/src/feature/bedlevel/abl/abl.h +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * - * Based on Sprinter and grbl. - * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -#pragma once - -#include "../../../inc/MarlinConfigPre.h" - -extern xy_pos_t bilinear_grid_spacing, bilinear_start; -extern xy_float_t bilinear_grid_factor; -extern bed_mesh_t z_values; -float bilinear_z_offset(const xy_pos_t &raw); - -void extrapolate_unprobed_bed_level(); -void print_bilinear_leveling_grid(); -void refresh_bed_level(); -#if ENABLED(ABL_BILINEAR_SUBDIVISION) - void print_bilinear_leveling_grid_virt(); - void bed_level_virt_interpolate(); -#endif - -#if IS_CARTESIAN && DISABLED(SEGMENT_LEVELED_MOVES) - void bilinear_line_to_destination(const_feedRate_t scaled_fr_mm_s, uint16_t x_splits=0xFFFF, uint16_t y_splits=0xFFFF); -#endif - -#define _GET_MESH_X(I) float(bilinear_start.x + (I) * bilinear_grid_spacing.x) -#define _GET_MESH_Y(J) float(bilinear_start.y + (J) * bilinear_grid_spacing.y) -#define Z_VALUES_ARR z_values diff --git a/Marlin/src/feature/bedlevel/abl/abl.cpp b/Marlin/src/feature/bedlevel/abl/bbl.cpp similarity index 72% rename from Marlin/src/feature/bedlevel/abl/abl.cpp rename to Marlin/src/feature/bedlevel/abl/bbl.cpp index ece74819..14c4bd24 100644 --- a/Marlin/src/feature/bedlevel/abl/abl.cpp +++ b/Marlin/src/feature/bedlevel/abl/bbl.cpp @@ -35,14 +35,19 @@ #include "../../../lcd/extui/ui_api.h" #endif -xy_pos_t bilinear_grid_spacing, bilinear_start; -xy_float_t bilinear_grid_factor; -bed_mesh_t z_values; +LevelingBilinear bedlevel; + +xy_pos_t LevelingBilinear::grid_spacing, + LevelingBilinear::grid_start; +xy_float_t LevelingBilinear::grid_factor; +bed_mesh_t LevelingBilinear::z_values; +xy_pos_t LevelingBilinear::cached_rel; +xy_int8_t LevelingBilinear::cached_g; /** * Extrapolate a single point from its neighbors */ -static void extrapolate_one_point(const uint8_t x, const uint8_t y, const int8_t xdir, const int8_t ydir) { +void LevelingBilinear::extrapolate_one_point(const uint8_t x, const uint8_t y, const int8_t xdir, const int8_t ydir) { if (!isnan(z_values[x][y])) return; if (DEBUGGING(LEVELING)) { DEBUG_ECHOPGM("Extrapolate ["); @@ -92,11 +97,26 @@ static void extrapolate_one_point(const uint8_t x, const uint8_t y, const int8_t #endif #endif +void LevelingBilinear::reset() { + grid_start.reset(); + grid_spacing.reset(); + GRID_LOOP(x, y) { + z_values[x][y] = NAN; + TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, 0)); + } +} + +void LevelingBilinear::set_grid(const xy_pos_t& _grid_spacing, const xy_pos_t& _grid_start) { + grid_spacing = _grid_spacing; + grid_start = _grid_start; + grid_factor = grid_spacing.reciprocal(); +} + /** * Fill in the unprobed points (corners of circular print surface) * using linear extrapolation, away from the center. */ -void extrapolate_unprobed_bed_level() { +void LevelingBilinear::extrapolate_unprobed_bed_level() { #ifdef HALF_IN_X constexpr uint8_t ctrx2 = 0, xend = GRID_MAX_POINTS_X - 1; #else @@ -113,8 +133,8 @@ void extrapolate_unprobed_bed_level() { yend = ctry1; #endif - LOOP_LE_N(xo, xend) - LOOP_LE_N(yo, yend) { + for (uint8_t xo = 0; xo <= xend; ++xo) + for (uint8_t yo = 0; yo <= yend; ++yo) { uint8_t x2 = ctrx2 + xo, y2 = ctry2 + yo; #ifndef HALF_IN_X const uint8_t x1 = ctrx1 - xo; @@ -131,41 +151,37 @@ void extrapolate_unprobed_bed_level() { #endif extrapolate_one_point(x2, y2, -1, -1); // right-above - - } - } -void print_bilinear_leveling_grid() { +void LevelingBilinear::print_leveling_grid(const bed_mesh_t* _z_values/*=nullptr*/) { + // print internal grid(s) or just the one passed as a parameter SERIAL_ECHOLNPGM("Bilinear Leveling Grid:"); - print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 3, - [](const uint8_t ix, const uint8_t iy) { return z_values[ix][iy]; } - ); + print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 3, _z_values ? *_z_values[0] : z_values[0]); + + #if ENABLED(ABL_BILINEAR_SUBDIVISION) + if (!_z_values) { + SERIAL_ECHOLNPGM("Subdivided with CATMULL ROM Leveling Grid:"); + print_2d_array(ABL_GRID_POINTS_VIRT_X, ABL_GRID_POINTS_VIRT_Y, 5, z_values_virt[0]); + } + #endif } #if ENABLED(ABL_BILINEAR_SUBDIVISION) - #define ABL_GRID_POINTS_VIRT_X GRID_MAX_CELLS_X * (BILINEAR_SUBDIVISIONS) + 1 - #define ABL_GRID_POINTS_VIRT_Y GRID_MAX_CELLS_Y * (BILINEAR_SUBDIVISIONS) + 1 #define ABL_TEMP_POINTS_X (GRID_MAX_POINTS_X + 2) #define ABL_TEMP_POINTS_Y (GRID_MAX_POINTS_Y + 2) - float z_values_virt[ABL_GRID_POINTS_VIRT_X][ABL_GRID_POINTS_VIRT_Y]; - xy_pos_t bilinear_grid_spacing_virt; - xy_float_t bilinear_grid_factor_virt; - - void print_bilinear_leveling_grid_virt() { - SERIAL_ECHOLNPGM("Subdivided with CATMULL ROM Leveling Grid:"); - print_2d_array(ABL_GRID_POINTS_VIRT_X, ABL_GRID_POINTS_VIRT_Y, 5, - [](const uint8_t ix, const uint8_t iy) { return z_values_virt[ix][iy]; } - ); - } + float LevelingBilinear::z_values_virt[ABL_GRID_POINTS_VIRT_X][ABL_GRID_POINTS_VIRT_Y]; + xy_pos_t LevelingBilinear::grid_spacing_virt; + xy_float_t LevelingBilinear::grid_factor_virt; #define LINEAR_EXTRAPOLATION(E, I) ((E) * 2 - (I)) - float bed_level_virt_coord(const uint8_t x, const uint8_t y) { + float LevelingBilinear::virt_coord(const uint8_t x, const uint8_t y) { uint8_t ep = 0, ip = 1; if (x > (GRID_MAX_POINTS_X) + 1 || y > (GRID_MAX_POINTS_Y) + 1) { // The requested point requires extrapolating two points beyond the mesh. // These values are only requested for the edges of the mesh, which are always an actual mesh point, // and do not require interpolation. When interpolation is not needed, this "Mesh + 2" point is - // cancelled out in bed_level_virt_cmr and does not impact the result. Return 0.0 rather than + // cancelled out in virt_cmr and does not impact the result. Return 0.0 rather than // making this function more complex by extrapolating two points. return 0.0; } @@ -181,8 +197,8 @@ void print_bilinear_leveling_grid() { ); else return LINEAR_EXTRAPOLATION( - bed_level_virt_coord(ep + 1, y), - bed_level_virt_coord(ip + 1, y) + virt_coord(ep + 1, y), + virt_coord(ip + 1, y) ); } if (!y || y == ABL_TEMP_POINTS_Y - 1) { @@ -197,14 +213,14 @@ void print_bilinear_leveling_grid() { ); else return LINEAR_EXTRAPOLATION( - bed_level_virt_coord(x, ep + 1), - bed_level_virt_coord(x, ip + 1) + virt_coord(x, ep + 1), + virt_coord(x, ip + 1) ); } return z_values[x - 1][y - 1]; } - static float bed_level_virt_cmr(const float p[4], const uint8_t i, const float t) { + float LevelingBilinear::virt_cmr(const float p[4], const uint8_t i, const float t) { return ( p[i-1] * -t * sq(1 - t) + p[i] * (2 - 5 * sq(t) + 3 * t * sq(t)) @@ -213,69 +229,66 @@ void print_bilinear_leveling_grid() { ) * 0.5f; } - static float bed_level_virt_2cmr(const uint8_t x, const uint8_t y, const_float_t tx, const_float_t ty) { + float LevelingBilinear::virt_2cmr(const uint8_t x, const uint8_t y, const_float_t tx, const_float_t ty) { float row[4], column[4]; - LOOP_L_N(i, 4) { - LOOP_L_N(j, 4) { - column[j] = bed_level_virt_coord(i + x - 1, j + y - 1); + for (uint8_t i = 0; i < 4; ++i) { + for (uint8_t j = 0; j < 4; ++j) { + column[j] = virt_coord(i + x - 1, j + y - 1); } - row[i] = bed_level_virt_cmr(column, 1, ty); + row[i] = virt_cmr(column, 1, ty); } - return bed_level_virt_cmr(row, 1, tx); + return virt_cmr(row, 1, tx); } - void bed_level_virt_interpolate() { - bilinear_grid_spacing_virt = bilinear_grid_spacing / (BILINEAR_SUBDIVISIONS); - bilinear_grid_factor_virt = bilinear_grid_spacing_virt.reciprocal(); - LOOP_L_N(y, GRID_MAX_POINTS_Y) - LOOP_L_N(x, GRID_MAX_POINTS_X) - LOOP_L_N(ty, BILINEAR_SUBDIVISIONS) - LOOP_L_N(tx, BILINEAR_SUBDIVISIONS) { + void LevelingBilinear::subdivide_mesh() { + grid_spacing_virt = grid_spacing / (BILINEAR_SUBDIVISIONS); + grid_factor_virt = grid_spacing_virt.reciprocal(); + for (uint8_t y = 0; y < GRID_MAX_POINTS_Y; ++y) + for (uint8_t x = 0; x < GRID_MAX_POINTS_X; ++x) + for (uint8_t ty = 0; ty < BILINEAR_SUBDIVISIONS; ++ty) + for (uint8_t tx = 0; tx < BILINEAR_SUBDIVISIONS; ++tx) { if ((ty && y == (GRID_MAX_POINTS_Y) - 1) || (tx && x == (GRID_MAX_POINTS_X) - 1)) continue; z_values_virt[x * (BILINEAR_SUBDIVISIONS) + tx][y * (BILINEAR_SUBDIVISIONS) + ty] = - bed_level_virt_2cmr( - x + 1, - y + 1, - (float)tx / (BILINEAR_SUBDIVISIONS), - (float)ty / (BILINEAR_SUBDIVISIONS) - ); + virt_2cmr(x + 1, y + 1, (float)tx / (BILINEAR_SUBDIVISIONS), (float)ty / (BILINEAR_SUBDIVISIONS)); } } + #endif // ABL_BILINEAR_SUBDIVISION // Refresh after other values have been updated -void refresh_bed_level() { - bilinear_grid_factor = bilinear_grid_spacing.reciprocal(); - TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate()); +void LevelingBilinear::refresh_bed_level() { + TERN_(ABL_BILINEAR_SUBDIVISION, subdivide_mesh()); + cached_rel.x = cached_rel.y = -999.999; + cached_g.x = cached_g.y = -99; } #if ENABLED(ABL_BILINEAR_SUBDIVISION) - #define ABL_BG_SPACING(A) bilinear_grid_spacing_virt.A - #define ABL_BG_FACTOR(A) bilinear_grid_factor_virt.A + #define ABL_BG_SPACING(A) grid_spacing_virt.A + #define ABL_BG_FACTOR(A) grid_factor_virt.A #define ABL_BG_POINTS_X ABL_GRID_POINTS_VIRT_X #define ABL_BG_POINTS_Y ABL_GRID_POINTS_VIRT_Y #define ABL_BG_GRID(X,Y) z_values_virt[X][Y] #else - #define ABL_BG_SPACING(A) bilinear_grid_spacing.A - #define ABL_BG_FACTOR(A) bilinear_grid_factor.A + #define ABL_BG_SPACING(A) grid_spacing.A + #define ABL_BG_FACTOR(A) grid_factor.A #define ABL_BG_POINTS_X GRID_MAX_POINTS_X #define ABL_BG_POINTS_Y GRID_MAX_POINTS_Y #define ABL_BG_GRID(X,Y) z_values[X][Y] #endif // Get the Z adjustment for non-linear bed leveling -float bilinear_z_offset(const xy_pos_t &raw) { +float LevelingBilinear::get_z_correction(const xy_pos_t &raw) { static float z1, d2, z3, d4, L, D; - static xy_pos_t prev { -999.999, -999.999 }, ratio; + static xy_pos_t ratio; // Whole units for the grid line indices. Constrained within bounds. - static xy_int8_t thisg, nextg, lastg { -99, -99 }; + static xy_int8_t thisg, nextg; // XY relative to the probed area - xy_pos_t rel = raw - bilinear_start.asFloat(); + xy_pos_t rel = raw - grid_start.asFloat(); #if ENABLED(EXTRAPOLATE_BEYOND_GRID) #define FAR_EDGE_OR_BOX 2 // Keep using the last grid box @@ -283,8 +296,8 @@ float bilinear_z_offset(const xy_pos_t &raw) { #define FAR_EDGE_OR_BOX 1 // Just use the grid far edge #endif - if (prev.x != rel.x) { - prev.x = rel.x; + if (cached_rel.x != rel.x) { + cached_rel.x = rel.x; ratio.x = rel.x * ABL_BG_FACTOR(x); const float gx = constrain(FLOOR(ratio.x), 0, ABL_BG_POINTS_X - (FAR_EDGE_OR_BOX)); ratio.x -= gx; // Subtract whole to get the ratio within the grid box @@ -298,10 +311,10 @@ float bilinear_z_offset(const xy_pos_t &raw) { nextg.x = _MIN(thisg.x + 1, ABL_BG_POINTS_X - 1); } - if (prev.y != rel.y || lastg.x != thisg.x) { + if (cached_rel.y != rel.y || cached_g.x != thisg.x) { - if (prev.y != rel.y) { - prev.y = rel.y; + if (cached_rel.y != rel.y) { + cached_rel.y = rel.y; ratio.y = rel.y * ABL_BG_FACTOR(y); const float gy = constrain(FLOOR(ratio.y), 0, ABL_BG_POINTS_Y - (FAR_EDGE_OR_BOX)); ratio.y -= gy; @@ -315,8 +328,8 @@ float bilinear_z_offset(const xy_pos_t &raw) { nextg.y = _MIN(thisg.y + 1, ABL_BG_POINTS_Y - 1); } - if (lastg != thisg) { - lastg = thisg; + if (cached_g != thisg) { + cached_g = thisg; // Z at the box corners z1 = ABL_BG_GRID(thisg.x, thisg.y); // left-front d2 = ABL_BG_GRID(thisg.x, nextg.y) - z1; // left-back (delta) @@ -336,8 +349,8 @@ float bilinear_z_offset(const xy_pos_t &raw) { /* static float last_offset = 0; if (ABS(last_offset - offset) > 0.2) { - SERIAL_ECHOLNPGM("Sudden Shift at x=", rel.x, " / ", bilinear_grid_spacing.x, " -> thisg.x=", thisg.x); - SERIAL_ECHOLNPGM(" y=", rel.y, " / ", bilinear_grid_spacing.y, " -> thisg.y=", thisg.y); + SERIAL_ECHOLNPGM("Sudden Shift at x=", rel.x, " / ", grid_spacing.x, " -> thisg.x=", thisg.x); + SERIAL_ECHOLNPGM(" y=", rel.y, " / ", grid_spacing.y, " -> thisg.y=", thisg.y); SERIAL_ECHOLNPGM(" ratio.x=", ratio.x, " ratio.y=", ratio.y); SERIAL_ECHOLNPGM(" z1=", z1, " z2=", z2, " z3=", z3, " z4=", z4); SERIAL_ECHOLNPGM(" L=", L, " R=", R, " offset=", offset); @@ -350,13 +363,13 @@ float bilinear_z_offset(const xy_pos_t &raw) { #if IS_CARTESIAN && DISABLED(SEGMENT_LEVELED_MOVES) - #define CELL_INDEX(A,V) ((V - bilinear_start.A) * ABL_BG_FACTOR(A)) + #define CELL_INDEX(A,V) ((V - grid_start.A) * ABL_BG_FACTOR(A)) /** * Prepare a bilinear-leveled linear move on Cartesian, * splitting the move where it crosses grid borders. */ - void bilinear_line_to_destination(const_feedRate_t scaled_fr_mm_s, uint16_t x_splits, uint16_t y_splits) { + void LevelingBilinear::line_to_destination(const_feedRate_t scaled_fr_mm_s, uint16_t x_splits, uint16_t y_splits) { // Get current and destination cells for this line xy_int_t c1 { CELL_INDEX(x, current_position.x), CELL_INDEX(y, current_position.y) }, c2 { CELL_INDEX(x, destination.x), CELL_INDEX(y, destination.y) }; @@ -384,7 +397,7 @@ float bilinear_z_offset(const xy_pos_t &raw) { // Split on the X grid line CBI(x_splits, gc.x); end = destination; - destination.x = bilinear_start.x + ABL_BG_SPACING(x) * gc.x; + destination.x = grid_start.x + ABL_BG_SPACING(x) * gc.x; normalized_dist = (destination.x - current_position.x) / (end.x - current_position.x); destination.y = LINE_SEGMENT_END(y); } @@ -393,7 +406,7 @@ float bilinear_z_offset(const xy_pos_t &raw) { // Split on the Y grid line CBI(y_splits, gc.y); end = destination; - destination.y = bilinear_start.y + ABL_BG_SPACING(y) * gc.y; + destination.y = grid_start.y + ABL_BG_SPACING(y) * gc.y; normalized_dist = (destination.y - current_position.y) / (end.y - current_position.y); destination.x = LINE_SEGMENT_END(x); } @@ -409,11 +422,11 @@ float bilinear_z_offset(const xy_pos_t &raw) { destination.e = LINE_SEGMENT_END(e); // Do the split and look for more borders - bilinear_line_to_destination(scaled_fr_mm_s, x_splits, y_splits); + line_to_destination(scaled_fr_mm_s, x_splits, y_splits); // Restore destination from stack destination = end; - bilinear_line_to_destination(scaled_fr_mm_s, x_splits, y_splits); + line_to_destination(scaled_fr_mm_s, x_splits, y_splits); } #endif // IS_CARTESIAN && !SEGMENT_LEVELED_MOVES diff --git a/Marlin/src/feature/bedlevel/abl/bbl.h b/Marlin/src/feature/bedlevel/abl/bbl.h new file mode 100644 index 00000000..ca2e9659 --- /dev/null +++ b/Marlin/src/feature/bedlevel/abl/bbl.h @@ -0,0 +1,70 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#include "../../../inc/MarlinConfigPre.h" + +class LevelingBilinear { +public: + static bed_mesh_t z_values; + static xy_pos_t grid_spacing, grid_start; + +private: + static xy_float_t grid_factor; + static xy_pos_t cached_rel; + static xy_int8_t cached_g; + + static void extrapolate_one_point(const uint8_t x, const uint8_t y, const int8_t xdir, const int8_t ydir); + + #if ENABLED(ABL_BILINEAR_SUBDIVISION) + #define ABL_GRID_POINTS_VIRT_X (GRID_MAX_CELLS_X * (BILINEAR_SUBDIVISIONS) + 1) + #define ABL_GRID_POINTS_VIRT_Y (GRID_MAX_CELLS_Y * (BILINEAR_SUBDIVISIONS) + 1) + + static float z_values_virt[ABL_GRID_POINTS_VIRT_X][ABL_GRID_POINTS_VIRT_Y]; + static xy_pos_t grid_spacing_virt; + static xy_float_t grid_factor_virt; + + static float virt_coord(const uint8_t x, const uint8_t y); + static float virt_cmr(const float p[4], const uint8_t i, const float t); + static float virt_2cmr(const uint8_t x, const uint8_t y, const_float_t tx, const_float_t ty); + static void subdivide_mesh(); + #endif + +public: + static void reset(); + static void set_grid(const xy_pos_t& _grid_spacing, const xy_pos_t& _grid_start); + static void extrapolate_unprobed_bed_level(); + static void print_leveling_grid(const bed_mesh_t *_z_values=nullptr); + static void refresh_bed_level(); + static bool has_mesh() { return !!grid_spacing.x; } + static bool mesh_is_valid() { return has_mesh(); } + static float get_mesh_x(const uint8_t i) { return grid_start.x + i * grid_spacing.x; } + static float get_mesh_y(const uint8_t j) { return grid_start.y + j * grid_spacing.y; } + static float get_z_correction(const xy_pos_t &raw); + static constexpr float get_z_offset() { return 0.0f; } + + #if IS_CARTESIAN && DISABLED(SEGMENT_LEVELED_MOVES) + static void line_to_destination(const_feedRate_t scaled_fr_mm_s, uint16_t x_splits=0xFFFF, uint16_t y_splits=0xFFFF); + #endif +}; + +extern LevelingBilinear bedlevel; diff --git a/Marlin/src/feature/bedlevel/bdl/bdl.cpp b/Marlin/src/feature/bedlevel/bdl/bdl.cpp new file mode 100644 index 00000000..3297872d --- /dev/null +++ b/Marlin/src/feature/bedlevel/bdl/bdl.cpp @@ -0,0 +1,196 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "../../../inc/MarlinConfig.h" + +#if ENABLED(BD_SENSOR) + +#include "../../../MarlinCore.h" +#include "../../../gcode/gcode.h" +#include "../../../module/settings.h" +#include "../../../module/motion.h" +#include "../../../module/planner.h" +#include "../../../module/stepper.h" +#include "../../../module/probe.h" +#include "../../../module/temperature.h" +#include "../../../module/endstops.h" +#include "../../babystep.h" + +// I2C software Master library for segment bed heating and bed distance sensor +#include + +#include "bdl.h" +BDS_Leveling bdl; + +//#define DEBUG_OUT_BD + +// M102 S-5 Read raw Calibrate data +// M102 S-6 Start Calibrate +// M102 S4 Set the adjustable Z height value (e.g., 'M102 S4' means it will do adjusting while the Z height <= 0.4mm , disable with 'M102 S0'.) +// M102 S-1 Read sensor information + +#define MAX_BD_HEIGHT 4.0f +#define CMD_START_READ_CALIBRATE_DATA 1017 +#define CMD_END_READ_CALIBRATE_DATA 1018 +#define CMD_START_CALIBRATE 1019 +#define CMD_END_CALIBRATE 1021 +#define CMD_READ_VERSION 1016 + +I2C_SegmentBED BD_I2C_SENSOR; + +#define BD_SENSOR_I2C_ADDR 0x3C + +int8_t BDS_Leveling::config_state; +uint8_t BDS_Leveling::homing; + +void BDS_Leveling::echo_name() { SERIAL_ECHOPGM("Bed Distance Leveling"); } + +void BDS_Leveling::init(uint8_t _sda, uint8_t _scl, uint16_t delay_s) { + int ret = BD_I2C_SENSOR.i2c_init(_sda, _scl, BD_SENSOR_I2C_ADDR, delay_s); + if (ret != 1) SERIAL_ECHOLNPGM("BD_I2C_SENSOR Init Fail return code:", ret); + config_state = 0; +} + +float BDS_Leveling::read() { + const uint16_t tmp = BD_I2C_SENSOR.BD_i2c_read(); + float BD_z = NAN; + if (BD_I2C_SENSOR.BD_Check_OddEven(tmp) && (tmp & 0x3FF) < 1020) + BD_z = (tmp & 0x3FF) / 100.0f; + return BD_z; +} + +void BDS_Leveling::process() { + //if (config_state == 0) return; + static millis_t next_check_ms = 0; // starting at T=0 + static float z_pose = 0.0f; + const millis_t ms = millis(); + if (ELAPSED(ms, next_check_ms)) { // timed out (or first run) + next_check_ms = ms + (config_state < 0 ? 1000 : 100); // check at 1Hz or 10Hz + + unsigned short tmp = 0; + const float cur_z = planner.get_axis_position_mm(Z_AXIS); //current_position.z + static float old_cur_z = cur_z, + old_buf_z = current_position.z; + + tmp = BD_I2C_SENSOR.BD_i2c_read(); + if (BD_I2C_SENSOR.BD_Check_OddEven(tmp) && (tmp & 0x3FF) < 1020) { + const float z_sensor = (tmp & 0x3FF) / 100.0f; + if (cur_z < 0) config_state = 0; + //float abs_z = current_position.z > cur_z ? (current_position.z - cur_z) : (cur_z - current_position.z); + #if ENABLED(BABYSTEPPING) + if (cur_z < config_state * 0.1f + && config_state > 0 + && old_cur_z == cur_z + && old_buf_z == current_position.z + && z_sensor < (MAX_BD_HEIGHT) + ) { + babystep.set_mm(Z_AXIS, cur_z - z_sensor); + #if ENABLED(DEBUG_OUT_BD) + SERIAL_ECHOLNPGM("BD:", z_sensor, ", Z:", cur_z, "|", current_position.z); + #endif + } + else { + babystep.set_mm(Z_AXIS, 0); //if (old_cur_z <= cur_z) Z_DIR_WRITE(!INVERT_Z_DIR); + stepper.apply_directions(); + } + #endif + old_cur_z = cur_z; + old_buf_z = current_position.z; + endstops.bdp_state_update(z_sensor <= 0.01f); + //endstops.update(); + } + else + stepper.apply_directions(); + + #if ENABLED(DEBUG_OUT_BD) + SERIAL_ECHOLNPGM("BD:", tmp & 0x3FF, ", Z:", cur_z, "|", current_position.z); + if (BD_I2C_SENSOR.BD_Check_OddEven(tmp) == 0) SERIAL_ECHOLNPGM("errorCRC"); + #endif + + if ((tmp & 0x3FF) > 1020) { + BD_I2C_SENSOR.BD_i2c_stop(); + safe_delay(10); + } + + // read raw calibrate data + if (config_state == -5) { + BD_I2C_SENSOR.BD_i2c_write(CMD_START_READ_CALIBRATE_DATA); + safe_delay(1000); + + for (int i = 0; i < MAX_BD_HEIGHT * 10; i++) { + tmp = BD_I2C_SENSOR.BD_i2c_read(); + SERIAL_ECHOLNPGM("Calibrate data:", i, ",", tmp & 0x3FF, ", check:", BD_I2C_SENSOR.BD_Check_OddEven(tmp)); + safe_delay(500); + } + config_state = 0; + BD_I2C_SENSOR.BD_i2c_write(CMD_END_READ_CALIBRATE_DATA); + safe_delay(500); + } + else if (config_state <= -6) { // Start Calibrate + safe_delay(100); + if (config_state == -6) { + //BD_I2C_SENSOR.BD_i2c_write(1019); // begin calibrate + //delay(1000); + TERN_(HAS_DISABLE_IDLE_AXES, gcode.stepper_inactive_time = SEC_TO_MS(60 * 5)); + gcode.process_subcommands_now(F("M17 Z")); + gcode.process_subcommands_now(F("G1 Z0.0")); + z_pose = 0; + safe_delay(1000); + BD_I2C_SENSOR.BD_i2c_write(CMD_START_CALIBRATE); // Begin calibrate + SERIAL_ECHOLNPGM("Begin calibrate"); + safe_delay(2000); + config_state = -7; + } + else if (planner.get_axis_position_mm(Z_AXIS) < 10.0f) { + if (z_pose >= MAX_BD_HEIGHT) { + BD_I2C_SENSOR.BD_i2c_write(CMD_END_CALIBRATE); // End calibrate + SERIAL_ECHOLNPGM("End calibrate data"); + z_pose = 7; + config_state = 0; + safe_delay(1000); + } + else { + float tmp_k = 0; + char tmp_1[30]; + sprintf_P(tmp_1, PSTR("G1 Z%d.%d"), int(z_pose), int(int(z_pose * 10) % 10)); + gcode.process_subcommands_now(tmp_1); + + SERIAL_ECHO(tmp_1); + SERIAL_ECHOLNPGM(" ,Z:", current_position.z); + + while (tmp_k < (z_pose - 0.1f)) { + tmp_k = planner.get_axis_position_mm(Z_AXIS); + safe_delay(1); + } + safe_delay(800); + tmp = (z_pose + 0.0001f) * 10; + BD_I2C_SENSOR.BD_i2c_write(tmp); + SERIAL_ECHOLNPGM("w:", tmp, ",Zpose:", z_pose); + z_pose += 0.1001f; + //queue.enqueue_now_P(PSTR("G90")); + } + } + } + } +} + +#endif // BD_SENSOR diff --git a/Marlin/src/feature/bedlevel/bdl/bdl.h b/Marlin/src/feature/bedlevel/bdl/bdl.h new file mode 100644 index 00000000..6307b1ab --- /dev/null +++ b/Marlin/src/feature/bedlevel/bdl/bdl.h @@ -0,0 +1,36 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#include + +class BDS_Leveling { +public: + static int8_t config_state; + static uint8_t homing; + static void echo_name(); + static void init(uint8_t _sda, uint8_t _scl, uint16_t delay_s); + static void process(); + static float read(); +}; + +extern BDS_Leveling bdl; diff --git a/Marlin/src/feature/bedlevel/bedlevel.cpp b/Marlin/src/feature/bedlevel/bedlevel.cpp index 8e03632d..17407eaf 100644 --- a/Marlin/src/feature/bedlevel/bedlevel.cpp +++ b/Marlin/src/feature/bedlevel/bedlevel.cpp @@ -27,7 +27,7 @@ #include "bedlevel.h" #include "../../module/planner.h" -#if EITHER(MESH_BED_LEVELING, PROBE_MANUALLY) +#if ANY(MESH_BED_LEVELING, PROBE_MANUALLY) #include "../../module/motion.h" #endif @@ -47,48 +47,41 @@ #endif bool leveling_is_valid() { - return TERN1(MESH_BED_LEVELING, mbl.has_mesh()) - && TERN1(AUTO_BED_LEVELING_BILINEAR, !!bilinear_grid_spacing.x) - && TERN1(AUTO_BED_LEVELING_UBL, ubl.mesh_is_valid()); + return TERN1(HAS_MESH, bedlevel.mesh_is_valid()); } /** - * Turn bed leveling on or off, fixing the current - * position as-needed. + * Turn bed leveling on or off, correcting the current position. * * Disable: Current position = physical position * Enable: Current position = "unleveled" physical position */ void set_bed_leveling_enabled(const bool enable/*=true*/) { + DEBUG_SECTION(log_sble, "set_bed_leveling_enabled", DEBUGGING(LEVELING)); const bool can_change = TERN1(AUTO_BED_LEVELING_BILINEAR, !enable || leveling_is_valid()); if (can_change && enable != planner.leveling_active) { + auto _report_leveling = []{ + if (DEBUGGING(LEVELING)) { + if (planner.leveling_active) + DEBUG_POS("Leveling ON", current_position); + else + DEBUG_POS("Leveling OFF", current_position); + } + }; + + _report_leveling(); planner.synchronize(); - #if ENABLED(AUTO_BED_LEVELING_BILINEAR) - // Force bilinear_z_offset to re-calculate next time - const xyz_pos_t reset { -9999.999, -9999.999, 0 }; - (void)bilinear_z_offset(reset); - #endif - - if (planner.leveling_active) { // leveling from on to off - if (DEBUGGING(LEVELING)) DEBUG_POS("Leveling ON", current_position); - // change unleveled current_position to physical current_position without moving steppers. - planner.apply_leveling(current_position); - planner.leveling_active = false; // disable only AFTER calling apply_leveling - if (DEBUGGING(LEVELING)) DEBUG_POS("...Now OFF", current_position); - } - else { // leveling from off to on - if (DEBUGGING(LEVELING)) DEBUG_POS("Leveling OFF", current_position); - planner.leveling_active = true; // enable BEFORE calling unapply_leveling, otherwise ignored - // change physical current_position to unleveled current_position without moving steppers. - planner.unapply_leveling(current_position); - if (DEBUGGING(LEVELING)) DEBUG_POS("...Now ON", current_position); - } + // Get the corrected leveled / unleveled position + planner.apply_modifiers(current_position, true); // Physical position with all modifiers + planner.leveling_active ^= true; // Toggle leveling between apply and unapply + planner.unapply_modifiers(current_position, true); // Logical position with modifiers removed sync_plan_position(); + _report_leveling(); } } @@ -122,26 +115,12 @@ TemporaryBedLevelingState::TemporaryBedLevelingState(const bool enable) : saved( */ void reset_bed_level() { if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("reset_bed_level"); - #if ENABLED(AUTO_BED_LEVELING_UBL) - ubl.reset(); - #else - set_bed_leveling_enabled(false); - #if ENABLED(MESH_BED_LEVELING) - mbl.reset(); - #elif ENABLED(AUTO_BED_LEVELING_BILINEAR) - bilinear_start.reset(); - bilinear_grid_spacing.reset(); - GRID_LOOP(x, y) { - z_values[x][y] = NAN; - TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, 0)); - } - #elif ABL_PLANAR - planner.bed_level_matrix.set_to_identity(); - #endif - #endif + IF_DISABLED(AUTO_BED_LEVELING_UBL, set_bed_leveling_enabled(false)); + TERN_(HAS_MESH, bedlevel.reset()); + TERN_(ABL_PLANAR, planner.bed_level_matrix.set_to_identity()); } -#if EITHER(AUTO_BED_LEVELING_BILINEAR, MESH_BED_LEVELING) +#if ANY(AUTO_BED_LEVELING_BILINEAR, MESH_BED_LEVELING) /** * Enable to produce output in JSON format suitable @@ -156,9 +135,9 @@ void reset_bed_level() { /** * Print calibration results for plotting or manual frame adjustment. */ - void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, element_2d_fn fn) { + void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, const float *values) { #ifndef SCAD_MESH_OUTPUT - LOOP_L_N(x, sx) { + for (uint8_t x = 0; x < sx; ++x) { serial_spaces(precision + (x < 10 ? 3 : 2)); SERIAL_ECHO(x); } @@ -167,16 +146,16 @@ void reset_bed_level() { #ifdef SCAD_MESH_OUTPUT SERIAL_ECHOLNPGM("measured_z = ["); // open 2D array #endif - LOOP_L_N(y, sy) { + for (uint8_t y = 0; y < sy; ++y) { #ifdef SCAD_MESH_OUTPUT SERIAL_ECHOPGM(" ["); // open sub-array #else if (y < 10) SERIAL_CHAR(' '); SERIAL_ECHO(y); #endif - LOOP_L_N(x, sx) { + for (uint8_t x = 0; x < sx; ++x) { SERIAL_CHAR(' '); - const float offset = fn(x, y); + const float offset = values[x * sy + y]; if (!isnan(offset)) { if (offset >= 0) SERIAL_CHAR('+'); SERIAL_ECHO_F(offset, int(precision)); @@ -187,7 +166,7 @@ void reset_bed_level() { SERIAL_CHAR(' '); SERIAL_ECHOPGM("NAN"); #else - LOOP_L_N(i, precision + 3) + for (uint8_t i = 0; i < precision + 3; ++i) SERIAL_CHAR(i ? '=' : ' '); #endif } @@ -209,7 +188,7 @@ void reset_bed_level() { #endif // AUTO_BED_LEVELING_BILINEAR || MESH_BED_LEVELING -#if EITHER(MESH_BED_LEVELING, PROBE_MANUALLY) +#if ANY(MESH_BED_LEVELING, PROBE_MANUALLY) void _manual_goto_xy(const xy_pos_t &pos) { diff --git a/Marlin/src/feature/bedlevel/bedlevel.h b/Marlin/src/feature/bedlevel/bedlevel.h index c623c99b..ccb9543e 100644 --- a/Marlin/src/feature/bedlevel/bedlevel.h +++ b/Marlin/src/feature/bedlevel/bedlevel.h @@ -23,7 +23,7 @@ #include "../../inc/MarlinConfigPre.h" -#if EITHER(RESTORE_LEVELING_AFTER_G28, ENABLE_LEVELING_AFTER_G28) +#if ANY(RESTORE_LEVELING_AFTER_G28, ENABLE_LEVELING_AFTER_G28) #define CAN_SET_LEVELING_AFTER_G28 1 #endif @@ -41,7 +41,7 @@ void reset_bed_level(); void set_z_fade_height(const_float_t zfh, const bool do_report=true); #endif -#if EITHER(MESH_BED_LEVELING, PROBE_MANUALLY) +#if ANY(MESH_BED_LEVELING, PROBE_MANUALLY) void _manual_goto_xy(const xy_pos_t &pos); #endif @@ -62,20 +62,14 @@ class TemporaryBedLevelingState { typedef float bed_mesh_t[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y]; #if ENABLED(AUTO_BED_LEVELING_BILINEAR) - #include "abl/abl.h" - #if ENABLED(X_AXIS_TWIST_COMPENSATION) - #include "abl/x_twist.h" - #endif + #include "abl/bbl.h" #elif ENABLED(AUTO_BED_LEVELING_UBL) #include "ubl/ubl.h" #elif ENABLED(MESH_BED_LEVELING) #include "mbl/mesh_bed_leveling.h" #endif - #define Z_VALUES(X,Y) Z_VALUES_ARR[X][Y] - #define _GET_MESH_POS(M) { _GET_MESH_X(M.a), _GET_MESH_Y(M.b) } - - #if EITHER(AUTO_BED_LEVELING_BILINEAR, MESH_BED_LEVELING) + #if ANY(AUTO_BED_LEVELING_BILINEAR, MESH_BED_LEVELING) #include @@ -84,7 +78,7 @@ class TemporaryBedLevelingState { /** * Print calibration results for plotting or manual frame adjustment. */ - void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, element_2d_fn fn); + void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, const float *values); #endif @@ -95,7 +89,7 @@ class TemporaryBedLevelingState { bool valid() const { return pos.x >= 0 && pos.y >= 0; } #if ENABLED(AUTO_BED_LEVELING_UBL) xy_pos_t meshpos() { - return { ubl.mesh_index_to_xpos(pos.x), ubl.mesh_index_to_ypos(pos.y) }; + return { bedlevel.get_mesh_x(pos.x), bedlevel.get_mesh_y(pos.y) }; } #endif operator xy_int8_t&() { return pos; } diff --git a/Marlin/src/feature/bedlevel/hilbert_curve.cpp b/Marlin/src/feature/bedlevel/hilbert_curve.cpp index 7474123e..57cbdfb3 100644 --- a/Marlin/src/feature/bedlevel/hilbert_curve.cpp +++ b/Marlin/src/feature/bedlevel/hilbert_curve.cpp @@ -28,8 +28,8 @@ constexpr int8_t to_fix(int8_t v) { return v * 2; } constexpr int8_t to_int(int8_t v) { return v / 2; } -constexpr uint8_t log2(uint8_t n) { return (n > 1) ? 1 + log2(n >> 1) : 0; } -constexpr uint8_t order(uint8_t n) { return uint8_t(log2(n - 1)) + 1; } +constexpr uint8_t log2(uint8_t n) { return (n > 1) ? 1 + log2(uint8_t(n >> 1)) : 0; } +constexpr uint8_t order(uint8_t n) { return uint8_t(log2(uint8_t(n - 1))) + 1; } constexpr uint8_t ord = order(_MAX(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y)); constexpr uint8_t dim = _BV(ord); diff --git a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp index 51cf28f8..05c9ea80 100644 --- a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp +++ b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp @@ -32,7 +32,7 @@ #include "../../../lcd/extui/ui_api.h" #endif - mesh_bed_leveling mbl; + mesh_bed_leveling bedlevel; float mesh_bed_leveling::z_offset, mesh_bed_leveling::z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y], @@ -40,9 +40,9 @@ mesh_bed_leveling::index_to_ypos[GRID_MAX_POINTS_Y]; mesh_bed_leveling::mesh_bed_leveling() { - LOOP_L_N(i, GRID_MAX_POINTS_X) + for (uint8_t i = 0; i < GRID_MAX_POINTS_X; ++i) index_to_xpos[i] = MESH_MIN_X + i * (MESH_X_DIST); - LOOP_L_N(i, GRID_MAX_POINTS_Y) + for (uint8_t i = 0; i < GRID_MAX_POINTS_Y; ++i) index_to_ypos[i] = MESH_MIN_Y + i * (MESH_Y_DIST); reset(); } @@ -63,7 +63,7 @@ */ void mesh_bed_leveling::line_to_destination(const_feedRate_t scaled_fr_mm_s, uint8_t x_splits, uint8_t y_splits) { // Get current and destination cells for this line - xy_int8_t scel = cell_indexes(current_position), ecel = cell_indexes(destination); + xy_uint8_t scel = cell_indexes(current_position), ecel = cell_indexes(destination); NOMORE(scel.x, GRID_MAX_CELLS_X - 1); NOMORE(scel.y, GRID_MAX_CELLS_Y - 1); NOMORE(ecel.x, GRID_MAX_CELLS_X - 1); @@ -80,7 +80,7 @@ float normalized_dist; xyze_pos_t dest; - const int8_t gcx = _MAX(scel.x, ecel.x), gcy = _MAX(scel.y, ecel.y); + const uint8_t gcx = _MAX(scel.x, ecel.x), gcy = _MAX(scel.y, ecel.y); // Crosses on the X and not already split on this X? // The x_splits flags are insurance against rounding errors. @@ -125,9 +125,7 @@ void mesh_bed_leveling::report_mesh() { SERIAL_ECHOPAIR_F(STRINGIFY(GRID_MAX_POINTS_X) "x" STRINGIFY(GRID_MAX_POINTS_Y) " mesh. Z offset: ", z_offset, 5); SERIAL_ECHOLNPGM("\nMeasured points:"); - print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 5, - [](const uint8_t ix, const uint8_t iy) { return z_values[ix][iy]; } - ); + print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 5, z_values[0]); } #endif // MESH_BED_LEVELING diff --git a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.h b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.h index cc546957..cb4f36cd 100644 --- a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.h +++ b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.h @@ -32,11 +32,8 @@ enum MeshLevelingState : char { MeshReset // G29 S5 }; -#define MESH_X_DIST (float(MESH_MAX_X - (MESH_MIN_X)) / (GRID_MAX_CELLS_X)) -#define MESH_Y_DIST (float(MESH_MAX_Y - (MESH_MIN_Y)) / (GRID_MAX_CELLS_Y)) -#define _GET_MESH_X(I) mbl.index_to_xpos[I] -#define _GET_MESH_Y(J) mbl.index_to_ypos[J] -#define Z_VALUES_ARR mbl.z_values +#define MESH_X_DIST (float((MESH_MAX_X) - (MESH_MIN_X)) / (GRID_MAX_CELLS_X)) +#define MESH_Y_DIST (float((MESH_MAX_Y) - (MESH_MIN_Y)) / (GRID_MAX_CELLS_Y)) class mesh_bed_leveling { public: @@ -56,9 +53,11 @@ class mesh_bed_leveling { return false; } + static bool mesh_is_valid() { return has_mesh(); } + static void set_z(const int8_t px, const int8_t py, const_float_t z) { z_values[px][py] = z; } - static inline void zigzag(const int8_t index, int8_t &px, int8_t &py) { + static void zigzag(const int8_t index, int8_t &px, int8_t &py) { px = index % (GRID_MAX_POINTS_X); py = index / (GRID_MAX_POINTS_X); if (py & 1) px = (GRID_MAX_POINTS_X) - 1 - px; // Zig zag @@ -70,18 +69,21 @@ class mesh_bed_leveling { set_z(px, py, z); } - static int8_t cell_index_x(const_float_t x) { + static float get_mesh_x(const uint8_t i) { return index_to_xpos[i]; } + static float get_mesh_y(const uint8_t i) { return index_to_ypos[i]; } + + static uint8_t cell_index_x(const_float_t x) { int8_t cx = (x - (MESH_MIN_X)) * RECIPROCAL(MESH_X_DIST); return constrain(cx, 0, GRID_MAX_CELLS_X - 1); } - static int8_t cell_index_y(const_float_t y) { + static uint8_t cell_index_y(const_float_t y) { int8_t cy = (y - (MESH_MIN_Y)) * RECIPROCAL(MESH_Y_DIST); return constrain(cy, 0, GRID_MAX_CELLS_Y - 1); } - static inline xy_int8_t cell_indexes(const_float_t x, const_float_t y) { + static xy_uint8_t cell_indexes(const_float_t x, const_float_t y) { return { cell_index_x(x), cell_index_y(y) }; } - static inline xy_int8_t cell_indexes(const xy_pos_t &xy) { return cell_indexes(xy.x, xy.y); } + static xy_uint8_t cell_indexes(const xy_pos_t &xy) { return cell_indexes(xy.x, xy.y); } static int8_t probe_index_x(const_float_t x) { int8_t px = (x - (MESH_MIN_X) + 0.5f * (MESH_X_DIST)) * RECIPROCAL(MESH_X_DIST); @@ -91,10 +93,10 @@ class mesh_bed_leveling { int8_t py = (y - (MESH_MIN_Y) + 0.5f * (MESH_Y_DIST)) * RECIPROCAL(MESH_Y_DIST); return WITHIN(py, 0, (GRID_MAX_POINTS_Y) - 1) ? py : -1; } - static inline xy_int8_t probe_indexes(const_float_t x, const_float_t y) { + static xy_int8_t probe_indexes(const_float_t x, const_float_t y) { return { probe_index_x(x), probe_index_y(y) }; } - static inline xy_int8_t probe_indexes(const xy_pos_t &xy) { return probe_indexes(xy.x, xy.y); } + static xy_int8_t probe_indexes(const xy_pos_t &xy) { return probe_indexes(xy.x, xy.y); } static float calc_z0(const_float_t a0, const_float_t a1, const_float_t z1, const_float_t a2, const_float_t z2) { const float delta_z = (z2 - z1) / (a2 - a1), @@ -102,20 +104,17 @@ class mesh_bed_leveling { return z1 + delta_a * delta_z; } - static float get_z(const xy_pos_t &pos - OPTARG(ENABLE_LEVELING_FADE_HEIGHT, const_float_t factor=1.0f) - ) { - #if DISABLED(ENABLE_LEVELING_FADE_HEIGHT) - constexpr float factor = 1.0f; - #endif - const xy_int8_t ind = cell_indexes(pos); + static float get_z_offset() { return z_offset; } + + static float get_z_correction(const xy_pos_t &pos) { + const xy_uint8_t ind = cell_indexes(pos); const float x1 = index_to_xpos[ind.x], x2 = index_to_xpos[ind.x+1], - y1 = index_to_xpos[ind.y], y2 = index_to_xpos[ind.y+1], + y1 = index_to_ypos[ind.y], y2 = index_to_ypos[ind.y+1], z1 = calc_z0(pos.x, x1, z_values[ind.x][ind.y ], x2, z_values[ind.x+1][ind.y ]), z2 = calc_z0(pos.x, x1, z_values[ind.x][ind.y+1], x2, z_values[ind.x+1][ind.y+1]), zf = calc_z0(pos.y, y1, z1, y2, z2); - return z_offset + zf * factor; + return zf; } #if IS_CARTESIAN && DISABLED(SEGMENT_LEVELED_MOVES) @@ -123,4 +122,4 @@ class mesh_bed_leveling { #endif }; -extern mesh_bed_leveling mbl; +extern mesh_bed_leveling bedlevel; diff --git a/Marlin/src/feature/bedlevel/ubl/ubl.cpp b/Marlin/src/feature/bedlevel/ubl/ubl.cpp index 964f1123..46356004 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl.cpp @@ -26,7 +26,7 @@ #include "../bedlevel.h" -unified_bed_leveling ubl; +unified_bed_leveling bedlevel; #include "../../../MarlinCore.h" #include "../../../gcode/gcode.h" @@ -59,7 +59,7 @@ void unified_bed_leveling::report_current_mesh() { void unified_bed_leveling::report_state() { echo_name(); - SERIAL_ECHO_TERNARY(planner.leveling_active, " System v" UBL_VERSION " ", "", "in", "active\n"); + serial_ternary(planner.leveling_active, F(" System v" UBL_VERSION " "), nullptr, F("in"), F("active\n")); serial_delay(50); } @@ -149,7 +149,7 @@ static void serial_echo_xy(const uint8_t sp, const int16_t x, const int16_t y) { static void serial_echo_column_labels(const uint8_t sp) { SERIAL_ECHO_SP(7); - LOOP_L_N(i, GRID_MAX_POINTS_X) { + for (uint8_t i = 0; i < GRID_MAX_POINTS_X; ++i) { if (i < 10) SERIAL_CHAR(' '); SERIAL_ECHO(i); SERIAL_ECHO_SP(sp); @@ -199,7 +199,7 @@ void unified_bed_leveling::display_map(const uint8_t map_type) { } // Row Values (I indexes) - LOOP_L_N(i, GRID_MAX_POINTS_X) { + for (uint8_t i = 0; i < GRID_MAX_POINTS_X; ++i) { // Opening Brace or Space const bool is_current = i == curr.x && j == curr.y; @@ -213,8 +213,8 @@ void unified_bed_leveling::display_map(const uint8_t map_type) { else if (isnan(f)) SERIAL_ECHOF(human ? F(" . ") : F("NAN")); else if (human || csv) { - if (human && f >= 0.0) SERIAL_CHAR(f > 0 ? '+' : ' '); // Display sign also for positive numbers (' ' for 0) - SERIAL_ECHO_F(f, 3); // Positive: 5 digits, Negative: 6 digits + if (human && f >= 0) SERIAL_CHAR(f > 0 ? '+' : ' '); // Display sign also for positive numbers (' ' for 0) + SERIAL_DECIMAL(f); // Positive: 5 digits, Negative: 6 digits } if (csv && i < (GRID_MAX_POINTS_X) - 1) SERIAL_CHAR('\t'); @@ -260,7 +260,7 @@ bool unified_bed_leveling::sanity_check() { */ void GcodeSuite::M1004() { - #define ALIGN_GCODE TERN(Z_STEPPER_AUTO_ALIGN, "G34", "") + #define ALIGN_GCODE TERN(Z_STEPPER_AUTO_ALIGN, "G34\n", "") #define PROBE_GCODE TERN(HAS_BED_PROBE, "G29P1\nG29P3", "G29P4R") #if HAS_HOTEND @@ -280,7 +280,7 @@ bool unified_bed_leveling::sanity_check() { #endif process_subcommands_now(FPSTR(G28_STR)); // Home - process_subcommands_now(F(ALIGN_GCODE "\n" // Align multi z axis if available + process_subcommands_now(F(ALIGN_GCODE // Align multi z axis if available PROBE_GCODE "\n" // Build mesh with available hardware "G29P3\nG29P3")); // Ensure mesh is complete by running smart fill twice diff --git a/Marlin/src/feature/bedlevel/ubl/ubl.h b/Marlin/src/feature/bedlevel/ubl/ubl.h index ffabadd9..593722da 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl.h +++ b/Marlin/src/feature/bedlevel/ubl/ubl.h @@ -38,8 +38,8 @@ enum MeshPointType : char { INVALID, REAL, SET_IN_BITMAP, CLOSEST }; struct mesh_index_pair; -#define MESH_X_DIST (float(MESH_MAX_X - (MESH_MIN_X)) / (GRID_MAX_CELLS_X)) -#define MESH_Y_DIST (float(MESH_MAX_Y - (MESH_MIN_Y)) / (GRID_MAX_CELLS_Y)) +#define MESH_X_DIST (float((MESH_MAX_X) - (MESH_MIN_X)) / (GRID_MAX_CELLS_X)) +#define MESH_Y_DIST (float((MESH_MAX_Y) - (MESH_MIN_Y)) / (GRID_MAX_CELLS_Y)) #if ENABLED(OPTIMIZED_MESH_STORAGE) typedef int16_t mesh_store_t[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y]; @@ -48,8 +48,8 @@ struct mesh_index_pair; typedef struct { bool C_seen; int8_t KLS_storage_slot; - uint8_t R_repetition, - V_verbosity, + grid_count_t R_repetition; + uint8_t V_verbosity, P_phase, T_map_type; float B_shim_thickness, @@ -70,20 +70,18 @@ class unified_bed_leveling { static void move_z_with_encoder(const_float_t multiplier); static float measure_point_with_encoder(); static float measure_business_card_thickness(); - static void manually_probe_remaining_mesh(const xy_pos_t&, const_float_t , const_float_t , const bool) _O0; - static void fine_tune_mesh(const xy_pos_t &pos, const bool do_ubl_mesh_map) _O0; + static void manually_probe_remaining_mesh(const xy_pos_t&, const_float_t , const_float_t , const bool) __O0; + static void fine_tune_mesh(const xy_pos_t &pos, const bool do_ubl_mesh_map) __O0; #endif - static bool G29_parse_parameters() _O0; + static bool G29_parse_parameters() __O0; static void shift_mesh_height(); - static void probe_entire_mesh(const xy_pos_t &near, const bool do_ubl_mesh_map, const bool stow_probe, const bool do_furthest) _O0; - static void tilt_mesh_based_on_3pts(const_float_t z1, const_float_t z2, const_float_t z3); + static void probe_entire_mesh(const xy_pos_t &near, const bool do_ubl_mesh_map, const bool stow_probe, const bool do_furthest) __O0; static void tilt_mesh_based_on_probed_grid(const bool do_ubl_mesh_map); static bool smart_fill_one(const uint8_t x, const uint8_t y, const int8_t xdir, const int8_t ydir); - static inline bool smart_fill_one(const xy_uint8_t &pos, const xy_uint8_t &dir) { + static bool smart_fill_one(const xy_uint8_t &pos, const xy_uint8_t &dir) { return smart_fill_one(pos.x, pos.y, dir.x, dir.y); } - static void smart_fill_mesh(); #if ENABLED(UBL_DEVEL_DEBUGGING) static void g29_what_command(); @@ -98,17 +96,18 @@ class unified_bed_leveling { static void report_state(); static void save_ubl_active_state_and_disable(); static void restore_ubl_active_state_and_leave(); - static void display_map(const uint8_t) _O0; - static mesh_index_pair find_closest_mesh_point_of_type(const MeshPointType, const xy_pos_t&, const bool=false, MeshFlags *done_flags=nullptr) _O0; - static mesh_index_pair find_furthest_invalid_mesh_point() _O0; + static void display_map(const uint8_t) __O0; + static mesh_index_pair find_closest_mesh_point_of_type(const MeshPointType, const xy_pos_t&, const bool=false, MeshFlags *done_flags=nullptr) __O0; + static mesh_index_pair find_furthest_invalid_mesh_point() __O0; static void reset(); static void invalidate(); static void set_all_mesh_points_to_value(const_float_t value); static void adjust_mesh_to_mean(const bool cflag, const_float_t value); static bool sanity_check(); + static void smart_fill_mesh(); - static void G29() _O0; // O0 for no optimization - static void smart_fill_wlsf(const_float_t ) _O2; // O2 gives smaller code than Os on A2560 + static void G29() __O0; // O0 for no optimization + static void smart_fill_wlsf(const_float_t ) __O2; // O2 gives smaller code than Os on A2560 static int8_t storage_slot; @@ -120,11 +119,11 @@ class unified_bed_leveling { static const float _mesh_index_to_xpos[GRID_MAX_POINTS_X], _mesh_index_to_ypos[GRID_MAX_POINTS_Y]; - #if HAS_LCD_MENU + #if HAS_MARLINUI_MENU static bool lcd_map_control; static void steppers_were_disabled(); #else - static inline void steppers_were_disabled() {} + static void steppers_were_disabled() {} #endif static volatile int16_t encoder_diff; // Volatile because buttons may change it at interrupt time @@ -141,26 +140,26 @@ class unified_bed_leveling { return FLOOR((y - (MESH_MIN_Y)) * RECIPROCAL(MESH_Y_DIST)); } - static int8_t cell_index_x_valid(const_float_t x) { + static bool cell_index_x_valid(const_float_t x) { return WITHIN(cell_index_x_raw(x), 0, GRID_MAX_CELLS_X - 1); } - static int8_t cell_index_y_valid(const_float_t y) { + static bool cell_index_y_valid(const_float_t y) { return WITHIN(cell_index_y_raw(y), 0, GRID_MAX_CELLS_Y - 1); } - static int8_t cell_index_x(const_float_t x) { + static uint8_t cell_index_x(const_float_t x) { return constrain(cell_index_x_raw(x), 0, GRID_MAX_CELLS_X - 1); } - static int8_t cell_index_y(const_float_t y) { + static uint8_t cell_index_y(const_float_t y) { return constrain(cell_index_y_raw(y), 0, GRID_MAX_CELLS_Y - 1); } - static inline xy_int8_t cell_indexes(const_float_t x, const_float_t y) { + static xy_uint8_t cell_indexes(const_float_t x, const_float_t y) { return { cell_index_x(x), cell_index_y(y) }; } - static inline xy_int8_t cell_indexes(const xy_pos_t &xy) { return cell_indexes(xy.x, xy.y); } + static xy_uint8_t cell_indexes(const xy_pos_t &xy) { return cell_indexes(xy.x, xy.y); } static int8_t closest_x_index(const_float_t x) { const int8_t px = (x - (MESH_MIN_X) + (MESH_X_DIST) * 0.5) * RECIPROCAL(MESH_X_DIST); @@ -170,7 +169,7 @@ class unified_bed_leveling { const int8_t py = (y - (MESH_MIN_Y) + (MESH_Y_DIST) * 0.5) * RECIPROCAL(MESH_Y_DIST); return WITHIN(py, 0, (GRID_MAX_POINTS_Y) - 1) ? py : -1; } - static inline xy_int8_t closest_indexes(const xy_pos_t &xy) { + static xy_int8_t closest_indexes(const xy_pos_t &xy) { return { closest_x_index(xy.x), closest_y_index(xy.y) }; } @@ -203,7 +202,7 @@ class unified_bed_leveling { * z_correction_for_x_on_horizontal_mesh_line is an optimization for * the case where the printer is making a vertical line that only crosses horizontal mesh lines. */ - static inline float z_correction_for_x_on_horizontal_mesh_line(const_float_t rx0, const int x1_i, const int yi) { + static float z_correction_for_x_on_horizontal_mesh_line(const_float_t rx0, const int x1_i, const int yi) { if (!WITHIN(x1_i, 0, (GRID_MAX_POINTS_X) - 1) || !WITHIN(yi, 0, (GRID_MAX_POINTS_Y) - 1)) { if (DEBUGGING(LEVELING)) { @@ -215,7 +214,7 @@ class unified_bed_leveling { return _UBL_OUTER_Z_RAISE; } - const float xratio = (rx0 - mesh_index_to_xpos(x1_i)) * RECIPROCAL(MESH_X_DIST), + const float xratio = (rx0 - get_mesh_x(x1_i)) * RECIPROCAL(MESH_X_DIST), z1 = z_values[x1_i][yi]; return z1 + xratio * (z_values[_MIN(x1_i, (GRID_MAX_POINTS_X) - 2) + 1][yi] - z1); // Don't allow x1_i+1 to be past the end of the array @@ -226,7 +225,7 @@ class unified_bed_leveling { // // See comments above for z_correction_for_x_on_horizontal_mesh_line // - static inline float z_correction_for_y_on_vertical_mesh_line(const_float_t ry0, const int xi, const int y1_i) { + static float z_correction_for_y_on_vertical_mesh_line(const_float_t ry0, const int xi, const int y1_i) { if (!WITHIN(xi, 0, (GRID_MAX_POINTS_X) - 1) || !WITHIN(y1_i, 0, (GRID_MAX_POINTS_Y) - 1)) { if (DEBUGGING(LEVELING)) { @@ -238,7 +237,7 @@ class unified_bed_leveling { return _UBL_OUTER_Z_RAISE; } - const float yratio = (ry0 - mesh_index_to_ypos(y1_i)) * RECIPROCAL(MESH_Y_DIST), + const float yratio = (ry0 - get_mesh_y(y1_i)) * RECIPROCAL(MESH_Y_DIST), z1 = z_values[xi][y1_i]; return z1 + yratio * (z_values[xi][_MIN(y1_i, (GRID_MAX_POINTS_Y) - 2) + 1] - z1); // Don't allow y1_i+1 to be past the end of the array @@ -265,15 +264,16 @@ class unified_bed_leveling { #endif const uint8_t mx = _MIN(cx, (GRID_MAX_POINTS_X) - 2) + 1, my = _MIN(cy, (GRID_MAX_POINTS_Y) - 2) + 1; - const float z1 = calc_z0(rx0, mesh_index_to_xpos(cx), z_values[cx][cy], mesh_index_to_xpos(cx + 1), z_values[mx][cy]); - const float z2 = calc_z0(rx0, mesh_index_to_xpos(cx), z_values[cx][my], mesh_index_to_xpos(cx + 1), z_values[mx][my]); - float z0 = calc_z0(ry0, mesh_index_to_ypos(cy), z1, mesh_index_to_ypos(cy + 1), z2); + const float x0 = get_mesh_x(cx), x1 = get_mesh_x(cx + 1), + z1 = calc_z0(rx0, x0, z_values[cx][cy], x1, z_values[mx][cy]), + z2 = calc_z0(rx0, x0, z_values[cx][my], x1, z_values[mx][my]); + float z0 = calc_z0(ry0, get_mesh_y(cy), z1, get_mesh_y(cy + 1), z2); - if (isnan(z0)) { // if part of the Mesh is undefined, it will show up as NAN - z0 = 0.0; // in ubl.z_values[][] and propagate through the - // calculations. If our correction is NAN, we throw it out - // because part of the Mesh is undefined and we don't have the - // information we need to complete the height correction. + if (isnan(z0)) { // If part of the Mesh is undefined, it will show up as NAN + z0 = 0.0; // in z_values[][] and propagate through the calculations. + // If our correction is NAN, we throw it out because part of + // the Mesh is undefined and we don't have the information + // needed to complete the height correction. if (DEBUGGING(MESH_ADJUST)) DEBUG_ECHOLNPGM("??? Yikes! NAN in "); } @@ -285,12 +285,14 @@ class unified_bed_leveling { return z0; } - static inline float get_z_correction(const xy_pos_t &pos) { return get_z_correction(pos.x, pos.y); } + static float get_z_correction(const xy_pos_t &pos) { return get_z_correction(pos.x, pos.y); } - static inline float mesh_index_to_xpos(const uint8_t i) { + static constexpr float get_z_offset() { return 0.0f; } + + static float get_mesh_x(const uint8_t i) { return i < (GRID_MAX_POINTS_X) ? pgm_read_float(&_mesh_index_to_xpos[i]) : MESH_MIN_X + i * (MESH_X_DIST); } - static inline float mesh_index_to_ypos(const uint8_t i) { + static float get_mesh_y(const uint8_t i) { return i < (GRID_MAX_POINTS_Y) ? pgm_read_float(&_mesh_index_to_ypos[i]) : MESH_MIN_Y + i * (MESH_Y_DIST); } @@ -300,18 +302,14 @@ class unified_bed_leveling { static void line_to_destination_cartesian(const_feedRate_t scaled_fr_mm_s, const uint8_t e); #endif - static inline bool mesh_is_valid() { + static bool mesh_is_valid() { GRID_LOOP(x, y) if (isnan(z_values[x][y])) return false; return true; } }; // class unified_bed_leveling -extern unified_bed_leveling ubl; - -#define _GET_MESH_X(I) ubl.mesh_index_to_xpos(I) -#define _GET_MESH_Y(J) ubl.mesh_index_to_ypos(J) -#define Z_VALUES_ARR ubl.z_values +extern unified_bed_leveling bedlevel; // Prevent debugging propagating to other files #include "../../../core/debug_out.h" diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp index df83923f..bc07d7df 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp @@ -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" @@ -57,7 +56,7 @@ #define UBL_G29_P31 -#if HAS_LCD_MENU +#if HAS_MARLINUI_MENU bool unified_bed_leveling::lcd_map_control = false; @@ -316,12 +315,46 @@ void unified_bed_leveling::G29() { planner.synchronize(); // Send 'N' to force homing before G29 (internal only) if (axes_should_home() || parser.seen_test('N')) gcode.home_all_axes(); - TERN_(HAS_MULTI_HOTEND, if (active_extruder) tool_change(0)); + TERN_(HAS_MULTI_HOTEND, if (active_extruder != 0) tool_change(0, true)); + + // Position bed horizontally and Z probe vertically. + #if HAS_SAFE_BED_LEVELING + xyze_pos_t safe_position = current_position; + #ifdef SAFE_BED_LEVELING_START_X + safe_position.x = SAFE_BED_LEVELING_START_X; + #endif + #ifdef SAFE_BED_LEVELING_START_Y + safe_position.y = SAFE_BED_LEVELING_START_Y; + #endif + #ifdef SAFE_BED_LEVELING_START_Z + safe_position.z = SAFE_BED_LEVELING_START_Z; + #endif + #ifdef SAFE_BED_LEVELING_START_I + safe_position.i = SAFE_BED_LEVELING_START_I; + #endif + #ifdef SAFE_BED_LEVELING_START_J + safe_position.j = SAFE_BED_LEVELING_START_J; + #endif + #ifdef SAFE_BED_LEVELING_START_K + safe_position.k = SAFE_BED_LEVELING_START_K; + #endif + #ifdef SAFE_BED_LEVELING_START_U + safe_position.u = SAFE_BED_LEVELING_START_U; + #endif + #ifdef SAFE_BED_LEVELING_START_V + safe_position.v = SAFE_BED_LEVELING_START_V; + #endif + #ifdef SAFE_BED_LEVELING_START_W + safe_position.w = SAFE_BED_LEVELING_START_W; + #endif + + do_blocking_move_to(safe_position); + #endif // HAS_SAFE_BED_LEVELING } // Invalidate one or more nearby mesh points, possibly all. if (parser.seen('I')) { - uint8_t count = parser.has_value() ? parser.value_byte() : 1; + grid_count_t count = parser.has_value() ? parser.value_ushort() : 1; bool invalidate_all = count >= GRID_MAX_POINTS; if (!invalidate_all) { while (count--) { @@ -366,14 +399,14 @@ void unified_bed_leveling::G29() { break; case 1: - LOOP_L_N(x, GRID_MAX_POINTS_X) { // Create a diagonal line several Mesh cells thick that is raised + for (uint8_t x = 0; x < GRID_MAX_POINTS_X; ++x) { // Create a diagonal line several Mesh cells thick that is raised + const uint8_t x2 = x + (x < (GRID_MAX_POINTS_Y) - 1 ? 1 : -1); z_values[x][x] += 9.999f; - z_values[x][x + (x < (GRID_MAX_POINTS_Y) - 1) ? 1 : -1] += 9.999f; // We want the altered line several mesh points thick + z_values[x][x2] += 9.999f; // We want the altered line several mesh points thick #if ENABLED(EXTENSIBLE_UI) ExtUI::onMeshUpdate(x, x, z_values[x][x]); - ExtUI::onMeshUpdate(x, (x + (x < (GRID_MAX_POINTS_Y) - 1) ? 1 : -1), z_values[x][x + (x < (GRID_MAX_POINTS_Y) - 1) ? 1 : -1]); + ExtUI::onMeshUpdate(x, x2, z_values[x][x2]); #endif - } break; @@ -443,7 +476,7 @@ void unified_bed_leveling::G29() { #endif // HAS_BED_PROBE case 2: { - #if HAS_LCD_MENU + #if HAS_MARLINUI_MENU // // Manually Probe Mesh in areas that can't be reached by the probe // @@ -555,7 +588,7 @@ void unified_bed_leveling::G29() { } case 4: // Fine Tune (i.e., Edit) the Mesh - #if HAS_LCD_MENU + #if HAS_MARLINUI_MENU fine_tune_mesh(param.XY_pos, parser.seen_test('T')); #else SERIAL_ECHOLNPGM("?P4 is only available when an LCD is present."); @@ -587,7 +620,6 @@ void unified_bed_leveling::G29() { #endif // UBL_DEVEL_DEBUGGING - // // Load a Mesh from the EEPROM // @@ -646,7 +678,7 @@ void unified_bed_leveling::G29() { LEAVE: - #if HAS_LCD_MENU + #if HAS_MARLINUI_MENU ui.reset_alert_level(); ui.quick_feedback(); ui.reset_status(); @@ -663,7 +695,7 @@ void unified_bed_leveling::G29() { UNUSED(probe_deployed); #endif - TERN_(HAS_MULTI_HOTEND, tool_change(old_tool_index)); + TERN_(HAS_MULTI_HOTEND, if (old_tool_index != 0) tool_change(old_tool_index)); return; } @@ -725,21 +757,23 @@ void unified_bed_leveling::shift_mesh_height() { void unified_bed_leveling::probe_entire_mesh(const xy_pos_t &nearby, const bool do_ubl_mesh_map, const bool stow_probe, const bool do_furthest) { probe.deploy(); // Deploy before ui.capture() to allow for PAUSE_BEFORE_DEPLOY_STOW - TERN_(HAS_LCD_MENU, ui.capture()); + TERN_(HAS_MARLINUI_MENU, ui.capture()); + TERN_(EXTENSIBLE_UI, ExtUI::onLevelingStart()); + TERN_(DWIN_LCD_PROUI, DWIN_LevelingStart()); save_ubl_active_state_and_disable(); // No bed level correction so only raw data is obtained - uint8_t count = GRID_MAX_POINTS; + grid_count_t count = GRID_MAX_POINTS; mesh_index_pair best; TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(best.pos, ExtUI::G29_START)); do { if (do_ubl_mesh_map) display_map(param.T_map_type); - const uint8_t point_num = (GRID_MAX_POINTS - count) + 1; + const grid_count_t point_num = (GRID_MAX_POINTS - count) + 1; SERIAL_ECHOLNPGM("Probing mesh point ", point_num, "/", GRID_MAX_POINTS, "."); TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " %i/%i"), GET_TEXT(MSG_PROBING_POINT), point_num, int(GRID_MAX_POINTS))); - #if HAS_LCD_MENU + #if HAS_MARLINUI_MENU if (ui.button_pressed()) { ui.quick_feedback(false); // Preserve button state for click-and-hold SERIAL_ECHOLNPGM("\nMesh only partially populated.\n"); @@ -747,6 +781,7 @@ void unified_bed_leveling::shift_mesh_height() { ui.quick_feedback(); ui.release(); probe.stow(); // Release UI before stow to allow for PAUSE_BEFORE_DEPLOY_STOW + TERN_(EXTENSIBLE_UI, ExtUI::onLevelingDone()); return restore_ubl_active_state_and_leave(); } #endif @@ -774,9 +809,9 @@ void unified_bed_leveling::shift_mesh_height() { TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(best.pos, ExtUI::G29_FINISH)); // Release UI during stow to allow for PAUSE_BEFORE_DEPLOY_STOW - TERN_(HAS_LCD_MENU, ui.release()); + TERN_(HAS_MARLINUI_MENU, ui.release()); probe.stow(); - TERN_(HAS_LCD_MENU, ui.capture()); + TERN_(HAS_MARLINUI_MENU, ui.capture()); probe.move_z_after_probing(); @@ -786,12 +821,15 @@ void unified_bed_leveling::shift_mesh_height() { constrain(nearby.x - probe.offset_xy.x, MESH_MIN_X, MESH_MAX_X), constrain(nearby.y - probe.offset_xy.y, MESH_MIN_Y, MESH_MAX_Y) ); + + TERN_(EXTENSIBLE_UI, ExtUI::onLevelingDone()); + TERN_(DWIN_LCD_PROUI, DWIN_LevelingDone()); } #endif // HAS_BED_PROBE void set_message_with_feedback(FSTR_P const fstr) { - #if HAS_LCD_MENU + #if HAS_MARLINUI_MENU ui.set_status(fstr); ui.quick_feedback(); #else @@ -799,7 +837,7 @@ void set_message_with_feedback(FSTR_P const fstr) { #endif } -#if HAS_LCD_MENU +#if HAS_MARLINUI_MENU typedef void (*clickFunc_t)(); @@ -846,8 +884,32 @@ void set_message_with_feedback(FSTR_P const fstr) { ui.capture(); save_ubl_active_state_and_disable(); // Disable bed level correction for probing - do_blocking_move_to(0.5f * (MESH_MAX_X - (MESH_MIN_X)), 0.5f * (MESH_MAX_Y - (MESH_MIN_Y)), MANUAL_PROBE_START_Z); - //, _MIN(planner.settings.max_feedrate_mm_s[X_AXIS], planner.settings.max_feedrate_mm_s[Y_AXIS]) * 0.5f); + do_blocking_move_to( + xyz_pos_t({ + 0.5f * ((MESH_MAX_X) - (MESH_MIN_X)), + 0.5f * ((MESH_MAX_Y) - (MESH_MIN_Y)), + MANUAL_PROBE_START_Z + #ifdef SAFE_BED_LEVELING_START_I + , SAFE_BED_LEVELING_START_I + #endif + #ifdef SAFE_BED_LEVELING_START_J + , SAFE_BED_LEVELING_START_J + #endif + #ifdef SAFE_BED_LEVELING_START_K + , SAFE_BED_LEVELING_START_K + #endif + #ifdef SAFE_BED_LEVELING_START_U + , SAFE_BED_LEVELING_START_U + #endif + #ifdef SAFE_BED_LEVELING_START_V + , SAFE_BED_LEVELING_START_V + #endif + #ifdef SAFE_BED_LEVELING_START_W + , SAFE_BED_LEVELING_START_W + #endif + }) + //, _MIN(planner.settings.max_feedrate_mm_s[X_AXIS], planner.settings.max_feedrate_mm_s[Y_AXIS]) * 0.5f + ); planner.synchronize(); SERIAL_ECHOPGM("Place shim under nozzle"); @@ -885,6 +947,7 @@ void set_message_with_feedback(FSTR_P const fstr) { */ void unified_bed_leveling::manually_probe_remaining_mesh(const xy_pos_t &pos, const_float_t z_clearance, const_float_t thick, const bool do_ubl_mesh_map) { ui.capture(); + TERN_(EXTENSIBLE_UI, ExtUI::onLevelingStart()); save_ubl_active_state_and_disable(); // No bed level correction so only raw data is obtained do_blocking_move_to_xy_z(current_position, z_clearance); @@ -898,11 +961,7 @@ void set_message_with_feedback(FSTR_P const fstr) { // It doesn't matter if the probe can't reach the NAN location. This is a manual probe. if (!location.valid()) continue; - const xyz_pos_t ppos = { - mesh_index_to_xpos(lpos.x), - mesh_index_to_ypos(lpos.y), - z_clearance - }; + const xyz_pos_t ppos = { get_mesh_x(lpos.x), get_mesh_y(lpos.y), z_clearance }; if (!position_is_reachable(ppos)) break; // SHOULD NOT OCCUR (find_closest_mesh_point only returns reachable points) @@ -948,6 +1007,8 @@ void set_message_with_feedback(FSTR_P const fstr) { restore_ubl_active_state_and_leave(); do_blocking_move_to_xy_z(pos, Z_CLEARANCE_DEPLOY_PROBE); + + TERN_(EXTENSIBLE_UI, ExtUI::onLevelingDone()); } /** @@ -995,11 +1056,7 @@ void set_message_with_feedback(FSTR_P const fstr) { done_flags.mark(lpos); // Mark this location as 'adjusted' so a new // location is used on the next loop - const xyz_pos_t raw = { - mesh_index_to_xpos(lpos.x), - mesh_index_to_ypos(lpos.y), - Z_CLEARANCE_BETWEEN_PROBES - }; + const xyz_pos_t raw = { get_mesh_x(lpos.x), get_mesh_y(lpos.y), Z_CLEARANCE_BETWEEN_PROBES }; if (!position_is_reachable(raw)) break; // SHOULD NOT OCCUR (find_closest_mesh_point_of_type only returns reachable) @@ -1009,7 +1066,7 @@ void set_message_with_feedback(FSTR_P const fstr) { KEEPALIVE_STATE(PAUSED_FOR_USER); - if (do_ubl_mesh_map) display_map(param.T_map_type); // Display the current point + if (do_ubl_mesh_map) display_map(param.T_map_type); // Display the current point #if IS_TFTGLCD_PANEL ui.ubl_plot(lpos.x, lpos.y); // update plot screen @@ -1070,7 +1127,7 @@ void set_message_with_feedback(FSTR_P const fstr) { ui.return_to_status(); } -#endif // HAS_LCD_MENU +#endif // HAS_MARLINUI_MENU /** * Parse and validate most G29 parameters, store for use by G29 functions. @@ -1084,7 +1141,7 @@ bool unified_bed_leveling::G29_parse_parameters() { param.R_repetition = 0; if (parser.seen('R')) { - param.R_repetition = parser.has_value() ? parser.value_byte() : GRID_MAX_POINTS; + param.R_repetition = parser.has_value() ? parser.value_ushort() : GRID_MAX_POINTS; NOMORE(param.R_repetition, GRID_MAX_POINTS); if (param.R_repetition < 1) { SERIAL_ECHOLNPGM("?(R)epetition count invalid (1+).\n"); @@ -1210,7 +1267,7 @@ void unified_bed_leveling::save_ubl_active_state_and_disable() { } void unified_bed_leveling::restore_ubl_active_state_and_leave() { - TERN_(HAS_LCD_MENU, ui.release()); + TERN_(HAS_MARLINUI_MENU, ui.release()); #if ENABLED(UBL_DEVEL_DEBUGGING) if (--ubl_state_recursion_chk) { SERIAL_ECHOLNPGM("restore_ubl_active_state_and_leave() called too many times."); @@ -1219,6 +1276,7 @@ void unified_bed_leveling::restore_ubl_active_state_and_leave() { } #endif set_bed_leveling_enabled(ubl_state_at_invocation); + TERN_(EXTENSIBLE_UI, ExtUI::onLevelingDone()); } mesh_index_pair unified_bed_leveling::find_furthest_invalid_mesh_point() { @@ -1231,7 +1289,7 @@ mesh_index_pair unified_bed_leveling::find_furthest_invalid_mesh_point() { if (!isnan(z_values[i][j])) continue; // Skip valid mesh points // Skip unreachable points - if (!probe.can_reach(mesh_index_to_xpos(i), mesh_index_to_ypos(j))) + if (!probe.can_reach(get_mesh_x(i), get_mesh_y(j))) continue; found_a_NAN = true; @@ -1283,11 +1341,11 @@ mesh_index_pair unified_bed_leveling::find_furthest_invalid_mesh_point() { static bool test_func(uint8_t i, uint8_t j, void *data) { find_closest_t *d = (find_closest_t*)data; - if ( d->type == CLOSEST || d->type == (isnan(ubl.z_values[i][j]) ? INVALID : REAL) + if ( d->type == CLOSEST || d->type == (isnan(bedlevel.z_values[i][j]) ? INVALID : REAL) || (d->type == SET_IN_BITMAP && !d->done_flags->marked(i, j)) ) { // Found a Mesh Point of the specified type! - const xy_pos_t mpos = { ubl.mesh_index_to_xpos(i), ubl.mesh_index_to_ypos(j) }; + const xy_pos_t mpos = { bedlevel.get_mesh_x(i), bedlevel.get_mesh_y(j) }; // If using the probe as the reference there are some unreachable locations. // Also for round beds, there are grid points outside the bed the nozzle can't reach. @@ -1331,7 +1389,7 @@ mesh_index_pair unified_bed_leveling::find_closest_mesh_point_of_type(const Mesh || (type == SET_IN_BITMAP && !done_flags->marked(i, j)) ) { // Found a Mesh Point of the specified type! - const xy_pos_t mpos = { mesh_index_to_xpos(i), mesh_index_to_ypos(j) }; + const xy_pos_t mpos = { get_mesh_x(i), get_mesh_y(j) }; // If using the probe as the reference there are some unreachable locations. // Also for round beds, there are grid points outside the bed the nozzle can't reach. @@ -1387,13 +1445,13 @@ typedef struct { uint8_t sx, ex, sy, ey; bool yfirst; } smart_fill_info; void unified_bed_leveling::smart_fill_mesh() { static const smart_fill_info - info0 PROGMEM = { 0, GRID_MAX_POINTS_X, 0, GRID_MAX_POINTS_Y - 2, false }, // Bottom of the mesh looking up - info1 PROGMEM = { 0, GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y - 1, 0, false }, // Top of the mesh looking down - info2 PROGMEM = { 0, GRID_MAX_POINTS_X - 2, 0, GRID_MAX_POINTS_Y, true }, // Left side of the mesh looking right - info3 PROGMEM = { GRID_MAX_POINTS_X - 1, 0, 0, GRID_MAX_POINTS_Y, true }; // Right side of the mesh looking left + info0 PROGMEM = { 0, GRID_MAX_POINTS_X, 0, (GRID_MAX_POINTS_Y) - 2, false }, // Bottom of the mesh looking up + info1 PROGMEM = { 0, GRID_MAX_POINTS_X, (GRID_MAX_POINTS_Y) - 1, 0, false }, // Top of the mesh looking down + info2 PROGMEM = { 0, (GRID_MAX_POINTS_X) - 2, 0, GRID_MAX_POINTS_Y, true }, // Left side of the mesh looking right + info3 PROGMEM = { (GRID_MAX_POINTS_X) - 1, 0, 0, GRID_MAX_POINTS_Y, true }; // Right side of the mesh looking left static const smart_fill_info * const info[] PROGMEM = { &info0, &info1, &info2, &info3 }; - LOOP_L_N(i, COUNT(info)) { + for (uint8_t i = 0; i < COUNT(info); ++i) { const smart_fill_info *f = (smart_fill_info*)pgm_read_ptr(&info[i]); const int8_t sx = pgm_read_byte(&f->sx), sy = pgm_read_byte(&f->sy), ex = pgm_read_byte(&f->ex), ey = pgm_read_byte(&f->ey); @@ -1430,7 +1488,7 @@ void unified_bed_leveling::smart_fill_mesh() { float measured_z; bool abort_flag = false; - #ifdef VALIDATE_MESH_TILT + #if ENABLED(VALIDATE_MESH_TILT) float z1, z2, z3; // Needed for algorithm validation below #endif @@ -1446,9 +1504,7 @@ void unified_bed_leveling::smart_fill_mesh() { abort_flag = true; else { measured_z -= get_z_correction(points[0]); - #ifdef VALIDATE_MESH_TILT - z1 = measured_z; - #endif + TERN_(VALIDATE_MESH_TILT, z1 = measured_z); if (param.V_verbosity > 3) { serial_spaces(16); SERIAL_ECHOLNPGM("Corrected_Z=", measured_z); @@ -1461,9 +1517,7 @@ void unified_bed_leveling::smart_fill_mesh() { TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " 2/3"), GET_TEXT(MSG_LCD_TILTING_MESH))); measured_z = probe.probe_at_point(points[1], PROBE_PT_RAISE, param.V_verbosity); - #ifdef VALIDATE_MESH_TILT - z2 = measured_z; - #endif + TERN_(VALIDATE_MESH_TILT, z2 = measured_z); if (isnan(measured_z)) abort_flag = true; else { @@ -1481,9 +1535,7 @@ void unified_bed_leveling::smart_fill_mesh() { TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " 3/3"), GET_TEXT(MSG_LCD_TILTING_MESH))); measured_z = probe.probe_at_point(points[2], PROBE_PT_LAST_STOW, param.V_verbosity); - #ifdef VALIDATE_MESH_TILT - z3 = measured_z; - #endif + TERN_(VALIDATE_MESH_TILT, z3 = measured_z); if (isnan(measured_z)) abort_flag = true; else { @@ -1512,9 +1564,9 @@ void unified_bed_leveling::smart_fill_mesh() { uint16_t point_num = 1; xy_pos_t rpos; - LOOP_L_N(ix, param.J_grid_size) { + for (uint8_t ix = 0; ix < param.J_grid_size; ++ix) { rpos.x = x_min + ix * dx; - LOOP_L_N(iy, param.J_grid_size) { + for (uint8_t iy = 0; iy < param.J_grid_size; ++iy) { rpos.y = y_min + dy * (zig_zag ? param.J_grid_size - 1 - iy : iy); if (!abort_flag) { @@ -1561,7 +1613,7 @@ void unified_bed_leveling::smart_fill_mesh() { probe.move_z_after_probing(); if (abort_flag || finish_incremental_LSF(&lsf_results)) { - SERIAL_ECHOPGM("Could not complete LSF!"); + SERIAL_ECHOLNPGM("Could not complete LSF!"); return; } @@ -1579,9 +1631,7 @@ void unified_bed_leveling::smart_fill_mesh() { matrix_3x3 rotation = matrix_3x3::create_look_at(vector_3(lsf_results.A, lsf_results.B, 1)); GRID_LOOP(i, j) { - float mx = mesh_index_to_xpos(i), - my = mesh_index_to_ypos(j), - mz = z_values[i][j]; + float mx = get_mesh_x(i), my = get_mesh_y(j), mz = z_values[i][j]; if (DEBUGGING(LEVELING)) { DEBUG_ECHOPAIR_F("before rotation = [", mx, 7); @@ -1632,7 +1682,7 @@ void unified_bed_leveling::smart_fill_mesh() { * The Z error between the probed point locations and the get_z_correction() * numbers for those locations should be 0. */ - #ifdef VALIDATE_MESH_TILT + #if ENABLED(VALIDATE_MESH_TILT) auto d_from = []{ DEBUG_ECHOPGM("D from "); }; auto normed = [&](const xy_pos_t &pos, const_float_t zadd) { return normal.x * pos.x + normal.y * pos.y + zadd; @@ -1677,19 +1727,19 @@ void unified_bed_leveling::smart_fill_mesh() { GRID_LOOP(jx, jy) if (!isnan(z_values[jx][jy])) SBI(bitmap[jx], jy); xy_pos_t ppos; - LOOP_L_N(ix, GRID_MAX_POINTS_X) { - ppos.x = mesh_index_to_xpos(ix); - LOOP_L_N(iy, GRID_MAX_POINTS_Y) { - ppos.y = mesh_index_to_ypos(iy); + for (uint8_t ix = 0; ix < GRID_MAX_POINTS_X; ++ix) { + ppos.x = get_mesh_x(ix); + for (uint8_t iy = 0; iy < GRID_MAX_POINTS_Y; ++iy) { + ppos.y = get_mesh_y(iy); if (isnan(z_values[ix][iy])) { // undefined mesh point at (ppos.x,ppos.y), compute weighted LSF from original valid mesh points. incremental_LSF_reset(&lsf_results); xy_pos_t rpos; - LOOP_L_N(jx, GRID_MAX_POINTS_X) { - rpos.x = mesh_index_to_xpos(jx); - LOOP_L_N(jy, GRID_MAX_POINTS_Y) { + for (uint8_t jx = 0; jx < GRID_MAX_POINTS_X; ++jx) { + rpos.x = get_mesh_x(jx); + for (uint8_t jy = 0; jy < GRID_MAX_POINTS_Y; ++jy) { if (TEST(bitmap[jx], jy)) { - rpos.y = mesh_index_to_ypos(jy); + rpos.y = get_mesh_y(jy); const float rz = z_values[jx][jy], w = 1.0f + weight_scaled / (rpos - ppos).magnitude(); incremental_WLSF(&lsf_results, rpos, rz, w); @@ -1697,7 +1747,7 @@ void unified_bed_leveling::smart_fill_mesh() { } } if (finish_incremental_LSF(&lsf_results)) { - SERIAL_ECHOLNPGM("Insufficient data"); + SERIAL_ECHOLNPGM(" Insufficient data"); return; } const float ez = -lsf_results.D - lsf_results.A * ppos.x - lsf_results.B * ppos.y; @@ -1708,7 +1758,7 @@ void unified_bed_leveling::smart_fill_mesh() { } } - SERIAL_ECHOLNPGM("done"); + SERIAL_ECHOLNPGM(" done."); } #endif // UBL_G29_P31 @@ -1721,10 +1771,9 @@ void unified_bed_leveling::smart_fill_mesh() { report_state(); if (storage_slot == -1) - SERIAL_ECHOPGM("No Mesh Loaded."); + SERIAL_ECHOLNPGM("No Mesh Loaded."); else - SERIAL_ECHOPGM("Mesh ", storage_slot, " Loaded."); - SERIAL_EOL(); + SERIAL_ECHOLNPGM("Mesh ", storage_slot, " Loaded."); serial_delay(50); #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) @@ -1747,16 +1796,16 @@ void unified_bed_leveling::smart_fill_mesh() { SERIAL_ECHOLNPGM("MESH_Y_DIST ", MESH_Y_DIST); serial_delay(50); SERIAL_ECHOPGM("X-Axis Mesh Points at: "); - LOOP_L_N(i, GRID_MAX_POINTS_X) { - SERIAL_ECHO_F(LOGICAL_X_POSITION(mesh_index_to_xpos(i)), 3); + for (uint8_t i = 0; i < GRID_MAX_POINTS_X; ++i) { + SERIAL_ECHO_F(LOGICAL_X_POSITION(get_mesh_x(i)), 3); SERIAL_ECHOPGM(" "); serial_delay(25); } SERIAL_EOL(); SERIAL_ECHOPGM("Y-Axis Mesh Points at: "); - LOOP_L_N(i, GRID_MAX_POINTS_Y) { - SERIAL_ECHO_F(LOGICAL_Y_POSITION(mesh_index_to_ypos(i)), 3); + for (uint8_t i = 0; i < GRID_MAX_POINTS_Y; ++i) { + SERIAL_ECHO_F(LOGICAL_Y_POSITION(get_mesh_y(i)), 3); SERIAL_ECHOPGM(" "); serial_delay(25); } @@ -1769,23 +1818,21 @@ void unified_bed_leveling::smart_fill_mesh() { SERIAL_EOL(); serial_delay(50); - #if ENABLED(UBL_DEVEL_DEBUGGING) - SERIAL_ECHOLNPGM("ubl_state_at_invocation :", ubl_state_at_invocation, "\nubl_state_recursion_chk :", ubl_state_recursion_chk); - serial_delay(50); + SERIAL_ECHOLNPGM("ubl_state_at_invocation :", ubl_state_at_invocation, "\nubl_state_recursion_chk :", ubl_state_recursion_chk); + serial_delay(50); - SERIAL_ECHOLNPGM("Meshes go from ", hex_address((void*)settings.meshes_start_index()), " to ", hex_address((void*)settings.meshes_end_index())); - serial_delay(50); + SERIAL_ECHOLNPGM("Meshes go from ", hex_address((void*)settings.meshes_start_index()), " to ", hex_address((void*)settings.meshes_end_index())); + serial_delay(50); - SERIAL_ECHOLNPGM("sizeof(ubl) : ", sizeof(ubl)); SERIAL_EOL(); - SERIAL_ECHOLNPGM("z_value[][] size: ", sizeof(z_values)); SERIAL_EOL(); - serial_delay(25); + SERIAL_ECHOLNPGM("sizeof(unified_bed_leveling) : ", sizeof(unified_bed_leveling)); + SERIAL_ECHOLNPGM("z_value[][] size: ", sizeof(z_values)); + serial_delay(25); - SERIAL_ECHOLNPGM("EEPROM free for UBL: ", hex_address((void*)(settings.meshes_end_index() - settings.meshes_start_index()))); - serial_delay(50); + SERIAL_ECHOLNPGM("EEPROM free for UBL: ", hex_address((void*)(settings.meshes_end_index() - settings.meshes_start_index()))); + serial_delay(50); - SERIAL_ECHOLNPGM("EEPROM can hold ", settings.calc_num_meshes(), " meshes.\n"); - serial_delay(25); - #endif // UBL_DEVEL_DEBUGGING + SERIAL_ECHOLNPGM("EEPROM can hold ", settings.calc_num_meshes(), " meshes.\n"); + serial_delay(25); if (!sanity_check()) { echo_name(); @@ -1807,7 +1854,8 @@ void unified_bed_leveling::smart_fill_mesh() { print_hex_word(i); SERIAL_ECHOPGM(": "); for (uint16_t j = 0; j < 16; j++) { - persistentStore.read_data(i + j, &cccc, sizeof(uint8_t)); + int pos = i + j; + persistentStore.read_data(pos, &cccc, sizeof(uint8_t)); print_hex_byte(cccc); SERIAL_CHAR(' '); } diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp index f7e98c9f..6c6075af 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp @@ -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 +//#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 @@ -52,7 +61,7 @@ const xyze_pos_t &start = current_position, &end = destination; #endif - const xy_int8_t istart = cell_indexes(start), iend = cell_indexes(end); + const xy_uint8_t istart = cell_indexes(start), iend = cell_indexes(end); // A move within the same cell needs no splitting if (istart == iend) { @@ -76,8 +85,8 @@ #endif // The distance is always MESH_X_DIST so multiply by the constant reciprocal. - const float xratio = (end.x - mesh_index_to_xpos(iend.x)) * RECIPROCAL(MESH_X_DIST), - yratio = (end.y - mesh_index_to_ypos(iend.y)) * RECIPROCAL(MESH_Y_DIST), + const float xratio = (end.x - get_mesh_x(iend.x)) * RECIPROCAL(MESH_X_DIST), + yratio = (end.y - get_mesh_y(iend.y)) * RECIPROCAL(MESH_Y_DIST), z1 = z_values[iend.x][iend.y ] + xratio * (z_values[iend.x + 1][iend.y ] - z_values[iend.x][iend.y ]), z2 = z_values[iend.x][iend.y + 1] + xratio * (z_values[iend.x + 1][iend.y + 1] - z_values[iend.x][iend.y + 1]); @@ -99,7 +108,7 @@ const xy_float_t dist = end - start; const xy_bool_t neg { dist.x < 0, dist.y < 0 }; - const xy_int8_t ineg { int8_t(neg.x), int8_t(neg.y) }; + const xy_uint8_t ineg { uint8_t(neg.x), uint8_t(neg.y) }; const xy_float_t sign { neg.x ? -1.0f : 1.0f, neg.y ? -1.0f : 1.0f }; const xy_int8_t iadd { int8_t(iend.x == istart.x ? 0 : sign.x), int8_t(iend.y == istart.y ? 0 : sign.y) }; @@ -122,7 +131,7 @@ const bool inf_normalized_flag = isinf(e_normalized_dist); #endif - xy_int8_t icell = istart; + xy_uint8_t icell = istart; const float ratio = dist.y / dist.x, // Allow divide by zero c = start.y - ratio * start.x; @@ -139,7 +148,7 @@ icell.y += ineg.y; // Line going down? Just go to the bottom. while (icell.y != iend.y + ineg.y) { icell.y += iadd.y; - const float next_mesh_line_y = mesh_index_to_ypos(icell.y); + const float next_mesh_line_y = get_mesh_y(icell.y); /** * Skip the calculations for an infinite slope. @@ -155,7 +164,7 @@ // Replace NAN corrections with 0.0 to prevent NAN propagation. if (isnan(z0)) z0 = 0.0; - dest.y = mesh_index_to_ypos(icell.y); + dest.y = get_mesh_y(icell.y); /** * Without this check, it's possible to generate a zero length move, as in the case where @@ -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. @@ -196,7 +207,7 @@ while (icell.x != iend.x + ineg.x) { icell.x += iadd.x; - dest.x = mesh_index_to_xpos(icell.x); + dest.x = get_mesh_x(icell.x); dest.y = ratio * dest.x + c; // Calculate Y at the next X mesh line float z0 = z_correction_for_y_on_vertical_mesh_line(dest.y, icell.x, icell.y) @@ -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)) @@ -239,14 +252,14 @@ * Generic case of a line crossing both X and Y Mesh lines. */ - xy_int8_t cnt = (istart - iend).ABS(); + xy_uint8_t cnt = istart.diff(iend); icell += ineg; while (cnt) { - const float next_mesh_line_x = mesh_index_to_xpos(icell.x + iadd.x), - next_mesh_line_y = mesh_index_to_ypos(icell.y + iadd.y); + const float next_mesh_line_x = get_mesh_x(icell.x + iadd.x), + next_mesh_line_y = get_mesh_y(icell.y + iadd.y); dest.y = ratio * next_mesh_line_x + c; // Calculate Y at the next X mesh line dest.x = (next_mesh_line_y - c) / ratio; // Calculate X at the next Y mesh line @@ -321,16 +334,14 @@ #else // UBL_SEGMENTED #if IS_SCARA - #define DELTA_SEGMENT_MIN_LENGTH 0.25 // SCARA minimum segment size is 0.25mm - #elif ENABLED(DELTA) - #define DELTA_SEGMENT_MIN_LENGTH 0.10 // mm (still subject to DELTA_SEGMENTS_PER_SECOND) - #elif ENABLED(POLARGRAPH) - #define DELTA_SEGMENT_MIN_LENGTH 0.10 // mm (still subject to DELTA_SEGMENTS_PER_SECOND) + #define SEGMENT_MIN_LENGTH 0.25 // SCARA minimum segment size is 0.25mm + #elif IS_KINEMATIC + #define SEGMENT_MIN_LENGTH 0.10 // (mm) Still subject to DEFAULT_SEGMENTS_PER_SECOND #else // CARTESIAN #ifdef LEVELED_SEGMENT_LENGTH - #define DELTA_SEGMENT_MIN_LENGTH LEVELED_SEGMENT_LENGTH + #define SEGMENT_MIN_LENGTH LEVELED_SEGMENT_LENGTH #else - #define DELTA_SEGMENT_MIN_LENGTH 1.00 // mm (similar to G2/G3 arc segmentation) + #define SEGMENT_MIN_LENGTH 1.00 // (mm) Similar to G2/G3 arc segmentation #endif #endif @@ -340,7 +351,7 @@ * Returns true if did NOT move, false if moved (requires current_position update). */ - bool _O2 unified_bed_leveling::line_to_destination_segmented(const_feedRate_t scaled_fr_mm_s) { + bool __O2 unified_bed_leveling::line_to_destination_segmented(const_feedRate_t scaled_fr_mm_s) { if (!position_is_reachable(destination)) // fail if moving outside reachable boundary return true; // did not move, so current_position still accurate @@ -348,23 +359,24 @@ const xyze_pos_t total = destination - current_position; const float cart_xy_mm_2 = HYPOT2(total.x, total.y), - cart_xy_mm = SQRT(cart_xy_mm_2); // Total XY distance + cart_xy_mm = SQRT(cart_xy_mm_2); // Total XY distance #if IS_KINEMATIC - const float seconds = cart_xy_mm / scaled_fr_mm_s; // Duration of XY move at requested rate - uint16_t segments = LROUND(segments_per_second * seconds), // Preferred number of segments for distance @ feedrate - seglimit = LROUND(cart_xy_mm * RECIPROCAL(DELTA_SEGMENT_MIN_LENGTH)); // Number of segments at minimum segment length - NOMORE(segments, seglimit); // Limit to minimum segment length (fewer segments) + const float seconds = cart_xy_mm / scaled_fr_mm_s; // Duration of XY move at requested rate + uint16_t segments = LROUND(segments_per_second * seconds), // Preferred number of segments for distance @ feedrate + seglimit = LROUND(cart_xy_mm * RECIPROCAL(SEGMENT_MIN_LENGTH)); // Number of segments at minimum segment length + NOMORE(segments, seglimit); // Limit to minimum segment length (fewer segments) #else - uint16_t segments = LROUND(cart_xy_mm * RECIPROCAL(DELTA_SEGMENT_MIN_LENGTH)); // Cartesian fixed segment length + uint16_t segments = LROUND(cart_xy_mm * RECIPROCAL(SEGMENT_MIN_LENGTH)); // Cartesian fixed segment length #endif - NOLESS(segments, 1U); // Must have at least one segment - const float inv_segments = 1.0f / segments, // Reciprocal to save calculation - segment_xyz_mm = SQRT(cart_xy_mm_2 + sq(total.z)) * inv_segments; // Length of each segment + NOLESS(segments, 1U); // Must have at least one segment + const float inv_segments = 1.0f / segments; // Reciprocal to save calculation + // Add hints to help optimize the move + PlannerHints hints(SQRT(cart_xy_mm_2 + sq(total.z)) * inv_segments); // Length of each segment #if ENABLED(SCARA_FEEDRATE_SCALING) - const float inv_duration = scaled_fr_mm_s / segment_xyz_mm; + hints.inv_duration = scaled_fr_mm_s / hints.millimeters; #endif xyze_float_t diff = total * inv_segments; @@ -378,13 +390,9 @@ if (!planner.leveling_active || !planner.leveling_active_at_z(destination.z)) { while (--segments) { raw += diff; - planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, segment_xyz_mm - OPTARG(SCARA_FEEDRATE_SCALING, inv_duration) - ); + planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, hints); } - planner.buffer_line(destination, scaled_fr_mm_s, active_extruder, segment_xyz_mm - OPTARG(SCARA_FEEDRATE_SCALING, inv_duration) - ); + planner.buffer_line(destination, scaled_fr_mm_s, active_extruder, hints); return false; // Did not set current from destination } @@ -413,17 +421,19 @@ LIMIT(icell.x, 0, GRID_MAX_CELLS_X); LIMIT(icell.y, 0, GRID_MAX_CELLS_Y); - float z_x0y0 = z_values[icell.x ][icell.y ], // z at lower left corner - z_x1y0 = z_values[icell.x+1][icell.y ], // z at upper left corner - z_x0y1 = z_values[icell.x ][icell.y+1], // z at lower right corner - z_x1y1 = z_values[icell.x+1][icell.y+1]; // z at upper right corner + const int8_t ncellx = _MIN(icell.x+1, GRID_MAX_CELLS_X), + ncelly = _MIN(icell.y+1, GRID_MAX_CELLS_Y); + float z_x0y0 = z_values[icell.x][icell.y], // z at lower left corner + z_x1y0 = z_values[ncellx ][icell.y], // z at upper left corner + z_x0y1 = z_values[icell.x][ncelly ], // z at lower right corner + z_x1y1 = z_values[ncellx ][ncelly ]; // z at upper right corner if (isnan(z_x0y0)) z_x0y0 = 0; // ideally activating planner.leveling_active (G29 A) if (isnan(z_x1y0)) z_x1y0 = 0; // should refuse if any invalid mesh points if (isnan(z_x0y1)) z_x0y1 = 0; // in order to avoid isnan tests per cell, if (isnan(z_x1y1)) z_x1y1 = 0; // thus guessing zero for undefined points - const xy_pos_t pos = { mesh_index_to_xpos(icell.x), mesh_index_to_ypos(icell.y) }; + const xy_pos_t pos = { get_mesh_x(icell.x), get_mesh_y(icell.y) }; xy_pos_t cell = raw - pos; const float z_xmy0 = (z_x1y0 - z_x0y0) * RECIPROCAL(MESH_X_DIST), // z slope per x along y0 (lower left to lower right) @@ -450,13 +460,10 @@ if (--segments == 0) raw = destination; // if this is last segment, use destination for exact const float z_cxcy = (z_cxy0 + z_cxym * cell.y) // interpolated mesh z height along cell.x at cell.y - #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) - * fade_scaling_factor // apply fade factor to interpolated mesh height - #endif - ; + TERN_(ENABLE_LEVELING_FADE_HEIGHT, * fade_scaling_factor); // apply fade factor to interpolated height const float oldz = raw.z; raw.z += z_cxcy; - planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, segment_xyz_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration) ); + planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, hints); raw.z = oldz; if (segments == 0) // done with last segment diff --git a/Marlin/src/feature/binary_stream.h b/Marlin/src/feature/binary_stream.h index 417e39c7..a9cd12b8 100644 --- a/Marlin/src/feature/binary_stream.h +++ b/Marlin/src/feature/binary_stream.h @@ -281,7 +281,7 @@ class BinaryStream { uint8_t data = 0; millis_t transfer_window = millis() + RX_TIMESLICE; - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA PORT_REDIRECT(SERIAL_PORTMASK(card.transfer_port_index)); #endif diff --git a/Marlin/src/feature/bltouch.cpp b/Marlin/src/feature/bltouch.cpp index b1cc30be..1c6c1eb4 100644 --- a/Marlin/src/feature/bltouch.cpp +++ b/Marlin/src/feature/bltouch.cpp @@ -38,15 +38,18 @@ bool BLTouch::od_5v_mode; // Initialized by settings.load, 0 = Open Drai #include "../module/servo.h" #include "../module/probe.h" -void stop(); - #define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE) #include "../core/debug_out.h" 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); - safe_delay(_MAX(ms, (uint32_t)BLTOUCH_DELAY)); // BLTOUCH_DELAY is also the *minimum* delay + const BLTCommand current = servo[Z_PROBE_SERVO_NR].read(); + if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("BLTouch from ", current, " to ", cmd); + // If the new command is the same, skip it (and the delay). + // The previous write should've already delayed to detect the alarm. + if (cmd != current) { + servo[Z_PROBE_SERVO_NR].move(cmd); + safe_delay(_MAX(ms, (uint32_t)BLTOUCH_DELAY)); // BLTOUCH_DELAY is also the *minimum* delay + } return triggered(); } @@ -111,11 +114,8 @@ bool BLTouch::deploy_proc() { // Last attempt to DEPLOY if (_deploy_query_alarm()) { // The deploy might have failed or the probe is actually triggered (nozzle too low?) again - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("BLTouch Recovery Failed"); - - SERIAL_ERROR_MSG(STR_STOP_BLTOUCH); // Tell the user something is wrong, needs action - stop(); // but it's not too bad, no need to kill, allow restart - + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("BLTouch Deploy Failed"); + probe.probe_error_stop(); // Something is wrong, needs action, but not too bad, allow restart return true; // Tell our caller we goofed in case he cares to know } } @@ -153,12 +153,8 @@ bool BLTouch::stow_proc() { // But one more STOW will catch that // Last attempt to STOW if (_stow_query_alarm()) { // so if there is now STILL an ALARM condition: - - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("BLTouch Recovery Failed"); - - SERIAL_ERROR_MSG(STR_STOP_BLTOUCH); // Tell the user something is wrong, needs action - stop(); // but it's not too bad, no need to kill, allow restart - + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("BLTouch Stow Failed"); + probe.probe_error_stop(); // Something is wrong, needs action, but not too bad, allow restart return true; // Tell our caller we goofed in case he cares to know } } diff --git a/Marlin/src/feature/bltouch.h b/Marlin/src/feature/bltouch.h index ae3ab663..fa857bb9 100644 --- a/Marlin/src/feature/bltouch.h +++ b/Marlin/src/feature/bltouch.h @@ -76,7 +76,7 @@ class BLTouch { static constexpr bool high_speed_mode = false; #endif - static inline float z_extra_clearance() { return high_speed_mode ? 7 : 0; } + static float z_extra_clearance() { return high_speed_mode ? 7 : 0; } // DEPLOY and STOW are wrapped for error handling - these are used by homing and by probing static bool deploy() { return deploy_proc(); } diff --git a/Marlin/src/feature/cancel_object.cpp b/Marlin/src/feature/cancel_object.cpp index bffd2bb7..9b658315 100644 --- a/Marlin/src/feature/cancel_object.cpp +++ b/Marlin/src/feature/cancel_object.cpp @@ -44,7 +44,7 @@ void CancelObject::set_active_object(const int8_t obj) { else skipping = false; - #if BOTH(HAS_STATUS_MESSAGE, CANCEL_OBJECTS_REPORTING) + #if ALL(HAS_STATUS_MESSAGE, CANCEL_OBJECTS_REPORTING) if (active_object >= 0) ui.status_printf(0, F(S_FMT " %i"), GET_TEXT(MSG_PRINTING_OBJECT), int(active_object)); else diff --git a/Marlin/src/feature/cancel_object.h b/Marlin/src/feature/cancel_object.h index 1d2d77f2..62548a37 100644 --- a/Marlin/src/feature/cancel_object.h +++ b/Marlin/src/feature/cancel_object.h @@ -32,10 +32,10 @@ class CancelObject { static void cancel_object(const int8_t obj); static void uncancel_object(const int8_t obj); static void report(); - static inline bool is_canceled(const int8_t obj) { return TEST(canceled, obj); } - static inline void clear_active_object() { set_active_object(-1); } - static inline void cancel_active_object() { cancel_object(active_object); } - static inline void reset() { canceled = 0x0000; object_count = 0; clear_active_object(); } + static bool is_canceled(const int8_t obj) { return TEST(canceled, obj); } + static void clear_active_object() { set_active_object(-1); } + static void cancel_active_object() { cancel_object(active_object); } + static void reset() { canceled = 0x0000; object_count = 0; clear_active_object(); } }; extern CancelObject cancelable; diff --git a/Marlin/src/feature/caselight.cpp b/Marlin/src/feature/caselight.cpp index 59832fd6..eb580a6d 100644 --- a/Marlin/src/feature/caselight.cpp +++ b/Marlin/src/feature/caselight.cpp @@ -64,12 +64,22 @@ void CaseLight::update(const bool sflag) { #endif #if CASE_LIGHT_IS_COLOR_LED - leds.set_color(LEDColor(color.r, color.g, color.b OPTARG(HAS_WHITE_LED, color.w) OPTARG(NEOPIXEL_LED, n10ct))); + #if ENABLED(CASE_LIGHT_USE_NEOPIXEL) + if (on) + // Use current color of (NeoPixel) leds and new brightness level + leds.set_color(LEDColor(leds.color.r, leds.color.g, leds.color.b OPTARG(HAS_WHITE_LED, leds.color.w) OPTARG(NEOPIXEL_LED, n10ct))); + else + // Switch off leds + leds.set_off(); + #else + // Use CaseLight color (CASE_LIGHT_DEFAULT_COLOR) and new brightness level + leds.set_color(LEDColor(color.r, color.g, color.b OPTARG(HAS_WHITE_LED, color.w) OPTARG(NEOPIXEL_LED, n10ct))); + #endif #else // !CASE_LIGHT_IS_COLOR_LED #if CASELIGHT_USES_BRIGHTNESS if (pin_is_pwm()) - set_pwm_duty(pin_t(CASE_LIGHT_PIN), ( + hal.set_pwm_duty(pin_t(CASE_LIGHT_PIN), ( #if CASE_LIGHT_MAX_PWM == 255 n10ct #else diff --git a/Marlin/src/feature/caselight.h b/Marlin/src/feature/caselight.h index b2e82f9b..d88b3d67 100644 --- a/Marlin/src/feature/caselight.h +++ b/Marlin/src/feature/caselight.h @@ -27,14 +27,10 @@ #include "leds/leds.h" // for LEDColor #endif -#if NONE(CASE_LIGHT_NO_BRIGHTNESS, CASE_LIGHT_IS_COLOR_LED) || ENABLED(CASE_LIGHT_USE_NEOPIXEL) - #define CASELIGHT_USES_BRIGHTNESS 1 -#endif - class CaseLight { public: static bool on; - #if ENABLED(CASELIGHT_USES_BRIGHTNESS) + #if CASELIGHT_USES_BRIGHTNESS static uint8_t brightness; #endif @@ -49,8 +45,8 @@ class CaseLight { } static void update(const bool sflag); - static inline void update_brightness() { update(false); } - static inline void update_enabled() { update(true); } + static void update_brightness() { update(false); } + static void update_enabled() { update(true); } #if ENABLED(CASE_LIGHT_IS_COLOR_LED) private: diff --git a/Marlin/src/feature/controllerfan.cpp b/Marlin/src/feature/controllerfan.cpp index 59ba665e..a64f2e68 100644 --- a/Marlin/src/feature/controllerfan.cpp +++ b/Marlin/src/feature/controllerfan.cpp @@ -38,8 +38,15 @@ uint8_t ControllerFan::speed; const controllerFan_settings_t &ControllerFan::settings = controllerFan_defaults; #endif +#if ENABLED(FAN_SOFT_PWM) + uint8_t ControllerFan::soft_pwm_speed; +#endif + void ControllerFan::setup() { SET_OUTPUT(CONTROLLER_FAN_PIN); + #ifdef CONTROLLER_FAN2_PIN + SET_OUTPUT(CONTROLLER_FAN2_PIN); + #endif init(); } @@ -72,13 +79,36 @@ void ControllerFan::update() { ? settings.active_speed : settings.idle_speed ); + speed = CALC_FAN_SPEED(speed); + + #if FAN_KICKSTART_TIME + static millis_t fan_kick_end = 0; + if (speed > FAN_OFF_PWM) { + if (!fan_kick_end) { + fan_kick_end = ms + FAN_KICKSTART_TIME; // May be longer based on slow update interval for controller fn check. Sets minimum + speed = FAN_KICKSTART_POWER; + } + else if (PENDING(ms, fan_kick_end)) + speed = FAN_KICKSTART_POWER; + } + else + fan_kick_end = 0; + #endif + #if ENABLED(FAN_SOFT_PWM) - thermalManager.soft_pwm_controller_speed = speed; + soft_pwm_speed = speed; #else if (PWM_PIN(CONTROLLER_FAN_PIN)) - set_pwm_duty(pin_t(CONTROLLER_FAN_PIN), speed); + hal.set_pwm_duty(pin_t(CONTROLLER_FAN_PIN), speed); else WRITE(CONTROLLER_FAN_PIN, speed > 0); + + #ifdef CONTROLLER_FAN2_PIN + if (PWM_PIN(CONTROLLER_FAN2_PIN)) + hal.set_pwm_duty(pin_t(CONTROLLER_FAN2_PIN), speed); + else + WRITE(CONTROLLER_FAN2_PIN, speed > 0); + #endif #endif } } diff --git a/Marlin/src/feature/controllerfan.h b/Marlin/src/feature/controllerfan.h index 55f2d5cf..68502afa 100644 --- a/Marlin/src/feature/controllerfan.h +++ b/Marlin/src/feature/controllerfan.h @@ -60,9 +60,12 @@ class ControllerFan { #else static const controllerFan_settings_t &settings; #endif - static inline bool state() { return speed > 0; } - static inline void init() { reset(); } - static inline void reset() { TERN_(CONTROLLER_FAN_EDITABLE, settings = controllerFan_defaults); } + #if ENABLED(FAN_SOFT_PWM) + static uint8_t soft_pwm_speed; + #endif + static bool state() { return speed > 0; } + static void init() { reset(); } + static void reset() { TERN_(CONTROLLER_FAN_EDITABLE, settings = controllerFan_defaults); } static void setup(); static void update(); }; diff --git a/Marlin/src/feature/cooler.cpp b/Marlin/src/feature/cooler.cpp index e0f99777..6c45e992 100644 --- a/Marlin/src/feature/cooler.cpp +++ b/Marlin/src/feature/cooler.cpp @@ -22,7 +22,7 @@ #include "../inc/MarlinConfig.h" -#if EITHER(HAS_COOLER, LASER_COOLANT_FLOW_METER) +#if ANY(HAS_COOLER, LASER_COOLANT_FLOW_METER) #include "cooler.h" Cooler cooler; diff --git a/Marlin/src/feature/dac/dac_dac084s085.cpp b/Marlin/src/feature/dac/dac_dac084s085.cpp index b88aaf80..772bb68d 100644 --- a/Marlin/src/feature/dac/dac_dac084s085.cpp +++ b/Marlin/src/feature/dac/dac_dac084s085.cpp @@ -11,7 +11,6 @@ #include "dac_dac084s085.h" #include "../../MarlinCore.h" -#include "../../module/stepper.h" #include "../../HAL/shared/Delay.h" dac084s085::dac084s085() { } diff --git a/Marlin/src/feature/dac/stepper_dac.cpp b/Marlin/src/feature/dac/stepper_dac.cpp index ff730e93..f5664bc5 100644 --- a/Marlin/src/feature/dac/stepper_dac.cpp +++ b/Marlin/src/feature/dac/stepper_dac.cpp @@ -29,7 +29,6 @@ #if HAS_MOTOR_CURRENT_DAC #include "stepper_dac.h" -#include "../../MarlinCore.h" // for SP_X_LBL... bool dac_present = false; constexpr xyze_uint8_t dac_order = DAC_STEPPER_ORDER; @@ -60,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)); @@ -85,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 diff --git a/Marlin/src/feature/digipot/digipot_mcp4018.cpp b/Marlin/src/feature/digipot/digipot_mcp4018.cpp index 37853ff4..48d7ff49 100644 --- a/Marlin/src/feature/digipot/digipot_mcp4018.cpp +++ b/Marlin/src/feature/digipot/digipot_mcp4018.cpp @@ -31,8 +31,12 @@ // Settings for the I2C based DIGIPOT (MCP4018) based on WT150 -#define DIGIPOT_A4988_Rsx 0.250 -#define DIGIPOT_A4988_Vrefmax 1.666 +#ifndef DIGIPOT_A4988_Rsx + #define DIGIPOT_A4988_Rsx 0.250 +#endif +#ifndef DIGIPOT_A4988_Vrefmax + #define DIGIPOT_A4988_Vrefmax 1.666 +#endif #define DIGIPOT_MCP4018_MAX_VALUE 127 #define DIGIPOT_A4988_Itripmax(Vref) ((Vref) / (8.0 * DIGIPOT_A4988_Rsx)) @@ -85,7 +89,7 @@ void DigipotI2C::set_current(const uint8_t channel, const float current) { } void DigipotI2C::init() { - LOOP_L_N(i, DIGIPOT_I2C_NUM_CHANNELS) pots[i].i2c_init(); + for (uint8_t i = 0; i < DIGIPOT_I2C_NUM_CHANNELS; ++i) pots[i].i2c_init(); // Init currents according to Configuration_adv.h static const float digipot_motor_current[] PROGMEM = @@ -95,7 +99,7 @@ void DigipotI2C::init() { DIGIPOT_I2C_MOTOR_CURRENTS #endif ; - LOOP_L_N(i, COUNT(digipot_motor_current)) + for (uint8_t i = 0; i < COUNT(digipot_motor_current); ++i) set_current(i, pgm_read_float(&digipot_motor_current[i])); } diff --git a/Marlin/src/feature/digipot/digipot_mcp4451.cpp b/Marlin/src/feature/digipot/digipot_mcp4451.cpp index ba5ecdad..e35b42a2 100644 --- a/Marlin/src/feature/digipot/digipot_mcp4451.cpp +++ b/Marlin/src/feature/digipot/digipot_mcp4451.cpp @@ -35,8 +35,8 @@ // Settings for the I2C based DIGIPOT (MCP4451) on Azteeg X3 Pro #if MB(5DPRINT) - #define DIGIPOT_I2C_FACTOR 117.96f - #define DIGIPOT_I2C_MAX_CURRENT 1.736f + #define DIGIPOT_I2C_FACTOR 117.96f + #define DIGIPOT_I2C_MAX_CURRENT 1.736f #elif MB(AZTEEG_X5_MINI, AZTEEG_X5_MINI_WIFI) #define DIGIPOT_I2C_FACTOR 113.5f #define DIGIPOT_I2C_MAX_CURRENT 2.0f @@ -94,7 +94,7 @@ void DigipotI2C::init() { DIGIPOT_I2C_MOTOR_CURRENTS #endif ; - LOOP_L_N(i, COUNT(digipot_motor_current)) + for (uint8_t i = 0; i < COUNT(digipot_motor_current); ++i) set_current(i, pgm_read_float(&digipot_motor_current[i])); } diff --git a/Marlin/src/feature/direct_stepping.cpp b/Marlin/src/feature/direct_stepping.cpp index b8ef04fc..13cf71e0 100644 --- a/Marlin/src/feature/direct_stepping.cpp +++ b/Marlin/src/feature/direct_stepping.cpp @@ -52,13 +52,13 @@ namespace DirectStepping { volatile bool SerialPageManager::fatal_error; template - volatile PageState SerialPageManager::page_states[Cfg::NUM_PAGES]; + volatile PageState SerialPageManager::page_states[Cfg::PAGE_COUNT]; template volatile bool SerialPageManager::page_states_dirty; template - uint8_t SerialPageManager::pages[Cfg::NUM_PAGES][Cfg::PAGE_SIZE]; + uint8_t SerialPageManager::pages[Cfg::PAGE_COUNT][Cfg::PAGE_SIZE]; template uint8_t SerialPageManager::checksum; @@ -74,7 +74,7 @@ namespace DirectStepping { template void SerialPageManager::init() { - for (int i = 0 ; i < Cfg::NUM_PAGES ; i++) + for (int i = 0 ; i < Cfg::PAGE_COUNT ; i++) page_states[i] = PageState::FREE; fatal_error = false; @@ -143,14 +143,16 @@ namespace DirectStepping { // special case for 8-bit, check if rolled back to 0 if (Cfg::DIRECTIONAL || !write_page_size) { // full 256 bytes if (write_byte_idx) return true; - } else { - if (write_byte_idx < write_page_size) return true; } - } else if (Cfg::DIRECTIONAL) { - if (write_byte_idx != Cfg::PAGE_SIZE) return true; - } else { - if (write_byte_idx < write_page_size) return true; + else if (write_byte_idx < write_page_size) + return true; + } + else if (Cfg::DIRECTIONAL) { + if (write_byte_idx != Cfg::PAGE_SIZE) + return true; } + else if (write_byte_idx < write_page_size) + return true; state = State::CHECKSUM; return true; @@ -161,11 +163,10 @@ namespace DirectStepping { return true; } case State::UNFAIL: - if (c == 0) { + if (c == 0) set_page_state(write_page_idx, PageState::FREE); - } else { + else fatal_error = true; - } state = State::MONITOR; return true; } @@ -183,10 +184,10 @@ namespace DirectStepping { SERIAL_CHAR(Cfg::CONTROL_CHAR); constexpr int state_bits = 2; - constexpr int n_bytes = Cfg::NUM_PAGES >> state_bits; + constexpr int n_bytes = Cfg::PAGE_COUNT >> state_bits; volatile uint8_t bits_b[n_bytes] = { 0 }; - for (page_idx_t i = 0 ; i < Cfg::NUM_PAGES ; i++) { + for (page_idx_t i = 0 ; i < Cfg::PAGE_COUNT ; i++) { bits_b[i >> state_bits] |= page_states[i] << ((i * state_bits) & 0x7); } diff --git a/Marlin/src/feature/direct_stepping.h b/Marlin/src/feature/direct_stepping.h index b3007731..b8a803f8 100644 --- a/Marlin/src/feature/direct_stepping.h +++ b/Marlin/src/feature/direct_stepping.h @@ -68,10 +68,10 @@ namespace DirectStepping { static State state; static volatile bool fatal_error; - static volatile PageState page_states[Cfg::NUM_PAGES]; + static volatile PageState page_states[Cfg::PAGE_COUNT]; static volatile bool page_states_dirty; - static uint8_t pages[Cfg::NUM_PAGES][Cfg::PAGE_SIZE]; + static uint8_t pages[Cfg::PAGE_COUNT][Cfg::PAGE_SIZE]; static uint8_t checksum; static write_byte_idx_t write_byte_idx; static page_idx_t write_page_idx; @@ -80,15 +80,12 @@ namespace DirectStepping { static void set_page_state(const page_idx_t page_idx, const PageState page_state); }; - template struct TypeSelector { typedef T type;} ; - template struct TypeSelector { typedef F type; }; - template struct config_t { static constexpr char CONTROL_CHAR = '!'; - static constexpr int NUM_PAGES = num_pages; - static constexpr int NUM_AXES = num_axes; + static constexpr int PAGE_COUNT = num_pages; + static constexpr int AXIS_COUNT = num_axes; static constexpr int BITS_SEGMENT = bits_segment; static constexpr int DIRECTIONAL = dir ? 1 : 0; static constexpr int SEGMENTS = segments; @@ -96,10 +93,10 @@ namespace DirectStepping { static constexpr int NUM_SEGMENTS = _BV(BITS_SEGMENT); static constexpr int SEGMENT_STEPS = _BV(BITS_SEGMENT - DIRECTIONAL) - 1; static constexpr int TOTAL_STEPS = SEGMENT_STEPS * SEGMENTS; - static constexpr int PAGE_SIZE = (NUM_AXES * BITS_SEGMENT * SEGMENTS) / 8; + static constexpr int PAGE_SIZE = (AXIS_COUNT * BITS_SEGMENT * SEGMENTS) / 8; - typedef typename TypeSelector<(PAGE_SIZE>256), uint16_t, uint8_t>::type write_byte_idx_t; - typedef typename TypeSelector<(NUM_PAGES>256), uint16_t, uint8_t>::type page_idx_t; + typedef uvalue_t(PAGE_SIZE - 1) write_byte_idx_t; + typedef uvalue_t(PAGE_COUNT - 1) page_idx_t; }; template diff --git a/Marlin/src/feature/e_parser.cpp b/Marlin/src/feature/e_parser.cpp index d98afcfe..b50a12d1 100644 --- a/Marlin/src/feature/e_parser.cpp +++ b/Marlin/src/feature/e_parser.cpp @@ -33,6 +33,9 @@ // Static data members bool EmergencyParser::killed_by_M112, // = false EmergencyParser::quickstop_by_M410, + #if HAS_MEDIA + EmergencyParser::sd_abort_by_M524, + #endif EmergencyParser::enabled; #if ENABLED(HOST_PROMPT_SUPPORT) diff --git a/Marlin/src/feature/e_parser.h b/Marlin/src/feature/e_parser.h index 1dee0cf7..df4456d8 100644 --- a/Marlin/src/feature/e_parser.h +++ b/Marlin/src/feature/e_parser.h @@ -41,13 +41,15 @@ extern bool wait_for_user, wait_for_heatup; void quickresume_stepper(); #endif -void HAL_reboot(); +#if ENABLED(SOFT_RESET_VIA_SERIAL) + void HAL_reboot(); +#endif class EmergencyParser { public: - // Currently looking for: M108, M112, M410, M876 S[0-9], S000, P000, R000 + // Currently looking for: M108, M112, M410, M524, M876 S[0-9], S000, P000, R000 enum State : uint8_t { EP_RESET, EP_N, @@ -56,6 +58,9 @@ class EmergencyParser { EP_M10, EP_M108, EP_M11, EP_M112, EP_M4, EP_M41, EP_M410, + #if HAS_MEDIA + EP_M5, EP_M52, EP_M524, + #endif #if ENABLED(HOST_PROMPT_SUPPORT) EP_M8, EP_M87, EP_M876, EP_M876S, EP_M876SN, #endif @@ -74,6 +79,10 @@ class EmergencyParser { static bool killed_by_M112; static bool quickstop_by_M410; + #if HAS_MEDIA + static bool sd_abort_by_M524; + #endif + #if ENABLED(HOST_PROMPT_SUPPORT) static uint8_t M876_reason; #endif @@ -143,6 +152,9 @@ class EmergencyParser { case ' ': break; case '1': state = EP_M1; break; case '4': state = EP_M4; break; + #if HAS_MEDIA + case '5': state = EP_M5; break; + #endif #if ENABLED(HOST_PROMPT_SUPPORT) case '8': state = EP_M8; break; #endif @@ -163,6 +175,11 @@ class EmergencyParser { case EP_M4: state = (c == '1') ? EP_M41 : EP_IGNORE; break; case EP_M41: state = (c == '0') ? EP_M410 : EP_IGNORE; break; + #if HAS_MEDIA + case EP_M5: state = (c == '2') ? EP_M52 : EP_IGNORE; break; + case EP_M52: state = (c == '4') ? EP_M524 : EP_IGNORE; break; + #endif + #if ENABLED(HOST_PROMPT_SUPPORT) case EP_M8: state = (c == '7') ? EP_M87 : EP_IGNORE; break; @@ -198,6 +215,9 @@ class EmergencyParser { case EP_M108: wait_for_user = wait_for_heatup = false; break; case EP_M112: killed_by_M112 = true; break; case EP_M410: quickstop_by_M410 = true; break; + #if HAS_MEDIA + case EP_M524: sd_abort_by_M524 = true; break; + #endif #if ENABLED(HOST_PROMPT_SUPPORT) case EP_M876SN: hostui.handle_response(M876_reason); break; #endif diff --git a/Marlin/src/feature/easythreed_ui.cpp b/Marlin/src/feature/easythreed_ui.cpp index 9f8af039..9617c62e 100644 --- a/Marlin/src/feature/easythreed_ui.cpp +++ b/Marlin/src/feature/easythreed_ui.cpp @@ -189,32 +189,29 @@ void EasythreedUI::printButton() { blink_interval_ms = LED_BLINK_2; // Blink the indicator LED at 1 second intervals print_key_flag = PF_PAUSE; // The "Print" button now pauses the print card.mount(); // Force SD card to mount - now! - if (!card.isMounted) { // Failed to mount? - blink_interval_ms = LED_OFF; // Turn off LED - print_key_flag = PF_START; - return; // Bail out + if (!card.isMounted()) { // Failed to mount? + blink_interval_ms = LED_OFF; // Turn off LED + print_key_flag = PF_START; + return; // Bail out } - card.ls(); // List all files to serial output - const uint16_t filecnt = card.countFilesInWorkDir(); // Count printable files in cwd - if (filecnt == 0) return; // None are printable? - card.selectFileByIndex(filecnt); // Select the last file according to current sort options - card.openAndPrintFile(card.filename); // Start printing it - break; - } + card.ls(); // List all files to serial output + const int16_t filecnt = card.get_num_items(); // Count printable files in cwd + if (filecnt == 0) return; // None are printable? + card.selectFileByIndex(filecnt); // Select the last file according to current sort options + card.openAndPrintFile(card.filename); // Start printing it + } break; case PF_PAUSE: { // Pause printing (not currently firing) if (!printingIsActive()) break; blink_interval_ms = LED_ON; // Set indicator to steady ON queue.inject(F("M25")); // Queue Pause print_key_flag = PF_RESUME; // The "Print" button now resumes the print - break; - } + } break; case PF_RESUME: { // Resume printing if (printingIsActive()) break; blink_interval_ms = LED_BLINK_2; // Blink the indicator LED at 1 second intervals queue.inject(F("M24")); // Queue resume print_key_flag = PF_PAUSE; // The "Print" button now pauses the print - break; - } + } break; } } else { // Register a longer press diff --git a/Marlin/src/feature/encoder_i2c.cpp b/Marlin/src/feature/encoder_i2c.cpp index 87e611f8..95a4d47e 100644 --- a/Marlin/src/feature/encoder_i2c.cpp +++ b/Marlin/src/feature/encoder_i2c.cpp @@ -27,7 +27,6 @@ //todo: try faster I2C speed; tweak TWI_FREQ (400000L, or faster?); or just TWBR = ((CPU_FREQ / 400000L) - 16) / 2; //todo: consider Marlin-optimized Wire library; i.e. MarlinWire, like MarlinSerial - #include "../inc/MarlinConfig.h" #if ENABLED(I2C_POSITION_ENCODERS) @@ -37,7 +36,7 @@ #include "../module/stepper.h" #include "../gcode/parser.h" -#include "../feature/babystep.h" +#include "babystep.h" #include @@ -49,7 +48,7 @@ void I2CPositionEncoder::init(const uint8_t address, const AxisEnum axis) { initialized = true; - SERIAL_ECHOLNPGM("Setting up encoder on ", AS_CHAR(axis_codes[encoderAxis]), " axis, addr = ", address); + SERIAL_ECHOLNPGM("Setting up encoder on ", C(AXIS_CHAR(encoderAxis)), " axis, addr = ", address); position = get_position(); } @@ -67,7 +66,7 @@ void I2CPositionEncoder::update() { /* if (trusted) { //commented out as part of the note below trusted = false; - SERIAL_ECHOLNPGM("Fault detected on ", AS_CHAR(axis_codes[encoderAxis]), " axis encoder. Disengaging error correction until module is trusted again."); + SERIAL_ECHOLNPGM("Fault detected on ", C(AXIS_CHAR(encoderAxis)), " axis encoder. Disengaging error correction until module is trusted again."); } */ return; @@ -92,7 +91,7 @@ void I2CPositionEncoder::update() { if (millis() - lastErrorTime > I2CPE_TIME_TRUSTED) { trusted = true; - SERIAL_ECHOLNPGM("Untrusted encoder module on ", AS_CHAR(axis_codes[encoderAxis]), " axis has been fault-free for set duration, reinstating error correction."); + SERIAL_ECHOLNPGM("Untrusted encoder module on ", C(AXIS_CHAR(encoderAxis)), " axis has been fault-free for set duration, reinstating error correction."); //the encoder likely lost its place when the error occurred, so we'll reset and use the printer's //idea of where it the axis is to re-initialize @@ -138,7 +137,7 @@ void I2CPositionEncoder::update() { errIdx = (errIdx >= I2CPE_ERR_ARRAY_SIZE - 1) ? 0 : errIdx + 1; err[errIdx] = get_axis_error_steps(false); - LOOP_L_N(i, I2CPE_ERR_ARRAY_SIZE) { + for (uint8_t i = 0; i < I2CPE_ERR_ARRAY_SIZE; ++i) { sum += err[i]; if (i) diffSum += ABS(err[i-1] - err[i]); } @@ -170,9 +169,9 @@ void I2CPositionEncoder::update() { errPrst[errPrstIdx++] = error; // Error must persist for I2CPE_ERR_PRST_ARRAY_SIZE error cycles. This also serves to improve the average accuracy if (errPrstIdx >= I2CPE_ERR_PRST_ARRAY_SIZE) { float sumP = 0; - LOOP_L_N(i, I2CPE_ERR_PRST_ARRAY_SIZE) sumP += errPrst[i]; + for (uint8_t i = 0; i < I2CPE_ERR_PRST_ARRAY_SIZE; ++i) sumP += errPrst[i]; const int32_t errorP = int32_t(sumP * RECIPROCAL(I2CPE_ERR_PRST_ARRAY_SIZE)); - SERIAL_CHAR(axis_codes[encoderAxis]); + SERIAL_CHAR(AXIS_CHAR(encoderAxis)); SERIAL_ECHOLNPGM(" : CORRECT ERR ", errorP * planner.mm_per_step[encoderAxis], "mm"); babystep.add_steps(encoderAxis, -LROUND(errorP)); errPrstIdx = 0; @@ -192,7 +191,7 @@ void I2CPositionEncoder::update() { if (ABS(error) > I2CPE_ERR_CNT_THRESH * planner.settings.axis_steps_per_mm[encoderAxis]) { const millis_t ms = millis(); if (ELAPSED(ms, nextErrorCountTime)) { - SERIAL_CHAR(axis_codes[encoderAxis]); + SERIAL_CHAR(AXIS_CHAR(encoderAxis)); SERIAL_ECHOLNPGM(" : LARGE ERR ", error, "; diffSum=", diffSum); errorCount++; nextErrorCountTime = ms + I2CPE_ERR_CNT_DEBOUNCE_MS; @@ -212,7 +211,7 @@ void I2CPositionEncoder::set_homed() { homed = trusted = true; #ifdef I2CPE_DEBUG - SERIAL_CHAR(axis_codes[encoderAxis]); + SERIAL_CHAR(AXIS_CHAR(encoderAxis)); SERIAL_ECHOLNPGM(" axis encoder homed, offset of ", zeroOffset, " ticks."); #endif } @@ -223,7 +222,7 @@ void I2CPositionEncoder::set_unhomed() { homed = trusted = false; #ifdef I2CPE_DEBUG - SERIAL_CHAR(axis_codes[encoderAxis]); + SERIAL_CHAR(AXIS_CHAR(encoderAxis)); SERIAL_ECHOLNPGM(" axis encoder unhomed."); #endif } @@ -231,7 +230,7 @@ void I2CPositionEncoder::set_unhomed() { bool I2CPositionEncoder::passes_test(const bool report) { if (report) { if (H != I2CPE_MAG_SIG_GOOD) SERIAL_ECHOPGM("Warning. "); - SERIAL_CHAR(axis_codes[encoderAxis]); + SERIAL_CHAR(AXIS_CHAR(encoderAxis)); serial_ternary(H == I2CPE_MAG_SIG_BAD, F(" axis "), F("magnetic strip "), F("encoder ")); switch (H) { case I2CPE_MAG_SIG_GOOD: @@ -252,7 +251,7 @@ float I2CPositionEncoder::get_axis_error_mm(const bool report) { error = ABS(diff) > 10000 ? 0 : diff; // Huge error is a bad reading if (report) { - SERIAL_CHAR(axis_codes[encoderAxis]); + SERIAL_CHAR(AXIS_CHAR(encoderAxis)); SERIAL_ECHOLNPGM(" axis target=", target, "mm; actual=", actual, "mm; err=", error, "mm"); } @@ -262,7 +261,7 @@ float I2CPositionEncoder::get_axis_error_mm(const bool report) { int32_t I2CPositionEncoder::get_axis_error_steps(const bool report) { if (!active) { if (report) { - SERIAL_CHAR(axis_codes[encoderAxis]); + SERIAL_CHAR(AXIS_CHAR(encoderAxis)); SERIAL_ECHOLNPGM(" axis encoder not active!"); } return 0; @@ -287,7 +286,7 @@ int32_t I2CPositionEncoder::get_axis_error_steps(const bool report) { errorPrev = error; if (report) { - SERIAL_CHAR(axis_codes[encoderAxis]); + SERIAL_CHAR(AXIS_CHAR(encoderAxis)); SERIAL_ECHOLNPGM(" axis target=", target, "; actual=", encoderCountInStepperTicksScaled, "; err=", error); } @@ -337,7 +336,7 @@ bool I2CPositionEncoder::test_axis() { ec = false; xyze_pos_t startCoord, endCoord; - LOOP_LINEAR_AXES(a) { + LOOP_NUM_AXES(a) { startCoord[a] = planner.get_axis_position_mm((AxisEnum)a); endCoord[a] = planner.get_axis_position_mm((AxisEnum)a); } @@ -395,7 +394,7 @@ void I2CPositionEncoder::calibrate_steps_mm(const uint8_t iter) { travelDistance = endDistance - startDistance; xyze_pos_t startCoord, endCoord; - LOOP_LINEAR_AXES(a) { + LOOP_NUM_AXES(a) { startCoord[a] = planner.get_axis_position_mm((AxisEnum)a); endCoord[a] = planner.get_axis_position_mm((AxisEnum)a); } @@ -404,7 +403,7 @@ void I2CPositionEncoder::calibrate_steps_mm(const uint8_t iter) { planner.synchronize(); - LOOP_L_N(i, iter) { + for (uint8_t i = 0; i < iter; ++i) { TERN_(HAS_EXTRUDERS, startCoord.e = planner.get_axis_position_mm(E_AXIS)); planner.buffer_line(startCoord, fr_mm_s, 0); planner.synchronize(); @@ -425,22 +424,22 @@ void I2CPositionEncoder::calibrate_steps_mm(const uint8_t iter) { travelledDistance = mm_from_count(ABS(stopCount - startCount)); SERIAL_ECHOLNPGM("Attempted travel: ", travelDistance, "mm"); - SERIAL_ECHOLNPGM(" Actual travel: ", travelledDistance, "mm"); + SERIAL_ECHOLNPGM(" Actual travel: ", travelledDistance, "mm"); - //Calculate new axis steps per unit + // Calculate new axis steps per unit old_steps_mm = planner.settings.axis_steps_per_mm[encoderAxis]; new_steps_mm = (old_steps_mm * travelDistance) / travelledDistance; SERIAL_ECHOLNPGM("Old steps/mm: ", old_steps_mm); SERIAL_ECHOLNPGM("New steps/mm: ", new_steps_mm); - //Save new value + // Save new value planner.settings.axis_steps_per_mm[encoderAxis] = new_steps_mm; if (iter > 1) { total += new_steps_mm; - // swap start and end points so next loop runs from current position + // Swap start and end points so next loop runs from current position const float tempCoord = startCoord[encoderAxis]; startCoord[encoderAxis] = endCoord[encoderAxis]; endCoord[encoderAxis] = tempCoord; @@ -465,7 +464,6 @@ void I2CPositionEncoder::reset() { TERN_(I2CPE_ERR_ROLLING_AVERAGE, ZERO(err)); } - bool I2CPositionEncodersMgr::I2CPE_anyaxis; uint8_t I2CPositionEncodersMgr::I2CPE_addr, I2CPositionEncodersMgr::I2CPE_idx; @@ -489,7 +487,7 @@ void I2CPositionEncodersMgr::init() { encoders[i].set_stepper_ticks(I2CPE_ENC_1_TICKS_REV); #endif #ifdef I2CPE_ENC_1_INVERT - encoders[i].set_inverted(I2CPE_ENC_1_INVERT); + encoders[i].set_inverted(ENABLED(I2CPE_ENC_1_INVERT)); #endif #ifdef I2CPE_ENC_1_EC_METHOD encoders[i].set_ec_method(I2CPE_ENC_1_EC_METHOD); @@ -518,7 +516,7 @@ void I2CPositionEncodersMgr::init() { encoders[i].set_stepper_ticks(I2CPE_ENC_2_TICKS_REV); #endif #ifdef I2CPE_ENC_2_INVERT - encoders[i].set_inverted(I2CPE_ENC_2_INVERT); + encoders[i].set_inverted(ENABLED(I2CPE_ENC_2_INVERT)); #endif #ifdef I2CPE_ENC_2_EC_METHOD encoders[i].set_ec_method(I2CPE_ENC_2_EC_METHOD); @@ -547,7 +545,7 @@ void I2CPositionEncodersMgr::init() { encoders[i].set_stepper_ticks(I2CPE_ENC_3_TICKS_REV); #endif #ifdef I2CPE_ENC_3_INVERT - encoders[i].set_inverted(I2CPE_ENC_3_INVERT); + encoders[i].set_inverted(ENABLED(I2CPE_ENC_3_INVERT)); #endif #ifdef I2CPE_ENC_3_EC_METHOD encoders[i].set_ec_method(I2CPE_ENC_3_EC_METHOD); @@ -576,7 +574,7 @@ void I2CPositionEncodersMgr::init() { encoders[i].set_stepper_ticks(I2CPE_ENC_4_TICKS_REV); #endif #ifdef I2CPE_ENC_4_INVERT - encoders[i].set_inverted(I2CPE_ENC_4_INVERT); + encoders[i].set_inverted(ENABLED(I2CPE_ENC_4_INVERT)); #endif #ifdef I2CPE_ENC_4_EC_METHOD encoders[i].set_ec_method(I2CPE_ENC_4_EC_METHOD); @@ -605,7 +603,7 @@ void I2CPositionEncodersMgr::init() { encoders[i].set_stepper_ticks(I2CPE_ENC_5_TICKS_REV); #endif #ifdef I2CPE_ENC_5_INVERT - encoders[i].set_inverted(I2CPE_ENC_5_INVERT); + encoders[i].set_inverted(ENABLED(I2CPE_ENC_5_INVERT)); #endif #ifdef I2CPE_ENC_5_EC_METHOD encoders[i].set_ec_method(I2CPE_ENC_5_EC_METHOD); @@ -634,7 +632,7 @@ void I2CPositionEncodersMgr::init() { encoders[i].set_stepper_ticks(I2CPE_ENC_6_TICKS_REV); #endif #ifdef I2CPE_ENC_6_INVERT - encoders[i].set_inverted(I2CPE_ENC_6_INVERT); + encoders[i].set_inverted(ENABLED(I2CPE_ENC_6_INVERT)); #endif #ifdef I2CPE_ENC_6_EC_METHOD encoders[i].set_ec_method(I2CPE_ENC_6_EC_METHOD); @@ -657,7 +655,7 @@ void I2CPositionEncodersMgr::report_position(const int8_t idx, const bool units, else { if (noOffset) { const int32_t raw_count = encoders[idx].get_raw_count(); - SERIAL_CHAR(axis_codes[encoders[idx].get_axis()], ' '); + SERIAL_CHAR(AXIS_CHAR(encoders[idx).get_axis()], ' '); for (uint8_t j = 31; j > 0; j--) SERIAL_ECHO((bool)(0x00000001 & (raw_count >> j))); @@ -712,7 +710,7 @@ void I2CPositionEncodersMgr::change_module_address(const uint8_t oldaddr, const // and enable it (it will likely have failed initialization on power-up, before the address change). const int8_t idx = idx_from_addr(newaddr); if (idx >= 0 && !encoders[idx].get_active()) { - SERIAL_CHAR(axis_codes[encoders[idx].get_axis()]); + SERIAL_CHAR(AXIS_CHAR(encoders[idx).get_axis()]); SERIAL_ECHOLNPGM(" axis encoder was not detected on printer startup. Trying again."); encoders[idx].set_active(encoders[idx].passes_test(true)); } @@ -756,7 +754,7 @@ int8_t I2CPositionEncodersMgr::parse() { if (!parser.has_value()) { SERIAL_ECHOLNPGM("?A seen, but no address specified! [30-200]"); return I2CPE_PARSE_ERR; - }; + } I2CPE_addr = parser.value_byte(); if (!WITHIN(I2CPE_addr, 30, 200)) { // reserve the first 30 and last 55 @@ -775,7 +773,7 @@ int8_t I2CPositionEncodersMgr::parse() { if (!parser.has_value()) { SERIAL_ECHOLNPGM("?I seen, but no index specified! [0-", I2CPE_ENCODER_CNT - 1, "]"); return I2CPE_PARSE_ERR; - }; + } I2CPE_idx = parser.value_byte(); if (I2CPE_idx >= I2CPE_ENCODER_CNT) { @@ -791,7 +789,7 @@ int8_t I2CPositionEncodersMgr::parse() { I2CPE_anyaxis = parser.seen_axis(); return I2CPE_PARSE_OK; -}; +} /** * M860: Report the position(s) of position encoder module(s). @@ -814,7 +812,7 @@ void I2CPositionEncodersMgr::M860() { if (I2CPE_idx == 0xFF) { LOOP_LOGICAL_AXES(i) { - if (!I2CPE_anyaxis || parser.seen_test(axis_codes[i])) { + if (!I2CPE_anyaxis || parser.seen_test(AXIS_CHAR(i))) { const uint8_t idx = idx_from_axis(AxisEnum(i)); if ((int8_t)idx >= 0) report_position(idx, hasU, hasO); } @@ -841,7 +839,7 @@ void I2CPositionEncodersMgr::M861() { if (I2CPE_idx == 0xFF) { LOOP_LOGICAL_AXES(i) { - if (!I2CPE_anyaxis || parser.seen(axis_codes[i])) { + if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) { const uint8_t idx = idx_from_axis(AxisEnum(i)); if ((int8_t)idx >= 0) report_status(idx); } @@ -869,7 +867,7 @@ void I2CPositionEncodersMgr::M862() { if (I2CPE_idx == 0xFF) { LOOP_LOGICAL_AXES(i) { - if (!I2CPE_anyaxis || parser.seen(axis_codes[i])) { + if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) { const uint8_t idx = idx_from_axis(AxisEnum(i)); if ((int8_t)idx >= 0) test_axis(idx); } @@ -900,7 +898,7 @@ void I2CPositionEncodersMgr::M863() { if (I2CPE_idx == 0xFF) { LOOP_LOGICAL_AXES(i) { - if (!I2CPE_anyaxis || parser.seen(axis_codes[i])) { + if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) { const uint8_t idx = idx_from_axis(AxisEnum(i)); if ((int8_t)idx >= 0) calibrate_steps_mm(idx, iterations); } @@ -934,7 +932,7 @@ void I2CPositionEncodersMgr::M864() { if (!parser.has_value()) { SERIAL_ECHOLNPGM("?S seen, but no address specified! [30-200]"); return; - }; + } newAddress = parser.value_byte(); if (!WITHIN(newAddress, 30, 200)) { @@ -976,7 +974,7 @@ void I2CPositionEncodersMgr::M865() { if (!I2CPE_addr) { LOOP_LOGICAL_AXES(i) { - if (!I2CPE_anyaxis || parser.seen(axis_codes[i])) { + if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) { const uint8_t idx = idx_from_axis(AxisEnum(i)); if ((int8_t)idx >= 0) report_module_firmware(encoders[idx].get_address()); } @@ -1007,7 +1005,7 @@ void I2CPositionEncodersMgr::M866() { if (I2CPE_idx == 0xFF) { LOOP_LOGICAL_AXES(i) { - if (!I2CPE_anyaxis || parser.seen(axis_codes[i])) { + if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) { const uint8_t idx = idx_from_axis(AxisEnum(i)); if ((int8_t)idx >= 0) { if (hasR) @@ -1045,7 +1043,7 @@ void I2CPositionEncodersMgr::M867() { if (I2CPE_idx == 0xFF) { LOOP_LOGICAL_AXES(i) { - if (!I2CPE_anyaxis || parser.seen(axis_codes[i])) { + if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) { const uint8_t idx = idx_from_axis(AxisEnum(i)); if ((int8_t)idx >= 0) { const bool ena = onoff == -1 ? !encoders[I2CPE_idx].get_ec_enabled() : !!onoff; @@ -1081,7 +1079,7 @@ void I2CPositionEncodersMgr::M868() { if (I2CPE_idx == 0xFF) { LOOP_LOGICAL_AXES(i) { - if (!I2CPE_anyaxis || parser.seen(axis_codes[i])) { + if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) { const uint8_t idx = idx_from_axis(AxisEnum(i)); if ((int8_t)idx >= 0) { if (newThreshold != -9999) @@ -1115,7 +1113,7 @@ void I2CPositionEncodersMgr::M869() { if (I2CPE_idx == 0xFF) { LOOP_LOGICAL_AXES(i) { - if (!I2CPE_anyaxis || parser.seen(axis_codes[i])) { + if (!I2CPE_anyaxis || parser.seen(AXIS_CHAR(i))) { const uint8_t idx = idx_from_axis(AxisEnum(i)); if ((int8_t)idx >= 0) report_error(idx); } diff --git a/Marlin/src/feature/encoder_i2c.h b/Marlin/src/feature/encoder_i2c.h index 50fb27a1..861a8e52 100644 --- a/Marlin/src/feature/encoder_i2c.h +++ b/Marlin/src/feature/encoder_i2c.h @@ -90,7 +90,7 @@ #define I2CPE_PARSE_ERR 1 #define I2CPE_PARSE_OK 0 -#define LOOP_PE(VAR) LOOP_L_N(VAR, I2CPE_ENCODER_CNT) +#define LOOP_PE(VAR) for (uint8_t VAR = 0; VAR < I2CPE_ENCODER_CNT; ++VAR) #define CHECK_IDX() do{ if (!WITHIN(idx, 0, I2CPE_ENCODER_CNT - 1)) return; }while(0) typedef union { @@ -261,32 +261,32 @@ class I2CPositionEncodersMgr { static void report_error_count(const int8_t idx, const AxisEnum axis) { CHECK_IDX(); - SERIAL_ECHOLNPGM("Error count on ", AS_CHAR(axis_codes[axis]), " axis is ", encoders[idx].get_error_count()); + SERIAL_ECHOLNPGM("Error count on ", C(AXIS_CHAR(axis)), " axis is ", encoders[idx].get_error_count()); } static void reset_error_count(const int8_t idx, const AxisEnum axis) { CHECK_IDX(); encoders[idx].set_error_count(0); - SERIAL_ECHOLNPGM("Error count on ", AS_CHAR(axis_codes[axis]), " axis has been reset."); + SERIAL_ECHOLNPGM("Error count on ", C(AXIS_CHAR(axis)), " axis has been reset."); } static void enable_ec(const int8_t idx, const bool enabled, const AxisEnum axis) { CHECK_IDX(); encoders[idx].set_ec_enabled(enabled); - SERIAL_ECHOPGM("Error correction on ", AS_CHAR(axis_codes[axis])); + SERIAL_ECHOPGM("Error correction on ", C(AXIS_CHAR(axis))); SERIAL_ECHO_TERNARY(encoders[idx].get_ec_enabled(), " axis is ", "en", "dis", "abled.\n"); } static void set_ec_threshold(const int8_t idx, const float newThreshold, const AxisEnum axis) { CHECK_IDX(); encoders[idx].set_ec_threshold(newThreshold); - SERIAL_ECHOLNPGM("Error correct threshold for ", AS_CHAR(axis_codes[axis]), " axis set to ", newThreshold, "mm."); + SERIAL_ECHOLNPGM("Error correct threshold for ", C(AXIS_CHAR(axis)), " axis set to ", newThreshold, "mm."); } static void get_ec_threshold(const int8_t idx, const AxisEnum axis) { CHECK_IDX(); const float threshold = encoders[idx].get_ec_threshold(); - SERIAL_ECHOLNPGM("Error correct threshold for ", AS_CHAR(axis_codes[axis]), " axis is ", threshold, "mm."); + SERIAL_ECHOLNPGM("Error correct threshold for ", C(AXIS_CHAR(axis)), " axis is ", threshold, "mm."); } static int8_t idx_from_axis(const AxisEnum axis) { diff --git a/Marlin/src/feature/ethernet.cpp b/Marlin/src/feature/ethernet.cpp index c5bfa932..9b022b4e 100644 --- a/Marlin/src/feature/ethernet.cpp +++ b/Marlin/src/feature/ethernet.cpp @@ -141,7 +141,7 @@ void MarlinEthernet::check() { case CONNECTING: telnetClient.println("Marlin " SHORT_BUILD_VERSION); - #if defined(STRING_DISTRIBUTION_DATE) && defined(STRING_CONFIG_H_AUTHOR) + #ifdef STRING_DISTRIBUTION_DATE telnetClient.println( " Last Updated: " STRING_DISTRIBUTION_DATE " | Author: " STRING_CONFIG_H_AUTHOR diff --git a/Marlin/src/feature/fancheck.cpp b/Marlin/src/feature/fancheck.cpp index 1b47fade..844191e7 100644 --- a/Marlin/src/feature/fancheck.cpp +++ b/Marlin/src/feature/fancheck.cpp @@ -34,7 +34,7 @@ #if HAS_AUTO_FAN && EXTRUDER_AUTO_FAN_SPEED != 255 && DISABLED(FOURWIRES_FANS) bool FanCheck::measuring = false; #endif -bool FanCheck::tacho_state[TACHO_COUNT]; +Flags FanCheck::tacho_state; uint16_t FanCheck::edge_counter[TACHO_COUNT]; uint8_t FanCheck::rps[TACHO_COUNT]; FanCheck::TachoError FanCheck::error = FanCheck::TachoError::NONE; @@ -72,7 +72,7 @@ void FanCheck::update_tachometers() { bool status; #define _TACHO_CASE(N) case N: status = READ(E##N##_FAN_TACHO_PIN); break; - LOOP_L_N(f, TACHO_COUNT) { + for (uint8_t f = 0; f < TACHO_COUNT; ++f) { switch (f) { #if HAS_E0_FAN_TACHO _TACHO_CASE(0) @@ -103,7 +103,7 @@ void FanCheck::update_tachometers() { if (status != tacho_state[f]) { if (measuring) ++edge_counter[f]; - tacho_state[f] = status; + tacho_state.set(f, status); } } } @@ -113,7 +113,7 @@ void FanCheck::compute_speed(uint16_t elapsedTime) { static uint8_t fan_reported_errors_msk = 0; uint8_t fan_error_msk = 0; - LOOP_L_N(f, TACHO_COUNT) { + for (uint8_t f = 0; f < TACHO_COUNT; ++f) { switch (f) { TERN_(HAS_E0_FAN_TACHO, case 0:) TERN_(HAS_E1_FAN_TACHO, case 1:) @@ -150,7 +150,7 @@ void FanCheck::compute_speed(uint16_t elapsedTime) { if (fan_error_msk & ~fan_reported_errors_msk) { // Handle new faults only - LOOP_L_N(f, TACHO_COUNT) if (TEST(fan_error_msk, f)) report_speed_error(f); + for (uint8_t f = 0; f < TACHO_COUNT; ++f) if (TEST(fan_error_msk, f)) report_speed_error(f); } fan_reported_errors_msk = fan_error_msk; } @@ -176,8 +176,8 @@ void FanCheck::report_speed_error(uint8_t fan) { } void FanCheck::print_fan_states() { - LOOP_L_N(s, 2) { - LOOP_L_N(f, TACHO_COUNT) { + for (uint8_t s = 0; s < 2; ++s) { + for (uint8_t f = 0; f < TACHO_COUNT; ++f) { switch (f) { TERN_(HAS_E0_FAN_TACHO, case 0:) TERN_(HAS_E1_FAN_TACHO, case 1:) diff --git a/Marlin/src/feature/fancheck.h b/Marlin/src/feature/fancheck.h index 6e8038b4..b13a34fb 100644 --- a/Marlin/src/feature/fancheck.h +++ b/Marlin/src/feature/fancheck.h @@ -51,12 +51,12 @@ class FanCheck { #else static constexpr bool measuring = true; #endif - static bool tacho_state[TACHO_COUNT]; + static Flags tacho_state; static uint16_t edge_counter[TACHO_COUNT]; static uint8_t rps[TACHO_COUNT]; static TachoError error; - static inline void report_speed_error(uint8_t fan); + static void report_speed_error(uint8_t fan); public: @@ -67,11 +67,11 @@ class FanCheck { static void compute_speed(uint16_t elapsedTime); static void print_fan_states(); #if HAS_PWMFANCHECK - static inline void toggle_measuring() { measuring = !measuring; } - static inline bool is_measuring() { return measuring; } + static void toggle_measuring() { measuring = !measuring; } + static bool is_measuring() { return measuring; } #endif - static inline void check_deferred_error() { + static void check_deferred_error() { if (error == TachoError::DETECTED) { error = TachoError::REPORTED; TERN(PARK_HEAD_ON_PAUSE, queue.inject(F("M125")), kill(GET_TEXT_F(MSG_FAN_SPEED_FAULT))); diff --git a/Marlin/src/feature/filwidth.cpp b/Marlin/src/feature/filwidth.cpp index 2bd9c789..1142423c 100644 --- a/Marlin/src/feature/filwidth.cpp +++ b/Marlin/src/feature/filwidth.cpp @@ -28,7 +28,7 @@ FilamentWidthSensor filwidth; -bool FilamentWidthSensor::enabled; // = false; // (M405-M406) Filament Width Sensor ON/OFF. +bool FilamentWidthSensor::enabled; // = false // (M405-M406) Filament Width Sensor ON/OFF. uint32_t FilamentWidthSensor::accum; // = 0 // ADC accumulator uint16_t FilamentWidthSensor::raw; // = 0 // Measured filament diameter - one extruder only float FilamentWidthSensor::nominal_mm = DEFAULT_NOMINAL_FILAMENT_DIA, // (M104) Nominal filament width @@ -42,7 +42,7 @@ int8_t FilamentWidthSensor::ratios[MAX_MEASUREMENT_DELAY + 1], // Ring void FilamentWidthSensor::init() { const int8_t ratio = sample_to_size_ratio(); - LOOP_L_N(i, COUNT(ratios)) ratios[i] = ratio; + for (uint8_t i = 0; i < COUNT(ratios); ++i) ratios[i] = ratio; index_r = index_w = 0; } diff --git a/Marlin/src/feature/filwidth.h b/Marlin/src/feature/filwidth.h index e63d3d71..ab50fe0a 100644 --- a/Marlin/src/feature/filwidth.h +++ b/Marlin/src/feature/filwidth.h @@ -41,9 +41,9 @@ class FilamentWidthSensor { FilamentWidthSensor() { init(); } static void init(); - static inline void enable(const bool ena) { enabled = ena; } + static void enable(const bool ena) { enabled = ena; } - static inline void set_delay_cm(const uint8_t cm) { + static void set_delay_cm(const uint8_t cm) { meas_delay_cm = _MIN(cm, MAX_MEASUREMENT_DELAY); } @@ -67,18 +67,18 @@ class FilamentWidthSensor { } // Convert raw measurement to mm - static inline float raw_to_mm(const uint16_t v) { return v * 5.0f * RECIPROCAL(float(MAX_RAW_THERMISTOR_VALUE)); } - static inline float raw_to_mm() { return raw_to_mm(raw); } + static float raw_to_mm(const uint16_t v) { return v * (float(ADC_VREF_MV) / 1000.0f) * RECIPROCAL(float(MAX_RAW_THERMISTOR_VALUE)); } + static float raw_to_mm() { return raw_to_mm(raw); } // A scaled reading is ready // Divide to get to 0-16384 range since we used 1/128 IIR filter approach - static inline void reading_ready() { raw = accum >> 10; } + static void reading_ready() { raw = accum >> 10; } // Update mm from the raw measurement - static inline void update_measured_mm() { measured_mm = raw_to_mm(); } + static void update_measured_mm() { measured_mm = raw_to_mm(); } // Update ring buffer used to delay filament measurements - static inline void advance_e(const_float_t e_move) { + static void advance_e(const_float_t e_move) { // Increment counters with the E distance e_count += e_move; @@ -106,7 +106,7 @@ class FilamentWidthSensor { } // Dynamically set the volumetric multiplier based on the delayed width measurement. - static inline void update_volumetric() { + static void update_volumetric() { if (enabled) { int8_t read_index = index_r - meas_delay_cm; if (read_index < 0) read_index += MMD_CM; // Loop around buffer if needed diff --git a/Marlin/src/feature/fwretract.cpp b/Marlin/src/feature/fwretract.cpp index 4077d8d1..23ab878e 100644 --- a/Marlin/src/feature/fwretract.cpp +++ b/Marlin/src/feature/fwretract.cpp @@ -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" @@ -45,7 +44,7 @@ FWRetract fwretract; // Single instance - this calls the constructor // private: #if HAS_MULTI_EXTRUDER - bool FWRetract::retracted_swap[EXTRUDERS]; // Which extruders are swap-retracted + Flags FWRetract::retracted_swap; // Which extruders are swap-retracted #endif // public: @@ -56,7 +55,7 @@ fwretract_settings_t FWRetract::settings; // M207 S F Z W, M208 S F bool FWRetract::autoretract_enabled; // M209 S - Autoretract switch #endif -bool FWRetract::retracted[EXTRUDERS]; // Which extruders are currently retracted +Flags FWRetract::retracted; // Which extruders are currently retracted float FWRetract::current_retract[EXTRUDERS], // Retract value used by planner FWRetract::current_hop; @@ -73,10 +72,10 @@ void FWRetract::reset() { settings.swap_retract_recover_feedrate_mm_s = RETRACT_RECOVER_FEEDRATE_SWAP; current_hop = 0.0; - LOOP_L_N(i, EXTRUDERS) { - retracted[i] = false; - E_TERN_(retracted_swap[i] = false); - current_retract[i] = 0.0; + retracted.reset(); + EXTRUDER_LOOP() { + E_TERN_(retracted_swap.clear(e)); + current_retract[e] = 0.0; } } @@ -111,10 +110,10 @@ void FWRetract::retract(const bool retracting E_OPTARG(bool swapping/*=false*/)) " swapping ", swapping, " active extruder ", active_extruder ); - LOOP_L_N(i, EXTRUDERS) { - SERIAL_ECHOLNPGM("retracted[", i, "] ", AS_DIGIT(retracted[i])); + EXTRUDER_LOOP() { + SERIAL_ECHOLNPGM("retracted[", e, "] ", AS_DIGIT(retracted[e])); #if HAS_MULTI_EXTRUDER - SERIAL_ECHOLNPGM("retracted_swap[", i, "] ", AS_DIGIT(retracted_swap[i])); + SERIAL_ECHOLNPGM("retracted_swap[", e, "] ", AS_DIGIT(retracted_swap[e])); #endif } SERIAL_ECHOLNPGM("current_position.z ", current_position.z); @@ -138,7 +137,7 @@ void FWRetract::retract(const bool retracting E_OPTARG(bool swapping/*=false*/)) // Retract by moving from a faux E position back to the current E position current_retract[active_extruder] = base_retract; prepare_internal_move_to_destination( // set current from destination - settings.retract_feedrate_mm_s * TERN1(RETRACT_SYNC_MIXING, (MIXING_STEPPERS)) + MUL_TERN(RETRACT_SYNC_MIXING, settings.retract_feedrate_mm_s, MIXING_STEPPERS) ); // Is a Z hop set, and has the hop not yet been done? @@ -166,28 +165,27 @@ void FWRetract::retract(const bool retracting E_OPTARG(bool swapping/*=false*/)) // Recover E, set_current_to_destination prepare_internal_move_to_destination( - (swapping ? settings.swap_retract_recover_feedrate_mm_s : settings.retract_recover_feedrate_mm_s) - * TERN1(RETRACT_SYNC_MIXING, (MIXING_STEPPERS)) + MUL_TERN(RETRACT_SYNC_MIXING, swapping ? settings.swap_retract_recover_feedrate_mm_s : settings.retract_recover_feedrate_mm_s, MIXING_STEPPERS) ); } TERN_(RETRACT_SYNC_MIXING, mixer.T(old_mixing_tool)); // Restore original mixing tool - retracted[active_extruder] = retracting; // Active extruder now retracted / recovered + retracted.set(active_extruder, retracting); // Active extruder now retracted / recovered // If swap retract/recover update the retracted_swap flag too #if HAS_MULTI_EXTRUDER - if (swapping) retracted_swap[active_extruder] = retracting; + if (swapping) retracted_swap.set(active_extruder, retracting); #endif /* // debugging SERIAL_ECHOLNPGM("retracting ", AS_DIGIT(retracting)); SERIAL_ECHOLNPGM("swapping ", AS_DIGIT(swapping)); SERIAL_ECHOLNPGM("active_extruder ", active_extruder); - LOOP_L_N(i, EXTRUDERS) { - SERIAL_ECHOLNPGM("retracted[", i, "] ", AS_DIGIT(retracted[i])); + EXTRUDER_LOOP() { + SERIAL_ECHOLNPGM("retracted[", e, "] ", AS_DIGIT(retracted[e])); #if HAS_MULTI_EXTRUDER - SERIAL_ECHOLNPGM("retracted_swap[", i, "] ", AS_DIGIT(retracted_swap[i])); + SERIAL_ECHOLNPGM("retracted_swap[", e, "] ", AS_DIGIT(retracted_swap[e])); #endif } SERIAL_ECHOLNPGM("current_position.z ", current_position.z); @@ -196,8 +194,6 @@ void FWRetract::retract(const bool retracting E_OPTARG(bool swapping/*=false*/)) //*/ } -//extern const char SP_Z_STR[]; - /** * M207: Set firmware retraction values * @@ -266,5 +262,4 @@ void FWRetract::M208_report() { #endif // FWRETRACT_AUTORETRACT - #endif // FWRETRACT diff --git a/Marlin/src/feature/fwretract.h b/Marlin/src/feature/fwretract.h index d6d0432e..db2a62c8 100644 --- a/Marlin/src/feature/fwretract.h +++ b/Marlin/src/feature/fwretract.h @@ -43,7 +43,7 @@ typedef struct { class FWRetract { private: #if HAS_MULTI_EXTRUDER - static bool retracted_swap[EXTRUDERS]; // Which extruders are swap-retracted + static Flags retracted_swap; // Which extruders are swap-retracted #endif public: @@ -55,7 +55,7 @@ class FWRetract { static constexpr bool autoretract_enabled = false; #endif - static bool retracted[EXTRUDERS]; // Which extruders are currently retracted + static Flags retracted; // Which extruders are currently retracted static float current_retract[EXTRUDERS], // Retract value used by planner current_hop; // Hop value used by planner @@ -63,9 +63,7 @@ class FWRetract { static void reset(); - static void refresh_autoretract() { - LOOP_L_N(i, EXTRUDERS) retracted[i] = false; - } + static void refresh_autoretract() { retracted.reset(); } static void enable_autoretract(const bool enable) { #if ENABLED(FWRETRACT_AUTORETRACT) diff --git a/Marlin/src/feature/host_actions.cpp b/Marlin/src/feature/host_actions.cpp index be7b055b..5a57ea1f 100644 --- a/Marlin/src/feature/host_actions.cpp +++ b/Marlin/src/feature/host_actions.cpp @@ -39,10 +39,7 @@ HostUI hostui; -flag_t HostUI::flag; - void HostUI::action(FSTR_P const fstr, const bool eol) { - if (!flag.bits) return; PORT_REDIRECT(SerialMask::All); SERIAL_ECHOPGM("//action:"); SERIAL_ECHOF(fstr); @@ -96,43 +93,47 @@ void HostUI::action(FSTR_P const fstr, const bool eol) { #endif void HostUI::notify(const char * const cstr) { - if (!flag.bits) return; PORT_REDIRECT(SerialMask::All); action(F("notification "), false); SERIAL_ECHOLN(cstr); } void HostUI::notify_P(PGM_P const pstr) { - if (!flag.bits) return; PORT_REDIRECT(SerialMask::All); action(F("notification "), false); SERIAL_ECHOLNPGM_P(pstr); } void HostUI::prompt(FSTR_P const ptype, const bool eol/*=true*/) { - if (!flag.bits) return; PORT_REDIRECT(SerialMask::All); action(F("prompt_"), false); SERIAL_ECHOF(ptype); if (eol) SERIAL_EOL(); } - void HostUI::prompt_plus(FSTR_P const ptype, FSTR_P const fstr, const char extra_char/*='\0'*/) { - if (!flag.bits) return; + void HostUI::prompt_plus(const bool pgm, FSTR_P const ptype, const char * const str, const char extra_char/*='\0'*/) { prompt(ptype, false); PORT_REDIRECT(SerialMask::All); SERIAL_CHAR(' '); - SERIAL_ECHOF(fstr); + if (pgm) + SERIAL_ECHOPGM_P(str); + else + SERIAL_ECHO(str); if (extra_char != '\0') SERIAL_CHAR(extra_char); SERIAL_EOL(); } + void HostUI::prompt_begin(const PromptReason reason, FSTR_P const fstr, const char extra_char/*='\0'*/) { - if (!flag.bits) return; prompt_end(); host_prompt_reason = reason; prompt_plus(F("begin"), fstr, extra_char); } - void HostUI::prompt_button(FSTR_P const fstr) { prompt_plus(F("button"), fstr); } + void HostUI::prompt_begin(const PromptReason reason, const char * const cstr, const char extra_char/*='\0'*/) { + prompt_end(); + host_prompt_reason = reason; + prompt_plus(F("begin"), cstr, extra_char); + } + void HostUI::prompt_end() { prompt(F("end")); } void HostUI::prompt_show() { prompt(F("show")); } @@ -141,14 +142,26 @@ void HostUI::action(FSTR_P const fstr, const bool eol) { if (btn2) prompt_button(btn2); prompt_show(); } + + void HostUI::prompt_button(FSTR_P const fstr) { prompt_plus(F("button"), fstr); } + void HostUI::prompt_button(const char * const cstr) { prompt_plus(F("button"), cstr); } + void HostUI::prompt_do(const PromptReason reason, FSTR_P const fstr, FSTR_P const btn1/*=nullptr*/, FSTR_P const btn2/*=nullptr*/) { prompt_begin(reason, fstr); _prompt_show(btn1, btn2); } + void HostUI::prompt_do(const PromptReason reason, const char * const cstr, FSTR_P const btn1/*=nullptr*/, FSTR_P const btn2/*=nullptr*/) { + prompt_begin(reason, cstr); + _prompt_show(btn1, btn2); + } void HostUI::prompt_do(const PromptReason reason, FSTR_P const fstr, const char extra_char, FSTR_P const btn1/*=nullptr*/, FSTR_P const btn2/*=nullptr*/) { prompt_begin(reason, fstr, extra_char); _prompt_show(btn1, btn2); } + void HostUI::prompt_do(const PromptReason reason, const char * const cstr, const char extra_char, FSTR_P const btn1/*=nullptr*/, FSTR_P const btn2/*=nullptr*/) { + prompt_begin(reason, cstr, extra_char); + _prompt_show(btn1, btn2); + } #if ENABLED(ADVANCED_PAUSE_FEATURE) void HostUI::filament_load_prompt() { @@ -174,13 +187,13 @@ void HostUI::action(FSTR_P const fstr, const bool eol) { switch (response) { case 0: // "Purge More" button - #if BOTH(M600_PURGE_MORE_RESUMABLE, ADVANCED_PAUSE_FEATURE) + #if ENABLED(M600_PURGE_MORE_RESUMABLE) pause_menu_response = PAUSE_RESPONSE_EXTRUDE_MORE; // Simulate menu selection (menu exits, doesn't extrude more) #endif break; case 1: // "Continue" / "Disable Runout" button - #if BOTH(M600_PURGE_MORE_RESUMABLE, ADVANCED_PAUSE_FEATURE) + #if ENABLED(M600_PURGE_MORE_RESUMABLE) pause_menu_response = PAUSE_RESPONSE_RESUME_PRINT; // Simulate menu selection #endif #if HAS_FILAMENT_SENSOR @@ -196,7 +209,7 @@ void HostUI::action(FSTR_P const fstr, const bool eol) { TERN_(HAS_RESUME_CONTINUE, wait_for_user = false); break; case PROMPT_PAUSE_RESUME: - #if BOTH(ADVANCED_PAUSE_FEATURE, SDSUPPORT) + #if ALL(ADVANCED_PAUSE_FEATURE, HAS_MEDIA) extern const char M24_STR[]; queue.inject_P(M24_STR); #endif diff --git a/Marlin/src/feature/host_actions.h b/Marlin/src/feature/host_actions.h index 45379afc..c030ebad 100644 --- a/Marlin/src/feature/host_actions.h +++ b/Marlin/src/feature/host_actions.h @@ -24,11 +24,6 @@ #include "../inc/MarlinConfigPre.h" #include "../HAL/shared/Marduino.h" -typedef union { - uint8_t bits; - struct { bool info:1, errors:1, debug:1; }; -} flag_t; - #if ENABLED(HOST_PROMPT_SUPPORT) enum PromptReason : uint8_t { @@ -40,14 +35,13 @@ typedef union { PROMPT_INFO }; + extern const char CONTINUE_STR[], DISMISS_STR[]; + #endif class HostUI { public: - static flag_t flag; - HostUI() { flag.bits = 0xFF; } - static void action(FSTR_P const fstr, const bool eol=true); #ifdef ACTION_ON_KILL @@ -87,7 +81,14 @@ class HostUI { #if ENABLED(HOST_PROMPT_SUPPORT) private: static void prompt(FSTR_P const ptype, const bool eol=true); - static void prompt_plus(FSTR_P const ptype, FSTR_P const fstr, const char extra_char='\0'); + static void prompt_plus(const bool pgm, FSTR_P const ptype, const char * const str, const char extra_char='\0'); + static void prompt_plus(FSTR_P const ptype, FSTR_P const fstr, const char extra_char='\0') { + prompt_plus(true, ptype, FTOP(fstr), extra_char); + } + static void prompt_plus(FSTR_P const ptype, const char * const cstr, const char extra_char='\0') { + prompt_plus(false, ptype, cstr, extra_char); + } + static void prompt_show(); static void _prompt_show(FSTR_P const btn1, FSTR_P const btn2); @@ -97,15 +98,25 @@ class HostUI { static void handle_response(const uint8_t response); static void notify_P(PGM_P const message); - static inline void notify(FSTR_P const fmsg) { notify_P(FTOP(fmsg)); } + static void notify(FSTR_P const fmsg) { notify_P(FTOP(fmsg)); } static void notify(const char * const message); static void prompt_begin(const PromptReason reason, FSTR_P const fstr, const char extra_char='\0'); - static void prompt_button(FSTR_P const fstr); + static void prompt_begin(const PromptReason reason, const char * const cstr, const char extra_char='\0'); static void prompt_end(); + + static void prompt_button(FSTR_P const fstr); + static void prompt_button(const char * const cstr); + static void prompt_do(const PromptReason reason, FSTR_P const pstr, FSTR_P const btn1=nullptr, FSTR_P const btn2=nullptr); + static void prompt_do(const PromptReason reason, const char * const cstr, FSTR_P const btn1=nullptr, FSTR_P const btn2=nullptr); static void prompt_do(const PromptReason reason, FSTR_P const pstr, const char extra_char, FSTR_P const btn1=nullptr, FSTR_P const btn2=nullptr); - static inline void prompt_open(const PromptReason reason, FSTR_P const pstr, FSTR_P const btn1=nullptr, FSTR_P const btn2=nullptr) { + static void prompt_do(const PromptReason reason, const char * const cstr, const char extra_char, FSTR_P const btn1=nullptr, FSTR_P const btn2=nullptr); + + static void continue_prompt(FSTR_P const fstr) { prompt_do(PROMPT_USER_CONTINUE, fstr, FPSTR(CONTINUE_STR)); } + static void continue_prompt(const char * const cstr) { prompt_do(PROMPT_USER_CONTINUE, cstr, FPSTR(CONTINUE_STR)); } + + static void prompt_open(const PromptReason reason, FSTR_P const pstr, FSTR_P const btn1=nullptr, FSTR_P const btn2=nullptr) { if (host_prompt_reason == PROMPT_NOT_DEFINED) prompt_do(reason, pstr, btn1, btn2); } @@ -118,5 +129,3 @@ class HostUI { }; extern HostUI hostui; - -extern const char CONTINUE_STR[], DISMISS_STR[]; diff --git a/Marlin/src/feature/hotend_idle.cpp b/Marlin/src/feature/hotend_idle.cpp index 4b137f42..b79cb568 100644 --- a/Marlin/src/feature/hotend_idle.cpp +++ b/Marlin/src/feature/hotend_idle.cpp @@ -37,7 +37,7 @@ #include "../module/planner.h" #include "../lcd/marlinui.h" -extern HotendIdleProtection hotend_idle; +HotendIdleProtection hotend_idle; millis_t HotendIdleProtection::next_protect_ms = 0; diff --git a/Marlin/src/feature/joystick.cpp b/Marlin/src/feature/joystick.cpp index 7f91c154..29addfcf 100644 --- a/Marlin/src/feature/joystick.cpp +++ b/Marlin/src/feature/joystick.cpp @@ -68,13 +68,13 @@ Joystick joystick; void Joystick::report() { SERIAL_ECHOPGM("Joystick"); #if HAS_JOY_ADC_X - SERIAL_ECHOPGM_P(SP_X_STR, JOY_X(x.raw)); + SERIAL_ECHOPGM_P(SP_X_STR, JOY_X(x.getraw())); #endif #if HAS_JOY_ADC_Y - SERIAL_ECHOPGM_P(SP_Y_STR, JOY_Y(y.raw)); + SERIAL_ECHOPGM_P(SP_Y_STR, JOY_Y(y.getraw())); #endif #if HAS_JOY_ADC_Z - SERIAL_ECHOPGM_P(SP_Z_STR, JOY_Z(z.raw)); + SERIAL_ECHOPGM_P(SP_Z_STR, JOY_Z(z.getraw())); #endif #if HAS_JOY_ADC_EN SERIAL_ECHO_TERNARY(READ(JOY_EN_PIN), " EN=", "HIGH (dis", "LOW (en", "abled)"); @@ -91,29 +91,29 @@ Joystick joystick; if (READ(JOY_EN_PIN)) return; #endif - auto _normalize_joy = [](float &axis_jog, const int16_t raw, const int16_t (&joy_limits)[4]) { + auto _normalize_joy = [](float &axis_jog, const raw_adc_t raw, const raw_adc_t (&joy_limits)[4]) { if (WITHIN(raw, joy_limits[0], joy_limits[3])) { // within limits, check deadzone if (raw > joy_limits[2]) axis_jog = (raw - joy_limits[2]) / float(joy_limits[3] - joy_limits[2]); else if (raw < joy_limits[1]) - axis_jog = (raw - joy_limits[1]) / float(joy_limits[1] - joy_limits[0]); // negative value + axis_jog = int16_t(raw - joy_limits[1]) / float(joy_limits[1] - joy_limits[0]); // negative value // Map normal to jog value via quadratic relationship axis_jog = SIGN(axis_jog) * sq(axis_jog); } }; #if HAS_JOY_ADC_X - static constexpr int16_t joy_x_limits[4] = JOY_X_LIMITS; - _normalize_joy(norm_jog.x, JOY_X(x.raw), joy_x_limits); + static constexpr raw_adc_t joy_x_limits[4] = JOY_X_LIMITS; + _normalize_joy(norm_jog.x, JOY_X(x.getraw()), joy_x_limits); #endif #if HAS_JOY_ADC_Y - static constexpr int16_t joy_y_limits[4] = JOY_Y_LIMITS; - _normalize_joy(norm_jog.y, JOY_Y(y.raw), joy_y_limits); + static constexpr raw_adc_t joy_y_limits[4] = JOY_Y_LIMITS; + _normalize_joy(norm_jog.y, JOY_Y(y.getraw()), joy_y_limits); #endif #if HAS_JOY_ADC_Z - static constexpr int16_t joy_z_limits[4] = JOY_Z_LIMITS; - _normalize_joy(norm_jog.z, JOY_Z(z.raw), joy_z_limits); + static constexpr raw_adc_t joy_z_limits[4] = JOY_Z_LIMITS; + _normalize_joy(norm_jog.z, JOY_Z(z.getraw()), joy_z_limits); #endif } @@ -123,7 +123,7 @@ Joystick joystick; void Joystick::inject_jog_moves() { // Recursion barrier - static bool injecting_now; // = false; + static bool injecting_now; // = false if (injecting_now) return; #if ENABLED(NO_MOTION_BEFORE_HOMING) @@ -163,7 +163,7 @@ Joystick joystick; // norm_jog values of [-1 .. 1] maps linearly to [-feedrate .. feedrate] xyz_float_t move_dist{0}; float hypot2 = 0; - LOOP_LINEAR_AXES(i) if (norm_jog[i]) { + LOOP_NUM_AXES(i) if (norm_jog[i]) { move_dist[i] = seg_time * norm_jog[i] * TERN(EXTENSIBLE_UI, manual_feedrate_mm_s, planner.settings.max_feedrate_mm_s)[i]; hypot2 += sq(move_dist[i]); } @@ -172,8 +172,9 @@ Joystick joystick; current_position += move_dist; apply_motion_limits(current_position); const float length = sqrt(hypot2); + PlannerHints hints(length); injecting_now = true; - planner.buffer_line(current_position, length / seg_time, active_extruder, length); + planner.buffer_line(current_position, length / seg_time, active_extruder, hints); injecting_now = false; } } diff --git a/Marlin/src/feature/leds/leds.cpp b/Marlin/src/feature/leds/leds.cpp index 17d790b8..8e381ac7 100644 --- a/Marlin/src/feature/leds/leds.cpp +++ b/Marlin/src/feature/leds/leds.cpp @@ -30,20 +30,8 @@ #include "leds.h" -#if ENABLED(BLINKM) - #include "blinkm.h" -#endif - -#if ENABLED(PCA9632) - #include "pca9632.h" -#endif - -#if ENABLED(PCA9533) - #include "pca9533.h" -#endif - -#if ENABLED(CASE_LIGHT_USE_RGB_LED) - #include "../../feature/caselight.h" +#if ANY(CASE_LIGHT_USE_RGB_LED, CASE_LIGHT_USE_NEOPIXEL) + #include "../caselight.h" #endif #if ENABLED(LED_COLOR_PRESETS) @@ -62,14 +50,107 @@ LEDLights leds; void LEDLights::setup() { - #if EITHER(RGB_LED, RGBW_LED) + #if ANY(RGB_LED, RGBW_LED) if (PWM_PIN(RGB_LED_R_PIN)) SET_PWM(RGB_LED_R_PIN); else SET_OUTPUT(RGB_LED_R_PIN); if (PWM_PIN(RGB_LED_G_PIN)) SET_PWM(RGB_LED_G_PIN); else SET_OUTPUT(RGB_LED_G_PIN); if (PWM_PIN(RGB_LED_B_PIN)) SET_PWM(RGB_LED_B_PIN); else SET_OUTPUT(RGB_LED_B_PIN); #if ENABLED(RGBW_LED) if (PWM_PIN(RGB_LED_W_PIN)) SET_PWM(RGB_LED_W_PIN); else SET_OUTPUT(RGB_LED_W_PIN); #endif - #endif + + #if ENABLED(RGB_STARTUP_TEST) + int8_t led_pin_count = 0; + if (PWM_PIN(RGB_LED_R_PIN) && PWM_PIN(RGB_LED_G_PIN) && PWM_PIN(RGB_LED_B_PIN)) led_pin_count = 3; + #if ENABLED(RGBW_LED) + if (PWM_PIN(RGB_LED_W_PIN) && led_pin_count) led_pin_count++; + #endif + // Startup animation + if (led_pin_count) { + // blackout + if (PWM_PIN(RGB_LED_R_PIN)) hal.set_pwm_duty(pin_t(RGB_LED_R_PIN), 0); else WRITE(RGB_LED_R_PIN, LOW); + if (PWM_PIN(RGB_LED_G_PIN)) hal.set_pwm_duty(pin_t(RGB_LED_G_PIN), 0); else WRITE(RGB_LED_G_PIN, LOW); + if (PWM_PIN(RGB_LED_B_PIN)) hal.set_pwm_duty(pin_t(RGB_LED_B_PIN), 0); else WRITE(RGB_LED_B_PIN, LOW); + #if ENABLED(RGBW_LED) + if (PWM_PIN(RGB_LED_W_PIN)) hal.set_pwm_duty(pin_t(RGB_LED_W_PIN), 0); + else WRITE(RGB_LED_W_PIN, LOW); + #endif + delay(200); + + for (uint8_t i = 0; i < led_pin_count; ++i) { + for (uint8_t b = 0; b <= 200; ++b) { + const uint16_t led_pwm = b <= 100 ? b : 200 - b; + if (i == 0 && PWM_PIN(RGB_LED_R_PIN)) hal.set_pwm_duty(pin_t(RGB_LED_R_PIN), led_pwm); else WRITE(RGB_LED_R_PIN, b < 100 ? HIGH : LOW); + if (i == 1 && PWM_PIN(RGB_LED_G_PIN)) hal.set_pwm_duty(pin_t(RGB_LED_G_PIN), led_pwm); else WRITE(RGB_LED_G_PIN, b < 100 ? HIGH : LOW); + if (i == 2 && PWM_PIN(RGB_LED_B_PIN)) hal.set_pwm_duty(pin_t(RGB_LED_B_PIN), led_pwm); else WRITE(RGB_LED_B_PIN, b < 100 ? HIGH : LOW); + #if ENABLED(RGBW_LED) + if (i == 3) { + if (PWM_PIN(RGB_LED_W_PIN)) hal.set_pwm_duty(pin_t(RGB_LED_W_PIN), led_pwm); + else WRITE(RGB_LED_W_PIN, b < 100 ? HIGH : LOW); + delay(RGB_STARTUP_TEST_INNER_MS);//More slowing for ending + } + #endif + delay(RGB_STARTUP_TEST_INNER_MS); + } + } + delay(500); + } + #endif // RGB_STARTUP_TEST + + #elif ALL(PCA9632, RGB_STARTUP_TEST) // PCA9632 RGB_STARTUP_TEST + + constexpr int8_t led_pin_count = TERN(HAS_WHITE_LED, 4, 3); + + // Startup animation + LEDColor curColor = LEDColorOff(); + PCA9632_set_led_color(curColor); // blackout + delay(200); + + /** + * LED Pin Counter steps -> events + * | 0-100 | 100-200 | 200-300 | 300-400 | + * fade in steady | fade out + * start next pin fade in + */ + + uint16_t led_pin_counters[led_pin_count] = { 1, 0, 0 }; + + bool canEnd = false; + while (led_pin_counters[0] != 99 || !canEnd) { + if (led_pin_counters[0] == 99) // End loop next time pin0 counter is 99 + canEnd = true; + for (uint8_t i = 0; i < led_pin_count; ++i) { + if (led_pin_counters[i] > 0) { + if (++led_pin_counters[i] == 400) // turn off current pin counter in led_pin_counters + led_pin_counters[i] = 0; + else if (led_pin_counters[i] == 201) { // start next pin pwm + led_pin_counters[i + 1 == led_pin_count ? 0 : i + 1] = 1; + i++; // skip next pin in this loop so it doesn't increment twice + } + } + } + uint16_t r, g, b; + r = led_pin_counters[0]; curColor.r = r <= 100 ? r : r <= 300 ? 100 : 400 - r; + g = led_pin_counters[1]; curColor.g = g <= 100 ? g : g <= 300 ? 100 : 400 - g; + b = led_pin_counters[2]; curColor.b = b <= 100 ? b : b <= 300 ? 100 : 400 - b; + #if HAS_WHITE_LED + const uint16_t w = led_pin_counters[3]; curColor.w = w <= 100 ? w : w <= 300 ? 100 : 400 - w; + #endif + PCA9632_set_led_color(curColor); + delay(RGB_STARTUP_TEST_INNER_MS); + } + + // Fade to white + for (uint8_t led_pwm = 0; led_pwm <= 100; ++led_pwm) { + NOLESS(curColor.r, led_pwm); + NOLESS(curColor.g, led_pwm); + NOLESS(curColor.b, led_pwm); + TERN_(HAS_WHITE_LED, NOLESS(curColor.w, led_pwm)); + PCA9632_set_led_color(curColor); + delay(RGB_STARTUP_TEST_INNER_MS); + } + + #endif // PCA9632 && RGB_STARTUP_TEST + TERN_(NEOPIXEL_LED, neo.init()); TERN_(PCA9533, PCA9533_init()); TERN_(LED_USER_PRESET_STARTUP, set_default()); @@ -95,6 +176,10 @@ void LEDLights::set_color(const LEDColor &incol #endif #endif + #if ALL(CASE_LIGHT_MENU, CASE_LIGHT_USE_NEOPIXEL) + // Update brightness only if caselight is ON or switching leds off + if (caselight.on || incol.is_off()) + #endif neo.set_brightness(incol.i); #if ENABLED(NEOPIXEL_IS_SEQUENTIAL) @@ -106,6 +191,10 @@ void LEDLights::set_color(const LEDColor &incol } #endif + #if ALL(CASE_LIGHT_MENU, CASE_LIGHT_USE_NEOPIXEL) + // Update color only if caselight is ON or switching leds off + if (caselight.on || incol.is_off()) + #endif neo.set_color(neocolor); #endif @@ -117,15 +206,15 @@ void LEDLights::set_color(const LEDColor &incol #endif - #if EITHER(RGB_LED, RGBW_LED) + #if ANY(RGB_LED, RGBW_LED) // This variant uses 3-4 separate pins for the RGB(W) components. // If the pins can do PWM then their intensity will be set. - #define _UPDATE_RGBW(C,c) do { \ - if (PWM_PIN(RGB_LED_##C##_PIN)) \ - set_pwm_duty(pin_t(RGB_LED_##C##_PIN), c); \ - else \ - WRITE(RGB_LED_##C##_PIN, c ? HIGH : LOW); \ + #define _UPDATE_RGBW(C,c) do { \ + if (PWM_PIN(RGB_LED_##C##_PIN)) \ + hal.set_pwm_duty(pin_t(RGB_LED_##C##_PIN), c); \ + else \ + WRITE(RGB_LED_##C##_PIN, c ? HIGH : LOW); \ }while(0) #define UPDATE_RGBW(C,c) _UPDATE_RGBW(C, TERN1(CASE_LIGHT_USE_RGB_LED, caselight.on) ? incol.c : 0) UPDATE_RGBW(R,r); UPDATE_RGBW(G,g); UPDATE_RGBW(B,b); @@ -139,7 +228,7 @@ void LEDLights::set_color(const LEDColor &incol TERN_(PCA9632, PCA9632_set_led_color(incol)); TERN_(PCA9533, PCA9533_set_rgb(incol.r, incol.g, incol.b)); - #if EITHER(LED_CONTROL_MENU, PRINTER_EVENT_LEDS) + #if ANY(LED_CONTROL_MENU, PRINTER_EVENT_LEDS) // Don't update the color when OFF lights_on = !incol.is_off(); if (lights_on) color = incol; @@ -150,7 +239,7 @@ void LEDLights::set_color(const LEDColor &incol void LEDLights::toggle() { if (lights_on) set_off(); else update(); } #endif -#ifdef LED_BACKLIGHT_TIMEOUT +#if LED_POWEROFF_TIMEOUT > 0 millis_t LEDLights::led_off_time; // = 0 diff --git a/Marlin/src/feature/leds/leds.h b/Marlin/src/feature/leds/leds.h index 74964b51..7a31ca68 100644 --- a/Marlin/src/feature/leds/leds.h +++ b/Marlin/src/feature/leds/leds.h @@ -30,7 +30,7 @@ #include // A white component can be passed -#if EITHER(RGBW_LED, PCA9632_RGBW) +#if ANY(RGBW_LED, PCA9632_RGBW) #define HAS_WHITE_LED 1 #endif @@ -40,6 +40,18 @@ #undef _NEOPIXEL_INCLUDE_ #endif +#if ENABLED(BLINKM) + #include "blinkm.h" +#endif + +#if ENABLED(PCA9533) + #include "pca9533.h" +#endif + +#if ENABLED(PCA9632) + #include "pca9632.h" +#endif + /** * LEDcolor type for use with leds.set_color */ @@ -54,6 +66,8 @@ typedef struct LEDColor { OPTARG(NEOPIXEL_LED, i(NEOPIXEL_BRIGHTNESS)) {} + LEDColor(const LEDColor&) = default; + LEDColor(uint8_t r, uint8_t g, uint8_t b OPTARG(HAS_WHITE_LED, uint8_t w=0) OPTARG(NEOPIXEL_LED, uint8_t i=NEOPIXEL_BRIGHTNESS)) : r(r), g(g), b(b) OPTARG(HAS_WHITE_LED, w(w)) OPTARG(NEOPIXEL_LED, i(i)) {} @@ -68,11 +82,6 @@ typedef struct LEDColor { return *this; } - LEDColor& operator=(const LEDColor &right) { - if (this != &right) memcpy(this, &right, sizeof(LEDColor)); - return *this; - } - bool operator==(const LEDColor &right) { if (this == &right) return true; return 0 == memcmp(this, &right, sizeof(LEDColor)); @@ -110,6 +119,13 @@ typedef struct LEDColor { class LEDLights { public: + #if ANY(LED_CONTROL_MENU, PRINTER_EVENT_LEDS, CASE_LIGHT_IS_COLOR_LED) + static LEDColor color; // last non-off color + static bool lights_on; // the last set color was "on" + #else + static constexpr bool lights_on = true; + #endif + LEDLights() {} // ctor static void setup(); // init() @@ -118,7 +134,7 @@ class LEDLights { OPTARG(NEOPIXEL_IS_SEQUENTIAL, bool isSequence=false) ); - static inline void set_color(uint8_t r, uint8_t g, uint8_t b + static void set_color(uint8_t r, uint8_t g, uint8_t b OPTARG(HAS_WHITE_LED, uint8_t w=0) OPTARG(NEOPIXEL_LED, uint8_t i=NEOPIXEL_BRIGHTNESS) OPTARG(NEOPIXEL_IS_SEQUENTIAL, bool isSequence=false) @@ -126,43 +142,38 @@ class LEDLights { set_color(LEDColor(r, g, b OPTARG(HAS_WHITE_LED, w) OPTARG(NEOPIXEL_LED, i)) OPTARG(NEOPIXEL_IS_SEQUENTIAL, isSequence)); } - static inline void set_off() { set_color(LEDColorOff()); } - static inline void set_green() { set_color(LEDColorGreen()); } - static inline void set_white() { set_color(LEDColorWhite()); } + static void set_off() { set_color(LEDColorOff()); } + static void set_green() { set_color(LEDColorGreen()); } + static void set_white() { set_color(LEDColorWhite()); } #if ENABLED(LED_COLOR_PRESETS) static const LEDColor defaultLEDColor; - static inline void set_default() { set_color(defaultLEDColor); } - static inline void set_red() { set_color(LEDColorRed()); } - static inline void set_orange() { set_color(LEDColorOrange()); } - static inline void set_yellow() { set_color(LEDColorYellow()); } - static inline void set_blue() { set_color(LEDColorBlue()); } - static inline void set_indigo() { set_color(LEDColorIndigo()); } - static inline void set_violet() { set_color(LEDColorViolet()); } + static void set_default() { set_color(defaultLEDColor); } + static void set_red() { set_color(LEDColorRed()); } + static void set_orange() { set_color(LEDColorOrange()); } + static void set_yellow() { set_color(LEDColorYellow()); } + static void set_blue() { set_color(LEDColorBlue()); } + static void set_indigo() { set_color(LEDColorIndigo()); } + static void set_violet() { set_color(LEDColorViolet()); } #endif #if ENABLED(PRINTER_EVENT_LEDS) - static inline LEDColor get_color() { return lights_on ? color : LEDColorOff(); } - #endif - - #if ANY(LED_CONTROL_MENU, PRINTER_EVENT_LEDS, CASE_LIGHT_IS_COLOR_LED) - static LEDColor color; // last non-off color - static bool lights_on; // the last set color was "on" + static LEDColor get_color() { return lights_on ? color : LEDColorOff(); } #endif #if ENABLED(LED_CONTROL_MENU) static void toggle(); // swap "off" with color #endif - #if EITHER(LED_CONTROL_MENU, CASE_LIGHT_USE_RGB_LED) - static inline void update() { set_color(color); } + #if ANY(LED_CONTROL_MENU, CASE_LIGHT_USE_RGB_LED) || LED_POWEROFF_TIMEOUT > 0 + static void update() { set_color(color); } #endif - #ifdef LED_BACKLIGHT_TIMEOUT + #if LED_POWEROFF_TIMEOUT > 0 private: static millis_t led_off_time; public: - static inline void reset_timeout(const millis_t &ms) { - led_off_time = ms + LED_BACKLIGHT_TIMEOUT; + static void reset_timeout(const millis_t &ms) { + led_off_time = ms + LED_POWEROFF_TIMEOUT; if (!lights_on) update(); } static void update_timeout(const bool power_on); @@ -181,7 +192,7 @@ extern LEDLights leds; static void set_color(const LEDColor &color); - static inline void set_color(uint8_t r, uint8_t g, uint8_t b + static void set_color(uint8_t r, uint8_t g, uint8_t b OPTARG(HAS_WHITE_LED, uint8_t w=0) OPTARG(NEOPIXEL_LED, uint8_t i=NEOPIXEL_BRIGHTNESS) ) { @@ -191,26 +202,26 @@ extern LEDLights leds; )); } - static inline void set_off() { set_color(LEDColorOff()); } - static inline void set_green() { set_color(LEDColorGreen()); } - static inline void set_white() { set_color(LEDColorWhite()); } + static void set_off() { set_color(LEDColorOff()); } + static void set_green() { set_color(LEDColorGreen()); } + static void set_white() { set_color(LEDColorWhite()); } #if ENABLED(NEO2_COLOR_PRESETS) static const LEDColor defaultLEDColor; - static inline void set_default() { set_color(defaultLEDColor); } - static inline void set_red() { set_color(LEDColorRed()); } - static inline void set_orange() { set_color(LEDColorOrange()); } - static inline void set_yellow() { set_color(LEDColorYellow()); } - static inline void set_blue() { set_color(LEDColorBlue()); } - static inline void set_indigo() { set_color(LEDColorIndigo()); } - static inline void set_violet() { set_color(LEDColorViolet()); } + static void set_default() { set_color(defaultLEDColor); } + static void set_red() { set_color(LEDColorRed()); } + static void set_orange() { set_color(LEDColorOrange()); } + static void set_yellow() { set_color(LEDColorYellow()); } + static void set_blue() { set_color(LEDColorBlue()); } + static void set_indigo() { set_color(LEDColorIndigo()); } + static void set_violet() { set_color(LEDColorViolet()); } #endif #if ENABLED(NEOPIXEL2_SEPARATE) static LEDColor color; // last non-off color static bool lights_on; // the last set color was "on" static void toggle(); // swap "off" with color - static inline void update() { set_color(color); } + static void update() { set_color(color); } #endif }; diff --git a/Marlin/src/feature/leds/neopixel.cpp b/Marlin/src/feature/leds/neopixel.cpp index 3569cb18..d157ba73 100644 --- a/Marlin/src/feature/leds/neopixel.cpp +++ b/Marlin/src/feature/leds/neopixel.cpp @@ -30,7 +30,7 @@ #include "leds.h" -#if EITHER(NEOPIXEL_STARTUP_TEST, NEOPIXEL2_STARTUP_TEST) +#if ANY(NEOPIXEL_STARTUP_TEST, NEOPIXEL2_STARTUP_TEST) #include "../../core/utility.h" #endif @@ -44,17 +44,17 @@ Adafruit_NeoPixel Marlin_NeoPixel::adaneo1(NEOPIXEL_PIXELS, NEOPIXEL_PIN, NEOPIX #ifdef NEOPIXEL_BKGD_INDEX_FIRST - void Marlin_NeoPixel::set_background_color(uint8_t r, uint8_t g, uint8_t b, uint8_t w) { - for (int background_led = NEOPIXEL_BKGD_INDEX_FIRST; background_led <= NEOPIXEL_BKGD_INDEX_LAST; background_led++) + void Marlin_NeoPixel::set_background_color(const uint8_t r, const uint8_t g, const uint8_t b, const uint8_t w) { + for (int background_led = NEOPIXEL_BKGD_INDEX_FIRST; background_led <= NEOPIXEL_BKGD_INDEX_LAST; background_led++) set_pixel_color(background_led, adaneo1.Color(r, g, b, w)); } void Marlin_NeoPixel::reset_background_color() { constexpr uint8_t background_color[4] = NEOPIXEL_BKGD_COLOR; - set_background_color(background_color[0], background_color[1], background_color[2], background_color[3]); + set_background_color(background_color); } -#endif +#endif // NEOPIXEL_BKGD_INDEX_FIRST void Marlin_NeoPixel::set_color(const uint32_t color) { if (neoindex >= 0) { diff --git a/Marlin/src/feature/leds/neopixel.h b/Marlin/src/feature/leds/neopixel.h index 814ae9c8..bb5d5d93 100644 --- a/Marlin/src/feature/leds/neopixel.h +++ b/Marlin/src/feature/leds/neopixel.h @@ -25,8 +25,6 @@ * NeoPixel support */ -#define MAX_NEOPIXELS 127 - #ifndef _NEOPIXEL_INCLUDE_ #error "Always include 'leds.h' and not 'neopixel.h' directly." #endif @@ -60,7 +58,7 @@ #define MULTIPLE_NEOPIXEL_TYPES 1 #endif -#if EITHER(MULTIPLE_NEOPIXEL_TYPES, NEOPIXEL2_INSERIES) +#if ANY(MULTIPLE_NEOPIXEL_TYPES, NEOPIXEL2_INSERIES) #define CONJOINED_NEOPIXEL 1 #endif @@ -68,7 +66,7 @@ // Types // ------------------------ -typedef IF<(MAX_NEOPIXELS > 127), int16_t, int8_t>::type pixel_index_t; +typedef value_t(TERN0(NEOPIXEL_LED, NEOPIXEL_PIXELS)) pixel_index_t; // ------------------------ // Classes @@ -90,16 +88,17 @@ class Marlin_NeoPixel { static void set_color(const uint32_t c); #ifdef NEOPIXEL_BKGD_INDEX_FIRST - static void set_background_color(uint8_t r, uint8_t g, uint8_t b, uint8_t w); + static void set_background_color(const uint8_t r, const uint8_t g, const uint8_t b, const uint8_t w); + static void set_background_color(const uint8_t (&rgbw)[4]) { set_background_color(rgbw[0], rgbw[1], rgbw[2], rgbw[3]); } static void reset_background_color(); #endif - static inline void begin() { + static void begin() { adaneo1.begin(); TERN_(CONJOINED_NEOPIXEL, adaneo2.begin()); } - static inline void set_pixel_color(const uint16_t n, const uint32_t c) { + static void set_pixel_color(const uint16_t n, const uint32_t c) { #if ENABLED(NEOPIXEL2_INSERIES) if (n >= NEOPIXEL_PIXELS) adaneo2.setPixelColor(n - (NEOPIXEL_PIXELS), c); else adaneo1.setPixelColor(n, c); @@ -109,12 +108,12 @@ class Marlin_NeoPixel { #endif } - static inline void set_brightness(const uint8_t b) { + static void set_brightness(const uint8_t b) { adaneo1.setBrightness(b); TERN_(CONJOINED_NEOPIXEL, adaneo2.setBrightness(b)); } - static inline void show() { + static void show() { // Some platforms cannot maintain PWM output when NeoPixel disables interrupts for long durations. TERN_(HAS_PAUSE_SERVO_OUTPUT, PAUSE_SERVO_OUTPUT()); adaneo1.show(); @@ -130,11 +129,18 @@ class Marlin_NeoPixel { } // Accessors - static inline uint16_t pixels() { return adaneo1.numPixels() * TERN1(NEOPIXEL2_INSERIES, 2); } + static uint16_t pixels() { return MUL_TERN(NEOPIXEL2_INSERIES, adaneo1.numPixels(), 2); } + + static uint32_t pixel_color(const uint16_t n) { + #if ENABLED(NEOPIXEL2_INSERIES) + if (n >= NEOPIXEL_PIXELS) return adaneo2.getPixelColor(n - (NEOPIXEL_PIXELS)); + #endif + return adaneo1.getPixelColor(n); + } - static inline uint8_t brightness() { return adaneo1.getBrightness(); } + static uint8_t brightness() { return adaneo1.getBrightness(); } - static inline uint32_t Color(uint8_t r, uint8_t g, uint8_t b OPTARG(HAS_WHITE_LED, uint8_t w)) { + static uint32_t Color(uint8_t r, uint8_t g, uint8_t b OPTARG(HAS_WHITE_LED, uint8_t w)) { return adaneo1.Color(r, g, b OPTARG(HAS_WHITE_LED, w)); } }; @@ -165,18 +171,19 @@ extern Marlin_NeoPixel neo; static void set_color(const uint32_t c); - static inline void begin() { adaneo.begin(); } - static inline void set_pixel_color(const uint16_t n, const uint32_t c) { adaneo.setPixelColor(n, c); } - static inline void set_brightness(const uint8_t b) { adaneo.setBrightness(b); } - static inline void show() { + static void begin() { adaneo.begin(); } + static void set_pixel_color(const uint16_t n, const uint32_t c) { adaneo.setPixelColor(n, c); } + static void set_brightness(const uint8_t b) { adaneo.setBrightness(b); } + static void show() { adaneo.show(); adaneo.setPin(NEOPIXEL2_PIN); } // Accessors - static inline uint16_t pixels() { return adaneo.numPixels();} - static inline uint8_t brightness() { return adaneo.getBrightness(); } - static inline uint32_t Color(uint8_t r, uint8_t g, uint8_t b OPTARG(HAS_WHITE_LED2, uint8_t w)) { + static uint16_t pixels() { return adaneo.numPixels();} + static uint32_t pixel_color(const uint16_t n) { return adaneo.getPixelColor(n); } + static uint8_t brightness() { return adaneo.getBrightness(); } + static uint32_t Color(uint8_t r, uint8_t g, uint8_t b OPTARG(HAS_WHITE_LED2, uint8_t w)) { return adaneo.Color(r, g, b OPTARG(HAS_WHITE_LED2, w)); } }; diff --git a/Marlin/src/feature/leds/pca9533.cpp b/Marlin/src/feature/leds/pca9533.cpp index 914db21b..d71760e2 100644 --- a/Marlin/src/feature/leds/pca9533.cpp +++ b/Marlin/src/feature/leds/pca9533.cpp @@ -1,4 +1,4 @@ -/* +/** * Marlin 3D Printer Firmware * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * diff --git a/Marlin/src/feature/leds/pca9533.h b/Marlin/src/feature/leds/pca9533.h index 431058c4..3a18e96b 100644 --- a/Marlin/src/feature/leds/pca9533.h +++ b/Marlin/src/feature/leds/pca9533.h @@ -1,4 +1,4 @@ -/* +/** * Marlin 3D Printer Firmware * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * @@ -21,7 +21,7 @@ */ #pragma once -/* +/** * Driver for the PCA9533 LED controller found on the MightyBoard * used by FlashForge Creator Pro, MakerBot, etc. * Written 2020 APR 01 by grauerfuchs diff --git a/Marlin/src/feature/leds/pca9632.cpp b/Marlin/src/feature/leds/pca9632.cpp index abea9880..40c16a92 100644 --- a/Marlin/src/feature/leds/pca9632.cpp +++ b/Marlin/src/feature/leds/pca9632.cpp @@ -148,7 +148,7 @@ void PCA9632_set_led_color(const LEDColor &color) { #if ENABLED(PCA9632_BUZZER) - void PCA9632_buzz(const long, const uint16_t) { + void PCA9632_buzz(const long, const uint16_t/*=0*/) { uint8_t data[] = PCA9632_BUZZER_DATA; Wire.beginTransmission(I2C_ADDRESS(PCA9632_ADDRESS)); Wire.write(data, sizeof(data)); diff --git a/Marlin/src/feature/leds/pca9632.h b/Marlin/src/feature/leds/pca9632.h index fb59a8c1..adef0200 100644 --- a/Marlin/src/feature/leds/pca9632.h +++ b/Marlin/src/feature/leds/pca9632.h @@ -33,5 +33,5 @@ void PCA9632_set_led_color(const LEDColor &color); #if ENABLED(PCA9632_BUZZER) #include - void PCA9632_buzz(const long, const uint16_t); + void PCA9632_buzz(const long, const uint16_t=0); #endif diff --git a/Marlin/src/feature/leds/printer_event_leds.h b/Marlin/src/feature/leds/printer_event_leds.h index b2201433..3a037eba 100644 --- a/Marlin/src/feature/leds/printer_event_leds.h +++ b/Marlin/src/feature/leds/printer_event_leds.h @@ -36,32 +36,32 @@ class PrinterEventLEDs { static bool leds_off_after_print; #endif - static inline void set_done() { TERN(LED_COLOR_PRESETS, leds.set_default(), leds.set_off()); } + static void set_done() { TERN(LED_COLOR_PRESETS, leds.set_default(), leds.set_off()); } public: #if HAS_TEMP_HOTEND - static inline LEDColor onHotendHeatingStart() { old_intensity = 0; return leds.get_color(); } + static LEDColor onHotendHeatingStart() { old_intensity = 0; return leds.get_color(); } static void onHotendHeating(const celsius_t start, const celsius_t current, const celsius_t target); #endif #if HAS_HEATED_BED - static inline LEDColor onBedHeatingStart() { old_intensity = 127; return leds.get_color(); } + static LEDColor onBedHeatingStart() { old_intensity = 127; return leds.get_color(); } static void onBedHeating(const celsius_t start, const celsius_t current, const celsius_t target); #endif #if HAS_HEATED_CHAMBER - static inline LEDColor onChamberHeatingStart() { old_intensity = 127; return leds.get_color(); } + static LEDColor onChamberHeatingStart() { old_intensity = 127; return leds.get_color(); } static void onChamberHeating(const celsius_t start, const celsius_t current, const celsius_t target); #endif #if HAS_TEMP_HOTEND || HAS_HEATED_BED || HAS_HEATED_CHAMBER - static inline void onHeatingDone() { leds.set_white(); } - static inline void onPidTuningDone(LEDColor c) { leds.set_color(c); } + static void onHeatingDone() { leds.set_white(); } + static void onPidTuningDone(LEDColor c) { leds.set_color(c); } #endif - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA - static inline void onPrintCompleted() { + static void onPrintCompleted() { leds.set_green(); #if HAS_LEDS_OFF_FLAG leds_off_after_print = true; @@ -71,7 +71,7 @@ class PrinterEventLEDs { #endif } - static inline void onResumeAfterWait() { + static void onResumeAfterWait() { #if HAS_LEDS_OFF_FLAG if (leds_off_after_print) { set_done(); @@ -80,7 +80,7 @@ class PrinterEventLEDs { #endif } - #endif // SDSUPPORT + #endif // HAS_MEDIA }; extern PrinterEventLEDs printerEventLEDs; diff --git a/Marlin/src/feature/max7219.cpp b/Marlin/src/feature/max7219.cpp index 474933aa..ac2881c0 100644 --- a/Marlin/src/feature/max7219.cpp +++ b/Marlin/src/feature/max7219.cpp @@ -39,12 +39,11 @@ #if ENABLED(MAX7219_DEBUG) -#define MAX7219_ERRORS // Disable to save 406 bytes of Program Memory +#define MAX7219_ERRORS // Requires ~400 bytes of flash #include "max7219.h" #include "../module/planner.h" -#include "../module/stepper.h" #include "../MarlinCore.h" #include "../HAL/shared/Delay.h" @@ -52,6 +51,7 @@ #define HAS_SIDE_BY_SIDE 1 #endif +#define _ROT ((MAX7219_ROTATE + 360) % 360) #if _ROT == 0 || _ROT == 180 #define MAX7219_X_LEDS TERN(HAS_SIDE_BY_SIDE, 8, MAX7219_LINES) #define MAX7219_Y_LEDS TERN(HAS_SIDE_BY_SIDE, MAX7219_LINES, 8) @@ -62,6 +62,15 @@ #error "MAX7219_ROTATE must be a multiple of +/- 90°." #endif +#ifdef MAX7219_DEBUG_PROFILE + CodeProfiler::Mode CodeProfiler::mode = ACCUMULATE_AVERAGE; + uint8_t CodeProfiler::instance_count = 0; + uint32_t CodeProfiler::last_calc_time = micros(); + uint8_t CodeProfiler::time_fraction = 0; + uint32_t CodeProfiler::total_time = 0; + uint16_t CodeProfiler::call_count = 0; +#endif + Max7219 max7219; uint8_t Max7219::led_line[MAX7219_LINES]; // = { 0 }; @@ -69,7 +78,7 @@ uint8_t Max7219::suspended; // = 0; #define LINE_REG(Q) (max7219_reg_digit0 + ((Q) & 0x7)) -#if _ROT == 0 || _ROT == 270 +#if (_ROT == 0 || _ROT == 270) == DISABLED(MAX7219_REVERSE_EACH) #define _LED_BIT(Q) (7 - ((Q) & 0x7)) #else #define _LED_BIT(Q) ((Q) & 0x7) @@ -127,7 +136,7 @@ uint8_t Max7219::suspended; // = 0; void Max7219::error(FSTR_P const func, const int32_t v1, const int32_t v2/*=-1*/) { #if ENABLED(MAX7219_ERRORS) SERIAL_ECHOPGM("??? Max7219::"); - SERIAL_ECHOF(func, AS_CHAR('(')); + SERIAL_ECHOF(func, C('(')); SERIAL_ECHO(v1); if (v2 > 0) SERIAL_ECHOPGM(", ", v2); SERIAL_CHAR(')'); @@ -146,7 +155,7 @@ void Max7219::error(FSTR_P const func, const int32_t v1, const int32_t v2/*=-1*/ */ inline uint32_t flipped(const uint32_t bits, const uint8_t n_bytes) { uint32_t mask = 1, outbits = 0; - LOOP_L_N(b, n_bytes * 8) { + for (uint8_t b = 0; b < n_bytes * 8; ++b) { outbits <<= 1; if (bits & mask) outbits |= 1; mask <<= 1; @@ -266,26 +275,27 @@ void Max7219::set(const uint8_t line, const uint8_t bits) { #endif // MAX7219_NUMERIC // Modify a single LED bit and send the changed line -void Max7219::led_set(const uint8_t x, const uint8_t y, const bool on) { +void Max7219::led_set(const uint8_t x, const uint8_t y, const bool on, uint8_t * const rcm/*=nullptr*/) { if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(F("led_set"), x, y); if (BIT_7219(x, y) == on) return; XOR_7219(x, y); refresh_unit_line(LED_IND(x, y)); + if (rcm != nullptr) *rcm |= _BV(LED_IND(x, y) & 0x07); } -void Max7219::led_on(const uint8_t x, const uint8_t y) { +void Max7219::led_on(const uint8_t x, const uint8_t y, uint8_t * const rcm/*=nullptr*/) { if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(F("led_on"), x, y); - led_set(x, y, true); + led_set(x, y, true, rcm); } -void Max7219::led_off(const uint8_t x, const uint8_t y) { +void Max7219::led_off(const uint8_t x, const uint8_t y, uint8_t * const rcm/*=nullptr*/) { if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(F("led_off"), x, y); - led_set(x, y, false); + led_set(x, y, false, rcm); } -void Max7219::led_toggle(const uint8_t x, const uint8_t y) { +void Max7219::led_toggle(const uint8_t x, const uint8_t y, uint8_t * const rcm/*=nullptr*/) { if (x >= MAX7219_X_LEDS || y >= MAX7219_Y_LEDS) return error(F("led_toggle"), x, y); - led_set(x, y, !BIT_7219(x, y)); + led_set(x, y, !BIT_7219(x, y), rcm); } void Max7219::send_row(const uint8_t row) { @@ -328,13 +338,13 @@ void Max7219::fill() { void Max7219::clear_row(const uint8_t row) { if (row >= MAX7219_Y_LEDS) return error(F("clear_row"), row); - LOOP_L_N(x, MAX7219_X_LEDS) CLR_7219(x, row); + for (uint8_t x = 0; x < MAX7219_X_LEDS; ++x) CLR_7219(x, row); send_row(row); } void Max7219::clear_column(const uint8_t col) { if (col >= MAX7219_X_LEDS) return error(F("set_column"), col); - LOOP_L_N(y, MAX7219_Y_LEDS) CLR_7219(col, y); + for (uint8_t y = 0; y < MAX7219_Y_LEDS; ++y) CLR_7219(col, y); send_column(col); } @@ -346,7 +356,7 @@ void Max7219::clear_column(const uint8_t col) { void Max7219::set_row(const uint8_t row, const uint32_t val) { if (row >= MAX7219_Y_LEDS) return error(F("set_row"), row); uint32_t mask = _BV32(MAX7219_X_LEDS - 1); - LOOP_L_N(x, MAX7219_X_LEDS) { + for (uint8_t x = 0; x < MAX7219_X_LEDS; ++x) { if (val & mask) SET_7219(x, row); else CLR_7219(x, row); mask >>= 1; } @@ -361,7 +371,7 @@ void Max7219::set_row(const uint8_t row, const uint32_t val) { void Max7219::set_column(const uint8_t col, const uint32_t val) { if (col >= MAX7219_X_LEDS) return error(F("set_column"), col); uint32_t mask = _BV32(MAX7219_Y_LEDS - 1); - LOOP_L_N(y, MAX7219_Y_LEDS) { + for (uint8_t y = 0; y < MAX7219_Y_LEDS; ++y) { if (val & mask) SET_7219(col, y); else CLR_7219(col, y); mask >>= 1; } @@ -426,29 +436,29 @@ void Max7219::set_columns_32bits(const uint8_t x, uint32_t val) { // Initialize the Max7219 void Max7219::register_setup() { - LOOP_L_N(i, MAX7219_NUMBER_UNITS) + for (uint8_t i = 0; i < MAX7219_NUMBER_UNITS; ++i) send(max7219_reg_scanLimit, 0x07); pulse_load(); // Tell the chips to load the clocked out data - LOOP_L_N(i, MAX7219_NUMBER_UNITS) + for (uint8_t i = 0; i < MAX7219_NUMBER_UNITS; ++i) send(max7219_reg_decodeMode, 0x00); // Using an led matrix (not digits) pulse_load(); // Tell the chips to load the clocked out data - LOOP_L_N(i, MAX7219_NUMBER_UNITS) + for (uint8_t i = 0; i < MAX7219_NUMBER_UNITS; ++i) send(max7219_reg_shutdown, 0x01); // Not in shutdown mode pulse_load(); // Tell the chips to load the clocked out data - LOOP_L_N(i, MAX7219_NUMBER_UNITS) + for (uint8_t i = 0; i < MAX7219_NUMBER_UNITS; ++i) send(max7219_reg_displayTest, 0x00); // No display test pulse_load(); // Tell the chips to load the clocked out data - LOOP_L_N(i, MAX7219_NUMBER_UNITS) + for (uint8_t i = 0; i < MAX7219_NUMBER_UNITS; ++i) send(max7219_reg_intensity, 0x01 & 0x0F); // The first 0x0F is the value you can set // Range: 0x00 to 0x0F pulse_load(); // Tell the chips to load the clocked out data } -#ifdef MAX7219_INIT_TEST +#if MAX7219_INIT_TEST uint8_t test_mode = 0; millis_t next_patt_ms; @@ -461,7 +471,7 @@ void Max7219::register_setup() { constexpr millis_t pattern_delay = 4; int8_t spiralx, spiraly, spiral_dir; - IF<(MAX7219_LEDS > 255), uint16_t, uint8_t>::type spiral_count; + uvalue_t(MAX7219_LEDS) spiral_count; void Max7219::test_pattern() { constexpr int8_t way[][2] = { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } }; @@ -536,13 +546,9 @@ void Max7219::init() { register_setup(); - LOOP_LE_N(i, 7) { // Empty registers to turn all LEDs off - led_line[i] = 0x00; - send(max7219_reg_digit0 + i, 0); - pulse_load(); // Tell the chips to load the clocked out data - } + clear(); - #ifdef MAX7219_INIT_TEST + #if MAX7219_INIT_TEST start_test_pattern(); #endif } @@ -554,41 +560,55 @@ void Max7219::init() { */ // Apply changes to update a marker -void Max7219::mark16(const uint8_t pos, const uint8_t v1, const uint8_t v2) { +void Max7219::mark16(const uint8_t pos, const uint8_t v1, const uint8_t v2, uint8_t * const rcm/*=nullptr*/) { #if MAX7219_X_LEDS > 8 // At least 16 LEDs on the X-Axis. Use single line. - led_off(v1 & 0xF, pos); - led_on(v2 & 0xF, pos); + led_off(v1 & 0xF, pos, rcm); + led_on(v2 & 0xF, pos, rcm); #elif MAX7219_Y_LEDS > 8 // At least 16 LEDs on the Y-Axis. Use a single column. - led_off(pos, v1 & 0xF); - led_on(pos, v2 & 0xF); + led_off(pos, v1 & 0xF, rcm); + led_on(pos, v2 & 0xF, rcm); #else // Single 8x8 LED matrix. Use two lines to get 16 LEDs. - led_off(v1 & 0x7, pos + (v1 >= 8)); - led_on(v2 & 0x7, pos + (v2 >= 8)); + led_off(v1 & 0x7, pos + (v1 >= 8), rcm); + led_on(v2 & 0x7, pos + (v2 >= 8), rcm); #endif } // Apply changes to update a tail-to-head range -void Max7219::range16(const uint8_t y, const uint8_t ot, const uint8_t nt, const uint8_t oh, const uint8_t nh) { +void Max7219::range16(const uint8_t y, const uint8_t ot, const uint8_t nt, const uint8_t oh, + const uint8_t nh, uint8_t * const rcm/*=nullptr*/) { #if MAX7219_X_LEDS > 8 // At least 16 LEDs on the X-Axis. Use single line. if (ot != nt) for (uint8_t n = ot & 0xF; n != (nt & 0xF) && n != (nh & 0xF); n = (n + 1) & 0xF) - led_off(n & 0xF, y); + led_off(n & 0xF, y, rcm); if (oh != nh) for (uint8_t n = (oh + 1) & 0xF; n != ((nh + 1) & 0xF); n = (n + 1) & 0xF) - led_on(n & 0xF, y); + led_on(n & 0xF, y, rcm); #elif MAX7219_Y_LEDS > 8 // At least 16 LEDs on the Y-Axis. Use a single column. if (ot != nt) for (uint8_t n = ot & 0xF; n != (nt & 0xF) && n != (nh & 0xF); n = (n + 1) & 0xF) - led_off(y, n & 0xF); + led_off(y, n & 0xF, rcm); if (oh != nh) for (uint8_t n = (oh + 1) & 0xF; n != ((nh + 1) & 0xF); n = (n + 1) & 0xF) - led_on(y, n & 0xF); + led_on(y, n & 0xF, rcm); #else // Single 8x8 LED matrix. Use two lines to get 16 LEDs. if (ot != nt) for (uint8_t n = ot & 0xF; n != (nt & 0xF) && n != (nh & 0xF); n = (n + 1) & 0xF) - led_off(n & 0x7, y + (n >= 8)); + led_off(n & 0x7, y + (n >= 8), rcm); if (oh != nh) for (uint8_t n = (oh + 1) & 0xF; n != ((nh + 1) & 0xF); n = (n + 1) & 0xF) - led_on(n & 0x7, y + (n >= 8)); + led_on(n & 0x7, y + (n >= 8), rcm); #endif } // Apply changes to update a quantity -void Max7219::quantity16(const uint8_t pos, const uint8_t ov, const uint8_t nv) { +void Max7219::quantity(const uint8_t pos, const uint8_t ov, const uint8_t nv, uint8_t * const rcm/*=nullptr*/) { + for (uint8_t i = _MIN(nv, ov); i < _MAX(nv, ov); i++) + led_set( + #if MAX7219_X_LEDS >= MAX7219_Y_LEDS + i, pos // Single matrix or multiple matrices in Landscape + #else + pos, i // Multiple matrices in Portrait + #endif + , nv >= ov + , rcm + ); +} + +void Max7219::quantity16(const uint8_t pos, const uint8_t ov, const uint8_t nv, uint8_t * const rcm/*=nullptr*/) { for (uint8_t i = _MIN(nv, ov); i < _MAX(nv, ov); i++) led_set( #if MAX7219_X_LEDS > 8 // At least 16 LEDs on the X-Axis. Use single line. @@ -599,6 +619,7 @@ void Max7219::quantity16(const uint8_t pos, const uint8_t ov, const uint8_t nv) i >> 1, pos + (i & 1) #endif , nv >= ov + , rcm ); } @@ -636,16 +657,20 @@ void Max7219::idle_tasks() { register_setup(); } - #ifdef MAX7219_INIT_TEST + #if MAX7219_INIT_TEST if (test_mode) { run_test_pattern(); return; } #endif + // suspend updates and record which lines have changed for batching later + suspended++; + uint8_t row_change_mask = 0x00; + #if ENABLED(MAX7219_DEBUG_PRINTER_ALIVE) if (do_blink) { - led_toggle(MAX7219_X_LEDS - 1, MAX7219_Y_LEDS - 1); + led_toggle(MAX7219_X_LEDS - 1, MAX7219_Y_LEDS - 1, &row_change_mask); next_blink = ms + 1000; } #endif @@ -655,7 +680,7 @@ void Max7219::idle_tasks() { static int16_t last_head_cnt = 0xF, last_tail_cnt = 0xF; if (last_head_cnt != head || last_tail_cnt != tail) { - range16(MAX7219_DEBUG_PLANNER_HEAD, last_tail_cnt, tail, last_head_cnt, head); + range16(MAX7219_DEBUG_PLANNER_HEAD, last_tail_cnt, tail, last_head_cnt, head, &row_change_mask); last_head_cnt = head; last_tail_cnt = tail; } @@ -665,7 +690,7 @@ void Max7219::idle_tasks() { #ifdef MAX7219_DEBUG_PLANNER_HEAD static int16_t last_head_cnt = 0x1; if (last_head_cnt != head) { - mark16(MAX7219_DEBUG_PLANNER_HEAD, last_head_cnt, head); + mark16(MAX7219_DEBUG_PLANNER_HEAD, last_head_cnt, head, &row_change_mask); last_head_cnt = head; } #endif @@ -673,7 +698,7 @@ void Max7219::idle_tasks() { #ifdef MAX7219_DEBUG_PLANNER_TAIL static int16_t last_tail_cnt = 0x1; if (last_tail_cnt != tail) { - mark16(MAX7219_DEBUG_PLANNER_TAIL, last_tail_cnt, tail); + mark16(MAX7219_DEBUG_PLANNER_TAIL, last_tail_cnt, tail, &row_change_mask); last_tail_cnt = tail; } #endif @@ -682,13 +707,28 @@ void Max7219::idle_tasks() { #ifdef MAX7219_DEBUG_PLANNER_QUEUE static int16_t last_depth = 0; - const int16_t current_depth = (head - tail + BLOCK_BUFFER_SIZE) & (BLOCK_BUFFER_SIZE - 1) & 0xF; + const int16_t current_depth = BLOCK_MOD(head - tail + (BLOCK_BUFFER_SIZE)) & 0xF; if (current_depth != last_depth) { - quantity16(MAX7219_DEBUG_PLANNER_QUEUE, last_depth, current_depth); + quantity16(MAX7219_DEBUG_PLANNER_QUEUE, last_depth, current_depth, &row_change_mask); last_depth = current_depth; } #endif + #ifdef MAX7219_DEBUG_PROFILE + static uint8_t last_time_fraction = 0; + const uint8_t current_time_fraction = (uint16_t(CodeProfiler::get_time_fraction()) * MAX7219_NUMBER_UNITS + 8) / 16; + if (current_time_fraction != last_time_fraction) { + quantity(MAX7219_DEBUG_PROFILE, last_time_fraction, current_time_fraction, &row_change_mask); + last_time_fraction = current_time_fraction; + } + #endif + + // batch line updates + suspended--; + if (!suspended) + for (uint8_t i = 0; i < 8; ++i) if (row_change_mask & _BV(i)) + refresh_line(i); + // After resume() automatically do a refresh() if (suspended == 0x80) { suspended = 0; diff --git a/Marlin/src/feature/max7219.h b/Marlin/src/feature/max7219.h index c25fef17..a6b110fd 100644 --- a/Marlin/src/feature/max7219.h +++ b/Marlin/src/feature/max7219.h @@ -47,7 +47,6 @@ #ifndef MAX7219_ROTATE #define MAX7219_ROTATE 0 #endif -#define _ROT ((MAX7219_ROTATE + 360) % 360) #ifndef MAX7219_NUMBER_UNITS #define MAX7219_NUMBER_UNITS 1 @@ -73,6 +72,67 @@ #define max7219_reg_shutdown 0x0C #define max7219_reg_displayTest 0x0F +#ifdef MAX7219_DEBUG_PROFILE + // This class sums up the amount of time for which its instances exist. + // By default there is one instantiated for the duration of the idle() + // function. But an instance can be created in any code block to measure + // the time spent from the point of instantiation until the CPU leaves + // block. Be careful about having multiple instances of CodeProfiler as + // it does not guard against double counting. In general mixing ISR and + // non-ISR use will require critical sections but note that mode setting + // is atomic so the total or average times can safely be read if you set + // mode to FREEZE first. + class CodeProfiler { + public: + enum Mode : uint8_t { ACCUMULATE_AVERAGE, ACCUMULATE_TOTAL, FREEZE }; + + private: + static Mode mode; + static uint8_t instance_count; + static uint32_t last_calc_time; + static uint32_t total_time; + static uint8_t time_fraction; + static uint16_t call_count; + + uint32_t start_time; + + public: + CodeProfiler() : start_time(micros()) { instance_count++; } + ~CodeProfiler() { + instance_count--; + if (mode == FREEZE) return; + + call_count++; + + const uint32_t now = micros(); + total_time += now - start_time; + + if (mode == ACCUMULATE_TOTAL) return; + + // update time_fraction every hundred milliseconds + if (instance_count == 0 && ELAPSED(now, last_calc_time + 100000)) { + time_fraction = total_time * 128 / (now - last_calc_time); + last_calc_time = now; + total_time = 0; + } + } + + static void set_mode(Mode _mode) { mode = _mode; } + static void reset() { + time_fraction = 0; + last_calc_time = micros(); + total_time = 0; + call_count = 0; + } + // returns fraction of total time which was measured, scaled from 0 to 128 + static uint8_t get_time_fraction() { return time_fraction; } + // returns total time in microseconds + static uint32_t get_total_time() { return total_time; } + + static uint16_t get_call_count() { return call_count; } + }; +#endif + class Max7219 { public: static uint8_t led_line[MAX7219_LINES]; @@ -88,13 +148,13 @@ class Max7219 { static void send(const uint8_t reg, const uint8_t data); // Refresh all units - static inline void refresh() { for (uint8_t i = 0; i < 8; i++) refresh_line(i); } + static void refresh() { for (uint8_t i = 0; i < 8; i++) refresh_line(i); } // Suspend / resume updates to the LED unit // Use these methods to speed up multiple changes // or to apply updates from interrupt context. - static inline void suspend() { suspended++; } - static inline void resume() { suspended--; suspended |= 0x80; } + static void suspend() { suspended++; } + static void resume() { suspended--; suspended |= 0x80; } // Update a single native line on all units static void refresh_line(const uint8_t line); @@ -110,10 +170,10 @@ class Max7219 { #endif // Set a single LED by XY coordinate - static void led_set(const uint8_t x, const uint8_t y, const bool on); - static void led_on(const uint8_t x, const uint8_t y); - static void led_off(const uint8_t x, const uint8_t y); - static void led_toggle(const uint8_t x, const uint8_t y); + static void led_set(const uint8_t x, const uint8_t y, const bool on, uint8_t * const rcm=nullptr); + static void led_on(const uint8_t x, const uint8_t y, uint8_t * const rcm=nullptr); + static void led_off(const uint8_t x, const uint8_t y, uint8_t * const rcm=nullptr); + static void led_toggle(const uint8_t x, const uint8_t y, uint8_t * const rcm=nullptr); // Set all LEDs in a single column static void set_column(const uint8_t col, const uint32_t val); @@ -147,11 +207,12 @@ class Max7219 { static void set(const uint8_t line, const uint8_t bits); static void send_row(const uint8_t row); static void send_column(const uint8_t col); - static void mark16(const uint8_t y, const uint8_t v1, const uint8_t v2); - static void range16(const uint8_t y, const uint8_t ot, const uint8_t nt, const uint8_t oh, const uint8_t nh); - static void quantity16(const uint8_t y, const uint8_t ov, const uint8_t nv); + static void mark16(const uint8_t y, const uint8_t v1, const uint8_t v2, uint8_t * const rcm=nullptr); + static void range16(const uint8_t y, const uint8_t ot, const uint8_t nt, const uint8_t oh, const uint8_t nh, uint8_t * const rcm=nullptr); + static void quantity(const uint8_t y, const uint8_t ov, const uint8_t nv, uint8_t * const rcm=nullptr); + static void quantity16(const uint8_t y, const uint8_t ov, const uint8_t nv, uint8_t * const rcm=nullptr); - #ifdef MAX7219_INIT_TEST + #if MAX7219_INIT_TEST static void test_pattern(); static void run_test_pattern(); static void start_test_pattern(); diff --git a/Marlin/src/feature/meatpack.cpp b/Marlin/src/feature/meatpack.cpp index b2899243..6db25005 100644 --- a/Marlin/src/feature/meatpack.cpp +++ b/Marlin/src/feature/meatpack.cpp @@ -26,7 +26,7 @@ * Algorithm & Implementation: Scott Mudge - mail@scottmudge.com * Date: Dec. 2020 * - * Character Frequencies from ~30 MB of comment-stripped gcode: + * Character Frequencies from ~30 MB of comment-stripped G-code: * '1' -> 4451136 '4' -> 1353273 '\n' -> 1087683 '-' -> 90242 * '0' -> 4253577 '9' -> 1352147 'G' -> 1075806 'Z' -> 34109 * ' ' -> 3053297 '3' -> 1262929 'X' -> 975742 'M' -> 11879 @@ -140,7 +140,7 @@ void MeatPack::handle_output_char(const uint8_t c) { #if ENABLED(MP_DEBUG) if (chars_decoded < 1024) { ++chars_decoded; - DEBUG_ECHOLNPGM("RB: ", AS_CHAR(c)); + DEBUG_ECHOLNPGM("RB: ", C(c)); } #endif } diff --git a/Marlin/src/feature/meatpack.h b/Marlin/src/feature/meatpack.h index a56e65b6..0de1f792 100644 --- a/Marlin/src/feature/meatpack.h +++ b/Marlin/src/feature/meatpack.h @@ -20,7 +20,7 @@ * */ -/* +/** * MeatPack G-code Compression * * Algorithm & Implementation: Scott Mudge - mail@scottmudge.com @@ -29,7 +29,7 @@ * Specifically optimized for 3D printing G-Code, this is a zero-cost data compression method * which packs ~180-190% more data into the same amount of bytes going to the CNC controller. * As a majority of G-Code can be represented by a restricted alphabet, I performed histogram - * analysis on a wide variety of 3D printing gcode samples, and found ~93% of all gcode could + * analysis on a wide variety of 3D printing G-code samples, and found ~93% of all G-code could * be represented by the same 15-character alphabet. * * This allowed me to design a system of packing 2 8-bit characters into a single byte, assuming @@ -38,7 +38,7 @@ * * Combined with some logic to allow commingling of full-width characters outside of this 15- * character alphabet (at the cost of an extra 8-bits per full-width character), and by stripping - * out unnecessary comments, the end result is gcode which is roughly half the original size. + * out unnecessary comments, the end result is G-code which is roughly half the original size. * * Why did I do this? I noticed micro-stuttering and other data-bottleneck issues while printing * objects with high curvature, especially at high speeds. There is also the issue of the limited @@ -144,7 +144,6 @@ struct MeatpackSerial : public SerialBase > { void flushTX() { CALL_IF_EXISTS(void, &out, flushTX); } SerialFeature features(serial_index_t index) const { return SerialFeature::MeatPack | CALL_IF_EXISTS(SerialFeature, &out, features, index); } - int available(serial_index_t index) { if (charCount) return charCount; // The buffer still has data if (out.available(index) <= 0) return 0; // No data to read diff --git a/Marlin/src/feature/mixing.cpp b/Marlin/src/feature/mixing.cpp index 9ebc9012..1ce48922 100644 --- a/Marlin/src/feature/mixing.cpp +++ b/Marlin/src/feature/mixing.cpp @@ -24,8 +24,6 @@ #if ENABLED(MIXING_EXTRUDER) -//#define MIXER_NORMALIZER_DEBUG - #include "mixing.h" Mixer mixer; @@ -44,7 +42,7 @@ int_fast8_t Mixer::runner = 0; mixer_comp_t Mixer::s_color[MIXING_STEPPERS]; mixer_accu_t Mixer::accu[MIXING_STEPPERS] = { 0 }; -#if EITHER(HAS_DUAL_MIXING, GRADIENT_MIX) +#if ANY(HAS_DUAL_MIXING, GRADIENT_MIX) mixer_perc_t Mixer::mix[MIXING_STEPPERS]; #endif @@ -63,7 +61,7 @@ void Mixer::normalize(const uint8_t tool_index) { #ifdef MIXER_NORMALIZER_DEBUG SERIAL_ECHOPGM("Mixer: Old relation : [ "); MIXER_STEPPER_LOOP(i) { - SERIAL_ECHO_F(collector[i] / csum, 3); + SERIAL_DECIMAL(collector[i] / csum); SERIAL_CHAR(' '); } SERIAL_ECHOLNPGM("]"); @@ -96,13 +94,13 @@ void Mixer::normalize(const uint8_t tool_index) { void Mixer::reset_vtools() { // Virtual Tools 0, 1, 2, 3 = Filament 1, 2, 3, 4, etc. // Every virtual tool gets a pure filament - LOOP_L_N(t, _MIN(MIXING_VIRTUAL_TOOLS, MIXING_STEPPERS)) + for (uint8_t t = 0; t < _MIN(MIXING_VIRTUAL_TOOLS, MIXING_STEPPERS); ++t) MIXER_STEPPER_LOOP(i) color[t][i] = (t == i) ? COLOR_A_MASK : 0; // Remaining virtual tools are 100% filament 1 #if MIXING_VIRTUAL_TOOLS > MIXING_STEPPERS - LOOP_S_L_N(t, MIXING_STEPPERS, MIXING_VIRTUAL_TOOLS) + for (uint8_t t = MIXING_STEPPERS; t < MIXING_VIRTUAL_TOOLS; ++t) MIXER_STEPPER_LOOP(i) color[t][i] = (i == 0) ? COLOR_A_MASK : 0; #endif @@ -140,7 +138,7 @@ void Mixer::init() { color[MIXER_AUTORETRACT_TOOL][i] = COLOR_A_MASK; #endif - #if EITHER(HAS_DUAL_MIXING, GRADIENT_MIX) + #if ANY(HAS_DUAL_MIXING, GRADIENT_MIX) update_mix_from_vtool(); #endif diff --git a/Marlin/src/feature/mixing.h b/Marlin/src/feature/mixing.h index f700c7b6..bc3ca794 100644 --- a/Marlin/src/feature/mixing.h +++ b/Marlin/src/feature/mixing.h @@ -108,7 +108,7 @@ class Mixer { } // Used when dealing with blocks - FORCE_INLINE static void populate_block(mixer_comp_t b_color[MIXING_STEPPERS]) { + FORCE_INLINE static void populate_block(mixer_comp_t (&b_color)[MIXING_STEPPERS]) { #if ENABLED(GRADIENT_MIX) if (gradient.enabled) { MIXER_STEPPER_LOOP(i) b_color[i] = gradient.color[i]; @@ -118,15 +118,15 @@ class Mixer { MIXER_STEPPER_LOOP(i) b_color[i] = color[selected_vtool][i]; } - FORCE_INLINE static void stepper_setup(mixer_comp_t b_color[MIXING_STEPPERS]) { + FORCE_INLINE static void stepper_setup(mixer_comp_t (&b_color)[MIXING_STEPPERS]) { MIXER_STEPPER_LOOP(i) s_color[i] = b_color[i]; } - #if EITHER(HAS_DUAL_MIXING, GRADIENT_MIX) + #if ANY(HAS_DUAL_MIXING, GRADIENT_MIX) static mixer_perc_t mix[MIXING_STEPPERS]; // Scratch array for the Mix in proportion to 100 - static inline void copy_mix_to_color(mixer_comp_t (&tcolor)[MIXING_STEPPERS]) { + static void copy_mix_to_color(mixer_comp_t (&tcolor)[MIXING_STEPPERS]) { // Scale each component to the largest one in terms of COLOR_A_MASK // So the largest component will be COLOR_A_MASK and the other will be in proportion to it const float scale = (COLOR_A_MASK) * RECIPROCAL(_MAX( @@ -145,11 +145,10 @@ class Mixer { #endif } - static inline void update_mix_from_vtool(const uint8_t j=selected_vtool) { + static void update_mix_from_vtool(const uint8_t j=selected_vtool) { float ctot = 0; MIXER_STEPPER_LOOP(i) ctot += color[j][i]; - //MIXER_STEPPER_LOOP(i) mix[i] = 100.0f * color[j][i] / ctot; - MIXER_STEPPER_LOOP(i) mix[i] = mixer_perc_t(100.0f * color[j][i] / ctot); + MIXER_STEPPER_LOOP(i) mix[i] = mixer_perc_t(100.0f * color[j][i] / ctot + 0.5f); #ifdef MIXER_NORMALIZER_DEBUG SERIAL_ECHOPGM("V-tool ", j, " [ "); @@ -165,7 +164,7 @@ class Mixer { #if HAS_DUAL_MIXING // Update the virtual tool from an edited mix - static inline void update_vtool_from_mix() { + static void update_vtool_from_mix() { copy_mix_to_color(color[selected_vtool]); TERN_(GRADIENT_MIX, refresh_gradient()); // MIXER_STEPPER_LOOP(i) collector[i] = mix[i]; @@ -182,7 +181,7 @@ class Mixer { // Update the current mix from the gradient for a given Z static void update_gradient_for_z(const_float_t z); static void update_gradient_for_planner_z(); - static inline void gradient_control(const_float_t z) { + static void gradient_control(const_float_t z) { if (gradient.enabled) { if (z >= gradient.end_z) T(gradient.end_vtool); @@ -191,7 +190,7 @@ class Mixer { } } - static inline void update_mix_from_gradient() { + static void update_mix_from_gradient() { float ctot = 0; MIXER_STEPPER_LOOP(i) ctot += gradient.color[i]; MIXER_STEPPER_LOOP(i) mix[i] = (mixer_perc_t)CEIL(100.0f * gradient.color[i] / ctot); @@ -234,13 +233,7 @@ class Mixer { for (;;) { if (--runner < 0) runner = MIXING_STEPPERS - 1; accu[runner] += s_color[runner]; - if ( - #ifdef MIXER_ACCU_SIGNED - accu[runner] < 0 - #else - accu[runner] & COLOR_A_MASK - #endif - ) { + if (TERN(MIXER_ACCU_SIGNED, accu[runner] < 0, accu[runner] & COLOR_A_MASK)) { accu[runner] &= COLOR_MASK; return runner; } diff --git a/Marlin/src/feature/mmu/mmu2-serial-protocol.md b/Marlin/src/feature/mmu/mmu2-serial-protocol.md index 7ff09017..088d41b4 100644 --- a/Marlin/src/feature/mmu/mmu2-serial-protocol.md +++ b/Marlin/src/feature/mmu/mmu2-serial-protocol.md @@ -28,11 +28,8 @@ Now we are sure MMU is available and ready. If there was a timeout or other comm - *Build number* is an integer value and has to be >=126, or =>132 if 12V mode is enabled - *FINDA status* is 1 if the filament is loaded to the extruder, 0 otherwise - *Build number* is checked against the required value, if it does not match, printer is halted. - - Toolchange ========== @@ -51,10 +48,9 @@ When done, the MMU sends - MMU => 'ok\n' -We don't wait for a response here but immediately continue with the next gcode which should +We don't wait for a response here but immediately continue with the next G-code which should be one or more extruder moves to feed the filament into the hotend. - FINDA status ============ @@ -63,8 +59,6 @@ FINDA status *FINDA status* is 1 if the is filament loaded to the extruder, 0 otherwise. This could be used as filament runout sensor if probed regularly. - - Load filament ============= @@ -74,7 +68,6 @@ MMU will feed filament down to the extruder, when done - MMU => 'ok\n' - Unload filament ============= @@ -84,11 +77,8 @@ MMU will retract current filament from the extruder, when done - MMU => 'ok\n' - - Eject filament ============== - MMU <= 'E*Filament index*\n' - MMU => 'ok\n' - diff --git a/Marlin/src/feature/mmu/mmu2.cpp b/Marlin/src/feature/mmu/mmu2.cpp index 2813337c..35dc850d 100644 --- a/Marlin/src/feature/mmu/mmu2.cpp +++ b/Marlin/src/feature/mmu/mmu2.cpp @@ -24,6 +24,10 @@ #if HAS_PRUSA_MMU2 +/** + * mmu2.cpp - Support for Průša MMU2 and MMU2S + */ + #include "mmu2.h" #include "../../lcd/menu/menu_mmu2.h" @@ -39,7 +43,7 @@ MMU2 mmu2; #include "../../MarlinCore.h" #if ENABLED(HOST_PROMPT_SUPPORT) - #include "../../feature/host_actions.h" + #include "../host_actions.h" #endif #if ENABLED(EXTENSIBLE_UI) @@ -54,7 +58,8 @@ MMU2 mmu2; #define MMU_CMD_TIMEOUT 45000UL // 45s timeout for mmu commands (except P0) #define MMU_P0_TIMEOUT 3000UL // Timeout for P0 command: 3seconds -#define MMU2_COMMAND(S) tx_str(F(S "\n")) +#define MMU2_SEND(S) tx_str(F(S "\n")) +#define MMU2_RECV(S) rx_str(F(S "\n")) #if ENABLED(MMU_EXTRUDER_SENSOR) uint8_t mmu_idl_sens = 0; @@ -131,18 +136,24 @@ void MMU2::reset() { safe_delay(20); WRITE(MMU2_RST_PIN, HIGH); #else - MMU2_COMMAND("X0"); // Send soft reset + MMU2_SEND("X0"); // Send soft reset #endif } -uint8_t MMU2::get_current_tool() { - return extruder == MMU2_NO_TOOL ? -1 : extruder; -} +int8_t MMU2::get_current_tool() { return extruder == MMU2_NO_TOOL ? -1 : extruder; } -#if EITHER(HAS_PRUSA_MMU2S, MMU_EXTRUDER_SENSOR) +#if ANY(HAS_PRUSA_MMU2S, MMU_EXTRUDER_SENSOR) #define FILAMENT_PRESENT() (READ(FIL_RUNOUT1_PIN) != FIL_RUNOUT1_STATE) +#else + #define FILAMENT_PRESENT() true #endif +void mmu2_attn_buzz(const bool two=false) { + BUZZ(200, 404); + if (two) { BUZZ(10, 0); BUZZ(200, 404); } +} + +// Avoiding sscanf significantly reduces build size void MMU2::mmu_loop() { switch (state) { @@ -152,11 +163,9 @@ void MMU2::mmu_loop() { case -1: if (rx_start()) { prev_P0_request = millis(); // Initialize finda sensor timeout - DEBUG_ECHOLNPGM("MMU => 'start'"); DEBUG_ECHOLNPGM("MMU <= 'S1'"); - - MMU2_COMMAND("S1"); // Read Version + MMU2_SEND("S1"); // Read Version state = -2; } else if (millis() > 30000) { // 30sec after reset disable MMU @@ -168,10 +177,8 @@ void MMU2::mmu_loop() { case -2: if (rx_ok()) { sscanf(rx_buffer, "%huok\n", &version); - DEBUG_ECHOLNPGM("MMU => ", version, "\nMMU <= 'S2'"); - - MMU2_COMMAND("S2"); // Read Build Number + MMU2_SEND("S2"); // Read Build Number state = -3; } break; @@ -186,31 +193,26 @@ void MMU2::mmu_loop() { #if ENABLED(MMU2_MODE_12V) DEBUG_ECHOLNPGM("MMU <= 'M1'"); - - MMU2_COMMAND("M1"); // Stealth Mode + MMU2_SEND("M1"); // Stealth Mode state = -5; - #else DEBUG_ECHOLNPGM("MMU <= 'P0'"); - - MMU2_COMMAND("P0"); // Read FINDA + MMU2_SEND("P0"); // Read FINDA state = -4; #endif } break; #if ENABLED(MMU2_MODE_12V) - case -5: - // response to M1 - if (rx_ok()) { - DEBUG_ECHOLNPGM("MMU => ok"); - - DEBUG_ECHOLNPGM("MMU <= 'P0'"); - - MMU2_COMMAND("P0"); // Read FINDA - state = -4; - } - break; + case -5: + // response to M1 + if (rx_ok()) { + DEBUG_ECHOLNPGM("MMU => ok"); + DEBUG_ECHOLNPGM("MMU <= 'P0'"); + MMU2_SEND("P0"); // Read FINDA + state = -4; + } + break; #endif case -4: @@ -245,14 +247,13 @@ void MMU2::mmu_loop() { else if (cmd == MMU_CMD_C0) { // continue loading DEBUG_ECHOLNPGM("MMU <= 'C0'"); - MMU2_COMMAND("C0"); + MMU2_SEND("C0"); state = 3; // wait for response } else if (cmd == MMU_CMD_U0) { // unload current DEBUG_ECHOLNPGM("MMU <= 'U0'"); - - MMU2_COMMAND("U0"); + MMU2_SEND("U0"); state = 3; // wait for response } else if (WITHIN(cmd, MMU_CMD_E0, MMU_CMD_E0 + EXTRUDERS - 1)) { @@ -265,7 +266,7 @@ void MMU2::mmu_loop() { else if (cmd == MMU_CMD_R0) { // recover after eject DEBUG_ECHOLNPGM("MMU <= 'R0'"); - MMU2_COMMAND("R0"); + MMU2_SEND("R0"); state = 3; // wait for response } else if (WITHIN(cmd, MMU_CMD_F0, MMU_CMD_F0 + EXTRUDERS - 1)) { @@ -280,7 +281,7 @@ void MMU2::mmu_loop() { cmd = MMU_CMD_NONE; } else if (ELAPSED(millis(), prev_P0_request + 300)) { - MMU2_COMMAND("P0"); // Read FINDA + MMU2_SEND("P0"); // Read FINDA state = 2; // wait for response } @@ -309,7 +310,7 @@ void MMU2::mmu_loop() { if (mmu_idl_sens) { if (FILAMENT_PRESENT() && mmu_loading_flag) { DEBUG_ECHOLNPGM("MMU <= 'A'"); - MMU2_COMMAND("A"); // send 'abort' request + MMU2_SEND("A"); // send 'abort' request mmu_idl_sens = 0; DEBUG_ECHOLNPGM("MMU IDLER_SENSOR = 0 - ABORT"); } @@ -322,9 +323,9 @@ void MMU2::mmu_loop() { const bool keep_trying = !mmu2s_triggered && last_cmd == MMU_CMD_C0; if (keep_trying) { // MMU ok received but filament sensor not triggered, retrying... - DEBUG_ECHOLNPGM("MMU => 'ok' (filament not present in gears)"); + DEBUG_ECHOLNPGM("MMU => 'ok' (no filament in gears)"); DEBUG_ECHOLNPGM("MMU <= 'C0' (keep trying)"); - MMU2_COMMAND("C0"); + MMU2_SEND("C0"); } #else constexpr bool keep_trying = false; @@ -356,7 +357,7 @@ void MMU2::mmu_loop() { */ bool MMU2::rx_start() { // check for start message - return rx_str(F("start\n")); + return MMU2_RECV("start"); } /** @@ -409,7 +410,7 @@ void MMU2::tx_str(FSTR_P fstr) { void MMU2::tx_printf(FSTR_P format, int argument = -1) { clear_rx_buffer(); const uint8_t len = sprintf_P(tx_buffer, FTOP(format), argument); - LOOP_L_N(i, len) MMU2_SERIAL.write(tx_buffer[i]); + for (uint8_t i = 0; i < len; ++i) MMU2_SERIAL.write(tx_buffer[i]); prev_request = millis(); } @@ -419,7 +420,7 @@ void MMU2::tx_printf(FSTR_P format, int argument = -1) { void MMU2::tx_printf(FSTR_P format, int argument1, int argument2) { clear_rx_buffer(); const uint8_t len = sprintf_P(tx_buffer, FTOP(format), argument1, argument2); - LOOP_L_N(i, len) MMU2_SERIAL.write(tx_buffer[i]); + for (uint8_t i = 0; i < len; ++i) MMU2_SERIAL.write(tx_buffer[i]); prev_request = millis(); } @@ -435,7 +436,7 @@ void MMU2::clear_rx_buffer() { * Check if we received 'ok' from MMU */ bool MMU2::rx_ok() { - if (rx_str(F("ok\n"))) { + if (MMU2_RECV("ok")) { prev_P0_request = millis(); return true; } @@ -463,10 +464,15 @@ static void mmu2_not_responding() { #if HAS_PRUSA_MMU2S + /** + * Load filament until the sensor at the gears is triggered + * and give up after a number of attempts set with MMU2_C0_RETRY. + * Each try has a timeout before returning a fail state. + */ bool MMU2::load_to_gears() { command(MMU_CMD_C0); manage_response(true, true); - LOOP_L_N(i, MMU2_C0_RETRY) { // Keep loading until filament reaches gears + for (uint8_t i = 0; i < MMU2_C0_RETRY; ++i) { // Keep loading until filament reaches gears if (mmu2s_triggered) break; command(MMU_CMD_C0); manage_response(true, true); @@ -525,7 +531,7 @@ static void mmu2_not_responding() { while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100); load_filament_to_nozzle(index); #else - BUZZ(400, 40); + ERR_BUZZ(); #endif } break; @@ -544,7 +550,7 @@ static void mmu2_not_responding() { active_extruder = 0; } #else - BUZZ(400, 40); + ERR_BUZZ(); #endif } break; @@ -580,7 +586,7 @@ static void mmu2_not_responding() { command(MMU_CMD_T0 + index); manage_response(true, true); mmu_continue_loading(); - command(MMU_CMD_C0); + //command(MMU_CMD_C0); extruder = index; active_extruder = 0; @@ -613,7 +619,7 @@ static void mmu2_not_responding() { while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100); load_filament_to_nozzle(index); #else - BUZZ(400, 40); + ERR_BUZZ(); #endif } break; @@ -633,7 +639,7 @@ static void mmu2_not_responding() { extruder = index; active_extruder = 0; #else - BUZZ(400, 40); + ERR_BUZZ(); #endif } break; @@ -648,13 +654,34 @@ static void mmu2_not_responding() { } void MMU2::mmu_continue_loading() { + // Try to load the filament a limited number of times + bool fil_present = 0; for (uint8_t i = 0; i < MMU_LOADING_ATTEMPTS_NR; i++) { - DEBUG_ECHOLNPGM("Additional load attempt #", i); - if (FILAMENT_PRESENT()) break; + DEBUG_ECHOLNPGM("Load attempt #", i + 1); + + // Done as soon as filament is present + fil_present = FILAMENT_PRESENT(); + if (fil_present) break; + + // Attempt to load the filament, 1mm at a time, for 3s command(MMU_CMD_C0); + stepper.enable_extruder(); + const millis_t expire_ms = millis() + 3000; + do { + current_position.e += 1; + line_to_current_position(MMU_LOAD_FEEDRATE); + planner.synchronize(); + // When (T0 rx->ok) load is ready, but in fact it did not load + // successfully or an overload created pressure in the extruder. + // Send (C0) to load more and move E_AXIS a little to release pressure. + if ((fil_present = FILAMENT_PRESENT())) MMU2_SEND("A"); + } while (!fil_present && PENDING(millis(), expire_ms)); + stepper.disable_extruder(); manage_response(true, true); } - if (!FILAMENT_PRESENT()) { + + // Was the filament still missing in the last check? + if (!fil_present) { DEBUG_ECHOLNPGM("Filament never reached sensor, runout"); filament_runout(); } @@ -677,7 +704,7 @@ static void mmu2_not_responding() { command(MMU_CMD_T0 + index); manage_response(true, true); command(MMU_CMD_C0); - extruder = index; //filament change is finished + extruder = index; // Filament change is finished active_extruder = 0; stepper.enable_extruder(); SERIAL_ECHO_MSG(STR_ACTIVE_EXTRUDER, extruder); @@ -707,7 +734,7 @@ static void mmu2_not_responding() { while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100); load_filament_to_nozzle(index); #else - BUZZ(400, 40); + ERR_BUZZ(); #endif } break; @@ -726,7 +753,7 @@ static void mmu2_not_responding() { extruder = index; active_extruder = 0; #else - BUZZ(400, 40); + ERR_BUZZ(); #endif } break; @@ -806,30 +833,29 @@ void MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) { } } else if (mmu_print_saved) { - SERIAL_ECHOLNPGM("MMU starts responding\n"); + SERIAL_ECHOLNPGM("\nMMU starts responding"); if (turn_off_nozzle && resume_hotend_temp) { thermalManager.setTargetHotend(resume_hotend_temp, active_extruder); LCD_MESSAGE(MSG_HEATING); - BUZZ(200, 40); - + ERR_BUZZ(); while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(1000); } - if (move_axes && all_axes_homed()) { - LCD_MESSAGE(MSG_MMU2_RESUMING); - BUZZ(198, 404); BUZZ(4, 0); BUZZ(198, 404); + LCD_MESSAGE(MSG_MMU2_RESUMING); + mmu2_attn_buzz(true); + + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" + if (move_axes && all_axes_homed()) { // Move XY to starting position, then Z do_blocking_move_to_xy(resume_position, feedRate_t(NOZZLE_PARK_XY_FEEDRATE)); - // Move Z_AXIS to saved position do_blocking_move_to_z(resume_position.z, feedRate_t(NOZZLE_PARK_Z_FEEDRATE)); } - else { - BUZZ(198, 404); BUZZ(4, 0); BUZZ(198, 404); - LCD_MESSAGE(MSG_MMU2_RESUMING); - } + + #pragma GCC diagnostic pop } } } @@ -855,7 +881,7 @@ void MMU2::filament_runout() { if (cmd == MMU_CMD_NONE && last_cmd == MMU_CMD_C0) { if (present && !mmu2s_triggered) { DEBUG_ECHOLNPGM("MMU <= 'A'"); - tx_str(F("A\n")); + MMU2_SEND("A"); } // Slowly spin the extruder during C0 else { @@ -874,7 +900,7 @@ void MMU2::filament_runout() { int filament_detected_count = 0; const int steps = (MMU2_CAN_LOAD_RETRACT) / (MMU2_CAN_LOAD_INCREMENT); DEBUG_ECHOLNPGM("MMU can_load:"); - LOOP_L_N(i, steps) { + for (uint8_t i = 0; i < steps; ++i) { execute_extruder_sequence((const E_Step *)can_load_increment_sequence, COUNT(can_load_increment_sequence)); check_filament(); // Don't trust the idle function DEBUG_CHAR(mmu2s_triggered ? 'O' : 'o'); @@ -898,7 +924,7 @@ void MMU2::load_filament(const uint8_t index) { command(MMU_CMD_L0 + index); manage_response(false, false); - BUZZ(200, 404); + mmu2_attn_buzz(); } /** @@ -909,7 +935,7 @@ bool MMU2::load_filament_to_nozzle(const uint8_t index) { if (!_enabled) return false; if (thermalManager.tooColdToExtrude(active_extruder)) { - BUZZ(200, 404); + mmu2_attn_buzz(); LCD_ALERTMESSAGE(MSG_HOTEND_TOO_COLD); return false; } @@ -924,7 +950,7 @@ bool MMU2::load_filament_to_nozzle(const uint8_t index) { extruder = index; active_extruder = 0; load_to_nozzle(); - BUZZ(200, 404); + mmu2_attn_buzz(); } return success; } @@ -933,7 +959,7 @@ bool MMU2::load_filament_to_nozzle(const uint8_t index) { * Load filament to nozzle of multimaterial printer * * This function is used only after T? (user select filament) and M600 (change filament). - * It is not used after T0 .. T4 command (select filament), in such case, gcode is responsible for loading + * It is not used after T0 .. T4 command (select filament), in such case, G-code is responsible for loading * filament to nozzle. */ void MMU2::load_to_nozzle() { @@ -945,7 +971,7 @@ bool MMU2::eject_filament(const uint8_t index, const bool recover) { if (!_enabled) return false; if (thermalManager.tooColdToExtrude(active_extruder)) { - BUZZ(200, 404); + mmu2_attn_buzz(); LCD_ALERTMESSAGE(MSG_HOTEND_TOO_COLD); return false; } @@ -960,13 +986,12 @@ bool MMU2::eject_filament(const uint8_t index, const bool recover) { manage_response(false, false); if (recover) { - LCD_MESSAGE(MSG_MMU2_EJECT_RECOVER); - BUZZ(200, 404); - TERN_(HOST_PROMPT_SUPPORT, hostui.prompt_do(PROMPT_USER_CONTINUE, F("MMU2 Eject Recover"), FPSTR(CONTINUE_STR))); - TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(F("MMU2 Eject Recover"))); + LCD_MESSAGE(MSG_MMU2_REMOVE_AND_CLICK); + mmu2_attn_buzz(); + TERN_(HOST_PROMPT_SUPPORT, hostui.continue_prompt(GET_TEXT_F(MSG_MMU2_EJECT_RECOVER))); + TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(GET_TEXT_F(MSG_MMU2_EJECT_RECOVER))); TERN_(HAS_RESUME_CONTINUE, wait_for_user_response()); - BUZZ(200, 404); - BUZZ(200, 404); + mmu2_attn_buzz(true); command(MMU_CMD_R0); manage_response(false, false); @@ -979,7 +1004,7 @@ bool MMU2::eject_filament(const uint8_t index, const bool recover) { set_runout_valid(false); - BUZZ(200, 404); + mmu2_attn_buzz(); stepper.disable_extruder(); @@ -994,7 +1019,7 @@ bool MMU2::unload() { if (!_enabled) return false; if (thermalManager.tooColdToExtrude(active_extruder)) { - BUZZ(200, 404); + mmu2_attn_buzz(); LCD_ALERTMESSAGE(MSG_HOTEND_TOO_COLD); return false; } @@ -1005,7 +1030,7 @@ bool MMU2::unload() { command(MMU_CMD_U0); manage_response(false, true); - BUZZ(200, 404); + mmu2_attn_buzz(); // no active tool extruder = MMU2_NO_TOOL; @@ -1020,14 +1045,13 @@ void MMU2::execute_extruder_sequence(const E_Step * sequence, int steps) { planner.synchronize(); stepper.enable_extruder(); - const E_Step* step = sequence; + const E_Step *step = sequence; - LOOP_L_N(i, steps) { + for (uint8_t i = 0; i < steps; ++i) { const float es = pgm_read_float(&(step->extrude)); const feedRate_t fr_mm_m = pgm_read_float(&(step->feedRate)); - DEBUG_ECHO_START(); - DEBUG_ECHOLNPGM("E step ", es, "/", fr_mm_m); + DEBUG_ECHO_MSG("E step ", es, "/", fr_mm_m); current_position.e += es; line_to_current_position(MMM_TO_MMS(fr_mm_m)); diff --git a/Marlin/src/feature/mmu/mmu2.h b/Marlin/src/feature/mmu/mmu2.h index 9574e221..fff7a8f8 100644 --- a/Marlin/src/feature/mmu/mmu2.h +++ b/Marlin/src/feature/mmu/mmu2.h @@ -21,6 +21,10 @@ */ #pragma once +/** + * mmu2.h - Support for Průša MMU2 and MMU2S + */ + #include "../../inc/MarlinConfig.h" #if HAS_FILAMENT_SENSOR @@ -43,11 +47,11 @@ class MMU2 { static void init(); static void reset(); - static inline bool enabled() { return _enabled; } + static bool enabled() { return _enabled; } static void mmu_loop(); static void tool_change(const uint8_t index); static void tool_change(const char *special); - static uint8_t get_current_tool(); + static int8_t get_current_tool(); static void set_filament_type(const uint8_t index, const uint8_t type); static bool unload(); @@ -57,10 +61,10 @@ class MMU2 { static bool eject_filament(const uint8_t index, const bool recover); private: - static inline bool rx_str(FSTR_P fstr); - static inline void tx_str(FSTR_P fstr); - static inline void tx_printf(FSTR_P ffmt, const int argument); - static inline void tx_printf(FSTR_P ffmt, const int argument1, const int argument2); + static bool rx_str(FSTR_P fstr); + static void tx_str(FSTR_P fstr); + static void tx_printf(FSTR_P ffmt, const int argument); + static void tx_printf(FSTR_P ffmt, const int argument1, const int argument2); static void clear_rx_buffer(); static bool rx_ok(); @@ -86,6 +90,7 @@ class MMU2 { #endif #if ENABLED(MMU_EXTRUDER_SENSOR) + #define MMU_LOAD_FEEDRATE 19.02f // (mm/s) static void mmu_continue_loading(); #endif @@ -99,7 +104,7 @@ class MMU2 { static millis_t prev_request, prev_P0_request; static char rx_buffer[MMU_RX_SIZE], tx_buffer[MMU_TX_SIZE]; - static inline void set_runout_valid(const bool valid) { + static void set_runout_valid(const bool valid) { finda_runout_valid = valid; #if HAS_FILAMENT_SENSOR if (valid) runout.reset(); diff --git a/Marlin/src/feature/password/password.cpp b/Marlin/src/feature/password/password.cpp index 4e841c24..1d376cc5 100644 --- a/Marlin/src/feature/password/password.cpp +++ b/Marlin/src/feature/password/password.cpp @@ -40,7 +40,7 @@ uint32_t Password::value, Password::value_entry; // void Password::lock_machine() { is_locked = true; - TERN_(HAS_LCD_MENU, authenticate_user(ui.status_screen, screen_password_entry)); + TERN_(HAS_MARLINUI_MENU, authenticate_user(ui.status_screen, screen_password_entry)); } // @@ -55,7 +55,7 @@ void Password::authentication_check() { is_locked = true; SERIAL_ECHOLNPGM(STR_WRONG_PASSWORD); } - TERN_(HAS_LCD_MENU, authentication_done()); + TERN_(HAS_MARLINUI_MENU, authentication_done()); } #endif // PASSWORD_FEATURE diff --git a/Marlin/src/feature/password/password.h b/Marlin/src/feature/password/password.h index 829d222e..208765b2 100644 --- a/Marlin/src/feature/password/password.h +++ b/Marlin/src/feature/password/password.h @@ -33,7 +33,7 @@ class Password { static void lock_machine(); static void authentication_check(); - #if HAS_LCD_MENU + #if HAS_MARLINUI_MENU static void access_menu_password(); static void authentication_done(); static void media_gatekeeper(); diff --git a/Marlin/src/feature/pause.cpp b/Marlin/src/feature/pause.cpp index 191c0e4b..36088e4e 100644 --- a/Marlin/src/feature/pause.cpp +++ b/Marlin/src/feature/pause.cpp @@ -35,10 +35,17 @@ #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 + #if ENABLED(FWRETRACT) #include "fwretract.h" #endif @@ -53,13 +60,13 @@ #if ENABLED(EXTENSIBLE_UI) #include "../lcd/extui/ui_api.h" -#elif ENABLED(DWIN_CREALITY_LCD_ENHANCED) - #include "../lcd/e3v2/enhanced/dwin.h" +#elif ENABLED(DWIN_LCD_PROUI) + #include "../lcd/e3v2/proui/dwin.h" #endif #include "../lcd/marlinui.h" -#if HAS_BUZZER +#if HAS_SOUND #include "../libs/buzzer.h" #endif @@ -84,7 +91,7 @@ static xyze_pos_t resume_position; fil_change_settings_t fc_settings[EXTRUDERS]; -#if ENABLED(SDSUPPORT) +#if HAS_MEDIA #include "../sd/cardreader.h" #endif @@ -94,10 +101,10 @@ fil_change_settings_t fc_settings[EXTRUDERS]; #define _PMSG(L) L##_LCD #endif -#if HAS_BUZZER +#if HAS_SOUND static void impatient_beep(const int8_t max_beep_count, const bool restart=false) { - if (TERN0(HAS_LCD_MENU, pause_mode == PAUSE_MODE_PAUSE_PRINT)) return; + if (TERN0(HAS_MARLINUI_MENU, pause_mode == PAUSE_MODE_PAUSE_PRINT)) return; static millis_t next_buzz = 0; static int8_t runout_beep = 0; @@ -194,7 +201,7 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load KEEPALIVE_STATE(PAUSED_FOR_USER); wait_for_user = true; // LCD click or M108 will clear this - TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(F("Load Filament"))); + TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(GET_TEXT_F(MSG_FILAMENTLOAD))); #if ENABLED(HOST_PROMPT_SUPPORT) const char tool = '0' + TERN0(MULTI_FILAMENT_SENSOR, active_extruder); @@ -203,8 +210,8 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load while (wait_for_user) { impatient_beep(max_beep_count); - #if BOTH(FILAMENT_CHANGE_RESUME_ON_INSERT, FILAMENT_RUNOUT_SENSOR) - #if ENABLED(MULTI_FILAMENT_SENSOR) + #if ALL(FILAMENT_CHANGE_RESUME_ON_INSERT, FILAMENT_RUNOUT_SENSOR) + #if MULTI_FILAMENT_SENSOR #define _CASE_INSERTED(N) case N-1: if (READ(FIL_RUNOUT##N##_PIN) != FIL_RUNOUT##N##_STATE) wait_for_user = false; break; switch (active_extruder) { REPEAT_1(NUM_RUNOUT_SENSORS, _CASE_INSERTED) @@ -253,7 +260,7 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_PURGE); TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(GET_TEXT_F(MSG_FILAMENT_CHANGE_PURGE))); - TERN_(HOST_PROMPT_SUPPORT, hostui.prompt_do(PROMPT_USER_CONTINUE, GET_TEXT_F(MSG_FILAMENT_CHANGE_PURGE), FPSTR(CONTINUE_STR))); + TERN_(HOST_PROMPT_SUPPORT, hostui.continue_prompt(GET_TEXT_F(MSG_FILAMENT_CHANGE_PURGE))); wait_for_user = true; // A click or M108 breaks the purge_length loop for (float purge_count = purge_length; purge_count > 0 && wait_for_user; --purge_count) unscaled_e_move(1, ADVANCED_PAUSE_PURGE_FEEDRATE); @@ -277,7 +284,7 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load // Show "Purge More" / "Resume" menu and wait for reply KEEPALIVE_STATE(PAUSED_FOR_USER); wait_for_user = false; - #if EITHER(HAS_LCD_MENU, DWIN_CREALITY_LCD_ENHANCED) + #if ANY(HAS_MARLINUI_MENU, DWIN_LCD_PROUI) ui.pause_show_message(PAUSE_MESSAGE_OPTION); // Also sets PAUSE_RESPONSE_WAIT_FOR #else pause_menu_response = PAUSE_RESPONSE_WAIT_FOR; @@ -319,18 +326,18 @@ inline void disable_active_extruder() { */ bool unload_filament(const_float_t unload_length, const bool show_lcd/*=false*/, const PauseMode mode/*=PAUSE_MODE_PAUSE_PRINT*/ - #if BOTH(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) + #if ALL(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) , const_float_t mix_multiplier/*=1.0*/ #endif ) { DEBUG_SECTION(uf, "unload_filament", true); DEBUG_ECHOLNPGM("... unloadlen:", unload_length, " showlcd:", show_lcd, " mode:", mode - #if BOTH(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) + #if ALL(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) , " mixmult:", mix_multiplier #endif ); - #if !BOTH(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) + #if !ALL(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) constexpr float mix_multiplier = 1.0f; #endif @@ -408,7 +415,7 @@ bool pause_print(const_float_t retract, const xyz_pos_t &park_point, const bool ++did_pause_print; // Pause the print job and timer - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA const bool was_sd_printing = IS_SD_PRINTING(); if (was_sd_printing) { card.pauseSDPrint(); @@ -433,18 +440,27 @@ bool pause_print(const_float_t retract, const xyz_pos_t &park_point, const bool // Wait for buffered blocks to complete planner.synchronize(); - #if ENABLED(ADVANCED_PAUSE_FANS_PAUSE) && HAS_FAN + #if ALL(ADVANCED_PAUSE_FANS_PAUSE, HAS_FAN) thermalManager.set_fans_paused(true); #endif // Initial retract before move to filament change position if (retract && thermalManager.hotEnoughToExtrude(active_extruder)) { DEBUG_ECHOLNPGM("... retract:", retract); + + #if ENABLED(AUTO_BED_LEVELING_UBL) + const bool leveling_was_enabled = planner.leveling_active; // save leveling state + set_bed_leveling_enabled(false); // turn off leveling + #endif + unscaled_e_move(retract, PAUSE_PARK_RETRACT_FEEDRATE); + + TERN_(AUTO_BED_LEVELING_UBL, set_bed_leveling_enabled(leveling_was_enabled)); // restore leveling } // If axes don't need to home then the nozzle can park if (do_park) nozzle.park(0, park_point); // Park the nozzle by doing a Minimum Z Raise followed by an XY Move + if (!do_park) LCD_MESSAGE(MSG_PARK_FAILED); #if ENABLED(DUAL_X_CARRIAGE) const int8_t saved_ext = active_extruder; @@ -456,9 +472,7 @@ bool pause_print(const_float_t retract, const xyz_pos_t &park_point, const bool if (unload_length) unload_filament(unload_length, show_lcd, PAUSE_MODE_CHANGE_FILAMENT); - #if ENABLED(DUAL_X_CARRIAGE) - set_duplication_enabled(saved_ext_dup_mode, saved_ext); - #endif + TERN_(DUAL_X_CARRIAGE, set_duplication_enabled(saved_ext_dup_mode, saved_ext)); // Disable the Extruder for manual change disable_active_extruder(); @@ -511,7 +525,7 @@ void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep // Wait for filament insert by user and press button KEEPALIVE_STATE(PAUSED_FOR_USER); - TERN_(HOST_PROMPT_SUPPORT, hostui.prompt_do(PROMPT_USER_CONTINUE, GET_TEXT_F(MSG_NOZZLE_PARKED), FPSTR(CONTINUE_STR))); + TERN_(HOST_PROMPT_SUPPORT, hostui.continue_prompt(GET_TEXT_F(MSG_NOZZLE_PARKED))); TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(GET_TEXT_F(MSG_NOZZLE_PARKED))); wait_for_user = true; // LCD click or M108 will clear this while (wait_for_user) { @@ -535,9 +549,7 @@ void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep TERN_(HOST_PROMPT_SUPPORT, hostui.prompt_do(PROMPT_INFO, GET_TEXT_F(MSG_REHEATING))); - TERN_(EXTENSIBLE_UI, ExtUI::onStatusChanged(GET_TEXT_F(MSG_REHEATING))); - - TERN_(DWIN_CREALITY_LCD_ENHANCED, LCD_MESSAGE(MSG_REHEATING)); + LCD_MESSAGE(MSG_REHEATING); // Re-enable the heaters if they timed out HOTEND_LOOP() thermalManager.reset_hotend_idle_timer(e); @@ -553,9 +565,12 @@ void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep HOTEND_LOOP() thermalManager.heater_idle[e].start(nozzle_timeout); - TERN_(HOST_PROMPT_SUPPORT, hostui.prompt_do(PROMPT_USER_CONTINUE, GET_TEXT_F(MSG_REHEATDONE), FPSTR(CONTINUE_STR))); - TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(GET_TEXT_F(MSG_REHEATDONE))); - TERN_(DWIN_CREALITY_LCD_ENHANCED, LCD_MESSAGE(MSG_REHEATDONE)); + TERN_(HOST_PROMPT_SUPPORT, hostui.continue_prompt(GET_TEXT_F(MSG_REHEATDONE))); + #if ENABLED(EXTENSIBLE_UI) + ExtUI::onUserConfirmRequired(GET_TEXT_F(MSG_REHEATDONE)); + #else + LCD_MESSAGE(MSG_REHEATDONE); + #endif IF_DISABLED(PAUSE_REHEAT_FAST_RESUME, wait_for_user = true); @@ -564,9 +579,7 @@ void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep } idle_no_sleep(); } - #if ENABLED(DUAL_X_CARRIAGE) - set_duplication_enabled(saved_ext_dup_mode, saved_ext); - #endif + TERN_(DUAL_X_CARRIAGE, set_duplication_enabled(saved_ext_dup_mode, saved_ext)); } /** @@ -640,9 +653,16 @@ void resume_print(const_float_t slow_load_length/*=0*/, const_float_t fast_load_ prepare_internal_move_to_destination(NOZZLE_PARK_Z_FEEDRATE); } + #if ENABLED(AUTO_BED_LEVELING_UBL) + const bool leveling_was_enabled = planner.leveling_active; // save leveling state + set_bed_leveling_enabled(false); // turn off leveling + #endif + // Unretract unscaled_e_move(PAUSE_PARK_RETRACT_LENGTH, feedRate_t(PAUSE_PARK_RETRACT_FEEDRATE)); + TERN_(AUTO_BED_LEVELING_UBL, set_bed_leveling_enabled(leveling_was_enabled)); // restore leveling + // Intelligent resuming #if ENABLED(FWRETRACT) // If retracted before goto pause @@ -652,8 +672,9 @@ void resume_print(const_float_t slow_load_length/*=0*/, const_float_t fast_load_ // If resume_position is negative if (resume_position.e < 0) unscaled_e_move(resume_position.e, feedRate_t(PAUSE_PARK_RETRACT_FEEDRATE)); - #if ADVANCED_PAUSE_RESUME_PRIME != 0 - unscaled_e_move(ADVANCED_PAUSE_RESUME_PRIME, feedRate_t(ADVANCED_PAUSE_PURGE_FEEDRATE)); + #ifdef ADVANCED_PAUSE_RESUME_PRIME + if (ADVANCED_PAUSE_RESUME_PRIME != 0) + unscaled_e_move(ADVANCED_PAUSE_RESUME_PRIME, feedRate_t(ADVANCED_PAUSE_PURGE_FEEDRATE)); #endif // Now all extrusion positions are resumed and ready to be confirmed @@ -675,7 +696,7 @@ void resume_print(const_float_t slow_load_length/*=0*/, const_float_t fast_load_ // Resume the print job timer if it was running if (print_job_timer.isPaused()) print_job_timer.start(); - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA if (did_pause_print) { --did_pause_print; card.startOrResumeFilePrinting(); @@ -690,9 +711,8 @@ void resume_print(const_float_t slow_load_length/*=0*/, const_float_t fast_load_ TERN_(HAS_FILAMENT_SENSOR, runout.reset()); - TERN_(HAS_STATUS_MESSAGE, ui.reset_status()); - TERN_(HAS_LCD_MENU, ui.return_to_status()); - TERN_(DWIN_CREALITY_LCD_ENHANCED, HMI_ReturnScreen()); + ui.reset_status(); + ui.return_to_status(); } #endif // ADVANCED_PAUSE_FEATURE diff --git a/Marlin/src/feature/pause.h b/Marlin/src/feature/pause.h index 134b1d1b..45f62dc3 100644 --- a/Marlin/src/feature/pause.h +++ b/Marlin/src/feature/pause.h @@ -48,15 +48,15 @@ enum PauseMessage : char { PAUSE_MESSAGE_PARKING, PAUSE_MESSAGE_CHANGING, PAUSE_MESSAGE_WAITING, - PAUSE_MESSAGE_UNLOAD, PAUSE_MESSAGE_INSERT, PAUSE_MESSAGE_LOAD, + PAUSE_MESSAGE_UNLOAD, PAUSE_MESSAGE_PURGE, PAUSE_MESSAGE_OPTION, PAUSE_MESSAGE_RESUME, - PAUSE_MESSAGE_STATUS, PAUSE_MESSAGE_HEAT, - PAUSE_MESSAGE_HEATING + PAUSE_MESSAGE_HEATING, + PAUSE_MESSAGE_STATUS }; #if M600_PURGE_MORE_RESUMABLE @@ -117,7 +117,7 @@ bool unload_filament( const_float_t unload_length, // (mm) Filament Unload Length - 0 to skip const bool show_lcd=false, // Set LCD status messages? const PauseMode mode=PAUSE_MODE_PAUSE_PRINT // Pause Mode to apply - #if BOTH(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) + #if ALL(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) , const_float_t mix_multiplier=1.0f // Extrusion multiplier (for a Mixing Extruder) #endif ); diff --git a/Marlin/src/feature/power.cpp b/Marlin/src/feature/power.cpp index fabe35b9..1855b165 100644 --- a/Marlin/src/feature/power.cpp +++ b/Marlin/src/feature/power.cpp @@ -24,10 +24,14 @@ * power.cpp - power control */ -#include "../inc/MarlinConfig.h" +#include "../inc/MarlinConfigPre.h" + +#if ANY(PSU_CONTROL, AUTO_POWER_CONTROL) #include "power.h" -#include "../module/stepper.h" +#include "../module/planner.h" +#include "../module/stepper/indirection.h" // for restore_stepper_drivers +#include "../module/temperature.h" #include "../MarlinCore.h" #if ENABLED(PS_OFF_SOUND) @@ -38,15 +42,14 @@ #include "../gcode/gcode.h" #endif -#if EITHER(PSU_CONTROL, AUTO_POWER_CONTROL) - 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) + #if ALL(USE_CONTROLLER_FAN, AUTO_POWER_CONTROLLERFAN) #include "controllerfan.h" #endif @@ -75,6 +78,10 @@ void Power::power_on() { if (psu_on) return; + #if ANY(POWER_OFF_TIMER, POWER_OFF_WAIT_FOR_COOLDOWN) + cancelAutoPowerOff(); + #endif + OUT_WRITE(PS_ON_PIN, PSU_ACTIVE_STATE); psu_on = true; safe_delay(PSU_POWERUP_DELAY); @@ -89,11 +96,14 @@ void Power::power_on() { /** * Power off if the power is currently on. * Processes any PSU_POWEROFF_GCODE and makes a PS_OFF_SOUND if enabled. - * */ void Power::power_off() { + TERN_(HAS_SUICIDE, suicide()); + if (!psu_on) return; + SERIAL_ECHOLNPGM(STR_POWEROFF); + #ifdef PSU_POWEROFF_GCODE gcode.process_subcommands_now(F(PSU_POWEROFF_GCODE)); #endif @@ -104,8 +114,57 @@ void Power::power_off() { OUT_WRITE(PS_ON_PIN, !PSU_ACTIVE_STATE); psu_on = false; + + #if ANY(POWER_OFF_TIMER, POWER_OFF_WAIT_FOR_COOLDOWN) + cancelAutoPowerOff(); + #endif } +#if ANY(AUTO_POWER_CONTROL, POWER_OFF_WAIT_FOR_COOLDOWN) + + bool Power::is_cooling_needed() { + #if HAS_HOTEND && AUTO_POWER_E_TEMP + HOTEND_LOOP() if (thermalManager.degHotend(e) >= (AUTO_POWER_E_TEMP)) return true; + #endif + + #if HAS_HEATED_CHAMBER && AUTO_POWER_CHAMBER_TEMP + if (thermalManager.degChamber() >= (AUTO_POWER_CHAMBER_TEMP)) return true; + #endif + + #if HAS_COOLER && AUTO_POWER_COOLER_TEMP + if (thermalManager.degCooler() >= (AUTO_POWER_COOLER_TEMP)) return true; + #endif + + return false; + } + +#endif + +#if ANY(POWER_OFF_TIMER, POWER_OFF_WAIT_FOR_COOLDOWN) + + #if ENABLED(POWER_OFF_TIMER) + millis_t Power::power_off_time = 0; + void Power::setPowerOffTimer(const millis_t delay_ms) { power_off_time = millis() + delay_ms; } + #endif + + #if ENABLED(POWER_OFF_WAIT_FOR_COOLDOWN) + bool Power::power_off_on_cooldown = false; + void Power::setPowerOffOnCooldown(const bool ena) { power_off_on_cooldown = ena; } + #endif + + void Power::cancelAutoPowerOff() { + TERN_(POWER_OFF_TIMER, power_off_time = 0); + TERN_(POWER_OFF_WAIT_FOR_COOLDOWN, power_off_on_cooldown = false); + } + + void Power::checkAutoPowerOff() { + if (TERN1(POWER_OFF_TIMER, !power_off_time) && TERN1(POWER_OFF_WAIT_FOR_COOLDOWN, !power_off_on_cooldown)) return; + if (TERN0(POWER_OFF_WAIT_FOR_COOLDOWN, power_off_on_cooldown && is_cooling_needed())) return; + if (TERN0(POWER_OFF_TIMER, power_off_time && PENDING(millis(), power_off_time))) return; + power_off(); + } + +#endif // POWER_OFF_TIMER || POWER_OFF_WAIT_FOR_COOLDOWN #if ENABLED(AUTO_POWER_CONTROL) @@ -116,7 +175,7 @@ void Power::power_off() { /** * Check all conditions that would signal power needing to be on. * - * @returns bool if power is needed + * @return bool if power is needed */ bool Power::is_power_needed() { @@ -133,7 +192,7 @@ void Power::power_off() { HOTEND_LOOP() if (thermalManager.autofan_speed[e]) return true; #endif - #if BOTH(USE_CONTROLLER_FAN, AUTO_POWER_CONTROLLERFAN) + #if ALL(USE_CONTROLLER_FAN, AUTO_POWER_CONTROLLERFAN) if (controllerFan.state()) return true; #endif @@ -149,19 +208,7 @@ void Power::power_off() { if (TERN0(HAS_HEATED_BED, thermalManager.degTargetBed() > 0 || thermalManager.temp_bed.soft_pwm_amount > 0)) return true; - #if HAS_HOTEND && AUTO_POWER_E_TEMP - HOTEND_LOOP() if (thermalManager.degHotend(e) >= (AUTO_POWER_E_TEMP)) return true; - #endif - - #if HAS_HEATED_CHAMBER && AUTO_POWER_CHAMBER_TEMP - if (thermalManager.degChamber() >= (AUTO_POWER_CHAMBER_TEMP)) return true; - #endif - - #if HAS_COOLER && AUTO_POWER_COOLER_TEMP - if (thermalManager.degCooler() >= (AUTO_POWER_COOLER_TEMP)) return true; - #endif - - return false; + return is_cooling_needed(); } /** @@ -193,7 +240,6 @@ void Power::power_off() { /** * Power off with a delay. Power off is triggered by check() after the delay. - * */ void Power::power_off_soon() { lastPowerOn = millis() - SEC_TO_MS(POWER_TIMEOUT) + SEC_TO_MS(POWER_OFF_DELAY); diff --git a/Marlin/src/feature/power.h b/Marlin/src/feature/power.h index 7f5a97e6..fdbb7126 100644 --- a/Marlin/src/feature/power.h +++ b/Marlin/src/feature/power.h @@ -25,7 +25,7 @@ * power.h - power control */ -#if ENABLED(AUTO_POWER_CONTROL) +#if ANY(AUTO_POWER_CONTROL, POWER_OFF_TIMER) #include "../core/millis_t.h" #endif @@ -37,20 +37,36 @@ class Power { static void power_on(); static void power_off(); - #if ENABLED(AUTO_POWER_CONTROL) && POWER_OFF_DELAY > 0 - static void power_off_soon(); - #else - static inline void power_off_soon() { power_off(); } - #endif + #if ANY(POWER_OFF_TIMER, POWER_OFF_WAIT_FOR_COOLDOWN) + #if ENABLED(POWER_OFF_TIMER) + static millis_t power_off_time; + static void setPowerOffTimer(const millis_t delay_ms); + #endif + #if ENABLED(POWER_OFF_WAIT_FOR_COOLDOWN) + static bool power_off_on_cooldown; + static void setPowerOffOnCooldown(const bool ena); + #endif + static void cancelAutoPowerOff(); + static void checkAutoPowerOff(); + #endif - #if ENABLED(AUTO_POWER_CONTROL) - static void check(const bool pause); + #if ENABLED(AUTO_POWER_CONTROL) && POWER_OFF_DELAY > 0 + static void power_off_soon(); + #else + static void power_off_soon() { power_off(); } + #endif - private: - static millis_t lastPowerOn; - static bool is_power_needed(); + #if ENABLED(AUTO_POWER_CONTROL) + static void check(const bool pause); - #endif + private: + static millis_t lastPowerOn; + static bool is_power_needed(); + static bool is_cooling_needed(); + #elif ENABLED(POWER_OFF_WAIT_FOR_COOLDOWN) + private: + static bool is_cooling_needed(); + #endif }; extern Power powerManager; diff --git a/Marlin/src/feature/power_monitor.cpp b/Marlin/src/feature/power_monitor.cpp index 1937a541..e3c3e58f 100644 --- a/Marlin/src/feature/power_monitor.cpp +++ b/Marlin/src/feature/power_monitor.cpp @@ -26,7 +26,7 @@ #include "power_monitor.h" -#if HAS_LCD_MENU +#if HAS_MARLINUI_MENU #include "../lcd/marlinui.h" #include "../lcd/lcdprint.h" #endif @@ -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_u8str(F("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_u8str(F("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_u8str(F("W")); } #endif diff --git a/Marlin/src/feature/power_monitor.h b/Marlin/src/feature/power_monitor.h index f6e0b292..d57ef6fa 100644 --- a/Marlin/src/feature/power_monitor.h +++ b/Marlin/src/feature/power_monitor.h @@ -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)))); @@ -46,11 +46,11 @@ struct pm_lpf_t { class PowerMonitor { private: #if ENABLED(POWER_MONITOR_CURRENT) - static constexpr float amps_adc_scale = float(ADC_VREF) / (POWER_MONITOR_VOLTS_PER_AMP * PM_SAMPLE_RANGE); + static constexpr float amps_adc_scale = (float(ADC_VREF_MV) / 1000.0f) / (POWER_MONITOR_VOLTS_PER_AMP * PM_SAMPLE_RANGE); static pm_lpf_t amps; #endif #if ENABLED(POWER_MONITOR_VOLTAGE) - static constexpr float volts_adc_scale = float(ADC_VREF) / (POWER_MONITOR_VOLTS_PER_VOLT * PM_SAMPLE_RANGE); + static constexpr float volts_adc_scale = (float(ADC_VREF_MV) / 1000.0f) / (POWER_MONITOR_VOLTS_PER_VOLT * PM_SAMPLE_RANGE); static pm_lpf_t volts; #endif @@ -119,7 +119,7 @@ class PowerMonitor { volts.reset(); #endif - #if ENABLED(SDSUPPORT) + #if HAS_MEDIA display_item_ms = 0; display_item = 0; #endif diff --git a/Marlin/src/feature/powerloss.cpp b/Marlin/src/feature/powerloss.cpp index 723ec190..3c72ed51 100644 --- a/Marlin/src/feature/powerloss.cpp +++ b/Marlin/src/feature/powerloss.cpp @@ -31,9 +31,13 @@ #include "powerloss.h" #include "../core/macros.h" -bool PrintJobRecovery::enabled; // Initialized by settings.load() +#if ENABLED(EXTENSIBLE_UI) + #include "../lcd/extui/ui_api.h" +#endif + +bool PrintJobRecovery::enabled; // Initialized by settings.load -SdFile PrintJobRecovery::file; +MediaFile PrintJobRecovery::file; job_recovery_info_t PrintJobRecovery::info; const char PrintJobRecovery::filename[5] = "/PLR"; uint8_t PrintJobRecovery::queue_index_r; @@ -54,6 +58,10 @@ uint32_t PrintJobRecovery::cmd_sdpos, // = 0 #include "../module/temperature.h" #include "../core/serial.h" +#if HOMING_Z_WITH_PROBE + #include "../module/probe.h" +#endif + #if ENABLED(FWRETRACT) #include "fwretract.h" #endif @@ -63,21 +71,28 @@ uint32_t PrintJobRecovery::cmd_sdpos, // = 0 PrintJobRecovery recovery; -#ifndef POWER_LOSS_PURGE_LEN - #define POWER_LOSS_PURGE_LEN 0 -#endif - #if DISABLED(BACKUP_POWER_SUPPLY) #undef POWER_LOSS_RETRACT_LEN // No retract at outage without backup power #endif #ifndef POWER_LOSS_RETRACT_LEN #define POWER_LOSS_RETRACT_LEN 0 #endif +#ifndef POWER_LOSS_PURGE_LEN + #define POWER_LOSS_PURGE_LEN 0 +#endif + +// Allow power-loss recovery to be aborted +#define PLR_CAN_ABORT +#if ENABLED(PLR_CAN_ABORT) + #define PROCESS_SUBCOMMANDS_NOW(cmd) do { if (card.flag.abort_sd_printing) return; gcode.process_subcommands_now(cmd); }while(0) +#else + #define PROCESS_SUBCOMMANDS_NOW(cmd) gcode.process_subcommands_now(cmd) +#endif /** * Clear the recovery info */ -void PrintJobRecovery::init() { memset(&info, 0, sizeof(info)); } +void PrintJobRecovery::init() { info = {}; } /** * Enable or disable then call changed() @@ -97,6 +112,7 @@ void PrintJobRecovery::changed() { purge(); else if (IS_SD_PRINTING()) save(true); + TERN_(EXTENSIBLE_UI, ExtUI::onSetPowerLoss(enabled)); } /** @@ -104,13 +120,18 @@ void PrintJobRecovery::changed() { * * If a saved state exists send 'M1000 S' to initiate job recovery. */ -void PrintJobRecovery::check() { +bool PrintJobRecovery::check() { //if (!card.isMounted()) card.mount(); + bool success = false; if (card.isMounted()) { load(); - if (!valid()) return cancel(); - queue.inject(F("M1000S")); + success = valid(); + if (!success) + cancel(); + else + queue.inject(F("M1000S")); } + return success; } /** @@ -178,7 +199,8 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW info.valid_foot = info.valid_head; // Machine state - info.current_position = current_position; + // info.sdpos and info.current_position are pre-filled from the Stepper ISR + info.feedrate = uint16_t(MMS_TO_MMM(feedrate_mm_s)); info.zraise = zraise; info.flag.raised = raised; // Was Z raised before power-off? @@ -191,21 +213,19 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW #if DISABLED(NO_VOLUMETRICS) info.flag.volumetric_enabled = parser.volumetric_enabled; #if HAS_MULTI_EXTRUDER - for (int8_t e = 0; e < EXTRUDERS; e++) info.filament_size[e] = planner.filament_size[e]; + EXTRUDER_LOOP() info.filament_size[e] = planner.filament_size[e]; #else if (parser.volumetric_enabled) info.filament_size[0] = planner.filament_size[active_extruder]; #endif #endif - #if HAS_EXTRUDERS + #if HAS_HOTEND HOTEND_LOOP() info.target_temperature[e] = thermalManager.degTargetHotend(e); #endif TERN_(HAS_HEATED_BED, info.target_temperature_bed = thermalManager.degTargetBed()); - #if HAS_FAN - COPY(info.fan_speed, thermalManager.fan_speed); - #endif + TERN_(HAS_FAN, COPY(info.fan_speed, thermalManager.fan_speed)); #if HAS_LEVELING info.flag.leveling = planner.leveling_active; @@ -265,6 +285,10 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW #endif +#endif // POWER_LOSS_PIN + +#if PIN_EXISTS(POWER_LOSS) || ENABLED(DEBUG_POWER_LOSS_RECOVERY) + /** * An outage was detected by a sensor pin. * - If not SD printing, let the machine turn off on its own with no "KILL" screen @@ -273,7 +297,7 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW * - If backup power is available Retract E and Raise Z * - Go to the KILL screen */ - void PrintJobRecovery::_outage() { + void PrintJobRecovery::_outage(TERN_(DEBUG_POWER_LOSS_RECOVERY, const bool simulated/*=false*/)) { #if ENABLED(BACKUP_POWER_SUPPLY) static bool lock = false; if (lock) return; // No re-entrance from idle() during retract_and_lift() @@ -291,6 +315,9 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW // and a flag whether the raise was already done here. if (IS_SD_PRINTING()) save(true, zraise, ENABLED(BACKUP_POWER_SUPPLY)); + // Tell the LCD about the outage, even though it is about to die + TERN_(EXTENSIBLE_UI, ExtUI::onPowerLoss()); + // Disable all heaters to reduce power loss thermalManager.disable_all_heaters(); @@ -301,10 +328,16 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=POW retract_and_lift(zraise); #endif - kill(GET_TEXT_F(MSG_OUTAGE_RECOVERY)); + if (TERN0(DEBUG_POWER_LOSS_RECOVERY, simulated)) { + card.fileHasFinished(); + current_position.reset(); + sync_plan_position(); + } + else + kill(GET_TEXT_F(MSG_OUTAGE_RECOVERY)); } -#endif +#endif // POWER_LOSS_PIN || DEBUG_POWER_LOSS_RECOVERY /** * Save the recovery info the recovery file @@ -332,12 +365,23 @@ void PrintJobRecovery::resume() { // Apply the dry-run flag if enabled if (info.flag.dryrun) marlin_debug_flags |= MARLIN_DEBUG_DRYRUN; + #if ENABLED(DEBUG_POWER_LOSS_RECOVERY) + struct OnExit { + uint8_t old_flags; + OnExit() { + old_flags = marlin_debug_flags; + marlin_debug_flags |= MARLIN_DEBUG_ECHO; + } + ~OnExit() { marlin_debug_flags = old_flags; } + } on_exit; + #endif + // Restore cold extrusion permission TERN_(PREVENT_COLD_EXTRUSION, thermalManager.allow_cold_extrude = info.flag.allow_cold_extrusion); #if HAS_LEVELING // Make sure leveling is off before any G92 and G28 - gcode.process_subcommands_now(F("M420 S0 Z0")); + PROCESS_SUBCOMMANDS_NOW(F("M420S0")); #endif #if HAS_HEATED_BED @@ -345,7 +389,7 @@ void PrintJobRecovery::resume() { if (bt) { // Restore the bed temperature sprintf_P(cmd, PSTR("M190S%i"), bt); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(cmd); } #endif @@ -356,10 +400,10 @@ void PrintJobRecovery::resume() { if (et) { #if HAS_MULTI_HOTEND sprintf_P(cmd, PSTR("T%iS"), e); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(cmd); #endif sprintf_P(cmd, PSTR("M109S%i"), et); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(cmd); } } #endif @@ -373,7 +417,7 @@ void PrintJobRecovery::resume() { // establish the current position as best we can. // - gcode.process_subcommands_now(F("G92.9E0")); // Reset E to 0 + PROCESS_SUBCOMMANDS_NOW(F("G92.9E0")); // Reset E to 0 #if Z_HOME_TO_MAX @@ -384,41 +428,39 @@ void PrintJobRecovery::resume() { "G28R0\n" // Home all axes (no raise) "G1Z%sF1200" // Move Z down to (raised) height ), dtostrf(z_now, 1, 3, str_1)); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(cmd); #elif DISABLED(BELTPRINTER) #if ENABLED(POWER_LOSS_RECOVER_ZHOME) && defined(POWER_LOSS_ZHOME_POS) #define HOMING_Z_DOWN 1 - #else - #define HOME_XY_ONLY 1 #endif float z_now = info.flag.raised ? z_raised : z_print; - // Reset E to 0 and set Z to the real position - #if HOME_XY_ONLY + #if !HOMING_Z_DOWN + // Set Z to the real position sprintf_P(cmd, PSTR("G92.9Z%s"), dtostrf(z_now, 1, 3, str_1)); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(cmd); #endif // Does Z need to be raised now? It should be raised before homing XY. if (z_raised > z_now) { z_now = z_raised; sprintf_P(cmd, PSTR("G1Z%sF600"), dtostrf(z_now, 1, 3, str_1)); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(cmd); } - // Home XY with no Z raise, and also home Z here if Z isn't homing down below. - gcode.process_subcommands_now(F("G28R0" TERN_(HOME_XY_ONLY, "XY"))); // No raise during G28 + // Home XY with no Z raise + PROCESS_SUBCOMMANDS_NOW(F("G28R0XY")); // No raise during G28 #endif #if HOMING_Z_DOWN // Move to a safe XY position and home Z while avoiding the print. - constexpr xy_pos_t p = POWER_LOSS_ZHOME_POS; - sprintf_P(cmd, PSTR("G1X%sY%sF1000\nG28Z"), dtostrf(p.x, 1, 3, str_1), dtostrf(p.y, 1, 3, str_2)); - gcode.process_subcommands_now(cmd); + const xy_pos_t p = xy_pos_t(POWER_LOSS_ZHOME_POS) TERN_(HOMING_Z_WITH_PROBE, - probe.offset_xy); + sprintf_P(cmd, PSTR("G1X%sY%sF1000\nG28HZ"), dtostrf(p.x, 1, 3, str_1), dtostrf(p.y, 1, 3, str_2)); + PROCESS_SUBCOMMANDS_NOW(cmd); #endif // Mark all axes as having been homed (no effect on current_position) @@ -429,12 +471,12 @@ void PrintJobRecovery::resume() { // Leveling may already be enabled due to the ENABLE_LEVELING_AFTER_G28 option. // TODO: Add a G28 parameter to leave leveling disabled. sprintf_P(cmd, PSTR("M420S%cZ%s"), '0' + (char)info.flag.leveling, dtostrf(info.fade, 1, 1, str_1)); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(cmd); - #if HOME_XY_ONLY + #if !HOMING_Z_DOWN // The physical Z was adjusted at power-off so undo the M420S1 correction to Z with G92.9. sprintf_P(cmd, PSTR("G92.9Z%s"), dtostrf(z_now, 1, 1, str_1)); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(cmd); #endif #endif @@ -442,24 +484,24 @@ void PrintJobRecovery::resume() { // Z was homed down to the bed, so move up to the raised height. z_now = z_raised; sprintf_P(cmd, PSTR("G1Z%sF600"), dtostrf(z_now, 1, 3, str_1)); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(cmd); #endif // Recover volumetric extrusion state #if DISABLED(NO_VOLUMETRICS) #if HAS_MULTI_EXTRUDER - for (int8_t e = 0; e < EXTRUDERS; e++) { + EXTRUDER_LOOP() { sprintf_P(cmd, PSTR("M200T%iD%s"), e, dtostrf(info.filament_size[e], 1, 3, str_1)); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(cmd); } if (!info.flag.volumetric_enabled) { sprintf_P(cmd, PSTR("M200T%iD0"), info.active_extruder); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(cmd); } #else if (info.flag.volumetric_enabled) { sprintf_P(cmd, PSTR("M200D%s"), dtostrf(info.filament_size[0], 1, 3, str_1)); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(cmd); } #endif #endif @@ -471,10 +513,10 @@ void PrintJobRecovery::resume() { if (et) { #if HAS_MULTI_HOTEND sprintf_P(cmd, PSTR("T%iS"), e); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(cmd); #endif sprintf_P(cmd, PSTR("M109S%i"), et); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(cmd); } } #endif @@ -482,7 +524,7 @@ void PrintJobRecovery::resume() { // Restore the previously active tool (with no_move) #if HAS_MULTI_EXTRUDER || HAS_MULTI_HOTEND sprintf_P(cmd, PSTR("T%i S"), info.active_extruder); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(cmd); #endif // Restore print cooling fan speeds @@ -491,17 +533,17 @@ void PrintJobRecovery::resume() { const int f = info.fan_speed[i]; if (f) { sprintf_P(cmd, PSTR("M106P%iS%i"), i, f); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(cmd); } } #endif // Restore retract and hop state from an active `G10` command #if ENABLED(FWRETRACT) - LOOP_L_N(e, EXTRUDERS) { + EXTRUDER_LOOP() { if (info.retract[e] != 0.0) { fwretract.current_retract[e] = info.retract[e]; - fwretract.retracted[e] = true; + fwretract.retracted.set(e); } } fwretract.current_hop = info.retract_hop; @@ -513,17 +555,17 @@ void PrintJobRecovery::resume() { // Un-retract if there was a retract at outage #if ENABLED(BACKUP_POWER_SUPPLY) && POWER_LOSS_RETRACT_LEN > 0 - gcode.process_subcommands_now(F("G1E" STRINGIFY(POWER_LOSS_RETRACT_LEN) "F3000")); + PROCESS_SUBCOMMANDS_NOW(F("G1F3000E" STRINGIFY(POWER_LOSS_RETRACT_LEN))); #endif // Additional purge on resume if configured #if POWER_LOSS_PURGE_LEN - sprintf_P(cmd, PSTR("G1 E%d F3000"), (POWER_LOSS_PURGE_LEN) + (POWER_LOSS_RETRACT_LEN)); - gcode.process_subcommands_now(cmd); + sprintf_P(cmd, PSTR("G1F3000E%d"), (POWER_LOSS_PURGE_LEN) + (POWER_LOSS_RETRACT_LEN)); + PROCESS_SUBCOMMANDS_NOW(cmd); #endif #if ENABLED(NOZZLE_CLEAN_FEATURE) - gcode.process_subcommands_now(F("G12")); + PROCESS_SUBCOMMANDS_NOW(F("G12")); #endif // Move back over to the saved XY @@ -531,46 +573,38 @@ void PrintJobRecovery::resume() { dtostrf(info.current_position.x, 1, 3, str_1), dtostrf(info.current_position.y, 1, 3, str_2) ); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(cmd); // Move back down to the saved Z for printing sprintf_P(cmd, PSTR("G1Z%sF600"), dtostrf(z_print, 1, 3, str_1)); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(cmd); // Restore the feedrate sprintf_P(cmd, PSTR("G1F%d"), info.feedrate); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(cmd); // Restore E position with G92.9 sprintf_P(cmd, PSTR("G92.9E%s"), dtostrf(info.current_position.e, 1, 3, str_1)); - gcode.process_subcommands_now(cmd); + PROCESS_SUBCOMMANDS_NOW(cmd); TERN_(GCODE_REPEAT_MARKERS, repeat = info.stored_repeat); TERN_(HAS_HOME_OFFSET, home_offset = info.home_offset); TERN_(HAS_POSITION_SHIFT, position_shift = info.position_shift); #if HAS_HOME_OFFSET || HAS_POSITION_SHIFT - LOOP_LINEAR_AXES(i) update_workspace_offset((AxisEnum)i); + LOOP_NUM_AXES(i) update_workspace_offset((AxisEnum)i); #endif // Relative axis modes gcode.axis_relative = info.axis_relative; - #if ENABLED(DEBUG_POWER_LOSS_RECOVERY) - const uint8_t old_flags = marlin_debug_flags; - marlin_debug_flags |= MARLIN_DEBUG_ECHO; - #endif - // Continue to apply PLR when a file is resumed! enable(true); // Resume the SD file from the last position - char *fn = info.sd_filename; - sprintf_P(cmd, M23_STR, fn); - gcode.process_subcommands_now(cmd); + sprintf_P(cmd, M23_STR, &info.sd_filename[0]); + PROCESS_SUBCOMMANDS_NOW(cmd); sprintf_P(cmd, PSTR("M24S%ldT%ld"), resume_sdpos, info.print_job_elapsed); - gcode.process_subcommands_now(cmd); - - TERN_(DEBUG_POWER_LOSS_RECOVERY, marlin_debug_flags = old_flags); + PROCESS_SUBCOMMANDS_NOW(cmd); } #if ENABLED(DEBUG_POWER_LOSS_RECOVERY) @@ -593,13 +627,13 @@ void PrintJobRecovery::resume() { #if ENABLED(GCODE_REPEAT_MARKERS) DEBUG_ECHOLNPGM("repeat index: ", info.stored_repeat.index); - LOOP_L_N(i, info.stored_repeat.index) + for (uint8_t i = 0; i < info.stored_repeat.index; ++i) DEBUG_ECHOLNPGM("..... sdpos: ", info.stored_repeat.marker.sdpos, " count: ", info.stored_repeat.marker.counter); #endif #if HAS_HOME_OFFSET DEBUG_ECHOPGM("home_offset: "); - LOOP_LINEAR_AXES(i) { + LOOP_NUM_AXES(i) { if (i) DEBUG_CHAR(','); DEBUG_DECIMAL(info.home_offset[i]); } @@ -608,7 +642,7 @@ void PrintJobRecovery::resume() { #if HAS_POSITION_SHIFT DEBUG_ECHOPGM("position_shift: "); - LOOP_LINEAR_AXES(i) { + LOOP_NUM_AXES(i) { if (i) DEBUG_CHAR(','); DEBUG_DECIMAL(info.position_shift[i]); } @@ -621,7 +655,7 @@ void PrintJobRecovery::resume() { #if DISABLED(NO_VOLUMETRICS) DEBUG_ECHOPGM("filament_size:"); - LOOP_L_N(i, EXTRUDERS) DEBUG_ECHOLNPGM(" ", info.filament_size[i]); + EXTRUDER_LOOP() DEBUG_ECHOLNPGM(" ", info.filament_size[e]); DEBUG_EOL(); #endif @@ -653,7 +687,7 @@ void PrintJobRecovery::resume() { #if ENABLED(FWRETRACT) DEBUG_ECHOPGM("retract: "); - for (int8_t e = 0; e < EXTRUDERS; e++) { + EXTRUDER_LOOP() { DEBUG_ECHO(info.retract[e]); if (e < EXTRUDERS - 1) DEBUG_CHAR(','); } @@ -662,7 +696,7 @@ void PrintJobRecovery::resume() { #endif // Mixing extruder and gradient - #if BOTH(MIXING_EXTRUDER, GRADIENT_MIX) + #if ALL(MIXING_EXTRUDER, GRADIENT_MIX) DEBUG_ECHOLNPGM("gradient: ", info.gradient.enabled ? "ON" : "OFF"); #endif @@ -681,7 +715,9 @@ void PrintJobRecovery::resume() { DEBUG_ECHOLNPGM("flag.dryrun: ", AS_DIGIT(info.flag.dryrun)); DEBUG_ECHOLNPGM("flag.allow_cold_extrusion: ", AS_DIGIT(info.flag.allow_cold_extrusion)); - DEBUG_ECHOLNPGM("flag.volumetric_enabled: ", AS_DIGIT(info.flag.volumetric_enabled)); + #if DISABLED(NO_VOLUMETRICS) + DEBUG_ECHOLNPGM("flag.volumetric_enabled: ", AS_DIGIT(info.flag.volumetric_enabled)); + #endif } else DEBUG_ECHOLNPGM("INVALID DATA"); diff --git a/Marlin/src/feature/powerloss.h b/Marlin/src/feature/powerloss.h index 76cb398a..29cba5fd 100644 --- a/Marlin/src/feature/powerloss.h +++ b/Marlin/src/feature/powerloss.h @@ -31,11 +31,11 @@ #include "../inc/MarlinConfig.h" #if ENABLED(GCODE_REPEAT_MARKERS) - #include "../feature/repeat.h" + #include "repeat.h" #endif #if ENABLED(MIXING_EXTRUDER) - #include "../feature/mixing.h" + #include "mixing.h" #endif #if !defined(POWER_LOSS_STATE) && PIN_EXISTS(POWER_LOSS) @@ -43,7 +43,7 @@ #endif #ifndef POWER_LOSS_ZRAISE - #define POWER_LOSS_ZRAISE 2 + #define POWER_LOSS_ZRAISE 2 // Default Z-raise on outage or resume #endif //#define DEBUG_POWER_LOSS_RECOVERY @@ -113,7 +113,7 @@ typedef struct { millis_t print_job_elapsed; // Relative axis modes - uint8_t axis_relative; + relative_t axis_relative; // Misc. Marlin flags struct { @@ -138,7 +138,7 @@ class PrintJobRecovery { public: static const char filename[5]; - static SdFile file; + static MediaFile file; static job_recovery_info_t info; static uint8_t queue_index_r; //!< Queue index of the active command @@ -152,7 +152,10 @@ class PrintJobRecovery { static void init(); static void prepare(); - static inline void setup() { + static void setup() { + #if PIN_EXISTS(OUTAGECON) + OUT_WRITE(OUTAGECON_PIN, HIGH); + #endif #if PIN_EXISTS(POWER_LOSS) #if ENABLED(POWER_LOSS_PULLUP) SET_INPUT_PULLUP(POWER_LOSS_PIN); @@ -165,28 +168,28 @@ class PrintJobRecovery { } // Track each command's file offsets - static inline uint32_t command_sdpos() { return sdpos[queue_index_r]; } - static inline void commit_sdpos(const uint8_t index_w) { sdpos[index_w] = cmd_sdpos; } + static uint32_t command_sdpos() { return sdpos[queue_index_r]; } + static void commit_sdpos(const uint8_t index_w) { sdpos[index_w] = cmd_sdpos; } static bool enabled; static void enable(const bool onoff); static void changed(); - static inline bool exists() { return card.jobRecoverFileExists(); } - static inline void open(const bool read) { card.openJobRecoveryFile(read); } - static inline void close() { file.close(); } + static bool exists() { return card.jobRecoverFileExists(); } + static void open(const bool read) { card.openJobRecoveryFile(read); } + static void close() { file.close(); } - static void check(); + static bool check(); static void resume(); static void purge(); - static inline void cancel() { purge(); IF_DISABLED(NO_SD_AUTOSTART, card.autofile_begin()); } + static void cancel() { purge(); } static void load(); static void save(const bool force=ENABLED(SAVE_EACH_CMD_MODE), const float zraise=POWER_LOSS_ZRAISE, const bool raised=false); #if PIN_EXISTS(POWER_LOSS) - static inline void outage() { + static void outage() { static constexpr uint8_t OUTAGE_THRESHOLD = 3; static uint8_t outage_counter = 0; if (enabled && READ(POWER_LOSS_PIN) == POWER_LOSS_STATE) { @@ -199,14 +202,14 @@ class PrintJobRecovery { #endif // The referenced file exists - static inline bool interrupted_file_exists() { return card.fileExists(info.sd_filename); } + static bool interrupted_file_exists() { return card.fileExists(info.sd_filename); } - static inline bool valid() { return info.valid() && interrupted_file_exists(); } + static bool valid() { return info.valid() && interrupted_file_exists(); } #if ENABLED(DEBUG_POWER_LOSS_RECOVERY) static void debug(FSTR_P const prefix); #else - static inline void debug(FSTR_P const) {} + static void debug(FSTR_P const) {} #endif private: @@ -216,9 +219,9 @@ class PrintJobRecovery { static void retract_and_lift(const_float_t zraise); #endif - #if PIN_EXISTS(POWER_LOSS) + #if PIN_EXISTS(POWER_LOSS) || ENABLED(DEBUG_POWER_LOSS_RECOVERY) friend class GcodeSuite; - static void _outage(); + static void _outage(TERN_(DEBUG_POWER_LOSS_RECOVERY, const bool simulated=false)); #endif }; diff --git a/Marlin/src/feature/probe_temp_comp.cpp b/Marlin/src/feature/probe_temp_comp.cpp index 9a975d67..2b362a21 100644 --- a/Marlin/src/feature/probe_temp_comp.cpp +++ b/Marlin/src/feature/probe_temp_comp.cpp @@ -28,6 +28,7 @@ #include "probe_temp_comp.h" #include +#include "../module/temperature.h" ProbeTempComp ptc; @@ -62,15 +63,16 @@ constexpr temp_calib_t ProbeTempComp::cali_info[TSI_COUNT]; uint8_t ProbeTempComp::calib_idx; // = 0 float ProbeTempComp::init_measurement; // = 0.0 +bool ProbeTempComp::enabled = true; void ProbeTempComp::reset() { - TERN_(PTC_PROBE, LOOP_L_N(i, PTC_PROBE_COUNT) z_offsets_probe[i] = z_offsets_probe_default[i]); - TERN_(PTC_BED, LOOP_L_N(i, PTC_BED_COUNT) z_offsets_bed[i] = z_offsets_bed_default[i]); - TERN_(PTC_HOTEND, LOOP_L_N(i, PTC_HOTEND_COUNT) z_offsets_hotend[i] = z_offsets_hotend_default[i]); + TERN_(PTC_PROBE, for (uint8_t i = 0; i < PTC_PROBE_COUNT; ++i) z_offsets_probe[i] = z_offsets_probe_default[i]); + TERN_(PTC_BED, for (uint8_t i = 0; i < PTC_BED_COUNT; ++i) z_offsets_bed[i] = z_offsets_bed_default[i]); + TERN_(PTC_HOTEND, for (uint8_t i = 0; i < PTC_HOTEND_COUNT; ++i) z_offsets_hotend[i] = z_offsets_hotend_default[i]); } void ProbeTempComp::clear_offsets(const TempSensorID tsi) { - LOOP_L_N(i, cali_info[tsi].measurements) + for (uint8_t i = 0; i < cali_info[tsi].measurements; ++i) sensor_z_offsets[tsi][i] = 0; calib_idx = 0; } @@ -82,7 +84,7 @@ bool ProbeTempComp::set_offset(const TempSensorID tsi, const uint8_t idx, const } void ProbeTempComp::print_offsets() { - LOOP_L_N(s, TSI_COUNT) { + for (uint8_t s = 0; s < TSI_COUNT; ++s) { celsius_t temp = cali_info[s].start_temp; for (int16_t i = -1; i < cali_info[s].measurements; ++i) { SERIAL_ECHOF( @@ -169,6 +171,13 @@ bool ProbeTempComp::finish_calibration(const TempSensorID tsi) { return true; } +void ProbeTempComp::apply_compensation(float &meas_z) { + if (!enabled) return; + TERN_(PTC_BED, compensate_measurement(TSI_BED, thermalManager.degBed(), meas_z)); + TERN_(PTC_PROBE, compensate_measurement(TSI_PROBE, thermalManager.degProbe(), meas_z)); + TERN_(PTC_HOTEND, compensate_measurement(TSI_EXT, thermalManager.degHotend(0), meas_z)); +} + void ProbeTempComp::compensate_measurement(const TempSensorID tsi, const celsius_t temp, float &meas_z) { const uint8_t measurements = cali_info[tsi].measurements; const celsius_t start_temp = cali_info[tsi].start_temp, @@ -223,7 +232,7 @@ bool ProbeTempComp::linear_regression(const TempSensorID tsi, float &k, float &d sum_xy = 0, sum_y = 0; float xi = static_cast(start_temp); - LOOP_L_N(i, calib_idx) { + for (uint8_t i = 0; i < calib_idx; ++i) { const float yi = static_cast(data[i]); xi += res_temp; sum_x += xi; diff --git a/Marlin/src/feature/probe_temp_comp.h b/Marlin/src/feature/probe_temp_comp.h index 4579f218..42348db6 100644 --- a/Marlin/src/feature/probe_temp_comp.h +++ b/Marlin/src/feature/probe_temp_comp.h @@ -74,11 +74,10 @@ class ProbeTempComp { static int16_t z_offsets_hotend[PTC_HOTEND_COUNT]; // (µm) #endif - static inline void reset_index() { calib_idx = 0; }; - static inline uint8_t get_index() { return calib_idx; } + static void reset_index() { calib_idx = 0; }; + static uint8_t get_index() { return calib_idx; } static void reset(); - static void clear_offsets(const TempSensorID tsi); - static inline void clear_all_offsets() { + static void clear_all_offsets() { TERN_(PTC_PROBE, clear_offsets(TSI_PROBE)); TERN_(PTC_BED, clear_offsets(TSI_BED)); TERN_(PTC_HOTEND, clear_offsets(TSI_EXT)); @@ -88,10 +87,16 @@ class ProbeTempComp { static void prepare_new_calibration(const_float_t init_meas_z); static void push_back_new_measurement(const TempSensorID tsi, const_float_t meas_z); static bool finish_calibration(const TempSensorID tsi); - static void compensate_measurement(const TempSensorID tsi, const celsius_t temp, float &meas_z); + static void set_enabled(const bool ena) { enabled = ena; } + + // Apply all temperature compensation adjustments + static void apply_compensation(float &meas_z); private: static uint8_t calib_idx; + static bool enabled; + + static void clear_offsets(const TempSensorID tsi); /** * Base value. Temperature compensation values will be deltas @@ -104,6 +109,8 @@ class ProbeTempComp { * to allow generating values of higher temperatures. */ static bool linear_regression(const TempSensorID tsi, float &k, float &d); + + static void compensate_measurement(const TempSensorID tsi, const celsius_t temp, float &meas_z); }; extern ProbeTempComp ptc; diff --git a/Marlin/src/feature/repeat.cpp b/Marlin/src/feature/repeat.cpp index 165f71fd..4484dab9 100644 --- a/Marlin/src/feature/repeat.cpp +++ b/Marlin/src/feature/repeat.cpp @@ -42,7 +42,7 @@ void Repeat::add_marker(const uint32_t sdpos, const uint16_t count) { SERIAL_ECHO_MSG("!Too many markers."); else { marker[index].sdpos = sdpos; - marker[index].counter = count ?: -1; + marker[index].counter = count ? count - 1 : -1; index++; DEBUG_ECHOLNPGM("Add Marker ", index, " at ", sdpos, " (", count, ")"); } @@ -66,7 +66,7 @@ void Repeat::loop() { } } -void Repeat::cancel() { LOOP_L_N(i, index) marker[i].counter = 0; } +void Repeat::cancel() { for (uint8_t i = 0; i < index; ++i) marker[i].counter = 0; } void Repeat::early_parse_M808(char * const cmd) { if (is_command_M808(cmd)) { diff --git a/Marlin/src/feature/repeat.h b/Marlin/src/feature/repeat.h index 0f4d9425..ce309f64 100644 --- a/Marlin/src/feature/repeat.h +++ b/Marlin/src/feature/repeat.h @@ -38,9 +38,9 @@ class Repeat { static repeat_marker_t marker[MAX_REPEAT_NESTING]; static uint8_t index; public: - static inline void reset() { index = 0; } - static inline bool is_active() { - LOOP_L_N(i, index) if (marker[i].counter) return true; + static void reset() { index = 0; } + static bool is_active() { + for (uint8_t i = 0; i < index; ++i) if (marker[i].counter) return true; return false; } static bool is_command_M808(char * const cmd) { return cmd[0] == 'M' && cmd[1] == '8' && cmd[2] == '0' && cmd[3] == '8' && !NUMERIC(cmd[4]); } @@ -48,6 +48,9 @@ class Repeat { static void add_marker(const uint32_t sdpos, const uint16_t count); static void loop(); static void cancel(); + static uint8_t count() { return index; } + static int16_t get_marker_counter(const uint8_t i) { return marker[i].counter; } + static uint32_t get_marker_sdpos(const uint8_t i) { return marker[i].sdpos; } }; extern Repeat repeat; diff --git a/Marlin/src/feature/runout.cpp b/Marlin/src/feature/runout.cpp index 9317e348..aac1cc9c 100644 --- a/Marlin/src/feature/runout.cpp +++ b/Marlin/src/feature/runout.cpp @@ -59,7 +59,7 @@ bool FilamentMonitorBase::enabled = true, // Filament Runout event handler // #include "../MarlinCore.h" -#include "../feature/pause.h" +#include "pause.h" #include "../gcode/queue.h" #if ENABLED(HOST_ACTION_COMMANDS) @@ -68,8 +68,8 @@ bool FilamentMonitorBase::enabled = true, #if ENABLED(EXTENSIBLE_UI) #include "../lcd/extui/ui_api.h" -#elif ENABLED(DWIN_CREALITY_LCD_ENHANCED) - #include "../lcd/e3v2/enhanced/dwin.h" +#elif ENABLED(DWIN_LCD_PROUI) + #include "../lcd/e3v2/proui/dwin.h" #endif void event_filament_runout(const uint8_t extruder) { @@ -88,7 +88,7 @@ void event_filament_runout(const uint8_t extruder) { #endif TERN_(EXTENSIBLE_UI, ExtUI::onFilamentRunout(ExtUI::getTool(extruder))); - TERN_(DWIN_CREALITY_LCD_ENHANCED, DWIN_FilamentRunout(extruder)); + TERN_(DWIN_LCD_PROUI, DWIN_FilamentRunout(extruder)); #if ANY(HOST_PROMPT_SUPPORT, HOST_ACTION_COMMANDS, MULTI_FILAMENT_SENSOR) const char tool = '0' + TERN0(MULTI_FILAMENT_SENSOR, extruder); diff --git a/Marlin/src/feature/runout.h b/Marlin/src/feature/runout.h index 8065e515..b5e32e0d 100644 --- a/Marlin/src/feature/runout.h +++ b/Marlin/src/feature/runout.h @@ -30,7 +30,7 @@ #include "../module/planner.h" #include "../module/stepper.h" // for block_t #include "../gcode/queue.h" -#include "../feature/pause.h" +#include "pause.h" // for did_pause_print #include "../inc/MarlinConfig.h" @@ -83,30 +83,30 @@ class TFilamentMonitor : public FilamentMonitorBase { static sensor_t sensor; public: - static inline void setup() { + static void setup() { sensor.setup(); reset(); } - static inline void reset() { + static void reset() { filament_ran_out = false; response.reset(); } // Call this method when filament is present, // so the response can reset its counter. - static inline void filament_present(const uint8_t extruder) { + static void filament_present(const uint8_t extruder) { response.filament_present(extruder); } #if HAS_FILAMENT_RUNOUT_DISTANCE - static inline float& runout_distance() { return response.runout_distance_mm; } - static inline void set_runout_distance(const_float_t mm) { response.runout_distance_mm = mm; } + static float& runout_distance() { return response.runout_distance_mm; } + static void set_runout_distance(const_float_t mm) { response.runout_distance_mm = mm; } #endif // Handle a block completion. RunoutResponseDelayed uses this to // add up the length of filament moved while the filament is out. - static inline void block_completed(const block_t * const b) { + static void block_completed(const block_t * const b) { if (enabled) { response.block_completed(b); sensor.block_completed(b); @@ -114,7 +114,7 @@ class TFilamentMonitor : public FilamentMonitorBase { } // Give the response a chance to update its counter. - static inline void run() { + static void run() { if (enabled && !filament_ran_out && (printingIsActive() || did_pause_print)) { TERN_(HAS_FILAMENT_RUNOUT_DISTANCE, cli()); // Prevent RunoutResponseDelayed::block_completed from accumulating here response.run(); @@ -144,7 +144,7 @@ class TFilamentMonitor : public FilamentMonitorBase { #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) if (runout_flags) { SERIAL_ECHOPGM("Runout Sensors: "); - LOOP_L_N(i, 8) SERIAL_ECHO('0' + TEST(runout_flags, i)); + for (uint8_t i = 0; i < 8; ++i) SERIAL_CHAR('0' + TEST(runout_flags, i)); SERIAL_ECHOPGM(" -> ", extruder); if (ran_out) SERIAL_ECHOPGM(" RUN OUT"); SERIAL_EOL(); @@ -168,12 +168,12 @@ class FilamentSensorBase { * Called by FilamentSensorSwitch::run when filament is detected. * Called by FilamentSensorEncoder::block_completed when motion is detected. */ - static inline void filament_present(const uint8_t extruder) { + static void filament_present(const uint8_t extruder) { runout.filament_present(extruder); // ...which calls response.filament_present(extruder) } public: - static inline void setup() { + static void setup() { #define _INIT_RUNOUT_PIN(P,S,U,D) do{ if (ENABLED(U)) SET_INPUT_PULLUP(P); else if (ENABLED(D)) SET_INPUT_PULLDOWN(P); else SET_INPUT(P); }while(0) #define INIT_RUNOUT_PIN(N) _INIT_RUNOUT_PIN(FIL_RUNOUT##N##_PIN, FIL_RUNOUT##N##_STATE, FIL_RUNOUT##N##_PULLUP, FIL_RUNOUT##N##_PULLDOWN) #if NUM_RUNOUT_SENSORS >= 1 @@ -205,14 +205,14 @@ class FilamentSensorBase { } // Return a bitmask of runout pin states - static inline uint8_t poll_runout_pins() { + static uint8_t poll_runout_pins() { #define _OR_RUNOUT(N) | (READ(FIL_RUNOUT##N##_PIN) ? _BV((N) - 1) : 0) return (0 REPEAT_1(NUM_RUNOUT_SENSORS, _OR_RUNOUT)); #undef _OR_RUNOUT } // Return a bitmask of runout flag states (1 bits always indicates runout) - static inline uint8_t poll_runout_states() { + static uint8_t poll_runout_states() { return poll_runout_pins() ^ uint8_t(0 #if NUM_RUNOUT_SENSORS >= 1 | (FIL_RUNOUT1_STATE ? 0 : _BV(1 - 1)) @@ -254,7 +254,7 @@ class FilamentSensorBase { private: static uint8_t motion_detected; - static inline void poll_motion_sensor() { + static void poll_motion_sensor() { static uint8_t old_state; const uint8_t new_state = poll_runout_pins(), change = old_state ^ new_state; @@ -263,7 +263,7 @@ class FilamentSensorBase { #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) if (change) { SERIAL_ECHOPGM("Motion detected:"); - LOOP_L_N(e, NUM_RUNOUT_SENSORS) + for (uint8_t e = 0; e < NUM_RUNOUT_SENSORS; ++e) if (TEST(change, e)) SERIAL_CHAR(' ', '0' + e); SERIAL_EOL(); } @@ -273,7 +273,7 @@ class FilamentSensorBase { } public: - static inline void block_completed(const block_t * const b) { + static void block_completed(const block_t * const b) { // If the sensor wheel has moved since the last call to // this method reset the runout counter for the extruder. if (TEST(motion_detected, b->extruder)) @@ -283,7 +283,7 @@ class FilamentSensorBase { motion_detected = 0; } - static inline void run() { poll_motion_sensor(); } + static void run() { poll_motion_sensor(); } }; #else @@ -294,7 +294,7 @@ class FilamentSensorBase { */ class FilamentSensorSwitch : public FilamentSensorBase { private: - static inline bool poll_runout_state(const uint8_t extruder) { + static bool poll_runout_state(const uint8_t extruder) { const uint8_t runout_states = poll_runout_states(); #if MULTI_FILAMENT_SENSOR if ( !TERN0(DUAL_X_CARRIAGE, idex_is_duplicating()) @@ -307,10 +307,10 @@ class FilamentSensorBase { } public: - static inline void block_completed(const block_t * const) {} + static void block_completed(const block_t * const) {} - static inline void run() { - LOOP_L_N(s, NUM_RUNOUT_SENSORS) { + static void run() { + for (uint8_t s = 0; s < NUM_RUNOUT_SENSORS; ++s) { const bool out = poll_runout_state(s); if (!out) filament_present(s); #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) @@ -324,7 +324,6 @@ class FilamentSensorBase { } }; - #endif // !FILAMENT_MOTION_SENSOR /********************************* RESPONSE TYPE *********************************/ @@ -341,34 +340,34 @@ class FilamentSensorBase { public: static float runout_distance_mm; - static inline void reset() { - LOOP_L_N(i, NUM_RUNOUT_SENSORS) filament_present(i); + static void reset() { + for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) filament_present(i); } - static inline void run() { + static void run() { #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) static millis_t t = 0; const millis_t ms = millis(); if (ELAPSED(ms, t)) { t = millis() + 1000UL; - LOOP_L_N(i, NUM_RUNOUT_SENSORS) + for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) SERIAL_ECHOF(i ? F(", ") : F("Remaining mm: "), runout_mm_countdown[i]); SERIAL_EOL(); } #endif } - static inline uint8_t has_run_out() { + static uint8_t has_run_out() { uint8_t runout_flags = 0; - LOOP_L_N(i, NUM_RUNOUT_SENSORS) if (runout_mm_countdown[i] < 0) SBI(runout_flags, i); + for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) if (runout_mm_countdown[i] < 0) SBI(runout_flags, i); return runout_flags; } - static inline void filament_present(const uint8_t extruder) { + static void filament_present(const uint8_t extruder) { runout_mm_countdown[extruder] = runout_distance_mm; } - static inline void block_completed(const block_t * const b) { + static void block_completed(const block_t * const b) { if (b->steps.x || b->steps.y || b->steps.z || did_pause_print) { // Allow pause purge move to re-trigger runout state // Only trigger on extrusion with XYZ movement to allow filament change and retract/recover. const uint8_t e = b->extruder; @@ -389,23 +388,23 @@ class FilamentSensorBase { static int8_t runout_count[NUM_RUNOUT_SENSORS]; public: - static inline void reset() { - LOOP_L_N(i, NUM_RUNOUT_SENSORS) filament_present(i); + static void reset() { + for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) filament_present(i); } - static inline void run() { - LOOP_L_N(i, NUM_RUNOUT_SENSORS) if (runout_count[i] >= 0) runout_count[i]--; + static void run() { + for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) if (runout_count[i] >= 0) runout_count[i]--; } - static inline uint8_t has_run_out() { + static uint8_t has_run_out() { uint8_t runout_flags = 0; - LOOP_L_N(i, NUM_RUNOUT_SENSORS) if (runout_count[i] < 0) SBI(runout_flags, i); + for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) if (runout_count[i] < 0) SBI(runout_flags, i); return runout_flags; } - static inline void block_completed(const block_t * const) { } + static void block_completed(const block_t * const) { } - static inline void filament_present(const uint8_t extruder) { + static void filament_present(const uint8_t extruder) { runout_count[extruder] = runout_threshold; } }; diff --git a/Marlin/src/feature/solenoid.cpp b/Marlin/src/feature/solenoid.cpp index b6795d1a..cc4522e3 100644 --- a/Marlin/src/feature/solenoid.cpp +++ b/Marlin/src/feature/solenoid.cpp @@ -22,36 +22,30 @@ #include "../inc/MarlinConfig.h" -#if EITHER(EXT_SOLENOID, MANUAL_SOLENOID_CONTROL) +#if ANY(EXT_SOLENOID, MANUAL_SOLENOID_CONTROL) #include "solenoid.h" #include "../module/motion.h" // for active_extruder - -// PARKING_EXTRUDER options alter the default behavior of solenoids, this ensures compliance of M380-381 - -#if ENABLED(PARKING_EXTRUDER) - #include "../module/tool_change.h" -#endif +#include "../module/tool_change.h" // for parking_extruder_set_parked // Used primarily with MANUAL_SOLENOID_CONTROL -static void set_solenoid(const uint8_t num, const bool active) { - const uint8_t value = active ? PE_MAGNET_ON_STATE : !PE_MAGNET_ON_STATE; - #define _SOL_CASE(N) case N: TERN_(HAS_SOLENOID_##N, OUT_WRITE(SOL##N##_PIN, value)); break; +static void set_solenoid(const uint8_t num, const uint8_t state) { + #define _SOL_CASE(N) case N: TERN_(HAS_SOLENOID_##N, OUT_WRITE(SOL##N##_PIN, state)); break; switch (num) { REPEAT(8, _SOL_CASE) default: SERIAL_ECHO_MSG(STR_INVALID_SOLENOID); break; } #if ENABLED(PARKING_EXTRUDER) - if (!active && active_extruder == num) // If active extruder's solenoid is disabled, carriage is considered parked + if (state == LOW && active_extruder == num) // If active extruder's solenoid is disabled, carriage is considered parked parking_extruder_set_parked(true); #endif } -void enable_solenoid(const uint8_t num) { set_solenoid(num, true); } -void disable_solenoid(const uint8_t num) { set_solenoid(num, false); } -void enable_solenoid_on_active_extruder() { } +// PARKING_EXTRUDER options alter the default behavior of solenoids to ensure compliance of M380-381 +void enable_solenoid(const uint8_t num) { set_solenoid(num, TERN1(PARKING_EXTRUDER, PE_MAGNET_ON_STATE)); } +void disable_solenoid(const uint8_t num) { set_solenoid(num, TERN0(PARKING_EXTRUDER, !PE_MAGNET_ON_STATE)); } void disable_all_solenoids() { #define _SOL_DISABLE(N) TERN_(HAS_SOLENOID_##N, disable_solenoid(N)); diff --git a/Marlin/src/feature/solenoid.h b/Marlin/src/feature/solenoid.h index 2ba4983f..3131aeb8 100644 --- a/Marlin/src/feature/solenoid.h +++ b/Marlin/src/feature/solenoid.h @@ -21,7 +21,6 @@ */ #pragma once -void enable_solenoid_on_active_extruder(); void disable_all_solenoids(); void enable_solenoid(const uint8_t num); void disable_solenoid(const uint8_t num); diff --git a/Marlin/src/feature/spindle_laser.cpp b/Marlin/src/feature/spindle_laser.cpp index cde2b47d..b83c1c17 100644 --- a/Marlin/src/feature/spindle_laser.cpp +++ b/Marlin/src/feature/spindle_laser.cpp @@ -35,21 +35,30 @@ #endif #if ENABLED(I2C_AMMETER) - #include "../feature/ammeter.h" + #include "ammeter.h" #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. + 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::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 -#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) /** @@ -57,20 +66,20 @@ cutter_power_t SpindleLaser::menuPower, // Power s */ void SpindleLaser::init() { #if ENABLED(SPINDLE_SERVO) - MOVE_SERVO(SPINDLE_SERVO_NR, SPINDLE_SERVO_MIN); - #else + servo[SPINDLE_SERVO_NR].move(SPINDLE_SERVO_MIN); + #elif PIN_EXISTS(SPINDLE_LASER_ENA) 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); - 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) && defined(SPINDLE_LASER_FREQUENCY) - set_pwm_frequency(pin_t(SPINDLE_LASER_PWM_PIN), SPINDLE_LASER_FREQUENCY); - TERN_(MARLIN_DEV_MODE, frequency = SPINDLE_LASER_FREQUENCY); + hal.set_pwm_duty(pin_t(SPINDLE_LASER_PWM_PIN), SPINDLE_LASER_PWM_OFF); // Set to lowest speed #endif #if ENABLED(AIR_EVACUATION) OUT_WRITE(AIR_EVACUATION_PIN, !AIR_EVACUATION_ACTIVE); // Init Vacuum/Blower OFF @@ -78,9 +87,7 @@ void SpindleLaser::init() { #if ENABLED(AIR_ASSIST) OUT_WRITE(AIR_ASSIST_PIN, !AIR_ASSIST_ACTIVE); // Init Air Assist OFF #endif - #if ENABLED(I2C_AMMETER) - ammeter.init(); // Init I2C Ammeter - #endif + TERN_(I2C_AMMETER, ammeter.init()); // Init I2C Ammeter } #if ENABLED(SPINDLE_LASER_USE_PWM) @@ -90,54 +97,63 @@ void SpindleLaser::init() { * @param ocr Power value */ void SpindleLaser::_set_ocr(const uint8_t ocr) { - #if NEEDS_HARDWARE_PWM && SPINDLE_LASER_FREQUENCY - set_pwm_frequency(pin_t(SPINDLE_LASER_PWM_PIN), TERN(MARLIN_DEV_MODE, frequency, SPINDLE_LASER_FREQUENCY)); + #if ENABLED(HAL_CAN_SET_PWM_FREQ) && SPINDLE_LASER_FREQUENCY + hal.set_pwm_frequency(pin_t(SPINDLE_LASER_PWM_PIN), frequency); #endif - set_pwm_duty(pin_t(SPINDLE_LASER_PWM_PIN), ocr ^ SPINDLE_LASER_PWM_OFF); + hal.set_pwm_duty(pin_t(SPINDLE_LASER_PWM_PIN), ocr ^ SPINDLE_LASER_PWM_OFF); } void SpindleLaser::set_ocr(const uint8_t ocr) { - WRITE(SPINDLE_LASER_ENA_PIN, SPINDLE_LASER_ACTIVE_STATE); // Cutter ON + #if PIN_EXISTS(SPINDLE_LASER_ENA) + WRITE(SPINDLE_LASER_ENA_PIN, SPINDLE_LASER_ACTIVE_STATE); // Cutter ON + #endif _set_ocr(ocr); } void SpindleLaser::ocr_off() { - WRITE(SPINDLE_LASER_ENA_PIN, !SPINDLE_LASER_ACTIVE_STATE); // Cutter OFF + #if PIN_EXISTS(SPINDLE_LASER_ENA) + WRITE(SPINDLE_LASER_ENA_PIN, !SPINDLE_LASER_ACTIVE_STATE); // Cutter OFF + #endif _set_ocr(0); } #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) { - static uint8_t last_power_applied = 0; - 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) + servo[SPINDLE_SERVO_NR].move(opwr); + #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) @@ -161,8 +177,8 @@ void SpindleLaser::apply_power(const uint8_t opwr) { #if ENABLED(AIR_ASSIST) // Enable / disable air assist - void SpindleLaser::air_assist_enable() { WRITE(AIR_ASSIST_PIN, AIR_ASSIST_PIN); } // Turn ON - void SpindleLaser::air_assist_disable() { WRITE(AIR_ASSIST_PIN, !AIR_ASSIST_PIN); } // Turn OFF + void SpindleLaser::air_assist_enable() { WRITE(AIR_ASSIST_PIN, AIR_ASSIST_ACTIVE); } // Turn ON + void SpindleLaser::air_assist_disable() { WRITE(AIR_ASSIST_PIN, !AIR_ASSIST_ACTIVE); } // Turn OFF void SpindleLaser::air_assist_toggle() { TOGGLE(AIR_ASSIST_PIN); } // Toggle state #endif diff --git a/Marlin/src/feature/spindle_laser.h b/Marlin/src/feature/spindle_laser.h index 95d60ae4..a443d7df 100644 --- a/Marlin/src/feature/spindle_laser.h +++ b/Marlin/src/feature/spindle_laser.h @@ -30,90 +30,103 @@ #include "spindle_laser_types.h" -#if USE_BEEPER - #include "../libs/buzzer.h" -#endif +#include "../libs/buzzer.h" -#if ENABLED(LASER_POWER_INLINE) - #include "../module/planner.h" -#endif +// Inline laser power +#include "../module/planner.h" +#define RPM_TO_PWM(X) ((X) * 255 / (SPEED_POWER_MAX)) +#define PWM_TO_RPM(X) ((X) * (SPEED_POWER_MAX) / 255) #define PCT_TO_PWM(X) ((X) * 255 / 100) +#define PWM_TO_PCT(X) ((X) * 100 / 255) #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)) +#define CUTTER_PWM_TO_SPWR(X) (CUTTER_UNIT_IS(PERCENT) ? PWM_TO_PCT(X) : (CUTTER_UNIT_IS(RPM) ? PWM_TO_RPM(X) : X)) + +// 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; - // cpower = configured values (e.g., SPEED_POWER_MAX) + 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 uint8_t power; + 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) - static inline void refresh_frequency() { set_pwm_frequency(pin_t(SPINDLE_LASER_PWM_PIN), frequency); } + #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 inline bool enabled(const cutter_power_t opwr) { return opwr > 0; } - static inline bool enabled() { return enabled(power); } + static bool enabled(const cutter_power_t opwr) { return opwr > 0; } + 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) @@ -124,13 +137,12 @@ class SpindleLaser { public: static void set_ocr(const uint8_t ocr); - static inline void ocr_set_power(const uint8_t ocr) { power = ocr; set_ocr(ocr); } static void ocr_off(); /** * Update output for power->OCR translation */ - static inline uint8_t upower_to_ocr(const cutter_power_t upwr) { + static uint8_t upower_to_ocr(const cutter_power_t upwr) { return uint8_t( #if CUTTER_UNIT_IS(PWM255) upwr @@ -142,205 +154,177 @@ class SpindleLaser { ); } - /** - * Correct power to configured range - */ - static inline cutter_power_t power_to_range(const cutter_power_t pwr) { - return power_to_range(pwr, _CUTTER_POWER(CUTTER_POWER_UNIT)); - } - - static inline 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 inline 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 inline 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. + * + * 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. * - * @param on true = state to on; false = state to off. + * - 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 inline 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(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: + case CUTTER_MODE_DYNAMIC: + TERN_(LASER_FEATURE, set_inline_enabled(enable)); + break; + case CUTTER_MODE_ERROR: // Error mode, no enable and kill power. + enable = false; + apply_power(0); + } + #if PIN_EXISTS(SPINDLE_LASER_ENA) + 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) static void set_reverse(const bool reverse); static bool is_reverse() { return READ(SPINDLE_DIR_PIN) == SPINDLE_INVERT_DIR; } #else - static inline void set_reverse(const bool) {} + static void set_reverse(const bool) {} static bool is_reverse() { return false; } #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 inline 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 inline 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_LCD_MENU - static inline 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 HAS_MARLINUI_MENU + + #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 inline void update_from_mpower() { - if (isReady) power = upower_to_ocr(menuPower); + static void update_from_mpower() { + 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 menu_set_enabled(const bool state) { + set_enabled(state); + if (state) { + if (!menuPower) menuPower = cpwr_to_upwr(SPEED_POWER_STARTUP); + power = TERN(SPINDLE_LASER_USE_PWM, upower_to_ocr(menuPower), 255); + apply_power(power); + } else + apply_power(0); + } + /** * Test fire the laser using the testPulse ms duration * Also fires with any PWM power that was previous set * If not set defaults to 80% power */ - static inline void test_fire_pulse() { - TERN_(USE_BEEPER, buzzer.tone(30, 3000)); - enable_forward(); // Turn Laser on (Spindle speak but same funct) - delay(testPulse); // Delay for time set by user in pulse ms menu screen. - disable(); // Turn laser off + static void test_fire_pulse() { + BUZZ(30, 3000); + cutter_mode = CUTTER_MODE_STANDARD; // Menu needs standard mode. + menu_set_enabled(true); // Laser On + delay(testPulse); // Delay for time set by user in pulse ms menu screen. + menu_set_enabled(false); // Laser Off } - #endif + #endif // LASER_FEATURE - #endif // HAS_LCD_MENU + #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 inline 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 inline 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 inline void inline_direction(const bool) { /* never */ } - - #if ENABLED(SPINDLE_LASER_USE_PWM) - static inline 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 + #endif // LASER_FEATURE - static inline void kill() { - TERN_(LASER_POWER_INLINE, inline_disable()); - disable(); - } + static void kill() { disable(); } }; extern SpindleLaser cutter; diff --git a/Marlin/src/feature/spindle_laser_types.h b/Marlin/src/feature/spindle_laser_types.h index d249a20e..4e5e4d06 100644 --- a/Marlin/src/feature/spindle_laser_types.h +++ b/Marlin/src/feature/spindle_laser_types.h @@ -57,7 +57,7 @@ #endif #endif -typedef IF<(SPEED_POWER_MAX > 255), uint16_t, uint8_t>::type cutter_cpower_t; +typedef uvalue_t(SPEED_POWER_MAX) cutter_cpower_t; #if CUTTER_UNIT_IS(RPM) && SPEED_POWER_MAX > 255 typedef uint16_t cutter_power_t; @@ -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 diff --git a/Marlin/src/feature/stepper_driver_safety.cpp b/Marlin/src/feature/stepper_driver_safety.cpp index 11b90954..d3fc1614 100644 --- a/Marlin/src/feature/stepper_driver_safety.cpp +++ b/Marlin/src/feature/stepper_driver_safety.cpp @@ -43,7 +43,7 @@ void stepper_driver_backward_check() { SET_INPUT(AXIS##_ENABLE_PIN); \ OUT_WRITE(AXIS##_STEP_PIN, false); \ delay(20); \ - if (READ(AXIS##_ENABLE_PIN) == false) { \ + if (READ(AXIS##_ENABLE_PIN) == LOW) { \ SBI(axis_plug_backward, BIT); \ stepper_driver_backward_error(F(STRINGIFY(AXIS))); \ } \ @@ -65,15 +65,18 @@ void stepper_driver_backward_check() { TEST_BACKWARD(I, 8); TEST_BACKWARD(J, 9); TEST_BACKWARD(K, 10); - - TEST_BACKWARD(E0, 11); - TEST_BACKWARD(E1, 12); - TEST_BACKWARD(E2, 13); - TEST_BACKWARD(E3, 14); - TEST_BACKWARD(E4, 15); - TEST_BACKWARD(E5, 16); - TEST_BACKWARD(E6, 17); - TEST_BACKWARD(E7, 18); + TEST_BACKWARD(U, 11); + TEST_BACKWARD(V, 12); + TEST_BACKWARD(W, 13); + + TEST_BACKWARD(E0, 14); + TEST_BACKWARD(E1, 15); + TEST_BACKWARD(E2, 16); + TEST_BACKWARD(E3, 17); + TEST_BACKWARD(E4, 18); + TEST_BACKWARD(E5, 19); + TEST_BACKWARD(E6, 20); + TEST_BACKWARD(E7, 21); if (!axis_plug_backward) WRITE(SAFE_POWER_PIN, HIGH); @@ -103,15 +106,18 @@ void stepper_driver_backward_report() { REPORT_BACKWARD(I, 8); REPORT_BACKWARD(J, 9); REPORT_BACKWARD(K, 10); - - REPORT_BACKWARD(E0, 11); - REPORT_BACKWARD(E1, 12); - REPORT_BACKWARD(E2, 13); - REPORT_BACKWARD(E3, 14); - REPORT_BACKWARD(E4, 15); - REPORT_BACKWARD(E5, 16); - REPORT_BACKWARD(E6, 17); - REPORT_BACKWARD(E7, 18); + REPORT_BACKWARD(U, 11); + REPORT_BACKWARD(V, 12); + REPORT_BACKWARD(W, 13); + + REPORT_BACKWARD(E0, 14); + REPORT_BACKWARD(E1, 15); + REPORT_BACKWARD(E2, 16); + REPORT_BACKWARD(E3, 17); + REPORT_BACKWARD(E4, 18); + REPORT_BACKWARD(E5, 19); + REPORT_BACKWARD(E6, 20); + REPORT_BACKWARD(E7, 21); } #endif // HAS_DRIVER_SAFE_POWER_PROTECT diff --git a/Marlin/src/feature/stepper_driver_safety.h b/Marlin/src/feature/stepper_driver_safety.h index 46edf339..ac3d8b64 100644 --- a/Marlin/src/feature/stepper_driver_safety.h +++ b/Marlin/src/feature/stepper_driver_safety.h @@ -21,7 +21,6 @@ */ #pragma once - #include "../inc/MarlinConfigPre.h" void stepper_driver_backward_check(); diff --git a/Marlin/src/feature/tmc_util.cpp b/Marlin/src/feature/tmc_util.cpp index 82c10e6e..228ab27a 100644 --- a/Marlin/src/feature/tmc_util.cpp +++ b/Marlin/src/feature/tmc_util.cpp @@ -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_LCD_MENU - #include "../module/stepper.h" -#endif - /** * Check for over temperature or short to ground error flags. * Report and log warning of overtemperature condition. @@ -421,16 +416,26 @@ if (monitor_tmc_driver(stepperI, need_update_error_counters, need_debug_reporting)) step_current_down(stepperI); #endif - #if AXIS_IS_TMC(J) if (monitor_tmc_driver(stepperJ, need_update_error_counters, need_debug_reporting)) step_current_down(stepperJ); #endif - #if AXIS_IS_TMC(K) if (monitor_tmc_driver(stepperK, need_update_error_counters, need_debug_reporting)) step_current_down(stepperK); #endif + #if AXIS_IS_TMC(U) + if (monitor_tmc_driver(stepperU, need_update_error_counters, need_debug_reporting)) + step_current_down(stepperU); + #endif + #if AXIS_IS_TMC(V) + if (monitor_tmc_driver(stepperV, need_update_error_counters, need_debug_reporting)) + step_current_down(stepperV); + #endif + #if AXIS_IS_TMC(W) + if (monitor_tmc_driver(stepperW, need_update_error_counters, need_debug_reporting)) + step_current_down(stepperW); + #endif #if AXIS_IS_TMC(E0) (void)monitor_tmc_driver(stepperE0, need_update_error_counters, need_debug_reporting); @@ -472,12 +477,8 @@ void tmc_set_report_interval(const uint16_t update_interval) { if ((report_tmc_status_interval = update_interval)) SERIAL_ECHOLNPGM("axis:pwm_scale" - #if HAS_STEALTHCHOP - "/curr_scale" - #endif - #if HAS_STALLGUARD - "/mech_load" - #endif + TERN_(HAS_STEALTHCHOP, "/curr_scale") + TERN_(HAS_STALLGUARD, "/mech_load") "|flags|warncount" ); } @@ -600,8 +601,8 @@ case TMC_STEALTHCHOP: serialprint_truefalse(st.en_pwm_mode()); break; case TMC_GLOBAL_SCALER: { - uint16_t value = st.GLOBAL_SCALER(); - SERIAL_ECHO(value ? value : 256); + const uint16_t value = st.GLOBAL_SCALER(); + SERIAL_ECHO(value ?: 256); SERIAL_ECHOPGM("/256"); } break; @@ -763,7 +764,7 @@ SERIAL_CHAR('\t'); st.printLabel(); SERIAL_CHAR('\t'); - print_hex_long(drv_status, ':'); + print_hex_long(drv_status, ':', true); if (drv_status == 0xFFFFFFFF || drv_status == 0) SERIAL_ECHOPGM("\t Bad response!"); SERIAL_EOL(); break; @@ -772,8 +773,8 @@ } } - static void tmc_debug_loop(const TMC_debug_enum n, LOGICAL_AXIS_ARGS(const bool)) { - if (x) { + static void tmc_debug_loop(const TMC_debug_enum n OPTARGS_LOGICAL(const bool)) { + if (TERN0(HAS_X_AXIS, x)) { #if AXIS_IS_TMC(X) tmc_status(stepperX, n); #endif @@ -815,6 +816,15 @@ #if AXIS_IS_TMC(K) if (k) tmc_status(stepperK, n); #endif + #if AXIS_IS_TMC(U) + if (u) tmc_status(stepperU, n); + #endif + #if AXIS_IS_TMC(V) + if (v) tmc_status(stepperV, n); + #endif + #if AXIS_IS_TMC(W) + if (w) tmc_status(stepperW, n); + #endif if (TERN0(HAS_EXTRUDERS, e)) { #if AXIS_IS_TMC(E0) @@ -846,8 +856,8 @@ SERIAL_EOL(); } - static void drv_status_loop(const TMC_drv_status_enum n, LOGICAL_AXIS_ARGS(const bool)) { - if (x) { + static void drv_status_loop(const TMC_drv_status_enum n OPTARGS_LOGICAL(const bool)) { + if (TERN0(HAS_X_AXIS, x)) { #if AXIS_IS_TMC(X) tmc_parse_drv_status(stepperX, n); #endif @@ -889,6 +899,15 @@ #if AXIS_IS_TMC(K) if (k) tmc_parse_drv_status(stepperK, n); #endif + #if AXIS_IS_TMC(U) + if (u) tmc_parse_drv_status(stepperU, n); + #endif + #if AXIS_IS_TMC(V) + if (v) tmc_parse_drv_status(stepperV, n); + #endif + #if AXIS_IS_TMC(W) + if (w) tmc_parse_drv_status(stepperW, n); + #endif if (TERN0(HAS_EXTRUDERS, e)) { #if AXIS_IS_TMC(E0) @@ -924,9 +943,9 @@ * M122 report functions */ - void tmc_report_all(LOGICAL_AXIS_ARGS(const bool)) { - #define TMC_REPORT(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); tmc_debug_loop(ITEM, LOGICAL_AXIS_ARGS()); }while(0) - #define DRV_REPORT(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); drv_status_loop(ITEM, LOGICAL_AXIS_ARGS()); }while(0) + void tmc_report_all(LOGICAL_AXIS_ARGS_LC(const bool)) { + #define TMC_REPORT(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); tmc_debug_loop(ITEM OPTARGS_LOGICAL()); }while(0) + #define DRV_REPORT(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); drv_status_loop(ITEM OPTARGS_LOGICAL()); }while(0) TMC_REPORT("\t", TMC_CODES); #if HAS_DRIVER(TMC2209) @@ -1051,8 +1070,8 @@ } #endif - static void tmc_get_registers(TMC_get_registers_enum n, LOGICAL_AXIS_ARGS(const bool)) { - if (x) { + static void tmc_get_registers(TMC_get_registers_enum n OPTARGS_LOGICAL(const bool)) { + if (TERN0(HAS_X_AXIS, x)) { #if AXIS_IS_TMC(X) tmc_get_registers(stepperX, n); #endif @@ -1094,6 +1113,15 @@ #if AXIS_IS_TMC(K) if (k) tmc_get_registers(stepperK, n); #endif + #if AXIS_IS_TMC(U) + if (u) tmc_get_registers(stepperU, n); + #endif + #if AXIS_IS_TMC(V) + if (v) tmc_get_registers(stepperV, n); + #endif + #if AXIS_IS_TMC(W) + if (w) tmc_get_registers(stepperW, n); + #endif if (TERN0(HAS_EXTRUDERS, e)) { #if AXIS_IS_TMC(E0) @@ -1125,8 +1153,8 @@ SERIAL_EOL(); } - void tmc_get_registers(LOGICAL_AXIS_ARGS(bool)) { - #define _TMC_GET_REG(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); tmc_get_registers(ITEM, LOGICAL_AXIS_ARGS()); }while(0) + void tmc_get_registers(LOGICAL_AXIS_ARGS_LC(bool)) { + #define _TMC_GET_REG(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); tmc_get_registers(ITEM OPTARGS_LOGICAL()); }while(0) #define TMC_GET_REG(NAME, TABS) _TMC_GET_REG(STRINGIFY(NAME) TABS, TMC_GET_##NAME) _TMC_GET_REG("\t", TMC_AXIS_CODES); TMC_GET_REG(GCONF, "\t\t"); @@ -1184,69 +1212,6 @@ #endif // USE_SENSORLESS -#if HAS_TMC_SPI - #define SET_CS_PIN(st) OUT_WRITE(st##_CS_PIN, HIGH) - void tmc_init_cs_pins() { - #if AXIS_HAS_SPI(X) - SET_CS_PIN(X); - #endif - #if AXIS_HAS_SPI(Y) - SET_CS_PIN(Y); - #endif - #if AXIS_HAS_SPI(Z) - SET_CS_PIN(Z); - #endif - #if AXIS_HAS_SPI(X2) - SET_CS_PIN(X2); - #endif - #if AXIS_HAS_SPI(Y2) - SET_CS_PIN(Y2); - #endif - #if AXIS_HAS_SPI(Z2) - SET_CS_PIN(Z2); - #endif - #if AXIS_HAS_SPI(Z3) - SET_CS_PIN(Z3); - #endif - #if AXIS_HAS_SPI(Z4) - SET_CS_PIN(Z4); - #endif - #if AXIS_HAS_SPI(I) - SET_CS_PIN(I); - #endif - #if AXIS_HAS_SPI(J) - SET_CS_PIN(J); - #endif - #if AXIS_HAS_SPI(K) - SET_CS_PIN(K); - #endif - #if AXIS_HAS_SPI(E0) - SET_CS_PIN(E0); - #endif - #if AXIS_HAS_SPI(E1) - SET_CS_PIN(E1); - #endif - #if AXIS_HAS_SPI(E2) - SET_CS_PIN(E2); - #endif - #if AXIS_HAS_SPI(E3) - SET_CS_PIN(E3); - #endif - #if AXIS_HAS_SPI(E4) - SET_CS_PIN(E4); - #endif - #if AXIS_HAS_SPI(E5) - SET_CS_PIN(E5); - #endif - #if AXIS_HAS_SPI(E6) - SET_CS_PIN(E6); - #endif - #if AXIS_HAS_SPI(E7) - SET_CS_PIN(E7); - #endif - } -#endif // HAS_TMC_SPI - template static bool test_connection(TMC &st) { SERIAL_ECHOPGM("Testing "); @@ -1268,10 +1233,10 @@ static bool test_connection(TMC &st) { return test_result; } -void test_tmc_connection(LOGICAL_AXIS_ARGS(const bool)) { +void test_tmc_connection(LOGICAL_AXIS_ARGS_LC(const bool)) { uint8_t axis_connection = 0; - if (x) { + if (TERN0(HAS_X_AXIS, x)) { #if AXIS_IS_TMC(X) axis_connection += test_connection(stepperX); #endif @@ -1313,6 +1278,15 @@ void test_tmc_connection(LOGICAL_AXIS_ARGS(const bool)) { #if AXIS_IS_TMC(K) if (k) axis_connection += test_connection(stepperK); #endif + #if AXIS_IS_TMC(U) + if (u) axis_connection += test_connection(stepperU); + #endif + #if AXIS_IS_TMC(V) + if (v) axis_connection += test_connection(stepperV); + #endif + #if AXIS_IS_TMC(W) + if (w) axis_connection += test_connection(stepperW); + #endif if (TERN0(HAS_EXTRUDERS, e)) { #if AXIS_IS_TMC(E0) @@ -1345,3 +1319,75 @@ void test_tmc_connection(LOGICAL_AXIS_ARGS(const bool)) { } #endif // HAS_TRINAMIC_CONFIG + +#if HAS_TMC_SPI + #define SET_CS_PIN(st) OUT_WRITE(st##_CS_PIN, HIGH) + void tmc_init_cs_pins() { + #if AXIS_HAS_SPI(X) + SET_CS_PIN(X); + #endif + #if AXIS_HAS_SPI(Y) + SET_CS_PIN(Y); + #endif + #if AXIS_HAS_SPI(Z) + SET_CS_PIN(Z); + #endif + #if AXIS_HAS_SPI(X2) + SET_CS_PIN(X2); + #endif + #if AXIS_HAS_SPI(Y2) + SET_CS_PIN(Y2); + #endif + #if AXIS_HAS_SPI(Z2) + SET_CS_PIN(Z2); + #endif + #if AXIS_HAS_SPI(Z3) + SET_CS_PIN(Z3); + #endif + #if AXIS_HAS_SPI(Z4) + SET_CS_PIN(Z4); + #endif + #if AXIS_HAS_SPI(I) + SET_CS_PIN(I); + #endif + #if AXIS_HAS_SPI(J) + SET_CS_PIN(J); + #endif + #if AXIS_HAS_SPI(K) + SET_CS_PIN(K); + #endif + #if AXIS_HAS_SPI(U) + SET_CS_PIN(U); + #endif + #if AXIS_HAS_SPI(V) + SET_CS_PIN(V); + #endif + #if AXIS_HAS_SPI(W) + SET_CS_PIN(W); + #endif + #if AXIS_HAS_SPI(E0) + SET_CS_PIN(E0); + #endif + #if AXIS_HAS_SPI(E1) + SET_CS_PIN(E1); + #endif + #if AXIS_HAS_SPI(E2) + SET_CS_PIN(E2); + #endif + #if AXIS_HAS_SPI(E3) + SET_CS_PIN(E3); + #endif + #if AXIS_HAS_SPI(E4) + SET_CS_PIN(E4); + #endif + #if AXIS_HAS_SPI(E5) + SET_CS_PIN(E5); + #endif + #if AXIS_HAS_SPI(E6) + SET_CS_PIN(E6); + #endif + #if AXIS_HAS_SPI(E7) + SET_CS_PIN(E7); + #endif + } +#endif // HAS_TMC_SPI diff --git a/Marlin/src/feature/tmc_util.h b/Marlin/src/feature/tmc_util.h index 1f7d5cf1..b884016b 100644 --- a/Marlin/src/feature/tmc_util.h +++ b/Marlin/src/feature/tmc_util.h @@ -45,6 +45,12 @@ constexpr uint16_t _tmc_thrs(const uint16_t msteps, const uint32_t thrs, const u return 12650000UL * msteps / (256 * thrs * spmm); } +typedef struct { + uint8_t toff; + int8_t hend; + uint8_t hstrt; +} chopper_timing_t; + template class TMCStorage { protected: @@ -58,13 +64,13 @@ class TMCStorage { uint8_t otpw_count = 0, error_count = 0; bool flag_otpw = false; - inline bool getOTPW() { return flag_otpw; } - inline void clear_otpw() { flag_otpw = 0; } + bool getOTPW() { return flag_otpw; } + void clear_otpw() { flag_otpw = 0; } #endif - inline uint16_t getMilliamps() { return val_mA; } + uint16_t getMilliamps() { return val_mA; } - inline void printLabel() { + void printLabel() { SERIAL_CHAR(AXIS_LETTER); if (DRIVER_ID > '0') SERIAL_CHAR(DRIVER_ID); } @@ -91,55 +97,61 @@ class TMCMarlin : public TMC, public TMCStorage { TMCMarlin(const uint16_t CS, const float RS, const uint16_t pinMOSI, const uint16_t pinMISO, const uint16_t pinSCK, const uint8_t axis_chain_index) : TMC(CS, RS, pinMOSI, pinMISO, pinSCK, axis_chain_index) {} - inline uint16_t rms_current() { return TMC::rms_current(); } - inline void rms_current(uint16_t mA) { + uint16_t rms_current() { return TMC::rms_current(); } + void rms_current(uint16_t mA) { this->val_mA = mA; TMC::rms_current(mA); } - inline void rms_current(const uint16_t mA, const float mult) { + void rms_current(const uint16_t mA, const float mult) { this->val_mA = mA; TMC::rms_current(mA, mult); } - inline uint16_t get_microstep_counter() { return TMC::MSCNT(); } + uint16_t get_microstep_counter() { return TMC::MSCNT(); } #if HAS_STEALTHCHOP - inline bool get_stealthChop() { return this->en_pwm_mode(); } - inline bool get_stored_stealthChop() { return this->stored.stealthChop_enabled; } - inline void refresh_stepping_mode() { this->en_pwm_mode(this->stored.stealthChop_enabled); } - inline void set_stealthChop(const bool stch) { this->stored.stealthChop_enabled = stch; refresh_stepping_mode(); } - inline bool toggle_stepping_mode() { set_stealthChop(!this->stored.stealthChop_enabled); return get_stealthChop(); } + bool get_stealthChop() { return this->en_pwm_mode(); } + bool get_stored_stealthChop() { return this->stored.stealthChop_enabled; } + void refresh_stepping_mode() { this->en_pwm_mode(this->stored.stealthChop_enabled); } + void set_stealthChop(const bool stch) { this->stored.stealthChop_enabled = stch; refresh_stepping_mode(); } + bool toggle_stepping_mode() { set_stealthChop(!this->stored.stealthChop_enabled); return get_stealthChop(); } #endif + void set_chopper_times(const chopper_timing_t &ct) { + TMC::toff(ct.toff); + TMC::hysteresis_end(ct.hend); + TMC::hysteresis_start(ct.hstrt); + } + #if ENABLED(HYBRID_THRESHOLD) uint32_t get_pwm_thrs() { return _tmc_thrs(this->microsteps(), this->TPWMTHRS(), planner.settings.axis_steps_per_mm[AXIS_ID]); } void set_pwm_thrs(const uint32_t thrs) { TMC::TPWMTHRS(_tmc_thrs(this->microsteps(), thrs, planner.settings.axis_steps_per_mm[AXIS_ID])); - TERN_(HAS_LCD_MENU, this->stored.hybrid_thrs = thrs); + TERN_(HAS_MARLINUI_MENU, this->stored.hybrid_thrs = thrs); } #endif #if USE_SENSORLESS - inline int16_t homing_threshold() { return TMC::sgt(); } + int16_t homing_threshold() { return TMC::sgt(); } void homing_threshold(int16_t sgt_val) { sgt_val = (int16_t)constrain(sgt_val, sgt_min, sgt_max); TMC::sgt(sgt_val); - TERN_(HAS_LCD_MENU, this->stored.homing_thrs = sgt_val); + TERN_(HAS_MARLINUI_MENU, this->stored.homing_thrs = sgt_val); } #if ENABLED(SPI_ENDSTOPS) bool test_stall_status(); #endif #endif - #if HAS_LCD_MENU - inline void refresh_stepper_current() { rms_current(this->val_mA); } + #if HAS_MARLINUI_MENU + void refresh_stepper_current() { rms_current(this->val_mA); } #if ENABLED(HYBRID_THRESHOLD) - inline void refresh_hybrid_thrs() { set_pwm_thrs(this->stored.hybrid_thrs); } + void refresh_hybrid_thrs() { set_pwm_thrs(this->stored.hybrid_thrs); } #endif #if USE_SENSORLESS - inline void refresh_homing_thrs() { homing_threshold(this->stored.homing_thrs); } + void refresh_homing_thrs() { homing_threshold(this->stored.homing_thrs); } #endif #endif @@ -161,39 +173,45 @@ class TMCMarlin : public TMC220 {} uint16_t rms_current() { return TMC2208Stepper::rms_current(); } - inline void rms_current(const uint16_t mA) { + void rms_current(const uint16_t mA) { this->val_mA = mA; TMC2208Stepper::rms_current(mA); } - inline void rms_current(const uint16_t mA, const float mult) { + void rms_current(const uint16_t mA, const float mult) { this->val_mA = mA; TMC2208Stepper::rms_current(mA, mult); } - inline uint16_t get_microstep_counter() { return TMC2208Stepper::MSCNT(); } + uint16_t get_microstep_counter() { return TMC2208Stepper::MSCNT(); } #if HAS_STEALTHCHOP - inline bool get_stealthChop() { return !this->en_spreadCycle(); } - inline bool get_stored_stealthChop() { return this->stored.stealthChop_enabled; } - inline void refresh_stepping_mode() { this->en_spreadCycle(!this->stored.stealthChop_enabled); } - inline void set_stealthChop(const bool stch) { this->stored.stealthChop_enabled = stch; refresh_stepping_mode(); } - inline bool toggle_stepping_mode() { set_stealthChop(!this->stored.stealthChop_enabled); return get_stealthChop(); } + bool get_stealthChop() { return !this->en_spreadCycle(); } + bool get_stored_stealthChop() { return this->stored.stealthChop_enabled; } + void refresh_stepping_mode() { this->en_spreadCycle(!this->stored.stealthChop_enabled); } + void set_stealthChop(const bool stch) { this->stored.stealthChop_enabled = stch; refresh_stepping_mode(); } + bool toggle_stepping_mode() { set_stealthChop(!this->stored.stealthChop_enabled); return get_stealthChop(); } #endif + void set_chopper_times(const chopper_timing_t &ct) { + TMC2208Stepper::toff(ct.toff); + TMC2208Stepper::hysteresis_end(ct.hend); + TMC2208Stepper::hysteresis_start(ct.hstrt); + } + #if ENABLED(HYBRID_THRESHOLD) uint32_t get_pwm_thrs() { return _tmc_thrs(this->microsteps(), this->TPWMTHRS(), planner.settings.axis_steps_per_mm[AXIS_ID]); } void set_pwm_thrs(const uint32_t thrs) { TMC2208Stepper::TPWMTHRS(_tmc_thrs(this->microsteps(), thrs, planner.settings.axis_steps_per_mm[AXIS_ID])); - TERN_(HAS_LCD_MENU, this->stored.hybrid_thrs = thrs); + TERN_(HAS_MARLINUI_MENU, this->stored.hybrid_thrs = thrs); } #endif - #if HAS_LCD_MENU - inline void refresh_stepper_current() { rms_current(this->val_mA); } + #if HAS_MARLINUI_MENU + void refresh_stepper_current() { rms_current(this->val_mA); } #if ENABLED(HYBRID_THRESHOLD) - inline void refresh_hybrid_thrs() { set_pwm_thrs(this->stored.hybrid_thrs); } + void refresh_hybrid_thrs() { set_pwm_thrs(this->stored.hybrid_thrs); } #endif #endif }; @@ -209,50 +227,56 @@ class TMCMarlin : public TMC220 {} uint8_t get_address() { return slave_address; } uint16_t rms_current() { return TMC2209Stepper::rms_current(); } - inline void rms_current(const uint16_t mA) { + void rms_current(const uint16_t mA) { this->val_mA = mA; TMC2209Stepper::rms_current(mA); } - inline void rms_current(const uint16_t mA, const float mult) { + void rms_current(const uint16_t mA, const float mult) { this->val_mA = mA; TMC2209Stepper::rms_current(mA, mult); } - inline uint16_t get_microstep_counter() { return TMC2209Stepper::MSCNT(); } + uint16_t get_microstep_counter() { return TMC2209Stepper::MSCNT(); } #if HAS_STEALTHCHOP - inline bool get_stealthChop() { return !this->en_spreadCycle(); } - inline bool get_stored_stealthChop() { return this->stored.stealthChop_enabled; } - inline void refresh_stepping_mode() { this->en_spreadCycle(!this->stored.stealthChop_enabled); } - inline void set_stealthChop(const bool stch) { this->stored.stealthChop_enabled = stch; refresh_stepping_mode(); } - inline bool toggle_stepping_mode() { set_stealthChop(!this->stored.stealthChop_enabled); return get_stealthChop(); } + bool get_stealthChop() { return !this->en_spreadCycle(); } + bool get_stored_stealthChop() { return this->stored.stealthChop_enabled; } + void refresh_stepping_mode() { this->en_spreadCycle(!this->stored.stealthChop_enabled); } + void set_stealthChop(const bool stch) { this->stored.stealthChop_enabled = stch; refresh_stepping_mode(); } + bool toggle_stepping_mode() { set_stealthChop(!this->stored.stealthChop_enabled); return get_stealthChop(); } #endif + void set_chopper_times(const chopper_timing_t &ct) { + TMC2209Stepper::toff(ct.toff); + TMC2209Stepper::hysteresis_end(ct.hend); + TMC2209Stepper::hysteresis_start(ct.hstrt); + } + #if ENABLED(HYBRID_THRESHOLD) uint32_t get_pwm_thrs() { return _tmc_thrs(this->microsteps(), this->TPWMTHRS(), planner.settings.axis_steps_per_mm[AXIS_ID]); } void set_pwm_thrs(const uint32_t thrs) { TMC2209Stepper::TPWMTHRS(_tmc_thrs(this->microsteps(), thrs, planner.settings.axis_steps_per_mm[AXIS_ID])); - TERN_(HAS_LCD_MENU, this->stored.hybrid_thrs = thrs); + TERN_(HAS_MARLINUI_MENU, this->stored.hybrid_thrs = thrs); } #endif #if USE_SENSORLESS - inline int16_t homing_threshold() { return TMC2209Stepper::SGTHRS(); } + int16_t homing_threshold() { return TMC2209Stepper::SGTHRS(); } void homing_threshold(int16_t sgt_val) { sgt_val = (int16_t)constrain(sgt_val, sgt_min, sgt_max); TMC2209Stepper::SGTHRS(sgt_val); - TERN_(HAS_LCD_MENU, this->stored.homing_thrs = sgt_val); + TERN_(HAS_MARLINUI_MENU, this->stored.homing_thrs = sgt_val); } #endif - #if HAS_LCD_MENU - inline void refresh_stepper_current() { rms_current(this->val_mA); } + #if HAS_MARLINUI_MENU + void refresh_stepper_current() { rms_current(this->val_mA); } #if ENABLED(HYBRID_THRESHOLD) - inline void refresh_hybrid_thrs() { set_pwm_thrs(this->stored.hybrid_thrs); } + void refresh_hybrid_thrs() { set_pwm_thrs(this->stored.hybrid_thrs); } #endif #if USE_SENSORLESS - inline void refresh_homing_thrs() { homing_threshold(this->stored.homing_thrs); } + void refresh_homing_thrs() { homing_threshold(this->stored.homing_thrs); } #endif #endif @@ -269,27 +293,33 @@ class TMCMarlin : public TMC266 TMCMarlin(const uint16_t CS, const float RS, const uint16_t pinMOSI, const uint16_t pinMISO, const uint16_t pinSCK, const uint8_t) : TMC2660Stepper(CS, RS, pinMOSI, pinMISO, pinSCK) {} - inline uint16_t rms_current() { return TMC2660Stepper::rms_current(); } - inline void rms_current(const uint16_t mA) { + uint16_t rms_current() { return TMC2660Stepper::rms_current(); } + void rms_current(const uint16_t mA) { this->val_mA = mA; TMC2660Stepper::rms_current(mA); } - inline uint16_t get_microstep_counter() { return TMC2660Stepper::mstep(); } + uint16_t get_microstep_counter() { return TMC2660Stepper::mstep(); } + + void set_chopper_times(const chopper_timing_t &ct) { + TMC2660Stepper::toff(ct.toff); + TMC2660Stepper::hysteresis_end(ct.hend); + TMC2660Stepper::hysteresis_start(ct.hstrt); + } #if USE_SENSORLESS - inline int16_t homing_threshold() { return TMC2660Stepper::sgt(); } + int16_t homing_threshold() { return TMC2660Stepper::sgt(); } void homing_threshold(int16_t sgt_val) { sgt_val = (int16_t)constrain(sgt_val, sgt_min, sgt_max); TMC2660Stepper::sgt(sgt_val); - TERN_(HAS_LCD_MENU, this->stored.homing_thrs = sgt_val); + TERN_(HAS_MARLINUI_MENU, this->stored.homing_thrs = sgt_val); } #endif - #if HAS_LCD_MENU - inline void refresh_stepper_current() { rms_current(this->val_mA); } + #if HAS_MARLINUI_MENU + void refresh_stepper_current() { rms_current(this->val_mA); } #if USE_SENSORLESS - inline void refresh_homing_thrs() { homing_threshold(this->stored.homing_thrs); } + void refresh_homing_thrs() { homing_threshold(this->stored.homing_thrs); } #endif #endif @@ -297,43 +327,6 @@ class TMCMarlin : public TMC266 sgt_max = 63; }; -template -void tmc_print_current(TMC &st) { - st.printLabel(); - SERIAL_ECHOLNPGM(" driver current: ", st.getMilliamps()); -} - -#if ENABLED(MONITOR_DRIVER_STATUS) - template - void tmc_report_otpw(TMC &st) { - st.printLabel(); - SERIAL_ECHOPGM(" temperature prewarn triggered: "); - serialprint_truefalse(st.getOTPW()); - SERIAL_EOL(); - } - template - void tmc_clear_otpw(TMC &st) { - st.clear_otpw(); - st.printLabel(); - SERIAL_ECHOLNPGM(" prewarn flag cleared"); - } -#endif -#if ENABLED(HYBRID_THRESHOLD) - template - void tmc_print_pwmthrs(TMC &st) { - st.printLabel(); - SERIAL_ECHOLNPGM(" stealthChop max speed: ", st.get_pwm_thrs()); - } -#endif -#if USE_SENSORLESS - template - void tmc_print_sgt(TMC &st) { - st.printLabel(); - SERIAL_ECHOPGM(" homing sensitivity: "); - SERIAL_PRINTLN(st.homing_threshold(), PrintBase::Dec); - } -#endif - void monitor_tmc_drivers(); void test_tmc_connection(LOGICAL_AXIS_DECL(const bool, true)); @@ -342,7 +335,7 @@ void test_tmc_connection(LOGICAL_AXIS_DECL(const bool, true)); void tmc_set_report_interval(const uint16_t update_interval); #endif void tmc_report_all(LOGICAL_AXIS_DECL(const bool, true)); - void tmc_get_registers(LOGICAL_AXIS_ARGS(const bool)); + void tmc_get_registers(LOGICAL_AXIS_ARGS_LC(const bool)); #endif /** @@ -355,7 +348,7 @@ void test_tmc_connection(LOGICAL_AXIS_DECL(const bool, true)); #if USE_SENSORLESS // Track enabled status of stealthChop and only re-enable where applicable - struct sensorless_t { bool LINEAR_AXIS_ARGS(), x2, y2, z2, z3, z4; }; + struct sensorless_t { bool NUM_AXIS_ARGS_() x2, y2, z2, z3, z4; }; #if ENABLED(IMPROVE_HOMING_RELIABILITY) extern millis_t sg_guard_period; @@ -385,12 +378,13 @@ void test_tmc_connection(LOGICAL_AXIS_DECL(const bool, true)); return drv_status.stallGuard; } + #endif // SPI_ENDSTOPS #endif // USE_SENSORLESS +#endif // HAS_TRINAMIC_CONFIG + #if HAS_TMC_SPI void tmc_init_cs_pins(); #endif - -#endif // HAS_TRINAMIC_CONFIG diff --git a/Marlin/src/feature/tramming.cpp b/Marlin/src/feature/tramming.cpp index d03f0cf5..3721c5eb 100644 --- a/Marlin/src/feature/tramming.cpp +++ b/Marlin/src/feature/tramming.cpp @@ -29,31 +29,11 @@ #define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE) #include "../core/debug_out.h" -PGMSTR(point_name_1, TRAMMING_POINT_NAME_1); -PGMSTR(point_name_2, TRAMMING_POINT_NAME_2); -PGMSTR(point_name_3, TRAMMING_POINT_NAME_3); -#ifdef TRAMMING_POINT_NAME_4 - PGMSTR(point_name_4, TRAMMING_POINT_NAME_4); - #ifdef TRAMMING_POINT_NAME_5 - PGMSTR(point_name_5, TRAMMING_POINT_NAME_5); - #ifdef TRAMMING_POINT_NAME_6 - PGMSTR(point_name_6, TRAMMING_POINT_NAME_6); - #endif - #endif -#endif +#define _TRAM_NAME_DEF(N) PGMSTR(point_name_##N, TRAMMING_POINT_NAME_##N); +#define _TRAM_NAME_ITEM(N) point_name_##N +REPEAT_1(_NR_TRAM_NAMES, _TRAM_NAME_DEF) -PGM_P const tramming_point_name[] PROGMEM = { - point_name_1, point_name_2, point_name_3 - #ifdef TRAMMING_POINT_NAME_4 - , point_name_4 - #ifdef TRAMMING_POINT_NAME_5 - , point_name_5 - #ifdef TRAMMING_POINT_NAME_6 - , point_name_6 - #endif - #endif - #endif -}; +PGM_P const tramming_point_name[] PROGMEM = { REPLIST_1(_NR_TRAM_NAMES, _TRAM_NAME_ITEM) }; #ifdef ASSISTED_TRAMMING_WAIT_POSITION diff --git a/Marlin/src/feature/tramming.h b/Marlin/src/feature/tramming.h index 925659e2..c8f20f00 100644 --- a/Marlin/src/feature/tramming.h +++ b/Marlin/src/feature/tramming.h @@ -31,43 +31,34 @@ constexpr xy_pos_t tramming_points[] = TRAMMING_POINT_XY; #define G35_PROBE_COUNT COUNT(tramming_points) -static_assert(WITHIN(G35_PROBE_COUNT, 3, 6), "TRAMMING_POINT_XY requires between 3 and 6 XY positions."); +static_assert(WITHIN(G35_PROBE_COUNT, 3, 9), "TRAMMING_POINT_XY requires between 3 and 9 XY positions."); -#define VALIDATE_TRAMMING_POINT(N) static_assert(N >= G35_PROBE_COUNT || Probe::build_time::can_reach(tramming_points[N]), \ - "TRAMMING_POINT_XY point " STRINGIFY(N) " is not reachable with the default NOZZLE_TO_PROBE offset and PROBING_MARGIN.") -VALIDATE_TRAMMING_POINT(0); VALIDATE_TRAMMING_POINT(1); VALIDATE_TRAMMING_POINT(2); VALIDATE_TRAMMING_POINT(3); VALIDATE_TRAMMING_POINT(4); VALIDATE_TRAMMING_POINT(5); - -extern const char point_name_1[], point_name_2[], point_name_3[] - #ifdef TRAMMING_POINT_NAME_4 - , point_name_4[] - #ifdef TRAMMING_POINT_NAME_5 - , point_name_5[] - #ifdef TRAMMING_POINT_NAME_6 - , point_name_6[] - #endif - #endif - #endif -; - -#define _NR_TRAM_NAMES 2 -#ifdef TRAMMING_POINT_NAME_3 - #undef _NR_TRAM_NAMES +#ifdef TRAMMING_POINT_NAME_9 + #define _NR_TRAM_NAMES 9 +#elif defined(TRAMMING_POINT_NAME_8) + #define _NR_TRAM_NAMES 8 +#elif defined(TRAMMING_POINT_NAME_7) + #define _NR_TRAM_NAMES 7 +#elif defined(TRAMMING_POINT_NAME_6) + #define _NR_TRAM_NAMES 6 +#elif defined(TRAMMING_POINT_NAME_5) + #define _NR_TRAM_NAMES 5 +#elif defined(TRAMMING_POINT_NAME_4) + #define _NR_TRAM_NAMES 4 +#elif defined(TRAMMING_POINT_NAME_3) #define _NR_TRAM_NAMES 3 - #ifdef TRAMMING_POINT_NAME_4 - #undef _NR_TRAM_NAMES - #define _NR_TRAM_NAMES 4 - #ifdef TRAMMING_POINT_NAME_5 - #undef _NR_TRAM_NAMES - #define _NR_TRAM_NAMES 5 - #ifdef TRAMMING_POINT_NAME_6 - #undef _NR_TRAM_NAMES - #define _NR_TRAM_NAMES 6 - #endif - #endif - #endif +#else + #define _NR_TRAM_NAMES 0 #endif + static_assert(_NR_TRAM_NAMES >= G35_PROBE_COUNT, "Define enough TRAMMING_POINT_NAME_s for all TRAMMING_POINT_XY entries."); -#undef _NR_TRAM_NAMES + +#define _TRAM_NAME_PTR(N) point_name_##N[] +extern const char REPLIST_1(_NR_TRAM_NAMES, _TRAM_NAME_PTR); + +#define _CHECK_TRAM_POINT(N) static_assert(Probe::build_time::can_reach(tramming_points[N]), "TRAMMING_POINT_XY point " STRINGIFY(N) " is not reachable with the default NOZZLE_TO_PROBE offset and PROBING_MARGIN."); +REPEAT(_NR_TRAM_NAMES, _CHECK_TRAM_POINT) +#undef _CHECK_TRAM_POINT extern PGM_P const tramming_point_name[]; diff --git a/Marlin/src/feature/twibus.cpp b/Marlin/src/feature/twibus.cpp index 9aec6b03..4aedb4b5 100644 --- a/Marlin/src/feature/twibus.cpp +++ b/Marlin/src/feature/twibus.cpp @@ -145,7 +145,7 @@ void TWIBus::echodata(uint8_t bytes, FSTR_P const pref, uint8_t adr, const uint8 void TWIBus::echobuffer(FSTR_P const prefix, uint8_t adr) { echoprefix(buffer_s, prefix, adr); - LOOP_L_N(i, buffer_s) SERIAL_CHAR(buffer[i]); + for (uint8_t i = 0; i < buffer_s; ++i) SERIAL_CHAR(buffer[i]); SERIAL_EOL(); } diff --git a/Marlin/src/feature/twibus.h b/Marlin/src/feature/twibus.h index d2c72703..de23abbe 100644 --- a/Marlin/src/feature/twibus.h +++ b/Marlin/src/feature/twibus.h @@ -74,7 +74,6 @@ class TWIBus { */ uint8_t buffer[TWIBUS_BUFFER_SIZE]; - public: /** * @brief Target device address @@ -244,11 +243,11 @@ class TWIBus { static void debug(FSTR_P const func, char c); static void debug(FSTR_P const func, char adr[]); #else - static inline void debug(FSTR_P const, uint32_t) {} - static inline void debug(FSTR_P const, char) {} - static inline void debug(FSTR_P const, char[]) {} + static void debug(FSTR_P const, uint32_t) {} + static void debug(FSTR_P const, char) {} + static void debug(FSTR_P const, char[]) {} #endif - static inline void debug(FSTR_P const func, uint8_t v) { debug(func, (uint32_t)v); } + static void debug(FSTR_P const func, uint8_t v) { debug(func, (uint32_t)v); } }; extern TWIBus i2c; diff --git a/Marlin/src/feature/bedlevel/abl/x_twist.cpp b/Marlin/src/feature/x_twist.cpp similarity index 61% rename from Marlin/src/feature/bedlevel/abl/x_twist.cpp rename to Marlin/src/feature/x_twist.cpp index c4a62c35..2b792470 100644 --- a/Marlin/src/feature/bedlevel/abl/x_twist.cpp +++ b/Marlin/src/feature/x_twist.cpp @@ -19,29 +19,36 @@ * along with this program. If not, see . * */ -#include "../../../inc/MarlinConfig.h" +#include "../inc/MarlinConfig.h" #if ENABLED(X_AXIS_TWIST_COMPENSATION) -#include "../bedlevel.h" +#include "x_twist.h" +#include "../module/probe.h" XATC xatc; +bool XATC::enabled; float XATC::spacing, XATC::start; -xatc_points_t XATC::z_values; +xatc_array_t XATC::z_offset; // Initialized by settings.load + +void XATC::reset() { + constexpr float xzo[] = XATC_Z_OFFSETS; + static_assert(COUNT(xzo) == XATC_MAX_POINTS, "XATC_Z_OFFSETS is the wrong size."); + COPY(z_offset, xzo); + start = probe.min_x(); + spacing = (probe.max_x() - start) / (XATC_MAX_POINTS - 1); + enabled = true; +} void XATC::print_points() { SERIAL_ECHOLNPGM(" X-Twist Correction:"); - LOOP_L_N(x, XATC_MAX_POINTS) { + for (uint8_t x = 0; x < XATC_MAX_POINTS; ++x) { SERIAL_CHAR(' '); - if (!isnan(z_values[x])) { - if (z_values[x] >= 0) SERIAL_CHAR('+'); - SERIAL_ECHO_F(z_values[x], 3); - } - else { - LOOP_L_N(i, 6) - SERIAL_CHAR(i ? '=' : ' '); - } + if (!isnan(z_offset[x])) + serial_offset(z_offset[x]); + else + for (uint8_t i = 0; i < 6; ++i) SERIAL_CHAR(i ? '=' : ' '); } SERIAL_EOL(); } @@ -49,11 +56,12 @@ void XATC::print_points() { float lerp(const_float_t t, const_float_t a, const_float_t b) { return a + t * (b - a); } float XATC::compensation(const xy_pos_t &raw) { + if (!enabled) return 0; + if (NEAR_ZERO(spacing)) return 0; float t = (raw.x - start) / spacing; - int i = FLOOR(t); - LIMIT(i, 0, XATC_MAX_POINTS - 2); + const int i = constrain(FLOOR(t), 0, XATC_MAX_POINTS - 2); t -= i; - return lerp(t, z_values[i], z_values[i + 1]); + return lerp(t, z_offset[i], z_offset[i + 1]); } #endif // X_AXIS_TWIST_COMPENSATION diff --git a/Marlin/src/feature/bedlevel/abl/x_twist.h b/Marlin/src/feature/x_twist.h similarity index 82% rename from Marlin/src/feature/bedlevel/abl/x_twist.h rename to Marlin/src/feature/x_twist.h index bbad9e73..6a2ff279 100644 --- a/Marlin/src/feature/bedlevel/abl/x_twist.h +++ b/Marlin/src/feature/x_twist.h @@ -21,15 +21,18 @@ */ #pragma once -#include "../../../inc/MarlinConfigPre.h" +#include "../inc/MarlinConfigPre.h" -typedef float xatc_points_t[XATC_MAX_POINTS]; +typedef float xatc_array_t[XATC_MAX_POINTS]; class XATC { + static bool enabled; public: static float spacing, start; - static xatc_points_t z_values; + static xatc_array_t z_offset; + static void reset(); + static void set_enabled(const bool ena) { enabled = ena; } static float compensation(const xy_pos_t &raw); static void print_points(); }; diff --git a/Marlin/src/feature/z_stepper_align.cpp b/Marlin/src/feature/z_stepper_align.cpp index 1b4eb447..9dba21d8 100644 --- a/Marlin/src/feature/z_stepper_align.cpp +++ b/Marlin/src/feature/z_stepper_align.cpp @@ -33,35 +33,35 @@ ZStepperAlign z_stepper_align; -xy_pos_t ZStepperAlign::xy[NUM_Z_STEPPER_DRIVERS]; +xy_pos_t ZStepperAlign::xy[NUM_Z_STEPPERS]; -#if ENABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS) - xy_pos_t ZStepperAlign::stepper_xy[NUM_Z_STEPPER_DRIVERS]; +#if HAS_Z_STEPPER_ALIGN_STEPPER_XY + xy_pos_t ZStepperAlign::stepper_xy[NUM_Z_STEPPERS]; #endif void ZStepperAlign::reset_to_default() { #ifdef Z_STEPPER_ALIGN_XY constexpr xy_pos_t xy_init[] = Z_STEPPER_ALIGN_XY; - static_assert(COUNT(xy_init) == NUM_Z_STEPPER_DRIVERS, + static_assert(COUNT(xy_init) == NUM_Z_STEPPERS, "Z_STEPPER_ALIGN_XY requires " - #if NUM_Z_STEPPER_DRIVERS == 4 + #if NUM_Z_STEPPERS == 4 "four {X,Y} entries (Z, Z2, Z3, and Z4)." - #elif NUM_Z_STEPPER_DRIVERS == 3 + #elif NUM_Z_STEPPERS == 3 "three {X,Y} entries (Z, Z2, and Z3)." #else "two {X,Y} entries (Z and Z2)." #endif ); - #define VALIDATE_ALIGN_POINT(N) static_assert(N >= NUM_Z_STEPPER_DRIVERS || Probe::build_time::can_reach(xy_init[N]), \ + #define VALIDATE_ALIGN_POINT(N) static_assert(N >= NUM_Z_STEPPERS || Probe::build_time::can_reach(xy_init[N]), \ "Z_STEPPER_ALIGN_XY point " STRINGIFY(N) " is not reachable with the default NOZZLE_TO_PROBE offset and PROBING_MARGIN.") VALIDATE_ALIGN_POINT(0); VALIDATE_ALIGN_POINT(1); VALIDATE_ALIGN_POINT(2); VALIDATE_ALIGN_POINT(3); #else // !Z_STEPPER_ALIGN_XY const xy_pos_t xy_init[] = { - #if NUM_Z_STEPPER_DRIVERS >= 3 // First probe point... + #if NUM_Z_STEPPERS >= 3 // First probe point... #if !Z_STEPPERS_ORIENTATION { probe.min_x(), probe.min_y() }, // SW #elif Z_STEPPERS_ORIENTATION == 1 @@ -73,7 +73,7 @@ void ZStepperAlign::reset_to_default() { #else #error "Z_STEPPERS_ORIENTATION must be from 0 to 3 (first point SW, NW, NE, SE)." #endif - #if NUM_Z_STEPPER_DRIVERS == 4 // 3 more points... + #if NUM_Z_STEPPERS == 4 // 3 more points... #if !Z_STEPPERS_ORIENTATION { probe.min_x(), probe.max_y() }, { probe.max_x(), probe.max_y() }, { probe.max_x(), probe.min_y() } // SW #elif Z_STEPPERS_ORIENTATION == 1 @@ -103,14 +103,14 @@ void ZStepperAlign::reset_to_default() { COPY(xy, xy_init); - #if ENABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS) + #if HAS_Z_STEPPER_ALIGN_STEPPER_XY constexpr xy_pos_t stepper_xy_init[] = Z_STEPPER_ALIGN_STEPPER_XY; static_assert( - COUNT(stepper_xy_init) == NUM_Z_STEPPER_DRIVERS, + COUNT(stepper_xy_init) == NUM_Z_STEPPERS, "Z_STEPPER_ALIGN_STEPPER_XY requires " - #if NUM_Z_STEPPER_DRIVERS == 4 + #if NUM_Z_STEPPERS == 4 "four {X,Y} entries (Z, Z2, Z3, and Z4)." - #elif NUM_Z_STEPPER_DRIVERS == 3 + #elif NUM_Z_STEPPERS == 3 "three {X,Y} entries (Z, Z2, and Z3)." #endif ); diff --git a/Marlin/src/feature/z_stepper_align.h b/Marlin/src/feature/z_stepper_align.h index e1b235b5..f3f9abb8 100644 --- a/Marlin/src/feature/z_stepper_align.h +++ b/Marlin/src/feature/z_stepper_align.h @@ -29,10 +29,10 @@ class ZStepperAlign { public: - static xy_pos_t xy[NUM_Z_STEPPER_DRIVERS]; + static xy_pos_t xy[NUM_Z_STEPPERS]; - #if ENABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS) - static xy_pos_t stepper_xy[NUM_Z_STEPPER_DRIVERS]; + #if HAS_Z_STEPPER_ALIGN_STEPPER_XY + static xy_pos_t stepper_xy[NUM_Z_STEPPERS]; #endif static void reset_to_default(); diff --git a/Marlin/src/gcode/bedlevel/G26.cpp b/Marlin/src/gcode/bedlevel/G26.cpp index 728771d5..209ae4a2 100644 --- a/Marlin/src/gcode/bedlevel/G26.cpp +++ b/Marlin/src/gcode/bedlevel/G26.cpp @@ -58,10 +58,10 @@ * * L # Layer Layer height. (Height of nozzle above bed) If not specified .20mm will be used. * - * O # Ooooze How much your nozzle will Ooooze filament while getting in position to print. This - * is over kill, but using this parameter will let you get the very first 'circle' perfect - * so you have a trophy to peel off of the bed and hang up to show how perfectly you have your - * Mesh calibrated. If not specified, a filament length of .3mm is assumed. + * O # Ooze How much your nozzle will Ooooze filament while getting in position to print. If not + * specified, a filament length of .3mm is assumed. This might be overkill, but this + * parameter ensures the very first 'circle' is perfect (providing an ideal trophy to hang + * up to show off your perfectly calibrated Mesh). * * P # Prime Prime the nozzle with specified length of filament. If this parameter is not * given, no prime action will take place. If the parameter specifies an amount, that much @@ -71,8 +71,8 @@ * pliers while holding the LCD Click wheel in a depressed state. If you do not have * an LCD, you must specify a value if you use P. * - * Q # Multiplier Retraction Multiplier. Normally not needed. Retraction defaults to 1.0mm and - * un-retraction is at 1.2mm These numbers will be scaled by the specified amount + * Q # Multiplier Retraction Multiplier. (Normally not needed.) During G26 retraction will use the length + * specified by this parameter (1mm by default). Recover will be 1.2x the retract distance. * * R # Repeat Prints the number of patterns given as a parameter, starting at the current location. * If a parameter isn't given, every point will be printed unless G26 is interrupted. @@ -102,12 +102,11 @@ #define G26_OK false #define G26_ERR true -#include "../../gcode/gcode.h" +#include "../gcode.h" #include "../../feature/bedlevel/bedlevel.h" #include "../../MarlinCore.h" #include "../../module/planner.h" -#include "../../module/stepper.h" #include "../../module/motion.h" #include "../../module/tool_change.h" #include "../../module/temperature.h" @@ -156,15 +155,15 @@ constexpr float g26_e_axis_feedrate = 0.025; static MeshFlags circle_flags; float g26_random_deviation = 0.0; -#if HAS_LCD_MENU +#if HAS_MARLINUI_MENU /** * If the LCD is clicked, cancel, wait for release, return true */ bool user_canceled() { if (!ui.button_pressed()) return false; // Return if the button isn't pressed - ui.set_status(GET_TEXT_F(MSG_G26_CANCELED), 99); - TERN_(HAS_LCD_MENU, ui.quick_feedback()); + LCD_MESSAGE_MAX(MSG_G26_CANCELED); + ui.quick_feedback(); ui.wait_for_release(); return true; } @@ -293,10 +292,10 @@ typedef struct { if (circle_flags.marked(p1.x, p1.y) && circle_flags.marked(p2.x, p2.y)) { xyz_pos_t s, e; - s.x = _GET_MESH_X(p1.x) + (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)) * dx; - e.x = _GET_MESH_X(p2.x) - (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)) * dx; - s.y = _GET_MESH_Y(p1.y) + (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)) * dy; - e.y = _GET_MESH_Y(p2.y) - (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)) * dy; + s.x = bedlevel.get_mesh_x(p1.x) + (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)) * dx; + e.x = bedlevel.get_mesh_x(p2.x) - (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)) * dx; + s.y = bedlevel.get_mesh_y(p1.y) + (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)) * dy; + e.y = bedlevel.get_mesh_y(p2.y) - (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)) * dy; s.z = e.z = layer_height; #if HAS_ENDSTOPS @@ -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); } } @@ -322,11 +321,9 @@ typedef struct { #if HAS_HEATED_BED if (bed_temp > 25) { - #if HAS_WIRED_LCD - ui.set_status(GET_TEXT_F(MSG_G26_HEATING_BED), 99); - ui.quick_feedback(); - TERN_(HAS_LCD_MENU, ui.capture()); - #endif + LCD_MESSAGE_MAX(MSG_G26_HEATING_BED); + ui.quick_feedback(); + TERN_(HAS_MARLINUI_MENU, ui.capture()); thermalManager.setTargetBed(bed_temp); // Wait for the temperature to stabilize @@ -341,20 +338,16 @@ typedef struct { #endif // HAS_HEATED_BED // Start heating the active nozzle - #if HAS_WIRED_LCD - ui.set_status(GET_TEXT_F(MSG_G26_HEATING_NOZZLE), 99); - ui.quick_feedback(); - #endif + LCD_MESSAGE_MAX(MSG_G26_HEATING_NOZZLE); + ui.quick_feedback(); thermalManager.setTargetHotend(hotend_temp, active_extruder); // Wait for the temperature to stabilize if (!thermalManager.wait_for_hotend(active_extruder, true OPTARG(G26_CLICK_CAN_CANCEL, true))) return G26_ERR; - #if HAS_WIRED_LCD - ui.reset_status(); - ui.quick_feedback(); - #endif + ui.reset_status(); + ui.completion_feedback(); return G26_OK; } @@ -365,14 +358,14 @@ typedef struct { bool prime_nozzle() { const feedRate_t fr_slow_e = planner.settings.max_feedrate_mm_s[E_AXIS] / 15.0f; - #if HAS_LCD_MENU && !HAS_TOUCH_BUTTONS // ui.button_pressed issue with touchscreen + #if HAS_MARLINUI_MENU && !HAS_TOUCH_BUTTONS // ui.button_pressed issue with touchscreen #if ENABLED(PREVENT_LENGTHY_EXTRUDE) float Total_Prime = 0.0; #endif if (prime_flag == -1) { // The user wants to control how much filament gets purged ui.capture(); - ui.set_status(GET_TEXT_F(MSG_G26_MANUAL_PRIME), 99); + LCD_MESSAGE_MAX(MSG_G26_MANUAL_PRIME); ui.chirp(); destination = current_position; @@ -399,17 +392,15 @@ typedef struct { ui.wait_for_release(); - ui.set_status(GET_TEXT_F(MSG_G26_PRIME_DONE), 99); + LCD_MESSAGE_MAX(MSG_G26_PRIME_DONE); ui.quick_feedback(); ui.release(); } else #endif { - #if HAS_WIRED_LCD - ui.set_status(GET_TEXT_F(MSG_G26_FIXED_LENGTH), 99); - ui.quick_feedback(); - #endif + LCD_MESSAGE_MAX(MSG_G26_FIXED_LENGTH); + ui.quick_feedback(); destination = current_position; destination.e += prime_length; prepare_internal_move_to_destination(fr_slow_e); @@ -448,7 +439,7 @@ typedef struct { GRID_LOOP(i, j) { if (!circle_flags.marked(i, j)) { // We found a circle that needs to be printed - const xy_pos_t m = { _GET_MESH_X(i), _GET_MESH_Y(j) }; + const xy_pos_t m = { bedlevel.get_mesh_x(i), bedlevel.get_mesh_y(j) }; // Get the distance to this intersection float f = (pos - m).magnitude(); @@ -579,7 +570,7 @@ void GcodeSuite::G26() { if (parser.seen('P')) { if (!parser.has_value()) { - #if HAS_LCD_MENU + #if HAS_MARLINUI_MENU g26.prime_flag = -1; #else SERIAL_ECHOLNPGM("?Prime length must be specified when not using an LCD."); @@ -637,8 +628,8 @@ void GcodeSuite::G26() { } // Get repeat from 'R', otherwise do one full circuit - int16_t g26_repeats; - #if HAS_LCD_MENU + grid_count_t g26_repeats; + #if HAS_MARLINUI_MENU g26_repeats = parser.intval('R', GRID_MAX_POINTS + 1); #else if (parser.seen('R')) @@ -699,7 +690,7 @@ void GcodeSuite::G26() { move_to(destination, 0.0); move_to(destination, g26.ooze_amount); - TERN_(HAS_LCD_MENU, ui.capture()); + TERN_(HAS_MARLINUI_MENU, ui.capture()); #if DISABLED(ARC_SUPPORT) @@ -716,7 +707,7 @@ void GcodeSuite::G26() { #error "A_CNT must be a positive value. Please change A_INT." #endif float trig_table[A_CNT]; - LOOP_L_N(i, A_CNT) + for (uint8_t i = 0; i < A_CNT; ++i) trig_table[i] = INTERSECTION_CIRCLE_RADIUS * cos(RADIANS(i * A_INT)); #endif // !ARC_SUPPORT @@ -729,7 +720,7 @@ void GcodeSuite::G26() { if (location.valid()) { TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(location.pos, ExtUI::G26_POINT_START)); - const xy_pos_t circle = _GET_MESH_POS(location.pos); + const xy_pos_t circle = { bedlevel.get_mesh_x(location.pos.a), bedlevel.get_mesh_y(location.pos.b) }; // If this mesh location is outside the printable radius, skip it. if (!position_is_reachable(circle)) continue; @@ -738,8 +729,8 @@ void GcodeSuite::G26() { // which is always drawn counter-clockwise. const xy_int8_t st = location; const bool f = st.y == 0, - r = st.x >= GRID_MAX_POINTS_X - 1, - b = st.y >= GRID_MAX_POINTS_Y - 1; + r = st.x >= (GRID_MAX_POINTS_X) - 1, + b = st.y >= (GRID_MAX_POINTS_Y) - 1; #if ENABLED(ARC_SUPPORT) @@ -795,7 +786,7 @@ void GcodeSuite::G26() { destination = current_position; } - if (TERN0(HAS_LCD_MENU, user_canceled())) goto LEAVE; // Check if the user wants to stop the Mesh Validation + if (TERN0(HAS_MARLINUI_MENU, user_canceled())) goto LEAVE; // Check if the user wants to stop the Mesh Validation #else // !ARC_SUPPORT @@ -819,7 +810,7 @@ void GcodeSuite::G26() { for (int8_t ind = start_ind; ind <= end_ind; ind++) { - if (TERN0(HAS_LCD_MENU, user_canceled())) goto LEAVE; // Check if the user wants to stop the Mesh Validation + if (TERN0(HAS_MARLINUI_MENU, user_canceled())) goto LEAVE; // Check if the user wants to stop the Mesh Validation xyz_float_t p = { circle.x + _COS(ind ), circle.y + _SIN(ind ), g26.layer_height }, q = { circle.x + _COS(ind + 1), circle.y + _SIN(ind + 1), g26.layer_height }; @@ -846,7 +837,7 @@ void GcodeSuite::G26() { g26.connect_neighbor_with_line(location.pos, 0, 1); planner.synchronize(); TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(location.pos, ExtUI::G26_POINT_FINISH)); - if (TERN0(HAS_LCD_MENU, user_canceled())) goto LEAVE; + if (TERN0(HAS_MARLINUI_MENU, user_canceled())) goto LEAVE; } SERIAL_FLUSH(); // Prevent host M105 buffer overrun. @@ -854,7 +845,7 @@ void GcodeSuite::G26() { } while (--g26_repeats && location.valid()); LEAVE: - ui.set_status(GET_TEXT_F(MSG_G26_LEAVING), -1); + LCD_MESSAGE_MIN(MSG_G26_LEAVING); TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(location, ExtUI::G26_FINISH)); g26.retract_filament(destination); @@ -866,7 +857,7 @@ void GcodeSuite::G26() { planner.calculate_volumetric_multipliers(); #endif - TERN_(HAS_LCD_MENU, ui.release()); // Give back control of the LCD + TERN_(HAS_MARLINUI_MENU, ui.release()); // Give back control of the LCD if (!g26.keep_heaters_on) { TERN_(HAS_HEATED_BED, thermalManager.setTargetBed(0)); diff --git a/Marlin/src/gcode/bedlevel/G35.cpp b/Marlin/src/gcode/bedlevel/G35.cpp index 8cabb923..aa4ded00 100644 --- a/Marlin/src/gcode/bedlevel/G35.cpp +++ b/Marlin/src/gcode/bedlevel/G35.cpp @@ -57,8 +57,9 @@ * 41 - Counter-Clockwise M4 * 50 - Clockwise M5 * 51 - Counter-Clockwise M5 - **/ + */ void GcodeSuite::G35() { + DEBUG_SECTION(log_G35, "G35", DEBUGGING(LEVELING)); if (DEBUGGING(LEVELING)) log_machine_info(); @@ -82,9 +83,7 @@ void GcodeSuite::G35() { set_bed_leveling_enabled(false); #endif - #if ENABLED(CNC_WORKSPACE_PLANES) - workspace_plane = PLANE_XY; - #endif + TERN_(CNC_WORKSPACE_PLANES, workspace_plane = PLANE_XY); // Always home with tool 0 active #if HAS_MULTI_HOTEND @@ -101,12 +100,14 @@ void GcodeSuite::G35() { bool err_break = false; // Probe all positions - LOOP_L_N(i, G35_PROBE_COUNT) { + for (uint8_t i = 0; i < G35_PROBE_COUNT; ++i) { // In BLTOUCH HS mode, the probe travels in a deployed state. // Users of G35 might have a badly misaligned bed, so raise Z by the // length of the deployed pin (BLTOUCH stroke < 7mm) - do_blocking_move_to_z(Z_CLEARANCE_BETWEEN_PROBES + TERN0(BLTOUCH, bltouch.z_extra_clearance())); + + // Unsure if this is even required. The probe seems to lift correctly after probe done. + do_blocking_move_to_z(SUM_TERN(BLTOUCH, Z_CLEARANCE_BETWEEN_PROBES, bltouch.z_extra_clearance())); const float z_probed_height = probe.probe_at_point(tramming_points[i], PROBE_PT_RAISE, 0, true); if (isnan(z_probed_height)) { @@ -132,7 +133,7 @@ void GcodeSuite::G35() { const float threads_factor[] = { 0.5, 0.7, 0.8 }; // Calculate adjusts - LOOP_S_L_N(i, 1, G35_PROBE_COUNT) { + for (uint8_t i = 1; i < G35_PROBE_COUNT; ++i) { const float diff = z_measured[0] - z_measured[i], adjust = ABS(diff) < 0.001f ? 0 : diff / threads_factor[(screw_thread - 30) / 10]; @@ -153,10 +154,10 @@ void GcodeSuite::G35() { // Restore the active tool after homing #if HAS_MULTI_HOTEND - tool_change(old_tool_index, DISABLED(PARKING_EXTRUDER)); // Fetch previous toolhead if not PARKING_EXTRUDER + if (old_tool_index != 0) tool_change(old_tool_index, DISABLED(PARKING_EXTRUDER)); // Fetch previous toolhead if not PARKING_EXTRUDER #endif - #if BOTH(HAS_LEVELING, RESTORE_LEVELING_AFTER_G35) + #if ALL(HAS_LEVELING, RESTORE_LEVELING_AFTER_G35) set_bed_leveling_enabled(leveling_was_active); #endif diff --git a/Marlin/src/gcode/bedlevel/G42.cpp b/Marlin/src/gcode/bedlevel/G42.cpp index a2896ed6..44f5cead 100644 --- a/Marlin/src/gcode/bedlevel/G42.cpp +++ b/Marlin/src/gcode/bedlevel/G42.cpp @@ -27,47 +27,56 @@ #include "../gcode.h" #include "../../MarlinCore.h" // for IsRunning() #include "../../module/motion.h" -#include "../../module/probe.h" // for probe.offset #include "../../feature/bedlevel/bedlevel.h" +#if HAS_PROBE_XY_OFFSET + #include "../../module/probe.h" // for probe.offset +#endif + /** * G42: Move X & Y axes to mesh coordinates (I & J) + * + * Parameters: + * F : Feedrate in mm/min + * I : X axis point index + * J : Y axis point index + * P : Flag to put the probe at the given point */ void GcodeSuite::G42() { - if (MOTION_CONDITIONS) { - const bool hasI = parser.seenval('I'); - const int8_t ix = hasI ? parser.value_int() : 0; - const bool hasJ = parser.seenval('J'); - const int8_t iy = hasJ ? parser.value_int() : 0; + if (!MOTION_CONDITIONS) return; - if ((hasI && !WITHIN(ix, 0, GRID_MAX_POINTS_X - 1)) || (hasJ && !WITHIN(iy, 0, GRID_MAX_POINTS_Y - 1))) { - SERIAL_ECHOLNPGM(STR_ERR_MESH_XY); - return; - } + const bool hasI = parser.seenval('I'); + const int8_t ix = hasI ? parser.value_int() : 0; + const bool hasJ = parser.seenval('J'); + const int8_t iy = hasJ ? parser.value_int() : 0; - // Move to current_position, as modified by I, J, P parameters - destination = current_position; + if ((hasI && !WITHIN(ix, 0, GRID_MAX_POINTS_X - 1)) || (hasJ && !WITHIN(iy, 0, GRID_MAX_POINTS_Y - 1))) { + SERIAL_ECHOLNPGM(STR_ERR_MESH_XY); + return; + } - if (hasI) destination.x = _GET_MESH_X(ix); - if (hasJ) destination.y = _GET_MESH_Y(iy); + // Move to current_position, as modified by I, J, P parameters + destination = current_position; - #if HAS_PROBE_XY_OFFSET - if (parser.boolval('P')) { - if (hasI) destination.x -= probe.offset_xy.x; - if (hasJ) destination.y -= probe.offset_xy.y; - } - #endif + if (hasI) destination.x = bedlevel.get_mesh_x(ix); + if (hasJ) destination.y = bedlevel.get_mesh_y(iy); - const feedRate_t fval = parser.linearval('F'), - fr_mm_s = MMM_TO_MMS(fval > 0 ? fval : 0.0f); + #if HAS_PROBE_XY_OFFSET + if (parser.seen_test('P')) { + if (hasI) destination.x -= probe.offset_xy.x; + if (hasJ) destination.y -= probe.offset_xy.y; + } + #endif - // SCARA kinematic has "safe" XY raw moves - #if IS_SCARA - prepare_internal_fast_move_to_destination(fr_mm_s); - #else - prepare_internal_move_to_destination(fr_mm_s); - #endif - } + const feedRate_t fval = parser.linearval('F'), + fr_mm_s = MMM_TO_MMS(fval > 0 ? fval : 0.0f); + + // SCARA kinematic has "safe" XY raw moves + #if IS_SCARA + prepare_internal_fast_move_to_destination(fr_mm_s); + #else + prepare_internal_move_to_destination(fr_mm_s); + #endif } #endif // HAS_MESH diff --git a/Marlin/src/gcode/bedlevel/M420.cpp b/Marlin/src/gcode/bedlevel/M420.cpp index 3c23e85a..8852d38d 100644 --- a/Marlin/src/gcode/bedlevel/M420.cpp +++ b/Marlin/src/gcode/bedlevel/M420.cpp @@ -27,7 +27,10 @@ #include "../gcode.h" #include "../../feature/bedlevel/bedlevel.h" #include "../../module/planner.h" -#include "../../module/probe.h" + +#if ENABLED(MARLIN_DEV_MODE) + #include "../../module/probe.h" +#endif #if ENABLED(EEPROM_SETTINGS) #include "../../module/settings.h" @@ -67,14 +70,17 @@ void GcodeSuite::M420() { const float x_min = probe.min_x(), x_max = probe.max_x(), y_min = probe.min_y(), y_max = probe.max_y(); #if ENABLED(AUTO_BED_LEVELING_BILINEAR) - bilinear_start.set(x_min, y_min); - bilinear_grid_spacing.set((x_max - x_min) / (GRID_MAX_CELLS_X), - (y_max - y_min) / (GRID_MAX_CELLS_Y)); + xy_pos_t start, spacing; + start.set(x_min, y_min); + spacing.set((x_max - x_min) / (GRID_MAX_CELLS_X), + (y_max - y_min) / (GRID_MAX_CELLS_Y)); + bedlevel.set_grid(spacing, start); #endif GRID_LOOP(x, y) { - Z_VALUES(x, y) = 0.001 * random(-200, 200); - TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, Z_VALUES(x, y))); + bedlevel.z_values[x][y] = 0.001 * random(-200, 200); + TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, bedlevel.z_values[x][y])); } + TERN_(AUTO_BED_LEVELING_BILINEAR, bedlevel.refresh_bed_level()); SERIAL_ECHOPGM("Simulated " STRINGIFY(GRID_MAX_POINTS_X) "x" STRINGIFY(GRID_MAX_POINTS_Y) " mesh "); SERIAL_ECHOPGM(" (", x_min); SERIAL_CHAR(','); SERIAL_ECHO(y_min); @@ -98,7 +104,7 @@ void GcodeSuite::M420() { set_bed_leveling_enabled(false); #if ENABLED(EEPROM_SETTINGS) - const int8_t storage_slot = parser.has_value() ? parser.value_int() : ubl.storage_slot; + const int8_t storage_slot = parser.has_value() ? parser.value_int() : bedlevel.storage_slot; const int16_t a = settings.calc_num_meshes(); if (!a) { @@ -113,7 +119,7 @@ void GcodeSuite::M420() { } settings.load_mesh(storage_slot); - ubl.storage_slot = storage_slot; + bedlevel.storage_slot = storage_slot; #else @@ -125,10 +131,10 @@ void GcodeSuite::M420() { // L or V display the map info if (parser.seen("LV")) { - ubl.display_map(parser.byteval('T')); + bedlevel.display_map(parser.byteval('T')); SERIAL_ECHOPGM("Mesh is "); - if (!ubl.mesh_is_valid()) SERIAL_ECHOPGM("in"); - SERIAL_ECHOLNPGM("valid\nStorage slot: ", ubl.storage_slot); + if (!bedlevel.mesh_is_valid()) SERIAL_ECHOPGM("in"); + SERIAL_ECHOLNPGM("valid\nStorage slot: ", bedlevel.storage_slot); } #endif // AUTO_BED_LEVELING_UBL @@ -145,7 +151,7 @@ void GcodeSuite::M420() { #if ENABLED(AUTO_BED_LEVELING_UBL) set_bed_leveling_enabled(false); - ubl.adjust_mesh_to_mean(true, cval); + bedlevel.adjust_mesh_to_mean(true, cval); #else @@ -153,7 +159,7 @@ void GcodeSuite::M420() { // Get the sum and average of all mesh values float mesh_sum = 0; - GRID_LOOP(x, y) mesh_sum += Z_VALUES(x, y); + GRID_LOOP(x, y) mesh_sum += bedlevel.z_values[x][y]; const float zmean = mesh_sum / float(GRID_MAX_POINTS); #else // midrange @@ -161,7 +167,7 @@ void GcodeSuite::M420() { // Find the low and high mesh values. float lo_val = 100, hi_val = -100; GRID_LOOP(x, y) { - const float z = Z_VALUES(x, y); + const float z = bedlevel.z_values[x][y]; NOMORE(lo_val, z); NOLESS(hi_val, z); } @@ -175,10 +181,10 @@ void GcodeSuite::M420() { set_bed_leveling_enabled(false); // Subtract the mean from all values GRID_LOOP(x, y) { - Z_VALUES(x, y) -= zmean; - TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, Z_VALUES(x, y))); + bedlevel.z_values[x][y] -= zmean; + TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, bedlevel.z_values[x][y])); } - TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate()); + TERN_(AUTO_BED_LEVELING_BILINEAR, bedlevel.refresh_bed_level()); } #endif @@ -199,11 +205,10 @@ void GcodeSuite::M420() { #else if (leveling_is_valid()) { #if ENABLED(AUTO_BED_LEVELING_BILINEAR) - print_bilinear_leveling_grid(); - TERN_(ABL_BILINEAR_SUBDIVISION, print_bilinear_leveling_grid_virt()); + bedlevel.print_leveling_grid(); #elif ENABLED(MESH_BED_LEVELING) SERIAL_ECHOLNPGM("Mesh Bed Level data:"); - mbl.report_mesh(); + bedlevel.report_mesh(); #endif } #endif diff --git a/Marlin/src/gcode/bedlevel/M777.cpp b/Marlin/src/gcode/bedlevel/M777.cpp index 0b0add6c..e61c716b 100644 --- a/Marlin/src/gcode/bedlevel/M777.cpp +++ b/Marlin/src/gcode/bedlevel/M777.cpp @@ -65,9 +65,7 @@ return; } } - parser.parse("G90"); - GcodeSuite::process_parsed_command(); - + gcode.process_subcommands_now("G90"); if (loo > 0) { digitalWrite(Z_DIR_PIN, HIGH); //High=up dir } else if (loo < 0) { @@ -76,9 +74,7 @@ SERIAL_ECHOLN("Failed to detect direction"); return; } - analogWrite(Z_ENABLE_PIN, 255); //Deactivate all z stepper - if (mot==0){ // Activate motor 1 and disable rest analogWrite(M1_ENABLE_PIN, 0); @@ -106,7 +102,6 @@ } // Move steps - planner.synchronize(); for (float x = 0; x < abs(loo); x++) { digitalWrite(Z_STEP_PIN, HIGH); delay (5/2); @@ -128,28 +123,23 @@ float getDesviation(){ idle(); float measuredDesv = 0; - parser.parse("G91"); // Relative positioning - GcodeSuite::process_parsed_command(); - + gcode.process_subcommands_now("G91"); // Relative positioning if (digitalRead(Z_MIN_PIN) == LOW) { // Endpoint triggered. Go down - parser.parse("G1 Z0.1 F500"); while (digitalRead(Z_MIN_PIN) == LOW){ - GcodeSuite::process_parsed_command(); + gcode.process_subcommands_now("G1 Z0.1 F500"); planner.synchronize(); measuredDesv = measuredDesv - PRECISSION; } measuredDesv = measuredDesv + PRECISSION; // last move goes out height } else { // Endpoint not triggered. Go up - parser.parse("G1 Z-0.1 F500"); while (digitalRead(Z_MIN_PIN) != LOW){ - GcodeSuite::process_parsed_command(); + gcode.process_subcommands_now("G1 Z-0.1 F500"); planner.synchronize(); measuredDesv = measuredDesv + PRECISSION; } } idle(); - parser.parse("G90"); // Absolute positioning - GcodeSuite::process_parsed_command(); + gcode.process_subcommands_now("G90"); // Absolute positioning return measuredDesv; } @@ -178,79 +168,56 @@ float getSteps(float desviation){ void aBitDown(){ idle(); - parser.parse("G91"); - GcodeSuite::process_parsed_command(); - parser.parse("G1 Z5 F500"); - GcodeSuite::process_parsed_command(); + gcode.process_subcommands_now("G91"); + gcode.process_subcommands_now("G1 Z5 F500"); planner.synchronize(); - parser.parse("G90"); - GcodeSuite::process_parsed_command(); + gcode.process_subcommands_now("G90"); } -void printDesviationSummary(float motDesv[]) { +void printDesviationSummary(float items[]) { SERIAL_ECHO("Desviation summary: "); - SERIAL_ECHO("Motor0:"); - SERIAL_ECHO(motDesv[0]); + SERIAL_ECHO(items[0]); SERIAL_ECHO(", "); - SERIAL_ECHO("Motor1:"); - SERIAL_ECHO(motDesv[1]); + SERIAL_ECHO(items[1]); SERIAL_ECHO(", "); - SERIAL_ECHO("Motor2:"); - SERIAL_ECHO(motDesv[2]); + SERIAL_ECHO(items[2]); SERIAL_ECHO(", "); - SERIAL_ECHO("Motor3:"); - SERIAL_ECHO(motDesv[3]); + SERIAL_ECHO(items[3]); SERIAL_ECHOLN("."); } void GcodeSuite::M777() { SERIAL_ECHOLN("Starting HW bed leveling..."); - - int repTimes = 0; - - parser.parse("G90"); - GcodeSuite::process_parsed_command(); - - parser.parse("G28 X Y"); - GcodeSuite::process_parsed_command(); + gcode.process_subcommands_now("G90"); + // Home XY + gcode.process_subcommands_now("G28 X Y"); planner.synchronize(); - + int repTimes = 0; bool run = true; xy_pos_t motPosition[NUM_Z_MOTORS] = Z_MOTORS_POS; char cmd[20], str_1[16], str_2[16]; - float desvSteps; float heightDiff; + float motDesv[NUM_Z_MOTORS]; while (run){ - - float motDesv[NUM_Z_MOTORS]; - for (int i = 0; i < NUM_Z_MOTORS; i++) { // Center - parser.parse("G28 Z"); - GcodeSuite::process_parsed_command(); - planner.synchronize(); - // Move to measure position 0 - parser.parse("G90"); - GcodeSuite::process_parsed_command(); + gcode.process_subcommands_now("G28 Z"); + planner.synchronize(); // Wait move to finish + // Move to measure position + gcode.process_subcommands_now("G90"); sprintf_P(cmd, PSTR("G1X%sY%sF1300"), dtostrf(motPosition[i].x, 1, 3, str_1), dtostrf(motPosition[i].y, 1, 3, str_2)); gcode.process_subcommands_now(cmd); + planner.synchronize(); // Gets the height difference motDesv[i] = getDesviation(); - // Calculate steps and move - desvSteps = getSteps(motDesv[i]); - if (desvSteps != 0) { moveMotor(i, desvSteps); } - planner.synchronize(); + if (motDesv[i] != 0) { + // Calculate steps and fix height + moveMotor(i, getSteps(motDesv[i])); + } } - - /////// - printDesviationSummary(motDesv); - heightDiff = getMax(motDesv, NUM_Z_MOTORS) - getMin(motDesv, NUM_Z_MOTORS); - - repTimes=repTimes+1; - if ( ((int)heightDiff*100 <= (int)MAXOFFSET)*100 || (repTimes == MAXREPETITIONS) ) { run = false; SERIAL_ECHO("Maximun: "); @@ -265,6 +232,8 @@ void GcodeSuite::M777() { SERIAL_ECHOLN("Not leveled."); } + repTimes=repTimes+1; + } SERIAL_ECHOLN("Ended HW bed leveling."); diff --git a/Marlin/src/gcode/bedlevel/abl/G29.cpp b/Marlin/src/gcode/bedlevel/abl/G29.cpp index 6765ec86..282fe086 100644 --- a/Marlin/src/gcode/bedlevel/abl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/abl/G29.cpp @@ -32,19 +32,9 @@ #include "../../../feature/bedlevel/bedlevel.h" #include "../../../module/motion.h" #include "../../../module/planner.h" -#include "../../../module/stepper.h" #include "../../../module/probe.h" #include "../../queue.h" -#if HAS_PTC - #include "../../../feature/probe_temp_comp.h" - #include "../../../module/temperature.h" -#endif - -#if HAS_STATUS_MESSAGE - #include "../../../lcd/marlinui.h" -#endif - #if ENABLED(AUTO_BED_LEVELING_LINEAR) #include "../../../libs/least_squares_fit.h" #endif @@ -53,21 +43,22 @@ #include "../../../libs/vector_3.h" #endif -#define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE) -#include "../../../core/debug_out.h" - +#include "../../../lcd/marlinui.h" #if ENABLED(EXTENSIBLE_UI) #include "../../../lcd/extui/ui_api.h" #elif ENABLED(DWIN_CREALITY_LCD) #include "../../../lcd/e3v2/creality/dwin.h" -#elif ENABLED(DWIN_CREALITY_LCD_ENHANCED) - #include "../../../lcd/e3v2/enhanced/dwin.h" +#elif ENABLED(DWIN_LCD_PROUI) + #include "../../../lcd/e3v2/proui/dwin.h" #endif #if HAS_MULTI_HOTEND #include "../../../module/tool_change.h" #endif +#define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE) +#include "../../../core/debug_out.h" + #if ABL_USES_GRID #if ENABLED(PROBE_Y_FIRST) #define PR_OUTER_VAR abl.meshCount.x @@ -82,7 +73,25 @@ #endif #endif -#define G29_RETURN(b) return TERN_(G29_RETRY_AND_RECOVER, b) +/** + * @brief Do some things before returning from G29. + * @param retry : true if the G29 can and should be retried. false if the failure is too serious. + * @param did : true if the leveling procedure completed successfully. + */ +static void pre_g29_return(const bool retry, const bool did) { + if (!retry) { + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_IDLE, false)); + } + if (did) { + TERN_(HAS_DWIN_E3V2_BASIC, DWIN_LevelingDone()); + TERN_(EXTENSIBLE_UI, ExtUI::onLevelingDone()); + } +} + +#define G29_RETURN(retry, did) do{ \ + pre_g29_return(TERN0(G29_RETRY_AND_RECOVER, retry), did); \ + return TERN_(G29_RETRY_AND_RECOVER, retry); \ +}while(0) // For manual probing values persist over multiple G29 class G29_State { @@ -93,16 +102,20 @@ class G29_State { bool dryrun, reenable; - #if EITHER(PROBE_MANUALLY, AUTO_BED_LEVELING_LINEAR) + #if HAS_MULTI_HOTEND + uint8_t tool_index; + #endif + + #if ANY(PROBE_MANUALLY, AUTO_BED_LEVELING_LINEAR) int abl_probe_index; #endif #if ENABLED(AUTO_BED_LEVELING_LINEAR) - int abl_points; + grid_count_t abl_points; #elif ENABLED(AUTO_BED_LEVELING_3POINT) - static constexpr int abl_points = 3; + static constexpr grid_count_t abl_points = 3; #elif ABL_USES_GRID - static constexpr int abl_points = GRID_MAX_POINTS; + static constexpr grid_count_t abl_points = GRID_MAX_POINTS; #endif #if ABL_USES_GRID @@ -123,20 +136,21 @@ class G29_State { #if ENABLED(AUTO_BED_LEVELING_BILINEAR) float Z_offset; + bed_mesh_t z_values; #endif #if ENABLED(AUTO_BED_LEVELING_LINEAR) int indexIntoAB[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y]; - float eqnAMatrix[(GRID_MAX_POINTS) * 3], // "A" matrix of the linear system of equations - eqnBVector[GRID_MAX_POINTS], // "B" vector of Z points + float eqnAMatrix[GRID_MAX_POINTS * 3], // "A" matrix of the linear system of equations + eqnBVector[GRID_MAX_POINTS], // "B" vector of Z points mean; #endif #endif }; -#if ABL_USES_GRID && EITHER(AUTO_BED_LEVELING_3POINT, AUTO_BED_LEVELING_BILINEAR) +#if ABL_USES_GRID && ANY(AUTO_BED_LEVELING_3POINT, AUTO_BED_LEVELING_BILINEAR) constexpr xy_uint8_t G29_State::grid_points; - constexpr int G29_State::abl_points; + constexpr grid_count_t G29_State::abl_points; #endif /** @@ -217,29 +231,34 @@ class G29_State { * There's no extra effect if you have a fixed Z probe. */ G29_TYPE GcodeSuite::G29() { + DEBUG_SECTION(log_G29, "G29", DEBUGGING(LEVELING)); + // Leveling state is persistent when done manually with multiple G29 commands TERN_(PROBE_MANUALLY, static) G29_State abl; - TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_PROBE)); - + // Keep powered steppers from timing out reset_stepper_timeout(); - const bool seenQ = EITHER(DEBUG_LEVELING_FEATURE, PROBE_MANUALLY) && parser.seen_test('Q'); + // Q = Query leveling and G29 state + const bool seenQ = ANY(DEBUG_LEVELING_FEATURE, PROBE_MANUALLY) && parser.seen_test('Q'); // G29 Q is also available if debugging #if ENABLED(DEBUG_LEVELING_FEATURE) if (seenQ || DEBUGGING(LEVELING)) log_machine_info(); - if (DISABLED(PROBE_MANUALLY) && seenQ) G29_RETURN(false); + if (DISABLED(PROBE_MANUALLY) && seenQ) G29_RETURN(false, false); #endif + // A = Abort manual probing + // C = Generate fake probe points (DEBUG_LEVELING_FEATURE) const bool seenA = TERN0(PROBE_MANUALLY, parser.seen_test('A')), no_action = seenA || seenQ, faux = ENABLED(DEBUG_LEVELING_FEATURE) && DISABLED(PROBE_MANUALLY) ? parser.boolval('C') : no_action; - if (!no_action && planner.leveling_active && parser.boolval('O')) { // Auto-level only if needed + // O = Don't level if leveling is already active + if (!no_action && planner.leveling_active && parser.boolval('O')) { if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("> Auto-level not needed, skip"); - G29_RETURN(false); + G29_RETURN(false, false); } // Send 'N' to force homing before G29 (internal only) @@ -247,25 +266,33 @@ G29_TYPE GcodeSuite::G29() { process_subcommands_now(TERN(CAN_SET_LEVELING_AFTER_G28, F("G28L0"), FPSTR(G28_STR))); // Don't allow auto-leveling without homing first - if (homing_needed_error()) G29_RETURN(false); + if (homing_needed_error()) G29_RETURN(false, false); + // 3-point leveling gets points from the probe class #if ENABLED(AUTO_BED_LEVELING_3POINT) vector_3 points[3]; probe.get_three_points(points); #endif + // Storage for ABL Linear results #if ENABLED(AUTO_BED_LEVELING_LINEAR) struct linear_fit_data lsf_results; #endif + // Set and report "probing" state to host + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_PROBE, false)); + /** * On the initial G29 fetch command parameters. */ if (!g29_in_progress) { - TERN_(HAS_MULTI_HOTEND, if (active_extruder) tool_change(0)); + #if HAS_MULTI_HOTEND + abl.tool_index = active_extruder; + if (active_extruder != 0) tool_change(0, true); + #endif - #if EITHER(PROBE_MANUALLY, AUTO_BED_LEVELING_LINEAR) + #if ANY(PROBE_MANUALLY, AUTO_BED_LEVELING_LINEAR) abl.abl_probe_index = -1; #endif @@ -277,35 +304,43 @@ G29_TYPE GcodeSuite::G29() { if (seen_w) { if (!leveling_is_valid()) { SERIAL_ERROR_MSG("No bilinear grid"); - G29_RETURN(false); + G29_RETURN(false, false); } const float rz = parser.seenval('Z') ? RAW_Z_POSITION(parser.value_linear_units()) : current_position.z; if (!WITHIN(rz, -10, 10)) { SERIAL_ERROR_MSG("Bad Z value"); - G29_RETURN(false); + G29_RETURN(false, false); } const float rx = RAW_X_POSITION(parser.linearval('X', NAN)), ry = RAW_Y_POSITION(parser.linearval('Y', NAN)); int8_t i = parser.byteval('I', -1), j = parser.byteval('J', -1); + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" + if (!isnan(rx) && !isnan(ry)) { // Get nearest i / j from rx / ry - i = (rx - bilinear_start.x + 0.5 * abl.gridSpacing.x) / abl.gridSpacing.x; - j = (ry - bilinear_start.y + 0.5 * abl.gridSpacing.y) / abl.gridSpacing.y; + i = (rx - bedlevel.grid_start.x) / bedlevel.grid_spacing.x + 0.5f; + j = (ry - bedlevel.grid_start.y) / bedlevel.grid_spacing.y + 0.5f; LIMIT(i, 0, (GRID_MAX_POINTS_X) - 1); LIMIT(j, 0, (GRID_MAX_POINTS_Y) - 1); } + + #pragma GCC diagnostic pop + if (WITHIN(i, 0, (GRID_MAX_POINTS_X) - 1) && WITHIN(j, 0, (GRID_MAX_POINTS_Y) - 1)) { set_bed_leveling_enabled(false); - z_values[i][j] = rz; - TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate()); + bedlevel.z_values[i][j] = rz; + bedlevel.refresh_bed_level(); TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(i, j, rz)); - set_bed_leveling_enabled(abl.reenable); - if (abl.reenable) report_current_position(); + if (abl.reenable) { + set_bed_leveling_enabled(true); + report_current_position(); + } } - G29_RETURN(false); + G29_RETURN(false, false); } // parser.seen_test('W') #else @@ -317,13 +352,13 @@ G29_TYPE GcodeSuite::G29() { // Jettison bed leveling data if (!seen_w && parser.seen_test('J')) { reset_bed_level(); - G29_RETURN(false); + G29_RETURN(false, false); } abl.verbose_level = parser.intval('V'); if (!WITHIN(abl.verbose_level, 0, 4)) { SERIAL_ECHOLNPGM("?(V)erbose level implausible (0-4)."); - G29_RETURN(false); + G29_RETURN(false, false); } abl.dryrun = parser.boolval('D') || TERN0(PROBE_MANUALLY, no_action); @@ -344,11 +379,11 @@ G29_TYPE GcodeSuite::G29() { if (!WITHIN(abl.grid_points.x, 2, GRID_MAX_POINTS_X)) { SERIAL_ECHOLNPGM("?Probe points (X) implausible (2-" STRINGIFY(GRID_MAX_POINTS_X) ")."); - G29_RETURN(false); + G29_RETURN(false, false); } if (!WITHIN(abl.grid_points.y, 2, GRID_MAX_POINTS_Y)) { SERIAL_ECHOLNPGM("?Probe points (Y) implausible (2-" STRINGIFY(GRID_MAX_POINTS_Y) ")."); - G29_RETURN(false); + G29_RETURN(false, false); } abl.abl_points = abl.grid_points.x * abl.grid_points.y; @@ -380,15 +415,15 @@ G29_TYPE GcodeSuite::G29() { if (!probe.good_bounds(abl.probe_position_lf, abl.probe_position_rb)) { if (DEBUGGING(LEVELING)) { DEBUG_ECHOLNPGM("G29 L", abl.probe_position_lf.x, " R", abl.probe_position_rb.x, - " F", abl.probe_position_lf.y, " B", abl.probe_position_rb.y); + " F", abl.probe_position_lf.y, " B", abl.probe_position_rb.y); } SERIAL_ECHOLNPGM("? (L,R,F,B) out of bounds."); - G29_RETURN(false); + G29_RETURN(false, false); } // Probe at the points of a lattice grid abl.gridSpacing.set((abl.probe_position_rb.x - abl.probe_position_lf.x) / (abl.grid_points.x - 1), - (abl.probe_position_rb.y - abl.probe_position_lf.y) / (abl.grid_points.y - 1)); + (abl.probe_position_rb.y - abl.probe_position_lf.y) / (abl.grid_points.y - 1)); #endif // ABL_USES_GRID @@ -404,47 +439,81 @@ G29_TYPE GcodeSuite::G29() { if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("> 3-point Leveling"); points[0].z = points[1].z = points[2].z = 0; // Probe at 3 arbitrary points #elif ENABLED(AUTO_BED_LEVELING_BILINEAR) - TERN_(EXTENSIBLE_UI, ExtUI::onMeshLevelingStart()); - TERN_(DWIN_CREALITY_LCD_ENHANCED, DWIN_MeshLevelingStart()); + TERN_(DWIN_LCD_PROUI, DWIN_LevelingStart()); #endif + TERN_(EXTENSIBLE_UI, ExtUI::onLevelingStart()); + if (!faux) { remember_feedrate_scaling_off(); #if ENABLED(PREHEAT_BEFORE_LEVELING) - if (!abl.dryrun) probe.preheat_for_probing(LEVELING_NOZZLE_TEMP, LEVELING_BED_TEMP); + if (!abl.dryrun) probe.preheat_for_probing(LEVELING_NOZZLE_TEMP, + #if ALL(DWIN_LCD_PROUI, HAS_HEATED_BED) + HMI_data.BedLevT + #else + LEVELING_BED_TEMP + #endif + ); #endif } + // Position bed horizontally and Z probe vertically. + #if HAS_SAFE_BED_LEVELING + xyze_pos_t safe_position = current_position; + #ifdef SAFE_BED_LEVELING_START_X + safe_position.x = SAFE_BED_LEVELING_START_X; + #endif + #ifdef SAFE_BED_LEVELING_START_Y + safe_position.y = SAFE_BED_LEVELING_START_Y; + #endif + #ifdef SAFE_BED_LEVELING_START_Z + safe_position.z = SAFE_BED_LEVELING_START_Z; + #endif + #ifdef SAFE_BED_LEVELING_START_I + safe_position.i = SAFE_BED_LEVELING_START_I; + #endif + #ifdef SAFE_BED_LEVELING_START_J + safe_position.j = SAFE_BED_LEVELING_START_J; + #endif + #ifdef SAFE_BED_LEVELING_START_K + safe_position.k = SAFE_BED_LEVELING_START_K; + #endif + #ifdef SAFE_BED_LEVELING_START_U + safe_position.u = SAFE_BED_LEVELING_START_U; + #endif + #ifdef SAFE_BED_LEVELING_START_V + safe_position.v = SAFE_BED_LEVELING_START_V; + #endif + #ifdef SAFE_BED_LEVELING_START_W + safe_position.w = SAFE_BED_LEVELING_START_W; + #endif + + do_blocking_move_to(safe_position); + #endif // HAS_SAFE_BED_LEVELING + // Disable auto bed leveling during G29. // Be formal so G29 can be done successively without G28. if (!no_action) set_bed_leveling_enabled(false); // Deploy certain probes before starting probing - #if HAS_BED_PROBE - if (ENABLED(BLTOUCH)) - do_z_clearance(Z_CLEARANCE_DEPLOY_PROBE); - else if (probe.deploy()) { + #if ENABLED(BLTOUCH) + do_z_clearance(Z_CLEARANCE_DEPLOY_PROBE); + #elif HAS_BED_PROBE + if (probe.deploy()) { // (returns true on deploy failure) set_bed_leveling_enabled(abl.reenable); - G29_RETURN(false); + G29_RETURN(false, true); } #endif #if ENABLED(AUTO_BED_LEVELING_BILINEAR) - if (TERN1(PROBE_MANUALLY, !no_action) - && (abl.gridSpacing != bilinear_grid_spacing || abl.probe_position_lf != bilinear_start) - ) { - // Reset grid to 0.0 or "not probed". (Also disables ABL) - reset_bed_level(); - - // Initialize a grid with the given dimensions - bilinear_grid_spacing = abl.gridSpacing; - bilinear_start = abl.probe_position_lf; - - // Can't re-enable (on error) until the new grid is written - abl.reenable = false; + if (!abl.dryrun && (abl.gridSpacing != bedlevel.grid_spacing || abl.probe_position_lf != bedlevel.grid_start)) { + reset_bed_level(); // Reset grid to 0.0 or "not probed". (Also disables ABL) + abl.reenable = false; // Can't re-enable (on error) until the new grid is written } - #endif // AUTO_BED_LEVELING_BILINEAR + // Pre-populate local Z values from the stored mesh + TERN_(IS_KINEMATIC, COPY(abl.z_values, bedlevel.z_values)); + #endif } // !g29_in_progress @@ -475,7 +544,8 @@ G29_TYPE GcodeSuite::G29() { SERIAL_ECHOLNPGM("idle"); } - if (no_action) G29_RETURN(false); + // For 'A' or 'Q' exit with success state + if (no_action) G29_RETURN(false, true); if (abl.abl_probe_index == 0) { // For the initial G29 S2 save software endstop state @@ -485,7 +555,7 @@ G29_TYPE GcodeSuite::G29() { } else { - #if EITHER(AUTO_BED_LEVELING_LINEAR, AUTO_BED_LEVELING_3POINT) + #if ANY(AUTO_BED_LEVELING_LINEAR, AUTO_BED_LEVELING_3POINT) const uint16_t index = abl.abl_probe_index - 1; #endif @@ -510,7 +580,7 @@ G29_TYPE GcodeSuite::G29() { #elif ENABLED(AUTO_BED_LEVELING_BILINEAR) const float newz = abl.measured_z + abl.Z_offset; - z_values[abl.meshCount.x][abl.meshCount.y] = newz; + abl.z_values[abl.meshCount.x][abl.meshCount.y] = newz; TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(abl.meshCount, newz)); if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM_P(PSTR("Save X"), abl.meshCount.x, SP_Y_STR, abl.meshCount.y, SP_Z_STR, abl.measured_z + abl.Z_offset); @@ -550,7 +620,7 @@ G29_TYPE GcodeSuite::G29() { // Disable software endstops to allow manual adjustment // If G29 is not completed, they will not be re-enabled SET_SOFT_ENDSTOP_LOOSE(true); - G29_RETURN(false); + G29_RETURN(false, true); } else { // Leveling done! Fall through to G29 finishing code below @@ -568,7 +638,7 @@ G29_TYPE GcodeSuite::G29() { // Disable software endstops to allow manual adjustment // If G29 is not completed, they will not be re-enabled SET_SOFT_ENDSTOP_LOOSE(true); - G29_RETURN(false); + G29_RETURN(false, true); } else { @@ -600,8 +670,6 @@ G29_TYPE GcodeSuite::G29() { bool zig = PR_OUTER_SIZE & 1; // Always end at RIGHT and BACK_PROBE_BED_POSITION - abl.measured_z = 0; - // Outer loop is X with PROBE_Y_FIRST enabled // Outer loop is Y with PROBE_Y_FIRST disabled for (PR_OUTER_VAR = 0; PR_OUTER_VAR < PR_OUTER_SIZE && !isnan(abl.measured_z); PR_OUTER_VAR++) { @@ -622,7 +690,7 @@ G29_TYPE GcodeSuite::G29() { zig ^= true; // zag // An index to print current state - uint8_t pt_index = (PR_OUTER_VAR) * (PR_INNER_SIZE) + 1; + grid_count_t pt_index = (PR_OUTER_VAR) * (PR_INNER_SIZE) + 1; // Inner loop is Y with PROBE_Y_FIRST enabled // Inner loop is X with PROBE_Y_FIRST disabled @@ -645,10 +713,6 @@ G29_TYPE GcodeSuite::G29() { break; // Breaks out of both loops } - TERN_(PTC_BED, ptc.compensate_measurement(TSI_BED, thermalManager.degBed(), abl.measured_z)); - TERN_(PTC_PROBE, ptc.compensate_measurement(TSI_PROBE, thermalManager.degProbe(), abl.measured_z)); - TERN_(PTC_HOTEND, ptc.compensate_measurement(TSI_EXT, thermalManager.degHotend(0), abl.measured_z)); - #if ENABLED(AUTO_BED_LEVELING_LINEAR) abl.mean += abl.measured_z; @@ -662,12 +726,12 @@ G29_TYPE GcodeSuite::G29() { #elif ENABLED(AUTO_BED_LEVELING_BILINEAR) const float z = abl.measured_z + abl.Z_offset; - z_values[abl.meshCount.x][abl.meshCount.y] = z PLUS_TERN0(X_AXIS_TWIST_COMPENSATION, xatc.compensation(abl.probePos)); + abl.z_values[abl.meshCount.x][abl.meshCount.y] = z; TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(abl.meshCount, z)); #endif - abl.reenable = false; + abl.reenable = false; // Don't re-enable after modifying the mesh idle_no_sleep(); } // inner @@ -677,7 +741,7 @@ G29_TYPE GcodeSuite::G29() { // Probe at 3 arbitrary points - LOOP_L_N(i, 3) { + for (uint8_t i = 0; i < 3; ++i) { if (abl.verbose_level) SERIAL_ECHOLNPGM("Probing point ", i + 1, "/3."); TERN_(HAS_STATUS_MESSAGE, ui.status_printf(0, F(S_FMT " %i/3"), GET_TEXT(MSG_PROBING_POINT), int(i + 1))); @@ -733,12 +797,16 @@ G29_TYPE GcodeSuite::G29() { if (!isnan(abl.measured_z)) { #if ENABLED(AUTO_BED_LEVELING_BILINEAR) - if (!abl.dryrun) extrapolate_unprobed_bed_level(); - print_bilinear_leveling_grid(); - - refresh_bed_level(); + if (abl.dryrun) + bedlevel.print_leveling_grid(&abl.z_values); + else { + bedlevel.set_grid(abl.gridSpacing, abl.probe_position_lf); + COPY(bedlevel.z_values, abl.z_values); + TERN_(IS_KINEMATIC, bedlevel.extrapolate_unprobed_bed_level()); + bedlevel.refresh_bed_level(); - TERN_(ABL_BILINEAR_SUBDIVISION, print_bilinear_leveling_grid_virt()); + bedlevel.print_leveling_grid(); + } #elif ENABLED(AUTO_BED_LEVELING_LINEAR) @@ -784,7 +852,7 @@ G29_TYPE GcodeSuite::G29() { auto print_topo_map = [&](FSTR_P const title, const bool get_min) { SERIAL_ECHOF(title); for (int8_t yy = abl.grid_points.y - 1; yy >= 0; yy--) { - LOOP_L_N(xx, abl.grid_points.x) { + for (uint8_t xx = 0; xx < abl.grid_points.x; ++xx) { const int ind = abl.indexIntoAB[xx][yy]; xyz_float_t tmp = { abl.eqnAMatrix[ind + 0 * abl.abl_points], abl.eqnAMatrix[ind + 1 * abl.abl_points], 0 }; @@ -848,33 +916,28 @@ G29_TYPE GcodeSuite::G29() { current_position = converted; if (DEBUGGING(LEVELING)) DEBUG_POS("G29 corrected XYZ", current_position); - } - #elif ENABLED(AUTO_BED_LEVELING_BILINEAR) + abl.reenable = true; + } - if (!abl.dryrun) { - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("G29 uncorrected Z:", current_position.z); + // Auto Bed Leveling is complete! Enable if possible. + if (abl.reenable) { + planner.leveling_active = true; + sync_plan_position(); + } - // Unapply the offset because it is going to be immediately applied - // and cause compensation movement in Z - const float fade_scaling_factor = TERN(ENABLE_LEVELING_FADE_HEIGHT, planner.fade_scaling_factor_for_z(current_position.z), 1); - current_position.z -= fade_scaling_factor * bilinear_z_offset(current_position); + #elif ENABLED(AUTO_BED_LEVELING_BILINEAR) - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM(" corrected Z:", current_position.z); - } + // Auto Bed Leveling is complete! Enable if possible. + if (!abl.dryrun || abl.reenable) set_bed_leveling_enabled(true); - #endif // ABL_PLANAR + #endif - // Auto Bed Leveling is complete! Enable if possible. - planner.leveling_active = !abl.dryrun || abl.reenable; } // !isnan(abl.measured_z) // Restore state after probing if (!faux) restore_feedrate_and_scaling(); - // Sync the planner from the current_position - if (planner.leveling_active) sync_plan_position(); - TERN_(HAS_BED_PROBE, probe.move_z_after_probing()); #ifdef Z_PROBE_END_SCRIPT @@ -883,14 +946,11 @@ G29_TYPE GcodeSuite::G29() { process_subcommands_now(F(Z_PROBE_END_SCRIPT)); #endif - TERN_(HAS_DWIN_E3V2_BASIC, DWIN_CompletedLeveling()); + TERN_(HAS_MULTI_HOTEND, if (abl.tool_index != 0) tool_change(abl.tool_index)); report_current_position(); - TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_IDLE)); - - G29_RETURN(isnan(abl.measured_z)); - + G29_RETURN(isnan(abl.measured_z), true); } #endif // HAS_ABL_NOT_UBL diff --git a/Marlin/src/gcode/bedlevel/abl/M421.cpp b/Marlin/src/gcode/bedlevel/abl/M421.cpp index 182dc325..f66d0231 100644 --- a/Marlin/src/gcode/bedlevel/abl/M421.cpp +++ b/Marlin/src/gcode/bedlevel/abl/M421.cpp @@ -56,13 +56,13 @@ void GcodeSuite::M421() { const float zval = parser.value_linear_units(); uint8_t sx = ix >= 0 ? ix : 0, ex = ix >= 0 ? ix : GRID_MAX_POINTS_X - 1, sy = iy >= 0 ? iy : 0, ey = iy >= 0 ? iy : GRID_MAX_POINTS_Y - 1; - LOOP_S_LE_N(x, sx, ex) { - LOOP_S_LE_N(y, sy, ey) { - z_values[x][y] = zval + (hasQ ? z_values[x][y] : 0); - TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, z_values[x][y])); + for (uint8_t x = sx; x <= ex; ++x) { + for (uint8_t y = sy; y <= ey; ++y) { + bedlevel.z_values[x][y] = zval + (hasQ ? bedlevel.z_values[x][y] : 0); + TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, bedlevel.z_values[x][y])); } } - TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate()); + bedlevel.refresh_bed_level(); } else SERIAL_ERROR_MSG(STR_ERR_MESH_XY); diff --git a/Marlin/src/gcode/bedlevel/mbl/G29.cpp b/Marlin/src/gcode/bedlevel/mbl/G29.cpp index eec89f73..f30f8c8b 100644 --- a/Marlin/src/gcode/bedlevel/mbl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/mbl/G29.cpp @@ -36,12 +36,12 @@ #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" -#elif ENABLED(DWIN_CREALITY_LCD_ENHANCED) - #include "../../../lcd/e3v2/enhanced/dwin.h" +#elif ENABLED(DWIN_LCD_PROUI) + #include "../../../lcd/e3v2/proui/dwin.h" #endif #define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE) @@ -64,6 +64,7 @@ inline void echo_not_entered(const char c) { SERIAL_CHAR(c); SERIAL_ECHOLNPGM(" * S5 Reset and disable mesh */ void GcodeSuite::G29() { + DEBUG_SECTION(log_G29, "G29", true); // G29 Q is also available if debugging @@ -75,8 +76,6 @@ void GcodeSuite::G29() { } #endif - TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_PROBE)); - static int mbl_probe_index = -1; MeshLevelingState state = (MeshLevelingState)parser.byteval('S', (int8_t)MeshReport); @@ -85,6 +84,8 @@ void GcodeSuite::G29() { return; } + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_PROBE)); + int8_t ix, iy; ix = iy = 0; @@ -93,18 +94,58 @@ void GcodeSuite::G29() { SERIAL_ECHOPGM("Mesh Bed Leveling "); if (leveling_is_valid()) { serialprintln_onoff(planner.leveling_active); - mbl.report_mesh(); + bedlevel.report_mesh(); } else SERIAL_ECHOLNPGM("has no data."); break; case MeshStart: - mbl.reset(); + bedlevel.reset(); mbl_probe_index = 0; if (!ui.wait_for_move) { - queue.inject(parser.seen_test('N') ? F("G28" TERN(CAN_SET_LEVELING_AFTER_G28, "L0", "") "\nG29S2") : F("G29S2")); - TERN_(EXTENSIBLE_UI, ExtUI::onMeshLevelingStart()); + if (parser.seen_test('N')) + queue.inject(F("G28" TERN_(CAN_SET_LEVELING_AFTER_G28, "L0"))); + + // Position bed horizontally and Z probe vertically. + #if HAS_SAFE_BED_LEVELING + xyze_pos_t safe_position = current_position; + #ifdef SAFE_BED_LEVELING_START_X + safe_position.x = SAFE_BED_LEVELING_START_X; + #endif + #ifdef SAFE_BED_LEVELING_START_Y + safe_position.y = SAFE_BED_LEVELING_START_Y; + #endif + #ifdef SAFE_BED_LEVELING_START_Z + safe_position.z = SAFE_BED_LEVELING_START_Z; + #endif + #ifdef SAFE_BED_LEVELING_START_I + safe_position.i = SAFE_BED_LEVELING_START_I; + #endif + #ifdef SAFE_BED_LEVELING_START_J + safe_position.j = SAFE_BED_LEVELING_START_J; + #endif + #ifdef SAFE_BED_LEVELING_START_K + safe_position.k = SAFE_BED_LEVELING_START_K; + #endif + #ifdef SAFE_BED_LEVELING_START_U + safe_position.u = SAFE_BED_LEVELING_START_U; + #endif + #ifdef SAFE_BED_LEVELING_START_V + safe_position.v = SAFE_BED_LEVELING_START_V; + #endif + #ifdef SAFE_BED_LEVELING_START_W + safe_position.w = SAFE_BED_LEVELING_START_W; + #endif + + do_blocking_move_to(safe_position); + #endif // HAS_SAFE_BED_LEVELING + + queue.inject(F("G29S2")); + + TERN_(EXTENSIBLE_UI, ExtUI::onLevelingStart()); + TERN_(DWIN_LCD_PROUI, DWIN_LevelingStart()); + return; } state = MeshNext; @@ -117,25 +158,28 @@ void GcodeSuite::G29() { // For each G29 S2... if (mbl_probe_index == 0) { // Move close to the bed before the first point - do_blocking_move_to_z(0.4f + do_blocking_move_to_z( #ifdef MANUAL_PROBE_START_Z - + (MANUAL_PROBE_START_Z) - 0.4f + MANUAL_PROBE_START_Z + #else + 0.4f #endif ); } else { // Save Z for the previous mesh position - mbl.set_zigzag_z(mbl_probe_index - 1, current_position.z); + bedlevel.set_zigzag_z(mbl_probe_index - 1, current_position.z); TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(ix, iy, current_position.z)); + TERN_(DWIN_LCD_PROUI, DWIN_MeshUpdate(_MIN(mbl_probe_index, GRID_MAX_POINTS), int(GRID_MAX_POINTS), current_position.z)); SET_SOFT_ENDSTOP_LOOSE(false); } // If there's another point to sample, move there with optional lift. - if (mbl_probe_index < (GRID_MAX_POINTS)) { + if (mbl_probe_index < GRID_MAX_POINTS) { // Disable software endstops to allow manual adjustment // If G29 is left hanging without completion they won't be re-enabled! SET_SOFT_ENDSTOP_LOOSE(true); - mbl.zigzag(mbl_probe_index++, ix, iy); - _manual_goto_xy({ mbl.index_to_xpos[ix], mbl.index_to_ypos[iy] }); + bedlevel.zigzag(mbl_probe_index++, ix, iy); + _manual_goto_xy({ bedlevel.index_to_xpos[ix], bedlevel.index_to_ypos[iy] }); } else { // Move to the after probing position @@ -153,8 +197,7 @@ void GcodeSuite::G29() { mbl_probe_index = -1; SERIAL_ECHOLNPGM("Mesh probing done."); TERN_(HAS_STATUS_MESSAGE, LCD_MESSAGE(MSG_MESH_DONE)); - BUZZ(100, 659); - BUZZ(100, 698); + OKAY_BUZZ(); home_all_axes(); set_bed_leveling_enabled(true); @@ -166,6 +209,7 @@ void GcodeSuite::G29() { #endif TERN_(LCD_BED_LEVELING, ui.wait_for_move = false); + TERN_(EXTENSIBLE_UI, ExtUI::onLevelingDone()); } break; @@ -191,9 +235,9 @@ void GcodeSuite::G29() { return echo_not_entered('J'); if (parser.seenval('Z')) { - mbl.z_values[ix][iy] = parser.value_linear_units(); - TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(ix, iy, mbl.z_values[ix][iy])); - TERN_(DWIN_CREALITY_LCD_ENHANCED, DWIN_MeshUpdate(ix, iy, mbl.z_values[ix][iy])); + bedlevel.z_values[ix][iy] = parser.value_linear_units(); + TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(ix, iy, bedlevel.z_values[ix][iy])); + TERN_(DWIN_LCD_PROUI, DWIN_MeshUpdate(ix, iy, bedlevel.z_values[ix][iy])); } else return echo_not_entered('Z'); @@ -201,7 +245,7 @@ void GcodeSuite::G29() { case MeshSetZOffset: if (parser.seenval('Z')) - mbl.z_offset = parser.value_linear_units(); + bedlevel.z_offset = parser.value_linear_units(); else return echo_not_entered('Z'); break; diff --git a/Marlin/src/gcode/bedlevel/mbl/M421.cpp b/Marlin/src/gcode/bedlevel/mbl/M421.cpp index 1368ab0b..e23683d5 100644 --- a/Marlin/src/gcode/bedlevel/mbl/M421.cpp +++ b/Marlin/src/gcode/bedlevel/mbl/M421.cpp @@ -43,9 +43,9 @@ */ void GcodeSuite::M421() { const bool hasX = parser.seen('X'), hasI = parser.seen('I'); - const int8_t ix = hasI ? parser.value_int() : hasX ? mbl.probe_index_x(RAW_X_POSITION(parser.value_linear_units())) : -1; + const int8_t ix = hasI ? parser.value_int() : hasX ? bedlevel.probe_index_x(RAW_X_POSITION(parser.value_linear_units())) : -1; const bool hasY = parser.seen('Y'), hasJ = parser.seen('J'); - const int8_t iy = hasJ ? parser.value_int() : hasY ? mbl.probe_index_y(RAW_Y_POSITION(parser.value_linear_units())) : -1; + const int8_t iy = hasJ ? parser.value_int() : hasY ? bedlevel.probe_index_y(RAW_Y_POSITION(parser.value_linear_units())) : -1; const bool hasZ = parser.seen('Z'), hasQ = !hasZ && parser.seen('Q'); if (int(hasI && hasJ) + int(hasX && hasY) != 1 || !(hasZ || hasQ)) @@ -53,7 +53,7 @@ void GcodeSuite::M421() { else if (ix < 0 || iy < 0) SERIAL_ERROR_MSG(STR_ERR_MESH_XY); else - mbl.set_z(ix, iy, parser.value_linear_units() + (hasQ ? mbl.z_values[ix][iy] : 0)); + bedlevel.set_z(ix, iy, parser.value_linear_units() + (hasQ ? bedlevel.z_values[ix][iy] : 0)); } #endif // MESH_BED_LEVELING diff --git a/Marlin/src/gcode/bedlevel/ubl/G29.cpp b/Marlin/src/gcode/bedlevel/ubl/G29.cpp index 932503d7..90deab3d 100644 --- a/Marlin/src/gcode/bedlevel/ubl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/ubl/G29.cpp @@ -39,7 +39,7 @@ void GcodeSuite::G29() { TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_PROBE)); - ubl.G29(); + bedlevel.G29(); TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_IDLE)); } diff --git a/Marlin/src/gcode/bedlevel/ubl/M421.cpp b/Marlin/src/gcode/bedlevel/ubl/M421.cpp index e6f0ef1f..f1fd4001 100644 --- a/Marlin/src/gcode/bedlevel/ubl/M421.cpp +++ b/Marlin/src/gcode/bedlevel/ubl/M421.cpp @@ -33,8 +33,8 @@ #if ENABLED(EXTENSIBLE_UI) #include "../../../lcd/extui/ui_api.h" -#elif ENABLED(DWIN_CREALITY_LCD_ENHANCED) - #include "../../../lcd/e3v2/enhanced/dwin.h" +#elif ENABLED(DWIN_LCD_PROUI) + #include "../../../lcd/e3v2/proui/dwin.h" #endif /** @@ -56,7 +56,7 @@ void GcodeSuite::M421() { hasZ = parser.seen('Z'), hasQ = !hasZ && parser.seen('Q'); - if (hasC) ij = ubl.find_closest_mesh_point_of_type(CLOSEST, current_position); + if (hasC) ij = bedlevel.find_closest_mesh_point_of_type(CLOSEST, current_position); // Test for bad parameter combinations if (int(hasC) + int(hasI && hasJ) != 1 || !(hasZ || hasQ || hasN)) @@ -66,10 +66,10 @@ void GcodeSuite::M421() { else if (!WITHIN(ij.x, 0, GRID_MAX_POINTS_X - 1) || !WITHIN(ij.y, 0, GRID_MAX_POINTS_Y - 1)) SERIAL_ERROR_MSG(STR_ERR_MESH_XY); else { - float &zval = ubl.z_values[ij.x][ij.y]; // Altering this Mesh Point + float &zval = bedlevel.z_values[ij.x][ij.y]; // Altering this Mesh Point zval = hasN ? NAN : parser.value_linear_units() + (hasQ ? zval : 0); // N=NAN, Z=NEWVAL, or Q=ADDVAL TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(ij.x, ij.y, zval)); // Ping ExtUI in case it's showing the mesh - TERN_(DWIN_CREALITY_LCD_ENHANCED, DWIN_MeshUpdate(ij.x, ij.y, zval)); + TERN_(DWIN_LCD_PROUI, DWIN_MeshUpdate(ij.x, ij.y, zval)); } } diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp index 8743c0d8..c345343d 100644 --- a/Marlin/src/gcode/calibrate/G28.cpp +++ b/Marlin/src/gcode/calibrate/G28.cpp @@ -24,8 +24,13 @@ #include "../gcode.h" -#include "../../module/stepper.h" #include "../../module/endstops.h" +#include "../../module/planner.h" +#include "../../module/stepper.h" // for various + +#if HAS_HOMING_CURRENT + #include "../../module/motion.h" // for set/restore_homing_current +#endif #if HAS_MULTI_HOTEND #include "../../module/tool_change.h" @@ -35,11 +40,17 @@ #include "../../feature/bedlevel/bedlevel.h" #endif +#if ENABLED(BD_SENSOR) + #include "../../feature/bedlevel/bdl/bdl.h" +#endif + #if ENABLED(SENSORLESS_HOMING) #include "../../feature/tmc_util.h" #endif -#include "../../module/probe.h" +#if HAS_BED_PROBE + #include "../../module/probe.h" +#endif #if ENABLED(BLTOUCH) #include "../../feature/bltouch.h" @@ -51,15 +62,11 @@ #include "../../lcd/extui/ui_api.h" #elif ENABLED(DWIN_CREALITY_LCD) #include "../../lcd/e3v2/creality/dwin.h" -#elif ENABLED(DWIN_CREALITY_LCD_ENHANCED) - #include "../../lcd/e3v2/enhanced/dwin.h" -#endif - -#if HAS_L64XX // set L6470 absolute position registers to counts - #include "../../libs/L64XX/L64XX_Marlin.h" +#elif ENABLED(DWIN_LCD_PROUI) + #include "../../lcd/e3v2/proui/dwin.h" #endif -#if ENABLED(LASER_MOVE_G28_OFF) +#if ENABLED(LASER_FEATURE) #include "../../feature/spindle_laser.h" #endif @@ -76,40 +83,33 @@ const int x_axis_home_dir = TOOL_X_HOME_DIR(active_extruder); - const float mlx = max_length(X_AXIS), - mly = max_length(Y_AXIS), - mlratio = mlx > mly ? mly / mlx : mlx / mly, - fr_mm_s = _MIN(homing_feedrate(X_AXIS), homing_feedrate(Y_AXIS)) * SQRT(sq(mlratio) + 1.0); + // Use a higher diagonal feedrate so axes move at homing speed + const float minfr = _MIN(homing_feedrate(X_AXIS), homing_feedrate(Y_AXIS)), + fr_mm_s = HYPOT(minfr, minfr); #if ENABLED(SENSORLESS_HOMING) sensorless_t stealth_states { - LINEAR_AXIS_LIST(tmc_enable_stallguard(stepperX), tmc_enable_stallguard(stepperY), false, false, false, false) - , false - #if AXIS_HAS_STALLGUARD(X2) - || tmc_enable_stallguard(stepperX2) - #endif - , false - #if AXIS_HAS_STALLGUARD(Y2) - || tmc_enable_stallguard(stepperY2) - #endif + NUM_AXIS_LIST( + TERN0(X_SENSORLESS, tmc_enable_stallguard(stepperX)), + TERN0(Y_SENSORLESS, tmc_enable_stallguard(stepperY)), + false, false, false, false, false, false, false + ) + , TERN0(X2_SENSORLESS, tmc_enable_stallguard(stepperX2)) + , TERN0(Y2_SENSORLESS, tmc_enable_stallguard(stepperY2)) }; #endif - do_blocking_move_to_xy(1.5 * mlx * x_axis_home_dir, 1.5 * mly * Y_HOME_DIR, fr_mm_s); + do_blocking_move_to_xy(1.5 * max_length(X_AXIS) * x_axis_home_dir, 1.5 * max_length(Y_AXIS) * Y_HOME_DIR, fr_mm_s); endstops.validate_homing_move(); current_position.set(0.0, 0.0); #if ENABLED(SENSORLESS_HOMING) && DISABLED(ENDSTOPS_ALWAYS_ON_DEFAULT) - tmc_disable_stallguard(stepperX, stealth_states.x); - tmc_disable_stallguard(stepperY, stealth_states.y); - #if AXIS_HAS_STALLGUARD(X2) - tmc_disable_stallguard(stepperX2, stealth_states.x2); - #endif - #if AXIS_HAS_STALLGUARD(Y2) - tmc_disable_stallguard(stepperY2, stealth_states.y2); - #endif + TERN_(X_SENSORLESS, tmc_disable_stallguard(stepperX, stealth_states.x)); + TERN_(X2_SENSORLESS, tmc_disable_stallguard(stepperX2, stealth_states.x2)); + TERN_(Y_SENSORLESS, tmc_disable_stallguard(stepperY, stealth_states.y)); + TERN_(Y2_SENSORLESS, tmc_disable_stallguard(stepperY2, stealth_states.y2)); #endif } @@ -130,14 +130,7 @@ * (Z is already at the right height) */ constexpr xy_float_t safe_homing_xy = { Z_SAFE_HOMING_X_POINT, Z_SAFE_HOMING_Y_POINT }; - #if HAS_HOME_OFFSET - xy_float_t okay_homing_xy = safe_homing_xy; - okay_homing_xy -= home_offset; - #else - constexpr xy_float_t okay_homing_xy = safe_homing_xy; - #endif - - destination.set(okay_homing_xy, current_position.z); + destination.set(safe_homing_xy, current_position.z); TERN_(HOMING_Z_WITH_PROBE, destination -= probe.offset_xy); @@ -176,7 +169,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; } @@ -185,7 +178,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 @@ -212,9 +205,14 @@ 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 + TERN_(BD_SENSOR, bdl.config_state = 0); - TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_HOMING)); + /** + * 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; @@ -223,7 +221,7 @@ void GcodeSuite::G28() { #if ENABLED(MARLIN_DEV_MODE) if (parser.seen_test('S')) { - LOOP_LINEAR_AXES(a) set_axis_is_at_home((AxisEnum)a); + LOOP_NUM_AXES(a) set_axis_is_at_home((AxisEnum)a); sync_plan_position(); SERIAL_ECHOLNPGM("Simulated Homing"); report_current_position(); @@ -237,7 +235,12 @@ void GcodeSuite::G28() { return; } - TERN_(HAS_DWIN_E3V2_BASIC, DWIN_StartHoming()); + #if ENABLED(FULL_REPORT_TO_HOST_FEATURE) + const M_StateEnum old_grblstate = M_State_grbl; + set_and_report_grblstate(M_HOMING); + #endif + + TERN_(HAS_DWIN_E3V2_BASIC, DWIN_HomingStart()); TERN_(EXTENSIBLE_UI, ExtUI::onHomingStart()); planner.synchronize(); // Wait for planner moves to finish! @@ -262,7 +265,7 @@ void GcodeSuite::G28() { reset_stepper_timeout(); #define HAS_CURRENT_HOME(N) (defined(N##_CURRENT_HOME) && N##_CURRENT_HOME != N##_CURRENT) - #if HAS_CURRENT_HOME(X) || HAS_CURRENT_HOME(X2) || HAS_CURRENT_HOME(Y) || HAS_CURRENT_HOME(Y2) || HAS_CURRENT_HOME(I) || HAS_CURRENT_HOME(J) || HAS_CURRENT_HOME(K) || (ENABLED(DELTA) && HAS_CURRENT_HOME(Z)) + #if HAS_CURRENT_HOME(X) || HAS_CURRENT_HOME(X2) || HAS_CURRENT_HOME(Y) || HAS_CURRENT_HOME(Y2) || (ENABLED(DELTA) && HAS_CURRENT_HOME(Z)) || HAS_CURRENT_HOME(I) || HAS_CURRENT_HOME(J) || HAS_CURRENT_HOME(K) || HAS_CURRENT_HOME(U) || HAS_CURRENT_HOME(V) || HAS_CURRENT_HOME(W) #define HAS_HOMING_CURRENT 1 #endif @@ -273,42 +276,60 @@ void GcodeSuite::G28() { #if HAS_CURRENT_HOME(X) const int16_t tmc_save_current_X = stepperX.getMilliamps(); stepperX.rms_current(X_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F("X"), tmc_save_current_X, X_CURRENT_HOME); + if (DEBUGGING(LEVELING)) debug_current(F(STR_X), tmc_save_current_X, X_CURRENT_HOME); #endif #if HAS_CURRENT_HOME(X2) const int16_t tmc_save_current_X2 = stepperX2.getMilliamps(); stepperX2.rms_current(X2_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F("X2"), tmc_save_current_X2, X2_CURRENT_HOME); + if (DEBUGGING(LEVELING)) debug_current(F(STR_X2), tmc_save_current_X2, X2_CURRENT_HOME); #endif #if HAS_CURRENT_HOME(Y) const int16_t tmc_save_current_Y = stepperY.getMilliamps(); stepperY.rms_current(Y_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F("Y"), tmc_save_current_Y, Y_CURRENT_HOME); + if (DEBUGGING(LEVELING)) debug_current(F(STR_Y), tmc_save_current_Y, Y_CURRENT_HOME); #endif #if HAS_CURRENT_HOME(Y2) const int16_t tmc_save_current_Y2 = stepperY2.getMilliamps(); stepperY2.rms_current(Y2_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F("Y2"), tmc_save_current_Y2, Y2_CURRENT_HOME); + if (DEBUGGING(LEVELING)) debug_current(F(STR_Y2), tmc_save_current_Y2, Y2_CURRENT_HOME); + #endif + #if HAS_CURRENT_HOME(Z) && ENABLED(DELTA) + const int16_t tmc_save_current_Z = stepperZ.getMilliamps(); + stepperZ.rms_current(Z_CURRENT_HOME); + if (DEBUGGING(LEVELING)) debug_current(F(STR_Z), tmc_save_current_Z, Z_CURRENT_HOME); #endif #if HAS_CURRENT_HOME(I) const int16_t tmc_save_current_I = stepperI.getMilliamps(); stepperI.rms_current(I_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F(AXIS4_STR), tmc_save_current_I, I_CURRENT_HOME); + if (DEBUGGING(LEVELING)) debug_current(F(STR_I), tmc_save_current_I, I_CURRENT_HOME); #endif #if HAS_CURRENT_HOME(J) const int16_t tmc_save_current_J = stepperJ.getMilliamps(); stepperJ.rms_current(J_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F(AXIS5_STR), tmc_save_current_J, J_CURRENT_HOME); + if (DEBUGGING(LEVELING)) debug_current(F(STR_J), tmc_save_current_J, J_CURRENT_HOME); #endif #if HAS_CURRENT_HOME(K) const int16_t tmc_save_current_K = stepperK.getMilliamps(); stepperK.rms_current(K_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F(AXIS6_STR), tmc_save_current_K, K_CURRENT_HOME); + if (DEBUGGING(LEVELING)) debug_current(F(STR_K), tmc_save_current_K, K_CURRENT_HOME); #endif - #if HAS_CURRENT_HOME(Z) && ENABLED(DELTA) - const int16_t tmc_save_current_Z = stepperZ.getMilliamps(); - stepperZ.rms_current(Z_CURRENT_HOME); - if (DEBUGGING(LEVELING)) debug_current(F("Z"), tmc_save_current_Z, Z_CURRENT_HOME); + #if HAS_CURRENT_HOME(U) + const int16_t tmc_save_current_U = stepperU.getMilliamps(); + stepperU.rms_current(U_CURRENT_HOME); + if (DEBUGGING(LEVELING)) debug_current(F(STR_U), tmc_save_current_U, U_CURRENT_HOME); + #endif + #if HAS_CURRENT_HOME(V) + const int16_t tmc_save_current_V = stepperV.getMilliamps(); + stepperV.rms_current(V_CURRENT_HOME); + if (DEBUGGING(LEVELING)) debug_current(F(STR_V), tmc_save_current_V, V_CURRENT_HOME); + #endif + #if HAS_CURRENT_HOME(W) + const int16_t tmc_save_current_W = stepperW.getMilliamps(); + stepperW.rms_current(W_CURRENT_HOME); + if (DEBUGGING(LEVELING)) debug_current(F(STR_W), tmc_save_current_W, W_CURRENT_HOME); + #endif + #if SENSORLESS_STALLGUARD_DELAY + safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle #endif #endif @@ -353,48 +374,72 @@ void GcodeSuite::G28() { #define _UNSAFE(A) (homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(A##_AXIS)))) const bool homeZ = TERN0(HAS_Z_AXIS, parser.seen_test('Z')), - LINEAR_AXIS_LIST( // Other axes should be homed before Z safe-homing + NUM_AXIS_LIST( // Other axes should be homed before Z safe-homing needX = _UNSAFE(X), needY = _UNSAFE(Y), needZ = false, // UNUSED - needI = _UNSAFE(I), needJ = _UNSAFE(J), needK = _UNSAFE(K) + needI = _UNSAFE(I), needJ = _UNSAFE(J), needK = _UNSAFE(K), + needU = _UNSAFE(U), needV = _UNSAFE(V), needW = _UNSAFE(W) ), - LINEAR_AXIS_LIST( // Home each axis if needed or flagged + NUM_AXIS_LIST( // Home each axis if needed or flagged homeX = needX || parser.seen_test('X'), homeY = needY || parser.seen_test('Y'), homeZZ = homeZ, - homeI = needI || parser.seen_test(AXIS4_NAME), homeJ = needJ || parser.seen_test(AXIS5_NAME), homeK = needK || parser.seen_test(AXIS6_NAME), + homeI = needI || parser.seen_test(AXIS4_NAME), homeJ = needJ || parser.seen_test(AXIS5_NAME), + homeK = needK || parser.seen_test(AXIS6_NAME), homeU = needU || parser.seen_test(AXIS7_NAME), + homeV = needV || parser.seen_test(AXIS8_NAME), homeW = needW || parser.seen_test(AXIS9_NAME) ), - home_all = LINEAR_AXIS_GANG( // Home-all if all or none are flagged + home_all = NUM_AXIS_GANG( // Home-all if all or none are flagged homeX == homeX, && homeY == homeX, && homeZ == homeX, - && homeI == homeX, && homeJ == homeX, && homeK == homeX + && homeI == homeX, && homeJ == homeX, && homeK == homeX, + && homeU == homeX, && homeV == homeX, && homeW == homeX ), - LINEAR_AXIS_LIST( + NUM_AXIS_LIST( doX = home_all || homeX, doY = home_all || homeY, doZ = home_all || homeZ, - doI = home_all || homeI, doJ = home_all || homeJ, doK = home_all || homeK + doI = home_all || homeI, doJ = home_all || homeJ, doK = home_all || homeK, + doU = home_all || homeU, doV = home_all || homeV, doW = home_all || homeW ); #if HAS_Z_AXIS UNUSED(needZ); UNUSED(homeZZ); #else constexpr bool doZ = false; + #if !HAS_Y_AXIS + constexpr bool doY = false; + #endif #endif + // Z may home first, e.g., when homing away from the bed TERN_(HOME_Z_FIRST, if (doZ) homeaxis(Z_AXIS)); - const float z_homing_height = parser.seenval('R') ? parser.value_linear_units() : Z_HOMING_HEIGHT; + // 'R' to specify a specific raise. 'R0' indicates no raise, e.g., for recovery.resume + // When 'R0' is used, there should already be adequate clearance, e.g., from homing Z to max. + const bool seenR = parser.seenval('R'); - if (z_homing_height && (LINEAR_AXIS_GANG(doX, || doY, || TERN0(Z_SAFE_HOMING, doZ), || doI, || doJ, || doK))) { + // Use raise given by 'R' or Z_HOMING_HEIGHT (above the probe trigger point) + float z_homing_height = seenR ? parser.value_linear_units() : Z_HOMING_HEIGHT; + + // Check for any lateral motion that might require clearance + const bool may_skate = seenR || NUM_AXIS_GANG(doX, || doY, || TERN0(Z_SAFE_HOMING, doZ), || doI, || doJ, || doK, || doU, || doV, || doW); + + if (seenR && z_homing_height == 0) { + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("R0 = No Z raise"); + } + else if (z_homing_height && may_skate) { // Raise Z before homing any other axes and z is not already high enough (never lower z) - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Raise Z (before homing) by ", z_homing_height); + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Raise Z before homing:"); do_z_clearance(z_homing_height); - TERN_(BLTOUCH, bltouch.init()); } + // Init BLTouch ahead of any lateral motion, even if not homing with the probe + TERN_(BLTOUCH, if (may_skate) bltouch.init()); + // Diagonal move first if both are homing TERN_(QUICK_HOME, if (doX && doY) quick_home_xy()); - // Home Y (before X) - if (ENABLED(HOME_Y_BEFORE_X) && (doY || TERN0(CODEPENDENT_XY_HOMING, doX))) - homeaxis(Y_AXIS); + #if HAS_Y_AXIS + // Home Y (before X) + if (ENABLED(HOME_Y_BEFORE_X) && (doY || TERN0(CODEPENDENT_XY_HOMING, doX))) + homeaxis(Y_AXIS); + #endif // Home X if (doX || (doY && ENABLED(CODEPENDENT_XY_HOMING) && DISABLED(HOME_Y_BEFORE_X))) { @@ -422,33 +467,53 @@ void GcodeSuite::G28() { #endif } - // Home Y (after X) - if (DISABLED(HOME_Y_BEFORE_X) && doY) - homeaxis(Y_AXIS); - - TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(saved_motion_state)); - - // Home Z last if homing towards the bed - #if HAS_Z_AXIS && DISABLED(HOME_Z_FIRST) - if (doZ) { - #if EITHER(Z_MULTI_ENDSTOPS, Z_STEPPER_AUTO_ALIGN) - stepper.set_all_z_lock(false); - stepper.set_separate_multi_axis(false); - #endif - - TERN(Z_SAFE_HOMING, home_z_safely(), homeaxis(Z_AXIS)); - probe.move_z_after_homing(); - } + #if ALL(FOAMCUTTER_XYUV, HAS_I_AXIS) + // Home I (after X) + if (doI) homeaxis(I_AXIS); #endif - #if LINEAR_AXES >= 4 - if (doI) homeaxis(I_AXIS); + #if HAS_Y_AXIS + // Home Y (after X) + if (DISABLED(HOME_Y_BEFORE_X) && doY) + homeaxis(Y_AXIS); #endif - #if LINEAR_AXES >= 5 + + #if ALL(FOAMCUTTER_XYUV, HAS_J_AXIS) + // Home J (after Y) if (doJ) homeaxis(J_AXIS); #endif - #if LINEAR_AXES >= 6 - if (doK) homeaxis(K_AXIS); + + TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(saved_motion_state)); + + #if ENABLED(FOAMCUTTER_XYUV) + // skip homing of unused Z axis for foamcutters + if (doZ) set_axis_is_at_home(Z_AXIS); + #else + // Home Z last if homing towards the bed + #if HAS_Z_AXIS && DISABLED(HOME_Z_FIRST) + if (doZ) { + #if ANY(Z_MULTI_ENDSTOPS, Z_STEPPER_AUTO_ALIGN) + stepper.set_all_z_lock(false); + stepper.set_separate_multi_axis(false); + #endif + + #if ENABLED(Z_SAFE_HOMING) + if (TERN1(POWER_LOSS_RECOVERY, !parser.seen_test('H'))) home_z_safely(); else homeaxis(Z_AXIS); + #else + homeaxis(Z_AXIS); + #endif + TERN_(HAS_BED_PROBE, probe.move_z_after_homing()); + } + #endif + + SECONDARY_AXIS_CODE( + if (doI) homeaxis(I_AXIS), + if (doJ) homeaxis(J_AXIS), + if (doK) homeaxis(K_AXIS), + if (doU) homeaxis(U_AXIS), + if (doV) homeaxis(V_AXIS), + if (doW) homeaxis(W_AXIS) + ); #endif sync_plan_position(); @@ -532,34 +597,30 @@ void GcodeSuite::G28() { #if HAS_CURRENT_HOME(K) stepperK.rms_current(tmc_save_current_K); #endif + #if HAS_CURRENT_HOME(U) + stepperU.rms_current(tmc_save_current_U); + #endif + #if HAS_CURRENT_HOME(V) + stepperV.rms_current(tmc_save_current_V); + #endif + #if HAS_CURRENT_HOME(W) + stepperW.rms_current(tmc_save_current_W); + #endif + #if SENSORLESS_STALLGUARD_DELAY + safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle + #endif #endif // HAS_HOMING_CURRENT ui.refresh(); - TERN_(HAS_DWIN_E3V2_BASIC, DWIN_CompletedHoming()); - TERN_(EXTENSIBLE_UI, ExtUI::onHomingComplete()); + TERN_(HAS_DWIN_E3V2_BASIC, DWIN_HomingDone()); + TERN_(EXTENSIBLE_UI, ExtUI::onHomingDone()); report_current_position(); if (ENABLED(NANODLP_Z_SYNC) && (doZ || ENABLED(NANODLP_ALL_AXIS))) SERIAL_ECHOLNPGM(STR_Z_MOVE_COMP); - TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_IDLE)); - - #if HAS_L64XX - // Set L6470 absolute position registers to counts - // constexpr *might* move this to PROGMEM. - // If not, this will need a PROGMEM directive and an accessor. - #define _EN_ITEM(N) , E_AXIS - static constexpr AxisEnum L64XX_axis_xref[MAX_L64XX] = { - LINEAR_AXIS_LIST(X_AXIS, Y_AXIS, Z_AXIS, I_AXIS, J_AXIS, K_AXIS), - X_AXIS, Y_AXIS, Z_AXIS, Z_AXIS, Z_AXIS - REPEAT(E_STEPPERS, _EN_ITEM) - }; - #undef _EN_ITEM - for (uint8_t j = 1; j <= L64XX::chain[0]; j++) { - const uint8_t cv = L64XX::chain[j]; - L64xxManager.set_param((L64XX_axis_t)cv, L6470_ABS_POS, stepper.position(L64XX_axis_xref[cv])); - } - #endif + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(old_grblstate)); + } diff --git a/Marlin/src/gcode/calibrate/G33.cpp b/Marlin/src/gcode/calibrate/G33.cpp index a4b9aec0..4673cc98 100644 --- a/Marlin/src/gcode/calibrate/G33.cpp +++ b/Marlin/src/gcode/calibrate/G33.cpp @@ -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" @@ -71,9 +71,9 @@ float lcd_probe_pt(const xy_pos_t &xy); void ac_home() { endstops.enable(true); - TERN_(HAS_DELTA_SENSORLESS_PROBING, probe.set_homing_current(true)); + TERN_(SENSORLESS_HOMING, endstops.set_homing_current(true)); home_delta(); - TERN_(HAS_DELTA_SENSORLESS_PROBING, probe.set_homing_current(false)); + TERN_(SENSORLESS_HOMING, endstops.set_homing_current(false)); endstops.not_homing(); } @@ -97,13 +97,12 @@ void ac_cleanup(TERN_(HAS_MULTI_HOTEND, const uint8_t old_tool_index)) { void print_signed_float(FSTR_P const prefix, const_float_t f) { SERIAL_ECHOPGM(" "); - SERIAL_ECHOF(prefix, AS_CHAR(':')); - if (f >= 0) SERIAL_CHAR('+'); - SERIAL_ECHO_F(f, 2); + SERIAL_ECHOF(prefix, C(':')); + serial_offset(f); } /** - * - Print the delta settings + * - Print the delta settings */ static void print_calibration_settings(const bool end_stops, const bool tower_angles) { SERIAL_ECHOPGM(".Height:", delta_height); @@ -129,7 +128,7 @@ static void print_calibration_settings(const bool end_stops, const bool tower_an } /** - * - Print the probe results + * - Print the probe results */ static void print_calibration_results(const float z_pt[NPP + 1], const bool tower_points, const bool opposite_points) { SERIAL_ECHOPGM(". "); @@ -153,7 +152,7 @@ static void print_calibration_results(const float z_pt[NPP + 1], const bool towe } /** - * - Calculate the standard deviation from the zero plane + * - Calculate the standard deviation from the zero plane */ static float std_dev_points(float z_pt[NPP + 1], const bool _0p_cal, const bool _1p_cal, const bool _4p_cal, const bool _4p_opp) { if (!_0p_cal) { @@ -171,7 +170,7 @@ static float std_dev_points(float z_pt[NPP + 1], const bool _0p_cal, const bool } /** - * - Probe a point + * - Probe a point */ static float calibration_probe(const xy_pos_t &xy, const bool stow, const bool probe_at_offset) { #if HAS_BED_PROBE @@ -183,7 +182,7 @@ static float calibration_probe(const xy_pos_t &xy, const bool stow, const bool p } /** - * - Probe a grid + * - Probe a grid */ static bool probe_calibration_points(float z_pt[NPP + 1], const int8_t probe_points, const float dcr, const bool towers_set, const bool stow_after_each, const bool probe_at_offset) { const bool _0p_calibration = probe_points == 0, @@ -344,7 +343,7 @@ static float auto_tune_a(const float dcr) { abc_float_t delta_e = { 0.0f }, delta_t = { 0.0f }; delta_t.reset(); - LOOP_LINEAR_AXES(axis) { + LOOP_NUM_AXES(axis) { delta_t[axis] = diff; calc_kinematics_diff_probe_points(z_pt, dcr, delta_e, delta_r, delta_t); delta_t[axis] = 0; @@ -391,6 +390,8 @@ static float auto_tune_a(const float dcr) { * X Don't activate stallguard on X. * Y Don't activate stallguard on Y. * Z Don't activate stallguard on Z. + * + * S Save offset_sensorless_adj */ void GcodeSuite::G33() { @@ -412,7 +413,8 @@ void GcodeSuite::G33() { dcr -= probe_at_offset ? _MAX(total_offset, PROBING_MARGIN) : total_offset; #endif NOMORE(dcr, DELTA_PRINTABLE_RADIUS); - if (parser.seenval('R')) dcr -= _MAX(parser.value_float(),0); + if (parser.seenval('R')) dcr -= _MAX(parser.value_float(), 0.0f); + TERN_(HAS_DELTA_SENSORLESS_PROBING, dcr *= sensorless_radius_factor); const float calibration_precision = parser.floatval('C', 0.0f); if (calibration_precision < 0) { @@ -435,9 +437,8 @@ void GcodeSuite::G33() { const bool stow_after_each = parser.seen_test('E'); #if HAS_DELTA_SENSORLESS_PROBING - probe.test_sensitivity.x = !parser.seen_test('X'); - TERN_(HAS_Y_AXIS, probe.test_sensitivity.y = !parser.seen_test('Y')); - TERN_(HAS_Z_AXIS, probe.test_sensitivity.z = !parser.seen_test('Z')); + probe.test_sensitivity = { !parser.seen_test('X'), !parser.seen_test('Y'), !parser.seen_test('Z') }; + const bool do_save_offset_adj = parser.seen_test('S'); #endif const bool _0p_calibration = probe_points == 0, @@ -463,8 +464,8 @@ void GcodeSuite::G33() { SERIAL_ECHOLNPGM("G33 Auto Calibrate"); // Report settings - PGM_P const checkingac = PSTR("Checking... AC"); - SERIAL_ECHOPGM_P(checkingac); + FSTR_P const checkingac = F("Checking... AC"); + SERIAL_ECHOF(checkingac); SERIAL_ECHOPGM(" at radius:", dcr); if (verbose_level == 0) SERIAL_ECHOPGM(" (DRY-RUN)"); SERIAL_EOL(); @@ -476,6 +477,25 @@ void GcodeSuite::G33() { if (!_0p_calibration) ac_home(); + #if HAS_DELTA_SENSORLESS_PROBING + if (verbose_level > 0 && do_save_offset_adj) { + offset_sensorless_adj.reset(); + + auto caltower = [&](Probe::sense_bool_t s){ + float z_at_pt[NPP + 1]; + LOOP_CAL_ALL(rad) z_at_pt[rad] = 0.0f; + probe.test_sensitivity = s; + if (probe_calibration_points(z_at_pt, 1, dcr, false, false, probe_at_offset)) + probe.set_offset_sensorless_adj(z_at_pt[CEN]); + }; + caltower({ true, false, false }); // A + caltower({ false, true, false }); // B + caltower({ false, false, true }); // C + + probe.test_sensitivity = { true, true, true }; // reset to all + } + #endif + do { // start iterations float z_at_pt[NPP + 1] = { 0.0f }; @@ -537,7 +557,7 @@ void GcodeSuite::G33() { case 1: test_precision = 0.0f; // forced end - LOOP_LINEAR_AXES(axis) e_delta[axis] = +Z4(CEN); + LOOP_NUM_AXES(axis) e_delta[axis] = +Z4(CEN); break; case 2: @@ -585,22 +605,31 @@ void GcodeSuite::G33() { // Normalize angles to least-squares if (_angle_results) { float a_sum = 0.0f; - LOOP_LINEAR_AXES(axis) a_sum += delta_tower_angle_trim[axis]; - LOOP_LINEAR_AXES(axis) delta_tower_angle_trim[axis] -= a_sum / 3.0f; + LOOP_NUM_AXES(axis) a_sum += delta_tower_angle_trim[axis]; + LOOP_NUM_AXES(axis) delta_tower_angle_trim[axis] -= a_sum / 3.0f; } // adjust delta_height and endstops by the max amount const float z_temp = _MAX(delta_endstop_adj.a, delta_endstop_adj.b, delta_endstop_adj.c); delta_height -= z_temp; - LOOP_LINEAR_AXES(axis) delta_endstop_adj[axis] -= z_temp; + LOOP_NUM_AXES(axis) delta_endstop_adj[axis] -= z_temp; } recalc_delta_settings(); NOMORE(zero_std_dev_min, zero_std_dev); // print report - if (verbose_level == 3 || verbose_level == 0) + if (verbose_level == 3 || verbose_level == 0) { print_calibration_results(z_at_pt, _tower_results, _opposite_results); + #if HAS_DELTA_SENSORLESS_PROBING + if (verbose_level == 0 && probe_points == 1) { + if (do_save_offset_adj) + probe.set_offset_sensorless_adj(z_at_pt[CEN]); + else + probe.refresh_largest_sensorless_adj(); + } + #endif + } if (verbose_level != 0) { // !dry run if ((zero_std_dev >= test_precision && iterations > force_iterations) || zero_std_dev <= calibration_precision) { // end iterations @@ -661,6 +690,9 @@ void GcodeSuite::G33() { ac_cleanup(TERN_(HAS_MULTI_HOTEND, old_tool_index)); TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_IDLE)); + #if HAS_DELTA_SENSORLESS_PROBING + probe.test_sensitivity = { true, true, true }; + #endif } #endif // DELTA_AUTO_CALIBRATION diff --git a/Marlin/src/gcode/calibrate/G34.cpp b/Marlin/src/gcode/calibrate/G34.cpp index 98a0bdef..9a0cb005 100644 --- a/Marlin/src/gcode/calibrate/G34.cpp +++ b/Marlin/src/gcode/calibrate/G34.cpp @@ -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 @@ -36,6 +39,23 @@ #define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE) #include "../../core/debug_out.h" +/** + * G34 - Align the ends of the X gantry. See https://youtu.be/3jAFQdTk8iw + * + * - The carriage moves to GANTRY_CALIBRATION_SAFE_POSITION, also called the “pounce” position. + * - If possible, the Z stepper current is reduced to the value specified by 'S' + * (or GANTRY_CALIBRATION_CURRENT) to prevent damage to steppers and other parts. + * The reduced current should be just high enough to move the Z axis when not blocked. + * - The Z axis is jogged past the Z limit, only as far as the specified Z distance + * (or GANTRY_CALIBRATION_EXTRA_HEIGHT) at the GANTRY_CALIBRATION_FEEDRATE. + * - The Z axis is moved back to the working area (also at GANTRY_CALIBRATION_FEEDRATE). + * - Stepper current is restored back to normal. + * - The machine is re-homed, according to GANTRY_CALIBRATION_COMMANDS_POST. + * + * Parameters: + * [S] - Current value to use for the raise move. (Default: GANTRY_CALIBRATION_CURRENT) + * [Z] - Extra distance past Z_MAX_POS to move the Z axis. (Default: GANTRY_CALIBRATION_EXTRA_HEIGHT) + */ void GcodeSuite::G34() { // Home before the alignment procedure @@ -55,7 +75,7 @@ void GcodeSuite::G34() { // Move XY to safe position if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Parking XY"); const xy_pos_t safe_pos = GANTRY_CALIBRATION_SAFE_POSITION; - do_blocking_move_to(safe_pos, MMM_TO_MMS(GANTRY_CALIBRATION_XY_PARK_FEEDRATE)); + do_blocking_move_to_xy(safe_pos, MMM_TO_MMS(GANTRY_CALIBRATION_XY_PARK_FEEDRATE)); #endif const float move_distance = parser.intval('Z', GANTRY_CALIBRATION_EXTRA_HEIGHT), @@ -79,7 +99,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); @@ -91,7 +111,7 @@ void GcodeSuite::G34() { digipot_i2c.set_current(Z_AXIS, target_current) #elif HAS_TRINAMIC_CONFIG const uint16_t target_current = parser.intval('S', GANTRY_CALIBRATION_CURRENT); - static uint16_t previous_current_arr[NUM_Z_STEPPER_DRIVERS]; + static uint16_t previous_current_arr[NUM_Z_STEPPERS]; #if AXIS_IS_TMC(Z) previous_current_arr[0] = stepperZ.getMilliamps(); stepperZ.rms_current(target_current); @@ -114,10 +134,6 @@ void GcodeSuite::G34() { if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Final Z Move"); do_blocking_move_to_z(zgrind, MMM_TO_MMS(GANTRY_CALIBRATION_FEEDRATE)); - // Back off end plate, back to normal motion range - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Z Backoff"); - do_blocking_move_to_z(zpounce, MMM_TO_MMS(GANTRY_CALIBRATION_FEEDRATE)); - #if _REDUCE_CURRENT // Reset current to original values if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Restore Current"); @@ -146,6 +162,10 @@ void GcodeSuite::G34() { #endif #endif + // Back off end plate, back to normal motion range + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Z Backoff"); + do_blocking_move_to_z(zpounce, MMM_TO_MMS(GANTRY_CALIBRATION_FEEDRATE)); + #ifdef GANTRY_CALIBRATION_COMMANDS_POST if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Running Post Commands"); process_subcommands_now(F(GANTRY_CALIBRATION_COMMANDS_POST)); diff --git a/Marlin/src/gcode/calibrate/G34_M422.cpp b/Marlin/src/gcode/calibrate/G34_M422.cpp index 328a40db..c137e07a 100644 --- a/Marlin/src/gcode/calibrate/G34_M422.cpp +++ b/Marlin/src/gcode/calibrate/G34_M422.cpp @@ -22,7 +22,7 @@ #include "../../inc/MarlinConfigPre.h" -#if EITHER(Z_MULTI_ENDSTOPS, Z_STEPPER_AUTO_ALIGN) +#if ANY(Z_MULTI_ENDSTOPS, Z_STEPPER_AUTO_ALIGN) #include "../../feature/z_stepper_align.h" @@ -41,7 +41,7 @@ #include "../../module/tool_change.h" #endif -#if ENABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS) +#if HAS_Z_STEPPER_ALIGN_STEPPER_XY #include "../../libs/least_squares_fit.h" #endif @@ -52,9 +52,9 @@ #define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE) #include "../../core/debug_out.h" -#if NUM_Z_STEPPER_DRIVERS >= 3 +#if NUM_Z_STEPPERS >= 3 #define TRIPLE_Z 1 - #if NUM_Z_STEPPER_DRIVERS >= 4 + #if NUM_Z_STEPPERS >= 4 #define QUAD_Z 1 #endif #endif @@ -79,6 +79,7 @@ * R Flag to recalculate points based on current probe offsets */ void GcodeSuite::G34() { + DEBUG_SECTION(log_G34, "G34", DEBUGGING(LEVELING)); if (DEBUGGING(LEVELING)) log_machine_info(); @@ -108,6 +109,7 @@ void GcodeSuite::G34() { } #if ENABLED(Z_STEPPER_AUTO_ALIGN) + do { // break out on error const int8_t z_auto_align_iterations = parser.intval('I', Z_STEPPER_ALIGN_ITERATIONS); @@ -122,7 +124,7 @@ void GcodeSuite::G34() { break; } - const float z_auto_align_amplification = TERN(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS, Z_STEPPER_ALIGN_AMP, parser.floatval('A', Z_STEPPER_ALIGN_AMP)); + const float z_auto_align_amplification = TERN(HAS_Z_STEPPER_ALIGN_STEPPER_XY, Z_STEPPER_ALIGN_AMP, parser.floatval('A', Z_STEPPER_ALIGN_AMP)); if (!WITHIN(ABS(z_auto_align_amplification), 0.5f, 2.0f)) { SERIAL_ECHOLNPGM("?(A)mplification out of bounds (0.5-2.0)."); break; @@ -179,16 +181,16 @@ void GcodeSuite::G34() { // Now, the Z origin lies below the build plate. That allows to probe deeper, before run_z_probe throws an error. // This hack is un-done at the end of G34 - either by re-homing, or by using the probed heights of the last iteration. - #if DISABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS) - float last_z_align_move[NUM_Z_STEPPER_DRIVERS] = ARRAY_N_1(NUM_Z_STEPPER_DRIVERS, 10000.0f); + #if !HAS_Z_STEPPER_ALIGN_STEPPER_XY + float last_z_align_move[NUM_Z_STEPPERS] = ARRAY_N_1(NUM_Z_STEPPERS, 10000.0f); #else float last_z_align_level_indicator = 10000.0f; #endif - float z_measured[NUM_Z_STEPPER_DRIVERS] = { 0 }, + float z_measured[NUM_Z_STEPPERS] = { 0 }, z_maxdiff = 0.0f, amplification = z_auto_align_amplification; - #if DISABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS) + #if !HAS_Z_STEPPER_ALIGN_STEPPER_XY bool adjustment_reverse = false; #endif @@ -217,20 +219,22 @@ void GcodeSuite::G34() { float z_measured_max = -100000.0f; // Probe all positions (one per Z-Stepper) - LOOP_L_N(i, NUM_Z_STEPPER_DRIVERS) { + for (uint8_t i = 0; i < NUM_Z_STEPPERS; ++i) { // iteration odd/even --> downward / upward stepper sequence - const uint8_t iprobe = (iteration & 1) ? NUM_Z_STEPPER_DRIVERS - 1 - i : i; + const uint8_t iprobe = (iteration & 1) ? NUM_Z_STEPPERS - 1 - i : i; // Safe clearance even on an incline if ((iteration == 0 || i > 0) && z_probe > current_position.z) do_blocking_move_to_z(z_probe); + xy_pos_t &ppos = z_stepper_align.xy[iprobe]; + if (DEBUGGING(LEVELING)) - DEBUG_ECHOLNPGM_P(PSTR("Probing X"), z_stepper_align.xy[iprobe].x, SP_Y_STR, z_stepper_align.xy[iprobe].y); + DEBUG_ECHOLNPGM_P(PSTR("Probing X"), ppos.x, SP_Y_STR, ppos.y); // Probe a Z height for each stepper. // Probing sanity check is disabled, as it would trigger even in normal cases because // current_position.z has been manually altered in the "dirty trick" above. - const float z_probed_height = probe.probe_at_point(z_stepper_align.xy[iprobe], raise_after, 0, true, false); + const float z_probed_height = probe.probe_at_point(DIFF_TERN(HAS_HOME_OFFSET, ppos, xy_pos_t(home_offset)), raise_after, 0, true, false); if (isnan(z_probed_height)) { SERIAL_ECHOLNPGM("Probing failed"); LCD_MESSAGE(MSG_LCD_PROBING_FAILED); @@ -240,7 +244,7 @@ void GcodeSuite::G34() { // Add height to each value, to provide a more useful target height for // the next iteration of probing. This allows adjustments to be made away from the bed. - z_measured[iprobe] = z_probed_height + Z_CLEARANCE_BETWEEN_PROBES; + z_measured[iprobe] = z_probed_height + (Z_CLEARANCE_BETWEEN_PROBES); if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("> Z", iprobe + 1, " measured position is ", z_measured[iprobe]); @@ -256,7 +260,7 @@ void GcodeSuite::G34() { z_maxdiff = z_measured_max - z_measured_min; z_probe = Z_BASIC_CLEARANCE + z_measured_max + z_maxdiff; - #if ENABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS) + #if HAS_Z_STEPPER_ALIGN_STEPPER_XY // Replace the initial values in z_measured with calculated heights at // each stepper position. This allows the adjustment algorithm to be // shared between both possible probing mechanisms. @@ -270,20 +274,20 @@ void GcodeSuite::G34() { // This allows the actual adjustment logic to be shared by both algorithms. linear_fit_data lfd; incremental_LSF_reset(&lfd); - LOOP_L_N(i, NUM_Z_STEPPER_DRIVERS) { + for (uint8_t i = 0; i < NUM_Z_STEPPERS; ++i) { SERIAL_ECHOLNPGM("PROBEPT_", i, ": ", z_measured[i]); incremental_LSF(&lfd, z_stepper_align.xy[i], z_measured[i]); } finish_incremental_LSF(&lfd); z_measured_min = 100000.0f; - LOOP_L_N(i, NUM_Z_STEPPER_DRIVERS) { + for (uint8_t i = 0; i < NUM_Z_STEPPERS; ++i) { z_measured[i] = -(lfd.A * z_stepper_align.stepper_xy[i].x + lfd.B * z_stepper_align.stepper_xy[i].y + lfd.D); z_measured_min = _MIN(z_measured_min, z_measured[i]); } SERIAL_ECHOLNPGM( - LIST_N(DOUBLE(NUM_Z_STEPPER_DRIVERS), + LIST_N(DOUBLE(NUM_Z_STEPPERS), "Calculated Z1=", z_measured[0], " Z2=", z_measured[1], " Z3=", z_measured[2], @@ -307,7 +311,7 @@ void GcodeSuite::G34() { #if HAS_STATUS_MESSAGE char fstr1[10]; - char msg[6 + (6 + 5) * NUM_Z_STEPPER_DRIVERS + 1] + char msg[6 + (6 + 5) * NUM_Z_STEPPERS + 1] #if TRIPLE_Z , fstr2[10], fstr3[10] #if QUAD_Z @@ -338,19 +342,19 @@ void GcodeSuite::G34() { return false; }; - #if ENABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS) + #if HAS_Z_STEPPER_ALIGN_STEPPER_XY // Check if the applied corrections go in the correct direction. // Calculate the sum of the absolute deviations from the mean of the probe measurements. // Compare to the last iteration to ensure it's getting better. // Calculate mean value as a reference float z_measured_mean = 0.0f; - LOOP_L_N(zstepper, NUM_Z_STEPPER_DRIVERS) z_measured_mean += z_measured[zstepper]; - z_measured_mean /= NUM_Z_STEPPER_DRIVERS; + for (uint8_t zstepper = 0; zstepper < NUM_Z_STEPPERS; ++zstepper) z_measured_mean += z_measured[zstepper]; + z_measured_mean /= NUM_Z_STEPPERS; // Calculate the sum of the absolute deviations from the mean value float z_align_level_indicator = 0.0f; - LOOP_L_N(zstepper, NUM_Z_STEPPER_DRIVERS) + for (uint8_t zstepper = 0; zstepper < NUM_Z_STEPPERS; ++zstepper) z_align_level_indicator += ABS(z_measured[zstepper] - z_measured_mean); // If it's getting worse, stop and throw an error @@ -365,12 +369,12 @@ void GcodeSuite::G34() { bool success_break = true; // Correct the individual stepper offsets - LOOP_L_N(zstepper, NUM_Z_STEPPER_DRIVERS) { + for (uint8_t zstepper = 0; zstepper < NUM_Z_STEPPERS; ++zstepper) { // Calculate current stepper move float z_align_move = z_measured[zstepper] - z_measured_min; const float z_align_abs = ABS(z_align_move); - #if DISABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS) + #if !HAS_Z_STEPPER_ALIGN_STEPPER_XY // Optimize one iteration's correction based on the first measurements if (z_align_abs) amplification = (iteration == 1) ? _MIN(last_z_align_move[zstepper] / z_align_abs, 2.0f) : z_auto_align_amplification; @@ -394,7 +398,7 @@ void GcodeSuite::G34() { // Lock all steppers except one stepper.set_all_z_lock(true, zstepper); - #if DISABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS) + #if !HAS_Z_STEPPER_ALIGN_STEPPER_XY // Decreasing accuracy was detected so move was inverted. // Will match reversed Z steppers on dual steppers. Triple will need more work to map. if (adjustment_reverse) { @@ -442,14 +446,14 @@ void GcodeSuite::G34() { // Use the probed height from the last iteration to determine the Z height. // z_measured_min is used, because all steppers are aligned to z_measured_min. // Ideally, this would be equal to the 'z_probe * 0.5f' which was added earlier. - current_position.z -= z_measured_min - (float)Z_CLEARANCE_BETWEEN_PROBES; + current_position.z -= z_measured_min - float(Z_CLEARANCE_BETWEEN_PROBES); sync_plan_position(); #endif // Restore the active tool after homing TERN_(HAS_MULTI_HOTEND, tool_change(old_tool_index, DISABLED(PARKING_EXTRUDER))); // Fetch previous tool for parking extruder - #if BOTH(HAS_LEVELING, RESTORE_LEVELING_AFTER_G34) + #if ALL(HAS_LEVELING, RESTORE_LEVELING_AFTER_G34) set_bed_leveling_enabled(leveling_was_active); #endif @@ -467,7 +471,7 @@ void GcodeSuite::G34() { * * S : Index of the probe point to set * - * With Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS: + * With Z_STEPPER_ALIGN_STEPPER_XY: * W : Index of the Z stepper position to set * The W and S parameters may not be combined. * @@ -486,42 +490,43 @@ void GcodeSuite::M422() { return; } - const bool is_probe_point = parser.seen('S'); + const bool is_probe_point = parser.seen_test('S'); - if (TERN0(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS, is_probe_point && parser.seen('W'))) { + if (TERN0(HAS_Z_STEPPER_ALIGN_STEPPER_XY, is_probe_point && parser.seen_test('W'))) { SERIAL_ECHOLNPGM("?(S) and (W) may not be combined."); return; } - xy_pos_t *pos_dest = ( - TERN_(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS, !is_probe_point ? z_stepper_align.stepper_xy :) + xy_pos_t * const pos_dest = ( + TERN_(HAS_Z_STEPPER_ALIGN_STEPPER_XY, !is_probe_point ? z_stepper_align.stepper_xy :) z_stepper_align.xy ); - if (!is_probe_point && TERN1(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS, !parser.seen('W'))) { - SERIAL_ECHOLNPGM("?(S)" TERN_(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS, " or (W)") " is required."); + if (!is_probe_point && TERN1(HAS_Z_STEPPER_ALIGN_STEPPER_XY, !parser.seen_test('W'))) { + SERIAL_ECHOLNPGM("?(S)" TERN_(HAS_Z_STEPPER_ALIGN_STEPPER_XY, " or (W)") " is required."); return; } // Get the Probe Position Index or Z Stepper Index - int8_t position_index; - if (is_probe_point) { - position_index = parser.intval('S') - 1; - if (!WITHIN(position_index, 0, int8_t(NUM_Z_STEPPER_DRIVERS) - 1)) { - SERIAL_ECHOLNPGM("?(S) Probe-position index invalid."); - return; - } - } + int8_t position_index = 1; + FSTR_P err_string = F("?(S) Probe-position"); + if (is_probe_point) + position_index = parser.intval('S'); else { - #if ENABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS) - position_index = parser.intval('W') - 1; - if (!WITHIN(position_index, 0, NUM_Z_STEPPER_DRIVERS - 1)) { - SERIAL_ECHOLNPGM("?(W) Z-stepper index invalid."); - return; - } + #if HAS_Z_STEPPER_ALIGN_STEPPER_XY + err_string = F("?(W) Z-stepper"); + position_index = parser.intval('W'); #endif } + if (!WITHIN(position_index, 1, NUM_Z_STEPPERS)) { + SERIAL_ECHOF(err_string); + SERIAL_ECHOLNPGM(" index invalid (1.." STRINGIFY(NUM_Z_STEPPERS) ")."); + return; + } + + --position_index; + const xy_pos_t pos = { parser.floatval('X', pos_dest[position_index].x), parser.floatval('Y', pos_dest[position_index].y) @@ -543,7 +548,7 @@ void GcodeSuite::M422() { void GcodeSuite::M422_report(const bool forReplay/*=true*/) { report_heading(forReplay, F(STR_Z_AUTO_ALIGN)); - LOOP_L_N(i, NUM_Z_STEPPER_DRIVERS) { + for (uint8_t i = 0; i < NUM_Z_STEPPERS; ++i) { report_echo_start(forReplay); SERIAL_ECHOLNPGM_P( PSTR(" M422 S"), i + 1, @@ -551,8 +556,8 @@ void GcodeSuite::M422_report(const bool forReplay/*=true*/) { SP_Y_STR, z_stepper_align.xy[i].y ); } - #if ENABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS) - LOOP_L_N(i, NUM_Z_STEPPER_DRIVERS) { + #if HAS_Z_STEPPER_ALIGN_STEPPER_XY + for (uint8_t i = 0; i < NUM_Z_STEPPERS; ++i) { report_echo_start(forReplay); SERIAL_ECHOLNPGM_P( PSTR(" M422 W"), i + 1, diff --git a/Marlin/src/gcode/calibrate/G425.cpp b/Marlin/src/gcode/calibrate/G425.cpp index 88c906f4..992d7c38 100644 --- a/Marlin/src/gcode/calibrate/G425.cpp +++ b/Marlin/src/gcode/calibrate/G425.cpp @@ -33,10 +33,13 @@ #include "../../lcd/marlinui.h" #include "../../module/motion.h" #include "../../module/planner.h" -#include "../../module/tool_change.h" #include "../../module/endstops.h" #include "../../feature/bedlevel/bedlevel.h" +#if HAS_MULTI_HOTEND + #include "../../module/tool_change.h" +#endif + #if !AXIS_CAN_CALIBRATE(X) #undef CALIBRATION_MEASURE_LEFT #undef CALIBRATION_MEASURE_RIGHT @@ -70,25 +73,34 @@ #define CALIBRATION_MEASUREMENT_CERTAIN 0.5 // mm #endif -#if BOTH(CALIBRATION_MEASURE_LEFT, CALIBRATION_MEASURE_RIGHT) +#if ALL(HAS_X_AXIS, CALIBRATION_MEASURE_LEFT, CALIBRATION_MEASURE_RIGHT) #define HAS_X_CENTER 1 #endif -#if HAS_Y_AXIS && BOTH(CALIBRATION_MEASURE_FRONT, CALIBRATION_MEASURE_BACK) +#if ALL(HAS_Y_AXIS, CALIBRATION_MEASURE_FRONT, CALIBRATION_MEASURE_BACK) #define HAS_Y_CENTER 1 #endif -#if LINEAR_AXES >= 4 && BOTH(CALIBRATION_MEASURE_IMIN, CALIBRATION_MEASURE_IMAX) +#if ALL(HAS_I_AXIS, CALIBRATION_MEASURE_IMIN, CALIBRATION_MEASURE_IMAX) #define HAS_I_CENTER 1 #endif -#if LINEAR_AXES >= 5 && BOTH(CALIBRATION_MEASURE_JMIN, CALIBRATION_MEASURE_JMAX) +#if ALL(HAS_J_AXIS, CALIBRATION_MEASURE_JMIN, CALIBRATION_MEASURE_JMAX) #define HAS_J_CENTER 1 #endif -#if LINEAR_AXES >= 6 && BOTH(CALIBRATION_MEASURE_KMIN, CALIBRATION_MEASURE_KMAX) +#if ALL(HAS_K_AXIS, CALIBRATION_MEASURE_KMIN, CALIBRATION_MEASURE_KMAX) #define HAS_K_CENTER 1 #endif +#if ALL(HAS_U_AXIS, CALIBRATION_MEASURE_UMIN, CALIBRATION_MEASURE_UMAX) + #define HAS_U_CENTER 1 +#endif +#if ALL(HAS_V_AXIS, CALIBRATION_MEASURE_VMIN, CALIBRATION_MEASURE_VMAX) + #define HAS_V_CENTER 1 +#endif +#if ALL(HAS_W_AXIS, CALIBRATION_MEASURE_WMIN, CALIBRATION_MEASURE_WMAX) + #define HAS_W_CENTER 1 +#endif 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, UMINIMUM, UMAXIMUM, VMINIMUM, VMAXIMUM, WMINIMUM, WMAXIMUM) }; static constexpr xyz_pos_t true_center CALIBRATION_OBJECT_CENTER; @@ -105,13 +117,27 @@ struct measurements_t { }; #if ENABLED(BACKLASH_GCODE) - #define TEMPORARY_BACKLASH_CORRECTION(value) REMEMBER(tbst, backlash.correction, value) + class restorer_correction { + const uint8_t val_; + public: + restorer_correction(const uint8_t temp_val) : val_(backlash.get_correction_uint8()) { backlash.set_correction_uint8(temp_val); } + ~restorer_correction() { backlash.set_correction_uint8(val_); } + }; + + #define TEMPORARY_BACKLASH_CORRECTION(value) restorer_correction restorer_tbst(value) #else #define TEMPORARY_BACKLASH_CORRECTION(value) #endif #if ENABLED(BACKLASH_GCODE) && defined(BACKLASH_SMOOTHING_MM) - #define TEMPORARY_BACKLASH_SMOOTHING(value) REMEMBER(tbsm, backlash.smoothing_mm, value) + class restorer_smoothing { + const float val_; + public: + restorer_smoothing(const float temp_val) : val_(backlash.get_smoothing_mm()) { backlash.set_smoothing_mm(temp_val); } + ~restorer_smoothing() { backlash.set_smoothing_mm(val_); } + }; + + #define TEMPORARY_BACKLASH_SMOOTHING(value) restorer_smoothing restorer_tbsm(value) #else #define TEMPORARY_BACKLASH_SMOOTHING(value) #endif @@ -148,7 +174,7 @@ inline void park_above_object(measurements_t &m, const float uncertainty) { #if HAS_HOTEND_OFFSET inline void normalize_hotend_offsets() { - LOOP_S_L_N(e, 1, HOTENDS) + for (uint8_t e = 1; e < HOTENDS; ++e) hotend_offset[e] -= hotend_offset[0]; hotend_offset[0].reset(); } @@ -241,16 +267,17 @@ inline void probe_side(measurements_t &m, const float uncertainty, const side_t park_above_object(m, uncertainty); + #define _ACASE(N,A,B) case A: dir = -1; case B: axis = N##_AXIS; break + #define _PCASE(N) _ACASE(N, N##MINIMUM, N##MAXIMUM) + switch (side) { #if AXIS_CAN_CALIBRATE(X) - case RIGHT: dir = -1; - case LEFT: axis = X_AXIS; break; + _ACASE(X, RIGHT, LEFT); #endif - #if LINEAR_AXES >= 2 && AXIS_CAN_CALIBRATE(Y) - case BACK: dir = -1; - case FRONT: axis = Y_AXIS; break; + #if AXIS_CAN_CALIBRATE(Y) + _ACASE(Y, BACK, FRONT); #endif - #if HAS_Z_AXIS && AXIS_CAN_CALIBRATE(Z) + #if AXIS_CAN_CALIBRATE(Z) case TOP: { const float measurement = measure(Z_AXIS, -1, true, &m.backlash[TOP], uncertainty); m.obj_center.z = measurement - dimensions.z / 2; @@ -258,17 +285,23 @@ inline void probe_side(measurements_t &m, const float uncertainty, const side_t return; } #endif - #if LINEAR_AXES >= 4 && AXIS_CAN_CALIBRATE(I) - case IMINIMUM: dir = -1; - case IMAXIMUM: axis = I_AXIS; break; + #if AXIS_CAN_CALIBRATE(I) + _PCASE(I); + #endif + #if AXIS_CAN_CALIBRATE(J) + _PCASE(J); + #endif + #if AXIS_CAN_CALIBRATE(K) + _PCASE(K); #endif - #if LINEAR_AXES >= 5 && AXIS_CAN_CALIBRATE(J) - case JMINIMUM: dir = -1; - case JMAXIMUM: axis = J_AXIS; break; + #if AXIS_CAN_CALIBRATE(U) + _PCASE(U); #endif - #if LINEAR_AXES >= 6 && AXIS_CAN_CALIBRATE(K) - case KMINIMUM: dir = -1; - case KMAXIMUM: axis = K_AXIS; break; + #if AXIS_CAN_CALIBRATE(V) + _PCASE(V); + #endif + #if AXIS_CAN_CALIBRATE(W) + _PCASE(W); #endif default: return; } @@ -323,6 +356,12 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { TERN_(CALIBRATION_MEASURE_JMAX, probe_side(m, uncertainty, JMAXIMUM, probe_top_at_edge)); TERN_(CALIBRATION_MEASURE_KMIN, probe_side(m, uncertainty, KMINIMUM, probe_top_at_edge)); TERN_(CALIBRATION_MEASURE_KMAX, probe_side(m, uncertainty, KMAXIMUM, probe_top_at_edge)); + TERN_(CALIBRATION_MEASURE_UMIN, probe_side(m, uncertainty, UMINIMUM, probe_top_at_edge)); + TERN_(CALIBRATION_MEASURE_UMAX, probe_side(m, uncertainty, UMAXIMUM, probe_top_at_edge)); + TERN_(CALIBRATION_MEASURE_VMIN, probe_side(m, uncertainty, VMINIMUM, probe_top_at_edge)); + TERN_(CALIBRATION_MEASURE_VMAX, probe_side(m, uncertainty, VMAXIMUM, probe_top_at_edge)); + TERN_(CALIBRATION_MEASURE_WMIN, probe_side(m, uncertainty, WMINIMUM, probe_top_at_edge)); + TERN_(CALIBRATION_MEASURE_WMAX, probe_side(m, uncertainty, WMAXIMUM, probe_top_at_edge)); // Compute the measured center of the calibration object. TERN_(HAS_X_CENTER, m.obj_center.x = (m.obj_side[LEFT] + m.obj_side[RIGHT]) / 2); @@ -330,6 +369,9 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { TERN_(HAS_I_CENTER, m.obj_center.i = (m.obj_side[IMINIMUM] + m.obj_side[IMAXIMUM]) / 2); TERN_(HAS_J_CENTER, m.obj_center.j = (m.obj_side[JMINIMUM] + m.obj_side[JMAXIMUM]) / 2); TERN_(HAS_K_CENTER, m.obj_center.k = (m.obj_side[KMINIMUM] + m.obj_side[KMAXIMUM]) / 2); + TERN_(HAS_U_CENTER, m.obj_center.u = (m.obj_side[UMINIMUM] + m.obj_side[UMAXIMUM]) / 2); + TERN_(HAS_V_CENTER, m.obj_center.v = (m.obj_side[VMINIMUM] + m.obj_side[VMAXIMUM]) / 2); + TERN_(HAS_W_CENTER, m.obj_center.w = (m.obj_side[WMINIMUM] + m.obj_side[WMAXIMUM]) / 2); // Compute the outside diameter of the nozzle at the height // at which it makes contact with the calibration object @@ -340,27 +382,32 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { // The difference between the known and the measured location // of the calibration object is the positional error - LINEAR_AXIS_CODE( + NUM_AXIS_CODE( m.pos_error.x = TERN0(HAS_X_CENTER, true_center.x - m.obj_center.x), m.pos_error.y = TERN0(HAS_Y_CENTER, true_center.y - m.obj_center.y), m.pos_error.z = true_center.z - m.obj_center.z, m.pos_error.i = TERN0(HAS_I_CENTER, true_center.i - m.obj_center.i), m.pos_error.j = TERN0(HAS_J_CENTER, true_center.j - m.obj_center.j), - m.pos_error.k = TERN0(HAS_K_CENTER, true_center.k - m.obj_center.k) + m.pos_error.k = TERN0(HAS_K_CENTER, true_center.k - m.obj_center.k), + m.pos_error.u = TERN0(HAS_U_CENTER, true_center.u - m.obj_center.u), + m.pos_error.v = TERN0(HAS_V_CENTER, true_center.v - m.obj_center.v), + m.pos_error.w = TERN0(HAS_W_CENTER, true_center.w - m.obj_center.w) ); } #if ENABLED(CALIBRATION_REPORTING) inline void report_measured_faces(const measurements_t &m) { SERIAL_ECHOLNPGM("Sides:"); - #if HAS_Z_AXIS && AXIS_CAN_CALIBRATE(Z) + #if AXIS_CAN_CALIBRATE(Z) SERIAL_ECHOLNPGM(" Top: ", m.obj_side[TOP]); #endif - #if ENABLED(CALIBRATION_MEASURE_LEFT) - SERIAL_ECHOLNPGM(" Left: ", m.obj_side[LEFT]); - #endif - #if ENABLED(CALIBRATION_MEASURE_RIGHT) - SERIAL_ECHOLNPGM(" Right: ", m.obj_side[RIGHT]); + #if HAS_X_AXIS + #if ENABLED(CALIBRATION_MEASURE_LEFT) + SERIAL_ECHOLNPGM(" Left: ", m.obj_side[LEFT]); + #endif + #if ENABLED(CALIBRATION_MEASURE_RIGHT) + SERIAL_ECHOLNPGM(" Right: ", m.obj_side[RIGHT]); + #endif #endif #if HAS_Y_AXIS #if ENABLED(CALIBRATION_MEASURE_FRONT) @@ -370,7 +417,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { SERIAL_ECHOLNPGM(" Back: ", m.obj_side[BACK]); #endif #endif - #if LINEAR_AXES >= 4 + #if HAS_I_AXIS #if ENABLED(CALIBRATION_MEASURE_IMIN) SERIAL_ECHOLNPGM(" " STR_I_MIN ": ", m.obj_side[IMINIMUM]); #endif @@ -378,7 +425,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { SERIAL_ECHOLNPGM(" " STR_I_MAX ": ", m.obj_side[IMAXIMUM]); #endif #endif - #if LINEAR_AXES >= 5 + #if HAS_J_AXIS #if ENABLED(CALIBRATION_MEASURE_JMIN) SERIAL_ECHOLNPGM(" " STR_J_MIN ": ", m.obj_side[JMINIMUM]); #endif @@ -386,7 +433,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { SERIAL_ECHOLNPGM(" " STR_J_MAX ": ", m.obj_side[JMAXIMUM]); #endif #endif - #if LINEAR_AXES >= 6 + #if HAS_K_AXIS #if ENABLED(CALIBRATION_MEASURE_KMIN) SERIAL_ECHOLNPGM(" " STR_K_MIN ": ", m.obj_side[KMINIMUM]); #endif @@ -394,6 +441,30 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { SERIAL_ECHOLNPGM(" " STR_K_MAX ": ", m.obj_side[KMAXIMUM]); #endif #endif + #if HAS_U_AXIS + #if ENABLED(CALIBRATION_MEASURE_UMIN) + SERIAL_ECHOLNPGM(" " STR_U_MIN ": ", m.obj_side[UMINIMUM]); + #endif + #if ENABLED(CALIBRATION_MEASURE_UMAX) + SERIAL_ECHOLNPGM(" " STR_U_MAX ": ", m.obj_side[UMAXIMUM]); + #endif + #endif + #if HAS_V_AXIS + #if ENABLED(CALIBRATION_MEASURE_VMIN) + SERIAL_ECHOLNPGM(" " STR_V_MIN ": ", m.obj_side[VMINIMUM]); + #endif + #if ENABLED(CALIBRATION_MEASURE_VMAX) + SERIAL_ECHOLNPGM(" " STR_V_MAX ": ", m.obj_side[VMAXIMUM]); + #endif + #endif + #if HAS_W_AXIS + #if ENABLED(CALIBRATION_MEASURE_WMIN) + SERIAL_ECHOLNPGM(" " STR_W_MIN ": ", m.obj_side[WMINIMUM]); + #endif + #if ENABLED(CALIBRATION_MEASURE_WMAX) + SERIAL_ECHOLNPGM(" " STR_W_MAX ": ", m.obj_side[WMAXIMUM]); + #endif + #endif SERIAL_EOL(); } @@ -415,6 +486,15 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { #if HAS_K_CENTER SERIAL_ECHOLNPGM_P(SP_K_STR, m.obj_center.k); #endif + #if HAS_U_CENTER + SERIAL_ECHOLNPGM_P(SP_U_STR, m.obj_center.u); + #endif + #if HAS_V_CENTER + SERIAL_ECHOLNPGM_P(SP_V_STR, m.obj_center.v); + #endif + #if HAS_W_CENTER + SERIAL_ECHOLNPGM_P(SP_W_STR, m.obj_center.w); + #endif SERIAL_EOL(); } @@ -428,7 +508,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { SERIAL_ECHOLNPGM(" Right: ", m.backlash[RIGHT]); #endif #endif - #if HAS_Y_AXIS && AXIS_CAN_CALIBRATE(Y) + #if AXIS_CAN_CALIBRATE(Y) #if ENABLED(CALIBRATION_MEASURE_FRONT) SERIAL_ECHOLNPGM(" Front: ", m.backlash[FRONT]); #endif @@ -436,10 +516,10 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { SERIAL_ECHOLNPGM(" Back: ", m.backlash[BACK]); #endif #endif - #if HAS_Z_AXIS && AXIS_CAN_CALIBRATE(Z) + #if AXIS_CAN_CALIBRATE(Z) SERIAL_ECHOLNPGM(" Top: ", m.backlash[TOP]); #endif - #if LINEAR_AXES >= 4 && AXIS_CAN_CALIBRATE(I) + #if AXIS_CAN_CALIBRATE(I) #if ENABLED(CALIBRATION_MEASURE_IMIN) SERIAL_ECHOLNPGM(" " STR_I_MIN ": ", m.backlash[IMINIMUM]); #endif @@ -447,7 +527,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { SERIAL_ECHOLNPGM(" " STR_I_MAX ": ", m.backlash[IMAXIMUM]); #endif #endif - #if LINEAR_AXES >= 5 && AXIS_CAN_CALIBRATE(J) + #if AXIS_CAN_CALIBRATE(J) #if ENABLED(CALIBRATION_MEASURE_JMIN) SERIAL_ECHOLNPGM(" " STR_J_MIN ": ", m.backlash[JMINIMUM]); #endif @@ -455,7 +535,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { SERIAL_ECHOLNPGM(" " STR_J_MAX ": ", m.backlash[JMAXIMUM]); #endif #endif - #if LINEAR_AXES >= 6 && AXIS_CAN_CALIBRATE(K) + #if AXIS_CAN_CALIBRATE(K) #if ENABLED(CALIBRATION_MEASURE_KMIN) SERIAL_ECHOLNPGM(" " STR_K_MIN ": ", m.backlash[KMINIMUM]); #endif @@ -463,6 +543,30 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { SERIAL_ECHOLNPGM(" " STR_K_MAX ": ", m.backlash[KMAXIMUM]); #endif #endif + #if AXIS_CAN_CALIBRATE(U) + #if ENABLED(CALIBRATION_MEASURE_UMIN) + SERIAL_ECHOLNPGM(" " STR_U_MIN ": ", m.backlash[UMINIMUM]); + #endif + #if ENABLED(CALIBRATION_MEASURE_UMAX) + SERIAL_ECHOLNPGM(" " STR_U_MAX ": ", m.backlash[UMAXIMUM]); + #endif + #endif + #if AXIS_CAN_CALIBRATE(V) + #if ENABLED(CALIBRATION_MEASURE_VMIN) + SERIAL_ECHOLNPGM(" " STR_V_MIN ": ", m.backlash[VMINIMUM]); + #endif + #if ENABLED(CALIBRATION_MEASURE_VMAX) + SERIAL_ECHOLNPGM(" " STR_V_MAX ": ", m.backlash[VMAXIMUM]); + #endif + #endif + #if AXIS_CAN_CALIBRATE(W) + #if ENABLED(CALIBRATION_MEASURE_WMIN) + SERIAL_ECHOLNPGM(" " STR_W_MIN ": ", m.backlash[WMINIMUM]); + #endif + #if ENABLED(CALIBRATION_MEASURE_WMAX) + SERIAL_ECHOLNPGM(" " STR_W_MAX ": ", m.backlash[WMAXIMUM]); + #endif + #endif SERIAL_EOL(); } @@ -476,7 +580,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { #if HAS_Y_CENTER && AXIS_CAN_CALIBRATE(Y) SERIAL_ECHOLNPGM_P(SP_Y_STR, m.pos_error.y); #endif - #if HAS_Z_AXIS && AXIS_CAN_CALIBRATE(Z) + #if AXIS_CAN_CALIBRATE(Z) SERIAL_ECHOLNPGM_P(SP_Z_STR, m.pos_error.z); #endif #if HAS_I_CENTER && AXIS_CAN_CALIBRATE(I) @@ -486,7 +590,16 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { SERIAL_ECHOLNPGM_P(SP_J_STR, m.pos_error.j); #endif #if HAS_K_CENTER && AXIS_CAN_CALIBRATE(K) - SERIAL_ECHOLNPGM_P(SP_Z_STR, m.pos_error.z); + SERIAL_ECHOLNPGM_P(SP_K_STR, m.pos_error.k); + #endif + #if HAS_U_CENTER && AXIS_CAN_CALIBRATE(U) + SERIAL_ECHOLNPGM_P(SP_U_STR, m.pos_error.u); + #endif + #if HAS_V_CENTER && AXIS_CAN_CALIBRATE(V) + SERIAL_ECHOLNPGM_P(SP_V_STR, m.pos_error.v); + #endif + #if HAS_W_CENTER && AXIS_CAN_CALIBRATE(W) + SERIAL_ECHOLNPGM_P(SP_W_STR, m.pos_error.w); #endif SERIAL_EOL(); } @@ -508,7 +621,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { // This function requires normalize_hotend_offsets() to be called // inline void report_hotend_offsets() { - LOOP_S_L_N(e, 1, HOTENDS) + for (uint8_t e = 1; e < HOTENDS; ++e) SERIAL_ECHOLNPGM_P(PSTR("T"), e, PSTR(" Hotend Offset X"), hotend_offset[e].x, SP_Y_STR, hotend_offset[e].y, SP_Z_STR, hotend_offset[e].z); } #endif @@ -526,7 +639,7 @@ inline void calibrate_backlash(measurements_t &m, const float uncertainty) { { // New scope for TEMPORARY_BACKLASH_CORRECTION - TEMPORARY_BACKLASH_CORRECTION(all_off); + TEMPORARY_BACKLASH_CORRECTION(backlash.all_off); TEMPORARY_BACKLASH_SMOOTHING(0.0f); probe_sides(m, uncertainty); @@ -534,45 +647,69 @@ inline void calibrate_backlash(measurements_t &m, const float uncertainty) { #if ENABLED(BACKLASH_GCODE) #if HAS_X_CENTER - backlash.distance_mm.x = (m.backlash[LEFT] + m.backlash[RIGHT]) / 2; + backlash.set_distance_mm(X_AXIS, (m.backlash[LEFT] + m.backlash[RIGHT]) / 2); #elif ENABLED(CALIBRATION_MEASURE_LEFT) - backlash.distance_mm.x = m.backlash[LEFT]; + backlash.set_distance_mm(X_AXIS, m.backlash[LEFT]); #elif ENABLED(CALIBRATION_MEASURE_RIGHT) - backlash.distance_mm.x = m.backlash[RIGHT]; + backlash.set_distance_mm(X_AXIS, m.backlash[RIGHT]); #endif #if HAS_Y_CENTER - backlash.distance_mm.y = (m.backlash[FRONT] + m.backlash[BACK]) / 2; + backlash.set_distance_mm(Y_AXIS, (m.backlash[FRONT] + m.backlash[BACK]) / 2); #elif ENABLED(CALIBRATION_MEASURE_FRONT) - backlash.distance_mm.y = m.backlash[FRONT]; + backlash.set_distance_mm(Y_AXIS, m.backlash[FRONT]); #elif ENABLED(CALIBRATION_MEASURE_BACK) - backlash.distance_mm.y = m.backlash[BACK]; + backlash.set_distance_mm(Y_AXIS, m.backlash[BACK]); #endif - TERN_(HAS_Z_AXIS, if (AXIS_CAN_CALIBRATE(Z)) backlash.distance_mm.z = m.backlash[TOP]); + TERN_(HAS_Z_AXIS, if (AXIS_CAN_CALIBRATE(Z)) backlash.set_distance_mm(Z_AXIS, m.backlash[TOP])); #if HAS_I_CENTER - backlash.distance_mm.i = (m.backlash[IMINIMUM] + m.backlash[IMAXIMUM]) / 2; + backlash.set_distance_mm(I_AXIS, (m.backlash[IMINIMUM] + m.backlash[IMAXIMUM]) / 2); #elif ENABLED(CALIBRATION_MEASURE_IMIN) - backlash.distance_mm.i = m.backlash[IMINIMUM]; + backlash.set_distance_mm(I_AXIS, m.backlash[IMINIMUM]); #elif ENABLED(CALIBRATION_MEASURE_IMAX) - backlash.distance_mm.i = m.backlash[IMAXIMUM]; + backlash.set_distance_mm(I_AXIS, m.backlash[IMAXIMUM]); #endif #if HAS_J_CENTER - backlash.distance_mm.j = (m.backlash[JMINIMUM] + m.backlash[JMAXIMUM]) / 2; + backlash.set_distance_mm(J_AXIS, (m.backlash[JMINIMUM] + m.backlash[JMAXIMUM]) / 2); #elif ENABLED(CALIBRATION_MEASURE_JMIN) - backlash.distance_mm.j = m.backlash[JMINIMUM]; + backlash.set_distance_mm(J_AXIS, m.backlash[JMINIMUM]); #elif ENABLED(CALIBRATION_MEASURE_JMAX) - backlash.distance_mm.j = m.backlash[JMAXIMUM]; + backlash.set_distance_mm(J_AXIS, m.backlash[JMAXIMUM]); #endif #if HAS_K_CENTER - backlash.distance_mm.k = (m.backlash[KMINIMUM] + m.backlash[KMAXIMUM]) / 2; + backlash.set_distance_mm(K_AXIS, (m.backlash[KMINIMUM] + m.backlash[KMAXIMUM]) / 2); #elif ENABLED(CALIBRATION_MEASURE_KMIN) - backlash.distance_mm.k = m.backlash[KMINIMUM]; + backlash.set_distance_mm(K_AXIS, m.backlash[KMINIMUM]); #elif ENABLED(CALIBRATION_MEASURE_KMAX) - backlash.distance_mm.k = m.backlash[KMAXIMUM]; + backlash.set_distance_mm(K_AXIS, m.backlash[KMAXIMUM]); + #endif + + #if HAS_U_CENTER + backlash.distance_mm.u = (m.backlash[UMINIMUM] + m.backlash[UMAXIMUM]) / 2; + #elif ENABLED(CALIBRATION_MEASURE_UMIN) + backlash.distance_mm.u = m.backlash[UMINIMUM]; + #elif ENABLED(CALIBRATION_MEASURE_UMAX) + backlash.distance_mm.u = m.backlash[UMAXIMUM]; + #endif + + #if HAS_V_CENTER + backlash.distance_mm.v = (m.backlash[VMINIMUM] + m.backlash[VMAXIMUM]) / 2; + #elif ENABLED(CALIBRATION_MEASURE_VMIN) + backlash.distance_mm.v = m.backlash[VMINIMUM]; + #elif ENABLED(CALIBRATION_MEASURE_UMAX) + backlash.distance_mm.v = m.backlash[VMAXIMUM]; + #endif + + #if HAS_W_CENTER + backlash.distance_mm.w = (m.backlash[WMINIMUM] + m.backlash[WMAXIMUM]) / 2; + #elif ENABLED(CALIBRATION_MEASURE_WMIN) + backlash.distance_mm.w = m.backlash[WMINIMUM]; + #elif ENABLED(CALIBRATION_MEASURE_WMAX) + backlash.distance_mm.w = m.backlash[WMAXIMUM]; #endif #endif // BACKLASH_GCODE @@ -583,11 +720,12 @@ inline void calibrate_backlash(measurements_t &m, const float uncertainty) { // allowed directions to take up any backlash { // New scope for TEMPORARY_BACKLASH_CORRECTION - TEMPORARY_BACKLASH_CORRECTION(all_on); + TEMPORARY_BACKLASH_CORRECTION(backlash.all_on); TEMPORARY_BACKLASH_SMOOTHING(0.0f); - const xyz_float_t move = LINEAR_AXIS_ARRAY( + const xyz_float_t move = NUM_AXIS_ARRAY( AXIS_CAN_CALIBRATE(X) * 3, AXIS_CAN_CALIBRATE(Y) * 3, AXIS_CAN_CALIBRATE(Z) * 3, - AXIS_CAN_CALIBRATE(I) * 3, AXIS_CAN_CALIBRATE(J) * 3, AXIS_CAN_CALIBRATE(K) * 3 + AXIS_CAN_CALIBRATE(I) * 3, AXIS_CAN_CALIBRATE(J) * 3, AXIS_CAN_CALIBRATE(K) * 3, + AXIS_CAN_CALIBRATE(U) * 3, AXIS_CAN_CALIBRATE(V) * 3, AXIS_CAN_CALIBRATE(W) * 3 ); current_position += move; calibration_move(); current_position -= move; calibration_move(); @@ -613,7 +751,7 @@ inline void update_measurements(measurements_t &m, const AxisEnum axis) { * - Call calibrate_backlash() beforehand for best accuracy */ inline void calibrate_toolhead(measurements_t &m, const float uncertainty, const uint8_t extruder) { - TEMPORARY_BACKLASH_CORRECTION(all_on); + TEMPORARY_BACKLASH_CORRECTION(backlash.all_on); TEMPORARY_BACKLASH_SMOOTHING(0.0f); TERN(HAS_MULTI_HOTEND, set_nozzle(m, extruder), UNUSED(extruder)); @@ -638,6 +776,9 @@ inline void calibrate_toolhead(measurements_t &m, const float uncertainty, const TERN_(HAS_I_CENTER, update_measurements(m, I_AXIS)); TERN_(HAS_J_CENTER, update_measurements(m, J_AXIS)); TERN_(HAS_K_CENTER, update_measurements(m, K_AXIS)); + TERN_(HAS_U_CENTER, update_measurements(m, U_AXIS)); + TERN_(HAS_V_CENTER, update_measurements(m, V_AXIS)); + TERN_(HAS_W_CENTER, update_measurements(m, W_AXIS)); sync_plan_position(); } @@ -650,7 +791,7 @@ inline void calibrate_toolhead(measurements_t &m, const float uncertainty, const * uncertainty in - How far away from the object to begin probing */ inline void calibrate_all_toolheads(measurements_t &m, const float uncertainty) { - TEMPORARY_BACKLASH_CORRECTION(all_on); + TEMPORARY_BACKLASH_CORRECTION(backlash.all_on); TEMPORARY_BACKLASH_SMOOTHING(0.0f); HOTEND_LOOP() calibrate_toolhead(m, uncertainty, e); @@ -666,7 +807,7 @@ inline void calibrate_all_toolheads(measurements_t &m, const float uncertainty) * 1) For each nozzle, touch top and sides of object to determine object position and * nozzle offsets. Do a fast but rough search over a wider area. * 2) With the first nozzle, touch top and sides of object to determine backlash values - * for all axis (if BACKLASH_GCODE is enabled) + * for all axes (if BACKLASH_GCODE is enabled) * 3) For each nozzle, touch top and sides of object slowly to determine precise * position of object. Adjust coordinate system and nozzle offsets so probed object * location corresponds to known object location with a high degree of precision. @@ -676,7 +817,7 @@ inline void calibrate_all() { TERN_(HAS_HOTEND_OFFSET, reset_hotend_offsets()); - TEMPORARY_BACKLASH_CORRECTION(all_on); + TEMPORARY_BACKLASH_CORRECTION(backlash.all_on); TEMPORARY_BACKLASH_SMOOTHING(0.0f); // Do a fast and rough calibration of the toolheads diff --git a/Marlin/src/gcode/calibrate/G76_M871.cpp b/Marlin/src/gcode/calibrate/G76_M871.cpp index 21bb2c75..be125b14 100644 --- a/Marlin/src/gcode/calibrate/G76_M871.cpp +++ b/Marlin/src/gcode/calibrate/G76_M871.cpp @@ -34,7 +34,6 @@ #include "../../module/probe.h" #include "../../feature/bedlevel/bedlevel.h" #include "../../module/temperature.h" -#include "../../module/probe.h" #include "../../feature/probe_temp_comp.h" #include "../../lcd/marlinui.h" @@ -82,12 +81,12 @@ * - `P` - Run probe temperature calibration. */ -static void say_waiting_for() { SERIAL_ECHOPGM("Waiting for "); } -static void say_waiting_for_probe_heating() { say_waiting_for(); SERIAL_ECHOLNPGM("probe heating."); } -static void say_successfully_calibrated() { SERIAL_ECHOPGM("Successfully calibrated"); } -static void say_failed_to_calibrate() { SERIAL_ECHOPGM("!Failed to calibrate"); } +#if ALL(PTC_PROBE, PTC_BED) -#if BOTH(PTC_PROBE, PTC_BED) + static void say_waiting_for() { SERIAL_ECHOPGM("Waiting for "); } + static void say_waiting_for_probe_heating() { say_waiting_for(); SERIAL_ECHOLNPGM("probe heating."); } + static void say_successfully_calibrated() { SERIAL_ECHOPGM("Successfully calibrated"); } + static void say_failed_to_calibrate() { SERIAL_ECHOPGM("!Failed to calibrate"); } void GcodeSuite::G76() { auto report_temps = [](millis_t &ntr, millis_t timeout=0) { @@ -108,8 +107,9 @@ static void say_failed_to_calibrate() { SERIAL_ECHOPGM("!Failed to calibra }; auto g76_probe = [](const TempSensorID sid, celsius_t &targ, const xy_pos_t &nozpos) { - do_z_clearance(5.0); // Raise nozzle before probing + ptc.set_enabled(false); const float measured_z = probe.probe_at_point(nozpos, PROBE_PT_STOW, 0, false); // verbose=0, probe_relative=false + ptc.set_enabled(true); if (isnan(measured_z)) SERIAL_ECHOLNPGM("!Received NAN. Aborting."); else { @@ -256,7 +256,7 @@ static void say_failed_to_calibrate() { SERIAL_ECHOPGM("!Failed to calibra say_waiting_for_probe_heating(); SERIAL_ECHOLNPGM(" Bed:", target_bed, " Probe:", target_probe); - const millis_t probe_timeout_ms = millis() + SEC_TO_MS(900UL); + const millis_t probe_timeout_ms = millis() + MIN_TO_MS(15); while (thermalManager.degProbe() < target_probe) { if (report_temps(next_temp_report, probe_timeout_ms)) { SERIAL_ECHOLNPGM("!Probe heating timed out."); diff --git a/Marlin/src/gcode/calibrate/M100.cpp b/Marlin/src/gcode/calibrate/M100.cpp index 338392b5..3791c69f 100644 --- a/Marlin/src/gcode/calibrate/M100.cpp +++ b/Marlin/src/gcode/calibrate/M100.cpp @@ -60,7 +60,7 @@ #define TEST_BYTE ((char) 0xE5) -#if EITHER(__AVR__, IS_32BIT_TEENSY) +#if ANY(__AVR__, IS_32BIT_TEENSY) extern char __bss_end; char *end_bss = &__bss_end, @@ -163,14 +163,14 @@ inline int32_t count_test_bytes(const char * const start_free_memory) { while (start_free_memory < end_free_memory) { print_hex_address(start_free_memory); // Print the address SERIAL_CHAR(':'); - LOOP_L_N(i, 16) { // and 16 data bytes + for (uint8_t i = 0; i < 16; ++i) { // and 16 data bytes if (i == 8) SERIAL_CHAR('-'); print_hex_byte(start_free_memory[i]); SERIAL_CHAR(' '); } serial_delay(25); SERIAL_CHAR('|'); // Point out non test bytes - LOOP_L_N(i, 16) { + for (uint8_t i = 0; i < 16; ++i) { char ccc = (char)start_free_memory[i]; // cast to char before automatically casting to char on assignment, in case the compiler is broken ccc = (ccc == TEST_BYTE) ? ' ' : '?'; SERIAL_CHAR(ccc); diff --git a/Marlin/src/gcode/calibrate/M425.cpp b/Marlin/src/gcode/calibrate/M425.cpp index 190af0f7..cd206ca4 100644 --- a/Marlin/src/gcode/calibrate/M425.cpp +++ b/Marlin/src/gcode/calibrate/M425.cpp @@ -46,24 +46,19 @@ void GcodeSuite::M425() { bool noArgs = true; - auto axis_can_calibrate = [](const uint8_t a) { + auto axis_can_calibrate = [](const uint8_t a) -> bool { + #define _CAN_CASE(N) case N##_AXIS: return bool(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) + default: break; } + return false; }; - LOOP_LINEAR_AXES(a) { + LOOP_NUM_AXES(a) { if (axis_can_calibrate(a) && parser.seen(AXIS_CHAR(a))) { planner.synchronize(); - backlash.distance_mm[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; } } @@ -77,33 +72,30 @@ void GcodeSuite::M425() { #ifdef BACKLASH_SMOOTHING_MM if (parser.seen('S')) { planner.synchronize(); - backlash.smoothing_mm = parser.value_linear_units(); + backlash.set_smoothing_mm(parser.value_linear_units()); noArgs = false; } #endif if (noArgs) { SERIAL_ECHOPGM("Backlash Correction "); - if (!backlash.correction) SERIAL_ECHOPGM("in"); + if (!backlash.get_correction_uint8()) SERIAL_ECHOPGM("in"); SERIAL_ECHOLNPGM("active:"); 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.distance_mm[a]); - SERIAL_EOL(); + LOOP_NUM_AXES(a) if (axis_can_calibrate(a)) { + SERIAL_ECHOLNPGM_P((PGM_P)pgm_read_ptr(&SP_AXIS_STR[a]), backlash.get_distance_mm((AxisEnum)a)); } #ifdef BACKLASH_SMOOTHING_MM - SERIAL_ECHOLNPGM(" Smoothing (mm): S", backlash.smoothing_mm); + SERIAL_ECHOLNPGM(" Smoothing (mm): S", backlash.get_smoothing_mm()); #endif #if ENABLED(MEASURE_BACKLASH_WHEN_PROBING) 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))); + LOOP_NUM_AXES(a) if (axis_can_calibrate(a) && backlash.has_measurement(AxisEnum(a))) { + SERIAL_ECHOPGM_P((PGM_P)pgm_read_ptr(&SP_AXIS_STR[a]), backlash.get_measurement((AxisEnum)a)); } } else @@ -118,16 +110,21 @@ void GcodeSuite::M425_report(const bool forReplay/*=true*/) { SERIAL_ECHOLNPGM_P( PSTR(" M425 F"), backlash.get_correction() #ifdef BACKLASH_SMOOTHING_MM - , PSTR(" S"), LINEAR_UNIT(backlash.smoothing_mm) + , PSTR(" S"), LINEAR_UNIT(backlash.get_smoothing_mm()) + #endif + #if NUM_AXES + , LIST_N(DOUBLE(NUM_AXES), + SP_X_STR, LINEAR_UNIT(backlash.get_distance_mm(X_AXIS)), + SP_Y_STR, LINEAR_UNIT(backlash.get_distance_mm(Y_AXIS)), + SP_Z_STR, LINEAR_UNIT(backlash.get_distance_mm(Z_AXIS)), + SP_I_STR, I_AXIS_UNIT(backlash.get_distance_mm(I_AXIS)), + SP_J_STR, J_AXIS_UNIT(backlash.get_distance_mm(J_AXIS)), + SP_K_STR, K_AXIS_UNIT(backlash.get_distance_mm(K_AXIS)), + SP_U_STR, U_AXIS_UNIT(backlash.get_distance_mm(U_AXIS)), + SP_V_STR, V_AXIS_UNIT(backlash.get_distance_mm(V_AXIS)), + SP_W_STR, W_AXIS_UNIT(backlash.get_distance_mm(W_AXIS)) + ) #endif - , LIST_N(DOUBLE(LINEAR_AXES), - SP_X_STR, LINEAR_UNIT(backlash.distance_mm.x), - SP_Y_STR, LINEAR_UNIT(backlash.distance_mm.y), - SP_Z_STR, LINEAR_UNIT(backlash.distance_mm.z), - SP_I_STR, LINEAR_UNIT(backlash.distance_mm.i), - SP_J_STR, LINEAR_UNIT(backlash.distance_mm.j), - SP_K_STR, LINEAR_UNIT(backlash.distance_mm.k) - ) ); } diff --git a/Marlin/src/gcode/calibrate/M48.cpp b/Marlin/src/gcode/calibrate/M48.cpp index 913ffe30..8bee3fd8 100644 --- a/Marlin/src/gcode/calibrate/M48.cpp +++ b/Marlin/src/gcode/calibrate/M48.cpp @@ -35,11 +35,15 @@ #include "../../module/planner.h" #endif +#if HAS_PTC + #include "../../feature/probe_temp_comp.h" +#endif + /** * M48: Z probe repeatability measurement function. * * Usage: - * M48 + * M48 * P = Number of sampled points (4-50, default 10) * X = Sample X position * Y = Sample Y position @@ -47,6 +51,7 @@ * E = Engage Z probe for each reading * L = Number of legs of movement before probe * S = Schizoid (Or Star if you prefer) + * C = Enable probe temperature compensation (0 or 1, default 1) * * This function requires the machine to be homed before invocation. */ @@ -61,9 +66,6 @@ void GcodeSuite::M48() { return; } - if (verbose_level > 0) - SERIAL_ECHOLNPGM("M48 Z-Probe Repeatability Test"); - const int8_t n_samples = parser.byteval('P', 10); if (!WITHIN(n_samples, 4, 50)) { SERIAL_ECHOLNPGM("?Sample size not plausible (4-50)."); @@ -79,7 +81,7 @@ void GcodeSuite::M48() { }; if (!probe.can_reach(test_position)) { - ui.set_status(GET_TEXT_F(MSG_M48_OUT_OF_BOUNDS), 99); + LCD_MESSAGE_MAX(MSG_M48_OUT_OF_BOUNDS); SERIAL_ECHOLNPGM("? (X,Y) out of bounds."); return; } @@ -97,6 +99,9 @@ void GcodeSuite::M48() { const bool schizoid_flag = parser.boolval('S'); if (schizoid_flag && !seen_L) n_legs = 7; + if (verbose_level > 0) + SERIAL_ECHOLNPGM("M48 Z-Probe Repeatability Test"); + if (verbose_level > 2) SERIAL_ECHOLNPGM("Positioning the probe..."); @@ -107,6 +112,8 @@ void GcodeSuite::M48() { set_bed_leveling_enabled(false); #endif + TERN_(HAS_PTC, ptc.set_enabled(parser.boolval('C', true))); + // Work with reasonable feedrates remember_feedrate_scaling_off(); @@ -141,7 +148,7 @@ void GcodeSuite::M48() { float sample_sum = 0.0; - LOOP_L_N(n, n_samples) { + for (uint8_t n = 0; n < n_samples; ++n) { #if HAS_STATUS_MESSAGE // Display M48 progress in the status bar ui.status_printf(0, F(S_FMT ": %d/%d"), GET_TEXT(MSG_M48_POINT), int(n + 1), int(n_samples)); @@ -168,7 +175,7 @@ void GcodeSuite::M48() { } // Move from leg to leg in rapid succession - LOOP_L_N(l, n_legs - 1) { + for (uint8_t l = 0; l < n_legs - 1; ++l) { // Move some distance around the perimeter float delta_angle; @@ -216,7 +223,7 @@ void GcodeSuite::M48() { } // n_legs // Probe a single point - const float pz = probe.probe_at_point(test_position, raise_after, 0); + const float pz = probe.probe_at_point(test_position, raise_after); // Break the loop if the probe fails probing_good = !isnan(pz); @@ -236,7 +243,7 @@ void GcodeSuite::M48() { // Calculate the standard deviation so far. // The value after the last sample will be the final output. float dev_sum = 0.0; - LOOP_LE_N(j, n) dev_sum += sq(sample_set[j] - mean); + for (uint8_t j = 0; j <= n; ++j) dev_sum += sq(sample_set[j] - mean); sigma = SQRT(dev_sum / (n + 1)); if (verbose_level > 1) { @@ -269,6 +276,9 @@ void GcodeSuite::M48() { // Re-enable bed level correction if it had been on TERN_(HAS_LEVELING, set_bed_leveling_enabled(was_enabled)); + // Re-enable probe temperature correction + TERN_(HAS_PTC, ptc.set_enabled(true)); + report_current_position(); } diff --git a/Marlin/src/gcode/calibrate/M665.cpp b/Marlin/src/gcode/calibrate/M665.cpp index aa21471b..a8e02831 100644 --- a/Marlin/src/gcode/calibrate/M665.cpp +++ b/Marlin/src/gcode/calibrate/M665.cpp @@ -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,33 @@ * * 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(); } 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 diff --git a/Marlin/src/gcode/calibrate/M666.cpp b/Marlin/src/gcode/calibrate/M666.cpp index 15f8baf1..143b6f24 100644 --- a/Marlin/src/gcode/calibrate/M666.cpp +++ b/Marlin/src/gcode/calibrate/M666.cpp @@ -22,7 +22,7 @@ #include "../../inc/MarlinConfig.h" -#if ENABLED(DELTA) || HAS_EXTRA_ENDSTOPS +#if ANY(DELTA, HAS_EXTRA_ENDSTOPS) #include "../gcode.h" @@ -44,15 +44,15 @@ void GcodeSuite::M666() { DEBUG_SECTION(log_M666, "M666", DEBUGGING(LEVELING)); bool is_err = false, is_set = false; - LOOP_LINEAR_AXES(i) { - if (parser.seen(AXIS_CHAR(i))) { + LOOP_NUM_AXES(i) { + if (parser.seenval(AXIS_CHAR(i))) { is_set = true; const float v = parser.value_linear_units(); if (v > 0) is_err = true; else { delta_endstop_adj[i] = v; - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("delta_endstop_adj[", AS_CHAR(AXIS_CHAR(i)), "] = ", v); + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("delta_endstop_adj[", C(AXIS_CHAR(i)), "] = ", v); } } } @@ -93,12 +93,12 @@ #if ENABLED(Z_MULTI_ENDSTOPS) if (parser.seenval('Z')) { const float z_adj = parser.value_linear_units(); - #if NUM_Z_STEPPER_DRIVERS == 2 + #if NUM_Z_STEPPERS == 2 endstops.z2_endstop_adj = z_adj; #else const int ind = parser.intval('S'); #define _SET_ZADJ(N) if (!ind || ind == N) endstops.z##N##_endstop_adj = z_adj; - REPEAT_S(2, INCREMENT(NUM_Z_STEPPER_DRIVERS), _SET_ZADJ) + REPEAT_S(2, INCREMENT(NUM_Z_STEPPERS), _SET_ZADJ) #endif } #endif @@ -114,11 +114,11 @@ SERIAL_ECHOLNPGM_P(SP_Y_STR, LINEAR_UNIT(endstops.y2_endstop_adj)); #endif #if ENABLED(Z_MULTI_ENDSTOPS) - #if NUM_Z_STEPPER_DRIVERS >= 3 + #if NUM_Z_STEPPERS >= 3 SERIAL_ECHOPGM(" S2 Z", LINEAR_UNIT(endstops.z3_endstop_adj)); report_echo_start(forReplay); SERIAL_ECHOPGM(" M666 S3 Z", LINEAR_UNIT(endstops.z3_endstop_adj)); - #if NUM_Z_STEPPER_DRIVERS >= 4 + #if NUM_Z_STEPPERS >= 4 report_echo_start(forReplay); SERIAL_ECHOPGM(" M666 S4 Z", LINEAR_UNIT(endstops.z4_endstop_adj)); #endif diff --git a/Marlin/src/gcode/calibrate/M852.cpp b/Marlin/src/gcode/calibrate/M852.cpp index b24a4496..6c661dcd 100644 --- a/Marlin/src/gcode/calibrate/M852.cpp +++ b/Marlin/src/gcode/calibrate/M852.cpp @@ -93,7 +93,7 @@ void GcodeSuite::M852() { void GcodeSuite::M852_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F(STR_SKEW_FACTOR)); - SERIAL_ECHOPAIR_F(" M851 I", planner.skew_factor.xy, 6); + SERIAL_ECHOPAIR_F(" M852 I", planner.skew_factor.xy, 6); #if ENABLED(SKEW_CORRECTION_FOR_Z) SERIAL_ECHOPAIR_F(" J", planner.skew_factor.xz, 6); SERIAL_ECHOPAIR_F(" K", planner.skew_factor.yz, 6); diff --git a/Marlin/src/gcode/config/M200-M205.cpp b/Marlin/src/gcode/config/M200-M205.cpp index 7b7ce5e1..96bfb783 100644 --- a/Marlin/src/gcode/config/M200-M205.cpp +++ b/Marlin/src/gcode/config/M200-M205.cpp @@ -93,12 +93,12 @@ } #else SERIAL_ECHOLNPGM(" M200 S", parser.volumetric_enabled); - LOOP_L_N(i, EXTRUDERS) { + EXTRUDER_LOOP() { report_echo_start(forReplay); SERIAL_ECHOLNPGM( - " M200 T", i, " D", LINEAR_UNIT(planner.filament_size[i]) + " M200 T", e, " D", LINEAR_UNIT(planner.filament_size[e]) #if ENABLED(VOLUMETRIC_EXTRUDER_LIMIT) - , " L", LINEAR_UNIT(planner.volumetric_extruder_limit[i]) + , " L", LINEAR_UNIT(planner.volumetric_extruder_limit[e]) #endif ); } @@ -108,12 +108,21 @@ #endif // !NO_VOLUMETRICS /** - * M201: Set max acceleration in units/s^2 for print moves (M201 X1000 Y1000) + * M201: Set max acceleration in units/s^2 for print moves. * - * With multiple extruders use T to specify which one. + * X : Max Acceleration for X + * Y : Max Acceleration for Y + * Z : Max Acceleration for Z + * ... : etc + * E : Max Acceleration for Extruder + * T : Extruder index to set + * + * With XY_FREQUENCY_LIMIT: + * F : Frequency limit for XY...IJKUVW + * S : Speed factor percentage. */ void GcodeSuite::M201() { - if (!parser.seen("T" LOGICAL_AXES_STRING)) + if (!parser.seen("T" STR_AXES_LOGICAL TERN_(XY_FREQUENCY_LIMIT, "FS"))) return M201_report(); const int8_t target_extruder = get_target_extruder_from_command(); @@ -121,34 +130,45 @@ void GcodeSuite::M201() { #ifdef XY_FREQUENCY_LIMIT if (parser.seenval('F')) planner.set_frequency_limit(parser.value_byte()); - if (parser.seenval('G')) planner.xy_freq_min_speed_factor = constrain(parser.value_float(), 1, 100) / 100; + if (parser.seenval('S')) planner.xy_freq_min_speed_factor = constrain(parser.value_float(), 1, 100) / 100; #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)); } } } void GcodeSuite::M201_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F(STR_MAX_ACCELERATION)); - SERIAL_ECHOLNPGM_P( - LIST_N(DOUBLE(LINEAR_AXES), - PSTR(" M201 X"), LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[X_AXIS]), - SP_Y_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Y_AXIS]), - SP_Z_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Z_AXIS]), - SP_I_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[I_AXIS]), - SP_J_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[J_AXIS]), - SP_K_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[K_AXIS]) - ) - #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS) - , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_acceleration_mm_per_s2[E_AXIS]) - #endif - ); + #if NUM_AXES + SERIAL_ECHOPGM_P( + LIST_N(DOUBLE(NUM_AXES), + PSTR(" M201 X"), LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[X_AXIS]), + SP_Y_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Y_AXIS]), + SP_Z_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Z_AXIS]), + SP_I_STR, I_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[I_AXIS]), + SP_J_STR, J_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[J_AXIS]), + SP_K_STR, K_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[K_AXIS]), + SP_U_STR, U_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[U_AXIS]), + SP_V_STR, V_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[V_AXIS]), + SP_W_STR, W_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[W_AXIS]) + ) + ); + #endif + + #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS) + SERIAL_ECHOPGM_P(SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_acceleration_mm_per_s2[E_AXIS])); + #endif + + #if NUM_AXES || (HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)) + SERIAL_EOL(); + #endif + #if ENABLED(DISTINCT_E_FACTORS) - LOOP_L_N(i, E_STEPPERS) { + for (uint8_t i = 0; i < E_STEPPERS; ++i) { report_echo_start(forReplay); SERIAL_ECHOLNPGM_P( PSTR(" M201 T"), i @@ -164,37 +184,48 @@ void GcodeSuite::M201_report(const bool forReplay/*=true*/) { * With multiple extruders use T to specify which one. */ void GcodeSuite::M203() { - if (!parser.seen("T" LOGICAL_AXES_STRING)) + if (!parser.seen("T" STR_AXES_LOGICAL)) return M203_report(); const int8_t target_extruder = get_target_extruder_from_command(); 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)); } } void GcodeSuite::M203_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F(STR_MAX_FEEDRATES)); - SERIAL_ECHOLNPGM_P( - LIST_N(DOUBLE(LINEAR_AXES), - PSTR(" M203 X"), LINEAR_UNIT(planner.settings.max_feedrate_mm_s[X_AXIS]), - SP_Y_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Y_AXIS]), - SP_Z_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Z_AXIS]), - SP_I_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[I_AXIS]), - SP_J_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[J_AXIS]), - SP_K_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[K_AXIS]) - ) - #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS) - , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS]) - #endif - ); + #if NUM_AXES + SERIAL_ECHOPGM_P( + LIST_N(DOUBLE(NUM_AXES), + PSTR(" M203 X"), LINEAR_UNIT(planner.settings.max_feedrate_mm_s[X_AXIS]), + SP_Y_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Y_AXIS]), + SP_Z_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Z_AXIS]), + SP_I_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[I_AXIS]), + SP_J_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[J_AXIS]), + SP_K_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[K_AXIS]), + SP_U_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[U_AXIS]), + SP_V_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[V_AXIS]), + SP_W_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[W_AXIS]) + ) + ); + #endif + + #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS) + SERIAL_ECHOPGM_P(SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS])); + #endif + + #if NUM_AXES || (HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)) + SERIAL_EOL(); + #endif + #if ENABLED(DISTINCT_E_FACTORS) - LOOP_L_N(i, E_STEPPERS) { - SERIAL_ECHO_START(); + for (uint8_t i = 0; i < E_STEPPERS; ++i) { + if (!forReplay) SERIAL_ECHO_START(); SERIAL_ECHOLNPGM_P( PSTR(" M203 T"), i , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS_N(i)]) @@ -206,9 +237,9 @@ void GcodeSuite::M203_report(const bool forReplay/*=true*/) { /** * M204: Set Accelerations in units/sec^2 (M204 P1200 R3000 T3000) * - * P = Printing moves - * R = Retract only (no X, Y, Z) moves - * T = Travel (non printing) moves + * P Printing moves + * R Retract only (no X, Y, Z) moves + * T Travel (non printing) moves */ void GcodeSuite::M204() { if (!parser.seen("PRST")) @@ -232,30 +263,40 @@ void GcodeSuite::M204_report(const bool forReplay/*=true*/) { ); } +#if AXIS_COLLISION('B') + #define M205_MIN_SEG_TIME_PARAM 'D' + #define M205_MIN_SEG_TIME_STR "D" + #warning "Use 'M205 D' for Minimum Segment Time." +#else + #define M205_MIN_SEG_TIME_PARAM 'B' + #define M205_MIN_SEG_TIME_STR "B" +#endif + /** * M205: Set Advanced Settings * - * B = Min Segment Time (µs) - * S = Min Feed Rate (units/s) - * T = Min Travel Feed Rate (units/s) - * X = Max X Jerk (units/sec^2) - * Y = Max Y Jerk (units/sec^2) - * Z = Max Z Jerk (units/sec^2) - * E = Max E Jerk (units/sec^2) - * J = Junction Deviation (mm) (If not using CLASSIC_JERK) + * B<µs> : Min Segment Time + * S : Min Feed Rate + * T : Min Travel Feed Rate + * + * With CLASSIC_JERK: + * X : Max X Jerk + * Y : Max Y Jerk + * Z : Max Z Jerk + * ... : etc + * E : Max E Jerk + * + * Without CLASSIC_JERK: + * J(mm) : Junction Deviation */ void GcodeSuite::M205() { - if (!parser.seen("BST" TERN_(HAS_JUNCTION_DEVIATION, "J") TERN_(HAS_CLASSIC_JERK, "XYZE"))) - return M205_report(); + if (!parser.seen_any()) return M205_report(); //planner.synchronize(); - if (parser.seenval('B')) planner.settings.min_segment_time_us = parser.value_ulong(); + if (parser.seenval(M205_MIN_SEG_TIME_PARAM)) planner.settings.min_segment_time_us = parser.value_ulong(); if (parser.seenval('S')) planner.settings.min_feedrate_mm_s = parser.value_linear_units(); if (parser.seenval('T')) planner.settings.min_travel_feedrate_mm_s = parser.value_linear_units(); #if HAS_JUNCTION_DEVIATION - #if HAS_CLASSIC_JERK && (AXIS4_NAME == 'J' || AXIS5_NAME == 'J' || AXIS6_NAME == 'J') - #error "Can't set_max_jerk for 'J' axis because 'J' is used for Junction Deviation." - #endif if (parser.seenval('J')) { const float junc_dev = parser.value_linear_units(); if (WITHIN(junc_dev, 0.01f, 0.3f)) { @@ -273,9 +314,12 @@ void GcodeSuite::M205() { if (parser.seenval('X')) planner.set_max_jerk(X_AXIS, parser.value_linear_units()), if (parser.seenval('Y')) planner.set_max_jerk(Y_AXIS, parser.value_linear_units()), if ((seenZ = parser.seenval('Z'))) planner.set_max_jerk(Z_AXIS, parser.value_linear_units()), - if (parser.seenval(AXIS4_NAME)) planner.set_max_jerk(I_AXIS, parser.value_linear_units()), - if (parser.seenval(AXIS5_NAME)) planner.set_max_jerk(J_AXIS, parser.value_linear_units()), - if (parser.seenval(AXIS6_NAME)) planner.set_max_jerk(K_AXIS, parser.value_linear_units()) + if (parser.seenval(AXIS4_NAME)) planner.set_max_jerk(I_AXIS, parser.TERN(AXIS4_ROTATES, value_float, value_linear_units)()), + if (parser.seenval(AXIS5_NAME)) planner.set_max_jerk(J_AXIS, parser.TERN(AXIS5_ROTATES, value_float, value_linear_units)()), + if (parser.seenval(AXIS6_NAME)) planner.set_max_jerk(K_AXIS, parser.TERN(AXIS6_ROTATES, value_float, value_linear_units)()), + if (parser.seenval(AXIS7_NAME)) planner.set_max_jerk(U_AXIS, parser.TERN(AXIS7_ROTATES, value_float, value_linear_units)()), + if (parser.seenval(AXIS8_NAME)) planner.set_max_jerk(V_AXIS, parser.TERN(AXIS8_ROTATES, value_float, value_linear_units)()), + if (parser.seenval(AXIS9_NAME)) planner.set_max_jerk(W_AXIS, parser.TERN(AXIS9_ROTATES, value_float, value_linear_units)()) ); #if HAS_MESH && DISABLED(LIMITED_JERK_EDITING) if (seenZ && planner.max_jerk.z <= 0.1f) @@ -286,27 +330,36 @@ void GcodeSuite::M205() { void GcodeSuite::M205_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F( - "Advanced (B S T" + "Advanced (" M205_MIN_SEG_TIME_STR " S T" TERN_(HAS_JUNCTION_DEVIATION, " J") - TERN_(HAS_CLASSIC_JERK, " X Y Z") - TERN_(HAS_CLASSIC_E_JERK, " E") + #if HAS_CLASSIC_JERK + NUM_AXIS_GANG( + " X", " Y", " Z", + " " STR_I "", " " STR_J "", " " STR_K "", + " " STR_U "", " " STR_V "", " " STR_W "" + ) + #endif + TERN_(HAS_CLASSIC_E_JERK, " E") ")" )); SERIAL_ECHOLNPGM_P( - PSTR(" M205 B"), LINEAR_UNIT(planner.settings.min_segment_time_us) + PSTR(" M205 " M205_MIN_SEG_TIME_STR), LINEAR_UNIT(planner.settings.min_segment_time_us) , PSTR(" S"), LINEAR_UNIT(planner.settings.min_feedrate_mm_s) , SP_T_STR, LINEAR_UNIT(planner.settings.min_travel_feedrate_mm_s) #if HAS_JUNCTION_DEVIATION , PSTR(" J"), LINEAR_UNIT(planner.junction_deviation_mm) #endif #if HAS_CLASSIC_JERK - , LIST_N(DOUBLE(LINEAR_AXES), + , LIST_N(DOUBLE(NUM_AXES), SP_X_STR, LINEAR_UNIT(planner.max_jerk.x), SP_Y_STR, LINEAR_UNIT(planner.max_jerk.y), SP_Z_STR, LINEAR_UNIT(planner.max_jerk.z), - SP_I_STR, LINEAR_UNIT(planner.max_jerk.i), - SP_J_STR, LINEAR_UNIT(planner.max_jerk.j), - SP_K_STR, LINEAR_UNIT(planner.max_jerk.k) + SP_I_STR, I_AXIS_UNIT(planner.max_jerk.i), + SP_J_STR, J_AXIS_UNIT(planner.max_jerk.j), + SP_K_STR, K_AXIS_UNIT(planner.max_jerk.k), + SP_U_STR, U_AXIS_UNIT(planner.max_jerk.u), + SP_V_STR, V_AXIS_UNIT(planner.max_jerk.v), + SP_W_STR, W_AXIS_UNIT(planner.max_jerk.w) ) #if HAS_CLASSIC_E_JERK , SP_E_STR, LINEAR_UNIT(planner.max_jerk.e) diff --git a/Marlin/src/gcode/config/M217.cpp b/Marlin/src/gcode/config/M217.cpp index 7576272a..908a19fa 100644 --- a/Marlin/src/gcode/config/M217.cpp +++ b/Marlin/src/gcode/config/M217.cpp @@ -34,25 +34,32 @@ #include "../../MarlinCore.h" // for SP_X_STR, etc. /** - * M217 - Set SINGLENOZZLE toolchange parameters + * M217 - Set toolchange parameters * * // Tool change command * Q Prime active tool and exit * * // Tool change settings - * S[linear] Swap length - * B[linear] Extra Swap length - * E[linear] Prime length - * P[linear/m] Prime speed - * R[linear/m] Retract speed - * U[linear/m] UnRetract speed - * V[linear] 0/1 Enable auto prime first extruder used - * W[linear] 0/1 Enable park & Z Raise - * X[linear] Park X (Requires TOOLCHANGE_PARK) - * Y[linear] Park Y (Requires TOOLCHANGE_PARK) - * Z[linear] Z Raise - * F[linear] Fan Speed 0-255 - * G[linear/s] Fan time + * S[linear] Swap length + * B[linear] Extra Swap resume length + * E[linear] Extra Prime length (as used by M217 Q) + * G[linear] Cutting wipe retract length (<=100mm) + * R[linear/min] Retract speed + * U[linear/min] UnRetract speed + * P[linear/min] Prime speed + * V[linear] 0/1 Enable auto prime first extruder used + * W[linear] 0/1 Enable park & Z Raise + * X[linear] Park X (Requires TOOLCHANGE_PARK) + * Y[linear] Park Y (Requires TOOLCHANGE_PARK and NUM_AXES >= 2) + * I[linear] Park I (Requires TOOLCHANGE_PARK and NUM_AXES >= 4) + * J[linear] Park J (Requires TOOLCHANGE_PARK and NUM_AXES >= 5) + * K[linear] Park K (Requires TOOLCHANGE_PARK and NUM_AXES >= 6) + * C[linear] Park U (Requires TOOLCHANGE_PARK and NUM_AXES >= 7) + * H[linear] Park V (Requires TOOLCHANGE_PARK and NUM_AXES >= 8) + * O[linear] Park W (Requires TOOLCHANGE_PARK and NUM_AXES >= 9) + * Z[linear] Z Raise + * F[speed] Fan Speed 0-255 + * D[seconds] Fan time * * Tool migration settings * A[0|1] Enable auto-migration on runout @@ -73,11 +80,12 @@ void GcodeSuite::M217() { if (parser.seenval('B')) { const float v = parser.value_linear_units(); toolchange_settings.extra_resume = constrain(v, -10, 10); } if (parser.seenval('E')) { const float v = parser.value_linear_units(); toolchange_settings.extra_prime = constrain(v, 0, max_extrude); } if (parser.seenval('P')) { const int16_t v = parser.value_linear_units(); toolchange_settings.prime_speed = constrain(v, 10, 5400); } + if (parser.seenval('G')) { const int16_t v = parser.value_linear_units(); toolchange_settings.wipe_retract = constrain(v, 0, 100); } if (parser.seenval('R')) { const int16_t v = parser.value_linear_units(); toolchange_settings.retract_speed = constrain(v, 10, 5400); } if (parser.seenval('U')) { const int16_t v = parser.value_linear_units(); toolchange_settings.unretract_speed = constrain(v, 10, 5400); } #if TOOLCHANGE_FS_FAN >= 0 && HAS_FAN - if (parser.seenval('F')) { const int16_t v = parser.value_linear_units(); toolchange_settings.fan_speed = constrain(v, 0, 255); } - if (parser.seenval('G')) { const int16_t v = parser.value_linear_units(); toolchange_settings.fan_time = constrain(v, 1, 30); } + if (parser.seenval('F')) { const uint16_t v = parser.value_ushort(); toolchange_settings.fan_speed = constrain(v, 0, 255); } + if (parser.seenval('D')) { const uint16_t v = parser.value_ushort(); toolchange_settings.fan_time = constrain(v, 1, 30); } #endif #endif @@ -87,11 +95,35 @@ void GcodeSuite::M217() { #if ENABLED(TOOLCHANGE_PARK) if (parser.seenval('W')) { toolchange_settings.enable_park = parser.value_linear_units(); } - if (parser.seenval('X')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.x = constrain(v, X_MIN_POS, X_MAX_POS); } - if (parser.seenval('Y')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.y = constrain(v, Y_MIN_POS, Y_MAX_POS); } + #if HAS_X_AXIS + if (parser.seenval('X')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.x = constrain(v, X_MIN_POS, X_MAX_POS); } + #endif + #if HAS_Y_AXIS + if (parser.seenval('Y')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.y = constrain(v, Y_MIN_POS, Y_MAX_POS); } + #endif + #if HAS_I_AXIS + if (parser.seenval('I')) { const int16_t v = parser.TERN(AXIS4_ROTATES, value_int, value_linear_units)(); toolchange_settings.change_point.i = constrain(v, I_MIN_POS, I_MAX_POS); } + #endif + #if HAS_J_AXIS + if (parser.seenval('J')) { const int16_t v = parser.TERN(AXIS5_ROTATES, value_int, value_linear_units)(); toolchange_settings.change_point.j = constrain(v, J_MIN_POS, J_MAX_POS); } + #endif + #if HAS_K_AXIS + if (parser.seenval('K')) { const int16_t v = parser.TERN(AXIS6_ROTATES, value_int, value_linear_units)(); toolchange_settings.change_point.k = constrain(v, K_MIN_POS, K_MAX_POS); } + #endif + #if HAS_U_AXIS + if (parser.seenval('C')) { const int16_t v = parser.TERN(AXIS7_ROTATES, value_int, value_linear_units)(); toolchange_settings.change_point.u = constrain(v, U_MIN_POS, U_MAX_POS); } + #endif + #if HAS_V_AXIS + if (parser.seenval('H')) { const int16_t v = parser.TERN(AXIS8_ROTATES, value_int, value_linear_units)(); toolchange_settings.change_point.v = constrain(v, V_MIN_POS, V_MAX_POS); } + #endif + #if HAS_W_AXIS + if (parser.seenval('O')) { const int16_t v = parser.TERN(AXIS9_ROTATES, value_int, value_linear_units)(); toolchange_settings.change_point.w = constrain(v, W_MIN_POS, W_MAX_POS); } + #endif #endif - if (parser.seenval('Z')) { toolchange_settings.z_raise = parser.value_linear_units(); } + #if HAS_Z_AXIS + if (parser.seenval('Z')) { toolchange_settings.z_raise = parser.value_linear_units(); } + #endif #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE) migration.target = 0; // 0 = disabled @@ -136,24 +168,44 @@ void GcodeSuite::M217_report(const bool forReplay/*=true*/) { SERIAL_ECHOPGM(" M217"); #if ENABLED(TOOLCHANGE_FILAMENT_SWAP) - SERIAL_ECHOPGM(" S", LINEAR_UNIT(toolchange_settings.swap_length)); - SERIAL_ECHOPGM_P(SP_B_STR, LINEAR_UNIT(toolchange_settings.extra_resume), - SP_E_STR, LINEAR_UNIT(toolchange_settings.extra_prime), - SP_P_STR, LINEAR_UNIT(toolchange_settings.prime_speed)); - SERIAL_ECHOPGM(" R", LINEAR_UNIT(toolchange_settings.retract_speed), - " U", LINEAR_UNIT(toolchange_settings.unretract_speed), - " F", toolchange_settings.fan_speed, - " G", toolchange_settings.fan_time); + SERIAL_ECHOPGM_P( + PSTR(" S"), LINEAR_UNIT(toolchange_settings.swap_length), + SP_B_STR, LINEAR_UNIT(toolchange_settings.extra_resume), + SP_E_STR, LINEAR_UNIT(toolchange_settings.extra_prime), + SP_P_STR, LINEAR_UNIT(toolchange_settings.prime_speed), + PSTR(" G"), LINEAR_UNIT(toolchange_settings.wipe_retract), + PSTR(" R"), LINEAR_UNIT(toolchange_settings.retract_speed), + PSTR(" U"), LINEAR_UNIT(toolchange_settings.unretract_speed), + PSTR(" F"), toolchange_settings.fan_speed, + PSTR(" D"), toolchange_settings.fan_time + ); #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE) - SERIAL_ECHOPGM(" A", migration.automode); - SERIAL_ECHOPGM(" L", LINEAR_UNIT(migration.last)); + SERIAL_ECHOPGM(" A", migration.automode, " L", LINEAR_UNIT(migration.last)); #endif #if ENABLED(TOOLCHANGE_PARK) SERIAL_ECHOPGM(" W", LINEAR_UNIT(toolchange_settings.enable_park)); - SERIAL_ECHOPGM_P(SP_X_STR, LINEAR_UNIT(toolchange_settings.change_point.x)); - SERIAL_ECHOPGM_P(SP_Y_STR, LINEAR_UNIT(toolchange_settings.change_point.y)); + #if NUM_AXES + { + SERIAL_ECHOPGM_P( + SP_X_STR, LINEAR_UNIT(toolchange_settings.change_point.x) + #if HAS_Y_AXIS + , SP_Y_STR, LINEAR_UNIT(toolchange_settings.change_point.y) + #endif + #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) + , SP_C_STR, U_AXIS_UNIT(toolchange_settings.change_point.u) + , PSTR(" H"), V_AXIS_UNIT(toolchange_settings.change_point.v) + , PSTR(" O"), W_AXIS_UNIT(toolchange_settings.change_point.w) + ) + #endif + ); + } + #endif #endif #if ENABLED(TOOLCHANGE_FS_PRIME_FIRST_USED) diff --git a/Marlin/src/gcode/config/M218.cpp b/Marlin/src/gcode/config/M218.cpp index c39447a2..d6456857 100644 --- a/Marlin/src/gcode/config/M218.cpp +++ b/Marlin/src/gcode/config/M218.cpp @@ -46,9 +46,15 @@ void GcodeSuite::M218() { const int8_t target_extruder = get_target_extruder_from_command(); if (target_extruder < 0) return; - if (parser.seenval('X')) hotend_offset[target_extruder].x = parser.value_linear_units(); - if (parser.seenval('Y')) hotend_offset[target_extruder].y = parser.value_linear_units(); - if (parser.seenval('Z')) hotend_offset[target_extruder].z = parser.value_linear_units(); + #if HAS_X_AXIS + if (parser.seenval('X')) hotend_offset[target_extruder].x = parser.value_linear_units(); + #endif + #if HAS_Y_AXIS + if (parser.seenval('Y')) hotend_offset[target_extruder].y = parser.value_linear_units(); + #endif + #if HAS_Z_AXIS + if (parser.seenval('Z')) hotend_offset[target_extruder].z = parser.value_linear_units(); + #endif #if ENABLED(DELTA) if (target_extruder == active_extruder) @@ -58,7 +64,7 @@ void GcodeSuite::M218() { void GcodeSuite::M218_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F(STR_HOTEND_OFFSETS)); - LOOP_S_L_N(e, 1, HOTENDS) { + for (uint8_t e = 1; e < HOTENDS; ++e) { report_echo_start(forReplay); SERIAL_ECHOPGM_P( PSTR(" M218 T"), e, diff --git a/Marlin/src/gcode/config/M220.cpp b/Marlin/src/gcode/config/M220.cpp index c9070df8..6797df25 100644 --- a/Marlin/src/gcode/config/M220.cpp +++ b/Marlin/src/gcode/config/M220.cpp @@ -36,16 +36,15 @@ * R : Flag to restore the last-saved factor */ void GcodeSuite::M220() { + if (!parser.seen_any()) { + SERIAL_ECHOLNPGM("FR:", feedrate_percentage, "%"); + return; + } static int16_t backup_feedrate_percentage = 100; - if (parser.seen('B')) backup_feedrate_percentage = feedrate_percentage; - if (parser.seen('R')) feedrate_percentage = backup_feedrate_percentage; - + const int16_t now_feedrate_perc = feedrate_percentage; + if (parser.seen_test('R')) feedrate_percentage = backup_feedrate_percentage; + if (parser.seen_test('B')) backup_feedrate_percentage = now_feedrate_perc; if (parser.seenval('S')) feedrate_percentage = parser.value_int(); - if (!parser.seen_any()) { - SERIAL_ECHOPGM("FR:", feedrate_percentage); - SERIAL_CHAR('%'); - SERIAL_EOL(); - } } diff --git a/Marlin/src/gcode/config/M281.cpp b/Marlin/src/gcode/config/M281.cpp index b90de6be..038a5d61 100644 --- a/Marlin/src/gcode/config/M281.cpp +++ b/Marlin/src/gcode/config/M281.cpp @@ -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"); @@ -56,7 +56,7 @@ void GcodeSuite::M281() { void GcodeSuite::M281_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F(STR_SERVO_ANGLES)); - LOOP_L_N(i, NUM_SERVOS) { + for (uint8_t i = 0; i < NUM_SERVOS; ++i) { switch (i) { default: break; #if ENABLED(SWITCHING_EXTRUDER) @@ -66,6 +66,9 @@ void GcodeSuite::M281_report(const bool forReplay/*=true*/) { #endif #elif ENABLED(SWITCHING_NOZZLE) case SWITCHING_NOZZLE_SERVO_NR: + #if ENABLED(SWITCHING_NOZZLE_TWO_SERVOS) + case SWITCHING_NOZZLE_E1_SERVO_NR: + #endif #elif ENABLED(BLTOUCH) || (HAS_Z_SERVO_PROBE && defined(Z_SERVO_ANGLES)) case Z_PROBE_SERVO_NR: #endif diff --git a/Marlin/src/gcode/config/M301.cpp b/Marlin/src/gcode/config/M301.cpp index fc9f1883..a3938acb 100644 --- a/Marlin/src/gcode/config/M301.cpp +++ b/Marlin/src/gcode/config/M301.cpp @@ -57,19 +57,18 @@ void GcodeSuite::M301() { if (e < HOTENDS) { // catch bad input value - if (parser.seenval('P')) PID_PARAM(Kp, e) = parser.value_float(); - if (parser.seenval('I')) PID_PARAM(Ki, e) = scalePID_i(parser.value_float()); - if (parser.seenval('D')) PID_PARAM(Kd, e) = scalePID_d(parser.value_float()); + if (parser.seenval('P')) SET_HOTEND_PID(Kp, e, parser.value_float()); + if (parser.seenval('I')) SET_HOTEND_PID(Ki, e, parser.value_float()); + if (parser.seenval('D')) SET_HOTEND_PID(Kd, e, parser.value_float()); #if ENABLED(PID_EXTRUSION_SCALING) - if (parser.seenval('C')) PID_PARAM(Kc, e) = parser.value_float(); + if (parser.seenval('C')) SET_HOTEND_PID(Kc, e, parser.value_float()); if (parser.seenval('L')) thermalManager.lpq_len = parser.value_int(); - NOMORE(thermalManager.lpq_len, LPQ_MAX_LEN); - NOLESS(thermalManager.lpq_len, 0); + LIMIT(thermalManager.lpq_len, 0, LPQ_MAX_LEN); #endif #if ENABLED(PID_FAN_SCALING) - if (parser.seenval('F')) PID_PARAM(Kf, e) = parser.value_float(); + if (parser.seenval('F')) SET_HOTEND_PID(Kf, e, parser.value_float()); #endif thermalManager.updatePID(); @@ -83,6 +82,7 @@ void GcodeSuite::M301_report(const bool forReplay/*=true*/ E_OPTARG(const int8_t IF_DISABLED(HAS_MULTI_EXTRUDER, constexpr int8_t eindex = -1); HOTEND_LOOP() { if (e == eindex || eindex == -1) { + const hotend_pid_t &pid = thermalManager.temp_hotend[e].pid; report_echo_start(forReplay); SERIAL_ECHOPGM_P( #if ENABLED(PID_PARAMS_PER_HOTEND) @@ -90,16 +90,14 @@ void GcodeSuite::M301_report(const bool forReplay/*=true*/ E_OPTARG(const int8_t #else PSTR(" M301 P") #endif - , PID_PARAM(Kp, e) - , PSTR(" I"), unscalePID_i(PID_PARAM(Ki, e)) - , PSTR(" D"), unscalePID_d(PID_PARAM(Kd, e)) + , pid.p(), PSTR(" I"), pid.i(), PSTR(" D"), pid.d() ); #if ENABLED(PID_EXTRUSION_SCALING) - SERIAL_ECHOPGM_P(SP_C_STR, PID_PARAM(Kc, e)); + SERIAL_ECHOPGM_P(SP_C_STR, pid.c()); if (e == 0) SERIAL_ECHOPGM(" L", thermalManager.lpq_len); #endif #if ENABLED(PID_FAN_SCALING) - SERIAL_ECHOPGM(" F", PID_PARAM(Kf, e)); + SERIAL_ECHOPGM(" F", pid.f()); #endif SERIAL_EOL(); } diff --git a/Marlin/src/gcode/config/M302.cpp b/Marlin/src/gcode/config/M302.cpp index e271dcd4..12408c89 100644 --- a/Marlin/src/gcode/config/M302.cpp +++ b/Marlin/src/gcode/config/M302.cpp @@ -27,6 +27,10 @@ #include "../gcode.h" #include "../../module/temperature.h" +#if ENABLED(DWIN_LCD_PROUI) + #include "../../lcd/e3v2/proui/dwin.h" +#endif + /** * M302: Allow cold extrudes, or set the minimum extrude temperature * @@ -47,6 +51,7 @@ void GcodeSuite::M302() { if (seen_S) { thermalManager.extrude_min_temp = parser.value_celsius(); thermalManager.allow_cold_extrude = (thermalManager.extrude_min_temp == 0); + TERN_(DWIN_LCD_PROUI, HMI_data.ExtMinT = thermalManager.extrude_min_temp); } if (parser.seen('P')) diff --git a/Marlin/src/gcode/config/M304.cpp b/Marlin/src/gcode/config/M304.cpp index 97dc4be2..a71a34c6 100644 --- a/Marlin/src/gcode/config/M304.cpp +++ b/Marlin/src/gcode/config/M304.cpp @@ -36,17 +36,17 @@ */ 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.set_Kp(parser.value_float()); + if (parser.seenval('I')) thermalManager.temp_bed.pid.set_Ki(parser.value_float()); + if (parser.seenval('D')) thermalManager.temp_bed.pid.set_Kd(parser.value_float()); } void GcodeSuite::M304_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F(STR_BED_PID)); - SERIAL_ECHOLNPGM( - " M304 P", thermalManager.temp_bed.pid.Kp - , " I", unscalePID_i(thermalManager.temp_bed.pid.Ki) - , " D", unscalePID_d(thermalManager.temp_bed.pid.Kd) + SERIAL_ECHOLNPGM(" M304" + " P", thermalManager.temp_bed.pid.p() + , " I", thermalManager.temp_bed.pid.i() + , " D", thermalManager.temp_bed.pid.d() ); } diff --git a/Marlin/src/gcode/config/M305.cpp b/Marlin/src/gcode/config/M305.cpp index 6957eef0..48d7cf18 100644 --- a/Marlin/src/gcode/config/M305.cpp +++ b/Marlin/src/gcode/config/M305.cpp @@ -52,24 +52,24 @@ 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 else if (t_index < 0) { // ...all user thermistors - LOOP_L_N(i, USER_THERMISTORS) + for (uint8_t i = 0; i < USER_THERMISTORS; ++i) thermalManager.M305_report(i); } else // ...one user thermistor diff --git a/Marlin/src/gcode/config/M309.cpp b/Marlin/src/gcode/config/M309.cpp index 57702329..49531130 100644 --- a/Marlin/src/gcode/config/M309.cpp +++ b/Marlin/src/gcode/config/M309.cpp @@ -36,17 +36,17 @@ */ void GcodeSuite::M309() { if (!parser.seen("PID")) return M309_report(); - if (parser.seen('P')) thermalManager.temp_chamber.pid.Kp = parser.value_float(); - if (parser.seen('I')) thermalManager.temp_chamber.pid.Ki = scalePID_i(parser.value_float()); - if (parser.seen('D')) thermalManager.temp_chamber.pid.Kd = scalePID_d(parser.value_float()); + if (parser.seenval('P')) thermalManager.temp_chamber.pid.set_Kp(parser.value_float()); + if (parser.seenval('I')) thermalManager.temp_chamber.pid.set_Ki(parser.value_float()); + if (parser.seenval('D')) thermalManager.temp_chamber.pid.set_Kd(parser.value_float()); } void GcodeSuite::M309_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F(STR_CHAMBER_PID)); - SERIAL_ECHOLNPGM( - " M309 P", thermalManager.temp_chamber.pid.Kp - , " I", unscalePID_i(thermalManager.temp_chamber.pid.Ki) - , " D", unscalePID_d(thermalManager.temp_chamber.pid.Kd) + SERIAL_ECHOLNPGM(" M309" + " P", thermalManager.temp_chamber.pid.p() + , " I", thermalManager.temp_chamber.pid.i() + , " D", thermalManager.temp_chamber.pid.d() ); } diff --git a/Marlin/src/gcode/config/M43.cpp b/Marlin/src/gcode/config/M43.cpp index 097aa142..52ede7d2 100644 --- a/Marlin/src/gcode/config/M43.cpp +++ b/Marlin/src/gcode/config/M43.cpp @@ -25,7 +25,7 @@ #if ENABLED(PINS_DEBUGGING) #include "../gcode.h" -#include "../../MarlinCore.h" // for pin_is_protected +#include "../../MarlinCore.h" // for pin_is_protected, wait_for_user #include "../../pins/pinsDebug.h" #include "../../module/endstops.h" @@ -61,21 +61,23 @@ inline void toggle_pins() { end = PARSED_PIN_INDEX('L', NUM_DIGITAL_PINS - 1), wait = parser.intval('W', 500); - LOOP_S_LE_N(i, start, end) { + for (uint8_t i = start; i <= end; ++i) { pin_t pin = GET_PIN_MAP_PIN_M43(i); - if (!VALID_PIN(pin)) continue; + if (!isValidPin(pin)) continue; if (M43_NEVER_TOUCH(i) || (!ignore_protection && pin_is_protected(pin))) { - report_pin_state_extended(pin, ignore_protection, true, F("Untouched ")); + printPinStateExt(pin, ignore_protection, true, F("Untouched ")); SERIAL_EOL(); } else { - watchdog_refresh(); - report_pin_state_extended(pin, ignore_protection, true, F("Pulsing ")); - #ifdef __STM32F1__ - const auto prior_mode = _GET_MODE(i); - #else - const bool prior_mode = GET_PINMODE(pin); - #endif + hal.watchdog_refresh(); + printPinStateExt(pin, ignore_protection, true, F("Pulsing ")); + const auto prior_mode = ( + #ifdef __STM32F1__ + _GET_MODE(i) + #else + getValidPinMode(pin) + #endif + ); #if AVR_AT90USB1286_FAMILY // Teensy IDEs don't know about these pins so must use FASTIO if (pin == TEENSY_E2) { SET_OUTPUT(TEENSY_E2); @@ -98,10 +100,10 @@ inline void toggle_pins() { { pinMode(pin, OUTPUT); for (int16_t j = 0; j < repeat; j++) { - watchdog_refresh(); extDigitalWrite(pin, 0); safe_delay(wait); - watchdog_refresh(); extDigitalWrite(pin, 1); safe_delay(wait); - watchdog_refresh(); extDigitalWrite(pin, 0); safe_delay(wait); - watchdog_refresh(); + hal.watchdog_refresh(); extDigitalWrite(pin, 0); safe_delay(wait); + hal.watchdog_refresh(); extDigitalWrite(pin, 1); safe_delay(wait); + hal.watchdog_refresh(); extDigitalWrite(pin, 0); safe_delay(wait); + hal.watchdog_refresh(); } } #ifdef __STM32F1__ @@ -118,7 +120,7 @@ inline void toggle_pins() { inline void servo_probe_test() { - #if !(NUM_SERVOS > 0 && HAS_SERVO_0) + #if !HAS_SERVO_0 SERIAL_ERROR_MSG("SERVO not set up."); @@ -139,24 +141,15 @@ inline void servo_probe_test() { bool deploy_state = false, stow_state; #if ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN) - #define PROBE_TEST_PIN Z_MIN_PIN - constexpr bool probe_inverting = Z_MIN_ENDSTOP_INVERTING; - - SERIAL_ECHOLNPGM(". Probe Z_MIN_PIN: ", PROBE_TEST_PIN); - SERIAL_ECHOPGM(". Z_MIN_ENDSTOP_INVERTING: "); - + #define _PROBE_PREF "Z_MIN" #else - #define PROBE_TEST_PIN Z_MIN_PROBE_PIN - constexpr bool probe_inverting = Z_MIN_PROBE_ENDSTOP_INVERTING; - - SERIAL_ECHOLNPGM(". Probe Z_MIN_PROBE_PIN: ", PROBE_TEST_PIN); - SERIAL_ECHOPGM( ". Z_MIN_PROBE_ENDSTOP_INVERTING: "); - + #define _PROBE_PREF "Z_MIN_PROBE" #endif - serialprint_truefalse(probe_inverting); + SERIAL_ECHOLNPGM(". Probe " _PROBE_PREF "_PIN: ", PROBE_TEST_PIN); + serial_ternary(F(". " _PROBE_PREF "_ENDSTOP_HIT_STATE: "), PROBE_HIT_STATE, F("HIGH"), F("LOW")); SERIAL_EOL(); SET_INPUT_PULLUP(PROBE_TEST_PIN); @@ -195,38 +188,37 @@ inline void servo_probe_test() { if (!blt) { // DEPLOY and STOW 4 times and see if the signal follows // Then it is a mechanical switch - uint8_t i = 0; SERIAL_ECHOLNPGM(". Deploy & stow 4 times"); - do { - MOVE_SERVO(probe_index, servo_angles[Z_PROBE_SERVO_NR][0]); // Deploy + for (uint8_t i = 0; i < 4; ++i) { + 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); + } - if (probe_inverting != deploy_state) SERIAL_ECHOLNPGM("WARNING: INVERTING setting probably backwards."); + if (probe_inverting != deploy_state) SERIAL_ECHOLNPGM("WARNING: " _PROBE_PREF "_ENDSTOP_HIT_STATE is probably wrong."); if (deploy_state != stow_state) { SERIAL_ECHOLNPGM("= Mechanical Switch detected"); if (deploy_state) { - SERIAL_ECHOLNPGM(" DEPLOYED state: HIGH (logic 1)", - " STOWED (triggered) state: LOW (logic 0)"); + SERIAL_ECHOLNPGM(". DEPLOYED state: HIGH (logic 1)\n" + ". STOWED (triggered) state: LOW (logic 0)"); } else { - SERIAL_ECHOLNPGM(" DEPLOYED state: LOW (logic 0)", - " STOWED (triggered) state: HIGH (logic 1)"); + SERIAL_ECHOLNPGM(". DEPLOYED state: LOW (logic 0)\n" + ". STOWED (triggered) state: HIGH (logic 1)"); } #if ENABLED(BLTOUCH) - SERIAL_ECHOLNPGM("FAIL: BLTOUCH enabled - Set up this device as a Servo Probe with INVERTING set to 'true'."); + SERIAL_ECHOLNPGM("FAIL: Can't enable BLTOUCH. Check your settings."); #endif return; } } // 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 +248,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; } } @@ -313,55 +305,85 @@ void GcodeSuite::M43() { // 'P' Get the range of pins to test or watch uint8_t first_pin = PARSED_PIN_INDEX('P', 0), - last_pin = parser.seenval('P') ? first_pin : NUMBER_PINS_TOTAL - 1; + last_pin = parser.seenval('L') ? PARSED_PIN_INDEX('L', 0) : (parser.seenval('P') ? first_pin : (NUMBER_PINS_TOTAL) - 1); + + NOMORE(first_pin, (NUMBER_PINS_TOTAL) - 1); + NOMORE(last_pin, (NUMBER_PINS_TOTAL) - 1); - if (first_pin > last_pin) return; + if (first_pin > last_pin) { + const uint8_t f = first_pin; + first_pin = last_pin; + last_pin = f; + } // 'I' to ignore protected pins const bool ignore_protection = parser.boolval('I'); // 'W' Watch until click, M108, or reset if (parser.boolval('W')) { - SERIAL_ECHOLNPGM("Watching pins"); #ifdef ARDUINO_ARCH_SAM NOLESS(first_pin, 2); // Don't hijack the UART pins #endif - uint8_t pin_state[last_pin - first_pin + 1]; - LOOP_S_LE_N(i, first_pin, last_pin) { + + const uint8_t pin_count = last_pin - first_pin + 1; + uint8_t pin_state[pin_count]; + bool can_watch = false; + for (uint8_t i = first_pin; i <= last_pin; ++i) { pin_t pin = GET_PIN_MAP_PIN_M43(i); - if (!VALID_PIN(pin)) continue; + if (!isValidPin(pin)) continue; if (M43_NEVER_TOUCH(i) || (!ignore_protection && pin_is_protected(pin))) continue; + can_watch = true; pinMode(pin, INPUT_PULLUP); delay(1); - /* - if (IS_ANALOG(pin)) - pin_state[pin - first_pin] = analogRead(DIGITAL_PIN_TO_ANALOG_PIN(pin)); // int16_t pin_state[...] - else - //*/ - pin_state[i - first_pin] = extDigitalRead(pin); + /* + if (isAnalogPin(pin)) + pin_state[pin - first_pin] = analogRead(digitalPinToAnalogIndex(pin)); // int16_t pin_state[...] + else + //*/ + pin_state[i - first_pin] = extDigitalRead(pin); + } + + const bool multipin = (pin_count > 1); + + if (!can_watch) { + SERIAL_ECHOPGM("Specified pin"); + SERIAL_ECHOPGM_P(multipin ? PSTR("s are") : PSTR(" is")); + SERIAL_ECHOLNPGM(" protected. Use 'I' to override."); + return; } + // "Watching pin(s) # - #" + SERIAL_ECHOPGM("Watching pin"); + if (multipin) SERIAL_CHAR('s'); + SERIAL_CHAR(' '); SERIAL_ECHO(first_pin); + if (multipin) SERIAL_ECHOPGM(" - ", last_pin); + SERIAL_EOL(); + #if HAS_RESUME_CONTINUE KEEPALIVE_STATE(PAUSED_FOR_USER); wait_for_user = true; - TERN_(HOST_PROMPT_SUPPORT, hostui.prompt_do(PROMPT_USER_CONTINUE, F("M43 Wait Called"), FPSTR(CONTINUE_STR))); - TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired(F("M43 Wait Called"))); + TERN_(HOST_PROMPT_SUPPORT, hostui.continue_prompt(F("M43 Waiting..."))); + #if ENABLED(EXTENSIBLE_UI) + ExtUI::onUserConfirmRequired(F("M43 Waiting...")); + #else + LCD_MESSAGE(MSG_USERWAIT); + #endif #endif for (;;) { - LOOP_S_LE_N(i, first_pin, last_pin) { - pin_t pin = GET_PIN_MAP_PIN_M43(i); - if (!VALID_PIN(pin)) continue; + for (uint8_t i = first_pin; i <= last_pin; ++i) { + const pin_t pin = GET_PIN_MAP_PIN_M43(i); + if (!isValidPin(pin)) continue; if (M43_NEVER_TOUCH(i) || (!ignore_protection && pin_is_protected(pin))) continue; const byte val = /* - IS_ANALOG(pin) - ? analogRead(DIGITAL_PIN_TO_ANALOG_PIN(pin)) : // int16_t val + isAnalogPin(pin) + ? analogRead(digitalPinToAnalogIndex(pin)) : // int16_t val : //*/ extDigitalRead(pin); if (val != pin_state[i - first_pin]) { - report_pin_state_extended(pin, ignore_protection, false); + printPinStateExt(pin, ignore_protection, true); pin_state[i - first_pin] = val; } } @@ -373,12 +395,14 @@ void GcodeSuite::M43() { safe_delay(200); } + + TERN_(HAS_RESUME_CONTINUE, ui.reset_status()); } else { // Report current state of selected pin(s) - LOOP_S_LE_N(i, first_pin, last_pin) { - pin_t pin = GET_PIN_MAP_PIN_M43(i); - if (VALID_PIN(pin)) report_pin_state_extended(pin, ignore_protection, true); + for (uint8_t i = first_pin; i <= last_pin; ++i) { + const pin_t pin = GET_PIN_MAP_PIN_M43(i); + if (isValidPin(pin)) printPinStateExt(pin, ignore_protection, true); } } } diff --git a/Marlin/src/gcode/config/M540.cpp b/Marlin/src/gcode/config/M540.cpp index 54d52f3a..e751248d 100644 --- a/Marlin/src/gcode/config/M540.cpp +++ b/Marlin/src/gcode/config/M540.cpp @@ -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>) diff --git a/Marlin/src/gcode/config/M672.cpp b/Marlin/src/gcode/config/M672.cpp index af742305..064d05d0 100644 --- a/Marlin/src/gcode/config/M672.cpp +++ b/Marlin/src/gcode/config/M672.cpp @@ -53,8 +53,8 @@ // b7 b6 b5 b4 ~b4 ... hi bits, NOT last bit // b3 b2 b1 b0 ~b0 ... lo bits, NOT last bit // -void M672_send(uint8_t b) { // bit rate requirement: 1KHz +/- 30% - LOOP_L_N(bits, 14) { +void M672_send(uint8_t b) { // bit rate requirement: 1kHz +/- 30% + for (uint8_t bits = 0; bits < 14; ++bits) { switch (bits) { default: { OUT_WRITE(SMART_EFFECTOR_MOD_PIN, !!(b & 0x80)); b <<= 1; break; } // send bit, shift next into place case 7: diff --git a/Marlin/src/gcode/config/M92.cpp b/Marlin/src/gcode/config/M92.cpp index 54fe698f..b5bdd784 100644 --- a/Marlin/src/gcode/config/M92.cpp +++ b/Marlin/src/gcode/config/M92.cpp @@ -24,7 +24,7 @@ #include "../../module/planner.h" /** - * M92: Set axis steps-per-unit for one or more axes, X, Y, Z, and E. + * M92: Set axis steps-per-unit for one or more axes, X, Y, Z, [I, [J, [K, [U, [V, [W,]]]]]] and E. * (Follows the same syntax as G92) * * With multiple extruders use T to specify which one. @@ -37,17 +37,18 @@ * H - Specify micro-steps to use. Best guess if not supplied. * L - Desired layer height in current units. Nearest good heights are shown. */ + void GcodeSuite::M92() { const int8_t target_extruder = get_target_extruder_from_command(); if (target_extruder < 0) return; // No arguments? Show M92 report. - if (!parser.seen(LOGICAL_AXES_STRING TERN_(MAGIC_NUMBERS_GCODE, "HL"))) + if (!parser.seen(STR_AXES_LOGICAL TERN_(MAGIC_NUMBERS_GCODE, "HL"))) return M92_report(true, target_extruder); LOOP_LOGICAL_AXES(i) { - if (parser.seenval(axis_codes[i])) { + if (parser.seenval(AXIS_CHAR(i))) { if (TERN1(HAS_EXTRUDERS, i != E_AXIS)) planner.settings.axis_steps_per_mm[i] = parser.value_per_axis_units((AxisEnum)i); else { @@ -92,21 +93,30 @@ void GcodeSuite::M92() { void GcodeSuite::M92_report(const bool forReplay/*=true*/, const int8_t e/*=-1*/) { report_heading_etc(forReplay, F(STR_STEPS_PER_UNIT)); - SERIAL_ECHOPGM_P(LIST_N(DOUBLE(LINEAR_AXES), - PSTR(" M92 X"), LINEAR_UNIT(planner.settings.axis_steps_per_mm[X_AXIS]), - SP_Y_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Y_AXIS]), - SP_Z_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Z_AXIS]), - SP_I_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[I_AXIS]), - SP_J_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[J_AXIS]), - SP_K_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[K_AXIS])) - ); + #if NUM_AXES + #define PRINT_EOL + SERIAL_ECHOPGM_P(LIST_N(DOUBLE(NUM_AXES), + PSTR(" M92 X"), LINEAR_UNIT(planner.settings.axis_steps_per_mm[X_AXIS]), + SP_Y_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Y_AXIS]), + SP_Z_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Z_AXIS]), + SP_I_STR, I_AXIS_UNIT(planner.settings.axis_steps_per_mm[I_AXIS]), + SP_J_STR, J_AXIS_UNIT(planner.settings.axis_steps_per_mm[J_AXIS]), + SP_K_STR, K_AXIS_UNIT(planner.settings.axis_steps_per_mm[K_AXIS]), + SP_U_STR, U_AXIS_UNIT(planner.settings.axis_steps_per_mm[U_AXIS]), + SP_V_STR, V_AXIS_UNIT(planner.settings.axis_steps_per_mm[V_AXIS]), + SP_W_STR, W_AXIS_UNIT(planner.settings.axis_steps_per_mm[W_AXIS]) + )); + #endif + #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS) + #define PRINT_EOL SERIAL_ECHOPGM_P(SP_E_STR, VOLUMETRIC_UNIT(planner.settings.axis_steps_per_mm[E_AXIS])); #endif - SERIAL_EOL(); + + if (ENABLED(PRINT_EOL)) SERIAL_EOL(); #if ENABLED(DISTINCT_E_FACTORS) - LOOP_L_N(i, E_STEPPERS) { + for (uint8_t i = 0; i < E_STEPPERS; ++i) { if (e >= 0 && i != e) continue; report_echo_start(forReplay); SERIAL_ECHOLNPGM_P( diff --git a/Marlin/src/gcode/control/M10-M11.cpp b/Marlin/src/gcode/control/M10_M11.cpp similarity index 95% rename from Marlin/src/gcode/control/M10-M11.cpp rename to Marlin/src/gcode/control/M10_M11.cpp index d5a69dcf..8fd299c5 100644 --- a/Marlin/src/gcode/control/M10-M11.cpp +++ b/Marlin/src/gcode/control/M10_M11.cpp @@ -20,6 +20,11 @@ * */ +/** + * gcode/control/M10_M11.cpp + * Air Evacuation + */ + #include "../../inc/MarlinConfig.h" #if ENABLED(AIR_EVACUATION) diff --git a/Marlin/src/gcode/control/M111.cpp b/Marlin/src/gcode/control/M111.cpp index 08c39b76..39fce1e5 100644 --- a/Marlin/src/gcode/control/M111.cpp +++ b/Marlin/src/gcode/control/M111.cpp @@ -34,44 +34,41 @@ void GcodeSuite::M111() { static PGMSTR(str_debug_8, STR_DEBUG_DRYRUN); static PGMSTR(str_debug_16, STR_DEBUG_COMMUNICATION); #if ENABLED(DEBUG_LEVELING_FEATURE) - static PGMSTR(str_debug_lvl, STR_DEBUG_LEVELING); + static PGMSTR(str_debug_detail, STR_DEBUG_DETAIL); #endif static PGM_P const debug_strings[] PROGMEM = { str_debug_1, str_debug_2, str_debug_4, str_debug_8, str_debug_16, - TERN_(DEBUG_LEVELING_FEATURE, str_debug_lvl) + TERN_(DEBUG_LEVELING_FEATURE, str_debug_detail) }; SERIAL_ECHO_START(); SERIAL_ECHOPGM(STR_DEBUG_PREFIX); if (marlin_debug_flags) { uint8_t comma = 0; - LOOP_L_N(i, COUNT(debug_strings)) { + for (uint8_t i = 0; i < COUNT(debug_strings); ++i) { 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])); } } } else { SERIAL_ECHOPGM(STR_DEBUG_OFF); - #if !defined(__AVR__) || !defined(USBCON) + #if !(defined(__AVR__) && defined(USBCON)) #if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS) SERIAL_ECHOPGM("\nBuffer Overruns: ", MYSERIAL1.buffer_overruns()); #endif - #if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS) SERIAL_ECHOPGM("\nFraming Errors: ", MYSERIAL1.framing_errors()); #endif - #if ENABLED(SERIAL_STATS_DROPPED_RX) SERIAL_ECHOPGM("\nDropped bytes: ", MYSERIAL1.dropped()); #endif - #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) SERIAL_ECHOPGM("\nMax RX Queue Size: ", MYSERIAL1.rxMaxEnqueued()); #endif - #endif // !__AVR__ || !USBCON + #endif // !(__AVR__ && USBCON) } SERIAL_EOL(); } diff --git a/Marlin/src/gcode/control/M17_M18_M84.cpp b/Marlin/src/gcode/control/M17_M18_M84.cpp index 4683786f..1742d288 100644 --- a/Marlin/src/gcode/control/M17_M18_M84.cpp +++ b/Marlin/src/gcode/control/M17_M18_M84.cpp @@ -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) @@ -33,8 +35,8 @@ #include "../../core/debug_out.h" #include "../../libs/hex_print.h" -inline axis_flags_t selected_axis_bits() { - axis_flags_t selected{0}; +inline stepper_flags_t selected_axis_bits() { + stepper_flags_t selected{0}; #if HAS_EXTRUDERS if (parser.seen('E')) { if (E_TERN0(parser.has_value())) { @@ -43,22 +45,27 @@ inline axis_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( - (parser.seen_test('X') << X_AXIS), - | (parser.seen_test('Y') << Y_AXIS), - | (parser.seen_test('Z') << Z_AXIS), - | (parser.seen_test(AXIS4_NAME) << I_AXIS), - | (parser.seen_test(AXIS5_NAME) << J_AXIS), - | (parser.seen_test(AXIS6_NAME) << K_AXIS) - ); + #if NUM_AXES + selected.bits |= NUM_AXIS_GANG( + (parser.seen_test('X') << X_AXIS), + | (parser.seen_test('Y') << Y_AXIS), + | (parser.seen_test('Z') << Z_AXIS), + | (parser.seen_test(AXIS4_NAME) << I_AXIS), + | (parser.seen_test(AXIS5_NAME) << J_AXIS), + | (parser.seen_test(AXIS6_NAME) << K_AXIS), + | (parser.seen_test(AXIS7_NAME) << U_AXIS), + | (parser.seen_test(AXIS8_NAME) << V_AXIS), + | (parser.seen_test(AXIS9_NAME) << W_AXIS) + ); + #endif return selected; } // Enable specified axes and warn about other affected axes -void do_enable(const axis_flags_t to_enable) { +void do_enable(const stepper_flags_t to_enable) { const ena_mask_t was_enabled = stepper.axis_enabled.bits, shall_enable = to_enable.bits & ~was_enabled; @@ -66,18 +73,18 @@ void do_enable(const axis_flags_t to_enable) { if (!shall_enable) return; // All specified axes already enabled? - ena_mask_t also_enabled = 0; // Track steppers enabled due to overlap + ena_mask_t also_enabled = 0; // Track steppers enabled due to overlap // Enable all flagged axes - LOOP_LINEAR_AXES(a) { + LOOP_NUM_AXES(a) { if (TEST(shall_enable, a)) { stepper.enable_axis(AxisEnum(a)); // Mark and enable the requested axis - DEBUG_ECHOLNPGM("Enabled ", axis_codes[a], " (", a, ") with overlap ", hex_word(enable_overlap[a]), " ... Enabled: ", hex_word(stepper.axis_enabled.bits)); + DEBUG_ECHOLNPGM("Enabled ", AXIS_CHAR(a), " (", a, ") with overlap ", hex_word(enable_overlap[a]), " ... Enabled: ", hex_word(stepper.axis_enabled.bits)); also_enabled |= enable_overlap[a]; } } #if HAS_EXTRUDERS - LOOP_L_N(e, EXTRUDERS) { + EXTRUDER_LOOP() { const uint8_t a = INDEX_OF_AXIS(E_AXIS, e); if (TEST(shall_enable, a)) { stepper.ENABLE_EXTRUDER(e); @@ -89,7 +96,7 @@ void do_enable(const axis_flags_t to_enable) { if ((also_enabled &= ~(shall_enable | was_enabled))) { SERIAL_CHAR('('); - LOOP_LINEAR_AXES(a) if (TEST(also_enabled, a)) SERIAL_CHAR(axis_codes[a], ' '); + LOOP_NUM_AXES(a) if (TEST(also_enabled, a)) SERIAL_CHAR(AXIS_CHAR(a), ' '); #if HAS_EXTRUDERS #define _EN_ALSO(N) if (TEST(also_enabled, INDEX_OF_AXIS(E_AXIS, N))) SERIAL_CHAR('E', '0' + N, ' '); REPEAT(EXTRUDERS, _EN_ALSO) @@ -125,14 +132,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_NUM_AXES(a) + if (parser.seen_test(AXIS_CHAR(a))) stepper.enable_axis((AxisEnum)a); } } else { @@ -141,7 +142,7 @@ void GcodeSuite::M17() { } } -void try_to_disable(const axis_flags_t to_disable) { +void try_to_disable(const stepper_flags_t to_disable) { ena_mask_t still_enabled = to_disable.bits & stepper.axis_enabled.bits; DEBUG_ECHOLNPGM("Enabled: ", hex_word(stepper.axis_enabled.bits), " To Disable: ", hex_word(to_disable.bits), " | ", hex_word(still_enabled)); @@ -149,9 +150,9 @@ void try_to_disable(const axis_flags_t to_disable) { if (!still_enabled) return; // Attempt to disable all flagged axes - LOOP_LINEAR_AXES(a) + LOOP_NUM_AXES(a) if (TEST(to_disable.bits, a)) { - DEBUG_ECHOPGM("Try to disable ", axis_codes[a], " (", a, ") with overlap ", hex_word(enable_overlap[a]), " ... "); + DEBUG_ECHOPGM("Try to disable ", AXIS_CHAR(a), " (", a, ") with overlap ", hex_word(enable_overlap[a]), " ... "); if (stepper.disable_axis(AxisEnum(a))) { // Mark the requested axis and request to disable DEBUG_ECHOPGM("OK"); still_enabled &= ~(_BV(a) | enable_overlap[a]); // If actually disabled, clear one or more tracked bits @@ -161,7 +162,7 @@ void try_to_disable(const axis_flags_t to_disable) { DEBUG_ECHOLNPGM(" ... still_enabled=", hex_word(still_enabled)); } #if HAS_EXTRUDERS - LOOP_L_N(e, EXTRUDERS) { + EXTRUDER_LOOP() { const uint8_t a = INDEX_OF_AXIS(E_AXIS, e); if (TEST(to_disable.bits, a)) { DEBUG_ECHOPGM("Try to disable E", AS_DIGIT(e), " (", a, ") with overlap ", hex_word(enable_overlap[a]), " ... "); @@ -178,7 +179,7 @@ void try_to_disable(const axis_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_NUM_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) @@ -187,14 +188,14 @@ void try_to_disable(const axis_flags_t to_disable) { }; // If any of the requested axes are still enabled, give a warning - LOOP_LINEAR_AXES(a) { + LOOP_NUM_AXES(a) { if (TEST(still_enabled, a)) { - SERIAL_CHAR(axis_codes[a]); + SERIAL_CHAR(AXIS_CHAR(a)); overlap_warning(stepper.axis_enabled.bits & enable_overlap[a]); } } #if HAS_EXTRUDERS - LOOP_L_N(e, EXTRUDERS) { + EXTRUDER_LOOP() { const uint8_t a = INDEX_OF_AXIS(E_AXIS, e); if (TEST(still_enabled, a)) { SERIAL_CHAR('E', '0' + e); @@ -213,7 +214,16 @@ void try_to_disable(const axis_flags_t to_disable) { void GcodeSuite::M18_M84() { if (parser.seenval('S')) { reset_stepper_timeout(); - stepper_inactive_time = parser.value_millis_from_seconds(); + #if HAS_DISABLE_IDLE_AXES + const millis_t ms = parser.value_millis_from_seconds(); + #if LASER_SAFETY_TIMEOUT_MS > 0 + if (ms && ms <= LASER_SAFETY_TIMEOUT_MS) { + SERIAL_ECHO_MSG("M18 timeout must be > ", MS_TO_SEC(LASER_SAFETY_TIMEOUT_MS + 999), " s for laser safety."); + return; + } + #endif + stepper_inactive_time = ms; + #endif } else { if (parser.seen_axis()) { @@ -229,19 +239,13 @@ 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_NUM_AXES(a) + if (parser.seen_test(AXIS_CHAR(a))) stepper.disable_axis((AxisEnum)a); } } else planner.finish_and_disable(); - TERN_(AUTO_BED_LEVELING_UBL, ubl.steppers_were_disabled()); + TERN_(AUTO_BED_LEVELING_UBL, bedlevel.steppers_were_disabled()); } } diff --git a/Marlin/src/gcode/control/M226.cpp b/Marlin/src/gcode/control/M226.cpp index 63f022e8..4eb3db4b 100644 --- a/Marlin/src/gcode/control/M226.cpp +++ b/Marlin/src/gcode/control/M226.cpp @@ -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(); diff --git a/Marlin/src/gcode/control/M280.cpp b/Marlin/src/gcode/control/M280.cpp index 2a8e73ea..82981e44 100644 --- a/Marlin/src/gcode/control/M280.cpp +++ b/Marlin/src/gcode/control/M280.cpp @@ -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()); diff --git a/Marlin/src/gcode/control/M282.cpp b/Marlin/src/gcode/control/M282.cpp index e6f5ce7d..3ac5ac9f 100644 --- a/Marlin/src/gcode/control/M282.cpp +++ b/Marlin/src/gcode/control/M282.cpp @@ -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"); diff --git a/Marlin/src/gcode/control/M3-M5.cpp b/Marlin/src/gcode/control/M3-M5.cpp index ddbbc4ab..ec24cf8a 100644 --- a/Marlin/src/gcode/control/M3-M5.cpp +++ b/Marlin/src/gcode/control/M3-M5.cpp @@ -26,24 +26,31 @@ #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) + * + * M3I - Enable continuous inline power to be processed by the planner, with power + * calculated and set in the planner blocks, processed inline during stepping. + * In 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. * * Spindle: * M3 - Spindle ON (Clockwise) * M4 - Spindle ON (Counter-clockwise) * * Parameters: - * S - Set power. S0 will turn the spindle/laser off, except in relative mode. - * O - Set power and OCR (oscillator count register) + * S - 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. + * At least 12.8kHz (50Hz * 256) is needed for Spindle PWM. * Hardware PWM is required on AVR. ISRs are too slow. * * NOTE: WGM for timers 3, 4, and 5 must be either Mode 1 or Mode 5. @@ -66,77 +73,84 @@ * PWM duty cycle goes from 0 (off) to 255 (always on). */ void GcodeSuite::M3_M4(const bool is_M4) { - #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 LASER_SAFETY_TIMEOUT_MS > 0 + reset_stepper_timeout(); // Reset timeout to allow subsequent G-code to power the laser (imm.) #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())); - #else - cutter.set_inline_enabled(true); - #endif - return; + 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); } - // 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) + auto get_s_power = [] { + if (parser.seenval('S')) { + const float v = parser.value_float(); + cutter.menuPower = cutter.unitPower = TERN(LASER_POWER_TRAP, v, cutter.power_to_range(v)); } - else - cutter.set_power(cutter.upower_to_ocr(get_s_power())); - #elif ENABLED(SPINDLE_SERVO) - cutter.set_power(get_s_power()); - #else + else if (cutter.cutter_mode == CUTTER_MODE_STANDARD) + cutter.menuPower = cutter.unitPower = cutter.cpwr_to_upwr(SPEED_POWER_STARTUP); + + // 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(cutter.unitPower), cutter.unitPower > 0 ? 255 : 0); + }; + + 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 + planner.synchronize(); + cutter.inline_power(cutter.power); + #endif + #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) + * + * Laser: + * M5 - Set power output to 0 (leaving inline mode unchanged). + * M5I - Clear inline mode and set power to 0. + * + * Spindle: + * M5 - Spindle OFF */ 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 diff --git a/Marlin/src/gcode/control/M350_M351.cpp b/Marlin/src/gcode/control/M350_M351.cpp index a92238e4..425abad5 100644 --- a/Marlin/src/gcode/control/M350_M351.cpp +++ b/Marlin/src/gcode/control/M350_M351.cpp @@ -27,35 +27,42 @@ #include "../gcode.h" #include "../../module/stepper.h" +#if NUM_AXES == XYZ && EXTRUDERS >= 1 + #define HAS_M350_B_PARAM 1 // "5th axis" (after E0) for an original XYZEB setup. +#endif + /** * M350: Set axis microstepping modes. S sets mode for all drivers. * * 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()); + TERN_(HAS_M350_B_PARAM, if (parser.seenval('B')) stepper.microstep_mode(E_AXIS + 1, parser.value_byte())); stepper.microstep_readings(); } /** - * M351: Toggle MS1 MS2 pins directly with axis codes X Y Z E B + * M351: Toggle MS1 MS2 pins directly with axis codes X Y Z . . . E [B] * S# determines MS1, MS2 or MS3, X# sets the pin high/low. + * + * Parameter 'B' sets "5th axis" (after E0) only for an original XYZEB setup. */ void GcodeSuite::M351() { + const int8_t bval = TERN(HAS_M350_B_PARAM, parser.byteval('B', -1), -1); UNUSED(bval); if (parser.seenval('S')) switch (parser.value_byte()) { case 1: - LOOP_LOGICAL_AXES(i) if (parser.seenval(axis_codes[i])) stepper.microstep_ms(i, parser.value_byte(), -1, -1); - if (parser.seenval('B')) stepper.microstep_ms(4, parser.value_byte(), -1, -1); + LOOP_LOGICAL_AXES(i) if (parser.seenval(AXIS_CHAR(i))) stepper.microstep_ms(i, parser.value_byte(), -1, -1); + TERN_(HAS_M350_B_PARAM, if (bval >= 0) stepper.microstep_ms(E_AXIS + 1, bval != 0, -1, -1)); break; case 2: - LOOP_LOGICAL_AXES(i) if (parser.seenval(axis_codes[i])) stepper.microstep_ms(i, -1, parser.value_byte(), -1); - if (parser.seenval('B')) stepper.microstep_ms(4, -1, parser.value_byte(), -1); + LOOP_LOGICAL_AXES(i) if (parser.seenval(AXIS_CHAR(i))) stepper.microstep_ms(i, -1, parser.value_byte(), -1); + TERN_(HAS_M350_B_PARAM, if (bval >= 0) stepper.microstep_ms(E_AXIS + 1, -1, bval != 0, -1)); break; case 3: - LOOP_LOGICAL_AXES(i) if (parser.seenval(axis_codes[i])) stepper.microstep_ms(i, -1, -1, parser.value_byte()); - if (parser.seenval('B')) stepper.microstep_ms(4, -1, -1, parser.value_byte()); + LOOP_LOGICAL_AXES(i) if (parser.seenval(AXIS_CHAR(i))) stepper.microstep_ms(i, -1, -1, parser.value_byte()); + TERN_(HAS_M350_B_PARAM, if (bval >= 0) stepper.microstep_ms(E_AXIS + 1, -1, -1, bval != 0)); break; } stepper.microstep_readings(); diff --git a/Marlin/src/gcode/control/M380_M381.cpp b/Marlin/src/gcode/control/M380_M381.cpp index 3f5b2524..20d24484 100644 --- a/Marlin/src/gcode/control/M380_M381.cpp +++ b/Marlin/src/gcode/control/M380_M381.cpp @@ -22,7 +22,7 @@ #include "../../inc/MarlinConfig.h" -#if EITHER(EXT_SOLENOID, MANUAL_SOLENOID_CONTROL) +#if ANY(EXT_SOLENOID, MANUAL_SOLENOID_CONTROL) #include "../gcode.h" #include "../../feature/solenoid.h" @@ -37,7 +37,7 @@ void GcodeSuite::M380() { #if ENABLED(MANUAL_SOLENOID_CONTROL) enable_solenoid(parser.intval('S', active_extruder)); #else - enable_solenoid_on_active_extruder(); + enable_solenoid(active_extruder); #endif } diff --git a/Marlin/src/gcode/control/M42.cpp b/Marlin/src/gcode/control/M42.cpp index 77c0ccc4..13965cb7 100644 --- a/Marlin/src/gcode/control/M42.cpp +++ b/Marlin/src/gcode/control/M42.cpp @@ -25,7 +25,6 @@ #if ENABLED(DIRECT_PIN_CONTROL) #include "../gcode.h" -#include "../../MarlinCore.h" // for pin_is_protected #if HAS_FAN #include "../../module/temperature.h" @@ -38,12 +37,14 @@ #define OUTPUT_OPEN_DRAIN OUTPUT_OPEN_DRAIN #endif +bool pin_is_protected(const pin_t pin); + void protected_pin_err() { SERIAL_ERROR_MSG(STR_ERR_PROTECTED_PIN); } /** - * M42: Change pin status via GCode + * M42: Change pin status via G-Code * * P Pin number (LED if omitted) * For LPC1768 specify pin P1_02 as M42 P102, @@ -52,7 +53,8 @@ void protected_pin_err() { * S Pin status from 0 - 255 * I Flag to ignore Marlin's pin protection * - * M Pin mode: 0=INPUT 1=OUTPUT 2=INPUT_PULLUP 3=INPUT_PULLDOWN + * T Pin mode: 0=INPUT 1=OUTPUT 2=INPUT_PULLUP 3=INPUT_PULLDOWN + * 4=INPUT_ANALOG 5=OUTPUT_OPEN_DRAIN */ void GcodeSuite::M42() { const int pin_index = PARSED_PIN_INDEX('P', GET_PIN_MAP_INDEX(LED_PIN)); @@ -63,7 +65,7 @@ void GcodeSuite::M42() { if (!parser.boolval('I') && pin_is_protected(pin)) return protected_pin_err(); bool avoidWrite = false; - if (parser.seenval('M')) { + if (parser.seenval('T')) { switch (parser.value_byte()) { case 0: pinMode(pin, INPUT); avoidWrite = true; break; case 1: pinMode(pin, OUTPUT); break; @@ -86,30 +88,8 @@ void GcodeSuite::M42() { #if HAS_FAN switch (pin) { - #if HAS_FAN0 - case FAN0_PIN: thermalManager.fan_speed[0] = pin_status; return; - #endif - #if HAS_FAN1 - case FAN1_PIN: thermalManager.fan_speed[1] = pin_status; return; - #endif - #if HAS_FAN2 - case FAN2_PIN: thermalManager.fan_speed[2] = pin_status; return; - #endif - #if HAS_FAN3 - case FAN3_PIN: thermalManager.fan_speed[3] = pin_status; return; - #endif - #if HAS_FAN4 - case FAN4_PIN: thermalManager.fan_speed[4] = pin_status; return; - #endif - #if HAS_FAN5 - case FAN5_PIN: thermalManager.fan_speed[5] = pin_status; return; - #endif - #if HAS_FAN6 - case FAN6_PIN: thermalManager.fan_speed[6] = pin_status; return; - #endif - #if HAS_FAN7 - case FAN7_PIN: thermalManager.fan_speed[7] = pin_status; return; - #endif + #define _CASE(N) case FAN##N##_PIN: thermalManager.fan_speed[N] = pin_status; return; + REPEAT(FAN_COUNT, _CASE) } #endif @@ -119,17 +99,17 @@ void GcodeSuite::M42() { } // An OUTPUT_OPEN_DRAIN should not be changed to normal OUTPUT (STM32) - // Use M42 Px M1/5 S0/1 to set the output type and then set value + // Use M42 Px T1/5 S0/1 to set the output type and then set value #ifndef OUTPUT_OPEN_DRAIN pinMode(pin, OUTPUT); #endif extDigitalWrite(pin, pin_status); #ifdef ARDUINO_ARCH_STM32 - // A simple I/O will be set to 0 by set_pwm_duty() + // A simple I/O will be set to 0 by hal.set_pwm_duty() if (pin_status <= 1 && !PWM_PIN(pin)) return; #endif - set_pwm_duty(pin, pin_status); + hal.set_pwm_duty(pin, pin_status); } #endif // DIRECT_PIN_CONTROL diff --git a/Marlin/src/gcode/control/M605.cpp b/Marlin/src/gcode/control/M605.cpp index 788659e7..167cdae4 100644 --- a/Marlin/src/gcode/control/M605.cpp +++ b/Marlin/src/gcode/control/M605.cpp @@ -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; @@ -128,25 +127,24 @@ case DXC_MIRRORED_MODE: DEBUG_ECHOPGM("MIRRORED"); break; } DEBUG_ECHOPGM("\nActive Ext: ", active_extruder); - if (!active_extruder_parked) DEBUG_ECHOPGM(" NOT "); - DEBUG_ECHOPGM(" parked."); - DEBUG_ECHOPGM("\nactive_extruder_x_pos: ", current_position.x); - DEBUG_ECHOPGM("\ninactive_extruder_x: ", inactive_extruder_x); - DEBUG_ECHOPGM("\nextruder_duplication_enabled: ", extruder_duplication_enabled); - DEBUG_ECHOPGM("\nduplicate_extruder_x_offset: ", duplicate_extruder_x_offset); - DEBUG_ECHOPGM("\nduplicate_extruder_temp_offset: ", duplicate_extruder_temp_offset); - DEBUG_ECHOPGM("\ndelayed_move_time: ", delayed_move_time); - DEBUG_ECHOPGM("\nX1 Home X: ", x_home_pos(0), "\nX1_MIN_POS=", X1_MIN_POS, "\nX1_MAX_POS=", X1_MAX_POS); - DEBUG_ECHOPGM("\nX2 Home X: ", x_home_pos(1), "\nX2_MIN_POS=", X2_MIN_POS, "\nX2_MAX_POS=", X2_MAX_POS); - DEBUG_ECHOPGM("\nX2_HOME_DIR=", X2_HOME_DIR, "\nX2_HOME_POS=", X2_HOME_POS); - DEBUG_ECHOPGM("\nDEFAULT_DUAL_X_CARRIAGE_MODE=", STRINGIFY(DEFAULT_DUAL_X_CARRIAGE_MODE)); - DEBUG_ECHOPGM("\toolchange_settings.z_raise=", toolchange_settings.z_raise); - DEBUG_ECHOPGM("\nDEFAULT_DUPLICATION_X_OFFSET=", DEFAULT_DUPLICATION_X_OFFSET); - DEBUG_EOL(); + if (!active_extruder_parked) DEBUG_ECHOPGM(" NOT ", F(" parked.")); + DEBUG_ECHOLNPGM( + "\nactive_extruder_x_pos: ", current_position.x, + "\ninactive_extruder_x: ", inactive_extruder_x, + "\nextruder_duplication_enabled: ", extruder_duplication_enabled, + "\nduplicate_extruder_x_offset: ", duplicate_extruder_x_offset, + "\nduplicate_extruder_temp_offset: ", duplicate_extruder_temp_offset, + "\ndelayed_move_time: ", delayed_move_time, + "\nX1 Home: ", x_home_pos(0), " X1_MIN_POS=", X1_MIN_POS, " X1_MAX_POS=", X1_MAX_POS, + "\nX2 Home: ", x_home_pos(1), " X2_MIN_POS=", X2_MIN_POS, " X2_MAX_POS=", X2_MAX_POS, + "\nDEFAULT_DUAL_X_CARRIAGE_MODE=", STRINGIFY(DEFAULT_DUAL_X_CARRIAGE_MODE), + "\toolchange_settings.z_raise=", toolchange_settings.z_raise, + "\nDEFAULT_DUPLICATION_X_OFFSET=", DEFAULT_DUPLICATION_X_OFFSET + ); HOTEND_LOOP() { DEBUG_ECHOPGM_P(SP_T_STR, e); - LOOP_LINEAR_AXES(a) DEBUG_ECHOPGM(" hotend_offset[", e, "].", AS_CHAR(AXIS_CHAR(a) | 0x20), "=", hotend_offset[e][a]); + LOOP_NUM_AXES(a) DEBUG_ECHOPGM(" hotend_offset[", e, "].", C(AXIS_CHAR(a) | 0x20), "=", hotend_offset[e][a]); DEBUG_EOL(); } DEBUG_EOL(); @@ -170,7 +168,7 @@ if (parser.seen("EPS")) { planner.synchronize(); if (parser.seenval('P')) duplication_e_mask = parser.value_int(); // Set the mask directly - else if (parser.seenval('E')) duplication_e_mask = pow(2, parser.value_int() + 1) - 1; // Set the mask by E index + else if (parser.seenval('E')) duplication_e_mask = _BV(parser.value_int() + 1) - 1; // Set the mask by E index ena = (2 == parser.intval('S', extruder_duplication_enabled ? 2 : 0)); set_duplication_enabled(ena && (duplication_e_mask >= 3)); } diff --git a/Marlin/src/gcode/control/M7-M9.cpp b/Marlin/src/gcode/control/M7-M9.cpp index ccde4f55..837bb114 100644 --- a/Marlin/src/gcode/control/M7-M9.cpp +++ b/Marlin/src/gcode/control/M7-M9.cpp @@ -37,7 +37,7 @@ } #endif -#if EITHER(COOLANT_FLOOD, AIR_ASSIST) +#if ANY(COOLANT_FLOOD, AIR_ASSIST) #if ENABLED(AIR_ASSIST) #include "../../feature/spindle_laser.h" diff --git a/Marlin/src/gcode/control/M80_M81.cpp b/Marlin/src/gcode/control/M80_M81.cpp index b8be9daa..d85463c2 100644 --- a/Marlin/src/gcode/control/M80_M81.cpp +++ b/Marlin/src/gcode/control/M80_M81.cpp @@ -63,7 +63,7 @@ OUT_WRITE(SUICIDE_PIN, !SUICIDE_PIN_STATE); #endif - TERN_(HAS_LCD_MENU, ui.reset_status()); + TERN_(HAS_MARLINUI_MENU, ui.reset_status()); } #endif // PSU_CONTROL @@ -79,20 +79,42 @@ void GcodeSuite::M81() { print_job_timer.stop(); - #if HAS_FAN - #if ENABLED(PROBING_FANS_OFF) - thermalManager.fans_paused = false; - ZERO(thermalManager.saved_fan_speed); - #endif + #if ALL(HAS_FAN, PROBING_FANS_OFF) + thermalManager.fans_paused = false; + ZERO(thermalManager.saved_fan_speed); #endif safe_delay(1000); // Wait 1 second before switching off - #if HAS_SUICIDE - suicide(); - #elif ENABLED(PSU_CONTROL) - powerManager.power_off_soon(); + LCD_MESSAGE_F(MACHINE_NAME " " STR_OFF "."); + + bool delayed_power_off = false; + + #if ENABLED(POWER_OFF_TIMER) + if (parser.seenval('D')) { + uint16_t delay = parser.value_ushort(); + if (delay > 1) { // skip already observed 1s delay + delayed_power_off = true; + powerManager.setPowerOffTimer(SEC_TO_MS(delay - 1)); + } + } #endif - LCD_MESSAGE_F(MACHINE_NAME " " STR_OFF "."); + #if ENABLED(POWER_OFF_WAIT_FOR_COOLDOWN) + if (parser.boolval('S')) { + delayed_power_off = true; + powerManager.setPowerOffOnCooldown(true); + } + #endif + + if (delayed_power_off) { + SERIAL_ECHOLNPGM(STR_DELAYED_POWEROFF); + return; + } + + #if ENABLED(PSU_CONTROL) + powerManager.power_off_soon(); + #elif HAS_SUICIDE + suicide(); + #endif } diff --git a/Marlin/src/gcode/control/M85.cpp b/Marlin/src/gcode/control/M85.cpp index 9c8c02c5..ee868349 100644 --- a/Marlin/src/gcode/control/M85.cpp +++ b/Marlin/src/gcode/control/M85.cpp @@ -29,7 +29,14 @@ void GcodeSuite::M85() { if (parser.seen('S')) { reset_stepper_timeout(); - max_inactive_time = parser.value_millis_from_seconds(); + const millis_t ms = parser.value_millis_from_seconds(); + #if LASER_SAFETY_TIMEOUT_MS > 0 + if (ms && ms <= LASER_SAFETY_TIMEOUT_MS) { + SERIAL_ECHO_MSG("M85 timeout must be > ", MS_TO_SEC(LASER_SAFETY_TIMEOUT_MS + 999), " s for laser safety."); + return; + } + #endif + max_inactive_time = ms; } } diff --git a/Marlin/src/gcode/control/M993_M994.cpp b/Marlin/src/gcode/control/M993_M994.cpp index 252792e5..bc634ae1 100644 --- a/Marlin/src/gcode/control/M993_M994.cpp +++ b/Marlin/src/gcode/control/M993_M994.cpp @@ -22,7 +22,7 @@ #include "../../inc/MarlinConfig.h" -#if ALL(HAS_SPI_FLASH, SDSUPPORT, MARLIN_DEV_MODE) +#if SPI_FLASH_BACKUP #include "../gcode.h" #include "../../sd/cardreader.h" @@ -85,4 +85,4 @@ void GcodeSuite::M994() { card.closefile(); } -#endif // HAS_SPI_FLASH && SDSUPPORT && MARLIN_DEV_MODE +#endif // SPI_FLASH_BACKUP diff --git a/Marlin/src/gcode/control/M997.cpp b/Marlin/src/gcode/control/M997.cpp index 73d795bc..74ed8b0d 100644 --- a/Marlin/src/gcode/control/M997.cpp +++ b/Marlin/src/gcode/control/M997.cpp @@ -24,8 +24,8 @@ #if ENABLED(PLATFORM_M997_SUPPORT) -#if ENABLED(DWIN_CREALITY_LCD_ENHANCED) - #include "../../lcd/e3v2/enhanced/dwin.h" +#if ENABLED(DWIN_LCD_PROUI) + #include "../../lcd/e3v2/proui/dwin.h" #endif /** @@ -33,7 +33,7 @@ */ void GcodeSuite::M997() { - TERN_(DWIN_CREALITY_LCD_ENHANCED, DWIN_RebootScreen()); + TERN_(DWIN_LCD_PROUI, DWIN_RebootScreen()); flashFirmware(parser.intval('S')); diff --git a/Marlin/src/gcode/control/T.cpp b/Marlin/src/gcode/control/T.cpp index 5e8f6b54..cbe4d26f 100644 --- a/Marlin/src/gcode/control/T.cpp +++ b/Marlin/src/gcode/control/T.cpp @@ -23,7 +23,7 @@ #include "../gcode.h" #include "../../module/tool_change.h" -#if EITHER(HAS_MULTI_EXTRUDER, DEBUG_LEVELING_FEATURE) +#if ANY(HAS_MULTI_EXTRUDER, DEBUG_LEVELING_FEATURE) #include "../../module/motion.h" #endif @@ -41,13 +41,21 @@ * S1 Don't move the tool in XY after change * * For PRUSA_MMU2(S) and EXTENDABLE_EMU_MMU2(S) - * T[n] Gcode to extrude at least 38.10 mm at feedrate 19.02 mm/s must follow immediately to load to extruder wheels. - * T? Gcode to extrude shouldn't have to follow. Load to extruder wheels is done automatically. + * T[n] G-code to extrude at least 38.10 mm at feedrate 19.02 mm/s must follow immediately to load to extruder wheels. + * T? G-code to extrude shouldn't have to follow. Load to extruder wheels is done automatically. * Tx Same as T?, but nozzle doesn't have to be preheated. Tc requires a preheated nozzle to finish filament load. * Tc Load to nozzle after filament was prepared by Tc and nozzle is already heated. */ void GcodeSuite::T(const int8_t tool_index) { + #if HAS_MULTI_EXTRUDER + // For 'T' with no parameter report the current tool. + if (parser.string_arg && *parser.string_arg == '*') { + SERIAL_ECHOLNPGM(STR_ACTIVE_EXTRUDER, active_extruder); + return; + } + #endif + DEBUG_SECTION(log_T, "T", DEBUGGING(LEVELING)); if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("...(", tool_index, ")"); @@ -63,8 +71,8 @@ void GcodeSuite::T(const int8_t tool_index) { tool_change(tool_index #if HAS_MULTI_EXTRUDER - , TERN(PARKING_EXTRUDER, false, tool_index == active_extruder) // For PARKING_EXTRUDER motion is decided in tool_change() - || parser.boolval('S') + , parser.boolval('S') + || TERN(PARKING_EXTRUDER, false, tool_index == active_extruder) // For PARKING_EXTRUDER motion is decided in tool_change() #endif ); } diff --git a/Marlin/src/gcode/eeprom/M500-M504.cpp b/Marlin/src/gcode/eeprom/M500-M504.cpp index a1f295eb..c3962117 100644 --- a/Marlin/src/gcode/eeprom/M500-M504.cpp +++ b/Marlin/src/gcode/eeprom/M500-M504.cpp @@ -26,7 +26,7 @@ #include "../../inc/MarlinConfig.h" #if ENABLED(CONFIGURATION_EMBEDDING) - #include "../../sd/SdBaseFile.h" + #include "../../sd/cardreader.h" #include "../../mczip.h" #endif @@ -56,6 +56,8 @@ void GcodeSuite::M502() { /** * M503: print settings currently in memory * + * S : Include / exclude header comments in the output. (Default: S1) + * * With CONFIGURATION_EMBEDDING: * C : Save the full Marlin configuration to SD Card as "mc.zip" */ @@ -64,11 +66,19 @@ void GcodeSuite::M502() { #if ENABLED(CONFIGURATION_EMBEDDING) if (parser.seen_test('C')) { - SdBaseFile file; - const uint16_t size = sizeof(mc_zip); + MediaFile file; // Need to create the config size on the SD card - if (file.open("mc.zip", O_WRITE|O_CREAT) && file.write(pgm_read_ptr(mc_zip), size) != -1 && file.close()) - SERIAL_ECHO_MSG("Configuration saved as 'mc.zip'"); + MediaFile root = card.getroot(); + if (file.open(&root, "mc.zip", O_WRITE|O_CREAT)) { + bool success = true; + for (uint16_t i = 0; success && i < sizeof(mc_zip); ++i) { + const uint8_t c = pgm_read_byte(&mc_zip[i]); + success = (file.write(c) == 1); + } + success = file.close() && success; + + if (success) SERIAL_ECHO_MSG("Configuration saved as 'mc.zip'"); + } } #endif } diff --git a/Marlin/src/gcode/feature/L6470/M122.cpp b/Marlin/src/gcode/feature/L6470/M122.cpp deleted file mode 100644 index 4a5629b0..00000000 --- a/Marlin/src/gcode/feature/L6470/M122.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * - * Based on Sprinter and grbl. - * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -#include "../../../inc/MarlinConfig.h" - -#if HAS_L64XX - -#include "../../gcode.h" -#include "../../../libs/L64XX/L64XX_Marlin.h" -#include "../../../module/stepper/indirection.h" - -void echo_yes_no(const bool yes); - -inline void L6470_say_status(const L64XX_axis_t axis) { - if (L64xxManager.spi_abort) return; - const L64XX_Marlin::L64XX_shadow_t &sh = L64xxManager.shadow; - L64xxManager.get_status(axis); - L64xxManager.say_axis(axis); - #if ENABLED(L6470_CHITCHAT) - char temp_buf[20]; - sprintf_P(temp_buf, PSTR(" status: %4x "), sh.STATUS_AXIS_RAW); - SERIAL_ECHO(temp_buf); - print_bin(sh.STATUS_AXIS_RAW); - switch (sh.STATUS_AXIS_LAYOUT) { - case L6470_STATUS_LAYOUT: SERIAL_ECHOPGM(" L6470"); break; - case L6474_STATUS_LAYOUT: SERIAL_ECHOPGM(" L6474"); break; - case L6480_STATUS_LAYOUT: SERIAL_ECHOPGM(" L6480/powerSTEP01"); break; - } - #endif - SERIAL_ECHOPGM("\n...OUTPUT: "); - SERIAL_ECHOF(sh.STATUS_AXIS & STATUS_HIZ ? F("OFF") : F("ON ")); - SERIAL_ECHOPGM(" BUSY: "); echo_yes_no((sh.STATUS_AXIS & STATUS_BUSY) == 0); - SERIAL_ECHOPGM(" DIR: "); - SERIAL_ECHOF((((sh.STATUS_AXIS & STATUS_DIR) >> 4) ^ L64xxManager.index_to_dir[axis]) ? F("FORWARD") : F("REVERSE")); - if (sh.STATUS_AXIS_LAYOUT == L6480_STATUS_LAYOUT) { - SERIAL_ECHOPGM(" Last Command: "); - if (sh.STATUS_AXIS & sh.STATUS_AXIS_WRONG_CMD) SERIAL_ECHOPGM("VALID"); - else SERIAL_ECHOPGM("ERROR"); - SERIAL_ECHOPGM("\n...THERMAL: "); - switch ((sh.STATUS_AXIS & (sh.STATUS_AXIS_TH_SD | sh.STATUS_AXIS_TH_WRN)) >> 11) { - case 0: SERIAL_ECHOPGM("DEVICE SHUTDOWN"); break; - case 1: SERIAL_ECHOPGM("BRIDGE SHUTDOWN"); break; - case 2: SERIAL_ECHOPGM("WARNING "); break; - case 3: SERIAL_ECHOPGM("OK "); break; - } - } - else { - SERIAL_ECHOPGM(" Last Command: "); - if (!(sh.STATUS_AXIS & sh.STATUS_AXIS_WRONG_CMD)) SERIAL_ECHOPGM("IN"); - SERIAL_ECHOPGM("VALID "); - SERIAL_ECHOF(sh.STATUS_AXIS & sh.STATUS_AXIS_NOTPERF_CMD ? F("COMPLETED ") : F("Not PERFORMED")); - SERIAL_ECHOPGM("\n...THERMAL: ", !(sh.STATUS_AXIS & sh.STATUS_AXIS_TH_SD) ? "SHUTDOWN " : !(sh.STATUS_AXIS & sh.STATUS_AXIS_TH_WRN) ? "WARNING " : "OK "); - } - SERIAL_ECHOPGM(" OVERCURRENT:"); echo_yes_no((sh.STATUS_AXIS & sh.STATUS_AXIS_OCD) == 0); - if (sh.STATUS_AXIS_LAYOUT != L6474_STATUS_LAYOUT) { - SERIAL_ECHOPGM(" STALL:"); echo_yes_no((sh.STATUS_AXIS & sh.STATUS_AXIS_STEP_LOSS_A) == 0 || (sh.STATUS_AXIS & sh.STATUS_AXIS_STEP_LOSS_B) == 0); - SERIAL_ECHOPGM(" STEP-CLOCK MODE:"); echo_yes_no((sh.STATUS_AXIS & sh.STATUS_AXIS_SCK_MOD) != 0); - } - else { - SERIAL_ECHOPGM(" STALL: NA " - " STEP-CLOCK MODE: NA" - " UNDER VOLTAGE LOCKOUT: "); echo_yes_no((sh.STATUS_AXIS & sh.STATUS_AXIS_UVLO) == 0); - } - SERIAL_EOL(); -} - -/** - * M122: Debug L6470 drivers - */ -void GcodeSuite::M122() { - L64xxManager.pause_monitor(true); // Keep monitor_driver() from stealing status - L64xxManager.spi_active = true; // Tell set_directions() a series of SPI transfers is underway - - //if (parser.seen('S')) - // tmc_set_report_interval(parser.value_bool()); - //else - - #if AXIS_IS_L64XX(X) - L6470_say_status(X); - #endif - #if AXIS_IS_L64XX(X2) - L6470_say_status(X2); - #endif - #if AXIS_IS_L64XX(Y) - L6470_say_status(Y); - #endif - #if AXIS_IS_L64XX(Y2) - L6470_say_status(Y2); - #endif - #if AXIS_IS_L64XX(Z) - L6470_say_status(Z); - #endif - #if AXIS_IS_L64XX(Z2) - L6470_say_status(Z2); - #endif - #if AXIS_IS_L64XX(Z3) - L6470_say_status(Z3); - #endif - #if AXIS_IS_L64XX(Z4) - L6470_say_status(Z4); - #endif - #if AXIS_IS_L64XX(E0) - L6470_say_status(E0); - #endif - #if AXIS_IS_L64XX(E1) - L6470_say_status(E1); - #endif - #if AXIS_IS_L64XX(E2) - L6470_say_status(E2); - #endif - #if AXIS_IS_L64XX(E3) - L6470_say_status(E3); - #endif - #if AXIS_IS_L64XX(E4) - L6470_say_status(E4); - #endif - #if AXIS_IS_L64XX(E5) - L6470_say_status(E5); - #endif - #if AXIS_IS_L64XX(E6) - L6470_say_status(E6); - #endif - #if AXIS_IS_L64XX(E7) - L6470_say_status(E7); - #endif - - L64xxManager.spi_active = false; // done with all SPI transfers - clear handshake flags - L64xxManager.spi_abort = false; - L64xxManager.pause_monitor(false); -} - -#endif // HAS_L64XX diff --git a/Marlin/src/gcode/feature/L6470/M906.cpp b/Marlin/src/gcode/feature/L6470/M906.cpp deleted file mode 100644 index d058ce55..00000000 --- a/Marlin/src/gcode/feature/L6470/M906.cpp +++ /dev/null @@ -1,376 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * - * Based on Sprinter and grbl. - * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -#include "../../../inc/MarlinConfig.h" - -#if HAS_L64XX - -#include "../../gcode.h" -#include "../../../libs/L64XX/L64XX_Marlin.h" -#include "../../../module/stepper/indirection.h" -#include "../../../module/planner.h" - -#define DEBUG_OUT ENABLED(L6470_CHITCHAT) -#include "../../../core/debug_out.h" - -/** - * MACRO to fetch information on the items associated with current limiting - * and maximum voltage output. - * - * L6470 can be setup to shutdown if either current threshold is exceeded. - * - * L6470 output current can not be set directly. It is set indirectly by - * setting the maximum effective output voltage. - * - * Effective output voltage is set by PWM duty cycle. - * - * Maximum effective output voltage is affected by MANY variables. The main ones are: - * KVAL_HOLD - * KVAL_RUN - * KVAL_ACC - * KVAL_DEC - * Vs compensation (if enabled) - */ -void L64XX_report_current(L64XX &motor, const L64XX_axis_t axis) { - - if (L64xxManager.spi_abort) return; // don't do anything if set_directions() has occurred - - const L64XX_Marlin::L64XX_shadow_t &sh = L64xxManager.shadow; - const uint16_t status = L64xxManager.get_status(axis); //also populates shadow structure - const uint8_t OverCurrent_Threshold = uint8_t(motor.GetParam(L6470_OCD_TH)); - - auto say_axis_status = [](const L64XX_axis_t axis, const uint16_t status) { - L64xxManager.say_axis(axis); - #if ENABLED(L6470_CHITCHAT) - char tmp[10]; - sprintf_P(tmp, PSTR("%4x "), status); - DEBUG_ECHOPGM(" status: ", tmp); - print_bin(status); - #else - UNUSED(status); - #endif - SERIAL_EOL(); - }; - - char temp_buf[10]; - - switch (sh.STATUS_AXIS_LAYOUT) { - case L6470_STATUS_LAYOUT: // L6470 - case L6480_STATUS_LAYOUT: { // L6480 & powerstep01 - const uint16_t Stall_Threshold = (uint8_t)motor.GetParam(L6470_STALL_TH), - motor_status = (status & (STATUS_MOT_STATUS)) >> 5, - L6470_ADC_out = motor.GetParam(L6470_ADC_OUT), - L6470_ADC_out_limited = constrain(L6470_ADC_out, 8, 24); - const float comp_coef = 1600.0f / L6470_ADC_out_limited; - const uint16_t MicroSteps = _BV(motor.GetParam(L6470_STEP_MODE) & 0x07); - - say_axis_status(axis, sh.STATUS_AXIS_RAW); - - SERIAL_ECHOPGM("...OverCurrent Threshold: "); - sprintf_P(temp_buf, PSTR("%2d ("), OverCurrent_Threshold); - SERIAL_ECHO(temp_buf); - SERIAL_ECHO((OverCurrent_Threshold + 1) * motor.OCD_CURRENT_CONSTANT_INV); - SERIAL_ECHOPGM(" mA)"); - SERIAL_ECHOPGM(" Stall Threshold: "); - sprintf_P(temp_buf, PSTR("%2d ("), Stall_Threshold); - SERIAL_ECHO(temp_buf); - SERIAL_ECHO((Stall_Threshold + 1) * motor.STALL_CURRENT_CONSTANT_INV); - SERIAL_ECHOPGM(" mA)"); - SERIAL_ECHOPGM(" Motor Status: "); - switch (motor_status) { - case 0: SERIAL_ECHOPGM("stopped"); break; - case 1: SERIAL_ECHOPGM("accelerating"); break; - case 2: SERIAL_ECHOPGM("decelerating"); break; - case 3: SERIAL_ECHOPGM("at constant speed"); break; - } - SERIAL_EOL(); - - SERIAL_ECHOPGM("...MicroSteps: ", MicroSteps, - " ADC_OUT: ", L6470_ADC_out); - SERIAL_ECHOPGM(" Vs_compensation: "); - SERIAL_ECHOF((motor.GetParam(sh.L6470_AXIS_CONFIG) & CONFIG_EN_VSCOMP) ? F("ENABLED ") : F("DISABLED")); - SERIAL_ECHOLNPGM(" Compensation coefficient: ~", comp_coef * 0.01f); - - SERIAL_ECHOPGM("...KVAL_HOLD: ", motor.GetParam(L6470_KVAL_HOLD), - " KVAL_RUN : ", motor.GetParam(L6470_KVAL_RUN), - " KVAL_ACC: ", motor.GetParam(L6470_KVAL_ACC), - " KVAL_DEC: ", motor.GetParam(L6470_KVAL_DEC), - " V motor max = "); - switch (motor_status) { - case 0: SERIAL_ECHO(motor.GetParam(L6470_KVAL_HOLD) * 100 / 256); SERIAL_ECHOPGM("% (KVAL_HOLD)"); break; - case 1: SERIAL_ECHO(motor.GetParam(L6470_KVAL_RUN) * 100 / 256); SERIAL_ECHOPGM("% (KVAL_RUN)"); break; - case 2: SERIAL_ECHO(motor.GetParam(L6470_KVAL_ACC) * 100 / 256); SERIAL_ECHOPGM("% (KVAL_ACC)"); break; - case 3: SERIAL_ECHO(motor.GetParam(L6470_KVAL_DEC) * 100 / 256); SERIAL_ECHOPGM("% (KVAL_HOLD)"); break; - } - SERIAL_EOL(); - - #if ENABLED(L6470_CHITCHAT) - DEBUG_ECHOPGM("...SLEW RATE: "); - switch (sh.STATUS_AXIS_LAYOUT) { - case L6470_STATUS_LAYOUT: { - switch ((motor.GetParam(sh.L6470_AXIS_CONFIG) & CONFIG_POW_SR) >> CONFIG_POW_SR_BIT) { - case 0: { DEBUG_ECHOLNPGM("320V/uS") ; break; } - case 1: { DEBUG_ECHOLNPGM("75V/uS") ; break; } - case 2: { DEBUG_ECHOLNPGM("110V/uS") ; break; } - case 3: { DEBUG_ECHOLNPGM("260V/uS") ; break; } - } - break; - } - case L6480_STATUS_LAYOUT: { - switch (motor.GetParam(L6470_GATECFG1) & CONFIG1_SR ) { - case CONFIG1_SR_220V_us: { DEBUG_ECHOLNPGM("220V/uS") ; break; } - case CONFIG1_SR_400V_us: { DEBUG_ECHOLNPGM("400V/uS") ; break; } - case CONFIG1_SR_520V_us: { DEBUG_ECHOLNPGM("520V/uS") ; break; } - case CONFIG1_SR_980V_us: { DEBUG_ECHOLNPGM("980V/uS") ; break; } - default: { DEBUG_ECHOLNPGM("unknown") ; break; } - } - } - } - #endif - SERIAL_EOL(); - break; - } - - case L6474_STATUS_LAYOUT: { // L6474 - const uint16_t L6470_ADC_out = motor.GetParam(L6470_ADC_OUT) & 0x1F, - L6474_TVAL_val = motor.GetParam(L6474_TVAL) & 0x7F; - - say_axis_status(axis, sh.STATUS_AXIS_RAW); - - SERIAL_ECHOPGM("...OverCurrent Threshold: "); - sprintf_P(temp_buf, PSTR("%2d ("), OverCurrent_Threshold); - SERIAL_ECHO(temp_buf); - SERIAL_ECHO((OverCurrent_Threshold + 1) * motor.OCD_CURRENT_CONSTANT_INV); - SERIAL_ECHOPGM(" mA)"); - SERIAL_ECHOPGM(" TVAL: "); - sprintf_P(temp_buf, PSTR("%2d ("), L6474_TVAL_val); - SERIAL_ECHO(temp_buf); - SERIAL_ECHO((L6474_TVAL_val + 1) * motor.STALL_CURRENT_CONSTANT_INV); - SERIAL_ECHOLNPGM(" mA) Motor Status: NA"); - - const uint16_t MicroSteps = _BV(motor.GetParam(L6470_STEP_MODE) & 0x07); //NOMORE(MicroSteps, 16); - SERIAL_ECHOPGM("...MicroSteps: ", MicroSteps, - " ADC_OUT: ", L6470_ADC_out); - - SERIAL_ECHOLNPGM(" Vs_compensation: NA\n"); - SERIAL_ECHOLNPGM("...KVAL_HOLD: NA" - " KVAL_RUN : NA" - " KVAL_ACC: NA" - " KVAL_DEC: NA" - " V motor max = NA"); - - #if ENABLED(L6470_CHITCHAT) - DEBUG_ECHOPGM("...SLEW RATE: "); - switch ((motor.GetParam(sh.L6470_AXIS_CONFIG) & CONFIG_POW_SR) >> CONFIG_POW_SR_BIT) { - case 0: DEBUG_ECHOLNPGM("320V/uS") ; break; - case 1: DEBUG_ECHOLNPGM("75V/uS") ; break; - case 2: DEBUG_ECHOLNPGM("110V/uS") ; break; - case 3: DEBUG_ECHOLNPGM("260V/uS") ; break; - default: DEBUG_ECHOLNPGM("slew rate: ", (motor.GetParam(sh.L6470_AXIS_CONFIG) & CONFIG_POW_SR) >> CONFIG_POW_SR_BIT); break; - } - #endif - SERIAL_EOL(); - SERIAL_EOL(); - break; - } - } -} - -/** - * M906: report or set KVAL_HOLD which sets the maximum effective voltage provided by the - * PWMs to the steppers - * - * On L6474 this sets the TVAL register (same address). - * - * I - select which driver(s) to change on multi-driver axis - * 0 - (default) all drivers on the axis or E0 - * 1 - monitor only X, Y, Z or E1 - * 2 - monitor only X2, Y2, Z2 or E2 - * 3 - monitor only Z3 or E3 - * 4 - monitor only Z4 or E4 - * 5 - monitor only E5 - * Xxxx, Yxxx, Zxxx, Exxx - axis to change (optional) - * L6474 - current in mA (4A max) - * All others - 0-255 - * - * Sets KVAL_HOLD which affects the current being driven through the stepper. - * - * L6470 is used in the STEP-CLOCK mode. KVAL_HOLD is the only KVAL_xxx - * that affects the effective voltage seen by the stepper. - */ -void GcodeSuite::M906() { - - L64xxManager.pause_monitor(true); // Keep monitor_driver() from stealing status - - #define L6470_SET_KVAL_HOLD(Q) (AXIS_IS_L64XX(Q) ? stepper##Q.setTVALCurrent(value) : stepper##Q.SetParam(L6470_KVAL_HOLD, uint8_t(value))) - - DEBUG_ECHOLNPGM("M906"); - - uint8_t report_current = true; - - #if HAS_L64XX - const uint8_t index = parser.byteval('I'); - #endif - - LOOP_LOGICAL_AXES(i) if (uint16_t value = parser.intval(axis_codes[i])) { - - report_current = false; - - if (planner.has_blocks_queued() || planner.cleaning_buffer_counter) { - SERIAL_ECHOLNPGM("Test aborted. Can't set KVAL_HOLD while steppers are moving."); - return; - } - - switch (i) { - case X_AXIS: - #if AXIS_IS_L64XX(X) - if (index == 0) L6470_SET_KVAL_HOLD(X); - #endif - #if AXIS_IS_L64XX(X2) - if (index == 1) L6470_SET_KVAL_HOLD(X2); - #endif - break; - - #if HAS_Y_AXIS - case Y_AXIS: - #if AXIS_IS_L64XX(Y) - if (index == 0) L6470_SET_KVAL_HOLD(Y); - #endif - #if AXIS_IS_L64XX(Y2) - if (index == 1) L6470_SET_KVAL_HOLD(Y2); - #endif - break; - #endif - - #if HAS_Z_AXIS - case Z_AXIS: - #if AXIS_IS_L64XX(Z) - if (index == 0) L6470_SET_KVAL_HOLD(Z); - #endif - #if AXIS_IS_L64XX(Z2) - if (index == 1) L6470_SET_KVAL_HOLD(Z2); - #endif - #if AXIS_IS_L64XX(Z3) - if (index == 2) L6470_SET_KVAL_HOLD(Z3); - #endif - #if AXIS_DRIVER_TYPE_Z4(L6470) - if (index == 3) L6470_SET_KVAL_HOLD(Z4); - #endif - break; - #endif - - #if E_STEPPERS - case E_AXIS: { - const int8_t target_e_stepper = get_target_e_stepper_from_command(0); - if (target_e_stepper < 0) return; - switch (target_e_stepper) { - #if AXIS_IS_L64XX(E0) - case 0: L6470_SET_KVAL_HOLD(E0); break; - #endif - #if AXIS_IS_L64XX(E1) - case 1: L6470_SET_KVAL_HOLD(E1); break; - #endif - #if AXIS_IS_L64XX(E2) - case 2: L6470_SET_KVAL_HOLD(E2); break; - #endif - #if AXIS_IS_L64XX(E3) - case 3: L6470_SET_KVAL_HOLD(E3); break; - #endif - #if AXIS_IS_L64XX(E4) - case 4: L6470_SET_KVAL_HOLD(E4); break; - #endif - #if AXIS_IS_L64XX(E5) - case 5: L6470_SET_KVAL_HOLD(E5); break; - #endif - #if AXIS_IS_L64XX(E6) - case 6: L6470_SET_KVAL_HOLD(E6); break; - #endif - #if AXIS_IS_L64XX(E7) - case 7: L6470_SET_KVAL_HOLD(E7); break; - #endif - } - } break; - #endif - } - } - - if (report_current) { - #define L64XX_REPORT_CURRENT(Q) L64XX_report_current(stepper##Q, Q) - - L64xxManager.spi_active = true; // Tell set_directions() a series of SPI transfers is underway - - #if AXIS_IS_L64XX(X) - L64XX_REPORT_CURRENT(X); - #endif - #if AXIS_IS_L64XX(X2) - L64XX_REPORT_CURRENT(X2); - #endif - #if AXIS_IS_L64XX(Y) - L64XX_REPORT_CURRENT(Y); - #endif - #if AXIS_IS_L64XX(Y2) - L64XX_REPORT_CURRENT(Y2); - #endif - #if AXIS_IS_L64XX(Z) - L64XX_REPORT_CURRENT(Z); - #endif - #if AXIS_IS_L64XX(Z2) - L64XX_REPORT_CURRENT(Z2); - #endif - #if AXIS_IS_L64XX(Z3) - L64XX_REPORT_CURRENT(Z3); - #endif - #if AXIS_IS_L64XX(Z4) - L64XX_REPORT_CURRENT(Z4); - #endif - #if AXIS_IS_L64XX(E0) - L64XX_REPORT_CURRENT(E0); - #endif - #if AXIS_IS_L64XX(E1) - L64XX_REPORT_CURRENT(E1); - #endif - #if AXIS_IS_L64XX(E2) - L64XX_REPORT_CURRENT(E2); - #endif - #if AXIS_IS_L64XX(E3) - L64XX_REPORT_CURRENT(E3); - #endif - #if AXIS_IS_L64XX(E4) - L64XX_REPORT_CURRENT(E4); - #endif - #if AXIS_IS_L64XX(E5) - L64XX_REPORT_CURRENT(E5); - #endif - #if AXIS_IS_L64XX(E6) - L64XX_REPORT_CURRENT(E6); - #endif - #if AXIS_IS_L64XX(E7) - L64XX_REPORT_CURRENT(E7); - #endif - - L64xxManager.spi_active = false; // done with all SPI transfers - clear handshake flags - L64xxManager.spi_abort = false; - L64xxManager.pause_monitor(false); - } -} - -#endif // HAS_L64XX diff --git a/Marlin/src/gcode/feature/L6470/M916-918.cpp b/Marlin/src/gcode/feature/L6470/M916-918.cpp deleted file mode 100644 index 8d614603..00000000 --- a/Marlin/src/gcode/feature/L6470/M916-918.cpp +++ /dev/null @@ -1,651 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * - * Based on Sprinter and grbl. - * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -// -// NOTE: All tests assume each axis uses matching driver chips. -// - -#include "../../../inc/MarlinConfig.h" - -#if HAS_L64XX - -#include "../../gcode.h" -#include "../../../module/stepper/indirection.h" -#include "../../../module/planner.h" -#include "../../../libs/L64XX/L64XX_Marlin.h" - -#define DEBUG_OUT ENABLED(L6470_CHITCHAT) -#include "../../../core/debug_out.h" - -/** - * M916: increase KVAL_HOLD until get thermal warning - * NOTE - on L6474 it is TVAL that is used - * - * J - select which driver(s) to monitor on multi-driver axis - * 0 - (default) monitor all drivers on the axis or E0 - * 1 - monitor only X, Y, Z, E1 - * 2 - monitor only X2, Y2, Z2, E2 - * 3 - monitor only Z3, E3 - * 4 - monitor only Z4, E4 - * - * Xxxx, Yxxx, Zxxx, Exxx - axis to be monitored with displacement - * xxx (1-255) is distance moved on either side of current position - * - * F - feedrate - * optional - will use default max feedrate from configuration.h if not specified - * - * T - current (mA) setting for TVAL (0 - 4A in 31.25mA increments, rounds down) - L6474 only - * optional - will report current value from driver if not specified - * - * K - value for KVAL_HOLD (0 - 255) (ignored for L6474) - * optional - will report current value from driver if not specified - * - * D - time (in seconds) to run each setting of KVAL_HOLD/TVAL - * optional - defaults to zero (runs each setting once) - */ - -/** - * This routine is also useful for determining the approximate KVAL_HOLD - * where the stepper stops losing steps. The sound will get noticeably quieter - * as it stops losing steps. - */ - -void GcodeSuite::M916() { - - DEBUG_ECHOLNPGM("M916"); - - L64xxManager.pause_monitor(true); // Keep monitor_driver() from stealing status - - // Variables used by L64xxManager.get_user_input function - some may not be used - char axis_mon[3][3] = { {" "}, {" "}, {" "} }; // list of Axes to be monitored - L64XX_axis_t axis_index[3]; - uint16_t axis_status[3]; - uint8_t driver_count = 1; - float position_max; - float position_min; - float final_feedrate; - uint8_t kval_hold; - uint8_t OCD_TH_val = 0; - uint8_t STALL_TH_val = 0; - uint16_t over_current_threshold; - constexpr uint8_t over_current_flag = false; // M916 doesn't play with the overcurrent thresholds - - #define DRIVER_TYPE_L6474(Q) AXIS_DRIVER_TYPE_##Q(L6474) - - uint8_t j; // general purpose counter - - if (L64xxManager.get_user_input(driver_count, axis_index, axis_mon, position_max, position_min, final_feedrate, kval_hold, over_current_flag, OCD_TH_val, STALL_TH_val, over_current_threshold)) - return; // quit if invalid user input - - DEBUG_ECHOLNPGM("feedrate = ", final_feedrate); - - planner.synchronize(); // wait for all current movement commands to complete - - const L64XX_Marlin::L64XX_shadow_t &sh = L64xxManager.shadow; - for (j = 0; j < driver_count; j++) - L64xxManager.get_status(axis_index[j]); // clear out any pre-existing error flags - - char temp_axis_string[] = " "; - temp_axis_string[0] = axis_mon[0][0]; // need to have a string for use within sprintf format section - char gcode_string[80]; - uint16_t status_composite = 0; - - uint16_t M91x_counter = kval_hold; - uint16_t M91x_counter_max; - if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT) { - M91x_counter_max = 128; // TVAL is 7 bits - LIMIT(M91x_counter, 0U, 127U); - } - else - M91x_counter_max = 256; // KVAL_HOLD is 8 bits - - uint8_t M91x_delay_s = parser.byteval('D'); // get delay in seconds - millis_t M91x_delay_ms = SEC_TO_MS(M91x_delay_s * 60); - millis_t M91x_delay_end; - - DEBUG_ECHOLNPGM(".\n."); - - do { - - if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT) - DEBUG_ECHOLNPGM("TVAL current (mA) = ", (M91x_counter + 1) * sh.AXIS_STALL_CURRENT_CONSTANT_INV); // report TVAL current for this run - else - DEBUG_ECHOLNPGM("kval_hold = ", M91x_counter); // report KVAL_HOLD for this run - - for (j = 0; j < driver_count; j++) - L64xxManager.set_param(axis_index[j], L6470_KVAL_HOLD, M91x_counter); //set KVAL_HOLD or TVAL (same register address) - - M91x_delay_end = millis() + M91x_delay_ms; - do { - // turn the motor(s) both directions - sprintf_P(gcode_string, PSTR("G0 %s%03d F%03d"), temp_axis_string, uint16_t(position_min), uint16_t(final_feedrate)); - process_subcommands_now(gcode_string); - - sprintf_P(gcode_string, PSTR("G0 %s%03d F%03d"), temp_axis_string, uint16_t(position_max), uint16_t(final_feedrate)); - process_subcommands_now(gcode_string); - - // get the status after the motors have stopped - planner.synchronize(); - - status_composite = 0; // clear out the old bits - - for (j = 0; j < driver_count; j++) { - axis_status[j] = (~L64xxManager.get_status(axis_index[j])) & sh.L6470_ERROR_MASK; // bits of interest are all active low - status_composite |= axis_status[j] ; - } - - if (status_composite) break; - } while (millis() < M91x_delay_end); - - if (status_composite) break; - - M91x_counter++; - - } while (!(status_composite & (sh.STATUS_AXIS_TH_WRN | sh.STATUS_AXIS_TH_SD)) && (M91x_counter < M91x_counter_max)); - - DEBUG_ECHOLNPGM("."); - - #if ENABLED(L6470_CHITCHAT) - if (status_composite) { - L64xxManager.error_status_decode(status_composite, axis_index[0], - sh.STATUS_AXIS_TH_SD, sh.STATUS_AXIS_TH_WRN, - sh.STATUS_AXIS_STEP_LOSS_A, sh.STATUS_AXIS_STEP_LOSS_B, - sh.STATUS_AXIS_OCD, sh.STATUS_AXIS_LAYOUT); - DEBUG_ECHOLNPGM("."); - } - #endif - - if ((status_composite & (sh.STATUS_AXIS_TH_WRN | sh.STATUS_AXIS_TH_SD))) - DEBUG_ECHOLNPGM(".\n.\nTest completed normally - Thermal warning/shutdown has occurred"); - else if (status_composite) - DEBUG_ECHOLNPGM(".\n.\nTest completed abnormally - non-thermal error has occurred"); - else - DEBUG_ECHOLNPGM(".\n.\nTest completed normally - Unable to get to thermal warning/shutdown"); - - L64xxManager.pause_monitor(false); -} - -/** - * M917: Find minimum current thresholds - * - * Decrease OCD current until overcurrent error - * Increase OCD until overcurrent error goes away - * Decrease stall threshold until stall (not done on L6474) - * Increase stall until stall error goes away (not done on L6474) - * - * J - select which driver(s) to monitor on multi-driver axis - * 0 - (default) monitor all drivers on the axis or E0 - * 1 - monitor only X, Y, Z, E1 - * 2 - monitor only X2, Y2, Z2, E2 - * Xxxx, Yxxx, Zxxx, Exxx - axis to be monitored with displacement - * xxx (1-255) is distance moved on either side of current position - * - * F - feedrate - * optional - will use default max feedrate from Configuration.h if not specified - * - * I - starting over-current threshold - * optional - will report current value from driver if not specified - * if there are multiple drivers on the axis then all will be set the same - * - * T - current (mA) setting for TVAL (0 - 4A in 31.25mA increments, rounds down) - L6474 only - * optional - will report current value from driver if not specified - * - * K - value for KVAL_HOLD (0 - 255) (ignored for L6474) - * optional - will report current value from driver if not specified - */ -void GcodeSuite::M917() { - - DEBUG_ECHOLNPGM("M917"); - - L64xxManager.pause_monitor(true); // Keep monitor_driver() from stealing status - - char axis_mon[3][3] = { {" "}, {" "}, {" "} }; // list of Axes to be monitored - L64XX_axis_t axis_index[3]; - uint16_t axis_status[3]; - uint8_t driver_count = 1; - float position_max; - float position_min; - float final_feedrate; - uint8_t kval_hold; - uint8_t OCD_TH_val = 0; - uint8_t STALL_TH_val = 0; - uint16_t over_current_threshold; - constexpr uint8_t over_current_flag = true; - - uint8_t j; // general purpose counter - - if (L64xxManager.get_user_input(driver_count, axis_index, axis_mon, position_max, position_min, final_feedrate, kval_hold, over_current_flag, OCD_TH_val, STALL_TH_val, over_current_threshold)) - return; // quit if invalid user input - - DEBUG_ECHOLNPGM("feedrate = ", final_feedrate); - - planner.synchronize(); // wait for all current movement commands to complete - - const L64XX_Marlin::L64XX_shadow_t &sh = L64xxManager.shadow; - for (j = 0; j < driver_count; j++) - L64xxManager.get_status(axis_index[j]); // clear error flags - char temp_axis_string[] = " "; - temp_axis_string[0] = axis_mon[0][0]; // need a sprintf format string - char gcode_string[80]; - uint16_t status_composite = 0; - uint8_t test_phase = 0; // 0 - decreasing OCD - exit when OCD warning occurs (ignore STALL) - // 1 - increasing OCD - exit when OCD warning stops (ignore STALL) - // 2 - OCD finalized - decreasing STALL - exit when STALL warning happens - // 3 - OCD finalized - increasing STALL - exit when STALL warning stop - // 4 - all testing completed - DEBUG_ECHOPGM(".\n.\n.\nover_current threshold : ", (OCD_TH_val + 1) * 375); // first status display - DEBUG_ECHOPGM(" (OCD_TH: : ", OCD_TH_val); - if (sh.STATUS_AXIS_LAYOUT != L6474_STATUS_LAYOUT) { - DEBUG_ECHOPGM(") Stall threshold: ", (STALL_TH_val + 1) * 31.25); - DEBUG_ECHOPGM(" (STALL_TH: ", STALL_TH_val); - } - DEBUG_ECHOLNPGM(")"); - - do { - - if (sh.STATUS_AXIS_LAYOUT != L6474_STATUS_LAYOUT) DEBUG_ECHOPGM("STALL threshold : ", (STALL_TH_val + 1) * 31.25); - DEBUG_ECHOLNPGM(" OCD threshold : ", (OCD_TH_val + 1) * 375); - - sprintf_P(gcode_string, PSTR("G0 %s%03d F%03d"), temp_axis_string, uint16_t(position_min), uint16_t(final_feedrate)); - process_subcommands_now(gcode_string); - - sprintf_P(gcode_string, PSTR("G0 %s%03d F%03d"), temp_axis_string, uint16_t(position_max), uint16_t(final_feedrate)); - process_subcommands_now(gcode_string); - - planner.synchronize(); - - status_composite = 0; // clear out the old bits - - for (j = 0; j < driver_count; j++) { - axis_status[j] = (~L64xxManager.get_status(axis_index[j])) & sh.L6470_ERROR_MASK; // bits of interest are all active low - status_composite |= axis_status[j]; - } - - if (status_composite && (status_composite & sh.STATUS_AXIS_UVLO)) { - DEBUG_ECHOLNPGM("Test aborted (Undervoltage lockout active)"); - #if ENABLED(L6470_CHITCHAT) - for (j = 0; j < driver_count; j++) { - if (j) DEBUG_ECHOPGM("..."); - L64xxManager.error_status_decode(axis_status[j], axis_index[j], - sh.STATUS_AXIS_TH_SD, sh.STATUS_AXIS_TH_WRN, - sh.STATUS_AXIS_STEP_LOSS_A, sh.STATUS_AXIS_STEP_LOSS_B, - sh.STATUS_AXIS_OCD, sh.STATUS_AXIS_LAYOUT); - } - #endif - return; - } - - if (status_composite & (sh.STATUS_AXIS_TH_WRN | sh.STATUS_AXIS_TH_SD)) { - DEBUG_ECHOLNPGM("thermal problem - waiting for chip(s) to cool down "); - uint16_t status_composite_temp = 0; - uint8_t k = 0; - do { - k++; - if (!(k % 4)) { - kval_hold *= 0.95; - DEBUG_EOL(); - DEBUG_ECHOLNPGM("Lowering KVAL_HOLD by about 5% to ", kval_hold); - for (j = 0; j < driver_count; j++) - L64xxManager.set_param(axis_index[j], L6470_KVAL_HOLD, kval_hold); - } - DEBUG_ECHOLNPGM("."); - reset_stepper_timeout(); // keep steppers powered - watchdog_refresh(); - safe_delay(5000); - status_composite_temp = 0; - for (j = 0; j < driver_count; j++) { - axis_status[j] = (~L64xxManager.get_status(axis_index[j])) & sh.L6470_ERROR_MASK; // bits of interest are all active low - status_composite_temp |= axis_status[j]; - } - } - while (status_composite_temp & (sh.STATUS_AXIS_TH_WRN | sh.STATUS_AXIS_TH_SD)); - DEBUG_EOL(); - } - if (status_composite & (sh.STATUS_AXIS_STEP_LOSS_A | sh.STATUS_AXIS_STEP_LOSS_B | sh.STATUS_AXIS_OCD)) { - switch (test_phase) { - - case 0: { - if (status_composite & sh.STATUS_AXIS_OCD) { - // phase 0 with OCD warning - time to go to next phase - if (OCD_TH_val >= sh.AXIS_OCD_TH_MAX) { - OCD_TH_val = sh.AXIS_OCD_TH_MAX; // limit to max - test_phase = 2; // at highest value so skip phase 1 - //DEBUG_ECHOLNPGM("LOGIC E0A OCD at highest - skip to 2"); - DEBUG_ECHOLNPGM("OCD at highest - OCD finalized"); - } - else { - OCD_TH_val++; // normal exit to next phase - test_phase = 1; // setup for first pass of phase 1 - //DEBUG_ECHOLNPGM("LOGIC E0B - inc OCD & go to 1"); - DEBUG_ECHOLNPGM("inc OCD"); - } - } - else { // phase 0 without OCD warning - keep on decrementing if can - if (OCD_TH_val) { - OCD_TH_val--; // try lower value - //DEBUG_ECHOLNPGM("LOGIC E0C - dec OCD"); - DEBUG_ECHOLNPGM("dec OCD"); - } - else { - test_phase = 2; // at lowest value without warning so skip phase 1 - //DEBUG_ECHOLNPGM("LOGIC E0D - OCD at latest - go to 2"); - DEBUG_ECHOLNPGM("OCD finalized"); - } - } - } break; - - case 1: { - if (status_composite & sh.STATUS_AXIS_OCD) { - // phase 1 with OCD warning - increment if can - if (OCD_TH_val >= sh.AXIS_OCD_TH_MAX) { - OCD_TH_val = sh.AXIS_OCD_TH_MAX; // limit to max - test_phase = 2; // at highest value so go to next phase - //DEBUG_ECHOLNPGM("LOGIC E1A - OCD at max - go to 2"); - DEBUG_ECHOLNPGM("OCD finalized"); - } - else { - OCD_TH_val++; // try a higher value - //DEBUG_ECHOLNPGM("LOGIC E1B - inc OCD"); - DEBUG_ECHOLNPGM("inc OCD"); - } - } - else { // phase 1 without OCD warning - normal exit to phase 2 - test_phase = 2; - //DEBUG_ECHOLNPGM("LOGIC E1C - no OCD warning - go to 1"); - DEBUG_ECHOLNPGM("OCD finalized"); - } - } break; - - case 2: { - if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT) { // skip all STALL_TH steps if L6474 - test_phase = 4; - break; - } - if (status_composite & (sh.STATUS_AXIS_STEP_LOSS_A | sh.STATUS_AXIS_STEP_LOSS_B)) { - // phase 2 with stall warning - time to go to next phase - if (STALL_TH_val >= 127) { - STALL_TH_val = 127; // limit to max - //DEBUG_ECHOLNPGM("LOGIC E2A - STALL warning, STALL at max, quit"); - DEBUG_ECHOLNPGM("finished - STALL at maximum value but still have stall warning"); - test_phase = 4; - } - else { - test_phase = 3; // normal exit to next phase (found failing value of STALL) - STALL_TH_val++; // setup for first pass of phase 3 - //DEBUG_ECHOLNPGM("LOGIC E2B - INC - STALL warning, inc Stall, go to 3"); - DEBUG_ECHOLNPGM("inc Stall"); - } - } - else { // phase 2 without stall warning - decrement if can - if (STALL_TH_val) { - STALL_TH_val--; // try a lower value - //DEBUG_ECHOLNPGM("LOGIC E2C - no STALL, dec STALL"); - DEBUG_ECHOLNPGM("dec STALL"); - } - else { - DEBUG_ECHOLNPGM("finished - STALL at lowest value but still do NOT have stall warning"); - test_phase = 4; - //DEBUG_ECHOLNPGM("LOGIC E2D - no STALL, at lowest so quit"); - } - } - } break; - - case 3: { - if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT) { // skip all STALL_TH steps if L6474 - test_phase = 4; - break; - } - if (status_composite & (sh.STATUS_AXIS_STEP_LOSS_A | sh.STATUS_AXIS_STEP_LOSS_B)) { - // phase 3 with stall warning - increment if can - if (STALL_TH_val >= 127) { - STALL_TH_val = 127; // limit to max - DEBUG_ECHOLNPGM("finished - STALL at maximum value but still have stall warning"); - test_phase = 4; - //DEBUG_ECHOLNPGM("LOGIC E3A - STALL, at max so quit"); - } - else { - STALL_TH_val++; // still looking for passing value - //DEBUG_ECHOLNPGM("LOGIC E3B - STALL, inc stall"); - DEBUG_ECHOLNPGM("inc stall"); - } - } - else { //phase 3 without stall warning but have OCD warning - DEBUG_ECHOLNPGM("Hardware problem - OCD warning without STALL warning"); - test_phase = 4; - //DEBUG_ECHOLNPGM("LOGIC E3C - not STALLED, hardware problem (quit)"); - } - } break; - - } - - } - else { - switch (test_phase) { - case 0: { // phase 0 without OCD warning - keep on decrementing if can - if (OCD_TH_val) { - OCD_TH_val--; // try lower value - //DEBUG_ECHOLNPGM("LOGIC N0A - DEC OCD"); - DEBUG_ECHOLNPGM("DEC OCD"); - } - else { - test_phase = 2; // at lowest value without warning so skip phase 1 - //DEBUG_ECHOLNPGM("LOGIC N0B - OCD at lowest (go to phase 2)"); - DEBUG_ECHOLNPGM("OCD finalized"); - } - } break; - - case 1: //DEBUG_ECHOLNPGM("LOGIC N1 (go directly to 2)"); // phase 1 without OCD warning - drop directly to phase 2 - DEBUG_ECHOLNPGM("OCD finalized"); - - case 2: { // phase 2 without stall warning - keep on decrementing if can - if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT) { // skip all STALL_TH steps if L6474 - test_phase = 4; - break; - } - if (STALL_TH_val) { - STALL_TH_val--; // try a lower value (stay in phase 2) - //DEBUG_ECHOLNPGM("LOGIC N2B - dec STALL"); - DEBUG_ECHOLNPGM("dec STALL"); - } - else { - DEBUG_ECHOLNPGM("finished - STALL at lowest value but still no stall warning"); - test_phase = 4; - //DEBUG_ECHOLNPGM("LOGIC N2C - STALL at lowest (quit)"); - } - } break; - - case 3: { - if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT) { // skip all STALL_TH steps if L6474 - test_phase = 4; - break; - } - test_phase = 4; - //DEBUG_ECHOLNPGM("LOGIC N3 - finished!"); - DEBUG_ECHOLNPGM("finished!"); - } break; // phase 3 without any warnings - desired exit - } // - } // end of status checks - - if (test_phase != 4) { - for (j = 0; j < driver_count; j++) { // update threshold(s) - L64xxManager.set_param(axis_index[j], L6470_OCD_TH, OCD_TH_val); - if (sh.STATUS_AXIS_LAYOUT != L6474_STATUS_LAYOUT) L64xxManager.set_param(axis_index[j], L6470_STALL_TH, STALL_TH_val); - if (L64xxManager.get_param(axis_index[j], L6470_OCD_TH) != OCD_TH_val) DEBUG_ECHOLNPGM("OCD mismatch"); - if ((L64xxManager.get_param(axis_index[j], L6470_STALL_TH) != STALL_TH_val) && (sh.STATUS_AXIS_LAYOUT != L6474_STATUS_LAYOUT)) DEBUG_ECHOLNPGM("STALL mismatch"); - } - } - - } while (test_phase != 4); - - DEBUG_ECHOLNPGM("."); - if (status_composite) { - #if ENABLED(L6470_CHITCHAT) - for (j = 0; j < driver_count; j++) { - if (j) DEBUG_ECHOPGM("..."); - L64xxManager.error_status_decode(axis_status[j], axis_index[j], - sh.STATUS_AXIS_TH_SD, sh.STATUS_AXIS_TH_WRN, - sh.STATUS_AXIS_STEP_LOSS_A, sh.STATUS_AXIS_STEP_LOSS_B, - sh.STATUS_AXIS_OCD, sh.STATUS_AXIS_LAYOUT); - } - DEBUG_ECHOLNPGM("."); - #endif - DEBUG_ECHOLNPGM("Completed with errors"); - } - else - DEBUG_ECHOLNPGM("Completed with no errors"); - DEBUG_ECHOLNPGM("."); - - L64xxManager.pause_monitor(false); -} - -/** - * M918: increase speed until error or max feedrate achieved (as shown in configuration.h)) - * - * J - select which driver(s) to monitor on multi-driver axis - * 0 - (default) monitor all drivers on the axis or E0 - * 1 - monitor only X, Y, Z, E1 - * 2 - monitor only X2, Y2, Z2, E2 - * Xxxx, Yxxx, Zxxx, Exxx - axis to be monitored with displacement - * xxx (1-255) is distance moved on either side of current position - * - * I - over current threshold - * optional - will report current value from driver if not specified - * - * T - current (mA) setting for TVAL (0 - 4A in 31.25mA increments, rounds down) - L6474 only - * optional - will report current value from driver if not specified - * - * K - value for KVAL_HOLD (0 - 255) (ignored for L6474) - * optional - will report current value from driver if not specified - * - * M - value for microsteps (1 - 128) (optional) - * optional - will report current value from driver if not specified - */ -void GcodeSuite::M918() { - - DEBUG_ECHOLNPGM("M918"); - - L64xxManager.pause_monitor(true); // Keep monitor_driver() from stealing status - - char axis_mon[3][3] = { {" "}, {" "}, {" "} }; // list of Axes to be monitored - L64XX_axis_t axis_index[3]; - uint16_t axis_status[3]; - uint8_t driver_count = 1; - float position_max, position_min; - float final_feedrate; - uint8_t kval_hold; - uint8_t OCD_TH_val = 0; - uint8_t STALL_TH_val = 0; - uint16_t over_current_threshold; - constexpr uint8_t over_current_flag = true; - - const L64XX_Marlin::L64XX_shadow_t &sh = L64xxManager.shadow; - - uint8_t j; // general purpose counter - - if (L64xxManager.get_user_input(driver_count, axis_index, axis_mon, position_max, position_min, final_feedrate, kval_hold, over_current_flag, OCD_TH_val, STALL_TH_val, over_current_threshold)) - return; // quit if invalid user input - - L64xxManager.get_status(axis_index[0]); // populate shadow array - - uint8_t m_steps = parser.byteval('M'); - - if (m_steps != 0) { - LIMIT(m_steps, 1, sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT ? 16 : 128); // L6474 - - uint8_t stepVal; - for (stepVal = 0; stepVal < 8; stepVal++) { // convert to L64xx register value - if (m_steps == 1) break; - m_steps >>= 1; - } - - if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT) - stepVal |= 0x98; // NO SYNC - else - stepVal |= (!SYNC_EN) | SYNC_SEL_1 | stepVal; - - for (j = 0; j < driver_count; j++) { - L64xxManager.set_param(axis_index[j], dSPIN_HARD_HIZ, 0); // can't write STEP register if stepper being powered - // results in an extra NOOP being sent (data 00) - L64xxManager.set_param(axis_index[j], L6470_STEP_MODE, stepVal); // set microsteps - } - } - m_steps = L64xxManager.get_param(axis_index[0], L6470_STEP_MODE) & 0x07; // get microsteps - - DEBUG_ECHOLNPGM("Microsteps = ", _BV(m_steps)); - DEBUG_ECHOLNPGM("target (maximum) feedrate = ", final_feedrate); - - const float feedrate_inc = final_feedrate / 10, // Start at 1/10 of max & go up by 1/10 per step - fr_limit = final_feedrate * 0.99f; // Rounding-safe comparison value - float current_feedrate = 0; - - planner.synchronize(); // Wait for moves to complete - - for (j = 0; j < driver_count; j++) - L64xxManager.get_status(axis_index[j]); // Clear error flags - - char temp_axis_string[2] = " "; - temp_axis_string[0] = axis_mon[0][0]; // Need a sprintf format string - //temp_axis_string[1] = '\n'; - - char gcode_string[80]; - uint16_t status_composite = 0; - DEBUG_ECHOLNPGM(".\n.\n."); // Make feedrate outputs easier to read - - do { - current_feedrate += feedrate_inc; - DEBUG_ECHOLNPGM("...feedrate = ", current_feedrate); - - sprintf_P(gcode_string, PSTR("G0 %s%03d F%03d"), temp_axis_string, uint16_t(position_min), uint16_t(current_feedrate)); - process_subcommands_now(gcode_string); - - sprintf_P(gcode_string, PSTR("G0 %s%03d F%03d"), temp_axis_string, uint16_t(position_max), uint16_t(current_feedrate)); - process_subcommands_now(gcode_string); - - planner.synchronize(); - - for (j = 0; j < driver_count; j++) { - axis_status[j] = (~L64xxManager.get_status(axis_index[j])) & 0x0800; // Bits of interest are all active LOW - status_composite |= axis_status[j]; - } - if (status_composite) break; // Break on any error - } while (current_feedrate < fr_limit); - - DEBUG_ECHOPGM("Completed with "); - if (status_composite) { - DEBUG_ECHOLNPGM("errors"); - #if ENABLED(L6470_CHITCHAT) - for (j = 0; j < driver_count; j++) { - if (j) DEBUG_ECHOPGM("..."); - L64xxManager.error_status_decode(axis_status[j], axis_index[j], - sh.STATUS_AXIS_TH_SD, sh.STATUS_AXIS_TH_WRN, - sh.STATUS_AXIS_STEP_LOSS_A, sh.STATUS_AXIS_STEP_LOSS_B, - sh.STATUS_AXIS_OCD, sh.STATUS_AXIS_LAYOUT); - } - #endif - } - else - DEBUG_ECHOLNPGM("no errors"); - - L64xxManager.pause_monitor(false); -} - -#endif // HAS_L64XX diff --git a/Marlin/src/gcode/feature/adc/M3426.cpp b/Marlin/src/gcode/feature/adc/M3426.cpp index 8205fa01..2820c8b8 100644 --- a/Marlin/src/gcode/feature/adc/M3426.cpp +++ b/Marlin/src/gcode/feature/adc/M3426.cpp @@ -28,6 +28,8 @@ #include "../../../feature/adc/adc_mcp3426.h" +#define MCP3426_BASE_ADDR (0b1101 << 3) + /** * M3426: Read 16 bit (signed) value from I2C MCP3426 ADC device * @@ -36,12 +38,15 @@ * M3426 I 0 or 1, invert reply */ void GcodeSuite::M3426() { - uint8_t channel = parser.byteval('C', 1), // Select the channel 1 or 2 - gain = parser.byteval('G', 1); - const bool inverted = parser.byteval('I') == 1; + uint8_t channel = parser.byteval('C', 1), // Channel 1 or 2 + gain = parser.byteval('G', 1), // Gain 1, 2, 4, or 8 + address = parser.byteval('A', 3); // Address 0-7 (or 104-111) + const bool inverted = parser.boolval('I'); + + if (address <= 7) address += MCP3426_BASE_ADDR; - if (channel <= 2 && (gain == 1 || gain == 2 || gain == 4 || gain == 8)) { - int16_t result = mcp3426.ReadValue(channel, gain); + if (WITHIN(channel, 1, 2) && (gain == 1 || gain == 2 || gain == 4 || gain == 8) && WITHIN(address, MCP3426_BASE_ADDR, MCP3426_BASE_ADDR + 7)) { + int16_t result = mcp3426.ReadValue(channel, gain, address); if (mcp3426.Error == false) { if (inverted) { diff --git a/Marlin/src/gcode/feature/advance/M900.cpp b/Marlin/src/gcode/feature/advance/M900.cpp index 054ea361..ec295f41 100644 --- a/Marlin/src/gcode/feature/advance/M900.cpp +++ b/Marlin/src/gcode/feature/advance/M900.cpp @@ -26,10 +26,9 @@ #include "../../gcode.h" #include "../../../module/planner.h" -#include "../../../module/stepper.h" -#if ENABLED(EXTRA_LIN_ADVANCE_K) - float other_extruder_advance_K[EXTRUDERS]; +#if ENABLED(ADVANCE_K_EXTRA) + float other_extruder_advance_K[DISTINCT_E]; uint8_t lin_adv_slot = 0; #endif @@ -37,8 +36,8 @@ * M900: Get or Set Linear Advance K-factor * T Which tool to address * K Set current advance K factor (Slot 0). - * L Set secondary advance K factor (Slot 1). Requires EXTRA_LIN_ADVANCE_K. - * S<0/1> Activate slot 0 or 1. Requires EXTRA_LIN_ADVANCE_K. + * L Set secondary advance K factor (Slot 1). Requires ADVANCE_K_EXTRA. + * S<0/1> Activate slot 0 or 1. Requires ADVANCE_K_EXTRA. */ void GcodeSuite::M900() { @@ -51,6 +50,7 @@ void GcodeSuite::M900() { #if EXTRUDERS < 2 constexpr uint8_t tool_index = 0; + UNUSED(tool_index); #else const uint8_t tool_index = parser.intval('T', active_extruder); if (tool_index >= EXTRUDERS) { @@ -59,12 +59,12 @@ void GcodeSuite::M900() { } #endif - float &kref = planner.extruder_advance_K[tool_index], newK = kref; + float &kref = planner.extruder_advance_K[E_INDEX_N(tool_index)], newK = kref; const float oldK = newK; - #if ENABLED(EXTRA_LIN_ADVANCE_K) + #if ENABLED(ADVANCE_K_EXTRA) - float &lref = other_extruder_advance_K[tool_index]; + float &lref = other_extruder_advance_K[E_INDEX_N(tool_index)]; const bool old_slot = TEST(lin_adv_slot, tool_index), // The tool's current slot (0 or 1) new_slot = parser.boolval('S', old_slot); // The passed slot (default = current) @@ -112,29 +112,28 @@ void GcodeSuite::M900() { if (!parser.seen_any()) { - #if ENABLED(EXTRA_LIN_ADVANCE_K) + #if ENABLED(ADVANCE_K_EXTRA) - #if EXTRUDERS < 2 + #if DISTINCT_E < 2 SERIAL_ECHOLNPGM("Advance S", new_slot, " K", kref, "(S", !new_slot, " K", lref, ")"); #else - LOOP_L_N(i, EXTRUDERS) { - const bool slot = TEST(lin_adv_slot, i); - SERIAL_ECHOLNPGM("Advance T", i, " S", slot, " K", planner.extruder_advance_K[i], - "(S", !slot, " K", other_extruder_advance_K[i], ")"); - SERIAL_EOL(); + EXTRUDER_LOOP() { + const bool slot = TEST(lin_adv_slot, e); + SERIAL_ECHOLNPGM("Advance T", e, " S", slot, " K", planner.extruder_advance_K[e], + "(S", !slot, " K", other_extruder_advance_K[e], ")"); } #endif #else SERIAL_ECHO_START(); - #if EXTRUDERS < 2 + #if DISTINCT_E < 2 SERIAL_ECHOLNPGM("Advance K=", planner.extruder_advance_K[0]); #else SERIAL_ECHOPGM("Advance K"); - LOOP_L_N(i, EXTRUDERS) { - SERIAL_CHAR(' ', '0' + i, ':'); - SERIAL_DECIMAL(planner.extruder_advance_K[i]); + EXTRUDER_LOOP() { + SERIAL_CHAR(' ', '0' + e, ':'); + SERIAL_DECIMAL(planner.extruder_advance_K[e]); } SERIAL_EOL(); #endif @@ -146,13 +145,13 @@ void GcodeSuite::M900() { void GcodeSuite::M900_report(const bool forReplay/*=true*/) { report_heading(forReplay, F(STR_LINEAR_ADVANCE)); - #if EXTRUDERS < 2 + #if DISTINCT_E < 2 report_echo_start(forReplay); SERIAL_ECHOLNPGM(" M900 K", planner.extruder_advance_K[0]); #else - LOOP_L_N(i, EXTRUDERS) { + EXTRUDER_LOOP() { report_echo_start(forReplay); - SERIAL_ECHOLNPGM(" M900 T", i, " K", planner.extruder_advance_K[i]); + SERIAL_ECHOLNPGM(" M900 T", e, " K", planner.extruder_advance_K[e]); } #endif } diff --git a/Marlin/src/gcode/feature/camera/M240.cpp b/Marlin/src/gcode/feature/camera/M240.cpp index 19051ffd..bb1d3f9e 100644 --- a/Marlin/src/gcode/feature/camera/M240.cpp +++ b/Marlin/src/gcode/feature/camera/M240.cpp @@ -84,7 +84,7 @@ inline void spin_photo_pin() { static constexpr uint32_t sequence[] = PHOTO_PULSES_US; - LOOP_L_N(i, COUNT(sequence)) + for (uint8_t i = 0; i < COUNT(sequence); ++i) pulse_photo_pin(sequence[i], !(i & 1)); } @@ -111,7 +111,7 @@ * B - Y offset to the return position * F - Override the XY movement feedrate * R - Retract/recover length (current units) - * S - Retract/recover feedrate (mm/m) + * S - Retract/recover feedrate (mm/min) * X - Move to X before triggering the shutter * Y - Move to Y before triggering the shutter * Z - Raise Z by a distance before triggering the shutter @@ -128,11 +128,13 @@ void GcodeSuite::M240() { if (homing_needed_error()) return; - const xyz_pos_t old_pos = { + const xyz_pos_t old_pos = NUM_AXIS_ARRAY( current_position.x + parser.linearval('A'), current_position.y + parser.linearval('B'), - current_position.z - }; + current_position.z, + current_position.i, current_position.j, current_position.k, + current_position.u, current_position.v, current_position.w + ); #ifdef PHOTO_RETRACT_MM const float rval = parser.linearval('R', _PHOTO_RETRACT_MM); @@ -140,7 +142,7 @@ void GcodeSuite::M240() { e_move_m240(-rval, sval); #endif - feedRate_t fr_mm_s = MMM_TO_MMS(parser.linearval('F')); + feedRate_t fr_mm_s = parser.feedrateval('F'); if (fr_mm_s) NOLESS(fr_mm_s, 10.0f); constexpr xyz_pos_t photo_position = PHOTO_POSITION; diff --git a/Marlin/src/gcode/feature/cancel/M486.cpp b/Marlin/src/gcode/feature/cancel/M486.cpp index 1f14ae0f..c1e90d1b 100644 --- a/Marlin/src/gcode/feature/cancel/M486.cpp +++ b/Marlin/src/gcode/feature/cancel/M486.cpp @@ -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 diff --git a/Marlin/src/gcode/feature/clean/G12.cpp b/Marlin/src/gcode/feature/clean/G12.cpp index a0b87b1a..0113170f 100644 --- a/Marlin/src/gcode/feature/clean/G12.cpp +++ b/Marlin/src/gcode/feature/clean/G12.cpp @@ -45,8 +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()) 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()) { diff --git a/Marlin/src/gcode/feature/digipot/M907-M910.cpp b/Marlin/src/gcode/feature/digipot/M907-M910.cpp index 757cffd4..8869f8d4 100644 --- a/Marlin/src/gcode/feature/digipot/M907-M910.cpp +++ b/Marlin/src/gcode/feature/digipot/M907-M910.cpp @@ -39,51 +39,77 @@ #endif /** - * M907: Set digital trimpot motor current using axis codes X, Y, Z, E, B, S + * M907: Set digital trimpot motor current using axis codes X [Y] [Z] [I] [J] [K] [U] [V] [W] [E] + * B - Special case for E1 (Requires DIGIPOTSS_PIN or DIGIPOT_MCP4018 or DIGIPOT_MCP4451) + * C - Special case for E2 (Requires DIGIPOTSS_PIN or DIGIPOT_MCP4018 or DIGIPOT_MCP4451) + * S - 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 - if (!parser.seen("BS" LOGICAL_AXES_STRING)) + if (!parser.seen("BS" STR_AXES_LOGICAL)) 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')) for (uint8_t i = 0; i < MOTOR_CURRENT_COUNT; ++i) 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 U V W) 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? + #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, MOTOR_CURRENT_PWM_U, MOTOR_CURRENT_PWM_V, MOTOR_CURRENT_PWM_W) + #define HAS_X_Y_XY_I_J_K_U_V_W 1 + #endif + + #if HAS_X_Y_XY_I_J_K_U_V_W || ANY_PIN(MOTOR_CURRENT_PWM_E, MOTOR_CURRENT_PWM_Z) + + if (!parser.seen("S" + #if HAS_X_Y_XY_I_J_K_U_V_W + "XY" SECONDARY_AXIS_GANG("I", "J", "K", "U", "V", "W") + #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')) for (uint8_t a = 0; a < MOTOR_CURRENT_COUNT; ++a) stepper.set_digipot_current(a, parser.value_int()); + + #if HAS_X_Y_XY_I_J_K_U_V_W + if (NUM_AXIS_GANG( + parser.seenval('X'), || parser.seenval('Y'), || false, + || parser.seenval('I'), || parser.seenval('J'), || parser.seenval('K'), + || parser.seenval('U'), || parser.seenval('V'), || parser.seenval('W') + )) 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 + #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? - #if HAS_EXTRUDERS - for (uint8_t i = E_AXIS + 1; i < DIGIPOT_I2C_NUM_CHANNELS; i++) + if (parser.seenval('S')) for (uint8_t q = 0; q < DIGIPOT_I2C_NUM_CHANNELS; ++q) 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 U V W) 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? + #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 @@ -91,9 +117,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 U V W) 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 } @@ -102,19 +128,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, U, V, W) , 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]); + LOOP_LOGICAL_AXES(q) { // X Y Z (I J K U V W) E (map to X Y Z (I J K U V W) E0 by default) + 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 } diff --git a/Marlin/src/gcode/feature/i2c/M260_M261.cpp b/Marlin/src/gcode/feature/i2c/M260_M261.cpp index e978fb50..cf9bb7e5 100644 --- a/Marlin/src/gcode/feature/i2c/M260_M261.cpp +++ b/Marlin/src/gcode/feature/i2c/M260_M261.cpp @@ -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 B S