Skip to content

Commit aeb3fec

Browse files
committed
Use larger flash erase sizes to speed up programming.
Loading a 600 KB UF2 file onto a Pico from Windows now takes 3.2 s instead of 4.8 s.
1 parent 03f2812 commit aeb3fec

File tree

6 files changed

+64
-8
lines changed

6 files changed

+64
-8
lines changed

main.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1838,29 +1838,38 @@ bool load_command::execute(device_map &devices) {
18381838
}
18391839
}
18401840
}
1841+
18411842
for (auto mem_range : ranges) {
18421843
enum memory_type type = get_memory_type(mem_range.from);
18431844
// new scope for progress bar
18441845
{
18451846
progress_bar bar("Loading into " + memory_names[type] + ": ");
1846-
uint32_t batch_size = FLASH_SECTOR_ERASE_SIZE;
1847-
bool ok = true;
18481847
vector<uint8_t> file_buf;
18491848
vector<uint8_t> device_buf;
1850-
for (uint32_t base = mem_range.from; base < mem_range.to && ok; ) {
1849+
for (uint32_t base = mem_range.from; base < mem_range.to; ) {
1850+
uint32_t batch_size = FLASH_SECTOR_ERASE_SIZE;
1851+
uint8_t block_erase_cmd = 0x20;
1852+
if (mem_range.to - base >= 0x10000) {
1853+
batch_size = 0x10000;
1854+
block_erase_cmd = 0xD8;
1855+
}
1856+
else if (mem_range.to - base >= 0x8000) {
1857+
batch_size = 0x8000;
1858+
block_erase_cmd = 0x52;
1859+
}
18511860
uint32_t this_batch = std::min(mem_range.to - base, batch_size);
18521861
if (type == flash) {
18531862
// we have to erase an entire page, so then fill with zeros
1854-
range aligned_range(base & ~(FLASH_SECTOR_ERASE_SIZE - 1), (base & ~(FLASH_SECTOR_ERASE_SIZE - 1)) + FLASH_SECTOR_ERASE_SIZE);
1863+
range aligned_range(base & ~(batch_size - 1), (base & ~(batch_size - 1)) + batch_size);
18551864
range read_range(base, base + this_batch);
18561865
read_range.intersect(aligned_range);
18571866
file_access.read_into_vector(read_range.from, read_range.to - read_range.from, file_buf);
1858-
// zero padding up to FLASH_SECTOR_ERASE_SIZE
1867+
// zero padding up to batch_size
18591868
file_buf.insert(file_buf.begin(), read_range.from - aligned_range.from, 0);
18601869
file_buf.insert(file_buf.end(), aligned_range.to - read_range.to, 0);
1861-
assert(file_buf.size() == FLASH_SECTOR_ERASE_SIZE);
1870+
assert(file_buf.size() == batch_size);
18621871
con.exit_xip();
1863-
con.flash_erase(aligned_range.from, FLASH_SECTOR_ERASE_SIZE);
1872+
con.flash_range_erase(aligned_range.from - FLASH_START, batch_size, batch_size, block_erase_cmd);
18641873
raw_access.write_vector(aligned_range.from, file_buf);
18651874
base = read_range.to; // about to add batch_size
18661875
} else {
@@ -1875,7 +1884,7 @@ bool load_command::execute(device_map &devices) {
18751884
bool ok = true;
18761885
{
18771886
progress_bar bar("Verifying " + memory_names[type] + ": ");
1878-
uint32_t batch_size = FLASH_SECTOR_ERASE_SIZE;
1887+
uint32_t batch_size = 0x8000;
18791888
vector<uint8_t> file_buf;
18801889
vector<uint8_t> device_buf;
18811890
uint32_t pos = mem_range.from;

picoboot_connection/call.s

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
.cpu cortex-m0
2+
.thumb
3+
push {r4, lr}
4+
mov r4, #20
5+
ldrh r0, [r4] // r0 = function_table
6+
ldrh r1, args
7+
ldrh r4, [r4, #4] // r4 = table_lookup
8+
blx r4
9+
mov r4, r0
10+
ldr r0, args + 4
11+
ldr r1, args + 8
12+
ldr r2, args + 12
13+
ldrb r3, args + 16
14+
blx r4
15+
pop {r4, pc}
16+
.balign 4, 0
17+
args:

picoboot_connection/picoboot_connection.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,28 @@ int picoboot_exec(libusb_device_handle *usb_device, uint32_t addr) {
305305
return picoboot_cmd(usb_device, &cmd, NULL, 0);
306306
}
307307

308+
// Calls flash_range_erase in the bootrom.
309+
int picoboot_flash_range_erase(libusb_device_handle *usb_device,
310+
uint32_t addr, uint32_t len, uint32_t block_size, uint8_t block_cmd)
311+
{
312+
// These bytes come from `arm-none-eabi-as -al call.s`, with the function
313+
// lookup code and function arguments appended.
314+
uint8_t call_asm[] = {
315+
0x10, 0xB5, 0x14, 0x24, 0x20, 0x88, 0x05, 0x49,
316+
0xA4, 0x88, 0xA0, 0x47, 0x04, 0x1C, 0x04, 0x48,
317+
0x04, 0x49, 0x05, 0x4A, 0x05, 0x4B, 0xA0, 0x47,
318+
0x10, 0xBD, 0, 0,
319+
'R', 'E', 0, 0,
320+
addr, addr >> 8, addr >> 16, addr >> 24,
321+
len, len >> 8, len >> 16, len >> 24,
322+
block_size, block_size >> 8, block_size >> 16, block_size >> 24,
323+
block_cmd, 0, 0, 0,
324+
};
325+
int ret = picoboot_write(usb_device, SRAM_START, call_asm, sizeof(call_asm));
326+
if (ret) { return ret; }
327+
return picoboot_exec(usb_device, SRAM_START);
328+
}
329+
308330
int picoboot_flash_erase(libusb_device_handle *usb_device, uint32_t addr, uint32_t len) {
309331
struct picoboot_cmd cmd;
310332
if (verbose) output("FLASH_ERASE %08x+%08x\n", (uint) addr, (uint) len);

picoboot_connection/picoboot_connection.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ int picoboot_enter_cmd_xip(libusb_device_handle *usb_device);
3939
int picoboot_exit_xip(libusb_device_handle *usb_device);
4040
int picoboot_reboot(libusb_device_handle *usb_device, uint32_t pc, uint32_t sp, uint32_t delay_ms);
4141
int picoboot_exec(libusb_device_handle *usb_device, uint32_t addr);
42+
int picoboot_flash_range_erase(libusb_device_handle *, uint32_t, uint32_t, uint32_t, uint8_t);
4243
int picoboot_flash_erase(libusb_device_handle *usb_device, uint32_t addr, uint32_t len);
4344
int picoboot_vector(libusb_device_handle *usb_device, uint32_t addr);
4445
int picoboot_write(libusb_device_handle *usb_device, uint32_t addr, uint8_t *buffer, uint32_t len);

picoboot_connection/picoboot_connection_cxx.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ void connection::exec(uint32_t addr) {
8181
wrap_call([&] { return picoboot_exec(device, addr); });
8282
}
8383

84+
void connection::flash_range_erase(uint32_t addr, uint32_t len,
85+
uint32_t block_size, uint8_t block_cmd) {
86+
wrap_call([&] { return picoboot_flash_range_erase(device, addr, len,
87+
block_size, block_cmd); });
88+
}
89+
8490
void connection::flash_erase(uint32_t addr, uint32_t len) {
8591
wrap_call([&] { return picoboot_flash_erase(device, addr, len); });
8692
}

picoboot_connection/picoboot_connection_cxx.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ namespace picoboot {
4141
void exit_xip();
4242
void reboot(uint32_t pc, uint32_t sp, uint32_t delay_ms);
4343
void exec(uint32_t addr);
44+
void flash_range_erase(uint32_t addr, uint32_t len, uint32_t block_size, uint8_t block_cmd);
4445
void flash_erase(uint32_t addr, uint32_t len);
4546
void vector(uint32_t addr);
4647
void write(uint32_t addr, uint8_t *buffer, uint32_t len);

0 commit comments

Comments
 (0)