mirror of
https://github.com/esphome/esphome.git
synced 2024-11-10 01:07:45 +01:00
Ili9341 8bit indexed mode pt1 (#2490)
This commit is contained in:
parent
9b6b9c1fa2
commit
c000e1d6dd
5 changed files with 90 additions and 3 deletions
|
@ -107,6 +107,53 @@ class ColorUtil {
|
|||
uint32_t gs4 = esp_scale8(color.white, 15);
|
||||
return gs4;
|
||||
}
|
||||
/***
|
||||
* Converts a Color value to an 8bit index using a 24bit 888 palette.
|
||||
* Uses euclidiean distance to calculate the linear distance between
|
||||
* two points in an RGB cube, then iterates through the full palette
|
||||
* returning the closest match.
|
||||
* @param[in] color The target color.
|
||||
* @param[in] palette The 256*3 byte RGB palette.
|
||||
* @return The 8 bit index of the closest color (e.g. for display buffer).
|
||||
*/
|
||||
// static uint8_t color_to_index8_palette888(Color color, uint8_t *palette) {
|
||||
static uint8_t color_to_index8_palette888(Color color, const uint8_t *palette) {
|
||||
uint8_t closest_index = 0;
|
||||
uint32_t minimum_dist2 = UINT32_MAX; // Smallest distance^2 to the target
|
||||
// so far
|
||||
// int8_t(*plt)[][3] = palette;
|
||||
int16_t tgt_r = color.r;
|
||||
int16_t tgt_g = color.g;
|
||||
int16_t tgt_b = color.b;
|
||||
uint16_t x, y, z;
|
||||
// Loop through each row of the palette
|
||||
for (uint16_t i = 0; i < 256; i++) {
|
||||
// Get the pallet rgb color
|
||||
int16_t plt_r = (int16_t) palette[i * 3 + 0];
|
||||
int16_t plt_g = (int16_t) palette[i * 3 + 1];
|
||||
int16_t plt_b = (int16_t) palette[i * 3 + 2];
|
||||
// Calculate euclidian distance (linear distance in rgb cube).
|
||||
x = (uint32_t) std::abs(tgt_r - plt_r);
|
||||
y = (uint32_t) std::abs(tgt_g - plt_g);
|
||||
z = (uint32_t) std::abs(tgt_b - plt_b);
|
||||
uint32_t dist2 = x * x + y * y + z * z;
|
||||
if (dist2 < minimum_dist2) {
|
||||
minimum_dist2 = dist2;
|
||||
closest_index = (uint8_t) i;
|
||||
}
|
||||
}
|
||||
return closest_index;
|
||||
}
|
||||
/***
|
||||
* Converts an 8bit palette index (e.g. from a display buffer) to a color.
|
||||
* @param[in] index The index to look up.
|
||||
* @param[in] palette The 256*3 byte RGB palette.
|
||||
* @return The RGBW Color object looked up by the palette.
|
||||
*/
|
||||
static Color index8_to_color_palette888(uint8_t index, const uint8_t *palette) {
|
||||
Color color = Color(palette[index * 3 + 0], palette[index * 3 + 1], palette[index * 3 + 2], 0);
|
||||
return color;
|
||||
}
|
||||
};
|
||||
} // namespace display
|
||||
} // namespace esphome
|
||||
|
|
|
@ -3,13 +3,16 @@ import esphome.config_validation as cv
|
|||
from esphome import pins
|
||||
from esphome.components import display, spi
|
||||
from esphome.const import (
|
||||
CONF_COLOR_PALETTE,
|
||||
CONF_DC_PIN,
|
||||
CONF_ID,
|
||||
CONF_LAMBDA,
|
||||
CONF_MODEL,
|
||||
CONF_PAGES,
|
||||
CONF_RAW_DATA_ID,
|
||||
CONF_RESET_PIN,
|
||||
)
|
||||
from esphome.core import HexInt
|
||||
|
||||
DEPENDENCIES = ["spi"]
|
||||
|
||||
|
@ -23,6 +26,7 @@ ILI9341M5Stack = ili9341_ns.class_("ILI9341M5Stack", ili9341)
|
|||
ILI9341TFT24 = ili9341_ns.class_("ILI9341TFT24", ili9341)
|
||||
|
||||
ILI9341Model = ili9341_ns.enum("ILI9341Model")
|
||||
ILI9341ColorMode = ili9341_ns.enum("ILI9341ColorMode")
|
||||
|
||||
MODELS = {
|
||||
"M5STACK": ILI9341Model.M5STACK,
|
||||
|
@ -31,6 +35,8 @@ MODELS = {
|
|||
|
||||
ILI9341_MODEL = cv.enum(MODELS, upper=True, space="_")
|
||||
|
||||
COLOR_PALETTE = cv.one_of("NONE", "GRAYSCALE")
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
display.FULL_DISPLAY_SCHEMA.extend(
|
||||
{
|
||||
|
@ -39,6 +45,8 @@ CONFIG_SCHEMA = cv.All(
|
|||
cv.Required(CONF_DC_PIN): pins.gpio_output_pin_schema,
|
||||
cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema,
|
||||
cv.Optional(CONF_LED_PIN): pins.gpio_output_pin_schema,
|
||||
cv.Optional(CONF_COLOR_PALETTE, default="NONE"): COLOR_PALETTE,
|
||||
cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
|
||||
}
|
||||
)
|
||||
.extend(cv.polling_component_schema("1s"))
|
||||
|
@ -73,3 +81,13 @@ async def to_code(config):
|
|||
if CONF_LED_PIN in config:
|
||||
led_pin = await cg.gpio_pin_expression(config[CONF_LED_PIN])
|
||||
cg.add(var.set_led_pin(led_pin))
|
||||
|
||||
if config[CONF_COLOR_PALETTE] == "GRAYSCALE":
|
||||
cg.add(var.set_buffer_color_mode(ILI9341ColorMode.BITS_8_INDEXED))
|
||||
rhs = []
|
||||
for x in range(256):
|
||||
rhs.extend([HexInt(x), HexInt(x), HexInt(x)])
|
||||
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
|
||||
cg.add(var.set_palette(prog_arr))
|
||||
else:
|
||||
pass
|
||||
|
|
|
@ -161,8 +161,13 @@ void HOT ILI9341Display::draw_absolute_pixel_internal(int x, int y, Color color)
|
|||
this->y_high_ = (y > this->y_high_) ? y : this->y_high_;
|
||||
|
||||
uint32_t pos = (y * width_) + x;
|
||||
uint8_t color332 = display::ColorUtil::color_to_332(color, display::ColorOrder::COLOR_ORDER_RGB);
|
||||
buffer_[pos] = color332;
|
||||
if (this->buffer_color_mode_ == BITS_8) {
|
||||
uint8_t color332 = display::ColorUtil::color_to_332(color, display::ColorOrder::COLOR_ORDER_RGB);
|
||||
buffer_[pos] = color332;
|
||||
} else { // if (this->buffer_color_mode_ == BITS_8_INDEXED) {
|
||||
uint8_t index = display::ColorUtil::color_to_index8_palette888(color, this->palette_);
|
||||
buffer_[pos] = index;
|
||||
}
|
||||
}
|
||||
|
||||
// should return the total size: return this->get_width_internal() * this->get_height_internal() * 2 // 16bit color
|
||||
|
@ -227,7 +232,13 @@ uint32_t ILI9341Display::buffer_to_transfer_(uint32_t pos, uint32_t sz) {
|
|||
}
|
||||
|
||||
for (uint32_t i = 0; i < sz; ++i) {
|
||||
uint16_t color = display::ColorUtil::color_to_565(display::ColorUtil::rgb332_to_color(*src++));
|
||||
uint16_t color;
|
||||
if (this->buffer_color_mode_ == BITS_8) {
|
||||
color = display::ColorUtil::color_to_565(display::ColorUtil::rgb332_to_color(*src++));
|
||||
} else { // if (this->buffer_color_mode == BITS_8_INDEXED) {
|
||||
Color col = display::ColorUtil::index8_to_color_palette888(*src++, this->palette_);
|
||||
color = display::ColorUtil::color_to_565(col);
|
||||
}
|
||||
*dst++ = (uint8_t)(color >> 8);
|
||||
*dst++ = (uint8_t) color;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,11 @@ enum ILI9341Model {
|
|||
TFT_24,
|
||||
};
|
||||
|
||||
enum ILI9341ColorMode {
|
||||
BITS_8,
|
||||
BITS_8_INDEXED,
|
||||
};
|
||||
|
||||
class ILI9341Display : public PollingComponent,
|
||||
public display::DisplayBuffer,
|
||||
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
|
||||
|
@ -24,6 +29,8 @@ class ILI9341Display : public PollingComponent,
|
|||
void set_reset_pin(GPIOPin *reset) { this->reset_pin_ = reset; }
|
||||
void set_led_pin(GPIOPin *led) { this->led_pin_ = led; }
|
||||
void set_model(ILI9341Model model) { this->model_ = model; }
|
||||
void set_palette(const uint8_t *palette) { this->palette_ = palette; }
|
||||
void set_buffer_color_mode(ILI9341ColorMode color_mode) { this->buffer_color_mode_ = color_mode; }
|
||||
|
||||
void command(uint8_t value);
|
||||
void data(uint8_t value);
|
||||
|
@ -59,6 +66,9 @@ class ILI9341Display : public PollingComponent,
|
|||
uint16_t y_low_{0};
|
||||
uint16_t x_high_{0};
|
||||
uint16_t y_high_{0};
|
||||
const uint8_t *palette_;
|
||||
|
||||
ILI9341ColorMode buffer_color_mode_{BITS_8};
|
||||
|
||||
uint32_t get_buffer_length_();
|
||||
int get_width_internal() override;
|
||||
|
|
|
@ -105,6 +105,7 @@ CONF_COLOR_BRIGHTNESS = "color_brightness"
|
|||
CONF_COLOR_CORRECT = "color_correct"
|
||||
CONF_COLOR_INTERLOCK = "color_interlock"
|
||||
CONF_COLOR_MODE = "color_mode"
|
||||
CONF_COLOR_PALETTE = "color_palette"
|
||||
CONF_COLOR_TEMPERATURE = "color_temperature"
|
||||
CONF_COLORS = "colors"
|
||||
CONF_COMMAND = "command"
|
||||
|
|
Loading…
Reference in a new issue