Checkpoint adding SSD1306 and PanelDevice.
This commit is contained in:
parent
0743fc4a5e
commit
9e912048ab
@ -11,7 +11,7 @@
|
|||||||
#include <driver/i2c_master.h>
|
#include <driver/i2c_master.h>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
// To use LV_COLOR_FORMAT_I1, we need an extra buffer to hold the converted data
|
// To use LV_COLOR_FORMAT_I1 we need an extra buffer to hold the converted data.
|
||||||
uint8_t Display::oled_buffer_[LCD_H_RES * LCD_V_RES / 8];
|
uint8_t Display::oled_buffer_[LCD_H_RES * LCD_V_RES / 8];
|
||||||
|
|
||||||
// LVGL library is not thread-safe, this example calls LVGL APIs from tasks.
|
// LVGL library is not thread-safe, this example calls LVGL APIs from tasks.
|
||||||
@ -26,13 +26,14 @@ Display::Display(const I2C &i2c) :
|
|||||||
lv_init();
|
lv_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a lvgl display
|
// Create a lvgl display.
|
||||||
|
// TODO: Use PanelDevice functions
|
||||||
display_ = lv_display_create(LCD_H_RES, LCD_V_RES);
|
display_ = lv_display_create(LCD_H_RES, LCD_V_RES);
|
||||||
// associate the i2c panel handle to the display
|
// associate the i2c panel handle to the display
|
||||||
lv_display_set_user_data(display_, panel_.get());
|
lv_display_set_user_data(display_, panel_.get());
|
||||||
// create draw buffer
|
// Create draw buffer.
|
||||||
ESP_LOGI(TAG, "Allocate separate LVGL draw buffers");
|
ESP_LOGI(TAG, "Allocate separate LVGL draw buffers");
|
||||||
// LVGL reserves 2 x 4 bytes in the buffer, as these are assumed to be used as a palette.
|
// TODO: Use PanelDevice functions
|
||||||
size_t draw_buffer_sz = LCD_H_RES * LCD_V_RES / 8 + LVGL_PALETTE_SIZE;
|
size_t draw_buffer_sz = LCD_H_RES * LCD_V_RES / 8 + LVGL_PALETTE_SIZE;
|
||||||
buf_ = heap_caps_calloc(1, draw_buffer_sz,
|
buf_ = heap_caps_calloc(1, draw_buffer_sz,
|
||||||
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||||
@ -40,11 +41,11 @@ Display::Display(const I2C &i2c) :
|
|||||||
|
|
||||||
// LVGL9 suooprt new monochromatic format.
|
// LVGL9 suooprt new monochromatic format.
|
||||||
lv_display_set_color_format(display_, LV_COLOR_FORMAT_I1);
|
lv_display_set_color_format(display_, LV_COLOR_FORMAT_I1);
|
||||||
// initialize LVGL draw buffers
|
// Initialize LVGL draw buffers.
|
||||||
lv_display_set_buffers(display_, buf_, nullptr, draw_buffer_sz,
|
lv_display_set_buffers(display_, buf_, nullptr, draw_buffer_sz,
|
||||||
LV_DISPLAY_RENDER_MODE_FULL);
|
LV_DISPLAY_RENDER_MODE_FULL);
|
||||||
lv_display_set_rotation(display_, LV_DISPLAY_ROTATION_0);
|
lv_display_set_rotation(display_, LV_DISPLAY_ROTATION_0);
|
||||||
// set the callback which can copy the rendered image to an area of the display
|
// Set callback which can copy the rendered image to an area of the display.
|
||||||
lv_display_set_flush_cb(display_, Display::lvgl_flush_cb);
|
lv_display_set_flush_cb(display_, Display::lvgl_flush_cb);
|
||||||
|
|
||||||
ESP_LOGI(TAG,
|
ESP_LOGI(TAG,
|
||||||
@ -57,6 +58,7 @@ Display::Display(const I2C &i2c) :
|
|||||||
esp_lcd_panel_io_register_event_callbacks(panel_.io_handle_, &cbs,
|
esp_lcd_panel_io_register_event_callbacks(panel_.io_handle_, &cbs,
|
||||||
display_));
|
display_));
|
||||||
|
|
||||||
|
// TODO: What is this
|
||||||
ESP_LOGI(TAG, "Use esp_timer as LVGL tick timer");
|
ESP_LOGI(TAG, "Use esp_timer as LVGL tick timer");
|
||||||
const esp_timer_create_args_t lvgl_tick_timer_args = {
|
const esp_timer_create_args_t lvgl_tick_timer_args = {
|
||||||
.callback = &Display::lvgl_increase_tick,
|
.callback = &Display::lvgl_increase_tick,
|
||||||
@ -109,8 +111,10 @@ void Display::lvgl_flush_cb(lv_display_t *display, const lv_area_t *area,
|
|||||||
auto panel_handle =
|
auto panel_handle =
|
||||||
(esp_lcd_panel_handle_t) lv_display_get_user_data(display);
|
(esp_lcd_panel_handle_t) lv_display_get_user_data(display);
|
||||||
|
|
||||||
// This is necessary because LVGL reserves 2 x 4 bytes in the buffer, as these are assumed to be used as a palette. Skip the palette here
|
// Necessary because LVGL reserves 2x4 bytes in the buffer for a palette.
|
||||||
// More information about the monochrome, please refer to https://docs.lvgl.io/9.2/porting/display.html#monochrome-displays
|
// For more information about the monochrome, please refer to:
|
||||||
|
// https://docs.lvgl.io/9.2/porting/display.html#monochrome-displays
|
||||||
|
// Skip the palette here.
|
||||||
px_map += LVGL_PALETTE_SIZE;
|
px_map += LVGL_PALETTE_SIZE;
|
||||||
|
|
||||||
uint16_t hor_res = lv_display_get_physical_horizontal_resolution(display);
|
uint16_t hor_res = lv_display_get_physical_horizontal_resolution(display);
|
||||||
@ -121,7 +125,7 @@ void Display::lvgl_flush_cb(lv_display_t *display, const lv_area_t *area,
|
|||||||
|
|
||||||
for (int32_t y = y1; y <= y2; y++) {
|
for (int32_t y = y1; y <= y2; y++) {
|
||||||
for (int32_t x = x1; x <= x2; x++) {
|
for (int32_t x = x1; x <= x2; x++) {
|
||||||
/* The order of bits is MSB first
|
/* The order of bits is MSB first.
|
||||||
MSB LSB
|
MSB LSB
|
||||||
bits 7 6 5 4 3 2 1 0
|
bits 7 6 5 4 3 2 1 0
|
||||||
pixels 0 1 2 3 4 5 6 7
|
pixels 0 1 2 3 4 5 6 7
|
||||||
@ -130,8 +134,8 @@ void Display::lvgl_flush_cb(lv_display_t *display, const lv_area_t *area,
|
|||||||
bool chroma_color = (px_map[(hor_res >> 3) * y + (x >> 3)] &
|
bool chroma_color = (px_map[(hor_res >> 3) * y + (x >> 3)] &
|
||||||
1 << (7 - x % 8));
|
1 << (7 - x % 8));
|
||||||
|
|
||||||
/* Write to the buffer as required for the display.
|
// Write to the buffer as required for the display.
|
||||||
* It writes only 1-bit for monochrome displays mapped vertically.*/
|
// It writes only 1-bit for monochrome displays mapped vertically.
|
||||||
uint8_t *buf = oled_buffer_ + hor_res * (y >> 3) + (x);
|
uint8_t *buf = oled_buffer_ + hor_res * (y >> 3) + (x);
|
||||||
if (chroma_color) {
|
if (chroma_color) {
|
||||||
(*buf) &= ~(1 << (y % 8));
|
(*buf) &= ~(1 << (y % 8));
|
||||||
@ -140,19 +144,19 @@ void Display::lvgl_flush_cb(lv_display_t *display, const lv_area_t *area,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// pass the draw buffer to the driver
|
// Pass the draw buffer to the driver.
|
||||||
ESP_ERROR_CHECK(
|
ESP_ERROR_CHECK(
|
||||||
esp_lcd_panel_draw_bitmap(panel_handle, x1, y1, x2 + 1, y2 + 1,
|
esp_lcd_panel_draw_bitmap(panel_handle, x1, y1, x2 + 1, y2 + 1,
|
||||||
oled_buffer_));
|
oled_buffer_));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::lvgl_increase_tick(void *arg)
|
void Display::lvgl_increase_tick(void *)
|
||||||
{
|
{
|
||||||
/* Tell LVGL how many milliseconds has elapsed */
|
// Tell LVGL how many milliseconds has elapsed
|
||||||
lv_tick_inc(LVGL_TICK_PERIOD_MS);
|
lv_tick_inc(LVGL_TICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::lvgl_port_task(void *arg)
|
void Display::lvgl_port_task(void *)
|
||||||
{
|
{
|
||||||
ESP_LOGI(TAG, "Starting LVGL task");
|
ESP_LOGI(TAG, "Starting LVGL task");
|
||||||
uint32_t time_till_next_ms = 0;
|
uint32_t time_till_next_ms = 0;
|
||||||
@ -164,14 +168,6 @@ void Display::lvgl_port_task(void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SSD1306::SSD1306() {
|
|
||||||
//
|
|
||||||
//}
|
|
||||||
//void *SSD1306::vendor_config()
|
|
||||||
//{
|
|
||||||
// return &ssd1306_config_;
|
|
||||||
//}
|
|
||||||
|
|
||||||
I2C::I2C() : i2c_bus_(nullptr)
|
I2C::I2C() : i2c_bus_(nullptr)
|
||||||
{
|
{
|
||||||
ESP_LOGI(TAG, "Initialize I2C bus");
|
ESP_LOGI(TAG, "Initialize I2C bus");
|
||||||
@ -203,18 +199,22 @@ Panel::Panel(i2c_master_bus_handle_t i2c) : io_handle_(nullptr), panel_(nullptr)
|
|||||||
esp_lcd_new_panel_io_i2c(i2c, &io_config, &io_handle_));
|
esp_lcd_new_panel_io_i2c(i2c, &io_config, &io_handle_));
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Install SSD1306 panel driver");
|
ESP_LOGI(TAG, "Install SSD1306 panel driver");
|
||||||
ssd1306_config_ = {
|
SSD1306 ssd1306({.height = LCD_V_RES});
|
||||||
.height = LCD_V_RES,
|
|
||||||
};
|
|
||||||
panel_config_ = {
|
panel_config_ = {
|
||||||
.reset_gpio_num = PIN_RST,
|
.reset_gpio_num = PIN_RST,
|
||||||
.bits_per_pixel = 1,
|
.bits_per_pixel = 1,
|
||||||
.vendor_config = &ssd1306_config_
|
|
||||||
};
|
};
|
||||||
ESP_ERROR_CHECK(
|
ssd1306.create_panel(panel_config_, io_handle_, panel_);
|
||||||
esp_lcd_new_panel_ssd1306(io_handle_, &panel_config_, &panel_));
|
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_));
|
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_));
|
||||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_));
|
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_));
|
||||||
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_, true));
|
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SSD1306::SSD1306(esp_lcd_panel_ssd1306_config_t ssd_config,
|
||||||
|
int width,
|
||||||
|
int height) :
|
||||||
|
PanelDevice<esp_lcd_panel_ssd1306_config_t>(width, height)
|
||||||
|
{
|
||||||
|
vendor_config_ = ssd_config;
|
||||||
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <driver/i2c_types.h>
|
#include <driver/i2c_types.h>
|
||||||
#include <driver/i2c_master.h>
|
#include <driver/i2c_master.h>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <esp_lcd_panel_ops.h>
|
||||||
#include "misc/lv_types.h"
|
#include "misc/lv_types.h"
|
||||||
#include "misc/lv_area.h"
|
#include "misc/lv_area.h"
|
||||||
#include "display/lv_display.h"
|
#include "display/lv_display.h"
|
||||||
@ -19,11 +20,11 @@
|
|||||||
|
|
||||||
static const char *TAG = "lcd-panel";
|
static const char *TAG = "lcd-panel";
|
||||||
|
|
||||||
// https://www.digikey.com/en/products/detail/winstar-display/WEA012864DWPP3N00003/20533255
|
|
||||||
// According to SSD1306 datasheet
|
// According to SSD1306 datasheet
|
||||||
|
// https://www.digikey.com/en/products/detail/winstar-display/WEA012864DWPP3N00003/20533255
|
||||||
// Bit number used to represent command and parameter
|
// Bit number used to represent command and parameter
|
||||||
#define SCREEN_WIDTH 128 // OLED display width, in pixels
|
#define SCREEN_WIDTH 128 // OLED display width, in pixels.
|
||||||
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
|
#define SCREEN_HEIGHT 64 // OLED display height, in pixels.
|
||||||
#define LCD_H_RES SCREEN_WIDTH
|
#define LCD_H_RES SCREEN_WIDTH
|
||||||
#define LCD_V_RES SCREEN_HEIGHT
|
#define LCD_V_RES SCREEN_HEIGHT
|
||||||
#define I2C_HW_ADDR 0x3C
|
#define I2C_HW_ADDR 0x3C
|
||||||
@ -31,7 +32,7 @@ static const char *TAG = "lcd-panel";
|
|||||||
#define LCD_CMD_BITS 8
|
#define LCD_CMD_BITS 8
|
||||||
#define LCD_PARAM_BITS 8
|
#define LCD_PARAM_BITS 8
|
||||||
|
|
||||||
// Pin may vary based on your schematic
|
// Pin may vary based on your schematic.
|
||||||
#define PIN_SDA GPIO_NUM_21
|
#define PIN_SDA GPIO_NUM_21
|
||||||
#define PIN_SCL GPIO_NUM_22
|
#define PIN_SCL GPIO_NUM_22
|
||||||
#define PIN_RST -1
|
#define PIN_RST -1
|
||||||
@ -54,6 +55,67 @@ struct ScopedLock {
|
|||||||
static _lock_t lock_;
|
static _lock_t lock_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class PanelDevice {
|
||||||
|
public:
|
||||||
|
PanelDevice(size_t width, size_t height) : width_(width), height_(height) { }
|
||||||
|
|
||||||
|
~PanelDevice() = default;
|
||||||
|
|
||||||
|
[[nodiscard]] size_t get_width() const { return width_; }
|
||||||
|
|
||||||
|
[[nodiscard]] size_t get_height() const { return height_; }
|
||||||
|
|
||||||
|
[[nodiscard]] size_t get_area() const { return width_ * height_; }
|
||||||
|
|
||||||
|
[[nodiscard]] size_t get_draw_buffer_size() const
|
||||||
|
{
|
||||||
|
// LVGL reserves 2x4 bytes in the buffer to be used as a palette.
|
||||||
|
return width_ * height_ / 8 + LVGL_PALETTE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] lv_display_t *create_display() const
|
||||||
|
{
|
||||||
|
return lv_display_create(width_, height_);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] T &get_vendor_config() const { return vendor_config_; }
|
||||||
|
|
||||||
|
void create_panel(esp_lcd_panel_dev_config_t &panel_config,
|
||||||
|
esp_lcd_panel_io_handle_t io_handle,
|
||||||
|
esp_lcd_panel_handle_t &panel_handle);
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t width_;
|
||||||
|
size_t height_;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
T vendor_config_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void PanelDevice<T>::create_panel(esp_lcd_panel_dev_config_t &config,
|
||||||
|
esp_lcd_panel_io_handle_t io,
|
||||||
|
esp_lcd_panel_handle_t &panel)
|
||||||
|
{
|
||||||
|
// If the passed handle is already allocated, delete it.
|
||||||
|
if (panel != nullptr) {
|
||||||
|
esp_lcd_panel_del(panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the vendor config and allocate a new panel handle.
|
||||||
|
config.vendor_config = &vendor_config_;
|
||||||
|
ESP_ERROR_CHECK(esp_lcd_new_panel_ssd1306(io, &config, &panel));
|
||||||
|
}
|
||||||
|
|
||||||
|
class SSD1306 : public PanelDevice<esp_lcd_panel_ssd1306_config_t> {
|
||||||
|
public:
|
||||||
|
explicit SSD1306(esp_lcd_panel_ssd1306_config_t ssd_config,
|
||||||
|
int width = SCREEN_WIDTH, int height = SCREEN_HEIGHT);
|
||||||
|
|
||||||
|
~SSD1306() = default;
|
||||||
|
};
|
||||||
|
|
||||||
class Panel {
|
class Panel {
|
||||||
public:
|
public:
|
||||||
explicit Panel(i2c_master_bus_handle_t i2c);
|
explicit Panel(i2c_master_bus_handle_t i2c);
|
||||||
@ -77,8 +139,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
esp_lcd_panel_dev_config_t panel_config_;
|
esp_lcd_panel_dev_config_t panel_config_;
|
||||||
|
|
||||||
esp_lcd_panel_ssd1306_config_t ssd1306_config_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Display {
|
class Display {
|
||||||
@ -125,15 +185,4 @@ private:
|
|||||||
std::unordered_map<const char *, lv_obj_t *> objects_;
|
std::unordered_map<const char *, lv_obj_t *> objects_;
|
||||||
};
|
};
|
||||||
|
|
||||||
//class SSD1306 : public Display {
|
|
||||||
//public:
|
|
||||||
// SSD1306();
|
|
||||||
//
|
|
||||||
// void * vendor_config() override;
|
|
||||||
//
|
|
||||||
//private:
|
|
||||||
// esp_lcd_panel_dev_config_t panel_config_;
|
|
||||||
// esp_lcd_panel_ssd1306_config_t ssd1306_config_;
|
|
||||||
//};
|
|
||||||
|
|
||||||
#endif // DISPLAY_H
|
#endif // DISPLAY_H
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
|
||||||
|
// TODO: Can this be static since there can only be one initialization?
|
||||||
I2C i2c;
|
I2C i2c;
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user