mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-09-09 13:25:36 +00:00
Fix QSPI wake race during OTA staging
This commit is contained in:
@@ -266,7 +266,7 @@ bool OtaStoreQspiNrf52::ensureFlash() {
|
||||
return false;
|
||||
}
|
||||
_qspi_awake = true;
|
||||
delayMicroseconds(50);
|
||||
delayMicroseconds(MOTA_QSPI_DPD_WAKE_GUARD_US);
|
||||
alignas(4) uint8_t jedec[4] = { 0, 0, 0, 0 };
|
||||
if (!customInstruction(0x9F, NRF_QSPI_CINSTR_LEN_4B, jedec) || jedec[0] == 0 || jedec[0] == 0xFF ||
|
||||
jedec[2] < 20 || jedec[2] > 24) {
|
||||
@@ -306,7 +306,10 @@ void OtaStoreQspiNrf52::releaseFlash() {
|
||||
// releasing the nRF QSPI peripheral instead of leaving both active for
|
||||
// the rest of the boot. ensureFlash() issues 0xAB on the next operation.
|
||||
(void)customInstruction(0xB9, NRF_QSPI_CINSTR_LEN_1B);
|
||||
delayMicroseconds(5);
|
||||
// Do not deactivate or let a following ensureFlash() assert CS until the
|
||||
// flash has both entered and remained in DPD for its required interval.
|
||||
// plan_layout() is intentionally followed immediately by begin().
|
||||
delayMicroseconds(MOTA_QSPI_DPD_ENTRY_GUARD_US);
|
||||
}
|
||||
// Match nrfx_qspi_uninit(): DEACTIVATE does not require a READY wait before
|
||||
// disabling the peripheral. Trigger it after every successful ENABLE, even
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(OTA_QSPI_STORE) && defined(QSPIFLASH)
|
||||
#error "OTA_QSPI_STORE raw staging cannot share a QSPI chip with QSPIFLASH"
|
||||
#endif
|
||||
@@ -16,6 +18,21 @@
|
||||
#error "RAK3401's RAK13302 radio already owns the WisBlock SPI bus/chip-select"
|
||||
#endif
|
||||
|
||||
namespace mesh {
|
||||
namespace ota {
|
||||
|
||||
// A status/capacity probe can be followed immediately by begin(). Supported
|
||||
// NOR parts need time both to enter deep power-down after B9 and to remain
|
||||
// there before CS may be asserted again. MX25R1635F needs 10 us + 30 us;
|
||||
// retain margin for scheduling granularity and other matched flashes.
|
||||
static const uint32_t MOTA_QSPI_DPD_ENTRY_GUARD_US = 50u;
|
||||
|
||||
// Release-from-deep-power-down latency is as high as 45 us on supported NOR.
|
||||
static const uint32_t MOTA_QSPI_DPD_WAKE_GUARD_US = 50u;
|
||||
|
||||
} // namespace ota
|
||||
} // namespace mesh
|
||||
|
||||
#if defined(NRF52_PLATFORM) && defined(OTA_QSPI_STORE)
|
||||
|
||||
#include "OtaStore.h"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <cstring>
|
||||
|
||||
#include "helpers/ota/OtaFlashLayout_nrf52.h"
|
||||
#include "helpers/ota/OtaStoreQspiNrf52.h"
|
||||
#include "helpers/ota/OtaSdHandoff.h"
|
||||
|
||||
using namespace mesh::ota;
|
||||
@@ -25,6 +26,15 @@ static constexpr uint32_t CAP_V7 = LEGACY - APP_END_V7;
|
||||
static constexpr uint32_t CAP_V6_EXPANDED = EXPANDED - APP_END_V6;
|
||||
static constexpr uint32_t CAP_V7_EXPANDED = EXPANDED - APP_END_V7;
|
||||
|
||||
TEST(OtaQspiTiming, PreservesDeepPowerDownEntryAndWakeGuards) {
|
||||
// MX25R1635F requires 10 us to enter DPD plus 30 us before another command;
|
||||
// its release latency can reach 45 us. These constants are consumed by the
|
||||
// real HAL path, so a future power-saving edit cannot restore the live
|
||||
// plan_layout()->begin() race without failing the native suite.
|
||||
EXPECT_GE(MOTA_QSPI_DPD_ENTRY_GUARD_US, 50u);
|
||||
EXPECT_GE(MOTA_QSPI_DPD_WAKE_GUARD_US, 45u);
|
||||
}
|
||||
|
||||
TEST(OtaFlashPlan, SelectsCeilingFromLinkedLayoutAndStorage) {
|
||||
// Actual internal secondary storage is authoritative regardless of linker selection.
|
||||
EXPECT_EQ(mota_nrf52_stage_ceiling_for_layout(EXPANDED, true), LEGACY);
|
||||
|
||||
Reference in New Issue
Block a user