- Notifications
You must be signed in to change notification settings - Fork13.3k
Handle unaligned address in EspClass::flashWrite u8 overload#8605
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes from1 commit
a83c0cd9a3a4fe553913c361b060e3ce307d7425f3349cbe0d4dcbe72530e918f198da175227278e236aFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
- Loading branch information
Uh oh!
There was an error while loading.Please reload this page.
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -673,7 +673,48 @@ bool EspClass::flashEraseSector(uint32_t sector) { | ||
| return rc == 0; | ||
| } | ||
| // Adapted from the old version of `flash_hal_write()` (before 3.0.0), which was used for SPIFFS to allow | ||
| // writing from both unaligned u8 buffers and to an unaligned offset on flash. | ||
| // Updated version re-uses some of the code from RTOS, replacing individual methods for block & page | ||
| // writes with just a single one | ||
| // https://github.com/espressif/ESP8266_RTOS_SDK/blob/master/components/spi_flash/src/spi_flash.c | ||
| // Wrapper around spi_flash_write, handling offset + size crossing page boundaries | ||
| // Note that we expect that both `offset` and `data` are properly aligned | ||
| static SpiFlashOpResult spi_flash_write_page_break(uint32_t offset, uint32_t* data, size_t size) { | ||
| static constexpr uint32_t PageSize { FLASH_PAGE_SIZE }; | ||
| size_t page_size = PageSize - (offset % PageSize); | ||
| // most common case, we don't cross a page and simply write the data | ||
| if (size < page_size) { | ||
| return spi_flash_write(offset, data, size); | ||
| } | ||
| // otherwise, write the initial part and continue writing breaking each page interval | ||
| SpiFlashOpResult result = SPI_FLASH_RESULT_ERR; | ||
| if ((result = spi_flash_write(offset, data, page_size)) != SPI_FLASH_RESULT_OK) { | ||
| return result; | ||
| } | ||
| uint32_t page_offset = PageSize; | ||
| for (uint32_t page = 0; page < (size - page_size) / PageSize; ++page) { | ||
mcspr marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| if ((result = spi_flash_write(offset + page_offset, data + (page_offset >> 2), PageSize)) != SPI_FLASH_RESULT_OK) { | ||
| return result; | ||
| } | ||
| page_offset += PageSize; | ||
| } | ||
| if ((offset + page_offset) < (offset + size)) { | ||
mcspr marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| return spi_flash_write(offset + page_offset, data + (page_offset >> 2), size - page_offset); | ||
| } | ||
| return SPI_FLASH_RESULT_OK; | ||
| } | ||
| #if PUYA_SUPPORT | ||
| // Special wrapper for spi_flash_write *only for PUYA flash chips* | ||
| // Already handles paging, could be used as a `spi_flash_write_page_break` replacement | ||
| static SpiFlashOpResult spi_flash_write_puya(uint32_t offset, uint32_t *data, size_t size) { | ||
| if (data == nullptr) { | ||
| return SPI_FLASH_RESULT_ERR; | ||
| @@ -720,195 +761,127 @@ static SpiFlashOpResult spi_flash_write_puya(uint32_t offset, uint32_t *data, si | ||
| } | ||
| #endif | ||
| static constexpr uint32_t Alignment { 4 }; | ||
| static uint32_t alignAddress(uint32_t address) { | ||
| static constexpr uint32_t Mask { Alignment - 1 }; | ||
| return (address + Mask) & ~Mask; | ||
| } | ||
| static uint32_t alignBeforeAddress(uint32_t address) { | ||
| return alignAddress(address) - Alignment; | ||
| } | ||
| static bool isAlignedAddress(uint32_t address) { | ||
| return (address & (Alignment - 1)) == 0; | ||
| } | ||
| static bool isAlignedSize(size_t size) { | ||
| return (size & (Alignment - 1)) == 0; | ||
| } | ||
| static bool isAlignedPointer(const uint8_t* ptr) { | ||
| return isAlignedAddress(reinterpret_cast<uint32_t>(ptr)); | ||
| } | ||
| size_t EspClass::flashWriteUnalignedMemory(uint32_t address, const uint8_t *data, size_t size) { | ||
| auto flash_write = [&](uint32_t address, uint8_t* data, size_t size) { | ||
| return flashWrite(address, reinterpret_cast<uint32_t*>(data), size); | ||
| }; | ||
| auto flash_read = [](uint32_t address, uint8_t* data, size_t size) { | ||
| return spi_flash_read(address, reinterpret_cast<uint32_t*>(data), size) == SPI_FLASH_RESULT_OK; | ||
| }; | ||
| alignas(alignof(uint32_t)) uint8_t buf[FLASH_PAGE_SIZE]; | ||
| size_t written = 0; | ||
| if (!isAlignedAddress(address)) { | ||
| auto r_addr = alignBeforeAddress(address); | ||
| auto c_off = address - r_addr; | ||
| auto wbytes = Alignment - c_off; | ||
| wbytes = std::min(wbytes, size); | ||
| if (spi_flash_read(r_addr, reinterpret_cast<uint32_t*>(&buf[0]), Alignment) != SPI_FLASH_RESULT_OK) { | ||
| return 0; | ||
| } | ||
| #if PUYA_SUPPORT | ||
| if (getFlashChipVendorId() == SPI_FLASH_VENDOR_PUYA) { | ||
| for (size_t i = 0; i < wbytes ; ++i) { | ||
| buf[c_off + i] &= data[i]; | ||
| } | ||
| } else { | ||
| #endif | ||
| memcpy(&buf[c_off], data, wbytes); | ||
| #if PUYA_SUPPORT | ||
| } | ||
| #endif | ||
| if (spi_flash_write(r_addr, reinterpret_cast<uint32_t*>(&buf[0]), Alignment) != SPI_FLASH_RESULT_OK) { | ||
| return wbytes; | ||
| } | ||
| address += wbytes; | ||
| data += wbytes; | ||
| written += wbytes; | ||
| size -= wbytes; | ||
| } | ||
| while (size > 0) { | ||
| auto len = std::min(size, sizeof(buf)); | ||
| ||
| auto wlen = alignAddress(len); | ||
| if (wlen != len) { | ||
| auto l_b = wlen - Alignment; | ||
| if (!flash_read(address + l_b, &buf[l_b], Alignment)) { | ||
| return written; | ||
| } | ||
| } | ||
| memcpy(&buf[0], data, len); | ||
| if (!flash_write(address, &buf[0], wlen)) { | ||
| return written; | ||
| } | ||
| address += len; | ||
| data += len; | ||
| written += len; | ||
| size -= len; | ||
| } | ||
| return written; | ||
| } | ||
| bool EspClass::flashWrite(uint32_t address, const uint32_t *data, size_t size) { | ||
| SpiFlashOpResult result; | ||
| #if PUYA_SUPPORT | ||
| if (getFlashChipVendorId() == SPI_FLASH_VENDOR_PUYA) { | ||
| result = spi_flash_write_puya(address, const_cast<uint32_t *>(data), size); | ||
| } | ||
| else | ||
| #endif | ||
| { | ||
| result =spi_flash_write_page_break(address, const_cast<uint32_t *>(data), size); | ||
| } | ||
| returnresult == SPI_FLASH_RESULT_OK; | ||
| } | ||
| bool EspClass::flashWrite(uint32_t address, const uint8_t *data, size_t size) { | ||
| if (data && size) { | ||
| if (!isAlignedAddress(address) | ||
| || !isAlignedPointer(data) | ||
| || !isAlignedSize(size)) | ||
| { | ||
| return flashWriteUnalignedMemory(address, data, size) == size; | ||
| } | ||
| return flashWrite(address, reinterpret_cast<const uint32_t *>(data), size) == size; | ||
| } | ||
| returnfalse; | ||
| } | ||
| bool EspClass::flashRead(uint32_t address, uint8_t *data, size_t size) { | ||