[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.
This commit is contained in:
parent
48d9140cfc
commit
8e614250b4
51 changed files with 1610 additions and 497 deletions
|
@ -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 RGB565 surfaces in Quantum Painter is done by adding the following to `rules.mk`:
|
||||
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 += rgb565_surface
|
||||
QUANTUM_PAINTER_DRIVERS += ssd1351_spi
|
||||
```
|
||||
|
||||
Creating a RGB565 surface in firmware can then be done with the following API:
|
||||
Creating a SSD1351 device in firmware can then be done with the following API:
|
||||
|
||||
```c
|
||||
painter_device_t qp_rgb565_make_surface(uint16_t panel_width, uint16_t panel_height, void *buffer);
|
||||
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 `buffer` is a user-supplied area of memory, and is assumed to be of the size `sizeof(uint16_t) * panel_width * panel_height`.
|
||||
The device handle returned from the `qp_ssd1351_make_spi_device` function can be used to perform all other drawing operations.
|
||||
|
||||
The device handle returned from the `qp_rgb565_make_surface` 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
|
||||
|
||||
#### ** SH1106 **
|
||||
|
||||
Enabling support for the SH1106 in Quantum Painter is done by adding the following to `rules.mk`:
|
||||
|
||||
```make
|
||||
QUANTUM_PAINTER_ENABLE = yes
|
||||
# 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);
|
||||
```
|
||||
|
||||
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
|
||||
// 3 SPI displays:
|
||||
#define SH1106_NUM_SPI_DEVICES 3
|
||||
// 3 I2C displays:
|
||||
#define SH1106_NUM_I2C_DEVICES 3
|
||||
```
|
||||
|
||||
Native color format mono2 is compatible with SH1106
|
||||
|
||||
<!-- tabs:end -->
|
||||
|
||||
### ** 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 -->
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue