'Fix' issues with screen tearing
This commit is contained in:
parent
19491d6038
commit
58c1b9626b
@ -8,6 +8,8 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
|
||||
set(PICO_USE_FASTEST_SUPPORTED_CLOCK 1)
|
||||
|
||||
pico_sdk_init()
|
||||
|
||||
add_library(devicelib STATIC
|
||||
|
||||
@ -19,6 +19,8 @@ public:
|
||||
uint16_t height);
|
||||
void fill(uint16_t left, uint16_t top, uint16_t width, uint16_t height,
|
||||
uint8_t r, uint8_t g, uint8_t b);
|
||||
void fill(uint16_t left, uint16_t top, uint16_t width, uint16_t height,
|
||||
const uint8_t* src);
|
||||
|
||||
PixelStream pixels();
|
||||
void clear();
|
||||
@ -27,6 +29,10 @@ private:
|
||||
uint8_t sck, tx, cs, dc;
|
||||
spi_inst_t* spi;
|
||||
int dma;
|
||||
bool frame;
|
||||
|
||||
void begin_dma(const volatile uint8_t* src, uint32_t transfer_count,
|
||||
uint32_t pixel_count);
|
||||
|
||||
void send_command(uint8_t command);
|
||||
void send_command(uint8_t command, uint8_t param);
|
||||
|
||||
@ -119,6 +119,7 @@ private:
|
||||
uint8_t previous;
|
||||
bool going_right;
|
||||
float progress;
|
||||
float old_progress;
|
||||
};
|
||||
|
||||
class CMCMenu : public Menu
|
||||
@ -144,6 +145,7 @@ private:
|
||||
uint8_t current;
|
||||
uint8_t previous;
|
||||
float progress;
|
||||
float old_progress;
|
||||
};
|
||||
|
||||
class SelectMenu : public Menu
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
#include "icons.h"
|
||||
#include "menu.h"
|
||||
#include "pixelstream.h"
|
||||
|
||||
using namespace menus;
|
||||
|
||||
@ -20,10 +19,17 @@ void CMCMenu::onTick(float dt)
|
||||
constexpr float CENTER_Y = 160;
|
||||
constexpr float DT_SCALE = 1.4f;
|
||||
constexpr uint8_t STEP = 48;
|
||||
constexpr uint8_t ERASE_DATA[39 * 5 * 3] = {};
|
||||
|
||||
old_progress = progress;
|
||||
|
||||
if (progress < 1.0f)
|
||||
{
|
||||
progress += dt * DT_SCALE;
|
||||
if (progress >= 0.75f)
|
||||
{
|
||||
progress = 1.0f;
|
||||
}
|
||||
|
||||
for (int8_t dcmc = -1; dcmc <= 1; dcmc++)
|
||||
{
|
||||
const int8_t dir = (previous > current ? 1 : -1);
|
||||
@ -36,35 +42,16 @@ void CMCMenu::onTick(float dt)
|
||||
|
||||
const float offset
|
||||
= dir * ease::outElastic(progress) * STEP + (dir * (dcmc - 1)) * STEP;
|
||||
const float old_offset = dir * ease::outElastic(old_progress) * STEP
|
||||
+ (dir * (dcmc - 1)) * STEP;
|
||||
|
||||
// left
|
||||
{
|
||||
display->set_update_area(CENTER_X - 20 + offset, CENTER_Y - 20, 5, 39);
|
||||
auto pixels = display->pixels();
|
||||
pixels.write(ERASE_DATA, 39 * 5 * 3);
|
||||
}
|
||||
// right
|
||||
{
|
||||
display->set_update_area(CENTER_X - 20 + offset + 37, CENTER_Y - 20, 5,
|
||||
39);
|
||||
auto pixels = display->pixels();
|
||||
pixels.write(ERASE_DATA, 39 * 5 * 3);
|
||||
}
|
||||
// erase old
|
||||
display->fill(CENTER_X - 15 + old_offset, CENTER_Y - 15, 32, 32, 0, 0,
|
||||
0);
|
||||
|
||||
// draw new
|
||||
{
|
||||
display->set_update_area(CENTER_X - 15 + offset, CENTER_Y - 15, 31,
|
||||
32);
|
||||
auto pixels = display->pixels();
|
||||
pixels.write(icon::NUMBER_ICONS[cmc_to_draw], icon::MTG_ICON_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
progress += dt * DT_SCALE;
|
||||
|
||||
if (progress >= 0.75f)
|
||||
{
|
||||
progress = 1.0f;
|
||||
display->fill(CENTER_X - 15 + offset, CENTER_Y - 15, 32, 32,
|
||||
icon::NUMBER_ICONS[cmc_to_draw]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ namespace
|
||||
|
||||
Display display(DISPLAY_SCK, DISPLAY_TX, DISPLAY_CS, DISPLAY_DC,
|
||||
100 * 1000 * 1000);
|
||||
Flash flash(FLASH_SCK, FLASH_TX, FLASH_RX, FLASH_CS, 25 * 1000 * 1000);
|
||||
Flash flash(FLASH_SCK, FLASH_TX, FLASH_RX, FLASH_CS, 50 * 1000 * 1000);
|
||||
|
||||
enum class RX
|
||||
{
|
||||
@ -54,6 +54,8 @@ volatile uint8_t debug_requested = false;
|
||||
|
||||
constexpr int MS_BUTTON_TIMEOUT = 500;
|
||||
|
||||
constexpr int FREQ = 90 * 1000 * 1000;
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
@ -87,12 +89,15 @@ int main()
|
||||
absolute_time_t last_press = get_absolute_time();
|
||||
absolute_time_t previous_time = last_press;
|
||||
|
||||
float dt_accum = 0;
|
||||
|
||||
menus::push_menu<menus::ManaMenu>(display, flash);
|
||||
|
||||
while (true)
|
||||
{
|
||||
absolute_time_t current = get_absolute_time();
|
||||
float dt = absolute_time_diff_us(previous_time, current) / 1000000.0f;
|
||||
dt_accum += dt;
|
||||
|
||||
if (!gpio_get(BUTTON_LEFT)
|
||||
&& absolute_time_diff_us(last_press, current)
|
||||
@ -122,7 +127,11 @@ int main()
|
||||
}
|
||||
|
||||
tud_task();
|
||||
menus::get_current_menu()->onTick(dt);
|
||||
if (dt_accum > 1.0f / 60.0f)
|
||||
{
|
||||
menus::get_current_menu()->onTick(dt_accum);
|
||||
dt_accum = 0;
|
||||
}
|
||||
|
||||
previous_time = current;
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
#include "icons.h"
|
||||
#include "menu.h"
|
||||
#include "pixelstream.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
@ -18,7 +17,8 @@ ManaMenu::ManaMenu(lib::Display& display, lib::Flash& flash) :
|
||||
current(0),
|
||||
previous(0),
|
||||
going_right(true),
|
||||
progress(0.7f)
|
||||
progress(0.7f),
|
||||
old_progress(progress)
|
||||
{
|
||||
}
|
||||
|
||||
@ -30,44 +30,41 @@ void ManaMenu::onTick(float dt)
|
||||
constexpr float CENTER_X = 120;
|
||||
constexpr float CENTER_Y = 190;
|
||||
constexpr float MAX_OFFSET = RADIUS / 1.5f;
|
||||
constexpr float DT_SCALE_ROTATE = 1.0f;
|
||||
constexpr float DT_SCALE_ROTATE = 1.1f;
|
||||
constexpr float DT_SCALE_UPDOWN = 1.6f;
|
||||
constexpr uint8_t ERASE_DATA[38 * 5 * 3] = {};
|
||||
|
||||
old_progress = progress;
|
||||
|
||||
if (progress < 1.0f)
|
||||
{
|
||||
const float offset
|
||||
= (1.0f - ease::outElastic(progress)) * MAX_OFFSET + RADIUS;
|
||||
|
||||
// erase old
|
||||
{
|
||||
display->set_update_area(CENTER_X - 20, CENTER_Y - 20 - offset, 38, 5);
|
||||
auto pixels = display->pixels();
|
||||
pixels.write(ERASE_DATA, 38 * 5 * 3);
|
||||
}
|
||||
{
|
||||
display->set_update_area(CENTER_X - 20, CENTER_Y - 15 + 30 - offset, 38,
|
||||
5);
|
||||
auto pixels = display->pixels();
|
||||
pixels.write(ERASE_DATA, 38 * 5 * 3);
|
||||
}
|
||||
|
||||
// write new
|
||||
{
|
||||
display->set_update_area(CENTER_X - 15, CENTER_Y - 15 - offset, 31, 32);
|
||||
auto pixels = display->pixels();
|
||||
const uint8_t* data = icon::wubrgc(COLORS[previous]);
|
||||
pixels.write(data, icon::MTG_ICON_LENGTH);
|
||||
}
|
||||
|
||||
progress += dt * DT_SCALE_UPDOWN;
|
||||
if (progress > 0.75f)
|
||||
{
|
||||
progress = 1.0f;
|
||||
}
|
||||
|
||||
// erase old
|
||||
const float old_offset
|
||||
= (1.0f - ease::outElastic(old_progress)) * MAX_OFFSET + RADIUS;
|
||||
display->fill(CENTER_X - 15, CENTER_Y - 15 - old_offset, 32, 32, 0, 0, 0);
|
||||
|
||||
// write new
|
||||
const float offset
|
||||
= (1.0f - ease::outElastic(progress)) * MAX_OFFSET + RADIUS;
|
||||
const uint8_t* data = icon::wubrgc(COLORS[previous]);
|
||||
display->fill(CENTER_X - 15, CENTER_Y - 15 - offset, 32, 32, data);
|
||||
}
|
||||
else if (progress < 2.0f)
|
||||
{
|
||||
progress += dt * DT_SCALE_ROTATE;
|
||||
if (progress > 1.75f)
|
||||
{
|
||||
progress = 2.0f;
|
||||
}
|
||||
|
||||
const float old_offset
|
||||
= (going_right ? -1 : 1) * STEP * ease::outElastic(old_progress - 1)
|
||||
+ STEP / 2.0f + (going_right ? 2 * STEP : 0);
|
||||
const float offset
|
||||
= (going_right ? -1 : 1) * STEP * ease::outElastic(progress - 1)
|
||||
+ STEP / 2.0f + (going_right ? 2 * STEP : 0);
|
||||
@ -75,47 +72,15 @@ void ManaMenu::onTick(float dt)
|
||||
// erase previous
|
||||
for (int i = 0; i < sizeof(COLORS) / sizeof(*COLORS); i++)
|
||||
{
|
||||
const float angle = i * STEP - offset;
|
||||
const float angle = i * STEP - old_offset;
|
||||
|
||||
const float x = cosf(angle) * RADIUS;
|
||||
const float y = sinf(angle) * RADIUS;
|
||||
|
||||
const int left = x - 20 + CENTER_X;
|
||||
const int top = y - 20 + CENTER_Y;
|
||||
const int left = x - 15 + CENTER_X;
|
||||
const int top = y - 15 + CENTER_Y;
|
||||
|
||||
// top rectangle
|
||||
{
|
||||
display->set_update_area(left, top, 38, 5);
|
||||
auto pixels = display->pixels();
|
||||
pixels.write(ERASE_DATA, 38 * 5 * 3);
|
||||
}
|
||||
|
||||
// bottom rectangle
|
||||
{
|
||||
display->set_update_area(left, top + 36, 38, 5);
|
||||
auto pixels = display->pixels();
|
||||
pixels.write(ERASE_DATA, 38 * 5 * 3);
|
||||
}
|
||||
|
||||
// left rectangle
|
||||
{
|
||||
display->set_update_area(left, top + 3, 5, 38);
|
||||
auto pixels = display->pixels();
|
||||
pixels.write(ERASE_DATA, 38 * 5 * 3);
|
||||
}
|
||||
|
||||
// right rectangle
|
||||
{
|
||||
display->set_update_area(left + 36, top + 3, 5, 38);
|
||||
auto pixels = display->pixels();
|
||||
pixels.write(ERASE_DATA, 38 * 5 * 3);
|
||||
}
|
||||
}
|
||||
|
||||
progress += dt * DT_SCALE_ROTATE;
|
||||
if (progress > 1.75f)
|
||||
{
|
||||
progress = 2.0f;
|
||||
display->fill(left, top, 32, 32, 0, 0, 0);
|
||||
}
|
||||
|
||||
// write new
|
||||
@ -129,43 +94,30 @@ void ManaMenu::onTick(float dt)
|
||||
const int left = x - 15 + CENTER_X;
|
||||
const int top = y - 15 + CENTER_Y;
|
||||
|
||||
display->set_update_area(left, top, 31, 32);
|
||||
auto pixels = display->pixels();
|
||||
const uint8_t* data = icon::wubrgc(COLORS[i]);
|
||||
pixels.write(data, icon::MTG_ICON_LENGTH);
|
||||
display->fill(left, top, 32, 32, data);
|
||||
}
|
||||
}
|
||||
else if (progress < 3.0f)
|
||||
{
|
||||
const float offset
|
||||
= ease::outElastic(progress - 2.0f) * MAX_OFFSET + RADIUS;
|
||||
|
||||
// erase old
|
||||
{
|
||||
display->set_update_area(CENTER_X - 20, CENTER_Y - 20 - offset, 38, 5);
|
||||
auto pixels = display->pixels();
|
||||
pixels.write(ERASE_DATA, 38 * 5 * 3);
|
||||
}
|
||||
{
|
||||
display->set_update_area(CENTER_X - 20, CENTER_Y - 15 + 30 - offset, 38,
|
||||
5);
|
||||
auto pixels = display->pixels();
|
||||
pixels.write(ERASE_DATA, 38 * 5 * 3);
|
||||
}
|
||||
|
||||
// write new
|
||||
{
|
||||
display->set_update_area(CENTER_X - 15, CENTER_Y - 15 - offset, 31, 32);
|
||||
auto pixels = display->pixels();
|
||||
const uint8_t* data = icon::wubrgc(COLORS[current]);
|
||||
pixels.write(data, icon::MTG_ICON_LENGTH);
|
||||
}
|
||||
|
||||
progress += dt * DT_SCALE_UPDOWN;
|
||||
if (progress > 2.75f)
|
||||
{
|
||||
progress = 3.0f;
|
||||
}
|
||||
|
||||
const float old_offset
|
||||
= ease::outElastic(old_progress - 2.0f) * MAX_OFFSET + RADIUS;
|
||||
const float offset
|
||||
= ease::outElastic(progress - 2.0f) * MAX_OFFSET + RADIUS;
|
||||
|
||||
display->fill(CENTER_X - 15, CENTER_Y - 15 - old_offset, 32, 32, 0, 0, 0);
|
||||
|
||||
// write new
|
||||
{
|
||||
const uint8_t* data = icon::wubrgc(COLORS[current]);
|
||||
display->fill(CENTER_X - 15, CENTER_Y - 15 - offset, 32, 32, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
void ManaMenu::onResume()
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
#include "cardslot.h"
|
||||
#include "icons.h"
|
||||
#include "menu.h"
|
||||
#include "pixelstream.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -103,10 +102,13 @@ void SelectMenu::draw_letter(uint8_t x, uint8_t y, uint8_t letter)
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t* const letter_data
|
||||
= letter >= 26 ? ERASE_DATA : icon::LETTERS[letter];
|
||||
if (letter >= 26)
|
||||
{
|
||||
|
||||
display->set_update_area(x * 12, y * 19, 11, 20);
|
||||
auto pixels = display->pixels();
|
||||
pixels.write(letter_data, icon::TEXT_ICON_LENGTH);
|
||||
display->fill(x * 12, y * 19, 12, 19, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
display->fill(x * 12, y * 19, 12, 19, icon::LETTERS[letter]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,7 +117,7 @@ int main()
|
||||
|
||||
time_since_last_display += dt;
|
||||
|
||||
if (time_since_last_display > 0.016f)
|
||||
if (time_since_last_display > 0.015f)
|
||||
{
|
||||
// ball
|
||||
draw_rectangle(old_ball_x, old_ball_y, 12, 12, 0, 0, 0);
|
||||
|
||||
@ -13,7 +13,7 @@ using namespace lib;
|
||||
namespace
|
||||
{
|
||||
|
||||
constexpr uint PIXELS_PER_TRANSFER = 16;
|
||||
constexpr uint PIXELS_PER_TRANSFER = 8;
|
||||
|
||||
int dma = -1;
|
||||
uint8_t cs;
|
||||
@ -28,6 +28,7 @@ void dma_handler()
|
||||
dma_channel_set_read_addr(dma, color_buffer, transfers_left > 0);
|
||||
|
||||
gpio_put(cs, transfers_left <= 0);
|
||||
busy_wait_at_least_cycles(35);
|
||||
}
|
||||
|
||||
}
|
||||
@ -37,7 +38,8 @@ Display::Display(uint8_t sck, uint8_t tx, uint8_t cs, uint8_t dc,
|
||||
sck(sck),
|
||||
tx(tx),
|
||||
cs(cs),
|
||||
dc(dc)
|
||||
dc(dc),
|
||||
frame(false)
|
||||
{
|
||||
spi_inst_t* sck_spi = detail::get_spi_instance(sck);
|
||||
spi_inst_t* tx_spi = detail::get_spi_instance(tx);
|
||||
@ -85,6 +87,7 @@ Display::Display(uint8_t sck, uint8_t tx, uint8_t cs, uint8_t dc,
|
||||
gpio_set_dir(dc, GPIO_OUT);
|
||||
|
||||
spi_init(spi, baudrate);
|
||||
spi_set_format(spi, 8, SPI_CPOL_1, SPI_CPHA_1, SPI_MSB_FIRST);
|
||||
|
||||
// initialize display command sequence
|
||||
// -----------------------------------
|
||||
@ -118,6 +121,14 @@ Display::Display(uint8_t sck, uint8_t tx, uint8_t cs, uint8_t dc,
|
||||
sleep_ms(10);
|
||||
|
||||
clear();
|
||||
sleep_ms(25);
|
||||
|
||||
// set framerate
|
||||
send_command(0xC6, 0x00);
|
||||
{
|
||||
constexpr uint8_t params[5] = { 0x01, 0x01, 0x01, 0x11, 0x11 };
|
||||
send_command(0xB2, params, 5);
|
||||
}
|
||||
}
|
||||
|
||||
void Display::set_update_area(uint16_t left, uint16_t top, uint16_t width,
|
||||
@ -149,7 +160,10 @@ void Display::fill(uint16_t left, uint16_t top, uint16_t width,
|
||||
if (dma >= 0)
|
||||
{
|
||||
while (transfers_left > 0)
|
||||
;
|
||||
{
|
||||
dma_channel_wait_for_finish_blocking(dma);
|
||||
}
|
||||
|
||||
for (int i = 0; i < PIXELS_PER_TRANSFER; i++)
|
||||
{
|
||||
color_buffer[3 * i + 0] = r;
|
||||
@ -158,11 +172,7 @@ void Display::fill(uint16_t left, uint16_t top, uint16_t width,
|
||||
}
|
||||
|
||||
set_update_area(left, top, width, height);
|
||||
|
||||
gpio_put(cs, false);
|
||||
send_command_and_begin_data_stream(0x2C);
|
||||
transfers_left = width * height + PIXELS_PER_TRANSFER;
|
||||
dma_channel_set_read_addr(dma, color_buffer, true);
|
||||
begin_dma(color_buffer, 3 * PIXELS_PER_TRANSFER, width * height);
|
||||
}
|
||||
// fallback if DMA is not available
|
||||
else
|
||||
@ -177,10 +187,42 @@ void Display::fill(uint16_t left, uint16_t top, uint16_t width,
|
||||
}
|
||||
}
|
||||
|
||||
void Display::fill(uint16_t left, uint16_t top, uint16_t width,
|
||||
uint16_t height, const uint8_t* src)
|
||||
{
|
||||
if (dma >= 0)
|
||||
{
|
||||
while (transfers_left > 0)
|
||||
{
|
||||
dma_channel_wait_for_finish_blocking(dma);
|
||||
}
|
||||
|
||||
set_update_area(left, top, width, height);
|
||||
// pixel count is set to 1 since this is the whole buffer
|
||||
begin_dma(src, width * height * 3, 1);
|
||||
}
|
||||
// fallback if DMA is not available
|
||||
else
|
||||
{
|
||||
set_update_area(left, top, width, height);
|
||||
|
||||
pixels().write(src, width * height * 3);
|
||||
}
|
||||
}
|
||||
|
||||
PixelStream Display::pixels() { return PixelStream(*this); }
|
||||
|
||||
void Display::clear() { fill(0, 0, 240, 320, 0, 0, 0); }
|
||||
|
||||
void Display::begin_dma(const volatile uint8_t* src, uint32_t transfer_count,
|
||||
uint32_t pixel_count)
|
||||
{
|
||||
gpio_put(cs, false);
|
||||
send_command_and_begin_data_stream(0x2C);
|
||||
transfers_left = pixel_count;
|
||||
dma_channel_transfer_from_buffer_now(dma, src, transfer_count);
|
||||
}
|
||||
|
||||
void Display::send_command(uint8_t command)
|
||||
{
|
||||
send_command(command, nullptr, 0);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user