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