diff --git a/examples/knx-demo/.gitignore b/examples/knx-demo/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/examples/knx-demo/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/examples/knx-demo/platformio-ci.ini b/examples/knx-demo/platformio-ci.ini index b426eb0..c114346 100644 --- a/examples/knx-demo/platformio-ci.ini +++ b/examples/knx-demo/platformio-ci.ini @@ -8,7 +8,7 @@ ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html -;--- SAMD -------------------------------------------------- +;--- SAMD21 -------------------------------------------------- [env:adafruit_feather_m0_rf] platform = atmelsam board = adafruit_feather_m0 @@ -21,8 +21,24 @@ build_flags = -DMASK_VERSION=0x27B0 -Wno-unknown-pragmas -DUSE_DATASECURE -;----------------------------------------------------------- +;--- SAMD51 -------------------------------------------------- + +[env:feather_m4_w5500] +platform = atmelsam +board = adafruit_feather_m4 +framework = arduino + +lib_deps = + WifiManager + knx + Ethernet + +build_flags = + -DMASK_VERSION=0x57B0 + -DUSE_W5X00=1 + -DKNX_NO_SPI=1 + -Wno-unknown-pragmas ;--- ESP8266 ----------------------------------------------- [env:nodemcuv2_ip] diff --git a/examples/knx-demo/platformio.ini b/examples/knx-demo/platformio.ini index 0de299b..8bbf656 100644 --- a/examples/knx-demo/platformio.ini +++ b/examples/knx-demo/platformio.ini @@ -20,11 +20,10 @@ board = adafruit_feather_m0 framework = arduino ; We consider that the this projects is opened within its project directory ; while working with VS Code. -lib_extra_dirs = ../../../ lib_deps = SPI - knx + knx=file://../../../knx build_flags = -DMASK_VERSION=0x27B0 @@ -39,11 +38,10 @@ build_flags = #framework = arduino ; We consider that the this projects is opened within its project directory ; while working with VS Code. -#lib_extra_dirs = ../../../ #lib_deps = # WifiManager -# knx +# knx=file://../../../knx #build_flags = # -DMASK_VERSION=0x57B0 @@ -55,11 +53,10 @@ board = nodemcuv2 framework = arduino ; We consider that the this projects is opened within its project directory ; while working with VS Code. -lib_extra_dirs = ../../../ lib_deps = WifiManager@0.15.0 - knx + knx=file://../../../knx build_flags = -DMASK_VERSION=0x07B0 @@ -75,11 +72,10 @@ board = esp32dev framework = arduino ; We consider that the this projects is opened within its project directory ; while working with VS Code. -lib_extra_dirs = ../../../ lib_deps = https://github.com/tzapu/WiFiManager.git - knx + knx=file://../../../knx build_flags = -DMASK_VERSION=0x57B0 @@ -91,10 +87,9 @@ board = esp32dev framework = arduino ; We consider that the this projects is opened within its project directory ; while working with VS Code. -lib_extra_dirs = ../../../ lib_deps = - knx + knx=file://../../../knx build_flags = -DMASK_VERSION=0x07B0 @@ -107,10 +102,9 @@ board = genericSTM32F103CB framework = arduino ; We consider that the this projects is opened within its project directory ; while working with VS Code. -lib_extra_dirs = ../../../ lib_deps = - knx + knx=file://../../../knx build_flags = -DENABLE_HWSERIAL1 @@ -130,10 +124,9 @@ board = genericSTM32F103CB framework = arduino ; We consider that the this projects is opened within its project directory ; while working with VS Code. -lib_extra_dirs = ../../../ lib_deps = - knx + knx=file://../../../knx build_flags = -DENABLE_HWSERIAL1 diff --git a/src/knx.h b/src/knx.h index 1a7b63b..49a9106 100644 --- a/src/knx.h +++ b/src/knx.h @@ -117,9 +117,11 @@ package platform { class Platform [[class_platform.html]] class ArduinoPlatform [[class_arduino_platform.html]] -class SamdPlatform [[class_samd_platform.html]] +class Samd21Platform [[class_samd21_platform.html]] +class Samd51Platform [[class_samd51_platform.html]] Platform<|--ArduinoPlatform -ArduinoPlatform<|--SamdPlatform +ArduinoPlatform<|--Samd21Platform +ArduinoPlatform<|--Samd51Platform class EspPlatform [[class_esp_platform.html]] ArduinoPlatform<|--EspPlatform class Esp32Platform [[class_esp32_platform.html]] @@ -219,9 +221,11 @@ package platform { class Platform [[class_platform.html]] class ArduinoPlatform [[class_arduino_platform.html]] -class SamdPlatform [[class_samd_platform.html]] +class Samd21Platform [[class_samd21_platform.html]] +class Samd51Platform [[class_samd51_platform.html]] Platform<|--ArduinoPlatform -ArduinoPlatform<|--SamdPlatform +ArduinoPlatform<|--Samd21Platform +ArduinoPlatform<|--Samd51Platform class EspPlatform [[class_esp_platform.html]] ArduinoPlatform<|--EspPlatform class Esp32Platform [[class_esp32_platform.html]] diff --git a/src/knx/knx_facade.cpp b/src/knx/knx_facade.cpp index b1cb9af..9f2eb4e 100644 --- a/src/knx/knx_facade.cpp +++ b/src/knx/knx_facade.cpp @@ -44,65 +44,76 @@ ICACHE_RAM_ATTR void buttonEvent() } #endif -#ifdef ARDUINO_ARCH_SAMD - // predefined global instance for TP or RF or TP/RF coupler - #if MASK_VERSION == 0x07B0 - Knx::KnxFacade knx(buttonEvent); - #elif MASK_VERSION == 0x27B0 - Knx::KnxFacade knx(buttonEvent); - #elif MASK_VERSION == 0x2920 - Knx::KnxFacade knx(buttonEvent); - #else - #error "Mask version not supported on ARDUINO_ARCH_SAMD" - #endif +#ifdef __SAMD51__ +// predefined global instance for TP or RF +#if MASK_VERSION == 0x07B0 + Knx::KnxFacade knx(buttonEvent); +#elif MASK_VERSION == 0x27B0 + Knx::KnxFacade knx(buttonEvent); +#elif MASK_VERSION == 0x57B0 + Knx::KnxFacade knx(buttonEvent); +#else + #error "Mask version not supported on SAMD51" +#endif +#elif defined(_SAMD21_) +// predefined global instance for TP or RF or TP/RF coupler +#if MASK_VERSION == 0x07B0 + Knx::KnxFacade knx(buttonEvent); +#elif MASK_VERSION == 0x27B0 + Knx::KnxFacade knx(buttonEvent); +#elif MASK_VERSION == 0x2920 + Knx::KnxFacade knx(buttonEvent); +#else + #error "Mask version not supported on SAMD21" +#endif #elif defined(ARDUINO_ARCH_RP2040) - // predefined global instance for TP or RF or IP or TP/RF coupler or TP/IP coupler - #if MASK_VERSION == 0x07B0 - Knx::KnxFacade knx(buttonEvent); - #elif MASK_VERSION == 0x27B0 - Knx::KnxFacade knx(buttonEvent); - #elif MASK_VERSION == 0x57B0 - Knx::KnxFacade knx(buttonEvent); - #elif MASK_VERSION == 0x2920 - Knx::KnxFacade knx(buttonEvent); - #elif MASK_VERSION == 0x091A - Knx::KnxFacade knx(buttonEvent); - #else - #error "Mask version not supported on ARDUINO_ARCH_RP2040" - #endif +// predefined global instance for TP or RF or IP or TP/RF coupler or TP/IP coupler +#if MASK_VERSION == 0x07B0 + Knx::KnxFacade knx(buttonEvent); +#elif MASK_VERSION == 0x27B0 + Knx::KnxFacade knx(buttonEvent); +#elif MASK_VERSION == 0x57B0 + Knx::KnxFacade knx(buttonEvent); +#elif MASK_VERSION == 0x2920 + Knx::KnxFacade knx(buttonEvent); +#elif MASK_VERSION == 0x091A + Knx::KnxFacade knx(buttonEvent); +#else + #error "Mask version not supported on ARDUINO_ARCH_RP2040" +#endif #elif defined(ARDUINO_ARCH_ESP8266) - // predefined global instance for TP or IP or TP/IP coupler - #if MASK_VERSION == 0x07B0 - Knx::KnxFacade knx(buttonEvent); - #elif MASK_VERSION == 0x57B0 - Knx::KnxFacade knx(buttonEvent); - #elif MASK_VERSION == 0x091A - Knx::KnxFacade knx(buttonEvent); - #else - #error "Mask version not supported on ARDUINO_ARCH_ESP8266" - #endif +// predefined global instance for TP or IP or TP/IP coupler +#if MASK_VERSION == 0x07B0 + Knx::KnxFacade knx(buttonEvent); +#elif MASK_VERSION == 0x57B0 + Knx::KnxFacade knx(buttonEvent); +#elif MASK_VERSION == 0x091A + Knx::KnxFacade knx(buttonEvent); +#else + #error "Mask version not supported on ARDUINO_ARCH_ESP8266" +#endif #elif defined(ARDUINO_ARCH_ESP32) - // predefined global instance for TP or IP or TP/IP coupler - #if MASK_VERSION == 0x07B0 - Knx::KnxFacade knx(buttonEvent); - #elif MASK_VERSION == 0x57B0 - Knx::KnxFacade knx(buttonEvent); - #elif MASK_VERSION == 0x091A - Knx::KnxFacade knx(buttonEvent); - #else - #error "Mask version not supported on ARDUINO_ARCH_ESP32" - #endif +// predefined global instance for TP or IP or TP/IP coupler +#if MASK_VERSION == 0x07B0 + Knx::KnxFacade knx(buttonEvent); +#elif MASK_VERSION == 0x57B0 + Knx::KnxFacade knx(buttonEvent); +#elif MASK_VERSION == 0x091A + Knx::KnxFacade knx(buttonEvent); +#else + #error "Mask version not supported on ARDUINO_ARCH_ESP32" +#endif #elif defined(ARDUINO_ARCH_STM32) - #if MASK_VERSION == 0x07B0 - Knx::KnxFacade knx(buttonEvent); - #else - #error "Mask version not supported on ARDUINO_ARCH_STM32" - #endif +#if MASK_VERSION == 0x07B0 + Knx::KnxFacade knx(buttonEvent); +#else + #error "Mask version not supported on ARDUINO_ARCH_STM32" +#endif #else // Non-Arduino platforms and Linux platform - // no predefined global instance +// no predefined global instance #endif #endif // KNX_NO_AUTOMATIC_GLOBAL_INSTANCE diff --git a/src/knx/knx_facade.h b/src/knx/knx_facade.h index ab23bea..509939b 100644 --- a/src/knx/knx_facade.h +++ b/src/knx/knx_facade.h @@ -14,20 +14,22 @@ #define USERDATA_SAVE_SIZE 0 #endif -#ifdef ARDUINO_ARCH_SAMD - #include "platform/samd_platform.h" +#ifdef __SAMD51__ +#include "platform/samd51_platform.h" +#elif defined(_SAMD21_) +#include "platform/samd21_platform.h" #elif defined(ARDUINO_ARCH_RP2040) - #include "platform/rp2040_arduino_platform.h" +#include "platform/rp2040_arduino_platform.h" #elif defined(ARDUINO_ARCH_ESP8266) - #include "platform/esp_platform.h" +#include "platform/esp_platform.h" #elif defined(ARDUINO_ARCH_ESP32) - #include "platform/esp32_platform.h" +#include "platform/esp32_platform.h" #elif defined(ARDUINO_ARCH_STM32) - #include "platform/stm32_platform.h" +#include "platform/stm32_platform.h" #elif __linux__ - #include "platform/linux_platform.h" +#include "platform/linux_platform.h" #else - #include "platform/cc1310_platform.h" +#include "platform/cc1310_platform.h" #endif #ifndef KNX_LED @@ -462,62 +464,73 @@ namespace Knx }; } #ifndef KNX_NO_AUTOMATIC_GLOBAL_INSTANCE - #ifdef ARDUINO_ARCH_SAMD - // predefined global instance for TP or RF or TP/RF coupler - #if MASK_VERSION == 0x07B0 - extern Knx::KnxFacade knx; - #elif MASK_VERSION == 0x27B0 - extern Knx::KnxFacade knx; - #elif MASK_VERSION == 0x2920 - extern Knx::KnxFacade knx; - #else - #error "Mask version not supported on ARDUINO_ARCH_SAMD" - #endif - #elif defined(ARDUINO_ARCH_RP2040) - // predefined global instance for TP or RF or TP/RF or TP/IP coupler - #if MASK_VERSION == 0x07B0 - extern Knx::KnxFacade knx; - #elif MASK_VERSION == 0x27B0 - extern Knx::KnxFacade knx; - #elif MASK_VERSION == 0x57B0 - extern Knx::KnxFacade knx; - #elif MASK_VERSION == 0x2920 - extern Knx::KnxFacade knx; - #elif MASK_VERSION == 0x091A - extern Knx::KnxFacade knx; - #else - #error "Mask version not supported on ARDUINO_ARCH_RP2040" - #endif - #elif defined(ARDUINO_ARCH_ESP8266) - // predefined global instance for TP or IP or TP/IP coupler - #if MASK_VERSION == 0x07B0 - extern Knx::KnxFacade knx; - #elif MASK_VERSION == 0x57B0 - extern Knx::KnxFacade knx; - #elif MASK_VERSION == 0x091A - extern Knx::KnxFacade knx; - #else - #error "Mask version not supported on ARDUINO_ARCH_ESP8266" - #endif - #elif defined(ARDUINO_ARCH_ESP32) - // predefined global instance for TP or IP or TP/IP coupler - #if MASK_VERSION == 0x07B0 - extern Knx::KnxFacade knx; - #elif MASK_VERSION == 0x57B0 - extern Knx::KnxFacade knx; - #elif MASK_VERSION == 0x091A - extern Knx::KnxFacade knx; - #else - #error "Mask version not supported on ARDUINO_ARCH_ESP32" - #endif - #elif defined(ARDUINO_ARCH_STM32) - // predefined global instance for TP only - #if MASK_VERSION == 0x07B0 - extern Knx::KnxFacade knx; - #else - #error "Mask version not supported on ARDUINO_ARCH_STM32" - #endif - #else // Non-Arduino platforms and Linux platform - // no predefined global instance - #endif +#ifdef __SAMD51__ +// predefined global instance for TP or RF +#if MASK_VERSION == 0x07B0 + extern Knx::KnxFacade knx; +#elif MASK_VERSION == 0x27B0 + extern Knx::KnxFacade knx; +#elif MASK_VERSION == 0x57B0 + extern Knx::KnxFacade knx; +#else + #error "Mask version not supported on SAMD51" +#endif +#elif defined(_SAMD21_) +// predefined global instance for TP or RF or TP/RF coupler +#if MASK_VERSION == 0x07B0 + extern Knx::KnxFacade knx; +#elif MASK_VERSION == 0x27B0 + extern Knx::KnxFacade knx; +#elif MASK_VERSION == 0x2920 + extern Knx::KnxFacade knx; +#else + #error "Mask version not supported on ARDUINO_ARCH_SAMD" +#endif +#elif defined(ARDUINO_ARCH_RP2040) +// predefined global instance for TP or RF or TP/RF or TP/IP coupler +#if MASK_VERSION == 0x07B0 + extern Knx::KnxFacade knx; +#elif MASK_VERSION == 0x27B0 + extern Knx::KnxFacade knx; +#elif MASK_VERSION == 0x57B0 + extern Knx::KnxFacade knx; +#elif MASK_VERSION == 0x2920 + extern Knx::KnxFacade knx; +#elif MASK_VERSION == 0x091A + extern Knx::KnxFacade knx; +#else + #error "Mask version not supported on ARDUINO_ARCH_RP2040" +#endif +#elif defined(ARDUINO_ARCH_ESP8266) +// predefined global instance for TP or IP or TP/IP coupler +#if MASK_VERSION == 0x07B0 + extern Knx::KnxFacade knx; +#elif MASK_VERSION == 0x57B0 + extern Knx::KnxFacade knx; +#elif MASK_VERSION == 0x091A + extern Knx::KnxFacade knx; +#else + #error "Mask version not supported on ARDUINO_ARCH_ESP8266" +#endif +#elif defined(ARDUINO_ARCH_ESP32) +// predefined global instance for TP or IP or TP/IP coupler +#if MASK_VERSION == 0x07B0 + extern Knx::KnxFacade knx; +#elif MASK_VERSION == 0x57B0 + extern Knx::KnxFacade knx; +#elif MASK_VERSION == 0x091A + extern Knx::KnxFacade knx; +#else + #error "Mask version not supported on ARDUINO_ARCH_ESP32" +#endif +#elif defined(ARDUINO_ARCH_STM32) +// predefined global instance for TP only +#if MASK_VERSION == 0x07B0 + extern Knx::KnxFacade knx; +#else + #error "Mask version not supported on ARDUINO_ARCH_STM32" +#endif +#else // Non-Arduino platforms and Linux platform +// no predefined global instance +#endif #endif // KNX_NO_AUTOMATIC_GLOBAL_INSTANCE diff --git a/src/knx/platform/samd_platform.cpp b/src/knx/platform/samd21_platform.cpp similarity index 76% rename from src/knx/platform/samd_platform.cpp rename to src/knx/platform/samd21_platform.cpp index 28819c8..6d61f3e 100644 --- a/src/knx/platform/samd_platform.cpp +++ b/src/knx/platform/samd21_platform.cpp @@ -1,6 +1,5 @@ -#ifdef ARDUINO_ARCH_SAMD -#include "samd_platform.h" - +#include "samd21_platform.h" +#if defined(_SAMD21_) #include #include @@ -22,7 +21,8 @@ extern uint32_t __data_end__; namespace Knx { - SamdPlatform::SamdPlatform() + + Samd21Platform::Samd21Platform() #ifndef KNX_NO_DEFAULT_UART : ArduinoPlatform(&KNX_SERIAL) #endif @@ -32,34 +32,25 @@ namespace Knx #endif } - SamdPlatform::SamdPlatform( HardwareSerial* s) : ArduinoPlatform(s) + Samd21Platform::Samd21Platform( HardwareSerial* s) : ArduinoPlatform(s) { #ifndef USE_SAMD_EEPROM_EMULATION init(); #endif } - uint32_t SamdPlatform::uniqueSerialNumber() + uint32_t Samd21Platform::uniqueSerialNumber() { -#if defined (__SAMD51__) - // SAMD51 from section 9.6 of the datasheet -#define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x008061FC) -#define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x00806010) -#define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x00806014) -#define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x00806018) -#else - //#elif defined (__SAMD21E17A__) || defined(__SAMD21G18A__) || defined(__SAMD21E18A__) || defined(__SAMD21J18A__) // SAMD21 from section 9.3.3 of the datasheet #define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x0080A00C) #define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x0080A040) #define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x0080A044) #define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x0080A048) -#endif return SERIAL_NUMBER_WORD_0 ^ SERIAL_NUMBER_WORD_1 ^ SERIAL_NUMBER_WORD_2 ^ SERIAL_NUMBER_WORD_3; } - void SamdPlatform::restart() + void Samd21Platform::restart() { println("restart"); NVIC_SystemReset(); @@ -67,7 +58,7 @@ namespace Knx #ifdef USE_SAMD_EEPROM_EMULATION #pragma warning "Using EEPROM Simulation" - uint8_t* SamdPlatform::getEepromBuffer(uint32_t size) + uint8_t* Samd21Platform::getEepromBuffer(uint32_t size) { //EEPROM.begin(size); if (size > EEPROM_EMULATION_SIZE) @@ -76,7 +67,7 @@ namespace Knx return EEPROM.getDataPtr(); } - void SamdPlatform::commitToEeprom() + void Samd21Platform::commitToEeprom() { EEPROM.commit(); } @@ -84,7 +75,7 @@ namespace Knx static const uint32_t pageSizes[] = {8, 16, 32, 64, 128, 256, 512, 1024}; - void SamdPlatform::init() + void Samd21Platform::init() { _memoryType = Flash; _pageSize = pageSizes[NVMCTRL->PARAM.bit.PSZ]; @@ -109,22 +100,22 @@ namespace Knx } } - size_t SamdPlatform::flashEraseBlockSize() + size_t Samd21Platform::flashEraseBlockSize() { return PAGES_PER_ROW; } - size_t SamdPlatform::flashPageSize() + size_t Samd21Platform::flashPageSize() { return _pageSize; } - uint8_t* SamdPlatform::userFlashStart() + uint8_t* Samd21Platform::userFlashStart() { return (uint8_t*)_MemoryStart; } - size_t SamdPlatform::userFlashSizeEraseBlocks() + size_t Samd21Platform::userFlashSizeEraseBlocks() { if (KNX_FLASH_SIZE <= 0) return 0; @@ -132,7 +123,7 @@ namespace Knx return ((KNX_FLASH_SIZE - 1) / (flashPageSize() * flashEraseBlockSize())) + 1; } - void SamdPlatform::flashErase(uint16_t eraseBlockNum) + void Samd21Platform::flashErase(uint16_t eraseBlockNum) { noInterrupts(); @@ -142,7 +133,7 @@ namespace Knx interrupts(); } - void SamdPlatform::flashWritePage(uint16_t pageNumber, uint8_t* data) + void Samd21Platform::flashWritePage(uint16_t pageNumber, uint8_t* data) { noInterrupts(); @@ -152,7 +143,7 @@ namespace Knx interrupts(); } - void SamdPlatform::writeBufferedEraseBlock() + void Samd21Platform::writeBufferedEraseBlock() { if (_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty) { @@ -169,12 +160,12 @@ namespace Knx } } - uint32_t SamdPlatform::getRowAddr(uint32_t flasAddr) + uint32_t Samd21Platform::getRowAddr(uint32_t flasAddr) { return flasAddr & ~(_rowSize - 1); } - void SamdPlatform::write(const volatile void* flash_ptr, const void* data, uint32_t size) + void Samd21Platform::write(const volatile void* flash_ptr, const void* data, uint32_t size) { // Calculate data boundaries size = (size + 3) / 4; @@ -216,7 +207,7 @@ namespace Knx } } - void SamdPlatform::erase(const volatile void* flash_ptr, uint32_t size) + void Samd21Platform::erase(const volatile void* flash_ptr, uint32_t size) { const uint8_t* ptr = (const uint8_t*)flash_ptr; @@ -230,7 +221,7 @@ namespace Knx eraseRow(ptr); } - void SamdPlatform::eraseRow(const volatile void* flash_ptr) + void Samd21Platform::eraseRow(const volatile void* flash_ptr) { NVMCTRL->ADDR.reg = ((uint32_t)flash_ptr) / 2; NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER; diff --git a/src/knx/platform/samd_platform.h b/src/knx/platform/samd21_platform.h similarity index 91% rename from src/knx/platform/samd_platform.h rename to src/knx/platform/samd21_platform.h index 7b32f51..c27d258 100644 --- a/src/knx/platform/samd_platform.h +++ b/src/knx/platform/samd21_platform.h @@ -2,17 +2,16 @@ #include "Arduino.h" -#ifdef ARDUINO_ARCH_SAMD - +#if defined(_SAMD21_) #define PAGES_PER_ROW 4 namespace Knx { - class SamdPlatform : public ArduinoPlatform + class Samd21Platform : public ArduinoPlatform { public: - SamdPlatform(); - SamdPlatform( HardwareSerial* s); + Samd21Platform(); + Samd21Platform( HardwareSerial* s); // unique serial number uint32_t uniqueSerialNumber() override; diff --git a/src/knx/platform/samd51_platform.cpp b/src/knx/platform/samd51_platform.cpp new file mode 100644 index 0000000..81e3e17 --- /dev/null +++ b/src/knx/platform/samd51_platform.cpp @@ -0,0 +1,363 @@ +#include "samd51_platform.h" + +#ifdef __SAMD51__ + +#include +#include + +#if KNX_FLASH_SIZE % 1024 + #error "KNX_FLASH_SIZE must be multiple of 1024" +#endif + +#ifndef KNX_SERIAL + #define KNX_SERIAL Serial1 +#endif + +extern uint32_t __etext; +extern uint32_t __data_start__; +extern uint32_t __data_end__; + +namespace Knx +{ + Samd51Platform::Samd51Platform() +#ifndef KNX_NO_DEFAULT_UART + : ArduinoPlatform(&KNX_SERIAL) +#endif + { + init(); + } + + Samd51Platform::Samd51Platform( HardwareSerial* s) : ArduinoPlatform(s) + { + init(); + } + + uint32_t Samd51Platform::uniqueSerialNumber() + { + // SAMD51 from section 9.6 of the datasheet +#define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x008061FC) +#define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x00806010) +#define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x00806014) +#define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x00806018) + + return SERIAL_NUMBER_WORD_0 ^ SERIAL_NUMBER_WORD_1 ^ SERIAL_NUMBER_WORD_2 ^ SERIAL_NUMBER_WORD_3; + } + + void Samd51Platform::restart() + { + println("restart"); + NVIC_SystemReset(); + } + +#if USE_W5X00 == 1 + + uint32_t Samd51Platform::currentIpAddress() + { + // IPAddress _ip = Ethernet.localIP(); + // _ipAddress = htonl(_ip); + // return _ipAddress; + + return Ethernet.localIP(); + + // _ipAddress = 0x0A063232; + // return _ipAddress; + + // return 0x0A063232; + } + + uint32_t Samd51Platform::currentSubnetMask() + { + // IPAddress _nm = Ethernet.subnetMask(); + // _netmask = htonl(_nm); + // return _netmask; + + return Ethernet.subnetMask(); + + // _netmask = 0xFFFFFF00; + // return _netmask; + + // return 0xFFFFFF00; + } + + uint32_t Samd51Platform::currentDefaultGateway() + { + // IPAddress _gw = Ethernet.gatewayIP(); + // _defaultGateway = htonl(_gw); + // return _defaultGateway; + + return Ethernet.gatewayIP(); + + // _defaultGateway = 0x0A063201; + // return _defaultGateway; + + // return 0x0A063201; + } + + void Samd51Platform::macAddress(uint8_t* mac_address) + { + //Ethernet.macAddress(mac_address); //try this first, not sure if this will work, is for ethernet3 lib + memcpy(mac_address, _macAddress, sizeof(_macAddress) / sizeof(_macAddress[0])); //sizeof should resolve to be just 6 + } + + void Samd51Platform::setupMultiCast(uint32_t addr, uint16_t port) + { + IPAddress _mcastaddr(htonl(addr)); + + KNX_DEBUG_SERIAL.printf("setup multicast on %d.%d.%d.%d:%d\n", _mcastaddr[0], _mcastaddr[1], _mcastaddr[2], _mcastaddr[3], port); + uint8_t result = _udp.beginMulticast(_multicastAddr, _multicastPort); + KNX_DEBUG_SERIAL.printf("result %d\n", result); + } + + void Samd51Platform::closeMultiCast() + { + _udp.stop(); + } + + bool Samd51Platform::sendBytesMultiCast(uint8_t* buffer, uint16_t len) + { + //printHex("<- ",buffer, len); + _udp.beginPacket(_multicastAddr, _multicastPort); + _udp.write(buffer, len); + _udp.endPacket(); + return true; + } + + int Samd51Platform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) + { + int len = _udp.parsePacket(); + + if (len == 0) + return 0; + + if (len > maxLen) + { + KNX_DEBUG_SERIAL.printf("udp buffer to small. was %d, needed %d\n", maxLen, len); + fatalError(); + } + + _udp.read(buffer, len); + printHex("-> ", buffer, len); + return len; + } + + bool Samd51Platform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) + { + IPAddress ucastaddr(htonl(addr)); + println("sendBytesUniCast endPacket fail"); + + if (_udp.beginPacket(ucastaddr, port) == 1) + { + _udp.write(buffer, len); + + if (_udp.endPacket() == 0) + println("sendBytesUniCast endPacket fail"); + } + else + println("sendBytesUniCast beginPacket fail"); + + return true; + } + +#endif + + static const uint32_t pageSizes[] = {8, 16, 32, 64, 128, 256, 512, 1024}; + + void Samd51Platform::init() + { + // println("Entered Init .h variables active, rest and .cpp commented"); + + // #if USE_W5X00 == 1 + // IPAddress _ip = Ethernet.localIP(); + // _ipAddress = htonl(_ip); + // _ip = Ethernet.subnetMask(); + // _netmask = htonl(_ip); + // _ip = Ethernet.gatewayIP(); + // _defaultGateway = htonl(_ip); + // #endif + + _memoryType = Flash; + _pageSize = pageSizes[NVMCTRL->PARAM.bit.PSZ]; + _pageCnt = NVMCTRL->PARAM.bit.NVMP; + _rowSize = (_pageSize * _pageCnt / 64); + + //find end of program flash and set limit to next row + uint32_t endEddr = (uint32_t)(&__etext + (&__data_end__ - &__data_start__)); // text + data MemoryBlock + _MemoryStart = getRowAddr(_pageSize * _pageCnt - KNX_FLASH_SIZE - 1); // 23295 + _MemoryEnd = getRowAddr(_pageSize * _pageCnt - 1); + + //chosen flash size is not available anymore + if (_MemoryStart < endEddr) + { + println("KNX_FLASH_SIZE is not available (possible too much flash use by firmware)"); + fatalError(); + } + } + + // Invalidate all CMCC cache entries if CMCC cache is enabled. + static void invalidate_CMCC_cache() + { + if (CMCC->SR.bit.CSTS) + { + CMCC->CTRL.bit.CEN = 0; + + while (CMCC->SR.bit.CSTS) {} + + CMCC->MAINT0.bit.INVALL = 1; + CMCC->CTRL.bit.CEN = 1; + } + } + + static inline uint32_t read_unaligned_uint32(volatile void* data) + { + union + { + uint32_t u32; + uint8_t u8[4]; + } res; + const uint8_t* d = (const uint8_t*)data; + res.u8[0] = d[0]; + res.u8[1] = d[1]; + res.u8[2] = d[2]; + res.u8[3] = d[3]; + return res.u32; + } + + size_t Samd51Platform::flashEraseBlockSize() + { + return (_pageSize / 64); //PAGES_PER_ROW; + } + + size_t Samd51Platform::flashPageSize() + { + return _pageSize; + } + + uint8_t* Samd51Platform::userFlashStart() + { + return (uint8_t*)_MemoryStart; + } + + size_t Samd51Platform::userFlashSizeEraseBlocks() + { + if (KNX_FLASH_SIZE <= 0) + return 0; + else + return ((KNX_FLASH_SIZE - 1) / (flashPageSize() * flashEraseBlockSize())) + 1; + } + + void Samd51Platform::flashErase(uint16_t eraseBlockNum) + { + noInterrupts(); + + eraseRow((void*)(_MemoryStart + eraseBlockNum * _rowSize)); + // flash_range_erase(KNX_FLASH_OFFSET + eraseBlockNum * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize()); + + interrupts(); + } + + void Samd51Platform::flashWritePage(uint16_t pageNumber, uint8_t* data) + { + noInterrupts(); + + write((void*)(_MemoryStart + pageNumber * _pageSize), data, _pageSize); + // flash_range_program(KNX_FLASH_OFFSET + pageNumber * flashPageSize(), data, flashPageSize()); + + interrupts(); + } + + void Samd51Platform::writeBufferedEraseBlock() + { + if (_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty) + { + noInterrupts(); + + eraseRow((void*)(_MemoryStart + _bufferedEraseblockNumber * _rowSize)); + write((void*)(_MemoryStart + _bufferedEraseblockNumber * _rowSize), _eraseblockBuffer, _rowSize); + // flash_range_erase(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize()); + // flash_range_program(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), _eraseblockBuffer, flashPageSize() * flashEraseBlockSize()); + + interrupts(); + + _bufferedEraseblockDirty = false; + } + } + + uint32_t Samd51Platform::getRowAddr(uint32_t flasAddr) + { + return flasAddr & ~(_rowSize - 1); + } + + void Samd51Platform::write(const volatile void* flash_ptr, const void* data, uint32_t size) + { + // Calculate data boundaries + size = (size + 3) / 4; + volatile uint32_t* src_addr = (volatile uint32_t*)data; + volatile uint32_t* dst_addr = (volatile uint32_t*)flash_ptr; + + // Disable automatic page write + NVMCTRL->CTRLA.bit.WMODE = 0; + + while (NVMCTRL->STATUS.bit.READY == 0) { } + + // Disable NVMCTRL cache while writing, per SAMD51 errata. + bool original_CACHEDIS0 = NVMCTRL->CTRLA.bit.CACHEDIS0; + bool original_CACHEDIS1 = NVMCTRL->CTRLA.bit.CACHEDIS1; + NVMCTRL->CTRLA.bit.CACHEDIS0 = true; + NVMCTRL->CTRLA.bit.CACHEDIS1 = true; + + // Do writes in pages + while (size) + { + // Execute "PBC" Page Buffer Clear + NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMDEX_KEY | NVMCTRL_CTRLB_CMD_PBC; + + while (NVMCTRL->INTFLAG.bit.DONE == 0) { } + + // Fill page buffer + uint32_t i; + + for (i = 0; i < (_pageSize / 4) && size; i++) + { + *dst_addr = read_unaligned_uint32(src_addr); + src_addr += 4; + dst_addr++; + size--; + } + + // Execute "WP" Write Page + NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMDEX_KEY | NVMCTRL_CTRLB_CMD_WP; + + while (NVMCTRL->INTFLAG.bit.DONE == 0) { } + + invalidate_CMCC_cache(); + // Restore original NVMCTRL cache settings. + NVMCTRL->CTRLA.bit.CACHEDIS0 = original_CACHEDIS0; + NVMCTRL->CTRLA.bit.CACHEDIS1 = original_CACHEDIS1; + } + } + + void Samd51Platform::erase(const volatile void* flash_ptr, uint32_t size) + { + const uint8_t* ptr = (const uint8_t*)flash_ptr; + + while (size > _rowSize) + { + eraseRow(ptr); + ptr += _rowSize; + size -= _rowSize; + } + + eraseRow(ptr); + } + + void Samd51Platform::eraseRow(const volatile void* flash_ptr) + { + NVMCTRL->ADDR.reg = ((uint32_t)flash_ptr); + NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMDEX_KEY | NVMCTRL_CTRLB_CMD_EB; + + while (!NVMCTRL->INTFLAG.bit.DONE) { } + + invalidate_CMCC_cache(); + } +} +#endif diff --git a/src/knx/platform/samd51_platform.h b/src/knx/platform/samd51_platform.h new file mode 100644 index 0000000..b72ff67 --- /dev/null +++ b/src/knx/platform/samd51_platform.h @@ -0,0 +1,79 @@ +#include +#include "arduino_platform.h" + +#ifdef __SAMD51__ +#include +#include +#include + +namespace Knx +{ + class Samd51Platform : public ArduinoPlatform + { + public: + Samd51Platform(); + Samd51Platform( HardwareSerial* s); + + // unique serial number + uint32_t uniqueSerialNumber() override; + + void restart(); + +#if USE_W5X00 == 1 + // ip config + uint32_t currentIpAddress() override; + uint32_t currentSubnetMask() override; + uint32_t currentDefaultGateway() override; + void macAddress(uint8_t* data) override; + + //multicast + void setupMultiCast(uint32_t addr, uint16_t port) override; + void closeMultiCast() override; + bool sendBytesMultiCast(uint8_t* buffer, uint16_t len) override; + int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) override; + + bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) override; +#endif + + // size of one EraseBlock in pages + virtual size_t flashEraseBlockSize(); + // size of one flash page in bytes + virtual size_t flashPageSize(); + // start of user flash aligned to start of an erase block + virtual uint8_t* userFlashStart(); + // size of the user flash in EraseBlocks + virtual size_t userFlashSizeEraseBlocks(); + // relativ to userFlashStart + virtual void flashErase(uint16_t eraseBlockNum); + // write a single page to flash (pageNumber relative to userFashStart + virtual void flashWritePage(uint16_t pageNumber, uint8_t* data); + + // writes _eraseblockBuffer to flash - overrides Plattform::writeBufferedEraseBlock() for performance optimization only + void writeBufferedEraseBlock(); + + private: + void init(); + uint32_t _MemoryEnd = 0; + uint32_t _MemoryStart = 0; + uint32_t _pageSize; + uint32_t _rowSize; + uint32_t _pageCnt; + + uint32_t getRowAddr(uint32_t flasAddr); + void write(const volatile void* flash_ptr, const void* data, uint32_t size); + void erase(const volatile void* flash_ptr, uint32_t size); + void eraseRow(const volatile void* flash_ptr); + +#if USE_W5X00 == 1 + uint8_t _macAddress[6] = {0xC0, 0xFF, 0xEE, 0xC0, 0xDE, 0x00}; + uint32_t _ipAddress = 0; + uint32_t _netmask = 0; + uint32_t _defaultGateway = 0; + + uint32_t _multicastAddr = -1; + uint16_t _multicastPort = -1; + EthernetUDP _udp; +#endif + }; +} +#endif