Load image from flash instead

This commit is contained in:
shylie 2026-01-05 15:32:51 -05:00
parent c3166e54b2
commit 88a6671d37
10 changed files with 239 additions and 41 deletions

View File

@ -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
)

View File

@ -3,7 +3,7 @@
#include <hardware/spi.h>
namespace display
namespace lib
{
class PixelStream;

58
include/flash.h Normal file
View File

@ -0,0 +1,58 @@
#ifndef FLASH_H
#define FLASH_H
#include <hardware/spi.h>
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

13
include/lib.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef LIB_H
#define LIB_H
#include <hardware/spi.h>
namespace lib::detail
{
spi_inst_t* get_spi_instance(uint8_t gpio);
}
#endif // LIB_H

View File

@ -3,7 +3,7 @@
#include <pico/stdlib.h>
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:

View File

@ -1,21 +1,12 @@
#include "display.h"
#include "lib.h"
#include "pixelstream.h"
#include <hardware/spi.h>
#include <pico/stdlib.h>
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
{

102
src/flash.cpp Normal file
View File

@ -0,0 +1,102 @@
#include "flash.h"
#include "lib.h"
#include <pico/stdlib.h>
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<uint8_t>(page_index >> 8),
static_cast<uint8_t>(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<uint8_t>(page_index >> 8),
static_cast<uint8_t>(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<uint8_t>(page_index >> 8),
static_cast<uint8_t>(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);
}
}

8
src/lib.cpp Normal file
View File

@ -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;
}

View File

@ -1,16 +1,17 @@
#include "display.h"
#include "flash.h"
#include "pixelstream.h"
#include "tusb.h"
#include <pico/stdlib.h>
#include <tusb.h>
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;
written += copy_size;
if (column >= 240 * 3)
for (int i = 0; i < 320 * 240 * 3 / 256; i += 4096 / 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.erase_sector(i);
}
}
column -= 240 * 3;
row += 1;
if (row == 320)
for (size_t read = 0; read < bufsize;)
{
row = 0;
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 (written == 256)
{
flash.write_page(page_index);
page_index += 1;
written = 0;
if (page_index == 900)
{
page_index = 0;
}
}
}

View File

@ -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);