diff --git a/include/sta/drivers/w25qxx.hpp b/include/sta/drivers/w25qxx.hpp index 9c40ffe..9d93c20 100644 --- a/include/sta/drivers/w25qxx.hpp +++ b/include/sta/drivers/w25qxx.hpp @@ -39,6 +39,18 @@ namespace sta _32BIT }; + /** + * @brief + * + */ + enum class ChunkSize + { + PAGE, + SECTOR, + BLOCK_32KB, + BLOCK_64KB + }; + class W25Qxx { public: @@ -62,13 +74,18 @@ namespace sta */ uint8_t init(); + uint32_t getChunkBytes(ChunkSize size); + /** - * @brief Find the last page satisfying the given criterion. Uses a binary search to find this page. + * @brief Find the first memory section not satisfying a given criterion using a binary search. + * + * @note This function assume that there is a page n such that every page before n satisfies the criterion, while every page after that doesn't * * @param criterion A function evaluating the criterion on a page. + * @param size The size of the memory section. Has to be one of the predefined sizes. * @return uint32_t The last address such that the criterion is satisfied. */ - uint32_t findLastPage(std::function criterion); + uint32_t findLast(std::function criterion, ChunkSize size); /** * @brief Set the Address Mode object @@ -188,6 +205,8 @@ namespace sta * @return uint8_t */ uint8_t pageProgram(uint32_t address, uint8_t * buffer, size_t length); + + uint8_t sectorProgram(uint32_t address, uint8_t * buffer, size_t length); public: /* * Erase operations diff --git a/include/sta/drivers/w25qxx_defs.hpp b/include/sta/drivers/w25qxx_defs.hpp index 9557178..64fc3b5 100644 --- a/include/sta/drivers/w25qxx_defs.hpp +++ b/include/sta/drivers/w25qxx_defs.hpp @@ -57,8 +57,15 @@ #define W25QXX_INDIV_BLOCK_UNLOCK 0x39 #define W25QXX_READ_BLOCK_LOCK 0x3D - #define W25QXX_DEVICE_ID_RESULT 0xEF +#define W25QXX_PAGE_SIZE 0x100 +#define W25QXX_SECTOR_SIZE 0x1000 +#define W25QXX_BLOCK_32_KB_SIZE 0x8000 +#define W25QXX_BLOCK_64_KB_SIZE 0xF000 + +#define W25QXX_24B_MEM_SIZE 0xFFFFFF +#define W25QXX_32B_MEM_SIZE 0xFFFFFFFF + #endif // STA_SENSORS_W25QXX_DEFS_HPP diff --git a/src/w25qxx.cpp b/src/w25qxx.cpp index 828d78a..61f0287 100644 --- a/src/w25qxx.cpp +++ b/src/w25qxx.cpp @@ -1,8 +1,10 @@ #include +#include #include #include #include +#include namespace sta @@ -44,21 +46,47 @@ namespace sta return 1; } - uint32_t W25Qxx::findLastPage(std::function criterion) + uint32_t W25Qxx::getChunkBytes(ChunkSize size) { + switch (size) + { + case ChunkSize::PAGE: + return W25QXX_PAGE_SIZE; + + case ChunkSize::SECTOR: + return W25QXX_SECTOR_SIZE; + + case ChunkSize::BLOCK_32KB: + return W25QXX_BLOCK_32_KB_SIZE; + + case ChunkSize::BLOCK_64KB: + return W25QXX_BLOCK_64_KB_SIZE; + + default: + STA_UNREACHABLE(); + break; + } + } + + uint32_t W25Qxx::findLast(std::function criterion, ChunkSize size) + { + uint32_t bytes = getChunkBytes(size); + uint32_t left = 0; - uint32_t right = 0xFFFFFFFF & (addrMode_ == AddressMode::_32BIT ? 0xFFFFFFFF : 0x00FFFFFF); + uint32_t right = (addrMode_ == AddressMode::_32BIT ? W25QXX_32B_MEM_SIZE : W25QXX_24B_MEM_SIZE) / bytes; uint32_t middle; - uint8_t * page = new uint8_t[256]; + + uint8_t * buffer = new uint8_t[bytes]; while (left < right) { - middle = (left + right) / 2 + 1; - readData(middle, page, 256); + middle = (left + right) / 2; + readData(middle * bytes, buffer, bytes); + STA_DEBUG_PRINTF("Left %d Middle %d Right %d\n", left, middle, right); - if (criterion(page)) + if (criterion(buffer)) { - left = middle; + left = middle+1; } else { @@ -66,7 +94,13 @@ namespace sta } } - return middle; + readData(middle * bytes, buffer, bytes); + if (!criterion(buffer)) + middle -= 1; + + delete[] buffer; + + return middle * bytes; } uint8_t W25Qxx::setAddressMode(AddressMode addrMode) @@ -145,9 +179,9 @@ namespace sta if (addrMode_ == AddressMode::_32BIT) { uint8_t addrBuffer[4] = { - (uint8_t) (address << 24), - (uint8_t) (address << 16), - (uint8_t) (address << 8), + (uint8_t) (address >> 24), + (uint8_t) (address >> 16), + (uint8_t) (address >> 8), (uint8_t) (address) }; @@ -156,17 +190,18 @@ namespace sta else { uint8_t addrBuffer[3] = { - (uint8_t) (address << 16), - (uint8_t) (address << 8), + (uint8_t) (address >> 16), + (uint8_t) (address >> 8), (uint8_t) (address) }; - return busRead(instruction, buffer, length, addrBuffer, 4); + return busRead(instruction, buffer, length, addrBuffer, 3); } } uint8_t W25Qxx::pageProgram(uint32_t address, uint8_t * buffer, size_t length) { + STA_ASSERT(length <= W25QXX_PAGE_SIZE); while (isBusy()) {} if (!writeEnable()) @@ -179,9 +214,9 @@ namespace sta if (addrMode_ == AddressMode::_32BIT) { uint8_t addrBuffer[4] = { - (uint8_t) (address << 24), - (uint8_t) (address << 16), - (uint8_t) (address << 8), + (uint8_t) (address >> 24), + (uint8_t) (address >> 16), + (uint8_t) (address >> 8), (uint8_t) (address) }; @@ -190,15 +225,32 @@ namespace sta else { uint8_t addrBuffer[3] = { - (uint8_t) (address << 16), - (uint8_t) (address << 8), + (uint8_t) (address >> 16), + (uint8_t) (address >> 8), (uint8_t) (address) }; - return busWrite(W25QXX_PAGE_PROGAM, buffer, length, addrBuffer, 4); + return busWrite(W25QXX_PAGE_PROGAM, buffer, length, addrBuffer, 3); } } + uint8_t W25Qxx::sectorProgram(uint32_t address, uint8_t * buffer, size_t length) + { + STA_ASSERT(length <= W25QXX_SECTOR_SIZE); + + uint32_t nPages = length / W25QXX_PAGE_SIZE; + uint32_t remainder = length % W25QXX_PAGE_SIZE; + + uint8_t rslt = 1; + + for (uint8_t i = 0; i < nPages; i++) + rslt &= pageProgram(address + i * W25QXX_PAGE_SIZE, buffer + i * W25QXX_PAGE_SIZE, W25QXX_PAGE_SIZE); + + rslt &= pageProgram(address + nPages * W25QXX_PAGE_SIZE, buffer + nPages * W25QXX_PAGE_SIZE, remainder); + + return rslt; + } + uint8_t W25Qxx::busWrite(uint8_t instruction, const uint8_t * data /* = nullptr */, size_t length /* = 0 */, uint8_t * arguments /* = nullptr */, size_t arg_length /* = 0 */, uint32_t delayCsHigh /*= 0 */) { device_->beginTransmission(); @@ -341,9 +393,9 @@ namespace sta if (addrMode_ == AddressMode::_32BIT) { uint8_t addrBuffer[4] = { - (uint8_t) (address << 24), - (uint8_t) (address << 16), - (uint8_t) (address << 8), + (uint8_t) (address >> 24), + (uint8_t) (address >> 16), + (uint8_t) (address >> 8), (uint8_t) (address) }; @@ -352,8 +404,8 @@ namespace sta else { uint8_t addrBuffer[3] = { - (uint8_t) (address << 16), - (uint8_t) (address << 8), + (uint8_t) (address >> 16), + (uint8_t) (address >> 8), (uint8_t) (address) }; @@ -377,9 +429,9 @@ namespace sta if (addrMode_ == AddressMode::_32BIT) { uint8_t addrBuffer[4] = { - (uint8_t) (address << 24), - (uint8_t) (address << 16), - (uint8_t) (address << 8), + (uint8_t) (address >> 24), + (uint8_t) (address >> 16), + (uint8_t) (address >> 8), (uint8_t) (address) }; @@ -388,8 +440,8 @@ namespace sta else { uint8_t addrBuffer[3] = { - (uint8_t) (address << 16), - (uint8_t) (address << 8), + (uint8_t) (address >> 16), + (uint8_t) (address >> 8), (uint8_t) (address) }; @@ -444,8 +496,8 @@ namespace sta while (!isWriteEnabled()) {} uint8_t addrBuffer[3] = { - (uint8_t) (address << 16), - (uint8_t) (address << 8), + (uint8_t) (address >> 16), + (uint8_t) (address >> 8), (uint8_t) (address) }; @@ -462,8 +514,8 @@ namespace sta while (!isWriteEnabled()) {} uint8_t addrBuffer[3] = { - (uint8_t) (address << 16), - (uint8_t) (address << 8), + (uint8_t) (address >> 16), + (uint8_t) (address >> 8), (uint8_t) (address) };