diff --git a/module_flash/include/flash.h b/module_flash/include/flash.h index 592e0d5..c64a1fc 100644 --- a/module_flash/include/flash.h +++ b/module_flash/include/flash.h @@ -409,6 +409,25 @@ unsigned fl_getWriteScratchSize(unsigned offset, unsigned size); int fl_writeData(unsigned offset, unsigned size, const unsigned char src[], unsigned char buffer[]); +/* Block level functions */ + +/** + * Write data to the data partition as blocks. A buffer is used to save + * the current data inside blocks that will be erased. The minimum size + * of the required buffer should be the same size as data being written, plus + * the size of 2 blocks. This function is used to minimize the regions of + * memory that need to be erased during data editing. Since not all memories + * support this feature, this function can be used on memories that have the + * sector erase size defined. + * \param offset The offset from the start of the data partition in bytes. + * \param size The number of bytes to write. + * \param src The data to write. + * \param buffer + * \return 0 on success, non zero on failure. + */ +int fl_writeDataAsBlocks(unsigned int offset, unsigned int size, + const unsigned char src[], unsigned char buffer[]); + /* Page level functions. */ /** diff --git a/module_flash/src/flashlib.c b/module_flash/src/flashlib.c index 0c5d647..5080b55 100755 --- a/module_flash/src/flashlib.c +++ b/module_flash/src/flashlib.c @@ -963,6 +963,61 @@ int fl_writeData(unsigned int offset, unsigned int size, return( 0 ); } +/* Write and arbitrary number of bytes to the store (endangers data sharing pages/sectors), + * block by block. + */ +int fl_writeDataAsBlocks(unsigned int offset, unsigned int size, + const unsigned char src[], unsigned char buffer[]) { + unsigned blockSize = g_flashAccess->sectorEraseSize; + if (blockSize == 0) { + return 1; // Used memory type cannot erase individual blocks + } + + unsigned startAddress = fl_getDataPartitionBase() + offset; + + // Remember the address of the first block thet needs to be buffered. + // If block remainder is zero, then the address is the start address. + unsigned firstBlockDataStartAddress = startAddress % blockSize; + unsigned blockStartAddress = startAddress - firstBlockDataStartAddress; + unsigned firstBlockRemainder = blockSize - firstBlockDataStartAddress; + + unsigned totalBlocksUsed = 1; + if (size > firstBlockRemainder) { + totalBlocksUsed += (size - firstBlockRemainder) / blockSize; + if ((size - firstBlockRemainder) % blockSize != 0) { + totalBlocksUsed++; + } + } + + // Store all of the blocks that will be erased into a buffer + if (fl_int_readBytes(g_flashAccess, blockStartAddress, buffer, totalBlocksUsed * blockSize) != 0) { + return 1; + } + + // Overwrite the old data with new + memcpy(buffer + firstBlockDataStartAddress, src, size); + + // Erase blocks + for (int i = 0; i < totalBlocksUsed; i++) { + fl_int_waitWhileWriting(g_flashAccess); + fl_setWritability(1); + fl_int_issueShortCommand(g_flashAccess->sectorEraseCommand, blockStartAddress + i * blockSize, 3, 0, 0); + } + + fl_int_waitWhileWriting(g_flashAccess); + fl_setWritability(0); + + // Write the new blocks into memory page by page + int totalPagesToWriteBack = totalBlocksUsed * (blockSize / fl_getPageSize()); + for (int i = 0; i < totalPagesToWriteBack; i++) { + if (fl_writePage(blockStartAddress + i * 256, buffer + i * 256) != 0) { + return 1; + } + } + + return 0; +} + int fl_int_copySpec( fl_DeviceSpec* dest ) { if( NULL == g_flashAccess )