mirror of
https://github.com/thelsing/knx.git
synced 2024-12-18 19:08:18 +01:00
Branch flash pr with large eeprom (#177)
* save WIP on flash api + header reorder * reduce diffs to master * added support for RP2040 (Raspberry Pi Pico) * support DPT9.009 (airflow) and DPT9.029 (absolute humidity) * added support for RP2040 (Raspberry Pi Pico) (#145) * worked on flash implementation * worked on flash implementation * added malloc for _EraseBlockBuffer, fixed some bugs * fixed memoryread and crash while loading KOs (+debugstuff) * some fixes and debugs * align to pagesize * clean up debug stuff, comments ... * added support for both Eeprom and Flash (NvMemoryType) plattforms. * changed memoryReadIndicationP to memoryReadIndication added stdlib and defines * fixed std::min * another try for fixing the min problem * rolled back linux plattform to eeprom * comments only, hints for plattforms * bugfix when calculating memorywrites over multiple blocks by mumpf * added support for EEPROM-Emulation / RAM-buffered Flash improvements in RP2040 plattform * fixed typo in KNX_FLASH_OFFSET * - writebuffersize clarified (PR discussion) - changed alignment from flashpagesize to 32bit - added override modifier (PR discussion) - changed comment regarding flash/eeprom functions for plattforms to override/implement (PR discussion) * resolved CodeFactor issue Co-authored-by: Thomas Kunze <thomas.kunze@gmx.com>
This commit is contained in:
parent
53425e2ef7
commit
a306174878
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -1,29 +1,36 @@
|
||||
#include "memory.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#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)
|
||||
|
@ -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
|
||||
|
@ -1,12 +1,15 @@
|
||||
#include "platform.h"
|
||||
|
||||
#include "bits.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -4,6 +4,11 @@
|
||||
#include <stddef.h>
|
||||
#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;
|
||||
};
|
@ -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*);
|
||||
|
||||
|
@ -1,16 +1,22 @@
|
||||
/*-----------------------------------------------------
|
||||
|
||||
Plattform for Raspberry Pi Pico and other RP2040 boards
|
||||
by SirSydom <com@sirsydom.de> 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 <com@sirsydom.de> 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.h> // EEPROM emulation in flash, part of Earl E Philhowers Pi Pico Arduino support
|
||||
#include <pico/unique_id.h> // from Pico SDK
|
||||
#include <hardware/watchdog.h> // from Pico SDK
|
||||
#include <hardware/flash.h> // 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
|
||||
|
||||
|
||||
|
@ -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:
|
||||
@ -16,8 +26,33 @@ public:
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user