From c036bb8fc24cd599e078cfc472e778ad8055bb00 Mon Sep 17 00:00:00 2001 From: kidproquo Date: Thu, 26 Feb 2026 15:29:29 -0800 Subject: [PATCH 1/3] Add 64KB block erase functionality to QSPI --- src/per/qspi.cpp | 67 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 6 deletions(-) diff --git a/src/per/qspi.cpp b/src/per/qspi.cpp index 3c58089a6..cc856fdbb 100644 --- a/src/per/qspi.cpp +++ b/src/per/qspi.cpp @@ -65,6 +65,8 @@ class QSPIHandle::Impl QSPIHandle::Result EraseSector(uint32_t address); + QSPIHandle::Result EraseBlock64K(uint32_t address); + uint32_t GetPin(size_t pin); GPIO_TypeDef* GetPort(size_t pin); @@ -434,21 +436,74 @@ QSPIHandle::Result QSPIHandle::Impl::Erase(uint32_t start_addr, uint32_t end_addr) { uint32_t block_addr; - uint32_t block_size = IS25LP080D_SECTOR_SIZE; // 4kB blocks for now. - // 64kB chunks for now. - start_addr = start_addr - (start_addr % block_size); + constexpr uint32_t BLOCK_64K = 0x10000; // 64KB + constexpr uint32_t SECTOR_4K = 0x1000; // 4KB + + // Align start address down to 4KB boundary + start_addr = start_addr - (start_addr % SECTOR_4K); + while(end_addr > start_addr) { block_addr = start_addr & 0x0FFFFFFF; - if(EraseSector(block_addr) != QSPIHandle::Result::OK) + + // Use 64KB block erase when aligned and enough space remaining + if((block_addr % BLOCK_64K) == 0 && (end_addr - start_addr) >= BLOCK_64K) { - ERR_RECOVERY(Status::E_HAL_ERROR); + if(EraseBlock64K(block_addr) != QSPIHandle::Result::OK) + { + ERR_RECOVERY(Status::E_HAL_ERROR); + } + start_addr += BLOCK_64K; + } + else + { + // Fall back to 4KB sector erase + if(EraseSector(block_addr) != QSPIHandle::Result::OK) + { + ERR_RECOVERY(Status::E_HAL_ERROR); + } + start_addr += SECTOR_4K; } - start_addr += block_size; } return QSPIHandle::Result::OK; } +QSPIHandle::Result QSPIHandle::Impl::EraseBlock64K(uint32_t address) +{ + QSPI_CommandTypeDef s_command; + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = BLOCK_ERASE_CMD; // 0xD8 = 64KB block erase + s_command.AddressMode = QSPI_ADDRESS_1_LINE; + s_command.AddressSize = QSPI_ADDRESS_24_BITS; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + s_command.Address = address; + + RETURN_IF_ERR(CheckProgramMemory()); + RETURN_IF_ERR(SetMode(Config::Mode::INDIRECT_POLLING)); + + if(WriteEnable() != QSPIHandle::Result::OK) + { + ERR_RECOVERY(Status::E_HAL_ERROR); + } + if(HAL_QSPI_Command(&halqspi_, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) + { + ERR_RECOVERY(Status::E_HAL_ERROR); + } + if(AutopollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) + != QSPIHandle::Result::OK) + { + ERR_RECOVERY(Status::E_HAL_ERROR); + } + + return QSPIHandle::Result::OK; +} QSPIHandle::Result QSPIHandle::Impl::EraseSector(uint32_t address) { From 7d6c050a7e92e00d07904bc091279d6d35f671bb Mon Sep 17 00:00:00 2001 From: kidproquo Date: Mon, 2 Mar 2026 17:20:14 -0800 Subject: [PATCH 2/3] Fix clang-format issues --- src/per/qspi.cpp | 131 ++++++++++++++++++++++++----------------------- 1 file changed, 66 insertions(+), 65 deletions(-) diff --git a/src/per/qspi.cpp b/src/per/qspi.cpp index cc856fdbb..a84b65fe1 100644 --- a/src/per/qspi.cpp +++ b/src/per/qspi.cpp @@ -433,76 +433,77 @@ QSPIHandle::Impl::Write(uint32_t address, uint32_t size, uint8_t* buffer) QSPIHandle::Result QSPIHandle::Impl::Erase(uint32_t start_addr, - uint32_t end_addr) + uint32_t end_addr) { - uint32_t block_addr; - constexpr uint32_t BLOCK_64K = 0x10000; // 64KB - constexpr uint32_t SECTOR_4K = 0x1000; // 4KB - - // Align start address down to 4KB boundary - start_addr = start_addr - (start_addr % SECTOR_4K); - - while(end_addr > start_addr) - { - block_addr = start_addr & 0x0FFFFFFF; - - // Use 64KB block erase when aligned and enough space remaining - if((block_addr % BLOCK_64K) == 0 && (end_addr - start_addr) >= BLOCK_64K) - { - if(EraseBlock64K(block_addr) != QSPIHandle::Result::OK) - { - ERR_RECOVERY(Status::E_HAL_ERROR); - } - start_addr += BLOCK_64K; - } - else - { - // Fall back to 4KB sector erase - if(EraseSector(block_addr) != QSPIHandle::Result::OK) - { - ERR_RECOVERY(Status::E_HAL_ERROR); - } - start_addr += SECTOR_4K; - } - } - return QSPIHandle::Result::OK; + uint32_t block_addr; + constexpr uint32_t BLOCK_64K = 0x10000; // 64KB + constexpr uint32_t SECTOR_4K = 0x1000; // 4KB + + // Align start address down to 4KB boundary + start_addr = start_addr - (start_addr % SECTOR_4K); + + while(end_addr > start_addr) + { + block_addr = start_addr & 0x0FFFFFFF; + + // Use 64KB block erase when aligned and enough space remaining + if((block_addr % BLOCK_64K) == 0 + && (end_addr - start_addr) >= BLOCK_64K) + { + if(EraseBlock64K(block_addr) != QSPIHandle::Result::OK) + { + ERR_RECOVERY(Status::E_HAL_ERROR); + } + start_addr += BLOCK_64K; + } + else + { + // Fall back to 4KB sector erase + if(EraseSector(block_addr) != QSPIHandle::Result::OK) + { + ERR_RECOVERY(Status::E_HAL_ERROR); + } + start_addr += SECTOR_4K; + } + } + return QSPIHandle::Result::OK; } QSPIHandle::Result QSPIHandle::Impl::EraseBlock64K(uint32_t address) { - QSPI_CommandTypeDef s_command; - s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; - s_command.Instruction = BLOCK_ERASE_CMD; // 0xD8 = 64KB block erase - s_command.AddressMode = QSPI_ADDRESS_1_LINE; - s_command.AddressSize = QSPI_ADDRESS_24_BITS; - s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; - s_command.DataMode = QSPI_DATA_NONE; - s_command.DummyCycles = 0; - s_command.NbData = 1; - s_command.DdrMode = QSPI_DDR_MODE_DISABLE; - s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; - s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; - s_command.Address = address; - - RETURN_IF_ERR(CheckProgramMemory()); - RETURN_IF_ERR(SetMode(Config::Mode::INDIRECT_POLLING)); - - if(WriteEnable() != QSPIHandle::Result::OK) - { - ERR_RECOVERY(Status::E_HAL_ERROR); - } - if(HAL_QSPI_Command(&halqspi_, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) - != HAL_OK) - { - ERR_RECOVERY(Status::E_HAL_ERROR); - } - if(AutopollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) - != QSPIHandle::Result::OK) - { - ERR_RECOVERY(Status::E_HAL_ERROR); - } - - return QSPIHandle::Result::OK; + QSPI_CommandTypeDef s_command; + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = BLOCK_ERASE_CMD; // 0xD8 = 64KB block erase + s_command.AddressMode = QSPI_ADDRESS_1_LINE; + s_command.AddressSize = QSPI_ADDRESS_24_BITS; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + s_command.Address = address; + + RETURN_IF_ERR(CheckProgramMemory()); + RETURN_IF_ERR(SetMode(Config::Mode::INDIRECT_POLLING)); + + if(WriteEnable() != QSPIHandle::Result::OK) + { + ERR_RECOVERY(Status::E_HAL_ERROR); + } + if(HAL_QSPI_Command(&halqspi_, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) + { + ERR_RECOVERY(Status::E_HAL_ERROR); + } + if(AutopollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) + != QSPIHandle::Result::OK) + { + ERR_RECOVERY(Status::E_HAL_ERROR); + } + + return QSPIHandle::Result::OK; } QSPIHandle::Result QSPIHandle::Impl::EraseSector(uint32_t address) From 032316025aae27d7849a82d0b46d1348888aa1cc Mon Sep 17 00:00:00 2001 From: Stephen Hensley Date: Thu, 2 Apr 2026 13:50:26 -0700 Subject: [PATCH 3/3] style fix. --- src/per/qspi.cpp | 132 +++++++++++++++++++++++------------------------ 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/src/per/qspi.cpp b/src/per/qspi.cpp index a84b65fe1..70640dfb0 100644 --- a/src/per/qspi.cpp +++ b/src/per/qspi.cpp @@ -433,77 +433,77 @@ QSPIHandle::Impl::Write(uint32_t address, uint32_t size, uint8_t* buffer) QSPIHandle::Result QSPIHandle::Impl::Erase(uint32_t start_addr, - uint32_t end_addr) + uint32_t end_addr) { - uint32_t block_addr; - constexpr uint32_t BLOCK_64K = 0x10000; // 64KB - constexpr uint32_t SECTOR_4K = 0x1000; // 4KB - - // Align start address down to 4KB boundary - start_addr = start_addr - (start_addr % SECTOR_4K); - - while(end_addr > start_addr) - { - block_addr = start_addr & 0x0FFFFFFF; - - // Use 64KB block erase when aligned and enough space remaining - if((block_addr % BLOCK_64K) == 0 - && (end_addr - start_addr) >= BLOCK_64K) - { - if(EraseBlock64K(block_addr) != QSPIHandle::Result::OK) - { - ERR_RECOVERY(Status::E_HAL_ERROR); - } - start_addr += BLOCK_64K; - } - else - { - // Fall back to 4KB sector erase - if(EraseSector(block_addr) != QSPIHandle::Result::OK) - { - ERR_RECOVERY(Status::E_HAL_ERROR); - } - start_addr += SECTOR_4K; - } - } - return QSPIHandle::Result::OK; + uint32_t block_addr; + constexpr uint32_t BLOCK_64K = 0x10000; // 64KB + constexpr uint32_t SECTOR_4K = 0x1000; // 4KB + + // Align start address down to 4KB boundary + start_addr = start_addr - (start_addr % SECTOR_4K); + + while(end_addr > start_addr) + { + block_addr = start_addr & 0x0FFFFFFF; + + // Use 64KB block erase when aligned and enough space remaining + if((block_addr % BLOCK_64K) == 0 + && (end_addr - start_addr) >= BLOCK_64K) + { + if(EraseBlock64K(block_addr) != QSPIHandle::Result::OK) + { + ERR_RECOVERY(Status::E_HAL_ERROR); + } + start_addr += BLOCK_64K; + } + else + { + // Fall back to 4KB sector erase + if(EraseSector(block_addr) != QSPIHandle::Result::OK) + { + ERR_RECOVERY(Status::E_HAL_ERROR); + } + start_addr += SECTOR_4K; + } + } + return QSPIHandle::Result::OK; } QSPIHandle::Result QSPIHandle::Impl::EraseBlock64K(uint32_t address) { - QSPI_CommandTypeDef s_command; - s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; - s_command.Instruction = BLOCK_ERASE_CMD; // 0xD8 = 64KB block erase - s_command.AddressMode = QSPI_ADDRESS_1_LINE; - s_command.AddressSize = QSPI_ADDRESS_24_BITS; - s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; - s_command.DataMode = QSPI_DATA_NONE; - s_command.DummyCycles = 0; - s_command.NbData = 1; - s_command.DdrMode = QSPI_DDR_MODE_DISABLE; - s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; - s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; - s_command.Address = address; - - RETURN_IF_ERR(CheckProgramMemory()); - RETURN_IF_ERR(SetMode(Config::Mode::INDIRECT_POLLING)); - - if(WriteEnable() != QSPIHandle::Result::OK) - { - ERR_RECOVERY(Status::E_HAL_ERROR); - } - if(HAL_QSPI_Command(&halqspi_, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) - != HAL_OK) - { - ERR_RECOVERY(Status::E_HAL_ERROR); - } - if(AutopollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) - != QSPIHandle::Result::OK) - { - ERR_RECOVERY(Status::E_HAL_ERROR); - } - - return QSPIHandle::Result::OK; + QSPI_CommandTypeDef s_command; + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = BLOCK_ERASE_CMD; // 0xD8 = 64KB block erase + s_command.AddressMode = QSPI_ADDRESS_1_LINE; + s_command.AddressSize = QSPI_ADDRESS_24_BITS; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + s_command.Address = address; + + RETURN_IF_ERR(CheckProgramMemory()); + RETURN_IF_ERR(SetMode(Config::Mode::INDIRECT_POLLING)); + + if(WriteEnable() != QSPIHandle::Result::OK) + { + ERR_RECOVERY(Status::E_HAL_ERROR); + } + if(HAL_QSPI_Command(&halqspi_, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) + { + ERR_RECOVERY(Status::E_HAL_ERROR); + } + if(AutopollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) + != QSPIHandle::Result::OK) + { + ERR_RECOVERY(Status::E_HAL_ERROR); + } + + return QSPIHandle::Result::OK; } QSPIHandle::Result QSPIHandle::Impl::EraseSector(uint32_t address)