Skip to content

Commit 21620de

Browse files
MichaelBellGadgetoidprojectgus
committed
rp2/rp2_flash: Support writes from PSRAM.
Add a 256 byte (FLASH_PAGE_SIZE) SRAM copy buffer to allow copies from PSRAM to flash. This would otherwise hardfault since PSRAM is disabled to write flash. Changes: ports/rp2/rp2_flash.c: Add 256 byte (flash page size) SRAM copy buffer for PSRAM to flash copies. Invalidate the XIP cache to purge any PSRAM data before critical flash operations. Co-authored-by: Phil Howard <[email protected]> Co-authored-by: Angus Gratton <[email protected]> Signed-off-by: Phil Howard <[email protected]>
1 parent c3f7e72 commit 21620de

File tree

1 file changed

+59
-5
lines changed

1 file changed

+59
-5
lines changed

ports/rp2/rp2_flash.c

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,13 @@
3333
#include "modrp2.h"
3434
#include "hardware/flash.h"
3535
#include "pico/binary_info.h"
36+
#include "rp2_psram.h"
3637

3738
#define BLOCK_SIZE_BYTES (FLASH_SECTOR_SIZE)
3839

40+
// Size of buffer for flash writes from PSRAM, since they are mutually exclusive
41+
#define COPY_BUFFER_SIZE_BYTES (FLASH_PAGE_SIZE)
42+
3943
static_assert(MICROPY_HW_ROMFS_BYTES % 4096 == 0, "ROMFS size must be a multiple of 4K");
4044
static_assert(MICROPY_HW_FLASH_STORAGE_BYTES % 4096 == 0, "Flash storage size must be a multiple of 4K");
4145

@@ -96,10 +100,27 @@ static uint32_t begin_critical_flash_section(void) {
96100
if (use_multicore_lockout()) {
97101
multicore_lockout_start_blocking();
98102
}
99-
return save_and_disable_interrupts();
103+
uint32_t state = save_and_disable_interrupts();
104+
105+
#if MICROPY_HW_ENABLE_PSRAM
106+
// We're about to invalidate the XIP cache, clean it first to commit any dirty writes to PSRAM
107+
// Use the upper 16k of the maintenance space (0x1bffc000 through 0x1bffffff) to workaround
108+
// incorrect behaviour of the XIP clean operation, where it also alters the tag of the associated
109+
// cache line: https://forums.raspberrypi.com/viewtopic.php?t=378249#p2263677
110+
volatile uint8_t *maintenance_ptr = (volatile uint8_t *)(XIP_SRAM_BASE + (XIP_MAINTENANCE_BASE - XIP_BASE));
111+
for (int i = 1; i < 16 * 1024; i += 8) {
112+
maintenance_ptr[i] = 0;
113+
}
114+
#endif
115+
116+
return state;
100117
}
101118

102119
static void end_critical_flash_section(uint32_t state) {
120+
#if MICROPY_HW_ENABLE_PSRAM
121+
// The ROM function to program flash will reset PSRAM timings to defaults
122+
psram_init(MICROPY_HW_PSRAM_CS_PIN);
123+
#endif
103124
restore_interrupts(state);
104125
if (use_multicore_lockout()) {
105126
multicore_lockout_end_blocking();
@@ -192,10 +213,43 @@ static mp_obj_t rp2_flash_writeblocks(size_t n_args, const mp_obj_t *args) {
192213
} else {
193214
offset += mp_obj_get_int(args[3]);
194215
}
195-
mp_uint_t atomic_state = begin_critical_flash_section();
196-
flash_range_program(self->flash_base + offset, bufinfo.buf, bufinfo.len);
197-
end_critical_flash_section(atomic_state);
198-
mp_event_handle_nowait();
216+
217+
// If copying from SRAM, can write direct to flash.
218+
// If copying from PSRAM/flash, use an SRAM buffer and write in chunks.
219+
#if MICROPY_HW_ENABLE_PSRAM
220+
bool write_direct = (uintptr_t)bufinfo.buf >= SRAM_BASE;
221+
#else
222+
bool write_direct = true;
223+
#endif
224+
225+
if (write_direct) {
226+
// If copying from SRAM, write direct
227+
mp_uint_t atomic_state = begin_critical_flash_section();
228+
flash_range_program(self->flash_base + offset, bufinfo.buf, bufinfo.len);
229+
end_critical_flash_section(atomic_state);
230+
mp_event_handle_nowait();
231+
}
232+
#if MICROPY_HW_ENABLE_PSRAM
233+
else {
234+
size_t bytes_left = bufinfo.len;
235+
size_t bytes_offset = 0;
236+
static uint8_t copy_buffer[COPY_BUFFER_SIZE_BYTES] = {0};
237+
238+
while (bytes_left) {
239+
memcpy(copy_buffer, bufinfo.buf + bytes_offset, MIN(bytes_left, COPY_BUFFER_SIZE_BYTES));
240+
mp_uint_t atomic_state = begin_critical_flash_section();
241+
flash_range_program(self->flash_base + offset + bytes_offset, copy_buffer, MIN(bytes_left, COPY_BUFFER_SIZE_BYTES));
242+
end_critical_flash_section(atomic_state);
243+
bytes_offset += COPY_BUFFER_SIZE_BYTES;
244+
if (bytes_left <= COPY_BUFFER_SIZE_BYTES) {
245+
break;
246+
}
247+
bytes_left -= COPY_BUFFER_SIZE_BYTES;
248+
mp_event_handle_nowait();
249+
}
250+
}
251+
#endif
252+
199253
// TODO check return value
200254
return mp_const_none;
201255
}

0 commit comments

Comments
 (0)