diff --git a/app/commands.hh b/app/commands.hh index c61d47d..85f9b55 100644 --- a/app/commands.hh +++ b/app/commands.hh @@ -155,19 +155,19 @@ struct VerifyFile : public Commands { } if (!page) { - std::println("Program page {:#x} failed.", addr); + std::println("Read page {:#x} failed.", addr); return 0; } - uint32_t chunck = std::min(remainder, std::size_t{flash::PageSize}); + uint32_t chunk = std::min(remainder, std::size_t{flash::PageSize}); std::span data(*page); - if (chunck < data.size()) { - data = data.subspan(0, chunck); + if (chunk < data.size()) { + data = data.subspan(0, chunk); } flash_hasher.process(data.begin(), data.end()); - addr += chunck; - remainder -= chunck; + addr += chunk; + remainder -= chunk; progress_bar.update(file_size - remainder); } @@ -188,9 +188,15 @@ struct LoadFile : public Commands { std::string& filename; bool quad; bool bootstrap; + bool skip_erase; LoadFile(flash::Generic f, std::string& filename, std::size_t addr = 0, bool bootstrap = false, - bool quad = false) - : Commands(f), filename(filename), start_addr(addr), quad(quad), bootstrap(bootstrap) {} + bool skip_erase = false, bool quad = false) + : Commands(f), + filename(filename), + start_addr(addr), + quad(quad), + bootstrap(bootstrap), + skip_erase(skip_erase) {} int run() override { if ((this->start_addr % flash::SectorSize) != 0) { @@ -235,8 +241,9 @@ struct LoadFile : public Commands { std::span data(buffer); auto progress_bar = ProgressBar(buffer.size(), 50, "Loading").with_throughput(); size_t addr = start_addr; + this->flash.write_enable(); while (data.size() > 0) { - if ((addr % flash::SectorSize) == 0) { + if (!skip_erase && (addr % flash::SectorSize) == 0) { auto erased = addr4b ? this->flash.template erase<4, flash::Opcode::SectorErase4b>(addr) : this->flash.erase(addr); if (!erased) { @@ -245,13 +252,15 @@ struct LoadFile : public Commands { } } + this->flash.wait_not_busy(); std::optional res; if (addr4b) { - res = this->flash.template single_page_program<4>(addr, data.first()); + res = this->flash.template single_page_program_non_blocking<4>( + addr, data.first()); } else if (quad) { res = this->flash.quad_page_program(addr, data.first()); } else { - res = this->flash.single_page_program(addr, data.first()); + res = this->flash.single_page_program_non_blocking(addr, data.first()); } if (!res) { @@ -263,6 +272,7 @@ struct LoadFile : public Commands { data = data.subspan(std::min(data.size(), std::size_t{flash::PageSize})); progress_bar.update(buffer.size() - data.size()); } + this->flash.write_enable(false); if (bootstrap) { this->flash.reset(); diff --git a/app/main.cc b/app/main.cc index 6d9b5f1..8339116 100644 --- a/app/main.cc +++ b/app/main.cc @@ -223,14 +223,19 @@ int main(int argc, char* argv[]) { .default_value(std::size_t{0}) .scan<'x', std::size_t>(); bootstrap_cmd->add_argument("--quad").help("Use qSPI").default_value(false).implicit_value(true); + bootstrap_cmd->add_argument("--skip-erase") + .help("Don't issue erase commands") + .default_value(false) + .implicit_value(true); program.add_subparser(*bootstrap_cmd); commands["bootstrap"] = [&]() -> int { - auto pid = program.get("--pid"); - auto filename = bootstrap_cmd->get("filename"); - auto addr = bootstrap_cmd->get("--addr"); - auto quad = bootstrap_cmd->get("--quad"); - auto spih = handle_flash_command(bootstrap_cmd, pid); - commands::LoadFile(flash::Generic(*spih), filename, addr, true, quad).run(); + auto pid = program.get("--pid"); + auto filename = bootstrap_cmd->get("filename"); + auto addr = bootstrap_cmd->get("--addr"); + auto quad = bootstrap_cmd->get("--quad"); + auto skip_erase = bootstrap_cmd->get("--skip-erase"); + auto spih = handle_flash_command(bootstrap_cmd, pid); + commands::LoadFile(flash::Generic(*spih), filename, addr, true, skip_erase, quad).run(); spih->close(); return 0; diff --git a/lib/flash/flash.hh b/lib/flash/flash.hh index 08f464e..fe829a2 100644 --- a/lib/flash/flash.hh +++ b/lib/flash/flash.hh @@ -250,7 +250,7 @@ class Generic { } template - Option single_page_program(uint32_t address, std::span data) { + Option single_page_program_non_blocking(uint32_t address, std::span data) { static_assert(ADDR_SIZE == 3 || ADDR_SIZE == 4, "Only 3 or 4 byte addresses supported"); Opcode op; @@ -259,7 +259,6 @@ class Generic { } else { op = Opcode::PageProgram4b; } - write_enable(); std::array cmd = {op}; for (size_t i = 0; i < ADDR_SIZE; ++i) { @@ -271,6 +270,13 @@ class Generic { std::ranges::copy(data, slice.begin()); TRY_OPT(spih.transfer(cmd, std::span())); + return true; + } + + template + Option single_page_program(uint32_t address, std::span data) { + write_enable(); + single_page_program_non_blocking(address, data); wait_not_busy(); return write_enable(false); } diff --git a/lib/ftdi/spi_host.cc b/lib/ftdi/spi_host.cc index f854229..d65f6eb 100644 --- a/lib/ftdi/spi_host.cc +++ b/lib/ftdi/spi_host.cc @@ -204,25 +204,24 @@ bool SpiHost::set_clock(size_t clock) { std::cerr << std::format("failed to update the clock:{}\n", res); return false; } + return true; + } - } else { - const size_t baseClk = 60000000; - for (auto div : clocks) { - if ((baseClk >> div) <= clock) { - clk_div = div; - break; - } + const size_t baseClk = 60000000; + for (auto div : clocks) { + if ((baseClk >> div) <= clock) { + clk_div = div; + break; } + } - FT4222_STATUS status; - status = FT4222_SPIMaster_Init(handle, SPI_IO_SINGLE, clk_div, CLK_IDLE_LOW, CLK_LEADING, - SLAVE_SELECT(0)); - if (FT4222_OK != status) { - std::cerr << std::format("failed to update the clock:{}\n", status); - return false; - } + FT4222_STATUS status; + status = FT4222_SPIMaster_Init(handle, SPI_IO_SINGLE, clk_div, CLK_IDLE_LOW, CLK_LEADING, + SLAVE_SELECT(0)); + if (FT4222_OK != status) { + std::cerr << std::format("failed to update the clock:{}\n", status); + return false; } - return true; } static std::optional new_ft4222(DeviceInfo& device) { diff --git a/lib/visuals/progressbar.hh b/lib/visuals/progressbar.hh index 48b5d07..8b02f9f 100644 --- a/lib/visuals/progressbar.hh +++ b/lib/visuals/progressbar.hh @@ -33,7 +33,7 @@ struct ProgressBar { std::string tp_str = ""; if (tp) { tp->total(progress); - tp_str = tp->render(); + tp_str = tp->render(false); } std::print("\r\033[32m{} [", label); diff --git a/lib/visuals/throughput.hh b/lib/visuals/throughput.hh index 8278c97..3993e4e 100644 --- a/lib/visuals/throughput.hh +++ b/lib/visuals/throughput.hh @@ -4,6 +4,7 @@ #pragma once #include +#include #include struct Throughput { @@ -16,14 +17,14 @@ struct Throughput { progress = 0; } - Throughput& add(size_t transfered) { - progress += transfered; + Throughput& add(size_t transferred) { + progress += transferred; elapsed = std::chrono::high_resolution_clock::now(); return *this; } - Throughput& total(size_t transfered) { - progress = transfered; + Throughput& total(size_t transferred) { + progress = transferred; elapsed = std::chrono::high_resolution_clock::now(); return *this; } @@ -37,15 +38,15 @@ struct Throughput { if (short_fmt) { return std::format("{}", human_size(throughput, "bps")); } - return std::format("Transfered {} in {}s, {}", human_size(mb, "b"), seconds, + return std::format("{} in {}, {}", human_size(mb, "b"), human_time(seconds), human_size(throughput, "b/s")); } - void show() { std::println("{}", render()); } + void show(bool short_fmt = true) { std::println("{}", render(short_fmt)); } private: std::string human_size(float num, const char* suffix = "B") { - std::array units{"", "ki", "Mi", "Gi", "Ti", "Pi"}; + constexpr std::array units{"", "ki", "Mi", "Gi", "Ti", "Pi"}; for (auto unit : units) { if (abs(num) < 1024) { return std::format("{:.1f} {}{}", num, unit, suffix); @@ -54,4 +55,27 @@ struct Throughput { } return ""; } + + std::string human_time(float seconds) { + if (seconds <= 0.0f) { + return "0"; + } + + constexpr std::array units{"s", "m", "h"}; + std::string result; + auto num = static_cast(std::round(seconds)); + + for (size_t i = 0; i < units.size(); ++i) { + int part = (i < static_cast(units.size()) - 1) ? num % 60 : num; + if (part != 0) { + result = std::format("{}{}", part, units[i]) + result; + } + num /= 60; + if (num == 0) { + break; + } + } + + return result; + } };