mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	[qspi_dbi] Bugfix and new features (#7979)
This commit is contained in:
		| @@ -23,7 +23,7 @@ from esphome.helpers import write_file_if_changed | |||||||
|  |  | ||||||
| from . import defines as df, helpers, lv_validation as lvalid | from . import defines as df, helpers, lv_validation as lvalid | ||||||
| from .automation import disp_update, focused_widgets, update_to_code | from .automation import disp_update, focused_widgets, update_to_code | ||||||
| from .defines import add_define | from .defines import CONF_DRAW_ROUNDING, add_define | ||||||
| from .encoders import ( | from .encoders import ( | ||||||
|     ENCODERS_CONFIG, |     ENCODERS_CONFIG, | ||||||
|     encoders_to_code, |     encoders_to_code, | ||||||
| @@ -205,6 +205,10 @@ def final_validation(configs): | |||||||
|                 raise cv.Invalid( |                 raise cv.Invalid( | ||||||
|                     "Using auto_clear_enabled: true in display config not compatible with LVGL" |                     "Using auto_clear_enabled: true in display config not compatible with LVGL" | ||||||
|                 ) |                 ) | ||||||
|  |             if draw_rounding := display.get(CONF_DRAW_ROUNDING): | ||||||
|  |                 config[CONF_DRAW_ROUNDING] = max( | ||||||
|  |                     draw_rounding, config[CONF_DRAW_ROUNDING] | ||||||
|  |                 ) | ||||||
|         buffer_frac = config[CONF_BUFFER_SIZE] |         buffer_frac = config[CONF_BUFFER_SIZE] | ||||||
|         if CORE.is_esp32 and buffer_frac > 0.5 and "psram" not in global_config: |         if CORE.is_esp32 and buffer_frac > 0.5 and "psram" not in global_config: | ||||||
|             LOGGER.warning("buffer_size: may need to be reduced without PSRAM") |             LOGGER.warning("buffer_size: may need to be reduced without PSRAM") | ||||||
|   | |||||||
| @@ -1 +1,4 @@ | |||||||
| CODEOWNERS = ["@clydebarrow"] | CODEOWNERS = ["@clydebarrow"] | ||||||
|  |  | ||||||
|  | CONF_DRAW_FROM_ORIGIN = "draw_from_origin" | ||||||
|  | CONF_DRAW_ROUNDING = "draw_rounding" | ||||||
|   | |||||||
| @@ -24,6 +24,7 @@ from esphome.const import ( | |||||||
| ) | ) | ||||||
| from esphome.core import TimePeriod | from esphome.core import TimePeriod | ||||||
|  |  | ||||||
|  | from . import CONF_DRAW_FROM_ORIGIN, CONF_DRAW_ROUNDING | ||||||
| from .models import DriverChip | from .models import DriverChip | ||||||
|  |  | ||||||
| DEPENDENCIES = ["spi"] | DEPENDENCIES = ["spi"] | ||||||
| @@ -41,7 +42,6 @@ COLOR_ORDERS = { | |||||||
| } | } | ||||||
| DATA_PIN_SCHEMA = pins.internal_gpio_output_pin_schema | DATA_PIN_SCHEMA = pins.internal_gpio_output_pin_schema | ||||||
|  |  | ||||||
| CONF_DRAW_FROM_ORIGIN = "draw_from_origin" |  | ||||||
| DELAY_FLAG = 0xFF | DELAY_FLAG = 0xFF | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -78,14 +78,17 @@ def _validate(config): | |||||||
|     return config |     return config | ||||||
|  |  | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = cv.All( | def power_of_two(value): | ||||||
|     display.FULL_DISPLAY_SCHEMA.extend( |     value = cv.int_range(1, 128)(value) | ||||||
|  |     if value & (value - 1) != 0: | ||||||
|  |         raise cv.Invalid("value must be a power of two") | ||||||
|  |     return value | ||||||
|  |  | ||||||
|  |  | ||||||
|  | BASE_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend( | ||||||
|     cv.Schema( |     cv.Schema( | ||||||
|         { |         { | ||||||
|             cv.GenerateID(): cv.declare_id(QSPI_DBI), |             cv.GenerateID(): cv.declare_id(QSPI_DBI), | ||||||
|                 cv.Required(CONF_MODEL): cv.one_of( |  | ||||||
|                     *DriverChip.chips.keys(), upper=True |  | ||||||
|                 ), |  | ||||||
|             cv.Optional(CONF_INIT_SEQUENCE): cv.ensure_list(map_sequence), |             cv.Optional(CONF_INIT_SEQUENCE): cv.ensure_list(map_sequence), | ||||||
|             cv.Required(CONF_DIMENSIONS): cv.Any( |             cv.Required(CONF_DIMENSIONS): cv.Any( | ||||||
|                 cv.dimensions, |                 cv.dimensions, | ||||||
| @@ -93,32 +96,17 @@ CONFIG_SCHEMA = cv.All( | |||||||
|                     { |                     { | ||||||
|                         cv.Required(CONF_WIDTH): validate_dimension, |                         cv.Required(CONF_WIDTH): validate_dimension, | ||||||
|                         cv.Required(CONF_HEIGHT): validate_dimension, |                         cv.Required(CONF_HEIGHT): validate_dimension, | ||||||
|                             cv.Optional( |                         cv.Optional(CONF_OFFSET_HEIGHT, default=0): validate_dimension, | ||||||
|                                 CONF_OFFSET_HEIGHT, default=0 |                         cv.Optional(CONF_OFFSET_WIDTH, default=0): validate_dimension, | ||||||
|                             ): validate_dimension, |  | ||||||
|                             cv.Optional( |  | ||||||
|                                 CONF_OFFSET_WIDTH, default=0 |  | ||||||
|                             ): validate_dimension, |  | ||||||
|                     } |                     } | ||||||
|                 ), |                 ), | ||||||
|             ), |             ), | ||||||
|                 cv.Optional(CONF_TRANSFORM): cv.Schema( |             cv.Optional(CONF_DRAW_FROM_ORIGIN, default=False): cv.boolean, | ||||||
|                     { |  | ||||||
|                         cv.Optional(CONF_MIRROR_X, default=False): cv.boolean, |  | ||||||
|                         cv.Optional(CONF_MIRROR_Y, default=False): cv.boolean, |  | ||||||
|                         cv.Optional(CONF_SWAP_XY, default=False): cv.boolean, |  | ||||||
|                     } |  | ||||||
|                 ), |  | ||||||
|                 cv.Optional(CONF_COLOR_ORDER, default="RGB"): cv.enum( |  | ||||||
|                     COLOR_ORDERS, upper=True |  | ||||||
|                 ), |  | ||||||
|                 cv.Optional(CONF_INVERT_COLORS, default=False): cv.boolean, |  | ||||||
|             cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, |             cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, | ||||||
|             cv.Optional(CONF_ENABLE_PIN): pins.gpio_output_pin_schema, |             cv.Optional(CONF_ENABLE_PIN): pins.gpio_output_pin_schema, | ||||||
|             cv.Optional(CONF_BRIGHTNESS, default=0xD0): cv.int_range( |             cv.Optional(CONF_BRIGHTNESS, default=0xD0): cv.int_range( | ||||||
|                 0, 0xFF, min_included=True, max_included=True |                 0, 0xFF, min_included=True, max_included=True | ||||||
|             ), |             ), | ||||||
|                 cv.Optional(CONF_DRAW_FROM_ORIGIN, default=False): cv.boolean, |  | ||||||
|         } |         } | ||||||
|     ).extend( |     ).extend( | ||||||
|         spi.spi_device_schema( |         spi.spi_device_schema( | ||||||
| @@ -128,6 +116,43 @@ CONFIG_SCHEMA = cv.All( | |||||||
|             quad=True, |             quad=True, | ||||||
|         ) |         ) | ||||||
|     ) |     ) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def model_property(name, defaults, fallback): | ||||||
|  |     return cv.Optional(name, default=defaults.get(name, fallback)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def model_schema(defaults): | ||||||
|  |     transform = cv.Schema( | ||||||
|  |         { | ||||||
|  |             cv.Optional(CONF_MIRROR_X, default=False): cv.boolean, | ||||||
|  |             cv.Optional(CONF_MIRROR_Y, default=False): cv.boolean, | ||||||
|  |         } | ||||||
|  |     ) | ||||||
|  |     if defaults.get(CONF_SWAP_XY, True): | ||||||
|  |         transform = transform.extend( | ||||||
|  |             { | ||||||
|  |                 cv.Optional(CONF_SWAP_XY, default=False): cv.boolean, | ||||||
|  |             } | ||||||
|  |         ) | ||||||
|  |     return BASE_SCHEMA.extend( | ||||||
|  |         { | ||||||
|  |             model_property(CONF_INVERT_COLORS, defaults, False): cv.boolean, | ||||||
|  |             model_property(CONF_COLOR_ORDER, defaults, "RGB"): cv.enum( | ||||||
|  |                 COLOR_ORDERS, upper=True | ||||||
|  |             ), | ||||||
|  |             model_property(CONF_DRAW_ROUNDING, defaults, 2): power_of_two, | ||||||
|  |             cv.Optional(CONF_TRANSFORM): transform, | ||||||
|  |         } | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.All( | ||||||
|  |     cv.typed_schema( | ||||||
|  |         {k.upper(): model_schema(v.defaults) for k, v in DriverChip.chips.items()}, | ||||||
|  |         upper=True, | ||||||
|  |         key=CONF_MODEL, | ||||||
|     ), |     ), | ||||||
|     cv.only_with_esp_idf, |     cv.only_with_esp_idf, | ||||||
| ) | ) | ||||||
| @@ -152,6 +177,7 @@ async def to_code(config): | |||||||
|     cg.add(var.set_brightness(config[CONF_BRIGHTNESS])) |     cg.add(var.set_brightness(config[CONF_BRIGHTNESS])) | ||||||
|     cg.add(var.set_model(config[CONF_MODEL])) |     cg.add(var.set_model(config[CONF_MODEL])) | ||||||
|     cg.add(var.set_draw_from_origin(config[CONF_DRAW_FROM_ORIGIN])) |     cg.add(var.set_draw_from_origin(config[CONF_DRAW_FROM_ORIGIN])) | ||||||
|  |     cg.add(var.set_draw_rounding(config[CONF_DRAW_ROUNDING])) | ||||||
|     if enable_pin := config.get(CONF_ENABLE_PIN): |     if enable_pin := config.get(CONF_ENABLE_PIN): | ||||||
|         enable = await cg.gpio_pin_expression(enable_pin) |         enable = await cg.gpio_pin_expression(enable_pin) | ||||||
|         cg.add(var.set_enable_pin(enable)) |         cg.add(var.set_enable_pin(enable)) | ||||||
| @@ -163,7 +189,8 @@ async def to_code(config): | |||||||
|     if transform := config.get(CONF_TRANSFORM): |     if transform := config.get(CONF_TRANSFORM): | ||||||
|         cg.add(var.set_mirror_x(transform[CONF_MIRROR_X])) |         cg.add(var.set_mirror_x(transform[CONF_MIRROR_X])) | ||||||
|         cg.add(var.set_mirror_y(transform[CONF_MIRROR_Y])) |         cg.add(var.set_mirror_y(transform[CONF_MIRROR_Y])) | ||||||
|         cg.add(var.set_swap_xy(transform[CONF_SWAP_XY])) |         # swap_xy is not implemented for some chips | ||||||
|  |         cg.add(var.set_swap_xy(transform.get(CONF_SWAP_XY, False))) | ||||||
|  |  | ||||||
|     if CONF_DIMENSIONS in config: |     if CONF_DIMENSIONS in config: | ||||||
|         dimensions = config[CONF_DIMENSIONS] |         dimensions = config[CONF_DIMENSIONS] | ||||||
|   | |||||||
| @@ -1,5 +1,10 @@ | |||||||
| # Commands | # Commands | ||||||
|  | from esphome.const import CONF_INVERT_COLORS, CONF_SWAP_XY | ||||||
|  |  | ||||||
|  | from . import CONF_DRAW_ROUNDING | ||||||
|  |  | ||||||
| SW_RESET_CMD = 0x01 | SW_RESET_CMD = 0x01 | ||||||
|  | SLEEP_IN = 0x10 | ||||||
| SLEEP_OUT = 0x11 | SLEEP_OUT = 0x11 | ||||||
| NORON = 0x13 | NORON = 0x13 | ||||||
| INVERT_OFF = 0x20 | INVERT_OFF = 0x20 | ||||||
| @@ -24,11 +29,12 @@ PAGESEL = 0xFE | |||||||
| class DriverChip: | class DriverChip: | ||||||
|     chips = {} |     chips = {} | ||||||
|  |  | ||||||
|     def __init__(self, name: str): |     def __init__(self, name: str, defaults=None): | ||||||
|         name = name.upper() |         name = name.upper() | ||||||
|         self.name = name |         self.name = name | ||||||
|         self.chips[name] = self |         self.chips[name] = self | ||||||
|         self.initsequence = [] |         self.initsequence = [] | ||||||
|  |         self.defaults = defaults or {} | ||||||
|  |  | ||||||
|     def cmd(self, c, *args): |     def cmd(self, c, *args): | ||||||
|         """ |         """ | ||||||
| @@ -59,9 +65,246 @@ chip.cmd(TEON, 0x00) | |||||||
| chip.cmd(PIXFMT, 0x55) | chip.cmd(PIXFMT, 0x55) | ||||||
| chip.cmd(NORON) | chip.cmd(NORON) | ||||||
|  |  | ||||||
| chip = DriverChip("AXS15231") | chip = DriverChip("AXS15231", {CONF_DRAW_ROUNDING: 8, CONF_SWAP_XY: False}) | ||||||
| chip.cmd(0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xA5) | chip.cmd(0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xA5) | ||||||
| chip.cmd(0xC1, 0x33) | chip.cmd(0xC1, 0x33) | ||||||
| chip.cmd(0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) | chip.cmd(0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) | ||||||
|  |  | ||||||
|  | chip = DriverChip( | ||||||
|  |     "JC4832W535", | ||||||
|  |     { | ||||||
|  |         CONF_DRAW_ROUNDING: 8, | ||||||
|  |         CONF_SWAP_XY: False, | ||||||
|  |     }, | ||||||
|  | ) | ||||||
|  | chip.cmd(DISPLAY_OFF) | ||||||
|  | chip.delay(20) | ||||||
|  | chip.cmd(SLEEP_IN) | ||||||
|  | chip.delay(80) | ||||||
|  | chip.cmd(SLEEP_OUT) | ||||||
|  | chip.cmd(INVERT_OFF) | ||||||
|  | # A magic sequence to enable the windowed drawing mode | ||||||
|  | chip.cmd(0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xA5) | ||||||
|  | chip.cmd(0xC1, 0x33) | ||||||
|  | chip.cmd(0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) | ||||||
|  |  | ||||||
|  | chip = DriverChip("JC3636W518", {CONF_INVERT_COLORS: True}) | ||||||
|  | chip.cmd(0xF0, 0x08) | ||||||
|  | chip.cmd(0xF2, 0x08) | ||||||
|  | chip.cmd(0x9B, 0x51) | ||||||
|  | chip.cmd(0x86, 0x53) | ||||||
|  | chip.cmd(0xF2, 0x80) | ||||||
|  | chip.cmd(0xF0, 0x00) | ||||||
|  | chip.cmd(0xF0, 0x01) | ||||||
|  | chip.cmd(0xF1, 0x01) | ||||||
|  | chip.cmd(0xB0, 0x54) | ||||||
|  | chip.cmd(0xB1, 0x3F) | ||||||
|  | chip.cmd(0xB2, 0x2A) | ||||||
|  | chip.cmd(0xB4, 0x46) | ||||||
|  | chip.cmd(0xB5, 0x34) | ||||||
|  | chip.cmd(0xB6, 0xD5) | ||||||
|  | chip.cmd(0xB7, 0x30) | ||||||
|  | chip.cmd(0xBA, 0x00) | ||||||
|  | chip.cmd(0xBB, 0x08) | ||||||
|  | chip.cmd(0xBC, 0x08) | ||||||
|  | chip.cmd(0xBD, 0x00) | ||||||
|  | chip.cmd(0xC0, 0x80) | ||||||
|  | chip.cmd(0xC1, 0x10) | ||||||
|  | chip.cmd(0xC2, 0x37) | ||||||
|  | chip.cmd(0xC3, 0x80) | ||||||
|  | chip.cmd(0xC4, 0x10) | ||||||
|  | chip.cmd(0xC5, 0x37) | ||||||
|  | chip.cmd(0xC6, 0xA9) | ||||||
|  | chip.cmd(0xC7, 0x41) | ||||||
|  | chip.cmd(0xC8, 0x51) | ||||||
|  | chip.cmd(0xC9, 0xA9) | ||||||
|  | chip.cmd(0xCA, 0x41) | ||||||
|  | chip.cmd(0xCB, 0x51) | ||||||
|  | chip.cmd(0xD0, 0x91) | ||||||
|  | chip.cmd(0xD1, 0x68) | ||||||
|  | chip.cmd(0xD2, 0x69) | ||||||
|  | chip.cmd(0xF5, 0x00, 0xA5) | ||||||
|  | chip.cmd(0xDD, 0x3F) | ||||||
|  | chip.cmd(0xDE, 0x3F) | ||||||
|  | chip.cmd(0xF1, 0x10) | ||||||
|  | chip.cmd(0xF0, 0x00) | ||||||
|  | chip.cmd(0xF0, 0x02) | ||||||
|  | chip.cmd( | ||||||
|  |     0xE0, | ||||||
|  |     0x70, | ||||||
|  |     0x09, | ||||||
|  |     0x12, | ||||||
|  |     0x0C, | ||||||
|  |     0x0B, | ||||||
|  |     0x27, | ||||||
|  |     0x38, | ||||||
|  |     0x54, | ||||||
|  |     0x4E, | ||||||
|  |     0x19, | ||||||
|  |     0x15, | ||||||
|  |     0x15, | ||||||
|  |     0x2C, | ||||||
|  |     0x2F, | ||||||
|  | ) | ||||||
|  | chip.cmd( | ||||||
|  |     0xE1, | ||||||
|  |     0x70, | ||||||
|  |     0x08, | ||||||
|  |     0x11, | ||||||
|  |     0x0C, | ||||||
|  |     0x0B, | ||||||
|  |     0x27, | ||||||
|  |     0x38, | ||||||
|  |     0x43, | ||||||
|  |     0x4C, | ||||||
|  |     0x18, | ||||||
|  |     0x14, | ||||||
|  |     0x14, | ||||||
|  |     0x2B, | ||||||
|  |     0x2D, | ||||||
|  | ) | ||||||
|  | chip.cmd(0xF0, 0x10) | ||||||
|  | chip.cmd(0xF3, 0x10) | ||||||
|  | chip.cmd(0xE0, 0x08) | ||||||
|  | chip.cmd(0xE1, 0x00) | ||||||
|  | chip.cmd(0xE2, 0x00) | ||||||
|  | chip.cmd(0xE3, 0x00) | ||||||
|  | chip.cmd(0xE4, 0xE0) | ||||||
|  | chip.cmd(0xE5, 0x06) | ||||||
|  | chip.cmd(0xE6, 0x21) | ||||||
|  | chip.cmd(0xE7, 0x00) | ||||||
|  | chip.cmd(0xE8, 0x05) | ||||||
|  | chip.cmd(0xE9, 0x82) | ||||||
|  | chip.cmd(0xEA, 0xDF) | ||||||
|  | chip.cmd(0xEB, 0x89) | ||||||
|  | chip.cmd(0xEC, 0x20) | ||||||
|  | chip.cmd(0xED, 0x14) | ||||||
|  | chip.cmd(0xEE, 0xFF) | ||||||
|  | chip.cmd(0xEF, 0x00) | ||||||
|  | chip.cmd(0xF8, 0xFF) | ||||||
|  | chip.cmd(0xF9, 0x00) | ||||||
|  | chip.cmd(0xFA, 0x00) | ||||||
|  | chip.cmd(0xFB, 0x30) | ||||||
|  | chip.cmd(0xFC, 0x00) | ||||||
|  | chip.cmd(0xFD, 0x00) | ||||||
|  | chip.cmd(0xFE, 0x00) | ||||||
|  | chip.cmd(0xFF, 0x00) | ||||||
|  | chip.cmd(0x60, 0x42) | ||||||
|  | chip.cmd(0x61, 0xE0) | ||||||
|  | chip.cmd(0x62, 0x40) | ||||||
|  | chip.cmd(0x63, 0x40) | ||||||
|  | chip.cmd(0x64, 0x02) | ||||||
|  | chip.cmd(0x65, 0x00) | ||||||
|  | chip.cmd(0x66, 0x40) | ||||||
|  | chip.cmd(0x67, 0x03) | ||||||
|  | chip.cmd(0x68, 0x00) | ||||||
|  | chip.cmd(0x69, 0x00) | ||||||
|  | chip.cmd(0x6A, 0x00) | ||||||
|  | chip.cmd(0x6B, 0x00) | ||||||
|  | chip.cmd(0x70, 0x42) | ||||||
|  | chip.cmd(0x71, 0xE0) | ||||||
|  | chip.cmd(0x72, 0x40) | ||||||
|  | chip.cmd(0x73, 0x40) | ||||||
|  | chip.cmd(0x74, 0x02) | ||||||
|  | chip.cmd(0x75, 0x00) | ||||||
|  | chip.cmd(0x76, 0x40) | ||||||
|  | chip.cmd(0x77, 0x03) | ||||||
|  | chip.cmd(0x78, 0x00) | ||||||
|  | chip.cmd(0x79, 0x00) | ||||||
|  | chip.cmd(0x7A, 0x00) | ||||||
|  | chip.cmd(0x7B, 0x00) | ||||||
|  | chip.cmd(0x80, 0x48) | ||||||
|  | chip.cmd(0x81, 0x00) | ||||||
|  | chip.cmd(0x82, 0x05) | ||||||
|  | chip.cmd(0x83, 0x02) | ||||||
|  | chip.cmd(0x84, 0xDD) | ||||||
|  | chip.cmd(0x85, 0x00) | ||||||
|  | chip.cmd(0x86, 0x00) | ||||||
|  | chip.cmd(0x87, 0x00) | ||||||
|  | chip.cmd(0x88, 0x48) | ||||||
|  | chip.cmd(0x89, 0x00) | ||||||
|  | chip.cmd(0x8A, 0x07) | ||||||
|  | chip.cmd(0x8B, 0x02) | ||||||
|  | chip.cmd(0x8C, 0xDF) | ||||||
|  | chip.cmd(0x8D, 0x00) | ||||||
|  | chip.cmd(0x8E, 0x00) | ||||||
|  | chip.cmd(0x8F, 0x00) | ||||||
|  | chip.cmd(0x90, 0x48) | ||||||
|  | chip.cmd(0x91, 0x00) | ||||||
|  | chip.cmd(0x92, 0x09) | ||||||
|  | chip.cmd(0x93, 0x02) | ||||||
|  | chip.cmd(0x94, 0xE1) | ||||||
|  | chip.cmd(0x95, 0x00) | ||||||
|  | chip.cmd(0x96, 0x00) | ||||||
|  | chip.cmd(0x97, 0x00) | ||||||
|  | chip.cmd(0x98, 0x48) | ||||||
|  | chip.cmd(0x99, 0x00) | ||||||
|  | chip.cmd(0x9A, 0x0B) | ||||||
|  | chip.cmd(0x9B, 0x02) | ||||||
|  | chip.cmd(0x9C, 0xE3) | ||||||
|  | chip.cmd(0x9D, 0x00) | ||||||
|  | chip.cmd(0x9E, 0x00) | ||||||
|  | chip.cmd(0x9F, 0x00) | ||||||
|  | chip.cmd(0xA0, 0x48) | ||||||
|  | chip.cmd(0xA1, 0x00) | ||||||
|  | chip.cmd(0xA2, 0x04) | ||||||
|  | chip.cmd(0xA3, 0x02) | ||||||
|  | chip.cmd(0xA4, 0xDC) | ||||||
|  | chip.cmd(0xA5, 0x00) | ||||||
|  | chip.cmd(0xA6, 0x00) | ||||||
|  | chip.cmd(0xA7, 0x00) | ||||||
|  | chip.cmd(0xA8, 0x48) | ||||||
|  | chip.cmd(0xA9, 0x00) | ||||||
|  | chip.cmd(0xAA, 0x06) | ||||||
|  | chip.cmd(0xAB, 0x02) | ||||||
|  | chip.cmd(0xAC, 0xDE) | ||||||
|  | chip.cmd(0xAD, 0x00) | ||||||
|  | chip.cmd(0xAE, 0x00) | ||||||
|  | chip.cmd(0xAF, 0x00) | ||||||
|  | chip.cmd(0xB0, 0x48) | ||||||
|  | chip.cmd(0xB1, 0x00) | ||||||
|  | chip.cmd(0xB2, 0x08) | ||||||
|  | chip.cmd(0xB3, 0x02) | ||||||
|  | chip.cmd(0xB4, 0xE0) | ||||||
|  | chip.cmd(0xB5, 0x00) | ||||||
|  | chip.cmd(0xB6, 0x00) | ||||||
|  | chip.cmd(0xB7, 0x00) | ||||||
|  | chip.cmd(0xB8, 0x48) | ||||||
|  | chip.cmd(0xB9, 0x00) | ||||||
|  | chip.cmd(0xBA, 0x0A) | ||||||
|  | chip.cmd(0xBB, 0x02) | ||||||
|  | chip.cmd(0xBC, 0xE2) | ||||||
|  | chip.cmd(0xBD, 0x00) | ||||||
|  | chip.cmd(0xBE, 0x00) | ||||||
|  | chip.cmd(0xBF, 0x00) | ||||||
|  | chip.cmd(0xC0, 0x12) | ||||||
|  | chip.cmd(0xC1, 0xAA) | ||||||
|  | chip.cmd(0xC2, 0x65) | ||||||
|  | chip.cmd(0xC3, 0x74) | ||||||
|  | chip.cmd(0xC4, 0x47) | ||||||
|  | chip.cmd(0xC5, 0x56) | ||||||
|  | chip.cmd(0xC6, 0x00) | ||||||
|  | chip.cmd(0xC7, 0x88) | ||||||
|  | chip.cmd(0xC8, 0x99) | ||||||
|  | chip.cmd(0xC9, 0x33) | ||||||
|  | chip.cmd(0xD0, 0x21) | ||||||
|  | chip.cmd(0xD1, 0xAA) | ||||||
|  | chip.cmd(0xD2, 0x65) | ||||||
|  | chip.cmd(0xD3, 0x74) | ||||||
|  | chip.cmd(0xD4, 0x47) | ||||||
|  | chip.cmd(0xD5, 0x56) | ||||||
|  | chip.cmd(0xD6, 0x00) | ||||||
|  | chip.cmd(0xD7, 0x88) | ||||||
|  | chip.cmd(0xD8, 0x99) | ||||||
|  | chip.cmd(0xD9, 0x33) | ||||||
|  | chip.cmd(0xF3, 0x01) | ||||||
|  | chip.cmd(0xF0, 0x00) | ||||||
|  | chip.cmd(0xF0, 0x01) | ||||||
|  | chip.cmd(0xF1, 0x01) | ||||||
|  | chip.cmd(0xA0, 0x0B) | ||||||
|  | chip.cmd(0xA3, 0x2A) | ||||||
|  | chip.cmd(0xA5, 0xC3) | ||||||
|  | chip.cmd(PIXFMT, 0x55) | ||||||
|  |  | ||||||
|  |  | ||||||
| DriverChip("Custom") | DriverChip("Custom") | ||||||
|   | |||||||
| @@ -33,19 +33,12 @@ void QspiDbi::update() { | |||||||
|   this->do_update_(); |   this->do_update_(); | ||||||
|   if (this->buffer_ == nullptr || this->x_low_ > this->x_high_ || this->y_low_ > this->y_high_) |   if (this->buffer_ == nullptr || this->x_low_ > this->x_high_ || this->y_low_ > this->y_high_) | ||||||
|     return; |     return; | ||||||
|   // Start addresses and widths/heights must be divisible by 2 (CASET/RASET restriction in datasheet) |   // Some chips require that the drawing window be aligned on certain boundaries | ||||||
|   if (this->x_low_ % 2 == 1) { |   auto dr = this->draw_rounding_; | ||||||
|     this->x_low_--; |   this->x_low_ = this->x_low_ / dr * dr; | ||||||
|   } |   this->y_low_ = this->y_low_ / dr * dr; | ||||||
|   if (this->x_high_ % 2 == 0) { |   this->x_high_ = (this->x_high_ + dr) / dr * dr - 1; | ||||||
|     this->x_high_++; |   this->y_high_ = (this->y_high_ + dr) / dr * dr - 1; | ||||||
|   } |  | ||||||
|   if (this->y_low_ % 2 == 1) { |  | ||||||
|     this->y_low_--; |  | ||||||
|   } |  | ||||||
|   if (this->y_high_ % 2 == 0) { |  | ||||||
|     this->y_high_++; |  | ||||||
|   } |  | ||||||
|   if (this->draw_from_origin_) { |   if (this->draw_from_origin_) { | ||||||
|     this->x_low_ = 0; |     this->x_low_ = 0; | ||||||
|     this->y_low_ = 0; |     this->y_low_ = 0; | ||||||
| @@ -175,10 +168,9 @@ void QspiDbi::write_to_display_(int x_start, int y_start, int w, int h, const ui | |||||||
|     this->write_cmd_addr_data(8, 0x32, 24, 0x2C00, ptr, w * h * 2, 4); |     this->write_cmd_addr_data(8, 0x32, 24, 0x2C00, ptr, w * h * 2, 4); | ||||||
|   } else { |   } else { | ||||||
|     auto stride = x_offset + w + x_pad; |     auto stride = x_offset + w + x_pad; | ||||||
|     uint16_t cmd = 0x2C00; |     this->write_cmd_addr_data(8, 0x32, 24, 0x2C00, nullptr, 0, 4); | ||||||
|     for (int y = 0; y != h; y++) { |     for (int y = 0; y != h; y++) { | ||||||
|       this->write_cmd_addr_data(8, 0x32, 24, cmd, ptr + ((y + y_offset) * stride + x_offset) * 2, w * 2, 4); |       this->write_cmd_addr_data(0, 0, 0, 0, ptr + ((y + y_offset) * stride + x_offset) * 2, w * 2, 4); | ||||||
|       cmd = 0x3C00; |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   this->disable(); |   this->disable(); | ||||||
| @@ -220,6 +212,7 @@ void QspiDbi::dump_config() { | |||||||
|   ESP_LOGCONFIG("", "Model: %s", this->model_); |   ESP_LOGCONFIG("", "Model: %s", this->model_); | ||||||
|   ESP_LOGCONFIG(TAG, "  Height: %u", this->height_); |   ESP_LOGCONFIG(TAG, "  Height: %u", this->height_); | ||||||
|   ESP_LOGCONFIG(TAG, "  Width: %u", this->width_); |   ESP_LOGCONFIG(TAG, "  Width: %u", this->width_); | ||||||
|  |   ESP_LOGCONFIG(TAG, "  Draw rounding: %u", this->draw_rounding_); | ||||||
|   LOG_PIN("  CS Pin: ", this->cs_); |   LOG_PIN("  CS Pin: ", this->cs_); | ||||||
|   LOG_PIN("  Reset Pin: ", this->reset_pin_); |   LOG_PIN("  Reset Pin: ", this->reset_pin_); | ||||||
|   ESP_LOGCONFIG(TAG, "  SPI Data rate: %dMHz", (unsigned) (this->data_rate_ / 1000000)); |   ESP_LOGCONFIG(TAG, "  SPI Data rate: %dMHz", (unsigned) (this->data_rate_ / 1000000)); | ||||||
|   | |||||||
| @@ -4,12 +4,10 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #ifdef USE_ESP_IDF | #ifdef USE_ESP_IDF | ||||||
| #include "esphome/core/component.h" |  | ||||||
| #include "esphome/components/spi/spi.h" | #include "esphome/components/spi/spi.h" | ||||||
| #include "esphome/components/display/display.h" | #include "esphome/components/display/display.h" | ||||||
| #include "esphome/components/display/display_buffer.h" | #include "esphome/components/display/display_buffer.h" | ||||||
| #include "esphome/components/display/display_color_utils.h" | #include "esphome/components/display/display_color_utils.h" | ||||||
| #include "esp_lcd_panel_ops.h" |  | ||||||
|  |  | ||||||
| #include "esp_lcd_panel_rgb.h" | #include "esp_lcd_panel_rgb.h" | ||||||
|  |  | ||||||
| @@ -105,6 +103,7 @@ class QspiDbi : public display::DisplayBuffer, | |||||||
|   int get_height_internal() override { return this->height_; } |   int get_height_internal() override { return this->height_; } | ||||||
|   bool can_proceed() override { return this->setup_complete_; } |   bool can_proceed() override { return this->setup_complete_; } | ||||||
|   void add_init_sequence(const std::vector<uint8_t> &sequence) { this->init_sequences_.push_back(sequence); } |   void add_init_sequence(const std::vector<uint8_t> &sequence) { this->init_sequences_.push_back(sequence); } | ||||||
|  |   void set_draw_rounding(unsigned rounding) { this->draw_rounding_ = rounding; } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   void check_buffer_() { |   void check_buffer_() { | ||||||
| @@ -161,6 +160,7 @@ class QspiDbi : public display::DisplayBuffer, | |||||||
|   bool mirror_x_{}; |   bool mirror_x_{}; | ||||||
|   bool mirror_y_{}; |   bool mirror_y_{}; | ||||||
|   bool draw_from_origin_{false}; |   bool draw_from_origin_{false}; | ||||||
|  |   unsigned draw_rounding_{2}; | ||||||
|   uint8_t brightness_{0xD0}; |   uint8_t brightness_{0xD0}; | ||||||
|   const char *model_{"Unknown"}; |   const char *model_{"Unknown"}; | ||||||
|   std::vector<std::vector<uint8_t>> init_sequences_{}; |   std::vector<std::vector<uint8_t>> init_sequences_{}; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user