Browse Source

Add LCD display virtual LED support

master
jrhoffa 3 years ago
parent
commit
fff36d84b6
7 changed files with 208 additions and 1 deletions
  1. +2
    -0
      CMakeLists.txt
  2. +2
    -0
      main/CMakeLists.txt
  3. +80
    -0
      main/display.cpp
  4. +28
    -0
      main/display.hpp
  5. +2
    -1
      main/main.cpp
  6. +79
    -0
      main/screen_leds.cpp
  7. +15
    -0
      main/screen_leds.hpp

+ 2
- 0
CMakeLists.txt View File

@@ -3,6 +3,8 @@
cmake_minimum_required(VERSION 3.16)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)
include($ENV{IOT_SOLUTION_PATH}/component.cmake)

project(blinky)

target_add_binary_data(blinky.elf "main/broker.pem" TEXT)


+ 2
- 0
main/CMakeLists.txt View File

@@ -11,6 +11,8 @@ idf_component_register(
"leds.cpp"
"presets.cpp"
"spi_leds.cpp"
"screen_leds.cpp"
"display.cpp"
"patterns/gradient.cpp"
"patterns/random.cpp"
"patterns/sparkle.cpp"


+ 80
- 0
main/display.cpp View File

@@ -0,0 +1,80 @@
static const char *TAG = "display";
#include <esp_log.h>



#include "display.hpp"


Display::Display(size_t w, size_t h) :
width(w), height(h), pitch(w), buffer(NULL),
bus(NULL), iface_drv(NULL), driver{.deinit = NULL}
{
esp_err_t ret;

spi_config_t bus_cfg = {
.miso_io_num = GPIO_NUM_4,
.mosi_io_num = GPIO_NUM_35,
.sclk_io_num = GPIO_NUM_36,
.max_transfer_sz = (int)(height * width * sizeof(*buffer) + 8),
};

bus = spi_bus_create(SPI2_HOST, &bus_cfg);
if (NULL == bus) {
ESP_LOGE(TAG, "Failed to acquire bus");
return;
}

scr_interface_spi_config_t spi_dev_cfg = {
.spi_bus = bus,
.pin_num_cs = 34,
.pin_num_dc = 37,
.clk_freq = 40 * 1000 * 1000,
.swap_data = 1,
};

ret = scr_interface_create(SCREEN_IFACE_SPI, &spi_dev_cfg, &iface_drv);
if (ESP_OK != ret) {
ESP_LOGE(TAG, "Failed to create interface");
return;
}

ret = scr_find_driver(SCREEN_CONTROLLER_ST7789, &driver);
if (ESP_OK != ret) {
ESP_LOGE(TAG, "Failed to find driver");
return;
}

scr_controller_config_t lcd_cfg = {
.interface_drv = iface_drv,
.pin_num_rst = 38,
.pin_num_bckl = 33,
.rst_active_level = 0,
.bckl_active_level = 1,
.width = (uint16_t)width,
.height = (uint16_t)height,
.offset_hor = 52,
.offset_ver = 40,
.rotate = SCR_DIR_LRTB,
};

ret = driver.init(&lcd_cfg);
if (ESP_OK != ret) {
ESP_LOGE(TAG, "Failed to initialize driver");
return;
}

buffer = new uint16_t[height * pitch]();
refresh();
}

Display::~Display() {
if (buffer) delete[] buffer;
if (driver.deinit) driver.deinit();
if (iface_drv) scr_interface_delete(iface_drv);
if (bus) spi_bus_delete(&bus);
}

void Display::refresh() {
driver.draw_bitmap(0, 0, width, height, buffer);
}

+ 28
- 0
main/display.hpp View File

@@ -0,0 +1,28 @@
#pragma once

#include <screen_driver.h>


class Display {
public:
Display(size_t w, size_t h);
~Display();

void refresh();

size_t get_width() const { return width; }
size_t get_height() const { return height; }
size_t get_pitch() const { return pitch; }
size_t get_stride() const { return pitch * sizeof(*buffer); }
uint16_t* get_buffer() const { return buffer; }

private:
size_t width;
size_t height;
size_t pitch;
uint16_t *buffer;

spi_bus_handle_t bus;
scr_interface_driver_t *iface_drv;
scr_driver_t driver;
};

+ 2
- 1
main/main.cpp View File

@@ -16,6 +16,7 @@ static const char *TAG = "blinky";
#include "presets.hpp"
#include "utils.hpp"
#include "spi_leds.hpp"
#include "screen_leds.hpp"


// mDNS / NetBIOS
@@ -176,7 +177,7 @@ extern "C" void app_main(void) {
} else {
ESP_LOGI(TAG, "Starting animation");

int period_us = 1000000 / 60;
int period_us = 1000000 / 30;
int64_t target_us = time_us();
int64_t profile_start = target_us;
#ifdef PROFILE_PERF


+ 79
- 0
main/screen_leds.cpp View File

@@ -0,0 +1,79 @@
static const char *TAG = "screen_leds";
#include <esp_log.h>

#include "screen_leds.hpp"


static inline void fill(uint16_t *buffer, uint16_t value, int w, int h, int p = -1) {
if (p <= 0) p = w;
uint16_t *line = buffer;
while (--h >= 0) {
uint16_t *pixel = line;
for (int _w = w; _w > 0; --_w) {
*pixel = value;
++pixel;
}
line += p;
}
}

static inline void box(uint16_t *buffer, uint16_t value, int x, int y, int w, int h, int p = -1) {
if (p <= 0) p = w;
fill(buffer + x + (y * p), value, w, h, p);
}

static inline uint16_t rgb16(int r, int g, int b) {
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((uint8_t)b >> 3);
}

static inline uint16_t color_to_565(Color c) {
return rgb16(c.r, c.g, c.b);
}

ScreenLEDs::ScreenLEDs(int length) : LEDStrip(length), display(135, 240) {}

void ScreenLEDs::length_changing(int length) {
fill(display.get_buffer(), COLOR_BLACK, display.get_width(), display.get_height());
}

void ScreenLEDs::show() {
const int width = display.get_width();
const int height = display.get_height();
const int pitch = display.get_pitch();
auto buffer = display.get_buffer();

const size_t size = ((width + height) * 2) / (length + 4);

int lx = 0, ly = 0;
int dx = 0, dy = size;
for (size_t l = 0; l < length; ++l) {
if (ly + dy > height) {
ly -= dy;
dx = size;
dy = 0;
lx += dx;
} else if (ly < 0) {
ly -= dy;
dx = -size;
dy = 0;
lx += dx;
} else if (lx + dx > width) {
lx -= dx;
dx = 0;
dy = -size;
ly += dy;
} else if (lx < 0) {
lx -= dx;
dx = 0;
dy = size;
ly += dy;
}

box(buffer, color_to_565(pixels[l]), lx, ly, size, size, pitch);

lx += dx;
ly += dy;
}

display.refresh();
}

+ 15
- 0
main/screen_leds.hpp View File

@@ -0,0 +1,15 @@
#pragma once

#include "leds.hpp"
#include "display.hpp"


class ScreenLEDs : public LEDStrip {
public:
ScreenLEDs(int length = 0);
void show();
void length_changing(int length);

private:
Display display;
};

Loading…
Cancel
Save