diff --git a/Marlin/src/HAL/HAL_STM32/HAL_SPI.cpp b/Marlin/src/HAL/HAL_STM32/HAL_SPI.cpp
index 82cae9b75cbdbede8a98fa2fa68d06866798cfdd..de45c8948e130d2516e2948b919b5cdaf62f9504 100644
--- a/Marlin/src/HAL/HAL_STM32/HAL_SPI.cpp
+++ b/Marlin/src/HAL/HAL_STM32/HAL_SPI.cpp
@@ -37,121 +37,193 @@ static SPISettings spiConfig;
 // ------------------------
 
 #if ENABLED(SOFTWARE_SPI)
+
   // ------------------------
   // Software SPI
   // ------------------------
-  #error "Software SPI not supported for STM32. Use Hardware SPI."
 
-#else
+  #include "../shared/Delay.h"
 
-// ------------------------
-// Hardware SPI
-// ------------------------
+  void spiBegin(void) {
+    OUT_WRITE(SS_PIN, HIGH);
+    OUT_WRITE(SCK_PIN, HIGH);
+    SET_INPUT(MISO_PIN);
+    OUT_WRITE(MOSI_PIN, HIGH);
+  }
 
-/**
- * VGPV SPI speed start and PCLK2/2, by default 108/2 = 54Mhz
- */
+  static uint16_t delay_STM32_soft_spi;
+
+  void spiInit(uint8_t spiRate) {
+    // Use datarates Marlin uses
+    switch (spiRate) {
+      case SPI_FULL_SPEED:   delay_STM32_soft_spi =  125; break;  // desired: 8,000,000  actual: ~1.1M
+      case SPI_HALF_SPEED:   delay_STM32_soft_spi =  125; break;  // desired: 4,000,000  actual: ~1.1M
+      case SPI_QUARTER_SPEED:delay_STM32_soft_spi =  250; break;  // desired: 2,000,000  actual: ~890K
+      case SPI_EIGHTH_SPEED: delay_STM32_soft_spi =  500; break;  // desired: 1,000,000  actual: ~590K
+      case SPI_SPEED_5:      delay_STM32_soft_spi = 1000; break;  // desired:   500,000  actual: ~360K
+      case SPI_SPEED_6:      delay_STM32_soft_spi = 2000; break;  // desired:   250,000  actual: ~210K
+      default:               delay_STM32_soft_spi = 4000; break;  // desired:   125,000  actual: ~123K
+    }
+    SPI.begin();
+  }
 
-/**
- * @brief  Begin SPI port setup
- *
- * @return Nothing
- *
- * @details Only configures SS pin since stm32duino creates and initialize the SPI object
- */
-void spiBegin() {
-  #if !PIN_EXISTS(SS)
-    #error "SS_PIN not defined!"
-  #endif
-
-  OUT_WRITE(SS_PIN, HIGH);
-}
-
-/** Configure SPI for specified SPI speed */
-void spiInit(uint8_t spiRate) {
-  // Use datarates Marlin uses
-  uint32_t clock;
-  switch (spiRate) {
-    case SPI_FULL_SPEED:    clock = 20000000; break; // 13.9mhz=20000000  6.75mhz=10000000  3.38mhz=5000000  .833mhz=1000000
-    case SPI_HALF_SPEED:    clock =  5000000; break;
-    case SPI_QUARTER_SPEED: clock =  2500000; break;
-    case SPI_EIGHTH_SPEED:  clock =  1250000; break;
-    case SPI_SPEED_5:       clock =   625000; break;
-    case SPI_SPEED_6:       clock =   300000; break;
-    default:
-      clock = 4000000; // Default from the SPI library
+  // Begin SPI transaction, set clock, bit order, data mode
+  void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) { /* do nothing */ }
+
+  uint8_t HAL_SPI_STM32_SpiTransfer_Mode_3(uint8_t b) { // using Mode 3
+    for (uint8_t bits = 8; bits--;) {
+      WRITE(SCK_PIN, LOW);
+      WRITE(MOSI_PIN, b & 0x80);
+
+      DELAY_NS(delay_STM32_soft_spi);
+      WRITE(SCK_PIN, HIGH);
+      DELAY_NS(delay_STM32_soft_spi);
+
+      b <<= 1;        // little setup time
+      b |= (READ(MISO_PIN) != 0);
+    }
+    DELAY_NS(125);
+    return b;
   }
-  spiConfig = SPISettings(clock, MSBFIRST, SPI_MODE0);
 
-  #if ENABLED(CUSTOM_SPI_PINS)
-    SPI.setMISO(MISO_PIN);
-    SPI.setMOSI(MOSI_PIN);
-    SPI.setSCLK(SCK_PIN);
-    SPI.setSSEL(SS_PIN);
-  #endif
+  // Soft SPI receive byte
+  uint8_t spiRec() {
+    DISABLE_ISRS();                                               // No interrupts during byte receive
+    const uint8_t data = HAL_SPI_STM32_SpiTransfer_Mode_3(0xFF);
+    ENABLE_ISRS();                                                // Enable interrupts
+    return data;
+  }
 
-  SPI.begin();
-}
+  // Soft SPI read data
+  void spiRead(uint8_t *buf, uint16_t nbyte) {
+    for (uint16_t i = 0; i < nbyte; i++)
+      buf[i] = spiRec();
+  }
 
-/**
- * @brief  Receives a single byte from the SPI port.
- *
- * @return Byte received
- *
- * @details
- */
-uint8_t spiRec() {
-  SPI.beginTransaction(spiConfig);
-  uint8_t returnByte = SPI.transfer(0xFF);
-  SPI.endTransaction();
-  return returnByte;
-}
+  // Soft SPI send byte
+  void spiSend(uint8_t data) {
+    DISABLE_ISRS();                         // No interrupts during byte send
+    HAL_SPI_STM32_SpiTransfer_Mode_3(data); // Don't care what is received
+    ENABLE_ISRS();                          // Enable interrupts
+  }
 
-/**
- * @brief  Receives a number of bytes from the SPI port to a buffer
- *
- * @param  buf   Pointer to starting address of buffer to write to.
- * @param  nbyte Number of bytes to receive.
- * @return Nothing
- *
- * @details Uses DMA
- */
-void spiRead(uint8_t* buf, uint16_t nbyte) {
-  if (nbyte == 0) return;
-  memset(buf, 0xFF, nbyte);
-  SPI.beginTransaction(spiConfig);
-  SPI.transfer(buf, nbyte);
-  SPI.endTransaction();
-}
+  // Soft SPI send block
+  void spiSendBlock(uint8_t token, const uint8_t *buf) {
+    spiSend(token);
+    for (uint16_t i = 0; i < 512; i++)
+      spiSend(buf[i]);
+  }
 
-/**
- * @brief  Sends a single byte on SPI port
- *
- * @param  b Byte to send
- *
- * @details
- */
-void spiSend(uint8_t b) {
-  SPI.beginTransaction(spiConfig);
-  SPI.transfer(b);
-  SPI.endTransaction();
-}
+#else
 
-/**
- * @brief  Write token and then write from 512 byte buffer to SPI (for SD card)
- *
- * @param  buf   Pointer with buffer start address
- * @return Nothing
- *
- * @details Use DMA
- */
-void spiSendBlock(uint8_t token, const uint8_t* buf) {
-  uint8_t rxBuf[512];
-  SPI.beginTransaction(spiConfig);
-  SPI.transfer(token);
-  SPI.transfer((uint8_t*)buf, &rxBuf, 512);
-  SPI.endTransaction();
-}
+  // ------------------------
+  // Hardware SPI
+  // ------------------------
+
+  /**
+   * VGPV SPI speed start and PCLK2/2, by default 108/2 = 54Mhz
+   */
+
+  /**
+   * @brief  Begin SPI port setup
+   *
+   * @return Nothing
+   *
+   * @details Only configures SS pin since stm32duino creates and initialize the SPI object
+   */
+  void spiBegin() {
+    #if !PIN_EXISTS(SS)
+      #error "SS_PIN not defined!"
+    #endif
+
+    OUT_WRITE(SS_PIN, HIGH);
+  }
+
+  // Configure SPI for specified SPI speed
+  void spiInit(uint8_t spiRate) {
+    // Use datarates Marlin uses
+    uint32_t clock;
+    switch (spiRate) {
+      case SPI_FULL_SPEED:    clock = 20000000; break; // 13.9mhz=20000000  6.75mhz=10000000  3.38mhz=5000000  .833mhz=1000000
+      case SPI_HALF_SPEED:    clock =  5000000; break;
+      case SPI_QUARTER_SPEED: clock =  2500000; break;
+      case SPI_EIGHTH_SPEED:  clock =  1250000; break;
+      case SPI_SPEED_5:       clock =   625000; break;
+      case SPI_SPEED_6:       clock =   300000; break;
+      default:
+        clock = 4000000; // Default from the SPI library
+    }
+    spiConfig = SPISettings(clock, MSBFIRST, SPI_MODE0);
+
+    #if ENABLED(CUSTOM_SPI_PINS)
+      SPI.setMISO(MISO_PIN);
+      SPI.setMOSI(MOSI_PIN);
+      SPI.setSCLK(SCK_PIN);
+      SPI.setSSEL(SS_PIN);
+    #endif
+
+    SPI.begin();
+  }
+
+  /**
+   * @brief  Receives a single byte from the SPI port.
+   *
+   * @return Byte received
+   *
+   * @details
+   */
+  uint8_t spiRec() {
+    SPI.beginTransaction(spiConfig);
+    uint8_t returnByte = SPI.transfer(0xFF);
+    SPI.endTransaction();
+    return returnByte;
+  }
+
+  /**
+   * @brief  Receive a number of bytes from the SPI port to a buffer
+   *
+   * @param  buf   Pointer to starting address of buffer to write to.
+   * @param  nbyte Number of bytes to receive.
+   * @return Nothing
+   *
+   * @details Uses DMA
+   */
+  void spiRead(uint8_t* buf, uint16_t nbyte) {
+    if (nbyte == 0) return;
+    memset(buf, 0xFF, nbyte);
+    SPI.beginTransaction(spiConfig);
+    SPI.transfer(buf, nbyte);
+    SPI.endTransaction();
+  }
+
+  /**
+   * @brief  Send a single byte on SPI port
+   *
+   * @param  b Byte to send
+   *
+   * @details
+   */
+  void spiSend(uint8_t b) {
+    SPI.beginTransaction(spiConfig);
+    SPI.transfer(b);
+    SPI.endTransaction();
+  }
+
+  /**
+   * @brief  Write token and then write from 512 byte buffer to SPI (for SD card)
+   *
+   * @param  buf   Pointer with buffer start address
+   * @return Nothing
+   *
+   * @details Use DMA
+   */
+  void spiSendBlock(uint8_t token, const uint8_t* buf) {
+    uint8_t rxBuf[512];
+    SPI.beginTransaction(spiConfig);
+    SPI.transfer(token);
+    SPI.transfer((uint8_t*)buf, &rxBuf, 512);
+    SPI.endTransaction();
+  }
 
 #endif // SOFTWARE_SPI
 
diff --git a/Marlin/src/gcode/feature/L6470/M906.cpp b/Marlin/src/gcode/feature/L6470/M906.cpp
index d6bf8a53c94522bf7728cc9e5a841082478c2a4b..5b4157b0b21d837875d400a29338b6f9a0a28233 100644
--- a/Marlin/src/gcode/feature/L6470/M906.cpp
+++ b/Marlin/src/gcode/feature/L6470/M906.cpp
@@ -39,22 +39,16 @@
  *
  * On L6474 this sets the TVAL register (same address).
  *
- * J - select which driver(s) to monitor on multi-driver axis
- *     0 - (default) monitor all drivers on the axis or E0
+ * I - select which driver(s) to change on multi-driver axis
+ *     0 - (default) all drivers on the axis or E0
  *     1 - monitor only X, Y, Z or E1
  *     2 - monitor only X2, Y2, Z2 or E2
  *     3 - monitor only Z3 or E3
  *     4 - monitor only E4
  *     5 - monitor only E5
- * Xxxx, Yxxx, Zxxx, Exxx - axis to be monitored with displacement
- *     xxx (1-255) is distance moved on either side of current position
- *
- * I - over current threshold
- *     optional - will report current value from driver if not specified
- *
- * K - value for KVAL_HOLD (0 - 255) (optional)
- *     optional - will report current value from driver if not specified
- *
+ * Xxxx, Yxxx, Zxxx, Exxx - axis to change (optional)
+ *     L6474 - current in mA (4A max)
+ *     All others - 0-255
  */
 
 /**
@@ -202,10 +196,12 @@ void L6470_report_current(L64XX &motor, const L64XX_axis_t axis) {
 
       const uint16_t MicroSteps = _BV(motor.GetParam(L6470_STEP_MODE) & 0x07); //NOMORE(MicroSteps, 16);
       SERIAL_ECHOLNPAIR("...MicroSteps: ", MicroSteps,
-                        "   ADC_OUT: ", L6470_ADC_out);
+                        "   ADC_OUT: ", L6470_ADC_out,
+                        "   Vs_compensation: NA");
+
+      SERIAL_EOL();
 
-      SERIAL_ECHOLNPGM("   Vs_compensation: NA\n"
-                       "...KVAL_HOLD: NA"
+      SERIAL_ECHOLNPGM("...KVAL_HOLD: NA"
                        "   KVAL_RUN : NA"
                        "   KVAL_ACC: NA"
                        "   KVAL_DEC: NA"
@@ -232,7 +228,7 @@ void GcodeSuite::M906() {
 
   L64xxManager.pause_monitor(true); // Keep monitor_driver() from stealing status
 
-  #define L6470_SET_KVAL_HOLD(Q) stepper##Q.SetParam(L6470_KVAL_HOLD, value)
+  #define L6470_SET_KVAL_HOLD(Q) (AXIS_IS_L64XX(Q) ? stepper##Q.setTVALCurrent(value) : stepper##Q.SetParam(L6470_KVAL_HOLD, uint8_t(value)))
 
   DEBUG_ECHOLNPGM("M906");
 
@@ -242,7 +238,7 @@ void GcodeSuite::M906() {
     const uint8_t index = parser.byteval('I');
   #endif
 
-  LOOP_XYZE(i) if (uint8_t value = parser.byteval(axis_codes[i])) {
+  LOOP_XYZE(i) if (uint16_t value = parser.intval(axis_codes[i])) {
 
     report_current = false;
 
diff --git a/Marlin/src/pins/stm32/pins_STEVAL_3DP001V1.h b/Marlin/src/pins/stm32/pins_STEVAL_3DP001V1.h
index fc600fd450e37fb0fbd53c6d5e8ec50ebb7aea77..3ec5c4c0ecee5a69a1245518c83627f226416002 100644
--- a/Marlin/src/pins/stm32/pins_STEVAL_3DP001V1.h
+++ b/Marlin/src/pins/stm32/pins_STEVAL_3DP001V1.h
@@ -68,18 +68,10 @@
 //  #define Z_MIN_PROBE_PIN  16  // PA4
 //#endif
 
-#define SCK_PIN            13   // PB13    SPI_S
-#define MISO_PIN           12   // PB14    SPI_M
-#define MOSI_PIN           11   // PB15    SPI_M
-
-#define L6470_CHAIN_SCK_PIN  17   // PA5
-#define L6470_CHAIN_MISO_PIN 18   // PA6
-#define L6470_CHAIN_MOSI_PIN 19   // PA7
-#define L6470_CHAIN_SS_PIN   16   // PA4
-
-//#define SCK_PIN   L6470_CHAIN_SCK_PIN
-//#define MISO_PIN  L6470_CHAIN_MISO_PIN
-//#define MOSI_PIN  L6470_CHAIN_MOSI_PIN
+//
+// Filament runout
+//
+//#define FIL_RUNOUT_PIN     53   // PA3    BED_THE
 
 //
 // Steppers
@@ -124,19 +116,34 @@
 #define E4_CS_PIN          16  // PA4     SPI_CS
 #define E5_CS_PIN          16  // PA4     SPI_CS
 
+#if HAS_L64XX
+  #define L6470_CHAIN_SCK_PIN  17   // PA5
+  #define L6470_CHAIN_MISO_PIN 18   // PA6
+  #define L6470_CHAIN_MOSI_PIN 19   // PA7
+  #define L6470_CHAIN_SS_PIN   16   // PA4
+
+  //#define SCK_PIN        L6470_CHAIN_SCK_PIN
+  //#define MISO_PIN       L6470_CHAIN_MISO_PIN
+  //#define MOSI_PIN       L6470_CHAIN_MOSI_PIN
+#else
+  //#define SCK_PIN        13   // PB13    SPI_S
+  //#define MISO_PIN       12   // PB14    SPI_M
+  //#define MOSI_PIN       11   // PB15    SPI_M
+#endif
+
 /**
- * macro to reset/enable L6474 chips
+ * Macro to reset/enable L6474 stepper drivers
  *
- * IMPORTANT - to disable (bypass) a L6474, install the corresponding
- *             resistor (R11 - R17) and change the "V" to zero for the
- *             corresponding pin.
+ * IMPORTANT - To disable (bypass) L6474s, install the corresponding
+ *             resistors (R11 - R17) and change the "V" to "0" for the
+ *             corresponding pins here:
  */
-#define ENABLE_RESET_L64XX_CHIPS(V)   do{OUT_WRITE(X_ENABLE_PIN, V);\
-                                         OUT_WRITE(Y_ENABLE_PIN, V);\
-                                         OUT_WRITE(Z_ENABLE_PIN, V);\
-                                         OUT_WRITE(E0_ENABLE_PIN,V);\
-                                         OUT_WRITE(E1_ENABLE_PIN,V);\
-                                         OUT_WRITE(E2_ENABLE_PIN,V);\
+#define ENABLE_RESET_L64XX_CHIPS(V)   do{ OUT_WRITE(X_ENABLE_PIN, V); \
+                                          OUT_WRITE(Y_ENABLE_PIN, V); \
+                                          OUT_WRITE(Z_ENABLE_PIN, V); \
+                                          OUT_WRITE(E0_ENABLE_PIN,V); \
+                                          OUT_WRITE(E1_ENABLE_PIN,V); \
+                                          OUT_WRITE(E2_ENABLE_PIN,V); \
                                         }while(0)
 
 //
@@ -146,7 +153,7 @@
 #define TEMP_1_PIN          4   // Analog input 4,  digital pin 55   PA1     E2_THERMISTOR
 #define TEMP_2_PIN          5   // Analog input 5,  digital pin 56   PA2     E3_THERMISTOR
 #define TEMP_BED_PIN        0   // Analog input 0,  digital pin 51   PC2     BED_THERMISTOR_1
-#define TEMP_BED_1_PIN      1`  // Analog input 1,  digital pin 52   PC3     BED_THERMISTOR_2
+#define TEMP_BED_1_PIN      1   // Analog input 1,  digital pin 52   PC3     BED_THERMISTOR_2
 #define TEMP_BED_2_PIN      2   // Analog input 2,  digital pin 53   PA3     BED_THERMISTOR_3
 
 //
@@ -171,7 +178,7 @@
 #define LED_PIN            -1   // 9 // PE1 green LED   Heart beat
 #define PS_ON_PIN          -1
 #define KILL_PIN           -1
-#define PWR_LOSS           -1   // Power loss / nAC_FAULT
+#define POWER_LOSS_PIN     -1   // PWR_LOSS / nAC_FAULT
 
 //
 // LCD / Controller
@@ -188,11 +195,6 @@
 //#define BTN_EN2            58   // PC5     E2_FAN
 //#define BTN_ENC            52   // PC3     BED_THE
 
-//
-// Filament runout
-//
-//#define FIL_RUNOUT_PIN     53   // PA3    BED_THE
-
 //
 // Extension pins
 //
@@ -225,7 +227,10 @@
 // 21   // PA14  JTAG_TCK/SWCLK
 // 22   // PB3   JTAG_TDO/SWO
 
-// SDCARD
+//
+// SD support
+//
+//#define SDIO_SUPPORT
 // 23   // PC8   SDIO_D0
 // 24   // PC9   SDIO_D1
 // 25   // PA15  SD_CARD_DETECT
@@ -234,6 +239,12 @@
 // 28   // PC12  SDIO_CK
 // 29   // PD2   SDIO_CMD
 
+#define SOFTWARE_SPI            // Use soft SPI for onboard SD
+#define SDSS               27   // PC11  SDIO_D3
+#define SCK_PIN            28   // PC12  SDIO_CK
+#define MISO_PIN           23   // PC8   SDIO_D0
+#define MOSI_PIN           29   // PD2   SDIO_CMD
+
 // OTG
 // 30   // PA11  OTG_DM
 // 31   // PA12  OTG_DP
diff --git a/buildroot/share/PlatformIO/variants/STEVAL_F401VE/hal_conf_custom.h b/buildroot/share/PlatformIO/variants/STEVAL_F401VE/hal_conf_custom.h
index 40046334289e12ab64dcf12ac8a59a5b524b6702..0c7781997fef87fbb874cbadf28ae7d47648193a 100644
--- a/buildroot/share/PlatformIO/variants/STEVAL_F401VE/hal_conf_custom.h
+++ b/buildroot/share/PlatformIO/variants/STEVAL_F401VE/hal_conf_custom.h
@@ -55,7 +55,7 @@ extern "C" {
 #define HAL_I2C_MODULE_ENABLED
 /* #define HAL_SMBUS_MODULE_ENABLED   */
 /* #define HAL_I2S_MODULE_ENABLED   */
-/* #define HAL_IWDG_MODULE_ENABLED   */
+#define HAL_IWDG_MODULE_ENABLED
 /* #define HAL_LTDC_MODULE_ENABLED   */
 /* #define HAL_DSI_MODULE_ENABLED   */
 #define HAL_PWR_MODULE_ENABLED
diff --git a/buildroot/share/PlatformIO/variants/STEVAL_F401VE/variant.cpp b/buildroot/share/PlatformIO/variants/STEVAL_F401VE/variant.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a53a92c48c29fcaddd39d787c522917d5655fdd6
--- /dev/null
+++ b/buildroot/share/PlatformIO/variants/STEVAL_F401VE/variant.cpp
@@ -0,0 +1,310 @@
+/*
+ *******************************************************************************
+ * Copyright (c) 2017, STMicroelectronics
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * 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.
+ *******************************************************************************
+ */
+
+#include "pins_arduino.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(ARDUINO_STEVAL)
+// Pin number
+// This array allows to wrap Arduino pin number(Dx or x)
+// to STM32 PinName (PX_n)
+const PinName digitalPin[] = {
+  PA_9,  // TX
+  PA_10, // RX
+
+  // WIFI
+  PD_3,  // CTS
+  PD_4,  // RTS
+  PD_5,  // TX
+  PD_6,  // RX
+  PB_5,  // WIFI_WAKEUP
+  PE_11, // WIFI_RESET
+  PE_12, // WIFI_BOOT
+
+  // STATUS_LED
+  PE_1,  //STATUS_LED
+
+  // SPI USER
+  PB_12, // SPI_CS
+  PB_15, // SPI_MOSI
+  PB_14, // SPI_MISO
+  PB_13, // SPI_SCK
+
+  // I2C USER
+  PB_7,  // SDA
+  PB_6,  // SCL
+
+  // SPI
+  PA_4,  // SPI_CS
+  PA_5,  // SPI_SCK
+  PA_6,  // SPI_MISO
+  PA_7,  // SPI_MOSI
+
+  // JTAG
+  PA_13, // JTAG_TMS/SWDIO
+  PA_14, // JTAG_TCK/SWCLK
+  PB_3,  // JTAG_TDO/SWO
+
+  // SDCARD
+  PC_8,  // SDIO_D0
+  PC_9,  // SDIO_D1
+  PA_15, // SD_CARD_DETECT
+  PC_10, // SDIO_D2
+  PC_11, // SDIO_D3
+  PC_12, // SDIO_CK
+  PD_2,  // SDIO_CMD
+
+  // OTG
+  PA_11, // OTG_DM
+  PA_12, // OTG_DP
+
+  // IR/PROBE
+  PD_1,  // IR_OUT
+  PC_1,  // IR_ON
+
+  // USER_PINS
+  PD_7,  // USER3
+  PB_9,  // USER1
+  PE_0,  // USER2
+  PB_4,  // USER4
+
+  // USERKET
+  PE_7,  // USER_BUTTON
+
+  // ENDSTOPS
+  PD_8,  // X_STOP
+  PD_9,  // Y_STOP
+  PD_10, // Z_STOP
+  PD_11, // U_STOP
+  PA_8,  // V_STOP
+  PD_0,  // W_STOP
+
+  // HEATERS
+  PD_13, // BED_HEAT_2
+  PD_14, // BED_HEAT_1
+  PD_15, // BED_HEAT_3
+  PC_7,  // E1_HEAT_PWM
+  PB_0,  // E2_HEAT_PWM
+  PB_1,  // E3_HEAT_PWM
+
+  // THERMISTOR
+  PC_2,  // BED_THERMISTOR_1
+  PC_3,  // BED_THERMISTOR_2
+  PA_3,  // BED_THERMISTOR_3
+  PA_0,  // E1_THERMISTOR
+  PA_1,  // E2_THERMISTOR
+  PA_2,  // E3_THERMISTOR
+
+  // FANS
+  PC_4,  // E1_FAN
+  PC_5,  // E2_FAN
+  PE_8,  // E3_FAN
+
+  // X_MOTOR
+  PE_13, // X_RESET
+  PE_14, // X_PWM
+  PE_15, // X_DIR
+
+  // Y_MOTOR
+  PE_10, // Y_RESET
+  PB_10, // Y_PWM
+  PE_9,  // Y_DIR
+
+  // Z_MOTOR
+  PC_15, // Z_RESET
+  PC_6,  // Z_PWM
+  PC_0,  // Z_DIR
+
+  // E1_MOTOR
+  PC_14, // E1_RESET
+  PC_13, // E1_DIR
+  PD_12, // E1_PWM
+
+  // E2_MOTOR
+  PE_4,  // E2_RESET
+  PE_5,  // E2_PWM
+  PE_6,  // E2_DIR
+
+  // E3_MOTOR
+  PE_3,  // E3_RESET
+  PE_2,  // E3_DIR
+  PB_8   // E3_PWM
+};
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**
+  * @brief  System Clock Configuration
+  *         The system Clock is configured as follow :
+  *            System Clock source            = PLL (HSI)
+  *            SYSCLK(Hz)                     = 84000000
+  *            HCLK(Hz)                       = 84000000
+  *            AHB Prescaler                  = 1
+  *            APB1 Prescaler                 = 2
+  *            APB2 Prescaler                 = 1
+  *            HSI Frequency(Hz)              = 16000000
+  *            PLL_M                          = 16
+  *            PLL_N                          = 336
+  *            PLL_P                          = 4
+  *            PLL_Q                          = 7
+  *            VDD(V)                         = 3.3
+  *            Main regulator output voltage  = Scale2 mode
+  *            Flash Latency(WS)              = 2
+  * @param  None
+  * @retval None
+  */
+WEAK void SystemClock_Config(void)
+{
+  RCC_OscInitTypeDef RCC_OscInitStruct = {};
+  RCC_ClkInitTypeDef RCC_ClkInitStruct = {};
+
+  /* Configure the main internal regulator output voltage */
+  __HAL_RCC_PWR_CLK_ENABLE();
+  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
+
+  /* Initializes the CPU, AHB and APB busses clocks */
+  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
+  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
+  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
+  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
+  RCC_OscInitStruct.PLL.PLLM = 15;
+  RCC_OscInitStruct.PLL.PLLN = 144;
+  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
+  RCC_OscInitStruct.PLL.PLLQ = 5;
+  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
+    Error_Handler();
+  }
+  /* Initializes the CPU, AHB and APB busses clocks */
+  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
+                                | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
+  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
+  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
+  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
+  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
+
+  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) {
+    Error_Handler();
+  }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+
+// PA_0  54 // E1_THERMISTOR
+// PA_1  55 // E2_THERMISTOR
+// PA_2  56 // E3_THERMISTOR
+// PA_3  53 // BED_THERMISTOR_3
+// PA_4  16 // SPI_CS
+// PA_5  17 // SPI_SCK
+// PA_6  18 // SPI_MISO
+// PA_7  19 // SPI_MOSI
+// PA_8  43 // V_STOP
+// PA_9   0 //TX
+// PA_10  1 //RX
+// PA_11 30 //OTG_DM
+// PA_12 31 //OTG_DP
+// PA_13 20 // JTAG_TMS/SWDIO
+// PA_14 21 // JTAG_TCK/SWCLK
+// PA_15 25 // SD_CARD_DETECT
+// PB_0  49 // E2_HEAT_PWM
+// PB_1  50 // E3_HEAT_PWM
+// PB_3  22 // JTAG_TDO/SWO
+// PB_4  37 // USER4
+// PB_5   6 // WIFI_WAKEUP
+// PB_6  15 // SCL
+// PB_7  14 // SDA
+// PB_8  77 // E3_PWM
+// PB_9  35 // USER1
+// PB_10 64 // Y_PWM
+// PB_12 10 // SPI_CS
+// PB_13 13 // SPI_SCK
+// PB_14 12 // SPI_MISO
+// PB_15 11 // SPI_MOSI
+// PC_0  68 // Z_DIR
+// PC_1  33 //IR_ON
+// PC_2  51 // BED_THERMISTOR_1
+// PC_3  52 // BED_THERMISTOR_2
+// PC_4  57 // E1_FAN
+// PC_5  58 // E2_FAN
+// PC_6  67 // Z_PWM
+// PC_7  48 // E1_HEAT_PWM
+// PC_8  23 // SDIO_D0
+// PC_9  24 // SDIO_D1
+// PC_10 26 // SDIO_D2
+// PC_11 27 // SDIO_D3
+// PC_12 28 // SDIO_CK
+// PC_13 70 // E1_DIR
+// PC_14 69 // E1_RESET
+// PC_15 66 // Z_RESET
+// PD_0  44 // W_STOP
+// PD_1  32 //IR_OUT
+// PD_2  29 // SDIO_CMD
+// PD_3   2 // CTS
+// PD_4   3 // RTS
+// PD_5   4 // TX
+// PD_6   5 // RX
+// PD_7  34 // USER3
+// PD_8  39 // X_STOP
+// PD_9  40 // Y_STOP
+// PD_10 41 // Z_STOP
+// PD_11 42 // U_STOP
+// PD_12 71 // E1_PWM
+// PD_13 45 // BED_HEAT_2
+// PD_14 46 // BED_HEAT_1
+// PD_15 47 // BED_HEAT_3
+// PE_0  36 // USER2
+// PE_1   9 // STATUS_LED
+// PE_2  76 // E3_DIR
+// PE_3  75 // E3_RESET
+// PE_4  72 // E2_RESET
+// PE_5  73 // E2_PWM
+// PE_6  74 // E2_DIR
+// PE_7  38 // USER_BUTTON
+// PE_8  59 // E3_FAN
+// PE_9  65 // Y_DIR
+// PE_10 63 // Y_RESET
+// PE_11  7 // WIFI_RESET
+// PE_12  8 // WIFI_BOOT
+// PE_13 60 // X_RESET
+// PE_14 61 // X_PWM
+// PE_15 62 // X_DIR