Add DMA capabilities to fill solid-color portions of the display
This commit is contained in:
parent
f47af9ee07
commit
19491d6038
@ -17,6 +17,8 @@ public:
|
||||
|
||||
void set_update_area(uint16_t left, uint16_t top, uint16_t width,
|
||||
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);
|
||||
|
||||
PixelStream pixels();
|
||||
void clear();
|
||||
@ -24,6 +26,7 @@ public:
|
||||
private:
|
||||
uint8_t sck, tx, cs, dc;
|
||||
spi_inst_t* spi;
|
||||
int dma;
|
||||
|
||||
void send_command(uint8_t command);
|
||||
void send_command(uint8_t command, uint8_t param);
|
||||
|
||||
@ -58,8 +58,6 @@ constexpr int MS_BUTTON_TIMEOUT = 500;
|
||||
|
||||
int main()
|
||||
{
|
||||
set_sys_clock_khz(200 * 1000, false);
|
||||
|
||||
gpio_set_function(FLASH_IO_2, GPIO_FUNC_SIO);
|
||||
gpio_set_function(FLASH_IO_3, GPIO_FUNC_SIO);
|
||||
|
||||
|
||||
@ -17,27 +17,13 @@ Flash flash(FLASH_SCK, FLASH_TX, FLASH_RX, FLASH_CS, 25 * 1000 * 1000);
|
||||
void draw_rectangle(float x, float y, float w, float h, uint8_t r, uint8_t g,
|
||||
uint8_t b)
|
||||
{
|
||||
int wi = w;
|
||||
int hi = h;
|
||||
display.set_update_area(x - w / 2, y - h / 2, wi, hi);
|
||||
|
||||
const uint8_t buf[24] = {
|
||||
r, g, b, r, g, b, r, g, b, r, g, b, r, g, b, r, g, b, r, g, b, r, g, b,
|
||||
};
|
||||
|
||||
auto pixels = display.pixels();
|
||||
for (int i = 0; i < (wi + 1) * (hi + 1); i += 8)
|
||||
{
|
||||
pixels.write(buf, sizeof(buf));
|
||||
}
|
||||
display.fill(x - w / 2, y - h / 2, w, h, r, g, b);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
set_sys_clock_khz(150 * 1000, false);
|
||||
|
||||
gpio_set_function(FLASH_IO_2, GPIO_FUNC_SIO);
|
||||
gpio_set_function(FLASH_IO_3, GPIO_FUNC_SIO);
|
||||
|
||||
@ -68,11 +54,14 @@ int main()
|
||||
|
||||
constexpr float SPEED = 75;
|
||||
float paddle_x = 120;
|
||||
float old_paddle_x = paddle_x;
|
||||
constexpr float paddle_y = 280;
|
||||
|
||||
constexpr float BALL_SPEED = 125;
|
||||
float ball_x = 120;
|
||||
float ball_y = 160;
|
||||
float old_ball_x = ball_x;
|
||||
float old_ball_y = ball_y;
|
||||
|
||||
float INITIAL_BALL_ANGLE = -3.1415926f / 4.0f;
|
||||
float ball_dx = cosf(INITIAL_BALL_ANGLE);
|
||||
@ -88,9 +77,6 @@ int main()
|
||||
float dt = absolute_time_diff_us(previous_time, current) / 1000000.0f;
|
||||
previous_time = current;
|
||||
|
||||
float old_ball_pos_x = ball_x;
|
||||
float old_ball_pos_y = ball_y;
|
||||
|
||||
ball_x += ball_dx * BALL_SPEED * dt;
|
||||
ball_y += ball_dy * BALL_SPEED * dt;
|
||||
|
||||
@ -116,8 +102,6 @@ int main()
|
||||
ball_y = paddle_y - 6;
|
||||
}
|
||||
|
||||
float old_pos = paddle_x;
|
||||
|
||||
left_history = (left_history << 1) | !gpio_get(BUTTON_LEFT);
|
||||
right_history = (right_history << 1) | !gpio_get(BUTTON_RIGHT);
|
||||
|
||||
@ -133,17 +117,21 @@ int main()
|
||||
|
||||
time_since_last_display += dt;
|
||||
|
||||
if (time_since_last_display > 0.02f)
|
||||
if (time_since_last_display > 0.016f)
|
||||
{
|
||||
// ball
|
||||
draw_rectangle(old_ball_pos_x, old_ball_pos_y, 12, 12, 0, 0, 0);
|
||||
draw_rectangle(old_ball_x, old_ball_y, 12, 12, 0, 0, 0);
|
||||
draw_rectangle(ball_x, ball_y, 4, 4, 0xFF, 0xFF, 0xFF);
|
||||
|
||||
// player paddle
|
||||
draw_rectangle(old_pos - 20, paddle_y, 6, 7, 0, 0, 0);
|
||||
draw_rectangle(old_pos + 20, paddle_y, 6, 7, 0, 0, 0);
|
||||
draw_rectangle(old_paddle_x - 20, paddle_y, 6, 7, 0, 0, 0);
|
||||
draw_rectangle(old_paddle_x + 20, paddle_y, 6, 7, 0, 0, 0);
|
||||
draw_rectangle(paddle_x, paddle_y, 40, 5, 0xFF, 0xFF, 0xFF);
|
||||
time_since_last_display = 0;
|
||||
|
||||
old_paddle_x = paddle_x;
|
||||
old_ball_x = ball_x;
|
||||
old_ball_y = ball_y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
112
src/display.cpp
112
src/display.cpp
@ -3,11 +3,35 @@
|
||||
#include "devicelib.h"
|
||||
#include "pixelstream.h"
|
||||
|
||||
#include <hardware/dma.h>
|
||||
#include <hardware/irq.h>
|
||||
#include <hardware/spi.h>
|
||||
#include <pico/stdlib.h>
|
||||
|
||||
using namespace lib;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
constexpr uint PIXELS_PER_TRANSFER = 16;
|
||||
|
||||
int dma = -1;
|
||||
uint8_t cs;
|
||||
volatile int transfers_left = 0;
|
||||
volatile uint8_t color_buffer[3 * PIXELS_PER_TRANSFER];
|
||||
|
||||
void dma_handler()
|
||||
{
|
||||
dma_hw->ints0 = 1u << dma;
|
||||
transfers_left -= PIXELS_PER_TRANSFER;
|
||||
|
||||
dma_channel_set_read_addr(dma, color_buffer, transfers_left > 0);
|
||||
|
||||
gpio_put(cs, transfers_left <= 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Display::Display(uint8_t sck, uint8_t tx, uint8_t cs, uint8_t dc,
|
||||
int baudrate) :
|
||||
sck(sck),
|
||||
@ -21,6 +45,36 @@ Display::Display(uint8_t sck, uint8_t tx, uint8_t cs, uint8_t dc,
|
||||
hard_assert(sck_spi == tx_spi, "Invalid configuration");
|
||||
spi = sck_spi;
|
||||
|
||||
// only support one display with DMA for now
|
||||
if (::dma < 0)
|
||||
{
|
||||
dma = dma_claim_unused_channel(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
dma = -1;
|
||||
}
|
||||
|
||||
if (dma >= 0)
|
||||
{
|
||||
::dma = dma;
|
||||
::cs = cs;
|
||||
|
||||
dma_channel_config config = dma_channel_get_default_config(dma);
|
||||
channel_config_set_transfer_data_size(&config, DMA_SIZE_8);
|
||||
channel_config_set_read_increment(&config, true);
|
||||
channel_config_set_write_increment(&config, false);
|
||||
channel_config_set_dreq(&config, spi_get_dreq(spi, true));
|
||||
|
||||
dma_channel_configure(dma, &config, &spi_get_hw(spi)->dr, color_buffer,
|
||||
3 * PIXELS_PER_TRANSFER, false);
|
||||
|
||||
dma_channel_set_irq0_enabled(dma, true);
|
||||
|
||||
irq_set_exclusive_handler(DMA_IRQ_0, dma_handler);
|
||||
irq_set_enabled(DMA_IRQ_0, true);
|
||||
}
|
||||
|
||||
gpio_set_function(sck, GPIO_FUNC_SPI);
|
||||
gpio_set_function(tx, GPIO_FUNC_SPI);
|
||||
|
||||
@ -46,8 +100,6 @@ Display::Display(uint8_t sck, uint8_t tx, uint8_t cs, uint8_t dc,
|
||||
send_command(0x3A, 0x66);
|
||||
sleep_ms(10);
|
||||
|
||||
set_update_area(0, 0, 240, 320);
|
||||
|
||||
// set memory addressing mode
|
||||
send_command(0x36, 0b11000000);
|
||||
|
||||
@ -61,25 +113,18 @@ Display::Display(uint8_t sck, uint8_t tx, uint8_t cs, uint8_t dc,
|
||||
// set display brightness
|
||||
send_command(0x51, 0x00);
|
||||
|
||||
// clear display to black
|
||||
{
|
||||
auto p = pixels();
|
||||
for (int i = 0; i < 320 * 240; i++)
|
||||
{
|
||||
p.write(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// turn on display
|
||||
send_command(0x29);
|
||||
sleep_ms(10);
|
||||
|
||||
clear();
|
||||
}
|
||||
|
||||
void Display::set_update_area(uint16_t left, uint16_t top, uint16_t width,
|
||||
uint16_t height)
|
||||
{
|
||||
const uint16_t right = left + width;
|
||||
const uint16_t bottom = top + height;
|
||||
const uint16_t right = left + width - 1;
|
||||
const uint16_t bottom = top + height - 1;
|
||||
{
|
||||
uint8_t params[4]
|
||||
= { static_cast<uint8_t>(left >> 8), static_cast<uint8_t>(left & 0xFF),
|
||||
@ -98,19 +143,44 @@ void Display::set_update_area(uint16_t left, uint16_t top, uint16_t width,
|
||||
}
|
||||
}
|
||||
|
||||
PixelStream Display::pixels() { return PixelStream(*this); }
|
||||
|
||||
void Display::clear()
|
||||
void Display::fill(uint16_t left, uint16_t top, uint16_t width,
|
||||
uint16_t height, uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
set_update_area(0, 0, 240, 320);
|
||||
|
||||
auto stream = pixels();
|
||||
for (int i = 0; i < 240 * 320; i++)
|
||||
if (dma >= 0)
|
||||
{
|
||||
stream.write(0, 0, 0);
|
||||
while (transfers_left > 0)
|
||||
;
|
||||
for (int i = 0; i < PIXELS_PER_TRANSFER; i++)
|
||||
{
|
||||
color_buffer[3 * i + 0] = r;
|
||||
color_buffer[3 * i + 1] = g;
|
||||
color_buffer[3 * i + 2] = b;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
// fallback if DMA is not available
|
||||
else
|
||||
{
|
||||
set_update_area(left, top, width, height);
|
||||
|
||||
auto pixels = this->pixels();
|
||||
for (int i = 0; i < width * height; i++)
|
||||
{
|
||||
pixels.write(r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PixelStream Display::pixels() { return PixelStream(*this); }
|
||||
|
||||
void Display::clear() { fill(0, 0, 240, 320, 0, 0, 0); }
|
||||
|
||||
void Display::send_command(uint8_t command)
|
||||
{
|
||||
send_command(command, nullptr, 0);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user