From b30401a1c27e783427701e9b0a6b81c1affd5137 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sun, 9 Jul 2023 11:48:03 +0200 Subject: [PATCH 1/5] drivers/st7735: fix Kconfig logic for ST7789 MODULE_ST7789 is enabled if MODULE_ST7735 is enabled and the board has selected HAVE_ST7789. --- drivers/st7735/Kconfig | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/st7735/Kconfig b/drivers/st7735/Kconfig index 1c873ac3f0bb..c015fa639816 100644 --- a/drivers/st7735/Kconfig +++ b/drivers/st7735/Kconfig @@ -16,12 +16,6 @@ config MODULE_ST7735 select MODULE_ZTIMER select MODULE_ZTIMER_MSEC -config HAVE_ST7735 - bool - select MODULE_ST7735 if MODULE_DISP_DEV - help - Indicates that an ST7735 display is present. - config MODULE_ST7789 bool depends on HAVE_ST7789 @@ -29,6 +23,12 @@ config MODULE_ST7789 help ST7789 display driver +config HAVE_ST7735 + bool + select MODULE_ST7735 if MODULE_DISP_DEV + help + Indicates that an ST7735 display is present. + config HAVE_ST7789 bool select MODULE_ST7735 if MODULE_DISP_DEV From 3f8ba798cb9a5dbc8c005b632524d25e05c4f0f7 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sun, 9 Jul 2023 11:55:42 +0200 Subject: [PATCH 2/5] drivers/lcd: move basic communication functions to drivers/lcd In preparation for the parallel interface support the following changes were made: 1. The code for basic communication (acquire/release SPI device, SPI transfers), which were always implemented identically in the individual display drivers again and again, have been moved to the LCD driver as low-level functions and are now used by the display drivers. These low level function allow - code deduplication on one hand and - to define a more abstract communication interface on the other hand that can then be extended by parallel communication 2. Identical GPIO initialization has also been moved from display drivers to the LCD driver. --- drivers/include/lcd.h | 46 ++++++++++++ drivers/lcd/lcd.c | 163 +++++++++++++++++++++++++++++++----------- 2 files changed, 168 insertions(+), 41 deletions(-) diff --git a/drivers/include/lcd.h b/drivers/include/lcd.h index 8ab2dbb2ce7d..a44d6bb7f635 100644 --- a/drivers/include/lcd.h +++ b/drivers/include/lcd.h @@ -137,6 +137,52 @@ struct lcd_driver { uint16_t y2); }; +/** + * @brief Low Level to acquire the device + * + * @param[out] dev device descriptor + */ +void lcd_ll_acquire(const lcd_t *dev); + +/** + * @brief Low Level function to release the device + * + * @param[out] dev device descriptor + */ +void lcd_ll_release(const lcd_t *dev); + +/** + * @brief Low level function to write a command + * + * @pre The device must have already been acquired with @ref lcd_ll_acquire + * before this function can be called. + * + * @param[in] dev device descriptor + * @param[in] cmd command code + * @param[in] data command data to the device + * @param[in] len length of the command data + */ +void lcd_ll_write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data, + size_t len); + +/** + * @brief Low level function for read command command + * + * @note Very often the SPI MISO signal of the serial interface or the RDX + * signal of the MCU 8080 parallel interface are not connected to the + * display. In this case the read command does not provide valid data. + * + * @pre The device must have already been acquired with @ref lcd_ll_acquire + * before this function can be called. + * @pre len > 0 + * + * @param[in] dev device descriptor + * @param[in] cmd command + * @param[out] data data from the device + * @param[in] len length of the returned data + */ +void lcd_ll_read_cmd(const lcd_t *dev, uint8_t cmd, uint8_t *data, size_t len); + /** * @brief Setup an lcd display device * diff --git a/drivers/lcd/lcd.c b/drivers/lcd/lcd.c index bb6b0cfd747f..c903a1b94a7a 100644 --- a/drivers/lcd/lcd.c +++ b/drivers/lcd/lcd.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2018 Koen Zandberg * 2021 Francisco Molina + * 2023 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -16,6 +17,7 @@ * * @author Koen Zandberg * @author Francisco Molina + * @author Gunar Schorcht * * @} */ @@ -25,6 +27,7 @@ #include "byteorder.h" #include "periph/spi.h" #include "kernel_defines.h" +#include "ztimer.h" #include "lcd.h" #include "lcd_internal.h" @@ -32,38 +35,127 @@ #define ENABLE_DEBUG 0 #include "debug.h" -static void _lcd_spi_acquire(const lcd_t *dev) +static inline void _lcd_write_byte(const lcd_t *dev, bool cont, uint8_t data) { - spi_acquire(dev->params->spi, dev->params->cs_pin, dev->params->spi_mode, - dev->params->spi_clk); + if (dev->params->spi != SPI_UNDEF) { + /* SPI serial interface is used */ + spi_transfer_byte(dev->params->spi, dev->params->cs_pin, cont, data); + } + else { + assert(false); + } +} + +static inline void _lcd_write_bytes(const lcd_t *dev, bool cont, + const void *data, size_t len) +{ + if (dev->params->spi != SPI_UNDEF) { + /* SPI serial interface is used */ + spi_transfer_bytes(dev->params->spi, + dev->params->cs_pin, cont, data, NULL, len); + } + else { + assert(false); + } +} + +static inline void _lcd_read_bytes(const lcd_t *dev, bool cont, + void *data, size_t len) +{ + if (dev->params->spi != SPI_UNDEF) { + /* SPI serial interface is used */ + /* Dummy read */ + spi_transfer_byte(dev->params->spi, + dev->params->cs_pin, true, 0x00); + spi_transfer_bytes(dev->params->spi, + dev->params->cs_pin, cont, NULL, data, len); + } + else { + assert(false); + } } static void _lcd_cmd_start(const lcd_t *dev, uint8_t cmd, bool cont) { gpio_clear(dev->params->dcx_pin); - spi_transfer_byte(dev->params->spi, dev->params->cs_pin, cont, cmd); + _lcd_write_byte(dev, cont, cmd); gpio_set(dev->params->dcx_pin); } -static void _write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data, - size_t len) +static void _lcd_set_area(const lcd_t *dev, uint16_t x1, uint16_t x2, + uint16_t y1, uint16_t y2) +{ + assert(dev->driver->set_area); + dev->driver->set_area(dev, x1, x2, y1, y2); +} + +void lcd_ll_acquire(const lcd_t *dev) +{ + if (dev->params->spi != SPI_UNDEF) { + /* SPI serial interface is used */ + spi_acquire(dev->params->spi, dev->params->cs_pin, + dev->params->spi_mode, dev->params->spi_clk); + } + else { + assert(false); + } +} + +void lcd_ll_release(const lcd_t *dev) +{ + if (dev->params->spi != SPI_UNDEF) { + /* SPI serial interface is used */ + spi_release(dev->params->spi); + } + else { + assert(false); + } +} + +void lcd_ll_write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data, + size_t len) { _lcd_cmd_start(dev, cmd, len ? true : false); if (len) { - spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false, data, - NULL, len); + _lcd_write_bytes(dev, false, data, len); } } -static void _lcd_set_area(const lcd_t *dev, uint16_t x1, uint16_t x2, - uint16_t y1, uint16_t y2) +void lcd_ll_read_cmd(const lcd_t *dev, uint8_t cmd, uint8_t *data, size_t len) { - assert(dev->driver->set_area); - dev->driver->set_area(dev, x1, x2, y1, y2); + assert(len); + _lcd_cmd_start(dev, cmd, len ? true : false); + _lcd_read_bytes(dev, false, data, len); } int lcd_init(lcd_t *dev, const lcd_params_t *params) { + dev->params = params; + + assert(gpio_is_valid(dev->params->dcx_pin)); + gpio_init(dev->params->dcx_pin, GPIO_OUT); + + if (dev->params->spi != SPI_UNDEF) { + /* SPI serial interface is used */ + int res = spi_init_cs(dev->params->spi, dev->params->cs_pin); + + if (res != SPI_OK) { + DEBUG("[st7735] init: error initializing the CS pin [%i]\n", res); + return -1; + } + } + else { + assert(false); + } + + if (gpio_is_valid(dev->params->rst_pin)) { + gpio_init(dev->params->rst_pin, GPIO_OUT); + gpio_clear(dev->params->rst_pin); + ztimer_sleep(ZTIMER_MSEC, 120); + gpio_set(dev->params->rst_pin); + } + ztimer_sleep(ZTIMER_MSEC, 120); + if (dev->driver->init) { return dev->driver->init(dev, params); } @@ -73,28 +165,22 @@ int lcd_init(lcd_t *dev, const lcd_params_t *params) } void lcd_write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data, - size_t len) + size_t len) { - _lcd_spi_acquire(dev); - _write_cmd(dev, cmd, data, len); - spi_release(dev->params->spi); + lcd_ll_acquire(dev); + lcd_ll_write_cmd(dev, cmd, data, len); + lcd_ll_release(dev); } void lcd_read_cmd(const lcd_t *dev, uint8_t cmd, uint8_t *data, size_t len) { - assert(len); - _lcd_spi_acquire(dev); - _lcd_cmd_start(dev, cmd, true); - /* Dummy transfer */ - spi_transfer_byte(dev->params->spi, dev->params->cs_pin, true, 0x00); - spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false, NULL, - data, len); - spi_release(dev->params->spi); + lcd_ll_acquire(dev); + lcd_ll_read_cmd(dev, cmd, data, len); + lcd_ll_release(dev); } - void lcd_fill(const lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1, - uint16_t y2, uint16_t color) + uint16_t y2, uint16_t color) { /* Send fill area to the display */ @@ -106,7 +192,7 @@ void lcd_fill(const lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1, x1, x2, y1, y2, (unsigned long)num_pix); /* Send fill area to the display */ - _lcd_spi_acquire(dev); + lcd_ll_acquire(dev); _lcd_set_area(dev, x1, x2, y1, y2); /* Memory access command */ @@ -117,16 +203,14 @@ void lcd_fill(const lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1, } for (int i = 0; i < (num_pix - 1); i++) { - spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, true, - (uint8_t *)&color, NULL, sizeof(color)); + _lcd_write_bytes(dev, true, (uint8_t *)&color, sizeof(color)); } - spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false, - (uint8_t *)&color, NULL, sizeof(color)); - spi_release(dev->params->spi); + _lcd_write_bytes(dev, false, (uint8_t *)&color, sizeof(color)); + lcd_ll_release(dev); } void lcd_pixmap(const lcd_t *dev, uint16_t x1, uint16_t x2, - uint16_t y1, uint16_t y2, const uint16_t *color) + uint16_t y1, uint16_t y2, const uint16_t *color) { size_t num_pix = (x2 - x1 + 1) * (y2 - y1 + 1); @@ -134,7 +218,7 @@ void lcd_pixmap(const lcd_t *dev, uint16_t x1, uint16_t x2, "y1: %" PRIu16 ", y2: %" PRIu16 ". Num pixels: %lu\n", x1, x2, y1, y2, (unsigned long)num_pix); - _lcd_spi_acquire(dev); + lcd_ll_acquire(dev); /* Send fill area to the display */ _lcd_set_area(dev, x1, x2, y1, y2); @@ -145,19 +229,16 @@ void lcd_pixmap(const lcd_t *dev, uint16_t x1, uint16_t x2, if (IS_ACTIVE(CONFIG_LCD_LE_MODE)) { for (size_t i = 0; i < num_pix - 1; i++) { uint16_t ncolor = htons(*(color + i)); - spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, true, - &ncolor, NULL, sizeof(uint16_t)); + _lcd_write_bytes(dev, true, &ncolor, sizeof(uint16_t)); } uint16_t ncolor = htons(*(color + num_pix - 1)); - spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false, - &ncolor, NULL, sizeof(uint16_t)); + _lcd_write_bytes(dev, false, &ncolor, sizeof(uint16_t)); } else { - spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false, - (const uint8_t *)color, NULL, num_pix * 2); + _lcd_write_bytes(dev, false, (const uint8_t *)color, num_pix * 2); } - spi_release(dev->params->spi); + lcd_ll_release(dev); } void lcd_invert_on(const lcd_t *dev) From c51496fe2e1e4539beee1e179aacd46e2e9cfea3 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sun, 9 Jul 2023 11:57:59 +0200 Subject: [PATCH 3/5] drivers/ili9341: move basic communication functions to drivers/lcd --- drivers/ili9341/ili9341.c | 87 +++++++++++++++------------------------ 1 file changed, 34 insertions(+), 53 deletions(-) diff --git a/drivers/ili9341/ili9341.c b/drivers/ili9341/ili9341.c index 36212e2be227..9490a4167487 100644 --- a/drivers/ili9341/ili9341.c +++ b/drivers/ili9341/ili9341.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2018 Koen Zandberg + * 2023 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -14,6 +15,7 @@ * @brief Device driver implementation for the ili9341 display controller * * @author Koen Zandberg + * @author Gunar Schorcht * * @} */ @@ -22,8 +24,8 @@ #include #include "byteorder.h" #include "periph/spi.h" -#include "ztimer.h" #include "kernel_defines.h" +#include "ztimer.h" #include "ili9341.h" #include "ili9341_internal.h" @@ -33,18 +35,6 @@ #define ENABLE_DEBUG 0 #include "debug.h" -static void _write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data, - size_t len) -{ - gpio_clear(dev->params->dcx_pin); - spi_transfer_byte(dev->params->spi, dev->params->cs_pin, len ? true : false, cmd); - gpio_set(dev->params->dcx_pin); - if (len) { - spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false, data, - NULL, len); - } -} - /* datasheet page 178, table converted to equation. * gvdd in 1mv increments: 4850 = 4.85V */ static uint8_t _ili9341_calc_pwrctl1(uint16_t gvdd) @@ -66,72 +56,57 @@ static uint8_t _ili9341_calc_vml(int16_t vcoml) static int _init(lcd_t *dev, const lcd_params_t *params) { assert(params->lines >= 16 && params->lines <= 320 && !(params->lines & 0x7)); - dev->params = params; - uint8_t command_params[4] = { 0 }; - gpio_init(dev->params->dcx_pin, GPIO_OUT); - int res = spi_init_cs(dev->params->spi, dev->params->cs_pin); - if (res != SPI_OK) { - DEBUG("[ili9341] init: error initializing the CS pin [%i]\n", res); - return -1; - } - if (gpio_is_valid(dev->params->rst_pin)) { - gpio_init(dev->params->rst_pin, GPIO_OUT); - gpio_clear(dev->params->rst_pin); - ztimer_sleep(ZTIMER_MSEC, 120); - gpio_set(dev->params->rst_pin); - } - ztimer_sleep(ZTIMER_MSEC, 120); + uint8_t command_params[4] = { 0 }; /* Acquire once at release at the end */ - spi_acquire(dev->params->spi, dev->params->cs_pin, dev->params->spi_mode, - dev->params->spi_clk); + lcd_ll_acquire(dev); /* Soft Reset */ - _write_cmd(dev, LCD_CMD_SWRESET, NULL, 0); + lcd_ll_write_cmd(dev, LCD_CMD_SWRESET, NULL, 0); ztimer_sleep(ZTIMER_MSEC, 120); /* Display off */ - _write_cmd(dev, LCD_CMD_DISPOFF, NULL, 0); + lcd_ll_write_cmd(dev, LCD_CMD_DISPOFF, NULL, 0); /* PWRCTL1/2 */ command_params[0] = _ili9341_calc_pwrctl1(CONFIG_ILI9341_GVDD); - _write_cmd(dev, LCD_CMD_PWCTRL1, command_params, 1); + lcd_ll_write_cmd(dev, LCD_CMD_PWCTRL1, command_params, 1); command_params[0] = 0x10; /* PWRCTL 0 0 0 */ - _write_cmd(dev, LCD_CMD_PWCTRL2, command_params, 1); + lcd_ll_write_cmd(dev, LCD_CMD_PWCTRL2, command_params, 1); /* VCOMCTL */ command_params[0] = _ili9341_calc_vmh(CONFIG_ILI9341_VCOMH); command_params[1] = _ili9341_calc_vml(CONFIG_ILI9341_VCOML); - _write_cmd(dev, LCD_CMD_VMCTRL1, command_params, 2); + lcd_ll_write_cmd(dev, LCD_CMD_VMCTRL1, command_params, 2); command_params[0] = 0x86; - _write_cmd(dev, LCD_CMD_VMCTRL2, command_params, 1); + lcd_ll_write_cmd(dev, LCD_CMD_VMCTRL2, command_params, 1); /* Memory access CTL */ command_params[0] = dev->params->rotation; command_params[0] |= dev->params->rgb ? 0 : LCD_MADCTL_BGR; - _write_cmd(dev, LCD_CMD_MADCTL, command_params, 1); + lcd_ll_write_cmd(dev, LCD_CMD_MADCTL, command_params, 1); /* Frame control */ command_params[0] = 0x00; command_params[1] = 0x18; - _write_cmd(dev, LCD_CMD_FRAMECTL1, command_params, 2); + lcd_ll_write_cmd(dev, LCD_CMD_FRAMECTL1, command_params, 2); /* Display function control */ command_params[0] = 0x08; command_params[1] = 0x82; /* number of lines, see datasheet p. 166 (DISCTRL::NL) */ command_params[2] = (params->lines >> 3) - 1; - _write_cmd(dev, LCD_CMD_DFUNC, command_params, 3); + lcd_ll_write_cmd(dev, LCD_CMD_DFUNC, command_params, 3); /* Pixel format */ command_params[0] = 0x55; /* 16 bit mode */ - _write_cmd(dev, LCD_CMD_PIXSET, command_params, 1); + lcd_ll_write_cmd(dev, LCD_CMD_PIXSET, command_params, 1); command_params[0] = 0x01; - _write_cmd(dev, LCD_CMD_GAMSET, command_params, 1); + lcd_ll_write_cmd(dev, LCD_CMD_GAMSET, command_params, 1); /* Gamma correction */ { @@ -139,27 +114,30 @@ static int _init(lcd_t *dev, const lcd_params_t *params) 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00 }; - _write_cmd(dev, LCD_CMD_PGAMCTRL, gamma_pos, - sizeof(gamma_pos)); + lcd_ll_write_cmd(dev, LCD_CMD_PGAMCTRL, gamma_pos, + sizeof(gamma_pos)); } { static const uint8_t gamma_neg[] = { 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F }; - _write_cmd(dev, LCD_CMD_NGAMCTRL, gamma_neg, - sizeof(gamma_neg)); + lcd_ll_write_cmd(dev, LCD_CMD_NGAMCTRL, gamma_neg, + sizeof(gamma_neg)); } if (dev->params->inverted) { - _write_cmd(dev, LCD_CMD_DINVON, NULL, 0); + lcd_ll_write_cmd(dev, LCD_CMD_DINVON, NULL, 0); } /* Sleep out (turn off sleep mode) */ - _write_cmd(dev, LCD_CMD_SLPOUT, NULL, 0); + lcd_ll_write_cmd(dev, LCD_CMD_SLPOUT, NULL, 0); /* Display on */ - _write_cmd(dev, LCD_CMD_DISPON, NULL, 0); - spi_release(dev->params->spi); + lcd_ll_write_cmd(dev, LCD_CMD_DISPON, NULL, 0); + + /* Finally release the device */ + lcd_ll_release(dev); + return 0; } @@ -176,12 +154,15 @@ static void _set_area(const lcd_t *dev, uint16_t x1, uint16_t x2, params[0] = byteorder_htons(x1); params[1] = byteorder_htons(x2); - _write_cmd(dev, LCD_CMD_CASET, (uint8_t *)params, - sizeof(params)); + /* Function is called by a high level function of the LCD driver where + * the device is already acquired. So we don't must acquire it here. + * Therefore the low level write command function is called. */ + lcd_ll_write_cmd(dev, LCD_CMD_CASET, (uint8_t *)params, + sizeof(params)); params[0] = byteorder_htons(y1); params[1] = byteorder_htons(y2); - _write_cmd(dev, LCD_CMD_PASET, (uint8_t *)params, - sizeof(params)); + lcd_ll_write_cmd(dev, LCD_CMD_PASET, (uint8_t *)params, + sizeof(params)); } const lcd_driver_t lcd_ili9341_driver = { From 878af4f9a1a16a6fe4c7882da4c22f53d9ae8191 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sun, 9 Jul 2023 11:58:20 +0200 Subject: [PATCH 4/5] drivers/st7735: move basic communication functions to drivers/lcd --- drivers/include/st7735.h | 2 +- drivers/st7735/st7735.c | 104 ++++++++++++++++----------------------- 2 files changed, 44 insertions(+), 62 deletions(-) diff --git a/drivers/include/st7735.h b/drivers/include/st7735.h index ccc0e10efa86..b9c0c42f62fa 100644 --- a/drivers/include/st7735.h +++ b/drivers/include/st7735.h @@ -83,7 +83,7 @@ extern "C" { #endif /** - * @name ILI9341 display rotation modes + * @name ST7735 display rotation modes * @{ */ #define ST7735_ROTATION_VERT 0 /**< Vertical mode */ diff --git a/drivers/st7735/st7735.c b/drivers/st7735/st7735.c index 2c7deef504da..6977091e0e6c 100644 --- a/drivers/st7735/st7735.c +++ b/drivers/st7735/st7735.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2018 Koen Zandberg * 2021 Francisco Molina + * 2023 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -16,16 +17,21 @@ * * @author Koen Zandberg * @author Francisco Molina + * @author Gunar Schorcht * * @} */ #include #include + #include "byteorder.h" -#include "periph/spi.h" -#include "ztimer.h" #include "kernel_defines.h" +#include "ztimer.h" + +#if IS_USED(MODULE_LCD_SPI) +#include "periph/spi.h" +#endif #include "st7735.h" #include "st7735_internal.h" @@ -35,18 +41,6 @@ #define ENABLE_DEBUG 0 #include "debug.h" -static void _write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data, - size_t len) -{ - gpio_clear(dev->params->dcx_pin); - spi_transfer_byte(dev->params->spi, dev->params->cs_pin, len ? true : false, cmd); - gpio_set(dev->params->dcx_pin); - if (len) { - spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false, data, - NULL, len); - } -} - /* datasheet page 178, table converted to equation. * gvdd in 1mv increments: 4850 = 4.85V */ static uint8_t _st7735_calc_pwrctl1(uint16_t gvdd) @@ -72,92 +66,75 @@ static int _init(lcd_t *dev, const lcd_params_t *params) else { assert(params->lines <= 162); } - dev->params = params; - uint8_t command_params[4] = { 0 }; - - gpio_init(dev->params->dcx_pin, GPIO_OUT); - int res = spi_init_cs(dev->params->spi, dev->params->cs_pin); - - if (res != SPI_OK) { - DEBUG("[st7735] init: error initializing the CS pin [%i]\n", res); - return -1; - } - if (gpio_is_valid(dev->params->rst_pin)) { - gpio_init(dev->params->rst_pin, GPIO_OUT); - gpio_clear(dev->params->rst_pin); - ztimer_sleep(ZTIMER_MSEC, 120); - gpio_set(dev->params->rst_pin); - } - ztimer_sleep(ZTIMER_MSEC, 120); + uint8_t command_params[4] = { 0 }; - /* Acquire once at release at the end */ - spi_acquire(dev->params->spi, dev->params->cs_pin, dev->params->spi_mode, - dev->params->spi_clk); + /* Acquire once and release at the end */ + lcd_ll_acquire(dev); /* Soft Reset */ - _write_cmd(dev, LCD_CMD_SWRESET, NULL, 0); + lcd_ll_write_cmd(dev, LCD_CMD_SWRESET, NULL, 0); ztimer_sleep(ZTIMER_MSEC, 120); /* Display off */ - _write_cmd(dev, LCD_CMD_DISPOFF, NULL, 0); + lcd_ll_write_cmd(dev, LCD_CMD_DISPOFF, NULL, 0); /* PWRCTL1 */ command_params[0] = _st7735_calc_pwrctl1(CONFIG_ST7735_GVDD); - _write_cmd(dev, LCD_CMD_PWCTRL1, command_params, 1); + lcd_ll_write_cmd(dev, LCD_CMD_PWCTRL1, command_params, 1); /* PWCTR2 VGH = 14.7V, VGL = -7.35V */ command_params[0] = 0x01; command_params[1] = 0x05; - _write_cmd(dev, LCD_CMD_PWCTRL2, command_params, 2); + lcd_ll_write_cmd(dev, LCD_CMD_PWCTRL2, command_params, 2); /* PWCTR3 Opamp current small, Boost frequency */ command_params[0] = 0x02; command_params[1] = 0x01; command_params[2] = 0x02; - _write_cmd(dev, LCD_CMD_PWCTRL3, command_params, 3); + lcd_ll_write_cmd(dev, LCD_CMD_PWCTRL3, command_params, 3); /* PWCTR6 */ command_params[0] = 0x02; command_params[1] = 0x11; command_params[2] = 0x15; - _write_cmd(dev, LCD_CMD_PWCTRL6, command_params, 3); + lcd_ll_write_cmd(dev, LCD_CMD_PWCTRL6, command_params, 3); /* No display Inversion , Line inversion */ command_params[0] = 0x07; - _write_cmd(dev, LCD_CMD_INVCTR, command_params, 1); + lcd_ll_write_cmd(dev, LCD_CMD_INVCTR, command_params, 1); /* VCOMCTL */ command_params[0] = _st7735_calc_vmh(CONFIG_ST7735_VCOMH); command_params[1] = _st7735_calc_vml(CONFIG_ST7735_VCOML); - _write_cmd(dev, LCD_CMD_VMCTRL1, command_params, 2); + lcd_ll_write_cmd(dev, LCD_CMD_VMCTRL1, command_params, 2); command_params[0] = 0x86; - _write_cmd(dev, LCD_CMD_VMCTRL2, command_params, 1); + lcd_ll_write_cmd(dev, LCD_CMD_VMCTRL2, command_params, 1); /* Memory access CTL */ command_params[0] = dev->params->rotation; command_params[0] |= dev->params->rgb ? 0 : LCD_MADCTL_BGR; - _write_cmd(dev, LCD_CMD_MADCTL, command_params, 1); + lcd_ll_write_cmd(dev, LCD_CMD_MADCTL, command_params, 1); /* Frame control */ command_params[0] = 0x00; command_params[1] = 0x18; - _write_cmd(dev, LCD_CMD_FRAMECTL1, command_params, 2); + lcd_ll_write_cmd(dev, LCD_CMD_FRAMECTL1, command_params, 2); /* Display function control */ command_params[0] = 0x08; command_params[1] = 0x82; /* number of lines, see datasheet p. 166 (DISCTRL::NL) */ command_params[2] = (params->lines >> 3) - 1; - _write_cmd(dev, LCD_CMD_DFUNC, command_params, 3); + lcd_ll_write_cmd(dev, LCD_CMD_DFUNC, command_params, 3); /* Pixel format */ command_params[0] = 0x55; /* 16 bit mode */ - _write_cmd(dev, LCD_CMD_PIXSET, command_params, 1); + lcd_ll_write_cmd(dev, LCD_CMD_PIXSET, command_params, 1); command_params[0] = 0x01; - _write_cmd(dev, LCD_CMD_GAMSET, command_params, 1); + lcd_ll_write_cmd(dev, LCD_CMD_GAMSET, command_params, 1); /* Gamma correction */ { @@ -165,31 +142,33 @@ static int _init(lcd_t *dev, const lcd_params_t *params) 0x02, 0x1c, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2d, 0x29, 0x25, 0x2B, 0x39, 0x00, 0x01, 0x03, 0x10 }; - _write_cmd(dev, LCD_CMD_PGAMCTRL, gamma_pos, - sizeof(gamma_pos)); + lcd_ll_write_cmd(dev, LCD_CMD_PGAMCTRL, gamma_pos, + sizeof(gamma_pos)); } { static const uint8_t gamma_neg[] = { 0x03, 0x1d, 0x07, 0x06, 0x2E, 0x2C, 0x29, 0x2D, 0x2E, 0x2E, 0x37, 0x3F, 0x00, 0x00, 0x02, 0x10 }; - _write_cmd(dev, LCD_CMD_NGAMCTRL, gamma_neg, - sizeof(gamma_neg)); + lcd_ll_write_cmd(dev, LCD_CMD_NGAMCTRL, gamma_neg, + sizeof(gamma_neg)); } if (dev->params->inverted) { - _write_cmd(dev, LCD_CMD_DINVON, NULL, 0); + lcd_ll_write_cmd(dev, LCD_CMD_DINVON, NULL, 0); } /* Sleep out (turn off sleep mode) */ - _write_cmd(dev, LCD_CMD_SLPOUT, NULL, 0); + lcd_ll_write_cmd(dev, LCD_CMD_SLPOUT, NULL, 0); /* Normal display mode on */ - _write_cmd(dev, LCD_CMD_NORON, NULL, 0); + lcd_ll_write_cmd(dev, LCD_CMD_NORON, NULL, 0); ztimer_sleep(ZTIMER_MSEC, 1); /* Display on */ - _write_cmd(dev, LCD_CMD_DISPON, NULL, 0); - spi_release(dev->params->spi); + lcd_ll_write_cmd(dev, LCD_CMD_DISPON, NULL, 0); + + /* Finally release the device */ + lcd_ll_release(dev); return 0; } @@ -207,12 +186,15 @@ static void _set_area(const lcd_t *dev, uint16_t x1, uint16_t x2, params[0] = byteorder_htons(x1); params[1] = byteorder_htons(x2); - _write_cmd(dev, LCD_CMD_CASET, (uint8_t *)params, - sizeof(params)); + /* Function is called by a high level function of the LCD driver where + * the device is already acquired. So we don't must acquire it here. + * Therefore the low level write command function is called. */ + lcd_ll_write_cmd(dev, LCD_CMD_CASET, (uint8_t *)params, + sizeof(params)); params[0] = byteorder_htons(y1); params[1] = byteorder_htons(y2); - _write_cmd(dev, LCD_CMD_PASET, (uint8_t *)params, - sizeof(params)); + lcd_ll_write_cmd(dev, LCD_CMD_PASET, (uint8_t *)params, + sizeof(params)); } const lcd_driver_t lcd_st7735_driver = { From 5cb51b17a332e949879e379db0f687bd10853d02 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Mon, 10 Jul 2023 12:12:10 +0200 Subject: [PATCH 5/5] driver/lcd: use a default implementation of lcd_set_area used Using a default implementation of `lcd_set_area` function allows further code deduplication. --- drivers/ili9341/ili9341.c | 26 +------------------------- drivers/include/lcd.h | 5 +++++ drivers/lcd/lcd.c | 32 ++++++++++++++++++++++++++++++-- drivers/st7735/st7735.c | 26 +------------------------- 4 files changed, 37 insertions(+), 52 deletions(-) diff --git a/drivers/ili9341/ili9341.c b/drivers/ili9341/ili9341.c index 9490a4167487..11f8ef9892df 100644 --- a/drivers/ili9341/ili9341.c +++ b/drivers/ili9341/ili9341.c @@ -141,31 +141,7 @@ static int _init(lcd_t *dev, const lcd_params_t *params) return 0; } -static void _set_area(const lcd_t *dev, uint16_t x1, uint16_t x2, - uint16_t y1, uint16_t y2) -{ - be_uint16_t params[2]; - - x1 += dev->params->offset_x; - x2 += dev->params->offset_x; - y1 += dev->params->offset_y; - y2 += dev->params->offset_y; - - params[0] = byteorder_htons(x1); - params[1] = byteorder_htons(x2); - - /* Function is called by a high level function of the LCD driver where - * the device is already acquired. So we don't must acquire it here. - * Therefore the low level write command function is called. */ - lcd_ll_write_cmd(dev, LCD_CMD_CASET, (uint8_t *)params, - sizeof(params)); - params[0] = byteorder_htons(y1); - params[1] = byteorder_htons(y2); - lcd_ll_write_cmd(dev, LCD_CMD_PASET, (uint8_t *)params, - sizeof(params)); -} - const lcd_driver_t lcd_ili9341_driver = { .init = _init, - .set_area = _set_area, + .set_area = NULL, /* default implementation is used */ }; diff --git a/drivers/include/lcd.h b/drivers/include/lcd.h index a44d6bb7f635..a29163342f5a 100644 --- a/drivers/include/lcd.h +++ b/drivers/include/lcd.h @@ -126,6 +126,11 @@ struct lcd_driver { /** * @brief Set area LCD work area * + * This function pointer can be NULL if the controller specific driver + * does not require anything special. In this case the default + * implementation is used which sets the column addresses and the row + * addresses of the area including the coordinates of the opposite corner. + * * @param[in] dev Pointer to the selected driver * @param[in] x1 x coordinate of the first corner * @param[in] x2 x coordinate of the opposite corner diff --git a/drivers/lcd/lcd.c b/drivers/lcd/lcd.c index c903a1b94a7a..8abe50518902 100644 --- a/drivers/lcd/lcd.c +++ b/drivers/lcd/lcd.c @@ -82,11 +82,39 @@ static void _lcd_cmd_start(const lcd_t *dev, uint8_t cmd, bool cont) gpio_set(dev->params->dcx_pin); } +static void _lcd_set_area_default(const lcd_t *dev, uint16_t x1, uint16_t x2, + uint16_t y1, uint16_t y2) +{ + be_uint16_t params[2]; + + x1 += dev->params->offset_x; + x2 += dev->params->offset_x; + y1 += dev->params->offset_y; + y2 += dev->params->offset_y; + + /* Function is called by a high level function of the LCD driver where + * the device is already acquired. So we don't must acquire it here. + * Therefore the low level write command function is called. */ + + params[0] = byteorder_htons(x1); + params[1] = byteorder_htons(x2); + lcd_ll_write_cmd(dev, LCD_CMD_CASET, (uint8_t *)params, + sizeof(params)); + params[0] = byteorder_htons(y1); + params[1] = byteorder_htons(y2); + lcd_ll_write_cmd(dev, LCD_CMD_PASET, (uint8_t *)params, + sizeof(params)); +} + static void _lcd_set_area(const lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1, uint16_t y2) { - assert(dev->driver->set_area); - dev->driver->set_area(dev, x1, x2, y1, y2); + if (dev->driver->set_area) { + dev->driver->set_area(dev, x1, x2, y1, y2); + } + else { + _lcd_set_area_default(dev, x1, x2, y1, y2); + } } void lcd_ll_acquire(const lcd_t *dev) diff --git a/drivers/st7735/st7735.c b/drivers/st7735/st7735.c index 6977091e0e6c..63ab9fb84b3f 100644 --- a/drivers/st7735/st7735.c +++ b/drivers/st7735/st7735.c @@ -173,31 +173,7 @@ static int _init(lcd_t *dev, const lcd_params_t *params) return 0; } -static void _set_area(const lcd_t *dev, uint16_t x1, uint16_t x2, - uint16_t y1, uint16_t y2) -{ - be_uint16_t params[2]; - - x1 += dev->params->offset_x; - x2 += dev->params->offset_x; - y1 += dev->params->offset_y; - y2 += dev->params->offset_y; - - params[0] = byteorder_htons(x1); - params[1] = byteorder_htons(x2); - - /* Function is called by a high level function of the LCD driver where - * the device is already acquired. So we don't must acquire it here. - * Therefore the low level write command function is called. */ - lcd_ll_write_cmd(dev, LCD_CMD_CASET, (uint8_t *)params, - sizeof(params)); - params[0] = byteorder_htons(y1); - params[1] = byteorder_htons(y2); - lcd_ll_write_cmd(dev, LCD_CMD_PASET, (uint8_t *)params, - sizeof(params)); -} - const lcd_driver_t lcd_st7735_driver = { .init = _init, - .set_area = _set_area, + .set_area = NULL, /* default implementation is used */ };