summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorNick Brassel <nick@tzarc.org>2023-10-22 13:27:31 +1100
committerGitHub <noreply@github.com>2023-10-22 13:27:31 +1100
commit8e614250b4b44a14a6a8c93bea3a6d1fd02790cf (patch)
tree15c000b7765082911a3a6d84b1499b51c25f43d8 /docs
parent48d9140cfc197d6f4c54bf8022902d28fac37624 (diff)
[QP] Add support for OLED, variable framebuffer bpp (#19997)
Co-authored-by: Pablo Martínez <58857054+elpekenin@users.noreply.github.com> Co-authored-by: Dasky <32983009+daskygit@users.noreply.github.com> Fixup delta frame coordinates after #20296.
Diffstat (limited to 'docs')
-rw-r--r--docs/quantum_painter.md166
1 files changed, 110 insertions, 56 deletions
diff --git a/docs/quantum_painter.md b/docs/quantum_painter.md
index 8acf6aeb36..e8fa1bdece 100644
--- a/docs/quantum_painter.md
+++ b/docs/quantum_painter.md
@@ -13,22 +13,24 @@ QUANTUM_PAINTER_DRIVERS += ......
You will also likely need to select an appropriate driver in `rules.mk`, which is listed below.
-!> Quantum Painter is not currently integrated with system-level operations such as disabling displays after a configurable timeout, or when the keyboard goes into suspend. Users will need to handle this manually at the current time.
+!> Quantum Painter is not currently integrated with system-level operations such as when the keyboard goes into suspend. Users will need to handle this manually at the current time.
The QMK CLI can be used to convert from normal images such as PNG files or animated GIFs, as well as fonts from TTF files.
Supported devices:
-| Display Panel | Panel Type | Size | Comms Transport | Driver |
-|----------------|--------------------|------------------|-----------------|---------------------------------------------|
-| GC9A01 | RGB LCD (circular) | 240x240 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += gc9a01_spi` |
-| ILI9163 | RGB LCD | 128x128 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ili9163_spi` |
-| ILI9341 | RGB LCD | 240x320 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ili9341_spi` |
-| ILI9488 | RGB LCD | 320x480 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ili9488_spi` |
-| SSD1351 | RGB OLED | 128x128 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ssd1351_spi` |
-| ST7735 | RGB LCD | 132x162, 80x160 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += st7735_spi` |
-| ST7789 | RGB LCD | 240x320, 240x240 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += st7789_spi` |
-| RGB565 Surface | Virtual | User-defined | None | `QUANTUM_PAINTER_DRIVERS += rgb565_surface` |
+| Display Panel | Panel Type | Size | Comms Transport | Driver |
+|---------------|--------------------|------------------|-----------------|------------------------------------------|
+| GC9A01 | RGB LCD (circular) | 240x240 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += gc9a01_spi` |
+| ILI9163 | RGB LCD | 128x128 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ili9163_spi` |
+| ILI9341 | RGB LCD | 240x320 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ili9341_spi` |
+| ILI9488 | RGB LCD | 320x480 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ili9488_spi` |
+| SSD1351 | RGB OLED | 128x128 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ssd1351_spi` |
+| ST7735 | RGB LCD | 132x162, 80x160 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += st7735_spi` |
+| ST7789 | RGB LCD | 240x320, 240x240 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += st7789_spi` |
+| SH1106 (SPI) | Monochrome OLED | 128x64 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += sh1106_spi` |
+| SH1106 (I2C) | Monochrome OLED | 128x64 | I2C | `QUANTUM_PAINTER_DRIVERS += sh1106_i2c` |
+| Surface | Virtual | User-defined | None | `QUANTUM_PAINTER_DRIVERS += surface` |
## Quantum Painter Configuration :id=quantum-painter-config
@@ -188,7 +190,8 @@ Writing /home/qmk/qmk_firmware/keyboards/my_keeb/generated/noto11.qff.c...
<!-- tabs:start -->
-### ** Common: Standard TFT (SPI + D/C + RST) **
+
+### ** LCD **
Most TFT display panels use a 5-pin interface -- SPI SCK, SPI MOSI, SPI CS, D/C, and RST pins.
@@ -302,32 +305,6 @@ The maximum number of displays can be configured by changing the following in yo
Native color format rgb888 is compatible with ILI9488
-#### ** SSD1351 **
-
-Enabling support for the SSD1351 in Quantum Painter is done by adding the following to `rules.mk`:
-
-```make
-QUANTUM_PAINTER_ENABLE = yes
-QUANTUM_PAINTER_DRIVERS += ssd1351_spi
-```
-
-Creating a SSD1351 device in firmware can then be done with the following API:
-
-```c
-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);
-```
-
-The device handle returned from the `qp_ssd1351_make_spi_device` function can be used to perform all other drawing operations.
-
-The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
-
-```c
-// 3 displays:
-#define SSD1351_NUM_DEVICES 3
-```
-
-Native color format rgb565 is compatible with SSD1351
-
#### ** ST7735 **
Enabling support for the ST7735 in Quantum Painter is done by adding the following to `rules.mk`:
@@ -386,62 +363,139 @@ Native color format rgb565 is compatible with ST7789
<!-- tabs:end -->
-### ** Common: Surfaces **
+### ** OLED **
-Quantum Painter has surface drivers which are able to target a buffer in RAM. In general, surfaces keep track of the "dirty" region -- the area that has been drawn to since the last flush -- so that when transferring to the display they can transfer the minimal amount of data to achieve the end result.
+OLED displays tend to use 5-pin SPI when at larger resolutions, or when using color -- SPI SCK, SPI MOSI, SPI CS, D/C, and RST pins. Smaller OLEDs may use I2C instead.
-!> These generally require significant amounts of RAM, so at large sizes and/or higher bit depths, they may not be usable on all MCUs.
+When using these displays, either `spi_master` or `i2c_master` must already be correctly configured for both the platform and panel you're building for.
+
+For SPI, the pin assignments for SPI CS, D/C, and RST are specified during device construction -- for I2C the panel's address is specified instead.
<!-- tabs:start -->
-#### ** RGB565 Surface **
+#### ** SSD1351 **
+
+Enabling support for the SSD1351 in Quantum Painter is done by adding the following to `rules.mk`:
+
+```make
+QUANTUM_PAINTER_ENABLE = yes
+QUANTUM_PAINTER_DRIVERS += ssd1351_spi
+```
+
+Creating a SSD1351 device in firmware can then be done with the following API:
+
+```c
+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);
+```
+
+The device handle returned from the `qp_ssd1351_make_spi_device` function can be used to perform all other drawing operations.
-Enabling support for RGB565 surfaces in Quantum Painter is done by adding the following to `rules.mk`:
+The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
+
+```c
+// 3 displays:
+#define SSD1351_NUM_DEVICES 3
+```
+
+Native color format rgb565 is compatible with SSD1351
+
+#### ** SH1106 **
+
+Enabling support for the SH1106 in Quantum Painter is done by adding the following to `rules.mk`:
```make
QUANTUM_PAINTER_ENABLE = yes
-QUANTUM_PAINTER_DRIVERS += rgb565_surface
+# For SPI:
+QUANTUM_PAINTER_DRIVERS += sh1106_spi
+# For I2C:
+QUANTUM_PAINTER_DRIVERS += sh1106_i2c
+```
+
+Creating a SH1106 device in firmware can then be done with the following APIs:
+
+```c
+// SPI-based SH1106:
+painter_device_t qp_sh1106_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);
+// I2C-based SH1106:
+painter_device_t qp_sh1106_make_i2c_device(uint16_t panel_width, uint16_t panel_height, uint8_t i2c_address);
```
-Creating a RGB565 surface in firmware can then be done with the following API:
+The device handle returned from the `qp_sh1106_make_???_device` function can be used to perform all other drawing operations.
+
+The maximum number of displays of each type can be configured by changing the following in your `config.h` (default is 1):
```c
-painter_device_t qp_rgb565_make_surface(uint16_t panel_width, uint16_t panel_height, void *buffer);
+// 3 SPI displays:
+#define SH1106_NUM_SPI_DEVICES 3
+// 3 I2C displays:
+#define SH1106_NUM_I2C_DEVICES 3
```
-The `buffer` is a user-supplied area of memory, and is assumed to be of the size `sizeof(uint16_t) * panel_width * panel_height`.
+Native color format mono2 is compatible with SH1106
+
+<!-- tabs:end -->
-The device handle returned from the `qp_rgb565_make_surface` function can be used to perform all other drawing operations.
+### ** Surface **
+
+Quantum Painter has a surface driver which is able to target a buffer in RAM. In general, surfaces keep track of the "dirty" region -- the area that has been drawn to since the last flush -- so that when transferring to the display they can transfer the minimal amount of data to achieve the end result.
+
+!> These generally require significant amounts of RAM, so at large sizes and/or higher bit depths, they may not be usable on all MCUs.
+
+Enabling support for surfaces in Quantum Painter is done by adding the following to `rules.mk`:
+
+```make
+QUANTUM_PAINTER_ENABLE = yes
+QUANTUM_PAINTER_DRIVERS += surface
+```
+
+Creating a surface in firmware can then be done with the following APIs:
+
+```c
+// 16bpp RGB565 surface:
+painter_device_t qp_make_rgb565_surface(uint16_t panel_width, uint16_t panel_height, void *buffer);
+// 1bpp monochrome surface:
+painter_device_t qp_make_mono1bpp_surface(uint16_t panel_width, uint16_t panel_height, void *buffer);
+```
+
+The `buffer` is a user-supplied area of memory, which can be statically allocated using `SURFACE_REQUIRED_BUFFER_BYTE_SIZE`:
+
+```c
+// Buffer required for a 240x80 16bpp surface:
+uint8_t framebuffer[SURFACE_REQUIRED_BUFFER_BYTE_SIZE(240, 80, 16)];
+```
+
+The device handle returned from the `qp_make_?????_surface` function can be used to perform all other drawing operations.
Example:
```c
static painter_device_t my_surface;
-static uint16_t my_framebuffer[320 * 240]; // Allocate a buffer for a 320x240 RGB565 display
+static uint8_t my_framebuffer[SURFACE_REQUIRED_BUFFER_BYTE_SIZE(240, 80, 16)]; // Allocate a buffer for a 16bpp 240x80 RGB565 display
void keyboard_post_init_kb(void) {
- my_surface = qp_rgb565_make_surface(320, 240, my_framebuffer);
+ my_surface = qp_rgb565_make_surface(240, 80, my_framebuffer);
qp_init(my_surface, QP_ROTATION_0);
+ keyboard_post_init_user();
}
```
-The maximum number of RGB565 surfaces can be configured by changing the following in your `config.h` (default is 1):
+The maximum number of surfaces can be configured by changing the following in your `config.h` (default is 1):
```c
// 3 surfaces:
-#define RGB565_SURFACE_NUM_DEVICES 3
+#define SURFACE_NUM_DEVICES 3
```
-To transfer the contents of the RGB565 surface to another display, the following API can be invoked:
+To transfer the contents of the surface to another display of the same pixel format, the following API can be invoked:
```c
-bool qp_rgb565_surface_draw(painter_device_t surface, painter_device_t display, uint16_t x, uint16_t y);
+bool qp_surface_draw(painter_device_t surface, painter_device_t display, uint16_t x, uint16_t y);
```
The `surface` is the surface to copy out from. The `display` is the target display to draw into. `x` and `y` are the target location to draw the surface pixel data. Under normal circumstances, the location should be consistent, as the dirty region is calculated with respect to the `x` and `y` coordinates -- changing those will result in partial, overlapping draws.
-?> Calling `qp_flush()` on the surface resets its dirty region. Copying the surface contents to the display also automatically resets the dirty region.
+!> The surface and display panel must have the same native pixel format.
-<!-- tabs:end -->
+?> Calling `qp_flush()` on the surface resets its dirty region. Copying the surface contents to the display also automatically resets the dirty region.
<!-- tabs:end -->