Skip to content

Commit 9174488

Browse files
committed
UpdateClass - improve flash erase/writes
- on flash writes try to use large block erase - skip writing empty blocks of data after erase
1 parent 08f26cc commit 9174488

File tree

2 files changed

+32
-4
lines changed

2 files changed

+32
-4
lines changed

libraries/Update/src/Update.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828

2929
#define ENCRYPTED_BLOCK_SIZE 16
3030

31+
#define SPI_SECTORS_PER_BLOCK 16 // usually large erase block is 32k/64k
32+
#define SPI_FLASH_BLOCK_SIZE (SPI_SECTORS_PER_BLOCK*SPI_FLASH_SEC_SIZE)
33+
3134
class UpdateClass {
3235
public:
3336
typedef std::function<void(size_t, size_t)> THandlerFunction_Progress;
@@ -166,6 +169,7 @@ class UpdateClass {
166169
bool _verifyHeader(uint8_t data);
167170
bool _verifyEnd();
168171
bool _enablePartition(const esp_partition_t* partition);
172+
bool _chkDataInBlock(const uint8_t *data, size_t len) const; // check if block contains any data or is empty
169173

170174

171175
uint8_t _error;

libraries/Update/src/Updater.cpp

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,14 +203,22 @@ bool UpdateClass::_writeBuffer(){
203203
if (!_progress && _progress_callback) {
204204
_progress_callback(0, _size);
205205
}
206-
if(!ESP.partitionEraseRange(_partition, _progress, SPI_FLASH_SEC_SIZE)){
207-
_abort(UPDATE_ERROR_ERASE);
208-
return false;
206+
bool block_erase = (_size - _progress >= SPI_FLASH_BLOCK_SIZE) && ((_partition->address + _progress) % SPI_FLASH_BLOCK_SIZE == 0); // if it's the block boundary, than erase the whole block from here
207+
bool part_head_sectors = _partition->address % SPI_FLASH_BLOCK_SIZE && (_progress < SPI_FLASH_BLOCK_SIZE); // sector belong to unaligned partition heading block
208+
bool part_tail_sectors = _partition->address + _progress > (_partition->address + _size) / SPI_FLASH_BLOCK_SIZE * SPI_FLASH_BLOCK_SIZE; // sector belong to unaligned partition tailing block
209+
if (block_erase || part_head_sectors || part_tail_sectors){
210+
if(!ESP.partitionEraseRange(_partition, _progress, block_erase ? SPI_FLASH_BLOCK_SIZE : SPI_FLASH_SEC_SIZE)){
211+
_abort(UPDATE_ERROR_ERASE);
212+
return false;
213+
}
209214
}
210-
if (!ESP.partitionWrite(_partition, _progress + skip, (uint32_t*)_buffer + skip/sizeof(uint32_t), _bufferLen - skip)) {
215+
216+
// try to skip empty blocks on unecrypted partitions
217+
if ((_partition->encrypted || _chkDataInBlock(_buffer + skip/sizeof(uint32_t), _bufferLen - skip)) && !ESP.partitionWrite(_partition, _progress + skip, (uint32_t*)_buffer + skip/sizeof(uint32_t), _bufferLen - skip)) {
211218
_abort(UPDATE_ERROR_WRITE);
212219
return false;
213220
}
221+
214222
//restore magic or md5 will fail
215223
if(!_progress && _command == U_FLASH){
216224
_buffer[0] = ESP_IMAGE_HEADER_MAGIC;
@@ -389,4 +397,20 @@ const char * UpdateClass::errorString(){
389397
return _err2str(_error);
390398
}
391399

400+
bool UpdateClass::_chkDataInBlock(const uint8_t *data, size_t len) const {
401+
// check 32-bit aligned blocks only
402+
if (!len || len % sizeof(uint32_t))
403+
return true;
404+
405+
size_t dwl = len / sizeof(uint32_t);
406+
407+
do {
408+
if (*(uint32_t*)data ^ 0xffffffff) // for SPI NOR flash empty blocks are all one's, i.e. filled with 0xff byte
409+
return true;
410+
411+
data += sizeof(uint32_t);
412+
} while (--dwl);
413+
return false;
414+
}
415+
392416
UpdateClass Update;

0 commit comments

Comments
 (0)