Skip to content

Commit 840271c

Browse files
committed
nRF52: Fix unreliable internal flash writes when writing >2k (big issue for compaction) (fix #2509)
1 parent c947f39 commit 840271c

File tree

2 files changed

+29
-25
lines changed

2 files changed

+29
-25
lines changed

ChangeLog

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
BLE: Ensure all Espruino devices advertise the Espruino 0x0590 manufacturer ID by default
4848
- The default Nordic UART scan response will be removed in future to reduce power usage
4949
nRF52: Ensure that if enabled the HID service gets added to the main advertising packet (#2631)
50+
nRF52: Fix unreliable internal flash writes when writing >2k (big issue for compaction) (fix #2509)
5051

5152
2v25 : ESP32C3: Get analogRead working correctly
5253
Graphics: Adjust image alignment when rotating images to avoid cropping (fix #2535)

targets/nrf5x/jshardware.c

+28-25
Original file line numberDiff line numberDiff line change
@@ -2546,6 +2546,7 @@ void jshFlashRead(void * buf, uint32_t addr, uint32_t len) {
25462546
* Writes an array of bytes to memory. Addr must be word aligned and len must be a multiple of 4.
25472547
*/
25482548
void jshFlashWrite(void * buf, uint32_t addr, uint32_t len) {
2549+
assert((len&3)==0); // ensure we're always a multiple of 4 long
25492550
//jsiConsolePrintf("\njshFlashWrite 0x%x addr 0x%x -> 0x%x, len %d\n", *(uint32_t*)buf, (uint32_t)buf, addr, len);
25502551
#ifdef SPIFLASH_BASE
25512552
if ((addr >= SPIFLASH_BASE) && (addr < (SPIFLASH_BASE+SPIFLASH_LENGTH))) {
@@ -2639,40 +2640,42 @@ void jshFlashWrite(void * buf, uint32_t addr, uint32_t len) {
26392640
if (jshFlashWriteProtect(addr)) return;
26402641
uint32_t err = 0;
26412642

2642-
if (((size_t)(char*)buf)&3) {
2643-
/* Unaligned *SOURCE* is a problem on nRF5x,
2644-
* so if so we are unaligned, do a whole bunch
2645-
* of tiny writes via a buffer */
2646-
while (len>=4 && !err) {
2647-
flashIsBusy = true;
2648-
uint32_t alignedBuf;
2649-
memcpy(&alignedBuf, buf, 4);
2650-
while ((err = sd_flash_write((uint32_t*)addr, &alignedBuf, 1)) == NRF_ERROR_BUSY);
2651-
if (err!=NRF_SUCCESS) flashIsBusy = false;
2652-
WAIT_UNTIL(!flashIsBusy, "jshFlashWrite");
2653-
len -= 4;
2654-
addr += 4;
2655-
buf = (void*)(4+(char*)buf);
2656-
}
2657-
} else {
2658-
flashIsBusy = true;
2659-
uint32_t wordOffset = 0;
2660-
while (len>0 && !jspIsInterrupted()) {
2661-
uint32_t l = len;
2643+
uint32_t wraddr = addr, wrlen = len; // destination + length, we increment these as we write
2644+
uint8_t *wrbuf = (uint8_t*)buf; // source, we increment this as we write
2645+
uint8_t alignedBuf[32]; // aligned buffer if writes need it (misaligned source)
2646+
2647+
while (wrlen>0 && !jspIsInterrupted()) {
2648+
uint32_t l = wrlen;
2649+
uint8_t *awrbuf = wrbuf; // write buffer pointer (always updated to be aligned)
26622650
#ifdef NRF51_SERIES
2663-
if (l>1024) l=1024; // max write size
2651+
if (l>1024) l=1024; // max write size
26642652
#else // SD 6.1.1 doesn't like flash ops that take too long so we must not write the full 4096 (probably a good plan on older SD too)
2665-
if (l>2048) l=2048; // max write size
2653+
if (l>2048) l=2048; // max write size
26662654
#endif
2667-
len -= l;
2668-
while ((err = sd_flash_write(((uint32_t*)addr)+wordOffset, ((uint32_t *)buf)+wordOffset, l>>2)) == NRF_ERROR_BUSY && !jspIsInterrupted());
2669-
wordOffset += l>>2;
2655+
if ((size_t)wrbuf & 3) {
2656+
// Unaligned *SOURCE* is a problem on nRF5x, so if so we are unaligned, do a whole bunch of tiny writes via a buffer
2657+
if (l>sizeof(alignedBuf)) l=sizeof(alignedBuf); // max write size
2658+
memcpy(alignedBuf, wrbuf, l);
2659+
awrbuf = wrbuf;
26702660
}
2661+
2662+
flashIsBusy = true;
2663+
while ((err = sd_flash_write(wraddr, awrbuf, l>>2)) == NRF_ERROR_BUSY && !jspIsInterrupted());
26712664
if (err!=NRF_SUCCESS) flashIsBusy = false;
26722665
WAIT_UNTIL(!flashIsBusy, "jshFlashWrite");
2666+
wrlen -= l;
2667+
wraddr += l;
2668+
wrbuf += l;
26732669
}
26742670
if (err!=NRF_SUCCESS)
26752671
jsExceptionHere(JSET_INTERNALERROR,"NRF ERROR 0x%x", err);
2672+
/* // (slow!) sanity check to ensure that all data is written correctly:
2673+
for (int i=0;i<len;i++) {
2674+
uint8_t a = ((uint8_t*)addr)[i];
2675+
uint8_t b = ((uint8_t*)buf)[i];
2676+
if (a!=b)
2677+
jsiConsolePrintf("Write failed at 0x%08x+%d %d!=%d\n", addr,i, a,b);
2678+
}*/
26762679
}
26772680

26782681
// Just pass data through, since we can access flash at the same address we wrote it

0 commit comments

Comments
 (0)