qp_ssd1351.c (6213B)
1 // Copyright 2021-2023 Nick Brassel (@tzarc) 2 // SPDX-License-Identifier: GPL-2.0-or-later 3 4 #include "qp_internal.h" 5 #include "qp_comms.h" 6 #include "qp_ssd1351.h" 7 #include "qp_ssd1351_opcodes.h" 8 #include "qp_tft_panel.h" 9 10 #ifdef QUANTUM_PAINTER_SSD1351_SPI_ENABLE 11 # include "qp_comms_spi.h" 12 #endif // QUANTUM_PAINTER_SSD1351_SPI_ENABLE 13 14 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 15 // Common 16 17 // Driver storage 18 tft_panel_dc_reset_painter_device_t ssd1351_drivers[SSD1351_NUM_DEVICES] = {0}; 19 20 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 21 // Initialization 22 23 __attribute__((weak)) bool qp_ssd1351_init(painter_device_t device, painter_rotation_t rotation) { 24 tft_panel_dc_reset_painter_device_t *driver = (tft_panel_dc_reset_painter_device_t *)device; 25 26 // clang-format off 27 const uint8_t ssd1351_init_sequence[] = { 28 // Command, Delay, N, Data[N] 29 SSD1351_COMMANDLOCK, 5, 1, 0x12, 30 SSD1351_COMMANDLOCK, 5, 1, 0xB1, 31 SSD1351_DISPLAYOFF, 5, 0, 32 SSD1351_CLOCKDIV, 5, 1, 0xF1, 33 SSD1351_MUXRATIO, 5, 1, 0x7F, 34 SSD1351_DISPLAYOFFSET, 5, 1, 0x00, 35 SSD1351_SETGPIO, 5, 1, 0x00, 36 SSD1351_FUNCTIONSELECT, 5, 1, 0x01, 37 SSD1351_PRECHARGE, 5, 1, 0x32, 38 SSD1351_VCOMH, 5, 1, 0x05, 39 SSD1351_NORMALDISPLAY, 5, 0, 40 SSD1351_CONTRASTABC, 5, 3, 0xC8, 0x80, 0xC8, 41 SSD1351_CONTRASTMASTER, 5, 1, 0x0F, 42 SSD1351_SETVSL, 5, 3, 0xA0, 0xB5, 0x55, 43 SSD1351_PRECHARGE2, 5, 1, 0x01, 44 SSD1351_DISPLAYON, 5, 0, 45 }; 46 // clang-format on 47 if (!qp_comms_bulk_command_sequence(device, ssd1351_init_sequence, sizeof(ssd1351_init_sequence))) { 48 return false; 49 } 50 51 // Configure the rotation (i.e. the ordering and direction of memory writes in GRAM) 52 const uint8_t madctl[] = { 53 [QP_ROTATION_0] = SSD1351_MADCTL_BGR | SSD1351_MADCTL_MY, 54 [QP_ROTATION_90] = SSD1351_MADCTL_BGR | SSD1351_MADCTL_MX | SSD1351_MADCTL_MY | SSD1351_MADCTL_MV, 55 [QP_ROTATION_180] = SSD1351_MADCTL_BGR | SSD1351_MADCTL_MX, 56 [QP_ROTATION_270] = SSD1351_MADCTL_BGR | SSD1351_MADCTL_MV, 57 }; 58 if (!qp_comms_command_databyte(device, SSD1351_SETREMAP, madctl[rotation])) { 59 return false; 60 } 61 return qp_comms_command_databyte(device, SSD1351_STARTLINE, (rotation == QP_ROTATION_0 || rotation == QP_ROTATION_90) ? driver->base.panel_height : 0); 62 } 63 64 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 65 // Driver vtable 66 67 const tft_panel_dc_reset_painter_driver_vtable_t ssd1351_driver_vtable = { 68 .base = 69 { 70 .init = qp_ssd1351_init, 71 .power = qp_tft_panel_power, 72 .clear = qp_tft_panel_clear, 73 .flush = qp_tft_panel_flush, 74 .pixdata = qp_tft_panel_pixdata, 75 .viewport = qp_tft_panel_viewport, 76 .palette_convert = qp_tft_panel_palette_convert_rgb565_swapped, 77 .append_pixels = qp_tft_panel_append_pixels_rgb565, 78 .append_pixdata = qp_tft_panel_append_pixdata, 79 }, 80 .num_window_bytes = 1, 81 .swap_window_coords = true, 82 .opcodes = 83 { 84 .display_on = SSD1351_DISPLAYON, 85 .display_off = SSD1351_DISPLAYOFF, 86 .set_column_address = SSD1351_SETCOLUMN, 87 .set_row_address = SSD1351_SETROW, 88 .enable_writes = SSD1351_WRITERAM, 89 }, 90 }; 91 92 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 93 // SPI 94 95 #ifdef QUANTUM_PAINTER_SSD1351_SPI_ENABLE 96 97 // Factory function for creating a handle to the SSD1351 device 98 painter_device_t qp_ssd1351_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode) { 99 for (uint32_t i = 0; i < SSD1351_NUM_DEVICES; ++i) { 100 tft_panel_dc_reset_painter_device_t *driver = &ssd1351_drivers[i]; 101 if (!driver->base.driver_vtable) { 102 driver->base.driver_vtable = (const painter_driver_vtable_t *)&ssd1351_driver_vtable; 103 driver->base.comms_vtable = (const painter_comms_vtable_t *)&spi_comms_with_dc_vtable; 104 driver->base.panel_width = panel_width; 105 driver->base.panel_height = panel_height; 106 driver->base.rotation = QP_ROTATION_0; 107 driver->base.offset_x = 0; 108 driver->base.offset_y = 0; 109 driver->base.native_bits_per_pixel = 16; // RGB565 110 111 // SPI and other pin configuration 112 driver->base.comms_config = &driver->spi_dc_reset_config; 113 driver->spi_dc_reset_config.spi_config.chip_select_pin = chip_select_pin; 114 driver->spi_dc_reset_config.spi_config.divisor = spi_divisor; 115 driver->spi_dc_reset_config.spi_config.lsb_first = false; 116 driver->spi_dc_reset_config.spi_config.mode = spi_mode; 117 driver->spi_dc_reset_config.dc_pin = dc_pin; 118 driver->spi_dc_reset_config.reset_pin = reset_pin; 119 driver->spi_dc_reset_config.command_params_uses_command_pin = false; 120 121 if (!qp_internal_register_device((painter_device_t)driver)) { 122 memset(driver, 0, sizeof(tft_panel_dc_reset_painter_device_t)); 123 return NULL; 124 } 125 126 return (painter_device_t)driver; 127 } 128 } 129 return NULL; 130 } 131 132 #endif // QUANTUM_PAINTER_SSD1351_SPI_ENABLE 133 134 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////