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 ) +AINLINE constexpr auto ADD_SIGNP( LT left, RT right ) noexcept +{ + return ( SIGNP_PROMOTE ( left ) + SIGNP_PROMOTE ( right ) ); +} + +template requires ( signed_integral == signed_integral ) +AINLINE constexpr auto SUB_SIGNP( LT left, RT right ) noexcept +{ + return ( SIGNP_PROMOTE ( left ) - SIGNP_PROMOTE ( right ) ); +} + +} // namespace eir + +#endif //_EIRSDK_ARITH_HEADER_ diff --git a/Marlin/src/HAL/ESP32/sdk/BitIteration.h b/Marlin/src/HAL/ESP32/sdk/BitIteration.h new file mode 100644 index 000000000000..0a2b6eb4f00e --- /dev/null +++ b/Marlin/src/HAL/ESP32/sdk/BitIteration.h @@ -0,0 +1,438 @@ +/***************************************************************************** +* +* PROJECT: Eir SDK +* FILE: eirrepo/sdk/BitIteration.h +* PURPOSE: Bit-based iteration utilities +* +* Find the Eir SDK at: https://osdn.net/projects/eirrepo/ +* +*****************************************************************************/ + +#include "MetaHelpers.h" +#include "Tuple.h" +#include "Compare.h" +#include "PlatformStrategy.h" + +#include +#include + +#if __has_include() +#include +#endif + +#ifdef _DEBUG +#include +#endif + +namespace eir +{ + +// Type-trait. +template +struct is_bitnumberiterator : false_type {}; + +template +concept bitnumberiterator_type = is_bitnumberiterator ::value; + +// Represents an iterator over bit-arrays. Segments the bit array into "hostBitCount" slices, each referred to as +// "number" indexed in order of occurrence. +template +struct BitNumberIterator +{ + static constexpr platformLocalBitcountType hostBitCount = _hostBitCount; + + AINLINE constexpr BitNumberIterator( size_t numOffset = 0, platformLocalBitcountType bitOffset = 0 ) noexcept : numOffset( numOffset ), bitOffset( bitOffset ) + { +#ifdef _DEBUG + assert( bitOffset < hostBitCount ); +#endif + } + AINLINE BitNumberIterator( const BitNumberIterator& ) = default; + template requires ( same_as == false ) + AINLINE BitNumberIterator( const otherIterType& other ) noexcept + { + auto bitCnt = other.getTotalBitOffset(); + this->numOffset = (size_t)( bitCnt / hostBitCount ); + this->bitOffset = ( bitCnt % hostBitCount ); + } + + AINLINE BitNumberIterator& operator = ( const BitNumberIterator& ) = default; + + template requires ( same_as == false ) + AINLINE BitNumberIterator& operator = ( const otherIterType& other ) noexcept + { + auto bitCnt = other.getTotalBitOffset(); + this->numOffset = (size_t)( bitCnt / hostBitCount ); + this->bitOffset = ( bitCnt % hostBitCount ); + return *this; + } + + AINLINE constexpr void addBits( platformBitCountType bitCount ) noexcept + { + platformBitCountType numBitOff = this->getTotalBitOffset(); + + platformBitCountType newBitOff = numBitOff + bitCount; + + this->numOffset = (size_t)( newBitOff / hostBitCount ); + this->bitOffset = (platformLocalBitcountType)( newBitOff % hostBitCount ); + } + AINLINE constexpr void addBytes( size_t byteCount ) noexcept + { + const platformLocalBitcountType hostByteCount = ( hostBitCount / 8u ); + + size_t numCountByBytes = byteCount / hostByteCount; + size_t remainderByBytes = byteCount % hostByteCount; + + this->numOffset += numCountByBytes; + this->addBits( remainderByBytes * 8u ); + } + + AINLINE constexpr platformBitCountType distBits( const BitNumberIterator& right ) const noexcept + { + return ( this->getTotalBitOffset() - right.getTotalBitOffset() ); + } + AINLINE constexpr size_t distBytes( const BitNumberIterator& right ) const noexcept + { + return ( this->getTotalByteOffset() - right.getTotalByteOffset() ); + } + + AINLINE constexpr size_t getNumberOffset( void ) const noexcept + { + return this->numOffset; + } + AINLINE constexpr platformLocalBitcountType getLocalBitOffset( void ) const noexcept + { + return this->bitOffset; + } + AINLINE constexpr platformBitCountType getTotalBitOffset( void ) const noexcept + { + return ( (platformBitCountType)this->numOffset * hostBitCount + this->bitOffset ); + } + AINLINE constexpr size_t getTotalByteOffset( void ) const noexcept + { + if constexpr ( hostBitCount % 8u == 0 ) + { + if constexpr ( hostBitCount == 8u ) + { + return (size_t)( this->numOffset * ( hostBitCount / 8u ) ); + } + else + { + return (size_t)( this->numOffset * ( hostBitCount / 8u ) + this->bitOffset / 8u ); + } + } + else + { + return (size_t)( getTotalBitOffset() / 8u ); + } + } + + // Optimized variant. + AINLINE constexpr BitNumberIterator& operator += ( const BitNumberIterator& right ) noexcept + { + this->numOffset += right.numOffset; + this->addBits( right.bitOffset ); + return *this; + } + // Less-optimized variant. + template + AINLINE constexpr BitNumberIterator& operator += ( const RT& right ) noexcept + { + this->addBits( right.getTotalBitOffset() ); + return *this; + } + + AINLINE constexpr BitNumberIterator operator + ( const BitNumberIterator& right ) const noexcept + { + BitNumberIterator res = *this; + res += right; + return res; + } + + AINLINE constexpr BitNumberIterator& operator -= ( const BitNumberIterator& right ) noexcept + { + this->numOffset -= right.numOffset; + platformLocalBitcountType bitOffset = this->bitOffset; + platformLocalBitcountType subBitOffset = right.bitOffset; + + if (bitOffset < subBitOffset) + { + this->numOffset--; + this->bitOffset = ( hostBitCount - ( subBitOffset - bitOffset ) ); + } + else + { + this->bitOffset = ( bitOffset - subBitOffset ); + } + return *this; + } + template + AINLINE constexpr BitNumberIterator& operator -= ( const RT& right ) noexcept + { + platformBitCountType res_bitc = ( this->getTotalBitOffset() - right.getTotalBitOffset() ); + this->numOffset = (size_t)( res_bitc / hostBitCount ); + this->bitOffset = ( res_bitc % hostBitCount ); + return *this; + } + + AINLINE constexpr BitNumberIterator operator - ( const BitNumberIterator& right ) noexcept + { + BitNumberIterator res = *this; + res -= right; + return res; + } + + AINLINE friend constexpr bool operator == ( const BitNumberIterator& L, const BitNumberIterator& R ) noexcept + { + return ( ( L.numOffset == R.numOffset ) && ( L.bitOffset == R.bitOffset ) ); + } + AINLINE static constexpr eCompResult compare( const BitNumberIterator& L, const BitNumberIterator& R ) noexcept + { + eCompResult numOff_cmpres = eir::DefaultValueCompare( L.numOffset, R.numOffset ); + + if ( numOff_cmpres != eCompResult::EQUAL ) + { + return numOff_cmpres; + } + + eCompResult bitOffset_cmpres = eir::DefaultValueCompare( L.bitOffset, R.bitOffset ); + + return bitOffset_cmpres; + } +#if defined(__cpp_impl_three_way_comparison) && !defined(_DEBUG_OLDSTYLE_COMPARISONS) + AINLINE friend constexpr auto operator <=> ( const BitNumberIterator& L, const BitNumberIterator& R ) noexcept + { + return eir::cmpres_to_ordering ( compare( L, R ) ); + } +#else + // Required for old compilers. + AINLINE friend constexpr bool operator != ( const BitNumberIterator& L, const BitNumberIterator& R ) noexcept + { + return !( operator == ( L, R ) ); + } + AINLINE friend constexpr bool operator < ( const BitNumberIterator& L, const BitNumberIterator& R ) noexcept + { + return compare( L, R ) == eCompResult::LEFT_LESS; + } + AINLINE friend constexpr bool operator > ( const BitNumberIterator& L, const BitNumberIterator& R ) noexcept + { + return compare( L, R ) == eCompResult::LEFT_GREATER; + } + AINLINE friend constexpr bool operator <= ( const BitNumberIterator& L, const BitNumberIterator& R ) noexcept + { + auto res = compare( L, R ); + return ( res == eCompResult::LEFT_LESS || res == eCompResult::EQUAL ); + } + AINLINE friend constexpr bool operator >= ( const BitNumberIterator& L, const BitNumberIterator& R ) noexcept + { + auto res = compare( L, R ); + return ( res == eCompResult::LEFT_GREATER || res == eCompResult::EQUAL ); + } +#endif + +private: + size_t numOffset; + platformLocalBitcountType bitOffset; +}; +template +struct is_bitnumberiterator > : true_type {}; +template requires ( is_bitnumberiterator ::type>::value ) +struct is_bitnumberiterator : true_type {}; + +template requires ( same_as == false ) +AINLINE constexpr bool operator == ( const LT& L, const RT& R ) noexcept +{ + return L.getTotalBitOffset() == R.getTotalBitOffset(); +} +#if defined(__cpp_impl_three_way_comparison) && !defined(_DEBUG_OLDSTYLE_COMPARISONS) +template requires ( same_as == false ) +AINLINE constexpr auto operator <=> ( const LT& L, const RT& R ) noexcept +{ + return L.getTotalBitOffset() <=> R.getTotalBitOffset(); +} +#else +// Required for old compilers. +template requires ( same_as == false ) +AINLINE constexpr bool operator != ( const LT& L, const RT& R ) noexcept +{ + return L.getTotalBitOffset() != R.getTotalBitOffset(); +} +template requires ( same_as == false ) +AINLINE constexpr bool operator < ( const LT& L, const RT& R ) noexcept +{ + return ( L.getTotalBitOffset() < R.getTotalBitOffset() ); +} +template requires ( same_as == false ) +AINLINE constexpr bool operator > ( const LT& L, const RT& R ) noexcept +{ + return ( L.getTotalBitOffset() > R.getTotalBitOffset() ); +} +template requires ( same_as == false ) +AINLINE constexpr bool operator <= ( const LT& L, const RT& R ) noexcept +{ + return ( L.getTotalBitOffset() <= R.getTotalBitOffset() ); +} +template requires ( same_as == false ) +AINLINE constexpr bool operator >= ( const LT& L, const RT& R ) noexcept +{ + return ( L.getTotalBitOffset() >= R.getTotalBitOffset() ); +} +#endif + +// Helper for deciding a compatible iterator based on a type. +template +using BitNumberIteratorForStruct = BitNumberIterator ; + +namespace BitIterationUtils +{ + +template +concept bit_iterator_advance_min_iterType = + tuple_type ::type> && T::count == 2 && ( bitnumberiterator_type ::type> && bitnumberiterator_type ::type> ) || + unsigned_integral ::type>; + +} // namespace BitIterationUtils + +template +AINLINE platformBitCountType bit_advance_min( const iterTypes&... iterPairs ) noexcept +{ + if constexpr ( sizeof...(iterPairs) == 0 ) + { + return 0u; + } + else + { + platformBitCountType bitadv = 0u; + bool has_bitadv = false; + + auto lamb = [&] ( const T& iterPair ) LAINLINE + { + if constexpr ( tuple_type ) + { + if constexpr ( T::count == 2 ) + { + auto start = iterPair.template Get <0> ().getTotalBitOffset(); + auto end = iterPair.template Get <1> ().getTotalBitOffset(); + + platformBitCountType adv; + + if ( start < end ) + { + adv = ( end - start ); + } + else + { + adv = 0u; + } + + if (has_bitadv == false || bitadv > adv) + { + bitadv = adv; + has_bitadv = true; + } + } + } + else if constexpr ( unsigned_integral ) + { + if (has_bitadv == false || bitadv > iterPair) + { + bitadv = iterPair; + has_bitadv = true; + } + } + }; + ( lamb( iterPairs ), ... ); + + return bitadv; + } +} + +template +AINLINE startIterType bit_iterator_advance_min( const startIterType& iter, const iterTypes&... iterPairs ) noexcept +{ + if constexpr ( sizeof...(iterPairs) == 0 ) + { + return iter; + } + else + { + startIterType end_iter = iter; + + end_iter.addBits( bit_advance_min( iterPairs... ) ); + + return end_iter; + } +} + +template +AINLINE size_t bit_advance_min_bytes( const iterTypes&... iterPairs ) noexcept +{ + if constexpr ( sizeof...(iterPairs) == 0 ) + { + return 0u; + } + else + { + size_t bytesadv = 0u; + bool has_bytesadv = false; + + auto lamb = [&] ( const T& iterPair ) LAINLINE + { + if constexpr ( tuple_type ) + { + if constexpr ( T::count == 2 ) + { + auto start = iterPair.template Get <0> ().getTotalByteOffset(); + auto end = iterPair.template Get <1> ().getTotalByteOffset(); + + size_t adv; + + if ( start < end ) + { + adv = end - start; + } + else + { + adv = 0u; + } + + if (has_bytesadv == false || bytesadv > adv) + { + bytesadv = adv; + has_bytesadv = true; + } + } + } + else if constexpr ( unsigned_integral ) + { + if (has_bytesadv == false || bytesadv > iterPair) + { + bytesadv = iterPair; + has_bytesadv = true; + } + } + }; + ( lamb( iterPairs ), ... ); + + return bytesadv; + } +} + +template +AINLINE startIterType bit_iterator_advance_min_bytes( const startIterType& iter, const iterTypes&... iterPairs ) noexcept +{ + if constexpr ( sizeof...(iterPairs) == 0 ) + { + return iter; + } + else + { + startIterType end_iter = iter; + + end_iter.addBytes( bit_advance_min_bytes( iterPairs... ) ); + + return end_iter; + } +} + +} // namespace eir diff --git a/Marlin/src/HAL/ESP32/sdk/BitManage.h b/Marlin/src/HAL/ESP32/sdk/BitManage.h new file mode 100644 index 000000000000..a47e9bff693b --- /dev/null +++ b/Marlin/src/HAL/ESP32/sdk/BitManage.h @@ -0,0 +1,1440 @@ +/***************************************************************************** +* +* PROJECT: Eir SDK +* FILE: eirrepo/sdk/BitManage.h +* PURPOSE: Low-level bit manipulation acceleration helpers +* +* Find the Eir SDK at: https://osdn.net/projects/eirrepo/ +* +*****************************************************************************/ + +#ifndef _BIT_MANAGE_HEADER_ +#define _BIT_MANAGE_HEADER_ + +#include +#include // for size_t + +#include "MemoryRaw.h" +#include "Endian.h" +#include "MetaHelpers.h" // for no_volatile +#include "PlatformStrategy.h" +#include "Variant.h" +#include "BitManip.h" +#include "Tuple.h" +#include "Arith.h" +#include "BitIteration.h" + +// Feel the power of C++20 on the embedded side. +// Documentation Video: https://youtu.be/L_o481OL0Xw (12 Jan 2023) + +namespace eir +{ + +#ifdef __cpp_if_constexpr +#define _BITMANAGE_IF_CONSTEXPR constexpr +#else +#define _BITMANAGE_IF_CONSTEXPR +#endif + +// During code-gen analysis I have detected that the inlining of the code-graphs does not lead to great results, especially +// because we use PlatformStrategy optimizations and those values are usually not retransformable by the compilers. +#ifdef _BITMANAGE_ALWAYS_INLINE +#define BM_AINLINE AINLINE +#else +#define BM_AINLINE inline +#endif + +// In comparison to the above always-inline guidelines, the "brutal" always-inline guide is applied to code-graph templates +// that are known to create a bigger mess. Thus be careful about applying this attribute! +#if defined(_BITMANAGE_ALWAYS_INLINE) && defined(_BITMANAGE_BRUTAL_ALWAYS_INLINE) +#define BM_BRUTAL_AINLINE AINLINE +#else +#define BM_BRUTAL_AINLINE inline +#endif + +template +struct identity_number_specificator +{ + typedef numberType type; +}; + +template +struct const_number_specificator +{ + typedef const T type; +}; + +template +struct volatile_number_specificator +{ + typedef volatile numberType type; +}; + +template +struct const_volatile_number_specificator +{ + typedef const volatile numberType type; +}; + +template +struct choose_default_number_specificator +{ + template + using spec = identity_number_specificator ; +}; +template +struct choose_default_number_specificator +{ + template + using spec = volatile_number_specificator ; +}; +template +struct choose_default_number_specificator +{ + template + using spec = const_number_specificator ; +}; +template +struct choose_default_number_specificator +{ + template + using spec = const_volatile_number_specificator ; +}; + +// The default type-list of hardware-supported native number types. +typedef typelist < +#if PLATFORM_WORDSIZE >= 8 + uint64_t, +#endif +#if PLATFORM_WORDSIZE >= 4 + uint32_t, +#endif +#if PLATFORM_WORDSIZE >= 2 + uint16_t, +#endif + uint8_t +> PlatformNumberTypeList; + +typedef OptTypeSelector PlatformNumberTypeSelector; + +template +AINLINE void SelectAlignedTypeAccess( numberType& loc, size_t bytes_left, callbackType&& cb ) +{ + using filteredSpecSuppTypes = typename no_volatile ::type>::type; + using distinctSuppTypes = typename types_distinct ::type; + using size_selected_types = typename sizeof_greaterequal_types ::type; + using forwardsSortedSuppTypes = typename sizeof_sorted_types ::type; + using sortedSuppTypes = typename types_reverse ::type; + + sortedSuppTypes::ForEach( + [&] () LAINLINE + { + if (is_same_as ::value || (bytes_left >= sizeof(T) && (uintptr_t)&loc % alignof(T) == 0)) + { + cb.template operator() (); + return true; + } + return false; + }); +} + +template < + template typename numberSpecific = identity_number_specificator, + typelist_type suppTypes = PlatformNumberTypeList, + template typename baseVariantType = BitfieldVariant +> +struct PlatformBitCache +{ + using filteredSpecSuppTypes = typename no_volatile ::type>::type; + using distinctSuppTypes = typename types_distinct ::type; + using forwardsSortedSuppTypes = typename sizeof_sorted_types ::type; + using sortedSuppTypes = typename types_reverse ::type; + + using distinct_t = typename numberSpecific ::type, + void>::type + >::type; + + BM_AINLINE PlatformBitCache( void ) = default; + BM_AINLINE PlatformBitCache( const PlatformBitCache& ) = default; + + BM_AINLINE PlatformBitCache& operator = ( const PlatformBitCache& ) = default; + + BM_AINLINE void Flush( void ) noexcept + { + if constexpr ( const_type == false ) + { + this->data.Visit( + [this]( auto& data ) LAINLINE + { + *(typename numberSpecific ::type>::type*PTR_NO_ALIAS)this->data_pointer = data; + } + ); + } + + this->data.Clear(); + } + BM_AINLINE void Invalidate( void ) noexcept + { + this->data.Clear(); + } + BM_AINLINE bool IsInitialized( void ) const noexcept { return ( this->data.IsEmpty() == false ); } + + template + requires ( sequence_contains ::type, sortedSuppTypes>::value ) + BM_AINLINE void PutIntoCache( numberType& num ) noexcept + { + this->data.Store( num ); + this->data_pointer = # + } + template + requires ( sequence_contains ::type, sortedSuppTypes>::value ) + BM_AINLINE numberType GetCacheValue( void ) noexcept + { + return this->data.template Get (); + } + + template + requires ( sequence_contains ::type, sortedSuppTypes>::value ) + BM_AINLINE void CacheMemoryLocation( cacheNumType *PTR_NO_ALIAS loc, size_t bytes_left ) noexcept + { + SelectAlignedTypeAccess ( *loc, bytes_left, + [&] () LAINLINE + { + if constexpr ( no_read ) + { + this->data.Store( typename base_type ::type() ); + } + else + { + using acc_T = typename conditional <(is_volatile ::value), volatile T, T>::type; + this->data.Store( *(const acc_T*PTR_NO_ALIAS)loc ); + } + } + ); + this->data_pointer = loc; + } + + template + requires ( sequence_contains ::type, sortedSuppTypes>::value ) + BM_AINLINE bool CanSatisfy( numberType& mem_val ) noexcept + { + if constexpr ( sortedSuppTypes::count == 1 ) + { + // Assume alignment guarantee. + return ( this->data_pointer == &mem_val ); + } + else + { + uintptr_t numloc = (uintptr_t)&mem_val; + uintptr_t cachenumloc = (uintptr_t)this->data_pointer; + + auto cache_size = this->data.GetSize(); + + // Structures must always be aligned but I can check for that anyway. + return /*(numloc % alignof(numberType) == 0) &&*/ (numloc >= cachenumloc && numloc + sizeof(numberType) <= cachenumloc + cache_size); + } + } + + template + requires ( sequence_contains ::type, sortedSuppTypes>::value ) + BM_AINLINE void SelectRef( distinct_t *PTR_NO_ALIAS orig_ptr, callbackType&& cb ) noexcept + { + if constexpr ( sortedSuppTypes::count == 1 ) + { + cb( this->data.Get() ); + } + else + { + uintptr_t cachenumloc = (uintptr_t)this->data_pointer; + + uintptr_t byteoff = ( (uintptr_t)orig_ptr - cachenumloc ); + + if _ENDIAN_CONSTEXPR ( endian::get_current_endianness() == endian::eSpecificEndian::BIG_ENDIAN ) + { + byteoff = ( this->data.GetSize() - sizeof(numberType) ) - byteoff; + } + + this->data.VisitBitsFrom( byteoff, + [&]( auto& ref ) LAINLINE + { + StaticBitfieldNumberSelectionView ::type> bfacc( &ref ); + cb( bfacc ); + }); + } + } + BM_AINLINE distinct_t*PTR_NO_ALIAS GetStoragePointer( void ) const noexcept + { + return this->data_pointer; + } + + template + requires ( sequence_contains ::type, sortedSuppTypes>::value ) + BM_AINLINE void SelectCachedBits( numberType& mem_val, size_t bytes_left, callbackType&& cb ) + { +#ifdef _DEBUG + assert( bytes_left >= sizeof(numberType) ); +#endif + + // All number types have a power-of-two size. + if (this->data.IsEmpty() == false) + { + if ( this->template CanSatisfy ( mem_val ) ) + { + goto returnResult; + } + + // We cannot use the previous cache anymore, so flush it. + Flush(); + } + + // Attempt to fill cache memory. + CacheMemoryLocation( &mem_val, bytes_left ); + + returnResult: + this->template SelectRef ( &mem_val, (callbackType&&)cb ); + } + + template + requires ( sequence_contains ::type, sortedSuppTypes>::value ) + BM_AINLINE typename no_const ::type>::type ReadCacheInto( numberType& mem_val, size_t bytes_left = sizeof(numberType) ) noexcept + { + typename no_const ::type>::type result = 0u; + + this->SelectCachedBits( mem_val, bytes_left, + [&]( auto& val ) LAINLINE + { + // Trim-off any bits that are too much, fill in any bits with zeroes that are missing. + result = (numberType)val; + } + ); + + return result; + } + + template + BM_AINLINE T ExtractNumberEndian( uint8_t byteoff ) const noexcept + { + unsigned int real_byteoff = byteoff; + + if _ENDIAN_CONSTEXPR ( endian::get_current_endianness() == endian::eSpecificEndian::BIG_ENDIAN ) + { + real_byteoff = ( this->data.GetSize() - sizeof(T) ) - real_byteoff; + } + + typename no_volatile ::type ret = 0u; + this->data.VisitBitsFrom( real_byteoff, + [&]( auto& ref ) LAINLINE + { + ret = (decltype(ret))ref; + }); + return ret; + } + + BM_AINLINE uint8_t GetCacheSize( void ) const noexcept + { + return this->data.GetSize(); + } + BM_AINLINE distinct_t* GetOriginalDataPointer( void ) const noexcept + { + return this->data_pointer; + } + +private: + typename conditional <(sortedSuppTypes::count == 1), + Variant , + baseVariantType + >::type data; + distinct_t *PTR_NO_ALIAS data_pointer = nullptr; +}; + +// Useful structure for performing the bit-ordering conversion on whole numbers outside of the BitManager class. +// You don't get the caching optimization of BitManager though so if you risk partial operations it is still preferable to use BitManager over directly this. +struct BitOrderingConverter +{ + AINLINE _ENDIAN_CONSTEXPR BitOrderingConverter( endian::eSpecificEndian storage_endianness = endian::eSpecificEndian::DEFAULT_ENDIAN, bool storage_msbfirst = false ) noexcept + { + bool is_diff_byteorder = ( storage_endianness != endian::get_current_endianness() ); + bool is_diff_bitorder = ( storage_msbfirst ); + + this->do_reverse_bitorder = ( is_diff_bitorder ); + this->do_reverse_byteorder = ( is_diff_byteorder != is_diff_bitorder ); +#if defined(_PLATFORM_HAS_FAST_REV16) + this->do_rev16 = false; +#endif + } + AINLINE constexpr BitOrderingConverter( bool revbits, bool revbytes, bool rev16 = false ) noexcept + : do_reverse_bitorder( revbits ), do_reverse_byteorder( revbytes ) +#if defined(_PLATFORM_HAS_FAST_REV16) + , do_rev16( rev16 ) +#endif + { + return; + } + AINLINE constexpr BitOrderingConverter( const BitOrderingConverter& ) = default; + + template + AINLINE constexpr numberType Identity( const numberType& val ) noexcept + { + numberType result = val; + if (this->do_reverse_byteorder) result = endian::byte_swap_fast( result ); + if (this->do_reverse_bitorder) result = reverse_bitorder( result ); +#if defined(_PLATFORM_HAS_FAST_REV16) + if constexpr ( __platform_number_supports_rev16 ::value ) + { + if (this->do_rev16) result = __platform_rev16( result ); + } +#endif + return result; + } + + AINLINE constexpr bool DoReverseBitorder( void ) const noexcept + { + return this->do_reverse_bitorder; + } + AINLINE constexpr bool DoReverseByteorder( void ) const noexcept + { + return this->do_reverse_byteorder; + } + +private: + bool do_reverse_bitorder, do_reverse_byteorder; +#if defined(_PLATFORM_HAS_FAST_REV16) + bool do_rev16; +#endif +}; + +// Takes a "unitNumberType" and a "containerNumberType". Returns a bitwise-operation if, performed on "containerNumberType", it's result is +// a bitwise-concatenation of "unitNumberType" entries - each solitarily assorted from LSB to MSB - in bit-index-ascending order. +struct BitVectorizedIdentityManager +{ + AINLINE _ENDIAN_CONSTEXPR BitVectorizedIdentityManager( BitOrderingConverter conv = {} ) noexcept : bitconv( conv ) + { + return; + } + AINLINE _ENDIAN_CONSTEXPR BitVectorizedIdentityManager( endian::eSpecificEndian endianness, bool msbfirst = false ) noexcept : BitVectorizedIdentityManager( BitOrderingConverter( endianness, msbfirst ) ) + { + return; + } + AINLINE BitVectorizedIdentityManager( const BitVectorizedIdentityManager& ) = default; + + template + AINLINE Variant VectorTransformGetConfig( void ) noexcept + { + if constexpr ( is_same_as ::value ) + { + return bitconv; + } + else + { +#if defined(_PLATFORM_FIXED_ENDIANNESS) + if constexpr ( sizeof(unitNumberType) == 1 ) + { + if constexpr ( endian::get_current_endianness() == endian::eSpecificEndian::BIG_ENDIAN ) + { + if ( bitconv.DoReverseBitorder() ) + { +#if defined(_PLATFORM_HAS_FAST_BITREVERSE) + if constexpr ( __platform_number_supports_bitreverse ::value ) + { + return BitOrderingConverter( true, false ); + } +#endif + } + else + { +#if defined(_PLATFORM_HAS_FAST_BYTESWAP) + if constexpr ( __platform_number_supports_byteswap ::value ) + { + return BitOrderingConverter( false, true ); + } +#endif + } + } + else + { + if ( bitconv.DoReverseBitorder() ) + { +#if defined(_PLATFORM_HAS_FAST_BITREVERSE) && defined(_PLATFORM_HAS_FAST_BYTESWAP) + if constexpr ( __platform_number_supports_byteswap ::value && __platform_number_supports_bitreverse ::value ) + { + return BitOrderingConverter( true, true ); + } +#endif + } + } + } + if constexpr ( sizeof(unitNumberType) == 2 ) + { + if constexpr ( endian::get_current_endianness() == endian::eSpecificEndian::LITTLE_ENDIAN ) + { + if ( bitconv.DoReverseByteorder() && bitconv.DoReverseBitorder() == false ) + { +#if defined(_PLATFORM_HAS_FAST_REV16) + if constexpr ( __platform_number_supports_rev16 ::value ) + { + return BitOrderingConverter( false, false, true ); + } +#endif + } + } + else + { + if ( bitconv.DoReverseByteorder() && bitconv.DoReverseBitorder() == false ) + { +#if defined(_PLATFORM_HAS_FAST_REV16) && defined(_PLATFORM_HAS_FAST_BYTESWAP) + if constexpr ( __platform_number_supports_byteswap ::value && __platform_number_supports_rev16 ::value ) + { + return BitOrderingConverter( false, true, true ); + } +#endif + } + } + } + if constexpr ( endian::get_current_endianness() == endian::eSpecificEndian::LITTLE_ENDIAN ) + { + if ( bitconv.DoReverseBitorder() == false && bitconv.DoReverseByteorder() == false ) + { + return BitOrderingConverter( false, false ); + } + } + else + { +#if defined(_PLATFORM_HAS_FAST_BYTESWAP) + if ( bitconv.DoReverseBitorder() == false && bitconv.DoReverseByteorder() == false ) + { + return BitOrderingConverter( false, true ); + } +#endif + } +#endif + // Unsupported transformation, related code-graphs should be deleted by compiler. + return {}; + } + } + template + AINLINE numberType VectorTransform( numberType val ) noexcept + { + if ( auto conf = VectorTransformGetConfig () ) + { + return conf.Get().Identity( val ); + } + // If everything else fails, do this. + // This code path should never be taken. + return 0u; + } + + // This method is required to be done using lambdas because in C++ it is currently ONLY possible to specialize DOWN the code-graph + // but NOT up (in the direction of the root of) the code-graph. + template + BM_AINLINE void Select( hostNumberType *vec, size_t num, callbackType&& cb ) noexcept + { + typedef typename no_volatile ::type hostFastNumberType; + + if (num == 0) return; + + // Check for support of FAST vectorized transformations. + using required_types_for_check = typename sizeof_greaterequal_types ::type; + using sorted_types_by_size = typename sizeof_sorted_types ::type; + using reversed_check_types = typename types_reverse ::type; + + reversed_check_types::ForEach( + [&] () LAINLINE + { + if ( sizeof(T) <= sizeof(hostNumberType) * num ) + { + if ( auto cfg = this->VectorTransformGetConfig () ) + { + const T& val = *(const T*)vec; + cb( cfg.Get().Identity( val ) ); + return true; + } + } + return false; + }); + } + +private: + BitOrderingConverter bitconv; +}; + +enum class eBitIdentityStorageIdentStrategy +{ + ALIASED, // uses memory-aliasing to fetch native integrals + BITFIELD // uses bitfield-extraction to fetch native integrals +}; + +inline constexpr eBitIdentityStorageIdentStrategy get_default_bit_identity_storage_ident_strategy( void ) noexcept +{ + endian::eSpecificEndian endianness = endian::eSpecificEndian::DEFAULT_ENDIAN; +#ifdef _PLATFORM_FIXED_ENDIANNESS + endianness = endian::get_current_endianness(); +#endif + + if (endianness == endian::eSpecificEndian::LITTLE_ENDIAN) + return eBitIdentityStorageIdentStrategy::BITFIELD; +#if !defined(_PLATFORM_HAS_FAST_BYTESWAP) + return eBitIdentityStorageIdentStrategy::ALIASED; +#else + return eBitIdentityStorageIdentStrategy::BITFIELD; +#endif +} + +// Storage that is identity-optimized on memory request, taking boundary specification into account, allowing flushing back +// of storage into fetched.from location. +// To identity-transform a bit-array is defined as permuting it so that the bits are assorted from LSB to MSB according +// to their indices. +// hostNumberType has to be unsigned integral. +template < + typename hostNumberType, + template typename numberSpecificator = identity_number_specificator, + typelist_type suppTypes = PlatformNumberTypeList, + template typename variantType = BitfieldVariant, + eBitIdentityStorageIdentStrategy idstrat = get_default_bit_identity_storage_ident_strategy(), + bool write_only = false +> requires ( write_only == false || mutable_type ) +struct BitIdentityStorage +{ + BM_AINLINE BitIdentityStorage( void ) = default; + BM_AINLINE BitIdentityStorage( const BitIdentityStorage& ) = default; + +private: + using amendedSuppTypes = typename eir::typelist_union ::type>>::type; + + BM_AINLINE void FlushIdCache( void ) noexcept + requires ( const_type == false ) + { + this->idcache.Visit( + [this]( auto& ref ) LAINLINE + { + typedef typename plain_type_bitfield ::type numType; + + numType data = ref; + + data = this->vecman.template VectorTransform ::type> ( data ); + + this->memcache.template SelectRef ( + this->idcache_pointer, + [&]( auto& cref ) LAINLINE + { + cref = data; + } + ); + } + ); + this->idcache.Clear(); + } + + using hostFastNumberType = typename no_volatile ::type>::type; + +public: + // Modelling assumption conflict: in the optimal BitManager implementation we base all of our memory requests on + // a fixed host-type that defines that bit-layout for all succeeding memory. Not having a fixed number type across requests + // does break the bit identity in certain operation orders. + // => That is why I have decided to introduce the template parameter "hostNumberType". + + template + BM_BRUTAL_AINLINE void Select( hostNumberType& num, size_t bytes_left, callbackType&& cb, bool cache_dirty ) + { + uintptr_t numloc = (uintptr_t)# + + if (this->idcache.IsEmpty() == false) + { + // Check whether the request is inside the identity cache. + uintptr_t cachenumloc = (uintptr_t)this->idcache_pointer; + + auto cache_size = this->idcache.GetSize(); + + if (numloc >= cachenumloc && numloc + sizeof(hostFastNumberType) <= cachenumloc + cache_size) + { + // Request is still within cache, so return it. + goto returnResult; + } + + if constexpr ( const_type == false ) + { + if ( cache_dirty ) + { + // Request fell outside of cache, so flush the cache. + this->FlushIdCache(); + } + else + { + this->idcache.Clear(); + } + } + else + { + // Just throw away const cache contents. + this->idcache.Clear(); + } + } + + // Invalidate the memory cache if the request is not inside of it. + if (this->memcache.IsInitialized() == false || this->memcache.template CanSatisfy ( num ) == false) + { + if constexpr ( const_type == false ) + { + if ( cache_dirty ) + { + this->memcache.Flush(); + } + else + { + this->memcache.Invalidate(); + } + } + else + { + this->memcache.Invalidate(); + } + this->memcache.template CacheMemoryLocation ( &num, bytes_left ); + } + + // Put new stuff into cache. + { + using required_types_for_check = typename sizeof_greaterequal_types ::type; + using sorted_types_by_size = typename sizeof_sorted_types ::type; + using reversed_check_types = typename types_reverse ::type; + + // Calculate the amount of bits that are possible to read at &num location. + auto boff = ( numloc - (uintptr_t)this->memcache.GetOriginalDataPointer() ); + auto bytecnt = ( this->memcache.GetCacheSize() - boff ); + + typename biggest_type ::type tmp = 0u; + uint8_t id_bytecnt = 0u; + + if constexpr ( idstrat == eBitIdentityStorageIdentStrategy::ALIASED ) + { + // Unused. + (void)tmp; (void)id_bytecnt; + +#ifndef _PLATFORM_SUPPORTS_UNALIGNED_MEMACCESS + // This aligned read check is only required if we use the memory-semantics-implementation of bit fetching. + // To support every hardware in existence we check that we can perform an aligned-read onto the memloc. + uint8_t aligncnt = 0u; + SelectAlignedTypeAccess ( num, bytecnt, + [&] () LAINLINE + { + aligncnt = alignof(T); + }); + + if (bytecnt > aligncnt) + { + bytecnt = aligncnt; + } +#endif //_PLATFORM_SUPPORTS_UNALIGNED_MEMACCESS + } + + reversed_check_types::ForEach( + [&] () LAINLINE + { + if ( sizeof(T) <= bytecnt ) + { + if ( auto vcfg = this->vecman.template VectorTransformGetConfig () ) + { + if constexpr ( idstrat == eBitIdentityStorageIdentStrategy::ALIASED ) + { + const auto& val = *(const T*PTR_NO_ALIAS)( (const char*PTR_NO_ALIAS)this->memcache.GetStoragePointer() + boff ); + this->idcache = vcfg.Get().Identity( val ); + } + else if constexpr ( idstrat == eBitIdentityStorageIdentStrategy::BITFIELD ) + { + T val = this->memcache.template ExtractNumberEndian ( (uint8_t)boff ); + tmp = vcfg.Get().Identity( val ); + id_bytecnt = sizeof(T); + } + return true; + } + } + return false; + }); + if constexpr ( idstrat == eBitIdentityStorageIdentStrategy::BITFIELD ) + { + this->idcache.StoreByBitfield( tmp, id_bytecnt ); + } + this->idcache_pointer = # + } + returnResult: + uint8_t idbyteoff = (uint8_t)( numloc - (uintptr_t)this->idcache_pointer ); + + this->idcache.VisitBitsFrom( idbyteoff, castforward ( cb ) ); + } + + BM_BRUTAL_AINLINE hostFastNumberType Read( hostFastNumberType& val, size_t bytes_left, bool cache_dirty ) noexcept + requires ( write_only == false ) + { + hostFastNumberType result = 0u; + + this->Select( val, bytes_left, + [&]( auto& data ) LAINLINE + { + result = (hostFastNumberType)data; + }, cache_dirty + ); + + return result; + } + BM_BRUTAL_AINLINE void Write( hostFastNumberType& val, hostFastNumberType write_to, size_t bytes_left, bool cache_dirty ) noexcept + requires ( const_type == false ) + { + this->Select( val, bytes_left, + [&]( auto& data ) LAINLINE + { + data = write_to; + }, cache_dirty + ); + } + + BM_AINLINE void Flush( void ) noexcept + { + if constexpr ( const_type == false ) + { + this->FlushIdCache(); + this->memcache.Flush(); + } + else + { + this->Invalidate(); + } + } + BM_AINLINE void Invalidate( void ) noexcept + { + this->idcache.Clear(); + this->memcache.Invalidate(); + } + + BM_AINLINE bool IsValid( void ) const noexcept + { + return ( this->idcache.IsEmpty() == false ); + } + + BM_AINLINE void SetStorageProperty( endian::eSpecificEndian endianness, bool msbfirst ) noexcept + { + this->Flush(); + this->vecman = { endianness, msbfirst }; + } + +private: + using size_feasible_supp_types = typename sizeof_greaterequal_types ::type; + + PlatformBitCache memcache; + variantType idcache; + typename decltype(memcache)::distinct_t *idcache_pointer; + BitVectorizedIdentityManager vecman; +public: + using supportedTypes = size_feasible_supp_types; +}; + +template + requires ( sizeof(containNumberType) >= sizeof(unitNumberType) ) +struct BitRepetitionCache +{ + static constexpr size_t count_contained = sizeof(containNumberType) / sizeof(unitNumberType); + + AINLINE BitRepetitionCache( unitNumberType val ) noexcept + { + BitIncrementalAccessor acc; + + for ( size_t n = 0; n < count_contained; n++ ) + { + acc.WriteBits( val, sizeof(unitNumberType)*8u ); + } + + this->data = acc.GetData(); + } + AINLINE BitRepetitionCache( const BitRepetitionCache& ) = default; + AINLINE BitRepetitionCache( BitRepetitionCache&& ) = default; + + AINLINE BitRepetitionCache& operator = ( const BitRepetitionCache& ) = default; + AINLINE BitRepetitionCache& operator = ( BitRepetitionCache&& ) = default; + + AINLINE const containNumberType& GetData( void ) const noexcept + { + return this->data; + } + +private: + containNumberType data; +}; + +#define BITMANAGER_REQUIREMENTS requires ( write_only == false || mutable_type ) +#define BITMANAGER_TEMPLARGS \ +template typename numberSpecificator = choose_default_number_specificator ::template spec, \ + typelist_type suppTypes = PlatformNumberTypeList, \ + template typename cacheVariantType = BitfieldVariant, \ + eBitIdentityStorageIdentStrategy idstrat = get_default_bit_identity_storage_ident_strategy(), \ + bool write_only = false \ + > BITMANAGER_REQUIREMENTS +#define BITMANAGER_TEMPLARGS_NODEF \ +template typename numberSpecificator, \ + typelist_type suppTypes, \ + template typename cacheVariantType, \ + eBitIdentityStorageIdentStrategy idstrat, \ + bool write_only \ + > BITMANAGER_REQUIREMENTS +#define BITMANAGER_TEMPLUSE + +// Takes a bit array as input. Allows bitwise read and write operations on the input bit array, using the +// optimized classes mentioned previously. +BITMANAGER_TEMPLARGS +struct BitManager +{ + static constexpr bool is_const_bitman = is_const ::value; + + BM_AINLINE BitManager( hostNumberType *buffer, size_t bufSize, size_t numOffset = 0, platformLocalBitcountType bitOffset = 0 ) noexcept + : buffer( buffer ), bufSize( bufSize ), iterator( numOffset, bitOffset ) + { + this->cache.SetStorageProperty( this->storage_endianness, this->storage_msbfirst ); + } + BM_AINLINE BitManager( const BitManager& ) = default; + + BM_AINLINE ~BitManager( void ) + { + if constexpr ( const_type == false ) + { + if (dirty_cache) + { + this->cache.Flush(); + } + } + } + + BM_AINLINE BitManager& operator = ( const BitManager& ) = default; + + BM_AINLINE size_t GetBufferSize( void ) const noexcept { return this->bufSize; } + +private: + typedef BitNumberIteratorForStruct iter_t; + + template + BM_AINLINE void SelectByIndex( size_t idx, callbackType&& cb ) + { + size_t bytes_left = sizeof(hostNumberType) * ( this->bufSize - idx ); + + this->cache.Select( this->buffer[ idx ], bytes_left, (callbackType&&)cb, this->dirty_cache ); + } + +public: + // I have decided to implement a true msbfirst parameter instead of reverse-bits because the reversing of entire hostNumberType bits would conflict + // with the reversing of bit-groups - the so called "byteswap" algorithm - in programming models. + // Read the algorithm proof inside the methods for further details. + + BM_AINLINE void Reset( void ) noexcept + { + this->Flush(); + this->iterator = iter_t(); + } + +private: + template + requires ( unsigned_integral ::type> ) + BM_AINLINE void _PutLoopImpl( const numberType& val, srcIterType& srcIter, iter_t& iter, endIterType& end_iter ) noexcept + requires ( const_type == false ) + { + while ( true ) + { + size_t numOff = iter.getNumberOffset(); + platformLocalBitcountType bitOff = iter.getLocalBitOffset(); + + platformBitCountType avail_bitCnt = ( end_iter - iter ).getTotalBitOffset(); + + if ( avail_bitCnt == 0 ) break; + + platformLocalBitcountType src_bitOff = srcIter.getLocalBitOffset(); + platformBitCountType src_bitCount = ( srcIterType::hostBitCount - src_bitOff ); + + platformLocalBitcountType bitCnt; + bool has_data = false; + + this->SelectByIndex( numOff, + [&]( auto& pnum ) LAINLINE + { + auto numBits = SUB_SIGNP( get_bitcount( pnum ), bitOff ); + + bitCnt = (platformLocalBitcountType)eir::Minimum( numBits, avail_bitCnt, src_bitCount ); + + // TODO: may think about implementing a rolling-replace algorithm to save invocations of the + // ROR/ROL instructions, improving performance. + + replace_bits( pnum, RSHIFT( val, src_bitOff ), bitOff, bitCnt ); + + has_data = true; + } + ); + if ( has_data ) + { + srcIter.addBits( bitCnt ); + iter.addBits( bitCnt ); + + this->dirty_cache = true; + } + } + this->iterator = end_iter; + } +public: + // Can be used across BitManager instances if their "shared-region" is calculated and passed as end-iter. + template requires ( unsigned_integral ::type> ) + BM_AINLINE void PutRepeatableSharedRemainder( const numberType& val, BitNumberIteratorForStruct & srcIter, const BitNumberIteratorForStruct & sharedIter_start, const BitNumberIteratorForStruct & sharedIter_end ) noexcept + { + auto iter = this->iterator; + + decltype(iter) end_iter; + + if constexpr ( byteOptimize ) + { + // Use this if you know that operations execute on multiples of bytes (8 bit packets). + end_iter = bit_iterator_advance_min_bytes( iter, + eir::Tuple( sharedIter_start, sharedIter_end ) + ); + } + else + { + end_iter = bit_iterator_advance_min( iter, + eir::Tuple( sharedIter_start, sharedIter_end ) + ); + } + + this->_PutLoopImpl( val, srcIter, iter, end_iter ); + } + template requires ( unsigned_integral ::type> ) + BM_AINLINE void PutRepeatable( const numberType& val, BitNumberIteratorForStruct & srcIter, const BitNumberIteratorForStruct & srcIter_start, const BitNumberIteratorForStruct & srcIter_end ) noexcept + { + auto iter = this->iterator; + + BitNumberIteratorForStruct dst_enditer( this->bufSize, 0 ); + + decltype(iter) end_iter; + + if constexpr ( byteOptimize ) + { + // Use this if you know that operations execute on multiples of bytes (8 bit packets). + end_iter = bit_iterator_advance_min_bytes( iter, + eir::Tuple( srcIter_start, srcIter_end ), + ( dst_enditer - iter ).getTotalByteOffset() + ); + } + else + { + end_iter = bit_iterator_advance_min( iter, + eir::Tuple( srcIter_start, srcIter_end ), + ( dst_enditer - iter ).getTotalBitOffset() + ); + } + + this->_PutLoopImpl( val, srcIter, iter, end_iter ); + } + template requires ( unsigned_integral ::type> ) + BM_AINLINE void PutSingle( const numberType& val, BitNumberIteratorForStruct & srcIter ) noexcept + requires ( const_type == false ) + { + BitNumberIteratorForStruct src_loopiter( 0, srcIter.getLocalBitOffset() ); + BitNumberIteratorForStruct src_enditer( 1, 0 ); + + this->template PutRepeatable ( val, srcIter, src_loopiter, src_enditer ); + } + template requires ( unsigned_integral ::type> ) + BM_AINLINE void PutPartialBits( const numberType& val, platformLocalBitcountType putBitcnt, BitNumberIteratorForStruct & srcIter ) noexcept + requires ( const_type == false ) + { + auto iter = this->iterator; + + BitNumberIteratorForStruct src_loopiter( 0, srcIter.getLocalBitOffset() ); + BitNumberIteratorForStruct src_enditer( 1, 0 ); + BitNumberIteratorForStruct dst_enditer( this->bufSize, 0 ); + + auto end_iter = bit_iterator_advance_min( iter, + ( src_enditer - src_loopiter ).getTotalBitOffset(), + ( dst_enditer - iter ).getTotalBitOffset(), + putBitcnt + ); + + this->_PutLoopImpl( val, srcIter, iter, end_iter ); + } + template requires ( unsigned_integral ::type> ) + BM_AINLINE void PutPartialBytes( const numberType& val, uint8_t putBytecnt, BitNumberIteratorForStruct & srcIter ) noexcept + requires ( const_type == false ) + { + auto iter = this->iterator; + + BitNumberIteratorForStruct src_loopiter( 0, srcIter.getLocalBitOffset() ); + BitNumberIteratorForStruct src_enditer( 1, 0 ); + BitNumberIteratorForStruct dst_enditer( this->bufSize, 0 ); + + auto end_iter = bit_iterator_advance_min_bytes( iter, + ( src_enditer - src_loopiter ).getTotalByteOffset(), + ( dst_enditer - iter ).getTotalByteOffset(), + putBytecnt + ); + + this->_PutLoopImpl( val, srcIter, iter, end_iter ); + } + template requires ( unsigned_integral ::type> ) + BM_AINLINE void PutSingle( const numberType& val, BitNumberIteratorForStruct & srcIter, endian::eSpecificEndian target_endianness, bool msbfirst = false ) noexcept + requires ( const_type == false ) + { + endian::eSpecificEndian prev_storage_endianness = this->storage_endianness; + bool prev_storage_msbfirst = this->storage_msbfirst; + + this->SetDefaultStorageProperty( target_endianness, msbfirst ); + + this->PutSingle( val, srcIter ); + + this->storage_endianness = prev_storage_endianness; + this->storage_msbfirst = prev_storage_msbfirst; + } + // Only use this function if you know that the put request will complete 100%. + // Otherwise you should use PutEx with the iterator, proceeding until the iterator is at it's end. + template requires ( unsigned_integral ::type> ) + BM_AINLINE void Put( const numberType& val, endian::eSpecificEndian target_endianness = endian::eSpecificEndian::DEFAULT_ENDIAN, bool msbfirst = false ) noexcept + requires ( const_type == false ) + { + BitNumberIteratorForStruct srcIter; + + this->PutSingle( val, srcIter, target_endianness, msbfirst ); + } +private: + template + requires ( write_only == false && unsigned_integral ::type> ) + BM_AINLINE void _FetchLoopImpl( numberType& result, dstIterType& dstIter, iter_t& iter, endIterType& end_iter ) noexcept + { + while ( true ) + { + size_t numOff = iter.getNumberOffset(); + platformLocalBitcountType bitOff = iter.getLocalBitOffset(); + + platformBitCountType avail_bitCnt = ( end_iter - iter ).getTotalBitOffset(); + + if ( avail_bitCnt == 0 ) break; + + platformLocalBitcountType bitCnt; + bool has_data = false; + + this->SelectByIndex( numOff, + [&]( auto& pnum ) LAINLINE + { + auto numBits = SUB_SIGNP( get_bitcount( pnum ), bitOff ); + + bitCnt = (platformLocalBitcountType)eir::Minimum( numBits, avail_bitCnt ); + + auto wbits = extract_bits( pnum, bitOff, bitCnt ); + + result |= LSHIFT( wbits, dstIter.getLocalBitOffset() ); + + has_data = true; + } + ); + if ( has_data ) + { + dstIter.addBits( bitCnt ); + iter.addBits( bitCnt ); + } + } + this->iterator = end_iter; + } +public: + // Can be used across BitManager instances if their "shared-region" is calculated and passed as end-iter. + template + requires ( write_only == false && unsigned_integral ::type> ) + BM_AINLINE void FetchSingleSharedRemainder( numberType& result, BitNumberIteratorForStruct & dstIter, const sharedEndIterType& sharedEndIter ) noexcept + { + auto iter = this->iterator; + + BitNumberIteratorForStruct dst_loopiter( 0, dstIter.getLocalBitOffset() ); + BitNumberIteratorForStruct dst_enditer( 1, 0 ); + + decltype(iter) end_iter; + + if constexpr ( byteOptimize ) + { + // Use this if you know that operations execute on multiples of bytes (8 bit packets). + end_iter = bit_iterator_advance_min_bytes( iter, + ( dst_enditer - dst_loopiter ).getTotalByteOffset(), + eir::Tuple( dstIter, sharedEndIter ) + ); + } + else + { + end_iter = bit_iterator_advance_min( iter, + ( dst_enditer - dst_loopiter ).getTotalBitOffset(), + eir::Tuple( dstIter, sharedEndIter ) + ); + } + + this->_FetchLoopImpl( result, dstIter, iter, end_iter ); + } + template + requires ( write_only == false && unsigned_integral ::type> ) + BM_AINLINE void FetchSingle( numberType& result, BitNumberIteratorForStruct & dstIter ) noexcept + { + auto iter = this->iterator; + + BitNumberIteratorForStruct dst_loopiter( 0, dstIter.getLocalBitOffset() ); + BitNumberIteratorForStruct dst_enditer( 1, 0 ); + BitNumberIteratorForStruct src_enditer( this->bufSize, 0 ); + + decltype(iter) end_iter; + + if constexpr ( byteOptimize ) + { + // Use this if you know that operations execute on multiples of bytes (8 bit packets). + end_iter = bit_iterator_advance_min_bytes( iter, + ( dst_enditer - dst_loopiter ).getTotalByteOffset(), + ( src_enditer - iter ).getTotalByteOffset() + ); + } + else + { + end_iter = bit_iterator_advance_min( iter, + ( dst_enditer - dst_loopiter ).getTotalBitOffset(), + ( src_enditer - iter ).getTotalBitOffset() + ); + } + + this->_FetchLoopImpl( result, dstIter, iter, end_iter ); + } + template + requires ( write_only == false && unsigned_integral ::type> ) + BM_AINLINE void FetchPartialBits( numberType& result, platformLocalBitcountType fetchBitCnt, BitNumberIteratorForStruct & dstIter ) noexcept + { + auto iter = this->iterator; + + BitNumberIteratorForStruct dst_loopiter( 0, dstIter.getLocalBitOffset() ); + BitNumberIteratorForStruct dst_enditer( 1, 0 ); + BitNumberIteratorForStruct src_enditer( this->bufSize, 0 ); + + auto end_iter = bit_iterator_advance_min( iter, + ( dst_enditer - dst_loopiter ).getTotalBitOffset(), + ( src_enditer - iter ).getTotalBitOffset(), + fetchBitCnt + ); + + this->_FetchLoopImpl( result, dstIter, iter, end_iter ); + } + template + requires ( write_only == false && unsigned_integral ::type> ) + BM_AINLINE void FetchPartialBytes( numberType& result, uint8_t fetchByteCnt, BitNumberIteratorForStruct & dstIter ) noexcept + { + auto iter = this->iterator; + + BitNumberIteratorForStruct dst_loopiter( 0, dstIter.getLocalBitOffset() ); + BitNumberIteratorForStruct dst_enditer( 1, 0 ); + BitNumberIteratorForStruct src_enditer( this->bufSize, 0 ); + + auto end_iter = bit_iterator_advance_min_bytes( iter, + ( dst_enditer - dst_loopiter ).getTotalByteOffset(), + ( src_enditer - iter ).getTotalByteOffset(), + fetchByteCnt + ); + + this->_FetchLoopImpl( result, dstIter, iter, end_iter ); + } + template + requires ( write_only == false && unsigned_integral ::type> ) + BM_AINLINE void FetchSingle( numberType& result, BitNumberIteratorForStruct & dstIter, endian::eSpecificEndian target_endianness, bool msbfirst = false ) noexcept + { + endian::eSpecificEndian prev_storage_endianness = this->storage_endianness; + bool prev_storage_msbfirst = this->storage_msbfirst; + + this->SetDefaultStorageProperty( target_endianness, msbfirst ); + + // Cannot throw exceptions so we are safe. + this->FetchSingle( result, dstIter ); + + this->storage_endianness = prev_storage_endianness; + this->storage_msbfirst = prev_storage_msbfirst; + } + // Only use this function if you know that the fetch request will complete 100%. + // Otherwise you should use FetchEx with the iterator, proceeding until the iterator is at it's end. + template + requires ( write_only == false && unsigned_integral ::type> ) + BM_AINLINE numberType Fetch( endian::eSpecificEndian target_endianness = endian::eSpecificEndian::DEFAULT_ENDIAN, bool msbfirst = false ) noexcept + { + BitNumberIteratorForStruct dstIter; + + typename no_volatile ::type result = 0; + this->FetchSingle( result, dstIter, target_endianness, msbfirst ); + + return result; + } + inline void Flush( void ) noexcept + { + if constexpr ( const_type == false ) + { + if (this->dirty_cache) + { + this->cache.Flush(); + + this->dirty_cache = false; + } + else + { + this->cache.Invalidate(); + } + } + else + { + this->cache.Invalidate(); + } + } + + BM_AINLINE bool IsAtEnd( void ) const noexcept + { + return ( this->iterator.getNumberOffset() == this->bufSize ); + } + + BM_AINLINE void SetDefaultStorageProperty( endian::eSpecificEndian endianness, bool msbfirst ) noexcept + { + if (this->storage_endianness == endianness && this->storage_msbfirst == msbfirst) return; + + this->cache.SetStorageProperty( endianness, msbfirst ); + this->storage_endianness = endianness; + this->storage_msbfirst = msbfirst; + } + + BM_AINLINE void SetIterator( iter_t iter ) noexcept + { + this->iterator = castmove( iter ); + } + BM_AINLINE iter_t GetIterator( void ) const noexcept + { + return this->iterator; + } + + BM_AINLINE iter_t GetRemainderIterator( void ) const noexcept + { + return ( iter_t( this->bufSize, 0 ) - this->iterator ); + } + +private: + hostNumberType *buffer; + size_t bufSize; + iter_t iterator; + + // Endian properties of storage. + endian::eSpecificEndian storage_endianness = endian::eSpecificEndian::DEFAULT_ENDIAN; + bool storage_msbfirst = false; + + BitIdentityStorage cache; + bool dirty_cache = false; +public: + using supportedTypes = typename decltype(BitManager::cache)::supportedTypes; +}; +template +struct is_bitmanager : false_type {}; +BITMANAGER_TEMPLARGS_NODEF +struct is_bitmanager : true_type {}; +template requires ( is_bitmanager ::type>::value ) +struct is_bitmanager : true_type {}; + +template +concept bitmanager_type = is_bitmanager ::value; + +// Namespace that contains useful code-graph templates for use with BitManager instances. +namespace BitManagerTemplates +{ + +// Performs an one way transfer operation, fetching data from src_bitman and pushing it into dst_bitman. +// Use the commit operation to perform the hardware send request. +template + requires ( eir::typelist_shared ::type::count > 0 && dstBitManType::is_const_bitman == false && + requires ( commitCallbackType cb ) { cb(); } ) +BM_AINLINE void Send( srcBitManType& src_bitman, dstBitManType& dst_bitman, commitCallbackType&& cb ) + noexcept(requires(commitCallbackType cb) { { cb() } noexcept; }) +{ + using txitem_t = typename eir::biggest_type ::type>::type; + + while ( src_bitman.IsAtEnd() == false ) + { + while ( dst_bitman.IsAtEnd() == false && src_bitman.IsAtEnd() == false ) + { + BitNumberIteratorForStruct iter; + txitem_t raw = 0u; + src_bitman.FetchSingle( raw, iter ); + BitNumberIteratorForStruct dst_iter; + dst_bitman.PutPartialBytes( raw, (uint8_t)iter.getTotalByteOffset(), dst_iter ); + } + dst_bitman.Flush(); + // Commit. + cb(); + dst_bitman.SetIterator({}); + } +} + +template + requires requires ( commitCallbackType cb, const BitNumberIteratorForStruct ::type> iter ) { cb( iter ); } +BM_AINLINE void SendFixed( dstNumberType *txbuf, size_t txbuf_cnt, srcBitManType& src_bitMan, commitCallbackType&& cb ) + noexcept(requires ( commitCallbackType cb, const BitNumberIteratorForStruct ::type> iter ) { { cb( iter ) } noexcept; }) +{ + while ( src_bitMan.IsAtEnd() == false ) + { + BitNumberIteratorForStruct ::type> dst_iter; + while ( src_bitMan.IsAtEnd() == false && dst_iter.getNumberOffset() < txbuf_cnt ) + { + typename base_type ::type tmp = 0u; + size_t n = dst_iter.getNumberOffset(); + src_bitMan.FetchSingle( tmp, dst_iter ); + txbuf[n] = tmp; + } + // Commit. + cb( make_const_ref( dst_iter ) ); + } +} + +// Similar to the Send template but fills the buffer using repeated data. +template + requires ( bitmanType::is_const_bitman == false && + requires ( commitCallbackType cb ) { cb(); } ) +BM_AINLINE void RepeatSendCountTo( const putNumberType& val, const countNumberType& count_to, bitmanType& dst_bitman, commitCallbackType&& cb ) + noexcept(requires ( commitCallbackType cb ) { { cb() } noexcept; }) +{ + using bigtx_t = typename biggest_type ::type; + + BitRepetitionCache repcache( val ); + + BitNumberIteratorForStruct val_iter( 0, 0 ); + BitNumberIteratorForStruct val_enditer( count_to / decltype(repcache)::count_contained, 0 ); + + while ( val_iter != val_enditer ) + { + dst_bitman.PutRepeatable( repcache.GetData(), val_iter, val_iter, val_enditer ); + dst_bitman.Flush(); + // Commit. + cb(); + dst_bitman.SetIterator({}); + } +} + +// Performs an one-way receive operation, using a "kickoff"/fill callback. +// Inside the fill callback you can also send data, but this template is mainly designed for reception. +template + requires ( recvBitManType::is_const_bitman == false ) +BM_AINLINE void Receive( recvBitManType& recv_bitman, txbufBitManType& txbuf_bitman, kickoffCallbackType&& kickoffCB ) +{ + using txitem_t = typename eir::biggest_type ::type>::type; + + while ( recv_bitman.IsAtEnd() == false ) + { + // Perform the hardware operation that fills the txbuf_bitman. + auto sharedEndIter = Minimum( recv_bitman.GetRemainderIterator(), txbuf_bitman.GetRemainderIterator() ); + kickoffCB( make_const_ref( sharedEndIter ) ); + // Fetch the data from txbuf_bitman into recv_bitman. + BitNumberIteratorForStruct dst_iter; + BitNumberIteratorForStruct iter; + while ( dst_iter != sharedEndIter ) + { + txitem_t raw = 0u; + txbuf_bitman.FetchSingleSharedRemainder( raw, iter, sharedEndIter ); + recv_bitman.PutRepeatableSharedRemainder( raw, dst_iter, dst_iter, iter ); + } + txbuf_bitman.Reset(); + } +} + +} // namespace BitManagerTemplates + +} // namespace eir + +#endif //_BIT_MANAGE_HEADER_ diff --git a/Marlin/src/HAL/ESP32/sdk/BitManip.h b/Marlin/src/HAL/ESP32/sdk/BitManip.h new file mode 100644 index 000000000000..df7a04c9ac5b --- /dev/null +++ b/Marlin/src/HAL/ESP32/sdk/BitManip.h @@ -0,0 +1,513 @@ +/***************************************************************************** +* +* PROJECT: Eir SDK +* FILE: eirrepo/sdk/BitManip.h +* PURPOSE: Low-level bit manipulation acceleration helpers +* +* Find the Eir SDK at: https://osdn.net/projects/eirrepo/ +* +*****************************************************************************/ + +#ifndef _EIR_BITMANIP_HEADER_ +#define _EIR_BITMANIP_HEADER_ + +#include "MacroUtils.h" +#include "PlatformStrategy.h" +#include "Arith.h" + +#ifdef _DEBUG +#include +#endif + +namespace eir +{ + +template +AINLINE constexpr unsignedNumberType ROTL( unsignedNumberType value, platformLocalBitcountType rotBy ) noexcept +{ +#ifdef _PLATFORM_HAS_FAST_BITROTATE + if constexpr ( __platform_number_supports_brotate ::value ) + { + return __platform_brotate_l( value, rotBy ); + } + else + { +#endif + constexpr platformLocalBitcountType bitCount = sizeof(value) * 8u; + + return ( value << rotBy ) | ( value >> ( bitCount - rotBy ) ); +#ifdef _PLATFORM_HAS_FAST_BITROTATE + } +#endif +} +template +AINLINE constexpr unsignedNumberType ROTR( unsignedNumberType value, platformLocalBitcountType rotBy ) noexcept +{ +#ifdef _PLATFORM_HAS_FAST_BITROTATE + if constexpr ( __platform_number_supports_brotate ::value ) + { + return __platform_brotate_r( value, rotBy ); + } + else + { +#endif + constexpr platformLocalBitcountType bitCount = sizeof(value) * 8u; + + return ( value >> rotBy ) | ( value << ( bitCount - rotBy ) ); +#ifdef _PLATFORM_HAS_FAST_BITROTATE + } +#endif +} + +template +struct is_bitfield_view : public false_type {}; +template requires ( is_bitfield_view ::type>::value ) +struct is_bitfield_view : public true_type {}; +template +struct plain_type_bitfield : public plain_type {}; +template requires ( is_bitfield_view ::value && is_plain_type ::value == false ) +struct plain_type_bitfield : public plain_type_bitfield ::type> {}; + +// Replaces bits inside of a single unsigned integer. +template + requires ( is_unsigned_integral ::type>::value && + is_unsigned_integral ::type>::value ) +AINLINE constexpr void replace_bits( dstNumType& dst, const srcNumType& src, platformLocalBitcountType bitoff, platformLocalBitcountType bitcnt ) noexcept; + +// Extracts bits from a single unsigned integer. +template + requires ( is_unsigned_integral ::type>::value ) +AINLINE constexpr typename plain_type_bitfield ::type extract_bits( const numberType& val, platformLocalBitcountType bitoff, platformLocalBitcountType bitcnt ) noexcept; + +// numberType has to be unsigned integer. +template +struct BitfieldNumberSelectionView +{ + template friend struct StaticBitfieldNumberSelectionView; + + AINLINE BitfieldNumberSelectionView( numberType *num, platformLocalBitcountType bitoff = 0u, platformLocalBitcountType bitcnt = sizeof(numberType)*8u ) noexcept + : num( num ), bitoff( bitoff ), bitcnt( bitcnt ) + { + return; + } + AINLINE BitfieldNumberSelectionView( const BitfieldNumberSelectionView& view, platformLocalBitcountType bitoff, platformLocalBitcountType bitcnt = sizeof(numberType)*8u ) noexcept + : BitfieldNumberSelectionView( view.num, bitoff, bitcnt ) + { + return; + } + AINLINE BitfieldNumberSelectionView( const BitfieldNumberSelectionView& ) = default; + + AINLINE void Write( typename plain_type ::type val ) noexcept + { + replace_bits( *num, val, this->bitoff, this->bitcnt ); + } + + AINLINE typename plain_type ::type Read( void ) const noexcept + { + return extract_bits( *num, this->bitoff, this->bitcnt ); + } + + AINLINE platformLocalBitcountType GetBitOffset( void ) const noexcept + { + return bitoff; + } + AINLINE platformLocalBitcountType GetBitCount( void ) const noexcept + { + return bitcnt; + } + + // Helpers for nicety. + AINLINE BitfieldNumberSelectionView& operator = ( typename plain_type ::type val ) noexcept + { + this->Write( val ); + return *this; + } + AINLINE operator typename plain_type ::type ( void ) const noexcept + { + return this->Read(); + } + + AINLINE platformLocalBitcountType GetRegionStart( void ) const noexcept + { + return this->bitoff; + } + AINLINE platformLocalBitcountType GetRegionEnd( void ) const noexcept + { + return this->bitoff + this->bitcnt; + } + +private: + numberType *num; + platformLocalBitcountType bitoff; + platformLocalBitcountType bitcnt; +}; + +template +struct is_bitfield_view > : public true_type {}; + +template +struct StaticBitfieldNumberSelectionView +{ + static constexpr platformLocalBitcountType bitcnt = sizeof(insideNumberType)*8u; + + AINLINE StaticBitfieldNumberSelectionView( numberType *num, platformLocalBitcountType bitoff = 0u ) noexcept + : num( num ), bitoff( bitoff ) + { + return; + } + AINLINE StaticBitfieldNumberSelectionView( BitfieldNumberSelectionView *bview ) noexcept + : num( bview->num ), bitoff( bview->bitoff ) + { + return; + } + AINLINE StaticBitfieldNumberSelectionView( const StaticBitfieldNumberSelectionView& ) = default; + + AINLINE void Write( typename plain_type ::type val ) noexcept + { + replace_bits( *num, val, this->bitoff, bitcnt ); + } + + AINLINE typename plain_type ::type Read( void ) const noexcept + { + return (typename plain_type ::type)extract_bits( *num, this->bitoff, bitcnt ); + } + + AINLINE constexpr platformLocalBitcountType GetBitCount( void ) const noexcept + { + return bitcnt; + } + + // Helpers for nicety. + AINLINE StaticBitfieldNumberSelectionView& operator = ( typename plain_type ::type val ) noexcept + { + this->Write( val ); + return *this; + } + AINLINE operator typename plain_type ::type ( void ) const noexcept + { + return this->Read(); + } + + AINLINE platformLocalBitcountType GetRegionStart( void ) const noexcept + { + return this->bitoff; + } + AINLINE platformLocalBitcountType GetRegionEnd( void ) const noexcept + { + return this->bitoff + bitcnt; + } + + template + AINLINE BitfieldNumberSelectionView & SharedBitRegion( platformLocalBitcountType right_start, platformLocalBitcountType right_end ) noexcept + { + platformLocalBitcountType left_start = this->bitoff; + platformLocalBitcountType left_end = left_start + bitcnt; + + return BitfieldNumberSelectionView( this->num, left_start < right_start ? left_start : right_start, left_end < right_end ? left_end : right_end ); + } + +private: + numberType *num; + platformLocalBitcountType bitoff; +}; + +template +struct is_bitfield_view > : public true_type {}; + +// Helper to abstract away bitfield type checking. +template +struct plain_type_bitfield > : public plain_type {}; +template +struct plain_type_bitfield > : public plain_type {}; + +template +AINLINE constexpr platformLocalBitcountType get_bitcount( const numberType& v ) noexcept +{ + if constexpr ( is_bitfield_view ::value ) + { + return v.GetBitCount(); + } + else + { + return sizeof(numberType)*8u; + } +} + +template + requires ( is_unsigned_integral ::type>::value && + is_unsigned_integral ::type>::value ) +AINLINE constexpr void replace_bits( dstNumType& dst, const srcNumType& src, platformLocalBitcountType bitoff, platformLocalBitcountType bitcnt ) noexcept +{ + // bitoff between 0 and sizeof(numberType)*8u + // bitcnt between 1 and sizeof(numberType)*8u + + platformLocalBitcountType src_bitcount = get_bitcount( src ); + platformLocalBitcountType dst_bitcount = get_bitcount( dst ); + +#ifdef _DEBUG + assert( bitcnt <= dst_bitcount ); +#endif + + if ( bitcnt >= dst_bitcount ) + { + dst = (typename plain_type_bitfield ::type)src; + } + else + { + typedef typename plain_type_bitfield ::type srcFastNumType; + typedef typename plain_type_bitfield ::type dstFastNumType; + + // In case of bitfield, do not modify the original value, as the bitfield is a view. + srcFastNumType src_val = src; + + dstFastNumType dst_bitmask; + if ( bitcnt < src_bitcount ) + { + srcFastNumType bitmask = ((srcFastNumType)1u<::value ) + { + dst_val = (dstFastNumType)src_val; + tmp = __platform_brotate_r( dst, bitoff ); + } + else + { +#endif + dst_bitmask <<= bitoff; + dst_val = ((dstFastNumType)src_val << bitoff); + tmp = dst; +#ifdef _PLATFORM_HAS_FAST_BITROTATE + } +#endif + tmp &= ~dst_bitmask; + tmp |= dst_val; +#ifdef _PLATFORM_HAS_FAST_BITROTATE + if constexpr ( __platform_number_supports_brotate ::value ) + { + dst = __platform_brotate_l( tmp, bitoff ); + } + else + { +#endif + dst = tmp; +#ifdef _PLATFORM_HAS_FAST_BITROTATE + } +#endif + } +} + +template + requires ( is_unsigned_integral ::type>::value ) +AINLINE constexpr typename plain_type_bitfield ::type extract_bits( const numberType& val, platformLocalBitcountType bitoff, platformLocalBitcountType bitcnt ) noexcept +{ + // bitoff between 0 and sizeof(numberType)*8u + // bitcnt between 1 and sizeof(numberType)*8u + + if constexpr ( is_bitfield_view ::value ) + { + return extract_bits( val.Read(), bitoff, bitcnt ); + } + else + { + if ( bitcnt == sizeof(numberType)*8u ) + { + return val; + } + else + { +#ifdef _PLATFORM_HAS_FAST_BITEXTRACT + if constexpr ( __platform_number_supports_bitextract ::value ) + { + return __platform_bitextract( val, bitoff, bitcnt ); + } + else + { +#endif + typedef typename no_volatile ::type fastNumberType; + + fastNumberType bitmask = ((fastNumberType)1u<>= bitoff; + tmp &= bitmask; + return tmp; + } +#ifdef _PLATFORM_HAS_FAST_BITEXTRACT + } +#endif + } +} + +#if defined(_PLATFORM_HAS_FAST_BITREVERSE) +AINLINE constexpr platformNativeWordType reverse_bitorder( platformNativeWordType v ) noexcept +{ + return __platform_bitreverse( v ); +} +template +AINLINE constexpr numberType reverse_bitorder( numberType v ) noexcept +{ + // IDEA: implement the other lesser-sized integer versions using the native word variant and then just perform + // a bit-shift to get the result, resulting in a two-op reverse_bitorder! + + // We assume that all numberType types are sized a power-of-two, meaning that each bigger sized number is + // also at least double the size of platformNativeWordType. + // This optional constexpr-if is fine because both code-graphs would compile anyway. + if constexpr (sizeof(v) > sizeof(platformNativeWordType)) + { + const size_t num_units = sizeof(v) / sizeof(platformNativeWordType); + + numberType result = 0u; + + for (size_t n = 0; n < num_units; n++) + { + platformNativeWordType buf = (platformNativeWordType)( v >> (n * (sizeof(platformNativeWordType)*8u)) ); + buf = __platform_bitreverse(buf); + result |= (numberType)buf << ( (num_units-1) - n ) * (sizeof(platformNativeWordType)*8u); + } + } + else + { + platformNativeWordType buf = v; + buf = __platform_bitreverse(buf); + return (numberType)( buf >> ((sizeof(platformNativeWordType) - sizeof(v)) * 8u) ); + } +} +#else +// Slow but generic variant. +template +constexpr AINLINE numberType reverse_bitorder( numberType v ) noexcept +{ + // MSVC cannot constant evaluate this function. Just wow. + numberType result = 0u; + + for ( platformLocalBitcountType n = 0; n < (platformLocalBitcountType)(sizeof(numberType) * 8u); n++ ) + { + result <<= 1; + result |= v & 0x1; + v >>= 1; + } + return result; +} +#endif + +template requires ( unsigned_integral ::type> ) +struct BitIncrementalAccessor +{ +private: + using fastNumberType = typename nospecmod_type ::type; + +public: + AINLINE BitIncrementalAccessor( void ) noexcept + : data( 0u ), bitoff( 0u ) + {} + AINLINE BitIncrementalAccessor( const BitIncrementalAccessor& ) = default; + AINLINE BitIncrementalAccessor( BitIncrementalAccessor&& ) = default; + + AINLINE BitIncrementalAccessor& operator = ( const BitIncrementalAccessor& ) = default; + AINLINE BitIncrementalAccessor& operator = ( BitIncrementalAccessor&& ) = default; + + AINLINE void SetData( const numberType& data ) noexcept + { + this->data = data; + this->bitoff = 0u; + } + + AINLINE fastNumberType GetData( void ) const noexcept + { +#ifdef _PLATFORM_HAS_FAST_BITROTATE + if constexpr ( mutable_type && __platform_number_supports_brotate ::value ) + { + if ( this->bitoff == 0 ) + { + return this->data; + } + else + { + return __platform_brotate_l( this->data, this->bitoff ); + } + } + else + { +#endif + return this->data; +#ifdef _PLATFORM_HAS_FAST_BITROTATE + } +#endif + } + + template + requires ( mutable_type && sizeof(writeNumType) <= sizeof(numberType) ) + AINLINE void WriteBits( writeNumType val, unsigned int bitcnt ) noexcept + { +#ifdef _PLATFORM_HAS_FAST_BITROTATE + if constexpr ( __platform_number_supports_brotate ::value ) + { + if ( bitcnt == sizeof(numberType)*8u ) + { + this->data = val; + } + else + { + fastNumberType data = this->data; + fastNumberType bmask = ( (fastNumberType)1u << bitcnt ) - 1; + data &= ~bmask; + data |= ( val & (writeNumType)bmask ); + this->data = __platform_brotate_r( data, bitcnt ); + } + } + else + { +#endif + replace_bits( this->data, val, this->bitoff, (platformLocalBitcountType)bitcnt ); +#ifdef _PLATFORM_HAS_FAST_BITROTATE + } +#endif + this->bitoff = ( this->bitoff + bitcnt ) % ( sizeof(numberType)*8u ); + } + + template requires ( sizeof(readNumType) <= sizeof(numberType) ) + AINLINE readNumType ReadBits( unsigned int bitcnt ) noexcept + { + readNumType val; +#ifdef _PLATFORM_HAS_FAST_BITROTATE + if constexpr ( mutable_type && __platform_number_supports_brotate ::value ) + { + if ( bitcnt == sizeof(numberType)*8u ) + { + val = this->data; + } + else + { + fastNumberType data = this->data; + fastNumberType bmask = ( (fastNumberType)1u << bitcnt ) - 1; + val = ( data & bmask ); + this->data = __platform_brotate_r( data, bitcnt ); + } + } + else + { +#endif + val = (readNumType)extract_bits( this->data, this->bitoff, (platformLocalBitcountType)bitcnt ); +#ifdef _PLATFORM_HAS_FAST_BITROTATE + } +#endif + this->bitoff = ( this->bitoff + bitcnt ) % ( sizeof(numberType)*8u ); + return val; + } + +private: + numberType data; + unsigned int bitoff; +}; + +} // namespace eir + +#endif //_EIR_BITMANIP_HEADER_ diff --git a/Marlin/src/HAL/ESP32/sdk/Compare.h b/Marlin/src/HAL/ESP32/sdk/Compare.h new file mode 100644 index 000000000000..c80cc65485f8 --- /dev/null +++ b/Marlin/src/HAL/ESP32/sdk/Compare.h @@ -0,0 +1,229 @@ +/***************************************************************************** +* +* PROJECT: Eir SDK +* FILE: eirrepo/sdk/Compare.h +* PURPOSE: Comparison handling helpers. +* +* Find the Eir SDK at: https://osdn.net/projects/eirrepo/ +* +*****************************************************************************/ + +#ifndef _EIRSDK_COMPARE_HEADER_ +#define _EIRSDK_COMPARE_HEADER_ + +#include "MacroUtils.h" +#include "MetaHelpers.h" + +#if __has_include() +#include +#endif + +namespace eir +{ + +// Comparison results. +enum class eCompResult +{ + LEFT_LESS, + EQUAL, + LEFT_GREATER +}; + +#if defined(__cpp_impl_three_way_comparison) +template +static AINLINE orderingTypeName cmpres_to_ordering( eCompResult res ) +{ + switch( res ) + { + case eCompResult::LEFT_LESS: + return orderingTypeName::less; + case eCompResult::LEFT_GREATER: + return orderingTypeName::greater; + default: break; + } + + return orderingTypeName::equivalent; +} +#endif + +AINLINE eCompResult flip_comp_result( eCompResult res ) noexcept +{ + if ( res == eCompResult::LEFT_LESS ) + { + return eCompResult::LEFT_GREATER; + } + else if ( res == eCompResult::LEFT_GREATER ) + { + return eCompResult::LEFT_LESS; + } + + return eCompResult::EQUAL; +} + +#define EIR_VALCMP( left, right ) \ + { \ + auto cmpRes = eir::DefaultValueCompare( left, right ); \ + if ( cmpRes != eir::eCompResult::EQUAL ) \ + { \ + return cmpRes; \ + } \ + } +#define EIR_VALCMP_LT( _cmpVal ) \ + { \ + eir::eCompResult cmpVal = _cmpVal; \ + if ( cmpVal != eir::eCompResult::EQUAL ) \ + { \ + return ( cmpVal == eir::eCompResult::LEFT_LESS ); \ + } \ + } + +template +concept less_than_comparable = requires ( A a, B b ) { { a < b } -> same_as ; }; +template +concept nothrow_less_than_comparable = requires ( A a, B b ) { { a < b } noexcept -> same_as ; }; + +template +concept greater_than_comparable = requires ( A a, B b ) { { a > b } -> same_as ; }; +template +concept nothrow_greater_than_comparable = requires ( A a, B b ) { { a > b } noexcept -> same_as ; }; + +template +concept equality_comparable = requires ( A a, B b ) { { a == b } -> same_as ; }; +template +concept nothrow_equality_comparable = requires ( A a, B b ) { { a == b } noexcept -> same_as ; }; + +template +concept three_way_comparable = +#if defined(__cpp_impl_three_way_comparison) + requires( LT l, RT r ) { l <=> r; }; +#else + less_than_comparable && equality_comparable && greater_than_comparable ; +#endif +template +concept nothrow_three_way_comparable = +#if defined(__cpp_impl_three_way_comparison) + requires( LT l, RT r ) { { l <=> r } noexcept; }; +#else + nothrow_less_than_comparable && nothrow_equality_comparable && nothrow_greater_than_comparable ; +#endif + +// Basic function. +template requires ( three_way_comparable ) +AINLINE eCompResult DefaultValueCompare( const leftType& left, const rightType& right ) noexcept(nothrow_three_way_comparable ) +{ +#if defined(__cpp_impl_three_way_comparison) + auto wo = ( left <=> right ); + + if ( std::is_lt( wo ) ) + { + return eCompResult::LEFT_LESS; + } + else if ( std::is_gt( wo ) ) + { + return eCompResult::LEFT_GREATER; + } +#else + if ( left < right ) + { + return eCompResult::LEFT_LESS; + } + else if ( left > right ) + { + return eCompResult::LEFT_GREATER; + } +#endif + + // TODO: think about the case of comparing floats of the "partial ordering" scenario (NaN, etc). + + return eCompResult::EQUAL; +} + +namespace CompareUtils +{ + +template +struct select_minimum_target_type : types_find_conversion_target > {}; +template +struct select_minimum_target_type : smallest_type {}; + +} // namespace CompareUtils + +template +struct types_less_than_comparable : true_type {}; +template +struct types_less_than_comparable > : types_less_than_comparable {}; +template +struct types_less_than_comparable + : conditional && (less_than_comparable && ...), + types_less_than_comparable , + false_type + >::type {}; + +template +struct types_nothrow_less_than_comparable : true_type {}; +template +struct types_nothrow_less_than_comparable > : types_nothrow_less_than_comparable {}; +template +struct types_nothrow_less_than_comparable + : conditional && (nothrow_less_than_comparable && ...), + types_nothrow_less_than_comparable , + false_type + >::type {}; + +template + requires ( sizeof...(numberTypes) > 0 && types_find_conversion_target ::type...>>::value && types_less_than_comparable ::type...>::value ) +AINLINE auto Minimum( numberTypes&&... values ) + noexcept(types_nothrow_less_than_comparable ::type...>::value) +{ + typename types_find_conversion_target ::type...>>::type result = + select_from <0> ( castforward ( values )... ); + + auto metalamb = [&] ( index_sequence ) LAINLINE + { + auto lamb = [&] ( T&& val ) LAINLINE + { + if constexpr ( N > 0 ) + { + if ( val < result ) + { + result = castforward ( val ); + } + } + }; + ( lamb.template operator() ( castforward ( values ) ), ... ); + }; + metalamb( index_sequence_until () ); + + return (typename CompareUtils::select_minimum_target_type ::type...>::type)result; +} + +template + requires ( sizeof...(numberTypes) > 0 && types_find_conversion_target ::type...>>::value && types_less_than_comparable ::type...>::value ) +AINLINE auto Maximum( numberTypes&&... values ) + noexcept(types_nothrow_less_than_comparable ::type...>::value) +{ + typename types_find_conversion_target ::type...>>::type result = + select_from <0> ( castforward ( values )... ); + + auto metalamb = [&] ( index_sequence ) LAINLINE + { + auto lamb = [&] ( T&& val ) LAINLINE + { + if constexpr ( N > 0 ) + { + if ( result < val ) + { + result = castforward ( val ); + } + } + }; + ( lamb.template operator() ( castforward ( values ) ), ... ); + }; + metalamb( index_sequence_until () ); + + return result; +} + +} // namespace eir + +#endif //_EIRSDK_COMPARE_HEADER_ diff --git a/Marlin/src/HAL/ESP32/sdk/Endian.h b/Marlin/src/HAL/ESP32/sdk/Endian.h new file mode 100644 index 000000000000..0a21acc3e689 --- /dev/null +++ b/Marlin/src/HAL/ESP32/sdk/Endian.h @@ -0,0 +1,256 @@ +/***************************************************************************** +* +* PROJECT: Eir SDK +* FILE: eirrepo/sdk/Endian.h +* PURPOSE: Endianness utilities header +* +* Find the Eir SDK at: https://osdn.net/projects/eirrepo/ +* +*****************************************************************************/ + +#ifndef _ENDIAN_COMPAT_HEADER_ +#define _ENDIAN_COMPAT_HEADER_ + +#include "MacroUtils.h" +#include "PlatformStrategy.h" // for _PLATFORM_FIXED_ENDIANNESS, intrinsics + +// For the inline functions. +#include +#include // for (u)int8/16/32/64_t + +#include +#if __has_include() +#include +#endif + +namespace eir +{ + +// Endianness compatibility definitions. +namespace endian +{ + +#ifdef _PLATFORM_FIXED_ENDIANNESS +#define _ENDIAN_CONSTEXPR constexpr +#else +#define _ENDIAN_CONSTEXPR +#endif + +#if defined(_PLATFORM_FIXED_ENDIANNESS) && defined(__cpp_if_constexpr) +#define _ENDIAN_IF_CONSTEXPR constexpr +#endif + +#if defined(__GNUC__) +#undef LITTLE_ENDIAN +#undef BIG_ENDIAN +#endif + + enum class eSpecificEndian + { + LITTLE_ENDIAN, + BIG_ENDIAN, +#if defined(_PLATFORM_FIXED_ENDIANNESS_ENFORCE_LE) + DEFAULT_ENDIAN = LITTLE_ENDIAN +#elif defined(_PLATFORM_FIXED_ENDIANNESS_ENFORCE_BE) + DEFAULT_ENDIAN = BIG_ENDIAN +#else + // Most of the systems are little-endian nowadays, which has advantages over big-endian. + DEFAULT_ENDIAN = LITTLE_ENDIAN +#endif + }; + + AINLINE static _ENDIAN_CONSTEXPR eSpecificEndian get_current_endianness( void ) noexcept + { +#ifdef _PLATFORM_FIXED_ENDIANNESS +#if defined(_PLATFORM_FIXED_ENDIANNESS_ENFORCE_LE) + return eSpecficEndian::LITTLE_ENDIAN; +#elif defined(_PLATFORM_FIXED_ENDIANNESS_ENFORCE_BE) + return eSpecificEndian::BIG_ENDIAN; +#else + // This does only make sense if the platform does specify endianness. + static_assert( std::endian::native == std::endian::little || std::endian::native == std::endian::big ); + + // Thanks to new C++ features we have this one in the bag! + return ( std::endian::native == std::endian::little ) ? eSpecificEndian::LITTLE_ENDIAN : eSpecificEndian::BIG_ENDIAN; +#endif +#else + // Calculate the endianness dynamically at run-time. + union + { + uint16_t val = 0x0102; + uint8_t low; + }; + return ( low == 0x02 ) ? eSpecificEndian::LITTLE_ENDIAN : eSpecificEndian::BIG_ENDIAN; +#endif + } + + AINLINE static _ENDIAN_CONSTEXPR bool is_little_endian( void ) noexcept + { + return ( get_current_endianness() == eSpecificEndian::LITTLE_ENDIAN ); + } + + template + AINLINE constexpr typename base_type ::type byte_swap_fast( numberType val ) noexcept + { +#ifdef _PLATFORM_HAS_FAST_BYTESWAP + if constexpr ( __platform_number_supports_byteswap ::value ) + { + return __platform_byteswap( val ); + } + else + { +#endif +#ifdef __cpp_lib_byteswap + // If we don't have the fast platform byteswap implementation then we could default to the C++ standard + // implementation which might not be as fast but still pretty fine. + return std::byteswap( val ); +#else + if constexpr ( sizeof(numberType) == 1 ) + { + return val; + } + else + { + // I guess that this version could be better because it does not force use of memory, or a compiler who could + // stil retranslate it back to register operations. + numberType result = 0; + + for ( unsigned int n = 0; n < sizeof(numberType); n++ ) + { + result |= val & 0xFF; + val >>= 8u; + result <<= 8u; + } + + return result; + } +#endif +#ifdef _PLATFORM_HAS_FAST_BYTESWAP + } +#endif + } + + // Aligned big_endian number type. + template + requires ( std::is_trivially_constructible ::value ) + struct big_endian + { + // Required to be default for POD handling. + inline big_endian( void ) = default; + inline big_endian( const big_endian& ) = default; + inline big_endian( big_endian&& ) = default; + + private: + AINLINE void assign_data( const numberType& right ) noexcept(nothrow_copy_assignable_with ) + { + if _ENDIAN_IF_CONSTEXPR ( is_little_endian() ) + { + *(numberType*)&this->data[0] = byte_swap_fast( right ); + } + else + { + *(numberType*)&this->data[0] = right; + } + } + + public: + inline big_endian( const numberType& right ) noexcept(nothrow_copy_assignable_with ) + { + assign_data( right ); + } + + inline operator numberType ( void ) const noexcept(nothrow_constructible_from ) + { + if _ENDIAN_IF_CONSTEXPR ( is_little_endian() ) + { + return byte_swap_fast( *(const numberType*)&this->data[0] ); + } + else + { + return *(numberType*)&this->data[0]; + } + } + + inline big_endian& operator = ( const numberType& right ) noexcept(nothrow_copy_assignable_with ) + { + assign_data( right ); + + return *this; + } + + inline big_endian& operator = ( const big_endian& ) = default; + inline big_endian& operator = ( big_endian&& ) = default; + + private: + alignas(typename conditional ::type) char data[ sizeof(numberType) ]; + }; + + // Aligned little_endian number type. + template + requires ( std::is_trivially_constructible ::value ) + struct little_endian + { + // Required to be default for POD handling. + inline little_endian( void ) = default; + inline little_endian( const little_endian& ) = default; + inline little_endian( little_endian&& ) = default; + + private: + AINLINE void assign_data( const numberType& right ) noexcept(nothrow_copy_assignable_with ) + { + if _ENDIAN_IF_CONSTEXPR ( !is_little_endian() ) + { + *(numberType*)&this->data[0] = byte_swap_fast( right ); + } + else + { + *(numberType*)&this->data[0] = right; + } + } + + public: + inline little_endian( const numberType& right ) noexcept(nothrow_copy_assignable_with ) + { + assign_data( right ); + } + + inline operator numberType ( void ) const noexcept(nothrow_constructible_from ) + { + if _ENDIAN_IF_CONSTEXPR ( !is_little_endian() ) + { + return byte_swap_fast( *(const numberType*)&this->data[0] ); + } + else + { + return *(numberType*)&this->data[0]; + } + } + + inline little_endian& operator = ( const numberType& right ) noexcept(nothrow_copy_assignable_with ) + { + assign_data( right ); + + return *this; + } + + inline little_endian& operator = ( const little_endian& ) = default; + inline little_endian& operator = ( little_endian&& ) = default; + + private: + alignas(typename conditional ::type) char data[ sizeof(numberType) ]; + }; + + // Shortcuts for the packed endian structs for use in packed serialization structs. + template + using p_big_endian = big_endian ; + + template + using p_little_endian = little_endian ; +}; + +}; // namespace eir + +// For compatibility with older code. +namespace endian = eir::endian; + +#endif //_ENDIAN_COMPAT_HEADER_ diff --git a/Marlin/src/HAL/ESP32/sdk/MacroUtils.h b/Marlin/src/HAL/ESP32/sdk/MacroUtils.h new file mode 100644 index 000000000000..bca66203e93d --- /dev/null +++ b/Marlin/src/HAL/ESP32/sdk/MacroUtils.h @@ -0,0 +1,70 @@ +/***************************************************************************** +* +* PROJECT: Eir SDK +* FILE: eirrepo/sdk/MacroUtils.h +* PURPOSE: Common macros in the SDK +* +* Find the Eir SDK at: https://osdn.net/projects/eirrepo/ +* +*****************************************************************************/ + +#ifndef _COMMON_MACRO_UTILITIES_ +#define _COMMON_MACRO_UTILITIES_ + +// Basic always inline definition. +#ifndef AINLINE +#ifdef _MSC_VER +#define AINLINE __forceinline +#elif defined(__GNUC__) +#ifdef _DEBUG +#define AINLINE inline +#else +#define AINLINE inline __attribute__((always_inline)) +#endif +#else +#define AINLINE inline +#endif +#endif + +#ifndef LAINLINE +#ifdef _MSC_VER +#define LAINLINE [[msvc::forceinline]] +#elif defined(__linux__) +#define LAINLINE __attribute__((always_inline)) +#else +#define LAINLINE +#endif +#endif + +#ifdef _MSC_VER +#define PTR_NO_ALIAS __restrict +#elif defined(__GNUC__) +#define PTR_NO_ALIAS __restrict__ +#else +#define PTR_NO_ALIAS +#endif + +#ifndef _MSC_VER +#define abstract +#endif + +#ifndef countof +#define countof(x) (sizeof(x)/sizeof(*x)) +#endif + +// Compatibility macros for certain compilers. +#ifdef __GNUC__ +#define _GCCCOMPAT_CONSTINIT_FUNCDECL_ +#else +#define _GCCCOMPAT_CONSTINIT_FUNCDECL_ constinit +#endif //_GCC_ + +// Fix bugs of the broken MSVC compiler that annoys me because they cannot get C++20 concept evaluation implemented properly. +// Their lexer fails anyway! +#ifdef _MSC_VER +#define _MSVC_BUGFIX(x) +#else +#define _MSVC_BUGFIX(x) x +#endif + +#endif //_COMMON_MACRO_UTILITIES_ diff --git a/Marlin/src/HAL/ESP32/sdk/MemoryRaw.h b/Marlin/src/HAL/ESP32/sdk/MemoryRaw.h new file mode 100644 index 000000000000..bc5aaad1ba58 --- /dev/null +++ b/Marlin/src/HAL/ESP32/sdk/MemoryRaw.h @@ -0,0 +1,135 @@ +/***************************************************************************** +* +* PROJECT: Eir SDK +* FILE: eirrepo/sdk/MemoryRaw.h +* PURPOSE: Base memory management definitions for to-the-metal things +* +* Find the Eir SDK at: https://osdn.net/projects/eirrepo/ +* +*****************************************************************************/ + +#ifndef _MEMORY_RAW_DEFS_ +#define _MEMORY_RAW_DEFS_ + +#include +#if __has_include() +#include // for std::has_single_bit +#endif +#include + +#include "MetaHelpers.h" +#include "MacroUtils.h" + +// Macro that defines how alignment works. +// num: base of the number to be aligned +// sector: aligned-offset that should be added to num +// align: number of bytes to align to +// EXAMPLE: ALIGN( 0x1001, 4, 4 ) -> 0x1004 (equivalent of compiler structure padding alignment) +// ALIGN( 0x1003, 1, 4 ) -> 0x1000 +// ALIGN( 0x1003, 2, 4 ) -> 0x1004 +template +AINLINE numberType _ALIGN_GP( numberType num, numberType sector, numberType align ) +{ + // General purpose alignment routine. + // Not as fast as the bitfield version. + numberType sectorOffset = ((num) + (sector) - 1); + + return sectorOffset - ( sectorOffset % align ); +} + +template +AINLINE numberType _ALIGN_NATIVE( numberType num, numberType sector, numberType align ) +{ +#if defined(__cpp_lib_int_pow2) + // assume math based on x86 bits. + if ( std::has_single_bit( align ) ) + { + //bitfield version. not compatible with non-bitfield alignments. + return (((num) + (sector) - 1) & (~((align) - 1))); + } + else + { +#endif + return _ALIGN_GP( num, sector, align ); +#if defined(__cpp_lib_int_pow2) + } +#endif +} + +template +AINLINE numberType ALIGN( numberType num, numberType sector, numberType align ) +{ + if constexpr ( eir::same_as || + eir::same_as || + eir::same_as || + eir::same_as ) + { + return _ALIGN_NATIVE( num, sector, align ); + } + else + { + return _ALIGN_GP( num, sector, align ); + } +} + +// Helper macro (equivalent of EXAMPLE 1) +template +inline numberType ALIGN_SIZE( numberType num, numberType sector ) +{ + return ( ALIGN( (num), (sector), (sector) ) ); +} + +// Aligning things to the boundary below. +template +AINLINE numberType SCALE_DOWN( numberType value, numberType modval ) noexcept +{ + // This is faster than divide-and-multiply, plus it does exactly the same. + numberType rem = ( value % modval ); + + return ( value - rem ); +} + +template +AINLINE numberType CEIL_DIV( numberType val, divNumberType div ) +{ + return ( ( val + ( div - 1 ) ) / div ); +} + +// Safely casting integers between each others, with clamping to bounds. +template +AINLINE destIntegerType TRANSFORM_INT_CLAMP( srcIntegerType value ) +{ + typedef typename eir::make_signed ::type srcIntegerSigned_t; + typedef typename eir::make_unsigned ::type srcIntegerUnsigned_t; + + typedef typename eir::make_signed ::type destIntegerSigned_t; + typedef typename eir::make_unsigned ::type destIntegerUnsigned_t; + + constexpr srcIntegerUnsigned_t src_max = (srcIntegerUnsigned_t)eir::numeric_limits ::MAX; + constexpr srcIntegerSigned_t src_min = (srcIntegerSigned_t)eir::numeric_limits ::MIN; + + constexpr destIntegerUnsigned_t dest_max = (destIntegerUnsigned_t)eir::numeric_limits ::MAX; + constexpr destIntegerSigned_t dest_min = (destIntegerSigned_t)eir::numeric_limits ::MIN; + + // We assume that all unsigned integer types start at 0, all maximum values of ranges are non-negative. + + if constexpr ( dest_max < src_max ) + { + if ( value > (srcIntegerType)dest_max ) + { + return dest_max; + } + } + + if constexpr ( dest_min > src_min ) + { + if ( value < (srcIntegerType)dest_min ) + { + return dest_min; + } + } + + return (destIntegerType)value; +} + +#endif //_MEMORY_RAW_DEFS_ diff --git a/Marlin/src/HAL/ESP32/sdk/MetaHelpers.h b/Marlin/src/HAL/ESP32/sdk/MetaHelpers.h new file mode 100644 index 000000000000..fb1c69ab82ec --- /dev/null +++ b/Marlin/src/HAL/ESP32/sdk/MetaHelpers.h @@ -0,0 +1,1226 @@ +/***************************************************************************** +* +* PROJECT: Eir SDK +* FILE: eirrepo/sdk/MetaHelpers.h +* PURPOSE: Memory management templates and other utils. +* +* Find the Eir SDK at: https://osdn.net/projects/eirrepo/ +* +*****************************************************************************/ + +#ifndef _COMMON_META_PROGRAMMING_HELPERS_ +#define _COMMON_META_PROGRAMMING_HELPERS_ + +#if __has_include() +#include +#endif + +#if __has_include() +#include +#endif + +#include "MacroUtils.h" + +#if __has_include() +#include +#endif +#include +#include + +namespace eir +{ + +template +struct index_sequence {}; + +template +struct index_sequence_until {}; +template +struct index_sequence_until <0, IDX...> : index_sequence {}; +template +struct index_sequence_until : index_sequence_until {}; + + +template +struct type_identity +{ + typedef T type; +}; + +struct true_type +{ + static const constexpr bool value = true; +}; +struct false_type +{ + static const constexpr bool value = false; +}; + +template +struct is_same_as : public false_type {}; +template +struct is_same_as : public true_type {}; + +template +concept same_as = is_same_as ::value; + +template +struct typelist +{ + static constexpr auto count = sizeof...(Ts); + + template + AINLINE static constexpr bool ForEach( callbackType&& cb ) + { + bool success = false; + + if constexpr ( sizeof... (Ts) > 0 ) + { + auto lamb = [&] () LAINLINE + { + if ( success == false ) + { + if ( cb.template operator() () ) success = true; + } + }; + + ( lamb.template operator() (), ... ); + } + + return success; + } +}; +template +struct is_typelist : false_type {}; +template +struct is_typelist > : true_type {}; +// do not allow specialization-cv, references, pointers-to, etc.. + +template +concept typelist_type = is_typelist ::value; + +template +struct sequence_contains : public false_type {}; +template +struct sequence_contains > : public sequence_contains {}; +template +struct sequence_contains : public true_type {}; +template +struct sequence_contains : public sequence_contains {}; + +template +struct sequence_get {}; +template +struct sequence_get > : public sequence_get {}; +template +struct sequence_get <0, typelist > : public sequence_get <0, Ts...> {}; +template +struct sequence_get <0, T, Ts...> +{ + typedef T type; +}; +template +struct sequence_get : public sequence_get {}; + +template +struct remove_reference +{ + typedef T type; +}; +template +struct remove_reference : public remove_reference {}; +template +struct remove_reference : public remove_reference {}; + +template +AINLINE constexpr typename remove_reference ::type&& castmove( T&& v ) noexcept { return (typename remove_reference ::type&&)v; } + +template +struct is_any_ref : false_type {}; +template +struct is_any_ref : true_type {}; +template +struct is_any_ref : true_type {}; + +// You may be wondering why I called this "castforward" instead of the equivalent "forward". +// For once I wanted to combat the malicious "using namespace std;" statement. +// On the other hand, the MSVC compiler suffers from some ambiguity look-up issue regarding "forward" templated-specifier by itself, +// causing a misdetection of "std::forward" as possible candidate, causing compilation failure. +// So to be on the safe side avoid name-collision with std-namespace things! +template +AINLINE constexpr T&& castforward( typename remove_reference ::type& v ) noexcept { return static_cast ( v ); } +template +AINLINE constexpr T&& castforward( typename remove_reference ::type&& v ) noexcept { return static_cast ( v ); } + +template +concept nothrow_move_assignable_with = requires ( To& a, From b ) { { a = castmove(b) } noexcept; }; + +template +concept copy_assignable_with = requires ( To& a, const From b ) { a = b; }; + +template +concept nothrow_copy_assignable_with = requires ( To& a, const From b ) { { a = b } noexcept; }; + +template +struct no_volatile : type_identity {}; +template +struct no_volatile : public no_volatile {}; +template +struct no_volatile > + : public type_identity ::type...>> {}; + +template +struct is_volatile : false_type {}; +template +struct is_volatile : true_type {}; +template +struct is_volatile : true_type {}; +template +struct is_volatile : true_type {}; + +template +concept volatile_type = is_volatile ::value; + +template +struct no_const +{ + typedef T type; +}; +template +struct no_const : public no_const {}; +template +struct no_const > + : public type_identity ::type...>> {}; + +template +struct is_const : false_type {}; +template +struct is_const : true_type {}; +template +struct is_const : true_type {}; +template +struct is_const : true_type {}; + +template +concept const_type = is_const ::value; +template +concept mutable_type = ( is_const ::value == false ); + +template +AINLINE constexpr const T& make_const_ref( T& v ) noexcept { return v; } + +template requires ( sizeof...(Ts) > 0 && N < sizeof...(Ts) ) +AINLINE constexpr typename sequence_get ::type&& select_from( Ts&&... args ) noexcept +{ + auto lamb = [&] ( auto& lamb, T&& sel, subTs&&... next ) LAINLINE -> typename sequence_get ::type&& + { + if constexpr ( IDX == N ) + { + return castforward ( sel ); + } + else + { + return lamb.template operator() ( lamb, castforward ( next )... ); + } + }; + + return lamb.template operator() <0> ( lamb, castforward ( args )... ); +} + +typedef typelist known_signed_integrals; +typedef typelist known_unsigned_integrals; + +template +struct find_sizeof_equal_type : false_type {}; +template +struct find_sizeof_equal_type > : find_sizeof_equal_type {}; +template requires ( sizeof(T) == SZ ) +struct find_sizeof_equal_type : type_identity , true_type {}; +template requires ( sizeof(T) != SZ ) +struct find_sizeof_equal_type : find_sizeof_equal_type {}; + +template +concept sizeof_equal_type = find_sizeof_equal_type >::value; + +#if __has_include() && !defined(_EIRSDK_PREFER_NATIVE_IMPL) +template +struct is_unsigned_integral +{ + static constexpr bool value = ( std::is_unsigned ::value && std::is_integral ::value ); +}; +#else +template +struct is_unsigned_integral : sequence_contains {}; +#endif + +template +concept unsigned_integral = is_unsigned_integral ::value; + +#if __has_include() && !defined(_EIRSDK_PREFER_NATIVE_IMPL) +template +struct is_signed_integral +{ + static constexpr bool value = ( std::is_signed ::value && std::is_integral ::value ); +}; +#else +template +struct is_signed_integral : sequence_contains {}; +#endif + +template +concept signed_integral = is_signed_integral ::value; + +template +concept integral_type = unsigned_integral || signed_integral ; + +#if __has_include() && !defined(_EIRSDK_PREFER_NATIVE_IMPL) +template +struct make_signed_integral +{ + typedef typename std::enable_if ::value, typename std::make_signed ::type>::type type; +}; +#else +template +struct make_signed_integral {}; +template +struct make_signed_integral : type_identity {}; +template <> +struct make_signed_integral : type_identity {}; +template <> +struct make_signed_integral : type_identity {}; +template <> +struct make_signed_integral : type_identity {}; +template <> +struct make_signed_integral : type_identity {}; +template <> +struct make_signed_integral : type_identity {}; +#endif + +template +struct make_signed : type_identity {}; +template +struct make_signed : make_signed_integral {}; + +#if __has_include() && !defined(_EIRSDK_PREFER_NATIVE_IMPL) +template +struct make_unsigned_integral +{ + typedef typename std::enable_if ::value, typename std::make_unsigned ::type>::type type; +}; +#else +template +struct make_unsigned_integral {}; +template +struct make_unsigned_integral : type_identity {}; +template <> +struct make_unsigned_integral : type_identity {}; +template <> +struct make_unsigned_integral : type_identity {}; +template <> +struct make_unsigned_integral : type_identity {}; +template <> +struct make_unsigned_integral : type_identity {}; +template <> +struct make_unsigned_integral : type_identity {}; +template <> +struct make_unsigned_integral : type_identity {}; +#endif + +template +struct make_unsigned : type_identity {}; +template +struct make_unsigned : make_unsigned_integral {}; + +// Converts to the underlying type, throwing away any array-spec, pointer-spec, reference, etc. +template +struct plain_type +{ + typedef T type; +}; +template requires ( is_const ::value == false ) +struct plain_type : public plain_type {}; +template +struct plain_type : public plain_type {}; +template +struct plain_type : public plain_type {}; +template +struct plain_type : public plain_type {}; +template +struct plain_type : public plain_type {}; +template +struct plain_type : public plain_type {}; + +// Converts to the underlying type of const/volatile/reference types. +template +struct base_type +{ + typedef T type; +}; +template requires ( is_volatile ::value == false ) +struct base_type : public base_type {}; +template +struct base_type : public base_type {}; +template +struct base_type : public base_type {}; +template +struct base_type : public base_type {}; + +// Converts to the type without specification modification (const, volatile, etc). +template +struct nospecmod_type +{ + typedef T type; +}; +template requires ( is_volatile ::value == false ) +struct nospecmod_type : nospecmod_type {}; +template +struct nospecmod_type : nospecmod_type {}; + +// Checks if a type is POD. +template +struct is_pod_type : public false_type {}; +template +struct is_pod_type : public true_type {}; +template <> +struct is_pod_type : public true_type {}; +template <> +struct is_pod_type : public true_type {}; +template <> +struct is_pod_type : public true_type {}; +template +struct is_pod_type : public is_pod_type {}; +template +struct is_pod_type : public is_pod_type {}; +template +struct is_pod_type : public is_pod_type {}; +template +struct is_pod_type : public is_pod_type {}; +template +struct is_pod_type : public true_type {}; + +template +struct conditional +{ + typedef false_type type; +}; +template +struct conditional +{ + typedef true_type type; +}; + +// Returns the first biggest type in the list. +template +struct biggest_type +{ + typedef void type; +}; +template +struct biggest_type +{ + typedef BT type; +}; +template +struct biggest_type + : public biggest_type = sizeof(T)), BT, T>::type, Ts...> {}; + +template +struct biggest_type > : public biggest_type {}; + +// Returns the first smallest type in the list. +template +struct smallest_type +{ + typedef void type; +}; +template +struct smallest_type +{ + typedef ST type; +}; +template +struct smallest_type + : public smallest_type ::type, Ts...> {}; + +template +struct smallest_type > : public smallest_type {}; + +// Filter template for type-list operations. +template