-
-
Notifications
You must be signed in to change notification settings - Fork 40.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
350 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
// Copyright 2023 Pablo Martinez (@elpekenin) <elpekenin@elpekenin.dev> | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
#include "qp_ls0xx.h" | ||
#include "qp_ls0xx_panel.h" | ||
|
||
#ifdef QUANTUM_PAINTER_LS0XX_SPI_ENABLE | ||
# include "qp_comms_spi.h" | ||
#endif // QUANTUM_PAINTER_LS0XX_SPI_ENABLE | ||
|
||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
// Common | ||
|
||
// Driver storage | ||
mip_panel_painter_device_t ls0xx_device_t_drivers[LS0XX_NUM_DEVICES] = {0}; | ||
|
||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
// SPI | ||
|
||
#ifdef QUANTUM_PAINTER_LS0XX_SPI_ENABLE | ||
|
||
// Factory function for creating a handle to the LS0XX device | ||
painter_device_t qp_ls0xx_device_t_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, uint16_t spi_divisor, int spi_mode, void *buf) { | ||
for (uint32_t i = 0; i < LS0XX_NUM_DEVICES; ++i) { | ||
mip_panel_painter_device_t *driver = &ls0xx_device_t_drivers[i]; | ||
if (!driver->base.driver_vtable) { | ||
painter_device_t surface = qp_make_mono1bpp_surface_advanced(&driver->surface, 1, panel_width, panel_height, buf); | ||
if (!surface) { | ||
return NULL; | ||
} | ||
driver->base.driver_vtable = (const painter_driver_vtable_t *)&ls0xx_driver_vtable; | ||
driver->base.comms_vtable = (const painter_comms_vtable_t *)&spi_comms_vtable; | ||
driver->base.native_bits_per_pixel = 1; | ||
driver->base.panel_width = panel_width; | ||
driver->base.panel_height = panel_height; | ||
driver->base.rotation = QP_ROTATION_0; | ||
driver->base.offset_x = 0; | ||
driver->base.offset_y = 0; | ||
driver->base.comms_config = &driver->spi_config; | ||
driver->spi_config.chip_select_pin = chip_select_pin; | ||
driver->spi_config.lsb_first = false; | ||
driver->spi_config.divisor = spi_divisor; | ||
driver->spi_config.mode = spi_mode; | ||
driver->surface.invert_order = true; | ||
if (!qp_internal_register_device((painter_device_t)driver)) { | ||
memset(driver, 0, sizeof(mip_panel_painter_device_t)); | ||
return NULL; | ||
} | ||
return (painter_device_t)driver; | ||
} | ||
} | ||
return NULL; | ||
} | ||
|
||
#endif // QUANTUM_PAINTER_LS0XX_SPI_ENABLE | ||
|
||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// Copyright 2023 Pablo Martinez (@elpekenin) <elpekenin@elpekenin.dev> | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
#pragma once | ||
|
||
#include "gpio.h" | ||
#include "qp_internal.h" | ||
|
||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
// Quantum Painter ILI9163 configurables (add to your keyboard's config.h) | ||
|
||
#ifndef LS0XX_NUM_DEVICES | ||
/** | ||
* @def This controls the maximum number of LS0XX devices that Quantum Painter can communicate with at any one time. | ||
* Increasing this number allows for multiple displays to be used. | ||
*/ | ||
# define LS0XX_NUM_DEVICES 1 | ||
#endif | ||
|
||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
// Quantum Painter ILI9163 device factories | ||
|
||
#ifdef QUANTUM_PAINTER_LS0XX_SPI_ENABLE | ||
/** | ||
* Factory method for an LS0XX MIP SPI device. | ||
* | ||
* @param panel_width[in] the width of the display panel | ||
* @param panel_height[in] the height of the display panel | ||
* @param chip_select_pin[in] the GPIO pin used for SPI chip select | ||
* @param spi_divisor[in] the SPI divisor to use when communicating with the display | ||
* @param spi_mode[in] the SPI mode to use when communicating with the display | ||
* @param buf[in] the address of the buffer where data will be stored | ||
* @return the device handle used with all drawing routines in Quantum Painter | ||
*/ | ||
painter_device_t qp_ls0xx_device_t_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, uint16_t spi_divisor, int spi_mode, void *buf); | ||
#endif // QUANTUM_PAINTER_LS0XX_SPI_ENABLE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// Copyright 2023 Pablo Martinez (@elpekenin) <elpekenin@elpekenin.dev> | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
#pragma once | ||
|
||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
// Quantum Painter LS0XX command opcodes (lsb_first, as the display expects them) | ||
#define LS0XX_WRITE 0x80 // Start sending framebuffer | ||
#define LS0XX_VCOM 0x40 // Set VCOM high | ||
#define LS0XX_CLEAR 0x20 // Clear |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
// Copyright 2023 Pablo Martinez (@elpekenin) <elpekenin@elpekenin.dev> | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
/* Code adapted from Zephyr's and Adafruit's drivers | ||
* | ||
* Should support several LS0xx because they are pretty much | ||
* the same, with different sizes. | ||
* | ||
* Driver was developed on a LS013B7DH03, cant grant anything else will work as is. | ||
* | ||
* Note: xx does not mean 2 chars, names are pretty long | ||
*/ | ||
|
||
#include "qp_internal.h" | ||
#include "qp_surface.h" | ||
#include "qp_surface_internal.h" | ||
#include "qp_ls0xx_panel.h" | ||
#include "qp_ls0xx_opcodes.h" | ||
|
||
#ifdef QUANTUM_PAINTER_SPI_ENABLE | ||
# include "spi_master.h" | ||
#endif // QUANTUM_PAINTER_SPI_ENABLE | ||
|
||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
// Quantum Painter API implementations | ||
|
||
__attribute__((weak)) bool qp_ls0xx_init(painter_device_t device, painter_rotation_t rotation) { | ||
mip_panel_painter_device_t *mip_dev = (mip_panel_painter_device_t *)device; | ||
painter_driver_t * surface = (painter_driver_t *)&mip_dev->surface; | ||
|
||
// Init the internal surface | ||
if (!surface->driver_vtable->init(surface, rotation)) { | ||
qp_dprintf("Failed to init internal surface in qp_ls0xx_init\n"); | ||
return false; | ||
} | ||
|
||
mip_dev->base.rotation = rotation; | ||
surface->rotation = rotation; | ||
|
||
writePinHigh(mip_dev->spi_config.chip_select_pin); | ||
const uint8_t ls0xx_init_sequence[] = {LS0XX_CLEAR, 0}; | ||
spi_transmit(ls0xx_init_sequence, ARRAY_SIZE(ls0xx_init_sequence)); | ||
writePinLow(mip_dev->spi_config.chip_select_pin); | ||
|
||
return true; | ||
} | ||
|
||
bool qp_ls0xx_passthru_power(painter_device_t device, bool power_on) { | ||
// No-op | ||
return true; | ||
} | ||
|
||
bool qp_ls0xx_passthru_clear(painter_device_t device) { | ||
// Just re-init the display | ||
painter_driver_t *driver = (painter_driver_t *)device; | ||
return qp_ls0xx_init(device, driver->rotation); | ||
} | ||
|
||
// FIXME: This code may not work on the biggest displays of the family | ||
// Since it uses uint8_t, we can "only" have 255 rows | ||
bool qp_ls0xx_flush(painter_device_t device) { | ||
mip_panel_painter_device_t *mip_dev = (mip_panel_painter_device_t *)device; | ||
surface_painter_device_t * surface = &(mip_dev->surface); | ||
surface_dirty_data_t dirty = surface->dirty; | ||
|
||
if (!dirty.is_dirty) { | ||
// nothing to be sent | ||
return true; | ||
} | ||
|
||
// find out dirty area | ||
uint8_t top = dirty.t; | ||
uint8_t bottom = dirty.b; | ||
|
||
// bytes sent for each row's data | ||
uint8_t bytes_per_line = (mip_dev->base.panel_width + 7) / 8 * mip_dev->base.native_bits_per_pixel; | ||
// offset used to access such data | ||
uint16_t buffer_offset = top * bytes_per_line; | ||
|
||
// start sending | ||
writePinHigh(mip_dev->spi_config.chip_select_pin); | ||
uint8_t cmd = LS0XX_WRITE | LS0XX_VCOM; | ||
spi_transmit(&cmd, 1); | ||
|
||
// dummy data for alignment, value doesnt matter | ||
uint8_t dummy = 0; | ||
|
||
// iterate over the lines | ||
for (uint8_t i = 0; i < bottom + 1 - top; ++i) { | ||
// set y-pos (counts from 1, needs the `+1`) | ||
uint8_t n_line = bitrev(i + top + 1); | ||
spi_transmit(&n_line, 1); | ||
|
||
// send data | ||
spi_transmit(&surface->u8buffer[buffer_offset], bytes_per_line); | ||
buffer_offset += bytes_per_line; | ||
|
||
spi_transmit(&dummy, 1); | ||
} | ||
|
||
spi_transmit(&dummy, 1); | ||
writePinLow(mip_dev->spi_config.chip_select_pin); | ||
|
||
// clear surface's dirty area, no API to prevent extra prints | ||
surface->base.driver_vtable->flush(surface); | ||
|
||
return true; | ||
} | ||
|
||
bool qp_ls0xx_passthru_viewport(painter_device_t device, uint16_t left, uint16_t top, uint16_t right, uint16_t bottom) { | ||
mip_panel_painter_device_t *mip_dev = (mip_panel_painter_device_t *)device; | ||
painter_driver_t * surface = (painter_driver_t *)&mip_dev->surface; | ||
|
||
return surface->driver_vtable->viewport(surface, left, top, right, bottom); | ||
} | ||
|
||
bool qp_ls0xx_passthru_pixdata(painter_device_t device, const void *pixel_data, uint32_t native_pixel_count) { | ||
mip_panel_painter_device_t *mip_dev = (mip_panel_painter_device_t *)device; | ||
painter_driver_t * surface = (painter_driver_t *)&mip_dev->surface; | ||
|
||
return surface->driver_vtable->pixdata(surface, pixel_data, native_pixel_count); | ||
} | ||
|
||
bool qp_ls0xx_passthru_palette_convert(painter_device_t device, int16_t palette_size, qp_pixel_t *palette) { | ||
mip_panel_painter_device_t *mip_dev = (mip_panel_painter_device_t *)device; | ||
painter_driver_t * surface = (painter_driver_t *)&mip_dev->surface; | ||
|
||
return surface->driver_vtable->palette_convert(surface, palette_size, palette); | ||
} | ||
|
||
bool qp_ls0xx_passthru_append_pixels(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices) { | ||
mip_panel_painter_device_t *mip_dev = (mip_panel_painter_device_t *)device; | ||
painter_driver_t * surface = (painter_driver_t *)&mip_dev->surface; | ||
|
||
return surface->driver_vtable->append_pixels(surface, target_buffer, palette, pixel_offset, pixel_count, palette_indices); | ||
} | ||
|
||
bool qp_ls0xx_passthru_append_pixdata(painter_device_t device, uint8_t *target_buffer, uint32_t pixdata_offset, uint8_t pixdata_byte) { | ||
mip_panel_painter_device_t *mip_dev = (mip_panel_painter_device_t *)device; | ||
painter_driver_t * surface = (painter_driver_t *)&mip_dev->surface; | ||
|
||
return surface->driver_vtable->append_pixdata(surface, target_buffer, pixdata_offset, pixdata_byte); | ||
} | ||
|
||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
// Driver vtable | ||
|
||
const painter_driver_vtable_t ls0xx_driver_vtable = { | ||
.init = qp_ls0xx_init, | ||
.power = qp_ls0xx_passthru_power, | ||
.clear = qp_ls0xx_passthru_clear, | ||
.flush = qp_ls0xx_flush, | ||
.pixdata = qp_ls0xx_passthru_pixdata, | ||
.viewport = qp_ls0xx_passthru_viewport, | ||
.palette_convert = qp_ls0xx_passthru_palette_convert, | ||
.append_pixels = qp_ls0xx_passthru_append_pixels, | ||
.append_pixdata = qp_ls0xx_passthru_append_pixdata, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// Copyright 2023 Pablo Martinez (@elpekenin) <elpekenin@elpekenin.dev> | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
#pragma once | ||
|
||
#include "qp_internal.h" | ||
#include "qp_surface_internal.h" | ||
|
||
#include "qp_comms_spi.h" | ||
|
||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
// Common MIP panel implementation for Sharp displays, using 3-wire SPI. | ||
|
||
// Device definition | ||
typedef struct mip_panel_painter_device_t { | ||
painter_driver_t base; // must be first, so it can be cast to/from the painter_device_t* type | ||
|
||
union { | ||
#ifdef QUANTUM_PAINTER_SPI_ENABLE | ||
// SPI-based configurables | ||
qp_comms_spi_config_t spi_config; | ||
#endif // QUANTUM_PAINTER_SPI_ENABLE | ||
|
||
// TODO: I2C/parallel etc. | ||
}; | ||
|
||
surface_painter_device_t surface; | ||
} mip_panel_painter_device_t; | ||
|
||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
// Forward declarations for injecting into concrete driver vtables | ||
extern const painter_driver_vtable_t ls0xx_driver_vtable; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters