From 95bafca9d9c0eae023d26af840d3215cd0d13747 Mon Sep 17 00:00:00 2001 From: InsanityAutomation Date: Sun, 14 Jan 2024 15:35:57 -0500 Subject: [PATCH 01/22] LPC4078 Initial Commit Co-Authored-By: Chris Pepper <24342+p3p@users.noreply.github.com> --- Marlin/Configuration.h | 118 ++-- Marlin/src/HAL/LPC4078/HAL.cpp | 125 ++++ Marlin/src/HAL/LPC4078/HAL.h | 267 ++++++++ Marlin/src/HAL/LPC4078/HAL_SPI.cpp | 404 ++++++++++++ Marlin/src/HAL/LPC4078/MarlinSPI.h | 45 ++ Marlin/src/HAL/LPC4078/MarlinSerial.cpp | 78 +++ Marlin/src/HAL/LPC4078/MarlinSerial.h | 108 ++++ Marlin/src/HAL/LPC4078/MinSerial.cpp | 51 ++ Marlin/src/HAL/LPC4078/Servo.h | 69 ++ Marlin/src/HAL/LPC4078/SoftwareSPI.cpp | 47 ++ Marlin/src/HAL/LPC4078/SoftwareSPI.h | 5 + Marlin/src/HAL/LPC4078/eeprom_internal.cpp | 116 ++++ Marlin/src/HAL/LPC4078/endstop_interrupts.h | 191 ++++++ Marlin/src/HAL/LPC4078/fast_pwm.cpp | 37 ++ Marlin/src/HAL/LPC4078/fastio.h | 120 ++++ Marlin/src/HAL/LPC4078/inc/Conditionals_LCD.h | 22 + Marlin/src/HAL/LPC4078/inc/Conditionals_adv.h | 26 + .../src/HAL/LPC4078/inc/Conditionals_post.h | 34 + Marlin/src/HAL/LPC4078/inc/SanityCheck.h | 276 ++++++++ Marlin/src/HAL/LPC4078/include/SPI.h | 197 ++++++ Marlin/src/HAL/LPC4078/main.cpp | 111 ++++ Marlin/src/HAL/LPC4078/pinsDebug.h | 57 ++ Marlin/src/HAL/LPC4078/spi_pins.h | 54 ++ Marlin/src/HAL/LPC4078/timers.cpp | 65 ++ Marlin/src/HAL/LPC4078/timers.h | 165 +++++ .../src/HAL/LPC4078/u8g/LCD_I2C_routines.cpp | 89 +++ Marlin/src/HAL/LPC4078/u8g/LCD_I2C_routines.h | 28 + Marlin/src/HAL/LPC4078/u8g/LCD_defines.h | 46 ++ Marlin/src/HAL/LPC4078/u8g/LCD_delay.h | 43 ++ .../src/HAL/LPC4078/u8g/LCD_pin_routines.cpp | 59 ++ Marlin/src/HAL/LPC4078/u8g/LCD_pin_routines.h | 37 ++ .../u8g/u8g_com_HAL_LPC1768_hw_spi.cpp | 129 ++++ .../u8g/u8g_com_HAL_LPC1768_ssd_hw_i2c.cpp | 198 ++++++ .../u8g/u8g_com_HAL_LPC1768_st7920_hw_spi.cpp | 138 ++++ .../u8g/u8g_com_HAL_LPC1768_st7920_sw_spi.cpp | 147 +++++ .../u8g/u8g_com_HAL_LPC1768_sw_spi.cpp | 209 ++++++ Marlin/src/HAL/platforms.h | 2 + Marlin/src/HAL/shared/servo.h | 2 + Marlin/src/core/boards.h | 1 + Marlin/src/pins/lpc4078/pins_EBAB.h | 605 ++++++++++++++++++ Marlin/src/pins/pins.h | 7 + ini/lpc176x.ini | 24 + 42 files changed, 4493 insertions(+), 59 deletions(-) create mode 100644 Marlin/src/HAL/LPC4078/HAL.cpp create mode 100644 Marlin/src/HAL/LPC4078/HAL.h create mode 100644 Marlin/src/HAL/LPC4078/HAL_SPI.cpp create mode 100644 Marlin/src/HAL/LPC4078/MarlinSPI.h create mode 100644 Marlin/src/HAL/LPC4078/MarlinSerial.cpp create mode 100644 Marlin/src/HAL/LPC4078/MarlinSerial.h create mode 100644 Marlin/src/HAL/LPC4078/MinSerial.cpp create mode 100644 Marlin/src/HAL/LPC4078/Servo.h create mode 100644 Marlin/src/HAL/LPC4078/SoftwareSPI.cpp create mode 100644 Marlin/src/HAL/LPC4078/SoftwareSPI.h create mode 100644 Marlin/src/HAL/LPC4078/eeprom_internal.cpp create mode 100644 Marlin/src/HAL/LPC4078/endstop_interrupts.h create mode 100644 Marlin/src/HAL/LPC4078/fast_pwm.cpp create mode 100644 Marlin/src/HAL/LPC4078/fastio.h create mode 100644 Marlin/src/HAL/LPC4078/inc/Conditionals_LCD.h create mode 100644 Marlin/src/HAL/LPC4078/inc/Conditionals_adv.h create mode 100644 Marlin/src/HAL/LPC4078/inc/Conditionals_post.h create mode 100644 Marlin/src/HAL/LPC4078/inc/SanityCheck.h create mode 100644 Marlin/src/HAL/LPC4078/include/SPI.h create mode 100644 Marlin/src/HAL/LPC4078/main.cpp create mode 100644 Marlin/src/HAL/LPC4078/pinsDebug.h create mode 100644 Marlin/src/HAL/LPC4078/spi_pins.h create mode 100644 Marlin/src/HAL/LPC4078/timers.cpp create mode 100644 Marlin/src/HAL/LPC4078/timers.h create mode 100644 Marlin/src/HAL/LPC4078/u8g/LCD_I2C_routines.cpp create mode 100644 Marlin/src/HAL/LPC4078/u8g/LCD_I2C_routines.h create mode 100644 Marlin/src/HAL/LPC4078/u8g/LCD_defines.h create mode 100644 Marlin/src/HAL/LPC4078/u8g/LCD_delay.h create mode 100644 Marlin/src/HAL/LPC4078/u8g/LCD_pin_routines.cpp create mode 100644 Marlin/src/HAL/LPC4078/u8g/LCD_pin_routines.h create mode 100644 Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_hw_spi.cpp create mode 100644 Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_ssd_hw_i2c.cpp create mode 100644 Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_st7920_hw_spi.cpp create mode 100644 Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_st7920_sw_spi.cpp create mode 100644 Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_sw_spi.cpp create mode 100644 Marlin/src/pins/lpc4078/pins_EBAB.h diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 6e4afa16c6..625cf35ab8 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -61,14 +61,14 @@ // @section info // Author info of this build printed to the host during boot and M115 -#define STRING_CONFIG_H_AUTHOR "(none, default config)" // Who made the changes. +#define STRING_CONFIG_H_AUTHOR "InsanityAutomation" // Who made the changes. //#define CUSTOM_VERSION_FILE Version.h // Path from the root directory (no quotes) // @section machine // Choose the name from boards.h that matches your setup #ifndef MOTHERBOARD - #define MOTHERBOARD BOARD_RAMPS_14_EFB + #define MOTHERBOARD BOARD_EBAB #endif /** @@ -79,7 +79,7 @@ * * :[-1, 0, 1, 2, 3, 4, 5, 6, 7] */ -#define SERIAL_PORT 0 +#define SERIAL_PORT -1 /** * Serial Port Baud Rate @@ -101,7 +101,7 @@ * Currently Ethernet (-2) is only supported on Teensy 4.1 boards. * :[-2, -1, 0, 1, 2, 3, 4, 5, 6, 7] */ -//#define SERIAL_PORT_2 -1 +#define SERIAL_PORT_2 0 //#define BAUDRATE_2 250000 // :[2400, 9600, 19200, 38400, 57600, 115200, 250000, 500000, 1000000] Enable to override BAUDRATE /** @@ -116,7 +116,7 @@ //#define BLUETOOTH // Name displayed in the LCD "Ready" message and Info menu -//#define CUSTOM_MACHINE_NAME "3D Printer" +#define CUSTOM_MACHINE_NAME "FatBoy" // Printer's unique ID, used by some programs to differentiate between machines. // Choose your own or use a service like https://www.uuidgenerator.net/version4 @@ -139,21 +139,21 @@ * TMC5130, TMC5130_STANDALONE, TMC5160, TMC5160_STANDALONE * :['A4988', 'A5984', 'DRV8825', 'LV8729', 'TB6560', 'TB6600', 'TMC2100', 'TMC2130', 'TMC2130_STANDALONE', 'TMC2160', 'TMC2160_STANDALONE', 'TMC2208', 'TMC2208_STANDALONE', 'TMC2209', 'TMC2209_STANDALONE', 'TMC26X', 'TMC26X_STANDALONE', 'TMC2660', 'TMC2660_STANDALONE', 'TMC5130', 'TMC5130_STANDALONE', 'TMC5160', 'TMC5160_STANDALONE'] */ -#define X_DRIVER_TYPE A4988 -#define Y_DRIVER_TYPE A4988 -#define Z_DRIVER_TYPE A4988 +#define X_DRIVER_TYPE TB6560 +#define Y_DRIVER_TYPE TB6560 +#define Z_DRIVER_TYPE TB6560 //#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 Y2_DRIVER_TYPE TB6560 +#define Z2_DRIVER_TYPE TB6560 +#define Z3_DRIVER_TYPE TB6560 +#define Z4_DRIVER_TYPE TB6560 //#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 A4988 +#define E0_DRIVER_TYPE TMC2209 //#define E1_DRIVER_TYPE A4988 //#define E2_DRIVER_TYPE A4988 //#define E3_DRIVER_TYPE A4988 @@ -552,7 +552,7 @@ #define TEMP_SENSOR_5 0 #define TEMP_SENSOR_6 0 #define TEMP_SENSOR_7 0 -#define TEMP_SENSOR_BED 1 +#define TEMP_SENSOR_BED 11 #define TEMP_SENSOR_PROBE 0 #define TEMP_SENSOR_CHAMBER 0 #define TEMP_SENSOR_COOLER 0 @@ -628,7 +628,7 @@ // Above this temperature the heater will be switched off. // This can protect components from overheating, but NOT from shorts and failures. // (Use MINTEMP for thermistor short/failure protection.) -#define HEATER_0_MAXTEMP 275 +#define HEATER_0_MAXTEMP 300 #define HEATER_1_MAXTEMP 275 #define HEATER_2_MAXTEMP 275 #define HEATER_3_MAXTEMP 275 @@ -636,7 +636,7 @@ #define HEATER_5_MAXTEMP 275 #define HEATER_6_MAXTEMP 275 #define HEATER_7_MAXTEMP 275 -#define BED_MAXTEMP 150 +#define BED_MAXTEMP 120 #define CHAMBER_MAXTEMP 60 /** @@ -645,7 +645,7 @@ * (especially before PID tuning). Setting the target temperature too close to MAXTEMP guarantees * a MAXTEMP shutdown! Use these values to forbid temperatures being set too close to MAXTEMP. */ -#define HOTEND_OVERSHOOT 15 // (°C) Forbid temperatures over MAXTEMP - OVERSHOOT +#define HOTEND_OVERSHOOT 10 // (°C) Forbid temperatures over MAXTEMP - OVERSHOOT #define BED_OVERSHOOT 10 // (°C) Forbid temperatures over MAXTEMP - OVERSHOOT #define COOLER_OVERSHOOT 2 // (°C) Forbid temperatures closer than OVERSHOOT @@ -748,7 +748,7 @@ * 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 +#define MAX_BED_POWER 180 // limits duty cycle to bed; 255=full current /** * PID Bed Heating @@ -762,7 +762,7 @@ * * With this option disabled, bang-bang will be used. BED_LIMIT_SWITCHING enables hysteresis. */ -//#define PIDTEMPBED +#define PIDTEMPBED #if ENABLED(PIDTEMPBED) //#define MIN_BED_POWER 0 @@ -833,8 +833,8 @@ #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) + #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 safety @@ -1234,7 +1234,7 @@ * Override with M92 (when enabled below) * X, Y, Z [, I [, J [, K...]]], E0 [, E1[, E2...]] */ -#define DEFAULT_AXIS_STEPS_PER_UNIT { 80, 80, 400, 500 } +#define DEFAULT_AXIS_STEPS_PER_UNIT { 40, 40, 200, 425 } /** * Enable support for M92. Disable to save at least ~530 bytes of flash. @@ -1259,7 +1259,7 @@ * Override with M201 * X, Y, Z [, I [, J [, K...]]], E0 [, E1[, E2...]] */ -#define DEFAULT_MAX_ACCELERATION { 3000, 3000, 100, 10000 } +#define DEFAULT_MAX_ACCELERATION { 12000, 12000, 500, 10000 } //#define LIMITED_MAX_ACCEL_EDITING // Limit edit via M201 or LCD to DEFAULT_MAX_ACCELERATION * 2 #if ENABLED(LIMITED_MAX_ACCEL_EDITING) @@ -1274,9 +1274,9 @@ * M204 R Retract Acceleration * M204 T Travel Acceleration */ -#define DEFAULT_ACCELERATION 3000 // X, Y, Z and E acceleration for printing moves +#define DEFAULT_ACCELERATION 7000 // X, Y, Z and E acceleration for printing moves #define DEFAULT_RETRACT_ACCELERATION 3000 // E acceleration for retracts -#define DEFAULT_TRAVEL_ACCELERATION 3000 // X, Y, Z acceleration for travel (non printing) moves +#define DEFAULT_TRAVEL_ACCELERATION 7000 // X, Y, Z acceleration for travel (non printing) moves /** * Default Jerk limits (mm/s) @@ -1329,7 +1329,7 @@ * * See https://github.com/synthetos/TinyG/wiki/Jerk-Controlled-Motion-Explained */ -//#define S_CURVE_ACCELERATION +#define S_CURVE_ACCELERATION //=========================================================================== //============================= Z Probe Options ============================= @@ -1345,10 +1345,10 @@ * The probe replaces the Z-MIN endstop and is used for Z homing. * (Automatically enables USE_PROBE_FOR_Z_HOMING.) */ -#define Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN +//#define Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN // Force the use of the probe for Z-axis homing -//#define USE_PROBE_FOR_Z_HOMING +#define USE_PROBE_FOR_Z_HOMING /** * Z_MIN_PROBE_PIN @@ -1405,7 +1405,7 @@ /** * The BLTouch probe uses a Hall effect sensor and emulates a servo. */ -//#define BLTOUCH +#define BLTOUCH /** * MagLev V4 probe by MDD @@ -1635,7 +1635,7 @@ * A total of 2 does fast/slow probes with a weighted average. * A total of 3 or more adds more slow probes, taking the average. */ -//#define MULTIPLE_PROBING 2 +#define MULTIPLE_PROBING 2 //#define EXTRA_PROBING 1 /** @@ -1658,7 +1658,7 @@ #define Z_PROBE_ERROR_TOLERANCE 3 // (mm) Tolerance for early trigger (<= -probe.offset.z + ZPET) //#define Z_AFTER_PROBING 5 // (mm) Z position after probing is done -#define Z_PROBE_LOW_POINT -2 // (mm) Farthest distance below the trigger-point to go before stopping +#define Z_PROBE_LOW_POINT -5 // (mm) Farthest distance below the trigger-point to go before stopping // For M851 provide ranges for adjusting the X, Y, and Z probe offsets //#define PROBE_OFFSET_XMIN -50 // (mm) @@ -1737,9 +1737,9 @@ // @section motion // Invert the stepper direction. Change (or reverse the motor connector) if an axis goes the wrong way. -#define INVERT_X_DIR false -#define INVERT_Y_DIR true -#define INVERT_Z_DIR false +#define INVERT_X_DIR true +#define INVERT_Y_DIR false +#define INVERT_Z_DIR true //#define INVERT_I_DIR false //#define INVERT_J_DIR false //#define INVERT_K_DIR false @@ -1809,8 +1809,8 @@ // @section geometry // The size of the printable area -#define X_BED_SIZE 200 -#define Y_BED_SIZE 200 +#define X_BED_SIZE 1200 +#define Y_BED_SIZE 1200 // Travel limits (linear=mm, rotational=°) after homing, corresponding to endstop positions. #define X_MIN_POS 0 @@ -1818,7 +1818,7 @@ #define Z_MIN_POS 0 #define X_MAX_POS X_BED_SIZE #define Y_MAX_POS Y_BED_SIZE -#define Z_MAX_POS 200 +#define Z_MAX_POS 1000 //#define I_MIN_POS 0 //#define I_MAX_POS 50 //#define J_MIN_POS 0 @@ -1870,7 +1870,7 @@ #endif #if ANY(MIN_SOFTWARE_ENDSTOPS, MAX_SOFTWARE_ENDSTOPS) - //#define SOFT_ENDSTOPS_MENU_ITEM // Enable/Disable software endstops from the LCD + #define SOFT_ENDSTOPS_MENU_ITEM // Enable/Disable software endstops from the LCD #endif /** @@ -2029,7 +2029,7 @@ */ //#define AUTO_BED_LEVELING_3POINT //#define AUTO_BED_LEVELING_LINEAR -//#define AUTO_BED_LEVELING_BILINEAR +#define AUTO_BED_LEVELING_BILINEAR //#define AUTO_BED_LEVELING_UBL //#define MESH_BED_LEVELING @@ -2037,14 +2037,14 @@ * Commands to execute at the end of G29 probing. * Useful to retract or move the Z probe out of the way. */ -//#define EVENT_GCODE_AFTER_G29 "G1 Z10 F12000\nG1 X15 Y330\nG1 Z0.5\nG1 Z10" +//#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 * leveling immediately after G28. */ -//#define RESTORE_LEVELING_AFTER_G28 +#define RESTORE_LEVELING_AFTER_G28 //#define ENABLE_LEVELING_AFTER_G28 /** @@ -2059,7 +2059,7 @@ /** * Enable detailed logging of G28, G29, M48, etc. * Turn on with the command 'M111 S32'. - * NOTE: Requires a lot of flash! + * NOTE: Requires a lot of PROGMEM! */ //#define DEBUG_LEVELING_FEATURE @@ -2076,7 +2076,7 @@ */ #define ENABLE_LEVELING_FADE_HEIGHT #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) - #define DEFAULT_LEVELING_FADE_HEIGHT 10.0 // (mm) Default fade height. + #define DEFAULT_LEVELING_FADE_HEIGHT 0.0 // (mm) Default fade height. #endif /** @@ -2090,7 +2090,7 @@ /** * Enable the G26 Mesh Validation Pattern tool. */ - //#define G26_MESH_VALIDATION + #define G26_MESH_VALIDATION #if ENABLED(G26_MESH_VALIDATION) #define MESH_TEST_NOZZLE_SIZE 0.4 // (mm) Diameter of primary nozzle. #define MESH_TEST_LAYER_HEIGHT 0.2 // (mm) Default layer height for G26. @@ -2106,7 +2106,7 @@ #if ANY(AUTO_BED_LEVELING_LINEAR, AUTO_BED_LEVELING_BILINEAR) // Set the number of grid points per dimension. - #define GRID_MAX_POINTS_X 3 + #define GRID_MAX_POINTS_X 15 #define GRID_MAX_POINTS_Y GRID_MAX_POINTS_X // Probe along the Y axis, advancing X after each column @@ -2116,7 +2116,7 @@ // Beyond the probed grid, continue the implied tilt? // Default is to maintain the height of the nearest edge. - //#define EXTRAPOLATE_BEYOND_GRID + #define EXTRAPOLATE_BEYOND_GRID // // Subdivision of the grid by Catmull-Rom method. @@ -2192,12 +2192,12 @@ * Add a bed leveling sub-menu for ABL or MBL. * Include a guided procedure if manual probing is enabled. */ -//#define LCD_BED_LEVELING +#define LCD_BED_LEVELING #if ENABLED(LCD_BED_LEVELING) #define MESH_EDIT_Z_STEP 0.025 // (mm) Step size while manually probing Z axis. - #define LCD_PROBE_Z_RANGE 4 // (mm) Z Range centered on Z_MIN_POS for LCD Z adjustment - //#define MESH_EDIT_MENU // Add a menu to edit mesh points + #define LCD_PROBE_Z_RANGE 8 // (mm) Z Range centered on Z_MIN_POS for LCD Z adjustment + #define MESH_EDIT_MENU // Add a menu to edit mesh points #endif // Add a menu item to move between bed corners for manual bed adjustment @@ -2259,7 +2259,7 @@ * - Allows Z homing only when XY positions are known and trusted. * - If stepper drivers sleep, XY homing may be required again before Z homing. */ -//#define Z_SAFE_HOMING +#define Z_SAFE_HOMING #if ENABLED(Z_SAFE_HOMING) #define Z_SAFE_HOMING_X_POINT X_CENTER // (mm) X point for Z homing @@ -2346,12 +2346,12 @@ * M501 - Read settings from EEPROM. (i.e., Throw away unsaved changes) * M502 - Revert settings to "factory" defaults. (Follow with M500 to init the EEPROM.) */ -//#define EEPROM_SETTINGS // Persistent storage with M500 and M501 +#define EEPROM_SETTINGS // Persistent storage with M500 and M501 //#define DISABLE_M503 // Saves ~2700 bytes of flash. Disable for release! -#define EEPROM_CHITCHAT // Give feedback on EEPROM commands. Disable to save flash. +#define EEPROM_CHITCHAT // Give feedback on EEPROM commands. Disable to save PROGMEM. #define EEPROM_BOOT_SILENT // Keep M503 quiet and only give errors during first load #if ENABLED(EEPROM_SETTINGS) - //#define EEPROM_AUTO_INIT // Init EEPROM automatically on any errors. + #define EEPROM_AUTO_INIT // Init EEPROM automatically on any errors. //#define EEPROM_INIT_NOW // Init EEPROM on first boot after a new build. #endif @@ -2409,11 +2409,11 @@ * P1 Raise the nozzle always to Z-park height. * P2 Raise the nozzle by Z-park amount, limited to Z_MAX_POS. */ -//#define NOZZLE_PARK_FEATURE +#define NOZZLE_PARK_FEATURE #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_POINT { (X_MIN_POS + 10), (Y_MIN_POS + 10), 5 } #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) @@ -2636,7 +2636,7 @@ * SD Card support is disabled by default. If your controller has an SD slot, * you must uncomment the following option or it won't work. */ -//#define SDSUPPORT +#define SDSUPPORT /** * SD CARD: ENABLE CRC @@ -2716,7 +2716,7 @@ // // Add individual axis homing items (Home X, Home Y, and Home Z) to the LCD menu. // -//#define INDIVIDUAL_AXIS_HOMING_MENU +#define INDIVIDUAL_AXIS_HOMING_MENU //#define INDIVIDUAL_AXIS_HOMING_SUBMENU // @@ -2725,7 +2725,7 @@ // If you have a speaker that can produce tones, enable it here. // By default Marlin assumes you have a buzzer with a fixed frequency. // -//#define SPEAKER +#define SPEAKER // // The duration and frequency for the UI feedback sound. @@ -2919,7 +2919,7 @@ // RepRapDiscount FULL GRAPHIC Smart Controller // https://reprap.org/wiki/RepRapDiscount_Full_Graphic_Smart_Controller // -//#define REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER +#define REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER // // K.3D Full Graphic Smart Controller diff --git a/Marlin/src/HAL/LPC4078/HAL.cpp b/Marlin/src/HAL/LPC4078/HAL.cpp new file mode 100644 index 0000000000..3cdf636480 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/HAL.cpp @@ -0,0 +1,125 @@ +/** + * 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_LPC4078 + +#include "../../inc/MarlinConfig.h" +#include "../shared/Delay.h" +#include "../../../gcode/parser.h" + +DefaultSerial1 USBSerial(false, MCDCSerial0); + +uint32_t MarlinHAL::adc_result = 0; + +// U8glib required functions +extern "C" { + void u8g_xMicroDelay(uint16_t val) { DELAY_US(val); } + void u8g_MicroDelay() { u8g_xMicroDelay(1); } + void u8g_10MicroDelay() { u8g_xMicroDelay(10); } + void u8g_Delay(uint16_t val) { delay(val); } +} + +// return free heap space +int freeMemory() { + char stack_end; + void *heap_start = malloc(sizeof(uint32_t)); + if (heap_start == 0) return 0; + + uint32_t result = (uint32_t)&stack_end - (uint32_t)heap_start; + free(heap_start); + return result; +} + +void MarlinHAL::reboot() { MCUCore::nvic_system_reset(); } + +uint8_t MarlinHAL::get_reset_source() { + #if ENABLED(USE_WATCHDOG) + if (watchdog_timed_out()) return RST_WATCHDOG; + #endif + return RST_POWER_ON; +} + +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) + + #define WDT_TIMEOUT TERN(WATCHDOG_DURATION_8S, 8.0f, 4.0f) // 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(); + + // WDT defaults to trigger an interrupt + + // 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 + MCUI::watchdog_set_timeout_triggers_reset(); + #endif + MCUI::watchdog_set_timeout_in_seconds(WDT_TIMEOUT); + MCUI::watchdog_enable(); + } + + void MarlinHAL::watchdog_refresh() { + MCUI::watchdog_feed(); + #if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED) + static millis_t next_flash = millis(); + if (ELAPSED(millis(), next_flash)) { + next_flash = millis() + 200; + TOGGLE(LED_PIN); // heartbeat indicator + } + #endif + } + + // Timeout state + bool MarlinHAL::watchdog_timed_out() { return MCUI::watchdog_has_triggered(); } + void MarlinHAL::watchdog_clear_timeout_flag() { MCUI::watchdog_clear_timeout_flag(); } + +#endif // USE_WATCHDOG + +// 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_LPC4078 diff --git a/Marlin/src/HAL/LPC4078/HAL.h b/Marlin/src/HAL/LPC4078/HAL.h new file mode 100644 index 0000000000..c4803909a7 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/HAL.h @@ -0,0 +1,267 @@ +/** + * 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 + * + * 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 + +/** + * HAL_LPC1768/HAL.h + * Hardware Abstraction Layer for NXP LPC1768 + */ + +#define CPU_32_BIT + +#include +#include +#include + +#include "../shared/Marduino.h" +#include "../shared/Delay.h" +#include "../shared/math_32bit.h" +#include "../shared/HAL_SPI.h" +#include "fastio.h" +#include "MarlinSerial.h" + +#include + +// ------------------------ +// Serial ports +// ------------------------ + +typedef ForwardSerial1Class< decltype(MCDCSerial0) > DefaultSerial1; +extern DefaultSerial1 USBSerial; + +#define _MSERIAL(X) MSerial##X +#define MSERIAL(X) _MSERIAL(X) + +#if SERIAL_PORT == -1 + #define MYSERIAL1 USBSerial +#elif WITHIN(SERIAL_PORT, 0, 3) + #define MYSERIAL1 MSERIAL(SERIAL_PORT) +#else + #error "SERIAL_PORT must be from 0 to 3. You can also use -1 if the board supports Native USB." +#endif + +#ifdef SERIAL_PORT_2 + #if SERIAL_PORT_2 == -1 + #define MYSERIAL2 USBSerial + #elif WITHIN(SERIAL_PORT_2, 0, 3) + #define MYSERIAL2 MSERIAL(SERIAL_PORT_2) + #else + #error "SERIAL_PORT_2 must be from 0 to 3. You can also use -1 if the board supports Native USB." + #endif +#endif + +#ifdef SERIAL_PORT_3 + #if SERIAL_PORT_3 == -1 + #define MYSERIAL3 USBSerial + #elif WITHIN(SERIAL_PORT_3, 0, 3) + #define MYSERIAL3 MSERIAL(SERIAL_PORT_3) + #else + #error "SERIAL_PORT_3 must be from 0 to 3. You can also use -1 if the board supports Native USB." + #endif +#endif + +#ifdef MMU2_SERIAL_PORT + #if MMU2_SERIAL_PORT == -1 + #define MMU2_SERIAL USBSerial + #elif WITHIN(MMU2_SERIAL_PORT, 0, 3) + #define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT) + #else + #error "MMU2_SERIAL_PORT must be from 0 to 3. You can also use -1 if the board supports Native USB." + #endif +#endif + +#ifdef LCD_SERIAL_PORT + #if LCD_SERIAL_PORT == -1 + #define LCD_SERIAL USBSerial + #elif WITHIN(LCD_SERIAL_PORT, 0, 3) + #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) + #else + #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() + #endif +#endif + +// +// Interrupts +// + +#define CRITICAL_SECTION_START() const bool irqon = !MCUCore::primask(); MCUCore::nvic_interrupts_disable() +#define CRITICAL_SECTION_END() if (irqon) MCUCore::nvic_interrupts_enable() + +// +// ADC +// + +#define ADC_MEDIAN_FILTER_SIZE (23) // Higher values increase step delay (phase shift), + // (ADC_MEDIAN_FILTER_SIZE + 1) / 2 sample step delay (12 samples @ 500Hz: 24ms phase shift) + // Memory usage per ADC channel (bytes): (6 * ADC_MEDIAN_FILTER_SIZE) + 16 + // 8 * ((6 * 23) + 16 ) = 1232 Bytes for 8 channels + +#define ADC_LOWPASS_K_VALUE (2) // Higher values increase rise time + // Rise time sample delays for 100% signal convergence on full range step + // (1 : 13, 2 : 32, 3 : 67, 4 : 139, 5 : 281, 6 : 565, 7 : 1135, 8 : 2273) + // 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_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 + +// +// Pin Mapping for M42, M43, M226 +// + +// Test whether the pin is valid +constexpr bool VALID_PIN(const pin_t pin) { + return MCUI::pin_is_valid(pin); +} + +// Get the analog index for a digital pin +constexpr int8_t DIGITAL_PIN_TO_ANALOG_PIN(const pin_t pin) { + return (MCUI::pin_is_valid(pin) && MCUI::pin_has_adc(pin)) ? pin : -1; +} + +// Return the index of a pin number +constexpr int16_t GET_PIN_MAP_INDEX(const pin_t pin) { + return MCUI::pin_index(pin); +} + +// Get the pin number at the given index +constexpr pin_t GET_PIN_MAP_PIN(const int16_t index) { + return MCUI::pin_index(index); +} + +// Parse a G-code word into a pin index +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, + +// ------------------------ +// Defines +// ------------------------ + +void flashFirmware(const int16_t); + +#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment + +// Default graphical display delays +#define CPU_ST7920_DELAY_1 600 +#define CPU_ST7920_DELAY_2 750 +#define CPU_ST7920_DELAY_3 750 + +// ------------------------ +// 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 MCUCore::primask(); } + static void isr_on() { MCUCore::nvic_interrupts_enable(); } + static void isr_off() { MCUCore::nvic_interrupts_disable(); } + + static void delay_ms(const int ms) { DELAY_US(ms * 1000); } + + // 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 = MCUI::ADC; + + // Called by Temperature::init once at startup + static void adc_init() { + // Turn on and initialise ADC in burst mode + MCUI::adc_hardware.init(); + MCUI::adc_hardware.burst_start(); + } + + // 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 void adc_start(const pin_t pin) { + adc_result = FilteredADC::read(pin) >> (16 - HAL_ADC_RESOLUTION); // returns 16bit value, reduce to required bits + } + + // 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 uint16_t(adc_result); } + + /** + * 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 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/LPC4078/HAL_SPI.cpp b/Marlin/src/HAL/LPC4078/HAL_SPI.cpp new file mode 100644 index 0000000000..3af5677fbc --- /dev/null +++ b/Marlin/src/HAL/LPC4078/HAL_SPI.cpp @@ -0,0 +1,404 @@ +// /** +// * 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 SPI functions originally from Arduino Sd2Card Library +// * Copyright (c) 2009 by William Greiman +// */ + +// /** +// * For TARGET_LPC4078 +// */ + +// /** +// * Hardware SPI and Software SPI implementations are included in this file. +// * The hardware SPI runs faster and has higher throughput but is not compatible +// * with some LCD interfaces/adapters. +// * +// * Control of the slave select pin(s) is handled by the calling routines. +// * +// * Some of the LCD interfaces/adapters result in the LCD SPI and the SD card +// * SPI sharing pins. The SCK, MOSI & MISO pins can NOT be set/cleared with +// * WRITE nor digitalWrite when the hardware SPI module within the LPC17xx is +// * active. If any of these pins are shared then the software SPI must be used. +// * +// * A more sophisticated hardware SPI can be found at the following link. +// * This implementation has not been fully debugged. +// * https://github.com/MarlinFirmware/Marlin/tree/071c7a78f27078fd4aee9a3ef365fcf5e143531e +// */ + +#ifdef TARGET_LPC4078 + +#include "../../inc/MarlinConfig.h" +#include + +// Hardware SPI and SPIClass + +#include "../shared/HAL_SPI.h" + +#define LPC_SOFTWARE_SPI + +// ------------------------ +// Public functions +// ------------------------ +#if ENABLED(LPC_SOFTWARE_SPI) + #include "SoftwareSPI.h" + + // Software SPI + static uint8_t SPI_speed = SPI_FULL_SPEED; + + static uint8_t spiTransfer(uint8_t b) { + return swSpiTransfer(b, SPI_speed, SD_SCK_PIN, SD_MISO_PIN, SD_MOSI_PIN); + } + + void spiBegin() { + swSpiBegin(SD_SCK_PIN, SD_MISO_PIN, SD_MOSI_PIN); + } + + void spiInit(uint8_t spiRate) { + SPI_speed = swSpiInit(spiRate, SD_SCK_PIN, SD_MOSI_PIN); + } + + uint8_t spiRec() { return spiTransfer(0xFF); } + + void spiRead(uint8_t*buf, uint16_t nbyte) { + for (int i = 0; i < nbyte; i++) + buf[i] = spiTransfer(0xFF); + } + + void spiSend(uint8_t b) { (void)spiTransfer(b); } + + void spiSend(const uint8_t *buf, size_t nbyte) { + for (uint16_t i = 0; i < nbyte; i++) + (void)spiTransfer(buf[i]); + } + + void spiSendBlock(uint8_t token, const uint8_t *buf) { + (void)spiTransfer(token); + for (uint16_t i = 0; i < 512; i++) + (void)spiTransfer(buf[i]); + } + +#else + + #ifdef SD_SPI_SPEED + #define INIT_SPI_SPEED SD_SPI_SPEED + #else + #define INIT_SPI_SPEED SPI_FULL_SPEED + #endif + + void spiBegin() { spiInit(INIT_SPI_SPEED); } // Set up SCK, MOSI & MISO pins for SSP0 + + void spiInit(uint8_t spiRate) { + #if SD_MISO_PIN == BOARD_SPI1_MISO_PIN + SPI.setModule(1); + #elif SD_MISO_PIN == BOARD_SPI2_MISO_PIN + SPI.setModule(2); + #endif + SPI.setDataSize(DATA_SIZE_8BIT); + SPI.setDataMode(SPI_MODE0); + + SPI.setClock(SPISettings::spiRate2Clock(spiRate)); + SPI.begin(); + } + + static uint8_t doio(uint8_t b) { + return SPI.transfer(b & 0x00FF) & 0x00FF; + } + + void spiSend(uint8_t b) { doio(b); } + + void spiSend(const uint8_t *buf, size_t nbyte) { + for (uint16_t i = 0; i < nbyte; i++) doio(buf[i]); + } + + void spiSend(uint32_t chan, byte b) {} + + void spiSend(uint32_t chan, const uint8_t *buf, size_t nbyte) {} + + // Read single byte from SPI + uint8_t spiRec() { return doio(0xFF); } + + uint8_t spiRec(uint32_t chan) { return 0; } + + // Read from SPI into buffer + void spiRead(uint8_t *buf, uint16_t nbyte) { + for (uint16_t i = 0; i < nbyte; i++) buf[i] = doio(0xFF); + } + + uint8_t spiTransfer(uint8_t b) { return doio(b); } + + // Write from buffer to SPI + void spiSendBlock(uint8_t token, const uint8_t *buf) { + (void)spiTransfer(token); + for (uint16_t i = 0; i < 512; i++) + (void)spiTransfer(buf[i]); + } + + // Begin SPI transaction, set clock, bit order, data mode + void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) { + // TODO: Implement this method + } + +#endif // LPC_SOFTWARE_SPI + +// /** +// * @brief Wait until TXE (tx empty) flag is set and BSY (busy) flag unset. +// */ +// static inline void waitSpiTxEnd(LPC_SSP_TypeDef *spi_d) { +// while (SSP_GetStatus(spi_d, SSP_STAT_TXFIFO_EMPTY) == RESET) { /* nada */ } // wait until TXE=1 +// while (SSP_GetStatus(spi_d, SSP_STAT_BUSY) == SET) { /* nada */ } // wait until BSY=0 +// } + +// // Retain the pin init state of the SPI, to avoid init more than once, +// // even if more instances of SPIClass exist +// static bool spiInitialised[BOARD_NR_SPI] = { false }; + +// SPIClass::SPIClass(uint8_t device) { +// // Init things specific to each SPI device +// // clock divider setup is a bit of hack, and needs to be improved at a later date. + +// #if BOARD_NR_SPI >= 1 +// _settings[0].spi_d = LPC_SSP0; +// _settings[0].dataMode = SPI_MODE0; +// _settings[0].dataSize = DATA_SIZE_8BIT; +// _settings[0].clock = SPI_CLOCK_MAX; +// //_settings[0].clockDivider = determine_baud_rate(_settings[0].spi_d, _settings[0].clock); +// #endif + +// #if BOARD_NR_SPI >= 2 +// _settings[1].spi_d = LPC_SSP1; +// _settings[1].dataMode = SPI_MODE0; +// _settings[1].dataSize = DATA_SIZE_8BIT; +// _settings[1].clock = SPI_CLOCK_MAX; +// //_settings[1].clockDivider = determine_baud_rate(_settings[1].spi_d, _settings[1].clock); +// #endif + +// setModule(device); + +// // Init the GPDMA controller +// // TODO: call once in the constructor? or each time? +// GPDMA_Init(); +// } + +// SPIClass::SPIClass(pin_t mosi, pin_t miso, pin_t sclk, pin_t ssel) { +// #if BOARD_NR_SPI >= 1 +// if (mosi == BOARD_SPI1_MOSI_PIN) SPIClass(1); +// #endif +// #if BOARD_NR_SPI >= 2 +// if (mosi == BOARD_SPI2_MOSI_PIN) SPIClass(2); +// #endif +// } + +// void SPIClass::begin() { +// // Init the SPI pins in the first begin call +// if ((_currentSetting->spi_d == LPC_SSP0 && spiInitialised[0] == false) || +// (_currentSetting->spi_d == LPC_SSP1 && spiInitialised[1] == false)) { +// pin_t sck, miso, mosi; +// if (_currentSetting->spi_d == LPC_SSP0) { +// sck = BOARD_SPI1_SCK_PIN; +// miso = BOARD_SPI1_MISO_PIN; +// mosi = BOARD_SPI1_MOSI_PIN; +// spiInitialised[0] = true; +// } +// else if (_currentSetting->spi_d == LPC_SSP1) { +// sck = BOARD_SPI2_SCK_PIN; +// miso = BOARD_SPI2_MISO_PIN; +// mosi = BOARD_SPI2_MOSI_PIN; +// spiInitialised[1] = true; +// } +// PINSEL_CFG_Type PinCfg; // data structure to hold init values +// PinCfg.Funcnum = 2; +// PinCfg.OpenDrain = 0; +// PinCfg.Pinmode = 0; +// PinCfg.Pinnum = LPC176x::pin_bit(sck); +// PinCfg.Portnum = LPC176x::pin_port(sck); +// PINSEL_ConfigPin(&PinCfg); +// SET_OUTPUT(sck); + +// PinCfg.Pinnum = LPC176x::pin_bit(miso); +// PinCfg.Portnum = LPC176x::pin_port(miso); +// PINSEL_ConfigPin(&PinCfg); +// SET_INPUT(miso); + +// PinCfg.Pinnum = LPC176x::pin_bit(mosi); +// PinCfg.Portnum = LPC176x::pin_port(mosi); +// PINSEL_ConfigPin(&PinCfg); +// SET_OUTPUT(mosi); +// } + +// updateSettings(); +// SSP_Cmd(_currentSetting->spi_d, ENABLE); // start SSP running +// } + +// void SPIClass::beginTransaction(const SPISettings &cfg) { +// setBitOrder(cfg.bitOrder); +// setDataMode(cfg.dataMode); +// setDataSize(cfg.dataSize); +// //setClockDivider(determine_baud_rate(_currentSetting->spi_d, settings.clock)); +// begin(); +// } + +// uint8_t SPIClass::transfer(const uint16_t b) { +// // Send and receive a single byte +// SSP_ReceiveData(_currentSetting->spi_d); // read any previous data +// SSP_SendData(_currentSetting->spi_d, b); +// waitSpiTxEnd(_currentSetting->spi_d); // wait for it to finish +// return SSP_ReceiveData(_currentSetting->spi_d); +// } + +// uint16_t SPIClass::transfer16(const uint16_t data) { +// return (transfer((data >> 8) & 0xFF) << 8) | (transfer(data & 0xFF) & 0xFF); +// } + +// void SPIClass::end() { +// // Neither is needed for Marlin +// //SSP_Cmd(_currentSetting->spi_d, DISABLE); +// //SSP_DeInit(_currentSetting->spi_d); +// } + +// void SPIClass::send(uint8_t data) { +// SSP_SendData(_currentSetting->spi_d, data); +// } + +// void SPIClass::dmaSend(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); + +// // Wait for data transfer +// while (!GPDMA_IntGetStatus(GPDMA_STAT_RAWINTTC, 0) && !GPDMA_IntGetStatus(GPDMA_STAT_RAWINTERR, 0)) { } + +// // Clear err and int +// GPDMA_ClearIntPending (GPDMA_STATCLR_INTTC, 0); +// GPDMA_ClearIntPending (GPDMA_STATCLR_INTERR, 0); + +// // Disable DMA +// GPDMA_ChannelCmd(0, DISABLE); + +// waitSpiTxEnd(_currentSetting->spi_d); + +// SSP_DMACmd(_currentSetting->spi_d, SSP_DMA_TX, DISABLE); +// } + +// uint16_t SPIClass::read() { +// return SSP_ReceiveData(_currentSetting->spi_d); +// } + +// void SPIClass::read(uint8_t *buf, uint32_t len) { +// for (uint16_t i = 0; i < len; i++) buf[i] = transfer(0xFF); +// } + +// void SPIClass::setClock(uint32_t clock) { _currentSetting->clock = clock; } + +// void SPIClass::setModule(uint8_t device) { _currentSetting = &_settings[device - 1]; } // SPI channels are called 1, 2, and 3 but the array is zero-indexed + +// void SPIClass::setBitOrder(uint8_t bitOrder) { _currentSetting->bitOrder = bitOrder; } + +// void SPIClass::setDataMode(uint8_t dataMode) { _currentSetting->dataMode = dataMode; } + +// void SPIClass::setDataSize(uint32_t dataSize) { _currentSetting->dataSize = dataSize; } + +// /** +// * Set up/tear down +// */ +// void SPIClass::updateSettings() { +// //SSP_DeInit(_currentSetting->spi_d); //todo: need force de init?! + +// // Divide PCLK by 2 for SSP0 +// //CLKPWR_SetPCLKDiv(_currentSetting->spi_d == LPC_SSP0 ? CLKPWR_PCLKSEL_SSP0 : CLKPWR_PCLKSEL_SSP1, CLKPWR_PCLKSEL_CCLK_DIV_2); + +// SSP_CFG_Type HW_SPI_init; // data structure to hold init values +// SSP_ConfigStructInit(&HW_SPI_init); // set values for SPI mode +// HW_SPI_init.ClockRate = _currentSetting->clock; +// HW_SPI_init.Databit = _currentSetting->dataSize; + +// /** +// * SPI Mode CPOL CPHA Shift SCK-edge Capture SCK-edge +// * 0 0 0 Falling Rising +// * 1 0 1 Rising Falling +// * 2 1 0 Rising Falling +// * 3 1 1 Falling Rising +// */ +// switch (_currentSetting->dataMode) { +// case SPI_MODE0: +// HW_SPI_init.CPHA = SSP_CPHA_FIRST; +// HW_SPI_init.CPOL = SSP_CPOL_HI; +// break; +// case SPI_MODE1: +// HW_SPI_init.CPHA = SSP_CPHA_SECOND; +// HW_SPI_init.CPOL = SSP_CPOL_HI; +// break; +// case SPI_MODE2: +// HW_SPI_init.CPHA = SSP_CPHA_FIRST; +// HW_SPI_init.CPOL = SSP_CPOL_LO; +// break; +// case SPI_MODE3: +// HW_SPI_init.CPHA = SSP_CPHA_SECOND; +// HW_SPI_init.CPOL = SSP_CPOL_LO; +// break; +// default: +// break; +// } + +// // TODO: handle bitOrder +// SSP_Init(_currentSetting->spi_d, &HW_SPI_init); // puts the values into the proper bits in the SSP0 registers +// } + +// #if SD_MISO_PIN == BOARD_SPI1_MISO_PIN +// SPIClass SPI(1); +// #elif SD_MISO_PIN == BOARD_SPI2_MISO_PIN +// SPIClass SPI(2); +// #endif + +#endif // TARGET_LPC4078 diff --git a/Marlin/src/HAL/LPC4078/MarlinSPI.h b/Marlin/src/HAL/LPC4078/MarlinSPI.h new file mode 100644 index 0000000000..fab245f904 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/MarlinSPI.h @@ -0,0 +1,45 @@ +/** + * 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 + +/** + * Marlin currently requires 3 SPI classes: + * + * SPIClass: + * This class is normally provided by frameworks and has a semi-default interface. + * This is needed because some libraries reference it globally. + * + * SPISettings: + * Container for SPI configs for SPIClass. As above, libraries may reference it globally. + * + * These two classes are often provided by frameworks so we cannot extend them to add + * useful methods for Marlin. + * + * MarlinSPI: + * Provides the default SPIClass interface plus some Marlin goodies such as a simplified + * interface for SPI DMA transfer. + * + */ + +using MarlinSPI = SPIClass; diff --git a/Marlin/src/HAL/LPC4078/MarlinSerial.cpp b/Marlin/src/HAL/LPC4078/MarlinSerial.cpp new file mode 100644 index 0000000000..d18ceedf7e --- /dev/null +++ b/Marlin/src/HAL/LPC4078/MarlinSerial.cpp @@ -0,0 +1,78 @@ +/** + * 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_LPC4078 + +#include "MarlinSerial.h" + +#include "../../inc/MarlinConfig.h" + +MarlinCDCSerial MCDCSerial0; + +#define MarlinSerial(ID) \ + MarlinSerial _MSerial##ID(ID); \ + MSerialT MSerial##ID(true, _MSerial##ID) + +#if USING_HW_SERIAL0 + MarlinSerial(0); +#endif +#if USING_HW_SERIAL1 + MarlinSerial(1); +#endif +#if USING_HW_SERIAL2 + MarlinSerial(2); +#endif +#if USING_HW_SERIAL3 + MarlinSerial(3); +#endif + +#if ENABLED(EMERGENCY_PARSER) + + bool MarlinSerial::recv_callback(const char c) { + // Need to figure out which serial port we are and react in consequence (Marlin does not have CONTAINER_OF macro) + if (false) {} + #if USING_HW_SERIAL0 + else if (this == &_MSerial0) emergency_parser.update(MSerial0.emergency_state, c); + #endif + #if USING_HW_SERIAL1 + else if (this == &_MSerial1) emergency_parser.update(MSerial1.emergency_state, c); + #endif + #if USING_HW_SERIAL2 + else if (this == &_MSerial2) emergency_parser.update(MSerial2.emergency_state, c); + #endif + #if USING_HW_SERIAL3 + else if (this == &_MSerial3) emergency_parser.update(MSerial3.emergency_state, c); + #endif + return true; + } + + #include "../../feature/e_parser.h" + + EmergencyParser::State emergency_state; + + bool CDC_RecvCallback(const char c) { + emergency_parser.update(emergency_state, c); + return true; + } + +#endif + +#endif // TARGET_LPC4078 diff --git a/Marlin/src/HAL/LPC4078/MarlinSerial.h b/Marlin/src/HAL/LPC4078/MarlinSerial.h new file mode 100644 index 0000000000..60869e76c9 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/MarlinSerial.h @@ -0,0 +1,108 @@ +/** + * 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 +#include +#include + +#include + +#include "../../inc/MarlinConfigPre.h" +#if ENABLED(EMERGENCY_PARSER) + #include "../../feature/e_parser.h" +#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 MarlinCDCSerial : public HardwareSerial { + public: + MarlinCDCSerial() {} + void begin(unsigned long baudrate) override {} + void begin(unsigned long baudrate, uint16_t config) override { } + void end() override { } + int available() override { + return MCUI::CDCSerial0::available(); + } + int peek() override { char c = 0; return MCUI::CDCSerial0::peek((uint8_t*)&c)? c : -1; } + int read() override { char c = 0; return MCUI::CDCSerial0::read((uint8_t*)&c, 1)? c : -1; } + void flush() override {}; + size_t write(uint8_t c) override { return write(&c, 1); } + size_t write(const uint8_t *buffer, size_t size) override { return MCUI::CDCSerial0::connected() ? MCUI::CDCSerial0::write(buffer, size) : 0; } + using Print::write; + operator bool() override { return true; } +}; +extern MarlinCDCSerial MCDCSerial0; + +class MarlinSerial : public HardwareSerial { + public: + MarlinSerial(const uint32_t uart_id) : uart_device(uart_id) {} + void begin(unsigned long baudrate) override { + uart_device.configure_pins(P0_02, P0_03); + uart_device.init({ .baud = baudrate }); + #if ENABLED(EMERGENCY_PARSER) + uart_device.set_rx_callback([this](char rx_value){ return this->recv_callback(rx_value); } ); + #endif + } + void begin(unsigned long baudrate, uint16_t config) override { + begin(baudrate); + } + void end() override { } + int available() override { + return uart_device.rx_available(); + } + int peek() override { char c = 0; return uart_device.peek(&c)? c : -1; } + int read() override { char c = 0; return uart_device.read(&c)? c : -1; } + void flush() override {}; + size_t write(uint8_t c) override { return write(&c, 1); } + size_t write(const uint8_t *buffer, size_t size) override { return uart_device.write((const char *)buffer, size); } + using Print::write; // pull in write(str) and write(buf, size) from Print + operator bool() override { return true; } + + bool recv_callback(char value); + private: + MCUI::BufferedUARTC uart_device; +}; + +// On LPC176x framework, HardwareSerial does not implement the same interface as Arduino's Serial, so overloads +// of 'available' and 'read' method are not used in this multiple inheritance scenario. +// Instead, use a ForwardSerial here that adapts the interface. +typedef ForwardSerial1Class MSerialT; +extern MSerialT MSerial0; +extern MSerialT MSerial1; +extern MSerialT MSerial2; +extern MSerialT MSerial3; + +// Consequently, we can't use a RuntimeSerial either. The workaround would be to use +// a RuntimeSerial> type here. Ignore for now until it's actually required. +#if ENABLED(SERIAL_RUNTIME_HOOK) + #error "SERIAL_RUNTIME_HOOK is not yet supported for LPC176x." +#endif diff --git a/Marlin/src/HAL/LPC4078/MinSerial.cpp b/Marlin/src/HAL/LPC4078/MinSerial.cpp new file mode 100644 index 0000000000..809a06b85d --- /dev/null +++ b/Marlin/src/HAL/LPC4078/MinSerial.cpp @@ -0,0 +1,51 @@ +/** + * 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 TARGET_LPC4078 + +#include "../../inc/MarlinConfig.h" +#include "HAL.h" + +#if ENABLED(POSTMORTEM_DEBUGGING) + +#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" + ); + } + 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 +#endif // TARGET_LPC4078 diff --git a/Marlin/src/HAL/LPC4078/Servo.h b/Marlin/src/HAL/LPC4078/Servo.h new file mode 100644 index 0000000000..f02f503a67 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/Servo.h @@ -0,0 +1,69 @@ +/** + * 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 + +/** + * servo.h - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2 + * Copyright (c) 2009 Michael Margolis. All right reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 - + * Version 2 Copyright (c) 2009 Michael Margolis. All right reserved. + * + * The only modification was to update/delete macros to match the LPC176x. + */ + +#include + +class libServo: public Servo { + public: + void move(const int value) { + constexpr uint16_t servo_delay[] = SERVO_DELAY; + static_assert(COUNT(servo_delay) == NUM_SERVOS, "SERVO_DELAY must be an array NUM_SERVOS long."); + + if (attach(servo_info[servoIndex].Pin.nbr) >= 0) { // try to reattach + write(value); + safe_delay(servo_delay[servoIndex]); // delay to allow servo to reach position + TERN_(DEACTIVATE_SERVOS_AFTER_MOVE, detach()); + } + + } +}; + +class libServo; +typedef libServo hal_servo_t; diff --git a/Marlin/src/HAL/LPC4078/SoftwareSPI.cpp b/Marlin/src/HAL/LPC4078/SoftwareSPI.cpp new file mode 100644 index 0000000000..156f0acc20 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/SoftwareSPI.cpp @@ -0,0 +1,47 @@ +#ifdef TARGET_LPC4078 + +#include +#include "SoftwareSPI.h" + +#include + +uint8_t swSpiTransfer(uint8_t b, const uint8_t spi_speed, const pin_t sck_pin, const pin_t miso_pin, const pin_t mosi_pin) { + for (uint8_t i = 0; i < 8; i++) { + if (spi_speed == 0) { + MCUI::gpio_set(mosi_pin, !!(b & 0x80)); + MCUI::gpio_set(sck_pin, HIGH); + b <<= 1; + if (miso_pin >= 0 && MCUI::gpio_get(miso_pin)) b |= 1; + MCUI::gpio_set(sck_pin, LOW); + } + else { + const uint8_t state = (b & 0x80) ? HIGH : LOW; + for (uint8_t j = 0; j < spi_speed; j++) + MCUI::gpio_set(mosi_pin, state); + + for (uint8_t j = 0; j < spi_speed + (miso_pin >= 0 ? 0 : 1); j++) + MCUI::gpio_set(sck_pin, HIGH); + + b <<= 1; + if (miso_pin >= 0 && MCUI::gpio_get(miso_pin)) b |= 1; + + for (uint8_t j = 0; j < spi_speed; j++) + MCUI::gpio_set(sck_pin, LOW); + } + } + return b; +} + +void swSpiBegin(const pin_t sck_pin, const pin_t miso_pin, const pin_t mosi_pin) { + pinMode(sck_pin, OUTPUT); + if (MCUI::pin_is_valid(miso_pin)) pinMode(miso_pin, INPUT); + pinMode(mosi_pin, OUTPUT); +} + +uint8_t swSpiInit(const uint8_t spiRate, const pin_t sck_pin, const pin_t mosi_pin) { + MCUI::gpio_set(mosi_pin, HIGH); + MCUI::gpio_set(sck_pin, LOW); + return (SystemCoreClock == 120000000 ? 44 : 38) / std::pow(2, 6 - std::min(spiRate, (uint8_t)6)); +} + +#endif // TARGET_LPC4078 diff --git a/Marlin/src/HAL/LPC4078/SoftwareSPI.h b/Marlin/src/HAL/LPC4078/SoftwareSPI.h new file mode 100644 index 0000000000..7b4fe79b44 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/SoftwareSPI.h @@ -0,0 +1,5 @@ +#include + +uint8_t swSpiTransfer(uint8_t b, const uint8_t spi_speed, const pin_t sck_pin, const pin_t miso_pin, const pin_t mosi_pin); +void swSpiBegin(const pin_t sck_pin, const pin_t miso_pin, const pin_t mosi_pin); +uint8_t swSpiInit(const uint8_t spiRate, const pin_t sck_pin, const pin_t mosi_pin); diff --git a/Marlin/src/HAL/LPC4078/eeprom_internal.cpp b/Marlin/src/HAL/LPC4078/eeprom_internal.cpp new file mode 100644 index 0000000000..69e2e15592 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/eeprom_internal.cpp @@ -0,0 +1,116 @@ +/** + * 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_LPC4078 + +/** + * Emulate EEPROM storage using Flash Memory + * + * Use a single 32K flash sector to store EEPROM data. To reduce the + * number of erase operations a simple "leveling" scheme is used that + * maintains a number of EEPROM "slots" within the larger flash sector. + * Each slot is used in turn and the entire sector is only erased when all + * slots have been used. + * + * A simple RAM image is used to hold the EEPROM data during I/O operations + * and this is flushed to the next available slot when an update is complete. + * If RAM usage becomes an issue we could store this image in one of the two + * 16Kb I/O buffers (intended to hold DMA USB and Ethernet data, but currently + * unused). + */ +#include "../../inc/MarlinConfig.h" + +#include "../shared/eeprom_api.h" + +//#include + +#ifndef MARLIN_EEPROM_SIZE + #define MARLIN_EEPROM_SIZE 4032 // 4KB +#endif + +size_t PersistentStore::capacity() { return 4032; } + +constexpr uint32_t page_size = MCUI::EEPROM::page_size; +uint32_t buffered_page = 0; +uint8_t page_buffer[page_size]; +bool buffered_page_dirty = false; + +bool PersistentStore::access_start() { + MCUI::EEPROM::init(); + MCUI::EEPROM::read_page(buffered_page, page_buffer, page_size); + return true; +} + +bool PersistentStore::access_finish() { + if (buffered_page_dirty) { + MCUI::EEPROM::write_page(buffered_page, page_buffer, page_size); + } + return true; +} + +bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) { + uint32_t address = pos; + //printf("Marlin::eeprom::write(pos = %d, size = %d)\n", pos, size); + uint32_t value_index = 0; + for (uint32_t addr = address; addr < address + size; ++addr) { + uint32_t page_address = addr & 0xFFFFFFC0; + if (page_address != buffered_page) { + //printf("Marlin::eeprom::write(@%ld):: page change new(%ld) != current(%d)\n",addr, page_address, buffered_page); + if (buffered_page_dirty == true) MCUI::EEPROM::write_page(buffered_page, page_buffer, page_size); + buffered_page = page_address; + buffered_page_dirty = false; + MCUI::EEPROM::read_page(buffered_page, page_buffer, page_size); + } + page_buffer[addr & ~0xFFFFFFC0] = value[value_index++]; + buffered_page_dirty = true; + } + + pos += size; + crc16(crc, value, size); + + return false; // return true for any error +} + +bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) { + uint32_t address = pos; + //printf("Marlin::eeprom::read(pos = %d, size = %d, writing = %d)\n", pos, size, writing); + uint32_t value_index = 0; + for (uint32_t addr = address; addr < address + size; ++addr) { + uint32_t page_address = addr & 0xFFFFFFC0; + if (page_address != buffered_page) { + if (buffered_page_dirty) { + MCUI::EEPROM::write_page(buffered_page, page_buffer, page_size); + buffered_page_dirty = false; + } + buffered_page = page_address; + MCUI::EEPROM::read_page(buffered_page, page_buffer, page_size); + } + if (writing) value[value_index++] = page_buffer[addr & ~0xFFFFFFC0]; + else crc16(crc, &page_buffer[addr & ~0xFFFFFFC0], 1); + } + + if (writing) crc16(crc, value, size); + pos += size; + + return false; // return true for any error +} + +#endif // TARGET_LPC4078 diff --git a/Marlin/src/HAL/LPC4078/endstop_interrupts.h b/Marlin/src/HAL/LPC4078/endstop_interrupts.h new file mode 100644 index 0000000000..e4ac17f608 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/endstop_interrupts.h @@ -0,0 +1,191 @@ +/** + * 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 + +/** + * 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" + +// One ISR for all EXT-Interrupts +void endstop_ISR() { endstops.update(); } + +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 !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 !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 !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 !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 !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 !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 !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 !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 !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 !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 !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 !LPC1768_PIN_INTERRUPT_M(Z4_MIN_PIN) + #error "Z4_MIN_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Z4_MIN_PIN); + #endif + #if HAS_Z_MIN_PROBE_PIN + #if !LPC1768_PIN_INTERRUPT_M(Z_MIN_PROBE_PIN) + #error "Z_MIN_PROBE_PIN is not INTERRUPT-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue." + #endif + _ATTACH(Z_MIN_PROBE_PIN); + #endif + #if HAS_I_MAX + #if !LPC1768_PIN_INTERRUPT_M(I_MAX_PIN) + #error "I_MAX_PIN is not INTERRUPT-capable." + #endif + _ATTACH(I_MAX_PIN); + #elif HAS_I_MIN + #if !LPC1768_PIN_INTERRUPT_M(I_MIN_PIN) + #error "I_MIN_PIN is not INTERRUPT-capable." + #endif + _ATTACH(I_MIN_PIN); + #endif + #if HAS_J_MAX + #if !LPC1768_PIN_INTERRUPT_M(J_MAX_PIN) + #error "J_MAX_PIN is not INTERRUPT-capable." + #endif + _ATTACH(J_MAX_PIN); + #elif HAS_J_MIN + #if !LPC1768_PIN_INTERRUPT_M(J_MIN_PIN) + #error "J_MIN_PIN is not INTERRUPT-capable." + #endif + _ATTACH(J_MIN_PIN); + #endif + #if HAS_K_MAX + #if !LPC1768_PIN_INTERRUPT_M(K_MAX_PIN) + #error "K_MAX_PIN is not INTERRUPT-capable." + #endif + _ATTACH(K_MAX_PIN); + #elif HAS_K_MIN + #if !LPC1768_PIN_INTERRUPT_M(K_MIN_PIN) + #error "K_MIN_PIN is not INTERRUPT-capable." + #endif + _ATTACH(K_MIN_PIN); + #endif + #if HAS_U_MAX + #if !LPC1768_PIN_INTERRUPT_M(U_MAX_PIN) + #error "U_MAX_PIN is not INTERRUPT-capable." + #endif + _ATTACH(U_MAX_PIN); + #elif HAS_U_MIN + #if !LPC1768_PIN_INTERRUPT_M(U_MIN_PIN) + #error "U_MIN_PIN is not INTERRUPT-capable." + #endif + _ATTACH(U_MIN_PIN); + #endif + #if HAS_V_MAX + #if !LPC1768_PIN_INTERRUPT_M(V_MAX_PIN) + #error "V_MAX_PIN is not INTERRUPT-capable." + #endif + _ATTACH(V_MAX_PIN); + #elif HAS_V_MIN + #if !LPC1768_PIN_INTERRUPT_M(V_MIN_PIN) + #error "V_MIN_PIN is not INTERRUPT-capable." + #endif + _ATTACH(V_MIN_PIN); + #endif + #if HAS_W_MAX + #if !LPC1768_PIN_INTERRUPT_M(W_MAX_PIN) + #error "W_MAX_PIN is not INTERRUPT-capable." + #endif + _ATTACH(W_MAX_PIN); + #elif HAS_W_MIN + #if !LPC1768_PIN_INTERRUPT_M(W_MIN_PIN) + #error "W_MIN_PIN is not INTERRUPT-capable." + #endif + _ATTACH(W_MIN_PIN); + #endif +} diff --git a/Marlin/src/HAL/LPC4078/fast_pwm.cpp b/Marlin/src/HAL/LPC4078/fast_pwm.cpp new file mode 100644 index 0000000000..d202a49d28 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/fast_pwm.cpp @@ -0,0 +1,37 @@ +/** + * 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_LPC4078 + +#include "../../inc/MarlinConfig.h" +#include + +void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) { + if (!MCUI::pin_is_valid(pin)) return; + if (MCUI::pwm_attach_pin(pin)) + MCUI::pwm_write_ratio(pin, invert ? 1.0f - (float)v / v_size : (float)v / v_size); // map 1-254 onto PWM range +} + +void MarlinHAL::set_pwm_frequency(const pin_t pin, const uint16_t f_desired) { + MCUI::pwm_set_frequency(pin, f_desired); +} + +#endif // TARGET_LPC4078 diff --git a/Marlin/src/HAL/LPC4078/fastio.h b/Marlin/src/HAL/LPC4078/fastio.h new file mode 100644 index 0000000000..9e384d6cf6 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/fastio.h @@ -0,0 +1,120 @@ +/** + * 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 + +/** + * Fast I/O Routines for LPC1768/9 + * Use direct port manipulation to save scads of processor time. + * Contributed by Triffid_Hunter and modified by Kliment, thinkyhead, Bob-the-Kuhn, et.al. + */ + +/** + * Description: Fast IO functions LPC1768 + * + * For TARGET LPC1768 + */ + +#include "../shared/Marduino.h" +#include + +#define PWM_PIN(P) true // all pins are software PWM capable + +#define LPC_PIN(pin) MCUI::gpio_pin(pin) +#define LPC_GPIO(port) MCUI::gpio_port(port) + +#define SET_DIR_INPUT(IO) MCUI::gpio_set_input(IO) +#define SET_DIR_OUTPUT(IO) MCUI::gpio_set_output(IO) + +#define SET_MODE(IO, mode) pinMode(IO, mode) + +#define WRITE_PIN_SET(IO) MCUI::gpio_set(IO) +#define WRITE_PIN_CLR(IO) MCUI::gpio_clear(IO) + +#define READ_PIN(IO) MCUI::gpio_get(IO) +#define WRITE_PIN(IO,V) MCUI::gpio_set(IO, V) + +/** + * Magic I/O routines + * + * Now you can simply SET_OUTPUT(STEP); WRITE(STEP, HIGH); WRITE(STEP, LOW); + * + * Why double up on these macros? see https://gcc.gnu.org/onlinedocs/gcc-4.8.5/cpp/Stringification.html + */ + +/// Read a pin +#define _READ(IO) READ_PIN(IO) + +/// Write to a pin +#define _WRITE(IO,V) WRITE_PIN(IO,V) + +/// toggle a pin +#define _TOGGLE(IO) MCUI::gpio_toggle(IO) + +/// set pin as input +#define _SET_INPUT(IO) SET_DIR_INPUT(IO) + +/// set pin as output +#define _SET_OUTPUT(IO) SET_DIR_OUTPUT(IO) + +/// set pin as input with pullup mode +#define _PULLUP(IO,V) pinMode(IO, (V) ? INPUT_PULLUP : INPUT) + +/// set pin as input with pulldown mode +#define _PULLDOWN(IO,V) pinMode(IO, (V) ? INPUT_PULLDOWN : INPUT) + +/// check if pin is an input +#define _IS_INPUT(IO) (!MCUI::gpio_get_dir(IO)) + +/// check if pin is an output +#define _IS_OUTPUT(IO) (MCUI::gpio_get_dir(IO)) + +/// Read a pin wrapper +#define READ(IO) _READ(IO) + +/// Write to a pin wrapper +#define WRITE(IO,V) _WRITE(IO,V) + +/// toggle a pin wrapper +#define TOGGLE(IO) _TOGGLE(IO) + +/// set pin as input wrapper +#define SET_INPUT(IO) _SET_INPUT(IO) +/// set pin as input with pullup wrapper +#define SET_INPUT_PULLUP(IO) do{ _SET_INPUT(IO); _PULLUP(IO, HIGH); }while(0) +/// set pin as input with pulldown wrapper +#define SET_INPUT_PULLDOWN(IO) do{ _SET_INPUT(IO); _PULLDOWN(IO, HIGH); }while(0) +/// set pin as output wrapper - reads the pin and sets the output to that value +#define SET_OUTPUT(IO) do{ _WRITE(IO, _READ(IO)); _SET_OUTPUT(IO); }while(0) +// set pin as PWM +#define SET_PWM SET_OUTPUT + +/// check if pin is an input wrapper +#define IS_INPUT(IO) _IS_INPUT(IO) +/// check if pin is an output wrapper +#define IS_OUTPUT(IO) _IS_OUTPUT(IO) + +// Shorthand +#define OUT_WRITE(IO,V) do{ SET_OUTPUT(IO); WRITE(IO,V); }while(0) + +// digitalRead/Write wrappers +#define extDigitalRead(IO) digitalRead(IO) +#define extDigitalWrite(IO,V) digitalWrite(IO,V) diff --git a/Marlin/src/HAL/LPC4078/inc/Conditionals_LCD.h b/Marlin/src/HAL/LPC4078/inc/Conditionals_LCD.h new file mode 100644 index 0000000000..5f1c4b1601 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/inc/Conditionals_LCD.h @@ -0,0 +1,22 @@ +/** + * 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 diff --git a/Marlin/src/HAL/LPC4078/inc/Conditionals_adv.h b/Marlin/src/HAL/LPC4078/inc/Conditionals_adv.h new file mode 100644 index 0000000000..8e7cab185f --- /dev/null +++ b/Marlin/src/HAL/LPC4078/inc/Conditionals_adv.h @@ -0,0 +1,26 @@ +/** + * 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 + +#if DISABLED(NO_SD_HOST_DRIVE) + #define HAS_SD_HOST_DRIVE 1 +#endif diff --git a/Marlin/src/HAL/LPC4078/inc/Conditionals_post.h b/Marlin/src/HAL/LPC4078/inc/Conditionals_post.h new file mode 100644 index 0000000000..865b71be7d --- /dev/null +++ b/Marlin/src/HAL/LPC4078/inc/Conditionals_post.h @@ -0,0 +1,34 @@ +/** + * 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 + +#if USE_FALLBACK_EEPROM + #define FLASH_EEPROM_EMULATION +#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) && ENABLED(FLASH_EEPROM_EMULATION) && PRINTCOUNTER_SAVE_INTERVAL > 0 + #define PRINTCOUNTER_SYNC 1 +#endif diff --git a/Marlin/src/HAL/LPC4078/inc/SanityCheck.h b/Marlin/src/HAL/LPC4078/inc/SanityCheck.h new file mode 100644 index 0000000000..f2f75e5854 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/inc/SanityCheck.h @@ -0,0 +1,276 @@ +/** + * 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 + +// #if PIO_PLATFORM_VERSION < 1001 +// #error "nxplpc-arduino-lpc176x package is out of date, Please update the PlatformIO platforms, frameworks and libraries. You may need to remove the platform and let it reinstall automatically." +// #endif +// #if PIO_FRAMEWORK_VERSION < 2006 +// #error "framework-arduino-lpc176x package is out of date, Please update the PlatformIO platforms, frameworks and libraries." +// #endif + +/** + * Detect an old pins file by checking for old ADC pins values. + */ +#define _OLD_TEMP_PIN(P) PIN_EXISTS(P) && _CAT(P,_PIN) <= 7 && !WITHIN(_CAT(P,_PIN), TERN(LPC1768_IS_SKRV1_3, 0, 2), 3) // Include P0_00 and P0_01 for SKR V1.3 board +#if _OLD_TEMP_PIN(TEMP_BED) + #error "TEMP_BED_PIN must be defined using the Pn_nn or Pn_nn_An format. (See the included pins files)." +#elif _OLD_TEMP_PIN(TEMP_0) + #error "TEMP_0_PIN must be defined using the Pn_nn or Pn_nn_An format. (See the included pins files)." +#elif _OLD_TEMP_PIN(TEMP_1) + #error "TEMP_1_PIN must be defined using the Pn_nn or Pn_nn_An format. (See the included pins files)." +#elif _OLD_TEMP_PIN(TEMP_2) + #error "TEMP_2_PIN must be defined using the Pn_nn or Pn_nn_An format. (See the included pins files)." +#elif _OLD_TEMP_PIN(TEMP_3) + #error "TEMP_3_PIN must be defined using the Pn_nn or Pn_nn_An format. (See the included pins files)." +#elif _OLD_TEMP_PIN(TEMP_4) + #error "TEMP_4_PIN must be defined using the Pn_nn or Pn_nn_An format. (See the included pins files)." +#elif _OLD_TEMP_PIN(TEMP_5) + #error "TEMP_5_PIN must be defined using the Pn_nn or Pn_nn_An format. (See the included pins files)." +#elif _OLD_TEMP_PIN(TEMP_6) + #error "TEMP_6_PIN must be defined using the Pn_nn or Pn_nn_An format. (See the included pins files)." +#elif _OLD_TEMP_PIN(TEMP_7) + #error "TEMP_7_PIN must be defined using the Pn_nn or Pn_nn_An format. (See the included pins files)." +#endif +#undef _OLD_TEMP_PIN + +/** + * Because PWM hardware channels all share the same frequency, along with the + * fallback software channels, FAST_PWM_FAN is incompatible with Servos. + */ +static_assert(!(NUM_SERVOS && ENABLED(FAST_PWM_FAN)), "BLTOUCH and Servos are incompatible with FAST_PWM_FAN on LPC176x boards."); + +#if SPINDLE_LASER_FREQUENCY + static_assert(!NUM_SERVOS, "BLTOUCH and Servos are incompatible with SPINDLE_LASER_FREQUENCY on LPC176x boards."); +#endif + +/** + * Test LPC176x-specific configuration values for errors at compile-time. + */ + +//#if ENABLED(SPINDLE_LASER_USE_PWM) && !(SPINDLE_LASER_PWM_PIN == 4 || SPINDLE_LASER_PWM_PIN == 6 || SPINDLE_LASER_PWM_PIN == 11) +// #error "SPINDLE_LASER_PWM_PIN must use SERVO0, SERVO1 or SERVO3 connector" +//#endif + +#if MB(RAMPS_14_RE_ARM_EFB, RAMPS_14_RE_ARM_EEB, RAMPS_14_RE_ARM_EFF, RAMPS_14_RE_ARM_EEF, RAMPS_14_RE_ARM_SF) + #if IS_RRD_FG_SC && HAS_DRIVER(TMC2130) && DISABLED(TMC_USE_SW_SPI) + #error "Re-ARM with REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER and TMC2130 requires TMC_USE_SW_SPI." + #endif +#endif + +static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported on LPC176x."); + +/** + * Flag any serial port conflicts + * + * Port | TX | RX | + * --- | --- | --- | + * Serial | P0_02 | P0_03 | + * Serial1 | P0_15 | P0_16 | + * Serial2 | P0_10 | P0_11 | + * Serial3 | P0_00 | P0_01 | + */ +#define ANY_TX(N,V...) DO(IS_TX##N,||,V) +#define ANY_RX(N,V...) DO(IS_RX##N,||,V) + +#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) + #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!" + #elif (AXIS_HAS_SPI(X) && IS_TX0(X_CS_PIN)) || (AXIS_HAS_SPI(Y) && IS_RX0(Y_CS_PIN)) + #error "Serial port pins (0) conflict with X/Y axis SPI pins!" + #endif + #undef IS_TX0 + #undef IS_RX0 +#endif + +#if USING_HW_SERIAL1 + #define IS_TX1(P) (P == P0_15) + #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) + #error "Serial port pins (1) conflict with other pins!" + #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) \ + || ANY_RX(1, LCD_SDSS, LCD_PINS_RS, SD_MISO_PIN, DOGLCD_A0, SD_SS_PIN, LCD_SDSS, DOGLCD_CS, LCD_RESET_PIN, LCD_BACKLIGHT_PIN) + #error "Serial port pins (1) conflict with LCD pins!" + #endif + #endif + #undef IS_TX1 + #undef IS_RX1 + #undef _IS_TX1_1 + #undef _IS_RX1_1 +#endif + +#if USING_HW_SERIAL2 + #define IS_TX2(P) (P == P0_10) + #define IS_RX2(P) (P == P0_11) + #define _IS_TX2_1 IS_TX2 + #define _IS_RX2_1 IS_RX2 + #if IS_TX2(X2_ENABLE_PIN) || ANY_RX(2, X2_DIR_PIN, X2_STEP_PIN) || (AXIS_HAS_SPI(X2) && IS_TX2(X2_CS_PIN)) + #error "Serial port pins (2) conflict with X2 pins!" + #elif IS_TX2(Y2_ENABLE_PIN) || ANY_RX(2, Y2_DIR_PIN, Y2_STEP_PIN) || (AXIS_HAS_SPI(Y2) && IS_TX2(Y2_CS_PIN)) + #error "Serial port pins (2) conflict with Y2 pins!" + #elif IS_TX2(Z2_ENABLE_PIN) || ANY_RX(2, Z2_DIR_PIN, Z2_STEP_PIN) || (AXIS_HAS_SPI(Z2) && IS_TX2(Z2_CS_PIN)) + #error "Serial port pins (2) conflict with Z2 pins!" + #elif IS_TX2(Z3_ENABLE_PIN) || ANY_RX(2, Z3_DIR_PIN, Z3_STEP_PIN) || (AXIS_HAS_SPI(Z3) && IS_TX2(Z3_CS_PIN)) + #error "Serial port pins (2) conflict with Z3 pins!" + #elif IS_TX2(Z4_ENABLE_PIN) || ANY_RX(2, Z4_DIR_PIN, Z4_STEP_PIN) || (AXIS_HAS_SPI(Z4) && IS_TX2(Z4_CS_PIN)) + #error "Serial port pins (2) conflict with Z4 pins!" + #elif ANY_RX(2, X_DIR_PIN, Y_DIR_PIN) + #error "Serial port pins (2) conflict with other pins!" + #elif Y_HOME_TO_MIN && IS_TX2(Y_STOP_PIN) + #error "Serial port pins (2) conflict with Y endstop pin!" + #elif USES_Z_MIN_PROBE_PIN && IS_TX2(Z_MIN_PROBE_PIN) + #error "Serial port pins (2) conflict with probe pin!" + #elif ANY_TX(2, X_ENABLE_PIN, Y_ENABLE_PIN) || ANY_RX(2, X_DIR_PIN, Y_DIR_PIN) + #error "Serial port pins (2) conflict with X/Y stepper pins!" + #elif HAS_MULTI_EXTRUDER && (IS_TX2(E1_ENABLE_PIN) || (AXIS_HAS_SPI(E1) && IS_TX2(E1_CS_PIN))) + #error "Serial port pins (2) conflict with E1 stepper pins!" + #elif EXTRUDERS && ANY_RX(2, E0_DIR_PIN, E0_STEP_PIN) + #error "Serial port pins (2) conflict with E stepper pins!" + #endif + #undef IS_TX2 + #undef IS_RX2 + #undef _IS_TX2_1 + #undef _IS_RX2_1 +#endif + +#if USING_HW_SERIAL3 + #define PIN_IS_TX3(P) (PIN_EXISTS(P) && P##_PIN == P0_00) + #define PIN_IS_RX3(P) (P##_PIN == P0_01) + #if PIN_IS_TX3(X_MIN) || PIN_IS_RX3(X_MAX) + #error "Serial port pins (3) conflict with X endstop pins!" + #elif PIN_IS_TX3(Y_SERIAL_TX) || PIN_IS_TX3(Y_SERIAL_RX) || PIN_IS_RX3(X_SERIAL_TX) || PIN_IS_RX3(X_SERIAL_RX) + #error "Serial port pins (3) conflict with X/Y axis UART pins!" + #elif PIN_IS_TX3(X2_DIR) || PIN_IS_RX3(X2_STEP) + #error "Serial port pins (3) conflict with X2 pins!" + #elif PIN_IS_TX3(Y2_DIR) || PIN_IS_RX3(Y2_STEP) + #error "Serial port pins (3) conflict with Y2 pins!" + #elif PIN_IS_TX3(Z2_DIR) || PIN_IS_RX3(Z2_STEP) + #error "Serial port pins (3) conflict with Z2 pins!" + #elif PIN_IS_TX3(Z3_DIR) || PIN_IS_RX3(Z3_STEP) + #error "Serial port pins (3) conflict with Z3 pins!" + #elif PIN_IS_TX3(Z4_DIR) || PIN_IS_RX3(Z4_STEP) + #error "Serial port pins (3) conflict with Z4 pins!" + #elif HAS_MULTI_EXTRUDER && (PIN_IS_TX3(E1_DIR) || PIN_IS_RX3(E1_STEP)) + #error "Serial port pins (3) conflict with E1 pins!" + #endif + #undef PIN_IS_TX3 + #undef PIN_IS_RX3 +#endif + +#undef ANY_TX +#undef ANY_RX + +// +// Flag any i2c pin conflicts +// +#if ANY(HAS_MOTOR_CURRENT_I2C, HAS_MOTOR_CURRENT_DAC, EXPERIMENTAL_I2CBUS, I2C_POSITION_ENCODERS, PCA9632, I2C_EEPROM) + #define USEDI2CDEV_M 1 // /Wire.cpp + + #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) + #error "SDA0 overlaps with SD_DETECT_PIN!" + #elif PIN_IS_SDA0(E0_AUTO_FAN) + #error "SDA0 overlaps with E0_AUTO_FAN_PIN!" + #elif PIN_IS_SDA0(BEEPER) + #error "SDA0 overlaps with BEEPER_PIN!" + #elif IS_SCL0(BTN_ENC) + #error "SCL0 overlaps with Encoder Button!" + #elif IS_SCL0(SD_SS_PIN) + #error "SCL0 overlaps with SD_SS_PIN!" + #elif IS_SCL0(LCD_SDSS) + #error "SCL0 overlaps with LCD_SDSS!" + #endif + #undef PIN_IS_SDA0 + #undef IS_SCL0 + #elif USEDI2CDEV_M == 1 // P0_00 [D20] (SCA) ............ P0_01 [D21] (SCL) + #define PIN_IS_SDA1(P) (PIN_EXISTS(P) && P##_PIN == P0_00) + #define PIN_IS_SCL1(P) (P##_PIN == P0_01) + #if PIN_IS_SDA1(X_MIN) || PIN_IS_SCL1(X_MAX) + #error "One or more i2c (1) pins overlaps with X endstop pins! Disable i2c peripherals." + #elif PIN_IS_SDA1(X2_DIR) || PIN_IS_SCL1(X2_STEP) + #error "One or more i2c (1) pins overlaps with X2 pins! Disable i2c peripherals." + #elif PIN_IS_SDA1(Y2_DIR) || PIN_IS_SCL1(Y2_STEP) + #error "One or more i2c (1) pins overlaps with Y2 pins! Disable i2c peripherals." + #elif PIN_IS_SDA1(Z2_DIR) || PIN_IS_SCL1(Z2_STEP) + #error "One or more i2c (1) pins overlaps with Z2 pins! Disable i2c peripherals." + #elif PIN_IS_SDA1(Z3_DIR) || PIN_IS_SCL1(Z3_STEP) + #error "One or more i2c (1) pins overlaps with Z3 pins! Disable i2c peripherals." + #elif PIN_IS_SDA1(Z4_DIR) || PIN_IS_SCL1(Z4_STEP) + #error "One or more i2c (1) pins overlaps with Z4 pins! Disable i2c peripherals." + #elif HAS_MULTI_EXTRUDER && (PIN_IS_SDA1(E1_DIR) || PIN_IS_SCL1(E1_STEP)) + #error "One or more i2c (1) pins overlaps with E1 pins! Disable i2c peripherals." + #endif + #undef PIN_IS_SDA1 + #undef PIN_IS_SCL1 + #elif USEDI2CDEV_M == 2 // P0_10 [D38] (X_ENABLE_PIN) ... P0_11 [D55] (X_DIR_PIN) + #define PIN_IS_SDA2(P) (P##_PIN == P0_10) + #define PIN_IS_SCL2(P) (P##_PIN == P0_11) + #if PIN_IS_SDA2(Y_STOP) + #error "i2c SDA2 overlaps with Y endstop pin!" + #elif USES_Z_MIN_PROBE_PIN && PIN_IS_SDA2(Z_MIN_PROBE) + #error "i2c SDA2 overlaps with Z probe pin!" + #elif PIN_IS_SDA2(X_ENABLE) || PIN_IS_SDA2(Y_ENABLE) + #error "i2c SDA2 overlaps with X/Y ENABLE pin!" + #elif AXIS_HAS_SPI(X) && PIN_IS_SDA2(X_CS) + #error "i2c SDA2 overlaps with X CS pin!" + #elif PIN_IS_SDA2(X2_ENABLE) + #error "i2c SDA2 overlaps with X2 enable pin! Disable i2c peripherals." + #elif PIN_IS_SDA2(Y2_ENABLE) + #error "i2c SDA2 overlaps with Y2 enable pin! Disable i2c peripherals." + #elif PIN_IS_SDA2(Z2_ENABLE) + #error "i2c SDA2 overlaps with Z2 enable pin! Disable i2c peripherals." + #elif PIN_IS_SDA2(Z3_ENABLE) + #error "i2c SDA2 overlaps with Z3 enable pin! Disable i2c peripherals." + #elif PIN_IS_SDA2(Z4_ENABLE) + #error "i2c SDA2 overlaps with Z4 enable pin! Disable i2c peripherals." + #elif HAS_MULTI_EXTRUDER && PIN_IS_SDA2(E1_ENABLE) + #error "i2c SDA2 overlaps with E1 enable pin! Disable i2c peripherals." + #elif HAS_MULTI_EXTRUDER && AXIS_HAS_SPI(E1) && PIN_IS_SDA2(E1_CS) + #error "i2c SDA2 overlaps with E1 CS pin! Disable i2c peripherals." + #elif EXTRUDERS && (PIN_IS_SDA2(E0_STEP) || PIN_IS_SDA2(E0_DIR)) + #error "i2c SCL2 overlaps with E0 STEP/DIR pin! Disable i2c peripherals." + #elif PIN_IS_SDA2(X_DIR) || PIN_IS_SDA2(Y_DIR) + #error "One or more i2c pins overlaps with X/Y DIR pin! Disable i2c peripherals." + #endif + #undef PIN_IS_SDA2 + #undef PIN_IS_SCL2 + #endif + + #undef USEDI2CDEV_M +#endif + +#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + #error "SERIAL_STATS_MAX_RX_QUEUED is not supported on LPC176x." +#elif ENABLED(SERIAL_STATS_DROPPED_RX) + #error "SERIAL_STATS_DROPPED_RX is not supported on LPX176x." +#endif diff --git a/Marlin/src/HAL/LPC4078/include/SPI.h b/Marlin/src/HAL/LPC4078/include/SPI.h new file mode 100644 index 0000000000..02bfdf8398 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/include/SPI.h @@ -0,0 +1,197 @@ +/** + * 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 "../../shared/HAL_SPI.h" + +#include +// #include +// #include + +//#define MSBFIRST 1 + +#define SPI_MODE0 0 +#define SPI_MODE1 1 +#define SPI_MODE2 2 +#define SPI_MODE3 3 + +#define SSP_CR0_DSS(n) ((uint32_t)((n-1)&0xF)) +#define SSP_DATABIT_4 SSP_CR0_DSS(4) /*!< Databit number = 4 */ +#define SSP_DATABIT_5 SSP_CR0_DSS(5) /*!< Databit number = 5 */ +#define SSP_DATABIT_6 SSP_CR0_DSS(6) /*!< Databit number = 6 */ +#define SSP_DATABIT_7 SSP_CR0_DSS(7) /*!< Databit number = 7 */ +#define SSP_DATABIT_8 SSP_CR0_DSS(8) /*!< Databit number = 8 */ +#define SSP_DATABIT_9 SSP_CR0_DSS(9) /*!< Databit number = 9 */ +#define SSP_DATABIT_10 SSP_CR0_DSS(10) /*!< Databit number = 10 */ +#define SSP_DATABIT_11 SSP_CR0_DSS(11) /*!< Databit number = 11 */ +#define SSP_DATABIT_12 SSP_CR0_DSS(12) /*!< Databit number = 12 */ +#define SSP_DATABIT_13 SSP_CR0_DSS(13) /*!< Databit number = 13 */ +#define SSP_DATABIT_14 SSP_CR0_DSS(14) /*!< Databit number = 14 */ +#define SSP_DATABIT_15 SSP_CR0_DSS(15) /*!< Databit number = 15 */ +#define SSP_DATABIT_16 SSP_CR0_DSS(16) /*!< Databit number = 16 */ + +#define DATA_SIZE_8BIT SSP_DATABIT_8 +#define DATA_SIZE_16BIT SSP_DATABIT_16 + +#define SPI_CLOCK_MAX_TFT 30000000UL +#define SPI_CLOCK_DIV2 8333333 //(SCR: 2) desired: 8,000,000 actual: 8,333,333 +4.2% SPI_FULL_SPEED +#define SPI_CLOCK_DIV4 4166667 //(SCR: 5) desired: 4,000,000 actual: 4,166,667 +4.2% SPI_HALF_SPEED +#define SPI_CLOCK_DIV8 2083333 //(SCR: 11) desired: 2,000,000 actual: 2,083,333 +4.2% SPI_QUARTER_SPEED +#define SPI_CLOCK_DIV16 1000000 //(SCR: 24) desired: 1,000,000 actual: 1,000,000 SPI_EIGHTH_SPEED +#define SPI_CLOCK_DIV32 500000 //(SCR: 49) desired: 500,000 actual: 500,000 SPI_SPEED_5 +#define SPI_CLOCK_DIV64 250000 //(SCR: 99) desired: 250,000 actual: 250,000 SPI_SPEED_6 +#define SPI_CLOCK_DIV128 125000 //(SCR:199) desired: 125,000 actual: 125,000 Default from HAL.h + +#define SPI_CLOCK_MAX SPI_CLOCK_DIV2 + +#define BOARD_NR_SPI 2 + +//#define BOARD_SPI1_NSS_PIN PA4 ?! +#define BOARD_SPI1_SCK_PIN P0_15 +#define BOARD_SPI1_MISO_PIN P0_17 +#define BOARD_SPI1_MOSI_PIN P0_18 + +//#define BOARD_SPI2_NSS_PIN PB12 ?! +#define BOARD_SPI2_SCK_PIN P0_07 +#define BOARD_SPI2_MISO_PIN P0_08 +#define BOARD_SPI2_MOSI_PIN P0_09 + +class SPISettings { +public: + SPISettings(uint32_t spiRate, int inBitOrder, int inDataMode) { + init_AlwaysInline(spiRate2Clock(spiRate), inBitOrder, inDataMode, DATA_SIZE_8BIT); + } + SPISettings(uint32_t inClock, uint8_t inBitOrder, uint8_t inDataMode, uint32_t inDataSize) { + if (__builtin_constant_p(inClock)) + init_AlwaysInline(inClock, inBitOrder, inDataMode, inDataSize); + else + init_MightInline(inClock, inBitOrder, inDataMode, inDataSize); + } + SPISettings() { + init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT); + } + + //uint32_t spiRate() const { return spi_speed; } + + 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 + Marlin_speed[2] = 2083333; //(SCR: 11) desired: 2,000,000 actual: 2,083,333 +4.2% SPI_QUARTER_SPEED + Marlin_speed[3] = 1000000; //(SCR: 24) desired: 1,000,000 actual: 1,000,000 SPI_EIGHTH_SPEED + Marlin_speed[4] = 500000; //(SCR: 49) desired: 500,000 actual: 500,000 SPI_SPEED_5 + Marlin_speed[5] = 250000; //(SCR: 99) desired: 250,000 actual: 250,000 SPI_SPEED_6 + Marlin_speed[6] = 125000; //(SCR:199) desired: 125,000 actual: 125,000 Default from HAL.h + return Marlin_speed[spiRate > 6 ? 6 : spiRate]; + } + +private: + void init_MightInline(uint32_t inClock, uint8_t inBitOrder, uint8_t inDataMode, uint32_t inDataSize) { + init_AlwaysInline(inClock, inBitOrder, inDataMode, inDataSize); + } + void init_AlwaysInline(uint32_t inClock, uint8_t inBitOrder, uint8_t inDataMode, uint32_t inDataSize) __attribute__((__always_inline__)) { + clock = inClock; + bitOrder = inBitOrder; + dataMode = inDataMode; + dataSize = inDataSize; + } + + //uint32_t spi_speed; + uint32_t clock; + uint32_t dataSize; + //uint32_t clockDivider; + uint8_t bitOrder; + uint8_t dataMode; + //LPC_SSP_TypeDef *spi_d; + + friend class SPIClass; +}; + +/** + * @brief Wirish SPI interface. + * + * This is the same interface is available across HAL + * + * This implementation uses software slave management, so the caller + * is responsible for controlling the slave select line. + */ +class SPIClass { +public: + /** + * @param spiPortNumber Number of the SPI port to manage. + */ + SPIClass(uint8_t spiPortNumber); + + /** + * Init using pins + */ + SPIClass(pin_t mosi, pin_t miso, pin_t sclk, pin_t ssel = (pin_t)-1); + + /** + * Select and configure the current selected SPI device to use + */ + void begin(); + + /** + * Disable the current SPI device + */ + void end(); + + void beginTransaction(const SPISettings&); + void endTransaction() {} + + // Transfer using 1 "Data Size" + uint8_t transfer(uint16_t data); + // Transfer 2 bytes in 8 bit mode + uint16_t transfer16(uint16_t data); + + void send(uint8_t data); + + uint16_t read(); + void read(uint8_t *buf, uint32_t len); + + void dmaSend(void *buf, uint16_t length, bool minc); + + /** + * @brief Sets the number of the SPI peripheral to be used by + * this HardwareSPI instance. + * + * @param spi_num Number of the SPI port. 1-2 in low density devices + * or 1-3 in high density devices. + */ + void setModule(uint8_t device); + + void setClock(uint32_t clock); + void setBitOrder(uint8_t bitOrder); + void setDataMode(uint8_t dataMode); + void setDataSize(uint32_t ds); + + inline uint32_t getDataSize() { return _currentSetting->dataSize; } + +private: + SPISettings _settings[BOARD_NR_SPI]; + SPISettings *_currentSetting; + + void updateSettings(); +}; + +extern SPIClass SPI; diff --git a/Marlin/src/HAL/LPC4078/main.cpp b/Marlin/src/HAL/LPC4078/main.cpp new file mode 100644 index 0000000000..40b77728bd --- /dev/null +++ b/Marlin/src/HAL/LPC4078/main.cpp @@ -0,0 +1,111 @@ +/** + * 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_LPC4078 + +#include "../../inc/MarlinConfig.h" +#include "../../core/millis_t.h" +#include "../../sd/cardreader.h" + +#include +#include + +TERN_(POSTMORTEM_DEBUGGING, extern void install_min_serial()); + +void MarlinHAL::init() { + + MCUI::pwm_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(int 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 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 + + TERN_(HAS_SD_HOST_DRIVE, MCUI::USBDevice::msc_storage_init()); // Enable USB SD card access + MCUI::USBDevice::connect(2000, LED_PIN); + + HAL_timer_init(); + + TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); // Install the min serial handler +} + +// 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()) + MCUI::USBDevice::msc_storage_lock(); + else + MCUI::USBDevice::msc_storage_release(); + #endif + // Perform USB stack housekeeping + MCUI::USBDevice::msc_run_deferred_commands(); +} + +#endif // TARGET_LPC4078 diff --git a/Marlin/src/HAL/LPC4078/pinsDebug.h b/Marlin/src/HAL/LPC4078/pinsDebug.h new file mode 100644 index 0000000000..a1bae08d92 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/pinsDebug.h @@ -0,0 +1,57 @@ +/** + * 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 . + * + */ + +/** + * Support routines for LPC1768 + */ + +/** + * Translation of routines & variables used by pinsDebug.h + */ + +#define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS +#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"), MCUI::pin_port(p), MCUI::pin_bit(p)); SERIAL_ECHO(buffer); }while(0) +#define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR("_A%d "), MCUI::pin_get_adc_channel(pin)); 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 +#ifndef M43_NEVER_TOUCH + #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 (!MCUI::pin_is_valid(pin) || MCUI::pin_adc_enabled(pin)) // found an invalid pin or active analog pin + return false; + + return MCUI::gpio_direction(pin); +} + +#define GET_ARRAY_IS_DIGITAL(x) ((bool) pin_array[x].is_digital) + +void print_port(const pin_t) {} +void pwm_details(const pin_t) {} +bool pwm_status(const pin_t) { return false; } diff --git a/Marlin/src/HAL/LPC4078/spi_pins.h b/Marlin/src/HAL/LPC4078/spi_pins.h new file mode 100644 index 0000000000..78bb0ec962 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/spi_pins.h @@ -0,0 +1,54 @@ +/** + * 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 "../../core/macros.h" + +#if ALL(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. +#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 */ +#ifndef SD_SCK_PIN + #define SD_SCK_PIN P0_15 +#endif +#ifndef SD_MISO_PIN + #define SD_MISO_PIN P0_17 +#endif +#ifndef SD_MOSI_PIN + #define SD_MOSI_PIN P0_18 +#endif +#ifndef SD_SS_PIN + #define SD_SS_PIN P1_23 +#endif +#if !defined(SDSS) || SDSS == P_NC // gets defaulted in pins.h + #undef SDSS + #define SDSS SD_SS_PIN +#endif diff --git a/Marlin/src/HAL/LPC4078/timers.cpp b/Marlin/src/HAL/LPC4078/timers.cpp new file mode 100644 index 0000000000..eb6d8a70ae --- /dev/null +++ b/Marlin/src/HAL/LPC4078/timers.cpp @@ -0,0 +1,65 @@ +/** + * 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 + * + * 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 . + * + */ + +/** + * Description: + * + * Timers for LPC1768 + */ + +#ifdef TARGET_LPC4078 + +#include "../../inc/MarlinConfig.h" + +void HAL_timer_init() { + SBI(MCUI::system_control.PCONP, SBIT_TIMER0); // Power ON Timer 0 + STEP_TIMER_REF.PR = (HAL_TIMER_RATE) / (STEPPER_TIMER_RATE) - 1; // Use prescaler to set frequency if needed + + SBI(MCUI::system_control.PCONP, SBIT_TIMER1); // Power ON Timer 1 + TEMP_TIMER_REF.PR = (HAL_TIMER_RATE) / 1000000 - 1; +} + +void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) { + switch (timer_num) { + case MF_TIMER_STEP: + STEP_TIMER_REF.MCR = _BV(SBIT_MR0I) | _BV(SBIT_MR0R); // Match on MR0, reset on MR0, interrupts when NVIC enables them + STEP_TIMER_REF.MR0 = uint32_t(STEPPER_TIMER_RATE) / frequency; // Match value (period) to set frequency + STEP_TIMER_REF.TCR = _BV(SBIT_CNTEN); // Counter Enable + + MCUCore::nvic_set_priority(MCUI::IRQNumber::TIMER0, MCUCore::nvic_encode_priority(0, 1, 0)); + MCUCore::nvic_enable_irq(MCUI::IRQNumber::TIMER0); + break; + + case MF_TIMER_TEMP: + TEMP_TIMER_REF.MCR = _BV(SBIT_MR0I) | _BV(SBIT_MR0R); // Match on MR0, reset on MR0, interrupts when NVIC enables them + TEMP_TIMER_REF.MR0 = uint32_t(TEMP_TIMER_RATE) / frequency; + TEMP_TIMER_REF.TCR = _BV(SBIT_CNTEN); // Counter Enable + + MCUCore::nvic_set_priority(MCUI::IRQNumber::TIMER1, MCUCore::nvic_encode_priority(0, 2, 0)); + MCUCore::nvic_enable_irq(MCUI::IRQNumber::TIMER1); + break; + + default: break; + } +} + +#endif // TARGET_LPC4078 diff --git a/Marlin/src/HAL/LPC4078/timers.h b/Marlin/src/HAL/LPC4078/timers.h new file mode 100644 index 0000000000..3db982168f --- /dev/null +++ b/Marlin/src/HAL/LPC4078/timers.h @@ -0,0 +1,165 @@ +/** + * Marlin 3D Printer Firmware + * + * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com + * + * 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 + +/** + * HAL For LPC1768 + */ + + +#include +#include + +#include "../../core/macros.h" + +#define SBIT_TIMER0 1 +#define SBIT_TIMER1 2 + +#define SBIT_CNTEN 0 + +#define SBIT_MR0I 0 // Timer 0 Interrupt when TC matches MR0 +#define SBIT_MR0R 1 // Timer 0 Reset TC on Match +#define SBIT_MR0S 2 // Timer 0 Stop TC and PC on Match +#define SBIT_MR1I 3 +#define SBIT_MR1R 4 +#define SBIT_MR1S 5 +#define SBIT_MR2I 6 +#define SBIT_MR2R 7 +#define SBIT_MR2S 8 +#define SBIT_MR3I 9 +#define SBIT_MR3R 10 +#define SBIT_MR3S 11 + +// ------------------------ +// Defines +// ------------------------ + +#define _HAL_TIMER(T) _CAT(MCUI::timer, T) +#define _HAL_TIMER_IRQ(T) TIMER##T##_IRQn +#define __HAL_TIMER_ISR(T) extern "C" void TIMER##T##_IRQHandler() +#define _HAL_TIMER_ISR(T) __HAL_TIMER_ISR(T) + +typedef uint32_t hal_timer_t; +#define HAL_TIMER_TYPE_MAX 0xFFFFFFFF + +#define HAL_TIMER_RATE ((F_CPU) / 2) // frequency of timers peripherals + +#ifndef MF_TIMER_STEP + #define MF_TIMER_STEP 0 // 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 1 // Timer Index for Temperature +#endif +#ifndef MF_TIMER_PWM + #define MF_TIMER_PWM 3 // Timer Index for PWM +#endif + +#define TEMP_TIMER_RATE 1000000 +#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 // frequency of pulse timer +#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) + +#ifndef HAL_STEP_TIMER_ISR + #define HAL_STEP_TIMER_ISR() _HAL_TIMER_ISR(MF_TIMER_STEP) +#endif +#ifndef HAL_TEMP_TIMER_ISR + #define HAL_TEMP_TIMER_ISR() _HAL_TIMER_ISR(MF_TIMER_TEMP) +#endif + +// Timer references by index +#define STEP_TIMER_REF _HAL_TIMER(MF_TIMER_STEP) +#define TEMP_TIMER_REF _HAL_TIMER(MF_TIMER_TEMP) + +// ------------------------ +// Public functions +// ------------------------ +void HAL_timer_init(); +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) { + switch (timer_num) { + case MF_TIMER_STEP: STEP_TIMER_REF.MR0 = compare; break; // Stepper Timer Match Register 0 + case MF_TIMER_TEMP: TEMP_TIMER_REF.MR0 = compare; break; // Temp Timer Match Register 0 + } +} + +FORCE_INLINE static hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) { + switch (timer_num) { + case MF_TIMER_STEP: return STEP_TIMER_REF.MR0; // Stepper Timer Match Register 0 + case MF_TIMER_TEMP: return TEMP_TIMER_REF.MR0; // Temp Timer Match Register 0 + } + return 0; +} + +FORCE_INLINE static hal_timer_t HAL_timer_get_count(const uint8_t timer_num) { + switch (timer_num) { + case MF_TIMER_STEP: return STEP_TIMER_REF.TC; // Stepper Timer Count + case MF_TIMER_TEMP: return TEMP_TIMER_REF.TC; // Temp Timer Count + } + return 0; +} + +FORCE_INLINE static void HAL_timer_enable_interrupt(const uint8_t timer_num) { + switch (timer_num) { + case MF_TIMER_STEP: MCUCore::nvic_enable_irq(MCUI::IRQNumber::TIMER0); break; // Enable interrupt handler + case MF_TIMER_TEMP: MCUCore::nvic_enable_irq(MCUI::IRQNumber::TIMER1); break; // Enable interrupt handler + } +} + +FORCE_INLINE static void HAL_timer_disable_interrupt(const uint8_t timer_num) { + switch (timer_num) { + case MF_TIMER_STEP: MCUCore::nvic_disable_irq(MCUI::IRQNumber::TIMER0); break; // Disable interrupt handler + case MF_TIMER_TEMP: MCUCore::nvic_disable_irq(MCUI::IRQNumber::TIMER1); break; // Disable interrupt handler + } +} + +FORCE_INLINE static bool HAL_timer_interrupt_enabled(const uint8_t timer_num) { + switch (timer_num) { + case MF_TIMER_STEP: return MCUCore::nvic_irq_is_enabled(MCUI::IRQNumber::TIMER0); // Check if interrupt is enabled or not + case MF_TIMER_TEMP: return MCUCore::nvic_irq_is_enabled(MCUI::IRQNumber::TIMER1); // Check if interrupt is enabled or not + } + return false; +} + +FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) { + switch (timer_num) { + case MF_TIMER_STEP: SBI(STEP_TIMER_REF.IR, SBIT_CNTEN); break; + case MF_TIMER_TEMP: SBI(TEMP_TIMER_REF.IR, SBIT_CNTEN); break; + } +} + +#define HAL_timer_isr_epilogue(T) NOOP diff --git a/Marlin/src/HAL/LPC4078/u8g/LCD_I2C_routines.cpp b/Marlin/src/HAL/LPC4078/u8g/LCD_I2C_routines.cpp new file mode 100644 index 0000000000..e714c3c16d --- /dev/null +++ b/Marlin/src/HAL/LPC4078/u8g/LCD_I2C_routines.cpp @@ -0,0 +1,89 @@ +/** + * 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 . + * + */ + +// 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 + +#ifdef TARGET_LPC1768 + +#include "../include/i2c_util.h" +#include "../../../core/millis_t.h" + +extern int millis(); + +#ifdef __cplusplus + extern "C" { +#endif + +////////////////////////////////////////////////////////////////////////////////////// + +#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) { + // 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 + // the slave address and write bit are actually sent. + do{ + _I2C_Stop(I2CDEV_M); // output stop state on I2C bus + _I2C_Start(I2CDEV_M); // output start state on I2C bus + while ((I2C_status != I2C_I2STAT_M_TX_START) + && (I2C_status != I2C_I2STAT_M_TX_RESTART) + && (I2C_status != I2C_I2STAT_M_TX_DAT_ACK) + && (I2C_status != I2C_I2STAT_M_TX_DAT_NACK)); //wait for start to be asserted + + LPC_I2C1->I2CONCLR = I2C_I2CONCLR_STAC; // clear start state before tansmitting slave address + LPC_I2C1->I2DAT = I2CDEV_S_ADDR & I2C_I2DAT_BITMASK; // transmit slave address & write bit + LPC_I2C1->I2CONSET = I2C_I2CONSET_AA; + LPC_I2C1->I2CONCLR = I2C_I2CONCLR_SIC; + while ((I2C_status != I2C_I2STAT_M_TX_SLAW_ACK) + && (I2C_status != I2C_I2STAT_M_TX_SLAW_NACK) + && (I2C_status != I2C_I2STAT_M_TX_DAT_ACK) + && (I2C_status != I2C_I2STAT_M_TX_DAT_NACK)); //wait for slaw to finish + }while ( (I2C_status == I2C_I2STAT_M_TX_DAT_ACK) || (I2C_status == I2C_I2STAT_M_TX_DAT_NACK)); + return 1; +} + +void u8g_i2c_init(const uint8_t clock_option) { + configure_i2c(clock_option); + u8g_i2c_start(0); // Send slave address and write bit +} + +uint8_t u8g_i2c_send_byte(uint8_t data) { + #define I2C_TIMEOUT 3 + LPC_I2C1->I2DAT = data & I2C_I2DAT_BITMASK; // transmit data + LPC_I2C1->I2CONSET = I2C_I2CONSET_AA; + LPC_I2C1->I2CONCLR = I2C_I2CONCLR_SIC; + const millis_t timeout = millis() + I2C_TIMEOUT; + while ((I2C_status != I2C_I2STAT_M_TX_DAT_ACK) && (I2C_status != I2C_I2STAT_M_TX_DAT_NACK) && PENDING(millis(), timeout)); // wait for xmit to finish + // had hangs with SH1106 so added time out - have seen temporary screen corruption when this happens + return 1; +} + +void u8g_i2c_stop() { +} + +#ifdef __cplusplus + } +#endif + +#endif // TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC4078/u8g/LCD_I2C_routines.h b/Marlin/src/HAL/LPC4078/u8g/LCD_I2C_routines.h new file mode 100644 index 0000000000..2d976c92d2 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/u8g/LCD_I2C_routines.h @@ -0,0 +1,28 @@ +/** + * 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 + +void u8g_i2c_init(const uint8_t clock_options); +//uint8_t u8g_i2c_wait(uint8_t mask, uint8_t pos); +uint8_t u8g_i2c_start(uint8_t sla); +uint8_t u8g_i2c_send_byte(uint8_t data); +void u8g_i2c_stop(); diff --git a/Marlin/src/HAL/LPC4078/u8g/LCD_defines.h b/Marlin/src/HAL/LPC4078/u8g/LCD_defines.h new file mode 100644 index 0000000000..5b58f1223a --- /dev/null +++ b/Marlin/src/HAL/LPC4078/u8g/LCD_defines.h @@ -0,0 +1,46 @@ +/** + * 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 + +/** + * LPC1768 LCD-specific defines + */ + +#ifndef U8G_HAL_LINKS + + #define U8G_COM_SSD_I2C_HAL u8g_com_arduino_ssd_i2c_fn // See U8glib-HAL + +#else + + uint8_t u8g_com_HAL_LPC1768_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); + uint8_t u8g_com_HAL_LPC1768_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); + uint8_t u8g_com_HAL_LPC1768_ST7920_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); + 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); + + #define U8G_COM_HAL_SW_SPI_FN u8g_com_HAL_LPC1768_sw_spi_fn + #define U8G_COM_HAL_HW_SPI_FN u8g_com_HAL_LPC1768_hw_spi_fn + #define U8G_COM_ST7920_HAL_SW_SPI u8g_com_HAL_LPC1768_ST7920_sw_spi_fn + #define U8G_COM_ST7920_HAL_HW_SPI u8g_com_HAL_LPC1768_ST7920_hw_spi_fn + #define U8G_COM_SSD_I2C_HAL u8g_com_HAL_LPC1768_ssd_hw_i2c_fn + +#endif diff --git a/Marlin/src/HAL/LPC4078/u8g/LCD_delay.h b/Marlin/src/HAL/LPC4078/u8g/LCD_delay.h new file mode 100644 index 0000000000..0b9e2b4fd0 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/u8g/LCD_delay.h @@ -0,0 +1,43 @@ +/** + * 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 + +/** + * LCD delay routines - used by all the drivers. + * + * These are based on the LPC1768 routines. + * + * Couldn't just call exact copies because the overhead + * results in a one microsecond delay taking about 4µS. + */ + +#ifdef __cplusplus + extern "C" { +#endif + +void U8g_delay(int msec); +void u8g_MicroDelay(); +void u8g_10MicroDelay(); + +#ifdef __cplusplus + } +#endif diff --git a/Marlin/src/HAL/LPC4078/u8g/LCD_pin_routines.cpp b/Marlin/src/HAL/LPC4078/u8g/LCD_pin_routines.cpp new file mode 100644 index 0000000000..4635beda8c --- /dev/null +++ b/Marlin/src/HAL/LPC4078/u8g/LCD_pin_routines.cpp @@ -0,0 +1,59 @@ +/** + * 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 . + * + */ + +/** + * Low level pin manipulation routines - used by all the drivers. + * + * These are based on the LPC1768 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. + */ + +#ifdef TARGET_LPC4078 + +#include + +extern "C" { + +#include "LCD_pin_routines.h" + +void u8g_SetPinOutput(uint8_t pin) { + MCUI::gpio_set_output(pin); +} + +void u8g_SetPinInput(uint8_t pin) { + MCUI::gpio_set_input(pin); +} + +void u8g_SetPinLevel(uint8_t pin, uint8_t pin_status) { + MCUI::gpio_set(pin, pin_status); +} + +uint8_t u8g_GetPinLevel(uint8_t pin) { + return MCUI::gpio_get(pin); +} + +} + +#endif // TARGET_LPC4078 diff --git a/Marlin/src/HAL/LPC4078/u8g/LCD_pin_routines.h b/Marlin/src/HAL/LPC4078/u8g/LCD_pin_routines.h new file mode 100644 index 0000000000..d60d93dadd --- /dev/null +++ b/Marlin/src/HAL/LPC4078/u8g/LCD_pin_routines.h @@ -0,0 +1,37 @@ +/** + * 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 + +/** + * Low level pin manipulation routines - used by all the drivers. + * + * These are based on the LPC1768 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/LPC4078/u8g/u8g_com_HAL_LPC1768_hw_spi.cpp b/Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_hw_spi.cpp new file mode 100644 index 0000000000..ac46456409 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_hw_spi.cpp @@ -0,0 +1,129 @@ +/** + * 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 . + * + */ + +/** + * Based on u8g_com_msp430_hw_spi.c + * + * Universal 8bit Graphics Library + * + * Copyright (c) 2011, 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 TARGET_LPC4078 + +#include "../../../inc/MarlinConfigPre.h" + +#if HAS_MARLINUI_U8GLIB + +#include +#include "../../shared/HAL_SPI.h" + +#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_com_HAL_LPC1768_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_SetPILevel(u8g, U8G_PI_CS, 1); + u8g_SetPILevel(u8g, U8G_PI_A0, 1); + u8g_SetPILevel(u8g, U8G_PI_RESET, 1); + u8g_SetPIOutput(u8g, U8G_PI_CS); + u8g_SetPIOutput(u8g, U8G_PI_A0); + u8g_SetPIOutput(u8g, U8G_PI_RESET); + 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) */ + u8g_SetPILevel(u8g, U8G_PI_A0, arg_val); + break; + + case U8G_COM_MSG_CHIP_SELECT: + u8g_SetPILevel(u8g, U8G_PI_CS, (arg_val ? 0 : 1)); + break; + + case U8G_COM_MSG_RESET: + u8g_SetPILevel(u8g, U8G_PI_RESET, 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; + + case U8G_COM_MSG_WRITE_SEQ_P: { + uint8_t *ptr = (uint8_t*) arg_ptr; + while (arg_val > 0) { + spiSend(*ptr++); + arg_val--; + } + } + break; + } + return 1; +} + +#endif // HAS_MARLINUI_U8GLIB + +#endif // TARGET_LPC4078 diff --git a/Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_ssd_hw_i2c.cpp b/Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_ssd_hw_i2c.cpp new file mode 100644 index 0000000000..bf76eaf0f4 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_ssd_hw_i2c.cpp @@ -0,0 +1,198 @@ +/** + * 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 . + * + */ + +/** + * Based on u8g_com_arduino_ssd_i2c.c + * + * COM interface for Arduino (AND ATmega) and the SSDxxxx chip (SOLOMON) variant + * I2C protocol + * + * Universal 8bit Graphics Library + * + * Copyright (c) 2011, 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. + */ + +/** + * Special pin usage: + * U8G_PI_I2C_OPTION additional options + * U8G_PI_A0_STATE used to store the last value of the command/data register selection + * U8G_PI_SET_A0 1: Signal request to update I2C device with new A0_STATE, 0: Do nothing, A0_STATE matches I2C device + * U8G_PI_SCL clock line (NOT USED) + * U8G_PI_SDA data line (NOT USED) + * + * U8G_PI_RESET reset line (currently disabled, see below) + * + * Protocol: + * SLA, Cmd/Data Selection, Arguments + * The command/data register is selected by a special instruction byte, which is sent after SLA + * + * The continue bit is always 0 so that a (re)start is equired for the change from cmd to/data mode + */ + +#ifdef TARGET_LPC1768 + +#include "../../../inc/MarlinConfigPre.h" + +#if HAS_MARLINUI_U8GLIB + +#include + +#define I2C_SLA (0x3C*2) +//#define I2C_CMD_MODE 0x080 +#define I2C_CMD_MODE 0x000 +#define I2C_DATA_MODE 0x040 + +uint8_t u8g_com_ssd_I2C_start_sequence(u8g_t *u8g) { + /* are we requested to set the a0 state? */ + if (u8g->pin_list[U8G_PI_SET_A0] == 0) return 1; + + /* setup bus, might be a repeated start */ + if (u8g_i2c_start(I2C_SLA) == 0) return 0; + if (u8g->pin_list[U8G_PI_A0_STATE] == 0) { + if (u8g_i2c_send_byte(I2C_CMD_MODE) == 0) return 0; + } + else if (u8g_i2c_send_byte(I2C_DATA_MODE) == 0) + return 0; + + u8g->pin_list[U8G_PI_SET_A0] = 0; + return 1; +} + +uint8_t u8g_com_HAL_LPC1768_ssd_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) { + switch (msg) { + case U8G_COM_MSG_INIT: + //u8g_com_arduino_digital_write(u8g, U8G_PI_SCL, HIGH); + //u8g_com_arduino_digital_write(u8g, U8G_PI_SDA, HIGH); + //u8g->pin_list[U8G_PI_A0_STATE] = 0; /* initial RS state: unknown mode */ + + u8g_i2c_init(u8g->pin_list[U8G_PI_I2C_OPTION]); + u8g_com_ssd_I2C_start_sequence(u8g); + break; + + case U8G_COM_MSG_STOP: + break; + + case U8G_COM_MSG_RESET: + /* Currently disabled, but it could be enable. Previous restrictions have been removed */ + /* u8g_com_arduino_digital_write(u8g, U8G_PI_RESET, arg_val); */ + break; + + case U8G_COM_MSG_CHIP_SELECT: + u8g->pin_list[U8G_PI_A0_STATE] = 0; + u8g->pin_list[U8G_PI_SET_A0] = 1; /* force a0 to set again, also forces start condition */ + if (arg_val == 0 ) { + /* disable chip, send stop condition */ + u8g_i2c_stop(); + } + else { + /* enable, do nothing: any byte writing will trigger the i2c start */ + } + break; + + case U8G_COM_MSG_WRITE_BYTE: + //u8g->pin_list[U8G_PI_SET_A0] = 1; + if (u8g_com_ssd_I2C_start_sequence(u8g) == 0) { + u8g_i2c_stop(); + return 0; + } + + if (u8g_i2c_send_byte(arg_val) == 0) { + u8g_i2c_stop(); + return 0; + } + // u8g_i2c_stop(); + break; + + case U8G_COM_MSG_WRITE_SEQ: { + //u8g->pin_list[U8G_PI_SET_A0] = 1; + if (u8g_com_ssd_I2C_start_sequence(u8g) == 0) { + u8g_i2c_stop(); + return 0; + } + + uint8_t *ptr = (uint8_t *)arg_ptr; + while (arg_val > 0) { + if (u8g_i2c_send_byte(*ptr++) == 0) { + u8g_i2c_stop(); + return 0; + } + arg_val--; + } + } + // u8g_i2c_stop(); + break; + + case U8G_COM_MSG_WRITE_SEQ_P: { + //u8g->pin_list[U8G_PI_SET_A0] = 1; + if (u8g_com_ssd_I2C_start_sequence(u8g) == 0) { + u8g_i2c_stop(); + return 0; + } + + uint8_t *ptr = (uint8_t *)arg_ptr; + while (arg_val > 0) { + if (u8g_i2c_send_byte(u8g_pgm_read(ptr)) == 0) + return 0; + ptr++; + arg_val--; + } + } + // u8g_i2c_stop(); + break; + + case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */ + u8g->pin_list[U8G_PI_A0_STATE] = arg_val; + u8g->pin_list[U8G_PI_SET_A0] = 1; /* force a0 to set again */ + break; + + } // switch + return 1; +} + +#endif // HAS_MARLINUI_U8GLIB + +#endif // TARGET_LPC1768 diff --git a/Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_st7920_hw_spi.cpp b/Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_st7920_hw_spi.cpp new file mode 100644 index 0000000000..c96e0f56f4 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_st7920_hw_spi.cpp @@ -0,0 +1,138 @@ +/** + * 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 . + * + */ + +/** + * Based on u8g_com_LPC1768_st7920_hw_spi.c + * + * Universal 8bit Graphics Library + * + * Copyright (c) 2011, 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 TARGET_LPC4078 + +#include "../../../inc/MarlinConfigPre.h" + +#if HAS_MARLINUI_U8GLIB + +#include +#include "../../shared/HAL_SPI.h" +#include "../../shared/Delay.h" + +void spiBegin(); +void spiInit(uint8_t spiRate); +void spiSend(uint8_t b); +void spiSend(const uint8_t *buf, size_t n); + +static uint8_t rs_last_state = 255; + +static void u8g_com_LPC1768_st7920_write_byte_hw_spi(uint8_t rs, uint8_t val) { + + if (rs != rs_last_state) { // Time to send a command/data byte + rs_last_state = rs; + spiSend(rs ? 0x0FA : 0x0F8); // Send data or command + DELAY_US(40); // Give the controller some time: 20 is bad, 30 is OK, 40 is safe + } + + spiSend(val & 0xF0); + spiSend(val << 4); +} + +uint8_t u8g_com_HAL_LPC1768_ST7920_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) { + switch (msg) { + case U8G_COM_MSG_INIT: + u8g_SetPILevel(u8g, U8G_PI_CS, 0); + u8g_SetPIOutput(u8g, U8G_PI_CS); + u8g_Delay(5); + spiBegin(); + spiInit(SPI_EIGHTH_SPEED); // ST7920 max speed is about 1.1 MHz + u8g->pin_list[U8G_PI_A0_STATE] = 0; // initial RS state: command mode + break; + + case U8G_COM_MSG_STOP: + break; + + case U8G_COM_MSG_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) + u8g->pin_list[U8G_PI_A0_STATE] = arg_val; + break; + + case U8G_COM_MSG_CHIP_SELECT: + u8g_SetPILevel(u8g, U8G_PI_CS, arg_val); // Note: the ST7920 has an active high chip-select + break; + + case U8G_COM_MSG_WRITE_BYTE: + u8g_com_LPC1768_st7920_write_byte_hw_spi(u8g->pin_list[U8G_PI_A0_STATE], arg_val); + break; + + case U8G_COM_MSG_WRITE_SEQ: { + uint8_t *ptr = (uint8_t*) arg_ptr; + while (arg_val > 0) { + u8g_com_LPC1768_st7920_write_byte_hw_spi(u8g->pin_list[U8G_PI_A0_STATE], *ptr++); + arg_val--; + } + } + break; + + case U8G_COM_MSG_WRITE_SEQ_P: { + uint8_t *ptr = (uint8_t*) arg_ptr; + while (arg_val > 0) { + u8g_com_LPC1768_st7920_write_byte_hw_spi(u8g->pin_list[U8G_PI_A0_STATE], *ptr++); + arg_val--; + } + } + break; + } + return 1; +} + +#endif // HAS_MARLINUI_U8GLIB + +#endif // TARGET_LPC4078 diff --git a/Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_st7920_sw_spi.cpp b/Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_st7920_sw_spi.cpp new file mode 100644 index 0000000000..436a972850 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_st7920_sw_spi.cpp @@ -0,0 +1,147 @@ +/** + * 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 . + * + */ + +/** + * Based on u8g_com_st7920_hw_spi.c + * + * Universal 8bit Graphics Library + * + * Copyright (c) 2011, 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 TARGET_LPC4078 + +#include "../../../inc/MarlinConfigPre.h" + +#if IS_U8GLIB_ST7920 + +#include +#include "../SoftwareSPI.h" +#include "../../shared/Delay.h" +#include "../../shared/HAL_SPI.h" + +#ifndef LCD_SPI_SPEED + #define LCD_SPI_SPEED SPI_EIGHTH_SPEED // About 1 MHz +#endif + +static pin_t SCK_pin_ST7920_HAL, MOSI_pin_ST7920_HAL_HAL; +static uint8_t SPI_speed = 0; + +static void u8g_com_LPC1768_st7920_write_byte_sw_spi(uint8_t rs, uint8_t val) { + static uint8_t rs_last_state = 255; + if (rs != rs_last_state) { + // Transfer Data (FA) or Command (F8) + swSpiTransfer(rs ? 0x0FA : 0x0F8, SPI_speed, SCK_pin_ST7920_HAL, -1, MOSI_pin_ST7920_HAL_HAL); + rs_last_state = rs; + DELAY_US(40); // Give the controller time to process the data: 20 is bad, 30 is OK, 40 is safe + } + 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); +} + +uint8_t u8g_com_HAL_LPC1768_ST7920_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) { + switch (msg) { + case U8G_COM_MSG_INIT: + SCK_pin_ST7920_HAL = u8g->pin_list[U8G_PI_SCK]; + MOSI_pin_ST7920_HAL_HAL = u8g->pin_list[U8G_PI_MOSI]; + + u8g_SetPIOutput(u8g, U8G_PI_CS); + u8g_SetPIOutput(u8g, U8G_PI_SCK); + u8g_SetPIOutput(u8g, U8G_PI_MOSI); + u8g_Delay(5); + + SPI_speed = swSpiInit(LCD_SPI_SPEED, SCK_pin_ST7920_HAL, MOSI_pin_ST7920_HAL_HAL); + + u8g_SetPILevel(u8g, U8G_PI_CS, 0); + u8g_SetPILevel(u8g, U8G_PI_SCK, 0); + u8g_SetPILevel(u8g, U8G_PI_MOSI, 0); + + u8g->pin_list[U8G_PI_A0_STATE] = 0; /* initial RS state: command mode */ + break; + + case U8G_COM_MSG_STOP: + break; + + case U8G_COM_MSG_RESET: + 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) */ + u8g->pin_list[U8G_PI_A0_STATE] = arg_val; + break; + + case U8G_COM_MSG_CHIP_SELECT: + if (U8G_PIN_NONE != u8g->pin_list[U8G_PI_CS]) u8g_SetPILevel(u8g, U8G_PI_CS, arg_val); //note: the st7920 has an active high chip select + break; + + case U8G_COM_MSG_WRITE_BYTE: + u8g_com_LPC1768_st7920_write_byte_sw_spi(u8g->pin_list[U8G_PI_A0_STATE], arg_val); + break; + + case U8G_COM_MSG_WRITE_SEQ: { + uint8_t *ptr = (uint8_t*) arg_ptr; + while (arg_val > 0) { + u8g_com_LPC1768_st7920_write_byte_sw_spi(u8g->pin_list[U8G_PI_A0_STATE], *ptr++); + arg_val--; + } + } + break; + + case U8G_COM_MSG_WRITE_SEQ_P: { + uint8_t *ptr = (uint8_t*) arg_ptr; + while (arg_val > 0) { + u8g_com_LPC1768_st7920_write_byte_sw_spi(u8g->pin_list[U8G_PI_A0_STATE], *ptr++); + arg_val--; + } + } + break; + } + return 1; +} + +#endif // IS_U8GLIB_ST7920 +#endif // TARGET_LPC4078 diff --git a/Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_sw_spi.cpp b/Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_sw_spi.cpp new file mode 100644 index 0000000000..03cd7b48a9 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_sw_spi.cpp @@ -0,0 +1,209 @@ +/** + * 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 . + * + */ + +/** + * Based on u8g_com_std_sw_spi.c + * + * Universal 8bit Graphics Library + * + * Copyright (c) 2015, 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 TARGET_LPC4078 + +#include "../../../inc/MarlinConfigPre.h" + +#if HAS_MARLINUI_U8GLIB && !IS_U8GLIB_ST7920 + +#include +#include "../../shared/HAL_SPI.h" + +#ifndef LCD_SPI_SPEED + #define LCD_SPI_SPEED SPI_QUARTER_SPEED // About 2 MHz +#endif + +#include +#include +#include +#include + +#include + +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) { + if (spi_speed == 0) { + LPC176x::gpio_set(mosi_pin, !!(b & 0x80)); + LPC176x::gpio_set(sck_pin, HIGH); + b <<= 1; + if (miso_pin >= 0 && LPC176x::gpio_get(miso_pin)) b |= 1; + LPC176x::gpio_set(sck_pin, LOW); + } + else { + const uint8_t state = (b & 0x80) ? HIGH : LOW; + LOOP_L_N(j, spi_speed) + LPC176x::gpio_set(mosi_pin, state); + + LOOP_L_N(j, spi_speed + (miso_pin >= 0 ? 0 : 1)) + 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) + LPC176x::gpio_set(sck_pin, LOW); + } + } + + return b; +} + +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) { + const uint8_t state = (b & 0x80) ? HIGH : LOW; + if (spi_speed == 0) { + LPC176x::gpio_set(sck_pin, LOW); + LPC176x::gpio_set(mosi_pin, state); + LPC176x::gpio_set(mosi_pin, state); // need some setup time + LPC176x::gpio_set(sck_pin, HIGH); + } + else { + LOOP_L_N(j, spi_speed + (miso_pin >= 0 ? 0 : 1)) + LPC176x::gpio_set(sck_pin, LOW); + + LOOP_L_N(j, spi_speed) + LPC176x::gpio_set(mosi_pin, state); + + LOOP_L_N(j, spi_speed) + LPC176x::gpio_set(sck_pin, HIGH); + } + b <<= 1; + if (miso_pin >= 0 && LPC176x::gpio_get(miso_pin)) b |= 1; + } + + return b; +} + +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) + swSpiTransfer_mode_3(val, SPI_speed, clockPin, -1, dataPin); + #else + swSpiTransfer_mode_0(val, SPI_speed, clockPin, -1, dataPin); + #endif +} + +uint8_t u8g_com_HAL_LPC1768_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) { + switch (msg) { + case U8G_COM_MSG_INIT: + u8g_SetPIOutput(u8g, U8G_PI_SCK); + u8g_SetPIOutput(u8g, U8G_PI_MOSI); + u8g_SetPIOutput(u8g, U8G_PI_CS); + u8g_SetPIOutput(u8g, U8G_PI_A0); + if (U8G_PIN_NONE != u8g->pin_list[U8G_PI_RESET]) u8g_SetPIOutput(u8g, U8G_PI_RESET); + SPI_speed = swSpiInit(LCD_SPI_SPEED, u8g->pin_list[U8G_PI_SCK], u8g->pin_list[U8G_PI_MOSI]); + u8g_SetPILevel(u8g, U8G_PI_SCK, 0); + u8g_SetPILevel(u8g, U8G_PI_MOSI, 0); + break; + + case U8G_COM_MSG_STOP: + break; + + case U8G_COM_MSG_RESET: + if (U8G_PIN_NONE != u8g->pin_list[U8G_PI_RESET]) u8g_SetPILevel(u8g, U8G_PI_RESET, 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 + u8g_SetPILevel(u8g, U8G_PI_CS, LOW); + } + else { + u8g_SetPILevel(u8g, U8G_PI_CS, HIGH); + u8g_SetPILevel(u8g, U8G_PI_SCK, 0); // Set SCK to mode 0 idle state after CS goes inactive + } + #else + u8g_SetPILevel(u8g, U8G_PI_CS, !arg_val); + #endif + break; + + case U8G_COM_MSG_WRITE_BYTE: + u8g_sw_spi_HAL_LPC1768_shift_out(u8g->pin_list[U8G_PI_MOSI], u8g->pin_list[U8G_PI_SCK], arg_val); + break; + + case U8G_COM_MSG_WRITE_SEQ: { + uint8_t *ptr = (uint8_t *)arg_ptr; + while (arg_val > 0) { + u8g_sw_spi_HAL_LPC1768_shift_out(u8g->pin_list[U8G_PI_MOSI], u8g->pin_list[U8G_PI_SCK], *ptr++); + arg_val--; + } + } + break; + + case U8G_COM_MSG_WRITE_SEQ_P: { + uint8_t *ptr = (uint8_t *)arg_ptr; + while (arg_val > 0) { + u8g_sw_spi_HAL_LPC1768_shift_out(u8g->pin_list[U8G_PI_MOSI], u8g->pin_list[U8G_PI_SCK], u8g_pgm_read(ptr)); + ptr++; + arg_val--; + } + } + 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); + break; + } + return 1; +} + +#endif // HAS_MARLINUI_U8GLIB && !IS_U8GLIB_ST7920 +#endif // TARGET_LPC4078 diff --git a/Marlin/src/HAL/platforms.h b/Marlin/src/HAL/platforms.h index 9eaf7cea98..c8e644087b 100644 --- a/Marlin/src/HAL/platforms.h +++ b/Marlin/src/HAL/platforms.h @@ -37,6 +37,8 @@ #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/LPC1768/NAME) #elif defined(ARDUINO_ARCH_HC32) #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/HC32/NAME) +#elif defined(TARGET_LPC4078) + #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/LPC4078/NAME) #elif defined(__STM32F1__) || defined(TARGET_STM32F1) #define HAL_PATH(PATH, NAME) XSTR(PATH/HAL/STM32F1/NAME) #elif defined(ARDUINO_ARCH_STM32) diff --git a/Marlin/src/HAL/shared/servo.h b/Marlin/src/HAL/shared/servo.h index 786c1e6a72..434e5b4055 100644 --- a/Marlin/src/HAL/shared/servo.h +++ b/Marlin/src/HAL/shared/servo.h @@ -76,6 +76,8 @@ #include "../LPC1768/Servo.h" #elif defined(ARDUINO_ARCH_HC32) #include "../HC32/Servo.h" +#elif defined(TARGET_LPC4078) + #include "../LPC4078/Servo.h" #elif defined(__STM32F1__) || defined(TARGET_STM32F1) #include "../STM32F1/Servo.h" #elif defined(ARDUINO_ARCH_STM32) diff --git a/Marlin/src/core/boards.h b/Marlin/src/core/boards.h index 91141b23f9..c2c896bd9f 100644 --- a/Marlin/src/core/boards.h +++ b/Marlin/src/core/boards.h @@ -409,6 +409,7 @@ #define BOARD_TEENSY31_32 5100 // Teensy3.1 and Teensy3.2 #define BOARD_TEENSY35_36 5101 // Teensy3.5 and Teensy3.6 +#define BOARD_EBAB 5102 // // STM32 ARM Cortex-M4F diff --git a/Marlin/src/pins/lpc4078/pins_EBAB.h b/Marlin/src/pins/lpc4078/pins_EBAB.h new file mode 100644 index 0000000000..83fa5bac4f --- /dev/null +++ b/Marlin/src/pins/lpc4078/pins_EBAB.h @@ -0,0 +1,605 @@ +/** + * 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 + +#ifndef BOARD_INFO_NAME + #define BOARD_INFO_NAME "Extra Big Ass Board" +#endif + +#ifndef DEFAULT_MACHINE_NAME + #define DEFAULT_MACHINE_NAME "XtraBigAssBoard" +#endif + +#define LED_PIN P3_18 // PWM0_3 + +// EXTRA PINS +#define FIL_RUNOUT_PIN P1_12 +#define PS_ON_PIN P3_15 + +// DRIVERS EXTRA PINS +#define DRIVERS_SCK P1_20 +#define DRIVERS_MISO P1_23 +#define DRIVERS_MOSI P1_24 + + +// +// Servos +// +#define SERVO0_PIN P2_05 // PWM1_6 +#define SERVO1_PIN P2_04 // PWM1_5 +#define SERVO2_PIN P2_03 // PWM1_4 +#define SERVO3_PIN P2_02 // PWM1_3 + + +// +// Limit Switches +// +#define X_MIN_PIN P0_19 +#define X_MAX_PIN P0_18 +#define Y_MIN_PIN P0_20 +#define Y_MAX_PIN P0_17 +#define Z_MIN_PIN P0_21 +#define Z_MAX_PIN P0_15 + +// +// Z Probe (when not Z_MIN_PIN) +// +#ifndef Z_MIN_PROBE_PIN + #define Z_MIN_PROBE_PIN P0_21 +#endif + +// +// Steppers +// +#define X_STEP_PIN P0_10 +#define X_DIR_PIN P4_03 +#define X_ENABLE_PIN P0_01 +#define X_CS_PIN P0_00 +#define X_DIAG_PIN P2_17 + +#define Y_STEP_PIN P1_29 +#define Y_DIR_PIN P2_14 +#define Y_ENABLE_PIN P1_28 +#define Y_CS_PIN P2_22 +#define Y_DIAG_PIN P2_16 + +#define Z_STEP_PIN P4_02 +#define Z_DIR_PIN P1_26 +#define Z_ENABLE_PIN P1_25 +#define Z_CS_PIN P4_01 +#define Z_DIAG_PIN P2_21 + +#define E0_STEP_PIN P1_19 +#define E0_DIR_PIN P0_14 +#define E0_ENABLE_PIN P1_22 +#define E0_CS_PIN P4_00 +#define E0_DIAG_PIN P2_20 + +#define E1_STEP_PIN P2_23 +#define E1_DIR_PIN P2_18 +#define E1_ENABLE_PIN P3_23 +#define E1_CS_PIN P1_18 +#define E1_DIAG_PIN P2_19 + +#define E2_STEP_PIN P3_26 +#define E2_DIR_PIN P2_25 +#define E2_ENABLE_PIN P3_25 +#define E2_CS_PIN P3_24 +#define E2_DIAG_PIN P2_26 + +#define E3_STEP_PIN P4_19 +#define E3_DIR_PIN P4_20 +#define E3_ENABLE_PIN P4_26 +#define E3_CS_PIN P4_21 +#define E3_DIAG_PIN P0_22 + +#define E4_STEP_PIN P4_17 +#define E4_DIR_PIN P4_18 +#define E4_ENABLE_PIN P4_05 +#define E4_CS_PIN P2_12 +#define E4_DIAG_PIN P2_11 + +#define E5_STEP_PIN P0_11 +#define E5_DIR_PIN P2_15 +#define E5_ENABLE_PIN P4_04 +#define E5_CS_PIN P4_16 +#define E5_DIAG_PIN P2_13 + +#define E6_STEP_PIN P2_28 +#define E6_DIR_PIN P0_28 +#define E6_ENABLE_PIN P0_31 +#define E6_CS_PIN P0_27 +#define E6_DIAG_PIN P2_24 + +#define E7_STEP_PIN P1_30 +#define E7_DIR_PIN P0_12 +#define E7_ENABLE_PIN P0_13 +#define E7_CS_PIN P2_29 +#define E7_DIAG_PIN P2_27 + +#define E8_STEP_PIN P3_15 +#define E8_DIR_PIN P3_07 +#define E8_ENABLE_PIN P2_30 +#define E8_CS_PIN P5_01 +#define E8_DIAG_PIN P2_31 + + +#if HAS_TMC_UART + #define X_SERIAL_TX_PIN P0_00 + #define X_SERIAL_RX_PIN P0_00 + #define Y_SERIAL_TX_PIN P2_22 + #define Y_SERIAL_RX_PIN P2_22 + #define Z_SERIAL_TX_PIN P4_01 + #define Z_SERIAL_RX_PIN P4_01 + #define E0_SERIAL_TX_PIN P4_00 + #define E0_SERIAL_RX_PIN P4_00 + #define E1_SERIAL_TX_PIN P1_18 + #define E1_SERIAL_RX_PIN P1_18 + #define E2_SERIAL_TX_PIN P3_24 + #define E2_SERIAL_RX_PIN P3_24 + #define E3_SERIAL_TX_PIN P4_21 + #define E3_SERIAL_RX_PIN P4_21 + #define E4_SERIAL_TX_PIN P2_12 + #define E4_SERIAL_RX_PIN P2_12 + #define E5_SERIAL_TX_PIN P4_16 + #define E5_SERIAL_RX_PIN P4_16 + #define E6_SERIAL_TX_PIN P0_27 + #define E6_SERIAL_RX_PIN P0_27 + #define E7_SERIAL_TX_PIN P2_29 + #define E7_SERIAL_RX_PIN P2_29 + #define E8_SERIAL_TX_PIN P5_01 + #define E8_SERIAL_RX_PIN P5_01 + + // Reduce baud rate to improve software serial reliability + #define TMC_BAUD_RATE 19200 +#endif // HAS_TMC_UART + +// +// Temperature Sensors +// +#define TEMP_0_PIN P0_23 +#define TEMP_1_PIN P0_24 +#define TEMP_2_PIN P0_25 +#define TEMP_3_PIN P0_26 +#define TEMP_BED_PIN P1_31 + +// +// Heaters / Fans +// + +#define HEATER_0_PIN P1_02 +#define HEATER_1_PIN P1_10 +#define HEATER_2_PIN P4_30 +#define HEATER_3_PIN P1_09 +#define HEATER_BED_PIN P4_23 + +#define FAN0_PIN P3_08 +#define FAN1_PIN P3_00 +#define FAN2_PIN P3_27 //PWM1_4 +#define FAN3_PIN P5_04 + +#define EFAN0_PIN P1_08 +#define EFAN1_PIN P4_31 +#define EFAN2_PIN P3_01 +#define EFAN3_PIN P3_10 +// +// Misc. Functions +// +#if SD_CONNECTION_IS(LCD) + #define SD_DETECT_PIN P3_02 + #define SD_SCK_PIN P1_00 + #define SD_MISO_PIN P1_04 + #define SD_MOSI_PIN P1_01 + #define SD_SS_PIN P3_03 + #define SDSS SD_SS_PIN +#elif SD_CONNECTION_IS(ONBOARD) + #define SD_DETECT_PIN P_NC + #define SD_SCK_PIN P0_07 + #define SD_MISO_PIN P0_08 + #define SD_MOSI_PIN P0_09 + #define ONBOARD_SD_CS_PIN P0_06 + #define SD_SS_PIN ONBOARD_SD_CS_PIN + #define SDSS SD_SS_PIN +#endif + +#ifndef NEOPIXEL_PIN + #define NEOPIXEL_PIN P_NC +#endif + +#ifndef FILWIDTH_PIN + #define FILWIDTH_PIN P_NC +#endif + +#ifndef FIL_RUNOUT_PIN + #define FIL_RUNOUT_PIN P_NC +#endif + +#ifndef PS_ON_PIN + #define PS_ON_PIN P_NC +#endif + +// +// Průša i3 MK2 Multiplexer Support +// +#if HAS_PRUSA_MMU1 + #ifndef E_MUX0_PIN + #define E_MUX0_PIN P_NC + #endif + #ifndef E_MUX1_PIN + #define E_MUX1_PIN P_NC + #endif + #ifndef E_MUX2_PIN + #define E_MUX2_PIN P_NC + #endif +#endif + +/** + * Default pins for TMC software SPI + */ +#if ENABLED(TMC_USE_SW_SPI) + #ifndef TMC_SW_MOSI + #define TMC_SW_MOSI P1_24 + #endif + #ifndef TMC_SW_MISO + #define TMC_SW_MISO P1_23 + #endif + #ifndef TMC_SW_SCK + #define TMC_SW_SCK P1_20 + #endif +#endif + + +////////////////////////// +// LCDs and Controllers // +////////////////////////// + +#if ANY(TFT_COLOR_UI, TFT_CLASSIC_UI, TFT_LVGL_UI) + + #define TFT_A0_PIN 43 + #define TFT_CS_PIN 49 + #define TFT_DC_PIN 43 + #define TFT_SCK_PIN SD_SCK_PIN + #define TFT_MOSI_PIN SD_MOSI_PIN + #define TFT_MISO_PIN SD_MISO_PIN + #define LCD_USE_DMA_SPI + + #define BTN_EN1 40 + #define BTN_EN2 63 + #define BTN_ENC 59 + #define BEEPER_PIN 42 + + #define TOUCH_CS_PIN 33 + + #define SD_DETECT_PIN 41 + + #define SPI_FLASH + #if ENABLED(SPI_FLASH) + #define SPI_DEVICE 1 + #define SPI_FLASH_SIZE 0x1000000 // 16MB + #define SPI_FLASH_CS_PIN 31 + #define SPI_FLASH_MOSI_PIN SD_MOSI_PIN + #define SPI_FLASH_MISO_PIN SD_MISO_PIN + #define SPI_FLASH_SCK_PIN SD_SCK_PIN + #endif + + #define TFT_BUFFER_SIZE 0xFFFF + #ifndef TFT_DRIVER + #define TFT_DRIVER ST7796 + #endif + #ifndef TOUCH_SCREEN_CALIBRATION + #if ENABLED(TFT_RES_320x240) + #ifndef TOUCH_CALIBRATION_X + #define TOUCH_CALIBRATION_X 20525 + #endif + #ifndef TOUCH_CALIBRATION_Y + #define TOUCH_CALIBRATION_Y 15335 + #endif + #ifndef TOUCH_OFFSET_X + #define TOUCH_OFFSET_X -1 + #endif + #ifndef TOUCH_OFFSET_Y + #define TOUCH_OFFSET_Y 0 + #endif + #elif ENABLED(TFT_RES_480x272) + #ifndef TOUCH_CALIBRATION_X + #define TOUCH_CALIBRATION_X 30715 + #endif + #ifndef TOUCH_CALIBRATION_Y + #define TOUCH_CALIBRATION_Y 17415 + #endif + #ifndef TOUCH_OFFSET_X + #define TOUCH_OFFSET_X 0 + #endif + #ifndef TOUCH_OFFSET_Y + #define TOUCH_OFFSET_Y -1 + #endif + #elif ENABLED(TFT_RES_480x320) + #ifndef TOUCH_CALIBRATION_X + #define TOUCH_CALIBRATION_X 30595 + #endif + #ifndef TOUCH_CALIBRATION_Y + #define TOUCH_CALIBRATION_Y 20415 + #endif + #ifndef TOUCH_OFFSET_X + #define TOUCH_OFFSET_X 2 + #endif + #ifndef TOUCH_OFFSET_Y + #define TOUCH_OFFSET_Y 1 + #endif + #elif ENABLED(TFT_RES_1024x600) + #ifndef TOUCH_CALIBRATION_X + #define TOUCH_CALIBRATION_X 65533 + #endif + #ifndef TOUCH_CALIBRATION_Y + #define TOUCH_CALIBRATION_Y 38399 + #endif + #ifndef TOUCH_OFFSET_X + #define TOUCH_OFFSET_X 2 + #endif + #ifndef TOUCH_OFFSET_Y + #define TOUCH_OFFSET_Y 1 + #endif + #endif + #endif + + #define BTN_BACK 70 + +#elif HAS_WIRED_LCD + + // + // LCD Display output pins + // + #if ENABLED(REPRAPWORLD_GRAPHICAL_LCD) + + #define LCD_PINS_RS P3_06 // CS chip select /SS chip slave select + #define LCD_PINS_EN P3_14 // SID (MOSI) + #define LCD_PINS_D4 P3_30 // SCK (CLK) clock + + #elif ALL(IS_NEWPANEL, PANEL_ONE) + + #define LCD_PINS_RS 40 + #define LCD_PINS_EN 42 + #define LCD_PINS_D4 65 + #define LCD_PINS_D5 66 + #define LCD_PINS_D6 44 + #define LCD_PINS_D7 64 + + #else + + #if ENABLED(CR10_STOCKDISPLAY) + + #define LCD_PINS_RS 27 + #define LCD_PINS_EN 29 + #define LCD_PINS_D4 25 + + #if !IS_NEWPANEL + #define BEEPER_PIN 37 + #endif + + #elif ENABLED(ZONESTAR_LCD) + + #define LCD_PINS_RS 64 + #define LCD_PINS_EN 44 + #define LCD_PINS_D4 63 + #define LCD_PINS_D5 40 + #define LCD_PINS_D6 42 + #define LCD_PINS_D7 65 + + #else + + #if ANY(MKS_12864OLED, MKS_12864OLED_SSD1306) + #define LCD_PINS_DC 25 // Set as output on init + #define LCD_PINS_RS 27 // Pull low for 1s to init + // DOGM SPI LCD Support + #define DOGLCD_CS 16 + #define DOGLCD_MOSI 17 + #define DOGLCD_SCK 23 + #define DOGLCD_A0 LCD_PINS_DC + #else + #define LCD_PINS_RS P3_06 + #define LCD_PINS_EN P3_14 + #define LCD_PINS_D4 P3_30 + #define LCD_PINS_D5 P3_05 + #define LCD_PINS_D6 P3_29 + #endif + + #define LCD_PINS_D7 P5_00 + + #if !IS_NEWPANEL + #define BEEPER_PIN 33 + #endif + + #endif + + #if !IS_NEWPANEL + // Buttons attached to a shift register + // Not wired yet + //#define SHIFT_CLK_PIN 38 + //#define SHIFT_LD_PIN 42 + //#define SHIFT_OUT_PIN 40 + //#define SHIFT_EN_PIN 17 + #endif + + #endif + + // + // LCD Display input pins + // + #if IS_NEWPANEL + + #if ENABLED(REPRAP_DISCOUNT_SMART_CONTROLLER) + + #define BEEPER_PIN P3_31 + + #if ENABLED(CR10_STOCKDISPLAY) + #define BTN_EN1 17 + #define BTN_EN2 23 + #else + #define BTN_EN1 P3_11 + #define BTN_EN2 P3_12 + #endif + + #define BTN_ENC P3_28 + #define SD_DETECT_PIN P3_02 + //#define KILL_PIN P_NC + + #if ENABLED(BQ_LCD_SMART_CONTROLLER) + #define LCD_BACKLIGHT_PIN 39 + #endif + + #elif ENABLED(REPRAPWORLD_GRAPHICAL_LCD) + + #define BTN_EN1 64 + #define BTN_EN2 59 + #define BTN_ENC 63 + #define SD_DETECT_PIN 42 + + #elif ENABLED(LCD_I2C_PANELOLU2) + + #define BTN_EN1 47 + #define BTN_EN2 43 + #define BTN_ENC 32 + #define LCD_SDSS SDSS + #define KILL_PIN 41 + + #elif ENABLED(LCD_I2C_VIKI) + + #define BTN_EN1 22 // https://files.panucatt.com/datasheets/viki_wiring_diagram.pdf explains 40/42. + #define BTN_EN2 7 // 22/7 are unused on RAMPS_14. 22 is unused and 7 the SERVO0_PIN on RAMPS_13. + #define BTN_ENC -1 + + #define LCD_SDSS SDSS + #define SD_DETECT_PIN 49 + + #elif ANY(VIKI2, miniVIKI) + + #define DOGLCD_CS 45 + #define DOGLCD_A0 44 + + #define BEEPER_PIN 33 + #define STAT_LED_RED_PIN 32 + #define STAT_LED_BLUE_PIN 35 + + #define BTN_EN1 22 + #define BTN_EN2 7 + #define BTN_ENC 39 + + #define SD_DETECT_PIN -1 // Pin 49 for display sd interface, 72 for easy adapter board + #define KILL_PIN 31 + + #define LCD_SCREEN_ROTATE 180 // 0, 90, 180, 270 + + #elif ENABLED(ELB_FULL_GRAPHIC_CONTROLLER) + + #define DOGLCD_CS 29 + #define DOGLCD_A0 27 + + #define BEEPER_PIN 23 + #define LCD_BACKLIGHT_PIN 33 + + #define BTN_EN1 35 + #define BTN_EN2 37 + #define BTN_ENC 31 + + #define LCD_SDSS SDSS + #define SD_DETECT_PIN 49 + #define KILL_PIN 41 + + #elif ENABLED(MKS_MINI_12864) + + #define DOGLCD_A0 27 + #define DOGLCD_CS 25 + + #define BEEPER_PIN 37 + // not connected to a pin + #define LCD_BACKLIGHT_PIN 65 // backlight LED on A11/D65 + + #define BTN_EN1 31 + #define BTN_EN2 33 + #define BTN_ENC 35 + + #define SD_DETECT_PIN 49 + #define KILL_PIN 64 + + //#define LCD_SCREEN_ROTATE 180 // 0, 90, 180, 270 + + #elif ENABLED(MINIPANEL) + + #define BEEPER_PIN 42 + // not connected to a pin + #define LCD_BACKLIGHT_PIN 65 // backlight LED on A11/D65 + + #define DOGLCD_A0 44 + #define DOGLCD_CS 66 + + #define BTN_EN1 40 + #define BTN_EN2 63 + #define BTN_ENC 59 + + #define SD_DETECT_PIN 49 + #define KILL_PIN 64 + + //#define LCD_SCREEN_ROTATE 180 // 0, 90, 180, 270 + + #elif ENABLED(ZONESTAR_LCD) + + #define ADC_KEYPAD_PIN 12 + + #elif ENABLED(AZSMZ_12864) + + // Pins only defined for RAMPS_SMART currently + + #else + + // Beeper on AUX-4 + #define BEEPER_PIN P3_31 + + // Buttons are directly attached to AUX-2 + #if IS_RRW_KEYPAD + #define SHIFT_OUT_PIN 40 + #define SHIFT_CLK_PIN 44 + #define SHIFT_LD_PIN 42 + #define BTN_EN1 64 + #define BTN_EN2 59 + #define BTN_ENC 63 + #elif ENABLED(PANEL_ONE) + #define BTN_EN1 59 // AUX2 PIN 3 + #define BTN_EN2 63 // AUX2 PIN 4 + #define BTN_ENC 49 // AUX3 PIN 7 + #else + #define BTN_EN1 P3_11 + #define BTN_EN2 P3_12 + #define BTN_ENC P3_28 + #endif + + #if ENABLED(G3D_PANEL) + #define SD_DETECT_PIN 49 + #define KILL_PIN 41 + #endif + #endif + + // CUSTOM SIMULATOR INPUTS + #define BTN_BACK 70 + + #endif // IS_NEWPANEL + +#endif // HAS_WIRED_LCD diff --git a/Marlin/src/pins/pins.h b/Marlin/src/pins/pins.h index d162881993..992e6a6814 100644 --- a/Marlin/src/pins/pins.h +++ b/Marlin/src/pins/pins.h @@ -496,6 +496,13 @@ #include "lpc1769/pins_BTT_SKR_E3_TURBO.h" // LPC1769 env:LPC1769 #elif MB(FLY_CDY) #include "lpc1769/pins_FLY_CDY.h" // LPC1769 env:LPC1769 +// +// LPC4078 ARM Cortex M4 +// + +#elif MB(EBAB) + #include "lpc4078/pins_EBAB.h" // LPC4078 env:LPC4078 + // // Due (ATSAM) boards diff --git a/ini/lpc176x.ini b/ini/lpc176x.ini index 8d5d2fd157..974debe59e 100644 --- a/ini/lpc176x.ini +++ b/ini/lpc176x.ini @@ -42,3 +42,27 @@ board = nxp_lpc1768 [env:LPC1769] extends = common_LPC board = nxp_lpc1769 + +# +# NXP LPC4078 ARM Cortex-M4 +# +[env:LPC4078] +board = nxp_lpc4078 +platform = symlink://C:\Users\DMenzel\Documents\GitHub\EBAB\ebab_platform\platform-mcui +platform_packages = framework-arduino-mcui@symlink://C:\Users\DMenzel\Documents\GitHub\EBAB\ebab_platform\framework-arduino-mcui +framework = arduino +upload_protocol = jlink +debug_tool = jlink +monitor_speed = 500000 +lib_ldf_mode = off +lib_compat_mode = strict +extra_scripts = ${common.extra_scripts} + Marlin/src/HAL/LPC1768/upload_extra_script.py +build_src_filter = ${common.default_src_filter} + + +build_flags = ${common.build_flags} -IMarlin/src/HAL/LPC4078/include -DTARGET_LPC4078 -DU8G_HAL_LINKS -IMarlin/src/HAL/LPC4078/u8g -DPLATFORM_M997_SUPPORT -O3 +build_unflags = -Os +lib_deps = ${common.lib_deps} + Servo + SoftwareSerial +custom_marlin.USES_LIQUIDCRYSTAL = arduino-libraries/LiquidCrystal@~1.0.7 +custom_marlin.NEOPIXEL_LED = Adafruit NeoPixel=https://github.com/p3p/Adafruit_NeoPixel/archive/1.5.0.zip From 4d78a91cbd765fe5d61f55c24cc2fe28cdb7e12c Mon Sep 17 00:00:00 2001 From: InsanityAutomation Date: Sun, 14 Jan 2024 15:36:03 -0500 Subject: [PATCH 02/22] Update Configuration_adv.h Co-Authored-By: Chris Pepper <24342+p3p@users.noreply.github.com> --- Marlin/Configuration_adv.h | 98 +++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 1d7c1a7277..7f06b0a0a4 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -307,11 +307,11 @@ #define THERMAL_PROTECTION_PERIOD 40 // (seconds) #define THERMAL_PROTECTION_HYSTERESIS 4 // (°C) - //#define ADAPTIVE_FAN_SLOWING // Slow down the part-cooling fan if the temperature drops + #define ADAPTIVE_FAN_SLOWING // Slow down the part-cooling fan if the temperature drops #if ENABLED(ADAPTIVE_FAN_SLOWING) //#define REPORT_ADAPTIVE_FAN_SLOWING // Report fan slowing activity to the console #if ANY(MPCTEMP, PIDTEMP) - //#define TEMP_TUNING_MAINTAIN_FAN // Don't slow down the fan speed during M303 or M306 T + #define TEMP_TUNING_MAINTAIN_FAN // Don't slow down the fan speed during M303 or M306 T #endif #endif @@ -335,7 +335,7 @@ * 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_PERIOD 90 // (seconds) #define THERMAL_PROTECTION_BED_HYSTERESIS 2 // (°C) /** @@ -547,10 +547,10 @@ * Hotend Idle Timeout * Prevent filament in the nozzle from charring and causing a critical jam. */ -//#define HOTEND_IDLE_TIMEOUT +#define HOTEND_IDLE_TIMEOUT #if ENABLED(HOTEND_IDLE_TIMEOUT) - #define HOTEND_IDLE_TIMEOUT_SEC (5*60) // (seconds) Time without extruder movement to trigger protection - #define HOTEND_IDLE_MIN_TRIGGER 180 // (°C) Minimum temperature to enable hotend protection + #define HOTEND_IDLE_TIMEOUT_SEC (30*60) // (seconds) Time without extruder movement to trigger protection + #define HOTEND_IDLE_MIN_TRIGGER 170 // (°C) Minimum temperature to enable hotend protection #define HOTEND_IDLE_NOZZLE_TARGET 0 // (°C) Safe temperature for the nozzle after timeout #define HOTEND_IDLE_BED_TARGET 0 // (°C) Safe temperature for the bed after timeout #endif @@ -602,8 +602,8 @@ * 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 +#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 @@ -931,7 +931,7 @@ //#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 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 real endstop (not a probe). //#define CODEPENDENT_XY_HOMING // If X/Y can't home without homing Y/X first @@ -1020,7 +1020,7 @@ * Z Steppers Auto-Alignment * Add the G34 command to align multiple Z steppers using a bed probe. */ -//#define Z_STEPPER_AUTO_ALIGN +#define Z_STEPPER_AUTO_ALIGN #if ENABLED(Z_STEPPER_AUTO_ALIGN) /** * Define probe X and Y positions for Z1, Z2 [, Z3 [, Z4]] @@ -1281,7 +1281,7 @@ // Backlash Compensation // Adds extra movement to axes on direction-changes to account for backlash. // -//#define BACKLASH_COMPENSATION +#define BACKLASH_COMPENSATION #if ENABLED(BACKLASH_COMPENSATION) // Define values for backlash distance and correction. // If BACKLASH_GCODE is enabled these values are the defaults. @@ -1296,7 +1296,7 @@ //#define BACKLASH_SMOOTHING_MM 3 // (mm) // Add runtime configuration and tuning of backlash values (M425) - //#define BACKLASH_GCODE + #define BACKLASH_GCODE #if ENABLED(BACKLASH_GCODE) // Measure the Z backlash when probing (G29) and set with "M425 Z" @@ -1342,7 +1342,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 flash). + // Uncomment to enable reporting (required for "G425 V", but consumes PROGMEM). //#define CALIBRATION_REPORTING // The true location and dimension the cube/bolt/washer on the bed. @@ -1528,7 +1528,7 @@ #endif // Include a page of printer information in the LCD Main Menu - //#define LCD_INFO_MENU + #define LCD_INFO_MENU #if ENABLED(LCD_INFO_MENU) //#define LCD_PRINTER_INFO_IS_BOOTSCREEN // Show bootscreen(s) instead of Printer Info pages #endif @@ -1580,7 +1580,7 @@ #define BOOT_MARLIN_LOGO_SMALL // Show a smaller Marlin logo on the Boot Screen (saving lots of flash) #endif #if HAS_MARLINUI_U8GLIB - //#define BOOT_MARLIN_LOGO_ANIMATED // Animated Marlin logo. Costs ~3260 (or ~940) bytes of flash. + #define BOOT_MARLIN_LOGO_ANIMATED // Animated Marlin logo. Costs ~3260 (or ~940) bytes of flash. #endif #if ANY(HAS_MARLINUI_U8GLIB, TOUCH_UI_FTDI_EVE) //#define SHOW_CUSTOM_BOOTSCREEN // Show the bitmap in Marlin/_Bootscreen.h on startup. @@ -1599,10 +1599,10 @@ #endif // The timeout to return to the status screen from sub-menus - //#define LCD_TIMEOUT_TO_STATUS 15000 // (ms) + #define LCD_TIMEOUT_TO_STATUS 15000 // (ms) // Scroll a longer status message into view - //#define STATUS_MESSAGE_SCROLLING + #define STATUS_MESSAGE_SCROLLING // Apply a timeout to low-priority status messages //#define STATUS_MESSAGE_TIMEOUT_SEC 30 // (seconds) @@ -1654,7 +1654,7 @@ #endif // Add 'M73' to set print job progress, overrides Marlin's built-in estimate -//#define SET_PROGRESS_MANUALLY +#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 @@ -1806,13 +1806,13 @@ // Allow international symbols in long filenames. To display correctly, the // LCD's font must contain the characters. Check your selected LCD language. - //#define UTF_FILENAME_SUPPORT + #define UTF_FILENAME_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_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 - //#define SCROLL_LONG_FILENAMES // Scroll long filenames in the SD card menu + #define SCROLL_LONG_FILENAMES // Scroll long filenames in the SD card menu //#define SD_ABORT_NO_COOLDOWN // Leave the heaters on after Stop Print (not recommended!) @@ -2263,18 +2263,18 @@ * * Warning: Does not respect endstops! */ -//#define BABYSTEPPING +#define BABYSTEPPING #if ENABLED(BABYSTEPPING) //#define EP_BABYSTEPPING // M293/M294 babystepping with EMERGENCY_PARSER support //#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 // Enable if Z babysteps should go the other way //#define BABYSTEP_MILLIMETER_UNITS // Specify BABYSTEP_MULTIPLICATOR_(XY|Z) in mm instead of micro-steps - #define BABYSTEP_MULTIPLICATOR_Z 1 // (steps or mm) Steps or millimeter distance for each Z babystep + #define BABYSTEP_MULTIPLICATOR_Z 25 // (steps or mm) Steps or millimeter distance for each Z babystep #define BABYSTEP_MULTIPLICATOR_XY 1 // (steps or mm) Steps or millimeter distance for each XY babystep - //#define DOUBLECLICK_FOR_Z_BABYSTEPPING // Double-click on the Status Screen for Z Babystepping. + #define DOUBLECLICK_FOR_Z_BABYSTEPPING // Double-click on the Status Screen for Z Babystepping. #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. @@ -2286,10 +2286,10 @@ //#define BABYSTEP_DISPLAY_TOTAL // Display total babysteps since last G28 - //#define BABYSTEP_ZPROBE_OFFSET // Combine M851 Z and Babystepping + #define BABYSTEP_ZPROBE_OFFSET // Combine M851 Z and Babystepping #if ENABLED(BABYSTEP_ZPROBE_OFFSET) //#define BABYSTEP_HOTEND_Z_OFFSET // For multiple hotends, babystep relative Z offsets - //#define BABYSTEP_GFX_OVERLAY // Enable graphical overlay on Z-offset editor + #define BABYSTEP_GFX_OVERLAY // Enable graphical overlay on Z-offset editor #endif #endif @@ -2310,7 +2310,7 @@ * * See https://marlinfw.org/docs/features/lin_advance.html for full instructions. */ -//#define LIN_ADVANCE +#define LIN_ADVANCE #if ENABLED(LIN_ADVANCE) #if ENABLED(DISTINCT_E_FACTORS) #define ADVANCE_K { 0.22 } // (mm) Compression length per 1mm/s extruder speed, per extruder @@ -2319,7 +2319,7 @@ #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 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 @@ -2504,7 +2504,7 @@ #endif // G5 Bézier Curve Support with XYZE destination and IJPQ offsets -//#define BEZIER_CURVE_SUPPORT // Requires ~2666 bytes +#define BEZIER_CURVE_SUPPORT // Requires ~2666 bytes #if ANY(ARC_SUPPORT, BEZIER_CURVE_SUPPORT) //#define CNC_WORKSPACE_PLANES // Allow G2/G3/G5 to operate in XY, ZX, or YZ planes @@ -2596,16 +2596,16 @@ #if ALL(HAS_MEDIA, DIRECT_STEPPING) #define BLOCK_BUFFER_SIZE 8 #elif HAS_MEDIA - #define BLOCK_BUFFER_SIZE 16 + #define BLOCK_BUFFER_SIZE 32 #else - #define BLOCK_BUFFER_SIZE 16 + #define BLOCK_BUFFER_SIZE 32 #endif // @section serial // The ASCII buffer for serial input #define MAX_CMD_SIZE 96 -#define BUFSIZE 4 +#define BUFSIZE 16 // Transmission to Host Buffer Size // To save 386 bytes of flash (and TX_BUFFER_SIZE+3 bytes of RAM) set to 0. @@ -2652,7 +2652,7 @@ * Currently handles M108, M112, M410, M876 * NOTE: Not yet implemented for all platforms. */ -//#define EMERGENCY_PARSER +#define EMERGENCY_PARSER /** * Realtime Reporting (requires EMERGENCY_PARSER) @@ -2683,7 +2683,7 @@ //#define NO_TIMEOUTS 1000 // (ms) // Some clients will have this feature soon. This could make the NO_TIMEOUTS unnecessary. -//#define ADVANCED_OK +#define ADVANCED_OK // Printrun may have trouble receiving long strings all at once. // This option inserts short delays between lines of serial output. @@ -2885,7 +2885,7 @@ * * Enable PARK_HEAD_ON_PAUSE to add the G-code M125 Pause and Park. */ -//#define ADVANCED_PAUSE_FEATURE +#define ADVANCED_PAUSE_FEATURE #if ENABLED(ADVANCED_PAUSE_FEATURE) #define PAUSE_PARK_RETRACT_FEEDRATE 60 // (mm/s) Initial retract feedrate. #define PAUSE_PARK_RETRACT_LENGTH 2 // (mm) Initial retract. @@ -2925,11 +2925,11 @@ //#define FILAMENT_CHANGE_RESUME_ON_INSERT // Automatically continue / load filament when runout sensor is triggered again. //#define PAUSE_REHEAT_FAST_RESUME // Reduce number of waits by not prompting again post-timeout before continuing. - //#define PARK_HEAD_ON_PAUSE // Park the nozzle during pause and filament change. + #define PARK_HEAD_ON_PAUSE // Park the nozzle during pause and filament change. //#define HOME_BEFORE_FILAMENT_CHANGE // If needed, home before parking for filament change - //#define FILAMENT_LOAD_UNLOAD_GCODES // Add M701/M702 Load/Unload G-codes, plus Load/Unload in the LCD Prepare menu. - //#define FILAMENT_UNLOAD_ALL_EXTRUDERS // Allow M702 to unload all extruders above a minimum target temp (as set by M302) + #define FILAMENT_LOAD_UNLOAD_GCODES // Add M701/M702 Load/Unload G-codes, plus Load/Unload in the LCD Prepare menu. + #define FILAMENT_UNLOAD_ALL_EXTRUDERS // Allow M702 to unload all extruders above a minimum target temp (as set by M302) #define CONFIGURE_FILAMENT_CHANGE // Add M603 G-code and menu items. Requires ~1.3K bytes of flash. #endif @@ -3110,7 +3110,7 @@ #endif #if AXIS_IS_TMC_CONFIG(E0) - #define E0_CURRENT 800 + #define E0_CURRENT 900 #define E0_MICROSTEPS 16 #define E0_RSENSE 0.11 #define E0_CHAIN_POS -1 @@ -3283,7 +3283,7 @@ #define STEALTHCHOP_U #define STEALTHCHOP_V #define STEALTHCHOP_W - #define STEALTHCHOP_E + //#define STEALTHCHOP_E #endif /** @@ -3301,7 +3301,7 @@ * Define your own with: * { , , hysteresis_start[1..8] } */ - #define CHOPPER_TIMING CHOPPER_DEFAULT_12V // All axes (override below) + #define CHOPPER_TIMING CHOPPER_DEFAULT_24V // All axes (override below) //#define CHOPPER_TIMING_X CHOPPER_TIMING // For X Axes (override below) //#define CHOPPER_TIMING_X2 CHOPPER_TIMING_X //#define CHOPPER_TIMING_Y CHOPPER_TIMING // For Y Axes (override below) @@ -3445,7 +3445,7 @@ /** * Step on both rising and falling edge signals (as with a square wave). */ - //#define EDGE_STEPPING + #define EDGE_STEPPING /** * Enable M122 debugging command for TMC stepper drivers. @@ -4114,14 +4114,14 @@ * 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 // Tell the host to pause in response to M76 - //#define HOST_PROMPT_SUPPORT // Initiate host prompts to get user feedback + #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 + #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_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 @@ -4489,12 +4489,12 @@ // // M42 - Set pin states // -//#define DIRECT_PIN_CONTROL +#define DIRECT_PIN_CONTROL // // M43 - display pin status, toggle pins, watch pins, watch endstops & toggle LED, test servo probe // -//#define PINS_DEBUGGING +#define PINS_DEBUGGING // Enable Tests that will run at startup and produce a report //#define MARLIN_TEST_BUILD From bef646d52c6d8270bd96e9760ef023ce2cb1ebad Mon Sep 17 00:00:00 2001 From: InsanityAutomation Date: Sun, 14 Jan 2024 15:17:45 -0500 Subject: [PATCH 03/22] Redundant Power control with EDM - First Pass --- Marlin/Configuration.h | 11 ++++++++++- Marlin/src/MarlinCore.cpp | 19 +++++++++++++++++++ Marlin/src/feature/power.cpp | 25 +++++++++++++++++++++++++ Marlin/src/feature/power.h | 6 +++++- Marlin/src/inc/SanityCheck.h | 2 ++ Marlin/src/lcd/language/language_en.h | 2 ++ Marlin/src/pins/pinsDebug_list.h | 3 +++ Marlin/src/pins/pins_postprocess.h | 4 ++++ 8 files changed, 70 insertions(+), 2 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 625cf35ab8..7957be41ea 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -392,7 +392,7 @@ * Enable and connect the power supply to the PS_ON_PIN. * Specify whether the power supply is active HIGH or active LOW. */ -//#define PSU_CONTROL +#define PSU_CONTROL //#define PSU_NAME "Power Supply" #if ENABLED(PSU_CONTROL) @@ -405,6 +405,15 @@ //#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 PSU_OFF_REDUNDANT // Second pin for redundant power control + //#define PSU_OFF_REDUNDANT_OPPOSING // Redundant pin works opposite standard pin + + #define PS_ON1_PIN 6 // Redundant Pin + + #define PS_ON_EDM_PIN 8 // EDM Pins to monitor feedback on external power control relay. Fault on mismatch. + #define PS_ON1_EDM_PIN 8 + #define PS_EDM_RESPONSE 250 // Time in MS to allow for relay action + //#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 diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index 91496b1c5c..e571d3ce9a 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -671,6 +671,25 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { TERN_(HOTEND_IDLE_TIMEOUT, hotend_idle.check()); + #if ANY(PSU_CONTROL, AUTO_POWER_CONTROL) + #if defined(PS_ON_EDM_PIN) + if(ELAPSED(ms, powerManager.last_state_change_ms + PS_EDM_RESPONSE)) + { + if(READ(PS_ON_PIN)!=READ(PS_ON_EDM_PIN)) + kill(GET_TEXT_F(PS_ON_EDM_FAIL)); + } + #endif + + #if defined(PS_ON_EDM_PIN) && ENABLED(PSU_OFF_REDUNDANT) + if(ELAPSED(ms, powerManager.last_state_change_ms + PS_EDM_RESPONSE)) + { + if(READ(PS_ON1_PIN)!=READ(PS_ON1_EDM_PIN)) + kill(GET_TEXT_F(PS_ON1_EDM_FAIL)); + } + + #endif + #endif + #if ENABLED(EXTRUDER_RUNOUT_PREVENT) if (thermalManager.degHotend(active_extruder) > (EXTRUDER_RUNOUT_MINTEMP) && ELAPSED(ms, gcode.previous_move_ms + SEC_TO_MS(EXTRUDER_RUNOUT_SECONDS)) diff --git a/Marlin/src/feature/power.cpp b/Marlin/src/feature/power.cpp index e908c8292f..c003be1363 100644 --- a/Marlin/src/feature/power.cpp +++ b/Marlin/src/feature/power.cpp @@ -60,6 +60,10 @@ bool Power::psu_on; millis_t Power::lastPowerOn; #endif +#if defined(PS_ON_EDM_PIN) || (defined(PS_ON_EDM_PIN) && ENABLED(PSU_OFF_REDUNDANT)) + static millis_t Power::last_state_change_ms = 0; +#endif + /** * Initialize pins & state for the power manager. * @@ -87,6 +91,16 @@ void Power::power_on() { #endif OUT_WRITE(PS_ON_PIN, PSU_ACTIVE_STATE); + #if ENABLED(PSU_OFF_REDUNDANT) + #if (ENABLED(PSU_OFF_REDUNDANT_OPPOSING)) + OUT_WRITE(PS_ON1_PIN, !PSU_ACTIVE_STATE); + #else + OUT_WRITE(PS_ON1_PIN, PSU_ACTIVE_STATE); + #endif + #endif + #if defined(PS_ON_EDM_PIN) || (defined(PS_ON_EDM_PIN) && ENABLED(PSU_OFF_REDUNDANT)) + last_state_change_ms = millis(); + #endif psu_on = true; safe_delay(PSU_POWERUP_DELAY); restore_stepper_drivers(); @@ -117,6 +131,17 @@ void Power::power_off() { #endif OUT_WRITE(PS_ON_PIN, !PSU_ACTIVE_STATE); + #if ENABLED(PSU_OFF_REDUNDANT) + #if (ENABLED(PSU_OFF_REDUNDANT_OPPOSING)) + OUT_WRITE(PS_ON1_PIN, PSU_ACTIVE_STATE); + #else + OUT_WRITE(PS_ON1_PIN, !PSU_ACTIVE_STATE); + #endif + #endif + #if defined(PS_ON_EDM_PIN) || (defined(PS_ON_EDM_PIN) && ENABLED(PSU_OFF_REDUNDANT)) + last_state_change_ms = millis(); + #endif + psu_on = false; #if ANY(POWER_OFF_TIMER, POWER_OFF_WAIT_FOR_COOLDOWN) diff --git a/Marlin/src/feature/power.h b/Marlin/src/feature/power.h index fdbb7126ce..480c6e8a5b 100644 --- a/Marlin/src/feature/power.h +++ b/Marlin/src/feature/power.h @@ -25,7 +25,7 @@ * power.h - power control */ -#if ANY(AUTO_POWER_CONTROL, POWER_OFF_TIMER) +#if ANY(AUTO_POWER_CONTROL, POWER_OFF_TIMER) || defined(PS_ON_EDM_PIN) || (defined(PS_ON_EDM_PIN) && ENABLED(PSU_OFF_REDUNDANT)) #include "../core/millis_t.h" #endif @@ -37,6 +37,10 @@ class Power { static void power_on(); static void power_off(); + #if defined(PS_ON_EDM_PIN) || (defined(PS_ON_EDM_PIN) && ENABLED(PSU_OFF_REDUNDANT)) + static millis_t last_state_change_ms; + #endif + #if ANY(POWER_OFF_TIMER, POWER_OFF_WAIT_FOR_COOLDOWN) #if ENABLED(POWER_OFF_TIMER) static millis_t power_off_time; diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index a60ead1d08..796a3d78de 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -3641,6 +3641,8 @@ static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive." #error "POWER_OFF_DELAY must be a positive value." #elif ENABLED(POWER_OFF_WAIT_FOR_COOLDOWN) && !(defined(AUTO_POWER_E_TEMP) || defined(AUTO_POWER_CHAMBER_TEMP) || defined(AUTO_POWER_COOLER_TEMP)) #error "POWER_OFF_WAIT_FOR_COOLDOWN requires AUTO_POWER_E_TEMP, AUTO_POWER_CHAMBER_TEMP, and/or AUTO_POWER_COOLER_TEMP." + #elif ENABLED(PSU_OFF_REDUNDANT) && !PIN_EXISTS(PS_ON1) + #error "PSU_OFF_REDUNDANT requires PS_ON1_PIN." #endif #endif diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index 553d9013a2..6ccb76de43 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -155,6 +155,8 @@ namespace LanguageNarrow_en { LSTR MSG_SPINDLE_REVERSE = _UxGT("Spindle Reverse"); LSTR MSG_SWITCH_PS_ON = _UxGT("Switch Power On"); LSTR MSG_SWITCH_PS_OFF = _UxGT("Switch Power Off"); + LSTR PS_ON_EDM_FAIL = _UxGT("PS_ON EDM Fault"); + LSTR PS_ON1_EDM_FAIL = _UxGT("PS_ON1 EDM Fault"); LSTR MSG_EXTRUDE = _UxGT("Extrude"); LSTR MSG_RETRACT = _UxGT("Retract"); LSTR MSG_MOVE_AXIS = _UxGT("Move Axis"); diff --git a/Marlin/src/pins/pinsDebug_list.h b/Marlin/src/pins/pinsDebug_list.h index fa6cbf49b9..58f42598a0 100644 --- a/Marlin/src/pins/pinsDebug_list.h +++ b/Marlin/src/pins/pinsDebug_list.h @@ -901,6 +901,9 @@ #if PIN_EXISTS(PS_ON) REPORT_NAME_DIGITAL(__LINE__, PS_ON_PIN) #endif +#if PIN_EXISTS(PS_ON1) + REPORT_NAME_DIGITAL(__LINE__, PS_ON1_PIN) +#endif // // LCD diff --git a/Marlin/src/pins/pins_postprocess.h b/Marlin/src/pins/pins_postprocess.h index e97b6ceaa4..e8c77a08cd 100644 --- a/Marlin/src/pins/pins_postprocess.h +++ b/Marlin/src/pins/pins_postprocess.h @@ -477,6 +477,10 @@ #undef PS_ON_PIN #define PS_ON_PIN -1 #endif +#if DISABLED(PSU_OFF_REDUNDANT) || DISABLED(PSU_CONTROL) || !defined(PS_ON1_PIN) + #undef PS_ON1_PIN + #define PS_ON1_PIN -1 +#endif #ifndef KILL_PIN #define KILL_PIN -1 #endif From a44871b272cafe9570f19b7931e42da1062d7c80 Mon Sep 17 00:00:00 2001 From: InsanityAutomation Date: Sun, 14 Jan 2024 15:38:54 -0500 Subject: [PATCH 04/22] Update Configuration.h --- Marlin/Configuration.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 7957be41ea..929b2f3f3b 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -407,11 +407,11 @@ #define PSU_OFF_REDUNDANT // Second pin for redundant power control //#define PSU_OFF_REDUNDANT_OPPOSING // Redundant pin works opposite standard pin + #define PS_ON_PIN P4_28 // Redundant Pin + #define PS_ON1_PIN P1_03 // Redundant Pin - #define PS_ON1_PIN 6 // Redundant Pin - - #define PS_ON_EDM_PIN 8 // EDM Pins to monitor feedback on external power control relay. Fault on mismatch. - #define PS_ON1_EDM_PIN 8 + #define PS_ON_EDM_PIN P4_29 // EDM Pins to monitor feedback on external power control relay. Fault on mismatch. + #define PS_ON1_EDM_PIN P1_17 #define PS_EDM_RESPONSE 250 // Time in MS to allow for relay action //#define POWER_OFF_TIMER // Enable M81 D to power off after a delay @@ -420,7 +420,7 @@ //#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 + #define AUTO_POWER_CONTROL // Enable automatic control of the PS_ON pin #if ENABLED(AUTO_POWER_CONTROL) #define AUTO_POWER_FANS // Turn on PSU for fans #define AUTO_POWER_E_FANS // Turn on PSU for E Fans From 6087ab634799db328222f8e50f457e53622603c5 Mon Sep 17 00:00:00 2001 From: InsanityAutomation Date: Sun, 14 Jan 2024 15:41:52 -0500 Subject: [PATCH 05/22] Tweaks --- Marlin/Configuration.h | 2 +- Marlin/src/feature/power.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 929b2f3f3b..531057de3f 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -399,7 +399,7 @@ //#define MKS_PWC // Using the MKS PWC add-on //#define PS_OFF_CONFIRM // Confirm dialog when power off //#define PS_OFF_SOUND // Beep 1s when power off - #define PSU_ACTIVE_STATE LOW // Set 'LOW' for ATX, 'HIGH' for X-Box + #define PSU_ACTIVE_STATE HIGH // 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 diff --git a/Marlin/src/feature/power.cpp b/Marlin/src/feature/power.cpp index c003be1363..6fa91b3826 100644 --- a/Marlin/src/feature/power.cpp +++ b/Marlin/src/feature/power.cpp @@ -61,7 +61,7 @@ bool Power::psu_on; #endif #if defined(PS_ON_EDM_PIN) || (defined(PS_ON_EDM_PIN) && ENABLED(PSU_OFF_REDUNDANT)) - static millis_t Power::last_state_change_ms = 0; + millis_t Power::last_state_change_ms = 0; #endif /** From 03162423477095d4617830d38e65982e118aeeea Mon Sep 17 00:00:00 2001 From: InsanityAutomation Date: Thu, 18 Jan 2024 22:36:36 -0500 Subject: [PATCH 06/22] Fix interupts and pin debugging --- Marlin/Configuration.h | 20 ++++++++++---------- Marlin/Configuration_adv.h | 6 +++--- Marlin/src/HAL/LPC4078/HAL.h | 11 ++++++++++- Marlin/src/pins/lpc4078/pins_EBAB.h | 3 +-- ini/lpc176x.ini | 3 ++- 5 files changed, 26 insertions(+), 17 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 531057de3f..8b2399674e 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -139,14 +139,14 @@ * TMC5130, TMC5130_STANDALONE, TMC5160, TMC5160_STANDALONE * :['A4988', 'A5984', 'DRV8825', 'LV8729', 'TB6560', 'TB6600', 'TMC2100', 'TMC2130', 'TMC2130_STANDALONE', 'TMC2160', 'TMC2160_STANDALONE', 'TMC2208', 'TMC2208_STANDALONE', 'TMC2209', 'TMC2209_STANDALONE', 'TMC26X', 'TMC26X_STANDALONE', 'TMC2660', 'TMC2660_STANDALONE', 'TMC5130', 'TMC5130_STANDALONE', 'TMC5160', 'TMC5160_STANDALONE'] */ -#define X_DRIVER_TYPE TB6560 -#define Y_DRIVER_TYPE TB6560 -#define Z_DRIVER_TYPE TB6560 +#define X_DRIVER_TYPE TB6600 +#define Y_DRIVER_TYPE TB6600 +#define Z_DRIVER_TYPE TB6600 //#define X2_DRIVER_TYPE A4988 -#define Y2_DRIVER_TYPE TB6560 -#define Z2_DRIVER_TYPE TB6560 -#define Z3_DRIVER_TYPE TB6560 -#define Z4_DRIVER_TYPE TB6560 +#define Y2_DRIVER_TYPE TB6600 +#define Z2_DRIVER_TYPE TB6600 +#define Z3_DRIVER_TYPE TB6600 +#define Z4_DRIVER_TYPE TB6600 //#define I_DRIVER_TYPE A4988 //#define J_DRIVER_TYPE A4988 //#define K_DRIVER_TYPE A4988 @@ -392,7 +392,7 @@ * Enable and connect the power supply to the PS_ON_PIN. * Specify whether the power supply is active HIGH or active LOW. */ -#define PSU_CONTROL +//#define PSU_CONTROL //#define PSU_NAME "Power Supply" #if ENABLED(PSU_CONTROL) @@ -1177,9 +1177,9 @@ * Endstop "Hit" State * Set to the state (HIGH or LOW) that applies to each endstop. */ -#define X_MIN_ENDSTOP_HIT_STATE HIGH +#define X_MIN_ENDSTOP_HIT_STATE LOW #define X_MAX_ENDSTOP_HIT_STATE HIGH -#define Y_MIN_ENDSTOP_HIT_STATE HIGH +#define Y_MIN_ENDSTOP_HIT_STATE LOW #define Y_MAX_ENDSTOP_HIT_STATE HIGH #define Z_MIN_ENDSTOP_HIT_STATE HIGH #define Z_MAX_ENDSTOP_HIT_STATE HIGH diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 7f06b0a0a4..a3b9360320 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1913,7 +1913,7 @@ * * :[ 'LCD', 'ONBOARD', 'CUSTOM_CABLE' ] */ - //#define SDCARD_CONNECTION LCD + #define SDCARD_CONNECTION ONBOARD // Enable if SD detect is rendered useless (e.g., by using an SD extender) //#define NO_SD_DETECT @@ -2565,7 +2565,7 @@ * * Override the default value based on the driver type set in Configuration.h. */ -//#define MINIMUM_STEPPER_PULSE 2 +#define MINIMUM_STEPPER_PULSE 10 /** * Maximum stepping rate (in Hz) the stepper driver allows @@ -2579,7 +2579,7 @@ * * Override the default value based on the driver type set in Configuration.h. */ -//#define MAXIMUM_STEPPER_RATE 250000 +#define MAXIMUM_STEPPER_RATE 150000 // @section temperature diff --git a/Marlin/src/HAL/LPC4078/HAL.h b/Marlin/src/HAL/LPC4078/HAL.h index c4803909a7..ceaac6492f 100644 --- a/Marlin/src/HAL/LPC4078/HAL.h +++ b/Marlin/src/HAL/LPC4078/HAL.h @@ -108,7 +108,8 @@ extern DefaultSerial1 USBSerial; #define CRITICAL_SECTION_START() const bool irqon = !MCUCore::primask(); MCUCore::nvic_interrupts_disable() #define CRITICAL_SECTION_END() if (irqon) MCUCore::nvic_interrupts_enable() - +#define cli() noInterrupts() +#define sei() interrupts() // // ADC // @@ -143,6 +144,14 @@ constexpr int8_t DIGITAL_PIN_TO_ANALOG_PIN(const pin_t pin) { return (MCUI::pin_is_valid(pin) && MCUI::pin_has_adc(pin)) ? pin : -1; } +// +// Misc. Functions +// +#ifndef analogInputToDigitalPin + #define analogInputToDigitalPin(p) (p) +#endif + + // Return the index of a pin number constexpr int16_t GET_PIN_MAP_INDEX(const pin_t pin) { return MCUI::pin_index(pin); diff --git a/Marlin/src/pins/lpc4078/pins_EBAB.h b/Marlin/src/pins/lpc4078/pins_EBAB.h index 83fa5bac4f..6e2e1ccb04 100644 --- a/Marlin/src/pins/lpc4078/pins_EBAB.h +++ b/Marlin/src/pins/lpc4078/pins_EBAB.h @@ -33,7 +33,6 @@ // EXTRA PINS #define FIL_RUNOUT_PIN P1_12 -#define PS_ON_PIN P3_15 // DRIVERS EXTRA PINS #define DRIVERS_SCK P1_20 @@ -234,7 +233,7 @@ #endif #ifndef PS_ON_PIN - #define PS_ON_PIN P_NC + //#define PS_ON_PIN P_NC #endif // diff --git a/ini/lpc176x.ini b/ini/lpc176x.ini index 974debe59e..f617bb40fe 100644 --- a/ini/lpc176x.ini +++ b/ini/lpc176x.ini @@ -27,7 +27,8 @@ lib_deps = ${common.lib_deps} custom_marlin.USES_LIQUIDCRYSTAL = arduino-libraries/LiquidCrystal@~1.0.7 custom_marlin.NEOPIXEL_LED = Adafruit NeoPixel=https://github.com/p3p/Adafruit_NeoPixel/archive/1.5.0.zip build_flags = ${common.build_flags} -DU8G_HAL_LINKS -DPLATFORM_M997_SUPPORT - -IMarlin/src/HAL/LPC1768/include -IMarlin/src/HAL/LPC1768/u8g + -IMarlin/src/HAL/LPC1768/include -IMarlin/src/HAL/LPC1768/u8g -O3 +build_unflags = -Os # debug options for backtrace #-funwind-tables #-mpoke-function-name From ca1869034951b1eedbe24b32b1dfad42956fc4fb Mon Sep 17 00:00:00 2001 From: InsanityAutomation Date: Tue, 30 Jan 2024 11:52:57 -0500 Subject: [PATCH 07/22] Change read function for PS_ON and EDM pins --- Marlin/Configuration.h | 10 +++++----- Marlin/src/MarlinCore.cpp | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 8b2399674e..25604a6c77 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -153,7 +153,7 @@ //#define U_DRIVER_TYPE A4988 //#define V_DRIVER_TYPE A4988 //#define W_DRIVER_TYPE A4988 -#define E0_DRIVER_TYPE TMC2209 +#define E0_DRIVER_TYPE TMC2209_STANDALONE //#define E1_DRIVER_TYPE A4988 //#define E2_DRIVER_TYPE A4988 //#define E3_DRIVER_TYPE A4988 @@ -392,7 +392,7 @@ * Enable and connect the power supply to the PS_ON_PIN. * Specify whether the power supply is active HIGH or active LOW. */ -//#define PSU_CONTROL +#define PSU_CONTROL //#define PSU_NAME "Power Supply" #if ENABLED(PSU_CONTROL) @@ -401,8 +401,8 @@ //#define PS_OFF_SOUND // Beep 1s when power off #define PSU_ACTIVE_STATE HIGH // 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 750 // (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 PSU_OFF_REDUNDANT // Second pin for redundant power control @@ -412,7 +412,7 @@ #define PS_ON_EDM_PIN P4_29 // EDM Pins to monitor feedback on external power control relay. Fault on mismatch. #define PS_ON1_EDM_PIN P1_17 - #define PS_EDM_RESPONSE 250 // Time in MS to allow for relay action + #define PS_EDM_RESPONSE 1000 // Time in MS to allow for relay action //#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 diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index e571d3ce9a..9d7bada97f 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -683,7 +683,7 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) { #if defined(PS_ON_EDM_PIN) && ENABLED(PSU_OFF_REDUNDANT) if(ELAPSED(ms, powerManager.last_state_change_ms + PS_EDM_RESPONSE)) { - if(READ(PS_ON1_PIN)!=READ(PS_ON1_EDM_PIN)) + if(extDigitalRead(PS_ON1_PIN)!=extDigitalRead(PS_ON1_EDM_PIN)) kill(GET_TEXT_F(PS_ON1_EDM_FAIL)); } From 7150d0eb5c9fb30dd3d92654ba63d3133c8b1d3e Mon Sep 17 00:00:00 2001 From: ellensp <530024+ellensp@users.noreply.github.com> Date: Wed, 31 Jan 2024 17:56:46 +1300 Subject: [PATCH 08/22] =?UTF-8?q?=F0=9F=94=A8=20No=20strlcpy=20in=20Window?= =?UTF-8?q?s=20(#26748)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ini/native.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/ini/native.ini b/ini/native.ini index 86608ff3d7..ba5ddbc4cc 100644 --- a/ini/native.ini +++ b/ini/native.ini @@ -140,5 +140,4 @@ build_src_flags = ${simulator_common.build_src_flags} -fpermissive build_flags = ${simulator_common.build_flags} ${simulator_common.debug_build_flags} -IC:\\msys64\\mingw64\\include\\SDL2 -fno-stack-protector -Wl,-subsystem,windows -ldl -lmingw32 -lSDL2main -lSDL2 -lSDL2_net -lopengl32 -lssp - -DHAS_LIBBSD build_type = debug From 7f339f7001d92c120606dfc1092e1e4dfe2df289 Mon Sep 17 00:00:00 2001 From: InsanityAutomation Date: Wed, 6 Mar 2024 10:53:00 -0500 Subject: [PATCH 09/22] tmc5160 and spi --- Marlin/Configuration_adv.h | 24 +-- Marlin/src/HAL/LPC4078/HAL_SPI.cpp | 234 +++++++++-------------- Marlin/src/HAL/LPC4078/include/SPI.h | 34 ++-- Marlin/src/pins/linux/pins_RAMPS_LINUX.h | 12 ++ Marlin/src/pins/lpc4078/pins_EBAB.h | 12 +- 5 files changed, 144 insertions(+), 172 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index a3b9360320..f8aca9aa99 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2961,7 +2961,7 @@ */ #if HAS_TRINAMIC_CONFIG || HAS_TMC26X - #define HOLD_MULTIPLIER 0.5 // Scales down the holding current from run current + #define HOLD_MULTIPLIER 0.7 // Scales down the holding current from run current /** * Interpolate microsteps to 256 @@ -2973,7 +2973,7 @@ #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_MICROSTEPS 16 // 0..256 - #define X_RSENSE 0.11 // Multiplied x1000 for TMC26X + #define X_RSENSE 0.022 // 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 @@ -2993,7 +2993,7 @@ #define Y_CURRENT 800 #define Y_CURRENT_HOME Y_CURRENT #define Y_MICROSTEPS 16 - #define Y_RSENSE 0.11 + #define Y_RSENSE 0.022 #define Y_CHAIN_POS -1 //#define Y_INTERPOLATE true //#define Y_HOLD_MULTIPLIER 0.5 @@ -3215,7 +3215,7 @@ * The default SW SPI pins are defined the respective pins files, * but you can override or define them here. */ - //#define TMC_USE_SW_SPI + #define TMC_USE_SW_SPI //#define TMC_SPI_MOSI -1 //#define TMC_SPI_MISO -1 //#define TMC_SPI_SCK -1 @@ -3275,7 +3275,7 @@ * When disabled, Marlin will use spreadCycle stepping mode. */ #if HAS_STEALTHCHOP - #define STEALTHCHOP_XY + //#define STEALTHCHOP_XY #define STEALTHCHOP_Z #define STEALTHCHOP_I #define STEALTHCHOP_J @@ -3301,11 +3301,11 @@ * Define your own with: * { , , hysteresis_start[1..8] } */ - #define CHOPPER_TIMING CHOPPER_DEFAULT_24V // All axes (override below) - //#define CHOPPER_TIMING_X CHOPPER_TIMING // For X Axes (override below) + //#define CHOPPER_TIMING CHOPPER_DEFAULT_36V // All axes (override below) + #define CHOPPER_TIMING_X CHOPPER_DEFAULT_36V // For X Axes (override below) //#define CHOPPER_TIMING_X2 CHOPPER_TIMING_X - //#define CHOPPER_TIMING_Y CHOPPER_TIMING // For Y Axes (override below) - //#define CHOPPER_TIMING_Y2 CHOPPER_TIMING_Y + #define CHOPPER_TIMING_Y CHOPPER_DEFAULT_36V // For Y Axes (override below) + #define CHOPPER_TIMING_Y2 CHOPPER_TIMING_Y //#define CHOPPER_TIMING_Z CHOPPER_TIMING // For Z Axes (override below) //#define CHOPPER_TIMING_Z2 CHOPPER_TIMING_Z //#define CHOPPER_TIMING_Z3 CHOPPER_TIMING_Z @@ -3316,7 +3316,7 @@ //#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_E CHOPPER_DEFAULT_24V // For Extruders (override below) //#define CHOPPER_TIMING_E1 CHOPPER_TIMING_E //#define CHOPPER_TIMING_E2 CHOPPER_TIMING_E //#define CHOPPER_TIMING_E3 CHOPPER_TIMING_E @@ -3338,12 +3338,12 @@ * M912 - Clear stepper driver overtemperature pre-warn condition flag. * M122 - Report driver parameters (Requires TMC_DEBUG) */ - //#define MONITOR_DRIVER_STATUS + #define MONITOR_DRIVER_STATUS #if ENABLED(MONITOR_DRIVER_STATUS) #define CURRENT_STEP_DOWN 50 // [mA] #define REPORT_CURRENT_CHANGE - #define STOP_ON_ERROR + //#define STOP_ON_ERROR #endif // @section tmc/hybrid diff --git a/Marlin/src/HAL/LPC4078/HAL_SPI.cpp b/Marlin/src/HAL/LPC4078/HAL_SPI.cpp index 3af5677fbc..4aefb25143 100644 --- a/Marlin/src/HAL/LPC4078/HAL_SPI.cpp +++ b/Marlin/src/HAL/LPC4078/HAL_SPI.cpp @@ -164,123 +164,103 @@ // /** // * @brief Wait until TXE (tx empty) flag is set and BSY (busy) flag unset. // */ -// static inline void waitSpiTxEnd(LPC_SSP_TypeDef *spi_d) { -// while (SSP_GetStatus(spi_d, SSP_STAT_TXFIFO_EMPTY) == RESET) { /* nada */ } // wait until TXE=1 -// while (SSP_GetStatus(spi_d, SSP_STAT_BUSY) == SET) { /* nada */ } // wait until BSY=0 -// } +static inline void waitSpiTxEnd(void *spi_d) { + #warning unimplemented + // while (SSP_GetStatus(spi_d, SSP_STAT_TXFIFO_EMPTY) == RESET) { /* nada */ } // wait until TXE=1 + // while (SSP_GetStatus(spi_d, SSP_STAT_BUSY) == SET) { /* nada */ } // wait until BSY=0 +} // // Retain the pin init state of the SPI, to avoid init more than once, // // even if more instances of SPIClass exist -// static bool spiInitialised[BOARD_NR_SPI] = { false }; +static bool spiInitialised[BOARD_NR_SPI] = { false }; -// SPIClass::SPIClass(uint8_t device) { +SPIClass::SPIClass(uint8_t device) { // // Init things specific to each SPI device // // clock divider setup is a bit of hack, and needs to be improved at a later date. -// #if BOARD_NR_SPI >= 1 -// _settings[0].spi_d = LPC_SSP0; + #if BOARD_NR_SPI >= 1 + _settings[0].device_id = 0; + _settings[0].m_config.pin_miso = BOARD_SPI1_MISO_PIN; + _settings[0].m_config.pin_mosi = BOARD_SPI1_MOSI_PIN; + _settings[0].m_config.pin_sck = BOARD_SPI1_SCK_PIN; + _settings[0].m_config.pin_ssel = BOARD_SPI1_NSS_PIN; // _settings[0].dataMode = SPI_MODE0; // _settings[0].dataSize = DATA_SIZE_8BIT; // _settings[0].clock = SPI_CLOCK_MAX; // //_settings[0].clockDivider = determine_baud_rate(_settings[0].spi_d, _settings[0].clock); -// #endif + #endif -// #if BOARD_NR_SPI >= 2 -// _settings[1].spi_d = LPC_SSP1; + #if BOARD_NR_SPI >= 2 + _settings[1].device_id = 2; + _settings[1].m_config.pin_miso = BOARD_SPI2_MISO_PIN; + _settings[1].m_config.pin_mosi = BOARD_SPI2_MOSI_PIN; + _settings[1].m_config.pin_sck = BOARD_SPI2_SCK_PIN; + _settings[1].m_config.pin_ssel = BOARD_SPI2_NSS_PIN; // _settings[1].dataMode = SPI_MODE0; // _settings[1].dataSize = DATA_SIZE_8BIT; // _settings[1].clock = SPI_CLOCK_MAX; // //_settings[1].clockDivider = determine_baud_rate(_settings[1].spi_d, _settings[1].clock); -// #endif + #endif -// setModule(device); + setModule(device); // // Init the GPDMA controller // // TODO: call once in the constructor? or each time? // GPDMA_Init(); -// } +} -// SPIClass::SPIClass(pin_t mosi, pin_t miso, pin_t sclk, pin_t ssel) { -// #if BOARD_NR_SPI >= 1 -// if (mosi == BOARD_SPI1_MOSI_PIN) SPIClass(1); -// #endif -// #if BOARD_NR_SPI >= 2 -// if (mosi == BOARD_SPI2_MOSI_PIN) SPIClass(2); -// #endif -// } +SPIClass::SPIClass(pin_t mosi, pin_t miso, pin_t sclk, pin_t ssel) { + #if BOARD_NR_SPI >= 1 + if (mosi == BOARD_SPI1_MOSI_PIN) SPIClass(1); + #endif + #if BOARD_NR_SPI >= 2 + if (mosi == BOARD_SPI2_MOSI_PIN) SPIClass(2); + #endif +} -// void SPIClass::begin() { +void SPIClass::begin() { // // Init the SPI pins in the first begin call -// if ((_currentSetting->spi_d == LPC_SSP0 && spiInitialised[0] == false) || -// (_currentSetting->spi_d == LPC_SSP1 && spiInitialised[1] == false)) { -// pin_t sck, miso, mosi; -// if (_currentSetting->spi_d == LPC_SSP0) { -// sck = BOARD_SPI1_SCK_PIN; -// miso = BOARD_SPI1_MISO_PIN; -// mosi = BOARD_SPI1_MOSI_PIN; -// spiInitialised[0] = true; -// } -// else if (_currentSetting->spi_d == LPC_SSP1) { -// sck = BOARD_SPI2_SCK_PIN; -// miso = BOARD_SPI2_MISO_PIN; -// mosi = BOARD_SPI2_MOSI_PIN; -// spiInitialised[1] = true; -// } -// PINSEL_CFG_Type PinCfg; // data structure to hold init values -// PinCfg.Funcnum = 2; -// PinCfg.OpenDrain = 0; -// PinCfg.Pinmode = 0; -// PinCfg.Pinnum = LPC176x::pin_bit(sck); -// PinCfg.Portnum = LPC176x::pin_port(sck); -// PINSEL_ConfigPin(&PinCfg); -// SET_OUTPUT(sck); + if ((_currentSetting->device_id == 0 && spiInitialised[0] == false) || + (_currentSetting->device_id == 1 && spiInitialised[1] == false) || + (_currentSetting->device_id == 2 && spiInitialised[2] == false)) { + MCUI::SSP::init(_currentSetting->device_id, _currentSetting->m_config); + spiInitialised[_currentSetting->device_id] = true; + } + updateSettings(); +} -// PinCfg.Pinnum = LPC176x::pin_bit(miso); -// PinCfg.Portnum = LPC176x::pin_port(miso); -// PINSEL_ConfigPin(&PinCfg); -// SET_INPUT(miso); +void SPIClass::beginTransaction(const SPISettings &cfg) { + setBitOrder(cfg.bitOrder); + setDataMode(cfg.dataMode); + setDataSize(cfg.dataSize); + //setClockDivider(determine_baud_rate(_currentSetting->spi_d, settings.clock)); + begin(); +} -// PinCfg.Pinnum = LPC176x::pin_bit(mosi); -// PinCfg.Portnum = LPC176x::pin_port(mosi); -// PINSEL_ConfigPin(&PinCfg); -// SET_OUTPUT(mosi); -// } +uint8_t SPIClass::transfer(const uint16_t b) { + uint16_t rx_word = 0; + // clear rx fifo + while(MCUI::SSP::read(_currentSetting->device_id, &rx_word) == 1); + MCUI::SSP::write(_currentSetting->device_id, b); + while(MCUI::SSP::read(_currentSetting->device_id, &rx_word) != 1); + return rx_word; +} -// updateSettings(); -// SSP_Cmd(_currentSetting->spi_d, ENABLE); // start SSP running -// } +uint16_t SPIClass::transfer16(const uint16_t data) { + return (transfer((data >> 8) & 0xFF) << 8) | (transfer(data & 0xFF) & 0xFF); +} -// void SPIClass::beginTransaction(const SPISettings &cfg) { -// setBitOrder(cfg.bitOrder); -// setDataMode(cfg.dataMode); -// setDataSize(cfg.dataSize); -// //setClockDivider(determine_baud_rate(_currentSetting->spi_d, settings.clock)); -// begin(); -// } - -// uint8_t SPIClass::transfer(const uint16_t b) { -// // Send and receive a single byte -// SSP_ReceiveData(_currentSetting->spi_d); // read any previous data -// SSP_SendData(_currentSetting->spi_d, b); -// waitSpiTxEnd(_currentSetting->spi_d); // wait for it to finish -// return SSP_ReceiveData(_currentSetting->spi_d); -// } - -// uint16_t SPIClass::transfer16(const uint16_t data) { -// return (transfer((data >> 8) & 0xFF) << 8) | (transfer(data & 0xFF) & 0xFF); -// } - -// void SPIClass::end() { +void SPIClass::end() { // // Neither is needed for Marlin // //SSP_Cmd(_currentSetting->spi_d, DISABLE); // //SSP_DeInit(_currentSetting->spi_d); -// } +} -// void SPIClass::send(uint8_t data) { -// SSP_SendData(_currentSetting->spi_d, data); -// } +void SPIClass::send(uint8_t data) { + MCUI::SSP::write(_currentSetting->device_id, data); +} -// void SPIClass::dmaSend(void *buf, uint16_t length, bool minc) { +void SPIClass::dmaSend(void *buf, uint16_t length, bool minc) { // //TODO: LPC dma can only write 0xFFF bytes at once. // GPDMA_Channel_CFG_Type GPDMACfg; @@ -329,76 +309,46 @@ // waitSpiTxEnd(_currentSetting->spi_d); // SSP_DMACmd(_currentSetting->spi_d, SSP_DMA_TX, DISABLE); -// } +} -// uint16_t SPIClass::read() { -// return SSP_ReceiveData(_currentSetting->spi_d); -// } +uint16_t SPIClass::read() { + uint16_t rx_word = 0; + MCUI::SSP::read(_currentSetting->device_id, &rx_word); + return rx_word; +} -// void SPIClass::read(uint8_t *buf, uint32_t len) { -// for (uint16_t i = 0; i < len; i++) buf[i] = transfer(0xFF); -// } +void SPIClass::read(uint8_t *buf, uint32_t len) { + uint16_t rx_word = 0; + // clear rx fifo + while(MCUI::SSP::read(_currentSetting->device_id, &rx_word) == 1); + for (uint16_t i = 0; i < len; i++) { + MCUI::SSP::write(_currentSetting->device_id, 0xFF); + while(MCUI::SSP::read(_currentSetting->device_id, &rx_word) != 1); + buf[i] = rx_word; + } +} -// void SPIClass::setClock(uint32_t clock) { _currentSetting->clock = clock; } +void SPIClass::setClock(uint32_t clock) { _currentSetting->clock = clock; } -// void SPIClass::setModule(uint8_t device) { _currentSetting = &_settings[device - 1]; } // SPI channels are called 1, 2, and 3 but the array is zero-indexed +void SPIClass::setModule(uint8_t device) { _currentSetting = &_settings[device - 1]; } // SPI channels are called 1, 2, and 3 but the array is zero-indexed -// void SPIClass::setBitOrder(uint8_t bitOrder) { _currentSetting->bitOrder = bitOrder; } +void SPIClass::setBitOrder(uint8_t bitOrder) { _currentSetting->bitOrder = bitOrder; } -// void SPIClass::setDataMode(uint8_t dataMode) { _currentSetting->dataMode = dataMode; } +void SPIClass::setDataMode(uint8_t dataMode) { _currentSetting->dataMode = dataMode; } -// void SPIClass::setDataSize(uint32_t dataSize) { _currentSetting->dataSize = dataSize; } +void SPIClass::setDataSize(uint32_t dataSize) { _currentSetting->dataSize = dataSize; } // /** // * Set up/tear down // */ -// void SPIClass::updateSettings() { -// //SSP_DeInit(_currentSetting->spi_d); //todo: need force de init?! +void SPIClass::updateSettings() { } -// // Divide PCLK by 2 for SSP0 -// //CLKPWR_SetPCLKDiv(_currentSetting->spi_d == LPC_SSP0 ? CLKPWR_PCLKSEL_SSP0 : CLKPWR_PCLKSEL_SSP1, CLKPWR_PCLKSEL_CCLK_DIV_2); +SPIClass SPI(1); -// SSP_CFG_Type HW_SPI_init; // data structure to hold init values -// SSP_ConfigStructInit(&HW_SPI_init); // set values for SPI mode -// HW_SPI_init.ClockRate = _currentSetting->clock; -// HW_SPI_init.Databit = _currentSetting->dataSize; - -// /** -// * SPI Mode CPOL CPHA Shift SCK-edge Capture SCK-edge -// * 0 0 0 Falling Rising -// * 1 0 1 Rising Falling -// * 2 1 0 Rising Falling -// * 3 1 1 Falling Rising -// */ -// switch (_currentSetting->dataMode) { -// case SPI_MODE0: -// HW_SPI_init.CPHA = SSP_CPHA_FIRST; -// HW_SPI_init.CPOL = SSP_CPOL_HI; -// break; -// case SPI_MODE1: -// HW_SPI_init.CPHA = SSP_CPHA_SECOND; -// HW_SPI_init.CPOL = SSP_CPOL_HI; -// break; -// case SPI_MODE2: -// HW_SPI_init.CPHA = SSP_CPHA_FIRST; -// HW_SPI_init.CPOL = SSP_CPOL_LO; -// break; -// case SPI_MODE3: -// HW_SPI_init.CPHA = SSP_CPHA_SECOND; -// HW_SPI_init.CPOL = SSP_CPOL_LO; -// break; -// default: -// break; -// } - -// // TODO: handle bitOrder -// SSP_Init(_currentSetting->spi_d, &HW_SPI_init); // puts the values into the proper bits in the SSP0 registers -// } - -// #if SD_MISO_PIN == BOARD_SPI1_MISO_PIN -// SPIClass SPI(1); -// #elif SD_MISO_PIN == BOARD_SPI2_MISO_PIN -// SPIClass SPI(2); -// #endif +#if SD_MISO_PIN == BOARD_SPI1_MISO_PIN + SPIClass SPI(1); +#elif SD_MISO_PIN == BOARD_SPI2_MISO_PIN + SPIClass SPI(2); +#endif #endif // TARGET_LPC4078 diff --git a/Marlin/src/HAL/LPC4078/include/SPI.h b/Marlin/src/HAL/LPC4078/include/SPI.h index 02bfdf8398..a1b2f4623f 100644 --- a/Marlin/src/HAL/LPC4078/include/SPI.h +++ b/Marlin/src/HAL/LPC4078/include/SPI.h @@ -24,8 +24,7 @@ #include "../../shared/HAL_SPI.h" #include -// #include -// #include +#include //#define MSBFIRST 1 @@ -63,17 +62,25 @@ #define SPI_CLOCK_MAX SPI_CLOCK_DIV2 -#define BOARD_NR_SPI 2 +#define BOARD_NR_SPI 3 -//#define BOARD_SPI1_NSS_PIN PA4 ?! -#define BOARD_SPI1_SCK_PIN P0_15 -#define BOARD_SPI1_MISO_PIN P0_17 -#define BOARD_SPI1_MOSI_PIN P0_18 +// SSP0 TMC port +#define BOARD_SPI1_NSS_PIN P_NC +#define BOARD_SPI1_SCK_PIN P1_20 +#define BOARD_SPI1_MISO_PIN P1_23 +#define BOARD_SPI1_MOSI_PIN P1_24 -//#define BOARD_SPI2_NSS_PIN PB12 ?! -#define BOARD_SPI2_SCK_PIN P0_07 -#define BOARD_SPI2_MISO_PIN P0_08 -#define BOARD_SPI2_MOSI_PIN P0_09 +// SSP2 LCD SD port +#define BOARD_SPI2_NSS_PIN P_NC +#define BOARD_SPI2_SCK_PIN P1_00 +#define BOARD_SPI2_MISO_PIN P1_04 +#define BOARD_SPI2_MOSI_PIN P1_01 + +// SSP1 Onboard SD port +#define BOARD_SPI3_NSS_PIN P_NC +#define BOARD_SPI3_SCK_PIN P0_07 +#define BOARD_SPI3_MISO_PIN P0_08 +#define BOARD_SPI3_MOSI_PIN P0_09 class SPISettings { public: @@ -115,13 +122,16 @@ private: dataSize = inDataSize; } + MCUI::SSP::Config m_config; + //uint32_t spi_speed; uint32_t clock; uint32_t dataSize; //uint32_t clockDivider; uint8_t bitOrder; uint8_t dataMode; - //LPC_SSP_TypeDef *spi_d; + + uint8_t device_id; friend class SPIClass; }; diff --git a/Marlin/src/pins/linux/pins_RAMPS_LINUX.h b/Marlin/src/pins/linux/pins_RAMPS_LINUX.h index 272c7d2ed2..d1da0336bc 100644 --- a/Marlin/src/pins/linux/pins_RAMPS_LINUX.h +++ b/Marlin/src/pins/linux/pins_RAMPS_LINUX.h @@ -128,6 +128,18 @@ #define E1_CS_PIN 44 #endif +#define Z4_STEP_PIN 13 +#define Z4_DIR_PIN 71 +#define Z4_ENABLE_PIN 12 + +#define Z2_STEP_PIN 4 +#define Z2_DIR_PIN 5 +#define Z2_ENABLE_PIN 6 + +#define Z3_STEP_PIN 12 +#define Z3_DIR_PIN 40 +#define Z3_ENABLE_PIN 44 + // // Temperature Sensors // diff --git a/Marlin/src/pins/lpc4078/pins_EBAB.h b/Marlin/src/pins/lpc4078/pins_EBAB.h index 6e2e1ccb04..c0bc2e19ac 100644 --- a/Marlin/src/pins/lpc4078/pins_EBAB.h +++ b/Marlin/src/pins/lpc4078/pins_EBAB.h @@ -255,14 +255,14 @@ * Default pins for TMC software SPI */ #if ENABLED(TMC_USE_SW_SPI) - #ifndef TMC_SW_MOSI - #define TMC_SW_MOSI P1_24 + #ifndef TMC_SPI_MOSI + #define TMC_SPI_MOSI P1_24 #endif - #ifndef TMC_SW_MISO - #define TMC_SW_MISO P1_23 + #ifndef TMC_SPI_MISO + #define TMC_SPI_MISO P1_23 #endif - #ifndef TMC_SW_SCK - #define TMC_SW_SCK P1_20 + #ifndef TMC_SPI_SCK + #define TMC_SPI_SCK P1_20 #endif #endif From da068d5bb1a8dac98d12ba035e5f56268a0c1cd2 Mon Sep 17 00:00:00 2001 From: InsanityAutomation Date: Wed, 6 Mar 2024 10:53:44 -0500 Subject: [PATCH 10/22] Update Configuration.h --- Marlin/Configuration.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 25604a6c77..c12bed8afd 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -79,7 +79,7 @@ * * :[-1, 0, 1, 2, 3, 4, 5, 6, 7] */ -#define SERIAL_PORT -1 +#define SERIAL_PORT 0 /** * Serial Port Baud Rate @@ -101,7 +101,7 @@ * Currently Ethernet (-2) is only supported on Teensy 4.1 boards. * :[-2, -1, 0, 1, 2, 3, 4, 5, 6, 7] */ -#define SERIAL_PORT_2 0 +#define SERIAL_PORT_2 1 //#define BAUDRATE_2 250000 // :[2400, 9600, 19200, 38400, 57600, 115200, 250000, 500000, 1000000] Enable to override BAUDRATE /** @@ -139,11 +139,11 @@ * TMC5130, TMC5130_STANDALONE, TMC5160, TMC5160_STANDALONE * :['A4988', 'A5984', 'DRV8825', 'LV8729', 'TB6560', 'TB6600', 'TMC2100', 'TMC2130', 'TMC2130_STANDALONE', 'TMC2160', 'TMC2160_STANDALONE', 'TMC2208', 'TMC2208_STANDALONE', 'TMC2209', 'TMC2209_STANDALONE', 'TMC26X', 'TMC26X_STANDALONE', 'TMC2660', 'TMC2660_STANDALONE', 'TMC5130', 'TMC5130_STANDALONE', 'TMC5160', 'TMC5160_STANDALONE'] */ -#define X_DRIVER_TYPE TB6600 -#define Y_DRIVER_TYPE TB6600 +#define X_DRIVER_TYPE TMC5160_STANDALONE +#define Y_DRIVER_TYPE TMC5160_STANDALONE #define Z_DRIVER_TYPE TB6600 //#define X2_DRIVER_TYPE A4988 -#define Y2_DRIVER_TYPE TB6600 +#define Y2_DRIVER_TYPE TMC5160_STANDALONE #define Z2_DRIVER_TYPE TB6600 #define Z3_DRIVER_TYPE TB6600 #define Z4_DRIVER_TYPE TB6600 @@ -392,7 +392,7 @@ * Enable and connect the power supply to the PS_ON_PIN. * Specify whether the power supply is active HIGH or active LOW. */ -#define PSU_CONTROL +//#define PSU_CONTROL //#define PSU_NAME "Power Supply" #if ENABLED(PSU_CONTROL) @@ -2734,7 +2734,7 @@ // If you have a speaker that can produce tones, enable it here. // By default Marlin assumes you have a buzzer with a fixed frequency. // -#define SPEAKER +//#define SPEAKER // // The duration and frequency for the UI feedback sound. From 0dcfc91c9e18441e3c3236666fe59177d1801f09 Mon Sep 17 00:00:00 2001 From: InsanityAutomation Date: Sat, 25 May 2024 19:53:01 -0400 Subject: [PATCH 11/22] Debug --- Marlin/Configuration.h | 4 ++-- Marlin/Configuration_adv.h | 2 +- .../src/HAL/LPC4078/inc/Conditionals_type.h | 22 +++++++++++++++++++ ini/lpc176x.ini | 1 + platformio.ini | 2 +- 5 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 Marlin/src/HAL/LPC4078/inc/Conditionals_type.h diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index df38e88b75..c219ea6667 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -2367,12 +2367,12 @@ * M501 - Read settings from EEPROM. (i.e., Throw away unsaved changes) * M502 - Revert settings to "factory" defaults. (Follow with M500 to init the EEPROM.) */ -#define EEPROM_SETTINGS // Persistent storage with M500 and M501 +//#define EEPROM_SETTINGS // Persistent storage with M500 and M501 //#define DISABLE_M503 // Saves ~2700 bytes of flash. Disable for release! #define EEPROM_CHITCHAT // Give feedback on EEPROM commands. Disable to save PROGMEM. #define EEPROM_BOOT_SILENT // Keep M503 quiet and only give errors during first load #if ENABLED(EEPROM_SETTINGS) - #define EEPROM_AUTO_INIT // Init EEPROM automatically on any errors. + //#define EEPROM_AUTO_INIT // Init EEPROM automatically on any errors. //#define EEPROM_INIT_NOW // Init EEPROM on first boot after a new build. #endif diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index bdf4a42e08..18201d773c 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2291,7 +2291,7 @@ #define BABYSTEP_ZPROBE_OFFSET // Combine M851 Z and Babystepping #if ENABLED(BABYSTEP_ZPROBE_OFFSET) //#define BABYSTEP_HOTEND_Z_OFFSET // For multiple hotends, babystep relative Z offsets - #define BABYSTEP_GFX_OVERLAY // Enable graphical overlay on Z-offset editor + //#define BABYSTEP_GFX_OVERLAY // Enable graphical overlay on Z-offset editor #endif #endif diff --git a/Marlin/src/HAL/LPC4078/inc/Conditionals_type.h b/Marlin/src/HAL/LPC4078/inc/Conditionals_type.h new file mode 100644 index 0000000000..82f95a1035 --- /dev/null +++ b/Marlin/src/HAL/LPC4078/inc/Conditionals_type.h @@ -0,0 +1,22 @@ +/** + * 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 diff --git a/ini/lpc176x.ini b/ini/lpc176x.ini index f617bb40fe..3b8627ca64 100644 --- a/ini/lpc176x.ini +++ b/ini/lpc176x.ini @@ -29,6 +29,7 @@ custom_marlin.NEOPIXEL_LED = Adafruit NeoPixel=https://github.com/p3p/Adafruit_N build_flags = ${common.build_flags} -DU8G_HAL_LINKS -DPLATFORM_M997_SUPPORT -IMarlin/src/HAL/LPC1768/include -IMarlin/src/HAL/LPC1768/u8g -O3 build_unflags = -Os +debug_tool = jlink # debug options for backtrace #-funwind-tables #-mpoke-function-name diff --git a/platformio.ini b/platformio.ini index 76200cbbd5..48fe111c5e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -13,7 +13,7 @@ [platformio] src_dir = Marlin boards_dir = buildroot/share/PlatformIO/boards -default_envs = mega2560 +default_envs = LPC4078 include_dir = Marlin extra_configs = Marlin/config.ini From 9200e8c2847b93ebd20fb6dfc60ee926c3243770 Mon Sep 17 00:00:00 2001 From: InsanityAutomation Date: Sun, 26 May 2024 14:59:09 -0400 Subject: [PATCH 12/22] SPI updates from @p3p upstream --- Marlin/src/HAL/LPC4078/HAL_SPI.cpp | 28 +++++++++++++++++-- Marlin/src/HAL/LPC4078/include/SPI.h | 2 ++ .../u8g/u8g_com_HAL_LPC1768_sw_spi.cpp | 4 +-- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/Marlin/src/HAL/LPC4078/HAL_SPI.cpp b/Marlin/src/HAL/LPC4078/HAL_SPI.cpp index 4aefb25143..b01df9d146 100644 --- a/Marlin/src/HAL/LPC4078/HAL_SPI.cpp +++ b/Marlin/src/HAL/LPC4078/HAL_SPI.cpp @@ -165,14 +165,13 @@ // * @brief Wait until TXE (tx empty) flag is set and BSY (busy) flag unset. // */ static inline void waitSpiTxEnd(void *spi_d) { - #warning unimplemented // while (SSP_GetStatus(spi_d, SSP_STAT_TXFIFO_EMPTY) == RESET) { /* nada */ } // wait until TXE=1 // while (SSP_GetStatus(spi_d, SSP_STAT_BUSY) == SET) { /* nada */ } // wait until BSY=0 } // // Retain the pin init state of the SPI, to avoid init more than once, // // even if more instances of SPIClass exist -static bool spiInitialised[BOARD_NR_SPI] = { false }; +static bool spiInitialised[BOARD_NR_SPI] = {}; SPIClass::SPIClass(uint8_t device) { // // Init things specific to each SPI device @@ -184,6 +183,12 @@ SPIClass::SPIClass(uint8_t device) { _settings[0].m_config.pin_mosi = BOARD_SPI1_MOSI_PIN; _settings[0].m_config.pin_sck = BOARD_SPI1_SCK_PIN; _settings[0].m_config.pin_ssel = BOARD_SPI1_NSS_PIN; + _settings[0].m_config.frequency = 100000; + _settings[0].m_config.data_bits = 8; + _settings[0].m_config.mode = 0; + _settings[0].m_config.format = MCUI::SSP::Config::Format::SPI; + + // _settings[0].dataMode = SPI_MODE0; // _settings[0].dataSize = DATA_SIZE_8BIT; // _settings[0].clock = SPI_CLOCK_MAX; @@ -202,6 +207,18 @@ SPIClass::SPIClass(uint8_t device) { // //_settings[1].clockDivider = determine_baud_rate(_settings[1].spi_d, _settings[1].clock); #endif + #if BOARD_NR_SPI >= 3 + _settings[2].device_id = 1; + _settings[2].m_config.pin_miso = BOARD_SPI3_MISO_PIN; + _settings[2].m_config.pin_mosi = BOARD_SPI3_MOSI_PIN; + _settings[2].m_config.pin_sck = BOARD_SPI3_SCK_PIN; + _settings[2].m_config.pin_ssel = BOARD_SPI3_NSS_PIN; +// _settings[1].dataMode = SPI_MODE0; +// _settings[1].dataSize = DATA_SIZE_8BIT; +// _settings[1].clock = SPI_CLOCK_MAX; +// //_settings[1].clockDivider = determine_baud_rate(_settings[1].spi_d, _settings[1].clock); + #endif + setModule(device); // // Init the GPDMA controller @@ -216,6 +233,9 @@ SPIClass::SPIClass(pin_t mosi, pin_t miso, pin_t sclk, pin_t ssel) { #if BOARD_NR_SPI >= 2 if (mosi == BOARD_SPI2_MOSI_PIN) SPIClass(2); #endif + #if BOARD_NR_SPI >= 3 + if (mosi == BOARD_SPI3_MOSI_PIN) SPIClass(3); + #endif } void SPIClass::begin() { @@ -341,7 +361,9 @@ void SPIClass::setDataSize(uint32_t dataSize) { _currentSetting->dataSize = data // /** // * Set up/tear down // */ -void SPIClass::updateSettings() { } +void SPIClass::updateSettings() { + MCUI::SSP::configure(_currentSetting->device_id, _currentSetting->m_config); +} SPIClass SPI(1); diff --git a/Marlin/src/HAL/LPC4078/include/SPI.h b/Marlin/src/HAL/LPC4078/include/SPI.h index a1b2f4623f..af4ab67745 100644 --- a/Marlin/src/HAL/LPC4078/include/SPI.h +++ b/Marlin/src/HAL/LPC4078/include/SPI.h @@ -120,6 +120,8 @@ private: bitOrder = inBitOrder; dataMode = inDataMode; dataSize = inDataSize; + m_config = {}; + m_config.frequency = 400000; } MCUI::SSP::Config m_config; diff --git a/Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_sw_spi.cpp b/Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_sw_spi.cpp index 03cd7b48a9..62d7008f99 100644 --- a/Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_sw_spi.cpp +++ b/Marlin/src/HAL/LPC4078/u8g/u8g_com_HAL_LPC1768_sw_spi.cpp @@ -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,7 +160,7 @@ 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 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 From 01df7e11dc6e9990cc7be4ad6e6121ff88562623 Mon Sep 17 00:00:00 2001 From: InsanityAutomation Date: Sun, 26 May 2024 15:04:33 -0400 Subject: [PATCH 13/22] Config Tweak --- Marlin/Configuration.h | 4 ++-- Marlin/Configuration_adv.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index c219ea6667..0de39c5720 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -79,7 +79,7 @@ * * :[-1, 0, 1, 2, 3, 4, 5, 6, 7] */ -#define SERIAL_PORT 0 +#define SERIAL_PORT -1 /** * Serial Port Baud Rate @@ -101,7 +101,7 @@ * Currently Ethernet (-2) is only supported on Teensy 4.1 boards. * :[-2, -1, 0, 1, 2, 3, 4, 5, 6, 7] */ -#define SERIAL_PORT_2 1 +//#define SERIAL_PORT_2 1 //#define BAUDRATE_2 250000 // :[2400, 9600, 19200, 38400, 57600, 115200, 250000, 500000, 1000000] Enable to override BAUDRATE /** diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 18201d773c..853d597a92 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -4494,7 +4494,7 @@ // // M43 - display pin status, toggle pins, watch pins, watch endstops & toggle LED, test servo probe // -#define PINS_DEBUGGING +//#define PINS_DEBUGGING // Enable Tests that will run at startup and produce a report //#define MARLIN_TEST_BUILD From 0f1a5a74344e177dd9683001dfb99b68ef584f67 Mon Sep 17 00:00:00 2001 From: InsanityAutomation Date: Tue, 28 May 2024 09:32:10 -0400 Subject: [PATCH 14/22] Update Configuration.h --- Marlin/Configuration.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 0de39c5720..06fea21614 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -139,11 +139,11 @@ * TMC5160, TMC5160_STANDALONE * :['A4988', 'A5984', 'DRV8825', 'LV8729', 'TB6560', 'TB6600', 'TMC2100', 'TMC2130', 'TMC2130_STANDALONE', 'TMC2160', 'TMC2160_STANDALONE', 'TMC2208', 'TMC2208_STANDALONE', 'TMC2209', 'TMC2209_STANDALONE', 'TMC2660', 'TMC2660_STANDALONE', 'TMC5130', 'TMC5130_STANDALONE', 'TMC5160', 'TMC5160_STANDALONE'] */ -#define X_DRIVER_TYPE TMC5160_STANDALONE -#define Y_DRIVER_TYPE TMC5160_STANDALONE +#define X_DRIVER_TYPE TB6600 +#define Y_DRIVER_TYPE TB6600 #define Z_DRIVER_TYPE TB6600 //#define X2_DRIVER_TYPE A4988 -#define Y2_DRIVER_TYPE TMC5160_STANDALONE +#define Y2_DRIVER_TYPE TB6600 #define Z2_DRIVER_TYPE TB6600 #define Z3_DRIVER_TYPE TB6600 #define Z4_DRIVER_TYPE TB6600 @@ -153,7 +153,7 @@ //#define U_DRIVER_TYPE A4988 //#define V_DRIVER_TYPE A4988 //#define W_DRIVER_TYPE A4988 -#define E0_DRIVER_TYPE TMC2209_STANDALONE +#define E0_DRIVER_TYPE TMC2209 //#define E1_DRIVER_TYPE A4988 //#define E2_DRIVER_TYPE A4988 //#define E3_DRIVER_TYPE A4988 From f67a0f847febecb19f41e4ae8e5aba23c22b0504 Mon Sep 17 00:00:00 2001 From: InsanityAutomation Date: Tue, 28 May 2024 09:39:16 -0400 Subject: [PATCH 15/22] Update lpc176x.ini --- ini/lpc176x.ini | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ini/lpc176x.ini b/ini/lpc176x.ini index 3b8627ca64..031e252116 100644 --- a/ini/lpc176x.ini +++ b/ini/lpc176x.ini @@ -27,9 +27,7 @@ lib_deps = ${common.lib_deps} custom_marlin.USES_LIQUIDCRYSTAL = arduino-libraries/LiquidCrystal@~1.0.7 custom_marlin.NEOPIXEL_LED = Adafruit NeoPixel=https://github.com/p3p/Adafruit_NeoPixel/archive/1.5.0.zip build_flags = ${common.build_flags} -DU8G_HAL_LINKS -DPLATFORM_M997_SUPPORT - -IMarlin/src/HAL/LPC1768/include -IMarlin/src/HAL/LPC1768/u8g -O3 -build_unflags = -Os -debug_tool = jlink + -IMarlin/src/HAL/LPC1768/include -IMarlin/src/HAL/LPC1768/u8g # debug options for backtrace #-funwind-tables #-mpoke-function-name @@ -50,8 +48,9 @@ board = nxp_lpc1769 # [env:LPC4078] board = nxp_lpc4078 -platform = symlink://C:\Users\DMenzel\Documents\GitHub\EBAB\ebab_platform\platform-mcui -platform_packages = framework-arduino-mcui@symlink://C:\Users\DMenzel\Documents\GitHub\EBAB\ebab_platform\framework-arduino-mcui +#platform = symlink:///home/p3p/workspace/EBAB_workspace/platform-mcui +#platform_packages = framework-arduino-mcui@symlink:///home/p3p/workspace/EBAB_workspace/framework-arduino-mcui +platform = https://github.com/p3p/pio-platform-mcui/archive/refs/heads/master.zip framework = arduino upload_protocol = jlink debug_tool = jlink From 5a0332ddeef93950d94cd1f2080617ef837e9b9c Mon Sep 17 00:00:00 2001 From: Mihail Dumitrescu Date: Wed, 20 Dec 2023 16:53:43 +0200 Subject: [PATCH 16/22] PR26555 Fix menu responsiveness when HAS_MARLINUI_U8GLIB. Co-Authored-By: Jason Smith --- Marlin/src/lcd/HD44780/marlinui_HD44780.cpp | 2 +- Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp | 2 +- Marlin/src/lcd/dogm/marlinui_DOGM.cpp | 2 +- Marlin/src/lcd/e3v2/marlinui/ui_common.cpp | 2 +- Marlin/src/lcd/marlinui.cpp | 49 ++++++++++----------- Marlin/src/lcd/marlinui.h | 5 +-- Marlin/src/lcd/tft/ui_common.cpp | 2 +- 7 files changed, 29 insertions(+), 35 deletions(-) diff --git a/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp b/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp index ea73243250..b7ee3c801a 100644 --- a/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp +++ b/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp @@ -1343,7 +1343,7 @@ void MarlinUI::draw_status_screen() { void MenuItem_sdbase::draw(const bool sel, const uint8_t row, FSTR_P const, CardReader &theCard, const bool isDir) { lcd_put_lchar(0, row, sel ? LCD_STR_ARROW_RIGHT[0] : ' '); uint8_t n = LCD_WIDTH - 2; - n -= lcd_put_u8str_max(ui.scrolled_filename(theCard, n, row, sel), n); + n -= lcd_put_u8str_max(ui.scrolled_filename(theCard, n, sel), n); for (; n; --n) lcd_put_u8str(F(" ")); lcd_put_lchar(isDir ? LCD_STR_FOLDER[0] : ' '); } diff --git a/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp b/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp index b29653f7b0..c045bc3edb 100644 --- a/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp +++ b/Marlin/src/lcd/TFTGLCD/marlinui_TFTGLCD.cpp @@ -1086,7 +1086,7 @@ void MarlinUI::draw_status_screen() { lcd_moveto(0, row); lcd.write(sel ? LCD_STR_ARROW_RIGHT[0] : ' '); uint8_t n = LCD_WIDTH - 2; - n -= lcd_put_u8str_max(ui.scrolled_filename(theCard, n, row, sel), n); + n -= lcd_put_u8str_max(ui.scrolled_filename(theCard, n, sel), n); for (; n; --n) lcd.write(' '); lcd.write(isDir ? LCD_STR_FOLDER[0] : ' '); lcd.print_line(); diff --git a/Marlin/src/lcd/dogm/marlinui_DOGM.cpp b/Marlin/src/lcd/dogm/marlinui_DOGM.cpp index 1bc55630af..df3fd05afb 100644 --- a/Marlin/src/lcd/dogm/marlinui_DOGM.cpp +++ b/Marlin/src/lcd/dogm/marlinui_DOGM.cpp @@ -606,7 +606,7 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop const uint8_t maxlen = LCD_WIDTH - isDir; if (isDir) lcd_put_lchar(LCD_STR_FOLDER[0]); const pixel_len_t pixw = maxlen * (MENU_FONT_WIDTH); - pixel_len_t n = pixw - lcd_put_u8str_max(ui.scrolled_filename(theCard, maxlen, row, sel), pixw); + pixel_len_t n = pixw - lcd_put_u8str_max(ui.scrolled_filename(theCard, maxlen, sel), pixw); for (; n > MENU_FONT_WIDTH; n -= MENU_FONT_WIDTH) lcd_put_u8str(F(" ")); } diff --git a/Marlin/src/lcd/e3v2/marlinui/ui_common.cpp b/Marlin/src/lcd/e3v2/marlinui/ui_common.cpp index 4a60f77c9d..08f14720ec 100644 --- a/Marlin/src/lcd/e3v2/marlinui/ui_common.cpp +++ b/Marlin/src/lcd/e3v2/marlinui/ui_common.cpp @@ -487,7 +487,7 @@ void MarlinUI::draw_status_message(const bool blink) { maxlen -= 2; } - dwin_string.add(ui.scrolled_filename(theCard, maxlen, row, sel), maxlen); + dwin_string.add(ui.scrolled_filename(theCard, maxlen, sel), maxlen); uint8_t n = maxlen - dwin_string.length; while (n > 0) { dwin_string.add(' '); --n; } lcd_moveto(1, row); diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index 5b83f0c6bf..daf11bf1a7 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -357,25 +357,21 @@ void MarlinUI::init() { #if HAS_MEDIA #if MARLINUI_SCROLL_NAME - uint8_t MarlinUI::filename_scroll_pos, MarlinUI::filename_scroll_max; + static uint8_t filename_scroll_pos, filename_scroll_max; #endif - const char * MarlinUI::scrolled_filename(CardReader &theCard, const uint8_t maxlen, uint8_t hash, const bool doScroll) { + const char * MarlinUI::scrolled_filename(CardReader &theCard, const uint8_t maxlen, const bool doScroll) { const char *outstr = theCard.longest_filename(); if (theCard.longFilename[0]) { #if MARLINUI_SCROLL_NAME if (doScroll) { - for (uint8_t l = FILENAME_LENGTH; l--;) - hash = ((hash << 1) | (hash >> 7)) ^ theCard.filename[l]; // rotate, xor - static uint8_t filename_scroll_hash; - if (filename_scroll_hash != hash) { // If the hash changed... - filename_scroll_hash = hash; // Save the new hash - filename_scroll_max = _MAX(0, utf8_strlen(theCard.longFilename) - maxlen); // Update the scroll limit - filename_scroll_pos = 0; // Reset scroll to the start - lcd_status_update_delay = 8; // Don't scroll right away + filename_scroll_max = _MAX(0, utf8_strlen(theCard.longFilename) - maxlen); + if (filename_scroll_max) { + // Ensure filename_scroll_pos isn't out of bounds even though it should never happen. + if (filename_scroll_pos > filename_scroll_max) filename_scroll_pos = 0; + // Advance byte position corresponding to filename_scroll_pos char position + outstr += TERN(UTF_FILENAME_SUPPORT, utf8_byte_pos_by_char_num(outstr, filename_scroll_pos), filename_scroll_pos); } - // Advance byte position corresponding to filename_scroll_pos char position - outstr += TERN(UTF_FILENAME_SUPPORT, utf8_byte_pos_by_char_num(outstr, filename_scroll_pos), filename_scroll_pos); } #else theCard.longFilename[ @@ -1003,22 +999,19 @@ void MarlinUI::init() { #endif // HAS_MARLINUI_MENU - if (ELAPSED(ms, next_lcd_update_ms) || TERN0(HAS_MARLINUI_U8GLIB, drawing_screen)) { - + const bool lcd_update_ms_elapsed = ELAPSED(ms, next_lcd_update_ms); + if (lcd_update_ms_elapsed) { next_lcd_update_ms = ms + LCD_UPDATE_INTERVAL; #if HAS_TOUCH_BUTTONS - if (on_status_screen()) next_lcd_update_ms += (LCD_UPDATE_INTERVAL) * 2; TERN_(HAS_ENCODER_ACTION, touch_buttons = touchBt.read_buttons()); - #endif TERN_(LCD_HAS_STATUS_INDICATORS, update_indicators()); #if HAS_ENCODER_ACTION - TERN_(HAS_SLOW_BUTTONS, slow_buttons = read_slow_buttons()); // Buttons that take too long to read in interrupt context if (TERN0(IS_RRW_KEYPAD, handle_keypad())) @@ -1083,12 +1076,17 @@ void MarlinUI::init() { #endif refresh(LCDVIEW_REDRAW_NOW); + TERN_(HAS_MARLINUI_U8GLIB, drawing_screen = false); + #if MARLINUI_SCROLL_NAME + filename_scroll_max = 0; + filename_scroll_pos = 0; + lcd_status_update_delay = 9; + #endif #if LED_POWEROFF_TIMEOUT > 0 if (!powerManager.psu_on) leds.reset_timeout(ms); #endif } // encoder activity - #endif // HAS_ENCODER_ACTION // This runs every ~100ms when idling often enough. @@ -1097,19 +1095,23 @@ void MarlinUI::init() { lcd_status_update_delay = TERN(HAS_MARLINUI_U8GLIB, 12, 9); if (max_display_update_time) max_display_update_time--; // Be sure never go to a very big number refresh(LCDVIEW_REDRAW_NOW); + TERN_(HAS_MARLINUI_U8GLIB, drawing_screen = false); } - #if ALL(HAS_MARLINUI_MENU, SCROLL_LONG_FILENAMES) + #if MARLINUI_SCROLL_NAME // If scrolling of long file names is enabled and we are in the sd card menu, // cause a refresh to occur until all the text has scrolled into view. - if (currentScreen == menu_media && !lcd_status_update_delay--) { + if (currentScreen == menu_media && filename_scroll_max && !lcd_status_update_delay--) { lcd_status_update_delay = ++filename_scroll_pos >= filename_scroll_max ? 12 : 4; // Long delay at end and start if (filename_scroll_pos > filename_scroll_max) filename_scroll_pos = 0; refresh(LCDVIEW_REDRAW_NOW); + TERN_(HAS_MARLINUI_U8GLIB, drawing_screen = false); reset_status_timeout(ms); } #endif + } + if (lcd_update_ms_elapsed || drawing_screen) { // Then we want to use only 50% of the time const uint16_t bbr2 = planner.block_buffer_runtime() >> 1; @@ -1131,7 +1133,6 @@ void MarlinUI::init() { TERN_(HAS_ADC_BUTTONS, keypad_buttons = 0); #if HAS_MARLINUI_U8GLIB - #if ENABLED(LIGHTWEIGHT_UI) const bool in_status = on_status_screen(), do_u8g_loop = !in_status; @@ -1160,14 +1161,11 @@ void MarlinUI::init() { return; } } - #else - run_current_screen(); // Apply all DWIN drawing after processing TERN_(IS_DWIN_MARLINUI, dwinUpdateLCD()); - #endif TERN_(HAS_MARLINUI_MENU, lcd_clicked = false); @@ -1212,8 +1210,7 @@ void MarlinUI::init() { case LCDVIEW_CALL_NO_REDRAW: default: break; } // switch - - } // ELAPSED(ms, next_lcd_update_ms) + } TERN_(HAS_GRAPHICAL_TFT, tft_idle()); } diff --git a/Marlin/src/lcd/marlinui.h b/Marlin/src/lcd/marlinui.h index 835102546d..3b2c44daa1 100644 --- a/Marlin/src/lcd/marlinui.h +++ b/Marlin/src/lcd/marlinui.h @@ -644,10 +644,7 @@ public: #if ALL(SCROLL_LONG_FILENAMES, HAS_MARLINUI_MENU) #define MARLINUI_SCROLL_NAME 1 #endif - #if MARLINUI_SCROLL_NAME - static uint8_t filename_scroll_pos, filename_scroll_max; - #endif - static const char * scrolled_filename(CardReader &theCard, const uint8_t maxlen, uint8_t hash, const bool doScroll); + static const char * scrolled_filename(CardReader &theCard, const uint8_t maxlen, const bool doScroll); #endif #if HAS_PREHEAT diff --git a/Marlin/src/lcd/tft/ui_common.cpp b/Marlin/src/lcd/tft/ui_common.cpp index 23f276349b..31e1fd42ef 100644 --- a/Marlin/src/lcd/tft/ui_common.cpp +++ b/Marlin/src/lcd/tft/ui_common.cpp @@ -386,7 +386,7 @@ void MenuItem_static::draw(const uint8_t row, FSTR_P const ftpl, const uint8_t s menu_item(row, sel); if (isDir) tft.add_image(MENU_ITEM_ICON_X, MENU_ITEM_ICON_Y, imgDirectory, COLOR_MENU_TEXT, sel ? COLOR_SELECTION_BG : COLOR_BACKGROUND); uint8_t maxlen = (MENU_ITEM_HEIGHT) - (MENU_TEXT_Y) + 1; - tft.add_text(MENU_ITEM_ICON_SPACE, MENU_TEXT_Y, COLOR_MENU_TEXT, ui.scrolled_filename(theCard, maxlen, row, sel)); + tft.add_text(MENU_ITEM_ICON_SPACE, MENU_TEXT_Y, COLOR_MENU_TEXT, ui.scrolled_filename(theCard, maxlen, sel)); } #endif From 666e8c0116e95d7e0d45a430d514916604d622ce Mon Sep 17 00:00:00 2001 From: John Robertson Date: Sun, 17 Mar 2024 15:26:47 +0000 Subject: [PATCH 17/22] PR26881 Fix planner wrong trap generation If the planner `entry_rate` or `final_rate` are larger thanthe `block->nominal_rate` then the trapezoid entry ramp continuously accelerates. Only happens if feed rate is less than MAXIMAL_STEP_RATE. Update planner.cpp removed Update planner.h Moved MINIMAL_STEP_RATE to this file. Update planner.h Added calc for MINIMAL_STEP_RATE Update planner.h fix minimal_step_rate calc Update planner.h Remove MINIMAL_STEP_RATE Revert "Update planner.cpp" This reverts commit 5e0158a8ee1340e5b0e6a7313eb5f5f7058bfa15. Revert "Update planner.h" This reverts commit 3da5d0c00102620dc7eddf46a30044773770a667. Update planner.cpp Update planner.h Update planner.cpp ws Apply to min_step_rate --- Marlin/src/HAL/ESP32/timers.h | 3 +-- Marlin/src/HAL/TEENSY31_32/timers.h | 2 +- Marlin/src/module/planner.cpp | 18 +++++++++++++----- Marlin/src/module/planner.h | 8 ++++++++ Marlin/src/module/stepper.cpp | 4 ++-- 5 files changed, 25 insertions(+), 10 deletions(-) diff --git a/Marlin/src/HAL/ESP32/timers.h b/Marlin/src/HAL/ESP32/timers.h index aa4e1551f0..3f336fbfc9 100644 --- a/Marlin/src/HAL/ESP32/timers.h +++ b/Marlin/src/HAL/ESP32/timers.h @@ -53,12 +53,11 @@ typedef uint64_t hal_timer_t; #if ENABLED(I2S_STEPPER_STREAM) #define STEPPER_TIMER_PRESCALE 1 #define STEPPER_TIMER_RATE 250000 // 250khz, 4µs pulses of i2s word clock - #define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // stepper timer ticks per µs // wrong would be 0.25 #else #define STEPPER_TIMER_PRESCALE 40 #define STEPPER_TIMER_RATE ((HAL_TIMER_RATE) / (STEPPER_TIMER_PRESCALE)) // frequency of stepper timer, 2MHz - #define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // stepper timer ticks per µs #endif +#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // stepper timer ticks per µs #define STEP_TIMER_MIN_INTERVAL 8 // minimum time in µs between stepper interrupts diff --git a/Marlin/src/HAL/TEENSY31_32/timers.h b/Marlin/src/HAL/TEENSY31_32/timers.h index 9fcbb6f232..3bbc2421e0 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) diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 8f11f4ec18..d944a718d6 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -730,8 +730,6 @@ void Planner::init() { #endif #endif -#define MINIMAL_STEP_RATE 120 - /** * Get the current block for processing * and mark the block as busy. @@ -784,9 +782,10 @@ block_t* Planner::get_current_block() { /** * Calculate trapezoid parameters, multiplying the entry- and exit-speeds - * by the provided factors. Requires that initial_rate and final_rate are - * no less than sqrt(block->acceleration_steps_per_s2 / 2), which is ensured - * through minimum_planner_speed_sqr in _populate_block(). + * by the provided factors. + * The factors come from the current and next entry speeds divided by the nominal speed, + * which is the top speed achievable during the move. Since entry and exit are presumed to + * be smaller, these factors should always be <= 1.0. ** * ############ VERY IMPORTANT ############ * NOTE that the PRECONDITION to call this function is that the block is @@ -807,6 +806,15 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t NOLESS(final_rate, uint32_t(MINIMAL_STEP_RATE)); NOMORE(initial_rate, block->nominal_rate); // NOTE: The nominal rate may be less than MINIMAL_STEP_RATE! NOMORE(final_rate, block->nominal_rate); + NOLESS(block->nominal_rate, (uint32_t)MINIMAL_STEP_RATE); + + // Limit minimal step rate (Otherwise the timer will overflow.) + NOLESS(initial_rate, MINIMAL_STEP_RATE); + NOLESS(final_rate, MINIMAL_STEP_RATE); + NOLESS(block->nominal_rate, MINIMAL_STEP_RATE); + + //NOMORE(initial_rate, block->nominal_rate); + //NOMORE(final_rate, block->nominal_rate); #if ANY(S_CURVE_ACCELERATION, LIN_ADVANCE) // If we have some plateau time, the cruise rate will be the nominal rate diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index fd26b4340e..3e9f3cd9cc 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -78,6 +78,14 @@ #include "../feature/closedloop.h" #endif +constexpr uint32_t MINIMAL_STEP_RATE = ( + #ifdef CPU_32_BIT + _MAX((STEPPER_TIMER_RATE) / HAL_TIMER_TYPE_MAX, 1U) // 32-bit shouldn't go below 1 + #else + (F_CPU) / 500000U // AVR shouldn't go below 32 (16MHz) or 40 (20MHz) + #endif +); + // Feedrate for manual moves #ifdef MANUAL_FEEDRATE constexpr xyze_feedrate_t manual_feedrate_mm_m = MANUAL_FEEDRATE, diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 083d2019dc..1f8d54cb07 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -2198,15 +2198,15 @@ void Stepper::pulse_phase_isr() { // Calculate timer interval, with all limits applied. hal_timer_t Stepper::calc_timer_interval(uint32_t step_rate) { + constexpr uint32_t min_step_rate = MINIMAL_STEP_RATE; + #ifdef CPU_32_BIT // A fast processor can just do integer division - constexpr uint32_t min_step_rate = uint32_t(STEPPER_TIMER_RATE) / HAL_TIMER_TYPE_MAX; return step_rate > min_step_rate ? uint32_t(STEPPER_TIMER_RATE) / step_rate : HAL_TIMER_TYPE_MAX; #else - constexpr uint32_t min_step_rate = (F_CPU) / 500000U; // i.e., 32 or 40 if (step_rate >= 0x0800) { // higher step rate // AVR is able to keep up at around 65kHz Stepping ISR rate at most. // So values for step_rate > 65535 might as well be truncated. From 87faa73beedfceedf7721b4907a30d23edc286c7 Mon Sep 17 00:00:00 2001 From: Mihail Dumitrescu Date: Tue, 16 Apr 2024 13:06:43 +0300 Subject: [PATCH 18/22] PR27035 Smoother motion by fixing calculating trapezoids and ISR stepping. Fix rounding directions in calculate_trapezoid_for_block(). Fix off-by-ones errors in ac/deceleration steps in block_phase_isr. Half-initialize ac/deceleration_time to smooth the speed change shock that happens between segments, which is critical as jerk/deviation adds to this. The result is a smoother motion profile that follows the imposed acceleration limits with a well defined 0.5-1.5x error factor (or 2x if axis is starting from ~0). Errors are due to converting a real-valued motion profile into discrete numbers of steps. Fixes are general and improve S_CURVE_ACCELERATION too (no endorsement implied). Tested by looking at the generated step/dir impulses with a logic analyzer. Enjoy the smoother motion or use more aggresive acceleration/jerk/deviation values for faster prints. Also improves: #12491 Remove nominal_length, remove MINIMAL_STEP_RATE, add min_entry_speed_sqr, initial clean up of reverse_pass_kernel and forward_pass_kernel. Removing MINIMAL_STEP_RATE allows for correct handling of moves with low acceleration, including fixing judder that's caused when the planner computes an entry speed based on minimum_planner_speed_sqr that's then promptly overriden by MINIMAL_STEP_RATE. Added min_entry_speed_sqr to avoid a specific potential source of judder due to working with discrete steps rather continuous real-valued physics. The first step of any segment runs at initial_rate. If it is too low compared to acceleration_steps_per_s2 it will result in too much accumulated acceleration_time (see stepper.cpp) which will mean the following step will be at a much higher speed, and the speed change will significantly surpass the set acceleration_steps_per_s2 limit. Making sure we can match this limit is why we have minimum_planner_speed_sqr in the first place. Optimal number of sqrts and trapezoid calculations. Remove forward_pass(). Call forward_pass_kernel() from recalculate() instead. Fix potential for large speed changes if planner falls behind. group for clarity and review as described combined float sq match modified names Optimal number of sqrts and trapezoid calculations. Remove forward_pass(). Call forward_pass_kernel() from recalculate() instead. Fix potential for large speed changes if planner falls behind. Save and use block->steps_per_mm to avoid many divisions. --- Marlin/src/core/macros.h | 2 +- Marlin/src/module/planner.cpp | 326 ++++++++++++---------------------- Marlin/src/module/planner.h | 13 +- Marlin/src/module/stepper.cpp | 114 ++++++++++-- Marlin/src/module/stepper.h | 4 +- 5 files changed, 229 insertions(+), 230 deletions(-) diff --git a/Marlin/src/core/macros.h b/Marlin/src/core/macros.h index 4f1aba23c8..90974f1c98 100644 --- a/Marlin/src/core/macros.h +++ b/Marlin/src/core/macros.h @@ -89,7 +89,7 @@ #define HYPOT2(x,y) (sq(x)+sq(y)) #define NORMSQ(x,y,z) (sq(x)+sq(y)+sq(z)) -#define FLOAT_SQ(I) sq(float(I)) +#define FLOAT_SQ(I) float(sq(I)) #define CIRCLE_AREA(R) (float(M_PI) * FLOAT_SQ(R)) #define CIRCLE_CIRC(R) (2 * float(M_PI) * float(R)) diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index d944a718d6..d6dba05d0e 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -128,7 +128,6 @@ Planner planner; block_t Planner::block_buffer[BLOCK_BUFFER_SIZE]; volatile uint8_t Planner::block_buffer_head, // Index of the next block to be pushed Planner::block_buffer_nonbusy, // Index of the first non-busy block - Planner::block_buffer_planned, // Index of the optimally planned block Planner::block_buffer_tail; // Index of the busy block, if any uint16_t Planner::cleaning_buffer_counter; // A counter to disable queuing of blocks uint8_t Planner::delay_before_delivering; // Delay block delivery so initial blocks in an empty queue may merge @@ -766,10 +765,6 @@ block_t* Planner::get_current_block() { // As this block is busy, advance the nonbusy block pointer block_buffer_nonbusy = next_block_index(block_buffer_tail); - // Push block_buffer_planned pointer, if encountered. - if (block_buffer_tail == block_buffer_planned) - block_buffer_planned = block_buffer_nonbusy; - // Return the block return block; } @@ -782,21 +777,22 @@ block_t* Planner::get_current_block() { /** * Calculate trapezoid parameters, multiplying the entry- and exit-speeds - * by the provided factors. - * The factors come from the current and next entry speeds divided by the nominal speed, - * which is the top speed achievable during the move. Since entry and exit are presumed to - * be smaller, these factors should always be <= 1.0. + * by the provided factors. If entry_factor is 0 don't change the initial_rate. + * Assumes that the implied initial_rate and final_rate are no less than + * sqrt(block->acceleration_steps_per_s2 / 2). This is ensured through + * minimum_planner_speed_sqr / min_entry_speed_sqr though note there's one + * exception in recalculate_trapezoids(). ** * ############ VERY IMPORTANT ############ * NOTE that the PRECONDITION to call this function is that the block is * NOT BUSY and it is marked as RECALCULATE. That WARRANTIES the Stepper ISR - * is not and will not use the block while we modify it, so it is safe to - * alter its values. + * is not and will not use the block while we modify it. */ -void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t entry_factor, const_float_t exit_factor) { +void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t entry_speed, const_float_t exit_speed) { - uint32_t initial_rate = LROUND(block->nominal_rate * entry_factor), - final_rate = LROUND(block->nominal_rate * exit_factor); // (steps per second) + const float spmm = block->steps_per_mm; + uint32_t initial_rate = entry_speed ? _MAX(long(MINIMAL_STEP_RATE), LROUND(entry_speed * spmm)) : block->initial_rate, + final_rate = _MAX(long(MINIMAL_STEP_RATE), LROUND(exit_speed * spmm)); // Legacy check against supposed timer overflow. However Stepper::calc_timer_interval() already // should protect against it. But removing this code produces judder in direction-switching @@ -804,17 +800,11 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t // constant acceleration when acceleration_steps_per_s2 is large compared to initial/final_rate. NOLESS(initial_rate, uint32_t(MINIMAL_STEP_RATE)); // Enforce the minimum speed NOLESS(final_rate, uint32_t(MINIMAL_STEP_RATE)); + + NOLESS(block->nominal_rate, MINIMAL_STEP_RATE); NOMORE(initial_rate, block->nominal_rate); // NOTE: The nominal rate may be less than MINIMAL_STEP_RATE! NOMORE(final_rate, block->nominal_rate); - NOLESS(block->nominal_rate, (uint32_t)MINIMAL_STEP_RATE); - - // Limit minimal step rate (Otherwise the timer will overflow.) - NOLESS(initial_rate, MINIMAL_STEP_RATE); - NOLESS(final_rate, MINIMAL_STEP_RATE); - NOLESS(block->nominal_rate, MINIMAL_STEP_RATE); - - //NOMORE(initial_rate, block->nominal_rate); - //NOMORE(final_rate, block->nominal_rate); + if (exit_factor < 1.0f) final_rate *= exit_factor; #if ANY(S_CURVE_ACCELERATION, LIN_ADVANCE) // If we have some plateau time, the cruise rate will be the nominal rate @@ -835,7 +825,6 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t // Steps required for acceleration, deceleration to/from nominal rate decelerate_steps_float = half_inverse_accel * (nominal_rate_sq - FLOAT_SQ(final_rate)), accelerate_steps_float = half_inverse_accel * (nominal_rate_sq - FLOAT_SQ(initial_rate)); - // Aims to fully reach nominal and final rates accelerate_steps = CEIL(accelerate_steps_float); decelerate_steps = CEIL(decelerate_steps_float); @@ -950,16 +939,16 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t * * Recalculates the motion plan according to the following basic guidelines: * - * 1. Go over every feasible block sequentially in reverse order and calculate the junction speeds - * (i.e. current->entry_speed) such that: - * a. No junction speed exceeds the pre-computed maximum junction speed limit or nominal speeds of - * neighboring blocks. - * b. A block entry speed cannot exceed one reverse-computed from its exit speed (next->entry_speed) - * with a maximum allowable deceleration over the block travel distance. - * c. The last (or newest appended) block is planned from safe_exit_speed_sqr. - * 2. Go over every block in chronological (forward) order and dial down junction speed values if - * a. The exit speed exceeds the one forward-computed from its entry speed with the maximum allowable - * acceleration over the block travel distance. + * 1. Go over blocks sequentially in reverse order and maximize the entry junction speed: + * a. Entry speed should stay below/at the pre-computed maximum junction speed limit + * b. Aim for the maximum entry speed which is the one reverse-computed from its exit speed + * (next->entry_speed) if assuming maximum deceleration over the full block travel distance + * c. The last (newest appended) block uses safe_exit_speed exit speed (there's no 'next') + * 2. Go over blocks in chronological (forward) order and fix the exit junction speed: + * a. Exit speed (next->entry_speed) must be below/at the maximum exit speed forward-computed + * from its entry speed if assuming maximum acceleration over the full block travel distance + * b. Exit speed should stay above/at the pre-computed minimum junction speed limit + * 3. Convert entry / exit speeds (mm/s) into final/initial steps/s * * When these stages are complete, the planner will have maximized the velocity profiles throughout the all * of the planner blocks, where every block is operating at its maximum allowable acceleration limits. In @@ -967,28 +956,22 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t * are possible. If a new block is added to the buffer, the plan is recomputed according to the said * guidelines for a new optimal plan. * - * To increase computational efficiency of these guidelines, a set of planner block pointers have been - * created to indicate stop-compute points for when the planner guidelines cannot logically make any further - * changes or improvements to the plan when in normal operation and new blocks are streamed and added to the - * planner buffer. For example, if a subset of sequential blocks in the planner have been planned and are - * bracketed by junction velocities at their maximums (or by the first planner block as well), no new block - * added to the planner buffer will alter the velocity profiles within them. So we no longer have to compute - * them. Or, if a set of sequential blocks from the first block in the planner (or a optimal stop-compute - * point) are all accelerating, they are all optimal and can not be altered by a new block added to the - * planner buffer, as this will only further increase the plan speed to chronological blocks until a maximum - * junction velocity is reached. However, if the operational conditions of the plan changes from infrequently - * used feed holds or feedrate overrides, the stop-compute pointers will be reset and the entire plan is - * recomputed as stated in the general guidelines. + * To increase computational efficiency of these guidelines: + * 1. We keep track of which blocks need calculation (block->flag.recalculate) + * 2. We stop the reverse pass on the first block whose entry_speed == max_entry_speed. As soon + * as that happens, there can be no further increases (ensured by the previous recalculate) + * 3. On the forward pass we skip through to the first block with a modified exit speed + * (next->entry_speed) + * 4. On the forward pass if we encounter a full acceleration block that limits its exit speed + * (next->entry_speed) we also update the maximum for that junction (next->max_entry_speed) + * so it's never updated again + * 5. We use speed squared (ex: entry_speed_sqr in mm^2/s^2) in acceleration limit computations + * 6. We don't recompute sqrt(entry_speed_sqr) if the block's entry speed didn't change * * Planner buffer index mapping: * - block_buffer_tail: Points to the beginning of the planner buffer. First to be executed or being executed. * - block_buffer_head: Points to the buffer block after the last block in the buffer. Used to indicate whether * the buffer is full or empty. As described for standard ring buffers, this block is always empty. - * - block_buffer_planned: Points to the first buffer block after the last optimally planned block for normal - * streaming operating conditions. Use for planning optimizations by avoiding recomputing parts of the - * planner buffer that don't change with the addition of a new block, as describe above. In addition, - * this block can never be less than block_buffer_tail and will always be pushed forward and maintain - * this requirement when encountered by the Planner::release_current_block() routine during a cycle. * * NOTE: Since the planner only computes on what's in the planner buffer, some motions with many short * segments (e.g., complex curves) may seem to move slowly. This is because there simply isn't @@ -1011,7 +994,8 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t */ // The kernel called by recalculate() when scanning the plan from last to first entry. -void Planner::reverse_pass_kernel(block_t * const current, const block_t * const next, const_float_t safe_exit_speed_sqr) { +// Returns true if it could increase the current block's entry speed. +bool Planner::reverse_pass_kernel(block_t * const current, const block_t * const next, const_float_t safe_exit_speed_sqr) { // We need to recalculate only for the last block added or if next->entry_speed_sqr changed. if (!next || next->flag.recalculate) { // And only if we're not already at max entry speed. @@ -1029,196 +1013,136 @@ void Planner::reverse_pass_kernel(block_t * const current, const block_t * const // become BUSY just before being marked RECALCULATE, so check for that! if (stepper.is_block_busy(current)) { // Block became busy. Clear the RECALCULATE flag (no point in - // recalculating BUSY blocks). And don't set its speed, as it can't - // be updated at this time. + // recalculating BUSY blocks). current->flag.recalculate = false; } else { // Block is not BUSY so this is ahead of the Stepper ISR: - // Just Set the new entry speed. + current->entry_speed_sqr = new_entry_speed_sqr; + return true; } } } } + return false; } /** * recalculate() needs to go over the current plan twice. - * Once in reverse and once forward. This implements the reverse pass. + * Once in reverse and once forward. This implements the reverse pass that + * coarsely maximizes the entry speeds starting from last block. + * Requires there's at least one block with flag.recalculate in the buffer. */ void Planner::reverse_pass(const_float_t safe_exit_speed_sqr) { // Initialize block index to the last block in the planner buffer. + // This last block will have flag.recalculate set. uint8_t block_index = prev_block_index(block_buffer_head); - // Read the index of the last buffer planned block. - // The ISR may change it so get a stable local copy. - uint8_t planned_block_index = block_buffer_planned; + // The ISR may change block_buffer_nonbusy so get a stable local copy. + uint8_t nonbusy_block_index = block_buffer_nonbusy; - // If there was a race condition and block_buffer_planned was incremented - // or was pointing at the head (queue empty) break loop now and avoid - // planning already consumed blocks - if (planned_block_index == block_buffer_head) return; - - // Reverse Pass: Coarsely maximize all possible deceleration curves back-planning from the last - // block in buffer. Cease planning when the last optimal planned or tail pointer is reached. - // NOTE: Forward pass will later refine and correct the reverse pass to create an optimal plan. const block_t *next = nullptr; - while (block_index != planned_block_index) { - - // Perform the reverse pass + // Don't try to change the entry speed of the first non-busy block. + while (block_index != nonbusy_block_index) { block_t *current = &block_buffer[block_index]; // Only process movement blocks if (current->is_move()) { - reverse_pass_kernel(current, next, safe_exit_speed_sqr); + // If no entry speed increase was possible we end the reverse pass. + if (!reverse_pass_kernel(current, next, safe_exit_speed_sqr)) return; next = current; } - // Advance to the next block_index = prev_block_index(block_index); - // The ISR could advance the block_buffer_planned while we were doing the reverse pass. + // The ISR could advance block_buffer_nonbusy while we were doing the reverse pass. // We must try to avoid using an already consumed block as the last one - So follow // changes to the pointer and make sure to limit the loop to the currently busy block - while (planned_block_index != block_buffer_planned) { + while (nonbusy_block_index != block_buffer_nonbusy) { // If we reached the busy block or an already processed block, break the loop now - if (block_index == planned_block_index) return; + if (block_index == nonbusy_block_index) return; // Advance the pointer, following the busy block - planned_block_index = next_block_index(planned_block_index); + nonbusy_block_index = next_block_index(nonbusy_block_index); } } } -// The kernel called by recalculate() when scanning the plan from first to last entry. -void Planner::forward_pass_kernel(const block_t * const previous, block_t * const current, const uint8_t block_index) { - // Check against previous speed only on current->entry_speed_sqr changes (or if first time). - if (current->flag.recalculate) { - // If the previous block is accelerating check if it's too short to complete the full speed - // change then adjust the entry speed accordingly. Entry speeds have already been maximized. - if (previous->entry_speed_sqr < current->entry_speed_sqr) { - float new_entry_speed_sqr = max_allowable_speed_sqr(-previous->acceleration, previous->entry_speed_sqr, previous->millimeters); +// The kernel called during the forward pass. Assumes current->flag.recalculate. +void Planner::forward_pass_kernel(const block_t * const previous, block_t * const current) { + // Check if the previous block is accelerating. + if (previous->entry_speed_sqr < current->entry_speed_sqr) { + // Compute the maximum achievable speed if the previous block was fully accelerating. + float new_exit_speed_sqr = max_allowable_speed_sqr(-previous->acceleration, previous->entry_speed_sqr, previous->millimeters); - // If true, previous block is full-acceleration and we can move the planned pointer forward. - if (new_entry_speed_sqr < current->entry_speed_sqr) { - // Current entry speed limited by full acceleration from previous entry speed. - // Make sure entry speed not lower than minimum_planner_speed_sqr. - NOLESS(new_entry_speed_sqr, current->min_entry_speed_sqr); - current->entry_speed_sqr = new_entry_speed_sqr; + if (new_exit_speed_sqr < current->entry_speed_sqr) { + // Current entry speed limited by full acceleration from previous entry speed. - // Set optimal plan pointer. - block_buffer_planned = block_index; - } - else { - // Previous entry speed has been maximized. - block_buffer_planned = prev_block_index(block_index); - } + // Make sure entry speed not lower than minimum_planner_speed_sqr. + NOLESS(new_exit_speed_sqr, current->min_entry_speed_sqr); + current->entry_speed_sqr = new_exit_speed_sqr; + // Ensure we don't try updating entry_speed_sqr again. + current->max_entry_speed_sqr = new_exit_speed_sqr; } - - // Any block set at its maximum entry speed also creates an optimal plan up to this - // point in the buffer. When the plan is bracketed by either the beginning of the - // buffer and a maximum entry speed or two maximum entry speeds, every block in between - // cannot logically be further improved. Hence, we don't have to recompute them anymore. - if (current->entry_speed_sqr == current->max_entry_speed_sqr) - block_buffer_planned = block_index; } + + // The fully optimized entry speed is our new minimum speed. + current->min_entry_speed_sqr = current->entry_speed_sqr; } /** - * recalculate() needs to go over the current plan twice. - * Once in reverse and once forward. This implements the forward pass. - */ -void Planner::forward_pass() { - - // Forward Pass: Forward plan the acceleration curve from the planned pointer onward. - // Also scans for optimal plan breakpoints and appropriately updates the planned pointer. - - // Begin at buffer planned pointer. Note that block_buffer_planned can be modified - // by the stepper ISR, so read it ONCE. It it guaranteed that block_buffer_planned - // will never lead head, so the loop is safe to execute. Also note that the forward - // pass will never modify the values at the tail. - uint8_t block_index = block_buffer_planned; - - block_t *block; - const block_t * previous = nullptr; - while (block_index != block_buffer_head) { - - // Perform the forward pass - block = &block_buffer[block_index]; - - // Only process movement blocks - if (block->is_move()) { - // If there's no previous block or the previous block is not - // BUSY (thus, modifiable) run the forward_pass_kernel. Otherwise, - // the previous block became BUSY, so assume the current block's - // entry speed can't be altered (since that would also require - // updating the exit speed of the previous block). - if (previous && !stepper.is_block_busy(previous)) - forward_pass_kernel(previous, block, block_index); - previous = block; - } - // Advance to the previous - block_index = next_block_index(block_index); - } -} - -/** - * Recalculate the trapezoid speed profiles for all blocks in the plan - * according to the entry_factor for each junction. Must be called by - * recalculate() after updating the blocks. + * Do the forward pass and recalculate the trapezoid speed profiles for all blocks in the plan + * according to entry/exit speeds. */ void Planner::recalculate_trapezoids(const_float_t safe_exit_speed_sqr) { - // The tail may be changed by the ISR so get a local copy. + // Start with the block that's about to execute or is executing. uint8_t block_index = block_buffer_tail, head_block_index = block_buffer_head; - // Since there could be a sync block in the head of the queue, and the - // next loop must not recalculate the head block (as it needs to be - // specially handled), scan backwards to the first non-SYNC block. - while (head_block_index != block_index) { - // Go back (head always point to the first free block) - const uint8_t prev_index = prev_block_index(head_block_index); - - // Get the pointer to the block - block_t *prev = &block_buffer[prev_index]; - - // It the block is a move, we're done with this loop - if (prev->is_move()) break; - - // Examine the previous block. This and all following are SYNC blocks - head_block_index = prev_index; - } - - // Go from the tail (currently executed block) to the first block, without including it) block_t *block = nullptr, *next = nullptr; - float current_entry_speed = 0.0f, next_entry_speed = 0.0f; + float next_entry_speed = 0.0f; while (block_index != head_block_index) { next = &block_buffer[block_index]; - // Only process movement blocks if (next->is_move()) { - next_entry_speed = SQRT(next->entry_speed_sqr); + // Check if the next block's entry speed changed + if (next->flag.recalculate) { + if (!block) { + // 'next' is the first move due to either being the first added move or due to the planner + // having completely fallen behind. Revert any reverse pass change. + next->entry_speed_sqr = next->min_entry_speed_sqr; + next_entry_speed = SQRT(next->min_entry_speed_sqr); + } + else { + // Try to fix exit speed which requires trapezoid recalculation + block->flag.recalculate = true; - if (block) { + // But there is an inherent race condition here, as the block may have + // become BUSY just before being marked RECALCULATE, so check for that! + if (stepper.is_block_busy(block)) { + // Block is BUSY so we can't change the exit speed. Revert any reverse pass change. + next->entry_speed_sqr = next->min_entry_speed_sqr; + if (!next->initial_rate) { + // 'next' was never calculated. Planner is falling behind so for maximum efficiency + // set next's stepping speed directly and forgo checking against min_entry_speed_sqr. + // calculate_trapezoid_for_block() can handle it, albeit sub-optimally. + next->initial_rate = block->final_rate; + } + // Note that at this point next_entry_speed is (still) 0. + } + else { + // Block is not BUSY: we won the race against the ISR or recalculate was already set - // If the next block is marked to RECALCULATE, also mark the previously-fetched one - if (next->flag.recalculate) block->flag.recalculate = true; + if (next->entry_speed_sqr != next->min_entry_speed_sqr) + forward_pass_kernel(block, next); - // Recalculate if current block entry or exit junction speed has changed. - if (block->flag.recalculate) { + const float current_entry_speed = next_entry_speed; + next_entry_speed = SQRT(next->entry_speed_sqr); - // But there is an inherent race condition here, as the block maybe - // became BUSY, just before it was marked as RECALCULATE, so check - // if that is the case! - if (!stepper.is_block_busy(block)) { - // Block is not BUSY, we won the race against the Stepper ISR: - - // NOTE: Entry and exit factors always > 0 by all previous logic operations. - const float nomr = 1.0f / block->nominal_speed; - calculate_trapezoid_for_block(block, current_entry_speed * nomr, next_entry_speed * nomr); + calculate_trapezoid_for_block(block, current_entry_speed, next_entry_speed); } // Reset current only to ensure next trapezoid is computed - The @@ -1228,30 +1152,17 @@ void Planner::recalculate_trapezoids(const_float_t safe_exit_speed_sqr) { } block = next; - current_entry_speed = next_entry_speed; } block_index = next_block_index(block_index); } - // Last/newest block in buffer. Always recalculated. - if (block) { + // Last/newest block in buffer. The above guarantees it's a move block. + if (block && block->flag.recalculate) { + const float current_entry_speed = next_entry_speed; next_entry_speed = SQRT(safe_exit_speed_sqr); - // Mark the next(last) block as RECALCULATE, to prevent the Stepper ISR running it. - // As the last block is always recalculated here, there is a chance the block isn't - // marked as RECALCULATE yet. That's the reason for the following line. - block->flag.recalculate = true; - - // But there is an inherent race condition here, as the block maybe - // became BUSY, just before it was marked as RECALCULATE, so check - // if that is the case! - if (!stepper.is_block_busy(block)) { - // Block is not BUSY, we won the race against the Stepper ISR: - - const float nomr = 1.0f / block->nominal_speed; - calculate_trapezoid_for_block(block, current_entry_speed * nomr, next_entry_speed * nomr); - } + calculate_trapezoid_for_block(block, current_entry_speed, next_entry_speed); // Reset block to ensure its trapezoid is computed - The stepper is free to use // the block from now on. @@ -1259,14 +1170,10 @@ void Planner::recalculate_trapezoids(const_float_t safe_exit_speed_sqr) { } } +// Requires there's at least one block with flag.recalculate in the buffer void Planner::recalculate(const_float_t safe_exit_speed_sqr) { - // Initialize block index to the last block in the planner buffer. - const uint8_t block_index = prev_block_index(block_buffer_head); - // If there is just one block, no planning can be done. Avoid it! - if (block_index != block_buffer_planned) { - reverse_pass(safe_exit_speed_sqr); - forward_pass(); - } + reverse_pass(safe_exit_speed_sqr); + // The forward pass is done as part of recalculate_trapezoids() recalculate_trapezoids(safe_exit_speed_sqr); } @@ -1675,7 +1582,7 @@ void Planner::quick_stop() { const bool was_enabled = stepper.suspend(); // Drop all queue entries - block_buffer_nonbusy = block_buffer_planned = block_buffer_head = block_buffer_tail; + block_buffer_nonbusy = block_buffer_head = block_buffer_tail; // Restart the block delay for the first movement - As the queue was // forced to empty, there's no risk the ISR will touch this. @@ -2444,6 +2351,7 @@ bool Planner::_populate_block( // Compute and limit the acceleration rate for the trapezoid generator. const float steps_per_mm = block->step_event_count * inverse_millimeters; + block->steps_per_mm = steps_per_mm; uint32_t accel; #if ENABLED(LIN_ADVANCE) bool use_advance_lead = false; @@ -2554,7 +2462,7 @@ bool Planner::_populate_block( // Formula for the average speed over a 1 step worth of distance if starting from zero and // accelerating at the current limit. Since we can only change the speed every step this is a // good lower limit for the entry and exit speeds. Note that for calculate_trapezoid_for_block() - // to work correctly, this must be accurately set and propagated. + // to work correctly this must be accurately set and propagated. minimum_planner_speed_sqr = 0.5f * block->acceleration / steps_per_mm; // Go straight to/from nominal speed if block->acceleration is too high for it. NOMORE(minimum_planner_speed_sqr, sq(block->nominal_speed)); @@ -2828,7 +2736,7 @@ bool Planner::_populate_block( #endif // CLASSIC_JERK // High acceleration limits override low jerk/junction deviation limits (as fixing trapezoids - // or reducing acceleration introduces too much complexity and/or too much compute) + // or reducing acceleration introduces too much complexity and/or too much compute). NOLESS(vmax_junction_sqr, minimum_planner_speed_sqr); // Max entry speed of this block equals the max exit speed of the previous block. @@ -2837,6 +2745,8 @@ bool Planner::_populate_block( block->entry_speed_sqr = minimum_planner_speed_sqr; // Set min entry speed. Rarely it could be higher than the previous nominal speed but that's ok. block->min_entry_speed_sqr = minimum_planner_speed_sqr; + // Zero the initial_rate to indicate that calculate_trapezoid_for_block() hasn't been called yet. + block->initial_rate = 0; block->flag.recalculate = true; diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index 3e9f3cd9cc..5813a442a5 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -227,6 +227,7 @@ typedef struct PlannerBlock { min_entry_speed_sqr, // Minimum allowable junction entry speed in (mm/sec)^2 max_entry_speed_sqr, // Maximum allowable junction entry speed in (mm/sec)^2 millimeters, // The total travel of this block in mm + steps_per_mm, // steps/mm acceleration; // acceleration mm/sec^2 union { @@ -246,7 +247,7 @@ typedef struct PlannerBlock { #endif // Settings for the trapezoid generator - uint32_t accelerate_before, // The index of the step event where cruising starts + uint32_t accelerate_before, // The index of the step event on which to start cruising decelerate_start; // The index of the step event on which to start decelerating #if ENABLED(S_CURVE_ACCELERATION) @@ -450,7 +451,6 @@ class Planner { static block_t block_buffer[BLOCK_BUFFER_SIZE]; static volatile uint8_t block_buffer_head, // Index of the next block to be pushed block_buffer_nonbusy, // Index of the first non busy block - block_buffer_planned, // Index of the optimally planned block block_buffer_tail; // Index of the busy block, if any static uint16_t cleaning_buffer_counter; // A counter to disable queuing of blocks static uint8_t delay_before_delivering; // This counter delays delivery of blocks when queue becomes empty to allow the opportunity of merging blocks @@ -812,7 +812,7 @@ class Planner { FORCE_INLINE static uint8_t nonbusy_movesplanned() { return block_dec_mod(block_buffer_head, block_buffer_nonbusy); } // Remove all blocks from the buffer - FORCE_INLINE static void clear_block_buffer() { block_buffer_nonbusy = block_buffer_planned = block_buffer_head = block_buffer_tail = 0; } + FORCE_INLINE static void clear_block_buffer() { block_buffer_nonbusy = block_buffer_head = block_buffer_tail = 0; } // Check if movement queue is full FORCE_INLINE static bool is_full() { return block_buffer_tail == next_block_index(block_buffer_head); } @@ -1089,13 +1089,12 @@ class Planner { } #endif - static void calculate_trapezoid_for_block(block_t * const block, const_float_t entry_factor, const_float_t exit_factor); + static void calculate_trapezoid_for_block(block_t * const block, const_float_t entry_speed, const_float_t exit_speed); - static void reverse_pass_kernel(block_t * const current, const block_t * const next, const_float_t safe_exit_speed_sqr); - static void forward_pass_kernel(const block_t * const previous, block_t * const current, uint8_t block_index); + static bool reverse_pass_kernel(block_t * const current, const block_t * const next, const_float_t safe_exit_speed_sqr); + static void forward_pass_kernel(const block_t * const previous, block_t * const current); static void reverse_pass(const_float_t safe_exit_speed_sqr); - static void forward_pass(); static void recalculate_trapezoids(const_float_t safe_exit_speed_sqr); diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 1f8d54cb07..2a1ee71476 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -58,16 +58,10 @@ * * time -----> * - * The speed over time graph forms a TRAPEZOID. The slope of acceleration is calculated by - * v = u + t - * where 't' is the accumulated timer values of the steps so far. - * - * The Stepper ISR dynamically executes acceleration, deceleration, and cruising according to the block parameters. - * - Start at block->initial_rate. - * - Accelerate while step_events_completed < block->accelerate_before. - * - Cruise while step_events_completed < block->decelerate_start. - * - Decelerate after that, until all steps are completed. - * - Reset the trapezoid generator. + * The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates + * while step_events_completed < block->accelerate_before, then starts cruising at constant speed while + * step_events_completed < block->decelerate_start, then it decelerates until the trapezoid generator is reset. + * The slope of acceleration is calculated using v = u + at where t is the accumulated timer values of the steps so far. */ /** @@ -2600,6 +2594,25 @@ hal_timer_t Stepper::block_phase_isr() { // The timer interval is just the nominal value for the nominal speed interval = ticks_nominal; } + + /** + * Adjust Laser Power - Cruise + * power - direct or floor adjusted active laser power. + */ + #if ENABLED(LASER_POWER_TRAP) + if (cutter.cutter_mode == CUTTER_MODE_CONTINUOUS) { + if (step_events_completed + 1 == accelerate_before) { + if (planner.laser_inline.status.isPowered && planner.laser_inline.status.isEnabled) { + if (current_block->laser.trap_ramp_entry_incr > 0) { + current_block->laser.trap_ramp_active_pwr = current_block->laser.power; + cutter.apply_power(current_block->laser.power); + } + } + // Not a powered move. + else cutter.apply_power(0); + } + } + #endif } #if ENABLED(LASER_FEATURE) @@ -2691,8 +2704,85 @@ hal_timer_t Stepper::block_phase_isr() { } #endif - // Set flags for all moving axes, accounting for kinematics - set_axis_moved_for_current_block(); + // Flag all moving axes for proper endstop handling + + #if IS_CORE + // Define conditions for checking endstops + #define S_(N) current_block->steps[CORE_AXIS_##N] + #define D_(N) current_block->direction_bits[CORE_AXIS_##N] + #endif + + #if CORE_IS_XY || CORE_IS_XZ + /** + * Head direction in -X axis for CoreXY and CoreXZ bots. + * + * If steps differ, both axes are moving. + * If DeltaA == -DeltaB, the movement is only in the 2nd axis (Y or Z, handled below) + * If DeltaA == DeltaB, the movement is only in the 1st axis (X) + */ + #if ANY(COREXY, COREXZ) + #define X_CMP(A,B) ((A)==(B)) + #else + #define X_CMP(A,B) ((A)!=(B)) + #endif + #define X_MOVE_TEST ( S_(1) != S_(2) || (S_(1) > 0 && X_CMP(D_(1),D_(2))) ) + #elif ENABLED(MARKFORGED_XY) + #define X_MOVE_TEST (current_block->steps.a != current_block->steps.b) + #else + #define X_MOVE_TEST !!current_block->steps.a + #endif + + #if CORE_IS_XY || CORE_IS_YZ + /** + * Head direction in -Y axis for CoreXY / CoreYZ bots. + * + * If steps differ, both axes are moving + * If DeltaA == DeltaB, the movement is only in the 1st axis (X or Y) + * If DeltaA == -DeltaB, the movement is only in the 2nd axis (Y or Z) + */ + #if ANY(COREYX, COREYZ) + #define Y_CMP(A,B) ((A)==(B)) + #else + #define Y_CMP(A,B) ((A)!=(B)) + #endif + #define Y_MOVE_TEST ( S_(1) != S_(2) || (S_(1) > 0 && Y_CMP(D_(1),D_(2))) ) + #elif ENABLED(MARKFORGED_YX) + #define Y_MOVE_TEST (current_block->steps.a != current_block->steps.b) + #else + #define Y_MOVE_TEST !!current_block->steps.b + #endif + + #if CORE_IS_XZ || CORE_IS_YZ + /** + * Head direction in -Z axis for CoreXZ or CoreYZ bots. + * + * If steps differ, both axes are moving + * If DeltaA == DeltaB, the movement is only in the 1st axis (X or Y, already handled above) + * If DeltaA == -DeltaB, the movement is only in the 2nd axis (Z) + */ + #if ANY(COREZX, COREZY) + #define Z_CMP(A,B) ((A)==(B)) + #else + #define Z_CMP(A,B) ((A)!=(B)) + #endif + #define Z_MOVE_TEST ( S_(1) != S_(2) || (S_(1) > 0 && Z_CMP(D_(1),D_(2))) ) + #else + #define Z_MOVE_TEST !!current_block->steps.c + #endif + + AxisBits didmove; + NUM_AXIS_CODE( + if (X_MOVE_TEST) didmove.a = true, + if (Y_MOVE_TEST) didmove.b = true, + if (Z_MOVE_TEST) didmove.c = true, + if (!!current_block->steps.i) didmove.i = true, + if (!!current_block->steps.j) didmove.j = true, + if (!!current_block->steps.k) didmove.k = true, + if (!!current_block->steps.u) didmove.u = true, + if (!!current_block->steps.v) didmove.v = true, + if (!!current_block->steps.w) didmove.w = true + ); + axis_did_move = didmove; #if ENABLED(ADAPTIVE_STEP_SMOOTHING) // Nonlinear Extrusion needs at least 2x oversampling to permit increase of E step rate diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index 8cf6d39dea..65263c12e5 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -386,8 +386,8 @@ class Stepper { static xyze_long_t advance_dividend; static uint32_t advance_divisor, step_events_completed, // The number of step events executed in the current block - accelerate_before, // The count at which to start cruising - decelerate_start, // The count at which to start decelerating + accelerate_before, // The point from where we need to stop acceleration + decelerate_start, // The point from where we need to start decelerating step_event_count; // The total event count for the current block #if ANY(HAS_MULTI_EXTRUDER, MIXING_EXTRUDER) From 42e4321b6fbea160b6ebb19c73f5ac5b5b8d7515 Mon Sep 17 00:00:00 2001 From: Mihail Dumitrescu Date: Sat, 18 May 2024 01:15:08 +0300 Subject: [PATCH 19/22] Add 4th order S_CURVE_ACCELERATION with configurable S_CURVE_FACTOR. --- Marlin/Configuration.h | 5 +++ Marlin/src/inc/SanityCheck.h | 10 ++++++ Marlin/src/module/stepper.cpp | 63 +++++++++++++++++++++++++++-------- Marlin/src/module/stepper.h | 2 +- 4 files changed, 65 insertions(+), 15 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 06fea21614..898d0dcd2c 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -1340,6 +1340,11 @@ * See https://github.com/synthetos/TinyG/wiki/Jerk-Controlled-Motion-Explained */ #define S_CURVE_ACCELERATION +#if ENABLED(S_CURVE_ACCELERATION) + // Uncomment to use 4th instead of 6th order motion curve + #define S_CURVE_FACTOR 0.35 // Initial and final acceleration factor, ideally 0.1 to 0.4 + // Shouldn't generally require tuning +#endif //=========================================================================== //============================= Z Probe Options ============================= diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 0383d29a69..96b373fe42 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -833,6 +833,16 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L #endif #endif +/** + * S_CURVE_ACCELERATION + */ +#if ENABLED(S_CURVE_ACCELERATION) && defined(S_CURVE_FACTOR) + #if defined(__AVR__) + #error "S_CURVE_FACTOR is not implemented for AVR yet" + #endif + static_assert(WITHIN(S_CURVE_FACTOR, 0, 1), "S_CURVE_FACTOR must be from 0 to 1"); +#endif + /** * Nonlinear Extrusion requirements */ diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 2a1ee71476..200552af49 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -685,7 +685,7 @@ void Stepper::apply_directions() { * a "linear pop" velocity curve; with pop being the sixth derivative of position: * velocity - 1st, acceleration - 2nd, jerk - 3rd, snap - 4th, crackle - 5th, pop - 6th * - * The Bézier curve takes the form: + * The 6th order Bézier curve takes the form: * * V(t) = P_0 * B_0(t) + P_1 * B_1(t) + P_2 * B_2(t) + P_3 * B_3(t) + P_4 * B_4(t) + P_5 * B_5(t) * @@ -705,7 +705,10 @@ void Stepper::apply_directions() { * Unfortunately, we cannot use forward-differencing to calculate each position through * the curve, as Marlin uses variable timer periods. So, we require a formula of the form: * + * 6th order: * V_f(t) = A*t^5 + B*t^4 + C*t^3 + D*t^2 + E*t + F + * 4th order: + * V_f(t) = A*t^3 + B*t^2 + C*t + F * * Looking at the above B_0(t) through B_5(t) expanded forms, if we take the coefficients of t^5 * through t of the Bézier form of V(t), we can determine that: @@ -728,15 +731,27 @@ void Stepper::apply_directions() { * E = 0 * F = P_i * + * For 4th order we want the initial and final acceleration to be a fixed S_CURVE_FACTOR fraction + * and solving gives us: + * + * A = 2*(1 - S_CURVE_FACTOR)*(P_i - P_t) + * B = 3*(1 - S_CURVE_FACTOR)*(P_t - P_i) + * C = S_CURVE_FACTOR*(P_t - P_i) + * F = P_i + * * As the t is evaluated in non uniform steps here, there is no other way rather than evaluating * the Bézier curve at each point: * + * 6th order: * V_f(t) = A*t^5 + B*t^4 + C*t^3 + F [0 <= t <= 1] + * 4th order: + * V_f(t) = A*t^3 + B*t^2 + C*t + F [0 <= t <= 1] * * Floating point arithmetic execution time cost is prohibitive, so we will transform the math to - * use fixed point values to be able to evaluate it in realtime. Assuming a maximum of 250000 steps - * per second (driver pulses should at least be 2µS hi/2µS lo), and allocating 2 bits to avoid - * overflows on the evaluation of the Bézier curve, means we can use + * use fixed point values to be able to evaluate it in realtime. + * + * 6th order: Assumes a maximum of 250000 steps/s (driver pulses down to 2µS hi/2µS lo), + * and allocates 2 bits to avoid overflows on the evaluation of the Bézier curve: * * t: unsigned Q0.32 (0 <= t < 1) |range 0 to 0xFFFFFFFF unsigned * A: signed Q24.7 , |range = +/- 250000 * 6 * 128 = +/- 192000000 = 0x0B71B000 | 28 bits + sign @@ -744,6 +759,8 @@ void Stepper::apply_directions() { * C: signed Q24.7 , |range = +/- 250000 *10 * 128 = +/- 320000000 = 0x1312D000 | 29 bits + sign * F: signed Q24.7 , |range = +/- 250000 * 128 = 32000000 = 0x01E84800 | 25 bits + sign * + * 4th order: With B coefficient at least 5x smaller the maximum will be ~1250000 steps/s. + * * The trapezoid generator state contains the following information, that we will use to create and evaluate * the Bézier curve: * @@ -758,9 +775,15 @@ void Stepper::apply_directions() { * * At the start of each trapezoid, calculate the coefficients A,B,C,F and Advance [AV], as follows: * + * 6th order: * A = 6*128*(VF - VI) = 768*(VF - VI) * B = 15*128*(VI - VF) = 1920*(VI - VF) * C = 10*128*(VF - VI) = 1280*(VF - VI) + * 4th order: + * A = 2*(1-S_CURVE_FACTOR)*128*(VI - VF) + * B = 3*(1-S_CURVE_FACTOR)*128*(VF - VI) + * C = S_CURVE_FACTOR*128*(VF - VI) + * both: * F = 128*VI = 128*VI * AV = (1<<32)/TS ~= 0xFFFFFFFF / TS (To use ARM UDIV, that is 32 bits) (this is computed at the planner, to offload expensive calculations from the ISR) * @@ -1409,9 +1432,17 @@ void Stepper::apply_directions() { // For all the other 32bit CPUs FORCE_INLINE void Stepper::_calc_bezier_curve_coeffs(const int32_t v0, const int32_t v1, const uint32_t av) { // Calculate the Bézier coefficients - bezier_A = 768 * (v1 - v0); - bezier_B = 1920 * (v0 - v1); - bezier_C = 1280 * (v1 - v0); + #ifndef S_CURVE_FACTOR + bezier_A = 768 * (v1 - v0); + bezier_B = 1920 * (v0 - v1); + bezier_C = 1280 * (v1 - v0); + #else + // Must convert from S_CURVE_FACTOR to int only once. + constexpr int FACTOR128 = S_CURVE_FACTOR * 128; + bezier_A = (2 * (128 - FACTOR128)) * (v0 - v1); + bezier_B = (3 * (128 - FACTOR128)) * (v1 - v0); + bezier_C = FACTOR128 * (v1 - v0); + #endif bezier_F = 128 * v0; bezier_AV = av; } @@ -1433,8 +1464,10 @@ void Stepper::apply_directions() { ".syntax unified" "\n\t" // is to prevent CM0,CM1 non-unified syntax A("lsrs %[ahi],%[alo],#1") // a = F << 31 1 cycles A("lsls %[alo],%[alo],#31") // 1 cycles - A("umull %[flo],%[fhi],%[fhi],%[t]") // f *= t 5 cycles [fhi:flo=64bits] - A("umull %[flo],%[fhi],%[fhi],%[t]") // f>>=32; f*=t 5 cycles [fhi:flo=64bits] + #ifndef S_CURVE_FACTOR + A("umull %[flo],%[fhi],%[fhi],%[t]") // f *= t 5 cycles [fhi:flo=64bits] + A("umull %[flo],%[fhi],%[fhi],%[t]") // f>>=32; f*=t 5 cycles [fhi:flo=64bits] + #endif A("lsrs %[flo],%[fhi],#1") // 1 cycles [31bits] A("smlal %[alo],%[ahi],%[flo],%[C]") // a+=(f>>33)*C; 5 cycles A("umull %[flo],%[fhi],%[fhi],%[t]") // f>>=32; f*=t 5 cycles [fhi:flo=64bits] @@ -1462,12 +1495,14 @@ void Stepper::apply_directions() { // For non ARM targets, we provide a fallback implementation. Really doubt it // will be useful, unless the processor is fast and 32bit - uint32_t t = bezier_AV * curr_step; // t: Range 0 - 1^32 = 32 bits + uint32_t t = bezier_AV * curr_step; // t: Range 32 bits uint64_t f = t; - f *= t; // Range 32*2 = 64 bits (unsigned) - f >>= 32; // Range 32 bits (unsigned) - f *= t; // Range 32*2 = 64 bits (unsigned) - f >>= 32; // Range 32 bits : f = t^3 (unsigned) + #ifndef S_CURVE_FACTOR + f *= t; // Range 32*2 = 64 bits (unsigned) + f >>= 32; // Range 32 bits (unsigned) + f *= t; // Range 32*2 = 64 bits (unsigned) + f >>= 32; // Range 32 bits : f = t^3 (unsigned) + #endif int64_t acc = (int64_t) bezier_F << 31; // Range 63 bits (signed) acc += ((uint32_t) f >> 1) * (int64_t) bezier_C; // Range 29bits + 31 = 60bits (plus sign) f *= t; // Range 32*2 = 64 bits diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index 65263c12e5..08830db86a 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -400,7 +400,7 @@ class Stepper { static int32_t bezier_A, // A coefficient in Bézier speed curve bezier_B, // B coefficient in Bézier speed curve bezier_C; // C coefficient in Bézier speed curve - static uint32_t bezier_F, // F coefficient in Bézier speed curve + static uint32_t bezier_F, // F/free coefficient in Bézier speed curve bezier_AV; // AV coefficient in Bézier speed curve #ifdef __AVR__ static bool A_negative; // If A coefficient was negative From 122b01d253b9d1e0e4065e04bd7b971e2896adcc Mon Sep 17 00:00:00 2001 From: Mihail Dumitrescu Date: Mon, 11 Dec 2023 15:33:48 +0200 Subject: [PATCH 20/22] Fully guard multistepping code in Stepper::pulse_phase_isr(). --- Marlin/src/module/stepper.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 200552af49..3cc73cb358 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -1752,7 +1752,7 @@ void Stepper::isr() { #if MINIMUM_STEPPER_PULSE || MAXIMUM_STEPPER_RATE #define ISR_PULSE_CONTROL 1 #endif -#if ISR_PULSE_CONTROL && DISABLED(I2S_STEPPER_STREAM) +#if ISR_PULSE_CONTROL && MULTISTEPPING_LIMIT > 1 && DISABLED(I2S_STEPPER_STREAM) #define ISR_MULTI_STEPS 1 #endif @@ -1801,11 +1801,9 @@ void Stepper::pulse_phase_isr() { // Just update the value we will get at the end of the loop step_events_completed += events_to_do; + TERN_(ISR_PULSE_CONTROL, USING_TIMED_PULSE()); // Take multiple steps per interrupt (For high speed moves) - #if ISR_MULTI_STEPS - bool firstStep = true; - USING_TIMED_PULSE(); - #endif + TERN_(ISR_MULTI_STEPS, bool firstStep = true); // Direct Stepping page? const bool is_page = current_block->is_page(); @@ -2110,7 +2108,7 @@ void Stepper::pulse_phase_isr() { TERN_(I2S_STEPPER_STREAM, i2s_push_sample()); // TODO: need to deal with MINIMUM_STEPPER_PULSE over i2s - #if ISR_MULTI_STEPS + #if ISR_PULSE_CONTROL START_TIMED_PULSE(); AWAIT_HIGH_PULSE(); #endif From 82c1171028a31051089c04c368abf9dd61fbbbe3 Mon Sep 17 00:00:00 2001 From: Mihail Dumitrescu Date: Mon, 27 May 2024 13:42:11 +0300 Subject: [PATCH 21/22] Protect pulse generation timing by disabling interrupts for longer. --- Marlin/src/module/stepper.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 3cc73cb358..ea3d252ba6 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -1526,6 +1526,12 @@ void Stepper::apply_directions() { */ HAL_STEP_TIMER_ISR() { + #ifndef __AVR__ + // Disable interrupts, to avoid ISR preemption while we reprogram the period + // (AVR enters the ISR with global interrupts disabled, so no need to do it here) + hal.isr_off(); + #endif + HAL_timer_isr_prologue(MF_TIMER_STEP); Stepper::isr(); @@ -1543,12 +1549,6 @@ void Stepper::isr() { static hal_timer_t nextMainISR = 0; // Interval until the next main Stepper Pulse phase (0 = Now) - #ifndef __AVR__ - // Disable interrupts, to avoid ISR preemption while we reprogram the period - // (AVR enters the ISR with global interrupts disabled, so no need to do it here) - hal.isr_off(); - #endif - // Program timer compare for the maximum period, so it does NOT // flag an interrupt while this ISR is running - So changes from small // periods to big periods are respected and the timer does not reset to 0 @@ -1569,8 +1569,6 @@ void Stepper::isr() { // We need this variable here to be able to use it in the following loop hal_timer_t min_ticks; do { - // Enable ISRs to reduce USART processing latency - hal.isr_on(); hal_timer_t interval = 0; @@ -1591,6 +1589,9 @@ void Stepper::isr() { NOLESS(nextBabystepISR, nextMainISR / 2); // TODO: Only look at axes enabled for baby-stepping #endif + // Enable ISRs to reduce latency for higher priority ISRs, or all ISRs if no prioritization. + hal.isr_on(); + interval = nextMainISR; // Interval is either some old nextMainISR or FTM_MIN_TICKS TERN_(BABYSTEPPING, NOMORE(interval, nextBabystepISR)); // Come back early for Babystepping? @@ -1619,6 +1620,9 @@ void Stepper::isr() { if (is_babystep) nextBabystepISR = babystepping_isr(); #endif + // Enable ISRs to reduce latency for higher priority ISRs, or all ISRs if no prioritization. + hal.isr_on(); + // ^== Time critical. NOTHING besides pulse generation should be above here!!! if (!nextMainISR) nextMainISR = block_phase_isr(); // Manage acc/deceleration, get next block From 298c3f2344c37ea04a8e5c1b6ab80155808dc350 Mon Sep 17 00:00:00 2001 From: InsanityAutomation Date: Tue, 28 May 2024 11:15:33 -0400 Subject: [PATCH 22/22] Update planner.cpp --- Marlin/src/module/planner.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index d6dba05d0e..34d856670d 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -804,7 +804,6 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t NOLESS(block->nominal_rate, MINIMAL_STEP_RATE); NOMORE(initial_rate, block->nominal_rate); // NOTE: The nominal rate may be less than MINIMAL_STEP_RATE! NOMORE(final_rate, block->nominal_rate); - if (exit_factor < 1.0f) final_rate *= exit_factor; #if ANY(S_CURVE_ACCELERATION, LIN_ADVANCE) // If we have some plateau time, the cruise rate will be the nominal rate