diff --git a/src/knx/bau_systemB.cpp b/src/knx/bau_systemB.cpp index 7eee281..9c6fb0a 100644 --- a/src/knx/bau_systemB.cpp +++ b/src/knx/bau_systemB.cpp @@ -112,9 +112,14 @@ void BauSystemB::memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t memoryAddress, uint8_t * data) { _memory.writeMemory(memoryAddress, number, data); - if (_deviceObj.verifyMode()) - memoryReadIndication(priority, hopType, asap, secCtrl, number, memoryAddress); + memoryReadIndication(priority, hopType, asap, secCtrl, number, memoryAddress, data); +} + +void BauSystemB::memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t * data) +{ + applicationLayer().memoryReadResponse(AckRequested, priority, hopType, asap, secCtrl, number, memoryAddress, data); } void BauSystemB::memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number, diff --git a/src/knx/bau_systemB.h b/src/knx/bau_systemB.h index 290f839..abbc653 100644 --- a/src/knx/bau_systemB.h +++ b/src/knx/bau_systemB.h @@ -48,6 +48,8 @@ class BauSystemB : protected BusAccessUnit uint16_t memoryAddress, uint8_t* data) override; void memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number, uint16_t memoryAddress) override; + void memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number, + uint16_t memoryAddress, uint8_t * data); void memoryExtWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number, uint32_t memoryAddress, uint8_t* data) override; void memoryExtReadIndication(Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl, uint8_t number, diff --git a/src/knx/memory.cpp b/src/knx/memory.cpp index a5945cb..f53a1a1 100644 --- a/src/knx/memory.cpp +++ b/src/knx/memory.cpp @@ -1,29 +1,36 @@ #include "memory.h" + #include + #include "bits.h" Memory::Memory(Platform& platform, DeviceObject& deviceObject) : _platform(platform), _deviceObject(deviceObject) -{ -} +{} + +Memory::~Memory() +{} void Memory::readMemory() { println("readMemory"); - if (_data != nullptr) + + uint8_t* flashStart = _platform.getNonVolatileMemoryStart(); + size_t flashSize = _platform.getNonVolatileMemorySize(); + if (flashStart == nullptr) + { + println("no user flash available;"); return; + } - uint16_t flashSize = KNX_FLASH_SIZE; - _data = _platform.getEepromBuffer(flashSize); - - printHex("RESTORED ", _data, _metadataSize); + printHex("RESTORED ", flashStart, _metadataSize); uint16_t metadataBlockSize = alignToPageSize(_metadataSize); - _freeList = new MemoryBlock(_data + metadataBlockSize, flashSize - metadataBlockSize); + _freeList = new MemoryBlock(flashStart + metadataBlockSize, flashSize - metadataBlockSize); uint16_t manufacturerId = 0; - const uint8_t* buffer = popWord(manufacturerId, _data); + const uint8_t* buffer = popWord(manufacturerId, flashStart); uint8_t hardwareType[LEN_HARDWARE_TYPE] = {0}; buffer = popByteArray(hardwareType, LEN_HARDWARE_TYPE, buffer); @@ -58,7 +65,7 @@ void Memory::readMemory() println(_saveCount); for (int i = 0; i < _saveCount; i++) { - println(_data - buffer); + println(flashStart - buffer); println("."); buffer = _saveRestores[i]->restore(buffer); } @@ -67,7 +74,7 @@ void Memory::readMemory() println(_tableObjCount); for (int i = 0; i < _tableObjCount; i++) { - println(_data - buffer); + println(flashStart - buffer); println("."); buffer = _tableObjects[i]->restore(buffer); uint16_t memorySize = 0; @@ -84,29 +91,37 @@ void Memory::readMemory() void Memory::writeMemory() { - uint8_t* buffer = _data; - buffer = pushWord(_deviceObject.manufacturerId(), buffer); - buffer = pushByteArray(_deviceObject.hardwareType(), LEN_HARDWARE_TYPE, buffer); - buffer = pushWord(_deviceObject.version(), buffer); + // first get the necessary size of the writeBuffer + size_t writeBufferSize = _metadataSize; + for (int i = 0; i < _saveCount; i++) + writeBufferSize = MAX(writeBufferSize, _saveRestores[i]->saveSize()); + + for (int i = 0; i < _tableObjCount; i++) + writeBufferSize = MAX(writeBufferSize, _tableObjects[i]->saveSize() + 2 /*for memory pos*/); + + uint8_t buffer[writeBufferSize]; + uint32_t flashPos = 0; + uint8_t* bufferPos = buffer; + + bufferPos = pushWord(_deviceObject.manufacturerId(), bufferPos); + bufferPos = pushByteArray(_deviceObject.hardwareType(), LEN_HARDWARE_TYPE, bufferPos); + bufferPos = pushWord(_deviceObject.version(), bufferPos); + + flashPos = _platform.writeNonVolatileMemory(flashPos, buffer, bufferPos - buffer); print("save saveRestores "); println(_saveCount); for (int i = 0; i < _saveCount; i++) { - println(_data - buffer); - println("."); - //println((long)_saveRestores[i], HEX); - buffer = _saveRestores[i]->save(buffer); + bufferPos = _saveRestores[i]->save(buffer); + flashPos = _platform.writeNonVolatileMemory(flashPos, buffer, bufferPos - buffer); } print("save tableobjs "); println(_tableObjCount); for (int i = 0; i < _tableObjCount; i++) { - println(_data - buffer); - println("."); - //println((long)_tableObjects[i], HEX); - buffer = _tableObjects[i]->save(buffer); + bufferPos = _tableObjects[i]->save(buffer); //save to size of the memoryblock for tableobject too, so that we can rebuild the usedList and freeList if (_tableObjects[i]->_data != nullptr) @@ -115,17 +130,23 @@ void Memory::writeMemory() MemoryBlock* block = findBlockInList(_usedList, _tableObjects[i]->_data); if (block == nullptr) { - println("_data of TableObject not in errorlist"); + println("_data of TableObject not in _usedList"); _platform.fatalError(); } - buffer = pushWord(block->size, buffer); + bufferPos = pushWord(block->size, bufferPos); } else - buffer = pushWord(0, buffer); + bufferPos = pushWord(0, bufferPos); + + flashPos = _platform.writeNonVolatileMemory(flashPos, buffer, bufferPos - buffer); } - _platform.commitToEeprom(); - printHex("SAVED ", _data, _metadataSize); + _platform.commitNonVolatileMemory(); +} + +void Memory::saveMemory() +{ + _platform.commitNonVolatileMemory(); } void Memory::addSaveRestore(SaveRestore* obj) @@ -151,7 +172,7 @@ void Memory::addSaveRestore(TableObject* obj) uint8_t* Memory::allocMemory(size_t size) { - // always allocate aligned to 32 bit + // always allocate aligned to pagesize size = alignToPageSize(size); MemoryBlock* freeBlock = _freeList; @@ -220,19 +241,19 @@ void Memory::freeMemory(uint8_t* ptr) void Memory::writeMemory(uint32_t relativeAddress, size_t size, uint8_t* data) { - memcpy(toAbsolute(relativeAddress), data, size); + _platform.writeNonVolatileMemory(relativeAddress, data, size); } uint8_t* Memory::toAbsolute(uint32_t relativeAddress) { - return _data + (ptrdiff_t)relativeAddress; + return _platform.getNonVolatileMemoryStart() + (ptrdiff_t)relativeAddress; } uint32_t Memory::toRelative(uint8_t* absoluteAddress) { - return absoluteAddress - _data; + return absoluteAddress - _platform.getNonVolatileMemoryStart(); } MemoryBlock* Memory::removeFromList(MemoryBlock* head, MemoryBlock* item) @@ -354,8 +375,9 @@ void Memory::addToFreeList(MemoryBlock* block) uint16_t Memory::alignToPageSize(size_t size) { - // to 32 bit for now - return (size + 3) & ~0x3; + size_t pageSize = 4; //_platform.flashPageSize(); // align to 32bit for now, as aligning to flash-page-size causes side effects in programming + // pagesize should be a multiply of two + return (size + pageSize - 1) & (-1*pageSize); } MemoryBlock* Memory::findBlockInList(MemoryBlock* head, uint8_t* address) diff --git a/src/knx/memory.h b/src/knx/memory.h index 962437f..8ebb5c2 100644 --- a/src/knx/memory.h +++ b/src/knx/memory.h @@ -28,8 +28,10 @@ class Memory { public: Memory(Platform& platform, DeviceObject& deviceObject); + virtual ~Memory(); void readMemory(); void writeMemory(); + void saveMemory(); void addSaveRestore(SaveRestore* obj); void addSaveRestore(TableObject* obj); @@ -49,13 +51,17 @@ public: MemoryBlock* findBlockInList(MemoryBlock* head, uint8_t* address); void addNewUsedBlock(uint8_t* address, size_t size); + void readEraseBlockToBuffer(uint32_t blockNum); + uint8_t* eraseBlockStart(uint32_t blockNum); + uint8_t* eraseBlockEnd(uint32_t blockNum); + void saveBufferdEraseBlock(); + Platform& _platform; DeviceObject& _deviceObject; SaveRestore* _saveRestores[MAXSAVE] = {0}; TableObject* _tableObjects[MAXTABLEOBJ] = {0}; uint8_t _saveCount = 0; uint8_t _tableObjCount = 0; - uint8_t* _data = nullptr; MemoryBlock* _freeList = nullptr; MemoryBlock* _usedList = nullptr; uint16_t _metadataSize = 4 + LEN_HARDWARE_TYPE; // accounting for 2x pushWord and pushByteArray of length LEN_HARDWARE_TYPE diff --git a/src/knx/platform.cpp b/src/knx/platform.cpp index 1816960..a66a341 100644 --- a/src/knx/platform.cpp +++ b/src/knx/platform.cpp @@ -1,12 +1,15 @@ #include "platform.h" +#include "bits.h" + +#include +#include NvMemoryType Platform::NonVolatileMemoryType() { return _memoryType; } - void Platform::NonVolatileMemoryType(NvMemoryType type) { _memoryType = type; @@ -97,3 +100,155 @@ int Platform::readBytesMultiCast(uint8_t *buffer, uint16_t maxLen) { return 0; } + +size_t Platform::flashEraseBlockSize() +{ + return 0; +} + +size_t Platform::flashPageSize() +{ + // align to 32bit as default for Eeprom Emulation plattforms + return 4; +} + +uint8_t *Platform::userFlashStart() +{ + return nullptr; +} + +size_t Platform::userFlashSizeEraseBlocks() +{ + return 0; +} + +void Platform::flashErase(uint16_t eraseBlockNum) +{} + +void Platform::flashWritePage(uint16_t pageNumber, uint8_t* data) +{} + +uint8_t * Platform::getEepromBuffer(uint16_t size) +{ + return nullptr; +} + +void Platform::commitToEeprom() +{} + +uint8_t* Platform::getNonVolatileMemoryStart() +{ + if(_memoryType == Flash) + return userFlashStart(); + else + return getEepromBuffer(KNX_FLASH_SIZE); +} + +size_t Platform::getNonVolatileMemorySize() +{ + if(_memoryType == Flash) + return userFlashSizeEraseBlocks() * flashEraseBlockSize() * flashPageSize(); + else + return KNX_FLASH_SIZE; +} + +void Platform::commitNonVolatileMemory() +{ + if(_memoryType == Flash) + { + if(_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty) + { + writeBufferedEraseBlock(); + + free(_eraseblockBuffer); + _eraseblockBuffer = nullptr; + _bufferedEraseblockNumber = -1; // does that make sense? + } + } + else + { + commitToEeprom(); + } +} + +uint32_t Platform::writeNonVolatileMemory(uint32_t relativeAddress, uint8_t* buffer, size_t size) +{ + if(_memoryType == Flash) + { + while (size > 0) + { + loadEraseblockContaining(relativeAddress); + uint32_t start = _bufferedEraseblockNumber * (flashEraseBlockSize() * flashPageSize()); + uint32_t end = start + (flashEraseBlockSize() * flashPageSize()); + + ptrdiff_t offset = relativeAddress - start; + ptrdiff_t length = end - relativeAddress; + if(length > size) + length = size; + memcpy(_eraseblockBuffer + offset, buffer, length); + _bufferedEraseblockDirty = true; + + relativeAddress += length; + buffer += length; + size -= length; + } + return relativeAddress; + } + else + { + memcpy(getEepromBuffer(KNX_FLASH_SIZE)+relativeAddress, buffer, size); + return relativeAddress+size; + } +} + +void Platform::loadEraseblockContaining(uint32_t relativeAddress) +{ + int32_t blockNum = getEraseBlockNumberOf(relativeAddress); + if (blockNum < 0) + { + println("loadEraseblockContaining could not get valid eraseblock number"); + fatalError(); + } + + if (blockNum != _bufferedEraseblockNumber && _bufferedEraseblockNumber >= 0) + writeBufferedEraseBlock(); + + bufferEraseBlock(blockNum); +} + +int32_t Platform::getEraseBlockNumberOf(uint32_t relativeAddress) +{ + return relativeAddress / (flashEraseBlockSize() * flashPageSize()); +} + + +void Platform::writeBufferedEraseBlock() +{ + if(_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty) + { + flashErase(_bufferedEraseblockNumber); + for(int i = 0; i < flashEraseBlockSize(); i++) + { + int32_t pageNumber = _bufferedEraseblockNumber * flashEraseBlockSize() + i; + uint8_t *data = _eraseblockBuffer + flashPageSize() * i; + flashWritePage(pageNumber, data); + } + _bufferedEraseblockDirty = false; + } +} + + +void Platform::bufferEraseBlock(uint32_t eraseBlockNumber) +{ + if(_bufferedEraseblockNumber == eraseBlockNumber) + return; + + if(_eraseblockBuffer == nullptr) + { + _eraseblockBuffer = (uint8_t*)malloc(flashEraseBlockSize() * flashPageSize()); + } + memcpy(_eraseblockBuffer, userFlashStart() + eraseBlockNumber * flashEraseBlockSize() * flashPageSize(), flashEraseBlockSize() * flashPageSize()); + + _bufferedEraseblockNumber = eraseBlockNumber; + _bufferedEraseblockDirty = false; +} diff --git a/src/knx/platform.h b/src/knx/platform.h index 769083f..2aaf758 100644 --- a/src/knx/platform.h +++ b/src/knx/platform.h @@ -4,6 +4,11 @@ #include #include "save_restore.h" +#ifndef KNX_FLASH_SIZE +#define KNX_FLASH_SIZE 1024 +#pragma warning "KNX_FLASH_SIZE not defined, using 1024" +#endif + enum NvMemoryType { Eeprom, @@ -49,21 +54,62 @@ class Platform virtual void setupSpi(); virtual void closeSpi(); virtual int readWriteSpi(uint8_t *data, size_t len); -#if 0 - // Flash memory - virtual size_t flashEraseBlockSize(); // in pages - virtual size_t flashPageSize(); // in bytes - virtual uint8_t* userFlashStart(); // start of user flash aligned to start of an erase block - virtual size_t userFlashSizeEraseBlocks(); // in eraseBlocks - virtual void flashErase(uint16_t eraseBlockNum); //relativ to userFlashStart - virtual void flashWritePage(uint16_t pageNumber, uint8_t* data); //write a single page to flash (pageNumber relative to userFashStart -#endif - virtual uint8_t* getEepromBuffer(uint16_t size) = 0; - virtual void commitToEeprom() = 0; + + //Memory + + // --- Overwrite these methods in the device-plattform to use the EEPROM Emulation API for UserMemory ---- + // + // --- changes to the UserMemory are written directly into the address space starting at getEepromBuffer + // --- commitToEeprom must save this to a non-volatile area if neccessary + virtual uint8_t* getEepromBuffer(uint16_t size); + virtual void commitToEeprom(); + // ------------------------------------------------------------------------------------------------------- + + virtual uint8_t* getNonVolatileMemoryStart(); + virtual size_t getNonVolatileMemorySize(); + virtual void commitNonVolatileMemory(); + // address is relative to start of nonvolatile memory + virtual uint32_t writeNonVolatileMemory(uint32_t relativeAddress, uint8_t* buffer, size_t size); NvMemoryType NonVolatileMemoryType(); void NonVolatileMemoryType(NvMemoryType type); + // --- Overwrite these methods in the device-plattform to use flash memory handling by the knx stack --- + // --- also set _memoryType = Flash in the device-plattform's contructor + // --- optional: overwrite writeBufferedEraseBlock() in the device-plattform to reduce overhead when flashing multiple pages + + // size of one flash page in bytes + virtual size_t flashPageSize(); + protected: + // size of one EraseBlock in pages + virtual size_t flashEraseBlockSize(); + // 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); + + + // ------------------------------------------------------------------------------------------------------- + + NvMemoryType _memoryType = Eeprom; + + void loadEraseblockContaining(uint32_t relativeAddress); + int32_t getEraseBlockNumberOf(uint32_t relativeAddress); + // writes _eraseblockBuffer to flash + virtual void writeBufferedEraseBlock(); + // copies a EraseBlock into the _eraseblockBuffer + void bufferEraseBlock(uint32_t eraseBlockNumber); + + // in theory we would have to use this buffer for memory reads too, + // but because ets always restarts the device after programming it + // we can ignore this issue + uint8_t* _eraseblockBuffer = nullptr; + int32_t _bufferedEraseblockNumber = -1; + bool _bufferedEraseblockDirty = false; }; \ No newline at end of file diff --git a/src/knx/table_object.cpp b/src/knx/table_object.cpp index 909337a..44c504e 100644 --- a/src/knx/table_object.cpp +++ b/src/knx/table_object.cpp @@ -82,7 +82,11 @@ bool TableObject::allocTable(uint32_t size, bool doFill, uint8_t fillByte) return false; if (doFill) - memset(_data, fillByte, size); + { + uint32_t addr = _memory.toRelative(_data); + for(int i = 0; i< size;i++) + _memory.writeMemory(addr+i, 1, &fillByte); + } _size = size; @@ -139,6 +143,7 @@ void TableObject::loadEventLoading(const uint8_t* data) case LE_START_LOADING: break; case LE_LOAD_COMPLETED: + _memory.saveMemory(); loadState(LS_LOADED); break; case LE_UNLOAD: @@ -293,7 +298,6 @@ void TableObject::initializeProperties(size_t propertiesSize, Property** propert //TODO: missing // 23 PID_TABLE 3 / (3) - // 27 PID_MCB_TABLE 3 / 3 uint8_t ownPropertiesCount = sizeof(ownProperties) / sizeof(Property*); diff --git a/src/rp2040_arduino_platform.cpp b/src/rp2040_arduino_platform.cpp index 6ab9909..e901502 100644 --- a/src/rp2040_arduino_platform.cpp +++ b/src/rp2040_arduino_platform.cpp @@ -1,16 +1,22 @@ /*----------------------------------------------------- Plattform for Raspberry Pi Pico and other RP2040 boards +by SirSydom 2021-2022 made to work with arduino-pico - "Raspberry Pi Pico Arduino core, for all RP2040 boards" by Earl E. Philhower III https://github.com/earlephilhower/arduino-pico V1.11.0 -by SirSydom 2021-2022 RTTI must be set to enabled in the board options -A maximum of 4kB emulated EEPROM is supported. -For more, use or own emulation (maybe with littlefs) +Uses direct flash reading/writing. +Size ist defined by KNX_FLASH_SIZE (default 4k) - must be a multiple of 4096. +Offset in Flash is defined by KNX_FLASH_OFFSET (default 1,5MiB / 0x180000) - must be a multiple of 4096. + +EEPROM Emulation from arduino-pico core (max 4k) can be use by defining USE_RP2040_EEPROM_EMULATION + +A RAM-buffered Flash can be use by defining USE_RP2040_LARGE_EEPROM_EMULATION + ----------------------------------------------------*/ @@ -25,6 +31,17 @@ For more, use or own emulation (maybe with littlefs) #include // EEPROM emulation in flash, part of Earl E Philhowers Pi Pico Arduino support #include // from Pico SDK #include // from Pico SDK +#include // from Pico SDK + +#define FLASHPTR ((uint8_t*)XIP_BASE + KNX_FLASH_OFFSET) + +#if KNX_FLASH_SIZE%4096 +#error "KNX_FLASH_SIZE must be multiple of 4096" +#endif + +#if KNX_FLASH_OFFSET%4096 +#error "KNX_FLASH_OFFSET must be multiple of 4096" +#endif RP2040ArduinoPlatform::RP2040ArduinoPlatform() @@ -32,10 +49,16 @@ RP2040ArduinoPlatform::RP2040ArduinoPlatform() : ArduinoPlatform(&Serial1) #endif { + #ifndef USE_RP2040_EEPROM_EMULATION + _memoryType = Flash; + #endif } RP2040ArduinoPlatform::RP2040ArduinoPlatform( HardwareSerial* s) : ArduinoPlatform(s) { + #ifndef USE_RP2040_EEPROM_EMULATION + _memoryType = Flash; + #endif } void RP2040ArduinoPlatform::setupUart() @@ -68,6 +91,47 @@ void RP2040ArduinoPlatform::restart() watchdog_reboot(0,0,0); } +#ifdef USE_RP2040_EEPROM_EMULATION + +#pragma warning "Using EEPROM Simulation" + +#ifdef USE_RP2040_LARGE_EEPROM_EMULATION + +uint8_t * RP2040ArduinoPlatform::getEepromBuffer(uint16_t size) +{ + if(size%4096) + { + println("KNX_FLASH_SIZE must be a multiple of 4096"); + fatalError(); + } + + if(!_rambuff_initialized) + { + memcpy(_rambuff, FLASHPTR, KNX_FLASH_SIZE); + _rambuff_initialized = true; + } + + return _rambuff; +} + +void RP2040ArduinoPlatform::commitToEeprom() +{ + noInterrupts(); + rp2040.idleOtherCore(); + + //ToDo: write block-by-block to prevent writing of untouched blocks + if(memcmp(_rambuff, FLASHPTR, KNX_FLASH_SIZE)) + { + flash_range_erase (KNX_FLASH_OFFSET, KNX_FLASH_SIZE); + flash_range_program(KNX_FLASH_OFFSET, _rambuff, KNX_FLASH_SIZE); + } + + rp2040.resumeOtherCore(); + interrupts(); +} + +#else + uint8_t * RP2040ArduinoPlatform::getEepromBuffer(uint16_t size) { if(size > 4096) @@ -91,6 +155,73 @@ void RP2040ArduinoPlatform::commitToEeprom() { EEPROM.commit(); } + +#endif + +#else + +size_t RP2040ArduinoPlatform::flashEraseBlockSize() +{ + return 16; // 16 pages x 256byte/page = 4096byte +} + +size_t RP2040ArduinoPlatform::flashPageSize() +{ + return 256; +} + +uint8_t* RP2040ArduinoPlatform::userFlashStart() +{ + return (uint8_t*)XIP_BASE + KNX_FLASH_OFFSET; +} + +size_t RP2040ArduinoPlatform::userFlashSizeEraseBlocks() +{ + if(KNX_FLASH_SIZE <= 0) + return 0; + else + return ( (KNX_FLASH_SIZE - 1) / (flashPageSize() * flashEraseBlockSize())) + 1; +} + +void RP2040ArduinoPlatform::flashErase(uint16_t eraseBlockNum) +{ + noInterrupts(); + rp2040.idleOtherCore(); + + flash_range_erase (KNX_FLASH_OFFSET + eraseBlockNum * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize()); + + rp2040.resumeOtherCore(); + interrupts(); +} + +void RP2040ArduinoPlatform::flashWritePage(uint16_t pageNumber, uint8_t* data) +{ + noInterrupts(); + rp2040.idleOtherCore(); + + flash_range_program(KNX_FLASH_OFFSET + pageNumber * flashPageSize(), data, flashPageSize()); + + rp2040.resumeOtherCore(); + interrupts(); +} + +void RP2040ArduinoPlatform::writeBufferedEraseBlock() +{ + if(_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty) + { + noInterrupts(); + rp2040.idleOtherCore(); + + flash_range_erase (KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize()); + flash_range_program(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), _eraseblockBuffer, flashPageSize() * flashEraseBlockSize()); + + rp2040.resumeOtherCore(); + interrupts(); + + _bufferedEraseblockDirty = false; + } +} +#endif #endif diff --git a/src/rp2040_arduino_platform.h b/src/rp2040_arduino_platform.h index 75cc7ff..8a9e7f3 100644 --- a/src/rp2040_arduino_platform.h +++ b/src/rp2040_arduino_platform.h @@ -4,6 +4,16 @@ #ifdef ARDUINO_ARCH_RP2040 +#ifndef KNX_FLASH_OFFSET +#define KNX_FLASH_OFFSET 0x180000 // 1.5MiB +#pragma warning "KNX_FLASH_OFFSET not defined, using 0x180000" +#endif + +#ifdef USE_RP2040_LARGE_EEPROM_EMULATION +#define USE_RP2040_EEPROM_EMULATION +#endif + + class RP2040ArduinoPlatform : public ArduinoPlatform { public: @@ -13,11 +23,36 @@ public: void setupUart(); // unique serial number - uint32_t uniqueSerialNumber() override; + uint32_t uniqueSerialNumber() override; void restart(); + + #ifdef USE_RP2040_EEPROM_EMULATION uint8_t* getEepromBuffer(uint16_t size); void commitToEeprom(); + + #ifdef USE_RP2040_LARGE_EEPROM_EMULATION + uint8_t _rambuff[KNX_FLASH_SIZE]; + bool _rambuff_initialized = false; + #endif + #else + + // 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(); + #endif }; #endif