diff --git a/Marlin/src/HAL/shared/Delay.h b/Marlin/src/HAL/shared/Delay.h
index 04df35d88d6..df07881f01d 100644
--- a/Marlin/src/HAL/shared/Delay.h
+++ b/Marlin/src/HAL/shared/Delay.h
@@ -92,6 +92,12 @@ void calibrate_delay_loop();
 
   #define DELAY_CYCLES(X) do { SmartDelay<IS_CONSTEXPR(X), IS_CONSTEXPR(X) ? X : 0> _smrtdly_X(X); } while(0)
 
+  #if GCC_VERSION <= 70000
+    #define DELAY_CYCLES_VAR(X) DelayCycleFnc(X)
+  #else
+    #define DELAY_CYCLES_VAR DELAY_CYCLES
+  #endif
+
   // For delay in microseconds, no smart delay selection is required, directly call the delay function
   // Teensy compiler is too old and does not accept smart delay compile-time / run-time selection correctly
   #define DELAY_US(x) DelayCycleFnc((x) * ((F_CPU) / 1000000UL))
@@ -200,9 +206,12 @@ void calibrate_delay_loop();
 #endif
 
 #if ENABLED(DELAY_NS_ROUND_DOWN)
-  #define DELAY_NS(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL) / 1000UL)          // floor
+  #define _NS_TO_CYCLES(x) ( (x) * ((F_CPU) / 1000000UL)        / 1000UL) // floor
 #elif ENABLED(DELAY_NS_ROUND_CLOSEST)
-  #define DELAY_NS(x) DELAY_CYCLES(((x) * ((F_CPU) / 1000000UL) + 500) / 1000UL)  // round
+  #define _NS_TO_CYCLES(x) (((x) * ((F_CPU) / 1000000UL) + 500) / 1000UL) // round
 #else
-  #define DELAY_NS(x) DELAY_CYCLES(((x) * ((F_CPU) / 1000000UL) + 999) / 1000UL)  // "ceil"
+  #define _NS_TO_CYCLES(x) (((x) * ((F_CPU) / 1000000UL) + 999) / 1000UL) // "ceil"
 #endif
+
+#define DELAY_NS(x)         DELAY_CYCLES(_NS_TO_CYCLES(x))
+#define DELAY_NS_VAR(x) DELAY_CYCLES_VAR(_NS_TO_CYCLES(x))
diff --git a/Marlin/src/HAL/shared/Marduino.h b/Marlin/src/HAL/shared/Marduino.h
index 3b5a68a3732..0e2a021a3c4 100644
--- a/Marlin/src/HAL/shared/Marduino.h
+++ b/Marlin/src/HAL/shared/Marduino.h
@@ -39,7 +39,7 @@
 #define DISABLED(V...) DO(DIS,&&,V)
 
 #undef _BV
-#define _BV(b) (1UL << (b))
+#define _BV(b) (1 << (b))
 #ifndef SBI
   #define SBI(A,B) (A |= _BV(B))
 #endif
diff --git a/Marlin/src/libs/MAX31865.cpp b/Marlin/src/libs/MAX31865.cpp
index df0702b9fb5..94048af2089 100644
--- a/Marlin/src/libs/MAX31865.cpp
+++ b/Marlin/src/libs/MAX31865.cpp
@@ -48,20 +48,17 @@
 
 #if HAS_MAX31865 && !USE_ADAFRUIT_MAX31865
 
-//#include <SoftwareSPI.h> // TODO: switch to SPIclass/SoftSPI
 #include "MAX31865.h"
 
+#ifdef TARGET_LPC1768
+  #include <SoftwareSPI.h>
+#endif
+
 // The maximum speed the MAX31865 can do is 5 MHz
 SPISettings MAX31865::spiConfig = SPISettings(
-  #if defined(TARGET_LPC1768)
-    SPI_QUARTER_SPEED
-  #elif defined(ARDUINO_ARCH_STM32)
-    SPI_CLOCK_DIV4
-  #else
-    500000
-  #endif
-  , MSBFIRST
-  , SPI_MODE_1 // CPOL0 CPHA1
+  TERN(TARGET_LPC1768, SPI_QUARTER_SPEED, TERN(ARDUINO_ARCH_STM32, SPI_CLOCK_DIV4, 500000)),
+  MSBFIRST,
+  SPI_MODE1 // CPOL0 CPHA1
 );
 
 #ifndef LARGE_PINMAP
@@ -93,7 +90,7 @@ SPISettings MAX31865::spiConfig = SPISettings(
     _sclk = _miso = _mosi = -1;
   }
 
-#else
+#else // LARGE_PINMAP
 
   /**
    * Create the interface object using software (bitbang) SPI for PIN values
@@ -106,9 +103,7 @@ SPISettings MAX31865::spiConfig = SPISettings(
    * @param spi_clk      the SPI clock pin to use
    * @param pin_mapping  set to 1 for positive pin values
    */
-  MAX31865::MAX31865(uint32_t spi_cs, uint32_t spi_mosi,
-                     uint32_t spi_miso, uint32_t spi_clk,
-                     uint8_t pin_mapping) {
+  MAX31865::MAX31865(uint32_t spi_cs, uint32_t spi_mosi, uint32_t spi_miso, uint32_t spi_clk, uint8_t pin_mapping) {
     _cs = spi_cs;
     _mosi = spi_mosi;
     _miso = spi_miso;
@@ -130,14 +125,12 @@ SPISettings MAX31865::spiConfig = SPISettings(
 
 #endif // LARGE_PINMAP
 
-
 /**
  *
  * Instance & Class methods
  *
  */
 
-
 /**
  * Initialize the SPI interface and set the number of RTD wires used
  *
@@ -152,22 +145,13 @@ void MAX31865::begin(max31865_numwires_t wires, float zero, float ref) {
   OUT_WRITE(_cs, HIGH);
 
   if (_sclk != TERN(LARGE_PINMAP, -1UL, -1)) {
-    // Define pin modes for Software SPI
-    #ifdef MAX31865_DEBUG
-      SERIAL_ECHOLN("Initializing MAX31865 Software SPI");
-    #endif
-
-    OUT_WRITE(_sclk, LOW);
-    SET_OUTPUT(_mosi);
-    SET_INPUT(_miso);
+    softSpiBegin(SPI_QUARTER_SPEED); // Define pin modes for Software SPI
   }
   else {
-    // Start and configure hardware SPI
     #ifdef MAX31865_DEBUG
-      SERIAL_ECHOLN("Initializing MAX31865 Hardware SPI");
+      SERIAL_ECHOLNPGM("Initializing MAX31865 Hardware SPI");
     #endif
-
-    SPI.begin();
+    SPI.begin();    // Start and configure hardware SPI
   }
 
   setWires(wires);
@@ -176,25 +160,15 @@ void MAX31865::begin(max31865_numwires_t wires, float zero, float ref) {
   clearFault();
 
   #ifdef MAX31865_DEBUG_SPI
-    #ifndef LARGE_PINMAP
-      SERIAL_ECHOLNPGM(
-        "Regular begin call with _cs: ", _cs,
-        " _miso: ", _miso,
-        " _sclk: ", _sclk,
-        " _mosi: ", _mosi
-      );
-    #else
-      SERIAL_ECHOLNPGM(
-        "LARGE_PINMAP begin call with _cs: ", _cs,
-        " _miso: ", _miso,
-        " _sclk: ", _sclk,
-        " _mosi: ", _mosi
-      );
-    #endif // LARGE_PINMAP
-
-    SERIAL_ECHOLNPGM("config: ", readRegister8(MAX31856_CONFIG_REG));
-    SERIAL_EOL();
-  #endif // MAX31865_DEBUG_SPI
+    SERIAL_ECHOLNPGM(
+      TERN(LARGE_PINMAP, "LARGE_PINMAP", "Regular")
+      " begin call with _cs: ", _cs,
+      " _miso: ", _miso,
+      " _sclk: ", _sclk,
+      " _mosi: ", _mosi,
+      " config: ", readRegister8(MAX31856_CONFIG_REG)
+    );
+  #endif
 }
 
 /**
@@ -371,7 +345,6 @@ float MAX31865::temperature(float Rrtd) {
 // private:
 //
 
-
 /**
  * Set a value in the configuration register.
  *
@@ -432,10 +405,15 @@ void MAX31865::readRegisterN(uint8_t addr, uint8_t buffer[], uint8_t n) {
     WRITE(_sclk, LOW);
 
   WRITE(_cs, LOW);
-  spixfer(addr);
+
+  #ifdef TARGET_LPC1768
+    DELAY_CYCLES(_spi_speed);
+  #endif
+
+  spiTransfer(addr);
 
   while (n--) {
-    buffer[0] = spixfer(0xFF);
+    buffer[0] = spiTransfer(0xFF);
     #ifdef MAX31865_DEBUG_SPI
       SERIAL_ECHOLNPGM("buffer read ", n, " data: ", buffer[0]);
     #endif
@@ -462,8 +440,12 @@ void MAX31865::writeRegister8(uint8_t addr, uint8_t data) {
 
   WRITE(_cs, LOW);
 
-  spixfer(addr | 0x80); // make sure top bit is set
-  spixfer(data);
+  #ifdef TARGET_LPC1768
+    DELAY_CYCLES(_spi_speed);
+  #endif
+
+  spiTransfer(addr | 0x80); // make sure top bit is set
+  spiTransfer(data);
 
   if (_sclk == TERN(LARGE_PINMAP, -1UL, -1))
     SPI.endTransaction();
@@ -480,21 +462,38 @@ void MAX31865::writeRegister8(uint8_t addr, uint8_t data) {
  * @param  x  an 8-bit chunk of data to write
  * @return    the 8-bit response
  */
-uint8_t MAX31865::spixfer(uint8_t x) {
+uint8_t MAX31865::spiTransfer(uint8_t x) {
   if (_sclk == TERN(LARGE_PINMAP, -1UL, -1))
     return SPI.transfer(x);
 
-  uint8_t reply = 0;
-  for (int i = 7; i >= 0; i--) {
-    reply <<= 1;
-    WRITE(_sclk, HIGH);
-    WRITE(_mosi, x & (1 << i));
-    WRITE(_sclk, LOW);
-    if (READ(_miso))
-      reply |= 1;
-  }
+  #ifdef TARGET_LPC1768
+    return swSpiTransfer(x, _spi_speed, _sclk, _miso, _mosi);
+  #else
+    uint8_t reply = 0;
+    for (int i = 7; i >= 0; i--) {
+      WRITE(_sclk, HIGH);           DELAY_NS_VAR(_spi_delay);
+      reply <<= 1;
+      WRITE(_mosi, x & _BV(i));     DELAY_NS_VAR(_spi_delay);
+      if (READ(_miso)) reply |= 1;
+      WRITE(_sclk, LOW);            DELAY_NS_VAR(_spi_delay);
+    }
+    return reply;
+  #endif
+}
 
-  return reply;
+void MAX31865::softSpiBegin(const uint8_t spi_speed) {
+  #ifdef MAX31865_DEBUG
+    SERIAL_ECHOLNPGM("Initializing MAX31865 Software SPI");
+  #endif
+  #ifdef TARGET_LPC1768
+    swSpiBegin(_sclk, _miso, _mosi);
+    _spi_speed = swSpiInit(spi_speed, _sclk, _mosi);
+  #else
+    _spi_delay = (100UL << spi_speed) / 3; // Calculate delay in ns. Top speed is ~10MHz, or 100ns delay between bits.
+    OUT_WRITE(_sclk, LOW);
+    SET_OUTPUT(_mosi);
+    SET_INPUT(_miso);
+  #endif
 }
 
 #endif // HAS_MAX31865 && !USE_ADAFRUIT_MAX31865
diff --git a/Marlin/src/libs/MAX31865.h b/Marlin/src/libs/MAX31865.h
index 5d50e870ecd..7610924c231 100644
--- a/Marlin/src/libs/MAX31865.h
+++ b/Marlin/src/libs/MAX31865.h
@@ -90,6 +90,13 @@ private:
   static SPISettings spiConfig;
 
   TERN(LARGE_PINMAP, uint32_t, uint8_t) _sclk, _miso, _mosi, _cs;
+
+  #ifdef TARGET_LPC1768
+    uint8_t _spi_speed;
+  #else
+    uint16_t _spi_delay;
+  #endif
+
   float Rzero, Rref;
 
   void setConfig(uint8_t config, bool enable);
@@ -99,7 +106,9 @@ private:
   uint16_t readRegister16(uint8_t addr);
 
   void writeRegister8(uint8_t addr, uint8_t reg);
-  uint8_t spixfer(uint8_t addr);
+  uint8_t spiTransfer(uint8_t addr);
+
+  void softSpiBegin(const uint8_t spi_speed);
 
 public:
   #ifdef LARGE_PINMAP
diff --git a/buildroot/tests/LPC1769 b/buildroot/tests/LPC1769
index f0dab630e5e..3fe99734ca6 100755
--- a/buildroot/tests/LPC1769
+++ b/buildroot/tests/LPC1769
@@ -14,11 +14,12 @@ exec_test $1 $2 "Azteeg X5GT Example Configuration" "$3"
 
 restore_configs
 opt_set MOTHERBOARD BOARD_SMOOTHIEBOARD \
-        EXTRUDERS 2 TEMP_SENSOR_1 -1 TEMP_SENSOR_BED 5 \
+        EXTRUDERS 2 TEMP_SENSOR_0 -5 TEMP_SENSOR_1 -1 TEMP_SENSOR_BED 5 TEMP_0_CS_PIN P1_29 \
         GRID_MAX_POINTS_X 16 \
         NOZZLE_CLEAN_START_POINT "{ {  10, 10, 3 }, {  10, 10, 3 } }" \
         NOZZLE_CLEAN_END_POINT "{ {  10, 20, 3 }, {  10, 20, 3 } }"
 opt_enable TFTGLCD_PANEL_SPI SDSUPPORT ADAPTIVE_FAN_SLOWING NO_FAN_SLOWING_IN_PID_TUNING \
+           MAX31865_SENSOR_OHMS_0 MAX31865_CALIBRATION_OHMS_0 \
            FIX_MOUNTED_PROBE AUTO_BED_LEVELING_BILINEAR G29_RETRY_AND_RECOVER Z_MIN_PROBE_REPEATABILITY_TEST DEBUG_LEVELING_FEATURE \
            BABYSTEPPING BABYSTEP_XY BABYSTEP_ZPROBE_OFFSET LEVEL_CORNERS_USE_PROBE LEVEL_CORNERS_VERIFY_RAISED \
            PRINTCOUNTER NOZZLE_PARK_FEATURE NOZZLE_CLEAN_FEATURE SLOW_PWM_HEATERS PIDTEMPBED EEPROM_SETTINGS INCH_MODE_SUPPORT TEMPERATURE_UNITS_SUPPORT \
diff --git a/buildroot/tests/teensy41 b/buildroot/tests/teensy41
index fd89512ea57..1affd7c89e1 100755
--- a/buildroot/tests/teensy41
+++ b/buildroot/tests/teensy41
@@ -15,12 +15,13 @@ exec_test $1 $2 "Teensy4.1 with default config" "$3"
 #
 restore_configs
 opt_set MOTHERBOARD BOARD_TEENSY41 \
-        EXTRUDERS 2 TEMP_SENSOR_0 1 TEMP_SENSOR_1 5 TEMP_SENSOR_BED 1 \
+        EXTRUDERS 2 TEMP_SENSOR_0 -5 TEMP_SENSOR_1 5 TEMP_SENSOR_BED 1 TEMP_0_CS_PIN 23 \
         I2C_SLAVE_ADDRESS 63 \
         GRID_MAX_POINTS_X 16 \
         NOZZLE_CLEAN_START_POINT "{ {  10, 10, 3 }, {  10, 10, 3 } }" \
         NOZZLE_CLEAN_END_POINT "{ {  10, 20, 3 }, {  10, 20, 3 } }"
-opt_enable EXTENSIBLE_UI LCD_INFO_MENU SDSUPPORT SDCARD_SORT_ALPHA \
+opt_enable MAX31865_SENSOR_OHMS_0 MAX31865_CALIBRATION_OHMS_0 \
+           EXTENSIBLE_UI LCD_INFO_MENU SDSUPPORT SDCARD_SORT_ALPHA \
            FILAMENT_LCD_DISPLAY CALIBRATION_GCODE BAUD_RATE_GCODE \
            FIX_MOUNTED_PROBE Z_SAFE_HOMING AUTO_BED_LEVELING_BILINEAR Z_MIN_PROBE_REPEATABILITY_TEST DEBUG_LEVELING_FEATURE \
            BABYSTEPPING BABYSTEP_XY BABYSTEP_ZPROBE_OFFSET \