diff --git a/Marlin/src/HAL/HC32/pinsDebug.h b/Marlin/src/HAL/HC32/pinsDebug.h
deleted file mode 100644
index e80b5a081e4..00000000000
--- a/Marlin/src/HAL/HC32/pinsDebug.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/**
- * Marlin 3D Printer Firmware
- * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- */
-#pragma once
-
-/**
- * Pins Debugging for HC32
- *
- * - NUMBER_PINS_TOTAL
- * - MULTI_NAME_PAD
- * - getPinByIndex(index)
- * - printPinNameByIndex(index)
- * - getPinIsDigitalByIndex(index)
- * - digitalPinToAnalogIndex(pin)
- * - getValidPinMode(pin)
- * - isValidPin(pin)
- * - isAnalogPin(pin)
- * - digitalRead_mod(pin)
- * - pwm_status(pin)
- * - printPinPWM(pin)
- * - printPinPort(pin)
- * - printPinNumber(pin)
- * - printPinAnalog(pin)
- */
-
-#include "../../inc/MarlinConfig.h"
-#include "fastio.h"
-#include
-
-#ifndef BOARD_NR_GPIO_PINS
- #error "Expected BOARD_NR_GPIO_PINS not found."
-#endif
-
-#define NUM_DIGITAL_PINS BOARD_NR_GPIO_PINS
-#define NUMBER_PINS_TOTAL BOARD_NR_GPIO_PINS
-#define isValidPin(P) IS_GPIO_PIN(P)
-
-// Note: pin_array is defined in `Marlin/src/pins/pinsDebug.h`, and since this file is included
-// after it, it is available in this file as well.
-#define getPinByIndex(x) pin_t(pin_array[x].pin)
-#define digitalRead_mod(P) extDigitalRead(P)
-
-#define printPinNumber(P) do{ sprintf_P(buffer, PSTR("%3hd "), int16_t(P)); SERIAL_ECHO(buffer); }while(0)
-#define printPinAnalog(P) do{ sprintf_P(buffer, PSTR(" (A%2d) "), digitalPinToAnalogIndex(P)); SERIAL_ECHO(buffer); }while(0)
-
-#define printPinNameByIndex(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0)
-
-#define MULTI_NAME_PAD 21 // Space needed to be pretty if not first name assigned to a pin
-
-//
-// Pins that will cause a hang / reset / disconnect in M43 Toggle and Watch utils
-//
-#ifndef M43_NEVER_TOUCH
- // Don't touch any of the following pins:
- // - Host serial pins, and
- // - Pins that could be connected to oscillators (see datasheet, Table 2.1):
- // - XTAL = PH0, PH1
- // - XTAL32 = PC14, PC15
- #define IS_HOST_USART_PIN(Q) (Q == BOARD_USART2_TX_PIN || Q == BOARD_USART2_RX_PIN)
- #define IS_OSC_PIN(Q) (Q == PH0 || Q == PH1 || Q == PC14 || Q == PC15)
-
- #define M43_NEVER_TOUCH(Q) (IS_HOST_USART_PIN(Q) || IS_OSC_PIN(Q))
-#endif
-
-int8_t digitalPinToAnalogIndex(const pin_t pin) {
- if (!isValidPin(pin)) return -1;
- const int8_t adc_channel = int8_t(PIN_MAP[pin].adc_info.channel);
- return pin_t(adc_channel);
-}
-
-bool isAnalogPin(pin_t pin) {
- if (!isValidPin(pin)) return false;
-
- if (PIN_MAP[pin].adc_info.channel != ADC_PIN_INVALID)
- return _GET_MODE(pin) == INPUT_ANALOG && !M43_NEVER_TOUCH(pin);
-
- return false;
-}
-
-bool getValidPinMode(const pin_t pin) {
- return isValidPin(pin) && !IS_INPUT(pin);
-}
-
-bool getPinIsDigitalByIndex(const int16_t index) {
- const pin_t pin = getPinByIndex(index);
- return (!isAnalogPin(pin));
-}
-
-/**
- * @brief print pin PWM status
- * @return true if pin is currently a PWM pin, false otherwise
- */
-bool pwm_status(const pin_t pin) {
- // Get timer assignment for pin
- timera_config_t *unit;
- en_timera_channel_t channel;
- en_port_func_t port_function;
- if (!timera_get_assignment(pin, unit, channel, port_function) || unit == nullptr) {
- // No pwm pin or no unit assigned
- return false;
- }
-
- // A pin that is PWM output is:
- // - Assigned to a timerA unit (tested above)
- // - Unit is initialized
- // - Channel is active
- // - PinMode is OUTPUT_PWM
- return timera_is_unit_initialized(unit) && timera_is_channel_active(unit, channel) && getPinMode(pin) == OUTPUT_PWM;
-}
-
-void printPinPWM(const pin_t pin) {
- // Get timer assignment for pin
- timera_config_t *unit;
- en_timera_channel_t channel;
- en_port_func_t port_function;
- if (!timera_get_assignment(pin, unit, channel, port_function) || unit == nullptr)
- return; // No pwm pin or no unit assigned
-
- // Print timer assignment of pin, eg. "TimerA1Ch2 Func4"
- SERIAL_ECHOPGM("TimerA", TIMERA_REG_TO_X(unit->peripheral.register_base),
- "Ch", TIMERA_CHANNEL_TO_X(channel),
- " Func", int(port_function));
- SERIAL_ECHO_SP(3); // 3 spaces
-
- // Print timer unit state, eg. "1/16 PERAR=1234" OR "N/A"
- if (timera_is_unit_initialized(unit)) {
- // Unit initialized, print
- // - Timer clock divider
- // - Timer period value (PERAR)
- const uint8_t clock_divider = timera_clk_div_to_n(unit->state.base_init->enClkDiv);
- const uint16_t period = TIMERA_GetPeriodValue(unit->peripheral.register_base);
- SERIAL_ECHOPGM("1/", clock_divider, " PERAR=", period);
- }
- else {
- // Unit not initialized
- SERIAL_ECHOPGM("N/A");
- return;
- }
-
- SERIAL_ECHO_SP(3); // 3 spaces
-
- // Print timer channel state, e.g. "CMPAR=1234" OR "N/A"
- if (timera_is_channel_active(unit, channel)) {
- // Channel active, print
- // - Channel compare value
- const uint16_t compare = TIMERA_GetCompareValue(unit->peripheral.register_base, channel);
- SERIAL_ECHOPGM("CMPAR=", compare);
- }
- else {
- // Channel inactive
- SERIAL_ECHOPGM("N/A");
- }
-}
-
-void printPinPort(pin_t pin) {
- const char port = 'A' + char(pin >> 4); // Pin div 16
- const int16_t gbit = PIN_MAP[pin].bit_pos;
- char buffer[8];
- sprintf_P(buffer, PSTR("P%c%hd "), port, gbit);
- if (gbit < 10) {
- SERIAL_CHAR(' ');
- }
-
- SERIAL_ECHO(buffer);
-}
diff --git a/Marlin/src/pins/samd/pins_MINITRONICS20.h b/Marlin/src/pins/samd/pins_MINITRONICS20.h
index 2111eb134ee..12cba80f000 100644
--- a/Marlin/src/pins/samd/pins_MINITRONICS20.h
+++ b/Marlin/src/pins/samd/pins_MINITRONICS20.h
@@ -22,7 +22,9 @@
#pragma once
/**
- * ReprapWorld's Minitronics v2.0
+ * ReprapWorld Minitronics v2.0
+ * https://reprap.org/wiki/Minitronics_20
+ * 48MHz Atmel SAMD21J18 ARM Cortex-M0+
*/
#if NOT_TARGET(__SAMD21__)
@@ -125,6 +127,11 @@
#endif
+// Verify that drivers match the hardware
+#if (HAS_X_AXIS && !AXIS_DRIVER_TYPE_X(DRV8825)) || (HAS_Y_AXIS && !AXIS_DRIVER_TYPE_Y(DRV8825)) || (HAS_Z_AXIS && !AXIS_DRIVER_TYPE_Z(DRV8825)) || (HAS_EXTRUDER && !AXIS_DRIVER_TYPE_E0(DRV8825))
+ #error "Minitronics v2.0 has hard-wired DRV8825 drivers. Comment out this line to continue."
+#endif
+
//
// Extruder / Bed
//
diff --git a/README.md b/README.md
index b6ec33bde6d..d355719faaa 100644
--- a/README.md
+++ b/README.md
@@ -60,12 +60,15 @@ Every new HAL opens up a world of hardware. At this time we need HALs for RP2040
[STM32F7x6](//www.st.com/en/microcontrollers-microprocessors/stm32f7x6.html)|ARM® Cortex-M7|The Borg, RemRam V1
[STM32G0B1RET6](//www.st.com/en/microcontrollers-microprocessors/stm32g0x1.html)|ARM® Cortex-M0+|BigTreeTech SKR mini E3 V3.0
[STM32H743xIT6](//www.st.com/en/microcontrollers-microprocessors/stm32h743-753.html)|ARM® Cortex-M7|BigTreeTech SKR V3.0, SKR EZ V3.0, SKR SE BX V2.0/V3.0
+ [SAMD21P20A](//www.adafruit.com/product/4064)|ARM® Cortex-M0+|Adafruit Grand Central M4
[SAMD51P20A](//www.adafruit.com/product/4064)|ARM® Cortex-M4|Adafruit Grand Central M4
- [Teensy 3.5](//www.pjrc.com/store/teensy35.html)|ARM® Cortex-M4|
- [Teensy 3.6](//www.pjrc.com/store/teensy36.html)|ARM® Cortex-M4|
- [Teensy 4.0](//www.pjrc.com/store/teensy40.html)|ARM® Cortex-M7|
- [Teensy 4.1](//www.pjrc.com/store/teensy41.html)|ARM® Cortex-M7|
- Linux Native|x86/ARM/etc.|Raspberry Pi
+ [Teensy 3.2/3.1](//www.pjrc.com/teensy/teensy31.html)|MK20DX256VLH7 ARM® Cortex-M4|
+ [Teensy 3.5](//www.pjrc.com/store/teensy35.html)|MK64FX512-VMD12 ARM® Cortex-M4|
+ [Teensy 3.6](//www.pjrc.com/store/teensy36.html)|MK66FX1MB-VMD18 ARM® Cortex-M4|
+ [Teensy 4.0](//www.pjrc.com/store/teensy40.html)|MIMXRT1062-DVL6B ARM® Cortex-M7|
+ [Teensy 4.1](//www.pjrc.com/store/teensy41.html)|MIMXRT1062-DVJ6B ARM® Cortex-M7|
+ Linux Native|x86 / ARM / RISC-V|Raspberry Pi GPIO
+ Simulator|Windows, macOS, Linux|Desktop OS
[All supported boards](//marlinfw.org/docs/hardware/boards.html#boards-list)|All platforms|All boards
## Marlin Support
diff --git a/ini/samd21.ini b/ini/samd21.ini
index f2acf829ff8..8652f13ba93 100644
--- a/ini/samd21.ini
+++ b/ini/samd21.ini
@@ -10,7 +10,7 @@
#################################
#
-# Adafruit Grand Central M4 (Atmel SAMD51P20A ARM Cortex-M4)
+# ReprapWorld Minitronics (Atmel SAMD21J18 ARM Cortex-M0+)
#
[env:SAMD21_minitronics20]
platform = atmelsam