From 88a6671d371b899c5f6cecbf4f903b9c3b3d87c1 Mon Sep 17 00:00:00 2001 From: shylie Date: Mon, 5 Jan 2026 15:32:51 -0500 Subject: [PATCH] Load image from flash instead --- CMakeLists.txt | 2 + include/display.h | 2 +- include/flash.h | 58 ++++++++++++++++++++++++ include/lib.h | 13 ++++++ include/pixelstream.h | 4 +- src/display.cpp | 19 +++----- src/flash.cpp | 102 ++++++++++++++++++++++++++++++++++++++++++ src/lib.cpp | 8 ++++ src/main.cpp | 68 ++++++++++++++++++---------- src/pixelstream.cpp | 4 +- 10 files changed, 239 insertions(+), 41 deletions(-) create mode 100644 include/flash.h create mode 100644 include/lib.h create mode 100644 src/flash.cpp create mode 100644 src/lib.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e58d61..f495427 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,8 @@ add_executable(mtgcard src/main.cpp src/display.cpp src/pixelstream.cpp + src/lib.cpp + src/flash.cpp src/usb_descriptors.c ) diff --git a/include/display.h b/include/display.h index abecdd7..4329f92 100644 --- a/include/display.h +++ b/include/display.h @@ -3,7 +3,7 @@ #include -namespace display +namespace lib { class PixelStream; diff --git a/include/flash.h b/include/flash.h new file mode 100644 index 0000000..c8792b3 --- /dev/null +++ b/include/flash.h @@ -0,0 +1,58 @@ +#ifndef FLASH_H +#define FLASH_H + +#include + +namespace lib +{ + +class Flash +{ +public: + class Page + { + public: + static constexpr size_t SIZE = 256; + static constexpr size_t COUNT_PER_SECTOR = 4096 / SIZE; + + operator uint8_t*(); + operator const uint8_t*() const; + + uint8_t& operator[](int address); + uint8_t operator[](int address) const; + + private: + uint8_t buffer[SIZE]; + }; + + Flash(uint8_t sck, uint8_t tx, uint8_t rx, uint8_t cs, int baudrate); + + void read_page(uint16_t page_index); + void write_page(uint16_t page_index); + + void erase_sector(uint16_t page_index); + + Page& page(); + const Page& page() const; + +private: + uint8_t sck, tx, rx, cs; + spi_inst_t* spi; + + Page page_buffer; + + void write_enable(); + void wait_done(); + + static constexpr uint8_t CMD_PAGE_PROGRAM = 0x02; + static constexpr uint8_t CMD_READ = 0x03; + static constexpr uint8_t CMD_STATUS = 0x05; + static constexpr uint8_t CMD_WRITE_EN = 0x06; + static constexpr uint8_t CMD_SECTOR_ERASE = 0x20; + + static constexpr uint8_t STATUS_BUSY_MASK = 0x01; +}; + +} + +#endif // FLASH_H diff --git a/include/lib.h b/include/lib.h new file mode 100644 index 0000000..98d6398 --- /dev/null +++ b/include/lib.h @@ -0,0 +1,13 @@ +#ifndef LIB_H +#define LIB_H + +#include + +namespace lib::detail +{ + +spi_inst_t* get_spi_instance(uint8_t gpio); + +} + +#endif // LIB_H diff --git a/include/pixelstream.h b/include/pixelstream.h index e185446..e8c7a85 100644 --- a/include/pixelstream.h +++ b/include/pixelstream.h @@ -3,7 +3,7 @@ #include -namespace display +namespace lib { class Display; @@ -17,6 +17,8 @@ public: PixelStream& operator=(const PixelStream&) = delete; ~PixelStream(); + // prefer other overload when possible + void write(uint8_t data); void write(uint8_t red, uint8_t green, uint8_t blue); private: diff --git a/src/display.cpp b/src/display.cpp index 7d00f75..15bb5c8 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -1,21 +1,12 @@ #include "display.h" +#include "lib.h" #include "pixelstream.h" #include #include -namespace -{ - -spi_inst_t* get_spi_instance(uint8_t gpio) -{ - return gpio % 16 < 8 ? spi0 : spi1; -} - -} - -using namespace display; +using namespace lib; Display::Display(uint8_t sck, uint8_t tx, uint8_t cs, uint8_t dc, int baudrate) : @@ -24,8 +15,8 @@ Display::Display(uint8_t sck, uint8_t tx, uint8_t cs, uint8_t dc, cs(cs), dc(dc) { - spi_inst_t* sck_spi = get_spi_instance(sck); - spi_inst_t* tx_spi = get_spi_instance(tx); + spi_inst_t* sck_spi = detail::get_spi_instance(sck); + spi_inst_t* tx_spi = detail::get_spi_instance(tx); hard_assert(sck_spi == tx_spi, "Invalid configuration"); spi = sck_spi; @@ -68,7 +59,7 @@ Display::Display(uint8_t sck, uint8_t tx, uint8_t cs, uint8_t dc, sleep_ms(10); // set display brightness - send_command(0x51, 0xFF); + send_command(0x51, 0x00); // clear display to black { diff --git a/src/flash.cpp b/src/flash.cpp new file mode 100644 index 0000000..6bc988e --- /dev/null +++ b/src/flash.cpp @@ -0,0 +1,102 @@ +#include "flash.h" + +#include "lib.h" + +#include + +using namespace lib; + +Flash::Page::operator unsigned char*() { return buffer; } +Flash::Page::operator const unsigned char*() const { return buffer; } + +uint8_t& Flash::Page::operator[](int address) { return buffer[address]; } +uint8_t Flash::Page::operator[](int address) const { return buffer[address]; } + +Flash::Flash(uint8_t sck, uint8_t tx, uint8_t rx, uint8_t cs, int baudrate) : + sck(sck), + tx(tx), + rx(rx), + cs(cs) +{ + spi_inst_t* sck_spi = detail::get_spi_instance(sck); + spi_inst_t* tx_spi = detail::get_spi_instance(tx); + spi_inst_t* rx_spi = detail::get_spi_instance(rx); + + hard_assert(sck_spi == tx_spi && tx_spi == rx_spi, "Invalid configuration"); + spi = sck_spi; + + gpio_set_function(sck, GPIO_FUNC_SPI); + gpio_set_function(tx, GPIO_FUNC_SPI); + gpio_set_function(rx, GPIO_FUNC_SPI); + + gpio_set_function(cs, GPIO_FUNC_SIO); + gpio_set_dir(cs, GPIO_OUT); + gpio_put(cs, true); + + spi_init(spi, baudrate); +} + +void Flash::read_page(uint16_t page_index) +{ + const uint8_t cmd[5] = { CMD_READ, static_cast(page_index >> 8), + static_cast(page_index), 0, 0 }; + + gpio_put(cs, false); + spi_write_blocking(spi, cmd, 4); + spi_read_blocking(spi, 0, page_buffer, Page::SIZE); + gpio_put(cs, true); +} + +void Flash::write_page(uint16_t page_index) +{ + write_enable(); + + uint8_t cmd[4] = { CMD_PAGE_PROGRAM, static_cast(page_index >> 8), + static_cast(page_index), 0 }; + + gpio_put(cs, false); + spi_write_blocking(spi, cmd, 4); + spi_write_blocking(spi, page_buffer, Page::SIZE); + gpio_put(cs, true); + + wait_done(); +} + +void Flash::erase_sector(uint16_t page_index) +{ + write_enable(); + + uint8_t cmd[4] = { CMD_SECTOR_ERASE, static_cast(page_index >> 8), + static_cast(page_index), 0 }; + + gpio_put(cs, false); + spi_write_blocking(spi, cmd, 4); + gpio_put(cs, true); + + wait_done(); +} + +Flash::Page& Flash::page() { return page_buffer; } +const Flash::Page& Flash::page() const { return page_buffer; } + +void Flash::write_enable() +{ + uint8_t cmd = CMD_WRITE_EN; + + gpio_put(cs, false); + spi_write_blocking(spi, &cmd, 1); + gpio_put(cs, true); +} + +void Flash::wait_done() +{ + for (uint8_t status = STATUS_BUSY_MASK; status & STATUS_BUSY_MASK;) + { + uint8_t cmd = CMD_STATUS; + + gpio_put(cs, false); + spi_write_blocking(spi, &cmd, 1); + spi_read_blocking(spi, 0, &status, 1); + gpio_put(cs, true); + } +} diff --git a/src/lib.cpp b/src/lib.cpp new file mode 100644 index 0000000..b9266bb --- /dev/null +++ b/src/lib.cpp @@ -0,0 +1,8 @@ +#include "lib.h" + +using namespace lib; + +spi_inst_t* detail::get_spi_instance(uint8_t gpio) +{ + return gpio % 16 < 8 ? spi0 : spi1; +} diff --git a/src/main.cpp b/src/main.cpp index 1371728..e23a78c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,16 +1,17 @@ #include "display.h" +#include "flash.h" #include "pixelstream.h" -#include "tusb.h" #include +#include + +using namespace lib; namespace { -display::Display disp(2, 3, 5, 6, 5000000); -uint16_t row = 0; -uint16_t column = 0; -uint8_t row_data[240 * 3]; +Display disp(2, 3, 5, 6, 120000000); +Flash flash(26, 27, 28, 29, 70000000); } @@ -20,6 +21,20 @@ int main() = { .role = TUSB_ROLE_DEVICE, .speed = TUSB_SPEED_AUTO }; tud_init(0); + { + auto pixels = disp.pixels(); + for (int page_index = 0; page_index < 900; page_index++) + { + flash.read_page(page_index); + const auto& page = flash.page(); + + for (int i = 0; i < Flash::Page::SIZE; i++) + { + pixels.write(page[i]); + } + } + } + while (true) { tud_task(); @@ -28,32 +43,37 @@ int main() void tud_vendor_rx_cb(uint8_t itf, const uint8_t* buffer, uint16_t bufsize) { - size_t written = 0; + static size_t written = 0; + static uint16_t page_index = 0; - while (written < bufsize) + if (written == 0 && page_index == 0) { - size_t copy_size = bufsize - written < (240 * 3) - column - ? bufsize - written - : (240 * 3) - column; - memcpy(row_data + column, buffer + written, copy_size); - column += copy_size; + for (int i = 0; i < 320 * 240 * 3 / 256; i += 4096 / 256) + { + flash.erase_sector(i); + } + } + + for (size_t read = 0; read < bufsize;) + { + size_t copy_size = bufsize - read < Flash::Page::SIZE - written + ? bufsize - read + : Flash::Page::SIZE - written; + + memcpy(flash.page() + written, buffer + read, copy_size); + read += copy_size; + written += copy_size; - if (column >= 240 * 3) + if (written == 256) { - disp.set_update_area(0, row, 240, 320); - auto pixels = disp.pixels(); - for (int i = 0; i < 240; i++) - { - pixels.write(row_data[i * 3], row_data[i * 3 + 1], - row_data[i * 3 + 2]); - } + flash.write_page(page_index); + page_index += 1; + written = 0; - column -= 240 * 3; - row += 1; - if (row == 320) + if (page_index == 900) { - row = 0; + page_index = 0; } } } diff --git a/src/pixelstream.cpp b/src/pixelstream.cpp index 57a85d8..f2027a4 100644 --- a/src/pixelstream.cpp +++ b/src/pixelstream.cpp @@ -2,7 +2,7 @@ #include "display.h" -using namespace display; +using namespace lib; PixelStream::PixelStream(Display& display) : display(display) @@ -10,6 +10,8 @@ PixelStream::PixelStream(Display& display) : display.send_command_and_begin_data_stream(0x2C); } +void PixelStream::write(uint8_t data) { display.send_data(data); } + void PixelStream::write(uint8_t red, uint8_t green, uint8_t blue) { display.send_data(red);