diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h
index b607588568be..89469c620883 100644
--- a/Marlin/Configuration_adv.h
+++ b/Marlin/Configuration_adv.h
@@ -2978,9 +2978,9 @@
* but you can override or define them here.
*/
//#define TMC_USE_SW_SPI
- //#define TMC_SW_MOSI -1
- //#define TMC_SW_MISO -1
- //#define TMC_SW_SCK -1
+ //#define TMC_SPI_MOSI -1
+ //#define TMC_SPI_MISO -1
+ //#define TMC_SPI_SCK -1
// @section tmc/serial
diff --git a/Marlin/Marlin.ino b/Marlin/Marlin.ino
index 57c825445fb5..744e98c2e313 100644
--- a/Marlin/Marlin.ino
+++ b/Marlin/Marlin.ino
@@ -27,7 +27,7 @@ Configuration
- https://github.com/MarlinFirmware/Configurations
Example configurations for several printer models.
- - https://www.youtube.com/watch?v=3gwWVFtdg-4
+ - https://youtu.be/3gwWVFtdg-4
A good 20-minute overview of Marlin configuration by Tom Sanladerer.
(Applies to Marlin 1.0.x, so Jerk and Acceleration should be halved.)
Also... https://www.google.com/search?tbs=vid%3A1&q=configure+marlin
diff --git a/Marlin/src/HAL/AVR/HAL.cpp b/Marlin/src/HAL/AVR/HAL.cpp
index 5382eb36a2bd..c0deceb3d002 100644
--- a/Marlin/src/HAL/AVR/HAL.cpp
+++ b/Marlin/src/HAL/AVR/HAL.cpp
@@ -61,6 +61,12 @@ void save_reset_reason() {
wdt_disable();
}
+#include "registers.h"
+
+MarlinHAL::MarlinHAL() {
+ TERN_(HAL_AVR_DIRTY_INIT, _ATmega_resetperipherals()); // Clean-wipe the device state.
+}
+
void MarlinHAL::init() {
// Init Servo Pins
#define INIT_SERVO(N) OUT_WRITE(SERVO##N##_PIN, LOW)
@@ -78,6 +84,25 @@ void MarlinHAL::init() {
#endif
init_pwm_timers(); // Init user timers to default frequency - 1000HZ
+
+ #if defined(BEEPER_PIN) || ENABLED(ATMEGA_NO_BEEPFIX)
+ // Make sure no alternative is locked onto the BEEPER.
+ // This fixes the issue where the ATmega is constantly beeping.
+ // Might destroy other peripherals using the pin; to circumvent that please undefine one of the above things!
+ // The true culprit is the AVR ArduinoCore that enables peripherals redundantly.
+ // (USART1 on the GeeeTech GT2560)
+ _ATmega_savePinAlternate(BEEPER_PIN);
+
+ OUT_WRITE(BEEPER_PIN, LOW);
+ #endif
+
+ // EXAMPLE: beep loop using proper pin state.
+ #if 0 && defined(BEEPER_PIN)
+ while (true) {
+ OUT_WRITE(BEEPER_PIN, HIGH); delay(1000);
+ OUT_WRITE(BEEPER_PIN, LOW); delay(2000);
+ }
+ #endif
}
void MarlinHAL::reboot() {
diff --git a/Marlin/src/HAL/AVR/HAL.h b/Marlin/src/HAL/AVR/HAL.h
index d458790979ff..465307fb0373 100644
--- a/Marlin/src/HAL/AVR/HAL.h
+++ b/Marlin/src/HAL/AVR/HAL.h
@@ -187,7 +187,7 @@ class MarlinHAL {
public:
// Earliest possible init, before setup()
- MarlinHAL() {}
+ MarlinHAL();
// Watchdog
static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {});
diff --git a/Marlin/src/HAL/AVR/HAL_SPI.cpp b/Marlin/src/HAL/AVR/HAL_SPI.cpp
deleted file mode 100644
index dc98f2f79e71..000000000000
--- a/Marlin/src/HAL/AVR/HAL_SPI.cpp
+++ /dev/null
@@ -1,254 +0,0 @@
-/**
- * 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 Arduino Sd2Card Library
- * Copyright (c) 2009 by William Greiman
- */
-
-/**
- * HAL for AVR - SPI functions
- */
-
-#ifdef __AVR__
-
-#include "../../inc/MarlinConfig.h"
-
-void spiBegin() {
- #if PIN_EXISTS(SD_SS)
- // Do not init HIGH for boards with pin 4 used as Fans or Heaters or otherwise, not likely to have multiple SPI devices anyway.
- #if defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega1284P__)
- // SS must be in output mode even it is not chip select
- SET_OUTPUT(SD_SS_PIN);
- #else
- // set SS high - may be chip select for another SPI device
- OUT_WRITE(SD_SS_PIN, HIGH);
- #endif
- #endif
- SET_OUTPUT(SD_SCK_PIN);
- SET_INPUT(SD_MISO_PIN);
- SET_OUTPUT(SD_MOSI_PIN);
-
- IF_DISABLED(SOFTWARE_SPI, spiInit(SPI_HALF_SPEED));
-}
-
-#if NONE(SOFTWARE_SPI, FORCE_SOFT_SPI)
-
- // ------------------------
- // Hardware SPI
- // ------------------------
-
- // make sure SPCR rate is in expected bits
- #if (SPR0 != 0 || SPR1 != 1)
- #error "unexpected SPCR bits"
- #endif
-
- /**
- * Initialize hardware SPI
- * Set SCK rate to F_CPU/pow(2, 1 + spiRate) for spiRate [0,6]
- */
- void spiInit(uint8_t spiRate) {
- // See avr processor documentation
- CBI(
- #ifdef PRR
- PRR
- #elif defined(PRR0)
- PRR0
- #endif
- , PRSPI
- );
-
- SPCR = _BV(SPE) | _BV(MSTR) | (spiRate >> 1);
- SPSR = spiRate & 1 || spiRate == 6 ? 0 : _BV(SPI2X);
- }
-
- /** SPI receive a byte */
- uint8_t spiRec() {
- SPDR = 0xFF;
- while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
- return SPDR;
- }
-
- /** SPI read data */
- void spiRead(uint8_t *buf, uint16_t nbyte) {
- if (nbyte-- == 0) return;
- SPDR = 0xFF;
- for (uint16_t i = 0; i < nbyte; i++) {
- while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
- buf[i] = SPDR;
- SPDR = 0xFF;
- }
- while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
- buf[nbyte] = SPDR;
- }
-
- /** SPI send a byte */
- void spiSend(uint8_t b) {
- SPDR = b;
- while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
- }
-
- /** SPI send block */
- void spiSendBlock(uint8_t token, const uint8_t *buf) {
- SPDR = token;
- for (uint16_t i = 0; i < 512; i += 2) {
- while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
- SPDR = buf[i];
- while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
- SPDR = buf[i + 1];
- }
- while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
- }
-
-
- /** begin spi transaction */
- void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) {
- // Based on Arduino SPI library
- // Clock settings are defined as follows. Note that this shows SPI2X
- // inverted, so the bits form increasing numbers. Also note that
- // fosc/64 appears twice
- // SPR1 SPR0 ~SPI2X Freq
- // 0 0 0 fosc/2
- // 0 0 1 fosc/4
- // 0 1 0 fosc/8
- // 0 1 1 fosc/16
- // 1 0 0 fosc/32
- // 1 0 1 fosc/64
- // 1 1 0 fosc/64
- // 1 1 1 fosc/128
-
- // We find the fastest clock that is less than or equal to the
- // given clock rate. The clock divider that results in clock_setting
- // is 2 ^^ (clock_div + 1). If nothing is slow enough, we'll use the
- // slowest (128 == 2 ^^ 7, so clock_div = 6).
- uint8_t clockDiv;
-
- // When the clock is known at compiletime, use this if-then-else
- // cascade, which the compiler knows how to completely optimize
- // away. When clock is not known, use a loop instead, which generates
- // shorter code.
- if (__builtin_constant_p(spiClock)) {
- if (spiClock >= F_CPU / 2) clockDiv = 0;
- else if (spiClock >= F_CPU / 4) clockDiv = 1;
- else if (spiClock >= F_CPU / 8) clockDiv = 2;
- else if (spiClock >= F_CPU / 16) clockDiv = 3;
- else if (spiClock >= F_CPU / 32) clockDiv = 4;
- else if (spiClock >= F_CPU / 64) clockDiv = 5;
- else clockDiv = 6;
- }
- else {
- uint32_t clockSetting = F_CPU / 2;
- clockDiv = 0;
- while (clockDiv < 6 && spiClock < clockSetting) {
- clockSetting /= 2;
- clockDiv++;
- }
- }
-
- // Compensate for the duplicate fosc/64
- if (clockDiv == 6) clockDiv = 7;
-
- // Invert the SPI2X bit
- clockDiv ^= 0x1;
-
- SPCR = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) |
- (dataMode << CPHA) | ((clockDiv >> 1) << SPR0);
- SPSR = clockDiv | 0x01;
- }
-
-
-#else // SOFTWARE_SPI || FORCE_SOFT_SPI
-
- // ------------------------
- // Software SPI
- // ------------------------
-
- // nop to tune soft SPI timing
- #define nop asm volatile ("\tnop\n")
-
- void spiInit(uint8_t) { /* do nothing */ }
-
- // Begin SPI transaction, set clock, bit order, data mode
- void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) { /* do nothing */ }
-
- // Soft SPI receive byte
- uint8_t spiRec() {
- uint8_t data = 0;
- // no interrupts during byte receive - about 8µs
- cli();
- // output pin high - like sending 0xFF
- WRITE(SD_MOSI_PIN, HIGH);
-
- LOOP_L_N(i, 8) {
- WRITE(SD_SCK_PIN, HIGH);
-
- nop; // adjust so SCK is nice
- nop;
-
- data <<= 1;
-
- if (READ(SD_MISO_PIN)) data |= 1;
-
- WRITE(SD_SCK_PIN, LOW);
- }
-
- sei();
- return data;
- }
-
- // Soft SPI read data
- void spiRead(uint8_t *buf, uint16_t nbyte) {
- for (uint16_t i = 0; i < nbyte; i++)
- buf[i] = spiRec();
- }
-
- // Soft SPI send byte
- void spiSend(uint8_t data) {
- // no interrupts during byte send - about 8µs
- cli();
- LOOP_L_N(i, 8) {
- WRITE(SD_SCK_PIN, LOW);
- WRITE(SD_MOSI_PIN, data & 0x80);
- data <<= 1;
- WRITE(SD_SCK_PIN, HIGH);
- }
-
- nop; // hold SCK high for a few ns
- nop;
- nop;
- nop;
-
- WRITE(SD_SCK_PIN, LOW);
-
- sei();
- }
-
- // Soft SPI send block
- void spiSendBlock(uint8_t token, const uint8_t *buf) {
- spiSend(token);
- for (uint16_t i = 0; i < 512; i++)
- spiSend(buf[i]);
- }
-
-#endif // SOFTWARE_SPI || FORCE_SOFT_SPI
-
-#endif // __AVR__
diff --git a/Marlin/src/HAL/AVR/HAL_SPI_HW.cpp b/Marlin/src/HAL/AVR/HAL_SPI_HW.cpp
new file mode 100644
index 000000000000..314ad365af00
--- /dev/null
+++ b/Marlin/src/HAL/AVR/HAL_SPI_HW.cpp
@@ -0,0 +1,585 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2023 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 .
+ *
+ */
+
+/**
+ * AVR HAL SPI implementation by Martin Turski, company owner of EirDev
+ * This implementation was specifically made for the Marlin FW.
+ * For inquiries please contact turningtides@outlook.de
+ * If there is any issue with this implementation, please open an inquiry on GitHub
+ * and include the link in the mail. Otherwise your mail may get ignored.
+ * Made to improve the reliability and future-proof Marlin.
+ */
+
+/**
+ * HAL for AVR - SPI functions
+ */
+
+#ifdef __AVR__
+
+#include "../../inc/MarlinConfig.h"
+
+#if NONE(SOFTWARE_SPI, FORCE_SOFT_SPI, HALSPI_HW_GENERIC)
+
+#include "registers.h"
+
+#include
+
+#ifndef AVR_CHIPOSCILLATOR_FREQ
+ #error "Missing AVR crystal oscillator frequency (AVR_CHIPOSCILLATOR_FREQ)! Consult manufacturer schematics for further details (XTAL1/XTAL2 pins as guidance)"
+#endif
+
+// ------------------------
+// Hardware SPI
+// ------------------------
+
+static void _spi_on_error(int code) {
+ for (;;) {
+ #if ENABLED(HALSPI_DO_ERRORBEEPS) && PIN_EXISTS(BEEPER)
+ OUT_WRITE(BEEPER_PIN, HIGH);
+ delay(400);
+ OUT_WRITE(BEEPER_PIN, LOW);
+ delay(400);
+ OUT_WRITE(BEEPER_PIN, HIGH);
+ delay(400);
+ OUT_WRITE(BEEPER_PIN, LOW);
+ delay(400);
+ OUT_WRITE(BEEPER_PIN, HIGH);
+ delay(1000);
+ OUT_WRITE(BEEPER_PIN, LOW);
+ delay(1000);
+ for (int n = 0; n < code; n++) {
+ OUT_WRITE(BEEPER_PIN, HIGH);
+ delay(500);
+ OUT_WRITE(BEEPER_PIN, LOW);
+ if (n < code-1)
+ delay(500);
+ }
+ delay(1000);
+ OUT_WRITE(BEEPER_PIN, HIGH);
+ delay(800);
+ OUT_WRITE(BEEPER_PIN, LOW);
+ delay(2000);
+ #endif
+ }
+}
+
+#ifndef HALSPI_LOOPBEEP_TIMEOUT
+ #define HALSPI_LOOPBEEP_TIMEOUT 3000
+#endif
+
+struct spi_monitored_loop {
+private:
+ #if defined(HALSPI_DO_LOOPBEEPS) && PIN_EXISTS(BEEPER)
+ uint32_t _start_millis;
+ #endif
+public:
+ inline spi_monitored_loop() {
+ #if defined(HALSPI_DO_LOOPBEEPS) && PIN_EXISTS(BEEPER)
+ _start_millis = millis();
+ #endif
+ }
+ inline void update(unsigned int beep_code) {
+ #if defined(HALSPI_DO_LOOPBEEPS) && PIN_EXISTS(BEEPER)
+ if ((millis() - _start_millis) <= HALSPI_LOOPBEEP_TIMEOUT) return;
+ OUT_WRITE(BEEPER_PIN, HIGH);
+ delay(500);
+ OUT_WRITE(BEEPER_PIN, LOW);
+ delay(200);
+ OUT_WRITE(BEEPER_PIN, HIGH);
+ delay(200);
+ OUT_WRITE(BEEPER_PIN, LOW);
+ delay(200);
+ OUT_WRITE(BEEPER_PIN, HIGH);
+ delay(200);
+ OUT_WRITE(BEEPER_PIN, LOW);
+ delay(1000);
+ for (unsigned int n = 0; n < beep_code; n++) {
+ OUT_WRITE(BEEPER_PIN, HIGH);
+ delay(200);
+ OUT_WRITE(BEEPER_PIN, LOW);
+ delay(200);
+ }
+ delay(800);
+ OUT_WRITE(BEEPER_PIN, HIGH);
+ delay(1000);
+ OUT_WRITE(BEEPER_PIN, LOW);
+ delay(2000);
+ #endif
+ }
+};
+
+static bool _spi_is_running = false;
+static int _spi_cs_pin;
+static bool _spi_transaction_is_active;
+static bool _spi_dirty_tx;
+
+#if defined(GET_LOW_FUSE_BITS)
+ static uint8_t _spi_lfuse;
+#endif
+
+void spiBegin() {
+ #if PIN_EXISTS(SD_SS)
+ // Do not init HIGH for boards with pin 4 used as Fans or Heaters or otherwise, not likely to have multiple SPI devices anyway.
+ #if defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega1284P__)
+ // SS must be in output mode even if it is not chip select
+ SET_OUTPUT(SD_SS_PIN);
+ #else
+ // set SS high - may be chip select for another SPI device
+ OUT_WRITE(SD_SS_PIN, HIGH);
+ #endif
+ #endif
+ // This could still be required because the specification says that the DDR of those pins is "User Defined".
+ // (we only support master SPI)
+ SET_OUTPUT(SD_SCK_PIN);
+ SET_INPUT(SD_MISO_PIN);
+ SET_OUTPUT(SD_MOSI_PIN);
+
+ #ifdef GET_LOW_FUSE_BITS
+ cli();
+ _spi_lfuse = boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS);
+ sei();
+ #endif
+
+ // By default we disable the SPI peripheral.
+ _PRR0._PRSPI = false;
+ _SPCR._SPE = false;
+ _PRR0._PRSPI = true;
+}
+
+// Returns the clock frequency as output by the System Clock Prescaler.
+inline uint32_t _GetSystemClockFrequency() {
+ // See which clock is selected.
+ const ATmega_lfuse lfuse = (
+ #ifndef GET_LOW_FUSE_BITS
+ AVR_DEFAULT_LFUSE_VALUE
+ #else
+ _spi_lfuse
+ #endif
+ );
+
+ uint32_t baseclk;
+
+ switch (lfuse._CKSEL) {
+ case 15: case 14: case 13: case 12: case 11: case 10: case 9: case 8:
+ case 7: case 6: case 5: case 4:
+ baseclk = AVR_CHIPOSCILLATOR_FREQ;
+ break;
+ case 3:
+ // Internal 128kHz RC Oscillator.
+ baseclk = 128000;
+ break;
+ case 2:
+ // Calibrated Internal RC Oscillator.
+ baseclk = 8000000;
+ break;
+ case 1:
+ case 0:
+ _spi_on_error(3);
+ break;
+ }
+
+ // Divide the system clock.
+ uint8_t clkps_po2 = _CLKPR._CLKPS;
+
+ return ( baseclk >> clkps_po2 );
+}
+
+// We could improve these definitions if we had C++20.
+template // SPCR_reg_t
+inline void _spiConfigBitOrder(regType& __SPCR, int mode) {
+ if (mode == SPI_BITORDER_LSB)
+ __SPCR._DORD = 1;
+ else if (mode == SPI_BITORDER_MSB)
+ __SPCR._DORD = 0;
+}
+
+template // SPCR_reg_t
+inline void _spiConfigClockMode(regType& __SPCR, int mode) {
+ if (mode == SPI_CLKMODE_0) {
+ __SPCR._CPOL = 0;
+ __SPCR._CPHA = 0;
+ }
+ else if (mode == SPI_CLKMODE_1) {
+ __SPCR._CPOL = 0;
+ __SPCR._CPHA = 1;
+ }
+ else if (mode == SPI_CLKMODE_2) {
+ __SPCR._CPOL = 1;
+ __SPCR._CPHA = 0;
+ }
+ else if (mode == SPI_CLKMODE_3) {
+ __SPCR._CPOL = 1;
+ __SPCR._CPHA = 1;
+ }
+}
+
+#ifndef HALSPI_AVR_NO_SLEEP
+
+ static volatile bool _spi_txcomplete = true;
+
+ inline void _spi_enter_wait() {
+ cli();
+
+ SMCR_reg_t __SMCR;
+ __SMCR._SE = true;
+ __SMCR._SM = 0; // IDLE
+ __SMCR.reserved1 = 0;
+ AVRHelpers::dwrite(_SMCR, __SMCR);
+
+ // Enable the SPI interrupt.
+ _SPCR._SPIE = true;
+ _spi_txcomplete = false;
+
+ sei();
+ }
+
+ inline void _spi_leave_wait() {
+ SMCR_reg_t __SMCR;
+ __SMCR._SE = false;
+ __SMCR._SM = 0;
+ __SMCR.reserved1 = 0;
+ AVRHelpers::dwrite(_SMCR, __SMCR);
+
+ // Disable the SPI interrupt.
+ _SPCR._SPIE = false;
+ _spi_txcomplete = true;
+ }
+
+ #include
+
+ ISR(SPI_STC_vect) {
+ // Make sure that a SLEEP instruction right after this interrupt call does not halt the processor.
+ // This is sort of like an event variable in Win32 or a futex in Linux.
+ _spi_leave_wait();
+ }
+
+#endif // !HALSPI_AVR_NO_SLEEP
+
+inline void _spi_waitForInterrupt() {
+ #ifndef HALSPI_AVR_NO_SLEEP
+ // This function is meant to sleep until the AVR SPI peripheral triggers the SPIF interrupt.
+ __asm__ __volatile__(
+ A("SLEEP")
+ );
+ #endif
+}
+
+inline bool _spi_hasTransferCompleted() {
+ return (
+ #ifdef HALSPI_AVR_NO_SLEEP
+ _SPSR._SPIF
+ #else
+ _spi_txcomplete
+ #endif
+ );
+}
+
+inline void _spi_push(uint8_t b) {
+ #ifndef HALSPI_AVR_NO_SLEEP
+ _spi_enter_wait();
+ #endif
+ _SPDR = b;
+}
+
+/**
+ * Initialize hardware SPI transaction
+ */
+void spiInitEx(uint32_t maxClockFreq, const int hint_sck/*=-1*/, const int hint_miso/*=-1*/, const int hint_mosi/*=-1*/, const int hint_cs/*=-1*/) {
+ if (_spi_is_running)
+ _spi_on_error(1);
+
+ // In hardware SPI mode we can only use the pre-determined SPI pins for MISO, MOSI and SCK, thus ignore the first three pin hints.
+ // We only support master SPI for now.
+ // For this we have to configure the chip-select (~SS) pin as output.
+ // This way it cannot be driven low by external peripherals., thus keeping our master state.
+ _spi_cs_pin = hint_cs;
+
+ // Clear the power-reduction.
+ _PRR0._PRSPI = false;
+
+ // Calculate the required division to run the SPI clock below maxClockFreq.
+ uint32_t sysclk = _GetSystemClockFrequency();
+
+ SPCR_reg_t __SPCR;
+ __SPCR._SPIE = false;
+ __SPCR._SPE = false;
+ _spiConfigBitOrder(__SPCR, SPI_BITORDER_DEFAULT);
+ __SPCR._MSTR = true;
+ _spiConfigClockMode(__SPCR, SPI_CLKMODE_DEFAULT);
+
+ if ((sysclk / 2) <= maxClockFreq) {
+ _SPSR._SPI2X = true;
+ __SPCR._SPR = 0;
+ }
+ else if ((sysclk / 4) <= maxClockFreq) {
+ _SPSR._SPI2X = false;
+ __SPCR._SPR = 0;
+ }
+ else if ((sysclk / 8) <= maxClockFreq) {
+ _SPSR._SPI2X = true;
+ __SPCR._SPR = 1;
+ }
+ else if ((sysclk / 16) <= maxClockFreq) {
+ _SPSR._SPI2X = false;
+ __SPCR._SPR = 1;
+ }
+ else if ((sysclk / 32) <= maxClockFreq) {
+ _SPSR._SPI2X = true;
+ __SPCR._SPR = 2;
+ }
+ else if ((sysclk / 64) <= maxClockFreq) {
+ _SPSR._SPI2X = false;
+ __SPCR._SPR = 2;
+ }
+ else {
+ // Cannot go below it.
+ _SPSR._SPI2X = false;
+ __SPCR._SPR = 3;
+ }
+
+ // Write initial configuration.
+ AVRHelpers::dwrite(_SPCR, __SPCR);
+
+ _spi_is_running = true;
+ _spi_transaction_is_active = false;
+ _spi_dirty_tx = false;
+}
+
+static void _maybe_start_transaction() {
+ if (_spi_transaction_is_active) return;
+
+ _SPCR._SPE = true;
+
+ if (_spi_cs_pin >= 0) {
+ _ATmega_pinMode(_spi_cs_pin, OUTPUT);
+ _ATmega_digitalWrite(_spi_cs_pin, LOW);
+ }
+
+ _spi_transaction_is_active = true;
+}
+
+void spiInit(uint8_t spiRate, int hint_sck, int hint_miso, int hint_mosi, int hint_cs) {
+ // Use Marlin datarates
+ uint32_t clock;
+ switch (spiRate) {
+ case SPI_FULL_SPEED: clock = 20000000; break; // 13.9mhz=20000000 6.75mhz=10000000 3.38mhz=5000000 .833mhz=1000000
+ case SPI_HALF_SPEED: clock = 5000000; break;
+ case SPI_QUARTER_SPEED: clock = 2500000; break;
+ case SPI_EIGHTH_SPEED: clock = 1250000; break;
+ case SPI_SPEED_5: clock = 625000; break;
+ case SPI_SPEED_6: clock = 300000; break;
+ default:
+ clock = 4000000; // Default from the SPI library
+ }
+ spiInitEx(clock, hint_sck, hint_miso, hint_mosi, hint_cs);
+}
+
+inline void _spi_safety_delay() {
+ //asm("nop"); // enable this if you encounter any delay troubles.
+}
+
+inline void _spi_finish_tx() {
+ if (_spi_dirty_tx == false) return;
+
+ _spi_safety_delay();
+ spi_monitored_loop txew;
+ while (_spi_hasTransferCompleted() == false) { txew.update(1); _spi_waitForInterrupt(); }
+
+ _spi_dirty_tx = false;
+}
+
+void spiClose() {
+ if (_spi_is_running == false)
+ _spi_on_error(2);
+
+ if (_spi_transaction_is_active) {
+ _spi_finish_tx();
+
+ if (_spi_cs_pin >= 0)
+ _ATmega_digitalWrite(_spi_cs_pin, HIGH);
+
+ _SPCR._SPE = false;
+
+ _spi_transaction_is_active = false;
+ }
+
+ // Disable the peripheral again.
+ _PRR0._PRSPI = true;
+
+ _spi_is_running = false;
+}
+
+void spiSetBitOrder(int bitOrder) {
+ if (_spi_is_running == false) _spi_on_error(4);
+ _spiConfigBitOrder(_SPCR, bitOrder);
+}
+
+void spiSetClockMode(int clockMode) {
+ if (_spi_is_running == false) _spi_on_error(4);
+ _spiConfigClockMode(_SPCR, clockMode);
+}
+
+void spiEstablish() {
+ if (_spi_is_running == false) _spi_on_error(4);
+ _maybe_start_transaction();
+}
+
+// SPI receive a byte
+uint8_t spiRec(uint8_t txval) {
+ if (_spi_is_running == false) _spi_on_error(4);
+ _maybe_start_transaction();
+ _spi_finish_tx();
+ _spi_push(txval);
+ _spi_safety_delay();
+ spi_monitored_loop rxew;
+ while (_spi_hasTransferCompleted() == false) { rxew.update(2); _spi_waitForInterrupt(); }
+ return _SPDR;
+}
+
+inline void _split_txbytes(uint16_t txval, uint8_t& tx_first, uint8_t& tx_second, bool msb) {
+ if (msb) {
+ tx_first = txval >> 8;
+ tx_second = txval & 0xFF;
+ }
+ else {
+ tx_first = txval & 0xFF;
+ tx_second = txval >> 8;
+ }
+}
+
+inline uint16_t _fuse_txbytes(uint8_t rx_first, uint8_t rx_second, bool msb) {
+ if (msb)
+ return ( (uint16_t)rx_first << 8 ) | ( (uint16_t)rx_second );
+ else
+ return ( (uint16_t)rx_first ) | ( (uint16_t)rx_second << 8 );
+}
+
+uint16_t spiRec16(uint16_t txval) {
+ if (_spi_is_running == false) _spi_on_error(4);
+ _maybe_start_transaction();
+ bool msb = ( _SPCR._DORD == 0 );
+ uint8_t tx_first, tx_second;
+ _split_txbytes(txval, tx_first, tx_second, msb);
+ _spi_finish_tx();
+ _spi_push(tx_first);
+ _spi_safety_delay();
+ spi_monitored_loop rxe1w;
+ while (_spi_hasTransferCompleted() == false) { rxe1w.update(3); _spi_waitForInterrupt(); }
+ uint8_t rx_first = _SPDR;
+ _spi_push(tx_second);
+ _spi_safety_delay();
+ spi_monitored_loop rxe2w;
+ while (_spi_hasTransferCompleted() == false) { rxe2w.update(4); _spi_waitForInterrupt(); }
+ uint8_t rx_second = _SPDR;
+ return _fuse_txbytes(rx_first, rx_second, msb);
+}
+
+// SPI read data
+void spiRead(uint8_t *buf, uint16_t nbyte, uint8_t txval) {
+ if (_spi_is_running == false) _spi_on_error(4);
+ if (nbyte == 0) return;
+ _maybe_start_transaction();
+ _spi_finish_tx();
+ for (uint16_t i = 0; i < nbyte; i++) {
+ _spi_push(txval);
+ _spi_safety_delay();
+ spi_monitored_loop rxew;
+ while (_spi_hasTransferCompleted() == false) { rxew.update(5); _spi_waitForInterrupt(); }
+ buf[i] = _SPDR;
+ }
+}
+
+inline void _spiSendByte(uint8_t byte) {
+ _spi_finish_tx();
+ _spi_push(byte);
+ _spi_dirty_tx = true;
+}
+
+// SPI send a byte
+void spiSend(uint8_t b) {
+ if (_spi_is_running == false) _spi_on_error(4);
+ _maybe_start_transaction();
+ _spiSendByte(b);
+}
+
+void spiSend16(uint16_t v) {
+ if (_spi_is_running == false) _spi_on_error(4);
+ _maybe_start_transaction();
+ bool msb = ( _SPCR._DORD == 0 );
+ uint8_t tx_first, tx_second;
+ _split_txbytes(v, tx_first, tx_second, msb);
+ _spiSendByte(tx_first);
+ _spiSendByte(tx_second);
+}
+
+// SPI send block
+void spiSendBlock(uint8_t token, const uint8_t *buf) {
+ if (_spi_is_running == false) _spi_on_error(4);
+ _maybe_start_transaction();
+ _spiSendByte(token);
+ for (uint16_t i = 0; i < 512; i++) {
+ _spiSendByte(buf[i]);
+ }
+}
+
+// Begin SPI transaction
+void spiWrite(const uint8_t *buf, uint16_t cnt) {
+ if (_spi_is_running == false) _spi_on_error(4);
+ _maybe_start_transaction();
+ for (uint16_t n = 0; n < cnt; n++)
+ _spiSendByte(buf[n]);
+}
+
+void spiWrite16(const uint16_t *buf, uint16_t cnt) {
+ if (_spi_is_running == false) _spi_on_error(4);
+ _maybe_start_transaction();
+ bool msb = ( _SPCR._DORD == 0 );
+ for (uint16_t n = 0; n < cnt; n++) {
+ uint8_t tx_first, tx_second;
+ _split_txbytes(buf[n], tx_first, tx_second, msb);
+ _spiSendByte(tx_first);
+ _spiSendByte(tx_second);
+ }
+}
+
+void spiWriteRepeat(uint8_t val, uint16_t repcnt) {
+ if (_spi_is_running == false) _spi_on_error(4);
+ _maybe_start_transaction();
+ for (uint16_t n = 0; n < repcnt; n++)
+ _spiSendByte(val);
+}
+
+void spiWriteRepeat16(uint16_t val, uint16_t repcnt) {
+ if (_spi_is_running == false) _spi_on_error(4);
+ _maybe_start_transaction();
+ bool msb = ( _SPCR._DORD == 0 );
+ uint8_t tx_first, tx_second;
+ _split_txbytes(val, tx_first, tx_second, msb);
+ for (uint16_t n = 0; n < repcnt; n++) {
+ _spiSendByte(tx_first);
+ _spiSendByte(tx_second);
+ }
+}
+
+#endif // !SOFTWARE_SPI && !FORCE_SOFT_SPI && !HALSPI_HW_GENERIC
+
+#endif // __AVR__
diff --git a/Marlin/src/HAL/AVR/HAL_SPI_HWgen.cpp b/Marlin/src/HAL/AVR/HAL_SPI_HWgen.cpp
new file mode 100644
index 000000000000..69c20f264a93
--- /dev/null
+++ b/Marlin/src/HAL/AVR/HAL_SPI_HWgen.cpp
@@ -0,0 +1,236 @@
+/**
+ * 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 .
+ *
+ */
+
+/**
+ * HAL for AVR - SPI functions
+ */
+
+#ifdef __AVR__
+
+#include "../../inc/MarlinConfig.h"
+
+#if NONE(SOFTWARE_SPI, FORCE_SOFT_SPI) && ENABLED(HALSPI_HW_GENERIC)
+
+#include
+
+#include "registers.h"
+
+ void spiBegin() {
+ #if PIN_EXISTS(SD_SS)
+ // Do not init HIGH for boards with pin 4 used as Fans or Heaters or otherwise, not likely to have multiple SPI devices anyway.
+ #if defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega1284P__)
+ // SS must be in output mode even if it is not chip select
+ SET_OUTPUT(SD_SS_PIN);
+ #else
+ // set SS high - may be chip select for another SPI device
+ OUT_WRITE(SD_SS_PIN, HIGH);
+ #endif
+ #endif
+ // This could still be required because the specification says that the DDR of those pins is "User Defined".
+ // (we only support master SPI)
+ SET_OUTPUT(SD_SCK_PIN);
+ SET_INPUT(SD_MISO_PIN);
+ SET_OUTPUT(SD_MOSI_PIN);
+ }
+
+ static SPISettings _spi_config;
+ static uint32_t _spi_maxClockFreq;
+ static int _spi_clockMode;
+ static int _spi_bitOrder;
+ static bool _spi_transaction_is_running;
+ static int _spi_cs_pin;
+
+ void spiInitEx(uint32_t maxClockFreq, const int hint_sck/*=-1*/, const int hint_miso/*=-1*/, const int hint_mosi/*=-1*/, const int hint_cs/*=-1*/) {
+ SPI.begin();
+
+ _spi_maxClockFreq = maxClockFreq;
+ _spi_clockMode = SPI_MODE0;
+ _spi_bitOrder = MSBFIRST;
+ _spi_config = SPISettings(_spi_maxClockFreq, _spi_bitOrder, _spi_clockMode);
+
+ _spi_cs_pin = hint_cs;
+
+ _spi_transaction_is_running = false;
+ }
+
+ void spiInit(uint8_t spiRate, int hint_sck, int hint_miso, int hint_mosi, int hint_cs) {
+ // Use Marlin datarates
+ uint32_t clock;
+ switch (spiRate) {
+ case SPI_FULL_SPEED: clock = 20000000; break; // 13.9mhz=20000000 6.75mhz=10000000 3.38mhz=5000000 .833mhz=1000000
+ case SPI_HALF_SPEED: clock = 5000000; break;
+ case SPI_QUARTER_SPEED: clock = 2500000; break;
+ case SPI_EIGHTH_SPEED: clock = 1250000; break;
+ case SPI_SPEED_5: clock = 625000; break;
+ case SPI_SPEED_6: clock = 300000; break;
+ default:
+ clock = 4000000; // Default from the SPI library
+ }
+ spiInitEx(clock, hint_sck, hint_miso, hint_mosi, hint_cs);
+ }
+
+ void spiClose() {
+ if (_spi_transaction_is_running) {
+ if (_spi_cs_pin >= 0)
+ _ATmega_digitalWrite(_spi_cs_pin, HIGH);
+
+ SPI.endTransaction();
+
+ _spi_transaction_is_running = false;
+ }
+
+ SPI.end();
+ }
+
+ void spiSetBitOrder(int bitOrder) {
+ int new_bitOrder;
+
+ if (bitOrder == SPI_BITORDER_MSB) {
+ new_bitOrder = MSBFIRST;
+ }
+ else if (bitOrder == SPI_BITORDER_LSB) {
+ new_bitOrder = LSBFIRST;
+ }
+ else return;
+
+ if (_spi_bitOrder == new_bitOrder) return;
+
+ _spi_bitOrder = new_bitOrder;
+ _spi_config = SPISettings(_spi_maxClockFreq, _spi_bitOrder, _spi_clockMode);
+
+ if (_spi_transaction_is_running) {
+ SPI.endTransaction();
+ SPI.beginTransaction(_spi_config);
+ }
+ }
+
+ void spiSetClockMode(int clockMode) {
+ int new_clockMode;
+
+ if (clockMode == SPI_CLKMODE_0) {
+ new_clockMode = SPI_MODE0;
+ }
+ else if (clockMode == SPI_CLKMODE_1) {
+ new_clockMode = SPI_MODE1;
+ }
+ else if (clockMode == SPI_CLKMODE_2) {
+ new_clockMode = SPI_MODE2;
+ }
+ else if (clockMode == SPI_CLKMODE_3) {
+ new_clockMode = SPI_MODE3;
+ }
+ else return;
+
+ if (new_clockMode == _spi_clockMode) return;
+
+ _spi_clockMode = new_clockMode;
+ _spi_config = SPISettings(_spi_maxClockFreq, _spi_bitOrder, _spi_clockMode);
+
+ if (_spi_transaction_is_running) {
+ SPI.endTransaction();
+ SPI.beginTransaction(_spi_config);
+ }
+ }
+
+ static void _maybe_start_transaction() {
+ if (_spi_transaction_is_running) return;
+
+ SPI.beginTransaction(_spi_config);
+
+ if (_spi_cs_pin >= 0) {
+ _ATmega_pinMode(_spi_cs_pin, OUTPUT);
+ _ATmega_digitalWrite(_spi_cs_pin, LOW);
+ }
+
+ _spi_transaction_is_running = true;
+ }
+
+ void spiEstablish() {
+ _maybe_start_transaction();
+ }
+
+ void spiSend(uint8_t txval) {
+ _maybe_start_transaction();
+ (void)SPI.transfer(txval);
+ }
+
+ void spiSend16(uint8_t txval) {
+ _maybe_start_transaction();
+ (void)SPI.transfer16(txval);
+ }
+
+ uint8_t spiRec(uint8_t txval) {
+ _maybe_start_transaction();
+ return SPI.transfer(txval);
+ }
+
+ uint16_t spiRec16(uint16_t txval) {
+ _maybe_start_transaction();
+ return SPI.transfer16(txval);
+ }
+
+ void spiRead(uint8_t *buf, uint16_t rdcnt, uint8_t txval) {
+ _maybe_start_transaction();
+ for (uint16_t n = 0; n < rdcnt; n++) {
+ buf[n] = SPI.transfer(txval);
+ }
+ }
+
+ void spiSendBlock(uint8_t token, const uint8_t *block) {
+ _maybe_start_transaction();
+ (void)SPI.transfer(token);
+ for (uint16_t n = 0; n < 512; n++) {
+ (void)SPI.transfer(block[n]);
+ }
+ }
+
+ void spiWrite(const uint8_t *buf, uint16_t cnt) {
+ _maybe_start_transaction();
+ for (uint16_t n = 0; n < cnt; n++) {
+ (void)SPI.transfer(buf[n]);
+ }
+ }
+
+ void spiWrite16(const uint16_t *buf, uint16_t cnt) {
+ _maybe_start_transaction();
+ for (uint16_t n = 0; n < cnt; n++) {
+ (void)SPI.transfer16(buf[n]);
+ }
+ }
+
+ void spiWriteRepeat(uint8_t val, uint16_t repcnt) {
+ _maybe_start_transaction();
+ for (uint16_t n = 0; n < repcnt; n++) {
+ (void)SPI.transfer(val);
+ }
+ }
+
+ void spiWriteRepeat16(uint16_t val, uint16_t repcnt) {
+ _maybe_start_transaction();
+ for (uint16_t n = 0; n < repcnt; n++) {
+ (void)SPI.transfer16(val);
+ }
+ }
+
+#endif
+
+#endif //__AVR__
diff --git a/Marlin/src/HAL/AVR/HAL_SPI_SW.cpp b/Marlin/src/HAL/AVR/HAL_SPI_SW.cpp
new file mode 100644
index 000000000000..817dfda75571
--- /dev/null
+++ b/Marlin/src/HAL/AVR/HAL_SPI_SW.cpp
@@ -0,0 +1,278 @@
+/**
+ * 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 Arduino Sd2Card Library
+ * Copyright (c) 2009 by William Greiman
+ */
+
+/**
+ * HAL for AVR - SPI functions
+ */
+
+#ifdef __AVR__
+
+#include "../../inc/MarlinConfig.h"
+
+#include "registers.h"
+
+#if EITHER(SOFTWARE_SPI, FORCE_SOFT_SPI)
+
+ // ------------------------
+ // Software SPI
+ // ------------------------
+
+ // nop to tune soft SPI timing
+ #define nop asm volatile ("\tnop\n")
+
+ static void _spi_on_error(int code) {
+ for (;;) {
+ #if ENABLED(HALSPI_DO_ERRORBEEPS) && PIN_EXISTS(BEEPER)
+ OUT_WRITE(BEEPER_PIN, HIGH); delay(400);
+ OUT_WRITE(BEEPER_PIN, LOW); delay(400);
+ OUT_WRITE(BEEPER_PIN, HIGH); delay(400);
+ OUT_WRITE(BEEPER_PIN, LOW); delay(400);
+ OUT_WRITE(BEEPER_PIN, HIGH); delay(1000);
+ OUT_WRITE(BEEPER_PIN, LOW); delay(1000);
+ for (int n = 0; n < code; n++) {
+ OUT_WRITE(BEEPER_PIN, HIGH); delay(500);
+ OUT_WRITE(BEEPER_PIN, LOW);
+ if (n < code - 1) delay(500);
+ }
+ delay(1000);
+ OUT_WRITE(BEEPER_PIN, HIGH); delay(800);
+ OUT_WRITE(BEEPER_PIN, LOW); delay(2000);
+ #endif
+ }
+ }
+
+ static pin_dev_state_t _spi_pin_devstate;
+ static int _spi_sck_pin, _spi_miso_pin, _spi_mosi_pin, _spi_cs_pin;
+ static int _spi_bit_order = SPI_BITORDER_DEFAULT;
+ static bool _spi_is_running = false;
+
+ void spiBegin() {
+ #if PIN_EXISTS(SD_SS)
+ // Do not init HIGH for boards with pin 4 used as Fans or Heaters or otherwise, not likely to have multiple SPI devices anyway.
+ #if defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega1284P__)
+ // SS must be in output mode even if it is not chip select
+ SET_OUTPUT(SD_SS_PIN);
+ #else
+ // set SS high - may be chip select for another SPI device
+ OUT_WRITE(SD_SS_PIN, HIGH);
+ #endif
+ #endif
+ }
+
+ void spiInit(uint8_t spiRate, const int hint_sck/*=-1*/, const int hint_miso/*=-1*/, const int hint_mosi/*=-1*/, const int hint_cs/*=-1*/) {
+ if (_spi_is_running)
+ _spi_on_error(1);
+
+ // In software SPI we want to power all pins in GPIO mode.
+ // That is why we have to disable all peripherals that conflict with our SPI operations.
+ int use_pin_sck = (hint_sck >= 0) ? hint_sck : SD_SCK_PIN;
+ int use_pin_miso = (hint_miso >= 0) ? hint_miso : SD_MISO_PIN;
+ int use_pin_mosi = (hint_mosi >= 0) ? hint_mosi : SD_MOSI_PIN;
+ int use_pin_cs = (hint_cs >= 0) ? hint_cs : SD_SS_PIN; // the chip-select should be initialized using spiSetupChipSelect! (much prior to usage)
+
+ _spi_pin_devstate = _ATmega_savePinAlternates({use_pin_sck, use_pin_miso, use_pin_mosi});
+
+ _spi_sck_pin = use_pin_sck;
+ _spi_miso_pin = use_pin_miso;
+ _spi_mosi_pin = use_pin_mosi;
+ _spi_cs_pin = use_pin_cs;
+
+ _ATmega_pinMode(_spi_sck_pin, OUTPUT);
+ _ATmega_pinMode(_spi_miso_pin, INPUT);
+ _ATmega_pinMode(_spi_mosi_pin, OUTPUT);
+
+ if (use_pin_cs >= 0)
+ _ATmega_digitalWrite(use_pin_cs, LOW);
+
+ _spi_is_running = true;
+ }
+
+ void spiInitEx(uint32_t maxClockFreq, int hint_sck, int hint_miso, int hint_mosi, int hint_cs) {
+ spiInit(0, hint_sck, hint_miso, hint_mosi, hint_cs);
+ }
+
+ void spiClose() {
+ if (_spi_is_running == false)
+ _spi_on_error(2);
+
+ if (_spi_cs_pin >= 0)
+ _ATmega_digitalWrite(_spi_cs_pin, HIGH);
+
+ // Restore pin device states.
+ _ATmega_restorePinAlternates({_spi_mosi_pin, _spi_miso_pin, _spi_sck_pin}, _spi_pin_devstate);
+
+ _spi_is_running = false;
+ }
+
+ void spiSetBitOrder(int bitOrder) {
+ _spi_bit_order = bitOrder;
+ }
+
+ void spiSetClockMode(int clockMode) {
+ // TODO.
+ _spi_on_error(3);
+ }
+
+ void spiEstablish() { /* do nothing */ }
+
+ // Soft SPI receive byte
+ uint8_t spiRec(uint8_t txval) {
+ if (txval != 0xFF) _spi_on_error(4);
+
+ uint8_t data = 0;
+ // no interrupts during byte receive - about 8µs
+ cli();
+ // output pin high - like sending 0xFF
+ _ATmega_digitalWrite(_spi_mosi_pin, HIGH);
+
+ bool msb = ( _spi_bit_order == SPI_BITORDER_MSB );
+
+ LOOP_L_N(i, 8) {
+ _ATmega_digitalWrite(_spi_sck_pin, HIGH);
+
+ nop; // adjust so SCK is nice
+ nop;
+
+ if (_ATmega_digitalRead(_spi_miso_pin) == HIGH) {
+ int bitidx = ( msb ? 7-i : i );
+ data |= ( 1 << bitidx );
+ }
+
+ _ATmega_digitalWrite(_spi_sck_pin, LOW);
+ }
+
+ sei();
+ return data;
+ }
+
+ uint16_t spiRec16(uint16_t txval) {
+ if (txval != 0xFFFF) _spi_on_error(4);
+
+ uint16_t data = 0;
+ bool msb = ( _spi_bit_order == SPI_BITORDER_MSB );
+ // no interrupts during byte receive - about 8µs
+ cli();
+ // output pin high - like sending 0xFF
+ _ATmega_digitalWrite(_spi_mosi_pin, HIGH);
+
+ LOOP_L_N(i, 16) {
+ _ATmega_digitalWrite(_spi_sck_pin, HIGH);
+
+ nop; // adjust so SCK is nice
+ nop;
+
+ if (_ATmega_digitalRead(_spi_miso_pin) == HIGH) {
+ int bitidx = ( msb ? 15-i : i );
+ data |= ( 1 << bitidx );
+ }
+
+ _ATmega_digitalWrite(_spi_sck_pin, LOW);
+ }
+
+ sei();
+ return data;
+ }
+
+ // Soft SPI read data
+ void spiRead(uint8_t *buf, uint16_t nbyte, uint8_t txval) {
+ for (uint16_t i = 0; i < nbyte; i++)
+ buf[i] = spiRec(txval);
+ }
+
+ // Soft SPI send byte
+ void spiSend(uint8_t data) {
+ bool msb = ( _spi_bit_order == SPI_BITORDER_MSB );
+ // no interrupts during byte send - about 8µs
+ cli();
+ LOOP_L_N(i, 8) {
+ int bitidx = ( msb ? 7-i : i );
+ _ATmega_digitalWrite(_spi_sck_pin, LOW);
+ _ATmega_digitalWrite(_spi_mosi_pin, ( data & ( 1 << bitidx )) != 0);
+ _ATmega_digitalWrite(_spi_sck_pin, HIGH);
+ }
+
+ nop; // hold SCK high for a few ns
+ nop;
+ nop;
+ nop;
+
+ _ATmega_digitalWrite(_spi_sck_pin, LOW);
+
+ sei();
+ }
+
+ void spiSend16(uint16_t v) {
+ const bool msb = ( _spi_bit_order == SPI_BITORDER_MSB );
+ // no interrupts during byte send - about 8µs
+ cli();
+ LOOP_L_N(i, 16) {
+ const int bitidx = msb ? 15 - i : i;
+ _ATmega_digitalWrite(_spi_sck_pin, LOW);
+ _ATmega_digitalWrite(_spi_mosi_pin, ( v & ( 1 << bitidx )) != 0);
+ _ATmega_digitalWrite(_spi_sck_pin, HIGH);
+ }
+
+ nop; // hold SCK high for a few ns
+ nop;
+ nop;
+ nop;
+
+ _ATmega_digitalWrite(_spi_sck_pin, LOW);
+
+ sei();
+ }
+
+ // Soft SPI send block
+ void spiSendBlock(uint8_t token, const uint8_t *buf) {
+ spiSend(token);
+ for (uint16_t i = 0; i < 512; i++)
+ spiSend(buf[i]);
+ }
+
+ void spiWrite(const uint8_t *buf, uint16_t cnt) {
+ for (uint16_t n = 0; n < cnt; n++)
+ spiSend(buf[n]);
+ }
+
+ void spiWrite16(const uint16_t *buf, uint16_t cnt) {
+ for (uint16_t n = 0; n < cnt; n++)
+ spiSend16(buf[n]);
+ }
+
+ void spiWriteRepeat(uint8_t val, uint16_t repcnt) {
+ for (uint16_t n = 0; n < repcnt; n++)
+ spiSend(val);
+ }
+
+ void spiWriteRepeat16(uint16_t val, uint16_t repcnt) {
+ for (uint16_t n = 0; n < repcnt; n++)
+ spiSend16(val);
+ }
+
+#endif // SOFTWARE_SPI || FORCE_SOFT_SPI
+
+#endif // __AVR__
diff --git a/Marlin/src/HAL/LPC1768/MarlinSPI.h b/Marlin/src/HAL/AVR/HAL_SPI_shared.cpp
similarity index 57%
rename from Marlin/src/HAL/LPC1768/MarlinSPI.h
rename to Marlin/src/HAL/AVR/HAL_SPI_shared.cpp
index fab245f904e3..d3bf47810b77 100644
--- a/Marlin/src/HAL/LPC1768/MarlinSPI.h
+++ b/Marlin/src/HAL/AVR/HAL_SPI_shared.cpp
@@ -19,27 +19,25 @@
* along with this program. If not, see .
*
*/
-#pragma once
-#include
+#ifdef __AVR__
-/**
- * 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.
- *
- */
+#include "../../inc/MarlinConfig.h"
+
+#include "registers.h"
+
+inline bool _ATmega_isPinSPI(int pin) {
+ return _ATmega_getPinFunctions(pin).hasFunc(eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::SPI_CS);
+}
+
+void spiSetupChipSelect(int pin) {
+ // If the pin is not hardware SPI, then we disable peripherals that may conflict with it due to badly written bootloaders
+ // or ArduinoCore.
+ if (_ATmega_isPinSPI(pin) == false) {
+ _ATmega_savePinAlternate(pin);
+ }
+ _ATmega_pinMode(pin, OUTPUT);
+ _ATmega_digitalWrite(pin, HIGH);
+}
-using MarlinSPI = SPIClass;
+#endif //__AVR__
diff --git a/Marlin/src/HAL/AVR/fastio/fastio_1280.h b/Marlin/src/HAL/AVR/fastio/fastio_1280.h
index f482f823e8b9..d5b6ce24fdfb 100644
--- a/Marlin/src/HAL/AVR/fastio/fastio_1280.h
+++ b/Marlin/src/HAL/AVR/fastio/fastio_1280.h
@@ -27,44 +27,13 @@
* Hardware Pin : 02 03 06 07 01 05 15 16 17 18 23 24 25 26 64 63 13 12 46 45 44 43 78 77 76 75 74 73 72 71 60 59 58 57 56 55 54 53 50 70 52 51 42 41 40 39 38 37 36 35 22 21 20 19 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 | 04 08 09 10 11 14 27 28 29 30 31 32 33 34 47 48 49 61 62 65 66 67 68 69 79 80 81 98 99 100
* Port : E0 E1 E4 E5 G5 E3 H3 H4 H5 H6 B4 B5 B6 B7 J1 J0 H1 H0 D3 D2 D1 D0 A0 A1 A2 A3 A4 A5 A6 A7 C7 C6 C5 C4 C3 C2 C1 C0 D7 G2 G1 G0 L7 L6 L5 L4 L3 L2 L1 L0 B3 B2 B1 B0 F0 F1 F2 F3 F4 F5 F6 F7 K0 K1 K2 K3 K4 K5 K6 K7 | E2 E6 E7 xx xx H2 H7 G3 G4 xx xx xx xx xx D4 D5 D6 xx xx J2 J3 J4 J5 J6 J7 xx xx xx xx xx
* Logical Pin : 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | 78 79 80 xx xx 84 85 71 70 xx xx xx xx xx 81 82 83 xx xx 72 73 75 76 77 74 xx xx xx xx xx
+ *
+ * Arduino Pin Layout video: https://youtu.be/rIqeVCX09FA
+ * AVR alternate pin function overview video: https://youtu.be/1yd8wuI5Plg
*/
#include "../fastio.h"
-// change for your board
-#define DEBUG_LED DIO21
-
-// UART
-#define RXD DIO0
-#define TXD DIO1
-
-// SPI
-#define SCK DIO52
-#define MISO DIO50
-#define MOSI DIO51
-#define SS DIO53
-
-// TWI (I2C)
-#define SCL DIO21
-#define SDA DIO20
-
-// Timers and PWM
-#define OC0A DIO13
-#define OC0B DIO4
-#define OC1A DIO11
-#define OC1B DIO12
-#define OC2A DIO10
-#define OC2B DIO9
-#define OC3A DIO5
-#define OC3B DIO2
-#define OC3C DIO3
-#define OC4A DIO6
-#define OC4B DIO7
-#define OC4C DIO8
-#define OC5A DIO46
-#define OC5B DIO45
-#define OC5C DIO44
-
// Digital I/O
#define DIO0_PIN PINE0
@@ -72,1043 +41,650 @@
#define DIO0_WPORT PORTE
#define DIO0_DDR DDRE
#define DIO0_PWM nullptr
+#define PinE0 0
#define DIO1_PIN PINE1
#define DIO1_RPORT PINE
#define DIO1_WPORT PORTE
#define DIO1_DDR DDRE
#define DIO1_PWM nullptr
+#define PinE1 1
#define DIO2_PIN PINE4
#define DIO2_RPORT PINE
#define DIO2_WPORT PORTE
#define DIO2_DDR DDRE
#define DIO2_PWM &OCR3BL
+#define PinE4 2
#define DIO3_PIN PINE5
#define DIO3_RPORT PINE
#define DIO3_WPORT PORTE
#define DIO3_DDR DDRE
#define DIO3_PWM &OCR3CL
+#define PinE5 3
#define DIO4_PIN PING5
#define DIO4_RPORT PING
#define DIO4_WPORT PORTG
#define DIO4_DDR DDRG
#define DIO4_PWM &OCR0B
+#define PinG5 4
#define DIO5_PIN PINE3
#define DIO5_RPORT PINE
#define DIO5_WPORT PORTE
#define DIO5_DDR DDRE
#define DIO5_PWM &OCR3AL
+#define PinE3 5
#define DIO6_PIN PINH3
#define DIO6_RPORT PINH
#define DIO6_WPORT PORTH
#define DIO6_DDR DDRH
#define DIO6_PWM &OCR4AL
+#define PinH3 6
#define DIO7_PIN PINH4
#define DIO7_RPORT PINH
#define DIO7_WPORT PORTH
#define DIO7_DDR DDRH
#define DIO7_PWM &OCR4BL
+#define PinH4 7
#define DIO8_PIN PINH5
#define DIO8_RPORT PINH
#define DIO8_WPORT PORTH
#define DIO8_DDR DDRH
#define DIO8_PWM &OCR4CL
+#define PinH5 8
#define DIO9_PIN PINH6
#define DIO9_RPORT PINH
#define DIO9_WPORT PORTH
#define DIO9_DDR DDRH
#define DIO9_PWM &OCR2B
+#define PinH6 9
#define DIO10_PIN PINB4
#define DIO10_RPORT PINB
#define DIO10_WPORT PORTB
#define DIO10_DDR DDRB
#define DIO10_PWM &OCR2A
+#define PinB4 10
#define DIO11_PIN PINB5
#define DIO11_RPORT PINB
#define DIO11_WPORT PORTB
#define DIO11_DDR DDRB
#define DIO11_PWM nullptr
+#define PinB5 11
#define DIO12_PIN PINB6
#define DIO12_RPORT PINB
#define DIO12_WPORT PORTB
#define DIO12_DDR DDRB
#define DIO12_PWM nullptr
+#define PinB6 12
#define DIO13_PIN PINB7
#define DIO13_RPORT PINB
#define DIO13_WPORT PORTB
#define DIO13_DDR DDRB
#define DIO13_PWM &OCR0A
+#define PinB7 13
#define DIO14_PIN PINJ1
#define DIO14_RPORT PINJ
#define DIO14_WPORT PORTJ
#define DIO14_DDR DDRJ
#define DIO14_PWM nullptr
+#define PinJ1 14
#define DIO15_PIN PINJ0
#define DIO15_RPORT PINJ
#define DIO15_WPORT PORTJ
#define DIO15_DDR DDRJ
#define DIO15_PWM nullptr
+#define PinJ0 15
#define DIO16_PIN PINH1
#define DIO16_RPORT PINH
#define DIO16_WPORT PORTH
#define DIO16_DDR DDRH
#define DIO16_PWM nullptr
+#define PinH1 16
#define DIO17_PIN PINH0
#define DIO17_RPORT PINH
#define DIO17_WPORT PORTH
#define DIO17_DDR DDRH
#define DIO17_PWM nullptr
+#define PinH0 17
#define DIO18_PIN PIND3
#define DIO18_RPORT PIND
#define DIO18_WPORT PORTD
#define DIO18_DDR DDRD
#define DIO18_PWM nullptr
+#define PinD3 18
#define DIO19_PIN PIND2
#define DIO19_RPORT PIND
#define DIO19_WPORT PORTD
#define DIO19_DDR DDRD
#define DIO19_PWM nullptr
+#define PinD2 19
#define DIO20_PIN PIND1
#define DIO20_RPORT PIND
#define DIO20_WPORT PORTD
#define DIO20_DDR DDRD
#define DIO20_PWM nullptr
+#define PinD1 20
#define DIO21_PIN PIND0
#define DIO21_RPORT PIND
#define DIO21_WPORT PORTD
#define DIO21_DDR DDRD
#define DIO21_PWM nullptr
+#define PinD0 21
#define DIO22_PIN PINA0
#define DIO22_RPORT PINA
#define DIO22_WPORT PORTA
#define DIO22_DDR DDRA
#define DIO22_PWM nullptr
+#define PinA0 22
#define DIO23_PIN PINA1
#define DIO23_RPORT PINA
#define DIO23_WPORT PORTA
#define DIO23_DDR DDRA
#define DIO23_PWM nullptr
+#define PinA1 23
#define DIO24_PIN PINA2
#define DIO24_RPORT PINA
#define DIO24_WPORT PORTA
#define DIO24_DDR DDRA
#define DIO24_PWM nullptr
+#define PinA2 24
#define DIO25_PIN PINA3
#define DIO25_RPORT PINA
#define DIO25_WPORT PORTA
#define DIO25_DDR DDRA
#define DIO25_PWM nullptr
+#define PinA3 25
#define DIO26_PIN PINA4
#define DIO26_RPORT PINA
#define DIO26_WPORT PORTA
#define DIO26_DDR DDRA
#define DIO26_PWM nullptr
+#define PinA4 26
#define DIO27_PIN PINA5
#define DIO27_RPORT PINA
#define DIO27_WPORT PORTA
#define DIO27_DDR DDRA
#define DIO27_PWM nullptr
+#define PinA5 27
#define DIO28_PIN PINA6
#define DIO28_RPORT PINA
#define DIO28_WPORT PORTA
#define DIO28_DDR DDRA
#define DIO28_PWM nullptr
+#define PinA6 28
#define DIO29_PIN PINA7
#define DIO29_RPORT PINA
#define DIO29_WPORT PORTA
#define DIO29_DDR DDRA
#define DIO29_PWM nullptr
+#define PinA7 29
#define DIO30_PIN PINC7
#define DIO30_RPORT PINC
#define DIO30_WPORT PORTC
#define DIO30_DDR DDRC
#define DIO30_PWM nullptr
+#define PinC7 30
#define DIO31_PIN PINC6
#define DIO31_RPORT PINC
#define DIO31_WPORT PORTC
#define DIO31_DDR DDRC
#define DIO31_PWM nullptr
+#define PinC6 31
#define DIO32_PIN PINC5
#define DIO32_RPORT PINC
#define DIO32_WPORT PORTC
#define DIO32_DDR DDRC
#define DIO32_PWM nullptr
+#define PinC5 32
#define DIO33_PIN PINC4
#define DIO33_RPORT PINC
#define DIO33_WPORT PORTC
#define DIO33_DDR DDRC
#define DIO33_PWM nullptr
+#define PinC4 33
#define DIO34_PIN PINC3
#define DIO34_RPORT PINC
#define DIO34_WPORT PORTC
#define DIO34_DDR DDRC
#define DIO34_PWM nullptr
+#define PinC3 34
#define DIO35_PIN PINC2
#define DIO35_RPORT PINC
#define DIO35_WPORT PORTC
#define DIO35_DDR DDRC
#define DIO35_PWM nullptr
+#define PinC2 35
#define DIO36_PIN PINC1
#define DIO36_RPORT PINC
#define DIO36_WPORT PORTC
#define DIO36_DDR DDRC
#define DIO36_PWM nullptr
+#define PinC1 36
#define DIO37_PIN PINC0
#define DIO37_RPORT PINC
#define DIO37_WPORT PORTC
#define DIO37_DDR DDRC
#define DIO37_PWM nullptr
+#define PinC0 37
#define DIO38_PIN PIND7
#define DIO38_RPORT PIND
#define DIO38_WPORT PORTD
#define DIO38_DDR DDRD
#define DIO38_PWM nullptr
+#define PinD7 38
#define DIO39_PIN PING2
#define DIO39_RPORT PING
#define DIO39_WPORT PORTG
#define DIO39_DDR DDRG
#define DIO39_PWM nullptr
+#define PinG2 39
#define DIO40_PIN PING1
#define DIO40_RPORT PING
#define DIO40_WPORT PORTG
#define DIO40_DDR DDRG
#define DIO40_PWM nullptr
+#define PinG1 40
#define DIO41_PIN PING0
#define DIO41_RPORT PING
#define DIO41_WPORT PORTG
#define DIO41_DDR DDRG
#define DIO41_PWM nullptr
+#define PinG0 41
#define DIO42_PIN PINL7
#define DIO42_RPORT PINL
#define DIO42_WPORT PORTL
#define DIO42_DDR DDRL
#define DIO42_PWM nullptr
+#define PinL7 42
#define DIO43_PIN PINL6
#define DIO43_RPORT PINL
#define DIO43_WPORT PORTL
#define DIO43_DDR DDRL
#define DIO43_PWM nullptr
+#define PinL6 43
#define DIO44_PIN PINL5
#define DIO44_RPORT PINL
#define DIO44_WPORT PORTL
#define DIO44_DDR DDRL
#define DIO44_PWM &OCR5CL
+#define PinL5 44
#define DIO45_PIN PINL4
#define DIO45_RPORT PINL
#define DIO45_WPORT PORTL
#define DIO45_DDR DDRL
#define DIO45_PWM &OCR5BL
+#define PinL4 45
#define DIO46_PIN PINL3
#define DIO46_RPORT PINL
#define DIO46_WPORT PORTL
#define DIO46_DDR DDRL
#define DIO46_PWM &OCR5AL
+#define PinL3 46
#define DIO47_PIN PINL2
#define DIO47_RPORT PINL
#define DIO47_WPORT PORTL
#define DIO47_DDR DDRL
#define DIO47_PWM nullptr
+#define PinL2 47
#define DIO48_PIN PINL1
#define DIO48_RPORT PINL
#define DIO48_WPORT PORTL
#define DIO48_DDR DDRL
#define DIO48_PWM nullptr
+#define PinL1 48
#define DIO49_PIN PINL0
#define DIO49_RPORT PINL
#define DIO49_WPORT PORTL
#define DIO49_DDR DDRL
#define DIO49_PWM nullptr
+#define PinL0 49
#define DIO50_PIN PINB3
#define DIO50_RPORT PINB
#define DIO50_WPORT PORTB
#define DIO50_DDR DDRB
#define DIO50_PWM nullptr
+#define PinB3 50
#define DIO51_PIN PINB2
#define DIO51_RPORT PINB
#define DIO51_WPORT PORTB
#define DIO51_DDR DDRB
#define DIO51_PWM nullptr
+#define PinB2 51
#define DIO52_PIN PINB1
#define DIO52_RPORT PINB
#define DIO52_WPORT PORTB
#define DIO52_DDR DDRB
#define DIO52_PWM nullptr
+#define PinB1 52
#define DIO53_PIN PINB0
#define DIO53_RPORT PINB
#define DIO53_WPORT PORTB
#define DIO53_DDR DDRB
#define DIO53_PWM nullptr
+#define PinB0 53
#define DIO54_PIN PINF0
#define DIO54_RPORT PINF
#define DIO54_WPORT PORTF
#define DIO54_DDR DDRF
#define DIO54_PWM nullptr
+#define PinF0 54
#define DIO55_PIN PINF1
#define DIO55_RPORT PINF
#define DIO55_WPORT PORTF
#define DIO55_DDR DDRF
#define DIO55_PWM nullptr
+#define PinF1 55
#define DIO56_PIN PINF2
#define DIO56_RPORT PINF
#define DIO56_WPORT PORTF
#define DIO56_DDR DDRF
#define DIO56_PWM nullptr
+#define PinF2 56
#define DIO57_PIN PINF3
#define DIO57_RPORT PINF
#define DIO57_WPORT PORTF
#define DIO57_DDR DDRF
#define DIO57_PWM nullptr
+#define PinF3 57
#define DIO58_PIN PINF4
#define DIO58_RPORT PINF
#define DIO58_WPORT PORTF
#define DIO58_DDR DDRF
#define DIO58_PWM nullptr
+#define PinF4 58
#define DIO59_PIN PINF5
#define DIO59_RPORT PINF
#define DIO59_WPORT PORTF
#define DIO59_DDR DDRF
#define DIO59_PWM nullptr
+#define PinF5 59
#define DIO60_PIN PINF6
#define DIO60_RPORT PINF
#define DIO60_WPORT PORTF
#define DIO60_DDR DDRF
#define DIO60_PWM nullptr
+#define PinF6 60
#define DIO61_PIN PINF7
#define DIO61_RPORT PINF
#define DIO61_WPORT PORTF
#define DIO61_DDR DDRF
#define DIO61_PWM nullptr
+#define PinF7 61
#define DIO62_PIN PINK0
#define DIO62_RPORT PINK
#define DIO62_WPORT PORTK
#define DIO62_DDR DDRK
#define DIO62_PWM nullptr
+#define PinK0 62
#define DIO63_PIN PINK1
#define DIO63_RPORT PINK
#define DIO63_WPORT PORTK
#define DIO63_DDR DDRK
#define DIO63_PWM nullptr
+#define PinK1 63
#define DIO64_PIN PINK2
#define DIO64_RPORT PINK
#define DIO64_WPORT PORTK
#define DIO64_DDR DDRK
#define DIO64_PWM nullptr
+#define PinK2 64
#define DIO65_PIN PINK3
#define DIO65_RPORT PINK
#define DIO65_WPORT PORTK
#define DIO65_DDR DDRK
#define DIO65_PWM nullptr
+#define PinK3 65
#define DIO66_PIN PINK4
#define DIO66_RPORT PINK
#define DIO66_WPORT PORTK
#define DIO66_DDR DDRK
#define DIO66_PWM nullptr
+#define PinK4 66
#define DIO67_PIN PINK5
#define DIO67_RPORT PINK
#define DIO67_WPORT PORTK
#define DIO67_DDR DDRK
#define DIO67_PWM nullptr
+#define PinK5 67
#define DIO68_PIN PINK6
#define DIO68_RPORT PINK
#define DIO68_WPORT PORTK
#define DIO68_DDR DDRK
#define DIO68_PWM nullptr
+#define PinK6 68
#define DIO69_PIN PINK7
#define DIO69_RPORT PINK
#define DIO69_WPORT PORTK
#define DIO69_DDR DDRK
#define DIO69_PWM nullptr
-
-//#define FASTIO_EXT_START 70
-//#define FASTIO_EXT_END 85
+#define PinK7 69
#define DIO70_PIN PING4
#define DIO70_RPORT PING
#define DIO70_WPORT PORTG
#define DIO70_DDR DDRG
#define DIO70_PWM nullptr
+#define PinG4 70
#define DIO71_PIN PING3
#define DIO71_RPORT PING
#define DIO71_WPORT PORTG
#define DIO71_DDR DDRG
#define DIO71_PWM nullptr
+#define PinG3 71
#define DIO72_PIN PINJ2
#define DIO72_RPORT PINJ
#define DIO72_WPORT PORTJ
#define DIO72_DDR DDRJ
#define DIO72_PWM nullptr
+#define PinJ2 72
#define DIO73_PIN PINJ3
#define DIO73_RPORT PINJ
#define DIO73_WPORT PORTJ
#define DIO73_DDR DDRJ
#define DIO73_PWM nullptr
+#define PinJ3 73
#define DIO74_PIN PINJ7
#define DIO74_RPORT PINJ
#define DIO74_WPORT PORTJ
#define DIO74_DDR DDRJ
#define DIO74_PWM nullptr
+#define PinJ7 74
#define DIO75_PIN PINJ4
#define DIO75_RPORT PINJ
#define DIO75_WPORT PORTJ
#define DIO75_DDR DDRJ
#define DIO75_PWM nullptr
+#define PinJ4 75
#define DIO76_PIN PINJ5
#define DIO76_RPORT PINJ
#define DIO76_WPORT PORTJ
#define DIO76_DDR DDRJ
#define DIO76_PWM nullptr
+#define PinJ5 76
#define DIO77_PIN PINJ6
#define DIO77_RPORT PINJ
#define DIO77_WPORT PORTJ
#define DIO77_DDR DDRJ
#define DIO77_PWM nullptr
+#define PinJ6 77
#define DIO78_PIN PINE2
#define DIO78_RPORT PINE
#define DIO78_WPORT PORTE
#define DIO78_DDR DDRE
#define DIO78_PWM nullptr
+#define PinE2 78
#define DIO79_PIN PINE6
#define DIO79_RPORT PINE
#define DIO79_WPORT PORTE
#define DIO79_DDR DDRE
#define DIO79_PWM nullptr
+#define PinE6 79
#define DIO80_PIN PINE7
#define DIO80_RPORT PINE
#define DIO80_WPORT PORTE
#define DIO80_DDR DDRE
#define DIO80_PWM nullptr
+#define PinE7 80
#define DIO81_PIN PIND4
#define DIO81_RPORT PIND
#define DIO81_WPORT PORTD
#define DIO81_DDR DDRD
#define DIO81_PWM nullptr
+#define PinD4 81
#define DIO82_PIN PIND5
#define DIO82_RPORT PIND
#define DIO82_WPORT PORTD
#define DIO82_DDR DDRD
#define DIO82_PWM nullptr
+#define PinD5 82
#define DIO83_PIN PIND6
#define DIO83_RPORT PIND
#define DIO83_WPORT PORTD
#define DIO83_DDR DDRD
#define DIO83_PWM nullptr
+#define PinD6 83
#define DIO84_PIN PINH2
#define DIO84_RPORT PINH
#define DIO84_WPORT PORTH
#define DIO84_DDR DDRH
#define DIO84_PWM nullptr
+#define PinH2 84
#define DIO85_PIN PINH7
#define DIO85_RPORT PINH
#define DIO85_WPORT PORTH
#define DIO85_DDR DDRH
#define DIO85_PWM nullptr
+#define PinH7 85
+
+#define DIO_NUM 86
+
+// change for your board
+// NOTE: these may actually be used by external libraries such as LiquidCrystal_AIP31068
+#ifndef DEBUG_LED
+ #define DEBUG_LED PinD0
+#endif
+
+// UART
+#ifndef RXD
+ #define RXD PinE0
+#endif
+#ifndef TXD
+ #define TXD PinE1
+#endif
-#undef PA0
-#define PA0_PIN PINA0
-#define PA0_RPORT PINA
-#define PA0_WPORT PORTA
-#define PA0_DDR DDRA
-#define PA0_PWM nullptr
-#undef PA1
-#define PA1_PIN PINA1
-#define PA1_RPORT PINA
-#define PA1_WPORT PORTA
-#define PA1_DDR DDRA
-#define PA1_PWM nullptr
-#undef PA2
-#define PA2_PIN PINA2
-#define PA2_RPORT PINA
-#define PA2_WPORT PORTA
-#define PA2_DDR DDRA
-#define PA2_PWM nullptr
-#undef PA3
-#define PA3_PIN PINA3
-#define PA3_RPORT PINA
-#define PA3_WPORT PORTA
-#define PA3_DDR DDRA
-#define PA3_PWM nullptr
-#undef PA4
-#define PA4_PIN PINA4
-#define PA4_RPORT PINA
-#define PA4_WPORT PORTA
-#define PA4_DDR DDRA
-#define PA4_PWM nullptr
-#undef PA5
-#define PA5_PIN PINA5
-#define PA5_RPORT PINA
-#define PA5_WPORT PORTA
-#define PA5_DDR DDRA
-#define PA5_PWM nullptr
-#undef PA6
-#define PA6_PIN PINA6
-#define PA6_RPORT PINA
-#define PA6_WPORT PORTA
-#define PA6_DDR DDRA
-#define PA6_PWM nullptr
-#undef PA7
-#define PA7_PIN PINA7
-#define PA7_RPORT PINA
-#define PA7_WPORT PORTA
-#define PA7_DDR DDRA
-#define PA7_PWM nullptr
-
-#undef PB0
-#define PB0_PIN PINB0
-#define PB0_RPORT PINB
-#define PB0_WPORT PORTB
-#define PB0_DDR DDRB
-#define PB0_PWM nullptr
-#undef PB1
-#define PB1_PIN PINB1
-#define PB1_RPORT PINB
-#define PB1_WPORT PORTB
-#define PB1_DDR DDRB
-#define PB1_PWM nullptr
-#undef PB2
-#define PB2_PIN PINB2
-#define PB2_RPORT PINB
-#define PB2_WPORT PORTB
-#define PB2_DDR DDRB
-#define PB2_PWM nullptr
-#undef PB3
-#define PB3_PIN PINB3
-#define PB3_RPORT PINB
-#define PB3_WPORT PORTB
-#define PB3_DDR DDRB
-#define PB3_PWM nullptr
-#undef PB4
-#define PB4_PIN PINB4
-#define PB4_RPORT PINB
-#define PB4_WPORT PORTB
-#define PB4_DDR DDRB
-#define PB4_PWM &OCR2A
-#undef PB5
-#define PB5_PIN PINB5
-#define PB5_RPORT PINB
-#define PB5_WPORT PORTB
-#define PB5_DDR DDRB
-#define PB5_PWM nullptr
-#undef PB6
-#define PB6_PIN PINB6
-#define PB6_RPORT PINB
-#define PB6_WPORT PORTB
-#define PB6_DDR DDRB
-#define PB6_PWM nullptr
-#undef PB7
-#define PB7_PIN PINB7
-#define PB7_RPORT PINB
-#define PB7_WPORT PORTB
-#define PB7_DDR DDRB
-#define PB7_PWM &OCR0A
-
-#undef PC0
-#define PC0_PIN PINC0
-#define PC0_RPORT PINC
-#define PC0_WPORT PORTC
-#define PC0_DDR DDRC
-#define PC0_PWM nullptr
-#undef PC1
-#define PC1_PIN PINC1
-#define PC1_RPORT PINC
-#define PC1_WPORT PORTC
-#define PC1_DDR DDRC
-#define PC1_PWM nullptr
-#undef PC2
-#define PC2_PIN PINC2
-#define PC2_RPORT PINC
-#define PC2_WPORT PORTC
-#define PC2_DDR DDRC
-#define PC2_PWM nullptr
-#undef PC3
-#define PC3_PIN PINC3
-#define PC3_RPORT PINC
-#define PC3_WPORT PORTC
-#define PC3_DDR DDRC
-#define PC3_PWM nullptr
-#undef PC4
-#define PC4_PIN PINC4
-#define PC4_RPORT PINC
-#define PC4_WPORT PORTC
-#define PC4_DDR DDRC
-#define PC4_PWM nullptr
-#undef PC5
-#define PC5_PIN PINC5
-#define PC5_RPORT PINC
-#define PC5_WPORT PORTC
-#define PC5_DDR DDRC
-#define PC5_PWM nullptr
-#undef PC6
-#define PC6_PIN PINC6
-#define PC6_RPORT PINC
-#define PC6_WPORT PORTC
-#define PC6_DDR DDRC
-#define PC6_PWM nullptr
-#undef PC7
-#define PC7_PIN PINC7
-#define PC7_RPORT PINC
-#define PC7_WPORT PORTC
-#define PC7_DDR DDRC
-#define PC7_PWM nullptr
-
-#undef PD0
-#define PD0_PIN PIND0
-#define PD0_RPORT PIND
-#define PD0_WPORT PORTD
-#define PD0_DDR DDRD
-#define PD0_PWM nullptr
-#undef PD1
-#define PD1_PIN PIND1
-#define PD1_RPORT PIND
-#define PD1_WPORT PORTD
-#define PD1_DDR DDRD
-#define PD1_PWM nullptr
-#undef PD2
-#define PD2_PIN PIND2
-#define PD2_RPORT PIND
-#define PD2_WPORT PORTD
-#define PD2_DDR DDRD
-#define PD2_PWM nullptr
-#undef PD3
-#define PD3_PIN PIND3
-#define PD3_RPORT PIND
-#define PD3_WPORT PORTD
-#define PD3_DDR DDRD
-#define PD3_PWM nullptr
-#undef PD4
-#define PD4_PIN PIND4
-#define PD4_RPORT PIND
-#define PD4_WPORT PORTD
-#define PD4_DDR DDRD
-#define PD4_PWM nullptr
-#undef PD5
-#define PD5_PIN PIND5
-#define PD5_RPORT PIND
-#define PD5_WPORT PORTD
-#define PD5_DDR DDRD
-#define PD5_PWM nullptr
-#undef PD6
-#define PD6_PIN PIND6
-#define PD6_RPORT PIND
-#define PD6_WPORT PORTD
-#define PD6_DDR DDRD
-#define PD6_PWM nullptr
-#undef PD7
-#define PD7_PIN PIND7
-#define PD7_RPORT PIND
-#define PD7_WPORT PORTD
-#define PD7_DDR DDRD
-#define PD7_PWM nullptr
-
-#undef PE0
-#define PE0_PIN PINE0
-#define PE0_RPORT PINE
-#define PE0_WPORT PORTE
-#define PE0_DDR DDRE
-#define PE0_PWM nullptr
-#undef PE1
-#define PE1_PIN PINE1
-#define PE1_RPORT PINE
-#define PE1_WPORT PORTE
-#define PE1_DDR DDRE
-#define PE1_PWM nullptr
-#undef PE2
-#define PE2_PIN PINE2
-#define PE2_RPORT PINE
-#define PE2_WPORT PORTE
-#define PE2_DDR DDRE
-#define PE2_PWM nullptr
-#undef PE3
-#define PE3_PIN PINE3
-#define PE3_RPORT PINE
-#define PE3_WPORT PORTE
-#define PE3_DDR DDRE
-#define PE3_PWM &OCR3AL
-#undef PE4
-#define PE4_PIN PINE4
-#define PE4_RPORT PINE
-#define PE4_WPORT PORTE
-#define PE4_DDR DDRE
-#define PE4_PWM &OCR3BL
-#undef PE5
-#define PE5_PIN PINE5
-#define PE5_RPORT PINE
-#define PE5_WPORT PORTE
-#define PE5_DDR DDRE
-#define PE5_PWM &OCR3CL
-#undef PE6
-#define PE6_PIN PINE6
-#define PE6_RPORT PINE
-#define PE6_WPORT PORTE
-#define PE6_DDR DDRE
-#define PE6_PWM nullptr
-#undef PE7
-#define PE7_PIN PINE7
-#define PE7_RPORT PINE
-#define PE7_WPORT PORTE
-#define PE7_DDR DDRE
-#define PE7_PWM nullptr
-
-#undef PF0
-#define PF0_PIN PINF0
-#define PF0_RPORT PINF
-#define PF0_WPORT PORTF
-#define PF0_DDR DDRF
-#define PF0_PWM nullptr
-#undef PF1
-#define PF1_PIN PINF1
-#define PF1_RPORT PINF
-#define PF1_WPORT PORTF
-#define PF1_DDR DDRF
-#define PF1_PWM nullptr
-#undef PF2
-#define PF2_PIN PINF2
-#define PF2_RPORT PINF
-#define PF2_WPORT PORTF
-#define PF2_DDR DDRF
-#define PF2_PWM nullptr
-#undef PF3
-#define PF3_PIN PINF3
-#define PF3_RPORT PINF
-#define PF3_WPORT PORTF
-#define PF3_DDR DDRF
-#define PF3_PWM nullptr
-#undef PF4
-#define PF4_PIN PINF4
-#define PF4_RPORT PINF
-#define PF4_WPORT PORTF
-#define PF4_DDR DDRF
-#define PF4_PWM nullptr
-#undef PF5
-#define PF5_PIN PINF5
-#define PF5_RPORT PINF
-#define PF5_WPORT PORTF
-#define PF5_DDR DDRF
-#define PF5_PWM nullptr
-#undef PF6
-#define PF6_PIN PINF6
-#define PF6_RPORT PINF
-#define PF6_WPORT PORTF
-#define PF6_DDR DDRF
-#define PF6_PWM nullptr
-#undef PF7
-#define PF7_PIN PINF7
-#define PF7_RPORT PINF
-#define PF7_WPORT PORTF
-#define PF7_DDR DDRF
-#define PF7_PWM nullptr
-
-#undef PG0
-#define PG0_PIN PING0
-#define PG0_RPORT PING
-#define PG0_WPORT PORTG
-#define PG0_DDR DDRG
-#define PG0_PWM nullptr
-#undef PG1
-#define PG1_PIN PING1
-#define PG1_RPORT PING
-#define PG1_WPORT PORTG
-#define PG1_DDR DDRG
-#define PG1_PWM nullptr
-#undef PG2
-#define PG2_PIN PING2
-#define PG2_RPORT PING
-#define PG2_WPORT PORTG
-#define PG2_DDR DDRG
-#define PG2_PWM nullptr
-#undef PG3
-#define PG3_PIN PING3
-#define PG3_RPORT PING
-#define PG3_WPORT PORTG
-#define PG3_DDR DDRG
-#define PG3_PWM nullptr
-#undef PG4
-#define PG4_PIN PING4
-#define PG4_RPORT PING
-#define PG4_WPORT PORTG
-#define PG4_DDR DDRG
-#define PG4_PWM nullptr
-#undef PG5
-#define PG5_PIN PING5
-#define PG5_RPORT PING
-#define PG5_WPORT PORTG
-#define PG5_DDR DDRG
-#define PG5_PWM &OCR0B
-
-#undef PH0
-#define PH0_PIN PINH0
-#define PH0_RPORT PINH
-#define PH0_WPORT PORTH
-#define PH0_DDR DDRH
-#define PH0_PWM nullptr
-#undef PH1
-#define PH1_PIN PINH1
-#define PH1_RPORT PINH
-#define PH1_WPORT PORTH
-#define PH1_DDR DDRH
-#define PH1_PWM nullptr
-#undef PH2
-#define PH2_PIN PINH2
-#define PH2_RPORT PINH
-#define PH2_WPORT PORTH
-#define PH2_DDR DDRH
-#define PH2_PWM nullptr
-#undef PH3
-#define PH3_PIN PINH3
-#define PH3_RPORT PINH
-#define PH3_WPORT PORTH
-#define PH3_DDR DDRH
-#define PH3_PWM &OCR4AL
-#undef PH4
-#define PH4_PIN PINH4
-#define PH4_RPORT PINH
-#define PH4_WPORT PORTH
-#define PH4_DDR DDRH
-#define PH4_PWM &OCR4BL
-#undef PH5
-#define PH5_PIN PINH5
-#define PH5_RPORT PINH
-#define PH5_WPORT PORTH
-#define PH5_DDR DDRH
-#define PH5_PWM &OCR4CL
-#undef PH6
-#define PH6_PIN PINH6
-#define PH6_RPORT PINH
-#define PH6_WPORT PORTH
-#define PH6_DDR DDRH
-#define PH6_PWM &OCR2B
-#undef PH7
-#define PH7_PIN PINH7
-#define PH7_RPORT PINH
-#define PH7_WPORT PORTH
-#define PH7_DDR DDRH
-#define PH7_PWM nullptr
-
-#undef PJ0
-#define PJ0_PIN PINJ0
-#define PJ0_RPORT PINJ
-#define PJ0_WPORT PORTJ
-#define PJ0_DDR DDRJ
-#define PJ0_PWM nullptr
-#undef PJ1
-#define PJ1_PIN PINJ1
-#define PJ1_RPORT PINJ
-#define PJ1_WPORT PORTJ
-#define PJ1_DDR DDRJ
-#define PJ1_PWM nullptr
-#undef PJ2
-#define PJ2_PIN PINJ2
-#define PJ2_RPORT PINJ
-#define PJ2_WPORT PORTJ
-#define PJ2_DDR DDRJ
-#define PJ2_PWM nullptr
-#undef PJ3
-#define PJ3_PIN PINJ3
-#define PJ3_RPORT PINJ
-#define PJ3_WPORT PORTJ
-#define PJ3_DDR DDRJ
-#define PJ3_PWM nullptr
-#undef PJ4
-#define PJ4_PIN PINJ4
-#define PJ4_RPORT PINJ
-#define PJ4_WPORT PORTJ
-#define PJ4_DDR DDRJ
-#define PJ4_PWM nullptr
-#undef PJ5
-#define PJ5_PIN PINJ5
-#define PJ5_RPORT PINJ
-#define PJ5_WPORT PORTJ
-#define PJ5_DDR DDRJ
-#define PJ5_PWM nullptr
-#undef PJ6
-#define PJ6_PIN PINJ6
-#define PJ6_RPORT PINJ
-#define PJ6_WPORT PORTJ
-#define PJ6_DDR DDRJ
-#define PJ6_PWM nullptr
-#undef PJ7
-#define PJ7_PIN PINJ7
-#define PJ7_RPORT PINJ
-#define PJ7_WPORT PORTJ
-#define PJ7_DDR DDRJ
-#define PJ7_PWM nullptr
-
-#undef PK0
-#define PK0_PIN PINK0
-#define PK0_RPORT PINK
-#define PK0_WPORT PORTK
-#define PK0_DDR DDRK
-#define PK0_PWM nullptr
-#undef PK1
-#define PK1_PIN PINK1
-#define PK1_RPORT PINK
-#define PK1_WPORT PORTK
-#define PK1_DDR DDRK
-#define PK1_PWM nullptr
-#undef PK2
-#define PK2_PIN PINK2
-#define PK2_RPORT PINK
-#define PK2_WPORT PORTK
-#define PK2_DDR DDRK
-#define PK2_PWM nullptr
-#undef PK3
-#define PK3_PIN PINK3
-#define PK3_RPORT PINK
-#define PK3_WPORT PORTK
-#define PK3_DDR DDRK
-#define PK3_PWM nullptr
-#undef PK4
-#define PK4_PIN PINK4
-#define PK4_RPORT PINK
-#define PK4_WPORT PORTK
-#define PK4_DDR DDRK
-#define PK4_PWM nullptr
-#undef PK5
-#define PK5_PIN PINK5
-#define PK5_RPORT PINK
-#define PK5_WPORT PORTK
-#define PK5_DDR DDRK
-#define PK5_PWM nullptr
-#undef PK6
-#define PK6_PIN PINK6
-#define PK6_RPORT PINK
-#define PK6_WPORT PORTK
-#define PK6_DDR DDRK
-#define PK6_PWM nullptr
-#undef PK7
-#define PK7_PIN PINK7
-#define PK7_RPORT PINK
-#define PK7_WPORT PORTK
-#define PK7_DDR DDRK
-#define PK7_PWM nullptr
-
-#undef PL0
-#define PL0_PIN PINL0
-#define PL0_RPORT PINL
-#define PL0_WPORT PORTL
-#define PL0_DDR DDRL
-#define PL0_PWM nullptr
-#undef PL1
-#define PL1_PIN PINL1
-#define PL1_RPORT PINL
-#define PL1_WPORT PORTL
-#define PL1_DDR DDRL
-#define PL1_PWM nullptr
-#undef PL2
-#define PL2_PIN PINL2
-#define PL2_RPORT PINL
-#define PL2_WPORT PORTL
-#define PL2_DDR DDRL
-#define PL2_PWM nullptr
-#undef PL3
-#define PL3_PIN PINL3
-#define PL3_RPORT PINL
-#define PL3_WPORT PORTL
-#define PL3_DDR DDRL
-#define PL3_PWM &OCR5AL
-#undef PL4
-#define PL4_PIN PINL4
-#define PL4_RPORT PINL
-#define PL4_WPORT PORTL
-#define PL4_DDR DDRL
-#define PL4_PWM &OCR5BL
-#undef PL5
-#define PL5_PIN PINL5
-#define PL5_RPORT PINL
-#define PL5_WPORT PORTL
-#define PL5_DDR DDRL
-#define PL5_PWM &OCR5CL
-#undef PL6
-#define PL6_PIN PINL6
-#define PL6_RPORT PINL
-#define PL6_WPORT PORTL
-#define PL6_DDR DDRL
-#define PL6_PWM nullptr
-#undef PL7
-#define PL7_PIN PINL7
-#define PL7_RPORT PINL
-#define PL7_WPORT PORTL
-#define PL7_DDR DDRL
-#define PL7_PWM nullptr
+// SPI
+#ifndef SCK
+ #define SCK PinB1
+#endif
+#ifndef MISO
+ #define MISO PinB3
+#endif
+#ifndef MOSI
+ #define MOSI PinB2
+#endif
+#ifndef SS
+ #define SS PinB0
+#endif
+
+// TWI (I2C)
+#define SCL PinD0
+#define SDA PinD1
+
+// Timers and PWM
+#define OC0A PinB7
+#define OC0B PinG5
+#define OC1A PinB5
+#define OC1B PinB6
+#define OC2A PinB4
+#define OC2B PinH6
+#define OC3A PinE3
+#define OC3B PinE4
+#define OC3C PinE5
+#define OC4A PinH3
+#define OC4B PinH4
+#define OC4C PinH5
+#define OC5A PinL3
+#define OC5B PinL4
+#define OC5C PinL5
diff --git a/Marlin/src/HAL/AVR/fastio/fastio_1281.h b/Marlin/src/HAL/AVR/fastio/fastio_1281.h
index e0bc5e2995d1..47c8b9f0b3a5 100644
--- a/Marlin/src/HAL/AVR/fastio/fastio_1281.h
+++ b/Marlin/src/HAL/AVR/fastio/fastio_1281.h
@@ -26,37 +26,13 @@
*
* Logical Pin: 38 39 40 41 42 43 44 45 16 10 11 12 06 07 08 09 30 31 32 33 34 35 36 37 17 18 19 20 21 22 23 24 00 01 13 05 02 03 14 15 46 47 48 49 50 51 52 53 25 26 27 28 29 04
* Port: A0 A1 A2 A3 A4 A5 A6 A7 B0 B1 B2 B3 B4 B5 B6 B7 C0 C1 C2 C3 C4 C5 C6 C7 D0 D1 D2 D3 D4 D5 D6 D7 E0 E1 E2 E3 E4 E5 E6 E7 F0 F1 F2 F3 F4 F5 F6 F7 G0 G1 G2 G3 G4 G5
+ *
+ * Arduino Pin Layout video: https://youtu.be/rIqeVCX09FA
+ * AVR alternate pin function overview video: https://youtu.be/1yd8wuI5Plg
*/
#include "../fastio.h"
-// change for your board
-#define DEBUG_LED DIO46
-
-// UART
-#define RXD DIO0
-#define TXD DIO1
-
-// SPI
-#define SCK DIO10
-#define MISO DIO12
-#define MOSI DIO11
-#define SS DIO16
-
-// TWI (I2C)
-#define SCL DIO17
-#define SDA DIO18
-
-// Timers and PWM
-#define OC0A DIO9
-#define OC0B DIO4
-#define OC1A DIO7
-#define OC1B DIO8
-#define OC2A DIO6
-#define OC3A DIO5
-#define OC3B DIO2
-#define OC3C DIO3
-
// Digital I/O
#define DIO0_PIN PINE0
@@ -64,652 +40,419 @@
#define DIO0_WPORT PORTE
#define DIO0_DDR DDRE
#define DIO0_PWM nullptr
+#define PinE0 0
#define DIO1_PIN PINE1
#define DIO1_RPORT PINE
#define DIO1_WPORT PORTE
#define DIO1_DDR DDRE
#define DIO1_PWM nullptr
+#define PinE1 1
#define DIO2_PIN PINE4
#define DIO2_RPORT PINE
#define DIO2_WPORT PORTE
#define DIO2_DDR DDRE
#define DIO2_PWM &OCR3BL
+#define PinE4 2
#define DIO3_PIN PINE5
#define DIO3_RPORT PINE
#define DIO3_WPORT PORTE
#define DIO3_DDR DDRE
#define DIO3_PWM &OCR3CL
+#define PinE5 3
#define DIO4_PIN PING5
#define DIO4_RPORT PING
#define DIO4_WPORT PORTG
#define DIO4_DDR DDRG
#define DIO4_PWM &OCR0B
+#define PinG5 4
#define DIO5_PIN PINE3
#define DIO5_RPORT PINE
#define DIO5_WPORT PORTE
#define DIO5_DDR DDRE
#define DIO5_PWM &OCR3AL
+#define PinE3 5
#define DIO6_PIN PINB4
#define DIO6_RPORT PINB
#define DIO6_WPORT PORTB
#define DIO6_DDR DDRB
#define DIO6_PWM &OCR2AL
+#define PinB4 6
#define DIO7_PIN PINB5
#define DIO7_RPORT PINB
#define DIO7_WPORT PORTB
#define DIO7_DDR DDRB
#define DIO7_PWM &OCR1AL
+#define PinB5 7
#define DIO8_PIN PINB6
#define DIO8_RPORT PINB
#define DIO8_WPORT PORTB
#define DIO8_DDR DDRB
#define DIO8_PWM &OCR1BL
+#define PinB6 8
#define DIO9_PIN PINB7
#define DIO9_RPORT PINB
#define DIO9_WPORT PORTB
#define DIO9_DDR DDRB
#define DIO9_PWM &OCR0AL
+#define PinB7 9
#define DIO10_PIN PINB1
#define DIO10_RPORT PINB
#define DIO10_WPORT PORTB
#define DIO10_DDR DDRB
#define DIO10_PWM nullptr
+#define PinB1 10
#define DIO11_PIN PINB2
#define DIO11_RPORT PINB
#define DIO11_WPORT PORTB
#define DIO11_DDR DDRB
#define DIO11_PWM nullptr
+#define PinB2 11
#define DIO12_PIN PINB3
#define DIO12_RPORT PINB
#define DIO12_WPORT PORTB
#define DIO12_DDR DDRB
#define DIO12_PWM nullptr
+#define PinB3 12
#define DIO13_PIN PINE2
#define DIO13_RPORT PINE
#define DIO13_WPORT PORTE
#define DIO13_DDR DDRE
#define DIO13_PWM nullptr
+#define PinE2 13
#define DIO14_PIN PINE6
#define DIO14_RPORT PINE
#define DIO14_WPORT PORTE
#define DIO14_DDR DDRE
#define DIO14_PWM nullptr
+#define PinE6 14
#define DIO15_PIN PINE7
#define DIO15_RPORT PINE
#define DIO15_WPORT PORTE
#define DIO15_DDR DDRE
#define DIO15_PWM nullptr
+#define PinE7 15
#define DIO16_PIN PINB0
#define DIO16_RPORT PINB
#define DIO16_WPORT PORTB
#define DIO16_DDR DDRB
#define DIO16_PWM nullptr
+#define PinB0 16
#define DIO17_PIN PIND0
#define DIO17_RPORT PIND
#define DIO17_WPORT PORTD
#define DIO17_DDR DDRD
#define DIO17_PWM nullptr
+#define PinD0 17
#define DIO18_PIN PIND1
#define DIO18_RPORT PIND
#define DIO18_WPORT PORTD
#define DIO18_DDR DDRD
#define DIO18_PWM nullptr
+#define PinD1 18
#define DIO19_PIN PIND2
#define DIO19_RPORT PIND
#define DIO19_WPORT PORTD
#define DIO19_DDR DDRD
#define DIO19_PWM nullptr
+#define PinD2 19
#define DIO20_PIN PIND3
#define DIO20_RPORT PIND
#define DIO20_WPORT PORTD
#define DIO20_DDR DDRD
#define DIO20_PWM nullptr
+#define PinD3 20
#define DIO21_PIN PIND4
#define DIO21_RPORT PIND
#define DIO21_WPORT PORTD
#define DIO21_DDR DDRD
#define DIO21_PWM nullptr
+#define PinD4 21
#define DIO22_PIN PIND5
#define DIO22_RPORT PIND
#define DIO22_WPORT PORTD
#define DIO22_DDR DDRD
#define DIO22_PWM nullptr
+#define PinD5 22
#define DIO23_PIN PIND6
#define DIO23_RPORT PIND
#define DIO23_WPORT PORTD
#define DIO23_DDR DDRD
#define DIO23_PWM nullptr
+#define PinD6 23
#define DIO24_PIN PIND7
#define DIO24_RPORT PIND
#define DIO24_WPORT PORTD
#define DIO24_DDR DDRD
#define DIO24_PWM nullptr
+#define PinD7 24
#define DIO25_PIN PING0
#define DIO25_RPORT PING
#define DIO25_WPORT PORTG
#define DIO25_DDR DDRG
#define DIO25_PWM nullptr
+#define PinG0 25
#define DIO26_PIN PING1
#define DIO26_RPORT PING
#define DIO26_WPORT PORTG
#define DIO26_DDR DDRG
#define DIO26_PWM nullptr
+#define PinG1 26
#define DIO27_PIN PING2
#define DIO27_RPORT PING
#define DIO27_WPORT PORTG
#define DIO27_DDR DDRG
#define DIO27_PWM nullptr
+#define PinG2 27
#define DIO28_PIN PING3
#define DIO28_RPORT PING
#define DIO28_WPORT PORTG
#define DIO28_DDR DDRG
#define DIO28_PWM nullptr
+#define PinG3 28
#define DIO29_PIN PING4
#define DIO29_RPORT PING
#define DIO29_WPORT PORTG
#define DIO29_DDR DDRG
#define DIO29_PWM nullptr
+#define PinG4 29
#define DIO30_PIN PINC0
#define DIO30_RPORT PINC
#define DIO30_WPORT PORTC
#define DIO30_DDR DDRC
#define DIO30_PWM nullptr
+#define PinC0 30
#define DIO31_PIN PINC1
#define DIO31_RPORT PINC
#define DIO31_WPORT PORTC
#define DIO31_DDR DDRC
#define DIO31_PWM nullptr
+#define PinC1 31
#define DIO32_PIN PINC2
#define DIO32_RPORT PINC
#define DIO32_WPORT PORTC
#define DIO32_DDR DDRC
#define DIO32_PWM nullptr
+#define PinC2 32
#define DIO33_PIN PINC3
#define DIO33_RPORT PINC
#define DIO33_WPORT PORTC
#define DIO33_DDR DDRC
#define DIO33_PWM nullptr
+#define PinC3 33
#define DIO34_PIN PINC4
#define DIO34_RPORT PINC
#define DIO34_WPORT PORTC
#define DIO34_DDR DDRC
#define DIO34_PWM nullptr
+#define PinC4 34
#define DIO35_PIN PINC5
#define DIO35_RPORT PINC
#define DIO35_WPORT PORTC
#define DIO35_DDR DDRC
#define DIO35_PWM nullptr
+#define PinC5 35
#define DIO36_PIN PINC6
#define DIO36_RPORT PINC
#define DIO36_WPORT PORTC
#define DIO36_DDR DDRC
#define DIO36_PWM nullptr
+#define PinC6 36
#define DIO37_PIN PINC7
#define DIO37_RPORT PINC
#define DIO37_WPORT PORTC
#define DIO37_DDR DDRC
#define DIO37_PWM nullptr
+#define PinC7 37
#define DIO38_PIN PINA0
#define DIO38_RPORT PINA
#define DIO38_WPORT PORTA
#define DIO38_DDR DDRA
#define DIO38_PWM nullptr
+#define PinA0 38
#define DIO39_PIN PINA1
#define DIO39_RPORT PINA
#define DIO39_WPORT PORTA
#define DIO39_DDR DDRA
#define DIO39_PWM nullptr
+#define PinA1 39
#define DIO40_PIN PINA2
#define DIO40_RPORT PINA
#define DIO40_WPORT PORTA
#define DIO40_DDR DDRA
#define DIO40_PWM nullptr
+#define PinA2 40
#define DIO41_PIN PINA3
#define DIO41_RPORT PINA
#define DIO41_WPORT PORTA
#define DIO41_DDR DDRA
#define DIO41_PWM nullptr
+#define PinA3 41
#define DIO42_PIN PINA4
#define DIO42_RPORT PINA
#define DIO42_WPORT PORTA
#define DIO42_DDR DDRA
#define DIO42_PWM nullptr
+#define PinA4 42
#define DIO43_PIN PINA5
#define DIO43_RPORT PINA
#define DIO43_WPORT PORTA
#define DIO43_DDR DDRA
#define DIO43_PWM nullptr
+#define PinA5 43
#define DIO44_PIN PINA6
#define DIO44_RPORT PINA
#define DIO44_WPORT PORTA
#define DIO44_DDR DDRA
#define DIO44_PWM nullptr
+#define PinA6 44
#define DIO45_PIN PINA7
#define DIO45_RPORT PINA
#define DIO45_WPORT PORTA
#define DIO45_DDR DDRA
#define DIO45_PWM nullptr
+#define PinA7 45
#define DIO46_PIN PINF0
#define DIO46_RPORT PINF
#define DIO46_WPORT PORTF
#define DIO46_DDR DDRF
#define DIO46_PWM nullptr
+#define PinF0 46
#define DIO47_PIN PINF1
#define DIO47_RPORT PINF
#define DIO47_WPORT PORTF
#define DIO47_DDR DDRF
#define DIO47_PWM nullptr
+#define PinF1 47
#define DIO48_PIN PINF2
#define DIO48_RPORT PINF
#define DIO48_WPORT PORTF
#define DIO48_DDR DDRF
#define DIO48_PWM nullptr
+#define PinF2 48
#define DIO49_PIN PINF3
#define DIO49_RPORT PINF
#define DIO49_WPORT PORTF
#define DIO49_DDR DDRF
#define DIO49_PWM nullptr
+#define PinF3 49
#define DIO50_PIN PINF4
#define DIO50_RPORT PINF
#define DIO50_WPORT PORTF
#define DIO50_DDR DDRF
#define DIO50_PWM nullptr
+#define PinF4 50
#define DIO51_PIN PINF5
#define DIO51_RPORT PINF
#define DIO51_WPORT PORTF
#define DIO51_DDR DDRF
#define DIO51_PWM nullptr
+#define PinF5 51
#define DIO52_PIN PINF6
#define DIO52_RPORT PINF
#define DIO52_WPORT PORTF
#define DIO52_DDR DDRF
#define DIO52_PWM nullptr
+#define PinF6 52
#define DIO53_PIN PINF7
#define DIO53_RPORT PINF
#define DIO53_WPORT PORTF
#define DIO53_DDR DDRF
#define DIO53_PWM nullptr
+#define PinF7 53
-#undef PA0
-#define PA0_PIN PINA0
-#define PA0_RPORT PINA
-#define PA0_WPORT PORTA
-#define PA0_DDR DDRA
-#define PA0_PWM nullptr
-#undef PA1
-#define PA1_PIN PINA1
-#define PA1_RPORT PINA
-#define PA1_WPORT PORTA
-#define PA1_DDR DDRA
-#define PA1_PWM nullptr
-#undef PA2
-#define PA2_PIN PINA2
-#define PA2_RPORT PINA
-#define PA2_WPORT PORTA
-#define PA2_DDR DDRA
-#define PA2_PWM nullptr
-#undef PA3
-#define PA3_PIN PINA3
-#define PA3_RPORT PINA
-#define PA3_WPORT PORTA
-#define PA3_DDR DDRA
-#define PA3_PWM nullptr
-#undef PA4
-#define PA4_PIN PINA4
-#define PA4_RPORT PINA
-#define PA4_WPORT PORTA
-#define PA4_DDR DDRA
-#define PA4_PWM nullptr
-#undef PA5
-#define PA5_PIN PINA5
-#define PA5_RPORT PINA
-#define PA5_WPORT PORTA
-#define PA5_DDR DDRA
-#define PA5_PWM nullptr
-#undef PA6
-#define PA6_PIN PINA6
-#define PA6_RPORT PINA
-#define PA6_WPORT PORTA
-#define PA6_DDR DDRA
-#define PA6_PWM nullptr
-#undef PA7
-#define PA7_PIN PINA7
-#define PA7_RPORT PINA
-#define PA7_WPORT PORTA
-#define PA7_DDR DDRA
-#define PA7_PWM nullptr
-
-#undef PB0
-#define PB0_PIN PINB0
-#define PB0_RPORT PINB
-#define PB0_WPORT PORTB
-#define PB0_DDR DDRB
-#define PB0_PWM nullptr
-#undef PB1
-#define PB1_PIN PINB1
-#define PB1_RPORT PINB
-#define PB1_WPORT PORTB
-#define PB1_DDR DDRB
-#define PB1_PWM nullptr
-#undef PB2
-#define PB2_PIN PINB2
-#define PB2_RPORT PINB
-#define PB2_WPORT PORTB
-#define PB2_DDR DDRB
-#define PB2_PWM nullptr
-#undef PB3
-#define PB3_PIN PINB3
-#define PB3_RPORT PINB
-#define PB3_WPORT PORTB
-#define PB3_DDR DDRB
-#define PB3_PWM nullptr
-#undef PB4
-#define PB4_PIN PINB4
-#define PB4_RPORT PINB
-#define PB4_WPORT PORTB
-#define PB4_DDR DDRB
-#define PB4_PWM &OCR2A
-#undef PB5
-#define PB5_PIN PINB5
-#define PB5_RPORT PINB
-#define PB5_WPORT PORTB
-#define PB5_DDR DDRB
-#define PB5_PWM nullptr
-#undef PB6
-#define PB6_PIN PINB6
-#define PB6_RPORT PINB
-#define PB6_WPORT PORTB
-#define PB6_DDR DDRB
-#define PB6_PWM nullptr
-#undef PB7
-#define PB7_PIN PINB7
-#define PB7_RPORT PINB
-#define PB7_WPORT PORTB
-#define PB7_DDR DDRB
-#define PB7_PWM &OCR0A
-
-#undef PC0
-#define PC0_PIN PINC0
-#define PC0_RPORT PINC
-#define PC0_WPORT PORTC
-#define PC0_DDR DDRC
-#define PC0_PWM nullptr
-#undef PC1
-#define PC1_PIN PINC1
-#define PC1_RPORT PINC
-#define PC1_WPORT PORTC
-#define PC1_DDR DDRC
-#define PC1_PWM nullptr
-#undef PC2
-#define PC2_PIN PINC2
-#define PC2_RPORT PINC
-#define PC2_WPORT PORTC
-#define PC2_DDR DDRC
-#define PC2_PWM nullptr
-#undef PC3
-#define PC3_PIN PINC3
-#define PC3_RPORT PINC
-#define PC3_WPORT PORTC
-#define PC3_DDR DDRC
-#define PC3_PWM nullptr
-#undef PC4
-#define PC4_PIN PINC4
-#define PC4_RPORT PINC
-#define PC4_WPORT PORTC
-#define PC4_DDR DDRC
-#define PC4_PWM nullptr
-#undef PC5
-#define PC5_PIN PINC5
-#define PC5_RPORT PINC
-#define PC5_WPORT PORTC
-#define PC5_DDR DDRC
-#define PC5_PWM nullptr
-#undef PC6
-#define PC6_PIN PINC6
-#define PC6_RPORT PINC
-#define PC6_WPORT PORTC
-#define PC6_DDR DDRC
-#define PC6_PWM nullptr
-#undef PC7
-#define PC7_PIN PINC7
-#define PC7_RPORT PINC
-#define PC7_WPORT PORTC
-#define PC7_DDR DDRC
-#define PC7_PWM nullptr
-
-#undef PD0
-#define PD0_PIN PIND0
-#define PD0_RPORT PIND
-#define PD0_WPORT PORTD
-#define PD0_DDR DDRD
-#define PD0_PWM nullptr
-#undef PD1
-#define PD1_PIN PIND1
-#define PD1_RPORT PIND
-#define PD1_WPORT PORTD
-#define PD1_DDR DDRD
-#define PD1_PWM nullptr
-#undef PD2
-#define PD2_PIN PIND2
-#define PD2_RPORT PIND
-#define PD2_WPORT PORTD
-#define PD2_DDR DDRD
-#define PD2_PWM nullptr
-#undef PD3
-#define PD3_PIN PIND3
-#define PD3_RPORT PIND
-#define PD3_WPORT PORTD
-#define PD3_DDR DDRD
-#define PD3_PWM nullptr
-#undef PD4
-#define PD4_PIN PIND4
-#define PD4_RPORT PIND
-#define PD4_WPORT PORTD
-#define PD4_DDR DDRD
-#define PD4_PWM nullptr
-#undef PD5
-#define PD5_PIN PIND5
-#define PD5_RPORT PIND
-#define PD5_WPORT PORTD
-#define PD5_DDR DDRD
-#define PD5_PWM nullptr
-#undef PD6
-#define PD6_PIN PIND6
-#define PD6_RPORT PIND
-#define PD6_WPORT PORTD
-#define PD6_DDR DDRD
-#define PD6_PWM nullptr
-#undef PD7
-#define PD7_PIN PIND7
-#define PD7_RPORT PIND
-#define PD7_WPORT PORTD
-#define PD7_DDR DDRD
-#define PD7_PWM nullptr
-
-#undef PE0
-#define PE0_PIN PINE0
-#define PE0_RPORT PINE
-#define PE0_WPORT PORTE
-#define PE0_DDR DDRE
-#define PE0_PWM nullptr
-#undef PE1
-#define PE1_PIN PINE1
-#define PE1_RPORT PINE
-#define PE1_WPORT PORTE
-#define PE1_DDR DDRE
-#define PE1_PWM nullptr
-#undef PE2
-#define PE2_PIN PINE2
-#define PE2_RPORT PINE
-#define PE2_WPORT PORTE
-#define PE2_DDR DDRE
-#define PE2_PWM nullptr
-#undef PE3
-#define PE3_PIN PINE3
-#define PE3_RPORT PINE
-#define PE3_WPORT PORTE
-#define PE3_DDR DDRE
-#define PE3_PWM &OCR3AL
-#undef PE4
-#define PE4_PIN PINE4
-#define PE4_RPORT PINE
-#define PE4_WPORT PORTE
-#define PE4_DDR DDRE
-#define PE4_PWM &OCR3BL
-#undef PE5
-#define PE5_PIN PINE5
-#define PE5_RPORT PINE
-#define PE5_WPORT PORTE
-#define PE5_DDR DDRE
-#define PE5_PWM &OCR3CL
-#undef PE6
-#define PE6_PIN PINE6
-#define PE6_RPORT PINE
-#define PE6_WPORT PORTE
-#define PE6_DDR DDRE
-#define PE6_PWM nullptr
-#undef PE7
-#define PE7_PIN PINE7
-#define PE7_RPORT PINE
-#define PE7_WPORT PORTE
-#define PE7_DDR DDRE
-#define PE7_PWM nullptr
-
-#undef PF0
-#define PF0_PIN PINF0
-#define PF0_RPORT PINF
-#define PF0_WPORT PORTF
-#define PF0_DDR DDRF
-#define PF0_PWM nullptr
-#undef PF1
-#define PF1_PIN PINF1
-#define PF1_RPORT PINF
-#define PF1_WPORT PORTF
-#define PF1_DDR DDRF
-#define PF1_PWM nullptr
-#undef PF2
-#define PF2_PIN PINF2
-#define PF2_RPORT PINF
-#define PF2_WPORT PORTF
-#define PF2_DDR DDRF
-#define PF2_PWM nullptr
-#undef PF3
-#define PF3_PIN PINF3
-#define PF3_RPORT PINF
-#define PF3_WPORT PORTF
-#define PF3_DDR DDRF
-#define PF3_PWM nullptr
-#undef PF4
-#define PF4_PIN PINF4
-#define PF4_RPORT PINF
-#define PF4_WPORT PORTF
-#define PF4_DDR DDRF
-#define PF4_PWM nullptr
-#undef PF5
-#define PF5_PIN PINF5
-#define PF5_RPORT PINF
-#define PF5_WPORT PORTF
-#define PF5_DDR DDRF
-#define PF5_PWM nullptr
-#undef PF6
-#define PF6_PIN PINF6
-#define PF6_RPORT PINF
-#define PF6_WPORT PORTF
-#define PF6_DDR DDRF
-#define PF6_PWM nullptr
-#undef PF7
-#define PF7_PIN PINF7
-#define PF7_RPORT PINF
-#define PF7_WPORT PORTF
-#define PF7_DDR DDRF
-#define PF7_PWM nullptr
-
-#undef PG0
-#define PG0_PIN PING0
-#define PG0_RPORT PING
-#define PG0_WPORT PORTG
-#define PG0_DDR DDRG
-#define PG0_PWM nullptr
-#undef PG1
-#define PG1_PIN PING1
-#define PG1_RPORT PING
-#define PG1_WPORT PORTG
-#define PG1_DDR DDRG
-#define PG1_PWM nullptr
-#undef PG2
-#define PG2_PIN PING2
-#define PG2_RPORT PING
-#define PG2_WPORT PORTG
-#define PG2_DDR DDRG
-#define PG2_PWM nullptr
-#undef PG3
-#define PG3_PIN PING3
-#define PG3_RPORT PING
-#define PG3_WPORT PORTG
-#define PG3_DDR DDRG
-#define PG3_PWM nullptr
-#undef PG4
-#define PG4_PIN PING4
-#define PG4_RPORT PING
-#define PG4_WPORT PORTG
-#define PG4_DDR DDRG
-#define PG4_PWM nullptr
-#undef PG5
-#define PG5_PIN PING5
-#define PG5_RPORT PING
-#define PG5_WPORT PORTG
-#define PG5_DDR DDRG
-#define PG5_PWM &OCR0B
+#define DIO_NUM 54
+
+// change for your board
+// NOTE: may be used by external libraries (LiquidCrystal)
+#ifndef DEBUG_LED
+ #define DEBUG_LED PinF0
+#endif
+
+// UART
+#ifndef RXD
+ #define RXD PinE0
+#endif
+#ifndef TXD
+ #define TXD PinE1
+#endif
+
+// SPI
+#ifndef SCK
+ #define SCK PinB1
+#endif
+#ifndef MISO
+ #define MISO PinB3
+#endif
+#ifndef MOSI
+ #define MOSI PinB2
+#endif
+#ifndef SS
+ #define SS PinB0
+#endif
+
+// TWI (I2C)
+#define SCL PinD0
+#define SDA PinD1
+
+// Timers and PWM
+#define OC0A PinB7
+#define OC0B PinG5
+#define OC1A PinB5
+#define OC1B PinB6
+#define OC2A PinB4
+#define OC3A PinE3
+#define OC3B PinE4
+#define OC3C PinE5
diff --git a/Marlin/src/HAL/AVR/fastio/fastio_168.h b/Marlin/src/HAL/AVR/fastio/fastio_168.h
index 8cfdd1e8f825..31a42c480344 100644
--- a/Marlin/src/HAL/AVR/fastio/fastio_168.h
+++ b/Marlin/src/HAL/AVR/fastio/fastio_168.h
@@ -26,34 +26,13 @@
*
* Logical Pin: 08 09 10 11 12 13 14 15 16 17 18 19 20 21 00 01 02 03 04 05 06 07
* Port: B0 B1 B2 B3 B4 B5 C0 C1 C2 C3 C4 C5 C6 C7 D0 D1 D2 D3 D4 D5 D6 D7
+ *
+ * Arduino Pin Layout video: https://youtu.be/rIqeVCX09FA
+ * AVR alternate pin function overview video: https://youtu.be/1yd8wuI5Plg
*/
#include "../fastio.h"
-#define DEBUG_LED AIO5
-
-// UART
-#define RXD DIO0
-#define TXD DIO1
-
-// SPI
-#define SCK DIO13
-#define MISO DIO12
-#define MOSI DIO11
-#define SS DIO10
-
-// TWI (I2C)
-#define SCL AIO5
-#define SDA AIO4
-
-// Timers and PWM
-#define OC0A DIO6
-#define OC0B DIO5
-#define OC1A DIO9
-#define OC1B DIO10
-#define OC2A DIO11
-#define OC2B DIO3
-
// Digital I/O
#define DIO0_PIN PIND0
@@ -61,297 +40,199 @@
#define DIO0_WPORT PORTD
#define DIO0_DDR DDRD
#define DIO0_PWM nullptr
+#define PinD0 0
#define DIO1_PIN PIND1
#define DIO1_RPORT PIND
#define DIO1_WPORT PORTD
#define DIO1_DDR DDRD
#define DIO1_PWM nullptr
+#define PinD1 1
#define DIO2_PIN PIND2
#define DIO2_RPORT PIND
#define DIO2_WPORT PORTD
#define DIO2_DDR DDRD
#define DIO2_PWM nullptr
+#define PinD2 2
#define DIO3_PIN PIND3
#define DIO3_RPORT PIND
#define DIO3_WPORT PORTD
#define DIO3_DDR DDRD
#define DIO3_PWM &OCR2B
+#define PinD3 3
#define DIO4_PIN PIND4
#define DIO4_RPORT PIND
#define DIO4_WPORT PORTD
#define DIO4_DDR DDRD
#define DIO4_PWM nullptr
+#define PinD4 4
#define DIO5_PIN PIND5
#define DIO5_RPORT PIND
#define DIO5_WPORT PORTD
#define DIO5_DDR DDRD
#define DIO5_PWM &OCR0B
+#define PinD5 5
#define DIO6_PIN PIND6
#define DIO6_RPORT PIND
#define DIO6_WPORT PORTD
#define DIO6_DDR DDRD
#define DIO6_PWM &OCR0A
+#define PinD6 6
#define DIO7_PIN PIND7
#define DIO7_RPORT PIND
#define DIO7_WPORT PORTD
#define DIO7_DDR DDRD
#define DIO7_PWM nullptr
+#define PinD7 7
#define DIO8_PIN PINB0
#define DIO8_RPORT PINB
#define DIO8_WPORT PORTB
#define DIO8_DDR DDRB
#define DIO8_PWM nullptr
+#define PinB0 8
#define DIO9_PIN PINB1
#define DIO9_RPORT PINB
#define DIO9_WPORT PORTB
#define DIO9_DDR DDRB
#define DIO9_PWM nullptr
+#define PinB1 9
#define DIO10_PIN PINB2
#define DIO10_RPORT PINB
#define DIO10_WPORT PORTB
#define DIO10_DDR DDRB
#define DIO10_PWM nullptr
+#define PinB2 10
#define DIO11_PIN PINB3
#define DIO11_RPORT PINB
#define DIO11_WPORT PORTB
#define DIO11_DDR DDRB
#define DIO11_PWM &OCR2A
+#define PinB3 11
#define DIO12_PIN PINB4
#define DIO12_RPORT PINB
#define DIO12_WPORT PORTB
#define DIO12_DDR DDRB
#define DIO12_PWM nullptr
+#define PinB4 12
#define DIO13_PIN PINB5
#define DIO13_RPORT PINB
#define DIO13_WPORT PORTB
#define DIO13_DDR DDRB
#define DIO13_PWM nullptr
+#define PinB5 13
#define DIO14_PIN PINC0
#define DIO14_RPORT PINC
#define DIO14_WPORT PORTC
#define DIO14_DDR DDRC
#define DIO14_PWM nullptr
+#define PinC0 14
#define DIO15_PIN PINC1
#define DIO15_RPORT PINC
#define DIO15_WPORT PORTC
#define DIO15_DDR DDRC
#define DIO15_PWM nullptr
+#define PinC1 15
#define DIO16_PIN PINC2
#define DIO16_RPORT PINC
#define DIO16_WPORT PORTC
#define DIO16_DDR DDRC
#define DIO16_PWM nullptr
+#define PinC2 16
#define DIO17_PIN PINC3
#define DIO17_RPORT PINC
#define DIO17_WPORT PORTC
#define DIO17_DDR DDRC
#define DIO17_PWM nullptr
+#define PinC3 17
#define DIO18_PIN PINC4
#define DIO18_RPORT PINC
#define DIO18_WPORT PORTC
#define DIO18_DDR DDRC
#define DIO18_PWM nullptr
+#define PinC4 18
#define DIO19_PIN PINC5
#define DIO19_RPORT PINC
#define DIO19_WPORT PORTC
#define DIO19_DDR DDRC
#define DIO19_PWM nullptr
+#define PinC5 19
#define DIO20_PIN PINC6
#define DIO20_RPORT PINC
#define DIO20_WPORT PORTC
#define DIO20_DDR DDRC
#define DIO20_PWM nullptr
+#define PinC6 20
+
+#define DIO13_PIN PINB6
+#define DIO13_RPORT PINB
+#define DIO13_WPORT PORTB
+#define DIO13_DDR DDRB
+#define DIO13_PWM nullptr
+#define PinB6 21
-#define DIO21_PIN PINC7
-#define DIO21_RPORT PINC
-#define DIO21_WPORT PORTC
-#define DIO21_DDR DDRC
-#define DIO21_PWM nullptr
-
-#undef PB0
-#define PB0_PIN PINB0
-#define PB0_RPORT PINB
-#define PB0_WPORT PORTB
-#define PB0_DDR DDRB
-#define PB0_PWM nullptr
-
-#undef PB1
-#define PB1_PIN PINB1
-#define PB1_RPORT PINB
-#define PB1_WPORT PORTB
-#define PB1_DDR DDRB
-#define PB1_PWM nullptr
-
-#undef PB2
-#define PB2_PIN PINB2
-#define PB2_RPORT PINB
-#define PB2_WPORT PORTB
-#define PB2_DDR DDRB
-#define PB2_PWM nullptr
-
-#undef PB3
-#define PB3_PIN PINB3
-#define PB3_RPORT PINB
-#define PB3_WPORT PORTB
-#define PB3_DDR DDRB
-#define PB3_PWM &OCR2A
-
-#undef PB4
-#define PB4_PIN PINB4
-#define PB4_RPORT PINB
-#define PB4_WPORT PORTB
-#define PB4_DDR DDRB
-#define PB4_PWM nullptr
-
-#undef PB5
-#define PB5_PIN PINB5
-#define PB5_RPORT PINB
-#define PB5_WPORT PORTB
-#define PB5_DDR DDRB
-#define PB5_PWM nullptr
-
-#undef PB6
-#define PB6_PIN PINB6
-#define PB6_RPORT PINB
-#define PB6_WPORT PORTB
-#define PB6_DDR DDRB
-#define PB6_PWM nullptr
-
-#undef PB7
-#define PB7_PIN PINB7
-#define PB7_RPORT PINB
-#define PB7_WPORT PORTB
-#define PB7_DDR DDRB
-#define PB7_PWM nullptr
-
-#undef PC0
-#define PC0_PIN PINC0
-#define PC0_RPORT PINC
-#define PC0_WPORT PORTC
-#define PC0_DDR DDRC
-#define PC0_PWM nullptr
-
-#undef PC1
-#define PC1_PIN PINC1
-#define PC1_RPORT PINC
-#define PC1_WPORT PORTC
-#define PC1_DDR DDRC
-#define PC1_PWM nullptr
-
-#undef PC2
-#define PC2_PIN PINC2
-#define PC2_RPORT PINC
-#define PC2_WPORT PORTC
-#define PC2_DDR DDRC
-#define PC2_PWM nullptr
-
-#undef PC3
-#define PC3_PIN PINC3
-#define PC3_RPORT PINC
-#define PC3_WPORT PORTC
-#define PC3_DDR DDRC
-#define PC3_PWM nullptr
-
-#undef PC4
-#define PC4_PIN PINC4
-#define PC4_RPORT PINC
-#define PC4_WPORT PORTC
-#define PC4_DDR DDRC
-#define PC4_PWM nullptr
-
-#undef PC5
-#define PC5_PIN PINC5
-#define PC5_RPORT PINC
-#define PC5_WPORT PORTC
-#define PC5_DDR DDRC
-#define PC5_PWM nullptr
-
-#undef PC6
-#define PC6_PIN PINC6
-#define PC6_RPORT PINC
-#define PC6_WPORT PORTC
-#define PC6_DDR DDRC
-#define PC6_PWM nullptr
-
-#undef PC7
-#define PC7_PIN PINC7
-#define PC7_RPORT PINC
-#define PC7_WPORT PORTC
-#define PC7_DDR DDRC
-#define PC7_PWM nullptr
-
-#undef PD0
-#define PD0_PIN PIND0
-#define PD0_RPORT PIND
-#define PD0_WPORT PORTD
-#define PD0_DDR DDRD
-#define PD0_PWM nullptr
-
-#undef PD1
-#define PD1_PIN PIND1
-#define PD1_RPORT PIND
-#define PD1_WPORT PORTD
-#define PD1_DDR DDRD
-#define PD1_PWM nullptr
-
-#undef PD2
-#define PD2_PIN PIND2
-#define PD2_RPORT PIND
-#define PD2_WPORT PORTD
-#define PD2_DDR DDRD
-#define PD2_PWM nullptr
-
-#undef PD3
-#define PD3_PIN PIND3
-#define PD3_RPORT PIND
-#define PD3_WPORT PORTD
-#define PD3_DDR DDRD
-#define PD3_PWM &OCR2B
-
-#undef PD4
-#define PD4_PIN PIND4
-#define PD4_RPORT PIND
-#define PD4_WPORT PORTD
-#define PD4_DDR DDRD
-#define PD4_PWM nullptr
-
-#undef PD5
-#define PD5_PIN PIND5
-#define PD5_RPORT PIND
-#define PD5_WPORT PORTD
-#define PD5_DDR DDRD
-#define PD5_PWM &OCR0B
-
-#undef PD6
-#define PD6_PIN PIND6
-#define PD6_RPORT PIND
-#define PD6_WPORT PORTD
-#define PD6_DDR DDRD
-#define PD6_PWM &OCR0A
-
-#undef PD7
-#define PD7_PIN PIND7
-#define PD7_RPORT PIND
-#define PD7_WPORT PORTD
-#define PD7_DDR DDRD
-#define PD7_PWM nullptr
+#define DIO13_PIN PINB7
+#define DIO13_RPORT PINB
+#define DIO13_WPORT PORTB
+#define DIO13_DDR DDRB
+#define DIO13_PWM nullptr
+#define PinB7 22
+
+#define DIO_NUM 23
+
+// NOTE: may be used by external libraries (LiquidCrystal)
+#ifndef DEBUG_LED
+ #define DEBUG_LED PinC5
+#endif
+
+// UART
+#ifndef RXD
+ #define RXD PinD0
+#endif
+#ifndef TXD
+ #define TXD PinD1
+#endif
+
+// SPI
+#ifndef SCK
+ #define SCK PinB5
+#endif
+#ifndef MISO
+ #define MISO PinB4
+#endif
+#ifndef MOSI
+ #define MOSI PinB3
+#endif
+#ifndef SS
+ #define SS PinB2
+#endif
+
+// TWI (I2C)
+#define SCL PinC5
+#define SDA PinC4
+
+// Timers and PWM
+#define OC0A PinD6
+#define OC0B PinD5
+#define OC1A PinB1
+#define OC1B PinB2
+#define OC2A PinB3
+#define OC2B PinD3
diff --git a/Marlin/src/HAL/AVR/fastio/fastio_644.h b/Marlin/src/HAL/AVR/fastio/fastio_644.h
index f4a9427e0abf..ac4b53b18258 100644
--- a/Marlin/src/HAL/AVR/fastio/fastio_644.h
+++ b/Marlin/src/HAL/AVR/fastio/fastio_644.h
@@ -26,6 +26,9 @@
*
* Logical Pin: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
* Port: B0 B1 B2 B3 B4 B5 B6 B7 D0 D1 D2 D3 D4 D5 D6 D7 C0 C1 C2 C3 C4 C5 C6 C7 A7 A6 A5 A4 A3 A2 A1 A0
+ *
+ * Arduino Pin Layout video: https://youtu.be/rIqeVCX09FA
+ * AVR alternate pin function overview video: https://youtu.be/1yd8wuI5Plg
*/
/** ATMega644
@@ -56,35 +59,6 @@
#include "../fastio.h"
-#define DEBUG_LED DIO0
-
-// UART
-#define RXD DIO8
-#define TXD DIO9
-#define RXD0 DIO8
-#define TXD0 DIO9
-
-#define RXD1 DIO10
-#define TXD1 DIO11
-
-// SPI
-#define SCK DIO7
-#define MISO DIO6
-#define MOSI DIO5
-#define SS DIO4
-
-// TWI (I2C)
-#define SCL DIO16
-#define SDA DIO17
-
-// Timers and PWM
-#define OC0A DIO3
-#define OC0B DIO4
-#define OC1A DIO13
-#define OC1B DIO12
-#define OC2A DIO15
-#define OC2B DIO14
-
// Digital I/O
#define DIO0_PIN PINB0
@@ -92,461 +66,275 @@
#define DIO0_WPORT PORTB
#define DIO0_DDR DDRB
#define DIO0_PWM nullptr
+#define PinB0 0
#define DIO1_PIN PINB1
#define DIO1_RPORT PINB
#define DIO1_WPORT PORTB
#define DIO1_DDR DDRB
#define DIO1_PWM nullptr
+#define PinB1 1
#define DIO2_PIN PINB2
#define DIO2_RPORT PINB
#define DIO2_WPORT PORTB
#define DIO2_DDR DDRB
#define DIO2_PWM nullptr
+#define PinB2 2
#define DIO3_PIN PINB3
#define DIO3_RPORT PINB
#define DIO3_WPORT PORTB
#define DIO3_DDR DDRB
#define DIO3_PWM &OCR0A
+#define PinB3 3
#define DIO4_PIN PINB4
#define DIO4_RPORT PINB
#define DIO4_WPORT PORTB
#define DIO4_DDR DDRB
#define DIO4_PWM &OCR0B
+#define PinB4 4
#define DIO5_PIN PINB5
#define DIO5_RPORT PINB
#define DIO5_WPORT PORTB
#define DIO5_DDR DDRB
#define DIO5_PWM nullptr
+#define PinB5 5
#define DIO6_PIN PINB6
#define DIO6_RPORT PINB
#define DIO6_WPORT PORTB
#define DIO6_DDR DDRB
#define DIO6_PWM nullptr
+#define PinB6 6
#define DIO7_PIN PINB7
#define DIO7_RPORT PINB
#define DIO7_WPORT PORTB
#define DIO7_DDR DDRB
#define DIO7_PWM nullptr
+#define PinB7 7
#define DIO8_PIN PIND0
#define DIO8_RPORT PIND
#define DIO8_WPORT PORTD
#define DIO8_DDR DDRD
#define DIO8_PWM nullptr
+#define PinD0 8
#define DIO9_PIN PIND1
#define DIO9_RPORT PIND
#define DIO9_WPORT PORTD
#define DIO9_DDR DDRD
#define DIO9_PWM nullptr
+#define PinD1 9
#define DIO10_PIN PIND2
#define DIO10_RPORT PIND
#define DIO10_WPORT PORTD
#define DIO10_DDR DDRD
#define DIO10_PWM nullptr
+#define PinD2 10
#define DIO11_PIN PIND3
#define DIO11_RPORT PIND
#define DIO11_WPORT PORTD
#define DIO11_DDR DDRD
#define DIO11_PWM nullptr
+#define PinD3 11
#define DIO12_PIN PIND4
#define DIO12_RPORT PIND
#define DIO12_WPORT PORTD
#define DIO12_DDR DDRD
#define DIO12_PWM &OCR1B
+#define PinD4 12
#define DIO13_PIN PIND5
#define DIO13_RPORT PIND
#define DIO13_WPORT PORTD
#define DIO13_DDR DDRD
#define DIO13_PWM &OCR1A
+#define PinD5 13
#define DIO14_PIN PIND6
#define DIO14_RPORT PIND
#define DIO14_WPORT PORTD
#define DIO14_DDR DDRD
#define DIO14_PWM &OCR2B
+#define PinD6 14
#define DIO15_PIN PIND7
#define DIO15_RPORT PIND
#define DIO15_WPORT PORTD
#define DIO15_DDR DDRD
#define DIO15_PWM &OCR2A
+#define PinD7 15
#define DIO16_PIN PINC0
#define DIO16_RPORT PINC
#define DIO16_WPORT PORTC
#define DIO16_DDR DDRC
#define DIO16_PWM nullptr
+#define PinC0 16
#define DIO17_PIN PINC1
#define DIO17_RPORT PINC
#define DIO17_WPORT PORTC
#define DIO17_DDR DDRC
#define DIO17_PWM nullptr
+#define PinC1 17
#define DIO18_PIN PINC2
#define DIO18_RPORT PINC
#define DIO18_WPORT PORTC
#define DIO18_DDR DDRC
#define DIO18_PWM nullptr
+#define PinC2 18
#define DIO19_PIN PINC3
#define DIO19_RPORT PINC
#define DIO19_WPORT PORTC
#define DIO19_DDR DDRC
#define DIO19_PWM nullptr
+#define PinC3 19
#define DIO20_PIN PINC4
#define DIO20_RPORT PINC
#define DIO20_WPORT PORTC
#define DIO20_DDR DDRC
#define DIO20_PWM nullptr
+#define PinC4 20
#define DIO21_PIN PINC5
#define DIO21_RPORT PINC
#define DIO21_WPORT PORTC
#define DIO21_DDR DDRC
#define DIO21_PWM nullptr
+#define PinC5 21
#define DIO22_PIN PINC6
#define DIO22_RPORT PINC
#define DIO22_WPORT PORTC
#define DIO22_DDR DDRC
#define DIO22_PWM nullptr
+#define PinC6 22
#define DIO23_PIN PINC7
#define DIO23_RPORT PINC
#define DIO23_WPORT PORTC
#define DIO23_DDR DDRC
#define DIO23_PWM nullptr
+#define PinC7 23
#define DIO24_PIN PINA7
#define DIO24_RPORT PINA
#define DIO24_WPORT PORTA
#define DIO24_DDR DDRA
#define DIO24_PWM nullptr
+#define PinA7 24
#define DIO25_PIN PINA6
#define DIO25_RPORT PINA
#define DIO25_WPORT PORTA
#define DIO25_DDR DDRA
#define DIO25_PWM nullptr
+#define PinA6 25
#define DIO26_PIN PINA5
#define DIO26_RPORT PINA
#define DIO26_WPORT PORTA
#define DIO26_DDR DDRA
#define DIO26_PWM nullptr
+#define PinA5 26
#define DIO27_PIN PINA4
#define DIO27_RPORT PINA
#define DIO27_WPORT PORTA
#define DIO27_DDR DDRA
#define DIO27_PWM nullptr
+#define PinA4 27
#define DIO28_PIN PINA3
#define DIO28_RPORT PINA
#define DIO28_WPORT PORTA
#define DIO28_DDR DDRA
#define DIO28_PWM nullptr
+#define PinA3 28
#define DIO29_PIN PINA2
#define DIO29_RPORT PINA
#define DIO29_WPORT PORTA
#define DIO29_DDR DDRA
#define DIO29_PWM nullptr
+#define PinA2 29
#define DIO30_PIN PINA1
#define DIO30_RPORT PINA
#define DIO30_WPORT PORTA
#define DIO30_DDR DDRA
#define DIO30_PWM nullptr
+#define PinA1 30
#define DIO31_PIN PINA0
#define DIO31_RPORT PINA
#define DIO31_WPORT PORTA
#define DIO31_DDR DDRA
#define DIO31_PWM nullptr
+#define PinA0 31
+
+#define DIO_NUM 32
+
+// NOTE: may be used by external libraries (LiquidCrystal)
+#ifndef DEBUG_LED
+ #define DEBUG_LED PinB0
+#endif
+
+// UART
+#ifndef RXD
+ #define RXD PinD0
+#endif
+#ifndef TXD
+ #define TXD PinD1
+#endif
+#ifndef RXD0
+ #define RXD0 PinD0
+#endif
+#ifndef TXD0
+ #define TXD0 PinD1
+#endif
+
+#ifndef RXD1
+ #define RXD1 PinD2
+#endif
+#ifndef TXD1
+ #define TXD1 PinD3
+#endif
-#define AIO0_PIN PINA0
-#define AIO0_RPORT PINA
-#define AIO0_WPORT PORTA
-#define AIO0_DDR DDRA
-#define AIO0_PWM nullptr
-
-#define AIO1_PIN PINA1
-#define AIO1_RPORT PINA
-#define AIO1_WPORT PORTA
-#define AIO1_DDR DDRA
-#define AIO1_PWM nullptr
-
-#define AIO2_PIN PINA2
-#define AIO2_RPORT PINA
-#define AIO2_WPORT PORTA
-#define AIO2_DDR DDRA
-#define AIO2_PWM nullptr
-
-#define AIO3_PIN PINA3
-#define AIO3_RPORT PINA
-#define AIO3_WPORT PORTA
-#define AIO3_DDR DDRA
-#define AIO3_PWM nullptr
-
-#define AIO4_PIN PINA4
-#define AIO4_RPORT PINA
-#define AIO4_WPORT PORTA
-#define AIO4_DDR DDRA
-#define AIO4_PWM nullptr
-
-#define AIO5_PIN PINA5
-#define AIO5_RPORT PINA
-#define AIO5_WPORT PORTA
-#define AIO5_DDR DDRA
-#define AIO5_PWM nullptr
-
-#define AIO6_PIN PINA6
-#define AIO6_RPORT PINA
-#define AIO6_WPORT PORTA
-#define AIO6_DDR DDRA
-#define AIO6_PWM nullptr
-
-#define AIO7_PIN PINA7
-#define AIO7_RPORT PINA
-#define AIO7_WPORT PORTA
-#define AIO7_DDR DDRA
-#define AIO7_PWM nullptr
-
-#undef PA0
-#define PA0_PIN PINA0
-#define PA0_RPORT PINA
-#define PA0_WPORT PORTA
-#define PA0_DDR DDRA
-#define PA0_PWM nullptr
-
-#undef PA1
-#define PA1_PIN PINA1
-#define PA1_RPORT PINA
-#define PA1_WPORT PORTA
-#define PA1_DDR DDRA
-#define PA1_PWM nullptr
-
-#undef PA2
-#define PA2_PIN PINA2
-#define PA2_RPORT PINA
-#define PA2_WPORT PORTA
-#define PA2_DDR DDRA
-#define PA2_PWM nullptr
-
-#undef PA3
-#define PA3_PIN PINA3
-#define PA3_RPORT PINA
-#define PA3_WPORT PORTA
-#define PA3_DDR DDRA
-#define PA3_PWM nullptr
-
-#undef PA4
-#define PA4_PIN PINA4
-#define PA4_RPORT PINA
-#define PA4_WPORT PORTA
-#define PA4_DDR DDRA
-#define PA4_PWM nullptr
-
-#undef PA5
-#define PA5_PIN PINA5
-#define PA5_RPORT PINA
-#define PA5_WPORT PORTA
-#define PA5_DDR DDRA
-#define PA5_PWM nullptr
-
-#undef PA6
-#define PA6_PIN PINA6
-#define PA6_RPORT PINA
-#define PA6_WPORT PORTA
-#define PA6_DDR DDRA
-#define PA6_PWM nullptr
-
-#undef PA7
-#define PA7_PIN PINA7
-#define PA7_RPORT PINA
-#define PA7_WPORT PORTA
-#define PA7_DDR DDRA
-#define PA7_PWM nullptr
-
-#undef PB0
-#define PB0_PIN PINB0
-#define PB0_RPORT PINB
-#define PB0_WPORT PORTB
-#define PB0_DDR DDRB
-#define PB0_PWM nullptr
-
-#undef PB1
-#define PB1_PIN PINB1
-#define PB1_RPORT PINB
-#define PB1_WPORT PORTB
-#define PB1_DDR DDRB
-#define PB1_PWM nullptr
-
-#undef PB2
-#define PB2_PIN PINB2
-#define PB2_RPORT PINB
-#define PB2_WPORT PORTB
-#define PB2_DDR DDRB
-#define PB2_PWM nullptr
-
-#undef PB3
-#define PB3_PIN PINB3
-#define PB3_RPORT PINB
-#define PB3_WPORT PORTB
-#define PB3_DDR DDRB
-#define PB3_PWM &OCR0A
-
-#undef PB4
-#define PB4_PIN PINB4
-#define PB4_RPORT PINB
-#define PB4_WPORT PORTB
-#define PB4_DDR DDRB
-#define PB4_PWM &OCR0B
-
-#undef PB5
-#define PB5_PIN PINB5
-#define PB5_RPORT PINB
-#define PB5_WPORT PORTB
-#define PB5_DDR DDRB
-#define PB5_PWM nullptr
-
-#undef PB6
-#define PB6_PIN PINB6
-#define PB6_RPORT PINB
-#define PB6_WPORT PORTB
-#define PB6_DDR DDRB
-#define PB6_PWM nullptr
-
-#undef PB7
-#define PB7_PIN PINB7
-#define PB7_RPORT PINB
-#define PB7_WPORT PORTB
-#define PB7_DDR DDRB
-#define PB7_PWM nullptr
-
-#undef PC0
-#define PC0_PIN PINC0
-#define PC0_RPORT PINC
-#define PC0_WPORT PORTC
-#define PC0_DDR DDRC
-#define PC0_PWM nullptr
-
-#undef PC1
-#define PC1_PIN PINC1
-#define PC1_RPORT PINC
-#define PC1_WPORT PORTC
-#define PC1_DDR DDRC
-#define PC1_PWM nullptr
-
-#undef PC2
-#define PC2_PIN PINC2
-#define PC2_RPORT PINC
-#define PC2_WPORT PORTC
-#define PC2_DDR DDRC
-#define PC2_PWM nullptr
-
-#undef PC3
-#define PC3_PIN PINC3
-#define PC3_RPORT PINC
-#define PC3_WPORT PORTC
-#define PC3_DDR DDRC
-#define PC3_PWM nullptr
-
-#undef PC4
-#define PC4_PIN PINC4
-#define PC4_RPORT PINC
-#define PC4_WPORT PORTC
-#define PC4_DDR DDRC
-#define PC4_PWM nullptr
-
-#undef PC5
-#define PC5_PIN PINC5
-#define PC5_RPORT PINC
-#define PC5_WPORT PORTC
-#define PC5_DDR DDRC
-#define PC5_PWM nullptr
-
-#undef PC6
-#define PC6_PIN PINC6
-#define PC6_RPORT PINC
-#define PC6_WPORT PORTC
-#define PC6_DDR DDRC
-#define PC6_PWM nullptr
-
-#undef PC7
-#define PC7_PIN PINC7
-#define PC7_RPORT PINC
-#define PC7_WPORT PORTC
-#define PC7_DDR DDRC
-#define PC7_PWM nullptr
-
-#undef PD0
-#define PD0_PIN PIND0
-#define PD0_RPORT PIND
-#define PD0_WPORT PORTD
-#define PD0_DDR DDRD
-#define PD0_PWM nullptr
-
-#undef PD1
-#define PD1_PIN PIND1
-#define PD1_RPORT PIND
-#define PD1_WPORT PORTD
-#define PD1_DDR DDRD
-#define PD1_PWM nullptr
-
-#undef PD2
-#define PD2_PIN PIND2
-#define PD2_RPORT PIND
-#define PD2_WPORT PORTD
-#define PD2_DDR DDRD
-#define PD2_PWM nullptr
-
-#undef PD3
-#define PD3_PIN PIND3
-#define PD3_RPORT PIND
-#define PD3_WPORT PORTD
-#define PD3_DDR DDRD
-#define PD3_PWM nullptr
-
-#undef PD4
-#define PD4_PIN PIND4
-#define PD4_RPORT PIND
-#define PD4_WPORT PORTD
-#define PD4_DDR DDRD
-#define PD4_PWM nullptr
-
-#undef PD5
-#define PD5_PIN PIND5
-#define PD5_RPORT PIND
-#define PD5_WPORT PORTD
-#define PD5_DDR DDRD
-#define PD5_PWM nullptr
-
-#undef PD6
-#define PD6_PIN PIND6
-#define PD6_RPORT PIND
-#define PD6_WPORT PORTD
-#define PD6_DDR DDRD
-#define PD6_PWM &OCR2B
-
-#undef PD7
-#define PD7_PIN PIND7
-#define PD7_RPORT PIND
-#define PD7_WPORT PORTD
-#define PD7_DDR DDRD
-#define PD7_PWM &OCR2A
+// SPI
+#ifndef SCK
+ #define SCK PinB7
+#endif
+#ifndef MISO
+ #define MISO PinB6
+#endif
+#ifndef MOSI
+ #define MOSI PinB5
+#endif
+#ifndef SS
+ #define SS PinB4
+#endif
+
+// TWI (I2C)
+#define SCL PinC0
+#define SDA PinC1
+
+// Timers and PWM
+#define OC0A PinB3
+#define OC0B PinB4
+#define OC1A PinD5
+#define OC1B PinD4
+#define OC2A PinD7
+#define OC2B PinD6
diff --git a/Marlin/src/HAL/AVR/fastio/fastio_AT90USB.h b/Marlin/src/HAL/AVR/fastio/fastio_AT90USB.h
index 51d400b70565..1dd66014bf6d 100644
--- a/Marlin/src/HAL/AVR/fastio/fastio_AT90USB.h
+++ b/Marlin/src/HAL/AVR/fastio/fastio_AT90USB.h
@@ -27,6 +27,9 @@
* Logical Pin: 28 29 30 31 32 33 34 35 20 21 22 23 24 25 26 27 10 11 12 13 14 15 16 17 00 01 02 03 04 05 06 07 08 09(46*47)36 37 18 19 38 39 40 41 42 43 44 45
* Port: A0 A1 A2 A3 A4 A5 A6 A7 B0 B1 B2 B3 B4 B5 B6 B7 C0 C1 C2 C3 C4 C5 C6 C7 D0 D1 D2 D3 D4 D5 D6 D7 E0 E1 E2 E3 E4 E5 E6 E7 F0 F1 F2 F3 F4 F5 F6 F7
* The logical pins 46 and 47 are not supported by Teensyduino, but are supported below as E2 and E3
+ *
+ * Arduino Pin Layout video: https://youtu.be/rIqeVCX09FA
+ * AVR alternate pin function overview video: https://youtu.be/1yd8wuI5Plg
*/
#include "../fastio.h"
@@ -47,324 +50,322 @@
#define DIO0_WPORT PORTD
#define DIO0_PWM 0
#define DIO0_DDR DDRD
+#define PinD0 0
#define DIO1_PIN PIND1
#define DIO1_RPORT PIND
#define DIO1_WPORT PORTD
#define DIO1_PWM 0
#define DIO1_DDR DDRD
+#define PinD1 1
#define DIO2_PIN PIND2
#define DIO2_RPORT PIND
#define DIO2_WPORT PORTD
#define DIO2_PWM 0
#define DIO2_DDR DDRD
+#define PinD2 2
#define DIO3_PIN PIND3
#define DIO3_RPORT PIND
#define DIO3_WPORT PORTD
#define DIO3_PWM 0
#define DIO3_DDR DDRD
+#define PinD3 3
#define DIO4_PIN PIND4
#define DIO4_RPORT PIND
#define DIO4_WPORT PORTD
#define DIO4_PWM 0
#define DIO4_DDR DDRD
+#define PinD4 4
#define DIO5_PIN PIND5
#define DIO5_RPORT PIND
#define DIO5_WPORT PORTD
#define DIO5_PWM 0
#define DIO5_DDR DDRD
+#define PinD5 5
#define DIO6_PIN PIND6
#define DIO6_RPORT PIND
#define DIO6_WPORT PORTD
#define DIO6_PWM 0
#define DIO6_DDR DDRD
+#define PinD6 6
#define DIO7_PIN PIND7
#define DIO7_RPORT PIND
#define DIO7_WPORT PORTD
#define DIO7_PWM 0
#define DIO7_DDR DDRD
+#define PinD7 7
#define DIO8_PIN PINE0
#define DIO8_RPORT PINE
#define DIO8_WPORT PORTE
#define DIO8_PWM 0
#define DIO8_DDR DDRE
+#define PinE0 8
#define DIO9_PIN PINE1
#define DIO9_RPORT PINE
#define DIO9_WPORT PORTE
#define DIO9_PWM 0
#define DIO9_DDR DDRE
+#define PinE1 9
#define DIO10_PIN PINC0
#define DIO10_RPORT PINC
#define DIO10_WPORT PORTC
#define DIO10_PWM 0
#define DIO10_DDR DDRC
+#define PinC0 10
#define DIO11_PIN PINC1
#define DIO11_RPORT PINC
#define DIO11_WPORT PORTC
#define DIO11_PWM 0
#define DIO11_DDR DDRC
+#define PinC1 11
#define DIO12_PIN PINC2
#define DIO12_RPORT PINC
#define DIO12_WPORT PORTC
#define DIO12_PWM 0
#define DIO12_DDR DDRC
+#define PinC2 12
#define DIO13_PIN PINC3
#define DIO13_RPORT PINC
#define DIO13_WPORT PORTC
#define DIO13_PWM 0
#define DIO13_DDR DDRC
+#define PinC3 13
#define DIO14_PIN PINC4
#define DIO14_RPORT PINC
#define DIO14_WPORT PORTC
#define DIO14_PWM 0 // OC3C
#define DIO14_DDR DDRC
+#define PinC4 14
#define DIO15_PIN PINC5
#define DIO15_RPORT PINC
#define DIO15_WPORT PORTC
#define DIO15_PWM 0 // OC3B
#define DIO15_DDR DDRC
+#define PinC5 15
#define DIO16_PIN PINC6
#define DIO16_RPORT PINC
#define DIO16_WPORT PORTC
#define DIO16_PWM 0 // OC3A
#define DIO16_DDR DDRC
+#define PinC6 16
#define DIO17_PIN PINC7
#define DIO17_RPORT PINC
#define DIO17_WPORT PORTC
#define DIO17_PWM 0
#define DIO17_DDR DDRC
+#define PinC7 17
#define DIO18_PIN PINE6
#define DIO18_RPORT PINE
#define DIO18_WPORT PORTE
#define DIO18_PWM 0
#define DIO18_DDR DDRE
+#define PinE6 18
#define DIO19_PIN PINE7
#define DIO19_RPORT PINE
#define DIO19_WPORT PORTE
#define DIO19_PWM 0
#define DIO19_DDR DDRE
+#define PinE7 19
#define DIO20_PIN PINB0
#define DIO20_RPORT PINB
#define DIO20_WPORT PORTB
#define DIO20_PWM 0
#define DIO20_DDR DDRB
+#define PinB0 20
#define DIO21_PIN PINB1
#define DIO21_RPORT PINB
#define DIO21_WPORT PORTB
#define DIO21_PWM 0
#define DIO21_DDR DDRB
+#define PinB1 21
#define DIO22_PIN PINB2
#define DIO22_RPORT PINB
#define DIO22_WPORT PORTB
#define DIO22_PWM 0
#define DIO22_DDR DDRB
+#define PinB2 22
#define DIO23_PIN PINB3
#define DIO23_RPORT PINB
#define DIO23_WPORT PORTB
#define DIO23_PWM 0
#define DIO23_DDR DDRB
+#define PinB3 23
#define DIO24_PIN PINB4
#define DIO24_RPORT PINB
#define DIO24_WPORT PORTB
#define DIO24_PWM 0 // OC2A
#define DIO24_DDR DDRB
+#define PinB4 24
#define DIO25_PIN PINB5
#define DIO25_RPORT PINB
#define DIO25_WPORT PORTB
#define DIO25_PWM 0 // OC1A
#define DIO25_DDR DDRB
+#define PinB5 25
#define DIO26_PIN PINB6
#define DIO26_RPORT PINB
#define DIO26_WPORT PORTB
#define DIO26_PWM 0 // OC1B
#define DIO26_DDR DDRB
+#define PinB6 26
#define DIO27_PIN PINB7
#define DIO27_RPORT PINB
#define DIO27_WPORT PORTB
#define DIO27_PWM 0 // OC1C
#define DIO27_DDR DDRB
+#define PinB7 27
#define DIO28_PIN PINA0
#define DIO28_RPORT PINA
#define DIO28_WPORT PORTA
#define DIO28_PWM 0
#define DIO28_DDR DDRA
+#define PinA0 28
#define DIO29_PIN PINA1
#define DIO29_RPORT PINA
#define DIO29_WPORT PORTA
#define DIO29_PWM 0
#define DIO29_DDR DDRA
+#define PinA1 29
#define DIO30_PIN PINA2
#define DIO30_RPORT PINA
#define DIO30_WPORT PORTA
#define DIO30_PWM 0
#define DIO30_DDR DDRA
+#define PinA2 30
#define DIO31_PIN PINA3
#define DIO31_RPORT PINA
#define DIO31_WPORT PORTA
#define DIO31_PWM 0
#define DIO31_DDR DDRA
+#define PinA3 31
#define DIO32_PIN PINA4
#define DIO32_RPORT PINA
#define DIO32_WPORT PORTA
#define DIO32_PWM 0
#define DIO32_DDR DDRA
+#define PinA4 32
#define DIO33_PIN PINA5
#define DIO33_RPORT PINA
#define DIO33_WPORT PORTA
#define DIO33_PWM 0
#define DIO33_DDR DDRA
+#define PinA5 33
#define DIO34_PIN PINA6
#define DIO34_RPORT PINA
#define DIO34_WPORT PORTA
#define DIO34_PWM 0
#define DIO34_DDR DDRA
+#define PinA6 34
#define DIO35_PIN PINA7
#define DIO35_RPORT PINA
#define DIO35_WPORT PORTA
#define DIO35_PWM 0
#define DIO35_DDR DDRA
+#define PinA7 35
#define DIO36_PIN PINE4
#define DIO36_RPORT PINE
#define DIO36_WPORT PORTE
#define DIO36_PWM 0
#define DIO36_DDR DDRE
+#define PinE4 36
#define DIO37_PIN PINE5
#define DIO37_RPORT PINE
#define DIO37_WPORT PORTE
#define DIO37_PWM 0
#define DIO37_DDR DDRE
+#define PinE5 37
#define DIO38_PIN PINF0
#define DIO38_RPORT PINF
#define DIO38_WPORT PORTF
#define DIO38_PWM 0
#define DIO38_DDR DDRF
+#define PinF0 38
#define DIO39_PIN PINF1
#define DIO39_RPORT PINF
#define DIO39_WPORT PORTF
#define DIO39_PWM 0
#define DIO39_DDR DDRF
+#define PinF1 39
#define DIO40_PIN PINF2
#define DIO40_RPORT PINF
#define DIO40_WPORT PORTF
#define DIO40_PWM 0
#define DIO40_DDR DDRF
+#define PinF2 40
#define DIO41_PIN PINF3
#define DIO41_RPORT PINF
#define DIO41_WPORT PORTF
#define DIO41_PWM 0
#define DIO41_DDR DDRF
+#define PinF3 41
#define DIO42_PIN PINF4
#define DIO42_RPORT PINF
#define DIO42_WPORT PORTF
#define DIO42_PWM 0
#define DIO42_DDR DDRF
+#define PinF4 42
#define DIO43_PIN PINF5
#define DIO43_RPORT PINF
#define DIO43_WPORT PORTF
#define DIO43_PWM 0
#define DIO43_DDR DDRF
+#define PinF5 43
#define DIO44_PIN PINF6
#define DIO44_RPORT PINF
#define DIO44_WPORT PORTF
#define DIO44_PWM 0
#define DIO44_DDR DDRF
+#define PinF6 44
#define DIO45_PIN PINF7
#define DIO45_RPORT PINF
#define DIO45_WPORT PORTF
#define DIO45_PWM 0
#define DIO45_DDR DDRF
-
-#define AIO0_PIN PINF0
-#define AIO0_RPORT PINF
-#define AIO0_WPORT PORTF
-#define AIO0_PWM 0
-#define AIO0_DDR DDRF
-
-#define AIO1_PIN PINF1
-#define AIO1_RPORT PINF
-#define AIO1_WPORT PORTF
-#define AIO1_PWM 0
-#define AIO1_DDR DDRF
-
-#define AIO2_PIN PINF2
-#define AIO2_RPORT PINF
-#define AIO2_WPORT PORTF
-#define AIO2_PWM 0
-#define AIO2_DDR DDRF
-
-#define AIO3_PIN PINF3
-#define AIO3_RPORT PINF
-#define AIO3_WPORT PORTF
-#define AIO3_PWM 0
-#define AIO3_DDR DDRF
-
-#define AIO4_PIN PINF4
-#define AIO4_RPORT PINF
-#define AIO4_WPORT PORTF
-#define AIO4_PWM 0
-#define AIO4_DDR DDRF
-
-#define AIO5_PIN PINF5
-#define AIO5_RPORT PINF
-#define AIO5_WPORT PORTF
-#define AIO5_PWM 0
-#define AIO5_DDR DDRF
-
-#define AIO6_PIN PINF6
-#define AIO6_RPORT PINF
-#define AIO6_WPORT PORTF
-#define AIO6_PWM 0
-#define AIO6_DDR DDRF
-
-#define AIO7_PIN PINF7
-#define AIO7_RPORT PINF
-#define AIO7_WPORT PORTF
-#define AIO7_PWM 0
-#define AIO7_DDR DDRF
+#define PinF7 45
//-- Begin not supported by Teensyduino
//-- don't use Arduino functions on these pins pinMode/digitalWrite/etc
@@ -373,313 +374,22 @@
#define DIO46_WPORT PORTE
#define DIO46_PWM 0
#define DIO46_DDR DDRE
+#define PinE2 46
#define DIO47_PIN PINE3
#define DIO47_RPORT PINE
#define DIO47_WPORT PORTE
#define DIO47_PWM 0
#define DIO47_DDR DDRE
+#define PinE3 47
+
+#define DIO_NUM 48
#define TEENSY_E2 46
#define TEENSY_E3 47
//-- end not supported by Teensyduino
-#undef PA0
-#define PA0_PIN PINA0
-#define PA0_RPORT PINA
-#define PA0_WPORT PORTA
-#define PA0_PWM 0
-#define PA0_DDR DDRA
-#undef PA1
-#define PA1_PIN PINA1
-#define PA1_RPORT PINA
-#define PA1_WPORT PORTA
-#define PA1_PWM 0
-#define PA1_DDR DDRA
-#undef PA2
-#define PA2_PIN PINA2
-#define PA2_RPORT PINA
-#define PA2_WPORT PORTA
-#define PA2_PWM 0
-#define PA2_DDR DDRA
-#undef PA3
-#define PA3_PIN PINA3
-#define PA3_RPORT PINA
-#define PA3_WPORT PORTA
-#define PA3_PWM 0
-#define PA3_DDR DDRA
-#undef PA4
-#define PA4_PIN PINA4
-#define PA4_RPORT PINA
-#define PA4_WPORT PORTA
-#define PA4_PWM 0
-#define PA4_DDR DDRA
-#undef PA5
-#define PA5_PIN PINA5
-#define PA5_RPORT PINA
-#define PA5_WPORT PORTA
-#define PA5_PWM 0
-#define PA5_DDR DDRA
-#undef PA6
-#define PA6_PIN PINA6
-#define PA6_RPORT PINA
-#define PA6_WPORT PORTA
-#define PA6_PWM 0
-#define PA6_DDR DDRA
-#undef PA7
-#define PA7_PIN PINA7
-#define PA7_RPORT PINA
-#define PA7_WPORT PORTA
-#define PA7_PWM 0
-#define PA7_DDR DDRA
-
-#undef PB0
-#define PB0_PIN PINB0
-#define PB0_RPORT PINB
-#define PB0_WPORT PORTB
-#define PB0_PWM 0
-#define PB0_DDR DDRB
-#undef PB1
-#define PB1_PIN PINB1
-#define PB1_RPORT PINB
-#define PB1_WPORT PORTB
-#define PB1_PWM 0
-#define PB1_DDR DDRB
-#undef PB2
-#define PB2_PIN PINB2
-#define PB2_RPORT PINB
-#define PB2_WPORT PORTB
-#define PB2_PWM 0
-#define PB2_DDR DDRB
-#undef PB3
-#define PB3_PIN PINB3
-#define PB3_RPORT PINB
-#define PB3_WPORT PORTB
-#define PB3_PWM 0
-#define PB3_DDR DDRB
-#undef PB4
-#define PB4_PIN PINB4
-#define PB4_RPORT PINB
-#define PB4_WPORT PORTB
-#define PB4_PWM 0
-#define PB4_DDR DDRB
-#undef PB5
-#define PB5_PIN PINB5
-#define PB5_RPORT PINB
-#define PB5_WPORT PORTB
-#define PB5_PWM 0
-#define PB5_DDR DDRB
-#undef PB6
-#define PB6_PIN PINB6
-#define PB6_RPORT PINB
-#define PB6_WPORT PORTB
-#define PB6_PWM 0
-#define PB6_DDR DDRB
-#undef PB7
-#define PB7_PIN PINB7
-#define PB7_RPORT PINB
-#define PB7_WPORT PORTB
-#define PB7_PWM 0
-#define PB7_DDR DDRB
-
-#undef PC0
-#define PC0_PIN PINC0
-#define PC0_RPORT PINC
-#define PC0_WPORT PORTC
-#define PC0_PWM 0
-#define PC0_DDR DDRC
-#undef PC1
-#define PC1_PIN PINC1
-#define PC1_RPORT PINC
-#define PC1_WPORT PORTC
-#define PC1_PWM 0
-#define PC1_DDR DDRC
-#undef PC2
-#define PC2_PIN PINC2
-#define PC2_RPORT PINC
-#define PC2_WPORT PORTC
-#define PC2_PWM 0
-#define PC2_DDR DDRC
-#undef PC3
-#define PC3_PIN PINC3
-#define PC3_RPORT PINC
-#define PC3_WPORT PORTC
-#define PC3_PWM 0
-#define PC3_DDR DDRC
-#undef PC4
-#define PC4_PIN PINC4
-#define PC4_RPORT PINC
-#define PC4_WPORT PORTC
-#define PC4_PWM 0
-#define PC4_DDR DDRC
-#undef PC5
-#define PC5_PIN PINC5
-#define PC5_RPORT PINC
-#define PC5_WPORT PORTC
-#define PC5_PWM 0
-#define PC5_DDR DDRC
-#undef PC6
-#define PC6_PIN PINC6
-#define PC6_RPORT PINC
-#define PC6_WPORT PORTC
-#define PC6_PWM 0
-#define PC6_DDR DDRC
-#undef PC7
-#define PC7_PIN PINC7
-#define PC7_RPORT PINC
-#define PC7_WPORT PORTC
-#define PC7_PWM 0
-#define PC7_DDR DDRC
-
-#undef PD0
-#define PD0_PIN PIND0
-#define PD0_RPORT PIND
-#define PD0_WPORT PORTD
-#define PD0_PWM 0 // OC0B
-#define PD0_DDR DDRD
-#undef PD1
-#define PD1_PIN PIND1
-#define PD1_RPORT PIND
-#define PD1_WPORT PORTD
-#define PD1_PWM 0 // OC2B
-#define PD1_DDR DDRD
-#undef PD2
-#define PD2_PIN PIND2
-#define PD2_RPORT PIND
-#define PD2_WPORT PORTD
-#define PD2_PWM 0
-#define PD2_DDR DDRD
-#undef PD3
-#define PD3_PIN PIND3
-#define PD3_RPORT PIND
-#define PD3_WPORT PORTD
-#define PD3_PWM 0
-#define PD3_DDR DDRD
-#undef PD4
-#define PD4_PIN PIND4
-#define PD4_RPORT PIND
-#define PD4_WPORT PORTD
-#define PD4_PWM 0
-#define PD4_DDR DDRD
-#undef PD5
-#define PD5_PIN PIND5
-#define PD5_RPORT PIND
-#define PD5_WPORT PORTD
-#define PD5_PWM 0
-#define PD5_DDR DDRD
-#undef PD6
-#define PD6_PIN PIND6
-#define PD6_RPORT PIND
-#define PD6_WPORT PORTD
-#define PD6_PWM 0
-#define PD6_DDR DDRD
-#undef PD7
-#define PD7_PIN PIND7
-#define PD7_RPORT PIND
-#define PD7_WPORT PORTD
-#define PD7_PWM 0
-#define PD7_DDR DDRD
-
-#undef PE0
-#define PE0_PIN PINE0
-#define PE0_RPORT PINE
-#define PE0_WPORT PORTE
-#define PE0_PWM 0
-#define PE0_DDR DDRE
-#undef PE1
-#define PE1_PIN PINE1
-#define PE1_RPORT PINE
-#define PE1_WPORT PORTE
-#define PE1_PWM 0
-#define PE1_DDR DDRE
-#undef PE2
-#define PE2_PIN PINE2
-#define PE2_RPORT PINE
-#define PE2_WPORT PORTE
-#define PE2_PWM 0
-#define PE2_DDR DDRE
-#undef PE3
-#define PE3_PIN PINE3
-#define PE3_RPORT PINE
-#define PE3_WPORT PORTE
-#define PE3_PWM 0
-#define PE3_DDR DDRE
-#undef PE4
-#define PE4_PIN PINE4
-#define PE4_RPORT PINE
-#define PE4_WPORT PORTE
-#define PE4_PWM 0
-#define PE4_DDR DDRE
-#undef PE5
-#define PE5_PIN PINE5
-#define PE5_RPORT PINE
-#define PE5_WPORT PORTE
-#define PE5_PWM 0
-#define PE5_DDR DDRE
-#undef PE6
-#define PE6_PIN PINE6
-#define PE6_RPORT PINE
-#define PE6_WPORT PORTE
-#define PE6_PWM 0
-#define PE6_DDR DDRE
-#undef PE7
-#define PE7_PIN PINE7
-#define PE7_RPORT PINE
-#define PE7_WPORT PORTE
-#define PE7_PWM 0
-#define PE7_DDR DDRE
-
-#undef PF0
-#define PF0_PIN PINF0
-#define PF0_RPORT PINF
-#define PF0_WPORT PORTF
-#define PF0_PWM 0
-#define PF0_DDR DDRF
-#undef PF1
-#define PF1_PIN PINF1
-#define PF1_RPORT PINF
-#define PF1_WPORT PORTF
-#define PF1_PWM 0
-#define PF1_DDR DDRF
-#undef PF2
-#define PF2_PIN PINF2
-#define PF2_RPORT PINF
-#define PF2_WPORT PORTF
-#define PF2_PWM 0
-#define PF2_DDR DDRF
-#undef PF3
-#define PF3_PIN PINF3
-#define PF3_RPORT PINF
-#define PF3_WPORT PORTF
-#define PF3_PWM 0
-#define PF3_DDR DDRF
-#undef PF4
-#define PF4_PIN PINF4
-#define PF4_RPORT PINF
-#define PF4_WPORT PORTF
-#define PF4_PWM 0
-#define PF4_DDR DDRF
-#undef PF5
-#define PF5_PIN PINF5
-#define PF5_RPORT PINF
-#define PF5_WPORT PORTF
-#define PF5_PWM 0
-#define PF5_DDR DDRF
-#undef PF6
-#define PF6_PIN PINF6
-#define PF6_RPORT PINF
-#define PF6_WPORT PORTF
-#define PF6_PWM 0
-#define PF6_DDR DDRF
-#undef PF7
-#define PF7_PIN PINF7
-#define PF7_RPORT PINF
-#define PF7_WPORT PORTF
-#define PF7_PWM 0
-#define PF7_DDR DDRF
-
-
/**
* Some of the pin mapping functions of the Teensduino extension to the Arduino IDE
* do not function the same as the other Arduino extensions.
diff --git a/Marlin/src/HAL/AVR/inc/Conditionals_LCD.h b/Marlin/src/HAL/AVR/inc/Conditionals_LCD.h
index a611ccd7c4a9..c747509990de 100644
--- a/Marlin/src/HAL/AVR/inc/Conditionals_LCD.h
+++ b/Marlin/src/HAL/AVR/inc/Conditionals_LCD.h
@@ -21,6 +21,6 @@
*/
#pragma once
-#if HAS_SPI_TFT || HAS_FSMC_TFT
- #error "Sorry! TFT displays are not available for HAL/AVR."
+#if HAS_FSMC_TFT
+ #error "Sorry! FSMC displays are not available for HAL/AVR."
#endif
diff --git a/Marlin/src/HAL/AVR/registers.cpp b/Marlin/src/HAL/AVR/registers.cpp
new file mode 100644
index 000000000000..9b1b9fe531ca
--- /dev/null
+++ b/Marlin/src/HAL/AVR/registers.cpp
@@ -0,0 +1,833 @@
+/**
+ * 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 .
+ *
+ */
+
+#include "registers.h"
+
+// Since the compiler could be creating multiple copies of function code-graphs for each header inline-inclusion,
+// we want to off-load the function definitions that define static memory into this solitary compilation unit.
+// This way the ROM is NOT bloated (who knows if the compiler is optimizing same-content constant objects into one?)
+
+ATmegaPinFunctions _ATmega_getPinFunctions(int pin) {
+ if (pin < 0) return {};
+
+ ATmegaPinInfo info = _ATmega_getPinInfo((unsigned int)pin);
+
+ #ifdef __AVR_TRM01__
+ if (info.port == eATmegaPort::PORT_A) {
+ if (info.pinidx == 7) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD7 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD6 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD5 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD4 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD3 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD2 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD1 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD0 };
+ return { funcs, countof(funcs) };
+ }
+ }
+ else if (info.port == eATmegaPort::PORT_B) {
+ if (info.pinidx == 7) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC0A, eATmegaPinFunc::TOC1C, eATmegaPinFunc::PCI7 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1B, eATmegaPinFunc::PCI6 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1A, eATmegaPinFunc::PCI5 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC2A, eATmegaPinFunc::PCI4 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::PCI3 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::PCI2 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::PCI1 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_CS, eATmegaPinFunc::PCI0 };
+ return { funcs, countof(funcs) };
+ }
+ }
+ else if (info.port == eATmegaPort::PORT_C) {
+ if (info.pinidx == 7) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD15 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD14 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD13 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD12 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD11 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD10 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD9 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD8 };
+ return { funcs, countof(funcs) };
+ }
+ }
+ else if (info.port == eATmegaPort::PORT_D) {
+ if (info.pinidx == 7) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER0_CLKI };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_CLKI };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART1_CLK };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ICP };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT3, eATmegaPinFunc::USART1_TXD };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT2, eATmegaPinFunc::USART1_RXD };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT1, eATmegaPinFunc::TWI_SDA };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT0, eATmegaPinFunc::TWI_CLK };
+ return { funcs, countof(funcs) };
+ }
+ }
+ else if (info.port == eATmegaPort::PORT_E) {
+ if (info.pinidx == 7) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT7, eATmegaPinFunc::TIMER3_ICP, eATmegaPinFunc::CLK0 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT6, eATmegaPinFunc::TIMER3_CLKI };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT5, eATmegaPinFunc::TOC3C };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT4, eATmegaPinFunc::TOC3B };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN1, eATmegaPinFunc::TOC3A };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN0, eATmegaPinFunc::USART0_CLK };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PDO, eATmegaPinFunc::USART0_TXD };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PDI, eATmegaPinFunc::USART0_RXD, eATmegaPinFunc::PCI8 };
+ return { funcs, countof(funcs) };
+ }
+ }
+ else if (info.port == eATmegaPort::PORT_F) {
+ if (info.pinidx == 7) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC7 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC6 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC5 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC4 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC3 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC2 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC1 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC0 };
+ return { funcs, countof(funcs) };
+ }
+ }
+ else if (info.port == eATmegaPort::PORT_G) {
+ if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC0B };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOSC1 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3 ) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOSC2 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_ALE };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_RD };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_WR };
+ return { funcs, countof(funcs) };
+ }
+ }
+ else if (info.port == eATmegaPort::PORT_H) {
+ if (info.pinidx == 7) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER4_CLKI };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC2B };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC4C };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC4B };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC4A };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART2_CLK };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART2_TXD };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART2_RXD };
+ return { funcs, countof(funcs) };
+ }
+ }
+ else if (info.port == eATmegaPort::PORT_J) {
+ if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI15 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI14 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI13 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI12 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART3_CLK, eATmegaPinFunc::PCI11 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART3_TXD, eATmegaPinFunc::PCI10 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART3_RXD, eATmegaPinFunc::PCI9 };
+ return { funcs, countof(funcs) };
+ }
+ }
+ else if (info.port == eATmegaPort::PORT_K) {
+ if (info.pinidx == 7) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC15, eATmegaPinFunc::PCI23 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC14, eATmegaPinFunc::PCI22 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC13, eATmegaPinFunc::PCI21 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC12, eATmegaPinFunc::PCI20 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC11, eATmegaPinFunc::PCI19 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC10, eATmegaPinFunc::PCI18 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC9, eATmegaPinFunc::PCI17 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC8, eATmegaPinFunc::PCI16 };
+ return { funcs, countof(funcs) };
+ }
+ }
+ else if (info.port == eATmegaPort::PORT_L) {
+ if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC5C };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC5B };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC5A };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER5_CLKI };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER5_ICP };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER4_ICP };
+ return { funcs, countof(funcs) };
+ }
+ }
+ #elif defined(__AVR_TRM02__)
+ if (info.port == eATmegaPort::PORT_A) {
+ if (info.pinidx == 7) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI7, eATmegaPinFunc::ADC7 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI6, eATmegaPinFunc::ADC6 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI5, eATmegaPinFunc::ADC5 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI4, eATmegaPinFunc::ADC4 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI3, eATmegaPinFunc::ADC3 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI2, eATmegaPinFunc::ADC2 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI1, eATmegaPinFunc::ADC1 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI0, eATmegaPinFunc::ADC0 };
+ return { funcs, countof(funcs) };
+ }
+ }
+ else if (info.port == eATmegaPort::PORT_B) {
+ if (info.pinidx == 7) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::TOC3B, eATmegaPinFunc::PCI15 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::TOC3A, eATmegaPinFunc::PCI14 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::TIMER3_ICP, eATmegaPinFunc::PCI13 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_CS, eATmegaPinFunc::TOC0B, eATmegaPinFunc::PCI12 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN1, eATmegaPinFunc::TOC0A, eATmegaPinFunc::PCI11 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN0, eATmegaPinFunc::EINT2, eATmegaPinFunc::PCI10 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ECI, eATmegaPinFunc::CLK0, eATmegaPinFunc::PCI9 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER0_ECI, eATmegaPinFunc::USART0_CLK, eATmegaPinFunc::PCI8 };
+ return { funcs, countof(funcs) };
+ }
+ }
+ else if (info.port == eATmegaPort::PORT_C) {
+ if (info.pinidx == 7) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOSC2, eATmegaPinFunc::PCI23 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOSC1, eATmegaPinFunc::PCI22 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI21 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI20 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI19 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI18 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI17, eATmegaPinFunc::TWI_SDA };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TWI_CLK, eATmegaPinFunc::PCI16 };
+ return { funcs, countof(funcs) };
+ }
+ }
+ else if (info.port == eATmegaPort::PORT_D) {
+ if (info.pinidx == 7) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC2A, eATmegaPinFunc::PCI31 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ICP, eATmegaPinFunc::TOC2B, eATmegaPinFunc::PCI30 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1A, eATmegaPinFunc::PCI29 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1B, eATmegaPinFunc::USART1_CLK, eATmegaPinFunc::PCI28 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT1, eATmegaPinFunc::USART1_TXD, eATmegaPinFunc::PCI27 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT0, eATmegaPinFunc::USART1_RXD, eATmegaPinFunc::PCI26 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART0_TXD, eATmegaPinFunc::PCI25 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART0_TXD, eATmegaPinFunc::PCI24, eATmegaPinFunc::TIMER3_ECI };
+ return { funcs, countof(funcs) };
+ }
+ }
+ #elif defined(__AVR_TRM03__)
+ if (info.port == eATmegaPort::PORT_B) {
+ if (info.pinidx == 7) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::XTAL2, eATmegaPinFunc::TOSC2, eATmegaPinFunc::PCI7 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::XTAL1, eATmegaPinFunc::TOSC1, eATmegaPinFunc::PCI6 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::PCI5 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::PCI4 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::TOC2A, eATmegaPinFunc::PCI3 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_CS, eATmegaPinFunc::TOC1B, eATmegaPinFunc::PCI2 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1A, eATmegaPinFunc::PCI1 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ICP, eATmegaPinFunc::CLK0, eATmegaPinFunc::PCI0 };
+ return { funcs, countof(funcs) };
+ }
+ }
+ else if (info.port == eATmegaPort::PORT_C) {
+ if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PCI14 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC5, eATmegaPinFunc::TWI_CLK, eATmegaPinFunc::PCI13 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC4, eATmegaPinFunc::TWI_SDA, eATmegaPinFunc::PCI12 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC3, eATmegaPinFunc::PCI11 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC2, eATmegaPinFunc::PCI10 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC1, eATmegaPinFunc::PCI9 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC0, eATmegaPinFunc::PCI8 };
+ return { funcs, countof(funcs) };
+ }
+ }
+ else if (info.port == eATmegaPort::PORT_D) {
+ if (info.pinidx == 7) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN1, eATmegaPinFunc::PCI23 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::AIN0, eATmegaPinFunc::TOC0A, eATmegaPinFunc::PCI22 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ECI, eATmegaPinFunc::TOC0B, eATmegaPinFunc::PCI21 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART_CLK, eATmegaPinFunc::TIMER0_ECI, eATmegaPinFunc::PCI20 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT1, eATmegaPinFunc::TOC2B, eATmegaPinFunc::PCI19 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT0, eATmegaPinFunc::PCI18 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART_TXD, eATmegaPinFunc::PCI17 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART_RXD, eATmegaPinFunc::PCI16 };
+ return { funcs, countof(funcs) };
+ }
+ }
+ #elif defined(__AVR_TRM04__)
+ if (info.port == eATmegaPort::PORT_A) {
+ if (info.pinidx == 7) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD7 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD6 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD5 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD4 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD3 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD2 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD1 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD0 };
+ return { funcs, countof(funcs) };
+ }
+ }
+ else if (info.port == eATmegaPort::PORT_B) {
+ if (info.pinidx == 7) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC0A, eATmegaPinFunc::TOC1C, eATmegaPinFunc::PCI7 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1B, eATmegaPinFunc::PCI6 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC1A, eATmegaPinFunc::PCI5 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TOC2A, eATmegaPinFunc::PCI4 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PDO, eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::PCI3 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::PDI, eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::PCI2 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::PCI1 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::SPI_CS, eATmegaPinFunc::PCI0 };
+ return { funcs, countof(funcs) };
+ }
+ }
+ else if (info.port == eATmegaPort::PORT_C) {
+ if (info.pinidx == 7) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD15, eATmegaPinFunc::TIMER3_ICP, eATmegaPinFunc::CLK0 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD14, eATmegaPinFunc::TOC3A };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD13, eATmegaPinFunc::TOC3B };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD12, eATmegaPinFunc::TOC3C };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD11, eATmegaPinFunc::TIMER3_CLKI };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD10 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD9 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_AD8 };
+ return { funcs, countof(funcs) };
+ }
+ }
+ else if (info.port == eATmegaPort::PORT_D) {
+ if (info.pinidx == 7) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER0_CLKI };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_CLKI };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::USART1_CLK };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::TIMER1_ICP };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT3, eATmegaPinFunc::USART1_TXD };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT2, eATmegaPinFunc::USART1_RXD };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT1, eATmegaPinFunc::TWI_SDA, eATmegaPinFunc::TOC2B };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT0, eATmegaPinFunc::TWI_CLK, eATmegaPinFunc::TOC0B };
+ return { funcs, countof(funcs) };
+ }
+ }
+ else if (info.port == eATmegaPort::PORT_E) {
+ if (info.pinidx == 7) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT7, eATmegaPinFunc::AIN1, eATmegaPinFunc::UVCON };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT6, eATmegaPinFunc::AIN0 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT5, eATmegaPinFunc::TOSC2 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EINT4, eATmegaPinFunc::TOSC2 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::UID };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_ALE };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_RD };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::EXTMEM_WR };
+ return { funcs, countof(funcs) };
+ }
+ }
+ else if (info.port == eATmegaPort::PORT_F) {
+ if (info.pinidx == 7) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC7 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 6) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC6 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 5) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC5 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 4) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC4 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 3) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC3 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 2) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC2 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 1) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC1 };
+ return { funcs, countof(funcs) };
+ }
+ else if (info.pinidx == 0) {
+ static const eATmegaPinFunc funcs[] = { eATmegaPinFunc::ADC0 };
+ return { funcs, countof(funcs) };
+ }
+ }
+ #endif
+
+ return ATmegaPinFunctions(); // default and empty.
+}
diff --git a/Marlin/src/HAL/AVR/registers.h b/Marlin/src/HAL/AVR/registers.h
new file mode 100644
index 000000000000..f9c3d98e6d04
--- /dev/null
+++ b/Marlin/src/HAL/AVR/registers.h
@@ -0,0 +1,4738 @@
+/**
+ * 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
+
+// This volatile-nonsense has to be done due to the C++ platform language specialization that specifies, for it's own compiler ideology,
+// that memory writes and reads can be optimized across easily-reachable code spaces. This is in contrast to MSVC which specifies that
+// memory writes and reads are holy.
+
+// OVERVIEW OF PREPROCESSOR DEFINITIONS:
+// __AVR_ATmega2560__
+// __AVR_ATmega1284P__
+// __AVR_ATmega1280__
+// __AVR_ATmega644__
+// __AVR_ATmega644P__
+// __AVR_ATmega2561__
+
+// Contributed by Martin Turski, company owner of EirDev, on the 29th of November, 2022
+// Contact E-Mail: turningtides@outlook.de
+// Created specifically for the Marlin FW for AVR backwards-compatibility.
+// Please expand this file with details of every supported AVR implementation.
+// 1) download the latest technical reference manual
+// 2) add the new technical reference manual below using a set of __AVR_*__ preprocessor definitions and a new __AVR_TRM*__ incrementing define
+// 3) check which of the existing AVR registers exist on the new implementation and enable them
+// 4) add any new register definitions
+// 5) add the register memory layout below the definitions
+// 6) extend the _ATmega_resetperipherals functions
+// 7) extend the _ATmega_savePinAlternate function
+// 8) copy the extension idea to _ATmega_restorePinAlternate and finish implementing it
+// You need to adjust the eATmegaPort enumeration aswell.
+
+#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ #error "Fatal error: __AVR_TRMn__ already defined! (n: 01|02|03|04)"
+#endif
+
+#if defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega640__)
+ // ATmega2560 technical reference manual date: 28th of November, 2022
+ // ATmega640-1280-1281-2560-2561-Datasheet-DS40002211A.pdf
+ #define __AVR_TRM01__
+#elif defined(__AVR_ATmega164A__) || defined(__AVR_ATmega164PA__) || defined(__AVR_ATmega324A__) || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega1284__) || defined(__AVT_ATmega1284P__)
+ // ATmega1284 technical reference manual date: 29th of November, 2022
+ // ATmega164A_PA-324A_PA-644A_PA-1284_P_Data-Sheet-40002070B.pdf
+ #define __AVR_TRM02__
+#elif defined(__AVR_ATmega48A__) || defined(__AVR_ATmega48PA__) || defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
+ // ATmega328 technical reference manual date: 29th of November, 2022
+ // ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061B.pdf
+ #define __AVR_TRM03__
+#elif defined(__AVR_AT90USB1287__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1286P__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB646P__) || defined(__AVR_AT90USB647__)
+ // AT90USB1287 technical reference manual ID: 7593D–AVR–07/06
+ // Preliminary.
+ #define __AVR_TRM04__
+#endif
+
+/**
+ * HELPER FUNCTIONS
+ */
+namespace AVRHelpers {
+
+ template
+ struct no_volatile {
+ typedef T type;
+ };
+
+ template
+ struct no_volatile : public no_volatile {};
+
+ template
+ inline void dwrite(volatile T& v, const T& V) noexcept {
+ if constexpr ( sizeof(T) == sizeof(uint8_t) ) {
+ (volatile uint8_t&)v = (const uint8_t&)V;
+ }
+ else if constexpr ( sizeof(T) == sizeof(uint16_t) ) {
+ (volatile uint16_t&)v = (const uint16_t&)V;
+ }
+ else if constexpr ( sizeof(T) == sizeof(uint32_t) ) {
+ (volatile uint32_t&)v = (const uint32_t&)V;
+ }
+ else {
+ v = V;
+ }
+ }
+
+} // namespace AVRHelpers
+
+// As old as the ATmega series of CPU is, the worse the actual libraries making
+// use of the MCU likely are.
+
+// These registers as references do not take program space since they are purely references.
+
+// It would be great if the old AVR definitions could be wasted in favor of these
+// and code be rewritten to use the following more robust definitions.
+
+struct _bit_reg_t {
+ uint8_t val;
+
+ bool getValue(uint8_t idx) const volatile {
+ return ( val & (1 << idx) );
+ }
+ void setValue(uint8_t idx, bool value) volatile {
+ if (value)
+ val |= (1 << idx);
+ else
+ val &= ~(1 << idx);
+ }
+};
+
+#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+
+ typedef _bit_reg_t PIN_reg_t;
+ typedef _bit_reg_t DDR_reg_t;
+ typedef _bit_reg_t PORT_reg_t;
+
+ struct PORT_dev_t {
+ PIN_reg_t _PIN;
+ DDR_reg_t _DDR;
+ PORT_reg_t _PORT;
+
+ inline void operator = ( const PORT_dev_t& r ) volatile {
+ using namespace AVRHelpers;
+ dwrite(this->_PIN, r._PIN);
+ dwrite(this->_DDR, r._DDR);
+ dwrite(this->_PORT, r._PORT);
+ }
+ };
+ static_assert(sizeof(PORT_dev_t) == 3, "invalid size of ATmega2560 GPIO_dev_t");
+
+#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM03__ || __AVR_TRM04__
+
+#ifdef __AVR_TRM01__
+
+ struct _bitG_reg_t {
+ uint8_t val : 6;
+ uint8_t reserved1 : 2;
+
+ bool getValue(uint8_t idx) const volatile {
+ return val & (1 << idx);
+ }
+ void setValue(uint8_t idx, bool value) volatile {
+ if (value)
+ val |= (1 << idx);
+ else
+ val &= ~(1 << idx);
+ }
+ };
+ typedef _bitG_reg_t PING_reg_t;
+ typedef _bitG_reg_t DDRG_reg_t;
+ typedef _bitG_reg_t PORTG_reg_t;
+
+ struct PORTG_dev_t {
+ PING_reg_t _PIN;
+ DDRG_reg_t _DDR;
+ PORTG_reg_t _PORT;
+
+ inline void operator = ( const PORTG_dev_t& r ) volatile {
+ using namespace AVRHelpers;
+ dwrite(this->_PIN, r._PIN);
+ dwrite(this->_DDR, r._DDR);
+ dwrite(this->_PORT, r._PORT);
+ }
+ };
+
+#endif
+
+#ifdef __AVR_TRM03__
+
+ struct _bitC_reg_t {
+ uint8_t val : 7;
+ uint8_t reserved1 : 1;
+
+ bool getValue(uint8_t idx) const volatile {
+ return ( val & (1 << idx) );
+ }
+ void setValue(uint8_t idx, bool value) volatile {
+ if (value)
+ val |= (1 << idx);
+ else
+ val &= ~(1 << idx);
+ }
+ };
+ typedef _bitC_reg_t PINC_reg_t;
+ typedef _bitC_reg_t DDRC_reg_t;
+ typedef _bitC_reg_t PORTC_reg_t;
+
+ struct PORTC_dev_t {
+ PINC_reg_t _PIN;
+ DDRC_reg_t _DDR;
+ PORTC_reg_t _PORT;
+
+ inline void operator = ( const PORTC_dev_t& r ) volatile {
+ this->_PIN = r._PIN;
+ this->_DDR = r._DDR;
+ this->_PORT = r._PORT;
+ }
+ };
+
+#endif
+
+#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+
+ struct TIFR0_reg_t {
+ uint8_t _TOV0 : 1;
+ uint8_t _OCF0A : 1;
+ uint8_t _OCF0B : 1;
+ uint8_t reserved1 : 5;
+ };
+ static_assert(sizeof(TIFR0_reg_t) == 1, "invalid size of ATmega2560 TIFR0_reg_t");
+
+ struct TIFR1_reg_t {
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ uint8_t _TOV1 : 1;
+ uint8_t _OCF1A : 1;
+ uint8_t _OCF1B : 1;
+ uint8_t _OCF1C : 1;
+ uint8_t reserved1 : 1;
+ uint8_t _ICF1 : 1;
+ uint8_t reserved2 : 2;
+ #elif defined(__AVR_TRM02__) || defined(__AVR_TRM03__)
+ uint8_t _TOV1 : 1;
+ uint8_t _OCF1A : 1;
+ uint8_t _OCF1B : 1;
+ uint8_t reserved1 : 2;
+ uint8_t _ICF1 : 1;
+ uint8_t reserved2 : 2;
+ #endif
+ };
+ static_assert(sizeof(TIFR1_reg_t) == 1, "invalid size of ATmega2560 TIFR1_reg_t");
+
+ struct TIFR2_reg_t {
+ uint8_t _TOV2 : 1;
+ uint8_t _OCF2A : 1;
+ uint8_t _OCF2B : 1;
+ uint8_t reserved1 : 5;
+ };
+ static_assert(sizeof(TIFR2_reg_t) == 1, "invalid size of ATmega2560 TIFR2_reg_t");
+
+#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM03__ || __AVR_TRM04__
+
+#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__)
+
+ struct TIFR3_reg_t {
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ uint8_t _TOV3 : 1;
+ uint8_t _OCF3A : 1;
+ uint8_t _OCF3B : 1;
+ uint8_t _OCF3C : 1;
+ uint8_t reserved1 : 1;
+ uint8_t _ICF3 : 1;
+ uint8_t reserved2 : 2;
+ #elif defined(__AVR_TRM02__)
+ uint8_t _TOV3 : 1;
+ uint8_t _OCF3A : 1;
+ uint8_t _OCF3B : 1;
+ uint8_t reserved1 : 2;
+ uint8_t _ICF3 : 1;
+ uint8_t reserved2 : 2;
+ #endif
+ };
+ static_assert(sizeof(TIFR3_reg_t) == 1, "invalid size of ATmega2560 TIFR3_reg_t");
+
+#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM04__
+
+#ifdef __AVR_TRM01__
+
+ struct TIFR4_reg_t {
+ uint8_t _TOV4 : 1;
+ uint8_t _OCF4A : 1;
+ uint8_t _OCF4B : 1;
+ uint8_t _OCF4C : 1;
+ uint8_t reserved1 : 1;
+ uint8_t _ICF4 : 1;
+ uint8_t reserved2 : 2;
+ };
+ static_assert(sizeof(TIFR4_reg_t) == 1, "invalid size of ATmega2560 TIFR4_reg_t");
+
+ struct TIFR5_reg_t {
+ uint8_t _TOV5 : 1;
+ uint8_t _OCF5A : 1;
+ uint8_t _OCF5B : 1;
+ uint8_t _OCF5C : 1;
+ uint8_t reserved1 : 1;
+ uint8_t _ICF5 : 1;
+ uint8_t reserved2 : 2;
+ };
+ static_assert(sizeof(TIFR5_reg_t) == 1, "invalid size of ATmega2560 TIFR5_reg_t");
+
+#endif // __AVR_TRM01__
+
+#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+
+ struct PCIFR_reg_t {
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM03__)
+ uint8_t _PCIF0 : 1;
+ uint8_t _PCIF1 : 1;
+ uint8_t _PCIF2 : 1;
+ uint8_t reserved1 : 5;
+ #elif defined(__AVR_TRM02__)
+ uint8_t _PCIF0 : 1;
+ uint8_t _PCIF1 : 1;
+ uint8_t _PCIF2 : 1;
+ uint8_t _PCIF3 : 1;
+ uint8_t reserved1 : 4;
+ #elif defined(__AVR_TRM04__)
+ uint8_t _PCIF0 : 1;
+ uint8_t reserved1 : 7;
+ #endif
+ };
+ static_assert(sizeof(PCIFR_reg_t) == 1, "invalid size of ATmega2560 PCIFR_reg_t");
+
+ struct EIFR_reg_t {
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ uint8_t _INTF0 : 1;
+ uint8_t _INTF1 : 1;
+ uint8_t _INTF2 : 1;
+ uint8_t _INTF3 : 1;
+ uint8_t _INTF4 : 1;
+ uint8_t _INTF5 : 1;
+ uint8_t _INTF6 : 1;
+ uint8_t _INTF7 : 1;
+ #elif defined(__AVR_TRM02__)
+ uint8_t _INTF0 : 1;
+ uint8_t _INTF1 : 1;
+ uint8_t _INTF2 : 1;
+ uint8_t reserved1 : 5;
+ #elif defined(__AVR_TRM03__)
+ uint8_t _INTF0 : 1;
+ uint8_t _INTF1 : 1;
+ uint8_t reserved1 : 6;
+ #endif
+ };
+ static_assert(sizeof(EIFR_reg_t) == 1, "invalid size of ATmega2560 EIFR_reg_t");
+
+ struct EIMSK_reg_t {
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ uint8_t _INT0 : 1;
+ uint8_t _INT1 : 1;
+ uint8_t _INT2 : 1;
+ uint8_t _INT3 : 1;
+ uint8_t _INT4 : 1;
+ uint8_t _INT5 : 1;
+ uint8_t _INT6 : 1;
+ uint8_t _INT7 : 1;
+ #elif defined(__AVR_TRM02__)
+ uint8_t _INT0 : 1;
+ uint8_t _INT1 : 1;
+ uint8_t _INT2 : 1;
+ uint8_t reserved1 : 5;
+ #elif defined(__AVR_TRM03__)
+ uint8_t _INT0 : 1;
+ uint8_t _INT1 : 1;
+ uint8_t reserved1 : 6;
+ #endif
+ };
+ static_assert(sizeof(EIMSK_reg_t) == 1, "invalid size of ATmega2560 EIMSK_reg_t");
+
+ struct EECR_reg_t {
+ uint8_t _EERE : 1;
+ uint8_t _EEPE : 1;
+ uint8_t _EEMPE : 1;
+ uint8_t _EERIE : 1;
+ uint8_t _EEPM0 : 1;
+ uint8_t _EEPM1 : 1;
+ uint8_t reserved1 : 2;
+ };
+ static_assert(sizeof(EECR_reg_t) == 1, "invalid size of ATmega2560 EECR_reg_t");
+
+ struct EEAR_reg_t {
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__)
+ uint16_t _EEAR : 12;
+ uint16_t reserved1 : 4;
+ #elif defined(__AVR_TRM03__)
+ #if defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega328P__)
+ uint16_t _EEAR : 16;
+ #else
+ uint8_t _EEAR : 8;
+ uint8_t reserved1 : 8;
+ #endif
+ #endif
+ };
+ static_assert(sizeof(EEAR_reg_t) == 2, "invalid size of ATmega2560 EEAR_reg_t");
+
+ struct GTCCR_reg_t {
+ uint8_t _PSRSYNC : 1;
+ uint8_t _PSRASY : 1;
+ uint8_t reserved1 : 5;
+ uint8_t _TSM : 1;
+ };
+ static_assert(sizeof(GTCCR_reg_t) == 1, "invalid size of ATmega2560 GTCCR_reg_t");
+
+ struct SPCR_reg_t {
+ uint8_t _SPR : 2;
+ uint8_t _CPHA : 1;
+ uint8_t _CPOL : 1;
+ uint8_t _MSTR : 1;
+ uint8_t _DORD : 1;
+ uint8_t _SPE : 1;
+ uint8_t _SPIE : 1;
+ };
+ static_assert(sizeof(SPCR_reg_t) == 1, "invalid size of ATmega2560 SPCR_reg_t");
+
+ struct SPSR_reg_t {
+ uint8_t _SPI2X : 1;
+ uint8_t reserved1 : 5;
+ uint8_t _WCOL : 1;
+ uint8_t _SPIF : 1;
+ };
+ static_assert(sizeof(SPSR_reg_t) == 1, "invalid size of ATmega2560 SPSR_reg_t");
+
+ struct ACSR_reg_t {
+ uint8_t _ACIS : 2;
+ uint8_t _ACIC : 1;
+ uint8_t _ACIE : 1;
+ uint8_t _ACI : 1;
+ uint8_t _ACO : 1;
+ uint8_t _ACBG : 1;
+ uint8_t _ACD : 1;
+ };
+ static_assert(sizeof(ACSR_reg_t) == 1, "invalid size of ATmega2560 ACSR_reg_t");
+
+ struct SMCR_reg_t {
+ uint8_t _SE : 1;
+ uint8_t _SM : 3;
+ uint8_t reserved1 : 4;
+ };
+ static_assert(sizeof(SMCR_reg_t) == 1, "invalid size of ATmega2560 SMCR_reg_t");
+
+ struct MCUSR_reg_t {
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__)
+ uint8_t _PORF : 1;
+ uint8_t _EXTRF : 1;
+ uint8_t _BORF : 1;
+ uint8_t _WDRF : 1;
+ uint8_t _JTRF : 1;
+ uint8_t reserved1 : 3;
+ #elif defined(__AVR_TRM03__)
+ uint8_t _PORF : 1;
+ uint8_t _EXTRF : 1;
+ uint8_t _BORF : 1;
+ uint8_t _WDRF : 1;
+ uint8_t reserved1 : 4;
+ #endif
+ };
+ static_assert(sizeof(MCUSR_reg_t) == 1, "invalid size of ATmega2560 MCUSR_reg_t");
+
+ struct MCUCR_reg_t {
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ uint8_t _IVCE : 1;
+ uint8_t _IVSEL : 1;
+ uint8_t reserved1 : 2;
+ uint8_t _PUD : 1;
+ uint8_t reserved2 : 2;
+ uint8_t _JTD : 1;
+ #elif defined(__AVR_TRM02__)
+ uint8_t _IVCE : 1;
+ uint8_t _IVSEL : 1;
+ uint8_t reserved1 : 2;
+ uint8_t _PUD : 1;
+ uint8_t _BODSE : 1;
+ uint8_t _BODS : 1;
+ uint8_t _JTD : 1;
+ #elif defined(__AVR_TRM03__)
+ uint8_t _IVCE : 1;
+ uint8_t _IVSEL : 1;
+ uint8_t reserved1 : 2;
+ uint8_t _PUD : 1;
+ uint8_t _BODSE : 1;
+ uint8_t _BODS : 1;
+ uint8_t reserved2 : 1;
+ #endif
+ };
+ static_assert(sizeof(MCUCR_reg_t) == 1, "invalid size of ATmega2560 MCUCR_reg_t");
+
+ struct SPMCSR_reg_t {
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__)
+ uint8_t _SPMEN : 1;
+ uint8_t _PGERS : 1;
+ uint8_t _PGWRT : 1;
+ uint8_t _BLBSET : 1;
+ uint8_t _RWWSRE : 1;
+ uint8_t _SIGRD : 1;
+ uint8_t _RWWSB : 1;
+ uint8_t _SPMIE : 1;
+ #elif defined(__AVR_TRM03__)
+ #if defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega328P__)
+ uint8_t _SPMEN : 1;
+ uint8_t _PGERS : 1;
+ uint8_t _PGWRT : 1;
+ uint8_t _BLBSET : 1;
+ uint8_t _RWWSRE : 1;
+ uint8_t _SIGRD : 1;
+ uint8_t _RWWSB : 1;
+ uint8_t _SPMIE : 1;
+ #else
+ uint8_t _SPMEN : 1;
+ uint8_t _PGERS : 1;
+ uint8_t _PGWRT : 1;
+ uint8_t _BLBSET : 1;
+ uint8_t reserved1 : 1;
+ uint8_t _SIGRD : 1;
+ uint8_t reserved2 : 1;
+ uint8_t _SPMIE : 1;
+ #endif
+ #endif
+ };
+ static_assert(sizeof(SPMCSR_reg_t) == 1, "invalid size of ATmega2560 SPMCSR_reg_t");
+
+#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM03__ || __AVR_TRM04__
+
+#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__)
+
+ struct RAMPZ_reg_t {
+ uint8_t _RAMPZ : 2;
+ uint8_t reserved1 : 6;
+ };
+ static_assert(sizeof(RAMPZ_reg_t) == 1, "invalid size of ATmega2560 RAMPZ_reg_t");
+
+#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM04__
+
+#ifdef __AVR_TRM01__
+
+ struct EIND_reg_t {
+ uint8_t _EIND0 : 1;
+ uint8_t reserved1 : 7;
+ };
+ static_assert(sizeof(EIND_reg_t) == 1, "invalid size of ATmega2560 EIND_reg_t");
+
+#endif // __AVR_TRM01__
+
+#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+
+ struct SP_reg_t {
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__)
+ uint16_t _SP;
+ #elif defined(__AVR_TRM03__)
+ #if defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega328P__)
+ uint16_t _SP : 11;
+ uint16_t reserved1 : 5;
+ #else
+ uint16_t _SP : 10;
+ uint16_t reserved1 : 6;
+ #endif
+ #endif
+ };
+ static_assert(sizeof(SP_reg_t) == 2, "invalid size of ATmega2560 SP_reg_t");
+
+ struct SREG_reg_t {
+ uint8_t _C : 1;
+ uint8_t _Z : 1;
+ uint8_t _N : 1;
+ uint8_t _V : 1;
+ uint8_t _S : 1;
+ uint8_t _H : 1;
+ uint8_t _T : 1;
+ uint8_t _I : 1;
+ };
+ static_assert(sizeof(SREG_reg_t) == 1, "invalid size of ATmega2560 SREG_reg_t");
+
+ struct WDTCSR_reg_t {
+ uint8_t _WDP0 : 1;
+ uint8_t _WDP1 : 1;
+ uint8_t _WDP2 : 1;
+ uint8_t _WDE : 1;
+ uint8_t _WDCE : 1;
+ uint8_t _WDP3 : 1;
+ uint8_t _WDIE : 1;
+ uint8_t _WDIF : 1;
+ };
+ static_assert(sizeof(WDTCSR_reg_t) == 1, "invalid size of ATmega2560 WDTCSR_reg_t");
+
+ struct CLKPR_reg_t {
+ uint8_t _CLKPS : 4;
+ uint8_t reserved1 : 3;
+ uint8_t _CLKPCE : 1;
+ };
+ static_assert(sizeof(CLKPR_reg_t) == 1, "invalid size of ATmega2560 CLKPR_reg_t");
+
+ struct PRR0_reg_t {
+ #ifdef __AVR_TRM01__
+ uint8_t _PRADC : 1;
+ uint8_t _PRUSART0 : 1;
+ uint8_t _PRSPI : 1;
+ uint8_t _PRTIM1 : 1;
+ uint8_t reserved1 : 1;
+ uint8_t _PRTIM0 : 1;
+ uint8_t _PRTIM2 : 1;
+ uint8_t _PRTWI : 1;
+ #elif defined(__AVR_TRM02__)
+ uint8_t _PRADC : 1;
+ uint8_t _PRUSART0 : 1;
+ uint8_t _PRSPI : 1;
+ uint8_t _PRTIM1 : 1;
+ uint8_t _PRUSART1 : 1;
+ uint8_t _PRTIM0 : 1;
+ uint8_t _PRTIM2 : 1;
+ uint8_t _PRTWI : 1;
+ #elif defined(__AVR_TRM03__)
+ uint8_t _PRADC : 1;
+ uint8_t _PRUSART0 : 1;
+ uint8_t _PRSPI : 1;
+ uint8_t _PRTIM1 : 1;
+ uint8_t reserved1 : 1;
+ uint8_t _PRTIM0 : 1;
+ uint8_t _PRTIM2 : 1;
+ uint8_t _PRTWI : 1;
+ #elif defined(__AVR_TRM04__)
+ uint8_t _PRADC : 1;
+ uint8_t reserved1 : 1;
+ uint8_t _PRSPI : 1;
+ uint8_t _PRTIM1 : 1;
+ uint8_t reserved2 : 1;
+ uint8_t _PRTIM0 : 1;
+ uint8_t _PRTIM2 : 1;
+ uint8_t _PRTWI : 1;
+ #endif
+ };
+ static_assert(sizeof(PRR0_reg_t) == 1, "invalid size of ATmega2560 PRR0_reg_t");
+
+#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM03__ || __AVR_TRM04__
+
+#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__)
+
+ struct PRR1_reg_t {
+ #ifdef __AVR_TRM01__
+ uint8_t _PRUSART1 : 1;
+ uint8_t _PRUSART2 : 1;
+ uint8_t _PRUSART3 : 1;
+ uint8_t _PRTIM3 : 1;
+ uint8_t _PRTIM4 : 1;
+ uint8_t _PRTIM5 : 1;
+ uint8_t reserved1 : 2;
+ #elif defined(__AVR_TRM02__)
+ uint8_t _PRTIM3 : 1;
+ uint8_t reserved1 : 7;
+ #elif defined(__AVR_TRM04__)
+ uint8_t _PRUSART1 : 1;
+ uint8_t reserved1 : 2;
+ uint8_t _PRTIM3 : 1;
+ uint8_t reserved2 : 3;
+ uint8_t _PRUSB : 1;
+ #endif
+ };
+ static_assert(sizeof(PRR1_reg_t) == 1, "invalid size of ATmega2560 PRR1_reg_t");
+
+#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM04__
+
+#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+
+ struct PCICR_reg_t {
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM03__)
+ uint8_t _PCIE0 : 1;
+ uint8_t _PCIE1 : 1;
+ uint8_t _PCIE2 : 1;
+ uint8_t reserved1 : 5;
+ #elif defined(__AVR_TRM02__)
+ uint8_t _PCIE0 : 1;
+ uint8_t _PCIE1 : 1;
+ uint8_t _PCIE2 : 1;
+ uint8_t _PCIE3 : 1;
+ uint8_t reserved1 : 4;
+ #elif defined(__AVR_TRM04__)
+ uint8_t _PCIE0 : 1;
+ uint8_t reserved1 : 7;
+ #endif
+ };
+ static_assert(sizeof(PCICR_reg_t) == 1, "invalid size of ATmega2560 PCICR_reg_t");
+
+ struct EICRA_reg_t {
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ uint8_t _ISC0 : 2;
+ uint8_t _ISC1 : 2;
+ uint8_t _ISC2 : 2;
+ uint8_t _ISC3 : 2;
+ #elif defined(__AVR_TRM02__)
+ uint8_t _ISC0 : 2;
+ uint8_t _ISC1 : 2;
+ uint8_t _ISC2 : 2;
+ uint8_t reserved1 : 2;
+ #elif defined(__AVR_TRM03__)
+ uint8_t _ISC0 : 2;
+ uint8_t _ISC1 : 2;
+ uint8_t reserved1 : 4;
+ #endif
+ };
+ static_assert(sizeof(EICRA_reg_t) == 1, "invalid size of ATmega2560 EICRA_reg_t");
+
+#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM03__ || __AVR_TRM04__
+
+#if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+
+ struct EICRB_reg_t {
+ uint8_t _ISC4 : 2;
+ uint8_t _ISC5 : 2;
+ uint8_t _ISC6 : 2;
+ uint8_t _ISC7 : 2;
+ };
+ static_assert(sizeof(EICRB_reg_t) == 1, "invalid size of ATmega2560 EICRB_reg_t");
+
+#endif // __AVR_TRM01__ || __AVR_TRM04__
+
+#if defined(__AVR_TRM03__)
+
+ struct _bitPCMSK1_reg_t {
+ uint8_t val : 7;
+ uint8_t reserved1 : 1;
+
+ bool getValue(uint8_t idx) { return val & (1 << idx); }
+ void setValue(uint8_t idx, bool value) {
+ if (value)
+ val |= (1 << idx);
+ else
+ val &= ~(1 << idx);
+ }
+ };
+
+#endif // __AVR_TRM03__
+
+#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+
+ struct TIMSK0_reg_t {
+ #ifdef __AVR_TRM01__
+ uint8_t _TOIE0 : 1;
+ uint8_t _OCIE0A : 1;
+ uint8_t _OCIE0B : 1;
+ uint8_t _OCIE0C : 1;
+ uint8_t reserved1 : 1;
+ uint8_t _ICIE0 : 1;
+ uint8_t reserved2 : 2;
+ #elif defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ uint8_t _TOIE0 : 1;
+ uint8_t _OCIE0A : 1;
+ uint8_t _OCIE0B : 1;
+ uint8_t reserved1 : 5;
+ #endif
+ };
+ static_assert(sizeof(TIMSK0_reg_t) == 1, "invalid size of ATmega2560 TIMSK0_reg_t");
+
+ struct TIMSK1_reg_t {
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ uint8_t _TOIE1 : 1;
+ uint8_t _OCIE1A : 1;
+ uint8_t _OCIE1B : 1;
+ uint8_t _OCIE1C : 1;
+ uint8_t reserved1 : 1;
+ uint8_t _ICIE1: 1;
+ uint8_t reserved2 : 2;
+ #elif defined(__AVR_TRM02__) || defined(__AVR_TRM03__)
+ uint8_t _TOIE1 : 1;
+ uint8_t _OCIE1A : 1;
+ uint8_t _OCIE1B : 1;
+ uint8_t reserved1 : 2;
+ uint8_t _ICIE1: 1;
+ uint8_t reserved2 : 2;
+ #endif
+ };
+ static_assert(sizeof(TIMSK1_reg_t) == 1, "invalid size of ATmega2560 TIMSK1_reg_t");
+
+ struct TIMSK2_reg_t {
+ uint8_t _TOIE2 : 1;
+ uint8_t _OCIE2A : 1;
+ uint8_t _OCIE2B : 1;
+ uint8_t reserved1 : 5;
+ };
+ static_assert(sizeof(TIMSK2_reg_t) == 1, "invalid size of ATmega2560 TIMSK2_reg_t");
+
+#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM03__ || __AVR_TRM04__
+
+#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__)
+
+ struct TIMSK3_reg_t {
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ uint8_t _TOIE3 : 1;
+ uint8_t _OCIE3A : 1;
+ uint8_t _OCIE3B : 1;
+ uint8_t _OCIE3C : 1;
+ uint8_t reserved1 : 1;
+ uint8_t _ICIE3 : 1;
+ uint8_t reserved2 : 2;
+ #elif defined(__AVR_TRM02__)
+ uint8_t _TOIE3 : 1;
+ uint8_t _OCIE3A : 1;
+ uint8_t _OCIE3B : 1;
+ uint8_t reserved1 : 2;
+ uint8_t _ICIE3 : 1;
+ uint8_t reserved2 : 2;
+ #endif
+ };
+ static_assert(sizeof(TIMSK3_reg_t) == 1, "invalid size of ATmega2560 TIMSK3_reg_t");
+
+#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM04__
+
+#ifdef __AVR_TRM01__
+
+ struct TIMSK4_reg_t {
+ uint8_t _TOIE4 : 1;
+ uint8_t _OCIE4A : 1;
+ uint8_t _OCIE4B : 1;
+ uint8_t _OCIE4C : 1;
+ uint8_t reserved1 : 1;
+ uint8_t _ICIE4 : 1;
+ uint8_t reserved2 : 2;
+ };
+ static_assert(sizeof(TIMSK4_reg_t) == 1, "invalid size of ATmega2560 TIMSK4_reg_t");
+
+ struct TIMSK5_reg_t {
+ uint8_t _TOIE5 : 1;
+ uint8_t _OCIE5A : 1;
+ uint8_t _OCIE5B : 1;
+ uint8_t _OCIE5C : 1;
+ uint8_t reserved1 : 1;
+ uint8_t _ICIE5 : 1;
+ uint8_t reserved2 : 2;
+ };
+ static_assert(sizeof(TIMSK5_reg_t) == 1, "invalid size of ATmega2560 TIMSK5_reg_t");
+
+#endif // __AVR_TRM01__
+
+#if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+
+ struct XMCRA_reg_t {
+ uint8_t _SRW0 : 2;
+ uint8_t _SRW1 : 2;
+ uint8_t _SRL : 3;
+ uint8_t _SRE : 1;
+ };
+ static_assert(sizeof(XMCRA_reg_t) == 1, "invalid size of ATmega2560 XMCRA_reg_t");
+
+ struct XMCRB_reg_t {
+ uint8_t _XMM : 3;
+ uint8_t reserved1 : 4;
+ uint8_t _XMBK : 1;
+ };
+ static_assert(sizeof(XMCRB_reg_t) == 1, "invalid size of ATmega2560 XMCRB_reg_t");
+
+#endif // __AVR_TRM01__ || __AVR_TRM04__
+
+#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+
+ struct ADCSRA_reg_t {
+ uint8_t _ADPS : 3;
+ uint8_t _ADIE : 1;
+ uint8_t _ADIF : 1;
+ uint8_t _ADATE : 1;
+ uint8_t _ADSC : 1;
+ uint8_t _ADEN : 1;
+ };
+ static_assert(sizeof(ADCSRA_reg_t) == 1, "invalid size of ATmega2560 ADCSRA_reg_t");
+
+ struct ADCSRB_reg_t {
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ uint8_t _ADTS : 3;
+ uint8_t _MUX5 : 1;
+ uint8_t reserved1 : 2;
+ uint8_t _ACME : 1;
+ uint8_t reserved2 : 1;
+ #elif defined(__AVR_TRM02__) || defined(__AVR_TRM03__)
+ uint8_t _ADTS : 3;
+ uint8_t reserved1 : 3;
+ uint8_t _ACME : 1;
+ uint8_t reserved2 : 1;
+ #endif
+ };
+ static_assert(sizeof(ADCSRB_reg_t) == 1, "invalid size of ATmega2560 ADCSRB_reg_t");
+
+ struct ADMUX_reg_t {
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__)
+ uint8_t _MUX0 : 1;
+ uint8_t _MUX1 : 1;
+ uint8_t _MUX2 : 1;
+ uint8_t _MUX3 : 1;
+ uint8_t _MUX4 : 1;
+ uint8_t _ADLAR : 1;
+ uint8_t _REFS0 : 1;
+ uint8_t _REFS1 : 1;
+ #elif defined(__AVR_TRM03__)
+ uint8_t _MUX0 : 1;
+ uint8_t _MUX1 : 1;
+ uint8_t _MUX2 : 1;
+ uint8_t _MUX3 : 1;
+ uint8_t reserved1 : 1;
+ uint8_t _ADLAR : 1;
+ uint8_t _REFS0 : 1;
+ uint8_t _REFS1 : 1;
+ #endif
+ };
+ static_assert(sizeof(ADMUX_reg_t) == 1, "invalid size of ATmega2560 ADMUX_reg_t");
+
+#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM03__ || __AVR_TRM04__
+
+#ifdef __AVR_TRM01__
+
+ struct DIDR2_reg_t {
+ uint8_t _ADC8D : 1;
+ uint8_t _ADC9D : 1;
+ uint8_t _ADC10D : 1;
+ uint8_t _ADC11D : 1;
+ uint8_t _ADC12D : 1;
+ uint8_t _ADC13D : 1;
+ uint8_t _ADC14D : 1;
+ uint8_t _ADC15D : 1;
+ };
+ static_assert(sizeof(DIDR2_reg_t) == 1, "invalid size of ATmega2560 DIDR2_reg_t");
+
+#endif // __AVR_TRM01__
+
+#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+
+ struct DIDR0_reg_t {
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__)
+ uint8_t _ADC0D : 1;
+ uint8_t _ADC1D : 1;
+ uint8_t _ADC2D : 1;
+ uint8_t _ADC3D : 1;
+ uint8_t _ADC4D : 1;
+ uint8_t _ADC5D : 1;
+ uint8_t _ADC6D : 1;
+ uint8_t _ADC7D : 1;
+ #elif defined(__AVR_TRM03__)
+ uint8_t _ADC0D : 1;
+ uint8_t _ADC1D : 1;
+ uint8_t _ADC2D : 1;
+ uint8_t _ADC3D : 1;
+ uint8_t _ADC4D : 1;
+ uint8_t _ADC5D : 1;
+ uint8_t reserved1 : 2;
+ #endif
+ };
+ static_assert(sizeof(DIDR0_reg_t) == 1, "invalid size of ATmega2560 DIDR0_reg_t");
+
+ struct DIDR1_reg_t {
+ uint8_t _AIN0D : 1;
+ uint8_t _AIN1D : 1;
+ uint8_t reserved1 : 6;
+ };
+ static_assert(sizeof(DIDR1_reg_t) == 1, "invalid size of ATmega2560 DIDR1_reg_t");
+
+ struct TCCRnA_reg_t {
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ uint8_t _WGMn0 : 1;
+ uint8_t _WGMn1 : 1;
+ uint8_t _COMnC : 2;
+ uint8_t _COMnB : 2;
+ uint8_t _COMnA : 2;
+ #elif defined(__AVR_TRM02__) || defined(__AVR_TRM03__)
+ uint8_t _WGMn0 : 1;
+ uint8_t _WGMn1 : 1;
+ uint8_t reserved1 : 2;
+ uint8_t _COMnB : 2;
+ uint8_t _COMnA : 2;
+ #endif
+ };
+ static_assert(sizeof(TCCRnA_reg_t) == 1, "invalid size of ATmega2560 TCCRnA_reg_t");
+
+ struct TCCRnB_reg_t {
+ uint8_t _CSn : 3;
+ uint8_t _WGMn2 : 1;
+ uint8_t _WGMn3 : 1;
+ uint8_t reserved1 : 1;
+ uint8_t _ICESn : 1;
+ uint8_t _ICNCn : 1;
+ };
+ static_assert(sizeof(TCCRnB_reg_t) == 1, "invalid size of ATmega2560 TCCRnB_reg_t");
+
+ struct TCCRnC_reg_t {
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ uint8_t reserved1 : 5;
+ uint8_t _FOCnC : 1;
+ uint8_t _FOCnB : 1;
+ uint8_t _FOCnA : 1;
+ #elif defined(__AVR_TRM02__) || defined(__AVR_TRM03__)
+ uint8_t reserved1 : 6;
+ uint8_t _FOCnB : 1;
+ uint8_t _FOCnA : 1;
+ #endif
+ };
+ static_assert(sizeof(TCCRnC_reg_t) == 1, "invalid size of ATmega2560 TCCRnC_reg_t");
+
+ struct TIMER_dev_t {
+ TCCRnA_reg_t _TCCRnA;
+ TCCRnB_reg_t _TCCRnB;
+ TCCRnC_reg_t _TCCRnC;
+ uint8_t reserved1;
+ uint16_t _TCNTn;
+ uint16_t _ICRn;
+ uint16_t _OCRnA;
+ uint16_t _OCRnB;
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ uint16_t _OCRnC;
+ #endif
+
+ inline void operator = ( const TIMER_dev_t& r ) volatile {
+ using namespace AVRHelpers;
+ dwrite(this->_TCCRnA, r._TCCRnA);
+ dwrite(this->_TCCRnB, r._TCCRnB);
+ dwrite(this->_TCCRnC, r._TCCRnC);
+ this->reserved1 = r.reserved1;
+ this->_TCNTn = r._TCNTn;
+ this->_ICRn = r._ICRn;
+ this->_OCRnA = r._OCRnA;
+ this->_OCRnB = r._OCRnB;
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ this->_OCRnC = r._OCRnC;
+ #endif
+ }
+ };
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ static_assert(sizeof(TIMER_dev_t) == 14, "invalid size of ATmega2560 TIMER_dev_t");
+ #elif defined(__AVR_TRM02__) || defined(__AVR_TRM03__)
+ static_assert(sizeof(TIMER_dev_t) == 12, "invalid size of ATmega1284 TIMER_dev_t");
+ #endif
+
+ struct TCCRnA_8bit_reg_t {
+ uint8_t _WGMn0 : 1;
+ uint8_t _WGMn1 : 1;
+ uint8_t reserved1 : 2;
+ uint8_t _COMnB : 2;
+ uint8_t _COMnA : 2;
+ };
+ static_assert(sizeof(TCCRnA_8bit_reg_t) == 1, "invalid size of ATmega2560 TCCRnA_8bit_reg_t");
+
+ struct TCCRnB_8bit_reg_t {
+ uint8_t _CSn : 3;
+ uint8_t _WGMn2 : 1;
+ uint8_t reserved1 : 2;
+ uint8_t _FOCnB : 1;
+ uint8_t _FOCnA : 1;
+ };
+ static_assert(sizeof(TCCRnB_8bit_reg_t) == 1, "invalid size of ATmega2560 TCCRnB_8bit_reg_t");
+
+ struct TIMER_8bit_dev_t {
+ TCCRnA_8bit_reg_t _TCCRnA;
+ TCCRnB_8bit_reg_t _TCCRnB;
+ uint8_t _TCNTn;
+ uint8_t _OCRnA;
+ uint8_t _OCRnB;
+
+ inline void operator = ( const TIMER_8bit_dev_t& r ) volatile {
+ using namespace AVRHelpers;
+ dwrite(this->_TCCRnA, r._TCCRnA);
+ dwrite(this->_TCCRnB, r._TCCRnB);
+ this->_TCNTn = r._TCNTn;
+ this->_OCRnA = r._OCRnA;
+ this->_OCRnB = r._OCRnB;
+ }
+ };
+ static_assert(sizeof(TIMER_8bit_dev_t) == 5, "invalid size of ATmega2560 TIMER_8bit_dev_t");
+
+ struct ASSR_reg_t {
+ uint8_t _TCR2BUB : 1;
+ uint8_t _TCR2AUB : 1;
+ uint8_t _OCR2BUB : 1;
+ uint8_t _OCR2AUB : 1;
+ uint8_t _TCN2UB : 1;
+ uint8_t _AS2 : 1;
+ uint8_t _EXCLK : 1;
+ uint8_t reserved1 : 1;
+ };
+ static_assert(sizeof(ASSR_reg_t) == 1, "invalid size of ATmega2560 ASSR_reg_t");
+
+ struct TWSR_reg_t {
+ uint8_t _TWPS0 : 1;
+ uint8_t _TWPS1 : 1;
+ uint8_t reserved1 : 1;
+ uint8_t _TWS3 : 1;
+ uint8_t _TWS4 : 1;
+ uint8_t _TWS5 : 1;
+ uint8_t _TWS6 : 1;
+ uint8_t _TWS7 : 1;
+ };
+ static_assert(sizeof(TWSR_reg_t) == 1, "invalid size of ATmega2560 TWSR_reg_t");
+
+ struct TWAR_reg_t {
+ uint8_t _TWGCE : 1;
+ uint8_t _TWA : 7;
+ };
+ static_assert(sizeof(TWAR_reg_t) == 1, "invalid size of ATmega2560 TWAR_reg_t");
+
+ struct TWCR_reg_t {
+ uint8_t _TWIE : 1;
+ uint8_t reserved1 : 1;
+ uint8_t _TWEN : 1;
+ uint8_t _TWWC : 1;
+ uint8_t _TWSTO : 1;
+ uint8_t _TWSTA : 1;
+ uint8_t _TWEA : 1;
+ uint8_t _TWINT : 1;
+ };
+ static_assert(sizeof(TWCR_reg_t) == 1, "invalid size of ATmega2560 TWCR_reg_t");
+
+ struct TWAMR_reg_t {
+ uint8_t reserved1 : 1;
+ uint8_t _TWAM : 7;
+ };
+ static_assert(sizeof(TWAMR_reg_t) == 1, "invalid size of ATmega2560 TWAMR_reg_t");
+
+ struct UBRRn_reg_t {
+ uint16_t _UBRR : 12;
+ uint16_t reserved1 : 4;
+ };
+ static_assert(sizeof(UBRRn_reg_t) == 2, "invalid size of ATmega2560 UBRRn_reg_t)");
+
+ struct UCSRnC_reg_t {
+ uint8_t _UCPOL : 1;
+ uint8_t _UCSZn0 : 1;
+ uint8_t _UCSZn1 : 1;
+ uint8_t _USBS : 1;
+ uint8_t _UPM : 2;
+ uint8_t _UMSEL : 2;
+ };
+ static_assert(sizeof(UCSRnC_reg_t) == 1, "invalid size of ATmega2560 UCSRnC_reg_t");
+
+ struct UCSRnB_reg_t {
+ uint8_t _TXB8 : 1;
+ uint8_t _RXB8 : 1;
+ uint8_t _UCSZn2 : 1;
+ uint8_t _TXEN : 1;
+ uint8_t _RXEN : 1;
+ uint8_t _UDRIE : 1;
+ uint8_t _TXCIE : 1;
+ uint8_t _RXCIE : 1;
+ };
+ static_assert(sizeof(UCSRnB_reg_t) == 1, "invalid size of ATmega2560 UCSRnB_reg_t");
+
+ struct UCSRnA_reg_t {
+ uint8_t _MPCM : 1;
+ uint8_t _U2X : 1;
+ uint8_t _UPE : 1;
+ uint8_t _DOR : 1;
+ uint8_t _FE : 1;
+ uint8_t _UDRE : 1;
+ uint8_t _TXC : 1;
+ uint8_t _RXC : 1;
+ };
+ static_assert(sizeof(UCSRnA_reg_t) == 1, "invalid size of ATmega2560 UCSRnA_reg_t");
+
+ struct USART_dev_t {
+ UCSRnA_reg_t _UCSRnA;
+ UCSRnB_reg_t _UCSRnB;
+ UCSRnC_reg_t _UCSRnC;
+ uint8_t reserved1;
+ UBRRn_reg_t _UBRRn;
+ uint8_t _UDRn;
+
+ inline void operator = ( const USART_dev_t& r ) volatile {
+ using namespace AVRHelpers;
+ dwrite(this->_UCSRnA, r._UCSRnA);
+ dwrite(this->_UCSRnB, r._UCSRnB);
+ dwrite(this->_UCSRnC, r._UCSRnC);
+ dwrite(this->reserved1, r.reserved1);
+ dwrite(this->_UBRRn, r._UBRRn);
+ dwrite(this->_UDRn, r._UDRn);
+ }
+ };
+ static_assert(sizeof(USART_dev_t) == 7, "invalid size of ATmega2560 USART_dev_t");
+
+#endif // __AVR_TRM01__ || __AVR_TRM02__ || __AVR_TRM03__ || __AVR_TRM04__
+
+#ifdef __AVR_TRM04__
+
+ struct UHCON_reg_t {
+ uint8_t _SOFEN : 1;
+ uint8_t _RESET : 1;
+ uint8_t _RESUME : 1;
+ uint8_t reserved1 : 5;
+ };
+ static_assert(sizeof(UHCON_reg_t) == 1, "invalid size of ATUSB90 UHCON_reg_t");
+
+ struct UHINT_reg_t {
+ uint8_t _DCONNI : 1;
+ uint8_t _DDISCI : 1;
+ uint8_t _RSTI : 1;
+ uint8_t _RSMEDI : 1;
+ uint8_t _RXRSMI : 1;
+ uint8_t _HSOFI : 1;
+ uint8_t _HWUPI : 1;
+ uint8_t reserved1 : 1;
+ };
+ static_assert(sizeof(UHINT_reg_t) == 1, "invalid size of ATUSB90 UHINT_reg_t");
+
+ struct UHIEN_reg_t {
+ uint8_t _SUSPE : 1;
+ uint8_t _MSOFE : 1;
+ uint8_t _SOFE : 1;
+ uint8_t _EORSTE : 1;
+ uint8_t _WAKEUPE : 1;
+ uint8_t _EORSME : 1;
+ uint8_t _UPRSME : 1;
+ uint8_t reserved1 : 1;
+ };
+ static_assert(sizeof(UHIEN_reg_t) == 1, "invalid size of ATUSB90 UHIEN_reg_t");
+
+ struct UHADDR_reg_t {
+ uint8_t _HADD : 7;
+ uint8_t reserved1 : 1;
+ };
+ static_assert(sizeof(UHADDR_reg_t) == 1, "invalid size of ATUSB90 UHADDR_reg_t");
+
+ struct UHFNUM_reg_t {
+ uint16_t _FNUM : 11;
+ uint16_t reserved1 : 5;
+ };
+ static_assert(sizeof(UHFNUM_reg_t) == 2, "invalid size of ATUSB90 UHFNUM_reg_t");
+
+ struct UPINTX_reg_t {
+ uint8_t _RXINI : 1;
+ uint8_t _RXSTALLI : 1;
+ uint8_t _TXOUTI : 1;
+ uint8_t _TXSTPI : 1;
+ uint8_t _PERRI : 1;
+ uint8_t _RWAL : 1;
+ uint8_t _NAKEDI : 1;
+ uint8_t _FIFOCON : 1;
+ };
+ static_assert(sizeof(UPINTX_reg_t) == 1, "invalid size of ATUSB90 UPINTX_reg_t");
+
+ struct UPNUM_reg_t {
+ uint8_t _PNUM : 3;
+ uint8_t reserved1 : 5;
+ };
+ static_assert(sizeof(UPNUM_reg_t) == 1, "invalid size of ATUSB90 UPNUM_reg_t");
+
+ struct UPRST_reg_t {
+ uint8_t _PRST : 7;
+ uint8_t reserved1 : 1;
+ };
+ static_assert(sizeof(UPRST_reg_t) == 1, "invalid size of ATUSB90 UPRST_reg_t");
+
+ struct UPCONX_reg_t {
+ uint8_t _PEN : 1;
+ uint8_t reserved1 : 2;
+ uint8_t _RSTDT : 1;
+ uint8_t _AUTOSW : 1;
+ uint8_t _INMODE : 1;
+ uint8_t _PFREEZE : 1;
+ uint8_t reserved2 : 1;
+ };
+ static_assert(sizeof(UPCONX_reg_t) == 1, "invalid size of ATUSB90 UPCONX_reg_t");
+
+ struct UPCFG0X_reg_t {
+ uint8_t _PEPNUM : 4;
+ uint8_t _PTOKEN : 2;
+ uint8_t _PTYPE : 2;
+ };
+ static_assert(sizeof(UPCFG0X_reg_t) == 1, "invalid size of ATUSB90 UPCFG0_reg_t");
+
+ struct UPCFG1X_reg_t {
+ uint8_t reserved1 : 1;
+ uint8_t _ALLOC : 1;
+ uint8_t _PBK : 2;
+ uint8_t _PSIZE : 3;
+ uint8_t reserved2 : 1;
+ };
+ static_assert(sizeof(UPCFG1X_reg_t) == 1, "invalid size of ATUSB90 UPCFG1X_reg_t");
+
+ struct UPSTAX_reg_t {
+ uint8_t _NBUSYBK : 2;
+ uint8_t _DTSEQ : 2;
+ uint8_t reserved1 : 1;
+ uint8_t _UNDERFI : 1;
+ uint8_t _OVERFI : 1;
+ uint8_t _CFGOK : 1;
+ };
+ static_assert(sizeof(UPSTAX_reg_t) == 1, "invalid size of ATUSB90 UPSTAX_reg_t");
+
+ struct UPIENX_reg_t {
+ uint8_t _RXINE : 1;
+ uint8_t _RXSTALLE : 1;
+ uint8_t _TXOUTE : 1;
+ uint8_t _TXSTPE : 1;
+ uint8_t _PERRE : 1;
+ uint8_t reserved1 : 1;
+ uint8_t _NAKEDE : 1;
+ uint8_t _FLERRE : 1;
+ };
+ static_assert(sizeof(UPIENX_reg_t) == 1, "invalid size of ATUSB90 UPIENX_reg_t");
+
+ struct UHWCON_reg_t {
+ uint8_t _UVREGE : 1;
+ uint8_t reserved1 : 3;
+ uint8_t _UVCONE : 1;
+ uint8_t reserved2 : 1;
+ uint8_t _UIDE : 1;
+ uint8_t _UIMOD : 1;
+ };
+ static_assert(sizeof(UHWCON_reg_t) == 1, "invalid size of ATUSB90 UHWCON_reg_t");
+
+ struct USBCON_reg_t {
+ uint8_t _VBUSTE : 1;
+ uint8_t _IDTE : 1;
+ uint8_t reserved1 : 2;
+ uint8_t _OTGPADE : 1;
+ uint8_t _FRZCLK : 1;
+ uint8_t _HOST : 1;
+ uint8_t _USBE : 1;
+ };
+ static_assert(sizeof(USBCON_reg_t) == 1, "invalid size of ATUSB90 USBCON_reg_t");
+
+ struct USBSTA_reg_t {
+ uint8_t _VBUS : 1;
+ uint8_t _ID : 1;
+ uint8_t reserved1 : 1;
+ uint8_t _SPEED : 1;
+ uint8_t reserved2 : 4;
+ };
+ static_assert(sizeof(USBSTA_reg_t) == 1, "invalid size of ATUSB90 USBSTA_reg_t");
+
+ struct USBINT_reg_t {
+ uint8_t _VBUSTI : 1;
+ uint8_t _IDTI : 1;
+ uint8_t reserved1 : 6;
+ };
+ static_assert(sizeof(USBINT_reg_t) == 1, "invalid size of ATUSB90 USBINT_reg_t");
+
+ struct UDPADD_reg_t {
+ uint16_t _DPADD : 11;
+ uint16_t reserved1 : 4;
+ uint16_t _DPACC : 1;
+ };
+ static_assert(sizeof(UDPADD_reg_t) == 2, "invalid size of ATUSB90 UDPADD_reg_t");
+
+ struct OTGCON_reg_t {
+ uint8_t _VBUSRQC : 1;
+ uint8_t _VBUSREQ : 1;
+ uint8_t _VBUSHWC : 1;
+ uint8_t _SRPSEL : 1;
+ uint8_t _SRPREQ : 1;
+ uint8_t _HNPREQ : 1;
+ uint8_t reserved1 : 1;
+ uint8_t _zero : 1;
+ };
+ static_assert(sizeof(OTGCON_reg_t) == 1, "invalid size of ATUSB90 OTGCON_reg_t");
+
+ struct OTGIEN_reg_t {
+ uint8_t _SRPE : 1;
+ uint8_t _VBERRE : 1;
+ uint8_t _BCERRE : 1;
+ uint8_t _ROLEEXE : 1;
+ uint8_t _HNPERRE : 1;
+ uint8_t _STOE : 1;
+ uint8_t reserved1 : 2;
+ };
+ static_assert(sizeof(OTGIEN_reg_t) == 1, "invalid size of ATUSB90 OTGIEN_reg_t");
+
+ struct OTGINT_reg_t {
+ uint8_t _SRPI : 1;
+ uint8_t _VBERRI : 1;
+ uint8_t _BCERRI : 1;
+ uint8_t _ROLEEXI : 1;
+ uint8_t _HNPERRI : 1;
+ uint8_t _STOI : 1;
+ uint8_t reserved1 : 2;
+ };
+ static_assert(sizeof(OTGINT_reg_t) == 1, "invalid size of ATUSB90 OTGINT_reg_t");
+
+ struct UDCON_reg_t {
+ uint8_t _DETACH : 1;
+ uint8_t _RMWKUP : 1;
+ uint8_t _LSM : 1;
+ uint8_t reserved1 : 5;
+ };
+ static_assert(sizeof(UDCON_reg_t) == 1, "invalid size of ATUSB90 UDCON_reg_t");
+
+ struct UDINT_reg_t {
+ uint8_t _SUSPI : 1;
+ uint8_t _MSOFI : 1;
+ uint8_t _SOFI : 1;
+ uint8_t _EORSTI : 1;
+ uint8_t _WAKEUPI : 1;
+ uint8_t _EORSMI : 1;
+ uint8_t _UPRSMI : 1;
+ uint8_t reserved1 : 1;
+ };
+ static_assert(sizeof(UDINT_reg_t) == 1, "invalid size of ATUSB90 UDINT_reg_t");
+
+ struct UDIEN_reg_t {
+ uint8_t _SUSPE : 1;
+ uint8_t _MSOFE : 1;
+ uint8_t _SOFE : 1;
+ uint8_t _EORSTE : 1;
+ uint8_t _WAKEUPE : 1;
+ uint8_t _EORSME : 1;
+ uint8_t _UPRSME : 1;
+ uint8_t reserved1 : 1;
+ };
+ static_assert(sizeof(UDIEN_reg_t) == 1, "invalid size of ATUSB90 UDIEN_reg_t");
+
+ struct UDADDR_reg_t {
+ uint8_t _UADD : 7;
+ uint8_t _ADDEN : 1;
+ };
+ static_assert(sizeof(UDADDR_reg_t) == 1, "invalid size of ATUSB90 UADDR_reg_t");
+
+ struct UDFNUM_reg_t {
+ uint16_t _FNUM : 11;
+ uint16_t reserved1 : 5;
+ };
+ static_assert(sizeof(UDFNUM_reg_t) == 2, "invalid size of ATUSB90 UDFNUM_reg_t");
+
+ struct UDMFN_reg_t {
+ uint8_t reserved1 : 4;
+ uint8_t _FNCERR : 1;
+ uint8_t reserved2 : 3;
+ };
+ static_assert(sizeof(UDMFN_reg_t) == 1, "invalid size of ATUSB90 UDMFN_reg_t");
+
+ struct UDTST_reg_t {
+ uint8_t reserved1 : 2;
+ uint8_t _TSTJ : 1;
+ uint8_t _TSTK : 1;
+ uint8_t _TSTPCKT : 1;
+ uint8_t _OPMODE2 : 1;
+ uint8_t reserved2 : 2;
+ };
+ static_assert(sizeof(UDTST_reg_t) == 1, "invalid size of ATUSB90 UDTST_reg_t");
+
+ struct UEINTX_reg_t {
+ uint8_t _TXINI : 1;
+ uint8_t _STALLEDI : 1;
+ uint8_t _RXOUTI : 1;
+ uint8_t _RXSTPI : 1;
+ uint8_t _NAKOUTI : 1;
+ uint8_t _RWAL : 1;
+ uint8_t _NAKINI : 1;
+ uint8_t _FIFOCON : 1;
+ };
+ static_assert(sizeof(UEINTX_reg_t) == 1, "invalid size of ATUSB90 UEINTX_reg_t");
+
+ struct UENUM_reg_t {
+ uint8_t _EPNUM : 3;
+ uint8_t reserved1 : 5;
+ };
+ static_assert(sizeof(UENUM_reg_t) == 1, "invalid size of ATUSB90 UENUM_reg_t");
+
+ struct UERST_reg_t {
+ uint8_t _EPRST : 7;
+ uint8_t reserved1 : 1;
+ };
+ static_assert(sizeof(UERST_reg_t) == 1, "invalid size of ATUSB90 UERST_reg_t");
+
+ struct UECONX_reg_t {
+ uint8_t _EPEN : 1;
+ uint8_t reserved1 : 2;
+ uint8_t _RSTDT : 1;
+ uint8_t _STALLRQC : 1;
+ uint8_t _STALLRQ : 1;
+ uint8_t reserved2 : 2;
+ };
+ static_assert(sizeof(UECONX_reg_t) == 1, "invalid size of ATUSB90 UECONX_reg_t");
+
+ struct UECFG0X_reg_t {
+ uint8_t _EPDIR : 1;
+ uint8_t _NYETSDIS : 1;
+ uint8_t _AUTOSW : 1;
+ uint8_t _ISOSW : 1;
+ uint8_t reserved1 : 2;
+ uint8_t _EPTYPE : 2;
+ };
+ static_assert(sizeof(UECFG0X_reg_t) == 1, "invalid size of ATUSB90 UECFG0X_reg_t");
+
+ struct UECFG1X_reg_t {
+ uint8_t reserved1 : 1;
+ uint8_t _ALLOC : 1;
+ uint8_t _EPBK : 2;
+ uint8_t _EPSIZE : 3;
+ uint8_t reserved2 : 1;
+ };
+ static_assert(sizeof(UECFG1X_reg_t) == 1, "invalid size of ATUSB90 UECFG1X_reg_t");
+
+ struct UESTA0X_reg_t {
+ uint8_t _NBUSYBK : 2;
+ uint8_t _DTSEQ : 2;
+ uint8_t _ZLPSEEN : 1;
+ uint8_t _UNDERFI : 1;
+ uint8_t _OVERFI : 1;
+ uint8_t _CFGOK : 1;
+ };
+ static_assert(sizeof(UESTA0X_reg_t) == 1, "invalid size of ATUSB90 UESTA0X_reg_t");
+
+ struct UESTA1X_reg_t {
+ uint8_t _CURRBK : 2;
+ uint8_t _CTRLDIR : 1;
+ uint8_t reserved1 : 5;
+ };
+ static_assert(sizeof(UESTA1X_reg_t) == 1, "invalid size of ATUSB90 UESTA1X_reg_t");
+
+ struct UEIENX_reg_t {
+ uint8_t _TXINE : 1;
+ uint8_t _STALLEDE : 1;
+ uint8_t _RXOUTE : 1;
+ uint8_t _RXSTPE : 1;
+ uint8_t _NAKOUTE : 1;
+ uint8_t reserved1 : 1;
+ uint8_t _NAKINE : 1;
+ uint8_t _FLERRE : 1;
+ };
+ static_assert(sizeof(UEIENX_reg_t) == 1, "invalid size of ATUSB90 UEIENX_reg_t");
+
+ struct UEBCX_reg_t {
+ uint16_t _BYCT : 11;
+ uint16_t reserved1 : 5;
+ };
+ static_assert(sizeof(UEBCX_reg_t) == 2, "invalid size of ATUSB90 UEBCX_reg_t");
+
+ struct UEINT_reg_t {
+ uint8_t _EPINT : 7;
+ uint8_t reserved1 : 1;
+ };
+ static_assert(sizeof(UEINT_reg_t) == 1, "invalid size of ATUSB90 UEINT_reg_t");
+
+ struct UPERRX_reg_t {
+ uint8_t _DATATGL : 1;
+ uint8_t _DATAPID : 1;
+ uint8_t _PID : 1;
+ uint8_t _TIMEOUT : 1;
+ uint8_t _CRC16 : 1;
+ uint8_t _COUNTER : 2;
+ uint8_t reserved1 : 1;
+ };
+ static_assert(sizeof(UPERRX_reg_t) == 1, "invalid size of ATUSB90 UPERRX_reg_t");
+
+ struct UPBCX_reg_t {
+ uint16_t _PBYCT : 11;
+ uint16_t reserved1 : 5;
+ };
+ static_assert(sizeof(UPBCX_reg_t) == 2, "invalid size of ATUSB90 UPBCX_reg_t");
+
+ struct OTGTCON_reg_t {
+ uint8_t _VALUE : 2;
+ uint8_t reserved1 : 3;
+ uint8_t _PAGE : 2;
+ uint8_t _one : 1;
+ };
+ static_assert(sizeof(OTGTCON_reg_t) == 1, "invalid size of ATUSB90 OTGTCON_reg_t");
+
+ struct PLLCSR_reg_t {
+ uint8_t _PLOCK : 1;
+ uint8_t _PLLE : 1;
+ uint8_t _PLLP : 3;
+ uint8_t reserved1 : 3;
+ };
+ static_assert(sizeof(PLLCSR_reg_t) == 1, "invalid size of ATUSB90 PLLCSR_reg_t");
+
+#endif // __AVR_TRM04__
+
+/**
+ * REGISTER MEMORY MAP
+ */
+
+#define __AVR_DEFREG(tn,n,a) static volatile tn& n = *(tn*)a
+#define _AVR_DEFREG(n,a) __AVR_DEFREG(n##_reg_t, _##n, a)
+
+#ifdef __AVR_TRM01__
+ // page 399ff of ATmega640-1280-1281-2560-2561-Datasheet-DS40002211A.pdf
+
+ __AVR_DEFREG(PORT_dev_t, _PORTA, 0x20);
+ __AVR_DEFREG(PORT_dev_t, _PORTB, 0x23);
+ __AVR_DEFREG(PORT_dev_t, _PORTC, 0x26);
+ __AVR_DEFREG(PORT_dev_t, _PORTD, 0x29);
+ __AVR_DEFREG(PORT_dev_t, _PORTE, 0x2C);
+ __AVR_DEFREG(PORT_dev_t, _PORTF, 0x2F);
+ __AVR_DEFREG(PORTG_dev_t, _PORTG, 0x32);
+ __AVR_DEFREG(PORT_dev_t, _PORTH, 0x100);
+ __AVR_DEFREG(PORT_dev_t, _PORTJ, 0x103);
+ __AVR_DEFREG(PORT_dev_t, _PORTK, 0x106);
+ __AVR_DEFREG(PORT_dev_t, _PORTL, 0x109);
+ __AVR_DEFREG(TIFR0_reg_t, _TIFR0, 0x35);
+ __AVR_DEFREG(TIFR1_reg_t, _TIFR1, 0x36);
+ __AVR_DEFREG(TIFR2_reg_t, _TIFR2, 0x37);
+ __AVR_DEFREG(TIFR3_reg_t, _TIFR3, 0x38);
+ __AVR_DEFREG(TIFR4_reg_t, _TIFR4, 0x39);
+ __AVR_DEFREG(TIFR5_reg_t, _TIFR5, 0x3A);
+ __AVR_DEFREG(PCIFR_reg_t, _PCIFR, 0x3B);
+ __AVR_DEFREG(EIFR_reg_t, _EIFR, 0x3C);
+ __AVR_DEFREG(EIMSK_reg_t, _EIMSK, 0x3D);
+ __AVR_DEFREG(_bit_reg_t, _GPIOR0, 0x3E);
+ __AVR_DEFREG(EECR_reg_t, _EECR, 0x3F);
+ __AVR_DEFREG(uint8_t, _EEDR, 0x40);
+ __AVR_DEFREG(EEAR_reg_t, _EEAR, 0x41);
+ __AVR_DEFREG(GTCCR_reg_t, _GTCCR, 0x43);
+ __AVR_DEFREG(TIMER_8bit_dev_t, TIMER0, 0x44);
+ __AVR_DEFREG(_bit_reg_t, _GPIOR1, 0x4A);
+ __AVR_DEFREG(_bit_reg_t, _GPIOR2, 0x4B);
+ __AVR_DEFREG(SPCR_reg_t, _SPCR, 0x4C);
+ __AVR_DEFREG(SPSR_reg_t, _SPSR, 0x4D);
+ __AVR_DEFREG(uint8_t, _SPDR, 0x4E);
+ __AVR_DEFREG(ACSR_reg_t, _ACSR, 0x50);
+ __AVR_DEFREG(_bit_reg_t, _OCDR, 0x51);
+ __AVR_DEFREG(SMCR_reg_t, _SMCR, 0x53);
+ __AVR_DEFREG(MCUSR_reg_t, _MCUSR, 0x54);
+ __AVR_DEFREG(MCUCR_reg_t, _MCUCR, 0x55);
+ __AVR_DEFREG(SPMCSR_reg_t, _SPMCSR, 0x57);
+ __AVR_DEFREG(RAMPZ_reg_t, _RAMPZ, 0x5B);
+ __AVR_DEFREG(EIND_reg_t, _EIND, 0x5C);
+ __AVR_DEFREG(SP_reg_t, _SP, 0x5D);
+ __AVR_DEFREG(SREG_reg_t, _SREG, 0x5F);
+ __AVR_DEFREG(WDTCSR_reg_t, _WDTCSR, 0x60);
+ __AVR_DEFREG(CLKPR_reg_t, _CLKPR, 0x61);
+ __AVR_DEFREG(PRR0_reg_t, _PRR0, 0x64);
+ __AVR_DEFREG(PRR1_reg_t, _PRR1, 0x65);
+ __AVR_DEFREG(uint8_t, _OSCCAL, 0x66);
+ __AVR_DEFREG(PCICR_reg_t, _PCICR, 0x68);
+ __AVR_DEFREG(EICRA_reg_t, _EICRA, 0x69);
+ __AVR_DEFREG(EICRB_reg_t, _EICRB, 0x6A);
+ __AVR_DEFREG(_bit_reg_t, _PCMSK0, 0x6B);
+ __AVR_DEFREG(_bit_reg_t, _PCMSK1, 0x6C);
+ __AVR_DEFREG(_bit_reg_t, _PCMSK2, 0x6D);
+ __AVR_DEFREG(TIMSK0_reg_t, _TIMSK0, 0x6E);
+ __AVR_DEFREG(TIMSK1_reg_t, _TIMSK1, 0x6F);
+ __AVR_DEFREG(TIMSK2_reg_t, _TIMSK2, 0x70);
+ __AVR_DEFREG(TIMSK3_reg_t, _TIMSK3, 0x71);
+ __AVR_DEFREG(TIMSK4_reg_t, _TIMSK4, 0x72);
+ __AVR_DEFREG(TIMSK5_reg_t, _TIMSK5, 0x73);
+ __AVR_DEFREG(XMCRA_reg_t, _XMCRA, 0x74);
+ __AVR_DEFREG(XMCRB_reg_t, _XMCRB, 0x75);
+ __AVR_DEFREG(uint16_t, _ADC, 0x78);
+ __AVR_DEFREG(ADCSRA_reg_t, _ADCSRA, 0x7A);
+ __AVR_DEFREG(ADCSRB_reg_t, _ADCSRB, 0x7B);
+ __AVR_DEFREG(ADMUX_reg_t, _ADMUX, 0x7C);
+ __AVR_DEFREG(DIDR2_reg_t, _DIDR2, 0x7D);
+ __AVR_DEFREG(DIDR0_reg_t, _DIDR0, 0x7E);
+ __AVR_DEFREG(DIDR1_reg_t, _DIDR1, 0x7F);
+ __AVR_DEFREG(TIMER_dev_t, TIMER1, 0x80);
+ __AVR_DEFREG(TIMER_dev_t, TIMER3, 0x90);
+ __AVR_DEFREG(TIMER_dev_t, TIMER4, 0xA0);
+ __AVR_DEFREG(TIMER_dev_t, TIMER5, 0x120);
+ __AVR_DEFREG(TIMER_8bit_dev_t, _TIMER2, 0xB0);
+ __AVR_DEFREG(ASSR_reg_t, _ASSR, 0xB6);
+ __AVR_DEFREG(uint8_t, _TWBR, 0xB8);
+ __AVR_DEFREG(TWSR_reg_t, _TWSR, 0xB9);
+ __AVR_DEFREG(TWAR_reg_t, _TWAR, 0xBA);
+ __AVR_DEFREG(uint8_t, _TWDR, 0xBB);
+ __AVR_DEFREG(TWCR_reg_t, _TWCR, 0xBC);
+ __AVR_DEFREG(TWAMR_reg_t, _TWAMR, 0xBD);
+ __AVR_DEFREG(USART_dev_t, USART0, 0xC0);
+ __AVR_DEFREG(USART_dev_t, USART1, 0xC8);
+ __AVR_DEFREG(USART_dev_t, USART2, 0xD0);
+ __AVR_DEFREG(USART_dev_t, USART3, 0x130);
+
+#elif defined(__AVR_TRM02__)
+ // page 637ff of ATmega164A_PA-324A_PA-644A_PA-1284_P_Data-Sheet-40002070B.pdf
+ __AVR_DEFREG(PORT_dev_t, _PORTA, 0x20);
+ __AVR_DEFREG(PORT_dev_t, _PORTB, 0x23);
+ __AVR_DEFREG(PORT_dev_t, _PORTC, 0x26);
+ __AVR_DEFREG(PORT_dev_t, _PORTD, 0x29);
+ __AVR_DEFREG(TIFR0_reg_t, _TIFR0, 0x35);
+ __AVR_DEFREG(TIFR1_reg_t, _TIFR1, 0x36);
+ __AVR_DEFREG(TIFR2_reg_t, _TIFR2, 0x37);
+ __AVR_DEFREG(TIFR3_reg_t, _TIFR3, 0x38);
+ __AVR_DEFREG(PCIFR_reg_t, _PCIFR, 0x3B);
+ __AVR_DEFREG(EIFR_reg_t, _EIFR, 0x3C);
+ __AVR_DEFREG(EIMSK_reg_t, _EIMSK, 0x3D);
+ __AVR_DEFREG(_bit_reg_t, _GPIOR0, 0x3E);
+ __AVR_DEFREG(EECR_reg_t, _EECR, 0x3F);
+ __AVR_DEFREG(uint8_t, _EEDR, 0x40);
+ __AVR_DEFREG(EEAR_reg_t, _EEAR, 0x41);
+ __AVR_DEFREG(GTCCR_reg_t, _GTCCR, 0x43);
+ __AVR_DEFREG(TIMER_8bit_dev_t, TIMER0, 0x44);
+ __AVR_DEFREG(_bit_reg_t, _GPIOR1, 0x4A);
+ __AVR_DEFREG(_bit_reg_t, _GPIOR2, 0x4B);
+ __AVR_DEFREG(SPCR_reg_t, _SPCR, 0x4C);
+ __AVR_DEFREG(SPSR_reg_t, _SPSR, 0x4D);
+ __AVR_DEFREG(uint8_t, _SPDR, 0x4E);
+ __AVR_DEFREG(ACSR_reg_t, _ACSR, 0x50);
+ __AVR_DEFREG(SMCR_reg_t, _SMCR, 0x53);
+ __AVR_DEFREG(MCUSR_reg_t, _MSUSR, 0x54);
+ __AVR_DEFREG(MCUCR_reg_t, _MCUCR, 0x55);
+ __AVR_DEFREG(SPMCSR_reg_t, _SPMCSR, 0x57);
+ __AVR_DEFREG(SP_reg_t, _SP, 0x5D);
+ __AVR_DEFREG(SREG_reg_t, _SREG, 0x5F);
+ __AVR_DEFREG(WDTCSR_reg_t, _WDTCSR, 0x60);
+ __AVR_DEFREG(CLKPR_reg_t, _CLKPR, 0x61);
+ __AVR_DEFREG(PRR0_reg_t, _PRR0, 0x64);
+ __AVR_DEFREG(PRR1_reg_t, _PRR1, 0x65);
+ __AVR_DEFREG(uint8_t, _OSCCAL, 0x66);
+ __AVR_DEFREG(PCICR_reg_t, _PCICR, 0x68);
+ __AVR_DEFREG(EICRA_reg_t, _EICRA, 0x69);
+ __AVR_DEFREG(_bit_reg_t, _PCMSK0, 0x6B);
+ __AVR_DEFREG(_bit_reg_t, _PCMSK1, 0x6C);
+ __AVR_DEFREG(_bit_reg_t, _PCMSK2, 0x6D);
+ __AVR_DEFREG(TIMSK0_reg_t, _TIMSK0, 0x6E);
+ __AVR_DEFREG(TIMSK1_reg_t, _TIMSK1, 0x6F);
+ __AVR_DEFREG(TIMSK2_reg_t, _TIMSK2, 0x70);
+ __AVR_DEFREG(TIMSK3_reg_t, _TIMSK3, 0x71);
+ __AVR_DEFREG(_bit_reg_t, _PCMSK3, 0x73);
+ __AVR_DEFREG(uint16_t, _ADC, 0x78);
+ __AVR_DEFREG(ADCSRA_reg_t, _ADCSRA, 0x7A);
+ __AVR_DEFREG(ADCSRB_reg_t, _ADCSRB, 0x7B);
+ __AVR_DEFREG(ADMUX_reg_t, _ADMUX, 0x7C);
+ __AVR_DEFREG(DIDR0_reg_t, _DIDR0, 0x7E);
+ __AVR_DEFREG(DIDR1_reg_t, _DIDR1, 0x7F);
+ __AVR_DEFREG(TIMER_dev_t, TIMER1, 0x80);
+ __AVR_DEFREG(TIMER_dev_t, TIMER3, 0x90);
+ __AVR_DEFREG(TIMER_8bit_dev_t, _TIMER2, 0xB0);
+ __AVR_DEFREG(ASSR_reg_t, _ASSR, 0xB6);
+ __AVR_DEFREG(uint8_t, _TWBR, 0xB8);
+ __AVR_DEFREG(TWSR_reg_t, _TWSR, 0xB9);
+ __AVR_DEFREG(TWAR_reg_t, _TWAR, 0xBA);
+ __AVR_DEFREG(uint8_t, _TWDR, 0xBB);
+ __AVR_DEFREG(TWCR_reg_t, _TWCR, 0xBC);
+ __AVR_DEFREG(TWAMR_reg_t, _TWAMR, 0xBD);
+ __AVR_DEFREG(USART_dev_t, USART0, 0xC0);
+ __AVR_DEFREG(USART_dev_t, USART1, 0xC8);
+
+#elif defined(__AVR_TRM03__)
+ // page 621ff of ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061B.pdf
+ __AVR_DEFREG(PORT_dev_t, _PORTB, 0x23);
+ __AVR_DEFREG(PORTC_dev_t, _PORTC, 0x26);
+ __AVR_DEFREG(PORT_dev_t, _PORTD, 0x29);
+ __AVR_DEFREG(TIFR0_reg_t, _TIFR0, 0x35);
+ __AVR_DEFREG(TIFR1_reg_t, _TIFR1, 0x36);
+ __AVR_DEFREG(TIFR2_reg_t, _TIFR2, 0x37);
+ __AVR_DEFREG(PCIFR_reg_t, _PCIFR, 0x3B);
+ __AVR_DEFREG(EIFR_reg_t, _EIFR, 0x3C);
+ __AVR_DEFREG(EIMSK_reg_t, _EIMSK, 0x3D);
+ __AVR_DEFREG(_bit_reg_t, _GPIOR0, 0x3E);
+ __AVR_DEFREG(EECR_reg_t, _EECR, 0x3F);
+ __AVR_DEFREG(uint8_t, _EEDR, 0x40);
+ __AVR_DEFREG(EEAR_reg_t, _EEAR, 0x41);
+ __AVR_DEFREG(GTCCR_reg_t, _GTCCR, 0x43);
+ __AVR_DEFREG(TIMER_8bit_dev_t, TIMER0, 0x44);
+ __AVR_DEFREG(_bit_reg_t, _GPIOR1, 0x4A);
+ __AVR_DEFREG(_bit_reg_t, _GPIOR2, 0x4B);
+ __AVR_DEFREG(SPCR_reg_t, _SPCR, 0x4C);
+ __AVR_DEFREG(SPSR_reg_t, _SPSR, 0x4D);
+ __AVR_DEFREG(uint8_t, _SPDR, 0x4E);
+ __AVR_DEFREG(ACSR_reg_t, _ACSR, 0x50);
+ __AVR_DEFREG(SMCR_reg_t, _SMCR, 0x53);
+ __AVR_DEFREG(MCUSR_reg_t, _MSUCR, 0x54);
+ __AVR_DEFREG(MCUCR_reg_t, _MCUCR, 0x55);
+ __AVR_DEFREG(SPMCSR_reg_t, _SPMCSR, 0x57);
+ __AVR_DEFREG(SP_reg_t, _SP, 0x5D);
+ __AVR_DEFREG(SREG_reg_t, _SREG, 0x5F);
+ __AVR_DEFREG(WDTCSR_reg_t, _WDTCSR, 0x60);
+ __AVR_DEFREG(CLKPR_reg_t, _CLKPR, 0x61);
+ __AVR_DEFREG(PRR0_reg_t, _PRR0, 0x64);
+ __AVR_DEFREG(uint8_t, _OSCCAL, 0x66);
+ __AVR_DEFREG(PCICR_reg_t, _PCICR, 0x68);
+ __AVR_DEFREG(EICRA_reg_t, _EICRA, 0x69);
+ __AVR_DEFREG(_bit_reg_t, _PCMSK0, 0x6B);
+ __AVR_DEFREG(_bitPCMSK1_reg_t, _PCMSK1, 0x6C);
+ __AVR_DEFREG(_bit_reg_t, _PCMSK2, 0x6D);
+ __AVR_DEFREG(TIMSK0_reg_t, _TIMSK0, 0x6E);
+ __AVR_DEFREG(TIMSK1_reg_t, _TIMSK1, 0x6F);
+ __AVR_DEFREG(TIMSK2_reg_t, _TIMSK2, 0x70);
+ __AVR_DEFREG(uint16_t, _ADC, 0x78);
+ __AVR_DEFREG(ADCSRA_reg_t, _ADCSRA, 0x7A);
+ __AVR_DEFREG(ADCSRB_reg_t, _ADCSRB, 0x7B);
+ __AVR_DEFREG(ADMUX_reg_t, _ADMUX, 0x7C);
+ __AVR_DEFREG(DIDR0_reg_t, _DIDR0, 0x7E);
+ __AVR_DEFREG(DIDR1_reg_t, _DIDR1, 0x7F);
+ __AVR_DEFREG(TIMER_dev_t, TIMER1, 0x80);
+ __AVR_DEFREG(TIMER_8bit_dev_t, _TIMER2, 0xB0);
+ __AVR_DEFREG(ASSR_reg_t, _ASSR, 0xB6);
+ __AVR_DEFREG(uint8_t, _TWBR, 0xB8);
+ __AVR_DEFREG(TWSR_reg_t, _TWSR, 0xB9);
+ __AVR_DEFREG(TWAR_reg_t, _TWAR, 0xBA);
+ __AVR_DEFREG(uint8_t, _TWDR, 0xBB);
+ __AVR_DEFREG(TWCR_reg_t, _TWCR, 0xBC);
+ __AVR_DEFREG(TWAMR_reg_t, _TWAMR, 0xBD);
+ __AVR_DEFREG(USART_dev_t, USART0, 0xC0);
+
+#elif defined(__AVR_TRM04__)
+ __AVR_DEFREG(PORT_dev_t, _PORTA, 0x20);
+ __AVR_DEFREG(PORT_dev_t, _PORTB, 0x23);
+ __AVR_DEFREG(PORT_dev_t, _PORTC, 0x26);
+ __AVR_DEFREG(PORT_dev_t, _PORTD, 0x29);
+ __AVR_DEFREG(PORT_dev_t, _PORTE, 0x2C);
+ __AVR_DEFREG(PORT_dev_t, _PORTF, 0x2F);
+ __AVR_DEFREG(TIFR0_reg_t, _TIFR0, 0x35);
+ __AVR_DEFREG(TIFR1_reg_t, _TIFR1, 0x36);
+ __AVR_DEFREG(TIFR2_reg_t, _TIFR2, 0x37);
+ __AVR_DEFREG(TIFR3_reg_t, _TIFR3, 0x38);
+ __AVR_DEFREG(PCIFR_reg_t, _PCIFR, 0x3B);
+ __AVR_DEFREG(EIFR_reg_t, _EIFR, 0x3C);
+ __AVR_DEFREG(EIMSK_reg_t, _EIMSK, 0x3D);
+ __AVR_DEFREG(_bit_reg_t, _GPIOR0, 0x3E);
+ __AVR_DEFREG(EECR_reg_t, _EECR, 0x3F);
+ __AVR_DEFREG(uint8_t, _EEDR, 0x40);
+ __AVR_DEFREG(EEAR_reg_t, _EEAR, 0x41);
+ __AVR_DEFREG(GTCCR_reg_t, _GTCCR, 0x43);
+ __AVR_DEFREG(TIMER_8bit_dev_t, TIMER0, 0x44);
+ __AVR_DEFREG(PLLCSR_reg_t, _PLLCSR, 0x49);
+ __AVR_DEFREG(_bit_reg_t, _GPIOR1, 0x4A);
+ __AVR_DEFREG(_bit_reg_t, _GPIOR2, 0x4B);
+ __AVR_DEFREG(SPCR_reg_t, _SPCR, 0x4C);
+ __AVR_DEFREG(SPSR_reg_t, _SPSR, 0x4D);
+ __AVR_DEFREG(uint8_t, _SPDR, 0x4E);
+ __AVR_DEFREG(ACSR_reg_t, _ACSR, 0x50);
+ __AVR_DEFREG(uint8_t, _OCDR, 0x51);
+ __AVR_DEFREG(SMCR_reg_t, _SMCR, 0x53);
+ __AVR_DEFREG(MCUSR_reg_t, _MCUSR, 0x54);
+ __AVR_DEFREG(MCUCR_reg_t, _MCUCR, 0x55);
+ __AVR_DEFREG(SPMCSR_reg_t, _SPMCSR, 0x57);
+ __AVR_DEFREG(RAMPZ_reg_t, _RAMPZ, 0x5B);
+ __AVR_DEFREG(SP_reg_t, _SP, 0x5D);
+ __AVR_DEFREG(SREG_reg_t, _SREG, 0x5F);
+ __AVR_DEFREG(WDTCSR_reg_t, _WDTCSR, 0x60);
+ __AVR_DEFREG(CLKPR_reg_t, _CLKPR, 0x61);
+ __AVR_DEFREG(PRR0_reg_t, _PRR0, 0x64);
+ __AVR_DEFREG(PRR1_reg_t, _PRR1, 0x65);
+ __AVR_DEFREG(uint8_t, _OSCCAL, 0x66);
+ __AVR_DEFREG(PCICR_reg_t, _PCICR, 0x68);
+ __AVR_DEFREG(EICRA_reg_t, _EICRA, 0x69);
+ __AVR_DEFREG(EICRB_reg_t, _EICRB, 0x6A);
+ __AVR_DEFREG(_bit_reg_t, _PCMSK0, 0x6B);
+ __AVR_DEFREG(TIMSK0_reg_t, _TIMSK0, 0x6E);
+ __AVR_DEFREG(TIMSK1_reg_t, _TIMSK1, 0x6F);
+ __AVR_DEFREG(TIMSK2_reg_t, _TIMSK2, 0x70);
+ __AVR_DEFREG(TIMSK3_reg_t, _TIMSK3, 0x71);
+ __AVR_DEFREG(XMCRA_reg_t, _XMCRA, 0x74);
+ __AVR_DEFREG(XMCRB_reg_t, _XMCRB, 0x75);
+ __AVR_DEFREG(uint16_t, _ADC, 0x78);
+ __AVR_DEFREG(ADCSRA_reg_t, _ADCSRA, 0x7A);
+ __AVR_DEFREG(ADCSRB_reg_t, _ADCSRB, 0x7B);
+ __AVR_DEFREG(ADMUX_reg_t, _ADMUX, 0x7C);
+ __AVR_DEFREG(DIDR0_reg_t, _DIDR0, 0x7E);
+ __AVR_DEFREG(DIDR1_reg_t, _DIDR1, 0x7F);
+ __AVR_DEFREG(TIMER_dev_t, TIMER1, 0x80);
+ __AVR_DEFREG(TIMER_dev_t, TIMER3, 0x90);
+ __AVR_DEFREG(UHCON_reg_t, _UHCON, 0x9E);
+ __AVR_DEFREG(UHINT_reg_t, _UHINT, 0x9F);
+ __AVR_DEFREG(UHIEN_reg_t, _UHIEN, 0xA0);
+ __AVR_DEFREG(UHADDR_reg_t, _UHADDR, 0xA1);
+ __AVR_DEFREG(UHFNUM_reg_t, _UHFNUM, 0xA2);
+ __AVR_DEFREG(uint8_t, _UHFLEN, 0xA4);
+ __AVR_DEFREG(uint8_t, _UPINRQX, 0xA5);
+ __AVR_DEFREG(UPINTX_reg_t, _UPINTX, 0xA6);
+ __AVR_DEFREG(UPNUM_reg_t, _UPNUM, 0xA7);
+ __AVR_DEFREG(UPRST_reg_t, _UPRST, 0xA8);
+ __AVR_DEFREG(UPCONX_reg_t, _UPCONX, 0xA9);
+ _AVR_DEFREG(UPCFG0X, 0xAA);
+ _AVR_DEFREG(UPCFG1X, 0xAB);
+ _AVR_DEFREG(UPSTAX, 0xAC);
+ __AVR_DEFREG(uint8_t, _UPCFG2X, 0xAD);
+ _AVR_DEFREG(UPIENX, 0xAE);
+ __AVR_DEFREG(uint8_t, _UPDATX, 0xAF);
+ __AVR_DEFREG(TIMER_8bit_dev_t, _TIMER2, 0xB0);
+ __AVR_DEFREG(ASSR_reg_t, _ASSR, 0xB6);
+ __AVR_DEFREG(uint8_t, _TWBR, 0xB8);
+ __AVR_DEFREG(TWSR_reg_t, _TWSR, 0xB9);
+ __AVR_DEFREG(TWAR_reg_t, _TWAR, 0xBA);
+ __AVR_DEFREG(uint8_t, _TWDR, 0xBB);
+ __AVR_DEFREG(TWCR_reg_t, _TWCR, 0xBC);
+ __AVR_DEFREG(TWAMR_reg_t, _TWAMR, 0xBD);
+ __AVR_DEFREG(USART_dev_t, USART1, 0xC8);
+ _AVR_DEFREG(UHWCON, 0xD7);
+ _AVR_DEFREG(USBCON, 0xD8);
+ _AVR_DEFREG(USBSTA, 0xD9);
+ _AVR_DEFREG(USBINT, 0xDA);
+ _AVR_DEFREG(UDPADD, 0xDB);
+ _AVR_DEFREG(OTGCON, 0xDD);
+ _AVR_DEFREG(OTGIEN, 0xDE);
+ _AVR_DEFREG(OTGINT, 0xDF);
+ _AVR_DEFREG(UDCON, 0xE0);
+ _AVR_DEFREG(UDINT, 0xE1);
+ _AVR_DEFREG(UDIEN, 0xE2);
+ _AVR_DEFREG(UDADDR, 0xE3);
+ _AVR_DEFREG(UDFNUM, 0xE4);
+ _AVR_DEFREG(UDMFN, 0xE6);
+ _AVR_DEFREG(UDTST, 0xE7);
+ _AVR_DEFREG(UEINTX, 0xE8);
+ _AVR_DEFREG(UENUM, 0xE9);
+ _AVR_DEFREG(UERST, 0xEA);
+ _AVR_DEFREG(UECONX, 0xEB);
+ _AVR_DEFREG(UECFG0X, 0xEC);
+ _AVR_DEFREG(UECFG1X, 0xED);
+ _AVR_DEFREG(UESTA0X, 0xEE);
+ _AVR_DEFREG(UESTA1X, 0xEF);
+ _AVR_DEFREG(UEIENX, 0xF0);
+ __AVR_DEFREG(uint8_t, _UEDATx, 0xF1);
+ _AVR_DEFREG(UEBCX, 0xF2);
+ _AVR_DEFREG(UEINT, 0xF4);
+ _AVR_DEFREG(UPERRX, 0xF5);
+ _AVR_DEFREG(UPBCX, 0xF6);
+ __AVR_DEFREG(uint8_t, _UPINT, 0xF8);
+ _AVR_DEFREG(OTGTCON, 0xF9);
+#endif
+
+inline void _ATmega_resetperipherals() {
+ using namespace AVRHelpers;
+
+ // Due to BOOTLOADER or other board inconsistencies we could get launched into Marlin FW
+ // with configuration that does not match the reset state in the documentation. That is why
+ // we should clean-reset the entire device.
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ SREG_reg_t __SREG;
+ __SREG._C = false;
+ __SREG._Z = false;
+ __SREG._N = false;
+ __SREG._V = false;
+ __SREG._S = false;
+ __SREG._H = false;
+ __SREG._T = false;
+ __SREG._I = false;
+ dwrite(_SREG, __SREG);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ _RAMPZ._RAMPZ = 0;
+ #endif
+ #ifdef __AVR_TRM01__
+ _EIND._EIND0 = false;
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__)
+ _EEAR._EEAR = 0;
+ dwrite(_EEDR, (uint8_t)0u);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ EECR_reg_t __EECR;
+ __EECR._EERE = false;
+ __EECR._EEPE = false;
+ __EECR._EEMPE = false;
+ __EECR._EERIE = false;
+ __EECR._EEPM0 = 0;
+ __EECR._EEPM1 = 0;
+ __EECR.reserved1 = 0;
+ dwrite(_EECR, __EECR);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ _GPIOR2.val = 0;
+ _GPIOR1.val = 0;
+ _GPIOR0.val = 0;
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ XMCRA_reg_t __XMCRA;
+ __XMCRA._SRW0 = 0;
+ __XMCRA._SRW1 = 0;
+ __XMCRA._SRL = 0;
+ __XMCRA._SRE = 0;
+ dwrite(_XMCRA, __XMCRA);
+
+ XMCRB_reg_t __XMCRB;
+ __XMCRB._XMM = 0;
+ __XMCRB.reserved1 = 0;
+ __XMCRB._XMBK = false;
+ dwrite(_XMCRB, __XMCRB);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ SMCR_reg_t __SMCR;
+ __SMCR._SE = false;
+ __SMCR._SM = 0;
+ __SMCR.reserved1 = 0;
+ dwrite(_SMCR, __SMCR);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ PRR0_reg_t __PRR0;
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM03__)
+ __PRR0._PRADC = false;
+ __PRR0._PRUSART0 = false;
+ __PRR0._PRSPI = false;
+ __PRR0._PRTIM1 = false;
+ __PRR0.reserved1 = false;
+ __PRR0._PRTIM0 = false;
+ __PRR0._PRTIM2 = false;
+ __PRR0._PRTWI = false;
+ #elif defined(__AVR_TRM02__)
+ __PRR0._PRADC = false;
+ __PRR0._PRUSART0 = false;
+ __PRR0._PRSPI = false;
+ __PRR0._PRTIM1 = false;
+ __PRR0._PRUSART1 = false;
+ __PRR0._PRTIM0 = false;
+ __PRR0._PRTIM2 = false;
+ __PRR0._PRTWI = false;
+ #elif defined(__AVR_TRM04__)
+ __PRR0._PRADC = false;
+ __PRR0.reserved1 = false;
+ __PRR0._PRSPI = false;
+ __PRR0._PRTIM1 = false;
+ __PRR0.reserved2 = false;
+ __PRR0._PRTIM0 = false;
+ __PRR0._PRTIM2 = false;
+ __PRR0._PRTWI = false;
+ #endif
+ dwrite(_PRR0, __PRR0);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__)
+ PRR1_reg_t __PRR1;
+ #ifdef __AVR_TRM01__
+ __PRR1._PRUSART1 = false;
+ __PRR1._PRUSART2 = false;
+ __PRR1._PRUSART3 = false;
+ __PRR1._PRTIM3 = false;
+ __PRR1._PRTIM4 = false;
+ __PRR1._PRTIM5 = false;
+ __PRR1.reserved1 = 0;
+ #elif defined(__AVR_TRM02__)
+ __PRR1._PRTIM3 = false;
+ __PRR1.reserved1 = 0;
+ #elif defined(__AVR_TRM04__)
+ __PRR1._PRUSART1 = false;
+ __PRR1.reserved1 = 0;
+ #endif
+ dwrite(_PRR1, __PRR1);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ WDTCSR_reg_t __WDTCSR;
+ __WDTCSR._WDP0 = 0;
+ __WDTCSR._WDP1 = 0;
+ __WDTCSR._WDP2 = 0;
+ __WDTCSR._WDE = false;
+ __WDTCSR._WDCE = false;
+ __WDTCSR._WDP3 = 0;
+ __WDTCSR._WDIE = false;
+ __WDTCSR._WDIF = false;
+ dwrite(_WDTCSR, __WDTCSR);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ _MCUCR._PUD = false;
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ PORT_dev_t __PORT;
+ __PORT._PIN.val = 0;
+ __PORT._DDR.val = 0;
+ __PORT._PORT.val = 0;
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__)
+ dwrite(_PORTA, __PORT);
+ dwrite(_PORTC, __PORT);
+ #endif
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ dwrite(_PORTB, __PORT);
+ dwrite(_PORTD, __PORT);
+ #endif
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ dwrite(_PORTE, __PORT);
+ dwrite(_PORTF, __PORT);
+ #endif
+
+ #ifdef __AVR_TRM01__
+ PORTG_dev_t __PORTG;
+ __PORTG._PIN.val = 0;
+ __PORTG._PIN.reserved1 = 0;
+ __PORTG._DDR.val = 0;
+ __PORTG._DDR.reserved1 = 0;
+ __PORTG._PORT.val = 0;
+ __PORTG._PORT.reserved1 = 0;
+ dwrite(_PORTG, __PORTG);
+ #endif
+
+ #ifdef __AVR_TRM03__
+ PORTC_dev_t __PORTC;
+ __PORTC._PIN.val = 0;
+ __PORTC._PIN.reserved1 = 0;
+ __PORTC._DDR.val = 0;
+ __PORTC._DDR.reserved1 = 0;
+ __PORTC._PORT.val = 0;
+ __PORTC._PORT.reserved1 = 0;
+ dwrite(_PORTC, __PORTC);
+ #endif
+
+ #ifdef __AVR_TRM01__
+ dwrite(_PORTH, __PORT);
+ dwrite(_PORTJ, __PORT);
+ dwrite(_PORTK, __PORT);
+ dwrite(_PORTL, __PORT);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ EICRA_reg_t __EICRA;
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ __EICRA._ISC0 = 0;
+ __EICRA._ISC1 = 0;
+ __EICRA._ISC2 = 0;
+ __EICRA._ISC3 = 0;
+ #elif defined(__AVR_TRM02__)
+ __EICRA._ISC0 = 0;
+ __EICRA._ISC1 = 0;
+ __EICRA._ISC2 = 0;
+ __EICRA.reserved1 = 0;
+ #elif defined(__AVR_TRM03__)
+ __EICRA._ISC0 = 0;
+ __EICRA._ISC1 = 0;
+ __EICRA.reserved1 = 0;
+ #endif
+ dwrite(_EICRA, __EICRA);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ EICRB_reg_t __EICRB;
+ __EICRB._ISC4 = 0;
+ __EICRB._ISC5 = 0;
+ __EICRB._ISC6 = 0;
+ __EICRB._ISC7 = 0;
+ dwrite(_EICRB, __EICRB);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ EIMSK_reg_t __EIMSK;
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ __EIMSK._INT0 = false;
+ __EIMSK._INT1 = false;
+ __EIMSK._INT2 = false;
+ __EIMSK._INT3 = false;
+ __EIMSK._INT4 = false;
+ __EIMSK._INT5 = false;
+ __EIMSK._INT6 = false;
+ __EIMSK._INT7 = false;
+ #elif defined(__AVR_TRM02__)
+ __EIMSK._INT0 = false;
+ __EIMSK._INT1 = false;
+ __EIMSK._INT2 = false;
+ __EIMSK.reserved1 = 0;
+ #elif defined(__AVR_TRM03__)
+ __EIMSK._INT0 = false;
+ __EIMSK._INT1 = false;
+ __EIMSK.reserved1 = 0;
+ #endif
+ dwrite(_EIMSK, __EIMSK);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ EIFR_reg_t __EIFR;
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ __EIFR._INTF0 = false;
+ __EIFR._INTF1 = false;
+ __EIFR._INTF2 = false;
+ __EIFR._INTF3 = false;
+ __EIFR._INTF4 = false;
+ __EIFR._INTF5 = false;
+ __EIFR._INTF6 = false;
+ __EIFR._INTF7 = false;
+ #elif defined(__AVR_TRM02__)
+ __EIFR._INTF0 = false;
+ __EIFR._INTF1 = false;
+ __EIFR._INTF2 = false;
+ __EIFR.reserved1 = 0;
+ #elif defined(__AVR_TRM03__)
+ __EIFR._INTF0 = false;
+ __EIFR._INTF1 = false;
+ __EIFR.reserved1 = 0;
+ #endif
+ dwrite(_EIFR, __EIFR);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ PCICR_reg_t __PCICR;
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM03__)
+ __PCICR._PCIE0 = false;
+ __PCICR._PCIE1 = false;
+ __PCICR._PCIE2 = false;
+ __PCICR.reserved1 = 0;
+ #elif defined(__AVR_TRM02__)
+ __PCICR._PCIE0 = false;
+ __PCICR._PCIE1 = false;
+ __PCICR._PCIE2 = false;
+ __PCICR._PCIE3 = false;
+ __PCICR.reserved1 = 0;
+ #elif defined(__AVR_TRM04__)
+ __PCICR._PCIE0 = false;
+ __PCICR.reserved1 = 0;
+ #endif
+ dwrite(_PCICR, __PCICR);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ PCIFR_reg_t __PCIFR;
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM03__)
+ __PCIFR._PCIF0 = false;
+ __PCIFR._PCIF1 = false;
+ __PCIFR._PCIF2 = false;
+ __PCIFR.reserved1 = 0;
+ #elif defined(__AVR_TRM02__)
+ __PCIFR._PCIF0 = false;
+ __PCIFR._PCIF1 = false;
+ __PCIFR._PCIF2 = false;
+ __PCIFR._PCIF3 = false;
+ __PCIFR.reserved1 = 0;
+ #elif defined(__AVR_TRM04__)
+ __PCIFR._PCIF0 = false;
+ __PCIFR.reserved1 = 0;
+ #endif
+ dwrite(_PCIFR, __PCIFR);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ _PCMSK0.val = 0;
+ #endif
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__)
+ _PCMSK1.val = 0;
+ _PCMSK2.val = 0;
+ #endif
+ #if defined(__AVR_TRM02__)
+ _PCMSK3.val = 0;
+ #endif
+ #if defined(__AVR_TRM03__)
+ _PCMSK1.reserved1 = 0;
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ TIMER_8bit_dev_t __TIMER_8bit;
+ __TIMER_8bit._TCCRnA._WGMn0 = 0;
+ __TIMER_8bit._TCCRnA._WGMn1 = 0;
+ __TIMER_8bit._TCCRnA.reserved1 = 0;
+ __TIMER_8bit._TCCRnA._COMnB = 0;
+ __TIMER_8bit._TCCRnA._COMnA = 0;
+ __TIMER_8bit._TCCRnB._CSn = 0;
+ __TIMER_8bit._TCCRnB._WGMn2 = 0;
+ __TIMER_8bit._TCCRnB.reserved1 = 0;
+ __TIMER_8bit._TCCRnB._FOCnB = false;
+ __TIMER_8bit._TCCRnB._FOCnA = false,
+ __TIMER_8bit._TCNTn = 0;
+ __TIMER_8bit._OCRnA = 0;
+ __TIMER_8bit._OCRnB = 0;
+ dwrite(TIMER0, __TIMER_8bit);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ TIMSK0_reg_t __TIMSK0;
+ __TIMSK0._TOIE0 = false;
+ __TIMSK0._OCIE0A = false;
+ __TIMSK0._OCIE0B = false;
+ __TIMSK0.reserved1 = 0;
+ dwrite(_TIMSK0, __TIMSK0);
+
+ TIFR0_reg_t __TIFR0;
+ __TIFR0._TOV0 = false;
+ __TIFR0._OCF0A = false;
+ __TIFR0._OCF0B = false;
+ __TIFR0.reserved1 = 0;
+ dwrite(_TIFR0, __TIFR0);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ TIMER_dev_t TIMER;
+ TIMER._TCCRnA._WGMn0 = 0;
+ TIMER._TCCRnA._WGMn1 = 0;
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ TIMER._TCCRnA._COMnC = 0;
+ #endif
+ TIMER._TCCRnA._COMnB = 0;
+ TIMER._TCCRnA._COMnA = 0;
+ TIMER._TCCRnB._CSn = 0;
+ TIMER._TCCRnB._WGMn2 = 0;
+ TIMER._TCCRnB.reserved1 = 0;
+ TIMER._TCCRnB._ICESn = 0;
+ TIMER._TCCRnB._ICNCn = 0;
+ TIMER._TCCRnC.reserved1 = 0;
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ TIMER._TCCRnC._FOCnC = false;
+ #endif
+ TIMER._TCCRnC._FOCnB = false;
+ TIMER._TCCRnC._FOCnA = false;
+ TIMER._TCNTn = 0;
+ TIMER._OCRnA = 0;
+ TIMER._OCRnB = 0;
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ TIMER._OCRnC = 0;
+ #endif
+ TIMER._ICRn = 0;
+ dwrite(TIMER1, TIMER);
+ #endif
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__)
+ dwrite(TIMER3, TIMER);
+ #endif
+ #ifdef __AVR_TRM01__
+ dwrite(TIMER4, TIMER);
+ dwrite(TIMER5, TIMER);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ TIMSK1_reg_t __TIMSK1;
+ __TIMSK1._TOIE1 = false;
+ __TIMSK1._OCIE1A = false;
+ __TIMSK1._OCIE1B = false;
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ __TIMSK1._OCIE1C = false;
+ #endif
+ __TIMSK1.reserved1 = 0;
+ __TIMSK1._ICIE1 = false;
+ __TIMSK1.reserved2 = 0;
+ dwrite(_TIMSK1, __TIMSK1);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__)
+ TIMSK3_reg_t __TIMSK3;
+ __TIMSK3._TOIE3 = false;
+ __TIMSK3._OCIE3A = false;
+ __TIMSK3._OCIE3B = false;
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ __TIMSK3._OCIE3C = false;
+ #endif
+ __TIMSK3.reserved1 = 0;
+ __TIMSK3._ICIE3 = false;
+ __TIMSK3.reserved2 = 0;
+ dwrite(_TIMSK3, __TIMSK3);
+ #endif
+
+ #ifdef __AVR_TRM01__
+ TIMSK4_reg_t __TIMSK4;
+ __TIMSK4._TOIE4 = false;
+ __TIMSK4._OCIE4A = false;
+ __TIMSK4._OCIE4B = false;
+ __TIMSK4._OCIE4C = false;
+ __TIMSK4.reserved1 = false;
+ __TIMSK4._ICIE4 = false;
+ __TIMSK4.reserved2 = false;
+ dwrite(_TIMSK4, __TIMSK4);
+
+ TIMSK5_reg_t __TIMSK5;
+ __TIMSK5._TOIE5 = false;
+ __TIMSK5._OCIE5A = false;
+ __TIMSK5._OCIE5B = false;
+ __TIMSK5._OCIE5C = false;
+ __TIMSK5.reserved1 = 0;
+ __TIMSK5._ICIE5 = false;
+ __TIMSK5.reserved2 = 0;
+ dwrite(_TIMSK5, __TIMSK5);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ TIFR1_reg_t __TIFR1;
+ __TIFR1._TOV1 = false;
+ __TIFR1._OCF1A = false;
+ __TIFR1._OCF1B = false;
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ __TIFR1._OCF1C = false;
+ #endif
+ __TIFR1.reserved1 = 0;
+ __TIFR1._ICF1 = false;
+ __TIFR1.reserved2 = 0;
+ dwrite(_TIFR1, __TIFR1);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__)
+ TIFR3_reg_t __TIFR3;
+ __TIFR3._TOV3 = false;
+ __TIFR3._OCF3A = false;
+ __TIFR3._OCF3B = false;
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ __TIFR3._OCF3C = false;
+ #endif
+ __TIFR3.reserved1 = 0;
+ __TIFR3._ICF3 = false;
+ __TIFR3.reserved2 = 0;
+ dwrite(_TIFR3, __TIFR3);
+ #endif
+
+ #ifdef __AVR_TRM01__
+ TIFR4_reg_t __TIFR4;
+ __TIFR4._TOV4 = false;
+ __TIFR4._OCF4A = false;
+ __TIFR4._OCF4B = false;
+ __TIFR4._OCF4C = false;
+ __TIFR4.reserved1 = 0;
+ __TIFR4._ICF4 = false;
+ __TIFR4.reserved2 = 0;
+ dwrite(_TIFR4, __TIFR4);
+
+ TIFR5_reg_t __TIFR5;
+ __TIFR5._TOV5 = false;
+ __TIFR5._OCF5A = false;
+ __TIFR5._OCF5B = false;
+ __TIFR5._OCF5C = false;
+ __TIFR5.reserved1 = 0;
+ __TIFR5._ICF5 = false;
+ __TIFR5.reserved2 = 0;
+ dwrite(_TIFR5, __TIFR5);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ dwrite(_TIMER2, __TIMER_8bit);
+ #endif
+
+ #if defined(__AV_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ ASSR_reg_t __ASSR;
+ __ASSR._TCR2BUB = false;
+ __ASSR._TCR2AUB = false;
+ __ASSR._OCR2BUB = false;
+ __ASSR._OCR2AUB = false;
+ __ASSR._TCN2UB = false;
+ __ASSR._AS2 = false;
+ __ASSR._EXCLK = false;
+ __ASSR.reserved1 = 0;
+ dwrite(_ASSR, __ASSR);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ TIMSK2_reg_t __TIMSK2;
+ __TIMSK2._TOIE2 = false;
+ __TIMSK2._OCIE2A = false;
+ __TIMSK2._OCIE2B = false;
+ __TIMSK2.reserved1 = 0;
+ dwrite(_TIMSK2, __TIMSK2);
+
+ TIFR2_reg_t __TIFR2;
+ __TIFR2._TOV2 = false;
+ __TIFR2._OCF2A = false;
+ __TIFR2._OCF2B = false;
+ __TIFR2.reserved1 = 0;
+ dwrite(_TIFR2, __TIFR2);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ SPCR_reg_t __SPCR;
+ __SPCR._SPR = 0;
+ __SPCR._CPHA = 0;
+ __SPCR._CPOL = 0;
+ __SPCR._MSTR = 0;
+ __SPCR._DORD = 0;
+ __SPCR._SPE = false;
+ __SPCR._SPIE = false;
+ dwrite(_SPCR, __SPCR);
+
+ SPSR_reg_t __SPSR;
+ __SPSR._SPI2X = false;
+ __SPSR.reserved1 = 0;
+ __SPSR._WCOL = false;
+ __SPSR._SPIF = false;
+ dwrite(_SPSR, __SPSR);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ USART_dev_t USART;
+ USART._UDRn = 0;
+ USART._UCSRnA._MPCM = false;
+ USART._UCSRnA._U2X = false;
+ USART._UCSRnA._UPE = false;
+ USART._UCSRnA._DOR = false;
+ USART._UCSRnA._FE = false;
+ USART._UCSRnA._UDRE = true;
+ USART._UCSRnA._TXC = false;
+ USART._UCSRnA._RXC = false;
+ USART._UCSRnB._TXB8 = false;
+ USART._UCSRnB._RXB8 = false;
+ USART._UCSRnB._UCSZn2 = false;
+ USART._UCSRnB._TXEN = false;
+ USART._UCSRnB._RXEN = false;
+ USART._UCSRnB._UDRIE = false;
+ USART._UCSRnB._TXCIE = false;
+ USART._UCSRnB._RXCIE = false;
+ USART._UCSRnC._UCPOL = false;
+ USART._UCSRnC._UCSZn0 = 1;
+ USART._UCSRnC._UCSZn1 = 1;
+ USART._UCSRnC._USBS = false;
+ USART._UCSRnC._UPM = 0;
+ USART._UCSRnC._UPM = 0;
+ USART._UCSRnC._UMSEL = 0;
+ USART._UBRRn._UBRR = 0;
+ USART._UBRRn.reserved1 = 0;
+ #endif
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__)
+ dwrite(USART0, USART);
+ #endif
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__)
+ dwrite(USART1, USART);
+ #endif
+ #ifdef __AVR_TRM01__
+ dwrite(USART2, USART);
+ dwrite(USART3, USART);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ dwrite(_TWBR, (uint8_t)0);
+
+ TWCR_reg_t __TWCR;
+ __TWCR._TWIE = false;
+ __TWCR.reserved1 = 0;
+ __TWCR._TWEN = false;
+ __TWCR._TWWC = false;
+ __TWCR._TWSTO = false;
+ __TWCR._TWSTA = false;
+ __TWCR._TWEA = false;
+ __TWCR._TWINT = false;
+ dwrite(_TWCR, __TWCR);
+
+ TWSR_reg_t __TWSR;
+ __TWSR._TWPS0 = false;
+ __TWSR._TWPS1 = false;
+ __TWSR.reserved1 = 0;
+ __TWSR._TWS3 = 1;
+ __TWSR._TWS4 = 1;
+ __TWSR._TWS5 = 1;
+ __TWSR._TWS6 = 1;
+ __TWSR._TWS7 = 1;
+ dwrite(_TWSR, __TWSR);
+
+ dwrite(_TWDR, (uint8_t)0xFF);
+
+ TWAR_reg_t __TWAR;
+ __TWAR._TWGCE = false;
+ __TWAR._TWA = 0x7F;
+ dwrite(_TWAR, __TWAR);
+
+ TWAMR_reg_t __TWAMR;
+ __TWAMR.reserved1 = false;
+ __TWAMR._TWAM = 0;
+ dwrite(_TWAMR, __TWAMR);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ ADCSRB_reg_t __ADCSRB;
+ __ADCSRB._ADTS = 0;
+ #ifdef __AVR_TRM01__
+ __ADCSRB._MUX5 = 0;
+ #endif
+ __ADCSRB.reserved1 = 0;
+ __ADCSRB._ACME = false;
+ __ADCSRB.reserved2 = 0;
+ dwrite(_ADCSRB, __ADCSRB);
+
+ ACSR_reg_t __ACSR;
+ __ACSR._ACIS = 0;
+ __ACSR._ACIC = false;
+ __ACSR._ACIE = false;
+ __ACSR._ACI = false;
+ __ACSR._ACO = false;
+ __ACSR._ACBG = false;
+ __ACSR._ACD = false;
+ dwrite(_ACSR, __ACSR);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ DIDR1_reg_t __DIDR1;
+ __DIDR1._AIN0D = false;
+ __DIDR1._AIN1D = false;
+ __DIDR1.reserved1 = false;
+ dwrite(_DIDR1, __DIDR1);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ ADMUX_reg_t __ADMUX;
+ __ADMUX._MUX0 = 0;
+ __ADMUX._MUX1 = 0;
+ __ADMUX._MUX2 = 0;
+ __ADMUX._MUX3 = 0;
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__)
+ __ADMUX._MUX4 = 0;
+ #elif defined(__AVR_TRM03__)
+ __ADMUX.reserved1 = 0;
+ #endif
+ __ADMUX._ADLAR = 0;
+ __ADMUX._REFS0 = 0;
+ __ADMUX._REFS1 = 0;
+ dwrite(_ADMUX, __ADMUX);
+
+ ADCSRA_reg_t __ADCSRA;
+ __ADCSRA._ADPS = 0;
+ __ADCSRA._ADIE = false;
+ __ADCSRA._ADIF = false;
+ __ADCSRA._ADATE = false;
+ __ADCSRA._ADSC = false;
+ __ADCSRA._ADEN = false;
+ dwrite(_ADCSRA, __ADCSRA);
+
+ dwrite(_ADC, (uint16_t)0);
+ #endif
+
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ SPMCSR_reg_t __SPMCSR;
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__)
+ __SPMCSR._SPMEN = false;
+ __SPMCSR._PGERS = false;
+ __SPMCSR._PGWRT = false;
+ __SPMCSR._BLBSET = false;
+ __SPMCSR._RWWSRE = false;
+ __SPMCSR._SIGRD = false;
+ __SPMCSR._RWWSB = false;
+ __SPMCSR._SPMIE = false;
+ #elif defined(__AVR_TRM03__)
+ #if defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega328P__)
+ __SPMCSR._SPMEN = false;
+ __SPMCSR._PGERS = false;
+ __SPMCSR._PGWRT = false;
+ __SPMCSR._BLBSET = false;
+ __SPMCSR._RWWSRE = false;
+ __SPMCSR._SIGRD = false;
+ __SPMCSR._RWWSB = false;
+ __SPMCSR._SPMIE = false;
+ #else
+ __SPMCSR._SPMEN = false;
+ __SPMCSR._PGERS = false;
+ __SPMCSR._PGWRT = false;
+ __SPMCSR._BLBSET = false;
+ __SPMCSR.reserved1 = false;
+ __SPMCSR._SIGRD = false;
+ __SPMCSR.reserved2 = false;
+ __SPMCSR._SPMIE = false;
+ #endif
+ #endif
+ dwrite(_SPMCSR, __SPMCSR);
+ #endif
+
+ // TODO: add the __AVR_TRM04__ initializations, if required (mostly USB related)
+}
+
+struct pin_dev_state_t {
+ #ifdef __AVR_TRM01__
+ uint8_t _SRE : 1; // port A
+ uint8_t _COM0B : 2;
+ uint8_t _COM1A : 2;
+ uint8_t _COM1B : 2;
+ uint8_t _COM1C : 2;
+ uint8_t _COM2A : 2;
+ uint8_t _COM2B : 2;
+ uint8_t _COM3A : 2;
+ uint8_t _COM3B : 2;
+ uint8_t _COM3C : 2;
+ uint8_t _COM4A : 2;
+ uint8_t _COM4B : 2;
+ uint8_t _COM4C : 2;
+ uint8_t _COM5A : 2;
+ uint8_t _COM5B : 2;
+ uint8_t _COM5C : 2;
+ uint8_t _PCIE0 : 1;
+ uint8_t _PCIE1 : 1; // INTn
+ uint8_t _PCIE2 : 1;
+ uint8_t _SPE : 1;
+ uint8_t _USART0_RXEN : 1;
+ uint8_t _USART0_TXEN : 1;
+ uint8_t _USART1_RXEN : 1;
+ uint8_t _USART1_TXEN : 1;
+ uint8_t _USART2_RXEN : 1;
+ uint8_t _USART2_TXEN : 1;
+ uint8_t _USART3_RXEN : 1;
+ uint8_t _USART3_TXEN : 1;
+ //uint8_t _JTAGEN : 1;
+ uint8_t _AS2 : 1;
+ #elif defined(__AVR_TRM02__)
+ uint8_t _PCIE0 : 1;
+ uint8_t _PCIE1 : 1;
+ uint8_t _PCIE2 : 1;
+ uint8_t _PCIE3 : 1;
+ uint8_t _ADC7D : 1;
+ uint8_t _ADC6D : 1;
+ uint8_t _ADC5D : 1;
+ uint8_t _ADC4D : 1;
+ uint8_t _ADC3D : 1;
+ uint8_t _ADC2D : 1;
+ uint8_t _ADC1D : 1;
+ uint8_t _ADC0D : 1;
+ uint8_t _SPE : 1;
+ uint8_t _COM0A : 2;
+ uint8_t _COM0B : 2;
+ uint8_t _COM2A : 2;
+ uint8_t _COM2B : 2;
+ uint8_t _COM1A : 2;
+ uint8_t _COM1B : 2;
+ //uint8_t _JTAGEN : 1;
+ uint8_t _AS2 : 1;
+ uint8_t _TWEN : 1;
+ uint8_t _USART1_TXEN : 1;
+ uint8_t _USART1_RXEN : 1;
+ uint8_t _USART0_TXEN : 1;
+ uint8_t _USART0_RXEN : 1;
+ #elif defined(__AVR_TRM03__)
+ uint8_t _AS2 : 1;
+ uint8_t _PCIE0 : 1;
+ uint8_t _PCIE1 : 1;
+ uint8_t _PCIE2 : 1;
+ uint8_t _SPE : 1;
+ uint8_t _COM2B : 2;
+ uint8_t _COM2A : 2;
+ uint8_t _COM1B : 2;
+ uint8_t _COM1A : 2;
+ uint8_t _COM0A : 2;
+ uint8_t _COM0B : 2;
+ uint8_t _TWEN : 1;
+ uint8_t _ADC7D : 1;
+ uint8_t _ADC6D : 1;
+ uint8_t _ADC5D : 1;
+ uint8_t _ADC4D : 1;
+ uint8_t _ADC3D : 1;
+ uint8_t _ADC2D : 1;
+ uint8_t _ADC1D : 1;
+ uint8_t _ADC0D : 1;
+ uint8_t _UMSEL : 2;
+ uint8_t _USART0_TXEN : 1;
+ uint8_t _USART0_RXEN : 1;
+ #elif defined(__AVR_TRM04__)
+ uint8_t _SRE : 1;
+ uint8_t _SPE : 1;
+ uint8_t _COM0B : 2;
+ uint8_t _COM1C : 2;
+ uint8_t _COM1B : 2;
+ uint8_t _COM1A : 2;
+ uint8_t _COM2A : 2;
+ uint8_t _COM2B : 2;
+ uint8_t _PCIE0 : 1;
+ uint8_t _USART1_RXEN : 1;
+ uint8_t _USART1_TXEN : 1;
+ uint8_t _TWEN : 1;
+ uint8_t _INT7 : 1;
+ uint8_t _INT6 : 1;
+ uint8_t _INT5 : 1;
+ uint8_t _INT4 : 1;
+ uint8_t _INT3 : 1;
+ uint8_t _INT2 : 1;
+ uint8_t _INT1 : 1;
+ uint8_t _INT0;
+ uint8_t _UVCONE : 1;
+ uint8_t _UIDE : 1;
+ //uint8_t _JTAGEN : 1;
+ #endif
+};
+
+// AVR ArduinoCore is written like a hack-job (random peripherals enabled all-the-time).
+
+enum class eATmegaPort {
+ #ifdef __AVR_TRM01__
+ PORT_A, PORT_B, PORT_C, PORT_D, PORT_E, PORT_F, PORT_G, PORT_H, PORT_J, PORT_K, PORT_L
+ #elif defined(__AVR_TRM02__)
+ PORT_A, PORT_B, PORT_C, PORT_D
+ #elif defined(__AVR_TRM03__)
+ PORT_B, PORT_C, PORT_D
+ #elif defined(__AVR_TRM04__)
+ PORT_A, PORT_B, PORT_C, PORT_D, PORT_E, PORT_F
+ #endif
+};
+
+struct ATmegaPinInfo {
+ eATmegaPort port;
+ uint8_t pinidx;
+};
+
+#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__)
+ #define _SPA_DIO_DDRA (eATmegaPort::PORT_A)
+#endif
+#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM03__) || defined(__AVR_TRM04__)
+ #define _SPA_DIO_DDRB (eATmegaPort::PORT_B)
+ #define _SPA_DIO_DDRC (eATmegaPort::PORT_C)
+ #define _SPA_DIO_DDRD (eATmegaPort::PORT_D)
+#endif
+#if defined(__AVR_TRM01__) || defined(__AVR_TRM04__)
+ #define _SPA_DIO_DDRE (eATmegaPort::PORT_E)
+ #define _SPA_DIO_DDRF (eATmegaPort::PORT_F)
+#endif
+#ifdef __AVR_TRM01__
+ #define _SPA_DIO_DDRG (eATmegaPort::PORT_G)
+ #define _SPA_DIO_DDRH (eATmegaPort::PORT_H)
+ #define _SPA_DIO_DDRJ (eATmegaPort::PORT_J)
+ #define _SPA_DIO_DDRK (eATmegaPort::PORT_K)
+ #define _SPA_DIO_DDRL (eATmegaPort::PORT_L)
+#endif
+
+#define __SPA_IFPORT_STMT(dr) if (ddrp == &D##dr) port = _SPA_DIO_D##dr;
+
+#ifdef _SPA_DIO_DDRA
+ #define _SPA_IFPORT_PORTA __SPA_IFPORT_STMT(DRA)
+#else
+ #define _SPA_IFPORT_PORTA
+#endif
+#ifdef _SPA_DIO_DDRB
+ #define _SPA_IFPORT_PORTB __SPA_IFPORT_STMT(DRB)
+#else
+ #define _SPA_IFPORT_PORTB
+#endif
+#ifdef _SPA_DIO_DDRC
+ #define _SPA_IFPORT_PORTC __SPA_IFPORT_STMT(DRC)
+#else
+ #define _SPA_IFPORT_PORTC
+#endif
+#ifdef _SPA_DIO_DDRD
+ #define _SPA_IFPORT_PORTD __SPA_IFPORT_STMT(DRD)
+#else
+ #define _SPA_IFPORT_PORTD
+#endif
+#ifdef _SPA_DIO_DDRE
+ #define _SPA_IFPORT_PORTE __SPA_IFPORT_STMT(DRE)
+#else
+ #define _SPA_IFPORT_PORTE
+#endif
+#ifdef _SPA_DIO_DDRF
+ #define _SPA_IFPORT_PORTF __SPA_IFPORT_STMT(DRF)
+#else
+ #define _SPA_IFPORT_PORTF
+#endif
+#ifdef _SPA_DIO_DDRG
+ #define _SPA_IFPORT_PORTG __SPA_IFPORT_STMT(DRG)
+#else
+ #define _SPA_IFPORT_PORTG
+#endif
+#ifdef _SPA_DIO_DDRH
+ #define _SPA_IFPORT_PORTH __SPA_IFPORT_STMT(DRH)
+#else
+ #define _SPA_IFPORT_PORTH
+#endif
+#ifdef _SPA_DIO_DDRJ
+ #define _SPA_IFPORT_PORTJ __SPA_IFPORT_STMT(DRJ)
+#else
+ #define _SPA_IFPORT_PORTJ
+#endif
+#ifdef _SPA_DIO_DDRK
+ #define _SPA_IFPORT_PORTK __SPA_IFPORT_STMT(DRK)
+#else
+ #define _SPA_IFPORT_PORTK
+#endif
+#ifdef _SPA_DIO_DDRL
+ #define _SPA_IFPORT_PORTL __SPA_IFPORT_STMT(DRL)
+#else
+ #define _SPA_IFPORT_PORTL
+#endif
+
+#define _SPA_RESOLVE_DIO(ddr) _SPA_DIO_##ddr
+#define _SPA_DIOn_PORTRET(val, n) if (val == n) { \
+ auto *ddrp = &DIO##n##_DDR; \
+ eATmegaPort port; \
+ _SPA_IFPORT_PORTA \
+ _SPA_IFPORT_PORTB \
+ _SPA_IFPORT_PORTC \
+ _SPA_IFPORT_PORTD \
+ _SPA_IFPORT_PORTE \
+ _SPA_IFPORT_PORTF \
+ _SPA_IFPORT_PORTG \
+ _SPA_IFPORT_PORTH \
+ _SPA_IFPORT_PORTJ \
+ _SPA_IFPORT_PORTK \
+ _SPA_IFPORT_PORTL \
+ return { port, DIO##n##_PIN }; \
+ }
+
+inline ATmegaPinInfo _ATmega_getPinInfo(uint8_t pin) {
+ #if DIO_NUM > 0
+ _SPA_DIOn_PORTRET(pin, 0)
+ #endif
+ #if DIO_NUM > 1
+ _SPA_DIOn_PORTRET(pin, 1)
+ #endif
+ #if DIO_NUM > 2
+ _SPA_DIOn_PORTRET(pin, 2)
+ #endif
+ #if DIO_NUM > 3
+ _SPA_DIOn_PORTRET(pin, 3)
+ #endif
+ #if DIO_NUM > 4
+ _SPA_DIOn_PORTRET(pin, 4)
+ #endif
+ #if DIO_NUM > 5
+ _SPA_DIOn_PORTRET(pin, 5)
+ #endif
+ #if DIO_NUM > 6
+ _SPA_DIOn_PORTRET(pin, 6)
+ #endif
+ #if DIO_NUM > 7
+ _SPA_DIOn_PORTRET(pin, 7)
+ #endif
+ #if DIO_NUM > 8
+ _SPA_DIOn_PORTRET(pin, 8)
+ #endif
+ #if DIO_NUM > 9
+ _SPA_DIOn_PORTRET(pin, 9)
+ #endif
+
+ #if DIO_NUM > 10
+ _SPA_DIOn_PORTRET(pin, 10)
+ #endif
+ #if DIO_NUM > 11
+ _SPA_DIOn_PORTRET(pin, 11)
+ #endif
+ #if DIO_NUM > 12
+ _SPA_DIOn_PORTRET(pin, 12)
+ #endif
+ #if DIO_NUM > 13
+ _SPA_DIOn_PORTRET(pin, 13)
+ #endif
+ #if DIO_NUM > 14
+ _SPA_DIOn_PORTRET(pin, 14)
+ #endif
+ #if DIO_NUM > 15
+ _SPA_DIOn_PORTRET(pin, 15)
+ #endif
+ #if DIO_NUM > 16
+ _SPA_DIOn_PORTRET(pin, 16)
+ #endif
+ #if DIO_NUM > 17
+ _SPA_DIOn_PORTRET(pin, 17)
+ #endif
+ #if DIO_NUM > 18
+ _SPA_DIOn_PORTRET(pin, 18)
+ #endif
+ #if DIO_NUM > 19
+ _SPA_DIOn_PORTRET(pin, 19)
+ #endif
+
+ #if DIO_NUM > 20
+ _SPA_DIOn_PORTRET(pin, 20)
+ #endif
+ #if DIO_NUM > 21
+ _SPA_DIOn_PORTRET(pin, 21)
+ #endif
+ #if DIO_NUM > 22
+ _SPA_DIOn_PORTRET(pin, 22)
+ #endif
+ #if DIO_NUM > 23
+ _SPA_DIOn_PORTRET(pin, 23)
+ #endif
+ #if DIO_NUM > 24
+ _SPA_DIOn_PORTRET(pin, 24)
+ #endif
+ #if DIO_NUM > 25
+ _SPA_DIOn_PORTRET(pin, 25)
+ #endif
+ #if DIO_NUM > 26
+ _SPA_DIOn_PORTRET(pin, 26)
+ #endif
+ #if DIO_NUM > 27
+ _SPA_DIOn_PORTRET(pin, 27)
+ #endif
+ #if DIO_NUM > 28
+ _SPA_DIOn_PORTRET(pin, 28)
+ #endif
+ #if DIO_NUM > 29
+ _SPA_DIOn_PORTRET(pin, 29)
+ #endif
+
+ #if DIO_NUM > 30
+ _SPA_DIOn_PORTRET(pin, 30)
+ #endif
+ #if DIO_NUM > 31
+ _SPA_DIOn_PORTRET(pin, 31)
+ #endif
+ #if DIO_NUM > 32
+ _SPA_DIOn_PORTRET(pin, 32)
+ #endif
+ #if DIO_NUM > 33
+ _SPA_DIOn_PORTRET(pin, 33)
+ #endif
+ #if DIO_NUM > 34
+ _SPA_DIOn_PORTRET(pin, 34)
+ #endif
+ #if DIO_NUM > 35
+ _SPA_DIOn_PORTRET(pin, 35)
+ #endif
+ #if DIO_NUM > 36
+ _SPA_DIOn_PORTRET(pin, 36)
+ #endif
+ #if DIO_NUM > 37
+ _SPA_DIOn_PORTRET(pin, 37)
+ #endif
+ #if DIO_NUM > 38
+ _SPA_DIOn_PORTRET(pin, 38)
+ #endif
+ #if DIO_NUM > 39
+ _SPA_DIOn_PORTRET(pin, 39)
+ #endif
+
+ #if DIO_NUM > 40
+ _SPA_DIOn_PORTRET(pin, 40)
+ #endif
+ #if DIO_NUM > 41
+ _SPA_DIOn_PORTRET(pin, 41)
+ #endif
+ #if DIO_NUM > 42
+ _SPA_DIOn_PORTRET(pin, 42)
+ #endif
+ #if DIO_NUM > 43
+ _SPA_DIOn_PORTRET(pin, 43)
+ #endif
+ #if DIO_NUM > 44
+ _SPA_DIOn_PORTRET(pin, 44)
+ #endif
+ #if DIO_NUM > 45
+ _SPA_DIOn_PORTRET(pin, 45)
+ #endif
+ #if DIO_NUM > 46
+ _SPA_DIOn_PORTRET(pin, 46)
+ #endif
+ #if DIO_NUM > 47
+ _SPA_DIOn_PORTRET(pin, 47)
+ #endif
+ #if DIO_NUM > 48
+ _SPA_DIOn_PORTRET(pin, 48)
+ #endif
+ #if DIO_NUM > 49
+ _SPA_DIOn_PORTRET(pin, 49)
+ #endif
+
+ #if DIO_NUM > 50
+ _SPA_DIOn_PORTRET(pin, 50)
+ #endif
+ #if DIO_NUM > 51
+ _SPA_DIOn_PORTRET(pin, 51)
+ #endif
+ #if DIO_NUM > 52
+ _SPA_DIOn_PORTRET(pin, 52)
+ #endif
+ #if DIO_NUM > 53
+ _SPA_DIOn_PORTRET(pin, 53)
+ #endif
+ #if DIO_NUM > 54
+ _SPA_DIOn_PORTRET(pin, 54)
+ #endif
+ #if DIO_NUM > 55
+ _SPA_DIOn_PORTRET(pin, 55)
+ #endif
+ #if DIO_NUM > 56
+ _SPA_DIOn_PORTRET(pin, 56)
+ #endif
+ #if DIO_NUM > 57
+ _SPA_DIOn_PORTRET(pin, 57)
+ #endif
+ #if DIO_NUM > 58
+ _SPA_DIOn_PORTRET(pin, 58)
+ #endif
+ #if DIO_NUM > 59
+ _SPA_DIOn_PORTRET(pin, 59)
+ #endif
+
+ #if DIO_NUM > 60
+ _SPA_DIOn_PORTRET(pin, 60)
+ #endif
+ #if DIO_NUM > 61
+ _SPA_DIOn_PORTRET(pin, 61)
+ #endif
+ #if DIO_NUM > 62
+ _SPA_DIOn_PORTRET(pin, 62)
+ #endif
+ #if DIO_NUM > 63
+ _SPA_DIOn_PORTRET(pin, 63)
+ #endif
+ #if DIO_NUM > 64
+ _SPA_DIOn_PORTRET(pin, 64)
+ #endif
+ #if DIO_NUM > 65
+ _SPA_DIOn_PORTRET(pin, 65)
+ #endif
+ #if DIO_NUM > 66
+ _SPA_DIOn_PORTRET(pin, 66)
+ #endif
+ #if DIO_NUM > 67
+ _SPA_DIOn_PORTRET(pin, 67)
+ #endif
+ #if DIO_NUM > 68
+ _SPA_DIOn_PORTRET(pin, 68)
+ #endif
+ #if DIO_NUM > 69
+ _SPA_DIOn_PORTRET(pin, 69)
+ #endif
+
+ #if DIO_NUM > 70
+ _SPA_DIOn_PORTRET(pin, 70)
+ #endif
+ #if DIO_NUM > 71
+ _SPA_DIOn_PORTRET(pin, 71)
+ #endif
+ #if DIO_NUM > 72
+ _SPA_DIOn_PORTRET(pin, 72)
+ #endif
+ #if DIO_NUM > 73
+ _SPA_DIOn_PORTRET(pin, 73)
+ #endif
+ #if DIO_NUM > 74
+ _SPA_DIOn_PORTRET(pin, 74)
+ #endif
+ #if DIO_NUM > 75
+ _SPA_DIOn_PORTRET(pin, 75)
+ #endif
+ #if DIO_NUM > 76
+ _SPA_DIOn_PORTRET(pin, 76)
+ #endif
+ #if DIO_NUM > 77
+ _SPA_DIOn_PORTRET(pin, 77)
+ #endif
+ #if DIO_NUM > 78
+ _SPA_DIOn_PORTRET(pin, 78)
+ #endif
+ #if DIO_NUM > 79
+ _SPA_DIOn_PORTRET(pin, 79)
+ #endif
+
+ #if DIO_NUM > 80
+ _SPA_DIOn_PORTRET(pin, 80)
+ #endif
+ #if DIO_NUM > 81
+ _SPA_DIOn_PORTRET(pin, 81)
+ #endif
+ #if DIO_NUM > 82
+ _SPA_DIOn_PORTRET(pin, 82)
+ #endif
+ #if DIO_NUM > 83
+ _SPA_DIOn_PORTRET(pin, 83)
+ #endif
+ #if DIO_NUM > 84
+ _SPA_DIOn_PORTRET(pin, 84)
+ #endif
+ #if DIO_NUM > 85
+ _SPA_DIOn_PORTRET(pin, 85)
+ #endif
+ #if DIO_NUM > 86
+ _SPA_DIOn_PORTRET(pin, 86)
+ #endif
+ #if DIO_NUM > 87
+ _SPA_DIOn_PORTRET(pin, 87)
+ #endif
+ #if DIO_NUM > 88
+ _SPA_DIOn_PORTRET(pin, 88)
+ #endif
+ #if DIO_NUM > 89
+ _SPA_DIOn_PORTRET(pin, 89)
+ #endif
+
+ // Default.
+ #if defined(__AVR_TRM01__) || defined(__AVR_TRM02__) || defined(__AVR_TRM04__)
+ return { eATmegaPort::PORT_A, 0 };
+ #elif defined(__AVR_TRM03__)
+ return { eATmegaPort::PORT_B, 0 };
+ #endif
+}
+
+enum class eATmegaPeripheral {
+ UNDEFINED,
+ #ifdef __AVR_TRM01__
+ PADC, PUSART0, PSPI, PTIM1, PTIM0, PTIM2, PTWI, PUSART1, PUSART2, PUSART3, PTIM3, PTIM4, PTIM5
+ #elif defined(__AVR_TRM02__)
+ PADC, PUSART0, PSPI, PTIM1, PUSART1, PTIM0, PTIM2, PTWI, PTIM3
+ #elif defined(__AVR_TRM03__)
+ PADC, PUSART0, PSPI, PTIM1, PTIM0, PTIM2, PTWI
+ #elif defined(__AVR_TRM04__)
+ PADC, PSPI, PTIM1, PTIM0, PTIM2, PTWI, PUSART1, PTIM3, PUSB
+ #endif
+ , NUM_PERIPHERALS
+};
+
+enum class eATmegaPinFunc : uint8_t {
+ #ifdef __AVR_TRM01__
+ EXTMEM_AD15, EXTMEM_AD14, EXTMEM_AD13, EXTMEM_AD12, EXTMEM_AD11, EXTMEM_AD10, EXTMEM_AD9, EXTMEM_AD8,
+ EXTMEM_AD7, EXTMEM_AD6, EXTMEM_AD5, EXTMEM_AD4, EXTMEM_AD3, EXTMEM_AD2, EXTMEM_AD1, EXTMEM_AD0,
+ EXTMEM_ALE, EXTMEM_RD, EXTMEM_WR,
+ TOC0A, TOC0B, TOC1A, TOC1B, TOC1C, TOC2A, TOC2B, TOC3C, TOC3B, TOC3A, TOC4C, TOC4B, TOC4A, TOC5C, TOC5B, TOC5A,
+ EINT7, EINT6, EINT5, EINT4, EINT3, EINT2, EINT1, EINT0,
+ PCI0, PCI1, PCI2, PCI3, PCI4, PCI5, PCI6, PCI7,
+ PCI8, PCI9, PCI10, PCI11, PCI12, PCI13, PCI14, PCI15,
+ PCI16, PCI17, PCI18, PCI19, PCI20, PCI21, PCI22, PCI23,
+ SPI_MISO, SPI_MOSI, SPI_SCK, SPI_CS,
+ TOSC1, TOSC2,
+ TIMER0_CLKI, TIMER1_CLKI, TIMER3_CLKI, TIMER4_CLKI, TIMER5_CLKI,
+ TIMER1_ICP, TIMER3_ICP, TIMER5_ICP, TIMER4_ICP,
+ USART0_CLK, USART1_CLK, USART2_CLK, USART3_CLK,
+ USART0_TXD, USART0_RXD, USART1_TXD, USART1_RXD, USART2_TXD, USART2_RXD, USART3_TXD, USART3_RXD,
+ TWI_SDA, TWI_CLK,
+ CLK0, PDO, PDI,
+ AIN0, AIN1,
+ ADC15, ADC14, ADC13, ADC12, ADC11, ADC10, ADC9, ADC8,
+ ADC7, ADC6, ADC5, ADC4, ADC3, ADC2, ADC1, ADC0
+ #elif defined(__AVR_TRM02__)
+ ADC7, ADC6, ADC5, ADC4, ADC3, ADC2, ADC1, ADC0,
+ SPI_SCK, SPI_MISO, SPI_MOSI, SPI_CS,
+ PCI31, PCI30, PCI29, PCI28, PCI27, PCI26, PCI25, PCI24,
+ PCI23, PCI22, PCI21, PCI20, PCI19, PCI18, PCI17, PCI16,
+ PCI15, PCI14, PCI13, PCI12, PCI11, PCI10, PCI9, PCI8,
+ PCI7, PCI6, PCI5, PCI4, PCI3, PCI2, PCI1, PCI0,
+ EINT2, EINT1, EINT0,
+ TIMER3_ICP,
+ TIMER3_ECI, TIMER1_ECI, TIMER0_ECI,
+ TIMER1_ICP,
+ TOC3B, TOC3A, TOC2A, TOC2B, TOC1A, TOC1B, TOC0B, TOC0A,
+ AIN1, AIN0,
+ USART0_CLK, USART1_CLK,
+ USART0_TXD, USART0_RXD, USART1_TXD, USART1_RXD,
+ CLK0,
+ TOSC2, TOSC1,
+ TWI_SDA, TWI_CLK
+ #elif defined(__AVR_TRM03__)
+ ADC5, ADC4, ADC3, ADC2, ADC1, ADC0,
+ XTAL2, XTAL1,
+ TOSC2, TOSC1,
+ SPI_SCK, SPI_MISO, SPI_MOSI, SPI_CS,
+ TOC2B, TOC2A, TOC1B, TOC1A, TOC0A, TOC0B,
+ TIMER1_ICP,
+ TIMER1_ECI, TIMER0_ECI,
+ TWI_CLK, TWI_SDA,
+ PCI23, PCI22, PCI21, PCI20, PCI19, PCI18, PCI17, PCI16,
+ PCI14, PCI13, PCI12, PCI11, PCI10, PCI9, PCI8,
+ PCI7, PCI6, PCI5, PCI4, PCI3, PCI2, PCI1, PCI0,
+ CLK0,
+ AIN1, AIN0,
+ USART_CLK,
+ USART_TXD, USART_RXD,
+ EINT1, EINT0
+ #elif defined(__AVR_TRM04__)
+ EXTMEM_AD15, EXTMEM_AD14, EXTMEM_AD13, EXTMEM_AD12, EXTMEM_AD11, EXTMEM_AD10, EXTMEM_AD9, EXTMEM_AD8,
+ EXTMEM_AD7, EXTMEM_AD6, EXTMEM_AD5, EXTMEM_AD4, EXTMEM_AD3, EXTMEM_AD2, EXTMEM_AD1, EXTMEM_AD0,
+ EXTMEM_ALE, EXTMEM_RD, EXTMEM_WR,
+ TOC0B, TOC0A, TOC1C, TOC1B, TOC1A, TOC2B, TOC2A, TOC3A, TOC3B, TOC3C,
+ CLK0, PDO, PDI,
+ SPI_MISO, SPI_MOSI, SPI_SCK, SPI_CS,
+ TIMER3_ICP, TIMER1_ICP,
+ TIMER3_CLKI, TIMER0_CLKI, TIMER1_CLKI,
+ USART1_CLK, USART1_TXD, USART1_RXD,
+ EINT7, EINT6, EINT5, EINT4, EINT3, EINT2, EINT1, EINT0,
+ PCI7, PCI6, PCI5, PCI4, PCI3, PCI2, PCI1, PCI0,
+ TWI_SDA, TWI_CLK,
+ AIN1, AIN0,
+ TOSC2,
+ UID, UVCON,
+ ADC7, ADC6, ADC5, ADC4, ADC3, ADC2, ADC1, ADC0
+ #endif
+ , NUM_FUNCS
+};
+
+#ifndef countof
+ #define countof(x) (sizeof(x) / sizeof(*x))
+#endif
+
+struct ATmegaPinFunctions {
+ inline ATmegaPinFunctions(const eATmegaPinFunc *funcs, uint8_t cnt) noexcept : funcs(funcs), cnt(cnt) {}
+ inline ATmegaPinFunctions() = default;
+ inline ATmegaPinFunctions(const ATmegaPinFunctions&) = default;
+
+ const eATmegaPinFunc *funcs = nullptr;
+ uint8_t cnt = 0;
+
+ inline bool hasFunc(eATmegaPinFunc query) const {
+ for (uint8_t n = 0; n < this->cnt; n++) {
+ eATmegaPinFunc func = this->funcs[n];
+ if (func == query) return true;
+ }
+ return false;
+ }
+ template
+ inline bool hasFunc(eATmegaPinFunc func, otherItemType&&... items) const {
+ return hasFunc(func) || hasFunc(((otherItemType&&)items)...);
+ }
+
+ template
+ inline void iterate(callbackType&& cb) const {
+ for (uint8_t n = 0; n < this->cnt; n++) {
+ eATmegaPinFunc func = this->funcs[n];
+ cb(func);
+ }
+ }
+};
+
+ATmegaPinFunctions _ATmega_getPinFunctions(int pin);
+
+struct ATmegaPinFuncSet {
+ inline ATmegaPinFuncSet() noexcept {
+ for (bool& f : this->funcs) f = false;
+ }
+ template
+ inline ATmegaPinFuncSet(eATmegaPinFunc func, funcItemType&&... items) noexcept : ATmegaPinFuncSet() {
+ add(func, ((funcItemType&&)items)...);
+ }
+ template
+ inline ATmegaPinFuncSet(int pin, funcItemType&&... items) noexcept : ATmegaPinFuncSet() {
+ addFromPin(pin, ((funcItemType&&)items)...);
+ }
+ inline ATmegaPinFuncSet(const ATmegaPinFuncSet&) = default;
+
+ inline void add(eATmegaPinFunc value) noexcept {
+ this->funcs[(uint8_t)value] = true;
+ }
+ template
+ inline void add(eATmegaPinFunc value, funcItemType&&... items) {
+ add(value);
+ add(((eATmegaPinFunc&&)items)...);
+ }
+
+ inline void addFromPin(int pin) noexcept {
+ ATmegaPinFunctions funcs = _ATmega_getPinFunctions(pin);
+ funcs.iterate(
+ [this]( eATmegaPinFunc func ) noexcept { this->add(func); }
+ );
+ }
+ template
+ inline void addFromPin(int pin, itemType&&... items) noexcept {
+ addFromPin(pin);
+ addFromPin(((itemType&&)items)...);
+ }
+
+ inline bool hasFunc(eATmegaPinFunc value) const noexcept {
+ return this->funcs[(uint8_t)value];
+ }
+
+ inline bool hasAnyFunc() const noexcept { return false; }
+ template
+ inline bool hasAnyFunc(funcItem&& item, otherFuncItem&&... funcs) const noexcept {
+ return hasFunc(item) || hasAnyFunc(((otherFuncItem&&)funcs)...);
+ }
+
+ template
+ inline void iterate(callbackType&& cb) const {
+ for (uint8_t n = 1; n < countof(this->funcs); n++) {
+ const bool& f = this->funcs[n];
+ if (f) cb((eATmegaPinFunc)n);
+ }
+ }
+
+private:
+ bool funcs[(uint8_t)eATmegaPinFunc::NUM_FUNCS];
+};
+
+inline void _ATmega_setPeripheralPower(eATmegaPeripheral peri, bool fullPower) {
+ bool reducePower = (fullPower == false);
+ switch(peri) {
+ #ifdef __AVR_TRM01__
+ case eATmegaPeripheral::PADC: _PRR0._PRADC = reducePower; break;
+ case eATmegaPeripheral::PUSART0: _PRR0._PRUSART0 = reducePower; break;
+ case eATmegaPeripheral::PSPI: _PRR0._PRSPI = reducePower; break;
+ case eATmegaPeripheral::PTIM1: _PRR0._PRTIM1 = reducePower; break;
+ case eATmegaPeripheral::PTIM0: _PRR0._PRTIM0 = reducePower; break;
+ case eATmegaPeripheral::PTIM2: _PRR0._PRTIM2 = reducePower; break;
+ case eATmegaPeripheral::PTWI: _PRR0._PRTWI = reducePower; break;
+ case eATmegaPeripheral::PUSART1: _PRR1._PRUSART1 = reducePower; break;
+ case eATmegaPeripheral::PUSART2: _PRR1._PRUSART2 = reducePower; break;
+ case eATmegaPeripheral::PUSART3: _PRR1._PRUSART3 = reducePower; break;
+ case eATmegaPeripheral::PTIM3: _PRR1._PRTIM3 = reducePower; break;
+ case eATmegaPeripheral::PTIM4: _PRR1._PRTIM4 = reducePower; break;
+ case eATmegaPeripheral::PTIM5: _PRR1._PRTIM5 = reducePower; break;
+ #elif defined(__AVR_TRM02__)
+ case eATmegaPeripheral::PADC: _PRR0._PRADC = reducePower; break;
+ case eATmegaPeripheral::PUSART0: _PRR0._PRUSART0 = reducePower; break;
+ case eATmegaPeripheral::PSPI: _PRR0._PRSPI = reducePower; break;
+ case eATmegaPeripheral::PTIM1: _PRR0._PRTIM1 = reducePower; break;
+ case eATmegaPeripheral::PUSART1: _PRR0._PRUSART1 = reducePower; break;
+ case eATmegaPeripheral::PTIM0: _PRR0._PRTIM0 = reducePower; break;
+ case eATmegaPeripheral::PTIM2: _PRR0._PRTIM2 = reducePower; break;
+ case eATmegaPeripheral::PTWI: _PRR0._PRTWI = reducePower; break;
+ case eATmegaPeripheral::PTIM3: _PRR1._PRTIM3 = reducePower; break;
+ #elif defined(__AVR_TRM03__)
+ case eATmegaPeripheral::PADC: _PRR0._PRADC = reducePower; break;
+ case eATmegaPeripheral::PUSART0: _PRR0._PRUSART0 = reducePower; break;
+ case eATmegaPeripheral::PSPI: _PRR0._PRSPI = reducePower; break;
+ case eATmegaPeripheral::PTIM1: _PRR0._PRTIM1 = reducePower; break;
+ case eATmegaPeripheral::PTIM0: _PRR0._PRTIM0 = reducePower; break;
+ case eATmegaPeripheral::PTIM2: _PRR0._PRTIM2 = reducePower; break;
+ case eATmegaPeripheral::PTWI: _PRR0._PRTWI = reducePower; break;
+ #elif defined(__AVR_TRM04__)
+ case eATmegaPeripheral::PADC: _PRR0._PRADC = reducePower; break;
+ case eATmegaPeripheral::PSPI: _PRR0._PRSPI = reducePower; break;
+ case eATmegaPeripheral::PTIM1: _PRR0._PRTIM1 = reducePower; break;
+ case eATmegaPeripheral::PTIM0: _PRR0._PRTIM0 = reducePower; break;
+ case eATmegaPeripheral::PTIM2: _PRR0._PRTIM2 = reducePower; break;
+ case eATmegaPeripheral::PTWI: _PRR0._PRTWI = reducePower; break;
+ case eATmegaPeripheral::PUSART1: _PRR1._PRUSART1 = reducePower; break;
+ case eATmegaPeripheral::PTIM3: _PRR1._PRTIM3 = reducePower; break;
+ case eATmegaPeripheral::PUSB: _PRR1._PRUSB = reducePower; break;
+ #endif
+ case eATmegaPeripheral::UNDEFINED: case eATmegaPeripheral::NUM_PERIPHERALS: break;
+ }
+}
+
+inline bool _ATmega_getPeripheralPower(eATmegaPeripheral peri) {
+ switch(peri) {
+ #ifdef __AVR_TRM01__
+ case eATmegaPeripheral::PADC: return _PRR0._PRADC == false;
+ case eATmegaPeripheral::PUSART0: return _PRR0._PRUSART0 == false;
+ case eATmegaPeripheral::PSPI: return _PRR0._PRSPI == false;
+ case eATmegaPeripheral::PTIM1: return _PRR0._PRTIM1 == false;
+ case eATmegaPeripheral::PTIM0: return _PRR0._PRTIM0 == false;
+ case eATmegaPeripheral::PTIM2: return _PRR0._PRTIM2 == false;
+ case eATmegaPeripheral::PTWI: return _PRR0._PRTWI == false;
+ case eATmegaPeripheral::PUSART1: return _PRR1._PRUSART1 == false;
+ case eATmegaPeripheral::PUSART2: return _PRR1._PRUSART2 == false;
+ case eATmegaPeripheral::PUSART3: return _PRR1._PRUSART3 == false;
+ case eATmegaPeripheral::PTIM3: return _PRR1._PRTIM3 == false;
+ case eATmegaPeripheral::PTIM4: return _PRR1._PRTIM4 == false;
+ case eATmegaPeripheral::PTIM5: return _PRR1._PRTIM5 == false;
+ #elif defined(__AVR_TRM02__)
+ case eATmegaPeripheral::PADC: return _PRR0._PRADC == false;
+ case eATmegaPeripheral::PUSART0: return _PRR0._PRUSART0 == false;
+ case eATmegaPeripheral::PSPI: return _PRR0._PRSPI == false;
+ case eATmegaPeripheral::PTIM1: return _PRR0._PRTIM1 == false;
+ case eATmegaPeripheral::PUSART1: return _PRR0._PRUSART1 == false;
+ case eATmegaPeripheral::PTIM0: return _PRR0._PRTIM0 == false;
+ case eATmegaPeripheral::PTIM2: return _PRR0._PRTIM2 == false;
+ case eATmegaPeripheral::PTWI: return _PRR0._PRTWI == false;
+ case eATmegaPeripheral::PTIM3: return _PRR1._PRTIM3 == false;
+ #elif defined(__AVR_TRM03__)
+ case eATmegaPeripheral::PADC: return _PRR0._PRADC == false;
+ case eATmegaPeripheral::PUSART0: return _PRR0._PRUSART0 == false;
+ case eATmegaPeripheral::PSPI: return _PRR0._PRSPI == false;
+ case eATmegaPeripheral::PTIM1: return _PRR0._PRTIM1 == false;
+ case eATmegaPeripheral::PTIM0: return _PRR0._PRTIM0 == false;
+ case eATmegaPeripheral::PTIM2: return _PRR0._PRTIM2 == false;
+ case eATmegaPeripheral::PTWI: return _PRR0._PRTWI == false;
+ #elif defined(__AVR_TRM04__)
+ case eATmegaPeripheral::PADC: return _PRR0._PRADC == false;
+ case eATmegaPeripheral::PSPI: return _PRR0._PRSPI == false;
+ case eATmegaPeripheral::PTIM1: return _PRR0._PRTIM1 == false;
+ case eATmegaPeripheral::PTIM0: return _PRR0._PRTIM0 == false;
+ case eATmegaPeripheral::PTIM2: return _PRR0._PRTIM2 == false;
+ case eATmegaPeripheral::PTWI: return _PRR0._PRTWI == false;
+ case eATmegaPeripheral::PUSART1: return _PRR1._PRUSART1 == false;
+ case eATmegaPeripheral::PTIM3: return _PRR1._PRTIM3 == false;
+ case eATmegaPeripheral::PUSB: return _PRR1._PRUSB == false;
+ #endif
+ case eATmegaPeripheral::UNDEFINED: case eATmegaPeripheral::NUM_PERIPHERALS: break;
+ }
+ return false;
+}
+
+inline eATmegaPeripheral _ATmega_getPeripheralForFunc( eATmegaPinFunc func ) {
+ // In C++20 there is the "using-enum" statement. I wish we had C++20 over here...
+ //using enum eATmegaPinFunc
+ switch(func) {
+ #ifdef __AVR_TRM01__
+ case eATmegaPinFunc::TOC0A: case eATmegaPinFunc::TOC0B: return eATmegaPeripheral::PTIM0;
+ case eATmegaPinFunc::TOC1A: case eATmegaPinFunc::TOC1B: case eATmegaPinFunc::TOC1C: return eATmegaPeripheral::PTIM1;
+ case eATmegaPinFunc::TOC2A: case eATmegaPinFunc::TOC2B: return eATmegaPeripheral::PTIM2;
+ case eATmegaPinFunc::TOC3A: case eATmegaPinFunc::TOC3B: case eATmegaPinFunc::TOC3C: return eATmegaPeripheral::PTIM3;
+ case eATmegaPinFunc::TOC4A: case eATmegaPinFunc::TOC4B: case eATmegaPinFunc::TOC4C: return eATmegaPeripheral::PTIM4;
+ case eATmegaPinFunc::TOC5A: case eATmegaPinFunc::TOC5B: case eATmegaPinFunc::TOC5C: return eATmegaPeripheral::PTIM5;
+ case eATmegaPinFunc::SPI_MISO: case eATmegaPinFunc::SPI_MOSI: case eATmegaPinFunc::SPI_SCK: case eATmegaPinFunc::SPI_CS: return eATmegaPeripheral::PSPI;
+ case eATmegaPinFunc::TIMER0_CLKI: return eATmegaPeripheral::PTIM0;
+ case eATmegaPinFunc::TIMER1_CLKI: case eATmegaPinFunc::TIMER1_ICP: return eATmegaPeripheral::PTIM1;
+ case eATmegaPinFunc::TIMER3_CLKI: case eATmegaPinFunc::TIMER3_ICP: return eATmegaPeripheral::PTIM3;
+ case eATmegaPinFunc::TIMER4_CLKI: case eATmegaPinFunc::TIMER4_ICP: return eATmegaPeripheral::PTIM4;
+ case eATmegaPinFunc::TIMER5_CLKI: case eATmegaPinFunc::TIMER5_ICP: return eATmegaPeripheral::PTIM5;
+ case eATmegaPinFunc::USART0_CLK: case eATmegaPinFunc::USART0_TXD: case eATmegaPinFunc::USART0_RXD: return eATmegaPeripheral::PUSART0;
+ case eATmegaPinFunc::USART1_CLK: case eATmegaPinFunc::USART1_TXD: case eATmegaPinFunc::USART1_RXD: return eATmegaPeripheral::PUSART1;
+ case eATmegaPinFunc::USART2_CLK: case eATmegaPinFunc::USART2_TXD: case eATmegaPinFunc::USART2_RXD: return eATmegaPeripheral::PUSART2;
+ case eATmegaPinFunc::USART3_CLK: case eATmegaPinFunc::USART3_TXD: case eATmegaPinFunc::USART3_RXD: return eATmegaPeripheral::PUSART3;
+ case eATmegaPinFunc::TWI_SDA: case eATmegaPinFunc::TWI_CLK: return eATmegaPeripheral::PTWI;
+ case eATmegaPinFunc::ADC15: case eATmegaPinFunc::ADC14: case eATmegaPinFunc::ADC13: case eATmegaPinFunc::ADC12: case eATmegaPinFunc::ADC11: case eATmegaPinFunc::ADC10: case eATmegaPinFunc::ADC9: case eATmegaPinFunc::ADC8:
+ case eATmegaPinFunc::ADC7: case eATmegaPinFunc::ADC6: case eATmegaPinFunc::ADC5: case eATmegaPinFunc::ADC4: case eATmegaPinFunc::ADC3: case eATmegaPinFunc::ADC2: case eATmegaPinFunc::ADC1: case eATmegaPinFunc::ADC0:
+ return eATmegaPeripheral::PADC;
+ #elif defined(__AVR_TRM02__)
+ case eATmegaPinFunc::ADC7: case eATmegaPinFunc::ADC6: case eATmegaPinFunc::ADC5: case eATmegaPinFunc::ADC4: case eATmegaPinFunc::ADC3: case eATmegaPinFunc::ADC2: case eATmegaPinFunc::ADC1: case eATmegaPinFunc::ADC0:
+ return eATmegaPeripheral::PADC;
+ case eATmegaPinFunc::SPI_SCK: case eATmegaPinFunc::SPI_MISO: case eATmegaPinFunc::SPI_MOSI: case eATmegaPinFunc::SPI_CS: return eATmegaPeripheral::PSPI;
+ case eATmegaPinFunc::TIMER3_ICP: case eATmegaPinFunc::TIMER3_ECI: return eATmegaPeripheral::PTIM3;
+ case eATmegaPinFunc::TIMER1_ECI: case eATmegaPinFunc::TIMER1_ICP: return eATmegaPeripheral::PTIM1;
+ case eATmegaPinFunc::TIMER0_ECI: return eATmegaPeripheral::PTIM0;
+ case eATmegaPinFunc::TOC3B: case eATmegaPinFunc::TOC3A: return eATmegaPeripheral::PTIM3;
+ case eATmegaPinFunc::TOC2A: case eATmegaPinFunc::TOC2B: return eATmegaPeripheral::PTIM2;
+ case eATmegaPinFunc::TOC1A: case eATmegaPinFunc::TOC1B: return eATmegaPeripheral::PTIM1;
+ case eATmegaPinFunc::TOC0B: case eATmegaPinFunc::TOC0A: return eATmegaPeripheral::PTIM0;
+ case eATmegaPinFunc::USART0_CLK: case eATmegaPinFunc::USART0_TXD: case eATmegaPinFunc::USART0_RXD: return eATmegaPeripheral::PUSART0;
+ case eATmegaPinFunc::USART1_CLK: case eATmegaPinFunc::USART1_TXD: case eATmegaPinFunc::USART1_RXD: return eATmegaPeripheral::PUSART1;
+ case eATmegaPinFunc::TWI_SDA: case eATmegaPinFunc::TWI_CLK: return eATmegaPeripheral::PTWI;
+ #elif defined(__AVR_TRM03__)
+ case eATmegaPinFunc::ADC5: case eATmegaPinFunc::ADC4: case eATmegaPinFunc::ADC3: case eATmegaPinFunc::ADC2: case eATmegaPinFunc::ADC1: case eATmegaPinFunc::ADC0:
+ return eATmegaPeripheral::PADC;
+ case eATmegaPinFunc::SPI_SCK: case eATmegaPinFunc::SPI_MISO: case eATmegaPinFunc::SPI_MOSI: case eATmegaPinFunc::SPI_CS: return eATmegaPeripheral::PSPI;
+ case eATmegaPinFunc::TOC2B: case eATmegaPinFunc::TOC2A: return eATmegaPeripheral::PTIM2;
+ case eATmegaPinFunc::TOC1B: case eATmegaPinFunc::TOC1A: return eATmegaPeripheral::PTIM1;
+ case eATmegaPinFunc::TOC0A: case eATmegaPinFunc::TOC0B: return eATmegaPeripheral::PTIM0;
+ case eATmegaPinFunc::TIMER1_ICP: case eATmegaPinFunc::TIMER1_ECI: return eATmegaPeripheral::PTIM1;
+ case eATmegaPinFunc::TIMER0_ECI: return eATmegaPeripheral::PTIM0;
+ case eATmegaPinFunc::TWI_CLK: case eATmegaPinFunc::TWI_SDA: return eATmegaPeripheral::PTWI;
+ case eATmegaPinFunc::USART_CLK: case eATmegaPinFunc::USART_TXD: case eATmegaPinFunc::USART_RXD: return eATmegaPeripheral::PUSART0;
+ #elif defined(__AVR_TRM04__)
+ case eATmegaPinFunc::TOC0B: case eATmegaPinFunc::TOC0A: return eATmegaPeripheral::PTIM0;
+ case eATmegaPinFunc::TOC1C: case eATmegaPinFunc::TOC1B: case eATmegaPinFunc::TOC1A: return eATmegaPeripheral::PTIM1;
+ case eATmegaPinFunc::TOC2B: case eATmegaPinFunc::TOC2A: return eATmegaPeripheral::PTIM2;
+ case eATmegaPinFunc::TOC3A: case eATmegaPinFunc::TOC3B: case eATmegaPinFunc::TOC3C: return eATmegaPeripheral::PTIM3;
+ case eATmegaPinFunc::SPI_MISO: case eATmegaPinFunc::SPI_MOSI: case eATmegaPinFunc::SPI_SCK: case eATmegaPinFunc::SPI_CS: return eATmegaPeripheral::PSPI;
+ case eATmegaPinFunc::TIMER3_ICP: case eATmegaPinFunc::TIMER3_CLKI: return eATmegaPeripheral::PTIM3;
+ case eATmegaPinFunc::TIMER1_ICP: case eATmegaPinFunc::TIMER1_CLKI: return eATmegaPeripheral::PTIM1;
+ case eATmegaPinFunc::TIMER0_CLKI: return eATmegaPeripheral::PTIM0;
+ case eATmegaPinFunc::USART1_CLK: case eATmegaPinFunc::USART1_TXD: case eATmegaPinFunc::USART1_RXD: return eATmegaPeripheral::PUSART1;
+ case eATmegaPinFunc::TWI_SDA: case eATmegaPinFunc::TWI_CLK: return eATmegaPeripheral::PTWI;
+ case eATmegaPinFunc::UID: case eATmegaPinFunc::UVCON: return eATmegaPeripheral::PUSB;
+ case eATmegaPinFunc::ADC7: case eATmegaPinFunc::ADC6: case eATmegaPinFunc::ADC5: case eATmegaPinFunc::ADC4: case eATmegaPinFunc::ADC3: case eATmegaPinFunc::ADC2: case eATmegaPinFunc::ADC1: case eATmegaPinFunc::ADC0:
+ return eATmegaPeripheral::PADC;
+ #endif
+ // There are quite some pin functions that have no peripheral assignment, and that is OK!
+ default: break;
+ }
+ return eATmegaPeripheral::UNDEFINED;
+}
+
+struct ATmegaPeripheralSet {
+ inline ATmegaPeripheralSet() noexcept {
+ for (bool& f : this->funcs) f = false;
+ }
+ template
+ inline ATmegaPeripheralSet(funcItemType&&... items) noexcept : ATmegaPinFuncSet() {
+ add(((eATmegaPinFunc&&)items)...);
+ }
+ inline ATmegaPeripheralSet(const ATmegaPeripheralSet&) = default;
+
+ inline void add(eATmegaPeripheral value) noexcept {
+ this->funcs[(uint8_t)value] = true;
+ }
+ template
+ inline void add(eATmegaPeripheral value, funcItemType&&... items) noexcept {
+ add(value);
+ add(((funcItemType&&)items)...);
+ }
+
+ inline bool hasItem(eATmegaPeripheral value) const noexcept {
+ return this->funcs[(uint8_t)value];
+ }
+ template
+ inline bool hasItem(eATmegaPeripheral&& item, otherFuncItem&&... funcs) const noexcept {
+ return hasItem(item) || hasItem(((otherFuncItem&&)funcs)...);
+ }
+
+ template
+ inline void iterate(callbackType&& cb) const {
+ for (uint8_t n = 1; n < countof(funcs); n++) {
+ const bool& f = this->funcs[n];
+ if (f) cb( (eATmegaPeripheral)n );
+ }
+ }
+
+ inline void fromPinFuncs(const ATmegaPinFuncSet& funcSet) {
+ funcSet.iterate(
+ [this]( eATmegaPinFunc func ) noexcept {
+ this->add( _ATmega_getPeripheralForFunc(func) );
+ }
+ );
+ }
+
+private:
+ bool funcs[(uint8_t)eATmegaPeripheral::NUM_PERIPHERALS];
+};
+
+struct ATmegaPeripheralPowerGate {
+ inline ATmegaPeripheralPowerGate(ATmegaPeripheralSet& periSet) noexcept : periSet(periSet) {
+ periSet.iterate(
+ [this]( eATmegaPeripheral peri ) noexcept {
+ this->states[(uint8_t)peri] = _ATmega_getPeripheralPower(peri);
+ _ATmega_setPeripheralPower(peri, true);
+ }
+ );
+ }
+ inline ATmegaPeripheralPowerGate(const ATmegaPeripheralPowerGate&) = delete;
+
+ inline ~ATmegaPeripheralPowerGate() {
+ periSet.iterate(
+ [this]( eATmegaPeripheral peri ) noexcept {
+ _ATmega_setPeripheralPower(peri, this->states[(uint8_t)peri]);
+ }
+ );
+ }
+
+ inline ATmegaPeripheralPowerGate& operator = (const ATmegaPeripheralPowerGate&) = delete;
+
+private:
+ ATmegaPeripheralSet& periSet;
+ bool states[(uint8_t)eATmegaPeripheral::NUM_PERIPHERALS];
+};
+
+inline pin_dev_state_t _ATmega_savePinAlternates(const ATmegaPinFuncSet& funcSet) {
+ // TODO: the manual states that registers of power-reduced peripherals cannot be read or written, and that
+ // the resources (GPIO pins) remain occupied during power-reduction. This is a serious problem and we should
+ // add power-reduction awareness to this logic!
+
+ pin_dev_state_t state;
+
+ ATmegaPeripheralSet periSet;
+ periSet.fromPinFuncs(funcSet);
+
+ ATmegaPeripheralPowerGate pgate(periSet);
+
+ #ifdef __AVR_TRM01__
+ // See page 75ff of ATmega2560 technical reference manual.
+ if (funcSet.hasAnyFunc(
+ eATmegaPinFunc::EXTMEM_AD15, eATmegaPinFunc::EXTMEM_AD14, eATmegaPinFunc::EXTMEM_AD13, eATmegaPinFunc::EXTMEM_AD12, eATmegaPinFunc::EXTMEM_AD11, eATmegaPinFunc::EXTMEM_AD10, eATmegaPinFunc::EXTMEM_AD9, eATmegaPinFunc::EXTMEM_AD8,
+ eATmegaPinFunc::EXTMEM_AD7, eATmegaPinFunc::EXTMEM_AD6, eATmegaPinFunc::EXTMEM_AD5, eATmegaPinFunc::EXTMEM_AD4, eATmegaPinFunc::EXTMEM_AD3, eATmegaPinFunc::EXTMEM_AD2, eATmegaPinFunc::EXTMEM_AD1, eATmegaPinFunc::EXTMEM_AD0,
+ eATmegaPinFunc::EXTMEM_ALE, eATmegaPinFunc::EXTMEM_RD, eATmegaPinFunc::EXTMEM_WR
+ )) {
+ state._SRE = _XMCRA._SRE;
+ _XMCRA._SRE = false;
+ }
+ if (funcSet.hasAnyFunc(
+ eATmegaPinFunc::PCI0, eATmegaPinFunc::PCI1, eATmegaPinFunc::PCI2, eATmegaPinFunc::PCI3, eATmegaPinFunc::PCI4, eATmegaPinFunc::PCI5, eATmegaPinFunc::PCI6, eATmegaPinFunc::PCI7
+ )) {
+ state._PCIE0 = _PCICR._PCIE0;
+ _PCICR._PCIE0 = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC1C)) {
+ state._COM1C = TIMER1._TCCRnA._COMnC;
+ TIMER1._TCCRnA._COMnC = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC1B)) {
+ state._COM1B = TIMER1._TCCRnA._COMnB;
+ TIMER1._TCCRnA._COMnB = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC1A)) {
+ state._COM1A = TIMER1._TCCRnA._COMnA;
+ TIMER1._TCCRnA._COMnA = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC2A)) {
+ state._COM2A = _TIMER2._TCCRnA._COMnA;
+ _TIMER2._TCCRnA._COMnA = 0;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::USART1_TXD, eATmegaPinFunc::USART1_CLK)) {
+ state._USART1_TXEN = USART1._UCSRnB._TXEN;
+ USART1._UCSRnB._TXEN = false;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::USART1_RXD, eATmegaPinFunc::USART1_CLK)) {
+ state._USART1_RXEN = USART1._UCSRnB._RXEN;
+ USART1._UCSRnB._RXEN = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC3C)) {
+ state._COM3C = TIMER3._TCCRnA._COMnC;
+ TIMER3._TCCRnA._COMnC = 0;
+ }
+ // There is an error in the technical reference manual signal mapping table
+ // of ATmega2560 where is says that pin 3 is mapped to OC3B, but the list
+ // says OC3A.
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC3B)) {
+ state._COM3B = TIMER3._TCCRnA._COMnB;
+ TIMER3._TCCRnA._COMnB = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC3A)) {
+ state._COM3A = TIMER3._TCCRnA._COMnA;
+ TIMER3._TCCRnA._COMnA = 0;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::USART0_RXD, eATmegaPinFunc::USART0_CLK)) {
+ state._USART0_RXEN = USART0._UCSRnB._RXEN;
+ USART0._UCSRnB._RXEN = false;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::USART0_TXD, eATmegaPinFunc::USART0_CLK)) {
+ state._USART0_TXEN = USART0._UCSRnB._TXEN;
+ USART0._UCSRnB._TXEN = false;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI15, eATmegaPinFunc::PCI14, eATmegaPinFunc::PCI13, eATmegaPinFunc::PCI12, eATmegaPinFunc::PCI11, eATmegaPinFunc::PCI10, eATmegaPinFunc::PCI9, eATmegaPinFunc::PCI8)) {
+ state._PCIE1 = _PCICR._PCIE1;
+ _PCICR._PCIE1 = false;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::TOC0B)) {
+ state._COM0B = TIMER0._TCCRnA._COMnB;
+ TIMER0._TCCRnA._COMnB = 0;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::TOSC1, eATmegaPinFunc::TOSC2)) {
+ state._AS2 = _ASSR._AS2;
+ _ASSR._AS2 = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC2B)) {
+ state._COM2B = _TIMER2._TCCRnA._COMnB;
+ _TIMER2._TCCRnA._COMnB = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC4C)) {
+ state._COM4C = TIMER4._TCCRnA._COMnC;
+ TIMER4._TCCRnA._COMnC = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC4B)) {
+ state._COM4B = TIMER4._TCCRnA._COMnB;
+ TIMER4._TCCRnA._COMnB = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC4A)) {
+ state._COM4A = TIMER4._TCCRnA._COMnA;
+ TIMER4._TCCRnA._COMnA = 0;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::USART2_RXD, eATmegaPinFunc::USART2_CLK)) {
+ state._USART2_RXEN = USART2._UCSRnB._RXEN;
+ USART2._UCSRnB._RXEN = false;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::USART2_TXD, eATmegaPinFunc::USART2_CLK)) {
+ state._USART2_TXEN = USART2._UCSRnB._TXEN;
+ USART2._UCSRnB._TXEN = false;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::USART3_TXD, eATmegaPinFunc::USART3_CLK)) {
+ state._USART3_RXEN = USART3._UCSRnB._RXEN;
+ USART3._UCSRnB._RXEN = false;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::USART3_TXD, eATmegaPinFunc::USART3_CLK)) {
+ state._USART3_TXEN = USART3._UCSRnB._TXEN;
+ USART3._UCSRnB._TXEN = false;
+ }
+ if (funcSet.hasAnyFunc(
+ eATmegaPinFunc::PCI23, eATmegaPinFunc::PCI22, eATmegaPinFunc::PCI21, eATmegaPinFunc::PCI20, eATmegaPinFunc::PCI19, eATmegaPinFunc::PCI18, eATmegaPinFunc::PCI17, eATmegaPinFunc::PCI16
+ )) {
+ state._PCIE2 = _PCICR._PCIE2;
+ _PCICR._PCIE2 = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC5C)) {
+ state._COM5C = TIMER5._TCCRnA._COMnC;
+ TIMER5._TCCRnA._COMnC = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC5B)) {
+ state._COM5B = TIMER5._TCCRnA._COMnB;
+ TIMER5._TCCRnA._COMnB = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC5A)) {
+ state._COM5A = TIMER5._TCCRnA._COMnA;
+ TIMER5._TCCRnA._COMnA = 0;
+ }
+ #elif defined(__AVR_TRM02__)
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI7, eATmegaPinFunc::PCI6, eATmegaPinFunc::PCI5, eATmegaPinFunc::PCI4, eATmegaPinFunc::PCI3, eATmegaPinFunc::PCI2, eATmegaPinFunc::PCI1, eATmegaPinFunc::PCI0)) {
+ state._PCIE0 = _PCICR._PCIE0;
+ _PCICR._PCIE0 = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC7)) {
+ state._ADC7D = _DIDR0._ADC7D;
+ _DIDR0._ADC7D = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC6)) {
+ state._ADC6D = _DIDR0._ADC6D;
+ _DIDR0._ADC6D = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC5)) {
+ state._ADC5D = _DIDR0._ADC5D;
+ _DIDR0._ADC5D = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC4)) {
+ state._ADC4D = _DIDR0._ADC4D;
+ _DIDR0._ADC4D = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC3)) {
+ state._ADC3D = _DIDR0._ADC3D;
+ _DIDR0._ADC3D = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC2)) {
+ state._ADC2D = _DIDR0._ADC2D;
+ _DIDR0._ADC2D = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC1)) {
+ state._ADC1D = _DIDR0._ADC1D;
+ _DIDR0._ADC1D = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC0)) {
+ state._ADC0D = _DIDR0._ADC0D;
+ _DIDR0._ADC0D = false;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI15, eATmegaPinFunc::PCI14, eATmegaPinFunc::PCI13, eATmegaPinFunc::PCI12, eATmegaPinFunc::PCI11, eATmegaPinFunc::PCI10, eATmegaPinFunc::PCI9, eATmegaPinFunc::PCI8)) {
+ state._PCIE1 = _PCICR._PCIE1;
+ _PCICR._PCIE1 = false;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::SPI_CS)) {
+ state._SPE = _SPCR._SPE;
+ _SPCR._SPE = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC0A)) {
+ state._COM0A = TIMER0._TCCRnA._COMnA;
+ TIMER0._TCCRnA._COMnA = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC0B)) {
+ state._COM0B = TIMER0._TCCRnA._COMnB;
+ TIMER0._TCCRnA._COMnB = 0;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::TOSC1, eATmegaPinFunc::TOSC2)) {
+ state._AS2 = _ASSR._AS2;
+ _ASSR._AS2 = false;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI23, eATmegaPinFunc::PCI22, eATmegaPinFunc::PCI21, eATmegaPinFunc::PCI20, eATmegaPinFunc::PCI19, eATmegaPinFunc::PCI18, eATmegaPinFunc::PCI17, eATmegaPinFunc::PCI16)) {
+ state._PCIE2 = _PCICR._PCIE2;
+ _PCICR._PCIE2 = false;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI31, eATmegaPinFunc::PCI30, eATmegaPinFunc::PCI29, eATmegaPinFunc::PCI28, eATmegaPinFunc::PCI27, eATmegaPinFunc::PCI26, eATmegaPinFunc::PCI25, eATmegaPinFunc::PCI24)) {
+ state._PCIE3 = _PCICR._PCIE3;
+ _PCICR._PCIE3 = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC2A)) {
+ state._COM2A = _TIMER2._TCCRnA._COMnA;
+ _TIMER2._TCCRnA._COMnA = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC2B)) {
+ state._COM2B = _TIMER2._TCCRnA._COMnB;
+ _TIMER2._TCCRnA._COMnB = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC1A)) {
+ state._COM1A = TIMER1._TCCRnA._COMnA;
+ TIMER1._TCCRnA._COMnA = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC1B)) {
+ state._COM1B = TIMER1._TCCRnA._COMnB;
+ TIMER1._TCCRnA._COMnB = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::USART1_TXD)) {
+ state._USART1_TXEN = USART1._UCSRnB._TXEN;
+ USART1._UCSRnB._TXEN = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::USART1_RXD)) {
+ state._USART1_RXEN = USART1._UCSRnB._RXEN;
+ USART1._UCSRnB._RXEN = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::USART0_TXD)) {
+ state._USART0_TXEN = USART0._UCSRnB._TXEN;
+ USART0._UCSRnB._TXEN = false;
+ }
+ // There is a bug in the ATmega164A technical reference manual where
+ // it says that pin 0 is mapped to USART1 RXD in the signal mapping table
+ // but the associated list says USART0 RXD.
+ if (funcSet.hasFunc(eATmegaPinFunc::USART0_RXD)) {
+ state._USART0_RXEN = USART0._UCSRnB._RXEN;
+ USART0._UCSRnB._RXEN = false;
+ }
+ #elif defined(__AVR_TRM03__)
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI7, eATmegaPinFunc::PCI6, eATmegaPinFunc::PCI5, eATmegaPinFunc::PCI4, eATmegaPinFunc::PCI3, eATmegaPinFunc::PCI2, eATmegaPinFunc::PCI1, eATmegaPinFunc::PCI0)) {
+ state._PCIE0 = _PCICR._PCIE0;
+ _PCICR._PCIE0 = false;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::TOSC1, eATmegaPinFunc::TOSC2)) {
+ state._AS2 = _ASSR._AS2;
+ _ASSR._AS2 = false;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::SPI_CS)) {
+ state._SPE = _SPCR._SPE;
+ _SPCR._SPE = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC2A)) {
+ state._COM2A = _TIMER2._TCCRnA._COMnA;
+ _TIMER2._TCCRnA._COMnA = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC1B)) {
+ state._COM1B = TIMER1._TCCRnA._COMnB;
+ TIMER1._TCCRnA._COMnB = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC1A)) {
+ state._COM1A = TIMER1._TCCRnA._COMnA;
+ TIMER1._TCCRnA._COMnA = 0;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI14, eATmegaPinFunc::PCI13, eATmegaPinFunc::PCI12, eATmegaPinFunc::PCI11, eATmegaPinFunc::PCI10, eATmegaPinFunc::PCI9, eATmegaPinFunc::PCI8)) {
+ state._PCIE1 = _PCICR._PCIE1;
+ _PCICR._PCIE1 = false;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::TWI_CLK, eATmegaPinFunc::TWI_SDA)) {
+ state._TWEN = _TWCR._TWEN;
+ _TWCR._TWEN = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC5)) {
+ state._ADC5D = _DIDR0._ADC5D;
+ _DIDR0._ADC5D = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC4)) {
+ state._ADC4D = _DIDR0._ADC4D;
+ _DIDR0._ADC4D = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC3)) {
+ state._ADC3D = _DIDR0._ADC3D;
+ _DIDR0._ADC3D = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC2)) {
+ state._ADC2D = _DIDR0._ADC2D;
+ _DIDR0._ADC2D = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC1)) {
+ state._ADC1D = _DIDR0._ADC1D;
+ _DIDR0._ADC1D = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC0)) {
+ state._ADC0D = _DIDR0._ADC0D;
+ _DIDR0._ADC0D = false;
+ }
+ // There is a bug in the ATmega48A technical reference manual where pin 2
+ // is said to be mapped to PCIE1 but logically it should be PCIE2 instead.
+ // The real mapping can be read in the documentation of the PCICR register.
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI23, eATmegaPinFunc::PCI22, eATmegaPinFunc::PCI21, eATmegaPinFunc::PCI20, eATmegaPinFunc::PCI19, eATmegaPinFunc::PCI18, eATmegaPinFunc::PCI17, eATmegaPinFunc::PCI16)) {
+ state._PCIE2 = _PCICR._PCIE2;
+ _PCICR._PCIE2 = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC0A)) {
+ state._COM0A = TIMER0._TCCRnA._COMnA;
+ TIMER0._TCCRnA._COMnA = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC0B)) {
+ state._COM0B = TIMER0._TCCRnA._COMnB;
+ TIMER0._TCCRnA._COMnB = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::USART_CLK)) {
+ state._UMSEL = USART0._UCSRnC._UMSEL;
+ USART0._UCSRnC._UMSEL = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC2B)) {
+ state._COM2B = _TIMER2._TCCRnA._COMnB;
+ _TIMER2._TCCRnA._COMnB = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::USART_TXD)) {
+ state._USART0_TXEN = USART0._UCSRnB._TXEN;
+ USART0._UCSRnB._TXEN = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::USART_RXD)) {
+ state._USART0_RXEN = USART0._UCSRnB._RXEN;
+ USART0._UCSRnB._RXEN = false;
+ }
+ #elif defined(__AVR_TRM04__)
+ if (funcSet.hasAnyFunc(
+ eATmegaPinFunc::EXTMEM_AD15, eATmegaPinFunc::EXTMEM_AD14, eATmegaPinFunc::EXTMEM_AD13, eATmegaPinFunc::EXTMEM_AD12, eATmegaPinFunc::EXTMEM_AD11, eATmegaPinFunc::EXTMEM_AD10, eATmegaPinFunc::EXTMEM_AD9, eATmegaPinFunc::EXTMEM_AD8,
+ eATmegaPinFunc::EXTMEM_AD7, eATmegaPinFunc::EXTMEM_AD6, eATmegaPinFunc::EXTMEM_AD5, eATmegaPinFunc::EXTMEM_AD4, eATmegaPinFunc::EXTMEM_AD3, eATmegaPinFunc::EXTMEM_AD2, eATmegaPinFunc::EXTMEM_AD1, eATmegaPinFunc::EXTMEM_AD0,
+ eATmegaPinFunc::EXTMEM_ALE, eATmegaPinFunc::EXTMEM_RD, eATmegaPinFunc::EXTMEM_WR
+ )) {
+ state._SRE = _XMCRA._SRE;
+ _XMCRA._SRE = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC1C)) {
+ state._COM1C = TIMER1._TCCRnA._COMnC;
+ TIMER1._TCCRnA._COMnC = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC1B)) {
+ state._COM1B = TIMER1._TCCRnA._COMnB;
+ TIMER1._TCCRnA._COMnB = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC1A)) {
+ state._COM1A = TIMER1._TCCRnA._COMnA;
+ TIMER1._TCCRnA._COMnA = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC2A)) {
+ state._COM2A = _TIMER2._TCCRnA._COMnA;
+ _TIMER2._TCCRnA._COMnA = 0;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::SPI_CS)) {
+ state._SPE = _SPCR._SPE;
+ _SPCR._SPE = false;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI7, eATmegaPinFunc::PCI6, eATmegaPinFunc::PCI5, eATmegaPinFunc::PCI4, eATmegaPinFunc::PCI3, eATmegaPinFunc::PCI2, eATmegaPinFunc::PCI1, eATmegaPinFunc::PCI0)) {
+ state._PCIE0 = _PCICR._PCIE0;
+ _PCICR._PCIE0 = false;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::USART1_CLK, eATmegaPinFunc::USART1_TXD)) {
+ state._USART1_TXEN = USART1._UCSRnB._TXEN;
+ USART1._UCSRnB._TXEN = false;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::USART1_CLK, eATmegaPinFunc::USART1_RXD)) {
+ state._USART1_RXEN = USART1._UCSRnB._RXEN;
+ USART1._UCSRnB._RXEN = false;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::TWI_SDA, eATmegaPinFunc::TWI_CLK)) {
+ state._TWEN = _TWCR._TWEN;
+ _TWCR._TWEN = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC2B)) {
+ state._COM2B = _TIMER2._TCCRnA._COMnB;
+ _TIMER2._TCCRnA._COMnB = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC0B)) {
+ state._COM0B = TIMER0._TCCRnA._COMnB;
+ TIMER0._TCCRnA._COMnB = 0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::EINT3)) {
+ state._INT3 = _EIMSK._INT3;
+ _EIMSK._INT3 = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::EINT2)) {
+ state._INT2 = _EIMSK._INT2;
+ _EIMSK._INT2 = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::EINT1)) {
+ state._INT1 = _EIMSK._INT1;
+ _EIMSK._INT1 = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::EINT0)) {
+ state._INT0 = _EIMSK._INT0;
+ _EIMSK._INT0 = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::UVCON)) {
+ state._UVCONE = _UHWCON._UVCONE;
+ _UHWCON._UVCONE = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::UID)) {
+ state._UIDE = _UHWCON._UIDE;
+ _UHWCON._UIDE = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::EINT7)) {
+ state._INT7 = _EIMSK._INT7;
+ _EIMSK._INT7 = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::EINT6)) {
+ state._INT6 = _EIMSK._INT6;
+ _EIMSK._INT6 = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::EINT5)) {
+ state._INT5 = _EIMSK._INT5;
+ _EIMSK._INT5 = false;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::EINT4)) {
+ state._INT4 = _EIMSK._INT4;
+ _EIMSK._INT4 = false;
+ }
+ #endif
+
+ return state;
+}
+
+inline void _ATmega_restorePinAlternates(const ATmegaPinFuncSet& funcSet, const pin_dev_state_t& state) {
+ ATmegaPeripheralSet periSet;
+ periSet.fromPinFuncs(funcSet);
+
+ ATmegaPeripheralPowerGate pgate(periSet);
+
+ #ifdef __AVR_TRM01__
+ // See page 75ff of ATmega2560 technical reference manual.
+ if (funcSet.hasAnyFunc(
+ eATmegaPinFunc::EXTMEM_AD15, eATmegaPinFunc::EXTMEM_AD14, eATmegaPinFunc::EXTMEM_AD13, eATmegaPinFunc::EXTMEM_AD12, eATmegaPinFunc::EXTMEM_AD11, eATmegaPinFunc::EXTMEM_AD10, eATmegaPinFunc::EXTMEM_AD9, eATmegaPinFunc::EXTMEM_AD8,
+ eATmegaPinFunc::EXTMEM_AD7, eATmegaPinFunc::EXTMEM_AD6, eATmegaPinFunc::EXTMEM_AD5, eATmegaPinFunc::EXTMEM_AD4, eATmegaPinFunc::EXTMEM_AD3, eATmegaPinFunc::EXTMEM_AD2, eATmegaPinFunc::EXTMEM_AD1, eATmegaPinFunc::EXTMEM_AD0,
+ eATmegaPinFunc::EXTMEM_ALE, eATmegaPinFunc::EXTMEM_RD, eATmegaPinFunc::EXTMEM_WR
+ )) {
+ _XMCRA._SRE = state._SRE;
+ }
+ if (funcSet.hasAnyFunc(
+ eATmegaPinFunc::PCI0, eATmegaPinFunc::PCI1, eATmegaPinFunc::PCI2, eATmegaPinFunc::PCI3, eATmegaPinFunc::PCI4, eATmegaPinFunc::PCI5, eATmegaPinFunc::PCI6, eATmegaPinFunc::PCI7
+ )) {
+ _PCICR._PCIE0 = state._PCIE0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC1C)) {
+ TIMER1._TCCRnA._COMnC = state._COM1C;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC1B)) {
+ TIMER1._TCCRnA._COMnB = state._COM1B;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC1A)) {
+ TIMER1._TCCRnA._COMnA = state._COM1A;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC2A)) {
+ _TIMER2._TCCRnA._COMnA = state._COM2A;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::USART1_TXD, eATmegaPinFunc::USART1_CLK)) {
+ USART1._UCSRnB._TXEN = state._USART1_TXEN;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::USART1_RXD, eATmegaPinFunc::USART1_CLK)) {
+ USART1._UCSRnB._RXEN = state._USART1_RXEN;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC3C)) {
+ TIMER3._TCCRnA._COMnC = state._COM3C;
+ }
+ // There is an error in the technical reference manual signal mapping table
+ // of ATmega2560 where is says that pin 3 is mapped to OC3B, but the list
+ // says OC3A.
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC3B)) {
+ TIMER3._TCCRnA._COMnB = state._COM3B;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC3A)) {
+ TIMER3._TCCRnA._COMnA = state._COM3A;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::USART0_RXD, eATmegaPinFunc::USART0_CLK)) {
+ USART0._UCSRnB._RXEN = state._USART0_RXEN;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::USART0_TXD, eATmegaPinFunc::USART0_CLK)) {
+ USART0._UCSRnB._TXEN = state._USART0_TXEN;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI15, eATmegaPinFunc::PCI14, eATmegaPinFunc::PCI13, eATmegaPinFunc::PCI12, eATmegaPinFunc::PCI11, eATmegaPinFunc::PCI10, eATmegaPinFunc::PCI9, eATmegaPinFunc::PCI8)) {
+ _PCICR._PCIE1 = state._PCIE1;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::TOC0B)) {
+ TIMER0._TCCRnA._COMnB = state._COM0B;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::TOSC1, eATmegaPinFunc::TOSC2)) {
+ _ASSR._AS2 = state._AS2;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC2B)) {
+ _TIMER2._TCCRnA._COMnB = state._COM2B;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC4C)) {
+ TIMER4._TCCRnA._COMnC = state._COM4C;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC4B)) {
+ TIMER4._TCCRnA._COMnB = state._COM4B;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC4A)) {
+ TIMER4._TCCRnA._COMnA = state._COM4A;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::USART2_RXD, eATmegaPinFunc::USART2_CLK)) {
+ USART2._UCSRnB._RXEN = state._USART2_RXEN;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::USART2_TXD, eATmegaPinFunc::USART2_CLK)) {
+ USART2._UCSRnB._TXEN = state._USART2_TXEN;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::USART3_TXD, eATmegaPinFunc::USART3_CLK)) {
+ USART3._UCSRnB._RXEN = state._USART3_RXEN;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::USART3_TXD, eATmegaPinFunc::USART3_CLK)) {
+ USART3._UCSRnB._TXEN = state._USART3_TXEN;
+ }
+ if (funcSet.hasAnyFunc(
+ eATmegaPinFunc::PCI23, eATmegaPinFunc::PCI22, eATmegaPinFunc::PCI21, eATmegaPinFunc::PCI20, eATmegaPinFunc::PCI19, eATmegaPinFunc::PCI18, eATmegaPinFunc::PCI17, eATmegaPinFunc::PCI16
+ )) {
+ _PCICR._PCIE2 = state._PCIE2;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC5C)) {
+ TIMER5._TCCRnA._COMnC = state._COM5C;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC5B)) {
+ TIMER5._TCCRnA._COMnB = state._COM5B;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC5A)) {
+ TIMER5._TCCRnA._COMnA = state._COM5A;
+ }
+ #elif defined(__AVR_TRM02__)
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI7, eATmegaPinFunc::PCI6, eATmegaPinFunc::PCI5, eATmegaPinFunc::PCI4, eATmegaPinFunc::PCI3, eATmegaPinFunc::PCI2, eATmegaPinFunc::PCI1, eATmegaPinFunc::PCI0)) {
+ _PCICR._PCIE0 = state._PCIE0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC7)) {
+ _DIDR0._ADC7D = state._ADC7D;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC6)) {
+ _DIDR0._ADC6D = state._ADC6D;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC5)) {
+ _DIDR0._ADC5D = state._ADC5D;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC4)) {
+ _DIDR0._ADC4D = state._ADC4D;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC3)) {
+ _DIDR0._ADC3D = state._ADC3D;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC2)) {
+ _DIDR0._ADC2D = state._ADC2D;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC1)) {
+ _DIDR0._ADC1D = state._ADC1D;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC0)) {
+ _DIDR0._ADC0D = state._ADC0D;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI15, eATmegaPinFunc::PCI14, eATmegaPinFunc::PCI13, eATmegaPinFunc::PCI12, eATmegaPinFunc::PCI11, eATmegaPinFunc::PCI10, eATmegaPinFunc::PCI9, eATmegaPinFunc::PCI8)) {
+ _PCICR._PCIE1 = state._PCIE1;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::SPI_CS)) {
+ _SPCR._SPE = state._SPE;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC0A)) {
+ TIMER0._TCCRnA._COMnA = state._COM0A;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC0B)) {
+ TIMER0._TCCRnA._COMnB = state._COM0B;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::TOSC1, eATmegaPinFunc::TOSC2)) {
+ _ASSR._AS2 = state._AS2;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI23, eATmegaPinFunc::PCI22, eATmegaPinFunc::PCI21, eATmegaPinFunc::PCI20, eATmegaPinFunc::PCI19, eATmegaPinFunc::PCI18, eATmegaPinFunc::PCI17, eATmegaPinFunc::PCI16)) {
+ _PCICR._PCIE2 = state._PCIE2;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI31, eATmegaPinFunc::PCI30, eATmegaPinFunc::PCI29, eATmegaPinFunc::PCI28, eATmegaPinFunc::PCI27, eATmegaPinFunc::PCI26, eATmegaPinFunc::PCI25, eATmegaPinFunc::PCI24)) {
+ _PCICR._PCIE3 = state._PCIE3;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC2A)) {
+ _TIMER2._TCCRnA._COMnA = state._COM2A;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC2B)) {
+ _TIMER2._TCCRnA._COMnB = state._COM2B;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC1A)) {
+ TIMER1._TCCRnA._COMnA = state._COM1A;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC1B)) {
+ TIMER1._TCCRnA._COMnB = state._COM1B;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::USART1_TXD)) {
+ USART1._UCSRnB._TXEN = state._USART1_TXEN;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::USART1_RXD)) {
+ USART1._UCSRnB._RXEN = state._USART1_RXEN;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::USART0_TXD)) {
+ USART0._UCSRnB._TXEN = state._USART0_TXEN;
+ }
+ // There is a bug in the ATmega164A technical reference manual where
+ // it says that pin 0 is mapped to USART1 RXD in the signal mapping table
+ // but the associated list says USART0 RXD.
+ if (funcSet.hasFunc(eATmegaPinFunc::USART0_RXD)) {
+ USART0._UCSRnB._RXEN = state._USART0_RXEN;
+ }
+ #elif defined(__AVR_TRM03__)
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI7, eATmegaPinFunc::PCI6, eATmegaPinFunc::PCI5, eATmegaPinFunc::PCI4, eATmegaPinFunc::PCI3, eATmegaPinFunc::PCI2, eATmegaPinFunc::PCI1, eATmegaPinFunc::PCI0)) {
+ _PCICR._PCIE0 = state._PCIE0;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::TOSC1, eATmegaPinFunc::TOSC2)) {
+ _ASSR._AS2 = state._AS2;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::SPI_CS)) {
+ _SPCR._SPE = state._SPE;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC2A)) {
+ _TIMER2._TCCRnA._COMnA = state._COM2A;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC1B)) {
+ TIMER1._TCCRnA._COMnB = state._COM1B;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC1A)) {
+ TIMER1._TCCRnA._COMnA = state._COM1A;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI14, eATmegaPinFunc::PCI13, eATmegaPinFunc::PCI12, eATmegaPinFunc::PCI11, eATmegaPinFunc::PCI10, eATmegaPinFunc::PCI9, eATmegaPinFunc::PCI8)) {
+ _PCICR._PCIE1 = state._PCIE1;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::TWI_CLK, eATmegaPinFunc::TWI_SDA)) {
+ _TWCR._TWEN = state._TWEN;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC5)) {
+ _DIDR0._ADC5D = state._ADC5D;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC4)) {
+ _DIDR0._ADC4D = state._ADC4D;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC3)) {
+ _DIDR0._ADC3D = state._ADC3D;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC2)) {
+ _DIDR0._ADC2D = state._ADC2D;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC1)) {
+ _DIDR0._ADC1D = state._ADC1D;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::ADC0)) {
+ _DIDR0._ADC0D = state._ADC0D;
+ }
+ // There is a bug in the ATmega48A technical reference manual where pin 2
+ // is said to be mapped to PCIE1 but logically it should be PCIE2 instead.
+ // The real mapping can be read in the documentation of the PCICR register.
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI23, eATmegaPinFunc::PCI22, eATmegaPinFunc::PCI21, eATmegaPinFunc::PCI20, eATmegaPinFunc::PCI19, eATmegaPinFunc::PCI18, eATmegaPinFunc::PCI17, eATmegaPinFunc::PCI16)) {
+ _PCICR._PCIE2 = state._PCIE2;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC0A)) {
+ TIMER0._TCCRnA._COMnA = state._COM0A;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC0B)) {
+ TIMER0._TCCRnA._COMnB = state._COM0B;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::USART_CLK)) {
+ USART0._UCSRnC._UMSEL = state._UMSEL;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC2B)) {
+ _TIMER2._TCCRnA._COMnB = state._COM2B;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::USART_TXD)) {
+ USART0._UCSRnB._TXEN = state._USART0_TXEN;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::USART_RXD)) {
+ USART0._UCSRnB._RXEN = state._USART0_RXEN;
+ }
+ #elif defined(__AVR_TRM04__)
+ if (funcSet.hasAnyFunc(
+ eATmegaPinFunc::EXTMEM_AD15, eATmegaPinFunc::EXTMEM_AD14, eATmegaPinFunc::EXTMEM_AD13, eATmegaPinFunc::EXTMEM_AD12, eATmegaPinFunc::EXTMEM_AD11, eATmegaPinFunc::EXTMEM_AD10, eATmegaPinFunc::EXTMEM_AD9, eATmegaPinFunc::EXTMEM_AD8,
+ eATmegaPinFunc::EXTMEM_AD7, eATmegaPinFunc::EXTMEM_AD6, eATmegaPinFunc::EXTMEM_AD5, eATmegaPinFunc::EXTMEM_AD4, eATmegaPinFunc::EXTMEM_AD3, eATmegaPinFunc::EXTMEM_AD2, eATmegaPinFunc::EXTMEM_AD1, eATmegaPinFunc::EXTMEM_AD0,
+ eATmegaPinFunc::EXTMEM_ALE, eATmegaPinFunc::EXTMEM_RD, eATmegaPinFunc::EXTMEM_WR
+ )) {
+ _XMCRA._SRE = state._SRE;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC1C)) {
+ TIMER1._TCCRnA._COMnC = state._COM1C;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC1B)) {
+ TIMER1._TCCRnA._COMnB = state._COM1B;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC1A)) {
+ TIMER1._TCCRnA._COMnA = state._COM1A;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC2A)) {
+ _TIMER2._TCCRnA._COMnA = state._COM2A;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::SPI_MISO, eATmegaPinFunc::SPI_MOSI, eATmegaPinFunc::SPI_SCK, eATmegaPinFunc::SPI_CS)) {
+ _SPCR._SPE = state._SPE;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::PCI7, eATmegaPinFunc::PCI6, eATmegaPinFunc::PCI5, eATmegaPinFunc::PCI4, eATmegaPinFunc::PCI3, eATmegaPinFunc::PCI2, eATmegaPinFunc::PCI1, eATmegaPinFunc::PCI0)) {
+ _PCICR._PCIE0 = state._PCIE0;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::USART1_CLK, eATmegaPinFunc::USART1_TXD)) {
+ USART1._UCSRnB._TXEN = state._USART1_TXEN;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::USART1_CLK, eATmegaPinFunc::USART1_RXD)) {
+ USART1._UCSRnB._RXEN = state._USART1_RXEN;
+ }
+ if (funcSet.hasAnyFunc(eATmegaPinFunc::TWI_SDA, eATmegaPinFunc::TWI_CLK)) {
+ _TWCR._TWEN = state._TWEN;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC2B)) {
+ _TIMER2._TCCRnA._COMnB = state._COM2B;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::TOC0B)) {
+ TIMER0._TCCRnA._COMnB = state._COM0B;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::EINT3)) {
+ _EIMSK._INT3 = state._INT3;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::EINT2)) {
+ _EIMSK._INT2 = state._INT2;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::EINT1)) {
+ _EIMSK._INT1 = state._INT1;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::EINT0)) {
+ _EIMSK._INT0 = state._INT0;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::UVCON)) {
+ _UHWCON._UVCONE = state._UVCONE;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::UID)) {
+ _UHWCON._UIDE = state._UIDE;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::EINT7)) {
+ _EIMSK._INT7 = state._INT7;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::EINT6)) {
+ _EIMSK._INT6 = state._INT6;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::EINT5)) {
+ _EIMSK._INT5 = state._INT5;
+ }
+ if (funcSet.hasFunc(eATmegaPinFunc::EINT4)) {
+ _EIMSK._INT4 = state._INT4;
+ }
+ #endif
+}
+
+inline pin_dev_state_t _ATmega_savePinAlternate(uint8_t pin) {
+ return _ATmega_savePinAlternates({pin});
+}
+
+inline void _ATmega_restorePinAlternate(uint8_t pin, const pin_dev_state_t& state) {
+ _ATmega_restorePinAlternate({pin}, state);
+}
+
+#ifndef LOW
+ #define LOW 0
+#endif
+#ifndef HIGH
+ #define HIGH 1
+#endif
+
+inline void _ATmega_digitalWrite(int pin, int state) {
+ if (pin < 0) return;
+
+ ATmegaPinInfo info = _ATmega_getPinInfo((unsigned int)pin);
+
+ #ifdef __AVR_TRM01__
+ if (info.port == eATmegaPort::PORT_A) {
+ _PORTA._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ else if (info.port == eATmegaPort::PORT_B) {
+ _PORTB._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ else if (info.port == eATmegaPort::PORT_C) {
+ _PORTC._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ else if (info.port == eATmegaPort::PORT_D) {
+ _PORTD._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ else if (info.port == eATmegaPort::PORT_E) {
+ _PORTE._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ else if (info.port == eATmegaPort::PORT_F) {
+ _PORTF._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ else if (info.port == eATmegaPort::PORT_G) {
+ _PORTG._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ else if (info.port == eATmegaPort::PORT_H) {
+ _PORTH._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ else if (info.port == eATmegaPort::PORT_J) {
+ _PORTJ._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ else if (info.port == eATmegaPort::PORT_K) {
+ _PORTK._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ else if (info.port == eATmegaPort::PORT_L) {
+ _PORTL._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ #elif defined(__AVR_TRM02__)
+ if (info.port == eATmegaPort::PORT_A) {
+ _PORTA._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ else if (info.port == eATmegaPort::PORT_B) {
+ _PORTB._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ else if (info.port == eATmegaPort::PORT_C) {
+ _PORTC._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ else if (info.port == eATmegaPort::PORT_D) {
+ _PORTD._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ #elif defined(__AVR_TRM03__)
+ if (info.port == eATmegaPort::PORT_B) {
+ _PORTB._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ else if (info.port == eATmegaPort::PORT_C) {
+ _PORTC._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ else if (info.port == eATmegaPort::PORT_D) {
+ _PORTD._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ #elif defined(__AVR_TRM04__)
+ if (info.port == eATmegaPort::PORT_A) {
+ _PORTA._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ else if (info.port == eATmegaPort::PORT_B) {
+ _PORTB._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ else if (info.port == eATmegaPort::PORT_C) {
+ _PORTC._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ else if (info.port == eATmegaPort::PORT_D) {
+ _PORTD._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ else if (info.port == eATmegaPort::PORT_E) {
+ _PORTE._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ else if (info.port == eATmegaPort::PORT_F) {
+ _PORTF._PORT.setValue(info.pinidx, state == HIGH);
+ }
+ #endif
+}
+
+inline int _ATmega_digitalRead(int pin) {
+ int value = LOW;
+
+ if (pin < 0) return value;
+
+ ATmegaPinInfo info = _ATmega_getPinInfo((unsigned int)pin);
+
+ #ifdef __AVR_TRM01__
+ if (info.port == eATmegaPort::PORT_A) {
+ value = _PORTA._PIN.getValue(info.pinidx);
+ }
+ else if (info.port == eATmegaPort::PORT_B) {
+ value = _PORTB._PIN.getValue(info.pinidx);
+ }
+ else if (info.port == eATmegaPort::PORT_C) {
+ value = _PORTC._PIN.getValue(info.pinidx);
+ }
+ else if (info.port == eATmegaPort::PORT_D) {
+ value = _PORTD._PIN.getValue(info.pinidx);
+ }
+ else if (info.port == eATmegaPort::PORT_E) {
+ value = _PORTE._PIN.getValue(info.pinidx);
+ }
+ else if (info.port == eATmegaPort::PORT_F) {
+ value = _PORTF._PIN.getValue(info.pinidx);
+ }
+ else if (info.port == eATmegaPort::PORT_G) {
+ value = _PORTG._PIN.getValue(info.pinidx);
+ }
+ else if (info.port == eATmegaPort::PORT_H) {
+ value = _PORTH._PIN.getValue(info.pinidx);
+ }
+ else if (info.port == eATmegaPort::PORT_J) {
+ value = _PORTJ._PIN.getValue(info.pinidx);
+ }
+ else if (info.port == eATmegaPort::PORT_K) {
+ value = _PORTK._PIN.getValue(info.pinidx);
+ }
+ else if (info.port == eATmegaPort::PORT_L) {
+ value = _PORTL._PIN.getValue(info.pinidx);
+ }
+ #elif defined(__AVR_TRM02__)
+ if (info.port == eATmegaPort::PORT_A) {
+ value = _PORTA._PIN.getValue(info.pinidx);
+ }
+ else if (info.port == eATmegaPort::PORT_B) {
+ value = _PORTB._PIN.getValue(info.pinidx);
+ }
+ else if (info.port == eATmegaPort::PORT_C) {
+ value = _PORTC._PIN.getValue(info.pinidx);
+ }
+ else if (info.port == eATmegaPort::PORT_D) {
+ value = _PORTD._PIN.getValue(info.pinidx);
+ }
+ #elif defined(__AVR_TRM03__)
+ if (info.port == eATmegaPort::PORT_B) {
+ value = _PORTB._PIN.getValue(info.pinidx);
+ }
+ else if (info.port == eATmegaPort::PORT_C) {
+ value = _PORTC._PIN.getValue(info.pinidx);
+ }
+ else if (info.port == eATmegaPort::PORT_D) {
+ value = _PORTD._PIN.getValue(info.pinidx);
+ }
+ #elif defined(__AVR_TRM04__)
+ if (info.port == eATmegaPort::PORT_A) {
+ value = _PORTA._PIN.getValue(info.pinidx);
+ }
+ else if (info.port == eATmegaPort::PORT_B) {
+ value = _PORTB._PIN.getValue(info.pinidx);
+ }
+ else if (info.port == eATmegaPort::PORT_C) {
+ value = _PORTC._PIN.getValue(info.pinidx);
+ }
+ else if (info.port == eATmegaPort::PORT_D) {
+ value = _PORTD._PIN.getValue(info.pinidx);
+ }
+ else if (info.port == eATmegaPort::PORT_E) {
+ value = _PORTE._PIN.getValue(info.pinidx);
+ }
+ else if (info.port == eATmegaPort::PORT_F) {
+ value = _PORTF._PIN.getValue(info.pinidx);
+ }
+ #endif
+
+ return value;
+}
+
+#ifndef OUTPUT
+ #define OUTPUT 1
+#endif
+#ifndef INPUT
+ #define INPUT 0
+#endif
+
+inline void _ATmega_pinMode(int pin, int mode) {
+ if (pin < 0) return;
+
+ ATmegaPinInfo info = _ATmega_getPinInfo((unsigned int)pin);
+
+ #ifdef __AVR_TRM01__
+ if (info.port == eATmegaPort::PORT_A) {
+ _PORTA._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ else if (info.port == eATmegaPort::PORT_B) {
+ _PORTB._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ else if (info.port == eATmegaPort::PORT_C) {
+ _PORTC._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ else if (info.port == eATmegaPort::PORT_D) {
+ _PORTD._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ else if (info.port == eATmegaPort::PORT_E) {
+ _PORTE._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ else if (info.port == eATmegaPort::PORT_F) {
+ _PORTF._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ else if (info.port == eATmegaPort::PORT_G) {
+ _PORTG._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ else if (info.port == eATmegaPort::PORT_H) {
+ _PORTH._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ else if (info.port == eATmegaPort::PORT_J) {
+ _PORTJ._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ else if (info.port == eATmegaPort::PORT_K) {
+ _PORTK._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ else if (info.port == eATmegaPort::PORT_L) {
+ _PORTL._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ #elif defined(__AVR_TRM02__)
+ if (info.port == eATmegaPort::PORT_A) {
+ _PORTA._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ else if (info.port == eATmegaPort::PORT_B) {
+ _PORTB._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ else if (info.port == eATmegaPort::PORT_C) {
+ _PORTC._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ else if (info.port == eATmegaPort::PORT_D) {
+ _PORTD._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ #elif defined(__AVR_TRM03__)
+ if (info.port == eATmegaPort::PORT_B) {
+ _PORTB._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ else if (info.port == eATmegaPort::PORT_C) {
+ _PORTC._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ else if (info.port == eATmegaPort::PORT_D) {
+ _PORTD._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ #elif defined(__AVR_TRM04__)
+ if (info.port == eATmegaPort::PORT_A) {
+ _PORTA._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ else if (info.port == eATmegaPort::PORT_B) {
+ _PORTB._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ else if (info.port == eATmegaPort::PORT_C) {
+ _PORTC._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ else if (info.port == eATmegaPort::PORT_D) {
+ _PORTD._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ else if (info.port == eATmegaPort::PORT_E) {
+ _PORTE._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ else if (info.port == eATmegaPort::PORT_F) {
+ _PORTF._DDR.setValue(info.pinidx, mode == OUTPUT);
+ }
+ #endif
+}
+
+#if defined(__AVR_TRM01__) || defined(__AVR_TRM02__)
+ struct _ATmega_efuse {
+ uint8_t _BODLEVEL : 3;
+ uint8_t reserved1 : 5;
+ };
+
+ struct _ATmega_hfuse {
+ uint8_t _BOOTRST : 1;
+ uint8_t _BOOTSZ : 2;
+ uint8_t _EESAVE : 1;
+ uint8_t _WDTON : 1;
+ uint8_t _SPIEN : 1;
+ uint8_t _JTAGEN : 1;
+ uint8_t _OCDEN : 1;
+ };
+
+ struct _ATmega_lfuse {
+ uint8_t _CKSEL : 4;
+ uint8_t _SUT0 : 1;
+ uint8_t _SUT1 : 1;
+ uint8_t _CKOUT : 1;
+ uint8_t _CKDIV8 : 1;
+ };
+
+ #ifndef AVR_DEFAULT_LFUSE_VALUE
+ #define AVR_DEFAULT_LFUSE_VALUE 0xFF
+ #endif
+ #ifndef AVR_DEFAULT_HFUSE_VALUE
+ #define AVR_DEFAULT_HFUSE_VALUE 0x99
+ #endif
+ #ifndef AVR_DEFAULT_LFUSE_VALUE
+ #define AVR_DEFAULT_LFUSE_VALUE 0x62
+ #endif
+
+#elif defined(__AVR_TRM03__)
+ #if defined(__AVR_ATmega48A__) || defined(__AVR_ATmega48PA__)
+ struct _ATmega_efuse {
+ uint8_t _SELFPRGEN : 1;
+ uint8_t reserved1 : 7;
+ };
+
+ #ifndef AVR_DEFAULT_EFUSE_VALUE
+ #define AVR_DEFAULT_EFUSE_VALUE 0xFF
+ #endif
+
+ #elif defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__)
+ struct _ATmega_efuse {
+ uint8_t _BOOTRST : 1;
+ uint8_t _BOOTSZ : 2;
+ uint8_t reserved1 : 5;
+ };
+
+ #ifndef AVR_DEFAULT_EFUSE_VALUE
+ #define AVR_DEFAULT_EFUSE_VALUE 0xF9
+ #endif
+
+ #else // defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
+ struct _ATmega_efuse {
+ uint8_t _BODLEVEL : 3;
+ uint8_t reserved1 : 5;
+ };
+
+ #ifndef AVR_DEFAULT_EFUSE_VALUE
+ #define AVR_DEFAULT_EFUSE_VALUE 0xFF
+ #endif
+
+ #endif
+
+ #if defined(__AVR_ATmega48A__) || defined(__AVR_ATmega48PA__) || defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__)
+ struct _ATmega_hfuse {
+ uint8_t _BODLEVEL : 3;
+ uint8_t _EESAVE : 1;
+ uint8_t _WDTON : 1;
+ uint8_t _SPIEN : 1;
+ uint8_t _DWEN : 1;
+ uint8_t _RSTDISBL : 1;
+ };
+
+ #ifndef AVR_DEFAULT_HFUSE_VALUE
+ #define AVR_DEFAULT_HFUSE_VALUE 0xCF
+ #endif
+
+ #else // defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
+ struct _ATmega_hfuse {
+ uint8_t _BOOTRST : 1;
+ uint8_t _BOOTSZ : 2;
+ uint8_t _EESAVE : 1;
+ uint8_t _WDTON : 1;
+ uint8_t _SPIEN : 1;
+ uint8_t _DWEN : 1;
+ uint8_t _RSTDISBL : 1;
+ };
+
+ #ifndef AVR_DEFAULT_HFUSE_VALUE
+ #define AVR_DEFAULT_HFUSE_VALUE 0xC9
+ #endif
+
+ #endif
+
+ struct _ATmega_lfuse {
+ uint8_t _CKSEL : 4;
+ uint8_t _SUT0 : 1;
+ uint8_t _SUT1 : 1;
+ uint8_t _CKOUT : 1;
+ uint8_t _CKDIV8 : 1;
+ };
+
+ #ifndef AVR_DEFAULT_LFUSE_VALUE
+ #define AVR_DEFAULT_LFUSE_VALUE 0xC9
+ #endif
+
+#elif defined(__AVR_TRM04__)
+ struct _ATmega_efuse {
+ uint8_t _BODLEVEL : 3;
+ uint8_t _HWBE : 1;
+ uint8_t reserved1 : 4;
+ };
+
+ struct _ATmega_hfuse {
+ uint8_t _BOOTRST : 1;
+ uint8_t _BOOTSZ : 2;
+ uint8_t _EESAVE : 1;
+ uint8_t _WDTON : 1;
+ uint8_t _SPIEN : 1;
+ uint8_t _JTAGEN : 1;
+ uint8_t _OCDEN : 1;
+ };
+
+ struct _ATmega_lfuse {
+ uint8_t _CKSEL : 4;
+ uint8_t _SUT0 : 1;
+ uint8_t _SUT1 : 1;
+ uint8_t _CKOUT : 1;
+ uint8_t _CKDIV8 : 1;
+ };
+
+ // Default values if not already defined.
+ #ifndef AVR_DEFAULT_EFUSE_VALUE
+ #define AVR_DEFAULT_EFUSE_VALUE 0xF3
+ #endif
+ #ifndef AVR_DEFAULT_HFUSE_VALUE
+ #define AVR_DEFAULT_HFUSE_VALUE 0x99
+ #endif
+ #ifndef AVR_DEFAULT_LFUSE_VALUE
+ #define AVR_DEFAULT_LFUSE_VALUE 0x62
+ #endif
+
+#endif
+
+struct ATmega_efuse : public _ATmega_efuse {
+ inline ATmega_efuse(uint8_t val = 0) { *(uint8_t*)this = val; }
+ inline ATmega_efuse(const ATmega_efuse&) = default;
+};
+struct ATmega_hfuse : public _ATmega_hfuse {
+ inline ATmega_hfuse(uint8_t val = 0) { *(uint8_t*)this = val; }
+ inline ATmega_hfuse(const ATmega_hfuse&) = default;
+};
+struct ATmega_lfuse : public _ATmega_lfuse {
+ inline ATmega_lfuse(uint8_t val = 0) { *(uint8_t*)this = val; }
+ inline ATmega_lfuse(const ATmega_lfuse&) = default;
+};
diff --git a/Marlin/src/HAL/DUE/HAL_SPI.cpp b/Marlin/src/HAL/DUE/HAL_SPI.cpp
index f5bcaacee505..b638e27b4646 100644
--- a/Marlin/src/HAL/DUE/HAL_SPI.cpp
+++ b/Marlin/src/HAL/DUE/HAL_SPI.cpp
@@ -146,67 +146,67 @@
// addr: The byte address of bitbanding bit.
// bit: The bit position of bitbanding bit.
#define BITBAND_ADDRESS(addr, bit) \
- (((uint32_t)(addr) & 0xF0000000) + 0x02000000 + ((uint32_t)(addr)&0xFFFFF)*32 + (bit)*4)
+ (((uint32_t)(addr) & 0xF0000000) + 0x02000000 + ((uint32_t)(addr) & 0xFFFFF)*32 + (bit)*4)
// run at ~8 .. ~10Mhz - Rx version (Tx line not altered)
static uint8_t spiTransferRx0(uint8_t) { // using Mode 0
uint32_t bin = 0;
uint32_t work = 0;
- uint32_t BITBAND_MISO_PORT = BITBAND_ADDRESS( ((uint32_t)PORT(SD_MISO_PIN))+0x3C, PIN_SHIFT(SD_MISO_PIN)); /* PDSR of port in bitband area */
- uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SD_SCK_PIN)) + 0x30; /* SODR of port */
+ uint32_t BITBAND_MISO_PORT = BITBAND_ADDRESS( ((uint32_t)PORT(SD_MISO_PIN)) + 0x3C, PIN_SHIFT(SD_MISO_PIN)); // PDSR of port in bitband area
+ uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SD_SCK_PIN)) + 0x30; // SODR of port
uint32_t SCK_MASK = PIN_MASK(SD_SCK_PIN);
- /* The software SPI routine */
+ // The software SPI routine
__asm__ __volatile__(
A(".syntax unified") // is to prevent CM0,CM1 non-unified syntax
- /* bit 7 */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
- A("bfi %[bin],%[work],#7,#1") /* Store read bit as the bit 7 */
-
- /* bit 6 */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
- A("bfi %[bin],%[work],#6,#1") /* Store read bit as the bit 6 */
-
- /* bit 5 */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
- A("bfi %[bin],%[work],#5,#1") /* Store read bit as the bit 5 */
-
- /* bit 4 */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
- A("bfi %[bin],%[work],#4,#1") /* Store read bit as the bit 4 */
-
- /* bit 3 */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
- A("bfi %[bin],%[work],#3,#1") /* Store read bit as the bit 3 */
-
- /* bit 2 */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
- A("bfi %[bin],%[work],#2,#1") /* Store read bit as the bit 2 */
-
- /* bit 1 */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
- A("bfi %[bin],%[work],#1,#1") /* Store read bit as the bit 1 */
-
- /* bit 0 */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
- A("bfi %[bin],%[work],#0,#1") /* Store read bit as the bit 0 */
+ // bit 7
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ldr %[work],[%[bitband_miso_port]]") // PDSR on bitband area for required bit: work will be 1 or 0 based on port
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+ A("bfi %[bin],%[work],#7,#1") // Store read bit as the bit 7
+
+ // bit 6
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ldr %[work],[%[bitband_miso_port]]") // PDSR on bitband area for required bit: work will be 1 or 0 based on port
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+ A("bfi %[bin],%[work],#6,#1") // Store read bit as the bit 6
+
+ // bit 5
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ldr %[work],[%[bitband_miso_port]]") // PDSR on bitband area for required bit: work will be 1 or 0 based on port
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+ A("bfi %[bin],%[work],#5,#1") // Store read bit as the bit 5
+
+ // bit 4
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ldr %[work],[%[bitband_miso_port]]") // PDSR on bitband area for required bit: work will be 1 or 0 based on port
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+ A("bfi %[bin],%[work],#4,#1") // Store read bit as the bit 4
+
+ // bit 3
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ldr %[work],[%[bitband_miso_port]]") // PDSR on bitband area for required bit: work will be 1 or 0 based on port
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+ A("bfi %[bin],%[work],#3,#1") // Store read bit as the bit 3
+
+ // bit 2
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ldr %[work],[%[bitband_miso_port]]") // PDSR on bitband area for required bit: work will be 1 or 0 based on port
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+ A("bfi %[bin],%[work],#2,#1") // Store read bit as the bit 2
+
+ // bit 1
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ldr %[work],[%[bitband_miso_port]]") // PDSR on bitband area for required bit: work will be 1 or 0 based on port
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+ A("bfi %[bin],%[work],#1,#1") // Store read bit as the bit 1
+
+ // bit 0
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ldr %[work],[%[bitband_miso_port]]") // PDSR on bitband area for required bit: work will be 1 or 0 based on port
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+ A("bfi %[bin],%[work],#0,#1") // Store read bit as the bit 0
: [bin]"+r"(bin),
[work]"+r"(work)
@@ -263,77 +263,78 @@
* Note: The cast is unnecessary, but without it, this file triggers a GCC 4.8.3-2014 bug.
* Later GCC versions do not have this problem, but at this time (May 2018) Arduino still
* uses that buggy and obsolete GCC version!!
+ * They are implemented to handle MSB transfers.
*/
static pfnSpiTransfer spiTransferRx = (pfnSpiTransfer)spiTransferX;
static pfnSpiTransfer spiTransferTx = (pfnSpiTransfer)spiTransferX;
// Block transfers run at ~8 .. ~10Mhz - Tx version (Rx data discarded)
static void spiTxBlock0(const uint8_t *ptr, uint32_t todo) {
- uint32_t MOSI_PORT_PLUS30 = ((uint32_t) PORT(SD_MOSI_PIN)) + 0x30; /* SODR of port */
+ uint32_t MOSI_PORT_PLUS30 = ((uint32_t) PORT(SD_MOSI_PIN)) + 0x30; // SODR of port
uint32_t MOSI_MASK = PIN_MASK(SD_MOSI_PIN);
- uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SD_SCK_PIN)) + 0x30; /* SODR of port */
+ uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SD_SCK_PIN)) + 0x30; // SODR of port
uint32_t SCK_MASK = PIN_MASK(SD_SCK_PIN);
uint32_t work = 0;
uint32_t txval = 0;
- /* The software SPI routine */
+ // The software SPI routine
__asm__ __volatile__(
A(".syntax unified") // is to prevent CM0,CM1 non-unified syntax
L("loop%=")
- A("ldrb.w %[txval], [%[ptr]], #1") /* Load value to send, increment buffer */
- A("mvn %[txval],%[txval]") /* Negate value */
-
- /* Bit 7 */
- A("ubfx %[work],%[txval],#7,#1") /* Place bit 7 in bit 0 of work*/
-
- A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ubfx %[work],%[txval],#6,#1") /* Place bit 6 in bit 0 of work*/
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
-
- /* Bit 6 */
- A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ubfx %[work],%[txval],#5,#1") /* Place bit 5 in bit 0 of work*/
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
-
- /* Bit 5 */
- A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ubfx %[work],%[txval],#4,#1") /* Place bit 4 in bit 0 of work*/
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
-
- /* Bit 4 */
- A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ubfx %[work],%[txval],#3,#1") /* Place bit 3 in bit 0 of work*/
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
-
- /* Bit 3 */
- A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ubfx %[work],%[txval],#2,#1") /* Place bit 2 in bit 0 of work*/
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
-
- /* Bit 2 */
- A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ubfx %[work],%[txval],#1,#1") /* Place bit 1 in bit 0 of work*/
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
-
- /* Bit 1 */
- A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ubfx %[work],%[txval],#0,#1") /* Place bit 0 in bit 0 of work*/
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
-
- /* Bit 0 */
- A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("subs %[todo],#1") /* Decrement count of pending words to send, update status */
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
- A("bne.n loop%=") /* Repeat until done */
+ A("ldrb.w %[txval], [%[ptr]], #1") // Load value to send, increment buffer
+ A("mvn %[txval],%[txval]") // Negate value
+
+ // Bit 7
+ A("ubfx %[work],%[txval],#7,#1") // Place bit 7 in bit 0 of work
+
+ A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") // Access the proper SODR or CODR registers based on that bit
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ubfx %[work],%[txval],#6,#1") // Place bit 6 in bit 0 of work
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+
+ // Bit 6
+ A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") // Access the proper SODR or CODR registers based on that bit
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ubfx %[work],%[txval],#5,#1") // Place bit 5 in bit 0 of work
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+
+ // Bit 5
+ A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") // Access the proper SODR or CODR registers based on that bit
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ubfx %[work],%[txval],#4,#1") // Place bit 4 in bit 0 of work
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+
+ // Bit 4
+ A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") // Access the proper SODR or CODR registers based on that bit
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ubfx %[work],%[txval],#3,#1") // Place bit 3 in bit 0 of work
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+
+ // Bit 3
+ A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") // Access the proper SODR or CODR registers based on that bit
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ubfx %[work],%[txval],#2,#1") // Place bit 2 in bit 0 of work
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+
+ // Bit 2
+ A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") // Access the proper SODR or CODR registers based on that bit
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ubfx %[work],%[txval],#1,#1") // Place bit 1 in bit 0 of work
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+
+ // Bit 1
+ A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") // Access the proper SODR or CODR registers based on that bit
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ubfx %[work],%[txval],#0,#1") // Place bit 0 in bit 0 of work
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+
+ // Bit 0
+ A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") // Access the proper SODR or CODR registers based on that bit
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("subs %[todo],#1") // Decrement count of pending words to send, update status
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+ A("bne.n loop%=") // Repeat until done
: [ptr]"+r" ( ptr ) ,
[todo]"+r" ( todo ) ,
@@ -354,63 +355,63 @@
uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SD_SCK_PIN)) + 0x30; /* SODR of port */
uint32_t SCK_MASK = PIN_MASK(SD_SCK_PIN);
- /* The software SPI routine */
+ // The software SPI routine
__asm__ __volatile__(
A(".syntax unified") // is to prevent CM0,CM1 non-unified syntax
L("loop%=")
- /* bit 7 */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
- A("bfi %[bin],%[work],#7,#1") /* Store read bit as the bit 7 */
-
- /* bit 6 */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
- A("bfi %[bin],%[work],#6,#1") /* Store read bit as the bit 6 */
-
- /* bit 5 */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
- A("bfi %[bin],%[work],#5,#1") /* Store read bit as the bit 5 */
-
- /* bit 4 */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
- A("bfi %[bin],%[work],#4,#1") /* Store read bit as the bit 4 */
-
- /* bit 3 */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
- A("bfi %[bin],%[work],#3,#1") /* Store read bit as the bit 3 */
-
- /* bit 2 */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
- A("bfi %[bin],%[work],#2,#1") /* Store read bit as the bit 2 */
-
- /* bit 1 */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
- A("bfi %[bin],%[work],#1,#1") /* Store read bit as the bit 1 */
-
- /* bit 0 */
- A("str %[sck_mask],[%[sck_port]]") /* SODR */
- A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
- A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
- A("bfi %[bin],%[work],#0,#1") /* Store read bit as the bit 0 */
-
- A("subs %[todo],#1") /* Decrement count of pending words to send, update status */
- A("strb.w %[bin], [%[ptr]], #1") /* Store read value into buffer, increment buffer pointer */
- A("bne.n loop%=") /* Repeat until done */
+ // bit 7
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ldr %[work],[%[bitband_miso_port]]") // PDSR on bitband area for required bit: work will be 1 or 0 based on port
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+ A("bfi %[bin],%[work],#7,#1") // Store read bit as the bit 7
+
+ // bit 6
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ldr %[work],[%[bitband_miso_port]]") // PDSR on bitband area for required bit: work will be 1 or 0 based on port
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+ A("bfi %[bin],%[work],#6,#1") // Store read bit as the bit 6
+
+ // bit 5
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ldr %[work],[%[bitband_miso_port]]") // PDSR on bitband area for required bit: work will be 1 or 0 based on port
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+ A("bfi %[bin],%[work],#5,#1") // Store read bit as the bit 5
+
+ // bit 4
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ldr %[work],[%[bitband_miso_port]]") // PDSR on bitband area for required bit: work will be 1 or 0 based on port
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+ A("bfi %[bin],%[work],#4,#1") // Store read bit as the bit 4
+
+ // bit 3
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ldr %[work],[%[bitband_miso_port]]") // PDSR on bitband area for required bit: work will be 1 or 0 based on port
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+ A("bfi %[bin],%[work],#3,#1") // Store read bit as the bit 3
+
+ // bit 2
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ldr %[work],[%[bitband_miso_port]]") // PDSR on bitband area for required bit: work will be 1 or 0 based on port
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+ A("bfi %[bin],%[work],#2,#1") // Store read bit as the bit 2
+
+ // bit 1
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ldr %[work],[%[bitband_miso_port]]") // PDSR on bitband area for required bit: work will be 1 or 0 based on port
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+ A("bfi %[bin],%[work],#1,#1") // Store read bit as the bit 1
+
+ // bit 0
+ A("str %[sck_mask],[%[sck_port]]") // SODR
+ A("ldr %[work],[%[bitband_miso_port]]") // PDSR on bitband area for required bit: work will be 1 or 0 based on port
+ A("str %[sck_mask],[%[sck_port],#0x4]") // CODR
+ A("bfi %[bin],%[work],#0,#1") // Store read bit as the bit 0
+
+ A("subs %[todo],#1") // Decrement count of pending words to send, update status
+ A("strb.w %[bin], [%[ptr]], #1") // Store read value into buffer, increment buffer pointer
+ A("bne.n loop%=") // Repeat until done
: [ptr]"+r"(ptr),
[todo]"+r"(todo),
@@ -423,15 +424,34 @@
);
}
+ static inline uint8_t _flip_bits_8(uint8_t v) {
+ uint8_t result = 0;
+ for (int n = 0; n < 8; n++) {
+ result <<= 1;
+ bool bitval = ( v & ( 1 << n ) ) != 0;
+ result |= bitval;
+ }
+ return result;
+ }
+
+ static inline uint8_t _spiTransferRx_ordered(uint8_t txval) {
+ return ( _spi_bit_order == SPI_BITORDER_MSB ? spiTransferRx(txval) : _flip_bits_8(spiTransferRx(_flip_bits_8(txval))) );
+ }
+
+ static inline void _spiTransferTx_ordered(uint8_t b) {
+ if (_spi_bit_order == SPI_BITORDER_LSB) b = _flip_bits_8(b);
+ (void)spiTransferTx(b);
+ }
+
static void spiTxBlockX(const uint8_t *buf, uint32_t todo) {
do {
- (void)spiTransferTx(*buf++);
+ _spiTransferTx_ordered(*buf++);
} while (--todo);
}
static void spiRxBlockX(uint8_t *buf, uint32_t todo) {
do {
- *buf++ = spiTransferRx(0xFF);
+ *buf++ = _spiTransferRx_ordered();
} while (--todo);
}
@@ -439,6 +459,8 @@
static pfnSpiTxBlock spiTxBlock = (pfnSpiTxBlock)spiTxBlockX;
static pfnSpiRxBlock spiRxBlock = (pfnSpiRxBlock)spiRxBlockX;
+ static int _spi_bit_order = SPI_BITORDER_DEFAULT;
+
#if MB(ALLIGATOR)
#define _SS_WRITE(S) WRITE(SD_SS_PIN, S)
#else
@@ -453,16 +475,56 @@
SET_OUTPUT(SD_MOSI_PIN);
}
- uint8_t spiRec() {
+ void spiSetupChipSelect(int pin) {
+ OUT_WRITE(pin, HIGH);
+ }
+
+ void spiSetBitOrder(int bitOrder) {
+ _spi_bit_order = bitOrder;
+ }
+
+ void spiSetClockMode(int clockMode) {
+ if (clockMode != SPI_CLKMODE_0) {
+ // TODO.
+ for (;;) {}
+ }
+ }
+
+ void spiEstablish() { /* do nothing */ }
+
+ uint8_t spiRec(uint8_t txval) {
_SS_WRITE(LOW);
WRITE(SD_MOSI_PIN, HIGH); // Output 1s 1
- uint8_t b = spiTransferRx(0xFF);
+ uint8_t b = _spiTransferRx_ordered(txval);
_SS_WRITE(HIGH);
return b;
}
- void spiRead(uint8_t *buf, uint16_t nbyte) {
+ uint16_t spiRec16(uint16_t txval) {
+ const bool msb = _spi_bit_order == SPI_BITORDER_MSB;
+ uint8_t tx_first, tx_second;
+ if (msb) {
+ tx_first = txval >> 8;
+ tx_second = txval & 0xFF;
+ }
+ else {
+ tx_first = txval & 0xFF;
+ tx_second = txval >> 8;
+ }
+ _SS_WRITE(LOW);
+ WRITE(SD_MOSI_PIN, HIGH); // Output 1s 1
+ uint16_t v = msb ? (uint16_t)_spiTransferRx_ordered(tx_first) << 8 : _spiTransferRx_ordered(tx_first);
+ v |= msb ? _spiTransferRx_ordered(tx_second) : (uint16_t)_spiTransferRx_ordered(tx_second) << 8;
+ _SS_WRITE(HIGH);
+ return v;
+ }
+
+ void spiRead(uint8_t *buf, uint16_t nbyte, uint8_t txval) {
if (nbyte) {
+ if (txval != 0xFF) {
+ // TODO.
+ for (;;) {}
+ }
_SS_WRITE(LOW);
WRITE(SD_MOSI_PIN, HIGH); // Output 1s 1
spiRxBlock(buf, nbyte);
@@ -472,17 +534,58 @@
void spiSend(uint8_t b) {
_SS_WRITE(LOW);
- (void)spiTransferTx(b);
+ _spiTransferTx_ordered(b);
+ _SS_WRITE(HIGH);
+ }
+
+ static void _spiSend16Internal(uint16_t v, bool msb) {
+ _spiTransferTx_ordered(msb ? ( v >> 8 ) : ( v & 0xFF ));
+ _spiTransferTx_ordered(msb ? ( v & 0xFF ) : ( v >> 8 ));
+ }
+
+ void spiSend16(uint16_t v) {
+ const bool msb = _spi_bit_order == SPI_BITORDER_MSB;
+ _SS_WRITE(LOW);
+ _spiSend16Internal(v);
_SS_WRITE(HIGH);
}
void spiSendBlock(uint8_t token, const uint8_t *buf) {
_SS_WRITE(LOW);
- (void)spiTransferTx(token);
+ _spiTransferTx_ordered(token);
spiTxBlock(buf, 512);
_SS_WRITE(HIGH);
}
+ void spiWrite(const uint8_t *buf, uint16_t cnt) {
+ _SS_WRITE(LOW);
+ spiTxBlock(buf, cnt);
+ _SS_WRITE(HIGH);
+ }
+
+ void spiWrite16(const uint16_t *buf, uint16_t cnt) {
+ const bool msb = _spi_bit_order == SPI_BITORDER_MSB;
+ _SS_WRITE(LOW);
+ for (uint16_t n = 0; n < cnt; n++)
+ _spiSend16Internal(buf[n], msb);
+ _SS_WRITE(HIGH);
+ }
+
+ void spiWriteRepeat(uint8_t val, uint16_t repcnt) {
+ _SS_WRITE(LOW);
+ for (uint16_t n = 0; n < repcnt; n++)
+ _spiTransferTx_ordered(val);
+ _SS_WRITE(HIGH);
+ }
+
+ void spiWriteRepeat16(uint16_t val, uint16_t repcnt) {
+ const bool msb = _spi_bit_order == SPI_BITORDER_MSB;
+ _SS_WRITE(LOW);
+ for (uint16_t n = 0; n < repcnt; n++)
+ _spiSend16Internal(val, msb);
+ _SS_WRITE(HIGH);
+ }
+
/**
* spiRate should be
* 0 : 8 - 10 MHz
@@ -493,7 +596,9 @@
* 5 : 250 - 312 kHz
* 6 : 125 - 156 kHz
*/
- void spiInit(uint8_t spiRate) {
+ void spiInit(uint8_t spiRate, const int hint_sck/*=-1*/, const int hint_miso/*=-1*/, const int hint_mosi/*=-1*/, const int hint_cs/*=-1*/) {
+ // Ignore pin hints... TODO?
+
switch (spiRate) {
case 0:
spiTransferTx = (pfnSpiTransfer)spiTransferTx0;
@@ -521,19 +626,224 @@
WRITE(SD_SCK_PIN, LOW);
}
- /** Begin SPI transaction, set clock, bit order, data mode */
- void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) {
- // TODO: to be implemented
+ void spiInitEx(uint32_t maxClockFreq, int hint_sck, int hint_miso, int hint_mosi, int hint_cs) {
+ // Use Marlin datarates
+ uint8_t spiRate;
+ if (maxClockFreq >= 20000000) spiRate = SPI_FULL_SPEED;
+ else if (maxClockFreq >= 5000000) spiRate = SPI_HALF_SPEED;
+ else if (maxClockFreq >= 2500000) spiRate = SPI_QUARTER_SPEED;
+ else if (maxClockFreq >= 1250000) spiRate = SPI_EIGHTH_SPEED;
+ else if (maxClockFreq >= 625000) spiRate = SPI_SPEED_5;
+ else if (maxClockFreq >= 300000) spiRate = SPI_SPEED_6;
+ else spiRate = SPI_SPEED_6;
+
+ spiInit(spiRate, hint_sck, hint_miso, hint_mosi, hint_cs);
}
+ void spiClose() { /* do nothing */ }
+
#pragma GCC reset_options
#else // !SOFTWARE_SPI
+ // https://github.com/arduino/ArduinoCore-sam/blob/master/system/libsam/include/spi.h
+
#define WHILE_TX(N) while ((SPI0->SPI_SR & SPI_SR_TDRE) == (N))
#define WHILE_RX(N) while ((SPI0->SPI_SR & SPI_SR_RDRF) == (N))
#define FLUSH_TX() do{ WHILE_RX(1) SPI0->SPI_RDR; }while(0)
+ #if 0
+ // ------------------------
+ // Hardware SPI
+ // https://github.com/arduino/ArduinoCore-sam/blob/master/libraries/SPI/src/SPI.h
+ // ------------------------
+ #include
+
+ static SPISettings spiConfig;
+
+ // Generic SPI implementation (test me please)
+ static bool _has_spi_pins = false;
+ static int _spi_pin_cs; // all SPI pins are tied together (CS, MISO, MOSI, SCK)
+
+ static uint32_t _spi_clock;
+ static int _spi_bitOrder;
+ static int _spi_clockMode;
+
+ // ------------------------
+ // hardware SPI
+ // https://github.com/arduino/ArduinoCore-sam/blob/master/libraries/SPI/src/SPI.h
+ // ------------------------
+ void spiBegin() {}
+
+ void spiSetupChipSelect(int pin) {
+ OUT_WRITE(pin, HIGH);
+ }
+
+ void spiInitEx(uint32_t clock, const int hint_sck/*=-1*/, const int hint_miso/*=-1*/, const int hint_mosi/*=-1*/, const int hint_cs/*=-1*/) {
+ _spi_clock = clock;
+ _spi_bitOrder = MSBFIRST;
+ _spi_clockMode = SPI_MODE0;
+ spiConfig = SPISettings(clock, MSBFIRST, SPI_MODE0);
+ // We ignore all pins other than chip-select because they have to be tied together anyway.
+ if (hint_cs != -1) {
+ SPI.begin(hint_cs);
+ _spi_pin_cs = hint_cs;
+ _has_spi_pins = true;
+ }
+ else {
+ SPI.begin();
+ _has_spi_pins = false;
+ }
+ }
+
+ void spiInit(uint8_t spiRate, int hint_sck, int hint_miso, int hint_mosi, int hint_cs) {
+ // Use Marlin datarates
+ uint32_t clock;
+ switch (spiRate) {
+ case SPI_FULL_SPEED: clock = 8000000; break;
+ case SPI_HALF_SPEED: clock = 4000000; break;
+ case SPI_QUARTER_SPEED: clock = 2000000; break;
+ case SPI_EIGHTH_SPEED: clock = 1000000; break;
+ case SPI_SIXTEENTH_SPEED: clock = 500000; break;
+ case SPI_SPEED_5: clock = 250000; break;
+ case SPI_SPEED_6: clock = 125000; break;
+ default: clock = 4000000; break; // Default from the SPI library
+ }
+ spiInitEx(clock, hint_sck, hint_miso, hint_mosi, hint_cs);
+ }
+
+ void spiClose() {
+ if (_has_spi_pins)
+ SPI.end(_spi_pin_cs);
+ else
+ SPI.end();
+ _has_spi_pins = false;
+ _spi_pin_cs = -1;
+ }
+
+ void spiSetBitOrder(int bitOrder) {
+ _spi_bitOrder = (bitOrder == SPI_BITORDER_MSB) ? (MSBFIRST) : (LSBFIRST);
+ spiConfig = SPISettings(_spi_clock, _spi_bitOrder, _spi_clockMode);
+ }
+
+ void spiSetClockMode(int clockMode) {
+ if (clockMode == SPI_CLKMODE_0)
+ _spi_clockMode = SPI_MODE0;
+ else if (clockMode == SPI_CLKMODE_1)
+ _spi_clockMode = SPI_MODE1;
+ else if (clockMode == SPI_CLKMODE_2)
+ _spi_clockMode = SPI_MODE2;
+ else if (clockMode == SPI_CLKMODE_3)
+ _spi_clockMode = SPI_MODE3;
+ else return;
+
+ spiConfig = SPISettings(_spi_clock, _spi_bitOrder, _spi_clockMode);
+ }
+
+ void spiEstablish() { /* do nothing */ }
+
+ uint8_t spiRec(uint8_t txval) {
+ if (_has_spi_pins)
+ SPI.beginTransaction(_spi_pin_cs, spiConfig);
+ else
+ SPI.beginTransaction(spiConfig);
+ uint8_t returnByte = SPI.transfer(txval);
+ if (_has_spi_pins)
+ SPI.endTransaction(_spi_pin_cs);
+ else
+ SPI.endTransaction();
+ return returnByte;
+ }
+
+ uint16_t spiRec16(uint16_t txval) {
+ if (_has_spi_pins)
+ sdSPI.beginTransaction(_spi_pin_cs, spiConfig);
+ else
+ sdSPI.beginTransaction(spiConfig);
+ uint16_t returnVal = sdSPI.transfer16(txval);
+ if (_has_spi_pins)
+ sdSPI.endTransaction(_spi_pin_cs);
+ else
+ sdSPI.endTransaction();
+ return returnVal;
+ }
+
+ void spiRead(uint8_t *buf, uint16_t nbyte, uint8_t txval) {
+ if (nbyte == 0) return;
+ memset(buf, txval, nbyte);
+ if (_has_spi_pins == false) {
+ SPI.beginTransaction(spiConfig);
+ SPI.transfer(buf, nbyte);
+ }
+ else {
+ SPI.beginTransaction(_spi_pin_cs, spiConfig);
+ SPI.transfer(_spi_pin_cs, buf, nbyte);
+ }
+ // There is no pin-specific endTransaction method.
+ SPI.endTransaction();
+ }
+
+ void spiSend(uint8_t b) {
+ if (_has_spi_pins) {
+ SPI.beginTransaction(_spi_pin_cs, spiConfig);
+ SPI.transfer(_spi_pin_cs, b);
+ }
+ else {
+ SPI.beginTransaction(spiConfig);
+ SPI.transfer(b);
+ }
+ SPI.endTransaction();
+ }
+
+ void spiSend16(uint16_t v) {
+ if (_has_spi_pins) {
+ sdSPI.beginTransaction(_spi_pin_cs, spiConfig);
+ sdSPI.transfer16(_spi_pin_cs, v);
+ }
+ else {
+ sdSPI.beginTransaction(spiConfig);
+ sdSPI.transfer16(v);
+ }
+ sdSPI.endTransaction();
+ }
+
+ // SD-card specific.
+ void spiSendBlock(uint8_t token, const uint8_t *buf) {
+ if (_has_spi_pins) {
+ SPI.beginTransaction(_spi_pin_cs, spiConfig);
+ SPI.transfer(_spi_pin_cs, token);
+ SPI.transfer(_spi_pin_cs, (uint8_t*)buf, 512);
+ }
+ else {
+ SPI.beginTransaction(spiConfig);
+ SPI.transfer(token);
+ SPI.transfer(buf, 512);
+ }
+ SPI.endTransaction();
+ }
+
+ void spiWrite(const uint8_t *buf, uint16_t cnt) {
+ // TODO: really has to be improved.
+ for (uint16_t n = 0; n < cnt; n++)
+ spiSend(buf[n]);
+ }
+
+ void spiWrite16(const uint16_t *buf, uint16_t cnt) {
+ for (uint16_t n = 0; n < cnt; n++)
+ spiSend16(buf[n]);
+ }
+
+ void spiWriteRepeat(uint8_t val, uint16_t repcnt) {
+ for (uint16_t n = 0; n < repcnt; n++)
+ spiSend(val);
+ }
+
+ void spiWriteRepeat16(uint16_t val, uint16_t repcnt) {
+ for (uint16_t n = 0; n < repcnt; n++)
+ spiSend16(val);
+ }
+ #endif
+
#if MB(ALLIGATOR)
// slave selects controlled by SPI controller
@@ -541,15 +851,19 @@
// ------------------------
// hardware SPI
+ // https://github.com/arduino/ArduinoCore-sam/blob/master/system/libsam/source/spi.c
+ // https://www.gadgetronicx.com/spi-protocol-tutorial-arm/
// ------------------------
static bool spiInitialized = false;
- void spiInit(uint8_t spiRate) {
+ void spiInit(uint8_t spiRate, const int hint_sck/*=-1*/, const int hint_miso/*=-1*/, const int hint_mosi/*=-1*/, const int hint_cs/*=-1*/) {
+ // I guess ignore the hinted pins?
+
if (spiInitialized) return;
// 8.4 MHz, 4 MHz, 2 MHz, 1 MHz, 0.5 MHz, 0.329 MHz, 0.329 MHz
constexpr int spiDivider[] = { 10, 21, 42, 84, 168, 255, 255 };
- if (spiRate > 6) spiRate = 1;
+ if (spiRate > SPI_SPEED_6) spiRate = SPI_HALF_SPEED;
// Set SPI mode 1, clock, select not active after transfer, with delay between transfers
SPI_ConfigureNPCS(SPI0, SPI_CHAN_DAC,
@@ -564,10 +878,31 @@
SPI_ConfigureNPCS(SPI0, SPI_CHAN, SPI_CSR_NCPHA |
SPI_CSR_CSAAT | SPI_CSR_SCBR(spiDivider[spiRate]) |
SPI_CSR_DLYBCT(1));
+
+ SPI0->SPI_CR &= ~( 1 << 5 ); // MSB config
SPI_Enable(SPI0);
spiInitialized = true;
}
+ void spiInitEx(uint32_t maxClockFreq, int hint_sck, int hint_miso, int hint_mosi, int hint_cs) {
+ // Use Marlin datarates
+ uint8_t spiRate;
+ if (maxClockFreq >= 20000000) spiRate = SPI_FULL_SPEED;
+ else if (maxClockFreq >= 5000000) spiRate = SPI_HALF_SPEED;
+ else if (maxClockFreq >= 2500000) spiRate = SPI_QUARTER_SPEED;
+ else if (maxClockFreq >= 1250000) spiRate = SPI_EIGHTH_SPEED;
+ else if (maxClockFreq >= 625000) spiRate = SPI_SPEED_5;
+ else if (maxClockFreq >= 300000) spiRate = SPI_SPEED_6;
+ else spiRate = SPI_SPEED_6;
+
+ spiInit(spiRate, hint_sck, hint_miso, hint_mosi, hint_cs);
+ }
+
+ void spiClose() {
+ spiInitialized = false;
+ SPI_Disable(SPI0);
+ }
+
void spiBegin() {
if (spiInitialized) return;
@@ -614,10 +949,32 @@
spiInit(1);
}
+ void spiSetupChipSelect(int pin) {
+ OUT_WRITE(pin, HIGH);
+ }
+
+ void spiSetBitOrder(int bitOrder) {
+ if (bitOrder == SPI_BITORDER_MSB) {
+ SPI0->SPI_CR &= ~( 1 << 5 ); // 6th bit.
+ }
+ else if (bitOrder == SPI_BITORDER_LSB) {
+ SPI0->SPI_CR |= ( 1 << 5 );
+ }
+ }
+
+ void spiSetClockMode(int clockMode) {
+ if (clockMode != SPI_CLKMODE_0) {
+ // TODO.
+ for (;;) {}
+ }
+ }
+
+ void spiEstablish() { /* do nothing */ }
+
// Read single byte from SPI
- uint8_t spiRec() {
+ uint8_t spiRec(uint8_t txval) {
// write dummy byte with address and end transmission flag
- SPI0->SPI_TDR = 0x000000FF | SPI_PCS(SPI_CHAN) | SPI_TDR_LASTXFER;
+ SPI0->SPI_TDR = txval | SPI_PCS(SPI_CHAN) | SPI_TDR_LASTXFER;
WHILE_TX(0);
WHILE_RX(0);
@@ -626,6 +983,37 @@
return SPI0->SPI_RDR;
}
+ uint16_t spiRec16(uint16_t txval) {
+ const bool msb = !TEST(SPI0->SPI_CR, 5);
+
+ uint8_t tx_first, tx_second;
+ if (msb) {
+ tx_first = txval >> 8;
+ tx_second = txval & 0xFF;
+ }
+ else {
+ tx_first = txval & 0xFF;
+ tx_second = txval >> 8;
+ }
+
+ SPI0->SPI_TDR = tx_first | SPI_PCS(SPI_CHAN);
+
+ WHILE_TX(0);
+ WHILE_RX(0);
+
+ uint16_t v = msb ? uint16_t(SPI0->SPI_RDR & 0xFF) << 8 : SPI0->SPI_RDR & 0xFF;
+
+ SPI0->SPI_TDR = tx_second | SPI_PCS(SPI_CHAN) | SPI_TDR_LASTXFER;
+
+ WHILE_TX(0);
+ WHILE_RX(0);
+
+ v |= (msb ? SPI0->SPI_RDR & 0xFF : uint16_t(SPI0->SPI_RDR & 0xFF) << 8);
+
+ return v;
+ }
+
+ #if 0
uint8_t spiRec(uint32_t chan) {
WHILE_TX(0);
@@ -637,14 +1025,15 @@
return SPI0->SPI_RDR;
}
+ #endif
// Read from SPI into buffer
- void spiRead(uint8_t *buf, uint16_t nbyte) {
+ void spiRead(uint8_t *buf, uint16_t nbyte, uint8_t txval) {
if (!nbyte) return;
--nbyte;
for (int i = 0; i < nbyte; i++) {
//WHILE_TX(0);
- SPI0->SPI_TDR = 0x000000FF | SPI_PCS(SPI_CHAN);
+ SPI0->SPI_TDR = txval | SPI_PCS(SPI_CHAN);
WHILE_RX(0);
buf[i] = SPI0->SPI_RDR;
//DELAY_US(1U);
@@ -662,10 +1051,22 @@
//DELAY_US(1U);
}
- void spiSend(const uint8_t *buf, size_t nbyte) {
+ void spiSend16(uint16_t v) {
+ const bool msb = !TEST(SPI0->SPI_CR, 5);
+ SPI0->SPI_TDR = uint32_t(msb ? (v & 0xFF) : (v >> 8)) | SPI_PCS(SPI_CHAN);
+ WHILE_TX(0);
+ WHILE_RX(0);
+ SPI0->SPI_RDR;
+ SPI0->SPI_TDR = uint32_t(msb ? (v >> 8) : (v & 0xFF)) | SPI_PCS(SPI_CHAN) | SPI_TDR_LASTXFER;
+ WHILE_TX(0);
+ WHILE_RX(0);
+ SPI0->SPI_RDR;
+ }
+
+ void spiWrite(const uint8_t *buf, uint16_t nbyte) {
if (!nbyte) return;
--nbyte;
- for (size_t i = 0; i < nbyte; i++) {
+ for (uint16_t i = 0; i < nbyte; i++) {
SPI0->SPI_TDR = (uint32_t)buf[i] | SPI_PCS(SPI_CHAN);
WHILE_TX(0);
WHILE_RX(0);
@@ -675,6 +1076,22 @@
spiSend(buf[nbyte]);
}
+ void spiWrite16(const uint16_t *buf, uint16_t cnt) {
+ for (uint16_t n = 0; n < cnt; n++)
+ spiSend16(buf[n]);
+ }
+
+ void spiWriteRepeat(uint8_t val, uint16_t repcnt) {
+ for (uint16_t n = 0; n < repcnt; n++)
+ spiSend(val);
+ }
+
+ void spiWriteRepeat16(uint16_t val, uint16_t repcnt) {
+ for (uint16_t n = 0; n < repcnt; n++)
+ spiSend16(val);
+ }
+
+ #if 0
void spiSend(uint32_t chan, byte b) {
WHILE_TX(0);
// write byte with address and end transmission flag
@@ -694,6 +1111,7 @@
}
spiSend(chan, buf[nbyte]);
}
+ #endif
// Write from buffer to SPI
void spiSendBlock(uint8_t token, const uint8_t *buf) {
@@ -711,11 +1129,6 @@
spiSend(buf[511]);
}
- /** Begin SPI transaction, set clock, bit order, data mode */
- void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) {
- // TODO: to be implemented
- }
-
#else // U8G compatible hardware SPI
#define SPI_MODE_0_DUE_HW 2 // DUE CPHA control bit is inverted
@@ -739,7 +1152,7 @@
* macro returns immediately which can result in the SPI chip select going
* inactive before all the data has been sent.
*
- * The TMC2130 library uses SPI0->SPI_CSR[3].
+ * The TMC2130 library uses SPI0->SPI_CSR[3] (???)
*
* The U8G hardware SPI uses SPI0->SPI_CSR[0]. The system hangs and/or the
* FYSETC_MINI_12864 gets upset if lower baud rates are used and the SD card
@@ -755,12 +1168,16 @@
* display to use software SPI.
*/
- void spiInit(uint8_t spiRate=6) { // Default to slowest rate if not specified)
- // Also sets U8G SPI rate to 4MHz and the SPI mode to 3
+ void spiInit(uint8_t spiRate, const int hint_sck/*=-1*/, const int hint_miso/*=-1*/, const int hint_mosi/*=-1*/, const int hint_cs/*=-1*/) {
+ // We ignore the hinted pins? Why don't we use the standard, already implemented SPI library?
+
+ // Default to slowest rate if not specified)
+ // Also sets U8G SPI rate to 4MHz and the SPI mode to 3
+ if (spiRate == SPI_SPEED_DEFAULT) spiRate = SPI_SPEED_6;
// 8.4 MHz, 4 MHz, 2 MHz, 1 MHz, 0.5 MHz, 0.329 MHz, 0.329 MHz
constexpr int spiDivider[] = { 10, 21, 42, 84, 168, 255, 255 };
- if (spiRate > 6) spiRate = 1;
+ if (spiRate > SPI_SPEED_6) spiRate = SPI_HALF_SPEED;
// Enable PIOA and SPI0
REG_PMC_PCER0 = (1UL << ID_PIOA) | (1UL << ID_SPI0);
@@ -783,7 +1200,27 @@
SPI0->SPI_CSR[0] = SPI_CSR_SCBR(spiDivider[1]) | SPI_CSR_CSAAT | SPI_MODE_3_DUE_HW; // U8G default to 4MHz
}
- void spiBegin() { spiInit(); }
+ void spiClose() {
+ // Disable the SPI.
+ SPI0->SPI_CR = SPI_CR_SPIDIS;
+ }
+
+ void spiBegin() { spiInit(SPI_SPEED_DEFAULT); }
+
+ void spiSetupChipSelect(int pin) {
+ OUT_WRITE(pin, HIGH);
+ }
+
+ void spiSetBitOrder(int bitOrder) {
+ if (bitOrder == SPI_BITORDER_MSB) {
+ SPI0->SPI_CR &= ~( 1 << 5 );
+ }
+ else if (bitOrder == SPI_BITORDER_LSB) {
+ SPI0->SPI_CR |= ( 1 << 5 );
+ }
+ }
+
+ void spiEstablish() { /* do nothing */ }
static uint8_t spiTransfer(uint8_t data) {
WHILE_TX(0);
@@ -793,20 +1230,73 @@
return SPI0->SPI_RDR;
}
- uint8_t spiRec() { return (uint8_t)spiTransfer(0xFF); }
+ uint8_t spiRec(uint8_t txval) {
+ return (uint8_t)spiTransfer(txval);
+ }
+
+ uint16_t spiRec16(uint16_t txval) {
+ const bool msb = !TEST(SPI0->SPI_CR, 5);
+ uint8_t tx_first, tx_second;
+ if (msb) {
+ take_first = txval >> 8;
+ take_second = txval & 0xFF;
+ }
+ else {
+ take_first = tx_val & 0xFF;
+ take_second = tx_val >> 8;
+ }
+ if (msb)
+ return (uint16_t)spiRec(take_first) << 8 | (uint16_t)spiRec(take_second);
+ else
+ return (uint16_t)spiRec(take_first) | (uint16_t)spiRec(take_second) << 8;
+ }
- void spiRead(uint8_t *buf, uint16_t nbyte) {
+ void spiRead(uint8_t *buf, uint16_t nbyte, uint8_t txval) {
for (int i = 0; i < nbyte; i++)
- buf[i] = spiTransfer(0xFF);
+ buf[i] = spiTransfer(txval);
}
- void spiSend(uint8_t data) { spiTransfer(data); }
+ void spiSend(uint8_t data) {
+ spiTransfer(data);
+ }
+
+ void spiSend16(uint16_t data) {
+ const bool msb = !TEST(SPI0->SPI_CR, 5);
+ if (msb) {
+ spiSend(data >> 8);
+ spiSend(data & 0xFF);
+ }
+ else {
+ spiSend(data & 0xFF);
+ spiSend(data >> 8);
+ }
+ }
void spiSend(const uint8_t *buf, size_t nbyte) {
for (uint16_t i = 0; i < nbyte; i++)
spiTransfer(buf[i]);
}
+ void spiWrite(const uint8_t *buf, uint16_t nbyte) {
+ for (uint16_t n = 0; n < nbyte; n++)
+ spiTransfer(buf[n]);
+ }
+
+ void spiWrite16(const uint16_t *buf, uint16_t cnt) {
+ for (uint16_t n = 0; n < cnt; n++)
+ spiSend16(buf[n]);
+ }
+
+ void spiWriteRepeat(uint8_t val, uint16_t repcnt) {
+ for (uint16_t n = 0; n < repcnt; n++)
+ spiSend(val);
+ }
+
+ void spiWriteRepeat16(uint16_t val, uint16_t repcnt) {
+ for (uint16_t n = 0; n < repcnt; n++)
+ spiSend16(val);
+ }
+
void spiSendBlock(uint8_t token, const uint8_t *buf) {
spiTransfer(token);
for (uint16_t i = 0; i < 512; i++)
@@ -814,6 +1304,7 @@
}
#endif // !ALLIGATOR
+
#endif // !SOFTWARE_SPI
#endif // ARDUINO_ARCH_SAM
diff --git a/Marlin/src/HAL/DUE/MarlinSPI.h b/Marlin/src/HAL/DUE/MarlinSPI.h
deleted file mode 100644
index 0c447ba4cb3d..000000000000
--- a/Marlin/src/HAL/DUE/MarlinSPI.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * 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 .
- *
- */
-#pragma once
-
-#include
-
-using MarlinSPI = SPIClass;
diff --git a/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_shared_hw_spi.cpp b/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_shared_hw_spi.cpp
index 68f6a5c1a7cb..ab95c0a1ffef 100644
--- a/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_shared_hw_spi.cpp
+++ b/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_shared_hw_spi.cpp
@@ -85,6 +85,7 @@ void u8g_SetPILevel_DUE_hw_spi(u8g_t *u8g, uint8_t pin_index, uint8_t level) {
uint8_t u8g_com_HAL_DUE_shared_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
switch (msg) {
case U8G_COM_MSG_STOP:
+ spiClose();
break;
case U8G_COM_MSG_INIT:
@@ -96,9 +97,7 @@ uint8_t u8g_com_HAL_DUE_shared_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_va
u8g_Delay(5);
- spiBegin();
-
- spiInit(LCD_SPI_SPEED);
+ spiInit(LCD_SPI_SPEED, U8G_PI_SCK, -1, U8G_PI_MOSI, U8G_PI_CS);
break;
case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
diff --git a/Marlin/src/HAL/DUE/inc/Conditionals_LCD.h b/Marlin/src/HAL/DUE/inc/Conditionals_LCD.h
index 58674144470c..8e964debea84 100644
--- a/Marlin/src/HAL/DUE/inc/Conditionals_LCD.h
+++ b/Marlin/src/HAL/DUE/inc/Conditionals_LCD.h
@@ -21,6 +21,6 @@
*/
#pragma once
-#if HAS_SPI_TFT || HAS_FSMC_TFT
- #error "Sorry! TFT displays are not available for HAL/DUE."
+#if HAS_FSMC_TFT
+ #error "Sorry! FSMC displays are not available for HAL/DUE."
#endif
diff --git a/Marlin/src/HAL/DUE/inc/SanityCheck.h b/Marlin/src/HAL/DUE/inc/SanityCheck.h
index 1f5acc360c72..996404a7d04c 100644
--- a/Marlin/src/HAL/DUE/inc/SanityCheck.h
+++ b/Marlin/src/HAL/DUE/inc/SanityCheck.h
@@ -64,7 +64,7 @@
* Usually the hardware SPI pins are only available to the LCD. This makes the DUE hard SPI used at the same time
* as the TMC2130 soft SPI the most common setup.
*/
-#define _IS_HW_SPI(P) (defined(TMC_SW_##P) && (TMC_SW_##P == SD_MOSI_PIN || TMC_SW_##P == SD_MISO_PIN || TMC_SW_##P == SD_SCK_PIN))
+#define _IS_HW_SPI(P) (defined(TMC_SPI_##P) && (TMC_SPI_##P == SD_MOSI_PIN || TMC_SPI_##P == SD_MISO_PIN || TMC_SPI_##P == SD_SCK_PIN))
#if ENABLED(SDSUPPORT) && HAS_DRIVER(TMC2130)
#if ENABLED(TMC_USE_SW_SPI)
diff --git a/Marlin/src/HAL/ESP32/HAL.cpp b/Marlin/src/HAL/ESP32/HAL.cpp
index 46dd4e761b8c..747dab58ed8c 100644
--- a/Marlin/src/HAL/ESP32/HAL.cpp
+++ b/Marlin/src/HAL/ESP32/HAL.cpp
@@ -209,16 +209,17 @@ int MarlinHAL::freeMemory() { return ESP.getFreeHeap(); }
// ADC
// ------------------------
-#define ADC1_CHANNEL(pin) ADC1_GPIO ## pin ## _CHANNEL
-
+//https://docs.espressif.com/projects/esp-idf/en/release-v4.4/esp32/api-reference/peripherals/adc.html
adc1_channel_t get_channel(int pin) {
switch (pin) {
- case 39: return ADC1_CHANNEL(39);
- case 36: return ADC1_CHANNEL(36);
- case 35: return ADC1_CHANNEL(35);
- case 34: return ADC1_CHANNEL(34);
- case 33: return ADC1_CHANNEL(33);
- case 32: return ADC1_CHANNEL(32);
+ case 39: return ADC1_CHANNEL_3;
+ case 36: return ADC1_CHANNEL_0;
+ case 35: return ADC1_CHANNEL_7;
+ case 34: return ADC1_CHANNEL_6;
+ case 33: return ADC1_CHANNEL_5;
+ case 32: return ADC1_CHANNEL_4;
+ case 37: return ADC1_CHANNEL_1;
+ case 38: return ADC1_CHANNEL_2;
}
return ADC1_CHANNEL_MAX;
}
diff --git a/Marlin/src/HAL/ESP32/HAL_SPI.cpp b/Marlin/src/HAL/ESP32/HAL_SPI.cpp
deleted file mode 100644
index 868ab1b6712d..000000000000
--- a/Marlin/src/HAL/ESP32/HAL_SPI.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/**
- * 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
- * Copyright (c) 2017 Victor Perez
- *
- * 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 ARDUINO_ARCH_ESP32
-
-#include "../../inc/MarlinConfig.h"
-
-#include "../shared/HAL_SPI.h"
-
-#include
-#include
-
-// ------------------------
-// Public Variables
-// ------------------------
-
-static SPISettings spiConfig;
-
-// ------------------------
-// Public functions
-// ------------------------
-
-#if ENABLED(SOFTWARE_SPI)
-
- // ------------------------
- // Software SPI
- // ------------------------
- #error "Software SPI not supported for ESP32. Use Hardware SPI."
-
-#else
-
-// ------------------------
-// Hardware SPI
-// ------------------------
-
-void spiBegin() {
- #if ENABLED(SDSUPPORT) && PIN_EXISTS(SD_SS)
- OUT_WRITE(SD_SS_PIN, HIGH);
- #endif
-}
-
-void spiInit(uint8_t spiRate) {
- uint32_t clock;
-
- switch (spiRate) {
- case SPI_FULL_SPEED: clock = 16000000; break;
- case SPI_HALF_SPEED: clock = 8000000; break;
- case SPI_QUARTER_SPEED: clock = 4000000; break;
- case SPI_EIGHTH_SPEED: clock = 2000000; break;
- case SPI_SIXTEENTH_SPEED: clock = 1000000; break;
- case SPI_SPEED_5: clock = 500000; break;
- case SPI_SPEED_6: clock = 250000; break;
- default: clock = 1000000; // Default from the SPI library
- }
-
- spiConfig = SPISettings(clock, MSBFIRST, SPI_MODE0);
- SPI.begin();
-}
-
-uint8_t spiRec() {
- SPI.beginTransaction(spiConfig);
- uint8_t returnByte = SPI.transfer(0xFF);
- SPI.endTransaction();
- return returnByte;
-}
-
-void spiRead(uint8_t *buf, uint16_t nbyte) {
- SPI.beginTransaction(spiConfig);
- SPI.transferBytes(0, buf, nbyte);
- SPI.endTransaction();
-}
-
-void spiSend(uint8_t b) {
- SPI.beginTransaction(spiConfig);
- SPI.transfer(b);
- SPI.endTransaction();
-}
-
-void spiSendBlock(uint8_t token, const uint8_t *buf) {
- SPI.beginTransaction(spiConfig);
- SPI.transfer(token);
- SPI.writeBytes(const_cast(buf), 512);
- SPI.endTransaction();
-}
-
-void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) {
- spiConfig = SPISettings(spiClock, bitOrder, dataMode);
-
- SPI.beginTransaction(spiConfig);
-}
-
-#endif // !SOFTWARE_SPI
-
-#endif // ARDUINO_ARCH_ESP32
diff --git a/Marlin/src/HAL/ESP32/HAL_SPI_HW.cpp b/Marlin/src/HAL/ESP32/HAL_SPI_HW.cpp
new file mode 100644
index 000000000000..7356080d2bb0
--- /dev/null
+++ b/Marlin/src/HAL/ESP32/HAL_SPI_HW.cpp
@@ -0,0 +1,3142 @@
+/**
+ * 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
+ * Copyright (c) 2017 Victor Perez
+ *
+ * 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 .
+ *
+ */
+
+/*
+ HAL SPI implementation by Martin Turski, company owner of EirDev
+ Inclusion date: 24th of November, 2022
+ Contact mail: turningtides@outlook.de
+ ---
+
+ Contact Martin if there is any grave SPI design or functionality issue.
+ Include a link to the Marlin FW GitHub issue post. Otherwise the mail
+ may be ignored. This implementation has been created specifically for the
+ Marlin FW. It was made with performance and simplicity-of-maintenance in
+ mind, while keeping all the SPI requirements in check.
+
+ Original pull request: https://github.com/MarlinFirmware/Marlin/pull/24911
+*/
+
+#ifdef ARDUINO_ARCH_ESP32
+
+#include "../../inc/MarlinConfig.h"
+
+#include "../shared/HAL_SPI.h"
+
+#if DISABLED(SOFTWARE_SPI) && DISABLED(HALSPI_HW_GENERIC)
+
+#include "sdk/BitManage.h"
+
+template
+using esp32BitManager = eir::BitManager ::template spec, eir::typelist >;
+
+// ------------------------
+// Hardware SPI
+// tested using MKS TinyBee V1.0 (ESP32-WROOM-32U / ESP32-D0WD (rev1))
+// ------------------------
+
+/*
+ The ESP32 SPI DMA hardware implementation problem.
+ - written by Martin Turski on the 30th of January, 2023
+
+ Reliability of a platform implementation comes first. Thus I have decided to cut away the optional SPI DMA
+ implementation from the first generation of ESP32 chips. Continue reading so I can elaborate on why.
+
+ Numerous people on the internet have tried to reach the Espressif support about custom SPI DMA implementations
+ but failed.
+ - https://www.esp32.com/viewtopic.php?t=16036 (https://web.archive.org/web/20230130174342/https://www.esp32.com/viewtopic.php?t=16036)
+ - https://esp32.com/viewtopic.php?t=5152 (https://web.archive.org/web/20230130174608/https://esp32.com/viewtopic.php?t=5152)
+ - https://esp32.com/viewtopic.php?t=10075 (https://web.archive.org/web/20230130174757/https://esp32.com/viewtopic.php?t=10075)
+ The esp-idf so called "SPI master driver" does not, by design, support automatic MSBFIRST 16bit SPI frames. I want to highlight
+ the ESP32 hardware "workaround" that points to reliability issues in the silicon.
+ - (https://www.esp32.com/viewtopic.php?t=8433 spi_master.zip:spi_master.c:line 754)
+ Support issues make people give up on the MCU altogether.
+ - https://esp32.com/viewtopic.php?t=14732 (https://web.archive.org/web/20230130185951/https://esp32.com/viewtopic.php?t=14732)
+
+ I would appreciate good help! I want to implement the ESP32 DMA SPI for the ESP32-D0WD, revision 1. The best way
+ would be in the form of a sample project easily compilable & runnable on the MKS TinyBee V1.0. The example project
+ must not use the SPI Master driver from esp-idf. Please contact me in the original pull request if you have found a solution.
+
+ ESP32 SPI DMA machine-state dump at DMASendBlocking call related to the error: https://pastebin.com/LNBzJvRy
+
+ Other SPI issues of ESP32 that seem fatal:
+ - https://www.esp32.com/viewtopic.php?t=31389 (https://web.archive.org/web/20230130184649/https://www.esp32.com/viewtopic.php?t=31389)
+
+ Please note that SPI with interrupts has been 100% tested and works just fine. Hence it is not a big deal to leave-out DMA acceleration.
+*/
+#ifndef HALSPI_DISABLE_DMA
+ #define HALSPI_DISABLE_DMA
+#endif
+
+static void IRAM_ATTR _spi_on_error(const uint32_t code=0) {
+ for (;;) {
+ #if defined(HALSPI_DO_ERRORBEEPS) && PIN_EXISTS(BEEPER)
+ OUT_WRITE(BEEPER_PIN, HIGH); delay(500);
+ OUT_WRITE(BEEPER_PIN, LOW); delay(500);
+ OUT_WRITE(BEEPER_PIN, HIGH); delay(500);
+ OUT_WRITE(BEEPER_PIN, LOW); delay(500);
+ OUT_WRITE(BEEPER_PIN, HIGH); delay(150);
+ OUT_WRITE(BEEPER_PIN, LOW); delay(150);
+ OUT_WRITE(BEEPER_PIN, HIGH); delay(150);
+ OUT_WRITE(BEEPER_PIN, LOW); delay(150);
+ OUT_WRITE(BEEPER_PIN, HIGH); delay(150);
+ OUT_WRITE(BEEPER_PIN, LOW); delay(code ? 800 : 150);
+ for (uint32_t n = 0; n < code; n++) {
+ OUT_WRITE(BEEPER_PIN, HIGH); delay(250);
+ OUT_WRITE(BEEPER_PIN, LOW);
+ if (n < code - 1) delay(250);
+ }
+ delay(3000);
+ #endif
+ }
+}
+
+#ifndef HALSPI_LOOPBEEP_TIMEOUT
+#define HALSPI_LOOPBEEP_TIMEOUT 3000
+#endif
+
+struct spi_monitored_loop {
+private:
+ #if defined(HALSPI_DO_LOOPBEEPS) && PIN_EXISTS(BEEPER)
+ uint32_t _start_millis;
+ #endif
+public:
+ inline spi_monitored_loop() {
+ #if defined(HALSPI_DO_LOOPBEEPS) && PIN_EXISTS(BEEPER)
+ _start_millis = millis();
+ #endif
+ }
+ inline void update(unsigned int beep_code) {
+ #if defined(HALSPI_DO_LOOPBEEPS) && PIN_EXISTS(BEEPER)
+ if ((millis() - _start_millis) <= HALSPI_LOOPBEEP_TIMEOUT) return;
+ OUT_WRITE(BEEPER_PIN, HIGH); delay(500);
+ OUT_WRITE(BEEPER_PIN, LOW); delay(200);
+ OUT_WRITE(BEEPER_PIN, HIGH); delay(200);
+ OUT_WRITE(BEEPER_PIN, LOW); delay(200);
+ OUT_WRITE(BEEPER_PIN, HIGH); delay(200);
+ OUT_WRITE(BEEPER_PIN, LOW); delay(1000);
+ for (unsigned int n = 0; n < beep_code; n++) {
+ OUT_WRITE(BEEPER_PIN, HIGH); delay(200);
+ OUT_WRITE(BEEPER_PIN, LOW); delay(200);
+ }
+ delay(800);
+ OUT_WRITE(BEEPER_PIN, HIGH); delay(1000);
+ OUT_WRITE(BEEPER_PIN, LOW); delay(2000);
+ #endif
+ }
+};
+
+static void __attribute__((unused)) _spi_infobeep(uint32_t code) {
+#if PIN_EXISTS(BEEPER)
+ OUT_WRITE(BEEPER_PIN, HIGH); delay(500);
+ OUT_WRITE(BEEPER_PIN, LOW); delay(500);
+ for (uint32_t n = 0; n < code; n++) {
+ OUT_WRITE(BEEPER_PIN, HIGH); delay(200);
+ OUT_WRITE(BEEPER_PIN, LOW); delay(200);
+ }
+ delay(300);
+ OUT_WRITE(BEEPER_PIN, HIGH); delay(400);
+ OUT_WRITE(BEEPER_PIN, LOW); delay(1000);
+#endif
+}
+
+// ESP32 TRM DATE: 14th of November, 2022
+
+template
+inline numberType _MIN(numberType a, numberType b) {
+ return ( a < b ? a : b );
+}
+
+namespace MarlinESP32 {
+
+#define __ESP32_DEFREG(tn,n,l) static volatile tn& n = *(volatile tn*)l
+
+template
+inline void dwrite(volatile T& v, const T& V) noexcept {
+ if constexpr ( sizeof(T) == sizeof(uint8_t) ) {
+ (volatile uint8_t&)v = (const uint8_t&)V;
+ }
+ else if constexpr ( sizeof(T) == sizeof(uint16_t) ) {
+ (volatile uint16_t&)v = (const uint16_t&)V;
+ }
+ else if constexpr ( sizeof(T) == sizeof(uint32_t) ) {
+ (volatile uint32_t&)v = (const uint32_t&)V;
+ }
+ else {
+ v = V;
+ }
+}
+
+struct spi_cmd_reg_t {
+ uint32_t reserved1 : 18;
+ uint32_t SPI_USR : 1;
+ uint32_t reserved2 : 13;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_CMD_REG.reserved1 = ", reserved1, ";");
+ SERIAL_ECHOLNPGM("SPI_CMD_REG.SPI_USR = ", SPI_USR, ";");
+ SERIAL_ECHOLNPGM("SPI_CMD_REG.reserved2 = ", reserved2, ";");
+ }
+};
+static_assert(sizeof(spi_cmd_reg_t) == 4, "invalid size for ESP32 spi_cmd_reg_t");
+
+#define _ESP32_BIT_ORDER_MSB 0
+#define _ESP32_BIT_ORDER_LSB 1
+
+struct spi_ctrl_reg_t {
+ uint32_t reserved1 : 13;
+ uint32_t SPI_FASTRD_MODE : 1;
+ uint32_t SPI_FREAD_DUAL : 1;
+ uint32_t reserved2 : 5;
+ uint32_t SPI_FREAD_QUAD : 1;
+ uint32_t SPI_WP : 1;
+ uint32_t reserved3 : 1;
+ uint32_t SPI_FREAD_DIO : 1;
+ uint32_t SPI_FREAD_QIO : 1;
+ uint32_t SPI_RD_BIT_ORDER : 1;
+ uint32_t SPI_WR_BIT_ORDER : 1;
+ uint32_t reserved4 : 5;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_CTRL_REG.reserved1 = ", reserved1, ";");
+ SERIAL_ECHOLNPGM("SPI_CTRL_REG.SPI_FASTRD_MODE = ", SPI_FASTRD_MODE, ";");
+ SERIAL_ECHOLNPGM("SPI_CTRL_REG.SPI_FREAD_DUAL = ", SPI_FREAD_DUAL, ";");
+ SERIAL_ECHOLNPGM("SPI_CTRL_REG.reserved2 = ", reserved2, ";");
+ SERIAL_ECHOLNPGM("SPI_CTRL_REG.SPI_FREAD_QUAD = ", SPI_FREAD_QUAD, ";");
+ SERIAL_ECHOLNPGM("SPI_CTRL_REG.SPI_WP = ", SPI_WP, ";");
+ SERIAL_ECHOLNPGM("SPI_CTRL_REG.reserved3 = ", reserved3, ";");
+ SERIAL_ECHOLNPGM("SPI_CTRL_REG.SPI_FREAD_DIO = ", SPI_FREAD_DIO, ";");
+ SERIAL_ECHOLNPGM("SPI_CTRL_REG.SPI_FREAD_QIO = ", SPI_FREAD_QIO, ";");
+ SERIAL_ECHOLNPGM("SPI_CTRL_REG.SPI_RD_BIT_ORDER = ", SPI_RD_BIT_ORDER, ";");
+ SERIAL_ECHOLNPGM("SPI_CTRL_REG.SPI_WR_BIT_ORDER = ", SPI_WR_BIT_ORDER, ";");
+ SERIAL_ECHOLNPGM("SPI_CTRL_REG.reserved4 = ", reserved4, ";");
+ }
+};
+static_assert(sizeof(spi_ctrl_reg_t) == 4, "invalid size for ESP32 spi_ctrl_reg_t");
+
+struct spi_ctrl1_reg_t {
+ uint32_t reserved1 : 28;
+ uint32_t SPI_CS_HOLD_DELAY : 4;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_CTRL1_REG.reserved1 = ", reserved1, ";");
+ SERIAL_ECHOLNPGM("SPI_CTRL1_REG.SPI_CS_HOLD_DELAY = ", SPI_CS_HOLD_DELAY, ";");
+ }
+};
+static_assert(sizeof(spi_ctrl1_reg_t) == 4, "invalid size for ESP32 spi_ctrl1_reg_t");
+
+struct spi_ctrl2_reg_t {
+ uint32_t SPI_SETUP_TIME : 4;
+ uint32_t SPI_HOLD_TIME : 4;
+ uint32_t reserved1 : 4;
+ uint32_t SPI_CK_OUT_HIGH_MODE : 4;
+ uint32_t SPI_MISO_DELAY_MODE : 2;
+ uint32_t SPI_MISO_DELAY_NUM : 3;
+ uint32_t SPI_MOSI_DELAY_MODE : 2;
+ uint32_t SPI_MOSI_DELAY_NUM : 3;
+ uint32_t SPI_CS_DELAY_MODE : 2;
+ uint32_t SPI_CS_DELAY_NUM : 4;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_CTRL2_REG.SPI_SETUP_TIME = ", SPI_SETUP_TIME, ";");
+ SERIAL_ECHOLNPGM("SPI_CTRL2_REG.SPI_HOLD_TIME = ", SPI_HOLD_TIME, ";");
+ SERIAL_ECHOLNPGM("SPI_CTRL2_REG.reserved1 = ", reserved1, ";");
+ SERIAL_ECHOLNPGM("SPI_CTRL2_REG.SPI_CK_OUT_HIGH_MODE = ", SPI_CK_OUT_HIGH_MODE, ";");
+ SERIAL_ECHOLNPGM("SPI_CTRL2_REG.SPI_MISO_DELAY_MODE = ", SPI_MISO_DELAY_MODE, ";");
+ SERIAL_ECHOLNPGM("SPI_CTRL2_REG.SPI_MISO_DELAY_NUM = ", SPI_MISO_DELAY_NUM, ";");
+ SERIAL_ECHOLNPGM("SPI_CTRL2_REG.SPI_MOSI_DELAY_MODE = ", SPI_MOSI_DELAY_MODE, ";");
+ SERIAL_ECHOLNPGM("SPI_CTRL2_REG.SPI_MOSI_DELAY_NUM = ", SPI_MOSI_DELAY_NUM, ";");
+ SERIAL_ECHOLNPGM("SPI_CTRL2_REG.SPI_CS_DELAY_MODE = ", SPI_CS_DELAY_MODE, ";");
+ SERIAL_ECHOLNPGM("SPI_CTRL2_REG.SPI_CS_DELAY_NUM = ", SPI_CS_DELAY_NUM, ";");
+ }
+};
+static_assert(sizeof(spi_ctrl2_reg_t) == 4, "invalid size for ESP32 spi_ctrl2_reg_t");
+
+struct spi_clock_reg_t {
+ uint32_t SPI_CLKCNT_L : 6;
+ uint32_t SPI_CLKCNT_H : 6;
+ uint32_t SPI_CLKCNT_N : 6;
+ uint32_t SPI_CLKDIV_PRE : 13;
+ uint32_t SPI_CLK_EQU_SYSCLK : 1;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_CLOCK_REG.SPI_CLKCNT_L = ", SPI_CLKCNT_L, ";");
+ SERIAL_ECHOLNPGM("SPI_CLOCK_REG.SPI_CLKCNT_H = ", SPI_CLKCNT_H, ";");
+ SERIAL_ECHOLNPGM("SPI_CLOCK_REG.SPI_CLKCNT_N = ", SPI_CLKCNT_N, ";");
+ SERIAL_ECHOLNPGM("SPI_CLOCK_REG.SPI_CLKDIV_PRE = ", SPI_CLKDIV_PRE, ";");
+ SERIAL_ECHOLNPGM("SPI_CLOCK_REG.SPI_CLK_EQU_SYSCLK = ", SPI_CLK_EQU_SYSCLK, ";");
+ }
+};
+static_assert(sizeof(spi_clock_reg_t) == 4, "invalid size for ESP32 spi_clock_reg_t");
+
+struct spi_user_reg_t {
+ uint32_t SPI_DOUTDIN : 1;
+ uint32_t reserved1 : 3;
+ uint32_t SPI_CS_HOLD : 1;
+ uint32_t SPI_CS_SETUP : 1;
+ uint32_t SPI_CK_I_EDGE : 1;
+ uint32_t SPI_CK_OUT_EDGE : 1;
+ uint32_t reserved2 : 2;
+ uint32_t SPI_RD_BYTE_ORDER : 1;
+ uint32_t SPI_WR_BYTE_ORDER : 1;
+ uint32_t SPI_FWRITE_DUAL : 1;
+ uint32_t SPI_FWRITE_QUAD : 1;
+ uint32_t SPI_FWRITE_DIO : 1;
+ uint32_t SPI_FWRITE_QIO : 1;
+ uint32_t SPI_SIO : 1;
+ uint32_t reserved3 : 7;
+ uint32_t SPI_USR_MISO_HIGHPART : 1;
+ uint32_t SPI_USR_MOSI_HIGHPART : 1;
+ uint32_t SPI_USR_DUMMY_IDLE : 1;
+ uint32_t SPI_USR_MOSI : 1;
+ uint32_t SPI_USR_MISO : 1;
+ uint32_t SPI_USR_DUMMY : 1;
+ uint32_t SPI_USR_ADDR : 1;
+ uint32_t SPI_USR_COMMAND : 1;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_USER_REG.SPI_DOUTDIN = ", SPI_DOUTDIN, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.reserved1 = ", reserved1, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.SPI_CS_HOLD = ", SPI_CS_HOLD, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.SPI_CS_SETUP = ", SPI_CS_SETUP, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.SPI_CK_I_EDGE = ", SPI_CK_I_EDGE, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.SPI_CK_OUT_EDGE = ", SPI_CK_OUT_EDGE, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.reserved2 = ", reserved2, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.SPI_RD_BYTE_ORDER = ", SPI_RD_BYTE_ORDER, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.SPI_WR_BYTE_ORDER = ", SPI_WR_BYTE_ORDER, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.SPI_FWRITE_DUAL = ", SPI_FWRITE_DUAL, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.SPI_FWRITE_QUAD = ", SPI_FWRITE_QUAD, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.SPI_FWRITE_DIO = ", SPI_FWRITE_DIO, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.SPI_FWRITE_QIO = ", SPI_FWRITE_QIO, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.SPI_SIO = ", SPI_SIO, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.reserved3 = ", reserved3, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.SPI_USR_MISO_HIGHPART = ", SPI_USR_MISO_HIGHPART, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.SPI_USR_MOSI_HIGHPART = ", SPI_USR_MOSI_HIGHPART, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.SPI_USR_DUMMY_IDLE = ", SPI_USR_DUMMY_IDLE, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.SPI_USR_MOSI = ", SPI_USR_MOSI, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.SPI_USR_MISO = ", SPI_USR_MISO, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.SPI_USR_DUMMY = ", SPI_USR_DUMMY, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.SPI_USR_ADDR = ", SPI_USR_ADDR, ";");
+ SERIAL_ECHOLNPGM("SPI_USER_REG.SPI_USR_COMMAND = ", SPI_USR_COMMAND, ";");
+ }
+};
+static_assert(sizeof(spi_user_reg_t) == 4, "invalid size for ESP32 spi_user_reg_t");
+
+struct spi_user1_reg_t {
+ uint32_t SPI_USR_DUMMY_CYCLELEN : 8;
+ uint32_t reserved1 : 18;
+ uint32_t SPI_USR_ADDR_BITLEN : 6;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_USER1_REG.SPI_USR_DUMMY_CYCLELEN = ", SPI_USR_DUMMY_CYCLELEN, ";");
+ SERIAL_ECHOLNPGM("SPI_USER1_REG.reserved1 = ", reserved1, ";");
+ SERIAL_ECHOLNPGM("SPI_USER1_REG.SPI_USR_ADDR_BITLEN = ", SPI_USR_ADDR_BITLEN, ";");
+ }
+};
+static_assert(sizeof(spi_user1_reg_t) == 4, "invalid size for ESP32 spi_user1_reg_t");
+
+struct spi_user2_reg_t {
+ uint32_t SPI_USR_COMMAND_VALUE : 16;
+ uint32_t reserved1 : 12;
+ uint32_t SPI_USR_COMMAND_BITLEN : 4;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_USER2_REG.SPI_USR_COMMAND_VALUE = ", SPI_USR_COMMAND_VALUE, ";");
+ SERIAL_ECHOLNPGM("SPI_USER2_REG.reserved1 = ", reserved1, ";");
+ SERIAL_ECHOLNPGM("SPI_USER2_REG.SPI_USR_COMMAND_BITLEN = ", SPI_USR_COMMAND_BITLEN, ";");
+ }
+};
+static_assert(sizeof(spi_user2_reg_t) == 4, "invalid size for ESP32 spi_user2_reg_t");
+
+struct spi_mosi_dlen_reg_t {
+ uint32_t SPI_USR_MOSI_DBITLEN : 24;
+ uint32_t reserved1 : 8;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_MOSI_DLEN_REG.SPI_USR_MOSI_DBITLEN = ", SPI_USR_MOSI_DBITLEN, ";");
+ SERIAL_ECHOLNPGM("SPI_MOSI_DLEN_REG.reserved1 = ", reserved1, ";");
+ }
+};
+static_assert(sizeof(spi_mosi_dlen_reg_t) == 4, "invalid size for ESP32 spi_mosi_dlen_reg_t");
+
+struct spi_miso_dlen_reg_t {
+ uint32_t SPI_USR_MISO_DBITLEN : 24;
+ uint32_t reserved1 : 8;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_MISO_DLEN_REG.SPI_USR_MISO_DBITLEN = ", SPI_USR_MISO_DBITLEN, ";");
+ SERIAL_ECHOLNPGM("SPI_MISO_DLEN_REG.reserved1 = ", reserved1, ";");
+ }
+};
+static_assert(sizeof(spi_miso_dlen_reg_t) == 4, "invalid size for ESP32 spi_miso_dlen_reg_t");
+
+struct spi_pin_reg_t {
+ uint32_t SPI_CS0_DIS : 1;
+ uint32_t SPI_CS1_DIS : 1;
+ uint32_t SPI_CS2_DIS : 1;
+ uint32_t reserved1 : 2;
+ uint32_t SPI_CK_DIS : 1;
+ uint32_t SPI_MASTER_CS_POL : 3;
+ uint32_t reserved2 : 2;
+ uint32_t SPI_MASTER_CK_SEL : 3;
+ uint32_t reserved3 : 15;
+ uint32_t SPI_CK_IDLE_EDGE : 1;
+ uint32_t SPI_CS_KEEP_ACTIVE : 1;
+ uint32_t reserved4 : 1;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_PIN_REG.SPI_CS0_DIS = ", SPI_CS0_DIS, ";");
+ SERIAL_ECHOLNPGM("SPI_PIN_REG.SPI_CS1_DIS = ", SPI_CS1_DIS, ";");
+ SERIAL_ECHOLNPGM("SPI_PIN_REG.SPI_CS2_DIS = ", SPI_CS2_DIS, ";");
+ SERIAL_ECHOLNPGM("SPI_PIN_REG.reserved1 = ", reserved1, ";");
+ SERIAL_ECHOLNPGM("SPI_PIN_REG.SPI_CK_DIS = ", SPI_CK_DIS, ";");
+ SERIAL_ECHOLNPGM("SPI_PIN_REG.SPI_MASTER_CS_POL = ", SPI_MASTER_CS_POL, ";");
+ SERIAL_ECHOLNPGM("SPI_PIN_REG.reserved2 = ", reserved2, ";");
+ SERIAL_ECHOLNPGM("SPI_PIN_REG.SPI_MASTER_CK_SEL = ", SPI_MASTER_CK_SEL, ";");
+ SERIAL_ECHOLNPGM("SPI_PIN_REG.reserved3 = ", reserved3, ";");
+ SERIAL_ECHOLNPGM("SPI_PIN_REG.SPI_CK_IDLE_EDGE = ", SPI_CK_IDLE_EDGE, ";");
+ SERIAL_ECHOLNPGM("SPI_PIN_REG.SPI_CS_KEEP_ACTIVE = ", SPI_CS_KEEP_ACTIVE, ";");
+ SERIAL_ECHOLNPGM("SPI_PIN_REG.reserved4 = ", reserved4, ";");
+ }
+};
+static_assert(sizeof(spi_pin_reg_t) == 4, "invalid size for ESP32 spi_pin_reg_t");
+
+struct spi_slave_reg_t {
+ uint32_t SPI_SLV_RD_BUF_DONE : 1;
+ uint32_t SPI_SLV_WR_BUF_DONE : 1;
+ uint32_t SPI_SLV_RD_STA_DONE : 1;
+ uint32_t SPI_SLV_WR_STA_DONE : 1;
+ uint32_t SPI_TRANS_DONE : 1;
+ uint32_t SPI_SLV_RD_BUF_INTEN : 1;
+ uint32_t SPI_SLV_WR_BUF_INTEN : 1;
+ uint32_t SPI_SLV_RD_STA_INTEN : 1;
+ uint32_t SPI_SLV_WR_STA_INTEN : 1;
+ uint32_t SPI_TRANS_INTEN : 1;
+ uint32_t SPI_CS_I_MODE : 2;
+ uint32_t reserved1 : 5;
+ uint32_t SPI_SLV_LAST_COMMAND : 3;
+ uint32_t SPI_SLV_LAST_STATE : 3; // read-only
+ uint32_t SPI_TRANS_CNT : 4; // read-only
+ uint32_t SPI_SLV_CMD_DEFINE : 1;
+ uint32_t SPI_SLV_WR_RD_STA_EN : 1;
+ uint32_t SPI_SLV_WR_RD_BUF_EN : 1;
+ uint32_t SPI_SLAVE_MODE : 1;
+ uint32_t SPI_SYNC_RESET : 1;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_SLAVE_REG.SPI_SLV_RD_BUF_DONE = ", SPI_SLV_RD_BUF_DONE, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE_REG.SPI_SLV_WR_BUF_DONE = ", SPI_SLV_WR_BUF_DONE, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE_REG.SPI_SLV_RD_STA_DONE = ", SPI_SLV_RD_STA_DONE, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE_REG.SPI_SLV_WR_STA_DONE = ", SPI_SLV_WR_STA_DONE, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE_REG.SPI_TRANS_DONE = ", SPI_TRANS_DONE, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE_REG.SPI_SLV_RD_BUF_INTEN = ", SPI_SLV_RD_BUF_INTEN, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE_REG.SPI_SLV_WR_BUF_INTEN = ", SPI_SLV_WR_BUF_INTEN, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE_REG.SPI_SLV_RD_STA_INTEN = ", SPI_SLV_RD_STA_INTEN, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE_REG.SPI_SLV_WR_STA_INTEN = ", SPI_SLV_WR_STA_INTEN, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE_REG.SPI_TRANS_INTEN = ", SPI_TRANS_INTEN, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE_REG.SPI_CS_I_MODE = ", SPI_CS_I_MODE, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE_REG.reserved1 = ", reserved1, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE_REG.SPI_SLV_LAST_COMMAND = ", SPI_SLV_LAST_COMMAND, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE_REG.SPI_SLV_LAST_STATE = ", SPI_SLV_LAST_STATE, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE_REG.SPI_TRANS_CNT = ", SPI_TRANS_CNT, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE_REG.SPI_SLV_CMD_DEFINE = ", SPI_SLV_CMD_DEFINE, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE_REG.SPI_SLV_WR_RD_STA_EN = ", SPI_SLV_WR_RD_STA_EN, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE_REG.SPI_SLV_WR_RD_BUF_EN = ", SPI_SLV_WR_RD_BUF_EN, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE_REG.SPI_SLAVE_MODE = ", SPI_SLAVE_MODE, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE_REG.SPI_SYNC_RESET = ", SPI_SYNC_RESET, ";");
+ }
+};
+static_assert(sizeof(spi_slave_reg_t) == 4, "invalid size for ESP32 spi_slave_reg_t");
+
+struct spi_slave1_reg_t {
+ uint32_t SPI_SLV_RDBUF_DUMMY_EN : 1;
+ uint32_t SPI_SLV_WRBUF_DUMMY_EN : 1;
+ uint32_t SPI_SLV_RDSTA_DUMMY_EN : 1;
+ uint32_t SPI_SLV_WRSTA_DUMMY_EN : 1;
+ uint32_t SPI_SLV_WR_ADDR_BITLEN : 6;
+ uint32_t SPI_SLV_RD_ADDR_BITLEN : 6;
+ uint32_t reserved1 : 9;
+ uint32_t SPI_SLV_STATUS_READBACK : 1;
+ uint32_t SPI_SLV_STATUS_FAST_EN : 1;
+ uint32_t SPI_SLV_STATUS_BITLEN : 5;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_SLAVE1_REG.SPI_SLV_RDBUF_DUMMY_EN = ", SPI_SLV_RDBUF_DUMMY_EN, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE1_REG.SPI_SLV_WRBUF_DUMMY_EN = ", SPI_SLV_WRBUF_DUMMY_EN, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE1_REG.SPI_SLV_RDSTA_DUMMY_EN = ", SPI_SLV_RDSTA_DUMMY_EN, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE1_REG.SPI_SLV_WRSTA_DUMMY_EN = ", SPI_SLV_WRSTA_DUMMY_EN, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE1_REG.SPI_SLV_WR_ADDR_BITLEN = ", SPI_SLV_WR_ADDR_BITLEN, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE1_REG.SPI_SLV_RD_ADDR_BITLEN = ", SPI_SLV_RD_ADDR_BITLEN, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE1_REG.reserved1 = ", reserved1, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE1_REG.SPI_SLV_STATUS_READBACK = ", SPI_SLV_STATUS_READBACK, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE1_REG.SPI_SLV_STATUS_FAST_EN = ", SPI_SLV_STATUS_FAST_EN, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE1_REG.SPI_SLV_STATUS_BITLEN = ", SPI_SLV_STATUS_BITLEN, ";");
+ }
+};
+static_assert(sizeof(spi_slave1_reg_t) == 4, "invalid size for ESP32 spi_slave1_reg_t");
+
+struct spi_slave2_reg_t {
+ uint32_t SPI_SLV_RDSTA_DUMMY_CYCLELEN : 8;
+ uint32_t SPI_SLV_WRSTA_DUMMY_CYCLELEN : 8;
+ uint32_t SPI_SLV_RDBUF_DUMMY_CYCLELEN : 8;
+ uint32_t SPI_SLV_WRBUF_DUMMY_CYCLELEN : 8;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_SLAVE2_REG.SPI_SLV_RDSTA_DUMMY_CYCLELEN = ", SPI_SLV_RDSTA_DUMMY_CYCLELEN, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE2_REG.SPI_SLV_WRSTA_DUMMY_CYCLELEN = ", SPI_SLV_WRSTA_DUMMY_CYCLELEN, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE2_REG.SPI_SLV_RDBUF_DUMMY_CYCLELEN = ", SPI_SLV_RDBUF_DUMMY_CYCLELEN, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE2_REG.SPI_SLV_WRBUF_DUMMY_CYCLELEN = ", SPI_SLV_WRBUF_DUMMY_CYCLELEN, ";");
+ }
+};
+static_assert(sizeof(spi_slave2_reg_t) == 4, "invalid size for ESP32 spi_slave2_reg_t");
+
+struct spi_slave3_reg_t {
+ uint32_t SPI_SLV_RDBUF_CMD_VALUE : 8;
+ uint32_t SPI_SLV_WRBUF_CMD_VALUE : 8;
+ uint32_t SPI_SLV_RDSTA_CMD_VALUE : 8;
+ uint32_t SPI_SLV_WRSTA_CMD_VALUE : 8;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_SLAVE3_REG.SPI_SLV_RDBUF_CMD_VALUE = ", SPI_SLV_RDBUF_CMD_VALUE, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE3_REG.SPI_SLV_WRBUF_CMD_VALUE = ", SPI_SLV_WRBUF_CMD_VALUE, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE3_REG.SPI_SLV_RDSTA_CMD_VALUE = ", SPI_SLV_RDSTA_CMD_VALUE, ";");
+ SERIAL_ECHOLNPGM("SPI_SLAVE3_REG.SPI_SLV_WRSTA_CMD_VALUE = ", SPI_SLV_WRSTA_CMD_VALUE, ";");
+ }
+};
+static_assert(sizeof(spi_slave3_reg_t) == 4, "invalid size for ESP32 spi_slave3_reg_t");
+
+struct spi_slv_wrbuf_dlen_reg_t {
+ uint32_t SPI_SLV_WRBUF_DBITLEN : 24;
+ uint32_t reserved1 : 8;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_SLV_WRBUF_DLEN_REG.SPI_SLV_WRBUF_DBITLEN = ", SPI_SLV_WRBUF_DBITLEN, ";");
+ SERIAL_ECHOLNPGM("SPI_SLV_WRBUF_DLEN_REG.reserved1 = ", reserved1, ";");
+ }
+};
+static_assert(sizeof(spi_slv_wrbuf_dlen_reg_t) == 4, "invalid size for ESP32 spi_slv_wrbuf_dlen_reg_t");
+
+struct spi_slv_rdbuf_dlen_reg_t {
+ uint32_t SPI_SLV_RDBUF_DBITLEN : 24;
+ uint32_t reserved1 : 8;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_SLV_RDBUF_DLEN_REG.SPI_SLV_RDBUF_DBITLEN = ", SPI_SLV_RDBUF_DBITLEN, ";");
+ SERIAL_ECHOLNPGM("SPI_SLV_RDBUF_DLEN_REG.reserved1 = ", reserved1, ";");
+ }
+};
+static_assert(sizeof(spi_slv_rdbuf_dlen_reg_t) == 4, "invalid size for ESP32 spi_slv_rdbuf_dlen_reg_t");
+
+struct spi_slv_rd_bit_reg_t {
+ uint32_t SPI_SLV_RDATA_BIT : 24;
+ uint32_t reserved1 : 8;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_SLV_RD_BIT_REG.SPI_SLV_RDATA_BIT = ", SPI_SLV_RDATA_BIT, ";");
+ SERIAL_ECHOLNPGM("SPI_SLV_RD_BIT_REG.reserved1 = ", reserved1, ";");
+ }
+};
+static_assert(sizeof(spi_slv_rd_bit_reg_t) == 4, "invalid size for ESP32 spi_slv_rd_bit_reg_t");
+
+struct spi_ext2_reg_t {
+ uint32_t SPI_ST : 3; // read-only
+ uint32_t reserved1 : 29;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_EXT2_REG.SPI_ST = ", SPI_ST, ";");
+ SERIAL_ECHOLNPGM("SPI_EXT2_REG.reserved1 = ", reserved1, ";");
+ }
+};
+static_assert(sizeof(spi_ext2_reg_t) == 4, "invalid size for ESP32 spi_ext2_reg_t");
+
+struct spi_dma_conf_reg_t {
+ uint32_t reserved1 : 2;
+ uint32_t SPI_IN_RST : 1;
+ uint32_t SPI_OUT_RST : 1;
+ uint32_t SPI_AHBM_FIFO_RST : 1;
+ uint32_t SPI_AHBM_RST : 1;
+ uint32_t reserved2 : 3;
+ uint32_t SPI_OUT_EOF_MODE : 1;
+ uint32_t SPI_OUTDSCR_BURST_EN : 1;
+ uint32_t SPI_INDSCR_BURST_EN : 1;
+ uint32_t SPI_OUT_DATA_BURST_EN : 1;
+ uint32_t reserved3 : 1;
+ uint32_t SPI_DMA_RX_STOP : 1;
+ uint32_t SPI_DMA_TX_STOP : 1;
+ uint32_t SPI_DMA_CONTINUE : 1;
+ uint32_t reserved4 : 15;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_DMA_CONF_REG.reserved1 = ", reserved1, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_CONF_REG.SPI_IN_RST = ", SPI_IN_RST, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_CONF_REG.SPI_OUT_RST = ", SPI_OUT_RST, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_CONF_REG.SPI_AHBM_FIFO_RST = ", SPI_AHBM_FIFO_RST, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_CONF_REG.SPI_AHBM_RST = ", SPI_AHBM_RST, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_CONF_REG.reserved2 = ", reserved2, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_CONF_REG.SPI_OUT_EOF_MODE = ", SPI_OUT_EOF_MODE, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_CONF_REG.SPI_OUTDSCR_BURST_EN = ", SPI_OUTDSCR_BURST_EN, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_CONF_REG.SPI_INDSCR_BURST_EN = ", SPI_INDSCR_BURST_EN, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_CONF_REG.SPI_OUT_DATA_BURST_EN = ", SPI_OUT_DATA_BURST_EN, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_CONF_REG.reserved3 = ", reserved3, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_CONF_REG.SPI_DMA_RX_STOP = ", SPI_DMA_RX_STOP, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_CONF_REG.SPI_DMA_TX_STOP = ", SPI_DMA_TX_STOP, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_CONF_REG.SPI_DMA_CONTINUE = ", SPI_DMA_CONTINUE, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_CONF_REG.reserved4 = ", reserved4, ";");
+ }
+};
+static_assert(sizeof(spi_dma_conf_reg_t) == 4, "invalid size for ESP32 spi_dma_conf_reg_t");
+
+struct spi_dma_out_link_reg_t {
+ uint32_t SPI_OUTLINK_ADDR : 20; // ESP32 base address: 0x3FF00000
+ uint32_t reserved1 : 8;
+ uint32_t SPI_OUTLINK_STOP : 1;
+ uint32_t SPI_OUTLINK_START : 1;
+ uint32_t SPI_OUTLINK_RESTART : 1;
+ uint32_t reserved2 : 1;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_DMA_OUT_LINK_REG.SPI_OUTLINK_ADDR = ", SPI_OUTLINK_ADDR, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_OUT_LINK_REG.reserved1 = ", reserved1, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_OUT_LINK_REG.SPI_OUTLINK_STOP = ", SPI_OUTLINK_STOP, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_OUT_LINK_REG.SPI_OUTLINK_START = ", SPI_OUTLINK_START, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_OUT_LINK_REG.SPI_OUTLINK_RESTART = ", SPI_OUTLINK_RESTART, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_OUT_LINK_REG.reserved2 = ", reserved2, ";");
+ }
+};
+static_assert(sizeof(spi_dma_out_link_reg_t) == 4, "invalid size for ESP32 spi_dma_out_link_reg_t");
+
+struct spi_dma_in_link_reg_t {
+ uint32_t SPI_INLINK_ADDR : 20; // ESP32 base address: 0x3FF00000
+ uint32_t SPI_INLINK_AUTO_RET : 1;
+ uint32_t reserved1 : 7;
+ uint32_t SPI_INLINK_STOP : 1;
+ uint32_t SPI_INLINK_START : 1;
+ uint32_t SPI_INLINK_RESTART : 1;
+ uint32_t reserved2 : 1;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_DMA_IN_LINK_REG.SPI_INLINK_ADDR = ", SPI_INLINK_ADDR, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_IN_LINK_REG.SPI_INLINK_AUTO_RET = ", SPI_INLINK_AUTO_RET, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_IN_LINK_REG.reserved1 = ", reserved1, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_IN_LINK_REG.SPI_INLINK_STOP = ", SPI_INLINK_STOP, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_IN_LINK_REG.SPI_INLINK_START = ", SPI_INLINK_START, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_IN_LINK_REG.SPI_INLINK_RESTART = ", SPI_INLINK_RESTART, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_IN_LINK_REG.reserved2 = ", reserved2, ";");
+ }
+};
+static_assert(sizeof(spi_dma_in_link_reg_t) == 4, "invalid size for ESP32 spi_dma_in_link_reg_t");
+
+struct spi_dma_status_reg_t {
+ uint32_t SPI_DMA_TX_EN : 1; // read-only
+ uint32_t SPI_DMA_RX_EN : 1; // read-only
+ uint32_t reserved1 : 30;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_DMA_STATUS_REG.SPI_DMA_TX_EN = ", SPI_DMA_TX_EN, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_STATUS_REG.SPI_DMA_RX_EN = ", SPI_DMA_RX_EN, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_STATUS_REG.reserved1 = ", reserved1, ";");
+ }
+};
+static_assert(sizeof(spi_dma_status_reg_t) == 4, "invalid size for ESP32 spi_dma_status_reg_t");
+
+struct spi_dma_int_ena_reg_t {
+ uint32_t SPI_INLINK_DSCR_EMPTY_INT_ENA : 1;
+ uint32_t SPI_OUTLINK_DSCR_ERROR_INT_ENA : 1;
+ uint32_t SPI_INLINK_DSCR_ERROR_INT_ENA : 1;
+ uint32_t SPI_IN_DONE_INT_ENA : 1;
+ uint32_t SPI_IN_ERR_EOF_INT_ENA : 1;
+ uint32_t SPI_IN_SUC_EOF_INT_ENA : 1;
+ uint32_t SPI_OUT_DONE_INT_ENA : 1;
+ uint32_t SPI_OUT_EOF_INT_ENA : 1;
+ uint32_t SPI_OUT_TOTAL_EOF_INT_ENA : 1;
+ uint32_t reserved1 : 23;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_ENA_REG.SPI_INLINK_DSCR_EMPTY_INT_ENA = ", SPI_INLINK_DSCR_EMPTY_INT_ENA, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_ENA_REG.SPI_OUTLINK_DSCR_ERROR_INT_ENA = ", SPI_OUTLINK_DSCR_ERROR_INT_ENA, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_ENA_REG.SPI_INLINK_DSCR_ERROR_INT_ENA = ", SPI_INLINK_DSCR_ERROR_INT_ENA, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_ENA_REG.SPI_IN_DONE_INT_ENA = ", SPI_IN_DONE_INT_ENA, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_ENA_REG.SPI_IN_ERR_EOF_INT_ENA = ", SPI_IN_ERR_EOF_INT_ENA, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_ENA_REG.SPI_IN_SUC_EOF_INT_ENA = ", SPI_IN_SUC_EOF_INT_ENA, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_ENA_REG.SPI_OUT_DONE_INT_ENA = ", SPI_OUT_DONE_INT_ENA, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_ENA_REG.SPI_OUT_EOF_INT_ENA = ", SPI_OUT_EOF_INT_ENA, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_ENA_REG.SPI_OUT_TOTAL_EOF_INT_ENA = ", SPI_OUT_TOTAL_EOF_INT_ENA, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_ENA_REG.reserved1 = ", reserved1, ";");
+ }
+};
+static_assert(sizeof(spi_dma_int_ena_reg_t) == 4, "invalid size for ESP32 spi_dma_int_ena_reg_t");
+
+struct spi_dma_int_raw_reg_t {
+ uint32_t SPI_INLINK_DSCR_EMPTY_INT_RAW : 1; // read-only
+ uint32_t SPI_OUTLINK_DSCR_ERROR_INT_RAW : 1; // read-only
+ uint32_t SPI_INLINK_DSCR_ERROR_INT_RAW : 1; // read-only
+ uint32_t SPI_IN_DONE_INT_RAW : 1; // read-only
+ uint32_t SPI_IN_ERR_EOF_INT_RAW : 1; // read-only
+ uint32_t SPI_IN_SUC_EOF_INT_RAW : 1; // read-only
+ uint32_t SPI_OUT_DONE_INT_RAW : 1; // read-only
+ uint32_t SPI_OUT_EOF_INT_RAW : 1; // read-only
+ uint32_t SPI_OUT_TOTAL_EOF_INT_RAW : 1; // read-only
+ uint32_t reserved1 : 23;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_RAW_REG.SPI_INLINK_DSCR_EMPTY_INT_RAW = ", SPI_INLINK_DSCR_EMPTY_INT_RAW, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_RAW_REG.SPI_OUTLINK_DSCR_ERROR_INT_RAW = ", SPI_OUTLINK_DSCR_ERROR_INT_RAW, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_RAW_REG.SPI_INLINK_DSCR_ERROR_INT_RAW = ", SPI_INLINK_DSCR_ERROR_INT_RAW, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_RAW_REG.SPI_IN_DONE_INT_RAW = ", SPI_IN_DONE_INT_RAW, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_RAW_REG.SPI_IN_ERR_EOF_INT_RAW = ", SPI_IN_ERR_EOF_INT_RAW, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_RAW_REG.SPI_IN_SUC_EOF_INT_RAW = ", SPI_IN_SUC_EOF_INT_RAW, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_RAW_REG.SPI_OUT_DONE_INT_RAW = ", SPI_OUT_DONE_INT_RAW, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_RAW_REG.SPI_OUT_EOF_INT_RAW = ", SPI_OUT_EOF_INT_RAW, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_RAW_REG.SPI_OUT_TOTAL_EOF_INT_RAW = ", SPI_OUT_TOTAL_EOF_INT_RAW, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_RAW_REG.reserved1 = ", reserved1, ";");
+ }
+};
+static_assert(sizeof(spi_dma_int_raw_reg_t) == 4, "invalid size for ESP32 spi_dma_int_raw_reg_t");
+
+struct spi_dma_int_st_reg_t {
+ uint32_t SPI_INLINK_DSCR_EMPTY_INT_ST : 1; // read-only
+ uint32_t SPI_OUTLINK_DSCR_ERROR_INT_ST : 1; // read-only
+ uint32_t SPI_INLINK_DSCR_ERROR_INT_ST : 1; // read-only
+ uint32_t SPI_IN_DONE_INT_ST : 1; // read-only
+ uint32_t SPI_IN_ERR_EOF_INT_ST : 1; // read-only
+ uint32_t SPI_IN_SUC_EOF_INT_ST : 1; // read-only
+ uint32_t SPI_OUT_DONE_INT_ST : 1; // read-only
+ uint32_t SPI_OUT_EOF_INT_ST : 1; // read-only
+ uint32_t SPI_OUT_TOTAL_EOF_INT_ST : 1; // read-only
+ uint32_t reserved1 : 23;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_ST_REG.SPI_INLINK_DSCR_EMPTY_INT_ST = ", SPI_INLINK_DSCR_EMPTY_INT_ST, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_ST_REG.SPI_OUTLINK_DSCR_ERROR_INT_ST = ", SPI_OUTLINK_DSCR_ERROR_INT_ST, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_ST_REG.SPI_INLINK_DSCR_ERROR_INT_ST = ", SPI_INLINK_DSCR_ERROR_INT_ST, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_ST_REG.SPI_IN_DONE_INT_ST = ", SPI_IN_DONE_INT_ST, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_ST_REG.SPI_IN_ERR_EOF_INT_ST = ", SPI_IN_ERR_EOF_INT_ST, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_ST_REG.SPI_IN_SUC_EOF_INT_ST = ", SPI_IN_SUC_EOF_INT_ST, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_ST_REG.SPI_OUT_DONE_INT_ST = ", SPI_OUT_DONE_INT_ST, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_ST_REG.SPI_OUT_EOF_INT_ST = ", SPI_OUT_EOF_INT_ST, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_ST_REG.SPI_OUT_TOTAL_EOF_INT_ST = ", SPI_OUT_TOTAL_EOF_INT_ST, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_ST_REG.reserved1 = ", reserved1, ";");
+ }
+};
+static_assert(sizeof(spi_dma_int_st_reg_t) == 4, "invalid size for ESP32 spi_dma_int_st_reg_t");
+
+struct spi_dma_int_clr_reg_t {
+ uint32_t SPI_INLINK_DSCR_EMPTY_INT_CLR : 1;
+ uint32_t SPI_OUTLINK_DSCR_ERROR_INT_CLR : 1;
+ uint32_t SPI_INLINK_DSCR_ERROR_INT_CLR : 1;
+ uint32_t SPI_IN_DONE_INT_CLR : 1;
+ uint32_t SPI_IN_ERR_EOF_INT_CLR : 1;
+ uint32_t SPI_IN_SUC_EOF_INT_CLR : 1;
+ uint32_t SPI_OUT_DONE_INT_CLR : 1;
+ uint32_t SPI_OUT_EOF_INT_CLR : 1;
+ uint32_t SPI_OUT_TOTAL_EOF_INT_CLR : 1;
+ uint32_t reserved1 : 23;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_CLR_REG.SPI_INLINK_DSCR_EMPTY_INT_CLR = ", SPI_INLINK_DSCR_EMPTY_INT_CLR, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_CLR_REG.SPI_OUTLINK_DSCR_ERROR_INT_CLR = ", SPI_OUTLINK_DSCR_ERROR_INT_CLR, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_CLR_REG.SPI_INLINK_DSCR_ERROR_INT_CLR = ", SPI_INLINK_DSCR_ERROR_INT_CLR, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_CLR_REG.SPI_IN_DONE_INT_CLR = ", SPI_IN_DONE_INT_CLR, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_CLR_REG.SPI_IN_ERR_EOF_INT_CLR = ", SPI_IN_ERR_EOF_INT_CLR, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_CLR_REG.SPI_IN_SUC_EOF_INT_CLR = ", SPI_IN_SUC_EOF_INT_CLR, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_CLR_REG.SPI_OUT_DONE_INT_CLR = ", SPI_OUT_DONE_INT_CLR, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_CLR_REG.SPI_OUT_EOF_INT_CLR = ", SPI_OUT_EOF_INT_CLR, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_CLR_REG.SPI_OUT_TOTAL_EOF_INT_CLR = ", SPI_OUT_TOTAL_EOF_INT_CLR, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_INT_CLR_REG.reserved1 = ", reserved1, ";");
+ }
+};
+static_assert(sizeof(spi_dma_int_clr_reg_t) == 4, "invalid size for ESP32 spi_dma_int_clr_reg_t");
+
+struct spi_dma_rstatus_reg_t {
+ uint32_t TX_DES_ADDRESS : 20; // read-only, ESP32 base address: 0x3FF00000
+ uint32_t reserved1 : 10;
+ uint32_t TX_FIFO_FULL : 1; // read-only
+ uint32_t TX_FIFO_EMPTY : 1; // read-only
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_DMA_RSTATUS_REG.TX_DES_ADDRESS = ", TX_DES_ADDRESS, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_RSTATUS_REG.reserved1 = ", reserved1, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_RSTATUS_REG.TX_FIFO_FULL = ", TX_FIFO_FULL, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_RSTATUS_REG.TX_FIFO_EMPTY = ", TX_FIFO_EMPTY, ";");
+ }
+};
+static_assert(sizeof(spi_dma_rstatus_reg_t) == 4, "invalid size for ESP32 spi_dma_rstatus_reg_t");
+
+struct spi_dma_tstatus_reg_t {
+ uint32_t RX_DES_ADDRESS : 20; // read-only, ESP32 base address: 0x3FF00000
+ uint32_t reserved1 : 10;
+ uint32_t RX_FIFO_FULL : 1; // read-only
+ uint32_t RX_FIFO_EMPTY : 1; // read-only
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_DMA_TSTATUS_REG.RX_DES_ADDRESS = ", RX_DES_ADDRESS, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_TSTATUS_REG.reserved1 = ", reserved1, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_TSTATUS_REG.RX_FIFO_FULL = ", RX_FIFO_FULL, ";");
+ SERIAL_ECHOLNPGM("SPI_DMA_TSTATUS_REG.RX_FIFO_EMPTY = ", RX_FIFO_EMPTY, ";");
+ }
+};
+static_assert(sizeof(spi_dma_tstatus_reg_t) == 4, "invalid size for ESP32 spi_dma_tstatus_reg_t");
+
+struct spi_dev_t {
+ spi_cmd_reg_t SPI_CMD_REG;
+ uint32_t SPI_ADDR_REG;
+ spi_ctrl_reg_t SPI_CTRL_REG;
+ spi_ctrl1_reg_t SPI_CTRL1_REG;
+ uint32_t SPI_RD_STATUS_REG;
+ spi_ctrl2_reg_t SPI_CTRL2_REG;
+ spi_clock_reg_t SPI_CLOCK_REG;
+ spi_user_reg_t SPI_USER_REG;
+ spi_user1_reg_t SPI_USER1_REG;
+ spi_user2_reg_t SPI_USER2_REG;
+ spi_mosi_dlen_reg_t SPI_MOSI_DLEN_REG;
+ spi_miso_dlen_reg_t SPI_MISO_DLEN_REG;
+ uint32_t SPI_SLV_WR_STATUS_REG;
+ spi_pin_reg_t SPI_PIN_REG;
+ spi_slave_reg_t SPI_SLAVE_REG;
+ spi_slave1_reg_t SPI_SLAVE1_REG;
+ spi_slave2_reg_t SPI_SLAVE2_REG;
+ spi_slave3_reg_t SPI_SLAVE3_REG;
+ spi_slv_wrbuf_dlen_reg_t SPI_SLV_WRBUF_DLEN_REG;
+ spi_slv_rdbuf_dlen_reg_t SPI_SLV_RDBUF_DLEN_REG;
+ uint8_t pad1[0x14];
+ spi_slv_rd_bit_reg_t SPI_SLV_RD_BIT_REG;
+ uint8_t pad2[0x18];
+ uint32_t SPI_W_REG[16];
+ uint32_t SPI_TX_CRC_REG;
+ uint8_t pad3[0x34];
+ spi_ext2_reg_t SPI_EXT2_REG;
+ uint8_t pad4[4];
+ spi_dma_conf_reg_t SPI_DMA_CONF_REG;
+ spi_dma_out_link_reg_t SPI_DMA_OUT_LINK_REG;
+ spi_dma_in_link_reg_t SPI_DMA_IN_LINK_REG;
+ spi_dma_status_reg_t SPI_DMA_STATUS_REG;
+ spi_dma_int_ena_reg_t SPI_DMA_INT_ENA_REG;
+ spi_dma_int_raw_reg_t SPI_DMA_INT_RAW_REG;
+ spi_dma_int_st_reg_t SPI_DMA_INT_ST_REG;
+ spi_dma_int_clr_reg_t SPI_DMA_INT_CLR_REG;
+ const uint32_t SPI_IN_ERR_EOF_DES_ADDR_REG;
+ const uint32_t SPI_IN_SUC_EOF_DES_ADDR_REG;
+ const uint32_t SPI_INLINK_DSCR_REG;
+ const uint32_t SPI_INLINK_DSCR_BF0_REG;
+ const uint32_t SPI_INLINK_DSCR_BF1_REG;
+ const uint32_t SPI_OUT_EOF_BFR_DES_ADDR_REG;
+ const uint32_t SPI_OUT_EOF_DES_ADDR_REG;
+ const uint32_t SPI_OUTLINK_DSCR_REG;
+ const uint32_t SPI_OUTLINK_DSCR_BF0_REG;
+ const uint32_t SPI_OUTLINK_DSCR_BF1_REG;
+ spi_dma_rstatus_reg_t SPI_DMA_RSTATUS_REG;
+ spi_dma_tstatus_reg_t SPI_DMA_TSTATUS_REG;
+
+ void serial_dump() volatile {
+ SERIAL_ECHOLNPGM("SPI_ADDR_REG = ", SPI_ADDR_REG, ";");
+ SERIAL_ECHOLNPGM("SPI_RD_STATUS_REG = ", SPI_RD_STATUS_REG, ";");
+ SERIAL_ECHOLNPGM("SPI_SLV_WR_STATUS_REG = ", SPI_SLV_WR_STATUS_REG, ";");
+ SERIAL_ECHOLNPGM("SPI_TX_CRC_REG = ", SPI_TX_CRC_REG, ";");
+
+ SPI_CMD_REG.serial_dump();
+ SPI_CTRL_REG.serial_dump();
+ SPI_CTRL1_REG.serial_dump();
+ SPI_CTRL2_REG.serial_dump();
+ SPI_CLOCK_REG.serial_dump();
+ SPI_USER_REG.serial_dump();
+ SPI_USER1_REG.serial_dump();
+ SPI_USER2_REG.serial_dump();
+ SPI_MOSI_DLEN_REG.serial_dump();
+ SPI_MISO_DLEN_REG.serial_dump();
+ SPI_PIN_REG.serial_dump();
+ SPI_SLAVE_REG.serial_dump();
+ SPI_SLAVE1_REG.serial_dump();
+ SPI_SLAVE2_REG.serial_dump();
+ SPI_SLAVE3_REG.serial_dump();
+ SPI_SLV_WRBUF_DLEN_REG.serial_dump();
+ SPI_SLV_RDBUF_DLEN_REG.serial_dump();
+ SPI_SLV_RD_BIT_REG.serial_dump();
+ SPI_EXT2_REG.serial_dump();
+ SPI_DMA_CONF_REG.serial_dump();
+ SPI_DMA_OUT_LINK_REG.serial_dump();
+ SPI_DMA_IN_LINK_REG.serial_dump();
+ SPI_DMA_STATUS_REG.serial_dump();
+ SPI_DMA_INT_ENA_REG.serial_dump();
+ SPI_DMA_INT_RAW_REG.serial_dump();
+ //SPI_DMA_INT_ST_REG.serial_dump();
+ //SPI_DMA_INT_CLR_REG.serial_dump();
+
+ SERIAL_ECHOLNPGM("SPI_IN_ERR_EOF_DES_ADDR_REG = ", SPI_IN_ERR_EOF_DES_ADDR_REG, ";");
+ SERIAL_ECHOLNPGM("SPI_IN_SUC_EOF_DES_ADDR_REG = ", SPI_IN_SUC_EOF_DES_ADDR_REG, ";");
+ SERIAL_ECHOLNPGM("SPI_INLINK_DSCR_REG = ", SPI_INLINK_DSCR_REG, ";");
+ SERIAL_ECHOLNPGM("SPI_INLINK_DSCR_BF0_REG = ", SPI_INLINK_DSCR_BF0_REG, ";");
+ SERIAL_ECHOLNPGM("SPI_INLINK_DSCR_BF1_REG = ", SPI_INLINK_DSCR_BF1_REG, ";");
+ SERIAL_ECHOLNPGM("SPI_OUT_EOF_BFR_DES_ADDR_REG = ", SPI_OUT_EOF_BFR_DES_ADDR_REG, ";");
+ SERIAL_ECHOLNPGM("SPI_OUT_EOF_DES_ADDR_REG = ", SPI_OUT_EOF_DES_ADDR_REG, ";");
+ SERIAL_ECHOLNPGM("SPI_OUTLINK_DSCR_REG = ", SPI_OUTLINK_DSCR_REG, ";");
+ SERIAL_ECHOLNPGM("SPI_OUTLINK_DSCR_BF0_REG = ", SPI_OUTLINK_DSCR_BF0_REG, ";");
+ SERIAL_ECHOLNPGM("SPI_OUTLINK_DSCR_BF1_REG = ", SPI_OUTLINK_DSCR_BF1_REG, ";");
+
+ SPI_DMA_RSTATUS_REG.serial_dump();
+ SPI_DMA_TSTATUS_REG.serial_dump();
+ }
+};
+static_assert(offsetof(spi_dev_t, SPI_CLOCK_REG) == 0x18, "invalid ESP32 offsetof SPI_CLOCK_REG");
+static_assert(offsetof(spi_dev_t, SPI_W_REG[0]) == 0x80, "invalid ESP32 offsetof SPI_W_REG");
+static_assert(offsetof(spi_dev_t, SPI_EXT2_REG) == 0xF8, "invalid ESP32 offsetof SPI_EXT2_REG");
+static_assert(sizeof(spi_dev_t) == 0x150, "wrong formatting of ESP32 spi_dev_t!");
+
+#ifdef HALSPI_ESP32_ENABLE_INTERNBUS
+__ESP32_DEFREG(spi_dev_t, SPI0, 0x3FF43000); // shares signals with SPI1 (USAGE DISALLOWED)
+__ESP32_DEFREG(spi_dev_t, SPI1, 0x3FF42000); // (USAGE DISALLOWED)
+#endif
+__ESP32_DEFREG(spi_dev_t, SPI2, 0x3FF64000); // HSPI
+__ESP32_DEFREG(spi_dev_t, SPI3, 0x3FF65000); // VSPI
+
+#define _SPI_DEFAULT_BUS 2
+#define __SPI_BUSOBJ(IDX) (SPI##IDX)
+#define _SPI_BUSOBJ(IDX) (__SPI_BUSOBJ(IDX))
+
+inline volatile spi_dev_t& SPIGetBusFromIndex(uint8_t idx) {
+ switch(idx) {
+#ifdef HALSPI_ESP32_ENABLE_INTERNBUS
+ case 0: return SPI0;
+ case 1: return SPI1;
+#endif
+ case 2: return SPI2;
+ case 3: return SPI3;
+ default: return _SPI_BUSOBJ(_SPI_DEFAULT_BUS);
+ }
+}
+
+inline uint8_t SPIGetBusIndex(volatile spi_dev_t& SPI) {
+#ifdef HALSPI_ESP32_ENABLE_INTERNBUS
+ if (&SPI == &SPI0) return 0;
+ else if (&SPI == &SPI1) return 1;
+ else
+#endif
+ if (&SPI == &SPI2) return 2;
+ else if (&SPI == &SPI3) return 3;
+ return _SPI_DEFAULT_BUS;
+}
+
+// page 57 of the ESP32 technical reference manual contains default GPIO states after reset.
+// MOSI: SPID/HSPID/VSPID
+// MISO: SPIQ/HSPIQ/VSPIQ
+// CS: SPICS0/HSPICS0/VSPICS0
+// CLK: SPICLK/HSPICLK/VSPICLK
+
+inline void SPIGetSignalForBus(uint8_t busIdx, uint8_t& sckOut, uint8_t& misoOut, uint8_t& mosiOut, uint8_t& csOut) {
+#ifdef HALSPI_ESP32_ENABLE_INTERNBUS
+ if (busIdx == 0 || busIdx == 1) {
+ sckOut = 0;
+ misoOut = 1;
+ mosiOut = 2;
+ csOut = 5;
+ }
+ else
+#endif
+ if (busIdx == 2) {
+ sckOut = 8;
+ misoOut = 9;
+ mosiOut = 10;
+ csOut = 11;
+ }
+ else if (busIdx == 3) {
+ sckOut = 63;
+ misoOut = 64;
+ mosiOut = 65;
+ csOut = 68;
+ }
+ else {
+ sckOut = 0xFF;
+ misoOut = 0xFF;
+ mosiOut = 0xFF;
+ csOut = 0xFF;
+ }
+}
+
+inline gpio_num_t _GetInternalPinName(int pin) {
+ if (pin >= 0 && pin <= GPIO_NUM_MAX) {
+ return (gpio_num_t)pin;
+ }
+ return (gpio_num_t)-1; // NC
+}
+
+#define SPI_IOMUX_INVAL 0xFF
+
+// page 57 of ESP32 ref manual.
+// IOMUX is faster than GPIO matrix.
+inline bool SPIFindIOMUXMapping(
+ int gpio_sck, int gpio_miso, int gpio_mosi, int gpio_cs,
+ uint8_t& spibusIdxOut, uint8_t& func_sck_out, uint8_t& func_miso_out, uint8_t& func_mosi_out, uint8_t& func_cs_out
+) {
+ uint8_t func_sck = SPI_IOMUX_INVAL;
+ uint8_t func_miso = SPI_IOMUX_INVAL;
+ uint8_t func_mosi = SPI_IOMUX_INVAL;
+ uint8_t func_cs = SPI_IOMUX_INVAL;
+ bool found = false;
+#ifdef HALSPI_ESP32_ENABLE_INTERNBUS
+ if (gpio_sck == 6 || gpio_miso == 7 || gpio_mosi == 8 || gpio_cs == 11) {
+ if (gpio_sck == 6) func_sck = 1;
+ if (gpio_miso == 7) func_miso = 1;
+ if (gpio_mosi == 8) func_mosi = 1;
+ if (gpio_cs == 11) func_cs = 1;
+ spibusIdxOut = 0;
+ found = true;
+ }
+ else
+#endif
+ if (gpio_sck == 14 || gpio_miso == 12 || gpio_mosi == 13 || gpio_cs == 15) {
+ if (gpio_sck == 14) func_sck = 1;
+ if (gpio_miso == 12) func_miso = 1;
+ if (gpio_mosi == 13) func_mosi = 1;
+ if (gpio_cs == 15) func_cs = 1;
+ spibusIdxOut = 2;
+ found = true;
+ }
+ else if (gpio_sck == 18 || gpio_miso == 19 || gpio_mosi == 23 || gpio_cs == 5) {
+ if (gpio_sck == 18) func_sck = 1;
+ if (gpio_miso == 19) func_miso = 1;
+ if (gpio_mosi == 23) func_mosi = 1;
+ if (gpio_cs == 5) func_cs = 1;
+ spibusIdxOut = 3;
+ found = true;
+ }
+
+ if (found) {
+ func_sck_out = func_sck;
+ func_miso_out = func_miso;
+ func_mosi_out = func_mosi;
+ func_cs_out = func_cs;
+ }
+ return found;
+}
+
+// There is very little documentation on certain ESP32 internals.
+
+struct gpioMapResult_t {
+ uint8_t spibusIdx;
+ int gpio_sck;
+ int gpio_miso;
+ int gpio_mosi;
+ int gpio_cs;
+ bool datasig_is_direct_iomux;
+};
+
+inline gpioMapResult_t SPIMapGPIO(int gpio_sck, int gpio_miso, int gpio_mosi, int gpio_cs) {
+ if (gpio_sck < 0 && gpio_miso < 0 && gpio_mosi < 0 && gpio_cs < 0) {
+ // Select SPI2.
+ gpio_sck = 14;
+ gpio_miso = 12;
+ gpio_mosi = 13;
+ gpio_cs = 15;
+ }
+
+ uint8_t spibusIdx = _SPI_DEFAULT_BUS; // default SPI bus index
+
+ uint8_t func_sck, func_miso, func_mosi, func_cs;
+ bool fastiomux = SPIFindIOMUXMapping(
+ gpio_sck, gpio_miso, gpio_mosi, gpio_cs,
+ spibusIdx, func_sck, func_miso, func_mosi, func_cs
+ );
+
+ bool has_sck_map = false;
+ bool has_miso_map = false;
+ bool has_mosi_map = false;
+#if 0
+ bool has_cs_map = false;
+#endif
+
+ uint8_t sck_sig, miso_sig, mosi_sig, cs_sig;
+ SPIGetSignalForBus(spibusIdx, sck_sig, miso_sig, mosi_sig, cs_sig);
+
+ (void)cs_sig;
+
+ bool miso_iomux = false;
+
+ if (fastiomux) {
+ if (func_sck != SPI_IOMUX_INVAL) {
+ gpio_iomux_in((unsigned int)gpio_sck, sck_sig);
+ gpio_iomux_out((unsigned int)gpio_sck, func_sck, false);
+ has_sck_map = true;
+ }
+ if (func_miso != SPI_IOMUX_INVAL) {
+ gpio_iomux_in((unsigned int)gpio_miso, miso_sig);
+ gpio_iomux_out((unsigned int)gpio_miso, func_miso, false);
+ has_miso_map = true;
+ miso_iomux = true;
+ }
+ if (func_mosi != SPI_IOMUX_INVAL) {
+ gpio_iomux_in((unsigned int)gpio_mosi, mosi_sig);
+ gpio_iomux_out((unsigned int)gpio_mosi, func_mosi, false);
+ has_mosi_map = true;
+ }
+ #if 0
+ if (func_cs != SPI_IOMUX_INVAL) {
+ gpio_iomux_in((unsigned int)gpio_cs, cs_sig);
+ gpio_iomux_out((unsigned int)gpio_cs, func_cs, false);
+ has_cs_map = true;
+ has_mosi_map = true;
+ }
+ #endif
+ }
+
+ if (has_sck_map == false && gpio_sck >= 0) {
+ gpio_matrix_out((unsigned int)gpio_sck, sck_sig, false, false);
+ pinMode(gpio_sck, OUTPUT);
+ }
+ if (has_miso_map == false && gpio_miso >= 0) {
+ gpio_matrix_in((unsigned int)gpio_miso, miso_sig, false);
+ pinMode(gpio_miso, INPUT);
+ }
+ if (has_mosi_map == false && gpio_mosi >= 0) {
+ gpio_matrix_out((unsigned int)gpio_mosi, mosi_sig, false, false);
+ pinMode(gpio_mosi, OUTPUT);
+ }
+ #if 0
+ if (has_cs_map == false && gpio_cs >= 0) {
+ gpio_matrix_out((unsigned int)gpio_cs, cs_sig, false, false);
+ pinMode(gpio_cs, OUTPUT);
+ }
+ #endif
+
+ gpioMapResult_t result;
+ result.spibusIdx = spibusIdx;
+ result.gpio_sck = gpio_sck;
+ result.gpio_miso = gpio_miso;
+ result.gpio_mosi = gpio_mosi;
+ result.gpio_cs = gpio_cs;
+ result.datasig_is_direct_iomux = (miso_iomux);
+ return result;
+}
+
+inline void SPIUnmapGPIO(gpioMapResult_t& result) {
+ if (result.gpio_sck >= 0) {
+ gpio_reset_pin(_GetInternalPinName(result.gpio_sck));
+ }
+ if (result.gpio_miso >= 0) {
+ gpio_reset_pin(_GetInternalPinName(result.gpio_miso));
+ }
+ if (result.gpio_mosi >= 0) {
+ gpio_reset_pin(_GetInternalPinName(result.gpio_mosi));
+ }
+ #if 0
+ if (result.gpio_cs >= 0) {
+ gpio_reset_pin(_GetInternalPinName(result.gpio_cs));
+ }
+ #endif
+}
+
+struct dport_perip_clk_en_reg_t {
+ uint32_t reserved1 : 1;
+ uint32_t DPORT_SPI01_CLK_EN : 1;
+ uint32_t DPORT_UART_CLK_EN : 1;
+ uint32_t reserved2 : 1;
+ uint32_t DPORT_I2S0_CLK_EN : 1;
+ uint32_t DPORT_UART1_CLK_EN : 1;
+ uint32_t DPORT_SPI2_CLK_EN : 1;
+ uint32_t DPORT_I2C_EXT0_CLK_EN : 1;
+ uint32_t DPORT_UHCI0_CLK_EN : 1;
+ uint32_t DPORT_RMT_CLK_EN : 1;
+ uint32_t DPORT_PCNT_CLK_EN : 1;
+ uint32_t DPORT_LEDC_CLK_EN : 1;
+ uint32_t DPORT_UHCI1_CLK_EN : 1;
+ uint32_t DPORT_TIMERGROUP_CLK_EN : 1;
+ uint32_t DPORT_EFUSE_CLK_EN : 1;
+ uint32_t DPORT_TIMERGROUP1_CLK_EN : 1;
+ uint32_t DPORT_SPI3_CLK_EN : 1;
+ uint32_t DPORT_PWM0_CLK_EN : 1;
+ uint32_t DPORT_I2C_EXT1_CLK_EN : 1;
+ uint32_t DPORT_TWAI_CLK_EN : 1;
+ uint32_t DPORT_PWM1_CLK_EN : 1;
+ uint32_t DPORT_I2S1_CLK_EN : 1;
+ uint32_t DPORT_SPI_DMA_CLK_EN : 1;
+ uint32_t DPORT_UART2_CLK_EN : 1;
+ uint32_t DPORT_UART_MEM_CLK_EN : 1;
+ uint32_t reserved3 : 1;
+ uint32_t reserved4 : 1;
+ uint32_t reserved5 : 5;
+};
+static_assert(sizeof(dport_perip_clk_en_reg_t) == 4, "invalid size of ESP32 dport_perip_clk_en_reg_t");
+
+struct dport_perip_rst_en_reg_t {
+ uint32_t reserved1 : 1;
+ uint32_t DPORT_SPI01_RST : 1;
+ uint32_t DPORT_UART_RST : 1;
+ uint32_t reserved2 : 1;
+ uint32_t DPORT_I2S0_RST : 1;
+ uint32_t DPORT_UART1_RST : 1;
+ uint32_t DPORT_SPI2_RST : 1;
+ uint32_t DPORT_I2C_EXT0_RST : 1;
+ uint32_t DPORT_UHCI0_RST : 1;
+ uint32_t DPORT_RMT_RST : 1;
+ uint32_t DPORT_PCNT_RST : 1;
+ uint32_t DPORT_LEDC_RST : 1;
+ uint32_t DPORT_UHCI1_RST : 1;
+ uint32_t DPORT_TIMERGROUP_RST : 1;
+ uint32_t DPORT_EFUSE_RST : 1;
+ uint32_t DPORT_TIMERGROUP1_RST : 1;
+ uint32_t DPORT_SPI3_RST : 1;
+ uint32_t DPORT_PWM0_RST : 1;
+ uint32_t DPORT_I2C_EXT1_RST : 1;
+ uint32_t DPORT_TWAI_RST : 1;
+ uint32_t DPORT_PWM1_RST : 1;
+ uint32_t DPORT_I2S1_RST : 1;
+ uint32_t DPORT_SPI_DMA_RST : 1;
+ uint32_t DPORT_UART2_RST : 1;
+ uint32_t DPORT_UART_MEM_RST : 1;
+ uint32_t reserved3 : 1;
+ uint32_t reserved4 : 1;
+ uint32_t reserved5 : 5;
+};
+static_assert(sizeof(dport_perip_rst_en_reg_t) == 4, "invalid size of ESP32 dport_perip_rst_en_reg_t");
+
+__ESP32_DEFREG(dport_perip_clk_en_reg_t, DPORT_PERIP_CLK_EN_REG, 0x3FF000C0);
+__ESP32_DEFREG(dport_perip_rst_en_reg_t, DPORT_PERIP_RST_EN_REG, 0x3FF000C4);
+
+#define DPORT_SPI_DMA_CHAN_SEL_NONE 0
+#define DPORT_SPI_DMA_CHAN_SEL_CHAN1 1
+#define DPORT_SPI_DMA_CHAN_SEL_CHAN2 2
+
+struct dport_spi_dma_chan_sel_reg_t {
+ uint32_t DPORT_SPI_SPI1_DMA_CHAN_SEL : 2;
+ uint32_t DPORT_SPI_SPI2_DMA_CHAN_SEL : 2;
+ uint32_t DPORT_SPI_SPI3_DMA_CHAN_SEL : 2;
+ uint32_t reserved1 : 26;
+};
+static_assert(sizeof(dport_spi_dma_chan_sel_reg_t) == sizeof(uint32_t), "invalid size of ESP32 dport_spi_dma_chan_sel_reg_t");
+
+__ESP32_DEFREG(dport_spi_dma_chan_sel_reg_t, DPORT_SPI_DMA_CHAN_SEL_REG, 0x3FF005A8);
+
+#if 0
+
+struct dport_cpu_per_conf_reg_t {
+ uint32_t DPORT_CPU_CPUPERIOD_SEL : 2;
+ uint32_t reserved1 : 30;
+};
+static_assert(sizeof(dport_cpu_per_conf_reg_t) == 4, "invalid size of ESP32 dport_cpu_per_conf_reg_t");
+
+__ESP32_DEFREG(dport_cpu_per_conf_reg_t, DPORT_CPU_PER_CONF_REG, 0x3FF0003C);
+
+#define RTC_CNTL_SOC_CLK_XTL 0
+#define RTC_CNTL_SOC_CLK_PLL 1
+#define RTC_CNTL_SOC_CLK_RC_FAST 2
+#define RTC_CNTL_SOC_CLK_APLL 3
+
+struct rtc_cntl_clk_conf_reg_t {
+ uint32_t reserved1 : 4;
+ uint32_t RTC_CNTRL_CK8M_DIV : 2;
+ uint32_t RTC_CNTL_ENB_CK8M : 1;
+ uint32_t RTC_CNTL_ENB_CK8M_DIV : 1;
+ uint32_t RTC_CNTL_DIG_XTAL32K_EN : 1;
+ uint32_t RTC_CNTL_DIG_CLK8M_D256_EN : 1;
+ uint32_t RTC_CNTL_DIG_CLK8M_EN : 1;
+ uint32_t reserved2 : 1;
+ uint32_t RTC_CNTL_CK8M_DIV_SEL : 3;
+ uint32_t reserved3 : 2;
+ uint32_t RTC_CNTL_CK8M_DFREQ : 8;
+ uint32_t RTC_CNTL_CK8M_FORCE_PD : 1;
+ uint32_t RTC_CNTL_CK8M_FORCE_PU : 1;
+ uint32_t RTC_CNTL_SOC_CLK_SEL : 2;
+ uint32_t RTC_CNTL_FAST_CLK_RTC_SEL : 1;
+ uint32_t RTC_CNTL_ANA_CLK_RTC_SEL : 2;
+};
+static_assert(sizeof(rtc_cntl_clk_conf_reg_t) == 4, "invalid size of ESP32 rtc_cntl_clk_conf_reg_t");
+
+__ESP32_DEFREG(rtc_cntl_clk_conf_reg_t, RTC_CNTL_CLK_CONF_REG, 0x3FF48070);
+
+struct syscon_conf_reg_t {
+ uint32_t SYSCON_PRE_DIV_CNT : 10;
+ uint32_t SYSCON_CLK_320M_EN : 1;
+ uint32_t SYSCON_CLK_EN : 1;
+ uint32_t SYSCON_RST_TICK_CNT : 1;
+ uint32_t SYSCON_QUICK_CLK_CHNG : 1;
+ uint32_t reserved1 : 18;
+};
+
+// Undocumented.
+__ESP32_DEFREG(syscon_conf_reg_t, SYSCON_CONF_REG, 0x3FF66000);
+
+#endif
+
+// You can transfer up to 64bytes in one burst using default SPI without DMA on the ESP32.
+
+struct clkcnt_res_t {
+ uint32_t n : 6;
+ uint32_t l : 6;
+ uint32_t h : 6;
+ uint32_t pre : 13;
+ uint32_t sysclock : 1;
+
+ inline uint32_t GetFrequencyDivider(void) const {
+ return (n+1)*(pre+1);
+ }
+};
+
+static void SPIConfigureClock(volatile spi_dev_t& SPI, int clkMode, bool is_direct_io, const clkcnt_res_t& clkdiv) {
+ if (clkMode == SPI_CLKMODE_0) {
+ SPI.SPI_PIN_REG.SPI_CK_IDLE_EDGE = 0;
+ SPI.SPI_USER_REG.SPI_CK_OUT_EDGE = 0;
+ }
+ else if (clkMode == SPI_CLKMODE_1) {
+ SPI.SPI_PIN_REG.SPI_CK_IDLE_EDGE = 0;
+ SPI.SPI_USER_REG.SPI_CK_OUT_EDGE = 1;
+ }
+ else if (clkMode == SPI_CLKMODE_2) {
+ SPI.SPI_PIN_REG.SPI_CK_IDLE_EDGE = 1;
+ SPI.SPI_USER_REG.SPI_CK_OUT_EDGE = 1;
+ }
+ else if (clkMode == SPI_CLKMODE_3) {
+ SPI.SPI_PIN_REG.SPI_CK_IDLE_EDGE = 1;
+ SPI.SPI_USER_REG.SPI_CK_OUT_EDGE = 0;
+ }
+
+ spi_clock_reg_t _SPI_CLOCK_REG;
+ _SPI_CLOCK_REG.SPI_CLK_EQU_SYSCLK = clkdiv.sysclock;
+ _SPI_CLOCK_REG.SPI_CLKDIV_PRE = clkdiv.pre;
+ _SPI_CLOCK_REG.SPI_CLKCNT_N = clkdiv.n;
+ _SPI_CLOCK_REG.SPI_CLKCNT_L = clkdiv.l;
+ _SPI_CLOCK_REG.SPI_CLKCNT_H = clkdiv.h;
+ dwrite(SPI.SPI_CLOCK_REG, _SPI_CLOCK_REG);
+
+#ifndef HALSPI_ESP32_DISABLE_ADV_DELAYCONF
+ uint32_t apbFreqDiv = clkdiv.GetFrequencyDivider();
+
+ if (is_direct_io) {
+ if (apbFreqDiv > 4) {
+ SPI.SPI_CTRL2_REG.SPI_MISO_DELAY_MODE = 0;
+ }
+ else {
+ if (clkMode == SPI_CLKMODE_0 || clkMode == SPI_CLKMODE_3) {
+ SPI.SPI_CTRL2_REG.SPI_MISO_DELAY_MODE = 2;
+ }
+ else {
+ SPI.SPI_CTRL2_REG.SPI_MISO_DELAY_MODE = 1;
+ }
+ }
+ SPI.SPI_USER_REG.SPI_USR_DUMMY = 0;
+ }
+ else {
+ if (apbFreqDiv <= 2) {
+ SPI.SPI_CTRL2_REG.SPI_MISO_DELAY_MODE = 0;
+ SPI.SPI_USER_REG.SPI_USR_DUMMY = 1;
+ SPI.SPI_USER1_REG.SPI_USR_DUMMY_CYCLELEN = 0;
+ }
+ else if (apbFreqDiv < 8) {
+ SPI.SPI_CTRL2_REG.SPI_MISO_DELAY_MODE = 0;
+ SPI.SPI_USER_REG.SPI_USR_DUMMY = 0;
+ }
+ else {
+ if (clkMode == SPI_CLKMODE_0 || clkMode == SPI_CLKMODE_3) {
+ SPI.SPI_CTRL2_REG.SPI_MISO_DELAY_MODE = 2;
+ }
+ else {
+ SPI.SPI_CTRL2_REG.SPI_MISO_DELAY_MODE = 1;
+ }
+ SPI.SPI_USER_REG.SPI_USR_DUMMY = 0;
+ }
+ }
+#else
+ SPI.SPI_USER_REG.SPI_USR_DUMMY = 0;
+ SPI.SPI_USER1_REG.SPI_USR_DUMMY_CYCLELEN = 0;
+ SPI.SPI_CTRL2_REG.SPI_MISO_DELAY_MODE = 0;
+#endif
+ SPI.SPI_CTRL2_REG.SPI_MISO_DELAY_NUM = 0;
+ SPI.SPI_CTRL2_REG.SPI_MOSI_DELAY_MODE = 0;
+ SPI.SPI_CTRL2_REG.SPI_MOSI_DELAY_NUM = 0;
+}
+
+#if 0
+static const uint8_t _spi_clkcnt_n_primes[] = {
+ 2, 3, 4, 5, 11, 13, 17, 19, 23, 29, 31,
+ 37, 41, 43, 47, 53, 59, 61
+};
+#endif
+
+template
+inline auto DIST(T1 a, T2 b) noexcept -> decltype(a-b)
+{
+ if (a < b) {
+ return b - a;
+ }
+ else {
+ return a - b;
+ }
+}
+
+// see page 121 of ESP32 technical reference manual (GP-SPI Clock Control)
+inline clkcnt_res_t SPIApproximateClockDivider(uint32_t maxClockFreq, uint32_t spibasefreq) {
+#if 0
+ // compare with https://github.com/espressif/esp-idf/blob/0a93ee1337c15668c7f9998a53822f281a17670e/components/hal/esp32/include/hal/spi_ll.h#L551
+ // Cannot get this code to work.
+
+ clkcnt_res_t res;
+
+ if (spibasefreq >= maxClockFreq) {
+ res.sysclock = true;
+ res.pre = 0;
+ res.n = 0;
+ res.l = 0;
+ res.h = 0;
+ return res;
+ }
+ res.sysclock = false;
+
+ // maxClockFreq = f_spi
+ // spibasefreq = f_apb
+
+ uint32_t approx_div = CEIL_DIV(spibasefreq, maxClockFreq); // pre + 1
+ if (approx_div <= (1<<13)) { // 2^13
+ res.pre = (approx_div - 1);
+ res.n = 1; // n needs to be at least 2 so we have one LOW and one HIGH pulse (this detail is found nowhere in the ESP32 docs)
+ goto finalize;
+ }
+
+ {
+ uint8_t best_approx_prime = 2; // n + 1
+ uint32_t best_approx = 2; // to avoid annoying GCC warning
+ bool found_best_approx_prime = false;
+
+ for (uint8_t prime : _spi_clkcnt_n_primes) {
+ uint32_t primediv = (approx_div / prime);
+ uint32_t approx_freqdiv = (primediv * approx_div);
+ if (approx_freqdiv <= (1<<6)*(1<<13)) { // (2^6 * 2^13)
+ if (found_best_approx_prime == false || (best_approx > approx_freqdiv)) {
+ best_approx_prime = prime;
+ best_approx = approx_freqdiv;
+ found_best_approx_prime = true;
+ }
+ }
+ }
+
+ if (found_best_approx_prime == false || (best_approx_prime*approx_div <= 1)) {
+ best_approx_prime = 2;
+ }
+
+ res.n = (best_approx_prime - 1);
+ res.pre = (approx_div - 1);
+ }
+finalize:
+ res.h = 0u;
+ res.l = eir::Maximum( ((unsigned int)(res.n+1u) / 2u), 1u ) - 1u;
+ return res;
+#else
+ // Taken from the ArduinoCore ESP32 because the ESP32 clock documentation is VERY lacking!
+ if(maxClockFreq >= spibasefreq) {
+ clkcnt_res_t sysreg;
+ sysreg.sysclock = true;
+ sysreg.pre = 0;
+ sysreg.n = 0;
+ sysreg.l = 0;
+ sysreg.h = 0;
+ return sysreg;
+ }
+
+ clkcnt_res_t minFreqReg;
+ minFreqReg.sysclock = false;
+ minFreqReg.pre = (1<<13)-1;
+ minFreqReg.n = (1<<6)-1;
+ minFreqReg.l = 0;
+ minFreqReg.h = 0;
+ uint32_t minFreq = (spibasefreq / minFreqReg.GetFrequencyDivider());
+ if(maxClockFreq < minFreq) {
+ return minFreqReg;
+ }
+
+ uint8_t calN = 1;
+ clkcnt_res_t bestReg;
+ bestReg.pre = 0;
+ bestReg.n = 0;
+ bestReg.l = 0;
+ bestReg.h = 0;
+ bestReg.sysclock = false;
+ uint32_t bestFreq = 0;
+ bool has_best_freq = false;
+
+ while(calN <= (1<<6)-1) {
+ clkcnt_res_t reg;
+ reg.pre = 0;
+ reg.n = 0;
+ reg.l = 0;
+ reg.h = 0;
+ reg.sysclock = false;
+ uint32_t calFreq;
+ int32_t calPre;
+ int8_t calPreVari = -2;
+
+ reg.n = calN;
+ reg.l = ((reg.n + 1) / 2);
+
+ calPre = ((int32_t)((spibasefreq / (reg.n + 1)) / maxClockFreq) - 1) + calPreVari;
+ while(calPreVari++ <= 1) {
+ calPre++;
+ if(calPre > (1<<13)-1) {
+ reg.pre = (1<<13)-1;
+ } else if(calPre <= 0) {
+ reg.pre = 0;
+ } else {
+ reg.pre = (uint32_t)calPre;
+ }
+ calFreq = (spibasefreq / reg.GetFrequencyDivider());
+ if(calFreq == maxClockFreq) {
+ return reg;
+ }
+ else if(calFreq < maxClockFreq) {
+ if(has_best_freq == false || ((maxClockFreq - calFreq) < (maxClockFreq - bestFreq))) {
+ bestFreq = calFreq;
+ bestReg = reg;
+ has_best_freq = true;
+ }
+ }
+ }
+ calN++;
+ }
+ return bestReg;
+#endif
+}
+
+static void SPIConfigureBitOrder(volatile spi_dev_t& SPI, int bitOrder) {
+ if (bitOrder == SPI_BITORDER_MSB) {
+ SPI.SPI_CTRL_REG.SPI_WR_BIT_ORDER = _ESP32_BIT_ORDER_MSB;
+ SPI.SPI_CTRL_REG.SPI_RD_BIT_ORDER = _ESP32_BIT_ORDER_MSB;
+ }
+ else {
+ SPI.SPI_CTRL_REG.SPI_WR_BIT_ORDER = _ESP32_BIT_ORDER_LSB;
+ SPI.SPI_CTRL_REG.SPI_RD_BIT_ORDER = _ESP32_BIT_ORDER_LSB;
+ }
+}
+
+inline uint16_t SPIGetWriteBufferSize(volatile spi_dev_t& SPI) {
+ return 64;//( SPI.SPI_USER_REG.SPI_USR_MOSI_HIGHPART == 1 ? 32 : 64 );
+}
+
+inline uint16_t SPIGetWriteBufferStartIndex(volatile spi_dev_t& SPI) {
+ return 0;//( SPI.SPI_USER_REG.SPI_USR_MOSI_HIGHPART == 1 ? 8 : 0 );
+}
+
+template
+inline void IRAM_ATTR SPIPrepareWriteBitManager(volatile spi_dev_t& SPI, bitManType& bitman) noexcept {
+ bool wr_msbfirst = (SPI.SPI_CTRL_REG.SPI_WR_BIT_ORDER == _ESP32_BIT_ORDER_MSB);
+
+ bitman.SetDefaultStorageProperty(
+ wr_msbfirst ? eir::endian::eSpecificEndian::BIG_ENDIAN : eir::endian::eSpecificEndian::LITTLE_ENDIAN,
+ false
+ );
+}
+
+template
+inline void IRAM_ATTR SPIPrepareReadBitManager(volatile spi_dev_t& SPI, bitManType& bitman) noexcept {
+ bool rd_msbfirst = (SPI.SPI_CTRL_REG.SPI_RD_BIT_ORDER == _ESP32_BIT_ORDER_MSB);
+
+ bitman.SetDefaultStorageProperty(
+ rd_msbfirst ? eir::endian::eSpecificEndian::BIG_ENDIAN : eir::endian::eSpecificEndian::LITTLE_ENDIAN,
+ false
+ );
+}
+
+template
+inline void IRAM_ATTR SPIWriteDataToTransferIsolated(
+ volatile spi_dev_t& SPI, const numberType *buf, uint16_t cnt, uint32_t srcByteStartIdx,
+ uint16_t& cntSentBytes_out
+) {
+ uint16_t start_num_idx = SPIGetWriteBufferStartIndex(SPI);
+
+ esp32BitManager src_bitman( buf, cnt );
+
+ SPIPrepareWriteBitManager( SPI, src_bitman );
+
+ eir::BitNumberIteratorForStruct src_iter;
+ src_iter.addBytes( srcByteStartIdx );
+ src_bitman.SetIterator( src_iter );
+
+ eir::BitNumberIteratorForStruct txiter( start_num_idx );
+ while ( src_bitman.IsAtEnd() == false && txiter.getNumberOffset() < COUNT(SPI.SPI_W_REG) ) {
+ uint32_t txitem = 0u;
+ uint32_t n = txiter.getNumberOffset();
+ src_bitman.FetchSingle( txitem, txiter );
+ SPI.SPI_W_REG[n] = txitem;
+ }
+
+ cntSentBytes_out = ( txiter.getTotalByteOffset() );
+}
+
+inline uint16_t SPIGetReadBufferSize(volatile spi_dev_t& SPI) {
+ return 64;//( SPI.SPI_USER_REG.SPI_USR_MISO_HIGHPART == 1 ? 32 : 64 );
+}
+
+inline uint16_t SPIGetReadBufferStartIndex(volatile spi_dev_t& SPI) {
+ return 0;//( SPI.SPI_USER_REG.SPI_USR_MISO_HIGHPART == 1 ? 8 : 0 );
+}
+
+static void SPITransaction(volatile spi_dev_t& SPI, uint32_t txcount_bytes) {
+ if (txcount_bytes == 0) return;
+
+ uint32_t txcount_bits = ( txcount_bytes * 8u );
+
+ if (SPI.SPI_USER_REG.SPI_USR_MOSI == true) {
+ SPI.SPI_MOSI_DLEN_REG.SPI_USR_MOSI_DBITLEN = txcount_bits - 1;
+ }
+ if (SPI.SPI_USER_REG.SPI_USR_MISO == true) {
+ SPI.SPI_MISO_DLEN_REG.SPI_USR_MISO_DBITLEN = txcount_bits - 1;
+ }
+
+ SPI.SPI_CMD_REG.SPI_USR = true;
+
+ spi_monitored_loop usrw;
+ while (SPI.SPI_CMD_REG.SPI_USR) {
+ /* wait until transfer has finished */
+ usrw.update(1);
+ }
+}
+
+static void SPIResetBus(volatile spi_dev_t& SPI) {
+ spi_cmd_reg_t SPI_CMD_REG;
+ SPI_CMD_REG.reserved1 = 0;
+ SPI_CMD_REG.SPI_USR = 0;
+ SPI_CMD_REG.reserved2 = 0;
+ dwrite(SPI.SPI_CMD_REG, SPI_CMD_REG);
+
+ SPI.SPI_ADDR_REG = 0;
+
+ spi_ctrl_reg_t SPI_CTRL_REG;
+ SPI_CTRL_REG.reserved1 = 0;
+ SPI_CTRL_REG.SPI_FASTRD_MODE = 1;
+ SPI_CTRL_REG.SPI_FREAD_DUAL = 0;
+ SPI_CTRL_REG.reserved2 = 0;
+ SPI_CTRL_REG.SPI_FREAD_QUAD = 0;
+ SPI_CTRL_REG.SPI_WP = 1;
+ SPI_CTRL_REG.reserved3 = 0;
+ SPI_CTRL_REG.SPI_FREAD_DIO = 0;
+ SPI_CTRL_REG.SPI_FREAD_QIO = 0;
+ SPI_CTRL_REG.SPI_RD_BIT_ORDER = _ESP32_BIT_ORDER_MSB;
+ SPI_CTRL_REG.SPI_WR_BIT_ORDER = _ESP32_BIT_ORDER_MSB;
+ SPI_CTRL_REG.reserved4 = 0;
+ dwrite(SPI.SPI_CTRL_REG, SPI_CTRL_REG);
+
+ spi_ctrl1_reg_t SPI_CTRL1_REG;
+ SPI_CTRL1_REG.reserved1 = 0;
+ SPI_CTRL1_REG.SPI_CS_HOLD_DELAY = 5;
+ dwrite(SPI.SPI_CTRL1_REG, SPI_CTRL1_REG);
+
+ SPI.SPI_RD_STATUS_REG = 0;
+
+ spi_ctrl2_reg_t SPI_CTRL2_REG;
+ SPI_CTRL2_REG.SPI_SETUP_TIME = 1;
+ SPI_CTRL2_REG.SPI_HOLD_TIME = 1;
+ SPI_CTRL2_REG.reserved1 = 0;
+ SPI_CTRL2_REG.SPI_CK_OUT_HIGH_MODE = 0;
+ SPI_CTRL2_REG.SPI_MISO_DELAY_MODE = 0;
+ SPI_CTRL2_REG.SPI_MISO_DELAY_NUM = 0;
+ SPI_CTRL2_REG.SPI_MOSI_DELAY_MODE = 0;
+ SPI_CTRL2_REG.SPI_MOSI_DELAY_NUM = 0;
+ SPI_CTRL2_REG.SPI_CS_DELAY_MODE = 0;
+ SPI_CTRL2_REG.SPI_CS_DELAY_NUM = 0;
+ dwrite(SPI.SPI_CTRL2_REG, SPI_CTRL2_REG);
+
+ spi_clock_reg_t SPI_CLOCK_REG;
+ SPI_CLOCK_REG.SPI_CLKCNT_L = 3;
+ SPI_CLOCK_REG.SPI_CLKCNT_H = 1;
+ SPI_CLOCK_REG.SPI_CLKCNT_N = 3;
+ SPI_CLOCK_REG.SPI_CLKDIV_PRE = 0;
+ SPI_CLOCK_REG.SPI_CLK_EQU_SYSCLK = 1;
+ dwrite(SPI.SPI_CLOCK_REG, SPI_CLOCK_REG);
+
+ spi_user_reg_t SPI_USER_REG;
+ SPI_USER_REG.SPI_DOUTDIN = 0;
+ SPI_USER_REG.reserved1 = 0;
+ SPI_USER_REG.SPI_CS_HOLD = 0;
+ SPI_USER_REG.SPI_CS_SETUP = 0;
+ SPI_USER_REG.SPI_CK_I_EDGE = 1;
+ SPI_USER_REG.SPI_CK_OUT_EDGE = 0;
+ SPI_USER_REG.reserved2 = 0;
+ SPI_USER_REG.SPI_RD_BYTE_ORDER = 0;
+ SPI_USER_REG.SPI_WR_BYTE_ORDER = 0;
+ SPI_USER_REG.SPI_FWRITE_DUAL = 0;
+ SPI_USER_REG.SPI_FWRITE_QUAD = 0;
+ SPI_USER_REG.SPI_FWRITE_DIO = 0;
+ SPI_USER_REG.SPI_FWRITE_QIO = 0;
+ SPI_USER_REG.SPI_SIO = 0;
+ SPI_USER_REG.reserved3 = 0;
+ SPI_USER_REG.SPI_USR_MISO_HIGHPART = 0;
+ SPI_USER_REG.SPI_USR_MOSI_HIGHPART = 0;
+ SPI_USER_REG.SPI_USR_DUMMY_IDLE = 0;
+ SPI_USER_REG.SPI_USR_MOSI = 0;
+ SPI_USER_REG.SPI_USR_MISO = 0;
+ SPI_USER_REG.SPI_USR_DUMMY = 0;
+ SPI_USER_REG.SPI_USR_ADDR = 0;
+ SPI_USER_REG.SPI_USR_COMMAND = 1;
+ dwrite(SPI.SPI_USER_REG, SPI_USER_REG);
+
+ SPI.SPI_USER1_REG.SPI_USR_DUMMY_CYCLELEN = 0;
+
+ spi_user2_reg_t SPI_USER2_REG;
+ SPI_USER2_REG.SPI_USR_COMMAND_VALUE = 0;
+ SPI_USER2_REG.reserved1 = 0;
+ SPI_USER2_REG.SPI_USR_COMMAND_BITLEN = 7;
+ dwrite(SPI.SPI_USER2_REG, SPI_USER2_REG);
+
+ spi_mosi_dlen_reg_t SPI_MOSI_DLEN_REG;
+ SPI_MOSI_DLEN_REG.SPI_USR_MOSI_DBITLEN = 0;
+ SPI_MOSI_DLEN_REG.reserved1 = 0;
+ dwrite(SPI.SPI_MOSI_DLEN_REG, SPI_MOSI_DLEN_REG);
+
+ spi_miso_dlen_reg_t SPI_MISO_DLEN_REG;
+ SPI_MISO_DLEN_REG.SPI_USR_MISO_DBITLEN = 0;
+ SPI_MISO_DLEN_REG.reserved1 = 0;
+ dwrite(SPI.SPI_MISO_DLEN_REG, SPI_MISO_DLEN_REG);
+
+ SPI.SPI_SLV_WR_STATUS_REG = 0;
+
+ spi_pin_reg_t SPI_PIN_REG;
+ SPI_PIN_REG.SPI_CS0_DIS = 0;
+ SPI_PIN_REG.SPI_CS1_DIS = 1;
+ SPI_PIN_REG.SPI_CS2_DIS = 1;
+ SPI_PIN_REG.reserved1 = 0;
+ SPI_PIN_REG.SPI_CK_DIS = 0;
+ SPI_PIN_REG.SPI_MASTER_CS_POL = 0;
+ SPI_PIN_REG.reserved2 = 0;
+ SPI_PIN_REG.SPI_MASTER_CK_SEL = 0;
+ SPI_PIN_REG.reserved3 = 0;
+ SPI_PIN_REG.SPI_CK_IDLE_EDGE = 0;
+ SPI_PIN_REG.SPI_CS_KEEP_ACTIVE = 0;
+ SPI_PIN_REG.reserved4 = 0;
+ dwrite(SPI.SPI_PIN_REG, SPI_PIN_REG);
+
+ spi_slave_reg_t SPI_SLAVE_REG;
+ SPI_SLAVE_REG.SPI_SLV_RD_BUF_DONE = 0;
+ SPI_SLAVE_REG.SPI_SLV_WR_BUF_DONE = 0;
+ SPI_SLAVE_REG.SPI_SLV_RD_STA_DONE = 0;
+ SPI_SLAVE_REG.SPI_SLV_WR_STA_DONE = 0;
+ SPI_SLAVE_REG.SPI_TRANS_DONE = 0;
+ SPI_SLAVE_REG.SPI_SLV_RD_BUF_INTEN = 0;
+ SPI_SLAVE_REG.SPI_SLV_WR_BUF_INTEN = 0;
+ SPI_SLAVE_REG.SPI_SLV_RD_STA_INTEN = 0;
+ SPI_SLAVE_REG.SPI_SLV_WR_STA_INTEN = 0;
+ SPI_SLAVE_REG.SPI_TRANS_INTEN = 0;
+ SPI_SLAVE_REG.SPI_CS_I_MODE = 0;
+ SPI_SLAVE_REG.reserved1 = 0;
+ SPI_SLAVE_REG.SPI_SLV_LAST_COMMAND = 0;
+ SPI_SLAVE_REG.SPI_SLV_LAST_STATE = 0;
+ SPI_SLAVE_REG.SPI_TRANS_CNT = 0;
+ SPI_SLAVE_REG.SPI_SLV_CMD_DEFINE = 0;
+ SPI_SLAVE_REG.SPI_SLV_WR_RD_STA_EN = 0;
+ SPI_SLAVE_REG.SPI_SLV_WR_RD_BUF_EN = 0;
+ SPI_SLAVE_REG.SPI_SLAVE_MODE = 0;
+ SPI_SLAVE_REG.SPI_SYNC_RESET = 0;
+ dwrite(SPI.SPI_SLAVE_REG, SPI_SLAVE_REG);
+
+ spi_slave1_reg_t SPI_SLAVE1_REG;
+ SPI_SLAVE1_REG.SPI_SLV_RDBUF_DUMMY_EN = 0;
+ SPI_SLAVE1_REG.SPI_SLV_WRBUF_DUMMY_EN = 0;
+ SPI_SLAVE1_REG.SPI_SLV_RDSTA_DUMMY_EN = 0;
+ SPI_SLAVE1_REG.SPI_SLV_WRSTA_DUMMY_EN = 0;
+ SPI_SLAVE1_REG.SPI_SLV_WR_ADDR_BITLEN = 0;
+ SPI_SLAVE1_REG.SPI_SLV_RD_ADDR_BITLEN = 0;
+ SPI_SLAVE1_REG.reserved1 = 0;
+ SPI_SLAVE1_REG.SPI_SLV_STATUS_READBACK = 1;
+ SPI_SLAVE1_REG.SPI_SLV_STATUS_FAST_EN = 0;
+ SPI_SLAVE1_REG.SPI_SLV_STATUS_BITLEN = 0;
+ dwrite(SPI.SPI_SLAVE1_REG, SPI_SLAVE1_REG);
+
+ spi_slave2_reg_t SPI_SLAVE2_REG;
+ SPI_SLAVE2_REG.SPI_SLV_RDSTA_DUMMY_CYCLELEN = 0;
+ SPI_SLAVE2_REG.SPI_SLV_WRSTA_DUMMY_CYCLELEN = 0;
+ SPI_SLAVE2_REG.SPI_SLV_RDBUF_DUMMY_CYCLELEN = 0;
+ SPI_SLAVE2_REG.SPI_SLV_WRBUF_DUMMY_CYCLELEN = 0;
+ dwrite(SPI.SPI_SLAVE2_REG, SPI_SLAVE2_REG);
+
+ spi_slave3_reg_t SPI_SLAVE3_REG;
+ SPI_SLAVE3_REG.SPI_SLV_RDBUF_CMD_VALUE = 0;
+ SPI_SLAVE3_REG.SPI_SLV_WRBUF_CMD_VALUE = 0;
+ SPI_SLAVE3_REG.SPI_SLV_RDSTA_CMD_VALUE = 0;
+ SPI_SLAVE3_REG.SPI_SLV_WRSTA_CMD_VALUE = 0;
+ dwrite(SPI.SPI_SLAVE3_REG, SPI_SLAVE3_REG);
+
+ spi_slv_wrbuf_dlen_reg_t SPI_SLV_WRBUF_DLEN_REG;
+ SPI_SLV_WRBUF_DLEN_REG.SPI_SLV_WRBUF_DBITLEN = 0;
+ SPI_SLV_WRBUF_DLEN_REG.reserved1 = 0;
+ dwrite(SPI.SPI_SLV_WRBUF_DLEN_REG, SPI_SLV_WRBUF_DLEN_REG);
+
+ spi_slv_rdbuf_dlen_reg_t SPI_SLV_RDBUF_DLEN_REG;
+ SPI_SLV_RDBUF_DLEN_REG.SPI_SLV_RDBUF_DBITLEN = 0;
+ SPI_SLV_RDBUF_DLEN_REG.reserved1 = 0;
+ dwrite(SPI.SPI_SLV_RDBUF_DLEN_REG, SPI_SLV_RDBUF_DLEN_REG);
+
+ spi_slv_rd_bit_reg_t SPI_SLV_RD_BIT_REG;
+ SPI_SLV_RD_BIT_REG.SPI_SLV_RDATA_BIT = 0;
+ SPI_SLV_RD_BIT_REG.reserved1 = 0;
+ dwrite(SPI.SPI_SLV_RD_BIT_REG, SPI_SLV_RD_BIT_REG);
+
+ for (uint32_t n = 0; n < 16; n++)
+ SPI.SPI_W_REG[n] = 0;
+
+ SPI.SPI_TX_CRC_REG = 0;
+
+ //SPI.SPI_EXT2_REG.SPI_ST = 0;
+ SPI.SPI_EXT2_REG.reserved1 = 0;
+
+ spi_dma_conf_reg_t SPI_DMA_CONF_REG;
+ SPI_DMA_CONF_REG.reserved1 = 0;
+ SPI_DMA_CONF_REG.SPI_IN_RST = 0;
+ SPI_DMA_CONF_REG.SPI_OUT_RST = 0;
+ SPI_DMA_CONF_REG.SPI_AHBM_FIFO_RST = 0;
+ SPI_DMA_CONF_REG.SPI_AHBM_RST = 0;
+ SPI_DMA_CONF_REG.reserved2 = 0;
+ SPI_DMA_CONF_REG.SPI_OUT_EOF_MODE = 1;
+ SPI_DMA_CONF_REG.SPI_OUTDSCR_BURST_EN = 0;
+ SPI_DMA_CONF_REG.SPI_INDSCR_BURST_EN = 0;
+ SPI_DMA_CONF_REG.SPI_OUT_DATA_BURST_EN = 0;
+ SPI_DMA_CONF_REG.reserved3 = 0;
+ SPI_DMA_CONF_REG.SPI_DMA_RX_STOP = 0;
+ SPI_DMA_CONF_REG.SPI_DMA_TX_STOP = 0;
+ SPI_DMA_CONF_REG.SPI_DMA_CONTINUE = 0;
+ SPI_DMA_CONF_REG.reserved4 = 0;
+ dwrite(SPI.SPI_DMA_CONF_REG, SPI_DMA_CONF_REG);
+
+ spi_dma_out_link_reg_t SPI_DMA_OUT_LINK_REG;
+ SPI_DMA_OUT_LINK_REG.SPI_OUTLINK_ADDR = 0;
+ SPI_DMA_OUT_LINK_REG.reserved1 = 0;
+ SPI_DMA_OUT_LINK_REG.SPI_OUTLINK_STOP = 0;
+ SPI_DMA_OUT_LINK_REG.SPI_OUTLINK_START = 0;
+ SPI_DMA_OUT_LINK_REG.SPI_OUTLINK_RESTART = 0;
+ SPI_DMA_OUT_LINK_REG.reserved2 = 0;
+ dwrite(SPI.SPI_DMA_OUT_LINK_REG, SPI_DMA_OUT_LINK_REG);
+
+ spi_dma_in_link_reg_t SPI_DMA_IN_LINK_REG;
+ SPI_DMA_IN_LINK_REG.SPI_INLINK_ADDR = 0;
+ SPI_DMA_IN_LINK_REG.SPI_INLINK_AUTO_RET = 0;
+ SPI_DMA_IN_LINK_REG.reserved1 = 0;
+ SPI_DMA_IN_LINK_REG.SPI_INLINK_STOP = 0;
+ SPI_DMA_IN_LINK_REG.SPI_INLINK_START = 0;
+ SPI_DMA_IN_LINK_REG.SPI_INLINK_RESTART = 0;
+ SPI_DMA_IN_LINK_REG.reserved2 = 0;
+ dwrite(SPI.SPI_DMA_IN_LINK_REG, SPI_DMA_IN_LINK_REG);
+
+ SPI.SPI_DMA_STATUS_REG.reserved1 = 0;
+
+ spi_dma_int_ena_reg_t SPI_DMA_INT_ENA_REG;
+ SPI_DMA_INT_ENA_REG.SPI_INLINK_DSCR_EMPTY_INT_ENA = 0;
+ SPI_DMA_INT_ENA_REG.SPI_OUTLINK_DSCR_ERROR_INT_ENA = 0;
+ SPI_DMA_INT_ENA_REG.SPI_INLINK_DSCR_ERROR_INT_ENA = 0;
+ SPI_DMA_INT_ENA_REG.SPI_IN_DONE_INT_ENA = 0;
+ SPI_DMA_INT_ENA_REG.SPI_IN_ERR_EOF_INT_ENA = 0;
+ SPI_DMA_INT_ENA_REG.SPI_IN_SUC_EOF_INT_ENA = 0;
+ SPI_DMA_INT_ENA_REG.SPI_OUT_DONE_INT_ENA = 0;
+ SPI_DMA_INT_ENA_REG.SPI_OUT_EOF_INT_ENA = 0;
+ SPI_DMA_INT_ENA_REG.SPI_OUT_TOTAL_EOF_INT_ENA = 0;
+ SPI_DMA_INT_ENA_REG.reserved1 = 0;
+ dwrite(SPI.SPI_DMA_INT_ENA_REG, SPI_DMA_INT_ENA_REG);
+
+ SPI.SPI_DMA_INT_RAW_REG.reserved1 = 0;
+
+ SPI.SPI_DMA_INT_ST_REG.reserved1 = 0;
+
+ SPI.SPI_DMA_RSTATUS_REG.reserved1 = 0;
+ SPI.SPI_DMA_TSTATUS_REG.reserved1 = 0;
+}
+
+#ifdef HAL_SPI_SUPPORTS_ASYNC
+
+struct spi_async_process_t {
+ volatile spi_dev_t *current_spibus;
+ const void *current_buffer;
+ size_t curoff_bytes;
+ size_t txlen;
+ uint8_t txunitsize;
+ void (*completeCallback)(void*);
+ void *complete_ud;
+ bool is_active = false;
+};
+static volatile spi_async_process_t _current_spi_proc;
+
+#ifdef HALSPI_ESP32_ENABLE_INTERNBUS
+static intr_handle_t _spi0_interrupt;
+static intr_handle_t _spi1_interrupt;
+#endif
+static intr_handle_t _spi2_interrupt;
+static intr_handle_t _spi3_interrupt;
+
+#ifdef HALSPI_DEBUG
+static int _cpu_core_id = -1;
+#endif
+
+static void IRAM_ATTR spi_async_fill_buffer(volatile spi_async_process_t& proc) {
+#ifdef HALSPI_DEBUG
+ if (_cpu_core_id == -1)
+ _cpu_core_id = xPortGetCoreID();
+ else if (_cpu_core_id != xPortGetCoreID())
+ _spi_on_error(13);
+#endif
+
+ auto& SPI = *proc.current_spibus;
+
+ bool has_prepared_spibus = false;
+ uint16_t writecnt_bytes = 0;
+
+ if (proc.txunitsize == 1) {
+ SPIWriteDataToTransferIsolated(SPI, (const uint8_t*)proc.current_buffer, proc.txlen, proc.curoff_bytes, writecnt_bytes);
+ has_prepared_spibus = true;
+ }
+ else if (proc.txunitsize == 2) {
+ SPIWriteDataToTransferIsolated(SPI, (const uint16_t*)proc.current_buffer, proc.txlen, proc.curoff_bytes, writecnt_bytes);
+ has_prepared_spibus = true;
+ }
+ else if (proc.txunitsize == 4) {
+ SPIWriteDataToTransferIsolated(SPI, (const uint32_t*)proc.current_buffer, proc.txlen, proc.curoff_bytes, writecnt_bytes);
+ has_prepared_spibus = true;
+ }
+
+ if (has_prepared_spibus == false || writecnt_bytes == 0) {
+ #ifdef HALSPI_DEBUG
+ if (proc.curoff_bytes < proc.txlen * proc.txunitsize)
+ _spi_on_error(12);
+ #endif
+
+ // Disable the interrupt.
+ SPI.SPI_SLAVE_REG.SPI_TRANS_INTEN = false;
+
+ auto cb = proc.completeCallback;
+ auto ud = proc.complete_ud;
+
+ proc.current_spibus = nullptr;
+ proc.current_buffer = nullptr;
+ proc.curoff_bytes = 0;
+ proc.txlen = 0;
+ proc.txunitsize = 0;
+ proc.completeCallback = nullptr;
+ proc.complete_ud = nullptr;
+ proc.is_active = false;
+
+ // Call any completion handler, if provided by the user.
+ if (cb) cb(ud);
+ }
+ else {
+ proc.curoff_bytes += writecnt_bytes;
+
+ uint32_t txcount_bits = ( writecnt_bytes * 8 );
+
+ if (SPI.SPI_USER_REG.SPI_USR_MOSI == true)
+ SPI.SPI_MOSI_DLEN_REG.SPI_USR_MOSI_DBITLEN = txcount_bits - 1;
+
+ if (SPI.SPI_USER_REG.SPI_USR_MISO == true)
+ SPI.SPI_MISO_DLEN_REG.SPI_USR_MISO_DBITLEN = txcount_bits - 1;
+
+ // Kick-off another async SPI transfer.
+ SPI.SPI_CMD_REG.SPI_USR = true;
+ }
+}
+
+static void IRAM_ATTR spi_async_process_isr(void *ud, uint32_t spibusIdx) {
+ auto& SPI = SPIGetBusFromIndex(spibusIdx);
+
+ // Check the type of the triggered interrupt.
+ if (SPI.SPI_SLAVE_REG.SPI_TRANS_DONE) {
+ // Clear the interrupt.
+ SPI.SPI_SLAVE_REG.SPI_TRANS_DONE = false;
+
+ auto& proc = _current_spi_proc;
+
+ if (proc.is_active && proc.current_spibus == &SPI) {
+ // Is the SPI bus ready? Otherwise we could have a spurious interrupt call.
+ if (SPI.SPI_CMD_REG.SPI_USR == false) {
+ spi_async_fill_buffer(proc);
+ }
+ }
+ }
+}
+
+#ifdef HALSPI_ESP32_ENABLE_INTERNBUS
+static void IRAM_ATTR spi_async_process_isr_spibus0(void *ud) {
+ spi_async_process_isr(ud, 0);
+}
+static void IRAM_ATTR spi_async_process_isr_spibus1(void *ud) {
+ spi_async_process_isr(ud, 1);
+}
+#endif
+static void IRAM_ATTR spi_async_process_isr_spibus2(void *ud) {
+ spi_async_process_isr(ud, 2);
+}
+static void IRAM_ATTR spi_async_process_isr_spibus3(void *ud) {
+ spi_async_process_isr(ud, 3);
+}
+
+static void SPIInstallAsync(volatile spi_dev_t& SPI, intr_handle_t& handleOut) {
+ int intsrc = -1;
+ void (*inthandler)(void*) = nullptr;
+
+#ifdef HALSPI_ESP32_ENABLE_INTERNBUS
+ if (&SPI == &SPI0) {
+ intsrc = ETS_SPI0_INTR_SOURCE;
+ inthandler = spi_async_process_isr_spibus0;
+ }
+ else if (&SPI == &SPI1) {
+ intsrc = ETS_SPI1_INTR_SOURCE;
+ inthandler = spi_async_process_isr_spibus1;
+ }
+ else
+#endif
+ if (&SPI == &SPI2) {
+ intsrc = ETS_SPI2_INTR_SOURCE;
+ inthandler = spi_async_process_isr_spibus2;
+ }
+ else if (&SPI == &SPI3) {
+ intsrc = ETS_SPI3_INTR_SOURCE;
+ inthandler = spi_async_process_isr_spibus3;
+ }
+ else
+ _spi_on_error(1);
+
+ esp_err_t err = esp_intr_alloc(intsrc, 0 /*ESP_INTR_FLAG_IRAM*/, inthandler, nullptr, &handleOut);
+
+ if (err != ESP_OK)
+ _spi_on_error(1);
+}
+
+static void __attribute__((unused)) SPIUninstallAsync(intr_handle_t handle) {
+ // Unregister the ISR.
+ esp_err_t err = esp_intr_free(handle);
+
+ if (err != ESP_OK)
+ _spi_on_error(2);
+}
+
+static void SPIAsyncInitialize() {
+ #ifdef HALSPI_ESP32_ENABLE_INTERNBUS
+ SPIInstallAsync(SPI0, _spi0_interrupt);
+ SPIInstallAsync(SPI1, _spi1_interrupt);
+ #endif
+ SPIInstallAsync(SPI2, _spi2_interrupt);
+ SPIInstallAsync(SPI3, _spi3_interrupt);
+}
+
+static void SPIStartRawAsync(volatile spi_dev_t& SPI, const void *buf, uint32_t txlen, uint8_t txunitsize, void (*completeCallback)(void*), void *ud) {
+ auto& proc = _current_spi_proc;
+
+ spi_monitored_loop asyncw;
+ while (proc.is_active) { asyncw.update(2); /* wait for any async process to conclude before we start another */ }
+
+ cli();
+
+ proc.current_spibus = &SPI;
+ proc.current_buffer = buf;
+ proc.curoff_bytes = 0;
+ proc.txlen = txlen;
+ proc.txunitsize = txunitsize;
+ proc.completeCallback = completeCallback;
+ proc.complete_ud = ud;
+ proc.is_active = true;
+
+ sei();
+
+ // Enable the interrupt (make sure that we do not trigger it over here already).
+ SPI.SPI_SLAVE_REG.SPI_TRANS_DONE = false;
+ SPI.SPI_SLAVE_REG.SPI_TRANS_INTEN = true;
+
+ // Kick it off.
+ spi_async_fill_buffer(proc);
+}
+
+static void SPIAbortRawAsync() {
+ cli();
+
+ auto& proc = _current_spi_proc;
+
+ if (proc.is_active) {
+ proc.is_active = false;
+
+ auto& SPI = *proc.current_spibus;
+
+ SPI.SPI_SLAVE_REG.SPI_TRANS_INTEN = false;
+ SPI.SPI_SLAVE_REG.SPI_TRANS_DONE = false;
+ }
+
+ sei();
+}
+
+#endif // HAL_SPI_SUPPORTS_ASYNC
+
+#ifndef HALSPI_DISABLE_DMA
+
+#define SPIDMA_OWNER_CPU 0
+#define SPIDMA_OWNER_DMAC 1
+
+// Has to be allocated inside the DMA-accessible memory range.
+// page 113 of ESP32 TRM.
+struct dma_descriptor_t {
+ // Configuration bits.
+ uint32_t size : 12;
+ uint32_t length : 12;
+ uint32_t reserved : 5;
+ uint32_t sosf : 1; // start-of-sub-frame (undocumented)
+ uint32_t eof : 1;
+ uint32_t owner : 1;
+
+ void *address;
+ volatile dma_descriptor_t *next;
+};
+static_assert(sizeof(dma_descriptor_t) == 12, "invalid size of ESP32 dma_descriptor_t");
+
+#ifndef HALSPI_ESP32_DMADESC_COUNT
+ // The default count of DMA descriptors usable.
+ #define HALSPI_ESP32_DMADESC_COUNT 1
+#endif
+
+#ifdef HALSPI_ESP32_STATIC_DMADESCS
+static volatile dma_descriptor_t _usable_dma_descs_static[HALSPI_ESP32_DMADESC_COUNT];
+#else
+static volatile dma_descriptor_t *_usable_dma_descs_dynamic = nullptr;
+static uint32_t _usable_dma_descs_count = 0;
+#endif
+
+// Specifies the valid memory range for DMA descriptors (not specified if necessary for DMA buffers).
+
+// For ESP32 basic.
+#define ESP32_DMADESC_HWPTR(ptr) ((uint32_t)ptr - 0x3FF00000)
+
+inline bool DMAIsValidPointer(volatile const void *ptr) noexcept {
+ size_t addr = (size_t)ptr;
+
+ return ( addr >= SOC_DMA_LOW && addr <= SOC_DMA_HIGH );
+}
+
+inline bool DMAIsValidDescriptor(volatile dma_descriptor_t *desc) noexcept {
+ return DMAIsValidPointer(desc);
+}
+
+inline void DMAInitializeMachine() {
+ #ifdef HALSPI_ESP32_STATIC_DMADESCS
+ for (auto& desc : _usable_dma_descs_static) {
+ if (DMAIsValidDescriptor(&desc) == false) {
+ _spi_on_error(3);
+ }
+ desc.owner = SPIDMA_OWNER_CPU;
+ desc.reserved = 0;
+ desc.sosf = false;
+ }
+ #else
+ void *dmabuf = heap_caps_malloc( sizeof(dma_descriptor_t)*HALSPI_ESP32_DMADESC_COUNT, MALLOC_CAP_DMA );
+ if (dmabuf == nullptr)
+ _spi_on_error(3);
+ _usable_dma_descs_dynamic = (volatile dma_descriptor_t*)dmabuf;
+ _usable_dma_descs_count = HALSPI_ESP32_DMADESC_COUNT;
+ if (DMAIsValidDescriptor(_usable_dma_descs_dynamic) == false)
+ _spi_on_error(3);
+ for (uint32_t n = 0; n < _usable_dma_descs_count; n++) {
+ auto& desc = _usable_dma_descs_dynamic[n];
+
+ desc.owner = SPIDMA_OWNER_CPU;
+ desc.reserved = 0;
+ desc.sosf = false;
+ }
+ #endif
+}
+
+/* Important restriction on DMA-usable memory addresses and their buffer sizes:
+ Please note that the buffer address pointer field in in_link descriptors should be word-aligned, and the size field (...).
+ -> each DMA-depending Marlin operation will need to use a special memory allocation function that ensures DMA-capability!
+ -> each DMA-internal memory buffer accepting function has to deny the buffer if it does not match
+ the requirements!
+*/
+inline bool DMAIsValidWriteDataBuffer(const void *buf, size_t bufsz) noexcept {
+ if (DMAIsValidPointer(buf) == false) return false;
+
+ size_t bufaddr = (size_t)buf;
+
+ if (bufaddr % sizeof(uint32_t) != 0) return false;
+ if (bufsz % sizeof(uint32_t) != 0) return false;
+
+ return true;
+}
+
+inline bool DMAIsValidReadDataBuffer(const void *buf) noexcept {
+ if (DMAIsValidPointer(buf) == false) return false;
+
+ size_t bufaddr = (size_t)buf;
+
+ if (bufaddr % sizeof(uint32_t) != 0) return false;
+
+ return true;
+}
+
+// Not every SPI bus is DMA-capable.
+inline bool DMAIsCapableSPIBus(volatile spi_dev_t& SPI) {
+#ifdef HALSPI_ENABLE_INTERNBUS
+ if (&SPI == &SPI1) return true;
+#endif
+ if (&SPI == &SPI2) return true;
+ if (&SPI == &SPI3) return true;
+ return false;
+}
+
+struct dma_process_t {
+ const void *current_buffer;
+ size_t bufsize;
+ size_t txlen;
+ size_t curoff;
+ bool is_active;
+};
+
+static volatile dma_process_t dma_current_process;
+
+static void DMABusInitialize(volatile spi_dev_t& SPI) {
+ #ifdef HALSPI_DEBUG
+ if (DMAIsCapableSPIBus(SPI) == false)
+ _spi_on_error(4);
+ #endif
+
+ // Reset and enable the SPI DMA clock.
+ DPORT_PERIP_RST_EN_REG.DPORT_SPI_DMA_RST = true;
+ DPORT_PERIP_RST_EN_REG.DPORT_SPI_DMA_RST = false;
+ DPORT_PERIP_CLK_EN_REG.DPORT_SPI_DMA_CLK_EN = true;
+
+ // Select the SPI DMA channel.
+ auto spibusIdx = SPIGetBusIndex(SPI);
+
+ unsigned int dma_chansel = (
+ #ifdef HALSPI_ESP32_DMA_SELECT_CHAN1
+ DPORT_SPI_DMA_CHAN_SEL_CHAN1
+ #elif defined(HALSPI_ESP32_DMA_SELECT_CHAN2)
+ DPORT_SPI_DMA_CHAN_SEL_CHAN2
+ #else
+ DPORT_SPI_DMA_CHAN_SEL_CHAN1
+ #endif
+ );
+ switch (spibusIdx) {
+ #ifdef HALSPI_ESP32_ENABLE_INTERNBUS
+ case 1: DPORT_SPI_DMA_CHAN_SEL_REG.DPORT_SPI_SPI1_DMA_CHAN_SEL = dma_chansel; break;
+ #endif
+ case 2: DPORT_SPI_DMA_CHAN_SEL_REG.DPORT_SPI_SPI2_DMA_CHAN_SEL = dma_chansel; break;
+ case 3: DPORT_SPI_DMA_CHAN_SEL_REG.DPORT_SPI_SPI3_DMA_CHAN_SEL = dma_chansel; break;
+ }
+}
+
+static void DMABusShutdown(volatile spi_dev_t& SPI) {
+ // Unselect the SPI DMA channel.
+ switch (SPIGetBusIndex(SPI)) {
+ #ifdef HALSPI_ESP32_ENABLE_INTERNBUS
+ case 1: DPORT_SPI_DMA_CHAN_SEL_REG.DPORT_SPI_SPI1_DMA_CHAN_SEL = DPORT_SPI_DMA_CHAN_SEL_NONE; break;
+ #endif
+ case 2: DPORT_SPI_DMA_CHAN_SEL_REG.DPORT_SPI_SPI2_DMA_CHAN_SEL = DPORT_SPI_DMA_CHAN_SEL_NONE; break;
+ case 3: DPORT_SPI_DMA_CHAN_SEL_REG.DPORT_SPI_SPI3_DMA_CHAN_SEL = DPORT_SPI_DMA_CHAN_SEL_NONE; break;
+ }
+
+ // Disable the SPI DMA clock.
+ DPORT_PERIP_CLK_EN_REG.DPORT_SPI_DMA_CLK_EN = false;
+}
+
+// TODO: manage list of free descriptors to speed up the process of generating a DMA chain.
+
+static volatile dma_descriptor_t* DMAGetFreeDescriptor() noexcept {
+ #ifdef HALSPI_ESP32_STATIC_DMADESCS
+ for (auto& desc : _usable_dma_descs_static) {
+ #else
+ for (uint32_t _n = 0; _n < _usable_dma_descs_count; _n++) {
+ auto& desc = _usable_dma_descs_dynamic[_n];
+ #endif
+ if (desc.owner == SPIDMA_OWNER_CPU) {
+ #ifdef HALSPI_DEBUG
+ if (DMAIsValidDescriptor(&desc) == false) _spi_on_error(5);
+ #endif
+ return &desc;
+ }
+ }
+ return nullptr;
+}
+
+static volatile dma_descriptor_t* DMAGenerateAcquireChain(volatile dma_process_t& proc) noexcept {
+ volatile dma_descriptor_t *startdesc = nullptr;
+ volatile dma_descriptor_t *chainend = nullptr;
+
+ while (proc.curoff < proc.txlen) {
+ volatile dma_descriptor_t *freedesc = DMAGetFreeDescriptor();
+
+ if (freedesc == nullptr) break;
+
+ size_t left_to_transmit = (proc.txlen - proc.curoff);
+ uint32_t txcount = eir::Minimum((1u<<12u)-4u, left_to_transmit);
+ uint32_t txbufsz = ALIGN_SIZE(txcount, (uint32_t)4u);
+
+ freedesc->size = txbufsz;
+ freedesc->length = txcount;
+ freedesc->address = ((uint8_t*)proc.current_buffer + proc.curoff);
+
+ // Advance the process.
+ proc.curoff += txcount;
+
+ // Give ownership of the descriptor to the DMA controller.
+ // (this decision turns valid as soon as the DMAC is kicked-off!)
+ freedesc->owner = SPIDMA_OWNER_DMAC;
+
+ if (chainend != nullptr) {
+ chainend->eof = false;
+ chainend->next = freedesc;
+ }
+ chainend = freedesc;
+
+ if (startdesc == nullptr) {
+ startdesc = freedesc;
+ }
+ }
+
+ if (chainend) {
+ chainend->eof = true;
+ chainend->next = nullptr;
+ }
+
+ return startdesc;
+}
+
+static void DMASendBlocking(volatile spi_dev_t& SPI, const void *buf, size_t bufsize, size_t txlen) {
+ DMABusInitialize(SPI);
+
+ // Reset the DMA state machine.
+ {
+ SPI.SPI_DMA_CONF_REG.SPI_OUT_RST = true;
+ SPI.SPI_DMA_CONF_REG.SPI_IN_RST = true;
+ SPI.SPI_DMA_CONF_REG.SPI_AHBM_RST = true;
+ SPI.SPI_DMA_CONF_REG.SPI_AHBM_FIFO_RST = true;
+
+ SPI.SPI_DMA_IN_LINK_REG.SPI_INLINK_START = false;
+ SPI.SPI_DMA_OUT_LINK_REG.SPI_OUTLINK_START = false;
+
+ SPI.SPI_DMA_CONF_REG.SPI_OUT_RST = false;
+ SPI.SPI_DMA_CONF_REG.SPI_IN_RST = false;
+ SPI.SPI_DMA_CONF_REG.SPI_AHBM_RST = false;
+ SPI.SPI_DMA_CONF_REG.SPI_AHBM_FIFO_RST = false;
+ }
+
+ // Configure DMA for the SPI bus.
+ spi_dma_conf_reg_t SPI_DMA_CONF_REG;
+ SPI_DMA_CONF_REG.SPI_DMA_CONTINUE = false;
+ SPI_DMA_CONF_REG.SPI_DMA_TX_STOP = false;
+ SPI_DMA_CONF_REG.SPI_DMA_RX_STOP = false;
+ SPI_DMA_CONF_REG.SPI_OUT_DATA_BURST_EN = false;
+ SPI_DMA_CONF_REG.SPI_INDSCR_BURST_EN = false;
+ SPI_DMA_CONF_REG.SPI_OUTDSCR_BURST_EN = false;
+ SPI_DMA_CONF_REG.SPI_OUT_EOF_MODE = 1;
+ SPI_DMA_CONF_REG.SPI_AHBM_RST = false;
+ SPI_DMA_CONF_REG.SPI_AHBM_FIFO_RST = false;
+ SPI_DMA_CONF_REG.SPI_OUT_RST = false;
+ SPI_DMA_CONF_REG.SPI_IN_RST = false;
+ SPI_DMA_CONF_REG.reserved1 = 0;
+ SPI_DMA_CONF_REG.reserved2 = 0;
+ SPI_DMA_CONF_REG.reserved3 = 0;
+ SPI_DMA_CONF_REG.reserved4 = 0;
+ dwrite(SPI.SPI_DMA_CONF_REG, SPI_DMA_CONF_REG);
+
+ auto& proc = dma_current_process;
+ proc.is_active = true;
+ proc.current_buffer = buf;
+ proc.bufsize = bufsize;
+ proc.txlen = txlen;
+ proc.curoff = 0;
+
+ #if 0
+ static volatile dma_descriptor_t _rxdesc;
+ _rxdesc.size = 0;
+ _rxdesc.length = 0;
+ _rxdesc.reserved = 0;
+ _rxdesc.sosf = false;
+ _rxdesc.eof = true;
+ _rxdesc.owner = SPIDMA_OWNER_DMAC;
+ _rxdesc.address = nullptr;
+ _rxdesc.next = nullptr;
+ {
+ // Workaround for SPI DMA hardware bug.
+ // (https://www.esp32.com/viewtopic.php?t=8433 spi_master.zip:spi_master.c:line 754)
+ // TODO: does it really matter???
+ spi_dma_in_link_reg_t SPI_DMA_IN_LINK_REG;
+ SPI_DMA_IN_LINK_REG.SPI_INLINK_ADDR = ESP32_DMADESC_HWPTR(&_rxdesc);
+ SPI_DMA_IN_LINK_REG.SPI_INLINK_AUTO_RET = false;
+ SPI_DMA_IN_LINK_REG.reserved1 = 0;
+ SPI_DMA_IN_LINK_REG.SPI_INLINK_STOP = false;
+ SPI_DMA_IN_LINK_REG.SPI_INLINK_START = true;
+ SPI_DMA_IN_LINK_REG.SPI_INLINK_RESTART = false;
+ SPI_DMA_IN_LINK_REG.reserved2 = 0;
+ dwrite(SPI.SPI_DMA_IN_LINK_REG, SPI_DMA_IN_LINK_REG);
+ }
+
+ SPI.SPI_USER_REG.SPI_USR_MISO = true;
+ SPI.SPI_USER_REG.SPI_USR_MOSI = true;
+ SPI.SPI_CTRL_REG.SPI_FASTRD_MODE = false;
+ SPI.SPI_CTRL_REG.reserved2 = 0;
+ SPI.SPI_CTRL2_REG.SPI_SETUP_TIME = 0;
+ SPI.SPI_CTRL2_REG.SPI_HOLD_TIME = 0;
+ SPI.SPI_USER1_REG.SPI_USR_DUMMY_CYCLELEN = 0;
+ SPI.SPI_USER1_REG.SPI_USR_ADDR_BITLEN = 0;
+ SPI.SPI_USER2_REG.SPI_USR_COMMAND_BITLEN = 0;
+ SPI.SPI_SLAVE1_REG.SPI_SLV_STATUS_READBACK = 0;
+ SPI.SPI_DMA_INT_CLR_REG.SPI_INLINK_DSCR_ERROR_INT_CLR = true;
+
+ SERIAL_ECHOLNPGM("RX CHAIN PTR: ", (uint32_t)&_rxdesc);
+ SERIAL_ECHOLNPGM("SOC_DMA: ", SOC_DMA_LOW, " to ", SOC_DMA_HIGH);
+
+ SPI.SPI_MOSI_DLEN_REG.SPI_USR_MOSI_DBITLEN = 0u;
+ SPI.SPI_MISO_DLEN_REG.SPI_USR_MISO_DBITLEN = 0u;
+ #endif
+
+ #if 0
+ // DUMP MACHINE STATE.
+ {
+ static bool _dumped = false;
+
+ if (_dumped == false) {
+ SPI.serial_dump();
+ _dumped = true;
+ }
+ }
+ #endif
+
+ //OUT_WRITE(BEEPER_PIN, HIGH);
+
+ // Is there data left to send?
+ while (proc.curoff < proc.txlen) {
+ // Generate a transfer chain.
+ volatile dma_descriptor_t *chain = DMAGenerateAcquireChain(proc);
+
+ if (chain == nullptr)
+ _spi_on_error(14);
+
+ //SERIAL_ECHOLNPGM("TX CHAIN PTR: ", (uint32_t)chain);
+ //SERIAL_ECHOLNPGM("CHAIN TXCNT: ", chain->length);
+ //SERIAL_ECHOLNPGM("CHAIN SIZE: ", chain->size);
+
+ // Configure the transfer.
+ spi_dma_out_link_reg_t SPI_DMA_OUT_LINK_REG;
+ SPI_DMA_OUT_LINK_REG.SPI_OUTLINK_ADDR = ESP32_DMADESC_HWPTR(chain);//(int)chain & 0xFFFFF;
+ SPI_DMA_OUT_LINK_REG.reserved1 = 0;
+ SPI_DMA_OUT_LINK_REG.SPI_OUTLINK_STOP = false;
+ SPI_DMA_OUT_LINK_REG.SPI_OUTLINK_START = true; // cleared by hardware on TX termination.
+ SPI_DMA_OUT_LINK_REG.SPI_OUTLINK_RESTART = false;
+ SPI_DMA_OUT_LINK_REG.reserved2 = 0;
+ dwrite(SPI.SPI_DMA_OUT_LINK_REG, SPI_DMA_OUT_LINK_REG);
+
+ #if 0
+ SPI.SPI_DMA_IN_LINK_REG.SPI_INLINK_ADDR = ESP32_DMADESC_HWPTR(chain); // ???
+ SPI.SPI_DMA_IN_LINK_REG.SPI_INLINK_START = true;
+ #elif 0
+ {
+ // Workaround for SPI DMA hardware bug.
+ // (https://www.esp32.com/viewtopic.php?t=8433 spi_master.zip:spi_master.c:line 754)
+ // TODO: does it really matter???
+ spi_dma_in_link_reg_t SPI_DMA_IN_LINK_REG;
+ SPI_DMA_IN_LINK_REG.SPI_INLINK_ADDR = ESP32_DMADESC_HWPTR(chain);
+ SPI_DMA_IN_LINK_REG.SPI_INLINK_AUTO_RET = false;
+ SPI_DMA_IN_LINK_REG.reserved1 = 0;
+ SPI_DMA_IN_LINK_REG.SPI_INLINK_STOP = false;
+ SPI_DMA_IN_LINK_REG.SPI_INLINK_START = true;
+ SPI_DMA_IN_LINK_REG.SPI_INLINK_RESTART = false;
+ SPI_DMA_IN_LINK_REG.reserved2 = 0;
+ dwrite(SPI.SPI_DMA_IN_LINK_REG, SPI_DMA_IN_LINK_REG);
+ }
+ #endif
+
+ //SPI.SPI_DMA_RSTATUS_REG.serial_dump();
+ //SPI.SPI_DMA_TSTATUS_REG.serial_dump();
+
+ //SERIAL_ECHOLNPGM("CUR INLINK DESCR PTR: ", SPI.SPI_INLINK_DSCR_REG);
+ //SERIAL_ECHOLNPGM("CUR OUTLINK DESCR PTR: ", SPI.SPI_OUTLINK_DSCR_REG);
+ //SERIAL_ECHOLNPGM("AFTER WRITE: ", SPI.SPI_DMA_OUT_LINK_REG.SPI_OUTLINK_ADDR);
+ //SERIAL_ECHOLNPGM("TX DMA STATUS (kickoff): ", SPI.SPI_DMA_STATUS_REG.SPI_DMA_TX_EN);
+ //SERIAL_ECHOLNPGM("RX DMA STATUS (kickoff): ", SPI.SPI_DMA_STATUS_REG.SPI_DMA_RX_EN);
+
+ //SERIAL_ECHOLNPGM("SPI STATE MACHINE ST (kickoff): ", SPI.SPI_EXT2_REG.SPI_ST);
+
+ // Kick it off.
+ SPI.SPI_CMD_REG.SPI_USR = true;
+
+ /* wait until DMA transfer has finished */
+ spi_monitored_loop usrw;
+ #if 0
+ while (SPI.SPI_DMA_RSTATUS_REG.TX_FIFO_EMPTY == false) {
+ usrw.update(3);
+ }
+ #endif
+ while (SPI.SPI_DMA_STATUS_REG.SPI_DMA_TX_EN) usrw.update(3);
+ while (SPI.SPI_CMD_REG.SPI_USR) usrw.update(3);
+
+ #if 0
+ if (SPI.SPI_DMA_INT_RAW_REG.SPI_OUTLINK_DSCR_ERROR_INT_RAW) {
+ _spi_on_error(20);
+ }
+ if (SPI.SPI_DMA_INT_RAW_REG.SPI_INLINK_DSCR_ERROR_INT_RAW) {
+ //_spi_on_error(21);
+ SPI.SPI_DMA_INT_CLR_REG.SPI_INLINK_DSCR_ERROR_INT_CLR = true;
+ }
+ if (SPI.SPI_DMA_INT_RAW_REG.SPI_IN_ERR_EOF_INT_RAW) {
+ _spi_on_error(22);
+ }
+ if (SPI.SPI_DMA_INT_RAW_REG.SPI_INLINK_DSCR_EMPTY_INT_RAW) {
+ _spi_on_error(23);
+ }
+ #endif
+
+ //SERIAL_ECHOLNPGM("CHAIN LENGTH (after tx): ", chain->length);
+
+ // Free the DMA chain back to CPU ownership, since that is unfortunately NOT done by hardware!
+ while (chain) {
+ chain->owner = SPIDMA_OWNER_CPU;
+ chain = chain->next;
+ }
+ }
+
+ //SERIAL_ECHOLNPGM("AFTER OP: ", SPI.SPI_DMA_OUT_LINK_REG.SPI_OUTLINK_ADDR);
+ //SERIAL_ECHOLNPGM("RSTATUS ADDR: ", SPI.SPI_DMA_RSTATUS_REG.TX_DES_ADDRESS);
+ //SERIAL_ECHOLNPGM("RSTATUS FIFO EMPTY: ", SPI.SPI_DMA_RSTATUS_REG.TX_FIFO_EMPTY);
+ //SERIAL_ECHOLNPGM("RSTATUS FIFO FULL: ", SPI.SPI_DMA_RSTATUS_REG.TX_FIFO_FULL);
+ //SERIAL_ECHOLNPGM("TX DMA STATUS (finish): ", SPI.SPI_DMA_STATUS_REG.SPI_DMA_TX_EN);
+ //SERIAL_ECHOLNPGM("RX DMA STATUS (finish): ", SPI.SPI_DMA_STATUS_REG.SPI_DMA_RX_EN);
+ ////SERIAL_ECHOLNPGM("SPI STATE MACHINE ST (finish): ", SPI.SPI_EXT2_REG.SPI_ST);
+ //SERIAL_ECHOLNPGM("TX COUNT: ", SPI.SPI_DMA_STATUS_REG.reserved1);
+
+ //OUT_WRITE(BEEPER_PIN, LOW);
+
+ proc.is_active = false;
+
+ DMABusShutdown(SPI);
+}
+
+#endif // HALSPI_DISABLE_DMA
+
+} // namespace MarlinESP32
+
+static void _spiAsyncBarrier() {
+#ifdef HAL_SPI_SUPPORTS_ASYNC
+ spi_monitored_loop asyncw;
+ while (MarlinESP32::_current_spi_proc.is_active) { asyncw.update(4); /* wait until any async-SPI process has finished */ }
+#endif
+}
+
+static MarlinESP32::gpioMapResult_t _spi_gpiomap;
+static volatile bool _spi_is_active = false;
+static volatile bool _spi_transaction_is_running = false;
+static MarlinESP32::clkcnt_res_t _spi_clkcnt;
+#ifdef HALSPI_DEBUG
+static int _spi_core_id;
+#endif
+
+void spiBegin() {
+#ifdef HALSPI_DEBUG
+ _spi_core_id = xPortGetCoreID();
+#endif
+
+#ifdef HAL_SPI_SUPPORTS_ASYNC
+ MarlinESP32::SPIAsyncInitialize();
+#endif
+
+#ifndef HALSPI_DISABLE_DMA
+ // Security checks.
+ MarlinESP32::DMAInitializeMachine();
+#endif
+
+ #if ENABLED(SDSUPPORT) && PIN_EXISTS(SD_SS)
+ OUT_WRITE(SD_SS_PIN, HIGH);
+ #endif
+
+ // By default disable the clock signals.
+#ifdef HALSPI_ESP32_ENABLE_INTERNBUS
+ // SPI0/1 are used for instruction-flash-memory access so it is not a good idea
+ // to use them in Marlin!
+ MarlinESP32::DPORT_PERIP_CLK_EN_REG.DPORT_SPI01_CLK_EN = false;
+#endif
+ MarlinESP32::DPORT_PERIP_CLK_EN_REG.DPORT_SPI2_CLK_EN = false;
+ MarlinESP32::DPORT_PERIP_CLK_EN_REG.DPORT_SPI3_CLK_EN = false;
+#if !defined(HALSPI_DISABLE_DMA)
+ MarlinESP32::DPORT_PERIP_CLK_EN_REG.DPORT_SPI_DMA_CLK_EN = false;
+#endif
+
+ // Reset DMA channel selections.
+#ifdef HALSPI_ESP32_ENABLE_INTERNBUS
+ MarlinESP32::DPORT_SPI_DMA_CHAN_SEL_REG.DPORT_SPI_SPI1_DMA_CHAN_SEL = DPORT_SPI_DMA_CHAN_SEL_NONE;
+#endif
+ MarlinESP32::DPORT_SPI_DMA_CHAN_SEL_REG.DPORT_SPI_SPI2_DMA_CHAN_SEL = DPORT_SPI_DMA_CHAN_SEL_NONE;
+ MarlinESP32::DPORT_SPI_DMA_CHAN_SEL_REG.DPORT_SPI_SPI3_DMA_CHAN_SEL = DPORT_SPI_DMA_CHAN_SEL_NONE;
+
+#ifdef HALSPI_ESP32_ENABLE_INTERNBUS
+ MarlinESP32::SPIResetBus(MarlinESP32::SPI0);
+ MarlinESP32::SPIResetBus(MarlinESP32::SPI1);
+#endif
+ MarlinESP32::SPIResetBus(MarlinESP32::SPI2);
+ MarlinESP32::SPIResetBus(MarlinESP32::SPI3);
+}
+
+void spiSetupChipSelect(int pin) {
+ OUT_WRITE(pin, HIGH);
+}
+
+void spiInitEx(uint32_t maxClockFreq, int hint_sck, int hint_miso, int hint_mosi, int hint_cs) {
+#ifdef HALSPI_DEBUG
+ if (_spi_core_id != xPortGetCoreID())
+ _spi_on_error(10);
+#endif
+
+#ifdef HAL_SPI_SUPPORTS_ASYNC
+ spi_monitored_loop actw;
+ while (_spi_is_active) { actw.update(5); /* wait until any other transaction has finished */ }
+#else
+ if (_spi_is_active)
+ _spi_on_error(6);
+#endif
+
+ _spi_gpiomap = MarlinESP32::SPIMapGPIO(hint_sck, hint_miso, hint_mosi, hint_cs);
+ _spi_is_active = true;
+
+ uint8_t spibusIdx = _spi_gpiomap.spibusIdx;
+
+ auto& SPI = MarlinESP32::SPIGetBusFromIndex(spibusIdx);
+
+ // Enable the clock signal and reset the peripheral.
+#ifdef HALSPI_ESP32_ENABLE_INTERNBUS
+ if (spibusIdx == 0 || spibusIdx == 1) {
+ MarlinESP32::DPORT_PERIP_RST_EN_REG.DPORT_SPI01_RST = true;
+ MarlinESP32::DPORT_PERIP_RST_EN_REG.DPORT_SPI01_RST = false;
+ MarlinESP32::DPORT_PERIP_CLK_EN_REG.DPORT_SPI01_CLK_EN = true;
+ }
+ else
+#endif
+ if (spibusIdx == 2) {
+ MarlinESP32::DPORT_PERIP_RST_EN_REG.DPORT_SPI2_RST = true;
+ MarlinESP32::DPORT_PERIP_RST_EN_REG.DPORT_SPI2_RST = false;
+ MarlinESP32::DPORT_PERIP_CLK_EN_REG.DPORT_SPI2_CLK_EN = true;
+ }
+ else if (spibusIdx == 3) {
+ MarlinESP32::DPORT_PERIP_RST_EN_REG.DPORT_SPI3_RST = true;
+ MarlinESP32::DPORT_PERIP_RST_EN_REG.DPORT_SPI3_RST = false;
+ MarlinESP32::DPORT_PERIP_CLK_EN_REG.DPORT_SPI3_CLK_EN = true;
+ }
+
+ // By default we transfer using MSB.
+ MarlinESP32::SPIConfigureBitOrder(SPI, SPI_BITORDER_MSB);
+
+ // Chapter 7.4.2 is relevant for the direct-IO/IOMUX timing optimization.
+ uint32_t apbfreq = getApbFrequency(); // from Arduino SDK, depends on undocumented things.
+ MarlinESP32::clkcnt_res_t clkdiv = MarlinESP32::SPIApproximateClockDivider(maxClockFreq, apbfreq);
+
+ _spi_clkcnt = clkdiv;
+
+ // Set basic SPI configuration.
+ SPI.SPI_SLAVE_REG.SPI_SLAVE_MODE = 0; // master.
+
+ // Enable the required SPI phases.
+ SPI.SPI_USER_REG.SPI_USR_COMMAND = false;
+ SPI.SPI_USER_REG.SPI_USR_ADDR = false;
+ SPI.SPI_USER_REG.SPI_USR_DUMMY = false;
+ SPI.SPI_USER_REG.SPI_USR_DUMMY_IDLE = false;
+ SPI.SPI_USER_REG.SPI_SIO = false;
+ SPI.SPI_USER_REG.SPI_USR_MOSI = (_spi_gpiomap.gpio_mosi >= 0);
+ SPI.SPI_USER_REG.SPI_USR_MISO = (_spi_gpiomap.gpio_miso >= 0);
+
+#ifdef HAL_SPI_SUPPORTS_ASYNC
+ // Clear important interrupt settings.
+ SPI.SPI_SLAVE_REG.SPI_TRANS_INTEN = false;
+ SPI.SPI_SLAVE_REG.SPI_SLV_WR_STA_INTEN = false;
+ SPI.SPI_SLAVE_REG.SPI_SLV_RD_STA_INTEN = false;
+ SPI.SPI_SLAVE_REG.SPI_SLV_RD_BUF_INTEN = false;
+ SPI.SPI_SLAVE_REG.SPI_SLV_WR_BUF_INTEN = false;
+#endif
+
+ // Configure the SPI clock to MODE0 by default.
+ MarlinESP32::SPIConfigureClock(SPI, SPI_CLKMODE_0, _spi_gpiomap.datasig_is_direct_iomux, clkdiv);
+
+ // Enable full-duplex communication (4lines R/W)
+ SPI.SPI_USER_REG.SPI_DOUTDIN = true;
+ // On ESP32 the input and output buffers of SPI are always being randomly overwritten/trashed.
+ // Thus it makes little sense to divide them! Purpose of half-half division is performance
+ // optimization using fill-while-writing.
+ // Notes:
+ // "If the data length is over 64 bytes, the extra part will be written from SPI_W0_REG."
+ // - page 120 of ESP32 technical reference manual.
+ // The buffer on the HIGHPART is limited to the HIGHPART.
+ SPI.SPI_USER_REG.SPI_USR_MOSI_HIGHPART = false;
+ SPI.SPI_USER_REG.SPI_USR_MISO_HIGHPART = false;
+
+ // Disable any hardware-chip-select.
+ SPI.SPI_PIN_REG.SPI_CS0_DIS = true;
+ SPI.SPI_PIN_REG.SPI_CS1_DIS = true;
+ SPI.SPI_PIN_REG.SPI_CS2_DIS = true;
+
+ _spi_transaction_is_running = false;
+}
+
+static void _maybe_start_transaction() {
+ if (_spi_transaction_is_running) return;
+ if (_spi_gpiomap.gpio_cs >= 0) {
+ OUT_WRITE(_spi_gpiomap.gpio_cs, LOW);
+ }
+ _spi_transaction_is_running = true;
+}
+
+void spiInit(uint8_t spiRate, int hint_sck, int hint_miso, int hint_mosi, int hint_cs) {
+ uint32_t clock;
+
+ switch (spiRate) {
+ case SPI_FULL_SPEED: clock = 16000000; break;
+ case SPI_HALF_SPEED: clock = 8000000; break;
+ case SPI_QUARTER_SPEED: clock = 4000000; break;
+ case SPI_EIGHTH_SPEED: clock = 2000000; break;
+ case SPI_SIXTEENTH_SPEED: clock = 1000000; break;
+ case SPI_SPEED_5: clock = 500000; break;
+ case SPI_SPEED_6: clock = 250000; break;
+ default: clock = 1000000; // Default from the SPI library
+ }
+ spiInitEx(clock, hint_sck, hint_miso, hint_mosi, hint_cs);
+}
+
+void spiClose() {
+ _spiAsyncBarrier();
+
+ if (_spi_is_active == false)
+ _spi_on_error(7);
+
+ if (_spi_transaction_is_running) {
+ if (_spi_gpiomap.gpio_cs >= 0) {
+ OUT_WRITE(_spi_gpiomap.gpio_cs, HIGH);
+ }
+ _spi_transaction_is_running = false;
+ }
+
+ // Disable the clock signal.
+ uint8_t spibusIdx = _spi_gpiomap.spibusIdx;
+
+#ifdef HALSPI_ESP32_ENABLE_INTERNBUS
+ if (spibusIdx == 0 || spibusIdx == 1) {
+ MarlinESP32::DPORT_PERIP_CLK_EN_REG.DPORT_SPI01_CLK_EN = false;
+ }
+ else
+#endif
+ if (spibusIdx == 2) {
+ MarlinESP32::DPORT_PERIP_CLK_EN_REG.DPORT_SPI2_CLK_EN = false;
+ }
+ else if (spibusIdx == 3) {
+ MarlinESP32::DPORT_PERIP_CLK_EN_REG.DPORT_SPI3_CLK_EN = false;
+ }
+
+ MarlinESP32::SPIUnmapGPIO(_spi_gpiomap);
+
+ _spi_is_active = false;
+}
+
+void spiSetBitOrder(int bitOrder) {
+ _spiAsyncBarrier();
+
+ auto& SPI = MarlinESP32::SPIGetBusFromIndex(_spi_gpiomap.spibusIdx);
+
+ MarlinESP32::SPIConfigureBitOrder(SPI, bitOrder);
+}
+
+void spiSetClockMode(int mode) {
+ _spiAsyncBarrier();
+
+ auto& SPI = MarlinESP32::SPIGetBusFromIndex(_spi_gpiomap.spibusIdx);
+
+ MarlinESP32::SPIConfigureClock(SPI, mode, _spi_gpiomap.datasig_is_direct_iomux, _spi_clkcnt);
+}
+
+void spiEstablish() {
+ _maybe_start_transaction();
+}
+
+void spiSend(uint8_t txval) {
+ auto& SPI = MarlinESP32::SPIGetBusFromIndex(_spi_gpiomap.spibusIdx);
+
+ if (SPI.SPI_USER_REG.SPI_USR_MOSI == false) return;
+
+ _spiAsyncBarrier();
+
+ _maybe_start_transaction();
+
+ uint16_t start_num_idx = MarlinESP32::SPIGetWriteBufferStartIndex(SPI);
+
+ SPI.SPI_W_REG[start_num_idx] = txval;
+ MarlinESP32::SPITransaction(SPI, 1);
+}
+
+void spiSend16(uint16_t txval) {
+ auto& SPI = MarlinESP32::SPIGetBusFromIndex(_spi_gpiomap.spibusIdx);
+
+ if (SPI.SPI_USER_REG.SPI_USR_MOSI == false) return;
+
+ _spiAsyncBarrier();
+
+ _maybe_start_transaction();
+
+ eir::BitOrderingConverter bitconv(
+ ( SPI.SPI_CTRL_REG.SPI_WR_BIT_ORDER == _ESP32_BIT_ORDER_MSB ? endian::eSpecificEndian::BIG_ENDIAN : endian::eSpecificEndian::LITTLE_ENDIAN ),
+ false // already done by HW
+ );
+
+ uint16_t start_num_idx = MarlinESP32::SPIGetWriteBufferStartIndex(SPI);
+
+ SPI.SPI_W_REG[start_num_idx] = bitconv.Identity( txval );
+ MarlinESP32::SPITransaction(SPI, sizeof(uint16_t));
+}
+
+uint8_t spiRec(uint8_t txval) {
+ auto& SPI = MarlinESP32::SPIGetBusFromIndex(_spi_gpiomap.spibusIdx);
+
+ if (SPI.SPI_USER_REG.SPI_USR_MISO == false) return 0;
+
+ _spiAsyncBarrier();
+
+ _maybe_start_transaction();
+
+ if (SPI.SPI_USER_REG.SPI_USR_MOSI) {
+ uint16_t start_num_idx = MarlinESP32::SPIGetWriteBufferStartIndex(SPI);
+ SPI.SPI_W_REG[start_num_idx] = txval;
+ }
+
+ MarlinESP32::SPITransaction(SPI, sizeof(uint8_t));
+
+ uint16_t start_num_idx = MarlinESP32::SPIGetReadBufferStartIndex(SPI);
+
+ return (uint8_t)SPI.SPI_W_REG[start_num_idx];
+}
+
+uint16_t spiRec16(uint16_t txval) {
+ auto& SPI = MarlinESP32::SPIGetBusFromIndex(_spi_gpiomap.spibusIdx);
+
+ if (SPI.SPI_USER_REG.SPI_USR_MISO == false) return 0;
+
+ _spiAsyncBarrier();
+
+ _maybe_start_transaction();
+
+ eir::BitOrderingConverter bitconv(
+ ( SPI.SPI_CTRL_REG.SPI_RD_BIT_ORDER == _ESP32_BIT_ORDER_MSB ? endian::eSpecificEndian::BIG_ENDIAN : endian::eSpecificEndian::LITTLE_ENDIAN ),
+ false // already done by HW
+ );
+
+ if (SPI.SPI_USER_REG.SPI_USR_MOSI) {
+ uint16_t start_num_idx = MarlinESP32::SPIGetWriteBufferStartIndex(SPI);
+ SPI.SPI_W_REG[start_num_idx] = bitconv.Identity( txval );
+ }
+
+ MarlinESP32::SPITransaction(SPI, sizeof(uint16_t));
+
+ uint16_t start_num_idx = MarlinESP32::SPIGetReadBufferStartIndex(SPI);
+
+ uint16_t bits = (uint16_t)SPI.SPI_W_REG[start_num_idx];
+
+ return bitconv.Identity( bits );
+}
+
+void spiRead(uint8_t *buf, uint16_t cnt, uint8_t txval) {
+ if (cnt == 0) return;
+
+ auto& SPI = MarlinESP32::SPIGetBusFromIndex(_spi_gpiomap.spibusIdx);
+
+ if (SPI.SPI_USER_REG.SPI_USR_MISO == false) {
+ spiWriteRepeat(txval, cnt);
+ return;
+ }
+
+ _spiAsyncBarrier();
+
+ _maybe_start_transaction();
+
+#if 0
+#ifndef HALSPI_DISABLE_DMA
+ if (MarlinESP32::DMAIsCapableSPIBus(SPI) && MarlinESP32::DMAIsValidWriteDataBuffer(buf, cnt)
+#ifndef HALSPI_ESP32_DMA_ALWAYS
+ && cnt > MarlinESP32::SPIGetReadBufferSize(SPI)
+#endif
+ ) {
+ // For bigger transfers we should use DMA.
+ //TODO.
+ return;
+ }
+
+ // Use direct SPI for such small transfer sizes.
+#endif
+#endif
+ // The no-DMA version.
+
+ esp32BitManager recv_bitman( buf, cnt );
+
+ uint16_t start_num_idx = MarlinESP32::SPIGetReadBufferStartIndex(SPI);
+
+ esp32BitManager txbuf_bitman( &SPI.SPI_W_REG[start_num_idx], COUNT(SPI.SPI_W_REG) - start_num_idx );
+
+ using reptx_t = typename eir::biggest_type ::type;
+
+ eir::BitRepetitionCache repcache( txval );
+
+ bool is_write_avail = (SPI.SPI_USER_REG.SPI_USR_MOSI);
+
+ eir::BitManagerTemplates::Receive( recv_bitman, txbuf_bitman,
+ [&] ( const auto& bititer ) LAINLINE
+ {
+ if (is_write_avail) {
+ eir::BitNumberIteratorForStruct repiter;
+ txbuf_bitman.PutRepeatable( repcache.GetData(), repiter, repiter, bititer );
+ txbuf_bitman.Flush();
+ }
+ auto bytecnt = bititer.getTotalByteOffset();
+ MarlinESP32::SPITransaction(SPI, (uint32_t)bytecnt);
+ if (is_write_avail) {
+ txbuf_bitman.SetIterator({});
+ }
+ }
+ );
+}
+
+void spiSendBlock(uint8_t token, const uint8_t *buf) {
+ auto& SPI = MarlinESP32::SPIGetBusFromIndex(_spi_gpiomap.spibusIdx);
+
+ if (SPI.SPI_USER_REG.SPI_USR_MOSI == false) return;
+
+ _spiAsyncBarrier();
+
+ _maybe_start_transaction();
+
+#ifndef HALSPI_DISABLE_DMA
+ if (MarlinESP32::DMAIsCapableSPIBus(SPI) && MarlinESP32::DMAIsValidReadDataBuffer(buf)
+#ifndef HALSPI_ESP32_DMA_ALWAYS
+#ifdef HALSPI_DMA_THRESHOLD
+ && 512 > HALSPI_DMA_THRESHOLD
+#endif
+#endif
+ ) {
+ // Only attempt DMA transfer if the buffer is valid.
+ spiSend(token);
+ MarlinESP32::DMASendBlocking(SPI, buf, 512, 512);
+ return;
+ }
+
+ // Use direct SPI otherwise.
+#endif
+
+ uint16_t start_num_idx = MarlinESP32::SPIGetWriteBufferStartIndex(SPI);
+
+ esp32BitManager src_bitman( buf, 512 );
+
+ esp32BitManager buf_bitman( &SPI.SPI_W_REG[start_num_idx], COUNT(SPI.SPI_W_REG) - start_num_idx );
+
+ buf_bitman.Put( token );
+
+ eir::BitManagerTemplates::Send( src_bitman, buf_bitman,
+ [&] ( void ) LAINLINE
+ {
+ auto bytecnt = buf_bitman.GetIterator().getTotalByteOffset();
+ MarlinESP32::SPITransaction( SPI, (uint32_t)bytecnt );
+ }
+ );
+}
+
+void spiWrite(const uint8_t *buf, uint16_t cnt) {
+ if (cnt == 0) return;
+
+ auto& SPI = MarlinESP32::SPIGetBusFromIndex(_spi_gpiomap.spibusIdx);
+
+ if (SPI.SPI_USER_REG.SPI_USR_MOSI == false) return;
+
+ _spiAsyncBarrier();
+
+ _maybe_start_transaction();
+
+#ifndef HALSPI_DISABLE_DMA
+ if (MarlinESP32::DMAIsCapableSPIBus(SPI) && MarlinESP32::DMAIsValidReadDataBuffer(buf)
+#ifndef HALSPI_ESP32_DMA_ALWAYS
+#ifdef HALSPI_DMA_THRESHOLD
+ && cnt > HALSPI_DMA_THRESHOLD
+#else
+ && cnt > MarlinESP32::SPIGetWriteBufferSize(SPI)
+#endif //HALSPI_DMA_THRESHOLD
+#endif
+ ) {
+ // For bigger transfers we should use DMA.
+ MarlinESP32::DMASendBlocking(SPI, buf, ALIGN_SIZE(cnt, (uint16_t)4u), cnt);
+ return;
+ }
+
+ // Use direct SPI for small transfer sizes.
+#endif
+
+ uint16_t start_num_idx = MarlinESP32::SPIGetWriteBufferStartIndex(SPI);
+
+ esp32BitManager src_bitMan( buf, cnt );
+
+ eir::BitManagerTemplates::SendFixed( &SPI.SPI_W_REG[start_num_idx], COUNT(SPI.SPI_W_REG) - start_num_idx, src_bitMan,
+ [&] ( const auto& iter ) LAINLINE
+ {
+ MarlinESP32::SPITransaction( SPI, iter.getTotalByteOffset() );
+ }
+ );
+}
+
+void spiWrite16(const uint16_t *buf, uint16_t cnt) {
+ if (cnt == 0) return;
+
+ auto& SPI = MarlinESP32::SPIGetBusFromIndex(_spi_gpiomap.spibusIdx);
+
+ if (SPI.SPI_USER_REG.SPI_USR_MOSI == false) return;
+
+ _spiAsyncBarrier();
+
+ _maybe_start_transaction();
+
+ // Problem: before we can kick-off the DMA transfer to the SPI device we have to FORMAT THE ENTIRE DMA BUFFER to match
+ // the byte-by-byte requirement of the DMA-to-SPI-buffer filling! This is kind of a bummer because it means that DMA
+ // transfers of color buffers have to be filled in a special way, at best directly when they are created.
+ // Not only that but also the buffer needs to meet special allocation rules. Yikes!
+
+ // This would call for a special DMA-capable buffer filling structure/framework that is also part of the HAL and
+ // specialized per architecture.
+ // At least, ESP32 SPI is pretty fast as it currently stands, even without async DMA.
+
+ // LSBFIRST transfers can be pushed through the DMAC just fine because no bit-reversing/byte-swapping is necessary.
+
+#if 0
+#ifndef HALSPI_DISABLE_DMA
+ if (MarlinESP32::DMAIsCapableSPIBus(SPI) && MarlinESP32::DMAIsValidReadDataBuffer(buf) && cnt > MarlinESP32::SPIGetWriteBufferSize(SPI)) {
+ // For bigger transfers we should use DMA.
+ //TODO.
+ return;
+ }
+
+ // Use direct SPI for small transfer sizes.
+#endif
+#endif
+
+ uint16_t start_num_idx = MarlinESP32::SPIGetWriteBufferStartIndex(SPI);
+
+ esp32BitManager src_bitMan( buf, cnt );
+
+ MarlinESP32::SPIPrepareWriteBitManager( SPI, src_bitMan );
+
+ eir::BitManagerTemplates::SendFixed( &SPI.SPI_W_REG[start_num_idx], COUNT(SPI.SPI_W_REG) - start_num_idx, src_bitMan,
+ [&] ( const auto& iter ) LAINLINE
+ {
+ MarlinESP32::SPITransaction( SPI, iter.getTotalByteOffset() );
+ }
+ );
+}
+
+void spiWriteRepeat(uint8_t val, uint16_t repcnt) {
+ if (repcnt == 0) return;
+
+ auto& SPI = MarlinESP32::SPIGetBusFromIndex(_spi_gpiomap.spibusIdx);
+
+ if (SPI.SPI_USER_REG.SPI_USR_MOSI == false) return;
+
+ _spiAsyncBarrier();
+
+ _maybe_start_transaction();
+
+ // There is no good repetition output engine on the ESP32 DMAC.
+ // Thus we have to use generic SPI.
+
+ uint16_t start_num_idx = MarlinESP32::SPIGetWriteBufferStartIndex(SPI);
+
+ esp32BitManager buf_bitman( &SPI.SPI_W_REG[start_num_idx], COUNT(SPI.SPI_W_REG) - start_num_idx );
+
+ eir::BitManagerTemplates::RepeatSendCountTo( val, repcnt, buf_bitman,
+ [&] ( void ) LAINLINE
+ {
+ auto bytecnt = buf_bitman.GetIterator().getTotalByteOffset();
+ MarlinESP32::SPITransaction( SPI, (uint32_t)bytecnt );
+ }
+ );
+}
+
+void spiWriteRepeat16(uint16_t val, uint16_t repcnt) {
+ if (repcnt == 0) return;
+
+ auto& SPI = MarlinESP32::SPIGetBusFromIndex(_spi_gpiomap.spibusIdx);
+
+ if (SPI.SPI_USER_REG.SPI_USR_MOSI == false) return;
+
+ _spiAsyncBarrier();
+
+ _maybe_start_transaction();
+
+ // There is no good repetition output engine on the ESP32 DMAC.
+ // Thus we have to use generic SPI.
+
+ uint16_t start_num_idx = MarlinESP32::SPIGetWriteBufferStartIndex(SPI);
+
+ esp32BitManager buf_bitman( &SPI.SPI_W_REG[start_num_idx], COUNT(SPI.SPI_W_REG) - start_num_idx );
+
+ eir::BitOrderingConverter bitconv(
+ ( SPI.SPI_CTRL_REG.SPI_WR_BIT_ORDER == _ESP32_BIT_ORDER_MSB ? endian::eSpecificEndian::BIG_ENDIAN : endian::eSpecificEndian::LITTLE_ENDIAN ),
+ false // already done by HW
+ );
+
+ eir::BitManagerTemplates::RepeatSendCountTo( bitconv.Identity( val ), repcnt, buf_bitman,
+ [&] ( void ) LAINLINE
+ {
+ auto bytecnt = buf_bitman.GetIterator().getTotalByteOffset();
+ MarlinESP32::SPITransaction( SPI, (uint32_t)bytecnt );
+ }
+ );
+}
+
+#ifdef HAL_SPI_SUPPORTS_ASYNC
+
+void spiWriteAsync(const uint8_t *buf, uint16_t nbyte, void (*completeCallback)(void*), void *ud) {
+ auto& SPI = MarlinESP32::SPIGetBusFromIndex(_spi_gpiomap.spibusIdx);
+
+ if (SPI.SPI_USER_REG.SPI_USR_MOSI == false) return;
+
+ if (nbyte == 0) {
+ if (completeCallback)
+ completeCallback(ud);
+ return;
+ }
+
+ _maybe_start_transaction();
+
+ // TODO: we could implement this async using DMA aswell because 8bit transfers are easily done using
+ // the hardware. Right now it is fine using SPI interrupts anyway (CPU is not being slowed down by slow SPI rates).
+
+ MarlinESP32::SPIStartRawAsync(SPI, buf, nbyte, sizeof(uint8_t), completeCallback, ud);
+}
+
+void spiWriteAsync16(const uint16_t *buf, uint16_t txcnt, void (*completeCallback)(void*), void *ud) {
+ auto& SPI = MarlinESP32::SPIGetBusFromIndex(_spi_gpiomap.spibusIdx);
+
+ if (SPI.SPI_USER_REG.SPI_USR_MOSI == false) return;
+
+ if (txcnt == 0) {
+ if (completeCallback)
+ completeCallback(ud);
+ return;
+ }
+
+ _maybe_start_transaction();
+
+ MarlinESP32::SPIStartRawAsync(SPI, buf, txcnt, sizeof(uint16_t), completeCallback, ud);
+}
+
+void spiAsyncAbort() {
+ MarlinESP32::SPIAbortRawAsync();
+}
+
+void spiAsyncJoin() {
+ _spiAsyncBarrier();
+}
+
+bool spiAsyncIsRunning() {
+ return (MarlinESP32::_current_spi_proc.is_active);
+}
+
+#endif
+
+#endif
+
+#endif
diff --git a/Marlin/src/HAL/ESP32/HAL_SPI_HWgen.cpp b/Marlin/src/HAL/ESP32/HAL_SPI_HWgen.cpp
new file mode 100644
index 000000000000..0e77970f20b2
--- /dev/null
+++ b/Marlin/src/HAL/ESP32/HAL_SPI_HWgen.cpp
@@ -0,0 +1,276 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ * Copyright (c) 2017 Victor Perez
+ *
+ * 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 ARDUINO_ARCH_ESP32
+
+#include "../../inc/MarlinConfig.h"
+
+#include "../shared/HAL_SPI.h"
+
+#if DISABLED(SOFTWARE_SPI) && ENABLED(HALSPI_HW_GENERIC)
+
+// ------------------------
+// Hardware SPI
+// ------------------------
+
+static void _spi_on_error() {
+ for (;;) {
+ #if defined(HALSPI_DO_ERRORBEEPS) && PIN_EXISTS(BEEPER)
+ OUT_WRITE(BEEPER_PIN, HIGH);
+ delay(500);
+ OUT_WRITE(BEEPER_PIN, LOW);
+ delay(500);
+ OUT_WRITE(BEEPER_PIN, HIGH);
+ delay(500);
+ OUT_WRITE(BEEPER_PIN, LOW);
+ delay(500);
+ OUT_WRITE(BEEPER_PIN, HIGH);
+ delay(150);
+ OUT_WRITE(BEEPER_PIN, LOW);
+ delay(150);
+ OUT_WRITE(BEEPER_PIN, HIGH);
+ delay(150);
+ OUT_WRITE(BEEPER_PIN, LOW);
+ delay(150);
+ OUT_WRITE(BEEPER_PIN, HIGH);
+ delay(150);
+ OUT_WRITE(BEEPER_PIN, LOW);
+ delay(3000);
+ #endif
+ }
+}
+
+static void __attribute__((unused)) _spi_infobeep(uint32_t code) {
+ #if PIN_EXISTS(BEEPER)
+ OUT_WRITE(BEEPER_PIN, HIGH);
+ delay(500);
+ OUT_WRITE(BEEPER_PIN, LOW);
+ delay(500);
+ for (uint32_t n = 0; n < code; n++) {
+ OUT_WRITE(BEEPER_PIN, HIGH);
+ delay(200);
+ OUT_WRITE(BEEPER_PIN, LOW);
+ delay(200);
+ }
+ delay(300);
+ OUT_WRITE(BEEPER_PIN, HIGH);
+ delay(400);
+ OUT_WRITE(BEEPER_PIN, LOW);
+ delay(1000);
+ #endif
+}
+
+#include
+#include
+
+static SPISettings spiConfig;
+
+static uint32_t _spi_clock;
+static int _spi_bitOrder;
+static int _spi_clkmode;
+static int _spi_pin_cs;
+static bool _spi_initialized = false;
+static bool _spi_transaction_is_running = false;
+
+void spiBegin() {
+ #if ENABLED(SDSUPPORT) && PIN_EXISTS(SD_SS)
+ OUT_WRITE(SD_SS_PIN, HIGH);
+ #endif
+}
+
+void spiSetupChipSelect(int pin) {
+ OUT_WRITE(pin, HIGH);
+}
+
+void spiInitEx(uint32_t maxClockFreq, int hint_sck, int hint_miso, int hint_mosi, int hint_cs) {
+ if (hint_sck != -1) SET_OUTPUT(hint_sck);
+ if (hint_miso != -1) SET_INPUT(hint_miso);
+ if (hint_mosi != -1) SET_OUTPUT(hint_mosi);
+ if (hint_cs != -1) SET_OUTPUT(hint_cs);
+
+ if (_spi_initialized) _spi_on_error();
+
+ _spi_clock = maxClockFreq;
+ _spi_bitOrder = MSBFIRST;
+ _spi_clkmode = SPI_MODE0;
+ _spi_pin_cs = hint_cs;
+ spiConfig = SPISettings(maxClockFreq, _spi_bitOrder, _spi_clkmode);
+ // https://github.com/espressif/arduino-esp32/blob/master/libraries/SPI/src/SPI.cpp SPIClass::begin method.
+ SPI.begin(hint_sck, hint_miso, hint_mosi);
+ _spi_initialized = true;
+ _spi_transaction_is_running = false;
+}
+
+void spiInit(uint8_t spiRate, int hint_sck, int hint_miso, int hint_mosi, int hint_cs) {
+ uint32_t clock;
+
+ switch (spiRate) {
+ case SPI_FULL_SPEED: clock = 16000000; break;
+ case SPI_HALF_SPEED: clock = 8000000; break;
+ case SPI_QUARTER_SPEED: clock = 4000000; break;
+ case SPI_EIGHTH_SPEED: clock = 2000000; break;
+ case SPI_SIXTEENTH_SPEED: clock = 1000000; break;
+ case SPI_SPEED_5: clock = 500000; break;
+ case SPI_SPEED_6: clock = 250000; break;
+ default: clock = 1000000; // Default from the SPI library
+ }
+ spiInitEx(clock, hint_sck, hint_miso, hint_mosi, hint_cs);
+}
+
+static void _maybe_start_transaction() {
+ if (_spi_transaction_is_running) return;
+ SPI.beginTransaction(spiConfig);
+ if (_spi_pin_cs != -1)
+ OUT_WRITE(_spi_pin_cs, LOW);
+ _spi_transaction_is_running = true;
+}
+
+void spiClose() {
+ if (!_spi_initialized)
+ _spi_on_error();
+ if (_spi_transaction_is_running) {
+ if (_spi_pin_cs != -1)
+ OUT_WRITE(_spi_pin_cs, HIGH);
+ SPI.endTransaction();
+ _spi_transaction_is_running = false;
+ }
+ SPI.end();
+ _spi_initialized = false;
+}
+
+void spiSetBitOrder(int bitOrder) {
+ bool update = false;
+ if (bitOrder == SPI_BITORDER_MSB) {
+ _spi_bitOrder = MSBFIRST;
+ update = true;
+ }
+ else if (bitOrder == SPI_BITORDER_LSB) {
+ _spi_bitOrder = LSBFIRST;
+ update = true;
+ }
+ if (update) {
+ spiConfig = SPISettings(_spi_clock, _spi_bitOrder, _spi_clkmode);
+ if (_spi_transaction_is_running) {
+ // On ESP32 it is safe to keep the chip-select LOW even if restarting
+ // a transaction, judging by the SPI library and HAL sources.
+ SPI.endTransaction();
+ SPI.beginTransaction(spiConfig);
+ }
+ }
+}
+
+void spiSetClockMode(int mode) {
+ bool update = false;
+ if (mode == SPI_CLKMODE_0) {
+ _spi_clkmode = SPI_MODE0;
+ update = true;
+ }
+ else if (mode == SPI_CLKMODE_1) {
+ _spi_clkmode = SPI_MODE1;
+ update = true;
+ }
+ else if (mode == SPI_CLKMODE_2) {
+ _spi_clkmode = SPI_MODE2;
+ update = true;
+ }
+ else if (mode == SPI_CLKMODE_3) {
+ _spi_clkmode = SPI_MODE3;
+ update = true;
+ }
+ if (update) {
+ spiConfig = SPISettings(_spi_clock, _spi_bitOrder, _spi_clkmode);
+ if (_spi_transaction_is_running) {
+ SPI.endTransaction();
+ SPI.beginTransaction(spiConfig);
+ }
+ }
+}
+
+void spiEstablish() {
+ _maybe_start_transaction();
+}
+
+uint8_t spiRec(uint8_t txval) {
+ _maybe_start_transaction();
+ uint8_t returnByte = SPI.transfer(txval);
+ return returnByte;
+}
+
+uint16_t spiRec16(uint16_t txval) {
+ _maybe_start_transaction();
+ uint16_t res = SPI.transfer16(txval);
+ return res;
+}
+
+void spiRead(uint8_t *buf, uint16_t nbyte, uint8_t txval) {
+ if (nbyte == 0) return;
+ _maybe_start_transaction();
+ for (uint16_t n = 0; n < nbyte; n++)
+ buf[n] = SPI.transfer(txval);
+}
+
+void spiSend(uint8_t b) {
+ _maybe_start_transaction();
+ SPI.write(b);
+}
+
+void spiSend16(uint16_t v) {
+ _maybe_start_transaction();
+ SPI.write16(v);
+}
+
+void spiSendBlock(uint8_t token, const uint8_t *buf) {
+ _maybe_start_transaction();
+ SPI.write(token);
+ SPI.writeBytes(buf, 512);
+}
+
+void spiWrite(const uint8_t *buf, uint16_t cnt) {
+ _maybe_start_transaction();
+ SPI.writeBytes(buf, cnt);
+}
+
+void spiWrite16(const uint16_t *buf, uint16_t cnt) {
+ if (cnt == 0) return;
+ _maybe_start_transaction();
+ for (uint16_t n = 0; n < cnt; n++)
+ SPI.write16(buf[n]);
+}
+
+void spiWriteRepeat(uint8_t val, uint16_t repcnt) {
+ if (repcnt == 0) return;
+ _maybe_start_transaction();
+ for (uint16_t n = 0; n < repcnt; n++)
+ SPI.write(val);
+}
+
+void spiWriteRepeat16(uint16_t val, uint16_t repcnt) {
+ if (repcnt == 0) return;
+ _maybe_start_transaction();
+ for (uint16_t n = 0; n < repcnt; n++) {
+ SPI.write16(val);
+ }
+}
+
+#endif // !SOFTWARE_SPI && HALSPI_HW_GENERIC
+
+#endif // ARDUINO_ARCH_ESP32
diff --git a/Marlin/src/HAL/ESP32/MarlinSPI.h b/Marlin/src/HAL/ESP32/HAL_SPI_SW.cpp
similarity index 68%
rename from Marlin/src/HAL/ESP32/MarlinSPI.h
rename to Marlin/src/HAL/ESP32/HAL_SPI_SW.cpp
index 0c447ba4cb3d..ef8430f63e44 100644
--- a/Marlin/src/HAL/ESP32/MarlinSPI.h
+++ b/Marlin/src/HAL/ESP32/HAL_SPI_SW.cpp
@@ -1,6 +1,6 @@
/**
* Marlin 3D Printer Firmware
- * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
@@ -19,8 +19,19 @@
* along with this program. If not, see .
*
*/
-#pragma once
+#ifdef ARDUINO_ARCH_ESP32
-#include
+#include "../../inc/MarlinConfig.h"
-using MarlinSPI = SPIClass;
+#include "../shared/HAL_SPI.h"
+
+#if ENABLED(SOFTWARE_SPI)
+
+ // ------------------------
+ // Software SPI
+ // ------------------------
+ #error "Software SPI not supported for ESP32. Use Hardware SPI."
+
+#endif
+
+#endif // ARDUINO_ARCH_ESP32
diff --git a/Marlin/src/HAL/ESP32/WebSocketSerial.h b/Marlin/src/HAL/ESP32/WebSocketSerial.h
index 6b3e419d10c5..94611034750a 100644
--- a/Marlin/src/HAL/ESP32/WebSocketSerial.h
+++ b/Marlin/src/HAL/ESP32/WebSocketSerial.h
@@ -21,7 +21,7 @@
*/
#pragma once
-#include "../../inc/MarlinConfig.h"
+#include "../../inc/MarlinConfigPre.h"
#include "../../core/serial_hook.h"
#include
diff --git a/Marlin/src/HAL/ESP32/inc/Conditionals_LCD.h b/Marlin/src/HAL/ESP32/inc/Conditionals_LCD.h
index 4da600179d6c..ed320ebab849 100644
--- a/Marlin/src/HAL/ESP32/inc/Conditionals_LCD.h
+++ b/Marlin/src/HAL/ESP32/inc/Conditionals_LCD.h
@@ -21,6 +21,6 @@
*/
#pragma once
-#if HAS_SPI_TFT || HAS_FSMC_TFT
- #error "Sorry! TFT displays are not available for HAL/ESP32."
+#if HAS_FSMC_TFT
+ #error "Sorry! FSMC displays are not available for HAL/ESP32."
#endif
diff --git a/Marlin/src/HAL/ESP32/ota.cpp b/Marlin/src/HAL/ESP32/ota.cpp
index 69a3e25e5631..f31a78c2c519 100644
--- a/Marlin/src/HAL/ESP32/ota.cpp
+++ b/Marlin/src/HAL/ESP32/ota.cpp
@@ -50,7 +50,7 @@ void OTA_init() {
})
.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
- char *str;
+ const char *str = "unknown";
switch (error) {
case OTA_AUTH_ERROR: str = "Auth Failed"; break;
case OTA_BEGIN_ERROR: str = "Begin Failed"; break;
diff --git a/Marlin/src/HAL/ESP32/sdk/Arith.h b/Marlin/src/HAL/ESP32/sdk/Arith.h
new file mode 100644
index 000000000000..35e3a795f3c6
--- /dev/null
+++ b/Marlin/src/HAL/ESP32/sdk/Arith.h
@@ -0,0 +1,60 @@
+/*****************************************************************************
+*
+* PROJECT: Eir SDK
+* FILE: eirrepo/sdk/Arith.h
+* PURPOSE: Arithmetic helpers
+*
+* Find the Eir SDK at: https://osdn.net/projects/eirrepo/
+*
+*****************************************************************************/
+
+#ifndef _EIRSDK_ARITH_HEADER_
+#define _EIRSDK_ARITH_HEADER_
+
+#include "MetaHelpers.h"
+#include "PlatformStrategy.h"
+
+namespace eir
+{
+
+template
+AINLINE constexpr auto SIGNP_PROMOTE( inputType v ) noexcept
+{
+ if constexpr ( unsigned_integral )
+ {
+ return (typename make_unsigned_integral ::type)v;
+ }
+ else
+ {
+ return v;
+ }
+}
+
+// Performs logical bitwise left-shift but keeps the sign-specification for the result type.
+template
+AINLINE constexpr auto LSHIFT( T v, platformLocalBitcountType cnt ) noexcept
+{
+ return SIGNP_PROMOTE ( v ) << cnt;
+}
+// Performs logical bitwise right-shift but keeps the sign-specification for the result type.
+template
+AINLINE constexpr auto RSHIFT( T v, platformLocalBitcountType cnt ) noexcept
+{
+ return SIGNP_PROMOTE >cnt)> ( v ) >> cnt;
+}
+
+template requires ( signed_integral == signed_integral